stella-3.9.3/0000755000175000001440000000000012267274567012421 5ustar stephenusersstella-3.9.3/config.sub0000644000175000001440000007577711205247262014407 0ustar stephenusers#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. timestamp='2005-07-08' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # 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 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. # # 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. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # 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. # 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 $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -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 (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 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-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) 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) os= basic_machine=$1 ;; -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 ;; -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/'` ;; -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*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -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 \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | ms1 \ | msp430 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m32c) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # 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-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | ms1-* \ | msp430-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa-* \ | ymp-* \ | z8k-*) ;; m32c-*) ;; # 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 ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; 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 ;; cr16c) basic_machine=cr16c-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 ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; 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'm not sure what "Sysv32" means. Should this be sysv3.2? 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 ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; 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 ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; 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 ;; nsr-tandem) basic_machine=nsr-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 ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; 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) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) 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 | ppc64-le | powerpc64-little) 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 ;; 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 ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; 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 ;; 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 ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; 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 ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-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[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b) 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. -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|'` ;; # First 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* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ | -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* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ | -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*) # 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 ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -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 *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) 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 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; 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 ;; *-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 ;; -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-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: stella-3.9.3/Makefile0000644000175000001440000002035012266336753014054 0ustar stephenusers##============================================================================ ## ## SSSS tt lll lll ## SS SS tt ll ll ## SS tttttt eeee ll ll aaaa ## SSSS tt ee ee ll ll aa ## SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" ## SS SS tt ee ll ll aa aa ## SSSS ttt eeeee llll llll aaaaa ## ## Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony ## and 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 := LDFLAGS := 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) else CXXFLAGS:= -O2 endif CXXFLAGS+= -Wall ifdef HAVE_GCC CXXFLAGS+= -Wno-multichar -Wunused -fno-rtti -Woverloaded-virtual endif ifdef PROFILE PROF:= -g -pg -fprofile-arcs -ftest-coverage CXXFLAGS+= $(PROF) else ifdef HAVE_GCC CXXFLAGS+= -fomit-frame-pointer endif endif # Even more warnings... #CXXFLAGS+= -pedantic -Wpointer-arith -Wcast-qual -Wconversion #CXXFLAGS+= -Wshadow -Wimplicit -Wundef -Wnon-virtual-dtor #CXXFLAGS+= -Wno-reorder -Wwrite-strings -fcheck-new -Wctor-dtor-privacy ####################################################################### # 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/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 Win32 icon stuff (there's probably a better way to do this ...) src/win32/stella_icon.o: src/win32/stella.ico src/win32/stella.rc $(WINDRES) --include-dir src/win32 src/win32/stella.rc src/win32/stella_icon.o .PHONY: deb bundle test install uninstall stella-3.9.3/Readme.txt0000644000175000001440000000053212106432605014334 0ustar stephenusersStella 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: http://stella.sourceforge.net Enjoy, The Stella Team stella-3.9.3/README-SDL.txt0000644000175000001440000000064711205247262014525 0ustar stephenusersPlease distribute this file with the SDL runtime environment: The Simple DirectMedia Layer (SDL for short) is a cross-platfrom 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 GNU LGPL license: http://www.gnu.org/copyleft/lesser.html stella-3.9.3/config.guess0000755000175000001440000012475311205247262014734 0ustar stephenusers#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. timestamp='2005-08-03' # 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 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. # # 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. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -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 (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 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 -q "$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 # 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 tupples: *-*-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=`(/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 ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null 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 # 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/[-_].*/\./'` ;; 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}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerppc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} 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'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; 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 ;; 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:SunOS:5.*:*) echo i386-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:*:[45]) 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/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` 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:BSD:*) 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 __LP64__ >/dev/null 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:*:*) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; x86:Interix*:[34]*) echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' exit ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-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-gnu`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 '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #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-gnu"; exit; } ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #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-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu 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 ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${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-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` test x"${LIBC}" != x && { echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit } test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; 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.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V: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 i386. echo i386-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; } ;; 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.0*:*) 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 ;; 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 ;; 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 case $UNAME_PROCESSOR in *86) UNAME_PROCESSOR=i686 ;; unknown) UNAME_PROCESSOR=powerpc ;; esac 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 ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-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 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 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-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: stella-3.9.3/docs/0000755000175000001440000000000012267274567013351 5ustar stephenusersstella-3.9.3/docs/index.html0000644000175000001440000042523612267025147015346 0ustar stephenusers Stella - A multi-platform Atari 2600 VCS emulator
Stella


A multi-platform Atari 2600 VCS emulator

Release 3.9.3



User's Guide



  1. A Brief History of the Atari 2600
  2. Introduction
  3. Getting Started
  4. Advanced Configuration
  5. Acknowledgments
  6. License and Disclaimer



February 1999 - August 2013
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++ code
  • 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 CX-22 / CX-80 style trackballs and Amiga 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-adaptor/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+ bankswitching scheme 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 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 both TIA sprites and collisions for each object separately
  • Full system state save/load functionality
  • 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 compiled by RomHunter


Getting Started


1. Requirements

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

General (required for all versions of Stella)

  • 1GHz+ CPU
  • Enough RAM for the OS + 64MB RAM for the emulation; 128MB+ highly recommended
  • 15/16 bit color minimum; 24/32 bit color graphics card highly recommended
  • SDL version 1.2.10 or greater, latest version highly recommended
  • CRT TV emulation effects require OpenGL 1.2/OpenGLES 1 or higher
  • Joysticks or gamepads are highly recommended
  • Mouse or Stelladaptor / 2600-adaptor 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 2.6.x/3.x
  • i386 or x86_64 class machine, with 32 or 64-bit distribution
  • OpenGL accelerated video card highly recommended
  • Other architectures (MIPS, PPC, PPC64, etc) have been confirmed to work, but aren't as well tested as i386/x86_64
  • GNU C++ compiler version 4.x 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.4 (Tiger) or above
  • PPC G4/G5 or Intel processor
  • OpenGL capable video card
  • Xcode 3.1 and SDL 1.2.14 required to compile a 10.4 compatible Universal Binary version; Xcode 3.2 and SDL 1.2.15 required to compile the Intel/64-bit version
  • The 64-bit version requires at minimum Snow Leopard (10.6) and Intel CPU/architecture

Windows

The Windows version of Stella is designed to work on Windows XP/Vista/7 with the following:

  • OpenGL accelerated video card highly recommended
  • 64-bit port has been tested on Windows Vista/7 only; it may work on WinXP64 as well, but isn't a priority
  • Visual C++ 2010 is required to compile the Stella source code
  • It may be possible to compile using MinGW, but this hasn't been extensively tested since Stella version 3.0

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.

2. 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

3. 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)
  • 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).

4. 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).

5. 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.

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 Tab
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 (only active in TIA mode when using OpenGL rendering)

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 HMOVE blanks Alt + m Cmd + m
Toggle TIA 'Fixed Debug Colors' mode Alt + Comma Cmd + Comma
Toggle all TIA objects Alt + . Cmd + .
Toggle all TIA collisions Shift-Alt + . Shift-Cmd + .

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 + ]
Toggle console type in increasing order (NTSC/PAL/SECAM, etc)) Control + f Control + f
Toggle console type in decreasing order (NTSC/PAL/SECAM, etc)) Shift-Control + f Shift-Control + f
Save current properties to a new properties file Control + s Control + s
Switch mouse between controller emulation modes Control + 0 Control + 0
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
Toggle palette Control + p Control + p
Toggle PAL color-loss effect Control + l Control + l
Save continuous PNG snapshots Alt + s Cmd + s

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)

6. 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


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.

1. 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 <soft|gl>
Use software or OpenGL rendering mode.
-gl_lib <filename>
OpenGL mode only. Specify the OpenGL library to use (only use this if you know what you're doing). For MacOSX, this should probably be left blank.
-gl_inter <1|0>
OpenGL mode only. Use interpolation for the TIA image (results in blending/smoothing of the image).
-gl_aspectn <number>
-gl_aspectp <number>
OpenGL mode only. 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.
-gl_fsscale <1|0>
OpenGL mode only. Stretch TIA image completely while in fullscreen mode (vs. an integral stretch which won't necessarily completely fill the screen).
-gl_vbo <1|0>
OpenGL mode only. Use the Vertex Buffer Object extension, if available. This is enabled by default.
-gl_vsync <1|0>
OpenGL mode only. Synchronize screen updates to the vertical blank period. This can result in smoother updates, and eliminate tearing.
-tv_filter <1 - 6>
OpenGL mode only. Blargg TV effects, 0 is disabled, next numbers in sequence represent presets for 'composite', 's-video', 'RGB', 'bad adjust', and 'custom' modes.
-tv_scanlines <0 - 100>
OpenGL mode only. Blargg TV effects scanline intensity, where 0 means completely off.
-tv_scaninter <1|0>
OpenGL mode only. Blargg TV effects scanline interpolation, resulting in blending/smoothing of the scanlines.
-tv_contrast <number>
OpenGL mode only. Blargg TV effects 'contrast' (only available in custom mode, range -1.0 to 1.0).
-tv_brightness <number>
OpenGL mode only. Blargg TV effects 'brightness' (only available in custom mode, range -1.0 to 1.0).
-tv_hue <number>
OpenGL mode only. Blargg TV effects 'hue' (only available in custom mode, range -1.0 to 1.0).
-tv_saturation <number>
OpenGL mode only. Blargg TV effects 'saturation' (only available in custom mode, range -1.0 to 1.0).
-tv_gamma <number>
OpenGL mode only. Blargg TV effects 'gamma' (only available in custom mode, range -1.0 to 1.0).
-tv_sharpness <number>
OpenGL mode only. Blargg TV effects 'sharpness' (only available in custom mode, range -1.0 to 1.0).
-tv_resolution <number>
OpenGL mode only. Blargg TV effects 'resolution' (only available in custom mode, range -1.0 to 1.0).
-tv_artifacts <number>
OpenGL mode only. Blargg TV effects 'artifacts' (only available in custom mode, range -1.0 to 1.0).
-tv_fringing <number>
OpenGL mode only. Blargg TV effects 'fringing' (only available in custom mode, range -1.0 to 1.0).
-tv_bleed <number>
OpenGL mode only. Blargg TV effects 'bleed' (only available in custom mode, range -1.0 to 1.0).
-tia_filter <filter>
Use the specified filter while in TIA/emulation mode. Currently, this can be zoomZx, where Z={2..10}.
-fullscreen <1|0|-1>
Play the game in fullscreen mode (1 or 0), or completely disable fullscreen mode (-1).
-fullres <auto|WxH>
Use the given resolution in fullscreen mode. If 'auto', let Stella decide which resolution to use.
-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.
-colorloss <1|0>
Enable/disable the PAL color-loss effect.
-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 GL 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 may need 2048 (but newer versions work with 512 as well).
-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).
-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. Bumper Bash ignores this setting, and always allows all 4 directions.
-grabmouse <1|0>
Keeps the mouse in the game window in emulation mode.
-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).
-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 10, 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 15, 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.
-stats <1|0>
Overlay console info on the TIA image during emulation.
-fastscbios <1|0>
Disable Supercharger BIOS progress loading bars.
-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 <1|2>
Used the specified palette for UI elements. This isn't yet complete.
-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).
-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 section 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.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.
-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).
-holdjoy1 <U,D,L,R,F>
Start the emulator with the right joystick direction/button held down (ie, use 'UF' for up and fire).
-holdselect
Start the emulator with the Game Select switch held down.
-holdreset
Start the emulator with the Game Reset switch held down.
-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.
-ramrandom <1|0>
On reset, either randomize all RAM content, or zero it out instead.
-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 77.
-thumb.trapfatal <true|false>
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.

2. 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
Renderer (*)use specified rendering mode (requires restart)-video
TIA Filterfilter for emulation mode -tia_filter
TIA Palettepalette for emulation mode-palette
Fullscrn Resresolution for fullscreen mode-fullres
Timing (*)how to wait between frames (requires restart)-timing
GL FilterOpenGL filter mode-gl_filter
GL Aspect (N)OpenGL width of TIA image in NTSC mode-gl_aspectn
GL Aspect (P)OpenGL width of TIA image in PAL mode-gl_aspectp
Framerateframes per second in emulation mode-framerate
Fullscreen modeself-explanatory-fullscreen
GL FS Stretchstretch fullscreen OpenGL in emulation mode-gl_fsmax
GL VBOenable OpenGL Vertex Buffer Objects-gl_vbo
GL VSyncenable OpenGL vertical synchronization-gl_vsync
PAL color-lossuse PAL color-loss effect-colorloss
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

Video Settings dialog (TV Effects):

    
ItemBrief descriptionFor more information,
see CommandLine
TV Modedisable TV effects, or select TV preset-tv_filter
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 (3 tabs):

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

    
ItemBrief descriptionFor more information,
see CommandLine
Debugger Width/Heightself-explanatory (requires ROM reload)-dbg.res
Set window size for ...self-explanatory presets (requires ROM reload)N/A
Font Styleself-explanatory (requires ROM reload)-dbg.fontstyle

    
ItemBrief descriptionFor more information,
see CommandLine
Interface Palettepalette to use for UI elements-uipalette
List quick delaytime to wait between keypresses in listwidget-listdelay
Mouse wheel scrollnumber of lines mouse scroll will move in listwidget-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 snapshot-ssinterval
Overwrite existing fileswhether to overwrite old snapshots-sssingle
Disable image filtering (1x mode)save snapshot in 1x mode, without filtering-ss1x

Config Paths dialog:

    
ItemBrief descriptionFor more information,
see CommandLine
Rom pathspecifies location of ROM files-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

Audit ROMs dialog:

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

Game Properties dialog:

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

3. 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 'Emulation 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
AVox serial portDescribed in further detail in Advanced Configuration - AtariVox/SaveKey Support -avoxport
Joy 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
Allow all 4 ...Allow all 4 joystick directions to be pressed simultaneously-joyallow4
Grab mouse ...Keep mouse in window in emulation mode-grabmouse

4. 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.

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.

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.

5. 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.

6. Stelladaptor/2600-daptor Support

Stella supports real Atari 2600 joysticks, paddles and driving controllers using the Stelladaptor and 2600-adaptor devices.

Stella can use up to two adaptors; any extra ones are ignored. Stelladaptor devices will be automatically detected and configured. Stelladaptor devices must be plugged in before starting the application; 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 'Starting a Game') and dynamically with the 'Control-1' key combo.

7. AtariVox/SaveKey Support

Stella supports a real AtariVox device for the speech/SpeakJet portion of the controller. You will need a real AtariVox device, located here, 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.

8. Developer Options/Integrated Debugger

Many 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.

9. 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 gl video = gl
-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/.stella/stellarc
Macintosh Not applicable; settings are saved in ~/Library/Preferences/net.sourceforge.Stella.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_)

10. 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 hexidecimal 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/.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.

11. 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.

12. 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. 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' 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. 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)
2K 64-2048 byte Atari
3E 32K Tigervision
3F 512K Tigervision
4A50 64K 4A50 + ram
4K 4K Atari
4KSC CPUWIZ 4K + ram
AR Supercharger
BF CPUWIZ 256K
BFSC CPUWIZ 256K + ram
CM ¹Spectravideo CompuMate
CV Commavid extra ram
DF CPUWIZ 128K
DFSC CPUWIZ 128K + ram
DPC Pitfall II
DPC+Enhanced DPC
E0 8K Parker Bros
E7 16K 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
MC ¹²C. Wilkson Megacart
SB 128-256k SUPERbanking
UA 8K UA Ltd.
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.
Console.SwapPorts: Indicates that the left and right ports should be swapped internally. This is used for ROMs like 'Raiders' where the Player 0 joystick is plugged into the right joystick port. The value must be Yes or No.
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.
Trackball22 Standard Atari 2600 CX-22 trackball controller.
Trackball80 Atari ST CX-80 trackball controller.
AmigaMouseCommodore Amiga computer mouse.
AtariVoxA SpeakJet based unlimited-vocabulary speech / sound synthesizer with 32K EEPROM.
SaveKeyA 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.
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
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.
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 77.

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/.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.

13. 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/.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-3.9.3/docs/debugger.html0000644000175000001440000020071112205116016015774 0ustar stephenusers Stella Debugger

Stella Integrated Debugger (a work in progress)

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.
  • Frame advance (automatic breakpoint at beginning of next frame) You can advance multiple frames with one command.
  • 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 ("saverom filename.bin").

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. Pressing Shift with the left or right arrow keys cycles between tabs from right-to-left and left-to-right, respectively. Pressing Tab cycles between widgets in the current tab (except for in the Prompt area, 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 (scanline 262, for NTSC games). 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.

Change Tracking

The debugger tracks changes to the CPU 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:

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". 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).

Tab completion

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 "print w" (but don't press Enter), then hit Tab. The "w" will change to "WSYNC" (since this is the only built-in label starting with a "w"). If there are multiple possible completions (try with "v" instead of "w"), you'll see a list of them, and your partial name will be completed as far as possible.

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++ programmer. 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.stella" file (see the section on "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".

Any time the debugger is entered due to a trap, breakpoint, or conditional break, the reason will be displayed in the status area near the TIA Zoom display (area H).

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".

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, 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'll be auto-loaded next time you load the same ROM in Stella. The save file is just a plain text file called "rom_filename.stella", so you can edit it and add new functions, etc.

You can also create a file called "autoexec.stella" which will be loaded when the debugger starts, no matter what ROM you have loaded. The location of this file will depend on the version of Stella, as follows:

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

Note that these '.stella' script 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.

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
_rwport Last address to attempt a read from the cart write port
_fcount Number of frames since emulation started
_cclocks Color clocks on a scanline
_scan Current scanline count
_vsync Whether vertical sync is enabled (1 or 0)
_vblank Whether vertical blank 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 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.

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" or "trapwrite". To remove a trap, you just attempt to set it again: the commands actually toggle the trap on & off. You can also get rid of all traps at once with the "cleartraps" command.

Use "listtraps" to see all enabled traps.

Prompt commands:

Type "help" to see this list in the debugger.

            a - Set Accumulator to value xx
         bank - Show # of banks, or switch to bank xx
         base - Set default base (hex, dec, or bin)
        break - Set/clear breakpoint at address xx (default=PC)
      breakif - Set breakpoint on condition xx
            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]
   cleartraps - Clear all traps
 clearwatches - Clear all watches
          cls - Clear prompt area of text and erase history
         code - Mark 'CODE' range in disassembly
    colortest - Show value xx as TIA color
            d - Decimal Flag: set (0 or 1), or toggle (no arg)
         data - Mark 'DATA' range in disassembly
       define - Define label xx for address yy
   delbreakif - Delete conditional breakif xx
  delfunction - Delete function with label xx
     delwatch - Delete watch xx
       disasm - Disassemble address xx [yy lines] (default=PC)
         dump - Dump 128 bytes of memory at address xx
         exec - Execute script file xx
      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 'CFX' range in disassembly
         help - This cruft
         jump - Scroll disassembly to address xx
   listbreaks - List breakpoints
   listconfig - List Distella config directives [bank xx]
listfunctions - List user-defined functions
    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)
           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 6507 to init vector (excluding TIA/RIOT)
       rewind - Rewind state to last step/trace/scanline/frame
         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 to file xx
   saveconfig - Save Distella config file
      savedis - Save Distella disassembly
      saverom - Save (possibly patched) ROM
      saveses - Save console session to file xx
    savestate - Save emulator state xx (valid args 0-9)
     scanline - Advance emulation by xx scanlines (default=1)
         step - Single step CPU [with count xx]
          tia - Show TIA state (NOT FINISHED YET)
        trace - Single step CPU over subroutines [with count xx]
         trap - Trap read/write access to address(es) xx [to yy]
     trapread - Trap read access to address(es) xx [to yy]
    trapwrite - Trap write access to address(es) xx [to yy]
         type - Show disassembly type for address xx [to yy]
         uhex - Toggle upper/lowercase HEX display
        undef - Undefine label xx (if defined)
            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 programmer.

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.


(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 programmer, 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. In the current release of Stella, these are read-only displays. 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' has been enabled for a ROM, you will see the effect here as well. That is, no flicker will be shown for 30Hz display, even though a real system would alternate between drawing frames (and hence produce flicker).

You can use the "Scan+1" button, the prompt "scan" command, or the Alt-L key-combo to watch the TIA draw the frame one scanline at a time.

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.
  • Set breakpoint: Will set a conditional breakpoint at the scanline where the mouse was clicked. Currently, you'll need to use the Prompt Tab to turn the breakpoint off again.
  • Set zoom position: Influences what is shown in the TIA zoom area (further described in part (G). The zoom area will contain the area centered at the position where the mouse was clicked.
  • Toggle fixed debug colors: Toggles fixed debug color mode. Note that after this is toggled, the framebuffer must be updated in some way (step/trace/frame advance) before the new colors are shown.

(F) TIA Info

To the right of the TIA display (E) there is TIA information, as shown:

The indicators are as follows:

  • 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. 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 Info (F) is the TIA Zoom area. This allows you to enlarge part of the TIA display, so you can see fine details. Note that unlike the TIA display area, this one does generate frames as the real system would. So, if you've enabled 'phosphor mode' for a ROM, it won't be honoured here (ie, you'll see alternating frames at 30Hz display, just like on a real system).

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 (G), there is a status line that shows the reason the debugger was entered (if a breakpoint/trap was hit), as shown:

The output here will generally be self-explanatory. Due to space concerns, conditional breakpoints will be shown as "CBP: ...", normal breakpoints as "BP: ...", read traps as "RTrap: ..." and write traps as "WTrap: ...". See the "Breakpoints" 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 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 (I), or the RIOT RAM (K), depending on which of these widgets is currently active.

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.

  0   [z]    - Set the current location/register to zero.
  Inv [i !]  - Invert the current location/register [toggle all its bits].
  Neg [n]    - Negate the current location/register [twos' complement negative].
  ++  [+ =]  - Increment the current location/register
  --  [-]    - Decrement the current location/register
  <<  [< ,]  - Shift the current location/register left.
  >>  [> .]  - 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 and extended RAM

This is a spreadsheet-like GUI for inspecting and changing the contents of the 2600's RAM. You can view 128 bytes of RAM at a time, starting with the RAM built in to the console (zero-page RAM). If a cartridge contains extended RAM, a scrollbar will be activated, allowing to scroll in sequence through each 128 byte 'bank' of RAM. The address in the upper left corner indicates the offset (in terms of the read port) for the bank currently being displayed.

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/associated shortcut keys (J).

Note: Many extended RAM schemes involve different addresses for reading versus writing RAM (read port vs. write port). The UI takes care of this for you; although the addresses shown are for the read port, modifying a cell will use the write port. Also, some bankswitching schemes can swap RAM and ROM dynamically during program execution. In these cases, the values shown may not always be for RAM, and may point to ROM instead. In the latter case, the data cannot be modified.

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 textboxes show the decimal and binary equivalent value. The remaining buttons to the right are further explained in section (L).


(L) M6532/RIOT and extended 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 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 'Search' is clicked and the input is empty, all RAM locations are 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 comparitive 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' with empty input. 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 (N).

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: cond-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 'PC addresses' 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.

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 programmers 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!


Global Buttons

There are also buttons on the right that always show up no matter which tab you're looking at. These are always active. They are: Step, Trace, Scan+1, Frame+1 and Exit. The larger button to the left (labeled '<') performs the rewind operation, which will undo the previous Step/Trace/Scan/Frame advance. The rewind buffer is currently 100 levels deep.

When you use these buttons, the prompt doesn't change. This means the status lines with the registers and disassembly will be "stale". You can update them just by re-running the relevant commands in the prompt.

You can also use the Step, Trace, Scan+1, Frame+1 and Rewind buttons from anywhere in the GUI via the keyboard, with Alt-S, Alt-T, Alt-L, Alt-F and Alt-R.


Distella Configuration Files

As mentioned in ROM Disassembly (M), 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 version of Stella, 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-3.9.3/docs/graphics/0000755000175000001440000000000012267274567015151 5ustar stephenusersstella-3.9.3/docs/graphics/options_video_tv.png0000644000175000001440000001751712162610274021243 0ustar stephenusers‰PNG  IHDRÞZ°¿< bKGDÿÿÿ ½§“ pHYsaa¨?§itIMEÝ 8&ÚM_tEXtCommentCreated with GIMPW·IDATxÚíݽŽÖHº`3ê`Fâ"&dDBr$$RP_Ñv†6ê„`‘ÈI'AÄHH³ ê‘6õE õÜ'˜cŽ©-Ûe»l—íç‘Z¢¿¯°Ë?]¯ß*Ûu硗ßÞ}üZËzþä^uçêêê›]˪뺪ªªºhGa`×ÇÝê'»Ö#ðÀŠ.ì‚srCݾ/‚.Ž!3ã½~óÙÞÚ±×/Éš]`/¯ »Ž!ÀÎ2Þ®¬ A€Ì/ ðÀîxœˆ$Ÿ½Š~þåÃËÿ*3ôÙÔuÅ–Ó.ÛµŽ”2§¼Gk(Ã@²Çmjê<%Î]çÐ~ýòáeõðÙ«êá³W¹¯ÌÇZ€º×Õ6\}ÙÏž‚–†€â2Þ0讕¥ï£}¼JÊŽûÊÄ.îúº´ceÂï»¶=e]€À»yc>¶¡ »ç6¦s—ü ±%÷g׸tûb/¥LJW|Êr€ãÛÝ]ÍíÆ«Ý… ~Mƒ+“²œ®Æ46f›RÆ_tuuÓÇŽå”2sëVÊroOÎ-ÌlèÞOM·äþJéÊÓݽƅR¸oôŽ€À[l#¾dC™c9²Ûc\0l±]Í ðž®¡œ»œ¾gWÙ§”,yJÅÞ©wÅæjÐ4Œyc®ã±dfšÒý;¦‹¸¯«]W3PUUuçêêê[UõO×¼d­I†ÆvÇÜ<63í{ØËt–"©Ç¯™Vδ€ûäøÁ>5mq‘]ÍCiÊ÷©Ÿ-QFF@Ã$ ð€À ÌÔ9ÆÛ }Æ~4Çï×_µ3t<2uÝÜx5ÎÇæŽØ}»w¿ú…\ǂ\8y5ýÅ〠¼ ð€À ¼pàÀûíÙ«ê[ë¥ÿ~÷ûQÿfzG`I³…÷Ž—þÏÖw«9Û«ëºúíßÿv®“Ûøº®xŽwòìD¢|~ûíŸvB¡ž>ý—sX„1^(9ð÷â,œë€ŒÎx{qÎu` SÿãÃŽn¸/­Æª)3ôYêºæ.'uÙ[ùùçüðû_ýÇ pöŒ÷[+PµƒUøûš ùð€coMÐýë¯ÿ|¸a ν¾%—Æx"ïÖŽtÛÙ®Œw›ž€%-úï—/«‡Ï^UŸ½úþïæó)še´—Õ˜cëI ܱ2CËZ:Ûç¾ÏÚú¾-#Vvh±r{ º?ÿüÿª»1^@Æ;àÂÀЇA7y_0 Ëì!Ó»«c]Öa&Ý•Y‡y( ¯Ñ=¾t¦+óŠ ¼¥Ž{…Aw€ÙÀK1¥Ë: º{ ªcöMx¡Rú¹ìÛÅÒ+hw7e¬%ò½’ØMSÆŠÓ2^û (2ðžeÜëËN·3 M Pº/Tºö1^` ‡ysUصœ3Ãngì±ÏçfDZ®Ü)ûL}D(üa}únÀ:Bð•éEÞ)ã^á¸ëZÁ7\_ûû®€ÙUf麷ƒ]×ãEíïûºIÃ2± ×°ÌÐ÷ír{Z]õ7Æ ,aöoj@š¸bÿ·kyCëI©ÇÛ4&¤~?6s›º¾±Ÿ0#ã5îÅY8×"/°bà5îÅY8×/ìœçx7ôôé¿ì„‚9×"oÓýÖ4J~Ÿöûó/«êÉ#û£ðß²_Ô_]]}«ªªzþäž½¼ûøµªëºzýâÑ÷Ï®ß|®ªÊ/¬Jà^@à€ý¸° ¨ª¿ïÀcO2^Ý•Ôuýý/£<þó÷2ëõéb÷™·2^ñ¥{™éËF¯Î ëÒW¦ì¯ù´^Ðàu ÁvÙ-ÈXãüðÙ«êá³W›Ô§YçÃO͘0U·˜+`(ÉйÚn<· v¥d»G­§ýîoxU·tãTÚU¤«Úód5¥ß”,¾/{• /4¦ˆ”‹ñÔuåêfϹ†z#Ɩɽ†Ö7´Î3·i{k˜ X&+j~JÀl^$ÄíØ…Dû³)cº£ûÖ•«›=e9)eúÊvm{J™\û§/È—2T!ðnt5ÞuÅÖwe7æ*2ÇtŽ+_W‘û>/K ¾)snV¸Å¾Øj¿Ÿ¹»¾k™Ú§ÞÔq²¾+»Ô«Èvfе¾¡F,ו/ûiÌÎ’ìõ†¨¹õNé5Øû>ʱí$ðŽ'Ëy"„rË«N'ø¾§£¯”±Æ#g}©[{:þ± Ú×µ}¶ ÍSg¼{»zv…HésÉÿwÄý±ä>ÜòÑ¢Üë6,&ðnzÕï ñ\çAׂíã¾U K¹œSfî…ëÔ;{smûšû°«ìØ2kî‰Ä8w®®®¾UUÙ3¬Œ½«nÌ]w]pì²R‰±w¦ÔgîUd3I‚w5×¼«ùõ‹GIdèœÑX±§D¹Úß®ÖuýCÛÐL¨²‹Œ7eŒ!åêpêúr]!N½Êιm¬îæ,Èx9È•™Œw™ŒŽ”õºX—ÔømÕ¸­±}^,Qîqé›tfëãfŒÈÿ5{ÍœÆ.ÇŒG[£Mx¿§‹¡pBš’Èx&\Xà˜¼°“+ñ¾2}åŽ6u`lºËpÛRç”z‰ʺÆ,§ï8Œ™KxÌ´ ~þso«}z±Æ†å¸*™;¦bL†­ÿÀSPl\*uìj¯û¨Ý-Øþ½oþê¡ Öµ»Ö•²œ”îË”:³Íoì|Øâoiñ1Þfl§äþöØ36ÃÚA·«aßÓØÕÔ6¢ÔuÍ›N Î}A:lCÉ—hmõ·tá–ýÃwWÎ…ÎP»èÖö3èn颔”:Æ“2þÕW¾oycÇfæŒå,–ÓP¸P´Ïó,ãhÝúgºá÷[鋵vDìį0cãW)]cvæ˜ñ›¡›aæŒå*טûGë0ætüÕ>¦C]WöwQîø ¼‡È,כɱœÜãTÆÊïíè:F)]’º-yÁµÆ±¬ëzô;ÅßdÞÛÓ޹ݤ)c*¹»dç6r¹º‘u5ï»aÍ]Þq?÷92Åó'÷ªëúXûí3ݹººúÖ #e¼2ƒtÍ´€f'ïíÿe¦Âvµ®ëÚ†ë7Ÿ«ª2;¬ê°7WÉvÇ™2ÀI¯ ;ÏÇÖ¤›8eàEðØc¼ ãö¬¹S>ÕžŸª/°« [×õ÷Ç,@Æ‹ÆÙÚD¿ýöϤrOÞ’”:íçmñ´†÷ ¼ºÅªëºº®ÝœÖåÓãÿéýþñ§?’–“{þÔ=–”©QU—*õÍU©óžz§-$( ¼£2¹® )RçÓe—]¯¤M]W_@Ë1ÉIjû¶}L·v_SöÏ™¹¹ 8\þòáe´‹¶ýyì÷0hô-'¼º‚_ß÷)ËHÍR‡ê<´í±Ï†.rúêÜw,d¼ÀbXW#™;ãa›ý׬/eþíp>í0€Åʔܳ0Tgç²À»Ù‰ÙõAxn”ÞèºpR_^8ÔEšà{ÞÌy©‹}ÊcŒ8ýÅÏPJ)3%8†]Îk÷ŒMÙ®­ë,ãe‘+Ô)wF#,ÿXŸñØäz,õnä1Á£tÂ`˜sšÑ¡ãßW—ÔmïªóØmOÝÏCuFà-¢ÁÍœuCîC¬=˱«ë:ë3Î)û¬+¨MYæÔõ-±¬œë*›cSŽ…ÀË"ÅÒã-Nê}œg¾Sæwöæ/^•9ÃÚRx“9³¿ ¦¾÷ ‡Y°13·Ÿ»šwؘw½ý&Ç—äox‡nBÉ= 㥣Q ”¹ï®¤Ü¬Ç1—ÌíÔ»ü4ÜÇ¢«d¼¬­®ëª¾{¿Èº½5ç- ãåHž?¹g'ÌàÑ@Æ‹à ã^xà˜ŒñRUUU½ûøÕN˜ÈÍi€ŒAw%u]W×o>Û€Œ—ñÿù{™õÊ4™úžzÆñ€À Tºša1C3Ou•5á¼Yž35*æW%åø·Ï“fHç ×b]ÍíÆ¤ùʆ–WÒ$ï&g‰‹³¹'ÀÉ3Þ3g»2]6¼}Wü]+ü>Ö}›òYØ×sÖ'%§Ôe¨ÎCË¡œsܱëjn¼öO¬\_wtûóØïSêû=g}Rë8T—v¹Ýõ¬ßã‘k¨xwÝð´ÇÓ¶Ê@ÆŒí¥Ô1ÜÏ”ˆ_ È®fõ@Æ»pÖWB¶VZ}Ø·px%v?@˜{ ÞlÎ^–½V}r7¸}ãèl#¼Ï¡ëøvÝÓb]Íí—Ä™¾2)Ë›ºœ)u[Ÿ”;Ÿ‡–Á±‚o®rÀþݹººúVUæ=³fZ@³×ÌNôúÅ£Cœ°¥#Å¡w¿Vu]ÿÐ64Sˆš$\xÙ lîLs[›$ï'}}÷~‘u{kÎÛU”ÚãÁIÚ BÛŸ%Èx1Ì0ÓÞ»™/‚€Œx`Wt5³]ÞÜþðûû¿$}·çí:Âñ:Êö¼ì’GJ¦;ûÍia#~ys[]ÞÜ~ÿ½ýù‘¶ëlÇA·u]W×õyoN‹5ÎGh¨º]GÜ—]óæªñžzÆx‘€ í`˜Rn­@ÓU—¾ ¨\W}û¶;eY)]ça™®Ìwíý|$n®ŠÌ2»WÓÝ+×^FW™µëËš»Êõ}?´®”moÞwQÖ¹ï"hý,ð,ÀRÙ^ê<ÆÐŘu¥ZÖ§«Ò7ËU8Q»¬™ŠòÅ3iºà×¼[†+ð.Ò`j™kèjO ÙLé¼›„l÷òwb˦§ÑÕÜÓe-û|ÛÛy×Õ-:6 —“óQ–õ‰-g©:÷ÝQÝ·®)Û™s.¹~W#t©”€ÐÕ@‡ÁeJ ë’sY±å¤Ö9e¬u¨¾CëJÙöÔc1´¾œûùŒt5ˆuùÅqJS&e]]åtS–yAwäcÓ×àŽiŒÇ.'õ³%¶k¨L®ÏÇ”™ûýRÇo–`Üþ‰Èv;·ÌкØïyÈxÙi¦"ËÝG vó ð&4”}yÍà.ÛóÑÕ<1†]ˆ{_Ë¿ö…Sxó^ûßÍw±2€Œ÷ðnÓ¸§FÐÍUeŸO}Ç&,·Åñ«ëºªïÞwÐ@àݾ± ÁXcÚ·¬9eƬ‹rϧœå–ðüɽêºv¬ØÞYfùx'4‚CÁrèó”2{j¸ÑàéŒñ€Œ—µ•<Æ÷Öœ·€Œ—#yþäž0ƒnZ@Æ‹à ãd¼@õîãW;ÍeØKÆ ‚®Àæêº®®ß|–ñ¢ñåfÙ¼ÑÆ©Ý𘜽:wÛçx{>è#Ý&\ÞÜV—7·ßo¾×mŠmÄlÚÕÜnpšŸ¡LŽ˜7çþÿbêýƒ_œ–Þ®£î7oáÙpní¬¸¯+6¥\Ô¶ ÖíL¹¯ëy¨®)=©ÛÞ·ÿ8XàÊ ºô˜.ë®ñ´¡e¤.gì²æ– ˹x)÷ÜulòeÏ}ݺíÏÃr¹ºˆÛuX:€§tŧìÔmOÝÏL³iWs»[­ýÓU¶¯;ºý}¬LøY_—^J·w3+—Ò…ž« å:'™t‡‚ÑZA¢éúmw·ëÓ­ØÏö3;ÍxcÞÒ7—„ãi}åºê³DýR–ÙUF&µ@|Ô›§öÈ—ÌS²ç¥/Ñ“Þ\JÌ$†'‰eøí9¥ °lP´í¼=nh¼vël~J¶¿EËœ—±ó4Ì‚øø\lœpJf—rÒÜ p̲ŽòŒl¬ky©ýL·ôF&gýRá9ëwOyb=±c–;âñ‹Ýˆ4ö& Ør¦ƒ\7Eå¾¹ªYÞÐÆ]û§«>Sê¼v×·À»qÃ4¥áéZÎÜ 9µÌÕ¬«ùÁ7g¹½ß)ßÍ]Nêg¹·)çòÆŒ窳`{ÐÀ›ÒàteS®àÚõÑp‹IàL/e¨ëºªïÞ/²noÍy ¼ÇtÖîÚçOîU×µã?Õëì@àEð ]É=p4Æxáäž?¹g' ñ<ñ2^rx÷ñ«0‘®Z@Æ‹ »’º®«ë7Ÿí@ÆËxÿü½Ìz}ú£Ø}öÔ3Æ€Œd¼@Á 7P‚³Ü/!ðÂBúfˊͳÜõ ËÔu]]×çx´m±ÀÛÕèlõZÆ-¦Ö;òüª¤:þíó¤™r‹s¦Ô1~NxOôæ´ÅÇx¿|xùýg( X£9ƒêVÛÂñ²âæÜÜúïØqÆ‹L€oìʾoü«/¨Í'‹u ‡Ÿ…uéû?)ué«sع䶳Î9îØ›>NÔ,]ÝÑ)eRdÎ,¶Ýxƺ°S»µSëÜŒùé†Ü_G)C-À‰2Þ%njêË ÛâV7©LÉ®ûꜲ 2©}âÒÏË=¸¼¹ýá÷÷~Iún/ÛÓW÷vÙðû1Ëáà·ÝMÚÕØ =v»‘IÃç ºM0¹¼¹­.on¿ÿÞþ|o ˆöv…Ûû>u9œ ð¦\éÑX†+k t]C áPEû|öZzÐ=S6nûPð¥l«ñ¦Žq…ÙmÊc;á²×n¼¦~µ&rs ãEÐ]I]×Õõ›Ïv ãe¼Çþ^f½>ýQì>{zgŒK~Žd¼À¡è*§gy¬QÆ xŽ^Ø¿¾Y®úfÏ2Ἣ5Rk48)SðiÉièjŸ“Í4‘Î;8®"ÆxÃÉàç,'Ç2ÚåÒË›¼^VÜ>ßÖ:ïo1Ùœ:ð†Ýp±f±îä°LJî*ËFúÆì¦Ö9u]a9ežÃŽ PDàßjÞU.ìž‹5n9»ðbÁ±]Ÿ®À?¶Î)Ë¡\CçII¼D…œåѶ¢n®JmÈ–j¸ÚuÈÝ@æZV×râ}⃯ K 꺮®ës<ÚVLà »’·®Cê]Ïk5Ô‚,K+õÍeœ$ðžèÍi›ÞÕ¼Ç;:Ûun~–¾áºÜñºáESì¢.<¦)~€À»‹Foõ‰5Ô©ÛД”ËѪcî?táØõ8QìF¬0ÛèË>¦¬cL™®F·«Îºš|s•ÞìRêgc°œ `®2)e5Ü/pb—7·?üþþÁ/Ißíe{rÖ½YöÔe]ÞÜ&ÿß¡uÍ­ /™•<ëÛƒÌy{¤ Û4Þ—7·?‡öç{^@Œ zKîë­ë±æ…†ÀËi<r¯º®í‡©Î2¥^¬QÕÀîóÂÁƒgϱ Ðò)åÖ0)ëZ3Ó³®®}»˜êû¬¯‡@æ›î'»Ø:{î "M7k¬\{]eÆÖ©ù‰özÆÔg‰ý3v]¹êÒµíaæn¿À °`Ðí ˜k6Þ¹øVYíšÖyt5‡äG ‚aWûVA¶Ý°ÅE‘ÀË!yQþtg™Q¥Tk€ÔqÏ¥z¶¾Ë:6–½§»­K£«Aw†º®«ë7ŸOàÂqͱ(\NÎq¦Ô‡eö©c!ã%A©³Ó<þôG±ûìéÉž1Žu;N¹»5\Δ ›» ´o9]ëJ©ÏZÇa©åŒÙÏ9Ž«À Б±ŽýnîrR?˹=cË-UŸ©Ûžso—`;LW3Èxaÿ†f°ê*k rÑõ+ð.ÞxYÞ›ùUI9þíó¤™Ò9CÎà‹À»Hã{Ί›ó[ð÷tÙ‡‹ΨäÙ©@à-„X—t˜%ù,e9í²}ËùÊxtß?øåûOW»œð³®2í þŽŒ`wíØ@Öd¨ÍØpŽ,´ù¿‚ªÀ d¾ê³-|#™i—•,Çf¸©Avx»¯¾iøÖn¸ºf 2¿*)Ç¿}ž4ïævÎ,|»îhÊ<Ûÿ¿¯¼ –!»ãýòáå÷ŸX† ¡bÏYqsþÆÎoòß”¬´`çf¿%-ïé3 ¬Lx(smÊö}7w}Äo¯ûŽ˜ã*¦­Æ\ØÃmy†“žX|GD[®cnKï%»`Xç­Ë ±%vÒsÍ-Ü·œÏ.]'zWÍ{h1oßz¨¹ƒp Éû®¨1WÝ­®Þ¥÷b/K]0bæ;uÙ>ë¹N{–üppM_( ½Nðüê;¯\W»ÝÏ/®ó©ŸhOóô>vºTO®ÇL3'Úí>e?¤ ÅØ‡sKµç–áºV»§ZOÿ¡u°ÛÁ©Ó¥šOÌGÙb?6·÷‡2]ëúØàÜvH9/ü‡À"ô\Y½76T³ötá ‰nwÝz²7½´šoý~ùòeÕ5 Ë:?ЪëZc@¦úÆWëí¹žõL°®ïæê²ºx|¶/€|Ü}øÔù †SèÄ&€ò¾»ìâÓ ®Â`Gáúôú]õÔøÌ¡ï}ïû<¿ò–°lD½[àéõ»êÂçÉDè!‘Ý\]:W78ëºþæÓ£Þ-`g!XóV×uuWWÕ{çj6ü‡EúÛÍg]þõïÍ×áúúgEf¢k®@þœ«……+ ”Ô\¡ Gx ¤oÚ˜¡¼úžMz®)†m9ú:w­Oß:Ž]÷)ÛZâ>=’¡}ÓR;4\wÌH{Ê|µpUÇA€–á)vSÂ84ÄLWxÆL#\ÙPO„côXÇì=¦‘uÍ5vм˜ÜÎo·ïšO̲ú¦;ŸØõY¢ýbêc1¿S»Ëi€»#¸˜8ÆÖœ^.ö\»j@Swþyp»¡[™¡e…¦‰™Oß |sêРc 웾ýóÐ|Sí/¶¿Ë±ïVè¹îá_êÆ^Á×èQµëRG:YFªsµ9Ž™ýµ`¸n¥Ô+§+>mÍ5TOÕ3{ÞN9çjèYE_ovê4ÂõàRk\í‡c¹·ZÛÞEuµ×pæ}õ÷ætS§®Zªæz²Þ7v}h'Î §Ø§ëKÏg̲Úíêéõ4ÆnŸ`ÌOû\³b§54zä]„÷¹R’ó+½ë[ç·býòÛoÎՕǾ÷¹F}Ë΂BzKÎղʓº®«úû²YŸx—*¼[€¢„ÊWG÷þÍ+çj‰=×fÝõ¼}ïû-¾ÿå·ß´GÇ÷U£îG%š˜Z<7ûãW€ø´EÞŠñœÒžž+ÖÄêºþZëCÏ&Ëé?´z×qÅÿܺöY[=Wá €²Ð/æU©¦ažk‰Ã/ç¶Î]ë3gçnŸ!µ÷¬¡ñ±RMƒ²¸Pñ<‡ל3 ʇâÖ ÇÈÂ54 A×U2tKÒæ¤}  -«oº±ó‰]ŸµÛph=BCsǶǪ]Ó:©× ήq­ØiY 9¾ýÜÛ‹óA3t+3´¬Ð41óéÜmn­t¨öZŸ¡ðjÏ'zc–³lÖï™Æ‹†òQ˜t¬qÀ´ëRs·kO½ 'ìöí:žëË%Èm½Ýâ±Äñ$X ×P=U¯kÝõ‰R™ýèP°öÕn/;. luuÎíàš²>KnÃÐIìÄÜî'´OBÓ^=ƒp =Éîê-Åô¨Rõ̦©æ“²Ç:´>1OðSo—“¯Ì;®1ûÉ>c˜=šÞPÎñ$:¿rÐ[±¾u~+Ö{ãh­~<æ`eʹ]̩ܣ®ëªþþ‡ìÛöÞ±*\°¥¸¹º¬îjû¬‹’€p!ÂWá pXj®ÅÐÚœµ?_*\a¦_~ù@öÉ+ Wá \H'ÛZ%¾².×÷»vÙÃkã^¼ø±ªªªúòåwg2•õ­¤Þã Ê@aw)z®ßú½ø¹oèëö˜î¡¡0B½Â1Cj ­óZC¢Älwh}bF=ˆYÖZ'f³”Ð,/4§m—úNð®yõýžéûïÅ‹‹jËâ{®Ÿ?¾ýæ«/¼b¦o>ͰZVhš˜ùt…þÜí ™»œPû4Þõý–¾|ùý›¯v¶Ö5Mówͼ/¤û–ż cIm©æ:Ð M9ýœuš³¬Ðß¶ƒµ=ÂçÛ›s=öˆz›yíí²,`½Ù²·£§ºl[–¸E‡k¨žº·^2óNΡºhLêÅ‹ƒ5Ù=ô¶rì¹Æ´yŽ|Z`f¸§óTó™òçå§ü(Ußv Õ€sévÝuèïôdÓ”J»heßs =Yï\¯=mŠ9Õ@~9Ø^§¹õÝTóJqëØÕãœÓƒjϧýpkhælI.nooŸªêß w÷›¼r0T^žÛ¸¾þyó÷¹Þ?<>{¯ì݇Oʇ- @.·¥nù®°PÀB,e=WÈì$®çæê²ª®^i”ô\!s÷ªªªgŸ/®0ÓÿD@~r¯½+ Wá \8^#¨íb$ Õ÷j¿9ƒô…~–j}¦Ì/‡^ʺZõeÊ1oÂ3MhºTÓĶ]ÛÐ]ËZŸæ;öþïÄ‹õ\çÒמvêûXSœ—jÀ@– »­{E1ËYçTÓ iÞ8â¡érÛÊ3zŸä5ÊêÖÁºôI=Ô#¬C#ÍΙ&Õ6Né­‡Ögʺ–Ô§Âã<éR!Ûì‘ÆÞöÇŒ¨:õv=¦$;’A¨üÒWRˆ›¬oý†¶?Ui%æ¶r­—\7ç™Kìåßçu.­”PDÏu­žÙ9ÄçÜö¯U:ˆé±Ž)¿ÌO_`o}×Ñî%-.cÆÕÊuÛc~¿ö©ö²JêÁž– ª-r©o׌C=²®1¾ÆlûïÖxh•rÍí_óbÙí]齬)·½Ökõ"KÞW§%ƒjOO²KÞžT½ÇœkßCáq™#¾ð:fÛÇ„ïšOüC5ÛÆ뜞éGd-©<“:XÛ·ÆG Ø’·½]ÃVsí8!ðÄ¿½­9öt»†õîú˜Ü”ùŒ]‡ÇÄ”'ÙSëv)žÈÇÔASM“jÛS®ÏØ^rsºÒ. §­B¨ëäZ"„ú‚d©ÀKÝãªï†¶k¨»JSæ³u¬+4Ú'{ó]â–6ô9Ô® ªƒ¦˜&å¶§Zç¹¥’\ÜÞÞ>UÕŸox‡ÌÝ?Ë±í®¯Þü}®÷ÏÞ+{÷áÓv=W(™PÕv1¼¸@¸W€ÃRs¥8¹•âÜ\]VÕÕ+ ²€ž+dîþáQ#l¤ýyN„+;³õ?•Z·²€p®W€­Œz zÿfªøJVâö”¼úÞMz‡hßïÇ.ÓË[H®s‚të“oANÿ;[C¸æøO×Í:J ô½sÊ0\CcÞ÷ ù2õMûSJ¡ùt ½do¼¯ Æ´as4®õZVßtcç»>k¶sÊpìé ÔCžºÌ®žxèg¡õš2Àß‘ÇK黩áÐ7RÌ8RŸ?¾<©ÚÓÄüÍœù ]R÷Ø›_s–w¦k>ÍmZVhš˜ùô ³—±Ó¾|ù=:hΡ”bÌ­˜î[VÌ4C‘%Ö]ÏuÆí|Êq¤ÖÐ^Ï’F­»~klO³·.µÃfžØV½½ËÕS͸,ÐXuÕ¸²€õ^.pöø„¿=`L¹bJùCàf®Í²€€íï%—Zöc~ÛÆ®Þù˜pœ[/æÿ-òOKÕÝRußžOLxOá¾DNùÛ½Ôc·ÐÕkMõwÍ¡¸Y¹çó +T¿ó?Uývh>)ëÄ¡öi/'f]çô4»æ3¥N›b>KL×÷K„šËê»å[S:P Hïâööö©ªþ|Ã;dîþáÑ+7r}ý³÷¹ví÷ÜÞ}ø´\Yàè„+€p®‡e -Šc,'„+$vsuYUWžX£, \®Â@¸ \„+€p@¸Wá €p®Âá \„+Â@¸W„+€p®Wá \„+y…ëO¯ß6ôû©Ël~¥œ7tW°j¸þôú]õùãÛg?ÿüñí×4ôû9Ël~9¶  ½ê:f×Üþ˜yï¹ý—Þ¶5Ûî´äŠŸ¿9`—<Ðæ{Ú~Ç|&…k¨WªççRI3äÛËh_š¿?¯SìßwmGhþ1¿i÷©Û7´þ]ÛÒ÷÷]ëbýÆ^ÀÇ쿘õ‹]~ßßÍÙÿçßÅ´ß”åÏÝþÔÇߜퟺÿ‡æŸmϵ}B. ±Áßþ¾kg…¦>}aj1mÔæ±óºŒY‡%ÖoJ¯mì>‰ÙgS·?fûB¿étÌ]þœíO}üMÝþ1?vþY‡kè@Êá–i(Pæ®shþÍ£¹ÃSnï˜À\£f=gý–Øk“©·?·’˜íKqüm¿-K(§© :ç °Evè6wJ…J#C;{©zôØÛ¼’Nî˜ý7tlmuì¥8þJ°äñ_Zûÿ9×9;öoÛŸV»Œv0¯Ñs쪱†>ÍQúþÚÆµÛ ´}GødÀÜãnûmÙ¾“ËS{¯sè®1§^66܆–?÷÷)z CóSÏëzàÕ>(çÖ+—ØSKCÛ7ôû±û¿oú¡2S—¿F¯uîñÚþ¹çoìÝg*···OUUU7W—ÓnKJþhLéë_JI€}ºx¬êº®Þ¿yõõgw>Íë¹ÑÖ= ÂuBÀÚž2·Å…5yq €p®Âá \„+Â@¸W„+€p®Wá \®Â@¸ \„+€p@¸Wá €p®Âá \„+€p@¸Wá €p®Âá \„+£ú~q÷á“Öxùòåøp ýxÿæÕ¸p½¹ºÔj©¹Wá \Hç4fâû‡G-¶×ã˜>î´Ñ´só;a^êºöcÁšÍq§¦Ÿ›§± øÛÕÊKîÀïÐ+sLwÚhü¹©æ °á \„+ÀaRÏðïÿùßg?ûç_ÿ’d~sæ3f—ZÇ5t^œ?ô³R¶/çu^k]ë¹þó¯ùºÒ]Ö˜F˜;Ÿ1ë³NK­ûÖóqs<—¬)Îù5Œ9ß³. ”ÐØkX•¸®k…×áÊK•ú~·ÖíV{9}óH]A°­,*Æœ_¹œƒ§\ óíöØFèjØ)óÛïšÊíâ¸öx¬Äž§ÍŸµ§‰9¿r:³ý´@óêSrIÁ-)zy.,å_§\¢æíA¨ñr:ÏëìÓ¤8†ötܬ}žæ §­¤%Ê %ÜþÀQv‹ó4‡vûn‹†í›®´Û¡ö:û˜©Ã!÷ã©k=×<b–µÕyyZr£û®"©nŸûæ3všØOtͯýebÁ½]Ûs^,ÑŽ1ÓŒ9ß³ רŒ™n­iæ~BA²Ä1XÒ±4÷‹Ýþ-Î÷lËG$\„+€p8¬Q´êº6Æ»â˜ÖF›÷\ ÷¼ž÷o^i„8¦‡;m4ýܼ¸½½}Òˆiœ‡ßVsز,€p®Âá \vâTUüÆ]­1’õ\ýó@Zïß¼ªþ$kÒræ–wZIEND®B`‚stella-3.9.3/docs/graphics/space_invaders.png0000644000175000001440000000576011433323254020633 0ustar stephenusers‰PNG  IHDR^ë®9i?gAMA± üasRGB®Îé pHYs  ÒÝ~ütIMEÒ,ª7ÿX rIDATxÚíÝ;o#×`‰rxÑewIĩҤ‹;'€påÊ¥#­ëþÞ_à&D€ti.*Ò$…›@Zïzw-r˜â³Nfy %êÂ3ÏSE}¢¨™—ß93st¸X,ÞÔó¢ Àu×øžöÓ&2àVîðao|˶ûyz|›o p¿Ñ7ÚgDÑ>ÖFCóÎ/ྡྷa) Ò§-3¢ØUû</^¼¨ïÿ‡5‹Å¢e:^GÈÌÅÅÅR"öz½øØ²  ›W¯^Õ!B¡ßï§õ˜Ø”¢róòå˃ƒƒ^M¿ßï÷û½^o±XÄÇ~¿_UUC:¬‰s‡°×ž?^Ï…âR¿ß_,Eñã^ßœºÈ0b슢\ª¿ñÇcbbòê®!¤öÔÙÙY R( ‡Ãáp8ŸÏÓÞs Ñ5ÄK±Ý€bôÅ[;yê¯>û6Ë?ɾ¿>ùïvRç·Oÿ–åßw_^Ÿóóóh"ʲœÍfUU¥#—1 YѰÚ8,Ÿ YUUUUƒÁ Ë]K´å½k‰¶ðå—_Ösa4F£ñx<'“Éh4*˲,Ëh(Ò1‹åãšõhˆÑDC4lÚµ¶Ý»Ö5ìËë³i×ÚvWìZ×ðÐ^Ÿ§OŸöûýGD.L&“Éd2NãÆx<.Ër8F4Äè#õ׉†}ßµD[Þ»–h Ÿþyj¢Y˜N§GGGGGGÓé4"z‡Á`ýEelŒ†P ‡C»–®A×°§¯Ï§Ÿ~ZE´ õ\8>>>>>>::ŠÞ!†qP3uÍhÐ5èt ß'Ÿ|’F“É$ráääää䤞£Ñ(ÆEQ´Š†ù|^–¥]K× kØÓ×ç£>Š£•©e8>>>=====M3ñ°èb>rc4Ìçóªª6Eƒ®A× kxø>üðØhˆÃñññÉÉÉééé£G""&“IDCêê)Þˆ†êÒ¶]öœ×ð0_ÿòx}>øàƒ Óé4:…ˆ†H‡S¤ã;ˆ†}ßµD[Þ»–h ï¿ÿþp8¬GCÊ…Ô8L§Óñx<b®!ÍD6EÃ|>F¶cØSï½÷^І4ÑðøñãG=~ü8ECÌDnŠ+JCnâx¢æàò¬¥ú=ÍDä&åBŒ–¢eÑv «-öED шàGK‡!V§ÚÌAˆ@4¢ ?úúã·¿þømõÕç†ò¼†"¶žw¾úæ_U_ý}÷î»ïÖ×q999‰ «žP4oRꫯkhèr>BñÎWߤ­¤~{WSYêç]¿ãrPÔ·ÛØVÔÏ»~Ç9¯èX×Ð|pK}õéP44o7ßhÔÏ»>‰ec!7ŽP·E4¢ €hD €»×•k(êvuežúy×ï¸.^”}ó Hý¼ëï;§<]½q,m«÷¨¯>è¶=‹~Û-Iý¼ëë2ŸkØ´:àêÚê«ÏZÖ†T_}: mV¾ÉZÃêç]ŸÄy €hÌ5ÜÍøSý¼ëw–Už 7NyÌ5¢ €hD Ñd-ÿ³!oûÊ<õó®¯kÈ-.×oþªúêsë*OÍ‹y´¹°WýnÖσUž®`©õ1 v)ÿÿC±ií@õÕ§CÑÐ~³¸ÉdêçZŸ$çQs{kªŸwý}·“iÈœ—rÑ0«/D°Ëhp„XC4¢ €hD €»—ÿ5«v{Êú¹Ö︜O”nvóuÕϵþ¾s6äÍê’«›Ôõ–Q?×ú¢A×à]W}ÑÐíË«Œ¥Õ €»bC¹ÕDÕÏ»~gY¯A}õu ìüŸõÑ5\ñîa©õu ¦!A4XÊØ)ш@4¢ €hDð XåI}õYÃz ꫟'J_±Ñ´¹\÷æ« ©ŸS}Ñ`®0× ¾ú˜khØtVU_} À©¯>m™kDÐNnŠMSS»š²R?ïú$€ƒÜ8¯0׈@4¢ €hòáß᪯>kXåI}õsc•§Vï!mîQ_}ÑС‹²Wß[v{¦½úy×7 Èv@±éãæK}¨Ÿw}]Ã#ÀZy(n{!0õó®ÏA.ÊÞ´ív…Bõs­o@û€Bó¬>€p'D ш@4¢ €hD ш@4¢@4¢ €hD ш@4¢ÈCá%hð¯_ü4ÝþÙ?ÿî‰Ûûõüë<t €®ÁûÕUÏ¿þÕ‡ü»ìûó×5º}„±.º@4°uÑ<ш@4åŲö“óèºç® €hD €}àE“M³ßûr*¤ç®Ð5ÜÇ;Õ¶ñü»ùüu €hD€hD ш@4¢á.Œ¾xkôÅ[þöР['J×!n¿úì[è]Æ~aõ~½t4bç_ ¡€®áª¡ÄêWuСhØ4”0¬]C«ÇHÌ5­»†Ÿÿfϯøçÿ¶}dN¿5]¶0 hôŸß=I·Ò> ÈÚýËtû÷ý‡Ä€ €hDprž†4õȪ.L=^JŸ¦õ,Ý©k (ÑÔm¢:ó†ßëE(ôz½t{ÛŒ a×PO„ K÷l ×è=€‡£_ÓëõÒÕ¼h°þàåßÿtöÃ?¼~ýúåË—ÏŸ?ÿî»ïÎÏÏÏÏÏÏÎÎÎÎΞ={öìÙ³/^|ÿý÷¯_¿¾¸¸˜Ífóù|±XTUµXüÿÚŽúmà6„¥N¡ßïEÑÓ¦&¢~£)–ŸFØÔLQƒÁ`0 ‡ÃØùã E.ˆ¸—hˆ~¡×ëE1c'M1QEÜn9 (Öþ¤”.K¹~äp8¼¸¸˜Ïçñà¢(ªªŠOEÜW4¤½ux©,ËØg#ÖŽ/ÖvŦV†(‰0G£Ñl6«ª*Ba0¤…®î+BêëcW «QÏ…µ}D±éçÅwF‰ú"r!„øR|*àDCjðG£Ñx<Žt¨1R4ÄǶŠôД  eY¦Ç” 鞪ªªª2 €{PÔ£!öÙñxœÒ¡,ˈ†”k‡Ww 1ŽHÍÉl6‹qDÌvEa-C:6!à£!Í&ÔÇ“ɤaX±6–PÄÎÜëõ‹E=ʲŒý?õ ƒÁ Z†Ùl–[.eh€»‰†ƒÚü`L¦=7Òa<—eC}&rSï°q@±4Ñã…¸3î‰I‡¥3dÜcL,ÝÒ!"u ƒÁ …¦3 Ö¡X,Q=ööÁ`º‰tÔ4Z†8f¹¨ñ‚{Œ†4¹t!‰®!)ÚÎ5Ô[†SEQŸ€ˆ1L:*¡e€Û8,£˜Ä4äÒ¥Ww ©qˆt¨ß™~Lô IL+¬Fƒ°€;›k¨OôjŠKõs"ëе•7žòÔëõªªê÷ûõ™B¨M.ˆ¸ãhØ”iÞ1¶Œ3¦—Nˆ|£Î¦½7öö)ÄÇ;¤DD¬³î7,–®uˆ÷õôqi4±¾NÃ.Òáàà 5õWÎ/È ¸ã®auÞ!uK7š¯³:¼rß^j V;…æpñǃ»†ú‰L kº4U¾rï­‡B}oo3Ž p]ÃÁºÓ%[®wØ~ï] m¾¸ûhXzÀ¶kC^cïÝ6M€ûІ­vÓh²gEi@4¢¸¶ÿ]ĵäi‹QIEND®B`‚stella-3.9.3/docs/graphics/romaudit.png0000644000175000001440000000617011433323254017465 0ustar stephenusers‰PNG  IHDR–²a²égAMA± üasRGB®ÎébKGDÿÿÿ ½§“ pHYsMœÞöœWtIMEÚ)ÔX!\tEXtCommentCreated with GIMPW ÃIDATxÚíÝ¿n7pÚØÆü(Qçò ¨¹ëü ª !:ÕîŒkŒàª”iõ’ÒRJo‘t.}…ou›ñ çã çïþ~€‘xÍåßpù 9#í‹”Ò×›÷7 Æúé??¥7ïo¾ c=>=¦”R:_¸¾º»}úöß—B@M    ”;D ýüë_"µ3žK,’Êþ<>=¦Û§”>þø&TÞŸÃsÆ!ZéÛÏ¿ˆì^ÈëËâ÷|ü÷µÀÁû×?oÃeÝc *‰‰‰€3q˜¢Òwü™îx]µ¾”Òwuv½¾U[èÏ«Wÿ¿ñÿåËÃß^;þ=÷¾\™%ú±D{NcØÕ†H™-ö+–Q“ãñ¿k˜¬×Ò–5¶ḡԜüÎ%©¼zuî{›/_z)#©pV+–¹ìe¥²E_¾<üm‚5Q‹$–¶­žÜk}õäL³ÌÐm¦¶¶DŽ××§\{Jû7W‚m&H2É%ž¶«þÓr§ïmÛ‚‹ÖS»=}u•´§Ö dlßaµ‰åt²­»ï[-#ý*u.]Ç‹Ä'úmŽ%1šcÒ.=Öо×ì÷кjÄHò©oõ7ïû>Ì‘-µmè|Í2¹÷ôµ¹/I is¤Ñúº&Òä–»'©£«\¤=‘øDbiÏœcµôX]%ã%rœ±ç´« g”XŽËÐ%–ícnh®aÛ­³)'¡1‰¾ïAæ¹Ò¯}ïjÏâ¸ôç¢öçs®sZ3&Ô†¶ÂN· ¦:q§û¨sl/°.k»áÞ7™Î5V·ü¹ð…ÄR4À§L.m«ÉeÿÖvŽ#[¥sÕè±Öv“Ûçv?^Î1P¦ÚK®UoÛ^îRmlƬæÊ¯F̆¶gH¿¢Çª5¦ª§æXÜ3)9VÍÏèZÎi´5ŸÎ‹›÷7_SJéúêb’yâ¤ä=%õ isô8¹cõ=‰ùÁÏ’§«úÚ4æ ˜Ò§z¢7»ûú\Ú÷È“s¥mªõ¿µÆj´o5>_‘¾¯å©°!çÞSaÓ¸ýô¹~baæ|Ão&ØV¬j®PŒ¡}%–ƒPÀö˜8ÅeÍüJª²@Ç­0+ª’XXXX@b@b@b‰‰‰‰$$$XXXz\¾û.ß}Xìý,ã0URI)¥‡û»Áu<Üß='—¡õ´µ#×¶®cu%¸¾z›¯Õª§­]cb}ÎjŒUœci¦ËVEn•ôp÷ü§¯lîý]3ˆ­î¬zÅ™Ý&–hÖŽ Æ-NšµÚš«§cÉe¸1Éhw˜ó`}[:{ù€Ù¾ZOW¹ZÛe¹zÚZtK±kËoÌñšÿžÛ^ŒÄ&Ò–¾6½˜Ú÷\{JÚ\rÆ~ŽûÎItœ•ÎA]«ÿ!ãpªñS£ï›^±”®@æJ*%+€1WþµVkZ…”Ü+ê*sZGW¹¶vׄÓWOß–ct¥íûñ"`èy‹Ä'Ò÷’öô•‰ž‡Z«¿\¿¢ñ™â±¤=SŒŸ%ú¾©ÄÒ•@Ö’yûNÔqû®/ÖêO´žf»rÖ±I%2¨k&è%·ªJú>EÇô=ò¾È*휷[ÇžÓ¥ÇÏÙl…õ]9­a õM˜ÑV_]µÚTóXkHÞsÕ±Uç~͹—X²¼ùÿS&—Ü_mW¹öÌÑ^Wñ«Àsšlιï{½²ßkß_NÕùܶLôõš÷_jž”¥·šÇïûÙœ1ƒ–«ô¼Íù˜êc éûÒm^bŒméœn!†{èûaé O}ŒÓ•EóïK/eÇ ´Ó•ÓÔñŒ+÷TK³Ž¡ã «žÒvGÏÅ\qŽÄ§¤ïsž÷Z1Ò÷)ÇOzjĦVßçôâæýÍ×”Rº¾º˜|Ù>çûYv‹8?·Ÿ>O»b;ɘ¤¶É¯t ªƒ°ôê°b‰‰‰‰$$$XXX@b@b@b@b‰‰‰$$$XXXX@b@b@b€¨ƒÀyúù׿ᮯ.Äh`Œ¬XfÃãÓcºýôYŒÄÈŠøÎÛÏ¿˜4__ŠÑÈY±0)‰‰‰€3áæ=Päݦû^W­/¥ô]]¯o-VM[î 0ÙDÙ6a.Õžµ´%çþ‡×Ï e í•X€]:Œ÷Ô§sH.¶Â€ª«™Ód{­¯žædœ+³·m³Ü¶`¤\_ü¬X€U&Ž!Wݧut­H"+•f™­¯n¢±=Þßj+×Û%VG 0øÊšúI%—¶’»µÄ¿4[aÀn’ßÚWRm4·¾j>ˆ°TL¬X€jWÊ}Y¤LÉ_ÍúÖºzÊ=ÉU«]±]"& 𴆾VZ¦t"\óV\IÛrekƶÂXXX œ›÷p¦Ÿ‹¿Ë\Œ°bZ]_]‰?¾£1²bOb„   H,H,H,H,PÁ!¥o?]zû$Œ÷"¥ôõí?ÞŠ£ýöûoé¿éãiâð’øIEND®B`‚stella-3.9.3/docs/graphics/options_video.png0000644000175000001440000002046112162610274020522 0ustar stephenusers‰PNG  IHDRÞZ°¿< bKGDÿÿÿ ½§“ pHYsaa¨?§itIMEÝ 8TÞ™tEXtCommentCreated with GIMPW IDATxÚíݽŽÝFšPJPè@è!ÚÁÀ‰:•°/°Šæf†#% Ø¡ &ët’âÌN„`R>D«7è j©ªÈ"YÅ{ ØÝ·šÿU_}E^Ö£ïß>ÜÞÝ7À¶^ßK†™svÐbËÄtœb;iSשNP|à]{o.gƒSþùÏÕ‘‹í¤MÜÔN# ðšAÅf)k÷#—AZÇ©ÌÇWL™-3ì½;‡€À{X£¼çr¦žä½Ö`ÏoÝ)Êp÷ç,<6‚/¼E5ÚKÍ-‚(²ë-×c¨Þâ3¦\YÃÖ˙ʦø²ÅœŸ%eœw išæÑåryhšé)ÿºiåL X§ðüu/Ù_2IBÊ(ÄÒûÜr.3Í’·þêÙšó§«»f'"9ÃÏYnëuìY&¦¬l0I¼ ð+Þãín7MÓ|ûí·ŽÔ ôÏéÐÏÔ}>²Œ=9xÃ`ë‰æz½¾yÖÜÞÝë@ìÜ9 ¾O¦kÎ|ØG÷5Î!îñÀŽ^x@à^x^¸§Ÿpln×½¦g»¦ÉÏsÌ5»å6Íkª>ÎhêgÓ¶mUóS_Í|¼áêk&j'®ƒqôqîo“sÎ5úå—¿\Å~¾|ùsUÛk¨™«ètÿñÔPOeÉýìi¨Llþ庖,'\ÖVYaìPtÎýš[€Œ÷àì¨û7ºáÊ¡2cËI]Wø»”u¥.çSÇ8×¹ñ–Ñ.Í~öΚ¡ҭ–sD6¸öÞkÊßì‘ѼüTûgÆ”k]gÍòrïW8,Mþó²´#4ö·¹:ËüáéÓï¿úݧOÿ™,7ôylÞ¨ kÏŠk]gmŒ4²ç>?1·ÜBÈtûAòéÓï›§O¿ÿêw]¹¡ÏcË0íñµ6s•¹ Ð{e9Öµf9Ýß‘õÏ5âK¶+<Ͼ³ çÍÜe¼•gÂkzõcËÙs]G–”홺ߚs¿Âe¥Üb óv¨¶ìøÄœ¿½¾Is]suek1YìÞ™ntkϲ].—‡¦iš×7Ï´‘áRþ9Œ <17暘*³®Øí ƒÜ’夔™û»µ÷öîþó 4Ɔšc~7üŽ ºCÿåËŸ‹{sÕíÝýWoÔzóÛï2^`ùGÍÛ6U&×7 ¶ÞÎ-ÛXFSæÈ ¼/Pu`ï[.K_’Sºîa©© S戌Wà… ³$Îs]mý^îÒ2ÕkÑúµgÀ/P­¥Ï äzÞ`í=ê”ÌY0ÿÿà[û°³À dÏçžîŸzUhJ™˜¡æ=¿IPÚ· €×ÖÀÎp¯×SÍ'Ôªùìj{ªÙ$ °£¨Àûðê]óÐ:ñ³Ÿý\ÖÏ@=¢†š^½k¹±ÏÄ ÇhÛ¶ùå_ÿR?¬—†š=þ«^ ¡R3çZ*x‰ Žú uñT3À‰;fTx 5C¹ÔO†¼¾yÖ47ψyªJ ¼zÓe[;îÞóð’—ú 2^vºM³îÍ8CÓ•­Ñ½!§ÿïhSÛRÊ6ïg¾'HJ€kš?^ëÖýëÿþèm:z[¶ ~B]<Õ|ÙnL¹þ;fÏô2ö0èößY[Û;_KØæÔïl{-, ¼î!'(çš•%G0ì››t{¨\?¨¦LVãKÖ»ý ¾{ÕÏÔ Û¶mó¦mŠ{±ÈxÙÄÐ,)%Ý¡8”M¶=–©öWk6›ÒQ9zÿb_–’òÒ©éïrOá7V_¦Ê­ÒoÍrjèгAàõ=ÁºƒoéíðoÊßÔ8‘öÜvÖ^?ûù·;RçÎ]²M)ËÙ3˜ œ2^vªdáïjªt¹„ ‡¥k=gÉèÃ@Pâ³¹¶C°#)ðÊvëÏ"JmÔrf³g5wûlõóZTØ1Ë’ÃzÝrgû ß¯kêD䇞ÿèç±2Èx‹Íf§z¢¥mOÊ6=5öYi½å¹áјû¥±÷T÷|ÀéÈ{Î×t·zº~MÆ=õÐâ\机²]·¨èÒ‹4GeX³®-+bÎõåªð)Á!¦lj°ÍœÆ:רï[f|SYØ‹¡fxkÉp›æËWº™‰ÆÞÓMy]íë§nÞ\$KùžnL‹þÍõp·¾˜ç*Ö¬'u¿·\/P©¶m“ÞH•šù¦~VÂúbŸ#Éõ¼ /4MÓlÒS–×7Ïš7mÚßœñ=ÍÞb…ÀK rsãEø×À„ͪ—o€À °0ø‚ÀËaR§‹#Ÿ¶me¡ ðrb§Š#/÷Ö¡>¾Ç /¼€À õ8ä᪱w‘NMŸ7T&\æÒGüs½ŠÎ«ßþ07%`)ÛwÄt‚‡d¼ýIŸ‡~Ž-¼µ/_;õÔ6.íÌmGi/UïšîßX0îϵ ð^±5Á—f0Û•ñm3’ÔÇ÷x3б s9áçC¯§‹)“²Íýr[‘‡dl8vnȺÿwý²1ˉ j[­kÍ1{úô{xˆý)¶Öޱ 6ÔR×7Dûˉ™ë3¦L̺¶Èn‡†ûÁ"~ $CAm(ðô–ZGÌ=èp9á~õN]WŽŽŠà o‘Ùèše\ÛƒQ9÷76`nµ¾­õƒñžëÞâGއ«¶î[,«¤uå´ç=͒þ”8pE7JÍ9Ü<·®µmÏŒºÆì}«aÛ£×µ4㺯 ¼dê{—É5̾ô{«¾ï|x7F)Aeë¬qî;³1Û<¶œ±¨úeSˤ¬+w€˜z¸j¬løVŽïùÆ,gÏu­]>P¿G—Ëå¡išæõÍ3GƒEnïîM x—/6/Ú.†óe¿ùí÷¦i¼@v%ð€À /°’¯‘ÅË—?;/{x}ó¬inU¦fýcØÍ«[C…‰™¶äº9lÔ«ÌY·ùH^ü8ùù‹ÿ\\ßç‚k õ ´¶éìmem 5shÐíÿ·ÿ·¹Êœi›S÷«æÎ¦Œw£a0£Ûj$f8k®LûúeSË”¶_Cå–no˜É­‘+>ÚÎ\ÛÜÏ`c†®S÷£Æì¸6{Ö™¹åìݦÄìWÎvGÆ»ÁÉëþ•P‰>¾ûù_xaÄ” 7Õ3ï†Â¶ì½çÚ¯œ>}úOTP³¼-3¹±uõ3Μ,\_Π{ ™ïX<¦ÞíU¯rnÏÜrRÚ-ŽÿÔ~—ÒîÈx+éÝÄlÛT™î³±2¹ö}‹"¶Þæ%ÙáÒÌu麶Ì·¸{ nl6wDã=× è²ÑÔ{Ï©Ëkwr?Кº_kÛS÷„úOmBxil{ç*]Éû>4ü›;è†Áw¯ ›3ø›³ãØk2reßúÓ¦ÔÜæ ¼÷XkyB8¶|Æ}ÏtûË©ñixÿùÚîñæÊ0Ù¯=­½ÝÙÚãk¨´KzÈ%ÜŸ/â¹í ·9e޼'?\ç‚îÜýÛ±å,¹G³®\e¦ÖïÁªãÛ°>.}04×r¶jgÆ‚Mm‡($ãŠêåŽõzcËœuh¤Äý hc™ZXv,XΕ»;7ü›²Í1÷Šs•™ ¾%HýžîÞÙñÒë=¶Î„åæî»Ž•›[ÎVÇeéöjÎãÑåryhïTe¹Û»{ÓäåËŸw›÷öî¾iÛ6ùïÌ̵¶‹á|ÙÝ+T½@ˆ²¤s.èÂ×ÌN¤°#/¼pN†šÉ"f 8^2x}ó¬inÜûˆa¨d¼ÔäöîÞA8Hø=A@àåJxÆ1Ü[‡újÎÉP3-õ~¾wÀƒŒ·:k§Ø2EGݶm?¿¨ ã CSKåšRëèù0·Øž#& šj/eJ@Êû ]̃_SÂ’§‘‹~0uj¼©:?V‡SÚʵmnìºbŽÏÚ)Þ „“2›Ë±CsÌöç¿í¶dBzÊðáÅ“Ÿ§Î×»gý^Û¦LM?¤úmÙTx.èNߘíYr.ÂåÄ´Ë1Ç'ö ¼Ëu¢J:á±CL¹#²^í6DzŽ6h¨^JêiÞ„¡‘˜¡Œ˜á“¹^\¿|ì:s^TcÁvMO~jŸŽÎž§‚xê°v­n?®5øæº ?/i4ÍÈÞu©úáªïßF]¨C½Î0ÐÄ^ð]Ö8´œ~åÙ²§;·î#õ‡‘ûÿ–šOŸþóù_HcÊô·«Ö!îp{Ï8DßÈLu\ûÿæê^L=O©÷cõon»sÝ¡!ë=ÏÅmJîc(ã5²Ûv¤>¸±×~ e¥¥djŸ>ý§¨íYr<Õ«ãëêP¶½õ­œ¹À”«=Øë¾ëÇPà%{%<ãE“Ýý!­³ —otúÏ1”ØQ^šíÎu¶Ç>7d]6ßãÝ ·õ0ÍÔƒg®é#÷‡‹SËÔ~ ݯ‡‘‡êßÔPsA7,3·_gm^V7©A|¬‰ý}lÏqŸeé=Ý\Ëž+3ôu§š‚¯§š§¯ß=þ.æoÆîCïkét\sçàTO5O˜˜^eJ »à÷î*mH©u,K{X¨_&f91e†ÖYkð*i»S¿§»öŸk¨Sê^Xv«z>T®†÷LíWL[s|j½5Ë£ËåòÐ4Þ©š;ã]ÄKùû·w÷ÅN Xk†ëåËŸw›÷öî¾iÛ6ùïÌÌ5êêKÿúï^¡êáªÂ­ ˜² —×7Ïš7‰qWÐ…¯ ¼™ƒä5Ÿp~)¼§ËPÉËÃH@i<Õ 2^j3/¼¾yÖ47îýÄ0Ô 2^jr{wï $üž ðr%J}ÆÙ¹·õ1Ô /œ“¡f Zêý|ï€/°SÐmÛöóKá“e¼CÓn…Ÿ­}•ãÜ”d±ë<û{œ‡f:û A×&öAºØ¿ÆæœÎ]‡s·7SÛ87Q=ï)‚n‚‚’ç¿M™¤ºä9;¯•NÄ>¼øqòóØùzÇ‚ØÖõxk5Ì»Ëqªj/ê” ¶u¥»öŠNNcªþÀI2ÞÜiŽŽÀÚm —3ÖkN¢›Ž—•ë>}úýhf8D²seúÙg¿lêrRÖuTæÛ­oꘞ]Lý»ŽçêP‰~Éí­’ËŒ“µë’ñ^Iåšs7gO=\ÎÐrû Fÿó¡†'öþSN]p hý Õý*Ûÿ|¨Lø»¡21ëŠ)ÓÿýÐÏ{fºgÊ|û×äTÝš»ÖºÎ÷N&†ö-¦-ÈU&üW0,)«<{†;Ô©L½Ç;tÛil9î»Æ×ùÒŽÑYÎÙ“³]HgéåæŽ*%hŒß¹ œ3hO-«ÛÆ¡Œ»1Cå074=4šf¤ser·9k·YàE0c&7õµ¤-²Æ¡{¾¥ÜO»‡ 1mAÌÈÂ\™©¯RMÌ¥#m9FCJôø Zw‚Ï<„4uï+¥ÌÜß•Aeœ{­kéº÷ÜæÜCé5]×9Û‚¡{ˆglwÂãºuû1tŒÃ{³[ls­].—‡¦©ûÕn1/ÐX›-ÆT®¥OòM-7uß–ÞÏZsüöîþóKb_ ±ôIã˜eeÏ©ëŠy"ûè@øòåÏ»M ؽ¹*õsÛ·ä1u®.¬ ˜KÚmNLÖ¹¶½H-säö”êöîþ«i;»7¹"ðrüfZÀë¼mÛ&ÿù‚¯KJGéìíâXàõu" ʒι  _óp ’Í™ŸFx(6ø2ÎP3Èx©Mìp/¬ôúæYÓܸ÷ÃP3¼pN†šÉ¢{«é¼¼d¼ èî¤mÛÏo³d¼äÅ¿ÿžoYþyÇÌÓà ðŒJÝ0Œ_3Ô lt £ƒŒ·J¹¦.ó ·ú¯©ó¸fZÇT©Ó¦î£ëuŸz¬m¨,ãš4}‹É‹Ï:òšŠ1tœ§^L~­Çðl×ÀXÛû\xñãä¿¥û¸Ç>œy‚uNx÷®äÝòkª(*6[Ý¡:S¦¶Îe?㘜ѓµ Ad\ûe»a¹¹2Îg©áu=T_Ɔ݇Fˆ†êXŽu-­ßs‰ÍØèWÌöÄvÆæŽßÜ6“9ðŽ5ê5TÈØ‹wª\êºöº sÔ=ï_·ú&·\¾¬kC×}ÿwa™0˜Í±±u…óÍnÙ±MÁ˜Ú÷±ýš â:ëÛx\S…› ls÷‡¦>YNL™p8há!÷pÏ|ßr~0^ódŽó›«ósÛÂí´3Þ½²¤”¼ç°k)=ÁÙ^mÁäš»=÷]P¡ØÀ»×ðרzÂ!ŸµA¤æÊvÍC‘ÈfkÏœ¹.Å5Ç{ô‡~×Ë…ËRù(¹N Õ‹Út»­3W‡s uî¹®¹ÎþÑçØk©¤m¾ŠŒwìa£*ù’õ§<-—Óñ ÏÇØ9 ¯•¡óSØGòPs8¼󖜰òçìíÇ5OÝ YNʺbÌu¼r–wB].—‡¦9µ¿^ÙM hv¢tÝìD¿þô\k'r{wß´mûEÝî¦õ®æ“e>²€² ¼dѶmÓ~ó]‘ÛöWsÞo=#ó^ß¾ûÅ¿#‚À5ž¡sºçñ‰Yö™ÏÏÖû¦Sy=Ù»Qè~Ži¬Ï|®ÙÑÇÇùNx§²Ù˜€Ûeª[4að×Ñÿ<ÜŽp›†¶qjߺòá:–nß’ 2õ÷sÛ³ý±ëû»5ûß}s|—¬íþo}þSöéùŸ[>PXÆ«-‚kLû=K†Õ¦†·‡:sÇ#åó%ÙÞ\g"õç5Ç'fÿ¦>é°­]ÿšýßúüÇîÊß§.(0ðN5¢¹–?Õ8¤Ó=îÏe$cÛÓo ×tLæ¶'õó#ÏÛs¶óôùw£à—’ç^êÐ`i {ìp}JF—rìÌxb¶¿vGŸ`_§úol¶:tOwê©ë#‚ÍØ¶®Íȇþvîì}Œ¦öïž`^{þ׿³_8MÆ»&ëÍÙ˜‡Û0ÔP –Ø`>ôðUØ ­½ÿͯy¸jlû—f]1AbìžùÐç©û?V~îá ¥ë?¢³˜º}Sû{þS¯!`¹G—Ëå¡išæõÍ3GcƒŽ@íûêÁ€t·w÷M۶ͯ?=ÿü»7¿ýÞ4WFÀ®Þ×”á•öD3€À ¼ ð/¼ ð/œÄè+#»7li¾ýöÛôÀ;õGÀ´þë"£¯w7@~îñ€À / ð@=ž¤¾½»wÄvàÁ68žön¾MrŒ–µÛ]„eiÛÖw¨AÐ-¾MrŒ–·ÛORWðâßw”·<ß|ç @!´wóm’c”Þn»Ç ;x@àXéIîþ×ÿüïW¿ûÇŸÿ”eyk–“²Í[­ µÍì>Ÿû]-ûWò6ïµ­›e¼ÿøóŸ>oôÐ…•rÖ.'e[c¶i«í®3èvmPL[WcÐÍö Š ¼aA°ÈÈjÜÖ½[éž}RbÓú±Ïö¦ ×3¶ŒÜCíµÝœ± ¿ßS·cÚÞRÚç'¥\@ÝnêA:°K–“š¹-?ç~\C'>¶ ïÿ.,Óö–Ô>ûTs¿gRó0µ¡`ËìP§£¾¶÷I©QXaêà•t!vÛì)i`ËöåLmÊÞmx 1ãÉÑRŽ8t? ”}2Ô ¾å´á%·ÇGرrµ £„Ûì«FÀ^ûÒÛš¡íܳŒY×Qmö“-wz¬‡‘kHvl9©ebŸXZ^ø¨¼¡f`mv–6chÿbÚÌ-ŽcL™”XPTàÝÀ˜r{•Yû$µ lÕfŽñ†‘ëIDAT%gÞ¿%ûD,XÊ»š`G/¼ ð+%=\Õ¶mÓ~󣜞öÎ1:<ã}}óÌÑÚɯ?=wà@Ú»ù6É1ZÞn?º\."lëÍo¿§e¼Àz/¼ ð/¼€À ÇzÒ4¼}äMë`Àæ¯gÀ>~ýéyóØ”çƒH,IEND®B`‚stella-3.9.3/docs/graphics/eventmapping_remap.png0000644000175000001440000001556211676164714021544 0ustar stephenusers‰PNG  IHDRÌ^u/ÎsRGB®ÎébKGDÿÿÿ ½§“ pHYsttÞfxtIMEÛ 1‡ LçtEXtCommentCreated with GIMPWÍIDATxÚíÝ-wÜH¾`eŽÁ ‹?F¨Y 7l ûB³Áa†;Ð0p†í†Yfª±a†¹ W9Š¢—*©T*©ŸçœœÛe½T·õëé¥^UUõít:U@¿?ÿü³zu:¾é èW×uUUUuÕ|ãþî^€Ž‡ïyYý¦+`ÚÕØŸÎ_õAŒPG÷›°$ïà¢+L•sÃòáÏÿè‚<žÞyïä½³Y… s9à1÷ýâ½CÉÇš+]ÎQ>ýqœž÷%~0Wa€À€4V’½ùðiðgÏý±êºR/«ýà3gˆ4ë ³=îל ¿ÔÐîÛÿî÷†Þ±}æCSÞ×4gÿîéï¨Ý?K¶w‹~˜P¸np.=(øÐ”ÿu»ùðÉÁ¼óZ§ê—œý¼Ç÷êU /øÔ(¤rØcµòÉ®ûG1Öfªo|ŠäÁ¹öÁÜßDž~VaÎ6h‡Áž^¨¥Ã!CÚ·ïíïuÛ„TM1뇦½öõ’Ý¡×A„ôaª6{;îý½šå*Ùç¿þøñïhŸÂ†ö«ûG¸´"^£ïŽøšlqðhþ- ÕöëÑ·¼æÃM_›îkÙ÷ÚÆ¬k¯L–ìWÈßCȺRµ =&¬1Ú6bS2ÆÚíù½êf¡ŸŽ×b1ü”¶_C‡µJýÐt)¯SÊ×b>Lµœ%ûZ=öõéÐþ”Ö?s¤c/x®7B߀!YšŽòú—V)O]£±ôµè;µô5-å½Pê{õ"3Õ¥ØknÛÒíŽ>4õCÓÔ>„¾9·'Õk‘ºj.ñõ,὚ý¢Ÿ¡ÎÚ ]GŽ7Oè~ Y¤ü5v@¸„!Ù5‡Ý|hÚWßäÜ×u­ýZtÏ®5|¿Öß×^Þ«¯N§Ó·ªúu¯fÊ&Ó{1¥û^iмÕ´CÎÃ,­ðb\0vKq…ç’ýßò Ô}¯t¿ÝÞ˜ýz-Bß%]%Û÷ZÏ ›˜ß™¡Kµ¬©þÉyœiÖ%09\`²S ¡ïëòðu 0@`@?ÃlÏ`ýöíÛªù>ŒiÎaÖu­3€Cy<½û‘?ÝVÒ„dCXâþîMõtþúËû`ïÚ…ä•€$UhI3zÖpL˜ 0 ›Ñ‡¯wOx— êv˜UUU÷z `¡‡‡§èãéÃÓŽ+ˆ!Y˜ 0.χOßÿùzù×#óÚöœ³ª¾_ôã&ÀrCç0ÿ}{WUUUýã˹÷w~96øTUýá¢Ì…îïÞüèË!Oç¯?=#û*f¯_ßüò½——çjÉ2bࢠËÅ꺮êªz Ë>ÁÙ];à^¿¾©^¿¾‰ ½¦m_ø®¥oÛ¶ÖT—Íÿ÷U™cî¾|Ö‰sóz^þ,:‡ùòò,„rŠ<ïFº¾¼J½þö¡Ë™jÓý¹J(±º\Re’Op`¾¼<ÿ‚ ¨¥Ã¶!Ë i3Ö`—þú£ªœÃL×—¢†d›!ØöPlÎs‘¡Û°·ê2äglk•û0›Joi˜¦ZÀalpó|û±:ß~œüÞÑûòjmHUå©#ÚëyÊóíÇêîËçýåÚæÜJ/U…²œTmŠyÞmмԾLzÑOÌ…Aݯc—Òf¨­Ê ^S]U™}ßkß+:õóÒE ɆÍT›Ð°J±®¹mŠõáSUN›†fèÏšóœÝï7_ý½‹~í^N§oUUõ~by:­ï©û½œm%°'O³§šÜÎÓùkU×õü 3dþÉXÂPaFT˜lbÖE?SUÝеíß Þ±åì‘ ¼ Àì†^_ÐÅN"=´,•' ÂdךÝ*qìüdˆßs>PaR\`N…èP¥˜ªÍP[a \‚'/XdÎÅTÁ:ôX©ÚÌi ,/[]×ÕCýÿ÷bnUaÏޟͺY`Î|B’'ý€À ÙLžÃüß¿oõÀBÿSÝë„£fUUÕ?ÿ¢§f*­ðøýù¿?}ý÷Íu±}WÒ¶’¸ Mý}sý#|º¡T’övî¢Â`¹óíÇbÂrÕei&@u]Wÿú×cÔï¼ÿPUwï²ok_ÅÙÖvð¶ÛvÃwj9¡mv˜K§÷Zcz°%†fD™š‹Ó£ø€£ê µßŸÿÛûýö°n÷ë¾ m³ÛÀì{úÔÃׇ‚¨”©»–>@°®Ó~·Ù(Âàxr_TòEG³+ÌØp]ªcËixªõU¡íjZ5 =,ûÎY–R©n%ùm%Có_¦^ÎÐPj)C½¥é»¤9g˜+Œ§Ö•s{6­0»á:ÉôÒå´Û0šÝPêÞf’"´†–²®±ê¶¯Þe`™‰ª£Uš)ú½ÔÛ’“'ý@ÊÀì;GØ®¸úÚÌ­ÆR-6©0»÷_ö…ØÔ}Ýí~ºœ-8W p¹¢Ïa†„ÅX›99H±¬û%,&;R×uU_».'ýìÌýݰÐã)þ¡ö*L€ 9à³LP`–6[8˜ÿüý‹^XèýÓƒNØ9ç0@`€À % ¾­dhžÉö“o†æ¬\CªG楞캯?æ<比GƼîS߸¨ óååùÇ¿¾ÀÙÓrï“O=‡7¥îkº·× {…I^B @`ŽÎNÓf¬ZÜCeÛ·_!ÃÚÝ6c3ÃäâöäÚÍÿ }àâ3ÅyÊ¡)¿ÆÎõuÛ¤Ëö>å~h;‡²Ý>dx8äœhl80·:­cjF…ÀâÀLH[kc÷š£„e®¾^«Z¸ØÀ»aézÉA:Õ¹·f¥|(\iìæÁc·P¤¸-¤ý»KÃn‹ ¹Å$Çm(*Ì0«û*¶¾áϱª14ˆæTšCÈs*ÖfYí‹wæT½¡WÀŽmÿÜ>LQͺ¨òx:Õ Ì™„;80C‚1Aµ´ÍP€¤¨çð»¿7õuh›¹ý”2¸R¾¶€°ÜR]×ÕC? ·ìÔÝ—Ï:aN`^Ï;5åáë 0@`€À€’¸èà‚o?þÌEEáÍ,¨0Xª¶½ûòù§!ÜnUÚ7¼»V›¢3f2⥳~ÌYWÈäÒK·9ÇL9e7gÛ<ÉŽŠ}áÔe78Ï·jÛ|í6íß_Òf7æÔóVû¦ÌZú¨¹%Ë Ùž”Û¼T̃äsN¥Õž…EhÂñ„†QÓ.UxíéÜéì!Ù¾péÀSO½Õ·œœoAV¥…c»R Í©eí*0·6gèrn›ÐuM %ÍÆ!3š¤Z@LXv‡R§*Ê¡áÖ+ÏÙWÉn}ð}yyζîuµû£Ý~ù'»Û³v_ôM0'TçTŽsoó sé=[U¡CÃÂ!m–ÛVºÃØ)>àJ8~…8·Ên iÓ½p(tضøÀÜÓp^HP¤ “KÐî+àb/ö)¥Í<¸€ ª²}!—j¸DI³{0MU¹íµl†D·Z×ÐÕËÄK~•lûÜÙÒƒôØùÒ+ESWYcëêîwßvµ™»_)û€Ds0^zàNu‹Hªe•¸®5¶-ô÷3 09 Oäc«ëºª¯]K“‹~ÊÕ¿p\÷wotÂB§w*L~MÀ&L˜ 0@`ÀEr•,À=¿ê„æÜš˜S“#µskÜu­'d{bÚä˜{rIÿ­¹=¥lKæªëºz¨ãoÍ™=½W{®Å¡Pj“j]1ü±íI¹ÍKÅÌ’óÁíulÝGÀw¥NƒU|`Î|BÒìs˜}öµ¦‚[ÎËËs¶wÎuP–ݞÜ3t9·M躦†’û*Â9UbÈŒ&©ÖÀÂÀÜúà›s"ãu ÔC—[ÌsYÚ¹U€Ü¢‡d÷4ÿbßpñœ6K‚­”K_³f_r~PØu…¹§Ê"dƳz—ì|û±÷û.(JPapÿø7¤9ƒ|ëmX50S6öZ¶‡¯·X×ç:Ž*ùU²í{—¤Ç&r¥hÊ0šZWw¿û¶{¨ÍÜýJÙ×±} |á²ôU{ÝaÛmº?o¾.aˆ880cK¦©nIµ¬׵ƶ­ñZÇ Ën°o?þ2„»´ÍXÛÃU˜”Á“x€%dŠ :Ú…Có \ý ĆÛTU7vNóû!Á[ÚÅ<A Ì ÍöiLÅØw¾²oY{­<ÝVÀ/a6Uv«É¹·„ü^)·˜¨0®<‡*ÅTm†Úîê*YŽ[QÎùÞZmæ´ÍÁ,L˜Mð9̩ɑûÚν­!õºÆ±7§Í¥>‚Îáý@ï¾hʇO­+&€ÚÏ]Úæ±6¹ÄÌ7¹ÅÒBÊP×uU_›—6§ÙC²}öµfæ ‘œ“4o9!4@ãþîNXèñôný 3´’ËUñtC5$xcÛ„®kj(¹¯"œS%†Ìh’j]ÀqølTav¾¹«¯Ò*Ëv´Û¯ñá¡»=k÷E÷µÎ5Ç'À®3×ü‹©«Ð¡ƒüšCÊ[á®1™· æŒØÃ°^· ›Ûýà>L‚ªÊöлj˜;9hï)lrKߺºá¦B˜/ùU²Cß[reßï‡\)ºÖ¾õ­«}g_hµ™»_Ýå D€sê`œò`ê‘TË*q]kl[èï fà9‡yPÎ1L+CCµé˜@úà¡ € &L˜ 0à"¹J`‡žÎ_uÂs&á̩ɑûÚν­!õºBÑÓ&ÇÜ“SÛ’ËÐܲÂr¯êº®êøI¸£+Ìö½_¿¾™|ÆëSëŠ9à·Ÿ»:´Ícmr‰™ $çƒ ÚëØº€ïî¾|Ö sóz^NÍ>‡Ùw`_ëqlc!’snνÌ @zÉg+i?’mMs†.ç¶ ]×ÔPr_E8§J ™Ñ$ÕºX˜C ç’s"ãu ÔC—[ÌsYÚ¹U€Ü¢‡d÷4ÿbÈpñšCÊ[ávCuékÖìKÎ*»®0÷TY„ÌØaV€ª:ß~üéë5.(jֱ׋•<¸@Xþ²&̺ÊN\°× p‹sŒíuµo“QA¡UŸÛUV̾sZ!]æÔýžk†BȺºáÔ·ÝCmæîWÎ@tÑЮ:Û¡:Vö…oÈðïкv˜SÈ”ÐT·ˆ¤ZV‰ëZcÛÖ~]cT¢çÛÕùöã/AÖü,¤]{¹Ý6!ËØ‚s˜å*V`°lÿwóœ9×%0ùQ:w ŽÙJš¨0X¨oȳ9o8ÔfÍû)s®K… @tH …äP›¡ ¶©«dC×%0جҜÓ&ôû1ÁWâ½ †d@`€À€l¢ÎaNM\¢=n3;Ìœ$§ËmNu“¿‡9Ôu]Õמè•Ó¢!Ù-'H¾¤mh»¿{£z<½[¯ÂŒ­°º!5Uõ }oh9kmïP…º_K—°ÖŸe¢f+™š¾j( b‡mS ÿ†N¹5p¡û²œ=kð]Ôl3œÙÖŒ£û{kŸóK±ÍeH¶„eÙ/Š Ì˜s‘í¡ÒÐaЭÃrj¿b«lö#xH¶ï\`îЊ]ÿÜmNµ¯!ËÙº_H\a†^@MÛ¾j+ô£ÛRõÎÙ¯˜å¨8˜¡öØ«XS,§´íɱ_äåY² 0@`€À &L@`ÀlÑ_{¬ÛÚSumÉÄÏ*Ìèи´¹%»û=¶ï9Ü@æÐÃÄ/•ê@`&«È†Âejx³Îí¶!ËZÖÚa×]ÏÐðtè¾/];Ìnt§ñê;ø÷MõÕþ^·M7HÆ&yžÚžý ™Úl,àB÷=d9©ö €sà-m[€À\]î‹YJºx&嶸(àÀ96t[ñu‡IC‡A·Ë¥û^bptÁ·•ôÝJ±å­C·z„ü^ì6ÏÝÏœ·˜¸    3¦ª‹YÆÜê*äBœ©6©Ö5Ô6d{BÖ¹Æ~°R`N”‡$f¡¿z¥hª‰½ª¶¤å°œgÉÀf) K 0#Br0$ &L˜ 0àx‚o+™šçqms×o¢eT˜!Û~@{_ˆæ|P:®0Bu @195›IÈ0i®*­»ž¡¡ß©mNµ.$0ÛAÑ7{ÈPˆ´Û­9Étw¹cëŒÙæå„ΰ@y’žÃìÂØ9Ã\Úç/KØT˜ÑÁº')·Y`Ìè*t’z› ¿ìOÒ!Ùîg ÷nÎ ¶œ·˜¸ à æÔUžÝ mú.ø™ ‰6¡:ÉôØvÇlÏœå¨8˜1õ©¶!ËJ"©¶{‹åPÏ’ &L˜ 0@`f‹z4ÞÞ&?ÞúY¶·oßVOÑ¿ÃÓäÇXæññ>ª}lÀRP…¹§êŠ Ì± ¬=|Û Ö©¡ÝС߹í¦ÚLm¯Jàò_ôÓžë²ýo(8_^ž™³½¬ö¿±ðúy;´B—²¬±íúæhe6t3u˜´ç‘L=uV7,C×0׿oïFþ/g´÷ÀLeéÄÐÝ`[3¬ ª6¸sh(unh† É”d¬‚T] 0ÇÎYæ ÙÔÛÓ ÚÐ z¶ì ̾‹~B‚%t9S¡4tžtéöô…æÐ2BÛÌ©2U—e[tÑOÈÏC¿—j}s×j›¸ð €õªLÕ¥À€C¸*q£ {—Xe¢Â ¨ª*àæû÷z `¡9H³£À¼¿{SUwïôÏ,L˜Í•.XæéüU'ìL]×Õã)î™Àãã½NØ‘9w€’ ö˜7>eÙЛŸ²­ Žàóë›êóë¡IdÑE?M€Ý|øT=ÿõÇâå,YFI`]#§+ë.ã£éÎFû©”þi¿n{yÍ–¾×J{¯…[{»úÞ7¥½—8h…™Ëó_¨í?ºæßØñöï^ê'é½}²ïp÷°íÝ÷ë^Þ«1ÛSÚöùûºà 3´rìßÐÏû*Ín›±Ðl·í¶k/{¬ÝÔræü³ÞÁ‘tÕ¹þ„•³@ÝaÙ¡ðk·kþ;6$Ûm3w{ÚíÚË\:œ¼ä`µôಜ©6ÝŸ/šÊµ=1Àcäíe§N-e{R`ª¾Ùâµê—¦Âj¯¯o])Öúžý^Èr†ú0åßû%ÊzÑÏZêÝÀ Ùõ7Û»­ía­ö¿¡7è’¡°å„´I9„Õ^ÏšÛº¡Ã¤ÍsíáÔ©íé~¿„áÝTÛ²Ç}OÝkÿ½‡¼Ÿ Yo˜G¸P'õ§×¥9¶ïèÛÓ=ð޽K×ß÷¡`ÉötÛmõzÅnsªå”°ï¹ÿÚý±´ê€ë™5$ÛWÑm5¼¹÷Ož¥,çhÛ’û€ghkŸ¯Y®×íˆïse!·Ì¹Å¤ØKoSIyÑÏÚŸK»¥bêœ \j@§pȶµÚm%Ý kb.ìé»Phèëeä 9!‘êïå¤j“³ÏælOêa®TÌR·§¯ŸSmsiû^‡Ë\ï9—s ^N§oUUU÷woôÆ Oç¯?ÍV²Æ•¢s—Ú¦¯mª«dCö-v{BûgjŸRÞÀú{S}œ;LB®8éÃ¥¯Eê}y=¶Ž{χü=Œý]„¾Ÿ÷ø ”Þ¿˜œÞëéüµªëZ`®˜30=|L˜ 0 ›+]°Üû÷:@`2æþîMUݽÓgH&L˜P’Ÿ.úyøó?zªªzûöíp`v—ìñôîG1ùS`z;ôs&L˜ 0`g¢¾þtþªÇ2pµ2Ìç85},ÑGóŽ·¿y–¥®ka¹Ú±DÍ?ÞFOïu÷å³^^ó¼¾Ñ °ãÔô±DÅoà &”ä*õþï/ßûûæ:Éò–,'f›×ZpSǺæçSßÛËþ•¼Í¹¶uµ óï›ëÝ÷Ɗ鄥ˉÙÖmZk;€}…esì9Fí1,SÇsˆ9†˜Ý¤2€€½Þå¶æ ¤Ò]mý¢„–ÑC?Ë5,Ò]ÏÐ2RI²äý 9öŽZ 9f–r\½*å Ô uÆvB_ÇÎYNl¥Ü·ü”ûÇÿþC½íïuÛ„3K:®{•lûÅž‡s e—|JjNTê1óªÔ7Q»Œë¼’ÞˆÍ6»êè;.éXûØ[±þjë7RŠì7/}˜š{ËœÇÞúí·-:v¨ÝÞ†-ºÛì–`ê€_ú1¢o;sÛBÖµÕ±öjÍúdjèrh9±mB¯€í[^÷ÒkC²pYãÿÖûö/äX·F?†´‰9†˜¡Ò.W›¥Wæ G¸ÜŠ1æç{:>,=n†îÿÇð¹åÇ›ûpöémðä¯}¹½º|j;Êu÷þK¡ñðÁÈ- ïNUUá® á]d@Ö¾ËõÇï^¿ŒJ{žºñWÿý·ÞÃAðãOÉßùõת8€Ì®¯ßD§¾¦Ì>i;€ý°úö”-Ú/m`¤ $ŠZèõxsÂá½Ñ_þøóoŸ}|ñLm7êf­ú˜rKÔÅÅó§ÿ?<|ýŸÏꟇ¾7”fKÍrõå3&ÍÜý—Z?ÇR†c¨gŒ” :õ¿¾@}Ìw¯åmwhí µeGxqñ<:?]¾Žæ/&@QN›ªgN2(Ͻ.٠άkNÛ¥Œ’˜ï|«MqwMó}Ö·yIÍóP~ûÒŽ¥Y뤦xcñÜ Ý5Rjn«ýû¾ýmg‰‘o̾†ê'¶ì_;/+L­Ã©ùéK7–f,¿9ÚÔÉ#'”S®)|ñ¬sú¶TÚ?×ßI >}A:u;í<õmc,Ïí©ú¡<äÊsLÛ-¹;W@n‹‹çOŸÅŒØc¶³äÉKß¾rå¹ùYWšØü m#%?ciÚ'}ùÍY?2Ç`‘Õ×ÍëÉS¯)·¿·æ©R®ƒ·ëðT,u]wÏeÏ]±k¦´E;@¦®Opl`¤<âìÓÛ2?9gÀ[+xîqñVÉ£äöH*Gʹhhî~Æê'gÙs¼œm±V~Œ’9¹ ¼Tp‹¹6Üœ ï1®1’ŒÍó©ÈÙÆN½NÙÖZe½FºDÙcò³E[äÑ÷åG@æØdöõÖ·åØΩò9ù©¿;§<%<ûºîH»ÅÔ[bb¾—ûv›¥ê¥”“ª\ùiÌØÀÙÞéí»)Ç,ôêK3´½®»¨,5wmcJž×~PÈ^GɱS¦í´í…CcÛ‰ÍÆ¤éÛ×”QrŽéâ±ütå­k?9§¯‡Ú*W›%sŒÎ‡Ãc!Ü^]&¬ß·{Œ¯n<Æàù¯ï¯nŒ}‡ç‡Ïß¼ºñˆ `°ëë7£}ñÝû/!Ͼ€bxŸò‘Óvûq® ¼,ƒãgÚŽh¤ì¼û¥íŽt¤\UU¨¾/ âø\_¿Q ¥åÇ›ûpûém¸«TØž¼{ý2úÙ×·W—!\½Ti{)?Þ܇wß;÷zñЙŸ‹þ9¼dö$ú>e`îS€Â$-ôúùMQ,ËìÀ‘ey_ªª wUÚc6X¦?Ží‹“rŒÏ¾>ʃ`­kž} _Êí¦®)@!e”A ”ý-Q¿üñga»7/m½ÿ½ç/„..ž?ý¿~»PýÙÐÛ†bÒ”R®¾|Ƥ™»ÿ=¿±ie8†zÆH™Ì·¾{ïtÛAjËŽðââyt~º<<|Í_L¢œ6UÏÊœŒ”Q2óo¹óæh²k:·k´ÙN—cD³Ÿ˜tíßMU·ÓŽ¥Ykº»xcñÜ Ý5Rjn«ýû¾ýmg‰‘o̾†ê'¶ì_;/+L­Ã©ùéK7–f,¿9ÚÔÉ#‚r†@øñų§éÞvàé ÀÍt]AoNnnwJ~†ò5Ì»ö·¹r;€\\<ú,fij%O^úö•+ÏÍϺÒÄægh)ùKÓ>™èËoÎú9›L_·ƒV;˜m­”ü||ñìéß)YêºîžËž»>b× Li‹v€L]ŸàØÀH¹P¥-–Úëâ­RGÉí‘TŽ ”sÑÐÜýŒÕOβç x9Ûb­ü%#(o0šÞ:(––ŸcÈCìÔiç5:æ¾iÕ)õ“£ì1ùÙ¢-rŽèûò# sl6™¾nO—vïnÎü̹=ªþîރݑvŠ©·ÄÄ|/÷í6KÕK)'U¹òÓ˜±³½ÿÒÛv5R[©Ü\àÕÛ¿ï î9ƒÖÐjç”}•Í(ù;ðØ)ÓvÚö¡±íÄŒfcÒôíkÊ(9ÇtñX~ºòÖµŸœÓ×Cm•«M’9Fg‡Ãá1„n¯.ÖïÛ=ÆW7cðü×÷W7¦¼OÙ«—Û¹¾~3Úß½ÿBðð(†  …8Wáäîæô˜¶#e`©‘rUU¡ú¾€ˆãs}ýF%ì!(ß^]†»J…íIìÊëº}ÃÕK•°—‘rJ'¤qMe@PA”@PbxÌ&°¹ú-tPšªªV½XPŠàÕ¡”hí'š¾€BÊ (‚2hÓ…^?ßÜÿí³ß?½Õ* Ô±z-§îµIœ‹‹ç!„¾ž\™k9˾e}žb[în¤Üì˜ê}š²6Ò¦{ tí`Wª‡‡¯E®=Õ¡‘rFFœÇy|€‚µO>¶>OylŠ»k*pè³¹cJ~šiû¦0Ƕ3–ß©éÆÒŒåwljvézΙ&¶ìSÚtjLÝWJ]ǶéXý¤¤‰íÇ‚ss:´™¾™¶½¾)Ô®`×vbö5”&f_¹Ì”4KÔalÛÆl'Wš¾¼m˜Ï‡Ãc!Ü^]p‡¾Óžî ʱ;6¿1ûÛj¹RO>æ|/¦sŽý]®ë§K¶{LÙÛí:çK ~SŽ9us¢05p÷ùðùÛß2t²+ðŒ±àóY;ð¶÷“Ÿ” 758Ä–k©üôÕÏÜüÄlgʾ†‚øõõ›Užèu÷þËö#å®Îêç›û¤?躣¨¿·ö"š¾ýäÞ»œ©ùIé”c÷5§~Öl‹˜‘tlÙ›é¶.Ëš'Î1õ³Ež×ÑÔûëÛ¯)÷°Ëc ¤vÛåôõVÛjvH¹a)ùÉ}âPBý@êÈòXö³v~ÖÚN=K‘r‰cê~· ÔEå”kÃÍ`°äè5Çè>¶\kå§´ÙœõsŒºN~,+¤46-¾U@ž›Ÿµ·Ó5µÞu8¥MÇÖ¬iÓ[¢¶ìh§ìË<÷ª\#îæ>b/´÷¿‡6í f©e/ådµy;áu˜R?õwK>йµÇí?¡Øú™ºï˜ï]šXKñ ½RV™ȶX}=eä7t¿ö”Õ×S ÕÍœUåsê9vÖdJ~ÆÊž²X/¥Ms?s‚slù‡ö“k¡W_ç»+vaXêhl¨Ãž²`¬k1eOyÆÔcÌþRëpJ¹¦æyÉUîk/ôÚ4(“62†Ô­½èZ} %X;({ö5â\À¾”¶ê”O¢ãÇœÓ×`¤ ðÿ®¯ß¨eUlíöê2„«—*‚“gúŒ”þòáó7•@‘ªªZå>eA(Ї‡P¢µ×:˜¾€BÊ (‚2hÑ…^¥=›×›—ö¡Ôv:ÅãgË¿áR^:¿µ±×Fb¤œÜ½O6×þJ~¹:Û–’Ž=«Í¿ß-єۃ‘òÀˆ¢„Ñ…2ŽŸý ¾†‹‹çáââ¹Ñ"‹{[c›ß§Ü1´;½fpïK×q ½~¨sMÙWÌËåcË•’ï©al;1eOÙNl]§¦K3–ß©ÓϹŸ”cgj{­}ŒµEŠœb×»½ý\iÚéú¶QŸd¤ìkJ¹˜v¬l˜7]èÕî$ú¦ô~¾¹ïoO¯uM·¥LÁ í+w¹b·1'?)Û+{sCÛú}J~ÆÒŒÕs̱;BÎqüÄä'¦~ÚŸÍ9ÎbÛtï#îú_; åJÓ5Âï ®u§Ÿ²¯Ôr1ïäm˺Ü,(·;”±Îy-s÷•R®%ƒÃ”íä®çزO)×’õ¼åñ3u]¿Yk,Rk÷%‚ë\}nîvº¦Ü×Ñæ*שjžàl]—³Y¨zjrîê×\ÛÉyb‘+?Çl­“‹ÒGÅsróZôXPÜÓ(3¥\L)oYŸ‚rá¹ÝÖÓ£ko'özäšå:¥¶Ïq”²¶a﹯cí[0¶·€[.ÒNtJ8~X²Ciþ·GGKN¯myËI®rå*ÖuÑ×éçqO©ç=Þµ—[¨ê|æÈkŽ€Ü5šÌõ½všötõ’÷O-q':[ŸØœ‡Ç¾¿d|¡Nyèì?Ç*å±mõu¹V«å=&¯cyš;‚JYÍ;§ì¹V_çZå>%]lýÍÉsìqs|Å”ehbJ›N)Ó˜Ÿ¿=½%j(à¤v˜¥®¾ŽùlhV_¯çúúÍ*¯n¼{ÿeù ÌiñÄ4¦je8å ìÙ×PA aõ5Ù˜¶0R#e€\®¯ß¨eUlíöê2„«—*‚“gúe@PA”@Pe”Ae@P€S Ê?ß܇Ÿoî?ëJsjÔº0RAØ1o‰ZÀïŸÞªÊ ÊíÑI;Pu^šiêßÿþéíÿ¤ðÆö•šŸ¾ÏÆÊœR®¾Ñ]jùsÕsìvbËŸšn,ÍX~»Úoj~œtK™<}=6%øû§·OÿÚé›d_šfÚ±41ùÛWó÷S÷ÕünL¾bëgn@ÎQϱõ3ôû”üŒ¥‰9!j×]_@žÛî›åµ,1*I ží|ÔvßÈkËrÍ){îüĸ)mÑ®ûœÁt¨~¦ä ŦהבÔÓ²S¦Ó÷.¶ìkµUÎü”V?›åöh±¤QpÌ~ꎸ=йFÚìÄ—ÊW°È5"o—}ÊÈtNÛçÈÏšÇÀš&O_çî´–ºue·Äô]ëÜSÙûy®w×ÉáX=͹§¾Nëz3PÌH¹Á5¯åMU¬9m³¯¾41uЈ†Óšõ³ôv†‚q×~r¶{ì¬ÅP:Ó×@i·Ãc!Ü^]ªGÊsü–y ÎÝû/!Oô€bx¢WL«Ê˜åà´˜¾A”@Pe”Avd÷)øü-)½G†`¤\@@®ªêé¢`¤¼€_ýgTºëë7QéúÞ—| Žõåk–«´:Œy·öPž=²åì~{õÁß¿úí?“;ÜS{¹ý)¿ÕioeoæwêqÚ~5 (³’c ´k–kuhô ‚òI¦†>ëëÛ£œ¾‘K»Cm>¶®¼ÄLcŽín§ŸR?ceËGì¾RÚs¨‡ÚbhT:'x.=5ÓîÇ|é¶æ–¨L»þ×î´ú‚oê4bÌvšyÚN3M×wbʵTýtʘrÅîkl»1ûjî³o_íü,¼Rò<·s€ <+æ¸Y·¯íz‡ò”íì½®s•iéúYsÁYÉïXŽC(éȩ̈rMÛN=<µso.‚Z;p.ðÖ^˜6Ô^ÇZÏ (ï¨Cë-¬š¿æŒÄœÀÜ5ó°Eût¯½'1—@J©g86¦¯eLan9M“ç©åŠÙÎÜëísë}‰úî»öº÷ãy©úþrv8C(÷Ñ”õ½RòîõËè 86B¤¬V}èCìŠì˜¼Ä¦ßÓêëyŽ]Á>5ÏKÔáœvÏY‡V_C~õ“(w”«ªJþÞXP†¥G˜1 ”‹Ÿ¾žr² °GÅ”aï£å&£d`h¤lõ5,DRY} ‚2 (€  Ê (1vqKTý¨ÍXî¹ÀH¹€€\UÕÓMØÀ¶¼ÀB½p„#åÒ_H1öÑû²ˆ¥þ@Çö±ÅûkõYÍ1¯S*{©ï.­½RŽë=¿EkJþ›¯öôv”Cá·Wÿüý«ßþ“ü‡ÑýaYªª w│wÛ_©£é}úyê^ý÷ßjyÉüñ'•; /ï¯ÔQzŸîš2BPA” @ç¹7øËþí³/žeÙÞœí¤äy©ýäìOëß}¶—ò•œçµòºØHùã‹gO™î:°R*aîvRò“§¥òÐÕÿÅö§{ È9bÅRâD‘A¹}6!¬äö˜×µ‚^éηn”Øé€¾ß­5½ÓÞOß6rOßS@Î'šåºÔÓ/—ÒwŸ—rÕÓ©•ÐU±S¶“:âïÚ~ÎrÌé ±L}ýió³vš˜~¹¤¾»ØÕ×ͳ–=O}›’¶U:!Ù_¿|^êAÔœŽª¼’Ä:ÏVs[õ=ÇÔ߬ݿ—Oη>rT`×5†RÊdú˜÷Ñ¿—Po?lQ±}éö6ýÒγۥ€¥÷C]ù\³ÿŒÙ×Výùù’…î;ûÈ5ÍÛ·Ô4±+«»¶×^ÒoúÈ=ò=Æþ¤«|1ýéõ“&%N”c3“n­4sW| ÀÀ’#Ê”ß署Û7Ç–‹81•g_@!e”A ”´Ð«ªªPýø“ZNš¾Pm>R¾½ºT[+y÷ú¥J€Bé Çû+u4½O?;*¶s÷þKÚHX–  ‚2 (€  Ê (1ÎCøëÉ+w•Ê€MGÊÛ{÷úeø?ÁèXù¿øIEND®B`‚stella-3.9.3/docs/graphics/options_audio.png0000644000175000001440000000614212162610274020515 0ustar stephenusers‰PNG  IHDRE²Õ”ÝHbKGDÿÿÿ ½§“ pHYsaa¨?§itIMEÝ :ƒSZtEXtCommentCreated with GIMPW ÊIDATxÚíÝ¿®ÕVÇq_tË7Š( ÍHH´ <ÕÜ¥¢¡¤e¤éiÓDÔHHiÒ ‰4­iòw 8ŒqügoÛûíÏWŠÂ9g{ÿó^?¯µíëuõáíË»7ï>6pvž=¾ß\ÝÞÞÞ™ g§mÛ¦išæº«pV^|ÒÄæž©€ÿC€(Q¢DjÅ»§¯š»§¯|öÙç…Ÿ‘‡/o§~Nñî髿êíK3Žäí/´ž=¾Ï~2ðâ—?š¦é<¼\}PÄhÚ¶m^´MóšýdãÚàˆ<úó×ù2ï¯~Ožüädf&ëž"öC@øüwì)iì燎ùa¤\HðwËO_}µÈǾ ­gɱ¨g-t…nè<†”AQ´'RÞ¾ä5ì„»±½2(>Øþ¢†‹¢=Åmáò^þ=f$k÷’†êî~7åqôÛ*›¢ÏG„ý0|F~rî%uÅk.Œë†í¸tç•‹¢=Ų²'ê 'æí‡ î0|FºzOÆÀ3ä!ÅÏØÃÝÞ~æ1fÿ™Ãg”Ÿ‹Ôh cÏGzv2Þëžzæ´¿b%ž¢W¥ ¡C¼„!cz¼_®_ÇR/p¬ºÜ~bæÎdܪȕ¸ jæ’¸ÊsŠP*|Rs´l~øDÛ¶Íëç‰"°„Ÿþ§I89³ Ÿ€(Q¢ˆíXûæo¾Á¸.e\}J½ Ö·¶Ôöš§-úÓ·_jnnŒþö×_ÿ,Ûÿ~¬¾©rsÇ/9űDH¹ eLŒy0ÇeN„¦ÄsHÐnn477Š‹‘=pø,GÝsê%†„ǵ]„b±ûÿc‘æœ.|^b‡¦ÕÜ2Lߪ®¹zBÂù±ñ/M)šB0ׄ۹Rœö½¿¥žæZ£ïÖ?äýõ¿ë?æ1iI™‚XÒÏî)v…mêµóÝŒncb8—VsÈëZâ¡l•ž3¤žqhnRõyÉöCmû¡—pwHŒJޥݥg¿ßCãè åX[!eJzˆ¥úQÄSò*rì)æÞè_2©BÛóºÕ¸¶ËPlá¤ÜËëïYæÞ7,é%Ö²7º«ðyï}Ú:OIˆ æ˜Ç±äSµíoq“do77æ¶Æ<èZúZ¢/UŠâØê½{u[zÉ¡bjaêö£ÿï…±V±”÷•Ê›^sÑ*-ÎU<’³Ç¶—ÔµUûKëYzÜ”ÈÅ$®ZâÝ®™«±µ?cØ÷àBÚŒyÎr‹ùH=ö’}Ê.Š!!äVi5CŒlMšÏ5â2VOHÆÊ¦èsnO:¥¸ô`(\*;tsb7³U¸:%ž!¡qmás-íúÍÛ’×5Ÿ9ÎÇ›wñê0fÍ“'?%ŸâåÍÛÞ§ˆlž ‹S˜²x!PaÈÏK,Ç¡=Ež ö*Œà)OHAÎ| Š@Õ<{|¿i?4>Oè!ïó1‘÷X¼ÏÇCÞg(Q¢D+‘÷gàzÏ:†?ïK7ßgÎûR6ä%©)òGû{i¢H1Ëœh…ˆgLÙÜÐ5æ†ð‰¼ÄÚó>OyX[ b÷ÿcÙóÆÊ@ÞçlÆóöí1ÉE=ôí˜\Ô[õ9´?©³¶¼Ïs!çœ!Æ”­YXj÷JO™÷9…ðMåŽ2бÅSù‘ûåÖ È\.æË¾Ûš>çܾ¨=ïó˜@l•ÿ¤Ô¸†Ò tÇV*·õçéTyŸSeh¹5žKN#_’ÿ¥ÿ¹{S#åjÍûÜ÷ŽŽ¶‡º °—›0ò>Wj­­Rã9bÞç!Of/áè.ò>ïÔãÜ[[¹ñÈyŸ×<¾Cã/Z¥=GwŸG }h³?…‡·ÕÍSéL׆ÎSãÛcû>4ïóóÒßoK)ý;ÉciGçÊœUûstª¼Ï5zˆ!ù‘çrQ‡äªÎ™?úèÞvl¸<ä}„æ}^ÚÞÐñKÝo’îA$å}>@Øx–~ÊûŒRÈûŒMlkñ‘÷gÀžâÁ·ˆOñÀ^1xŠÀSºÈû ¢|FÞgŸ€(Q¢Dˆ"E ŠP+Þ®œ7ï>F•÷ 8€§H?Ó¶í—wÂà)–З¦†üÍïÜ›Á·$4õ@Ê>ì ¯{#Šäý£LþþèýïQõÕbt%sVÂgà)bM7”Õp*ŸÊà·ÆK mk«zBÆÝý¾ÿÝš9O…„o.ûà%ÏËXˆ{ùmªL¿Ü!è LŽzÆné<µ5ÖðQ€<ƒ‘ÎyÝt²KæƒÐEœ0ÌÞK{µæËQÄqh_­¤w»Ä3L‘ûÅž"v+ÊKöçŽéïýyn§ˆJ‰}qI(cøc¡hH[SÞåmö†ÖÓ/7÷ûÖá<Êru{{{×4þf¶FÞ¼ûØ´m}Üëç7±\þDVø\1K.T>"ä…§Dˆ"E Š@€(Q¢Dˆ"E Š@€(Q€S‰âPn‰¡dßsÇÄ´×ÿy1ï ŠÆ1”8h.yøå÷¥|xûò«ÿJè™E!$YTÊùY’(ëh%k;-×)'ô¨é!¥»¬{~œdÅ)/0D /^ŠÅ;—¾²û{¿ý> õqjl—òý6–öo‰Ï¥ê_HÿCÛ;nÍøû¹˜§Ž_ÒþÚñ§>ÿ1ã_zþçê'Š+3…ð…œôÐþ, ¦Bö!±Ÿ›˜ß—xIsBûyÍü„Œoê÷‹éÚö׌?õùÌñ±õÅ•¡KŠÉ;q1B—cOrîJ>ÖŸîBÝrOh®¾Ü3?{ ½k;ÿ¶‰âÚ+ÊÚ«ÑTû±áNmFºã ÅÌ}IO!¤ÿ{§ôùÇ<÷ö¼¸bïDvïŒ×&Œ=´ÅÝõ¡cçæ ÷Mï wš×žÿµówôùÍ>/õ·4´~†Ñч íИþbY»ßÖßnXs£e¬ÿ[…ÐsãŸû=vücåçn,m¿Ä…<¶Sã=ÿ±kèl\ÝÞÞÞ5MÓ<{|ÿ”®ò™6–kÒ¼øå}‡Ï‚Ó‹â™<£Úî<Dˆ"E Š@€(Q¢Dˆ"€(Q¢³D½döÍ»f,g}·¥µ¸íz1GËlêžEXmÛ~yÙ%¬Å¥ëÅ-·©ètþüÕ,§<ß|g¬ÅÍÖ‹9Š·){Š@€(Q€®·®ðÇÿ÷oßýöý·›Ô·¦ž˜>§jûcn=_~Ÿûn/㫹ϹúšÌSüíûo¿tzhaÅLÂÚzbúÒ§Tý@FxY!ëp‚¸…­æ ÆN«Ÿ÷0ÙÀÖ"³Ç¾æÓ…Ï©Âì±ßr…7ývÆêØzûq/ÛS[]!vQ‹í\ײ€.aiì$ Mì’zb=Þ¡ú·öÇÏq¨}u¿ë— ±‹šl§Ú»ÏݫƞCo!Éù¼E„}ÛÅu­‹¨ëŽOM^M ñÒgw³Ï) GŒ rÛW ö|]z!¥Ã÷n€0îEsÚW óv¯ÄÄŽ•Û[øÑï³Çu°—§-†ú™sý†´UÊž®SzLý· 3Çê‰-zgy¨¾þ# Âçcz~G<ŸCã YÏ)æ1¤LŒV%Š¡ )—«ÌÚ;Þðøž_Ìï{Zkm#tü%ì´ÚðöQ¢Df‰ºÑÒ¶­"¨kÑ÷¥ÝÌÇëçM‚µ¸j½˜£å6uu{{{gœKT{а$|¢Dˆ"€(Q€Q®›æÓ“ï/Z“÷<´ Ÿxýüaó?RC3PÇ=ÊIEND®B`‚stella-3.9.3/docs/graphics/rominfo_2x_small.png0000644000175000001440000011424011433323254021111 0ustar stephenusers‰PNG  IHDRx„‹YosRGB®Îé˜ZIDATxÚíý=Œ%K–hÞ„ÀкEŠÔX+‘ ,°E­kÑÂTK…š#‘OJ$›ÀFIb„C<öÓÓ 0xCi†Â¢r¥i%1ÕZ—°@r¥y¥Q¤ÈÔ‚Z­Ð¼Ù÷yúÏ1·cnî~¿H¼7,ÜÝŽ™{ø=a÷øï].—ß½{ûîÀqüÅ¿ù‹Ëï½{ûîwBp?üö‡Ëår¹<^_øæ~_TàÛßþÍ„à˜$xJ‚à $xêQ€#ùþãgA Õ¿ýáòÝŸþT 8$ ^àp¾û³o4üóoÃR¢à $xjU‰†7Ï/?úúÓ‡÷« s[ß=̇k{ôÍùmßÓ/½÷~h©½÷òëÇí1\“7z¨ÙÉuGKsiÒš˜´˜[8ß K$GÉm\¿7ü·v{ÔÉÑ=¬ Èí¤–/_RçŒñ{4¬&'˜Wp?ï½ß?—ÇÒÁ¿.Ï.ùëCÖä‰noì¯)·m‡ßÏzèUt¿Ã¿ø´~H]i#ÅÀoû0üÿÚ>Lmkî/f‘~ï¥S?³vYùƒ¬÷û=óH‘<ÃÚ¾fô#òziþ/clïÝÛw¿»\.—oþè÷›L†±Î­™ÌÑí½^Ò¶ö™ÛïØ€e'—#ƒ’6sýš²¶/k/h%±ßC?JæAéy”ë¥v¥ç•Ä.åûŸ/ßýÙ7Aš?þù·—ïþô§Uï§×æ}"ÉÎ{È#µÊ'd÷#š»YÓ·Òdï·þ›ËåRøµÛÌ=y.ûalÑíMkîi„YJö±×‡Ô•Ž[‹"ß%ñžŠýQú±f>ᡆ[œo°ç÷ÅÑ÷ñ‘äã½ç‘ZçZå_jò>¥3&íTÙ†ìɶç¤Ö™ž*è ‰Æ£ôÜŸ»ˆç••·gX¯éCÖ²ƒ¿×Á,­²wNãQsl%uºà^¥”aæñË3¬óx8×/Ã¥ëRv;€½(ªÁ[['tj™õšýŽm¯v¿k免ã·%õ™{Ä9{Þïeþlýó°'%ùˆ’Ú»{Íodç-zå jò5z3¶÷¸fçSºÔnØvì §¶Ù^I»’¾¬‰Éíë-O¬hü¢ý-‰ßÞ/ªcÛ{ß™ã/Ñv¥µqzŽ ¬U›¿ªy½½ç‘zÖà]›ï¬Íýemï÷Þ½}÷»Ëårùæ~ß ìÞ÷?_¾û³o‚4üóo/ßýéO‚CùöÏs¹\ K4°¼%Á pPBÍÿü[A¸HðóÍýþåòGˆp¹(ÑpX¼Kð>¿üÍ?_ûÚ×¾öµ¯}ík_ûÚ×ã_@¿÷îí»ß].ÿ¥~Í”ç—Ë÷o߉ŒøæßüÅåòáýW¯ÿñ³àP~9—«ý/¾ýóß\.—èCÖ>¼¿\>~¾|÷g߈.§÷í/¿ßû~ûËï%wHóÃo¸|ûÛËå»?=LòQÈ ‹$(ñÇ?ÿ¶¨}¼/à~€]yXö—?ýÙå/ú3`WŠjð^==½möúú©ù÷=·Ï’¶÷D\â1šŠÍÒ÷KâœÙ.r\½ãräqïµ-ú»MìþåOvùùo~ýõý2tPµ‚÷õõÓ——Ëtâ7ÓíþæÜ&W¶<¾½—²Í}?#ÎÙíZŽiI\Ž:§œŒ[µk%/{‘VƒwO‰‘±DÔ7OOo6=ž£ÄeosgìûqÎn×rLKVî.íëy_ºïžçDÏØ0n.‘û£ï©Á @'÷ÔY•—·ILI8¸_•b€‰­àUSŒ;°´J5Z$Ûšýf®B]Sww¯+ã±ìuü½æ Ü/ÐÉ&+x×>Dj®íœë ˧§7¡‡` Wd®}ÈÕÜ ÏÛ¶ÃïÍ%Ð2hK«q[Ûnmœ÷nl<¢æ:â¼Jæ}d¾”̃ÞódéúRú½Èõ ¸±ïóËåòöÝl“©dÍðõ©ãØÏ—$#‡n“g·¯M{éñµîsªm4™7ÓÖqÉ·µíjâÜË\â¶fž·s´Ä^I;2_JæAﺺKs´äø"Û Ç·¿ü>ÞøùÅ*^º¨ZÁ[²Òò¶Í\&S4Y¼t|%ý˜Úf«~µˆK´¿S‰ºÈ<¨/[Ĺ6ÆÃäãXò®4I½çÄ^fòtmIŠ½ÍƒÒùÜc{Œûá·?\þ÷¿ü.Ôöþ­€ÐM,ÁûáýåòñóW/GWEW¥µtÄDÈØêÎaìÏ—³<ÀlM™…èxìqÜ–Ê"ÜãàŽX½ @')5xKVYŽY*ïpϦÊ'œyÅ^¯~íõkêífÖèÝ:.{¸±Æ1pŸB­ž_Õ©©U¯÷N\¶5÷sNoŽv¿ ÀyÓ±šŠÉÒ÷Kæ_f»ÈqõŽË‘ǽÅö{^O×û+À=¿XÅ @U+x__?}ùwû†·¥ÛýEß|oy|{6¯©×î]4‰™1ÿ²Ûµœë%q9ê¹Ö3~=®§÷x [Î&­ïžÞ8%RöøÆþééDÃÎb“Ü›ÙíZÎõ’•»Kûï9ï#û×ÓìñØûu­çï×|89«wèä®jðZ©J É`ob Þç‘bS=’ñÑÐ!™«×ÔÝÝëGᣱÜ2~ô™=æ§?2Âɹ_ “Ç-v²ö!Rsm—ÞD_? yÖµ}éñ ÛMmoØvø½¹Оh_IœkæÊVqÉ26OÏœ ,™÷‘ëAô|+™WGˆ_¤¿%çïÚñX»½èëÙ×ç­æöÚëZià*­oäM{ÉC¤jWXÝþüRÝÃk‚­ö!Wc‰‰±¶S:‹Äd«•g¥5U³ÚEV¸õŒKéÜóÒ<;‡Jη=‹Îûèõ z¾EçÕžDVEÏõwMLJÆ£v{¥±Èza«±Ê¸®•^ORƒ€Nªjð“§‘•Z[&`¢É¿ì‡\µÍì[ëdÕÚ‡zeµÛk\JåöÉx8ÙíöÆÎ·Þn¯µãZ:–-Ï·ñ[ß¹þf—Ìè]‚£ÅõyËãë½=Î/V¢áùåryûnòèÒ›ÏÈ›ÓÖo`£eöäö˜ç’­ì5©Ð;.%ljï0¡35O÷¾jwé#ûg˜{=ç æ °sÏ/VñÐEJ Þ¥äéšD—7ìÓ±Û*Q½ç„S‹¸ìù¥ÉÝÌdðÖqÙÃõàÈñs­Üv| ·´¼{’ñq¨ƒÙÛ’Œ‚>¿Kü>Îx¿ ÀyRßbþ•Ì«ÈýZ&˜²J ¬÷Ãó4{^%~1.mÛz{sc»öú<Ö¶Uò~îøJæppjðÐɪ¼soìK^/ýÙÒ7Â%íkŽqí>#í[½ùÏèKt¼kÛm—¹í·š™s`Oq™;–Ösë¬óªgÛ3l/óŽþnª½H°ä”5xØ'5mÓr¿ @'BÀV¶ªi÷"–à}~)RÜ&y%wÓp¿ @'÷Üy €}^]Ÿ F ^¨å~€NÔà8(5x –ûe:±‚à bYûðþrùøùË—×§žmñPœá¾çöYÒöL›øLÇj*&Kß/™™í"ÇÕ;.G÷Û_s=;Î’>dö÷ècPM ^:©ZÁûúúéË¿Û7ø-ÝîoÎm²aËãÛ³áxM½vï¢IÌŒù—Ý®å\/‰ËQϵžñ‹^O3ãìÚÇ—VƒwO‰‚±DÊOOo$Vv›ìäîÜüËn×r®—¬Ü$({ÍûȾ{Ä/z -þpÕóÚ蜊¼trW5x­T¥† °7±¯šbl¬G2>úú#Ä"sU暺»{ýè4–[Ưf;G_ÅënÀ©¸_ “Ç-v²ö!Rsmç¼¾~úòÑß胊n÷½ö!WSÛ¶ûØu$&kã’=nÑø•Ĺf®l—,có4š <âjâ’y¹DÏ·’yEþX¯=ÏK¯Ïp¯b Þç—Ëåí»Ðú¹äÞõë±ÄëÔÓå—’´Sn“gK‰a‚-r|cí†ûœjMæÍÅtm\¢¢ã_´]d%aϸ”ν¥þ”ÌÓávŽ–è*IbG®Ñó-:¯öäÈå@²ÎóÒë @wÏ/«WñªGp_²ß×VÕཾَ&wçÞØ·ø¨nô©ôÙ¹k›Ù·Ök^ûP¯¬v{Ëšu)!UúЬ̇kµ˜7ÃkÂVcÙò|뿹‹}fœ[ÿ’ʘ«GNÔÀb+x?¼¿\>~ž|ã½ôf;ºJ«¥hÙ†=[Ý9Œ}K{M¢ôŽKÉqFâ;µ |îç÷8Ÿ—Ê"œaîõœ/-â @"5xè$¥ïR²im=Q‰‹éÚ”[$ööœo—½þ`ÍÇõ3?â¿u\öp=8rüz÷ØVZ Þ=‘¬`sÐüãŒóúÊü¹_>è*ÞwÿËÏŒ«ýú´zèãgÿüEà¿xÈÚÐX¹†©­kGFëè¿7Õ®t{k ãÒ«Æf¯q[§-ú¾ö83æÕÚùœ]÷9+.[Žg͸%~{ëoëë$ðcU5x#¦ê¥NÕûÙ±ÄÁØkKÛœJ2 ÷3Uf"º½šØDâ’±ïŒqËßÖq™úH}‹ù—Ý®eB-«ÔÀÚy?KÚÞƒ©qŸéXMÅdéû%ó/³]ä¸zÇåÈãÞk[Àó‹U¼tQµ‚÷õõÓ——Ër1ÃíþæÜ&W¶<¾=Ž×Ôk÷.šÄ̘ÙíZÎõ’¸õ\s­Ž&­ïž#c‰¨=&nžžÞH$í,6ÙÉݹù—Ý®å\/Y¹»´ÿžó>²ïž× ×€³z€N•ªÔð‘{ö&–à}~)6Õ#¿”Àíõ‚5ûÍ\…º¦îî^KDcÙëøý àÀÜ/ÐÉã;Yû©¹¶s^_?}ù¨sä!X×ö¥Ç7l7µ½aÛá÷æh{~ ]4~%q®™+[Å%ËØ<®>âjâ’y¹DÏ·’yµEß×ÎûÒëpÒjðN%kÖ>DªvÝíÏ/Õµ¼&Øjr5–¤k;õ ³HL¶ZYXZS5«]dcϸ”νá1/ÍÓ±shØ÷£–ŠˆÎûèõ z¾EçUËs)cÞ—žolL ^:©ªÁ;LžÎ%w¯¶LÀD“Ù¹k›Ù·ÖɪµõÊj·×¸”Ëí9’ñp²’v=Ü^j­t,[žoYs!kÞ¡°X‰†ç—Ëåí»¯^Ž&"É‡Ö ŠhÙ†=¹=æ©Ø·´×¤Q︔g$¾Ã„]džîq>/•E8ÃÜ€Ùûe«xè ¥ïR²im=QIžéZœ[$ööœo—½þ`MI†Ì2[Çe׃£–ÁîOZ Þ=Éøˆ8ÔÎAîcœ]o8âý2çñµ¡ÈC®Z'D¢ut‡ß›jWº½µ†qé•8ê5nkã´Eß×gƼZ;Ÿ³ë>gÅeËñ¬·¬øµ¾n÷­ªoÄT½Ô©º£c?{5–K(Oms*©2ÜÏT™‰èöjb‰Kƾ3Æ-[t|[Çeª$A‹ù—Ý®e1«TÃÚy?Bßk^eÌÅVq™Zaœµÿ±Ü2~5ÛÉ:Î^ãåºQƒhá¿ÿÑ—?ùOßýøðmQûÒí°[ìdíCšÖ¾ÁŽ&n·û^û©©í ÛÎ}¬9“­½RWç5ql=ÿÎâÞþ Pr^FæKôzÐó\»WK׃ÒF®/ÐJ,Áûür¹¼}zü”t›J¼N=½}튭ÛäÔÒïa+r|cí†ûœjM–ÍÅ´õJ¶è¸a¿kÆwË>om.q[sEæîÞã=öÈ|‰^Æö½wGNôG®%ãÙp'ž_¬âÒÕ®¨þüpE¯»çPUƒ÷úf¶dEåÔçõq£O}Ï~ˆÔXÛ̾Õlo˜ˆ¨·L­öÛkþíY4!UúЬ¹yÕÛíõ*ãÁ_%ýky=迹ñÍŒs˹¿åõZªªÁ}3]ÕúMýÑVW­žÆþŒz$Gî1!³4‡Jkªî}UçRYó¥n¾´ˆ3À¡X½ ìÐR ^+zÎ!¥ïRòtM"Ib`:vgÿðÖý:ÊüÛó)J“»™Éà­ã²‡ùräøõî/œMZ ^É€ã¸}(ݧÌdž¹ÄÞ®ýæ#Ð…¼ÀY‘ p²64V®aª„CëÚŒÑ:ºcIhØI­a\zհܪ¿‘ýŽÅaîø¦âºe?¶›šùÖcÞ·ƒ–µO÷VKöhñÛ[Ït=€Ë¥²oÄTÙ©ºžc?;öÆ|ìµ¥mN½‰îgªÌDt{5±‰Äe‹„D¤¿Ññ¨·±}Û Ç°d|³ç_IkÇæv[-Î’yyà`Ë„ZV©µçåÜœS2nGˆ_M¿·èïÒõ õù œ˜Õ»t²ªï\¢´äõÒŸ-}c½ö)÷­Û”´o•LÈèËÚ‡.eµ/9¾µ}Y3ÿ¶H­©u½Eœ{Ǧ$.sÇ’1_Z\3ö¿–1i1§£çrv µX‰†ç‘b7öö‘y÷Ëôò M¯Á°7±¯šbìÌm’WrèÎý2<Þsç%™¼PËý2¨Á pPjð@-÷Ëtb/ÀAŲöür¹¼}÷å˧§7£Í¶xèÕpßsû,i{®ñÆaêõÌñè15ýÚ{—úé{v_"íZŒIv\Žxïåü¸kÏ/VñÐEÕ Þ××O_þ].Ó‰ßL·û›s›¼ØòøîMt<¢íô÷R4·ç¾Ÿq~d·ky.–Äå¨××2`(­ïžc‰ž=&FžžÞHÔP=·Ç¾Ÿq~d·ky.–¬Ü]ÚÏó2²ïž×2×,€ºûehá®jðže)Œñ‘{€ûKð>¿ˆÔ DW_²OKcÕëkö›¹ uMÝݽ–:()Òãøý‘ Àý2ûó¸ÅNÖ>¤i®íœ××O_>JyÈÔµ}éñÍ=¬l®íð{s ª£<ÐnËý®yXÜšñݲÏ{4vù%çed¾D¯=ϵèùQú½ÈùäH«ÁIº•<¤©v…ÚíÏ/Õ¼&°j"5–k;\7µ*n,&[­Üëõºû]3¾g~˜ÕÜJî¥óhì/¹ì=.‘ó2:_¢×ƒ¥}mqÎEŽ=¾ÈöNI ^:©ªÁ;LžFVTn™àˆ&ë²"5Ö6³o5Û‹$ìz}¤½Õ~{Í¿=΃Œ‡“-Í«Þn¯Wµó¸t¾´¼dÍ…-Ï7 O¬DÃóËåòöÝäù¥7ï‘7÷­Ѳ {r{ÌS±?£É {L@-Í¡©„ûÔy´÷U»Ke̪<¿XÅ @)5x—’§kI·¯ß³©Ò GJTgô¹¥£Ì¿=ÿ‘¢4¹›™ Þ:.{˜/Ž\¥ÕàÝ“Œ`ŸÙØG¨¹/™ç‡dãþ¯…®‡°z€N²6yÈÐUë„C´Žîð{SíJ··Ö0.½3[õ7²ß±8”<$¬G?¶›šùÖcÞ·ƒ–µ^÷– ͎ߙθGU5x#¦êÈNÕõûÙ«±$ËXâoj›SI‹á~¦ÊLD·W›H\2ö]{l%ãQ;ncû¶ŽaÉøfÏ¿’þÖŽÍí¶Zœ%ó>òÀÁ– ĬR kÏ˹98§dÜZ%Ç3Îs€»§/¬ªÁ;—(-y½ôgK kŸrߺMIûVÉ“Œ¾D­Õ¸•ßÚ¾¬™[$¼ÖÔºÞ"νcS—¹cɘ/-®™cÛµóDÚ:e ^ÎMMQ`wÜ/ÐɃp4½jÀÞļÏ/"Å®Ü&y%w€îÜ/ÐÉã=w^BÐøÀ‘żÞ_.?‹LÝ/pW~õ“ïS·÷‹¾T`5x*¶‚÷ùåryûN´`ê~Ù*^€S[Z±[ºw¸½á×VôQVðÔª¼OOoF›e?ô꺟ÒíNýÜÚíe‹ßÔ1 ÛîýÁbK1ŽŒA´Ï%±É8®Þq9ò¸·ØþV×!rÇ÷ès`ö~nd×è˜Rµ‚÷õõÓ—·oÜ)‹ß\ìnÛì]4‰ÝÆ\l¢í¢ûm9‡KârÔs¨gü\‡Ž=¾@X‚÷ùE ¡3Ä.;¹;›h»Ò˜¶‡’•»‘Du¯9Ùwøõ<—²Ç£çøîý:µ÷ØDï—¸/¿øá›ýhE ^šëõ‘làìVÕàÝ»××O_V| WIöå‹|„¾×<Ș;­â2µ9kÿ=b¹eüØÇµu¯ç2ÀæÔà`@ ^`+[ìdÍC³¶zC¿‡5Õ&²J*w´·Í=%ð§ÊN””Ã{8Ù5Žssáès¥´¿‘>׎ÇÚíE_Ÿêïä¸t|%ãí/œMZ ÞHò¡ä¡Y[ÕмÝçÖjêQW²¤æëÖæêíε=ûJÏáƒöæ¼76§‡qKNÍ…#=äoê:TÒß51)Úí•Æ"óa…-Æji¿%±ˆl )5x褪ï5¹V²â¬ô¡YkÕ$·JjmT.y8Y/ÃqËx8ÙÞÝžGµ}(»-‹=ã·tžÏõ7ûüè}¾e>¬°ÇñõÞEU Þè›è½¾É¾ý¨ÿ\²`ëci½ï½'=–ú¤Úµkú[3>÷˜ÐòQüs_C ^€óûïþåì·õÕ+ÿ²nòÅI©Á»”\Ûsfª¦ã…5}n9þG’Yîaë¸Dk.‹k¯|ûKð>¿\.oß®s·µ|³âÓ–dœã?¢ó¹¤‘¸dëס^㑽ߞó Τªoéê´¹7úSO]ßjeZ½žno–æÐT‚m*)|–ò g™ [÷£÷õ €RƒàîY‘ ô’RƒwéA>‘¤ÇÔG‘·øØî‘ÚU#Zƒ¸·^†ª‰aVû-ãr–dd~ô¼^µœ¯Àñ¤Õà…=ÊL¸%Yvûð*‰=q)™ÛbPÁê]€óûïþåì·ñ'ÿñG_ÿêßýݺý ¶0å!kCcå¦J8 ?Þ<õqçÈ>Æ~~¬ÝÜÇ©—¶—­×~$³&çØ¸m¬ÝµŽi´íÔ÷—­Ùç\?®qX:¾¥¸”´+‰It¿äΛµ”+Wl/­ïTrôöõ©UŠÃ6SmÇÚm/Úv¸zqn5c¤¥®õO§ê FãrÛ>#.%í¢+@KÆî,–Æ·å~—b\²r7²=¸{jðÐIÕ Þ¥U€S¥º&¼–L%+‡m3WÖö#£‘Ÿ‹_i26+¦÷¸ê³WŸ[ÎÓŒí'–àýðþrùøù«—£+ú–¾›4šÚG©« {ÔG=B\ö¼_€M¨Á @')5x—VõE’‘S5@׬\*QÓÏ­!.{Ýot~îÁÀþ¤ÕàÝÂíŠáÛ•­’b´­»eÝ5}€ãÜ/p²64õ³ákׯ‡O‹&Ò®Û>¬+Óðx¢ýh}Ñø c•1–[ô·¥¥ŽEâm·fœk·Ñb°U5x#¦êÈN=¸iìç³Ú]_ãØÆ–úQj*YzÝfi ÞaÿJú0õÚ\ÇŽklÿÑýF··Ö\©†È(ißÛ6™ Ø¥yÐ:Îp—Ôà “U5x§@¥¯—¶™«å:LÚõ:Æšøeìs©}Iÿ×nkí~·H,Îí#ºÿ-âR{ü-û) °‡ªÁ »ä~€N„à˜š×àÍTZ“6¡/<í€%rÅøjð@-÷Ët¢/ÀAżjŠ€ûevÇ ^€ƒŠ=díùåryûîË—OOoF›yØW;Ø·Œõu_[çØ¼ê} GšÓÙã6už;ßûed¬£s9³]ëkÇÜöKÎÝŒãlÕ×#_ƒöô;rËëUæ\èõû—$Ï/VñÐEÕ Þ××O_þEÞ`Qÿ†ïbÝ«Ÿ÷çÒó{ê5ÚÍùïgÌåìv-Ï›Hr7rîÞ¾¾·óÛ5(÷ºµÕõÊX½¥Õàõç8žžÞbœŽ>§Žgóy_}¹ûSß/ÝÆØ¹”Ý®åyMî.Ci"¸×˜z\]¯ŽûûÊØíˆÕ»tò(Ç}#‰8s?n€’9®Cp[Áûü"R -­ÞíUcÍ~3W3fÅ¥÷ Yί×|R6gGÜ/ÐÉ&+x—3õ~éõÈönÛFÌsûs¥ûm—¥x¬Ý_郚jÒ´öx[?ª$.‘ –Æym?"±Þò=‘8ßž“Ãÿ/íïVq^;öîÿÛk<µ»Nöü½:w|ÑþF_Ÿ[i>vþF÷³÷û’ÖǸöÁ‚%÷CÀq¥Õà¼ÊXÝRZCq®Ýp[ÊìÇÔ®Ö*ÝÞRüZÄåúóKÛÈ|8T4.cóel›%q^ÛH¬{$"¢ý˜ûÿh·ˆsôØö´t®Žî\Û’ù²÷DpÍñµ¸Nö:ß"Ç×â÷L«ß %¿?æ~D/LG[]S#5ŒKyz—Ôà “‡š¾‰Š¬t™JÔDÞH­}ØÏR»¹7©kö»&ù°Ç7]Ù_*M°Dl=ޝæMöÚyPº^ÉݵçeVLkޝv¾ìécÒÃÄmmâ{xÍßjn­ý´åñm}ßò÷`vl¶“±?¼Ô\wÏ2¯”&€s‹•hx~¹\Þ¾›M"DÞf¿Áí‘<`Û¸Œ}Œ¼t¿YÇw{,sož[į¤gø˜}Ïsmiß­æA‹s§tžDη3®Úuްt¾ßÓÜ¢Âó‹U¼t‘Rƒw.)}S4–4™[Ý×ëÇÌã›Z6·J²öø¢µ¨Ç~îˆsvm·œW­æAí6¶“¬öµq‰ìïl5‡ý>:ε  µ´¼G4üø¥7gœe^ûî}Ëw+wû÷Ïy¼s)k–js`VïÐÉCÖ†¢µuçÞ°.Õæ,Ý^Ib`®f_ö~{?¼%+—¥1*Ýo‹ùRû`½–ÇŸl{ŸÏµõv‡Ûk™˜É³5ýÍ·cŸ—ššª­rÙótËó(»¿{¹^•>Ì.sÞïåz CU Þ蛩±7žc®Ý^I-Í-ú±åÃ[²ö—±7ÐSI÷È~{Í—hœ#Ç7צ¤^lËùµÕœšŠýš8¯W­kðNÙØþ¦úSÓߥ2s}n™ˆZšË‘ãΣhI‡­®Ñ™ó´Å¾‡m"× ’}Ön/³¯%5ª[ýQ#r|‘ëRƒ€NVÕà-­[òFcmýË5Ç1·jg,‰ý†©G ÙÈ6[Žof?³ã—1÷Zm3û–ã“}^FWëgÎÁžó #Þ½Îìëwï¸dŦÕùÖzÜÖôi®Mí˜ìõ÷GIü2÷¹¦gÌ `8—X‚÷ÃûËåãgѪ);À)Y½ ð•þÿ÷Ùïÿäü‚àA€-í­v7À‘żÏ/§ƒ9|ªµ7˜°Ýï`¿{9¼“Þ/°÷o&Àï`€£Rƒj©Á Ü¡¥»lC ^€ƒŠ­à}~¹\Þ¾-˜º_¶Š8™Ö+t—¶ÿ“ð€+xjU ÞëÓ®‡<,e½¹'ˆã=çh»£Ç#òý=ì?{Ü"펗#Ï»Û_s=\/"}ÈìïÑÇ šÕ»ÀýË¿ó‹ùÿ·ßï|„¿hºõõŸe§Pµ‚÷õõÓ—·oð)MÖÌÅ9ÚîHñXš{­úMbF·‘1nÑv{‰ËQç^ÏøE¯§™qví€ã‹%xŸ_›ÜK¢àééMjKWâÅ9ÚnýÆ#¢ÅœËNîfŒ[éøöŒK4AÙë:ÙwøE¡Årz^»{΀tûe¶õ¯þó¯fÿœ…¼ìÆÞ?âí#èìͪ¼÷,3¹ùÈöÖÇ´å¶3öõúúéË*ÀÚcͽÌÓ­â2µÂ8kÿ=æØ–ñ«ÙNÖqö/,NE ^à€~õÏÿòÐÇÿÃÿðj.Ño¥¥‡CM%@–^l/Úv¨tŸ[Ùjié½nÛKÚÄŒ%Õ¢I¼#®&ž+7i?l[sž›£ÛõÚGº¾@L,Áûür¹¼}zC¿”¤­]%ÙÞmBl®íÜ1ms,1±•ÒGm°¤¿Ã˜îmÕæÖæ²smçÆ7Únïq‰Îͱ6ØFÏó=œ¿µ×¹#‰\\_€Sz~±Š8œ¥°?ùoŸ àªjð^ßl—¬À{c}°Ôš‡‰ ÛFÑv[Š>Tinû l+V¢áùE¤vLrf¿cg›×{- Ðûe:yÈÚP´¶îm’`jÃÿ_»½%{HTÌ•¹ˆÖ&¾W-b‘YãsiÜ¢ã[:ö—=ž‡GŽßÞúëzÛªªÁ1UçvíþÌíEkðÎ=ôª¦/cÇ1ö´ùhéŠÈƒæ"Z÷7c¿-GSãQr|ÑqËn×#.çÝRìn_?Û¼j%r=h•Ìž›§½®/Í©Á @'«jð–ÖÆ-yíכÑ&{[5æö±´ÿìã«]Mò¾EÛ¬c)ÝgæÜË\-‰K‹9=ö{™W™1i1§—>Ñûúg¥/Ôr¿ @'BpL±¯šbà~€Ý±‚à Ôà€Zî—èÄ ^€ƒRƒj¹_ +xê1ÔêùåryûîË—OOoF›½¾~J=¸ë~–¶;ÖnxŒÙÇ–ÝÇ-Ž3Ͻ÷µw?¶ˆÑTß"}Æ9³]ë1‰œã­¯GG˜[Æ92kçJfÏ|ÝvâùÅ*^º¨ZÁûúúéË¿¹D@·ÇµW· ‡=ÆP_ûÅhîûqÎn×rL§â2¼þL½v&=â\z½¿}½ö8]+`Ylï‡÷—ËÇÏ‹oÄŸžÞ\žžÞtYáÇ~cò¸ýú}Od€Ri5xaÊÙ’3s5\÷plYÇ#©6n¬~±8íïÜ4Àæ¬Þ….Ôð…~ç°Yª)×0WvM»Úc^[;2ZÏv+™ýØ2.{‰ßTL¯Ç“Y¢$s[kê)gĹÅXí± ÌpdÕížo÷çVýÝóõÖ¨ªÁ[òFz쵩 ·_EÚÕìw¬M‰±ím•<ÈÜwϸ Ç´öá}‘yP²½híÚšÝn«v>WÉxD†×2Q–—Ú9?ÜîTò5sÜÆúÐ#έôšWK×—ìyÜ5xèdU Þ¹Ä\¤]t»k÷S»ßŒBý.m3ÏÞqÉêGí8¬Ù1j5Ÿ—ÚeW︌­^.Ýf$é8L޶·£Ä9ëúœÃ¥±oÕ_hM ^¨eõ.’¾ÜóüÎãAŽ)–à}öW!€ËåÇ$»ýwû=îûe:yöBr s Œ¼PK ^¸KjøÒsþ\©Á pP±¼Ï/—ËÛw¢S÷ËVñÂ_üÓ_7Ýþ»ÿåg‚ lÊ ^€ƒZUƒ÷úÄø¡ìEŸL?ÖnxŒ{}(Ò–ÇçÞûÚ»[Ähªo‘¾GãœÙ®õ˜DÎñÖ×£#Ìç@GVïîF뺵û·ÂÈVµ‚÷õõÓ——ËrÂeK·ÇµW· –=ÆP_ûÅhîûqÎn×rL§â2¼þL½v&Î`(­ïëë§ËÓÓ›ËÓÓ›.+üØoŒÇŽki¾ÜKl¢ÇWšÜ‹sv»–cz–ëFf?¶>w\Ç‚ÔàÝLïº­ß _ Ô£ìǽ%M$‰bn“jVnpkU Þ5$óèiÏóoiUd¯c_³ßÌÕ¥gZ-šÝ‡^«x]Çî—ÙÄÿùÃÿyêþýÅoþ™AŠ4_Á[ò`­Û¶íZcÆö†ß¯Md­Ù^$†Yq‰&£¦VªÖô£ôasÛ›ŠëÑ‘Ñr gqíçØ8GæLä¾ÝîÚ‡=Fö»ÅuºõyäJ«Á;÷ ¤±ÁÒÏOµ¶‹Û^ͪ¸Èö²“j¥Û&öÆú›—Û¤âð¸×_´]Éj®Ç’9ï{n˜WUƒ÷,oÞ%¶K¯¢™Ç~{ìíø"㺴:y®½9#÷ËÐAJ Þ#'ë®Ç¸ôŒó^ÏŸÒänf2xë¸,ÕX>ò¸ç•Vƒ¦œ-5WÃuÇ–u<’ˆãÆêï5Nv°!5xw£¶ÆmïŸ(õµ¡šr su`×´«=æ©&Õô£Gr%³[Æe/ñ›Šéõx2K”dnkM=åŒ8·«=–άº½Ñó-;Î{>߀eU5x—Ì%'.—é ·_EÚÕìw¬M‰±ím•,ÉÜwϸ Ç´öá}‘yP²½híÚšÝn«v>WÉxD†×21˜—Ú9?ÜîTò5sÜÆúÐ*‰>·ì8œ–Õ»›ù‹ßü3A¸±ªï\b.Ò.ºÝµû©Ýo­èöZ%ÃjÇ­w\²úQ;kçcvŒZÍç¥vYãÕ;.c«—K·If“Ð-Æ-s›K±hu¹b%ž_D Ü/°3BpLMkðœM´/wF ^þ‹øÓ¿7ûýÿ›ÿ H@ªG!`/$Ç0WʨÁ µÜ/Љ¼Kðª)î—Ø+x*öµç—Ëåí»/_Ž==þr9ÎÔßa_²ûpÝþÔv—¾_rŒkûòôôæ«¶‘ãÊŽËÔ¼:ûùt¦kBƵž{läùÅ*Þ;ñú÷šþü¿ÿÍd HÕ Þ××O_þ].Ë «£;Co?[4¹ÝÆ\œ£í¢ÇÐrL§â2œOS¯±Ïóè®yÀþ¥Õà]Jx<=½9U2$#Ás¦˜d'wçâmWz -’vÙ«3Ï2g²ûÑ#.=“¼g»žœ‚Õ»t¢/Ííá#è’aœÑª¼køÈùy-%p{ýíñEVñ^WGÖw‹ÄöYΣì~ôŠKæ|q=885xO£¶Ænëý«Ñ =¶ÞAäAXS‰°¥×§¶9—ÐÛ"12–Dœ{¸V¤ÿ%qܲ¯=Œ%ÕJçÐѬ}ðÜm¼ZG%±¯éÇškAF·œ;Kû-½žöê°´¼K’Êy¸ÖXÒ/»^f$©5µß©k •ô£e_·2Wow®íÙ“»Ñó(2÷zŸGkû1wŒ‘ñ-éÃ5¾õyÙoÉõ´W?î–Õ»tRUƒ÷š\«M¤E¤µæáZ‘Djf³Ú‘~¬}èØ ·K+<%°ÊçOöy=3ú°f{¥ýíueï÷ ×`YU Þ^Iƒ^IŠ’•‚´‹óTÂn*)<µ‚õÞ?²¾×¹z;–kÎAèB ÞÓXªqÛºF¯»@©”¼Kêìõ¡]S¢5ƒÏ¦×ƒ¦"Ç£è÷Ï—çQÉù[3v{‹å™Ê€ÇKð~x¹|ü,Z4geízS+_ÅsóÚxœœÕ»wci…íøÿzöûïÿù3AR=dm¨UÍÈÈ>¦>Î}4kû±U ÔÖã?<ö©~´êo«º±Yq)9þáÃɶ8–ÎßÖçÁÖçGö|éyþÇUUƒwÉTíÓ«5É‹=¯Rœ;¶©z¢Ykl«ÅxLÃØC½"ûÆ$»$@Ë„Zm©†hüJj×ö8²ûÑb^õœ/ÃëÄÖç/•Ôà “U5x£µq×&p·j“yL¥±‰n;cß-bR²ÒýFÛgίֱ©›è±ÍÕ€K.·82úÑãØJçF«¸dÄïhµË€:jð@-«wù/ÔØ¶ö ÇKð>¿ˆìÜíÃÄnÿÝ~hÄý2< œ‡D.À}‰­àUS Ü/°;jð”¼PËý2XÁ pP±‡¬}x¹|üüå˧§7£ÍÎú€§½õ÷z<û_ÚVd_Ãø,m+£]f ZÅ…c Ñí¯¹ÌgI¶<÷(¤/T­à}}ýôåßå2ø8‹³õ7šÄŒnc..ÙíZŽAI\Î>çpNöšÑëAæ|¹—k-—Vƒ7’ä8SR"+ÑÒ+.ÙÉݹ¸d·Ëƒ5qÉLô—Ììù²÷ímy.–̃è1´˜/=“¼g»Ž¤Rƒ€NÔàå+>º ÇKð&Ô»]ÁF߸D?z~„Xd®f\SwwëÕ”Ùc³÷ííqÔlçè«x]ÇÚÞ/À­wPóÀ¬¥×§¶yûsÑ{µìóš>Lµ=brå:OOo¾JL9Y´4æ>ÎßúdÏç¹9sýƒÀ,vä?XDâ\2ÿŽ4n©Ôà “ª¼×d]mr#úÀ­5yŽ&вú›™ˆ›ëï^ ·Y'˘W­Ü΃±>lõÇŽµçQÆ~ÖloíCô"çyïy0ã¥ù²—s8+Î{78›X‰†ï/—Ÿ'ßÈoýæ½W² š˜¼7%+Aof*)¼÷ÕKå Î4®SII»Çà^æ ÀÝSƒ€N26’¹ê+²"nø‘ñ­ü3Õß¹´ïÉžWÕ•&w3“ÁgXm¸¶ÆÜö"%Ž6oŽ>5“Vƒ—û”™“´‚üós¯¥!NÇý2z$0¶XåWò³žÇ¿TóµUmØVõe³æñÚyZ;Ÿ³j6gŸW÷6ZÉîoëšÍ@[U5x—Ì=€êrY—D˜ª º‡„Äܱ-%i§â2Üæp[YÇ;ö0»5Ç75ÑvSû¶o™ˆš«Übž.Å&û<Šn/Zƒ·Å|)íË^çAí¸l1ï‡×”HÍà¬ñ8•#×àýÿþÄø¸þ[ú“ÜÍ=®ù¡¹Ú¸‘vk¶Ý¢Mv£mK-#®%}«=¾µíJöÛ:©´vl[ô'û<ÊŽsö|É8ßöp~´¸NfÆ:zMÊî/K ^¨å~€N„à˜b Þ#×€ÖÜ/Љ¼¥/Ôr¿ @'VðÔc¨Õ‡÷—ËÇÏ¢S÷Ëõ³?ú™ñƒN~ý1¸g®¿@+x*¶‚÷ùåryûîË—OOoF›½¾~:eöÖßëñdìi[‘} ã³´­Œv™1hÎu.ÀâýòWñp\U+x__?}ùw¹L'BÏâlý&1£Û˜‹Kv»–cP—³Ïù#œ“Ƹg±o`5ÂR¢åééÍ©’0Y‰¥^qÉNîÎÅ%»]ö¬‰Kf¢¿ddÏ—½ooËsñHç/;dõ.¨ÁËW|TŽ!–à}~©ÞÑíŠGúÆe)Ûk¬Öì7sõ暺»[¯Í›½o¯ÇÖ>ð.{>—œ¿[Ε¥ý–ŽÇÑÏa`¿ÒjðN%—²W¸Ej Ž%³WøE’iKljËp{{ª÷9WGw®mIr÷¨‰àÈ<ι9Ñc¥íX²çóÜœ¹þA`ëÕ¹‘ý–ŒG¯~°15x褪ï5YW›„‹>pkÍGä£ ´¬þf&âæú»ÃÄmÖÃÉ2æU+·ó`¬[ý±cíy”±Ÿ5Û[û½ÈyÞ"ŽYûíYÒ8¿X‰†ç—Ëåí»¯^蕉&&ïMÉJÐÛŸ™J ï}ÕîRy‚3ëT[™¹_¶Š€RjðÎ%ëÖlãöµ©¶=Mõ7Z3¸·Œñj¥4¹›™ Þs\ZœGÑíÅ|o1º‡šÎcb Þï/—ŸE‹¯d&ú$éØb¾^™g¤²z Ø_ÿÕ¿þÑ×ÿèÿ… ¬ðµ¡Vµ*#û˜úyK[”§(yˆYÏã_ªùÚª6l«ú²Yóxí<­ÏY5›³Ï«£ÌƒÖ5Œ2UÕà]2÷ªËe]Òdª.è0sǶ”¤ŠËp›ÃmeïX©‰5Ç75%¥"Ìk™xkUrdml²Ï£èö¢5x[Ì—Ò¾d'ù环Åu €Pƒ€NVÕàÖÆ]›ÀݪMv£mK-#®%}«=¾µíJöÛ:‰¶vl[ô'û<ÊŽsö|É8ßjã’¿½ÖÎE ^¨uàÕ»?ûÃïôòß«9{Ï\ážý«Ô­=(À15­Á wA ^€EýWÿºèûÿè­pˆ°‚à Ôà€Z^½ûë¿úÆøM,­Ø-ýù³­èuý…ûõóÿ*w{Vð”¼PK ^€ê»¥ÛW£àoXÁ pP«jð>=½möúúé”AÚ[¯Ç“±ÿ¥mEö5ŒÏÒ¶2ÚeÆ Úï©}®=–Ö}8êœì5-úºå¹ @gVïÐIÕ Þ××O_þ].Ӊг8[£ÉÝè6æâ’Ý®åH¤­;7ŒÇ¶q¸\¢ Þç—Å&K‰Œ§§7§Jrd%nzÅ%;¹;—ìvÙcPÚŸgžIÞ³]wv-p¿ pïþÑþ‹ý+ý>ãÔàå+’œp «jð®!Y¸Ÿ¸,%p{Õšý¾¾~ú²J±ö¸%¶sÆÐx´‹ë.ÀN©Á ð•ÚU¸ÃŸÿë¿úׂ 0â±õj˜µôúÔ6o.ú`¯–}^Ó‡©¶G­C:Ln9™:5ÿÖ>”«t{%çÇÜë5ýØó¸D¯G%×­çóÒx”^wÏ0¾p¯b Þç—Ëåí»Ù&S Žìú“cI¨áª¸Û„âRÛ¬ã˜{}ê#q™JºíÁ\âv®í0kâ|ø,ͽH]ä¥íµ˜ó¥ýèç5óh¬/Ñv=çhdp«ô!\cmk]Ký­ÝÇpSýÝ‹hbè¶/‘äSƼÚKl"ó4Ò×ì‡ÔµèG¯8ßþ›kSz¾-ýl9zoã Ì«ªÁÛ+Ð+ùMLÞ›5‰³¹š¤÷V ·gï%Ö-ÎK5›øê~€YK5t‡ß·b æ!c#™«È"+7‡+ö2WÍÖôw¸JuëãÚr¼Z)Mše&ÙzÇå Øãx´>/×–ˆÈVƒ—û”Y¯ó^“`ꟷá9pçÀá©Á ð•¥»¥?oE/À¸‡¬ µªÙÇðá][Øbµç\Õ=ÿš:°ÉÜ Ṹ´êGÖ˜”_ö¼Úz<¶:§—®/õ•3Ï7à¾TÕà]2–ð¨]¡v[»uøzosǶ”L›ŠËp›ÃmeïØÃìÖßÔXDÛMíؾebk®>pI?²÷½vNõáö{µñì5™çeÍõeé\j1G¦Ž­Åu€àýòAýúã¯tó|W½®À]Z¡[»ØõØ«ŸÿWߤnïqÍÍÕÆ´[³ím²ûm[zlq-é[íñ­mW²ßÖIª¹í¯íGt×¶«9?ÖÎåžã‘}^foö¹½†ÔžÀp,jð@-5x¾²T3·öûü!8¦X‚×jp¿ ÀîXÁ pP±ïó‹H€ûevÆ ^€ƒz µúðþrùøY´`ê~ù¨þ¯??èå7Bp×\$VðTlïóËåòöÝ—/ŸžÞŒ6{}ýtÊ í­¿×ãÉØÿÒ¶"ûÆgi[í2cPÚï¬~LÍ«±öÙýÍžÓ™Ûk=¶ÐÄó˱WñpX5?µÍ¹¨[$‚ÆV½–öaªíYÑ2s}—Àë'2Ÿ·Ø÷ÚÞM]Ì)à ÒjðN%↠½Z‘‡WÝ&—ÚfÇÜëSljËXöb.q;×vƒ¹~/µ;ƒ„¨™ç[­ Ϋ©:ÌÑó"²=XíÀ5xاoþI]æïÿíÏîÄCÍ_“$µ«,Ç’4S‰¥ák‘Äâíÿ×>m©¿µûîoª¿{M˜Ýö%’”‹¶;ƒk_3çNö±õœ[‘ó¼Çöö ªo¯$I¯¤L¤¿÷˜0ZSf!ZKVÍÙ¾$@ èÀ5x؇¥»K+r‡??üÚŠ^8¯”¼I¸’ð÷NôMõ7Z3¸·½&M׬ϬÑ{„dò–5‰2ŸîY¬DƒÕLì»|õ‡‰Úv÷3ñà4Ü/ÐÉCÖ†ZÕÈŒì£G¢h‹òsµ‰÷tüKµ“£5–£í"ßk—Vý(󽔪ȎÀUÕà]2–$‹”`˜3VÊaí¶²ÍÛR’v*.Ãm·•u¼c¥&ÖßÔXd·k™ð›+ÕÝ©xÛ·êïÜyÏs}ȇ©øµ¸¾ÀjjðÐɪ¼ÑÚ¸k¸[µÉîo´mé±eĵ¤oµÇ·E»ÖÉ»¥¿eô£¤Ùý­íC휌Ʒå8Hg /Ôr¿ @'BpL±ïó‹H€ûevÆ ^€ƒŠ=díÃûËåãçË?ûÿü#àÞ÷ªÁ @'VðTlïóËåòöhÀÔý²U¼TøþßþìG_óO~=ûuéö€ó²‚à Šjð^}ÿÿóh³oþ·¿sÊ í­¿×ãÉØÿÒ¶"ûÆgi[í2cPÚï¬~LÍ«±ö[Ž9°‚Õ»d¿/µªZÁûÍÿöw¾ü»\–VGw¶þF“»ÑmÌÅ%»]Ë1ˆ$w³ú1œWÃ9¶E8®X‚÷ùe±ÉRêûüŸO•œÊJ¸õŠKvrw..Ùí²Ç —VýØzÎižÀaî— …G!`è6A)©·,Zê@I²­ªÁ»†äÖ~â²´z·×X­Ùï5 ýý?þÏÕÇ}„Ú´™ýuþ@"5xßþò[A`3ßýÙw‚'Ñ|oͳ–^ŸÚæÜ Ô-UsåJâ2Ööˆ‰¶±¤d4™ê`ÛÍÕµ”›:ߌ@{±ïóËåòöÝl“©D\vÝÐá~ÆV3Þ&—ÚfÇÜëSljËXöb.q;×vƒ¹~/µ;ƒ„¸îwéÜ(™w‘íÀi=¿XÅ ¤[Za¹´â÷ì+4‡ý¿·þfÏà¸j~øšÄ©]e}PÕš‡W ÛÖ$œ"ý­ÝÇpSýÝ‹hBï¶/‘¤a´Ý\ûš9wJÆ.rõØ˪jðöJâôJEú{ ­5e¢µd{Õœ(bõ.µÍÛŸ‹>$ªeŸ×ôaªíYÑr s}?Z¿×>Pî6^sx›;¢±ëqnÔÄ1Òç¥ëËÑÏ%€¡´¼Sɤì‡/ ÷3¶Zð6¡¸Ô6ë8æ^Ÿ:ÆH\Æú°s‰Û¹¶ÃÌõ{©Ý^EÆkn®¬Ù^Iò¼å¹‘e8¯¦ê0GÏ‹Èö`5«w(­9Û{EëÖûßzÅ0ÀVªjð^“$µ«,Ç’4Sɯák‘Äâíÿ×>m©¿µûîoª¿{M˜Ýö%š¬ÜcR{븶°æ<ꃌãÛ{Ö¨ªÁÛ+IÒ+)S²*óž¬)³­ÕÚ«¦ë=Ü€DjðXqzìø? KJ ÞŒ$\ÉGø{'ú¦ú­ÜÛ^“¦kV‚gÖè½·dr‹>µf2ÀQ¥Õàå>YY»ÞØ5®¯ßü¹§þp¬Þ(­©ËÙçÃâ/#A‚;õµ¡V52#û˜z0UK[”§˜«M¼§ã_ª­±mùÞVq©9†a]âÌúÍsçG«ó({<¢óàžUÕà]2–,ª]¹·çUsǶ”¤ŠËp›ÃmeïX©‰5Ç75ÙíZ&ü–J5,ͽhü¦æËp›¥çQ$†‘ó¨d¿­’ís}hq}€ÕÔà¨É À«jðFkã®MànÕ&»¿Ñ¶¥Ç–×’¾ÕßíZ'ïjâm7W³ù6¹Üë<*Ùo有ž+µã! œA¬DƒÕà~€Ýy€cjZƒ˜­Á €¼pJßü“_Wýü÷ÿög‡:ÞÚã¿÷ýôò(ÐD.5b Þï/—ŸE ¦î—î­]AZ»½Òým{ß?À^¨Á pPjð@-5xáζBs©?­WÀÞûþ¶b/ÀA­ªÁûôôf´ÙYµ·þ^'cÿKÛŠìkŸ¥m•ÆïééÍWm3cPÚïµýÈŒÉΓ#ö¥Ç¼Zs}‰ÌÏH¶¼–œžÕ»p—–V€ÖÖðm½¢¸÷ŠåÖûßz…®š½@/U+x__?}ùwûÿ¬ÎÖßhr7º¹¸DÛE¡åD“gÇp»³Ì¥#Ÿ½æUÉõåöõÚã¼—k7œYZ Þ××O—§§7£«-/—ó­îZêoT¯¸d'wçâmWz YcËÚ~œÝÙâ²õ¼*9†áv2޳çXYõ œŠ¼À K+>­­³õ aãôò( Ý&]z­ì;ÒŠBÉ)qèeU Þ5${ö—ÈGÅ{*I0g®>´š=Ï«–+¥{­âu®§bõ.Ü¥¥›K+8{¯ø,­Q›}RB'{ì}{=÷[R§¹tîîé<šjw×€]²zNa©¦jíöö~¼¥ÇïûØ‹”¼Y«´–>¿ôúV¦ú­ÜÛ^WÁ•ÔgŽ~¿G\²çÁÞ·×{¿‘±šš[Sc½ÇyÕcl€ýK«ÁË}òQéý˜Z©j|È<ßÍ+€™ûe«xát޶‚³÷ñÞûþzyÈÚPF¹†¥z¹Sû˜úøuK[”§ÛGÖþ2ìø–(—±b°ÅªÃHýØã‘á6·ÿzœ [Ä%z=(½>l=¯ö4o2·×*–ÀUÕà-y£?öÚš7ý{^¥8wlKɯ©¸DbV{¼c¥&ÖßÔX””à(™[-Æ}î#õSýû:kD·­5Ý^íÜ_—ìëAI Þ^óª…©˜FÊÊdôs)Æ™¿váÀ«w¿ýå·Æ`CïÞæ¾÷]Uƒ7Zwmw«6Ùý¶-=¶Œ¸–ô­öø2ǤWæ¹íGb–="Û›«q;L*¶ˆk‹¸dsË9ºÕùÖ⺛y®GçvvàÞÅJ4<¿ˆ¸_`g„à˜šÖà¶SRkHvà¼Û£ÀyHäÜ5x –ûe:Qƒà b ^5ÅÀý2»c/ÀAŲöür¹¼}÷å˧§7£ÍÎú€§½õ÷z<û_ÚVd_Ãø,m«4~OOo¾j›ƒÒ~¯íGfLŽpž±/[ž[œÌó‹U¼tQµ‚÷õõÓ——Ët"ô,ÎÖßhr7º¹¸DÛE¡åD’»Yóàv;g™KG>?îåZœGZ Þ¥ÄÈÓÓ›S%M²A½â’Ü‹K´]é1´HÆE“»-áhΗžÇ~¶ë$À]±z€N…€¡Û„]¯dÓ‘’\>‚/.½ÄVð>¿Tïè,EÏÖ#.K«w{UIíÒÌÕ–j¦Òb^¹N܉„ûeX£ù Þȃ—¦kK¯OmsnêÉ“±¤Pi¦Ú1ùs‡Û‡¥•ŽùEæAëyuÿhÛÞq¹ëØy¼ö¡w½”¸t—^'~Mò¤ÕàJÀd¯H‹<Ìi,‰˜½"/’ \:ÆH\†ÛÛS邹z»smϒܽöe¬njt¬÷KµŽKz—½º6.Ssji{‘6[?îš°žÛgÉu2²=:Pƒ€Nj~x˜ÄY›˜‹>˜kÍ܆mkWP.õ73¡=×ß½&n—Úv¦ÄÔÜXgÿa£v{­ÿðÒ".Kó¾öán[•CÈ~øœ‡ü·b%ž_.—·ï¾z¹Wr¡W2#Òß{L´,%ɦqSIá©§Gú(zö<Øûözîwi›·s­tî@ØóËêU¼~P#¥ï\²nÍ6–nv{ßOõ7Z3¸·Œñju\CK«Ã3Ë:dÅ%{ì}{½÷[ò0¾á~§ÆÚ÷€£H«ÁË}òÑðý–ˤÜfþO­àθ_ “‡¬ µª-ÙGËå)JbÖóø—j'Gk,¯Ýov­Û©¸´ sÛú\Ø".ÑëAéõ!{^eÏ{€[U5x—LÕR½Z“䘪§¹‡„Éܱ-%¿¦â2Üæp[YÇ;VjbÍñMEI Ž’¹ÕbÜçJ5Lõcìë¬yÝ^´Ölt{µsm\²¯%5x[ýÑ`nÞ·¸NÐAE ^¨±ªo´6îÚîVm²ûm[zlq-é[íñeŽI¯:ÌsÛÄ,{D¶7Wãv˜¬n×qÉ:æVs4:OJçÓžÎ`ßÔà€Zî—èäAŽ)–à}~)عۇŽÝþ»ýЈûe:y8‰\€û¢/Ôr¿ @'jð”¼PËý2XÁ pP±‡¬}x¹|üüå˧§7£ÍÎú€§½õ÷z<û_ÚVd_Ãø,m«4~OOo¾j›ƒÒ~¯íûœãB ^:©ZÁûúúéË¿Ëe:zgëo4¹ÝÆ\\¢í¢ÇÐr "ÉÝ{š÷½Î5±X–Vƒw)!óôôæTÉš¬T¯¸d'wçâmWz -’€ÑänËc lÏv½`jðЉ¼|ei?Rrív5/l)–àM¨)& ¶Ÿ¸,%p{UI‚9s•§Z­û–àýðþrùøùË—OOoF›õAZ{ëïõx2ö?·­a¿8¾[Å 8—ŸüýŸ„K+üäïÿärùÓŸ ]T­à½Mt==½¹<=½9uòëlý$w¯ß;j__?ÝÅÜòýì7ÿk¨Ý¯ú_ ݤÕà½M޹&ÙÎb©¿Q½âR’ÜÍìï‘ÇêHã lL ^:Qƒ—0+``_b+x?¼¯ÞÑëë' ÂÄåkÉöZÅkÞÀH¸_€5š¯à<¨k*á¸ôúÔ6o®ÇƒÂÆ’ˆ¥}˜j»ÇdáÚñ(ïa ä1[ÅgiLJçýÞÇ€}Š%xŸ_.—·ïf›L%ç²WNFþuû`­¥¶YÇ1÷úÔ1Fâ2Ö‡­Í%+Kb|ûzÍXÌÅ~‹‡©EúQ2^Yqòýü7¿žýþ_þôg{¿l/T­àÍZ{›&Ææ’‰S?;uLµI³H3ssýÝÒT²²t=·ÔÇ’rr‘Ri™óyê|9ÊñÀRjðf­b&í¦¶Õû—íT£5ƒ{Ë^%Úc<¦nbçnpöæèÏ Þœ{µ£%µ3ŽuëÒaÑ÷Kc±ôýèó'2ú7%ÇyOuü°•´¼pvÜjUƒwÉ£ÞÇpö{­^ý»ŽëV‹Lö0—# [8³Ç¬ e®âú%\ºr¶õMDëZ©sµ‰[t¿ÙãÝoéö³çÇR­hàFãßìÒ kVgÜ—Îñšmoù~Ï}>GPUƒwÍÍBíÍÌTýÕ=üâ;¶Û×Jâ2Üfæ_ã£IÞ©~´HKjð¶HÀ.½ah1ï€+X½;¼§ˆ$éÆ>"?õ±ôèGÔ[&¯–î kîi#%"IâÚãÄ7rü½žgýzêþµ÷ ²æ§{sÎ`Õ Þhmܵ Ü­Úd÷7ÚvÍÊÖ­ûVÒ¿µ‰ª™GÑÔÆzÍÖ››L¸S‰ÀÚ¤_äç[Þsl@nqOX²ÂºÅh=ïæb©{{䇒¹ßàlB­ž_D Ü/O%Ónÿ­Ùfí6j­M\ÞþÜÜ çÖý›K¾÷ŽmM|·R›ôíÝ?å8’G!€¯ýú§ÿõ.Ž##É]•™m«:¦­ö9þ-V[ï)v{L|FÆH²€3kZƒŽè‡ßþpùßÿò»PÛ?þù·«jðN‰ÔD½¾ùù±¶[ÖO&IÇžM1U£wîÁË‘X´8þ¥ñYê_t|×[4¾s5h—â_c2Ö¿¬ã›;Ÿ$„8+x`C‘ç L}õ,Œ–+k—ú—ñ,…µÏ€h=>Ñ}g>ccͶjã×2þkÆ#sîd?lA ^¨uÀûeI,€sx€cŠ%xkŠÀé¸_ +x*öµç—Ëåí»/_N=åõ¬u¼öÖß©§á¶ØÖ‘Çzé©Á{èCëcÛ~¯¸”lË9)ž_¬â ‹Çš&Z=‰w/ÎÖßHâëú=I²vsªÕ\:ò˜µŒ ô¾ÿûÝÖãwÞíòý¾mÛ±øÎ}ÿÞÓõÒjðc79Sß;¢¥þ–ÜüõˆË=$lÇÆhýΚKgßqÙûy Àlõî5¡|ý—ý{ïžc;ŒïÒ÷¯÷AÃSÔà€ “y{H†Þcq˸/ÅW¨Kð>¿¤ÜÔ¸qÙG\î©ÜÂí*Ð=÷;sµê™Æ·×*^×+ŠÜ/߮؜+ÙpûoìwýÒ÷§¾ŽÞOLm¿õñ-ý|íþ‡mŽî±õ–êOݶ‰>ô)ZÓjêãN[÷yM¦Úî1é´v<¢vkÝçÚù7lSÚß½‹Ìç’v‘oÑ—H–®Wj°Öõ÷ÈÔï±ûáýÆÜב߇s¿Çæö?¶¯Û×–ú¶&6µû~]{Œ½ïYnżÞ_.?‡nB¦n³þ:>ÜÏØƒ˜nдÔ6ë8æ^Ÿ:ÆH\Æú°Ç›ÏHŒ‡7æS7çÙcv›ˆ«ûèøFû»—7µý-‰ËÒ9Ô²¿KãQrží}|ØXr Þ¥ßE÷FÑÑm¶ùƒ{éñíù÷¶{  DÕ Þ¬•–· Ùa‚e)‰4ö³SÇ”•ÜÛêFq®¿{P:KíÖŒïžo¶÷Üè¥È±.ýq§äg¶êoÆxì}|Ø¿¹?‚Ö&4kïñzî?ûž àìb Þç—Ëåí»É«­oøzÝ`Fú«Ž×qÇ÷èÇv”þÞS hîÈóKú*޽ܔ~²eÍ÷3ޱtû[þa¶w|€sK©Á›µnø„hM²­Mõ·¤fë©[ßµß̘g­&m=Ÿ#Ç' À=«ó^òûwê磿O—öyÎÅ\­úìã[s¯°ô»Ìñ[êô~Ëý0%­/@ôMÏõKvMlo~è&¸z7º€a©ÔUÍÏG~_ÖþüR›ìã[óý–«fkŽÏ½ Pê!û&¦fu_ôÆu¸áÊß-lQžblYû›;þá÷J W³â²×ø¶ŒsD‹Uª[–OY;nKǘ—¬y œƒûà,ªjð.KÜÔ®´+å°—´¹c[J.}„í6!•™ä{ Úp¿Ñ>g<ÕyëñÄ9:¾kΑý«-ÕPÒßµãVZî$#SÇÖâzÀiXƒ欪Á»ö£e5ÛnÑ&»¿Ñ¶¥Ç–×5q*©ƒ–¿ìþÕÌ™ìñ-Ù^Ë~gÏçó öYsîÕÎw ` ‡X‰«Àý2»ó ÇKð>¿ˆTÞ//=\t­ÒŸïñâ±ý¯=ŽÈÏ/m·gÿ2= Ü—Ì÷–{lÉCa#?/¹ Ü5x VÁýò0¹¸×dã–Ç•ù°Ò¥dqI2à¬à€ ]WÏÿ{køõØŠÕ©ïE~~Éõç˜ ]:^É]àlb Þç—Ëåí;Ñ€©ûå‚U¼·ÉÝ¡¥KåjK ,_kc+‡oc,!.i Ü3+xàÀ"+€×n·Wæd$°Î$–àýðþrùøyñ†ñ¬7U{ëïõx2ö¿´­#õTß2ãw¤±ZñÌŠ–¿³Ý܇š~}ýôåßårþ§Ñž­¿‘„àmǾ&çÍ—'9µ÷tµm2~¦e—Vƒ÷úѰ¹Zb×vg°ÔßÒ›Ù­ãr«=ÇÆhýΚKætTXƒ7ro0|mêûK_þö{KŸxjqR[C·¶‘þ‰¼°‘©Dâðõ¥„ãRû¥OhE޳åŸk·[Ó?É\àlb%V#øhÿ~ârO+nWîî¹ß½J58/ IÒêÝ=ÞŸ°oÍWðF>~Uú0¬¥mÞþ\ÍÇ¿²ú¼¦Sm÷x£½v<¢vkÝçÚù7lSÚßÖc2wÎEÏ˽ÏA€{[Áûü²Ød*–½Bðv?S«Çê­f¯Œ$—Ž1—áöööŠ’_?æ7׮Ř kÖeöw©/=ÊÙoÉyÙ«p(ûehá¡æ‡¯{¯ýèûXâhîc »©¤Ó°míÑ–ú›™ÐžëÇR»5㻵’ñíÕìýîy<î]¬DÇ÷—ËÇÏ_½Ü+ÙÓ+¹é¯Ä×qÇ÷èÇtt¼CJ Þk通'íÞnãöµ©¶=Mõ·¤fë©[ßµß{zðÜ»Èó *­/°ÍÂáB€(¼_¾­çßê9 >up²6ÔªÖgd=^[”§˜«SÛòø‡ß›{€ÞÔñ­Y…Òk|[ƹäÍWvíæÛŽ£õïIb€}¨ªÁ»æ¦/R‚aéFu,á·‡Öܱ-%§â2Üfæ ¹R cûö¹f,zo$ÎÑñ]sŽdöox<‘’Yãw+¹ïܽÐõÞ-òû~®×ÔÏÝN•&«)Ñ@ŽU5x£µqkVqnÑ&»¿Ñ¶¥Ç–×5qŠîg©]i-åoÖÌ™ìñ-Ù^íxµWoâ ÞÒ³ç¬×äî\RvîÐc?¿æÞJr`Ôà€Z+jð^ÿ;µÊ¶¤ö~D«ä.À>< lojìÔk½¨µ °o±¼É5ÅàTVÞ/Gjùo‘`Öã½]=<µRWâ`¬à€Ž†+yÇ V’L{¸ïÔuo¿~?²uxúSƒjÜ/G¼z­Í{›ô]ÚÆØÏNÕøÛÇUIÍ_É]€þ¬à¾[1IJÐG,Áûáýåòñ³hÀÔýò‰HÞǃSlïóËåòöÝ—/§êrõ/ý{ëïÔÃ2²¶Õ¢¿‘ùi.´Š=pPÏ/§[Å À1T­à>˜¡äé¾Gt¶þ.%3û;÷€£Í{˜ëC,ÁX°”øzzzsª¤XV¢¯W\JWJlî#g;à4 VïŽý.÷û€µÔà€ƒ‘à*–à}~©ÞÑY>¢Ÿ­G\Ô~Í·o®œG°S…÷Ë{HÐJœÃcëD®5•p\z}j›·?×ãá^c7Ë¥}˜j»Çä^VŒ£ó å|‰¼Þ:†sçHô<Úûœ€{wý}=õ{zîwÿõ{s¿ï£÷?sÇÀ1¤ÕàJ†e¯8¼ÝÏÔ*ʱD`öŠËHRpé#qn¯×J‹h3cÜk¾Ìõ·Õ1.ůä<ŠlHVPƒ÷ö÷ûT=ÞÛ{É©?Þï7£??ÜÇVUƒ÷úÀ§ÚdX4Á6öÚRkضæ&6ÒßÌ„ö\·°Ôß5ã‘¡Å|¹}}ëÙñÛz<€ºû€¿§oïã"÷ÉW¬DÃóËåòöÝäMáÖÉ£^ɪHÏ”H»·›þÛ7XÞðEž_V­âÞƒ¸ ÔCÆF2WFVP?r¶õƒ§¦ú;Vža7×gXÕÙsÅíp¬z[º¯›*ÀñÅVð~x¹|ü,ZÜÍ£¬ŽxØ܉•«wÇD<÷PÕÈÏ{ÈÀyæj‹µÒ»ÖìžÆ+ëád¥ý]3_2—½z·×ÃÝ€>æî[n¿^úDØÜ÷—~ÞCÖΣªï’¥‚­MŽ%t÷ps:wlKIË¥·‰¿Ì$ïuÛ5Èöy*yÚ£¿%Ç7uKnˇŒøTÔàíyï Àñ=®ù¡¹Uµ7‘ŸÉj“ÝßhÛÒcˈkIßj¯õö²çBÆø®ÙwtND÷YÒÎ!V¢á`«8¦¥6R¸_ “!`/²kúÀÙżÏ/"Å&n“¼’»Àa¸_ “G!`o$t€³Ûãƒ×ÿÔqßÃêÇJ‹}"møúXL¦ì»´Ýh›¥‡ø÷=Ö~íXNm¯v~ÔãXÍ}‚os'ã=ך{ø5û5?úÏ•ëu!³¬ ÀÞ©Á Zª¡™Qc³fÛÒþo¿·Tîkìûµý‹ü|ˇ¬-Åv‹þÍÉŽíJܱz§-çGdŒ¢ý©é³ù±n~l}ü-çÀ–VÕà]{#Ä>âreëUªÁ¼€;QXƒwéa)¡²öµVû/½ÿ©ÝFäû­Õ25?ßbß5qKpî9¾óÆü¨‹UMß#ql} =4_ÁùëÙTÂqéõ©mÞþ\'ŒŽ}„£´Sm÷øË¤E_–þbZòzë>ÏÍéè¼ßû{*Ì›û¿9€ÞÒjðN%×2kß ÷3U[uì¡ ÙuX#IÆ¥cŒÄe¸½^õ¢ý‹ñm=¤Œv½DޝdÞソ@Îý2íݾ—ÜîÅCÍ‹Ï×z$ä¶XÕ:W›xëãk­Ìõ)—ÖãvÛ—¹äôÜ~o¿žúÿÖs/ÒÏ¥ý–œ—‘íÀÝSƒ€Nj~x˜,[›ÈKmsÍC³¢ Ȭþf&´çú»…¥dçšm•Ή̘Îm§dKãÑûánÙûÝûCêîY¬DÃóËåòöÝW/÷JöôJ.Eú{ÖÄW´lÃQãÒâø$AàŽ<¿XÅ @)5xk“Ãmܾ6Õ¶§©þFk÷–1^%ö—VÇW[¾`´¼œÇTÍ]ö36ÆvÆý2z$¼¶(O1W›¸åñGk"OÙK²eüÖÄv*.Ù«w׎ÇSUƒwÉ\2ërY—t+å°v[ÙæŽm)É8—á6‡ÛÊ:ÞaüJKf̵Æe«1î·ÅñEçi‹ìXÿZŸ—p÷Ôà “U5x£µq×&p·j“ÝßhÛÒcˈëš8•ìg©mË9³æØ¢û·Èx¶˜§ÑñÊ×½ÖÀào©Á µÜ/ÐɃS,Áûü"Rà~€±‚à Ôà€Zî—èÄ ^€ƒRƒj¹_ +xê1ÔêÃûËåãç/_>=½möúúé”AÚ[¯Ç“±ÿ±mMmí~3w/s¡U_æÆ£dþÍgIzö7kþµÛÖç ¤/T­à}}ýôåßå2ˆ:‹³õWbiÝh5öKã·¯×gÏþÞë<(‘Vƒ7’t:S2$+ÁÓ+.’»ýǾf<¦Žáv;Yǹ‡þÞË<Øûu€ºûehA ^€ƒŠ%xjŠÝ®(¤o\¬ÞÍ·ÛXîa<ƶ³ÇU¼gš½Vñºžì¼tòØzÃÄGÉCŸ–^ŸÚæíÏEöߺÏkú0ÕvOI©8¯}HUéöJæÁÜë5ý`?ó0z)¹lŒ^š¥×SóÎ/­ïT"${¥Y¤ÆèXâ.{¥]$y¸tŒ¥‰Ð±„õ<=½)ŠñRÒ,²½c[ÚÞ1Ÿ‹á\ëÌÎÕ›žoÑv=c™%×Ó#Íg€SPƒ€Nªjð“/k!c ˆ¥žs?;¶íëÿ×$k"ýÍLhÏõwOJÆ#2W–¶×ªA‹Ò™¢ç[$1z·ÉØ©¾Fη5|ê‘@¿·ù 䈕høðþrùøù«—{% z%)JVý1›Iê3¬xûR93Î)s€îÔà “‡Œd®6‹¬P®ìÛúC%ßóŠÛ^‰¿3$3“€÷V"³¤FËó-r|’Á@oi5xa‰z Üë<=CÉ Ü/°OYjU32²‰“-•sõg[´îm¯Ø•_vüZ¬ÚÜsâûèý]{ÝȨ'½&έbœSU Þ%c‰‘Û×Ö$/^_?&fö™;¶¥$ãT\†Ûn+ëxÇ@5ìKv‚ojßkc=Õ‡ÛïÕ&ÎZ&Þjc’q~û¶çþFÏ·šëÆÔ1¶JzÏÍç×S©Á @'k~h®6n¤Ýšm·h“ÝßhÛÒcˈëš8E’_5Ç»¶]Ífœ/Àñ¨Á µÜ/ÐɃS,Á«¦¸_`w¬à8(5x –ûe:±‚à Ôà€Zî—èÄ ^€ƒz µz~¹\Þ¾ûòåÓÓ›Ñf¯¯ŸN¤½õ÷z<ûÛÖÔö×î7óx÷2ZõenLµÝS²k*ÎkÞUº½’y0÷zM?¨?Gæ® Ñë†qîUZ Þ©dZö ¼HѱÄ]ö ÄHòpéK¡c ë=xzzS㥫‘íµÛÒ~ôŽù\ ÷,ç’ëÆ‘Æ €Sƒ€Nªjð^€T›lKÌ,­ðœûÙ±m_ÿ¿&!éofB{®¿{R2‘¹²´½V¥Z”6È=ßnÛí1ÙyoãÐR¬DÃóËåòöÝW/÷J¦ôJÞDú+±´¿ˆ¸_`g¬à8(5x –ûe:±‚à Ôà€Zî—èÄ ^€ƒz µúðþrùøùË—OOoF›½¾~:eöÖßëñ”îªÃþDÛµìC¤Ãã\ÚÖT»’þ®}M\îí|[3¶[ÌIX¼_€k~x˜„zzzsêäÈÑûMT¶NhF“»%Û˜h»h__?5û¥¸ÜÓùVòdž{¸öLI«Á»”¹&aÎ"š€Zr¶¸Dú{¿©ï—ncl<¢íz}I\zŸo‘íõšË-ÆÃù @15xèD ^vÃGä Ìª¼kHÚ‰KI ‚#Œ[Vi€‰íìXî}lz•jp]àG÷ËÐÁcëD–4•àZz}j›·?}XSË>¯éÃT[ ¥¸±¤_I‰ˆ#Æzíƒçnã5÷€·¹ówé¼]3÷÷ÇHŸ—®kÎa •´¼SI××OÍÐ5U{s,™—]§3’”^:ÆH\†ÛSïs¾Þî\ÛHâ±Å\Ù:6Kó*:G£Û¶™û™–çdæ5&#.gšWäÜ/@ U5x¯I³Ú˜Gµæ¡YÑÄSV3Úsý½wÃÄmMBq˜èŒÌ«³Çµ…V½kƒÌ‡òÝó¼Ú©ªÁÛ+YÑ+9é¯ÄÍöã±4Ã[Z­8G895xè$¥oFÒìv·¯Mµíiª¿ÑšÁ÷êLÉÕÌ£Ý[Ò¹E[<¨àÒjð–2“æÃ?,œÝ°¼Å=%G‡}€4î—èä!kC­jUFöÑ#a³EyŠ’‡‰EfÜ–j6Gk;GÛE¾·U\jŽaì!k­VÕŽ­ÈÏ>³Ç#:ö ªï’±¤M¤ܱRk·•mîØ–’´Sqns¸­ãÑbܦâ4VâbM\¦Ž+»]Ë„ßR©†¥9ßÔ<n³tDb9KöÛ*Ù>ׇÖç¥/¬ªÁ­»6»U›ìþFÛ–[F\K~n‹UIì¶êÏÖó*;.Ñvsµ¢o“˽Îß’ýfΙè9Z;À@&5x –ûe:y€cjZƒØŸh ^ €¼tò(p$rÎA ^¨å~€NÔà8¨X‚WM1p¿ ÀîXÁ pP±‡¬=¿\.oß}ùòééÍh³³>¸ioý½Oéþ§ú1ìO´]Ë>Dú8<Î¥me´[û-ãÂ~ÏÁší¯¹ÍgI2ûk§õüb/]T­à}}ýôåßí÷³:z‡Ç_ûÚZÑ$ftsã‘Ý®åØ—ÄåìçÚÎ¥^ó zÊœ/÷r€#J«ÁI6œ)9•ð8[\"ý½ßÔ÷K·16Ùí²Ç~M\2ÿÀP2÷²çéÞ··å5 dD¡Å|é™ä½·ë$pPVïЉ¼ì†n@™X‚÷ù¥zGYï?›{ŠKô£çG·Û>µŒKé ã#ÌÓ½ooó f;G_Åë÷p ÷˰ÆcëÔ<¸jéõ©mÞþ\ô[-û¼¦Sm%9â®ãÿôôæ«ÄÔ0ùiwKóoîãü­Ïßµ¼Ë>J®ιmæjÆü3nÜ£´¼SIžì•W‘Ú’cIºì•g‘¤ÖÒ1–>½~,a}æêèεKdFÛí]dþM=@o*~[¯´ëCöy47g®‰þ#zMdeõ73!6×ß{7LÈÖ>œ¬å²Üο¥>´š“5çoÆ~ÖloíCô"×—Þó`.ÆKóe/çpVœ÷>nÐJ¬DÃóËåòöÝäê­ßD÷zÓ鯄Âöã±4kÊ1ŒµÛ[Ï:×nc_:ææýýÍ€Ýx~±Š€.26’¹ú*²2møÑí­À3Õß¹–s®Uu™+TÏ—ìSç÷WUßÓ<8rI8«´¼°%«aßçç^KC4ã~€N²6Ôª†bd= [¬¶+y˜ØQdÆm©æk´6li ÙVõe³ÎŸµçGíy”U+:û|nU#x¯ó •ìþ¶®Ù ÷¢ªoÉø±×Ö¼™ŸªÏ¹‡ÄÀܱ-%i§â2Üæp[-ƣŸMÅiì!zkâ2u\ÙíZ&¢2êþ–œK}ΞÑíEkð¶˜/¥}Ùë<¨—©Xg'³çÆ£õu ¼tò¸æ‡æjãFÚ­Ùv‹6Ùý¶-=¶Œ¸–ü܉“’ØmÕŸ­çUæœZ{Œsm³Ï߬ãj5_2Îó=œ-®Ï™±Ž^ ³û g¥/Ôr¿ @'BpL±ïó‹H€ûevÆ ^€ƒRƒj¹_ +xJ ^¨å~€N¬à8¨ÇP«ï/—Ÿ¿|ùôôf´Ùëë§Sioý½Oéþ§ú1ìO´]Ë>Dú8<Î¥me´[û-ãÂ~ÏAc pbjðÐIÕ Þ××O_þ].ˉÁ£;z‡Ç_ûÚZÑ$ftsã‘Ý®åØ—ÄåìçÚÎ%ãìAZ Þ¥„ÇÓÓ›S%C²×>ð.û<*¹nl9–ö[:®p~i5x§’<Ù+Í"µHÇ’tÙ+í"I­¥cŒÄe¸=u7çëèεKdFÛí]dþM=@o*~[¯´ëCöy47g®‰þ­WçFö[2½úp·Ôà “ª¼×dXmB,úà«5U&²²ú›™›ëï½&dkNÖòYnçßRZÍÉšó7c?k¶·ö!z‘ëK‹8fí·gI`;± Þ_.?õr¯¤A¯$E¤¿(ÛÇÒX¬)Ç0Önoý=ë\»}é˜@7jðÐIJ ÞŒdØXRgîcã=Mõ7Z3ø^í1iºVæ Õ3Ä¥äüno,æ{‹Ñ‘ËyçVƒ¶$iÎÑæëÔªdNÂý2z$N¶(OQò0±£ÈŒÛRÍ×hmØÒ²­êËf?kÏÚó(«VtöùܪFpöZ~çqiQî!;~{^«x¿Ðþ~Öxl½ƒa"j,I4•ø[z}j›·?Ùë>¯éÃT[I¶²øMŰ–mtžÞΩáÿ—΃Òyß:Ž‘>,¿æ*À¶ÒjðN%¥²WþÝîgj5ãðõ¹¶Ç1w|sljËp{ê Æã‹5ã1÷ÿÑ}½¶ur7+.ÑíÀi©Á @'U5x¯^ªMJE]c¯-%“†mkg‘þf&´çúKš8FÆ#:nçï–ÉÝÒó¨ÇöX+Ñðür¹¼}÷Õ˽’8½’F‘þJhQ:–J=ðüb/]¤Ôà½&¨†uM×nãöµ©¶=Mõ7Z3ø^eÌ“#h9$‚¸•VƒöfXþ`¯ÉѹZ¾5ÛþÁhÈý2z$²¶(O1W›ø¨JãV“”{ÐÙ^“»‘‡“e'¨{=Ü €¿ˆ‡s[Søößí÷R¸_ “G!àÌ$r835x –ûe:Qƒà Ôà€Zî—èD ^øÉßÿÉåÛ_~n{ù«_ ]ļÞ_.?‹wã»?û&ÔîÛ_~¯/ݨÁ pPjð@-÷Ët¢/LøËŸþlöû?ÿÚ»ô[Á«¦wh.û£ï¹_ 5x`ÆX’×Ê]öB ^Xp›ÐMîº_ 5x Àª]öH ^¨å~€N¬à€F~øí—?þù·@3±ïóËåòö›SîÂOþþO.ßþòûø<¿|µŠ÷›?úýË·¿KÊ}÷§? · ¯àýæßüÅßÞ´^"ák_ûÚ×¾öµ¯}ík_ûúrù7õ7æ°Æï½{ûîw—Ë߬0`ÿ¾ýóß\.—èCÖØ ^€ƒ’à8( ^€ƒ’à8¨ÇÚ ¼y~}ýÓ‡÷wÄk î©ÏâLË1^ºŽDÛµ<¶ÚcœšÏkçyt{­ÚMÉj×ë¼óüâšÀ®=fmèö ð›ç—S¿)>K¢QÂTœ÷v|ÙIÃq‰\ëÆ’ G½&.÷0Ks)ƒ=üN)™_®§ôÒ¤DÃRòåúfc3ŽÜû<»Ö%ú殉c?KÙï”VóŽ@ Þ•oú­Þå q6Ä¥$úk¾°?=vêM0Àß²ZtcñéÃ{ãÀ!lšà<iîÍuäaF-“Ç‘UZ‘c‰<|é¶ÿÃÿ_×h?"8¶YŠKÉæ¢c™ç’ýŽÅ&rŒµqŽž ½Ž/kluÝ©‰K Sçú^\éÈ5„—Îÿš±·z€Þ6-ÑðéÃûÅ7ÁcOpïQqm"aéx£ýšªË9—T«Óp[SÛŽãܸ–_$~Ùq^»½šX—Ä9Ú—^Ç×bdŸ“YqYÚþž®C·ÿöx,=¾-â,Q ÀQíºo4y4LÞôzó¿ôP¥Ò‡/µ[:¦H2s©Sñ͈Yi×´k±ßÒdÇyî\˜ÚW4ặy} É·arro Á±Ä|Öµ8c¼¢Ç—çè5¢ÕïhíQŽ/+IvûQì±ïõ>¾žûÍÜV«8ïýøz̃û<Ê' Ž®Wœ§VðKâ°W¼oø÷ú?z\¥«o®&ÁÑ+nYû]ªá¹—8gÎç3̃ã6ìOÖ˜!yØ«>pFœÇþh1¶â½dNX½ À^<À15Iðn½²©å…2û’] rî[sáZŠcí8¬9¾^qé1_²ãl󠇵ó-òp¼×ÄVסޫñkæËRMó=ÿŽ€9i%ÆJ5÷ýák÷òF9òQáÚí­ÝfiíÕèÇž£Ç7üøÞã²ö#ë-jÜžaD¯ÑvÙãÖóEQK­VKêÖhÌ{ïu®ë²åu®ñ³zUÂ>ÕÅT5V;1Ùõÿ§ÛfêÚø+’#çÚ¹ÿ'¶¹Î*ÌÄnƒnÔôF-í èÐkï~¯¿MLÕ4çXø£©Ök½äîØû b®a®mjk÷ŽþYÝä.Ù¯ÿüÇó¿£ýz]ýÿ —VÄk\»#¾'{4çKCµû~ íïüÇÍÐ6ý÷rè½s¬Zÿ0Yòºbþˆ9V®mbÛ„5zÛ¦Blꌱíjþ¬Ã,ô¯ã5»Xt?å½®±ÝZ¥þÑt)ïSÎ÷bk˜k?K^[lõ8tMC¯§´ë#0+øŸtì ßêƒ0ô?€.Y4åý/­RžºGcé{14Œµô=-å³Pêgõ"3×­ØkžÛÒó u‰G4õ¦©×û^ly>¹Þ‹ÜUs‰ïg ŸÕÍoú ]ŒØ®­Øclñá‰}]c]9ÿŠk.¡KvÍn74Õum¶|­1ÇZû½è®Õ}¿Öÿ_µ|V9N6ÍÏËx—l²¼SúŸ•óC‘÷z€vÌ8ÌÒ oîƒ Æ±wx.yý{6JýÏJÿëØóóºBïEìg£¤»d‡Þë”°™ó;S=t¹ö5u}¶lgÎǘ.0©ÇT`Bìgg‹cyø:D˜ 0 Æ0»+X¿zõª9ÆœÇ0Û¶u1€Cy8½~ÎÆ¦•œCòLXãîöeóøôí§Ï@íº…ä•€$Whɹ÷ìÌ&D˜ 0`íÀ|÷᯾öµ¯}íëý¾®|½Ò# >¯y÷¡y<\!€Ý}üØ4VÚÅãÓ·¦Ë…W+ùç?šæé[óÇ›GW `¡¿}¹kîfýÎýý£°,ˆ1LX˜úÍö§-Va@M&Ç0XÏ¿ßÜ6MÓ4ÿòn‹†™£Û6v?SÛô®ÒJ¬.G«Ló0+Ì :wÁNÔÒnÛ˜ýÄl3¶-Ì1kæÝ§¿ýð/Tåí¥{^5U—ÁŸ™‡Y_…9G®-)Œ.Õo_oš¦i>ß\~ïrsÁ<Ì\Užj8¢àœËP[\Pp~¾¹~ËKý¤Ÿ¡ñË5/e?¹¶`¼Ú¼DÑó0cnú™scPÿë¹û‰Ù&´­Ê¨ÆÈ<Ì­«ËP•9ô½¡nÜÐÏë Ì1A3µMlXå8Vê¶„C3ög¿}ýý9`‡¶ ý¼¾Àô,Y€¬îïÖ>ð<Ìs¥ZKh^ùÃÑÇ7£Ç0Xfî³_ŸÞ¼/j 3&,§Æ,kf=LŠ Ù:+ÌÿŽaþßo_¼« ÝyLûÅJÆ0»ã‘±AYSXŽ&B-ö{±û«Á¬gɰ1mq <3 dš‡YûƒÚ£Ç0_¼¸üþ÷ï_} ¸à 30³/^Ü4/^Üìšç ÜÀ!æa¶mÛ´×7®Ï†ŒaTæîö¥‹°ÐÃéuÆ 3q s¨ë¶_ý娦ÿs•&PƒØµ0ÿýæömq¦Ÿe²Îà ­~·m®mƶ(Õsr À Œaö+»A%ìf X+y–¬ 3nSU]èŽÚîïÇïØ~T˜”˜#c˜ÝÐ º©Šqh¼rh_*Oàâ+LÕe½flhö«Ä¥cŽ1¿g<Pa²}`&¬‡ÓÝšk›Ð¶Â8”Àæ£'±-’25'ºÂŒíz ¬\Û¤l P;a¹LÛ¶Í};jŽgÉ”ld óöË'×'%0ŸäI?°(0­Á°?mq D¦¹?ûÓãÊ%¸,OoÞÿðuÉ7•t®Æ0J–¹->Ðí—OÏáÓ¥’tÏS… p¡•Ý^Çï©)9ÓzoNý÷´¶÷ªg ³¾ “m %€ZsÅgÉŽ­N2g›±j±†ÊvèuÅtk÷·[f‹ î.®}þo¡™ì·ÂÌ1NZòkl¬¯¿Mްì6ô9øÐy†²»}L÷p̘èÜkÀ¸¬c˜k ­QÍl16Åf½f®@*A7lû!y”*lË?hÖ¨ÖÊÌ•Æ0Ǧ ,m¨—4Ò¹ÆÞÎû(åÁ•3†YŒjžô3ÖMš£{¸û»KÃnŠéFÖÕ °F…XsΞCÛP÷çXÕD)•f¨1¥b=ï«{óNJÕ{ìØù§^ÃÕ¬›Š ³Àz˜+Íb¸)‹pGaÆ4‚s‚jé6¡ÉQ ¦6øýß›ú:v›Ôë”3¸r¾·À2Âr™¶m›ûvþ"Ü»Ìà ÒÈæí—O®OJ`^§ MY­¦¹?ûÓW˜@D`šû°?mq1¬VpÁ~ûú{ðgŸo®] ¨À ÌÃ`Cy˜¹ ÇiÆ0`Q…i&Àþ ÃÊ.åÜ<ÉŽi,ÏAÙÎß¾þþöCÁ×ݦûûK¶ÙKòz˜¡`z.kªënÆœOÎs^*´îgèµmu®¥­Âc£y˜Ÿo®ŸÿMm×Ý>×qk|—ìÐÃÎûÁ“{é­¡ýlYñ¨®âªÔP8v+ÕPe³¯²³ð1Ì”®ËÔmb5Õ•<¶èœ0ŽYÑ$×±€U23Ô•ªP»Û u·–Xu&ß%»wã;§ër‹cu¯GŽ®ä9ç³öµ(©Ë¨»M©So» 3b=ÌÒ+•þ¢ÐSÕcî›Zö¼>ýnìàJØÁFó0—Þ™ênÙ¦ãPl·m9Y`¤†ÆØyç “KнVÀ1ÄQÌv[n³Ï’%ªªìÞÈ¥Ú„ i‹+ÌÄ ¤Û˜æªÜj­·žöº9I °f`&ÎýÉÙHwC ¿Ÿ~@¬N1Çê¾îÐy‡¶I}].€õ0‹=†9§1^Úpçš"’k_%ks‹ý=Á Ì.Ï’­šÇØÁAÆ0Û¶mÚk÷lÉj%åî_8®»Û—.ÂB§×+Lëa"4Êæa¦4ø¨0`ÇÀ4÷`Úb&#0ÍýØŸ¶X… 51 d1ÌGíó")Ss¢Ÿô3µ8rhÛ”© )Ç;NÌùÌÙf‹µ'—\¿5ϧ”ó‚K&,—iÛ¶¹oçOÍ™=³ÿ<Ô¡g¼ž· mkêXsü±óÉyÎKÍY dËt±÷5‚‹2²æí—O®OJ`&>!)y s¨a_k)¨±ý|ÿþu³†{ËcP–jÇ0Sº.S·‰=ÖTWòPE˜R%ö»_ʃ ™‡YA`F6Ú5t]nq¬P@­Ñu¹Ç²^¥­lmö<̱5*K®BCa³Í’`+劥ïÙùµlù‡ И‡Ys…YSe³b‡U=€KöÛ×ß¿ÿùæÚʼn®0õ›ìo£¶øóÍõó¿± Ý2È÷>‡øÀL¬èš&_7àY­`·ûzcí1Ö pTÙ×ÃìÎe\ÚH=L æNÑœa4u¬þë:ïÐ6©¯+絞{ „/lddæÖßPUš{›þÏÏ_—ÐE=†9§\Ú˜æš"’k_%ks[ã½ê7Zç.Ó~îÒmƶ-70=K¶jžÄ±QuÙ¯ìrÕÑnºòi<&wÿsÃmªª» çüû1Á[ÚÍ<Ë3q “²B¨Ü†c˜ÝÐ º©Šqh¼rh_µVžÖÃà§0›ªûÕdê4˜ß+eЉ1L€’p‡lLwk®mBÛVu—,Ç­(S¾·Ö6)Ûnaö³dض¸‚À"Ó³dö§-.FôæÔâÈCÛ¦NkÈ}¬±Gì¥ls© ó0@` ÌÃì>Ð{¨Íù°ñ©cÍ  îsWCç<¶ÍVæ¬7¹ÇÒB6˜‡Ù¶mÓ^[—vKÉc˜C ûZ+sŒ…È–‹4ï¹ 4ÀÙÝíKa¡‡ÓëŒæÌy˜ý*m«Š§ª1Á;w›ØcMu%U„)UbÌŠ&¹Žì,0†™Òà³S…Ùo|·®¾J«,»×£»ý<ôÏgíkѯ·Zã ŽÀ ÌýÙjýÅÜUh¨‘_³KyÏ.Ü5ó”°ó0ë­0ûTÉúUXê6¸>æaUUv»ÞU›°!mq½f vMa³U° «n*D€tÙÖà †˜‡Äîsj¾çš¡s¬îΡÐÛ&õuõ÷'á€6\“ÔÀhœ—ü|Ž\SDrí«Äc­qn±¿'˜Kd ó Œ1ÂAh‹+LªÖ}€„Š`ÍÀ4÷ç¡),¡rÚb&#0õ›ìO[¬Â€c¦~s€ýi‹U˜P“lëa°‚Àæ£öy‘”E¸£Ÿô3µ8òж©Sr+æ}s¶ÙbíÉ©sÙJ覫À~„å2mÛ6÷íüE¸g?K¶û@ï/n&ŸñºÄÔ±æ4øÝ箆Îyl›­ÌY dËt±÷5‚‹2ò,ÙÛ/Ÿ\Ÿ”À¼NË©ä1Ì¡†}­Ç±…È–“ó=àreÃìWikKéºLÝ&öXS]ÉCaJ•³¢I®c;3³‚Àœ{4Â[.ds¬P@­Ñu¹Ç:—¥­lmö<ÌšÖ_Œé.^³KyÏ.Ü~¨.}ÏίeË?T€Æ<Ìš+Ìš*‹˜;¬êÐ4OoÞÿðõ7QëÍJž% P² Úânì ,ÃÜR­àcŒÝcu§É¨ ØªÏt•¹˜‡9Õ`‡¾·dåÐïÇÜ)š;Œæ„ÓÐy‡¶I}][¢›~`'#ó0÷ ×~¨ŽU£CáÓý:VæT™³Í5E$×¾J<Öç¶öû £}zó¾yzóþ§ ;ÿ,f»î~ûÛÄìcÆ0Ê]¬p´ÅýnÛ5Ç9·¢[>( š1Ìú*Ì£P]70¬‡9µFeL7éVUZÿ8¡®ß©sε€ŸÚbŽYavƒbhõPˆt·[s‘éþ~ÇŽ9çœcö»Â åÉ:†Ù„±1í =kÖ#P c˜Ç­0çkMrž³À8R`.ÜS…Ö ¹ÏY÷+Íf1²>é§ßåYÂÜÍ”`ÛrЉi(µf ßüÜÀwÿ…f膟ÐïÇn37À»û ð±óžs>)ûQqsÛb¶=†9§QŸÚ6f_¹B$×yï±j¨0õ›ìO[\A`©ß`Úb&#0õ›ìO[¬Â€c¦~s€ýi‹U˜pŒÀÔo°?mq1f­VRÛâÇ=”âÕ«WÍýýãìß¡†À|÷¡iN§Ñð¹´Å0°ÄÃÃݬíïïÿj‹U™õU˜5U—°M`&¬‡Ù­ÀºÝ·ý`êÚíúMÝnj›©óUi›Q]#ú.Ù¡¥©BË\»iûK]u÷Õý7~¡ŸwC+v?1û;ßÐ×\r…Ùà U^Cc˜¹Ãä\±N—¦·–±ÇHõï7·£?ÿû—§ÛbUfá¹¢Ô¡C!ºfX@Óì03Ô•šš1]²%ù¡‚œú™ê²‚Àº½ÂhlJKŽJµ{ŒØzö¼”˜½çÝô,c5:cÇÉu>C¡ÚGìv)Uæ`åéY²Å˜5†9C?ý^®ã¥;×9pi¦~s€ÍªÌฦ¶¸‚À"sÇ~s.©Ê»kÖ¦ ˜úÍö§-Va@M&Ÿ%ûöí½«°PÊÒÏm±*³ðÀlšæîãÇÿ½Qçg_ûÚ×¾öõü¯ŸžÒ~ÿ£ *Å/§ÓéϦiš»Û—®ü×ãÓ·¦mÛç¯a@ ®\‚å%;uiÛ¶y8½˜[{x¸s*’2D—,L˜PO`Þlô$ý›w6;ô-ºéç`7ï>4_<ºé¼Ÿ¯•?þéÅ‹›àÏúË•·µŒÀæ–j Ó© V.00‡ºP»Á×ÿùP¥Ùßf,8»Ûö·ëî{l»©ý¬Y…P®ä1Ì~¸…ßùßPu©ÿuè{)çÓÝ.t>kÓ pÁæœÀY«[µ–ç*rhl5æ–žg·Šì†£ ¸À sí¬Ù÷ï_ŸÿpÁ9TÑÍ­6à¢*̹A;ª)ó-û½tšÊùüÀêÙ ±nø …X?ðúwÉvƒ+dcû€¥~9N6MÓÜݾt5<>}{^­dê.Ø©)%Æ<¶ñöíýäò^Oßš¶mŸ¿¶¼WFS'êåáë 0@`€À€’¸é'ƒ·oï]ɘ»Û—MsûÚ…88]² 0@`€À€’üpÓÏýÇÿ¸"Ð4Í«W¯ÂÙÿ!\²‡Óëçbò‡À´b 3† &L˜P™Y_|úæŠmÀÝÊN;5Ý–¸Fiíí¯>„eiÛÖ$@X®Ö–¸Féííìå½n¿|r•×|¯o\XH;5Ý–¸FóÛ[c˜ 0@`€À€’\åÞáo_ÿé{Ÿo®³ìoÉ~æœóZÇŽcª­;ÿ|ê{µ¼¾’Ïy«s]­Âü|sý|ÒC¬9aé~æœkÌ9­u@]ayn;bÚ¨Ã2G;¾…9mx‘ÙOz!Øë*Ïu«@*ÝÕÞoJlúÙVÝ"ýã„ö‘»K–%¿®˜¶wlh-¦Í,¥]½*åtîêœ{†.lÊ~æVÊCûÏùº€ã8âÿÿ±mo÷{ýmbÚÌ’ÚÕbï’íþEQsw®® à’‡¤RŠ RÛÌ«R?DÝ2~ìâ•ôA<Ÿ³»n¡váHmÁÖmo mýÕÞ¤p¨ß¼ôn @hÖ–[¶½%\·_÷¸°¡íjë¶èŸ³)'ÀTƒ_z1tž[¶m1ÇÚ«­½ZóE‡þ2ÈÕuÚÏÜmbï€Ú_ÿÖk]²pYãÿ_z}1mÝ×1f›9mxQ{‚1ÛmµÍÒ;s…#\nÅ8çç5µKÛÍØ×¿GžÊ³d@`€À %™uÓOÛ¶M{}ãªÅÒN¹F»W˜w·/]­<œ^»@;5Ý–¸Féíí/§ÓéO†Ýüϼ .™À &L˜p„'¡Hõ/ztu£"jnØÄ™ž¨ý=áÖÚæÊ4Û¶ý¿¿bqelX9]PìiûeÕSpY¶Inï÷4A(ÒEý‹{Už¯1{š'˜ü¨Èѽ¿ŠFýwSìoº=Ä• ò®©sv«ä#­Ú6h÷^,P|w^W˜4a³Hõ/*j>QÉY»Þjo0û«—ëØyÌÍSoX Š¢LݨƒZ<)ì=®%Û<¹(ºOCõW`uQº×ûèêfþÓ’i ïñgÊ¢µ—¦®`âI©xŽ÷³PT³¯çž(êI×¢Oòdªx´ J­Ùò·À&ºWzžß­-j6iplOøŒŠŽK¡á×±EG„ûQ·pŠ(¾6yCk>(³·@âIGDÓ& Á(²èˆ˜½ïñgª%Z¢5ÿ%ôiÅê÷SΤu¦•ÐÊ6I õ4N2{åb]Ðð¶¶j @iæ8ñ^9,ÌJ8t ˜ó~iZ¢Ô±Ü¶ ­{Q´¿™ê½êmcþìäbí® ñÞÅ"a¥Bö"­˜ó¢žì‰Ù(J šzê¶MýJ ½˜Š‡ë®*q ´íl;eb «±j“*Ã~w`lX›VÀ&€”×'%ñúû~;€ž?¹çþÛ߳ѻ@–6i†W¯>×õ嗿וö«ßýNKÚ^¼Ð•fùwCšiô7 Ò†¸GÜtæLiÇëqøú‹OcNnl“ äñû7­› ÆxçAüÉÄ“À Éã¤ÔýR¹{÷ãéÇ?Ä¥J›G üäváà_/6Šâºç E‹x×21]‘P)sç]°Ü6¹Jj©Ù¶¿ŒEÒ ¢hðv¢{,·-©J’A*Ú¶¼» ;B2{¥º]´y‡?' ã¤æéb“˜:Ðâ;NÆ+ð&î;fe+ £hŽŽkTök}ª´y~î¿M&wÜ»‡Ïæ#®wní¸W–"ÍwW.?t Ü÷šµ“çúÝkõ5\Ð ]%ÌÀrÛNiBp 6—V/J4ÿ_«²x¤jñ$ƒl:£“ºÑšÞZÐgݘ.–Ûç1Hº-Cš·©òP)Ò–xé&èÄ“ ²é 6þ^P‡Onÿû7¤Ìt(ÁI×'a†aøëÅOþãþþðIÂAH°IÙ9Ñ#ñ†2Þ¬„µ¢ iºIå½RRù½U÷.Xn[R•Í WÕÚvž» ®õrÝÒÒAsÇÝ 8ÇAeúƒ0+!fÂB¼´°KmÊ mÃü^™ºÊU¨’!MÝ» KzzcV뽩ÒÜ5ÞÓ¯Ì^©PE÷ž¦J«: CA11¤p>ÞüožÀý$ïã Ø•)º!ñÅ*rdÎPoÅI%&hÉ´Ü6¹J^óê´-UZ|Š?Óæ•ÊUtï©AçÿšÍ»G¼R¡¨''€A°I`…‹†kŒúK›òîõ÷?Žãذ1…8Fþ$Ëù¸†4¤!m´qß¾ýÍæ™——/‡'ÿ}^?rïº;“i†æ6 <âŸàýA< ¬¼ßû¯‹ÒÝžus…ZÌ\Ìŵç‘¶Y„´jÒ†ôõ­½Òn¤ ʘ­§°I‚M wgXÛ’uÿö¬kZ…¸VÍ[òviX M]Ú¾òÿ WÚ“4Á¤-–‚ :ñ¤ÅíY³ÍÒÔ]vîÞ>è÷ìÂrPi_„4uiCz—>è•v&M^”þæ$» eÌÍqn¼îKJ’´ÅGŒ‘¶qj>Ë ‹7±žögÆq¼ËÏ/‘¨B6HkÃðý_9_sF7oX†Ûwt&Å—S]O›ìëSˆñ΃ø““sŸ¯ý»á¦êÞìå…x’`xòŠæ¯[ûŠxßÝ7w Ñ›ø±ß]$™q¯ûçÖ­èÇïßL–`þSÅ5fIq úÁ*CsGüÊd€³Ñ_¶SLf&âdˆŠ¯UÇ>5¶I_~ùû“H8!‹JdYO¤õ¡YlÆ|rhɬÍ&'§_Ž´u\€†„Jd<¤+MKÔ‹6¦ ŠÍÀwpx¼ Ñ €ÖIr­ÈoT´‹Ø$€c>ú#}w ²Ç/CàNrlÒÚ’X•õI‚ԕ 夽xñ"² ,.>]\Ý£§–¥A$É6i2Hñùý’òAEõ¥OÐBо =µ, bHÞÇa26žYRÉé'ìsš±jQiÃÅÑÝøØ²´q“ò;ôDšÙEÃS IÐ ‘é»w?žÿܺy[Z–C— #7q˜ãmüêûÝY–Oü¼?°IÐŒxŸyä¾àf¥A$ùû‚ÈØ‰ÙX–.»òÌb¢@}ÁUrú aÃŒˆbQiæf j•¡§–¥A$jñ$•œ~f³{yUX3ër{u3 ÃÅw_ñù„Ÿçó“ã)fák. "!§_Ž´iÍl—S63¸½ºùFú”ŒãøêOZ´ISò¤0£ñ]S-äô;9Ì»ƒ½\|÷Õ úzGáòòåžA@6©Þ&ãÑìMžš@N¿"Òäý;ãöêfxñb†_ÿÿ/ÿïÿÒº9P•Û«a¨DN?H…œ~9Òè¸1ÓRÁwW w$¸õÖŠæaÖâäFÙOè–†cµ©tÏnŠ'eW‡CC< tÁ&A˜/»õÖŠf‹V*>oHÇ.D耛´´ß¹>©f>.aÙAŒ´˜õI®U”æ8D ñ¶oW‘)0Ç“à„Èñ¤øädӇœ3V¤êfŸY;™õI%Èß[HxÏ~¯“+¬žº!c’§8Í{2Åo×Äpú@VíŒýS6«$Éœš$?4ØÇA‘|ß›¸O%§Ÿ@éÕû“|ùkE‹^8݆•€xÒ™‘ãI1Aµg{ßžÍ*I2çÆ,6l­Ù°‡üýî E&*äã: Ù)©â£«›CX>8Ö\vÞfBìwWˆü\… R|\ym›?oÆ“Â$¼î,†È¢ÈL¾‚À:O:3rªÏ»K=3<'LWùu<~ÿ¦œðÊŒwÄŸL< t¸¼|9 Ÿ\¾~Ùº!p`°I°—Û«›_ýç}ùöêfàó™>$í®ËÓ¿ÿÓý÷Û_ü¼IÊ}ïEÃå)Gw›ÆGíÎÆõoÿ< Ãýû÷[7¤%ã8¾}û›ÍÓ./_º±–éÁ¸è» AQó°Fê—~sçÁ0ˆ'•Àr>.rú서~ ¾;€£âŽW·ÞZÑ<â™Oˆè•*ŽÕ°IÇàÛ_ü|Ñx [n½µ¢Y࢕z¥Š.ÄüõIÃzŽí=1*aÊ¿VN¿ŒÅIžLÖ'ijQwx°D&ÏK÷·M ×* J”H!îiå‚Xiyf#slgoÏ*,VÌé7+²ƒÎ§á)ˆa§ž6×zݶéŽf.÷âIèÆƒzÒ;¾4[fèiµ¼ 5÷`}÷ð™ûoOC¨üx’»qÃbN¿½M[‡ý»§›§vèIïøÒBö<©3ôT¨¢«õ5Ÿ!ï>{üþû癨Î8d<éÌù¸NEïƒkžôŽ/-Ëzj°mt[6Ér>.·Ä“´°–7ï(m›XsëÍÇçq•[ä ¶\#'œ>»’7ke`Ë&YÎÇE< @›yó&,·mb¶‹Gfâ}+†µÂ¢5Û¶ÙŒTlÙ¤HvfŽXôã¾ë›µ,ÎOÿþO/Efx¤MRM ÍhÕ€ Ëzj¹m1dŒ nÃCÚ$€$â O[ƒdÄ:N_êH8 ñ(ßÝòm’;×N%§_<ÆóqÁAih1Õ˜<6•KWO…*ÒNø YôÂÅTT?¥Ù$w†·guTrú %kÉCö=º¥îUÎÀ:~ÂH+²V%CO…*©ÒÌ>CöDk’$4™tž–gvç 2‘T¦ÊÄnuÌôt¶l† y®õ¬éü¯à ´ã' äÍS|’¨·-ƒpA’;asÂÛ¢íY›w1K1͈‡xœoœq8âm‰q» køµ¢MãYÑý7£`“þm–,?²Õ­æ¡Í0tLc›¤»ÐDz40Že³´èjÛ)³Î•.*‘e=Eë›CN¿itÜ.±f–„ ëºËAN¿<ÆqTܺiAz9á»ÁwýFŒÖÍ Í’ÐÈpf]ŒYŠ8¬LÉ;ÄìþxþäÞõغÚÄ'wÇ&Á)ŒP䙾Ú+r­‹pf¼ÀÈ"¨Cü¼?òsúMx)”ƒ©ØÌÇEN?€rÒzAZ¤À¹–,*IÈäçôóPÙÇÁr>.ö`(A9­¤%5Onóá’ŸÓÏE%§_—ù¸ÎLÛ,|‚´Hâka´è<žd0DRvêQS:¾´žhødè&ñÌó'÷"ÏTÛïÎ äô;.=M=òâÕ_š}’âI$-Æq¼c{‹Z<Éäô;:‡{ÞÅÓñ¥YF%¼Tžœ'ytâIÇ‚xÀ ±l`¦óx@¯„›vw0ºÒ'yíòæ‚{㕵ðÏ7è†>Ò ƒÔüI;µÞ£¦j·òµ<~ÿÆý+ñ¨BF¥ü9^ªYï`*gÈÇ.ŠZ?¬Ïb›¢¼fdHƒH åô›°™‹P-­×MÁg!¡ß„<{EóñùC!?!ñ$€£"˜ÏfÌGòŠÖNP›pTTL…©™ —ziØ8ö²î ÷ïßoÝ„càns0=cì„kŠ<³´8!tÄÉǽÒð["ùæÎƒ!zY9ýr¤ýãßv³ _ñéGŸ=õϧžÓ/F ÊüiÒk0ã±æ “kÕß]}öôm lÆ5iH«& Êš¥E´bB…bKØ$€Þ×*¹#¡Œ¢ð„öóîìäô[,†™NÂÓ6÷Ǫä­TÐÊc†4¤Õ”&è‚®f©ëé|NÆR§ým+Ahò|w‘E‘'ìä9ý’.ϵV%/»—n3¤!­¦4ÅE„5¥ ÿ¹ÀýY‘ä7浈NÑCæôËhÝM”hM¼ã^©'¡œ²lþDÓ ~:á2Í·Rå6Y'M]Áë7Æ ïœwdú³p¦Ù¯†ÙȺÓÿM—.òOTç.Óx‘{CUžiøîj¤é`}˜ùÛw_ýõ®4M~" c¼"ï¸Ê3Myœ$„ÝRïÝD¨ó›Uæßnq˜¹é^˜ë²x -A½ÓòhɃ᧪·yr¼qÒZì`:míæÖ4±¨Ê6iñÎ…ŸÝÃÁr ChTBXäš4Lt€ w…T2Ò§½vr9Ó"ÄÖh©—i¿¨õâI…ܲIb1'„Z–ªÎ¡”±ò›_žiÙ<íXÓ²ìPÖwW´ÖNß]Qˆ!ªé]†ñÔ¤š•šÂ\˜‹æo­`™D&Ã&ÎìÙ`G™\8 &Øà#ØdÀ½Ážu¦dpv@àDpV ´qxã;Ü`q¦ ^¹Ýªêzúéú]O?qæí_Uýv×óÖîºz÷öÕ€E?i€6îîZ'¡¸ÏµN4öAë4p†7&› ø¡&wóæ›¶é¨àËÏ>YÿÓvEljpgû~Ï–_!Lç(¦ÓdÓw’Œ/Ù<[~þÖ'gû‡!%Âپ߳åÀ¦“<Éèñõ­ÿá2fÕYêe}|}ËW(ä@óKsJçéÇñÌ?!—OB‘ìòùpqn7r¯×ÔÇû$~Îæ—,÷™Sà$ŽÕäœÛµaé<\`ð-Y.ÎÉ‘{áD¸~.žì¿9zË pBg|„ NIz)[¦ÎoŽÖÉGž>¹¥€XJ¿Ñfá·_-ÅŠóý¡¿Õæ±Ð‰+j‚Íß›ÖÍÉe+gŸ›ŸOƒ´Ü6 r¡›3¥¦½v*g¡kýC{s·èÇI¾!àM« UÞjó¹$õÉZz”ùÛž61chç:Têó!*]¨uktƒÖKÌœk<'‡œp“ÝßÀÉõ;ºR_Êô\=¾¾½$oùVñý*^“ó;*BOLË:묗vRuåB¹r'¹Ðp¸ÊÃ_h.ƒ>ù×aèa矡³4î©Ft ÈE:‰.èkŽsžþ Õ/mK¾…ËR¿H>€Búm® A`ÖÕ/ùËÖi¨íç?ÿùtŽISçynhéêÓO?m†lG¸ grp8¡+úÀVÑ'0‹ 0‹ 0‹ 0‹ 0‹ 0‹ 0‹ 0‹ 0‹ 0‹ 0«øÌàˆ3cõôãY¿ýõw_|*L-L#.ïÐÙJóIÊN@/œÃ¸Vm†tNø™äð#B‰WL¤¶C6ƒqÊÞÖa^™xeÔ<9ÍÏ "ÒÑ\‰zÞ½}•^į÷àì-ºvú{½·\‰§àj¢&‡z²ñ—`³þâÎC;ÌŽ'óÛÆý¶âån6#ËíŸë¥Ê­vT/+ðµöŒ ‡QÞð‡:½"¶ŠÐOA:‡ý¤°ëßΙY˜Æ–­6ÞÐþj ¶JìîE'røáî§On©u¥ïªÄ)•œª›þ¼Eœá\^‰Ý¢(‚êÉœ`ƒPuSn›"Ô@í·]s鎈 ‡!e/n(¿*ëç玾õ¢Ÿ4CÑ•¨g¬2Âù!?VâÉ;(7ã&¯oy&¤sÔäP–0ðDóÜtÜŽ>Á" ŽˆP"…ãÚm ù‡ÿü¯õ"gÍ®8I~œÚ2‡ñ ÷ýõí4MWo_åýûj¨ ±9ù'q¥Éñ¯C¡Ô—¬rÓ4ýë~:ýÿ™¦iúÃO§iJÿûŸª%Æx»zûê‡(•wŸ]â={èܺÓi t­›;l64“‘30äJ‹¬5Ïó—Ÿ}’71D54ä·à­‹øC…x(r”n6 žá2‚5ãAîûëÛZ³îs]™ûçþ;ùÕ¯ò%è•3EYŽë‹û¼!¦Ñ2‚5)È Í_¡EˆÑòI®áï‡üÛ¯ÿò^üû·_ÿeýO„øÑ›K½-”Î2‚‹`“cRö s õÉ9ÁlùЉj›°Û>¹g8%C+QǸ‘À‰sãfÓ¡7ž4)7‡¿'îs3tm2S“»œ·ËD8dç²8´mÊq£·•Ed§ÏŒÀBŸÜ%ìm–Ý~Ÿœ>Â…ôùœÜnèÒĶyž³¼³ƒýœÇºÒãT€ü8Ê¡,â…e&#çÔK«6üÝLå,»ÏÝÌû«í e?û+Ù². ý–š­äÏ…ýg}ÜÞ2G/A.%ª Ûžê9¹t¹ hö™™^.31¬—  góý4û>—Ê\W“¦ .¯~œÃdŸÿSØaÑÉjfdâ¥Ìµrô?ijó™.U·PÅPr‚„<ñ[çRæmÀ!cLš*ïYpõöÕ¨l}øáÇïßç¸þ§¿ÂÔkŸÜþRzˆp—?ˆsg#¼k¬×ðçÍȸ±yDLš:èOr‚Ùò¡Õ6a·l”E·B¥¼_”/Ÿ‹„–V-#D¸š4W¶*CSú“6ûä.¡k3Î96#ï®<äë§Oh®´-TÜGìÄÿ»&3ÁZï}rš:â¡wWŽU9³ðv›=d¡>§žg 5“\ôä õ'ù}réŽj°Éú¹F»ê¦2“Lý¹B“¦búñˆèW]Gày¸RŽxŒ‹Î΋†“¢AM½¹BJ?'×!héãÙ<ÏYÞýau?8DhÊ‹nå[oX-ºdÏÈz“úÙ9ãAzÊù$wŸa·ºlò‹æ¸V>Í&ÊâÔÌñ¬¦Þ'MÕžÏÉilŽRé°—K®‚Þê~ §÷IS³÷'­ŸXþ¾D2ÿ¹Æaó<ÛxM°™Œ@ÉþT;ÿþé§y_Ðü›ßýnýîJ&MÅܼù¦ubøw™™Œ@‰>¹T–&MB̲f2%ãA.±O.¸Ï¿zñìÑôŒ{:e<È]|ñÅï['Ѐñ wyN.oŸ\ŸÏÉe¡™ïųGÃí颧NlË¿<ÌdJƃ\i£Lšª¡ÉË<Ï7óN¯FoûAºAƒy˜ÉôŒ¹Ò}rÓ4ýö·1ûú4Sjþjwþ#år­WÿÞÞöƒtO¿ýªuŽ =*`&#Ðè}ÒÔÍv²<ö°9{œ¿šGåÖ'¿Û‡ú1"ÿõü‰¯ógh›Š½«~F6?AvLšš²çл+C“ÉiBZ·}rN$Ûü|úëSùÄ9äR³à.ú‚æÊ(4}òú@¿ª™bÑê”rË;eˆaÚæû‹'/êø/GîM(#u¸Š,ôÉzwez„ë³tHxC¿°h™æfùétîÊ›"\M½9eÿ_zEŽpëfÌk{4E¢¾P)/tAõÙ;U-#Ísz*½¹”éЄŽÎ'7tŸÐD¨¸ØÉúŸõÞ™Œ`­— ‡\¨Æ¡‰ÍÒ<ÔÒ=ijf2‚ ãA®ÂsrýsÚ0iÏD!~xÐOêÇ•†ÑÂLF0]¹ùÈZ_ßv›¶N\âÜå?"ÊQމKâì¼h3`ÑŒ ¦Þ'MMä÷É “¦N[ÏÏù½t}öÉù'ÓùDs¶çyÎò‘Þöƒ&„¦¼èV¾õ†ÕjHÙ3²ùh¾B¤æÊˆÁ rI±•¦h>,…¡%#§ÌèųG7óþj»/Ðëm?(Ê/šãZù”;”÷™¢fFˆg5Ñ'µÏ•§O‡|åë¦\£·ý8-ãA®4&MÅIÌólã5Áf2¥+Ûþ¿¾ý÷#ÏÉiüæw¿ë°O(êæÍ7­“Ão 0“(¢&—wÒÔ\»b¦5“(r¥ûä,Mš ör|ôÑG[ͳbà M“¦:J™»nw>9ÿ±Ýw4÷ùœ\šŠé‹gªíýˆn´hË¿ÌÌdJ=Nšz(RFX϶ã̼cuª9 ÍÍ?Ïóͼӫ‘k?èÇ Á¿ÌÌdzš+«Ã Íávç“{ÿþ»åe„ë³§ùå¡9ò ýûGríýxúíW­“pLèQ3F}rG#œ0i*¼Þ%ø/oL|‡<=i¹w… 7û”z rĄ̂)1ìè|rÓÈ}rÎTþ"âJȪ6œÁYŠz÷öÕòßÑ÷8_¶Ê’ŒK‹åòŸÿ¾æž-§Î©õ2óÆ¥œ  ´ÍW*c½ÔäÖü>¹P/Ý®£ÏÉÛ'' ¡¹í1´ÈÙC5¹e†¹åÿË¢PFäFN¦Z­¦Ç ·):Î g õE”òúP³ô¨¢Åu×ÑÉWS“¦†ŠéP¯’0iê÷ÞçN#dÄ3þ>3û¿ÿ»K½ü·g‡—ÿj¶ ®»9QΡPTsŠWz™4Uxâ§*±¦²ŽsþãΚ)j‚jšØŒ¡¥Ÿkôhh{ÕŒ7iªæ“E¨O.½LöÉuøI?×è‘ìh ž¼”]!Ú0}rÝúãÿØ: ;Öµäåo*|(AYñÒ‡´!‚zf<ÈE<'§ÙçR™ëgÒT¡‚«gó™Èô¨Éáo¸‹C°ožg¯ 6“(1ºÀŽq'3s'ÌdzôÉÌ¢&0‹ 0‹ 0‹ 0‹ 0‹ 0‹ 0‹ 0‹ 0‹ 0‹ 0‹ 0‹ 0‹ 0‹ 0‹ 0ë'­Œêîþ¡Ú±ZMi—Çq'à†=öƒ\Í’‡( _¿~Yá(_|ñû G 9šÇˆÔjnRWK"ÎRûAn:þÅßÝ?°I…M­«4WÂ<Ï7óôågŸTHOŸ8KÑNätN®/>þyhÑãë[ç“wo_é»l¾ÞjóÃä:Kú|u{*ô‚An÷ÒÉ›ùÐwxcPƾ÷?üØÿðýûï6WX®ñøúÖ¿7/Ÿ‹R,©=šÔB¢ó¸^sý÷rö2&2Ë™OáDqebJœŠÊ¤šœpé„þŽ#ߊ%îRô¯“ï]‡ñàÃ?î$Zh¬S;Vʱx÷öÕy Ò˜æJçì”8_'9û@é8áüMÜ›“Ú÷ï¿ë<Îé›éô•¿ÐV»ÍQÝ6ýÅ5f ù«5RªOî’ÿ:y«y,ô ¢ qV8t¯ ©”Ë,¥M2Úòtù¿³‚ÛGYÚn~rô@-ÃYZʉ>K´µì’‚\t_e^$•E”\Ù µu+Ez„s:árõÉMƒw™¤‹ø‚œÚU‰R…’ªúä‰ÞÖ¯Ñï^Á\L&eùZý4¹Zä¸%Ç?Р°eénŸÍl†Âô“¿'â25Ê©èî‚Ð`žSõ”"Žß—>$júñ¯þW`Ï}ZcñK‰ìß—É"("SúßÍôîÊÍ`íÝÛWëÿ/˜¥Oeݹ2¢qS~T?¥„Œæ)Ìþs-”£æ9âjrÎÏ¥ÍóU¨¥[h‘8ÏmŒÍ­Ûäjéyâ¡â §ì9_SBÍ>Ôc'ìp÷XëZ= ³NÌúoÍH.ùT8¹Ûü»•ÈæÊ¼_XöV&–RÐÄ.}W—Øà|²»¨OëçJê<ÏÂÛ:dr·«ü­EôSÆ-R® Ë{–”Kõ‹Š¶§¹Ä/ìh&õW['C PT‰{R¹B!B è Í•³r@/œ75g_8¡.š+7gÏIJýè¤*›3µn®ž¶ÍâIÿÞÛÄÍóº$¦ówçoÊþ6ý¡ik„D:ßðuä ‰EB¬ÝBï¿`:ô«4Ðäm@Ÿzi®l>±žÌ‰jÙgL,¿(þF·ù :ú3Ï…>°è¥&·9å÷äEÿŸÎNüE¡&ÇІѢ§œ®á„ù9C‹.û_/ÝÜj·r©9V qÇŠK|Þ|5 7Ч^‚ÜŽs!rOÞåM7›2jr)£Ë¯C›û«-Ÿ‹ü¥ë†Zü¢•Wܱâ_"_%¦áN¥£ 7sþæ‡Ö÷•Õâ¶Müžkó,«ESFè¸ Ó7©¼Ã5jr@¢¾‚Üt¤»Ë_óP˜émŽv{B}E~7’¦ìî¤|—Ÿ·{l³O®“󌢻 7Œsëê㮡8®Ö\Y‚ørœD/£+#DoŒˆpNÜ ‘Ñ')ñ'®ƒr?Ù+(÷Vùè…¯9© ÀÑcMn͉.ëN;¹¹rYä z¼ü3¢s}¸ôZ`\“]âæÂVò5£+G£•—²u1KâKä‹'@¢+Zí긻ˆxA³? Aý4SW¨æè©.÷Õ<þ9³À†›+cŽF,~|»r³zds~¸þQ]0.‚\%NïZ4f³=žÌ¢O`A`A`A`A`A`A`A`A`A`A`A`A`A`óÉ‘îîª+×|„GÅå±UjŸý W³$Â!ŠÂׯ_V8JÛ9åæ1"µš›ÔÀÕ’ˆ³Ç~›Žñw÷lRa“CëÃ*Í•0ÏóÍ<}ùÙ'ÒÓ'ÎR´S9“ë‹ÏŸZôøúÖùäÝÛWúã.›¯·Úü°¹Î’>_Ýž ½`Ó\:¯oså<ô$^Á”ÉïýÃ?^þ~ÿþ»Ð:¡E!þm¸|",J±dähR ‰ÎãzÍõßËÙ˘È\¥å×OŸl~þôë?É:Q\™˜§¢2©&'_:³-ߊ%îRô¯“ï]‡h¢×: vk‘ˆŒ¼{ûê<idsåå• ï'9û8 e„{ÿþ»ìqΩ¬$îÍÉÈ%Á=Ç9}3¾òÚj·9ªÛ¦¿¸ÆL!¿qµÆBb‚œ&Ñ—ü×É[Íc¡³Â¡Ûx]HºÌÊ…Šå7{臩ÛGYÚn~rô@-ÃYZʉ>K´µì’‚\èÒ©œ“è.S -¢äÊ^¨­[uÒïáPŸ\z„ºË$]ÄäÔ®J”*”T8Ð'wHô¶~~÷ æb2)Ë×êï¤ÕÕâD²åŸYêp~hw–žáöÙÌf(üGÿp1ù{".S£œŠî! æ9UO)âøÍq‰LÆæJ!’9ýp÷rõÌ/%²—&‹ ˆLéO47Ò»+‹u ïÞ¾Zÿ—xÁ,}*ëΕ¼Þ¿ÿnýßTf\¾É¢yS?¥„Œæ)Ì^aå¨yN§r5¹B-ÝB‹Äync„ô6$j‡Nˆ3œ²óJgtÍ>Ôc'ìp÷XëR.¿ÝçáBÖÉs*»š‘\ò©pr·ùw+‘£+ý¿Ó»÷O¢÷ÛR š¸Ã¥ïÊ6 çØ [ç%W.æyÞÖ!“»]åo-¢Ÿ2å!„Ä«1ïYR.Õ/*ÚJœ"äR¾Kå:šõ5º:¡È¢Ä=©\¡e<ˆÂQèöÉ¡_<{t3ï¯vòW2t–z<ÑÝÀgÓCÑÜ¿QÎ’ß’Ù01AWóÀ¶Fâµé­Ž3ä†]urK`Þ²n1Á#€Òì×ä(Ià´Fz€Cr³r³ì÷Éu"nü‹Ó¡È Ô1Ïó(Oe2‚\=¯_¿<´þæÐí£;"D¿> è Í•³r@/œ—8g_8¡.š+7gÏIJýè¤*›3µúëdy|~³xÒ¿÷6qó¼.‰ñµúÙߦŸ"4mHgâ¾.‚\!ÑH޵'Fò ¦C¿Ê7ÏkÜBö’òžëCMÞô©—æÊæëí*:DbùEñ7ºÍoÐùП”.ô!€E/5¹Í)¿§­º”PµÚ\´9¸t9yE§œ®á„©;C‹.û_/ÝÜj·r©9V qÇŠK|Þ|5 7Ч^‚ÜŽs!rOÞåÝn6eÔ,Z‡›ʯC›û«-Ÿ‹ü¥ë†Zü¢•Wܱâ_"_%¦áN¥£ 7sþæ‡Ö÷•Ìâ¶Müžkó,«ESFè¸ Ó7©¼Ã5jr@¢¾‚ÜäÍ*{hÍCa¦·9Úí õùÝH𲻓ò]N|Þî±Í>¹NÎ0Šî‚Üt0έÿ©[D¸ „â¸Zse BâÊp½Œ®Œ= ³P„{|}«ORâOþ\5å~²WP2î­òÑ %^3rR3€£ÇšÜšS«[wÚÉÍ•Ë"gÐãåŸGÛ9×ë‡Æm×d—¸¹°•¼CÍèJç‘ðècå¥l]Ì’øùbà èŠV»:îî"^ÐìÏBPÿÍÔª9zªË}5ÏŸÎ,°aàæJÀ˜£‹À.‚À¬Þûä,Ùœ®TŒ‹ W‰Ó»Ù,@'³è“˜E˜E˜E˜E˜E˜E˜E˜E˜E˜E˜E˜E˜E˜Å|rP¹»¨v¬\sï—ÇV©s†<k9h½~ý²ÂQÚΟ~4#Îö^!šPJàDíƒ÷`‰æŽžçùfž¾üì“ éÁÉ5rÜ€Ir}ñùóÏC‹_ß:Ÿ¼{û*OšpJÁ ÷øúÖ¹¶œO–k1ýÌx?$¦ÇÏõæáòÞuCßÕ~øñû÷ß9Ÿø«-ë8Kmw —åîgIðѤ.iXÿÓO¡ÿa}‰yÌ®Ä÷((½´Y“[_m/‘š‡^ ÓB{^´:¥BÀØ´ϦpY¹;)X7­“‘ÔݸÛCÙš˜G sRs"ÙæçÓ4½{ûŠŸB't)Cq®‰ÐÇ)ñ/™5†Ë£P3ŽX´|^¨‘=‚ܽ–ÿë÷Û¼ÆO³ò~p–*³ ï0EÜ]½^áPÖ·½°ánQ¸~Õ ÍÝ+¶ùe©ið—áó~é}bRDcµ°èP»Õ~te"! ùˆË?…5…­„4$¶7潫ã¬kä»»ÚpëB1®X¢¹¸u õÏg¨õ[qn~b@–Øcï´ ÎN‹nЬv… ŠKC“{#ËACÅheBüsš7ãZ;åz|ÅÖ?!N ìh"î>3…ûæWú‰ãWÜ…6œÊð5¹8Ù/úúw‘|WG8Ô\­çþž¢"j'›+Ÿª¼öãœþG­ÐrƒSÙrö®ýÏC½ê5›+{ÖOÊSNchÛ~rW‡²1)×;ô•M159ç²~oq¹8n”«\yçOÕ¿ýð¼úùg¨aÍÔ&FÇi„xM™ KÆsÕöÛ½»˜çY³&¯õjëîþ¡Ú šÎBñòâ±^¬Z'7o¾Ù]‡;u4xòâÙ£EŒã~ ‹~´]Éý(¤}Ã(Fœ;í(òÓ¸O€r>hJ!ÈÌ"ÈÌ"ÈÌbt%TîáÃà[ ÷0xÄVcåX#ÈA«ÚO*%$âm …RRN… A¢BåLÈ(³k!N|M®“Šk^KaZhÏ‹Vw]…IS;)F•çZÛ»=”­Í'D‚œ33ª¿¨“8\Wl§Äwæµa¸áòó7Ìû¥÷IˆIÕ¢ÒíèALseW„œkwýOaMa+! ‰íyïê8KlHß•À©(ĵæNT)ë@šðz·GV¸87?1 ËEhï´ ÎN[|‡T»ÂRæ¼Ï¸U¢, £ýÈRo“ë=ò[ÿ„85°£ ˆ¸ûzûÒ£m~•¡Ÿ8~Å]hóÀ©´N®‰ì}ý»H¾«#Tk®<§ˆÚÉæÊ§*¯ý8§ÿQ+´ÜàTöƒœ½ëCÿóP¯‡úßÍ•ô“ò”ÓÚ¶ŸÜÕ¡lLÊuÅ}åcS©šÜ@½ß›G[%Foˆá?Žæ#÷g¨aÍÄ'FÇi„héæK‘ê|Râ@¹¬‘TeG‘s99íÆë K|é‰yÜ4ϳð™Üµ×¯)t©Ãx®Ú~»w÷óáòó7Ìû¥¶£[¤;i)AR‹(ëë)üLÖŒøq—Þ¤ü¥¹þ${Ôº²ž±ªqµ‡:]Ö64áõn¬pqn~rÈ@ˆSªO®ZPL™ó>ãV‰²4TŒVæ´}­ÿ),Ò“ë=r»zýâÔÀŽ& "†uû{4‹¸Ÿ8ý0Bv'í“Ë~Ñ׿‹üæ¸Äo'cs¥P?8mÕ!¢Š¼¹òÉËëˆkr³ú›/Eè]û‡Áë+qÑ÷Pÿë³¹²¾~RžrCÛö“»:²_Š¡›Èg•Ù'zÎÅ=Jù®ì,œZ ÂІú£g8eÍÔ&FÇ©õ—ž(ÔÑ.·^¬!Ö‹ühëŽÒÍ¿aIäÀ“~ž_ŽH‰pÑoþÓ?–|iÒ $ì¹ÄACsŽr:Þ”‹:ät(Ý<®PvÚ×fÿÒ×_Gâcïkó< ïpÉ9Šëƒw9óHê0ž«¶ßñÝýÃ<Ïš5y­W[w÷Õ^ÐÜp‚ˆ—õbÕ:y¼yóÍî:=ÜÑ<'wûä^<{t£ˆq=Ü”F¹a…f˜Ñ~àÉ(÷{læµrňs§Ec÷ÉPέ@)9€Y9€Y9€Y9€Yí!¸»h„œ.ï†0–)Kø‚:7ÖdпöAnš¦>úèÐúþóŸ»Ýdù»Ûž|“åïnSxòM­좹`V°&'¼ÝsB *ôFj®æä$¤úGs%À¬RAîñõ-ÓìÚÒÎ >&5žhºôê@Ÿœr‘rJ£O`A`OfQ“˜x’2êD¹EQ“˜E˜E˜uÕ¼óÌØô•ÌÉÙ9¾ Î1i*òjä(„æJ€Y9€Y9€Y9€YÒT;Õh†º1æêlgélùPBûšœ¦,›çùæÍ7Ó­³¥³å@!]Ôä¦izýú¥°ôùóÏC‹ü¹=±l¾9ïyoÏWDŸ¥Iœç½[M®ŠË¶ÏOöÐë%ÈMÓôõÓ'›Ÿ?ýúOò†NññøúVY ¬×\ÿ}ù#ïTAúT•à½mz*ˆÎoöÓ"ìÐü·4×¾¹€B:ªÉ• o£ÓWþB[…-ŸwÕ ªI¹°h©‚Èí½þ¢æ”)÷Óœx*üšeh§zGmHa!Èí–>ë5SÊ a‡Â¢Ð 5½{ûJ(mã2åt5i¶ª)tU)ŸÂ-Õq§BØaWp‚\DyáüŽ.QÐôVx95ËôJí¡5ë“ÓV³ã @C‚ÜÅåu¨QÈ_yŠúw4J…êBseçx€av‚Ü´ç(¿.*7‹ z–Øcmtåºó©-!¤0¤óäYµyÚù.€DÕävŸ‡;ÊxG‡P:ÝWÂw% ý¨ .åq'0ú´÷ â«Û¡¿ÛÍcõó£ TûISïîæyÖ¬ùågŸ”NL·Îv–Ζ_#0í›+•ïØ5_–ÉÎv–Ζß5ªn@Fíkrë8Ç ¤ ÈÌjß\ @!9€Y9€Y9€Y9€Y9€Y9€Y9€Y9€Y9€Y9€Y9€Y9€Y9€Y9€Y9€Y9€Y9€Y? -¸»ØÝøÅ³GY@NÛ59M„›çùæÍ7¹Ó@6ÁšÜ4M¯_¿–>þyhÑãëÛõ?ß½}¥OÐeÛC›Xòøúv7ïÎé½X¶Ú=ùšCè™ù¾ÒOËræ œš„3Ÿ÷Z­³gôF r)ÖСë‰+o×:žù§ëòIèœ_>Ïx‡ó}-–3ß:!F‡E'—RµÂ [J ¾'Qª&²”³›m;¡ÿ7Ýú“ˆÖQg‡ÎÞœª9ùÿ %C¹¨èïV'µÊúœp6¦½ïkw«ÍmåÄË—³HŸ ?ý¡.ŸèÛiåËFÞ0” !_;”7‰8óúEʆÊè+JŸe*ŽVÕr~é°¾¶"|äø'¢T’¡_ÔgíJ8Â÷Ú*îûÒ\6›;T&c9…Îæ5;4ù’å=óšå/Ò\ó› ‹¸¢”›™~eljóœÜÑëÉùWú7W–Gì¤ÏÛ,.U%zaËÒ>ϼ r‚ˮ跿ëñõí¥0î€^íšœ/ýòê¡ä÷ruXEë!ò‰:´Ÿåïò5„,'Jyæ£ñ6.´OžDû §´ô!ù—f'Wª¾é¦¹ç©a2RÎÏf“TôÞ +q¢”=júcÅ] Â&ò"*Ï Fså~1e)Xû,ó¦ªtãö_íÌ÷ó×LI– _‰_*/–ÙwŽN”ªÉE ýZoµù +T‹hþòGjê„÷·’¡_ä¯A>‡4£ÚôÇÊÕ\)$Os…­4)ÜLsèlÈ;W¦0tP½ì[Ü…-,’ïÁÐuwëùžá·ø9]m~¯w÷ó7MÓ4§vÒ°Ì›¯ÙÚçÚ§õ¦ƒ#œÃcu2,`è ÂpûFwè€NµbRµ˜æœ<µž„±-Å¡}šsÆnK ïKß±KÕ+I¹.š¿f{6åå©@žÆ´®n½ïá8ÄÞZWB«´[ï—çŠzžëºj©÷ËùâZ5 @Ža®Ð°)–’ ޹zú:ô{òäIÓwÍ×eÌõ|>U®¡yîNS'ð=ÁºMßÜÞ—Mo>|êý’ùää|¨-kM÷q·@Â@¸ì(\ï_¼kî[÷zíµ×^½&ðç¯÷/Þ5ÜwÈŽŒ}Á|çó¹ùù·ß“7·wÍù|þænÉ[±¾I`ÁÊýüó¿UBbWW¯åḚÂÕ J^h¹l®ÆP€Pòâ«äOÅ ™o¾T5Í 46ÃÃ’õõiT=ýî½/_~/®|k”iÍm¾å3†Ò7×ü’ 6Å/1!SÛÜöíúSæÔsÓ‡¯µŽéœ0¹ü ÜGžö¾Ï¼¼8|¸RGÈÖô¡PºvÈÞÚ'rXàAÆ@‡ºâ!³Z†tC¶Ú½銧Z¦ôáƒ9Ç+Õ1í[.÷pF7H†ºÎSà íÿ×^6d=±C)·5´íGž~·>c®áš³+Þnqµ_MV7uw×Ó_Ï™ùµ¯{;5±^ì2)†5BËh´òg†k®Ÿ¿®ýåI7úZ@©/âÜûXÓ—p%Ÿ?¡¡˜k{k s¤ÚîÔ:ü\¾€–kήoìE2usÊñÌTëš ˜Ë\Ú¶rìe[1ÃD„kéŸBk´ØBÆ•¹Þ^MÊЉéb×°­¡a”¡`Õj­°åÓº,å⬱Ìkî×’eR ‰Ì½¯óÈ÷ƒ^V‹u¤Qšú‘ƒ!?"kQÅ~+óí|ª‹Ü4ÏÍRŠa-W(ÝÍíJÈ {ϧp…ò#‚ôŒc®Âá CÔZ)sW›5÷s¯3+„ìW û>÷9¬1³l="…¶\/€'åñùãÛ]~X…ì×Öû¾äÔ_¾ü.,Y>, XÙ›5Ÿì¿‡ .i¶Üê‡Ú­‹îìœcá;ô”ùÐ'ëucf"ˆéîO½¿¤Å:µT7 ×”NßÌž!ß0o-¤ŸÝc,X‹9ïÔÑükó»ü÷µœóþíï*aeÎééóNÅ_›Æ\2®Â@¸Ö)õ ÿùŸÿ}÷Þ¯?þd}KÖSæ\ÛḦ®‹Ëß§Þ«eÿJ.óZeÍÖrýõÇþ,t߉S K×SÖ2å*ûÖËyr>׬)®ù5Ä\ïE ÔPÙPjXÕXÖµÂëpù††þ¶Vw«»¡u¤A°mXdl(0äú*å<•r]ºÛ±•ÐW±sÖÛï[Êýâ¸öx®„^§í÷ºË„\_%]ƒÅÞ-Ðþô©yHA‰­<,õ]_§RO¢v÷`¬òJ:/ev÷)Ρ=7k_§%äÂië)ÇðB Ý8JÀnq–Po·¨Ø¡åjëuËì6-R‡CéçS_9×¼B¶µÕuyʹÓCŸ"©ºÏCë‰]&ôN€¾õuoA1,@è9¸—ó¢oÿB®‹õ²LÌõ^T¸†0d¹µ–Yz‡‚ %Ç9XÓ¹´ô Ýÿ-®÷b‡ŽH¸Wá pXQ_hÏgs<±+Îiu´yËÕtÏëyÿê™JXszú¼SGó¯Í×××÷* ËôÛÆ\¶@¸Wá €p®;qjš¯¿ÀxsVÉZ®~<ÖûWÏšÿÈx]_ƒŽ‘IEND®B`‚stella-3.9.3/docs/graphics/eventmapping_devsports.png0000644000175000001440000001542612206177002022450 0ustar stephenusers‰PNG  IHDRÌ^u/ÎbKGDÿÿÿ ½§“ pHYsœœ&Í:4tIMEÝ*«·qtEXtCommentCreated with GIMPW~IDATxÚíݽŽÝÈPjÐá@1¡'0”(°”¶°/°Š|3a"% ŒB8ëÔ‰¡¸v DX“ò!X½Ao0Ë^ŠÍŸªb‘,’ç»[l²X¬[«ÈK>ùòéÝýÍí]ô{ýòYõär¹Ü« èW×uUUUuÕNOà[oÏËê;UÓ®TP÷Tjí™Q#L@X¢½Ìa¾ýøÙ!ȇ7/´²´-FËY#L1ÚíEÛ!µí@É&¯aöýAH‡§í ,9×0@`@¾Vëù«÷~÷åÓ»U¶¹ôvr×ÏœònQÏ3à ,u0ºÛZò`¯¹_Ìë躿:v±ÇMXWûø=õ^wÚv®zY³ž÷tb²ês ™ê÷º_Go€[v¼9êJXÿø-Ý™ûü¬SÏF˜ž( _ÊìÃPP„L_æZ¦ôºÚ§&pÇŽÅÔI^‰õsUZ#Omì%O—„ü.dߨÏЉkÛÔsìè(d–*d[¹–‰æ>ŽSíghÚW¦îr!³<¹Žé.sêÂt»#ØÓTÀÜ î1¢ûa;J<ÒÈF(W·_É2¹ê.×zæì[èè1¤¯î¶ÍRê§øÀ<òõ”µ> KÔ¡ ÔŽÔÖ¼anyº#±”ãÑ7Ș{\Ki9êg·ÉöôR ÚÀZá¿äfjyºm u´Ÿ{Ô\âñ<Í”ì™G!е@‰ PÐRN,¦Ê»fx„lkè£ÜÓ°Íÿ_j6b©ií¥ëG`fj\GýZÀ^à^>ÐÚ@¹ŸÙ˜‘s³ìØ5ޱ㲭\ˤžŒ-y”s”>¶®RgCž\.—ûªzü:æ¡Ès 2‡?tÖÛýýÔÎc¾žëF˜í¥Þ¢{‡pÈEûÜ °ÛVr´¥:×­\pô6«í4¯lòz/¦¬ÙVšvºh`r¥&ûm;“’ÓÃ× €À y|s ÓÛÏ-ýøãUÓÁ˜æf]׋nçÛÙxÕ×X¶", m'7·w‹çV{ y¥¡àäjxÛp L˜˜÷¯ÞW÷­§‚øÙÏ~ö³ŸÏù3¿|ÒÏý«÷Õå†Cè^‹1u]W¿þë_§Ï€›Û»oîÂ|øº°„cùõ׿¨‚\_ÿ"z¸† sÓü5ÀyÉ#LȘæ¯ÎKýiðß¶£¯_{øo¬ÜkÖãÖeX:Œ0g2Ju–‘áÓ§?Ï Ì-毻#‡¡)®µ¦vC·2â™ZOÊvƦÛË­ç˧w£Ë娛\å‰Ù÷ز§ÖOÎãr,æ«9£¸Ð›ÖÌ52ÌµŽ˜ýÚNèôîØú–¨Ÿ”}í M×0[í.Ùölû¿î2펠oÚ4fj7W¹Ç¶5TžØõôísJýô…ÉÐõÚ©åbëhh9ʺï1a9§¹;Ò¹S—í¿íû¹´° -c·~ÆÂu¬s×ÏœƒÒ¦„w˜KÌ_‡†ég·ãZO{¹¹£–©`Y»<¥ÕOhý mkê¤l«PÝcgÛ\3<ó9í ï j×0»ÚkÁ× Ú\Ûqbp^{>öcAøõëo«NÎm­]ö½[×2³ôùë5βû®“¥t~¹Öþg ö: )©sÏYž&4Snziÿí^æ}ÒÐW~×0[ífê×Bþîˆ_5½©¥»ïÝ)Æ5¿Ø·­%Ë“rÜ·¬Ÿ¹muèÚÿš¡•c굤¯P¤^›ºÆ[R=Çì¿‘e˜U_ï•û®Ê¡õL] ]&约–‰½ówî•9‚"×ñŒ-OŽ»Es”'õ¸ÝȶÔ~ßÜÞ=¼­djšµ c#Θ‘_êh,çè²o]¡ß%ºûuj½SûRÒhõúú¯÷ª¿ÞËû0w6¢TfR?ø^ï•w´†{#0ûÓ³d®T@œ¾›~Ž2º$!0MÉ®kÓš¦b9{h™ xÌû0`ÎÓ™Ëõõ/*`2 "0›Ç"5•æg?ûy¿?ÿç_ÿª>üõó½»dŸD }­Î,øk%Àÿóµ8É™2„ªëºúðæ…Š˜pNžôC(7ˆõ3% &L(ÉäM?}¯pòZ'ެûË©÷îù³ðôéO‹>u'_úµ\Gzí—&ì,̆^ܜ˗Oï&0d™=„e_¨åôõëo‚ ÀþO–ibZð ¤cîà Í9ûêܦ~SæÔQ^ŽQE®òäÚVêz–ºc9u]±í9õ8¤¶ežrs{÷ð¶’˜;ÇÔn̛io{¨Ü¡S©!åÉ5Ú ÝNè±Ý÷Ôã¾×pŠ-O)Á> OŸþôh»SË´×5´8Š )ÙnG˜:ý6µžîïç†e3ÍÙ·½eº¿Z&¤|ííÌ­ÇГ˜±íÄ‹}ßó´òÙ}ýú[tÐuƒ·ùß¡Ñ)œj„9§ƒïv¼ÝQißh5çhdîzÚåÞ“¾z=9÷}‰z Í…üý؈*äwSÿÖÝNÈiìÔªQ˜Ý鹡Ž9Gç:ÔydžÄT§½ÖÍ*nŠY?,S)uJq¬<Ý‘Wê29G“;, Õ›`F`f..sC³»Î¾õ­1b»6K¹º×å¶Íå,Oß(8å&œÉj.½>™ãziê׎øõˆ¾zÎu­8¦›ßç¨ßœÁÕ„Àœën¦EÁ3)ÇF…SÓ¶¹F³!S²1Ó¶!4PSasÇil¹†®KæžB_ãa¹Ãij=ÝéË¡ë“ÂŽïÉår¹¯ªÿ{#;‡QîÝÍíÝÃÃ×S¿šÑý]Ì 4cß3Œ ÌîW0¦Ö—Ržu䬟ò–®¯I~[ÉÍí]U×õÃÏž%Ën„vÈíNhºuh™±ræŽ.׺ùgj1û>µÌš7+ÁÖ<é‡ÝˆéŒC–»¾7ÛÌ)רr¡'kÕ5LŠãÁÇa 'ØŽ)YØÑÛÔ'a¨œoMß³?ýéOê&ô{ýòYU½|¡"€M™’ &L˜ 0à”|xps{§zx›F˜€°œP×uõöãg&ð­æÝ£üÎc1 y™’˜áù«÷ƒÿÖ}?m{Ù¡w׿Z#ÌG¦ýß^Ê»Õßoµî-·u„ãNÙ¾|z÷迱kþ½¯MäZ9zö¶õY–Nè ´¾ßõ…]®eXŽ)ÙÇs„¥6 0wÕxûlÈYàÐ™ÛØ¿‡¬#äºDÈmèÃ[71ËŒ]“‰Y&äßûö+ô˜†,7·C‹mSû3·ž§ê‡õúænÏôšéÒØd(üÚëêN‰ôm#dÚ$d[¹Ã2%ø»åéëØÛˤœ@ ÕSè1ín?¤<±í#¥m¤c®2³ÎLBȱ™óùe;‡üZIÈ<÷w¡ xì¢þÀÜa¹·csL·YÍm9ŽëÔ'¬œÂÒóT ¿ïfž35ôÔéÔ­#×~­Ý6BöÝ”ßqO˜‡hpSSŽ[ùÒåˆVJíÔ·>®[¶˜Ù Êï“BgI¦>×}ˇ,Ãr9%:ÝÒÀS ×WLÆÖ³ÅíäK}u&äCŸ:…¾Ô~å<Æ)û1´ý=}/ùˆýÍTXvÑÐ EÌ=Âr=O.—Ë}Uíëõ5)w¦.slh]¹î„ ½³7¥CËzƒNÌþ/q—lì(x»d—l1m~Hó¶_ÿVóðõo^¨Œ“¹¹½«êºÞw`®=º³tS`2˜§}øº)+bœö.YÌᱺ®½ÿfh¿{ýòYõ¶V}LÇrúÀ„òi˜ 0`5®ašïbò­³~O#L@X«ëºzûñ³ŠÀø–'ý|Ë÷R1  8^«v|W! kêõVs9·Æ3^C_¶õpªlC/¯-y¿J¨·=®‡òÛF˜ö-^Z¼ÔÙ\{Žä¨ûuôрщ°ä#̾¹ùpw;æ\µŸÚöLÌìà˜IgXSS¶CJÈzºË MwÅL%ç>» )wh™—:›ÍU?©ûÕ^f¨ÓI]ÏÜö³ž¡ýX¢¼:æ°vXR,­<8Abæ³/¶<ã?Âz€“fóª¢ö+‹ÆµÛÙ„Níö­{h]s:·Ðu¤–g©“ûž«žÛÇ/äØO­'æ8„´±õŒµÃÜå ¹œ1V]²Ãfè5¹fš*5ĺL{]!ˤìÓÐ:ú:¶òÄvî¹êg‹zîþ]ìz†‚jè8 µÅõ͉9åÊPÔ×JºF®Ž«Y×QÎ2ïÑœzŽý»-¯×vó’³­¦N¯Ñ%a®Ñ™õÝD±åÝl%hŽÔZõ³-9c´:UºÖ™g šcß׬çÐmmub&¼áØŠš’Í5Í•z‹~Ž[û÷Úy¦ìûšõ¼ä×.öð“ÐkÍߺò{r¹\î«jù××ä¼Óo¨3ØÛ]²¡£Î˜eBÖ‘kßsÕs®;ŸC÷}ª¥¬'õ˜§¶ûÔuŒiÞVâáëßj¾þáÍ ‰q27·wU]×ëæQ™Žã(mM` LÆÓÃ×a'A lËÃסpí:,=“Q×uUÿ‡Õ÷ñ¿¼syŽÎ ŽÐÎ^¿|V½­ÕuÓ±L@0@ ×0@`€À &L˜€À &L8„¤·•4ofõúå35 À¹F˜±aY×uõöãg5 ÀùF˜UUU¿þú— å®#ߤþüÕûÞ—å6oœo¤.Sš-÷«YoŽõ ­+ç6Ö>&^~œzš[Vm‚¤æºMCj¬!Ë”f«ýê«ã³tògÝwÇ6a²ÿ‘ÁZ'{cq¼zrL˜™B£ýaÊ=µ84ZÞz¿¿|z7+8§þ6fª¹[–¡º[ßÔ2Ýï;ž1Sß!åͱ_sÛsLyrm/¦<1ÇcÉc{,LÑžS1S²Ý¸ä(hÍm5Ó©íiÕ­¦r}ÈÛëš.jž:CÛŠ]¦[ž¾ò…N}‡¶Ÿæz|j™s·ç±òä±åø|­yLc…°˜EŽüÖ±‡k#ëiÑR׳cÚOìöSʼdy–ªŸîïBhÍ{†¶%,Ï­¸)Ù¹S…g;ÈQ¦¡;“Õãòí|wv«faû¬´ù°ìùz]fíQÜÏ–ØQö½·ù£×ÏQú&Ò|wÖáÔtPßõ&Ê9 ¹é(Ç2©í'Ç>¬Yžµ?_CׯçÖO®z[ÏÖ÷"°'—Ë循Â_×<é'öÁÞ¼H‰M5ÎÑÛÜ»øætB©ºÔýš;^s¿BËã.Ùc¿Tû‰™mXú.Ùœ³ cë¹7æNÛ¥iè¹¹ë²ÝÜÞUu]Ï Ìö B&°ŸÑ}žžÃÙ3zJ6åAê˜õAé¢G˜€Àk]r¦¦GãQr}OöÆ ¤@`€À &L˜@¿¤4`å)Bœn„–u]Wo?~VÓœo„YUñ¯÷ ‘ã•¡Ûðh®sÕS÷ßkì×ÚšÏ3Ð?~þóè¿ÿü&}ð¼ÑœÜr¿ôWPÀùqÓO·óñFó2F¨C ÓsÁÐtj¹±uõ-Ó±yìÛçCßä²_1o¨Ý·±ý™:©urÂZ_s÷ê8„«±2„¶ÔzÎÙVCObs´C0Â̠ݪ¯sjÿ7öžZ&&Ô‡Ö3UÞØøP™C–É=*j¦ÍS·ZæzÎ=**O·~úê+´CÛÆÜzÎÕV‡ŽWÊ1™Is sèCÖžº-ùÌuÉ©æöݨa¶±Å J‚+rJ¶;•òÁ?’öPSé÷¿¤2 õ» Ì\gÉGúàö]ß껓x£¾RÊ|äöcöæû®¤WÓ9å–ý\û56=½ÄßmZg(sim~Éòìñ˜BŸ'—Ë循Â_×<é'öÁÞ¼>Ãú †|ˆ§®{Ný{êH$ä÷Sû5V¦­î’+ËÒw¥ÆÔs®ãÓ>†ŽkŽuäªçRÛ*ìÁÍí]U×õ¼Àl¯ TH`@©=%›ò ua ÀÞ%Ýô#8ïà &L˜ 0@`&L˜ 0@`€À&L˜ 0@`€À ˜ 0@`€À & 0@`€À &L@`€À &L˜ 0 &L˜ 0@`&L˜ 0@`€À&L˜ 0@`€À ˜ 0@`€À & 0@`@nWíÞ~ü¬F ªªüq80»ÿgöáÍ‹‡Áä7ùúå3µ=\à &LØ™«˜…onïÔØ Ü­ éôSÓ}‰:Jëo¿ÓËR×µH€°\¬/QGéýíUì~þ÷ßÔò’ðû?¨˜I?5Ý—¨£øþÖ5L˜ 0@`@I®r¯ð?þûýîïü!Ëúæ¬'¦ÌKm8Ž©¾®ù÷©ßíeÿJ.óZe]l„ù÷?þðP辆S s×SÖ2-U`_aÙô!}ÔÃ2G?¾†˜>¼ÈÀì&½ì»,ëZTº«­Jè0zèßÖšéngh¹§¤aYò~…ô½c—ÖBúÌRúÕ«RP3Õ[ }›²žØ‘rßúsîpGüü‡ö½íßu— é3KêW‹½K¶}F±çé\SÀ™/I¥ ‚Jí3¯JmDíaüXå•Ô›2»ëèëŽÔ¬Ý÷–Ð×_mÝrT`ß¼yéÓ€ÐÜ{X®Ù÷–PoßmQ±CËímÚ¢[f_9¦:üÒûˆ¾r®Ù·…lk«¾öjÉ:3È5u9´žØeBï€í[_÷ÖkS²p®ã?ë}ûÒ×-Q!ËÄôáEfhC–[k™¹wæ G8ïˆ1æß÷Ô?Ìí7C÷‹><•gÉ€À JuÓO]×UýýÔP,ý”:Ú|„ùúå3µµ’o^¨H ŸšîKÔQzûär¹Ü«Dè÷öãç¸&œ™À &L˜p¼yQý/¡7²ÌJ+¤IEND®B`‚stella-3.9.3/docs/graphics/launcher_filter.png0000644000175000001440000000403511433323254021005 0ustar stephenusers‰PNG  IHDR¢€”2¥gAMA± üasRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÙ!›ð VtEXtCommentCreated with GIMPWhIDATxÚíݽnÔHpmC…t”‡”æ®Ë+¤ŠVté¨é¢kºŠòZ^)”t¹r÷-ŽŽ2W€s–ñÇŒ=öŽíßOŠ »ŽãÿÎÌnvΊ¢xÜßì €1>üõ¡8Ûßì0Æáx(Š¢(vå ×—çJäöøãßgŠHE (€@è· :êêÝ?½õ½ï}Ÿêûêm+ñô>”Η¯Þ­î—>~þæi…ÙއâîËýjúÕíû¯#”•†IéîÏk-œYýñûí*û•5`æ@©Îù€4VدŒP€™eåk(p+ìW»Ø¸h¦=T ¦¼ÿaá…õüùEñýûCãíUC‰½–¾s•ÇÌq=0n„ò3$ªaQ~µ…ÌÒä©#–±¯C†{-åùš®©OÊë!¡®¡ìÆžàÁt( cy£Ý5šì}(õQKSðT ™6õݾö€›z:Ó6"‹=†æÑî/å´õ÷¡T§8Õ¯¶c»¦EõpÈeÚ”bŠ1wȤèÐÕÇ]=gõñ‡C{øn¡œÂÿ–çgÇo\\½‹ÔÃäáÓÛÖó„,òN1*É¡òë9Ç‘€ÑɈ²Y៴ìT{{c8u¨T¯a®ŽÛõ˜ËëñªQº)¤5” 4€²Ò«h+&ä¬z™m©|Æ<)YCi˜ª¤X먯›„,¶výÞ¾õ†l}Úe½dX@o%p£Þ‡Ò´(;t £*ÕsÔÿßv_®lÎŽ˜êzª ¬Õû«!ä"F}Þ‡Òß¡›îoû™˜…Ö9e›*¾~[HçIÙÁb§ c®gîÇÆVG(Þ¼éù<€±b±Òóy(í¼¥øùùž0·Í~ÊŠ·5¸¾f«…êÏùÔûôaR¯‹® Ù¬wMÇŠiѦÂD Àt#¿¾]„É<6½†b‘tùõÂD dÙ˜ë2f¿¦¡4½±°oÏõ´á@Yò~/m§¯Ñ)ê©mËØ¦W㘞}yPO$s¶¿Ù?JqÖ4-ÕžçWþ¡§569:b£S@ @ ((À"Ø—ØÎÅ~/ P P€ økã1ûé´Ýßµþcá#” iÛç¥ïcû>›#f/(+—ëËóÆÈ¿@ @ L¬ütô¡S”úÇ6FéÚ¤»~œ aíìË3âþ¾ãbo#”™F1ì÷F(ŒP P@ @ ((€@ €@ P P€±¢öåº0q¦ÞYP=ö—µ2ÖŸi„y9Åíû¯Âä„e­Œ†·Çè_ý[)OY/.fù=걿¬•Q|{´†$#P`Åv©OxõÏ¿¿Üöéå‹$çsž˜kžê÷lM_[(ïï»m)/çkžëZ'¡|zùâ颛VL!Œ=O̵†\ÓT×±Æ0)Ë6¤—&)ÚùbÚxÖSž%6yuÐ%^ë\vsSž©¦Fm÷Í5¬®ÿž¶s¤žò “mLùº¦ö!m*—v·Ë¥•S‰ØBh*Ø!ç‰i5?åãÚš5–OhÛ¬ÞV?&¤MåÔî²}•§š¸Kž. 6¦ËkS»\QuØUx95Äòš½j4¼ÜÖTVs·ÍúÂîÔ iЩӆ¹¬;TNÑ6s(·g§(ضã–6ì­_³—”ÓtˆÜ˰é:ç¬ûßuª¶¸›:HšÂ$ÕÔ í<±Ç„¾‚Ót¾úK‡¦<Û(‹¦ÇÒ¦(ÇcbÚxVz!ÇÍuÌØW–¬—¤+÷%•ߨvúøOÑÆ³òÛ!P`Å¢eÇÃlŸyÊtÔ£2:ùeê­øßÝ›W“[=ö—µ2ÞÏö7ûG…ŒQnµa ˜Ê P@  #»¢øñ®ÀÛ£ÂÆ9+Šâñõo¯•0Êý—ûâ?‰ |œr+Í^IEND®B`‚stella-3.9.3/docs/graphics/commandmenu.png0000644000175000001440000000760611433323254020151 0ustar stephenusers‰PNG  IHDR£Ã/~gAMA± üasRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÙ5&¯tEXtCommentCreated with GIMPWÑIDATxÚíÝ?ŽHpl½ŒâÉîHs¾ÂDVËÙd;ëlem´á¦¾ÀJ³á„y·ðÜÀ¸éeþ|@õûI–e7Í£ª>꣊z𪪪oï+8§|ª^=¾ü¦*8B}¯«ªªª[ó¿üüƒZ`W¿Þ¿ÿýZUp4ÉÉ$#$#Œ8I2zøøýû7À^¾ô:ú=£‡Uõù·êŸÿþSè—Ÿx‰>â¢à¸!.ÄEįÿcÆÈH"*V}¯¿‹DD_\HD̈‹1·¹¿ðÓÿRã%×›Å₤qÑ'~ψ²‰`CVÓp’d4p¿€‚ˆÀÈÉÈýİ¡ÛÙ ððåë_þïóÛ7«ö1÷÷Y×v©ê»ÝŽ[µáœx‹”/rÌ)Ëõðåë)ã;Åy02Êô~Aûdoþ ÁhñZ¿»ç±Ï=ÎCe~ϨÛñÕmªz_osŽ9Z®9Ÿwª¸KxžçzÌ©bòt}ÊÕFF®<8:ÞšN {bÑy.R'£‡Uõþñ´…L5\Žìgj›îÏSOUmW‰Ím¿¾ŸíYïK¦}SmS²è¹ý¿­ë>“©ú”ܧ O=2j_•Î À¹sç‘ýD¶Û–eõ>çªtzÏq©]î%õ—ûy>Ôùnqž§:æhLN•+²ŸTåÚÒé¿gÔž“ͱ8â~Ô6É7Úí}–9óÈ1oQ®³ÞSHqžwoë “Üû¦ÜÜJ)hé'ó•Û¯¹ =ÓH3rÌ[”«½Oçø9Îó«–kY2:ù=£Ô's™Ùàã¡£#Ó™ë; ö´ÎÙ¦êæ–q¨ãíNŸE§Ær/×Σ×gÀ% ³çRÊTÛpLû-é,ȳ½÷üü«ôM{н\¯úßûIr{$ü+Ü–î'ºMß¶¹vfŸž ÿôá]ò¸˜šz[Rï‘z\SïKc`é1§HvÑUd¹ÄÅÖõÞl9/לŸ©ú‚¹åJÑ7mÕ_ôiÞtúdÄy“₲âb,y6•Žæ©Ýœ$y— b02@2r¿1lhÖê{]ÕÏ«%@\ .Øwdôù·É¥ß\×Ó‡wƒ÷ŒÄEáq1@\ˆ‹mFFÏS4OM‡ÔLÙøw™ÿN|è” þÒ+¤6ïK¯°¡Y šG|P–裢â‚¥³lá‘‘À*S}¯_†ÑâqÁš¸H62ª*>,.¸‚KsÅ…¸¬YÊ“ŒŒ@2@2€ÛÕ 4ç}ñäÑV©Ú¦Ýö[µw_| }V¤|‘c^[®+œsêýìýU»\ÝŸ_¹»ìÈèóÛ7/ÆNÈ=ƒîèc()± ÕuªvH[‘cŽ–ëŒçÄ’zš:þTí»Çù)Wûÿ¯ÞÝ*`UßœàÝNÃh|ÛzW®k)6E†ý)¶éþ<õÔ”¶ŠÐ{¶Ã’©•TÛˆ‘ñöMu¾æ8m86{†~èVràvƒ°}u›j›±mIÓVs®8÷h‡\§ÁÎzÿ¡=ú:þhûöuÒsÏ×”19U®%çIß±œ¡z}åN¬ÝÐ)*?õü-é;Ù³Ý;æÔå:ë=£î±Ÿñø·,W·;ký\vdÔ\!Œ%¢±ÆšsÕbaÂþWõsÛúŒñyÆr9ŽŽÜŸ¦»¹9Á§†ôg›î8{[BŠä1vHLçò_zY»£ ¥K #¿g™÷úN%—å»F.ù¶÷žq²ä³R~Í ‹Ñ˜Ì­*rCô†hŠm†¶ÕyOw´ç¿SÝäMÙg\¹tå ‘öÚÏÜ8I“‘ýDc)×9÷C¯ß?~«ªø[½Ÿ¤,ŸžßOòôá¸@\°*.ú4/ãól:' €d€d³–v×÷ºªŸWK€¸@\°ûÈhjé7×5¶LS\ˆ qA4.Æ„¿g©ùžÙŒ8ܬ Í#>(KôQQˆ qÁÒ[>á‘‘À*S}¯_ætÅâ‚5q‘ldTU|X\p—æŠ q!.X³”ß=#' €d€d·Üpí{æ×þþÖåé;®¾÷ÓçøÎúÔåNUÖ=몯\CŸ9®öþ¦ö“¢Œ_¾fSGÇþÒÏŸd>2jAÓˆCÚöïæ {<¹ß^å_Úž[ÄXŠcHQ¦n§×·ŸÈ6s?ïè6¸¢nß5Õ¦)Ú Õ~ŒŒW#®*ÊIXg>ö¦Sè–CüŠkN˜Œ–‡×4øØ~ÚÉ1å4I¤C;ûÝÒiÈ4ÕØöcûëþlË:^2Uœj›RG$Cõ™:ÛktÁ©cNµŸ£½¾Jðm=EÒýÿ\¦™®vå8urôMÝTcS${N—æ8{Å8Ž”©}Û M¯-5•}ShÑœ:æÈ~æLJF ‚oiÏÝO{;W§óÛ¬}bª¿j°C\²ÍÚ«óÒû‚-.BríüssSùŽ®Øi—4혺^¶¨»î´sII¿Äcιü’‡&Ú¹j7IKjiFKÛãÌå>CrJ}Ì9·o¶ÓtCó¹}Pw‰ê’.Å~X×¾sOÎÔÓ¤)–ÆŠ<â)‡ï&-‰¥=—yç¶ü–{€M]OMgEWšä8-ÖS)[¤­úbbM{¥j÷ÈJL +m|LÅÆÔ9ísRõ]Cm>vÜsŽgÉ~rŠÁWï¿UUü­ÞOR–OÏï'yúð.‹¸¸âÓ)Ä¥ÄEŸæe|žMÀá,`àTÎ0ÝHF’€k1M€d³¦éê{]ÕÏ«%@\ .Ø}d4µô›ë[¦).Ä…¸ cÂß3€Ô|Ï€lHFnÖ†æ”%ú¨(Ä…¸`é-ŸðÈH`•©¾×/sºâqÁš¸H62ª*>,.¸‚KsÅ…¸¬YÊ“ŒŒ@2@2€S¿Ïhè½ðSï»é¾¦:Õ«¬#ÇSêk³ç´ÕÚúس>ûÊ5ô¹‘ãjïoj?K˸ô¼9cŒå\¦ÎûâFFŸß¾yù3v²mícèû7óÚj¯!Å1¤(ÓÐEÒÜmÎÚ©:ö«”é¨X62‚ \¡·_‹Þ-‡ q„d”Ͱ¸ÛYªÿµ}¦:“è4ÓØþº?Û²¢åÚbúÛxlªsjº/:¸t»©m¦Ž÷¬}ÊíJAiÌÈý$'ù±W²s¦YÇÚµÛ´Û6òû{–+çä¶i¤/h·I÷œïëìÇFº}?º7<5bžÚרñžý¶¸{Fß¶; ‰ÿ¯‰a(~#Û”|Þ´Ë3V¦Ô1­¿%÷»çÉ•û¸×%è¹t|W¹’YSv‰h~½¨»ý/˜–vúÝQÓÙHF;'¢f[A³o2^s’ë˜Ùª¿X»6:R£ ‘ÑÒ+TòKH);‹¡+â+ÂKÍärÁ›ò+}Ê‘{ßgK|—^Àm¸æÆ`{^vë… {|ÆÙÛ±¯ýæÜ¨žÓ©¾hÛ·\W;•º€aÉ~æ¶yÊ8ÆhªX>Ê«Ç÷ߪ*þÖFï')˧ç÷“<}x—E\”ú q‘ßE“x›}š—ñ™¦àpžÀÀ©¤ž¦$#Xœ@ü]‹i:$#˜5MWßëª~^-âqÁî#£©¥ß\ר2Mq!.ÄѸþž¤æ{FdC2àp³04ø ,ÑGE!.ÄKoù„GF«Lõ½~™Óˆ ÖÄE²‘QUyPjqÁ\š+.Ä…¸`ÍR~÷Œ8œd€d’’dû>£È륇ÞSß}ßHßv}ï$™û¶ÈñŒíãáË×ÑãðÞ”y±2§í"ûQÿù¶ï’ö9º}—œ×©ú¸Hjd´Âç·oþ¯"»ÿîVxûçÝÆën7S ÙGóÿcŸÁòxXR¯}ñ³¶ó™:ŽÈ6T¡sxïöÍ¥ìÑ>.÷~'ûd´E¥uƒ²/±¤Ü5#êÎÒ§¦p;KååtEcí:'aŠé¼¡éÈÉTL¥:fí»|_‘)ýhÛåp¡Öô§¹_öɨ©´¥7ôûkƒ4òûSLûØt0Û_,ôµÃܺJ,íýtGfCS¹SÛD>‹ôu9?§b)rrô̑ъ„’ªò·>¡§®ªr._áÊXg}ý‘ÏmÜM"¹\0–°¸æv–ÍaXE%Ç¡ò™EW?nÑ9ìÙ•ܾSçà^uµw›DÊ.< p¥+¯Û/åhûÈ$[bB:_ö¨«£¦à®ÞW\þK¯‘ûMCË%]‘’*Æöܦ”ðuÕÝwn£‘+¯½•¸‘ }ÛEn2ï=à*9mŒÕ÷Ð’ÿ肘î¶s·I½ø¦ôó<º‚qªÝ"±´váÕ}\î^=¾üVUñ·6z?IY>=¿ŸäéÃ;q¸`U\ôi^ÆçÙtN2@2ÉÉf-í®ïuU?¯–q¸`÷‘ÑÔÒo®kl™¦¸â‚h\Œ ÏRó=#²!p8OífµæÑ/”ÅÔ>FFHDª¾×/sý`dD6<³°ddÉ6FFHF  €dÀÕXMGÖ¾|üÙç·oïoÉï®9ö=>$#ØØžyŠ„ÕÞÇׯÕׯŒ0MGqImë¤ÐMfÍßc£<02‚“ëÉtÿ¯›úRw›”Sz‘Ï‹&®î¾ÆöFF8á4¦:ð¾$u·ÙzÕì¿ý9cI³o›vYÇöFF¨ãžúy;Yå42°$# KX9.hŽk,I¥Lx A#3¬\»ÏµÅÈrçž—JD©ï™ ݧŠ$†±{X[×…‘FF°a²ëôÛK©»ß홳R.Åý§©}t¾tÔ3´#%$#H(Ò©%”5óV˹ç$™¥e…32M€d’’HFÎj:V«ïuU¿ùQEFFã—ŸP …zúðN%`d„N 02ÉÉ$#$#ŒŒ@2@2ÉÉ’¹UÕ÷§.ÿzWãUUUß~úÛOj€CüþŸß«ÿ. }˜ôVaIEND®B`‚stella-3.9.3/docs/graphics/developer_stats.png0000644000175000001440000000703111433323254021041 0ustar stephenusers‰PNG  IHDR€¤¡”žsRGB®Îé ÓIDATxÚíÝ/Œ×ðÙè@ËZxE.¨Ô”媒œ ÓƒŽ,%¶BbT1‰Î®5¨rª+,©rf1(hQ¶lKºÑÝtwþì{óç½ßç#ìÍÎìÌ›õÝWß}3»išfÛÆk†@ b'íl·w?Þl6M×sÚˇ¬ß%uý¾ý»½ü˜mYèò”}˜Âv»MÚŸ}ëï~Ö>¯‡Îqßù²|÷³Ô〰ëø0dýcD®“úÖ³|m!eԦ؟!Çœcsø½}|S?„ €Cþ˜¦|<œ~r®?dž]ÊqN9FSž)ömèÏrŒ-0Œ¯‚2Á¨0¶¯¸Üw…o×sRoÑÑ·~êþ€#ƒÒ¾«eoßÇnÊ{ ¦î€8"|zÎ.øzœË±ûÀž˜®Úß,±ï›&R^Žð§ÀŒáj·|Š¥ùȇè vípnÚ=€‘p7oïöwâβº¶Ÿcÿ´„@dßÜ”†|gîÁpÍûP‚¤AOÙæØö¾m…€Ø ºúYΘ{ÿ„?@ ”CärõáÓQÏ?ÿô¡AX€ ˜MÓ4nšG§÷¾6 ÓR“³O ÅZü#àû_œ9 íú³ ”¸4|Ë0  0™›Ÿ>ºóøgn=¡µüôÕ¥A˜  pÐÍȆ®ýü©_€ãh‚ч½¸¸óð¦¹éYá"ïëßs ¦ ¨†9€Àao=¿ópìU¹c¯ vÕ/À<4€ÁhƒR¹öúîó°@€`4€Àdúæj–¡FLF£°N@@@@@@@@@@@@@@@¨Ü‰!(ÓÕéó¬Û;¿¹0¨„  @!ú¿± ^{{íÇA¨—  @¥rÏê¡FP©ö> °£FP)pˆ@@ æ”âãÇ‹¯þï'Ó^ïï9TJŒ ç­Æîê«×G-âЀ€€€ÀUÀ•:w?à @0@€J¸¯0”  @)þðIçâó›‹Q›»:}ÞóŒ c•Ò£¨TÃD¥FP©öœ@ °£FP)pˆ  @¥úî ¨!„¸4€Áh*¡Ñ†Ò£(ÅÇ;Ÿ¿óýÇW_½žöz­íõЀ€€€€€,Ê}*uÞs¿äûÅÒ£¨„FJŒ ç¾›ÈD             €€€€€€€€€€€€€€       ³:1@­nþõëÎå§÷¾6H@H@€j˜«oŽûi‚Ñ«5uÃç*a * @0@`1tÞý„_þdá=<ŸtëŸüçÊ›X„  ÀD4|ÀZi‚Ñ‹¹zð·¢÷ÿæÓ;‰@‘4€ÁhÅô5h§þØ L@ŒX-s즡@‚Ø4M³]rîqæ,°˜ëÏ>2ÔÙƒ'°4€  Õ0˜CË1‡ާ¨†9€° s‰Ì>XŽ@@ æBÁÌ!dIæðA¹4€  Õ03‡06sø . @0'†`^ŸÿþzÒíkT€>@€`4€™MÝ𥾾†Ð£ié†oêý×@ý4€ÁhGúöæÛªïó—ï9ÉP9 @0ÀÌú´ûoþiÕëõÓ€€TÃÀÌRçØ-½>P? @0À‘Ü'(@@ æVæço¾Ñ¹üŸ/¿3Hœ@@@@ ®.LßU¾©ë»Jꧨ†9€+“:Çoê×7Gʧ¨†9€+Ó7Çnê9‚æø@ý4€Áh Ó×Ð}÷—ëÎåoüîÌ @p@€j˜Xsü€>@@@@@@`ÅN߃œ: ~ÿ3Ò€€€€€€,jñûžýæÌY€…\¿4‘ùý qi@@@@@@@@@@@@@€ 6MÓl—ÜW¯~ë,ÀB~õÖCƒØ7/žJ  P“¥wàúÅ…³à÷/0# €€€€€€€€€€€€€ ÄÉÒ;pý÷kgó¶!Ìï_ˆK      °¨ÅïØüâÆY€¥¼4¡ùý ai@@ª±išfkâгøUÀ—Ï.€i‚91 qñîuçòç_ž$(„  {õ5~@¹4€ÁhØ«=§O#õЀ€€€€€€€LÄ7°×Øoþh?¿ýM"Àzh‚Ѱ—ꥨ†9€À}ðÈ 0›Ëg—¢FÔ×Ðô5†µ7<íãv¼¹ß/À|4€  Õ0à¢ÍéâÒ£ŽVzC–zUêØã/ýªéíöíÎåOÿèÿ”BŒ«Ý¸å¾O]ôû$ë¥Fmî9t¥ÇÚŽwìù{ôÁÝÇ}sõÒ£²)­ÑëkÀúî XÛ¿¾ý}øþ7ÞäP @0@ ¬©ïã7vŽ«‚¹h‚ÑÙÔ6'.õxú–ç¾ïàÔÇûð}WýB-4€ÁhljÿnàÜsË;®†Zh‚ÑaÍ=gÑU¾ÀZh‚ÑÙ”vß»¹_¿¶«¤ri‚ÑGÓX•=>ÎÄ¥FTÚ}ì˜úýÐ÷Œ¿$(„  ðsÂbЀ€TÃ@XÐÅ»×Ië?ÿòÌ t~/`-4€ÁhaEú¢Ôư6S7lc·ßw~R÷·oý±ïµ­ÌGŒ ¢1Y÷xô5bsïïÜ ŸÊ¡FYÛ°Ôå¹_oìñŒßµ5’©ÛØõ5|P @0@(ÈØ9eK_å™*w£Vúx¤Ž—«| @0@X‘ÜÒÜsÀ¦>žµ¯÷cÚúBXŽ ˜MÓ4Û%wàòÙ¥³+±¶oÖ(ýxÖJŒ9€@6æü”AŒ9€Áh‚Y¼`^@@@@ xÿ~ì*…Yì`yIEND®B`‚stella-3.9.3/docs/graphics/console.png0000644000175000001440000017207511433323254017313 0ustar stephenusers‰PNG  IHDRúí]ÿIgAMA± üasRGB®ÎébKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÒ 24T?ó­IDATxÚìýi¬mÛuˆ}ßs­µOsï}÷õ {Š}gQT/Q²-• ÛQU¹*( U€ A¡‚ü¬‚ ?‚AA$A`T!@’rÛq72lK–%Ù²DR$Eò±}| _»Óì½Öœc|ù1×ÞçÒ¨è¯O€|·9gŸsîkÎ1¾ñ5”„?yû“·ÿÿx+òOpíÞ¤”(@´š-$@’€$©Lˆ’‚II$(* I‚@&€”$+µf6€>m`ÌZšdÆùòr÷àLbBE(•°’@BÈ`$x¼¹ùä£ÓÍóë[QóòÿKå¾;¿l5$ ô¢€Ðÿ£V’uÞIpws_æ9£™Ñ¼´ÖêvçCÉ:Ó=êR6Gô¡Õjk @n&¥"(HŒÌZkÅP ŒeYÎ/.Û9æMCqµ4 ²µ0.µºÑÝ8ó¸]‚…¤‹5vÛ[G'Amƒ Yw IÜK«-2=–V­EL…¥EªÑœ ¥",3D7FÊb[|²yF͇¢j­.2ˆdÖˆÖL³,ZÀH#h2µ¶¸æjÛ­8-Uw»FU$ s·Ú”JX–d¦–@Fó2>zó©gž{ß»>ñ‘Û|ïtã”e¸nõ³]‚׿™ió|ç•×~ð•o|ÿ;ß¾övºˆ¤£L¥¶ªE´ÀLŽé¥D]jr§¬ŠThËäãR3È’!JÚÜœ6yU…ÏM–­©’ô0E­È@™ŽÝ3b×ZØPb™y4NÆh- P3ɹ•’Y“¢ Å47ˆŠLBžJ´¶6 ÔB(47ºi´¡%(@‰°–1cÊ#`˜J)‘@QÓL¤Äq€•¢¦¹í2b¸®Ì­ìeŠËXëåTJ G…¡¶€N÷âC›çR Ãt9(°¥ÁÓ!©¸A†R 0“JÉAƒ§Y.5ÍU³Í‹ „©ln`»ýʾñÚ ¿;#w˺åÎk{º/U¹éÑÇßûÑý*óÂŒ˜£FŒ7¦B%s»Ýú€"“¹©T´Ö8Mˆ”ݸ)E«»%Ì–j"Œ¥0am¹(“žBãp]°?]Û­ª3ÜX`CFÅYDk úÑ൶ݬâ˲„” ÔlsóÁZzŽe—¢êÝ]4Í‹ZÔ¢md¢”º,̪KMA¶+ƒg¸ ]Ù"k ‚Á-j "Ëd†ÉhÞ¢y)X §Yº—–Ùèe$•ñXeÌyGÉäe9·éh˜«†a„™»aQ!OŽNš£J 9Ðàe‰6/S™Ïçi:jmIyšm¾,‘ÒD ½f[ÈVs𤖺ÛÑšDE"w;£+£åp¹½’ŠæµÆéÑx~ÑhéÅ‹ ÂY¡»KÕX±3sŸÆM&–ݘ©¦¼qûV™&qÉqXJ <Ï)®IÁ_ÛQuaA2€ã0–2çonïÞyg7_²¡¶&¯2:’ Q"£¹ZüèÖÍ-.273 aÓT´ #jÊX’>X†#‰Ã0Y±a8j¼6D…±ŒÅ ³ÎYÊXŠ™P”U`†€! 6 ‡2ЄfCi²r¹ +Y€e®Ó4Œ¾ êr{(ÃÑQfdÄQ|š[…9e©¢¬8/‹»ªc­‹çàR3ÐÌ2%'j"8™É¢fDM™—âžÛyÝ3«tƒ­¹å²§j¦E]l£ÕlˆŸÈ¤k®-–6Œ%M1×F³ÖZÜP—¶´- *5jfàÁ…-ãæäQh.Y@SfÑ.òZ”»¤kZîGj‘ón7hÌ]>x0×»öȲYDðtÁ‰D™ íÈ5zɄ̆a(©>ÉJÖmŠ µ³6/ôq’˜­·Á¢Í2+~¶“q0AÁ-R–FH©çÉ„rÉ2ê@þÆ/çš‹Úd–Û–mñÓM†×‹êØ5 \mvmK¸…²ÕMÜÝËbÍg‚Vv ²e‹(’¡¤QR f ´`z[Í‚(¥f„"a›4‘K &án1G¥o­ø˜묌VSËöÒÇb2dÀ|%"›fBˆ¦4}¬-[ +dlQÍhK¤–œÜæe9«óí£"#5/©q°±œŸ>í,7nÜ}ôšéP°Øõ"Í®ë¨Ú ¤ù€¢ÝÅ=6½ðõûï<¸ŒZÍœpˆº ƒ%'CC„È0@ô¢4¸ 4ÄÒ¤–Æ’¡ÖÒ H…õ±ËªÍFjQÛL£KæR+d†Ì€Y it$°ÖHµ‘Æ#”–%Å­‘ R-)F6KTˆ!E¡'hiE¨ePÈHë0¬`N@! $H I‡™HÈhFÁ„T:2ÒhÜÎõíûge$Pݼ¸õ%t(HÐ(¥“€Â`JÑÌ‘NЩ “:óÌ‹Q|ù͋۷†_úñ§Ç“Íè˜3.w¼ûvµ—žúÌÏ}ÒNžº¬5#I5¯I/smO÷2[jŽ9m;ëâ‹ÿúÅ/~ãËwÔ"‡Á¬óÿˆ$:á ªR¢82H£:¸L (…ëÆÃ‹·–¡\aoÈ Ì;<úd!–ËsÏÝQ¹ûå¯ÿð©Þ~ì±G•E‚¨¶HŠëQî×µwWØ@†[A‰óÄ/½ü¼•ÇÑLè'Š9­i("#Å©#–Pˆ„}÷dÄD'ŒJp ¨Eçĺ¤dýÇY:Ýr°¤2„LIM*´™tš"×-Œ¤!;¢¥õ§”[4 Ð2§¢Ssˆ Áв#Ù "éÁ°´i´–‰bÙÀT^HX1K3s§P”‹9ÌÌæ8 A<9²Ë­Ÿݾ±ñd(‹ÉݽE1.-¡´‰Ñà¡B«Ñy:Iæ`, '&ó±pôr4¡¹å|žå;1—Ý}ÇŽ“!:u¸-Ôµèf®/9ŽVFP$JÎMK&ÓÝ I7 ÷–©YèÌŒÑFïÇ8È ‘æCˆ®àè‘I: BƒeBÊHRBãànŽHÀÈ¢x´ÝÜÄáŽÎ0‡Å°”¨FçNK£ ¾£IC¡gˆ^ŠY*ƒ¢³Ð3R‘F Ñia9%ƒ›êõfŽ%’4³Á „B‘‘„™›lpB K£Qnæf D!åœ"A·¨b³jrAòú`½°f³Í’I ¥CÔæÁ–a D*·Á̹Æåƒ­.ß2.-m®»!QΚÎI5BÌkÒÍ\ÓrÌZEV-íÇ:t¨,1š%ÉBÏUd¥°Ö»03‘ I‹S€iÝ|3­J)ÐÓƒkˆ2BæÀ`CqÙJ‰ ‡²LC“˜"5ƒÛv‰ŒÎTÔphp¯ „9±í¹¦ël*€¼ô¿ è 8j*æ(f’몕š'`k„Q¥3ŒJÁ0˜Aéƒgƒ( “eƒR-½¸Œ´—¶.jÜÇ‹¯mï좟x)Iª-*óøt4)ÉÛMzòô‘…£¶K*DXn6‹›s«ËóùÞf°¬6K Jš;Çã1ÊÐÉã㉸&àë:ª†—Ëš‘Ú §åÆ&5T2XÂTH ž*,!¡A’0¸X6ÒBRi ± Öæ$ …ÅÍÀ13/"-£sç:5l‘£‘.4˜Ñ¥HIÄ@:: F7 Q HÂÜi€0-ÒVžJ_†Á(š‰D*3‚n†Lné…µÂÌÙ¹nC*Ý0ˆ±Ð|dÆT¢0Z– AºÓ ˜èÈLÖô4šYêþv~¹.,>–áxš.vÛÝÒDþä/ÿÄOýÔ§™±DûÇÿ|wwyûÔÛï¼öÒÿ­¹të™Çv÷Îç‹ a8*ãÑæâÞy?·OŸ¾}ñæ}„ ''Ì6_.蜎Çù|î£ëÑã·—ûgQ£7OO”§NÊO¼ë}~úÙ/|ë›ïÅ×–ÌuXèSUú¦D®\J IX(©He"µ†$‹¼Aÿôíã;å’@)¨Ø0¥ŒX^¼÷Æ ÅŒ†'OŒ*ŽHv¹–’¨–GƒYÂ?¾yòÝãH{ïsŒgowCÐKMu—„Zq=À×—"&bp[ÂêEÔ@K¦F†Ù’4S"ZîÏHI‚$ŸXž»yºý•÷¼y^Û‡žüÀæä‘ê/ßÝíþþw¿;~ú™Ûï?~dÚ<áÅiÃļ1í&Η»æ~ZëɃZç¤ñxÎgÏò‰2=]좲…§ÚþË—þÕo¼}çÃ?û¡§ß?qêËxãäôCŸÃË_«ßCÒ­|ÒOsþêóm×6=rëÃŸÎøòå›gt¿õ¡µó·Û ¯¥tüÌ»7ŸÄw¾S/c89¾ù¿üÍí÷25šüñw}òÑ'Ÿ¼ýÜd7—õÇ{?ƒ@vÂ;AÈ\,>8Ml s@]€®Læß~óò,4N6ÂÎÏëÒrn!Ó“ï¹ác‰ß8{ãÑc›Œì: gæl’18óÙéÖ¿÷±O›•G|¸t“Y äÂpvë(ë¼ýkÑÌ\×r73˜ZjA¢-X„SÑ2ÌÅ ¢d‘ˆHuÇ“•z%w·—õ‹¿½±1%CyìI<[üaÊG7éßYR˜¯Û?9nž>ñ§>ð‹wïþð_¾ü­;gw¿uþ{K´ïo/¶™/Ÿ}ç‘©æòc{îÄ_¾ éÂr2Õ÷žê½'XQ…ŽŸx÷ñ“ŸÍˆíëw2ìèÙÇã­Wr¾{üôG†Ç?·yòííç§[·Ÿù¹¶{ãòÍ»vò®OOO<·»óvlß:yöýÇÏýLD´;_¨3–ˆ/¾öÊ‹wÞø3Âg§“#Ǧð|YÏË^G)to 7…1úÝYN(ÖÛ!«`k²â¬÷–zV3¬JaI¶ ^~îg~úóÿÎç7ÃXwÛ¿õ×þÖ|›Q…îZ@%MØ-¹m»1_¹1A™­š–œH§,.¬.èÒ“¼.@$q]{w²¤ŒdA”ÉÏæœç&CÁÒÀLš+…b23$÷v_Ø·WÏ^׊âûW^½¥]{é¢=²9þÅgß{sœLL——úÆw^ºX–¡<ÿÖýصw?òÔã­mŠ-óŃË3›_xϦòè¾úŽ?úÈSol_ÿÆëï Ú³}ð™ÇQÊÍ^¿÷ÚÝ{s¤Ópôž‹Wî´ùÈoŒåvÌŒË6?7r8yêòµ·X?:¾9Ü|ÿ|ÿ2Ááô1M:ß9Nži'»áæ._¿ƒ¸e››Xîf¿ôžwúñ' ½s÷ì¹›ÿÒSþékoÎÑû™ž‚¢ #»Á¦ÉEëPUZˆ"ªÁ"a›2ŸÖ7Ïæù¢ ;[ÔZÈ?úê·^ÿÁ½ÑË\çzùÃ=1’bŠÛ4“œã ?*¥Ü€{6Ñks3È-sÚˆ$n×ÄeFBôëVîap#,¶«ƒ¹'-1¤VøW—È”¥Ö5 ö7€ (jhÿê•ç¿ðÚ·[¡¿ûýïi}ÿÕ=Ô$ü_îýãn%‰•º«–óK÷ÿèpmˆÙ2~ã…/ýÖ÷m}0•"S±dqçù.P3»¿}ë•TBÅ[_üÇR‚dÖÝÅž½ôe€R3àîÝ¿-J™ÊöÎþãýgé«¿ùýWû¥7VÈl¹,¡ýoׯbo™Ù²JL ªÐŠSìþf"™Ä4àÇ;~{°9b=²5ër·žÝ w$n”Bç(òJäfݬ¢VÝ{õâ —“)C› 'šÑUa—™ 6Æ5!˜Y¹†µŽnJ!è¸X‘¢Âà Oc‘@4£›É"Ô5 ³‹C/{ÀÂ;è‡DFß:&"gÑpX~v8oŽÝ¡‚’ÚgD‹8,F;‚ž¨5öÛR=tYJʶú)R¨h Øõ HbÙï]‘¢+ÖOfÎÂ#DX“3bA‡s°u]ERÙÝî¼õX“.C·¼Ý™]TL i»_åâA‹q² ¼ÿ`Î ¥n<¾y߇Ÿ°Á3ðòóoòþî·”P! ž°Ì¡riynü™¿øùM°ìrzÏ£¯þÑW¾÷úýP6«Ê+ðšôîymÅ{ÞR ¶6re6EÀLF‘RÖMoMû ë°ôYQ ¬˜ãZ™\—®³ì«£þ¾fßp&±î7±öÿŸÿf…_-–Öå¡VØq-kû±²».Jû×ëpd ¶ßÑ®6’ؿϺ]ÊÃ).Ñ!NÚþ›ºâ¶Sé%(I$3]­t5Gw*MZº" ¹dÜoÍl1Œ€&¥ ÃO~ègò—i3»³Ë¿þÊÿs{ÿÅK †ÁÙBR†saìf|üÑ'žºõ™\^ó£üÇ ïGÆÜê’ÛÆ¥›V.±ËëA¾¾¶J4PÆ wCKË%º÷¬É†”rõûL!33׌—«û~v]7ù‡†«ýõŠNqÝÜt†AG úòôá—3­i!z¨Æ÷¿RIv¯à}3Ä}¯£=—á@»‰õÑR72]q÷¶^n+“&W;þ‹¤¯Ñ®~ŒÊÌì†!9IÒ 7¤2v™½Ü¨¹f¦»ßýñGË+ïl·u[vÖ Z´Öþõ—¿ðï}obɨ^_Ï­2hJWjÍäp#CˆåâÅßûÝS˜ /=¸xQ©œÓëxT6‚Í`ëïOÊýÿÛ[››™¼Ø|iËÚœ²f„§”*d3*IúÚÀp_zºjg ¢ ç1‘÷ K[1TWlàæ±=~‹/¿‘í!´¸?«}n/ã~¶î‹±›• Ú³ Vš@¯Y­„®Î†¨Î÷YWÁ¶Z÷^]¶2®ª{ÿûÎày¨¹Z;…2`P¬ùBKúÀ/% K D؇nLdZp ƒDäå|®‚•#ÑÒÆT‚ƒ1… »f;ÇX¶¾u–Iƒ'hòqðÑ’YkëPÿ.âÚ¸ˆ]×f&ͪh…6RÞíºèæaJÆ"ë;¦€V+÷+ØC¹ŒÌ•Oµ¿AŽLå¨Ìw¶ ®~ä@ ?þ¡ñ£ð>9>wóŸÏÿâÛËÒ :® öýÈ¡ãÙ“h°.Ja}JÞoUD×”CZ‡ê«o¶¯ òÀ[yjýûÍ38ž}lxí‰ãÁnL¾9Õ«ofΙ@ {ĽëVît<×L¡żwL÷wñû//ôMáÑà»%.—¥f<ñÌé§>õn£/fßúâ Ëí=~dŬX¦¦2²i’ÙàeÃÌáŽ( ­Õ+ǰ“íºL‡™×–D@“”™1‡¡Êº b a…ŽNUñž)!î½È×rO8éÊ8ÑD˜ Äæ‰Gÿ̯Øw¿þ/v¯Þ•ÐåHŸû`ù/ÿò㣒 þÇÿÎñh÷ÿÙóÛ¥sćé“W/|öµz`]Ñ~¾ïííp„w!È>OïªÕé÷Ç=“âÑÀ³3=yÃv³ÝßµÓQgè÷÷$›îOÂöÌP#†„™T1Ž¥¸|i™¡&ô|÷!é /ƒYÄ'žüôç>ö§'òr7¿ô•¿iå6@&!AD¦›µÞ²™0Y5’f#Ô%Z4‘¡©à¨;ÏÇ`ׄï^¼\×5SRÊ(¥Xù®y?™L!$(QepëÙ+œý@î =¹ãÍÓG?ù«Ó£ŸÚ#ç™~kûÚ=ƒ~òýãúçNnžúî&xÉÍ©ÿêÏíæüçÖÚž°²¿ðPwΫ;e_©ýÏûl±ÿYÓÜßmèíp^=W0šáñãr6«.[¼ïɲÞ<ç:¶z¡“´ºÕ>¸wáÞTÂÙ.–±ÆÈ¼û©ÍKo^.­¶42¤ ßøÎW^~å».¶î¿ÿ±c‡;ÍÝj E*4s!¨9m(&æBV1$r®^ÕB0ç&óš0"¯/‰à˜ ¡ÀŠÂ½OsHAÅ“™­·²dfTÈ;¯êp"â@¬ÂÚƒˆ€¹¼ûS›G?F‰V67?nïß>®ßþé÷ág>r|c(óÛh‹D‹dùøéø‹m_ÿa{kÛÖéñ µì˜ x讦Qö2՞ŵg0]¾Êý»>FóᦠDB/ßkã€M1篟Ŷ­ÍËÚ]uÉm—Ìöv h-§ÉÒ…¢dâ`V‘¦¡ø—ô£l$™Ê®ðŠõþ.Ñ2oÒvÍÊ€ZÓ£õfìü¼²8@˜X²kM4™C†óhY–èäÔsÔëg×¶w÷Âbn©´¬eÛ†mN©…Ü {óÒçÓìèÝêèµGÁ¾’à:ûÁ÷çwþÑ÷|àæû>»îŸÿû?ã'Þ-D–!Z¡ ™&-Ͻoø¹LÿàQS{ÇÊQùÈ£¥U £}ûíJËèVe$œ+××ôp¯"u ÈÄ®‡:ýÎêZAtÀñ¯„Ò\1/ äî2nM>M<»ìÊ*R(b·MCfF†¶sÔ%]( u¡3&Þ=ÓW_;[\ÓT¢¡UIÚ¶x×{ýìO~øôæÑù‡¿ûü÷^~óï>u#a-5×üöë—?|Pw[-}4S×vnFŒÓèe˜ÆB33 ¿6Ö×w7Ç Ñód¤œƒ•™ 9ÛÜq¸%YŠ}V[9àWŸˆ«ª"¢¿ž—¯ÛØ6O¾w~á‹w¿óû_ÂøS>†r¹pYÒÆ9ÔÀ0DI¼ùƒøúKó’ëlý³@_º·Ž¹œkùá'Æï¼Q/kº[&zÅqïŒÈ=ëmr²g¨iÜX?Ô¥dÇ:µoð÷ùHqp>”hM÷RË4@d(Ó2‚`Lå"V²5 KfÛdã ZãìÒβU°í¬Î0óZ+ þ4ßó8â¶N.ÛÌÝk¼=j©b“s}ÿ|ùþ½‹›“ZÖ2²l«Ò5•a·Ó¼SÙ†w Ñ#¥òjZù·ŽD^WÓ<–ÍÀV[m»9²%‘Ã0´,®Z„’–Ú÷Ò¼B˯†½ÃÚ¦_ûÛWŸ{nܽ9 ñ¹“cÙJÉØY²oDTÜbñ[OÕ¿xñ«­J}+ß;‡ÓÝœìö þàÍXš¾ùÚ²(®-ÕC?Üu~]±Ê‡àÇ@ξ-½‚Õí Þ쳯­[·HEùtYúçJÀ$ú<œÑ¢ÁŠ!eaÍD‚Ôh‘žMDàñ£áCOç o]ÔÚ¼ØfdŒúþk_ý׿5ÒÁ¼Yvï¹}D™9ZHnK‹EÙéÍ¥’Å89ZKX2E#M((£B‚® #òÚRĆ[DZoYÞ‹4ÔàÒ²oúÊQ‘i¥xñý{l¤ƒâ¼>s­Ÿ¹Ìo}àPðåë{ŸŸ¹EZMÑÝS™¤•vÆ{o®Á‘XŸ{Ì¢øök•>ùôøúýöÖå*­ÃC ×=n²:» ó;¨F´¶\`9£)¦áƤGŽÂ̲˜†¢“ÓÖeF¬fÕˆÊ,=“•¨‘bpd_?d¯Çé~}×LI*‘RÔ\fÍŒL¨[Fvï­ƒŽ?÷ËŸýf¥ öQ²Op«þ¿ïX!T~çK—/¼ÐþÜÏ}þ§6ãMFKÑ"Æ¡´ŒüÎK»¯½½d‚5!õl×Þw{ô,ç¯ÞÏóݽ?ov(]»jL ¸±áùV±:‡­£cÈÞ?¦«ÉqåC¤‡‘4¯ÈÈtöUƒ E skÊÌ0äÑ]þª¾õÎåyËÛ'G7§Í[çó®5éÃ|òs?û‘£ãÍÒòwÿÅ×^|åO={ºqxÀÁ~ôéÍ#'¼oŸEkÑ2‡F‡b[ÆÊ–iÍé?r—ý[¥ˆñúZ¢FBT„P½TÝŠA@éxžeÛo%kÍPšuûþ}¡u[ѫגÚ?7XC¯¼3ÿÍßÖ[[þäG‡goQ ÛîÍøç_[~ë+óY[w‡ÛH’;‰E7KyåNF>sb¯Ü ØáŽÙ6S'©øùÏýâg¦ÿÃ_;{û,Öí“Ù¾´ßÕvÃa/d]Ë7PgŸIºIŒŠ4˜Ìé…©´Ä: tホ/Ñ ZQÈ]é›];ß =Ìtðv{öäÁLJ˂y‡{ß;-°FÄ÷ß<~ÿÍ“ýÒÙ³KOCÜÙÊʨª¶yÛj8i^4׆ï~m93Š @K´â‘CÒ,‚¾¢‰„%$  \Ç¿Žp–óýŒïVW61‡rÔUqçþò÷~£}á«ã_þüéûŸ°³{ñ÷ÿÙÅ´UdyuŒbßkÜ9ÏeA*Ì(q7cu@8ì} %žñ³-ãP~æc›go ?ù‘Ý ¿s?ðFìgPí¹<«c‡=´x]ù .È[÷[+©†±÷xí¶Ã„õµ”9S¡„$“,!Q¥XmòF±<5½|Þ.»–óPòhH³á‡çß|ów¾•ACÞ–w?wZ+–¹Q<š©VapP^ÔåR©L[wr§óèÆ)W6ëºÖþ“Qõ#$–%ŽˆjÚBK*»MÌ ¬`ß>þö¿ƒ®ØZd>L7éÃNÃJTäÞÜýŸÿnœ5u>G><ߢ¯uDoŸ€Û“y^óí¥ÓeM~·“|ÏøŸÿÚ­Rгµ%ÿ“?siøí?œ_yë¼Ö`¢Ãî=KDë Þ³uhÝÓšßiPR°hèñ®ÊίðÞþT*¥4Q° )¥°)>DÁeè‚2b8;ÛÚT:[îâR…Ë“7ËÔ#‘« •©÷R¨mÛE#5XÚ`#9º›„Ù§ËëA»Æœ %T`0l .cï²²²^“‘H‘ (¤NÚ=4󺢌ùÞ€h¥…éG¸…¹ç½t~ÉùçºÂÍr¿Eåþ=A\-“ ‹–OŸúEeî`r³øz¦é»/ÕÿÝ_;ûþâ=gÅìîý­xö•W–¥ž{hÞV·½u?–}Þè âNäÃC×Csjß*0é¾÷ú]gónB¶'Ï0L´EEº¿«ôúù¥4•Bã¨ÁZÛ'>ö¾_ü¥?5M¡öÿä^ùÁN7'…Lëà<˜0Â|ñ•³áñÍ“ï¹ac›ËK‰¦AÛmŽÍ™û¼žëPT¼¶¶J,EØ"[fÖäEqx±Äº)W)/¤÷*ÖaYßïχ`Y0beñÐÞØŠpã°þìˆ#ûQk«?ÒÞèëëQƒ»Š£ç‹ö"ºƒhc¥owùµïmïÿ·ùÈ•ÜÕ|ñÍeפN^»–«Å«öLµß²72û¯{¿JÊÕ E7Úˆ¨AЉØ”RÃ"±d¶ 1c7Gˆu‰4ܽ]^ù"ÏV—ËW.9¶œ§è>dRSÿïý{¿öž÷}ôì2Ê Wžÿý~ø; —üDȤL]^^^“æýÚRÄ\ J4w?†f,‰ì¼/u67ìUÓ±®½ZuýìNŠ Š+~‚„­ݽ>¨WSGð¨<„+ŽâþÌ|˜+&¨™N6v>g§ôØÀ ­ª¥ý‡gêÅ7gðP­8K·}Üç—íU)Ir•fö¯Œ°µÏ¿æ÷ç+1MÝ~¬õÏg°2ál§Ë]EðÄù‰§^¾¿m™™AèØ½r÷â·¾ù’9 ò©cW†=+s½M2Aëž¿j’¹ ƒ Çb<©™}Ú>¿ßv ByIárÉËE—óÉ­Á‹+³ÜÕû¶|ßS#çTœ 3IúàNØPÚ+ßûíË-5Ú4ÄöìŽ >,m^jé‚*e êõ°Uº¶NRŒH‘ÃFg6·•kâ„%2…D¡l=¦¯V6ÒzNëÀ³Ú3ºV“¼n÷µgŠÛ`óÇ ê¹€Õþë€i Láþ¢Á¹ôØ™ÜËÃ&_{ð}ðö6Ž~ÃÆÊd¶”¨irôf9»K^gÜè!V  NëJ± u]£Y1DÀ: Ù8L,Õ2q±ä‹çóN8-GGc©UÛ6ÏQâãúþ£_±q˜küú?ü­;ßüV±MD!-cQÆAn¸1MV©œ§ÜØLChsÊ3ÐÙWl5–?éÝÿxà}ŒL$¡†œmp‰Ö{™–ª±6êkŒîñ°Ýíw–À•ù,`x·1¸=ƒÜóXm öíðJa_SU{Üâ•pGÄשeÞÞ”ÍË•çäñ_Ÿ%îÅUk7&ªC†I0»‘å:o˜]qÅÜ·þÁÆTÿûƒ‡ª6}¼¥­M™S@ÖeVa¥X0Bc±ãc¿xgçóVD,TÔöÃW¶ÿä¯×]5–×ßxóɾԄ!“a0SŽÞ"S„øú›gï¼yqÑ]h}r¯çàCè©®ÁÎrãC/r LH¡ý&ØOZÍ‹)7'vÝ ‘@jžsi­ÀZæ@~ä±£Sß-s¦bCsShÜÍo½úúÛŒöÈ„Û7Žš€%A*Îf_¾ÜýÌŸùÉ~ðÃ’ëKßøÊîµo—í¥.î¹s€Òfñ'!ñü[]2åjÈ-' ƒ õqŒ{"G$“r•3éÐЊW6ÔÚïžzeñ·ž{æöGn·¿vÿüí¶]ý%I³¼õÜ{Þÿ îÞ›Ïÿð‹_ÜÝ‘PwïXù¹èJPæþc3=qôï+¿ñåvç|ɼRá­œ‚=@ÒPjxàì)—Úãö{Iì©|˜g`Žü‘‹Kt^y`§à”´D÷be‘ÙÒÚ’ÝpÆ‘zõå³Ö€…Y ƒvK,Чž=ñiDÆ[wj¼UßûøÈ¤»Š¯}— t˦|êѧ~â#æÖ“նІù•óѾH°A€eÚlËÅŸpfþ¸·@A’ HwÒ»\ M›±Ô ãÕ È,XÀÎXìÍJ×ÅíšÃúÝ:ƒøúÝ·çç¿òî£Í‹»–‚­Z‘|äÙ§>ø‹¿6Þzïã§O úáïqwoéÅN[! .’zxR¬5¿þüöW>{óøß¿ù{_½üÍ/]Ö†Ä`dâ=î7Ü+ {·“X¥ßë€Ê}´Í¾E:ˆœ°vB: ®Êý8Ò‘n)C™Q:k¥µî $GªÅz£¶¼?J6××O~ìé/ÿÚ ±-»ðëÿâû_ûÒ»5wŽ48²ÆÊêõa÷­ßÿW·Ž È7Þx¾–T[J‹ÍR¹[ü“(²?þÞ‘B™Ã†–Ùré¤)05¹™‘´Ìèû'¦a˜t÷µ]$ÖÄàœc=ÞÚ½³;ÿ‚yU#­7-ÓñÑþ/mn~`‰8yä=??ß;{íKßÈëiïüþ#ZlòéÛå×~æÔêðá÷ú üò·æ{—9·‡Ö»{pE+̲–tGÛMì¦ã‚?vú»÷—äõÜÃDût3fç"kÏwîÓL#3³ „AHƒ%-"³³:éfB£ÉãtäݳÆØUQ­µlñ½ïÜý›ÿõo\æzçüÅ÷?¹Ñàǃ/ræX m½xŽgï|ý^ŠÄfp.m#Î ­^„"@ï^Îך¹®ÍLb‹ŠldNÌaƒ”¬ F‹5$dÞaû3ÄÄ ?õìøàBI¼x/N<Øe u (‘ŠEßÿ×ßo¼ùô'?zôÈíË{|ðÒNÝŠqÆhß÷<ÌTpsËÆ!ÇÇ><ýWå‘·îÅó7Îï\ÄÕí²ç.ÊD)Éî‘Ô'dB›âÿá'?ù¹§?ð[ßýÂ?xñ•]t"ÛêIö¾ªµ+p¹º°óÌ»iG/cωS"•ÔêA8x•˜8.å“O Ù圄Ò3yËûî~åÄ©÷Ý,7¦#KÖHÐ<åfÜ¥(„ÐBD¸s0¨Í±G‹Zëv¼±!i©l¨­^ÃýÚ‘ŠT»OÐF„õS8#P¼s¡È¾=íµwêÚ¯kºSdâ믷§oÙï§›n å¢j-†}ï#PÙvï¼ø/}<9yü‘éøôõ?ü'go¾¨ØƒâzˆAs çgíí;óxj‹i|rºx{>v¾C¼÷¸rÀVªãúu效Ïm”?u§7Ççˆ×ˆ†}æˆÚjµÎ߯}tTÇt %°ªä”1e SLµÈ%„Ô1‘Ä®âÛ¯_¼s1ûQ!­¶\ªv59è™>r1Œ^|óìôÍ‹æè«êÀ˜hqMÊêº&ïDH4´sE“U ‰49jP+ £'?^Y¾ìa&ÄÇì¸ðþ%æ¦bj®Ø±xëÆðêÛK­UF"CAêë_ûÖ›¯<ðqÓZ;»xùýOLÓHT¤ÌûÖËL–ƒÑI&ÛœF Vs…÷ᱨ^@cñî’¼k&][ÎL{ª(r!/ކ¥ô¶%eWB,A“ìÊ@”W¾§Xƒ}=SåÄN6zñVCŸ'¨ôûv%ˆQ{ú˜j‡HTñ´’¸îVI÷L}ã…ú¿xñÝê 'íÙ6«‹ã1àa%®TâÜ›oðª’ñ™+®Ê{|f¿EÆ2O Ù¢ƒ;’žMê>KÁÌ0¨EžïtZŠ5ÀGÙ¼kÈ(ãh(Ošâ¥âƒÚ©36e1$[Ó4“Eæ¶5úXˆtÐ “ó®JŒeÎ¥ãu‰Ý|-z÷¼¶œ9E*¬ÈŽ#[£”‘‘f6x‡`’d:iîìÚ@¬F¤¤¹e÷Ïñæ™BxúÔ›ü›wjïô{jêAïw Ð>,HxØÆ—v0'€¥®+”Ë=乺ËаÊ;ö ½C¯½>X^‘Ò!=raÀ}NñÒDio䇸>€Q°~Ä$¥`¡RV¬4Gãvnær÷¶äH÷Mè \&„,£´©@hˆ%°\-wUÃ`H·j€ŠgÄJÌEæfQŒÔ™M¢®E¹óÚ63VˆîäÙ4ywµ-nû¸Æu<[i28œöje1%âûo¶ø¨·.òîVyE'\ñöéoÍ&ÞdÛEÙj³ûMìT6AZ)7FëFbºZrÊÿ€Œ]9ñ0¬9¯k6,`{ÇÈ}`ë^Ëd{ÎÃz…ØÁ6¢ºM¶™»”=º))2A«’ Ü LY¢©tö†“{m}“q\7ØsX12²VµÌɋʗº ¡¬KÍmåõ(÷k‹»wÇ* “åè†Õpc ,–¾×3!÷÷¶§ë¡Ø‘?­€ô+6Ý{—%6OåšöÈÃGR{š—ö.=”þž]¯‡sP¸Â‚~õ}è²öK¦u ZŽÌ§a~0§VC>4P¬ç¾äŽ¡ønnüõŠW¹&¦ ©nÁ u÷ë ŒM¢ Êb4÷yε•iÝŠi[“PeZd µH—ÉE9¹xëAm‚B:9-çÛ–&Fƒ(GŽÁ)˜i˜®gæox×á Á/ç¶KƒQP÷1ç:ÂIfwg±=ìÁEh4¸JzT¦Ò.òaâl§‚‰Ý|Z+¤}%Þ;œ«?bð…+fbǃú@i:EÚ{? fFaÕiï ‡“é™Ïþbz}çë_ؾu¾ÿ©à`Åa¤hÏ>5üù?û®/|é­?úæƒ]=øæªZ‰ÍÝ%³ÏÁBJV—¨µµ–?¼³ò,…n_âÖùµ[˜„h˜FÎ"•5å#„49ŠÍH¦Áí‚1]ðËY 3R@Ή%Çã,¾_8D½eÆk»fZú’ÅЪæ3›Êhý,”gî…Ò{X}u¢3¬9{ø®Gb§)ÓÞúègÊÍͽ¯ÿá|o»÷4ÝÿkX”èâ¹=…Wg9ÏŠ¯àÐé`·=%— ÍVVæÕ(Ñaw”ÍøÄg>üÜÏÕùòÑæøƒùÎ6|ƒ^ëà8øöÿ…¿ü~åw>õÏþ—ÿ«øæ-×l‘}¿¿2 Ö˜oZëOƒ‡bî˜Y±£©<þXyúé‘ ߌ<š<h´± Pf;‡aF’dqTóÚ‚a°ž ­_Yßëò–×T[‹´ïYA2 ËnW·£%š•UËõ8D¯ë¨êƒ§÷rQø²SM™w‘„!‘âêÃ(õPÞµæÞ|®O «f¯7…·>ñS›g†®Ó¾õÅåÞ¼O¸åþ¬h ñ£æ/Je_ÁŒÎ~î³»?‡{"&Ùï%ƒDç£øÌñs?ÕÄÍôÄO¾¿.þ­r¿Ïꤳܽû¯o¹E©€c±r:6S3-£9/"¬œÛ@䱌#†Ä¸I&29l¼X1C-ª÷w“ æ}:ŸT°aÅÓÊ77Û¸—k}Hx¯Ó´BŒÖJ9e0ÒÖ Õ^JÊÕëzmµÕ‰†Å ­/dNßý©£wÿ"X =ö9ûpÜýÃ/Ö¹Ú Z¯Žob+Ôå›…­[Í|ÈÕ—ëkÒ l&~êcG¯¾Ö^{£è€_¼u¶üá=ùÔñÓï:ÌoGFv4²Ó ú6/»ÿÛ_û¿ùÛ¿¿;?»sïìê³g¯äPýFÐ2ciCaÑG»¸|6òÄhÎ;Ë𽛸w8¥müÆ›ó{/ò†QÏùÅûÛýGG…åââr¯cd V3+v_C=ÊÊ•&dÎ-–2œ×è'‰œÕ¯E™éÚ†ÄGÚŠG»š‰Ë˜1¶LM$çj(ɇ¤_éJ*»Þ“$@¹íìôo=ùôpëQâh¹w¢Æ½ãÕlÊU$}Õ²_ý’kgsPV<œÿ fìH7þ§ÿá'þ£¿ü«_ùÆW_zé•ï<ÿÖ?ÿÂ;ÛRìÞþÎ|÷{ÈO?ñÜÅ _¼xå+ÊØ[ƒ¬qQH%q¹;ûÎw¿.=<›^=a{q „ìIi‘én€ÌQã ?Çâ-\LžŽ0Ávº£°ÅŽ‹Þ}ãÎeœÏj7l¶í|ÙÎBX¶;ß Tnhª-ÜYûHßä2Q5ˆ²ÁX)L‹Ý8.¥XS4DüÉéþÇ"3¦u²„6‰¨±x·IJ™cO éè¡ÎZIî{àd¶fÏL^í¸9SÑŸ‚ìIœP*•FGËî¿—4-uq÷¥I¦1’ô,nÛ¹oŠÓØ0JƒÐÒj„,p°VJ0¸²jÙ‡zíí¼ºÁØÊ³‚­ê6ßf g¬3öŸ¬3Trÿ¹"ûëÕ—^ûÎ+o|ïr¾÷Ìígê'ßSŠB,‰—¿úÚ?ø{¿ù¯†rµ®¡u~çYÙí#ó@‡YIޏòàÞ[¬L @©ly0ÿƒ¨P6ù B™4+«aåÍ8s³âtWè¼, ›ÑGrsc<Ê®!¡áÄiʰËä»m%‘ž@só 0Ú.2i9Óhƒ1‘as½£êµIÈjâÞ\oKž© é-”}ƒŒ’öÞ¿½JÅ÷©ñÑk×.+‰×|jxù­VñP³ò9LZì}Ry0m{éÒú0 '~ã‰ã³7.Û_ùê—þ篼ö‹?ý Ÿÿ³ŸûñO½OÛ³¿ý÷ÿÆ_ÿ­ß›[[÷¿PÏTâžp€ü”‹yE»\3»FHWÄ’3»w“¥2-Í,Ù‘XÂÁÑJÌíh²]S!#¢Èz8ŽÓ"¸æ¦â˜ŒjÚe„aåÁœ:&+ Åb¤{©ÛØuà=b>Ÿ ]€®Iœ®­¿»A´¥ÌÒèK©32epkSé쥢~$§´&›‚™2vû•³v:¤´ÜÞýFy2Ú½s>ýÈp¹Ó[çM“û¡óéÃáCðÿrf‹ä+o¼üêë/çêm¤ý­|x¾ Ù¾Š¢×¡ªWf`­È’í{›Hø>ù†{`5SJH^8‰D6WL¥(ÅÈl¶SiCáRƒ4 cB n¼„IÑš†Ìa°Ñµ0#¤š©fKf“Ð2›rBC‚$=`K\‹ÓÎkŠÌ»Æš-´Õ.§æ!Ù@81¬n=¥¨‹Ü ÷w:¤laÖÔø\Ñý*~ÍóÂKgõ¼j»Ú…Rk¤Ó ̯”1v-žr%+ü;XôÈs¿õ¾Ÿom$ìøæÿø/OÇÇÊÈÌìÍúª Í+µxŸ²ò®LßÄË=¯ÿþð=Úaµ°Žæ¹Ú6%¨²ér‰Ý‚]XKK˜ „!ªFWPK£¥Òd@–IÅÈe[ͳ¶@kÈþLe·6X˜Ò®¥Åœ-€Lm1Ø8:ÙZF«­n¯E3“*È ®a3SlÝY7Sš\ 5ÌÖ™ììÂL!冴ž‘¾¯•Õ9=W¦ãÞ €=wT«ünoú‹¹å.$XoròP7}î»ò¶[žW_Èûo¼ñ­ßü§7Ÿxæý?þ§æ(g?8¯—qtsÕj¯¾Û¦Õñ×ij‡ÕzŽ&rOè_ˆÍa…n¶½ö8mDuY?6Šú•’ ˱ žéÎq2´½mªnòœŠ¡–…@„«»Q&[jæŠ×ZmbhrZ²µtAÍ,ä© ‚áÆâ}"¸&¹ªB¹†µ¾Í+Ý]æí89Á„mÊF°Õ?Å:‚~|:•v»Új¶Ð²kË6 EZæzHûÚ¹£ûέ2}=œa­õØØëµW7í‡ÝÄ{©aïB³»óÊîîçû¼ýî\ÞyíÕ/ýæ¼lòz¿2ˆÜ £úˆ©‡€ÿ}ÀØÙ¾X´`|ƒÞƒš4Á•è,Ài´yn43 5ºõ€9xT°)Ç8•‘A¨f¤ŠÖ¢¶ŒTD¶šÑ2›¢e Jdì¹Ý:¸K_¥<® H¿&úM€+«Te=ûá×Ùs ®p{€¯5ª›íiÛ‹C¨ƒCI·î“D:ÒÒ£Icfš”µFk™>8jô®Öy@M´Le¦ ¥ y¼)G¯!­iP–¡Ñ ^ãXP’¡qâéÑä‘Ѳƒ¶‘ Ø?ž\Žº ÖÐýÅL­1r(iBÍtM|ftM›FïúPÆz–^}GØü<˜GƒeÕËssÇRܧ±ŒÓ0¸ƒûÀÁ­K,eV Å*3C 2{ît‹9Z6-¡h‘‘­!¢e달•€•Î̽Œj]ÄÚ¡M¹òmÌ•ºB_½ ¸¢¹·o‚õCû`EO0¹ßîpÐÑM3^1Ĥ¢æÚ9@Šl™šƒ6%– ºó}ǦLhÑ ”Äæh€l(2‚†RtRÊÒäƒÈðQ!÷â ©íU“A»š 2MN°©šP“n®¶=ò‹–‹eLZ6“Ѥ½uÏ5!\GŠXäË õ¸9·œU–‰°0—OvT¼.ض ÑvÛàÌ:÷›nÅŒ^̽ îf‡âŦÑ! t˜àp%Ì¢¥sšJæB Kg«fA…Ä”ÝÀbïË·îm îŸÚÞÜ{¥‡öÉ4×jМnÖsÖ?,%muÒ&ÔZæš”ƒ<(8V_&%@#…T$):¦ïn©H±ê` f¶°Ö´3µV£`JXm¸gs.òê¥ ^¢ž/ç-{ò¦pnQzvƒc(Sï|ª%†æ”s±Ú/Ŷ(Zƒyq“_(²kÛ»ol˜@@¾ñr6™ù€Ldú0¾™Æóaj¥¬Ô°Ã©Ù=^"k-®4ÕÖßzu™ ÅVžAÒ»Ö΄$œkKCPÍá0%´ê+"WJbÒüÊ@†Iʯ°úšïÊ«DÈ5iŒX3ù:+@}µ´VvhŸMÙµxru]Z“0A‘öpäeŸp»Ev'eBÃPÜö6ª$Åq2ùnsªÌsÛ…e1Ì&Í´nüM©¡xó6¤f2ŒƒµæL“ïjF99VöÎXn?³ÙO uÛ¶ç-ÏÆ&r*9ŽK`©¡v-p÷ ~tx]ÞJ;ɜۮr“Òéiµ,O†áƳ·Š\éL¦§"Êqä\! VÓÀ¡ fFÝÏ–Ú233‘™h†Õ>[ºJVJ_{å}ü©­€¹$Ë}4õê[#%(¯â‡Wýª‘Ñn€XKû”™«~4˜(#e{\Ý´¦( ±Òeakå]²šÏô²×’PÒTÎç¨U’.Zn3YëH.¤ÃDËÕótïϨL¤5ÆbYUS6 "ëR/ß¾v±[‚l\¤¢.¾À*‡f@ÊUãZ0"¼¦ÍŒZ¶ÖÌ!š.ÃÛ ”lIw’7& i Í, VØÉ4V`sµŠ,á0lž+LN !"5ØB6 ­EDF(æJ$(eMt@‰ŒÜçWr¿ÐЇòøØ;”؃˜ýü~HrH àšÃ±'äçéÞà>R Ñ#À»˜/»Ó£öÌÌŒ¾eíò½> çz}õÛF@ÿ'Ë–t郹™c°¸—‚èé? J3’[-Ì^ëÐÒ,HùÈB²%S±ÌË;oAšB¤L¶FÔf€¼ñ×8›‰…Ũ€VbfÌhJF“õðIDƒda†2°}p¶£5å¢0ÌÚ B™­§–I1"3]”ÑÅDÙ÷ù^BEK8XDF}˜Õre—´ö4aìÇî™Å€õݺíï¼³vE\Í 2ruî«ïµ}=]ÓhùPE™IȺ‚Ѳï”m†ìý‹‹&€L%4q ,ÇâKM—ZÓÆmÞE:¼$%ëi ÌÆ´Á+±ÙpÜLƒÙVHbz¤„6f‰ÂEæ¥.Ö¢[d†Z\YõÚRÄܘé^¦£›C9‹«OnŽŒfæ-ze!˜yˆZDÈÙþL`ÜGŽffr¥¨3™}Ú30 ¼Z‹âj>$´ú¥çjT}µ¬# ԥшã(§pt+~ a0dìwÈáH_ycRº‰˜]nëƒwæHí½”©+s"eÅ}ìa³öЭߖ ¥59Š3¦‚lK‹ ÓîƒÆÑ 8 €#i¥˜‰-⨠x9=* -å&@ %‡Â].m»ì„a,Cvý,áŽkSîj×Ð8s߃³Õùª†´¦4Ç41mÉÝ’Hrc°¤©„"D1ר–ŒL»jkp^îcfŒ\)0™¢À)Â¼Š¯«ØÙh™ß;T'( åØ/}ú#øÜ'>hKxd23ël…-S†"£ eRÔM™jhŽIjVúÕ_¬h*ÅÎ.âõ·ßùý/|ãîݳqÇþ WJÌ‘ávàßdªä´ÞÐÓŒÚÅ ·H@ÚŒnCqçc²ËÌ#/î(“gƒÌ¦£áTYFkKDÕX˜­XÃöb,gÏš‘5Ñ ;çõ›?|pãöÑSÇkrd÷G`æõhfX®©çµàë=Y6<>)—Ϥ$Zy-"Í »ó{ë¼Õ¼ŽÇ±¼ë©gŸxì½Oœ=ÿüËrrdÓ`“K´ŠîÕÆ‹¹I¸¥/(¥s“ÝNoœ|üÓúÒ7¿q?/ަñÌÙV]Ì08×”Ù\]á#±n_û¶6He}Ýå†q  6s·¶$šÍ vÕÔ°3EbÉ%JÕ`¶ÆäLÛ-µðÝ Ò-[Éç×Ïξ{¹õ’e(›AiüÐ'ûSïÿÀæÆ‰Fëø“#—åšø»_ÛÞé„h2U\ ·OŸ:þŸùä7¾ÿÒҲΉ¥f‹lUU™©šjUµWëj¿%­ö«›@tB¼õíMf'ò®-­C{-Rd®>Y¹Ê]s嘛I+£Æq•ßëù‡â6¶ê÷.Ï_ºórR¤E¦™Y†R#³µÈ,41B<ÞØ@t -œ(îåø±iüÈÑ Lw¸Ù ‡Øš·.5S«ª„‚» Š îÖ´×­#\Íe$^½XÞyùN@­;U²ÐœeÑ8˜™Y)> ôâÓxäæ§nC13Û”aÃiãTNožÜ8T5Ï‘á^6¬³Š?òÄæô‘c•#2éEB d\“(²k+ï(Ò €”Cñ£]›ßóø3O=]çF1\îæP©æ@ÎÑ il™±ÌHCÎA½ÎuΨu'D_Pši{™µE ÎK›ëèÎȬ­¹¬f†’™m–ˆH… #®Hé éF70˜Íó²1ò™[?=~$[+PKÁLÃ¥ T Fx™0¨¢fÍH÷‘˜¦éôø¦ãÑøHÓkãQyô‰cXº‘©bénS¡¹9XŠMƒUÑ`ÓT6Å”¤qòΘ´a(&$|p¸^bÜ‹Òɬ‘a˜¦i·ÝÁ!Yg‘Ö¬nÙ(x,Òåî|~÷Ûï|ÿû–5rp>ùÔ#é/üpË©Ðå·º&)Â×7Î@U’Ä$ª»6'ÃMÃÀ;Yƒ±å2ñˆQc¹œ+‹ùRw­4'’<£l”aʆãÍ)2j³8*r÷yj,Ìjm^æÈi(tµÖÜÕhlŠÖj2F(kbnŠhƒ£LˆÄ²dCŒ€&„°=ko¾uï‹óóO}û&r,“±n“šo¢™òr<¤¨¬Y#Sæ2ŒÜÖå¶¼pV/Þyðv­õ¹ÇOŽÝé}èO˜]óRl ø Y|ôžµçFDPYØ2‡I-2¼G¶’Û` QÅ1Ž&š!oÞ>ÆÁâ6 Sñ$­¤' ÇdJ|ç÷ßÙ>¨©Èœ¼<‡›“ &sn«ÙàµYì\_È~¢dŒÝ|±­§œ‚æ§G>d.f^¬ ˼;9­ði™—Ù`¨­=â-;Ä^[c‘VŽ—eË–™­ È&ŸJí¨‹JÏå^|Œ®S†Ãa –F¹ËÍe)ydV4CcÀˆL‡mÕ¾ÿýo}µ}ÓÍh–!ëäcì“U&–Üçabe'DZÇnöþu|4<úÄ“fžÃhjRÒÌ`pãÈ5-¡ 6”’r+Š .5ŒG'‰Æ£¨u†q°žÅZÜ(£»¹–0ãPÜ ­Êàˆ$K5™ÑÆ…æho¿~÷øtìܦ eSb—•CC9^Â.½JȆvMÔL×Ö#2Ù™¿Åp2ÔR³µÌT’ôá5R¸tÛb ¸Q‹…ÃåS[j,ÍKA†s`…\Vk3Å—mø8”²É%H4¶¡MÙP7£µ+£ÕYáµIC¨ªŒɺ[œI•G9F 'w“™µ•ã8€JµZ÷‘½S^WM{ÃŒNÉUž—ë°›X¶db®V—(#†Ùè…>1"‹ƒ,£Y0YÜ€a({¹C‹œ#¨ lñÿ!ï¿Ã4»®óNt…½ÏùBåêªÎntBN€$Á$Š”©`Yc[NrÐØÒ[ö}îŒõÜñ±¯mÍ3²$Ë–í‘%KVƒHŠ$¹Ñº@w£sîêÊ_:çì½ÖºìóUCD‚  xëáC‚@ꫪõí³öZïû{¡)Z 3 T†Ž[œpˆ]ïT =Šó*æ¼F+«Ê(÷ MɱEeU!A¡"ø›nرqó81ÅÊš&Ú“³ÁR3  o’Á Ø›¶™)T"jb«óƒEjŠZU BH& ¡Ó"€€‚–J ЪŒ …i)ˆ„Á™vû!Zæ‘-†¢‚ŠÄ FVIí2Ũ¥Š9ƒ¨ •ŠI=ùC«DŒ 4XRÎ#BÆ.‚x‚•^‚¦Åj ¥I³NP6’z7´†Ncmk´!8 G®úáØ±etÄb‚ÁÔŒ ‘a-j>-jó!8dFSÀ –«™Ô@s„ L¢!kÊV€ŒA £0:s‰]ef¦d‰ýPÃÀbÓ9PCFµ+„ÇÀD‰x¾»”2HoŽÞÝôMË™aŸ3YªÏ>ðˆÃ,jʨÒ2Ò QM“jÍdWãL×Ò¸¬ö@=‰±·°Ü •gƒh‚UÆîs¿û•SŽ ¬!ÄêÚIG:¥•“A³É7\·…–ÍÔH%d䣊Š:ÏU%¨–;TR,cpQbýËEEPмᢪ±ŒPˆhu¥»p¹CÖB%SoE€ª`TçõÕ|ƒ¡F kÓ÷0Óìe±–ÐÊyãø¤*zFT0ÈëÜ5©D¥¶ £™±s"BªàA¢«aÐfˆêGà£G‹ÉÌm¦í†ÏWΚƒÄ¼|™=å×DB,VÍpÆ3dä™Íf³Õºå¶·íØuý›³¨ÞÄŠHγöæ?õ7§¬9q¡èÎ#I¥J@ ±»Ô9y~>Äê$aMkvz@kíÀöÍ®iÏ>òäóËe¨g€b‘ÐÚšþ–ˆ¢ £!rMïI™®fd/3nGSD0I1àˆ¢©©hÃË xé/ôeùÚ¸–*¬kyõ[`˜Pª%•ÌJg°ï™céÝAHjjL˜^¶‚ÖiÆC{ שôéΰÆÀL¼µÄøÀô©kYÐh¶®Ý¾i±¹Üíuv!j[ˆ/ã˜!*X·Û¹xöüö-]î¼wYÖhzj¶Úðfýx‡Õ¼Ò‡Ï²Û^âN7MÅ@MQÚfŽšg\X’¡+ù– '˜l"9‡«¥®–)×J†–Ùd7Càzð±(ûƒÁºu#eQ&™4Öq Cɨ@€U®œ»ˆª¬j¢bŠ>Ä7s ½•ʉófÞn6@Í(rã¥sŠ*Ó ž u~5¤œgPµ™©ñv–ï;{yvv¬5‘›ÅD5«›WFh"¬ó¯Ï[9WçúWÌGCšI&3ôˆYƪ]ê[eà8â~3§® Š¢¾l¥TGÐ ¯Ñ¸6¤©gIkÐ¥5´‡ÕÓãc·Þ°Ë¨XÜ>i™Ë©5ž<_^\ bäD¢G#Ý9噟mŸ>Ý=q±`ï)–Prˆˆ#"怾„CæÉÈÖç“ÍâK0s*£el6ý÷ß=²eÜ>ópÅÌ1KL® ’lغóÆ÷ÝýÔS–¾t°ôž”½#$”¨9㈘Q^@˜»tùJÐâ̾ck;S#2²¬Ø D‘GšÕììøÞ½·´Û£@855Ûl¾yK|kîHíÉÙöälŽIŒÇ^x²‹Ì1 'CQº‚")‚Cßô p¶Ù8{nÞûF¦  1“RYF4B&.û!Ïs¥ .VÙãÌÏÏÏŸX¬Lx¦æ Ý@q|lç¨í½²ta®X`2SL†ªÞÊ ªd8ÙXKµ†—e¾®õóIç‚ø§d%C êÚ8²?(V»Ý±6‡P@gÕ¹¾u¾rvòšxiI’Ÿ»ÕâÀP5?½ÿÒ¥¹ƒ ºŠm†((J´ƒ€‚¡P@S‹Lè GGÚ—çú«ýÑv³ß+BTk0!H4c@Iáp&†ª  U³³[v_wk-ÞyÓwo¥rÿS¥ï|–ç™h¬LÒ¥±¾k&œª;Š!šé¦Ù©Ù©üÅ3ýM³ÌjJ „ˆ„1Dg‚ŒFƒ€áD³N{Bsãs¿¿Ü\³qóú‘æ5-lEÕÑŒÊÆ§ÿø±…ßù¢q¹}Ã4ºÛŽ‹XÍ-,‰B[»j^¥³×i5j†ÖìW£–ÒÄR×ò„‹¢˜_]jÌDð¦Â]^Y}àéOyöwÜxý8²¡,DCfRk{. >7wæÌÒå][·7ÈO°]JF M¤á ™TfhQ$s>Ï›­V»³Òš˜öy§TƒyFÓI3Ïd ¢õv@ȲFã-QëðfVD¾Z­AY¨Yâ²±%’VŒÊLlYŒˆff¦çW:ƒ€­‘ A@ƒBS‚ ˜1ˆ Fp^e©ö(¸Üé–¡Zí,OäþÔ2 ¤E¬cgyÎgÎ,õ»£­‘¦s3DŒ¥Y´hC5­Ñ ×àÔÃ@oL«~ƌخšnÏŒiyŠ ¦EQ`€ÌØ;¡þÌÍwÝ52:þÖ= ¿ÝÊýøÁçž:x¨¨*&.º¶ ¾™gQ" ¡!'¡‚Š’™(H*iò&’BŽ‘@E]cà,ȦµíŸIU×Nñ„˜”dëК_§CLðËCõ‡=ŒÉ44¦b§w!kŠg®b!!Р9"S®ãoj¾1Qí‡fS#"0uŒ¨jÀ(:¼? 2CP DJaŒ˜âå•% H°Òë>ùøÓïüè±o}Û[¶:ôÛªÜEâã_{âÌÜe3m·ò`ƒªßÔ¬‘9õd)© Ì5\†¢† ‚bЦ! Á0dfÈ+¥aú6¸äc3E KkªÈD*`d-ˆ5U‰QD-e&¡aBWãLSk Í´N™O3v¥ÚùñòÆÇ<»Ì{#0FΙS¡r÷A™Ó›ì˜TÙP¢&@}Ê„Hú` ´¤UÎÐ" %¬±#’)0)š©*:Äh‚jh航(û>~àÐu7Ýú½°Š|{•ûÊå‹û¢7(Á@M‹X 3¥ ‰ ƒ JOMRú@BïV„’Ñ0¬ÏŒ, ‚QM bºc2@Ä”ªƒ€9ªh¨¢(‚Hai@hj`ŒÉû´&;NZz[ócןRáƒ!B:ÎÕ´Ò舑Yµn;œ7ƒ£g ‡ h‚1¥4(¡£¨¡£3† Émè¹VÂ2fÀQ’¨ß™1d bÀÆedbaué©GÞûË37¿%GvåàÛªÜ<ûÌ‹'OU1›1ÔH5vqMÅn’bé†ô`1pšP’Xj”f*&Ä)›ETkç…"$~tÝ„ ¨€šªÕi F’¾@ô¥ d­€¯Áï/ Þ4«™À„éí‚u¦ªX4DVd¤DÀ®B$P åÔܧ˦:R53#«]}„`Ó]M8L‰ P¢y À˜D°*j†¨)©Ù¢ó>„ðÈSû>ðôÓ÷}tÓ[ñÂJHß>å^ ú~éÁËËSm5rçÐ{F55e„6AòF‚˜ ÷ÄÄFB$*Ž@P™©‰†äú•zStÈ£bõÈ$ ˆ€} ÆÄl4£ˆ«Hcº‚¡&ÇÇ¢4ŒënM RÊ»Á0Ú½V-'½2‚#¥Ðd@dä4`ñÀb@DŽP » ‘ÁÐD" ÅZn¬Bhj I  ¦7ôy¥…–Æ:ÐOLÉ@$MD w$…0œ¼töч½ó½ïmŒ½å*DíÛh2såì™§Ÿ>8(Kb朙Øyˆ!p… 0QT!4%d¢:ʈÉÀ‘)UCÏ €æÀ¢£”´ ¨*"ÀH $*²‘˜gUúlCÝ« ¡ Ö`ª¯¤Pg( ÷4zÇ&P`@"@ö‘4Ó'ù¹'"€€¨9“G.ÑYì"˜Xƒ8 ˜¨9@2óMOe l ˆL¢!2f`d&DjÀ Êæý*–ªý²|fÿóó.µ÷¼õÊñÛhîþ̾ÇNÍ]¬$úŒ+•` FD³"Ĥ†„hf&ÃlTPcdÕ@€)Ñ"`¨¡0Ôájrù#¡‹é¼N9Nbl `‰¬&)-9‡ÈÚ †kéºXƒ^jíÌPN¨inh1ANÕT™0HÅœBÔˆÌ"D`D‡ˆQÕÔ]zÇHçŒA$æLŒÀF4aFP‹„Äd¢„h föØïWOœxø¿¼ùÚÎù·V…dŽ¿MÊ=”Å×¾üÕ…^_ÕrÎ’ÅŽ5N£÷.¤„;#k86À ¦9±¤Aš¹4Ÿ0@¨æ,KÉ!ˆ)86³}@Œ¢Ž9F#$«ÈÔÌc J"†h2¤°×û®Ûw£:ÉÀ†‰ ŒfHI#ƒCPIÆ-6”˜ÐȈ ̆³ïÉAe¦2!“½.¦ $1¹‰ MöÄÌ!UfQMÕ4©J¤¶\Ô«|ªÔ„ ITfêH&á0(ª(¦­­)qRt¡!“E$•Z\/¤DÍ1UÀ"1Š¢F53r$ ÂhÁ0)u’¤†i« Kš^BRIÉšf¤\]Å× Š©& ‰£‘Öh°8„¤¢¢) 1jY #*š¥*¢htŠ">ýâáCOì_¿i³óÙ[ Ü__½; ‰%ùRBH˜5òø*^ÈŸ©uSÀoü>|~ßS/ž>Õ/íVÞqj@ÀމA¢ hDO.™%XÁ¡FÄ3U#­9Ž`e°{f$‹Ñ) Œ@ŒÄˆƒ(…y@UG*ÊA•Rn†F44MNÔ”Ñ 9Q©JN¢Wðy˜"ªÆ%ZDóèÌ” 9$VS5r ‹ ‰AÐDÀÐ;"G^³n×UøÚsÏ¿ßþû>ö(÷×™DEÕÔp踴JŠ×Ög}ãMêÁgŸ}þpoPâød Y4˜‚AÃ{ FQ%w¢FHrBQCRÀÌR‹ !ZI‘D$©¯¤îZk—´)¢c"sŠX‰ªCjªÁ<3"bæ1ªI3$bKm–e" * Z´¤ƒACÄ`ʈdÈŽÙ´PEUG)&•ÁPM iÌPMØ\rR-±Œ¢Ìf†ž™bPQõ®Îý jIðŸ$tf€L ”HߢÊ&bD @(Ñ‘+Bº6·Ž_8ÿȃûn¼û®é™o«êëºSU(ÍFMËEeCÞ‚Äðă]œ[ UØ>ݹ™$™c„äDesÄ)s ””ˆrÈ‚9QcC@0e R…(Ñ)a¨Ôƒ1¡(Šó@€Ñ¬Š†&BÞeŒH¾,%ª‘šA1qÈž¢h”M‘Ì#Oè€ ˆ\‹tDäX„hŠ ;"uU:ð*ELäDb ÂľáÌ”ˆ›¥«zF@C#FSĨ ¬LžLЩ§”ÉI45!R@!ðI'ʨ™™2Y…E4rÕ0DÅ(ëzüØÀ Šâñ'ŸüðÑ÷O­Ûð&ÁëëÛ» BB6¦üÛDhxƒ6©=¾o¹Û%Ô·n™Î¢©¢`ôsPE‡„ ƒ(àÍÔ•*°ÌƒEDl D-Kã 63—S@Ì‘' ÊQÑaT"°hfLì0FS3PJJ’"§’”WC d5´J13ïÉåžÀ´Ī"°œ¢X F¢Œ GGÄЛsÀ@àÐ’ãÃ+¥IBdp`Ȫ&èPkæ8*™3BOHbb+%´@+P!WFÑ\-ªxÆ&‰g ‚QUÅÌ£FªåÏiSlbEåäÔ<y2‡bè0UH[XF$0óÄ Q°ªÞAꦓzË ™@”œ'C2K® çŒ%š3dcB0!‚h0*1šW),“M;Öô`#5!F¡’#*:§àYDÉÀÕÀ3CzžE1!DQ4CdDt)QžˆÁ z,#  ²Õ‰éV;ã"„éQÇ!T‚ŒPšU UÁZìŽ[nyó/VÅ^_7SäY>׬’Þˆ—>:¾îö·ÝðÀƒ/ÆAHpDréÚ™19g &UE€£#€,eÁ8TQ0-ŒÀ€ØŒ#Ôé¹JYã‡À *Q¥¤ŸE1t¤e‡hQkxžgˆš tF*˜Qje, 66DQI©¿jèÉê;®%Ä:¸ÃP¡BE¢`ˆ¦Ìh†Ši.BÆT˜ª·¤4”ª ­  ŠÕœ¡IJ±5@„``ˆј¬¨Ä2st¦911³°PTU¯5Þª¼Æ¹RU¥ÆdÖ4ƒÙéé›Þvâ·ô‹–2HU ÀÐ:dÇüºŠÏ™}×LÅÌRÔnRËZ…R³¸^×,oÝrË“£Ÿ.Ë  "b“ê ydÌjÌä2$l°©‘©@²ö3J†ìrÓ¡MDRpäÍÐ(ÌÁ¬L0±ŒÈ‘sPES¼—¢8K+ Hh¡0$/6R 2P#ïÌX !D5&phAÑÈ FHá ˆD ŽI’&ÉÁ @i5G…,#ªÔDU5ZR[´ˆ†ž@¢FÕzkŠ€L¢ÉMŽÐÀ2Æ`Ön¸uõ«—;Ñ*o´eÛú‹2ßYô£Zroˆ°{÷ŽM[¶½æxñ¥3xúég:wvµ×EÑÆÄèøìº»·Ý|Ïí×ìÞ:»~Öûì[ê7ýëZîƒ2FÓ$" J÷,Ðþ`iþâÔÌŸæNu5FÇÜžž~M·lڳ維ÛÖ]^蛂ÕhZ"˜÷¨Q•­20@‡Ô`4³J€rcˆ11€ˆpeF†ˆL "À¨Á ÌH*0#t.Ⴀ̥•$@ö¨Á¼GRš¢'ð¨iºÌă9Ç@Æ1HD"ª@@ÈD½G³h±ªÓÈ¢"H¦M™dB4Dö`9f@  éœUBARéÓR ÃÏ;d54cJšDMÌ3Å•~lÈ’Ÿ„¢'Qd¤Å%¦ÇË+¡ äžï¸íºf{ìµÕúÿý‡ÿåW~óé“GWËnH„µdÐq6öŸÇ·^sí;Þuï;ï¿û–wÏÌ|«¸í×Õ¼WUªŠh¦&ÃÔ9õ5ÆÜ̺ ó'Ï-\¼xxÿ3Ï@ÎUYLÀ¬R 5AÄ`•'0FC‰H¢æÐØ0 ¨( ˜c¬@ë† D4qˆQɱD Ñ(,Dh9+ “Ì´'`=CTS¤œ%8$S¬Ì$Jr¥šzP@CDDdjœh~hD‚Œ„jÈÌ`ȈFŒ9i$BAS̤öU]…&€¢iÀ $qZ¡Šh–øb †@FPzÔB0ªMŒº=»w ––×Fm1‘NÎÏõe Q“Œll´õ¶;ïöYã5ÌÙS§þͯüçƒ/-c5¤p£YÍg®bqeµ¸rðò¡÷ÿÁ'?ùà¯ü•ï¾áº½ÙkúZ¯¹kÔôÊVͰè—Ëçž¿üìcÏ]<òôV˜›¹¦½5J;?5èÍå”>qâÙóÅŸøÉÛ¶s÷7÷Ò}㆛on4ŠQ,5ÖÁLb@T@t9ª¢x¤B@ÑT€Èbˆ¦êˆš²"V`Ê–DU1 Ü¦ùXƒÙ{ˆjÑÀR4ÌÈ”HÐ ZÌÀP0¹b­A <"t  @@!*ªVŠˆÐ†hM4ATM"°£hÈhlД‚¤K§ RBßIª!SU50AAC°fŠZˆ$é’n`DQD â™æ¬*" ’ö|Ö©zK½n)`6Œ(ܽ}Óõ7ÞüÚ æ™ûN_>'©X‘ëÀÌ0]/ªP^¸xâ·ó¿=rô/ÿ•ïýØw~ÇÈkµ„¿žå~ea!JšÈjF"À¹“ ÿÛ?ý¹ssg–.ýÈFÝ8–ù•‰uõïmÂc® –¿ôå/ÎLŒþµ¿÷?LÎþé§U '/ÂÉÑäÖé±uSéqá}~û­wmÙ<}øèÅÔUtƒðÆ2"ÄRL3Ö¨æQUÍ’ÊL )ŠÕkñX{XȰ4LLFö"¢ƒ&oScnbX˜0`¡ (¢‰û¥È`jj͘!$b  CC„ õÅ "$V$Öa{5YÒDÑ@!#FAU5uŒ±Î ÄÒPF# æ‰L-wõ÷Õ@u¨Ð0Õˆh†AM£ZÎHALÌŒ -‘x@;EevÁÀRÄ¥•³YÔÄU4t„·Ý°græ5f6]<{*FeO¨@¦Z3í¯ÆS óL‹²÷Äc^¸p¡êW?úW~™ÿï,w3[™»¢HJETKéB+Ý…G>Öét*Åh£“EW”QM‘Ÿ] «Q¨ ½Ï}áK³ÖýÀ_ýá¼Ù\û^:râ‹¿ûù}ûŸY\YTEŸå7Þvó_ûG?6»©¾ ìÜ}Ûw\䥋éÿVb‹=é „AM B béˆA4U¬Õüéá©ÎH0vîÊ̇‘¨X{SÐXÍ÷Z ƾú³¨m¬5ÞºVª§è5œõ0– Ì^~% 0’•CÁŒ‘´Î°13H(¨ÇP3ÝS6ÕË^3Ô:Ùl-§ÃÖ>¥Öw¦ÑÙ0÷£þª:<ºa µ¶„·µ(ÍßvÏ]y£ýÚ æÒ¥¥²(9£¼Ñ,ú1%+¨i '1®oöFˆª¦gNùÿþ?άŸùÈw|àÿ¦r7ë-­}ò¹çŸ9£¨ˆ&NRžG)‹>¡Ó# á|'探Ãó÷´@m8çç»s¿÷ûŸœžþÀw}ÄyçŽý¥ñ O¼°iРÈL—ª+w<ç†åž7FßvÛ¿ÿ‰‡»R¥ó@ yCÓoK É¢&·Ž¡%ÖÁZŽ©Pò4p‚cÄš³s QëàGMýT4W+ ×ÃVo+‡¼Ó:v£Nǰú_Ÿâ'›¬f 0}jÂßÕ¡ iz %ƒkA4i_<„Â'=B‚F[cÙššA Ø~TGx5f'ýŽ×ÞÑ.¹ÄLíÞ›¯½û]ï{mUÓïw_:}º‘žæíFÞÎD •a Š9¬)…)WHTÕìì©“ŸýÝ?xç=wŒMLýÅ•»ª._\8qàøÁç=ó̳'¿xùL‘áQAõèF˜&ó¼µÌðyƒ2Ø•U°Çé‰V–7"ž;õë¿úßY󾼨;sø‘C-eQUä3C¼pñÒCïÿýÉsÈìÞöö»n¹é÷Ûw1MýS¡ yhˆj@  ”ètµ€k¸.¨"¥ç3!¦LTÀ”r:Ý™°‘¦ ǵ~îé'8üÂÉ ÇBaÊÅ1ƒª_÷Ȉ5¨?Ŭ1Ú Kɉ&~ý/Þ·¸J"EDõðK/þ·ÿò[ë7Ï^û­QC¿*;½A ¢èWUêáV窪h4Zi¹kïÝÿoo ¿ùÜ +!¤‡-Õ•e˜¦j˜š—'>"ÖI‰¼><óÒû%‘%“Ÿ¯N†úŸ&${ÝL¤k¢abeXB¹§³ tØãê0 Œ(½<5 ôNZ#›U33Ç$)ž ½?Sd "*C½ª¿ÔOÀz€Wweuûb)g$s§gš¢bêçSSbuC…˜Ðò À "­;%D`‡D5ˆÛyš™È>rß ?òWþöž[>ŒÄ¯­ÜE£:#•^·DH@Ì Ø<‚£_ÌÌ#!D‰¯ÍcýªÊ=–U¹wê…#Ï>vðСçŸ?qòÊêÜ t›¼Å ²s•1fÀT·´p5é<Y\îfyÑ—ˆ%Àj¯%\ç¹áðB§çÍŒMTÁ @|öèþ_ý…ÿëýìO j$­b%¢õH½Ž¼LTœ7'Þÿ?¹qó5Ÿþ£O<}ðD·[j3T@5ƒ¨d¦±’²’啸º"éÙ¬Xë7qØ;`ý¢ÍŒ@MŒ &²¿\Þl–Ò¿’~RUÓa>lrR§Q«-E&™‚¤¬Ë”—¤Q_Þ¿ÚZòÙPZš:e3µ{$ ü°Á¡ðe·[û_1ÃÃl>´:$u(f©™B44°=;fßñ޽€„™ãí[×mݲÉgÑØù,ó›6ß°~ãõ£ãßR¨A 2îrC4MNY3‰&@AÖš( (Ž(½× €ãÄÄØèØøë\îÕ ¸rêÒá}ì;xð¥ãÇÎ[î/—R†(Ázg“Ž^ìéÿü‹Ÿûã¯|ö‹/Hͯ«ï›ÉTZÓo‡Ým’G!‰’?$ÝfS•¦PŽa¸£ÔÍ Ö‚Ðú=VgÔØ‘®þÿ¦5î½F9%îËr",á•lí-k.ÞˆI¸VÖV?ˆ¯^-­nßa- êïº>ÚSòTÝYæùÖ»îØ¹ë¦$Ëy¬Ýºåæën½ë}ôZOñ?ïãà¾g/t-íê-£¾ ƒ)PB#˜ZJ–’ôT3çyjdÒgùëVîÕ xòs<ð¹¯8zøÌü¹¢Z É¢jƒìÚ6_*ìL/"ZTë¬v‚—Z°ôm5ÝÞ­[»Øë_pl`&*,mõ¤8߉y抢lä çÙ@ Ñ#•eõGŸþã½;·Ä`ˆuÞº¦g:a¿L±¦rÉJ<:±etâÏ5O¬»râl¹~ý1Ÿ‰E¨]ý4ô‘ˆ]M’„zæKkp=¾IM{QÇ*%-ozõr8U4]t¤«{&¨«µÖ£§gÌZÎ)p‚À°“—MpÖŠzXÐ8ìÛ¹Îÿ€44Lg~ªdþq&`Æ"uÛÕpï 3cÛ7Í:4ç¼ÏÆ'Ö¿îµí{øü•‹"¢ÃáOºéÚÕß/@’=×ÌdrDyþ5)¯PîU¿ÿßþÕ/ÿÚ'ÿðRçJ°˜ˆ(é÷Ä|Œ›Û|x¹êeÏfµR…¢ªK?5„²´O]ªªÁhƒ=çKýÒ3FÓtÄäFO*T 12+1ˆ(s4éUË<;?¨*Ó¤Þ«SU Ó™ÓoÞªJb˜šÉ‹AR¦VE­‘Áظ—`½^b9b>ªš#CFöT« TÁhLA€=}S1$¶ñQnx ‰íNˆ+ÁŒlbÜ7 „ÆÌ˜üç.”Q°Õ„ ësfd&Ç$H˜y ¥u‹¸ºW–K‘z0êm½flãú6#2"2;bitzÅñS—¯Ì‘ä` ¸}Çô×];5Ñmf…”+Ë‹ªldùú™-£cÓé%ï›#c“³¾õ⃎˜ TåÉcg{E$&I’€‚áPpuì§Š&\'fÁkÎB{…rŸ?wâ|âìây Žª ¨Ž™ÌQè_ÛÆ#Ëå@Õ±+«€¢Ôh0’•eLiãé‰.*Êõ£Íh¼:(&[®2ˆE$&qì¦çËhˆD Þùv2¾I‚è"VÁÖò¸ÖFß,5ÛÌæç‚èÔäú[nÙtôèÙ¢Š$j`0’ó ;¯EÊNŸ¹t¢X* ¦DÝVN7ŒÜ¸wË5;6g€˜ç™™3«¹ý’s&µXEjú•˃OüѾK «ÌÞýö=·Þy#Sæ3ޱ  úä'93·¸~Ýè÷~ß;'&&Ëʘ°‘ç„\… *ŸùôW½¸yóÖ}ô¾ñÑv—3I,Í9°«0é>zøèñ ç/t½€½nÞ¸öúöj ¡@æ ô®ØY]¹páÂÙ‹—–Î^œŸŸ/=3§—ç.i´§&gg¶nX·nãÔØh³ÕÎêF#†Fúyˆeù-I¸çŽŸùʯ}úô±cY«9Þ™Ù¶aÛî]//9V“ R\2Y`KWX‚zG„ ½Iˆãí|מݯ[¹wºWú±« o2üÚ PVå4J·¢nˆ­‘fU‰ªæy&EY–Êœg¨I)IX"¸Ð«r‡Ó£­"HQr¢èÉ’µˆ‹¢•g ƒ!0U}¡ÔÐ"˜¶`ÖëV QûMŒx{sgNWƒ 9»ï=¼çž‚Hb¯Z¹²tæüÂéS‹ûÎ/÷V¢ª5sœnïÙ1³÷ÆëGÇ6´ZÓÞSYb20ÇN¢SÑlz Bþ±Ë|é‘ËK½éQ~ÿûoÜ{Ã;˜›h޽IâboieP2áÆ™c×’Ë›s>s­Ù1ܽw×±——Wƒ*›ÌÚ™¢#n :ŽYÛdÝwl¹éÆå+WÎ9vò؉‹K ó>øð¡g^¼æÚko¸a÷¶­3&•uŽ!›mMŒo¿éVW…ÎêꕹKsç.ÏÍu»ËËs‹g掞9äÐsî›­V³Ùiû,o·ó©é©¥Å2Ãý7ì)FGG¹ÔË1“'Ì0MsóV$—ÿ‰–úâ‘ã¿ü¿ÿüCÏ=^„(:ÇD®ÉMCwîÒ‘$øµ„ZKOÔz³•ºZ[É"(MMnÜðúî vˆLªJžjF‘jŒÕø(í+1¥ÖÐLc ®åc˲¨§:¼S!!‚o8¿Ü/3ÖñfÞ)ªVÃ:¿ ªãÝhÌãã£>÷f€†}4•(Ìf@D ÓÈ0¥­§Ë+4ï_÷h¿2wiqq!š9‚"6Š_^è>³ÿù3sç—+!3õÞf'³íÛÖ]ݵ³·¶ò)—µb¨˜L@ÈJ´¨1Fu ¹‡(V•zâùÓ?øè…Åó[f›~ß½[wÞì³\-¨R1¨œGvtöÒ|¿ H´qËÆ¤Õ )x8 ‘ˆm˦uÞ»N§sæô¥3“ˆLÐLÀ!3™;å|,óɱÍ×îº}aáü™³GÛwláòÜóæO8ºný–mÛ6]ãµ³“#&$Î+R#_—MMÍNï½éF=‰ƒ+ ç.]¾|åòòÂboa¥[ôËîÂ’©%#1gc­ñvÖl;—créIë}Ɔk’g×öùôädnR)ÌlÙ<»~ÝÌìºmÛ7K¬~ç×ãýWšZR-£E)¡[T!DA4bJv…µ`{K+JÈ…a˜2€(€éj§<ýÒùn-lÓW(÷±‰uë¦ÆÏ^^íT¼# Uƒ°1˜yv`¤ªÄ\U*eGìi¦÷,X…AȺ~´YE\è òo›ÙJå‹+Õ*Âøø(9%jrݧ”¹fE-“×Ú¢¦¡ž˜!`U%À«ý¨ªâÒ¥ólñüÒÂùåS'ξtúÄ\wqúàf§ýömS;¯Ý¼iûöFcCæ *R+(MÀ¢¤=_ÊÓõ¢Ñ@íÏ<òÂãöu+o»uêî;ß5½~A3‰Ê"à¥/½pTUZ¹¿fû†l4sæ¬DC”äW%sYÞlM6r·Ò)Ïž;{Ç-»óÜAÆF²²(HÑå™FUèœKAR3뮙ݶkÇÞç>pðäÜ¥ÅGÎñÐC×Ýxó7_³n9ÞÚ´c[P³b°TôWû+..,,.öûe·Sö‹X•ÁB¯·2¨oÒŽRnZBc43©@+H[ G”±oúæLsÄçÙjÕTÇÅ@»¨Úé•1 $oTCt1 Š0mÁÌ¥U&ý‡‰¨Š*ÂÙù+¿÷Éß¿ï#÷ŽO¼å>>³eûÖ©“gæb°J”Œ™©Ñr£·60馕X£ÕP‘¨!Ö3%0d4dtLÍ,GuVJÀ8;ѸijÌ“XTi6Çû4&TòìZŽ+åXho«`–t\”6!T¯¾Ø«~qôѧýäW=ýüé×WŠPF“ŒaÓ†|Ïž »·o™™Ýšµ&‘}ÆYˆ*ѨYÃ+€Cð¤f™€…ªç‰]cdP ¨´ÞBøÚWž~æ¥g¾üлwß~׎f„› )K%ÆÌˆ,/ö——@mçîõ3Öys‰Ð‘å¨Be¨rG¨Á!µ›+«ƒÅ…ù2—;`¥8—²V&ˆ”C,$ª";¢´`š™Ýý®ÉͷݰxøØóO?wäÜ™ÎüÜ™'–çÏ_ºþÞ»oÙsíú·4F&C""l¶ÚUcðY#VežONmÛʰ{×5kT¢aPVe"XMOíÙ¹@ ˜eÎi,Á¹xñȉ‡ÿhßW’„H0e·Ìõ›9O´Çš­˜:BßÌT!F jeU™¨Q­ùE€˜‚6餌YH¤UINðD+ަGÛ£c¯O3CävŒÏŸºÔ\ ƒL3QNVÍ•2âýd.µ¼é‹~Q *fç8ÃLE%QŠA‚J4Ä3ÌŽ5®Ÿš™pøì|2×nGÄê1;"òÞ\YU‹ËƒÕ^1( ÑØjg˜2Öû ˆH_÷¦*U\½¼xæØ©Ç~|ÿþƒº°2? A²·®ÏÞvóž;·¯[¿=Ë'ˆòr #¢ÄŽ3pÊX‚åä‚E@ʼn56ÈΟœà˹tjt>úþ{¶í½©‘£Å<ËBT©LL-ˉ);øÌá¥N·ÑÌn»ãm¹oQæ] ]ÇNF›Þ±+¢f­fsd h¹ªJ@i80 öžMÐ祔ØòθárÅ(*h H À~ÝôæwNn¸qïÞgØ·ÿÄÂüàô‘g—Ο:vÃMï}ï½£#ìÉ#“©!ÄvËU%ƪˆè½ËœóŠ09’WƒÈ jêšöM·Þ¾çº[þÔRIªê©O}ñ‘ßûÒSÇ/õ…‚:çØ±KÓC±"Èå¥%ßiŒŽ6'FÛ9²çW{!†DGHiˆ¨–´¤¡OƒZQÕRÓZºÞ.3SÓ»¼âÞòêèÔëqºƒiFÙæ©‰¹~¿ŠZ©$¤}eøb®¨v49VP¶Ò&‘8(ªtàš%3DÚr4N7³‰Ìïk>1ß5O®ÕjfÍhƩЉ=úPÅå~¿Û Ê2†*š (ø¤i*Q¢Uƒ‚üÙ9W÷ââ…ãç=óü3GzéÈ™ËçV¢Ï`vC¶sûôîn¸þÆkvÞ¶iËÍ>éu{± ”s¯³Zô:ƒRDDÊBÀTL«XT!ŠÄ²,EÙú¼!†GžûâW:¿piëú懿ãÞ¯»])oTýÒy”ÖdÛBQ"àÊÒò ÇèŽ-÷\³m¤=BÄÞÑX³ÑA¤~¥_¼B¹³ÏÚ3#Só“ׄ²Ó Ký~¬b£‘ûF“Yʪx©' °ÉÜ­DÎZYÄ3• ¢NxZ(dû-VšnÈÜå(û»%Ž6[y2£#&ãþ ì E±2èe,E…’—ˆ9™PíOìVÌ´´áÜ]BìÎ/x?ÿÐ#O=qbîü|oY©j4púæ½÷lºñÆíÛwìÞsÝ]ëfwŒŽor®É.[»Â¦K¿ªšŠHrcƒˆ€™ª”UªPUe¯»Z–å¥ó:«+û9ôù¾|euáΛ§?þñmØt]«Ñ"G¤bHê˜ÔXU9X]øò¾WºÝÜ»|è÷¾ó]ã“fÓû 9ï™]оPÓ~gµ¬VüêÁ²Œó——Æïn¯›Y¿iË–Fs4of­V›]î³¼Q៼Œ›sg¨ÈmwÝÏ»¾óÝïùäç>÷ùG?yþÒ‰…Ï_5óç•þ+3"óæX>>rifljÝÄJ?VeˆÄHHyfì["q¥,CŒ<2ž9EFÎ,F,ÄNv¤2`G݈£#£”å-dŽQ«`ƒ~¿,ÊÞ cŒÍŒÙ%d"Õ߈µôyH¿FQ鬮¬ÎÏŸ;|æá/>þø¾'Ÿ;~äÊê\ž‡­[FÞuÛ®[oÚuÝ wÍÎnZ¿é†¼1é|ãÏq»â°y# ú³¦÷6Œ_-'Õm×,þÖÏÿúg¿ðàboá£ïßó×üG÷ÞrÖɳ&qÚ]"\ïbUöïÛwèЯ‹ÅÛ7ÿàüÕk¯»åK§6·FÞõîmÙü›ÇŽ]>qò\{lêÎwÜ×ù¦;Tbæõ›ö~ÿ÷ýÃûÞùá¯>ôÉÏ=ðÕ§Ÿ~êÒ‡¾5Â(»|Ãæ[?þƒ×àýæ™/î ŸêÉã‡Ï9wùÒÑN¿ãî[ßûñ]yž¿6™WÃòjùåGþ×ñ¯N\xéãßuó?þŸvÇu÷à7j—.^ü7ÿêÿþ£7ÝôŽÍÛïv¾ñ†F•›Ùñg^ø¥ÿóß=uô»ÞwËßÿéŸÝ²óm¯æ³ž|èÑCÇy†ÿ¥÷ßrçý¯ò1rϽïÛ¹ã7_|ñÂÉ'Ž;ñŽÙÙ×éÅ#£o¾ýûö\ÿÁ}ð‘Ï~á¿ðù'¿øâãÏ?úŽy÷»ïºã£ïŸ¾f+¿jËÜ…‹Õ ehåÞ‘Å2äY£>`r"õ™•!EK;r"BÇRcíÆ z+ ÉÉoH < †„„dõ1¥wÖõäÀ{'CŒF›Ôr8s™Ñb?.ý—.Ÿê}âw[Xýø?û‡cõÿʧ{wþÂs=ZŒÕ5€U§S–EöI¶W7T쓜˜€ˆ˜=…2v»ÅòJ¯×í–¡‹µÂ«ö÷ !!¢%Ã@²cÊD©«`€Dä½1S $ÂúqÐj5ú§æ£ßýÓ;ˆýZëpùÄÙõÏÿå#ž¸û®kþÙ?ÿ_{ݯæ+.]ºüïþí/:ùÒuÛ7ýÌÿü¿¬{ÕÑE## óÇ÷í{±¨ª™õëî½çn¤×“Hå\¾nöÚÛo}×½wߨ§æÏ>}äØ/~âùÞÉ )k6|#ÿ³^€¿úÅz¼(C¬Ä‰&à|ž{rÎ#ùœ}îœcFD—.Hˆ*©BtŒëFF''FKÐbŽ2¼P!®™SU@ÒÒˆ) 0c3óy#€ª ¢&Q@ÐçÔ-uPi¡Ĉ@,jUÝ~Ï]³ë×=pcllrãèáWš­ LF[VæúU,ú!sÞ;DOŽ Õ0­B(ƒV%DQÚ 7t¥Uí7 WÍ›õ ÍD’ :™w½¢&çjýƒ8°ª_äí&¼Áå`ðßÿÓ¯}í¹Ço¿iãÏüÓŸ¹öú·¿ÊæçÙG÷=yð€gü¾ï¹˵ßÚùüCþ®O|òËgO->ûøÓ—¯\Ù¸aÃëûM!R«=uýMÚ±óÞïüðãŸùÌï?üðþϼôȃGìþüwí½þöwßvÃý÷LnÝòuÚú Ϥ_à †r9°sËÝ~¾²:3>996’y"€¨ê@B0K°äªŒeY …Ê2Ÿ­kçŽWWûå ª}Ÿh–Zÿ¡ª?¹æ¦™2ïØgФ1z´¢ë3¼ùºϾx¾W ´nüQT–Bõê}æO÷¼9ÚéžzúɃݲb§£ö )«¨bA,‹jeÔ^¿èõ½¢¡’Ô†wk"òÐÿžÔ൯€`8æ‚%“¡-y RÛÂHjéÝ¡Ã4”(Ž^>þô±î…y-ªöÄ{÷FĤ¨ÈçÓÿí7~}lý?þÑOÜñ®ïz•ƒ•¹+ÿîßþâ³Çß°cý?ùý?ǧ6þÙ^þü<1±îòÅ—ö?{¸ê—×_¿{מ½oЛÙù|výÎÛn{Ç=wß´kw«´åƒN>qôÅgž:tùÀI:5;ãòì//xáñGŸ.‹`*¢E¢Æ*V˽îÂj§ß9  4‘Ð9ŽÑÊ2.­vzƒ>±"R§7Xîô«²òäŒH‡^ÔT)HˆÈTÍŒ™¸^ê ‚)*´sT¢f³cc×lÛuüì…Á ¤Ï%&ÇÜȲwÜ÷λv½ÓÝùüÆ;ïÛö•÷=9oÚ&ÄÉFs>ë-÷­(JH¹Éf’,kµ,©Ä‡N„¡¡©«ª¡&X RŠÄ —éÉÌjò?j{K‚Š4Ÿ©Ñ”ž?÷â…åózh¢9¹ijóÍ·\Ã7^{Óî™m¿ÅGÿ\pðáÇëWÿ+äåßúëßwÏøÕ|üì~úɦ‡û¡o¼æÆW<`¿Î§çöG¾ã#Ÿûã¯-\\~ú¡ÇßýÞ÷´GÆÞ¸'X{djï ÷ïÚó®}ìʳÏ|á«_ûêCøoO~î Ï=ýŽ=wÜ{×wþÀ7íÜöò»l( ïV‡ÖAPK@o3ëW±Wö®tˆsŸiš­YTS@%@P &•ˆÅbPÁb'ébR[‹h ©MW‘a¶ÝÂÓ89š{ç–Š¨ãíVQ¢H:]SR_šÇø Nwh¶§@ç÷ï{v¥sGV,¬ôB )ZSÌ1ÖL^OM}ËÚάö ½Ò~ 1á •…FZÜn6K³ÄÍ×dËI×òôç£,s+ƒÕ‹ËçŸ;rè‘Gž|âKúÚÁîÜŠEiŽ´}#{MúúõÍ>÷ ÿû¿=vùô_þáû¾ç‡²Ñzµ7åÊÏýÜÏ?}âï¾ñïþÔ?k޾ÈÿÄäÌ©s/<ûì‘•¹¥ugvïÝKDohÛFÄycìš·½ý®÷½ëžÛ&§Êc—OX\>öسüû>÷Ù® Š*„‡~Ãá}ˆVÐJcÔ –Ö¨¦ªeŒDUrãC²/¥ˆË„Œ_3ž¯íÐê¹ãÚBŸîr»7Îø¦3Ɔw{g6gŽÎ,\U&n73bÓ‘fãýxÿ5»ö|¯*»üÖ»?zë|áKǸÀ<§¦Ïš¬ !hÌD!‘‚êžuèNozDFd„ˆ¦J8\hŠ€nºRdpúT›ÏvlXwz®£!UTu¨2aACˆ‰}ëºÕòñù¥Ã>°ïɱÉk7^»kמ;ï»óÚvŒ­›pÙ7WúK—/ÿÆÿñK‡^zþ¾ìýžý‡í‰ob<òÄW=pèùv+ûþïä†×˜žÞj}÷G¿ëËŸÿÚ‰K>ñÛŸºõö[vìÜØlMì¹á=×\{çÎ=¿ö¯ÿõ¯iñ¡#uôÂê•Õ~wj|¬ÙjŠ Ô†6ï´m#®°µÖ%Ýg Á2bGTim+LÿœäjâK-.0»Ú÷YŠ?€DÈ#䨅™©ñ‘™6#È †-›&ûeÕ`WÒéѤ‘g‘æ7>Ý Ñ\~âѧ;Ý@Ä‚Ø-Ê¢ªA2©a!¢ú\·Ú“¾q¬ß¡5ãª, ¯MÆDC‡gb‰ ÂôxsûÆYäÆÂJÇÐ4ЦV¦^@Ôžbðy–·ò¤ùÇ”æ…P‰TRu‹Õs‹ç>øèC>ö¥GNì?Š€Šy#s™ÿ†]~(Š?üO¿ñ{Ÿùôõ·¬û{?ù7n½^õÅ`áÒ¥_úùøøK÷¼}÷ßü»?Ýh¾æëäøØø±Óû_|þôòÒꆙ™o¹‰ƒ¿ t.Û¶uÏÌdXí/>;ß/ÝþüÙK'NÌéT½h±[T!ˆ2…*¨)AÍ¡¡aE çŽ\ãt“ŽžÐbê®Ò›ˆàª­|«ZÓ»ãZÁ@¢†¨—:óóËKK½þj}‘G ¹±1:–.öU „°yzòßñ†<î¯÷Dâ›n~ïÛïüÒ¿ü â¼é°Þx7A˜Þ¾ ú”‚ÇÞûá[W ^fŒ7õ};õÀyhfÜȺ‰öúuë<ùÊ$±Çc4r»j0¢¡y„­mWõËŒ¨ Ž(ZÕ¨Û,Ð¥ÁÂüéù#^üÌ£¼¾=sÝö·¾íŽo¿yÓu[›ã#äø•¬-ñáßÿìg>ù‰‰ îÇÿÖߺfÏÛ_ý ³ ~ùçþãW}v_ëÄô¦o¥âFÇg¾÷cßýÔc/ž9µôÉßþÔúõÞyÿ}ãQÆØ½w~ï™}K‡ZÔb–5Ä š(‚§¥Þ€ ”dóä«3r\ãIÕȈÚjœÄŽÆDMF[ ˜VÐzV.uXôèe …«|†t‘5©$V±êšï¯"¤‡\ 'ˆ*£­ŒsbÿUîà³v9¸ðüs/ö:âvUoP©j}ÈÚ°wInZ­ß‘5±%ñ´ð*†ßR@³Ñ¾ùÆÉwß³·è‚ÏÝÆÙY‡v )ŠÁTFý2JBÙšyßR?”©ÈÃFŒ3rÕ•(U0"@Bd²ûb:ˆåRoù¥K§ö=³ÿ±¯>üÜO]>r¼·ÜÍFÛ#c#/¿§>ýÙ/ýê/ÿÊ¢.üøOüØ»Þÿñoj×øÄƒý‹ýozE€ö^¿çüз¨\˜Ý²Ú=±ÿK/Í=·ï`¯[Þ|ëÞ¼Ñü‹)÷ãϾðkÿǯþÑ_!ìrD A‰LM̪(%¥Ø#Xª5$’wD‡ kdv”e4ÑnM´ý Sö£ ÑéŽZ Ò k ®]í‰kªY]ÿkÓyÃÔ «IЈ6Ûíþ lølldäÞ÷¼ûší;¿ñéYÞ¼ñ¶÷ÜûîýŸüÔ³R@Tr×RÏ]_ÌŠêÖ>½D«çë”JÕ4ËlÛn½fÇÎ]Ò›xüñÃÝB&G¦bIJ‹ÕµYl7}*Q1Áš<š¾5"4ÆŽeЋËE8Þô3žoj¸zÕRß5yƒÌŒ@,ž˜¡ÆŠNy¶sù‰ÓèÓ°kû®þsÿËÖíu‡ýÜù•_øOÇWÎÿøßøKùKý7A2‰!|ú“ŸZíõÉ6Í´¾õ‚kµ'ÿÒGþòïý÷¯:;wââÉßÿßÞµ{ë÷þðüÔú‡ÿÿúWžyieâ7%" çÌzepQEŒRËJiúD¤f˜n¡h< !:£éfsEdÙ,Ñ’ÑëÌBLt'DP%«agC|1@ ÷ÆÄ1LɸCþ!`Te\)—€Ð‚Å—÷¢ßøôÚ´õ†wÜ÷þgŸ>~â\7éZ kѤ†2$™ƒ OõÀ‚@Q@3Ó“~Ïu®Û½{fvk³=µ|bõ¡ïT ãÍvU©†þž¦ž ÕÙ.œë•è’jHÓn†Ç„©!j{r$ e¨æ‹p¥W]ö4Ñp³M:Ö°6óŒTˆÍÈ¡‰@î³ j€Ñb=3}éüó«‹‹°}‡©{ê™ÿë—~ùøò©þ‘w÷ÇÿÆ7Ë矻pæéýÏŠ*6¼¿í¶·¿.e7»iç¦ÍOŸ»"ªç®\üíßú½[îºyçνo\¡›ÙÁ‡ù¹ù‹/]8ª9y`3lç`©Þq¯,KQL‘)VëÐM•9 ¾H!'<šªj„:ëÀ‘Ñ–WŠÑQBÊ–;A£™¢Õ[õšmI”"`@†£l"С+ þÔ“Z&I³c5Âc9˜o}åž7Ú×ÝðÎ{ÞýÄéßz¥f.¦¯‘ú‹:˜7Áê.kˆéV†õÓþ†ëÖmÛ¶eÃÆ-ÍÑõˆ9)_8<÷Õ‡ÄÕãcX•#¾¸Ts}:Ó @2»a¼ìc¯%Ýt‡«eV3‹+åÞ ó„Yž4šâ\·?ÜØtç}v-θ¦M«Z¥dŒä„š9Ÿç¡™ž?yæW~ñ?={îðÇ>zûÇôŽMoùf«äØÉãg.Ï©*´'Ƨ^—⛟¾ãŽ=Ÿ?º²Ú+cØÿܳŸùÔçþÞ?ØÁνîqW©Ö<õÔ¿û¹_uöòÒJwi¥»¼T!†Rc©ö²Ã…Œ"Ô0€VïºãúFkòåÑe¯¶ÜÙùÝ7ÞýÁÝÿľ3W‚®…¸˜ÉÌ”ÛvÍÔî½;¶mÚîü˜kŽ’óL"“ÅJ=û²'_ûⓇŽäFî –»=(z›§ϬÄRÂH£¹ÒëHDÍžŠª !F:: ~+¯túf]bØ0ÖpËUÃë‚(0³W,¨Hꊘ÷Ž1MèJg0·¼¤bæ^Uí;óâ{îÝòÓÿøŸî¾ùÏ^º|öЉÃhâØnÛym(XLM…H£š:3NNÏðT@¨7âª:’ûS½ÅA0ˆå±sç÷}ñ«sÎ÷ßúP…jnuÍ2ïwmZßí1aµHØðlAÌ¥¢ŠªzbBŒ€Ì"ÁÌ!mhO·cg._êÇòéGñÒ¼ø±ŸúãÓë^å¯Xb\^šo‘®ݪ*« “ã#Mï™2òÁ9§I%µ5c-'ÄЉˆL-…T!שý¨CŒÔ4˜>uêØåÕÕ^¯;Õ½ùžw´Ú#µZsd¢5“Ó6n±P7õ;ýþj¯×[\ºÒ]]^Yžï¬®vËÝÕ•NwÐE¬Ê2DÐØíô˜@z|ëÆuwÜþžÙ ›ÝpÂv¥Óÿ&æÊSÞùÎ}äû>óÅçz}iµhӦѽ;¯Ùµ{ÇäÔfÀ‹F#D#P1"!ºÜKáË_zôÅ“‡óf‰T5ƒ;×ù‹¥®–ÅäØè HYUÜY´Xhk¬Ñï ¤?)¨Bmç<Ñn ¯ô;Ìšû¬_FDX3mne¹ÏÅ,sÄä\ÃQ}qZìõ¯,-W±bv΀Ý~óúŸþ'ÿÓž[?øuÖIE·[õ‚0Ùh4çÊy4ȳVM_”%@…èÀA¨ à36ï Éõ{„Ç›yî³~T¿öÈÇŸ?±ûm»R¹“óȾRm“Ct¥ôª;ÇÙĺõå çÌT£÷­Xt• Ô;ïUÕ»|~qÎbJ#å`¤å™A:ðä#Ïíߺmó{?þ}¯¾Ü­|d¤ºcwûóçûÏ®”g–æVŠÁ¦é™ñ‘ˆéˆã‘vÞíºçÐp…>œÚPÒWsÁ‡ã–pth$be%fzìÊùå¯væ.Î}Ç,Þ÷Ñû'×Íþ©ÍC–7³¼969kfÛ%–å ß]é./Ewey±ÓëW¡ Ac R‰¤¹‰Q£Ùœ™Ý´}çu/—}厈›¶]ÿ7â'oºõSs—–Z#Óccë‰F‚h–·” Û­VÞh†P…P…PVU¥ªs§ç¿ôùÇÎΟoæÞg¢u‹ &%ð¹N‰„àXŠ8s,:èõ±ÑÈšÁ‹TASF38"weµŒZžÇ[cKýM3fvÔÎ2ËŠéÿÂ* A;o51s@hj «ýù¥å²*¼gï ·ï˜þ©ÿé\ÇG¾þ”ãò¥ Ý~ˆ€ì}¡R%£0Ê“­Ñ1µ™@©  {c ËúÕÀ¤‘AÕØˆl¹×Y­ú–gêùz³ÙÈ=(!2¢” @±+›Ž\ž£ˆ4!0eUÙ) )Õ‚zã˜1s:ˆ€æ.~éðM·Þò*¿ÝóÇ6.\Ù25²eÄ}ù|ï¹òr¥¬Šõc“³S“œ;E?ÒÍÝbT0³!S h¸ðáÀØðªpц '&¢(’¦ò®«G<ÿËósÇOðGþÒ¶={è•"õ‘o9ßjMÏnQ UÑë­ö»å¥…«þ`0(J“@äZcë¦g6mÞ62:ñòÁÓ7'ÃðYcï ïmn\¸t1ŠrĤh4ڭёё±±‰uÍÖH(‹ËË—NÍ_¾ôÔ×^üÌgº´tÑù̈Ò§ Õ$ÓåÁª<ó”Ń"fy¦ZUå0vFq-CDM+$›m9È—{ƒ*T­<«¢N¶[&´©á@ýb¿ÛÎ}žg„iÿ ó«½¹¥Å¢dgyF@Þáý÷½ë¶»>öõkÝÌ.^Y*+AÀœÐÄÈÐ ÑÕr¹êšÄèØ+‹Ä !z”µz¡a9ô˨©#TQBÓtS]éÃu}kdt"- •Ø[T‹P(U2ò°2u,ÏÅ7˪‚’5*+D4HváÔ3÷Å™“G¿ }¿U½PäÝrÆùØ<º«í?}aðüjyzqnµ,6MO¯›m,í¢X%¨¨ °6øª»,õ$¤½˜¥ Ì­S¢|ÎÈH/žûµOþáÉsç¾çÇ~ø¶wÞ•}]I_âz3;Ÿå­‘q›µÍÁL$VeQ…Ò»¬ÑqÎÿ))á7ŸÍDì¶m¿qËÖ½¨¦¦ `Îý @–7 oŒ¾ôì™OýÑ—®¬^i¶š)PÀVƒv¥BPÏ™;ƒ ²<ˆ!D2ŒJö£„gA^XW˜l¢•¢±£Ñ±±F,wŒàCWÅ⺉™ÜgA$^Yí_\X*Bá½Ëó¼0)ðâ3ä¹Ï3F&$U.8‹Kìб¦F#€ØŒ³Ü¥yjœ‹[õ°6ê5 óÅ+/^¼ûìË ÷xqµñšÝß»`4ŠL|+Äëä²v]ëúé0ÙHfí¹vSÍëÁpP¤–Ëž#NQŸ%,R<°¦ÊÍ/cTh ‘J +Pˆ01$™c`"ìö÷·skó‡üÃ~ףƘ:ÜÙû_ùÿùßý—_´’ëPkE¤ˆ‘Kãp1JÕ¢h2ÉÏÝ-m…¤ö n4ëc˜øÜ2)RF1ˆ0SÙÄü¦ì”sÀl‘¤3S;ÜîÜYS;ƒÉçºIT ›­z-ª!"’|·;MÒ(¤v³…†« ÒÜÜRÿ;Eãao§7O¨€€H’Úq’°H«ffZ F ñ8§CÇE+Š:íº"bT½þh’¥Ž]'®Õ––M‘E¹s•:à%5™EZ‰AâQ2Û h¡„tÜ6šwÜO?ŠBL 0d굚ÛOÆlrÓB›Jo4‰Z5ÒHe®ÜÝßÛÜX¿ûì}/+Ü;+Ç?ð£FÿB÷ÓOÚ„Á+Il:I `«*²²äÎmºƒ4­Åq;j&&ϳ” ®È"å´‘¹œUÕ*€ ‘RJm¨°^kc ˜ä9ŠkÇš9q6yâ OL“Ioôæw<ÖnunÜpïuw~û?ÕOQ)!p^C„PXå^›‘f3è÷üV"±òK!õ Pm™Œ&YîlQ~5þBî†Sf‚†^šm>°ØÙÏm7 գ噭Bq™¹b»;ŒÆQíV= R¥É ‘Š1¾Œ]vç%‘˜H¥y×JrËÉŽbÙÞ™XQ„yî¼$·œh Ãå«ÃÂZ†E–w^vN¶6{Î9ñKˆ³8ç½óJ+ФE@ÄOØY–<ÏVZùÖÌÖÎ^w<®5Dqù¤ÕW¢Ù«ÉÎ^1ˆ!{ŸµÂF‹›Å~wÔ=³Ú¸²«ÃIš^xþ¼óeê÷ôüч✻8ûó¿óÞ,<@ˆ¨æSnŸ’¤EZ¸<ÐA‡µ¸QP^zX³ÿ¦ñ]e6Um"0[/Þ;¥Ð(œ âÔA¶Ø!â( PÚ9N‹ìÏŸûóû¯Çƒñäûàû¢(ºQow)&i×y?™$6wµZ¤B€,¨‘Á±°C:nšÝIÞ´² ¸cÐŒ_$œX—$¹+Üç€ÓYqÉv¤È˜sñ­sõï1.RÀ¹™öl³atX8/Ìi^ôG£áhìÔbаœ3•ù.òÊ\ôr”½î~w0aÁHĘ"õY–¸ÁŽëwÆÉj+U›¸áp\\¹\xç{餇ˆd…ãìÜ f£c«ÅßNÌB½A/ËÒz£ãd\Vtyî8@àùݶ¶C’•¹¶F• s wFÝí^W)YéDšR§0 7‡Ýu¿)µÜ^ ½Ò¤œ8ïüÆÖÎ+Z³¯/Üvü½ÿ2>þ+ûŸüÕáSû蜯ø±À T:F.·“"CT„³ŽÙzÏ(\¦hYD`/<ùGÊ,DA/q›/Ôqm&"5¢F _Ð À“ §6þÅçÿûüå•Vóíïï î®°¶`ÏâÙÞçΆa›0Žu U $ÏÙÒ­8ÖŠÆÃtœÆP÷4_7@á×T¨ ïŽmž;-œYiŠ4Z†»á p~kr%óBPÌ¡Zݘš0fÖŠõ£Ìî&½Ñ(4ÐnÖuh `UZ7 ·êá¯{ˆ^ÆRa1äã1)Ô^EuŽ¢äJrU3.-4!µêÍÔý¢‡ ‡ë­FQT€õN0I qy¡ÙŠZ½dJƒ FœŒ’ápX†ûlÊìóÙ¨åZmÛl:Æ16¡sÞ ¬¶;¶ÓB 8w¡1iÎH0WïÌÖÛÌì2 Xó¢Pt®w:ç_\O&£ZýÈëÍå#¯ûHsåäîg~yôOO.yÐ" ¸ÄœRy_3 2diFDŠ”VB@g‰%Ÿb¡²úDf!ÅŠt¨”f¼:ÎpTSÃÍ î¼8iŒ}DD¹8–fl<À…Ëç>ñŸþÛ­÷ž=vòÄîA@L­,}áÅ¥>ËóQJ‘ Ñ&0AhzjÆA=ŠÓIú\bÃIÚVØuŒ@  'ÎϪ½È² Ðì{ynTL|! ÃP7ëa-ŽQ„2ë•’±ÍöF“ÁpˆÄõ¸&@Ö²(ÄÒš„Xü}ßu÷í÷>ôrZ]—/eֆТÀAdÂÕÖ’²6«×E¢ו9Ô\tD6ŸÔB]x/‘6a<—) ƺñȾxQ…Àž¤ÙA&QÞîLdÉ€SãA>Î'„Òi¶:í†A°úÝtœ „m³Y_˜i ïwÇI1ନÏϵÃ@§Ö*¥E–åò… ÛÛ›ÇO¼2Õ¬  'ßÑX<»qê¿nâ7®|f#/U§T:z•KŽ45§Favĉ´6" Ñy7Æ–)¬¥ˆäÎf‚€¸0W{û#÷Ý2wä Ož{züÌéEÈ<­ïÙTd¶‰6à9³î©‹ç.ž{æ† ÷xíðÒŸÜ`W²k¹ôafï ¢LEAP3Fk&ŠšQѰY–\u.Gð–wÆ™îZïËØ")@D*ˆt¨ÀDÊSæ9>Ï‘!)\o4ŒÇ€R¯Õ”6$"¢J) ÛÂ1ÃÚjë½ïû¾¨ö²  ­½íÒñ©aŒõ~œg{ƒ¡u–|{v¦å“Ôníw:i‡ÍN« ÀVüN¿Ú‹Œ"žc ¦RÛ#"ÈžÝÔ¥òÌ"ƒÎò„UrêØLšƒAâ}„a2I ]k¡u;Ý"Ë|=4yV8ŸZ]­…úòÆNo§ Z3*Rìíx<õ»ß’zPÕZ‡<üpñއþ|ñÙ/=y%™ØRÔP6S}ɶžŠì˶ •–XZ#8æé°€ ”8WY[϶‚÷½ùÁÕÎé?ùüž\?Ÿ³{q)ŠÍB9ܱóì½dùÕÍÝ4™2 «aøtõÆXJ$fï³))mTEAÖMd”i€Xïs޽c_Î:«½!‚è ‘*`aôŠ´Bëm4ŽÆ ®‡Z0 ‚c/ ¾Þ>ü#ï?ûÚG_¦Üaoghh ™D’¥ÃÑx¾S;¶¸ÔïMÖ÷÷[M! I’-Í6o?z¼»Ýúê•Z½jJÆI#Šo]=‘dÙ ëûi&ˆa@YáÊ”–Qù)e A‰ˆ€$V”s™ÍÒ±Ýq6sùĦ³³Î‹¶àŠÄío:Ïn”OÚºPìD¬+.^ÙB¡œÓ•v»×Òþ° $I¾»Ó©]Ô+»¼Âæ‰3ßýã§}Ë׿ükŸüÅßüÝ?½ryȾ€–Ûâ¶K{rBª4’ ÒøYxP î9sj9^ý—¿xqxU`X±¹zA'–Å»,·ÖZ"P ·67nÐpoµæ—çg5©ÊsD(`ðÌJÚ±°ó®(Ü$ÍeÂ(ŠŒ¦€HD‰gR†Ê²‘JF*M„BŠˆJÁ¯±¶%Ù`’xqqh£…H°\Ì%çK xï{ÞðÝïþA¼,-i–Œ¶7¶D¡4"H8+¼ÛÜìïìd¹Íš5rŽ'.Ûºšnl¥¹Í´*B˜ET9øn·¿µ;öÚðÁ!f刊€@\`hºG`ªF¤g%ÔlÔ¸AÑ%•¹F¬#vX7qÑÎS;Q"ËÍN=®±·Í8d=—‰AX4³ºV‹t°YjG ¡…$Iž=wþÑ·É·ì+ˆHaÔ8s÷——œºíW?ñ[¿ó¥Ï_̧„AJ^—hÈÒ”ñ@_*Púf)‚zo#Ȳ¹‘ü™<•ñxm±5È"GÔ¡`«Ÿö’Ô:Ÿe™g¯M`Éé·ü½îc¦öLGkUI µBA­À{W^cå&Œó–Å[çrgÇ„Z«À"¥‘Fñ ¼-WŒ„”*1¶  ”Q¹³½aµZ)ã½h…"¶ð\™¯ò÷¼ë¡Çì§;ÿ·iã_söv6/owMÊ™†á¬=ט$ KÑÒá|³c™=p»Ù%^ÒÒ3µ„2ßn-©X탙z3n6üdÌ–˜+iïTûvøð/`½×¤”1õ 5ñ˜Zˆ½“ 0ËzÞ4.&¨”CD…4ĹR›s_7ù|”8H£uEáÝúú‹Ìü*}Èhnéø{¾ç#·ÝvöŸü¥OýÞÖ×'Þ ‚000‹ARTU§%=Ê•ÓUP°V‹ È3UÔÛõ ¢CQ=ë»ç¯n%iær›d‹WDÑFkfxö™ ;ÛW—–߈áNA€ Á—þâ+ÿ? P,à½Ti à@Ê)²”™ÖÚhc´"-BJyò U'*ƒ¤"Òyîãd03ÛZh”2HŠJ gœ’nü›ºý<þ“K«'_þ)lÞX€ ø±åD±Ž€1¢MÈ΂‡XQ8oQŠÐ„Ì^ )Ð-ìhϬ¼wÌŠ„Ê5*`m•»ßqûí Ekdëuùî`”¹L<7LX ÃPå^ö†£A:°( sA¡‚Ñ$}QÁÒøùÙ9ÒJóö¸±¾5™ŒÚí™Wù±"b½5wöì›WWN½áµŸþ¥_ûÏýÉ¹É a Ð¥!‡gç°2ɨDNX²gDX¼°¦©-ú.ì¨ÕÅùZ^¸Ô}nëro’$Yf½cfc("å™'ã¼7Ú!1™€åÙ…zDû ¢„ËŽ­"$`"D!`*]Ù³ïØ)Ÿ!‘Â’ÞŒ2 ‘Ö:Pd´Ê-ÆI4öÞFµ@‘ÆÊ¦øî²xàûï^ûèG?zâôÙW¤hΓ4OÊVcÈNŠýá¨ð) hQJÍÇaÀÀÃqÒOú¥¾aηãZ ’¼è%=ŠcàAºØì ‘[Ú'–!@ÓúÞx‘¼`2XS´kY¼?±²^ÝïõÆÉ\§%Þe6;uhm6Š×wvú£d. 5R’¥‘ªnêAw¯»_䩔ϭRTz`\¸pioo÷Õ‡ûÁ¾ÃâʉGßö¡S·Üÿ©ßÿõßû½Oõ©,q $4õ9ÇejSù@ð"E!/ì•Þþp’,\Ú C3pãQQdYî½B£I‘ÒHÞI–Y¥äÑ7Ý;¿¸zƒ†ûìÜB½–îbB$ ÄàË%¯ <%åó‘xêA"^ÊeѲÿŒˆŠA uŽHJ+AÌsçIù“4%‰ó.®imt¹Y @Η ØóÙ3‡>þñŸ»çµ©W¸r4èõ'“D"ªðVß{ì´RæÜÕõ$ÉQÀ6ËO¬¬›™½´±y¥;ë5ГvP?³rt0?»µžÙxaAE"À,zºBJ1‹B(Q(9úÔ/\Ø ¶¹('\°ûú…‰Ñ±í4M c#;ýîN¯ Àõ@5Žu˜:’Bñ0ö÷º'O^Ë8Œj§n½~iíö“·þïÏþá?ñ•K—öóÔ#‘"ÔÖ;aϾ¼¯ÊU@Âé܉A —OúEB¤£œó,L„F£Q PYÇYV0ðÚáŻΞ½&X‡ëî +kK+sßxaJܲïPÊÝv(mCJç% ­Ù—…OYï zADï¥Ä„@Q9•iÎ:ë]™Ðç+úÔÙ33œ>Þù™=~öWëpuýÅ,/´&­fÞuÇÉçŸ} έ.*£Ç6Y÷ùËÔÆÄ¥fÜÖ*eÞØß¹ºÝõâãC­ 'ª|âT,¨ìd6ˆÀ „´ªG±›sÎ,Ò ízÓz1ÚÌw:“hÄFÂÙFD!ÀB«G!hÂ5M„D: òQ$àÆãñ…ó_ÍеW!vf–^ÿÆ÷=yÏ÷þÑg>÷Ù'¾ðÌÆÕ‘³"ÀŠ«-`Lj(ŠH).ÃZ!Zaö"ìï¡Òe'‚ÉzŸg… Ôkჯ=sö¾7Þ¸‘Q}®µ‘ˆÃr]«ä+#¨üºiZÄH•î#"‰xTÌŒ$â-"9R*AP 2*Ô†™<(F¬ª–…¹ðñþÀƒßõ>m¾#ŠýgLD¨€¹FÙl=÷²Rk5ëÜz£ôìlk4:¶‹a}¾9ãØùN£hø‚ùz‹0pn„ÈBB@ ž‹¼8H‹Ð:ÑZØúÍb<ªfoÒG(¬'$ÁZ×0ÎsÎ|ê@$`È4Éä &ܰQAHàÉh¥‰=ä…»pî"³§ëÀi‹kã§î\X\=qê®×Þû¹ÿõ™?ø³¯^êídâ«l}êŠËÀÞzVTY{®P•æ•”*™]iæ¬w@Áꑹ·¿í±k’É\¯pgæ¼piÁTÚÝ€”ze©ü ˜¥\ë ž ^Xø› 'U"@X üBõ³JJ%ª€Lh±¬ª€ˆx/­ºþ‘ùÀ»?ðƒ¨ù-½ ßßKR CÑj' š³“þ>‰/ß ÍDÍ–é¶@d$cC„ØDaíu¾p)b@¤¹°,Þ—–ÉŠ”ÀÛ¦Ö€Q ×w»ÃÉ:%Psõ™N»)à³4Ûô½X°66³óZkËnÜ75׈Uš¸Á(j/,¢bÒD¹3_ÚØL&ívp=>nDl¶gï¼ç‘¥CÇŽ½ã¹o<ùÙ'žøÒŸ^¬cÂ’-&ªÄpx) /@аòÍÀêÑèY\n™ÙJ+]oèw½õ5gî|-^#×õñPF"¡8(U‰Ó© JÙ`áÊ2“©œ¹zfªDK‚‚BXªj¥<³(MĈ•"m4"–‚‘ŠRNµÂ>üáw½ÿƒ©5¿Å-MFûÝ}FdhsÊòls¯ï6×…}+ªÏÏÍ(@!ÙÙ '#Ç®„« a¨q0ʺ£>Ï^š«Kó •R€ HŒà¦SÕ²é 4)0&I—§kKó‡:íýþî`Ò¨ÇD˜ey¬èÐÒáƒK»;ã4›ixë\fuÖ–âÆ7’«»ý¹¹Y­•(P¡¦äÒ‹W†£áµªVÿš…JZZ>ÒéÌÏÏ/;rê¡ûžüƒÏ?ùÌ3ûû¹ø©3 !•·9ƒ0û²S "ž=08çÑB$cämo¹çÁ‡ßRkÎÿ•Ö%ÜEÄÄzêÍ]¹ÔW%*x8˜C2**­×xêÁƒ\å9U ÕPz V%¿ •&™,HÀÈâ•’ï}÷?ôC?±¸tä[ßu³Ew¿Ë"H¤RŸO&éáåæÚâÜ`˜_ßÍr‡Z³¹5ŒÓ9Ý`”"K,/Þ¾¶¶¿×öâåþ uÌÕš• ÒÀªŠ,÷OP Ï<Û+ë;›W{¹Ïku¥ƒ9&â†ÃtraC\«]ÓHJ‘ÓüÔ徯âÅ/vZsÍøJWÛÜj¨ìµº;[{;Ûk‡Âu>aT»õÌk—9|êÈá;Î=ðìWžzú+O]éí¦¾˜:GC•Z)/ÂPyT¤‰1®á;ßrßÃ>¦°®õ5{(]—p7ÆÜu×Úýñ—·¶]ÉÍ“ÊþW*×’§^ŠØX¤2/–Jè5mWV¨Šª¡ 3—åV?X B‰9©P'þ±7ÜñøþÄò¡¯fgÛŒ "4cãlÖŸ$ýa:Ø‘´HÇv´43C¨»Ùd¯7 ½5ÌGN-græqžw_¸²}¥›…P1×ÇYË\Ùþ£ :3UÇBÀ³ª‡ñL§5É’"÷0šk·H‹´juYà$ÉH`®1ÓŒ#ö> ³Ð™Ç)Š I/´Z…¤ò~Bá4Mzû{ðm9¤ôÜâᙹååÃ'Žœ?}ÿ=?ûüSO=óÌ7^xñÅKÝÉȲc ó^ žá‘AV—ëoxä¾{î}=™zE×PÐt]Â=Ž[ïxûûêáèSŸþâ—¾²×ír)¾.#uzç#£ˆ€/m-ËM ˜RUÙãÔHP*/Läo:ÂÈÔWû%|ñozäô?ù§?}Ûý¯Ò4´·¿Ùïõˆ´jñØ»æL¼?l¤[JáÒü )ãØ¥TMó±XßhÆ+ËóÞ 4[µžØ¾‘><³Ð®ÕiÒC¯ÁZd Â0ަÙ;1q€œ×k‘YZDëÑÚ9¤Ì\læ;­Ô{E‘R( ^Úq¤ Uz_H£A adØÒä ŸN²+W6^ýlõ}gn©Þš zËËk'ݹßÝÙÜ<ÿÕçžýƹ«›ë£<+[s  Q™%nÐÙ»Ž>öƇ—Ž3€ÖdÌ·Ôfø6NU•>vêáC‡nyçÛ¾úµgþèŸüì_¼¼½“æY¹ø,¢‘¼TüƒêâÇ©â‘HD¹ü/¢;VA?X‚ *=­„…ï¿ûÐOÿÔ?>}çÃ¯Þ wÔL’T¥µf1aH«™v#²–Mª§õ ˆ–œ8@‰ƒš#_ä,²0מë4¬x"]jctEæh©š¬à}a‹ig†D¼÷ž¤gÓÚXP4hÔ’;ad4ÌóÂ{±"4ån:‘V#j5cPÈi¡•Nœ÷Ú;v±AÈ{ú¹óÎAÁ·ï 1áìürgvaéÐÑÍõÕå#'Žß=x¤wáòó_þÊSç/lú…Í= ÄÝzzù×ÝsôÈÆ4Ñ ÃxaiQiuC‡{5)¬-Ì­=vÜοë]k÷Ýsá¹sO}íéó—^öú«d@®L³KTÙ79•S¯5/@Ó½Ù’&^’΀H¼ °s|ûmË?õ“=ûšw\3èÑd\–HéÞxЩ5¦ë×…œ-X@;ïš*ò¥ù„uP8Pa¬) ë<°@î7G»Š0P4I} ƫۧNŸc “$w¢P)@AP 5‘-m¹XR›™ÉzïH9ç'ÝÑî ¨6‘dJ)Å`â=2s:ÜïÈ!R3s+홥µ#½Ý­õÍõ………»NŸÙëx~g{«Ói®.]XX Âxâ֛͵#GWÖ®¡µ÷u wf¿µµ~îÜ…áÍcgî\>~â5½áæ¹çÏûÆúÕ«“ö†Ç¾W]£Êf8L&IὨ ó½Á¤¬.!;‘ÜÛþh(‚(\¶‘IH¨Ýœ aëYØ‹²ˆó<É3öBe¶xæégßô¦G  ¹¢°“qÙ–.Éu¥•mU†æø¡cš´s– ‘õú£ít/O'P¡x.9pZ«²ªƒ°"Àw*è©Ùžk´f91êïõº{[WÖVŽ¥y @âUf-ˆ7ÖÂz£9yËÑ·Áµ|]¯p‘nw÷ 纽~2™Jœ çæfÚ­#÷Ü5¼pþ¹K—._¾2Øëf.g™òªhï’*üñp†(¥²¦ôñ¼ºÒüWÿìc½ùÝúÚåyýɘEÒ»´ræþ{Ç[[—.^záÒåÝ«[Y‘Vùhù¦j0C¤¦tB%|ÿàñŸs×|0\æ,¥; Udg…ÈÓA¨ÀSv ¾”¼)h±N×ýÊá!Ry¢PÿЇÞÿáüt4Ý];vôä÷¼çÑ_ø÷ÿ#»òbI!â¿”EUEP)&Àéå_‚ƒ/IùX C|ð¾µµ¥££›±~ÝÃ}Z”P\kŵÖüÒá,ôöw67.÷»ûãdœç¹µbH¬g¥1wˆŒq” ‚öÜlcaéÄmwO\¶wþüó_?wuckâ yëÃg~öç>~ää}שüBÄS'NÎÏÇã~âKl§($@¤Òý“s‚jÜ[¶#+¡~YhT_G"B £ä‘û޼á¡7EqëàåêÙ}ðÚ'¿þÛŸÛÜØb–%9Mów¬:RHJ˜‘”Z="¥U I+ÕiéN;>vhõî»î‡¨ãEnÆ:¼Tüí<ÞYkóa¿»·}u¿·?êõ†ã„ˆÒ<AïYeyùI{Ϥ!4!ˆ'fÙÎüâÌÞøÁù¥ÛàzvÖÆÃóóÿâþ΃‘-g6ì¸ g–ƒúQ‰÷ QiT„!*òZ¡6ªÞ©7kÓGWzð±×½éïµgþR5í½ðÜgŸ}þk—/_MRpN¶^)MÈ*¥ŒfÅ–ÂPÑ@š4ÅÚy4(ÒBA= ê³s³¯{ýÃcq3Ü¿#‡Ùy:&“aw¯»»=Iò4KŠ"·Þë òÎ!€6DZ‡J^Y:zôäüêq¥ƒoï7®ïm%Í-3O†ãõÍIn³Ì…ïQ¡F@Ç(žÀ‚0Db4†¼wDÊYV¨jºF­³rèÈmg_oþšy>{·½~áëÏüy¿×/Ä¡2yb]^¹(ª±ˆˆd–Ë&{§5‘Rг £º°¶.eFP„ÎÌ™»î^Z>òmÛ–¹î/«8ôÎÙ<ívwûÝÝÑx8²¼pE®Èh­µ¦cÇN¬9YoÍ~G~?[ä»Ûý^w4ižY±!e­G£‘+,)TÆ¥µVÌžˆEé@)UkvâZ£Ù™‹þŸ^ÛÎÛW/n^}±ÛÝs,ynÙy@P:`ë$ñ©/Œ¡@¡ :*p ÒZ)ÝhÔ¯X\>T«7oÆúî/ð;g“ñÐY–&J)cB­UkfQ]kœÃ+üÕD„½seÉXâ~™™±g@PJQ¹ã!"DÄìKø¤RF„I©—™€‰H‘%y–Z› €wž™ƒ0rÎ{ï¡2.a(DÒTRµJ,‘6Ƙo¨éÒÍpÿ>÷ƒÎÃßíóW|Pˆùã;ø?7Cüoi¸ß<7Ï5;7Sº›çf¸ß<7ÏÍp¿ynž›á~óÜ<7Ãýæ¹yn†ûÿgdz»ùïð·âü.zûëC9:IEND®B`‚stella-3.9.3/docs/graphics/chucky_cheese.png0000644000175000001440000012220511433323254020441 0ustar stephenusers‰PNG  IHDR ¥ØgAMA± üasRGB®Îé pHYs  ÒÝ~ütIMEÒôÒã¤IDATxÚíÝoèÿ÷]ßûs½W,ˆâ@ÆXp2WeHFYMGEÒ0´a GM\”.Ø¢TˆÝ¤R£q­YÚ¥©Õ’Z™ÁÚZK2jj¬˜vAZ‘Z:( õÂ.œsç{#^ûdœß§W}_øðþ¾¿ï?¯×ëùzþÿ÷üÏÿù?ÿÞßû{ûoÿíøÿá?ûgÿ¬óÿóæøÞïýÞðþA~×w}×ßý»·+?ôC?ôýßÿýýv['ßömßæÁïº9züÿãÜ•ôþÑÿðÿÓúO¿ç{¾§—t÷û·ÿ­¿õ·zÉw|ÇwtÒmý·;»Ò;ñéî÷ì?ÿçÿ¼÷÷_Ÿö#ìúß»9þþßÿûÝÜ#ÝÐyCýÎïüÎÎà~àïÞ}È#{mßõ`G/¹ãŽ;¾ïû¾¯gRWºßÛöiƒwþ·n']ñçßù;çÛoWÌÔŸM¶!}Çͱ?û—E°h½­‹N†‘÷N#q˜{÷tÝ:—®ôûÿüÿ‰òOþIKÐIkÝB´”͹Õé¥Ýðƒ?øƒ­Boï¶þÛ«p6ÃoýÖoížÛn»­Ñ÷H«Ù¯q|çÍÑ ˜uò†7¼áöÛo7ÿê=â¿}ýMoz“yöæ~»Øk»¿Û,(6¶`Óoðø'7GÛ…Mð¼ÿ®»îê_]é_?öc?Ö,ºÞ#ÞéåýÙŒº§+M T,ecîÏ.RãqÞ|÷ fžêÊ·|Ë·¸ÞÎ;,‘:ú—ýáÝæ=6Ç·¾rxÜÏG<åÎ~o àöN“lò­N@WZÁfØŠ4úþ ]ú@kÑbµ4.:é3Ы?»¡÷´ü·G¼d'¼üõ¯}ï´%ƒGç›*¨÷ ËÛ?zsü_7Gòg€ìëþëý^n_6Ámß¿ýÊÑ'zÄ4{soë"PF'0¸?­ì dõ|BbP„œôz¿mäU€7˜us°÷æ|°E0/‡n `‹øƒ7GŸoÇèaËÔÛ;ù‘ù‘Ö¢•jþ(¤=…îõg«ü/þÅ¿ÌÑÖ†Á&fY‘С©g»-ýÄOüJˆ0€ììÚŸüÉŸ€]ïa¿Ý$s$úç~îçzU÷ßþlœ¡~÷¬E7`‹h ßñÊÑŸƒP7„°OôE€²z§]â|xißôÛ:Üyç÷ÜsEÀæ¾ý•Ã×bp3l{Q'1' …  b­Å½÷ÞÛ }©A"ãaØßFAÛ-“YµÖô¡¾œøVXè¾åë8tÿíþf ÿå¿ü—A½“¶N ý©Ÿú©ÎêæèÄ¿:~ø•7éëh8w3äFŸ þûo, ‰|€6º8°Ü¤ážrÛàúš×¼æÜÇG;i;FZIóú·ÿößþÎïüÎïÿþïÿÂ/üÖ«ºò_þËùÝßýÝÆßÍ=ÒKºÞm—«0¸9´ìOˆ À ºMêžÆ´yŽ´v-kßî†Öºó DÀß 1i;±÷@_¼¶xx§ìý}(p†^8ðüøÿ8Üí¼é÷_ÞwO¿<c-šN7ì¾ÛÞêO"dQÁ¡jd ïÂHEŸ»g8Ú aÇ·†O=غ٠ßú¿£´ækm;ì]4¯ßÇ{ì7~ã7þ‘7°þ‹õþí6²ÎvÌU$º¡· Ô—Z«ßL _‹Ž#’ý«OÂBØÅ»¹uăÿÎÍa³¿Iéî´Ð6ŒÁwß}w³Âh›j ´?ýÓ?Ýlææè"èöÛŸŒb£Õð>`÷*О3߯C$|ôç¸)©‚D=Ô¼ƒ@Ô*‡£vçVÞ¾ëæˆÇ7¦Ð Ð¥e Ÿ¿ø‹¿øîw¿;èþ»÷ïÌ UëAóíÁ„DÊ‹UE'®"Ñø"í¨Q¶4C¾SÐm-úEÉ-Òׂ6ž"àüÂÍñÀtR9Né‘ÉY°»~‚z‹Þ”@ô-oyKPì$>ÚïC=d:0ã¨tàlm/vBr¥E–Pod¦¥ûÙ²`¹MÙù&×ì÷˜Ý39¹wFoï÷~ï…^xöÙg;ùÃ?üÃÿößþÛûÞ÷>K 4Óðßü›ók¿ökÿþßÿû_ù•_±_[ëù¯ÿõ¿n²6¡ÏPǼo à£&5ÏFÐbÁ¿ñ×– V6­`ßkÇ5 üãÿù?ÿççž{îOÿôOãÍç¿þ×ÿÚÅÎ?ö±ýÖoýÖúOÿé£ýh|%Àõ†Ûä{? A:#aõfû  ‡RÄZð ¢oûÛîæh/Ããa3*ý7G¢_0þg7Gk”„òoŽ6Ü´Ì6Vm¾8twv24õ Ú8!.ŽnET‚Ç?øAp 0?s4ÓÀùßÿûÿüç?ÿ—ù—ývÞ•ŸýÙŸŽ [Ø.6÷ hI$†„fÑÍ]'^µ™Æ3®ß W¸yi#èE0¯Ïã…¤èV¡Ñ·7?ðËFüñýãÏ~ö³AñþèþäOþäwoŽ ûð;!`âŸèbjÐ-4ñƒ§âÊ}ñŸÞݨ iãiZÌ Èçnc&‚P‡ÐÔ*Ì8±‘@öQ’Nng`·ãm6Œ™î4wÒ,¢¨ÑÕ61]¼Á4ÇfÝ܃hkòW7GKÔy¿Ht„jÔ±uh¨o|ã›ÝoÜ6®a7nîb±áú4ëq±¹5€=ÌР†dæ`ß—Ú•¿ú«¿,úŸýÙŸ¶ÿzstÒÅ08Xøßº9b$ÿþæhòþ©§žjæÿñ?þÇ}èC4Þoù¦÷u¨ÌèN°¦þÜ+GWƃÿÕ¿úWÝÆ°X ‰[»èšO'¦ ›ò?Í~Æk¡Ú)sMfîÏ^Þ¶k$Í·×öÝÆÓRü‡ÿðžxâ‰?»9àñg_9p@´ó ÞØ¢²%ê¤%jaC¡&Û Ü#Í‚ùåÔƒ¯"ÑV–1²ù·L6{c® ú“Ÿüä¾9‚Y`Ž©„”4¥¶Þ¯ÿú¯ÇBšÕoþæoög»¡iw¥á>ùä“Ý÷µézD!Ð6Ï׿þõþìëñ`@ ƒ{O‹ˆ2GGœ¿ð…/Úþ Ø­'«$ñ B­øÍ›#¥èÏoŽnÆìNMœZA>§}Lî»ÖÐÑÇìñ>ÌÜoԸݎ~úæˆü¡¦d—*ô³$µâ]ù¥_ú¥°-0wýßÜý·ûÛñÑþ Hͤ{zÿì2}½bÚmM8è¢ÌAômo{[íÓþì7÷Ú YÁÕý9át!q»ÍŠm#j±ÅBœ|±Ù’fÐc<øÂîA|¥X÷ÝŒð4Œ¦Ö0p€ÿú¯ÿ}•QÄD"´¯ãJï|ç;cÀ¼V»§º9‡o¸±%‡3Ò‘ŠìÑ¿®’¢ûRóïÛ=ßòõ®§Ÿ~:”mdÑÞ6fëØÂZ8ÔI TçhiëŽqZåfâ6í®÷ßæÐŸÝ­£f – º5 ÀqWû£“PÖuxÜy = ž<øÿ<¦uFl–œl÷ÏÕ•)„¬Y9ü·_4¹Ć™HN^zé%¼¬ƒ„äöiôÍ`cÇ€CxïYÖœ,mµ‰~®|B9³?þøãA—< Ú_ ºÉ„‹ð‘hhmqƒDxOfîæÈfT´û*BÝ4 }PïÏH=¡Sà¨èU?~sP S}ÖÚ+½ß¿6Ó¸Þwß} í=ƒ.ClKœ:@¡‡ ¬ë½jž?§  ÃC(Ô²G¢“[»¿ßl`}¨Ùu3Fã~Ú9zs#ѽ¢oÐpýp›.XØÖŦ„Z†‹É/!_PŒFE~¢;™õ*ZD»È •´âR$Z…ž%‹u7ßC¤zæ™g>zsô§ m± Ž/&Èò·¾õ­Ï=÷\’Wÿ†~(Û4|p‚+½áMozSKO…íh4ÖTORhØÜi†äÃyHO›-E¢nÁø§^9X1C)ÐÅ/ÈÏ8:0X›©µF¢{|,(‹DO¤¢VÍ *}¨ñ4r`ˆþ5)ÂWËT$&ÖV3Ÿ`BÖ¤“VîþO|âHz¿ôrðfd$î‘ê¯r6´Ê %™"$¶§˜&‚D’aWšCƒ¢øWnŽI@0©UŽ’zàM@"¢·®ôTçÃÈÀÕšLÓHMêsóu[Ÿ&Á‘¢=H°cHьϼ‡$,<˜e”CÅÉí·ßÎuÍéÙ¨z|jî„‹Àß=ý¶îLi¨7ÃsG „cÉÃàx?<îq6,Ü—›„ñhqOßýÝßMQnƒÁ{ì–wýäÊP™Õ@×wmǶ})0„-as;ž*ÌÊñÉO~Ò™ ç6èþ8T£m-{8Ó '…BDÂt>û.Þ1Óé­Kk÷õöè>'÷°I¼/¾øb_ýÚ×¾Ö/QÞ• ûå/9è~ñæèœöùçŸo?R!z0`vàQf5 ®÷Þ{o¿!Áb6 Û :™ :`Ï»0ñjš·=!¸®%cßèCoxð=‹Ë§ÔÁçÑçzÉ"=UH!­iÔ{t¶T¿}…õ¾µB0h¡¬íÞ2´¶S¾pþ7ÂÜSѳ!½¹5Ü,8Bt¡l‘\×òàP-`ÀàŽð52Ûz衇BØmÔ&ÐE° ®¡rWBܯ~õ«]t%ûíž†Ø ý«7î`Ó{‚­´uù‘›ƒÂ˜û”Ö–še âò ÷òy8Jfæí?U#F]AŽð ®–•¬Î࢈ Rì˜Ò:2©.X“üÕžKÅ z¶µ À5¨ôõþla0€u‚D1ža¹™6åø`“âŽC¢[®n°>‹¼l"·Ýv‰o `âÕ‡>ô!FcêÆÐèèW_9¾|sŒ&wÖ6®]ÿí_ýÙIWqÔ©åh_!ZièÅMkª,£Œ- ä­°ýä+Çè!xsAnXKÂëíˆ/ êe^R0»GVÂÁiÝ ©žùøãG„|ðA ï=ïy“j“ ÀˆG 86ôžuòì³Ï‡_–B“näÓ€£‘‘U!ÆÁ’Ä JpÁLc÷p£aŸjÄÛб´G}4h}ýë_dG@ q_~ùe¬×ůÜA½‹L9A« ´@©ÅT¦;uÇ]Г°>àÖ>k†à:Ÿ Cnî¡{CÔ~²•èkŸhAAî”`Yoh´µ>ÝolλX)2‘âþèÚ©é?*`³±'£`+Í(³åj`탖Ñôg°ì=xĶ4SIcî»á¿SÛ¢ÓPÅzöò„<›0±€Î«0¸y2ô˲Ѹ'ë£ç ÛŸý‚h¤»i|éæ~÷ÈïýÞï5ù¦š†Ó;Ùñ÷Ü,þ¡Hã‰Þ cP´:ùÓË›d+¢”f˜Šï¶"¬c?:"d+Æ#«Ù}£{ôõÞã%nö62×}”–}¸ÝÖõ›©kvO=õé¯å2†ÞÐl·íƒÏ|æ3„ç`ØaýÛV^äé¡ö‰ݶ¸­Ù»'í Ĉ®AéA¾–Dj»u L£l .DDqÖàG˜"’«1c÷„ÓM/5+qǾr4=®I@mÄüWeì­ÁOR"@¬ð0ÝaðBhw2Ës4™a’ð _e0P;ÅÁÑÔEaYÄ{büŒ0»“&ÕštþŽw¼#lëÊÛßþö0$zOrÌpç À(ÁO>ù$Ã$êµ€f™¶r; ÛèÁ=ÞZ5æþËËxÞÈûóu¯{]Ð}ík_{­M¶j¬ oLn}Øáت?[ýFOØÃhqÜvCCLôh@"¤lm1Sín.#ÄÇ.nÎbƒ: ?Rþ¢‡1Å–²Õé…Ì:­uÛEÜä$m  k1Ýö8ÜI9ñÊ~¢z.Η±ÐzÑŒsă6TÖ(ºu«ßwB5焎°Óß`dφ٭[(ÎÊ wý&B7bÝi0f(!Bº³Z·Õ:éÙF˜HkµHÍ«xpËÊi߈›$nq‡—_~å £<䩎°¶ó®§õ*¨ÐœƒñoŽÆ‡1H–Õ¢Câ—^z©jiøÒ#ï]ÁÚ£.¡òwÇ8îl7¶*‚`Âò¼¨ÕvCW,ÖL˜m›RÌmÄv€CNIÂDnï3ßn‘WÅdqú’h Zme“›HÅÁ’R4Ów#)A7À4‚¦*™ŸŽ‰˜c¸_ÁîüŒh`#k¬‚±Ý/¾);ZÂUÕWÞûÞ÷Æóþò•£-%üÓ‹—c»­ ,¡fx“„5 ^øêD°ÇÈ’YÛ5œ9]Üç8ÿ¹Xšo‹ ƒ;qû³ Rü~×+WM4*5Ïq/AíZÃ6¨Um.DîÂYÙ®0õ— ĎTÌX‘.äœ|‹ãõˆIÏ6D)h;#ð’{m„—æ ⹉ ‘âֱݑH'!!¾N¸c ±Ê¬’H4g[+xQþB¢ÊP9é>´xU¸Ûo¶ã‡Ùld6–L*FõàÔÅæ›ˆ„°ýùŸÿyCí¼ßdˆm,ÎoVåækß‚IÑÂíìßm³æžáøW8uHTM«ÖIŒXï,Ì!ëenÐÍ$èö M´Ç†Ž!ú®+ÝÓ2µ¦ÔÙV‡B°;ÁU˜ßÃO<ѳV0nä’¨ûhÿêÏæo{5˜°¹o ²‡¾hàðÖRH /ŸÒB-ç!&48ßß`Ðrõ"®1à&ËøÚoBµ¬“æÕ›ƒƒT«”¾ÔyÀfîF?ÔÑ!橃Ùù{ª½Â#ÙÁÀ×W–!ÀèÁ§'¾ÊÐÑÁÕ úGÝy«IœìhNÛ¢§Z_úF<†0Ø4ÕÎùvºòðÃGÖMçâu|_Co¸9¬)Š×ƒXF"[¶3šyœ¸Ú¿Ù­c¢·µ‡à±G˜æ]˜=,g¦ŽÚŸ¬Á@l°ù®»î’ø„\³{³ô±otóC=Ô =ƒ”¥TǼP,ê"›T»¡‘è¶ßb ï6ÞØG}”¦ƒœ †·p|®¥dš ¿³,†À<¦ÛX}C‰ï6aÉ Û´e^´ö "lÓ‘6{-U›/rMB±¬ È“CšnhÎ}ˆÕ,öÜðš/l‡%Ö5dPbxºJ:Éã7*²£ÑÊ"ÂEàœÈ dEo›3Kˆ«œì—Zȶ63D#δ¦Ã{ƒ}»_†³lCCúî¼Ñ"#Fˆªso/rè* n|¦ê4¡U»•M¤u´Ä‰ ±Šl7€„ Ñ ‚ø‰w„ t ÉUÍgwâÇlÍ\}ˆ¹X;/$h˜â²¶pÝÜõàbŸî·ÿ6Ô„Õ`Ü5ΦÅý7¡¢Þ ò0òë»DbA“ùy´ˆWdÝù™H!=PQ¸€³m×0¸[älÚ^iq«A«îÙDØë)i¥‘„ßvXO­ÚÄ‚¯Íðo-z ~£?»o4VfØhò¼9ì893LÿÁCž¼‘0ÕŸ²6º ©ÃÐ*PQfððvÈjYm"úþÝ”' É·ôVB-™ß’°ª{àëü†ìmèP_&'Ót '{“}[ª}r>" )¶W§§ÄÐó3ΆÕ›àîgD[í fvƯ^ÒI+FžZšvÛ×»¿¥î3á­÷ŽÄ‘ñ\#È‘£h2ZúŽw¼#ä·Å³FÙï$-SX+ŸQ e¡´%5ÑÀ.\ì>Wi,8BàV¿GB˜ÒD0‚+<:f·«pÃÆ³ß•˜ïÿ_a\‡ Ѽ­¼Îí''áÐBw[¨SüFšQÀhѺ­—­¾+:1yž/¹e!r*\4Í­·õ•¾ÅSÒ4Ûyß~|‚~mSägŸ«Âfçh”¾¸ˆ°ÖÞgtlôÁ/`ðIáò¨“<Ò]»„^X5ÉKÒ>K5¦ß¯+>ø`S%­$ÊvyÜSÄ‘¨2À‹­!FŒ¹•˜€gÖ1fĬ÷»Ðvl¨‹ö7‘ðõ~?‹´†—}¾‰'š„?«‡±ì&–µ‹Ê:gy%"VH‹¡T¬Ö’Z¯%ÑÂÒXÑóQÉCh‚Cï B!bè˜Ee4Õv@Ðí¿ýFœŠTòì³Ï6ÕNØ=:–&S¼ÊÓ!~v\GxÛÛû3 £¨Ó©øùO?ÁÌÔLQäd'Õ4–¦æë Ò-G'K¶8=’v%¶ŽÞÓ²4x1 í­Æ6j¼2wg`ýé-8&Î S„d(¥*;߀-zñA§Åǰ¨µŠ·(Üg ØÂ:d’aÞ±FFˆU —,X  ÝZðF°Eǧ©Xhö /ÈßbAK éýÝÙZ³ÊZÁ~[ô”ÄI §—žDb¼Tðkšo~ó›'ˆQå=bFT¦¹­`ž cŽUßÁ° (˜íüÌÉïä5¯yëV{õ=øW©i¹ú”h¹fɹn ` Ã<á`ÐùÆa7CF®ÀÙê3i!¿; î„m!0ÄS¥{w3 ¶¯é3”+´Ž€*ì²sh×:ÆÂeÙþõ_ÿµXþ†4%±T(0Ìhœó(PE^ws@£EBÍß _›U¹]Ŧ/¨ÈX¸D슈zE6X ~…Òï¿’X¬V®eùm‹¨øwÏŠoœØÜ9£aKtòà«u2¨å³-Åš{€WN€¾ähÓA©CO?ýt‹¨ÄÉ’ `j¤O!ŽÅU‰½åèmM»¢PnèÛŽÁŒ»ÎWc+4ú§V¬püÂZ‹2ïÏž `m’‘ÇÇ,r›\«¦Ð# k`È$4\틤-ºr`ãœÛË%™‚»ŠýÐîði¸¤ÏNGgA¢å˜ž_eªÄuäc!MjÀ9|û$å¶ña):оãï›Á‹pæÞ7šÐŽÇ02 ±âD±4»Ddè*›¨E¬%°¯áǃO}êSÑf ZµÒ½-1‡gŠoDHɪ`Éðd¥zEá]™®§%‹®RòˆçÜõª ž%˜Véõ†îíY+ÜK`ök^óH<¤ßÉ> ä©›]eÉ–*X—¦'ÜéOþäO¢„-h 5XŠý€1\ið`5}ûW; TÀYR÷ÎNä˜Ëóyæ™gzgØÃÛ¯Æ H·è!qŠ+D‹§L¬ŒÅÅ €TðY±7-ì¤gãåêOÿôO%Ýò`âUT¤ßž]-y–m›ÉÁ»0©“&ÝÊòκ8ŒœÝãì¼a°X­äÖYóù”›&6ŸÂš¤n.¯wpUfë …8·‚i)-J{¿=ÞŸâ:ù„|»ùÕ›CÉÔ.Š×!mX¿O>ù$E¹ãC7Gª™Á¤wc~â·¾õ­ 6Ý;‰•ޏ4f^zñSŒSC• îZ¤( Þ‹ÝŠ*Á/–oºk*‚ïbÛR¶§=Ê_ˆòY«šÒte[EïÓò|qåÛ^9Nªàœ—¬_"Š _UŒt¦Íä¹çžK„ÃÆ¦M†Ä²XUZ»UÔ_Ê=ý˜ÀœT8U‘Q¡”{ÿ×oöjƒ“ºÿýï¿ ËÍu¼¥Nõ‘P0»m'jsÕtØŸ ¼Ñ’¶‘R.k2´nFA]˜°€:Û–Ö-32ðXò,”l)SÖe…>ܼ²V«ÜpÖeš(¾n,gшÁ¸g)­ó…ê*oÒL?‘ÇpWŸAí­‚iñć©…¦“ŸW&G.v#Ij¡p•ZíVI^ YC@º½6iŸwR‚m6¥´X-P{Îùß®%Šw `¡ÈKø”i?óËê=œ‰tÌûsJrÊuòè£"!9ûu†Bmå~ô£/¼ðBó]#Ÿ¬¶Î ‰g£ˆ®ßÀ–OÜq“A+¼i}5ŒärQņqÚSQ<Vœü팕N~fŽXŠÓ {§µÆSížnë)uöÞþö·70’ûdQDß§‘~âŸàgKÖZ ¸ßÜ=gC5õm;–·²r0·0j&–¸OB8Í@A¹–Pe^‹­Ä,˜Û¿µS)Ð| HŸ8VŠ×2' ±?ô¬Ê—J9)ëÔ¯biàÚƒ-V@GÇц#$SÒÈÌ“ÔÄ~°Ãôu¥zHg^»’µ¹}€ |àù§&Ñ-¡ç#<¢"@ÝSO=¥eE0“Ò•áf7€Ö䡇"卸wß}÷5©æ.bMÚ6 ÒßêyAñ[8ÖÛÃð uÄ;ûdƒ°Çªä#õ½è²¦H)¥6M …yŠ «B(žm*,eÍ·=qÖIÚ¤ñNzáÃ?¬ÞŠ¢Â¢-qèB6A!õ°A“©XVPbñ*\âúÞI‰_âLWhÆö /$鉿3s&³A¯ œu…±¤ÒpzJÿé7ÞËdŒÌÈ÷]*söir d]ÚR§8øZTÏ­ÜL¢$\¤áįàظl%n÷m>¾ð@K¢7¿ùÍíý¥¢°WHÚ T œÃ¶žmŸqYEúmoaíDñþð+b0Z‹ 1‚HH ö*ŒŸÅgåq8í]‰Ð;‰*«¶Úzë`#vsK)ãA,Ǥ*$šWªC-»Ù­ò˜V¹Ê?ÿó?o |ãߨ.Çã?ÞÎH^:®@¤Ò¶‚x©(ÁÙ—uÎÊ«ÜÖÛ†«îËzY”„FK§·ˆPb³¾*ó!:éd(yf@ûÒÍ¡íåSCr5Zj¢Ïb˜Ú‘ ¾9Š/8¾ˆåî ¬% ¶½ ÀÍMo…ÐRNh·|…õ@Ý%V(ä‘Jf¬„Ésâ±Ì^„Ij@K¸kMÁl¹A÷¹çžc¬†Ç;À7âð§7ÓÜ’Q—Þ¹\±~5øaÓ0峕ÚJkt%íQÑÕ>b¹$жVznÅ~ãµÄf”yUv:XAöñ`ò¦<Êñf|±·óuÈ>aáâcøz6´²­cä"ì‰úÑq×<̹ÎŽ€miZP¼ [‹È DÝ)ùXá‡~#SÉtr>e Ðd›‹Â!D—Y›œeO(HÌÛ‘L›ÈõâñUÃ#R¸ °¹—ñ¬S›C¦o1qN}àÚ¢½N€’¾; }•é`»ÐxªÕ³ó´Õ!–Øù£>ÚÄEDÉê8Ããz,òFÏè}U¥»Ø’Š\M>nª–¡cýVD·Ë²jE”<_G• ÛÃ%œuO3ìÖ´i(¤l#Å0U®?—º9;67*qA_&nf¦éÃPV]ÄI·9H óU¬t1ÃçU[>’©X¯•¬lH7¯O|âönœŽÙ§ÕŽÈö ”y°1+špz™ÖЖR0C÷7à&VpãÄ1Tüc%h4 C¯fç³52è²"È¢¶Â|”DVK?$hŒ±üþLmHÜ`¥åŒSïáå:ãâbü¬ 0+&IQœÔåHP§·¬h5FŸÂ$óbêÂŒg|ö{çwªªút§:ö«¸-µ“Žû]ÇÈÛbÍ– ±˜¯Áu©.}¾Ø¡BtWy“$y*й‡¾Í°ñ¥Èv. K݉Qbåæ–¤Œ,ëq×/ þÎÍ!Ýa˜Ú¹Ð|×m®<óÌ3`ɾýä“Oj}º]áÿ›®8W"B±k0æA"ÛGßT{±}éu0¸7ÐlbSS¾kÑÁ%ÌA´,•Á‰¨öç|M Ì8=‰kD~„œ©. ù Ù an—¨x¤RÝ­¼ܵ&!°2³šuOJÕ3$Üéæ%^Wj%ÿ±.-§ÓPÍ¡wØ'J /Þí„)6m„7nmgôlˆK3î$jÞ{É«cÆý+`w2]ˆ´%““oCW¯õß[½y»6‚Éßm‹‰XdÖb¯Þ»l†yÏIJELzZ¦—ê™Ã²+\Xë“>‹ÊUFÊÈw×]w‰ÍT(·ý®#Uõ cw„tD6ä5Q€@âß,½àE‰‡Ôx‰£@‹nÛÂóø?èÁ®·9„ÚàåKLµ-°4‚7”1XÅfue:ˆ}à²:mÑð£5¦7_’í Ë)£ƒâž‡©‹¿Y˜ÕÒ>Oœ^°%=èŽrÌ&ú•¯|åÖ^8Ä*cˆ½bh§G©Ò&›| †5I ÏWeN“t P+¢ü“ÊÚ8+h¤¥~À R„j–úþ÷¿gà=>™ËÁ‚M|C!€¿Ýü Ÿð ²UÂÖZø0ðmH›ë_íþAwíW.ú¾ŸyÙëî Úù ¤ÏTàEêì%Þùš×¼æµ¯}- ŽXzgü¹Ï}ßÀmÕˆ’xÕ¥d1QI©ä'à7ÅWձТ•Âö•£Å’ßÍ{ÆÄ¨®Û‰š\êwWG`¸>3?cá.?t”œ÷${ŸœÆ«>ûªw¾v'¢==paSë\:d=ã ×çò"Òê NJËç_üì(óð8¼œˆÎnzkóû¢fj1@®„ø11̶FÒ°j±GFú¤^Bz ‰ÔÁŽßµWÅ¢#³@Ü?ýÓ?¥Gö‹+<üÖLÜŸóHzÛ #‹ÆÅ¶6ý‡ÃªIÙškј#Tí]À–Ý›Ž¨ru#Îá®29±'^‡áëÿDZ ÙqVQCî3¡t™,£Õì* õ"Œþª2J|ºò0#­RoW[›Iº2 e%HØè£ÖK7$w2:ê 1yþùçgБƒÊ¾!Z¤;Ñ9ž‘¯ßÿts° :ûe¯ ³ñïh¸M @gZ2¡4—À%^Œ «3ã˜ƒÌ ™N S ¤©­Ó|3‚O–[4 Íx×÷{òæ3x+CÐ3KúÂãå« ÌáSÊsk³I1fµ ¿ýÛ¿-¼TåÅŵp: @‡ÁÈÔòì ¨/8$Ñ nZƼ?¹9‚eð€¯óñ|÷tòéOº{X.¹æ+$o£@ëÎ hýƤ©a0˜©nüÖ‰t5³­"ÁgCõ—ú…÷ÁX“šè’å§/êý¢¶Æhõ™‘¶Œ•`¹¶ñg 9ª w]DÀÉ¡mŽ«x0pj÷+O𡇒£ÍVºíý¶-_´äÿ³.‚saªœÿ8«âœaä'>ñ‰€!ø(03ÞveäÚmvÌËd£Š”+[dÜ:0ãÇþK"ë¿R+-$L¦’¥1¶@¾ÂBfŠP‰ÆZ^š¡ R³E/íl0ž¹§>©å0|%=ÉH{dxÏ¡”<{î𒫤hݺ#Îmgõέؖ…•¨È¢\Ûiâ€I7äÛÈ,Â;vÑrýþÑ+‡»°¼ÿ‚}'«Ñ«? ×ýI[¡(Î&)R~ʼL«¼Š;ö+Юu˪߲áà;Ík±´­8s ñ… }ÊØ#³£º'6O‰: ?´·!–"ušA®-„ÆØ,Š 3ü›ÀI$Y¡cX+2|±¸~ÄÊb± QmyІ¯Ø0–¼ˆQÍ‚ü·?D.þ~÷@º_4Í×4Âþ˜¬Þ‘À·È³Œ™òž…•L|Åüg‡G½]O¡ ‰‡elëÉA§´Ía׿&)::„'¼U k,{˜jdJgyE ]5fM÷˜EC²Q,jކJ>§p ü¨ƫâ‰óí/(ç×ý×½ÖdßàÁ|ì꾫»Šp"1­(!^‰Ê *ͽM¡jlFÈV%Dëô^”:[IpšN|Q„å°5cõ¶ X²di‰E]Þq•%‹C ³ ®Œï4Ц-|ðä»ð–U·®qL(¡Aó7,®/ü–WJ4sa™/âR/”70å¸_æÌ8L][JBÃÙ+idÆwÇVk¥¶ú—M?j,Ö•~Hégô †ºâ c½g?ñÓÑ;¤?=QóUÌÛÀúzªq÷š›c"ØU–,’Mõî»ïæuè¤y&Z€5#8¬Îφ²¦Ê´ÃžMæ|ªP JËéÛI\ Ú:*´Š8Ð9˜ÜÄW8ç.¥Kv“˜¬Y¡=G«eœ®ç<ótú5€gÌherÀuI‚‚7ä4ˆi%—œæU¬<Ë<Õ\O`¶:—'yÝ>+öglxù½“­¾̰Î]OŽ˜1R` “ÕYöí~in&lYá‡5"»EÿE\HyâÉ'¥šÚ'_9¨=ìY§_Nž~}¢ó'f·u¼$GœO‰û8¥¿ã&K äó=üðq,B¤û™ø6V`æ§é¸¾rg¼ÀEPÕ$¯‹šYcÀ²¡6‹Ék×XÞôbKQ-òEŸ9Ë,¯„`OdX¯{UEdÊ•·2öÙÉC=´tì _¶;ñÅ)Ê`Lù‰æKº¸`ZVð–fÂz:ú|&žØ¦Ùõš‰ÆN9!ký W8b>èž5îvœÅÏ€Üdxà·¼å->ú(u\{ñ³âáì!sFÍ²Ý -þÜ”“¿®0é‘GHâ†,6pe@Ù’-ï}jö¹•õ”@€E“Ÿ©½s¹[Óî—?wa¿€i@ÝïÚ?¼:º‹|ñätUMÀƒQš¡2³°7³“bä‘;3ïaAzL÷¬';5yj|w .;vä'åMʨºž-K`¾ð6ž•”΂YXÃvÃ)cßÀè³4:!,DhJ:" -:Ëž%¢f ™À"'qñ—Ár½ +`’Œ‰§ ñ²YrÍ&Ì-ÙÛßþvAù8ƒjݸ áÿ¬‘³Ø¹Ñ<{­f剨÷¤ëõuU§æ|ÏÌ>À2óÁ¸9ŠˆP÷2ÔSGmÿj+æ œÒ‚Ï"Òß@pÖvöE1B;œ²%ÓÄ.fl´ît¡X\žsFlâ2 4™4Þ›ç„ M“þÕͪ¿÷½ïàÝ».þ+úÜžè·{XÍž|òÉ »é:o*¢}bÛš ÒYWuåýESƒîj¦œÄŸGµ¡kâcö°\ü¬àF~-R¡ÃíiÜçt D°¸]…˜¦&][eg ê};õCÙƒÖ1T@³š=k†èùLV€•o˜f¹â7:›¬we’ãµâÖ Æ$‹% $B¯z¸ö µ ¡Ãæ60 ÆÃ¹áÙBmfMDKì&aðp“«g²»b»(<Å ½¾;ö÷€ê´ô+ qŸÊ¹ºœ?÷Üspt–ÿv*›Ûx²ôUÉg!«ØXè+`8-V„é²Z—?é“§€0ÙHmü%¢`ã…R€±Øc›iæO¯ò½H G¤Æ©ØMêS'+²;³ÚšlØ3îðJ¥,Ë›Ôʾ±Ú Ãà‹j¾ Ž 6ßÞÏ3xÒzð,PN¯mRq¥çŸ>Q#ºÍ,£ûÎz‰€G˜S¦ ]«/r}A-\c3}¨µ:£ÁæÆ cE¦¯†'Kì‹æÆˆ¡H K¯B7+ì|ßûÞ§ÇßɇNk­C­XQ8‘;¾g9ÊÖbòTrM€WÌ~¨¼ÄÁ7„yFÙvÒê²Nå[›á™ŸV>³¹ç)JíŠÆŽ¨ÎuîƒH]ŸÌ­À:  snvçYsü°d¡B-Y©±s¨µÖLwCYÔcÕ*ÌÁÅ}›ÿRþä@r'û¬ Öh•û ¶ªÞæÅªB®&KL´ùKËZ‰˜e—n¥+µºNT\Lx0ÖXo¿Àôù¬FiH‹p>½ã£èÄéÝ›¤2AÌ^A~›…K–töN>IôµæE‘h%”}æÅÛ_#h“Ÿ±½â§äå»u¼F£{¦mŸ¥+ë¡÷Êhéi¼­D ¹"¯›¶’e,YŸ~â‰'ºŠ[Ü™AZbk:¬]_«Ìò<)ú,39ÃÓEpÝiÍ;[@õg9ÙPòíd=+æ‹´»où_«¤htXܤ$nÒTeá,$ y=A>©øŒÐ_Q¸™Ù0¡Ðhe…Ú=#¼RO…Ñ •U…|uéÎ)𠤆ñœ¦ä†ÿ;¿ó;J†¶Ò¾´†›·ç̢ʒ9fG'7ß 3ò?5¯ð«±Ö*¹²΂u€w†ÇÌsâÕx<¾*}”vƒz]n†ß÷}ß·6®,cx|‚pªÔøôŠ.X•ô~úκm}̓VúO`sÏÄŸMrŸn!BÍõµGÖðTXÛk·R3úŸ<àæ+䪛…žÂù”à‘3–qž‘rÅ;Í׳|-³ÍŒ¬ÞYçri×Ft覞[ïŠ2s´Í³“EcmSº«”ªñé<žP† +ãBÔÚÒè•§ÕúwÞ©“^8·ê_'«;+²§P¦/=òÈ#“–OW’¡äë)³5]oRíØ×L~ì˜ÑB5§Á{FæEÞœøÌf°].¢ägµöi¾bùäÿ‹«x0ï·m3EÑgÆ¢tí˜ó_æÙÌX+9`±æ¨ËœÍËú.Ý-›Ì¦§àHjb£ê[|JÁ›/딹†4½A›ÞTI­'œþ€¹N?Þ̸2[í­ebiÖÿVÒf[€'N¼š=Q@=Ldc;Ûn\d-hP5ÀçÙtgÊä²NºrŠcÒÆ)*o¶œRôUzFª½9k\_BœYk#bݳþ.ÛY­\“]žžÍaÅžVcßvÛm`Ìí!OB èó ƒÜ“O>©¯Š&Ú<öÖäÏqà FMX«)#1¢õÜDVcûx–E`›“.^dè>äÚz\´p˜v*`3VŸ«§ûáµ–Ð]úîïþnrÊ*}l” 2ä°¢hÝÓS R[ñ9¬|¶‚­ n÷ß?»ÄÂ’µ4j6÷ZÍw$P“†ºì™bÛkÕ €-ºVÞÔzžÕW:ð”Tq»iöêrŒõÒ$»“™E׺ù¢dû:¸¾ò‹+wuNü´ð,dsrÜ,”ßÿÌÏüŒÂtkž _gðƒÊÀÌ»ÂDÕ([Ù¨Oï…ß›õ*ñíÞ{ïå-ÀøÙÈFœÏ€³T‹òÔ{ùWõWS{DÕìs:sFŸ5Sú³?û3BA70¿éMo:•X8 Lø:ý}4ã³bó¬NöϨ ´fùá÷š1 f ·RvéÓã;nÿéÓc £¬•×Ú¢eVi/È¢ä0 ù̙Ҭ„ÅÛÞö¶„ ä¯ðX#^¡Âs”ÎuãÏ9y¬&VØ<l¸²@'VIõÚò=ÒþÐÙG OŸþ«¿ú«¿þë¿àO~ò“ÚcuÎóús?÷sš]1/äc ·f¡gcqñs?Q7†ë§M~aYKæo„÷ÜsåþñÇ×UGÛôì¼Æ–ß] ÞžÌWeø-…lWUŠIhQgcÖîOïÔ§IÔRË·Lž.ª4p¶%Ø@ÏžkáJ/²úg.žó×½îu?û³?OÕA ÛDÈiÆSú¨º$Qé—^zéÙgŸ•Ä€yâ¤7u˜‡©+¡rÊb0æŒ:i)\'=L7“tÉÁì)o«@ÿôÓO/š¬×ROü>ËûŸku¶æ¸È¿VMBl[™¢ëMâ@Á˜‡P逡ÊÉdrb Ɇˆ§)`!‡Çö‡jo>:Zz†/±8¢1ÉÕê Y²ÐZ­ÿ⿌ðŸÿùŸìckÿ)º²=á=…þ´zže7.2ûÎÞcg·éf}—ÝM˜"«xCmç=ðÀˆYh'ü[ìÑÇ?þñþÛË"k‘g9CD.œQÛôó#]Û³ál< Ü‚¾«~ƒÊ}ë¸CÖÚ\Ù]…#b®ÍJùÞVÿ-oy‹¥œ˜&3€çj½0{°Ï±xŒ™ê)èõÛ="×5jùDm*=Ðã/¿üò:H§ËŸ vò$¯¤ Ž´Lkšqу,ùìJ§h¦ï{ßû>qs|îsŸSó&îÐo_T­ßÏ~ö³Iõ]Ñ»<ñ¾_uÑ!é Oª=BÃæÁ˜"pf&N€¿ªÅû.&RÙkE ¼CsXvC;·©*räR ãL}g@µ  xz„]s–²õ™ä ÌS‡ÖÌY  +M·©ãh[eYnJüÚþÕšö”­v:h5õaZéÙ6eÄ~[ ÓW#z½nSÒ¸#QW˜d`$]üèG? ƒµ˜Yê×tè3‹i?E‰Sv8#¿/ôÈu^WŒãh&Zl_ kÃÝÀìä+_ù òÿ;í—'v®ÝÂŒJû׌S‹©nšñ¡öø=Õ¾vJZ)¼øâ‹:bBkD{% ¤ð´)Q ÛpôlH?‰äŒ¢]ÔU$š³s&ÃÓkDRpýXnfÜÁïÇ~ìÇøMS7EªfŸ†¨ÿ“ §û¿ºJÔ«­€–{þ¨¬ŽU¿äÕYpY…Cq„|p"’x|ÕNj½Hv²òß*Ћ{U‰@`ï ;‚(4 _£"6Æ¡¬´Hï|àO>ù¤’ÛFK-8ÛÔŽð̸±åº ÀóRÁÑ9¤ë/’®,­áo|£²KZI„R"&{¤qÏÙ†§õø” Ïýxê‘gpáÙ0yö¨œX'øDâÅè*áΉ}9­HgÆD­­ìY¤Î§_ûÚ׺a©ñ‰WQ×Õ†šÁõ/n8í_É__þò—]•õDúÌg>ÃЦ^˜€åy¶S/”Ìíø³ºÃµþ`Ó×ù€ák³š+c>8ìYöDµ¼#›d4™¨³²­;f7?ó2vœšS8ÓñÎVot¹UÍ9ë|Ž]0ø‘»“·mœFSÿ`¾È’H¿¬‚a$Äí—Ì¥lD£Õk¤.CêMë¦å ;§ò’7·áμï¹®U“Öà KƒÁs‰¸™Béòݯ4&/‰nãÐCˆ™×AeVÙÙ«/"].Ò¢_mù;+Îô¸Lí1—“··N{ïiœ“à4w\@šÖ®þ—ò£´H´ÔëÅï-Áª›åÚ¬xH烨‚þ§ÓúÜjsK,êchpmàûZï UgÓÔY'H¬ü¼ì_"XU‡–HÎúqš`NÉ¿º° 4gy°1éæs¶mwyT )>·£-{6P?¹ûvÞé„Þ›O^0‚AòÒ®HÈê䬄;rûz¯ø—¸öh»°À@«bª`}âÙɹ@Dz¬ÞÖI„N ¾VMZ ±ðVøù2q\‘§Kî€"‘¬~Ó…R v‚‡sþ´³¼•OLšé꬜ôÐCÒÚm@Ý¿˜ä"B::­i ìAÕ–îºë®%õ_õó•Ù’Û=—ÿÙS¼!Ç7ƒ«Ú“ín–^q²a3ð*jIýÕµ’zÈAÕ¹º‹Í(j$†ú¼ôg„ö,Yd®ÓB‰O[©Í4J›8Ùà£IzoEÆD]\i&¹Þ¬§ß©+¡oO´À͗˵‰p8Úým‚ŸÿùŸ?僳ÃËU<ÌXrA´W³õOf‚^$F¿wÜqGc¦¶éÎu› „Š6âÇü-oy‹ŽhŠªpº}óŽw¼£g•ü¶:„… ÊÅ6gU¥*!øJstÒk¶w>ñÄ®+–£BAŸh´È€_Ø|ºhfBº0}35œÆÎæ…eôé¸I˜*>Wù‘€*ÒOêf¤\òl§÷ðË_þ2¿³WÀ³3zD[TX‘VÝ#-HokešÑik›µ{UAðõÙßjá8O–#Æ2…-+ÿ¨º-Z£ilHZý w»®Ò«í/Ì?ŠÁOíB„K7GK­Uv'|v]‡ã¸¸ à.ö+Ͱj¬'(Ä]ì7Ò:…äèÏÓÄ6×ÅåÛ"Ñað#+¨'ò±Zïv$yB7FNˆèð—¾ô¥¯|å+_üⵌ^t¡ cn­Œ0†¤¤#m»e % ¦IµâûÅÜÀ¡¬¾_ø™Vàz”ø•±º$á.qW`ºGZîX”6âêDâÄÝÙœ…,õ6‘…ôÅÞ°n øÛ ¦¼…JÖŽÜõB†‚Ö”€£H¼–µj˜5u70¾ÆX«t–P¹ÐCFÌÝc¨}ˆ7iå0»ÒÒÃ"ë4û„»3ëR°… ïÏ}îs\RʲôH[“gŒÔæqEV‰Ù[|T¯’ÖáÖn› ik›ˆóSæ\D™WKO `ŠPQæÉþ$ø¥÷ßà×mM¸ëËÛ 'yçývÞ– š•IJUýfóã€c£ob/ÞÑ+þWÍ–í µÐTv_™» I³†Ù”A| kÊÒTƒ¥–œÊôÔ*Âz{Æ[ =8 ¶îÀÜ9s&¬ º‚x–új¶º³íÛ¯ø‘-Ž)ÛÓ­* nüMŒB½5€!k2QøJ©`äÈÛì‰ìüI.¨zçNíl¨›Ê}D]5€ b]êÝõòès/Ñåq œlômpÑ6l÷Dų(=îV еoiO×€xà“RìMÔÊq,àí´¥Ìäyú‰{–Ä$F‡ý9À€5N›lW!‚˜y…ÝéJ3µ'šN¤:a"vAü-æ,ç"`µqµýíÓW•ô×zBë[ßúV®±•“Ĩx×ÅŠr"…÷ÜsOßk5Eë«úxô¬öX¡lï4JkÑê<úè£-–Öï“3Í| ½Z ALØÕLxiO P©"­òš74* p“z-!\P¾Ô ‰‹s[öí¬â .عÅmÖøâ¶«D-ì^ÝúîÁƒ×Ù¯¶é"dzØíþ†-±Q 98Ë”i_¢¬r>zäªb¤o~ó›u[§l¨ÄºœR±ÐKËjIQ–ZILU6 òf# ÉYáõ?fßIaïyÏ{$“aÏ*H·ýùÚîç^í¢ v‹Ò²FØ„{ I¤+Ð…žMÌîd SÂZ6–µÇ]²ë”¥Õs>a<¯ZoÐB‘” ûc\ =°Î~ðƒi _#ìüKÊ#6ÚA+K¢$CTZÛ&Õ¢-Ü^\‡i…ÖUÁõ«_;ï©(¬‹Ã…åM5Q¹û)¾÷º×½®ÛB£Em,ôª±¶ Ia»©vÒ ÃãgŸ}¶÷0îØÚu!¨ ;][àO”kþ6¾•J­²ˆ,½ Œ^Û±ûMÇDtäÝ3cÿ ¦<=Ö "!Àz[â¦)±c`ƒiF§F!íá¬Qâ°JຫëCæ_ÀÂJþ,XZMoU^mß[˜…˜=ß“i“i~ [luâó\mÿv¨þ”-ßC=ÔTûdD¦ÍøüóÏ pìmI@ŸúÔ§¢3¬˜oûÛ¡Ùß›g0hV€Ô±Ðâ3ˆ|-$éVĶó,!Å’…B9Eܵ¾Q ˆžPjê\ÿ]=6¼Ïš2Å@ΤÂÎÃ×Nƒ&”¿u³³“O£ÿR~z-¿SóE̦ØÑVLR2kÃÍG%!áO[Ô”‹ fEb¯J]­H|²o÷|xy–¢M`mè†P0€…¯­]ƒ¾ÿþûEG³"u±åèUO=õT„d=ÕöosYÒí±ÇS+öŒ#‰¨rP €U‰yg$µÆWŽ¢­ÆÆÔ,Â'AÔ$jÁškÊv?»Pœ±º‹@ÀÕ¡KÅ"Ñ=}¥Oð LÄœ¤Í|Àn¢aRÅ™ÕY©9ž[lq´ Hê¼ÍÝ¢ÝU)C¹$M ð´(¬Rzãm·Ý¦Nï^¬4¨|ä# HŒÌ‰ÇMµùô F¼æÖqVëöuýòË/¿÷½ïímæLŽˆ&“0×%÷ ¯4Bóo’=ËýÞî±K Sßj ȲQ än¹›Ý’äÖŒaº³üÑŒû³Š_¥,ßu×]2aðÙn‰#ækêˆ+iG®1ó²“çZ8 &gl>¥± ÖV;•#ò*)š¿v$u€`É]h9~C»nƒ,9¢E ä/ÍM8 Þö¶·%T‡d}¢ãÜ7Û}èC}…*¹¶uX/‹Ï_ÝB»ø?nAŠ„ð(‡V ºÛÙ"m–Õ8ûz³h#ª<…¦1»6<µt[Çî·Ö™×3ö®Jàð½Í†Vz¬º*A+TÒeÔw©`Í¡¥Ôó"Ihw‹}@œƒk:ËŠÉõÔUz°ü¾À¥º²àÙyĉZÓx-ù"ÊNÄhæÖïA½ZYmDºyQHämN÷6†ê‡\Pß œ]º_ýêW!ñ—¾ô%;c+EVD»bcÅlʶXr0¡·ßL§ß¡ïI–'vÿ±Š(áF€¬`¿¾;ê£Bè®ô!aø¢j>’°Ê{>´€¡î”þ³"Ws£qÔòíöÈU àë®B0&>ˆñÐò;™Ëhyä‘& ¤bTš•¿%jqûS/iÝûoÏ ¤¶.ÂHÖÌ[\IAô¥—^ê74¥ R ‰™~ú³‹˜t'‰Ó4`xŒ$Ré rw`–i¹õt‡ Õ²)-ú°vÑ×3Už–/íe3¤N§„w”9\øŠRšM¿a^X»´Ê³†ïbFµ(Q4”j„sÛyj¢[Xb¿BÍüíªž¯êŠ0†nàì B» ‘cC-‰‚¢AóCHl ƒ£Õq¯(9}I#P‚ôÇ^9–ØÃhÀñØË-„2*’MÈq__qs¥¸´s#HK¦æ5ÓÖN”VwzÏèèÕ8§ºœuRÈ+Üê}¥!õ]ºlŒ©Ï5’¨ësÏ=÷ôÓO/„¦ûíŒÅrØjt¡Ÿ¸9¨¯Ù ãÔ'.ð[¸¥ARz^ç`r¼™³fˆ¶”Œß fº·j<¢×r‹(C¥9¹gµÔðZb­¶Y”oÎà–€¡‡7„?ŒYqçtÈa×2Z{³^Õ,Bb¹4“ ¹ƒkkˆ+érsy»¹‰?gšá@¸Ê_ã +Má6ØÙŒÒ{Þ󞆊õ’$íËE+ŒÁÏ} ÌÔ0*²BÀrÌÈåŽâ^eè@(ºÛyòÂdB5w#t:gµ%%ÈÆV;?Öo"²1ÂØÊ¶š,V@ÈNŸhOô/ÁY>¢açЕþòÍÁZ4{Ï„jÿ3ÿÊ®P_§É ÐRF`ýÉwÉæÕNeª´Ê É7Ô¶iešèY Ŷ‰¾Ø¬Û¸ÚTt´>Í #cÖ0BFÖˆF |yÌZžYŸnq§­všÎ°D5Ç`$šêª®+4°^ÑÃEh+‰E•Ö×¢³b±XÑÕv¶ÚVèæ0¾ËrÒ„ßùÎw6«ž}á…±ÕLÄ#.c&3ÏôÑyKÃ$Ô·­”u€'¼Í Ki¡>j ³âÁÜÍ3ð °>ø Mt©Ù£áë Ñâð’‰cio5ÎÍ(“üŒ\C¸LC•͵öÚ§3?.™ÊôÔù/Þ,ÏAOHÆP‹yUÐ~@°”¹Êûî»OC¶Ы»¿/Èà×VR´ ¡e­ì¼Ù ,Må w;OÖà$@jO›³aìeNfæx ¨ó£áÃ`-ÐødÚˆ ë/[—¶B¿¸AïÄ‚®O‚ÇœN‰¾‘ôîyøá‡›é™ÞÆÒâ‚M*(~ðƒìµíà–H'‰®kO-T¡á`{TÆžfµ+´¼ä³3DoÊÊh<ÅÀ@P4¨Á˾¿ª^´ªbwE(ŠîP)!ük(rm#D*vªÇØ8ÃÔ$ˆæÙEÞÍ”ÆÜŸaC縵?˜å‚ô¯Ý’-›9WÒ_¿r4I±˜.o1üâ‹/bÀí›~´½¿×Úø`¦x~ “Né÷³3O:mGýH­4“åS—©Fkj¾(psä&|¬F¹˜$üƘ»a’ͪ\Ì}Ù:ÛÁBSÖÈÁÔû³/^e‹†©”°Uݧ³³–µñÛ•teÆjU~uRÆŠÿC‡}ôQÆK!pŽç+$÷ó8‰äZKÙv7¬mDA× ûµ¯}²”Ń&€ÔMFþÑNÚ[õ¼Då ÀV­Gú—2þgáŸ5uãgŒH²¢ô­>Ú¤V àìÖ@Û,pŠ0Øê©G}®ñ¦ôËÄFŠVøt)» ¸ìžfݶ éQ:t©×e Wn÷æ«þZ® mK€ÌÆc¯Â'hçMµù´^J®4n.¼À,$8Œñ`ó¸š$Š,h÷q7%`søðŒ”˜ = –ö‰!tpÕŒHÚO‹bEôà‡Ä¼ªMf@Õ¥KÝ÷°“ÿõ,Akg¿ÿýïÇ8ù :žy摦öY‰[ÞŽD§^NÛ-‚àQc ¸{ÄÄŸ)» Ý‘Ù{ÒøÛÓ %ÈTƒ¸ücLÜk°ÞýW¥®È„§Â¯ëGïÒT˜¥B»À£Shv›XD’Ÿ§¦ÑÓtd¼i·Üí’»îºK„!Kù’éÁ‰Íd«LΜ¥ñ]¬Wî+Ü«¬%|V¤èJƒÁÉkÛŒ´Óê·1·ù VÎ!€©3(ºoÍ/u_Ó°Z&Îèv¿:0ò{ êngs3ºáÁ=Û|ûîr\zð£7Ç>ð6ÁßüÍßD¢×‹"p.RüB˜-ÆôZ Z-£Î£]X§W"âã?‰[‘ ¥wß}w¸‹ù·ŽA«½¯/{[>|íóèma˜î£íÖÈ~5ÅÁ"‡_~ùå:”@À”`11úÄG®ù!$ ¾Œº4$šÏŽa2Ü•ûE³ÔnS©‰V.>/3Öøú›ƒf¡Ø°_ìyå"ø¦'i j< 1 ˜°íìl¹Ö †¸A·ß6U¦ê½ÄÝ£ ¶ /ËU¼ÊœK¡ci¢ A¡ÿÆÍÁ)Ô>ÚhCJ^šÎµç ê}¾?Iœ/V-ô®+]_‚Oôù±Ç[sXñÀÍ6Ó‹ÔËA01ãˆys^£÷ - ž¼µxÓÍ!ôNÔQé¼ð´O\‘¬pú¹çžkƒjj݉ºôi†hÐ:s¦²šÒúÊïÝ-…`á$sÞ¡3$[ý:Hkø77GSîA‚ 9QÔ‡€ÜÖß”qýöôUõ¢ðæ@©XïèZeIDï·MÔ7¢À¬ù5³¢,ö¶ ÑÄšg‹‘i}E›v°^H:¢¬u$HÏĉÉ\lÔÁUJ.16ÜæƒNËdŸ ´éâdº° Yhô=÷Ü“$™ºátò¨ Ë9MpSs°ÇWäqù´0aÐ:[¬±ìö« àê/‘n]ºZºøÅ³Ï>Û†€™J´OFŠ1 êu'ݯ0b^Õ}”3y“•'&|6½h/¶„žß›|x–°’®yä!Œ]Òâ¶Ðí€6DüLr)œƒùíªBL¶ê„¡£å¦Göj\™t#–6 îýÚç´E B¾#®˜õuë뱉f·¢äàÔmÂqLau4¶©!xl bŸy½Tjš¯nOsÖ%g\jY‚îès‡ðýÅéÎ]tC˜6_ôù*S·¹À0$¹ú­N€éóñ>ÓÇ¢þÍ3Ö% +æÔ$ŸOŒŠý´ÖÝÙàZúV0ÜÕøUZƒò¡½-ñ*œP.VéX&žžApѱ8øU¡‚墷”~¯Ó{za›µ‘ø"f!JW¢­ nnEî…6¤5“íw éá.?|;©-~Ö‡=ëÔ-œï¢ä|•Y;Áª±{ô¹nz-‹i«‘°O‹Ì’ªäª7˜$‰>§ë|¿Á5D矔Lf”… «Ä@ff'€‚kO1ã¯màÔd'™¯!BÛ…K±õlØ@ }ûmî¤n²#öC¯|“|5ÇUz°Ç3ÊOIÙˆˆ-\‹÷W€g2 ÓhèÒš¶:m·(Ò¸eåºàñ¢½J—°­ØJx/õ!HëÎŽöºÈ²¬Ãöbw:—¼4ÂõÑ›£Qõi±Dz õ™´Du°¾1Sm¿*It¿Úeœêîêâ€ÎáÖ@+¤™ï¶‘3b„Jö$šgëIbjÝšÂ<,D0m…Y°y­Ïàʜ縊σóî[ èX´ºeºï¾û6™¹!öyàOZnsõ'{HXÛChÖæ¶ÓRàÿÝSÂ?"/máÆÝdºôvÊÅ×¥Ù­ÜÀZ‚Ö¦2áßäOð#ýÀü@PäsÕ>|•Ì#CIÙyèX²  !iºÙ‹Ä+%:¤è q¥oáh¡AC½œ¶×Ý@h•–Tšãßü¯G÷ö³ŸeÇfà[e< Óø®H´ÎY‡®Ê.\+A¯Ù†Ž;(>ðÀô]ûœ‘ᢨÕ!17¦]j±L¦ÿ ‹†­j{‡Ø½g…¾²Bã¯ÌŸùÌg¸»8ßb'Ýß™ëØ)¥ X}ñÔ$µr8 ¶AÐþ ´”NØÃÄxgpÆ>¸ ºW,âB/Ú”ã©â|í˜îdb w¹º³‰$T²çHônر…í†9˜Q¬ +V¤+WY²X¡•;1 ,*`ˆƒT± =hûí“ð4&M–ýÒ÷`´7Y±97Ž`ß÷TúU°ï±",m_f“¤Ù¥'Á]‡;I’öµä>_Û—Êù$ SáÆœ”§£.ä&'òîÉ\²Ðäp$£-‚•"_6D‹Ö>;…¦ÎCÖ¶]ãiC$Šžÿ ÍÖªG­\¦QæV¯iv½ÿ:IںʛDµPöG ·nóaœ’*iø­K¡Fºûp[SG¤RÖa oé â‡»3!97 f ¬¨¦Ý–I5&ÝáNè«P D/ÉyÚm' ŠªiHÂÕÚpm…Ð% k: FçxÀè)T€áþÅÉÍ—* ¤O$Ù¹hÌÉYûJ+ÀàóüóÏyÔ fäΦ¬éŽ'd¹ý½´÷¥œÓPdu\UÒŸÄO™S^Qô…Xª úâ‹/ ‚lÎr½û“( ó„©Ö+´–Z¨~_H,Ôk[¯G¡6)¼ï™èä†(C†õnAÕ–:izŒØ‚=•3j*ÃÅmÌè`ÐX 1‚U__YÔÞ þ§bJøˆZš/÷>C; K‹›¤µ (Wl¿a·ÛDu7÷föB[Ÿ3€û³ÿê|IØl­Z1¹ÿö6å™è…Tôxs U”Þ!K6G”¹å`*>O¹*`]• ÊuóUîBñu=Ð>R€¡¶Ëâ¦/âäÚª²Ó›R_jzw}âŸè3ý—j3µÊý× &Iõf±-YØ áNJDôC­^Øô„÷ÛH’§h½³l(É*4¢Ç§6àöb•2ÃëºHœd¸Àþ%d´îÍ"@v¢2‰ìVáÍ*$"BsصÝ ·¥ñ÷es£^ÓÕ{ã°i§60±1ÔªFÞð8$F™)Gºt­^[uM©O´*â­ŒX©¯¸káLRYX~aÂÛÈŸ­EcJA’®Ù·…k|Ôqlæ>úh; ¥éÛîñ~›pÏZÊ`£Û  Ùá>“ uR¢¹µ·ø”ÚÔ¥ñ´ÜëÂÇÇ%ß²sd8;i¾"/Šš~¿œ|S‰0X¬…ˆAý7ô%gIümÉMmS3ªGBìWª0ߨ¨Bž†^"S‹üüÉ›Cµ%e{\%¿ À”–d3Q³ü#ùˆ,UI#¿ ŠŠð„²÷ –­5'q(€ãå-Dã£û6 1ÜÍ0xÓ¸T ïPt~x‚¢0w!•Mûs¯Üõ Ê­Dj°&F09Õ‘ñƬú¬Š`ÐÑqÖ_¸9Ðí@õØcWڔu)@ÓSJ[cÀlO¨ˆþQÂ<ø¶¶45a¹êSŸšëDâN`$v+—‰ëWàmÃP Ì4»NÀ¾5€™w£oß ^W£sEU„x‰‹Žb„yŠß}÷ݪ¯Ú%<ÕÝÖÄhÉhŒçìl á4âÖyWÚ(­ Ø^#X+¡¡!9Ì Xâ¥ÝC"Ó²w…ŒƒJ/!C5 ¹¬lUm_ò¨¨¼«C©€×o½ro|×Sof¿ë—Pµ×ܼ7@P_ç7ŒkD-BÿŒq"±iS|ÏÒLðâuxû¢½5€›*[L¸øþ÷¿_Y=Im"·ÞØ4bWÊÑË"ìíý5n㇯=îm"F;šL×UDkߤÞüôOÿtCüíßþmöÎUWUÉÈ·ÚXÊÇÉüK+ÈRX|;݆ÐÓ/Õ¢ÑR°Þ(³44I².(¾«J° ÓÌ•mJ!G]]ŠÒ¿}B‚Ha§ØA«ª ´Ík6,æè¦ÃœŽ×{¶ÃhÃÌ·q%¯Q]e‹ŽÄ…gBôZÓŽ–2ÆÊ Œ77ž­cðlàš°Ý=¡E2H¿SÔa®~j±¤Bþ‰nŽ˜G  xOÁT¼\o=ÃL˜uZDt÷kïÑ~’PÊ…Ü×ã)­f¬Üv›0ÑL!ºØ’Ø“u¿„ápÝ(p° ¢ÉfBB«Zœ~ÅO²úV˜ÚL[æVýßñê4 ‘”<›¦° •Ä%F° `ÔH6ìã*K–rsM•,*¾®ÏìNiomrú€b…<Ò{ô‘ïæ­>¿.*½Û ©Ñþð‡[£ˆ»‡ÌüüóÏwgk~\ëÔ¨ˆB øî„ž\›¶ö6ÆØ´Fµ¦[kJ§|²61»ß¾( ÚFam$m8KÙ`z9Ge[±Ü¤*ÊF¥þ*û°x[6¬É;Â[V7/÷;€ØãòÔÍæ]°¿ÇwÙbûzÓ,Ú|·0Å‹u††ÓöÌ ½é^pB¾"o~ó›©O„¬®· ÑÛHh¶ÅÂl ­Z Ú ê@ÓuMzÚ=äµþ\»GÅϰ<³`Ùêqù[VíßrG•Ï|æ3{÷3w„@„%®Ú0²ÕáPj/Õ¬VÛ˜V*h¦Í!¬Ì–Zº¦`†ê_Ý„MŸÀL÷•Û²”$ÑùÓ›²—˜ÝExlÙUÌ£2E)ƒ±÷Ö~×»Þ&ÑcKÐ{É·ÄH5Úe*¨£V¿i‹’Ž“Þ,ÿŸ#A®\WH³‡ý·gɽTÏÞŒÊ-Sß]®©¸ZÉNÌ,­)"RÌõDæ$tCó(÷'?·¨Y'Ö–F!©ž"¢ÀMÞµMƒó)ÎþÕÀV„ž{ÈÅË¿U@<à ¶•ÌØ'Du©±Õ q¥ Ý lŽíN9±Zv°E{?Åó-¹*?88õjµsøðIŒŒ- ŸóœƒÍç¾ûîÔ.Ù°ÿBt1:ìId­]Ús†"~xεH8зúìE†@Ê(KGòšõ®·'å˜üµê‹±:º uCŸÄÌšC´æ-¢>IÕìäkÛذ ßñŽýKÎù_ ÐÞªÀò'Ú ÈÒÎm#qž!ýÙÖQ¥róóÛ^!Õ­Ü}jk‘õz)@“°‘ƒ3‚ØDPYL"¯°MªdÿÒ\ˆ„¢×N/'vv. Ïæžã[eQÒá“MÀض¢Þ­Gú׿þõj‰  xÌòÕo+‚£ÆÈ2;‹…x<^Åw¿ûÝ xap>°uSÍkV:Þóž÷¨È  ŒÍ…_eÍOÔŒ‡=\=Ê=Â]ØW¨Âôc,Yø;$¾Š³.ѦYŒ#AM›ž3ƒY\V*©™tO„·ëáDh*PÒ´o¿ývu›Õ ×>¡9ôN¶$uÚáMÛK"P'T¦ÝVÊf€üêW¿ Š~çtò§¾5}`˜&ˆQ´ ÂÑ´,B”ŒrLªêÏ&¨àÄêsTîiõõÚ.÷)f$ÉE Äå€ui鶆¡yC/!ЉÙI kU¨A“ú„‡h_UÒ!VI$šV.¶q¢o}« á³p€ôÕþõÈ#¸ø•;P¿†Þ* º")»ø‘|¤‘5î¾+$›i¾‰ÊàÛŸ‘V¶Ù {N@—ÉZ¸ƒW/QˆjÞ0¿ ´ 'fQZ,£‡(h.áîÄhíx\CÅ+¤ðlB¯ŽÞýªÔ¤~½¨/ W œÜþiä˜Ë„=D<è¬2‘èþ$uJFb™Ž~kë| k_èØÖîJl úÐ öÆpn¤)*ªïyøá‡ÉÛ݆´jlÖ¡£GdÌ!D@‹s¥}þæXâ¡^5K3diÇ4È{ï½wÕÅt íC¤ þ]jOÀP`±©bÝêî(?¼ã6„J ,$\uˆ§€NÐmõ¹ )ÁX™Ì5H›ËAk>Ø À4@J,ÏäçVUýñDÖ癛èˆÜWÙ¢{þ·û·C¬†ø‡ø‡Á»÷¶âyÁŠÜ»á½ï}o# aEÍFô·j]X¾. ^pZË z¶7§³¶ ­T×S…WÁþ{¿÷{ÃfÊqS)^4KÖ üŠVúoïoÏE •$RKR™v¾úU-QJŒ§2ñÉc1¬¶\êð÷ÛnaŸtM0ì¿Ô$Î Ezø”Úß+LÚE×®Œq'„,ýˆTŒOßô`q è6 fp¼ƒIùÒ8_xá…iÁ²EïÏ¢µµ£Ã í£6D7 éývQeÑölÿ…Ç2¤'fÞV3JÕ‰Œ?Õ"'ƒ¨¬ÀॴL,³O«“… ³ÿ ÒDèɽðF—Aíb-4¡;kT½R16R¡ ÁÝ/Â°Õ fˆ3Îj%Ñi&k²XoëåB5äI(S´ô>ü¡ú!¡‹A®M¬<}wGsxa› .´Ä'7˜ÞƒÝvÈbâRíd”$§KðjòŠDíI¢"}"åd¼”…%¿ô7-( æE¨ÉV½G\‡ÿJ\t)™ì*t“õ SÜVôEkîÑä¨ဨÌMZ³°>Í}´¨2àU%t±sDE;‘uÃ*Ûp[¯6W;„ZGBS^ÙÀÝ–®6ºËÐR¢÷³`+N¶Þq«*9Jb§‚²¬KÜúhm|v>Ä™š¨•‚XPé•M‘ÚÚE…($÷”LC¥ÙeIÝ„©5…!sAVbcäÝuíºØ˜b&¼•âV%ú ÕÝÚgÝÌ8Ú'ÔÕÒlD 0gSÝŒ*dø[¸·ð ö@”P-Àò3ÑÞp·íÙç#›"šFÔ†€–h“ÀÕ<>– Ûã³V®8gTQ@ù*È1$©×¾ÞÁµ+óz\ ÑXÂN“¿„¬ÊŽ^˜( Îa:«S S{´)³_†ÙB|¸ôiÃ$€7©Ç£O€×ãÍ‹W8*Õoª¥®N–ïžE“ÔZfÛ²_»7æ 3§Ï-Èr7âšüÓíŒ[¸Í SÓ^ú N÷Üs b·2’­’ÂØ­èK¨hxŒ¿6>eñš¡+œq¡l"ž½ ´rï×|ü”c¬Éú€‘šÁK¡ÿΛ£“ôh jYµ,#>Aàjâ=ˆÓ¼~Êth0É‘‡ü4<êæáaêÏ`)<ï¡Ñ ™Ö²ˆ2èæ§Ÿ~ºDª¯Ó¯^bâ»®A­nuüÁ"ëàkËŽJKÏA–IìDvÉU%ý¡¼%4n‘7zZIðmd}2y;Ô¤3´¦ítM û³YµW„=s?hRq§ÿå_þåH}ÿ¢ÌH>ˆÔyÄCÉY!æC &wÞyçú(À†HHwµZ” ·€õvÿ_Éù7^9x/º.]“]Z87”¢ãžÞC*"Ž«·W/ ŠD™´|­:éŸ)¶)öãÏD}Éd ß89™ÂÆôÁó†Y´2Iì·pëôŠ€´Ž¼ ’ëªõˆ"Ý#^¼UªøÅ³|xîÚ¿­W[¯™D`1'™z\§mO°n¹æ|ÔìA†á¨÷÷ßV[~Î"Ý!´REÌ~ÝI–VïOjEçHÙŠ¶k{ak¤¨˜4CY JÇ,"H¬kòÙ8ÿ範¬T/KX²±Aö9‚+x¦†B–YCSàÅì¡pÔöé¾­¤í§¾u€Øï“mºÆÚŽnVI¼I­½E ~·EfG¿AEC$pòNKÓ&H—Ôàû/V×:¨*â+MuÂerúÍ*|2ÿèJ¢Kæ´LÝ`ùBeÅådpþpÐ"§ öŠÀ9y°ŠãIðíµ4è®LB‡Ù7šWèËq9¦ÞÍÂâ•çìÁf “á±Ô)wJ¶Þ·è»kM÷m÷Ûm¢òŽ(]WÅE·:¡…tÞ[Óè$öï,€QRu®#puŠ*/½ô’]¯ÎYGOµWqë~ï¾ûnóŒ” F—I-›kÝ?,·¶myê23q÷ ¢`L6¦± í~OqøCVJ œšÓ–Šz½á oPס¹´‚ø*=‰È&ôN³rD®ÙàØÞa°Ôwûë XQe9PUT·a/ãoüÊ3 Æ\yêu Ô¡–üôÆ|Uê ©•>Ú€áMHŠuž2eß”ÎegQÇÜ B¤g/ ödÂÎe$ÐzW§E÷e8¢cêA665ÎUãG¨×Õmé¹Á)€‰Voxo¿9„µêxÕìæ7Ä›[Ênèf ­ô -¶/rÄÊÆ¨H´_ÐU怙oV$€ÇìÏŽW’ÙvºŸÏTô®Ñ¨BÙß=ÙÃ[؆ʠƘ£¢óUAwíáÍ"‡éjwÜqɨ!ö_qç&ØôUÈѺ̩Â÷Âì T±4 †Î Ê·³zzÓt9X(NÈ2ç‚!Ö`@å¢×o ÛVµPHlW¤¼?a:µú­ŠÈȇ“÷׫Q§¨}N–>j G…xBñÐŽ6Œ7‹¬#uöŽ×5MZ*© 6rU»_K ™)«%oj­‰ Ilë*o’è'ÎjZZQ–› c|ÈWøÔZ0ï1D¿¶ˆ‘2ùàšô…Á|ݪ %+`CÐe0ii‚Dµ`¨j­[¸wß XÎoÓzuÁ̺G€¾²Ua aUáÓ+ðsbÂK%sdâ…¶!ÈuíÐo2`S‚ ÌZ/è‹Ñ’§æKV© $„i"ª¦/ÎiI.Ñù¾¾ª¾AºÉ¶æz>*s«Ñ!+‰L‡8sïÇ%ðImÍëÖþÊW¾Œ[¸w½ë]>èÍVQ‹ÖBR׺ð꘨:c'ò9u 6uAЮ²™„ú’:úJ7“‰ ¯Ø5@>Ý#Ì£…[‹(õk D“á(z°‹­šˆÝþTc¾v¥ÇE’q ˆKûT ¶Ï±Mªä5œ–2ü˜£¾ÛzJ:®F8v[³klÊJ;„mpHlã2ô9YÆ€E¨qWk#Á@Ôš\²#”K’tfípµH‡º ­È]wÝµŠœÇ’”"×E‡5þnbj*"§Ä½µHŽ þÊi]xÖ"ã`¬ˆ€r-²{}âìóÙ=Ê0´@¡;Ìî6‡dà Ä—¢2䦭 Іâ‚µä ‰…s³Ð€yøIÑ4Ql'^õ~µä;ZonjĽ‰Z‚gíW‹Léï—<¸èö¾Ûr±«xÉ7†ÁbE“ËG/å—ýñ›Ãî6CŒ£GP£ïN¡µ’äiÌ1Ê¥\ ¨’º98'¢¡5g+O°¤;Á†6SP—F¦èµi#RxÕ·RÀ¬/c‰U-½ì?Q%#ÑÊkhöÖHì¸çž{ˆá=Ÿ#ue1Y4`¦‰%àXÞHh%½ŒY5ÒBzAd†fQš~Ù:Èwóh hœ¼ÎMùÖ¶MDAÛï½Ý· É[”S`hÉZVN¤@µj¢ÓÄ¿öµ¯I{ÅݵéŠP3Iö'þ$:•ˆÎ$ÅMQåe~”tô5!J1\ÓT­yÐ7n¥¶ìgÓÑO]q2†[J—²Aɧ›)”¥I;?öEB–€b±²Ü˜N›}U8. ^*¦•®DW$üÁcf|F:ústó­Ì@ØäƒP/U¹[³IYz_|úÓŸî¿ u•!ÂQ:2ªX)n™“§×jrЪöʨïf„Ÿyå Í$©ñ&B"¤ ¡2™S‘ÖHŽ•sÀï)!Óˆ˜ÉPr`žeö¢4xMtâVZj]0f@´œe·QÉBNˆ 0¡i_Çà‰ ,UMøU"cÒ·†Y.[áÞÙ"óÈ-7Âv¼ŠD÷:5)›†Ò¼ªÄžÎû P©bûâ‹/Ű“`¹qð/5ÖÖEͩ֗ –ȦBEk1lqIžL6¢™¦†õ]r¬öU˜½ƈ%j`¿üË¿,²›[ÊT£¾«Ö€’ Úp3Œ hTAâžbi÷Ýw‘"!‘VªÚP¿=ô¾WpKãsî6MUºAV®Š•¨¨•Ò¯WüQÄ“1ëêfn%9“ø¥—^¢0ðÃQ†©¡ƒð GlõŸ}öY‰Ý‘·4¨kz¹ª ÌUP_‘(FP¢™€ ›¯ßp×ùÞðþŒévƒº%½™eƒ©aÁY||Bvè9è–ªó"XT†Sm¼14Té²Úà5„ëÓãd‘žbpåcÕ‹(Ð*,Ê ò êX{jìc^#|òÑô1Â0?˜2&Dk¶0ÖP.™ÕmŸ¹ãÖ^OÅ}µ?)²›Øƒ2-+3,ئÝFi[ÊPï—YC²¹n”kœìÖW¼‡SLû-±yÍÊîî¿õ½§Ç%)õ¸÷¬éÎz?ô«¬š’Kƒhc…”½ŒçoÖ°nm}\ÒÃjI’³œ‹Ë@¢¹´ÒÜøc½DÍœƒ¥´JFYVë¹¶ZXálÐ –¨Øxäã¬:0ñÖng5֦ͷ¬š¯jöjÐ9Fڳ˿ˆÙà4)$bŒµS ÏL £Y%²ªI¦$5k(‹±Èø¿ýöÛÙ1tMhG”ZâY€mµá5)]=¢.FÛÛ²ò¥¯ízÆCwÉ”~º¯I¼g<6šDšµ` ²ýZ­É=ß>¦«XfìúĺøRѯ ºÄ+V뀛P™p_$Zo—µ¹ªZhŠf~æ3Ÿ $l]ò»CÔ/®Ñ‰Ö¢ëœ¸`Ù=sÈÏÍøµ/iˆ¡]Â‡ë »Gb¶T;ÿ†ž0ÅÔ2‰WNò½ï}o`Öa÷å—_VªH™ y…lg$5H¼ZÓ«ß=ò$ºÆ e-«ŽÐA$¡†Ñ;Ø¢;èfM$HrÔ¥ëd#W¢µÐΫ¶àY]¸íiv͵g뺶EÏoHgÓ «ú&õ™F)|\<_"®t(DìAyV6zu°z5ë(ŽÂù…×0,ðP)UÞkÉ;‘—XÑLç2¬²Œ©iJÄ*/$©¥V)–&•Tá áUDc^qÈ •Ud’ìÔ¹J^³´÷i dù …šÀ3l˜I’1K¹ÀæécÙ4aA@H ýXñBüÏ0çŠÂÚó²0ê­Á"C_¿·0ÿI$¾EoÄ*Îu`râ`º®6CÕPˆ ªÑö„š*Œe¶Š›ˆœ€8CJ”@œî×”ÿ@{ç&YîJtLC2¥ò¹Ä‰—gïhêÜz…6x ¿e™JVð1éÎÛÊ]#ç‹Ïbè8ëioÛî§} ¤e“ŸãAÌÞcbâÀƒ¡t–Ö›‡Á ¢3\ˆŒsâ%…=›ãR¯½5€IŒÐH‰Õ¦·%1§K, cÖݡϴ(Q99ü `±Š"ð/‰Çëêj¶Øðú;¢éñs0G´•(Sñ°Û ®jK*y’™U“Vþ®#4•^¬Û2þ7ó7+}¢:•—¼øâ‹Ì&Ê—ƒ1«Â?~å`´â!zÎ’%€‰,Íwkéu8Óæ‚±¨ õ26Ú>hãêtqFùh›=…Œ­«1Á7¼ŠD#G Í‘°Û ÅÄ‹BR³¯É—Q‡2²ÉÑ|BqÁñ-– 1W<˜J=œTC!;,‚&ÍD&*áV`¤;V¿ä¤ú×Nóæ }Qo2…YMª¬ÊIŒI5<-©ùƒÛÙzï ác¬&“›—è±G}”PB|Aº¤·Èü°LåÄOÉ’|À!!ÁžxKô‹È]ÛVg~(M÷:¹ãæàHטÀ¸ÀÒSO=Õ°:ä‘GÀXÖê! áX ã¸IUk0€£žÙcÙo!ƒ[»{Úã½ðZ»¢sûkûö«{ôdÀ²8®êºÀÌ7{ײ¦BètúþH|ØFÁe‚àûë_Üé‘Ek„kK‘[Šð 7¢€›ä¾ö/!Sð,n=½¨}£üŸ†¥_zåPþ.Äú¥WŽw½ë]„G|w0f$ÚEE0Î~MA. khxذ*½pΞƒ«:©A#¤+µ$4@×-–]r5ÔÄìÈb|¦t ¢–OcÀx0©~jÒUEôyîÆE'Ééf¸>¨‹^¶ý#_Þ*ñLçcÓÑ=ICK/È jJeèbpmzJäõf2§@åf®'KdÓ•H©ŠÃlÚVÍDKÛ1-´0oîa0 ð+Kˆ’^ýÆeè›R`}{s7k&q¶t¾h†ÕæÀ¤Ya#iÔåFÂÌW¦/ ä l˜!R'­Ã*Ü+šÇ–°àð«¬ZÓtébúâcFÕ×ÇŸúÖpaI¬wÀ= ®ŠîéPœý+¸*¶>ìgoŽ¿yÕqb°mÑ& ,¬ª¸ „)(¤¢äúRz³=0³-b=†­2 …S¤4a¢ÛbÞ‘ñ«œ ²’gC–¿ÿ8XÏY^:N\jžðÑ>yðvÀÙûOš³Pl; ·é'Z/i3 ~ãßHcHÉĪq©&Íœ²ÂÃk'&“?ÆüT:U>¡ã¥—^¢’%éXœ;î¸ãBTv2ÏÃWYF Ìw…=f¬#6H4²ŒÒ¸Î8*†®¹_…ÁÊtM¶òÛ:†.‚uˆ‘ó¦Jd"Âr D–GŸÁvž"ØḂëýëí…ßzs`ÒýéÓÔÐŽ·¾õ­ üP'$3Æfq‰Të±¼n4*'º®¬$&ÝS,Õ½³¡RÇ/Èò©ãÙ!½ê¬˜®UtUez^0>˜A÷UN„ßA1=… õà±Ê®WEU.%wxyÛm·1Ñ1ß̾üåÁäˆEþŒOk°Km"”¦FÒûŘ'p­§ǥܸ¦Kx‘u Zލî‡` &|NÑÇOúÓIUiDa*ˉòˆ-Pù-oy 鲉ŸòÔ«!íèÍ„ø£|]M^]®ºäˆ`Äl13 0Z jÙ=h–D0åGÚ·pÛí Ïpÿ—¥ÛŒ ~”'§J=î6v’um„²ÛCb$šú´ë¼.ì· xE 8G;°¤M²¨,‡EˆB)/ÏܚϴÏ~ö³‘SëCûïyÛš õ«•€í…rh  üáN©UÎÇ>?[e#hÍ0ÎP£BÖ@+”JäèUÌoÝ¢ŠÃÅ‘\ù0«x|jÌ68‘R›O‰zö“í¡‘åݶs¯B±qtÖœ~Ñý€…Á&[© :Œ²S(fŒD·ˆÞ  ¾Z$>ÕžŽ?üÃ?|àú´]tgßIBÁš}—€NÚÐßÚgŠSiÇêŠö¯J:½!£ÑôT¥Åâa¼5€ÇS!Ü’”IÈ@â ZƒÐiY¸ÐiÇVGg0F„/¬f§Þ5‚|J[»Ñž]EK3›R®Ã2”Xz-ºÇRÈkƒ<¡rÂ2x$¸j“zi›¥×ÌË/¿üùÏþ…^8¡>ùùkÇ!O+ ´À–Ü«ãÚŠMrNèšÃ|±|'¾Ë>%X z5ÈöDo¸5€Ù9§ 5Y6Àæ¬5±Û$®¯@Øo ùvù?O>m Æ€:–ÜI\àu][/¬\iSÞPaF°@ZÊ&°$â^ nGL—côñÇÌÊ«·”«µÃ6·Äâž ÉnÓIïÔg(Àˆøá}™ùM^†œ^Ó"àÈh¸¸龯9Ý W©I‹æ"NÏ À'²^2;ÐÉý¹š Û"ØíiÍ>m '1§_í°KvÃö ˆh=(…¢?°¹8[‹7½éMÜÕïxÇ;Zî“ÑÓ§Sºþ╃”kå÷Ñ[¤qêÉÜžXW:¦+¾)èⲨ¬^;ë•‚H¨ôâm×seÏÚLb4%'ÊŸ_-&[LËï¿WñàAŽú*ˆÆŒ'"!æt*~…îNéëÛÛ"3‡M:h§³¢Pºv}Cº°TcÕ=¢¶º‡ûsýÚ5¶ ‰dãW3Ý£.«$kx:¹›’*½¢øÒ•y–‰–á˜4Çð´^e"þ08°IÇRQËW´RU[ ?ÝÉwìú3î+ÆèZw¡¾/¯v(m¹áâüV»8ø´x ®Pv[‡,6šá~Ôþ$§ùz"ÛˆöÄ®†—î$Žñ•ê•Ñnl8tWNïDNiÂÇC¿z^*y€óIõ¤.9xÝnäÏ-cVgT&Æ&pyAP$IÀ•g±Ñe&6¡UϪ?%BŠ£¢5É%›åî* ¦àRˆ§ŸªÎº;ÍùìÎåîÁ{Ù] _Opº¢3€O¹÷§ÓEqRéW ç°ìWå]\1¢Í¨«3Ëd¢¡o¼\¶•È=á"âÑè÷9}6V|]Ó<¾È=齟¯‚«QgÔ™Pz3!Yá´õ Ñ$JôxÃæQÏKZ¬Âââ!»3ð³qêf{[ëiñ`§Ê –NÎb‚â7E†Ò;NcÖ©[Û^íš<ÍÔ“¼fÊžY"=S¿·ß~;/SÿÒJ QñÙIW ™a××};h).\– úƒ kø qyÚî\ëçpwñ¼^¸61jD·£É‚äøü_7‡|5‘³Ë![¹„³nV\2_U'kÎAè~Â9….çÃÑa¤{ºø†7¼to(PxJ[§µ6û]<Ð)޽Z®žYÛk§(‡ÓèAP­[¼`#x6rj»±•j*(}Ø’uCð@{æ&‰Ä#Z‡ÊÂr…ê õ¼‰]âDf Ä™,&pì±ÇK $ðËL –@+ÖN* ÝOe’F¨?ª#Ö£®àž«üÁ'^:¥€çUZ –ÝÒœ¾&`1éQéÛn»íÄÑÙCXQN ©8ÄÈS½dQ"ŽÈòäíA½)|À°Scž°A$IëÂ×Ûº‡Ä쨟ïr#‚¥JûgÛKaxH·(h* SÖÓòhƉEÿ-®®º0+EĬ<É2•ÅðÀW…ì\ˆW,—"¾ts_ú,«b1xÿ)ðÊ¡MZ➎A÷ ˜‡qJÔ(6Rÿj‹æ$ö†*/²?ÛéD¡v½Þ­øâ¥C‹µ”†«“ –¼HašI°—0 „¢> òrŸÖ}M['¨¬ê2Z@Ú×i·¼ÖÄ9NgÁ]xà–åΫ„¬±^‹~Zb ³жRÒ&(Ž&x<_r.fL<×4¨Àhòɪg¤|µâžäzÊ1KH_[ÏØê™àêYA¯t¤úGôG­¯èóšç®ƒ×ÏñôÓO?óÌ3ô(xQÖ®ÌèAÂÚ¹_Ûe"ÚÄôÅ‹85Õ!¡±T‚w™ä[ùî¿5€mŠÖâÍo~³nèg£ºrRlNxÞº©Û.QoŸ_0þìYÓÁNyj&³ÓyJa§­ûBLó'ÿ1»ý—ìþNZÐ^x!rן&ŽHnSÞnë…š~èCRY”¬K«‘3y ù•]õÂZ ®QcWtYè[|E½1ïÞ&º§Y%œ¯.áE¤ÛiºŸöq†£ŸµÅ¯²E p²ÂiøÚ¡úX=º= Îî¿Ââ#Ú§ëb׿÷{¿w%¿/„,øMù>'vBúÄïs£\(Êgo{7>úÇüÇ¡ÎË/¿L„^eµ»ï¾;iëilz‡¦8i¬xx‘á«°ËñWböÀUö”ø,œ[<½L*0¦\½ûÝïžÀ±“Ÿjàš‡m¡«ý^ à8'UuB`ë¤5J YBcÜ K€ÓgýƒSdc™¾Óªu`ƶG´ÇkO\Ÿ5{~§‰ÍðuÁæ,îÓHd€L¶øð‡?üàƒÎóÁvv†€5N-5TgeâÔ!” ¨¡x[AÛú£RˆÝfOЗºyd#J „ó\I›ÈˆÓb8^»‚%õß[í¶Ø¯¬ Þ·H.ø>áíÔ¦V D63äø7Mz"Ýwt¤{N§ )lqzc–¦’ó¿Ó¶Ï(O’KƒovÊl‡ž˜¡ìÃ?,—DõwÊÒ$)ÂÔã?ŽÝŽõÔðuˆÎ’Õu|Ç&dºjB??÷¾îpq‚·é¨”ÀÓ«Œ›F‡g¹~ €GŠÝIXìHw'jM ›¹ãüs }Bñä àÅÌœ)¬`Ôxx|FY_ þEH¶,0[÷¼m âO€—GãHoLæb²æG¢ì~üã×ý e8¶ û [P£×Uµ{’¿L>ikñáäœi|-‹2¾–D‚­VÔ ‚1Ϙ5[Ç2B<_p+ŸQ ã¸#¿¯v=ýÀÍ!è`zÔy„›Òuú’!ßÂE^mùšÏ¡ÒQx—êºèžUYpî¼8T*,Ù8ˆU0SF\€ç¨Ð]–ûW›#/WðW~åWС…¥žiæ5“ûà:;¹ ƒ§ÞL-ÚùêÂÁW‚·+wÜqÍxÜ•ög4@µÙU}‚:ËöÄ«3Vd—ÿžY¹þÀ'ÊNݲ|6Šb‚œ¬ê»_ß/DZœµÔhj\³a…‹!ñÌ“Ô'îŠÙCü·ûyòzè!tñ-oyKsD{}v2Ý)ýÓò‘œ[˜ðÌ>µägÔ;:Êq'·ÝvÛHñi'™•`N¤SE>©4KŒÿ©Ÿú©Ç{ì}ï{Ÿ¤Ð­éÉ€Ï8!˽ü«Î“¹¤œ/M-±™úëOög‰kãÖ¯91ëcÇ3Ï<“v¾ô»™kÎTÛwF=e‡Î°Æ[8 IaÑVvCD´z(çê†@ÇSEžì½Šì6„=1#ÉD3°NO?š+úu YËr?ƒpO!ëŒÙ!¶¬ …£RlÆà·¦£™{Éi) BœKˆmL7ý{¿÷{Q`is¿?ÿó?Ÿ¢EifûTmUæg‡†pðõäµIOs˜žÞqufOÆq­µŠ~#¼NXRN“EõV¹ß×½îuë_´º/ìjD0ì|E›û׌æÃæ•O@žV‘I[|NÝ>E*a=:LÌ»5©{üb ¡žøó¦7½) /D^Ú×G>òvWÒ¯šõSO=…%këçÓР_MîÏ´øÑÍh:¶Þ¦À"4V}•%«ƒ¦oÅç©ÀO½vÎDjÏÄ‚÷VŠÌf2]Y&øª¬4È~ö|ŠT¤SÞ>ùwûìôHžIŽ»5f$²`"EXõEÜçi9VQ]PKzTóMŸN{&³®ôÛ{PþœÁ,gÎ’‰NãJË©¼ØÓv€ -=cׯâÁd"xF’ê}1ËÀeÁøô+À¼™>ཽ2J ñþÔŒí›åÝ‚“?ÏTÇÅhN&é,÷Bߢ àî¹€pjÌ3;ÌÁuf] 0§4üžm!ïæ[nŽý÷L‘í:?Çö…ØJ!Ø0BâU,<¸ØUÜâ2wL»½ýöÛÏf‚§×ˆí»™½¢¿ë¡ÒT)/†±ächêXÄË×ðx*Óéoè:[üÿö¿Â=§ÞŒæùt¼¥¹žÉéÀv¾ê´Ã,uc}ª/à7Ó·¾rœÈ:U;oOœFÙm¯™åÏD{Ûe\Yáò«ôà;ï¼sBgÃBã^í-fÚœ´5ðŸ8º_k:çÄi [X <9‹±z±|ó Íâq‚S\>08YÈÀrÃ`IM䀓 œ¥H&‡Ûô ;…8¥¤iÕíPß¿ÎL‘Ó+|æZ^ÓFü«±]à…Û5ÿÈò…=¦Zñýëôó“ŒvXÚð¨ÂЗvÚ®I[Ê‹€4ÖÞ<3Åé²Du˜Ðmµ3ÌïdÒqN·ÙjˆS²Ç‰'½3ŒxD 6±šYæ{Ú[&  >+R\„ œq‰§Ø8ÕÀöÝNZ¦î侫Hô„Ø‘SxuôäéNèá#'ÊNòyŸ[Ùuê2‘Ù×è°C^Sk:_ÅüN÷Æœ"+ f‹ÌcaÉDLüžkN­En¿ZDö3jîµÛÊSí.|blu\ü,}1Ëëª_ÉÓHôm·ÝvãpÀž—åÖfœRÛT°øpz šyËÉ")WwœØ,nÈ¿Ò8×4öäÁ Ò9ã—ÅòEŸXè5ìÜ".~©ÚpŠÀæ3Âk¶°‘„“œÂ9Ë傸O߯iÞ„öY¦¼çír<Ï\ê%-2i¦Í«„¬SZ>=¸ »¹¹ dý‘ù‘ûï¿_71ø)Äýž¡ó¡µãèD°©ËÛ Ú• [&veEzƒÖ[”æ®ØÞ:ÃÕÎÄ8ãÀ^]åolu뾘©‰ñƒ+%m ût£¡Ã¨NU피.‚œ¦nöµ«":lgÕÍ f€møßÉ•!·ÎàxÖ"ýŽFHY4OW•ѧG™ùe'M;ǶšÝ κuQtsªö…QìT²ÿ·ñ$ƒýE0É“^bôRèN”ب.èüi2›¨¼(ÚUšZd8j|:I'™_Ñq®øôœÑÒSÞ¹Àï‹óCJðž =F~jØ üÞÆÃ±7Ÿ4f'+oiöìI¢¸²p5;ÌX@ò@uÚG/ •üo…¬™ÛÎgGꆈ¾xZ¼‡ÁsÝOÚ3Ji¿ñ-ä¬oÀ“HÇ _MºOÓ˜4”ÚôæE˜q{Ê«ÃuÂŽ?)ç¹p[¾s!Ù$ð3ùqÀc^=šÏOÌ:}ª7K£]hÑŒD>ñ•byVšmYTÐEfìEåš‹šbgøŽ<ÊéÄòí®2t ·fI˜˜za@æ ¸èø8œ;Ñwìs'.&uãß§m„ÁÙ;§ªÎ¾ ¨±Ág ßYhT¼[£Ñê³þÄi»>iìY'jðm?3¤/IÇ’Fi.‡ŽsBŸÕKN£ô6{QFnê«L•ÃL—ÔwÚŸE·)©´Ó¤%X «¾ï¾ûl5Ï-2£ºÅbÀ£iðàB ¾ˆÜ»ˆÝœ7ó´aõìÔÅÞ¥OR<Ö¸dC:Òl^ xÚ·½ªÎ)rRˆ‹@¥W—™Ë?ÉÉî?õQºêkƒîËY£-€‚‡nœ´Eç˜98׿¦‹¨Nלê¤ùl“ÂÒ¸.6ÄxÄEJêE¢úpî´B㩃͙ÒnÏj3hX2ûã4\ŸL÷”u±€Õ'yu­±“¼æŸ¹9‹i9$ @˜65 kÖ±«² /d¥3 ÅZóøŠ__.X;7°Ž§‘ùÌ2=m™‹å›ïazÑ™sfbï%< ãEÊù¹Ü{jÑ ¯6SœõÞ@ë$Â7O[]ðŽW‡vOeº¨,vº2çº~µ^~aP»ˆíâU†|´ôÎY᥂K` eÁ•iÓ=”`M¡{›q§Ô}úð/\Oƒ%Î Ø^§0sØÈ/øñ’'Îà66²Óq2ï‹d¸‹³=ädF+tû¼rE›Ì† …­,É÷ÔEôÙ-ÙF«¾€ÿŸoÿ¿>¾ àoø›Ç7üÍã›þæñMóø&€¿y|Àß<¾ àoø›ÇÿoŽÿeFpT-ÓþIEND®B`‚stella-3.9.3/docs/graphics/launcher.png0000644000175000001440000005343411433323254017447 0ustar stephenusers‰PNG  IHDR Xšv‚psRGB®ÎéVÖIDATxÚíÝ;¯æFš hJH£å©ÿE—¹åÕklr$k9c¦•8ÛN#½´—(§¶ÑÆ@f·™k•œTÞÊÓ˜*oÂÈËñ´F÷§f±xyãÂ`| Q¥sxȸ‘|ƒŒ`|6 Ã/Ïož€=ýó¿üóðÙó›ç_°§ŸþòÓ0 Ãðêñƒ×_}©T€]¼ýË¿ÿïçŠhEÐt@²½Rp]ß~üY!ð7~úËOÃûü‚@¨ïý^+þÊ7_¿UÆ,@ÐÈ–<ä·O/ó³?¼+ÚGêßßÅ£œÎT>㺽B½¶¬ƒ”óâŒm€ëÝ#÷®HlP+~¸êý±çø*§Ì?Ï=ÀãßR§dÍøo[Nj:ÏÒ {É×´ž¥¼{)Cç=¼©qajlÐ:~8Û½ï¬ñUµH/AÓ]([´ zï|D·™  #Û¸?^Ï«V 7§1Dö³µÍô÷%¯æ¢Çúñû¢We©¯3×òµ–浓»ôäÝz ²U>K¿¯™æ”¶±U'µÚ|¶Ñú¼àzé½:7x¼mïï¨ûcëØiØ :n)-KqkJœVã Ìç9™~4¦¹WXµ†iEöÙfÚ.é³õ*qï!j‘|EëbºŸZkëä]:VäUc4§´ÒvX³ ·ÚFëó€ëH½,Ń[÷þ¥ßïùæ£eìÔ26ˆÆN)ûJyv퀤ág9qöJÃ]Ÿ˜DÛÃøUëZoüJãï~^píûKîüŽ»ÜësîÅ‘øjal{Ûm%ôZ¨§ÆxÖ£Eº÷~µªœÓëÂ׿8âÞ³ôÖcn›¹{T÷ÓšÃÏJîÅW¯^íÙ{ÚO­†ØÛ r¦2¼ÃÅ·×´,]ð€}îéîÅË’?Ût×úÜYd?µ¶9£+ä}i,h«“µe[í-%iÞ\sÎq¿Î¹§÷xßϹ/µ¼—;åøìùÍó/Ã0 ¯¿ú2\ ‘ÞÚ6[•jkiÛZ_Á𫸵9 5Ž“’¯ÈXËÈ—RÒ]ã²õ¬ZiÎ9^ômXéW¹ö>wjÑ}´\ˆ øOß~üyxÿ‡× ‚¿òÍ×o‡÷ÿø»ð½(r¿É½¶×2ÜcìTû«°¹±Sí86µ¬ÇÞþñ‡¼ Â5; °§GäsE´¢è€×óJÀµ}óõ[…è€û{ýÕ—Ãð•ÉÆ@? Át@€»v@ž^þýŸÿößþÛûoÿí¿ý·ÿößþÛoý÷ŠØB„O/÷ožu×€Y¯ÿ埇aeEôÇB„±IèÞ ƒ•Tà6ÞþÓ·áøÿí?}»Úù3h&> °Ïà òÝï~?|÷»ßí#Ö Žç‚£|ñÅo‡/¾øí-Óz¦¼+ççî|ÌýÿÔ>CÖJèK7›OŸ~Üåæ9Æ\šöHO7ÿVu‘“®éˆ+e›h;ËÝæÓ§ ÚJË'ZÎ5ŽÕª¾Z•Ï]¯µÕ¨¯”ëEËk Ãj‡ã»ßý~øú‡ï“÷U4äÓ§ý· —ÞÜ"ÁU«ô¤ÞT÷Nô|"åu7‘:˜5sSk›£ò¿––;?ÅnyͨUÎÞ:ptçcöwÁ9 ¯®ZP‚ð{”ÿÖÓМÎÇÜÝZی˧åSã³µ#ʧ曗;žï­ÊNÝ´—ó–£¼òë€äk7Và R޳6„fÔ,m7=ÖR ÔrÈÖ±Rò•’÷#‡Ì-¥·F€5W§g ŒjµÕšm£ÇòYËWÊu#Ò9*ÝOägÑó¯õ0µµ6i?)õÀŽ^$:,jüûÜaã¿ÿ[Ú¶dÍÒÓîéÍnkXTËac)ÇzعÛô4d.:mzü­y5gzóiÏ‘!|[çiÎyÑ{YEóU³œkí'çYËS«aj[m,š×Èu €ãÄÞ€<½ ÛçÅ›åôf}„¹m8@éšév{䡇rl•Σó>®ëH€nÒSG¥eVû¼hY6ki^ÊWêu#Ú^r÷y[¹ž™7õ¼ý§oã?½„ނ͉ÜܶŸ;O| x[o¸SÞSƒ–­'Ü[[ooIJ‡¡]ù<¬Þ·îX÷Ó_~þôÝûжß|ý6¼ßâ9 Ñ·k7¶µÀïêiyìù²§@«uÞØzûr­'ó‚Ò{ÑA ¬åè8Û½>™³ßÈxïšä4GFóÈã×<öc¼KÚFʺ¥mk¯ñí=|âµçòÙ:NJX›G“»Ÿ¹}ÕjKm#ºÎŽÏ0 …s@¶nÊ[ÃlRÆÝo‡Ñ!=)‹ÄÕ€–öÕrRËcÕ®¯šiY«ÿHZ¶ÚÆ´ƒ¹wYïÙFRÏÓZm㬢׭íjí'§N¶ÒÒ¢-§|Ë‚„ ÎùìùÍó/Ã0 ¯¿úrugß¾yÞÿáõiËÃÍêÚÎüe*m[ù´.ÇÚow][®é›¯ß&ÍyÿçïW; oÿøÃ0 ;¯­œ)ø©Ö«~ʧ¼CÐ2Ï:üUŸ!às%p­œ·ô,Öyz¹ÄMÙ͸K'dkÝ×Cª ö¼š‰u@‚ã¹€›2èÍmæ€;2è9 \B•ºÏšÖ3åýÎåsµz€Ü>ëœ}/ÝD÷ø¬ãôXKǘKÓ>3Ù².rÒÕ"‘c¥lmgÓmÖ‚Ëñ¶uj,-çÖ‹Ó•¤¹Uù¤^3–Ò­ƒùJ9¯¬@¯Šæ€<¾%ÿ¸Áíñt/ò½úñvïô¤ {§aZ>¾ï來ks³µÍ¸ýõTt®•ßÎG®‘2€Û»ûø=Êë)oNçc.l“’¶ä³>Ꮄ#ʧŃ‹–G\èUlÖ‡wÃðñçì`MÍ@5rœÈ0›Çpйí¦ÇZ „ZÛ:VJ¾Rò~ä¹¥ôæsãá3ÑŽOï`­¶Z³m^o©å©/Hvô: ÑaQsCVRƒÅñßÿ-m[:Ìfk»È°¨–ÃÆRŽõ°s·éiÈ\ô ðôø[ójj¼ui¨n[e¶užæœ½õkçj/õ»UÑrŽœïP[Ñi°dp‘Ú‘©1Ìf¼]¼÷ ¥ìGtöÎwʪÜNî‘Áu˲<Ë è5ìŠÁ¹7Tœòªä)CQîtSO)»–ÃRz)ë#òžŒm MŠ|Ѩæ×œj•ùÙÛΑAx¡|@…9 [AVê§QïtƒŸê±g°ÚÓÓÎÖy¿£œN“ótŸ2€[h9$:Üd¯O}æìw.¨Zš P#И¦ñèÏžyüšÇÞc¨SnÛ˜«ã¥öS£mí5Ì«‡Oòö\>{çkkœ]ì ÈÓË0¼yN¾ùo ³YÚfF‡ôl}ñeº¯Òhi_-‡!µ»Û².rÒÕ"‘c¥lmgÓmÖ‚æé íK«sïUÎ5ŽÕª¾j”OJûkÙV€Â9 µ57î=žZFÖï{§'5Ú; Óò±ÞI¼“¶„ÎýÍÖ6ãö×S=<Ò¹VÞ:Åî>D ~òßzzÓù˜ë`D¶II[NòYŸÜGÚFˇ®ÐVlÖ‡wÃðñçìi.°HÙ¦f 9Nd˜Íc˜ÈÜvÓc-Š-‡m+%_)y?rÈÜRzsƒÔñ° hǧ÷À¶V[­Ù6öÌ_jz"ùF}†€ÝÞ€D‡EÍ YI Ç7þ·´mé0›­í"âZK9Ö#ÀÎݦ§!sÑ'ÛÓãoÍ«©ñÖ¥ucëüÛ*³­ó4ç¼ha+ÍÑôDÎ ¦hÈ4Ø?ò©`jG¦Æ0›ñv5òÞÃP”€ýˆÎÂÞùNR•ÛÉ=²#Ò²,¯4´ÉÈï3L½*9FÊP”£Þš¹75{:½”õyO 2·†&E¾ÔTókWµÊüìm8¿â9 [AVê§QïèÌ ËÚ3Xíé)në¼ßQN§Éy dk9$:Üd¯O}æìw.¨Zš P#(ž¦ñèÏžyüšÇÞc¨SnÛ˜«ã¥öS£mí5Ì«‡OòF×mñù`8ŸØ§—axóœm ³YÚf.Ù £Cz¶¾d3ÝWi€¸´¯–ÃZ«v}ÕLËZýGÒ²Õ6æòu–7:9mu¶±w{ÌùZôôz ’5$:ԪƄæh0Ps»ZiÚÚ¶f SšæHýånÓ"ïsC‹jÕSí¶Q3Ð]V•zN–¶ÕZçM´|öNoÉu (í€d®­œ)(¬Ö«Ä|8©£×È뀿éÛ³+­IÝ ö¼š‰u@‚ã¹€›2èÍmæ€;2è9 °ƒ+‡Ÿ5­gÊûËçjõ@‚}†¬•ЗnZ{|ævz¬¥cÌ¥éŸÝ[5:g¥íH9Gëb¯|íÕ~jç+’ö”m¢í>w›µÕÔ÷ª·ÇjÕÖZ•Oê5l)=)+É—æ+å<­uNp~Es@kk®Önù…¸”¯`™ópaO/¡· Ys@¢C­R¾ø“ûû=¶«•¦­mk߀KÒ]£\ró•ÛvjÕÕõ07,¦V»©Ý¾j„kC‚Rëyïöz†òÉ9Wjç«Åu£äÀùìº,>W.Δ¿Öá»×eO€ªŽ^ÖÃ0î©h³½‚]õÀN‚}o@€fbàx.à¦Ìzs›9 ÀŽÌzcì ÆJÝgMë™ò~ÇüÀn‚}†¬•ЗnÆ{|Vuz¬¥cÌ¥éŸy[O#gH9Gëb¯|íÕ~jç+’ö”m¢í>w›µÕ¹÷ª·ž£ÜJsòIiÏÖÈàêŠæ€<ÖrxÜ(÷xJY/b|ÃÞ;=©AÇYžœFÊùŒkwô˜¯H›˜¡sSk›£þµ´xë't÷9 ºãÈà:åMÝÖ>æ:µ¶Ÿ/¥”³>¹vR[uà\»¸ºØ¬ï†áãÏÙÉܲF†ë´(ë”ac[ãÎ4ôn©íä©[õ~Æ ¶Ö¹“sž¶(¯µc¦ \Ëæèu@¢Ã¢Æ¿Ï}Ê8þ»ñ¿¥mK†¬L>·Ýô æÜÍÖÃÆZ Å©¯í§•è“íi>¶æ\éÍCäüÚ:w"õžsž¶l¥éyt<{oóßYÏ5 ö €RÑÒ!+Óíjä}¯€(5_-êj.Àöw½}–v*{*ç–m¯öyÚSû€®瀼*9ÆÖŸ” è޿ܛšœÀbº¯;˜Wn?)Ãú¶¾ÔÔ['¯tš'þp^Ås@¶ŸÔO‘Þ)°˜–ÕÓçIkæmÏÎÇ]ÛOI9õŽÜÏÛªwèTË9 )C@örö»6iw¡AÓ4¶üÌèÑCžÖÞô\møÕÃÛJÚjʺ¥õ°×о>É]·Åçƒ`[ì ÈÓË0¼yNF¶†-m3wãß Æ¢Ã™Re«-í«æ¬ñþ"‹©­ªkå\».R¿=ÛOôËKµ‚ØH{Œ”_JñŧҎ\ê¹SZ-:Ã)_Á27 €Óyz ½Éšj•òÅŸÜßï±]­4mm[;°(IwrÉÍWnÛ©UW{ÔÃÜТZí¦vûªè® «J­ç½Ûkíòiq~•œ+Ћ]×¥€îêAÓ™ò׺#¬.ࢎ^Ö:ÃKî©h³½‚]õÀN‚}o@€fbàx.à¦Ìzs›9 ÀŽÌzc£Æ*ÓgMë™ò®|œ{Е`Ÿ!k%ô¥dϪæ¬1÷7G®3)Ÿé6½|’6Rn)Û¬m—²ÍÒï×VÞÞ«íõ´b/å3׿}f9]úJ¹öY€#Íy¬åð¸yyr/Ÿ³®ƒ©ãiP3÷7)Ûô˜ÿµ´Ýù)vËëA­röÖ*1„Üà:òÆ"º¹`4e›hÐ[ðžõIp¤#{Dùx(QV§­Ê΂ !6ëûaøøsvÐ2wsÍ 4×n¢ãa KÁÒÙ†‰D‡–µÈ×ø¸¥u¶U_5uD}mí[õµ”ÿ3 áËiC[Cº¶Ê/:4,g?‘ŸEÏ¿Öןµ6i?)õ¿öv{2¾y- ËXÚæ¨ôìqÌñðŽ=ò×*_Ñú™k>Ì\ÙôúTv+ðœ¦{)ãºZž·u¼ÞŸ\/Õk¤k•s­ýäœ#kyjuý©5ôñ À[-j)šÒ"ÀÞÓÞAÜ]çÈDòyŠÜ{pݲ,Ï2T&z=XÊWdx^N(w?KêHÞ®r¾{ã@XpÈ«’c¬ wj¬‡õÌ¥gúû«Ý\{ vÖ†{̇µ¾ÔÔ²­]¥®«÷=OàÅs@¶‚Çž’¹1àg z~}Ž¥¦ètÐàtZΉ98òs—)Çž-;c°œ“ö=†ŽDæ”á«1p¯a3=´£žËgë8)k³¬Í£ÉÝÏܾ"ûÈ=VôïÏ~àÞbo@ž^†áÍsr ±5äii›’àeíMLë!X)_¡Y ԷʧU¾¶ÖéHýÂÎÚ¹”cõh-oµÚ|Ê— Îfk8et»ZûÉ©“†€–^ ÙÓKè-HÖèP«”¯&Õ ^JUš¦šùn]†KC‹RŽQš·Ò!MµóžÓ¾KÛatmžË§Å9X«œjlW#-ÑúÚ»}•\Ó N$sÎéLAFˬº¼_ÚzŽ˜€S;z€+tà O€ºŠÖ¸C'dkȓΠÄû Þ€ÍÄ: Áñ\ÀM™ôÆ œ9 @oÌa75W¹?[ZÏ”wÔ7Tì3d­„¾t£½Ã§(¯š÷ÚùЬ²ÍÚv5¶Y[å»fÞç~w—u&Rò^«LZ•mö“’Vk“pfEs@ß¿ÜïðpúÍÿ«¬Ð:_‘¶2 ²æþ¦Ö6Wü=vgG¼ã€¿Fçc®óPk›q§«´ƒâÉô>â£÷=V«®Å8³Ø¬ï†áãÏÙÁØÜMºæ6Ñ¡‘cÕÂ#i^Ù¦u¾jvNJµé°—¹:ï­"i®Ý~rÏ“i@]Ú#yŸî#¥›³Ÿé¶kCÁ"Cýö¸v¤æëˆ4À¯}†€ÝÞ€Œo‚KôjmS+=-ó>Üål3=NïÃŒ¢On§ùØš£r¥7)mõÌ/µŸÃê"í°ÖùIcôüÊ™K±”ÞµrÞë)ÉWë4@Š¢9 §™5ƒ¿È öjÃÆÃƒ–òÙæj"SêüŽ« ‘j^ÛaNzr†çiÞg˜zUrŒµ!$Ó›üÚß§ —(Õò)`«c]ùÉfÊ¢­/õÒù˜¶û’¹2½ÙJs4ï)ûpÀ¹ÏÙ ú"o3¦LO¡F×*xÞ;àÛšërwg|óá©{?× Øg¨2$eøËtÜxN°\ë³¢-?Oz§O¡î1æ|m‚ùtžHîš5:){·×æëï7Ú~jvr§ÃVàŽbo@ž^†áÍsòÍ}k˜ÄÞÛ¤¦§f~ô±rƒ§šÁxä8ÓŸ¥~ñgkHÏÜDé=ë#µÞ"y*MïZÕj?)i^Ë{¤FŽmÏ5†„íÑÁ*Íâé%ô$kHt¨UÊ׎zÙ¦¤ Μ¯ÚÌÒм”ãD·]Û.å‹A5Ë22$¨$Ý©ç[iÕn‡[[hqþå–MÉü¢£êA€žìº÷vçù>mnçèu@ò: Áoú7ì3x4ë€Çs7eÐs@€r怽1„îÕX©ûJéèR°ÏµúRf1®õò9C•®>Í{i~#é‰sm›h}EW8¯U¾5WgèEÑOŸ~üõßV ×S€Ý*ãò—Ó•µÎç8H_j‡‘mîZ_Õ瀼RRLƒðž:‹kišûýtÛÈ6©åSúäŒuPK¬òáÝ0|ü9;€\ ªr·™n·µŸµ§â©é©`çæ©f9G‡Nµ,Ÿ+K¶V瑺·ç”kXŸçl³Ôq˜ ¸ÇûÙúûhzrƒÌÈ“ù¥cÓ¾öû’rŽ£Û:ÖU:-ßnäÖÅc›­öГXäéeÞ<¯lµ‚¶+O©yÙÚ¾æðAê5ÊD=Ýxz ½)z2þ‘2dg. . ªjN,o1I½×¼÷t,®§xÈÖSùÈSýi€;Ž2 ԣÙJ:-ÔÎT;ï½ €“ Ω²ztÌú´#ù$îôª5;Ñãïdçì·æºgXTo«]Íý~©³šÚîJêà±3€¿U4d+xÜb´÷6‘t¥+'XÛWʱÖÞþDò9Vä+a‘cE¿6V³“²õ†,²ÍV}íÑ-© €îì9$:Ô*0mmýZTJp¶¶mˉôµ¶«QÎ-Ó’ÛÁXÚwiþ£iŽvJ•» p»®µ:!Òй£×©ôÕ'6 ýéåðNÈôßÜ)¯œ\°Ïð¹’Z‰u@‚ã¹€›j¹@½ÈÁs@€Î™ôÆàöæ>õ}—´ž)ï8¯€Îí¹ÈÒÅ'cËÊr¯ò‹®à];?­ÚF‹2ì­.œƒmë$e›µíjl3^©V;j‘¯–×(ëF¥]7ö*£m5¥m´¼×eŠæ€L×åð¤£ìÂZR~½=ijÕ6®\†‘ò]úï#ÛôÕ®‘üDÚa­mz»FEÓܪmŒÓÓ¢ÏØæïº¶Ѐ9 ivÎÇ\Ð[k›qY£ÃÉ{­4UŸìã;;­Ú„º†óˆ Áúðn>þœ}3˜»-Ý,Ö~ÙÏÚP€È°•­cåæk5ޱTl K¨™÷Ò¶‘“ž” r­Î—Êp4·2°ÔS†cÔ*ÃÈy±G9—³¥ÁÓt(ÊR ÜcàXû\/¹FµºþDî)‘|E~–r¬­Ÿµ¸nôž­ºXk[[qPèèu@¦¯ÁsŸ‚¤ìçqsßzR·tÓ¯•æµ›ÌÞO|Öž­å«fÞ7šZÎ-ÛO¤ £é™Ö°6$¥Uç#ò4}m»­|EÛáVzZ¶Ôsk+PëAÇÝÆ©×ºFqoZ»§Ô¹Ô.Z ‹^›–üi›ß³M§\¶ònè8¯hÈZ™sá-½ˆõrCOºpÕ `Ë@"uÿ=¼¦?¢óÑÛð˜šé9ºN#yI 0{ë¨Üq‚o뼎ϵ5î•чÑNÈYÚ…7°³àW¥'r1Ô©Áf«íÞÁ/ܽ•óÖ0¡­2}©qŠWÓ:_‘zïíKG)Ãs¶¾¤óq½6}ÕZ¯±÷S<dëF™ûy‹Rz› Zö:ÖÙo(=«Fzæ†SåÞ4Sçs¬ Ç©õ)Õ#‚Ͻƒ·Ô9Sg)Ë3ûW}ó!h®×6tB€¿ê3T™’2¤ Fà’³Ÿ¥q¿{ëˆñ±½”óžÇÊ­÷Ü9<{·çóƒzj‡¹é™î§f»Ü£Ö&˜oå=¥LJë2gØX­6¶×µei¸kÏ÷¦Ü¼íuç¶Õ’¹n[sR€ë‰½yz†7Ïɱè0‰µ×¸µ†[DöSshGôÍNÍ›Fé|œ=‡*¥–sËz”aIš£éÛ{!°H ™R†9ÇKýýÞçiJžþ,õ+<[y_›ÓtÄÓåhzRÚX‹kâÖÛîÚí'çºÑ»h[)Üã|Ìý °³§—Ð[Ïžß<ÿ2 Ãðú«/Wwöí›çáý^Ÿ¶<Žøl pÞëÃ]Òê:¨J/°ä›¯ßúî}xÛ÷þ~µòö? ðó: gp¦©vZ‡çäÏXOÚÜPpÈ«»”G¯_΀ÈýË= ¸Š¢u@ÎxŸ[P ÎpÿèZ°Ïð¹’Z‰u@‚ã¹€›j¹@½ÈEæ€;1è9 ;;ã*¸g,—3•óó~çòq-àòö\dé&z•OÖúÞúÚ~Ö‘éöãmKÒÔò;ò[ǯ˲g9çl³¶]mZçý±]/çg/mcîÜjkûÙJk|¥œÃÖ WEs@¦ëixº]“dDœ¡Œ{Kc$=‘r®µÍQù_KËŸÎG®a‘2€Û3¤N@RôE÷3·ýôg¥Am‹…¬RÒV#Hß*çœÎÇ\ºjmÓ2ïg>¿Ž(ŸÆ–S ×ЫØ¬ï†áãÏU‚ѵ{ëg‘ý¬ ‰îgéï÷Ú§Ç«uüH¾¢eÍGOOþk¤g:|f®Î"ÛôfZ.Ki®qu~]ÑZY¶:ß`¶Ï°Ûñ ®d˜Vd?ÓŸm=^ÛOëpoOBÁsN}õöÄ5šži^·æ8­u,"ÛÕ [ N§¨¥|•žƒ½?‘ßê|õ4¬®Öu¬ä|€\Es@O{sƒ­¥À¯$H‰ ó8: J¹ù·jïú4RgÒ:)ç`/e“ú‘‚«µ{¨"8äUÉ1"ÃLjÝ´k¡éñ¼õ…_´iŒm Mš«¯È6G·¯3t`z Â{ZgW<d+ÈJù4åÚö5¸¹¡=}žt+øÓù ¤Ýävˆ¢ó²”!Ü\Ë9 )Cˆj.9ûiý™ÑÈg=×¾ t‡ÎGÍ!wµ®›¦+2\0eHa¯y?â\9SÛh‘¯éÐV¸šØ§—axóœ|óyzl»µhÛÖ~JÓý"P­Ê4=k_*É«|­Í‰8¢•’ž”vº5 ½d^ÔQÖÒ½tî”ÖÇÕ:ש Ö<ÖQ×1ø›>Cà-HÖèP«”ÞÚ¶)_2*Ù¦ö ºÆð´Zé¨U§µÒ[3(Z*çZí¯v;k‘÷œ:Ýû,Y§Uù䜵óuÔµP€Vv]7õ–=y×6z.×.ïèu@ò: Áoú7ì3x4ë€Çs7eÐs@€r怽1ÕXü¬i=SÞ•¡º ±`Ÿ!k%ô¥›ÖÜB[©«G¶Ÿn3MO/ ~ÓµWšj®[÷©ÇNIsëüíÑ>sÛFmÖV¯™÷”kBoõµåÈ2ÜjC%×Üù:ó¹ ÀqŠæ€|úôã¯ÿÖ‚½ÓЋ­NRê¾zybÚS½÷(R‘¶Qk›£ÎÁÏɳˆœ[Ÿ;÷èJ/s@"÷ –®Þ~¶žàæt>æÍZی˰F'x-ïWoŸG”a‹ŽeËΫ{±!XÞ ÃÇŸ³n¶Ó]IÐV+€Œ¤+e_‘¡5Ò›2|cºMͼ×*ãµ4GÚϸ<–êc®Ìö¦—Ò’¨‡ÆÌ¥÷lÜZ™ä´Õ­!_%×Aryýîq.pG¯yÚµ4¤'u›Ô±tøP«¡/)ÃZÖòU+ïã¿ÿÛJûÖ6sÛ¥Ôõ#P_ÚÏøg{=ɦw)=[Û]%›ëDͨ)íyi߹ן^†5-Õ}OCïZžË\GÑiz‡§U)Ãc®xÝ ·齃Ú3ó‘2I 2MðmÛ‘Üû“ú!ƒ+•?'œòªäKÃCÎÐØû&Úc¹Üùiâ£Nz©µ!*sܵ¯]­óq÷§Þ)sD¼!àŒŠç€ÔüDeO7÷;6W4òt¥r¸jçckÁtøß]Úvjçšj9ä¬ãus>oÛjNAÍ4×ÚOîß Ö3¿G;_›`¾ÕÆ¢e[k-Œ^ÎñZóÂRÚøÕÊ0%_[ó½ Uì ÈÓË0¼yκ±mZ[7¶È6%ÇÊ (¦ûÚ;¸.=^­¼§ì§ôétÊÀR¬½ž¯­ÓtGÊo«Î׿ÑÙK©¯µô•\R†µÕ¾&ôú€%¥ìk+µ.¸ˆ§—Ð[Ïžß<ÿ2 Ãðú«/Wwöí›çáý^+X’~y¼VZ{|£µwº®X†:D|óõÛáOß½oûþÏ߯v@Þþñ‡av\®êLÛŸVß×(Cª Îy¥¤€³u®æ:µ¶—aNðZÞ¯Þ>[vò\3¸ºØ¬ï†áãÏYËô^´Õ #éJÙ×Ö>jc+Ü*ïšy¯UÆkiŽ´Ÿqy,ÕÇ\™íL/¥%7ù™KïÙÔµ2Éi«[C¾J®?{–m‹6‡9zÈS¼¥!=©Û¤ˆ¥Ã‡Z }IÖ²–¯ZyÿÝøßVÚ·¶™Û.¥®úÒ~Æ?ÛëI~4½KéÙÚî*æ\'j.ðNiÏKûνþìù–£E›€ÞÍ™¡wx —2<æŠÁVp¸HïÔž!˜”Ij'×Äå¶Éž:rÐàW%ÇXr†ÄÞÁAår秤:é¥>Ö†ÞÌur×¾ÂtµÎ‡§ùpmÅs@j~æ³uàwÇ ü®ÆCž®TWí|l͘ÿóF:ÐrÈYÇ!ç|Þ¶Õœ‚ši®µŸÜ¿9:@¬5ggv¾6Á|«E˶ÖZ½œãµæ…¥´ñèÚ.-€m±7 O/Ãðæ9+HØ ´¶nØ‘mJŽ•¼L÷µwp]z¼ZyOÙOéÓé”/€¥ß{½±[ Z§éŽ”ßV¯Í3:¢³—R_ké+¹&¤ k«}MÈ-§Ô4@מ^BoA²æ€D‚ŠèM3åËA%û¨}#ßëÓ»©û‹xµÒS£¬kµŸÜýì±*vÊ>÷*ÃH¬VG8µ¾JÛïVž¦éªyMˆ–ai}ÕjóлÝÖ«:SÀת#¬¾€èWJ 8[‡ õÐ) ž¢u@`.8Òªí1Èì3|®¤€V’æ€ü_ÿÏQbp ‰±Ëu@êu@Ì*ô¼š‰u@‚㹸†oÿëÿ¾ý¯ÿë–i=SÞµQõ]Ùs¥ÿëû»Åmç~×cPÉSÏi.Mo¤¾R¶YÛ.²ÍÖ1_ÿÛßýŒî™÷«¶ùÚin•÷õž’Ö3Ö)ôªhÈëû»_ÿ­igS+O-žÒŽÓzT'm+X›û›È6)ÇlÙ&Ž(w€îõ2äÌÚÕ:V©‡¹2Œl“rÌZŵ¼_½Í×Js˼·§éÜ ¶#³ˆ”Ñ´=ouönó9iŽ´ùè9µ”ÞGç´E»¯‘¯Öi€3+šòxŠ,.«%AçxXOÉäÔ–ðRšS†*õˆo¥³—ŽÕ,µŸ=ί’ )íùŒo¼ñàö‚s@^•cmøLm-Ôèabe¸õVgí‹Fs{—@¯—v6®7PªxHéç0§ÁÍÒ>z v¢sT¨Û ¼ÊgPç‚ù=Û|ôüÊ©;u€`Ÿ! ÊÖÃhθYNš÷BÓªçÒ\;_5‡îíÝ®–æSôÜækûˆzŸŽ{òô2 ož³‚ƒH°ðxJ»ö»^†,¥'²íoˆRʹFà¼ô³Ô/Õz2ß['3ÒùÚjϵÛüÚùU+ÍÑvØc½×Èð}†À[Ïžß<ÿ2 Ãðú«/Wwöí›çáýïß*Ø8ãêõµÒºwÞ£Ÿžæ:mÎêÿûïÿeøÓwïCÛ~óõÛáýŸ¿_퀼ýãÃ0ì¸çu¶OßÞ5ïÚ(ЕàWJ Úξ(ÜÙns@€åNÀåç€|®¤€V’æ€üßÿçÿ«Äà¾ùïoÓþ å: õ: O/J (î3x4ë€Çsq¬/¾øíðÅ¿½eZÏ”wíï\uªm@Оë€,ÝŒ?}úqqÛ¹ßõ@E󕲿èß—”UäoS¶YÛ®Æ6Ÿ>ýøk`WÚ6¢åVãX{×cÏûÙÒªNçÎÓ­6]rmª‘¯”:8Ó5rÍùôéÇ_ÿ­ðgsÅ|Eò0 |æþ¦Ö6Gå¿4-ž†÷wž®Õk­zòû yJA¤ÁuämDts]­mÆåSöø´¸V½÷¶Ÿè±Z×i‹ŽnËÎô¯™ÜCÒ: 9AÄô¾h¬ýli㿉 ªðo¥g+-‚™¥²É ŒÆCQæêê¬SjFÚin›/i?9ípºít»Öçו­ÕIjûQtçèu@j=Åßp—†\L¶÷ÓÊqZ–Ò™0—¯£êaš­ù0gœÛ³Ô.¢mlÚÑšæ½å‹œ4ç–Ïx»‡&.µÅ‡Ö¨¯žëêu@Æs=ž†ç£KAoI7úS2a´$_g fRƒºžÊ0%HÛ«S¸G›/Isιž:–©V¸Ú¹ ] ÎyUrŒ¥a8G5nî©_á¹b`³5ìhëë@½uàj C멞æ&Äß)0M™#â ô£xÒ!Ñ!=ÓaO->)º„›,ºÝa<º|Ržð·œKËhk( ö×W½À嵜ÒúæÞêS¨g ZöHçÚó­áC)ër”vRöª£H;ò“¼µŽ]{HXÏuºw‡z:t˜‚õô2 ož³nØ‘øcˆÄÖ‚usAÊÁþVÉ{d?5§¥Ÿ¥~…gšî¥ÎGt½tà¢ml-ÿµÚ|IûÉIÏV^]Ëù.5ê ºõôz ’5d) *¹¯mŸò§Ò@4÷g9i©X,ÍÇH9Ft·Xõ=š÷šuÙ¶V›¯Õ~jÕ}´¼Ž¬Ó=¯Q)+¦ï} +m»ÐƒÝÖ¡½3"µÓ*S§Î+8ØÑë€äu@‚ßôn*Øgðh¦xs@€î˜”3è9 Òbeõ^Óz¦¼kÀ%û Y+¡/{¯ŽÜ"€Šæ+e-VümÊ6kÛÕØfm¥ë½Ê¹Æ±ö®Çž÷³¥F¦¤õL×à?ÍùôéÇ_ÿ­ðgsÅ|Eò0 èæþ¦Ö6Gå¿4-žò¤õò: ‚ù;j•÷­'Á9¹ÎC­mÆåSÚ)èñ)x­zïm?ÑcµêtÞùÚg‚õáÝ0|ü9+0œ&[ÁãÚÏ–ö7þ›Èð ZÿVz¶ÒÑ"H[*›Ü€o<Äf®®Î¦Öi¤æ¶ù’ö“Ó§ÛN·k}~m¥=µœ[¥nïèu@j=Kâ¦?Ûû)ì8-Ké‰ÌG˜Ë×Qõ0ÍÇÖ|˜3ÎíYjÑ66íhMóÞòENšsËg¼]«¡‰5òÕ:Í@LÑÇÓðÜ`t)è- âÆCJ&–äë¬"AZj'¯§2L >÷êîÑæKÒœ3dîŒmh 8äUÉ1–†á<ÖZÖòu姨)ÃŽ¶¾zÔ[®Æ0´žêinB¼€è]ñ: ¥C¢Cz¦ÃžZ|Rt+7 v»Ãxtù¤<áoÝÉ+-£­¡€MµœÒ:øiõ)Ô³u{¤sm‚ùÖð¡”u9J;){ÕQ¤ùIÞZÇ®=$,ºÖŒÏÀ}ņ`=½ Ûç¬@$˜<†“l-X78ìoO‘¼GöS³#±ô³Ô¯ MÓ½Ôùˆî¯—\´­å¿V›/i?9éÙªÓ£:X¥ù{z ½Éš²P•›kÛ§|Å©4ÍýYNZjLKó1RŽQ#Ý-V}æ½fF¶­ÕækµŸZu-¯h¶8×KëØÏnë€ÐÞ™¬Úi\jÀÁŽ^ ¯ü¦/pSÁ>ƒ7 @3Å뀘tÇ œ9 @o̹+«÷šÖ3å]9;à’‚}†¬•Зnê%«#÷°D󕲿«ƒGþ6e›µíjl³¶zyͼÏý.§œÏÔŽÏ\Î5ë¢FÞSòpÖ6­ÍùôéÇ_ÿ­ðgsÅ|Eò0  æþ¦Ö6\L/s@ÆüÝ´Êû֓לÎÇ\ç¡Ö6ãò)í xêk‡w-ç–à;_ë ElÖ‡wÃðñ笀el5k?[Úßøo"Ãjü[éÙJG‹ h©lr¬ñ–¹º:c–Ó~¶ÚîÖ~–~¿è/½UjÕæ[;ÑmZwŽÖÎéÔkÝ™ê ’½H­§ã÷Ò°¨¹ lÏœ–¥ôlå})_GÕÃ4[óa®øæáѱÚj?‘7Nkû©ÙN£inY†k“¿·ÎÈùÞºó¹þ¤Ìóºâ°UHQ4dl¤KAoI01úS2ñ´$_g ŠRƒç3•a­‰Æ)Oë·æÒl•ooåºG‡zig)ÜÊוŸZ® -™ ž×¾2d~w:w€˜âu@J‡D‡ôL‡n´r±„›tºh^­| ©Ó&jœ;ê:ÓrHë@ Õcg pöHçÚó­!sÑÎGÍ!wÑ9+-Ž™ò·[eX£^Îóžç{9"[óV€ºbC°ž^†áÍsVÐ Cy¶¬› <Žö·‚•HÞ#û©Ù‘XúYê×|¦éN œ{©³é(Yän-=sÃÿ®ò6)ÒæsÎ÷š‹-FÏ£”¡ŠpO/¡· Ÿ=¿yþe†áõW_®îìÛ7ÏÃû?¼V°;ãªóµÒ*èSÎÚÔõÍ×o‡?}÷>¼íû?¿ÚyûdžaØqÚ»ó×€™ÊY›€ƒ½@^$øM_ং}o@€fŠ×0èŽ9 @9s@€ÞXäB,Dx|Þk¥cnµðœ}ö²=pÁ9 ¯rö=-7g Šk~9y/)«Èߦl³¶ÝÚ6Ke8ÝöÓ§‡/¾øíðÅ¿­¬GóµÕVç¶9"_5ΛÇ߯¥¿f»´ú8°¥hȧO?þú¯4ÈéÉóÉÃ4xœû›­mÆe7.Ãò¾V§‘mzÍ@z™rç ­UÞ·ž:çt>æ‚ðÈ6)ikñt~î÷Óz‰l“ZïWê;߀šv›’2äe+Ü?þ›È¢ZÿVz¶ÒÑ"@]*›Üàr<¼('ø§];Üûx©m¾õy 4vô: µž„N‡ÆÌ=]žþlï'ÐsCp¦éÙÊûR¾Žª‡i>¶æÃÔxërÖ ÿñïh[ípÏãå´ùq^qè&S4dŒ¥ÑKAoI0>T2y¼$_g•3¤j­£rÅÓÜzí ¸˜àW%Lj é¥e»•¯+?±]V37dë‹Oµ¿ Å=Ú!p]±7 +ã¹JŸrG‡ô´þúPôkI‚jŽì|h‡@7ö\d.Xoù”»Õ[—³<½ß#K_†Úš„¾4Dk¯5b¶ò>÷ûÈ›œ½×déµCs¶tûùÍ?üfxûO߆·Šu@ž^†áÍsv@³”=À­rúó£ƒý’¼GöS;°Ü 6#ei»ÍÎ/ÜÁØspǼ1n)ÜÁ0(eÐLí9 Ÿ+R s@.äL«Oïµ`ßÑy·8p%ßÿî¿Å7ÞsÈÒêÊsA׃âH¾öFKÊ*ò·)Û¬m·¶ÍÚÊÛÓÚ·V/ß#ï‘¶:·MË|¥´`/?ýå§áOß½mûÍ×o‡á«ß…¶ ÁzzY ¼ÿ¶‚´3¹b¾"y˜³s³µÍ¸ìÆeØCÞ×ê4²M¯ùèÂBŸ!¯R!˜¿£Vyßz žÓù˜ Â#Û¤¤­F/š÷é[й·kÛ¤Ö{«Ž«Np6»ÍIò² .=‰žû›È¢ZÿVz¶ÒÑ"@]*›Ü`w<¼('ø§Î9”z~µ8/€› ÎÙí H­'³Ó¡1sO—§?Ûû ôÜœiz¶ò¾”¯£êaš­ù05ÞºœµSðø··Ò66Nó‡JçT4dŒ¥ÑKAoI0>T2 ¸$_g•3¤j­£rÅ€÷Œs?¼ñšh1d:f~O­Ÿ<¯åkœ–«=M^ °sæ€xê@zde°ö嬭cÔÎûÒ×¼Öæ•¶±èº$W|ƒ°%ö¬§—axóœ„E‚²ÇWzÖ~ý²T‹`+pŒä=²Ÿš‰¥Ÿ¥~Yišîé6sù:ú-Q$MÑto}mϺ[«+_÷ôz ’µúÚš¹AÙÚö)_q* Ts–“–šÁâÒ Ü)Ǩ•îÖ+xGV/mCµW³oÑÞsÚ.ÀÞv[„öîüe¦^ò.Ànëèu@ò: Áoú7Õb€Å뀘tÇ œ9 @o̹+«÷šÖ3å]›.)ØgÈZ }) ™[„­æŠ×-‚µh¾RöW{íÜ¿MÙfm»µmÖ‚Ýé í[«—×Èû\z¶òµgzöj«k+À—–sJ~Ît¾Ç(šòéÓ¿þÛ >ÏäŠùŠäa<ÎýÍÖ6ã²—a/uÚK}–¾™è©lÖú yJßÝ´ÊûÖSçœÎÇ\°Ù&%m5:©OÜ׎Y«¾zkó-;^:FÀ–جï†áãÏYá4Ú ×~¶´¿ñßD†Õ ø·Ò³•ŽáRÙä—ãá<ÑŽOïii}­½ ÚÚÇR¥ 로RÏ÷ç)ÐØÑë€Ôz:Z–†ÑL¶÷ß¹!FÓôlå})_GÕÃ4Ñ`ûÈÎUË2šÖ×\ðÙÏÜß/u>z XÚæÇù»âÐM ¦hÈãixî“·$*™t[’¯³ÊRµÖQ`²Ö΀‹ ÎyUrŒÈ0œZZ±[ùºr@½6¬fnÈÖ–j~íêntÜ€+*žR`Žÿ~­#Ó:x]ÊWtŽ ×ë˜M¿\µw›ÔaN¥åÖCmZ-®v–!D{¤s®£27­›È›¤Cî¢yÏ=æžsv"í¹¤ÍG×±h!ÐBì ÈÓË0¼yÎ z"AÐãéòÚï¢_*jìoj‘¼GöS³#±ô³Ô/m½±:âMAj9l}q*¥¾R†¬E˱ö±öjKG§èÌÓKè-HÖµ5rƒÎµíS¾âTÚ¹ÈýYNZjgKCÆRŽQ+Ý­WÌ^X«í¬½í™®‹Ò¢Í§|qªtµÊ0ç\®g·u@hïLÁ\í´ d• p°àWJ b|OCΪh¸['dnJâ}†Ï•ÐJ¬ÏÜTËu@êu@Ì*ô¼š1äBZ¬¬ÞkZÏ”wîÙ6´Q.oÏu@–n¢sŸ%­¹âu‹!š¯”ýÕ^µ:÷oS¶YÛ.²ÍÖ1×V/ß3ï¥å[Ú&Žn×gHw«¶1w¾oµ¡’k\|¥\#Îtíà^Šæ€L×C¸ÊÓ½+æ+’‡iÀ2÷7‘mRŽÙ2ï%õyÖu?jäýê"çúãçÊÒû yJ7÷;6-ƒÌ¹€,²MÊ1kÅѼGÒ|5gÎ{‹¶±Ç1{8†k/½‹ Áúðn>þœuóŸÞx·„µŸ-íoü7-†›DÓ³•ŽAÈRÙä4ã!$K^Ícî¦Ôi­¶±Vï)m¾UÞ×ê/’¯œm(»¾¦^{Ï6D€Ž½H­§oãåÒP‰éÏö~Ê8NËRzRæFìù¤2ºïi>¶‚äHçãL¶ê´Ö~¦õ¾øÕJO­¼Ï¥u-_¹ÛôÔoµéÒ[zýçíŠÃhè[ÑÇÓðÜ s)è- ^ÇÃMJ&z–äë¬Ræuœ5`™Öíô˜÷† EÏõ+¶o<¨*8äUÉ1Ö†áì$´¼)§~=çŠÉ4Ÿss –¾ê3÷·=;KÃÂjÕioûi™÷­}ÛKOApÊo \ñÒOKNƒ’¥}´R–ò£rWg’U«N#û™ Â#e¶W«}¬È§h§Çï¥s)ŸšŸ€Ëi9¤õpœVÃHÎ2ÌhtΦµ‡ÌÕr³rt‡¨ÕÜŸò>=OSÎÛm£—ÎîR¹y°ÀUÅÞ€<½ Ûç¬mäÆûxª¸ö»^†m,¥'5ï‘ýÔ x–~–úõœè«Þ:hkinY§‘ö\³mÔÈ{äœ+É×UÞ$´üÂWÊW°,H@3O/¡· Ys@–Ó’ïVpSò÷5ó9V꺵ƒìµ¯+µNwt}Ž=ò^³Îj•ÍÒ§’z+MSι—s^D·iÕ6rÓ›{­KY1}ïkaný@ »­B{g j§Uð¤÷Þ6´Q./8ä•’‚¶A蕇!l)ZÈë„Ì-þpjÁ>ÃçJ h%Ö Žçnªå: õ: æ€ú ހ͘r!-VVï5­gÊ;ê.iÏu@–‚ƒ¹Ï‰Ö\Õ¸EàÍWÊþj¯”œû·)Û¬mÙf똑ÕË÷È{iù–¶‰£ÛõÒ]£m¤œKgºFÀÍ™®cp•§–WÌW$Ó@lîo"Û¤³eÞKêó¬ëuÔÈ;@IŸ!¯R!˜¿£Vyßz‚›Óù˜ X#Û¤³FPÍ{$ÍWsæ¼·L«Å  ­Ø¬ï†áãÏYÁÏ4 Ø ×~¶´¿ñß´nMÏV:ZWKe“¨‡Æ,ÿ5¹gp›R§µÚÆZ½§´ùVy_«¿H¾r¶Ùó\M=O[_[àÔŽ^¤ÖSÅq°4,jú³½ŸžŽÓ²”ž”¹{>î{š­ 9Òù8“­:­µŸi½/´µÒS+ïsi]ËWî6{æ-ç<§ýŠÃMàEs@OÃsƒÎ¥ ·$x7)™ÀZ’¯³J™×qÖ@lZ·wÒcÞÏ2üÉÈï3L½*9ÆÚ0œ=‚§–ÁÆZ¾®¼® Q™›S°ôµ¢¹¿í!ˆ[V«N{ÛO˼oíkÜ^÷p_Ås@J?™9 J–öÑ:HYÊWtŽÊ]qHV­:ìg.”Ù^m¬ö±¶êy.¯½tN€B-瀴ŽÓjÉY†í‘ιÀ´ö¹šCî¢sVŽîµšûÓCÞ§çiÊy]ÛÅ¢…p>±7 O/Ãðæ9+Њ§Âk¿ëeØÆRzRóÙOÍ€wég©_о±ê­ƒ¶–æ–uiÏ5ÛF¼Gι’|õò, @¡§—Ð[¬9 KiIP±Ü”ü}Í|EŽMKÍ@giÈXÊ1öHwt}Ž=ò^³Îj•ÍÒ§’z+MSι—s^D·‰¶׌Ü|¥Œu@hïLQí´ µcà`Á9 ¯”´ ®} ¸³¢u@€¼NÈÜâ§ì3|®¤€Vbàx.à¦Z®P¯bP¡Ïà ÐŒ9 Òbeõ^Óz¦¼k[À%í¹ÈR 2÷9Ñš+^·²¢ùJÙ_ôïKÊ*ò·)Û¬mÙf똑ÕËkå}®^}ú6MúJißgºniŠæ€L×1¸ÊÒ+æ+’‡iÐ7÷7‘mRŽÙ*ßWm«ÝèeÈZk•÷œ7[û˜ Ô#Û¤³Fg çI¹ÅÿòÛs«Î›:€ëŠ Áúðn>þœNƒ—­àqígKûÿMÊð Ò w+=[éhÈ-•MnP8†³ü×z0Nïø_òœî§V[îg)ÀÞj‡Ó¿‰«Å[ŽÒsgœvÃêà|Šæ€LºÔ s)è- ^ÇÃJ&Ë–äë¬Ræuœ)è‹ê{”U‹¶zgÊ :œòªäkÃpjkènåëÊOZ׆ÃÌÍYú2ÒÜßÞ%`lÕ>jÆ …â9 ¥ŸçÿýZG¦u𺔯è•»ê}HÖePzND˵ÆÛ€l-瀴ŽÓjQ´³ 3Ú#sní!s5‡Ü-å}¯¶M{Îñ[ÍJMst‹kbo@ž^†áÍsV ^O|×~ý²T‹`+ÀŠä=²ŸšòÒÏR¿@}cÕSçl«ý¤ÔÅÚ[‰Zmµvš×ŽÄù•ò, À‰<½„Þ‚dÍY LKƒ®œßÕ ˜"ùŠ+š–šAÕÒ±Ôõ1j§{ëĵêmm`ÍöS£îsVO­Û”¡Œ5W&oqçæèÃnë€ÐÞ™‚°Úi€j[ÀÁ‚s@^))è/ØïiØ!@MEë€À:-;ÓµKt>€îû Ÿ+) •X$8ž ¸©–ë€Ô뀘Tè3x4c ±jt?e§.îUÎwn?µÒ:ýìtî>}¾à@{®2w£XºÐŸñFZã&˜“÷’²Šüí8[+”—nÓ[µu¬­ÕÔkki•óÔr8k§u9GÏã¥ô¤¬¦öS³ÕÌ{|<þ~éz^ûüò° ]Ñé%üÞ‚¤«åkz“œËS­mÎÒ±äú"çñãçÚ êeÈQk•÷­'pÓßÏdµ¶é­|RÒÖúÉé;­Ë¹E‡ùÎíçj¡ÜãöµÛÈ8Üèp‚­áã¿©5<(5¨]Kod(S‹à Æ~ÆC-rƒ¥Ô¶‘[§Kûè]NÞ·Î¥­ý,ý~©Ž—Þ„µ:)»FE·é­sTkžHkU«ëÀ©½H­§Bã øÒpй hÏœ–¥ôlå})_½[*ë½ÚÆ£³“S§g2Í{ä ØÚ~jž7%õÕªS·WÞ[ççñ/ç¹®öÖùˆäkÏãå\ç{?/ŽR4dzL½9M/Æ5nrãáA%“ÇKòu†à%7_­¶;?)¬56å©öÖüŸ­úî­¾¢çñÙÂ=\,íϰB×1€°àW%Ç(†“ø¶ºY¤~açŽÚ_¿£¿³ Óëéz)_¤Š½YÏUc"r$0ž¾zß;à W9ÛO2¯` ÌÊχ«”eíkT/åræk/Àm´œÒú r§à.’ÎHo¼ÝÜö{ ™»Zm«.öv˜ÓN£é™›?Ðs9_µýu]=Ë‘œüê¼´‚õô2 ož³nÆ‘ÔcøÃÚïzYÝv)=©yì§v`4—¶µ4Eê£ÆJÅ{/¤¶ô³^ÚP­ÅÛr‡Ã­¥gn8âߤµþúÒÞרœëêÑC.[^3#×ËV×1€Syz ½ùìùÍó/Ã0 ¯¿úrugß¾yÞÿᵂ=Aäx|Ù©‹{•óÛO­´Öêäõò° à ¾ùúíð§ïÞ‡·}ÿçïW; oÿøÃ0 ;®B{n´ý”º¸W9ß¹ýÔ\gȹprG¯× ~Ó¸©`ŸÁ ™âu@̺cPΠ7æ€\HëU‚•ºPÎÚ¶@jŸáUξ—n6s @qEßH¾Röýû’²Šüí8KÛÕÚfïüÖ>Ö§O?þHÕZÑ9z>ä”ÃYWZo]ÎÑóx)=Ñr>[û©ÙÆjä=%gmûü§¢9 Ÿ>ýøë¿µþl®˜¯éM{.Oµ¶9Kǒ닜ǟk'P¨—9 ãàÎÁOËÎÅÖïç²ZÛôV>)i«Ñ©òt¶ÏrnÑa¾sûiù@âÎ÷€«ˆ Áúðn>þ\ø• 'ØN1þ›ZÃRƒÚµôF†2µjìg<Ô"7XJm¹uº´Þåä}ë\ÚÚÏÒï—êxéMX«s²kTt›Ö£µkC«ëŽ^¤ÖSªñ ei8Å\´g€?NËRz¶ò¾”¯Þ-•õ^mãÑÙɩӳ?)æ=òlm?5Ï›’újÕ©Û+ï­ó³6ù{ë¹®¶î|D®ó-®ì¯hÈô&˜zsšÞjÜäÆÃƒJ&D–äë ÁKn¾Zlw~rYkBnÊSí­ù?[õÝ[}EÏ㳨{<¸XÚ߯ƒÞx$8äUÉ1J†áä¾­n^©_عcç£æ—àÈ@ôlÃôzº^@ªâu@jLDŽÆÓ!-†Ìåë¬C§J;ô` 8Ëχ«”eík”6@XË9 ­oP­¾:Ë7’ÎHo¼ÝÜö{ ™»Zm«.öv˜ÓN£é™›?Ðs9_µýu]­1GdkÞ ÷‚õô2 ož³nÆ‘ÔcøÃÚï¢_–jìoÝD#yì§v`4—¶µ4Eê£d(WÍÀ-rœéÏziC5ÒQ2n-=sÃïø&-õ‹QG?غ¶ä\W[ ¹Lù –7ºzz ½ùìùÍó/Ã0 ¯¿úrugß¾yÞÿᵂ=Aä†||Ù©‹{•óÛ¶p]ß|ývøÓwïÃÛ¾ÿó÷«·üa†×¡=@?e§.îUÎwn?Ú:Õgø\I­­Ògðh¦xs@€î˜”3è9 ÒjeuÔ@nŸáUξ—¬¹©Î¸¢o$_)û‹þ}IY­ýí\¾–ŽQ«¾®ºŸ-Ÿ>ýøk'¤E»± 5p6Es@>}úñ×küÙ\=_WÊÎyµw:îüd¶UÞSŸ‚¯=¥¯•æ«î§´|_ÀÝÅ: Þ ÃÇŸ³‚âµ@i.p^ûÙÒþÆ3Þv¯à,šž­tôô¢4ÍKoVrë½$=9u1Ývº]ë6¶•öÔrn•fàÆŽ^d<ܧF¶6,jú³½‡Ó²”ž­¼/åë(9iž hk奤 Së"¥í<Þj´ÊV#_­Ó P§²0žë1Ì$w"ì4 ª1¡öñ·%pi¾h_ï% éñ×õ3¶íh¢ÅñÐŽ½ƒœ–Om·òå r?õÜgoÜý*^¤tXÇÒð©¹íæ†>íÜÎå«·¡S­þG”v<£õÙÏU¿Zp*-瀴üZ-öv–€65¹Ao¯Zí ö°ÈßO‡ùÜElÖÓË0¼yÎ Â"AÙc(ÍÚïzf³”žÔ¼Gö³GÀ¾T~%i^û:Sn½·NÏt_=¼ÙªUÎM<½„Þ‚dÍY &K:kÛGöUksîÏrÒR3X,]Û#wÕíé1kÕ{­2LIOjŒ~bø¨öžÓvö¶Û: ´'¸T‡ Îy¥¤H ®}u €Eë€pÏNH˯‘pÁ>ÃçJ h¥xs@€l¿ù‡ß oÿéÛð¶Q»­œÛû?¼m÷öŸ¾ ¯bÐŒ9 @9s@€Rßýî÷«¿ÿú‡ï“ög «ƒñW¿³°W'$õÍGZÄÐ Yë|˜ìÕ ÉePΠ7±!XÞ ÃÇŸ‡o¾~«Äà~ó¿ù÷ΣªÎyz^wúx½â¿ý·ÿößþÛûoÿí¿ý·ÿ¾æÿùû´íÿ%Ö ùìùÍó/Ã0 ¯¿úR7ØÅÛ?þ0 ƒ9 @C: €  è€üêUé~;³äú ßÿ}lûcp‘’–Æùx¤/’ÞÞòtdz¦ma. ‘mjå}®mÎs« Ï•iN9GöS{›H¾Ö¶‹–áí'z¼ž¯+À¹€å·O/§ ÆLJú¯Öù(ýû­ 5ºMí´Oƒîqý.ósmàñ³ÚißCJ':Rß‘ò©öÞ;Ü@žêC°ÖÌ?¼ë>PH ܸŸž:gèL½jq”¡9Ó'Ì[Ãxjt¦û(}û‘2¤g-/µ†·EÓ³µ¯”ôì\=´ïQ_=½9ËÛÆZÃØŽ¨w ®&“Ð#o>–Þ<ôø”7ì?ò<—H^#û©™žñßÎÕWJzj¶™’¼ï•®íçñ¯FZJ÷S+=5ϯ­ôè|Ày½ê1Q b)¸8[П:ÿè úLöœø^Zþ5:!µ:2{–át~Õ\b®Ó{¶ùdÀI; gf×:GsOo÷ªÔ*=­ž’GŽ} ¾ð^E‹!aG”áÒG!¼ý™Àiúw{<É="=-‚¾µù¹AhêΨ_†ÓÎpÎ>t>àüªÏi ô6f}.m½ì;7=‘¿ëµ¶:O=§yšÆÞî=ËpÚžt6àšª½IùšÓ‹Ôá>5Ç̯€5Ó³ö„:²ŸH=G¶Y:Öí§õ¹œ4í––_7I,R†^Àõ|öüæù—a†×_}©4 RßKgFÞ€^¼ýãÃ0˜Åîdë`©>W€  è€è€Í%}†÷Û?+1n!º.Žsç„sç„sÒÖ ¿qq?ýå§_ÊqN€sœPçœxH^ˆð÷?ü«RæÚ'ÑßÿÖ9Î pNÀNç„9 @3: € í•"È÷ô?þçßüìÃÿö÷EûHý{8Óy²Wû~c¼ÿ¹ŸAï÷„ÒvîΓ3ð¤Bƒ~ü[º­ÿmË´§¦j\øµ;Ü\§¡·{‡óMäÔŽèLÀYn :!àž­ïΓ>‚ÕèDšž {ìgk›év䈀i«}ï=L«ô\„=Û`ä:2twíÜï;²s‡^;)s?‹œ'â¢ãxRH=^Ûͽ¾«õJ>²ŸÈ6Ó§ž Ðãdï7$5†ÇÀ^m0rŽ^»£çÖÓÿøŸE÷èý<‹n#.Ò9Uãîõ¢ìD¢·ŽÆ´£~ä0-=\£÷jƒ)çVê}½(eV£À«§ýÀQÁ–6 ç{~óüË0 Ã믾\ÝðÛ?Ã0 ¿ÿá_•ÚJϼôËT¹û‰n3·­ì¯ýóßÿv†axÿ¿sNT>Oön¾äãœèùžÚ—Úsô¾='¶ðtî8'Îr>Íu¾ÅE}oÿøÃ0 †`U饗lmä5ŽåæÁYÏ“{^Ï×¶«u­Ÿû]ôgÐú|šý«_içÇÐà|ÎÁ o@€[ðô m Þ€Í$½ùé/? ?ýÇ,wÀ9Î pN@ªð­Ïô•l}FÎ9sÂ9sÂ9içÄCx€\u@̚њy5 ÿ>Aêí_°¯Ï†aøå÷ÿÇï•°«ïÿüýðÿc‘€²=äIEND®B`‚stella-3.9.3/docs/graphics/debugger_rom.png0000644000175000001440000003104312205116016020271 0ustar stephenusers‰PNG  IHDR‰ f¦dPsBITÛáOà pHYsaa¨?§i IDATxœíÝ¿ëîÊy p9,Ë–'à?â´‚1\¸åÞt[®·Ii¼Mn‘2…ÓlHéÊl·]¼¥á‚›@,˜t§J—&8p ÿ@Š÷]YGÒ<~ÍHŸÆœûþÐWïŒfi4šçÿð·Ñ=Ã/ý»OŸ>]½Pè¯~ú£«w¡Ä™íNµ¢Ñš:ÔŸÿÍßu]÷‡üÓù§ü·ýç<'6@F±ù®Þà b3ÔEl€ºˆÍP—ÿzã—¿þÝ™ûÁ9~òÍ¯ÞÆþê§?zM{™¿n˜ïJÍÔ/yÝܹƺQ`ž£qž…p¿ù¡æ»R³pÑu3·çëff¸‡ bóýé_ÿsº0ÙëÍ-XöGú—Á>÷¿º¹ßÀÉ®¹nƧiH»eôzý¨ÑyÉ]-ž~¼'‹;ŸWüÑ~kÓ-ïû·€[º~Lûþö/ôVwrP4*ÛÈùÇU|úåPr\›G‚±ßàjì´·†»7{M6übN/<ê¬oÙwß良ª/žoY¹Àª‹Í©±ßøj,õVð­²·†{8ýðíFÁIϨê§çC³o¥¾•zqºñÙÕ¨~gw~´3³ @¾êbs¾²ž.øÖö®Sç»(Ϧã÷ºDl ¾ÕeŸç ?œ]ÅglAèmtn#p¡fbót¨0‚ÎùVÙ9Ôîç[™_ßXÝñ5ñöíOÓLlîV\/~kÕ[ì%?J]§cÁÎÞ“&<«\›3û¬ü®-¢,Û`¾Û¼ýÕU|UƒÑ5næÓ}97ž…g ß5±9g&Îè.]þèôð?ËÆ´ãáîÔ+³{²êwÝuð3“Šìî#´åáÈtAlŽû¦²¹ZÁõÍ. ^ ƒç1ç­•E­ÚìÚ”øáÈñƒÙnâ•°HªœùØÕ°Z_ /[O{¤õe¼T+´ëÏÿæïþðú/ÿôÿö¯ÿ|ýý懋opð@bóõÄãzì2p °Ñ±¹O0÷ñãÇ+v†3 ÓJ)8õ'ò'Ãÿl±ˆZÜgx¸Ñ­¨/bó0$»Ù|??ù懿üõïœxÔftJýEloOÔæ5Qwè.Ù El€ºˆÍP±ê"6@]Äf¨‹Ø u±fç᦮@×uŸ>}šMN#6Ÿáç?ÿ³«w€ê|ûíÏf_7¦ u™¹nÞ=O[pköáÃWŸ?ÿöê½`•,š¿nþ‡¿ý‹þ£P]²»üç|øðÕë_¼°O/Øá“7Øov¯-´ÏŸ{ÐoncyL»æðÜœW|}ýO}„WÙξ¥ÀV,ÏH§F¼_¾ŒcgŽrkôÌ=,øÖè[çG¾¯ðœy)l ôNVU=ð@ó±9±£ÿFÙißá¦_ï_yý*À|+ø[5{õïÃËÁaw?JÍùÖâ_<îo ÃU¼ÁÅoM?| õ·¦ïf~«¬lzó±y1Ä.~kjûuçµÁ²ÎP=ŠUý.ưÙo•ý­n.ž­ú[¯`–€ýoO½>û§ v>øÖô+‹» 0²<¦ý©žŽ ¯Rp:½Ï¹…F爕)»,[uG6€7þ­á_\ÜrNLÝËè¾Ãö­ ÏÀZëÖ™ûÍùbhWEè‚qæ-{˜¿cwUŠÊÂO*¾NãY…#Ã".pœÕsÁFoåÿ¥þvoWz¿¹àÃñ®ý>gv€7ç‹} ž†Þ²1í3Õ¶?À¬› 6‰½v(8žÆ5úd<¦=ü@ÿÖâæ|kú·v1š»*ÞÔ0³7ÿ¶tþ6‡wˆóK¦Ÿb¶åB?Øß±œgKãòª*÷‚Gûå¯7\O;5—xQÎ ©íS㿞3iy5óçLeîüôcù3®»DáoœopöBl^¾ýögõÓýò׿ûôéS×uøÇ?ý—úÇû×›7ŠÍ[èÓo@%½Tl–ë¢%úôP‰À"±ê"6@]Ö=ßL™Töl˜›÷“o~Ø}ó£«÷€fÓ€ºˆÍP±ê"6@]ÆsÁ~ùëß]²ð@?ùæ‡Ógæi—-0ùÝw¿è¿ø?ÿï)Ø4íý׿ýcß}÷‹Ù×z†ªß?*—Hˆíx]ê~3ÔÅÚ#tÝR>ãáÎ~¬þÜJ³{d‡œ}½(áæ¬jA‹›šý–£b(76ÿõ»®ûúûß¹3T*•>yøÊµá9N =üGfzæø'³…„ÖÍ™mã[2Á§^¹w»[F—Ç´¿ÿúǯ-ŽþÍ3½šhÿŸ}û½^‰×îõ{X¶“uþ48ÇUmüáíÎýfÊNl¯jK¯?úáÃWý?‚Ïž¡wK£ú7;?S_/=Í Ù½?¶Ý /qs>¿0¦=»•ï¿þ±Ámê1m›íJÊÆÙ†Ùuù½›õ¿OV³µ»€¹`Ü\¦Ÿ ³¯ßû¾×™‚¢S°M]C¯½¤~T»]åæ\ß.Äæ¯¿ÿÍôÒÙE3½n†²§Mº¿z.›½rùL·[R¤­Úxq jw‹\7³I0$uæ>ó´SŸ\ü0ÇQò Ù½?­öËn /Çæ×÷=CÅK[íj—™&mýäÚŒ]ë”çMeV«v—)÷ºYT¾½ééðìšu¶–Ôìëá=°Ù ‘ÚNý?¹iAÉÓ²fò´vW=iÓua3XõV…Í)5Ö]ö“Yk:EHñ6$nãU©Ýeò|3 Ù ›=ü®!”9jL[ g ëºÿñ¿ÿ“Þ ~ÿ±ûïªiw©ÜÌ9‰Í’74仿ÿ…~{_Ÿ>}úÕ¯þzñcß~û³î›M_7¦ u› .ž¡â-3áùèÝþ3×&ož¾˜ÚÿÌüÍ]Þ£–£UÆ‚Ý Åd±úõÇv°<@ñóÍ»¤»˜ÝÃ-;y9±™® Õâ —©¥ªOïaÎZžS™Ù«òwƒY5¬ÇN,Xæ¶`¹·øœ¸¬í¤¶P¶~~%Œi³ÉUy×w1ÜáÑ¿ ÒJ²–2¬_~þæí=ÀöÀ¼ËnTBlf^Á)ps­b1}dŠ ’ïǯf eØ„Q£n«ÖÚ½hîŒió2l ¾‡JÝ÷j«…×I6äÐÎazÞvÐ’ÚÍrb3o£9MmÇÅRwʧóÂÊî[³X¶Tnß´ª£ ñøº|¯C¥ÅCNlflUjk;_ðÛG?¹Åf9eØŠÙûVÛÃsÁ[Å=ºÄfºnÃá?±Ð„U?¼é;X•P†œ¦Ý£Ë\0à@©¹`4!.Ø.³¬ {Øn`î\7órã$»ýïÊ¿~ãÒ€µ‚¹`× }«¸ÝeîáÚý¼–ØÌÛâ!›ZÖcÕF5û×S»ï|~§ÿŸiñÉ:ÅU¿}ó#î7߯%Ó€ºˆÍÀš¾çW› ÌP@l€ºˆÍP±êâ*ºniIáÎ~ìòù>ù©”GK¬ý–çžwwùÁCŽÙF1üϵ™Üf¿U¼ÍÝ7x9±™eñêó¯W.ìaË2¨ç]—“jG– kBª—µ…ÔÒ]ÅMr÷ ÖÀ˜6ë¤VÈ[\b¢~ö¿úB u”O–ÙÆ3ÛÂîIß[Ï"Ÿ"6S®ÚVqZ/º,J­§­èš°{–¿Þý·Ý‹æÎ˜67¬¦Û[Û,ƒè ÜïÒV/ɾŽh°‹š;äÄfî`4½k{#Ì\Ó¿¹¾iù(´‡[L%0wb3U2ˆÝëgSŸÓ¯×®Ña£ k¶oŸ$?ô|·Ñ£Klf“ÅŒl'h´í=VÓwèÌ6.0÷Ìcõþ Å•m¹t¿!5Œ›É15¬¬5í¾ÁJ¸næ-HB^ùì§iÜÎü=2zkö[±ÊKNSÖ‚¹`A/tæk 6Óu¥ÙΧo]uÜgîd°rBüzê1-ŽX(ÒšÔf¿[Õ/gLê"6júž\El$0C±ê"6@]Äf¨‹g¨èº¥ ;©ç€Û}vkµ›ñþáÎYþšNlfQœŸÜú‹¬ÕtÆû' r}ªÁÝÓ`A|Å\OîöÛ›YÍ 2ù¦ëi»hnNÎP¶ð¼/cÚ,ˆ¡»qÈsýÔÑ%Äf–&MW¨ÖzI‰ç:l*§Ž®"6³B*› ÂZ˜VŒÆÆFI¯Ø£G›Y°*-«Þ–•VÄ“2RÌ\0vc2SÓ¹`3,rÝÌ[j!‘iÄÕ±²‘Uk &6ÓuK=cêÝ ï:¼8·»“`@{öŠÓ€ºˆÍÀÜ]†b3p  ˆÍP±ê"6@]ûTÆÚ_Ìd1É%Ç´”U‹ŠëQ Ê!6ÓuyvrÞºª9åïdjþvÿJêj`t“¬`Oži—ó!®·ñâzÔ‚‰Íð]p9÷›=ü®!”› ÌP@l€ºˆÍP±êbž6o‹ùšfßí?óÛŠùùäŸS&kå—aêë öd9Þ¦ˆ7µø­‡W´ØL×…‰ëW¥Z^ œŸié«À´sŠ+8D9Tš¢¬üµ Æ´Ùdß¼ë÷ f¬RX0ÿ[l4›šâä?úL®›™—yn[CJ™aæ~O†ï?<«ÿØ u06J`quHÑZ!v`lÞ=ãý– ‹ 0õ®y,rnw'Á€öì+«nLNläî2› ÌP@l€ºˆÍP±êÒØº`d1SPêÝ fÍ®…2»ÿùË>×ð“[§ [±XS9-(µåü~æÄfÞR‹–Ï6¡ÔÂÚNÊÝ’U¥ Ž¿HŠ2lKΠxÝÆÔ‚R'ôŒi3#^}ó &'ûlNïpÒ€ÃfRœ¿yÕýeûyb33ŠÏX TÁÊí©W(0]O[9·k{eåoáá†1mÞ†hf“V>¯Gð»â•Û«ýEw¢œëWÐ3â-ìû·š&6óVv§g”k¤ÂæTp¿YÀØQþ$;êtæ=`÷›{Æ´™Qp§çóçß¶u(¾[ö‰íÇcú]­xxÏÛ¨3Ûx[ýÉî\7Sî®Ý«ñí£)Rˆ¹nfFÜuÞãdvq.X¦{”Æq¦sÁæv ën¯”ó·Èu3o©YAþÝzRóNäÚ‡4 ¦¿­ú"CeõÅ%ÊfSælmú]sÁzb3]·Ô ‚wkh?[v/3„¯ý =g3MÛýùþÊ;“zÓ€ºˆÍÀ~×ʈÍÀf( 6@]Äf¨‹Ø uñ ]f5Ÿ][cöyÄî17ãg:Í~ŠÅGTÎ×ï™Óˆ¥ÞÊÙ¦”"6ó¬2Ÿj'ÏÌ«gŰLXŽ‚ƒä™Ûåâb/«-(‡1mf¯2û¾r1CÆíKà*Šº;æNµ¦¹n¦y}{ž(KÈ ?œŸàòõa™%ó¥ÊvK¾pEÝ.-(“ØÌ²Ê¹×ÑŠüÃO߆ö-«pWX2ÕufÉ¿>6üÿ#÷‘,[α:-(MlfYmæ´t¦¿Ê´|Šó}MÇBþµ¶œc­úʉÍÜÐâ<ób"ÄUöŠñìh¯ûͪrJlæÎ̽ý8O`ž63ŠÏd+|ÛwÏ´Òµ>|øjTì•$Ä6VŸ”Éu3oÁœŽik|} þÔ¼£=œ}6¬ íâ„ðµ ç¥þÆ^PYÅõ¨å›éº Ï+i9ùûŸš¿Ý¿’º,XœPZIQÔf—ó!.TÜ9¬Ý¦£bHl†/è €Ë¹ß È E( 6˜¡€Ø u› .b3ÔÅ¥ .þ»òÆqïç›yË¿ßÜ–‚ûÍq¿ßtiœ/³üÉû{{9™ižClfÆ:¾¸¯Ÿ¦5¼wiœom‘¦r“p'ê´'6ØÏGÛR¤ê‚'0ŒOˆFæýžc:LQßÃÑ-èáljëfÞʦ8UòøoÙnsÁvÿ[ )ÃVŒ¢ïëÃ$èk[P¼A-{b3]Wš>½’Ƴe3CøªÏ34Ñ£ ²K Êÿ¼c£gLê"6zø]C(#6˜¡€Ø u› .b3ÔÅ3Tt]vj‡.qûðió}‚g:‹SÍ?Çì"ÉÅ ksŽÙDmÓ­}ÊY J›Y¤Áè_yNdÅ(N5ÿ(AwÄóB©6^VþZPcÚ¬“Z¨ï!Ic‚|òÅ©æ.³ ¶ÆêUömãZP&×Í”«$m_ÿGgGÃRcòÿþ!œÚç‹ËvUö5¥ØO³ØÆ×®²©e›iÞ4¸|0ÚGôÑ?2ÿÜt㬲6ÐGVõé5F¤ZP±™›8­‘;ë_%gµóœb¬d†^qákA9Äf6©ó†P0¦½‘q•i!+öshA—›Ù$籊 e>øACôã'Ó‚.až6ë4}’»½[ f ›H<ëǯFÅ®s¿‡²zÔ‚2¹næ-HwßnÂóQkŸ}*£ mj&‹I.9¦µ ¬ZT\ZP±™®Ë›°“óÖUÍ)'Só·ûWRW£›d{òL»œq•¸×£´Hl†/è€Ë¹ß èáw ¡ŒØ H`†b3ÔÅýfØÙÇ¿ûî9›}]l€ý}ýÿþÏâg¾ÿÏÿmöu±™®[J“¾˜ÊiúVmR3’â‡)Íc:È–ç›UÊ…‚$TÝšzÔî‰Í¼ågñËÌòt¦ —Ô0;l7Yj;XsßòU‰¨}¿ÅŽ¦ë»•Õˆv—Ã\0îìÕò?ÿÿÌ🳹ë÷k£‚®µWkw™Äfš×§îÿ|xíy=M×Ó.¾üíûqt²s \µÓæ­lÑìF¦™Û%â4«jçõááÿºo¼äToüC*tHlæ­¬a¤îòÖÃÅÖµ‚2/ÌÃͪÐ…œ“H†¯¿ÿMðî÷_ÿ8õ–ØÌ®í(GCÙÓ=q±U¡µuQOb•§ ¦€©‚EAô‰ÍìãÂÈŒiŸäB[jAõÉÜø\7s½ #ßâˆ\ð,»ˆ]ã62«õiíÎu3[¥™ÞFª°-¥ÙFM>ð9‘È}ôPÇì–Ù¢¡Uk”M }T»sÝÌ&q.=WmçñXwþ‹”iâÜŽLÓsß]¶³qk5+¾nö|3pËfÜ•Ø èö7áb3p  ˆÍPsÁ`©ÜÌ9ÄfØÙ§OŸ~õ«¿^üØ·ßþ¬ûæGÓ×ÅfÞRºÌ®‘ûðÕ‚‚‡/oó\æqrލøëÊöd‹#÷2«F Z$6ÓuašôÅ|ž¶Tu°ªÑ£<*tÇàåPÁQ]VþZPsÁØdŸ…&È ''eÕZk¿ÅF»ÕZP&×ÍÌËÌØZCÚ¾a¢‹~O†ï?<«ï»«!.ÛUøYºÏÓ-ðk—íÔ‚2‰Ít]z…Û&LƒkÆnúVf«éŸ›nœUÖÚáÝ}úi‚>‘.Û =±™·Ñesmæ´vÖ¿JP>«Š±’AšJðÅ…¯å›[uYç ¡ÅÙ¤ÅDˆ«4‘Xå~v?ൠLb3]·áì5¸ùTƒøö-Òóæió Ûs0[ØDâY>|5*v§G Žê²zÔ‚2¹n¦ëî›dwô»fŸÊXûKƒ™,&¹ä¸ëÁvW©£º¸µ b3o‹-!ç†ßUÍ)gÂÑè?S;ŸºõJ{òL»œq­T}×£´Hl†/è€Ë¹ß èáw ¡ŒØ H`†b3ÔEl€ºˆÍPó´y[Ì×4ûnÿ™‡ÜV JcKªùGÙXPÏ9Øê‘“ámúxSÓoiACb3]&®_\•þiyòŸõ´Ö¬²‚ Q¤¦Øe¡ßàÝžg¸ºIDATõ'· cÚl2 áOnHS"G¦‚Ä‚ùßb£ÙÔ—üé§qÝ̼Ì$T5¤”&`î÷døîðÃÓ±úÏ“ôÏì(.ÛUL_SïµÏ4jÔqò•²#±™®k|Ûip ²ÌN߆öÌ3’áŸN}¦¹b<ßÚ@;¼{¢„Ot£ZЂv$6ó6º l®aœ¶Ã̵͕rVNÎéˆ+¤y Ôuó‹iÓ›+¾ˆ¬ÇâlÒC‰G¨'±Ê£\rJ¤ub3/Å!¸ùTƒøö-Òkóæió 'f§ü#>|5*v§G ¦ÇTZЋëfºî¾éîG¿K.áÜõ`»«Ô\0õx(±™·Åv•sÃïªÆ™Ÿª=˜É,NÔ¿[PJç|èòW )ÞÔ–mÞ’Ø _Ð5—s¿8Û‡P@l$0C±ê"6@]Äf¨‹yÚ¼-ækš}·ÿÌCn+æ§N™¬•_†©¯+Ø“ådx›~ ÞÔâ·^Ñb3]&®_LHð´¼@í.3^‰iæWpˆr¨ Gä. ý¦þhÁ–ïĘ6› C¸æô"f¬’Y\Áâ‘g6×ÅÉô™\73/óܶ†´}ÃÌýž ß~x:V?Mÿ¼ËÎð—íªâêkJ!ŸfÔ¨ãä1ZÐŽÄfº.LŸ^¿ip ²ÌN߆öµ£mFY·Xh‡wOõi‚ÎaT ZÐŽÄfÞF”͵Óvx—KÀçÈYê<§è*¤y ÔusqákA9ÄfÆŠ/"ë±8›ô Ódˆúš½Ô“XåQN>%Ò‚zb3]·¡ 7Ÿjßۗѹs(Õ»Ò‚†ÌÓæAj;ux‚¾š^ ]µ3¬LW‡rÝL×Ý7MúèwÉ%\ƒ»lw•š ¦%6óVó¼ž[€9ŽFÿ™ÚùÔÕÀh%–-»ô(·n U_õ¨e›á ï€¸ß èá3z ŒØ H`†b3ÔEl€ºˆÍPó´ùÂìÌ •“»‰Øò\¬£î|q"5r±™ß›Íð#§=û*;¢‡WYÌ)ïÈŒióÖ·®ÙÅ"àZÁâ‘g6×Åô]ÆîÄfºn©ŽèÉ7]O»øò·?,æ¬ê4XKlfÁ«ÉM{XØnU”u•Æs¸ß̲Qæ—,ä Ž–²ÀÜoÖÕ37&6ó–s!ÒgƒÐ'²ÑÚ£¨žÄ*ôŒ^Glæmz°ÿ‡N}m9¨õHulç~3p éLg{ 1=þ*®›YgP—𗛆 {Õt±™®[º™·cfuž&>·£ ³UfÀ¡Œi@]Äfà@îPB±8À Äf¨‹Ø u› .ž¡â ³3wRÏÀ˜æC™-OU9êÎ?߬FŽ 6ó{³iÒå´g_eG”ãð*ÃrNÕ‚ºØ1mÞ$à£f¼Dœ¤Y§q±™®[™&]ŸH¾ézÚÅ—¿ýa)0×`U§ÁZb3 ^MnÚÃÂve)œ…nÏýf– ï6u®›Y#8ZÊs¿YWÏܘØÌ[Î…È«+Ô'²ÝÚ£Hf… ½8ŽØÌ[*MºHÌî¶TŽÆz¤: ¶s¿8Ðt¦‚³½†˜×Í,ˆóïNÏ”5]9l2ìTÓiÄfºnéf^ªAj¨,ŠÏíhÂl•™p(cÚP±8;”P@l$0C±ê"6@]Äf¨‹g¨øÂìÌÔ30¦ùPfËSUŽºóÅÏ7«‘#ˆÍüÞlšt9íÙWÙå8¼Ê°œSµ .vgL›7 ø¨™Å#/'iÖiGl¦ëV¦I×'’oºžvñåoX Ì5XÕi°–ØÌ‚W“›ö°°]Y ga€Ûs¿™eûMëfÖŽ–²ÀÜoÖÕ37&6ó–s!òê õ‰l·ö(’Y¡BF/Ž#6ó–J“.³»-•£±©NƒíÜo4©àl¯!¦Ç_Åu3 âü»Ó3eM—E›† {Õt±™®[º™—j*‹âs;š0[efʘ6ÔElä%› ÌP@l€ºˆÍP±êâ*¾0›ŸuøŸ«Þ­GjFRðà¦g:³å°1¹ì|Ãú –7Xµ:zê+ÚÝ‹ØÌï¥Ò¤Zãb¢õvu¤ÿ»Á¹Å4QGð[âŸÉe‡M=ÛÓçµe5¢Ýå0¦Í[f¾¶R;¿~Tÿ»†;dŸ•˜¶B¼Äîå¬Ýe›éºÆ[ÅkWûu›ã=Ïéh„M×Ó.¾üíëEÜ’v7dL›æ Çá÷Êòk ás¤pNÝyá8©ûÍ©ÏÓîzb37Wv±å¾×^‚¢+®‘nÃYk¥n .swlÓîzb3o bŒ†²gç²­ºØN°¶HeV¸JPÎ'ÜŠ~l-‹Í¼ÅGÕ,Ó>É…¶Ô‚êã Ìc¸W­-¢çO8þ.sRv4 ¦î’z¦’§TƒÙF³kÌþ¨á[£ïÆ+¦¹ŸZ¦ìÑØÎä²Ó-¦›}=s›Û×–6^3±™/LŸŽ3¨çû;MÙ“”©(Î'ÏPA¡)ùKÄÅ^–šb÷Æu˧¥iÃØªlÖí6þ«lÏÚY¼vT–ô]ãÊ$6³Ú“ kM×Ó.ö¹(Ý'[«¸Š1mÄ+ÜÖó5¸¯Y|Ë“í ˜èS8_µe~Ë6.6³l4ùk4$ÕUÜh»›Þ‹jÈl!˜œãGrßkÕ\Ú·lãÆ´YáóçßÎÞʼÕ/e÷›·o„25æ»›Yt…gÎ!HœL`¾„ØL×eàØmÂóª)Á÷øÉÇÙq.ç þ²™óW&÷›éºIƒ‰r¨ð$z÷UPR3àš(Ê)ö+ž(š¢qå›y+˜OQÉ-À²™ ‹»šÿ« ¤&(\²3¬UÜLʾµËD„-[«‡1m¨‹Ø ÈL"( 6˜¡€Ø u› .b3ÔÅ3T|aöùÂÔC‡•<Ì6*λžÿ“;·T‹'!0¹ìdñ3ÇÏ7ïÛ¸ŠÛxåÄf¾0Í]'<¯?…\ÁãÁO^ÌÄEŽ‚ã$>9H\ìqG±vƒÅë–8Ó†rÂC²B+[!’ãÌf;nûO#6³Ú“ kí¸žvßû?¼×>“±Š«ÓfA¼dnýëßnÏ»ž -ú©- î7¿ |øÿ‡í3Ž(ó]×ö6^!±™e£É£¬®î(U¶Nø¨I»©\l¶GLÎñ3;‚ZíQw?{•öë–÷›ÅfVHEâûu”kC«ì’Ò@ùŸfߣ]ãÊá~3 ò§Jº¸äz퓉”—›éººkxöôÎ;Îã|Á¡¾ËÌy+Ř6]7w(õVWå…Ëî« ´;…¤~MQô‚ÆOÍÙ ªO›y+›3•¿‘ã”͉wuË» ÍŽ¦(ÀV,ÖÔ.S¶lð–Á:cÚP±8Û‡P@l$0C±ê"6@]Äf¨‹g¨èºpÂNð(jCëÄ?0X¿WçïjԖ盫=Æî-UìÏ7§6¨Ý ‰Í,[›–à|ý^ ~š¨£K/ˆVáo¼²Sº†Nï'•ûkøJqæ¨!Ú3¦Í:£•€*OwÿÚ¥×^½þQù“¢î®Òu\ùKöª»b3›|® Ý}¿ý?‚—æSlºžvñåo ÛÓàÌ ’"6³Õå "‡—ÅÝ—]ЕÄ;üŠ(ò4mí@èì Ñî2¹ßÌÍ•]l9µßKP’e¹ß¬+°ûQ¡=±™æ†²§]vßëÍë±¶.*I¬ò@.a/!6Ó¼aÐ{|á¹[jAõ,óÑöå~3ë´Ûô#—›Þ;lë"ÅÌùC¹næ-H²[.ôa²÷Ñë©ç›GÝÊèëRJñÞÃè‰Êœ¯hw™Äfºns~òšÛOj¬û®)Ùk3S­x²x›mmjw™Œióš=б8ÛP@l$0C±ê"6@]Äf¨ËÏPÅÙì§/Ž’O_Œ·ï9RTÖcSêÆÇçC ¡Øbó§6ò– jAÝ…Ï7gÖqª’WR»«(©âH||Z‰lÑô(Rh5+è·lÐÁðRݘvNºÐœ !Šœà‹öÅÇçJ`w ­f{uÈ™t0ôª‹Í‹U¥òÎÑPºû᪜³«7Ï&…¾’Ÿ/68>™³â²Uh•Û½CÖ‚2]6¦,ѬѪòR°.îè»ÖK¿ó³<8„FwÍ3Eª¬™k]~VGŽÝ;d-(GK÷›µáC&5WÔ§í°cr•œõ“cÍvïµ Õ庘½‘š3¬^°ê"²NÁþâãnf÷Y ÊT]lß>Î] Ó,P8ˆùPíÍˤ fjûQaZéZ³³ó®ÚÖÚý€×‚2{ÝÈçIúgv—­æ\¹Å6nú —Åæ Fƒå[3o‹:De\‡ÇIpõ}ô-‡ù^e%<·k§µ ½´t¿9®ø'×"]À]UërÚ¬‚jÑU¦õªÓÞ=•7‡ªós0¦}Úß…{Ђ.Q]l¸ñ\¡œÇ*.”ùà¢]¢ºyÚ©iÀT¢é9¢[ÑUÅ>|øj:ÜuÕΰ£½êÑñ0ëØëæ²§ƒ¹`»ÿ-zA¶;;ctª·=—ðt Ùe9ë´  î¡¬µ LÆæ-ó¶2ëxÕç ”UÖô­«*"'Só·ûWRgñÁsvã±¶Ÿq¡¸—Õ£”£¥ûÍp½p¹êî7wÒô¸ŠØ H`†b3ÔEl€ºˆÍPó´éº0Ûùb¾ÕÔO“™¥7»¢çâ2Ÿ–¥ÛQ ‡ 9ÊZPþf§ß*ÛàýˆÍ¼•-1¿c§ƒdU‰¿Õ¸æ_]3‰_ÄÎnM.¢ÑRß*Ûà-ÓfÆtåÔÙ7m6«Êª/æî!>ÍiÁ·Š›ä-‰ÍÌH5’;É.®ÜþZz´´îc­ézÚ.šutMI¦0dL›·vÍŽ¿+X¹]Ùs(ØVœsv^–L¡N?~üî»_ä|löu±™·8µ{{µà~s‹?³Z™åOåι |³ûÍ?ÿùŸ-~&¿Åff´‰óÍŽNçüdƒØ»¸ýÆZÅMò–Äfr=¶‘ŒLG¿¯Ú“v=¹Ï…æ‚1ã ]g0ñD¸ÝÑt.ØŽ®ÛÚBÙÔ­à[æ‚ ¹næ­l.Øðù‡U_ÜWY†àÔÄ“éìë'÷Gѹq[(›º|ëNsÁzßýãÙ׿þþ7Á·Äfºne¶óíÉÕ÷µ%U{êù¯×P5s¢Óº¸¾ÊjsK›}cÚp”Ùëãø¢¹›C=ü®!”› Ì0ºJ^¼hîÄf¨Ø ðt9+X±E­œsÑ܉ÍPÏPÀá2¯˜_\7@]Äf¨‹Ø u™¹ßüí·?+ØÐÇ˾7óñãÇTnæÿAR}b ð|iIEND®B`‚stella-3.9.3/docs/graphics/launcher_override.png0000644000175000001440000002004612204753072021341 0ustar stephenusers‰PNG  IHDR¿Ä©ö$pbKGDÿÿÿ ½§“ pHYsœœ&Í:4tIMEÝ- ¿Ì30tEXtCommentCreated with GIMPWŽIDATxÚíÝ¿ŽÕJ‚`ƒ7`$d'‘®DÚ­y%º'CD$„pC¤ÍÙp“1Ù$hV"=4ý½Á\÷úúúOU¹Ê.Ûß'!ÔÝ>þS¶ëçªc»ž|ÿòááóן œÁ›×/š'—ËåAQp×ëµiš¦yÖMB8²÷ÿʾ橢àl„„?~°Š‡Û»æáöÎÏ~öóÉîþ>Õãs~u`á÷ß—‹‚€»^¯ÍÇ¿ÿ½yòåCÒçßúÖ4Mç9?¨Ý“/šæëÏæãÇ_œÔÍÍ»äàëÒí Àé?v#G?? .~hùAÍrôóꂦ‰¼áååHSó{J©]Ö÷+¼5–¹ÅvÁóçnîïìvÝ›¦ÙíúÃiZ~ß¿|xü7ŠGôòö®ªí­m}JëçoãýI-ÇÁ¹Ö:ï±|8W]P¬åwtZcu]Ü•ê)~C-‘n°t»þºÓN…ÏXwáÔ²æ>3ÖrZþ4)ë35]lð†¬OÈïR×7dºÜís~±'OÓü¾K±ÿ»~kfª²;mêIÒzšfhæÖyn>9—¹ƒo,WÿÎ/´â „—·wƒ¿ïVÂCÓÄ„ØÜ|æZ|S݇s»>¹×yiÐLí‡\å\ò¹¿ÿñØ-[)÷Cpìó9–5ÆsÓt—²Î!óɵ,(q^—l&…_®J0ä3±•ûØt[Ýh²e8´-ëvÿ„”Aÿ35mïÃí]ÓŒ¼Þ¬ôwQýŠ(§ÖaO!ܨý|¸½[Üú[­Û³tå^KàYÍ7Ö´at¤Ðȵ=nRaï-¿çWöð›úž)Gëe®¥QKwÜm]¦ýïüBZcG¾úÕ’ãÈ-¿©ï×OónϱïäBoóïN“³õ²ü5E˜j‡vûÆL7´]íï÷þøEÿ¶þ~׿Úß…w³%ŸëõÚüúö•‚@øA­ i”Ÿ·æp6º=~ ü@øÀ¾EÝð’{Tðv~9ç9µŒ¹e…l_È:ÇLSr0Ùþ¶m4÷çÏÿü‡ßÝßÿÈ2¿%ó‰YçRË*mùõ+ÿ¡j?ö·ß¿|˜]VŽuÝ®5t·9dÛ¶\×%îï<†ÈP Æ„ÒÒùĬkÈ:•Z~'3J1a±f0,%ƒëÈ-f8›"ÏùÅt5Žý­?’Ý„)݃©Ó„.k® ‡Ê#¥ŒBÊ9fYkteç¨ì§Z_c››O¿õ8ö»ØõM™ÇܼŸ?ÿ³.W„_‰ éW”/oï¢*Ã~ ­dEºfeȲr•amå¼eðõ)¥òïOŸ:ŸØl®ù…ªä¬6éöìVü{ùž)dKnזݤý€œ Êv=÷¢ÝP8r—`û}c÷hù ‹¡ ro-uÞãvÅT¨Ýßÿjeí=sß Âo¢µµ´zrÇÐ÷y{*ƒ5ç€=X¥Û3×mô9æ³×–Ùš" -+ô»Áö³[tg‡~G¶ÇGr­s[6‚-¿2T9¶]¹°îÏ/u>Sw!nygéвBÊplšÔíÊUÎ[ÃXk¦mí,}¸|l>±ÓÄÜÉÙŸ_®À|Ð4O.—ËCÓ4Í›×/”Õ·š?ýiH£nnÞÏSxÿé[Ó4ÞíIbK`Ï„³ÜÅ ‘Ü @-?ÐòƒuÜܼS€ðã<Þ¼~Ñ4¯Ý•,£ÛáG§Û“]ùüõ§B(àz½zÈá5ó†—üÜDÄÙèö@ø€ðáûuÃËØÛý‡Þû˜kü½5Þ)95>aÊzM˜2MÉ2È5îâ†ÆÍ[2VÝ£œ/Wذå÷ýˇÇS¡¸–\#‡çئ~` Í'dšµt·y­rÎíþþÇcˆ¤ŽvÞ0¶ÔHïÝu Y§½8‡lùÅVª{ÕÕ¼¿kn—‘⃥ -ªéPU>¿­° <´ uj~ý¿•ì&LéLfI•ÏÜïb·=t¾cË éòÍ]ÙåTˆ¦Ì§ßzû]ìú¦ÌcnÞáW¨µ2Õ=6Öí7Tö+Ónk,äókn×–e8T>¥Ögß ö)¥òïO_ª•ÙïzÍ5ÿ¡P€¿Â­ 3è–ËX…L³4¤¶Ðï*½ ©) ‚þ_ò /‚/­\”Ýv7vI7¦¢;=ÞˆÒ_7Ó üTô)Ý€ÝÏî±+}¶zúÿRZ‡©Ÿ¯±å§%ˆð[9»s«}è¼—~/·×@^óQ„¡e…~7Ø~6÷º†~G¶ÇVO®unËFðqvÅïöª»ß Už)!œ£9uâ–w–¦–áØ4©Û•«œKÃTëf(8Rnv™  ibîäìÏ/W` >hš'—Ëå¡išæÍë«¶Pú•§îÏc(½?ýiH£nnÞÏSxÿé[Ó4ÞíI¡Ö*@Í6Ì6w·'Û›{¼àôá§‚ý© ¸^¯rGøAͼá%?7q6º=~ ü@øÀ¾EÝð2öæþ¹¡‰R^x²,Îmhܼ%cÕM Xj­;¿Ð‘ºsXsYì[ íÀ¯)Ò0vÉ|bÖ5f€¼t{rÈ$®Å Z~ZlíX}¥Çx ébê>Z—”é´F÷[ÙOµ¦Æþ67Ÿ¡–ZJë­¿œœ-Àv^¥Z¶ åW™ï_>Œb70§¦c¿Áwÿãñ_jë§;’­Ìîü‡~Îu ˆðÛq uC*¤•¹4ØúɱZ†G„~xkùqfE^oÖíúœ £šhé#à†B!¤kqïÁ˜ûîX~¡5w\K+ù©ïóöTk<Î{°ûïüb‰ˆ™n¨%Øþ^+±Þ–Í\¥Þ>ʰ·m˱ÎmÙ>´ü †R{Çg ¦îÒìwÓj î3ô†*õîs{KZ‚có‰&æNÎþür–àƒÄð …á3]jØ&ò­ÄC¦[kš”ÐòÛu·§®GN~¥¢à˜v·g®îL´ü@ËjqsóN!ÂóxóúEÓ¼~¥ €Et{ ü@ø€ðá„TÄs~ìÊç¯?B×ëµùõ­ç'~P­Q™ykg£Ûá„ì[ô /íÈé]Œý}ÙtË#×HóF¬÷üùŸ÷óýýë äkùu+àößX ¾¼½ü}©ÐYkY1åTÓ:=øîï<I?`jÒ]O`G-?­¾ô2å‚OK*®Ü”¯p¥?Ö]7×}Úý\wÚ¡i¦–ò»Ü]¹í:÷×}lû‡–ž¡ë=·¬3åP@vC4dº~K.fY)ë›3ØÛù @Î.ªÛ³ÝýiºlÿçþïǺOû¿›&dY1Û7ˆ¹ZÄsá;Ö½2ç| q¬[´ „¡éúÝ«có ]VèúæìÎ[WÐòK¨ÔÛ,Ù¢hç½V«¥m±•Ø®~ð•\ÖÙ[{CaÔ¶î†Z>±-¡©äܲ¶ ¥ Â/w ÷ dkJî–Y©®T~‰­•¸VÝ^°&%[u¹ç;÷&œIô£)!µ·ÇJ>S×ÿn.ç²Æ¶}ìûÙ£„Qÿ»¹¡ ¾{£GJÅ?Ôê›[ŸÔe¥.?¦Ìg÷är¹<4MÓ¼yý"*BZSwŽUÄ©ˆ/YV®»=crO½Ûs®µ|ô»=?ýù‡QBº"Cïö ù]Že…´*K·»nnÞÒˆSxÿé[Zø‘·§ì;ü~~Þí Àé?NÇHîîN-?ÐòƒºÜܼS€ðã<Þ¼~Ñ4¯Ý•,£Ûá„?~ ü@ø€ðá„?=ªÃËÛ»?üÎ`°ëëï‡ZöA»^©ë³ôóµ.kh¿¥,7d¿oqllQ–%×#µ s/_ÝZI˯»CÚcøòönð÷¥øµ–U‹nùï1¸Ïxlô+´”õ Ùï{>6œ_TÛòÓêÃñ€ýÎéÃo®»`¬ù>×}ÚýÜXWQè²RÖ{l>SÝV!ëœkY¹·+´µÚŠ 鎛Ú_K»îr.«DWÿÔçsì÷”r;ÿrí÷”ó"×ù\jŸæêUO®ý5·/Ö>·ð4å„m»’†º”úÝcÝݮӡihg M²¬˜ ~ª;7´ÛêåíÝè|r/+Çv­ÕM³¿–®s®e­Y†¹öûšËŠ9çb΋¥•îûtl>¹ÎÓ’ÇÆÔ¾8‹§Kªµ ®]Κýðýeõ¼©m]Ç%ËZÓ¿[-ÑšºhZk¿Ç,+×~×5ZÏþ ÙKC½vÏj¨ ΤínXóŽ<µ}v»™„À1ö)ÂoñUÌÙÄ¡~ù¶bå¡ ÷pQXºÌíÓs‹~Ô!õ»§½ÝÚ>v"¶¿K½Šé’Xº¬Üû°Ä…ÊŽÜ•q‰ýžº¬Rû}ê‚x‹®¶Ú»ô·Ø_c÷uÅ“ËåòÐ4Móæõ‹ä®‚¹/hçvÒØ¼bNþÜÍ'ônÏØVnê²BZ•K¯x§î‹]Ÿ¹m -ÃÔ}›²¬ÜwÎ}6×y“ûxNÝïk–s®e-9¿–¬wÌò–쯘;EÖJ~ÿé[Zø”lùåºè©ðónONç™"¶¶Å]Ð?€*Ö¢Ûá„¿Yc/_ ý{ÊòŽþvŽmîØ­ýØÞÛ¹—û­EÊ_ø¾³²{kóÔßSu_“´ôu^µàG¯ük_~Éu ªfîÜÜöøTþ•´üæ®JJ_¥, RPÁÀ±}ÎoªU×½z™d4Çhýy„üÜ¿ºŠùûЕÙÐòR?ŸreXãòSËjþýÏ„¼·pÉþ ywi‰ò=ïbΣ­µÿ^b¤ø’õCÈñYòø~Oпäàž Ý¹¿‡\S?ç88§>?´þk.iùÏ­ßÐvô?[>1½ !åWsåSúøXZ>sŸý{Êî%Ïï¹òÏÕ(Ðò« Ë¨ä-µ^Õ„V¬ý =õÊ4%¬r]|ÔhíõË]¾[¯¥©¿‡œ1ëûµHÈòs×7‚ngá·ô %WhíñJ)´k8æÊt­“-Çò×êuØbýÖ^~ɱK|>¤|æÎµÂ=ÂÈg½âÏùåúÞp­¨ße»ô†\¸îuù9æ]²¥“{ÛºwR¯uÑ·fù¤œ9Ë?÷ù¹vùoq|Ôh•ñüR xi‹qî*pèÆˆØ/Å—~¡=µ½9o(˜û!µ —.IùOµÆöU®å‡ º{ÃEÿ;¡©ù§ ú{>-9>J—OìçS濤ŽÉq~‡¬Ï’ã³Da/ f 'êépƒŽß‡Ÿ!à`†ºáŽß~pÐ ã¼Øá„ßqœyØ£#o·—˜+S~'óÔ°GG?ÙK?ô¯Âܶl”=¿UÂe ìÇauXòËC¥®È=±os‰-¿ÒCþä(¿%ûoéñ“³üRÊgéüç> ÂoG­Ž¡×Gà9†ÔY@9†ì)Y~k ù³4Àç>¿dHœû/¤üR¯¥ÇïÒ!@øUÔòª˜—Ž\°$LrÏÍòÛââ%÷ç—™3·ì­‡¤Ê9ÿ^Ü ÂoÁ•wM•óÖóߺüj?>–Y³õT5_PƒÓ iTzG¾{ïèwvæ2géçKy´õòAËoC7¤t#Í}'XêJ:tþcËÛþ¡›f†Z&!årÃEèü×n‰ÌmßÒõ ù|Ìñµöñ›cùP;CpíFžóàt„„?~ ü@ø€ðá„?~ ü@ø€ð@ø€ðá„?¨Ë³-þòö®iš¦ùþåCÖùåœgèòÖZæ^ôËfªŒ–¹#û_ÇVÍåîÑò[=HÇ*ß—·w£‹Õ=ÔãeÔþ›Ú/k'öÿ1ÎóZŽ©ã-?j BH ߱áÃoèÊnê ŸêZ›:‘J®w9CË[§µ»s·Ú¯cÛÚ…:5?ûÿœA9Wö!ÓÅÔ-K»î×Xÿòt/ñÒî³~÷CéîˆÐnس·øæöÁP7ר‰?uŒØÿçm!N}2v¼„Ö;9ös®:Žƒ…_ìUS Lÿ„«Œ»¿›j‰ôOнí›î÷lg¸Zµÿë.ûÔ–SÄ,+÷£ca¹g{;¨Çˆ3U®{kÝÙ7ìõ¸]ónM-=á7z0ÖxeI\E’rµÝ¯„¶,{ûÿ\ÇíP/F©}ï˜Z×.»=sÝ®žó¶÷¡ƒx®K«?ÝÔ ¥ÖuíŠ$vƾ©é8²ÿ·;†Æ.ŒBº“—¹–³|ÇB>O.—ËCÓ4Í›×/6»Šž» é¯9ð–¶"RîR,=M(cûq.cﺋ¹sÒþß¿òÏq§mŽ;0s㎅|Þú¶}ø¡-GˆÚÿ@løy·g%W¯ØÿÀz´ü\õï2(´ú€%-?¯7ÛJïÜådÿÃvt{ ü@ø€ðá„?~ ü ¯7ûÍç¯?£¦÷.Tûû-¿S|×ëõñ卨ߨhùíÚÇ¿MwsóNaÙßT¼/rŒ:h1Z~›ëÕþ Ä)ÝÏ®¹îÆzÔòÈB« áÐä$9d>sÓôÿn cáÝÊê> ›þï^ÞÞENÈ|B¦™šá€ýŠ ¶5×á°š\7—¸IEøì¶…¨%wuךKi‰åzÌ d>¹¦AËà±6wÃKÌM1ýŸcç2ÍØ´Z”å<¹\.Msî÷å}þú³¹^¯ÑŸûõí+Gý}ÁŽ´¯ÇÓí™üN>ûû-?Ðò€Z ?„?~ ü@ø€ð€ŠìúÝžŸ¿þŒš~­ùk]¯½³¿íWåÇé[~±'Ìõz}|²ÿŒëu¶ Òþ¶_á°-¿¦iš šîææõ:ûÛ~36 8DË`Ê÷/ÿM…âZŒÏ'ü`S³Ni¨ÖïÍ1MÈ ¸?€Õ‚¯R/oïþÐMºtš©i~E[v9BGp ?€ª}ÿòa¶µ5uJûùu#‹ð¨.»Ý1-¹¡ï÷†æ¥E¸?îö€!­³~+/õÑ„ÏyìAË`ÓáX .×4cÓj- ¿d×ëµÊ7fÔº^{gÛ¯1-½”ß•š&eZÊÚm·gÊËm}ûê´ëµwö·ýªüÈéÉåryH=`OÚ£»á€Ó~?~ ü@ø€ðáñnÏß|þú3jz/°¿-¿SU„×ëõñ-Øß€–ß®}üøKÐt^blZ~ ü@ø€ðá„?~Ä^~s½^½ÉÃþ´üÎ#å¥Å¿¾}¥àìo@ËoßTnö7 å„?~ ü@ø€ð€òvýûç¯?£¦Oy³ö7 å·ÛŠðz½6ï?}³Çío€ý¿ÞìãÇ_‚¦ y‰ñËۻѿ}ÿòapÚþﱿá·K*8û~¨0íoû„ß™õ»Ê†*ÅnYwú±®4•¬ý ¬Ë£#^ûo¨²š«°Ú¿÷¿'êίû·î<§¾‡Âþ´üŠÉy5ÞÎ˾ý ?z-ìo@øiu`ÅøÎ¯²V–ý hùUYa ý{EßÞr7!ö7דËåòÐ4û{âç¯?›ëõý¹_ß¾²×wÈþrh_{¸ÛnÏ”°Vî—ý ä´ënO•Û¹Øß@.nx@ø€ðá„?~ ü@ø€ðá„?~?~ ü@ø€ð€#‡ßËÛ»ÉßÍý=vYcÿ–ÎÎ*ç9s†ó¯_çœmûŽ´ýO—Ò÷/þðûï_><ÐÔßc}ÿòáñßÐÏ*«sUBG öW¾¥ë›­·nûŽTß>+¹ãÚŸÏPG?AN~S­ºÐk[¥*én÷—Ñèܽ@è~¾-“±õo²}cëµdù[oÿÒå/Hù/ÙþÐò™:cæ¿öù7·þ¥Ë7äüš;>bëŘz.æü.uü ¿…~7×.Ü©lîà\ú÷'ÇÔÏ! SÝÊK—¿tûÇNæ©í˽ü%ó_zѲþ%¯±°Yëü 96–ÖKŽï¥ëŸ£Çfjy¥Ï?á—±Ëm‹B[æÔ ß Žn…úù5ÖËò )ŸØ+Ï”“u¯å»ÆñóùÔïßk>~ç¶çLßiå8ÿ„_æ+´-¯6Bþ±îÃ5¾ð®ù íÚŽ¹rÝSåZ²üæÊ§{ÞÍ}õpF!Ç×Üù•óü«-hrœGrúçüÆ•hï$;8J\9wãXÒ’-YV¡åSzÝ·>yc–[~¥ËgìQ¤%·³çÞ¹¯¹ó+öüËõÙ-Žï³·“»=S[[·ú¦¾ð]ú÷¥Ë™gÈ 1c-‹µÖ?fÝ—vÓå<–Bæ¿ä†ˆØãklú˜Çˆbç¿´\§ÊglùsÓä>¾R»>çίÇcLùå.Ÿ¹í Ùþ=yr¹\š¦iÞ¼~ÑP_·8þÖÙ¾¥ÛŸã†Ê{ÿéÛ²–p,*éò=hùÀf-?/¶àt„ÂŽn—7¼¬ñ~±ånùvÈmÛc_¸­ûÑîF+} vÉùïe_LKSÇf ç÷·è»ÃS˯è•ã!ëЀ©IwÛ‡žÓ™úûÞ.lR¦)]é„Ì¿t™×¼O—{¥Ïïš^ð+^1|bïõD¯}Ÿ×Àµ”ÞßÅʱê9¿Ð7´/2hîïK‡ìY£2êÿºþ5”ÿZÝš©ûgÉRså97ÿØ!›RßÒ´ôAðå;u~M•_ȼ—)$°…_±Šiéë– ”{HœÔ4õD›ÚÆ5ÞPQrȦÜë–²ýK‡”šû}Èû@Cϵ¿› riîü.y|®1¤¯ÈÁ¹F·Jîï r†WÎnªÔ!‹ŽÖµvæÒ–míå2¤ØÜÅçÖõOÉóá·[kœ Kp®e•£fÙñSâgË.÷ˬaHçÇqxÎoÁ•꟭Èrok-w‹}ùS£*”Ø¿Ý;)×(»’wW®ql,ò -¿Õ»%R[H%‡¬)ݬuÈ¢\å_zÈ•¹í_ºüØòí—_éí+qµÆñzü…ITjH!êâÅÖp¢^ 7lpv†4‚“Ñrÿ'üàd¸áá„?~ ü@ø€ðá„?~ ü@ø ü@ø€ðá„?~ ü@ø€ðá„?„?~ ü@ø€ðá„?ÈìYÌÄŸ¿þTb+xóú…B`ÎñõÎge½mÝùÔIQ—ëõÚ¼ÿôMA ø|>+ëíëÎg± øÿý¥\rþÛ¿+6å_ï|VÖÛÕ¾óàt„„̳Ü3üë?þù‡ßýí/Ê2¿%ó‰YçRË=kÏ“­Î”åÕGC󘫷†–½uy¤ÔgêºZ~ûËŸ vìŒ=ØSç³®!ëTj=€²õÑP]Ò­gæê­öwµÖýmj@¸¸/~ý+ ©¼‡–¹°÷¬¦hj'ým­îŠþrÆæ‘»ÛöCÇÈyRcÈüí/jþú>þoÆïÃZêç[jH7CLwFÉVfÿ jèŠ*çvÁÞ+Í©ãî¼;—j À³ïú®öúðií…¿÷ðÐíÀ™ƒ¯– ¯ý®¾Ö›Tް÷V×=«¡§ºæÔš‚±]gwTAú¹_òÜt>®_×ÕÚxy¶uæ¼B©¡ ‡ºBÛï€íÎÛn…í|\¯®«µ¬Ÿnq OuKìí$îwÏú~â ¨¥<ò÷ðcß»ÅnkÈ>L­ëjª#‹µü¦îÊÕ=86ŸØiBïäš_ÿ&Ýžœ¥å6vŒO#9ÏÛ-½Ÿ·CÛ2ÕÂÝG)uxíåúär¹<4Íü €íøS†à(ë¿~–ã×·¯«rޝw>+ëíêÎvÌ?ïöàt„„LÔÝž×ëµ¹þö¥"p<Îqe­å×3w7(ù¸Ó“-8Ç×;Ÿ•õöugð£°wuഄ„?~ ü fÏšæ_oxUœ¤åçávÎä×·¯šÿ½=ŠÙdRQbIEND®B`‚stella-3.9.3/docs/graphics/options_gameinfo.png0000644000175000001440000001470211433323254021201 0ustar stephenusers‰PNG  IHDRÜ*¿háñgAMA± üasRGB®ÎébKGDÿÿÿ ½§“ pHYsMœÞöœWtIMEÚ&§ˆÂtEXtCommentCreated with GIMPW IDATxÚíÝ¿rÜFž`HÅDýëp™i³Û*&Tt|F*®2fŒ™©œø\1¼”û¬òfçŒßâ˜1Ô6dŸn h ¾¯Jes6žþõ¯¼©ªêËõÇë Èã—þR½¹þxýES@‡çCUUUuR¿pu~ªU ±›çßÿûVS@~'C¿¼|ÑB+°Úp|Þ ¶åÑö;Ëpe[eÛ›ŸÓ0+øüé½óà<ÐsH˜áRƒKmï<8΃¶Ïžábvipqœç.¸Àïf/)Ÿ]Þ}óóÓÃmñ]×9´®±Û@Ò€ÛDg—wÕÙå]¶À$ðígr´•ºnqÂ9÷x¶~ÌíúÃcαõ!ú½ÛIšãéáve+õÌ5YiNœ£í´i=¡]»ÝåýSÊ{aã‘ w¥ÙdsÐjnÛµÍP°ŸRÎØ¬6ö¸Æö·Öìµor„6åÏ1£kuÎ9eS·ÝaÛ»ÙÙû:{Úõ&˜RNè@:ðÇ&}Ç^r é;wc“š˜‰ÆP©&tÇЦ©&œ)Û}©Év ç,vržkÒÓžC¯±ž¢îRnÆ9$U9{ÏÚú&&õ¤¡k»ö2k_Y¡û ­o©Kå)Ú´Ý»úußä/G»§:7¡u^k,;bú_ŠþÙÜÏ. ±BÀ­³º%®?•ĶpìíAolð˜3xÅìë˜&0)ÛtÊ„³äv?–IòXýs¶y»lÙmyN–pŽePm/_uê½uö®¶ÉÝfùåO:ôumÉŒ€ÛutÉÕš³·©ûÞËŒsìº}îýQn_Ð×%/{ö6Egk߬Ô÷û¹dn`o×ahv:Tç®mBËYcê»Ö:t=-U‡Ô'eÛ,µ|¿d›¦:ε—K½´’³¯/=é^#ù!Ü›ë×_ªêûÇðÕ‰óx¾¸ÙæÜÞn÷úKÃS|Y{ì— ÝQ;󞺯Œ"GVÕn÷¾ó°T›N-k¬Li÷”çf¬Î¡çaÎû gÿ˽¯±íRÜ”ãÐÕíçiA;òæ ¹ácÊk)ö5g»­·éRm6÷xr•UÒ9ÛJ_—Ý–Çà f.Û¬½\ 0”SnÆY2À’c’É¿€ `b.ؽonšª/ìVUUýø—«úu–Sß4ux>h €ûüé}÷MSu­ ¶Ë»:?­î_¾;lO3‘=`Ë ºl[½bYs—2,@ÀeÜåÝïÿüìg?ûÙÏý?|4«÷›¦ Ù¡î?^k€‡çCõùß¿VUãNñûÇ—on€õ± Æ=ÜVÕãKõù§+mÐáÃÅÍ7Á¶‹%eX€€Ë8_ÌðýÍX)à€ —Røº¸Mx÷î¬z÷îl—uÝÒ±ëû+'Ý4•óy°lãÕåõõ©wÛ®ßmù¸bÊ ýû9mò·1Û m—b›××§¯ôܾÚn)ö•û<–\Θ”çT†Ë~õ\—x}}úúo(`mÍ1WÈ1´殿IµÍZÇ?·.²8¦Œ•I®ç/¼ûzÕ”`Û,SmÓÎ|ç°WPR÷ÒÊ Ý×1M¾S›ý9ܳ˻Þe䮀Ü|x{ŸvyCåômgi;¡?>‡;'£ ]nz­¯¼æß„,wæÈ‡ê;'¦ Æs÷×^2ì:W[\ÅžÓ~:µÏÏé?Súa{ÛövK¿¿6?VæÊpÇ‚çÓÃí7ÿº¶mÆ®mš×†‡Êá8³»æ›½o™·ýZîYv³.}õ ¹žØu\k‡öqŒ]ÏÞâµù¾~ÚÇÚ‹ö±/™‘N©óÔöinwŒ—–4ûnI™d;(“HÏä¦Îv¦¾}ƒüœA«¹”9çf§9ǵåIÒØ@;©)© cD®IPŽ>?§ÎS.?VÖ’|µãÓÃmgÆ™2 •Ñ–9@/5 .9›;®cžÙÇ,£ŽÝ•ZÚ„%ŲzixecÖ—í»”‡>:´õLzw®áÎý(@{àè+cé¤ï¸B¯1ï])Á6v’°F°œZ®k­>’SÀX9`“ :»¼ëͨû~Gþ¬h©À³ÔG3¶r­*G=‡nˆ[ù\ìÜ œë…ô±5?"”jß©—¸÷v¦˜ ·^f ~CÙk_92Þ]ÞUUäãùBîêlÏøÇ¾ aÍŒw¬>±ÇRNÊÀÙ÷Zì]­cÙY×G„Ö>gSÏiìñ§êósúÏ”ú¤Ê¸ùc¬ˆMž‡KP'ºÿxíñ|…ÛòÃ{:ö=ö¿üëoÕýçÿõñ¸¸ñ<\˜ð9\ÖÉÔöZWVÿ+f¬à«ÈêØ³ÛP2\Æýq ÷ÃŶ+²\— WÿüåÏŽTßÀæg?ûÙÏ~þóçÿ:8Žºi 2hß4å.,@À\@ÀvÅçp 6ô ŠöÃ$šÛýnN9}õëÚnn9Së<§ÞCÇ“º}Öès+uߘZŸ˜¿iû˜c_¢ K{/ï.à Hõk]'bÎÉb}c¬«/ÔOzjþmªrBûRŠr¦Ô9WKÝ>kô¹Ç•ºo¤jçT—c_¢ K{/oÝÛc,páæ6Íl'ãšxûåÄ”=µœ)uÎl×,onûÄü]×ùJÝ7æÖ'W› ûu.í½¼Û wJ-1;dÝurÚ3ç±~²|;Ö§SÕyÊñÄ®…”7u5*f¹sêqÍYýÚgÊúôµQHöÓ‡BëÚç§Öcó%Ã혱äàChÏ2Áv¨O„¬~Ì-'4ðµËšr .6Ãèë«Í}u­æ¤\ች¶Ø·²ÍXû„WLÿ™sì9VÒBÚgh›±c©óXŸŸRFΉè±^³MpS5`º-!ƒJÈ4U9±oæ9åÅ\"IQ÷ÀŸz!{ß6)Ž=öïi°^ªÏ‡öŸýx/Á5KÀM5#Œ¹ÎKùƒCÌùš[N{²6çz_Ê(gлqeêq•8BûÏØà½Æ±§Î”ç´¡l:t…(ä=Úí|Å8)­£¹ÎËÔÕ•©3çTåkû”jèxŽýØ/.;xà e¡o²TåLÉ´¦–RçTû*í<‡¶Gì93H/Õ¶kžÓµû|ªú˜ðüiÒópc>‡;tñ>d›®¥³Ôõg©CçbÉmBßÔ)>tZŸ±} ]6 ¹î=u =®TÛÄ|$hhÛŸß½ŽŸâ‹\BŽ?WÆôÃÐ/ψißÔçk«ÚÏÃÍpS ª.» ¸@\Àu  à€€ . à€€ »r¢ qÿø¢zžÕçOï\ÒøüÓ•FèðáâftKʰ\p€@“nš yZÐç15Ëoþ;¶¾liš¢3Ü”pŽvJ™½-‘ Öû˜»¯±rrKÌ ”+¨3®:x¥Ì<¦”ÑÞ»~K´ÉÁ9$ë:ö”õhî?ç|²ZŠ ¸K]ßm.§•­^o.¹ÞíåÅ-k‡cŠ9'OŽ ¸C×1× Z¥Ô§´,;W·V°œZ¥3¦RÏ鞂Оeùâ‹€@=˜—üˆÐœ}Õ»ÖD#äã?k~D(Õ¾Û×çNÆ®OÆÖ'g;§>ö’úJ»ý ˜ ·^æ;¸/YNß6]f{ÛöT9ë¼…/õˆYžÊNCîdn—3v×l_9!u­OªŒ;çù9ö« 1ç4U›RNû÷] ×r‰ñæúãõ—ªªª«óS­A¯ûÇç[‘Êöáâæ»çáÞ?¾T‡çÃן-)ƒ` ,Àè¡p-¸ì̇‹ à’ÓÕùiU¿×¹† .Kʹ|Ñ=χï>$à2™Ïát ¹©Ô’2,@À\ Ф›¦†ž-;÷I6SÊÙâÓtŽÅØÓyºž´3å« ûžr“cí3¿}bÊñ]ÑÈp#ÝÚrz¸dW ¶íÁ5ç~ºžëšzí3¿}bÊñ\YÜ AšR=ˆ¼ýw}SO±ö™ß>1å¶ìͬÏáÖH¯ÿ;»²Ð€ÝµÍÔŒv¬>¤ *K<„}«K‘{nŸæ1 ¼Èp#‚îXp«·iÎæïû–…û¶‘Y—3`e+íLGûh×l‘á&Ö¶u\gÄk‘Õæ©ëÓn—¾;ºAÀ•™î>«m.‡Ö×"û>æÒõûc ¶Ú'.p[bf/²}ñEûZkªÏéÖeMÍxë¿•1/tº²šÐÁyìnÞ±A;æ®à:øå¼™gËí“¢> ÃÍt›Á­lÛ¿)£+ãº‹í»›·ëã-]ÙÔRwï½}޵a®7ׯ¿TUU]Ÿj zÝ?¾ìêñ|‚ãÃÅÍwÏý|©χ¯?û.elx=´´€€Ëª>\Üh—œ®ÎO«êü½†˜È5\pà8XR&Èýã‹Fèqx>|÷± —Éöô9\€!7•ZR€¸ à€€ štÓTßÓ}r>Ç€Øm†ûôpûõßP ^ŠçÜpTîd¶¸çPàl.7·z¸|Wà y}èkíòzRÈzÓTsɹkÙ¹ýZß6cA¯½MÈßÀf2Üì3&8çÌ(ë,úìòºk‚5EܱÀå&øÝì%å¾;”›Ø/n¥|,¨ðû–¼Ç>Ó[ÿ­ €T²Ý¥Ü¼f:7pöeÎcû”U°é€z£QHÀ ¹ynÝb·¨Hm7ߥlywcwT@N'{:Xvž7@À%§«óÓª:¯!&ò<\pà8XR&Èýã‹Fèqx>TŸ?½pIãóOW CÈM¥–”`.¸ à9n×S€<Î ÏpkÜ‘@ Œ›ý9ܳ˻Á‡4ƒr{»Ð‡Ëwö®}í 6›áÖA­/ÓmÐövO·ßÆöÏí2š¿—]°›€;”I¶ƒí²” I¾Ú±ùp÷\d´ì>à.AÖ À–eûXP{ ¹ï†¨®Lv,›íÛ¦~]6 ÀnnWÐí ¶CÛ5× ¦2^¶dÒ’rW° ¦SÊLYm† ¸°˜M@¨7@À%§«óÓª:¯!&²¤ .Kʹ|Ñ ‡çCõù“%v@À%ƒÏ?]i„?¸ ˆeI\pÊ1ù¦©®Gà•ôðOÊçÝ»³ªªªêõõið5ff¸Í`Vÿë Âà­ÿ @† ·äì–åƒî±£Ì(&àŽeÃ]A¹kÙ·ýZóç²æÔ‡8¯¯O_ƒQ_àm¾ÞZÍeè¡íÆÊY*‹t9&-)7ƒaó__pK±ä|vy×»|Ý·ÄÍ2Aw,XÕÛ å××§ÞíBËɽ[:VÉp»2Ì:(vÛ:Cmn3g©êMÞ`UÉ:‹íÊc‚öP9KN& ¸°—Iƒ ¤às¸˜á ¶Àâ·ïšmS{i¹”ÏÅ]s&}°jt(6h¥*gîq¶À\“–”›×c»‚lßvc¿Ÿ*U9¤VõõÖ9A+U9©2]€)Þ\¼þRUUuu~ª5èuÿøâñ| .n<7χ¯?»† p@Àä‹/öáâF#¸ätu~ZUçîÊpÉêþñE#À‘:<|ÌMÀ¥$>‡ ÇÉå¢e¸i \pÊ1馩¾§ò¬ýè=–÷îÝÙfŸ¦³ÖÓ‡7XûY·í~ƒmŠ »ÅÀ·dM à8XRØáD™d¸!º²ßök]KÓ]Ùò”ídÝåe€í×Úoü¡L®¹íÔL/d éÚ¦ëÆêY÷Mœ;°¿¾>UïÞ}3CªÃ–”`Šþ%àAF[î›xí™rê$ÕñÈ (}r, ¸²×¼q‡²N™€ÁŒ²'Çúçò²^ÃýøPÌv]oýºlxÛÁ¼kPhÞì±ä`Ѯ϶±I `»ã wèîâæu]ïöfÓ!Á¡½m{0û}ªúômÓµ¿¡:…”“j_05è²±€ôÆn–J±Ax½7lèkSƒDH©ê¼ä¾€mȶ¤lY¸¡€=Èz 7ÕR1Èp€u3\ŽË‡‹ à’ÓÕùiU¿×YR\@À\@ÀøÞ7_|qóóoZøñ/?öÜö/€é>zÿ5™ý&à^ŸjÈÀ5\p@À\p@À\p\p€uîÙåÝàkc¿ŸºÏæ¿”eåj¿÷ûÆ—®ß÷ K}õι?Êq2çD>=Ü~÷úÓÃíד<ôû®ßMÙçÔ²¶<èìéxs´ÏÞÛpËÇ?ôþßÂøÐ‘á&½-1›|Ðgÿ”lOàcîPvÛìÈ}oì9Ynì«kÆÛ7øÔu ýû®ã*?ä÷!Ç5õøBÏk_ù±í³ôßÇ´O_»ä>sެÿuõŘãOQ¿Ø ·dðo¶W×±.qþæ¶Olÿành0^c9glÐ[rú9fÛÐöˆi£±‰JŠ%µ¡cê›`Äßœ¿ÛÈDnh]ãüÅ”?6¹‹©CŽúMÉ®§ôÏ9mÎd?wû„ü}îþÁÆîPç(a¹l¬έóPù]×·K›…NÀ–¥õ¸s;ýZo˜¡%¶)xhY}ì :¶´¹–Üç&$-y‘ûüÍÉöJœ¥|ÿ¥rö±¥ß;ê¶lþs¸s:\ìßÖ¾þ»v°N1Mý†«ëTÿËPbÊ_»}rŸ¿˜ýç>7¥¿ÿ¶˜½å¬ãXÙ‚ñ‘d¸sf™sg¦s®áte¨s—hÚKès~?7ËNQþœYzèþÇn¦ËÕ>]Áséó7·ýb®OwÝT5tü¥¿ÿÆÆ Üçgnû¤î±?³¾7ׯ¿TUU]Ÿj‰K:Çr7àÚËÉhS8F7?ÿ6/ÃÝ£µgÐÈp€ ×à `.¸ à.¸ à.¸€€ .¸€€ .¸@nQ ¿|Ñb ðlbXqn|,ÒFÓÆë·:aYχ¯+ÛÒÆ"m4}¼>‰ÝÁßûo­œóþp¦`eƹñ±HÅ×®áÀ\p@À¤.ðòÿï»×þúC’òæ”Sç\û+ëß½¶•ã+¹ÎKÕ5[†ûð×¾Vº«cÅ4ÂÜrbêR§\õölë±'dŒÛb°M–Š ¸í™‚ 0?€m±®K´Ò¬}RBÓø¾ß-µ,ÓÞO_©—ÔÁöÇ‘˜±{èÒbȘ[ʸ|RJª—jc¡«a§”›©w•Ÿò¸ŽyÒ:v7_ko2æ–4.{—rsF²ååhK)@ŽlÐdc{cîI©¨¹Œ0Ôx%uĺÎîzrŒ+Ç4–,=v—+NÖîH)°kÝ¿”c²¤ ºëÝ%´ÛÛ5¶o»­-›´ëì#C@î€QúÓUÏ%ÇÆ}­5VŸä<è¾™Eª¥×¾rb· ½¹«¼ö­ï–”©c×±Œ]Ç2VæhÇmbb@Q7´‚!Û-µÍÜ;£W õXÙ7á?æã›rükÄ€©|—2¸ à.”#ꦩÃó¡:üp¦Õ€£eœÓF«g¸Wç§Zk!Ÿ?½×°ãÜøX¤¦×o®?^шÇÍÏ¿Åe¸Àt.¸ à.¸ àiTÕïßró¬1 —7UU}ùûü]K@&¿þû×êÿö)Ö@ÓO¯IEND®B`‚stella-3.9.3/docs/graphics/rom_browser.png0000644000175000001440000001153112162610274020177 0ustar stephenusers‰PNG  IHDR€à5ÑÜäsBIT|dˆ pHYsaa¨?§iûIDATxœíÝ?Gzàâ0\Àø!ž‚a€¡ Í…>€E'7™ ˆ n %6˜I‰uΜx©² PºB€NÖn¤ÖðíéêÙþûÖó mÏôôÔt/{^UýºúÁ»·¯ï¾þæ‡@~/®—‡Ãání†0¿ÛÛÛRJ)¼¸z¼Zc˜ßËŸê¿ò›u›ÀÒ€Q4FÐ @c¯,áéõͽ{ûú^Ûûú5DŸ»”Û>´ŽÏ=vŸ6öµiû K l@·8þt¯Õ}íRž^ߌngäÜg³ŽMѦ½™êXùé„Ò«t¹¥Š ÇØ+ ìÈÃĵ۩r=]^»(z÷öuyz}óó/1ôºš¡öîþè®?v?׬3æXÔ´å\›Ç µŸ{/`]†€aºCšÝŸ®©†‰k¶S³ÎépóÃÏ}îÓŽ¾Ï~ºý¡÷8Ýg—îç)Ź¶Ô¶ÈA lDÔ{rìÉÚ‚¹Û±Ç Xj?ËTŸé>½¾Ý¶œûëkóéëÎõ6f:†vfªÞ˜­õê ™míXù)agÖìEšÛP¯TV-}V`da.¾cªi?j¶3Õ:CZÏÍu,N÷ë}z[û²‚}mhõX–=8w¥”òâêñÚm¦Íq5è¥Û©]'Z÷ÒÉ«k¯4íkÏ”AíDZûùÜû/},jŸÚg5ÇÜUÀ°=/ß|[JQpVóš°wÇÐ0Õ çB @ªµ|µ6dâ*`FQøÁþéhŒ 1 @€Æ(£hŒ 1 @€Æ(£hŒ 1£n×½ øñV@5÷„tßH€í¨î<-âºÅà˜×°®‹†€Çôþ°-ÕCÀ§E^Mѧ@ØžÙ.Qül“«€3K¨÷`»&/Ûf 1“€zÿ¶oÔ@†(ü¶Ï0@c€Q4FÐ @c€Q4FИªðîú¦Üýý.–-[¶lÙ²eË–·¿|΃ÃápWJ)/®÷®tw}Sþt8Tm€u|òå—åÁ™;³½|óm)¥òVpÞ¾.å›ÊÿýÓŸ&iýþáoŸ”Ï?ÿã¨×¼zõÕÙâ¯K 1Õ@¶­¶fÓИQÀ±þó_ÿ÷ƒÇþí¿þqôv.y¯¹Þ`-¯^}UJ)½ùÀÚ `Ux_KcÇ÷ˆŠN~!°ÇÞ¿Óß»dU€µãÉL/êñ‹3 !@€ ëËûEÏÉšu@îgÌ=75àîÜ}}sÖ¬À0@€$jk¶Ez‡zïjzô†Öq€:³f—ª5, drîêß>»Êð‹ÛÛÛò—¿üǨ×<þY)WϪ֕HÂ<€„Feÿý_þ6w{š÷üëÏ.z{’HB€Ð¬ó>zôѽÿýèí´ìtÚ@ŸM͸¥¢¥[Põµë¸Î¥í¾´h‹Þ÷ø{TL\¢© ài5WQõþý÷›*z€6lê^À{£x2›5X£¯®[„ e »={5C¼}ÏÕÝN•m4¬ Lióv ·(÷Ö]îþt_Û]ÿ¾C¼5C·§m¾ô½ú¶0·tÀc!uZTu 4=o@F©2€SlÝáá)zÛ‘À^­š<eçr{QѶ…âË-°5›š°Ï”=rkÊò9€6T€w×7¥“¿yÔx||h9œ¾GßÄÌCm¾Ïv.uw}SÕ ¸H`ßoßðî£G½*82Å:µ=xKm§”m w¹Ìš4$zö!PkÀšáT¦µú<€§“<+þ.S[³­z'–WUÖŽ'°ž]Ü €å­ž`2€„f0šÄxÍ«|M7d¶©y·RhÛáî@Ëd’ 4k°ÆPNðøüñ¶qÑ:5ÛÈnóv‹»îmà¢B¯»îé:5Ûà'›Ëž»ðññš{»¯0Кښm‘«€û‡uMϰœÕïܶ5t p¹Ýdç*öæÜ6Àž­šìöøu ¶±CÀSm`Ï6•<7}KM‘6Õ:zfžpk=p[kÀ”v‘`y››€Ë¸0¡Õç`2€„d’ 4ë<€ÑÄËæâûÅéþ±o€û¨Í.r'½6KßB®{ ;€¥ì&ؽÇ/’ 4k°ÆPNðôù¾aÚ±Û‰¶Ñ·î¥ïõþý÷¿Zw/CáÀ>íbÀn¡tüé>Þ}®o¹v;Ñëû†”ÏmgÌ{=zôQÕû,isÀ¨À›ë}J™·(Óã,©¶f[ä*à>Ç!Ò©¦CY²‡Mo°W«g£áÜãÐé}·5'½{ÀÖì&xIOZÍë†Ö™rÎ?SÔ{²j°›ÃëQQQvšÙ;½0¤v;CÏOÙf€%m*xn*”1…Ó¹uk·3vµ]ò½†ÀfÍê;Ïþ¦´‹ ËÛÜ<€sYj~A€µ¸0¡ª°v<€õÈj& !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $„ !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $„ !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $„ !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $„ !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $„ !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $„ !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $„ !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $„ !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $„ !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $„ !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $„ !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $„ !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $„ !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $„ !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $„ !@€$dÉ$!@H @B2€IÈ’HB€ @2€„d’ $DmÍöpæv0Ò“'OÊ«W_~Mùë_«Ö­*¼}]Ê7?Œj—ûüó?ŽZÿÕ«¯dˆÉ$a@B2€6t1H7+(@H`ÃÎ] |úœ !÷ظ¨0zL€ Àt{üúr2€„̰C÷– $„ ¡QÀçÏ?›»=Í{òäÉà=€#µÀªðîú¦|ÒÙè±{ѲeË–-[¶lÙòv–ï¾üeùœ‡Ãá®”R^\=\€ýzùæÛRŠ @s®Ý€µ}m~C ÛÛÛòŧϪÖm¾,exRE€­s±®!`€Æ(£h̽ À§×7åéßç 9÷Û¡ 1“€züöc²i`ž^ß”w=·‰ ÄãºçŠÇÓíÛNßz}mhÕ$=€CÅÜ»·¯õ­Û-Ô¢uŽ¿m€ó&ë|÷öõfŠ1½~ý&½H_8ea¸•"`¯f¿\wèöô±KèݸŸ]ß 8*.»GÏ´nöð8,\Óëw®XëÛŽ`œ{€QñUûØÐsc·sÉz-r'€Æ(£hŒ 1 @€ÆìzÀ©<þÙÚMXLóà‹«Ç¥\=[»‹1 Ð @c€Q4FÐ @c€Q4FÐ @cFÝ îëo~˜«t¼¸zÜûœc°ŒsÇØçÎeô;íÿeŒùîªîtð–q{{[^¾ù6|Î1Xƹcìsç2úÎöÿ2Æ~wê,¥”þŸÿûF¸ýíï×q æUs €ýqîœ×йÓþŸ×Øï.@€Æ(£hŒ 1£/™ÛÇßýøóïþÃïVlÉ~u÷a×–÷gÔæ¾ö×Ýòçr;=guÏGÎQó;·ÿ·f«mÝTàé?š¾B†:þÃï~þ)eûsoíÚÓý®r¾ZÞÞö·[²™ð´øÛÃAe>çŽÿVÿ1ùE½{ÎI˱ÿ§³¹!஡!ÀsëœýÕô>fû«ùŒS­3…šnôîq'Ö4æœÕ÷|Í:[:OoÅÐç­ý®È¼o7ÓXkéaâ½t1G>þîÇŸJùð²;D}ÆÓnöK×™JÍÿå¾ÿ^°CçÅšóÔÐ:[;OoÅÐ÷ÛÑÇßý¸›ïÀ©m¶<-^Ž•²Î0ñžêÑ{êjïþì¥Í@j¾Ï.ýÎsΫ7v?eÚ·›>í–ez5'‘Ó"üøøØm0=çéØÒŸuûv³ ó:—ƒìвÇ.ósë° çé_«ý~›Ò÷íf†€O»¶û®ôZg.-Îëý_圯;ÝF)mío`ûú†jÇžó¦úÎ[ó<½†©öÿ¥jÞk/ûvS=€§]ÙÑ—Í:cßçœ=_IznH fÔ -Œ~Ûæ¡+­‰À¢óÞßE—|ç­qž^ÛÐþó?ö}jßë\ïãV¾»6U–R·C¦ØiµÛXû]bÊ϶¥ã‘ù˜ûrî<ÓWÈÝNí:K§·ä¾û¤ö-u|Ö°™!`–¡hÌæ†€·b«]¶÷¥ 1£zoooËío?W[¨àŒçܹ.û{ª{_\=ž³t|ñé³ðqÇ`9}ÇØçÎåDçNû9c¾»‡»R €ì^¾ù¶”"Ð @c€Q4FÐ @c€yXÊO3t¿¼]»),á7&€hÇŸ>+ÿøF<îø›èIEND®B`‚stella-3.9.3/docs/graphics/debugger_dataops.png0000644000175000001440000000142012205116016021123 0ustar stephenusers‰PNG  IHDR^eK ÃWsBITÛáOà pHYsaa¨?§i³IDATxœíœ=NÃ0†]ÄÈR‰ƒ°tc‰„ÄzNÀÈ‘ØYY*f&TC õ –¢âæuüóù³½ÏšÏ<ØNê·éêûýÑ1Îj7 ]¨B5ªP äÜøõãW¡w·— Ubñõ/}ß?<)Še¢×cn~ÞŠ¶ ¿¸*zþd8×@¦{M8ÛýÁnì6kÁÓÖBLÍvŒoÏ™叨mÖCš/œk T¡Õ@¨"£Æ¹$-ãâ-v_slg^ŒìÝð2Œ p®Lôš¾ï›}g\_¯Q[azº¿Ö)ÅŠ9‚s „j T¡Õ@šÎ¡êVo7‡ªž‚µžCU¬Î¹÷ÎÛÉ 4ßjŸ®•^ŠSc›²Œ•ªIæ4 ”³-™¥,ÛŽ›îI2“;-1úZÏHwZ^½H°{ú££›gON«Ä*)¾¢®–K® «qj§„, 5Ã(ehjKûµQfÙkÂÉùg$ÞòÙðª²]fôäΞÉC“¤Üò…ìÙ“YÚùDÏè«rnæt˧LÓ9T~õ—®ûü? º®3açœ[t>Ñ‹r¨ºÕ™CA8×@¨B5ªP „9s¨Èê†9s¨¨B5\5žEÙ¹?Å^¡Hâ²¹-Ù!C‡¤ª§ÕC±$ªñä¶ §zN+X‘ B5\5:}» ì5ª,<‡Ê¡Ý硪?Å ¹B5ªP „j Ì¡˜CEV7Ì¡˜C¥ ö k ‡¯( Æ³Ð©ùYáCQäPú^,¥íd©©èÅRÔNºšê^,åìð IW£0†P®ófõšêvŠj°¥–Ò“À\SÅŽÂE@ìÛ5^‘W(s(s(æPñp®P „j Tùù³䌦6IEND®B`‚stella-3.9.3/docs/graphics/pacman.png0000644000175000001440000000614011433323254017075 0ustar stephenusers‰PNG  IHDR^æÅí¶gAMA± üasRGB®Îé pHYs  ÒÝ~ütIMEÒ%ýE© âIDATxÚíÝ;oÙàOäp¨»7ùA²åViý/Rl‘TAéŒMµX¤ °]ŠER&…¤K•r«ûR¤H›j%YZÛ/iöL†cR”HQs{€ Í‹É93~ýéã½o>ÿt°#ú×ß¶zý¯?ù¹Adg~öÅ?coo/"báº|Yuß62CôÕÝÝÝÒ`ÝÛÛ‹Á`P\Wm¾‚è­÷ïß¶)p‡ÃáÂu5ˆ· _Á ôÖ»wï""ŠÀM—ápÃá0ƒAÌçóâz8Æl6Û:|×ï¶=:êµ®GÚôý»ëÏ×öña»ý{}}ýQèfYV\†ÃaÌçóȲÿGåS„¯Šè­ëëë¢.Y–Åh4*.óùâüƒôüù|¾»Š «...Š–B9pó<<Ïc:.oêñ¦Š7=öؼ@o]^^Un Þñx“É$f³YQÕ–¿\K!›‚W«à¾ûî»B÷îîn!x«=àÙlV´"b£ð¼@o]]]Åp8,Ú åÐMUm¹÷;N‹/×R¯w“ð¼@¯[ ÕÃt:-B·\ F£È²,f³Ù¬†Z*Þm§ãx}³§3ízûÖ1~^¿ËýûöíÛȲ,ò<_¨t˳ÒcéñôœMCWÅ ôÚÍÍMŒF£¥¡›ZåöCêû¦ëMí­û%9&·›Œý»ÚÿóÓbêØÁÁAÅññqœœœÄÙÙYœÅééiœžžÆÉÉIÆÁÁAñš4-V¬âXãöö¶¨\³,‹ÛÛÛ¢ÂMýÞTé–+ÞtÙ´å xÞïÞÞ^ÑÓM¡»,|SÈnKð½5™Lb0Ät:]¸T+ÛòœÝe·k`è¾Z¸åÛ«øÙ+Þ¯¾þìÞÇ_¿zco;ñÔùSž¡°ªº}êÐUñ½VÝU_ž=eàn\ñ>Ö®×ÌÚõš^u¯ÖôéLu¯‰Öõñéúñ]÷þ]UÕî"lU¼5¼‚ ÛvÞãíû)—uoÿ®ß¿íû×øô{ûV…V¾®>wÙc*^€®U¼æéuéJþ¨x/€à@ð´Wï×\ëûö7}ü¯ã»ÎíWñtDï×\³æŽïþnÿ—ßžEžç±¿¿‡‡‡q||§§§q~~çççñâÅ‹âöÉÉIÇÑÑQŒÇãÈó<²,+Ö]K˽«x´¼‚@ð xÚkí m_3­nMÿ|mÿ®?uŸ Ñ÷ñWñ^/@ ¬íñ6ý”BŸï~MïÑ75åÚýùšÚCVñ^Á €à¼^€fêýškÖ”ªwÿ®cü¼¾ÉûWŠн_s­ë¬)g|ìßÕ¬¹Ð‚@ð^/€àà²]¿AÛ×l«{M©¦OgjûškMŸ®ßmß¿*^Á €àh€÷xû~ÊeÝÛßÔ÷ÿêëÏî}ÝëWo"¢ý=DkÒ¡âèCÅ ©t«Ïû÷Œ*^T¼´©ÒM½ÛU•oõñÿ&û¡òDT¼^Zäõ«7Eu»ÉãÐf½_s­ïÛßõìÿ¾;¼ðëf5öÏ xØØÞ7Ÿ:¯ót}ͧº×$ëúöÙ?þ}lãËoÏ"ÏóØßßÃÃÃ8>>ŽÓÓÓ8??óóóxñâEqûää$Žãèè(ÆãqäyY–Åp8ŒÁ`ƒÁÃëX/€V€àà ­=e¸é§ìù|÷kûšeŽ/ÿ>š|ü«xZBð^Á €à¼A¾ëº¾Š°ña›ýë—äô„༂Á xx l×oÐö5Ÿê^SªéÓ™Ú¾æZÓǧëÇwÛ÷¯Š@ð x`ç=Þ¾ŸrY÷öïúý­IÖïãß)Õ*^Á €à¼‚Á Ð%½_s­ïÛßôñ7¾Žï:·_Šн_sÍš[8¾û»ýÖ\è Á x/‚@ðð@kO hûšiukúçkûøwýø©û‰¾¿Š@ð xZ`m·é§ú|÷kz¾é¬)×îÏ×Ôrð þü‹/–ÞÿË¿üÎàÐ;Z *^º\é¦ 7ÝŸ®U¾¨xPñÒîJ÷¡÷«|QñмŠ×šXÝ^SjÓÏ·®r]UùV߯¯ãçõíØ¿*^€–èýšk]WWŰª¢]ç¹{¼ÖÜë÷ñoÍ5€ž0«¨Î×mZ¥ uRñ¨xéSå«ÒEð>ÀW_vïã¯_½1ªÀNt%T¼wÙc‚@Å €àˆÅVÃS¶/Àª ŠÀ  Þe ^ ×o5lË»ì~Á °…áp¸p  ·W…ò¶²›››¸½½>Ä»wïâúú:Þ¾}———qyyqqqWWWquu777ñý÷ßLJâîî.&“IL§Ó˜Ïç1›Íb>Ÿ/¼AõÏÏ]Õ.«p‡ÃadYöQø¦Ð½¯ ®Þ~tðV?\Jùêɲ,F£QŒF£Èó¼Ô´)t/ÐäàM•î`0ˆ,Ë"Ïó"ÛÊAœeYñç§n5dåD_ºå–çyÜÝÝÅt:-6"˲˜ÍfÅ}‚hzð–s.Ïóâ2‹¼K¡{_ûaÙ{<¸â­oz£¶yžÇþþ~L&“˜ÍfEàŽF£…VƒŠhzð¦Kù'ù”qé²*€«¡»i%œ•{é/®¶R親6='Ý'x6où§úýýý888(·ڂ(oºÞ¸Õn”C7ïx<^ø­ºåûg³YÌf3­ ­†jð¦¼;88Xßñx\o9|7m1|Tñ¦öB¹ôžL&E{!"ŠÇS §j·<›AðmÞrï¶Ún8<<|PËaÓð̓AÌçó‚w<¡Z®tG£QQíN&“…idËBVðM Þr»!…gõ§ü¾1‹ª·úÛ6•oVýb-}€Ô>H¥ûS¿wÙü]! ´!ˆ—Íç-‡o àrÅ;w›“*²r¿#…çh4*B´Èi:Yj?T¿T¼@[‚·ü%Û²IåKªxËí†MÛ EÅ[n7dY¶ðËSËʳT»@—ªÞe'‹•/é˵e¿ßa£àM¡[ Ïê\·Té–/qoð d î]¼åŸê«3»Ru[¾]m5lª¨xg³Y ‡Ã>Xùdž®àš¼ë·üEZyY:}xÙÙkÞôÆ)|Ëñ|>_h+”[ «¦´%—ýÚ„Tt–¯—µ6~ïù©™‚4U²åª¶zû1=]¡ 4±â]Vý¦6B¹¥P½ý¿0§ÞrøV«ÙUîCBUðMÞê‰ù¥è[¦y%«[ ÏǶ/Ð†Š·úÜU¿ƒ÷I>Óüžd¼/xJðMÞeÏÝåšk÷ïS¨àÚ¼Û¼f'Á ÀÓ°Ø%€à¼^Á €à¼^Á xxZÿô5qíï’qyIEND®B`‚stella-3.9.3/docs/graphics/launcher_options_files.png0000644000175000001440000001222612162610274022377 0ustar stephenusers‰PNG  IHDRâ8kZbKGDÿÿÿ ½§“ pHYsaa¨?§itIMEÝ,=Ç|tEXtCommentCreated with GIMPWþIDATxÚíݽnÜF»àQ 2Å Ð…D…;•¶]ÃW êÛ.P¥&¥‹¸4Þm!µ{7 –aÀ{:EDfø3$‡Ë¿ç X»£áÌhÁ÷ápyñÿþüéó·lÃÝþ:\ÇgCÛeY!„Ëb6¬Ûÿñ?üd(`{$ $Àö€ç·ïÃóÛ÷~öó, ¿×Û«îx~û>\üý{ð=ÌÁÝþúõ3 @?¿„ ·Vf‚?3‘eYxÈBøü}n­ž+?üvUö2¶Ò_ÿùËÈ2݇úç_:ÿÎüÏÀ›r8ÜG—mÝsâ3 †»@ð#›­˜ŸI+@O›Ÿß¾áx\DGÞ}ý^ùú㛫Õÿó¾o¡¯}nÜín^ÿ:=ýðZþsÓï5•9§)ÛSú6Ä”YbßÁ ÀB<¾¹zý×”,1ȯ¥/SÍrÚJðßín¢û^åtzj=vLÁ’¸ÞÊÜ ùLv™ý¬Ýå;]œI—Í›fØ]—׫ꪪ£­\ùý¦åþrÙ¶2[¸dPò1A¿)A¨šEË·êÒCl=©ÛÓVW—ö¤šÑí;0â Àï¹.ж<ôRBÛåˆâ%‹ªrÅ׫~®«kH›çlìÏdL°Í—º«.+Ô­2ËÄÔ“²=Åß­Z¦ïÒžTIÙоV:Í‚ËÁÿñÍÕëµõ±gÃçe{Æšñ÷9ŽÙ?XXôl;6øÇîC`ü ³Ó½ü{»ÝMò@5E{Îl«ú»OHkµ{ê®§_;çJAÊc ¹%0ÿÝ¥&S~&‡ÞJ—ºî¾í‰ù½1û X˜|u ) §J švÝ—Û’¢ÝŒ;ÛN±äÞVÏí)—-o l«'f–S¦îXfÿp~Çãñ9„îöוòçª{ðt3~BøóåqÀ±Ï¹þôù›Ç›s8Ü·ž'>~ !xlÒæ¾€eó™HãÒŒÃÒ?‹]ð,æÆgàŒ+Y–…ìe,Åápoú$Ïo߇»¿™bz~» ÏoßG­Üí¯CØß4€¾+Ïo߇/'Ü|Ö…Ÿý<áÏ ×ú=Àzøذ¨M€ŸöD@ÖÉ*ÀÁŸ9Ȳ,…¯Ø¯ºö7õ¯i\a·»yýÿéôôÃkùÏM¿×Tf.ýªkgL™¡ÇŸb|¦îûÒÆ ½P €y€+¾)Ú4´ åÀÞ§¾â˜Ð|Ò-…)OÖ»ÝMt{ªœNO­í‹)3E0[rßÏõ¹2>°š€ªÙïÖž?ÜéôôÉÕL ¬HÛrxÕ »k™òû©.?Œ½¼Ó÷r¹¥'å ôSÌn›ÚQ~¿îxmõŒ1£9VÓø¬½ï)êiº4;> h ¢ù}yy½©L]BP,ÓTßXýI}©¡®ï[—*ø—Oê»ÝÍëk1ûbê3Qª;ÖÐ6/¹ïCÿîu¿ëø€`e«s Ä‚qŒ¾ë;Hfxû¼Ÿ2Оûî…©7N®yöŸÿnÕ®”—ÆìûñYsßA°MÁ¶n©| }üÓÌÚR,)ŸsY·|Ýg|ÖØwL´b®ç™Ï¥ž)VBš6AJšgŒ]®‘M@–ò½kí{Óß}Ì6ÛÀæWŠI@ßàTUG¹žº21õ,cî8ˆ)Ów³ÿ4³ÿØeð¦Ûcꉙ¥Ç”©;VŸÙÿÚú>Æß½O}‚?c¸8Ï!„p·¿®,?WÝ〙ҟ/Ž}Îõ§Ïß<ØœÃá¾õ<ùðñKÁ³`“$ $À*EÝeYÈ^6aÁR÷ op·¿™bz±wäŸÛ°¿5hCVºœx€ù³$ÀD]È¿ ¦T÷m•ŒþÌA–eá!ëöUÀ[kïûÐ:ÎÙ/X\PL«‚뻯ß;Ÿº`^¬§¼QUL™˜cÍmÕäœmž«TÁ¿ôv»›××bV"bê3Qª;ÖÐ6/¹ï]ꪫ#å±`5 ÀRf”SŽËœ±¿Qÿ£ïÛè·àŽ Q@I¹'àœû †ëñÍUãJÃÛ¼ÕÙùÄŸ"Ù(—ú8mã³æ¾/ñX°˜ & 5]‡Ÿëìu‰3ew ¤õ¦XR>wßc¯Õo¡ïK<¬&8wr1e™¥ŒÏ–/ÙT}¯ÀÐDbMßK°Ö¾7ýÝ—ö·‚Å$ù2xÓ¬?fg~]=uýŠe»–ér¬TAºËŠÉÔm^óì?v¼\¶X&¦ž˜YzL™ºcõ™ý¯­ï)“„˜cõ]y>.ŽÇãs!Üí¯+ äÏU÷8`¦ôçËã€cŸsýéó7f‘I$ q8Ü·ž'>~ !xl’6èÒ cé+ÀzV², ÙË&,XŠÃáÞ ôMîö×á!3PL/ö€üsö· `È @—/0ö€Ø‚¨Kù·”꾭€ÁŸ9Ȳ,ó8`™D‡Ã}ëyòáã—‚gÀ&I`ƒy€¥`N,ýcXÏ @–e!{Ù„Kq8Ü€¾ ÀÝþ:«uu¤hs]âзÍk•*ø—ƒÕnwóúZÌ>„˜zÆL”êŽ5´Í±{0ÚÚ“z $3Oš‚à)û%!7¸ê; ˜@ÊMrçÚpgcß2fÿùïVmLKy9a̾Ÿ”}ccߘw,$ø7]?ŸÛL9u›?Ä.§Ïe]·TÞg|Rô=¦=©ÆPðG°ÀÀ=æïõ©'űRÞ«?¤®5m{¶œêZòš¾—`Œ¾oe AP1ÓnÛXW¶¼Q0ö^ù>õô –M7U›9ßì?v¼é¶Ä˜zbfé1eêŽÕgö?fßcŽÙe %H¢K0‹Ý®z†ö-E›ë’¥±û¶]@×eð¾eS'¶-CÚ1EßSÔ#ð³už` . Át\£À 0¯€,ËBöó/F‹E9î @ßàn2Åô>üv]önÂþÖ  YèrâæÏ[u àÓçoFŠÉÝí¯ À¹ÁŸ9Ȳ,&èMªfõźÊïׯ­ž1f¾1ÇjkïéôTyÙ¥îwëVišêiksÓÊJ×~€h»–ŸzVs¼²írDñ’EU¹âëU?×Õec¼àŸ/½W¤ò²|Õ2}L=©¥˜cÅîÒæº•šªý mm.ó~€$CƒVÌ,xŠàX^Ř:ÑbœUˆ-÷7ŸÕçIB[àÍ_˜AИhS ‹½D"ÙH¹"Á¼gÿå—" kÆßç8s›%§³$S7Û.'SÏÊ›n9d^Á¿.Øg¼s\=hº.?Öø“¤>uÆ´Yð‡f›þ" ¹]O¹qqÈ-ùïJ4êƒFÝ-|}oí‹ù½¡· ¬z ¸3)švÝ—/kÄ®j¤J$Ìþ‡Ín›fòM3á˜zbfé1eêŽ5æ,9?fß:ÛÚ³ŠböÏÖ]ÇçB¸Û_WÈŸ«îqÀóžñ¯ÝŸ/Ž}Îõ§Ïß<ØœÃá¾õ<ùðñKÁ³`“$°A—†`:–þ°Ìk ˲½l‚¥8î @ßàn2ÅôbïÈ?·akІ¬t9ñógH $€@H $€@H@H $€˜³Ë.…?}þfÄÎànmçÝÈs£1ê?~ò!œ—,ËÂÃÇ/pÞ87£þñã²ë~ýç/£<æðç_ à¼ÛñÜhŒºÇ{`ƒ$ $À*]¦®ðÝ×ïÿyíñÍU’ú†ÔÓ¥Íc`®ÚÎÝùûm¯-¥snó¹Ú:Ú À㛫×FW}°º ÂÐzº´5¦Mcµ`Ê€“Ÿ cιK þ)âÒ9t‰I³LÊ™‹  °¾„a‰m=W€»Ë©ÿ(UÉBS"ѵžTËVåãÔÕ‘ú€à?}L*ö»éÒtL ˜Kœ¸œË(_Zï:UÛ§ž®+Uõ§ìÀ\­ñ|KН•ËÄÄ€9ʼnÙÞPÌ–|ùÀR°ÖUÉϲcÀå\?DÅe–¦Á›Ó1o³» €5À5®lž;–Ì!v]NýAJ1€U×iæÒ'—IÀ2‚ÿ9cÉÆí§)¶®ÜÒ–•Êmv‹ °¥$`.3Ù®í<ç¹:æXSÅŽË1;]—é¤Z*¯«§k™ØþUõ•o-q XòŒ~箪þÅœ»Çǘ2]bÒ¬€ØÆ”;W™¡wöÀZfô]Þ_Òùnhˆíÿ1©/Ï€ ’€«Ôi`–e!ûù£p&λÆhò€»ýµÑ:“¿ÝÀy7âÜhŒúÇ‹ãñøl`>~鶬‡$€@,Åeÿ~‹ÒCf0`3+¾¶åÃo·áÿଦÿ ?æIEND®B`‚stella-3.9.3/docs/graphics/eventmapping.png0000644000175000001440000001626511676164714020361 0ustar stephenusers‰PNG  IHDRÌ^u/ÎsRGB®ÎébKGDÿÿÿ ½§“ pHYsttÞfxtIMEÛ 0;;ÈÍtEXtCommentCreated with GIMPWIDATxÚíÝ!wÜHº`̓5‹F¨Y 7,†}¡Ùâ0Ãh¸a;Ð0ËLõ3&,ËrÁ\yeE%•¤’T¥~žsrδ[-©Õ=õöW%©~«ªêçétª€~Ÿ?®~;N? èW×uUUUuÑüáöæ•£wåeõ»Cã.†ž|xüîEpt¿ KRð}κÂT907,ï>ÿÛ!ÊýéïI¾;»U˜0—¹ßßrnk.rŽòëã4x¾;äøÃ\… ÒXµKöúçàsOÿüǪÛJ½þ½Þg˜[†H³¡0+ñ}Í òs í¾÷ßý[èû1õ˜ùÑ´ígºåñ-éÿ£öñY²¿{g ™ëçÒFÁ¦í?·ëŸ4æÏ:ÕqÙò8—ø]½Èákˆb*‡«˜_vÝÿ)†–;6~Er„à\»1÷ÿÄ6ÇY…9³Û %}PK»CBÚ÷ÞÛë.S5MÙ~4•z¬—üèŽ="æ¦Z¦´vïèßÕMÎ’}úç?žÿíWXè}uÿ'\Z¯qìŽø™ìÑx4ÿ–†jûóè[_óã¦o™îgÙ÷ÙNÙV©?L–¼¯˜ÿb¶•j™Ø6aÞ¶±û‘1´\ÉßUc˜™þ:^³‹E÷SÚãÛ­•ë¦sùœR~kÃTëYòÞb«Ç¾cz?¹YÀÿ¤CøV_„¾ÿtÉúÑt”Ï?·Jy쥟Eß0ÖÒÏ4—ïB®ßÕ³ ÌT§b¯¹oK÷+Ô%"ýh:ꦱ÷ûYl¹?©>‹ÔUsŽŸgßÕÍOú ŒØ®­Ømlñå‰}_C])E 5çÐ%»f·›Me›-ßk̶Öþ,ºã£ku߯õÿW)ßÕßN§ÓϪúu¯fÊ&Ó{1¦û]inŠ¼× ´cÆa–VxSo\0Ôˆ¥8ÃsÉûß³Qê~Wºc÷wÊû }±ßœÎ’íû¬ç„͔׌õÐ¥ZרñÙ²i¶%09\`RޱÀ„ØïÎÛróuˆ 0@`@/Æ0Û3X¿~ýºjþCš1̺® àPîOož³ñÅe%MH6„%1no^Ußùþ”®]H^HR…&À‘4½g c˜A`€À€µóç¿þyì±Ç{¼ßãÂç+=’à­ñªŸª‡ÓÉØÑíçÏUe–¡]<<~q¹\x¶’þ£ª¿W÷÷·ŽÀBww“ÛÓ»»a™c˜°(0õ›ìO[¬Â€’ŒŽa°ž?ÞÞTUUUÿön‹{ÌŸªªuYIt퀻¼¼®./¯'…^³l_ø®¥oßr©.›ÿî­2?| V™7ß¾8ˆsój^þ\,Ù¨à\$ÃLÑm»ž±eºÏ«4«ËÁ*Óu˜fO5]°cµ´Û6f=1Ë - SLºóǧÿBUÞ^ÚûPRu|Îu˜åU˜S¤ ÑœÂà\½ú³ªªªúz}5ø·ó Ì×a¦ªòT‹À¯¹ µÅç×ë«ç°<7Ñwúé¿\óusÖ“j†«Ís}fÌI?SN ê>žºž˜eB˪\b \‡¹µ¦º U™}ëëÆ =_n`öˆ š±ebÃ*Ŷæ. @84cŸ{ÿôçsÀö-z¾¼Àt/Y€¤îèÀ×a6•j)¡yá+ @ GߌÃ`™©÷~}|û1«1̘°³,™ù0È&dˬ0aì¯1ÌöxdlP––à P‹ý[ìúJ0é^²lL[\@`ÏŒaäì@×a–~£öè1ÌÐýWÝA€ó®0×a.:5÷‡-pf]×U}e"‰-Ã(ÌíÍ+a¡ûÓ›„æÌ1̾®Ûnõ—b™˜YOr;æooþÛ'jðY&éu˜}¡Õí¶MµÌв¹zB˜1̘ù'§v€ 3¬…ÜKV…·±ª.tFmûõ1Á;´&yæÀf;ôú‚nê$Ò¡u©<³¯0U—åV˜±¡Ù­—Ž9ƼÎx& ÂdûÀœ1fLwkªeBË KàPc˜îĶȜKs¢+ÌØ®×˜ÀJµÌœeJ',—©ëºº«§_šã^²9üùöÅñ™˜3ïäN?°(0ÍÁ°?mq <ÃüŸ¯o%€…þVÝÎ{¡ë0 LéñíÇs>y(§}5† ³Ämq@7ß¾<‡O7”rÒÞO&À™Vv{m¿@.MI˜®ÃH¦®ëê_ÿºŸôšwïîvÃì öv°¶ƒ·½l7|ÇÖ»Lþððñ?/ß~ùÛ¦¯O­»?}ûÕ,3ö7€#è µÇ·{ÿÞîÖí>î Ú©ËädÒf;$š NHûµ9èîOnûœ¹ŒÏ'™j9G®ZaöUT‚àx¶kÍù¤£¸À\0†Ù®:—„êÐzÚžj{CUèÃÇÿTÿób{~0«Ûx 3ÔMšS¥º—äwúé†ÉÔ.ÛØõtÿ¾t{G×wI3f¸UmkËýI˜3úÍ»á57Ħ®§½œª8”Äc˜Ý“tº^÷ù¹áZO̶úNÊ!P]‡©Ý-Ûi€R+Í”ÏÇþ-õ¾äQaº!Àþ´ÅfO…UU/»EÛWß2s«±Të€õ³§ß¼d¡ Œ ÙîãØõì¡;¦ °:÷õÎÆä1̘°ZfJØŒ-›2¸b×%,æKî% °¿Àf]×U}uíølèw‡ ,·7¯„…îOoV˜>UÕéä¨ìéçÞ*sNƒ V7:†ù¿ï¿9J ½{¸›÷B×aª0àéÚ€ýi‹U˜pŒÀÔo°?mq6¢ïôsyÙìOÁeÚÏ¥Ölké6Úû¼d]}ûÓýÛ”}NõþRç˜Ï}ìoǬ0ýæ?~<=ÿë œ’ÈP •´ÿkïs÷3-í3†âÃ,¯Âd[B  ”À\ñ^²}UQ7 b–ªK¨lûÞWL·vw™Ð{Ÿz —„{Sí6ÿ-ô!c˜åV˜)Æ)ûö¦± @w™aÙnèS6ð¡ý d{ù˜îá˜1ѩǀaIÇ0×;[£šÙbl Š1Ìr+ÌT”ƒvØvCò(UØ–?hÖ¨ÖòÌ•Æ0‡.AXÚP/i¤S½5ëÈåGà‚ÂÃÌF1wúê&MÑ=Ü~íÒ°Û#¤bº‘u5¬QaæÃœr†g_ÅÖ×ý9T5ÆÑœJ3Ô8§bmÖÕ>ygNÕ{ìÐþÏ=†)ªY'Abù0VºŠá\Ì™„;z 3¦œTK— HŠjpnƒß}ÝØãØeæ§”Á•ò³––ËÔu]ÝÕÓ'áÞå:L" ŒaÞ|ûâøÌ Ì«yCSf+€EéÚ€ýi‹ L "0]û°?mq6ÌVpÆÞ?ý|îëõ•˜ë0ØPà:ÌÔ„ã8c˜°¨Ât&Àþ2Ãlºm¿^_½èÂíV¥}Ý»k-“W`vL™Œxé¬s¶3¹ôÒ}Þb&Ž-oe7gßÜÉŽi(› ìçû§?_,Û|íeÚ¯_²Ì^fχ ¶¾û²Î•bÞ͘ýI¹ÏK…æý ½·­ö5·YXàlltæ×ë«çc˵—OµÝÌ>K¶ïfçÝàI=õVßz¶¬xTWqUj(Û•j¨2YW^™ù朮˹ËÄnk¬+yh.Ð)a3£Iªm;+ä:ÌPWj¨Bm/Ó×ÝšcÕ9û,Ù½ß)]—[l«}©eÏãÓíÆNñGPÂ6ºs险¡îÖ˜eº'ÅvÛæ˜†ÀÜÐÚïTarÚÇ 8†Ø ŠYnËeöà^²DU•í¹T›°!mq9³i7¦©*·R+À­/ûœ¤‚X30g^û“²‘n‡@w=Ý€X3œb¶Õ~ß¡ý-3÷} D8æÃÌFôæ”ÆxiÃê‘TëÊq[kì[ìë3 0ÛÜK¶hncì뺪¯œK°%³•”³á¸no^9 ÝŸÞ$¬0͇yˆÐ ¸sNƒ v L×þìO[¬Â€c¦kö§-Va@I\‡ ³Àæƒöy‘9—æDßéglräвs.m˜³­¡íÄìÏ”e¶˜{rÉñ[srÙ/8gÂr™º®«»zú¥9“¯ÃìÞµï¯Ír¡ebmkJƒ?´?)÷y©)³lyc‚ö6ö>FpVæÃ¼ùöÅñ™˜3ï4{ ³¯a_k*¨¡õüøñ´Yýå¶ÈK±c˜sº.ç.»­±®ä¾ŠpN•ØÝNìzÝ* ä:Ì3²Ñ.¡ër‹m…j®Ë=¦õÊml`k“¯Ãš£2ç*4v1Ë, ¶\~P,ýÌš÷²å rfÉfI•EÌŒfõÎÙû§?{ÿþõúÊÁ‰®0õ›ìo£¶øëõÕó¿¡ Ý2È÷Þ‡øÀœYÑUUºnÀF©`»ûzmí1Ö pTÉçÃl_˸´‘º™@Ì™¢)Ãhl[Ý÷Ý·ß¡e澯”Çzê1¾°‘ë0·®øúªÒÔËtŸoçÐE=†9¥\Ú˜¦ºD$ÕºrÜÖû¶Æg ”¯/´š.ÓnîÒe†–Í70ÝK¶hîıQuÙ­ìRÕÑNºðm<&gÿSÃm¬ª: §y}Lðæv2ÏòÀœ9†I^¡ nÃ1ÌvèõÝXÅØ7^Ù·®R+OóaðK˜UÝjrîe 1¯Ëåc˜9Ëà Ù˜îÖTË„–-ê,YŽ[QÎùÛZËÌYv “ï% À†´Å&˜î% °?mq6¢Ç0Ç&Gî[vîe ©·5t‹½9Ëœë-èÜ ˜}×a¶oèÝ×€¦¼ÙøØ¶¦Pû¾«¡}Zf+Sæ›Üci¡  \‡Y×uU_™—vK³Ç0ûöµfæ ‘-'iÞsBh€ÆíÍ+a¡ûÓ›„æÄë0»UÚVO7Tc‚wê2±ÛëJî«çT‰13š¤Ú°³À期*Ìnã»uõ•[eÙ>íå×øñÐÝŸµE÷³ÞjŽO€23píÏVó/¦®BCüš]Ê{vá®1™· „¸³Ü ³[Aå¬[…Í]ÇÀu˜DU•í®wÕ&lH[\n…™C£]RØl,}Ûꆛ `¾dóaöCÌÍb×9v½ç𡳭ö5œ}¡5´ÌÜ÷Õ]Ÿ@„Úp>LæfOã¼äù)R]"’j]9nk}‹}`Α1̃2Æ¡-. 0)Zû*B€5Óµ?‡Ma …Ó«0à©ß`Úb&#0õ›ìO[¬Â€’$›€Æ0´Ï‹Ì™„;úN?c“#÷-;÷’†ÔÛŠ¹Eß”e¶˜{rl_¶º‚ËU`?Âr™º®«»zú$Ü“ï%Û¾¡÷ååõè=^—ÛÖ”¿}ßÕÐ>-³•)³lyc‚ö6ö>FpVî%{óí‹ã3'0¯æåÔì1̾†}­Û± …È–ç»ÀùJ6†Ù­ÒÖ6§ërî2±ÛëJî«çT‰13š¤Ú°3×a˜rFxˉŒc¶ ¨5º.÷˜ç2·±U€­M¾³¤ùcº‹×ìRÞ³ ·ªK?³æ½lùC¨\‡Yr…YRe3c‡Y=ªêñíÇ×8¡¨ÙF©'+¹—,@Î6h‹ÛAÖ„Y7@Y0†¹¥R+À=ÆÛÛj_&£‚b«>—«L ÌÀu˜c vèoK®¡ì{}Ì™¢©ÃhJ8õíwh™¹ïkË@tÒìdà:̽µªCÕh_øÆtÿ†¶UD…9Ö@¦l@S]"’j]9nk}[ûsŽQ‰>¾ýX=¾ýøK5ÏÅ,×^ow™˜uìÁæA9‹"ƒ¶¸Ûm»æ8ç–ÛJ˜ÍÙ¿[¦kšÂ §-. 08¼¾.ÏfÜ0´Ìš×Sn¹­©Ì‡ ³ Æ0Û'×tƒ+´L(Àb‚mì,ÙØm嘜]¥9g™Ø¿O ¾¯5† 3mq D¦ë0ö§-ÎÆ¤1̱ ’sTâ>PR`vî%»åÉ©Ã2fŸS]äïf@R{ÉÖu]ÕWîèµ¥Ec˜%^ïb~ t·7¯„…îOoV˜3¯Ãë U}¡¿…Ö“º «cß×ÒõüÒ'jðYfÒl%cÓW…bj·mªîߨ)·†.ö}Ŭ§Änmþ2é:̦;³Ý­9uVŒîëÖóK±Ï»qfyæÔê0·uy_¬˜3Æ0§ŒE¶»Jc»A÷˱÷5µÊå:ÌlDŸ%Û7¸uhMÝþÜ}Nõ^cÖ³÷q`i`vúÍÛã¡ê0´ÌP•ÕWmÅlkJ%³ž¡“v漯)ëQq±m1û™4†Ó°O=‹5ÅzrÛŸ-Þ¹T˜úÍö§-. 0€ˆÀÔo°?m± Ž˜úÍö§-VaÀ1S¿9Àþ´Å*L8F`ê7ØŸ¶8“g+š[òÈ·z3ñ3€ ³_O¿y;ÏinÉîûzï[Þ¸8Æ0Ë«0‡n&~ŽT—ó/3æÃì†k(\ƺ7ÛáÜ^6f=¡u­vÝ턺§cßûÒõa ³¼ snõÕt-U¦}Ë4ïN‰š>kh’ç±ý‰y?}]¤¡©»†Âkì½Ç¬'Õû ^Ö×aæÔø·Ç/ÏiüØ™1ÌcW˜c¶šœ‚-å¾l€sÁfL#?6ÎSñu»Ic»A÷Ë¥ï=Ç X‰1ÌlDß駯rÏKB—zļnê>Ï}Ÿ[^bâ2€½³§ß¼{Μ*§»Ž¹|ßzB'åtŸOµÏ}ë:igÊ{Ÿ³'1ÌlLÃj”‡$v±¯‰=S4UˆL=«6§õ°f…©ß`Úâr+Ì\Ä\ ëW˜ô›w¯–ÀáÃ, 0€ˆÀÔo°?m± Ž˜úÍö§-VaÀ1S¿9Àþ´ÅÙˆ¾sïÛ¯Íݾ‰–X·Â<@¿yèí}!ºåÒ¢Ã,¯Â< Õ%isÁ|˜csTÆt“nU¥u·êúÛçTëø¥-æ˜f;(úf …H{¹5'™î®wh›Sö9f=±3¬Ÿ¤c˜Ý@3ÜJß½f1Å0†yÜ sJ°–$å> l€#æ‚1Ì)Uh ’zŸu¿ÑŒaf#é~º]ž9\»9'ض¼ÄÄe(¥f ß¼iàÛÿ†B3tÂOèõ±ËL ðözú|h¿§ìÏœõ¨8©m1Û‹ÜҨ-³®T!’j¿÷X%T˜úÍö§-. 0€ˆÀÔo°?m± Ž˜úÍö§-VaÀ1S¿9Àþ´Å*L8F`ê7ØŸ¶8“f+)mòc·žrñúõëêîîaòk(!0?|ªªÓi0|Îmòc ,q;iù»»‡¿ÚbUfyfIÕ%l˜3æÃlW`íîÛn°ŽuíÆvýÎ]nl™±ýUi›Q]f#ú,Ù¾©©BÓ\5Ý´Ý©®Úëjÿ ¿ÐóíЊ]O̺†ö7ô€s®0;c˜¡Ê«o 3u˜4ëØxéœívÃ2v[sýñöfðù¿{|Ù«23ÌÍ:¢k†5TÕ×a†ºRç†fL—,@N^TcÏ©. Ìž Û+Œ†.iIQ©¶·{BϞǀœ³sÿ¾“~b‚e( ÆBgh;©ö§/4Cëˆ]`N•Ù[yº—l6&aŽDßó±Kµ½¹ÛNµOœ[…©ß`³*38®©-. 0€ˆÀܱßÜ€sª2‡Îš5†©Â€ƒ¦~s€ýi‹U˜P’Ñ{ɾ{wç(,4géç¶X•™y`VUuûùó?¨fàÙc=öØãéç½þ³ ÊÅo§ÓégUUÕíÍ+GþßÃã÷ª®ëçÇÆ0 ‚À€Áò’€²Ôu]ÝŸÞÌ­Ýßß:™sˆ.Y˜ 0 œÀ¼ÞèNú×>m¶-èZtÒO`×>UO nÝÔ¬ç©ðÛ?]^^Ÿk¦+‹Y€ƒæ–J Ó¡àë{n(D8ƒÀìëBm_÷ù¾J³»ÌPp¶—í.×^÷ÐrcëY«*U]ämöf7܆¯ù×Fí@ê>ýmÎþ´— íÏÖ„%ÀU˜Sg­j­–MÙ7¶³K÷³ÝÅ CݰgRa®‚%ûñãéùߨ2ÂàÀÙWÑM­6yY M€ƒW˜Sƒv,Tç\o٠쥗©4ûà«f;ÄÚáÓbÝÀëž%Û®P ­#'——×/ªI'þ”á·Óéô³ªªêöæ•£1ÃÃã÷çÙJbïÛý*,¶õîÝÝèô^ß«º®Ÿ›Þ+¡Øàåqóu˜ 0@`@Nœô“À»ww€ÀdÈíÍ«ªºyã@œ.Y˜ 0@`@N^œôs÷ùߎTUõúõëp`vŸ€svzó\L¾L3–@?c˜ 0@`€À …™tóõ‡ÇïŽØœ­ ói§ÆÛÇh^{û»/a^êºv –«µ%ŽÑüövòô^7ß¾8Êk~€W×,¤oK£éí­1L˜ 0@`@N.R¯ðýÓŸ¿üíëõU’õ-YÏ”}^k;ÀqŒµuÍóc+åýå¼Ï[íëjæ×ë«çîûbM9K×3e_cöi­ýÊ Ë¦íˆi£J Ëíø¦´áYf7é… `¯ŠÜ×­)w{(±etè¹­ºEºÛ ­#u—4 ,s~_1mïÐÐZL›™K»z‘˨éêœzúìœõL­”ûÖŸò}ÇqÄÿÿcÛÞöߺËÄ´™9µ«Ùž%ÛþEQrw®® àœ‡¤æA¹¶™¹~‰ÚeüÐÁËé‹Øì³³n¾váHmÁÖmomýÅÞ_¤°¯ß<÷n @h––[¶½9·ß÷8°¡åJë¶èî³KN€±?÷6¢o?·lÛb¶µW[{±æ›ý2HÕuZÏÔebÏ€í[_÷Ôk]²p^ãÿ_ï{1mÝÇ1f™)mxV»ƒ1ËmµÌÒ3s…#œoÅ8åù’Ú‡¥ífìûߣ ŸË½d@`€À 9™tÒO]×U}uí¨ÙÒN9F»W˜·7¯­ÜŸÞ80ƒvj¼-qŒæ··¿N§Ÿ"ô»ûüïi&œ3 &L˜ 0àx.ªê¯»>ÜÕ„üVUÕÏ››G«ÿpóþüªè‚LIEND®B`‚stella-3.9.3/docs/graphics/debugger_tiainfo.png0000644000175000001440000000356012205116016021130 0ustar stephenusers‰PNG  IHDR;^Óð$ÍsBITÛáOà pHYsaa¨?§iIDATxœí?nÝ8Æ•`à"Iåf›ÒÚGHµå"Uš”.²åžÀGHmÀ@š4©Ò¾C¸ð¶ •EÎp8ü£òû!Eü$‘?8䓾÷æ×÷¯ À oÏn D,ž@Äà D,žøãìŒÆÃãóÙMxÅårùçï?ÏnŰ´“›[Ÿoßþ:» ÿs{ûùì& N#¹)áà‰ã{}wîdí;ÛC#­5Ï=;s«+Z˺jòD²bã]v}whaøIë˹ºz¿ÿóååwôóÃÖêtî̵ä訰˜¿ð’Pš†[÷›ø£BF˜ÇºSúêê}(çúI(X4†5M£[%GEɈØíîÍm¨äj¿s˜öTOɘfê=lÚ6žIçšærIýª#T‡ïçhgòP=̘¼~,dÚuEŒD,Õ;aÈí¯{&¹ÚâœúOô(ê©x¦ÚYHîmµû`HvPnææÈ·d!fªÀþó#¦Š£²ç±îRP %'UØ!ŒH}"ùP0§#<ÓêWȉêèˆ GÍcù£BŠæ±L~"DwÔ0œ8º†d%F„3ÒŒ=T¸V›ÔyV•§h~"9pÈ[/RŸ`Ö¥‘j¹«cíú¡Tã¥ÌÒºÉõëY]X×õݽ¢¦FW!Ôiè6têèÐiš{T16\Í »)¼†» —(¨£ä›Ö?å3þ«ÿ\’"u‹çŠ)©î°öUÉWwu×O#ú„ë²,o¬åÞyx|N>hš|L¢bÄÞÞ~Æ›íØäæ5U<0C 7ÂîHF£»„ð’Q[BãM<ˆÀˆXÊ1ªX;^Š úkÚ½3Û$^еN„*G®Ì˜™4à‹’u§°ï¥(§µ¦íX…VޱrfðRlÑÂCf»ÿ“Ù$¡d`÷襨Ã`ã“¿°/ÅZȨ¢9E¸z÷RÔaÿªcÖK1Ù†ZìéÖÇÐaq¸§—"4¥ÖK1Ù$‰‘_·¾òŸP‡kg/ÅÂf8ÒT¼_qÊ Â\O÷³…û–|N1²®»!±Îä¡}™ÂKÑ”œ:s=fS‹©¯}LiÚ‚\톊غßÝ @ÓCEìEGšîÁÛvxb´1Öx‰|*ॠAV €'±xóXôøöR”´þÓÇwkàt¼z)JÂõr¹|ù÷g­˜ÊY1¿aÖÁyg;nFò…ºþ) CÉ+%Sá`kÖæc ø¾­ÛÏ:CïêËß Y;ˆX¼#›²“E9ëß”»W¸st·°ê!r¤Ùt¦m=ûVáöxØÁôV"–ñûã¡âiöæÊ¦’XæöÚ¢oy§Õh]%V˜ìEq±KŽß_ô¨Š{އîÜ· í UÊZ ”+$´‰­Ä…ÏPÄJ.‚,¿?ÐJ) Iý­a˜å%ÞŠ ×:ÓPÄR >mBÝ^ˆÕ9+V'º¹Žó\qɭݰà‹-ÊmÙZ i’eÃD[c,uÏVí%k‰öPv„áw¶LKü uèŒ û#7L”ìYíý؇ÇçËå"Ù³µògС—¢ðÇG÷Ÿ7÷RüôñÝAÀÖ W„(pAEÌšYq_\íÙ°5U€(S1ÎZ13à~Œà\ॠAV €'±xóXôÀKgÀK@âÀK‘¤[gO!oÆð螘¯ÛíºÂ'T¿þ<öéæCôó›§ê2)3§m“Çצ, vWéÖí| P?×KÑßZ±Í2‡Áþ c¿…rÖ×ëöÿÎô XUjÈ= ÷R”§.¼£—ð™R# æÃQá4ǬÍâ~Ïè,ìÄK¢UÄn9ðÍÓaÐ2è^Ðá:™L{_éÌáªH˜™£¶»¤ä¾\H¹Í¢Yõ}|›Œ®’C̪5{5kmÚþ3½Ÿn>deÅ‹ØPS›îΜwÆ`?wVß–—by2\5I&o`ú«?¾—¢î.˜5ÞþúþuUnÂEiû§\½…áB£þéWEý1¶ð{פi55rnájpnGÏàf®¶#vûRÿðóŸíøöËO»‡ÛíöìT´£ïû®ëºîiœí¨ß›¿ó{÷èT´I‚ààààˆð²ÑóWßu]×uÞúÞ÷Õ|?þ\ÑË:­Íƒþê»îáÃÛÎ_¼R‹o¿üô%nCˆmjŠí-o¾ÿ-¼D#¹S“¾ï»7ßÿ&¹Óll'-ÑŒ}ñÇÎ2ew‚ý{×ï‰mZ‹í ü¸¦ µ·\Y4WNðf"P#q‹Àu¼Z&5·\ÝS) ùú÷¿º®ëºŸ>ÿdõgk?Ù÷=Žmì^m)圴n|ÍK?Ç%Ƨþpâ^-3Mà _K*t[¿²ÍÜ+n§É¢–k‘">KíƒWíUÖàǨý×<‡µŒkL˜-&ù«ö‡ðgÑÜnÙOððN;üÿô–ipK$$0CoKϺÕÞjÏôßCÎÏÞs8þ½µã_:Ïk¯wæmpÌ£ ÎH˜¡×{-~C®AŽó[}fO¿[‹«µö¤ê¡í.±ÔUÕ>ä]v©$²§l’âV{ü»ã¯ØöLeîØöl³u.—Ú3móV'lõöÿh,¯—¹óºv Rß¹D8Ý÷Ñ>ÚïÖúÃÖë¥ê!í)5ÖƒFðÞvÝÅž×1w«=¾Ã82‚Û»ŸFž%îs5n ‰£Fs©Ú:-?é3GúÕV{Zì?Yü™'d<ÂÍ}‚JI¶6²^ÏZ]ŽsóZ§ÚWi×¥¦þYj¬Sƒ¿ê;l­‰o. çÚÏ»—Rjð!%#ɬÕ7ÌÚúg‰wêþ’ur1¦køÙÞ»Š½S´RM‡Ì5E,ô³Ž«ÕÛSÅMª8.ýØCÏOªãʵŸRc=hÁ®ûß3³Ïx¤êÒ»^ȬÐíΜE“úø6…Î,XÛ&ôg©Ž+•÷©úîõ« ísÄvÌL“¥’NÈø¥8¿1I6f»#ñ[!Ç{¤?”롱=<3¾ÈOwØ32O52הɥéŸg¼öÕò8Ѧ˜¢xïý„×t›”uÿTÇ^¢à5Y‡gfçzç;:C&f›}Ìíkï¨3d&IÌl“6-msþö\‹#Ç•ÊûT ]H;wlç./„~и5™E³tž¶f·=®Ð× isͳhBc{xf|1 žº„¾ ”Ü Ä6µ‰MðJ4zr ØÃ ài<ÉåR¢à¨IT‰¦ïûÝ+ÖCÉÄ6—ÁoM£„’„N‘Û´ÛO¹v ­vhn€€@.Q5øá™PºØNÅ6-Æö£@kú¾yØ’ØæÊ±ý¨OÜ£øN°s>»Ø¦µØVƒh” Á Á ÁG1 ~Ä,„]›{,<Ú&‹vˆ›R[l6”à‡‹YÚÅ=Úž¥Å©¿þý¯]û iÒf’;7«ÏÉofWo®üìc|û:åluŒ¥ÑÑÜÄY£›­v‡´gÏ6sÇrž—Ú¼çzv”{ Bc}m?K±ûz¯Å§­ôCÖá6u-¸¶þ=d´4¾ÈÓïcG]ÃíõðµÔ¡–ÚÒž=Ûì=ÏÓ6¯uœµãbÜľ ‰­Ðk9 ¹®wÌ ìª1úXsðÇv”{¶·ÆÊ1ŠÙûFyÕ$¿•˜Ç? ½ËláL5e¿j)FÕà Ú–ÔÜÈS‚¯÷ˆQ ž‚FÌgvŒ¹öÏÝêçœ B—õˆQ ¾è[¹³÷µ÷õSM‡Ìõá°éšeÄí4‰…L(háúŽ{<`ëç«ÅèÃív{îºí‡ÈÏÌÎõHÕ˜O»cf¿,]¼˜?¬Úì9¶˜ {Ú3ËhÏyÎq\©¼ÿøHÕÐ…´sÇvÊ>±'>SÅVÈ,šo013rR{M³hBc{xf|1 ¾Ä;qç¹”sßJ‚óíÆèY Þ³h òK|ÈÊ.fÈ”s œw1z™/Ðk×ççoJ4<5‰*Ñô}¿{Åz(™ØæÒ#ø­i”P’Ð)’b›–cû)׎¡ÕNÍàààÈ%ª?<³JûÁ©Ø¦ÅØ~ÔhMß÷/[Û\9¶£UPë÷¸P'Ø9Ÿ]lÓZl«Á4J‚àààÈ£ê?ö.Â=ýØ×;ºŸÜçÎè[{úŒ8•à“ÚZõýhÀýû_‡Þ,Ö~Wò¦µþ‡_]ð^½ €©[Û¥$<ý÷µ[á˜mæýø÷ÆÛO· )c•Xž¢üx?kHð‡GÊ[+´‡”qBJF{¶Ùê@ãí§ßo½fêòu'ð\q±£Hðw)‡Ôˆ9Ú§ó]/æÏª£SâL‚¯jÔÓêÝ â þ’#ýÚ’÷ZI¨¶»Äû•=¶XCrÊ9­pn›ê÷RmsdôõÓ矼|õÚ´9š?+¦Á/Ž@·fˆì ž2EL)c«Ý[Û”z\\kä:ñ $N·î"¹`‚ß †”²¯˜×;²¿½¿»ô¸5B‡Sv ýYÎþ@Ï¢0‚窷ـOC·ã þê§D ÁP“¨Mß÷»W¬‡’‰m.=‚ÿöËO-ªñîõ«NlsõØ~ʵchµÓ@s#x$x$xr‰ªÁÿðóŸÎUˆýàTlÓbl?ê´¦ïûîÍ÷¿Iî\>¶£UðÅ?:Ë”Ý vÎgÛ´Ûjð’à$x$x$xòȲàÇܪê%?Ô¿ÄUÜK<‡V»oßt-^×Þ~1†¯¥„Õr'9r¼©ÏaH{޶™6ⶤ¾*& Á×4z¯E çÐu >j„:~‡ž&­2Ehcïv[Ûlµ7÷mmìù™kÏžm¶nác¯éÞëÊýúîÑ>2w½—îT•‡öK^¢_¤ñ×R°¬• Æ%е2ÅÚ¿Ç”;¶¶Ù ÄñïÎ}Ÿò†WH{öl³•–Ú3móZr¿r‰ïÞƒ®­7â#}$4þSô#2Í¢‰I̹Þ\bhOÈxBÏáJI:øýFè%÷ -Ñœlãä07n%a´ÖyZ¿^µœ$øSo$³¹:àÒt°;dÍÉ{®ý-_¯úÚø:9çuË2Mò^#€¥7…Twã×ýàgÏëïmsªé¹®áR}½”øá>}¤ô¼bŸá{i?[eйSÝòO÷µ´Ð펜Øã iÏÚ6©f5¤>.î7ˆ ío¡ý1G?¢ën·Ûs×m¯2,ŠPÒ3³]øºK¹®áûÏÌ~÷úUÐö%Æ6‰íaQÏ¢hÔ“SÀY”_@‚J¸fÀ<% €šD•hú¾ß½b=”LlséüÖ4J(IèI±M˱ý”kÇÐj§æFðHðHðäUƒžÙ¥‹ýàTlÓbl?ê´¦ïû—‡-‰m®ÛÑ*ðÄ=Šï;糋mZ‹m5x€FIð<<<yT¹àÇ™+­-è=Ýæ¬vä>nkÝÖÙŽÆÆ™qœ{]^*ÁƒaˆÚSc®×‰‘ê¸CW¶§|CLŒ¿rö¿q3ìC Á¯¾Ó—ð®6Œ×75ò¡Æ8–Ü%ø$Á3 ÜñEH féßBKEKœ£Cm•r¦ÿ¾v{¼u|g–H7(Úº3 ‰…£e•¡ïMû`l¯õaå F?d -­ ¶·är;íÓv,µem?Óã*©ŒuÅ$¾T:™^—¥»à­xŒ‰›£w 1±u´Kð•'÷µ ¿ sɬ¤Î\â($wý—.èx+É·tÄÛEK4)§ÄzÇpÖù9sFǯWM×Çh\‚¯¦c…ÖúSÞ½äî$s5yú–,kº>â踪J4Kµà¹ä¹Vs¼GÇ:c Û‘6ƾ˜fY_rO]§>3ÄÛEFð!#âé6¹GÌk#è3KK¯²ml{”hÊ.e,ÕÝç¦×ÆÌ9£o¥Š­˜þЪ‡ÛíöÜuÛ«„ ‹"xfvº²‰d˜ÇûÏÌ~÷úUÐöb›Öb{XijhåCÖÌ”2 ¾ñ$p6% €šD•hú¾ß½b=”LlséüÖ4J(IèI±M˱ý”kÇÐj§æFðHðHðäUƒžÙ¥óÁ)DŒà%wjÑ÷ýËÖÀ>‚'îQ|‚7ŸâFðHðHðHðHð4¾àÇxaáTûëº.àqÆ«K /µeikÄ‚|É}-1Þ£=)ÚòÓ矼|Moœ¨—¶)õüFðEªuä+¹ƒßìè>´tš çýt›RÊ!ÃbàÃC’¿Ô¥ÉÍ4‰î©.•;¦ o+éM· ù{ßyÄ”z#x%ˆLÇtÖ›…Ñ;Á¥Å¤4½ÈùÃé> $ø$#Ü!IµX^8ã˜Æå%à‰x:š,s&]#vhÃ%gÑ 3GÖ’XÈ613d¦ûËQ^Yjsìk¥Úp_·Ûí¹ë¶WÀüðÞ¾øƒ*èÐÒüZ!ð?ùñ;…ÀnLq: @€N$¯AõøôŸ}øêó¢}¤~ÿ*îåt¤òÖíêµe¤œGlWê§/õí¦bª¹>`­Øé¬ýÇžãœ2Yz€WO·WOI½o»Ô0»ÇË×0-9íâêeè¼8V@˜ÛÇšú|j¿­ûjGë5þ¨ Gu6Ð6ΜG¿S;XÖ¼H€m¸9 "²ŸµmÆ/ièÑcÝïàäæ=2%š¯¥4§L­©qH)Ÿ¹¿×LsJÛX«“Zm¾FÛh}^\)8÷evS¡‡Øb‹¾st¹Á\Z–nŽDã˜íâEN¦ïÓîÿÍeðþ_Nb#û‰l3ü|êß©ùäë>µ"7ï‘4Fò­‹ñ~j5®µ“wîXk¯•æ”¶QÚk–áZÛh}^\Aji.^Z껕ìç(±E˾s4¶HÙWjL°i€ž¤åÄÙ* W3Õ8#e4®¯ñ Ôc»Â õú_%}Ù^㮽ûª‘ø£vlÑ¢?ýr«×j<=5£ž-Ò=œîqÕ@°—ö1|HFë ó}³Èôêœý©Ï[«¯zÖøãå– ±§ýÔjˆÑõн]¸V9O]üÏðTKŽßçÕW—4Å=wíCÉš‰ÔýÔÚæˆÎ÷ñ´“=^-Ѫ­ö–‡’4GÖFÕÚàliöýâœ~[˾ÞÞe˜ã{oß¼ýåív»½þÑ÷ù²´Í\…ä<Ý/å €¥/±_Kw­×#DË'’¯È“K¦Ú¤~/ºïµ§¸×JsÎñ¢³)JŸ*¿õ¹S뼈î£Ö6P˗�}ñǯßñ“¿»}ñ? ÷Õ"ý±µ¾OîÈ[Ô~ëWnlQ;ÎK-ë¡wòM^€t® Ã–îú Eû €¸Ý6|Íôî'?~§:ìéõ¾»ýÈÃÀ€~˜ât  ?>ýê?ÿöoÿöoÿöoÿöoÿnÿïáçœÖ÷Þ¾yûËÛí×kpô/ß¼UZ;xýïÿôvûêóßøüË÷ß*€Þ¯áK±ö¯½û“on·[ô!q_}~»½ÿööÅ¿Vº…ÞýìËp¿êÝϾœÔÇ_|¼½ûÅíöÅÄHé)îf _©¯rŒ¯A`úb—à)îøù?»ýü‡Ÿ)úЉuOГ‡‡W·‡‡W—Lë‘ò~åò9[=õƒó©ÿ¯/p-YkÐç:™ÏÏ6éÔFŽ1•¦-ÒÓc0Óª.rÒÕ"‘c¥lmgãm–‚¯á¶ÏÏ>k¥å-çÇjU_­Ê'õš1—žhÔÈWÊyÕòêçÃÏ~üÍ× àbŠÖ ??øôßZ€’k¸ÿHGtëô¤v¦·Nø|"åu5‘:3SßYÛfØþzª‡{:—ÊáÊ£»‘kF¤ j瓳àNûwAê5Êm”0'8ŸéŒl“’¶Ö£©Gk{”OÍ‘û=áÇb”€ôý×ïAÏí /u[MMO9Ndó½£=µÝøXsBËiùkÇJÉWJÞ÷\’0—ÞUôÆ@ïAR­¶Z³m^o©å©/ 3Ö \ÂfOqN;ŸšœL ¿7üonÛÒiÌkÛE¦·œ–Ÿr¬{š»MOK¢ÓÌÇÇ_[×_cÔ¾u ·vþ­•ÙÚyšs^ôô.«½ÔïZ]DË9r¾ÐNlýñév{óv5Ù³ó=Õ©^šFZcóp»-òÐC9¶JçÞyÖu$€‹´‹VS™S‚Ï–mè(£±Ñä3¯FÌa_ï~öe|ãÇ'£èôXP³ÔÑ[ëÔ^ùÁTSá–æ^Êz¼§+kS¿#k‰[®7N9WÜvö Rk,•¸ûø‹·ÿúó/BÛþäÇï€}`a zt4q©Ó¿=H—ÇÖ¨ºjÞ¯(禂ót›2(fôબA®_ÜêUN9û :æÖ"×èˆÓ¸÷k­ö<~Íco±v6·mLÕñ\û©Ñ¶¶Z7ÜÃ+×z.Ÿ­óµö Ϋh úZçxmsʺߵà):ezm½éx_¥ÂܾZNóny¬ÚõU3-KõIËZÛ˜Ê×QFYsÚêmãÈö|+CÎ[$€ƒ±@€¾Ô™Ïý,u›”õ¡µ¶«•¦µmkv˜KÓ©¿ÜmZä}jÚq­zªÝ6jLKS®SÏÉÒ¶Zë¼Ù³|j%ùÚºJ®×ô g¾Z9RpQ;­g ¬ÎZ>` ˆÑs€Kx¡à(úãÓá3úüüÁpL'è‹P+@:Э{ؾ€è)@·î `?úbt §Ýº':÷ððêöððê’i=RÞ¯˜€*ôÅ.áenzʯ1kîSiºÂkÕZÖENºZ¤#r¬”m¢íl¼ÍRP9Üöùùç ´´|¢å\ãX­ê«Fù¤´¿–m–­A¿¿[üÞ±ÝbÔ+òþòa{ëô¤ [§a\>Þ÷¿‰±¤M}gm›aûë©îé\*£Ö³@€~dÕk”ÿÚègNp>€G¶II[›HGù´–7Ù\+èElŠûWŸßnï¿Í ¦:Þ)ÛÔ ä"ljLc¾OÃÚn|¬¹@ªå´üµc¥ä+%ï{.I˜Kon7œv½1Ð{àW«­Öl[æ/5=‘|4a :À%l6‚v>5%85˜~oøßܶ¥Ó˜×¶‹L;o9-?åX÷4w›ž–$DGFÇÇ_[×_cÔ¾u¾vþ­•ÙÚyšs^´°–æhz"ç´ ÐgÖ=ƒá=G•RýÓ˜‡ÛÕÈ{SmSÚ=‚é­ó2e=÷&Оz˲<ÓÔq#æÀî¬A¸„—%_N™êÛCàÐ[‡j¤Ë@ —²Þ#ï©AØÚÔïÈ“Æk>­½V™½í°=×|àªz”)^ƒ¾„¤¾úêJ? SÓÞ· æzl÷+w°Rn*8O:e :À%¼¬±“hÇ«©ð9ûúNêƒÀJÒ¸÷²€=_óØ[ŒRç¶”:®Q[Ð÷°d¥Ö{ëhïíüL!,øúߺÙB¾Ïþ©å.ôÛíWëžÞ¼ÍÆŸ¯m3× OsÇŠvêÇûª@•¤¹f»õ±j×WÍ´,Õ$-kmc*_G sÚêmcëö˜ó¶€.<>E Ïwæs?KÝ&ÚY®¹]­4­m[3(Ms¤þr·i‘÷©‘äZõT»m´šAzN–¶ÕZçM´|¶NoÉu ¶ Ð3߃­)hªÖ³Œ`€™¾§÷BÀQô¼{óLïd.Æ{Ðè@OºuOûÑ =èÖ=ìG_ @€ô [÷I^Ý^]2­GÊû•Ëçlõ§§/p /s;vS¶xÙøXsǘJÓ^«vÏ÷0¯SŸÕ(çh]l•¯­ÚOí|EÒž²M´ÝçnóüüáS°Ö"ï÷íz9?×Òܪ|R¯asé‰ÖA|¥œ§µÎiúðgÿüßL~þÓý‡ 6Пn·7o;µ:°sÇXé™ R÷ŽÔ!”sdùJ¿i°ÖvæÚr­mö:/–Òrå`nØׂðžnt{|2ŠNWÆø=`îvØ"@?p'ö>Sfz¬íc*¸®µÍð|i9šz´kÅåÓâ¦JË7®É× Ü-ô¯>¿ÝÞ›Ý!]ꤵššžrœ¥)ÁãÉ©íÆÇšë˜×Èû¸ƒBÛbzú\¾R¦å¯M??ÒÒ†¹¶S#°š*¿#DµÎœóTY¯ÞRË9R_pyFÏéÔÇß~w»Ýn·ÿñ?üúƒ_ÿûý… ›=Å}Øáºÿ7×Y[Û&¬Ü¿7üonۥ㌂¹ÎåÒvÃcLý;¥|¶¨VÇ©‘¯í§•©v°Öž—ò3×È­ÕçZ™­Õ{ÎyÚ{Yµ>—k§)å|¿átÄå4gÀïAxäóèßiEkÐ{šêÄ.MÛ,<Þn‹7ÝtÈSe zt½àڔݒNkê~—ª5^û[£ã;NãVe©ŸÖÛÒL³MoßbílI[My/yi=lµn¸å¹rÄòÙ:_kÏõàÜ~ð×_,Û㿯m,+Zƒ¾Ö]›Â²Îv-X‰N_[ßYsºøÒ¾jNqî/²æ~)[*çÚu‘@lÙ~¢O¯ EÚc¤üRêôhO,Ï9wJëãl7‹Z¾á å)îž9™¬A§Sãôžâ ô@'/uz{t›”õ˜µ¶«•¦µmkwPKÒ]£\ró•ÛvjÕÕõ05í¸V»©Ý¾jLkïZ¯•þ–çñžå“s®ÔÎW‹ëFÉ5€} Äa=ó=è0œ½ó}¤üµ¾QtõºìéA}À=¸„Š€=Ó\rôǧS…‚Aõ‡t‚¾µt ƒÝº'€ýè‹Ð€žtëžö£/ @z Э{‚$¯>½Jîji=RÞ¯˜à ôÅ.áen‡uʯÍkîSiºÂk¼¦Þ'žóŽñH9Gëb«|mÕ~jç+’ö”m¢í>w›û{é^5Éû}»^Îϵ4×(Ÿ”ö\«íp®]¬‰MqÿêóÛíý·Ùö©ŽnÊ65§Èq–¦ƒ¹íÆÇš \jä}<ýv)HŠL‡nQÖ)ÓòצŸiiÃ\ÛÉ âÖêýˆA^­s'çãmzyåX¤ÜR¶YÚ.e›¹¿ßß©þð𪸠£m¦Æ±ZÕW«ò™jó^£—®F}¥\ûö¼N@Œ Ó›¢÷ ßße}ïÜù‰—ÏQß©ãq§ê;)Ûô˜ÿ¥´]y´åõ V9µÁ{Ða÷t#éôÂtfƒæÁùÔˆ`Ê6Ñ °å¨coqåSsäþjZ–ºઌœsì=ó=è‘i¯5F®ÆÚ¹`âhÓp£S÷[äkxÜÒ:[«¯šÇÚ£¾Ö‚ÚµúšËÿ–Hä´¡µ)ókåzŸ³ŸÈgÑó¯õõg©DÚOJ} XƒeþÅ}çŸ÷÷Ÿ¯¾nÍ{ÒiìÅV;vîæ¦½Îm³Wz¶8æpúìùk•¯hýŒ¿¶ªlzþ¿˜Ó=—a]Í-X;^ïK$æê5RŽµÊ¹Ö~rΑ¥<µºþÔZbs¿‘f)@/ú̺§è–¶r®ºF?’ßÈ(dïÁg˲<Ê3 ¢×ƒ¹|M-È)óZû™»áÉÛYÎw#æÐ kÐ.¡h úÒtòÖÁÌpÚôTzÆ?[ç³·``i:md zïKIyŸùF`îºu@«}a úZpÕS‡}j êYb%0jX•ÞTˆ>C€sržÙ¬A‡Müt´Æ|uM:t :‘`¥‡w“§¼ø¨êÜrÞb${n-rä¡~[çwë¼ïÝæP>kÇIy7ýp»Zûï+w)ÛE¾ï¡mPF αôǧÛíÍÛìŽöøóµmJ;÷s#ù­§¸§ÖÖÈŸiä:¥­ÞƒÝ¹öScÙB¤Ö:¿"iŒž_9k¹çÒ»TÎ[#%ùjfZè3ëžî£a5ƒ£HôlÓ;‡Ó¯çòÙæl"Eêúò³MAo^ÛaNzr–?hÀn¬A¸„—%_^š¢;î/}?e:j©–£H­Žu摱”)ÛkOÒî%8·û’µú½YKs4ï)ûp­}a úZP wðk¼ê*z¼VÁåÖÑÚZû«;âȹQÛ~®»³“úøÿý¯ßù÷þîÿ£P¸´*kÐS¦×­æ“µ^ÕòõSWzÕÕk^—7^§žûNíAüVë}µùúû¶Ÿ’6:—v7јA|ºÝÞ¼Mîü®MCÝz›ÔôÔ P÷>VnpQ3XgüYê«×¦LO=ÈlËúH­·HžJÓ»TFµÚOJš—òi‡‘cEÛs)÷[Ü€(ÍpBOFÑ9…ñˆ9 Ot°s?ë}›’28r¾jwðç–>¤'ºíÒv)O¼®Y–‘)×%éN=ßJ˨v;\{b‹ó/·lJžo°W=à8J@nÊ;ôˆÌ÷ smW^ï- ÒÖª2zÎAüÑoýô»üÏß/ÜãO“¶þWóg* èsÍ=c :•XƒÎAüÙ?ýù¦ûÿø¯Ÿ2t€ÔúÿüA¡@õÝt€ý=ç$;°ì…"€£èOJ `/úbt §Ýº'vôððêöððJ:¸.}1€KÈzŠû\òüüA‰.”ÏÊèžöÜtŽó^šßHz"Ç\Ú&Z_ÏÏ>é¥åù~i]ÇR´ýùùçÿÖžÐVé–ϰœÎ¬u>‡Aì\;ŒlsÕúà ¬A¸ïAç7‚Ô^¬ Oý}¼md›Ôò)E?b]½è™ïAŸ¥¬±Íx»µý,ª¦¦§vš›§šåšÞ²|Î,eÊýRßo¨ €“³ý4>û§Ë³!¾þ·êZû@€¾a2<†#9ÛÌÖSép?kߦ'7‹ŒìÎk˜ö¥¿—”st™ÂÚ±Î4·Ï­‹û6kí8S€þøt»½y»ÐÔ jÎ\¤æemûšÓ«qç(õpOFÑ/ÂûµëŠFЇÓkS¦DOœ¥AGÍ¿µxˆ\¯yïéXô±…5èk£º‘Qáq8žî;d£ÓÅK‚çjL¯÷^ŽŒúbp3Â~ôú5/jì$ºfvhG^y6~EVÍà9zü-‚МýÖ|/vË×ÍmÕ®¦þ>w3'µÝ•ÔÁ}ÿn^)ŠÖ ¯WkS¸·Þ&’®ÔcåsSûJ9ÖÒìHÞ#ÇŠ<å>r¬èÓòkñk3,"Û¬ÕWm¥uÀÅXƒNö}ËÚè %gz{d›èÓÎS‚—¥m[>è®Öv5ʹeZrð¹}—æ?šæh \z¬Ümðp…=ó=èP+H—.Íè9•a/+è#@ß9(ª9í€óùÓüuÒöoÿãg 8h€ž±½v~EnBŸúbFÑ‹òµï Øãèpà€\Àœ'@·`?FÏoÿíãk{Cà›¢ÝèБqýö‡ÿ®êßöð"´Õ£§ìF_ àŒ p8k#Þ¥è7@·8±ûkðæ„Úi=RÞq^]š5èÖ„ôµÝ1?Âee¹Uùµì$íÑ6Z”aouál[')Û,mWc›çç·‡‡W·‡‡WÕÚQ‹|íqÓÁy»nlUF5ÚjJÛpC€3(ZƒþüüáÓk?þ¬w&JÊïÞ êE«¶qæ2Œ”ïÜ¿÷lÓg»Dòi‡µ¶éíMs«¶1LO‹rkæ½´mä¤'%ÈZªó¹2Ü"Í-¦dεÔ鮵Ê0r^lQÎ¥Á^ip1žê;HöXÕ>×K®Q­®?‘ß”H¾"Ÿ¥kí³×Ò³VKmk­ŸÐ5kÐ.a³ôñ4ÃÜ»è)û¹w~×Fzæ:ÅµÒ¼Ô Û¢-ZÊWͼ߿7œú™ZÎ-ÛO¤ £é™š6º4å·Up]Ún-_Ñv¸–ž–m#õÜZ dïÇ_»xµu²µ®Q{ü6-ý¦ÔZf2×.ZLË^›æàq›ß²M§\ÖòniÞu­Mi7å8N€>³îi)Ë阔þÈ÷ÒáM™zÖBËŽvêþ{˜¹GpÞÛôãšéÙ»N#yI Àz 䝸®ÖyžK7ÎjüVFo¢Eƒô£´‹C·_kÐ.¡è=èsS5炨ZÁX«ŽèÖ„;6½•óÚ4ìµ2N-®ÑI‹UgÓ:_‘zïíIÝ)ӟמn-8?_›>ë Œo€­”Ž‚¿ÿ—ßü•B: ÐÖ ¯u4#k¯#£ð¥€©NýVÇ:z‡«§cÕHÏÔtõÜNeêzò¥éε^•µGp¶up“ú̆£”åƒá³Žœ *ëµ Az#Ö \B•5è)S6ktìsö3·îp‹cí±>¯—rÞòX¹õžû ­Ûs‹çôÔsÓ3ÞOÍv¹E,=n-ï)eRZ—9Óòkµ±­®-sˉzþmÊÍÛVçqn[-yÖÆÚšxÈõ—ßüÕwþký}€±ôǧÛíÍÛäùè4Ô¥irµ¦³FöSsêltf@ÍNUéó¶œ žZÎ-ë=R†%iަo‹6Rc†JJ¾ÖŽ—ú÷­ÏÓ”6<þ,õ)Òky_z¦Â£“Ñô¤´±×ĵÙRµÛOÎu£wѶ]²±Åù˜û‰C{|2Š^!`ú«ÿëëïüûïüïŸ)$à z 3Ÿ3½=%@(MÏÜ4Ýq‡¢æúV¯VKÝßõUš§ZÓÛkO“/i‡µÚjíòN Ê·<—kµÏÓÒkAvŸ2«§æù:XµÌëó¢öyºõu£VÙly-,y–B‹òÛê7ö Ð3߃pG꨷º±G?ŽºÆ[ÛªÌèyuFÌãè'é€÷øägˆü~ùÍ€ó+zú;9ãÿà(¿_\˜÷ Ð€žtëžö£/ @z Э{ؾ€è)@·î)Ûԫݨ_.G*ç+çýÊåãZѸ„¬÷ Ïu2Ïò ˜Zï›]ÚÏRG}¼ýpÛ’4µ|îÚ±†ï¥ß²œs¶YÚ®Æ6­ó~ß®—ó³—¶1u®µ¥ý¬¥µF¾RÎaïÍ8k€þøt»½y»Ø™­Õ¡¾ŠhÀ0ìd¥Œ{%Œ¤'Rε¶Ù+ÿKi¹r0wÏóR}EÊ`SOÇEÿ ¾8.í÷Ú~ÿ$Xƒ>Óao5²¹´ýø³a ±W¾jç¥ù‰”sjp>—®ZÛ´Ìû‘ϯ=ʧÆ1{8FËó€ºb#è_}~»½ÿ¶J°¶€®}ÙÏÒôâè~澿uP;>^­ãGò-Ãh>zYó[+=ãñ©:‹lÓ›q¹Ì¥¹Æ9¸×ùuFKeÙê|³à6Av‡#9©Rd?ãÏÖF7—öÓºƒÚÛHÚ=¸Ì©¯ÞFì¢éçuí Kwd›½nRÌoã› sù*={Ñ]»9Ñrô;Ú¶K˹ä| ¾¢5è¥#b[Œ8ާG¶Ý»£}/˵õ­-‚¾«Ž  Ûb¤ü´½uà•rö˜¯¥ùŒÁ«s8­AÿìGŸ©¯ûú›kç_ûåúJP³Ôѫթ­9E¹ÇêZ@ç‰Ìmƒ•µ©ßSõÙfïöu„¿× µ—¥\=@_Xƒ¾„¤¼zhiûÎÔh瑞Š.8§¤ÝäÞ0ˆ>BlÈt€K¨²=º~qm qJ§9g-ûÓ|çŽ9NOtý뙃Ÿ-Û^iºæÖ©§nÓ{Þ÷8WŽÔ6Zäë^þFë®§h úZç8:¥ü¾íÒßj®wŸÛOô‰Öµøqz–žœ]’ÿVùZzû7RÒ“ÒN×™Ò›¥tGÖç÷Ô÷¾K®S¹ÇÚë:4t¤÷ °q€ètæLon[ëoÑw/oôäNÿ¯•ŽZuZ+½5ƒ†¹r®Õþj·³yϩӭÏÁ”'‹ïU>9çEí|íu-À%@Ï|::½­ÊåHå|å¼_¹|\ €"FϹˆ¿øós»Ýn·ßý½?T\Ò EûÛl :•é=è¿÷¥ú:²yí‘kí÷êþÕAt€Ü§¶ÿmª;Wc :@ï´ýë?­¾ÈÌçþÞ*P×~¯íÇÿ(:@£À|ï@ö{HÜã“’Ø‹¾€`k¿û{øÑññ¿á*¬A‡D¯n·Û1Þk];­GÊ»2T—p*ރΉóÈßS§Äùô™ŽÝØTG/µÙ~¼Í8=½t8‡éÚ*M­;ÙSuŸzì”4÷Dä´ÏܶQc›çç·‡‡W·‡‡WÅe¸”¯”kÂÑ‚Ð=Ëp­ •\skäëÈç2}æ¥ÛÃQ­A~þðé¿¥NúÖ†ièÅÚM„Ô}íU¶syê¡Þ{)‹HÛ¨µÍ^ç`çäQDέûçÎ=¸kÐ9¹¿øóóQòñ¿A€~âà™ãÔoOígm0'8Ÿ Äjm3,ÃÒ`ŸµÚÏeØâÆKË›;~ ˆæ©‡³Ùl ztÚyJPS+ÀФ+e_‘©¤5Ò›2=v¼Mͼ×*ã¥4GÚϰ<æêcªÌ¶6çÒ’È §O¥÷hÎR™ä´Õµ)õ%×Adyýnq.Ãåé=èï¿V_‡ö¸ËQÇkÍ÷Z{®ý^Ûÿþëƒè™AÆZÇ|)xJÙ&5€~–³þrÜ™¬±65R†KÇXÊW­¼ó»Öá{î8KéIÙçu¼Ÿµ`·f]åßke}–@e\Síc*_jÏK70r®?[Ï5®Y-¯?¹í«s€s¯-_û7œ]Ñô{êJÿI™~œ{3¡÷+e zËiº5nt´ fR‚ǵòó®ºí{ïkLêƒÏTþ@Z_ €s)AßrDrë{ëNfåråJÝ뤗úH™5²6Rz¶àüê>KÀÕô…5è=M³¬Ùù½rÇÿŒ†O½>S9œ58_[Ã<^jq•¶zó8‘#½ýú¨¾Žì›‹ç_ûegUžâ~Ô×må¼¾lœ×=ÞC^£œsö“û½¨Z¯#Û¢GÖOGÖ"o]=ãs¯ûÛòü:[¦äk¼” €íÄFПn·7o³:~kÈZÇ/²Mɱr:Ü­àUz¼ZyOÙOéèfÊìS­F—‚ºqº£Ù[ªó¥çìq3$¥¾Öv˜{MH}ØdÍkBZ>¡¾´.€`_ì £èú=ûØ®]ÿ±pe_üþQô@'oüYê»~K¶©y¬’2ز#<·¿hT+=5ʺVûÉÝOé(häÉã{”aäEiÝÏÝÜÈ=rê'òôõš×„^ʰöµ7š¯ÒvX+_À:¸ü…BØ4@Ïx:œÕ‘‡½^'§¾û/C0̑֠ɼþGË3 ¾üOŸ)$vÐ: ˜Ï<5è/0â÷¿ßÿW N-EïA‡©àI D«v¶Åƒâº¤/ @z Э{ؾ€è)@·î `?úb—à)î÷§²ŸÖ>·´ н>¹¿ÞëO¯Ö#åýŠõ œ˜5è°k }è3Ö±©ljç6²ýx›^߇sÛFm†ï /-Ã¥|¥\Ž\×(Ã#·yz Пn·7o;ßµ‚€ÜôR°w`вsß:ØÙ³Þ{iƒ‘¶Qk›½ÎAí ²Ç'£è4õîgïB†/þø …@ƒ½BÇsÚº~{j?kÁgjp>\×ÚfX†g¹I´WûiyÄ5€žÎqàÞ: ½¯ãF˶ Ð3Ö G§§5µ¬á”éë5ޱ$­•wͼ×*ã¥4GÚÏxyi?kŸÕ ÞKÛë8œJïÑ‚¸¥2Éi«kSêK®?[–m‹6œ”Ñs€KØì=èÏÏV;ÃÎæÜö‘mR¨á~r‚©µ5ð[•áRþ—òU+ïÃï ÿ[KûÚ6SÛ¥Ôõ=ÛÏð³­F‚£éKÏÚvg À¦n2L¦)íyn߹ן-—Ê´hópï~öΨ4—T´½×‡³m)eúñ°#}S#™Kyl1582ƒax3aïú§g­EÊÏÚï6mI:ÝXƒN'¶žZ¾”Ïë©÷¿üåãwþýoþm=ô•@ãHÆ#M½–Ë•GÙîuÒK},MmNY_~ÆàÜh0¸=ß{M<ì /¬Aïá ҹуԫN)?S9œ58_[›=ž`D8=£çt"w„{ëtÔ:î\þÞýìWÿ;I‡}ô@àwÄ×må7‘x! ËÙO«ïlYf%ít‹v>÷¸H‹–m/ï?ÂM‰’²vÀ+Ù*Èã§¶·1ï÷ÿÙ_¨t: ÐgÖ G:ºÑ@$lq¬Ò@­Eg¼ôxµòž²ŸÒ`%å ö)×VæTû\{²üRù¬ÕùÔCÓö Sêk)}%ׄ”eµ¯ ¹å”šfà¬Açâÿ\`>7âmª;çÐì©w/çî+u›šÇ*)ƒ-;ùKaËýl‹|Gƒ°í'w?[Œ$§ÎÂØ¢ #7(Jë~é]ë[¶ßµ<ÓUóš-ÃÒúªÕæ …V#ÙkÇÙê}äãýüá?3µžôŒ÷ ÃY) ju£H}lÌè9iý4÷èÈúvù3Åžt€ŽæÖSÓ€6rGæMiçZzÆt®-c zdêõTP´ôÙÜþÆ£±[wª£é‰æs-Í-ò”À–Žh«¹à¸æ1[–ÑZ]E¦Ë×hó‘ó«$ÍKéÍ]þÐú\^K{êu¬‡s8)£çThçÖ —®s#Ú¥kÜk}_`Î9ôÌ l)É ‡Ÿ G͆ßTXóØsAÅ8=KßOIsí<•Ögnðɤì{iósr$°Þ¢Íç¤9Òæ£7zæÒ;žq±e»¯‘¯Öi€h š€nõи^¾/0çØúÌôÒ”EGRs:Û5óVâ\šS¦‚÷¨ƒÇ’@üö³ÅùUr^¤´ç+/˜í‹E'#­ýšµÔ§©÷¿÷÷áúJ Ö¢sÚrŠsô‰âÄÊpmÊÊô+ò½´³¹.R8N ÞÛ~÷þ>;@_Xƒ^:º6Õ¹·` ºFžzþ\¹5_ã`wË6=¿rê쀆4zþîgïÔpHoßìß·}Q3˜jùª¯£Å9i—ëÖAêõ8•æÚùª¹4bëv5Lëý¿ÞÛ|­cïQï÷´»‰À­Atž#éû(_äajãÎ~k‘õÕsÛn1à ¥œk–sŸ¥>ùºÖÈnO"uiϵÛüÒùU+ÍÑvØc½×ÈÀæ¬A /uø×>Ëy`\Îßjì)O*o•¯Zûȹ!05êÝ[9Ö~ðÙÚÔíÒºˆ<}‹6_:~m»-ωè+÷º®DÓ uôŒ÷ s\G|µÙó®\ˆÑs:P?°ôDt`Jì!qOJ *éãÿ@_ €ŠŽ [÷°}1€K°€O,½Ø5è½Ó =èÖ=ÂÔë»®’Ö#å]û;Vj[@ôÅ.!k ú\gujÍÒ}Û#¬gJÉWÊþ¢ß/)«ÈwS¶YÚ®Æ6Ã÷—¶h¹Õ8ÖÖõØó~Ö´ªÓ©ót­M—\›jä+¥ŽtÍ ®¢5èã÷8Ÿe”éŒùŠäaL}§Ö6{å¿4-FSû;O—êµV½ìÎtzíNô•ˆÁgd4;º©À§Ö6Ãò) žzm¬Uï½í'z¬ÖuÚâFPË›MW¾f\]lŠûWŸßnï¿Íêd;¸kñ¥Ïæö7üNdúu­€x-=kéhÑÙŸ+›ÜÀa8Õwª®ŽX¤Öi¤æ¶ù’ö“ÓÇÛŽ·k}~ÙR¤¶uc :À%l6‚^khØ!›Ò:þlëÑ®aZæÒY=•¯½êaœµõøG|¶À\»ˆ¶±ñˆqÞ[Žxç¤9·|†Ûõ¸ôc®-ö¸Ô¢F}õ\´ÐgÖ=ÝGSsƒµ¹ °$ÈN­.y SI¾Ž*ÒÙO zz*Ô f«›&[´ù’4ç,IèéÆKêƒÏv®b :À%¼,ùòÜ4罃«ßÔ§HŸ±ã¿6­{íéÖ½Ýà¨1Í¿§zšz`Ý•·”5êF˜8‚â÷ —N±ŒN™O+oñʨµ ÕÜæõœ§Œ·,KËhm©…ö×W½±@€^ÌnÙùnõ4å#tê·HçÒàÖ¦g§¼—¼4ˆßªŽ"mlÏW®Õ:ví)÷=×iíóa®NÜ WlŠûãÓíöæmV‡6ÒÁ½OA]ú[/SyçÒ“š÷È~jsŸ¥>Ezœî¹à<º¿^npDÛØRþkµù’ö““žµ:=»–ëíkÔpQOFÑèóÍÚg¹ŒKý[Íu$_‘c¥¾¿¹v™ûÚ³éNy uÍz›[ _«N#ÛÖjóµÚO­º–מuºå5*š¯×°Ò¶ ÀôŒ÷ ÓÞ‘:êµÓ*HQ§Î+àÔŒž\ EG н{`?úbt §Ýº'€ýè‹Ð€žtëžö£/ @z Э{:„‡‡W·‡‡W—Lë‘ò®ýL_ à^ævħ›Ûßð;‘é×µâµô¬¥£E3W6¹Ñp óT]5`J­ÓH;Ímó%í'§Ž·o×úüZK{j9·J3À¦¬A¸„ÍFÐkn ;ÚsÓÎÇŸm=Š7LË\z"ë¡§òµW=Œó±¶ÿˆÏ˜kÑ66¾1Î{Ëïœ4ç–Ïp»VK?jä«uš M€>³îé>šš¬Í…%AÎpjuɃªJòuT‘ &õ&HOe˜œmuÓd‹6_’æœ% GlÓ‡g :À%¼,ùòÜ4罃«ú¥|y.eZ÷ÚS»{»ÁQcšOõ4õÀ:)Wñ{ÐK§ŽF§L§•·xeÔZê!Uóz ÎSFˆ[×5Êhm©'b :€½4˜Ý2èjõ”è#=[¤sépkÓ³SÞK^ÄoUG‘6¶ç+×j»ö”ûÈ÷ÇKH€_‰Mq|ºÝÞ¼Íê¨G:î÷éºKëe*ï\zRóÙOÍ@{î³Ô§cÓ=œG÷×Ë Žh[Ê­6_Ò~rÒ³V§{Ý€(ÍÀ©<>ÍŽ¢¿ûÙ—Ê S?øÜ>þâcå}"¸Xû,÷q©«üEò9V4-5йõà)Ǩ‘î”§k׬·¹µðµê4²m­6_«ýÔªûhyEë´Å¹^ZÇPCJpÐ3ÞƒN{G @j§Uð¥ýœÚÂô/þøµòèÔO~ü.iûŠ öWôtР=èÞ½ °}1:ÐS€nÝÀ~ôÅè@OºuO‡ðððêöððê’i=RÞ•³ó ™¾À%¼ÌíøNy~þ0»íÔßzìÐG󕲿è÷KÊ*òÝ”m–¶«±Íóó‡OTiÛXÊ×ÔßrÊùHíøÈå\³.jä=%Gm#À¹Œ¯y5®ÿ-ú\ã4¶N÷Zz¢åú÷µmç>›JçÔçS}ÛáßrûœkÇm™8›¢5èÏÏ>ý·àÍóÉÃ8À˜úN­m€­A¯ñÛ>ìoåÈ[õÿ¢ù«•ε@|¼Ý8sŸ?ï?%ŸKÁyJz–Ò”“¸n€^ábwE­ò¾6r—œO×µ¶ÿ¨•\ŒZÆ;W,ç–7‰®|­ú2wÍ»Ï*ÿnƒªµí‡Ûmum]:æÔ¿çò5·¯ÜôÌ•O$ý9ÁùÚoJipGÒ4÷÷èï£ ¢SÜ¿úüv{ÿmÑCÉ´Ø¥ànüÈôë-~ø–Ò[8× ÞK7ž2OIGIÔü¼¤¬JêÅo9üJ•§¸·~V'rö˜¯žÒ¹ô¸µ% Ñà¼æ’†µõg[,£È)ïÔ2¬Q¯{çyËó}-]‘¼Ï=€x@±ôǧÛíÍÛ¬  ÒQ^º;aßû‡a.=©yì§f =÷YêÓ¨×f<,–½ÔYÍéo%ÓÃÖ¦¨-Me;jgn­Íçœï-FÒSžâni°‰Ç§¤'¹pæ}¢C¼öYéÔ¢Ô}Õ ºr?ËIKíiM)¹S«¶¬«ÚAL$@+.Wk›œô”´ËVå\sÊaÎùU’÷מÓ/ ÿJÆ{ÐiïÊO³ì(gm85£çtŽcí}Ø5s»•Ý =úC>#K—ž•âF20¥è=è4ÐQ_,ò ²#×¥e0,‡¹Ïïy­÷µWÐ8Tð9õËñƒ8‡Û.=èuímsû¯uܹíS÷¿T>%zyM0p|Ö ô.a úðí8KÓ°‡Ó¯§þ$øŸ{0íðøSŸç¼K}*KSúçþ÷¸—Ü8¸å:‡±ôv‹È¶‘à?ºÿÜc-}wéu—kÛï ÊkÐzWدNýn­ýÏíkêóèôœµÝµ×Χä `‰t€“K} ÛpûÈwç¶Yšf?>FãFôñÝj”çTúÇéçň: [ƒ~5^yrÔ´ö’÷Zé¨õ:€“®A_šÊ=õÝ~m?9ŸGÒ4 |s÷1\—þ&¦ä×ï/P7@sŸ#µ.ª©y/)«ÈwS¶YÚni›¥;ÝSwÍkü@¦æk­­Nm³G¾jœ7Kï_Ý¢é|àºüN½*Zƒ>^ïs–u6gÌWtýØZP·¶ÍxX?€Ã4Ï¥;²M¯ùà<@€^3ؽ¢Vy_µÌ Χ‚ÔÈ6)ik1º;÷˜©Ññ¥mRë½4_Ú<\ÏfkÐS¦¯Kkëqç&²U MÏZ:Zp)Z‰_ÃéÛ9Á1íÚáÖÇKmó­ÏS€SIx:ǵÙz­‘´ñÔã©ÑÉñg[`NMq§g-ïsùÚ«ÆùX[_cÔþ¨Añý¿½­µÃ-—Óæ‡exÆ¥1½üN•üGgÝmyíNý­]ÚÞëÏ€sè3ëžÆÄÔ s.(, V‡Ó¯KîV’¯£Ê™²¾ÈŸ1³ö¼^; AGkÐsÞsžÒþÖ®íoi{Á9pDEïALs®¥åÅt-_g¾°/M[ž{WéÒËk?Õ bAîÒhúÚòÂ¥í×~—jþæ— ¶Ì•Aeûè kÐK°á÷—.Ä­ƒ»¹|E×ÈC‹à\;¸ˆ„5èÃ÷|ÏÍÿÏ=vjûèq·úÝoî¹&½ô'RUYƒÞz*s«5ÀG™¢½E:çžl>üÛ\¸ôä÷µcÔÎû\§cé¥mìˆK#zZ[@½¾AÉwr~¶~¦ÎÔóPR¦Äô.6‚þøt»½y›¤D‚–¥;®ãö­"?k?V‘¼GöS3Оû,õIÜk3¦òµw IS4Ý­Ÿœ^Ò·nK)Ë!(ôø´ù“Ükôµj ["ЃÁÁÚg¹ŒKý[Í )’¯È±¢i©ùƒ37%?åµÒ²N­V½EÖÂoÝ·L×n*¤v¶ö<ÿrÎ%êöÆ×ßñsw"¯Ä\š6_T§¾Šsnû¹Ù|ÑY~}èïAgŸß«¦µ—¼ïýP0ÀIGÏ—næFnb§n?,—þöÔä±8ªŠ€À-ôŽÞ½ p9úbt ¤5èÿäÿþ]%P,±OµñÜèƒt€“¾»¼Æ«8×^× ÀºuOûIè‹=?øô_i0½ÅkC( Ð8´©‘õá»ËÇAôÜgS›ÛnüjèÖ=—ÿàon_þƒ¿¹dZ{Éû‘ê€Iè‹ ññ{ͧFÖïÛ?_z¿ø}ûˆáwXö2çKsÈëÿò[³ÛNý­Ç 1š¯”ýE¿_RV‘ï¦l³´ÝÒ6KÁépÛ×ÿå·>³¥m#5_kmuj›–ùJiG:¿hãhâ¹ìq_jê8‚s€˜¢5è¯ÿËo}úo-ˆ9’3æ+’‡q°7õµm†e7,Ãò¾T§‘mzÍø< ¥QòšÁòý÷ãMÝXº9@N€^!ؽ¢Vy_EÍ Î§‚ÔÈ6)i«q$š÷ñ(÷ÔèøÒ6©õ^š/祆Aú0€ŽËskÇç‚ñ¹àßt€¸¤÷ çNã e-xZúlnÃïD¦h× ˆ×Ò³–ŽÜ\ÙäƒÃéÛ9Á1uΡÔó«ÅyÀ†‚kÐÇòÚôõ¥Ñô”¿ÍœzÓÜÖm6‚^kdo<õxjtrüÙÖ#˜SSœÇéYËû\¾öª‡q>ÖÖã×µ?jÐÜêAp¥ml˜æ3.E ãú¥”è3ëžÆÁJj9–«Ãé×%é*É×QåLY_ äÏqí¹s€H\ƒ¾W^{;€=³ã¿uÐzär)_ôœm4r)ÍYƒnÔ f€¾°î©4‹N™nýôìèÓ¾N›Kx:gÐ3ƒÙ­´Iï}ôw‹tÎ=Ù|ø·¹ú-=ù}íµó>÷4ú¥g”¶±è{ÙÏ8€}Ÿ”yrº§«ô#ö÷ǧÛíÍÛ¬ %´ÜŸ2½ô·è“Ñ[ÃkU$ï‘ýÔ ´ç>K}2ø8Ýãm¦òµ÷,ƒHš¢é^{‚ÿ–u·TWž˜prO]¢{*;À6¾÷öÍÛ_Þn·Ûë}ñGáË7ooó¿|©Ä:v¤ ­vZ{É»@€ˆ¿ú¿{û¯?ÿ"´íO~üîöÅŸýú—¿~îüú;óíö·OMÒÑò©Ï†ŸÏm¿ô9Ó×ðÛívûâ~¸¸Ý»?ùæv»møtÚ»ò“Å{É»À€M$ŒžO½w|îßsï(_ú¾÷šlç¥"8—{]béû‚s€m½€2úb9AôxúúÜ»Í=X`FÐNn<¢> ¸‡OcŸÚþþ¹iî{è¿^ƒþïþ·¿Pb…~òÞ¥}!¸}0ñè÷–¶·`;/)ç{èÖ ìG_ @€ô '¼{“ý<<¼:ÌSUk§õHy×&H¦/p YOqŸëðO­G?´÷`&š¯”ýE¿_RV‘ï¦l³´ÝÒ6Ñw¦Þ0Sã!3KùšJÏZ¾¶LÏVmuíA>%園Ÿ#ïgù-î§Æõ|î·á¨}Ä{zç>?ñ~mû¹~ÊÚSô£ÇM­çœz™úÎ\j>`ðJõRcÛ¥íZÔ1EkÐÇïÆ<ËHÝóÉÃøâ:õµmÆïLíå„î­>KG¶{*[®A¿w¦ïÿõð›·t¹‡þOJÆW´œç¶þžÛÇÇŒ·4°K­—aš"å]³]^©^rαZel6fz¥ÀèjZå}íNgNp>ÌF¶II[€9õ.ïÚÑõÕ[›oyc€þú"ÃßÌñ âá;ÍK>ŸÛîo{ã¿Ó²¼#õ[95+a« 0R¿ã>ÇÜö­ƒ¾£×K¤ý/Õ×Úwz«¯«KzzNà´Ôàç¦ÃÌ}¶ôƒ3Õx¶ ¢éYKG‹†>W6%·û…#zc ÷€­´¾–f¬ícmÚß?[”SêùÞâ<8•Â5èkS|§F #S^‡}‚Ü©¼%é\ ¶ö˜ž;uÜ¿}[æu®^Æ7A†ƒ8½M>z½Ì S}ü¹e 9ç;½èwŽjÜE ¦æ8ت¡MSãô¬å=z#¢vZSƒï¥íö¾ùв­ÎMퟚò”rg9åÆÕÞεs0Zïã?}üæl¿U@=îZ€Õ㌶­‚é­ƒ¬¥‘Õ#ÿŽ¥^jwú\ý+Zƒ>ž6‘{Ÿ»ûVÒèJ¦Ú–æë訜@uj_g{6ût¸e¿½ÖopëéÈ)ϲYZû[k ¨×ò›šÁ=VêìÊ’g ­ðŽûàê¥Þ¬×œ}Eë‹m¼¬Qù-:Ý{­S‰>üŒÁÓÚtìÈL…­g3œ™”ôa¦~³§~ïkôó–ö?·öwêóÔtF–_•ôAæÊ 59åŸ[>)#¶sËJëe©ìÖÒV²ï3×KJzÖúô5닽ô…5è¥XtÊô^ë‡"¯žH]§ÃÓrí´‹!ßé‹þ~,=°5÷ß¹Ç-Mg4=µ§—”E­ísê1%µê15_µž\~ÆzIMã\Yæœßú£íUyŠ{ë©Ì5žÚc¾zJgdõÒZé¥ýDþ¶UÞs9~íFÍ‹U¤=—´ùHžk=yzì#¡®®V–þ²=–ØúãÓíöæmVP –îpN\îyÏ¥'5ï‘ýÔ ´ç>K}÷ÚŒ‡=FšSËaí‰é)õ•²$ Z޵µU[Ú;=—òøTü$wÀ Π*¼ô©™5Ö¢lÑs¦z¤¾“»öƒÜ§<ÖJwÊz™Zõ6w‡°VÛ‰¾M U›Oy—féþj•¡iSP#@Ïx:í)ØÙâ(€Ó2z @þ6Ðíi©p>EïA‡«é%ï€lúbt §Ýº'€ýè‹Ð€žtëžö£/ @z Э{:„©×€]%­GÊ;×lÚ(PD_ à²Þƒ>×ÉœzíÔ}Û#¼’*%_)û‹~¿¤¬"ßMÙfi»È6kǾW¼´mÔÊWJÛ8Ò+ÖJóÞZ«¶1u¾¯µ¡’k\|¥\#ŽtíàWŠÖ ß}–Ñ¡3æ+’‡q‡~ê;‘mRŽÙ2ï%õyÔ÷ž×ÈûÙEÎõûçÊØ5èôÚß+wü[a5‚ó©€%²MÊ1kѼGÒ|6GÎ{‹¶±Å1{8†k/ÀqŦ¸õùíöþÛ¬Îñ¸cºÖ^úlnÃï´˜ÎMÏZ:ZtÒçÊ&·Ã?œ¢;Õ<æ–ARJÖjKõžÒæ[å}©þ"ùÊÙ†²ëkêµ÷hK ಬA¸„ÍFÐkÞ ;’sSQÇŸm=J5LË\zRÖfo9ÒÝ÷8kAd$8?’µ:­µŸq½ÏFµÒS+ïSi]ÊWî6=½kmº‡ô–^†y;ã2%€sè3ëžî£©¹AÙ\PXÜ §ó–<ˆ©$_G•²®ü¨úqÝ^Iyïavô\?c›1bb :À%¼,ùòÒ4ç-:Ñ-;­©O>c‡}œÏ©5ÍsO¥žúnÁÀÜ´ûZuÚÛ~Zæ}m_ÃöÒS˜²FÝ3ûè kÐK_4î´Ïí£u'~._Ñ5òWuÄ)ïµê4²Ÿ© 5Rf[µ±ÚÇŠ¼jl|ü^nÞDʧæ+à’Xƒp UÖ ·žîÜjšîQ¦qo‘ΩÀ­ö’„šK¢kæ÷¾aÐêÙ=ä}|ž¦œ·-ÚFÿR¹¹ñp=±ôǧÛíÍÛ¬Žh¤cz•Zú[/ÓbçÒ“š÷È~jsŸ¥>ý9:ã¡·KinY§‘ö\³mÔÈ{äœ+É×YF¢[>¡>å)îW{–œÖã“Qtz¼£>Õñ/Ýgʾ¶zUô³œ´Ôì0ÏM½M9Æ鎾Ÿ|‹¼×¬³Ze37¥¼¤ÞJÓ”sîåœÑmZµÜôæ^ë¢ùjq-Ì­?zÐ3ÞƒN{Gê`×N«àB;î½mh£@£çt ~væiÞ@¾¢÷ yAúø?Ðà…"€£èÖ=ìG_ @€ô [÷°}1:ÐS€nÝÓ!L½¾ë*i=RÞQ—ÉôÅ.!ë=èsç©×EÝ·=«¤Rò•²¿è÷KÊ*òÝ”m–¶‹l³vÌáûÀKÛF­|¥´#½­4ï­Õh)çÒ‘®Qœ[Ñôñ{œÏ2êuÆ|Eò0T¦¾Ù&å˜-ó^RŸG}_y¼ÐkÐè5ƒÝ+j•÷µÀœà|* ‹l“rÌAc4ï‘4ŸÍ‘óÞ2­W¾FЗØ÷¯>¿ÝÞ›Œ;ÜkÁÕÒgsû~§ÅtÞhzÖÒÑ"ø˜+›Ü@f8õx.8®yÌ-ƒ¿”:­Õ6–ê=¥Í·ÊûRýEò•³Í–çjêyÚúÚ°Øàô6A¯5*5ì ÏM;¶õèÛ0-séIY›½å^tßã|¬‘‘àüHÖê´Ö~Æõ>ðÕJO­¼O¥u)_¹Ûl™·œót˜ö3.çàˆú̺§ûhjnP6–wÃé¼%˜*É×Q¥¬+?j 2®Û+é1ïG™^nÄØ5è—ð²äËKÓœ·.ZvÆ—òuæàni ðÔšæ¹§mO}·‡ gnÚ}­:ím?-󾶯a{ü@n€¾°½ô•HãNûÜ>Zwâçò]#UGœò^«N#û™ R#e¶U«}¬µzžÊk/7oºf :À%TYƒÞzºs«iºG™Æ½E:§·ÚKj.iˆ®™ßû†A«gô÷ñyšrÞFßmÕå œSlýñév{ó6+‰t¸ï£ŠKëeZì\zRóÙOÍ€pî³Ô§ZGg<ôvc)Í-ë4Òžk¶yœs%ùêå)îW{æp0OFÑèñŽúTÇ¿tŸ)ûÚêTÑÏrÒR3˜›’ŸrŒ-Ò}?ùy¯YgµÊfnJyI½•¦)çÜË9/¢ÛDÛF‹kFn>`»=ã=è´w¤À¡vZMÚ1À©= õƒOO2¦½È ÒÇÿ€¾/%@·î `?úbt §Ýº'€ýè‹Ð€žtëžaêõ]WIë‘ò®mL_ à²Þƒ>×QŸz]Ô}Û#¼J*%_)û‹~¿¤¬"ßMÙfi»È6kǾ¼´m¬åkª^½Ú,MúJißGºn@-EkÐÇïq>ËÛóÉÃ8(šúNd›”c¶Ê÷YÛ*a :€½f°{E­òž3‚¼¶©@6²MÊ1kË9#­Wn“¥í¹´¾ÔÌ‹MqÿêóÛíý·YÓ¸s¿\-}6·¿áwR¦_—…kéYKG‹@g®lrƒ¦á4ç¹à¸æ1[ˆ´Ãè4ùZm5²ÜbéXKå9Ö–ÁñÒù‘zÝhq¾tÁt€KØl½ÖXdŠòø³­Gú†i™KOÊÚì-G £ûçc-@Œç=¦wø_òï§V[ïg.]k‡ãïDŽÕb”¼ôܦݲ® Ï¬{<©AÙ\PXÜ §_—<̪$_G•²®üHAQ$Ý¢¬Z´Õ+SfÀ¥Xƒp /K¾¼4͹¶–àZ¾ÎA;:ã¡§›kí'¥.–FµkµÕÚi^:þçWÊSܯ8`¶/f@€íðO+¥ûLÙW|$_‘cEÓR3蘛’Ÿú~ðÚé^{Å\­z[ZfQ³ýÔ¨û”'ü?K©Û”¥"‘4Gë«Åyœ›8G€žñtÚ;RR;­4m àÔŒžÐ}‚áž–um½®4· Çïnœ\œ¾€è)@·î `?úbt §Ýº'€ýè‹Ð€žtëžaêÕ\¨N@_ à²Þƒ>€L½ ê¾í^•’¯”ýE¿_RVKßÊ×Ü1jÕ×Y÷³føóíæHç°¬h úøÍg9<{¾Î”'¸kÐ.áåÖ¸òÈ^«¼§Ž¢.òÖJóY÷SZ¾Î/ ,@ÿêóÛíý·YAãR 1X.}6·¿áw†Ûn¼DÓ³–ŽžF±KÓ<72Ÿ[ï%éÉ©‹ñ¶ãíZ·±µ´§–s«4°kÐ.a³§¸§S×R–¦?Ûz÷0-séYËû\¾ö’“æ©€¯V^JÊ0µ.RÚÎ}T¼ÅRùjf`ë}fÝÓ}oÆC^Ý¿[(–æ‹öõ^rƒ`|ü¥@öˆmAû8kÐ.¡h úpêìÖA@ËQ¿µ|ì'ðœz­™€8¢â÷ —N››ž>µÝÔÔò-ƒ¿©|õ65½u@|/ƒÒ3Ñzìç¬OÝ€H_ €«è™ÁìV¦FM[é=ÎÑòË Š{»9Q«Ôžrùþx@lŠûãÓíöæmV ZîS•—þÖË4æ¹ô¤æ=²Ÿ-Ú¹ò+IóÒÓÅsë½uzÆûêafD­ràŸŒ¢ÐçƒÔµÏr—ú·š{$_‘c¥¼|‹9u‘ó¤óûgÃcÖª÷Ze˜’žÔ6}…Ü^í=§í½èïA§=Á—:ऌžÐa|zj:À6ŠÞƒÎ5ƒô–OÓôÅè@gºuOûÑ =èÖ=ìG_ @€´á=è'rýÙYž¬~¶üÀÝ~ç·w?û2¼íí~¨ÐèËÓØT u¤ +%_[˜%eùî0G¨á{×[Ô´ôÙ7ÿ9´Ý×?ü‡ à"ŠÖ ß…=àÍó5>ÏRWp Ö Ðk»WÔ*ïk#¿ã¿)Ho™Ö+·U`›­ATÑéïKŸÍíoøÓ¸£éYKÇžòR}””s­:ݺÎRë«uà~üÍ׋ÿù?ûÛ¾ôÒ°4 î†ë’‡k•ÇÿÞ"€ïs*=ky­­DÊyøù0©åœr¬-ê,§¾jå&pèO·Û›·³Ö\à š†AN‡tƒ®’`57_½+nqÓ£W‚qj  ?>E ÇìKËÑåµ|ýkãiÚ­ó6žñ øઌ  /¬A/N>5=}n»=‚Øq¾z›š¾E¾÷8Žéâ\‘5è¤è™ÁìVZÚ·Î×VéÌ]J°U9×~7¹‡¶pTFÐHÐgÖ G«H uׂËñç{Ã%yìgËt˯V9GòµG¦<Å½Õ ³@€¾`­}–Øåü­fpÉWäXÑ´Ô #£ý¥é®U>Ñm¢r‹¶“›O˜óõÿ¡B #@Ïx:í-`pVññö_þEhÛŸüøÑs€‹x¡à(úã“’Ø‹¾€è)@·î `?úbt §Ýº'€ýè‹Ð€žtëžáááÕíáá•‚8Hù©¾´-€é‹\ÂËÜÎú”çç³ÛNý­Ç $š¯”ýE¿_RVÑïŽóØc½Ìåeï¶ôüüáS Zš†¥¼Lým«¼G÷[#ï)y8Òuj)ZƒþüüáÓKîÑœ5_ã€Gða :€½f°{E­ò~¶ÑÆ©#½ä±ÆM›£ÖWËVW¾np]±)î_}~»½ÿ6+wîו¥Ïæö7üÎpÛ­:øÑô¬¥£Ç‘ù¥ò‹–óZùD´ñºçÈ”÷#´ŸVí0§.ZÜZ–Íå+ºÆ¹Ç@®eö2ºyÄúÚ#_5_!À¬A¸„*kÐ[¯]Z—»EÙ{@W#[,7h]_{ÆGjWkkÚ—ÒÉûÚºy`^lýñév{ó6+‰tîï£wK‹>½E0¼€DòÙÏ–iŽ”u[ÖW¤ [–soí0§.ZŒ¤§<ÅýJÏXí‹E Ïuâ×>Ë}`\êßj€‘|EŽMKí‡-V5ÒT«|jµ‹Zm#š‡šÁâR}Õ,çÖyoqoÝæ ï=ã=è´'H9Vùzb:aFÏ.á…"€£èÞ½ °}1:ÐS€nÝÀ~ôÅè@OºuOûÑ =èÖ=ÂÃëÛÃÃ+¡|8}1€Kx™¨Ly~þ0»íÔßz À¢ùJÙ_ôû%eýî8=ÖË\^önKÏÏ>é-ÚđΠ\ÑôççŸþ[ pæ¬ù{?8kÐè5ƒÝ+j•÷³´NÝé%-oÚ\ùÜ€+ŠMqÿêóÛíý·YAã8°Y ,—>›Ûßð;Ãm· n¢éYKG#óKå-çµò‰§ã5ß‘)ïGh?km$õÜi•fvd :À%l6‚^kôoˆÌM;¶õ(ç0-s鉮劉à|­üîk°×FºK— ÔšŽ¿V_‘|mÙ†rÚÏizÐgÖ=ÝG8s§ƒŠÓ˜ïß- zKóuDã¼.|g-#æËˆ9ÀEXƒp /K¾<œ^»u Ðrdp-_F)ûª¯#¥ ,@_Xƒ^úê©ñZã¹}´)œËWtsÁrË2ìed÷ˆõ“}1N¯ÊôÖë_ÇÛ:Èì= «‘Î-–´®¯½þ¹üº¤ˆ ?>ÝnoÞf2‘Àæ>Z½ô·è“Ñ[ÃkÁW$ï‘ýl™æHYט±e}Eʰe9—œK#üWz }1£èô¹ gí³ÜÆ¥þ­fÉWäXÑ´Ô ¸Ö–ÔHS­ò©Õ.jµh¢r‹¶¼u¹½èïA§=šòऌž\ EG н{`?úbt §Ýº'€ýè‹Ð€žtëžö£/ @z Э{:„‡‡W·‡‡W B¹p6úb—ð27à™òüüavÛ©¿õÈE󕲿è÷KÊjé»Sù*9Fi¹´öüüáSÞ¢.Ôæ€~­A~þðé¿¥÷hΞ¯Ü< ¿4d :€½vPx5­òž:b{¶½åÙ GlŠûWŸßnï¿Í ÇÒZ`¹ôÙÜþ†ßn»UMÏZ:z KË/R§Ñz_KOÊ~¶ªûÔzoÝV8 kÐ.a³ôZ£ˆÃ€fnŠö\à·U—¯–AøZÀ»÷ „µôŒ?o±ö»´Þ‡y;ã2 `ë}fÝÓýÁ[¹ÑÖý»%Aoi¾zµ”§ñç¹c¤N#ÛDÓ³4*ß3#æ$±à^–|y8Mw뀣åãZ¾Ž:ÚyÖ ð^_‚^àȊ߃^:E7::žV¾u06—¯=§¦Ÿ-¨ŽÔ{Äx$NÇtzi0»•áTí=‚ôÞƒÝû( œkßÑôD×ÍGÒ2^ÚÐ_€ž±îiè,>ãuÆsZëÂçÒ“š÷È~öô§‚áh¦oiÖDJpÞâ†ÊR;¬]>PÒàx²Ö /ÒKÛ¤î3e_5öH¾"ÇJ}y­àú–ÔEi=Ô.«ÔôD_ç·WÌiOÀ5¯A§=¬‰ïqÄØ³8<}1:äÃg{=@?ºuO$é‚s¨H_ @€ô [÷°}1:ÐS€nÝÀ~ôÅè@OºuO‡ðððªË÷ËÒ¸„—¹Ó”©WkéØ)ùJÙ_ôû%eµôÝZùФ¯f}ßß©þððªIx;°§¢5è÷÷]ßš³ŒvÊÐkÐ.áåÖ¸òhd«¼Ÿyä·Æ(º¶ œ'@ÿêóÛíý·YAãRð3X.}6·¿áw†ÛnpEÓ³–ŽG°#å—R·kõÕê&C$=ѶڢÀoôÅ8½Ížâ>œJ]#°Zšž=þlë)Üô̥g-ïsùê!8_+¿ÈTùÞ¦Ó—Ö×°Œ,ö ÐgÖ=ݧçŽ~Žƒœ£¨÷ï–½¥ùêÕR¾ÆŸm€nQï-}hÎt€K(Zƒ>œî»uàÒr¤r-_G5mY_¤)~zéHëÜôô©í¦¦–oÌNå«Ç©é5òtÌtz¯Aßpš¶`6=‘uü[´GoÌDß½ÞªMl%6Åýñév{ó69ˆŽZ÷©×K‹>½E0¼ FòÙÏÞyÛê)î{HyŠ»etçñÉ(:€}>[û,÷q©«Fò9V4-5À¥÷…§äaz(=o•æœv¢x :ý8Êšø”©ø‚`РÃF¿ÝÞ›`›µÀré³¹ý ¿ÓbJt4=kéèiDxœ–¹ ϺXjC©Atj¾¶.ïÔöӺͰ3kÐ.a³ôZ£‘éÙã϶å¦e.=kyŸË×Vé½søßR}Í¥)’÷žêb´Nm“²`‹tç´ŸaÚϸÌèsfÖ=ƒ½Ô sTÔx(ÖpJtɃ¼JòÕ£H »Õ7 æn,\s€‹°à^–|y8½vë@¡e`¶–¯+‰{å}<•{‹ôþ€þô…5襯ž~)Ðo=R8—¯èù3ç½ä½vzŒFÐ-kÐ.¡ÊôÖë_[Mu>ʺ޵tæ–מSÊ·XþP#ï‘t˜Ž䈠?>ÝnoÞ&8ÑÀæ>Z½ô·è“Ñ[ŽkÁW$ï‘ýlæHyï•æµ´¤¦g©½ìÑÆRžâ~¦g!éñÉ(:€=ìLO¥ûLÙ×V¯ñŠ~–“–š×ÚRƒÔw¤ï]5Ê:e¹D$ÍÑ@¹Eù•Ö1pÔ=ã=è´'@S¾œ”Ñs€Kx¡à(ºwoìG_ @€ô [÷°}1:ÐS€nÝÀ~ôÅè@OºuO‡ðððêöððJAl\.½”óYó¥­è‹\ÕËÜÎñ”çç³ÛNý­ÇN4_)û‹~¿¤¬–¾;õ·œc©.ÇõwèJÓ)çhÛ™KO´œ[ç«´ýÔlc5òž’‡£¶}Ž¥h úóó‡Oÿ-¸GsÖ|Ѷý,µûçÚ%}1® W V®¨mÉè^¬.JâÔrnqƒg|©N]ÇèIlŠûWŸßnï¿Íêô;ÓkÁÒgsû~g¸íVêhzÖÒÑÓèiN®ÕßÚ~æþ>0Ž?o]ï”ÑmZß,í§f]EÓ¼çM­òÞ:?Kg[;/"çrëà?o]ïg¶ÔfSÏeu°kÐ.a³ôZ£mÃŽÿÜÔá©€mËx˜–¹ô¬å}._=j)S´—n>,í§f]EÓ¼çM­ò¾E›ÎiϽל'@ŸY÷t@Uîëq'¾ÆTíûwK‚ÞÒ|Y­‡…¥Œ¼/s‘'•÷V?ѶsÆàÕˆ9ÀF¬A¸„—%_NgݺcÞ2˜YË—QAj©ãéàÀµ¿½t*ëÜôô©í¦¦–od-M;êC³L_Η2{"}1® w°E¦=_)]Kç–K rÊ&šžá¾Kë`ï<· ø—Î7à zƺ§q@° ŒGç‚¢Ö…Ï¥'5ï‘ýlÄ×(¿šAú0=ãÿ?÷·³¶­ÛÈÒù•r.°kÐ.!k úR Hå>p¬fàÉWäX©ïÉ®€ß§¥eµë4g›œô”ÔMí›såœÛNsÏh¾Zœ[9ç  g¼öDmÊ¥—rVßb :À%¼Pp”ݺ'€ýè‹Ð€žtëžö£/ @z Э{ؾ€è)@·î‰‘‡‡W·‡‡W—Lë‘ò®Mœ„¾À%¼ÌíˆOy~þ0»íÔßz 0¢ùJÙ_ôû9eIóùJÙfi»¥m–‚Áá¶ÏÏ>¥íp)_SéYË×–éÙ꼘;VrNÉÏ‘®-Q´ýùùçÿÖ¦#9R¾†éœúwt›7:–‚«©ïD¶××ÖyK­“ÚNéÈve pyÖ з ¯äŒy_µÌ Χ‚ÙÈ6©uQ0§ŽØ.³VÛè­µ¼1áÆg›âþÕç·Ûûo³‚™qÇ}-àYúlnÃïD¦M× R×Ò³–޳­×«‡Üàk8]ú,Ó™KÛÆ\™r?W†)Só{(§ÔkK‹kÀæ¬A¸„ÍFÐkn ;ÚsS‡ÇŸm=Š75zœžµ¼ÏåëÈ¢ù—Y4] fò€²œ¶1\FöYÚ9¿ö,§Üók˜¿3.ÃàÊú̺§q`”dÎj%ÁêpJtɃªJòEzݯªSÛ®Ý(ç.pÖ \ÂË’/·œzÜ2ðZË— °~ð´6;ò„ðšOk¿mŽ /¬A/ Іß_ ô[\sùŠ®‘‡m¯UûwC sÖ \B•5è­§·ZolÚt›2™ºéYþ0n‘Y5–ODóž{Ì-ŸO9wJίHžôÌh)6‚þøt»½y›ÕQtÜï#†K‹>ýºE€º\DòÙO­rN©‹ši–ú$îµÙ{Œ4§–ÃÚÓSÚFn.•cícmÕ–öNÀ¢ÐçƒÔµÏr—ú·šY$_‘c¥¾'»vš·8Î\À7÷”ñZiªQÖ5¸¥%µêbi¶Àø½ð-ί”'¦—î¯V朷pŒ=ã=èœÛ‘‚-nP \š2z @ö t{ZÖ´Qôt`» }ê=ï\”¾€è)@·î `?úbt §Ýº'€ýè‹Ð€žtëž™z ØUÒz¤¼kǪSm 趬÷ Ïu §^ußö¯‰JÉWÊþ¢ßÏ)«Hš÷ÈWÊ6KÛÕØfø^ñÒv­£ÇÚªÍa?kZÕéÔ¹³Ö¦K®ƒ5ò•RGº>\AÑôñ;šÏ2òs¤|ß‘=õÎìÈ6-nt,Sß©µMk÷4”¦ÅhjŸçÙ\Ôªw€”¾W Ð+WíÔŸÅÚˆ[Np>øÔÚfX¥ÁS£µÚXoû‰«u¶¸ÔòfÓ•¯Ï=ŠMqÿêóÛíý·Yßq§s­s¼ôÙÜþ†ß‰L‰®¤®¥g-gi›«‡ÜÀa8Õwª]D¶é¹œ¢í'rNäž_%m5§Í·o×ú\>³¥:Im?ê:` :À%l6‚^kdfØIœ›f:þlë¨aZæÒY£<•¯#‹æc\fkkä—ïÈ6{ݤX ¶£í'²laË:ËIsnù ·ëq™É\;ëq©Eúê¹.® Ï¬{º^æGsZIà1œî\ò¥’|‘^÷¹Á\Qj:¶ºA³ÅùU’æœ% ½ˆ^μºþA'¬A¸„—%_n9­¸eÇw-_FêwüצuO=Ý:²Ížy;ÓC§Xw¥À-eºë¹Šßƒ^:r¢<žVÞâ5Nk£,±vS¡äÜØ¢ç¶×µe꽯zNÈtzi0»e‡¸ÕŽu´·/“¹À ÿ–»ÍÒ1zi‘ö¼ç+×j»ö”ûžë´öù0W'®Mç›âþøt»½y›ÕÉŒt:ïÓB—þÖËôÚ¹ô¤æ=²ŸZåœR5Ó2þ,õ)Òã2Êݦ·Ñö¼”·ZçWI[ÍIÏÑêk«à»Åµ¬F}y|2Š @Ÿ2Ö>Ë}`\êßjvr#ùŠ+õʵӼu0·Ö;å85Ë(å)ä[å½fû‰l[ëüªUµê>Z^{Öé–×Ãh¾Z\/KÛ.[èïAçÜŽÔQßâêôêçИÑs€Kx¡à(ºwoìG_ @€ô [÷°}1:ÐS€nÝÀ~ôÅè@OºuOŒ<<¼º=<¼ºdZ”wíà$ôÅ.áençxÊóó‡Ùm§þÖc§?š¯”ýE¿ŸSV‘4”m–¶«±Íóó‡O]i;ŒÖQcmÕfްŸ55ê4%­GºŽp\EkПŸ?|úo)<š#åk˜Î©G·iq£c)à™úN­mZ»§¡4-F‰Xë‹pŽby%gÌûÚHbNp>\×ÚfX¥As£¨µÚXoû‰«´N]ÇèIlŠûWŸßnï¿Í fÆéµ€gé³¹ý ¿™]+H]KÏZ:Î6::W¹Ñp óT»ˆlÓs9EÛOäœÈ=¿JÚjN›o;Þ®õ¹¼–öÔrn•fà‚¬A¸„ÍFÐk8 ;¿sÓÎÇŸm=²6LË\z"k”§òudÑ|ŒËlmüRàÙf¯›kÁv´ýD–-lYg9iÎ-Ÿáv­–™ÔÈWë4på}fÝÓ}ô278š ÔJátç’‡G•ä‹ôºÏ æz\ƒžšŽ­nÐlq~•¤9gIÂÛ4À&¬A §tH·îœŽƒæVí¹)­-Ósæ }.Ы½]°V'Ð×î`ï}aÝSiP¢<žVÞâ5NSù:ãÔtêèñ†A­%kË:ؘ5èôÒ`vË@¨åHº@dÛ2™{Üðo¹Û,£—öiÏ{ŽZ×:ví)÷‘ïñàHbOq|ºÝÞ¼Íꇠf¥<…|«¼×l?‘mk_µê¡VÝGË+Z§-®+¥u izÆ{Ð9·# [Ü @ûhÊè9À%¼Pp”Ý»7ö£/ @z Э{ؾÀ%¼Tmýàw~p{÷³/ÃÛ @ÿ[ïA`Þü:´Ý»Ÿ}é=èa :&@wÇ`?úb—` :ÀN~þÃÏÿþão¾VHâ=è;Y À¿ó7}1:íƒt#çôyÖ=4 Ò'ƒs}1€K° ³ €k² wúb—`à >þâãí'?~§ . õùíöþ[?üàw~p{÷³/ã_˜XƒþúGß¿½û…²èÝðÃÊúãÓíõðÇá>ÍÊ¿ýÛ¿ýÛ¿ýÛ¿ýÛ¿Ûü»°Ó@ÿ¾÷öÍÛ_Þn¿º ´õîO¾¹ÝnÞƒ] € € @G^–îàÕýfÞ×yßöÃÂû<{2NïÒß{•á±Ò3>¿§ÒÙ¦ö9¸vÍY».M•iN9GöS{›H¾–¶‹–ážmùh¿ÝèS¿WO‡ïX±ƒXšfâóç¥ß_ ê¢ÛÔNû8(^sæ‚Ý©ëÒý³ÚißBÊÂH}GÊg‹út˜W}ŠûRgýÃWŸët]é)8?ÂùØÎËI™&;ÍZ›R»EÀ¿6‚“:í7u êÒ¶9Ë¢Ó}×ö•ºŸ’2L™¢¼ÔZ—aoé)­Ó­ƒ´½—ÃÜë«§Qô£Ì@Š.˜;7ö¬w€^5yH\dä|núfëNstúè0OkÁÐZ`2µÝpKÇŠrKû×ÏT}¥¤gíïkûIÍûÒ6Ã}l]†kuä:­y(ÉûVéªqݸÿW#-¥û©•ž×SÁ9ÀßzÙc¢î´¹ŽÚ‘0v5êiT¬eà³uÞ÷*ÓÈúßÔuÀG,‡½Ï³^ò%“rÞlÝJËp|~ °N ÷\÷ˆ¤¦y؉®д‘«q¬È>Z—aoéiU§5êb*ˆ=c@ØbÊ}Ë2œšeTú}ºà|—Žz`fü½ÜQí–åSz¬¥õ°{–a­õHuZ³.¦nTìÊ‚ô’¶3¼Y4ÞÇÒ² Á9Àoª¾½Eg«—õ•KÁÎ=m5Ë#'ϹåùÞÚ6{ç½v{ëeß{ÖiïçÛÒØ[@z„2¸Šj#è)O®>Û»¦§:¼K£Jså´´¹Îtt*pd:ôRºSöSú”ýZS¸çö“Zï[§§ç:œ»‘mjÕEËöS;Ž\¶¸oÿá“ð÷¾öÝ÷Þ¾yûËÛív{ý£ï+ ººÑ{·å¥ TÞ¨åÝŸ|s»Ý¬A„Ê;@^(ØŸtª1òÏ:Ð:Ѐ»¤‡Ä}ùþ[%òúGßwnƒspn8·o·„t8–¿øx{÷'ß8·Á¹ 8·ÎÏí»ä׬}öÍVÊp„‹Áo¿rnƒsÛ¹ Îmà@ç¶5èÐ:Ð:tâ¥"èÛã_þõo|öÕßûí¢}¤~h¾oužÞ1ÜÿÔg@›ßèÒó8ço¹óýºŒ àÿêïýö§ÿæ:K†ßm™öÔt‚óý–}žÇüö» ~Ëõ· ØÁ6Ðö]èÀµËï×eŠû‰.ã“z‹ý¬m3þ»é9ß_;O·ž_zM¿Ïé¿«KËP"çãÒ5b¸ïÈv®°m?õYä|×ß>7#èè ß§¯LMc©5Å.²ŸÈ6ã»}îþÁv?ì[°×˜¶ ,ŸK‘ßÍèoiôñø—]ô[´¹^D·Ñß ³ÃIÚë¤ lˆoÈí9 ^ú?—R®©¿Û~ëÚ1ÅýDúžö”uâ‹Àž×o€ SøƒÚÓ~€sô)î»>ĸÉN SÜ;?¹sNðZ¯\ˆì§Ö6 3ü·?èS{‰lSëXs s¨Ói_;—r~7k]#üfCùoùÔïw¯qýùÞÛ7oy»Ýn¯ôýÅ ¿|ÿíív»Ý>ûæ?+µ~̧.ÑmæNÖœ§¶¦¬ekñ´iæýéo¿ºÝn·ÛðCçöÏ÷­Ï+Opvn³ýotê¹4w^FÇ£çöÒ¤]œÛ´¿.Œüèù®¿}®sûÝŸ|s»ÝLqï^äD‹<é±Õ±ü˜Ã¾ç{Ç‚+Ÿ³5¶«õÛ;õ·èg@Þ98^"R«ßî|=/:@ƒ€ÖXƒ0‚Àw¸ÛÎ%öa:4‚þñoý:à<œÛàÜœÛÀþÂ#èk¯aú³ö:ç68·ç6°ÿ¹}~:Pßý=èÖ @èЗ·Û¯4ñî öò½ÛíöËÏ~ï3%;ùúÏ¿¾ýÿÖÀs.°ìIEND®B`‚stella-3.9.3/docs/graphics/select_romdir.png0000644000175000001440000000746311433323254020502 0ustar stephenusers‰PNG  IHDRÊ´ÃlÙgAMA± üasRGB®ÎébKGDÿÿÿ ½§“ pHYs a ÿÓæÅºtIMEÚ!/)BûtEXtCommentCreated with GIMPW~IDATxÚíÝ¿ŽÜ6`­±eš~4›+Ràz‘'p7ݕ۸Ü&¥»t×^¸¾Î…› ÷ûäöŠdrãñH"©)Jú> ¼;+Qü÷)Žx7 ÃËét€/ýüóÏÃÝétz‘ð¥ççça†áþüƒwo_ËøÓãqrx%+`œ@ %” P€@ %” P€@ %pé>çÃožnþü×ï¿úÌåÏæŽ—òYÖ£œòÛÇX^í5/Õ‘íäÏ­~¼Fº®Ïsë)ŸÙ܈ò×￸ë³N¥»a½Ž°‡2‰ªêØ>ëéeÿ}«|—–{J|ØJ ¹_óä‚,G³×:¯-o7”ÝŠrjH:ÜŽš"H9ÎÒÏLÝy•œ+÷š¦¦vR¦—–iôu¥LçO]WÊq.ÿ•G)e0÷™¹ôÌåsNÝXZÇJêD«ú3–‡Qu#ç3µÊ½F K­?­¦p[Ÿë–j‹y¦†ö)Ãíœ)‚¥Ç‰úÌuá-9Nî´ÆXžFN FäO)¤ÒóÜêk¥9uj.=)ùõˆ$å8©ÇnÙ."ËôÍÃSÒå’¾.å8×ùS,.}ù_n¹·nï—çYãñƪS¯kMô6ÕPû.ì|üóë¹AöZÆ—iL¹û¸®Ëc-¹ÛÊÛœô˜:‹/Óœ¼ÝZ¿t+èõÜ'ôà¾çJ>v·Së8)w(Kïb¢®«WG\ô1Ð{nê[*¯µëE×#ʨ;ŸÔã´º{Üó»R#õ§Í RyÕ" )ÏÆkëö…k/mOù»’c×\j?ÖÎ?ký]®Òk{ÎÔËum±]lñ«"¾–r;X,ùJEoýa­:Ž»Óéô2 ÃðîíëE>%úÏ=„­µªªåª×œÕ—Qwfsw™KïB[—Wjšs®{,MQAvî8¹y8•žœ|®±â9åÎ~ÍvQš‡séžZ»¤¯K]éݲ?L©?¹«¯K?Sú¹ˆçÇŸË%¬1ÝÚÃ{m¤¡s ô®Wºìzq/ èIˤ°µv±×ÕÎ%t €vÑ S¯ P€@ %´”µ˜'z›—Þ^ǰ„ÛF”_µ¥Ûô¸#<í:¯Auu׎¢Ê÷(sßI˜úNÆ©÷E.y'aÉxìg9iž;ND>§¾q.#ÒµszÉÎòK¦Äj¾cs.Ý—¿Ÿm¬µû|oí"²O(ýÌÒz‘ò.íZåIàˆòú íc•»öôlÔŽð5;Ž発®ÔÁSvr_šž”ÓSÒœRî©çJ±»zêõ)çºõ÷kÖùžÚEJ}NÉŸ%Ÿ)­_suÕãªʨNcêooíbŸrW¾¤ÂÎ]óåùSî€[W襵§ô䦻ŹØN»Ø[]X»o9ºûÚ;V‰×ØñˆZé¨wQöVV-Óy.èòü‘‡T ”½ÝÑq´Ñzgð[ÏoÎS`½¦¹UzRv¨¾v#ìåù#†F«^K–=×ÜžtöÜf´5Ó\óºÖ<÷Q¾*õ<+úÚ#v„ï½]DÕ5ëêòpϲ6nŽÜé>µ Sw±Ú>'Jw•zqÃ’Uy9»´G¦'%Jw…_Rfõ¾vyÍ­&M]=™7½µ‹Ôú\{Õk­þŪ׶Î7gJÜÉWoz©KéÐ.Øs ôÂ…£ 8òŸvÁQºkfÅ›­=Ô%킽(ïeE:êvÁñ˜zJ( ¥],æÉ}éÀš‹¬l›Ï×–léu´2ŒxoïžúŒ(Ñà½qÿx–n¥týÙ#Õ^wdYóU„QnºAÃZ£T@ œí,–¾crìs¹ç*Ý bz-ç=œ)iÏ™\º“{ɵÕÚÅ>õºÖ¸;ï„25â\z×S¹—¦»U{Om[©Ÿ1¯JCÊTÕÔï£vßòf½×>hrË+²³\rž”ëêmæ"2Ÿ/±—rOMOʵ_–Á­ö¿¤o@9Õ°S;¾šçš»ÓMÝI#âý—-;öË]Ïk4úµv±¸®ëm¤ZuŠ-:àÚå^$SË]€bKîsfÔ.ö­F SÛõ.*Ž<ÍÔ¢ü#ÛEdYm­Ü|íì(PÞjü%»Ø/ °Gêä{:ÎÖƒei=mÕ.R÷MÜc¹ùÚé_ö3ÊÜÊ›³Aóš;ŒÏíÒ^r'}‡q¼Òãl}ûšÏé¶ðu…Zi,-÷–õyɹ®§î9¦ìm¶z^õ:wœ”Æ»äŽtjgÊséì©/ZXz·ÝjûZ —äsdy•¶¯’ü‰\íœÛž#Û{Éù"ÏÕÓÊkÚ;o³¾å–ßpáíòà:Pz×ëàÁ¿ü'PÛ^+ê …Ý–_€ü0¢J(@ J(@ J(@ J(@ J(J(c½yxÞ<<íî\”»/íä/ýúñ}ÒïÆŽ3õ™”t”þýÒë»ö¹ŸùF$µn)?Jòá2/kåcËò»i¼>çšmpì8Ú¸åde9WŒëF»Ç s}Ý·®}@¾¥‘éuc#÷ëzUëúrÊ+*Ÿ§ÚWN<ÿ숳6f«VQÞêø—t|{¾s— }Í`Ô¼D ¬^Ç*ÚÜ4KtpŠªð)鈚J9gÄ4]JYä–WÍsåäODz¢:îÜs•¶¨)ÊÈ|Ž^ožþú@›Ò]æÇT;l]çSÒ2•æ£=fzµV%žËÌÜ©ÎÞ ©v:®óp,O#¦éRÊ¢djºæ¹Ró''¯k\×’:_;Í‘õpkm0¥¼R®õ:ïKësdŸëRÒ|4›ZõšZðGšöÉÙFVøÞžEïõÙøT½ÚcÇu~¾¶ÇÑÉe;Œ¸®’ãäö ci¾þ»½?jº¨6ísžúÙÓõ¤N5íáFc­´Lïr:,å1ÄVëÚž;ݽ•Ùì"Pö˜ö,oÝù_ÿ<êZ{ɳ©g1­òz iÖvöSçùÚ«’‚¼žþéáKú=Σ·NÓuþDM”–qTÝH9NÔgze1ÍG.V«ÎGN™Ž=ËKÖËòît:½ Ã0¼{ûºxŠ åÎ5÷3cŸ[såU¯/˜[ÕÚ˪רrOýLÔõ§¦;â89×^2õšS¹×½$ŸSÛNË6•?¥åU³Î§þ>uÑeÍö·¦ÇŸË%äÔ­Jïz d´½§ yɪW²ä¬NÞÃ"%€¢`y¦^@ Ž(¼·š}åÖ·‹Å<-wb?RZK®Ëk¸úÉŸœ/ƒ§¼·WÙ«®N•ûÑêÆ«½jíí„¢¬±Ë…‘éñò9b‹¤-ïÈ¢Î×í£Ž²[Ï.F”·î†ÝõB^§T”KwÇnÝsÞY{ò–×µãù’s–äóTzÆ®¡ä½ QåUšÏµëOjþF—yÉuE¿ë5µ¾Ü:ÎÜ6gKò%"rÚFi»¨5Ùê#šWK/~ »c§îö~ÞÖ§æ.äkN¡”îx^š×coî|éiY^©ùÜSý‰š:k™Ï)ÇI)‹ÔôLmT\z£2u®¥}TtHa ŒÚ{/ÓP{˜§Ï-Óè¼¾ÎÜôä>‡:Ês•[AªÇ¶6@r^fÏʾÓ±¥×Úñ »žv¨§]#½HS¦!·^_sÞÃÙ"Í9eU¦[k§-Ó¢(gGL-GKôu÷}îd¯Þ[ym±þä¾{¬,¢ÊtKùܲZ£?܃W%«—¡ôØóVµ yëFYkÇóeš²#bZ6º¼z;Κu,õÆža·(S_'iÓž§¾ÏÛsmܵ;v­©„”es…Xkeî®ñ5ò¨Æª×ÈÝÞçÒ3¶ØgíUÊSén½"1¥cš+¯Ü2Èçœz:—?¥+ØsVV—”AΨ.¢*=WT?–óâ‹ÞfTÎ7J€š7t_(Óž¥—¢Ýt¦(Ó ”ÀêÖX©‹2Mu¯8^:V”©%” P€@ % P€@ %” P€@ %” P%” P€@ %” P€@ %”€@ %”ÐȽ,¶ìåái†a¸ûøÞ¿/þ}ù3–¹;N/Ã0 ïÞ¾–À&åÝÇ÷Ã?ÿý_™ñ§wo_ÿ•/—äÑ—y4çñÃçaL½[¿Û$¿ðüü<<~ø,H&äQ*S¯Ànüý?ÿ¾ùN-Ì£kF”À¦]>“C¾Ô P€@ ì••òE €YÌlÚËÃÓ0œNÍÎ÷ão¿õ³_¾ÿö«ßÏý¬E¾”Œ*¯¯¯eš{M«%@fÇüË÷ßþõßXð\3HF]ßܵ­í2F”#î>¾†N¿#¸fÌMÞJë‚{ %À΂d‹ëºÙݺîËÏ^çÃÜqR?Ó‚©W`Ózþ¾àšA²V¾\N;OMÏþøÛI™Â.™æ(v0ú:ŠÜ›„VÏK˜z6­×g”ç©ÇóÈj•|ÙAðïáfC Øi°¬´n=“ìedZƒ©W`Óz§éZÏÖróeì9a«t§œ«ezŒ(Ž{õÔº¾ë¯‹D«”|LùÌõïj­4(MkýŒr®¾õû-=£,¹¾’ëOÉ“¥i‰bêJ`¯ì»(_J(ÊØwQ¾Ôf1° ÏÏÏÃó7ßÉydD péåáix÷öµŒ¸ðÓ?þöÕ3JyôuQ‡ –?ý9Õxwþ÷˧O‹ƒÿww:^ÜmÀ—?|†ÁÔ+L(@ J( ÷ÃðÇÛŸe\»†áå‡~påÓ§OÃÿºäy ;§CýIEND®B`‚stella-3.9.3/docs/graphics/jr_pacman.png0000644000175000001440000000611211433323254017567 0ustar stephenusers‰PNG  IHDR^È/§gAMA± üasRGB®Îé pHYs  ÒÝ~ütIMEÒ ‘k ÌIDATxÚíÝ=oäÆÇñÝá\I+ÝžŠvpã"H“òŠ+Ý»°ß@ʸ Ü'uJ¿»H oÃA€4—)§‡Õé¤åƒ‹47âӵˇ!¿ŸBXñ(ùñ?ÃÙ¹ežç xNq  ˆ/¥_ð3îà dZ.—GÜíÙ´mçf—$€a£Áì Ü3B»'Be447~¢* Y`¾uÌ}”òã÷¿ZµÚÿÏÿþp”óR÷¼Ÿ÷eJïK[üÇÿìö¿´äyî˜z—ôÉ÷(ik·Ûa¹\*¥ä«c ù»&æÃ‡v"H(A`¾Ú1Q—D¦¯ë«÷PÕAûûûÅb¡,AA ”Êó\¾AeYC:TDc‡€×¶Û­ úIyžkýÿVßœû«†±%✯s{ýS}ß»8¾=Þ±Ýn¥ï ´ÖáûÂ/ûÈÀäþªÁܤà©««+é>˜Pˆ¢(Š¢4MMë–±©dc! èPSs}}-Å‚DCÇI’dYfî\Ê0¤dDÃþUà»wïÞÙ¹°ÛíL4ØcY–I‡B~SÕ@(pssô#L.H`FÒ4•aHq(§7/çhlStpô…Ý•HÓTrÁ”aj­³,3w(öT t(hÒƒôåõû²6äØÎ3¯Ÿª€Uƒ/kúòú}Yrlç™×OÕ€h@4  Æg˜y ¾`Õ)Þ—>ÿžGõwEÕ ÷ª úóôõS5 jÀ,±ÚUªFò‡=?Sý̯Ÿ:ñýo~¨Üþõ_qr@4 ÕÿJ@€h  xÞàËà˜<îPÌ®v(´ÿò`1¶µ!}7þ5ËÝ—Žk7úµ? aÄ’DÃÜîOrÀk7Îò}g¬Ñ€h@¯üªrô±n;fˆaÈÙ…Báqyvé¢a¦¡à²DC‡†º_í ß_[¬ÝØO»`¬ À·êÏë*ƒªUÐI®ÖEÕ`rUkr•U¢Ñ€h@4ðóš°Fà4ÎÃÜÖ¶¤jЕežçæ›,˲,KÓôŸoŽ’Ls[Qª]ØÇüû§¿¢hµZžž®×ë‹‹‹Íf³Ùl.//åÁùùùz½>;;‹ã8Š"­uJ)¥U:ˆD¢@_üž×àûýdÖ†œçûNÕ€ª ºœPCÕ€ª³äûÚ¬ `UŸ•öü´½Âû5÷ªÑ€h@4n^‡šäÄj¢aÈ?Ö†ìç÷[Óõâ}§C€ª¡cmS¼ëýù½ÆYØ{ñ¾ ÀÔ¢‡¢Ñ€h0:û‡!»X¿Oø5Ÿ[ßÏk+öߦ¨Œ£j¨ÎfX%Q5 jÀ,Ím¶%Uª®\Íxß©¼“o¿Ì·_r@Õ€¡°X,–ë¿p*@4àc(” ÂDÃLI㯠ª  ¨ Dì;åJ¡‹QI_Ö†ìúø¾ïO4̺[Áˆ¨…Šj¢‹PðemÈ®ïûþDÃŒ:Ô Ðbôð³!êP4´æG‚h@4 Míxj˜±/ÖÆkå›_ÿõˆ¿éôÎÏ´/ªD¢ˆD€öªïP°6à¯7ŸR5 C`àº÷¹y¼üÝ? [lò¯]¿’®ŸDzjºîQÒ|„r0½ì/ÛÞü¼ PѼëÿáU@](¼,J¨Sˆ ÐÝ8$Jì-vƒ¬«ÜcåðW~H¸€h˜E×À¥ÙwÝÌêJýC®íTD:©^Ö¨Ê?åÞ(Wýwˆ@4àhWÝæAʺnÅq¯ö‡<#ˆ†Ys¹ÐÜPÛÌê®í4cÿ$ò<7ßdY–eYš¦«Kn¾zóæME«Õêôôt½^_\\l6›Ífsyy)ÎÏÏ×ëõÙÙYÇQi­ƒ PJ)õq$³!T  Ü0 Ù‡æ[zm&ËÇtŸžÜvš“û„è¶gƒO¢PØÓ€››ŠK¬Ô5ûCnIvqÄ= A4ÌBó-C÷Æ?ž˜sù˜VóïK@ èðÊÙ¶ùòy‡º#7Oµ&øëzb¾5_í ‰†u4Ÿ˜ìr=/O‚v ˆ¶S­AÕ€£ïÊ}q ¨½ö¾lM§¶=ü~úóåWR÷yŠîê&ìíP¸tjÂDi`bÞ¾}†¡™(}~~¾yòúõëW¯^]\\¬×ëÓÓÓÕj†!¥¹T J©ráPØÒLU—“ ø+°(¥Ìƒr^´k¸»»{|||xx¸¿¿ßn····××××××WWWWWW777777wwwïß¿xxØívI’¤išçy–evÅ~  ‹¡P)A „B@Töƒ¦h(ì!ßJØØO£µÃ0 Ã(ФñË ’\ €A¢A꥔Ö:Š"i¤&&´ÖòرC¡+ŸÉ¤K!ÌSFQ´ÛíÒ4•µÖ2~Yˆ¢è3LkžÈŠ öXc¹QYèº'³£A'‰ KD$I’e™„B†¦CAÕ  ÂÔõÒTE9 ì\¨¬#tÝóÉOÊ!ì„ä‚òOò-ÑŒ$L¿Z­NNN$ì.†‰ùêÚ¡0»š\hˆãØŒ8š\0[dN `À… ÒfONNL:Äq,Ñ`Ò¡²+±¿j~„)N’$‘~„Œvh­%,¤d0÷&ˆ`Àh0£ vŸBf7Õu+*Ó¡x‡B³R*Ïs;â8–öoê…0 ¥dH’Äܶ,dÑô k|PMË•t899‰ãX {$²®v¨íP¤¿ e‹ :f4À€1Q˜Ý`ÒAÂT ašP¨›U}‡"Ïs9º´ö0 M5aîšJÉ ÷,s ï0`4˜ÁÈ CªÓ§pk°KéSh­í騻” Àh ‡ÂEC†! µØ_5˜ÂAÒÁÞhžFêC†ÊÑ@X½5ØÊ¢ŸØs"íEå‘k§<)¥², ‚À~JB.¹@4=GC]:˜qGsÛRfL&D>;N]ë•Ö.=ù*}Óƒ0ˆò=KÆEá³r]7_ ½‰êã44i“‹§U^ öŽ/@ÏUCyÜÁT…ÍŸ³ZîmÛ…Ò \)4‡ oÐ4Ø™Öti:òÞÖk‡‚ÝÚ]úD0`Õ°¨š.é¸ZäÒ½õVFƒËè? ;´]?vù‚ÖÛ6M  ­v;4L+J  ^ìg°ÕÝÐÚIEND®B`‚stella-3.9.3/docs/graphics/debugger_romcmenu.png0000644000175000001440000003277112205116016021332 0ustar stephenusers‰PNG  IHDRƒë;CssBITÛáOà pHYsaa¨?§i IDATxœíÝ¿‹I–èñÔ°<ÆxF=Ðÿ0m>Á,Í‚@æV!g½]Óå ­£2dÖ‚älÓ°ÆÊYÍxã4ÒšA;C3ãÞ¶Ÿ+™ëÕ3²&;*~œŒ8™?¾š¦tófÞ¸™7óDĹ÷ãûW¶ôîãçׯ¿9º€êœŸ¿xóüá/Ž.Cû»£ 0„óóGP©{<à@<àH´Ä‰–€#Ýi‰o.®o.®ù›¿ù›¿ù›¿ù;óï)Ú[7׿½¼Œ_¸þå?ÿ3²=}öäþß™ÿ¾÷þÕ¤†âêêí²â¿þ÷?(¶@Óþýÿ8ÿñÓ“û¯=]}ÿÕÕÛi»ñÄKi•3o¥ ¦¾ µãÄ% ÀÐ’ÚÓ­î‰Ñ–³³_¾ü%´Èü§÷mÂê•ð–0ôÕb¾2r°‡›“TƒV7å]kä³Â'>ª(¨–Y%Ü 9¿rlc¼|º·xæfµ÷~‘ùoù+#‡¼çQ!o×ÇqêÝ=gþÊOMÓôøÓî›OŒ4s…\þ¹ÔëõJÌÅ[J¨+d_ ØÇQu|¨zGœzÖÖ£jÎü¡gg–?„7{}OkÏç›þm~¬å¸,¸!nHñ:>N½³ÚÓù†ØüÃDœÍ3Ÿ›y/º'fæFŠ–?kýj‹…¢…¦Þ-ˆ£s˯øÐEßûzOñªc »ŽÛ4ëþ8õv¹ûzgƉ­ûàOYÑb¥†@ŽõPÚ­À˱®ÉáýѺÄ.m…PÇÕGzg!NŒ,s7¨å¿£Ê°”d¯¡îfØ{¾!Åëø GiO½aëEúN#M[µHø9ÿEÚúʵq{l±?»yX©w^ĉqËm´¼#îë¬¡ÑæM°5žxjü+7MØóhˆ®š Rï–8±w±…81¦ií‰nü¢ +OhÆÝWF*·#»·!rWJêqb aäJ`Ií)qb*Úèl'&E1€iš~ó»_r5¨ßÿšþ…ÃTÖ½÷¯æÜÃ16‰“œrõÇ·\·‹‹Iù|~þbzò81…' Œ'Æ­ÈôÝÖÒå=öÊ‘K(|/ù[Ä m4W‰ÙQpÑ¥«~˹- ÇW'.’Â[œBæsó OŒi›%¡é2_?ðz*—04žX™Á)¾ðªaÞrȬŸ›¡ñÄê9¶„íg–P7Ïü!ˆ#ËQYÄ‹°æ 6ÿV$RD*öaýâóç_ò›á"Å(…81 Pü¼­§Dú²–01„&$ž;ïôò:û°~M'Miå†x"NŒ™Yߪ=YwŠWÕ\Ÿ[Á>lȦ÷WÚFSOïÊ'††Õóh e(ÂíöÞÒÅ›±ºoQ¹ü8®ÉºÉ–ï¹K*õŸrwZ⛋ëéòò¨¢ IMN[£ã ßù؇­ðF òcÅ"µ£Î®›‹ëéËÓÈ7sOŒiÊ8Yå1MHúâ EžªÅ>ÄnZ9»îôØJz® «B=¶Ð„ø[Ez>+%<¶&NŒd'‘]¾W|ü»ã½¤zleÎÂa­¥®w‘%L-瞈ãÖê š4#i#›ò~z¨Hráã/ñŸ8¦Õ±mì®ú•=Ï·ˆWX“âÄŒ'àHĉl¨•.3@YIí)÷Ä6D3 ¬bÞi cÞišAœ€ÂOŒdò€}óŸÞ·Þ+'>U°5ð?u-ÆwøÉƒÞJaþ35›™w-õ6‹opgŒ'Æ:yNöù•¯§º|àê,âäe*ˆé·šªãººšK]%‹o°ÆcC¡¹åV'p¨Ÿ¢Švð­Äï˜&DÖñȺP<©yëYÒgĉ¡WmØíúN[²*4ï4»® Åë¸0Mtñû×cs'ÆX„Yg©•P¸Ül”É|(4Ã#ۢ®ªü”#NŒX°ò«\äL÷•Wï¸û‡6¸ÕtI}4Ãä'Æ~*y½Xz8ïSñŽíªÖ.ë´aÖ¬l÷>îÞô×mg×–øÞûWÓÇÏG-ZÍA¶ƒ&jÇFïjÏ:ÞS3Ì¼ÓØP‹×Íe ÆêÛt[Ö–k¡[èLü ÀP-]m*¾ÁC'Æ-!¥vå}”ÜVÖìiÁ°y×’U¾7€Ýèê‚ÐcK¸ í¹Á"ˆ#™pv&-:ªeŠ,¤0/üzh V­>`—Öl£ºà]·ª îŒñÄFœ@-ŠÕG!?1€ Ñ cLä' ĉ(Œ81Í`<1¦i­[MhÜícõдVò·Ã²Ï4Ñ}`<1J’³m3s!R›¿jBvKŽ`&âÄ€òÝp=¹ÉëAœÛâÇ/â¹óNsCÜœ˜‡Ò4Æ9ˆc…œÖ›€rÐ ×c¤Cœ…Y]´Ü™œ©«‘{rÚTŽc´ò#A¨Ý¥ËRq´Âzîe¥<¢DmHŠsOŒIiG¹¶"§J+ä þj BDbÞiC— ¸Ü[4ÃAR{Ê=1n…¦épÛW.£ÈÄœ0€‰81¦ií:Z*dfü’ë‰ðhÚûÊÈO @3ˆØQaŒ‰üÄjA3 ¬"N øÙ¿þ÷?]„†ýû?þqþƒ81Í N @aŒ'F²Õl9¡¥5 Púygñ–?ò+¯n1j8mã¿þùÌþæw¿ ½Á]³Yk­ÕëqbܲÚ'³í Íx×DÊ÷È ‘_YÞ b4qÚ`a6‡ÿõÏÿú§µHZËÝBü6+Dœ¹äy+û¸h’]Hõ›ßýr¹mµšIs‘@·V÷ÈO õ=JCô’²â§¾÷ñó4M———WWoÍ?Â"¤v/¶ðìÉý_=ŠM”+kú&ugä'††yGÙ š÷‘Õ¶ÁÂ÷šËɯOôët:½|øVÞŽy'SŽ%ÓéìÁW7*çç/Þ<È=1àA3ŒúÍc…ßlvCŒÝ'$ÿüû£‹øþ÷ÿ=º"N äbæW´¢xœxy¾ŠÝ0ž€ÂÈO äÊŒÔ<ýÓ_Í~ÿ÷ÿ'»DQd}–®»¾ ËÞðî‡yé±»h»ŽÓØ qbL“8•G̈afŽ4=ýÓ_­K³ûJüº«BŸ¥+FNáë§Þ½î/sé¼Y¥Ý·E^„Ì1õ'•‰Dœ…ÉÉ!æW:kŒ»ŒÓl eÓñijP×Uys;Ö6…E}#?1ÒXrù»¿Æ¸ ˜'ÆËëòãÐÝ„î#ßo~/ë뻋ܯ,,Zý,s馻7´)¡Bá«U¶Ž[[0·),jù‰±“JjŽY“—’˜KÍ7[i§iòÎv™©1¯Â«Oz—WB”Wmqe·Úˤ÷‡^q-;Êm€…Eòg…~õî•Ë?öO¨[<üßô†xµŽ§æ5ý”qb4o™þÚ[½½ÏÒÍEÞÙ.3YÍØ¦÷=›n<õÎx_*ኯVÉ-f%ÅØšðlY`ÎWßq3Lœ#*[¥KEjÜ;!uÛ¶'ó–tÏG¶ÊMìÃâ…ß!N쥮qÜ»ˆ#K‰…§Ó;Ÿ7¶r·´”³ÂWX¤x;l ª$¤µâÄØOÌÀ†E½pÕ©)>|hÏñHõ}ª¿„‘¶¾!®¼Ž÷81Ò4ývŸ‹ˆûD×¼¿”;X ½½ cϵÜ^Ä™M ®„óœ¸!aQL’ŠQ!Ý¥@è±ÕYg.âÄÐp[)·›ñÔZ ³oˆûOAf¤&çétÒ¥Y~³î*_|-÷׆b­˜Eîë1¯ÈŠ£xÓ{`œ8fÚyEw€ò¹\ĉ1MâIŸ´è¨Ê_ÈPŸj.¹Ž«+‘î‚Ó–¤8ñ/Öߌ‡¹|Ñ ÎÕÜi‰9¢ä#N äš#5§Ó‰dì¨ÜQqbD~bÀïÙ“ûGXñæùã‹?òÜ\\¿yÿjú[ºÇßü]åßÜwàÞw⻟_¿þF±¡««·ºcÍóNsŒ.½üîÓ4}øð­ü6.àÅýôÃ÷¿z´ÞwúüüÅ›ç¹'Æ­ÕœEÞ¥Ë{º{À“åÌ}ƒ¼©Õµ†ºª0žÓ˜rIJzùúPÕ‡0ï•®ÊǬÕÁœšÌ;ý”Í"^›wLþŠºmU9$aÃòã~ÓO© ã‰áù»Õ­¥[*XŒåù?k©ùŸûzh³4èÜétšÃÀÛ±*µ÷áÙjUJÒÍzÆ#YÓÓ½.…M+o¾Ù]4÷Ø yüçß/0PÄ>ƒÝ…‹ƒÕjF6¢Â<öÝ4éˆã–ÕE«¹úÐ\&©“t ­ØY3LœYæÊ øy[Õžbì'vCK=µÍòcš2ÎøÊ³ˆ{ÃZE¶le™²³Ý¹Ìܦ\B]–Ünrë!§:ŽOZŒYgOª‰~e(XÙ§úkÎewY7s;ÞmZ[v?"æCukµBñ]–),mu,ŒhBâʦŒ¤ß•³¾×hC#âõÑl` ¡[½^4J!N ÕZ$ç ÜÈFâç÷7YeÝ]™ÿœÿ6ï¢Z|,º Œ|èîßÝQ“ï °°hõ³¼{~yQ~Úœ$´)ù¨ê(›B•EQ‰âWª]'N (©C­¡æ'r•ȵÔ%Œ/LL“¬+üÒ\¹ °°Hþ¬Ðž­›Cxp*FßÿDœØƒî ¾çµuÓÏJ½3^Ä—Jx§â«UÒªUR T…81e¾EçòjÞ’ªcÝçÆ,Ú³HÅ5]xXˆ»°1¶þ¨G…EŠ×tᑃy§v¾A,nÏÂ׿£ê/!êGœ8’Û96¨qÙ¾Wº _«ªe®›Ú¡ÝÄCXS€¤b ĉ1Mâ }aÈ Õ¸6Âd[—ªsÞ½Jš¯XK…ǹ1¯„^L-aæ·X+´£’ÖŠY¤Þó‚âŨ¹éõVmÅxbï€þe†ÝТ'FaŠt+;[J%´¸nf‹˜\L–„ÁE~ˆÇNgâÄHcM¸#ç.=Ü\¤¹TóãÔm ˆ¥^ï\}*¼ž$IjO±þ l©œV›¥Ë››®ÛÀμ¹˜–¿…w" qbäÚ:QZR’’¸Í×!N|:öIÆ4-é `MŸ¿Á:%ʼn¹'FçÌ»vw‘PÛŸ=¹¿mÉ€lož?<ºÉ­æ\ïäÚ7æF.ooŽ 0Ýí™åf}в†Ëp,9ܳEÅïà†x"NŒ=Õ›ÃdvÈšÄH0=¶€Tæ-,±áÜi‰o.®*Z!¤ ¯°«­<@76j†»iÝ“ÚSÆã–7Œê.ª³’„²›?ÜñÄr $!NŒiZ{¢¿¨Âzšñ#¦¨ï¨¨ÛÖý …:®«ì«kUx Ñ!N ØÕ›f•;N/¿ûÃÑ¥@Œ'$ÿüû£‹ø1ؽfŒ' Ì; @aä'zææ±/žMÏÊŸd·*r¶ãÔlÄÀvˆí±¹É)þq}˜¿”û³(‚üÄÐsS YH+M¸šãÁbåX2@0¹)ŠÍ¥Š$Â*‘S|ÄÔñÔâíñĸ#4úV~ÿ¢ÂùqV«úÕÕÛ=˳5ë&/òvÖ\˽ámJø¬Ý™Åó>E¾ZˆnvÏjó„ßè«Û ÍÓú,Yds¾óÕ‰81 ³Îæc SJ…?â Í’âÁµ7*lmÜ}Š+Vh‘°–n‘YB÷ÍîWKÝ‘kuoÉ¡"¼'µžÄ§nù—š¤©Ç"NŒuV.£nãv…Ú'7 ê]}¹¹Ô•ªàZùí-h{6`Õ6–©ˆc?ê@ÑnêŸ4[mn2…‡±Ö›·øôÐGÅ­¥ÛàèÆeª¿î Ž'F”ЃúÏûúK˜ÃmŒ÷¼ Lz˜¼ºVÒ¢Mq'½¨¿žj­ãÌ; Dý09$rkñj¾SXk‹;Qînó=Xþ›6î)²çgU…81bÕùÃ&ùoäZÖ?—¿­žÉñÏ™ÍêžNÇ|¯˜˜·÷qwü÷Оƒ#ꈑ„81’µ~Ò+ÔÜ‘R&7BEºMEn0~Qñ ¯[´ãWŒYAL…²êÝÖMû£˜’'Æ4ýí”5ÿy`atsŒÌßš™=wEü$»Í¶±çgYO ÐiZ3õ}PèyÞišáýEîóúO¾~ý°ôüü…°ôë»ÕòÇ¿=¹úúâúGf™½kÞW­ì–¾ Ü;GeŠxÕå'r;w¡oÝñ§Ç¼¯?þôƒ°–{±>ðò]ü£uÖê¸aÃ8*Šçäo÷¾_Ø ³Ld í@u>p@Œ;-ñÍÅõtyYjÓ™ùÛËn2y†–ÒoNͽEö.Цscºlmù#þ³¼%To0f­Õ/h¾ú,™°Vä"á8Æ£!£iï+#»¹¸ž¾<|scqb EfKæ^­6fùgñgÚ¡Í®~V¨„§pS³Ö×)½]Ô¿KBkÅ/2ËYU m!?1°‡ß¿šÿûúâºàSR‹¥VCsbÝ—oÑÈ)6XÞA*аÈw„*Þ¨ïó+aÿÏTR 4gÃ81€Y…í®këÕù­Ô|[¼üßZ”¹ñ"*)j'®nÞi‘ܾTŠ-,°Aùƒ*¹•T£’’£uÕ'j&qÛ˘›'a-ó¾Ð{¹Ykƒ©%Œß wûrßiïü¡â-voÌ"ë[tßwñ’âÄ÷¬såÝÇÏòDB!WWou+¢òˆaai C…éD¼“þX忼¼œÖ¦Œ~÷ñóétŠ)Ì›çcÞìcžõÇoå·….à«|5[OˆœÅG±ÁÚüôÃ÷¿z´þtúüüÅ›ç‰ã–Õ> S›-¯‹ê±škäêêíêFž=¹ÿ2¢!¦FBW†)cÄм˜Âg5‡ñÄÈ%Ï[ÙtõX¤ÖsZYÀ¼2x³õÄÔ©ùm«“T0{î‚ñÄðPW€†ªM÷ù£€âò›Æø-´Þ 3žf³Y„Âë!|¯¹ü—Dd€0Å•A o¡ìg5„81né"4VŽ +O‘810¬=c·ÃƉO Å“Û/_þÒÖóÞÖë9°¿=ëx[דLĉ¡7N=€$Ií)÷Äðïûh€‡úÅ a^¬Tü!ÓPO­ˆãV¨¯„Ûb…ªât\œØmScJB-`ÕjŸG­¹ëöÔc‹ñÄH&ŸôÂÒjKNñè±bjP© Öp19 qb #N @3ˆQÞE¤)“ÓHã‰ÂbšáÓé4ç½€$ä'bÉy?ÏÏ_KC™k“R grÓÚ{»‹J}zh›{î`Ì; ÔÅmiŽj{BŨ§„À€ˆcšÄÝÞé/¼ãÿ¦±Ç!t†f3¹ŽëFË£û˜ÓƒñÄÐæ^Õ ·ÂôQ…vàÞ€zÅ?Ó>êVx¦úRÂ"ó]Þà‹†"×q]}—·0æÌwĉá¡ÎÑM3ìõãûWÞ¦ef5¢›>1.ÞÀD>î6?WX´ì(÷7‡°7ö\„‚Íðä\jæ¿ûhŒ‰c,KMö>ò =[[^ßg¶K³i™î6`9—øÔâ¨æÄü-²º¨øïƒüÓ —âmzÝ¿GCœë*Ÿ vùí­Ò³µùg» Ýu5*Ô¾–"<16ßjËåf~ϽR\B³UWxmÉAœ…5QCj.d7í®Åûw»‹¿Ó5 ¿(rƒXXw±‘7µÜ»˜w²®æ–ª¸¹yبñSlVXE·hÓÏÕm¦Rq⢅ªqbàV%=3uO;WºÎÿ4ÿ>¶„VÇ4Å"] ÷\l81<ÔŒ*Ö”Ó ŸN'y-YèRî¾Ù™KÑçK~[‘®LB©t‹"K¸ç¢ÁeÖq¡ÇVgˆCCèyá6`óÜ'KµU*«„êGaÏžÜyZÛ›çª%ÔquõõØ2·&OýÑÆcš2ÒwWROâËêS½ŠVcR_R·YÉŤòÐŒ;-ñ =È–ÔžrO À‘O @aĉhqb KjOOŒi“‡OՌʊá=l}»}r1M Õ2õÀ_ï+ŸŸ`;Œ'Æ-a&w!Qý„¢Î_dç\L@sBóá¨gËònÐ;7mC— qbäêxZöEÓ•Øp7¬Ëå@Õs'†ÇUe„_@¦â—‚®-3âÄЈŸwº­Š$|¯¹1ŽŒ¿‹Ü<{r?µx@ÍŠWöÌ'ؽ"NŒ[ñqⶉÇ4çÓéå‰é©¥RùZ*A~bä²2—uIñ_¿þFX*çL å»ÍO-œD(†ûæy©[ÂËù¡óW ›aÓú¾æÈO $øôø‘÷õÇŸ~Öª¶13_i½ k½üèLR~búNãûâ©ýg_EÄ´^?¾eÞ1ò²j}»r'Æ-¡gSäZ©ë¤+FR­²Ü{Sï¢øgÚ›6sc¼ü?r­PáåEñÛônл[Ô»×ݬµºÿ]bµµóf’ïÔ™=ä ê®Bu"NŒdºdà•T•œî3³‡Ù¸îÐÅ}çæ6Ô\-¯¤~z¨ðêï%´‚VÙ´–»h9^G…óëSƒ n°’KÊþˆ{°úF™—õœK¼º…pØÒD~´®„êï5fÓ‹R’âÄÜ» ÝUŒÈ÷ç?6?Zýtº¬ø¯O«ŒM'6wx»›Ézl«x’<‰O¿ëéI¾sÐ1æ†àvGÚîS–ê>Ñê}­.‰nÅ6NËRˆ äqÃ!ºç±ÂZæ½iü}êž…ÝËfdZWŒ˜^Ðñó{%Œ\k‡ŸAhWRœøžyÊÞ\\ÿöòRžH(äêê­nEàXsßiyÊèw?ŸN§˜­1ÛåPê;¼üîÓ4}øð­ü6.àÅÎ|ÑüüüÅ›ç‰cšÄAô1麃ÿìÉý— 1Íp÷êoz7âMì¾-uT±ûþÔÊÕb<1 ’C,¯tßÓÊbŸw,TÇuUÞÜŽµMaQ߈#U!—¿GhŒi˜ÖwQ¶Ž»yÞ–W„E-b<1vRIÍ1kòRs©ùfw^½Cf»š°ZÇSç§ ý”qb4o™üÖ[½½ÏÒÍE;Ìv tIx¶,PÌVÝ"âÄQÇU¨ºÆqOì"NŒ,u&žNHR¶UÒÚqbì'f`Ã"‡^¡íàÎl—Iϵ1¦¦ÀrJÑÕ&3H<9ý6B‹ZDœn½ê }·U·­PskSäÅAè±5Hg.qbL“xÒ'-:ªòÄ2Ô§€K®ãêJ¤»à´%)NL.&ŽÄxb Ê»ˆª!§‘0ò…Å4çÓiÎ{Iˆ±ä´qçç/B‹Ü>•¤ôŠQI ó™é„k(ÉáÅÀ>O ·æ–ÏL ´)á mðhbfÒýꫯ&âÄwïý«Çÿö«oûô뚸'ÆLNú½šÎÈ]T›Ð,ggÏÅdÝ®™wN¢ü ºÌC«X·•‘%,û½ÔÅ·©(ahÑòº\B·lÂkK‡,$bšRª¿ÕþîÞíR+|»(¿TI—ÿβFû\W©úâÍQüSšCœÍ›krd[[=·?NâƒÐH[÷NŠ)¡ð½ä¯\¶[Øó³*±OÙY3|ïý«)"N<#NŒ[ºÉ¥Õ¢‚ÌÄj-æ\‹Ãû´3§x²ø;ݘ¼[£¬wo âŸ9g~PåõtSĉqKW BÑÙz,¿ê,äÖ‘?¡Ð-ŠÿÜžF*‡Ê,憎©E¨5¤W‘ÍqâÇŸ~Þóéñ£ùî‰QÀ±·ž«O§—âUHÝ£ZÝS\··­ÙkW±(þ³" _êétL1&§Ksf Ww”µWsŠQ ¡£V…?mk³´µ²{ÖQ÷ñ³<‘PÈÕÕ[!Ž’IDATÝŠ¨ÐD =$Ý! 6Æòݹû†å¹ï´|+¿-ò.×ñ˜+@Lë:_¥úé‡ïÿß¿ýÇê=ñ§_ÿÓ³'÷¹'F1eWŸ­E–öÙ“û/#bša +²6Yõ®¶+Fq‘÷Äĉq+4M‡:øžBˬaKÖ楑3{ÐÊ]7O³V†æ ‘§þhqb$“Owá¶2i;‡ŸZ>³Ð÷—n‘ídn­f‘÷ÄwföHʧ4¤ËJ Zä' wZâ›Þ‡¨°ƒ¤ö”{bŽÄ¼Óvïý«OÑí)}§(/f²”óóÓ“‡Œ'ƭРaï\²]ΉÀkuøï"ò: î`$ñìæâzúò4òÍÜcšÄ çVgÃ9vJg›¦ÄÒUyaƒCM¿eb<1²˜ 6™X€ÎxÓŒn´ÁâŸu¬¤ö”{bøEf$­!°™Ôa)‰¹Ô|³ûÔ=r¶K`@«ÓD§Nx9Ú¼Ó‘ˆcšÂ3Á6a)¼·z !m3/áâ ËÆÖôÕ&qbhX7‹ÍÕœŸN§˜TKÀ€B·°êÇ=±‹ñİÉ),urV{xš"3ÊI#V<UIHkĉ‘L]„ Q ä°Öìë‹ëøB'ó^žï€…Á1ï4’ÿCÁêÏi=¬ -ÙÙÙk·×ös á¬ÖÇqjPR{Ê=1¦É7` é:°°¾—w\Dê7ú› Ò%S¯'[¯Bgµú8Rƒ\ĉqkõ¼wßóÊ>„Ï å6>ôK?rBƒ¡.1ŠüúÁ±BÇK}G¨Aĉ½n.ZAœÀ†Zö:ä'P ša`óNPXR{Ê=1G"N @aŒ'†ÆjÎ"ïÒå=ƒ„…½‘“8}(™;jœ“­1YÎÜ7È›r×¹1žÓ$ÎÔ¸:Wûüú8×Çø±•L&å¥ÛQL&z!aC‘)r…×›®Aĉ±³ÁnºÚG;I‘J/~-dò&l8ä£ûF~bøE&bª!­Š™ƒa)‰¹Ô|³ûÔý‹“ÞÉû6é„YŽÔP×ècY•ZN©ÂA1‘ŸÉšžîÕmJ…,ªî"!™’WÌ¥‡¦"Fj³jÆAØÃ».ÖQ ©'Æ-ëf±¹j°[›Û3ÇŠ™aX‘’Æx7¡{â-&î óN#‹ú±«=<7E ±…zÒ å@Ö âʦŒS_Õ@k¡E£]£Ñ¨¤81}§1šáÎËÎÎX»C º¬otǬAĉ1Mý&o·¾¹rkÐëÉÖ«P-Ž£Œ814VkQL î¨ªŸx\èo"Lô³,Uì¥Áñë§ñsq¨7•³Í'îóB ,âÄj1fØHB~b¢Ƙ˜w€fŸ€Â’ÚSî‰8ã‰qk5g‘wéòžAÂñÉÌÇÙ'©2³c÷“åÌ}ƒ¼©ÕµZ?ÐŒ'F2! ûê4ý£åÆiw:îJ¸;0fw §(6%dE,2EnèC[nqbd1ìÑ*O-D’ÈÝ%L»ˆíx3@ìü¡JjO¹'†_äïÖÕ™ †—’˜KÍ7»OÝÝôÆE ƒ™¼o“v×r¤ØÉ»±*µœR…¤FœÓ$&¯ŸÛ” YTÝEfCžúÜŒç¥9R›U3®Þpq°Ž5ÈDœÖÍbsõa·¹½GÌ”à1»®’0 Ý«w>5ÈżӰ©oë±ÚÃs#nú¿a¯,ÅÕ“nd(;ÿê©%Í;Í=1¦)㌂F5ÃZeuüœ­*ìÕ^\ƒ˜w©í‡ÂÎθ7:G©„.ëGqb$s'ôñkÔú^äÊ­A¯'[¯B=¶8Ž'Æ-EïzBw1Ý‚¬† ú¥oÍs’S¤¡ðë§¡ã¥8ŽãÔ âÄ€^ëõ@sˆØÐPýn€ù‰Ô‚fXżÓF~bšAœ€ÂO =oÿ!Q@(äŒCå¬ÛŸœ†#’81~¶d¹q_4ÿcnäÐQî{8÷a/ïQàšàEœË[ê*$L»ˆíx3@¸K¹hd"NŒiZ«o®€ˆçÎ;­žè9-i†ktÑã‰QÒ\ÁÜë)/©Må ½"NŒuf”ˆ+ ’ÌgŽw‘®^6Ë©ˆš%µ§ôÆ­˜ëÚ’#gƒÈ”zÕ“n ~ •r§%¾÷þÕôñóQEÁ±ÜèÝò—<”•sRq6Ö#tÑÀDœ@=܈¿íB—õ}Ÿ+ä|ञ…§MCÌ+‡)ù‰‘LÂÌŽÑÈ¿äÐï!#r_ã‰(Œ81€ZYV1žÀ†h†1&æ ĉ(Œ81Í NŒ;¼³ä, ¬Y˜R:¡3*rÝJ…ùHqD¼˜wJKÒokîu;À¥;£8bîçÐQàXd"NŒ[¤œC͘vñr ,.âÄH–”rŽ+ â¹O5Õ·¶ËiI3\òTDœ+–´ÄT3§KQÌEõ#NŒÂÌ(ÑÄ=1Rg‹®^6Ë1ºA~bÜŠ¹É˜/|\‘/õ,"ß@…x2!HŠsOŒ[¡¤ß´»(.ç¤âl¬Gè¢TĉlÈíaÀo»†Ðe]81J’óË’ò œ6 1¯¦'Æ4­áBÕj‰Uò/94Á{ȈÜËO @3ˆØ‘EŒ‰üÄjA3 ¬bÞi #N @3ˆP㉡çí_…BgèäŒkâ¬ÛŸ<ž˜#’ñÄø™7é7ÚQ–îŒâ<<йŸCGcá"N RΡfL»x9 1Rˆcš“~sDWø%᦯¾‹ü5‘CwÚÔs²Fø«;"Ô;qbÜŠL9×VêâùK-ßË,¼]•Ä«bÚÅCßÏãÔ;âÄHÖtX²Ç/o޹¬pÑ/ÈwZ}k»ŽH—F®wĉÑ<ó‰z©,¶Ìµ»EŠâP Û Å‰CïQë©Þ'~¦»‘6^Uœ°ëÔGdÊø…T¡P®u [äAÚ°õŽ81nÍO—ÿŽ.N‚Õ§Ó1ñokƒí>«oEêu–|GöóÜ÷b銑©³z—ÔžrOŒ[ò𤚠O§…wâ@9GÇþ0ï4ÒÈ×ÐÚÚïøNàæ÷¹çHqî#ög—"ë8õŽ81 õ×pUsÌÊl½.Œ'º‡ôÔs¤B¡j#×ñ˜ž\ò6©w³;-ñÍÅõtyyTQp !'ׇúk‹üÔZ~”½a±†QÏÏ5èlQGF¨w7×Ó—§‘of<1†ÐMõÐâÄ6Ôz´Ð!?1€ZÐ «O @aÌ; @3ˆP㉡çp…RɨP¡Owfï—2YëʳÕÑ Eè¶»ÕTZÞ×#·™_¹rêx=OŒ;ÜÑ·r>pu†»ÝèF.†ö€¼7I±ÓØó‡w».aCñÊUçèdÆY’f¢§1H•Ÿ§R½¤KØ@åò"NŒdãTä+˜Úë‹*Á%rðB81J’g‚­?h*Ä#Õ¡JäSìü¹0ÿ¿YéàQí>ï Ž'Æ:«‹–õpiª¸ŠNµÆÆáÝÉ¡äóïSMŽànjÞÛuÖqâÄØÊ—/ñÆu"CDÀL'Îßtjn†û@œ+"›Xcìƒ&ag4Ã:Ì;dEÑnã¤nº}|åíì±…ý '¿®7;•Ë‹81¦É©ò0ƒ  Ÿc$ÔO­‰½Q9öa[„Ê%wç ¤r%ʼné;[Š^•„îtý5V‹ÿ­!u,8¤0H¥®&ºµŠt ÈÙÚQˆPqbµ ¿°ŠüÄ6D3Œ1‘Ÿ€f' 0âÄ4ƒñĸÃ;ž/4ȯ’Ñ)BŸ uñø¯< UQOÍO°Éc|ã‰ËV.uß㉡çftÓwן4M1ÜPøÊ«Ù¨Cqž¨ÓÈ#‡¼Ûå EêÕ•«ƒ!Åĉ=ÝNÓÍ­ˆíx³cm·ýæ'ƶš®ØYÁy§—k}ë×è†ðbĉ±BžZ¶þyb󳈇®J9qây‡›ÿ߬tðØbŸ©\ùu| ĉQ˜Õ¥Âz$5ÕÝ&éæÓ¶*0Á`5ïN¶N˜˜óÇû,´Ú³®?¥öö•«ƒ8ñ–øÞûWÓÇÏGõ µ»ý]S$)2Ñ?û7eÏöA*qb”ß}‘Gì ƒkt[úh+ǼӘ¦BCqzmŒ?“£`-ìO8Õ‹ôfï¸r%µ§Ä‰1M¾àMhÑTåMIñ9Fìèѽ&Î(,„Ê%wçŒÙ ‡~Fœ·t=›â7²] ¹¨9Kaò>)a¶bõH ùçl°ÚîZĉhqbê&ì$!?1€ZÐ «˜w€ÂˆÐ âÄÆxb$ºÕC?•/AaÖøEß«Q9㉫=ÇúÚíŠñÄ¡ Ž\ïOŒu©“õïo)•P½ÝôSxr± ¿c7t?àúÙןPþ+óuö$SO”816dͪSyòö¹Hs©æ?*/0B8vGYvµ|â'»åعˆ#Ë— ’·/XþÞ¬û 5wÞiõ­m 'ÛhÔÍmä;Æxbìêð”ˆæ-ït÷B/\8äÏíÙ ¶–úHÓ{s††P(£sº©A~¶ï@Ø“ºfxÙì8wWãèé€&ʼné;æY¥Ý ôrÕæÚ]ÔcQIº‘v{zâÄhžðtÚ}'—•äü$¢ÞÙ\³–ÿŽ.N3ˆcCmÝVÒîÎùµu !„Þì'Æ-!‰lý™½ÍÔåÖë¡ñÄÖEÄZ”º›b÷öÁÓ³Ê8õŽ81’efÛ®¹¶„fü¨6Áxg܈»·!«áùÔ£I½ó"NŒ!Œ\Éì81€Z>V‘ŸÀ†h†1&æ ĉ(Œ81ÍØp#%2…v p°†M+ŸŸƒìµ‘Â7JqAÎÙ`5¨ñÄ‘G4tHVgíéãXîFؤ´Èç'³z­rÏ"vZÍäœ Žy2T'ŽI‡Ó$Ðfì`Àéîäós„=P;­f¥.È‘ìédh;N¼z`z:T5‹Üɺœƒe™óYzg9ö&=5_‰Ï‡*œŸœ™^ò¾e§U®ø™äuؼÓÂTÆÂ\¦#ªM)æµÖ=ð¸,…÷ViᲢݑß"´¯83Sþ1Š_©AÝÆ‰©±›²ºh5·«w+0çd’˜y†Ù5+~A¦¹î´Ä7×ÓååQE™y£¡~¼Å-$Ý ÖIèTŸI>?ο Sƒn.®§/O#ßÜR.&žTo§×IÏL`#\ ªnÞéR]é¸à•VtÜÕs#Þ>tG©ŠŸðãÔ ŠâÄn•Ëé¹JÒŠ˜õº­ïåƒ¡ë¡æ®k]_tA¯'[¯rºs&mpä´aœ8¦§†ú î{9`ÛÉ9(‡ïüø²…úT/¯„îØV;y¾êTä׎¥¸ +ÞÜÙYÑmœØAg—õ«.N  'ù‰Ô‚fXUݼӴ®íy§ qb «e<±ÐSÃ;PÄ;°,~zjyƒÅ,ïÛ†ê•#ï!µ fÔÖENWs©A®ÃæVd€°Þ¿Ad²~$yg¹¤1–³Â ²2¹»ˆY·*ªãг}œ”4ž¸º8±w~pù=ØSh²:ï‘A—‘=±ß*·u§Mæ'qs}0Ïxµ*I«b&^Jb.5ßìF4¾8éQ¼o©Î•[­ãc>LŽQKœX&?ašÓÈp&'ÄPܦÔÌã3xÕplqaj]LeGµh‹CÖS j{Þé≩±©:cÃÂÓéÝ>è5hÕʼnŒ+3°á@‘C/„PƒtÚžw:Ô5•húˆlqáÂ$;;{à>Ê:ª0(¨Ôqä|˜¶ŽëFý =¶ŠÂl·…õÃ.?W®»³ÿWÌ,(`GõAwÇ©AµÄ‰szWEѤ÷C ;XD|!C}ª—WB¿Ð…cŠ1¬ü_?8\ÇuÇ‘äj)N ì`Øk€‚ÚŽèIÓ €}ŸÀ†h†1&òÐ òPqbšqؼӨŠ0Œo5ŸhhÅÝDæYxçÂ\ “)Þ ªá´A ] Šß¬»–nƒªe<1Ú¢›x½`£(rÈk-o®ù[׌T§ ZÊ)%Cµ…ÐZº v€81<Ü9G½7Í›k$iÅøU€>È?^cªƒ°–ºJÖ‰81r…ªDO¿RWg8Ÿ'L¶¦Mîìb±wÞinˆµõ‘9éqbÜjwri™ð½„Î{Ê“Z3vl+öù-®K:P§›‹ë«Ëõ9+¿ú꫉81rÃÓnXT'nñkV+rÿ£rû„o;‹¿~ýÍê{®®ÞNĉá5ÂCל8±÷Á5’tpEY…~’ÚSëæÌ}Ž}TIÚE3 ˜˜w#\(…î!4®¹OF8»º!Ô]+a­Îzl%µ§Ü㖮ǖ9!iŲtpCÝCÜÇbM_*DÆâVÈuA×ÁJX«§[‹Oy_üé‡åoòcšswç§ /+'ñxè ñ¯×°jÆÏšÖÉÇKw4sêl+O @Ì{ßЋĉl¨õh C~bµ ¬;`÷.™ñÄFœ f6(äXacâÄÆxbê⽞' 0âÄ4ãÿÅYóð3$ñâIEND®B`‚stella-3.9.3/docs/graphics/debugger_banksimple.png0000644000175000001440000000705312205116016021625 0ustar stephenusers‰PNG  IHDRŒŒ0äsBITÛáOà pHYsaa¨?§i ÎIDATxœíÝ=rÜ8Àqjj À‡Pêȉs¥­Œ£qæR´ *ÐD[›Ù‘æžÔÙ›8Ú´áÀ7Ь¡±øx|x ýÿ•ËÕj4@ÝÂ>š¸úöåãv÷Kë p¡ˆÁ´ñÖ@Ï_¿·®ê{wûªud |‰À£âŽ%Þþç¿ÿ³s=°ƒß?¼u¤Ï40p8‘~0xT¼³Ð•ä|°×gÂÑ€ 7Ì£²7wî¿æ5Ѽ¬îA…’Û^½Ù{]´×…w™_p¸;‡¼¹{꼜õáÎ+Wxä+c.Vcÿ«-‡Ø*—ÀH|7Ém†ÂViÈFj>©Ëì ù†FÍæÔ»Ljüýà¹Í¢mº©Qå3,ÏD“R¹RO†Õ{ín’ûᔇpVBøõue»9%ZÛ­“ÜêEÇÌ…Æ=Êkš‡o©Sq+¼žnÒ”¸2B®)=ö^s!)Z²&Õ+ì·€Y_1XÙnN±Ö6LrÙ’¦ $ ñðµ:Ûå*¼ÈÂè±’üF——``}Å`½êíuy¼$â®ÒG£&ñX&TÞKò¢2.RŽƒÃ΄0t¬Ée+%¢ ­*å}*”«5ÄaQLjÁSæ€ój®¬$”HÅs®Ì„ùàºÃBc°²UÒ7^Ê&u‹Ö°°ÌÞ:…6ú±‡¬‰R÷ŹŸoU”P óÀIÖY†,®Âa¾©áF÷ª\ý‚G*U™¤ÿ>‰m]´ÜOuÁ5ÇÚºvßÖùæþìÙàÙè#»ámgï~°Ü¢ÙÖL óvU ž÷†¯õ5I€±f>xHÇêf ¯Ê€3èƒ[’âb¼öôs>˜½í.ÇÍÍÍÄÄápæùàóùܺ"´~öƒçv‚<žw·¯ž¿~ç8Ⱥh°ƒ_ZW€ E   b0mƒhƒ @Ä`Ú Ð1€6ˆÁ´Áž ]›ï 8®óù<ïÝ"÷îéé·ÖUØN÷©$m ööUþ—·Ô®«áþ¸Êsåm\çTît 8´Œ~p*ššmÊjD_À6_“åöhÃÎ4l®¯_‡ÏÌÿRϯ¦ÚŽÛ?CÝ,Ñ‹¶<Ƚ€àÚ|>øÛ—s/vùßVÈòx)!:@Ê(nO‡ߎF…?þ+?Ö¤njçÙ*GS¯@÷q“ph1x5ŒÕâ†êð(Ëxôù…;|]}´¼¡¹¡÷:j^TÐFTxyÃÔT^å•€Eö|°!z-àÜcMÖî©­’Y¯o¢“&Þ Q©^µ×áöx¯t W&)뙕E~ýji¼;${,ÚPKôÅLE—7ñÂÔæ¤ŽpB¬M™_}¥0Z.¤çÖ³äõóUЦ. ,,óÁ%ýZ’ŸÊ{ˆn®À€½aUy[yˆ†‘f»Ck™W«D?@.㚬{ÃJ…Á{ê;T{a @® ë¢ÃÕÎ…‘L.pIò¢æüc4cõî¯dT¶sú¿”gm¸8šbT§Á©õÉ©TM®¬ÃŽ•uÜÃEå…äyÍò¢\t]¥Þž†;¬0€Îq¿è¸Ã¶a—Î}Y4K4£æXn.¯aŽVR¨†­†[Âð/7i»ã1ø¢#¥ÊWj’ä,†c /Ø¢†…Rwáðž!è(ÄþÁ¨ƒ›5@.úÁ¨#5F H!£â.d!÷NØüphWÇýN‡Æš,Ú`,ºkÏ_¿·® Èù|þýÃÛh1¸wOO¿µ®ÀNXÖ£‹÷þÛa7À7wó¿­Àþúž7AšÿU ÃÄr@W2b°Èg­ìv;ªëë×Üú 6•1¼ì¼ü¿$¥v _é%¹%(÷JÒlkË{ ©Æò8̵zÊ©\n^Ã·ÂæÝ¢ÛTß«€nÀÖê¬ÉòÂI4’E¬x¬°äå™Ô VnQ¬9V*W¡%ʲ‘-Œ!//à¬,™Uò»­æV%òÙ )ÜÌ8ä]7 /#ÆÑí SÛÿ…Ù£¹ˆô°:ýàºÓÃr·µáT´0­Ìµ…%”jvô:ÓS,*»enYq¸tÙ18:»ÌU*mÏcÉÆ¸Ç'Ý\h¨þ=:ö Šò±„aóZs´6¶1v[¯TŸ‹x ;«ƒÃ•Ïš0͵–„c…ÇõJó^\±á±¶Ž*¯f ¨^€~°oRמ¿~ŸïU¦Þ*ªèz«p¥Ut8ŠÕ×Pîtºç~у[ÖXMN”uŸ xk­‰Ä°bð1„QPóLø¤÷'ýáÕõ{¿hÆF   b0m0Ü;aógÀ¡ñÝ$Ú`,º_/w/ß „Ç<æ1y|èÇS ýà~½Ü=þñþ}ëZJýúéÓU,Ú2ܯ«/§¿ï“èÍÃÃgMýðð9€'} ÞÿöÈ‚Â}…w(€Uý`o÷܆Ëvh¡Î}Fß—»Ç‰±h8¾—»ÇhWظ&K¹9*º¾~íþÛùÐÍ t³„Ù·”òM<Üyåêᣥ,¶Vɽ•ƒ¶êÌ #Õ†¤¥Ãn5˜zrÉåmDèeÉ*pµ†ÑcyyKzØó|ðü8kߤñÈÍMÛs·}à7kHÂû5ö¯r=<|ž¦)œ$.„c¼n5$-á-ŒÊË“Ñ^¸W¦[`ôˆrB …c¡º¹K…aZ@ǵ÷ºh!PyI†¶g\=Vyeäù`w`ïA¸gp4W¸³a4WØÿ ÔT#+dÊ!67§*/$ ç%\yåÕ+¯¼òó{Ö$UlýgcR¢V¸Ý±4JgJ½_¶_½0U™ËüK„ÝÌà)¶^:5¼ÉXô"œ6¶E&º˜ÑíÝSÑHnY¢£Ùáóš—FãP @±†åvÖp^•r¹åzSà©©‡Õy ågC®‰²B®Âc oAV Sï—ð°](!—ù—«ƒõ½[ÆlõÜùà)è~•ÿ!¬,A¶•©,Pn³j%Rý•å¹Üì­šÚºç=‹T -<–{ÄÕ’5±³·Ø*¿¼„áÞ,àåG·+\y>XJ³"nyxÖ—°ÃŸÛ}çXîøz®;-oh¼cy§ìÇÖ=– I<–uÞ›ÏÝv^˜PÝAû-tþV¢ºŒœZ, 8Û’”Õƒœ¼VÙM®‹ö ¬5næÎÛ‚Mth«¤JÕ h† k…á=ÏËFžþì0–”3¿)áD€›$¢¹Þê%¯¼<¹t…Kçƒåð£‹Þ4É–j8Vø¼æ™Ý¤Zs¯Âd+Р$ ×½PBæÒj•\kþb [Œè¸3¸Â|p´&%—Z^Á°Ñg‡Æý¢ûåί£ýˆ-Ú ;Oš_]!Wõ«P¶›Â5,©aôÊË–×{ABå…\újlq¬T¿ücãÍÚ¬^C÷eÑPÑ?e4¿za®T…·øˆb«wNͳoÒ«½žÙ³Ó4ÕXüÜá¸+ptú=ÞݾŠ&³ðx8µß$àXRí9cÑÀÓ úD î—÷ý`\¸’ J6]Úð~Ñ\ óùüçŸÿZ}Ùét?ݾ&3<æƒ` ©öœ @ŒE÷+:Üùâšè(å:ç~¹VY‡EáÚ%ù^Ç“X[ҲΫzæƒGP~Ÿ­*&´àæïÑ ÷aÿ€H݆ɖTí¼ª'ˆb,º_Þüp»š¯íry•W8º‡DIRu¶óPß>6yË aôµIÒêM˜sï阕+š7ר]ºQÏ 8(bp¿”ßF_÷LšÄQea0Öp^«„?P¢ä~Ã_0ŸWõ$àÂ1|AªÏØ•تE6l½­‰yÅ“í¼˜öA î—»ð´Áne©õ›·L7»æS^ê™5ºô;\õVx“¬nÏ ¸¥û£9ÍwKJ ”å 8G“ª«rwFÛRí!ÃÕ¨çë¢û•š?X%„gårß’ìu3îÃV=¯“íý¥bHª®óË\惇e:®ž4­}5µ`'•Ë6î]ž+z›MÆp¶ÕT—ù¼ìãj¼mw‡ñr÷øÇû÷š ¢Q˨Cµ£žÐÖét¯Ü³á鯿¢]aÆ¢ŸF T£žptÄà~™çƒ]IµçÄ`Ú`MV¿¼ïºrssóððYó2¾ @eše³Bœf,º_ÌÀ˜ /Äà~¥ö› û°‰ÔŒïêl1ýà~1 c`>€MDû»š%ÓÄà~1 cHµçÄ`Jy½^åv;Äà~1 c`>€ -}_ýž³Äà~1 càûÁlKßžÑîóÁ0æƒè 1¸_ÌÀ˜>ªÓé¾u777ÂÞÀÄà®ýúéÓ<‹0ÿ Åcó˜Ç<îèñ‡·Ê×O·ñùà«o,ü æƒhƒ @Ä`Ú Ð1€6ˆÁ´A   b0mƒhãŸ?dáó¿XIEND®B`‚stella-3.9.3/docs/graphics/debugger_main.png0000644000175000001440000012551512205116016020430 0ustar stephenusers‰PNG  IHDR\xAbKGDÿÿÿ ½§“ pHYsaa¨?§itIMEÝ (ò IDATxÚìÝ{”G}çý¯dY¾ ìîæê@ ÄF V@²cb£˜‹‚sCœHÖZ‘]fžØ°m2" ^;~x¤¬… ‡ÅÈáA ØlXÅÂ2V0ÍÅ&ØlhlÀ7Éöó‡i¹§§ª»º»ªºªúý:ÇÇšßôtuU×ï7êê2OD  6Ѐ¤MŒÊšHO–e2™I÷ð‚KϤ5+\õwÑhmõÛÞK#8tÞI£4 Y“ÙÃÿŸOSé"Æ€¨´c׫ç›õVÖèÚ•€Ð²ÈeY&“]㥬!©jWF:V·‰›„Ð?ˆÁš½—Y9O¶h‰·²†¤ª]$Œ€=c„à°ï/€îbŸ"e™lݸ’IŸ¤/xpîuç¼vùòÅÉ×›½ééõÑ^ûøø&n }’¾Tc¨_µˆyìuŸøÇ¬G¬X»EDDöìÜLcXtîu•aŸêuݱ±" #ã¾? ¹˜Bý©©íÉÖ |ãFw@!ÿ7•ØÿNU7þe‘{×õzª®ƒÁ@ÈŠ#ýŠS„‹V¬;ÏåËÏ9®¯Q…€‘c„`¿í‹´¥V¬X»EY/Ýë}_— ##Kµß›™ÙWylùûC¿wy¹Uyªï¥®}NÕ—êú›éyÚö/“{Ç? €˜•9U—¿V5Øt*qHS‹ ƒz€×&åpeddi¯Ò ëGå×ëú›éylæ>Cè¶Á}›6ås€´©Fû¹ äBZC0qŒìÖ>@•òƒ±î!ºnÄLùguÓ%}޼1¹fÕõ©Ž)ŸKWw“餮¦’6 cBÒ¦Ÿ˜Þߪ{צ/U…Gue5éÿ±M9Ž=dòÕÎ&mdú^® Ë?K@ºLFû騦‡,Úðâó¯ltü—žIÏÐH] ¡ ëÊA˜ÉˆÕ›¾FÞØ,«.(¬«Ÿ±<Ü—C²&÷¨MŸ4 yM¯[õ~jÒOBºnÂÖ¨=×£ÿ\~†úœÞ_nU€W öLÎE@:lN¿m‡àhÀ¦_ÝϨcúÐÊúWþÚÆÅÈ?]pPü~1L¥=›„+mÚÍg¿½ŸØîs¦ÓлN_m*öõýªÂ¾&íf$€ai;J0” 0ذkà×ôü‚\…u$ty8G÷À IPRÐeôdŒ})…þ_þ™ö7Wý0–À^õþ-¾Vµ æڕ7½îØâ1¦ça`7Ýt“×ò¶}å¼XW5u±ï‡iT -(°5ÝÕfŸô)öþ_Ú™ö·!B³¹ ®&\Õ±¦ça`Cå€nÃK/±ú}ð%Ä %´µÔêB*ÂP»÷7µÑ¥¡õ[!aVóöi;u×d“@ÿvì:ÄuLŒr3øüÛíåìø‚ˆˆœ~êɃ½?L©¶o0à’e§Ìúú†½7s÷˜ÝËÖÍ ýÊ_÷å%çþ·#>ê¨ùrÞk_ÌÍ‚5ói0ª°oÍÞËfìÓñÇ.”e§=].yÏyòœ_{7 Ö0½ññM4è“ ™šÚNß Nh™!-É€å)¿ußgJ0ÄiblTdŒ5B@ŸLªýè ÚŽ]hË—b ù~ßach3ªúóÀ^¿âž`H²,cóð¹×ñ=4™©7QI&¬ñ×ôçÐééõÎËèkš±ºu­(×#WýŠ{‚¡`™…²;sL²EK´ßc j±ÿ !ÿÒMŸ¤/ÀµdÀòˆ½¦#ññŠydÿÒMŸ ¥/­X»eÎkÅÅÈUß/@èò‹£ËT;#~ç^wPû½Ë—/\{$;°è}ûWÎúúÙ¯;“w€<î©‚¼òë&Ǹ02²Tû½™™}ÆÇ„JuíÅk©þ##KkÏ7äcBé/ªë,¾nr ²<,~ôC¾s¯;8ÈЯˆ)À yÖ‰}´KÝ(We1J(®{GChLB‰ƒ Ó &„úW…Œãÿ½@XtC臡LȈ?M¥ ˜Žò±Ý†Uªï‡j݃\ùX“cl•â½£¿…¥¯Ñm]îS~cÓéƒ33û*ûâ õ~U}†˜©+Ž ,N.TM'vuŒ+Œ$÷€nò Wõz“©Q]Ë¢¿ÁD“€¹í=1Aã(ÔïmÕg‡ÉÏšô¦Ÿ©Lû¯_ƒKU€ir º,Ë*w=ê\¾|ñ‘P®jʰ*¤+‡‡6Žq‰Z*Žbªzpn²°~ñ!¼éy\Ô«î5×Óä<&#Š|>Ä„ðÀÔæ¾˜ôÉr D í`Bõ¹T®{“¶°Ýn}…_¡ÜWÝ?@Ô­ýf£ŸØš~œê1ú116*“YײuãJnHä\p!­;H†AêAXõÜfÑübX÷çªóøl×c»^>Gj˜”esôŸÉ-›9˜sCîo}rÝ×ë>{ú0„°Fw_ ªÐö=S÷Yar 2‚7¸b2u· [çiƒj€mG›¹?Û˜6 À·)«ëC–É-[÷%†~ÝwëKÞm>´Ç‚¦†€0UMÝmªÏ€à84°µ!AŠôQ¯ªušÓ÷Ã}—Z©ö¥¡Ô½nÊghmM°èÿóP}^t90›iøçk}?€àøX7å°©T¢û¨—ï"÷¶FhÙì“ô·´Ú… >ú1ôÍ*]q£Ýkªcò×›ã xbÐR.5¹^×ÓcQÂCyÝ}ñÝ'éoaª«gÓv 9ôþæûßÕè.bµc× ®cbl4‰ëDÚ:€óöŸF+"Zôß[E¨Ä¼¨Ï‘4,¬N µ0¡„jY–Éd&²uãʨ¯34Y–I¶h Ý"FfÑMÁèoðejj;uãQ0>¾‰F4Ö콬×òMCªX®3c£2™Ñ·ÛÒ…¼€€9`@CŸ¦§×;/£¯ËGݺÖ?”kŒ‘«~uÅÒ¸Ânäb©@„ÝËÖÍy­ïÑwªkT]“îuÀ†ÎàgœA+FìÊ/»þôß¡»‘&HÿZ ú¤=¬ËˆY ¦³1µ‰±Q‘1¦€>iCþ…êvÛnzLÊ\ÖßVû§zL÷XuM##Kµ»Ûç¯ëv¨W«kYÔ(á f…~!†€å@A0˜“2—õ·Õþ©Óô½–¿ÏÚ(†xm¯Ã´>6ÊB“oå©ÂÅ0ÎÇÝüªÎg2YUÂÅPvOŽÑÄØ¨òõù4 À°©Â>ÕÍÅãußsA>ÌÌì›5:É䘔¹¬¿­öOõ˜PûC_e å=‡¸åYñ?UØæZU¹ªk,¯«áßpeY&“]£ü#øKk–eì˜@D )}ŒÚ+–Uü?²º€L¤¹ ÖR íú¸OPü}pÑí÷ À@@7l@¦§×{/ÓçÆ#l„Ïg ÝHÀ>F%"]€àXÓð/Ë2™Ì„‘<¼ò9¥€¾B@ÂF¤¨82Ïǽºu mýŒ/>ÚìÜëÎyíòå‹“éƒç^wÐj}ÀÓA&£xt‹ó—_W=Ð3r'NºpF×|Üëâ5µ-«I½àVU_/¦äé uê°¯ðOŽÙÍú¢ 7»ê¾ìeË».fÓ ºúôßaûþW_týLCBÄÃô~úº¿y9]C¢¡÷ÓªóòNUß÷ýù⳯èÆGÈè?„¢¼I†HûQq}®Ï§›\¼“cúhÖî«WTæß³2 €‡ó*º©uC™r§š^XþÚ䘡·QßíŸê1Âb2mÖÆë.®±üz]Ùº°­¯.„𯪙L®;FȹièrcçðK_z Ÿ0ˆýwØžvôÑ^ûž›•Ó}MFãÔýŒî¼åQ^ªŸ«* ~ÔMËuú¸Éõ4¹fF°™µSÓ×]*`R0&ǤÌeýmµªÇøT¼–üÏ®®ÉgYâæ;ü+rM¦—_79Fu.aËéËŒ€„èm¬Ñ–‡%UA!Óý0 ¸ê¦åš„Ǿïg]½L®'…>XžžÇCö\&m2ôvsY[íŸê1¡ÜcÝ÷›¾î¢,À¶,Ë$[´d¸×™e"Š)À±´KW倮üšÉϵ)«­òºÓ6@H˜jDW›0¤m€Bøçî~v=Oqdgß÷Éeù!`«¢šRX7ÍEýC616*“YײuãÊÞ®3Ë2+×ÙUŸë%Š< µ•çbêkl{]@¤š†8u#¥0Üþ£ÛiêÅ~ß“ >LG©F†Ìe 5ÄëìÊgh+@«š&œ@HALú‡®ŸÄØwBœl{ ¶¡˜šÚNݸFŒo¢D¡ï‘€&êÂÃÃ?@@íQ_„áÞçü¾„2 Øw_c°MO¯w^F_!—ºu­(×#“~ÕæsçŠ+.¤q1„ÝiðªvåÍ_ïzŒîçl_¿ŠËu  bu#¸ê¦Dª6 i†:ýrˆŠ÷Ar©úK¹™ÞϺ²l÷ó&}9¦>X·ÖŸíŸpÍÇ@[~¨Ž©Û%ØôÜ.êÔ xe™³Ѭ 8LÂÓµë^)h© 1S™ÞÚ÷ý´Ñ޶êÕôzB꺵üT›‚T}¿ë{†¼ÒÕ9¼öÚkiŨ½jе§ÿÛÓV=ÚK9mvþòµP0÷@L7ºbªk“c†ÞF}·ªÇ ý=iò™ÅÈeè#ÀƒPwþRM›L)$Üš}ÔMïS98P &ǤÌeýmµªÇ ™i[äíFûÁ¦»qc£I\gH²,“lÑ:¹EóiàÁ¿ø€á~äÿ Pþ­X»Åú¦A&ÁAQyê´É1)sY[íŸê1hÖ‡h?ØJ¨–e™L^tMô×’˜‚ÊéŸ0"’ήÐ@ªŠAZÕ´äºuEË?›íbd^UˆÊH@Øàc³‰*¦£Ôb¹ÎP„:ƒ*fÀ‡NÛO+ÆìËÃ^þ;t/¥ ÇÎÄè‹«MBÁûè‡.¬+‡i&ëïƒDÕŸM¹Ü `#,š‹ó_­óÑŒÂRÈFàq $‹0W ý¸˜Lîkþ@ÿNöU…€ùôzB <ºi¼}†p¡]†i÷²uµëð™?BÙ<%FºMTø k–eÉ.˜­Ú0@µžYÝ1)sY[íŸê11 lÀߥ†!Ë2™ÌÔ›¨@€¿Ätÿj ÓÓë½—ÙeãÝH¾¦¯»TÜü ÿºÍ1)sY[íŸê1!÷ÝkC}Ÿˆ£1›«Úí™kþUý« ™IP1ô0ÃeýmµªÇ„þ>¨Û%¸øz݈Áü¸.mGðv/[§ý:—LŽñ}EºëTT!OLG™Œâ©Z—+=_£«¨j-/Ý÷maC;mhrO›œ'„{bR/ú)øC8‡Tƒ1Ýú~&Çø¼Î.ǤìÜëj¿wùòŃj‡¶õ%v¯Y]ý‹}÷UVËS…(ª…þóï¥"ÅÇ$ômÚ>!ÜsÓz¥ØO›RÈá! Å‚>•ªÔ HÕ®žˆ÷žR¯ôUíê™b85µ=Ù{CÝRnÿXuY㇪Ñ}ù÷º„€€Ð“|´_ݨ@Ugìµ ÿê¦hæç-gR¤].¦ WÝóò±}Þ˦S‰môÓü|ôa»|l¢ÒWÈÕÇ1MëÊ5ÆÈU¿ºâŠ i\ ‚˰›i¶é+hÅ ¬ª©B´â1åŸÍ¿nzõê‚zPœê»f÷U­B@m9“)šª€¤*Ü#8qs¿mL69O1ðmD÷U÷6íC?C9p+‡bº°® ©Â4Ý1åPQõçªóØ`ë|€°&œí²tTÒîc©ÔÁ´ŸöYÿº]:›°¹Æ$€ ¦AXLk–Cͪ‘‹]@v¯YÝi °ÈìiÀ¦ém×´µñaBúR¸¿!öÓ™™}s?Õk©+ÖW·&¢ªíbªŸi½tõ«k#Wר¤üÐŽ±U¯>Þªk2Y3thëŠ"]Y–I¶h ׉J&SwÛ°qžª‘ж@O\Mûµ­ní³&tÓF„ÚO]>”·]WÔ§r0Q÷uÝë¡iòé~Æ´M\\£iù¡c«^}|Öaè&ÆFe2 ãZ¶n\ýuEÕÔݦbÛ•˜ÄÖ}—å#ø§C®—ª,Ó~šR?n2ªØw½UAG>2…$¯G“&¡”Í6ª»F“òC;ÆV½BîSůÛ„.–@‹à-l¶F†Ž<*nþaû½ê!½jèŽQ=Ôëv÷í:-¸ncˆQ›×Ý+Õ}osÏuýÇG½l]s›z…ÜO]m— p­*¸)ã£B¸¾ë•êH³”GÐß3ºÓäHMq£ª×Šß3=OÕñ¦×¦bk@@ð Ë2ßääܺuÓxÓµ«^3¹†®×‰ö÷ªÏcb«WÓ~ê³ÿªÞCî‹® ÓúÇî´ ÿ|×/å ›€¨Ž©Û%Xõº¯)Àì ‘h³îÓ” =¬h²[ê#»†POØé+u}$¥©ô€j€à´×d6 €¹ÐH¨›Ÿþ³™¼xÏQ–e’-ZBCXuxñùWV~ÿ‚KÏäDÎd”Ã?“º™´Qß÷(´clÕ @vì:ÄuLŒ&q¡h³„¡›}Æ@Ë\múãƒÏ `š0ÙD·ƒiÈaMùšUuÔíΪ›m»Þ&×hZ~HÇØ¬W_}&ÿ3$†(”P-Ë2™Ìô¡K,×–P²/‰‘~ c£"cü¥Õ…ºÍ R«“Ëã\\£é±¡c»^¡ôÝ÷Ë¡fJï# Ûš½—õZ¾é4ÕX®éšOé"ƒ°{Ù:+Ç åºŽ$¦ë6aj0@|¦¦¶S7®1¯+ „d÷²uµSqMŽqaÍÞËjË69&¡¬#Ýf/l€àÿÒJݸÆA¿'XWè,äð/Gø0¿öª6{að—~Dƒ@S1„9BÀÙõD3U›½0A™ž^ßé秦¶sŽ„ÏMÄþåá ’wîuµß»|ùâÖçkó³¾ ÜŠµ[”¯ïÙ¹¹ö¸ò1„$ÆÑt1ŽZŒ‰Í°Îä\ç^w0ˆ€]€ÀëRˆAÛõÑTAÞŠµ[޼^ü³îWFF–ÊÌÌ>ã×C62²tÎk¶êд=\^K(m;ÿ›Ö™ïãó‹)$üƒ+Œ„bPµóÂQ·ú 2ó2û RS wSÕgøZØÅ-†ð/ º{å׋ӉuÇ›ëCÔ #üø¶mÛ6@°V­Zå½LÝÃp>bÈÖÃrÊÐÌÌ>/E›!(†~„€ñ 9$üó§¼`9»|ùbeا:Nu>Õ÷™ €`rËŠ¹ùƒ¯ê{>t ÉBiÖæÊÓfC™ºÛçõÀ¯¦k„ª‚³òkåeÚ–ezŒÉçbùgT!`¹,݈ɺëõY÷!Oë6 ÐúÙB½®™„qÅ0”¯+@=ø©xu?çâA2•‘r]Ã;UT…q®0uw8Ÿ uá¿­iÂŲª‚ÁÖ,Õ›MñYw¦ufR ÿDÐ2èã±m¨ú9›fÏßäZÊçíšåõëá_úï÷ü=_~Íey.ÆåõëvW¯;ÆU=šþ#O,²,“lÑ®N0ÐÖ>EW}à]4BÂö_¶Óó‡42¤¯°ËU¸•ÂÈF¿áè#üoSN]çû<¶ên#Xô>º216*“Y×RµùV,׉ي¡Ÿí°¯@‘Ö¹%Ô&,mVöЖ鿗cfëšMÖó ­^&Ó{S™K Eð–6›vè6)ÿYìå?[.Ç7@=PyÑx—lh}Mÿuþ*¢©Â+“€ÐUˆhÒ¬õ‡!3ÝÄäõ&A» w¦‚MóQ£ÿºn¢ýØfDdñøüÏmÖDT•kzÝuþ…õù`cJ©êÕŽº¾®Çeû¨6N©;¦ï{òç6;4]Ô6$ê3\²U¶ê}ðþ¹,Ëgøçk£ë5}¶a9 ó9•:f¾û@*|µ÷¨FkŠŸ.À09fÈʾGÚ.3¥)‘UuJiÔœ«õåTLÌ!`J} ÏvKá3ˆ Öôû°W÷`Lø7WJí¡ yb®_ë\º<·«÷cê# ù@X¯{0f º=RÐך†.]Ÿ<‚¬‹Ï¿Òéù/¸ôL»k÷™ìÆÙuÇΘÖ4Ñçzy1K5Tt]¯>ß?ôÁ°Ë"¨ÒF£MêŽ1™Zhkú¡M T;¥º*O7ZÉf9ºõ×bž–ë£>©µ›¯÷ª_Ç.ù¨ÏþÖ׿©ô 6óDä¡.'`ôD܆¾žQ×õ ·óNz©ñ±;v‘mÛ¶õzÍ©}æºáG{cH¿3÷_¶¬ZµJDD¶n\É €L^tˆˆÌ§)€t1àLè#üº^?#Ä€€@Âp榛nJº~Û¾òn2€à ù¦KÄbbl”ßgÚ ~zS7‚nÃK/ úç¸1=½ÞySSÛ)‡r(‡r(‡rf•ÓæwPþsE„jY–Éd&²uãJ£€–­Ù{P-ZB#ôˆM@€„1FV¬ÝräÏ{vnn}L[##Küyff_ëcº–Sü~›²L~¾kª2MÚÌV}Êç19&”~Z}LΑZ}|—cú^£Ýì÷·ª¶wUŽO»—­SŽ"Ô½nëüH  7]רëûç!Y±vˬ@¯üµé16ìT•uÇt-GwΦeÕ]»é1MêdÒf¶êãêÛW?H­>uçhÇPŸåti¯!·›íN×ö¶Ê™Bû IDATi»> ¦ ’*ÈÛ³só¬Ñ~&ÇØ Iò‡ºâŸÉ16ÊqŤœ6×R¬“¯º¸â«¤VŸ¶çhü„TŸ>Ú­k@?Ôvsõ^0#ÎÔí² yçjt_(T£äLFJ…úðYõ ÎÃ2àö½³v+>¹hû®åwùõµ#qù4ÞÝËÖÍz½<µ·îûªctÇ!N€¨UÍ—ZøW|0l²þUŠþmFê˜<`ÛxØï« b¯O›úhÑV¾ÛÍÆ¨SåÄ@µ–_ñ5Ý÷ëÎQõ:âC€ZC¨z0¬Û<#ö‡HÕÔ¼6Óõ|­™ç³]Rªü|^ÀÞûËFÛÛ(§8ú¯øZh£ÛtªQƒH *U­ï—RØdÊl,þ&AbìÛ!¿ÇhCÚ `°–,;¥òû7ì½™Fõ¦ÉÔUvß_Pi´½jô_ñ{ìŒØ° 0*©vó-þ39¦Ëƒ^9´RmÎQwŒr\=Ü·]ËÊ…P _ý µú49G—¶ ©>¾Û-•~àósÔþ±£Ó‡‡€¨e² ˆËBL6çhºGÛrt•M¯¯ûY_›LÄ´™…¯~Z}|µIHõ¡ÝÂ-G·Î¨pµI9!ŒðÓ­Ó×tÍ?Ý.ÁÅ×l•…pÀˆI çrM@_3TÃõù}”£z¡>¾ÊK­>”ã¾e­Ý\„©º@3vuœîûå×UÇ™ƒt0H °y"òP—\pé™´bÄ®úÀ»]ÿÕo{/`ÀÎ;饯ÇîØu@DD¶mÛÖë5ó™ÛLÝ.¿]±K0¿3C²ÿú³eÕªU""²uãÊhÛ9ÿ¼ c£s~—eYFÃhÄü÷”M^tˆ° ãcáõ©©í”C9”C9”C9³ÊɲL®¸âÂF?7>¾Idlv 516*“äJ„ýé^|þ•´bÔ†}ÿöŸO²óv¾”F`ABÓ9|ÿûßO+ˆÔÏh@ò˜ (¼éM»g}ýÑ®¡Q€¹^ã¯kù¬ˆ”¬X»eÎk{vn®í÷ÊÊÇRŽÿršC9ý•“×¶Œ6×Ú¶<úA˜å˜|¦ØøÜQÃåç@  ü€‡C=]ØW|½îë.Ê!*4°ñ@G9îÊ19†rú+§.0±YN×òèá–c*ÚúÜ©»v[å©  ò‘~4£ ûöìÜl%Ô=Ôu©D9þʱq-”㮜âq¶B¹ºkm[ý ìrLËvÁÅç[ìj¯VÞ1þ ]F™T…"6ËñUŸËA¸ïŸ÷<¤ýÝkÛŸ;}^þ©eY&“¤ô…ÐÙ¡ûo|ù‡róõ?‘Ÿþàrß=ÈÑ çË =Nžô¬åÔ?AžðÌ­—[·Æžë5YãC¦Z0ÄÍ6Ó×êÖ¿²Qޝú„TÂEøW÷ºÉgLÓ¾aìõýù¶fïet„‚lÑ¡G€€n wÜ-ŸºøF™¹ãîY¯ßïrà¶_ÈÛ~!7^ù¹àÒ3i, RùTÞº×zý,²ô0W7Ð×Ccjåª÷ÿ;¢æ³ÔV¨ öèkÀl€€ÖÝ÷À‘ðoäñÇÉòW?]NþõÅrü åÁ’»Ü#?øöŒd_½½—ë«¡÷íO\Yùýg¿ŽÐÈÙÞÑ7D¾Ö̆Lµæï1ØÛçõîe딯3j®ºÍ?ò×óMB<ì_þ¡ÌÜq·,~âñò†ÿ´LŽ9î‘_+G-9éÉ‹ä¤'/’ÓWŸLc0p¦S4¡P…}»—­ >Œá1×|šxÄG?º¦ò?³}÷k?‘¿ýŒYá€ô•w÷UM ¶±p”G ©¦êRN¸å˜C9ý•cCHåÐú+Çä3ÅÆçŽî¼¶?߀”ð´hí§?ü…ˆˆœ|êâY¯_|þÜ©µ¬ÄMµ`Y9´9m¸nsÕƒ«ê8Êé§Óc(§ŸrT¡O›òl\+÷'îrL>Sl}îÔmb«œ¾©¦ GßéFã•_oržâ±ºsèŽA¸!""ï|ç;i„Þÿþ÷Ó´ûïy@DDŽ=>Î_'¬ñ˜3 ó\®X÷ÐæjayʱSŽ­²(Ç~96‘6÷'­rB)ÃvßvÁV¸gRNÝyÖì½ìÈõ计úŇ³”­r0è;ðÊËï«\Óv†já±GÉ}w–ûî>,Ç=zá‘׋£ýT£€¡³¨åÁIpØäš@@kyÒ£äGß½S~tóòÌ%¥A€†T!^N·[pSmÏC ˜@¡¯‘~ºyæÒQùÑwï”ë>ó¯ò´ß8IŽZÀÞRº›šÚN9”C9”C9”㽜>éB@“®ø³º ‘ €¨ä:«›J«+ßõÔäÇ_7ëë‹/¦/*§½üÉrã?ý@îøÞÏåò÷^//zÍ3䉧œ %¿œ¹On¹á ±ééõ^&)‡r(‡r(‡rŠåô­*À kƽʃ;Ó5õú^“Àl ] ¯¹àtùÔE_—Ûo¹K>uÑ×ç3ÿ¨yòòß}64Pܘ£üºîت§ÍuþŕڎÐs}¶ÊÕÕ/¹<À\£'/’óþË ùú•ÿ&·ìû‰ÌÜq·>ô ,Z|Œ<õy‘¼ò©2òøãi(àWt¡Y›)À&ÇšN%¶QÂD#®‚¾rW^ Ð׈¿òy/¸à+Üt cŽ_ /zõÓåE¯~:$nÅÚ-²gçæÊï窎kcddé‘?ÏÌìk} åôSNñû]ʪ*GUFÛ²(‡rêú¬ršœ£Ëû”rº}¾) D¯š®ñ§±ÇT`ÜËÃ?]X~½.,lú°W~ðV=äÕC9ý”£;gÓ²êÎkpRå´)Cõº­ú˜¼l¼O)§]9@*aÄ×H¼ºrÊ_›®Ø´Ü .`ê/EÅ0OªÂ¾ª°°ËÃ~þàW|ÝäÊé¯Ú–Ó5d¤œa–c³ŸöÕ÷)ÇO9:Y–I¶h @0aÄ÷nÀ¦#ÝÕ)Àä\†{¢6#V»KåQƒå¶F²QŽŸðoblT&3ÞG*[7®¤zBˆ^µYÈ”_€¸5&Ù¶ŒXG}QNX嘄mË2™šŸ‡YůmÔrÜ!èBhaÄÕÚ{mÞ×”dtW~×½„È$Ôk;ʬíTû¦A#å´+H  *…¬Ù¾‚CÀPä»ó–§ìÞö£ŸÉÛÞýaùñOï’?>oµ¼åugTþ<Жï‡nF±QŽrBŒX›/ìr€XbWkìÅ×åW>A£’óýüTÞöî¿“!rþ+å ç¼H{¬n×_HA€”BD ÀÐÜrÛOäíÿùÃrðÎ_Êæw¼Z^sV· MwnÃd!w‹½SŽ»rT\–Ó%¸¡ÊqÕ‡ÛžÃÆû”rìÝ3 V€ó½CÞñg‘Ÿÿò^ÙòÎß‘5+Ÿkå¼yXüÚ“…Üm,öN9îʩڭÓf9¾úå¤_Žnʼ<Ý:–m‚íºst­3å¸í+@ ó¦7í®üþG?º†F`À¾uËíòŽ÷|Dî¹ç~yïäëeåògÕþŒ.ÈS½n3ôkóPmãáŽrÜ”cëÁ›ûC9>ʱ½‰GeQNútëý"€É(å /ÿ~þ_A`] Y§î:ÛžŸ 0To{÷ßÉá” ß½N–Ÿþ `a….XÔmuAd]°Wxµûî?,~Ô±rÒâE4À@¢“rWöLƒ:Ó‘‰¦#ËÊ×£»¾ºã›^/`Û¼ý§Ñ:ùËw+“[?!¼ùïä’ÿrž<ëé¶SåPåPåx/H ¬0 ÔÚÒMG¶½~?@*~sù³åÏß¹V6¿ï“ò¶wÿüõ{ΓSOybP×8=½ÞËÃ$åPåPåPN± e€°¢ëZ¦ç5 à\MvUO|:ë¥Ï‘C‡~[ÞsÑ?ÈÛÿó‡å¢?{“üƳŸLÃ$ŠVÔ ³uþ¦ÇÙº×õÀ·³_~šÜwÿaù‹|FþÝŸ}D.|÷:YòܧÒ0 "LD9 r5·­¶Sh›ß6 3ý9‚@@J^ûŠ¥rßý‡å}—î’ÿõcò¾?}£,;íésŽ[±vËœ×öìܬúÀÄøøêÖÞÓ]OÛŸkzÛÇ÷Õθò†s–Ëý‡Ë_èŸä[.“¿úÞ +–M€¦úöFF–Îú/%¶FÙ @›Ò&ÜCç°=í·$ª‚Eú)†Œ)À‘3Î8ƒFzrå—‡]ÿò:€}„M§Í†þ ]~píûa<¥v«;¦+WÓe]ÕÇG9)†*>úRHïk_ÓÍ}~6©BÁ!þÎîëw7ÂB€Z&kº|€K‹õÊúzÀî³Ýbï/)®8´þ†°?›Xx  a}¿”èÖ¯êúàlã‘Êû×Õç[ÝùR_ßɨBÆÆ”`WÓŠ ïÏ·ªóP#@cåѪ¶FÚ^(¾êa²nº˜éN“>ëèB,íæ*œ`Ú`¸mC³ýþ±Q‡!öë¾ë¼c×Þô c£4BOPËd<¬:¦ËCœêõ&Ç´)Kõó6•esØÚ­MÛ¶)¯îZU;‹ö}/ûfÚ&6úA(ýÍçûÇÅõºèס½7úÚ„ðO-Ë2™ÌD¶n\Icô€•šy®Öò¹‰ë²ºŒàqQ·”ÚÍæÃ}Õ¹bÚ˜#¤rbªW“|1}ƅЯmüœîx—Ÿqm¬Ù{‰(È-¡z´`Æ "Â0L EŒðìÜëÎyíò勃¾Þ¯Õæmذá!F@•|mÛ¶õzÿøÇ¹@Oþ|ú„ ¯oÿõg˪U«D$îµuX7 З,ËäŠ+.lô3ãã›æüÞÍ—UMÖ…i!‡l]¯í’_Mf @¿&/ºFD€ÀLO¯w^ÆÔÔvʡʡʡœYå)#@y„É4áºcŠ#÷ŠÇ¶)KuÓ‚ã@àÑåËW†q"æÓ„ëŽ)–U š”¥:޵ã@€Z+Ön™óÚž›+S}¿‹‘‘¥Gþ<3³¯õ1&ç/ËÏ¥:¦i9M¯uddië2Úœ£Kyu?ëúþ¤ÖšÔÙv}l´_ õ©ëß]û‚¯ú¤öþñU×ÊÁZù5—åµý‚¾x Òе[´a_ñõº¯»(?xëÄ뎩cr|]¹¶êS÷kãAÙfyyªêâãþ¤Ölmêãê}S}êÞ¦}=”ú¤öþñU_t#ñTÓrËLŽ©*Ã0Ÿ&@uaßž›•#»† ùƒ_ñÜäWš–cz­±Žü3­‹‹û“b?ˆEjõ±ý^äÚ}ÿ¤Ð'MC»Ë—/VþW}k;"Pw.Å4“MŽéÊ×t?ŸÄå‘7möë¦ú*'¤>K¿Ž­>m§uÇTWêãJyâë]Ñý\×ëAÜ€‡¡C6ø¼ö®#qÚš®Ê ©Oºè×C¯I¿QM'm3ÅÔG}|½|}Žú¬K&áZÛcÚlÞQwŒîû„„q :>XÇÖ=4·9GÝù\´›¯r0 &ïÔ¦÷õþáóp"ò¥/½…FX}è6yhn{`èï  Z)îü›ïø[·3pÛñºi\1-^?Ä…émԹɔL×åÐè×¶ûO×ÓçhèõɲL²EKøË‚A€Jy¸§z½ê8á_ùA®øu›cl=¨–˵]Ÿrmêeã6u½?ºµÕtSü\—ã£ø¤±Ù&ÔL¥>¾>úxÿ¹zÿøj·ÐêS616*“PÙºq%Ð@Ô2 ól†~mÜ»<ÜùÞ(¡ê\>wîúsºãu!­:¹.'µ~@}Ú—í£OÛª÷Ojõé‚  ¡™Oé"6oÆ ‰<M®5•ú4¹‡ô·ÙçêZ'_õ ©_Û¬@Ô*‡y+Ön©}MuL[&mª‡¾¦{&Ç—Ïëªê“~}L®5¥ú˜Aô·ú2Ú–å«>!õk娴{Ùº9¯1J¾° Û³só¬Ñ~ª°¯|Œo33û M&]•C}үɵ¦VÓŸ£¿™×)´ú„Ô¯û¾?e»—­“5{/›óŸ*\` ’Ô6X(?–G0õ5¢„ú¤YŸ*©Õ'ÖÏ‘ûõI§>Œ„/€ˆú!¼É1&åÔMU+ ±bQŸáÔÇDjõ©»Ÿ¶êãêúúêo1ÕÇçꓫ›&\ü~qaùÕèÂrØhRVþu¹Ü&çA<k~5Ù„ †5Ù¨OØõirÄ^_Ÿ¾ÊðubªOH} ¶ÅÀ­êõb(§ú³î\ºó莩 ›\3úG¹öÚki 7¯¢ "£šþÕUÕšR®*©õ‰½>uu‹MŸ÷‡ú ¯>MÙ ßòÒ@00m7 1™Œð° 0+ïú«ÚñWµ3°OMGy˜ì ©ÚA2ÔM¨OØõ1¹ÖÔêã»)÷7Ókô]_ý:†û:Ý®Äm¨ÎèÁð0µÊáž*Ø+‡€¾Ã¿® é«Uçñµ¨<õI»>¦×šZ}ø<ÎíÚ¦,ŸõñѯCû<èÂÕZymÎËH¾´ R“ ÏEè×f—eu-úPŸåQŸøû›­:…VV×r|ÖÇÕ®¼ùëMŽ1y]w®º²tåw­Â@à˜I(VwL“0°Í¹Ê¯Ù¸f„5€„ÍÛ°aÃC""c£´hìØu@DD¶mÛÖëulܸ‘›ôäÊ/¿*èëÛýÙ²jÕ*ÙºqeôŸ·ø–e™\qÅ…~f||Ӝ߻ùï²¾FƹZW°«K-‰þï)1š¼èa 0Då¡ÓöÓ@_S2=½ÞySSÛ)‡r(‡r(‡rf•cS–e’ý*ðò®Ï²,¦X K=Fÿõ‡€t!4€¨´bíí÷öìܬ=¶ü½®FF–ùóÌ̾Öǘœ¿¬|.×å4¹êg}Bê×¾îÍvËÏWõs]ÚÍ×ýI­Õ=6)§kLËèR;@Ô2 óV¬Ý2ë¸ò×]”ðT|&ÇÔ19ÞW96R©OØõ ©_û¸?MBÓ¶Óµ‡vóuR+§îœmÏÛ´ï˜ö `(X©Â¾=;7WŽlûК?`üLޱÁW9¾PŸ°¯5µûcÚM~FÕ6ÚÍ×ýI­“r|õüz€!b Pz¨Ô=,ªF…>š„ú0Ú'”û£:¶ë(6Ý}Gúý,ôû½c×n”¤ô‡µÊ#ùl¯ïòCeùµòh–¶k—馩ÕC}â®Ï~Êý)—Gp7\]úá_œ²,“ÉŒ RúB€Z©~m(cY“ú„]ŸÐú¶¯û£:žpx\® ’5{/ãfd‹–Ð=":<´Æ<ýú Ö÷!âÆûð “)Ì@Œv/[§|‘„°]€ЙjÇ_ÕÎÀmöëvù4Ý ´ŠI€`£_¨OØõñÕ¯Cº?¾B:íæëþ¤VŽî¾‡ÔgC‹×ì½lκ`З¾Ë‡Œ@­r¸—+|åÐæº&;tÝüAõð«:M&| >a×ÇW¿éþ˜ÞC_mÊýI­œºÍ=lôUPY>ÏþÄ€•šy.7 i#ƒ.åøÜ`‚ú„]å…v\½GuaV uJ©ïQŸå„J5"¯MÛ­K›QåPξÖç×½ß}}îøü|«û¬ ¥>¾é‚5[S€ÛÓæX„‰µL¼k·Ì:®üuå‡DÕCcÛÉ&–¶ëÎQ@6)¿M»µiGÊ¡Êi_ŽÉñ>>w|–Sl«¶ŸÝu?cúE:ukûùX—°‰5Й*ìÛ³ssåèÁ¶áùƒ]ñ!ÎføêÈ_íV>†r(‡rÜ•3TŶóÙf)}ÆM1àÁzû¬í2ÐÕgüôôzí(@“ÑY–I¶h 7Á €ˆ\|þ•4Лa¿ÿÊ#ùl¯ïgó¯üPiªíW6Ö¯29£Š€4™|øúÜéëóÍõç}~¬¯è™•ÉŒ¾­²uãJ¡'€`(Ë2Yµj `B üÊx®Ö´ý0k²v•êá–HÏP×ôYNÛuU£M×þ#èBhÀÿŠ C~àHmú.Ó‘¤ŠÌü#ªoL¦‡¢8 3v@gªU;·}P,?qÃŽ¦u6i7mK9”C9Ãþl ù3À#+Ê! ÍuËÚº$U?×öaQWžî¡²KY&å´ êÚÍôÊ¡ÊqWܰñ{!ÇÈ?¤€•šy.7 1Ù8Ãåùm=Ü›žÃV0Ä (‡rb)‡öjW¾ïÏQ LF$lÞ† ™¥5Ы»Ð€¨§ d“]#"¯xÿ¡ÃrÎ\$=ø|æƒÿ^ŽYÈ’…m”wä;îØ£åä',–ñW¾@~gì…2þ<IãðÊ®«÷Ë篹I¾}Ëírç/î‘£%Ozüˆ<ÿ9O‘sVŸ.§ýúÉ4T˾xì1GË ‹Ž“g=ýqrÆ M^µêt9þ¸…4ð‹‚NÔ®üÊ7実ß#""»¯½IÎY}:wÌ‚{î=$ßù×Ë_ýÍçäöß)ïxóY4ŠÂŸý\þãôÿ‘›¾óÃY¯?ðÀƒrË­?‘[ný‰ìÜu½ÓÅÎSwï}‡äÞûÉz—\ûµïʇ>ùÙ:õzyÎ)O¤q°$èð“»®?òç»®'ì(ª~yÏ}òñO_'Û>úEùÔ?Ý@¨pøðò'ñ÷’Ý|»<î¤GËÄëWÊ‹—ž"{Ì£åðÊ~|§|ý›·Ê§¯¼‘ÆêÐï?tXü…ìû—ïˇ>ùùþ~*›þücò÷oO8ž†À‚`À[nû‰|ý›·Éóžõ$™7žìÿÖ¿ÉÍßÿ±œò´Çq×:zÔqÇÈ_ý"ÙöÑ/Ê¡CÐ Ÿ¾òë’Ý|»<ñ±'ÊßûVyÌÈ£yÓ,8Jžñ”QyÆSFeü•/ ±:XxôyÒãFäIgŽ€™›C IDATÈ™/}Žœ?õ·òÝïÿX>þÙ½ò‡ë^Ôµ²&€XdY&[7®¤!pD°àÎ_þ{Íš%rÌÂò/ßúìüüõòþðlîZG¿¼ç>ùÄg÷ŠˆÈòç?ƒQøÂ57‰ˆÈ½éå³Â?¸sܱ åü7¾L¦Þû ùêõß .™ž^ϼññM4f 2¼÷¾CòÙ«n”c.W¬|ž½à(¹ðƒ_Ï~q¿¼ã÷Ï’c9š;×Bq†…G%¯}ÅRyÇïŸIÃ(|û_ïx¸Í–<“ÆðhÉsŸ"""·þðg4–Ìñ¢v_{“üâîûäÌ—ñxyý«–Ñ8XTøù/ÿ‹üòžûåÅKO™þ‰ˆ<~ôDyÑóŸ){n¸E>ÿåoÈk_±”;Ø@qàÜQóçÉŸ·ŠÆ)9úè£ä}úFùùqÉn¾]¦ÿ¿ÏÒ(ŽûâÃïñdëäëäÄØ|[‚ 󩽿}ÖóµÇ¼vÍÙsÃ-òÉ]_#liþüy²øÄGÉé¿~²üÞÚ—Èo<ûÉ4ŠÂãN:Aþ×ô„üãÕûå ×Ü$ßþÞír×Ïï‘£^ Ozüˆ,yîSå·VFCupÌÂr⣓_{Úãdå²gÉ«V.ÇÇÈ^Ä%ßìBTø¡ÿ~~í1gñ\ÙsÆs¹s ä»ÿ¢ÅdÁQòš³–°ó4}€h-  hoffŸòuFñÚ±ë.Ë2Ùºq%ŸOÜ~GðÞ…!@ dzz=l||ŸOÜ~GðÞEói ]€@˜ #+Ön±²¡“­óäçÊ i³©â:£&k‘ꎠÿLÚgK(ŸMîA~lß÷ÈÖgrªÇ €ˆVþЧz`Lù!½øUþÚôÕŸ+9›ÿhóçJˆ÷ „ûbë39Õc¦ÐÂÌ̾ʿàÔ}lÃbnãºß+&K@Ôý®†„ÞõñðÕ¥ÌB6Fé}öHU·GÛЮÉÏp:@Xek¦×Ü2™ìBÕšK„€@|Ÿs0“Oå%¤Ú[016J+X¶cסú i=›¬÷gúÀ]øÆBè@º¢Ä†]€-#ü£ÍÀlªð¯Ñ3+ÖnñV®«ðOµÃ¢j­Áºc4ûì°øé>ƒ|~>µù\IéØüaë39ÕcåàÉ‹®¡eغqîÆŒj3£ ÿèÝúí×ýý hþðš?˜év\4}­êûåcÊ×Ó׎ª‡ ÕkÅïÙ,Ou>6 ì}Ε?SL>ŸL?ÃBÚg†É& !|þÛüLNõ„cÞž›"<°"ä ™r{Ñÿºõ?Ú¯[ûÿýdzz½×2ëF òPÌ6>¾i‡ëãó‰{î=འyN°€b; »èÝúíÇû>à»Gªjm‚â°ç&ÃÎÙU =VÀºµ``_9äÓµuþz]¸—H!`Û59ÊmÓÚmÚÈv]TçìsÍRgm nQÎÐèõ6» †š†£UýE÷³)´¡ÏP˜àšññM4>ŸÀ=@2˜{€tx ‹Bqʤn*`‘nºeqkuÕ¨¬ª­ÃU[†«®Põá¡Õ³ê¦ñÖ½Ÿu£%ëÞ)O³À5k`Ýz]X§ T¯«Ž7™šYÕTU&PÕѮͪ>'tk‰¦<Íœ®Øå8_׃ê…ÛïKú~õ¾ A]ÿê¦eÝGšqÿH›€†:Í”P†aÇ®4¼š¥ðhëÆ•2yÑ52?Õ ¶ +R 9V¬Ýr¤NÅ?1½/öþ~Àp5P·>˜nVÕȬº]€uÇÅ8Ú«®ÚüìPv»-ÿ¹n#™®}6º÷Wy£Ý1MîÃPÛ|aD|Q…“]CÃÀ«­WÒÉJhs›Uh“ ,mûZêýÇô=fòžk{ ïQÒGø‡¾ú! €!b @½!Œ/„ΆŒ³—^øOo?G^»fé¬ïÿß}7ËÆÿú±#_7©ÝdiÕòCh“úƾŒ ðgˆú_BbþבU«Vy¿þ¼¼SO=•^Õ¡ýRè´_üí±³5¢êØcŽ–Ï^yãœðS»oc9Zî½ïPës—+]èE°U߆l²Õ\¬ë · ÄMe×f²ž¶¯ë̶@„ÐÊ6ÓnÖV;v `‘­5®V¿øTùÇ«÷Ën?(O~Âb™¹ën¹úŸ¿%¯\ù<ùì÷[»æòfRž<Ü:ïµ/– Þ²Fûý®}¤`ÊÖ¹C}˜†Ð¼Ç ? D¬Ð/úö¨vZmëœ3O—¼z¿|æªå~÷å""òÙ/î—Ç”sÎ|¾ÕPäꦩF†rL¹NU¡Vù\m¦Z›Ž´ ÉeŸþgyí+–ÊÓž|’×r ¦Ú¿O‹}¹IøÃ€PZvÚÓåñ£'Èg¯ºQþpÝËdÞ¼yò©Ýûä =Q^øOs^~ÝWÓ‘\uǘœÇÖ1åzé~6ÖðΆxPÞwé.¹øÏÞÔëu˜„¹ª>ª |«Ž©;OÝ÷t×l,«ú_UÝ›öIÂ?è ”æÍ›'¿µútÙñ®‘ë¿ñ}Y¸`|ï¶òÖׯ”yóæ{ݶ‚“ó¸ 5†–¼ä§ÈW¯¿Y®Þó-yùŠ_ªƒ,ÝÎò1å×TåÔ§|.]hlrL›µûLB½!nâ¡"€Ö9¿ ?}årÔüyG^ nڡɴܦç±Uêýû‰WÈ?ßp‹ü~A^¼ô9faØ,>g[ï‘®LGô¹*Ð ´žòÄÇÈé§ž,W~å›2ožÈóŸó9ù‰ æúºLËmrž.Ç ™§Ÿ<*¯û­eò÷Ÿ¾N>|ÅWåÞð›½\GÛà*ä@ÐfÝUǨÞolða @¥WŸù|ù‹|FDÞÄ…6AÛPÁdZ¤­²|¶GÓz‡ìü7¾Lþñê‘]~­œ³útyÂcOôZ¾ipÕˆ1MÇñÉrÛm·i¿s«V­ª½'C냲­WŠ ¡[¹¼æ‰N“õ4ùWS[kÓb£Ü&ç´¹ˆµÉ}`±hÿڛ{ ¸Uý&ÆFix316*;vІÏU¡45íäÿèAˆd¸ZÐØ¤¬B‹¶»Òµ)Çd1i÷Ëg½†ªiðK8ÄÀôA†cÇ®Gþ<ŸæºÓ­§bCù¼ªrlŽ8¬ûZµÃ›Ëº8Ð # \UyÀVþ¿‹²ëÊJ¥MaÖŠ÷BõgÝHЪ)â¦Óëv­4ŠoRVñXú€"m.ëåÙ8 ±u÷‹ Æ_ÿ©[Ó±ìéîKñÔó6=ÇŠµ[zÛð\c ЂÉ& º0ÁvX¦ ä\••ŸÓu}Ôk¨šL•ízïMËRWÞ Æd¦HÕŽ]h •e™lݸrÖkóöìÜüM†»(ÿÒ‡´îñôôz(o’­Wù{¡S€€¤1``|N‘g­Ø8Œ,•™™}4è[F О›gý—ÒF8¶êS›ŒŒ,=òŸsÅÐØ¨kˆe•ïiÌõRff_/í CG€äBÀ!É»ü?•4ä÷³îÞ`‚)ÀHBÓÝð&ÆF9Dç§?§O×'h ÀÕTݺ©ÂùÏTíÜݤ<“Ÿ©»ÕŸÛÔËÆyTÇÚž­­—‡€mFñ1=>t飀v½¦A–e2™‰ñ¿ßóÓŸÓ§ë´à–Ih§z­Üé‚CÛA˜îœÅ×óÿ×…‹6Îcr=©É›ò¨³rˆ£›öÙô¶xL“z5=O¯Qí¦Ú%pŠmwÖ¶ëviïâ9Ú¶{qãÛ£M¦Wû¸¿UíÌÀà`„le™×Ý& û»tÓXËAU—ª.ë{Šm]à6¤¶lÿ>®ÛXwž¦Ç¸ø{DÓ]€Û\§­ëéª<õ´Ï`Å÷4غÝ{ußï:¥Uµù…IÝË¡Ÿ.Tíò«jê{oë^4©—ívØCØÂCk·<2M×SyåQ€ïyÏ­Vνn÷H•jC6!TÛàÊWàU¾ ©- —Í€MJ™N{­»–&ÓgMÎÓ¦<“DšcZ“Ÿ±±ÉˆÍ{Ѧ^º×ýýhšLu¨;Æt™º…žuSPêvö1 íƒo¾WÞª ?øæ{ç¼öV"€á1 ÉR¨£Iý†ÐÐ è[–F i(gc‡6S&eÕ}ÝTÝ€ª€¯ø=UØWÎдYÕŽ¿ì 47ÔpKôºù6Nr8£ l,`­SäUaàÜû“ÿGø¨é6¥èr>Û××m’J[€kΑƒU¡“n À¶á_Õ€1r¹Pv–e2>¾ÉÙµsþ~ÏÙÊ£ÜT£Þt!XÝæm‚*“²Bh/Ú@Jø½ šˆ>4Y“ÐFñõcblT&³f?ÓdçcÎßïù¡V”t;7=é÷MÊ\_ìm`X÷‘1~—sÑ€¶Ã>“óÕ­hÛ<¦ÀÖr(qþ~Ï7X¶0 L€ÀdY&Ù¢%Î˹dõj¹ª4]uõêÕ"ʦ-ÀÀtkº,Q€À0´™RÝÅêÕ«ƒ¨·j)mvX CÞ©5ßQ¶x}U×k² ˆ ®6 Úljæašêõ&Lj¨7ï(gzž6×Ý5ÜÓ­øÁ7ß«ý:÷Þú¡cçWü¾¶< vì:@#$nbltÖ×Gš„guǘp¶Îc³Ì*¦#øéú4=½ÞÊy¦¦¶[;ìü}kjjûœ×X°…Ö\·înnDAÓÑ å$œów;?úíÏ)Ðõ9Úh¬CŽ0Ö‡Ã1ÖÅÊ5 ²,“ÉÌ|m1Îûs t}޶;[Эè´¼Ô­û¨:¾É”lÓÕßÔêú9?|Z³÷²ÁÔ5[´„¶0l ’‘‘¥23³OùzY—ãRkÓcRoŸ¡¾glÞS“>†tûOùÞûì_|>¹AØÒ¯¾ÅË0Ú©©í"cé´›*ÐS}º°°o»×¬®*v_Å›Î{ÝAåë—/_ÜkYÅc]\KLm‘ï« ÅÑ™™}ÚDÕƒiñµªð0ä‡Èâõ™ ùŸMÐØÛâüžÒ7è?>úŸOvó Ó‚°…‡ÖnÙ°ÁkyÅQ€6§ÅeYÜT³< 5B  à\N&eÕ}=¤¶È_t­ ‹š—JÛT……ŵ ®¡z/¼ ç3×gy|>ùG©÷¼çV+çY·.¬z5öÛ§ÕW6έûš¶¸~r½M¦3: Uý¨KÐý,},mM—@œ’_°éÈÃ<$ljòËwXþ‚ªµöêÖ Ó­SkÈE[@º¢CM¦›ü†Ëv? Oá©Ê!êFFö±¦œn @WŒþPE|™„W>wÐ¥-®˜±e®¯Ÿ 1Ž> zöäÞ!µÏ#>Ÿì‹>´ð±F]¿ÊnñëîÉÎ:@Úìºk+ÜR•ÝgpÖg[ü=éÖ,+ ýá±x}USËíPÞX×VUëyÅÐ>hö¾à¾ÂôsÇäó é&!&}”Ï'¿™Äš¯¹ª5]•—Â(@“¯mÈ—e™Œorv휱1™ÒjsÚkù\!…i>Û¢|ŽPÛB~­{Ýô!0Շź)ÂCoŸ!¼GGàë³×vãó©_€ˆÞÄØ¨LfÍ~fëÆ•œßÒùáŸ.H²5íµé9Ú›j[òBz` g%lºÑFÈL6Ñ­ØEÕ|vÖ¬ç:°âüúÆ:hÚjîÙ¹ÙhÓºcDÔ›w3=OŸkÊ1Ÿ€ Y–I¶h A[ðÜ@¦¦¶w>Gã€6Öq3 Þlœ§iÈgr¼n @WóÙSY@½6S¶S ¥J[º,ËäŠ+.lô3ãã›DÆf?W°`¤Ö­»›FED[€M€-¸X°¶¼‚‰±Ñ9I. BØ9Øf²ÁÉzÚºó¤´B]]Të‘7mGÄ×'lÞS6á3¸éçJ›¾Êç“?€-äkNO¯w^ÖÔÔvÖ4°£áˆÌ‰±ÑAi÷çèú4mP1 üb~ø® 1Ë®kº¯SkÇ!²uOéô!Ó>жOðùÔÀ‡Y–E¿ÆVÓöȲL&3óµÅb??†ûþŽ…®OÓSå‡VÕCl º€°.8¬z¨/ÞK)¾w`þÙbÚL?Wtåðùä` }¯("rÉ%vÊ_³Æ_»­X»E¹Ë²êõk·ù³éNΦ#2ÇÇ7µºþØÏ¸¬Ù{Ù`êš-ZB[¶À\ñ¡2†#ÍWágrÝ<‡nÔ§ÍSù{¦Ë9WŸ²î!|Àb0“« oTÇè‚ ò9êÂ"U9ª²tö8œVk2dŸ_Üf÷Þ¤¿Crîu•¯_¾|±“²TçU½^¼.×S[T½ð'¦‡ØòµòPÏ£M~6¦@½F i(g:ÊË“²l—›¯XõY÷˽iy©¬¨ ÷êúÉž› ’ЧrÙ>¯%ÄðMLУ³¸ÿul„ª>G_â6߯Ifì|ØAæ‰0²ˆE9ÌR}]Û._¾8ɬ®-tí€ÉsDþÕtà¢òZ]€­çQÝÏòŒ›~¿)ÿ‡ô°`INUSº5]…ì   U8U5mWwLæ•ÿO[Ìm Â?@[&S€M~Ãe»Ч†õù£êOHKô`›5 ]:3ý€,¿‘†öÁÊ”^ »º°Êd]ºTÖ® ©-ÿ C ÀLwÊl»‹+Ab}@õ ɽƒK¶v‡æó©_Ñ€&!R“ ÉäØº5M:}ÿ{÷ïrG²ÿx/oàà1èo¸Lxk„A‰a@á>ÂɆ«7™Í„œè *’]n¶Šf7sbd;¸‰Á&=Ü¿aÀúî÷=ÞžVÿ¨ª®ê®ªþ|`é<ýôé®þvóýªªº§5<Ö W9ö=~­Ö ¶èËڴשmzI ‡ç1uNã)¿KO„n·öóÞÚѽãºR¦ZêWríGÿTŽ)ÀÂè?Èc©µ6Mwn*o«…-mÐG‚™c›ž“ÆÐ)Â!#ióú+ްG¿;÷{ôõâ¹ Àsk}¿“˜šlº0,›+|…¯b¦½¶P Óœ=i€)Yž<µ_«ž¾x×Õù´èV¼ý§øëRÌ‘ëASï}äÙ#Û $ë ©¢FÞ 3S¯Çls¹Ì oÛ…îçskއbÏÍk]›¡—5ç®ÝÔë±×ùz½^îï_;öÖ÷Ïù„LiÍ9íu¼¯šFÈíÙS…ÐÛh“â*z pއn„wrì'¶´¥ÀXbÍÖ½|þøòæ÷;^=;ÍþéÏ\!)×´×”÷ }¿ÞÛB‘¨‘5Ô°àwßýâB ”.ˆµ¾à¼ôòùãË幂ôêz½^®þ[ ¡-²PLp[ðááãnï÷g„§2%¼S£`µÀù„<à`j=íñïÌí§§(¬ËÜzä±ÛÐVL¬Ý¹ïGÎÓçŒ/ýÓ17xÿþûâï±W‘¨‡¶`YhÁ¯åä{©ˆ9þóZ{Lí+dÚŒ-÷ÆŠç,_ûþbK\蟎£˜àè5ÈøÞ×ëU‚ @ÓÆIëTÛC9W \+ŽÛ#dÜK=Ý;„÷-%ûýÓ±õ›ßü&Ë~®×«Æ ;ı…Äñ6šo<Â/ä¸cÏM‘§]s£>sŽÚ»Å‡¸8OL­Üöª*'ºøôÅ»¯^û<¡¶¶ÍÓï¾ú©÷™Úføz豬í'Öm ÀµNyéÃx<`4I IDAT~)˜­¸.vTäËç«Ú?l‰·ÌÝ3ڀ܉d+ÇZz̰ȳ–О-q2.œ+¾3¾ôOlj*†årÜ–„üö8–©!fþÞ¹Q”Ô‘hÎ%ŽsÛôò=zœÏ%Ïãv˜+vÆìKr}Ž{ŽŽ/ýÓqº›<·àÚÚ€1æÖLù`~¿“Püƒ|B§ï®m3µßÖF‹–ÃÿÇ´EèTâ”6 ü{ò–mzH"C§çjKê»þS…×’ÜýîÚ?HÔÐ×çÑ™N6g׎”£X•ZЪ­˜•c4_®u­7ÀÑI;Lù&ÇNjZ«m­°´6øé‹w«çóÇ™ŸOýkLŽ©½´0ò÷ùÿQPþ9×¾§Þëö_mÓgÇÇ7×[§.ÏTØöb-4 UÔÀ¹âÙ°à²Íå2_4¼m—ºŸQe%G ­ÍU7d;ü:ë–ŠZk…º¹bÞZA«Å5÷d}A Å? UôàÐÛÖ}äÚÏÜ6±¯­­òd®¦X,˜+È…èÎ6]uëyM­%˜û=r{¤ ÚôOÿôO]ž×xDçðïF ¼”Qy©…>£ÿÚ¢˜à/Þ].ÿí¿íú~ÃQ€/Ÿ?¾\ž?k®ÝBF]¦ù®×ëåþþu±c/½È-dzoèà‡€ÌM{m¥P3zmôŸ§µQÜàáá£F¨ÀËç/o®q¿óáÕ³jö±–r²]Ì69öqt[äl¯mûÒ…¬•=÷„áëSû™Û_Mç¾vl1çµ´.yÌ6¡ÇF÷Oî˜ä\qÚgl/ÏM(C0ÑýŸÿó?FåÝžÒ[êï—禾®)]pSÐØGhÁ/v?½¶OHb=Õ†!ÛÌ%âÔ'¤0¾ç~è¯ß í3BãL îO0Áø¡¥ÿœËõz½\ÿü·B[ðÿ'¦9ÏÞMµÍ¸ C¶n§è~s¿;BûŒ˜>J¿²¿o4@=^>|Êóže«-XK<™OÜ×Ú0¥Ý©ã~¹eôìí=Ä¥ûó’±Ì¯P mpöq-¼½³†T/ÉcÈy‹€¦PŸó>Ú2=sx)¾KJ‰¿|€jÄ¥äo©8a @S8]ÿx9§zÂVâ./S€€j­M÷5x=aÖFç¾þ±÷[ÌëPk,ó5#éÂ?þµýY×£ÏxîÁÜ=©-¡Àù &Š/ôËü‰€4/¶@p½^/o~÷ÏŽ.â¹s÷¤¶@"/ä! ¹Â1÷ÃT±Ûõ£d¿»gŸ!–Ë1Ý<}ñî«×>zûÕ6ã×B½ÿ}Ðv÷÷¯] ª÷Ý¿ýÝiÎõúç¿Õmp–ÄshËZfSjN,ssÈC@Ö¶™Jö[hC÷N[1O;ýnއ …ö+b¹ @v•³àgõ7ÿúï—¿ÿË¿~}m_cã} ·‰Ýÿ^í±vgi €Ö…$w!k”µ˜$n9÷û“h×'SÅ׋’}O®8ËÝÏGC}þôVZH¼ýyª@ÖÊ9œ¡-æXC)þA}zÙ–ëŒòjb}4 •€ìj¼ â”1žªzû{‰‚Öp”\SdsN™n½-€¶)þ©Ù•5!)¨ÃBÔÔŸs™+0–x¯-ǷDZÕÞÀ9)r(kBš¹mµSMíu+ÂíQŒSìjb @Ѝ­¶Wñ¯…¶ÎÅ@eô°—=GÂÙ…,Rw÷dög·ßÝsÚŽñïÌíÇâ®EÌ}£mÛº^Òã,6¶ô+ÇRdW!o³´-_²¥5ÿbЀЅPÖÚ—ú¹Ÿ§$ ˆ¾cG’xÌ=:nס¾kµTp˜û8×ý­_9Ž » )à¥ù®×ëåþþµF† s¬á+–¶nSòi©ç¶vSE¼q°‡¶€³%(0N(‡±1•4Šò÷¤d]IŸ÷ñÞ±¤_)Cæ½|þøòæ÷;^=Óp4k© ³ÍÒv%¶Ù»=ÎØü_ä±…äqxŒÃQ[S£§Îuêç·sŸÚOîcžjwÊÄIÈõt hõ>Ö¯”£Hô ÝDvø?%¡ ÙÏÖu‹hSKIã\±n|ü!Só†…Ä©?—ºG©«oU0áèÏmýJ]*s½^/×?ÿ­†Ðн\_ú­ˆû¢ÿc!­¿S$—©XJ‰/ñx@€Š¤LiïÁÔ(^mlM2 ‡EäC¦ÝÆ@û}el_¤_i @e€´yÈÞ‘¿§ÚŽhÿ>Ö¯”ñ& fFÿ#K‹È÷xîœ+Ö§®¹8Ö@‘$uJ©'‘îõ^Ô;g]D~ªˆ¹TØtœÇ\ˆÄ7 €dOrl²­€ˆ˜mj…Ôs[{Jððõµ‘bÃiÓ½¶së÷ˆ‚/{ô;S£¨ìãÅ÷v €'Oöè›5 ÖDR)@ÿ€T €Ð1@è˜ tÌS€€*ÜÝ=ùêµñšgSÛLm²¯ÚÎ}íøBÏ}¼íÜ~—¶‰y/Ú¹ t¿’£ÏËe(Õ˜J8ǯ…ʦ¶éá ª!Ç?>Ï©óÙFÂÝŽžcžvú•˜xËû3¨:1]JYO’Çm² @‰>C!ï8FM%žÌ»%å¥Fê¸ÇßS×Áˆ)zéÏÅr9 €@U bH2¸¶Í™Ûg<2gKñ/dJ6uƉëDÎ~%‡”ýŠå|€jäXðLí’0§$Ðî~®?´z¿‹å¼¬T˜Z›n[¬ Ï}ýA,s¹òÿTuE{Õ~ž ñby €'ëôK!æryÿþû*Žãááã)Ú+ÇyÆöm⼎Ï×N›z FïB²¼Þûáv sÝ'£_©¡Ïg™à[®~üÅ>:Þ´&6n¯×ëåÍõrùðê™Æs²&ãÄsm›ñ¶ã)¯sE“ÚÏ}© B’õ¥ß_ÛfnڰļÿøÔ~%6Fçö'–ËPàWBG"Þß¿^Ýæé‹w“¯þô6ùø†ûïgég®CžkÐSu&˜9¶™J&kOsž{®ýI¶ëŒ…Yöî{rÅYî~Ž8QÀ˜Dn¯a-©)‘|BÉø={|.-P=5Õ!ç‡ÅÓïfû³Ûë!Û”l“?s¶×ø÷Æ^§½îáVîשbiʱïÝÆ¹ÜVF@ Ñ#C¹µ¿—N¼æÂV“6úÖb|†Ķ~I_s–µ!¬ÇCɾÇg!p&>?éñ»!@¨ìS€§’‰½“ É øâSÒÔ?rìuž½.fž:E5uáÚ~bF—÷4%6×TáöË5"ÎDñHuø€·$¡–/ýµ„&å1‰û–8¿ýûžÉ=½7§á?j ÿ¯OI‹ß=§Uçšæ]rì‘×)×u0òê]̹x-É'ÔŸµ­K7Ñ[ªø7µÞ_é5ç®Ûcfk¬L¸Û»÷¹´*Ë€µ$TsÓ°b’O {+ssû®9ÎC‹x¡EÂm6W¤Õ§Ä·íR±:¤sœyË·6€º<êédÖžLhÁsz57µÔÃwÆ÷Ù÷•õOÚŽÕ©µb÷þ¬ LÛ¤yéKÈ?È„<õ}Ïm¨'vÖ®Qèõ ÙÛîÑØûžz®W®¾œóô½SÛÅÆ‡~åXÎvŠ€œ)qou pËmN¿ýpÈ1·t^{ëZñOqð¼Ö¾ÔÏý<6 ÝuÆÅÜC±R ’ɼ÷è¸]µo×˽CÊ5Ïú•ãd/N%vKIÆk9…LC“ØÓ[a¢•8ï­ƒßÒÖSx=~æÁº¶V`È{ÅÏxÛš?;Æç45 3öC¡m<ÕNK‡=>'$m5öNþì”·ç!{‰Î?¤_8¢OÙëƒîåóÇ—7׸ßùðê™Ùuˆf)RÕ¥iJ¡û‘Ôž3vZ0W¬ÇjÈT½a!qêÏgnçÞï‹ÉO½Ô_’³OЯç‘&àFAÏuØÃÜ4aÎ'×—þ˜ý˜Ö&vœ›vî1>r]+£¯ˆ‰”¸GÇQv§àGŽÄÎ æ)ÈGÝ›ôok¯#6ô+íPŠyxø¨´1)™tQ@òÞE?ô+}QÜà‡±û`ÆËç5‚öÈbëè?£Ï}ý{Iñùî‡Ëå’e*&øì<@É:@±$uìˆdâLOï1vbF‚ܶíõšO×ܹŠñsÑÏQ2vÄWÈžLäØ&dÛÐýHRÎ;-^óÔó_{JððõµƒÃ"jêñºßÊÆˆ‚/µn—xñ½ €D€Ž}£  ~ÖeRx"¹l1µþ¡‡f@¼ëõzùðꙆ ˆâJðdÞ¿ÿ~Óï?<|,¶o8›ûû×€âL€Ž)Í[{š]é߀š5=øé‹w—ÏŸÞ¿žë=/—Kòþo¿?6wK?Ïa©ð‘º¾D‰}îåvìg[[cxÍZ;÷µ…CÎíË—Ÿ-¨ •}'™û9÷™û:œáþÙûîóÆÏZ~%.Úd ÀH9 q!E˵¿ç2wãnUbŸ{9kG6üBÝÛ‡Øðšú°€v¾‹åøÜ¾íÃwz—«®.~Bâ@<´©ù)Às#êZ?§q±ïó§·»k‰›YÁÞ±:õ³Û‡Õ\Âa*0Ôoê3{êsøšÏyÈ{ÑwNµúÔ65?ðV›7õ³¹×¦ö=·Íڔݵ}å´uZréÎ}Ë>C†±¯m3üWŠÐýÄŒbŒ=ž#:ôÇ“ëÜ÷jŸ©™òåú*RÌDYJh} esKåµ7ÌÜ3çêOçbGŸÚ‡.¦¯ׄ®%xûsì:~)ÅÆ#?LrÞÄ[ö2üµ-ßh‚¼OÎQü›*b®=è$õJܰ¥;”ýï9ꬕ/=œ{ìS}cŸ Ôù=&䉕ÐküOźï²äÌ©ÄSŸõ~‚SÅ´ñz¡S€‡ÛL=y÷öZŽéÄãc*5¢0×”Õû ÙOè{Å>xêéZ9çÈÎüÈsß»},f ÀY,ýÃ8È›hº8W¿ò ŽÛÚ69ö‘²íÖâ`©§¯îµŸÐ÷ZÛ.×{ÕÖYîy^G´ÏÚº~¥JöýòºuÌèù¾¨iÀý÷¹úÔ~˜ týaµÇï@Í f®©i‚syxøxºsö Èm€3S<‘—ÏÝÿýýk P@²xùüñåòü™†¨Œ5 cFU}ÀÁÝÝ“¯^þÞÔÏÇÛ@÷OΘ÷À}±¸è‹ Ð|b:~=d8Û}±×~h;–ÖâC<´É`à?Š;CŠ=ç:òo*N¨Ÿ Ð< ÎàîîIðTßÔÂݰ¸£øw®ØŠ™ö«ØS€€fŒ“Î¥„uêwá ¶îÆÓ<Å }Pš2õÀ©Ñ)[zŽý99Šã÷tõ˵=@ Yk…>Å Îdk¬Ïý®û§ÿ¸Y‹%Ó}Û§4•¨Æ#qoÄs¿œCèú‘sÛÑN‘äJViÝÜC@¸5FÕ˜+ÒÝŠs…<ÅÜ;Ë÷pn €@B kÛYÇŒžïpöî‹õ©}0:¦ °ÖÊ` ˆ~ü¥ªãyùüñ)Ú«öó âJðàd~)Ä\.ïß_Åq<<| 5±q{½^/o®—ˇWÏ4žëTL€_ ‰xÿzu›§/ÞM¾þùÓÛäãîs¼Ÿ¥Ÿ¹y®AOm gUŒMäž¾xW<9XKjJ$ŸP2~ÅçŸÜÝ=ùÕß×Ö;ɱ ò\Ÿ5|=d›’mÑâº/9Ûkü{㿯Ó^÷pÉûõ§ïþzñçßýôûäëzì{·1à;Àøó/ô3m?p¶{'eî™óÅÐÒ5o=/9»è€¡‰Ü‰Ah"¾w²%„ÄJ~ð„|ÙéõCØ1rö=> V’Ï”ï9öî÷ΙbH^Ò·"S€o ÅQ£$3Ðß——µí÷,NBÛ«-nçÚÛ‡mêÕÔQ„kû‰]ÞÓ”Ø\S…CÚ/׈Dàr}îIVaýQè9o6—S)/éYö`ìø[’PË—þÚŽB“ò˜Ä}Kœß~w\9âž9êg8rjí<ô)iÅ Rq•kšwɰG^§\×ÁÈ{(÷ý÷r¹Lcr}W‚xÎSk×Xa¸ÑÀµD®Æ/÷9?‡½ã³¶uéÆÓK%õkk–úÀ±®Y~9bejÄÝÞý¸Ï  [¾+GƒåÕ¿Ðk;!(&Ú“e ÀZª¹iX1ɧ½•Œ¹¹}×çS_2†¯•ü2WHÚNŸß¶KÅêvÌQpVä-ß6ÚÊ}ÎÖâßø=1°}z:™µ'Zðœ^ÍMA-ë{LN}²Ÿ¡vbu/{öË>ʶMj‘Ønë÷á¹ßõ[\) ·ï›³&ŸÐclÿ+ëÃ5ÐÆë¡íåË—Ÿ¿úïˆ/& Içê‡C޹¥óÚóÄÖÚÅç2l—»£°}9|àk9…LC“ØÓ’Ö¾ÓûµImë³,¶›sëÚZ!ïs<ãmsßSßýôûì±8w¬¡çÒÆSí´ôw€R… £Uèá^¸}OÛìÅC@úPä)Às/õ0‚I#Ô*wÁ"×1•z¹ÇÏŸõÃeïÅv¯×ëåþþu‘XYz=4Žr¬¹˜k›’÷Ù^×aÏö;rÚ7ÐîçÞÜçßÔ6Ãí|ŸàŒÖî ‰›¹ÜÃC@ÚUÌ4åHR“ÁVŽ@_öNÊ[‰ó”“@!ýÂ}Ê^®/Ÿ?¾¼¹Æý·WÏÜÈ®C4ëñ[>÷bžX =ÞŠÛ•{‰³¶=ÒÜ(è¹{˜›& ”¡ìNÁâYw H¥óððQ#h/2QüR)nðÿ؇}0ãåóÇA{P@É:ûF@¿Œª3÷°ƒ»»'_½¶e»ÞÚgêüCÎÛÃ%úˆ‰œ1/&Î?ãkŸ3¾ôOÇPªKD¿|ùy6é›JL‡¯-kN"‡ÇR½ý9µ=–{Ú¼g¶Æ|«÷eâ§D\蟎£x"¹l1µþ¡‡f@¼ëõzùðꙆ€™äp©8³]/mòçö[a*VÿÎÓçñ^ú§ý(žÌû÷ßoúý‡‡Åö gsÿZ#À†ä°·sþ?&1ß2 Oa§Í8™ºOr]ßaÁEŒPÓçÛxÀÁ†£‡o“k$Œäºo[®ïÔ(\Î3ÃÿB¶¯1~™g pê/8>`€–äå»OÛ׿äõ=ó(\ùÔüZ¢S…àRÅa±VNÓÀ§/Þ]>züz®÷¼\.Éû¿ýþØÜþJžËíæÚòá²×>÷ìøZ8Î’qÐÚ¹çxž/5Pç÷’3žwÈàáw—-E@‰wŸq´å.}_¦_%—Èõ9 ÚÎÀH9Šq¡E˹bá7ú–/^%öYSÇ×s‡ßÛn @‰èŠ‚ãb^Ìú±ßq<åµO¹¯¡x ¦Ïñ¸]ókîQ$;ê¼JŽüÛóƒÃ ˱º4}aéË3Ð×w‚ñv­ŸgHò<ÞÎwñ¾bÝè(ZêwõOõh~àçOo‹es#ëBFÛ-m37Šoé8CÅÿ¶NK.}óm]ƒbªÓˆÙfîÑáKû‰Å{<5|QÌ5M$åÜ÷jŸ© ÷áý$žKß%æþa¯öïÃã[šú;n‡µó÷ýçœ÷…ëOLޛǥƕþé8]L^+® ]Kðöç˜uüRŠGŽü»ý?×M¸eŸs¿25"¤ð3~mmlÎãÙóšæ8ž\ç¾wûøp€öѵ×C?Ï{ýÜ"œ22‡6®‹ÅmÚì{KŘþéݬ¸µ8·Ï-æŽ'w/×þJŒ”*½ÏV:Œ”âgÉsÙ³=Žýh pÖ„nºzÈ­˜ë÷¶ÖŽ\ÃrÖÖ]Éõ/r-~¡K:^òZÍM‡ñ…€VóßeÝ=xKp,µˆ§ø×¯Ô¡Ñgù 9w_X \>0åM÷IÂGÿž¾x—|%Fc•ᕲÿ=Gµ Åë>÷(橾±O €<êý§FŽ× <ÜfêÉ»·×¶N'ÿþÚÓ‡·(±ˆlÎi°kû }¯Ø§O=Q-çñì%eZnÉsß»}</ÎÃÆ¯‡<ˆ#¤°¶¶MŽ}„n³eû±RO_Ýk?¹ž—ë½j+2íy^G´ÏÚº~!ïgô={¤ €Öm-Þ)þ@––‰Yg9öuèõþÙïî—sÆÐÚ5íRª0L*×’ÌÛÏ%£¯è­x.†BÖMmR<™‡‡§þ" @?‰êí»Þ8zM a¹“{GŸ:uÍC¶¡n €'òòùã¢û¿¿­‘Ø-Q½Y+JTé)þoñ=¾Bî•Ãé¹wô©1ý.uS$‹—Ï_.ÏŸiª!A嬶Äý¸pî‚>|£  ~_¾ü\ô! K#½€¶4%´ag¼7¶ÄúÜïºô©ŠÀíSš2·ÞÙøï¬çLrǸûEŸ» u3èŠiŒôÛSq¬À ¬17WàV.@ B±k‘ _·Ž=ßS…>±MɾVŸÚS€ c €Ðký© Š@*@è˜ tL:öH5yÀÁÝÝ“¯^[úMØ~MæÚyêZ„\Ê^§\×½£._ú•c(M™Jç’Ö/_~VÈÈT ÿ}®M—xö¹'R¯ÅÚ½Dÿ÷ûܵÎuýõ+ÇQä4~øñ—ªŽçåóǧh¯ÚÏS{@û¦’Öáß·'é¡í¨ë¾†[ï%ú•’ý¥~åX €œÊû÷ßWqOÑ^­œgOí[ˆTp ÷d6&ɬå˜c§Ç‹5ãsžÚÏš”B$}Ÿ8 ¹ž[®Å0n\SýåRÿ£_iK³@I.À¶~ñz½^Þ\/—¯ži<8Ø\±.dzÜÜ6ã¢bj²’ì+ÕcëµOuM™‹'ýJ[š,Jræ…ŽD¼¿½ºÍÓï&_ÿüé­†€jJrcFê˜2ZO|l¹-Žž¥­~I¿rœ¨àÓï&“¾©×‡Ic©Dq$·ÄñϵãÒ1í•lŸ9ÙßúÄ£Ø'ÒåºçbîËœm•ûÃ`*öæÎ«µ˜,Ñ^{Ú;¾rö£œW/ ÆÇÃÉÞ IDATJ„¾W­É~Ž8¸ýî¸0²¯˜ÎeëJй/[ºçb—Ê¿Wlö"¤(—cªzÈ6[FúÐVc*qlá{YISÿh½ôÙ[Ûem±þ¹÷–¼×®5Æ—~å84Á|’³Þáðµß ÙOÈñ–˜®»W²ŸËx„iÌ{Äÿbÿ•-׿Æî=üã‚åÜõ[›Ÿz͞®OÉûb¾›mÙ¦ö2õÜÖž<|=v雵c’”ï#¥ ¾èw·ô9û:±\FR0ç”Þš’¿cÉu¼5'½%m­°Óò±˜ÝÚfsEÚû²Ö¶ž¡·õXsôS Ta1¶V¨ž•2rØ÷»-ý1°€=ØZ“åÐd?g¤LöeêRmül½ŽK¿«È´ýÞNy8KÈÈKW€yÖGR%%iÓRGÇôxZ˜Ü›VÏ;÷5[ÛŸþ+ï=wÄ5Þ{ÿ5PüRe8•†ŒÄé9q›*þõž¬¦jƒÔe«õ_ç¶´uÈS›Z‹½³·WÎ~êõÜÛÌm«ø0¯ÈàV³˜ Ä$Â1¯ÍÏTbÏi¶%’ýÜÇ”òã5ú¦žFú¢³Þ×Þ±Y¢½–\¯×Ëýýë"÷ÖÒë¹ÖPíoXUŒy€Chb–šÀí•äæJ„§ T9ÖpÔ9{IäC‹1¹žH—ëz„peÏsÙ¦D¿Sk{MyùüñåÍ5îw>¼zæ“ sM>D’  ¯ Ok3/¦~>Þf¼¿gf„œ×Ú6{ÎRàø{§DŒÑgüL]÷½ãKÿ”_³O–ä@ è\â9|=d›ák­2†Ç¹Ôã?‡&ëKí¥ØsŽ{g¯ýÐvü„ö[ÖË×?íï‘&àL>jí¥½àd mKEÀÐsZ* Ÿ!ÉuOmÄ6gyˆÇõú§ã(r/Ÿ?ÖÚK{€„¶Úcþî<¦ÄkyÚŽíñ5Ÿúû–k:,Έ J÷Íú§ý(Í%‘SIcËÆIoj3æ!wÖØêûI½¦ã©óŠ/„öÃ!ýŽþé8 €@SÖÖÉëýÜsŒÎ2Â¦íØ¹¶[âbsâãÜq7.ø-MãÝJÿT† ÐtRšòŒÚÄLÞ::K‘§_[¯áÜïŠ öŠýS9ßh å¤tnJðø¿’ë᱆®ÿ×Z±“2rH[ /Fr?üøKUÇSûC#rµ×YŽ¡½à8g’ë-²ßv Ü®a‰Ø@ÿO¥bNÿTŽ §òþý÷UÇÃÃÇS´W+çÙS{Å"¨1zý,ç¿tÎãö™*Ûon!}‹ì÷gn$¨kKlß²¬BJ\éŸÒ|ûí·Ñ¹â·ß~ûÕkÍ%¹ÛúÅëõzys½\>¼z¦ñ¨*MùùZñ¬—$rí(1ç¨0Ôæõ?s‘œúúÞœï!¦ç}÷oµýOÿé¿|õZ“@I.À¼Ð‘ˆ÷÷¯W·yúâÝäëŸ?½ÕÐPq²CQÀ§/ÞM&}±¯·”ä–HtCÛexL{%Û’ý4K /oùrroqÿ•Ž={sçÕZL¶>|ýˆþ=W? Ð[Þ¡ø ¤(6p© ÖR’[ÃñìÝ–5&û1Å€£Žõ,Ä%d)b¶Vô±€-ràhÑÀqB>UœºmÓbZr_æ0U¼:ËS÷´×z Ž‹µ9¶þüˆQÒ-Š.Þ {ãÿ²˜D¬¥é|s…Í”$wj»”6}¯Z“ýqpûÝ-q˜KŽ'#¥X»/[½ç–b*äžšÛ×^±Ù‹¢\Ž©ê!Û=Ò EÙ§·œ…䦒Îñk!¿²Ÿã-1]w¯d?gÌÕ0xjTW®é±½,ç®ßÚ´øÔ{ïȸiåú”¼XöÝO¿Úî§ïþzòõ¤à¸àÒKòr,¹Ž·æ¤·ä±­vZUr¤_èH·Ðû²Ö¶ž¡·õXsôS Ta1¶V¨ž•2r€óùÇÓ©‡¯…þ#lOËp¬KÈCÈZPñ÷Fîû‘sõÁ¹ú ýSš¹Â^¨Gš0¿=ØZ“åÐd?gÔ0˜|ñ³õ:.ý®"Óö{;åá,!#/Ý·„(1뢶ä{©ˆ9þóZ{„ÌTQìé'v¶Üg(ž³|íCc 5&ôOé(I‹/:”*8´6’°ç)Àµ¶yË÷M©ýé¿òÞsG\ã½÷@ÝÆIëTÛC9W \+ŽÛÃݽ—z¹wï[Bc ¥ÏÐ?mÓüÀ3,°¿ô¤äžÏ¹×‡Á„vdµÇcJ[·ð… D1±çöÊ!dÄo®mæ¶Uü`és¸…ÏßÛh¾ñ¿ãŽ=7EžvÍúÌ9jïââ<1USÁMÿ4ï°€kÉòÔßkOÐb,“Ǽ6wpeÏsÙ&güÖÞ^S^>|ysû¯žù$€FãEž¹¿ÓnΑ3.†1'>Ø‹þ©Œ&"ÉÐ×@o ïðÿKIïÖÑYŠ<}ÇÑ–k8÷»ââýO­1¬Ê£Ù§Kr€^„Lù=Î+wˆ©sõ?SñD_iÎäáá£FÐ^Ú :s–XÈy†, o‘ý¶càv ÏxpŒ\}†þéX €œÆËç5‚öÒ^P¹¹Q'ãdpîg­'ÙKç4^鉰k è[dÿœ÷léŸrôú§4?ý§ÿ²y €@5 fŽm¶lßJ­ˆ)Ñ–Ôqý§ }®%¹ûݹÂ\­}}Ï®×ëåþáDýÎýýëËåù¯—ÎûFSô‘´À@h€µÐ€T €ÐÅ? •59~ü¥ªã©ý¡¹Úë,ÇÐ^ÔJSyÿþû*Žãááã)Ú«•ó쩽b ‘ Žýk¶(ÉØÖ/^¯×Ë›ëåòáÕ3б& €’\€y¡#ïï_¯nóôÅ»¯^ûüémÒq ÷•º  !‹ÔßÝ=™ýÙøw‡ÛÎí7d›ÐcãøøYЉ˜ØiõšÏsÈëkíw–6tß\‚úÄ­}9}ÆÐÖ>#G|…~®.ª’>}ñn·Ä®t’[*Q m£#’å¹v8{²žúEjkG5+Ã×C¶ÙóÃ!gìÍW‹1Ùò¨\ýü0fB?CÆýçT²ÍZCÝŸ—Ã×C®õøç-}ç8æµ{$æ;œû¦íþ4öúÅŸé³ïÝÒgäèWB?׉=ðÈ‚ßÞIn-dzw²¼w1)‡‚XÉ/¢gú ,ÑÇ1[ìozûâüùÓÛ®ú~ Ïœ[²öûùÚæàÖÄ«¥é|·s'¨SÉhH"¼¶Ÿ=“îïsl[âàö»Ã÷;[A`XˆŸ‹Óï¹¥˜ ¹§æöµWlžåƒ*ç4ôG ÛÙ¥Dbü()ýª¤¡½DÔµ;þþÓöí_ÛÔï¢ãièŠ/úÞ¹xŠÐm}”]ÌQ´ª9‰MIDǯ…ü^ŽQ,¥Ö~K3~}Ïu鯣P÷(„ŒæÊ5âë ë¥ –s×omZ|ê½W*n|Plï'8w\„ŽvÂ÷×mþйÖfüœÓÚgíÞ×Þg‡¯XS1äXroͅӒǶVØ©õCvê_HÇÿ"±¶MÎ6›+҆ܵ¶õÔ½­Çš£¨gäYx[×´ Ï„D"zÞbGêÔïcj¸çB_Çg­ÏþvX°âD¸ådyn j‰8Ùc pì¿´±=~¶^Ç¥ßUd*wͶÞ˱S»è?Íùý­ö›§WS{<íz¤ òÚ;mm$a/S€[jó–ï›Rûóu]¯µ÷Úòs ýä3dZ’©B°Ì=Ñ×µ¼õ}®1{}Öî_>×ËñƒØÞ‹T)ë¶!P­Ô–¶n¡3.QL콊íÃÆm:âwJÅTÈ=15|¼¯=cóˆ/Î×ëõrÿºÈ½µu»Ôm¦ Ž@ýŸ9¶Éµ?‰Cñ³¶m‹ë˜…óÚ9äºÿÜ7m|wÍØ«ïÍ_%žL¸¨`‰‡d¤&rG$¹¡°XK`‡…ˆ½Û»¶d¿•„þ¨/I!1û`•m½ç¹Æl“3~s´×ÞZ/Ÿ?¾¼¹Æý·WÏšúвæ,@¼&×r}Ö–ŒËR}áÙ)P¥ÜEœ»»'¿ú¶baKü´Vü[ºöº·ꓘÑS°÷gíÖ¸ô{å4=øøƒ}hûp^ö±S¬”HÆ_ðד-Å¿’Ó™(“ˆn½>¦mk;Úî[Å>¹ûÞ­kŠÇc5[|ùü±«§m+4žp„$²[G%I8Ú‹[²éBxf$'±R×_mñšHHn‰­„ã<ÖžêC-=ýw϶µÈ>úY»gaºo €@µ‰hŽ}µRäš{2À™è ËðªMÖ&}˜çbùõö Ýk9Çú9J~ÖÒ#(’¤Î%[“”…Ì~$7m$¢®U|û„.Ô¿42rª àz¸w8Gü”úÕ¯«éà?þµ½¸ÚöI$rl“s‹¾âgmÛØ×k>ï©DNr|)— Óº³bAßFûý×ÒçúQ±Üû=Ôtðz½^îï_gÛß\Ñ"u ðÚv¹jSl)Q´Ê}ön›’©)Ž{jã¥mM×h+ ˆý2.Á…_'Ñ{ŒqßÕßoºF´"u]¾½«GÍ_>|ysû¯ž¹Û\í×±× ï—ñ­ÅIò¹â§wÖyc-æõyÔÔ_†~®ïËg¹Oš¨â:h?†¦¦ü*À9ÍM+ëññ` + ~}%$kSƒB¶‘ ÷ϵåL±~ëû µ~7æ3{ïgûìP X’:õ…<å üÒï—xPuÇNÈdZ?÷Ò…ž=ß è¯oNí/öüÌ}àHŽï+-P ûîÛäÞŸâÆybgn›Úc`íøbÏki¹ß‹ýb$tj¦kÅ–8¶ß»¯ÏË[úÁÞ|#Ü _ €Ðë]© Š@*@è˜ tL:öH5¸»{òÕkã5Ïæ‚0|}j?sû«éÜ׎-漆ÛÎíwi›ÛÐýóĵ¢hÜ„ô+[û0q\Ž PЂ_ì~zmŸ¹${¸ÝT®mR !…qØÒï†ô+¹ú°\Ÿüš)À@Õ‰é¸è¤5o*Q·aÈ6¡ûúïwSûŒ’ŸÄSªutâÙzâ>׆´{?„N‘tÝéùs€x¦U%zCsIß­Ð:Uµ—ä1伯EÀç.o/N\/ZíÃzí¿¦T#fí§¥" 5·¯ÕE×Z‹ak–a 0Pu²¸öäHÓ—å­m$ùnûúCQšOáìÿ€% €@µ5â„<$æA!Ú¿¾ûaj$”ëDÉ~÷è‡ ‰ï<¬T•x¥&}sÓÅjN"ssÈC@J<(„>â±stŸá! eDøñ—¨¿|þX AR‡Ÿz½Ådq˹—ÜŸÄ»¾8™*ô¹N”ì{rÅ™>çXÁS€c‹×ëõòæwÿ¬…à@ÑS€ß¿ÿ>h»ûû׫Û<}ñî«×>z›|2·ýmÙ_·iL{N]Ó©ksícAüìÝSâC;·yÝ÷ºky_€šX Huø€ã„nK’'9<Þ¸È7wMn¯¯]ïÛÏ÷HþÅÏ~ñ±T(¦^ŠpÇRüRU÷à[±†Åq¦ú§‹@KÓצÎ\¿žcZòÔ{M½ÏTQkmÝÜkkÇœ²Í‘#}¦Î3e$`H;ÇÄOÌ~rÄOhÌ/ÅOì1ÏÿÚ{¯S©{'f_9Ú'Ç{íyÝKÝïK×&Ç}‘Ú†F%¬«¾8WL'}9¦† sÉQì9æÔmzqÒÎ!ñ³¶Ÿ\ñóKï•rÌã6=¯©}Ö¶^\lûÄ\³=®{ìµÈu¿/KŽû"åÞ±f'@¸G­èÖ$ojôØÑ#GJ¾wŽ}÷2í6W;ï½6e®kxÖë~ô=ØÚ1¥^÷½Wá o!8¸»{òÕkãß™ÛOOPX;—a;͵ÅZ;Ò^L¸¦Ù¯¤Äªþi?Z=ðRÉ_k…¹¤½‡Ñ|½^‹\1oMÄsÄjÊuÏy<9þ¡$×1›î À\"ØKaoxKEÌñŸ×Úcíオ㹦䊡ÐXJ-ýÓqéd‡£çÉ“ËÔ)­žWë×"‡¥)“ìkïk‘²V_êñäŠÝ}„nc SÆIëTÛCò8W \+.%õ)ýgJ¿¢:VuO6Â#¾½ZÜw/mTS{åzÿš®{«1XÛq—5¸÷¹~þôö? Þ,¹%•sIg øíÿÃ?‡žëÔyÏ%ÝF×´ks1àšSsE¹’ý²þi‡ÌõäÙá~–Fˆ¬þË1…s[ 0·ŸcNݦäZp¡×+WÁ æ)¥©ÇSz phläÞOìy-ïZ;‡¾w×"×y¥^Óñk¡ýÕÚý•«šû™4 $Ùl!që–‘2ã$;d]EÉuÿE¨©¯Ó?íïÏ>zûÇ øñ—Ëõz~ƒ¯žie£8àâÚÀÙܾ³Í}ûáÇ_.ïߟå½>fÛ„&z±ëCµ”<†¬xûÙRò3ýYr}ÎûˆóXû¬é;sö¯ú§x÷÷¯/ÿðÿ#úw>¼zö«Z^ðà—ÏG¤âÔNà¬b¦×êZK˜ç¦óI®ûŒ#×””¸ÿ·W|êŸö5XA()dº6@B¦‡üÞ–Dœ¶¹¦lé¦âI,÷å‘& gŠG®®ý;K²³þßÒ;ÉuÛ1p»Îg¼8F®'«ëŸŽ¥TcmÚëÔ6½$‹kOÂO•›+…,²ÒÎôwïÀ–þ)æá[ö#–ËPªI0slÓsÂ:E8õgÔý§Š#®)¹ûݹ„(Ý׋år¾Ñ}$í0E`}4 • 4@ñH¥S€Ž)@Çi wwO¾zm¸îÙÔÏÇÛÍ=(¡æ(„sHû¬í'×{Q÷}ãš‘C!1³¥?]{/}O €@5 èZa*¤Øuæöiñ½Ønîš,aî¾^»Ï·ÄÕÚ{é{Ê1èÊ—/?• ž%y =÷Ô^ÞRãdªÉW±ïE^ €@ÕR’ÍaRÙ{!d)¡ž;wIw›îîž]7Å?RúʵøÙ#®Œþ+Ç` ÊDtkÂwÛ_k‰chÑné¼BνÕöa=~–âRú–£âIç£T•ˆ¿¹dTûäiEÀv¯hŒ¸¶¬I]—oïãb@ JkO­Õ>yÚÇt`8¯¥uùÖž ^²oÖïçg @ šD”cÚG¢ ,õãÿJöŠe(Tâ–øÖZ U¤=¾ýçFbAŠ=Ÿšò^Šå˜ T›ˆÞ^?˹GÖŒá=ÛçÌ×½ÃÙã§dÜ„>pdîwI§T•ˆæÜ¶¥„qj®íúºd»ÎQáè¾wk¼­=œ2L€Ž)@¬¤R€(þ© c €Ð1@èØ#MÔâîîÉW¯ ×=›úùx»¹%Ôü…ÐciŸµýäz/ê¾o\3Rc($f¶ô§!ï{<¬SªI@× S!Å®3·O‹ïÅv!E½ß×îó-qò^±ÇCS€€®|ùòóW êYÈÐsOMà%áíP4!5N¦ú‘qò^±ÇC8@ j)Éæ0al¡²¥h¹”,ÏíCBݦ»»'A×Mñ}¸j›)À@•‰èÖDó¶¿^Ö˜ö 9÷ÞÚ‡?i©ðM;}‹xjŸ PU":L8ç’Qí“§}Û½þ¡1âÚ²fmÍ=qÔS€€*}ùò󩦪ÆN[ÎÕ>¦Ãy…®¹w›~>œ†®ßh‹ PM"Ê1íct°Ô?ŒÿÓo´G€ Š´Ç·ÿÔ5p]HµçSÓCÞëÌOq/Í€@µ‰èíõ³µAÌ“{÷JÔÏv-Ü;œ5~JÆMÈ{íyyÚÇt`8¯¥uùÖž ^²oÖïçg @ šD”cÚG¢ ,õãÿJöŠe(Tâ–øÖZ U¤=¾ýçFbAŠ=Ÿšò^Šå˜ T›ˆÞ^?˹GÖŒá=ÛçÌ×½ÃÙã§dÜ„>pdîwI§T•ˆæÜ¶¥„qj®íúºd»ÎQáè¾wk¼­=œ2L€Ž)@¬¤R€(þ© c €Ð1@èØ#MÔâîîÉW¯ ×=›úùx»¹%Ôü…ÐciŸµýäz/ê¾o\3Rc($f¶ô§kï¥ï)C¨&]+L…»ÎÜ>-¾ÛÍ]“¥Â ÌÝ×k÷ù–¸Z{/}O9¦]ùòåç¯Ô³$¡çžšÀKÀÛ¡`BjœLõ#9â*ö½ÈK¨ZJ²9L*{/„,%Ôsç.énÓÝÝ“ ë¦øGJ_¹?{Ä•Ñå˜ T™ˆnMønûk-q -Ú-Wȹ·Ú>¬ÇÏRAJßrT<‰ã|€ªÑaâ7—ŒjŸ<í£Øîõ×–5©ëòí}\l£Tií©µÚ'Oû˜ çµ´.ßÚSÁKöÍúýü¬T“ˆrLûH´¥þaü_É~Cñ¯ @€JÜßZ‹¡Š´Ç·ÿÜH,H±çSÓCÞKñ¯S€€jÑÛëg9÷áÈšq"¼gûœùZ¸w8{ü”Œ›ÐŽÌý.逪ќ۶”0N­ÃU¢}B_—l×#Š#Ý÷n·µ§“S†)ÀÐ1@h€õÑ€T €ÐÅ? • tL:¦{¤ €ZÜÝ=ùêµáºgS?o7÷ „š zÌ!í³¶Ÿ\ïEÝ÷kFj …ÄÌ–þtí½ô=e(Õ$ k…©b×™Û§Å÷b»¹k²T„¹ûzí>ßWkï¥ï)Ç` +_¾üüU‚z–ä1ôÜSx x;LH“©~$G\žy)UKI6‡Ieï…¥„zîÜ%Ýmº»{tÝÿHé+×âg¸2ú¯S€€*Ñ­ ßm­%Ž¡E»¥ó 9÷VÛ‡õøYŠ#Hé[ŽŠ'qœ PU":Lüæ’Qí“§}Û½þ¡1âÚ²&u]¾½‹m€*­=µVûäiÓá¼–Öå[{*xɾY¿ŸŸ5€jQŽi‰6°Ô?Œÿ+Ùo(þ•¡P‰[â[k1T‘öøöŸ‰)ö|jzÈ{)þ•c 0Pm"z{ý,ç>Y3N„÷lŸ3_ ÷gŸ’qúÀ‘¹ß% PU"šsÛ–Æ©u¸J´Oèë’í:cDq„£ûÞ­ñ¶ötrÊ0:¦ °>J ø¤R€Ž)@Ç c4P‹»»'_½6\÷lêçSÛ ·oaÝ´¹ã¿Ò>kûÉõ^Ô}߸f¤ÆÐ8frÇ×Ò{ÅlC@ št­0Rìÿ¼—'§†îZ{/¶ )¢@èý>uŸçºïCÞ+dâ™ tÐÞŠ€g0u®s vêþi8)Õg†¼×žÇs6 €@Õb‹-&¡…»öîknê6ÝÝ= ºnŠ”è{nñ‡ÔÅ` ÊDT#½}B¦>÷4=šÿk­ø )}KÈT]ê¦T•ˆ“˹dTûäiEÀv¯hŒ¸¶¬Y[sO õA¨ÒÚSk×ÚÏ7æÁ%[Úgê}óYZ2Aá¯/ÖªIDsùòåç¯þÓ>Ëí@¿b¤àñí?u \R…<$W|…¼×–"±Ì` ÚDôöúÙÚ æÉ½%ÚǵpïpÞø }ŠzJ|…4aé¼ÖÚ(¶ i'&\WŽêWrÅ©8.GhÊ8œKZo¯·RçÒ9ÿFÿΘ @#†#sÖŠž4¦t’´Я¥~K?»\  ÖBR™ @6û¥ ùÿþ÷ÿ«Ÿ%Êÿsù¯b¦3ßýôû¯Ö\ýw¹(ÉÿÏÿ¢ "ÿòÑç3—ËÅ`€.½ÿ½FèÐpÄ_Èè¿ËEºf 04$tä߀Ð1@è˜ tÌ€'sÿ:Ë~¾ýöÛlû`úûÖÃÃÇÍûQ8‰7¿ûç¬û»^¯  Ôï[o®*Þ<*ñe€cܾè¿ß}xõìW_è߇WÏ.o~÷Ï—?ûüéíøñ-Љ—Ïû^.—ËŸŠ€ÿ{øž|ÕÝq0IEND®B`‚stella-3.9.3/docs/graphics/cheat.png0000644000175000001440000000717711133124416016731 0ustar stephenusers‰PNG  IHDR¨¨ãAÓsRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÙ.8(ªz tEXtCommentCreated with GIMPW ÚIDATxÚíÝ¡sÛXð×›’²ä¿ØÂ†åØf&$AgZhÔÉ•dÌŠÃ<%ÝÎ"ÃÒÚ%™Í² k ü_$¬°ZåTÕ’ŸdI~²?Ÿ™Ì®í—'é5yßüždùYáëÅ›‹©øøûÇðìâÍÅWC@*²eBáyþÄôôÀ¨°u³å·ÿþÃP"€€€€€€€myÛpqóh´€ÑóžÏ ¨B˜¿Ÿv²ÑÙ墳¾€ýÖd>™]. ؈Xâ@@€€öÖìr¿œ7¹úöåñv×xº›ùº‡‹›Gç €$è8Ÿ”ƒ©üÚOsÝä*„ëw.ÈôôàiÌ+ÿM?Ü© €Ý «˜ç~ œ“-³oáSNEÏ °«áTUeU9¹ûd û ¨Ã£Fí°ZŸ6˜\…àSҵf‰/g‰€$ (`¿Ežaø1·ÄŒž;Dì&ŒZ¶ÌÂΣڞŸÍB8=þñÉÏAMîÂõ«Ãè¶!„Úö1m†=@ç F'“ü¿ûL@ûÍ9¨dÇÜÀ+¬MÛ¨ ’Ÿñ¯ÒÙ•Ò¹¢rÐ_Ï¿êú¨j3–1P#¬’ö€ö[‚ç ’¬z¶0æ ¡ª)§ªe>ÀÞ$Õ1HtÌ]Å0ׯÃäþ¡¶ªŠi3 ØóYÿ] |ÔªóN±Ïµi³õ1`‰€$ (`¿9•ì˜ (TPÉq/¾dÇÜEáÛÇvd‡GBˆÉU˜ž‡Ìß{@“šçËNùäéq¿#<»xsñ5„°ö/ˆÅÍc˜¿Ÿvò³0»\tÖ°ßÎÏf>QwþöØ %nöá.„`‰€D ((FÍU|áÛ…`ô¯É%ý*(@8 §AdËìé =@'wŸ BŸÕðN*(’$ P  5I ìöøuåkujäßWnSõ¼€ •!eŒ!& € yÕûúª *·S%%  ˜óJUsNËÑܹ¢žËÌP  XéöøõÚ 0RàÀƒ¢,?/ur÷im4¹B¯ÜŸ«ø¨ ¡MÛ5 ™±]”a‰ ]s‘@![f!;<2*(€tLO Â@æoUP}Mœ¨ PK|-¼xq.Þ\HÀË_^†Ùå"ºíâæqð}üøûÇðùú,Tÿ„+[fáäס‚–+€ufKc  ¶¥Å±ÿao‰€AdË,Ì>Ü© R2¶ºè% Þ©C@’  ÀÝ¿6 €]à}P‰TTù{¥êª­Uï§*¶/¿ž¿V|¾î¹uÛRAìA8Ü}zúZÅ€¨jS›6K‰±û# vPÕH9œVKù¹UÕSª,ñl¹’²? `竪ªíÜ¿^[=¥VUYâH :)HÓ€ëcù®Íþ¨ Ÿ}Ã>È–Y˜¿=Þ¸¢©«`Ö…M“êèöøuå6b÷G@±æï§v~6k\íÄLþM—àbƒ¤Í6·ÉIP(P‰8š\…£ÉÕÚçø‘‹$èÝ‹G+ŸÿòåóÆýUõ‘·i»®ûék SØ7â|<<2*¨t+©}õåËç&ÑòãM£nâ2<†Ú|ìŠ_0&M.ËWA RŸ¯ßEXÞ¶.ÜÊýÕõSÕ®jŸÆŠ)õmÞ/µïÔ@>_¿«=÷´*hÊ–÷Qî¯dÅïYÕOŠŠ•QÌ^ÕkåJ¦®MݶšôSUÝUµë+øbÇpÝþlÒϪ궪oXÇßÀ!•Ò¾ä_©UqéªéÒY“e¯ºmÅô³tYœ79®bë–ëŽ+fª¦®'*¨ª¤Êºó ,ÿ·R=! F¨jin*µ®'ç±Nr)\Ì‘òþ€€~+pWml•Ϙö§X¹"E@Qñľy·.Lªú@ÃW&1K•©Lèmö'ö{ÊA¶Ï!æÿßLOTJáÓö¹u¯5íg[¡{µ[JÛjÒOÝ$¼ªÒØäØ7½"°«ýéú¸ØÙ2 ³eü%÷ŠÞµ=±û\Ûj3ao²O)aL›ªKÈë.^Ù÷ðJñã,¨†wÓp™90Hå M© €Vݺ%>—–# €­…Tm Š%>TPì—ó³™A€-›Ü?„B¸~u(  „ïïu8u÷fxíYâ@žü‰õýNù›=öx×·xã{^‰µ©Jbû)·[צüzùû‡¨¤ž]¼¹øú´$Scqóæï§ltv¹è¬¯m˜].B̘ís@-Þ\v^¶ÌÂüïÛÚ€š}¸ !„ð×í_O“ùªÉ½Í„ÓOì¶ŠÏÕíË&Á”ìýº;Iäc¦‚¢{×ïBèðHÕùÙ¬UõÔë¯ßUXþ½yHMî¶zq…€ØÖbÊ幦a”ɦ!•"E¿uW!ìøß¿ÿóÏðÛ¿þëßšÖç º ’U状]ùtÅU|‰TSM+ª6ßSry_±ç™ºÚ¾ jËúøŒ¦ª#ܺïç `/´øýëji®Ë%¾r_U}ĶP# §]l³+–ø§üÿw:œV|2pq¢Ï¿bƒ,•@…ØŸwTP;få@[õzL±}õ–Mªá¨„+­UK€«*±rUµ|9±å9¨bUDÌGžoÚ&f?à‡ŸwÔ>„S]HuiKŒÅɾ*0šž—*ÌxìG‘¯Ú~ÞÆù&Pôx[Sñ>¨bˆ”£-aÂÖE¾*¿Íj¯¥~FñãÂ×-½µ ²uKs–î`;Ö݇O@ ååºuKz]¾¿©ª¯^/’hqªÍ’_ÛʪjZÿ¼w<1# ¶RU¡Pn³îõØí¤PQ•+¦.ß[ÔöÜ  hëÚtÑÇ ¡µâT1¤Ú†E¹UÕÒ&mꪩº <ØsÜ‹E"šLìUmcúØ´‚4¸“Ýó×$~ÞP(ˆåÞdøyG@Ávø°B蟋$èÞ÷÷AŸÍŒûñóŽ€b$&WaZüÅÍ—@<öxÓ›go.¾†Âôô ¶áâæ1ÌßO;ÙèìrÑY_Û0»\„˜1˜}¸ !¸“D›1s €$ ((((P(P(P(P  P  P  P  @@  @@  @@€€ YÏ üßâæÑ |7==0F-ǧždË,Ì>Ü£c„ zsr÷Éä{xdŒ6#TP(P(H‹$` &÷?=wýêð§××=7–ãKyŸÇ´¯*(` ñúÕáÓWUh9œbmÛŠû‰ h9áq_Mþ(N£;®r%³ê¸‹mËã°®ŸØ6¤É$n'ÓâòfÝ2àäþ¡²MÌRi›åT°Aµ!œëƒÝ`‰Ÿ '÷O•„Ðò R=‡ÅªsN©Tb¤ÁŒ$¤ÆP Tj¿c¶5äþ ‚‚ÑVD»øWþªã+_vÞEHÄŒcL›òk»z夀UM^Ó„ÙæøÚ̘lº/l%>(tÍEP-³c„ Ò1==0ó·ÇƨÅ¡‚Ž1B   ûÃû ZÊ–Y˜-€ *!ÿh€h·ßÔ0¾|ùl çg³ðÇŸóè¶[¹†»o¨ P  P  @@  @@  @@  @@€€`¬Ü͵—¿¼ ³ËEt[À`æï§QíbƒŒ4Xâ@@@,K|ÀNX·|» ˆ  Su$œ@r!%œ@r!%œÆÍ9(`/*)TP  Ø]–øÎÏflôå//;ë ØoMnuÄŽÔôô „Óãî¶Üe_ìK|(P(P(P  P  PÐ#Ÿldqóh¾›ž£–c¤‚„SO²efîŒQ‹1RA½9¹ûdò=<2FŽ‘ €QP(PŒš‹$€Q˜Ü?üôÜõ«ÃŸ^_÷ÜXŽ/å}j_UPÀh&ïëW‡O_U¡5æpŠ=¶m+î§  å„?Æ}Ã~A@ÂiDÇU®dVw±myÖõÛf–ø€³‹Hqy³nprÿPÙ&f©´Írª€Ø ÚÎõÁ—"K|ÀÎMГû‡§JBèŽ7ä ¤FN«Î9¥R‰õÁ°³!•J%Ðt?óp*üÖmkÈýQA£­ˆRû+¿¯ã+_vÞEHÄŒcL›òk}]9) €QUDM^S€µ9¾6Ç3&›îKW,ñ$€€À¨¹HØH¶ÌBvxd Œ‘ HÇôôÀ Ìߣc¤‚¶>á#TP(P(P  PÐÒó¾½Ëy¶4¤ãYáëɯ'F€dÜþ}þØŒG™Ði †IEND®B`‚stella-3.9.3/docs/graphics/debugger_ram.png0000644000175000001440000001437012205116016020257 0ustar stephenusers‰PNG  IHDR/ÂóµfsBITÛáOà pHYsaa¨?§i›IDATxœí?¯æD–‡Ý« ;h¤þ ‚`B¤NmB8DC6"ê &$`¢ÕJlÄ„$h&E"Ü€Ñ"‘úC íýl`ɘ*ûøÔ©SUÇ~ŸG7x¯Ëõó±«ÊÇõÿÙ¿þñ× `(ÿ6Ú¼oãÁÀxðF0žÏ}ðñË|¸ä‹û…>øø ©Õ°…ÍDª^0fÛV3¬mõÏß1‡l5Ö®,8æ´zͦ嶤Þh›ï“2 ùâ~¡ÝüdÓIŒ©1Opö•¸èø¦¯c†qnŽùÍ7‡l\àQq6[%eÛä{ñ=}ø]K]’ –2pä‹û…š:NGkoÑî·Û·K}ôvÛÆjž»a-¥B¥ôÁ¡ß(Ï7[vzrS|߃îR¾÷ûÁÇ_¬^šÑH^|¡|ySOêN¦Ý~£R’f„ío!¨a?É)AwWäÛxâÕo”hº´_5êæÅ[$AL|ïôqžÛX¼Ñ´ñ:ùÛAº.ª\5²Mkõ¸û6G?˜’êK´§°IàýFWÄÇMY5HtEÂÞKòâ eg K¼F¸ä­a^½ñõ´sf7+•pܼ‘PºSÝ(ì]´ëÓ‚äÉ:Ê€ÖünƒÐ£+wö #J]¨W¹^ÍKÊȶ-x¥EÓü*÷&¸ÛÆ ¨ä™0{C$Ì<0OJðêUÞ-!5}3Žj¹`¨÷ ¯mîwÚèË T·ïœžIà%Ø4³Ujâ»±ã:Ã:u0¼ŒoãÁÀxÜæñÍ÷¿ ¹.@(>}ýrûïýÞÉ ŒñFÓ4}ù埼¤þò—ÿöUûã×_{©ýý³Ï|Õ"?7Ô"¨‘ß"¨MºWÜræÊý\Ñ<ÏoçéoþƒæäaÞr>úéÛÑ&¸1?¥?™~#OAݨt†R^¼xwùñôô³>¨Tm=®üð׃?>; Ò nÏ‚vIîea¹#!H©Y™ ‘m“£”æž¶ÙÔ¦iúðדìtzB#Û:¨ùæ7³Z;~x:•±étFë„U÷]äñâÝ5E·¿å Rµ<ºFP(¥Ê¼’—ùõˆ$ o(!¾©Ù6ßÒÇ6›ÚtðÙTtB#Ûº©ùæ7›ïÑw&=,ª–:aJ—í)óÄ^?@„ ƒZ@]]%¾©Ù¶¢(E®¨©m¶Tð­…½Sß,:<Ã?&ªºÑð-\‹X²Îîwá³÷”íwegÿ ã芮ÎÖÔ—úRµuìœïà½S–Æ·Þûd=²m‹;:žå¡Ð¶ÔµÛ­¹Ûo™£¼bkèÓú—m¡Tø?‘m{pE B3àpµÖ$½Aë¿ùñ£(»GZàÐoÓFç¢ tTb#”dß¾_"ÛãŠ|3›A-™TÔ¹z¤ô"IjµýF9mó þ-Їýío*ËЂ‡›o„+˜¦éÇg¿û›bÔõïGR1‚Ê™w(W’T_’qGA5_Wäò-)ˆtþVõM…ȶE9LÕͶÇI÷R/Çm­v †7ÓM.£\8ã4Côjyf:Õ̽Âú-Y:_UˆbPsÇ7|é“Còv]`·Ü[ª¶ÍQëïš|öN…(¾iZªÖ¡‹(ïòÑôåcíÖm‚õ¬Å x—A ¾Þ»Q :rÑ5lÇ F-† xiF¶MŽb3¯m¥jú¥?3æÊQ|Ó4`Sÿ‘·Èo$¡BP®ß‚7€ñ<2sè~ÛxØnF÷Í÷¿Ìó<ИFDßß(òNY¨¡†j5jó<ÿóŸÿyzæ›7ŸO¯{SúúåÛÛ9#¥+šØm úw÷ý ßÆS°NÝöߤ·ÉwAÕÓ¹fš–»sGí4µnjSùLÕ‹ÞémÔ„Âh.§pŠÊå+,-¢Z¿ ªavê®ÈÖŸ%“×DͰjîjSùìý‹ÞéÔg¶ .Ôöí.¨jvHKF©\{#Å׬¡rQ5Ã…PsW›Ê³ôEïôfj²xSî7Þx;hP&Ð(!É}?LŠÔv_.Alƒàô|‹A#v±Q9½Ÿ+šçùíÜr„w‹í$dWtT鮿²Ú~Ôè<Ü6ˆ Éwu–‚/L÷r:dUžFÌÏ_éO.؉üèßz„äôMf›ÚQÝ(‚mÐŽ¼àSNÛQ°†wS;’†õ8ÕßžùŽwªB-„è7’›¿ q??¼÷É(‡ÔèÒ–Ù¯î»í Æ×%C˜’v¶Q‚Pë¦fà¢wz35¡0Ê)(±Ì~m±ÛÞùèXMQ?wð8jrj}Ô’— RóŠwz35¡0ÚÊikŽ6ÇË+1Û#§±¶ûï%Qò z|ú|Pž“êEPÍ&ˆš£šù=u¹;½Ÿš¯a.Ø\Ž vkÝû5¿Äꥢ´Ô@g>úéÛÕ%(A²§x‘éß)bhXL^­1HécõñLì¶àŒ~£í:Ë‹q÷ÕŸx ¤ûGöË ‚ÂéåŠB·|õüÕÄn{¨¡†j£Ô¼¤ŽØ­! ÁÑ Zê.LÒ94eµ«]×uKyÅcê`ùK{äÔ%ìž Ä² VRæŽ&·ºÌ7&”Î<@Í]Í6ÇâtN‘ jcÕN£å·ÇQ%ÞhqEú÷Š8Z™TB­Z]9¡}WAðš¨WÝßG 4¬Å°¸™Ä!¹ì¶—¤èS¤}·P¢¸¨•:6ÔF©¹\5™yž‹va¸ªÙ¯».§™I—/Þ]ÿÖƒOÖÅúGMƒ~›Ô ¡Þ=1Š hštôRŽ…µÖjBkðSùÊr£¦Gÿî¾x#8'ù|ÊŽ„G@ßÒ«qo£J,kxÃÒ¢ÈÝ£º€Z.ªo&²l1®ásGj×ðvÙmOè4ô¢æ®–à¢VôE‰Z5¡yÖßG ”8ô¹ì¶'t ú QsWKú*Õ  6\-ï/ÌÛ¬ôz5P¢òF¹É·­7EHWC’£æ«f+uW¼SÔlR¨A%ì¶ãÁÀxØmÀÛn{»í¡†j¨]l·½[BKŒoãQµÔ%+/ä]M•óvçšmÇPî—Õ„i5á|Ã<¸|eÆ"Û’Xùù^Ïí4Jm«L…JÛZÜétœ sS:¤iZ“ßÜsÈZY¦*5ÓN±¬ ”,¸à²Ûžò-¯ÌIGçØæ¢'¥NÎz’(6Û„‡ãøÜä RÛêS¡Þ6_µé8R¡Ošúæ7ÁkÔô ¥-Ò\L’k18bi©Û.¾Ðzë£$±ó9Ò•æÄå´ø‚ÓØ&<œÖÏí”áôDøF)}Ó´&¿ÉgÔâÔŠdÃî±;cSg®Éì®=“|›èó“a%¥¬á‹òT䡨€¡¸ºý‰ãжo!ó N±ì(ÑȵH<•¯ %¨Ùl[ßÛÉwzTyÅúÏ ƒmŽjaSs¡QÂÉW¬¼oÓëä]è o$ÐàÐoT>'¹4p•RÙp¿%²+šô¦È=àýFa¹Ùíp/tÔai©[:‡ú,â T™‡×Ó·¡ÊæòÒ(·äaoüÞÄLÖúrzwøéN°¹C«ÝͺLÌ<ìCl…®~€”R;Š!©'ÙêLBþ0ôÖtWºŸ_Ã鵄‡3¼¯U0àq\‘!¦iM~3˜4<‹ÚhmöýÖðüôõK噣êwÛËGI¡T~Ô©É:¢O?°Í6ááøöµæß†Êëîɵ°$×5cpú¤©{~«´!éÍŸö.—F1ÓnÃý\Ñ<ÏoçI¹2¬q·½ÒN9ý(óRs”ªTΣØr¶×ͶèØß8|ÐA7µš^iZ*¥‰åu§-R¡èÌü—¢ªä£Ÿ¾m'Þ™ùù+ýɬSãaÀøÿý¿í¿ß½ÿÎÚ]—Ýöœ±í¶·¼w[êr7ÐÔ1Qzѯž¿š&×~£DÞ) 5›Ú¿þÚKíïŸ}ùNQCMVó’z(h©¸Û:ŠÐˆw´ÖrÖ”‚I¨cý oïÞg×mLgxGA«à®“PÇCË|£)Ò]9ßhAÂ_4ºwÖôÑ0ÁBc@´%‡·Ç—•ÏÍ ¶ð᯿ýþñÙÎÁ7ƒšàŠúÐȶ­\eÝ…á¥^`TrËNå»÷ßIþÖX»ÇcòÐýF•E4Ž+ZØÖž¬«ií.ƒdVØmăDvEÝòÛöŠÑÊB7ôõ¤išG¯\œÔ`[·ÒséÞûdûïªM9–~£íâ .»íéÉçH±»â¡‡]jØf3 ²mò™lhúܦêE"Jmë–CZ?·-?¼÷ÉG?}»ýKœÓ͸X¿‘¾<ï®ò4zý+l«±m—ȶ¡šb[#î]7Šâ„…¤ «i õô§ò5¦°-‚m‘mÛÊÖÛVÝvi:Ü6_"Û¶pÔˆ·_ëRÛ ¤‚µuo‚àò{«|Ë@oäØV.Ÿ0¶Ûl¶ÉD¶Í€okžêûÜJq·Í‘ȶ-¬b÷Èê<’yÄgÃ4²é`rkiš‚Ën{ .»í ú®íØn…M%Øf³­[)µMX|Á¶.ƒo*ø>·ÈjGÑõ ¹y²Í5âSÛoä²Û^’œÛ©ÎB_5_°ÍfÀpÛºa¸SßçY-APS¢…+òâ¶ýF»ó'vñº²m1iñ¥lkV/æðûÍ~ÑÍpX§. B=ý©|)áÕ`xk`›Í6_Ù&¿Å”ø.­LP”¬¸"/æy~;{Ï7ŠïVäœ4¶Ûl¶¹Ó¶ü±$MLš§áOæ–\ËÁßi»ñ¢éM5ß(r¶]š£ÜÓÓÏë_«`‡ nÛoÐàßÚp?ò¶oP£ª­¹ì¶—|kuWLºb/|¶Ô|Á6¾9Äýûç^ßçY-¡g6ÕNìq×zG¢;YF1,ìnÿjî^:ÉKûÏóv¤£V¦þß³ØfÆ1‡¸“¿¶}lùA÷Tð}n‘ÕŽµüHO¥3 j $Än{ Ý:ä‹ÔÜ»»±Í\z½4}ms|hýo£æûÐÜ“ 3Âx† õøú£Q« ýF×Cp‰·XØ‚ŽNpop=\œD¨±ì¶0ŒíRúÝö¶N(qH»Ã òf7ùxš_E »í¡†j¨T›t¯¸š}ùV–u[W!¸£æ89Vkö+ÀýPŽðö¥Ýh´7ýF÷!÷LÛÚ!(?a䘺8»íí† ‚ÉÉ»óÔdA9ŠmææN‹n5Ô:¨ eÁ·d¹—ÓõÃÔ¥zÛZû[K2HyB%Ûm¯Hp÷¸ã”ˆ]o§™X§¹Så]£†ZOµ˜“4Q–Ô¿LŽN“¿•sŽz†»©nÃÅvÛ³ ÆA§ù”oÔP«v]Ö›u¿Í°¯š+rÃ~#ò¬ìú]—W„FçË/ÿ”W„ŠÑ<ÏE»0܉kì¶WÔo¤o_64" Qnüi ° ”ß’Õ®œ*9U[NðýöýôõË·³—X”“¦Kì¶çÒ´âØÔúïÝÖ0]¹ßÈ]Mßå–Tä#ý»û~\ ¥.r³[dÛ`ÏÄKÀìW¸9O›x‡|A®õ!†Ò DßmïBhÌîÔðPC­§LT³ZâÐR×t·½¼3æ´Ì$e,‰•g¦"AAMY˜îTB µj`x#-P+:å»í•–“ž]£¶2|Ñ®`Ô\-¦U5ýC(˜¡ßƃ7€ñ°ÛÀ0¶»í=8cæ‘°…–:Þƃ7€ñà`Ú;}Êè*èSŠ–:ÞÆSÐR÷ÁÇ_¶-·ÅZ".?†ì•næÅ‹w·ÿ>=ýœŸðe-> C ÑQYHŽ'¡‰B»Ârúˆ–:<:á6ƒ­Ié’Lqû–Lä˜àäi–YþÅ!A¶¯QóG¡¹,hòÿ®ÓòE~D}ž˜p›Áƒ¶ êòN£¥®-¹+Zv(i+ÿúÇ_¯þaך!(BýÆ”wy§¹Õäjï64ùbi®xe}j»•ÊÓÆ„õ)W–ÝÄ£†CÊWû•ÜH0ý¾èžÜ¤ntÔS°œvôBÛÆÕ¿š®Ô7o´›fùïí¿yÕ¸E{BîN„ƒ›S9=íZ¯âЪ¥®i¬J„–º¦ÐWAèVî Þ%)&ÝüÓÒþ†#ˆ7Ú­àk"ŽM{¹-Ûž×è6Z¬Ô‘Dè@‚Q4S—¸¢Fb|ü…¯r ÷€ËÔOûÛÑ”;¹oÜ`Ik+F€$ƒè\¾ÊêFù#^Ò/d"ÿ»{|:ÛÓnZò@w)=â\/;ÅQ½Pîä"YÊQiŠSL„Q Þ?ÉÛ|ù‘ 4ý>]RðÙ]ÛI¿ùþ—K}ÖáuÀ‘7o>¿îÕÝVMå]}JÅ]‹!&x€°Œoã¹sKÝ¥÷ã¸(”»SxD»Üv\Zê`‹"^³r÷ü²þóáæzÔžbCٻ痔›{Â' ‡n€ÂF͆ø õ.áolj95êáæzý¨zÉÛPv­ÂF‚ËŸQ7È{ÚOl(ë‚"mWíËf”õdŠ4dã=±¡¬ø£:pÂpÀ¹Aa¢ËÙFÍnÎã.v OqùQœüg÷È£OÈ‚zÅÝ`¨,Šn°,Kfqßoox—à5MÌ×Ïï/7zÔ¬±SAŸEAeQPY=|öTñm2WçT²î§âê0'jLº"]â›-Í3©²©´Êt“Öl_ÅU1¸ø!1ö”õY@Ô1R1x&!ß½G†U7`*ÞƒÌçºDÚxe=ÑÏuÉ@DýZuƒò²2¯ º×ó‡Ô`7r—1»²µYwôzºÚQ*Ù ÆBeQœ4ïSqe˜ŠÃ¡Ï¢ ²(¨, ¦âÊ0‡ÀTSñHjV1OµÒ.8äjeueEPêÈVrëÜ`Î#×"ª ø+j¶ƒ¬!¶zxË!—*‹5Óž7Šnà-cg åà…)Ðb]ã©wZ@©²—ú¹ÁÀpÐ5d5«.®lkâè»3usƒ0æìFêuç”Õ |V±reIu&únߟÍ=-,9ƒ)‚ì”•Š¾Ã!»Ú2œë(¨, ¦â(˜Š+ÃT}•EAeQ0W†©8¦â(˜Š÷ w¦p€&pW¶²< ­1§ã†ÂEKºA’Æ|¢®%YxØñ…k¯Zò lêzY¸ ÒI\xÕØé|v¸ k…ä¹AÈ&p­|je=S5brn0m¾ÆFÍ–$áÑà¶enÐ’÷VV|ú’%áºnPµ5“n`*‹‚©8 ¦âÊ0‡CŸEAeQPYLÅ•a*©8 ¦â=°±ÖÕ’¥kýŠk-6”u ÒdB{é(ÌÔlŠÝŸ¸¾ÜH…=жÌ(›ÏÒS±àæ†ð~œ˜Q67øo6ª{â³³Éê£lømÃ9‚²¾Z[ÄUWÌøláY(<¡­o„ðÙçU-åU©8ÿS°•Eqõ›©¸sÍ!vÓž6¿zz¼»+G…>‹‚Ê¢ ²(þËz.ôFIEND®B`‚stella-3.9.3/docs/graphics/debugger_tiazoomcmenu.png0000644000175000001440000000244312205116016022210 0ustar stephenusers‰PNG  IHDR%£C›ŸQsBITÛáOà pHYsaa¨?§iÆIDATxœíݯo$uÇá- I5ªÜ‘×€ 58®[QÕ„Š ªâÄeE“Ãà9‡âêΜ¨YAøHš3„SˆMæ&3;³?ºß÷ìçɉ2»¾b^÷™™íôF#Ø=E÷~ysZtÿ¬×«çO‡^ÂŽû`èÀÑäè rô9zƒ½AŽÞ Go£7ÈÑäè rô9zƒ½AŽÞ Go£7ÈÑäè rô9zƒ½AŽÞ 磡[é׫gsßóÃõec‹ù9~¿2ïùýÊ×?÷Ì7Èqý¥¸~ƒ!™oðPwÿT}ýùMí…ÚöGo™od¾AÓ]k.õ¿gñ}šoc¾AËíyõåÝ诎7wlïc¾AŽÞ Goãú Z¾}ÿ!Z×ýɺEîUúü ÒÌ7hZd¦u½¿ÿ³;ó rÌ7x¨®ë·ö¬3ß Ç|ƒ‡ZüzÏ|ƒ½AŽÞ Go£7ÈÑäè rô9zƒ½AŽÞ Go£7ÈÑäxgžÿqqq1ô*V÷õ—¿ÍÜ>}ñ{x1;éâ{ÿêûO‹îÓòÝÐKX¿Édrttôïß ½]`¾­ß»“_†^ÂZM½‚Ýáú rô9zƒ×o]?y]ÿÏ«—'C­„ ¡·R®Ÿ¼nÖÞ¾q> 9æ[)=ÃmµÑ×8;mü_zÎ]»^ª¶_½<™~mü–¦·„FNÓã»'¿™V ¸¿íÆ{œñ–æ|²¸™q5RV;Ä…±¥ôVVO)·–}²áôVPÓWg^•­¼O6œÞJY$¶QíÄòáûdó¹_RP;¤™·%<±¬®÷Ú;lG[¿#2÷cw ÇÝûåÍiÑýošw~6Ú¹çþ~ñx4ýóvþ? Ï\Î'!Goãúmý–½å¸áÎ^ü8ôv‡ù9zƒ½AŽÞB‡^ÃÓ[‚ؘÒ[q‡‡Ç÷÷o†^ÁçeÍŒ­½q‘&gÉ껯Ö÷ÖõRµýþþÍôk/”¦·‚º*šßõã~‘½'Ñž€ûÛn¼Ç(.Íùd)ýÇn5RV;Ä…±¥Ì·‚'rHSn©ÝŠmKé­”¹WhÓ-ËÆ#¶­æ|rU6Õ‰åRßÅ–2ß°Ú‰eu½WߨmýŽHÏ­Ë®-¢·F`=¯.²‡¥^ízIxyÎ'!Go£7ÈÑäè rô9>(«þ3øÃ®„M ·‚Vx€Ýæ|²”™?D2àzØæ[)=¹yÞtoé­ úLëùIÏ›îç“MßéŸöñ¼éÒ[)s¯ßzú“`çÏKÚ×'ÆŠÊŽë,–°tQæ?ø5B&Ef/Ñ‹‘kÒõ%(™^b–9v8aU œÀAr0ˆpb ´‰•\âüèÁb¨D‚Ø4ÄŽQÿ~ýú_“šà&H QR@ÜûújpD»Ìû—‡ÝÅl© ¸~­«&õ/;?ú‹Ú*Këï'–ý7g‡XQt G3Óìø™kRÿ²ó£¿¨9ãò"×­`‡XQ8¹ƒ“ïËï;÷¸aÙù´ÙwwEKhRÿ²ó£¿h°æÇ%­ìN˜TÁ½4Åf‡´7PxÙÍö7,cc$=DLÖ2¤ÀfÚÆD"ì6²²Ý±ŸåF¢1@áâöY`q Ût4÷ hRÅùŶû BÑšÔ¿ìüè/ôgÌ.x¤ ûkã|a„¢%4©ÙùÑ_Ô\ó±dœ½ E b„ÚêŸÂ&õ/;?ú‹ÚŠ(vÅuò¹5;ÄBu™`."œH›F‚ØU •H›F‚Ø1H‹ÁH Qál7ÉG`?ê.»Ñ^´Ä®þúä´²f›m^ïöÂfÛ)IÛ bWcäòx¥;½Þ½…ÇMRØX4$Aì%$ˆ]ý,c^õM^ï¢]æ) ªõL öÐÀd7ZÍ#MîÏ þÐNTޱØÑœ4öÆ~‘Osâ—a‰w«‹^vcVÝY •‘÷M›cŽˆ~t­ºô t™»bÜp9€\u/˜C›@‰µø½à®1kä±Ð„¢;UžöM/Ú¤þeçGÑDD(8H;H“ú—ýEÃ8q9x5ÌŠŸ.´¢îNáã¸ú'µIýËÎþ¢¶òë›}6ÄZ‘æÃü:¬þ¾uP…(v+ŠÆ`.Ħ‘ v$ˆE%Ħ‘ v Äb0Ä@ bà¤n–9v©Z,IÉ,™÷<ok›F%gÿƒS½Ô°-!¥M,¹ƒP„ûX#A¬¶kNždg³VéQc—ÅéIõZPÃæ.¥«Œ5Ī’Ÿ*öý/~iBË+¶ÿÁ©^ j8˜SÛÌ"ÜDtRe|žùNX{ˉ¿üÑpð¡'Ò_ÃÃú˜ùµŠpºÄæÜî:÷Ú õÔÿÕ_C@¦kR%9Ì´ÄO÷°‘2”yŠgóŠpŠ®CL3ñIÐUa@ì1©"#¢! )y ¢¢0©²D4æ%3§b‹ÉóQR½ö>@Ò¢0s2~REI"Ïà•&5žpõxÎ|Qñ¡åý+*®asöEB‡mèšT9"Ÿ]=h¹&5¥•‡–7STSöbò]Ú%ìSÔe€¹ˆp"Al bWA‚XTzÆÚÊð0³…øùÛ¯‰G‡àí«³«L°ØïÞ}â)žri{`LªÀ)ÐBôïɳÇR† l#ÜevœIŒègHl˜3Q[Zl»öÿßg’|b“åÔdÀQ¶´Ak ç +l38GêxêîTÑ)–@¿ÇQºþ ¨ýÕѯkk`ŒG…—«öHµcˆþ™­I„³DÞvµk”!Þ„‰ƒføÂ-ÄX×À>•=~d®¦çœÒÞÉ_EÀü=¦óÛõXð匭;ͱàòmÁï”Ð=/è¹;Õð’‹í-VÔ£òF$²ÆƒEÚû[V¾ )‹¯F7™ºµ¢ó;’Ð(ëM›Cä°q|?dç5¯¼’‰ò1ÄØË¨—- &.Ì~’²÷p5î èe H¶jöÙd³zB‡Ú/ª¯Õøƒ²kqXÌîA꣆Â6¬¶úl¯Sk soe#€½Ç …ί½MÎpœ¿ÃaÚÏ2·úñÌŒ‰&<Ý6(Üö…¦gr¶¬Âà`sùí>û¬®×eVÅç*@ýúËõÑxº„aÑA”õ1TÿŽ€(W+g¨¸ªF× h^Tqš·™­Ý«‰ïÍÐΡó+–s<”u÷œ¢ÌËGv-ƒ5Låïð(:QÇ6]æb59Ü»~«Ëvî¯CÒü@M*†|e3N‘sùKÛcå?E¨FYQf µÍ¢8Hî'"œffÌ&A¬Z$ˆÅ=ÍCä[@ºÌp" À‰€'"œˆpúÝp£v’²mIEND®B`‚stella-3.9.3/docs/graphics/eventmapping_combo.png0000644000175000001440000000641611433323254021520 0ustar stephenusers‰PNG  IHDREjÿÇgAMA± üasRGB®ÎébKGDÿÿÿ ½§“ pHYsMœÞöœWtIMEÚTÞ»øtEXtCommentCreated with GIMPW YIDATxÚíݽŽÔX`ƒ:!›¹”!#\$ȸ"Ôš¬³‰ÉÐ&«ÑF„›rHL8vßÅ’uÈ´¯×?Çö9Ÿ]Ï#¡UոݶÛ~ëWm½š¦ùvýöº¸t¿ÿó÷æÑõÛëopénïn›¦iš«ö‰7/~rT€‹us÷ý;ŠB@(E¡°ÒÕ¥€§¯ß5_>þ–¼lÓ4“˧,Ãøq«åØu·§Ô6íq®8?“NþÀ_Ç'âØô/Ô½ÿÝí©e›J=Fаj$u†Q•@Ša'R®“mh=Ý‹qèbz.e=cSÖþ:Ʀ\s¿k”[SÛ2µ_QSþ©sbh{R¦ê[öiìØ`ú¼hÊÖŸBM¨Sˬ™®­²-YO{/uh™þ¾ í[®mÎõ÷ê?¿÷öŒ6Ç–›:†[÷i˹)«Õ¿ ¶Þ0/q‘¬¹øºÇìoÑß×¹pè.ñIÉŽü]˜>W7¥(9/uܶ¾KÛ=þF3ÅJ¦ÎÝ |Ï sîw÷ƒhlù¨}šRï} ÁôùÄÁcÄWj=Q×)që`ÉïÚ×=·Ç¨º¼_2{Iß§¸åÜ5ˬòŽ­cj4–ë]ì¡õ•z÷9õBŸ{6g`lyGxîÝúÔ{¢Kö}ËíûÝÍ?þ¼ÜP EÓg€¡ „"€PŠB@(E¡ „"@塸úÝ÷{ì±Ç5=.ðõuiß’óú]Óøz¡Í>|úê @&·w·Íû?>g˦ö[rÒ¾y[ fóþïoÈàÕË›"Ùäž"ÀâPÔÔ¨@6),E÷ȦE§S8g(¿‰lJ{òäiÓ4Msÿeò9 VZ(ö>’S[æ³§î›Âñø¸ {Š;b;:ê¸N²NqK§òØÏÌõën1Žýž”Í5b~òäé䔹{Bô—ëN¹S–ë2MçH8xì}O1W0Œ…äPÉ{÷¹þ2ýRñ5Û²÷­€6ÌÆ^ û¡7 ÝçûËÝ¿œ c¨m„qÎf¿§ØŽ¸ÚðÚz¿¯¶û—%¶§?Ê Ĺ`nœÑìy]àžâÕž;ìÍù`<ê}(uÎÖ1R\˜ÄÝÑâÔèê‹Ï?Öõª •ª½§XrÔ¸5(KÖ°Ä-s'D;]Îù9FŸ‰ähÁu®®º§8÷Îqw´8ý‘äÖI™¦Ná#ƒoI0® ±±7s"‡Ÿå¸§èû}øôÕW‡A&¯^Þù>Eÿßgà¸|Ÿ"@Y¾O8.ß§P–Ž–`¯^Þ8ËnŸSl‡¨íx¼êñ›¿5Í‹gއÇç|œYÚGrNnYÅ)Yè}†|nïn›÷¿>ÛiúL6>¼ y”º?ïÝg¡ „"ÀzŸGö¯ôþè}†„b­˜³÷¹ß1˜>_œ~¨ö[#FŒ@×IöÏ)­÷yéòzŸaŸ@Œª$X5Rl§—kGRÝðjÿe;Z¦ûüÐã#èw3)ËÝß\®»Ž±eà#Ĉs6û=Å3ô>Om³Þgˆ4DÒû¼ Kÿñõ>Ãü9[GïóŠÑÝ{Ÿ÷ Ä3¿êBÎÁBÄ9¬÷yáÏé}†}‚±®Þç„iïQ{Ÿûû“k›JãÚÓûŒYN:_2Hï3äóêåMÖïS\Öû p!„"€Pгt´Óû B‘o^üô½÷0}0Räè}†|ô>Ÿ„oCzŸE¡ fé}Þi¿ô>à B±Ö,ÑScU`ú|È]3bê¸Nô>/ D½Ï°O ê}î,Õû¼Ç”Yï3¤õ>7±÷/»Á;Õ/S"õ>CSÅlFïsB°Gýñõ>Ãü9«÷™C¿êBÎÁ‚Þç õôfjzŸaŸ`Ôû\`dšúó5bõ>ƒÞçÓÒû ùè} „"€P˜¥£%˜ÞgŠ<Ðû ¦ÏFŠ Óû ùè}> Þ†<ô>ŠB@(ÌÒû<±Ÿ%÷Iï3œ k Àœ!¦ïLŸÙ1õ¦@]׉Þç™ß7œzŸ!.õ>w–-ÝûqqŒÞgH!ê}n껩÷â ‘ô>OlÞg¨k¤”zŸ¶cÏéôÙ^u!ç`AïóŽëIMê}†¸`Ôû\`dzäBï3—ŒQô>Òû ùè} „"€P˜¥£%˜ÞgŠ<Ðû ¦ÏFŠ Óû ùè}> Þ†<ô>ŠB@(ÌÒû¼Ó~é}†„b­˜ë{ÏöMÛ€éóáèMº®½Ï¦ÚzŸ!.£* ®ö†±ª/è>×_¦ß«ß%r*=V0zc'F÷ùþrc÷/#{/ Ç1âœÕûÜ ·ùMõË” Æ©@œ FáÆé}®D?Ø#GŒg¹/¥ÎY½ÏúUrô>­§ÿ3SëÐû û£Þç#ÓÔŸ¯i«÷ô>Ÿ–ÞgÈGï3@¡ „"À,-Áô>ƒPäÞg0}0Rd˜ÞgÈGïóIøð6ä¡÷ €PŠB`–Þç‰ý+¹OzŸá¡Xkæø‚Úˆ&@ÀôùP#Ä=Qo Ôuè}Þ0ÅÖû q¨÷¹ó¼Þg½Ï!F£Þçߥ÷ê ÷¹zŸ¡Î‘bDPê}öª UŸ³Ñ½ÏÕ¼ûsèW]È9Xˆ8‡«ùBˆ\£´Ò£½o´Ìít9wï³ äHÁ¨÷¹ÀÈôÈ'„ÞgÌrbè}¤÷òÑû @(E¡0KGK0½Ï y ÷LŸŒ¦÷òÑû|>¼ yè} „"€P˜¥÷ydÿJïÞg8A(Ö€9¾G±ß8ö]€éóéõCuª]°Ôˆ¨ã:ÑûÜ,k Ôû û¢Þçβ½Ïýõë}†úFˆzŸÃ)õž¢Þgˆ£÷yçíèÞSŒ~³Eï3¤³zŸ9ô«.ä,T{O±Ôh-ÇÈqÍzú÷çÞhɵ­©!ֽќëĪ<…š_Ìõ>™–^GÉWJ½ÏÆzŸé}†|ô>ŠB@(ÌÒÑLï3Eè}Óg¡ „"€PŠB@(E„"€PŠB@(E¡Û¢/™ýðé«#@ݬs1Çùâ­»¦; ër{wû£çâÚóÅ1ZM-®#xþç¿å’ÀŸŸ:ÎÅlç‹c´üšrO@(E¡°DöÞç×ÿþÏÿ=÷ñ—Ÿ³¬oËz–ls©ßÃñÌÏíŸ{î(ûWó6Gmk±‘âÇ_~þ±ÑC'Ö’ƒ°u=K¶5e›Jmu^„íù‘r1s\«–\§UOŸp°!wÈq[£Bçâ¦Ï¥¦Ùcÿ-jzÓÿ=cëÈ}ûx”ÛS·ºR®‹Z®«ZN vZºô Ø5ëY:âZÎýâxÎø7N½¾ºÏõ—I¹.jºvª}÷¹ûªqä©·)Éå½ ûº¸ªõ$êǧ^M'b»ÍÞ;ÌP8㬠úúªáz¾ÚûD*1 ?ÂtÁx”@Œ¼¾j8n÷8°cËmúÑßf×á(Ÿ¶ÚÎÈó7åwíu=]•Üé±ôÏ5Í[ÏÒeRßYZ_ÿ# ¦Ïçùñï9´)çs‰ã˜²Ì’ë´ªPLÝÀ”墖ÙúŽ·<ÿÈoÉ?Ò9°õÚHÝÿ=®Ój§ÏG"„"€P˜µè–Û»["TÁ¹èí>RT»çý¯Ïçâ¦óÅ1ZM=º~{ýÍA.][ƒêž"Àšé3€PŠB¡ F]5Í÷O¾ßÜ9š¦ùöüoÏ àâ}þãsó_fÈ‘¿ÚWIEND®B`‚stella-3.9.3/docs/graphics/rominfo_1x_small.png0000644000175000001440000005153611433323254021120 0ustar stephenusers‰PNG  IHDR à] õsRGB®ÎéSIDATxÚíÝ1¬Gv á–ÀÀÌ4á†Î†ÙXØ`h(0í6°7²Ï2`̓ ~‰Ak´#{ƒ…´Ñ(–“™Á²#?e7´2N¦ ¤+7›UuNÕ9§ªºûÿBºïÞî®®®¾}Îíª®·–eùæúéõ‘~öóŸ-o]?½þ†ªéî«»eY–åÞåOÞ{‡Zâæ«oÿû6U $ H@ Ù=ªDxþÅ×TÂAÝ}u·<ûð!0—gŸ<¡èýÇ7Tú% ï^ݾöúËÏ>nZ¾v9ô³>Æ{:Nï^݆——ö €Ïu9olcÍ\L²×xåˆñZm vϺòÚ ~ùÙÇÙ†µ— 4²Œ£Ë¿Ýþlõ9º<šök)ãÚ/5Áqíõ.õ÷íú<®—3Çc{×$æAèKÇ®3Ž/u€W`ß,GÛGº^ïm_îE4:K…HË—Þ¿¼g¹%%­û ¸g4MùsåÛ.ÑUH³ÿ‘åÓß–òy·ÿÒ/*‘í€#ÃQ¿ìŽÇzÅ#¥xVz­Ýÿ–²ß«mP5;TÛp¤å¥÷/å³D©üÖ,¼Ô…G*¿fÿ5uÖà§ÊW{|,åÓ_Kù¼¾tsÇ·Gû`/¬A¬eù‘ñ˜G¼\Úx§&žjZQ}D {fl=³lÍögäù‹EKBµ§_]"ë¯æËnû%ÀÙ’KÐ|HE ÊÍO_.Ëâ0€¹HɃõ} ÝÜ£ @”÷ßP H@@¼'ï½³,ï1NÀëè‚€ÀY«Ûoÿñš×¼æ5¯yõšI0àtó€\Ý.ÏŸ^S[€0O~þ³eI<úù_S90ûw¸bNÁË< ºAèŸ}¼,L&¨póÑsõuãæ£ç$°Sw_Ý-7_-êÉ)y `züóª}ܶ~ ÈÊýûï¾ñÏ›´Þèí’Û—Ú}ÔÖ_Ï}˜µü-u.µ?÷{´©YÏK¹Žô}p:Œ€Sh~ Ö«W_¾öÏû¢ÿêÕ—Å#zû{rJõ§yÿ,å¿´¥Úä£Ôþ¬ï_öÏ+‘Ëí_éÜéѾKÛèqN“¨ŒñùÃGËçQ@"HôËÝ[Àº©À+D".0=r}o÷oD?Ã9Ë95&ùHýÿž®5»°1 ©_tkÞ÷°ÖÛ¨Ù¾´üåï­ëïQ¿‘ëO蹿ªK¢Q[–Úà]»þKl­›Öe­í»æü+•Ïcÿ[¶¯)?lÉÇúo_¾ r€$áêvY6ᵨšV L¤'W&©|©ÀGz_ŒGvšmý¥ú³ÿÑRÁiéµÀζïšÀßrþäê(2¹¬Ý¾´<ìÉG2 ¹ºå.€´)Rpa >j ¬%@]e-u;*ðñ>>ÞëŸ!H·&pš»³ߨ»>#Î×Ê{tÜåÔ' ßÍR“„´hÞÖÈ b}·eMíÝë±5ad‚§IÒ,e«9?kê¿×ñã®Ã q÷Námë ´])¤îµ‰¶\—ÑÌö)GërŒäµšº­ h÷^7–îi{;þ³¿ËdÍc@RÁþ¶øö3¹¤%õ˜ÒíÿKý·kîÂÔöÑ׬£¥|šõçöKƒSª?úÕ<&W[?µÇ_zßZÏšõ—(kÇ(•Ú«W’Òz—ÇrüZ’õÚ1Aëòšs$ªý@vóÑsý‡$ ¥àDú[í<µã7¢ûx[ËàjëÀz¼­û7ë|‘ûq~¥N¨Oz$ ‰~¹— öŽ2Ñ^-ißg¤Ý2Qàe™Ü>Jïk‚4¯6SÚ¿ÒñéÑ^KÛˆÞÿèóÓº¾Ñß=¾³HT0H@f üSÁîÈ€o Xt}>Ûí:><)ìÜ8þ¤…ÍR3tÄ…ºç<µwjæmi¦ì–òKµµÖ¥WàÕ:K·5ÑYÏ¢­iŸÛ÷/ÛÕ,/MÈ7jÿµåÏí¿µþJËç·Ë߬å÷¬ÿ–ã¯)ÿi1H@Z|mÑà¶fÞ¿ÊG=ʯI ´¯÷@iÏRý§–Ÿå®‹æü”Ê/µ?©þ¬Ë[“ø^ç¿åøk~„àÜ ÈÕí²<½® âj‚¯Ú`m½íTÖë[=ÞAldð0CùY¤õu×g†ã·‡ò[Ë}þXë‹d£p­á.€hÙ.°ë_C£Ëãñ‹nDýE”Ë;I°”­¦ýÕ¤š.q³ïÿ‘ä"Ps+¢þ@ó< Ú»½ɺ]_'!õdFwç9c;CÝ¡þZÎÙõ#„Kã7JŸ±–61w?àîy¬dûK¬4F@3¦ v›RR”ûEÛ:¹´îõÿkö_[Öz’Ê'íŸT>íúGÞå) ¶¶Ï=ìMÝhÚ€4þ¡fym{Ï}F{þKÝ KŸ+•_sü ‘lÆ€hº¼HÜ–€C€h·ß¸Õî[ËþGvç²wu?bÿj» ZŽÏŒûߣ {-ï‘PY÷OÓ½¯”Õn›eu­á.€}`Îór†§¬ñýÀȤaˆþI Œ»p oSæJ@®n©)@,®5p ÷¨ÀÙð(eg5CWæ¦1 ©/î£ôË.]”ö²ÞÇ'÷4 ÒÓŠ´A¶¼ïu<ÖëjÙ×½µï#쟥¼L@81Æ€À)4߉ gÉ ÷ºOR0í°Ö,#ù5ï_ö1rÿf ÷RÆÈ}ì1 <‰ J®ÿö•Pðâ¯H&ÑîÑÑóè³D`{Ôý­Ù¿è¹8öôc:áZ§6$² NjfïÚõGîߥ<¥™’¥™ g˜Á+0m™å¾&˜ÑÇzü·ë¨iß=Ú4ƒ·öümY^³^Ç¿¥üÚòK’˜¤&AØþÍ£ Nm`5f õ·T`Tó~. ÚK“ ÎJ¯¥n¶}×´¯ÚãßR¿¹õ{´ÿÔ1ªÙëòš<ê_Ó}°” zï/€…1 @2ŽÇ :I@=óÈà°f/ìc@€ú' ôËDãZ$ àI7ýêvYž^ÿRz*Þ¬'Ïú‰ž`¯×¢êçˆíHz qªþZìѾÎü‰Ü2³|L=AçÕ-wA€$¯ffo‚Æúú]Ÿ–²Ÿ¡~F'ÒßÖ¯µëè]晓pÏó'jý=~ˆà;1  Hz;ÔÏ>“–ÇãËw– ®5p aó€H3uK¿~k–/uáIÍô›ÍºåbÙÅd=KwiýÚý·–¯¥ Pdýjê'º|# ¯²z´¯ßÒLô¥÷5¯µË—ŽEïÇÜ߬wA4çO®]Hß¿ØÍ¯ hmÀ« 2j>Q>m€—£ ,¢»ÜHÁ‰´ÿ–ú‘–—êG³ÿGêBX[vkûŠ(oÍ9k ¼s?HD%µç϶|#º@JwÍÂê1 @b b¬]>¤å½ÉzêÑ?[Z·uÿjïPÕl_ªŸuð³Ê<ïè.IžAnD;‹NÆ¢ÏïÑûk]_꘭|Ä& Ÿ}¼,_|]H–.Pëå"º™hºý깩ã$­ß+Ài Âj~ÝŸ5!){ ¼§²Ïš¬r8w?àÌó€h¸FßI]˜/ÿödŒ¨¿–@ÇóŽÃ6yÔ´1Ëû¹÷"·xnëËãøE·ß‘í;W—#‚üõwXë¾µ´yzh’º`oû0o?SZFJjZú¸ç–^¿g4ª|¥mÏP¿¥ú©-_êóëq*¥Ú­ï×Ö…æŽMn5çXij¨öQ{ü[ºDFwŸ¬C×2fEjšAþëÿï–„1pñéƒçªÏ}p÷„ÊÂÄ ˆâ✠-ùÚ÷j™G÷ö¸`—ÆHxÔ¿¥ìÖý÷¨¿Öö£©/í8•Ö÷-ÇC»ÎÖ:öè²h9¾Úí׬£¦=’Fï¶[Û4Ý[kŽ¿wûÐ'ñÈ%—Ï]þK"‚9ÌYõ¸Cãë‘DïQíwJÜýº$&À>À÷€3¸Üá Á,tƒÐ¯n©)@,®5@ˆO<'ùÀppÈ1 €b `ó§?yíå§ßÿßOÊËýîÿ£î0a²!=ôlRÈL)}fÆú“fº÷*sËd{Rýy¼ßcÿöxì#ΚúÑÎkÒZþCNðà”>ø.±øôþ‡äk`”æ1 ë‰þ,“e²"µmÝä(kýEÖ¹´n¯c.ç¥erõg}¿×þ•Ž}ó©´èý—êß:_ï$&ó À 9º^¿rFý¢UþÑ¿ýèÜDsGmÿ{­Ÿ½Ö³ R3Ó¯f¦çÔçK39k»àX‚ˆÖ® K©üšúñ¬¬“íI¥µ¶5ÏsDWžõ,Ö-í»æü&ÄÛsW&ò·ÔŸõü;5Æ€!>`Œv™€ŒÚ`DZ>X¬_kgBïÕECÚ÷– I*¿&ÉÛ«TpWz½mŸ³O4§ œ-çG¯ößúý1kýùü°ŒõÀ¾«Ûeyz]$Yƒ›ÚåsÁÁ:(HJIUTÙŽìÔ&tµ jï¼çù1ûñó¨ŸÑçÉF£«[î‚ö篽¼L@øFbòÆœ O¨;L˜€.²-ÝhÖËyuÃÉ-ä[ºÙì=H±îƒµ‹Ìž÷OêRU[®ˆ€}äñõØ?î:@.áÆÒ B/ü"¥íÊÑóßmwœÞÝM¤mÍ(ïe£Î­3·êt2ÜýB|p÷${7ážÇJ¶¿tjúØK¿[úˆKËoÉZ»~i?4å·Ì¥âYþÖõ{ý¹ñ šíKm+W·Úãµ-m¸TþÚ{ôñJjÆ\Hã³Jõ}þ€7î€`Ÿ Èf ˆ¦K‰æ‚\3ÈÖó}ï`¡¥ š÷ö,åiù¬gz·ï{ ÕÔáìÇWª ¯ö!uË­#úü;5Æ€!¶w?HH°†¤ÀÑ‘h`ß HÃ< Táî`ó§?yíåeþñq¼Ì‚ÎÞ¦ Ì•€\ÝRS€X\k€<5±G³žõcyD±¥ü§ž'ˆ1 @ˆ6c<Ä1!À H‚æ¢y!í=¹ &¨ÙKßëXÍH•’Öú±¾¿n¿‰{©{I""ëGóý%Ï^å'Q`A¢}' ›y@Z“”#Ûû¾F”Ö:¹nÌvÍ9¡ ì{$güÎÉ^k¸ 4û€§YáP HãE¼t‘”º/Y»7Yºy,¯Y·¥¢ËWš º¦|¥®O¥™¦=îÐhý®m ^¡5°m­“íö[ÚWj=5]$5íwDýx'ÖòGœ_ì#IÌ"¥_˜¥>Ùš>ÛµGM  ébcI’4Im—šýK›š.)š×Ò†ÒòÛúéH¦‚·ÒkéøÏöëyª^SǯÔþ¥„±æüQG‘ ¼çç×Ô¸û$ Ö º5à«}_`D¨‘tÍ WÏõKhmù¬ûWúu¾gn  gxP‚W€>²¾÷x~®îxöŸ€dÆ€ÌÚ7ú àOÉ:¸–Qûý¤¤Èý+%S©¢êwdýH]ÒÎruÇ8ó< ƒy¥å=~œ}ÀqtÖ~ör\/ÿzR—mÎ0X|OO8ëÑ6×ÇÆóQ¹g#u¡ਚǀ¤‚Õí‰õÿ—ú/×¾®]ÿöý–¤Ê; ´üŠÜkÿ<϶tCò| Qi€t©|¥c£CSªOïûW:&Ö10çgdýD%5Çw=ެ4¿¥~w»@Rº¨—þ¦¹ææ.мnY¿Ç>z'$¥°¶¾¼÷/òø·,ïY^öSz¿GûlÝ?m›+½–ÆÀD×oôñø~«IŒ¤z´–€Ñt]°®n©)¯Ï#»è¥ÁµÎèU#ÐF@/º; ôËDãZ$ Ð?¡_. ×8…¦1 Ò#([×Y3ûô ŸŒšŒ­Ç ^Ëc|÷6è8WÞÒ~Ô>f·å}Ï94rihŸ#ÙÛ'$ )‰y@4Ud 0z‚ºTз— ¾×±š!,%­õc}Ý~#÷R9ö’Dô˜ÅžDeBŒ€Sr¦‹ûÞ÷5¢ü³Ö 'çÄÙ¾Ÿ˜‰îÈÕí²<½®òJy©û’µ{“u&óÈ™Ð׳ ·ÖAtù43µkÊWêúTšéÙã4Ñ[k[ð l­¿ò·ÖÉvû-í+µžš.’šöëQ?í®n¹ $ íz©‹”Ôg]Ó§½60« d4]l,I’&°*uñ²î_êØHë«}-u‘+-¿­ŸÞw,RÁgéµtüg»ã’ª×Ôñ+µ)a¬9ÿ#ê(²}€ Hf ˆ×EY ZÆ{DŽéÑ?]Z·uÿ4c,å³î_é×ùžAº%€žáA ^?0Œ¬ïë#Ù„»8¨»þí×^?øÿC¥€dæ@œbÌþáß‘íS³]kÙ¢ö¯”L¥~ˆª_î:pLæy@<žF%-ïñkìÈ'fõ(_ÍòšÏ^Žëå_ï@ð²ÍÑO;k „8çºH^þjÿR*ìó€à îþù·_ûàu÷½»/Öî_é˜XÇÀxœŸš1R¥ÏI9°´OH%–ÏÓ% $ )›1 R0£¹˜çæ.мnYK`¹~)¬­/ïý«]Ö:~DZÞ³¼í§ô~öÙºÚ6Wz-‰®_))•ÊamŸÄìÄO~íƒ×ÿðŸß1®ñƒªOÿù¯>å à l‚ÿÑ:I€³ áÀ9†y@°ï  ;æÁN|úGŸ‡®ÿî/^QÉ @:Axð'÷©À=IÌ€+î~à €²·©½4‘1:»=”ßóñ ¹§•uZû˜Y™Ã=ö¯4ÿã|Û§å1Í d¯5Üm0dz³–5zß¼&à+%­ CͱÎmÇkïÔœ!Úc4{ l-_äþõ˜ežD€cÒuÁjüEŠàá˜íQÈÙÛçȹ^8>‚»p aOÁ*u!JÍÜ\ÓÅçòùÖ™ÄkÊŸÛþö3µåë1‚4Q[k]x%Ö_Ñ­Ë–ê"5ówn6íÚã_Óþ­]äZ–מ_ǯ¥ü=Î0:IÌ"@–.Dš™–5A\k‚‘ ˆJÛ—³Ö.L#¤‚»Òk)ÀžQ©}Jm«Gû¬)_êoÖå­å¯=ÇkÊߣ|„1 @¢ ¢.úµÉKm9¤Ï{Œ¿°”o†½5A<ƒèö©MNÖIÏžÚëÙ»—@"ÉÌÒš„¬—óê&ä\J]¦ö’DŒJ ¶õ‘´Dퟶû‘G¹[Ë¿}êרcL"WÜý8ŒGt[|ÿÅ_q¬i83ó< ^Okª hGÓ³•o¶@óÕ«/_û7:¡lÝßuùg:þÛä¨×9èyÞù|eÍc@RIHj.†Ü/´Ò݃´µIU®<­ƒ`5c(¤ú«ÝVíúKûæq|¼~=o¹‹ í¿´û_*·µ|Öå=ŽßúA šs<ªýcgrÜ!9÷ñšÆ€H]R´ÁBésš'(Y‚ÖÚÏÔvñ”?º?Ëþ[ÊÝÅ®ô0€–²ky{·1¯ã±|mÒt¯lÝÿÙºl€ˆ$38¢ÑwàŽT@î~à;Ü!Ù÷ñ|€àÝa fŒwHÆÖ/`õ6U Æ€æÀÝ8ቭ~€9Ô3ü÷6ÏCïò[;[z\knÒ j÷½êLz-ã1ú¶7i]Úó§ôˆç–'‘Øw`6?ûƒUŸ¿þÛGT€& ‰1 š bæ@À£¬=öO3W„f™í<-–÷/õç±ÿšä*êØXË?zy©}G©}X_Ô,÷$*“c ˆ9á–'!°ŸÄ)È?šQûw œŽ:›tT²ã}üF/öãÇ÷H8HH9iRê>Súµt»|*XHàÞÁ„¶‹’¦ ”wW’–»™5°´.[jÒ1ðjŸÖ.p-ËkÛÿÈãã• xµ‘–ãùý‚µæäþåî_ú&¤:²ÖqMù<–·¶ÿè}¶6RSÿ3Ô/K®þµëû0o’yQŽúÕ^[~ϤaDw©Ú„¢åWþž®÷ñï•®“¢^Çwtû‘t{×ÉÆ Œk¯YΫ›‘gù5]Âz²£€èAÜ5Ç¿gýkÚ§6€ÄEŸÚ¾åøq×ïXX߀yÂ^ArÔ64å·¿£ néž¶·ÀOs {íÓ¶;ÁtÿcN}ïw?“€¤5ˆ_ܹ_€¥_¿{ö1ß–E3!íŸfÌ…%AÒÔoi­¦~¥¹¼¼–VSþÒ bkû¬=þµÛ÷hÿ#OkR^Ó¾ÖÐ|‡Ô0:ÙŒ‘ºÌÔKy[¶ïY÷Þ›fÿ<ëÀÚ>­õ±¼g{³®ÛãûA³ ©û^ëñÕ% c@üæÃ_íõ?½üW*ÀpoSöˆ¤€#' ü"ˆÆµNáUÀ1l»\IïÓ% Àº; W·Ô ×8SÒÚå¹#`žd3ˆôÍÙ(¿åQ¦¥ÇÁjgr—³Ûò¾WI»e°ñí Ç )ÑÎ>k ãQÖ‘0–摎…õýKýyì¿&¹Š:6Öò^^jßÑí“Do{Ç¢öŽw<Ì›€læi òfÔþ]¿Ñ3¬÷ l£‚iëúF/Ööc÷„ä_ÿ׋×^ÿú{D%ØIÒDæ‚”ÔÌÞ5]€RxôL͹òiº@yw…i¹XZë²¥ö!¯öiíײ¼¶ý{KýEžŸàè Èf ˆ&À²üB/uJVµ–¦ü¥2•ö/U¶žRÁ_éµ ÎÖÕ¦¥}Hud­ãšòy,omÿµu\SþåÃAq÷Ãw<ì7)`QAEÔ¯öÚò{& #ºKÕ&-¿òG'‘Ç¿W¸NŠzßÖO²rLó€´ÖëåJÝŒ¶ÿ"ÅT0¹íY—TÔ$2^û7²þ5íS³ŽËzFC`7˜H@f ’£¶¡)¿uÛ£‹·tOÛ[à} [˲NDöTgG}À¯y H*ˆ_?6uÈäÆˆ”Ïnÿe[iÌ„´š1­eÓÖoi°¦~¥¹R¼’”–®|šò—A[Ûgíñ¯Ý¾Gû—êTsÒR@Æ€ H),ý­æ)J-ïYÍ“¥J¯5Û–Ög)oËö=ëÞ;àÔìŸgXÛ§µ~"–¯­éËþ{<¹ —i €ý")Àt¸Ö ôO@è— ˆÆµH@À“núÕí²<½¦¶q®n÷säÿ>àxa¿h¿çö»ã‹Ðtä2¹ÚúßžŒ(¿e¹e¥yJûçñ~TÝX··‡ö8sýy”=¢½€chž$5o„æo³ð(kýÓÌE¡Yf;O‹åýKýyìÿYgë>zýyímçd§:äèÁÁ¨ý#ðxŒ0{6¤4Crjfoi&îÔçK³}{ù¥`GšÚ£lÒDq­ûâØYån]¶öøçÚ[iùÜñ/Ý‘Ú~F*ߨú«iß-õë¹-ç_ïÙÑGï=âxíØ‹—çÞÚ/ö‘€40ÛÀX­ÿ– ljMùKe*í_ªl=¥‚¯ÒëÖs$íñ×þ½¶ šWù"ë§&ÉlÝÿ¨ý’êOú~]ÿÀš€dÆ€D^Ô£~µ×–ß3i°$c–m¶&xÛ:˜uŒ¦ýä>ç±O¥ö3ºÎ¤;Öó+ºmX×K²±SŒk¯YΫ›‘gù5]Âz‘£~¹Õl×Z¶Èý“ºLÍ`Týy´oMýrפè¡_ÝŠAP`-2ÈÜöèÇŠZ»íYTûL3Ø+Ëcu­]-g=g0HáZ8Ž{+Ùþ»r]5¤»5c¼Ë/™öO3梵lÚú- ÀÕÔoª¼}êSûç}ükï”¶Ÿk+£áܲ}ï1B-c².ë×~Ô¶°÷d3Dê2Uèµ¼çJ+½Öl[ZŸ¥¼-Û÷¬{¶ ^Kû«y¿vûše=ÛC˺kËl©mû“º_¶Ž¯Õ¥‚“øÇ_þå²,Ëò[?ú1•Sz›*0Iç6Uö4Èžs¼öìÏÎ}çö{v¾“&—®WÛ×tÅÂÙ4Ï€«yñË'/4'¹÷{%"´ßs{ü;{I@àšxŒND€¹Íé­³Q~ËcWsËÖÌä.=f7÷˜ÓÒg¼êL31Þlå·<&Øúˆa&øÃaíh  :‚¹R9k äQÖûWJ>júÒìÕÛ¹-4A³Çþ×ÌD¯-¿&¨÷(벚ditÒ ðw¹³±½ÓQ{§8GÒ8äèÁϨýë= ÷ lä¼0´O`ÜýÀÁmb€‚Ö\¤™5YêbSš)Ù³ü¹õK30{”Mš¨­u_¼’ë]„щ×]œ–ö㽚öÙãüÔå`ìH@Öó€H–åzM!Mc 5]|rû—*ÛˆÀZûº¨Î(x罎Ad²%µéü³ž?@Æ€ààx /P“€‚ܨ ¥6h¯-‡T~Ϥ¡gw)M}hÇ]ì9@]ÖèãmÝ?’ —xäÞ' ÈZf Hk²^Ϋ›‘g¥éÖ+ˆž9ð÷Ä=rÿ"»_ÍÐ~€ÝÙÓ< _¼àxíÚÕ­Î2ö{ngü<0æ1 ½‚ȨmhÊo GŸ-ÝÓfKz4ÇhæDÍ{Ÿé2û±½³!½Ž®y H)ˆ_\¹Á°Ò݃xse‘ÆLHû§saI4õ[!Õ¯¦þ½àÔþy•/µ-Ïòç긦ýHëÖž#µí˜c@€¤4–þ¦ vJŸ‹|쪦ËWéµfÛÒú,åmÙ~ï÷½‡gÛñ(mùZÚÔ=±ôt2ïú蛀4Î .ÉgOw?þÓÇkÏ^ž|ÿi¿ìmª@/.c@0ÛÑŸýOÚ·s¿»? œÙ³ßÝKò?üß¿ÅQ(÷šñì“g^M@ˆÆ°€!žü~ùŽÐó¿{D%a@²mˆ¿÷«7ï?üÚnvzDùŸÿÞ¯š·‘[¶´Îí>n?Wz?U?©ÏxÕYj]3—ßsߘ%ñØ&—÷/ÿ%Aß$1$jþ6ÍIçPÖûWJ>júËߤ÷5Û{ò¿æ²ÿÚvSS~MBéU~Àó€À)„>ëèÁרýëØÎHk ÚÀüÂÆ€\~1×tªí‚sùüú3ÞÁž¶ ¦ ”wWŸ–;5ɇõ.ÂèÄÆ£ü-í£Gûv‰»@b з–50ÝvÒ$1Öò—ÊTÚ¿TÙFÖÚ×¥@y†DÁ;9ðZ©ýIíßÚ~Ž€dÆ€DMµA{m9¤ò{& –d̲ÍÖ/µŽ½ÈÑeµ®ŸdÈ\k¸ $ – ^³œW7#Ïòkº„õ ¢gü­e½ÜuœÙå©VÛ§]å>ôM@ c@z‘QÛДߚ|ŒH^,u7c`®9Fã€JwÈH^gÜý†&"À\ He¿¸sƒq¥»š1 QIˆ4fBÚ?͘ K‚¤©ßÒ©~5õöÏ«|©mÕ$4¥Ï•‘kŽÀY½uýôú›eY–'sÿÔÕíòüéõò«ÿòœÃip—°ù׿ù­åŸ?S}öýÇ7˳_¾xã.Èóïî¾?ûä‰kÙîß×´ü³Ožq€àæ£*ö:×Oýïx½ÿøÛséÙ‡ËçÜO_.Ëât8"’8g@½MLzÜ—íÚ®¶^€Vº‰é— ˆÆµH@ãæ£î*à”ªæùëÿúÔ@åý¿© ¬˜“ˆîú$%¹íGw û曫×^ÿåÿ -`d×G{÷cô˜`L²™$õôW¯¾ÜÍN(ÿýûï6o#·liÛ}Ü~®ô~îé0ÛÏxÕÙv]RÙ÷ÔÆJÇÇ»=»ÇÝL¢õEt9¼¶›Û¿›¾ýïöN0&‚Ñ\P4s äQÖûWJ>j–YÿMz_³½W¯¾tÙÿÜ:4ÉŽuûRgY÷¥~¤÷#Û‰ ØD%Û`ûÔ«^w<¶ëýñÓÕ3% ß±ùG3jÿ.¥õ9ö{ dsÁºµL´O`2ŒÁÉ›\â‘»cAW,;i ZsAPªËMm¡mîli»0iº@ywµi¹S‘|XÅ·.[Sÿ¹n^¥»=¥cèÑMÌ£þZÚgóŽ ×i;Qóql×óã?¦ëfJ@6c@4˜åzM!McI0¤.Z¥ý“Æ4DK—¥×š@|¶µ¶þkÚ§”ÌÐÝPÚGéü³ž?@î~`2½Ÿ†¥½3·tÁÂL HCæ`ՖdzüžICÏîRšúÐШ~í³çñí±< >ñès% ™1 ­IÈz9¯nFžI”¦KX¯ sæÀßk ¶÷þõè^ä±N’: q­á.&N¼Öåy/Ε€L$GmCS~kò1ú×ò–îi3Æ3”_ÓFzn“äâÌØ{—‡ÄûH@c@JAü:àÎ †•î~ôœ b[iÌ„´š1–IS¿¥;Rýjêß+.Ý…*m»¦þ·ï×´Ï–úÑMÒ«=Gj·L‰»$jŒÅþêá“’JÁÀ$ü”þ¦ vJŸ“Öaíú#ý­ôZ³mÏGƶ¬ËZ‘õoÝ?éý–yN<Û§×ñ‘º'–žNfmÿpÜ Æx[õ©«[j »q Þ×ÿö`“àt¸ÖÀ)Ü£ pÔ$pO~ÿEñýç÷(d½ÒúG/ì;Æ€`Æ4&R/}®5ðÏ•côòÀ1€Éô ¸·Û©MF/ì3ÉÌ€æ“m€.Ý!©Md¬‰Oíò­ wF°ïd#õHÙ=õ¹Q~Ë@èܲ53¹K+zÌœîY7ÖÇ0ÏþøÙž™îÝ^¥uiÏ¿ÖGGoŽ— l»<ͨ·&,{Ù?€¤%Æ€hgŸõBîQÖ‘0–摎EͱÊmÇkÊš™èk¶e™{eDp?Û¹y|5çŸÔ^{•ŸD¥3î~À9`ϱæ¹;Ö1&^Ë“xà ˆS4£öïøDؽ¶C[â©]¥À¾G2Á1öÉ`G JŸeyì;iRêSúµs»|êbŸ Œ½ƒm&M(ï® ­Ý‘<¶½-Ǩ®.^]´¤ã›ÛÏè.T¹õ§Ê%•¿åýÑÇ×+Aðjc5çï§Ãb lïÇðÖ>j»þÑËÇH@8Ë/çš™¬5IŒµü¥2•öOÓç½Gà¥}KðfæÑE+·¼¦mEw¡ÒÌäž+³g¼({SsþkÛÿDd¶õŽ^Øw’yQ­ Ú½ûˆ{& #º1TÕ<“ºÑËܿԓÞÇ^3ˆ|¦·÷ò§µ£»7Ýp¼ìÒõÓñ×(ÓÖ$d½œW7#Ïòkº„õ ‚F%ÛýHZ4û—êzd=>ÒòR÷Ïö±šóg»ÝÚ§¬E·_úå®sz[õ©«[1Èè{ù‘ÛýknK÷¤õ¿^ akýyŸK}­÷dûðh?Ûg{¬g}bبvuÆú˜BáZ8—§`méL;¹1"¥Á¯Û¿EÙ–E3!íŸfÌEkÙ´õ[úߣ~½~]Ní_íïã#ÕõøZ÷O:fµåϵŸ¨ã•<ÔŒ¹¸,¯ýª=ÿ@Þ[×O¯¿Y–eyòÞ;Å>ÿâëåÙ'O¨1ÞÞæ´ßq†¯÷ß,¿øü™ú³Ï>|˜¼ö,Ëâ~ýá.€³Š¸ö½ÿøÛqq©ïñµ›Ÿ¾\–%x`¯'æìOiœ_À@f58­À× €þ 3Ó¢q­€S` àtèZ ã4¹ÿÝ7þíɈò[¶‘[VšÇ ´5ûŸ[>²n¬Çgöv9ûùÑ^Úk à˜šï€hg‡žõW&²öØ¿Ü6¤ä£´5Ç*·¯ùjf¢¯LqÖ@xçJÔü{ù~qBÇ€=¸µ½·™DÚûŒ` œBØÒ Á©™½K3yo×sù|i¶o¯òçÖ/Í€ìQ¶Ò,Í–}ñJ>¬¿’[—õ¬i&ùÒlô=Û_n†ôšóG[~ãÛrþô8¿Àì ÈÕí²<½® `,]`¤.*¹€°&HÑ”¿T¦ÒþIÁj´TðVzKðfæÑE+·¼¦mEw¡’Ú©Ìž]ð, T©¥ïëùººå.€ÈAnTPP´×–C*¿gÒ0bö4^'÷+¸µ>G/?rÿRwN¼½u}$œ=ùìãeùâk·$d½œW7#Ï$JÓ%¬W1*1ØîoDÒ¢Ù¿T×#ëñ‘–—ºÿx¶ˆýÓœ?ÛíjºJá¸û§`ž ½×¯ûQÛД–_Ë-ۯힴþ×+!l­?ïãs©¯õþlíg›àluë8¡YÛ<˜WóTŸû57ÀJw?¢ù–Ê"™öO3梵lÚú-ý‚ïQ¿^¿Ž§ö¯v ‹÷ñ‘êÇz|­û'³ÚòçÚÔ¯ô¹Ò]$MûÅI1H@JTéoÚ`BÓõ¦õ}Kù¥×šmKë³”·eû–ú‹î"g=ÞÇGÓÝÌz|[÷¯”txËÐjËÚ»½€=$ ™1 Àõ¾·çz\q÷H@‚kxÒ B¿º¥¦±¸Ö ôO@è— ˆÆµN¡i HÍ#Ag4¢ü–ÇÖæ–­™É]šØnäÌ隉÷“ßžzh²¬.ÔÏ<™¦ü-‰L¯@Sš®´ÒûšíxM@YJn¬ÇçÈzÔ uŽî$ AÒуÀzý‚=Ó/åübO€c›¤4Ãqjfïš.8—Ï—fûö¾KÁ˜4ƒ³GÙ¤‰ÞZ÷Å+ù(MF™àHíGÓ>¬í+5Syn¶ïõò¹Î[º yÔKûîqþá¤$ –ÝÒEDs øj‚ MùKe’º-•‚Ñh©à°ô:€â1`©}XÛ—¦íIë/­3zÌf¤ó×zþ²«Ûeyz £‚ŽÚ ½¶Rù=“†cF*(mù¤ÏF·/ëñŽn/ÖcM²W·Ü[¯YΫ›‘gù5]ÂzᣃíþF$-‘û'­×£Ü5ÉRDÂÃ]pܤ0¤Wµ Mùgÿ5Û»îFßñØ^í…šmZ»ûõªéÉ ¢=øáƒåæ£çêÏ.>¤Ò€¤-ˆß>ò5Jw?zα-‹4fBÚ?͘ K‚¤©ßRð1ÆÂ3”Ê—«_i†×þ·–OJôjʧMšµçXmû´½ü{Õç^<üïT€¬lÆ€H]¦´ÁŠ¥‹Œµ ô·ÒkͶµÁpKy[¶o©¿è.r-ë·Ö¯¥~4ÝÑrå+%žÇOÓ½Q[–Þí'Æ îgÀI À~†y@€#Þ÷€Þã—/ŠïþðÑ¿_k$ X|Ÿ`°æ@C}„1 @€w@õ Èf HÍ#Eg4¢ü–ÇÖ–û·ºŸ© xeŒÔ' ÚÙŸg Ô<Ê:rÆmB’úŒµ|{_^:þÑÇDØ$,Ác@Ž|ͲµñõÚ¿ÑËÓ>€)ŒÑΨèïÁ,w_Ý9' J3(§º•fòÞ®çòùÒlß^åÏ­_š!Ú£lÖnB5åËuó²?Íö­õÛÚ>¬wAJë×Ô_dûfÁ çp|5ɇ>IÌ"©ÉÚ,÷úo¹€¹&ˆÓ”¿T¦ÒþIc6z¨-Ÿçñ«Ý¾µ~5ûäÝJZ¿TÑåf¹ ýâógªÏ¾ÿø¦8äÙ'O¨P˜ÔûoB€4Õ¿µåÊï™4Xƒù£Y×Ç:©ôÞFô>Ì\>€Y½­úÔÕ­k`½^®4Èzû/2Þ&ÑÛ™¸\Ö{ùך¼•ŽŸfërŒÀ]`2™k àŒ È€ 9,Ž ò­ÛŽ®Ÿ–îg#“«í؇YïI]¨P¯y H*ˆ¿³ëà,7·Ô*FÊÛ²¤§ö)·Òò–²å‚øÜ{šòmß·¿èí{´)iÓÜ¡ËMýÈ\k$ ¹ ¸ô7m°Uúœ´K@'•_z­Ù¶ç#qk×%½¯äo9~-õ½|KJs°´î¿¦|Ge‚}ÚŽa,„’  ×8…{TÁ5ЋîýrѸÖÀ)p°+{™ÈSzXFïr·>¼CóÐ˺j´’ú{ê!/ë÷Zê¸4¡ðˆòçL@®n—åé5µˆsu;Õ]`±”(D[7¯rJ‰†”`æþ.%/­ªo-O©Î¢'qöâíÖ/‘í¿=Q~Ë6r_Ð3׿÷þ€æ{"õ½¸~½].÷=šû¼÷u¨´O©}H=æÛã:Pª‡Ò5Èš|hžÚhMrj…¯)“å µåŽªyí-ÔY³|²öØ¿šÛÕ3Õu_yø 8˜Š»¹ï˜Ò/ÒÛ_®¥_°=¾cr]w,AñvÞ­šî=¥ò”ê!WK -Ý%(ýî:>c‚Ìu hM@œ¿\Žb¶€ÿløRÎ-·Šß15‰Œ”Ie¬Ý†Gðõk~n’[M—¶~œâú”…ÍRº=«¹`”ºmo;G|ùI]œ¤íz”Íò%j©?ëññº0µÖö @õ&7& ¦;Ln¯ï ½TNkyZê­¶ŽZëÀ£›V͵TSNmlqmŽ¢ùˆô4 Ë®f¦nëSP4å/•©´Ú_®¢hºhYê¯G0Í/]R¸‡§äð#}/HשÔ÷¶×wÇöº•[êú&u=²–Gºžå®Áµ×ú\¬ÿûž¦¤ãX[_Ûr¶n7Õö¸5 Hf Hä‰T´[¿`¬Ûøå§¶žj’ËqÛ^|¼.ˆ^å‹(€”c@J?¥ÎýÚÏ{]ãZ¶«Ý‡Öë^K=H¯)‡¥<ÿn©+ËqáÚÔ$ A¼f¹Üò=NÒR_Ø·iê770ºþJ¿R•êö‚ï/ˆaÒëqrQÛ°ô÷]öšõ{–a{×ÅÒ·wT˜PÃÀþ¸<«¦_gn))ˆü%JÓß3µO¹ý“–·”M³~kýåÖWz,c혩µ¶omé öš€lÆ€H]¦jž6Ñòž5à¬í#ܲÚþ£=ʱ>ëñÑt¿kíÓ;ªK£‰fAŒN@€$ZôzÊÇÖ½…Ó܉.MJÈ÷<€”°y@¨2ѵFóˆÚ=%Ö:X×Cîï—„Ãk¾gO@˜0¸NMœº€t;9i.@×Ì6^šÀÕºÝÜçk×_ª ïGÝ8¯æy@pU1dû8÷\²š®æ!Ûu¦ÖŸëÖò¨úT9K]Îrÿ=W—Tw$&ì “ÉÍ?¤ý¬&¹Ñ®¿u[¥e5“Ë–2" é Ñ4d}+8uëwv#ÊoÙFnÙC©¬3”Ãc]©uGn¯W{†3ŽÙŽMˆ8ï4ë¯ùÔž-c+¼ÏõY¾ßì_óíìá³þâQÖûWÚ†¶;Áyu?˜µn{t¯ ]a¯ç}Ëç5Ëæ>Sê¶Ý†Çv5ç¥4×RK}–æÊÊ%#|‡hO@Ç€ý‹‡/V]`L KûÔך†¶)ÍÓ¤ý¼f¾§–ØÚ¹³¬ó7EüHQ³¿|gðM@”žŸ® PK¿¢H=ËŸ[¿ô|x²Y.Öúó˜I=wìuü­à¨ú¯­_i¶x2Ö´ïç~DpöäêvYž^WP–g§KA«Ç¯ìšò—ÊTÚ¿TÙzj ú¥'ÄÔÖ¯58¶”¿W·–¿¦~#'X+ÕŸtþr— !®n™ H@âLk€'|Öò{?;}¶AzR}.om€?ºþ´ó Ô®/j?£ºeø$ ™1 ­IˆÔE§W€£í"4* õ÷ѦWý[뮵þ=ʯyÀwp8Üý€S0Ï„Þë×ý¨mhÊoÝv¯G!î±þgßv¯ò—žñoéÊxÔ:ŹYï8jÏÉÈó¤öñé¥Ïóx\{Ó<$$­µÝ~æÆˆ”×nÿe[–ÔÛÔ>åöOZÞR¶Üú=ë/ºþsõ£­íÅÚ£Ì-wA¤ò×Öo˘'éœÚÇhFwÞ¸ÖLr¤fœ_KòQ{>—Æì‘|8f’øb.ýMûÅ\ûÈA¯€¸ö1-ûç9#mK5ë㽂÷Öúñ|̦÷~XÛOã£éÞØò8ÑÖöxK=mx§ëR÷È^ókx?¥:˜qì!Ô% 󀇤»Sq÷c;–0•¤ÆnïðÕ>Í-rl^n’ÃÒ„€œûŽ›€p€$»Ô¥vtr¯}à °wºAèW·Ô V‡kMjüÕú_Ë:¼ËGÇÀ!”º*­Ç€¤þýùuR›XÖ:ÑjÍØ“ÜçsŒàAŽ‘€0M9¤å!!¹ÏÔŽ£ðÒ2VM`ÿ ÈFn Ü^Œ(¿å‚•[vÆãP*kϲEÔ7à€]óm¿ÙšÉ‘f¹€HåoIdzÒë>Ë5ý—Ï DúmÎo$ Aàу\ÈÿQï(püê…) |Ó¾5åO] Rû”Û?iyKÙrë÷¬¿èúÏÕ¶þµÁI©ÌÒ¯•š’Kí@¬ÒìR‚àu¾î}>,˜?ÙŒ‘ºLÕþbTûžõ‹^Óå«e¦Ýšõy—×Z·žåm)ƒµþk˯éþ×:Ëð¨.…ÀîUŒIÇQIÝ=9Ó#Ç`LpŒó8×½J›\¤’‡Ü˜éÁ%$!à•€4Ì@•†'`i„Ö»í5æùÐ8fÀÉiÆßdº§`]ÝRS€X;¸Ö¬Ÿ²ˆL@ÀAÓ½?~pDù-}ƒ5Ov©]÷ìõ¬/;Qñ,À~5ßY߆Î=ydæÉÜ4åoIdzâÖòÏ ÷˜à’É}J=þ–óŽ–€4öË=ú¯ÐüÊÎñàh²1 $-#ì)X¥.>©.EÒl¶©Ï—žFâ}áÉ•Oz&¼¥lÖnH­Ávîx”&ûj9~Ò6­µ,MûŒl_ìßѹów{Þ®çèH}å¾§¬ßÃK’˜D p-]h¤5˜Ö^$4å/•©´Q³ñzø=ƒÒñ‹(›Ô>¤öim_fA/·¹3JË3¯ŒN@”_þ‘¶¦<žå÷L"Æ3ìý¢˜›ex–ú!èöõ=q­á{b˜Æ€´~ù¯—Ó²Ž Rsƒç£·=*qñ¸@kŽŸ×v €iÒò±ív•û®g ŒL@&’£¶¡)ä/l3ºÔÉå_D°íá]¯Àù”¾»Öïm»Y]þ¥¾Cø.Íc@R_úÛëÿ¯`œ J# ß–%59µO¹ý“–·”­5©ÊI)ŸÖri¶Ÿª¯š1š;hÒàÒÒþ@9¤ô}U:—sß^߽ϤòK\û…]{¡ðJH4¡Ö œv}–ò¶l¿fyíE·u-õ_›I…µ}8>Î{ˆ:ö{Ñ]wK˜õW@‚à`¸ÖÀ)Ü£ @p€^tw@*žÍ@®5@ÀŒrO¯jYgy´ßKæþ–«Cišõ·l·ö8·—ÒÓÒ¢ÚÕÙŽ‹Çg[žÉÓîfM@è— ˆ¦¼Ölçjš!xh}è…W€ê¹ë'ZÖÔsîóë9V¶ó­¤¢ÙnÍØÄÔgkKí£ã=Û噎KË9æUÇ$!}Ýóú²ÛÓ˜å· äN=¢ÖR~Í#n­õṿ  LRß¾|§l»½ëCú|nýÖëe»=&…ÍkÒ£Š½Ê“š 2*ÈÕ_©ý¤ê‰ã"Mû—& --3Ûñ"ÑHÌ¢ix3H²öØ?éQ³³Öu™/ à`Œc@Jó ¥þ¿ô=•ú|í|E^唂Éß…©í–æ_ÚÃ÷~î¸ä×Ö½—ܹºCQúq¶ö|Ǭ ˆS44bêÀ1¿/Z涪 ´´Û•ÈÙàÈd!:ˆÌõ0Ø{ທãâuÞÌ/l Hi€—fÀRn`Ôúó^ƒKåoXèQ6k7&© ­ïçê#÷…äq ZÚWdû q¼¡ç@òžáú_Íç-ƒ~÷X©n6ÚmÕ^‡j‹Ûäî®iÊÄqÑ­£õ:¯=^ˆqϳáy5.©;—Ç­pMùKe*íŸfÌFĉ¯­?×ѤíKíktùÄï©;-]Mr}Îk¶»ýáCú{m95ýÜ-ßq¹:¨-gKý·ÖOÍ/Áz\Ju'•Ͳî#—šòäÎ…ˆã…Q Hf HïÛ R£jùÂÍ-ç™4D<]ÁZÿš/¬ÑÆÈå P1¤f€­ôSM—¦Ú½–rjËãÝõÅR^Ÿo9Ž5ûçuk÷ËëÉOG<.µeÔŽ‘Õ”˜aÖÄù‹Oó¤†!·ýÜßFá3>Ô&kü¢}®àX±.£×#Žy H¯g'GmCû íËn©Ë>oû]ZÆ©Œ¨3“bÎ)•1PËxŒwÏ«ly¶ $kž·œ ª{L@Sê瘛õSÛ?³5 ÖÜåÊ_ªËûRr!Í5Rúœ¦¯u©}`Ï Èf ˆÔeJ Zhy?ž­¦Ï vpUTy­}0S3œÖ¼¯¹ë¡WÚ—ÖI”èß ì”qÀ‘ ‘ïúÐc@àšŸ‚¥=|ÖÊeí±53µoçÊU÷3´…³Ä3Ó;@½Ð1 GÎfÚ¿ÙëúˆmäpÆ8…°y@J3Tk~­/Í3qù|i¦n¯òçÖ/ÍÀíQ¶Ö_Ø×³ŒK埭~s3È×”»¼¥þ[Žú8vru»,O¯«ÀÔdu–À{ý·T`YhjÊ_*SiÿReó$M¨ ¼£ëW³¥íoÿ–ûÿ¨òIû/µï™ºÄ»quË] ‘ƒà¨ ª6h¯-‡T~ϤÁ’Œµð3Ôoj;žIYô@qk»&Ù°$ Ÿ}¼,_|í–„¬—Ë-ß#€Ëm_Ó%¬‡¨$¯çþ¥ºVyl_S'Üuv†»p æy@"~ÝÏ“‘A~ä¶½ËÞ²>©»ÐÈcç±ý½Õ ÀY5Iñ¹_»/Ÿ)-#%‘¿doË’@œÚ§ÜþIË[ʦ­ŸÒ hÏòi’ºÚ×Ò1×ì¿t÷c=P_ÓsÝǤ‡¨À )˜¥¿iƒ±šAÒµï[Ê/½Öl[ZŸwy­õëYÞ–õo [ëSó¾ÔýO[¯ãp¡ó€3#)&õH@ ruKMbq­蟀Ð/k €äÜ¿ÿîÿödDù-ÛØ.›ZWÍú÷p¼<˘ª?ÍñϽ§)[tù{n/º=7%úå¾zõåkÿ¢ƒ"ošòÏHu6o¯¹IJÚ-ÿËr­åˆ.ÿQމ ¤k ଠˆ!H9zŒãÑLüÎ/ÐF7ág/Ë_Wq¹ bà¥~å-Ít}ù|n¦j¯ ´ I3`{”­õ×ïÚúÉÒò¹úÉ•yýwmùJ“FÖŸg=ªüÚöÛÒ><÷¯åüêqþcÆ€ ˆ%À±üjœKHÖ3Tk’kùKe*í_ªl½iëGû÷Ta –­Ç/:ÁœÔ¦JǧæøEéøKߣۈN@®n—åéu2Áˆºè×íµåÊï™4ŒèÂ#Õ‡tÇ㸖êwt°¨­ŸYIw4¬çÔ>¢ë?zyLêê–» @b â5Ë•ºwôâ´¿H#“<©ËÔ ¬e³ÔŸÇñU~ö«iÜu-Ìó€ôúu?jšò[·=ûÓÀ"Ê—ê§q‰\ëg¬])÷xN` î~À)ÜóXÉö—Úup‘ëÊ!ÝýèÙG[–Ô×Ô>åöOZÞR¶ˆú©ý¥½´ý\]züŠßcß,ÁuĘ„–òKí¯¶ý´Œ¹º¬_{ŽçÆLEwý½uýôú›eY–'sÿÔÕíòüéõòì“'Ô€®I$öëýÇ7Ë/>¦þì³_¾xã.ÈóïžÀÈõæþ¾_–eyöáÃâçn~úrY–ày@œÉH1À× €þ ÈÕ-5ˆÅµH@ ²é—{ÿþ»oüÛ“å·lC3ËuÍú÷p¼<˘ª?ÍñϽg™Wã(ÇÁ8…æy@´³‡Ïú$²öØ¿³>ÊÔkþŽÒ<¥Ïm絩-Gä,ögo`ßBÇ€=8"ø;&ÍÄ´? c@àîE­¸4ƒ±fVåÒLÍ—ÏçfRö,nýÒ Íeký…»¶~rÇ£´|®~reNÝQÊg½‹0úGù[Ú_ó 6ùìãeùn6Zm€nùÕXêΕ ìj=MùKe*í_ªl½iëGûw©KRKý[Ž_t‚9šT?Òù5º~eY–?|°Ü|ô\ýÙE˜Ap¦$!º{mÐîÝGß3iÑ…GªéŽÇq-Õïè`X[?³–/zyÀ˳Ož¨>§MTûgÒX¯—+ Þþ‹òrO9ŠÞöèÄå²_3?qÉšàZöÏãøs×¨Ä $oƒ¹QA¾uÛ3ùQÇ/5úvA½€£j’ b×c¶TnŒHiðñöoÑAøvŒI®<ÒþIË[ÊQ?µÝéJÛÏÕå¨GGuLÏš1š;€¹Aäšó ˜ÉçßüòÅ¿_k$ ¹ ®ô·š@¶å=€[ú[éµfÛÒú¼Ëk=>5ï×n_³¬g}Y×íѾ5Ûæ(i?SÛ^€h_¾È&!ß'€Ó@L ì1 ÿƵH@ˆHB¸óçå2€Ú$$y­w@t£»ru»,O¯©-@œ«Ûä]»¯î–÷ßP?pªä;\Z~øÀ<Ãù“÷ÞYn¾¢.`vÏ>|蟀<ùùÏþý—©Ë“JxÍk^óš×¼özýÞÇæ‹`~o]?½þæò+D¸ùéËeY„ #$ Žçžuï^~çËN$õîÕí÷e_ÿÿŒå£,ó•©÷ö/ç]n›ÒûÖóck»Ü÷B®žjê/õYéüÕ¾ŸÚ·Ô>Ô¾Ù64u7ã9 1Y_Ø< 3I€ßñÑË¥÷=ÏùÚ`fšï2MBÑkÿ#1QÜ»`åëÅ7òB;{pD21wýýøxïßö\D!p×¾?³¹×c#¥î ©®¹îÒÒ:5eÚ¾¿]&·ïÚ®k¥;J¹å×õU[~í1‰^týŒÞ¾¥þ"ðÚýóø‘bûßžÖÛž=±°ÜQ"ùœ6)©@`û:*X’\™¤€ õ¹–.*5ÝÙ¶Û¯Ù7MÐSóÚcý½ëgoÇÇ㜴lÓš YÏi„ÅR†šäÜ;$ù€%,š¿E^Ä£/ÜR%õ?ßÞY©-¯´ýÚ>îÞëï]?ž}ú{Ÿ‘í/òGKåý㈵½Œ¬’ Èdf¸8—¶¯)ß¶ËWË/БudY6÷k|Ïú±ÖMôññ.mýzÙ³ÈQ]ÀZë'ÕEMJ gŠkîƒÐgÚËÌý¾µåÛvÿÐPµï_Öyù7ò!µÁqKýìíøD[µÇzÄø=‰¨ŸK›ºüÛ&¼$€Ù¹ÜѦmý58rºWPQÓmL»¼eû¥AÖÖò{ÕvùÚ ®GýŽ<>Ò9%½o­ßÜþnǸx´¥í¯5¡–Î÷–6D28¢·®Ÿ^³,Ëòä½w¦.(cêçh{¥ œý`¿n~úrY–áâ ßÑÏs¾Ç‚$€  °_UOÁzþÅ×ÔNAûXjÎ pNpN€s‚s¨›ÒC}„gq÷ÕÝ÷Ï©æœ8'Î À眸¨žäÑË¿§–qì“èïrNœçtN0@7÷¨Wÿôo¯½þì7д|írÀYÎiÝÛõ¥þ¥ÍœC á1?ŸýæÞ8Ñ¢ËìéÎÖæ5Ÿç<çPûyÄù3]°‚Р΀óàÁ›¸Ò1“·œÒò¥÷/ï­?à ‰£#Òº·w90º½—Ú¤æ{[êº+]¤s‚î/ØÃ9”{-#ÄF$ ‡È®5_ô¥§æ$ÛþMzÿR>N,ìåBR{Žx]¬€Y(Í÷v©ë®æœ*½¦Û$ŽŸmߣM“€ì¾‘K_ôÖ •¥<ÀLA׈vÊ9Ù¯3m¸­“" 9Ñ…†/~í\ˆ|èB.ñá<ÂlÉøÌmr{®rþ€ó^„îtrôX¦fyëûÀlçŒG0uõOÿöý?.h˜!À¯i“=Ï›íÊè'5ÒyrÔkÓYq$èäX_H4cD¶ÿ_³¼ô~ê3_yŽH¯kÛ¨vyÚ=f¹.hÚ¤fzëuëü@¯sh›¤ç®#©»ì¹»xÄF$ ‡8QZß×4xËú9±0ã9"½ö>Ù® –uX¿ó5Éçf;‡RIHîóÚöK;ƒ.X8ERà¢Ú$€@Œª1 w_Ý-w?x—Z8'Î €sh¢¾òä½w¨-œÆ³rNœçàxN\¼uýôúN‘n~úrYÆ€èˆ@7÷–åÛR7_Qb½µ,Ë7~ôˆšêÅ/_,ÿ;±!nÛXIEND®B`‚stella-3.9.3/docs/graphics/debugger_bpstatus.png0000644000175000001440000000065612205116016021347 0ustar stephenusers‰PNG  IHDR8*š¥sBITÛáOà pHYsaa¨?§iQIDATxœíܽ Â0†aƒ «¤g˜‚Ñ3LÁ©Š6CP0:ÅöÅ!É…÷éòë+ü‘‹,nÕј¶åØhGPVþ®Ëõ1|>êº>ï×rO ¨Î¹Ói7H=6›Cc­/`A ·¾oUQÊÍíó;Ô8ÚÃØˆÁª¢Œ ¬Ð‚꼨ÈÍÆìÿ>Êåòæþ@ÁË“É*¬Ëh}ß3þw¥Äø²Œ”géX•}Éjîs©*Ê^â¡$3½ã%«0­¥õ•“[o8¿ï-•±dÌ”ö˜«ÞÞQõkSt~Gf¯%¨ÒX«2Á&6¥ z]ÌFFPÍI_&Îöbð'º/& )¶˜Ô°0ZP•Ÿ†¬Àt[šÊªÃ.¾ë @P*`@øÕÿÝ*€-øB`úh}*`À ®ä¸˜¥†µIEND®B`‚stella-3.9.3/docs/graphics/debugger_bankcomplex.png0000644000175000001440000002523312205116016022003 0ustar stephenusers‰PNG  IHDR…ÍNsBITÛáOà pHYsaa¨?§i IDATxœíÝ=’Ý8’ÀqÖÆ@FBn[rÚoWºÁ¶¥ö:ÚÚ2dʨ±6ÖkYšh\yk¬#«Ý:„ŒºA¯ÁÉD"‚äÿ Å«GùXÌÂǾ}ù°€þãèp;D_F#ú0Ñ€Ñþvt0Úç¯ß.üýòóG@ê¾÷Bè½*>Yà\âºïýÏÿRtõ÷ß~ ¤žt1„^àtþ­îKè½*>Y˜J¦ß7ª'áì½0F]¡É›wÜ:m-ÉnÞ¼ûØRHá|£MòVæ˜nn\ôÝ}ú(Ÿž³‘ŸæÛYŸî¼4ÒsoŒm-‰ »ÂQL ,]N Ày ­û ­å¢ñi{ø]A.ù! ¾}ù0ùß ætX˳ù±…³(µv„5ÂtSôBsTéÍ´i4ÜÞ4èj–~_åÓsQ÷¥ùn ‹—m!ñYÑ_—üC¤ÔÖš^ÃpÓR¸ÂQK¹!½Î¦lÊ¥w²ˆÙ”f‰¾Ê§ç’{榛„£l›–$0ëK†Rw¶KÔxa·Þ Ÿ;¥Y¢¯žûS»ý‰É37Kç‰Ä²ûtÕ8ÄìÑ7­¬ÈßñØ=Ê– jeŽ*LVt'Üa €yÌ}—ÊæåÝ£ª6¡V©ÕÝz}›ñ…~_s‚¶Dèžnî°è«Æ¢|H)¬=žz¾8œˆ¾¡ªÃ5ܹöÓFf Åpi QONÀ =„OuJÂN3MÊOŸö!ÊúoŒØÆ<ËUðÒY“Wï/_…ë:?«,,ךƒ8qu_ù¹f%ôÕ¹$(¼5VëÔl\Û ú}/é¼Õ¬Ë 5Àˆ¾ÇÜb .;€£<|ûòèîãõë× „—³öû>??]Z[þõDÆMz¯ç—Ÿøüõ;¿ÈÀ‰<ÐøÀ`ÿqt¸¢/£}è ÀhD_F#ú0рш¾ŒFô`4VY˜Ô:s/༞ŸŸ×µÕSDßy==½?º»·o/mھѨ˿¯ËVZ!5]¿V¹¢­¼ä꺕¹©§¦ªû–â¨9Ä–ì&HÜ\@Ç–ç0p¦hÔzõêÇ——?³ï¯/²[³Çn‡DFïï&+lfUe®ºòéÎÛ;¥Ëà†:Fßo_>¬xûß–ÈözK!Û]:PnÊ^NÒš‹Ë¿?ëwƒDi·ðÁ!áÈ]zwŒ6ÉqÀ}¨¢ïnóé4—­¹;ûþ&ªsû¶b}L§a }²—"k)„@ÖråÓÝ"¥£ÜAE¿¯!nmߪCÖ¶*©­UûÖò€¶[±T)Œê‹Ñ MÛ¸¼IYNå!¡q÷pB/pg-φPÚÂò³;Ÿ½Ë¹wè•Û¥õ‰Ôµu…jªŒaשÐl^[NM ÖKºÛ @è߷¥.«ÑÝKÇN^µíD3QSjø£9H&ŒaBS?ý¾VÕ£®×€•ÃörÅ -Tjçè ÑËÜò<2Úiúté÷î¬iÌs:’¹1†É n›¢x¹þ˜=н„gÑÒ<;y°Rø£­m|‚+Á~ô-=.mÕU•!¯ª|Ï£ç»yŒUc ÊwÇ]+™!ž)¯¼€'9‡`žçÙ…A+í µõÚ–Æþ˜ÛuÓ¾älñÒœ-¿P [ ÛÇ~›¯|§ÃMµEpDßÙ)Wí£o×ÕXyU•m÷(s ÝR–üDÝí†a}_tÄ,EÝ•Z¤à戾苈 )¢ï¼„e™§öpÞïÛpRŒº`4Zž'õùë÷£‹hòüüü÷ß~Ên"úÎëééýÑEØ Ãwö[žÓú¬Ù÷æÝÇõ_ïŒoÆ~ßuÁ¢õŸK&Šß ³|ìâÇRµ<‡ë÷ÉŽâ;)¿°ü$G™¥*;¿tºCË\ÐÊc…ým«, ³^Ëb³p,UôÝÖôÝþß6•ÖïK÷Œ6…)(×5Ò,>˜æ½Ðc{µ{Ê¥£Âc ßòZ”µKaÿNS;åK^—P(¡r‘"åG³î“­w ›4 –æ—&Äsju’l Ëþè˜WšòöNi‡ÝŒÒ%„5y•Žj´=@©¯ìâúèq;ÒFß­â«OÚx¢ªª9t¹Ä<["‹ §ÒZZiź%¨ÃmïgÛ3KœÙ6Û4M¡ÕTŸ—\ø‘D WCÞ!¤oò€¥½îëÛ ,WUìrZž•Gõ K¹Õ±±‘S_ óQÑÖö*šK%4·ÜîþMÑ7Û‹™6Ã:*gd^²™çæl|ʧë£:zÝÕo‚Qµ˜à  –çl#᜗ÐHîÕkckQŸüË!Q+ñrƒh$W‹'ÿ¼Ì )ú¦£š58{Ôn@òJóR‹vv,FšW»ßŸñÍË0¾š¶ÖæûN°}Ó输ƹ–£JÇîš^ Ú6)wh¤üz̰LÇë:Ž×òÌ¡wª¸æy>±Ý&ßp‡ì Ül·e)€•Ž’‹a;j$ÍÕØ^練ŽÖò²õ%»'` Ö÷Ôç¯ßYeÁŒZÝ..0ÀÛ·¿—Ö8šqžg qe—8рш¾ŒÆ¨«y Ë2NQWŒFËóŒþz÷ñ¯ÍéÁk^óš×¼>õë%‡ºïŒþz÷ñ¿þzt)­þó?rq–~ß=|ù°ð}_˜Õãã'Í#úññS6ô.šè;~ZcA㺿`—ªî­n{`¬²e-”yθû×» -Ïp~½û˜­þVºR.d/¯^ýþ6É[Ç–Ú²Øg<µÙY£…wäÜ‹t¬Ò=o»PÙôÓì é”ó«záà\Zû}…viæ­’š.Xzs;*Z.0:¤*ÁÝfóŠŽm©U¯ý¾ÛÑÔùᥥý²ëܸŒ!ëù§BIåÇÜͧnÖßó^Ê÷jo¿¹Žib¤ÇÇO˲¤Áö~_AÚ¢†Oæ-°¥ñx{3[óŽÒ Ìæ('(”PÈk ó zw~._öup‘zëqR—¼P8£qcžõËâ‚ÙÈø7`ßû}5kF›Â wº)z¡9ªôfZ aûèÏßÕ 5çîÜ^ 9f4.<¬ÿ”…‹_*ϰu$5ßÚ ¥¹Ùä[t±^C}‚ánUwT¶î7ÀM¬ß%7ºÔïëÜò¼I»‡m1iÎQQóp*Â#¬´iûL ¥fpù¨ð@¹„Qß^éIäÞ/œ—À\ a7Ûڽµ’ÿtØ}Ö Ÿéî¹8Êæ»T^(áf[Ô·èR Sî×pØ AkôÕ×h,}.Q¿¯ ÷]®OßV’Æò -±‡ó 3r:¶+ÐãÃR>v•m¤¯Û Úos Â@£x\ÒVñÝ~ «¿ný¾Ê ZkÛ³>…\õ;ÄúGÏ!‘X6mÖH‡ÚFtÇ ¥íB• F¬ªªž­E½tˆï…*±²läÝë{@ Š¾¥!¾Bó²m“²ix“Ç!‡[³cž£½šÍÍ&ü¾o©)or§Ôy šVG¯¸bþ”Ó~„p“œ…£ÝćàªRÉFþêõ¸./ªønonÕ_{¿¯xô-Ï]7Ù¶òJß×¼ãÈü›l;°t”ù÷ß÷Ù'ôûÚ’2§íY!¨ÊNßß\U€%¹Œ#¯€¾Õü»Ð^ —.Ûª÷[ŠÑ~@À<Ï3Šú} ƒ$Í-~¥£ÒšeUCtmïݶôË,C_x}1dÙó îу¾S1¢ò>h—O9L*ºéU©é¥¥ÚÃ5]ÔÂÕPÞ¢Q„šÆ{Þü+©ÌKŸòr³†èÝÙžKý¾WXãè’ã¹>³ÊB¥öáµ·zd`¼Þ77ðHúU~ùù‡ì¦+¬ï{½Ð[Z6³½@VéyNË3.¢±‘“zNGiˆÉ}g¤ÿ¾/B-Ož\è­Ç=Æ}{ ìhçT—yž¸¡çççþó¿ww{ûö÷å矲›®Ðï{=ôûÀ5”žçD_F£åyFa¿¯0’Hþvcׯ–Vá ø]e/ïîœë ¯Åw¼[v(oöÞN3²mêÁ뼄£vÄ è÷=±t¥ì¦pkû—_œœë† WIxv˜o¶Òü‹xRaâÙ)Æj7¹ó=/áÏ9ALŽ–ç ý¾†Ùg¶J8[Ì6%–òÆNÿú Ca“;÷ó’÷Äüø¾/ö…UçõeSv:;]øW|º¿œ`TuPÃ\x¾ÙÿðMÙ32T’Ûõ;§®T®z^hDô‘þû¾¾»Û_ÜÙ¦låζ§Ïe!AaªXù(Cáw/ˆæ”Ú´”/oz æ”[:,²r ^ÄÉ–ÏÛ¸Úõ¼ä¾äs]¨û ß÷šzü¾«{Ø–ˆû9 ÚòjOð¨ÏQ_Þþ`JƒÊ Ä<¦iäyÍp¡`CôÑ<ëû íŸí)»´ËY ËK©” PBsám̧¶=Ô`¹¾x”–òô8¯ /4ìëû«Òoþ‹u²Y—Öà~yÉ­|6ú­0êµëS¸1䘙3·»êy¡cžgTê'Xž¼y¾ük¨§{y ïrîr"ÂVå×–Ã}Ãþã×_5K7Ï€¿ÓÑâªwËUÏ «·oW®²ðô¿ÿ›­þÒò àHW QW=/x¡åyFçZßwð \8ú}ÑáªÐò<#Ö÷€k`}_fAô‘ð}_œHíW?'ÿ†.jq`¡ß÷¶”6e¿ šöæÚ6õàu^ÂQæi~õ%Ì~'Õ÷úÞšd¹„Êï01Ö­}gä2ϳ<ƒpÔ¶5zØ6¹ó=/áÏ9A›‘_Œv¿Ò”«Žòrê7Tšç™–çkÚf\–入ˇ/]nNÇëêõ»PÊ \Sé÷JÈ € úΨG¿ïUÿŠw<¯k7úTú™­<@„~ß{‘;ÎÛ¶Öï¼^ådu¿Pæ%éq¡f½]ol¹/™¿óà‹è;#—~ß­ +ýUŸá7ß<¤¥Óy);mÃy|¾ªÇp°ôÍo€R^¾ â†Xß÷޶ŠÂ„k7FÊiÏKcXÉ}/T/Óœí8齄ó¢ßwFîý¾WÊqÞó\òöì^‚%œ·AON¥k*ÕIoÜGéyNô½&Û#)z–Em°†MîÜϫӳ[”#ŠÃMúÒº_(÷£l:—{™w‡U÷tùÑò<£ö~ßèA K—J˜>¯ñìëq¸e0ø¼|…Måçí7A-ú}o§4Àg÷^ØÁ¶É—ûyÕ¾¯”>^Ó«j`µ­¬=naŸóÞ¥Mî7@”fš>ñøVhyž‘c¿ïU™Oq^µ…ìqR§¸P§8¯nŽ~_àܨWBôëû"EèΈõ}˜ÑwF¬ï ×@¿/³ úÎ(ê'X§YØþU*_î'rÈ•¹ÌÇ “R¿/ß÷Ýî¼<=¦¿g€¡€ußÑï;?þF Áú¾×‘ÎQœB¯4â6Ò£„… w:o­>,•Ž’ ¯Ì«_€$ôhDôQ8ϳ<»òRŽ¥öê-Á4²Ê láÂQBc»&/ý À¶Uf ½”˜çùÄ¢º©Ë£ß}E—IŽª½DÄQ‡ úÎèáˇåë÷ôýªº©~LЄÈ6 ‰a³¡ß÷¬l%;RÚ¯P}™ Ÿ6ªkòʦ£<ló<#ó<Ï’ݾ º¤ß#ñ——?׬Øé?}v ãû¾g•®êšŽ½J‡e¥ƒ«¢• [k3ò*|˜T×1ÏékÂ6=¢ïŒ¢~_Ûܪe½Ô¤™M­tT)qaQ÷‘ë½h(1Ï3³ úΈõ}àX߽Рµˆ¾3bžg¸ú}˜ÑwFôûâp'šžåø8΋ïûž•üe_[‚æD ßmm)ÿî¤W¥õ7õPu^Âl\¶MæÒÁŸRÎ˦üP„û0ú†=.€è;#áû¾þ i©=0|Qú²ò›ÜÙÎK(’mÓ`#oÚay)?ʈ°iä}ˆ‘è÷½ÃÄO.ÒxЯk^ÛtB^á&¡„¶Mîlç5þ]ú²*ÁíÇl‚ÇÞpGÝwFáú¾‘´Þnþv>|ú0‹–˵ÚÍ]&)†^éŽîÃèEûÝkË«·«Þ¢hÇú¾'&Q¡]×wúQ©v÷ïÑÅõ’›¼z0óy 7€m“MéŽúJ;ÈG¹ç%ŸTúæn òGiûPf¸E1ÑwF.ý¾òncân6SíIä†}+æ1M¶óš¤ß·÷Ý¢ì:í—ií¥’~_„Xß÷"Ò*C"ƒ··çTUÇÕv¦.Á2íTkI³ñX¯ó:µôf8ÝÕ˜ùÅüˆ¾3ú}CÙV8Múa8´•°Ö–‘!Ç«>‰®z^zBËó0æfŒhÿ›””ú}ó|2ÊÞ¦]/õ«Ð‡{v}ÖèO$,†PBÛ&w¶ó¯ª‰¢V:6JÞÍ%/Áú‹ýsI¹Šæ>$À_ ußEý¾¥‘Ño¬á¡Y5PÅ0*ÄÖº•ÖÑmãVl›|™Ïkr»Ÿrö ËG¥÷vK^îä²=ÍsÝ•ú}¾1¡ÿ”>ýþôôþèRìªìŸâ¼,ä)®ÏjXQOtMnâíÛßÿùÏÿÖìö÷ß~Ên¢åyFÌó¼ºêãæçuŠBnþ±Ù8ëû0 ¢ïŒXßwF=WÂ÷}ðñúõëÇÇOšÝJ›ˆ¾3R~ßpÍÀØÇÇO|ß@…~_ù…ÇõP÷Qø}_÷Ùø¿ºÐ8‹}í±šÉ¼²ßšÍNV`ØÔCÕy¹o2—îØ”×G™nÍ~™àŒè÷=±(ºøXû¸ù!.Le .ÌSoÛäÎv^î›yÓŽünø¢ñ£äÏ"úÎHè÷=ðOàmBù1e_hŽZ…ʶÉí¼Æ›³TS9䣤ú;§ÒØ«­W˜õ}/"­·…[£:œròBCl«Õ³Ÿ8ÑckžGØ$ÅÐ+ÝQÂ}½h¿{myõvº‡#úÎH9Ïsú£²}5JYóàðê*VN|/HÛ|È3L¢k>/÷M6¥;Jh5ê…r[«o^òI¥oî¦Ðã£Ü-æôôô>­þ†Ã¡é÷=1[¿¯¼›×ÔðUôÏ”-X¦çk+³oÝ×<¦Év^“ôûhY–W{F¾eZ×'_ß8š‘0ÏsôkùêÕá?eúëóbän-^UŽ[…¦ý1”íÜmIðÅ´,Ýv¬KÎn»+jïÞyø~”†{ “ˆ¾øýXzžS÷=±l+œæÀíy1¾†aÈñªƒM®z^zBËó0æfŒhÿ›”0 î;#ažgeoÓ®õOì9ë¶"¥­aÈ7lr7á¥ÎêZ/OÇFÉ»¹ä%°5côþ(•=å˜ÇVßM'À¢ß÷ÄJ#5ÚûŠôU¢•¦”~i„ªò¨ª:º0´Ê¶É—ù¼&·û)g¯°|Tzo·äå®ÇGé>J“{øÆr:óùëÝÇüú«fÑk»êû§8¯ yŠë³VÔ]“›x|ü¤œçù?ÿøƒyžq2W}Üœâ¼NQÈÃÍ?6Ó"úΈõ}àJÏs¢/€¹PÏÃÐï;£µß÷ùùùè‚2^¿~­Ü³Ôï˘çImØúMm^óš×¼æõD¯ûI»ÿKu_F£ß€Ñˆ¾ŒFô`4¢/£}è ÀhD_F#ú0рш¾ŒFô`4¢/£}è ÀhD_F#ú0Úߎ.À™|þúýè"Ìëùùùï¿ýtt)àˆ¾užžÞ]„I½}ûûÑE€Ó å€Ñˆ¾ÇxõêÇ›îLÕòüæÝÇðÇo_>ô)ÌòæÝGßÄÝŒ¼zõãËËŸŽG¥›²arÝGØ”n’}yùÓVx@»ýè›0}HëüŽå[}ÜR[_„qQˆ‘UQœX “ åÙÈ̲®o®ï¯/´ 7æBÛ5˜YÆ<‡ÕÙR£ôöþöB_ ÓTæõíˇÒQiâiU¾ªxËzääõÔ5ôRŸ›ýè¶Ý&èíõCËstHø£»pTøfšˆ{È‘{aÃZ¦Ð+,”ªS#ùBUÝ7ªÑvíʵ%.%{’žé­8g†~ߨUÙ·)›p êZžÓmÔÜ•-¯üÚjÀ.Ê~1RM ØeóØJýµ»¶–ó³Äàeú¯…5éi 37æY,}w[}ûòaÁÙ£Jïw’mî=~XhmKpžÝZ2¸¥ºQWÛ;»›Ò”UÏÒèåôýÚi–І­/ZBQ’ÓïûÚ(d™zÀìáDí±‡ûüõ»×* ¥zç°g÷ŒÞ¾ý5Ž@‰Ù6Ž!ŒU>¶€ˆ¾ŒFô`4ËL“wÆò€vŒº`4Zžè ÀhD_F#ú0рш¾ŒFô`4¢/£}è Àhûó£N©…GEû7†^—²õ#„[CÙ„kuø™côó\ZPo­8––,ôÍkIÖF «­éšƒšÂ Çʧ\{T´Ãäµí¨"(´Êž½Z“ <“œT{E\Ÿ‘­Í@³ÿ<×èªKôMÛf£°…MhÙmi‚rFQDÔ>›¬æ¨(‚–JXJüÂ*‹Ð!zùg«¡ß·S1Ò`¼½n¬£/Š[H*Mp’‹ŒtÀ÷}mÑEˆ|½¹ä¨L$Ýí,Áx·2d®*ˆÐq{`1V¾%1×}w\øöB'›m#j=^eG_7f½£9P_Œ-As^³™¹=ÖÐ+9Ã)»_ùÝÁe¾÷µo`s²è»äp)b™;˜m­Á-uúÚ¼p ¡E÷pÄ-à,óÜ^UM«Œ¥Œ¾}ù°ýS&^U¼ÆsQž…oå¾aô¯!8 ©†û¦æË·l=Ê_jÄ6”­%GàzºÔ}åUß1ÏB^r1¢ÌúÖàp‡Æ6äË´²Y»´JëUWo•#Êø œ¾iº¶ÙpTäJŸ;àâ˜~ßT…êYID^Ù‘Ðgy“'oÔdz™TCß3€]n-ÏQ3ìYd‹íÛm^èP_Œ°਱èw{.gCÑü L‚¹®2¸±¢Ø¦l¶Ö`[à<°å ä6æÙü”jxÃQ+l¯ç¸ýS&^u§¬<‹ÉG§Gm¶Q#viÓ˜Ôô{U¶Æ"…;W¥l*Q>)j縃.£®vÛ?Ã4›4 ª^5ÎÒ¨«tën‚ÑΦ1© ãËËEëªbÈ‹’’?nCÙ®:.Ø£¯üXß}è ;Ú„-” 2IDATd7 ­ÁµY寧 $z­ÌN³ƒ-Á–+ßÂqªÝ iŽIÍv²^e3LbÞÿÀ¤€k`žgFcÔU…G®äøƒÏ_¿]ÜË/?ÿptOÔ}aÁ£ZÐï ÀhD_F£åôûÐ9µ‹è £§§÷Çàññe  ”aÎ2[€S å€Ñˆ¾Œæ6Ïór•©'Ò\Î+šüù’²s gçß_wÐo2¬ Ð^†ôXý »û§Ë!g °[<[J+'k˜8Úý³J>¦ ¶ÛR¸t†[E¹©± =®"öè+OzÜðÅòzœ—y¨³ìðA­Õ“î¹½VNÿ«|ʸ—Á°ÞN© ¥Ü³»É…o,Ci="åSþ¨ÏbKǶU{ä©¶ ò¦lÁô›ÚË \"Ûu@ʳåù,qî¢_¿t œÒžJB‚ýÊÐzKeèý¨’Ë <å•QçÏ"ÜSS€NeˆT…Þ¨ ·ŠíOCj³ƒ^¯1Ï¥Fé¨2þ¸¾Î®Z-Þ·ü{¤ßÍ«´š¡f…Áå_3B§åO ^8ÖvÊ»=‡4Ûª-Ùø9cîQuóSÈÆ‰kÇ—ÐÛ»$hÑ%úš¥K±y‹(Ù€QÊk‹å¥Ø/#üQ8<Œv¥¿*ÂòWÞ÷”Ç÷¤vÛ¬¢§üö¾cèÍf*däX }»S4uµìÎ/®« ‡Ù ­âcžø3”!5UèÝ-ϰÂ\Ì\ß÷í i ‘¯7—•‰Ø–Fv$?D ý¾ú•«Âµ„c£¿ôG[޵”=‚]Ÿþ3Ô±/Ã<¡wÉýÊÈ·+ô抾6i²¤*ºD­Çµy鳈ÞÑh8å×GlypÕÒ蛣0Øêð'¾P†N­¾µ‰ôxÄOÛ¦*Ü*¦aæ¼h§s…èÛ/Ф¸”W©ÇZ“Eø£²Âm;åÃ[žïŒa¢„öá‹nî¢+ñóì[/œ$¯´Ê˜µF²íŸ2ñª³hÛì ïë¦1©EiNu¦3—­Ç™§ÖÔï+§mú–ômÅp™`ٖµçv– °Öfö1<—}S›ùLg.›ojÀÙÑò ÙØw7ÑÌg:sÙDó¬Y‰o©\|Ð7/¡Ù¼”`´† WtTÔH 9*Úá¶µm8¯¦è0åQ¥†â(ÖêCïnl«Í«Ôl.$˜MVsTAK%,%~U¢†µE}SóuŸ²Í|¦Àx½ú}G"ߘ¬Ç$’î6Éõïá>=Ž÷)ÛÌg Œw|˳—lKµo^æeõÅØdÉB¸°ÑÑWQ¼1›4—1çek ¶Î;·<Àµ<Ód½¾)¤IÇ–WÕQ§£<‹eŽ:ñ:†6û…aÓÍ|¦3— @¤WôÆ—TÃÝÛZ…å¼”…OKŽò¨ÚÂÏ)üKôd6ÑÌg:sÙ„ìÑW»q¤?ÚFùÊc‘J‡Ëyé ¯ÜÁ– -¯y «™°Ïœgê›æüŸpj̶Àh­08²­õtíº€+y êÀàó×ïG÷òËÏ?]ÀÓDu_œBhA¿/£}è ÀhD_F#ú0рш¾ŒFô`4¢/£}™&qY·šŒš¹?s!úâÊžžÞ{%õøøiæÔ¼’0-ÏŒFôí"Z<U¸z.o¿åùÍ»ÑÀé;ëvªÕ…]Î+›NN­ÙH³î l2µå•î \ŠÆ¼v‹ñí˯Ï"õêÕë‹——?õ› ©­[õI¹§`f‡õûNwˆ"Sl4G „õy)^{^éûÃ*»a‹‚™°ÉÚ„Òö²R09UËsøp¤UP¦‰akÝnLy”y¹Ô5mç•ͺÇ%ŠBÚËËŸ[H6RK·¶”Í€ù©ê¾[Kàöÿú~ôÜLŒI7íVƒ”µ±°œ¥¼„b¤ŠÑÉnkp¿FÚcóʰÌÝvâ, ½À%õjy–{‹Kýæ>æ-ÁÒ‹4Aáo…N]Ý%òÂß7†‚ɱ|w«c^¶4OÁ7XzKÒFßö0¶c‡=šG¶§YW½ß#¯Eéóš0Y©WÝ7 fçzhž¢{Û·â('Õ£’zÉŠ/hTDßÚåÈÆ[wóõnݽp%½fÛðª;«ƒze¤iÁÖ·§½<Óiygaë›wmWFHlcì;,™AÎÀÝ4µþ¾ŸâŸùRÿxv,×ÿ³Šjè{wuÿ¡GØßã#þ{ºÔ?æûïjßÁ  ~nµ. â¿§§›—ß þ™d?þ*ÀÐų1ÇÇ/ÎǯGlŠŸ½#ànv¶½2諭ø¹Õ* ü>âs•>}&®ê‹Ÿ½ÌÀCËû~x»Jnüã -ïíDˆŸ;úÇo339“÷Û‡âç`çüc2»Í¾ÛûfÆ_òñâĈ? ~@ü€øñâĈ? ~`¯ü>ÿ1úþÿuãñ|ü-/ÎV>ýú»¾úÁþ'~Ž=ûô«†€Ý ÷vÿ4²7¼™÷ÿý߯¾Sž‹Ÿc1öø‚àïßøšAüSÊ><ú_å6œóst‹3ÿ>òöÿ¬Îÿ2ôÇÑÿüÛî04 þɲßß pOļCÀ>ùv<ò—þéeÙ¡ôtàÞžÿ‹ÿx½û½Ê‹p˼7/þïù¶ŸøË§ín<þÝö§ñöùϽPˆnÞÏ>β,Ïó,ËÚ¶½ñ6ÛúÉ¿ãEÿñ/V7eo@ü³%oÄoæyÛü¿?þÁgY–ýùoß?Ç8 ‘ý¶îyäCü%? ~@ü€øñâĈ? ~@ü€øñâĈ? ~@ü€øñâÄâĈ? ~@ü€øñâĈ? ~@ü€ø=)½o mÛ­îŸç¹ç™0óOÖÔgB39f~?»põáGW~äuÀ²ÿ~eß¹]ÿõ/ f~ÀÌ?ë9¿Üü™0óÏ}Î7ÿcæÌüsd>Ç̈? ~@ü€øñâĈ? ~@ü€øñâĈĈ? ~@ü€øñâĈ? ~à ü'ºw£ýõ¯âíü7¿í|èvÿþéÏ=ì#?Žøg«ÿ¯ø¶‘l~ä1÷ŸY8x³ç°«FÄïV ·9¾ùñû3ù1?gÄo°Å bÛŸøf°yé?ònÄ?™ù|ßÿêo^¨ß}lòžê ä%€ézï½÷êº~ðàÁÇ=zôÎ;žžžž>~ü8Üxûí·=zôÖ[o-—˺®Ë²,ŠbxùÀ²ŸÃ,’û ømÒcaÛŸòfÏÊ%=ñ³Å¹ñø‹mwùSvû¬¿ìgÔ4¶Í³î˜­¾1?ehÆ>†îc€˜(çü`æç ‹ÿÃþoÈ5óf~öãö{ûûø)ýóùñoXrþoægž')ÞÀ7ÛyÈKÓå~€e? ~@ü@—K}wí—?k;G~÷§|Ã}Æuów>c~îmž?âçK©¤‘„ÛáxúÕÝF5óгBüì ¶þŒ}ØØ†V›ï ÏñÏP?0 iÄ?Ã3ÿy O&ñ³—Ó™!þ™Ì™û[Œß™¿ýs:=Aüì`ÎßÇüß¿‚0f˜`6ü æ{€­‰ÄLî¼ý•øiü˜Þ¡sPü`æÄLqÙ¿ay/~˜ãì½X„ìÃÅ»­Fñôgþ´ù˜}çˆøanŠÄb±ˆ7ú#B_yyyyuuõâÅ‹çÏŸ?{öìéÓ§ççççççgggggg———Ÿþù‹/®¯¯W«Õz½nÛ¶iš¶}ýÎÐô6°I¾3ÛEÞ±×n\¤7^ÆŸ>n0Ò*˲ªªªªêºy‡Ê?$þ0ç/‹²,뺑Ơ,Ëp{󲿌#D§üø u]___¯×ëðS˲lš&|*~8Tü±Öú•ðîý8 Üx>B‹WŠ¢͇_X­VMӄ쫪ŠË~3?*þ ®ÍCªAHËO‡€2ž?„;¥ëüP~˜ä×§â‡#‰?.Ò¿øá€ñdzútåÿðáà ‹ÿôqÊÅbѶmÿr¹ …Ç9¿ªª0í¯V«x‘¯S»øánâÏ’}º°Ë ýŸœœ,—Ë0ù§{~ù¿LwûÂC„U}8Ž„“ÿÎ~µÃ‚ÎÕþØâÌ_UU̾óžŸ2ž<„ž«ª UÇá \ê géVŸøá°ñÇm¿ÎV}fþ¸ò¿ùœ?¬üËòõ{~â5¿¸ÃoÚ‡£ü;ïʋ†_çW^ÇÊO{N/!†9? §÷ýø pgçüYrÅ~‘(_Ißç—.ûÓGx9ó7MSEú q S¾øáŽãê?îðÅ‹|á}¾7ùeY–Çø°žà ?®óãR¿…8ìpÐy‡~˜¹ãÇΚÿKß{gY'ùôÆWžçàŽgþþù\tnÜø>yŒ¶³ßÿtsá⇃ğ¾ugÃ_õ¸áûïÒë/ïǬöÅœù³›Þ¸ùïyåvï:ño&~8Tü;Œü~ù®æsñÃaãßên_?0Wÿóp–Ô—O¨=IEND®B`‚stella-3.9.3/docs/graphics/logs.png0000644000175000001440000002214612162610274016607 0ustar stephenusers‰PNG  IHDRà|ph­bKGDÿÿÿ ½§“ pHYsaa¨?§itIMEÝ ÁtEXtCommentCreated with GIMPW IDATxÚíÝ=¯ÜFš(`ÊPx-àáð ˜Å$“ @©„M&´#w6˜È *ÐD 7#;œdáI˜ œ v¥çGØóÎ f[Ûn“¬*V«Šý<ÀÔê&Y,~¼,YÿôíÃï>NÀ>¾zþùôèt:=¨ ØÇÝÝÝ4MÓôø2u}óÏø;}¦*`0À 0À@íüðòõôðòµÏ>ûì³Ï>ûœðyͧ8ÖÞ~xùzúñtr¹_¾};=úéÛÅï¿ùîçiš.âXÒ?};Mï>NoÞ|­f¸ ¯^}Ÿ÷^½ú~5ø^Ò Dµ€^¾ž¦«[ÐOž<ýÅçûûE vžÿÒ|Cß—Xöµ”eÕ®úôðòuT+øñ–™?yòôWåúÿæ~“âþþÃb Œù>Ç\¹S–S?ܶ¨[Ð1‘üÈÁEðàìý³ßOïŸý>+fnnǬëVã\‹°f/5ÿÁ·VK€ƒ·€¯ßi:ßþ½ü› v÷÷>ý͵˿ÒAªÄüç.$b—}Y7ZÏÇiýÎý{-foçöqÖn–˜NŸ¶  @v>¿\º…Z3ø†nyÀÖÖïåÿ={ÿ·_ÇÌ›ÞιۢEœ:ïØß§üN‹€äðõ{Às}ª×æú7—߇¦¿ünî}ßÐ÷sËN Â1ëwÙ?zmIð8^ëw©\õ=àØ ²ö›­ßm]vjŒ)ÃZËVÐ ;×è>Aà6\÷ócfcA@›Þòb¦04 ¼zõ}ò4MÇ‚)‘îïÖµNwz¬ôøÙ­÷-ë4·ŸaÏݾ¹ÛöÞ«¯}|1P x.p®Ú;БwÒÖék/ÿ(éÏåmQö˜e¶¬S¥ïýß6ù_Ïþñ—¤ß¿ÿÍ¢ßÖÜÑUîÈj¬NÇ­Óš¹½m+†o·èމjéŠúú7kWÜKŸsÒ)掤Uâêukùc¦ïíâ¥æö­±î©·çÖaëþùÝÒº¥Ü&®µ‡–¿õøž›v­~Cß·:~jŸzH';º®û€c6nèÿÖ¾R{E¾t‡Ê[þš·yrÊ{Û³E” JÖOéÖYnùCÓÇì[k­Î”òÕ¼€¬µ¦Î+6 ¯ÕézÊ=¾söŸ£t ÓnÑÜ2yCLy×–yr»Ü©÷¼­”[¿)'³ëSûOM-ÙÓ-ÒØýký¿æd©í×¢|µËÛòüÙbÿMõ± ÷x1W`½”ïòûÚ'ª”:ªqB¸^Oö9Ù·Þ¿j?`VûâtíÂ1æöqï§öù³õþwQaÅÞÏnuųóÔsšÎ;æR ªf™ÎË<ÿå^1ïY·½óZé,·n»Øý«d™Ö^,1ïÔý3w=×ÛÚmõ¥ï[Ÿ_ZŸ?·ì·¦û>à”+Ôë+¬˜tƒ)éSûcSË7w…˜óVÌü×®Jc§OiAÄœ ÷ªßÒÛ77e¨…µô›œí¿V†Ôtž±åIíƒÏ­Ÿ­Çwéý«t °ôñYûü©œ¨O§ÓÃ4MÓWÏ?_üÑÃË×Ó§ÓôæÍ×j¬ðUm­§#ÇÚ/lÓýêWýsöêÕ÷›ÞþòíÛÕVð7ßýÜo øV8 ©Ñ¢î(ÅXÐ;¶¡úUÿ$0tL>`(H>`èX“>à=pH}A<ç5Šëå„Ò-¦¦côf^ý×z¢5g>%޵á!Sö¯åËËyË2Ržð€µuÿp‰qRצ«ùrxÌX°¥Nh=¿àÞê u¬Û=’”.îòK¬oÎÅEêXεö½Ðûè ¥.ú€·ËQ®\k\`ô §²mM<0Ò…ÇQîˆì|µnia¨>àÐ-¢¥as[![ç‘“u'¶ µ3%ÅÖïZùÖ²éĬßåw#µDr·Ë^Óçì㩭ʇ|é]³÷€sûrZ5¥ÓÍm9ØSÓ‰µ>y-¥S,±~©ë{´öHéWr×C;Æì{ö ¾´v}À%˲%Ç$55“Jnº±éñF;éÖÊ$³G=Ìí#)p¹-óUî-àù€×®¨oµÕ²tußâS3ÝXLº·£»õ€Qû6|ëã‡Û6T>àn¹–.o¨ï7%WoLJºZÛ£Æmñ½Âi½­½&Tó!¢=Ö·§.“#ÞA ø“½û€CéÄBéÔRÓ­m¹]3Ý^í–Dnº¶PýÖ^ÿ”tKóÎÙ~1ëJ7ûzLèâ«D:ÁÔct©Ï·Tº¿ÚûW¨-¶8*á4MÓï>JG؉#¾†rÄVÊÞ-ý£ÔYÉ‹Mȱ5a(ž&¥#¬ÝLýVoo必шZ¿®d߆6†êÆEÀ­‰ˆ#ö~6Ü:ù€`ô°|ÀG>`½¬âè€Ñ[Àú€ Ž>`½¬âè€Ñ[Àú€ Ž>`½¬âè€Ñ[Àú€ Ž>`½¬âè€Ñ[À×÷³ŸàûûŸþF=ÐZ–ÛÉ©ïý¢õ~»ìûûYß´€C÷³G ·~r0Eíסý$æ7·pÁÄÅ̳ǵÀë“{éïS‚ËÜ´çï—¾»¾¨(Yþów[ç*ßÒöX*íž<—ÖûòÿkßšûG‹³¥ù¯­¿  ðÃË×Ót:%¸µ 1$å¤8×Ò[kµÏµ|J–?Ô²Ú2}j ˆmÝQ'øÖÜ?j\œì±L8Ї—¯£ZÁK 1-à¥àwyÒ‰~KYK÷©¥Î¯ö‰jËü<÷¾±ûj µÆúÕZ !?úéÛiz÷1º5•rKzéVpï÷H'}½ýߨý¿åþ:~_ˆˆ™>«uÀ®€ëÛ×1-Ôœ ²GÊ-ÿùoíV&õ‚ïRýÖØÿknKÁ¶€Sû€çZû|=Ð÷±héóÜ¿sæ¿¥ükQå®Ìï=„µÏÙ\ýÖÞ?Bûwèû˜ãX™Õú€cNØ¡[ʵßS\[Þ–ò—þ>ô›œùÇUa•Ù¯¶ÖoÍý£Æ¾¹µ¯È À¡>`ú 1-h'Ó>‚5p,»¾Œ“?i䀂ä€Ñ[Àò@œêïï‘’p´”‡£É©ß#léŸîR—GX¿ꄃ¶€çò_¦#¬ñžàõ2FË7ÚûI;·~ü—t„ÖrìÞÜb¬ãѲžÊߢ~{o!HG˜vÁ¤©öpN:½”ùÇ ³«zésNºÀ¹2l-úË­ßœí]G­NÞÒnß~¡õyýJ¤#Õ ¿mMߎÍG»–î/t€®Ý"¬‘ªïúsN:¹Ôò§Ö_ìÉgký–ØþG‰K:§«ù´G]¿Üt¤P´<7t­ÖG¯'çšéK×ß– ŒÁ©æ:Œ|¯/nŽ˜Žðë—º¯ ¾\Ç̪ù€{¶ÇíÙÞrÛਤ#|F\?ØK±÷€{Ú¯ŸðÝcy#ÕO«mr„:‘Žðit¦­ׯå<8Žª}ÀµÓ ¦žR—¿”n-5ÓMhyK­ðÜòï,K¤³›+ÿÑÓ!Þr:BëÇÑ<{ÿ·¨ß½öû´@}:¦iš¾zþùâ^¾ž~<¦7o¾¶•â!‰±[“ÖØÛ«WßOÏþñ—¤iÞÿæÓ—oß®¶‚¿ùîçí-àÞ¹Bg;Y?àV[À‡Íìä@ É·–å€Á[À5Þ€#¶€cß–ØôðQÞéä¶IG(á¨û'}«žÁë¨'é­tÓŽÍm{žkHéÓ.X€´˜ù¸æA¹v2Þ+]áÒ‰tiùK#ä”L—Z¿ékN_;ÝbÊ÷¹IBÿ/áÜŽGKGØúøÕŠ¿UÞDµ%]Y꼡iCË_+s‰‘¶ÖÊX"ZÎô¡å×N·8J:C陎°‡ã—±5}8&Yét`¹WÀ{O_;;LÊ€ù½Õl:»ƒoÊúÕÜÿrçké÷>~ÑþdË{À¡td5wȘÛ?­/öÈÇj¡¶T;]¯Á·ÔúIGXoýz8~[Ó÷€k¤#ÛrpĦ#l‘Žì\'ç¿Òsêü[ßXzígmÿiñ”²t„·“Ž0æ.M­ã-àO®û€sÓÖN–°5aìUx©ò—¸…¹6¯šå¯™nñé ¥#{ýbö¯ÚÇ/ãŠíŽJG8MÓôûÒ6hEõ8ÿž·³òQ{ûÙ®·ck:ÂP<=§#<ä{À×·‡0ÇÔû6µÏÙ¿¸MÍßvð´+›8¾èߦ± €¼˜i,hèµl,hˆ3µ€ ×°>`ˆ£Foë€8ú€`ô°>`ˆ£Foë€8ú€`ô°>`ˆ£Foë€8ú€`ô°>`ˆ£Fo_ÞÏ~òäéìo–þ?Vîô½;úúÍ­ïå_OËïq[ÜÚþGÛü¸öIåþþƒ­qcõ;W®=ËÚzùÅZÀ—÷³ïï?̶(æNnNxuÕ®ß#µÊì‹À^bû€«µ€Ï'ï¥ßåÉ}î7×'ÿ¹ÍÖìù‚a­ kóO>uýRæ¿4ïÔò]_D¿¯ÑrÜ£þ÷¸(¹,Cêþ™»ÿã‹ À/_OÓé”ÜâXë/ž;Ù¯µ¨/ÿ/÷ãRÀI™Êô©ë*_¨~·”ïºàµÛÏ—'‹¹‡TæZ`kŸCÓ—n1äÎ?wýRNÆ¡‡Ý¶®_ÎCX±ë·4ßÚõ¿ÐJÝæOÝKï@[Uû€cN@©Ó†>çž,S§O½=šº>¥—ŸR¾˜‡|rû÷knŸÜúÏ)[ì>ŸºR§n¤Ü¢˜zr[¨bf©Ì1ƒð-. ò@AòÀè-`ù€ N·}Àk¯.Õì4”ßz]„F6»JñÚÚЊ1£Œ­½Î¶e»y8D X0×ÁìrÜê¥'¨ÏsÁ04ýå`!©ƒP\4²e#\D•ø P^·}À)é p­ì5¶OjLM<[†[¼PúÕí{À£¤õâ¡v¶£Ñ.@R¶ÿÞé,ç¦íã)é@·”ÄÌR¸ÅÉq”t€#Ÿ˜n5—Øþ9éc÷¯”éSî:ôžî´€/lÉ{âOzi©ËË-sNz©ÛgïjõTsÛ§¦ÃÜ{}x»Œíp =>¤Ô[@ŠiEÖn¡Ç2Ì{À=¦£sRl¬Zm«ÔtеËn_„~tß¼v{³÷t€—'¼£ö夛¼þÍÚw9ïú¦´èk¤³l™N1ôØZýJwêÓéô0MÓôÕóÏôðòõôãé4½yóµë¬e‡íÔñêÕ÷Ó³ü%iš÷¿ùÃôåÛ·«­ào¾ûyš&cAg·´` cAƒ /  Ø˜© ½¶€ q䀎5 :6]Iž\]ß)u³–ÈáHë;žxh¼å’é×Þ÷][NJ:ÉPýÔ8~CÃÇæ–/ôçJâ=`²]ðÉ­ÿ‘·Õ–±Cmm~©u»6¿Rã3§–÷z,êšÇì–ú ¥]zÿ‡ôwÔ kÉÉ'þdJ—Ø[:ÅÁ¥öH_¡ùç~{Š™ÝŽ=J:ÂÜé{½ò.5RXú-Q¾^/„Z·–ûO‹ò Öô¢Y>à˜ôÚÚ2áÑÓÆÖÿZp¬Y¿¹·c†zŒ¹ˆ9øÖìÝ>[‡¢J3eÛ¹ýÌš÷¿ùCò4CÓ*ÉMG˜ÚêÉÍNÓk:Øñ„÷hE¤Þb¬}K·—|¸[/bòïÙÎ-_J¾äØõ«19Çrww7ýõ¯ÿž4Í‹š¦ç¿+€KçŽ ÂµŠžûÄö¾ªÝ"êqû²}cž~î±E—úTOw Wl>àæïÇ> R;an‹jËô½ô=Žî.¦Eµ×É8õ¡«Ü“}Á·ÔñS¾šÛZð¥'Íú€×Z½§#=aïõ³G:Áµ[»1ó¿üM¨3µl±}Ô{^ï™î°tphF¹ëÃ8bû€£ÒNÓ4ýðî£t„Zz€>½xñ§M}ÀþãzpR:Bï×kip,Æ‚€ŽÉ É £·€õ@œnÇ‚^zò×Áûnƒ9±õ_*áÖ×tÖ†5ŒÙ¿R_QI}Å¥ÄúÅÔoÍ¡&sÓý…pí÷€[¢[àÚéìB'ðÜtˆKe챞sN¢­sPÇ-¶Oé¡,×úÕaØ®Iðå‰3tpo¹jŸ‡wïôy5–Y#€å´dz¸-º4.phÿÚ+x¶Ú>%Ö9ôYÏ·Å¡¥îó×>\?ñêäp\=ÞŽ.¿¸Å„cêæ=àÔ‡`.O„­Nнžtc˵v‹>gúÒéúŽŒJï7©w™Bëë‰g(3›µ€×nÖNgV;Úå|{ .)éÜ–Ê™þz5ê'¶{c© ké c¦¯¹}r˳}ÖÞu.q|ÒªåÔ[ùÝÆ´ÂȺHGÈö–Ì-—ßÉÝþ ,34$0ŒÞ–âÈ ‹z éáåëi:Š.¸Ôk>$ɯû¹m³}Fxº¶fº¾=¦¯} „^ƒÊ}:>´î©éK¦ƒ„\/_Gµ‚›¼œ›.í|P`›˜wcs·On ®Äk§ëÛcÿ¯™ÎqíŸ2®úÜÿ¥ŒÕîu+zÕMpÈ­ø£¦ƒ¼•íµÇÅhÍmSþ½Ó]BŽáÇ‚®y‹ïr þµ+ê[¸z.‘î.f,Õoh”&ÁÚ U³>àÔ²ä-¾P:Ã¥ßñÄS·[ê!¶~×ZDµê>e¨Ç¹ï[O¤}oëº “žuÝÜ£¥ñŠoe—.Z¶ÖÃhÉ®/Ðzž~¤@¹uß -?t‘æ–3#ð0«ABËÂ…ií} t7d-qh:û0- ÷pW¬G½Š­W‰Û¿5Rê]>ÿÝbPŒyj½TýÔ®ãœô‡°bdMú€C}`Ò î{Ÿ«ŸÜ~ȵ‡ÜbÒé…’Ûº]Kì­§¿žÇÚ´%êg®¼¹ûÇÚ¶YþÜïµtéE÷}À¡ƒ%÷¤’3ÿ[8¨KŸ´ç¦Ï š5ß}ú½ëgíÜ”ÖêÖã7´ü”ïa¨𣟾¦wo®r´¶‹ú±m •±  cò@AòÀè-`ï@œ®Ç‚ŽI‡G½º_ù2{Lh»ô<`ÌSÀ¥SÕy ¨Ò®Ñ|=RMn²…ž.$Žàr»Ì½z½íF« Á¨Eð œÄ·½µ€š2 yº|84X}LººRéCßÇ_kù{Üú¬±ŒÚõÚ?rÊ—;oàØºÏ3ÝeÀMÍ„Jg¸ö9fúµVážË¯uò¯`rëg) ¦LŸ{JP$×È;äÖ:)ÆÞr­•"®Äò·–é2x/¦­ÁkíSbúÜò-m/€›Ï\j,ÜÒOËŽ²üµ;­·ÏZîâ^ö€nß¾|Ò6æä“boKë§ÅS¾±Ëß«L{õ3—œ¶v:ÄÛÃP}Às­¾PçÚC:µÓÅÕN‡˜’.pkpŒéG_Zvoéü–æ·5bjºL· Mút:=LÓ4}õüóÅ=¼|=ýx:MoÞ|­Æ:bð€z^¼øÓô׿þ{ò4oþó?W[Áß|÷ó4MÞšà 0.cA@AòÀè-`ù€ ޱ `ô°>`ˆ£Foë€8ú€`ô°>`ˆ£Foë€8ú€`ô°>`ˆ£Foë€8ú€`ô°>`ˆ£Foë€8Uû€Ÿtq±T®-å«Uskëwù9´üÜï·”à&[À~úvšÞ}LD½º,óåI¿ö2c[Ð%Ê—ûûµmS¾Ð>!¸GÛü¸ÄÂzÂse»l­µk­ÅåËmA†¦ •O€XwÈ÷€Ï翵ÖÙýý‡¨ ˆÜ Œ¥é—n±§–/µrÊßKýyRèQlÌ|\cás'äœþË-ó/1}è!¡¥`êú_÷yæÖ_n+4´üÜï·”aé"J_10ªM}Àk·LsOþ%‚KÌI9¦|K¿É™v„ú«ý}Ìú§^´ôb×>àÚ-èÜÖÓ6û À¨ºí>÷-æÜF͇À@*ù€`ô°|ÀG>`½T}¸äXÏ·jÄ!<عs?[ðí°¿æï§¤ \ú›.oKðÏI—š¾DSÒý­-Û €>mÊè¢v:½PnßÔy§\¬Ä”ésʳþFŠh£z>àÚ}À)óÚÒŸš›.¯vº½”õYZÁ`ððZ>àQå§P†¥Öå ªï÷öpO‰òäÌcTykó[úÎCXƒ·€Sû€S¿Oí¯\š>¥u™“¬!fù5ÓÆ,ßCXmìÞœûýÚN¡ß§ÐÐïs—™×wKÝäÖß–‹öe,è|ög,h½Ü"0ŒH>`½¬âtÛ\êÕ^Ò ULºIÛ r ¸Ç>`OøÖ ¾÷÷~ñ7÷žñÒw·¬Û>൓ùˆê–ôÚ6`]·cAçŒTʤ48RÓ y¤)w¶kž¸d «t ›Kë·–îo­Õw ÁʈZå5é¾lyözryéèAé¼î‚/@¼Ø˜ùXUM7\µzh{xŸ”ƒ£ß뇮k€ô˜Ù¬¼Ö‡JÇ—šÎoiYkÙŠnù!¬¥‹‹¥:|ÒmÊ\2—þné7©)cÒ5ø¦äeà×13¦l,èl Àú€ ÎÐï@k_|ñÅôêÕ÷ÉÓÄjÚ ={óæë¤ß¿zõ½>`èY“± oud©Ñ\¿Ê•ò}ÎXÞ#â=à#¨£–к­}_{,o€›iënsÑ*hå_€#zÿì÷«ß?{ÿ·_Ä̘Vp×ÙrnqÆŒ„*CÌüC·f—æqK#mÉ °1×ȼ\çæ\:À¥VYhÚ--À”$ô¡iGIw¸µxi(P€Q={ÿ·ÅVðeë÷SÌ,€kH ,¡pé²]·p·Â¥ SþÖÁwí¢!õ € ¸·>à¥äZ lëBNµlï*f,l€[o_·~Ï1ófÞ¾nMžßù/g~çy¤¶¸sûœk·ò[_0hG¨ÑœÛ: µxsÞCÍM‡xùÕܼ|ý‹f¶Ï>ûì³Ï>ûü¿Ÿc<:NÓ4M_=ÿÜåTöÍw?OÓ¤š€@€à8«~è(ÓÕ(îîî¦?ÿñw*€ÉóæÍ×*!Ai€\nA€0#µÛÀ@;  ì|ïîî>¼h™bûícú«;3~íß3Òžç÷w©L»v½Ým¯ À½¤½íŒ-ÊóäÉÓÙÿ¿¿ÿP}™5—Aœó>öÛ—¯§ß¾|ÝÍ1[áíÍþÜ‚¾Ú{:@[–çþþ翵ÀŒóÇhÃέëR-t­ó_¶"/óe ¹k³e>[[°)óY*KÎò¶,+¦~J-«ôzqÐÚ‰–®Ôkì$¡qî _û¿å-q¥¥P ýæúû¥ ³¬ÚëykAxn=„ëqy«:¥å|9]h>[÷éØù¬­SNÍÍ+vYkõSzY%Ö‹tŸx2X»ª½>aÔ,ËåòRoÕ•šOÍÀsþ› x—·¨çnS_N·ô›ËÿÀ·Ä¯—q ·á¯l(°åÜjîíÙ-1ë¸v!¾¶¬ÔúÉYZÀÑGïW_×eÜãÒó¾n©–h–jAîÕ½ÅÛÎZ4ãl§Ë‹¥=¶ŸÀ}ƒ¸÷ ƒ[Ý©C­Áûû¿hAÔZÞú†Ô‹¥Ú gpôÕ`í%4ÿ¹þ²£ìÔs·¥cû„GêK=_D¾}]ô–~%©æ«ZËí"´ÂIDATŠí&Øk½8hŽÙ‰Zï =¼«¸÷CX[‚ôó^ ‚oú~XâØˆ½ÍO‰åÄÞîiY1Û«Åíî[ñèt:=LS›±b×n¿®í(±OAç¾²S–вÖn Å>M³¬œüûŸFUŠˆ#æw©OA§,«u@|ñâOÍÒþðîãtww—<ô‰Ð‡óаMpͨ[$Û0ýàËXð…q°‡°`@*Œï°aiý ï„`’1€0­ÄäŒ@¦ ¯ž>MÏ=Ô°'· @€@`€`@`@€@`€€zœòãÞ}Tc4÷ÕóÏU»qÞ {êhÛùé3;!#¹»»›¾ùîgàÛɱ§Ž¶ŸŸ§.àÙ?þ¢–i·ƒÿŸÿ«Øó^øØSGéç'}ÀЀ 0À@%kÌôßþë¿õÿñ¯ÿÒm%\—·ç²îY×õ°ôÿ¹óÂç͹ãg¤cj¤óì^eý¬VÁÿã_ÿåÓßÒÎÕ‹Ërö¶ô\o@»óæˆÁWLØ¡ ã§fYÝ]Í·«X¬÷ÉŸÿüç®ë¾}ñ¬"üÓÞ€ƒùƒç¥|øôyï*lN“¶¦ßy!WœÝe^&°£? þýú§_w©GM?~ÿõã﫽ÞîìݲAà¼àç TðýÎ+œhºÞ˼Ú뽚‹¼ð‹¼LhʰßÙýgìøDsµ×{5>_ ¸‰Ø ‘ž¿z×ÿçoßžùØ_  M9±spîëœþº®›z[ºÞ;³0úÑå(î^¬ù pžÜæ _Y«Añû§ßàËòdö;Û9ýµsæ „‡n)ÌÜoçµ\\ñÃÇ 'ã•ý=ÎÑ÷óõÞÕ)ìp?ÎýqE¾Þù8ïjqZK$×;áäœ+;ô~èÊ×tÈy¶©s¨²ç\ý5· øt€½Dõ;#?<’Wj')~kóüËßÿø·è«¡OŸ~uÿãË—ßÙ¨@˱³øâ‡‘Glá2õ“o»ÑõÎÿø—ÿ~„ÌþßOŸ~õý¿YSÄD!`/õÆl“g7Ão^@¼¯yÑ XþÛþó£:gpêÿòå÷GJ‘REjʉÛu'ÇZ7:Vÿ sGqE­e>`/Ëc¶1K]¤v7Šˆ- ópzQs…ÓÖǧñ¥Ð•;\#ðr&¯wÒ×;½¤ÝßYaiÁÝW|€°œy¶›jªKú×Wﺬ5ù¨à¯¯Þéz»(0ÏöqKÉâÓÖ+p p5J%¬L¬¹Ge0M4æ& ER‹Ô”6WèñHSÿ–’"‰xRª±ÒäõÎ~øŒ\¡ "À"‹Et:½¤Í o§s‹Ü[?âÆ'å>Bû÷‹Äçû;ýïî…Ÿ}À>ô; ~'œÖ‡OŸŸcèûR4‰RÌ‚sŠ9KÞn·×?ýZ¡2´@“(H¿sALkc~Çxÿþ»ÀÖ—/¨V¡I!v. 7µ±7o~V¤B‘¤çdÌÒˆ&jÌvnU÷ñ:±1äíp2ÕÉ^7ؤ®l®H"uääïŒOTòÈ Ö~Þñµ²~J¬ÈôXŠT(P͆c¶ƒ¼`g"ëvUZopdšTd¯"5åÄΘnß w“;õ™“m<ôp˱óÌÂa©lÄZ>`ki¹¯ï!­ÂåÆÉ×1¥6ª<¤­ð˜ò9l›Y©¿KïÖ¸Ýn–‰¡O“(eyÌ6;€ýöñmÿ¿¼=äˆ\³ðÇï¿Þº&4B“(¨Àš|“7¢dì¡HMº#î}ÎgÒíŠT(Â$'A4‰R–cçxìôœú!3>|vxý[&"ÏéŠT(PMÚ\¡ð¦¹¿c¶Æ”JªÌ¦2ÎæŠT(P‡õl Ø ižëZc}r_7Kîk`/r_/p‚fw1?àÊ6ÔúG$‰&±;c¶Ð´˜sÖív{ýÓ¯Ç="I4‰èw¼ÿ]`ë+ÅÔ?"I4‰}éw@ýÎæ 5ëRW€¦ˆËÂ#coÞü¬H…"IÏ(Ș-¤9dìLMí"—EÙÎ-Ý>^ü½ÿH^©¹GÂOØZy¶[JŸ¶þX1J ›4WÒæ =éoêßR2Ø4YêÐú7>þÏmQ¤B€šÒæ …7Wó‰Ü[?âÆMb_˱3&V•*Õ>Â?¿§O¿zœÍû+²oæ„¿D ~ÅØš&±^½1ÛŒÏãÞ_ì?’MÇ»Ê38ùòû£{¤ÈŽEjÊ™+TíWI~§ .ëñƒrñ2ÊxLïÁwçL4‰H˱³ßc›{GRƒ\  Øß”ú´9Æ û |§&çt½oýxšBöåÚ¡I¬ÕïLÿYÿ¦ŒßèÉMu>€ÓÆ\\v ÷Õ8+Mb½´1Û¹_)>?È ãš.Þ$ræÙWæ„ÀÀ›Dy¶÷àºø»#ã‡É8l®FàÀóWïâë6˜ósû„"ŠÔ”6WèñHÓýŸƒñÕ@©°Œ¹Bjl¡f<§+R¡_·ø© Ù_mA“ˆ”6W(¼ir¾VÌÞú7¦2“ýÑÀþÃÑ4ãcÎ8›+R¡ÈYÝn·À21aÙwÁ—ýÊP–&±»C®g›ú9]ðså4"Wôþñû¯·® Ð$Z ´ÎIMbwOôÉÂä¾n–KÀ^ô;8A0pÈë°#±ÒˆÆõÎæ 5Ë¥h`/bç²÷ï¿Kzþ›7?+R¡HÒó 2f iÄNH5f;·Îo ]xxiàõ;œÜm5Ë”+R¡@9ù;#• 2£ÆȘ½ížO´Ÿ+2=–"ŠTSiÌ6œàó@ùÇçñA¦IEö*PSNìÌèöÅwcÒhŽÒxèàÒr_ÏÅ¿ÉИ‘źD‹ÔЦ´Ü×ñ™Ä»ùë‘e3§p @ic¶¿}|›7¦šQjÍà-lg9vîÀô#hPy¶÷ÁÕpˆ À– Ïæ æ|ÆÜ>¡H…"5¥Íz<Òßtÿçø åÜ\¡À¡f<§+R¡@5is…›æþŽßáøñ˜G"ZPÆÙ\‘ Eê°ž-¤; Í“c]k¬OîëfÉ} ìEîëNÐ ³€4b'¤; ë Ìj–KÑÀ^ÄÎeïß—ôü7o~V¤B‘¤çdÌÒ2v¦.ø.—EÙÎ-Ý>ÎŽÒ$£TÌñ“ÅÏöÒÚÑfãS³EjJË}=ÉRƒ\ VÍeÌNÚáѸo6Af³EjJË}}Që#S`²ÏšëyýÔ£Z*K³ýíãÛR#—t¬šuಖcç±¢‘ð ÀÖ Ì³½”.F¬Œ6ƒ9ÐäsùIs…³dcfµd eis…ô7Ýÿ9X P*,o®PMýXS‹ bmLÁ‹¨)m®PxÓ¸¹·~ĩ̠Øá]xQF„Þzîh³ÓY›-PÓ!׳Mvmö_8¨CÆNØÑ}²0¹¯›%÷5°¹¯8A0`ÌÒˆFì€4b'¤; Ø iÄNH#v@±ÒˆFì€4b'¤; Ø iä ƒã)žVV®½£Ó$*;h‘´éýûïJíêÍ›ŸKíŠi5‰Ë´Hú\ï€4úð7Ï_½ëÿó·o?þ<2(2(5>D?' vžíéÓ¯î|ùò{ü&j6‰¹c­¡Ilg9væ}Þ¶~$p¬vh‘§ô8÷%5¹¹Vø. L=⤧O¿z4¹þßáM„Uk1¤Ò$6µ;Ãßð¼¶ÕE„äCæyAeä`o¿}|»rÿƒÆöåËïG›X£åsT§IloÃëýè8ˆ”7»€Éf·¸‰£»‡·šG|þê]å#’¤l“ˆétjMÙðzçã×ôãÿ÷ÇWÎû~z9®¹Þá—©8„šÄq»—²Ã\!Í‚ƒšs…Š/„ È}Í@ñ&‘tM”í“ûzM¿SbGǺÄ@šÄ5íp硯w‚_o h$÷5´H¢ãK‰ù¬5‰¦ìp½óÐs…ä¾>±j‰Ž·Ha+­ìª5‰ñðÛúci›Ú!÷uwð¹BZäYItÌ@ÍüÄ‹5‰¦ìû:\pqk ±V‹¸2kÁ@kÁÃ!ÉgÇ€&Q“عL‹¤AÒÊ2 IÔ$v.Ó"ès½ÒèwÂßÔÏ}=·ÿ<ÒÊ'÷5söÏ}ÝÍ7‘Á jÔ7^ú`qL‹<œÊ¹¯[sê:"­ìj6‰âg3MbSûç¾<'¾•Í%æœkÝF­®Tl‰ŽëkáD IlmÿÜ×se›m—‘íLîë3Ù"cÁb´Èâ¥ld£&ñøonkä®4‰­íûzQvରԭ&xYeÿuh=Èú6më[ˆ&±©Ýæ Í]ïl¹ÇÙi‚×V*ÑqL#OÝ­+X»(Õ$¶XâX“ØÔþ¹¯ûÿ\8[ºœC©‘ºÁNV¶|W°vÔfbMbkûô;ã§6Þ å‚ÖŸ+ÃSÐ9œ6Ã'›Ú}.»Ão_<+»C*Óï\&÷5}®w@±Ò¬Í}ýxÎäuÓGÙñó{›ÜmS¹¯ec¸²µ¹¯»ùÄ÷ƒÈØORŸÝê“àâÖŽÙê`1„¤µ’ws&³,nàLVÅμ·Øé\“ûZ6¶¶*v®ï œPÇž÷wœ‚.ì;#gé†К}bç\D4~ @û¶Za0±6|J)æ fÏŽ³±OnàLVõ;ÑñþG?läÚã'´L6v€‹“GeÁ‡OŸË®/ ÀÑYÏÒˆFþÎe’n“ ÝX=œ‰ë°JLà¼Ýn]×ýøý×ÛWçܽvç}Ø‘~'žPöòå­ñ)ƒfªggë››_ÜÊ3~ÌzdsoÔÜ„ÿ"/9ïu-&dì?a°õ~/ƒð¹ ±vö8Ë'ç¢EöÔsQyQã§ï~ÝÆùº¬—\V †¿·Wf®´k÷ÓzkÖ/yÝø[Ú¯aÌ‹mÿ•~'´«‘A¹À¨òàAŸi²ÔxëÊ8x—ïXü›H¬| Ÿ;¡isásñ:YÙ: Ýž«^àªd͑ɼ ½²ò÷ƒ–ºŒ:W+v$vBë&ÃçáN£ã õ[$H‡÷P0jv.6Lì„Ø÷²VûWÔ?/ÂÑ%~ <ï%m"e³ÄN8†½ÂçäèkýjÔ”ý’Ÿ‘˜wzæÙ ÂQ$°µHÄ]ù¢È-˜a¿}|{¯dž«QܽèwÂγU÷:ÎUc<­t|ú|_ro‘5ùJÑÙºó>ìH섵^ÿôëâsN8±Ò˜+iÄNH#v@÷¨l"&òÉ|ûâÙÞU¨DìÜJ8òɼyóóÞU¨Ç˜-¤; MÔ˜m8 ìà™Å¨Æû§Ìßá¡=}úÕøÁ/_~oº?ȱÄ\Þv=Î$*v&­ÍØ/2W*c‡‡6ŽˆýÙßúôéWÂç±ÄÎÛíöúfi¡ ¹ÎÉ-ìÄïÃÚ¹BÅßšA~ö‚{nG @~ùò»ðyDá©a/_þØZd\'ü­ÉKrÖ³^†¤w#fül[­¾ÈgQ$Ì ÷øùãåìOÙÖÆÎâoÍ ‡íø³9zz<¡ñ¬~ùæO“óË_Âó†aæÎÅá!ŸC8nÍó ¢Ñ öt ô"æjÎZsnæ í›ÑþXîCµ“—?aÌ7ëpVþöO§Î]¡küå)sgÙÞgxo‡þAúèqê}žØ½£9× MRsÈk.‹ä “WUçÇA¯7;3\‡É±Ê¼d–ãLœýŽ~àU§(`ð9>Óø;<ÔYÿ«uñ *¶6ÂY\@’Çí7¿üeÓðY6+ò8@ÆW¯_<!bNÓáë¼Iøá:Ìý3ûÝÈ“§ïFÌ;_üâ×ÕÂpÉu… †ÏK}6>7ýŽù.·ÿ-ެáÖƒÔ_I;;ú”‘FoM¾#~ðñ#´Ærî—oþTpÌöÁ¸ÎÑ fA.>mq‡yía£ÞáÕ:]êÚ¥âVñ6î~çÉà‘Çßs÷zrPe£æƒð™!ãšë!LŽ`Ç_™&OÂÚ1Ç<²ÅÛ¸¡³rM`Q‘ ]¤/²r'¥êÿä•Ó»ŠÜ‚Ö¿ï%ïXIžÏÚ%=Þ˜-´iñ>Î9- ÃŒûgã9´ýÆ\|Íîó Ž>¹·È)UªÇ3ík®79hëk˜–5vʾûJO¼[øðéóÕr]v½ÖŸ>ßn·˜g^jM¾Fzy³s·8î5ø}ÐïÜŠ”–ñí‹g¯#Bç¥'g ©Nü>ˆ[¹Z¿sï*ìI\lVÞ˜-,;òÚ QíÔ„3‘ûÒ,÷;'§oõš{<¼dTj©p5áqg §[VÚ·;Ãë'Mt^S*\öõ ,Ø@ƒ6³í÷ãï=:åÊ)ƒˆØ_f(° €6m;3ÜRû—Ùáóù«wm†ÞADÔ¹8´ç rÝÎ{ø¼ÿ'pÚ¶÷¨d/í˜W°åë .jœF‹ýλ3õ>]Ô8“Ícçš¾`ËýH.«Ý~g†#Î2àpÖ^ïÌKŸÔBÒ¥Êú1r›hd›ƒ àÄN5f ˆF²­\<¥%À‰‰[¹Úõν«P1[H£ß WôáÓ罫PÌívûñû¯÷®ײ6÷uqÃ%b.™v`‡5ó€N®Àw¿•3° 6ušË /_þ°w¸œµ¹¯Ã²×sOZh|”þ#;ÜB Š”ÇrÎë|`;ÅÖä»ëwRLŽ£Ž7í¨ß[]¬áuV¼ˆñÈÄx0còñȦ6¡Àáò®kÌ\5‚XoîVÅÎÀ`éc¤tòë½ã¥ÇIƒ³Xx8Oÿ 58û6QSàCŸû;~‡ãR—W“°~« DG®>Ï6²û8~Bê9ËõÎㄨìÄì»ÿFŒqÏLÐx›l¿†œÞ>±s÷™;wnq›£ÊœFü¸kà [\J˜ Kãǃ½›ûwÃO€ vˆ“#¢õ«Ñõbäb·ò=Vªùƒ©‘éßw‹W &gà‘¹M1û‰¯ªðÉŽêÅιð³Åé#õŠÔâõÎÉCtú£çÒ§Hm“õ6ï%Dvø¶z,Á’F¬Š‹c›ý'ôo¸ì—ü3#-v¸ñgœþD'c¶ì"0É.<ÿ®”ñõÎÀ(îÜNæ6õÓ¼?IªÞÊâPJBìÌûSj0#¾J1¥æ6…Çi×\…3Qˆƒ tCã§ã†'™'}úÑ×w‡sm(h<4’ñ ¯Î%óç¯Þ­¼R|Ìvp…2µÈؽz'ûºú=*còêâÁµ‰ÉM-\8Ÿë†;sçƒMƒžbL©ñÓÆG¾ ØÜWò¶p¦$‘¾}ñlï*àçÏ-¯ŸÔý}ùòyT¨L¿s+-Ÿ˜Š“ûš•Üp±ˆÀþÆ#½;V‰@ÄK$*v’¥Ì­¿Θ±Ã¼ö7"÷µÓÕHý3AÁ}ú¢bgÆMÙá5zÊÞåÝ~îëqD̘Ù}ûâY÷Âü𮋠œ·Ûíõ­3#‰‡ù;ËöÞI4ã5>yxqê¿ð •…'÷…ûèyË•ÍÃJekcgñÌJ>þ_jÏ‹êä¾áL²¯4m1$&kE5æ %1a@…Ü×wÒ'œ@™y¶eÃgÍ`\-÷õÝ\¶Bà4&ç*Ž7ÄL~l¬T,ò»G¥òøjr_sYgZúêv»í8‹'°^cÞVøþ…¹MuÒìðPòþ΂á³ÎÇ/÷5Wvš¥¯v¿ÙfÐù«y®p^ÚË9×Fh-÷uü­±\8®qç/¯;q¸1¼ J[¡Ô¯ª²;l?÷u8寥Èà¸Â?µ‹'$¦ k#Ä<9§fÍ“j˜}¬²¹¯»ù (X6büKòƤ¼ds{›||P|®` l’¤•­Œ‹´&Ð&]iÚÔ9Çl!Cø"wÆ0Ú ø`ÿóÚ`Ðon?¥NŽ‘+[ œ“ÃTyCbÙ;±sR.Q` ¬ø±¶X-ÛâlµÉÀxdnSÌ~â«Z0|Š‹¤;áoZì L Ÿ1žjÇL>©Çj|0™ë;¡!Õaê,3¾ÞÅÛÉܦðÍZ1以b'0+œ//²H`L8µ›Û¾' ز; ÄIDAT;ú§½+—Pg’íóWïV^C->f;¸B™Zdì^=“}éw‚~4Jºy®_p|óhÿ}/µÎõ “´™Ü4è)Æ”?m|ôà ‚Í=ia~PÙ‡OŸ[^ >©ûûòå+'ÊÆd•1yž>c¶Àþ"‡s·8o·ÛëŸ~­PŽÂ˜-°¿ñHoå „{áU‡bVBæ|ÄN  ǽŠY9Ýï!w<=±.j÷”Ñp\b'\Ñ·/žu/,D·¹˜<*ñ›Ó³;ãÃû;V „º¹áܼMuÖ–"†Ø °J‘&‹Ø PÀdŠÖ¹ež"ÓbÓ,± ŒqøŒO¿Ú/¨Ú>±®(fA€£¸Ýní$àœì}Ž•ºféÚç^ÄN¸¨–×äKÒìÍ6Ù¼Mã'œ{±ž-\QãëÙ&Y¹ží‡OŸo·[Ì3Ûéݲ;ëÙ—¹È»ÀIŸ1[躙™‹÷Ûåí°5syÁ"Kw-½q‘Tb't]ð~öFv¸‘q¶¯Èü_÷çì˜ÿvdÌøí÷#lv§ß w¬ïGö0Þy¼7rÔþ vsWçJ=z´kÆ{ïe“’cCqb'´e.²æ]v]#o87PꑤsMã«”TØˆØ m9ýš¨kž`I#ÄNXö¶ÝwâÏù–9M…ycÈPœØ ‡qˆn妣¾Àɮ̳…=»’k:—Ï_½[ß7m|ëãÒéÞáÒô;!JÁÛÁz¤ãÙ³“ól—9ÍÓïÉ=YÜÔõBì`úO¸T'»;áÄ'Z³Ãð®æ¶.V ¯†PTsˆ1[¨í|S~àjô;¡¶ÀêÀ!ˆ°ƒìQY b'\T³)£¡}r_@s… Ø iÄNH#v@±ÒˆFì€4b'¤; Ø iÄNH#v@±ÒˆFì€4b'¤; Ø iÄNH#v@±ÒˆFì€4X|ÆóWï~ûøvò‘ñ¦M=õîþÇF¼œûáj¾Àx·âa\óñ¦ÀG @¼åØÙŽGÀ®y¸fÅÿ  Ê2f{-ý_Õ~…œL~gÿ?r8Wj}"«ÑÍ×¼›W~ðxd‡/PÃ⵿~eôSbçd$_#Œ9œ+•'|¬È±ÍÉ6Ù3‹|Éñ/*oˆµfÄ om¿3ï”Ýà‰~²6÷Ì­+#{ºV¸CÜÈ«hÙ†s…¹œÖH5ÖÔ0~d€R6Œ-œÐ'‡s7:VÞEÜõ5ÌŸ-|4Ç;ûL6­Ð¦ai}L-òæäU£àGc®À¢åØÙ?/ÇŸ£Ç— Æ•Áù=p¬q_°?vnSàXy/9\ [¼óô=qb-Å¢amH£ßY’ÁR€+; 1[H#v@±ÒˆFì€4b'¤Ùp-øE>}^|η/žU¨ ÄÛ­ß8o·ÛëŸ~­PX¯ýlw]êÅÂØžýήëÞ¿ÿ.°õåËæ6¿ºÅy(˜¥ÂsKÞ¨¦à=zþ–À[ó®>ž“ô¡¬/5ØÔ/^$ëY•`cg×u¿|ó§ÉÇ¿ùå/á‚íœ÷êT)|ê<ñÕæké‹IÞ—÷*Š”škMý®‚™+tNNs5ÍÅ•Aò¾˜]sáed²«çÖç˃ãÚ¿ß¹…Àæ8_æd©ñî¹>:ö·ö6·Ïɲ»øEôÓ”N¾ãÃMîp`5²Ù•Ï0îáM†´ñƒg&畊×Z;„}8vÎtá¦Áécn*ü+~<":¹Ÿ˜«JáêM>’ªlHÿJˆè›{ÛûU¿QÎq±TFå·3wˆ¼˜Q*&i¼¨ c޳çb©˜§Õªp‚Þbÿ{O‹7¾ ¬?Vã¯qÐſ»ñ;ï&kå2LLW }aÏõ{Îë4ÇWc²§•t¬ìj,ö#{Õ‘5Y9Zk®ô>vvSÏJ#oõ+SÊ\å—™“v?w&rÿ땴ØF˜cÝ‘2J‰”v’y¶!Ö¼À¹u¸ÝúÜÔÚÏ…ûë}ü_*éYU+P¼àÿä £"{.N|åÊöïw.ÞÇ™jÜʼn9ûJÅŒæMžDsA&÷™7rX³TÞÃÇš{£k89¥¥‘w# æ¸k^©šïÑ“½¾>}¾Ýn1Ïüñû¯·® [Ûekeç{E—z±0¶Û˜mä"ï'Gq©Xr© c»õ;¹c€Àiˆæ$ól ±ÒˆFì€4b'¤Ùs]¡Ÿ>/>'ò6P¨f·~gLà¼Ýn¯úµBe ÞÎëÙ¾ÿ]`ëË—?ÌmZL(½^‘UÇä><®C/;·Ýâ·1_½˜%ýöÂþkÁÿòÍŸ&_\#þ_Å«D#Úl±1Â_½@òQ8 s…€bÉG›&ÿ†#Ú¿ß¹…¹¥S¿ˆÇ›¥ÂÙ³Ùĺޙbr‡1¹¸Çûœ,;)o‡ÓÜd=óªùö63™§V#P*»dkðÌÁžôÎo½áR&“rÃõÿ¿òp°£ÇÎÀ!0¦49¾4ùødññ#ƒâ“›5¯Þä#cy;Çû¹w#²ã§ßñ¦@‘ìj”m‹oïäqçÞäðó*á/yüLc³\Ðcgà´X*æiu~¿,´ÑÒß`'íŸFk6€AOkåÞº+_*ï«×~OÀq8vÞM~24×óØk‡]ºxy¯«f©<áceD‹â•ßèÝ8ôWV:|ì삃cGö¨×‚¹SêšàTv‡>”À5¼ñ?Wk áfô;‹^Û5€ñK[|ç[h°ÞIæÙ†›Úì¸ì>T»‘øË„ý¿ûøöñß^U*Rj¼“Á¥åM·roy¥Ìúášöïw.ÞÇ™j܉ùnJ÷0>ÅOžôÓ)û=ãntªš;ÉFÎÐ)»Ã¼Rã‚ýë oo‘ʯoñ¥ºü”²ÉG¥Š¿äø·W„xOöê¬|øôùv»Å<óÇï¿Þº2‘×÷ÍžL °—ÝÆl#y8hÍžc¶â"ÝŠña€½ì6f u’y¶PØ iÄNH#v@±ÒˆFì€4b'¤; Ø iÄNH#v@±ÒˆFì€4b'¤; Ø iÄNH#v@±ÒüÛ {¯üÀ‡IEND®B`‚stella-3.9.3/docs/graphics/circuit.png0000644000175000001440000001441211433323254017301 0ustar stephenusers‰PNG  IHDRoy;РgAMA± üasRGB®ÎéPLTEÿÿÿ´´´ØØØoooÿÿÿ¾ØÚatRNS@æØfbKGDˆH pHYsaa¨?§itIMEÒ -2.hOTIDATxÚío‚£*ÓÅŸ-”R p&.À¹²ùþ"œýoåý€À˜Ž&ÑŽ ~˜ÛIwOßþ PU‡âð?¤ç‘çÿþ—$p \—À¥ç68ÃÝ…XEçÙï!Pð‚è’Àu,„a†ˆÊ×-pâêoøVpþÃ"³ŠïƒCK PSæH(Ò€*á.P¤AIGÂä‘ðàjÊ@• 80¹ÿ¶/GD'D Àe "v$ ET‚@ ¢ÒZ‚"* }38'PènªáTV ‚ ­ò_§û5Ž´b#¾yª:"ÀIÿ&ùE/üƒº¯ë£*Á°á®WÂ]îƒëÃÉ—ƒø';p*³ŠýT™SõŸ ÀiõÍàˆèBD%ÁPÙåqŽHtÌ2ÃPD²þëzpŠHößöàtMŽ4Egøt†¡„aÄéÈΑ€áîÛR­:yl*PS‘ŸÀ%p \—ž.Kà¸.=›€38zÇù?›è9'pwÁU¾ Íîp'Jà–ƒ;S6€S ÜrpBeøN·\§¸À1,'pC·\ ËÈÐ&pëÀ9!+ JÁauÉu"!!Æt$[óÕ|=¸.Kà ŽHÈ£m,+]¸aŒÕzö…ï™N#îöäœ'T÷3¸”€Ó.ƒ0ußÈÕæ>‘Kànƒ3.wÚ±67—±äB‘ÀÝgJËmnǦ«MkÜ]p#+ §Í˜‘XuIàî¬q`4©Ê\•§<î¸ÆHËP™SÀ‰”ßËãØq­QåNàÚ<»W9JHnCpŽˆ¸'ž.Kà¸Ãƒ3C•u¥”$Yi¸|¬¸*¿o“FÜ"pTŠJropNœn3(¨Ýe%Û\ ¨¤xœoÕŸ÷³¬´v®NÀÕÍVOy\KDìŽsþ0¸hõ2o¥º|œþåWœÐ¯§ä²Zõ$ ®ºØ vö~»åà´©t=î’å°r ¸V\KTÎì©®ÇFÈ^[/K€WVù¿ îµêLp›Ò¹ -›ª'|58?âÐ=ŠÙ"YÉ• ›¨fã%²Ò³•ÃÇŒ¸^[òÁá>¸g+‡íÀ~LëúÜõUàm €Z$+5qEÜuÉhE÷lj±^ÎéH½(ªÚËqÀ‰¸&å^ ‹Á9®W€{XVZ«+ý"¸Þõ3Ç0ŽÒŽ4¼A¨)½Ûåæ½#ª†8—u{. %xƒÐÞÐlspª¬˜Àe¨à B÷w Ê¡sý ¦j3€cßò ¸6Ç•Š|¯[é5•Ã.²R•O¢™g×SDAEn—µë?¹ç ±Õ3U1*0Øo‘ ¸²]U aÄ®î«#/ªv7ÝdX‚° 9r(ÛtàÚ¼ZN(døÏ²ÀâE•Ã.àÜä!]PÐ ¤I;ºô«›òg1'À‚2ü³ø»Kå°ÏTýá‘O”\Eé8(óM¹\[~¸gjÕ-Û<ªÅ¢tä4úÛÀÝìgˆ`k6[Ά!çÌåGœïNRãšeç½Î'éÒŸ [©º<›mí*+Áv‡ ù9pBV%ª,P –Œ¸ú_ùÌTÅž#®šœ×jc=nâx°x+†sa]lÐKÀ…—Ã[ƒë]?ƒÙµ^OZî‰"4÷‹àz×Ï1Áÿ“£NkKBŽzÒîàùÞà®:]”pº]i„W2ì Îj¼;8•Oj%+2°‘Vþ¸e:Éh³”D¡ÁNüÅëÁ->·H™ûÜ¿?/{äÜÏÖ8o×Ph0NTFÚuàj" À .ܬ‰âùÓéÈyKpŽcpFñÍø?´ž´•­€þ(Ü8š°ì^°­ÿ38½åTí]?‡ Z¢Íœ.$eèIKÁ9 i”öèðË?rÜåÁõ®ŸCP ”tšwõR‘·×}p%ÐJSåÜ0\›õ–ݵ|kp/®UÓ’7,ë¯%pO¯qDZÒþ¸/ùìÊÓƒ/ˆªÇql`²Ü¢¦›W‡çJÀ²AKU´Æñl›×í6ñËë¶öÎ/7++Eø¬"xî^ã»àZ@)˜`¡jd­W¸úe#Îm4â\¤†˜ …ißusµÏy?kJ«ØEyÜú¸ywpOÒ‘6‡]»Òy58Gâ6@KQå°ºV]´Éú›à:×Ïðßù/r’Üi5¸Wù‹‹ü&8ò/¸ðÓ^þ}-‚.o ®Áœ!;ñûà´Êý"8›Çàrø®*··Ü[ée•ƒÛF™tKŸá»nŠ|ù¤-¦ã>3Ö¸×Uv+=.ú5 'Ø÷Ê-¤-1¸ 1»‘+e¥T8wFM`€Œš—jùœ÷3Ø÷dïºç°+8(:ŸÀ@Áþ^ãEàÀVQ9xRq—ïfcq¾ܲ.êƒ×ªŒšÝÅ1”$(IàΓ*P—›µš½`_õíÁQÙÊ®Ù:C¶ £#p5­•Η ¹Ã8'ѵw-¿Ñ~ÆJé¼½è¯çÄ9× <ØèØ‹_îVXvÓŸ·Š¿\V³²{“O*îÎ žÇ"+ýÞ³ Üù¥àz×Ïgd¥ƒ€Ó/ª½ëçTV²+d¥¯×»~Þ•d·a­šÀ%p \÷à9§¸ÙWOvd&‡àâ,/_v®ŸAQ‘oIàâ—ëçðLÁµMwÜ4†€Ó…ìÁM¶]¸á%M¦êä\w \ËJÓCpÇ÷gëçZéÛÁ‡Ø09wpö7ÀåqÂa4c<wpø©ªbYiz.»gqP‚Kà>¸VMà¸.[(+Ý´ìÖiÄE/Û ©–Ý}²—À/+›µìîÕ¥.xm:ó¼e·m¸éËØ%¶ìþ¯·ìîóàn|iÊIp˜³ìNà®_Fñ·,»ßÜùÏNÏŒ:‚ skÜ1ÀýûEp6Ÿ7µì~SpøÅ©êxÎ:ËnÙ$p·ÀM.è,»›©ew÷Qµj—À%p Ü:Y© yuè&¸èåd³‘¨ôÕå" \ô2»¾ÜiÀñ4ÃKàâ—ùÕé8íoˆÓ Üàš‰e·Œ¢…Là~ª&kœ̥͠®§p¸I›—þ*)¸Ÿ×¸°é¦%"``Îy÷8žt‡ *8¡¸Ÿ§jl„i€êb3X*¸5 °Z¢ Tr¥Z5Kà¸ï—d¥×8wmK˜d¥ey\’•¬®d%£ïÈJD$ú‹‡tÏ*šw ¥0%¤kÿóÃÖªÕ•:rOV""Ò8à QXlÐMpÃÒ`øÐS5¾Ð 0úެD'ÿ®Èlx¶õ8´ôà:×Ϩäº'+`Ø0TÖ€ *i@•p(Ò ‚¤#aráHxp5e JHT)Ò›²ût+EkÜ2Y‰`•6ìˆDÄDÚÛCÂe "v$ ET‚@ ¢ÒZ‚›¶çö×»~®’•ˆHHÃF8•îçæðF€´bÈ št¿Æù·õVSÕí2U;×ÏU²Qiذ%ŸµÝˆ3 ÿVô9"Ò4DÕñsWMæËY‰¥ ”<¸îrœÿãÀ=R«öà2€S™UÝì™SõŸ Àù·¿œ0l¨ìò8G$:f™aï•K KDå®{ÛPù…àrÃV Α è ŸŽÀ0”0Œ8Àuo»­¢êd%ú!›úµ¢tps²Rücn‚›çrGïXÍï4â* iÝ8×E®¹)ã{Àp\àfÁUÚ‹LñT-6Z¤ŽN¦L[xþ\!Á‡Ñãvšª&ºÓ=>'ÇCpm÷#¸›‡à*Àý<âæÁÕÞ„äqpþ·icÑáï¦àþm++ÀŒKŒþú”\o¹\x r^æŸÓ¦àΛƒse«ãà0=×ï?< îDs³Èm No>UÛ¼ÁY‚°ÓCpýþÃãàÔ'‚ƒ¼¹»Cp§É!8å…á•àÎA'”ù8p·y¿VýœÚd¿ ž——¤&p+Àq°Ð%p_ 4þ¥W–Ý+a92.ý¼W!òåžXv·±>·œ²Ò‘UîÇ;QìË=±ìîõ¤•àp"!§w~}8ûrO,»{=i-¸ÓýÓààWTVÀéƒew›À-weÙ]én¸+Ëî:º)éYp»ÊJÝok·SG‚_qjÙÝg' ÁÍÜHõ¸rpnpFñ-»'ý¬÷ÀÍÜæŸÂoˆýÆTu»LÕ©e÷¤Ÿõ>8Ì6[õÙখݽž´Ü JÀi—Aø2À÷b¸—Öª —;íØ›÷;d~²&pwÀ™Ò²ÍMã¸ß!ë&kwÀÈŠÂé`÷̪Kwg3£iLUàªGw¿[É*¾Ÿ÷¡kBhŒ´Œ"s*ܯÀ§¸¸[Éd(4H{²Ö«ÁÕìr§ar'pýºw"ÀŒÚ‘ÚBtîy%8"á÷Ì ·!8GDŸNEÚQà/r’ØäòíK€Ã6/\øˆÉ¹î \°“oˆÀNxp&ûܨåð]7TnîWÔ‘íÀÚѾë¦È_ãÚÅøó*¿ýðz܆àí¨ Àp‚}¯Ü3àò±pÈ>R ´#wFM`€xN\[nlÀnõç©#&ÖŽO` `Ìtã/WSæ¨7e½1bªUï‚k¤’a˿ʸ%àl£CpV%pKÀµDK ð2pŽ£ààx\³åSî)+½¢[Éx9¤-GpV`ÿà€Íe%X­Lº•lä²"8©$cp’(èòaàNTå +]u+ŸZ Žˆà(czJî“À)àn¬ÆÝJ'<Ñ­„«ìOšª>]>sÕ­©À‡RGvçÆ*Ú­ä¢æ‘n:âÂj<êVŠëÕCÉJóàìK›nÆ„kÒ­„•k]z9Nsôî²Ò|ø…àÔø[N»•ÔJp '†ÃïõÁù ¦ª{áT­ôpfÚ­|j!¸Áä*W|"¸vÜyžv+µ´®#“mU¦‘Q6Z²ØìãÀ½¶VeØì¸bTA§§Nàî 6¥eä0#¸ Ü×f`ô–ÝL͸»kœ˜ç:ë¡me¥r3p7e%MµçÀ5`#m ®°ÛŽ8½ëˆ«ú`ÚOµ9o¥^]Z8âÜÅypùç‚;xóò¼·’éÔ¥%à”ä–2.¾N¨Šܵ·RµÞJü Eþ¾SÕh‚=äÞJ^]Zn"~,8§Mf½•:ui!¸–Dù à*iâ¨xí­´nÄý’¬tþ³ÕsK›xÞ[©?}>ÎŒw ÀÓäŸJù4g[YéßÞà¢>™Yo%õcp0®Ìœ€û7{LÕÝÕ‘ܬ·R¯.Ý7ô¼ÆàÆÃþâÓÁÝðVj»¹|œAMj*PSѽ ûw¾ßQ«Ê¥%—Uh¤‚’% T2LçŠ2ù3Á!Ã_d¨|c¹kóìÁ•¾±}¸“üpÐ6Ô…cÓöbÁ¤Ê_®ý«¿œjŠÜP8tÿµÚز]¶éa:¿TVºzVÝgýyŽÊç0m޶ Á Y­[ãÚóF#¯q•¿ú-üIko‚3Y…FI0“àP¬ŽªÿðÞàN¸øýÕ7Á¦àšÔÔÀÀu¶Jüp­z~wpêÊ#ãîMp/Ï^Twì1jì\rÜàZ‰#€Óm‚»wÜ#®9¸vì[XtܲR{9¸±X]vܽǷê/÷“¬äÊ÷W'z—Üwï™V¯÷Vz8<쮺Øp»{Üà”\_äë·×RUïÞ·œ6•®G̾1v¸º|op/¨UçÀ±²×–ä«+‡öÝK® ÀØ”6H¢iíTµï^9l7âÐ(ÙZ=î‰;2ÎÅbÜ*poV9L¤©­G\¯-ùà°nĽWåðô³ Ü -P«õ¸Ëƒ Ò‘zuT­õ÷{E‘ÿ^•áÀÙ¿ ÜCà®ò?ÜŠn¥·ªv׿£(ßçÂËe¥÷ªö§ˆ."2ªÖùïU9ì® Êïë\ Þ¬rØ\!ƒ=m¿d¥Êá^,(ƒÑÁž¶)×ûÖÊAÈ¢t”ùÅ¢tä¿Ù¿œ-Ѳ̓=íl 8wÛ\¾ \Ñyþ2ÄTí¼e÷U‹ÒøaõçEýHÇq–¡Æ¾›´÷FÜÃoתˋþŸNȪD\¯ª—€³Í˜…œÊoçÛº ¯¬Uíü?C‘ß {Ü3åÂWƒ³—ZëïWiLx6îFâv5ÂNòkÁQÙ áOtY5ò\´Yc›oç(¤QÚ…äï¥^ç¶üVp%ÐJSåÜ óBà æê1À ¦%n<¯* ™[D‡ƒ€ˆØ@iÓÝùîŸjÑ·I>r Ç&‹Á5‹Ú¼¾¸rp%`Ù ¥j²Æ-8w®wpð~Sp-Ž  ”7æèÞÏ—´y=±%¸<é~×<®)­bTåq¬õý©êô÷‚s$þh´UnY\˯÷T­ºIxøpVŸ nÃÊá£ÁmY9¼¸à[otó1c¬´iåð~à‚ lcpÅxÔ¿‘KÔ‘M+‡w7Ôò185ÊkìÏ'þæžÃ;‚[Eå`­Än™ç‡ó%à¶ÝsxË©ê}X{k%x4»j]höe••­ì¬!3TàÎZ)WÓ"øÏ·MUà¤xpâ®å—Ëm—(Àm#¿ œçœã0"øÕ«Vu+ý®™ÒnàŒì¬!sTàîøÛylvÉuïŽ4>ó¹ ®¬y°Vâîø[ñßÇUÉ=p¿«6þ¸–2Bo­ÄŠä®7¤ßpùùŒ"?Kà¸îÈàît+%péIà^îÿ}S „M¹äSIEND®B`‚stella-3.9.3/docs/graphics/debugger_tiaoutcmenu.png0000644000175000001440000000550312205116016022033 0ustar stephenusers‰PNG  IHDRBÓ{‚™sBITÛáOà pHYsaa¨?§i æIDATxœíÝ¿‹EÇñ‰XX…@¬›‚;›´I“B ¹J‘| ±–`qÅ!ኀ 1Bš4Ц2‚…p\eá Á2XX¬.s»;s³³óãû}¿Š°ÙŸ³{ûyfvöÙ}N íîîöÃχ/¶¹s9Caêûéöǵ‹Ð”ûw_ꇯïüÙ±‡í©s½ùÁK‹Ø„›g_쇟«XIc@½j N\ãáˆ12²¯„‘1FjŸÞ^?ÜL¼ÿÊ]ëéˆCŒ‘Ýñè"=º¸ÝõÃqµŒ„¨‘µqnÄÙÙU1‘Î##B[1FjŸ~ÚŽ¿€y ÷“¡‹ Pêc@=®‘ýj¾ž™1FF„¶ bŒÄxž©<®õˆ1 1Ô#Æ€zÄPêc@=ÿA^Í¡1nœ`× îº ³^Äxux”¿=\¯/¸kµñêP·‡ÚPÚ¸uÖ›±îÿ?jzNžLR‹ÚxE®ïüÙ?EhC;b ¨GŒõ¸6^ÚÒí!Æ+›±ZEŒ[ǯ ¯1^¾þѺ¸V‡/c¶‡Úxu¨ÛCŒW‡_n1^BÛ*bÜ:~mxèâÔ#Æ€zÄPkãÕá׆ÛCŒW„жŠ7Žç™Ö€kc@=b ¨GŒõˆ1 1Ô#Æ€zÄPêc@=b ¨GŒõˆ1 1Ô#Æ€z<¨¨À·ÛýÁ˜›{›*%LÄX(¢‹pÄX(;´ãH6b,Úï§?1Æœ¿cŒ1æô'ƘWÿ¾UµDèTø¬›;—s”`ÿ½wwws¬Èíàà S.NtóìÅ~¸~O5†RGGG—.]ª] cä4ªoÝz¿v€y®]û¨vþS¿6°1Ô#Æ€zR®;gμ6ùôéoƒì1ƒgMj•—]ÇzÉŠ±9éôrMíÆ{>&'ù9óšÒsÝ¿ËJw 4ªõÄÕÆÅšÇý†&·8¨å ãY*bR×R°§Î-Æ`~ÿ ãvň‹±çÔŒnÏÕohòJ{2þz–ò¯Ð3i°`à%€çºV·Ë(I\ŒWr~xv3ð$?P+9òMã& Ú«&¶)^‹bÀ…’ª)ž¾d¨¨…£§:ÈÂüÌZÜ53U"\4ÕÆƒäÉ®ÔY“üì–°ÝçÑ<ö,>i<§KÚ£}E€bê?oüì×s†'œ P÷„Óù:MZYÏXˆêc@=b ¨GŒõˆ1 ž¸ûÆÅnQ–ü~¦mñtdÅxÉÃ4+|ì&nWx šG£POVm<ø ý` ¼¶™|¼Ù~Ô6¼þIãíÚOóF<¯ñ€% ’ÉŠñäט;žö¶ç)?׃ò}1&ƒ÷”¿=ÒŒñ¼~Ä ¢„“c3ª:²žpq¯ï‹æÚ#^€…ÄŸ7®:*>©çièÚü“H2‘cÿ¹.$®bøŸò7ÔTÚ쩞û\n™2<}ú[æÁ¤Š­ ^EÐYµqÜãõãÂßJ7÷±ËŸò_,¸Šáßå´¯C€j²bl–½2rÖIiwÞ¦*Æø“ŵˆkÎåÅéB#½i³Q ¬ 1Ô#ƕѾÅrÄPêc@=q7œx³yqßã{fJÉŠ1¯ H%äÉYKA2Õ€z²jã±|¯ ð|SÒ³­bÌz bùk<“\jø_‡àzFz¼-áQŒ¬—|m€gýžm>Ê?«H¯ ˆ{£€¿T®¥üÛr%ÉŠ±)ûÚ€^Ý“/ɦk•ŸÐJ .ƽb¯ ÐXœø¼VEVŒË¿6@c†;Ñ]úhO›=ÕᯠpêG´2R5Lxm@dÕÆ%_ÐÍ<¹Î%Åܺ«äÛZòF×r-E^>Y16Å_°Kòœõí3Þe$Ôf£Xb ¨'¥Q½}x¡vêx÷›V»ïú½^»ÿ¡6Ô#Æ€zÄPOʵqgïê“ñÈ|—ŽýæÒnµÚn|¦ÝÙ»ú$bÍ!KÅ­¹°LJ-dŸÿ”9uºML~vD³K>Ø‹užaeäøS*B£POVmì7ø¬µ+7{Òöá…A•èš·­p“%·´=cÂw9°Hž¥ü»<¹à ðãÿÚ‹,?òq×R}y&ÿ4IN€bÔÄØsº{N&ÿy±­h®VßøCÇseáÙå2x–:ñÓdîaL~äãþ(ž¥º#oÁN~dE£:™½«OºÓ¢ÔŸOÑçJî¥*žÁ¹7¸~É6ŠjãÂ":K\äËN.X²ÏfµýC½þø÷¬ãI2µãÁAtÇ]Cþ³u'¹d1Òn+úÈ ¡«QÝBŒ=‡XøÑï ®ÖânÿÆm7|ι¥Juä«üUœ6¶Sá³nî\ÎQ‚g¿ž3Æ<»ðµ=2¤…د˜|’Ÿë 8±¿tr qóþâ¹–ò—ÐUµF¬0¼„žm¥šä©\KõþøêucÌù:L7Ï^쇅Æx–äÝ›Xn G^NŒé©ÔkáÚØÓ¯¨®Ë±ù’D4ªŽŽr¬(€Fµ1ÆÔ.éñãǵ‹`Œ„Ú¸ºŸn\»˜á;¨]dÕÆ"Æ€zĸYß?ÚÿþÑ~íR b ¨GŒõZøúì¶t7üö•M½â ;n89i¼å¿Öfn,ùÙ7œ¨Ò›EÍÜ*bìäª 4ÖÒ’Që.GWƒÞ¾²é«\{­¢6žMr-íJl7¾îmdjÝ|ˆq#Bª\ªåVÑS]ùZz\ë– 0µnôT7ËÕl¦ºmÄ8»ò×Òö•p¾«bj]9DÄxÿ½Oœ‡&}»¾u £=Õb]×üD°ñÜ膬‡HEc|xx˜|?˜|€.ÕÕvüv/~=ÀŒûÆäøåÁgýðŒÚxoo/CaÄù«qà ÒܸñÃäø{÷ÞJ2?ҚѨ¦6^ƒ.ãøÙAµ§ÎTÞx™ÚDN#bŒP¯ÊÇkõˆ1NpïÞ[}%|ãÆ®Þ,TDŒq AÕˆžjLà†“|vO51T²cL£PN•m·ÛÚE(„Ö\>ÄXû·ƒãÔïÖŸoÍ×!Õ€zĸqÛí–ʰy4ªÅIÕÜu¥w¼þTÍøþy§Þ¯ù«CŒ›ÕÒ_ç¾GÄXœðZ4ÕVâÖ<.g7®“Q1jyhí˜Ù½Óik`{ ›ÍÏ ×†8ĸY!×À㕦µFÄX¨´u¦kmËïîÚKm64§ë ÆBåè¯ö×Ïqޝ“FuĸYáõ9 i툱P˯ZÃçç¶“vÄXœ’AZ²-/1¡ïK߉ïjc…ˆqeÔiXŽG#õ¨³àÝT(‰'æÿñ×Ôå[ 7÷µxák@-Ä8±Ü§øøƒÀõ‘áÿ&×x"ª1Î.UHìõØAõ¯ß_ÿ‡üš=Õµ]×ë‡ù2& 1Ô#Æ€zÄPêc@=b ¨GŒõNÙ7‘hDm ¨÷/ð+ÕÃ÷IEND®B`‚stella-3.9.3/docs/graphics/options_debugger.png0000644000175000001440000001142512206650651021202 0ustar stephenusers‰PNG  IHDRWI¤–ÇbKGDÿÿÿ ½§“ pHYsaa¨?§itIMEÝ 7 ßùAtEXtCommentCreated with GIMPW}IDATxÚíݽ®Ý¶¶†a­`•)Àá2»Ò¸ àÖF®ÀÕ™‘ÊMJq ½Û4Aj8»H$Àiu²ï`"Q Ëú!%R"¥ç\ÌiNŠü48¤EÞýöËwoß½oixñôQsw»Ý˜ÒжmÓ4MsßWZÀ6^ý¥­Í'Lé!®{&¨ AÚ "W ¶GM‘ë«~e­xóò‰(ª@a5Ê™UG®é8ØÞ˜ NÛGå\kºkp$ˆ¢Ì‡â#Wq€ºÒ¨¯ž¿þè»ß~ùnu=k~ ˆ\O걉]ºÕÖæP~û廄ñ¬}<ãq8VS>zfß%®¨Fd l«c&-€§†åúeÆRsßÍ]om™©k÷ËÖ˜ÚXVéâ=©C&lè$J! gœÔS6þêùëÚR&æZ±ãÓæÎþÃñˆms «®Íci‚‘ ñýTùy’èr)r‚ŽÕÓŸ`Kך+RÏ”(XÖŸéYíŸòÕÐZŠù ¦b'Í“¬?©k_zjóµæŠ¨õ„i“ºŽ›Ó–%î\º$¤ Øfs¶;¹¸Æ<츢íeó-år\íµ½‹î¯5æž‰ë …æ “:6RœêÏ\™©zb¯•ª òܬjóâ4â:÷rËd'ä”TeD®‘tûpöÿm©çŠŒõ}ʱvZc×+Å™|*´ÌܱکÊ׿Y“Çqöyý‚Žúx˜»a›»©Ê×DØüöµ±4¶¤Býh8—¶;Ïa9×¹ƒ çÊÃúÝÜõÖ–™ºvîœSè(K7µîb®)×v,w+ÏØŠ¹™÷W9ÆøÀÈuénº”>)s­%Q -3Öž©ÓK·Dís¢sÒêTù±>OÕ»u,PÄ+ŸšX\½;·>rµeûœ#?)æj¨°ØiÜwÇïèÀ•"Vd×\ï¹î1€cÇ4ý¾TfÏ6 #”-suIXûó¤ÿ\aêXô©2Äuç;a®Aˆyq:öÚ{8ÎðáXéÑ‹Z寴枌ýfJ<§ÆØC¯¿ot©·\ûÀ°\ÈÓûÐr!mJ]f«Cuwþ¹Ï©ì³$Œ¡oel×nW,·ÄÓmÜòýþã/*wdnËÁÓïç" 1⼎J\‰ëYÄ5èmƒT²5W‹áôû¹Ž=¬F¤!e°mÛ6í§_$©ëG{œ¢tq­ý舑$¤Çóâ飿UËkyóò‰c^jŒ\ûƒÖ½¨ì³Ï©?wÁñŸ›^Þ¤hBh>fó-@Ä2àôW·ÌÂ:¤öD®aMLÛ¶ÿäú rFIõZQ׬ü¯¹žy§Wä Ä -`šËœ“v¸†n'ZÏ&õ\[mi÷¯ëù]3ëX_©Ò©»î5ÞõßÐç6ÈŽÙTžd×aÔʸÇá0@ÄÎS«•Ó©ÓsùÐåóÚ“BÊL]{œSìI ¡9´©ò!cåÈÇ•+°!G¯¿B"×¥¥ÃRú ¤L̵–D1´ÌX{¦N-XµwŽ>wÆÑR{bÎ%›ê{ÈXŒýÞÄ«;50wÓµ"-T\¯´ÌÚ"2C1;[š‚ø–+¬!âI` M Ô:(¥µ™cÄuòΗ;J.­‡× )³g›÷´aLßqî•Vÿµ©±¼kª2H$®¡ÆÍ5k^IÝ·£–vG÷!ÇÑÚØ/™Ê»§(ƒ â)N šCc¯Uã…!í y‚Ÿº_&Vý»WT~ÌKÈëZ©ÿ"êlö)‰nËA»bÅÓíŠõÆ9Z»û¬c^@äº.E1µlIµ'ÂYíSZ€õˆ\ˉ\«ßKŽè<}ñôQóжÖ“`ËA r®@\€¸qW ®@\Ĉ+Wqâ Ä@\€¸qW ®@\Ĉ+Wq€¸ÏYùÛwïY@±¼xú¨¾È•°(™¶m›W?üZgäÚ4Móõ?Eå‰ë§_d­_Έ+W ®€tÜ—Ú°o~ÿó£ï~þòóâ Úµ;e[sÔYKßSùP ¾“cÞŒõ;¤ ;Ÿ4ríOÒîß”à†Ö·ö·¨[d¶úNmôçË–2¥Ú¹¦¹|_“Óh§¾Ò¤†ÿ¿fÙ:õ›¥;öÜrìç/?Ÿ]J…Þ™§êms.;‡,Ecú¾U´ç~2KãµÕ†s㽇}ö¸¹nµsй,-0pºþ¿ØÔÁpù“r9´e©õÍïN¶yª_G-ÇÖØyÎ>¡}J‘Úº¤~¿¶=¡ýúêT™½ì³wŠfn^ì9—O-®¥:Qª|Oª]=söÉ‘£ÚêØ¹£Ž±›ÕË¥hw â°·Ï–Vº¯½Tå¿É ôÚ‰"¬[Ç´¿¼,a¦´aIþ^š‰ëŽyä±q'ks·!)6 ³ŸàBZ`—åwÈï¶Ô]ŠC—VK°¶´9UZaËôöµá‘þ|¦›J;—n×ûRdi³Ô–ر¥OH±Ö‰¦úÓ§Ð6§‹˜¾§Ó~¶×u–|u‹o„ŒÅÞOÞSÚy¯1KÁÝív{hšô›Ævû¹Úr@‰üø÷–ƒo^>Ù¤smÛ~PG·G¬½ Ĉ+W¸,YßhÛ6û95p©È5瑵‚-o ¹æl8\2râ ®P:Ys®ÝŸÀ@‰ä|ðž-r%¬J¦mÛö¨.rm·(T\3¿ƒ/ç Ĉ+W@:Š8æ¥Öcvs5QËiš¥µsxÆýY:+ÍXˆ\'£–ûÑê¡^Ñ1þ׋’ç{±ÖÀ•ïÊŽ47¨P\פRœhºì 9ųÿ›¹eRè]wªŽÔKÅX;‡œðÓ÷­B1÷ûqX¯XÛmé{È1ñ1~¸ÔךÆbïl«L ô«ÿ/6uÐÿ~ìsê6‡ÖýÍïN¶yª_G-µÖØyÎ>¡}J‘Úº\:‚|M{†~:î±¾‘ÒÇ—Ú|Dê`nîì9ß«שÉxt%U.gë€qÎ>9òO[6wD1&H[l8,gÉ}ÜXÔnûûZynrc½ÖÉC„uë˜ö—޵MƳùsÍcqyq5`ûÛ¸Ûµ¹Û[ãŒñ*Öš;xÈï¶Ô]Jt1\6-=ÀÚÒæTi…-ÓrØ;Ô†5΃Zo(9Æ¢4Þ—`쥥hÌruX6fÐÆ–5sO[·ŠÉT¿búÚæTcÓ÷TcšÃÏr ë\ý[|~ξsþ":{ÝlRŽÅÞãÃÝív{hšô›Ævû¹Úr@‰üø÷–ƒ[R}ûî}Ó¶íut{ÄÚ[2@\€¸q€Ë’õm¶m³ŸS—Š\sY )Øò¦À¡‘kΆÀ%#W ®â ¥“5çÚý ,”HÎïÙ"W  dÚ¶ýg€ê"צ±q €BÅ5ó;ør®@\€¸q¤£Ø k=j7Çqµœ¨YZ;‡çÜ—âËg;˜°;‹\#'iÿìø£ÞC}~«ï¤ ïÃì¼ýzµÌåjŽÖ®Å9  *q]“:HqJëÒQÖSwì¹ÓPû'¶ÎÕ½v9Úæ\v9 6¦ï[E{î÷!ã°4^{ûóZÿ™³ÒíœêÄå˧ú‚Õÿ›:.Çr.Ïbêþæ÷?'Û<Õ¯£–ckì¥Hm]ÒNUž«=c6›¹ö m¸$Ò%Ø9d^ì9—O-®!ŽvT¤œ¢ [bè¬söÉ‘£ÚêØ¹£Ž1±ÙbÃa¹&u íImç³¥•îkï€Uù'ñ˜@¯!ºuLûËËš&ìÞ¾|U;×¢@ÄÛ¸Ûµ¹ÛÂÕ³Íñ»NÙÓܹ`Z`íR6äw[ê.%Z.­–`misª´Â–‡i9ìjÚE:ö9@mv.ýµ¬"#×¥hÌruX6f`Ç–>!QÆZ'šêWLŸBÛœj,búžjLsøÙ^oÌYª¥úYí¼×˜¥àîv»=4MúMc»ý\m9”‘^øÿÞrpËAªoß½oÚ¶ý ŽnX{ ÀUÒò¥@\¬X´Ô¹¶m›ýœ¸TäšóÈZHÁ–7\s6.¹qW ®@\Ĉ+Wqâ Äý\OJwÌpe†G°W$áûïÿ‡piž=ûVZÎqâ Ä.KÔ­¯ž¿žü¿ß~ù®ØN޵;G{‡×)Ñ&Ÿ}ö¯æ¿ÿý¿Ñïû¬-Ú†áïǾ+Ín)ú>V_©}ÆŽâz„ht‚µöšc¿ÿêùëæ«ç¯?ªs뵺ßÍÝ„Jˆ1í>E$¶ÌYIÙ÷þä³Ïþ5yÃK=îD¼q­’£ì+‘[TÀŸN)®ýèm.Bœ*7Œþ¶F•1Ëù©h7ä»”iŠ9^eBÌ-Ÿ‡àš(|jÙ¿W¤—«ïc}:s;·*;ŠOÖŠQ÷/d)>Wî·_¾-×ÿ~ìóš¥úT»S]+6M1Õ÷=–†%,í—Ú²Ôæá÷Kå–Êôÿm£ÐñêÄd¬\ÿû±ÏgÖ¹e5‘ëœð …µ‹NÇrœ{Ecc‘óX{–êèÿ.g$Ó>¥åK‡‘×”¸,å'ûåj‚¥‡‹!}—V)×þüõ Žzè5%f% ì‘ÑÏ}%ŒùÆ®Û׃Ø3‡^urÎå+QväZâ«mŸä.2K¹|žËó¦üÍÔï†}K%Sm\Êm_a©×Pq•h/gß»›êYmvú·úùÉ­"´µ®áïç"Ç­× yë ¦=G.­B¢¹Ü‚×°·^gî·Ã묵OÉ}OUW [ w·Ûí¡išæÅÓGÖZú«Qoß½·å .ϳgßfÝÏõí»÷íûê‡_ó¤Î.ªqL/Ôµ8o D ,ˆ\@äŠÔy~@\qJ^<}Ô4OŸ0 -Ä@\€¸qW ®@\Ĉ+Wqâ Ĉ+€¸@ÑLn–Ý çñãÇñâ:÷#À_¼yù$N\_<}Äj°9W ®@\€¸ÒqSøí»÷,¶&îŸ^ö;6Z77?á„eѶ­wŒ k1~ÇFëçæ}ì¾þã'VÎ9€Ÿ~Á;ç—ýŽâ禜+d€¸qâ —å>u…ßüþçGßýüåçIêÛROL›s]×ei^tÿ¿ô]-ý+¹Í{µ5[äúó—ŸÿÓè1ÇŠ1ÂÖzbÚÒ¦\íÀ¹…µó³®QXSÌù=ˆ™ïE§j06PªXÕØÖ½Äëri\郩ÿÛk¹5¼ÎT©Ó" ¬WK‹Ì¥CæW)sð¾ê–Û±F3ìšzb#ð±úSö ×匾:Oûß Ë„Ì¯’æ`±o ôï>5§,‘"Êsc©o~Ý—êDýåÁœñJrÄ®ÍÞ>@ :“ßì=OKÐ…û£)Gz¡†åp=bž–`·OŽ0ìT¹Ú–CÃ6{M ©Å¡tkçžó äZGÍËûœžº‹¤Z>OÕ[&ôM€±ú†¯ H ÔÏâcý ™9ìR&f¾%®¡ )·W™­o(RäðÁš|ië íÿ󽨴\â Ĉ+\–¨ZmÛ:ã §‚O³Ñá‘«ãž÷ãÍË'Œ°|zÙïØhýܼ»ÝnŒièŽß–s€#Óâ Ĉ+€¸q€“pß4ýÆ«–1 Yäê -o^>iþU2z-7¯Ì>IEND®B`‚stella-3.9.3/src/0000755000175000001440000000000012267274567013210 5ustar stephenusersstella-3.9.3/src/libpng/0000755000175000001440000000000012267274567014463 5ustar stephenusersstella-3.9.3/src/libpng/pngtrans.c0000644000175000001440000006055012141232502016437 0ustar stephenusers /* pngtrans.c - transforms the data in a row (used by both readers and writers) * * Last changed in libpng 1.6.2 [April 25, 2013] * Copyright (c) 1998-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 */ #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; png_ptr->usr_bit_depth = 8; } } #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 && png_ptr->interlaced) { 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) { # 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) 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) { png_byte t = *rp; *rp = *(rp + 1); *(rp + 1) = t; } } } #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 /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */ #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) /* 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) /* 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) /* 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) /* 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 = 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)) { 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 /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */ #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 = (-row_info->pixel_depth * row_info->width) & 7; png_bytep rp = png_ptr->row_buf + row_info->rowbytes; 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 /* PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED */ #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 and * 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 /* PNG_USER_TRANSFORM_INFO_SUPPORTED */ #endif /* PNG_READ_USER_TRANSFORM_SUPPORTED || PNG_WRITE_USER_TRANSFORM_SUPPORTED */ #endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ stella-3.9.3/src/libpng/pngrtran.c0000644000175000001440000051530212141232502016436 0ustar stephenusers /* pngrtran.c - transforms the data in a row for PNG readers * * Last changed in libpng 1.6.2 [April 25, 2013] * Copyright (c) 1998-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 * * 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"); 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 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) 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) || 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) 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)) 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)) 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)) 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) 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) 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)) 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. */ if (output_gamma < 70000 || output_gamma > 300000) 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) { /* 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) 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 then 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)) return; png_ptr->transformations |= PNG_QUANTIZE; if (!full_quantize) { int i; png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr, (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_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) break; } /* Swap the palette around, and set up a table, if necessary */ if (full_quantize) { 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_uint_32)(num_palette * (sizeof (png_byte)))); png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr, (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_uint_32)(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_uint_32)(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) { 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) { 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_uint_32)(num_entries * (sizeof (png_byte)))); distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(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 /* PNG_READ_QUANTIZE_SUPPORTED */ #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)) 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_SUPPORTED */ #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)) 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)) 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)) 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)) return; png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); } #endif /* defined(PNG_READ_EXPAND_SUPPORTED) */ #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)) 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)) 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)) 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"); break; } 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_alpha = 1; } /* If no alpha we can optimize. */ if (!input_has_alpha) { /* Any alpha means background and associative alpha processing is * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA * and ENCODE_ALPHA are irrelevant. */ png_ptr->transformations &= ~PNG_ENCODE_ALPHA; png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; if (!input_has_transparency) 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) && (png_ptr->transformations & PNG_EXPAND)) { { 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) { if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) { /* 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 /* PNG_READ_INVERT_ALPHA_SUPPORTED */ } } /* background expand and (therefore) no alpha association. */ #endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ } 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) { /* Any alpha means background and associative alpha processing is * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_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) 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) && (png_ptr->transformations & PNG_EXPAND) && !(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* 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: /* FALL THROUGH (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)) { 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 /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ } 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) 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_SHIFT * 16) PNG_PACK * 17) PNG_BGR * 18) PNG_PACKSWAP * 19) PNG_FILLER (includes PNG_ADD_ALPHA) * 20) PNG_INVERT_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) && !(png_ptr->transformations & PNG_COMPOSE)) { /* 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)) { 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) 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) { /* 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)) png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; } else if (png_ptr->transformations & PNG_COMPOSE) { /* 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) { 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 /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ #endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED */ /* 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) && (png_ptr->transformations & PNG_COMPOSE) && !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && 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 /* PNG_READ_BACKGROUND_SUPPORTED && PNG_READ_EXPAND_16_SUPPORTED */ #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)) && (png_ptr->transformations & PNG_COMPOSE) && !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && 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) || ((png_ptr->transformations & PNG_RGB_TO_GRAY) && (png_gamma_significant(png_ptr->colorspace.gamma) || png_gamma_significant(png_ptr->screen_gamma))) || ((png_ptr->transformations & PNG_COMPOSE) && (png_gamma_significant(png_ptr->colorspace.gamma) || png_gamma_significant(png_ptr->screen_gamma) # ifdef PNG_READ_BACKGROUND_SUPPORTED || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE && png_gamma_significant(png_ptr->background_gamma)) # endif )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) && png_gamma_significant(png_ptr->screen_gamma)) ) { png_build_gamma_table(png_ptr, png_ptr->bit_depth); #ifdef PNG_READ_BACKGROUND_SUPPORTED if (png_ptr->transformations & PNG_COMPOSE) { /* 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) png_warning(png_ptr, "libpng does not support gamma+background+rgb_to_gray"); if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { /* 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)) { 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)) { 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) png_ptr->background_1.gray = png_gamma_correct(png_ptr, png_ptr->background.gray, g); if (gs_sig) 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) { 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) { 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 /* PNG_READ_BACKGROUND_SUPPORTED */ 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 /* PNG_READ_GAMMA_SUPPORTED */ #ifdef PNG_READ_BACKGROUND_SUPPORTED /* No GAMMA transformation (see the hanging else 4 lines above) */ if ((png_ptr->transformations & PNG_COMPOSE) && (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 /* PNG_READ_BACKGROUND_SUPPORTED */ #ifdef PNG_READ_SHIFT_SUPPORTED if ((png_ptr->transformations & PNG_SHIFT) && !(png_ptr->transformations & PNG_EXPAND) && (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 /* PNG_READ_SHIFT_SUPPORTED */ } /* 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) { 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; } else { if (png_ptr->num_trans) { if (png_ptr->transformations & PNG_EXPAND_tRNS) 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) 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) info_ptr->bit_depth = 8; # endif # ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED if (png_ptr->transformations & PNG_16_TO_8) 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_SUPPORTED */ } #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED if (png_ptr->transformations & PNG_GRAY_TO_RGB) 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) 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) { if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && png_ptr->palette_lookup && 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 && 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) && (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) info_ptr->channels = 3; else info_ptr->channels = 1; #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED if (png_ptr->transformations & PNG_STRIP_ALPHA) { 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) info_ptr->channels++; #ifdef PNG_READ_FILLER_SUPPORTED /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ if ((png_ptr->transformations & PNG_FILLER) && ((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) 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) { if (info_ptr->bit_depth < png_ptr->user_transform_depth) info_ptr->bit_depth = png_ptr->user_transform_depth; if (info_ptr->channels < png_ptr->user_transform_channels) 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) return; #endif } /* 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)) { /* 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) { 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 && (png_ptr->transformations & PNG_EXPAND_tRNS)) 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) && !(png_ptr->transformations & PNG_COMPOSE) && (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) { int rgb_error = png_do_rgb_to_gray(png_ptr, row_info, png_ptr->row_buf + 1); if (rgb_error) { 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) && !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) 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) png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr); #endif #ifdef PNG_READ_GAMMA_SUPPORTED if ((png_ptr->transformations & PNG_GAMMA) && #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED /* Because RGB_TO_GRAY does the gamma transform. */ !(png_ptr->transformations & PNG_RGB_TO_GRAY) && #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) && ((png_ptr->num_trans != 0) || (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) && #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) && (png_ptr->transformations & PNG_COMPOSE) && (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) && (row_info->color_type & PNG_COLOR_MASK_ALPHA)) 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) 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) png_do_chop(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED if (png_ptr->transformations & PNG_QUANTIZE) { 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 /* PNG_READ_QUANTIZE_SUPPORTED */ #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) 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) && (png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) 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) png_do_invert(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_READ_SHIFT_SUPPORTED if (png_ptr->transformations & PNG_SHIFT) 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) 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) png_do_bgr(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_READ_PACKSWAP_SUPPORTED if (png_ptr->transformations & PNG_PACKSWAP) png_do_packswap(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_READ_FILLER_SUPPORTED if (png_ptr->transformations & PNG_FILLER) png_do_read_filler(row_info, png_ptr->row_buf + 1, (png_uint_32)png_ptr->filler, png_ptr->flags); #endif #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED if (png_ptr->transformations & PNG_INVERT_ALPHA) png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED if (png_ptr->transformations & PNG_SWAP_ALPHA) 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) 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) { 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) row_info->bit_depth = png_ptr->user_transform_depth; if (png_ptr->user_transform_channels) 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 } #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. */ void /* PRIVATE */ 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 = 7 - (int)((row_width + 7) & 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 = (int)((3 - ((row_width + 3) & 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 = (int)((1 - ((row_width + 1) & 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. */ void /* PRIVATE */ 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) { 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) { 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) 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 & 0xff); } break; } #endif } } } #endif #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* Scale rows of bit depth 16 down to 8 accurately */ void /* PRIVATE */ 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 void /* PRIVATE */ /* 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 void /* PRIVATE */ 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 void /* PRIVATE */ 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 */ void /* PRIVATE */ 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) & 0xff); #endif png_byte lo_filler = (png_byte)(filler & 0xff); 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) { /* 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) { /* 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) = hi_filler; *(--dp) = lo_filler; *(--dp) = *(--sp); *(--dp) = *(--sp); } *(--dp) = hi_filler; *(--dp) = lo_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) = hi_filler; *(--dp) = lo_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) { /* 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) { /* 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) = hi_filler; *(--dp) = lo_filler; *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); } *(--dp) = hi_filler; *(--dp) = lo_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) = hi_filler; *(--dp) = lo_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 */ void /* PRIVATE */ 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)) { 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 * http://web.archive.org/web/20000816232553/http://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. */ int /* PRIVATE */ 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) && (row_info->color_type & PNG_COLOR_MASK_COLOR)) { 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) *(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) *(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; red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; 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) { *(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; red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; 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) { *(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 #endif /* PNG_READ_TRANSFORMS_SUPPORTED */ #ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED /* 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; palette[i].green = (png_byte)v; palette[i].blue = (png_byte)v; } } #endif #ifdef PNG_READ_TRANSFORMS_SUPPORTED #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. */ void /* PRIVATE */ 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 |= png_ptr->background.gray << shift; *sp = (png_byte)(tmp & 0xff); } if (!shift) { 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 |= 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 |= g << shift; *sp = (png_byte)(tmp & 0xff); } if (!shift) { 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 |= png_ptr->background.gray << shift; *sp = (png_byte)(tmp & 0xff); } if (!shift) { 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 & (0xf0f >> (4 - shift)); tmp |= 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 & (0xf0f >> (4 - shift)); tmp |= g << shift; *sp = (png_byte)(tmp & 0xff); } if (!shift) { 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 & (0xf0f >> (4 - shift)); tmp |= png_ptr->background.gray << shift; *sp = (png_byte)(tmp & 0xff); } if (!shift) { 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) 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) 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) 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) 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) 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) 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) 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) 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 /* PNG_READ_BACKGROUND_SUPPORTED || PNG_READ_ALPHA_MODE_SUPPORTED */ #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(). */ void /* PRIVATE */ 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. */ void /* PRIVATE */ 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) { 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. */ void /* PRIVATE */ 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. */ void /* PRIVATE */ 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 ? 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 == 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) == gray_high && *(sp) == 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) { 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. */ void /* PRIVATE */ 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 void /* PRIVATE */ 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 /* PNG_READ_QUANTIZE_SUPPORTED */ #endif /* PNG_READ_TRANSFORMS_SUPPORTED */ #ifdef PNG_MNG_FEATURES_SUPPORTED /* Undoes intrapixel differencing */ void /* PRIVATE */ 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)) { 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 = (*(rp ) << 8) | *(rp + 1); png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); png_uint_32 s2 = (*(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 /* PNG_MNG_FEATURES_SUPPORTED */ #endif /* PNG_READ_SUPPORTED */ stella-3.9.3/src/libpng/pngpriv.h0000644000175000001440000024104412172241216016302 0ustar stephenusers /* pngpriv.h - private declarations for use inside libpng * * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-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.) * * Last changed in libpng 1.6.3 [July 18, 2013] * * 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.) */ #define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ #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: */ # ifdef __ARM_NEON__ # 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 #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) extern type name array #endif #ifndef PNG_INTERNAL_FUNCTION # define PNG_INTERNAL_FUNCTION(type, name, args, attributes)\ extern PNG_FUNCTION(type, 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 /* SECURITY and SAFETY: * * By default libpng is built without any internal limits on image size, * individual heap (png_malloc) allocations or the total amount of memory used. * If PNG_SAFE_LIMITS_SUPPORTED is defined, however, the limits below are used * (unless individually overridden). These limits are believed to be fairly * safe, but builders of secure systems should verify the values against the * real system capabilities. */ #ifdef PNG_SAFE_LIMITS_SUPPORTED /* 'safe' limits */ # ifndef PNG_USER_WIDTH_MAX # define PNG_USER_WIDTH_MAX 1000000 # endif # ifndef PNG_USER_HEIGHT_MAX # define PNG_USER_HEIGHT_MAX 1000000 # endif # ifndef PNG_USER_CHUNK_CACHE_MAX # define PNG_USER_CHUNK_CACHE_MAX 128 # endif # ifndef PNG_USER_CHUNK_MALLOC_MAX # define PNG_USER_CHUNK_MALLOC_MAX 8000000 # endif #else /* values for no limits */ # ifndef PNG_USER_WIDTH_MAX # define PNG_USER_WIDTH_MAX 0x7fffffff # endif # ifndef PNG_USER_HEIGHT_MAX # define PNG_USER_HEIGHT_MAX 0x7fffffff # endif # ifndef PNG_USER_CHUNK_CACHE_MAX # define PNG_USER_CHUNK_CACHE_MAX 0 # endif # ifndef PNG_USER_CHUNK_MALLOC_MAX # define PNG_USER_CHUNK_MALLOC_MAX 0 # endif #endif /* Moved to pngpriv.h at libpng-1.5.0 */ /* NOTE: some of these may have been used in external applications as * these definitions were exposed in pngconf.h prior to 1.5. */ /* 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(s1,s2) ((void)(s1)) # define png_chunk_warning(s1,s2) ((void)(s1)) # 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_error(s1,s2) png_err(s1) # define png_chunk_error(s1,s2) png_err(s1) # define png_fixed_error(s1,s2) png_err(s1) #endif /* 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) # define png_constcast(type, value) ((type)(value)) # define png_aligncast(type, value) ((void*)(value)) # define png_aligncastconst(type, value) ((const void*)(value)) #endif /* __cplusplus */ /* 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. */ #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)\ ((((const char*)ptr-(const char*)0) & (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 0x01 (defined in png.h) */ /* #define PNG_HAVE_PLTE 0x02 (defined in png.h) */ #define PNG_HAVE_IDAT 0x04 /* #define PNG_AFTER_IDAT 0x08 (defined in png.h) */ #define PNG_HAVE_IEND 0x10 /* 0x20 (unused) */ /* 0x40 (unused) */ /* 0x80 (unused) */ #define PNG_HAVE_CHUNK_HEADER 0x100 #define PNG_WROTE_tIME 0x200 #define PNG_WROTE_INFO_BEFORE_PLTE 0x400 #define PNG_BACKGROUND_IS_GRAY 0x800 #define PNG_HAVE_PNG_SIGNATURE 0x1000 #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */ /* 0x4000 (unused) */ #define PNG_IS_READ_STRUCT 0x8000 /* Else is a write struct */ /* Flags for the transformations the PNG library does on the image data */ #define PNG_BGR 0x0001 #define PNG_INTERLACE 0x0002 #define PNG_PACK 0x0004 #define PNG_SHIFT 0x0008 #define PNG_SWAP_BYTES 0x0010 #define PNG_INVERT_MONO 0x0020 #define PNG_QUANTIZE 0x0040 #define PNG_COMPOSE 0x0080 /* Was PNG_BACKGROUND */ #define PNG_BACKGROUND_EXPAND 0x0100 #define PNG_EXPAND_16 0x0200 /* Added to libpng 1.5.2 */ #define PNG_16_TO_8 0x0400 /* Becomes 'chop' in 1.5.4 */ #define PNG_RGBA 0x0800 #define PNG_EXPAND 0x1000 #define PNG_GAMMA 0x2000 #define PNG_GRAY_TO_RGB 0x4000 #define PNG_FILLER 0x8000 #define PNG_PACKSWAP 0x10000 #define PNG_SWAP_ALPHA 0x20000 #define PNG_STRIP_ALPHA 0x40000 #define PNG_INVERT_ALPHA 0x80000 #define PNG_USER_TRANSFORM 0x100000 #define PNG_RGB_TO_GRAY_ERR 0x200000 #define PNG_RGB_TO_GRAY_WARN 0x400000 #define PNG_RGB_TO_GRAY 0x600000 /* two bits, RGB_TO_GRAY_ERR|WARN */ #define PNG_ENCODE_ALPHA 0x800000 /* Added to libpng-1.5.4 */ #define PNG_ADD_ALPHA 0x1000000 /* Added to libpng-1.2.7 */ #define PNG_EXPAND_tRNS 0x2000000 /* Added to libpng-1.2.9 */ #define PNG_SCALE_16_TO_8 0x4000000 /* Added to libpng-1.5.4 */ /* 0x8000000 unused */ /* 0x10000000 unused */ /* 0x20000000 unused */ /* 0x40000000 unused */ /* Flags for png_create_struct */ #define PNG_STRUCT_PNG 0x0001 #define PNG_STRUCT_INFO 0x0002 /* Scaling factor for filter heuristic weighting calculations */ #define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT)) #define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT)) /* Flags for the png_ptr->flags rather than declaring a byte for each one */ #define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 #define PNG_FLAG_ZSTREAM_INITIALIZED 0x0002 /* Added to libpng-1.6.0 */ /* 0x0004 unused */ #define PNG_FLAG_ZSTREAM_ENDED 0x0008 /* Added to libpng-1.6.0 */ /* 0x0010 unused */ /* 0x0020 unused */ #define PNG_FLAG_ROW_INIT 0x0040 #define PNG_FLAG_FILLER_AFTER 0x0080 #define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 #define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 #define PNG_FLAG_CRC_CRITICAL_USE 0x0400 #define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 #define PNG_FLAG_ASSUME_sRGB 0x1000 /* Added to libpng-1.5.4 */ #define PNG_FLAG_OPTIMIZE_ALPHA 0x2000 /* Added to libpng-1.5.4 */ #define PNG_FLAG_DETECT_UNINITIALIZED 0x4000 /* Added to libpng-1.5.4 */ /* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000 */ /* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000 */ #define PNG_FLAG_LIBRARY_MISMATCH 0x20000 #define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000 #define PNG_FLAG_STRIP_ERROR_TEXT 0x80000 #define PNG_FLAG_BENIGN_ERRORS_WARN 0x100000 /* Added to libpng-1.4.0 */ #define PNG_FLAG_APP_WARNINGS_WARN 0x200000 /* Added to libpng-1.6.0 */ #define PNG_FLAG_APP_ERRORS_WARN 0x400000 /* Added to libpng-1.6.0 */ /* 0x800000 unused */ /* 0x1000000 unused */ /* 0x2000000 unused */ /* 0x4000000 unused */ /* 0x8000000 unused */ /* 0x10000000 unused */ /* 0x20000000 unused */ /* 0x40000000 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) ) /* 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_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), ((char*)(s))[1]=(char)((c)>>16),\ ((char*)(s))[2]=(char)((c)>>8), ((char*)(s))[3]=(char)((c))) /* 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)((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 /* PNG_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_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, png_size_t text_len, 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); 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); /* 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 /* Initialize the row buffers, etc. */ PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY); #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 /* These are the functions that do the transformations */ #ifdef PNG_READ_FILLER_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_read_filler,(png_row_infop row_info, png_bytep row, png_uint_32 filler, png_uint_32 flags),PNG_EMPTY); #endif #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_read_swap_alpha,(png_row_infop row_info, png_bytep row),PNG_EMPTY); #endif #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_write_swap_alpha,(png_row_infop row_info, png_bytep row),PNG_EMPTY); #endif #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_read_invert_alpha,(png_row_infop row_info, png_bytep row),PNG_EMPTY); #endif #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_write_invert_alpha,(png_row_infop row_info, png_bytep row),PNG_EMPTY); #endif #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 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED PNG_INTERNAL_FUNCTION(int,png_do_rgb_to_gray,(png_structrp png_ptr, png_row_infop row_info, png_bytep row),PNG_EMPTY); #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_gray_to_rgb,(png_row_infop row_info, png_bytep row),PNG_EMPTY); #endif #ifdef PNG_READ_PACK_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_unpack,(png_row_infop row_info, png_bytep row),PNG_EMPTY); #endif #ifdef PNG_READ_SHIFT_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_unshift,(png_row_infop row_info, png_bytep row, png_const_color_8p sig_bits),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 #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_scale_16_to_8,(png_row_infop row_info, png_bytep row),PNG_EMPTY); #endif #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_chop,(png_row_infop row_info, png_bytep row),PNG_EMPTY); #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_quantize,(png_row_infop row_info, png_bytep row, png_const_bytep palette_lookup, png_const_bytep quantize_lookup),PNG_EMPTY); # ifdef PNG_CORRECT_PALETTE_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_correct_palette,(png_structrp png_ptr, png_colorp palette, int num_palette),PNG_EMPTY); # endif #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 #ifdef PNG_WRITE_PACK_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_pack,(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth),PNG_EMPTY); #endif #ifdef PNG_WRITE_SHIFT_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_shift,(png_row_infop row_info, png_bytep row, png_const_color_8p bit_depth),PNG_EMPTY); #endif #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ defined(PNG_READ_ALPHA_MODE_SUPPORTED) PNG_INTERNAL_FUNCTION(void,png_do_compose,(png_row_infop row_info, png_bytep row, png_structrp png_ptr),PNG_EMPTY); #endif #ifdef PNG_READ_GAMMA_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_gamma,(png_row_infop row_info, png_bytep row, png_structrp png_ptr),PNG_EMPTY); #endif #ifdef PNG_READ_ALPHA_MODE_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_encode_alpha,(png_row_infop row_info, png_bytep row, png_structrp png_ptr),PNG_EMPTY); #endif #ifdef PNG_READ_EXPAND_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_expand_palette,(png_row_infop row_info, png_bytep row, png_const_colorp palette, png_const_bytep trans, int num_trans),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_do_expand,(png_row_infop row_info, png_bytep row, png_const_color_16p trans_color),PNG_EMPTY); #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_expand_16,(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_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 /* PNG_READ_iCCP_SUPPORTED */ #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 /* PNG_READ_sPLT_SUPPORTED */ #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_structrp png_ptr, png_uint_32 chunk_name),PNG_EMPTY); #ifdef PNG_READ_SUPPORTED 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. */ #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED #ifdef PNG_SET_UNKNOWN_CHUNKS_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 #endif /* PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ #endif /* PNG_READ_SUPPORTED */ /* 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_crc_skip,(png_structrp png_ptr, png_uint_32 length),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_push_crc_finish,(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 /* PNG_PROGRESSIVE_READ_SUPPORTED */ #ifdef PNG_MNG_FEATURES_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_read_intrapixel,(png_row_infop row_info, png_bytep row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_do_write_intrapixel,(png_row_infop row_info, png_bytep row),PNG_EMPTY); #endif /* 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. */ 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); 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_READ_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_FUNCTION(void,png_safe_error,(png_structp png_ptr, png_const_charp error_message),PNG_NORETURN); #ifdef PNG_WARNINGS_SUPPORTED PNG_INTERNAL_FUNCTION(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. */ PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon, (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); #endif /* Maintainer: Put new private prototypes here ^ */ #include "pngdebug.h" #ifdef __cplusplus } #endif #endif /* PNG_VERSION_INFO_ONLY */ #endif /* PNGPRIV_H */ stella-3.9.3/src/libpng/png.h0000644000175000001440000044204612172241216015406 0ustar stephenusers /* png.h - header file for PNG reference library * * libpng version 1.6.3 - July 18, 2013 * Copyright (c) 1998-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 (See LICENSE, below) * * Authors and maintainers: * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger * libpng versions 0.97, January 1998, through 1.6.3 - July 18, 2013: Glenn * See also "Contributing Authors", below. * * 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.8beta1-4 1 10008 2.1.0.8beta1-4 * 1.0.8rc1 1 10008 2.1.0.8rc1 * 1.0.8 1 10008 2.1.0.8 * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 * 1.0.9rc1 1 10009 2.1.0.9rc1 * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 * 1.0.9rc2 1 10009 2.1.0.9rc2 * 1.0.9 1 10009 2.1.0.9 * 1.0.10beta1 1 10010 2.1.0.10beta1 * 1.0.10rc1 1 10010 2.1.0.10rc1 * 1.0.10 1 10010 2.1.0.10 * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 * 1.0.11rc1 1 10011 2.1.0.11rc1 * 1.0.11 1 10011 2.1.0.11 * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 * 1.0.12rc1 2 10012 2.1.0.12rc1 * 1.0.12 2 10012 2.1.0.12 * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned) * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 * 1.2.0rc1 3 10200 3.1.2.0rc1 * 1.2.0 3 10200 3.1.2.0 * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4 * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 * 1.2.1 3 10201 3.1.2.1 * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 * 1.0.13 10 10013 10.so.0.1.0.13 * 1.2.2 12 10202 12.so.0.1.2.2 * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 * 1.2.3 12 10203 12.so.0.1.2.3 * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1 * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 * 1.0.14 10 10014 10.so.0.1.0.14 * 1.2.4 13 10204 12.so.0.1.2.4 * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3 * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3 * 1.0.15 10 10015 10.so.0.1.0.15 * 1.2.5 13 10205 12.so.0.1.2.5 * 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 * 1.0.16 10 10016 10.so.0.1.0.16 * 1.2.6 13 10206 12.so.0.1.2.6 * 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 * 1.0.17rc1 10 10017 12.so.0.1.0.17rc1 * 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 * 1.0.17 10 10017 12.so.0.1.0.17 * 1.2.7 13 10207 12.so.0.1.2.7 * 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 * 1.0.18rc1-5 10 10018 12.so.0.1.0.18rc1-5 * 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 * 1.0.18 10 10018 12.so.0.1.0.18 * 1.2.8 13 10208 12.so.0.1.2.8 * 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3 * 1.2.9beta4-11 13 10209 12.so.0.9[.0] * 1.2.9rc1 13 10209 12.so.0.9[.0] * 1.2.9 13 10209 12.so.0.9[.0] * 1.2.10beta1-7 13 10210 12.so.0.10[.0] * 1.2.10rc1-2 13 10210 12.so.0.10[.0] * 1.2.10 13 10210 12.so.0.10[.0] * 1.4.0beta1-5 14 10400 14.so.0.0[.0] * 1.2.11beta1-4 13 10211 12.so.0.11[.0] * 1.4.0beta7-8 14 10400 14.so.0.0[.0] * 1.2.11 13 10211 12.so.0.11[.0] * 1.2.12 13 10212 12.so.0.12[.0] * 1.4.0beta9-14 14 10400 14.so.0.0[.0] * 1.2.13 13 10213 12.so.0.13[.0] * 1.4.0beta15-36 14 10400 14.so.0.0[.0] * 1.4.0beta37-87 14 10400 14.so.14.0[.0] * 1.4.0rc01 14 10400 14.so.14.0[.0] * 1.4.0beta88-109 14 10400 14.so.14.0[.0] * 1.4.0rc02-08 14 10400 14.so.14.0[.0] * 1.4.0 14 10400 14.so.14.0[.0] * 1.4.1beta01-03 14 10401 14.so.14.1[.0] * 1.4.1rc01 14 10401 14.so.14.1[.0] * 1.4.1beta04-12 14 10401 14.so.14.1[.0] * 1.4.1 14 10401 14.so.14.1[.0] * 1.4.2 14 10402 14.so.14.2[.0] * 1.4.3 14 10403 14.so.14.3[.0] * 1.4.4 14 10404 14.so.14.4[.0] * 1.5.0beta01-58 15 10500 15.so.15.0[.0] * 1.5.0rc01-07 15 10500 15.so.15.0[.0] * 1.5.0 15 10500 15.so.15.0[.0] * 1.5.1beta01-11 15 10501 15.so.15.1[.0] * 1.5.1rc01-02 15 10501 15.so.15.1[.0] * 1.5.1 15 10501 15.so.15.1[.0] * 1.5.2beta01-03 15 10502 15.so.15.2[.0] * 1.5.2rc01-03 15 10502 15.so.15.2[.0] * 1.5.2 15 10502 15.so.15.2[.0] * 1.5.3beta01-10 15 10503 15.so.15.3[.0] * 1.5.3rc01-02 15 10503 15.so.15.3[.0] * 1.5.3beta11 15 10503 15.so.15.3[.0] * 1.5.3 [omitted] * 1.5.4beta01-08 15 10504 15.so.15.4[.0] * 1.5.4rc01 15 10504 15.so.15.4[.0] * 1.5.4 15 10504 15.so.15.4[.0] * 1.5.5beta01-08 15 10505 15.so.15.5[.0] * 1.5.5rc01 15 10505 15.so.15.5[.0] * 1.5.5 15 10505 15.so.15.5[.0] * 1.5.6beta01-07 15 10506 15.so.15.6[.0] * 1.5.6rc01-03 15 10506 15.so.15.6[.0] * 1.5.6 15 10506 15.so.15.6[.0] * 1.5.7beta01-05 15 10507 15.so.15.7[.0] * 1.5.7rc01-03 15 10507 15.so.15.7[.0] * 1.5.7 15 10507 15.so.15.7[.0] * 1.6.0beta01-40 16 10600 16.so.16.0[.0] * 1.6.0rc01-08 16 10600 16.so.16.0[.0] * 1.6.0 16 10600 16.so.16.0[.0] * 1.6.1beta01-09 16 10601 16.so.16.1[.0] * 1.6.1rc01 16 10601 16.so.16.1[.0] * 1.6.1 16 10601 16.so.16.1[.0] * 1.6.2beta01 16 10602 16.so.16.2[.0] * 1.6.2rc01-06 16 10602 16.so.16.2[.0] * 1.6.2 16 10602 16.so.16.2[.0] * 1.6.3beta01-11 16 10603 16.so.16.3[.0] * 1.6.3rc01 16 10603 16.so.16.3[.0] * 1.6.3 16 10603 16.so.16.3[.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-manual.txt or libpng.3 for more information. The PNG * specification is available as a W3C Recommendation and as an ISO * Specification, defines should NOT be changed. */ #define PNG_INFO_gAMA 0x0001 #define PNG_INFO_sBIT 0x0002 #define PNG_INFO_cHRM 0x0004 #define PNG_INFO_PLTE 0x0008 #define PNG_INFO_tRNS 0x0010 #define PNG_INFO_bKGD 0x0020 #define PNG_INFO_hIST 0x0040 #define PNG_INFO_pHYs 0x0080 #define PNG_INFO_oFFs 0x0100 #define PNG_INFO_tIME 0x0200 #define PNG_INFO_pCAL 0x0400 #define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ #define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ #define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ #define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ #define PNG_INFO_IDAT 0x8000 /* ESR, 1.0.6 */ /* 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 */ #define PNG_TRANSFORM_SCALE_16 0x8000 /* read only */ /* 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 3: 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 /* PNG_CONVERT_tIME_SUPPORTED */ #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 when an alpha channel, or 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. 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. The * advantage is that the color channels can be resampled (the image can be * scaled) in this form. The disadvantage is that normal practice is to store * linear, not (gamma) encoded, values and this requires 16-bit channels for * still images rather than the 8-bit channels that are just about sufficient if * gamma encoding is used. In addition all non-transparent pixel values, * including completely opaque ones, must be gamma encoded to produce the final * image. This is the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' mode (the * latter being the two common names for associated alpha color channels.) * * Since it is not necessary to perform arithmetic on opaque color values so * long as they are not to be resampled and are in the final color space it is * possible to optimize the handling of alpha by storing the opaque pixels in * the PNG format (adjusted for the output color space) while storing partially * opaque pixels in the standard, linear, format. The accuracy required for * standard alpha composition is relatively low, because the pixels are * isolated, therefore typically the accuracy loss in storing 8-bit linear * values is acceptable. (This is not true if the alpha channel is used to * simulate transparency over large areas - use 16 bits or the PNG mode in * this case!) This is the 'OPTIMIZED' mode. For this 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. The values used * correspond to the normal numbers used to describe the overall gamma of a * computer display system; for example 2.2 for an sRGB conformant system. The * values are scaled by 100000 in the _fixed version of the API (so 220000 for * sRGB.) * * The inverse of the value is always used to provide a default for the PNG file * encoding if it has no gAMA chunk and if png_set_gamma() has not been called * to override the PNG gamma information. * * When the ALPHA_OPTIMIZED mode is selected the output gamma is used to encode * opaque pixels however pixels with lower alpha values are not encoded, * regardless of the output gamma setting. * * When the standard Porter Duff handling is requested with mode 1 the output * encoding is set to be linear and the output_gamma value is only relevant * as a default for input data that has no gamma information. The linear output * encoding will be overridden if png_set_gamma() is called - the results may be * highly unexpected! * * The following numbers are derived from the sRGB standard and the research * behind it. sRGB is defined to be approximated by a PNG gAMA chunk value of * 0.45455 (1/2.2) for PNG. The value implicitly includes any viewing * correction required to take account of any differences in the color * environment of the original scene and the intended display environment; the * value expresses how to *decode* the image for display, not how the original * data was *encoded*. * * sRGB provides a peg for the PNG standard by defining a viewing environment. * sRGB itself, and earlier TV standards, actually use a more complex transform * (a linear portion then a gamma 2.4 power law) than PNG can express. (PNG is * limited to simple power laws.) By saying that an image for direct display on * an sRGB conformant system should be stored with a gAMA chunk value of 45455 * (11.3.3.2 and 11.3.3.5 of the ISO PNG specification) the PNG specification * makes it possible to derive values for other display systems and * environments. * * The Mac value is deduced from the sRGB based on an assumption that the actual * extra viewing correction used in early Mac display systems was implemented as * a power 1.45 lookup table. * * Any system where a programmable lookup table is used or where the behavior of * the final display device characteristics can be changed requires system * specific code to obtain the current characteristic. However this can be * difficult and most PNG gamma correction only requires an approximate value. * * By default, if png_set_alpha_mode() is not called, libpng assumes that all * values are unencoded, linear, values and that the output device also has a * linear characteristic. This is only very rarely correct - it is invariably * better to call png_set_alpha_mode() with PNG_DEFAULT_sRGB than rely on the * default if you don't know what the right answer is! * * The special value PNG_GAMMA_MAC_18 indicates an older Mac system (pre Mac OS * 10.6) which used a correction table to implement a somewhat lower gamma on an * otherwise sRGB system. * * Both these values are reserved (not simple gamma values) in order to allow * more precise correction internally in the future. * * NOTE: the following values can be passed to either the fixed or floating * point APIs, but the floating point API will also accept floating point * values. */ #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 Gray or 24-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 Gray or 24-bit RGB images. */ PNG_EXPORT(40, void, png_set_add_alpha, (png_structrp png_ptr, png_uint_32 filler, int flags)); #endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ #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 */ /* 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)); /* 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_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ 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_WEIGHTED_FILTER_SUPPORTED /* EXPERIMENTAL */ /* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ * defines, either the default (minimum-sum-of-absolute-differences), or * the experimental method (weighted-minimum-sum-of-absolute-differences). * * Weights are factors >= 1.0, indicating how important it is to keep the * filter type consistent between rows. Larger numbers mean the current * filter is that many times as likely to be the same as the "num_weights" * previous filters. This is cumulative for each previous row with a weight. * There needs to be "num_weights" values in "filter_weights", or it can be * NULL if the weights aren't being specified. Weights have no influence on * the selection of the first row filter. Well chosen weights can (in theory) * improve the compression for a given image. * * Costs are factors >= 1.0 indicating the relative decoding costs of a * filter type. Higher costs indicate more decoding expense, and are * therefore less likely to be selected over a filter with lower computational * costs. There needs to be a value in "filter_costs" for each valid filter * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't * setting the costs. Costs try to improve the speed of decompression without * unduly increasing the compressed image size. * * A negative weight or cost indicates the default value is to be used, and * values in the range [0.0, 1.0) indicate the value is to remain unchanged. * The default values for both weights and costs are currently 1.0, but may * change if good general weighting/cost heuristics can be found. If both * the weights and costs are set to 1.0, this degenerates the WEIGHTED method * to the UNWEIGHTED method, but with added encoding time/computation. */ 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 /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ /* Heuristic used for row filter selection. These defines should NOT be * changed. */ #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 */ #ifdef PNG_WRITE_SUPPORTED /* 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. */ 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 #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 /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ /* 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 occured, 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)); #ifdef PNG_READ_INTERLACING_SUPPORTED /* 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 /* PNG_READ_INTERLACING_SUPPORTED */ #endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ 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_EXPORTA(99, void, png_data_freer, (png_const_structrp png_ptr, png_inforp info_ptr, int freer, png_uint_32 mask), PNG_DEPRECATED); /* 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 0x0008 #define PNG_FREE_ICCP 0x0010 #define PNG_FREE_SPLT 0x0020 #define PNG_FREE_ROWS 0x0040 #define PNG_FREE_PCAL 0x0080 #define PNG_FREE_SCAL 0x0100 #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED # define PNG_FREE_UNKN 0x0200 #endif /* PNG_FREE_LIST 0x0400 removed in 1.6.0 because it is ignored */ #define PNG_FREE_PLTE 0x1000 #define PNG_FREE_TRNS 0x2000 #define PNG_FREE_TEXT 0x4000 #define PNG_FREE_ALL 0x7fff #define PNG_FREE_MUL 0x4220 /* 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); #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)); #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 /* PNG_EASY_ACCESS_SUPPORTED */ #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_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)); #endif #ifdef PNG_hIST_SUPPORTED 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 /* PNG_sCAL_SUPPORTED */ #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. */ PNG_EXPORT(172, void, png_set_keep_unknown_chunks, (png_structrp png_ptr, int keep, png_const_bytep chunk_list, int num_chunks)); /* 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 #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. */ PNG_EXPORT(178, void, png_read_png, (png_structrp png_ptr, png_inforp info_ptr, int transforms, png_voidp params)); PNG_EXPORT(179, void, png_write_png, (png_structrp png_ptr, png_inforp info_ptr, int transforms, png_voidp params)); #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 /* PNG_pHYs_SUPPORTED */ #endif /* PNG_INCH_CONVERSIONS_SUPPORTED */ /* 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 /* ?PNG_IO_STATE_SUPPORTED */ /* 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); } # 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)((temp + (temp >> 16)) >> 16); } #else /* Standard method using integer division */ # define png_composite(composite, fg, alpha, bg) \ (composite) = (png_byte)(((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)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \ 32767) / 65535) #endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ #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) ^ 0xffffffffL) + 1)) \ : (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 /******************************************************************************* * 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 and set the * version field to PNG_IMAGE_VERSION. * 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: */ #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 http://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 /* 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. */ #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. */ #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 /* PNG_STDIO_SUPPORTED */ 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 /* PNG_SIMPLIFIED_READ_SUPPORTED */ #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED #ifdef PNG_STDIO_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) */ 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*). */ /* With both 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. * * Note that the write API does not support interlacing or sub-8-bit pixels. */ #endif /* PNG_STDIO_SUPPORTED */ #endif /* PNG_SIMPLIFIED_WRITE_SUPPORTED */ /******************************************************************************* * END OF SIMPLIFIED API ******************************************************************************/ #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 */ /******************************************************************************* * 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_OPTION_NEXT 4 /* 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 /******************************************************************************* * END OF HARDWARE OPTIONS ******************************************************************************/ /* Maintainer: Put new public prototypes here ^, in libpng.3, and project * defs, scripts/pnglibconf.h, and scripts/pnglibconf.h.prebuilt */ /* The last ordinal number (this is the *last* one already used; the next * one to use is one more than this.) Maintainer, remember to add an entry to * scripts/symbols.def as well. */ #ifdef PNG_EXPORT_LAST_ORDINAL PNG_EXPORT_LAST_ORDINAL(244); #endif #ifdef __cplusplus } #endif #endif /* PNG_VERSION_INFO_ONLY */ /* Do not put anything past this line */ #endif /* PNG_H */ stella-3.9.3/src/libpng/pnglibconf.h0000644000175000001440000001606012141232502016726 0ustar stephenusers/* pnglibconf.h - library build configuration */ /* libpng version 1.6.2 - April 25, 2013 */ /* Copyright (c) 1998-2012 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*/ /*#undef PNG_ARM_NEON_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 #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_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 /*#undef PNG_SAFE_LIMITS_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_CHUNK_CACHE_LIMIT_SUPPORTED #define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED /*#undef 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_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_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_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_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_CALLOC_SUPPORTED #define PNG_COST_SHIFT 3 #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_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_WEIGHT_SHIFT 8 #define PNG_ZBUF_SIZE 8192 #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-3.9.3/src/libpng/png.c0000644000175000001440000044073412172241216015403 0ustar stephenusers /* png.c - location for general purpose libpng functions * * Last changed in libpng 1.6.2 [April 25, 2013] * Copyright (c) 1998-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 */ #include "pngpriv.h" /* Generate a compiler error if there is an old png.h in the search path. */ typedef png_libpng_version_1_6_3 Your_png_h_is_not_version_1_6_3; /* 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) { png_debug(1, "in png_set_sig_bytes"); if (png_ptr == NULL) return; if (num_bytes > 8) png_error(png_ptr, "Too many bytes for PNG signature"); png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes); } /* 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 /* PNG_READ_SUPPORTED */ #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)) { 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) 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 && length > 0) { uLong crc = png_ptr->crc; /* Should never issue a warning */ do { uInt safe_length = (uInt)length; if (safe_length == 0) safe_length = (uInt)-1; /* evil, but safe */ 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) { if (user_png_ver) { int i = 0; do { if (user_png_ver[i] != png_libpng_ver[i]) png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; } while (png_libpng_ver[i++]); } else png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) { /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so * we must recompile any applications that use any older library version. * For versions after libpng 1.0, we will be compatible, so we need * only check the first and third digits (note that when we reach version * 1.10 we will need to check the fourth symbol, namely user_png_ver[3]). */ if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || (user_png_ver[0] == '1' && (user_png_ver[2] != png_libpng_ver[2] || user_png_ver[3] != png_libpng_ver[3])) || (user_png_ver[0] == '0' && user_png_ver[2] < '9')) { #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); 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); # 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)) { /* 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; # else { # endif /* Call the general version checker (shared with read and write code): */ if (png_user_version_check(&create_struct, user_png_ver)) { 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))); *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 ((mask & PNG_FREE_TEXT) & info_ptr->free_me) { if (num != -1) { if (info_ptr->text && info_ptr->text[num].key) { 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_data(png_ptr, info_ptr, PNG_FREE_TEXT, i); png_free(png_ptr, info_ptr->text); info_ptr->text = NULL; info_ptr->num_text=0; } } #endif #ifdef PNG_tRNS_SUPPORTED /* Free any tRNS entry */ if ((mask & PNG_FREE_TRNS) & info_ptr->free_me) { png_free(png_ptr, info_ptr->trans_alpha); info_ptr->trans_alpha = NULL; info_ptr->valid &= ~PNG_INFO_tRNS; } #endif #ifdef PNG_sCAL_SUPPORTED /* Free any sCAL entry */ if ((mask & PNG_FREE_SCAL) & info_ptr->free_me) { 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) { 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) { unsigned int i; for (i = 0; i < info_ptr->pcal_nparams; i++) { png_free(png_ptr, info_ptr->pcal_params[i]); info_ptr->pcal_params[i] = NULL; } 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) { 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 ((mask & PNG_FREE_SPLT) & info_ptr->free_me) { if (num != -1) { if (info_ptr->splt_palettes) { 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 { if (info_ptr->splt_palettes_num) { int i; for (i = 0; i < info_ptr->splt_palettes_num; i++) png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, (int)i); 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 ((mask & PNG_FREE_UNKN) & info_ptr->free_me) { if (num != -1) { if (info_ptr->unknown_chunks) { png_free(png_ptr, info_ptr->unknown_chunks[num].data); info_ptr->unknown_chunks[num].data = NULL; } } else { int i; if (info_ptr->unknown_chunks_num) { for (i = 0; i < info_ptr->unknown_chunks_num; i++) png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, (int)i); png_free(png_ptr, info_ptr->unknown_chunks); info_ptr->unknown_chunks = NULL; info_ptr->unknown_chunks_num = 0; } } } #endif #ifdef PNG_hIST_SUPPORTED /* Free any hIST entry */ if ((mask & PNG_FREE_HIST) & info_ptr->free_me) { 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) { 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) { if (info_ptr->row_pointers) { png_uint_32 row; for (row = 0; row < info_ptr->height; row++) { png_free(png_ptr, info_ptr->row_pointers[row]); info_ptr->row_pointers[row] = NULL; } 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 /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ /* 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 /* The png_save_int_32 function assumes integers are stored in two's * complement format. If this isn't the case, then this routine needs to * be modified to write data in two's complement format. Note that, * the following works correctly even if png_int_32 has more than 32 bits * (compare the more complex code required on read for sign extension.) */ void PNGAPI png_save_int_32(png_bytep buf, png_int_32 i) { buf[0] = (png_byte)((i >> 24) & 0xff); buf[1] = (png_byte)((i >> 16) & 0xff); buf[2] = (png_byte)((i >> 8) & 0xff); buf[3] = (png_byte)(i & 0xff); } #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 */ # 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)) png_warning(png_ptr, "Ignoring invalid time value"); else return png_ptr->time_buffer; } return NULL; } # endif # endif /* PNG_TIME_RFC1123_SUPPORTED */ #endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ 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.3 - July 18, 2013" PNG_STRING_NEWLINE \ "Copyright (c) 1998-2013 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.3 - July 18, 2013\ Copyright (c) 1998-2013 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_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)) 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; } #ifdef PNG_READ_UNKNOWN_CHUNKS_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 */ #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 /* PNG_READ_SUPPORTED */ /* 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) || png_gamma_significant(gtest))) { /* 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 assymetrical 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) return; else { if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA, 1/*from gAMA*/)) { /* 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) { /* 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) info_ptr->valid |= PNG_INFO_sRGB; else info_ptr->valid &= ~PNG_INFO_sRGB; if (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) info_ptr->valid |= PNG_INFO_cHRM; else info_ptr->valid &= ~PNG_INFO_cHRM; # endif if (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) 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 #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)) return 1; if (!png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d)) 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)) return 1; if (!png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d)) 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)) return 1; if (!png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d)) 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)) return 1; if (!png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite)) 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.) */ 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 < 0 || 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 invertion 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)) return 2; if (!png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7)) return 2; denominator = left - right; /* Now find the red numerator. */ if (!png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7)) return 2; if (!png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7)) 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) || 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)) return 2; if (!png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7)) return 2; if (!png_muldiv(&green_inverse, xy->whitey, denominator, left-right) || 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)) return 1; if (!png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse)) return 1; if (!png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1, red_inverse)) return 1; if (!png_muldiv(&XYZ->green_X, xy->greenx, PNG_FP_1, green_inverse)) return 1; if (!png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse)) return 1; if (!png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1, green_inverse)) return 1; if (!png_muldiv(&XYZ->blue_X, xy->bluex, blue_scale, PNG_FP_1)) return 1; if (!png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1)) return 1; if (!png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale, PNG_FP_1)) 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)) return 1; if (!png_muldiv(&XYZ->red_Y, XYZ->red_Y, PNG_FP_1, Y)) return 1; if (!png_muldiv(&XYZ->red_Z, XYZ->red_Z, PNG_FP_1, Y)) return 1; if (!png_muldiv(&XYZ->green_X, XYZ->green_X, PNG_FP_1, Y)) return 1; if (!png_muldiv(&XYZ->green_Y, XYZ->green_Y, PNG_FP_1, Y)) return 1; if (!png_muldiv(&XYZ->green_Z, XYZ->green_Z, PNG_FP_1, Y)) return 1; if (!png_muldiv(&XYZ->blue_X, XYZ->blue_X, PNG_FP_1, Y)) return 1; if (!png_muldiv(&XYZ->blue_Y, XYZ->blue_Y, PNG_FP_1, Y)) return 1; if (!png_muldiv(&XYZ->blue_Z, XYZ->blue_Z, PNG_FP_1, Y)) 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 */ return !(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)); } /* 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) return result; result = png_xy_from_XYZ(&xy_test, XYZ); if (result) return result; if (png_colorspace_endpoints_match(xy, &xy_test, 5/*actually, the math is pretty accurate*/)) 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) return result; result = png_xy_from_XYZ(xy, XYZ); if (result) 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) 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)) { /* 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)) { colorspace->flags |= PNG_COLORSPACE_INVALID; png_benign_error(png_ptr, "inconsistent chromaticities"); return 0; /* failed */ } /* Only overwrite with preferred values */ if (!preferred) 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)) 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"); break; } 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"); break; } 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)) { /* 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); /* 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) 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", (unsigned)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", (unsigned)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 }; int /* PRIVATE */ png_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"); if (profile_length & 3) return png_icc_profile_error(png_ptr, colorspace, name, profile_length, "invalid length"); return 1; } 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_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)) 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) 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 cannnot 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 misintrepretation. 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. */ 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"); } /* 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"); } return 1; /* success, maybe with warnings */ } #ifdef PNG_sRGB_SUPPORTED /* 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; 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) 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_sRGB_checks[i].length && intent == 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) { /* 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) { 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 is an apparent violation of the ICC terms of use and, * anyway, probably indicates a data error or uninformed hacking. */ if (png_sRGB_checks[i].have_md5) png_benign_error(png_ptr, "copyright violation: edited ICC profile ignored"); # endif } } return 0; /* no match */ } #endif #ifdef PNG_sRGB_SUPPORTED 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)) (void)png_colorspace_set_sRGB(png_ptr, colorspace, (int)/*already checked*/png_get_uint_32(profile+64)); } #endif /* PNG_READ_sRGB_SUPPORTED */ 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) return 0; if (png_icc_check_length(png_ptr, colorspace, name, profile_length) && png_icc_check_header(png_ptr, colorspace, name, profile_length, profile, color_type) && png_icc_check_tag_table(png_ptr, colorspace, name, profile_length, profile)) { # ifdef PNG_sRGB_SUPPORTED /* 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 && (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 #endif /* COLORSPACE */ 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 (height == 0) { png_warning(png_ptr, "Image height is zero in IHDR"); 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; } # 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; } if (width > PNG_UINT_31_MAX) { png_warning(png_ptr, "Invalid image width in IHDR"); error = 1; } if (height > PNG_UINT_31_MAX) { png_warning(png_ptr, "Invalid image height in IHDR"); error = 1; } if (width > (PNG_UINT_32_MAX >> 3) /* 8-byte RGBA pixels */ - 48 /* bigrowbuf hack */ - 1 /* filter byte */ - 7*8 /* rounding of width to multiple of 8 pixels */ - 8) /* extra max_pixel_depth pad */ png_warning(png_ptr, "Width is too large for libpng to process pixels"); /* 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) && png_ptr->mng_features_permitted) 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) && (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) { 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) 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) /* two dots */ goto PNG_FP_End; else if (state & PNG_FP_SAW_DIGIT) /* 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) /* 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) 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) && (char_index == size || string[char_index] == 0)) return state /* must be non-zero - see above */; return 0; /* i.e. fail */ } #endif /* pCAL or 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) 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. */ 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. */ { 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 = -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-clead+1 < (int)precision) 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-clead < (int)precision && 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 if flag - it got * to '-1' because of the decrement after outputing * 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 * doest 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 = -exp_b10; } else uexp_b10 = 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 ((int)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"); } # 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, --size, num = -fp; else num = 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 /* READ_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); return (png_fixed_point)r; } #endif #if defined(PNG_READ_GAMMA_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. */ 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) result = -result; /* Check for overflow. */ if ((negative && result <= 0) || (!negative && result >= 0)) { *res = result; return 1; } } #endif } } return 0; } #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)) 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)) 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 /* 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)) return res; #endif return 0; /* overflow */ } /* 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 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 */ 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); } /* 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 accuracty 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 * frational 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) & 0xf]; /* 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); } 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 /* 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 double r = floor(255*pow(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)) return png_exp8bit(res); /* Overflow. */ value = 0; # endif } return (png_byte)value; } 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 double r = floor(65535*pow(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)) return png_exp16bit(res); /* Overflow. */ value = 0; # endif } return (png_uint_16)value; } /* 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); else return png_gamma_16bit_correct(value, gamma_val); } /* 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); 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)) { /* 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: */ double d = floor(65535*pow(ig/(double)max, gamma_val*.00001)+.5); sub_table[j] = (png_uint_16)d; # else if (shift) 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) 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 index 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++; } } /* 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)) 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; } /* 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; 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; } #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; 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 /* 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)) { 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 */ } else { png_byte shift, sig_bit; if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) { 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 = (png_byte)(16U - sig_bit); /* shift == insignificant bits */ else shift = 0; /* keep all 16 bits */ if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) { /* 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; #ifdef PNG_16BIT_SUPPORTED /* 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)) #endif 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); #ifdef PNG_16BIT_SUPPORTED 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); #endif #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)) { 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 /* READ_GAMMA */ /* HARDWARE 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) { int mask = 3 << option; int setting = (2 + (onoff != 0)) << option; int current = png_ptr->options; png_ptr->options = (png_byte)((current & ~mask) | setting); return (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 http://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 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 only */ /* 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) { 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) { # 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 /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ stella-3.9.3/src/libpng/pngget.c0000644000175000001440000010003312125603007016062 0ustar stephenusers /* pngget.c - retrieval of values from info struct * * Last changed in libpng 1.6.1 [March 28, 2013] * Copyright (c) 1998-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 * */ #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)) { 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); } #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)) { 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); } #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)) { 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); } #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)) { 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) && 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)) 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)) { 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); } #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)) { 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); } #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)) { 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); } #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)) { 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); } #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)) return 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)) { 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 /* PNG_pHYs_SUPPORTED */ #endif /* PNG_INCH_CONVERSIONS_SUPPORTED */ /* png_get_channels really belongs in here, too, but it's been around longer */ #endif /* PNG_EASY_ACCESS_SUPPORTED */ 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) && 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)) { 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)) { 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)) { 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)) { 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) && 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) && 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) && 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) && 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_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) && 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 || width == NULL || height == NULL || bit_depth == NULL || color_type == NULL) return (0); *width = info_ptr->width; *height = info_ptr->height; *bit_depth = info_ptr->bit_depth; *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) && 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) && 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)) { *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)) { *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)) { *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)) { 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) && 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) && 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) && 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)) { 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) # 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 /* ?PNG_SET_USER_LIMITS_SUPPORTED */ /* 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 /* ?PNG_IO_STATE_SUPPORTED */ #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 /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ stella-3.9.3/src/libpng/pngmem.c0000644000175000001440000001765012125603007016075 0ustar stephenusers /* pngmem.c - stub functions for memory allocation * * Last changed in libpng 1.6.0 [February 14, 2013] * Copyright (c) 1998-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 * * 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 then 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. */ #ifdef PNG_USER_MEM_SUPPORTED PNG_UNUSED(png_ptr) #endif 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; } /* 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 = 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 */ } /* 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 /* PNG_USER_MEM_SUPPORTED */ /* 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 /* PNG_USER_MEM_SUPPORTED */ 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 /* PNG_USER_MEM_SUPPORTED */ #endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ stella-3.9.3/src/libpng/pngread.c0000644000175000001440000040443112125603007016227 0ustar stephenusers /* pngread.c - read a PNG file * * Last changed in libpng 1.6.1 [March 28, 2013] * Copyright (c) 1998-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 * * 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 /* PNG_USER_MEM_SUPPORTED */ 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_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC 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)) 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)) png_chunk_error(png_ptr, "Missing PLTE before IDAT"); else if (png_ptr->mode & PNG_AFTER_IDAT) png_chunk_benign_error(png_ptr, "Too many IDATs found"); png_ptr->mode |= PNG_HAVE_IDAT; } else if (png_ptr->mode & PNG_HAVE_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_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 /* PNG_SEQUENTIAL_READ_SUPPORTED */ /* 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 /* PNG_SEQUENTIAL_READ_SUPPORTED */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED 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)) 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); 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) 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) 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) 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) 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) 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) 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) png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined"); #endif } #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 && (png_ptr->transformations & PNG_INTERLACE)) { 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)) { png_read_finish_row(png_ptr); return; } break; } } #endif if (!(png_ptr->mode & PNG_HAVE_IDAT)) png_error(png_ptr, "Invalid attempt to read row data"); /* Fill the row with IDAT data: */ 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) && (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 /* Blow up interlaced rows to full size */ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) { 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 /* PNG_SEQUENTIAL_READ_SUPPORTED */ #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 /* PNG_SEQUENTIAL_READ_SUPPORTED */ #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)) { pass = png_set_interlace_handling(png_ptr); /* And make sure transforms are initialized. */ png_start_read_image(png_ptr); } else { if (png_ptr->interlaced && !(png_ptr->transformations & PNG_INTERLACE)) { /* 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 /* PNG_SEQUENTIAL_READ_SUPPORTED */ #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)) #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_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) { if (chunk_name == png_IDAT) { if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) 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. */ if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) 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_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)); } #endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ /* 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_free(png_ptr, png_ptr->big_prev_row); png_free(png_ptr, png_ptr->read_buffer); #ifdef PNG_READ_QUANTIZE_SUPPORTED png_free(png_ptr, png_ptr->palette_lookup); png_free(png_ptr, png_ptr->quantize_index); #endif if (png_ptr->free_me & PNG_FREE_PLTE) png_zfree(png_ptr, png_ptr->palette); 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) png_free(png_ptr, png_ptr->trans_alpha); 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); #endif #if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) &&\ defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) png_free(png_ptr, png_ptr->unknown_chunk.data); #endif #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED png_free(png_ptr, png_ptr->chunk_list); #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) { int row; 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 ------------------- */ #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* Tell libpng to strip 16-bit/color files down to 8 bits per color. */ if (transforms & PNG_TRANSFORM_SCALE_16) { /* 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. */ png_set_scale_16(png_ptr); } #endif #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED /* 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) png_set_strip_16(png_ptr); #endif #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED /* Strip alpha bytes from the input data without combining with * the background (not recommended). */ if (transforms & PNG_TRANSFORM_STRIP_ALPHA) png_set_strip_alpha(png_ptr); #endif #if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) /* 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) png_set_packing(png_ptr); #endif #ifdef PNG_READ_PACKSWAP_SUPPORTED /* 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) png_set_packswap(png_ptr); #endif #ifdef PNG_READ_EXPAND_SUPPORTED /* 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) if ((png_ptr->bit_depth < 8) || (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) png_set_expand(png_ptr); #endif /* We don't handle background color or gamma transformation or quantizing. */ #ifdef PNG_READ_INVERT_SUPPORTED /* Invert monochrome files to have 0 as white and 1 as black */ if (transforms & PNG_TRANSFORM_INVERT_MONO) png_set_invert_mono(png_ptr); #endif #ifdef PNG_READ_SHIFT_SUPPORTED /* 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) && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) { png_color_8p sig_bit; png_get_sBIT(png_ptr, info_ptr, &sig_bit); png_set_shift(png_ptr, sig_bit); } #endif #ifdef PNG_READ_BGR_SUPPORTED /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ if (transforms & PNG_TRANSFORM_BGR) png_set_bgr(png_ptr); #endif #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ if (transforms & PNG_TRANSFORM_SWAP_ALPHA) png_set_swap_alpha(png_ptr); #endif #ifdef PNG_READ_SWAP_SUPPORTED /* Swap bytes of 16-bit files to least significant byte first */ if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) png_set_swap(png_ptr); #endif /* Added at libpng-1.2.41 */ #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED /* Invert the alpha channel from opacity to transparency */ if (transforms & PNG_TRANSFORM_INVERT_ALPHA) png_set_invert_alpha(png_ptr); #endif /* Added at libpng-1.2.41 */ #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED /* Expand grayscale image to RGB */ if (transforms & PNG_TRANSFORM_GRAY_TO_RGB) png_set_gray_to_rgb(png_ptr); #endif /* Added at libpng-1.5.4 */ #ifdef PNG_READ_EXPAND_16_SUPPORTED if (transforms & PNG_TRANSFORM_EXPAND_16) png_set_expand_16(png_ptr); #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_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 (row = 0; row < (int)info_ptr->height; row++) info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); } 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(transforms) /* Quiet compiler warnings */ PNG_UNUSED(params) } #endif /* PNG_INFO_IMAGE_SUPPORTED */ #endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ #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) */ /* TODO: change these, dang, ANSI-C reserves the 'E' namespace. */ # define E_NOTSET 0 /* File encoding not yet known */ # define E_sRGB 1 /* 8-bit encoded to sRGB gamma */ # define E_LINEAR 2 /* 16-bit linear: not encoded, NOT pre-multiplied! */ # define E_FILE 3 /* 8-bit encoded to file gamma, not sRGB or linear */ # define E_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 conver the data to color-map indicies. */ #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 E_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) format |= PNG_FORMAT_FLAG_COLOR; if (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) 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) 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; png_set_benign_errors(png_ptr, 1/*warn*/); 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_MATCHE_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_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)) { /* 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)) { 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 /* PNG_STDIO_SUPPORTED */ 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)) { /* 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. */ { 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 */ 105, 67, 67, 80, '\0', /* iCCP */ 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, (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 /* PNG_HANDLE_AS_UNKNOWN_SUPPORTED */ /* 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)) { if (png_gamma_not_sRGB(g)) { display->file_encoding = E_FILE; display->gamma_to_linear = png_reciprocal(g); } else display->file_encoding = E_sRGB; } else display->file_encoding = E_LINEAR8; } static unsigned int decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding) { if (encoding == E_FILE) /* double check */ encoding = display->file_encoding; if (encoding == E_NOTSET) /* must be the file encoding */ { set_file_encoding(display); encoding = display->file_encoding; } switch (encoding) { case E_FILE: value = png_gamma_16bit_correct(value*257, display->gamma_to_linear); break; case E_sRGB: value = png_sRGB_table[value]; break; case E_LINEAR: break; case E_LINEAR8: value *= 257; break; default: png_error(display->image->opaque->png_ptr, "unexpected encoding (internal error)"); break; } 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 E_FILE and the * file and alpha are 8-bit values. The (output) encoding will always be * E_LINEAR or E_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 == E_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 /* E_sRGB */ f = PNG_sRGB_FROM_LINEAR(f); return f; } /* NOTE: E_LINEAR values to this routine must be 16-bit, but E_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) ? E_LINEAR : E_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 == E_FILE) { if (display->file_encoding == E_NOTSET) set_file_encoding(display); /* Note that the cached value may be E_FILE too, but if it is then the * gamma_to_linear member has been set. */ encoding = display->file_encoding; } if (encoding == E_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 || output_encoding == E_LINEAR) { alpha *= 257; encoding = E_LINEAR; } else { red = PNG_sRGB_FROM_LINEAR(red * 255); green = PNG_sRGB_FROM_LINEAR(green * 255); blue = PNG_sRGB_FROM_LINEAR(blue * 255); encoding = E_sRGB; } } else if (encoding == E_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 = E_LINEAR; } else if (encoding == E_sRGB && (convert_to_Y || output_encoding == E_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 = E_LINEAR; } /* This is set if the color isn't gray but the output is. */ if (encoding == E_LINEAR) { if (convert_to_Y) { /* 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 == E_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); encoding = E_sRGB; } blue = red = green = y; } else if (output_encoding == E_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 = E_sRGB; } } if (encoding != output_encoding) png_error(image->opaque->png_ptr, "bad encoding (internal error)"); /* Store the value. */ { # ifdef PNG_FORMAT_BGR_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) ? 2 : 0; # else # define bgr 0 # endif if (output_encoding == E_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; /* FALL THROUGH */ 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; /* FALL THROUGH */ 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 E_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; 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; 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, E_FILE); return 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, E_sRGB); return 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, E_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, E_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, E_sRGB); } return 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, E_sRGB); } } return 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) ? E_LINEAR : E_sRGB; unsigned int cmap_entries; unsigned int output_processing; /* Output processing option */ unsigned int data_encoding = E_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 == E_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, "a 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) { back_r = display->background->red; back_b = display->background->blue; } else back_b = back_r = back_g; } } else if (output_encoding == E_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 == E_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 = E_sRGB; if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) png_error(png_ptr, "gray[16] color-map: too few entries"); cmap_entries = make_gray_colormap(display); if (png_ptr->num_trans > 0) { unsigned int back_alpha; if (output_format & PNG_FORMAT_FLAG_ALPHA) 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 == E_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, E_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; } back_alpha = output_encoding == E_LINEAR ? 65535 : 255; } /* 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 leve * 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 = E_sRGB; if (output_format & PNG_FORMAT_FLAG_ALPHA) { if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) png_error(png_ptr, "gray+alpha color-map: too few entries"); cmap_entries = 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 = make_gray_colormap(display); if (output_encoding == E_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, E_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, E_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, output_encoding == E_LINEAR ? 65535U : 255U, 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 == E_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, E_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 = E_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 = 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)) { cmap_entries = make_gray_file_colormap(display); data_encoding = E_FILE; } else cmap_entries = 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 == E_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 (E_FILE) * encoding then set this palette entry to the required * output encoding. */ if (output_encoding == E_sRGB) gray = png_sRGB_table[gray]; /* now E_LINEAR */ gray = PNG_DIV257(png_gamma_16bit_correct(gray, png_ptr->colorspace.gamma)); /* now E_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 == E_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*/, E_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 = E_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) { 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 = make_rgb_colormap(display); /* Add a transparent entry. */ png_create_colormap_entry(display, cmap_entries, 255, 255, 255, 0, E_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, E_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 = make_rgb_colormap(display); png_create_colormap_entry(display, cmap_entries, back_r, back_g, back_b, 0/*unused*/, output_encoding); if (output_encoding == E_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, E_sRGB, 128, back_r, output_encoding), png_colormap_compose(display, g, E_sRGB, 128, back_g, output_encoding), png_colormap_compose(display, b, E_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 = 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 = E_FILE; /* Don't change from color-map indicies */ cmap_entries = png_ptr->num_palette; if (cmap_entries > 256) cmap_entries = 256; if (cmap_entries > image->colormap_entries) png_error(png_ptr, "palette color-map: too few entries"); for (i=0; i < cmap_entries; ++i) { if (do_background && 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, E_FILE, trans[i], back_r, output_encoding), png_colormap_compose(display, colormap[i].green, E_FILE, trans[i], back_g, output_encoding), png_colormap_compose(display, colormap[i].blue, E_FILE, trans[i], back_b, output_encoding), output_encoding == E_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, E_FILE/*8-bit*/); } /* The PNG data may have indicies 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*/ break; } /* Now deal with the output processing */ if (expand_tRNS && png_ptr->num_trans > 0 && (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0) png_set_tRNS_to_alpha(png_ptr); switch (data_encoding) { default: png_error(png_ptr, "bad data option (internal error)"); break; case E_sRGB: /* Change to 8-bit sRGB */ png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB); /* FALL THROUGH */ case E_FILE: if (png_ptr->bit_depth > 8) png_set_scale_16(png_ptr); break; } 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 = 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: passes = 0; 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; */ /* FALL THROUGH */ 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 = display->row_bytes; while (--passes >= 0) { png_uint_32 y = image->height; png_bytep row = png_voidcast(png_bytep, display->first_row); while (y-- > 0) { 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: passes = 0; 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) ? 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: passes = 0; png_error(png_ptr, "unknown interlace type"); } switch (png_get_bit_depth(png_ptr, info_ptr)) { default: png_error(png_ptr, "unexpected bit depth"); break; case 8: /* 8-bit sRGB gray values with an alpha channel; the alpha channel is * to be removed by composing on a backgroundi: 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; int preserve_alpha = (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; unsigned int outchannels = 1+preserve_alpha; int swap_alpha = 0; if (preserve_alpha && (image->format & PNG_FORMAT_FLAG_AFIRST)) swap_alpha = 1; 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) outrow[1 ^ swap_alpha] = alpha; inrow += 2; /* components and alpha channel */ } } } } break; } 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) { /* gray<->color transformation required. */ if (format & PNG_FORMAT_FLAG_COLOR) 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) 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) && (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) { /* 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) 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 '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) { 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) && !png_gamma_significant(gtest)) 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) { if (linear /*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) { /* 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) { /* 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) do_local_background = 2/*required*/; /* 16-bit output: just remove the channel */ else if (linear) /* 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) filler = 65535; else filler = 255; # ifdef PNG_FORMAT_AFIRST_SUPPORTED if (format & PNG_FORMAT_FLAG_AFIRST) { 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) { /* 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) 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) { /* 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) { /* 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) { PNG_CONST png_uint_16 le = 0x0001; if (*(png_const_bytep)&le) png_set_swap(png_ptr); } /* If change is not now 0 some transformation is missing - error out. */ if (change) 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 && 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) info_format |= PNG_FORMAT_FLAG_COLOR; if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) { /* do_local_compose removes this channel below. */ if (!do_local_compose) { /* 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) /* internal error */ png_error(png_ptr, "png_image_read: alpha channel lost"); if (info_ptr->bit_depth == 16) info_format |= PNG_FORMAT_FLAG_LINEAR; # ifdef PNG_FORMAT_BGR_SUPPORTED if (png_ptr->transformations & PNG_BGR) info_format |= PNG_FORMAT_FLAG_BGR; # endif # ifdef PNG_FORMAT_AFIRST_SUPPORTED if (do_local_background == 2) { if (format & PNG_FORMAT_FLAG_AFIRST) 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) 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) { 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 = display->row_bytes; while (--passes >= 0) { png_uint_32 y = image->height; png_bytep row = png_voidcast(png_bytep, display->first_row); while (y-- > 0) { 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) { png_uint_32 check; if (row_stride == 0) row_stride = PNG_IMAGE_ROW_STRIDE(*image); if (row_stride < 0) check = -row_stride; else check = row_stride; if (image->opaque != NULL && buffer != NULL && check >= PNG_IMAGE_ROW_STRIDE(*image)) { 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) 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: invalid argument"); } else if (image != NULL) return png_image_error(image, "png_image_finish_read: damaged PNG_IMAGE_VERSION"); return 0; } #endif /* PNG_SIMPLIFIED_READ_SUPPORTED */ #endif /* PNG_READ_SUPPORTED */ stella-3.9.3/src/libpng/module.mk0000644000175000001440000000074211405741415016264 0ustar stephenusersMODULE := 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-3.9.3/src/libpng/pngwutil.c0000644000175000001440000025557312141232502016467 0ustar stephenusers /* pngwutil.c - utilities to write a PNG file * * Last changed in libpng 1.6.2 [April 25, 2013] * Copyright (c) 1998-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 */ #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) & 0xff); buf[1] = (png_byte)((i >> 16) & 0xff); buf[2] = (png_byte)((i >> 8) & 0xff); buf[3] = (png_byte)(i & 0xff); } /* 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) & 0xff); buf[1] = (png_byte)(i & 0xff); } #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 that 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 maxima"); 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) { /* 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; } } } } #else # define optimize_cmf(dp,dl) ((void)0) #endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */ /* 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) { 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"); # if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC 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) 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) && (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 * to a simple reset to the previous parameters. */ if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) 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) { /* Fix up the deflate header, if required */ optimize_cmf(comp->output, comp->input_len); /* 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 /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_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. */ static png_uint_32 png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key) { png_const_charp orig_key = key; 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)(0xff & *key++); if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/)) *new_key++ = ch, ++key_len, space = 0; else if (!space) { /* 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) bad_character = ch; /* just skip it, record the first error */ } if (key_len > 0 && space) /* trailing space */ { --key_len, --new_key; if (!bad_character) bad_character = 32; } /* Terminate the keyword */ *new_key = 0; if (key_len == 0) return 0; /* Try to only output one warning per keyword: */ if (*key) /* keyword too long */ png_warning(png_ptr, "keyword truncated"); else if (bad_character) { 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'"); } return key_len; } #endif /* 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 */ 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: #ifdef PNG_WRITE_16BIT_SUPPORTED if (bit_depth != 8 && bit_depth != 16) #else if (bit_depth != 8) #endif 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: if (bit_depth != 8 && bit_depth != 16) png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); png_ptr->channels = 2; break; case PNG_COLOR_TYPE_RGB_ALPHA: #ifdef PNG_WRITE_16BIT_SUPPORTED if (bit_depth != 8 && bit_depth != 16) #else if (bit_depth != 8) #endif 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) && ((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 relevent 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)) { 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 i; png_const_colorp pal_ptr; png_byte buf[3]; png_debug(1, "in png_write_PLTE"); if (( #ifdef PNG_MNG_FEATURES_SUPPORTED !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && #endif num_pal == 0) || num_pal > 256) { 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)) { 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) && png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) optimize_cmf(data, png_image_size(png_ptr)); # endif 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 effect 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) && png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) optimize_cmf(data, png_image_size(png_ptr)); # endif 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_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"); if (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 * 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) { 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) { 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])) #else if (buf[0] | buf[2] | buf[4]) #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 || (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && #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) { 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])) #else if (buf[0] | buf[2] | buf[4]) #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_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) 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, png_size_t text_len, int compression) { png_uint_32 key_len; png_byte new_key[81]; compression_state comp; png_debug(1, "in png_write_zTXt"); PNG_UNUSED(text_len) /* Always use strlen */ 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) { 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) png_write_compressed_data_out(png_ptr, &comp); else png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.input_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)(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; 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_bytep)png_malloc(png_ptr, buf_size); png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; #ifdef PNG_WRITE_FILTER_SUPPORTED /* Set up filtering buffer, if using this filter */ if (png_ptr->do_filter & PNG_FILTER_SUB) { png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1); png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; } /* We only need to keep the previous row if we are using one of these. */ if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) { /* Set up previous row buffer */ png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, buf_size); if (png_ptr->do_filter & PNG_FILTER_UP) { png_ptr->up_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1); png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; } if (png_ptr->do_filter & PNG_FILTER_AVG) { png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1); png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; } if (png_ptr->do_filter & PNG_FILTER_PAETH) { png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1); png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; } } #endif /* PNG_WRITE_FILTER_SUPPORTED */ #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced, we need to set up width and height of pass */ if (png_ptr->interlaced) { if (!(png_ptr->transformations & PNG_INTERLACE)) { 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) { png_ptr->row_number = 0; if (png_ptr->transformations & PNG_INTERLACE) { 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) 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; 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; 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; 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 png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, png_size_t row_bytes); #define PNG_MAXSUM (((png_uint_32)(-1)) >> 1) #define PNG_HISHIFT 10 #define PNG_LOMASK ((png_uint_32)0xffffL) #define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT)) void /* PRIVATE */ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) { png_bytep best_row; #ifdef PNG_WRITE_FILTER_SUPPORTED png_bytep prev_row, row_buf; png_uint_32 mins, bpp; png_byte filter_to_do = png_ptr->do_filter; png_size_t row_bytes = row_info->rowbytes; #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED int num_p_filters = png_ptr->num_prev_filters; #endif png_debug(1, "in png_write_find_filter"); #ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS) { /* These will never be selected so we need not test them. */ filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH); } #endif /* Find out how many bytes offset each pixel is */ bpp = (row_info->pixel_depth + 7) >> 3; prev_row = png_ptr->prev_row; #endif best_row = png_ptr->row_buf; #ifdef PNG_WRITE_FILTER_SUPPORTED row_buf = best_row; mins = PNG_MAXSUM; /* 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. */ if ((filter_to_do & PNG_FILTER_NONE) && filter_to_do != PNG_FILTER_NONE) { png_bytep rp; png_uint_32 sum = 0; png_size_t i; int v; for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) { v = *rp; sum += (v < 128) ? v : 256 - v; } #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) { png_uint_32 sumhi, sumlo; int j; sumlo = sum & PNG_LOMASK; sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */ /* Reduce the sum if we match any of the previous rows */ for (j = 0; j < num_p_filters; j++) { if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) { sumlo = (sumlo * png_ptr->filter_weights[j]) >> PNG_WEIGHT_SHIFT; sumhi = (sumhi * png_ptr->filter_weights[j]) >> PNG_WEIGHT_SHIFT; } } /* Factor in the cost of this filter (this is here for completeness, * but it makes no sense to have a "cost" for the NONE filter, as * it has the minimum possible computational cost - none). */ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> PNG_COST_SHIFT; sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> PNG_COST_SHIFT; if (sumhi > PNG_HIMASK) sum = PNG_MAXSUM; else sum = (sumhi << PNG_HISHIFT) + sumlo; } #endif mins = sum; } /* Sub filter */ if (filter_to_do == PNG_FILTER_SUB) /* It's the only filter so no testing is needed */ { png_bytep rp, lp, dp; png_size_t i; for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; i++, rp++, dp++) { *dp = *rp; } for (lp = row_buf + 1; i < row_bytes; i++, rp++, lp++, dp++) { *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); } best_row = png_ptr->sub_row; } else if (filter_to_do & PNG_FILTER_SUB) { png_bytep rp, dp, lp; png_uint_32 sum = 0, lmins = mins; png_size_t i; int v; #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* We temporarily increase the "minimum sum" by the factor we * would reduce the sum of this filter, so that we can do the * early exit comparison without scaling the sum each time. */ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) { int j; png_uint_32 lmhi, lmlo; lmlo = lmins & PNG_LOMASK; lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; for (j = 0; j < num_p_filters; j++) { if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) { lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> PNG_WEIGHT_SHIFT; lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> PNG_WEIGHT_SHIFT; } } lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> PNG_COST_SHIFT; lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> PNG_COST_SHIFT; if (lmhi > PNG_HIMASK) lmins = PNG_MAXSUM; else lmins = (lmhi << PNG_HISHIFT) + lmlo; } #endif for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; i++, rp++, dp++) { v = *dp = *rp; sum += (v < 128) ? v : 256 - v; } for (lp = row_buf + 1; i < row_bytes; i++, rp++, lp++, dp++) { v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); sum += (v < 128) ? v : 256 - v; if (sum > lmins) /* We are already worse, don't continue. */ break; } #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) { int j; png_uint_32 sumhi, sumlo; sumlo = sum & PNG_LOMASK; sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; for (j = 0; j < num_p_filters; j++) { if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) { sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >> PNG_WEIGHT_SHIFT; sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >> PNG_WEIGHT_SHIFT; } } sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> PNG_COST_SHIFT; sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> PNG_COST_SHIFT; if (sumhi > PNG_HIMASK) sum = PNG_MAXSUM; else sum = (sumhi << PNG_HISHIFT) + sumlo; } #endif if (sum < mins) { mins = sum; best_row = png_ptr->sub_row; } } /* Up filter */ if (filter_to_do == PNG_FILTER_UP) { png_bytep rp, dp, pp; png_size_t i; for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, pp = prev_row + 1; i < row_bytes; i++, rp++, pp++, dp++) { *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); } best_row = png_ptr->up_row; } else if (filter_to_do & PNG_FILTER_UP) { png_bytep rp, dp, pp; png_uint_32 sum = 0, lmins = mins; png_size_t i; int v; #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) { int j; png_uint_32 lmhi, lmlo; lmlo = lmins & PNG_LOMASK; lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; for (j = 0; j < num_p_filters; j++) { if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) { lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> PNG_WEIGHT_SHIFT; lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> PNG_WEIGHT_SHIFT; } } lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> PNG_COST_SHIFT; lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> PNG_COST_SHIFT; if (lmhi > PNG_HIMASK) lmins = PNG_MAXSUM; else lmins = (lmhi << PNG_HISHIFT) + lmlo; } #endif for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, pp = prev_row + 1; i < row_bytes; i++) { v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); sum += (v < 128) ? v : 256 - v; if (sum > lmins) /* We are already worse, don't continue. */ break; } #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) { int j; png_uint_32 sumhi, sumlo; sumlo = sum & PNG_LOMASK; sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; for (j = 0; j < num_p_filters; j++) { if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) { sumlo = (sumlo * png_ptr->filter_weights[j]) >> PNG_WEIGHT_SHIFT; sumhi = (sumhi * png_ptr->filter_weights[j]) >> PNG_WEIGHT_SHIFT; } } sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> PNG_COST_SHIFT; sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> PNG_COST_SHIFT; if (sumhi > PNG_HIMASK) sum = PNG_MAXSUM; else sum = (sumhi << PNG_HISHIFT) + sumlo; } #endif if (sum < mins) { mins = sum; best_row = png_ptr->up_row; } } /* Avg filter */ if (filter_to_do == PNG_FILTER_AVG) { png_bytep rp, dp, pp, lp; png_uint_32 i; for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, pp = prev_row + 1; i < bpp; i++) { *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); } for (lp = row_buf + 1; i < row_bytes; i++) { *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); } best_row = png_ptr->avg_row; } else if (filter_to_do & PNG_FILTER_AVG) { png_bytep rp, dp, pp, lp; png_uint_32 sum = 0, lmins = mins; png_size_t i; int v; #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) { int j; png_uint_32 lmhi, lmlo; lmlo = lmins & PNG_LOMASK; lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; for (j = 0; j < num_p_filters; j++) { if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG) { lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> PNG_WEIGHT_SHIFT; lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> PNG_WEIGHT_SHIFT; } } lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> PNG_COST_SHIFT; lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> PNG_COST_SHIFT; if (lmhi > PNG_HIMASK) lmins = PNG_MAXSUM; else lmins = (lmhi << PNG_HISHIFT) + lmlo; } #endif for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, pp = prev_row + 1; i < bpp; i++) { v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); sum += (v < 128) ? v : 256 - v; } for (lp = row_buf + 1; i < row_bytes; i++) { v = *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); sum += (v < 128) ? v : 256 - v; if (sum > lmins) /* We are already worse, don't continue. */ break; } #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) { int j; png_uint_32 sumhi, sumlo; sumlo = sum & PNG_LOMASK; sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; for (j = 0; j < num_p_filters; j++) { if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) { sumlo = (sumlo * png_ptr->filter_weights[j]) >> PNG_WEIGHT_SHIFT; sumhi = (sumhi * png_ptr->filter_weights[j]) >> PNG_WEIGHT_SHIFT; } } sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> PNG_COST_SHIFT; sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> PNG_COST_SHIFT; if (sumhi > PNG_HIMASK) sum = PNG_MAXSUM; else sum = (sumhi << PNG_HISHIFT) + sumlo; } #endif if (sum < mins) { mins = sum; best_row = png_ptr->avg_row; } } /* Paeth filter */ if (filter_to_do == PNG_FILTER_PAETH) { png_bytep rp, dp, pp, cp, lp; png_size_t i; for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, pp = prev_row + 1; i < bpp; i++) { *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); } for (lp = row_buf + 1, cp = 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); } best_row = png_ptr->paeth_row; } else if (filter_to_do & PNG_FILTER_PAETH) { png_bytep rp, dp, pp, cp, lp; png_uint_32 sum = 0, lmins = mins; png_size_t i; int v; #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) { int j; png_uint_32 lmhi, lmlo; lmlo = lmins & PNG_LOMASK; lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; for (j = 0; j < num_p_filters; j++) { if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) { lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> PNG_WEIGHT_SHIFT; lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> PNG_WEIGHT_SHIFT; } } lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> PNG_COST_SHIFT; lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> PNG_COST_SHIFT; if (lmhi > PNG_HIMASK) lmins = PNG_MAXSUM; else lmins = (lmhi << PNG_HISHIFT) + lmlo; } #endif for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, pp = prev_row + 1; i < bpp; i++) { v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); sum += (v < 128) ? v : 256 - v; } for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) { int a, b, c, pa, pb, pc, p; b = *pp++; c = *cp++; a = *lp++; #ifndef PNG_SLOW_PAETH 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; #else /* PNG_SLOW_PAETH */ p = a + b - c; pa = abs(p - a); pb = abs(p - b); pc = abs(p - c); if (pa <= pb && pa <= pc) p = a; else if (pb <= pc) p = b; else p = c; #endif /* PNG_SLOW_PAETH */ v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); sum += (v < 128) ? v : 256 - v; if (sum > lmins) /* We are already worse, don't continue. */ break; } #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) { int j; png_uint_32 sumhi, sumlo; sumlo = sum & PNG_LOMASK; sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; for (j = 0; j < num_p_filters; j++) { if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) { sumlo = (sumlo * png_ptr->filter_weights[j]) >> PNG_WEIGHT_SHIFT; sumhi = (sumhi * png_ptr->filter_weights[j]) >> PNG_WEIGHT_SHIFT; } } sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> PNG_COST_SHIFT; sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> PNG_COST_SHIFT; if (sumhi > PNG_HIMASK) sum = PNG_MAXSUM; else sum = (sumhi << PNG_HISHIFT) + sumlo; } #endif if (sum < mins) { best_row = png_ptr->paeth_row; } } #endif /* PNG_WRITE_FILTER_SUPPORTED */ /* 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); #ifdef PNG_WRITE_FILTER_SUPPORTED #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* Save the type of filter we picked this time for future calculations */ if (png_ptr->num_prev_filters > 0) { int j; for (j = 1; j < num_p_filters; j++) { png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1]; } png_ptr->prev_filters[j] = best_row[0]; } #endif #endif /* PNG_WRITE_FILTER_SUPPORTED */ } /* 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); /* 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; } /* 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 } #endif /* PNG_WRITE_SUPPORTED */ stella-3.9.3/src/libpng/pnginfo.h0000644000175000001440000003007212125603007016250 0ustar stephenusers /* pnginfo.h - header file for PNG reference library * * Copyright (c) 1998-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.) * * Last changed in libpng 1.6.1 [March 28, 2013] * * 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 /* PNG_TEXT_SUPPORTED */ #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_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-3.9.3/src/libpng/pngrutil.c0000644000175000001440000042274712172241216016467 0ustar stephenusers /* pngrutil.c - utilities to read a PNG file * * Last changed in libpng 1.6.3 [July 18, 2013] * Copyright (c) 1998-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 * * 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 uval; uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */ return -(png_int_32)uval; } /* 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 /* PNG_READ_INT_FUNCTIONS_SUPPORTED */ /* 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)) { 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); #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)) { if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) ? !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) : (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)) { png_chunk_warning(png_ptr, "CRC error"); } else { png_chunk_benign_error(png_ptr, "CRC error"); return (0); } 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)) { 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) 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) { crc = png_get_uint_32(crc_bytes); return ((int)(crc != png_ptr->crc)); } else return (0); } /* 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) { png_ptr->read_buffer = buffer; png_ptr->read_buffer_size = new_size; } else if (warn < 2) /* else silent */ { #ifdef PNG_WARNINGS_SUPPORTED if (warn) png_chunk_warning(png_ptr, "insufficient memory to read chunk"); else #endif { #ifdef PNG_ERROR_TEXT_SUPPORTED png_chunk_error(png_ptr, "insufficient memory to read chunk"); #endif } } } return buffer; } /* 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_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC 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 PNG_ZLIB_VERNUM >= 0x1240 # if defined(PNG_SET_OPTION_SUPPORTED) && \ defined(PNG_MAXIMUM_INFLATE_WINDOW) int window_bits; if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) == PNG_OPTION_ON) window_bits = 15; else window_bits = 0; # else # define window_bits 0 # endif # endif /* 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) { # if PNG_ZLIB_VERNUM < 0x1240 ret = inflateReset(&png_ptr->zstream); # else ret = inflateReset2(&png_ptr->zstream, window_bits); # endif } else { # if PNG_ZLIB_VERNUM < 0x1240 ret = inflateInit(&png_ptr->zstream); # else ret = inflateInit2(&png_ptr->zstream, window_bits); # endif if (ret == Z_OK) png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; } if (ret == Z_OK) png_ptr->zowner = owner; else png_zstream_error(png_ptr, ret); return ret; } # ifdef window_bits # undef window_bits # endif } #ifdef PNG_READ_COMPRESSED_TEXT_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 = inflate(&png_ptr->zstream, 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_CHUNK_MALLOC_LIMIT_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) { 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) 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); if (ret == Z_STREAM_END) 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 /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */ #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 = inflate(&png_ptr->zstream, *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 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) 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 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)) 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) png_chunk_error(png_ptr, "duplicate"); else if (png_ptr->mode & PNG_HAVE_IDAT) { /* 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)) { 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; #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, 0); } #ifndef PNG_READ_OPT_PLTE_SUPPORTED else if (png_crc_error(png_ptr)) /* 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)) { if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) { png_chunk_benign_error(png_ptr, "CRC error"); } else { png_chunk_warning(png_ptr, "CRC error"); return; } } /* Otherwise, we (optionally) emit a warning and use the chunk. */ else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) { 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) || !(png_ptr->mode & PNG_HAVE_IDAT)) 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)) png_chunk_error(png_ptr, "missing IHDR"); else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) { 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)) 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; png_byte buf[4]; png_debug(1, "in png_handle_sBIT"); buf[0] = buf[1] = buf[2] = buf[3] = 0; if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_chunk_error(png_ptr, "missing IHDR"); else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) { 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)) { 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; else truelen = png_ptr->channels; if (length != truelen || length > 4) { png_chunk_benign_error(png_ptr, "invalid"); png_crc_finish(png_ptr, length); return; } png_crc_read(png_ptr, buf, truelen); if (png_crc_finish(png_ptr, 0)) return; if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) { 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)) png_chunk_error(png_ptr, "missing IHDR"); else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) { 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)) 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) return; if (png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) { 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)) png_chunk_error(png_ptr, "missing IHDR"); else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) { 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)) return; /* If a colorspace error has already been output skip this chunk */ if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) 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) { 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 /* PNG_READ_sRGB_SUPPORTED */ #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)) png_chunk_error(png_ptr, "missing IHDR"); else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) { 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 minimum 'deflate' stream is assumed to be just the 2 byte header and 4 * byte checksum. The keyword must be one character and there is a * terminator (0) byte and the compression method. */ if (length < 9) { 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) { 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; 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]; 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)) { /* 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)) { /* 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 these 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 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)) { /* 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; # ifdef PNG_sRGB_SUPPORTED /* 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; } } else if (size > 0) errmsg = "truncated"; else 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) 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 /* PNG_READ_iCCP_SUPPORTED */ #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)) png_chunk_error(png_ptr, "missing IHDR"); else if (png_ptr->mode & PNG_HAVE_IDAT) { 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)) 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 (entry_start > buffer + length - 2) { 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 % entry_size) { png_warning(png_ptr, "sPLT chunk has bad length"); return; } dl = (png_int_32)(data_length / 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 / entry_size); new_palette.entries = (png_sPLT_entryp)png_malloc_warn( png_ptr, 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 /* PNG_READ_sPLT_SUPPORTED */ #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)) png_chunk_error(png_ptr, "missing IHDR"); else if (png_ptr->mode & PNG_HAVE_IDAT) { 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)) { 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)) { /* 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 > png_ptr->num_palette || length > 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)) { 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)) png_chunk_error(png_ptr, "missing IHDR"); else if ((png_ptr->mode & PNG_HAVE_IDAT) || (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && !(png_ptr->mode & PNG_HAVE_PLTE))) { 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)) { 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) 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)) 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 && info_ptr->num_palette) { 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)) /* 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_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)) png_chunk_error(png_ptr, "missing IHDR"); else if ((png_ptr->mode & PNG_HAVE_IDAT) || !(png_ptr->mode & PNG_HAVE_PLTE)) { 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)) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "duplicate"); return; } num = length / 2 ; if (num != png_ptr->num_palette || num > 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)) 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)) png_chunk_error(png_ptr, "missing IHDR"); else if (png_ptr->mode & PNG_HAVE_IDAT) { 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)) { 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)) 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)) png_chunk_error(png_ptr, "missing IHDR"); else if (png_ptr->mode & PNG_HAVE_IDAT) { 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)) { 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)) 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)) png_chunk_error(png_ptr, "missing IHDR"); else if (png_ptr->mode & PNG_HAVE_IDAT) { 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)) { 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)) 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)) png_chunk_error(png_ptr, "missing IHDR"); else if (png_ptr->mode & PNG_HAVE_IDAT) { 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)) { 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)) 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) || i >= length || buffer[i++] != 0) png_chunk_benign_error(png_ptr, "bad width format"); else if (!PNG_FP_IS_POSITIVE(state)) 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) || i != length) png_chunk_benign_error(png_ptr, "bad height format"); else if (!PNG_FP_IS_POSITIVE(state)) 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)) png_chunk_error(png_ptr, "missing IHDR"); else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "duplicate"); return; } if (png_ptr->mode & PNG_HAVE_IDAT) 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)) 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)) png_chunk_error(png_ptr, "missing IHDR"); if (png_ptr->mode & PNG_HAVE_IDAT) 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)) 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)) 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)) png_chunk_error(png_ptr, "missing IHDR"); if (png_ptr->mode & PNG_HAVE_IDAT) png_ptr->mode |= PNG_AFTER_IDAT; 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)) 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; /* 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)) 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)) png_chunk_error(png_ptr, "missing IHDR"); if (png_ptr->mode & PNG_HAVE_IDAT) 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)) 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 allocaton may overflow. */ ++prefix_length; if (!compressed && prefix_length <= length) uncompressed_length = length - prefix_length; else if (compressed && 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) 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)) 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_CHUNK_MALLOC_LIMIT_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 /* PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ /* 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)) { /* 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 occured, 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 /* PNG_READ_USER_CHUNKS_SUPPORTED */ # 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)) 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"); /* FALL THROUGH */ 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); /* FALL THROUGH */ case 0: /* no limit */ # endif /* PNG_USER_LIMITS_SUPPORTED */ /* 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! */ PNG_UNUSED(info_ptr) # error untested code (reading unknown chunks with no store support) # 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 /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ /* Check for unhandled critical chunks */ if (!handled && 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_structrp png_ptr, png_uint_32 chunk_name) { int i; png_debug(1, "in png_check_chunk_name"); for (i=1; i<=4; ++i) { int c = chunk_name & 0xff; if (c < 65 || c > 122 || (c > 90 && c < 97)) png_chunk_error(png_ptr, "invalid chunk type"); chunk_name >>= 8; } } /* 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_uint_32 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) /* little-endian byte */ end_mask = 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 && (png_ptr->transformations & PNG_INTERLACE) && 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), S_MASK(3,d,s), S_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 /* !PNG_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) 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) { /* 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 = 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 /* PNG_ALIGN_ 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 = row_width; } } /* NOT REACHED*/ } /* pixel_depth >= 8 */ /* Here if pixel_depth < 8 to check 'end_ptr' below. */ } else #endif /* 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 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); int sshift, dshift; int s_start, s_end, s_inc; int jstop = png_pass_inc[pass]; png_byte v; png_uint_32 i; int j; #ifdef PNG_READ_PACKSWAP_SUPPORTED if (transformations & PNG_PACKSWAP) { sshift = (int)((row_info->width + 7) & 0x07); dshift = (int)((final_width + 7) & 0x07); s_start = 7; s_end = 0; s_inc = -1; } else #endif { sshift = 7 - (int)((row_info->width + 7) & 0x07); dshift = 7 - (int)((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 |= v << dshift; *dp = (png_byte)(tmp & 0xff); if (dshift == s_end) { dshift = s_start; dp--; } else dshift += s_inc; } if (sshift == s_end) { sshift = s_start; sp--; } else 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); int sshift, dshift; int s_start, s_end, s_inc; int jstop = png_pass_inc[pass]; png_uint_32 i; #ifdef PNG_READ_PACKSWAP_SUPPORTED if (transformations & PNG_PACKSWAP) { sshift = (int)(((row_info->width + 3) & 0x03) << 1); dshift = (int)(((final_width + 3) & 0x03) << 1); s_start = 6; s_end = 0; s_inc = -2; } else #endif { sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1); dshift = (int)((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 |= v << dshift; *dp = (png_byte)(tmp & 0xff); if (dshift == s_end) { dshift = s_start; dp--; } else dshift += s_inc; } if (sshift == s_end) { sshift = s_start; sp--; } else 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); int sshift, dshift; int s_start, s_end, s_inc; png_uint_32 i; int jstop = png_pass_inc[pass]; #ifdef PNG_READ_PACKSWAP_SUPPORTED if (transformations & PNG_PACKSWAP) { sshift = (int)(((row_info->width + 1) & 0x01) << 2); dshift = (int)(((final_width + 1) & 0x01) << 2); s_start = 4; s_end = 0; s_inc = -4; } else #endif { sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2); dshift = (int)((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 |= v << dshift; *dp = (png_byte)(tmp & 0xff); if (dshift == s_end) { dshift = s_start; dp--; } else dshift += s_inc; } if (sshift == s_end) { sshift = s_start; sp--; } else 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 = 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 /* PNG_READ_INTERLACING_SUPPORTED */ 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) { 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 += 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; c = b; a += *row; *row++ = (png_byte)a; } } static void png_init_filter_functions(png_structrp pp) /* This function is called once for every PNG image 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 (pp->read_filter[0] == NULL) png_init_filter_functions(pp); if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST) 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 = inflate(&png_ptr->zstream, 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)) { /* 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)) { 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) { #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[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_READ_INTERLACING_SUPPORTED */ png_debug(1, "in png_read_finish_row"); png_ptr->row_number++; if (png_ptr->row_number < png_ptr->num_rows) return; #ifdef PNG_READ_INTERLACING_SUPPORTED if (png_ptr->interlaced) { 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)) { 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; } #endif /* PNG_READ_INTERLACING_SUPPORTED */ /* Here after at the end of the last row of the last pass. */ png_read_finish_IDAT(png_ptr); } #endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ void /* PRIVATE */ png_read_start_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[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 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 #ifdef PNG_READ_INTERLACING_SUPPORTED if (png_ptr->interlaced) { if (!(png_ptr->transformations & PNG_INTERLACE)) 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 #endif /* PNG_READ_INTERLACING_SUPPORTED */ { png_ptr->num_rows = png_ptr->height; png_ptr->iwidth = png_ptr->width; } max_pixel_depth = png_ptr->pixel_depth; /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpliar 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) && png_ptr->bit_depth < 8) max_pixel_depth = 8; #endif #ifdef PNG_READ_EXPAND_SUPPORTED if (png_ptr->transformations & PNG_EXPAND) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { if (png_ptr->num_trans) 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) max_pixel_depth *= 2; } else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) { if (png_ptr->num_trans) { max_pixel_depth *= 4; max_pixel_depth /= 3; } } } #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED if (png_ptr->transformations & PNG_EXPAND_16) { # 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) { 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)) { 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) { if ( #ifdef PNG_READ_EXPAND_SUPPORTED (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) || #endif #ifdef PNG_READ_FILLER_SUPPORTED (png_ptr->transformations & (PNG_FILLER)) || #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) { 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) >> 3); #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) 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) { 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 /* PNG_READ_SUPPORTED */ stella-3.9.3/src/libpng/pngwio.c0000644000175000001440000001273212125603007016111 0ustar stephenusers /* pngwio.c - functions for data output * * Last changed in libpng 1.6.0 [February 14, 2013] * Copyright (c) 1998-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 * * 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 #endif /* PNG_WRITE_FLUSH_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 /* PNG_WRITE_SUPPORTED */ stella-3.9.3/src/libpng/pngpread.c0000644000175000001440000010666112172241216016415 0ustar stephenusers /* pngpread.c - read a png file in push mode * * Last changed in libpng 1.6.0 [February 14, 2013] * Copyright (c) 1998-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 */ #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_SKIP_MODE 3 #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 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) 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) { png_uint_32 remaining = 0; if (png_ptr != NULL && png_ptr->process_mode == PNG_SKIP_MODE && png_ptr->skip_length > 0) { /* At the end of png_process_data the buffer size must be 0 (see the loop * above) so we can detect a broken call here: */ if (png_ptr->buffer_size != 0) png_error(png_ptr, "png_process_data_skip called inside png_process_data"); /* If is impossible for there to be a saved buffer at this point - * otherwise we could not be in SKIP mode. This will also happen if * png_process_skip is called inside png_process_data (but only very * rarely.) */ if (png_ptr->save_buffer_size != 0) png_error(png_ptr, "png_process_data_skip called with saved data"); remaining = png_ptr->skip_length; png_ptr->skip_length = 0; png_ptr->process_mode = PNG_READ_CHUNK_MODE; } return remaining; } /* 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; } case PNG_SKIP_MODE: { png_push_crc_finish(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)) { png_byte chunk_length[4]; png_byte chunk_tag[4]; if (png_ptr->buffer_size < 8) { png_push_save_buffer(png_ptr); return; } 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_ptr->mode |= PNG_HAVE_CHUNK_HEADER; } chunk_name = png_ptr->chunk_name; if (chunk_name == png_IDAT) { if (png_ptr->mode & PNG_AFTER_IDAT) 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)) png_error(png_ptr, "Missing IHDR before IDAT"); else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && !(png_ptr->mode & PNG_HAVE_PLTE)) png_error(png_ptr, "Missing PLTE before IDAT"); png_ptr->mode |= PNG_HAVE_IDAT; if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) if (png_ptr->push_length == 0) return; if (png_ptr->mode & PNG_AFTER_IDAT) 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"); if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); } else if (chunk_name == png_IEND) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } 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) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } 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) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } 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) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } 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) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } 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) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sRGB_SUPPORTED else if (chunk_name == png_sRGB) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } 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) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sPLT_SUPPORTED else if (chunk_name == png_sPLT) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tRNS_SUPPORTED else if (chunk_name == png_tRNS) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_bKGD_SUPPORTED else if (chunk_name == png_bKGD) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_hIST_SUPPORTED else if (chunk_name == png_hIST) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_pHYs_SUPPORTED else if (chunk_name == png_pHYs) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_oFFs_SUPPORTED else if (chunk_name == png_oFFs) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_pCAL_SUPPORTED else if (chunk_name == png_pCAL) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sCAL_SUPPORTED else if (chunk_name == png_sCAL) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tIME_SUPPORTED else if (chunk_name == png_tIME) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tEXt_SUPPORTED else if (chunk_name == png_tEXt) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_zTXt_SUPPORTED else if (chunk_name == png_zTXt) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_iTXt_SUPPORTED else if (chunk_name == png_iTXt) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); } #endif else { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, PNG_HANDLE_CHUNK_AS_DEFAULT); } png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; } void /* PRIVATE */ png_push_crc_skip(png_structrp png_ptr, png_uint_32 skip) { png_ptr->process_mode = PNG_SKIP_MODE; png_ptr->skip_length = skip; } void /* PRIVATE */ png_push_crc_finish(png_structrp png_ptr) { if (png_ptr->skip_length && png_ptr->save_buffer_size) { png_size_t save_size = png_ptr->save_buffer_size; png_uint_32 skip_length = png_ptr->skip_length; /* We want the smaller of 'skip_length' and 'save_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 or 64 bit platforms. */ if (skip_length < save_size) save_size = (png_size_t)skip_length; else skip_length = (png_uint_32)save_size; png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); png_ptr->skip_length -= skip_length; png_ptr->buffer_size -= save_size; png_ptr->save_buffer_size -= save_size; png_ptr->save_buffer_ptr += save_size; } if (png_ptr->skip_length && png_ptr->current_buffer_size) { png_size_t save_size = png_ptr->current_buffer_size; png_uint_32 skip_length = png_ptr->skip_length; /* We want the smaller of 'skip_length' and 'current_buffer_size', here, * the same problem exists as above and the same solution. */ if (skip_length < save_size) save_size = (png_size_t)skip_length; else skip_length = (png_uint_32)save_size; png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); png_ptr->skip_length -= skip_length; png_ptr->buffer_size -= save_size; png_ptr->current_buffer_size -= save_size; png_ptr->current_buffer_ptr += save_size; } if (!png_ptr->skip_length) { if (png_ptr->buffer_size < 4) { png_push_save_buffer(png_ptr); return; } png_crc_finish(png_ptr, 0); png_ptr->process_mode = PNG_READ_CHUNK_MODE; } } 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) { 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 && png_ptr->current_buffer_size) { 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) { 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"); } memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); 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)) { png_byte chunk_length[4]; png_byte chunk_tag[4]; /* TODO: this code can be commoned up with the same code in push_read */ if (png_ptr->buffer_size < 8) { png_push_save_buffer(png_ptr); return; } 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)) png_error(png_ptr, "Not enough compressed data"); return; } png_ptr->idat_size = png_ptr->push_length; } if (png_ptr->idat_size && png_ptr->save_buffer_size) { 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 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 && png_ptr->current_buffer_size) { 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) { if (png_ptr->buffer_size < 4) { png_push_save_buffer(png_ptr); return; } 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)) { 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 = inflate(&png_ptr->zstream, 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 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) 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 /* Blow up interlaced rows to full size */ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) { 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) { 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) 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 /* PNG_READ_INTERLACING_SUPPORTED */ } 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/*display*/); } #endif /* PNG_READ_INTERLACING_SUPPORTED */ 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 /* PNG_PROGRESSIVE_READ_SUPPORTED */ stella-3.9.3/src/libpng/pngdebug.h0000644000175000001440000001243311554142764016421 0ustar stephenusers /* pngdebug.h - Debugging macros for libpng, also used in pngtest.c * * Copyright (c) 1998-2011 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.) * * Last changed in libpng 1.5.0 [January 6, 2011] * * 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' tab characters (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) /* Note: ["%s"m PNG_STRING_NEWLINE] probably does not work on * non-ISO compilers */ # 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 ? "\t" : \ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \ } 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 ? "\t" : \ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),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 ? "\t" : \ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),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-3.9.3/src/libpng/pngset.c0000644000175000001440000013320612172241216016110 0ustar stephenusers /* pngset.c - storage of image information into info struct * * Last changed in libpng 1.6.3 [July 18, 2013] * Copyright (c) 1998-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 * * 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*/)) 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)) 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 Red X"), png_fixed(png_ptr, green_Y, "cHRM Red Y"), png_fixed(png_ptr, green_Z, "cHRM Red Z"), png_fixed(png_ptr, blue_X, "cHRM Red X"), png_fixed(png_ptr, blue_Y, "cHRM Red Y"), png_fixed(png_ptr, blue_Z, "cHRM Red Z")); } # endif /* PNG_FLOATING_POINT_SUPPORTED */ #endif /* PNG_cHRM_SUPPORTED */ #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) info_ptr->channels = 3; else info_ptr->channels = 1; if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) 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_error(png_ptr, "Invalid pCAL equation type"); if (nparams < 0 || nparams > 255) png_error(png_ptr, "Invalid pCAL parameter count"); /* 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_warning(png_ptr, "Insufficient memory for pCAL purpose"); 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)((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, (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_debug1(1, "in %s storage function", "PLTE"); if (png_ptr == NULL || info_ptr == NULL) return; if (num_palette < 0 || num_palette > PNG_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_chunk_report(png_ptr, "Invalid palette", PNG_CHUNK_ERROR); return; } /* 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 that has * 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, 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)) { /* 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) 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) 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 ? "unexpected" : (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 /* PNG_iTXt_SUPPORTED */ { 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) 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)) 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); /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ png_ptr->trans_alpha = info_ptr->trans_alpha = png_voidcast(png_bytep, png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans); } if (trans_color != NULL) { int sample_max = (1 << info_ptr->bit_depth); 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"); 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 even 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); 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, 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; } while (++entries, --nentries); if (nentries > 0) png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR); } #endif /* PNG_sPLT_SUPPORTED */ #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)) { /* 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) { 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)) { 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 ((location & PNG_HAVE_IDAT)) /* undocumented! */ location = PNG_AFTER_IDAT; else location = PNG_HAVE_IHDR; /* also undocumented */ } info_ptr->unknown_chunks[chunk].location = check_location(png_ptr, location); } } #endif #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 */ 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 = (sizeof chunks_to_ignore)/5; } 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 = 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) { 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 && (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) 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) { 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)) { if (png_ptr->zowner != 0) { png_warning(png_ptr, "Compression buffer size cannot be changed because it is in use"); return; } if (size > ZLIB_IO_MAX) { png_warning(png_ptr, "Compression buffer size limited to system maximum"); size = ZLIB_IO_MAX; /* must fit */ } else 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 && info_ptr) info_ptr->valid &= ~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 0x7ffffffL. */ 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) 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) png_ptr->user_chunk_malloc_max = user_chunk_malloc_max; } #endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ #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) 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 /* PNG_BENIGN_ERRORS_SUPPORTED */ #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 zeroes * (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 #endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ stella-3.9.3/src/libpng/pngwtran.c0000644000175000001440000004161512125603007016450 0ustar stephenusers /* pngwtran.c - transforms the data in a row for PNG writers * * Last changed in libpng 1.6.0 [February 14, 2013] * Copyright (c) 1998-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 */ #include "pngpriv.h" #ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED /* 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) 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) 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) png_do_packswap(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_WRITE_PACK_SUPPORTED if (png_ptr->transformations & PNG_PACK) png_do_pack(row_info, png_ptr->row_buf + 1, (png_uint_32)png_ptr->bit_depth); #endif #ifdef PNG_WRITE_SWAP_SUPPORTED if (png_ptr->transformations & PNG_SWAP_BYTES) png_do_swap(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_WRITE_SHIFT_SUPPORTED if (png_ptr->transformations & PNG_SHIFT) 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) 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) png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_WRITE_BGR_SUPPORTED if (png_ptr->transformations & PNG_BGR) png_do_bgr(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_WRITE_INVERT_SUPPORTED if (png_ptr->transformations & PNG_INVERT_MONO) png_do_invert(row_info, png_ptr->row_buf + 1); #endif } #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). */ void /* PRIVATE */ 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; int shift, 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; int shift, 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. */ void /* PRIVATE */ 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]; int channels = 0; if (row_info->color_type & PNG_COLOR_MASK_COLOR) { 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) { 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 void /* PRIVATE */ 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 /* PNG_WRITE_16BIT_SUPPORTED */ } 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 /* PNG_WRITE_16BIT_SUPPORTED */ } } } #endif #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED void /* PRIVATE */ 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 /* PNG_WRITE_16BIT_SUPPORTED */ } 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 /* PNG_WRITE_16BIT_SUPPORTED */ } } } #endif #endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ #ifdef PNG_MNG_FEATURES_SUPPORTED /* Undoes intrapixel differencing */ void /* PRIVATE */ 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)) { 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)) & 0xff); *(rp + 2) = (png_byte)((*(rp + 2) - *(rp + 1)) & 0xff); } } #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 = (*(rp ) << 8) | *(rp + 1); png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); png_uint_32 s2 = (*(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) & 0xff); *(rp + 1) = (png_byte)(red & 0xff); *(rp + 4) = (png_byte)((blue >> 8) & 0xff); *(rp + 5) = (png_byte)(blue & 0xff); } } #endif /* PNG_WRITE_16BIT_SUPPORTED */ } } #endif /* PNG_MNG_FEATURES_SUPPORTED */ #endif /* PNG_WRITE_SUPPORTED */ stella-3.9.3/src/libpng/pngconf.h0000644000175000001440000005352712172241216016256 0ustar stephenusers /* pngconf.h - machine configurable file for libpng * * libpng version 1.6.3 - July 18, 2013 * * Copyright (c) 1998-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 * */ /* 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 /* To do: Do all of this in scripts/pnglibconf.dfa */ #ifdef PNG_SAFE_LIMITS_SUPPORTED # ifdef PNG_USER_WIDTH_MAX # undef PNG_USER_WIDTH_MAX # define PNG_USER_WIDTH_MAX 1000000L # endif # ifdef PNG_USER_HEIGHT_MAX # undef PNG_USER_HEIGHT_MAX # define PNG_USER_HEIGHT_MAX 1000000L # endif # ifdef PNG_USER_CHUNK_MALLOC_MAX # undef PNG_USER_CHUNK_MALLOC_MAX # define PNG_USER_CHUNK_MALLOC_MAX 4000000L # endif # ifdef PNG_USER_CHUNK_CACHE_MAX # undef PNG_USER_CHUNK_CACHE_MAX # define PNG_USER_CHUNK_CACHE_MAX 128 # endif #endif #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 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), \ extern 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(__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__ == 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 /* _MSC_VER */ #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 > 4294967294 typedef unsigned int png_uint_32; #elif ULONG_MAX > 4294967294 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-3.9.3/src/libpng/pngwrite.c0000644000175000001440000022077112172241216016453 0ustar stephenusers /* pngwrite.c - general routines to write a PNG file * * Last changed in libpng 1.6.2 [April 25, 2013] * Copyright (c) 1998-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 */ #include "pngpriv.h" #if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) # include #endif #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) { 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) { /* 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 /* PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */ /* 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)) { /* Write PNG signature */ png_write_sig(png_ptr); #ifdef PNG_MNG_FEATURES_SUPPORTED if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \ (png_ptr->mng_features_permitted)) { 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 and * 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) && (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) && (info_ptr->valid & PNG_INFO_gAMA)) 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) && (info_ptr->valid & PNG_INFO_iCCP)) { # ifdef PNG_WRITE_sRGB_SUPPORTED if (info_ptr->valid & PNG_INFO_sRGB) 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) && (info_ptr->valid & PNG_INFO_sRGB)) 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) 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) && (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) && (info_ptr->valid & PNG_INFO_cHRM)) 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) 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) { #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED /* Invert the alpha channel (in tRNS) */ if ((png_ptr->transformations & PNG_INVERT_ALPHA) && info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { int j; for (j = 0; j<(int)info_ptr->num_trans; j++) info_ptr->trans_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) png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); #endif #ifdef PNG_WRITE_hIST_SUPPORTED if (info_ptr->valid & PNG_INFO_hIST) 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) 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) 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) 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) 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) { 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) 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); #else png_warning(png_ptr, "Unable to write international text"); #endif /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; } /* 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, 0, info_ptr->text[i].compression); #else png_warning(png_ptr, "Unable to write compressed text"); #endif /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; } 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)) 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) && !(png_ptr->mode & PNG_WROTE_tIME)) 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); #else png_warning(png_ptr, "Unable to write international text"); #endif /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; } 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, 0, info_ptr->text[i].compression); #else png_warning(png_ptr, "Unable to write compressed text"); #endif /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; } 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); #else png_warning(png_ptr, "Unable to write uncompressed text"); #endif /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; } } #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 /* PNG_USER_MEM_SUPPORTED */ 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 /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ /* 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 png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; /* In stable builds only warn if an application error can be completely * handled. */ #endif /* App warnings are warnings in release (or release candidate) builds but * are errors during development. */ #if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC 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); } } } /* 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)) 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) 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) 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) 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) 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) 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) 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) 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 && (png_ptr->transformations & PNG_INTERLACE)) { switch (png_ptr->pass) { case 0: if (png_ptr->row_number & 0x07) { png_write_finish_row(png_ptr); return; } break; case 1: if ((png_ptr->row_number & 0x07) || 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) || 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) || png_ptr->width < 2) { png_write_finish_row(png_ptr); return; } break; case 6: if (!(png_ptr->row_number & 0x01)) { 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)) { 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)) { png_write_finish_row(png_ptr); return; } } #endif #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED /* Handle other transformations */ if (png_ptr->transformations) 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) && (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 : 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 /* PNG_WRITE_FLUSH_SUPPORTED */ #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED static void png_reset_filter_heuristics(png_structrp png_ptr);/* forward decl */ #endif /* 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) 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); #ifdef PNG_WRITE_FILTER_SUPPORTED png_free(png_ptr, png_ptr->prev_row); png_free(png_ptr, png_ptr->sub_row); png_free(png_ptr, png_ptr->up_row); png_free(png_ptr, png_ptr->avg_row); png_free(png_ptr, png_ptr->paeth_row); #endif #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* Use this to save a little code space, it doesn't free the filter_costs */ png_reset_filter_heuristics(png_ptr); png_free(png_ptr, png_ptr->filter_costs); png_free(png_ptr, png_ptr->inv_filter_costs); #endif #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED png_free(png_ptr, png_ptr->chunk_list); #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) && (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"); /* FALL THROUGH */ #endif /* PNG_WRITE_FILTER_SUPPORTED */ 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 /* 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 add and * remove them after the start of compression. */ if (png_ptr->row_buf != NULL) { #ifdef PNG_WRITE_FILTER_SUPPORTED if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) { png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, (png_ptr->rowbytes + 1)); png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; } if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL) { if (png_ptr->prev_row == NULL) { png_warning(png_ptr, "Can't add Up filter after starting"); png_ptr->do_filter = (png_byte)(png_ptr->do_filter & ~PNG_FILTER_UP); } else { png_ptr->up_row = (png_bytep)png_malloc(png_ptr, (png_ptr->rowbytes + 1)); png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; } } if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL) { if (png_ptr->prev_row == NULL) { png_warning(png_ptr, "Can't add Average filter after starting"); png_ptr->do_filter = (png_byte)(png_ptr->do_filter & ~PNG_FILTER_AVG); } else { png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, (png_ptr->rowbytes + 1)); png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; } } if ((png_ptr->do_filter & PNG_FILTER_PAETH) && png_ptr->paeth_row == NULL) { if (png_ptr->prev_row == NULL) { png_warning(png_ptr, "Can't add Paeth filter after starting"); png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH); } else { png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, (png_ptr->rowbytes + 1)); png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; } } if (png_ptr->do_filter == PNG_NO_FILTERS) #endif /* PNG_WRITE_FILTER_SUPPORTED */ png_ptr->do_filter = PNG_FILTER_NONE; } } else png_error(png_ptr, "Unknown custom filter method"); } /* This allows us to influence the way in which libpng chooses the "best" * filter for the current scanline. While the "minimum-sum-of-absolute- * differences metric is relatively fast and effective, there is some * question as to whether it can be improved upon by trying to keep the * filtered data going to zlib more consistent, hopefully resulting in * better compression. */ #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */ /* Convenience reset API. */ static void png_reset_filter_heuristics(png_structrp png_ptr) { /* Clear out any old values in the 'weights' - this must be done because if * the app calls set_filter_heuristics multiple times with different * 'num_weights' values we would otherwise potentially have wrong sized * arrays. */ png_ptr->num_prev_filters = 0; png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED; if (png_ptr->prev_filters != NULL) { png_bytep old = png_ptr->prev_filters; png_ptr->prev_filters = NULL; png_free(png_ptr, old); } if (png_ptr->filter_weights != NULL) { png_uint_16p old = png_ptr->filter_weights; png_ptr->filter_weights = NULL; png_free(png_ptr, old); } if (png_ptr->inv_filter_weights != NULL) { png_uint_16p old = png_ptr->inv_filter_weights; png_ptr->inv_filter_weights = NULL; png_free(png_ptr, old); } /* Leave the filter_costs - this array is fixed size. */ } static int png_init_filter_heuristics(png_structrp png_ptr, int heuristic_method, int num_weights) { if (png_ptr == NULL) return 0; /* Clear out the arrays */ png_reset_filter_heuristics(png_ptr); /* Check arguments; the 'reset' function makes the correct settings for the * unweighted case, but we must handle the weight case by initializing the * arrays for the caller. */ if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) { int i; if (num_weights > 0) { png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, (png_uint_32)((sizeof (png_byte)) * num_weights)); /* To make sure that the weighting starts out fairly */ for (i = 0; i < num_weights; i++) { png_ptr->prev_filters[i] = 255; } png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, (png_uint_32)((sizeof (png_uint_16)) * num_weights)); png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, (png_uint_32)((sizeof (png_uint_16)) * num_weights)); for (i = 0; i < num_weights; i++) { png_ptr->inv_filter_weights[i] = png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; } /* Safe to set this now */ png_ptr->num_prev_filters = (png_byte)num_weights; } /* If, in the future, there are other filter methods, this would * need to be based on png_ptr->filter. */ if (png_ptr->filter_costs == NULL) { png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST)); png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST)); } for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) { png_ptr->inv_filter_costs[i] = png_ptr->filter_costs[i] = PNG_COST_FACTOR; } /* All the arrays are inited, safe to set this: */ png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_WEIGHTED; /* Return the 'ok' code. */ return 1; } else if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT || heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED) { return 1; } else { png_warning(png_ptr, "Unknown filter heuristic method"); return 0; } } /* 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_debug(1, "in png_set_filter_heuristics"); /* The internal API allocates all the arrays and ensures that the elements of * those arrays are set to the default value. */ if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights)) return; /* If using the weighted method copy in the weights. */ if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) { int i; for (i = 0; i < num_weights; i++) { if (filter_weights[i] <= 0.0) { png_ptr->inv_filter_weights[i] = png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; } else { png_ptr->inv_filter_weights[i] = (png_uint_16)(PNG_WEIGHT_FACTOR*filter_weights[i]+.5); png_ptr->filter_weights[i] = (png_uint_16)(PNG_WEIGHT_FACTOR/filter_weights[i]+.5); } } /* Here is where we set the relative costs of the different filters. We * should take the desired compression level into account when setting * the costs, so that Paeth, for instance, has a high relative cost at low * compression levels, while it has a lower relative cost at higher * compression settings. The filter types are in order of increasing * relative cost, so it would be possible to do this with an algorithm. */ for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) if (filter_costs[i] >= 1.0) { png_ptr->inv_filter_costs[i] = (png_uint_16)(PNG_COST_FACTOR / filter_costs[i] + .5); png_ptr->filter_costs[i] = (png_uint_16)(PNG_COST_FACTOR * filter_costs[i] + .5); } } } #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_debug(1, "in png_set_filter_heuristics_fixed"); /* The internal API allocates all the arrays and ensures that the elements of * those arrays are set to the default value. */ if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights)) return; /* If using the weighted method copy in the weights. */ if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) { int i; for (i = 0; i < num_weights; i++) { if (filter_weights[i] <= 0) { png_ptr->inv_filter_weights[i] = png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; } else { png_ptr->inv_filter_weights[i] = (png_uint_16) ((PNG_WEIGHT_FACTOR*filter_weights[i]+PNG_FP_HALF)/PNG_FP_1); png_ptr->filter_weights[i] = (png_uint_16)((PNG_WEIGHT_FACTOR* PNG_FP_1+(filter_weights[i]/2))/filter_weights[i]); } } /* Here is where we set the relative costs of the different filters. We * should take the desired compression level into account when setting * the costs, so that Paeth, for instance, has a high relative cost at low * compression levels, while it has a lower relative cost at higher * compression settings. The filter types are in order of increasing * relative cost, so it would be possible to do this with an algorithm. */ for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) if (filter_costs[i] >= PNG_FP_1) { png_uint_32 tmp; /* Use a 32 bit unsigned temporary here because otherwise the * intermediate value will be a 32 bit *signed* integer (ANSI rules) * and this will get the wrong answer on division. */ tmp = PNG_COST_FACTOR*PNG_FP_1 + (filter_costs[i]/2); tmp /= filter_costs[i]; png_ptr->inv_filter_costs[i] = (png_uint_16)tmp; tmp = PNG_COST_FACTOR * filter_costs[i] + PNG_FP_HALF; tmp /= PNG_FP_1; png_ptr->filter_costs[i] = (png_uint_16)tmp; } } } #endif /* FIXED_POINT */ #endif /* PNG_WRITE_WEIGHTED_FILTER_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 which 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; } /* 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 /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ /* 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; /* Write the file header information. */ png_write_info(png_ptr, info_ptr); /* ------ these transformations don't touch the info structure ------- */ #ifdef PNG_WRITE_INVERT_SUPPORTED /* Invert monochrome pixels */ if (transforms & PNG_TRANSFORM_INVERT_MONO) png_set_invert_mono(png_ptr); #endif #ifdef PNG_WRITE_SHIFT_SUPPORTED /* Shift the pixels up to a legal bit depth and fill in * as appropriate to correctly scale the image. */ if ((transforms & PNG_TRANSFORM_SHIFT) && (info_ptr->valid & PNG_INFO_sBIT)) png_set_shift(png_ptr, &info_ptr->sig_bit); #endif #ifdef PNG_WRITE_PACK_SUPPORTED /* Pack pixels into bytes */ if (transforms & PNG_TRANSFORM_PACKING) png_set_packing(png_ptr); #endif #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED /* Swap location of alpha bytes from ARGB to RGBA */ if (transforms & PNG_TRANSFORM_SWAP_ALPHA) png_set_swap_alpha(png_ptr); #endif #ifdef PNG_WRITE_FILLER_SUPPORTED /* Pack XRGB/RGBX/ARGB/RGBA into RGB (4 channels -> 3 channels) */ if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); #endif #ifdef PNG_WRITE_BGR_SUPPORTED /* Flip BGR pixels to RGB */ if (transforms & PNG_TRANSFORM_BGR) png_set_bgr(png_ptr); #endif #ifdef PNG_WRITE_SWAP_SUPPORTED /* Swap bytes of 16-bit files to most significant byte first */ if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) png_set_swap(png_ptr); #endif #ifdef PNG_WRITE_PACKSWAP_SUPPORTED /* Swap bits of 1, 2, 4 bit packed pixel formats */ if (transforms & PNG_TRANSFORM_PACKSWAP) png_set_packswap(png_ptr); #endif #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED /* Invert the alpha channel from opacity to transparency */ if (transforms & PNG_TRANSFORM_INVERT_ALPHA) png_set_invert_alpha(png_ptr); #endif /* ----------------------- end of transformations ------------------- */ /* Write the bits */ if (info_ptr->valid & PNG_INFO_IDAT) 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(transforms) /* Quiet compiler warnings */ PNG_UNUSED(params) } #endif #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED #ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */ /* 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; } 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 int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; int aindex = 0; png_uint_32 y = image->height; if (image->format & PNG_FORMAT_FLAG_ALPHA) { if (image->format & PNG_FORMAT_FLAG_AFIRST) { aindex = -1; ++input_row; /* To point to the first component */ ++output_row; } else aindex = channels; } 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); while (y-- > 0) { 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 = 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 += 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 int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; if (image->format & PNG_FORMAT_FLAG_ALPHA) { png_bytep row_end; int aindex; if (image->format & PNG_FORMAT_FLAG_AFIRST) { aindex = -1; ++input_row; /* To point to the first component */ ++output_row; } else aindex = channels; /* Use row_end in place of a loop counter: */ row_end = output_row + image->width * (channels+1); while (y-- > 0) { 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 = 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 += 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; while (y-- > 0) { 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 += 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 int channels = PNG_IMAGE_SAMPLE_CHANNELS(format); # ifdef PNG_FORMAT_BGR_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) ? 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 += i * channels; switch (channels) { case 4: tRNS[i] = entry[afirst ? 0 : 3]; if (tRNS[i] < 255) num_trans = i+1; /* FALL THROUGH */ 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; /* FALL THROUGH */ 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 = 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; int colormap = (format & PNG_FORMAT_FLAG_COLORMAP) != 0; int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR) != 0; /* input */ int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA) != 0; int write_16bit = linear && !colormap && !display->convert_to_8bit; # 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. */ if (display->row_stride == 0) display->row_stride = PNG_IMAGE_ROW_STRIDE(*image); /* Set the required transforms then write the rows in the correct order. */ if (format & PNG_FORMAT_FLAG_COLORMAP) { 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) { /* 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)) 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)) 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) { PNG_CONST png_uint_16 le = 0x0001; if (*(png_const_bytep)&le) png_set_swap(png_ptr); } # ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED if (format & PNG_FORMAT_FLAG_BGR) { if (!colormap && (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) { if (!colormap && (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 && 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) 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. */ png_set_compression_level(png_ptr, 3); } /* 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 && alpha) || (!colormap && display->convert_to_8bit)) { 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) 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) 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; while (y-- > 0) { png_write_row(png_ptr, row); row += row_bytes; } } png_write_end(png_ptr, info_ptr); return 1; } 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) { if (png_image_write_init(image)) { 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) { FILE *fp = fopen(file_name, "wb"); if (fp != NULL) { if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, row_stride, colormap)) { 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 /* PNG_STDIO_SUPPORTED */ #endif /* SIMPLIFIED_WRITE */ #endif /* PNG_WRITE_SUPPORTED */ stella-3.9.3/src/libpng/pngrio.c0000644000175000001440000000752212125603007016105 0ustar stephenusers /* pngrio.c - functions for data input * * Last changed in libpng 1.6.0 [February 14, 2013] * Copyright (c) 1998-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 * * 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 then 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 /* 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"); } #ifdef PNG_WRITE_FLUSH_SUPPORTED png_ptr->output_flush_fn = NULL; #endif } #endif /* PNG_READ_SUPPORTED */ stella-3.9.3/src/libpng/pngerror.c0000644000175000001440000006737412125603007016460 0ustar stephenusers /* pngerror.c - stub functions for i/o and memory allocation * * Last changed in libpng 1.6.1 [March 28, 2013] * Copyright (c) 1998-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 * * 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 /* PNG_WARNINGS_SUPPORTED */ /* 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)) { 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) { 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) { 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 /* PNG_ERROR_TEXT_SUPPORTED */ /* 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 || number % 10 != 0) { *--end = digits[number % 10]; output = 1; } number /= 10; break; case PNG_NUMBER_FORMAT_02u: /* Expects at least 2 digits. */ mincount = 2; /* FALL THROUGH */ 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; /* FALL THROUGH */ 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) if (count == 5) if (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) *--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)) #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 /* PNG_WARNINGS_SUPPORTED */ #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) { # 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); } } void /* PRIVATE */ png_app_warning(png_const_structrp png_ptr, png_const_charp error_message) { if (png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) png_warning(png_ptr, error_message); else png_error(png_ptr, error_message); } void /* PRIVATE */ png_app_error(png_const_structrp png_ptr, png_const_charp error_message) { if (png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) png_warning(png_ptr, error_message); else png_error(png_ptr, error_message); } #endif /* BENIGN_ERRORS */ /* 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, * this 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' }; #define PNG_MAX_ERROR_TEXT 196 /* Currently limited be profile_error in png.c */ #if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) 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)) { 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 /* PNG_WARNINGS_SUPPORTED || PNG_ERROR_TEXT_SUPPORTED */ #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 /* PNG_READ_SUPPORTED && PNG_ERROR_TEXT_SUPPORTED */ #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 /* PNG_WARNINGS_SUPPORTED */ #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) png_chunk_warning(png_ptr, error_message); else png_chunk_error(png_ptr, error_message); } #endif #endif /* PNG_READ_SUPPORTED */ void /* PRIVATE */ png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error) { /* 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) # 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)) # 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) 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 && png_ptr->longjmp_fn && png_ptr->jmp_buf_ptr) png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val); #endif /* Here if not setjmp support or if png_ptr is null. */ 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 /* PNG_WARNINGS_SUPPORTED */ /* 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 */, 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 */ 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) { 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) png_image_free(image); return result; } #endif /* SIMPLIFIED READ/WRITE */ #endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ stella-3.9.3/src/libpng/pngstruct.h0000644000175000001440000004767012125603007016655 0ustar stephenusers /* pngstruct.h - header file for PNG reference library * * Copyright (c) 1998-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.) * * Last changed in libpng 1.6.1 [March 28, 2013] * * 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. * This is a pointer into big_prev_row */ png_bytep row_buf; /* buffer to save current (unfiltered) row. * This is a pointer into big_row_buf */ #ifdef PNG_WRITE_SUPPORTED png_bytep sub_row; /* buffer to save "sub" row when filtering */ png_bytep up_row; /* buffer to save "up" row when filtering */ png_bytep avg_row; /* buffer to save "avg" row when filtering */ png_bytep paeth_row; /* buffer to save "Paeth" 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_ below ) */ 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 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 /* PNG_bKGD_SUPPORTED */ #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 /* PNG_PROGRESSIVE_READ_SUPPORTED */ #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 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED png_byte heuristic_method; /* heuristic for row filter selection */ png_byte num_prev_filters; /* number of weights for previous rows */ png_bytep prev_filters; /* filter type(s) of previous row(s) */ png_uint_16p filter_weights; /* weight(s) for previous line(s) */ png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */ png_uint_16p filter_costs; /* relative filter calculation cost */ png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */ #endif /* Options */ #ifdef PNG_SET_OPTION_SUPPORTED png_byte options; /* On/off state (up to 4 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-3.9.3/src/macosx/0000755000175000001440000000000012267274567014502 5ustar stephenusersstella-3.9.3/src/macosx/AboutBox.m0000644000175000001440000000671712266336753016411 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: AboutBox.m 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #import "AboutBox.h" @implementation AboutBox static AboutBox *sharedInstance = nil; + (AboutBox *)sharedInstance { return sharedInstance ? sharedInstance : [[self alloc] init]; } - (id)init { if (sharedInstance) [self dealloc]; 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:nil]]; // 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-3.9.3/src/macosx/AboutBoxTextView.m0000644000175000001440000000251212266336753020076 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: AboutBoxTextView.m 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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-3.9.3/src/macosx/English.lproj/0000755000175000001440000000000012267274567017220 5ustar stephenusersstella-3.9.3/src/macosx/English.lproj/InfoPlist.strings0000755000175000001440000000100011313526507022515 0ustar stephenusersÿþ/* Localized versions of Info.plist keys */ CFBundleName = "Stella"; CFBundleShortVersionString = "Stella version 3.0"; CFBundleGetInfoString = "Stella version 3.0"; NSHumanReadableCopyright = "Stella MacOS X version by Stephen Anthony and Mark Grebe."; stella-3.9.3/src/macosx/SDLMain.h0000644000175000001440000000061711361062110016053 0ustar stephenusers/* SDLMain.h - main entry point for our Cocoa-ized SDL app Initial Version: Darrell Walisser Non-NIB-Code & other changes: Max Horn Feel free to customize this file to suit your needs */ /* $Id: SDLMain.h 2007 2010-04-13 12:32:08Z stephena $ */ #import @interface SDLMain : NSObject { } + (SDLMain *)sharedInstance; @end stella-3.9.3/src/macosx/SettingsMACOSX.cxx0000644000175000001440000000446512266336753017745 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SettingsMACOSX.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "Settings.hxx" #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) { setInternal("video", "gl"); // Use opengl mode by default setInternal("gl_lib", "libGL.so"); // Try this one first, then let the system decide setInternal("gl_vsync", "true"); // OSX almost always supports vsync; let's use it } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SettingsMACOSX::~SettingsMACOSX() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SettingsMACOSX::loadConfig() { string key, value; char cvalue[4096]; // Read key/value pairs from the plist file const SettingsArray& settings = getInternalSettings(); for(unsigned int 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 const SettingsArray& settings = getInternalSettings(); for(unsigned int i = 0; i < settings.size(); ++i) prefsSetString(settings[i].key.c_str(), settings[i].value.toCString()); prefsSave(); } stella-3.9.3/src/macosx/stella_intel.xcodeproj/0000755000175000001440000000000012267274567021155 5ustar stephenusersstella-3.9.3/src/macosx/stella_intel.xcodeproj/project.pbxproj0000644000175000001440000073466012267227155024240 0ustar stephenusers// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 2D28DDE509DC2D9F00A17585 /* MenusEvents.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D28DDE409DC2D9F00A17585 /* MenusEvents.h */; }; 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 */; }; 2D9173DF09BA90380026E9FF /* CartMC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF370627AE07006BEC99 /* CartMC.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 */; }; 2D9173F109BA90380026E9FF /* TIA.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF910627AE34006BEC99 /* TIA.hxx */; }; 2D9173F709BA90380026E9FF /* FrameBufferGL.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D733D5E062893E7006265D9 /* FrameBufferGL.hxx */; }; 2D9173F809BA90380026E9FF /* FrameBufferSoft.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D733D62062893E7006265D9 /* FrameBufferSoft.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 */; }; 2D9173FD09BA90380026E9FF /* SoundSDL.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDA34030665817D00CDD299 /* SoundSDL.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 */; }; 2D91745409BA90380026E9FF /* ColorWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20F9E508C603EC00A73076 /* ColorWidget.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 */; }; 2D91746809BA90380026E9FF /* MediaFactory.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D05FF5B096E261E00A518FE /* MediaFactory.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 */; }; 2D91748809BA90380026E9FF /* CartMC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF360627AE07006BEC99 /* CartMC.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 */; }; 2D91749609BA90380026E9FF /* Random.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF880627AE34006BEC99 /* Random.cxx */; }; 2D91749709BA90380026E9FF /* Serializer.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF8A0627AE34006BEC99 /* Serializer.cxx */; }; 2D91749809BA90380026E9FF /* Switches.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF8E0627AE34006BEC99 /* Switches.cxx */; }; 2D91749909BA90380026E9FF /* TIA.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF900627AE34006BEC99 /* TIA.cxx */; }; 2D91749F09BA90380026E9FF /* FrameBufferGL.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D733D5D062893E7006265D9 /* FrameBufferGL.cxx */; }; 2D9174A009BA90380026E9FF /* FrameBufferSoft.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D733D61062893E7006265D9 /* FrameBufferSoft.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 */; }; 2D9174A509BA90380026E9FF /* SoundSDL.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDA34020665817D00CDD299 /* SoundSDL.cxx */; }; 2D9174A709BA90380026E9FF /* mainSDL.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEA0A0845700300812C11 /* mainSDL.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 */; }; 2D9174CB09BA90380026E9FF /* PackedBitArray.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D403BCE08611A69001E31A1 /* PackedBitArray.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 */; }; 2D9174DC09BA90380026E9FF /* Expression.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DF971DE0892CEA400F64D23 /* Expression.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 */; }; 2D9174F609BA90380026E9FF /* ColorWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20F9E408C603EC00A73076 /* ColorWidget.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 */; }; 2D91751109BA90380026E9FF /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D4764C806683C5F00F63D87 /* SDL.framework */; }; 2D91751209BA90380026E9FF /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D17D98E08BC398400E47F69 /* ApplicationServices.framework */; }; 2D91751409BA90380026E9FF /* SDL.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 2D4764C806683C5F00F63D87 /* SDL.framework */; }; 2DEFB40C09C3386F00754289 /* Cart.icns in Resources */ = {isa = PBXBuildFile; fileRef = 2DEFB40B09C3386F00754289 /* Cart.icns */; }; DC07A3C80CAD738A009B4BC9 /* StateManager.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC07A3C60CAD738A009B4BC9 /* StateManager.cxx */; }; DC07A3C90CAD738A009B4BC9 /* StateManager.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC07A3C70CAD738A009B4BC9 /* StateManager.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 */; }; DC1FC18A0DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC1FC1880DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx */; }; DC1FC18B0DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1FC1890DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx */; }; DC36D2C814CAFAB0007DC821 /* CartFA2.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC36D2C614CAFAB0007DC821 /* CartFA2.cxx */; }; DC36D2C914CAFAB0007DC821 /* CartFA2.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC36D2C714CAFAB0007DC821 /* CartFA2.hxx */; }; DC3EE2DA1417801800F9DA4A /* FBSurfaceGL.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE2D61417801800F9DA4A /* FBSurfaceGL.cxx */; }; DC3EE2DB1417801800F9DA4A /* FBSurfaceGL.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3EE2D71417801800F9DA4A /* FBSurfaceGL.hxx */; }; DC3EE2DC1417801800F9DA4A /* FBSurfaceTIA.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE2D81417801800F9DA4A /* FBSurfaceTIA.cxx */; }; DC3EE2DD1417801800F9DA4A /* FBSurfaceTIA.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3EE2D91417801800F9DA4A /* FBSurfaceTIA.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 */; }; DC56FCDE14CCCC4900A31CC3 /* MouseControl.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC56FCDC14CCCC4900A31CC3 /* MouseControl.cxx */; }; DC56FCDF14CCCC4900A31CC3 /* MouseControl.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC56FCDD14CCCC4900A31CC3 /* MouseControl.hxx */; }; 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 */; }; DC5EE7C214F7C165001C628C /* NTSCFilter.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC5EE7C014F7C165001C628C /* NTSCFilter.cxx */; }; DC5EE7C314F7C165001C628C /* NTSCFilter.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5EE7C114F7C165001C628C /* NTSCFilter.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 */; }; DC676A571729A0B000E4E73D /* CartMCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A3B1729A0B000E4E73D /* CartMCWidget.cxx */; }; DC676A581729A0B000E4E73D /* CartMCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A3C1729A0B000E4E73D /* CartMCWidget.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 */; }; 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 */; }; 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 */; }; DC74D6A1138D4D7E00F05C5C /* StringList.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC74D69F138D4D7E00F05C5C /* StringList.hxx */; }; DC74D6A2138D4D7E00F05C5C /* StringParser.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC74D6A0138D4D7E00F05C5C /* StringParser.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 */; }; DC932D470F278A5200FEFEFC /* TIATables.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC932D420F278A5200FEFEFC /* TIATables.cxx */; }; DC932D480F278A5200FEFEFC /* TIATables.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC932D430F278A5200FEFEFC /* TIATables.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 */; }; DCA23AE90D75B22500F77B33 /* CartX07.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCA23AE70D75B22500F77B33 /* CartX07.cxx */; }; DCA23AEA0D75B22500F77B33 /* CartX07.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCA23AE80D75B22500F77B33 /* CartX07.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 */; }; DCAD60A81152F8BD00BC4184 /* CartDPCPlus.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAD60A61152F8BD00BC4184 /* CartDPCPlus.cxx */; }; DCAD60A91152F8BD00BC4184 /* CartDPCPlus.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAD60A71152F8BD00BC4184 /* CartDPCPlus.hxx */; }; DCC467F014FBECC700E15508 /* atari_ntsc_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC467ED14FBECC700E15508 /* atari_ntsc_impl.h */; }; DCC467F114FBECC700E15508 /* atari_ntsc.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC467EE14FBECC700E15508 /* atari_ntsc.c */; }; DCC467F214FBECC700E15508 /* atari_ntsc.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC467EF14FBECC700E15508 /* atari_ntsc.h */; }; 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 */; }; DCC527D410B9DA19005E1287 /* NullDev.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCC527CC10B9DA19005E1287 /* NullDev.cxx */; }; 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 */; }; 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 */; }; DCD56D3C0B247DB40092F9F8 /* RectList.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCD56D3A0B247DB40092F9F8 /* RectList.cxx */; }; DCD56D3D0B247DB40092F9F8 /* RectList.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCD56D3B0B247DB40092F9F8 /* RectList.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 */; }; 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 */; }; DCE6EB220DD9ADA00047AC28 /* TrackBall.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCE6EB200DD9ADA00047AC28 /* TrackBall.cxx */; }; DCE6EB230DD9ADA00047AC28 /* TrackBall.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCE6EB210DD9ADA00047AC28 /* TrackBall.hxx */; }; DCEECE560B5E5E540021D754 /* Cart0840.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCEECE540B5E5E540021D754 /* Cart0840.cxx */; }; DCEECE570B5E5E540021D754 /* Cart0840.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCEECE550B5E5E540021D754 /* Cart0840.hxx */; }; DCF467B50F93993B00B25D7A /* Array.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF467B10F93993B00B25D7A /* Array.hxx */; }; DCF467B60F93993B00B25D7A /* SharedPtr.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF467B20F93993B00B25D7A /* SharedPtr.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 */; }; 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 */; }; DCFFE59D12100E1400DFA000 /* ComboDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCFFE59B12100E1400DFA000 /* ComboDialog.cxx */; }; DCFFE59E12100E1400DFA000 /* ComboDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCFFE59C12100E1400DFA000 /* ComboDialog.hxx */; }; /* End PBXBuildFile section */ /* Begin PBXBuildRule section */ 2D91751B09BA90380026E9FF /* PBXBuildRule */ = { isa = PBXBuildRule; compilerSpec = com.apple.compilers.llvm.clang.1_0; fileType = sourcecode.c; isEditable = 1; outputFiles = ( ); }; DC5EE7DF14F7C32D001C628C /* PBXBuildRule */ = { isa = PBXBuildRule; compilerSpec = com.apple.compilers.llvm.clang.1_0; fileType = sourcecode.asm; isEditable = 1; outputFiles = ( ); }; DC5EE7E014F7C32D001C628C /* PBXBuildRule */ = { isa = PBXBuildRule; compilerSpec = com.apple.compilers.llvm.clang.1_0; fileType = sourcecode.cpp; isEditable = 1; outputFiles = ( ); }; /* End PBXBuildRule section */ /* Begin PBXCopyFilesBuildPhase section */ 2D91751309BA90380026E9FF /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( 2D91751409BA90380026E9FF /* SDL.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 = ""; }; 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 2D02207F08A301F200B9C76B /* InputTextDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = InputTextDialog.cxx; path = ../gui/InputTextDialog.cxx; sourceTree = SOURCE_ROOT; }; 2D02208008A301F200B9C76B /* InputTextDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = InputTextDialog.hxx; path = ../gui/InputTextDialog.hxx; sourceTree = SOURCE_ROOT; }; 2D05FF5B096E261E00A518FE /* MediaFactory.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MediaFactory.hxx; path = ../emucore/MediaFactory.hxx; sourceTree = SOURCE_ROOT; }; 2D05FF5E096E269100A518FE /* EventMappingWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = EventMappingWidget.cxx; path = ../gui/EventMappingWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D05FF5F096E269100A518FE /* EventMappingWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = EventMappingWidget.hxx; path = ../gui/EventMappingWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D05FF60096E269100A518FE /* InputDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = InputDialog.cxx; path = ../gui/InputDialog.cxx; sourceTree = SOURCE_ROOT; }; 2D05FF61096E269100A518FE /* InputDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = InputDialog.hxx; path = ../gui/InputDialog.hxx; sourceTree = SOURCE_ROOT; }; 2D113E090672BF2100317017 /* ../../docs */ = {isa = PBXFileReference; explicitFileType = folder; 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 = ""; }; 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; }; 2D20F9E408C603EC00A73076 /* ColorWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ColorWidget.cxx; path = ../debugger/gui/ColorWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9E508C603EC00A73076 /* ColorWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = ColorWidget.hxx; path = ../debugger/gui/ColorWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9E608C603EC00A73076 /* CpuWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CpuWidget.cxx; path = ../debugger/gui/CpuWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9E708C603EC00A73076 /* CpuWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CpuWidget.hxx; path = ../debugger/gui/CpuWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9E808C603EC00A73076 /* DataGridOpsWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DataGridOpsWidget.cxx; path = ../debugger/gui/DataGridOpsWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9E908C603EC00A73076 /* DataGridOpsWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = DataGridOpsWidget.hxx; path = ../debugger/gui/DataGridOpsWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9EA08C603EC00A73076 /* DataGridWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DataGridWidget.cxx; path = ../debugger/gui/DataGridWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9EB08C603EC00A73076 /* DataGridWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = DataGridWidget.hxx; path = ../debugger/gui/DataGridWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9EC08C603EC00A73076 /* DebuggerDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DebuggerDialog.cxx; path = ../debugger/gui/DebuggerDialog.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9ED08C603EC00A73076 /* DebuggerDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = DebuggerDialog.hxx; path = ../debugger/gui/DebuggerDialog.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9EE08C603EC00A73076 /* PromptWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PromptWidget.cxx; path = ../debugger/gui/PromptWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9EF08C603EC00A73076 /* PromptWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = PromptWidget.hxx; path = ../debugger/gui/PromptWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9F008C603EC00A73076 /* RamWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RamWidget.cxx; path = ../debugger/gui/RamWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9F108C603EC00A73076 /* RamWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RamWidget.hxx; path = ../debugger/gui/RamWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9F208C603EC00A73076 /* RomListWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RomListWidget.cxx; path = ../debugger/gui/RomListWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9F308C603EC00A73076 /* RomListWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RomListWidget.hxx; path = ../debugger/gui/RomListWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9F408C603EC00A73076 /* RomWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RomWidget.cxx; path = ../debugger/gui/RomWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9F508C603EC00A73076 /* RomWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RomWidget.hxx; path = ../debugger/gui/RomWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9F608C603EC00A73076 /* TiaInfoWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TiaInfoWidget.cxx; path = ../debugger/gui/TiaInfoWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9F708C603EC00A73076 /* TiaInfoWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TiaInfoWidget.hxx; path = ../debugger/gui/TiaInfoWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9F808C603EC00A73076 /* TiaOutputWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TiaOutputWidget.cxx; path = ../debugger/gui/TiaOutputWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9F908C603EC00A73076 /* TiaOutputWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TiaOutputWidget.hxx; path = ../debugger/gui/TiaOutputWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9FA08C603EC00A73076 /* TiaWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TiaWidget.cxx; path = ../debugger/gui/TiaWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9FB08C603EC00A73076 /* TiaWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TiaWidget.hxx; path = ../debugger/gui/TiaWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9FC08C603EC00A73076 /* ToggleBitWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ToggleBitWidget.cxx; path = ../debugger/gui/ToggleBitWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9FD08C603EC00A73076 /* ToggleBitWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = ToggleBitWidget.hxx; path = ../debugger/gui/ToggleBitWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9FE08C603EC00A73076 /* TogglePixelWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TogglePixelWidget.cxx; path = ../debugger/gui/TogglePixelWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9FF08C603EC00A73076 /* TogglePixelWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TogglePixelWidget.hxx; path = ../debugger/gui/TogglePixelWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20FA0008C603EC00A73076 /* ToggleWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ToggleWidget.cxx; path = ../debugger/gui/ToggleWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20FA0108C603EC00A73076 /* ToggleWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = ToggleWidget.hxx; path = ../debugger/gui/ToggleWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D23318F0900B5EF00613B1F /* AudioWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AudioWidget.cxx; path = ../debugger/gui/AudioWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D2331900900B5EF00613B1F /* AudioWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = AudioWidget.hxx; path = ../debugger/gui/AudioWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D28DDE409DC2D9F00A17585 /* MenusEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenusEvents.h; sourceTree = ""; }; 2D30F8750868A4DB00938B9D /* TIADebug.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TIADebug.cxx; path = ../debugger/TIADebug.cxx; sourceTree = SOURCE_ROOT; }; 2D30F8760868A4DB00938B9D /* TIADebug.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TIADebug.hxx; path = ../debugger/TIADebug.hxx; sourceTree = SOURCE_ROOT; }; 2D313F0A0879C4C0005BD3E5 /* YaccParser.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = YaccParser.cxx; path = ../yacc/YaccParser.cxx; sourceTree = SOURCE_ROOT; }; 2D313F0B0879C4C0005BD3E5 /* YaccParser.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = YaccParser.hxx; path = ../yacc/YaccParser.hxx; sourceTree = SOURCE_ROOT; }; 2D403BA0086116D1001E31A1 /* EditableWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = EditableWidget.cxx; path = ../gui/EditableWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D403BA1086116D1001E31A1 /* EditableWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = EditableWidget.hxx; path = ../gui/EditableWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D403BA4086116D1001E31A1 /* EditTextWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = EditTextWidget.cxx; path = ../gui/EditTextWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D403BA5086116D1001E31A1 /* EditTextWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = EditTextWidget.hxx; path = ../gui/EditTextWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D403BCE08611A69001E31A1 /* PackedBitArray.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PackedBitArray.cxx; path = ../debugger/PackedBitArray.cxx; sourceTree = SOURCE_ROOT; }; 2D403BCF08611A69001E31A1 /* PackedBitArray.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = PackedBitArray.hxx; path = ../debugger/PackedBitArray.hxx; sourceTree = SOURCE_ROOT; }; 2D4764C806683C5F00F63D87 /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SDL.framework; sourceTree = SOURCE_ROOT; }; 2D659E2D085D3DD6005D96C8 /* Debugger.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Debugger.cxx; path = ../debugger/Debugger.cxx; sourceTree = SOURCE_ROOT; }; 2D659E2E085D3DD6005D96C8 /* Debugger.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Debugger.hxx; path = ../debugger/Debugger.hxx; sourceTree = SOURCE_ROOT; }; 2D659E31085D3DD6005D96C8 /* DebuggerParser.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DebuggerParser.cxx; path = ../debugger/DebuggerParser.cxx; sourceTree = SOURCE_ROOT; }; 2D659E32085D3DD6005D96C8 /* DebuggerParser.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = DebuggerParser.hxx; path = ../debugger/DebuggerParser.hxx; sourceTree = SOURCE_ROOT; }; 2D6CC10308C811A600B8F642 /* TiaZoomWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TiaZoomWidget.cxx; path = ../debugger/gui/TiaZoomWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D6CC10408C811A600B8F642 /* TiaZoomWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TiaZoomWidget.hxx; path = ../debugger/gui/TiaZoomWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D733D5D062893E7006265D9 /* FrameBufferGL.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = FrameBufferGL.cxx; path = ../common/FrameBufferGL.cxx; sourceTree = SOURCE_ROOT; }; 2D733D5E062893E7006265D9 /* FrameBufferGL.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FrameBufferGL.hxx; path = ../common/FrameBufferGL.hxx; sourceTree = SOURCE_ROOT; }; 2D733D61062893E7006265D9 /* FrameBufferSoft.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = FrameBufferSoft.cxx; path = ../common/FrameBufferSoft.cxx; sourceTree = SOURCE_ROOT; }; 2D733D62062893E7006265D9 /* FrameBufferSoft.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FrameBufferSoft.hxx; path = ../common/FrameBufferSoft.hxx; sourceTree = SOURCE_ROOT; }; 2D733D6E062895B2006265D9 /* EventHandler.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = EventHandler.cxx; path = ../emucore/EventHandler.cxx; sourceTree = SOURCE_ROOT; }; 2D733D6F062895B2006265D9 /* EventHandler.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = EventHandler.hxx; path = ../emucore/EventHandler.hxx; sourceTree = SOURCE_ROOT; }; 2D733D70062895B2006265D9 /* FrameBuffer.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = FrameBuffer.cxx; path = ../emucore/FrameBuffer.cxx; sourceTree = SOURCE_ROOT; }; 2D733D71062895B2006265D9 /* FrameBuffer.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FrameBuffer.hxx; path = ../emucore/FrameBuffer.hxx; sourceTree = SOURCE_ROOT; }; 2D733D77062895F1006265D9 /* Settings.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Settings.hxx; path = ../emucore/Settings.hxx; sourceTree = SOURCE_ROOT; }; 2D73959308C3EB4E0060BB99 /* CommandDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CommandDialog.cxx; path = ../gui/CommandDialog.cxx; sourceTree = SOURCE_ROOT; }; 2D73959408C3EB4E0060BB99 /* CommandDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CommandDialog.hxx; path = ../gui/CommandDialog.hxx; sourceTree = SOURCE_ROOT; }; 2D73959508C3EB4E0060BB99 /* CommandMenu.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CommandMenu.cxx; path = ../gui/CommandMenu.cxx; sourceTree = SOURCE_ROOT; }; 2D73959608C3EB4E0060BB99 /* CommandMenu.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CommandMenu.hxx; path = ../gui/CommandMenu.hxx; sourceTree = SOURCE_ROOT; }; 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; name = ConsoleFont.hxx; path = ../gui/ConsoleFont.hxx; sourceTree = SOURCE_ROOT; }; 2D9217FB0857CC88001D664B /* Font.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Font.cxx; path = ../gui/Font.cxx; sourceTree = SOURCE_ROOT; }; 2D9217FC0857CC88001D664B /* Font.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Font.hxx; path = ../gui/Font.hxx; sourceTree = SOURCE_ROOT; }; 2D944848062904E800DD9879 /* Settings.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Settings.cxx; path = ../emucore/Settings.cxx; sourceTree = SOURCE_ROOT; }; 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; name = Cart3E.cxx; path = ../emucore/Cart3E.cxx; sourceTree = SOURCE_ROOT; }; 2D9555DA0880E78000466554 /* Cart3E.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cart3E.hxx; path = ../emucore/Cart3E.hxx; sourceTree = SOURCE_ROOT; }; 2D9555DD0880E79600466554 /* CpuDebug.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CpuDebug.cxx; path = ../debugger/CpuDebug.cxx; sourceTree = SOURCE_ROOT; }; 2D9555DE0880E79600466554 /* CpuDebug.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CpuDebug.hxx; path = ../debugger/CpuDebug.hxx; sourceTree = SOURCE_ROOT; }; 2DDA34020665817D00CDD299 /* SoundSDL.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SoundSDL.cxx; path = ../common/SoundSDL.cxx; sourceTree = SOURCE_ROOT; }; 2DDA34030665817D00CDD299 /* SoundSDL.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = SoundSDL.hxx; path = ../common/SoundSDL.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEA0A0845700300812C11 /* mainSDL.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = mainSDL.cxx; path = ../common/mainSDL.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEA0C0845708800812C11 /* FSNodePOSIX.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = FSNodePOSIX.cxx; path = ../unix/FSNodePOSIX.cxx; sourceTree = SOURCE_ROOT; }; 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; name = AboutDialog.cxx; path = ../gui/AboutDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAA4084578BF00812C11 /* AboutDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = AboutDialog.hxx; path = ../gui/AboutDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAA6084578BF00812C11 /* AudioDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AudioDialog.cxx; path = ../gui/AudioDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAA7084578BF00812C11 /* AudioDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = AudioDialog.hxx; path = ../gui/AudioDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAA8084578BF00812C11 /* BrowserDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = BrowserDialog.cxx; path = ../gui/BrowserDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAA9084578BF00812C11 /* BrowserDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = BrowserDialog.hxx; path = ../gui/BrowserDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAAA084578BF00812C11 /* Command.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Command.hxx; path = ../gui/Command.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAAB084578BF00812C11 /* Dialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Dialog.cxx; path = ../gui/Dialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAAC084578BF00812C11 /* Dialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Dialog.hxx; path = ../gui/Dialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAAD084578BF00812C11 /* DialogContainer.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DialogContainer.cxx; path = ../gui/DialogContainer.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAAE084578BF00812C11 /* DialogContainer.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = DialogContainer.hxx; path = ../gui/DialogContainer.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAB2084578BF00812C11 /* GameInfoDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = GameInfoDialog.cxx; path = ../gui/GameInfoDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAB3084578BF00812C11 /* GameInfoDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = GameInfoDialog.hxx; path = ../gui/GameInfoDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAB4084578BF00812C11 /* GameList.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = GameList.cxx; path = ../gui/GameList.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAB5084578BF00812C11 /* GameList.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = GameList.hxx; path = ../gui/GameList.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAB6084578BF00812C11 /* GuiObject.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = GuiObject.hxx; path = ../gui/GuiObject.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAB8084578BF00812C11 /* HelpDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = HelpDialog.cxx; path = ../gui/HelpDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAB9084578BF00812C11 /* HelpDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = HelpDialog.hxx; path = ../gui/HelpDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEABA084578BF00812C11 /* Launcher.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Launcher.cxx; path = ../gui/Launcher.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEABB084578BF00812C11 /* Launcher.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Launcher.hxx; path = ../gui/Launcher.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEABC084578BF00812C11 /* LauncherDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = LauncherDialog.cxx; path = ../gui/LauncherDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEABD084578BF00812C11 /* LauncherDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = LauncherDialog.hxx; path = ../gui/LauncherDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC0084578BF00812C11 /* ListWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ListWidget.cxx; path = ../gui/ListWidget.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC1084578BF00812C11 /* ListWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = ListWidget.hxx; path = ../gui/ListWidget.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC2084578BF00812C11 /* Menu.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Menu.cxx; path = ../gui/Menu.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC3084578BF00812C11 /* Menu.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Menu.hxx; path = ../gui/Menu.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC4084578BF00812C11 /* OptionsDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = OptionsDialog.cxx; path = ../gui/OptionsDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC5084578BF00812C11 /* OptionsDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = OptionsDialog.hxx; path = ../gui/OptionsDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC6084578BF00812C11 /* PopUpWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PopUpWidget.cxx; path = ../gui/PopUpWidget.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC7084578BF00812C11 /* PopUpWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = PopUpWidget.hxx; path = ../gui/PopUpWidget.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC8084578BF00812C11 /* ProgressDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ProgressDialog.cxx; path = ../gui/ProgressDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC9084578BF00812C11 /* ProgressDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = ProgressDialog.hxx; path = ../gui/ProgressDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEACA084578BF00812C11 /* ScrollBarWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ScrollBarWidget.cxx; path = ../gui/ScrollBarWidget.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEACB084578BF00812C11 /* ScrollBarWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = ScrollBarWidget.hxx; path = ../gui/ScrollBarWidget.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAD0084578BF00812C11 /* TabWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TabWidget.cxx; path = ../gui/TabWidget.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAD1084578BF00812C11 /* TabWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TabWidget.hxx; path = ../gui/TabWidget.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAD2084578BF00812C11 /* VideoDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = VideoDialog.cxx; path = ../gui/VideoDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAD3084578BF00812C11 /* VideoDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = VideoDialog.hxx; path = ../gui/VideoDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAD4084578BF00812C11 /* Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Widget.cxx; path = ../gui/Widget.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAD5084578BF00812C11 /* Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Widget.hxx; path = ../gui/Widget.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEB7008457B7D00812C11 /* CartUA.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartUA.cxx; path = ../emucore/CartUA.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEB7108457B7D00812C11 /* CartUA.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartUA.hxx; path = ../emucore/CartUA.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEB7208457B7D00812C11 /* FSNode.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = FSNode.cxx; path = ../emucore/FSNode.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEB7308457B7D00812C11 /* FSNode.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FSNode.hxx; path = ../emucore/FSNode.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEB7408457B7D00812C11 /* OSystem.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = OSystem.cxx; path = ../emucore/OSystem.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEB7508457B7D00812C11 /* OSystem.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = OSystem.hxx; path = ../emucore/OSystem.hxx; sourceTree = SOURCE_ROOT; }; 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; name = Booster.cxx; path = ../emucore/Booster.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF110627AE07006BEC99 /* Booster.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Booster.hxx; path = ../emucore/Booster.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF120627AE07006BEC99 /* Cart.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Cart.cxx; path = ../emucore/Cart.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF130627AE07006BEC99 /* Cart.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cart.hxx; path = ../emucore/Cart.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF140627AE07006BEC99 /* Cart2K.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Cart2K.cxx; path = ../emucore/Cart2K.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF150627AE07006BEC99 /* Cart2K.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cart2K.hxx; path = ../emucore/Cart2K.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF160627AE07006BEC99 /* Cart3F.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Cart3F.cxx; path = ../emucore/Cart3F.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF170627AE07006BEC99 /* Cart3F.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cart3F.hxx; path = ../emucore/Cart3F.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF180627AE07006BEC99 /* Cart4K.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Cart4K.cxx; path = ../emucore/Cart4K.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF190627AE07006BEC99 /* Cart4K.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cart4K.hxx; path = ../emucore/Cart4K.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF1A0627AE07006BEC99 /* CartAR.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartAR.cxx; path = ../emucore/CartAR.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF1B0627AE07006BEC99 /* CartAR.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartAR.hxx; path = ../emucore/CartAR.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF1C0627AE07006BEC99 /* CartCV.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartCV.cxx; path = ../emucore/CartCV.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF1D0627AE07006BEC99 /* CartCV.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartCV.hxx; path = ../emucore/CartCV.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF1E0627AE07006BEC99 /* CartDPC.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartDPC.cxx; path = ../emucore/CartDPC.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF1F0627AE07006BEC99 /* CartDPC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartDPC.hxx; path = ../emucore/CartDPC.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF200627AE07006BEC99 /* CartE0.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartE0.cxx; path = ../emucore/CartE0.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF210627AE07006BEC99 /* CartE0.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartE0.hxx; path = ../emucore/CartE0.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF220627AE07006BEC99 /* CartE7.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartE7.cxx; path = ../emucore/CartE7.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF230627AE07006BEC99 /* CartE7.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartE7.hxx; path = ../emucore/CartE7.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF240627AE07006BEC99 /* CartF4.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartF4.cxx; path = ../emucore/CartF4.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF250627AE07006BEC99 /* CartF4.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartF4.hxx; path = ../emucore/CartF4.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF260627AE07006BEC99 /* CartF4SC.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartF4SC.cxx; path = ../emucore/CartF4SC.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF270627AE07006BEC99 /* CartF4SC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartF4SC.hxx; path = ../emucore/CartF4SC.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF280627AE07006BEC99 /* CartF6.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartF6.cxx; path = ../emucore/CartF6.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF290627AE07006BEC99 /* CartF6.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartF6.hxx; path = ../emucore/CartF6.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF2A0627AE07006BEC99 /* CartF6SC.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartF6SC.cxx; path = ../emucore/CartF6SC.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF2B0627AE07006BEC99 /* CartF6SC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartF6SC.hxx; path = ../emucore/CartF6SC.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF2C0627AE07006BEC99 /* CartF8.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartF8.cxx; path = ../emucore/CartF8.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF2D0627AE07006BEC99 /* CartF8.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartF8.hxx; path = ../emucore/CartF8.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF2E0627AE07006BEC99 /* CartF8SC.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartF8SC.cxx; path = ../emucore/CartF8SC.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF2F0627AE07006BEC99 /* CartF8SC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartF8SC.hxx; path = ../emucore/CartF8SC.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF320627AE07006BEC99 /* CartFE.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartFE.cxx; path = ../emucore/CartFE.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF330627AE07006BEC99 /* CartFE.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartFE.hxx; path = ../emucore/CartFE.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF360627AE07006BEC99 /* CartMC.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartMC.cxx; path = ../emucore/CartMC.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF370627AE07006BEC99 /* CartMC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartMC.hxx; path = ../emucore/CartMC.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF380627AE07006BEC99 /* Console.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Console.cxx; path = ../emucore/Console.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF390627AE07006BEC99 /* Console.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Console.hxx; path = ../emucore/Console.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF3A0627AE07006BEC99 /* Control.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Control.cxx; path = ../emucore/Control.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF3B0627AE07006BEC99 /* Control.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Control.hxx; path = ../emucore/Control.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF3E0627AE07006BEC99 /* Driving.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Driving.cxx; path = ../emucore/Driving.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF3F0627AE07006BEC99 /* Driving.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Driving.hxx; path = ../emucore/Driving.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF410627AE07006BEC99 /* Event.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Event.hxx; path = ../emucore/Event.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF420627AE07006BEC99 /* Joystick.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Joystick.cxx; path = ../emucore/Joystick.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF430627AE07006BEC99 /* Joystick.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Joystick.hxx; path = ../emucore/Joystick.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF440627AE07006BEC99 /* Keyboard.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Keyboard.cxx; path = ../emucore/Keyboard.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF450627AE07006BEC99 /* Keyboard.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Keyboard.hxx; path = ../emucore/Keyboard.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF7C0627AE33006BEC99 /* M6532.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = M6532.cxx; path = ../emucore/M6532.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF7D0627AE33006BEC99 /* M6532.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = M6532.hxx; path = ../emucore/M6532.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF7E0627AE33006BEC99 /* MD5.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = MD5.cxx; path = ../emucore/MD5.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF7F0627AE34006BEC99 /* MD5.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MD5.hxx; path = ../emucore/MD5.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF820627AE34006BEC99 /* Paddles.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Paddles.cxx; path = ../emucore/Paddles.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF830627AE34006BEC99 /* Paddles.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Paddles.hxx; path = ../emucore/Paddles.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF840627AE34006BEC99 /* Props.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Props.cxx; path = ../emucore/Props.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF850627AE34006BEC99 /* Props.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Props.hxx; path = ../emucore/Props.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF860627AE34006BEC99 /* PropsSet.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PropsSet.cxx; path = ../emucore/PropsSet.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF870627AE34006BEC99 /* PropsSet.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = PropsSet.hxx; path = ../emucore/PropsSet.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF880627AE34006BEC99 /* Random.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Random.cxx; path = ../emucore/Random.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF890627AE34006BEC99 /* Random.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Random.hxx; path = ../emucore/Random.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF8A0627AE34006BEC99 /* Serializer.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Serializer.cxx; path = ../emucore/Serializer.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF8B0627AE34006BEC99 /* Serializer.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Serializer.hxx; path = ../emucore/Serializer.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF8D0627AE34006BEC99 /* Sound.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Sound.hxx; path = ../emucore/Sound.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF8E0627AE34006BEC99 /* Switches.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Switches.cxx; path = ../emucore/Switches.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF8F0627AE34006BEC99 /* Switches.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Switches.hxx; path = ../emucore/Switches.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF900627AE34006BEC99 /* TIA.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TIA.cxx; path = ../emucore/TIA.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF910627AE34006BEC99 /* TIA.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TIA.hxx; path = ../emucore/TIA.hxx; sourceTree = SOURCE_ROOT; }; 2DE7242D08CE910900C889A8 /* TIASnd.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TIASnd.cxx; path = ../emucore/TIASnd.cxx; sourceTree = SOURCE_ROOT; }; 2DE7242E08CE910900C889A8 /* TIASnd.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TIASnd.hxx; path = ../emucore/TIASnd.hxx; sourceTree = SOURCE_ROOT; }; 2DEB3D4C0629BD24007EBBD3 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; 2DEF21F808BC033500B246B4 /* CheckListWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CheckListWidget.cxx; path = ../gui/CheckListWidget.cxx; sourceTree = SOURCE_ROOT; }; 2DEF21F908BC033500B246B4 /* CheckListWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CheckListWidget.hxx; path = ../gui/CheckListWidget.hxx; sourceTree = SOURCE_ROOT; }; 2DEF21FA08BC033500B246B4 /* StringListWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = StringListWidget.cxx; path = ../gui/StringListWidget.cxx; sourceTree = SOURCE_ROOT; }; 2DEF21FB08BC033500B246B4 /* StringListWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = StringListWidget.hxx; path = ../gui/StringListWidget.hxx; sourceTree = SOURCE_ROOT; }; 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; name = DebuggerSystem.hxx; path = ../debugger/DebuggerSystem.hxx; sourceTree = SOURCE_ROOT; }; 2DF971DE0892CEA400F64D23 /* Expression.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Expression.cxx; path = ../debugger/Expression.cxx; sourceTree = SOURCE_ROOT; }; 2DF971DF0892CEA400F64D23 /* Expression.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Expression.hxx; path = ../debugger/Expression.hxx; sourceTree = SOURCE_ROOT; }; B2F367C504C7ADC700A80002 /* SDLMain.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; path = SDLMain.nib; sourceTree = ""; }; DC07A3C60CAD738A009B4BC9 /* StateManager.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = StateManager.cxx; path = ../emucore/StateManager.cxx; sourceTree = SOURCE_ROOT; }; DC07A3C70CAD738A009B4BC9 /* StateManager.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = StateManager.hxx; path = ../emucore/StateManager.hxx; sourceTree = SOURCE_ROOT; }; DC0984830D3985160073C852 /* CartSB.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartSB.cxx; path = ../emucore/CartSB.cxx; sourceTree = SOURCE_ROOT; }; DC0984840D3985160073C852 /* CartSB.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartSB.hxx; path = ../emucore/CartSB.hxx; sourceTree = SOURCE_ROOT; }; DC0DF8670F0DAAF500B0F1F3 /* GlobalPropsDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GlobalPropsDialog.cxx; path = ../gui/GlobalPropsDialog.cxx; sourceTree = SOURCE_ROOT; }; DC0DF8680F0DAAF500B0F1F3 /* GlobalPropsDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = GlobalPropsDialog.hxx; path = ../gui/GlobalPropsDialog.hxx; sourceTree = SOURCE_ROOT; }; DC11F78B0DB36933003B505E /* MT24LC256.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = MT24LC256.cxx; path = ../emucore/MT24LC256.cxx; sourceTree = SOURCE_ROOT; }; DC11F78C0DB36933003B505E /* MT24LC256.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MT24LC256.hxx; path = ../emucore/MT24LC256.hxx; sourceTree = SOURCE_ROOT; }; DC13B53D176FF2F500B8B4BB /* RomListSettings.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RomListSettings.cxx; path = ../debugger/gui/RomListSettings.cxx; sourceTree = SOURCE_ROOT; }; DC13B53E176FF2F500B8B4BB /* RomListSettings.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = RomListSettings.hxx; path = ../debugger/gui/RomListSettings.hxx; sourceTree = SOURCE_ROOT; }; DC173F740E2CAC1E00320F94 /* ContextMenu.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ContextMenu.cxx; path = ../gui/ContextMenu.cxx; sourceTree = SOURCE_ROOT; }; DC173F750E2CAC1E00320F94 /* ContextMenu.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = ContextMenu.hxx; path = ../gui/ContextMenu.hxx; sourceTree = SOURCE_ROOT; }; 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 = ""; }; DC36D2C614CAFAB0007DC821 /* CartFA2.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartFA2.cxx; path = ../emucore/CartFA2.cxx; sourceTree = SOURCE_ROOT; }; DC36D2C714CAFAB0007DC821 /* CartFA2.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartFA2.hxx; path = ../emucore/CartFA2.hxx; sourceTree = SOURCE_ROOT; }; DC3EE2D61417801800F9DA4A /* FBSurfaceGL.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FBSurfaceGL.cxx; path = ../common/FBSurfaceGL.cxx; sourceTree = SOURCE_ROOT; }; DC3EE2D71417801800F9DA4A /* FBSurfaceGL.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FBSurfaceGL.hxx; path = ../common/FBSurfaceGL.hxx; sourceTree = SOURCE_ROOT; }; DC3EE2D81417801800F9DA4A /* FBSurfaceTIA.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FBSurfaceTIA.cxx; path = ../common/FBSurfaceTIA.cxx; sourceTree = SOURCE_ROOT; }; DC3EE2D91417801800F9DA4A /* FBSurfaceTIA.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FBSurfaceTIA.hxx; path = ../common/FBSurfaceTIA.hxx; sourceTree = SOURCE_ROOT; }; DC4613650D92C03600D8DAB9 /* RomAuditDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RomAuditDialog.cxx; path = ../gui/RomAuditDialog.cxx; sourceTree = SOURCE_ROOT; }; DC4613660D92C03600D8DAB9 /* RomAuditDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RomAuditDialog.hxx; path = ../gui/RomAuditDialog.hxx; sourceTree = SOURCE_ROOT; }; DC47454A09C34BFA00EDDA3A /* BankRomCheat.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = BankRomCheat.cxx; path = ../cheat/BankRomCheat.cxx; sourceTree = SOURCE_ROOT; }; DC47454B09C34BFA00EDDA3A /* BankRomCheat.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = BankRomCheat.hxx; path = ../cheat/BankRomCheat.hxx; sourceTree = SOURCE_ROOT; }; DC47454C09C34BFA00EDDA3A /* Cheat.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cheat.hxx; path = ../cheat/Cheat.hxx; sourceTree = SOURCE_ROOT; }; DC47454D09C34BFA00EDDA3A /* CheatCodeDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CheatCodeDialog.cxx; path = ../cheat/CheatCodeDialog.cxx; sourceTree = SOURCE_ROOT; }; DC47454E09C34BFA00EDDA3A /* CheatCodeDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CheatCodeDialog.hxx; path = ../cheat/CheatCodeDialog.hxx; sourceTree = SOURCE_ROOT; }; DC47454F09C34BFA00EDDA3A /* CheatManager.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CheatManager.cxx; path = ../cheat/CheatManager.cxx; sourceTree = SOURCE_ROOT; }; DC47455009C34BFA00EDDA3A /* CheatManager.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CheatManager.hxx; path = ../cheat/CheatManager.hxx; sourceTree = SOURCE_ROOT; }; DC47455109C34BFA00EDDA3A /* CheetahCheat.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CheetahCheat.cxx; path = ../cheat/CheetahCheat.cxx; sourceTree = SOURCE_ROOT; }; DC47455209C34BFA00EDDA3A /* CheetahCheat.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CheetahCheat.hxx; path = ../cheat/CheetahCheat.hxx; sourceTree = SOURCE_ROOT; }; DC47455309C34BFA00EDDA3A /* RamCheat.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RamCheat.cxx; path = ../cheat/RamCheat.cxx; sourceTree = SOURCE_ROOT; }; DC47455409C34BFA00EDDA3A /* RamCheat.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RamCheat.hxx; path = ../cheat/RamCheat.hxx; sourceTree = SOURCE_ROOT; }; DC487FB40DA5350900E12499 /* AtariVox.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AtariVox.cxx; path = ../emucore/AtariVox.cxx; sourceTree = SOURCE_ROOT; }; DC487FB50DA5350900E12499 /* AtariVox.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = AtariVox.hxx; path = ../emucore/AtariVox.hxx; sourceTree = SOURCE_ROOT; }; DC4AC6ED0DC8DACB00CD3AD2 /* RiotWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RiotWidget.cxx; path = ../debugger/gui/RiotWidget.cxx; sourceTree = SOURCE_ROOT; }; DC4AC6EE0DC8DACB00CD3AD2 /* RiotWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RiotWidget.hxx; path = ../debugger/gui/RiotWidget.hxx; sourceTree = SOURCE_ROOT; }; DC4AC6F10DC8DAEF00CD3AD2 /* SaveKey.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SaveKey.cxx; path = ../emucore/SaveKey.cxx; sourceTree = SOURCE_ROOT; }; DC4AC6F20DC8DAEF00CD3AD2 /* SaveKey.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = SaveKey.hxx; path = ../emucore/SaveKey.hxx; sourceTree = SOURCE_ROOT; }; DC56FCDC14CCCC4900A31CC3 /* MouseControl.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MouseControl.cxx; path = ../common/MouseControl.cxx; sourceTree = SOURCE_ROOT; }; DC56FCDD14CCCC4900A31CC3 /* MouseControl.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = MouseControl.hxx; path = ../common/MouseControl.hxx; sourceTree = SOURCE_ROOT; }; DC5BE4B117C913AC0091FD64 /* ConsoleBFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ConsoleBFont.hxx; path = ../gui/ConsoleBFont.hxx; sourceTree = SOURCE_ROOT; }; DC5BE4B217C913AC0091FD64 /* ConsoleMediumBFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ConsoleMediumBFont.hxx; path = ../gui/ConsoleMediumBFont.hxx; sourceTree = SOURCE_ROOT; }; DC5C768E14C26F7C0031EBC7 /* StellaKeys.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = StellaKeys.hxx; path = ../common/StellaKeys.hxx; sourceTree = SOURCE_ROOT; }; DC5D1AA6102C6FC900E59AC1 /* Stack.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Stack.hxx; path = ../common/Stack.hxx; sourceTree = SOURCE_ROOT; }; DC5D2C4E0F117CFD004D1660 /* Rect.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Rect.hxx; path = ../gui/Rect.hxx; sourceTree = SOURCE_ROOT; }; DC5D2C4F0F117CFD004D1660 /* StellaFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = StellaFont.hxx; path = ../gui/StellaFont.hxx; sourceTree = SOURCE_ROOT; }; DC5D2C500F117CFD004D1660 /* StellaLargeFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = StellaLargeFont.hxx; path = ../gui/StellaLargeFont.hxx; sourceTree = SOURCE_ROOT; }; DC5D2C510F117CFD004D1660 /* StellaMediumFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = StellaMediumFont.hxx; path = ../gui/StellaMediumFont.hxx; sourceTree = SOURCE_ROOT; }; DC5D2C5E0F129B1E004D1660 /* LauncherFilterDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LauncherFilterDialog.cxx; path = ../gui/LauncherFilterDialog.cxx; sourceTree = SOURCE_ROOT; }; DC5D2C5F0F129B1E004D1660 /* LauncherFilterDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = LauncherFilterDialog.hxx; path = ../gui/LauncherFilterDialog.hxx; sourceTree = SOURCE_ROOT; }; DC5EE7C014F7C165001C628C /* NTSCFilter.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NTSCFilter.cxx; path = ../common/tv_filters/NTSCFilter.cxx; sourceTree = SOURCE_ROOT; }; DC5EE7C114F7C165001C628C /* NTSCFilter.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = NTSCFilter.hxx; path = ../common/tv_filters/NTSCFilter.hxx; sourceTree = SOURCE_ROOT; }; DC6727081556F4860023653B /* CartCTY.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartCTY.cxx; path = ../emucore/CartCTY.cxx; sourceTree = SOURCE_ROOT; }; DC6727091556F4860023653B /* CartCTY.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartCTY.hxx; path = ../emucore/CartCTY.hxx; sourceTree = SOURCE_ROOT; }; DC67270A1556F4860023653B /* CartCTYTunes.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartCTYTunes.hxx; path = ../emucore/CartCTYTunes.hxx; sourceTree = SOURCE_ROOT; }; DC676A251729A0B000E4E73D /* Cart3EWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart3EWidget.cxx; path = ../debugger/gui/Cart3EWidget.cxx; sourceTree = SOURCE_ROOT; }; DC676A261729A0B000E4E73D /* Cart3EWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart3EWidget.hxx; path = ../debugger/gui/Cart3EWidget.hxx; sourceTree = SOURCE_ROOT; }; DC676A271729A0B000E4E73D /* Cart4A50Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart4A50Widget.cxx; path = ../debugger/gui/Cart4A50Widget.cxx; sourceTree = SOURCE_ROOT; }; DC676A281729A0B000E4E73D /* Cart4A50Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart4A50Widget.hxx; path = ../debugger/gui/Cart4A50Widget.hxx; sourceTree = SOURCE_ROOT; }; DC676A291729A0B000E4E73D /* CartARWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartARWidget.cxx; path = ../debugger/gui/CartARWidget.cxx; sourceTree = SOURCE_ROOT; }; DC676A2A1729A0B000E4E73D /* CartARWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartARWidget.hxx; path = ../debugger/gui/CartARWidget.hxx; sourceTree = SOURCE_ROOT; }; DC676A2B1729A0B000E4E73D /* CartCMWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartCMWidget.cxx; path = ../debugger/gui/CartCMWidget.cxx; sourceTree = SOURCE_ROOT; }; DC676A2C1729A0B000E4E73D /* CartCMWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartCMWidget.hxx; path = ../debugger/gui/CartCMWidget.hxx; sourceTree = SOURCE_ROOT; }; DC676A2D1729A0B000E4E73D /* CartCTYWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartCTYWidget.cxx; path = ../debugger/gui/CartCTYWidget.cxx; sourceTree = SOURCE_ROOT; }; DC676A2E1729A0B000E4E73D /* CartCTYWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartCTYWidget.hxx; path = ../debugger/gui/CartCTYWidget.hxx; sourceTree = SOURCE_ROOT; }; DC676A2F1729A0B000E4E73D /* CartDPCPlusWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDPCPlusWidget.cxx; path = ../debugger/gui/CartDPCPlusWidget.cxx; sourceTree = SOURCE_ROOT; }; DC676A301729A0B000E4E73D /* CartDPCPlusWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDPCPlusWidget.hxx; path = ../debugger/gui/CartDPCPlusWidget.hxx; sourceTree = SOURCE_ROOT; }; DC676A311729A0B000E4E73D /* CartDPCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDPCWidget.cxx; path = ../debugger/gui/CartDPCWidget.cxx; sourceTree = SOURCE_ROOT; }; DC676A321729A0B000E4E73D /* CartDPCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDPCWidget.hxx; path = ../debugger/gui/CartDPCWidget.hxx; sourceTree = SOURCE_ROOT; }; DC676A331729A0B000E4E73D /* CartE0Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartE0Widget.cxx; path = ../debugger/gui/CartE0Widget.cxx; sourceTree = SOURCE_ROOT; }; DC676A341729A0B000E4E73D /* CartE0Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartE0Widget.hxx; path = ../debugger/gui/CartE0Widget.hxx; sourceTree = SOURCE_ROOT; }; DC676A351729A0B000E4E73D /* CartE7Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartE7Widget.cxx; path = ../debugger/gui/CartE7Widget.cxx; sourceTree = SOURCE_ROOT; }; DC676A361729A0B000E4E73D /* CartE7Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartE7Widget.hxx; path = ../debugger/gui/CartE7Widget.hxx; sourceTree = SOURCE_ROOT; }; DC676A371729A0B000E4E73D /* CartFA2Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartFA2Widget.cxx; path = ../debugger/gui/CartFA2Widget.cxx; sourceTree = SOURCE_ROOT; }; DC676A381729A0B000E4E73D /* CartFA2Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartFA2Widget.hxx; path = ../debugger/gui/CartFA2Widget.hxx; sourceTree = SOURCE_ROOT; }; DC676A391729A0B000E4E73D /* CartFEWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartFEWidget.cxx; path = ../debugger/gui/CartFEWidget.cxx; sourceTree = SOURCE_ROOT; }; DC676A3A1729A0B000E4E73D /* CartFEWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartFEWidget.hxx; path = ../debugger/gui/CartFEWidget.hxx; sourceTree = SOURCE_ROOT; }; DC676A3B1729A0B000E4E73D /* CartMCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartMCWidget.cxx; path = ../debugger/gui/CartMCWidget.cxx; sourceTree = SOURCE_ROOT; }; DC676A3C1729A0B000E4E73D /* CartMCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartMCWidget.hxx; path = ../debugger/gui/CartMCWidget.hxx; sourceTree = SOURCE_ROOT; }; DC676A3D1729A0B000E4E73D /* CartSBWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartSBWidget.cxx; path = ../debugger/gui/CartSBWidget.cxx; sourceTree = SOURCE_ROOT; }; DC676A3E1729A0B000E4E73D /* CartSBWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartSBWidget.hxx; path = ../debugger/gui/CartSBWidget.hxx; sourceTree = SOURCE_ROOT; }; DC676A3F1729A0B000E4E73D /* CartX07Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartX07Widget.cxx; path = ../debugger/gui/CartX07Widget.cxx; sourceTree = SOURCE_ROOT; }; DC676A401729A0B000E4E73D /* CartX07Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartX07Widget.hxx; path = ../debugger/gui/CartX07Widget.hxx; sourceTree = SOURCE_ROOT; }; DC6967071361FD0A0036499D /* pngdebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pngdebug.h; path = ../libpng/pngdebug.h; sourceTree = SOURCE_ROOT; }; DC6967081361FD0A0036499D /* pnginfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pnginfo.h; path = ../libpng/pnginfo.h; sourceTree = SOURCE_ROOT; }; DC6967091361FD0A0036499D /* pnglibconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pnglibconf.h; path = ../libpng/pnglibconf.h; sourceTree = SOURCE_ROOT; }; DC69670A1361FD0A0036499D /* pngstruct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pngstruct.h; path = ../libpng/pngstruct.h; sourceTree = SOURCE_ROOT; }; DC6B2BA011037FF200F199A7 /* CartDebug.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDebug.cxx; path = ../debugger/CartDebug.cxx; sourceTree = SOURCE_ROOT; }; DC6B2BA111037FF200F199A7 /* CartDebug.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDebug.hxx; path = ../debugger/CartDebug.hxx; sourceTree = SOURCE_ROOT; }; DC6B2BA211037FF200F199A7 /* DiStella.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DiStella.cxx; path = ../debugger/DiStella.cxx; sourceTree = SOURCE_ROOT; }; DC6B2BA311037FF200F199A7 /* DiStella.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = DiStella.hxx; path = ../debugger/DiStella.hxx; sourceTree = SOURCE_ROOT; }; DC6C726013CDEA0A008A5975 /* LoggerDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LoggerDialog.cxx; path = ../gui/LoggerDialog.cxx; sourceTree = SOURCE_ROOT; }; DC6C726113CDEA0A008A5975 /* LoggerDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = LoggerDialog.hxx; path = ../gui/LoggerDialog.hxx; sourceTree = SOURCE_ROOT; }; DC74D69F138D4D7E00F05C5C /* StringList.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = StringList.hxx; path = ../common/StringList.hxx; sourceTree = SOURCE_ROOT; }; DC74D6A0138D4D7E00F05C5C /* StringParser.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = StringParser.hxx; path = ../common/StringParser.hxx; sourceTree = SOURCE_ROOT; }; DC79F81017A88D9E00288B91 /* Base.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Base.cxx; path = ../common/Base.cxx; sourceTree = SOURCE_ROOT; }; DC79F81117A88D9E00288B91 /* Base.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Base.hxx; path = ../common/Base.hxx; sourceTree = SOURCE_ROOT; }; DC7A24D4173B1CF600B20FE9 /* Variant.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Variant.hxx; path = ../common/Variant.hxx; sourceTree = SOURCE_ROOT; }; DC7A24DD173B1DBC00B20FE9 /* FileListWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FileListWidget.cxx; path = ../gui/FileListWidget.cxx; sourceTree = SOURCE_ROOT; }; DC7A24DE173B1DBC00B20FE9 /* FileListWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FileListWidget.hxx; path = ../gui/FileListWidget.hxx; sourceTree = SOURCE_ROOT; }; DC8078DA0B4BD5F3005E9305 /* DebuggerExpressions.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = DebuggerExpressions.hxx; path = ../debugger/DebuggerExpressions.hxx; sourceTree = SOURCE_ROOT; }; DC8078E60B4BD697005E9305 /* UIDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = UIDialog.cxx; path = ../gui/UIDialog.cxx; sourceTree = SOURCE_ROOT; }; DC8078E70B4BD697005E9305 /* UIDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = UIDialog.hxx; path = ../gui/UIDialog.hxx; sourceTree = SOURCE_ROOT; }; DC8C1BA714B25DE7006440EE /* CartCM.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartCM.cxx; path = ../emucore/CartCM.cxx; sourceTree = SOURCE_ROOT; }; DC8C1BA814B25DE7006440EE /* CartCM.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartCM.hxx; path = ../emucore/CartCM.hxx; sourceTree = SOURCE_ROOT; }; DC8C1BA914B25DE7006440EE /* CompuMate.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompuMate.cxx; path = ../emucore/CompuMate.cxx; sourceTree = SOURCE_ROOT; }; DC8C1BAA14B25DE7006440EE /* CompuMate.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CompuMate.hxx; path = ../emucore/CompuMate.hxx; sourceTree = SOURCE_ROOT; }; DC8C1BAB14B25DE7006440EE /* MindLink.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MindLink.cxx; path = ../emucore/MindLink.cxx; sourceTree = SOURCE_ROOT; }; DC8C1BAC14B25DE7006440EE /* MindLink.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = MindLink.hxx; path = ../emucore/MindLink.hxx; sourceTree = SOURCE_ROOT; }; DC8CF9BC17C15A27004B533D /* ConsoleMediumFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ConsoleMediumFont.hxx; path = ../gui/ConsoleMediumFont.hxx; sourceTree = SOURCE_ROOT; }; DC932D3F0F278A5200FEFEFC /* DefProps.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = DefProps.hxx; path = ../emucore/DefProps.hxx; sourceTree = SOURCE_ROOT; }; DC932D400F278A5200FEFEFC /* Serializable.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Serializable.hxx; path = ../emucore/Serializable.hxx; sourceTree = SOURCE_ROOT; }; DC932D410F278A5200FEFEFC /* SerialPort.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = SerialPort.hxx; path = ../emucore/SerialPort.hxx; sourceTree = SOURCE_ROOT; }; DC932D420F278A5200FEFEFC /* TIATables.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TIATables.cxx; path = ../emucore/TIATables.cxx; sourceTree = SOURCE_ROOT; }; DC932D430F278A5200FEFEFC /* TIATables.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = TIATables.hxx; path = ../emucore/TIATables.hxx; sourceTree = SOURCE_ROOT; }; DC98F35411F5B56200AA520F /* MessageBox.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MessageBox.cxx; path = ../gui/MessageBox.cxx; sourceTree = SOURCE_ROOT; }; DC98F35511F5B56200AA520F /* MessageBox.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = MessageBox.hxx; path = ../gui/MessageBox.hxx; sourceTree = SOURCE_ROOT; }; DC9EA8850F729A36000452B5 /* KidVid.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = KidVid.cxx; path = ../emucore/KidVid.cxx; sourceTree = SOURCE_ROOT; }; DC9EA8860F729A36000452B5 /* KidVid.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = KidVid.hxx; path = ../emucore/KidVid.hxx; sourceTree = SOURCE_ROOT; }; DCA00FF50DBABCAD00C3823D /* RiotDebug.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RiotDebug.cxx; path = ../debugger/RiotDebug.cxx; sourceTree = SOURCE_ROOT; }; DCA00FF60DBABCAD00C3823D /* RiotDebug.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = RiotDebug.hxx; path = ../debugger/RiotDebug.hxx; sourceTree = SOURCE_ROOT; }; DCA23AE70D75B22500F77B33 /* CartX07.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartX07.cxx; path = ../emucore/CartX07.cxx; sourceTree = SOURCE_ROOT; }; DCA23AE80D75B22500F77B33 /* CartX07.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartX07.hxx; path = ../emucore/CartX07.hxx; sourceTree = SOURCE_ROOT; }; DCA43BFF10DED5890070CEFD /* Info-Stella.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Stella.plist"; sourceTree = ""; }; DCAACAEC188D631500A4D282 /* Cart4KSC.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart4KSC.cxx; path = ../emucore/Cart4KSC.cxx; sourceTree = SOURCE_ROOT; }; DCAACAED188D631500A4D282 /* Cart4KSC.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart4KSC.hxx; path = ../emucore/Cart4KSC.hxx; sourceTree = SOURCE_ROOT; }; DCAACAEE188D631500A4D282 /* CartBF.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartBF.cxx; path = ../emucore/CartBF.cxx; sourceTree = SOURCE_ROOT; }; DCAACAEF188D631500A4D282 /* CartBF.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartBF.hxx; path = ../emucore/CartBF.hxx; sourceTree = SOURCE_ROOT; }; DCAACAF0188D631500A4D282 /* CartBFSC.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartBFSC.cxx; path = ../emucore/CartBFSC.cxx; sourceTree = SOURCE_ROOT; }; DCAACAF1188D631500A4D282 /* CartBFSC.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartBFSC.hxx; path = ../emucore/CartBFSC.hxx; sourceTree = SOURCE_ROOT; }; DCAACAF2188D631500A4D282 /* CartDF.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDF.cxx; path = ../emucore/CartDF.cxx; sourceTree = SOURCE_ROOT; }; DCAACAF3188D631500A4D282 /* CartDF.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDF.hxx; path = ../emucore/CartDF.hxx; sourceTree = SOURCE_ROOT; }; DCAACAF4188D631500A4D282 /* CartDFSC.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDFSC.cxx; path = ../emucore/CartDFSC.cxx; sourceTree = SOURCE_ROOT; }; DCAACAF5188D631500A4D282 /* CartDFSC.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDFSC.hxx; path = ../emucore/CartDFSC.hxx; sourceTree = SOURCE_ROOT; }; DCAACB04188D636F00A4D282 /* Cart4KSCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart4KSCWidget.cxx; path = ../debugger/gui/Cart4KSCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAACB05188D636F00A4D282 /* Cart4KSCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart4KSCWidget.hxx; path = ../debugger/gui/Cart4KSCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAACB06188D636F00A4D282 /* CartBFSCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartBFSCWidget.cxx; path = ../debugger/gui/CartBFSCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAACB07188D636F00A4D282 /* CartBFSCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartBFSCWidget.hxx; path = ../debugger/gui/CartBFSCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAACB08188D636F00A4D282 /* CartBFWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartBFWidget.cxx; path = ../debugger/gui/CartBFWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAACB09188D636F00A4D282 /* CartBFWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartBFWidget.hxx; path = ../debugger/gui/CartBFWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAACB0A188D636F00A4D282 /* CartDFSCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDFSCWidget.cxx; path = ../debugger/gui/CartDFSCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAACB0B188D636F00A4D282 /* CartDFSCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDFSCWidget.hxx; path = ../debugger/gui/CartDFSCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAACB0C188D636F00A4D282 /* CartDFWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDFWidget.cxx; path = ../debugger/gui/CartDFWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAACB0D188D636F00A4D282 /* CartDFWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDFWidget.hxx; path = ../debugger/gui/CartDFWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5B21715887B0080BB82 /* Cart2KWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart2KWidget.cxx; path = ../debugger/gui/Cart2KWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5B31715887B0080BB82 /* Cart2KWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart2KWidget.hxx; path = ../debugger/gui/Cart2KWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5B41715887B0080BB82 /* Cart3FWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart3FWidget.cxx; path = ../debugger/gui/Cart3FWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5B51715887B0080BB82 /* Cart3FWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart3FWidget.hxx; path = ../debugger/gui/Cart3FWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5B61715887B0080BB82 /* Cart4KWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart4KWidget.cxx; path = ../debugger/gui/Cart4KWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5B71715887B0080BB82 /* Cart4KWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart4KWidget.hxx; path = ../debugger/gui/Cart4KWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5B81715887B0080BB82 /* Cart0840Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart0840Widget.cxx; path = ../debugger/gui/Cart0840Widget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5B91715887B0080BB82 /* Cart0840Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart0840Widget.hxx; path = ../debugger/gui/Cart0840Widget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5BA1715887B0080BB82 /* CartCVWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartCVWidget.cxx; path = ../debugger/gui/CartCVWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5BB1715887B0080BB82 /* CartCVWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartCVWidget.hxx; path = ../debugger/gui/CartCVWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5BC1715887B0080BB82 /* CartDebugWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDebugWidget.hxx; path = ../debugger/gui/CartDebugWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5BD1715887B0080BB82 /* CartEFSCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartEFSCWidget.cxx; path = ../debugger/gui/CartEFSCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5BE1715887B0080BB82 /* CartEFSCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartEFSCWidget.hxx; path = ../debugger/gui/CartEFSCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5BF1715887B0080BB82 /* CartEFWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartEFWidget.cxx; path = ../debugger/gui/CartEFWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5C01715887B0080BB82 /* CartEFWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartEFWidget.hxx; path = ../debugger/gui/CartEFWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5C11715887B0080BB82 /* CartF0Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF0Widget.cxx; path = ../debugger/gui/CartF0Widget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5C21715887B0080BB82 /* CartF0Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF0Widget.hxx; path = ../debugger/gui/CartF0Widget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5C31715887B0080BB82 /* CartF4SCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF4SCWidget.cxx; path = ../debugger/gui/CartF4SCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5C41715887B0080BB82 /* CartF4SCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF4SCWidget.hxx; path = ../debugger/gui/CartF4SCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5C51715887B0080BB82 /* CartF4Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF4Widget.cxx; path = ../debugger/gui/CartF4Widget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5C61715887B0080BB82 /* CartF4Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF4Widget.hxx; path = ../debugger/gui/CartF4Widget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5C71715887B0080BB82 /* CartF6SCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF6SCWidget.cxx; path = ../debugger/gui/CartF6SCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5C81715887B0080BB82 /* CartF6SCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF6SCWidget.hxx; path = ../debugger/gui/CartF6SCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5C91715887B0080BB82 /* CartF6Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF6Widget.cxx; path = ../debugger/gui/CartF6Widget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5CA1715887B0080BB82 /* CartF6Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF6Widget.hxx; path = ../debugger/gui/CartF6Widget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5CB1715887B0080BB82 /* CartF8SCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF8SCWidget.cxx; path = ../debugger/gui/CartF8SCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5CC1715887B0080BB82 /* CartF8SCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF8SCWidget.hxx; path = ../debugger/gui/CartF8SCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5CD1715887B0080BB82 /* CartF8Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF8Widget.cxx; path = ../debugger/gui/CartF8Widget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5CE1715887B0080BB82 /* CartF8Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF8Widget.hxx; path = ../debugger/gui/CartF8Widget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5CF1715887B0080BB82 /* CartFAWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartFAWidget.cxx; path = ../debugger/gui/CartFAWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5D01715887B0080BB82 /* CartFAWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartFAWidget.hxx; path = ../debugger/gui/CartFAWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAAE5D11715887B0080BB82 /* CartUAWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartUAWidget.cxx; path = ../debugger/gui/CartUAWidget.cxx; sourceTree = SOURCE_ROOT; }; DCAAE5D21715887B0080BB82 /* CartUAWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartUAWidget.hxx; path = ../debugger/gui/CartUAWidget.hxx; sourceTree = SOURCE_ROOT; }; DCAD60A61152F8BD00BC4184 /* CartDPCPlus.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDPCPlus.cxx; path = ../emucore/CartDPCPlus.cxx; sourceTree = SOURCE_ROOT; }; DCAD60A71152F8BD00BC4184 /* CartDPCPlus.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDPCPlus.hxx; path = ../emucore/CartDPCPlus.hxx; sourceTree = SOURCE_ROOT; }; DCBA710010DED62E0077193B /* Stella.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Stella.app; sourceTree = BUILT_PRODUCTS_DIR; }; DCC467ED14FBECC700E15508 /* atari_ntsc_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = atari_ntsc_impl.h; path = ../common/tv_filters/atari_ntsc_impl.h; sourceTree = SOURCE_ROOT; }; DCC467EE14FBECC700E15508 /* atari_ntsc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = atari_ntsc.c; path = ../common/tv_filters/atari_ntsc.c; sourceTree = SOURCE_ROOT; }; DCC467EF14FBECC700E15508 /* atari_ntsc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = atari_ntsc.h; path = ../common/tv_filters/atari_ntsc.h; sourceTree = SOURCE_ROOT; }; DCC527C910B9DA19005E1287 /* Device.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Device.hxx; path = ../emucore/Device.hxx; sourceTree = SOURCE_ROOT; }; DCC527CA10B9DA19005E1287 /* M6502.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = M6502.cxx; path = ../emucore/M6502.cxx; sourceTree = SOURCE_ROOT; }; DCC527CB10B9DA19005E1287 /* M6502.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = M6502.hxx; path = ../emucore/M6502.hxx; sourceTree = SOURCE_ROOT; }; DCC527CC10B9DA19005E1287 /* NullDev.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NullDev.cxx; path = ../emucore/NullDev.cxx; sourceTree = SOURCE_ROOT; }; DCC527CD10B9DA19005E1287 /* NullDev.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = NullDev.hxx; path = ../emucore/NullDev.hxx; sourceTree = SOURCE_ROOT; }; DCC527CE10B9DA19005E1287 /* System.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = System.cxx; path = ../emucore/System.cxx; sourceTree = SOURCE_ROOT; }; DCC527CF10B9DA19005E1287 /* System.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = System.hxx; path = ../emucore/System.hxx; sourceTree = SOURCE_ROOT; }; DCC527D810B9DA6A005E1287 /* bspf.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = bspf.hxx; path = ../common/bspf.hxx; sourceTree = SOURCE_ROOT; }; DCCF47DB14B60DEE00814FAB /* ControllerWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ControllerWidget.hxx; path = ../debugger/gui/ControllerWidget.hxx; sourceTree = SOURCE_ROOT; }; DCCF47DC14B60DEE00814FAB /* JoystickWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JoystickWidget.cxx; path = ../debugger/gui/JoystickWidget.cxx; sourceTree = SOURCE_ROOT; }; DCCF47DD14B60DEE00814FAB /* JoystickWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = JoystickWidget.hxx; path = ../debugger/gui/JoystickWidget.hxx; sourceTree = SOURCE_ROOT; }; DCCF49B514B7544A00814FAB /* PaddleWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PaddleWidget.cxx; path = ../debugger/gui/PaddleWidget.cxx; sourceTree = SOURCE_ROOT; }; DCCF49B614B7544A00814FAB /* PaddleWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = PaddleWidget.hxx; path = ../debugger/gui/PaddleWidget.hxx; sourceTree = SOURCE_ROOT; }; DCCF4ACE14B7E6C300814FAB /* BoosterWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BoosterWidget.cxx; path = ../debugger/gui/BoosterWidget.cxx; sourceTree = SOURCE_ROOT; }; DCCF4ACF14B7E6C300814FAB /* BoosterWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = BoosterWidget.hxx; path = ../debugger/gui/BoosterWidget.hxx; sourceTree = SOURCE_ROOT; }; DCCF4AD014B7E6C300814FAB /* NullControlWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = NullControlWidget.hxx; path = ../debugger/gui/NullControlWidget.hxx; sourceTree = SOURCE_ROOT; }; DCCF4ADA14B9433100814FAB /* GenesisWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GenesisWidget.cxx; path = ../debugger/gui/GenesisWidget.cxx; sourceTree = SOURCE_ROOT; }; DCCF4ADB14B9433100814FAB /* GenesisWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = GenesisWidget.hxx; path = ../debugger/gui/GenesisWidget.hxx; sourceTree = SOURCE_ROOT; }; DCCF4AFE14BA27EB00814FAB /* DrivingWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DrivingWidget.cxx; path = ../debugger/gui/DrivingWidget.cxx; sourceTree = SOURCE_ROOT; }; DCCF4AFF14BA27EB00814FAB /* DrivingWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = DrivingWidget.hxx; path = ../debugger/gui/DrivingWidget.hxx; sourceTree = SOURCE_ROOT; }; DCCF4B0014BA27EB00814FAB /* KeyboardWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = KeyboardWidget.cxx; path = ../debugger/gui/KeyboardWidget.cxx; sourceTree = SOURCE_ROOT; }; DCCF4B0114BA27EB00814FAB /* KeyboardWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = KeyboardWidget.hxx; path = ../debugger/gui/KeyboardWidget.hxx; sourceTree = SOURCE_ROOT; }; DCD2839612E39F1200A808DC /* Thumbulator.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Thumbulator.cxx; path = ../emucore/Thumbulator.cxx; sourceTree = SOURCE_ROOT; }; DCD2839712E39F1200A808DC /* Thumbulator.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Thumbulator.hxx; path = ../emucore/Thumbulator.hxx; sourceTree = SOURCE_ROOT; }; DCD3F7C311340AAF00DBA3AE /* Genesis.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Genesis.cxx; path = ../emucore/Genesis.cxx; sourceTree = SOURCE_ROOT; }; DCD3F7C411340AAF00DBA3AE /* Genesis.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Genesis.hxx; path = ../emucore/Genesis.hxx; sourceTree = SOURCE_ROOT; }; DCD56D360B247D920092F9F8 /* Cart4A50.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Cart4A50.cxx; path = ../emucore/Cart4A50.cxx; sourceTree = SOURCE_ROOT; }; DCD56D370B247D920092F9F8 /* Cart4A50.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cart4A50.hxx; path = ../emucore/Cart4A50.hxx; sourceTree = SOURCE_ROOT; }; DCD56D3A0B247DB40092F9F8 /* RectList.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RectList.cxx; path = ../common/RectList.cxx; sourceTree = SOURCE_ROOT; }; DCD56D3B0B247DB40092F9F8 /* RectList.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RectList.hxx; path = ../common/RectList.hxx; sourceTree = SOURCE_ROOT; }; DCD6FC5D11C281ED005DA767 /* png.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = png.c; path = ../libpng/png.c; sourceTree = SOURCE_ROOT; }; DCD6FC5E11C281ED005DA767 /* png.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = png.h; path = ../libpng/png.h; sourceTree = SOURCE_ROOT; }; DCD6FC5F11C281ED005DA767 /* pngconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pngconf.h; path = ../libpng/pngconf.h; sourceTree = SOURCE_ROOT; }; DCD6FC6011C281ED005DA767 /* pngerror.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngerror.c; path = ../libpng/pngerror.c; sourceTree = SOURCE_ROOT; }; DCD6FC6111C281ED005DA767 /* pngget.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngget.c; path = ../libpng/pngget.c; sourceTree = SOURCE_ROOT; }; DCD6FC6211C281ED005DA767 /* pngmem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngmem.c; path = ../libpng/pngmem.c; sourceTree = SOURCE_ROOT; }; DCD6FC6311C281ED005DA767 /* pngpread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngpread.c; path = ../libpng/pngpread.c; sourceTree = SOURCE_ROOT; }; DCD6FC6411C281ED005DA767 /* pngpriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pngpriv.h; path = ../libpng/pngpriv.h; sourceTree = SOURCE_ROOT; }; DCD6FC6511C281ED005DA767 /* pngread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngread.c; path = ../libpng/pngread.c; sourceTree = SOURCE_ROOT; }; DCD6FC6611C281ED005DA767 /* pngrio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngrio.c; path = ../libpng/pngrio.c; sourceTree = SOURCE_ROOT; }; DCD6FC6711C281ED005DA767 /* pngrtran.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngrtran.c; path = ../libpng/pngrtran.c; sourceTree = SOURCE_ROOT; }; DCD6FC6811C281ED005DA767 /* pngrutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngrutil.c; path = ../libpng/pngrutil.c; sourceTree = SOURCE_ROOT; }; DCD6FC6911C281ED005DA767 /* pngset.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngset.c; path = ../libpng/pngset.c; sourceTree = SOURCE_ROOT; }; DCD6FC6B11C281ED005DA767 /* pngtrans.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngtrans.c; path = ../libpng/pngtrans.c; sourceTree = SOURCE_ROOT; }; DCD6FC6C11C281ED005DA767 /* pngwio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngwio.c; path = ../libpng/pngwio.c; sourceTree = SOURCE_ROOT; }; DCD6FC6D11C281ED005DA767 /* pngwrite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngwrite.c; path = ../libpng/pngwrite.c; sourceTree = SOURCE_ROOT; }; DCD6FC6E11C281ED005DA767 /* pngwtran.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngwtran.c; path = ../libpng/pngwtran.c; sourceTree = SOURCE_ROOT; }; DCD6FC6F11C281ED005DA767 /* pngwutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngwutil.c; path = ../libpng/pngwutil.c; sourceTree = SOURCE_ROOT; }; DCD6FC9111C28C6F005DA767 /* PNGLibrary.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PNGLibrary.cxx; path = ../common/PNGLibrary.cxx; sourceTree = SOURCE_ROOT; }; DCD6FC9211C28C6F005DA767 /* PNGLibrary.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = PNGLibrary.hxx; path = ../common/PNGLibrary.hxx; sourceTree = SOURCE_ROOT; }; DCDE17F617724E5D00EB1AC6 /* ConfigPathDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ConfigPathDialog.cxx; path = ../gui/ConfigPathDialog.cxx; sourceTree = SOURCE_ROOT; }; DCDE17F717724E5D00EB1AC6 /* ConfigPathDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ConfigPathDialog.hxx; path = ../gui/ConfigPathDialog.hxx; sourceTree = SOURCE_ROOT; }; DCDE17F817724E5D00EB1AC6 /* SnapshotDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SnapshotDialog.cxx; path = ../gui/SnapshotDialog.cxx; sourceTree = SOURCE_ROOT; }; DCDE17F917724E5D00EB1AC6 /* SnapshotDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = SnapshotDialog.hxx; path = ../gui/SnapshotDialog.hxx; sourceTree = SOURCE_ROOT; }; DCE395DA16CB0B2B008DB1E5 /* FSNodePOSIX.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FSNodePOSIX.hxx; path = ../unix/FSNodePOSIX.hxx; sourceTree = SOURCE_ROOT; }; DCE395EA16CB0B5F008DB1E5 /* FSNodeFactory.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FSNodeFactory.hxx; path = ../common/FSNodeFactory.hxx; sourceTree = SOURCE_ROOT; }; DCE395EB16CB0B5F008DB1E5 /* FSNodeZIP.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FSNodeZIP.cxx; path = ../common/FSNodeZIP.cxx; sourceTree = SOURCE_ROOT; }; DCE395EC16CB0B5F008DB1E5 /* FSNodeZIP.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FSNodeZIP.hxx; path = ../common/FSNodeZIP.hxx; sourceTree = SOURCE_ROOT; }; DCE395ED16CB0B5F008DB1E5 /* ZipHandler.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ZipHandler.cxx; path = ../common/ZipHandler.cxx; sourceTree = SOURCE_ROOT; }; DCE395EE16CB0B5F008DB1E5 /* ZipHandler.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ZipHandler.hxx; path = ../common/ZipHandler.hxx; sourceTree = SOURCE_ROOT; }; DCE3BBF50C95CEDC00A671DF /* RomInfoWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RomInfoWidget.cxx; path = ../gui/RomInfoWidget.cxx; sourceTree = SOURCE_ROOT; }; DCE3BBF60C95CEDC00A671DF /* RomInfoWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RomInfoWidget.hxx; path = ../gui/RomInfoWidget.hxx; sourceTree = SOURCE_ROOT; }; DCE6EB200DD9ADA00047AC28 /* TrackBall.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TrackBall.cxx; path = ../emucore/TrackBall.cxx; sourceTree = SOURCE_ROOT; }; DCE6EB210DD9ADA00047AC28 /* TrackBall.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TrackBall.hxx; path = ../emucore/TrackBall.hxx; sourceTree = SOURCE_ROOT; }; DCEECE540B5E5E540021D754 /* Cart0840.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Cart0840.cxx; path = ../emucore/Cart0840.cxx; sourceTree = SOURCE_ROOT; }; DCEECE550B5E5E540021D754 /* Cart0840.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cart0840.hxx; path = ../emucore/Cart0840.hxx; sourceTree = SOURCE_ROOT; }; DCF467B10F93993B00B25D7A /* Array.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Array.hxx; path = ../common/Array.hxx; sourceTree = SOURCE_ROOT; }; DCF467B20F93993B00B25D7A /* SharedPtr.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = SharedPtr.hxx; path = ../common/SharedPtr.hxx; sourceTree = SOURCE_ROOT; }; DCF467B40F93993B00B25D7A /* SoundNull.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = SoundNull.hxx; path = ../common/SoundNull.hxx; sourceTree = SOURCE_ROOT; }; DCF467BC0F9399F500B25D7A /* Version.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Version.hxx; path = ../common/Version.hxx; sourceTree = SOURCE_ROOT; }; DCF467BE0F939A1400B25D7A /* CartEF.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartEF.cxx; path = ../emucore/CartEF.cxx; sourceTree = SOURCE_ROOT; }; DCF467BF0F939A1400B25D7A /* CartEF.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartEF.hxx; path = ../emucore/CartEF.hxx; sourceTree = SOURCE_ROOT; }; DCF467C00F939A1400B25D7A /* CartEFSC.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartEFSC.cxx; path = ../emucore/CartEFSC.cxx; sourceTree = SOURCE_ROOT; }; DCF467C10F939A1400B25D7A /* CartEFSC.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartEFSC.hxx; path = ../emucore/CartEFSC.hxx; sourceTree = SOURCE_ROOT; }; DCF7B0D910A762FC007A2870 /* CartF0.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF0.cxx; path = ../emucore/CartF0.cxx; sourceTree = SOURCE_ROOT; }; DCF7B0DA10A762FC007A2870 /* CartF0.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF0.hxx; path = ../emucore/CartF0.hxx; sourceTree = SOURCE_ROOT; }; DCF7B0DB10A762FC007A2870 /* CartFA.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartFA.cxx; path = ../emucore/CartFA.cxx; sourceTree = SOURCE_ROOT; }; DCF7B0DC10A762FC007A2870 /* CartFA.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartFA.hxx; path = ../emucore/CartFA.hxx; sourceTree = SOURCE_ROOT; }; DCFFE59B12100E1400DFA000 /* ComboDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ComboDialog.cxx; path = ../gui/ComboDialog.cxx; sourceTree = SOURCE_ROOT; }; DCFFE59C12100E1400DFA000 /* ComboDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ComboDialog.hxx; path = ../gui/ComboDialog.hxx; sourceTree = SOURCE_ROOT; }; 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 = ( 2D91750F09BA90380026E9FF /* Cocoa.framework in Frameworks */, 2D91751009BA90380026E9FF /* OpenGL.framework in Frameworks */, 2D91751109BA90380026E9FF /* SDL.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 = ""; }; 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, ); name = "Linked Frameworks"; sourceTree = ""; }; 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { isa = PBXGroup; children = ( 2D17D98E08BC398400E47F69 /* ApplicationServices.framework */, 2D4764C806683C5F00F63D87 /* SDL.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 /* «PROJECTNAMEASXML» */ = { isa = PBXGroup; children = ( DCA43BFF10DED5890070CEFD /* Info-Stella.plist */, 080E96DDFE201D6D7F000001 /* Classes */, 29B97315FDCFA39411CA2CEA /* Other Sources */, 29B97317FDCFA39411CA2CEA /* Resources */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, ); name = "«PROJECTNAMEASXML»"; sourceTree = ""; }; 29B97315FDCFA39411CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( DCCC0C9109C3541E0088BFF1 /* cheat */, 2D6050C5089876F300C6DE89 /* common */, 2D605130089879BA00C6DE89 /* debugger */, 2D6050CC0898776500C6DE89 /* emucore */, 2D6050FA0898786C00C6DE89 /* gui */, DCD6FC5A11C281A1005DA767 /* libpng */, 2D6050C60898771C00C6DE89 /* macosx */, 2D6050C90898774B00C6DE89 /* unix */, 2D60513708987A5400C6DE89 /* yacc */, ); name = "Other Sources"; sourceTree = ""; }; 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( 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 = ( 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; 2D20F9E308C603C500A73076 /* gui */ = { isa = PBXGroup; children = ( 2D23318F0900B5EF00613B1F /* AudioWidget.cxx */, 2D2331900900B5EF00613B1F /* AudioWidget.hxx */, DCCF4ACE14B7E6C300814FAB /* BoosterWidget.cxx */, DCCF4ACF14B7E6C300814FAB /* BoosterWidget.hxx */, DCAAE5B81715887B0080BB82 /* Cart0840Widget.cxx */, DCAAE5B91715887B0080BB82 /* Cart0840Widget.hxx */, DCAAE5B21715887B0080BB82 /* Cart2KWidget.cxx */, DCAAE5B31715887B0080BB82 /* Cart2KWidget.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 */, DC676A291729A0B000E4E73D /* CartARWidget.cxx */, DC676A2A1729A0B000E4E73D /* CartARWidget.hxx */, DCAACB06188D636F00A4D282 /* CartBFSCWidget.cxx */, DCAACB07188D636F00A4D282 /* CartBFSCWidget.hxx */, DCAACB08188D636F00A4D282 /* CartBFWidget.cxx */, DCAACB09188D636F00A4D282 /* CartBFWidget.hxx */, DC676A2B1729A0B000E4E73D /* CartCMWidget.cxx */, DC676A2C1729A0B000E4E73D /* CartCMWidget.hxx */, DC676A2D1729A0B000E4E73D /* CartCTYWidget.cxx */, DC676A2E1729A0B000E4E73D /* CartCTYWidget.hxx */, DCAAE5BA1715887B0080BB82 /* CartCVWidget.cxx */, DCAAE5BB1715887B0080BB82 /* CartCVWidget.hxx */, 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 */, 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 */, DC676A3B1729A0B000E4E73D /* CartMCWidget.cxx */, DC676A3C1729A0B000E4E73D /* CartMCWidget.hxx */, DC676A3D1729A0B000E4E73D /* CartSBWidget.cxx */, DC676A3E1729A0B000E4E73D /* CartSBWidget.hxx */, DCAAE5D11715887B0080BB82 /* CartUAWidget.cxx */, DCAAE5D21715887B0080BB82 /* CartUAWidget.hxx */, DC676A3F1729A0B000E4E73D /* CartX07Widget.cxx */, DC676A401729A0B000E4E73D /* CartX07Widget.hxx */, 2D20F9E408C603EC00A73076 /* ColorWidget.cxx */, 2D20F9E508C603EC00A73076 /* ColorWidget.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 */, DCCF4AFE14BA27EB00814FAB /* DrivingWidget.cxx */, DCCF4AFF14BA27EB00814FAB /* DrivingWidget.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 */, 2D20F9EE08C603EC00A73076 /* PromptWidget.cxx */, 2D20F9EF08C603EC00A73076 /* PromptWidget.hxx */, 2D20F9F008C603EC00A73076 /* RamWidget.cxx */, 2D20F9F108C603EC00A73076 /* RamWidget.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 */, 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 */, ); name = gui; sourceTree = ""; }; 2D6050C5089876F300C6DE89 /* common */ = { isa = PBXGroup; children = ( DCF467B10F93993B00B25D7A /* Array.hxx */, DC79F81017A88D9E00288B91 /* Base.cxx */, DC79F81117A88D9E00288B91 /* Base.hxx */, DCC527D810B9DA6A005E1287 /* bspf.hxx */, DC3EE2D61417801800F9DA4A /* FBSurfaceGL.cxx */, DC3EE2D71417801800F9DA4A /* FBSurfaceGL.hxx */, DC3EE2D81417801800F9DA4A /* FBSurfaceTIA.cxx */, DC3EE2D91417801800F9DA4A /* FBSurfaceTIA.hxx */, 2D733D5D062893E7006265D9 /* FrameBufferGL.cxx */, 2D733D5E062893E7006265D9 /* FrameBufferGL.hxx */, 2D733D61062893E7006265D9 /* FrameBufferSoft.cxx */, 2D733D62062893E7006265D9 /* FrameBufferSoft.hxx */, DCE395EA16CB0B5F008DB1E5 /* FSNodeFactory.hxx */, DCE395EB16CB0B5F008DB1E5 /* FSNodeZIP.cxx */, DCE395EC16CB0B5F008DB1E5 /* FSNodeZIP.hxx */, 2DDBEA0A0845700300812C11 /* mainSDL.cxx */, DC56FCDC14CCCC4900A31CC3 /* MouseControl.cxx */, DC56FCDD14CCCC4900A31CC3 /* MouseControl.hxx */, DCD6FC9111C28C6F005DA767 /* PNGLibrary.cxx */, DCD6FC9211C28C6F005DA767 /* PNGLibrary.hxx */, DCD56D3A0B247DB40092F9F8 /* RectList.cxx */, DCD56D3B0B247DB40092F9F8 /* RectList.hxx */, DCF467B20F93993B00B25D7A /* SharedPtr.hxx */, DCF467B40F93993B00B25D7A /* SoundNull.hxx */, 2DDA34020665817D00CDD299 /* SoundSDL.cxx */, 2DDA34030665817D00CDD299 /* SoundSDL.hxx */, DC5D1AA6102C6FC900E59AC1 /* Stack.hxx */, DC5C768E14C26F7C0031EBC7 /* StellaKeys.hxx */, DC74D69F138D4D7E00F05C5C /* StringList.hxx */, DC74D6A0138D4D7E00F05C5C /* StringParser.hxx */, DCC467EA14FBEC9600E15508 /* tv_filters */, DC7A24D4173B1CF600B20FE9 /* Variant.hxx */, DCF467BC0F9399F500B25D7A /* Version.hxx */, DCE395ED16CB0B5F008DB1E5 /* ZipHandler.cxx */, DCE395EE16CB0B5F008DB1E5 /* ZipHandler.hxx */, ); name = common; sourceTree = ""; }; 2D6050C60898771C00C6DE89 /* macosx */ = { isa = PBXGroup; children = ( 2D28DDE409DC2D9F00A17585 /* MenusEvents.h */, 2DDBEA0E0845709700812C11 /* OSystemMACOSX.cxx */, 2DDBEA0F0845709700812C11 /* OSystemMACOSX.hxx */, DC1FC1880DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx */, DC1FC1890DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx */, 2D944866062911CD00DD9879 /* SettingsMACOSX.cxx */, 2D94486C0629124700DD9879 /* SettingsMACOSX.hxx */, ); name = macosx; sourceTree = ""; }; 2D6050C90898774B00C6DE89 /* unix */ = { isa = PBXGroup; children = ( 2DDBEA0C0845708800812C11 /* FSNodePOSIX.cxx */, DCE395DA16CB0B2B008DB1E5 /* FSNodePOSIX.hxx */, ); name = unix; sourceTree = ""; }; 2D6050CC0898776500C6DE89 /* emucore */ = { isa = PBXGroup; children = ( DC487FB40DA5350900E12499 /* AtariVox.cxx */, DC487FB50DA5350900E12499 /* AtariVox.hxx */, 2DE2DF100627AE07006BEC99 /* Booster.cxx */, 2DE2DF110627AE07006BEC99 /* Booster.hxx */, 2DE2DF120627AE07006BEC99 /* Cart.cxx */, 2DE2DF130627AE07006BEC99 /* Cart.hxx */, DCEECE540B5E5E540021D754 /* Cart0840.cxx */, DCEECE550B5E5E540021D754 /* Cart0840.hxx */, 2DE2DF140627AE07006BEC99 /* Cart2K.cxx */, 2DE2DF150627AE07006BEC99 /* Cart2K.hxx */, 2D9555D90880E78000466554 /* Cart3E.cxx */, 2D9555DA0880E78000466554 /* Cart3E.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 */, 2DE2DF1A0627AE07006BEC99 /* CartAR.cxx */, 2DE2DF1B0627AE07006BEC99 /* CartAR.hxx */, DCAACAEE188D631500A4D282 /* CartBF.cxx */, DCAACAEF188D631500A4D282 /* CartBF.hxx */, DCAACAF0188D631500A4D282 /* CartBFSC.cxx */, DCAACAF1188D631500A4D282 /* CartBFSC.hxx */, DC8C1BA714B25DE7006440EE /* CartCM.cxx */, DC8C1BA814B25DE7006440EE /* CartCM.hxx */, DC6727081556F4860023653B /* CartCTY.cxx */, DC6727091556F4860023653B /* CartCTY.hxx */, DC67270A1556F4860023653B /* CartCTYTunes.hxx */, 2DE2DF1C0627AE07006BEC99 /* CartCV.cxx */, 2DE2DF1D0627AE07006BEC99 /* CartCV.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 */, 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 */, 2DE2DF360627AE07006BEC99 /* CartMC.cxx */, 2DE2DF370627AE07006BEC99 /* CartMC.hxx */, DC0984830D3985160073C852 /* CartSB.cxx */, DC0984840D3985160073C852 /* CartSB.hxx */, 2DDBEB7008457B7D00812C11 /* CartUA.cxx */, 2DDBEB7108457B7D00812C11 /* CartUA.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 */, 2D733D70062895B2006265D9 /* FrameBuffer.cxx */, 2D733D71062895B2006265D9 /* FrameBuffer.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 */, 2D05FF5B096E261E00A518FE /* MediaFactory.hxx */, DC8C1BAB14B25DE7006440EE /* MindLink.cxx */, DC8C1BAC14B25DE7006440EE /* MindLink.hxx */, DC11F78B0DB36933003B505E /* MT24LC256.cxx */, DC11F78C0DB36933003B505E /* MT24LC256.hxx */, DCC527CC10B9DA19005E1287 /* NullDev.cxx */, DCC527CD10B9DA19005E1287 /* NullDev.hxx */, 2DDBEB7408457B7D00812C11 /* OSystem.cxx */, 2DDBEB7508457B7D00812C11 /* OSystem.hxx */, 2DE2DF820627AE34006BEC99 /* Paddles.cxx */, 2DE2DF830627AE34006BEC99 /* Paddles.hxx */, 2DE2DF840627AE34006BEC99 /* Props.cxx */, 2DE2DF850627AE34006BEC99 /* Props.hxx */, 2DE2DF860627AE34006BEC99 /* PropsSet.cxx */, 2DE2DF870627AE34006BEC99 /* PropsSet.hxx */, 2DE2DF880627AE34006BEC99 /* Random.cxx */, 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 */, DC07A3C60CAD738A009B4BC9 /* StateManager.cxx */, DC07A3C70CAD738A009B4BC9 /* StateManager.hxx */, 2DE2DF8E0627AE34006BEC99 /* Switches.cxx */, 2DE2DF8F0627AE34006BEC99 /* Switches.hxx */, DCC527CE10B9DA19005E1287 /* System.cxx */, DCC527CF10B9DA19005E1287 /* System.hxx */, DCD2839612E39F1200A808DC /* Thumbulator.cxx */, DCD2839712E39F1200A808DC /* Thumbulator.hxx */, 2DE2DF900627AE34006BEC99 /* TIA.cxx */, 2DE2DF910627AE34006BEC99 /* TIA.hxx */, 2DE7242D08CE910900C889A8 /* TIASnd.cxx */, 2DE7242E08CE910900C889A8 /* TIASnd.hxx */, DC932D420F278A5200FEFEFC /* TIATables.cxx */, DC932D430F278A5200FEFEFC /* TIATables.hxx */, DCE6EB200DD9ADA00047AC28 /* TrackBall.cxx */, DCE6EB210DD9ADA00047AC28 /* TrackBall.hxx */, ); name = 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 */, 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 */, 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 */, 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 */, 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 */, DC8078E60B4BD697005E9305 /* UIDialog.cxx */, DC8078E70B4BD697005E9305 /* UIDialog.hxx */, 2DDBEAD2084578BF00812C11 /* VideoDialog.cxx */, 2DDBEAD3084578BF00812C11 /* VideoDialog.hxx */, 2DDBEAD4084578BF00812C11 /* Widget.cxx */, 2DDBEAD5084578BF00812C11 /* Widget.hxx */, ); name = gui; sourceTree = ""; }; 2D605130089879BA00C6DE89 /* debugger */ = { isa = PBXGroup; children = ( 2D20F9E308C603C500A73076 /* gui */, 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 */, 2DF971DE0892CEA400F64D23 /* Expression.cxx */, 2DF971DF0892CEA400F64D23 /* Expression.hxx */, 2D403BCE08611A69001E31A1 /* PackedBitArray.cxx */, 2D403BCF08611A69001E31A1 /* PackedBitArray.hxx */, DCA00FF50DBABCAD00C3823D /* RiotDebug.cxx */, DCA00FF60DBABCAD00C3823D /* RiotDebug.hxx */, 2D30F8750868A4DB00938B9D /* TIADebug.cxx */, 2D30F8760868A4DB00938B9D /* TIADebug.hxx */, 2D6CC10308C811A600B8F642 /* TiaZoomWidget.cxx */, 2D6CC10408C811A600B8F642 /* TiaZoomWidget.hxx */, ); name = debugger; sourceTree = ""; }; 2D60513708987A5400C6DE89 /* yacc */ = { isa = PBXGroup; children = ( 2D313F0A0879C4C0005BD3E5 /* YaccParser.cxx */, 2D313F0B0879C4C0005BD3E5 /* YaccParser.hxx */, ); name = yacc; sourceTree = ""; }; DCC467EA14FBEC9600E15508 /* tv_filters */ = { isa = PBXGroup; children = ( DCC467EE14FBECC700E15508 /* atari_ntsc.c */, DCC467EF14FBECC700E15508 /* atari_ntsc.h */, DCC467ED14FBECC700E15508 /* atari_ntsc_impl.h */, DC5EE7C014F7C165001C628C /* NTSCFilter.cxx */, DC5EE7C114F7C165001C628C /* NTSCFilter.hxx */, ); name = 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 */, ); name = 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 */, ); name = libpng; 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 */, 2D9173D009BA90380026E9FF /* Cart4K.hxx in Headers */, 2D9173D109BA90380026E9FF /* CartAR.hxx in Headers */, 2D9173D209BA90380026E9FF /* CartCV.hxx in Headers */, 2D9173D309BA90380026E9FF /* CartDPC.hxx in Headers */, 2D9173D409BA90380026E9FF /* CartE0.hxx in Headers */, 2D9173D509BA90380026E9FF /* CartE7.hxx in Headers */, 2D9173D609BA90380026E9FF /* CartF4.hxx in Headers */, 2D9173D709BA90380026E9FF /* CartF4SC.hxx in Headers */, 2D9173D809BA90380026E9FF /* CartF6.hxx in Headers */, 2D9173D909BA90380026E9FF /* CartF6SC.hxx in Headers */, 2D9173DA09BA90380026E9FF /* CartF8.hxx in Headers */, 2D9173DB09BA90380026E9FF /* CartF8SC.hxx in Headers */, 2D9173DD09BA90380026E9FF /* CartFE.hxx in Headers */, 2D9173DF09BA90380026E9FF /* CartMC.hxx in Headers */, 2D9173E009BA90380026E9FF /* Console.hxx in Headers */, 2D9173E109BA90380026E9FF /* Control.hxx in Headers */, 2D9173E309BA90380026E9FF /* Driving.hxx in Headers */, 2D9173E409BA90380026E9FF /* Event.hxx in Headers */, 2D9173E509BA90380026E9FF /* Joystick.hxx in Headers */, 2D9173E609BA90380026E9FF /* Keyboard.hxx in Headers */, 2D9173E709BA90380026E9FF /* M6532.hxx in Headers */, 2D9173E809BA90380026E9FF /* MD5.hxx in Headers */, 2D9173EA09BA90380026E9FF /* Paddles.hxx in Headers */, 2D9173EB09BA90380026E9FF /* Props.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 */, 2D9173F109BA90380026E9FF /* TIA.hxx in Headers */, 2D9173F709BA90380026E9FF /* FrameBufferGL.hxx in Headers */, 2D9173F809BA90380026E9FF /* FrameBufferSoft.hxx in Headers */, 2D9173F909BA90380026E9FF /* EventHandler.hxx in Headers */, 2D9173FA09BA90380026E9FF /* FrameBuffer.hxx in Headers */, 2D9173FB09BA90380026E9FF /* Settings.hxx in Headers */, 2D9173FC09BA90380026E9FF /* SettingsMACOSX.hxx in Headers */, 2D9173FD09BA90380026E9FF /* SoundSDL.hxx in Headers */, 2D9173FF09BA90380026E9FF /* OSystemMACOSX.hxx in Headers */, 2D91740009BA90380026E9FF /* AboutDialog.hxx in Headers */, 2D91740109BA90380026E9FF /* AudioDialog.hxx in Headers */, 2D91740209BA90380026E9FF /* BrowserDialog.hxx in Headers */, 2D91740309BA90380026E9FF /* Command.hxx in Headers */, 2D91740409BA90380026E9FF /* Dialog.hxx in Headers */, 2D91740509BA90380026E9FF /* DialogContainer.hxx in Headers */, 2D91740609BA90380026E9FF /* GameInfoDialog.hxx in Headers */, 2D91740709BA90380026E9FF /* GameList.hxx in Headers */, 2D91740809BA90380026E9FF /* GuiObject.hxx in Headers */, 2D91740A09BA90380026E9FF /* HelpDialog.hxx in Headers */, 2D91740B09BA90380026E9FF /* Launcher.hxx in Headers */, 2D91740C09BA90380026E9FF /* LauncherDialog.hxx in Headers */, 2D91740E09BA90380026E9FF /* ListWidget.hxx in Headers */, 2D91740F09BA90380026E9FF /* Menu.hxx in Headers */, 2D91741009BA90380026E9FF /* OptionsDialog.hxx in Headers */, 2D91741109BA90380026E9FF /* PopUpWidget.hxx in Headers */, 2D91741209BA90380026E9FF /* ProgressDialog.hxx in Headers */, 2D91741309BA90380026E9FF /* ScrollBarWidget.hxx in Headers */, 2D91741609BA90380026E9FF /* TabWidget.hxx in Headers */, 2D91741709BA90380026E9FF /* VideoDialog.hxx in Headers */, 2D91741809BA90380026E9FF /* Widget.hxx in Headers */, 2D91741909BA90380026E9FF /* CartUA.hxx in Headers */, 2D91741A09BA90380026E9FF /* FSNode.hxx in Headers */, 2D91741B09BA90380026E9FF /* OSystem.hxx in Headers */, 2D91741D09BA90380026E9FF /* Preferences.h 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 */, 2D91742509BA90380026E9FF /* EditTextWidget.hxx in Headers */, 2D91742809BA90380026E9FF /* PackedBitArray.hxx in Headers */, 2D91742909BA90380026E9FF /* TIADebug.hxx in Headers */, 2D91742A09BA90380026E9FF /* YaccParser.hxx in Headers */, 2D91742B09BA90380026E9FF /* Cart3E.hxx in Headers */, 2D91742C09BA90380026E9FF /* CpuDebug.hxx in Headers */, 2D91743609BA90380026E9FF /* DebuggerSystem.hxx in Headers */, 2D91743A09BA90380026E9FF /* Expression.hxx in Headers */, 2D91744F09BA90380026E9FF /* InputTextDialog.hxx in Headers */, 2D91745009BA90380026E9FF /* CheckListWidget.hxx in Headers */, 2D91745109BA90380026E9FF /* StringListWidget.hxx in Headers */, 2D91745209BA90380026E9FF /* CommandDialog.hxx in Headers */, 2D91745309BA90380026E9FF /* CommandMenu.hxx in Headers */, 2D91745409BA90380026E9FF /* ColorWidget.hxx in Headers */, 2D91745509BA90380026E9FF /* CpuWidget.hxx in Headers */, 2D91745609BA90380026E9FF /* DataGridOpsWidget.hxx in Headers */, 2D91745709BA90380026E9FF /* DataGridWidget.hxx in Headers */, 2D91745809BA90380026E9FF /* DebuggerDialog.hxx in Headers */, 2D91745909BA90380026E9FF /* PromptWidget.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 */, 2D91746809BA90380026E9FF /* MediaFactory.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 */, 2D28DDE509DC2D9F00A17585 /* MenusEvents.h in Headers */, DCD56D390B247D920092F9F8 /* Cart4A50.hxx in Headers */, DCD56D3D0B247DB40092F9F8 /* RectList.hxx in Headers */, DC8078DB0B4BD5F3005E9305 /* DebuggerExpressions.hxx in Headers */, DC8078EB0B4BD697005E9305 /* UIDialog.hxx in Headers */, DCEECE570B5E5E540021D754 /* Cart0840.hxx in Headers */, DCE3BBFA0C95CEDC00A671DF /* RomInfoWidget.hxx in Headers */, DC07A3C90CAD738A009B4BC9 /* StateManager.hxx in Headers */, DC0984860D3985160073C852 /* CartSB.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 */, DCE6EB230DD9ADA00047AC28 /* TrackBall.hxx in Headers */, DC173F770E2CAC1E00320F94 /* ContextMenu.hxx in Headers */, DC0DF86A0F0DAAF500B0F1F3 /* GlobalPropsDialog.hxx in Headers */, DC5D2C520F117CFD004D1660 /* Rect.hxx in Headers */, DC5D2C530F117CFD004D1660 /* StellaFont.hxx in Headers */, DC5D2C540F117CFD004D1660 /* StellaLargeFont.hxx in Headers */, DC5D2C550F117CFD004D1660 /* StellaMediumFont.hxx in Headers */, DC5D2C610F129B1E004D1660 /* LauncherFilterDialog.hxx in Headers */, DC932D440F278A5200FEFEFC /* DefProps.hxx in Headers */, DC932D450F278A5200FEFEFC /* Serializable.hxx in Headers */, DC932D460F278A5200FEFEFC /* SerialPort.hxx in Headers */, DC932D480F278A5200FEFEFC /* TIATables.hxx in Headers */, DC9EA8880F729A36000452B5 /* KidVid.hxx in Headers */, DCF467B50F93993B00B25D7A /* Array.hxx in Headers */, DCF467B60F93993B00B25D7A /* SharedPtr.hxx in Headers */, DCF467B80F93993B00B25D7A /* SoundNull.hxx in Headers */, DCF467BD0F9399F500B25D7A /* Version.hxx in Headers */, DCF467C30F939A1400B25D7A /* CartEF.hxx in Headers */, DCF467C50F939A1400B25D7A /* CartEFSC.hxx 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 */, DCC527D510B9DA19005E1287 /* NullDev.hxx in Headers */, DCC527D710B9DA19005E1287 /* System.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 */, DCD6FC7711C281ED005DA767 /* pngpriv.h 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 */, DC74D6A1138D4D7E00F05C5C /* StringList.hxx in Headers */, DC74D6A2138D4D7E00F05C5C /* StringParser.hxx in Headers */, DC6C726313CDEA0A008A5975 /* LoggerDialog.hxx in Headers */, DC3EE2DB1417801800F9DA4A /* FBSurfaceGL.hxx in Headers */, DC3EE2DD1417801800F9DA4A /* FBSurfaceTIA.hxx in Headers */, DC8C1BAE14B25DE7006440EE /* CartCM.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 */, 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 */, DCC467F014FBECC700E15508 /* atari_ntsc_impl.h in Headers */, DCC467F214FBECC700E15508 /* atari_ntsc.h in Headers */, DC67270C1556F4860023653B /* CartCTY.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 */, 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 */, DC676A501729A0B000E4E73D /* CartE0Widget.hxx in Headers */, DC676A521729A0B000E4E73D /* CartE7Widget.hxx in Headers */, DC676A541729A0B000E4E73D /* CartFA2Widget.hxx in Headers */, DC676A561729A0B000E4E73D /* CartFEWidget.hxx in Headers */, DC676A581729A0B000E4E73D /* CartMCWidget.hxx in Headers */, DC676A5A1729A0B000E4E73D /* CartSBWidget.hxx in Headers */, DC676A5C1729A0B000E4E73D /* CartX07Widget.hxx in Headers */, DC7A24D5173B1CF600B20FE9 /* Variant.hxx in Headers */, DC7A24E0173B1DBC00B20FE9 /* FileListWidget.hxx in Headers */, DC13B540176FF2F500B8B4BB /* RomListSettings.hxx in Headers */, DCDE17FB17724E5D00EB1AC6 /* ConfigPathDialog.hxx in Headers */, DCDE17FD17724E5D00EB1AC6 /* SnapshotDialog.hxx in Headers */, DC79F81317A88D9E00288B91 /* Base.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 */, DCAACB13188D636F00A4D282 /* CartBFWidget.hxx in Headers */, DCAACB15188D636F00A4D282 /* CartDFSCWidget.hxx in Headers */, DCAACB17188D636F00A4D282 /* CartDFWidget.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 = { ORGANIZATIONNAME = net.sourceforge.stella; }; buildConfigurationList = 2D91752109BA903B0026E9FF /* Build configuration list for PBXProject "stella_intel" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, Japanese, French, German, ); mainGroup = 29B97314FDCFA39411CA2CEA /* «PROJECTNAMEASXML» */; projectDirPath = ""; projectRoot = ""; targets = ( 2D9173C809BA90380026E9FF /* Stella */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 2D91746C09BA90380026E9FF /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 2D91746E09BA90380026E9FF /* SDLMain.nib 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 = ( 2D91747409BA90380026E9FF /* SDLMain.m in Sources */, 2D91747509BA90380026E9FF /* Booster.cxx 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 */, 2D91747C09BA90380026E9FF /* CartDPC.cxx in Sources */, 2D91747D09BA90380026E9FF /* CartE0.cxx in Sources */, 2D91747E09BA90380026E9FF /* CartE7.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 */, 2D91748609BA90380026E9FF /* CartFE.cxx in Sources */, 2D91748809BA90380026E9FF /* CartMC.cxx in Sources */, 2D91748909BA90380026E9FF /* Console.cxx in Sources */, 2D91748A09BA90380026E9FF /* Control.cxx in Sources */, 2D91748C09BA90380026E9FF /* Driving.cxx in Sources */, 2D91748E09BA90380026E9FF /* Joystick.cxx in Sources */, 2D91748F09BA90380026E9FF /* Keyboard.cxx in Sources */, 2D91749009BA90380026E9FF /* M6532.cxx in Sources */, 2D91749109BA90380026E9FF /* MD5.cxx in Sources */, 2D91749309BA90380026E9FF /* Paddles.cxx in Sources */, 2D91749409BA90380026E9FF /* Props.cxx in Sources */, 2D91749509BA90380026E9FF /* PropsSet.cxx in Sources */, 2D91749609BA90380026E9FF /* Random.cxx in Sources */, 2D91749709BA90380026E9FF /* Serializer.cxx in Sources */, 2D91749809BA90380026E9FF /* Switches.cxx in Sources */, 2D91749909BA90380026E9FF /* TIA.cxx in Sources */, 2D91749F09BA90380026E9FF /* FrameBufferGL.cxx in Sources */, 2D9174A009BA90380026E9FF /* FrameBufferSoft.cxx in Sources */, 2D9174A109BA90380026E9FF /* EventHandler.cxx in Sources */, 2D9174A209BA90380026E9FF /* FrameBuffer.cxx in Sources */, 2D9174A309BA90380026E9FF /* Settings.cxx in Sources */, 2D9174A409BA90380026E9FF /* SettingsMACOSX.cxx in Sources */, 2D9174A509BA90380026E9FF /* SoundSDL.cxx in Sources */, 2D9174A709BA90380026E9FF /* mainSDL.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 */, 2D9174B709BA90380026E9FF /* OptionsDialog.cxx in Sources */, 2D9174B809BA90380026E9FF /* PopUpWidget.cxx in Sources */, 2D9174B909BA90380026E9FF /* ProgressDialog.cxx in Sources */, 2D9174BA09BA90380026E9FF /* ScrollBarWidget.cxx in Sources */, 2D9174BB09BA90380026E9FF /* TabWidget.cxx in Sources */, 2D9174BC09BA90380026E9FF /* VideoDialog.cxx in Sources */, 2D9174BD09BA90380026E9FF /* Widget.cxx in Sources */, 2D9174BE09BA90380026E9FF /* CartUA.cxx in Sources */, 2D9174BF09BA90380026E9FF /* FSNode.cxx in Sources */, 2D9174C009BA90380026E9FF /* OSystem.cxx in Sources */, 2D9174C209BA90380026E9FF /* Preferences.m in Sources */, 2D9174C409BA90380026E9FF /* AboutBox.m 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 */, 2D9174CB09BA90380026E9FF /* PackedBitArray.cxx in Sources */, 2D9174CC09BA90380026E9FF /* TIADebug.cxx in Sources */, 2D9174CD09BA90380026E9FF /* YaccParser.cxx in Sources */, 2D9174CE09BA90380026E9FF /* Cart3E.cxx in Sources */, 2D9174CF09BA90380026E9FF /* CpuDebug.cxx in Sources */, 2D9174DC09BA90380026E9FF /* Expression.cxx in Sources */, 2D9174F109BA90380026E9FF /* InputTextDialog.cxx in Sources */, 2D9174F209BA90380026E9FF /* CheckListWidget.cxx in Sources */, 2D9174F309BA90380026E9FF /* StringListWidget.cxx in Sources */, 2D9174F409BA90380026E9FF /* CommandDialog.cxx in Sources */, 2D9174F509BA90380026E9FF /* CommandMenu.cxx in Sources */, 2D9174F609BA90380026E9FF /* ColorWidget.cxx in Sources */, 2D9174F709BA90380026E9FF /* CpuWidget.cxx in Sources */, 2D9174F809BA90380026E9FF /* DataGridOpsWidget.cxx in Sources */, 2D9174F909BA90380026E9FF /* DataGridWidget.cxx in Sources */, 2D9174FA09BA90380026E9FF /* DebuggerDialog.cxx in Sources */, 2D9174FB09BA90380026E9FF /* PromptWidget.cxx in Sources */, 2D9174FC09BA90380026E9FF /* RamWidget.cxx in Sources */, 2D9174FD09BA90380026E9FF /* RomListWidget.cxx in Sources */, 2D9174FE09BA90380026E9FF /* RomWidget.cxx in Sources */, 2D9174FF09BA90380026E9FF /* TiaInfoWidget.cxx in Sources */, 2D91750009BA90380026E9FF /* TiaOutputWidget.cxx in Sources */, 2D91750109BA90380026E9FF /* TiaWidget.cxx in Sources */, 2D91750209BA90380026E9FF /* ToggleBitWidget.cxx in Sources */, 2D91750309BA90380026E9FF /* TogglePixelWidget.cxx in Sources */, 2D91750409BA90380026E9FF /* ToggleWidget.cxx in Sources */, 2D91750609BA90380026E9FF /* TiaZoomWidget.cxx in Sources */, 2D91750709BA90380026E9FF /* TIASnd.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 */, DC47455E09C34BFA00EDDA3A /* RamCheat.cxx in Sources */, DCD56D380B247D920092F9F8 /* Cart4A50.cxx in Sources */, DCD56D3C0B247DB40092F9F8 /* RectList.cxx in Sources */, DC8078EA0B4BD697005E9305 /* UIDialog.cxx in Sources */, DCEECE560B5E5E540021D754 /* Cart0840.cxx in Sources */, DCE3BBF90C95CEDC00A671DF /* RomInfoWidget.cxx in Sources */, DC07A3C80CAD738A009B4BC9 /* StateManager.cxx in Sources */, DC0984850D3985160073C852 /* CartSB.cxx in Sources */, DCA23AE90D75B22500F77B33 /* CartX07.cxx 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 */, DC4AC6EF0DC8DACB00CD3AD2 /* RiotWidget.cxx in Sources */, DC4AC6F30DC8DAEF00CD3AD2 /* SaveKey.cxx in Sources */, DCE6EB220DD9ADA00047AC28 /* TrackBall.cxx in Sources */, DC173F760E2CAC1E00320F94 /* ContextMenu.cxx in Sources */, DC0DF8690F0DAAF500B0F1F3 /* GlobalPropsDialog.cxx in Sources */, DC5D2C600F129B1E004D1660 /* LauncherFilterDialog.cxx in Sources */, DC932D470F278A5200FEFEFC /* TIATables.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 */, DCC527D410B9DA19005E1287 /* NullDev.cxx in Sources */, DCC527D610B9DA19005E1287 /* System.cxx in Sources */, DC6B2BA411037FF200F199A7 /* CartDebug.cxx in Sources */, DC6B2BA611037FF200F199A7 /* DiStella.cxx in Sources */, DCD3F7C511340AAF00DBA3AE /* Genesis.cxx in Sources */, DCAD60A81152F8BD00BC4184 /* CartDPCPlus.cxx in Sources */, DCD6FC7011C281ED005DA767 /* png.c in Sources */, DCD6FC7311C281ED005DA767 /* pngerror.c in Sources */, DCD6FC7411C281ED005DA767 /* pngget.c in Sources */, DCD6FC7511C281ED005DA767 /* pngmem.c in Sources */, DCD6FC7611C281ED005DA767 /* pngpread.c in Sources */, DCD6FC7811C281ED005DA767 /* pngread.c in Sources */, DCD6FC7911C281ED005DA767 /* pngrio.c in Sources */, DCD6FC7A11C281ED005DA767 /* pngrtran.c in Sources */, DCD6FC7B11C281ED005DA767 /* pngrutil.c in Sources */, DCD6FC7C11C281ED005DA767 /* pngset.c in Sources */, DCD6FC7E11C281ED005DA767 /* pngtrans.c in Sources */, DCD6FC7F11C281ED005DA767 /* pngwio.c in Sources */, DCD6FC8011C281ED005DA767 /* pngwrite.c in Sources */, DCD6FC8111C281ED005DA767 /* pngwtran.c in Sources */, DCD6FC8211C281ED005DA767 /* pngwutil.c in Sources */, DCD6FC9311C28C6F005DA767 /* PNGLibrary.cxx in Sources */, DC98F35611F5B56200AA520F /* MessageBox.cxx in Sources */, DCFFE59D12100E1400DFA000 /* ComboDialog.cxx in Sources */, DCD2839812E39F1200A808DC /* Thumbulator.cxx in Sources */, DC6C726213CDEA0A008A5975 /* LoggerDialog.cxx in Sources */, DC3EE2DA1417801800F9DA4A /* FBSurfaceGL.cxx in Sources */, DC3EE2DC1417801800F9DA4A /* FBSurfaceTIA.cxx in Sources */, DC8C1BAD14B25DE7006440EE /* CartCM.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 */, DC5EE7C214F7C165001C628C /* NTSCFilter.cxx in Sources */, DCC467F114FBECC700E15508 /* atari_ntsc.c in Sources */, DC67270B1556F4860023653B /* CartCTY.cxx in Sources */, DCE395F016CB0B5F008DB1E5 /* FSNodeZIP.cxx in Sources */, DCE395F216CB0B5F008DB1E5 /* ZipHandler.cxx in Sources */, DCAAE5D31715887B0080BB82 /* Cart2KWidget.cxx in Sources */, DCAAE5D51715887B0080BB82 /* Cart3FWidget.cxx in Sources */, DCAAE5D71715887B0080BB82 /* Cart4KWidget.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 */, DCAAE5E41715887B0080BB82 /* CartF4SCWidget.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 */, DC676A451729A0B000E4E73D /* CartARWidget.cxx 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 */, DC676A571729A0B000E4E73D /* CartMCWidget.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 */, DCDE17FC17724E5D00EB1AC6 /* SnapshotDialog.cxx in Sources */, DC79F81217A88D9E00288B91 /* Base.cxx in Sources */, DCAACAF6188D631500A4D282 /* Cart4KSC.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 */, DCAACB10188D636F00A4D282 /* CartBFSCWidget.cxx in Sources */, DCAACB12188D636F00A4D282 /* CartBFWidget.cxx in Sources */, DCAACB14188D636F00A4D282 /* CartDFSCWidget.cxx in Sources */, DCAACB16188D636F00A4D282 /* CartDFWidget.cxx in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ 2D91751709BA90380026E9FF /* Development */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( ., "$(HOME)/Library/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_INTTYPES, HAVE_GETTIMEOFDAY, DISPLAY_OPENGL, CHEATCODE_SUPPORT, DEBUGGER_SUPPORT, JOYSTICK_SUPPORT, SOUND_SUPPORT, THUMB_SUPPORT, WINDOWED_SUPPORT, BSPF_MAC_OSX, MAC_OSX, ); HEADER_SEARCH_PATHS = ( ./SDL.framework/Headers, ../cheat, ../common, ../common/tv_filters, ../debugger, ../debugger/gui, ../emucore, ../gui, ../yacc, ., ); INFOPLIST_FILE = "Info-Stella.plist"; INSTALL_PATH = "$(HOME)/Applications"; LIBRARY_SEARCH_PATHS = "$(LIBRARY_SEARCH_PATHS)"; OTHER_CFLAGS = ""; OTHER_LDFLAGS = ( "-framework", SDL, "-lz", ); PRODUCT_NAME = Stella; SECTORDER_FLAGS = ""; WARNING_CFLAGS = ( "-Wmost", "-Wno-four-char-constants", "-Wno-unknown-pragmas", ); WRAPPER_EXTENSION = app; }; name = Development; }; 2D91751809BA90380026E9FF /* Deployment */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( ., "$(HOME)/Library/Frameworks", ); GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( HAVE_INTTYPES, HAVE_GETTIMEOFDAY, DISPLAY_OPENGL, CHEATCODE_SUPPORT, DEBUGGER_SUPPORT, JOYSTICK_SUPPORT, SOUND_SUPPORT, THUMB_SUPPORT, WINDOWED_SUPPORT, BSPF_MAC_OSX, MAC_OSX, ); HEADER_SEARCH_PATHS = ( ./SDL.framework/Headers, ../cheat, ../common, ../common/tv_filters, ../debugger, ../debugger/gui, ../emucore, ../gui, ../yacc, ., ); INFOPLIST_FILE = "Info-Stella.plist"; INSTALL_PATH = "$(HOME)/Applications"; LIBRARY_SEARCH_PATHS = "$(LIBRARY_SEARCH_PATHS)"; OTHER_CFLAGS = ""; OTHER_LDFLAGS = ( "-framework", SDL, "-lz", ); PRODUCT_NAME = Stella; SECTORDER_FLAGS = ""; WARNING_CFLAGS = ( "-Wmost", "-Wno-four-char-constants", "-Wno-unknown-pragmas", ); WRAPPER_EXTENSION = app; }; name = Deployment; }; 2D91751909BA90380026E9FF /* Default */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( "$(HOME)/Library/Frameworks", ., ); GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( HAVE_INTTYPES, HAVE_GETTIMEOFDAY, DISPLAY_OPENGL, CHEATCODE_SUPPORT, DEBUGGER_SUPPORT, JOYSTICK_SUPPORT, SOUND_SUPPORT, THUMB_SUPPORT, WINDOWED_SUPPORT, BSPF_MAC_OSX, MAC_OSX, ); HEADER_SEARCH_PATHS = ( ./SDL.framework/Headers, ../cheat, ../common, ../common/tv_filters, ../debugger, ../debugger/gui, ../emucore, ../gui, ../yacc, ., ); INFOPLIST_FILE = "Info-Stella.plist"; INSTALL_PATH = "$(HOME)/Applications"; LIBRARY_SEARCH_PATHS = .; OTHER_CFLAGS = ""; OTHER_LDFLAGS = ( "-framework", SDL, "-lz", ); PRODUCT_NAME = Stella; SECTORDER_FLAGS = ""; WARNING_CFLAGS = ( "-Wmost", "-Wno-four-char-constants", "-Wno-unknown-pragmas", ); WRAPPER_EXTENSION = app; }; name = Default; }; 2D91752209BA903B0026E9FF /* Development */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = dwarf; FRAMEWORK_SEARCH_PATHS = ( ., "$(HOME)/Library/Frameworks", ); GCC_OPTIMIZATION_LEVEL = 0; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INSTALL_PATH = "@rpath"; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.6; SDKROOT = macosx10.6; VALID_ARCHS = "i386 x86_64"; }; name = Development; }; 2D91752309BA903B0026E9FF /* Deployment */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; FRAMEWORK_SEARCH_PATHS = ( ., "$(HOME)/Library/Frameworks", ); GCC_ENABLE_CPP_RTTI = NO; GCC_OPTIMIZATION_LEVEL = 3; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INSTALL_PATH = "@rpath"; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.6; SDKROOT = macosx10.6; VALID_ARCHS = "i386 x86_64"; }; name = Deployment; }; 2D91752409BA903B0026E9FF /* Default */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INSTALL_PATH = "@rpath"; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.6; SDKROOT = macosx10.6; VALID_ARCHS = "i386 x86_64"; }; name = Default; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 2D91751609BA90380026E9FF /* Build configuration list for PBXNativeTarget "Stella" */ = { isa = XCConfigurationList; buildConfigurations = ( 2D91751709BA90380026E9FF /* Development */, 2D91751809BA90380026E9FF /* Deployment */, 2D91751909BA90380026E9FF /* Default */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Default; }; 2D91752109BA903B0026E9FF /* Build configuration list for PBXProject "stella_intel" */ = { isa = XCConfigurationList; buildConfigurations = ( 2D91752209BA903B0026E9FF /* Development */, 2D91752309BA903B0026E9FF /* Deployment */, 2D91752409BA903B0026E9FF /* Default */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Default; }; /* End XCConfigurationList section */ }; rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; } stella-3.9.3/src/macosx/stella_intel.xcodeproj/TemplateInfo.plist0000644000175000001440000000062310403717551024603 0ustar stephenusers Description This project builds an SDL-based application with Cocoa menus. FilesToMacroExpand English.lproj/InfoPlist.strings stella-3.9.3/src/macosx/AboutBox.h0000644000175000001440000000237112266336753016374 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: AboutBox.h 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #import /** AboutBox window class and support functions for the Macintosh OS X SDL port of Stella. @author Mark Grebe */ @interface AboutBox : NSObject { IBOutlet id appNameField; IBOutlet id creditsField; IBOutlet id versionField; NSTimer *scrollTimer; float currentPosition; float maxScrollHeight; NSTimeInterval startTime; BOOL restartAtTop; } + (AboutBox *)sharedInstance; - (IBAction)showPanel:(id)sender; - (void)OK:(id)sender; @end stella-3.9.3/src/macosx/AboutBoxTextView.h0000644000175000001440000000174412266336753020077 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: AboutBoxTextView.h 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #import /** AboutBoxTextView class and support functions for the Macintosh OS X SDL port of Stella. @author Mark Grebe */ @interface AboutBoxTextView : NSTextView { } @end stella-3.9.3/src/macosx/Info-Stella.plist0000644000175000001440000000361112267025147017661 0ustar stephenusers CFBundleDevelopmentRegion English CFBundleDocumentTypes CFBundleTypeExtensions bin BIN rom ROM zip ZIP a26 A26 CFBundleTypeIconFile Cart CFBundleTypeName Atari 2600 Cartridge File CFBundleTypeOSTypes Cart CFBundleTypeRole Viewer CFBundleExecutable Stella CFBundleDisplayName Stella CFBundleGetInfoString Stella CFBundleHelpBookFolder docs CFBundleHelpBookName docs CFBundleIconFile Stella CFBundleIdentifier net.sourceforge.Stella CFBundleInfoDictionaryVersion 6.0 CFBundleName Stella CFBundlePackageType APPL CFBundleSignature StLa CFBundleVersion 3.9.3 NSMainNibFile SDLMain.nib NSPrincipalClass NSApplication «PROJECTNAMEASXML» SDL Cocoa App LSMinimumSystemVersionByArchitecture x86_64 10.6.0 i386 10.4.0 ppc 10.4.0 stella-3.9.3/src/macosx/SerialPortMACOSX.hxx0000644000175000001440000000337612266336753020236 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SerialPortMACOSX.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: SerialPortMACOSX.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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); /** Close a previously opened serial port. */ void closePort(); /** 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); private: // File descriptor for serial connection int myHandle; }; #endif stella-3.9.3/src/macosx/MenusEvents.h0000644000175000001440000000202612266336753017122 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: MenusEvents.h 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ /** Menus window class defines for event sending between Objective-C and C++ for the Macintosh OS X SDL port of Stella. @author Mark Grebe */ #define MENU_OPEN 2 #define MENU_VOLUME_INCREASE 3 #define MENU_VOLUME_DECREASE 4 stella-3.9.3/src/macosx/Credits.html0000644000175000001440000000313212266336753016757 0ustar stephenusers Acknowledgements

Stella

A multi-platform Atari 2600 VCS emulator

Copyright © 1995-2014 The Stella Team
http://stella.sourceforge.net

Stella is now DonationWare!
http://stella.sourceforge.net/donations.php

Macintosh OS X version:
Copyright © 2007-2013 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-3.9.3/src/macosx/SerialPortMACOSX.cxx0000644000175000001440000000461612266336753020227 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SerialPortMACOSX.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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-3.9.3/src/macosx/template.dmg.gz0000644000175000001440000034733611361062110017412 0ustar stephenusers‹ ^ÄKtemplate.dmgìÜMlÕð·»¶³ë¬×Ç@>LpC m>R>'ÐÊH…¦­)—Ö䋈¢&Ѐ Bå€8¢U¨‡ŠVB=T¨BU¨Bq…ª(Ú ­”S‘ŠàPÕj£Ò7o×»³ÎÚq°Û:ø÷[=Ïz÷ÍÌÛÿÌμ÷æÍ†,Wc{B÷‰P7oÙ¼%û²zzxò\í¥úóÇâäʘúBˆ“âŸÏ}ªq–R»bÚÚX\a¶õt½ðÍ?ß´iâ¾úÔ\JaA¢ël=…ð@LÅÆt‘–Wzcq—v/xyð)}r¡óÿõ•îh®ËXâú_ø÷ŠlC½#\Ž BªÉ¥N¯„Ðê׫îÓW±êר.k'lr–þ©0އšHðÿT¡ÔéõáPè“bÚS×ÙúËÅËýóž°Éø Ø0¦ÂñP €Ï¶B¥8)†útWLÝÙˡاÄ4S×Ù~§=—ûç=o“° ôO…©p<Ôÿv}RW6Úõ7fÿ§WGB%Ü&±°9 {Ãáp4å¹%—geøv|ø~|LÌÈ·µ™ou[:<¶…›Ãma{|ìOslkô@„pEœn9nCéõJ\ö½q]ßMë{"–j(¦‹Ìí“ã{¶7Ó¹ÚþF¿ÆßÓºÃó'êu£óŠÑPWãI\Ǫ/Ô§KÄpŠH_[ä¿ÿÛc4ŽÄG!Æ»þ‰¯=ufð_Yš¬~üÒ…‘Ùù·|d.¢¶ÑíÍ­Úy«dy¶7·c1ôÎØCê%L¹Êq{"î/ÙûÙߣ¹’ß19þà+q{öÇôP,ùÁ—üŽf©:­y(娄oÅWŽÆ÷žŒŸfoz^/S¶ýïl”i8•)¦”©þ}»³Y¦ÎëJy:}[{ÿ]õR¥’u(Õó¯_R©’=ØxR‰{ÿMõé±6Ed¶ãN+*w/~TÞ<Úx²2Få¶út‰Èö¥»šßÌ;g=vßË3×±{GÛ±{[¸5¦­ñ»k|l „áËñïD<>ï烞ÆaõbsìMGûa_šcç<çÈÖt»³6°½Q[ßÿQíTí'µ#ýôߨÿFÿÉÚkëûÞ¬¾Xý^õÞêHõÙÞó•÷+=oö<Ó3Ö3Øýa÷{]o•~Zz®T-ž+>S/n)ü:¼^ÇZ[­QÿêŽíÿ5q:˜Z9å0[ ûbÚk‡Çcjթׯ–äYJ­É˜^§^²:ê@®%{Uó±ðµXw¾)¶ÄwÇ:ö¡ðT¬ g5éáØΞM¤yWåæ]£9×\‡RÛyo£ýtnI}iYWä–UŽË¹&b]ýÑÔJ¬¶õ˜´Ú«Û&ÇúS£Oä¹ìùŒöê;—Ð/RoC¯nkÙoŽuô£±O5[Ñû¦yö÷´öª­qOúG3]PÊöÞ›y6ø¿Ú,uXõù%µWnšg›ªŸq >ÚLéÝš§ó¹øì¸ŒâÓjA¶â3còl>-B|~–‹ÏèeŸz{¹Ÿ1&/åÓ"Äçµ\|v.©ølLŸªÖáÈô¥ðd|jÛw®ŠÇœû96#¹Øt-©ØdGð«r½.sG©§Q'èjï«agÌu8õONý“Ó5„,çš\Εážxfšˆ¹¦óS>ßP.__ê…=ÏwÙùð`œçX[Þ«Û–ùõÔCµ?õQµ¯ûš\¾ÞÔ‹:ËÿøŒ\×6Ï]s÷ž¦¼³õMg##7,b¯z)•mmî\XËr¬Ë嘭ß}Cóv*ÿ5)Go¬…du‡,:?Ló>Öül™áSgÖ”²Ô¹Žw‰}Ü,²“ý#ý¡ÿ©Ú¾¾÷ªWÿºòtïÛ•ÞG*VþPùEåÅÊ`ù\ùÝòkå#å±òúõ¼ßýV×+¥cÅñâæÂï ?/<\Xß¼þŸQºm̬•—?3fç»Ùú²W§Ï)÷ÅsÌôÞ‘8ß¡xF9–ÎWÓc œ3àëpx$ì ›Rû?k•?)¤‘¬sµå[WL®›»ïûÓŒè9Ùx’]1Y±¤ú RLºÃýa"ìM× Z=åOYÓ¥Eé)_Ö´"ì…ƒÍmЊûõ‹÷PÎŽ¼¤â>”¢1÷hü‘ûZŒÆSZØU˜úµ±á0}ýd¶ë$Y®ëÂô•˜Ù¾-Y®¹eå÷Ÿì½ësK˜¹Å³÷GróÎvWÀÈEî ¸±mY”±:mwÔÂR»+`dwÜÒ•ñ‡þ²ð¨´Ý°.,¥»X&Þíýee[¥Z9Y^[žêé>Ûõ^éíÒ+¥c¥=¥[JÕâ /6¦öªÇö_è|ý¿ÞÚÊÆ—cylr|ÏwbKëéøü7 (^wjå›­œ™kÝ.u¼}«U>Ê™Kmk.ކ| w{ÜûP˜m¼]«M±®Þ–hŽÏ>0W›bt~Íßü¯t‡¥ôë£a¡÷3´¶Õª¹·Õ=_Ò¶š§2óîˆÖo \‘Fû¦{"bŠÏÛ·Ô®ÚZsoªBê/›í.ˆÖXÑÕ3F?7£—âKjq®sÄm핃Ëê^µa®qÇ­¨¬YVQeÝŠÌвÜ_:)oEåêe•é#Z§ô­˜\³,cÒéWlZg–í_ùÝ¢üZ ,È@oåÕÊHy çŸ©àW¥¯Oo‹mÿWÃ3¹ñÿÀ؃ ÿ×FPUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUaïNàë*ëÄá?çdiÚ$m’¶ J@QèJËR(Ý¡RÚB (bHDÒ¤&)‹X<)iDR*d°,"ÈZ‘¥ì X Ê"²)¨£þggsfä=çÞ›4-Eý¿Ÿ÷ý/óù~/é]Îù=ç9Ïz–KÿMì;kÂìñ“fßgÎøé³öÙwüþ³÷™¾ÿÄÙûÌ7nÿ‰gÍž>~Æ ¥ÿ׋f,oBUú²,䟋‡mÕ²ÂÏûăVˆ²4:NN_Ýzò²¶Ö®nE ÿÇË÷Ý1'ŸÙµìä¶ÁýwܸŸFqQqI鲡eeKŽmmoî8sFÇòöæ®Në8³¡µ¹åäÆÎs¯»»—wÍhìÌ-YØØ}ÚɅ׋::ÚÒ×K kÛÚÜ}ÚIU;œsÎÄÉûî]?aü+ö®?gÒäI{×OÜoÒŠÙ¶ª,½Û˜ƒ[Ôø…ç~1)ŒWQ!ÕÛìÀÊô§"Líé£#,Oÿm -aLèg…î¹mM…ÝÊF¸%éÏ.Ybï½—‹-3Ãi¡195éÚ~T4<‹z/§ƒ™é––…³CghM#OK£¶ùà6‘åa^‘å¯=ÝÚ_ÊåE G¥ë6†æ°ôƒbryÜ:¦!]¯%´¥Æ4¦1Íï²íļ”þbÊ¢t¿šÓŸÞ›/dÃ~a}þo?( åŠØÎøP_xžVxNòÏQay\x.SUx®/ÿþ;ÏóųfÍØrBð>qá@à3ƒ ¶w PX7›Šwt@à@þ7:è³–¶ÕŸÑÒÙÕÚÑ~ðnãnjۭ¾¥½©£¹µýÔƒw;zÑœ}ößí©ÃÚuÖ‚™‹Ž[8»>wG°~áÑ3æÍY¿Û>cÇN_¶¬­eìØY‹fÕ/œ7·aQ}𯨱³çïV¿ÛiÝÝË;öÌ3ÏÓ˜­5¦©ci¶bר…ËZ:»Ïž—&¶O0¦¹»y·t3ùÔ·ÊNúiskS÷ÔaC:½åì©3çÌXÞÞÜÖ2«åŒ–¶ŽeK[Ú»j95]û ±Ùât­®îÎ4óSg·Ÿš&vÚAc ï·ïhZž/:{YK×@lcggcöbhÿ6‡n•­=û¬î–ö,aCÈÀÉ­íƒ6>hÁŒ¹ó·¿ ³céöµàˆí/ø|ë²í/8~îÂí/hœ0yû ¦o³à ±[öé}e0·©£}Nk[Ë („ÎlììÞ:mcç7.ÝNÜôîÆÎÖú “ǫϒèlm>µ¥>¿‰¿”Ø‚†­*pû5ñþ<ý¥};ªc{ûuLkË™-ƒS9hl»Hm«´fŸÕÒ´¼»ñä-©õ§ÕÐÝÒÖÖ¸ añ5ÎC[ºç¶ŸÒÑ[øÑõÇŒû ki[6££ãô9mÍY¶·N¢¹£©ë¯E®¦¿%nÛ&±uv?0ª9탭§´¾?µ²š•Ö@Ú;Ï>&?fl›Êä.¢ííàßT¶ ›No<5×V¶Ÿ¾pá¼ kh=µ½±{yçv6:ïËçvë/æs~ííó[OÞnuÌš—-ÓÞzòûã¦o›Z—5¶ÍlkìêÚNh6Ø·65vç²´uôÃßYxÔ‚OÍž¹hþô#fOoX|ļ‡ïÝN õ3;š:ëÓ„¶$Ðß“›ÿ§ºú ðÿ›ì€5;þTðß×9ÃêSsgänø´tÕ\ÿñÜ'™s^e¦Ï\4wÁü†tsžþÛÚ<¥~Å”ú­Ö™9ozC¶Æô“;–wÏè8k›Åó¦Ï?ôèé‡ÎN×Xpòggn³tÁÑ‹æÍ^”Û@ã²eÙݹ9­-mÍ…M5u¶4·vw þ¨ð5Ám›¡†£Î>ª?WóÒ­¶4uZgÅÞ[^ŸÓ¿ÞœÖήî£Zº–u´7·tNy¶? Õ¹¤ö*$?wFáÞ]ºÎøô³ÿÛüôýÿú™K—-ïnéü_÷?ÌÑÿþyýßHÝúÛ¦÷T?ù€ê'Nš\?aßqõÙcü„ýÓÆ›P¿í÷WçΘÓÙ¸´åÌŽÎÓë?à[·ûNÜïýß¶;cA[sKW÷‚†Õ[Û»[Nméœ:á ±ý/·¬¼¬¥=Á`{ÿ×Á@中B·þ‚ùÜ gwu·,ý lî?cü$_®`°þßðý|î·o…âPJÃ0ì¸Ý;›NkMÏÀï^8 _´{wDzŻwäÏ^Oª1¿áð–³[š§V¬ QßÕφ²0ôĹ3ÆäWknìnL¢[«n å¡"Œ“ÂäpP88L³ÃáèÐZÃgÃçÃ9á¼Ð¾. «Ã¥áòððwáêpMøv¸%Üîß? ¯†¿¿ ¿ÿ#üCøÇðnø§ðÇðÏá_¿FQ44ÕD£££G»Föˆöö §‡ó£iÑìhNtx4/Zž ç‡÷¢ã£ÏDQStjôÙèô¨-Z}.:#Z>­Š¾]}-úvúú†èÆèæèÎèt›¿ïFO„ßE?ŒžŠžŽ~½ý{fG{{º¼£3ß _#ɯ}|ÝÚÜ•¶‘®æ7d_èȽ>q`µìÝû“Ìbò ,É'пíªù Ç´¦kµµä}×1»7e e 泑ýR† ›ÊG8°ùÕmgc… \þIcæt´wÑØÞxjKçqiz-gu§+3¿á¨ŽŽîduòÝä›ÉUɥɕɭÉß%¥É÷’²dMòµä–¤$ US“ø¹´Ä'„‰aß ;›e))NŠ÷5æ¹°_Ø?\œß‰´¸ò/ÚÓ5ׇÔO§¡Ë»º;–æw`qÿž¤1wFîÿ¢ÈñsajºÁC´´È ¯ëêdH~3ÂÌkÂÌ0+LIËóˆüo$hhé>z~Cúo>rN˜w]84æ†O…Ó¡ÉG’…ɱɅɤçÃü° ]ca82¸´pfµtu·¶ç.¹;¿a^ãÉ-miæ:–w6µ$Ã’“'ñÏÂ1áØ°8ŽO£OKÒǧÃIá3¡1œœk*Y¡|É&-¦†åËZ:Ïhm9óØBU¤?»=ËlsšúsÚOíJk`fK[[Rž>*†VG!ùPRù|hN7¶8ÝLö+ñO §Ÿ%vr–TWrb’¾äK'UÕžsÎäö®Ÿ8aÿìÏ LÜÜÞõX±âÅt„h Ks1 6, Ÿ ¡+t‡åéþžÎ gŸTU=¿aFcÓé§vfð`fG[G–ÛEiîs¯Ëå|YGg÷ñ¹fØÝÒÞ]h‘ÝmÙ¯8!ŸëÜ,ôzBR“Ô%#’ái¡íTSý9í®ÓBHKç ƒÚZÏh©oYº¬ûì©SŸ_+Òì¾’ÐV¦åÐÐúù–còM=-žSr î6ýÁ’ª¤ºªjɼåM­Í‡v6¦Å›o«BßúЦ“oÞ/¤ãà—ÃWÂiÂ_ †‹ÂÅákÇfÏïaî9K~IáuòƦ–lÏÒ!½­ãÔ\‹Œª*MF&µÇä/I.iÊïv.`sX“¦_. ks){ZkwËáãÆLÎ; T%µù¼­ ç¯Oó3ep¦®Wæ3•ì˜ìm#mø…äJ¿ßÊ61c\èOïÚp]ú_¸>mySr­-‹È}Q,+ý%Ù 5ßìM>à†pãõáÆpSøN¸9|7L9aPÈ’=½9nKÕfÃQ®všñ’Á_\Ë'ü½pÛ5á¶p{–Qi}µž¼`yw[K÷ÀÀùé܇o·t¸;Ã]Y‡KvId=êçáž\ŸúA¸7ÜîäzÖÆð`x(<œ> …ÇÓpQx2ü0<žîÒ²–’6‘#ZÛÓé®7œÖØÙÒ<+­Åã²ßqV¶üø¬W·µœÚØu»EÇäšSšÀ¬ÎÆSs¿`e ³olmoéLöIêÓÇÉþɼ$T­Iæ'»&c^ÉõÆcæðãðLøI:Ý.Îeô¹°9}Ü~šþ¼^ /‡WÂÏOÌ霕dºå‡öwªYM…Ïšò}q6vvut&Ë’öô±Kr@²KUqÒ™|®zhH #Ù/´ï„×Âëáðfx+ü2ü*¼Þ ¿¿IvK>šìžì‘|,Ù3ùx²Wò‰ä“ÉÞÉ“ªvÊßÂ8lÑóê—5¦ÍøäŽÆÎæúît¿.œ;sÑûŽŸß²xQýìö¦Æe]ËÛÒÂk®_ØÑÕÝÐÔÙº¬»þŒñc&¼?湘£Z›N«Ïʳ~NGçÒÆÜÊãÞ¿òŽ…­Ïšóþe£ÓúmmkÉæ‹®…¹‹rŸ×¤Uœ»ö?øÃ䶺hîœ9õg컽-Õzùû—|tfGgËÂOÓÊ8££3Kµ~ÜY“gMž3yÎ~“³Y<·[‹æÌÚ6…ãÏ™x@6Úî;iÅ áß¿‡?…ÿHkê?Ó†ðçôH,d#Cö·`ŽÏ7°¬Ös­m^ãÙéT¹e^43?ÈÍ|$ävIÆVEÉ~/DqT”v†Ú¨8*I›þ˜hHTvb>¡†´7¥¡iä¼#r‘¹#ˆ­ÚpW2.&'ûnÎ¥1,¯ˆ*÷`ºlb2þ¹hDº¬*ªNS“¿«²0™ëÝÑÈhÔ5Ѩ40?ÊôÏ®¹•òkÔFñµi&뢲uvXgzwºÒÉËÓ&“_;WoÛ~˜kÓÑNaÞ·ÂÓɘdR>ÉD»\íÕçú“Ën¥%™{ί¶[øÓú´¬§äßí\ŸŽS^Œ>í}<Ú+úDšô'ÃéÑÞQv¼wE4.Ÿ>ÿ47L5¤ƒASš ue³r¾ë²±â”ÆåmÝ Óîl\vZC÷Ùm-¹âÛÞÕÒ™Z³Æ”ûh^kûé[ÒÉíç§N<9°º|iZÚ;&3’ÃÓç ãz4)7®OÇõÍaj´úÉÑAÑ!ifÆœžµ­Œ¦$'‡¬ަ&S’ƒ’é[ÍkÑŒÂ2:™šŸB>ÔUص¬!l3¯o5ûD‡ Ì>Óò¡ÕƒCsù¢="š¿>šŸ;¼Úòûˆúó»0ZrMtdtTÔÌIM>uMtttLtl23™•ÌN¦§£ìÑÙÜÑ–6ÈÍÑ Ñ’4èÄèÓÑIis;¬£»aYG÷’þ¡/ëuÉaU•ÉÜcÏÙïú}ö_‘ÏÁÉáÙõéH;esÔœ+¶–ð^øZz€wÔ¡3æäîzöOŒÑiQëú¨µ0õw·-3Â’|_ßòÉqû­H;î~ó7¼4üûõáߣö¨£0Iî±%cò/— þžöÀ\uF]¹¹ìÈä˜8:ŒÎÎF_ÈÝ54=´kØrØ6~ÜÀaÛøÉpØõD+£Îüa[îÐêèdQºÅŸ¢¾ìð)úònÓ擪‹G-ü-ò-“ï¸èÂÐ]œÄÉWÓ /þytI´:º4Z]­¾î‹.Ö¥ýèŠèÊè›ÑUÑßEWGߊ֧;rmt]t}î°1š’ëG4vž" <+mxiÿ>.7-gð‰ýKµ¦GïrçKúß•¶¾lO˸¥½ð&¿¤0U»¨âÎ>ÈWGéYgòåäøä„ä¸äüä+IyͲ³ÒÝ¿ Y’ûë[ru¼_þ¯oMŸýõ­q+V,îO9?úÝU/Ê’ÌÆ½lHúnzÂÝ’ö‘ast{òé´˜‡¥sò¹É¤—¶©ÚÑ]¹êý~V½Ñ¢{£ûÂIéP?;m%ÙÀ•«íS†&K“S““†æSߦ]======–|&iLNN𒿤%=«Érþ!ªN&l™ çº òœsÆOh;û¦fßýW¬x)úQ´)k:Ñ£gò'úIú艞‹6§Ïχ³¢ŽÍJ¹1=Ñ̦‚´úÒ OooMçéÜ@8½­õÔöª¶¯ÓÊ’¶šì׎oŽ~–òE/F/E/:wH˜;Ê%69=iMãæ.Mç£\Ëô{´²ß›–ï^¿ˆ^»&z-z=ëUý'ý ¥a{lûY>ìÍè­k£·¢_fǺ'6’;ÊÝcЛüªoGï\½3è7·<«Ø-‡m‹£ß„ã£ßFý.­ŠßçÎÜŽþ1z7­¾Šþ˜¾þ—4ð°´v´µµt¦ ¥k ÑõxâÀ©P®Ñtä*¹>ùBrvUM²<}µ"_Ñÿæ]“&øÇèÝô³åÉÙÙ —}þçlÆ»3ä'¥ãTZ‹i§ÏuÿÆç‡£…2.J NJº²ñpßt<, Tñ¸ìÚ¸,¿—ÙiY[ë²,#/f»Ë‘ÆåqEî˜ts\>WÇ5ñÈtg5vžÚÒö¥…-i ·g§Ýùs…$ÿ8#9k·Cv[Mrf®M<`B!sã'ò¶ä¤æŽþ‚80ŸŸºx‡ëâúËýø\Î-9—£òyŠ~»%Wñ‡ÓŸ]Òñ½4g»Æ»Ÿ›r×4²lìvH’váöäóYn:kg&çäúò>ãÇ¥döo–£ý÷K³–¶øQtÒ¤\G·–ÓýV ëcñž×Æ{æ³¶¤?kYqmg”Ž?™uãxŸxL®J¿84Y•$¹‚˜0!­€ñrÛÍ:Ý„+^ÇÇòƒt<1Þ7ž”îÞä°,Þ/|.Þ?ío=ñ”èötŽ§Æ‡ÄÓÂYñôxFÿeÅÙŸ[ÞzFÚÛ»saz[wKg{Úÿr-6í`3–ww§£vî<:wL‘ÖWkGskÓÜ´Ýu¦‘'nµN.ÙþUÒSÆôÄ~ä dûÏÜ“óÒ^}tÒ“œ[µãÈìoèõ­œö^Ò[õd²²&ûsG-8|àx°pv]|X<7º¹¤»Y·;qÁïò«Ï».ž×ß÷¯ÐßÒ·ˆó1 ÂÍ×ä×ÏUfZɹξʹwîëL+ÒÙzÂø‰YVøNçL³ï¸ ûOhùäÄ´¶½)$¸(>z}|ta¤)Ì<-K—eç0‹› g‚ƒfÃø¸øøtœ“‹’‹“sóIœúšøÓù3ÛÑý'±ù“ÿ¹l®3ÇŸ‰[oHgŠÍé$pqZßGF·¤]ûÈ´ñ–'‹ÓcX:{ì’\’Oóô¨~}v`›\šFæ&‹Ã¸Ü8´$lε»ÅiNÊsö,2[÷¬¸õÛÙV²u£Û¶‘­ynÿ²õV¦ëÅçŽñª¸/þR|~üåä²dmòõäòd]òäŠä’#Ç9é˜|‘,ÉN°öìª_pfz²pä„#'çÓX·^ÝŸÞeƒ^_·Þ’æñS…KiéÌÏö7=üÉöàÎ4¿Ç.®eså…¹}?2—Çüݘ¦ß'¾9þn|K|kü½ø¶øöøŽøÎø®èÈxCruò­d}rMrmr]r}òíä†äÆä¦ä;é±åÍÉ%U£«ÆT}¢jïª}ªöªšRupÕÇ«>VµgÕ¨ªÝó©?æ]]dã§å|SáuV?‰Ÿ]?›;¹˜;#É1;4 eaÇðѰw óÒ‰ÿ˜tÊ8%z:z6Þ9*^ŸwÅ=ñ7Óìß??¿ÿ¡¨¬hTÑnE{M,šT´_ÑESŠ.:¤hzÑÌ¢ÙE‡Í-:¼èˆ¢EG5]tlÑgŠÚŠÚ‹–]´²è‚¢µEWÝTtGÑãEϽ\ôJÑ«Eoý¾èOÅ¡xhñ¨âÚâŠw*Þ¹ø#ÅõÅã‹)>´xañQÅ‹Š)^\¼¼øKÅ—_Q|]ñ-Åwo(¾§øÞâûŠ7?TüHñóů¿QüVñ¯Šß) %»–L*™^rxÉ1%Í%ËJV”|±¤§ä¼’U%_*ùrÉE%—–\WrwÉý%–l*y®äù’Ÿ–¼Xò«’?”üSÉŸJG”Ö•~´t\éÔÒi¥3Jg•Î)=¬tAé’ÒÖÒÏ•®(ýbiOéWJ/.½¶ôúÒJo*½¹tcéJŸ)}¶ôåÒ·JÿyH<¤|ÈCv2~È”!3†ÌrÂæ!§Y9ä’!ë‡\;äú!7 ¹iÈ+CÞòCþ«lHYMÙÎe/;°ì ²©eÓÊf”Í*›SvXÙáeG”-(;²ìܲ¯–­-»ºì¦²;Êî*ÛPvOÙ½e÷—m,{¨ì‘²ÇÊž,{ªlsÙoË~Wö‡²({·ìeÿRöoe*ûϲ? Cã¡» =h財ßzÏÐg‡¾=lȰ]‡:¬iXû°ó†]0lí°†Ý>lð{†Ý;ìþa‡=?ìÍa¿ö^yT^T^R>¤|Tù‡Ëw)ßµü£å{—O.߯ü€òåsËO(o._Zþåò«Ê¿]~SùÍå·”o( |Sù å¿(«üwåÿXQS±WÅøŠÃ+>]ñ¹Š¾Šó+.¨¸°ââŠK*.­¸¬âë×V|»âÆŠ»+¨x¤â±Š'*~Tñ㊟TwøÂá'o¾lxçðîág ¿tøeÿ>|Ýðo ¿røUÃ7 qøËÃ>üÃ_þæð_ÿçáþŸÃÿ<"1|Ä.#vñÑ{ŒØsÄâm#Îqþˆµ#®qÛˆF<=â…oŒøåˆ·GüzÄoGünÄFüÈwGüqÄ¿øÿUµCÕ®iW[5¾êÀªÙU‡VÍ­:¼êˆªUGVQÕSu^Õªª/U_õ•ª¯V]TuqÕåU×U}»êƪïT}·ê֪۪¯êª—«Þ­®«Þ¥zÏê ÕVT=µzZõôê™Õ‡U]Ý\}JõiÕŸ­î¬î«¾¸zmõÕ÷W?^ýLõ+Õ¿®þÇêÿ¬)«™T3½æS5ÇÔ4לRsZÍgkÚjÚk–ÕtÖtלQsVMOÍù5_©ùjÍE5_«YWseÍU5W×l¨y´æñš'k~RóRÍ›5¿9|dÝÈ]G~bäÞ#ÇŒ7rÂÈ}G0rÊȆ‘ŸÙ:²{äGÞ0òŽ‘wÜ0ò¾‘Œ|päÃ#ŸùÑ¿ù_£JGµó¨FMuð¨CFM5cÔ¬QKF]2êšQwzlÔË£~=êO£«F׌5ºvô£w½óè=Fï9z¯ÑŸ=nôÄÑž:úÐÑG>iôÒÑgŒîý•Ñß}ÓèÛF?5ú…ÑïŽþÚP;²vçÚ}jÇÖŽ¯X;©vjíìÚkO©=³öìÚsjWÔ~±¶§ö¼ÚUµ_ªýríêÚ¯×^]{[íµwÕn¨½§öÞÚûk7Ö>TûHíj_©}µöµÚ7jߪýUí;µ¿©ýûÚ?ÖÕ•Ô ©ZW^WY7¢®ºndÝ躺ºÔ}²nŸº±uû×P7¥nVÝìºCëÖ-­ë¨û\]WÝòº3ëή;§nEÝëzêΫ[U÷¥º/×]P·¦î¶º;êîªÛPwOݽu÷×m¬{¨î‘ºÇꞨûaÝÓu›êž©{¶nsÝ u?«{©î•ºWë^«{£î­º_Õ½S÷›ºwëþ©îŸëþ\÷ÞÑÃv(ß¡r‡Ú>”¿§þRüÜÖ÷zwø„ûÝl­¸<;Wnîêîli\ÚSôëÞhZooïð­§þžðzooYÿýǰju~•Áw'÷ZÓOËBËú/žFkz£O–õßîì[Õ×µ–­M×(t7eÇÞÞ¡7Töêí-Í_¹Ø+·ÖÀm•°fuï•«W­ ½ÓR§äs1øhèíR¸Ö¬+YßÚÀIîNW¬¾jÝÊ쯆]µjÕªtaÅà¢ipIîžhHs>·tuïå—ðå÷¾lñÿüåÿ\Ø_¹ß—e{Û‹ÉÑå—oÿz.Å¿p“¢oð~¼ÿ*I__EO4yܸÆ[}ÕêUÙ£·¸µ©iZˆÂ âËN_òõ“½šžÖvkëÊì–åÊl°é-Îê%]ý}—-öZ³6ÝþB*}éë÷_ýèëëÍ¥œÝ•üÈšu»÷–œ0qrÓ‰¥iÂ;¥?~/=Ü\žû¦HshL­;s§½9´¤ŽN©ìšÂ­Ñ­áÖâ¾´R‹Z[[Ó ¾[£¾ÕëV÷~cp¯šÝÖ}áÃ!dÿöïïõù]Ýö.áÔ\ûØr£°ú{7æ÷8»I{Sº'ÛÞ¦íë½{Ýîßý[²}Ë·æ³²,Ç­†,#z‹š¦M˲2¤p3&¬¹µ´·(+ÚË//ÍßaÍŠ°bð]Ö¾Þn-êO9å¼C>qÓw¢¾ì}éÝÓÕÞw·4·ê†®Ó—Örtàª\S«|ÎßÞ¼r Èz¯^W”­1lË%”¯\ýXºôÁüÒ([Z³å"pÿ)dOôx®oþlÌ•«Ÿ\·²æÁBç»îÚòA-w{÷Þþ¦–ýÿ² þOÜ„ëû‚¿Ð5·s7îo.¿üƒîÉåþ-·åòyÿÀ;s}}YGèë ÿÜÿ¼úÉ|—Èâ†m©×¾ì“¬íDQ“Ùr§#iãÕù޽Íý”¾Õmñ/Ývé{(—ÏþF?(êýw\úMÛî£ÒÜ® —¯MÒËÓl¼_½*íVQ®sE….6ègõª¾´¿­Š¢žèK…ΞW?–îÞÓÙOoÉ´iMMM¯äç±ü=—ê5Šÿ#M7ë¬!ä÷Ø–+x=aó¹.Ñ?ÆôDçG#r©èO;7Æ„´?Ö[tÊ)†ó² ˆ½ƒ¯æ’_ÝûÎVI]yå±5![³M"Eçe×üÎv)·C³÷ë‰.ï ÿšíPöœزš|{õ¯ó5Ú[’M˜­ÃR+{³áqu~ó—žÂVóâªtº¯8ª>„£ê·!+_Ì:ä…á0»,– ‡ñ‚ÃûîZµêŽÜXö›Þ¡]]­­Ù´0­'<¹c´2»–®úz¿“þ³ê®´.r•1´'Ùu¦yÏ=Úߪ¾­‡íÉé€]•¶«¶ÊÔ=mLÈѺ;Ãý§ ùû«ú®ZûØUk¯ÊOW[_ûê‰þmMoekk®´r™oꉢ¸'ªî‰êò\™Ý=Ùîèùåeýée;Yœë9W­Šz‹³äÒÌ—„ž¢ßÞmè /ô„ž´MÅÎûâßûCµï^¶ö7W­ÝpÕÚõW­}ú±uCÖ®K“ŒÆ÷­},{ž”®M… ¬½,›_Ÿê[û›|òuÔ·v}6¡oíÓÙs6\wmVñW猶ûe”žðLnàü”ê5w_¶!ÛØà/·¤½°7ºû²§s³Ñ [~…ϳœW ¾³–ÿüÝ,Óeý×ûr­pû—ÓŒÄwÿæ²B³Êæ«uÃÓ#ÌÖ«Fo*³)|bSñÞ›J÷ÙôØ^›~3eÓ°ƒ7møø¦õÛ´nÏMïŽÚtY´ééÝ×M]²Qå}ß•Ë=Z›Ú»ÒƒŠ£[»'Naöìì³÷ÒÇ…¡çõ¾×Vþ"¼šü|è+/¿üÒK/¾ø³Ÿþ4yaôó›7?÷ì³?ùñ¦§ž|ì¡Üs÷÷þÐý÷ÜyëMß^ÇÆÓ_ý«O=ñèƒ÷n¸íæëׯ¿ÿÁÓï¦áõ•[ül«€4c÷ÜþÝë×óæ'üì}ᢷzÞ oô¼úCz^þP¶Ÿee¾yó³ÏlúáãÝ{÷­7~ëÊu<µ±õÞpñ¶Iºû[Bž{öÇO?ñèÆïï¦k®¸ì¦ÍiÈÂ×r!Éëe¯½ö‹_¼º½˜MO=öà½wÜtÍ•k.}5‹¹'\Rˆéymx.æ•W¶´¡š,â‡Üw×Í×\±æÂŸ¥œöý°z "«˜úA¹m<óôã7ÜrÝk.øá¯rÂ¥¿ìy+¤5ZüúëiÎò•™¼¼S!cÏoþɦ'ºç{×óÒ¯>ðû|ÌÝaÍ_ˆIëÿÙgÒ|Ý~ÃUk¾rÇó1§Þ.+Ää ­>ß´sY{áùçžùÑãï¾éê˾rßú#î k?0âùç²\m¸å[k/øÆ{w„¯ÿªç—á­$WƒªfÇ—^J³•æêáÜzí×/XûÞ–˜ÛÃåÛ©|éÅŸ¾°ù™§¹÷¶ë×]xaò^Ù@Ìm¹˜è­÷U¼øâO7ÿä©Gî»ãÛW\tQÏ ˜ï…u[bzÒ~S“¯Ï´e>ÿ“=vß7|ók}+·œvkˆÞ~{Õ¯ÂÛoW‹K‹á…ç~ôÄwÝtÕ%«ÎvKHÞé};¼óµ·{~ýò—I®CW•ťŗîÓ“Ýý¿»´¯wPØwÃyï$o¯|ç¢mÃF¤aéÖ~ºùÇ?|ðû7_½æË«EÝV½Þ^õNüöÛï|ypdòúˆÿ‡½ëˆâÚÚw—* X¢/ƘÌ3Ï’D)lˆ"ò”FF]ØV–Ýewh–8[XŠ€]£&/RŒ* Š5j4QÑXboôÞ¤ÉffAÙÄç+{]¸s¾ó{î;»ßÞA˜ÀwãÚ¥ßNÞ¿cc„²ÇÛƒ6f)[úÿýEtóÏËçO¦ìßµy(ÈHR¹óÀ±ËèÓá´.›••–%}Êzò„¤Gí` R=ûóò…Si‡b·Ä(–IøEÍØ»wþºžyñôÑÄ=±ßn\.‹è³fí†Í›wûEænÌaegKaD¤OÖP·o\½³>߶YJ}F¿±Û¦o6oÞ¶í»ïö%ý€V箣@dL6òIŸÇ@öàÞ[×._yòøñÇßÍk—.œ9~äpü¡ƒûöïÛ`ÿ{÷îùåçÝ?ýôó?¦ÄÆ"2omîÀ±² 0½øpA†`OOK•¥˜¦¦¦NJŒ;x`?€÷‰Eò<2—•—·*wuŽ4°Ï“'Ñ]»«ìÙ3§Nž8yBzÒøDFÆÑô4@Ç:p(-…æ³óòó£òVç’9ý²³©\# Â?¯fþqñÂo¿—þfrþü¹_Ïœ:žq4-59!>9­Ê_•“+Íé›ý”b‚âß»åOæâ{Y~©ûïΟ=u .À©II±(8¢€C'ëá_’™ä5ÖÕä_†·nQ ½R÷¸ ëÕïp!=uühêáXÄ*(ˆ’U¹¦9Ù®Ÿ9–˜˜’š’vôô¥[ät›ü Áß„¾bQë¼B8q ú#-Œ)X•‘÷qîÓ›'~IÞ·çDzì÷ ‰é—nÓ‹ðÝÛªµ`™W~¿pî̉ŒX¤(Ô)((,Œ,ˆÌËû8çÞÙ½»M?uæ·ƒ'n¯YôÏûPÓRµ¤Ü¤WVêbw2E®*ˆÈWä}’ûøJò÷Sû-ùÈÅ4¯¹¿üú×CvOuEºE­”ôe8EÑ(iÞ§¹Y7n?q!åøéãñg~_±`ÑòäË÷™©L2kùu‹PqtѪˆ‚ùù¹÷Ïïýñâ‘ôc»´s>çŸ'o<¢æJT…¼ô;€‘…áÃóŸf¦l;™š~>-éüiÁBgaüÅ»›€ÔrDˆ¬*&‹XÅÅE…¡Àšó×±íÉé GOžÝâòêùœÅ‹=¾Œ8´Oè3âASÊjCå=óü¶÷dz‰GÓ.&¤þ‘°p!‡\¬ëùÕþkÉ'½‘÷TÕ½~ æ à ÉÓü§W“¿9w,)ídRÜ©3ÁóI΀Ŝ¯ˆc7Ó'TKè­ë0gJK£KÂþaAÎ_ÛSÏħ9½'ý·_.æ@ºž®»Ïß{šMäãÐe¦Çw Ç±HVUQ¬,‚tÏîÙu559õÔÁ”S)¼nÏy+Ý|’•­Âvo¬3Õ]˜?¥:%%¥¥á€—™<ú=aÓù3 )'ïO¿>O¶XßÓ-þÒã8©u¼QþÎm*ë²ðÒˆvqI‰¢XZ40ÿé•”û-.5õìž”ŒC<ÎbªÔnŠSw²ss›ƒtkçcyXRZR˜uíȦø‡“ÏŠ?rm£×b ?/åúSi>‚uÎ'ºMƒ//S–~PRøäê‘õqi;&¥gì>rüLˆ¿°Ÿí8ÿ0¿ €¤á&ðÇ ò¯¨ˆ²ÒKò]NÝx }ËöÔ¤³Û“R2wSûî=¿š·äèÍœ‚Â&cU„'L˜gÑþ¥%E9wÎÚ|0ýÅáÄS{þ™~øµ!Á„ÈÛcæËO¥…H@‡ @>Õcº‹"*"ÊeƒKþjFì7É©›ù¿¤¦ž ;|ì¬råò ‰`áÊS÷ó‹‹Š sèÞÜ‹G¡|aHYT/çáõ_“6íJKÝø™âHâ…QéñgN+å+—’…Éײ‹Š©s¢jaš—£ñB1 Œ•ŠŠ!åe%¹°Ê]>}xû–ýÉC§|™,Þ뇴„³G"Ãå+B–„yX$-!‹YE0ËMòóU‘`ñ…µÎóªÕ•ÒŠ!e®_:w2mï¶{ÿÌÿÔâ§”øÓK=ãSÎ&¯‰RJWz'\Ë+–A nг‚:™£Ç‚]]ùqEyÁÝs ‰±;b>˜p8>Ôiè{ËÒžØ>/Vò3ék×E„~½ìø½¢ÒRY‰´Øð…8ºt˜ÝU:••UUa•C+JýºýÇÝ{öïONØ0{˜Ùßg&ŧ$-™+OON<~nã†5‘˾;ÿ´DZ*eb6ÆÒ¡bÁ’PZ9¤,û=[öý²÷PâžÈÏÍ,Æÿ]JÜÑÐE‹ÂÓ“’RþصaÚàÝ—sätTDꪂ°!T§2ªJV9¤änúæ„ýûv­òš:ÚzÚtÛ‘+RÝå»W¤%'%\JÚ¶~Sà¾ky¡¥dc”& +‚¬®"+‡Ý’ qwÛ‰S\ç¸Í˜nóåÁƒq‡— DžDJbrü¯çb7mYw£Î VI« (;±«ž=[]5 ä~Æ¢/8‹¸^øÂ¹sÜœ]¿OÜŸÃI8_%'IW¿Û*O¸UH–…¶“O…¡z#Æ®ªz^5¤<ïzÆ2É2ë±`Þ¼™ŠÃûR~ö]"X0y_bBrÂñ‹?}§L¼U(ƒ@ˆž<ÁDdÃÜ¡…?SV ©,Ëûëx¤o°?÷Xèî³ÿСäåK|%Ÿý}kJ\BrüÙ“?F$\/C½’’ââÆ ¬¼\ˆQ±êYhÕàò‚{çöxÜÅ»’÷ÞÄõòöòÛWr,.>1)ñ·ŒÕ?]É) -“· ò¨,bžÉ«þQQü$ó˜Ì—Ï_¬ˆKÝãç‰Ã•Æìý1¿Ž‹ƒgSÖŸzX+ «^#žâ_óLV5¸²,÷Î…”„„øxåœ-ŠœE‹=æùè9‡á%ObR¯;2sJË•—–ÐU`C9].­^ýŒ„Te?„¥ùÏ3?q¼¾Z¼h1÷‹Á}ƒeÒ#q>9Y–~3¯´¼<” P X4^^­óìYuõ*®¬(#K>þ#އs.öœÙÚ¡+bSã!FÚÏŸ{¿_FB )£˜ê„(‹´¢êƒÊÒìÌgÁbû÷÷]¼|4lR\|üáåŽÖa§ï”IHPªWX¸Ò¨êH(Ü•e972Â~ŵ :÷(ûFZ¼P;üýçS'Æüz¯ L8¸ÆIKt( àJb€O ¸òü»ç~‘ÌšxäNaiîµäȤÃñâ)Ó¦O\wîaQ™p`l€Áz]R³è¤U*ŠŸþy6>ùfnyeYö•8"iËÿÙ9:88ÚlÍÌUÂ’Š˜ÎQ/=¤5«ªoUUeYÁ“óË*++J³.\êkëèH:è9ÚžxZVJ‘%ˆÂÉktª«kjVЀåee•d•AEIö•Ï)ŽRÝ©‹.d•‘S”é”––”P¨V¥9];‚O…àÓ­÷_Ë+—Ÿ¼Œ ~àV¸ª&º:¦¼1L—G}';:Øúžy\ N2ªH”OLMø„Vu‡úÜ:±ÔfºÍ¾ëá ð@´ÃZàŠ„ëVQpû”t¢øü“2i%BZF½­]G—WVÞ»øÏ3w +ä•Ê y9 ‡ájT»¾&‚}jÊ=Í/ …£ŠrD•ײkjjWC„Ê£²¼º_¥¤ñÔñ8 Ñ•°´†VÈ趨Úh‹€ÞSm$ݶZÕÆø1±×ÕFCÜpð …k¢ý6€_8OY)£ýØuuTk„ÊSªBËêÈZT·bPG(vEU‚ph© £Ù”•L"¡USÁá–¡•ˆ®tÝÚÚUt[¬Çô€®×(€SA¥ª¶Ð:v}]=Y§ Ô³Niff YË®«­ ­UÔFq£kj®p¹—ÉjT#«–>CÕÔ’ø ªÎ®¬¢&yÑÚzVYŒgɳ#굆ÑÜèÚÚL.÷JP)©åSåÕ#Çw&mfÖÕeìÙ£¬“5ûfFоôIZ´¦^ç.Žï%ëõëJëê¢ñ舺µµM®µµ”³‚vf=S¯sËëõö qaô²N/CŽã›ïu½^Û,àr£®(j”ÐD-(E²ç«êõÊ„ÀU&­GÐ…£ëêöà¸âdÓÌàh®<àOÀ % –Ò¢ðçÊz”Aâ,a†´þ£<¦¾¾.Ç“êJq|®S¡3KjkK‚¹ ¡€&tñªçŠzÖy!‰ëSV_h²¾Ï^§iå ºŽB+jÙÑÜÄ0ÈšýìŒ~.‡‚ï$q½oT@6–Œî iâ8Ж$Ê¥\vbm-…fXW]%qÝ© Șiô;/Kä\îöÄ`n¢´VYZ¨KOñúçd½x_e€:;q<‡¬—ÖõnÂÕeàÜcT©e€S¨pkž³rsÉç†e!lÉ —¬þEκ$?_[+ç&*+Se»æ¹ù5/EròR/|o}}2ŽO@ M;Cêë›Ñçq<$)„Ë•gRpiœ]¾SDzé‹’Ÿ?¯/‹!q²ž•,”â&!TáÁu; II\nb(TŠ]]Çô—}ïÚ=ÅsvÎÕY=y•)êCë ²3aJÞÉÌ ãùýó5õ«ê¡¡Ý¿GÖEÀÉCýÎ*nØõ|54„×ÊUÒ†tKX­¬†žˆÅŠÖó†ïa&SRhl@-¿H•/»Ú!)^~߀ÖáïSR¼îÛð††¼exãæÍë´˜J^íCkñÌûóô”¤øûTZ<ë>­ÔuHŠW<€™zIýe1ž¤Äx©VŒ×ŠñZ1þßRŒGYÊΊñÒ¬ÕãeYì§”¼Š²Â;$ȯÏb=í”&¿!;¼3züælVV¶â_,ÉÓ¤Ò×QåÙYÙ-tù{šuù(Z+ï¤,O>í«Ò ïÝ’^-!!9¥=Âüê‚ÈFa~íÒðå²µ1dä®v ó«TÂüK6²b³8pÇâÈv óI¾ëÃ×ÉÅ«£ÆŒú™æï«æ?¤„y劭AäZÑ×Ûf˜›óZ óämÃ6…ù|¾]´tK`àf¡Ù+³­Œ0ÿH“0xɪPI@L¤P¹Áf¤•Õ¨)qMÂüµÂ¼)%̇«Å_o-ýv¡9iõÞØ+4 ó¦y~ûÁç›eÄæåâu2ËÑR+Ý1“ö¨ÑåÃÇèòI¼¨(ÿ€0%ÿ뎖2«þž/«ò·[«ò¦”*°Q¼V@lô5—YñsKMþA+M>¼8¬2=ûwÛJBµÔ?4rÂ(©U±æD+Iþ:IþgÕZ¡ˆô Ø2Ç\n¥76N" @i1*‘K‹zæ?¹’¼A,X'òW*ÆC™ Ç~º‚RãóZ©ñô«Rã#Jß)¡Åø á ±(b™0hÇfÂÒJw´ÝËbüãVb|ZŒ'AžÉÒð%ak§Û’Vc?þ§Z1^§¢¢¼"ê9>pIÐB@q¤·H¼ÍßÎiú$++‹/µ!Ç?däx²UD4KòûE¾ ]üeNPÀú¹NNöƘïoC’ø’$¿•+"ÙðƒäîþD°ÒÕyº“ÓT B$ÿ µ$ŸìA,øôó qØ‚Ù!þ+¿v¥¢8Ø$©“äµ–äO%E{øø ÜYÂ¥c½‚ü¥KÝÜf:9M^ÑI>eçRÜK(æMé×o !’:úË‚¿øbÖ 'ÛøvJò;ÿ©ñåòüü…®ÃÞ1ü¿ ¿>æöA„˜\öå¼ÙŸO÷|Q’/T/É+s½y¾~þ¢ù#{÷5þT" °1#„¯-œ?w¶ãÆöHò± —ð–øùûÎÑï=ìý÷9„p™ÛèÑn!„$ Ôká—_8ýt9GÑ,¦¿Z’Oó øøì‰ƒÞÿpØ'C¸ˆ}C|¦L™àHþab…óöj’äE6ŽÍ}øóÑŸ4FÀ:O›6Þ‘þ¤”ËY8S£$oPrÿ˜³Ù„ñãÉqÆŒ273÷„ùûåÇñc%" !YåïÉ™ÛI¾[yÞ îTgûIc¥VïšÏò_"áOž<ÕiÜ?üüý ñr…—çüö)ò+'Ow°?Æj”µ/ß/à³±“§Ø7õ „þ„¿l9¾ ¾•"¯Ç £I‘ÿe¶½ÓÔ‰cFã¢%’Eã'Lœ`=PÏ!D(bEðÜ]êù”"ÔoªÃäqS]þ”±ã¬¬Æöë>€/ I‰žLLžzX¬,“7Jê/ òÉñqññ䨅®#ÇttoSã ‘P,¯Ä·!È“Õkž‘UÆÍ‚|ìäñ£I«¾ã,zéË>RxBìÓ– /«&Ÿ±Z ò]Æc5ÎLÏæÐ¡'! %K>ù²‚ü|+«1ã‡ô¤y__±P$"œ‡”¶%ȯ‚®3‚üò1#'ö#(A>•/ %\³† W'È÷¥ù˜}ÊòI‹DûAäP½÷£Ï=Ò ÈLR ò‡\ý ñ54ùµ´äþ¢&OiôŒ&Ï.nh`Tú.å;º?^y_çÁ=Jé–Þ5º}›~ãH)òäŸìk×®’™½DïŽ?ÞzwüýîŽGC)E¾£»ãɇr­¯UãµjüWãOà¡£r<++kË¿rc|Ô¿`S|§xegÔwvNvΖlYgõwª˜äöãÇ*\ûµ÷õÙ:Y𖼃â{dïѹ¬œ–úûãôw5»âQÞšN*ðkr×¶Pà¼q>:/æUûâ¯hRà_ÚýMí‹?t(>¡£ò»î'ÃúŸë:!°I~¿ó*ù]^H°^Ü¿ ½«‹Ð;õdË^–ßo¼Z~Oè׫B½L‘ñ»ÈèÇöÈïô¾øEh é÷g±¥»æ}ñád¾qîýó[YïuC¬þèS½ÇZòÆ£Ç-ä÷¿^’ßMòŸf&4ê…I¤ÿKŠú8ÔNõÝ„Rß=QÒíÇbõ3£w-¤÷{-¥÷È¢ðByqރ߶¡>õ1B=z*Nߟ4êîæÕDÌ 'B†&ˆý[Þu9ªNu§6´G™PªûÔ‹…X¦,ÔÓHºéüð*Íý6­¹KK£é}ðâÙ­¨‡>B= ‘A¯PdäÝ^½Ý¤àÑï{Môº#¤oŒÐ»z ¤×[ÜN–ê••–•––ÉJå%ÝJ!Pqq ü“K‹LòŸd¶D†,„ŒØÈäo¡è=â$½>;;Gµ‚4O Fz,Õ£•w{ÒÓ×C¬úPà4o€×£4÷4[@±`dºõ EzÛÚ+¶ëQb{Ê49ÒÓ…TM ÏúöTvjÓ»£°ï¶#‹E"¤ ©êîÓ,­0Òz„‰!¶! +®YQ7jRÔãCôM’Ú±­½G³†ç×c=Òá·G07bóÉë dT£‘®^œF…¼¥ÿ¶Ìyœñf¤7¥}»Óu+J]@ýÝ”uH'\“ä­S–ýÇ7aˆd­Aì]š6›ë”ÜMê¦@lbÓ€=jElvÑ­Ù¡HÎZt iÒªuJîµRÒyèôj&­[žw㘭’*f(õ D:¦ 4h=Zƒ®†ÚÀ”f!ÃCmïz¦¨Ò£ôæ]ƒ7!}X3¶µ­,Gƒ¯­,»²Ù,£þ0-©ÙØÝÖ‘8¿T? ±Œ !›î_ÐŽ‹[læŽy&L“v¼ÝH‰ØÁ+¡ úS޶W0Ö-|üÇ> Ωq‡ÌS"]µ2±%'Àˆ‰­°T<¬GËÃÞR¤O«ÃiVrdg¿T4Ü“–†¿·Fï¤ÓÒpÂ{R~Xf•j„aSZÞ— †ö$©‘ÿV·[ƤF²ô~FGvjEý-]4Yƒ0œ6žÎÚK+à ðkV†)7•2œî@¥=C½2<!Ýj•a/4[­2¼öÔÝ oV†#ÿE{µÃé6E«¼Iެ{¥4Ö´YΔºõ¯- SQïh’†WS’îËêðj€·Ü¨-¯Cõ úû…-ÚŒ(,­é^[[ÅbDayµ^Muõ³êjÙ3x®z+“T“2ü&wkw^~½ÝÚr(ë»2üŸº[;ø­)Ã/ïÖnV†»j·61ÎÏ¡)†­ÿÈ ‹­«ß­»±‰©iÏö›©©©‰q#C}]X›_ÇXl=CãÞýúøÁ‡í¶>8ðýïöíeld Ë~X,]C“¾ ±Úüûþ}Œ»éë¼F,}ã¾XC'íù¯ãßíÙýu`évë=pxC§­F0 ÷ë$ÀÒëÞo°Uçùj—ìó °ôûbóü Õó^#[ßd€™}Ãk%ðåÀNð›´tz-þ†ºùïw6ÛÀôƒQŸ½Cý—Mø{~8ʹáµÐÛ¨3 t§`ø]^?ùJ Ëø;™@×ñw..äo¨_Ðñº’¿3 t)'èZþŽ'ÐÅüN «ù;š@—ów0®çïØ:ðø;”À›àïHo„¿ ¼~úrÜ®$oˆ¿Ý ¼)þö¾${cü µíJàÍñÃû* oNß Cµã€^ÝôÔ'ð&ùJ†ö75Ô}{ü §ÿѯ‡úx³üÕÓ>èÝM÷íñ7lú7õxÃü·-ö4Ôy{üÕc?zÇH÷íñ?·ö·îzo¿Ánø{Æúo‘ßÑü}}öÛãw²hªîxÓüÿ7òíò6ꃷÊïüöù{¼Uþÿ§ù]´üZ~-¿–_˯å×òkùµüZ~-¿–_˯å×òkùµüZ~-¿–_˯å×òkùµüZ~-¿–_˯å×òkùÿ%üÎoŒßùߟ¿ î¿jÛ¨ýGêù»àþ35¦yÿ×ëß§Îì͘¨ß€ùÚ÷ª5›Oú«Ýÿ§ºÿÒi>XúõJ²ëlå×K Þ|'«ÁýÔîTÝ:ÑiöW¸WWîñÕl§‰ÃjÚ€Kß;ÜÊÆÞé3gg—®2gçÏœìm¬†c}ÕïAgî?8ø3ËQ]k–fŸ Ø×ÄP—Åêòû¯Ûs‹öÀýûõ66Ôck܂߉ûÏÛs‡º‰q÷núí¸;œÅÒÑÕÓ××7èZƒˆzí»;žE»ëŽ‹´¦5­iMkZÓšÖ´¦µÿ³þû´™vîó\í±éî.Θëì©ÎNvØ ææsFÙ™›OsŸÆmfa‰¹‹9 à ¾¹¹ýŒA6FÖ>„ŸzÂ9\# ³&x·±õôƒø8×÷ÄÄÚœi§<üp‚ƒù„hîÀ œ4ÈS( Ài"Âaªß& "ð`œ ?óôáˆ%81)€ð1Žb5gø¬=„Üxâò1 ÂÇÔŸç-˜€yB\Ôƒ Ç“' „l¦6 ÄÅÌ#dBkÏ)C¶tÊV˜ Gì‹9Šq\`,ÓGèŸÈ`¶ÂG(yeVvb1Tãx¼@óÃý< 1Lè…Íââ8_(¢æF@µ˜Œ‡<$¢‰/>bSÅ.T‚‹¹ 6’âÁÌÃl ñÇmÁZ%Š kÌÊ…%ƒo¼mlsUT àÐPâ¹·$#Àæp‰PЈ±÷ às¡³ŠqÌ^àÃxÒçù4Ü#ÀÛ»1úÁQÌùð<%0v˜ÏOÄDZi<1îI¸à\sæ„àbŒÏósÄ!¯œXAAAfp\Âå›Á´išP-›©‰„5“ºûð$˜H,ôsü0øÑKŒã˜DèEqÄøD,D€yB·Ä‚„ó<ãÁ¸ ¸æÐ-:„ŸËó ¡Z\H‘a8¯üš†ÛqÆl̇jùxðyž˜3N> 3ã8Õ*ñÁ¹Tß)ˆ•†›* Ì!@¡9ÔzÓXmœnâ¦é>’ޤâSŽA†Ã8Õ 1&Qð!ó ƤkÖ\ &vë’4÷œ‹ñ4ƒP}ôØÐë ŸyàX€÷ àgŠîØ'÷é3g»c¶3æaslgͲŸá>o"¸Ãl„£0ù™`´?5Þ< €þÂÚJ„Pµs±Ÿe7Ýv†»íT'g'÷yXcÁœÜgØ»¹a3ga¶˜«í,w'»Ùζ³`Ñžå:ÓÍÞLU#ÚÙ Ç5 §æGMP.,È<¾ä¥Š`ó`H k>óáÀù ³‡óš‹q`•…¼j ix+"ªëàØ\Þ‰Ï ‰áX˜3‹Rq˜u ÕhšÃ1'§™ªÌc`ÉÅéSÅ•Ïñı˜[hÔ(‹á´ÃT¡„ 0.¶˜ÅHKKË–£,ÆÇf»ÙšµXÙU×ø.!t3sA1g.kÚ×ZÓšÖ´¦5­ií¿Ïž›£O†œ‘y"â#ZŠpÄ…¶@x# ´‘ž1xö‚G'øÍ ~6C"Ú_‚hõïÚëdŽŒàË9 ©(¼¹à‡£ßž14 ¾!7Àáp„í3á·¹Ð6ñ87älbðþ¢EF^ ? ·š˜­û¡Q¹E\ŽðM4õ°+f€Ït`ðšžàâ šÏ"¨Åâ ý$^Ƀ!xôl“Ï"`*„¢àt«-<tíôqÝK&–Æ ƒÞŠÁ×¾ÍTÙjMkZÓšÖ´¦5­iMkZÓšÖþ;m™æ4ÕŽÏ‘Hp 6 F·P¶¬é'ÊlíÜfÎpea+G€óáw"¶b"ÖÂÕÎÙÖr´õS…Á­;ÛÎpœmëh3=–ص::s¶»³½;ÍÉfpüpÎ窨<©$ É‹Mªô^ljÛlWûYYÍpVÜ“xÁgÅðæŸ—5ú9ðÄb. ©Ï7'¾œvQ[k«„-Ú)óàQŸ »Aÿpª/ùp…®bÜKÒÖa¯>_}o1ÇÃE ÁÛrðÁ©þ]x‚‰zW~Û~¸Øw Emz‰§+‡ï"ä¶™‰P„ ì8b¢­ã"—ËÇí|8o¼mèª#Ì ¶ĸ„u.N ú¾Hü8|¾¦‘#„ÞÞ|Ü•ò$ˆ6¹…ü?\mõuÕâq µ1hu!‚ݨª¨Á¸¨ ¢9HˆÚ m­*.8„ìì’òò9…ÃÀq$øtfæCl'÷kó TyÁŒT;½çÐCÒNç¹LÝÚé=¯]ÞÍ+ƒ&ϦB“#OБº5z·¯nÞíª[£sûêÖèݾº5¯d=©š¹Òk’E|-;à;²¾£4ù6®ÀܨUX“½Êjt‚ .Æž¸ÆRªeMnM ³FGzâO¥¯¯íóuc–tMÎ-uuÞ]òzĵ¹„|1ÒxØmš3µ®Qè«2tšú…jÿÕ$ÌÚVh_FkMkZÓÚœYOöã7¾…ž4ÈÒÌb—!—'ðž4h¶»Ãˆqƒ&Û5ß& âó$Ä‹÷ ØŠ¨}˜vB?Q‹™[\ÜÜ1Fß%€½¸S™C¹›y ý(G‰9uÇÅDˆ3D3.Á¥6ø34-ò¢÷ù{6Fݬ}ñ§©Ó„žÔ®jg¡'½EÔÚœj‡ÃÔÆ]·¥¥%6Ær46jÌxl”¥f_–#ÇÁƒ…ÅHÌÚ\åÖÏžË#„bW!s‹ƒ¤)œŠ•q9¾±½™gìHl4õ=z,|34V4ÍÈq-hÌ[æï †÷AB±/¦ºž¶îÀèÑVf–/çé"¡^g´ç<ÒräØfT#«µ9]Sí¦V­iMkZÓšÖ´¦5­iMkZûŸ4Ýîð>çøQ÷Þs¥Ù: Ö…Ba2ÃÍi*#þNãé}¤P6ÊÁ(tãb !„~LãÇì)Ôt†›KÁñàãnôPTý¼AÁúÔx†%ð˜÷ìÊP¥‚Å›´ F€TièÒïÙ(}¦IzmPèò¦L™‚[¶t›ÆÜ@Ž‹•L*>[±˜‰ýㆭFëÛÖ}«0¨“…Ÿ2GÇèçNk÷Ø w7;sW[gÌA(öãJ8ÄòRÊê‰d +Q(Pôlìê,œ¹=ÿã ›Àxœü8Þ82eµóÁ=}ý8b_¥2Tñ㦟àHOæˆ /纇CPAøRÒÉm2”ŽH¹÷EÞBw·ô£Ò6uR}|…1Ÿv)÷ªwŸ†wȽ)ú¼ŽEo—ûßš¢Óë5}¢Ö¯‰¥¬ÝdÌç“êa[aÒ°¾Md/Â^ úv“â»ï(Lw;¡€ ©Œ$JÅö­l*‹#t8æÃ8ÉK#«0‘xøÁ´°õ¤N‚ tL*^Ð¥§ôb6kð$ ³ g¨…RÍLiiI#-_B²4"GÒÈ‘/!Ù‘£h䨗: ª®l.õ‡<0: ón«“ÔÑî‹f¸9@Ý©S ¶­S †ê£-j ¨ØW·76c°ê¼4ÿÏÞ“†GQe{ëvV²M88ŠDA0#‹:zY (‹,BD(hH0da‘!—†@¡,‚)GŒÎøôBØ„ ÊÃÄe"öâ<Ç'øºû}¾GÅT½soU’N§ÓÄ÷üfþPܪ:û=÷ܪ:·Ï×µ»ÕóŽ(ÆÑÄ9âxíRr+_'ÎÖ‰ãý¾šƒ§Zó“§XË“YñPqî¢%Ö¿U¼Î ¹¥³Ñ9{L׿wNnù¹VÄ‹CyÝ××è f°ßP0¼sáªÀd—tê þÞFµ „;š[ÂWÕÃ×(GÒ¿õæšîÕ +Þà2¾ÿælbh¶ëw^ÝmBY^žþí:÷ˈ7îãÓ²øwð\tá/#Úï1#¸Û«õ1úØo”f°Ÿ«1JÝ[îI7\½.†›¿&”ùIw^?¾Õ]‹¤ˆÙ¹ù‹ ÊCϬ"0W`¬½õkÅäÜüÜe¹«t}ËBÍëx˜×ºŒ’Ž3;ÚWx™ÍIZ´÷7¦þóASgÌIÖÑ`ĨPn¹Q°‚nÅ+èXp½õ•r¯$y½ÌžëâŒ[KV~›;*«äÕòOä|r7Un¬—« ÒÖÛ #ÚS-#Õ@„ó"5~ï„ìh’}ywµ|ñ‚¬þ$Û«eÏùD£üe“lRå[.ÈJµ\[-Ÿ¯—cT¹ßùB•|ò„ÜûÙÝ$÷ï'_õÉ_/Èû«å¦‹††¨–âZ®¤®ZŽWåžIò¥&9B•¿j’“{ËI‰òMò·>¹¦ZŽTåS'ä³'äËMò×Mr‚*§ô—¿÷튕‡Ü#_f£’ [¥“wysûA¤Ü|ZR˜–hV?ÍBØ&o'%Á…f1$!lŽe•–Ã43Ðߦ2ž–zXˆ0οhØ@˜"¾]Qª‰d˜˜¶R@ÃÀ ík™ ÔI®Ä¿ÒÖ@œê ñ^gˆ³!Î3D·Ö²Cªp[ÛŠL ð~Žõ+O5à8ùÊ@r;'_Ù|7‡û!ðnKky¬­åÂÛÊj p·UCà]\¶_µ¿Êá~ÇÜ‘ÊcG¯ì6`=¹è¶R_Ü‹‹ð+6à?p³[ëá 襡ÚRªÏ¡½‘Êu‚•Äx{ˆ ZgDA÷Ž¥6†Í¢à…qÅnnå‡JaÌÁë9 ŠýŒ"x¥¬AqÀ_Ff0 »¿Œ 5ÌA‹P ‚ZF´º× ¨ó·¢}‰¬A±Ëߊ 'ÙH«+5ð§ð©ø÷ð÷àÏà‡à{ú÷¡}á®AÑË¿A)γ´°CM±ü–…³…©¿Ê"$  Ô@ýÀäu¨ü4@&)4eOƒv-_È%6D>À4—ìÀ”¼‰È—°{ì ò5¦Yd¦U½Ð›6’ Oazž(y‘K˜*L¿ •ˆ®!v`ۂȧ˜ž$‡ZFþˆéפ ÑDÄ´ÿRz ¹(йd1¦CÉyL÷àØƒÈßa·‘a÷*"nL#ÉdF¹E`ZG^Æt!YéògD‰‘+˜N"'Ed¶@{‘˜V“§1-"¯‚çùÓžä-8Þ†ÈEL‘fDcÈ1–“?ašL. 4‘ìÃô[R(Ðyd¦ ÙäùÓT2Óndtó5D¾Àô,©ƒc‘¯0ýžÂt-9ˆ©•¬ÁôR‹©›¼ƒèdÒO &2G %ä5õ"Ø=ƒÈ_1'ïD¤ Ó¦ô ²Ó©ä*!ò1¦ï‘Ã}„|.ÐÝd;¦+‰‚é.ò ¦—É&D¿"2¢"Y‰i-y S•dã~DþÓÙ$ S± ÔGôOˆü Ó pM"ûA'A¤Ó%ä8þ7Dþv/"âÄô9‡éU²Óä @LjÚÉVLäN&m˜ž"µ­!/O"ŸaºŒ<‹éjò6¦“õ í)D>Á´ßz1Ö“íM>è~²Ó äˆ~ ݧ™$ÓŸÈÃM)ØE¾Á»Ð¸Åÿj☱ ²Zë~*+o,@ߨnl7¶ÛíÆvc»±ÝØþ©[îÂü„ö–L;¥/BBTÛ{í¾mÔ4ÏZM» ÿW|šVçWnviÚk5õ¹F­y™¦]{TÓ¾;ªiŽsšzävuõí›ï>Ñ´Kû´æÚ2íç.iZ#ð}0õ“2TÕÜ¢¨Ñÿmzÿzä CGuþ¾?Uý±Ý¹Ãáðù6;NÿsÎÕr¯Ÿ4‡Óáõµ1xœÀîmGîU¯øK÷ø¼~ä‡Ó]u:fŠ%“}:“{ý²Æ{ @I÷ªBÁýPÇ»À– ÑçÖ¡ ôD‘”Î'ˆk´äTÏÍíPŠ3Äs¿;ä$t(×™¥î.Íåܼ¡÷"~âŠøÝ´q£ûšãªPä9{æèŇžEѦ]çª{ÿåyI;Q·YgêO646.^œ!<ƒbn?|´áÝÚ÷7ÎÍZr×v‡·Ÿ®;Y÷îÞÇd-ž&lC±³Ïn8ZûNἬ9©ÛPÜíÇO>aÿ÷e-°NÛŠâ^;Ss¢îÈáÜùYY‹o@ä¦?¿}¤áÀ{//Y˜e¿ÅG­¯ùP£rô´­xiö¼Ä-(þ7ÛŽIÊñ=ôÄá'W-³lA ãö{b[CýöCïì¯XS¾4n3JŒ0ÛŽ¿9]¬=.í<úΞ6òàFÔ³ûÀûÉÇêm#½Ñ°7ëõº“ÊÖM¶>•è¦Øöºã5›§ì·®¾®,û­ÃÇìܹ<|º)¬ôÐëÏMy_ZVMýs‹òö×Õ~éù<à‰z|Ù£?<}æÄ‡_«UJ ³ÿXWsÚþâRP•¹j™uÞœi[jk×å”M}æHÍ‘Óo.Û„z„?¸²(W\e?ô¢Üü{Šì5ï®ÝŒ’R<>¾ðÐ[ -¸3íÀ¡ƒ5'k~ýJįœ¿ {îí(³ñíƒ5§ó¶¡ø¡9ÙÙ³PTUÃÛíˆÈbÎD¡;éуo[‡GnC¸û)E{ëøÆ1“FDÈ(rÈ«sÇ<øÙ$£ˆ[ÇOš01Ýô ëþÀ¤ŒÏ#SÌØtabbw#»,wº¹_ „@ÏMOUìX¹k(„^RUºiÍæ‚Ôá;WUH«6¥Oa!У‚”=]¾}δ¿†²·¯_KV¥¦¥ÌB }çŠUJž;4-ÍÒBঠ•Å•¥IKKb‚ï–·µpíÚ²J˰´´‘ÝaÄ#æ¬.,³<ßð´)ŒxÄÌåÙÅ…eÛ§=xÚð€tŸ[>cÙ“E¹O>™1ñÁûûB Ì[>zÎÊUsJ×Lž4itÄ@øÓWäI/Y=sNùï—MŸ2y0 Nì­wš·¼tjŸž9å朲ßΞ95‰gAñŠ¢™ƒoJ˜º|ù¸´ÂÒÕås›1`šT´dî¸A·õ½mDáò–Qùee űÀ>âÔ”»SïùíÀÅEùãG.)+YW´h ¨ OxÔð4ó=³ K¦ÊüXiIyÅÒ ¦™61¿({Ä}£o¿¢°xõšG ~sÿˆŠòÇ ž–ا°¸¨xMiâfÔ]€ 8}hÚð¡¿B#Ë ŠJ*2`ÈoÿÝðôÔH!dÅã0äñ½Òï»‚àæ¼ÒÂ"Kr8AÌ€›!ú®˜Ù/åŽ0‚>‹‡õðÛ>‚ iÀ]R’1Aì))qQý“YDFñ ï&„‡a©{¬ÐÝÔ=ŠALŠ‹ŽN@‚ "),õ<Ñêþ§©@k/rißiôÌZíÚµòÏ[ðâWšÚü„؆†OÁ„eå?ì ÇšÚQÚ·¶ky«±VÐVoM£äm‚Æäôáí(®²HN¨r’Ÿ8ø'v-PkßmÞŽò;Öᑼ5ñVà-ˆdrÞ"í¼Ê´lcºúldzxLïâ½@ky;ŠCúð6¡‚wž·Bkb˜‰aئÿçÛâ›÷y ú¸ÛûA”Áƒ<yêÌk¸À¨¾ b\^o‡gf'ß!ab♘+‰Ó9d”>o b–e‚x5Pþq1ªÏh OS½Þ@1Ìx—/üGf#K%‚×¹¥2Ò@ëÌGñÈuY6 rZæ4fN{¥ê2Ž1ò6ƒ$G{¸êqºÀ÷^g;øÌ@ Ä@Nët:ýœNT›–Ó·‰f4>‡ÇËämÍé!«Þ§²£w¶deÌ>–?³¤ÛÓFÏ2sÈÅ¹å §•½^¶lÐUÌ…ŒŸÆªù#Øê$úN§ª<õúf6bÞWY@wíÓGˆ•±' ­ô²ñnv:Q ôÒw6€ÍNg‡ð÷é±¥½È5ƒ¯|Án>ŸW ¾Î£ù‚NaŸ·³…¡Næ¼Oû7¸¥#¥ýK7;Ëy%È÷º–E¹Å!™ó‹%ÑÖ%zqä Ã M k\ÌlYg3¤È]°H-f³Å2Ltv²JÒnc)¹ÈY‚/L&Úæù`ù0‘‘w²ÐÑÞ7ï›Í­Ë&ANÚ-’ð΂.>! R,ÜzÐÐ"^¹®oø‘Ùº¿#Ïd‹6¶®XocãEóHCº#´ñ¢~‡ÿ!-Ö‡²†­Àˆ–Ln=ïig‹d­ËM¢hxG”tû¯„6Fb¾a B¢”Áã–tr ¸þlVø„NèD_œ²²p€@%Qétú1‹ÙšèÐW”ø¢WPâË 3c´tÙÎÖö$Ædfl6kßÛp“m±)v7_Ž“l–Loc‹b½u‰"_ÐË]Š›/,INÖ]Ö ±ÃX]ùð€á.—ÓÅVÂØ Z-|ÉP´‰æK:…b·+È!Î$¾€¦wØHÏFîx[sJ™`ˆ œ³×’ *:Ê×Z"¢P 2%c¡M÷Ðèôn›h„¡b5ëóÕ&9ø‚wiaÕ£P’Øš+ÛKN—U_uÁâÀÊãO)®ÉåæevB¯]fW»¯=êWÅ‹E¹ÞœË×ç0Ó †ºªžºÜºŒ ŸP×N{Û|U2ÍÜGbÈ‹ó‡móUÑåÛ”Ðת¶‹™Ô,LB^;]Ζd˨’Sq*JïxŒlQÒ¡Ø»ÊAÈ?î.2¸$ûÏ‘ &ÿgܵÝ!¯XÁ×aÝÚÏb°kÿ¤-7‡-Ìvûîо炬¢Ìé3{íFÝzîûðÔ¹.Ôœ¹²ôU‹ÉÅºÆÆ35 Ô.¾õ—ñá_?ÕXsúlù‚Y¦—PüMož?ÒpüÌþã¼ðØÂÜÁ/¡„ÕçìG©­={"g~öB1±%Žy§¾æÙ{¸¨®çôl_zWŠRDª¤£ônïôÞa;KUw)Š¢*¨±+Vú.ì.½Š½÷-&–XbLù%ysÓ~‰1Fýýßç=!‹÷ÎwfΜ™9íÞ³êûÏ, ‰ŽŠJô%|‚4uª6uµµª ‹ˆŽŠŽN0€«üsÒ¶þ&ñ@;.FÅFkl@šþ‡Ó¾êΕ €2**ÙyÒÒÚQ&kí¯k= Ž ‡‹‘ñóé둪BÁ¹þfÙ@g}ÇÑÅÁQÑ‚(B’)P3Žilm;¸¿µ·6sŽJ˜JX´ftw×K¤‡ëšÛÏ­JJˆîqúp9°»m›HÒÕ¹¿­¯ÏIŠŠsY´ƒÚ:×îh•Ü"“Û…ß2ˆU©D:äð¶Î5KZ›voíl=YšÅe%&ÚW¢!z‹ûÚÊÓZÚ»—4K{ y|.3B¡ ñÝÕ'+õ/éh>^ZÖ!>ÜSX¸8‡—e·éÇ ZÚê9E·Šzjãö·‰È–--X˜›¢PŽôuƒJšÚ[«âÌìj¤Í}œD‰¬épÓªK„EA+‘‘™ýÔˆ%{[[[zVØÙÐÿɼÜv©øP[ÙêeE…#V c›zQ“´YÒÒ¸bŠùX£­¢vQ‚¥’¦¾CkËVdÑK±r¹¨ºNܼ[8z‚“íä2qÇ¢ÈÈIÛ©k×TÄ– JNg]ͶÂðI'ûø{صÔumMN[Ò.‘4–l\³) ˆT¼¨3çÏžêïÝTßÔœÉdEó[›¥âƒ‡vVl]°é*ÍKŠNHL_0Ö”Y»šêZ—'±y‘-b„|¶iÓ¶ùP±áL+)>&lAðôYmË®äGcs“´©çøîá¥ÈPaÖbnr|LĬtT13&%•ë3bk ÔV|¨¯&­ ·ÍÌã¦'%×Hkee1I‰ ‰6C²»EÍ’æ£}K©eh˜þÜð9^9¢¶=)±ñàg£ Æìka‚ÃÝ–ëл­‹C£#£b˜k!ÿŽ&‘¸YÒtb)aÒñ`DDEFÅÍ1$!rA—H Y«õzD³I‹ˆŒ¦.@Šm"±¸¹mq=¢šE&†E{…H!H&–|ÿ1YcVlʸ¤Ú#µl˜êhµ‘ˆ&žêH‘”Ô%kLu𠲬BŠÁÝk}½ü|}Gv"…¹,??_?z"Ž ôø,v#ª…¿¿¯Ÿ'}"ëùûšïC$Ý@…ýˆ0Äà.‚à·L ˜ìënjê¬ Á¯ÊÙV ,Þ–)¨ ÂÁ?sK!Ÿ¿v1wM±½ÿ˜22 W±„ýmÆ!øÕ[ò2ó>áf®OkïdÁ?µ2Ÿ›Q¾„¹¬ÌÑÆÞÁ^iR².(eg×0nž7N`Ot²‚àWVelÌâg¬ÏæT掳Úœ!Ê• Aë‹ÙËóS…k<&í‰JÒØ¢µìŒœ²ôŒõñcóí .Ëʪi[syÜÒLö²Bû‰@éhK]”és*W²¸K—¦en˜>“Rÿ%«ÙìÌÕLö2&u Q¯jŸ›Çä²J2YÙ;C';Ù °pyB.?†ÉY¸$%£d%85\v QoËÏ ãóJâ9Ü-iž~“ìpÔOâg†ÌÌd0cùüÕs}ü}œœF@ÔkÎÊÍÌÊÈÌâòr §Oñð´§®EC c“rx ¬æñ¹Ëæ-Èf s§Ïò2Áao<“ÃMŸ6Ì…ÏÈeÙ¥d²ó³fÍžèM+C óY¢ ©b:" ®‘iù. ^û.„ÊV "J¿ä»Bx߆´S‘„x–ÍjD&iTB9æQ*ßÊ¡Ò(x‡€wÈ„¸F!S©dPái0!6`~%x[f VÁD¼—òˆQ~…„w—H$ùžˆˆp§¸,ܯD\-ÃV[ ñ¶“|ï Sñމ öºR¼yD¬Ü<*C4‰B¢@õ—Àu2Þð"RË H˜Y!Бˆdà„wˆD2T4Fd2Þ£®“_Ê—¯ý¨M&É¥­‡¡Óà*™"ñæI1ï¶HØÙÉØ2Ú…÷À4W"âm;\Y"…°Àø®LFÜ zS‰ð7"ï4"ÞË"î8o”íE@ÜU¹‹’ÓSñêßû}èMÅÜHGWƒN¡Sÿ„\kçíã½ÇZ7n¬)°øBîï¦è:o¦÷|ôýÕ ò›È‡ôü~Z°Ýø äÄÅÜ¢ˆQø{zÿZííµûÛ*íøïuçâ¡g›…šØ\ö'¾ž~Òƒ?Ñߥ½–\·çÏ'™×kù“ÿbuöNÖëõüúOäßítx-{û[f*\éuä£ÿ™ü›µæ¯%ø‹YâÀœ×gÜ‘¿ZL ùÔ‹5 möüëÊê.~ôWäw2´ÿŠšæÓû× 5NákºS«žþõ”ø[ã{¸Jºc¦ûþuSè&×?°7\S{øÞ·¯Ÿq?/Òû=9}Ëf胩¿§úþ ô2Çß“;ÞyÓ ÀŽ‘¿ëåo"ÿ©rØï]}îµ7Ñ—éþ!é%¾a%ä§50ÒŽ=ñ÷€mFlXõ º—Gß2î¿ýƦøößlêßœIúïl3,¶¶¿·uWÛor¾;÷íoÐÿ“³)[»¸:ŽrÙù+ý…‚ößL'½&«Ùíùnä‡í³?ÿ°sÄëϸò'ƒ«ŒIJšKø5Ú—¾.oŽÌ¼‚)Dà3Ö;~ðíÊ×Å/Ò i{öóÃèHv’ßòI¶öëÊÕë&áø¦xHciÿ£.ž`-·ðOõNÿpL@)„v—§õG†¹÷¬w%üóa‡ArE¨ÆÛŒSôŒ~ ±d^ýsi’?ÅñëÏDRÔR§}‹†:-ÙºqÙtCëY)©ažcA EÛ`˜õÒÓ+>ræÂYñŽÆ“§uµ¶®›éÍÞR+jÉT¹…ô"%}Î’ô8ÐÛsðÒ¥¶Ý¢ÃgN^zxÔã2pÜÒ×ÖÕ/mê<ÐÓÓÕ{êBÇnñác^¾Þ¥p Óæ·è隷oïéíîî:zõȾ݇û{Ï|z`u‚Õ d¨!:xò\W¤¿·§»³÷ÜùæÍýý݇®žÙÅ‹ž­sj¾t¶¥©»¿»§³ýðùîݵ}»»N^h.Œ‹ˆó¦]ƒypéƒ'/ö4´ôôõôtôœ>T½§} ¿ëÈ¥Þò”°Èø8ë«h„jbË׉;»ûzº{N“îôu¸pzoVdxt\ò å+hÄämœ¾ØÙØÚÝÕÝÝ1p~ º¦ëPo-Ë#¢bcF_F†Z­ ï`sKwWWggÿ¹cõ»¤}}]‡®Ù#ˆ%&ÍP¹ˆ ƒë»zÏ”4ua[ç™K­Ûkºû»ºN©Ï ‹Æ’âãɹãÖþ¶¶-õ²î®Î޶Ã׎î«jéëí>~©seBHTLll\lTl”Åyd¨Ão=Ðß+®iîÒöž‹šwŠûú:\>µ+#2DSãb#¢“§+EÖŠa ]=Ǻö×µ÷mûÑKÝ;÷v ôöœ¹,-NŒˆŽŒŠŒŽŠ‰q$ŸAÃí·ôuô¨Û/ÎmŽTooêëíñú°ÅId⺵¯³o ±¶£ è½pZ¼GÖÛÕ~ìÆñO˜ááQq‚hPG ¢ˆ Ó”£qÚ‚ÌŒ–vw½?ƒ6NŽ‹Ož?¬9©ÍÙÕÙ&minÜ¿†—³»³›©óܱ­¹û;dà¼MÝWNì,æçÚ™<;=59%a©ÑƧïé67Iv¬b‡&UÊ:póÈŽŸmÌç­‘µK…’!Gnü¤ ¿H(X˜—Šóx¬ô4æ<µä¢9{#ÔR,‘5ì\™>sf^-ø„´©ùОլÜ=]¬À—ÏÝî«,È/Ì @{>‡ pVº¡ ¹Òl¸{¡iš%RQUIj{øziÞqîäþœ”’Nü/QÛåÛk—,)åæåp9ðà ÖîB&š3>‘ÊD™´~sqJ€C€PÔÞ$jn’=']žÂØÔÑ&” ml½zSZ¾lEqaQ>Ô`a6ÇÏa;;Ðd;îžVic}#˜}Ýâx?[—ô=í2‘H,î:;°“S« •4¶_».*_±biÑÒ%ù‚¼¼ÜL.?+bH;rWµMÛ*•554ˆÄõ;K¹¡>ãlÂÖ·âͪzé‘Ã{s#¢‹›¡PÆŽë—ªËJJ–.[†õÈÍÍáee¸['iÈ$ÆfI«DTß –Ôo$Ïtµ²XÚÔ.‰úOˆ–&Î[ î#gÓyýüî²ÒòåËŠ‹ „Ð"¹ S ¥È‡ l5#Ÿ´ØÔ74IêÖg…ùÛfËØ×.m‰[OöoàEÍOÙÔ1ÈHÔyýÜžòµëV//.ZZ$ÈË]$œMoB~ú¯Ô -àOÀI,•ì]Áž7y´ñPÓ¹ë!òE¢†¦ƒÇëña¡ÜªNˆ)æuí,ðª,[±¬ Í”'\èØñ@ÑïS^'i‘ŠêDIÝÆE‘ΣŒ †M4u4ƒb ':`ü¹¨®³E"ꀹ¯žÛ»zM°[RX˜Ö*bÛ‡œ¨ŠtmKÛI>³ïjhjÅ ÖÕ546ÉšwÅOqkii2lLìŽöQ£¸AräÐîÈ?1ÅM-ùíÆ¶+—êÖ”WT¬^½¼¤¸¨¨@X0“¶Í‘X´y÷þºFi Xª¡¾¾ª-“ì_Új7vìH#3£SV6·65‚¨G—Ã8*,¾¼¥›¤õò ÙºÕ••å+V.+ZR´4wÜ^DÓÌ‹êꛄ"ÃÆ}Õ˜g}c³LZ·!g³…ɨ‰Vf&F.Yµ « Ñ¼óXË&ŒÌB“6@ë šTzþf׿µk+±QK—.YÁ¾¹çÔKjëjj÷ï®Þ_S··ŒÚØÜ"­ûDá5Æx„ÕD‡ VFcb¶µ·ˆE ¢–ê²¢ MÙÒÕ. •ÅÍ'nìZ¿¶¢²bÕª5Ë ŠW%¨ïAʕҚÝÕÕ5ûvOAݨqs‹¬¦2;Üw‚¹©Åg;K³À’v1ØVÔy aYBhdLTXú¶ÎV¡D¢^tðÆñú-k*ÖU–•®(.YHÞ\•REµ{vWïÝS³wwMumcC³L´]ælçqf£m]ímGOæW·4ƒg5Jú$k8Q1À˜½£³Uî ÙÜØ}ílÓ®kÖT®«([¹²,Ân4¸³qÍþê}»jöí­oh–4To]š>ÛÉr¤ù({/wW'û1Žq[dâÆfQ}SwÏ®ÅI±ñ‰IñÑœííØkåFn»|¥­zûúŠÊµ«×–¯,XìBó ®÷íÙ¿{_ÍþQs³¸nëJ~˜·­¥ÅXGw¿ /W;›‰óW‰% `䮆•ìÄäÔÔääxö–ÖH€8¼Ä’“×{kölY·vMÙÚÊ•k&»‚iYkã¾}û÷×7 D5K2#¬Ì­mÝýý}ýýü<\'ø êe¢úFpÁƒ]²S“©ôäÔø´ÐßA2ÖCÜ8!ªÞ³aÍšµ•ëVW.4¨B Ô˜à  ¢†Úš}[Ë‹2ÂüG[ZŽsõ1{Êôþ¾>¾ÞnN.qÛdM2µ¢î¾š%Ìt#--5%*nm«¬Y"W»¹±ëÆõöÚÚíë**Ö–WlÌ ¼í×í­Ú¾eCYQ.+jª‡ãX«Q6“üf†Î›={ÆŒéÞ>ðãì8kØ£©\¿¥ œ #ã„ÂÜL~‡ÅL‹‹‹Y:gÎìiÓfM™/¬ç€&¬okÛ!HKLfrÙL/#Ñ}bZM›DÔØÔÔ,Ïîå'könݸ~ýv¶Ê^äj’¸\˜ÅÏ`¦¥¥$ÄÇÅÆÇ„‡‡†„Ï™ýé9IõžÍë6nÏÑÙF ÊÏÏá¥%ߨØèˆù ‚CBÌ Ö`ÓÖ×6´wî.fÄ&¥ SG0Øì™öæÎÂl]°ï 3KN^í¯«Þ»uóŽÂáÕÈŠ66¥ —Ïe±Ðhx€ÝR½go¥k=J'ÌËà°-59´Œ žÏÜ UÔ)Ö7·5Tðãc’’òM“Râ§XéÛ/†D£ÖSÔ|ðòIiõžM h hŠÎ\0 óKMNJHHŒM_Ý$Å}qmc›xKArTbbr2„Eb\d\”¯¥ñ‹˜ÝílCèðåÙ’Á‘˧¤{wç iD†ª~™ù‹r³38L<çHÌÝÑÞÞɤ^Òº»„+H2HH„`ˆ OŒ™dbljdè¹¼µ½ÓðSA©¢¤Y,=|ñ„¬aí8²§Œ ãgC;3RcçûØNœ·¬¾µ¥©^ÜÚX‘ ÓÅÆDDÇFF$F94f4·ª«U,ŠÔÅ" ÎßÍ"É3Ç»÷Ì ‰Q€Š¥½½­íó‘ªDD²®¦u­» Rbââñ‚Q$žDÇ&.˜`db6R‹¨»·C"–{¡»Œ¸¹ëÔÙ>¡~/¢ÓÇÇ®ªo¯_ÉÄbM¢ÂaŠ—0ÝÚÈÔl!ÓLQª©FØR ­©©ûÌEÙLb22¯x÷VèÐÃñÄ=üÕd<>ÀÜh¤E€ô©>:ÛšäFÁXa3775uœ<³Î¸éÓ\’ŠŠÓ‚ÃðÓV‘À!ü 6Îg¤ÑHÍ|¤®›´¿½¹:4€âøÉÔ&që‘îprÒ:•—™*Ÿ·F®ÄG{˜#ç#*aÌb1´†P¬6XeìÍÍí=«ÌûÑP­;&L¾â)7zL|$´¡J!ÒWž¾¹S5Å?âzq“>~¾¾>þSì”n#}E·R4AÝš”é^ž>~>^òß €±t¸KuZ.ín­Z4ßÇËËÛ/ÀßÏÇ××Ï×Û×ÏŠ wÉvâæÊ”@¸çïëç8üäo wõH¶;–†yƒ=`xäëPüà«s©Rœ32æyyÊap=ß—ìãëç©q©ÑmfNÇúyûûcY>¸åçgI¼‡tH:cý|}áèöð"[Úˆ¬áì ðE@L…Êùøyé|‰ˆ†S}±è_b€õ¢Ü‚ý–ø|Œ!aˆµGÔ)ß—èç@û ‘ f ¼Ð—äãç=ü)RR°ö ¼Ÿ¿íR šzMóóö ôö5¢“,¦øÃˆªhåàgøQÈ#<íiß‚í Fªüü»Ý‹¥¿û»)¨©P_"]¨ñ© wáö¾>.VFzªQT444)wžvð‚­ÕEñìÅùyCãr„·°3òæeåVV—§§-æï8Sn¢aS3ò×m]Âæggåæd­¬ÞÌMä/Ê\´Y\73Ü‹Ö×Tr¹ s²ù‹¶í+H`-Î寬¯bzÚŽS½ŽŒIv©YËköæ3ùy¹9¼•{V§'ç,â/Ú^[0u¢£å2ÖÉl©]ÅæåædgqoÛœ™±8;{m]E„ó8'¼™áÅÊ^U»9“™““•ÅË^··81}áB~Ñž*®í„‰öŽã® ácã2ówT³ø¹ÙÙ™Ë÷~ÂKÉ^œµpþ¥³&LØ .#C)\Á†š >TÊälßž—˜±8‡_²g]Œ«Àžè8VofLbd•îßšÇÊÆKy›jJ’óñ…Ûwdx·±Ú“ÍHç‘!Á:>kñ'; 9™Y™ü²†­œ8^^fve]é܉ã&Øõ€Nk*;oÍöåLFNVv6O°«¦0±0‹»dï–—Í»B{¢Ó8úYd¨àÆÌ\¾«’—ÌÍÉÌæóË÷­NKÎ]È[¸yÑ,'›‰EX°)ù 2´ŒÉZ¼q› …“•ÉçnßÀ‹ã-æg¬®ß7j²D.ø4žÂÊ*Ý\Ì`dggñ9y›ªò ó¸…»wgNœ0±¡ž„Þß“‘Q¸¥Œ“–‘•Éå•U¯c¥ä.ÌX´¹Ðv¹=ÁAÈÆ&d/Ú°C˜ÆË†¾S°«jQ'/“¿¦asü¤ 6vËåõ8†žÆË)Û î‘•“ÉÊÚP]’œž“Ëî®^bKÀÐÎÃŽ!WfÎÒÛ¥rÙ|NñÞìXîÂÌŒÒ}å!ÎlWØ“GŽ"C‹h~þö½ÅéŒì,é.Ú°976-3›+ؼ‰åm;Á® ã2Q5‚XÙ•5븩\° +kÝva\?‹›»aWþt˜2G'3ÒhãÉéüâÝ›rÀ„™™Ü’½©1¼¼ ÎŠê ±.ã±h;#Ȉh“”¹hÓÎü&DB;gÖ¼8F^;oÛîÜ Ûñvr–æd`©7ŸÏ_µw +53'#“Ë^¶­8!!;›Q¾§4ÄÕËvtµ–†ÊžÌŒÂª‹R¸9\{áÆõÜö¢ VáÎOR½mA6ÙÁÙy8(­bø 7Õ®b2ø $›_¶E˜ž“ÍÉݸsá '[¹lK h©ÀÌZ]»9+-#33;ƒW²­4-!3—Ã]¹gUØ$[›W‚¤o¤éÎ+Ú³'?™ÅeçïÜ”ÍÌÍb/Ú±“ç…y:›àíU?oSm“™‘‘ÉcdVî*Š‹ÏÌá0KjÖ„ºŒ·‘Wh¼ÒadLweee®Ú¿13…Ããr9Ü»V3âXÙ|Fæú™~ÇS¢‹“ÁadB“œËlݺ8…Ƀ¹{ñÖ-9qéYYlöŠª•¡“íí°¦Ž“ÆÐ£Cçeó3Vl(JOãeð¸ NéÖÂÄ$U2î¬Êr4É<Žäì¤O8„Fjúrrx¹%ÂôT.0f§ ·¬J‰ådeqùëÄQ~“ÝÜœ&ÚokÊ!d¦îÅÊåg rS’8@ÏàWnÉŽHçbÖ7.šéíåîæê`·[ÍAç²Pug/ÌÎàg%ŤczkÉÖå ±¹9lÎZÉæx?/_O·Iy`½‘”ƒÈRy\VRD"¨Ïã0ò6T²£X¹™™ìÜ5ùó||aìdW„Í8Nñ ²VsM†Àâ³âC¢X|¬wÕ¦E‘±™Yð÷òšM©S½}‚ü½Ü\pÊpvz™ªº§eòù™Éóæ'ã5iÐlCq\(¾ÈÍÙ*^æïí' €vPÿ|\+Ê«:)=‹ËIëÜéQ\,‹™·¾wÁ|v6´&gyݦ”i0F€~/ÐßË‹´·‰Ô~dFÐòLÏæq`v¿À+0%›g– ×.‰š“™ÉåB”ìZ9-@à/Pòõñtwµ¨³Ã~dI5š–BÙŒOÏp~^yÏXQƘ1—)ÿ;{æ̹0ô¨2 |=';ÙÙA;Sñš¾]4Ïes8Œp/—Yìl¼ðÎ.¨,ŠÂ‰ŽËÈùdmÚŒ€@@ȼÝ]ì&j÷¡ÑªN©™<ˆOVz¸—C@j.Ðs˜Ù«V&LOÏ–7éÂOV%̘6cZ ¿¿0€Íé>ÉÙÉÔƒ i¦~É™\žç†yŽwŽàË%óŠWñ¦y…ef xÊVþ†¢¨éÓgN›šÓýadæîf£Ô4 ꎱÜL“ÃMñ=:(=CÀÂæä¯.pLÃYƒÇæ,[Ÿ xÁTe¬¸à=ÝM‰xQß,0™ÇcsY s<­M¢3àŸ<èIW¤z»Ì—+ÃeñV®Ëš7sÖL¬¼ú0¬rPëD#êÑlv:B™3Ë}ÌpË™\>‹Éåd—gÍrš5Ðå²2Ê*ysgÎÓ§€ €EÐß‘Äv4’ l˜Èc§§18œôˆ©®VÃLi¹|o(ð(¯`Ï›T×163x¤q‹–¤N˜0“›™0ù«×0æÏY0göìYƒ• ˜`E”!/EÓÚ/–Åyr“ÍŸæek¬¦b± #ƒË`1Ó.åÎv=1˜/ßSÁ| æ†ÎŸ Uš1»ñtŸ!RäCR2´Ÿl°60CŽôµµ4Ö¤h{22Ù,&“Á[&Œö¶í †‘3be¯-O?/8dîìY³fϘâï4ÍžÖ„öÑëÉ`³Y Aš|&-ðµ1ÒTUT•™¬Ò™ÂbîtÇñã<’røBžfU–<_ngp–©AfõH…@ RÕMǹ…¦±ÀHÂ4¨d?ÖLGYIÙh:/“Ãb29ËóB'Og;••!g—QV–:wî¼ÙÀ*9ÍK{r¤)Òhj†f£ÆÙÏLd0A¿ô´´Ô4àÉŽ›=Ér¸žŽ–ª¢–Sb&Éd¥s–,Mš8~¼Ý¼Œ¬|9ÓUåÌÐа°àùsæÈ½aêê^¤>Ä \bn\2fÄ‚*§ RÍÀ~vJ˜‡…®¶Žšª¦²²Õ|n‹‘Î`.*ä»M°oÂÏÌçicU+x‘á‘¡ ‚çƒ̘h´‘T§0Ò©´ôt&ƒ™žœœŸjžž™äh¨¢¤­«©©¦¨Àäó òé9Eü0ï‰6Ç9Ffò䕮ώ‰Š  nؼ³x¨ìAäaQìÔ$A 11!%?mL:“ËŒ ˜h¦§©®¥3w-ðDêí$àÌugkg;Þ-!’£§½ãšüT˜G„,˜7wÞ¬9sÆSv#W_VjbRjJbrR"hËHgqYéQã 4Õ4u LŒGèjú3 +Ïä.æ…ûN´±ÆIXYM.+«l#..&,,"dÎÜy f˜ì†ùˆm"SlŸšœ’œ˜šÎžñóüm†«)«ë›ZZXŒ42¦­ëÏMgpiì…‹ÓfLrrvqqvðNȆl #ŸŒÒ2^BBLhTTðüyóBfìB“ £bÉIÉ `Ü4/#~žŸ½Å0-5-}ÓQ£¬,FŽ02Ö×Âa¥1Áº¹ìo×É®“'yÅò30k.Þª]²:791.Ü!xÁÜÐCw!7½PN:^ÖW`°1sýíÁ¶CôM­,G²°°27a¤k>ƒÅ<”ÎÊ(È‹ pŸìæîá:ÉerL&/£€§Áå,,_ÆLJŠ‹Œ{„M×®BVJÐR 6“‘ž<;ÀÞÜ@[]]ÛØj̸±cÇ[›Yޱ²676rIÈ`RµR˜yBæLo//7W{§0 ÀÕ@iVfyE&T=62"2<4bªF²5‹f¤ÆÇD…Ì òr´1lˆÖ=˱vÀyìh sKkKS£ÑsñC©ÉɼEœðŸ’—»»«ÍÄà .› ¾¡Áes—¯¦$&«ˆ ¢ü«§¶“—»‹ýxkSC=mí!ºÃÍÇM°wvvq?Öv”…åËf¦FV¾É\FjZj [;æÈ~þÞn6ãƒqhsóyê\˜«”²âc£ðÃGþŠ»‰¦ol(¦8ÜÐÈxäèq¶Î.NG {Û cÆŒ=nŒµ…Ñ·8Kª›’–µ˜9Ï×Û¦ü¾žã­góy2ù<56·¸R˜Œÿ¢"££ý”v#e뉶öN®®“&Ovqpt´w°··ok7Xž0q¼…}¶DZJ*7—èá…×ü|½Ý-L¦òùøí#àËaå®Y™œ”GÅ(î†ì¨ç>úå/O7‡"û1öZFM°g;#“ž’–™™4Ëk’ðóò ðs5ÒóÄß1IÚO {ÜzðŒÄ¸Ø˜¨ø)J{‘êP÷Y3¦x»»Ovrr€A‘ÀAI®¬Í˜1¾ pÝôt^6#ÄwÒ$7/oŸÀ ×C'ÆC*0´›*—™Y¶6«7EiRÕv›>mJ ¯—ÇdW×ÙØì€/Õv´s8D„ u8fD1®®nžžÀ40ÐÞTß:4›4‹á¡Êe³¯)a%$ÆÅD'ÎTßT5ÆûBGàçí1 ïØ+@õí&LœžÆ†Ô©œ–™›>×Ía’‡Ð]ÝËÇßwŒÑPã|è~à´Tá² ÚBÀÆÇ$,ЩFjT#ÏéSðR Ì\í`øI±?) WÙ$%•Åg†ú8;ww7woï±ÊC2²™*Àš\í@½W¬È‚›>¬©ê¸N›äççíæ2y²#˜R'Ž·Ÿ™ÊJ¦³³¹ñA0› ¡êîáîé7ÙLªæ’žÅfÊ5ä`~lv^ÙÊŒ¤¤„ä(Ó:¤ªfã7}¼Aþ$û‰0•§B«%³AÁ)éY9éÁžvN8_SO‰zJ Šá™|v:çpòyŠl¶ |9Ru´u=J3œ4mjŒ~=`HçCQÛ îÑ&¨GcñY‘~NŽÎE.š®Îc´•Uè3`PÏd1À9BžXO°f;!9Ö•Ö€´Õì¦íü½apèþm79˜ÉVPIIç³fM¶svž<ÉÅEà¨cçàh®¡¢¦ áœÊgsél“…§ Ê—°gh6¢IŠcüñ0ôœììà˜‰w”RÓØüô`_wWWGpN>;9«¨j¨(Œ˜õÝÀtX?‹[°ªˆ1B„ìÉÃ\‚¦å<]&Ž2áÂÆÏ1x¬¨'G9'<wpv0PRÕPSÒtHÍå±XB& ƃà} \WPR˜™è@##Es 33#==e"j¹ÆÀøÇKœåfç g”o?ÔÑyÂPeu M%¢šGzg°IÁS„<:$µ…K—-œ£ÓŒ„„%H…jâÌÌb-pw°›hó$3Gç±C”Õ5UñqŽS`€Ãa°``2˜vò8vVñªgRRPŸ8+%ÁßÖv"LáhŽNÖÚ*ê$"ÓÆÆädY0¬Üè0[ee.-IÔïC4ªù¤Ys'áUšƒ“£©ºª†R>Ò×òHÏ„©C :2ðø*%\ìó ª†M@€“†8;šj¨©‘ò•h4²Ô fLŽ|DÈåðsÇ÷#ªê_/[Ћ cU5z!RWš›ÃÁ„›Æsƒ¡&Ú“ héå !².ŽÃ”ÔÈ…HŸ0<€ùÊvl¹ ’ÁcDºª@T²¡›Ÿ+6F¨(Š>Í"4›úsp1¬”¹N†T@tÝ'ÉÃÚÑÉFO•´)*»¤å`›w‹HA•å7ÞbiQu]¼]íqÜ’Æé*#Áp 'øB¦€UJœî`9vŒ6èU,]Ü¡B w7”¼ QȦÓ|®X3!9*±yŒ·Q¦VcÌ5ˆ@OêêïŠã˜ääd¥V‚ È#‚Òñèk°Î,/nн¹éH3둤ƒHièd_˜·›:™ÒV %ʨ9|’ØAlåôù®£MÍ,--,M1µ¢ÆøÉ“œÀ8ú„•È@Å!&;¢YL6ÌwÇ›icë‘êxá2t´ƒ³«›½ê*d 1 ;¬—›:ÏÕ|„¹µ¥¹…•µ•©&^x§h›ÛMM+CúêNqÙ|6› ÕŠðc2Òb”…™¥µ…Ù(sU¼ð®¢­°i©ØFfÂä”ÅIC™š››YXš ,HVÖ&Š·‘¾‚ux&̵Ó# ÆUEHÁÔ€*+Ô)@Dh„åòסO_00Qo„®® ŠæDüR1ý4ðU€v1RÃ/ ÙD>‚¾4&„úàÍ•áCðkÂÊ–ØD@d®†³¥ŸÀ¶ #Šr;ŽÄvT4ÓÇo3ÓHÇå¶@ªf:€%ª›ªåc¨!½ ¿ÑK8:¨1ÙÈX, ZÕX}5Kµ€±¶)¶Qg8 c‡ÒʱÆÅ«™haƪÕ¡²jF*åØˆ$€*‚[PŒôqã‘õ5ÁÒ4ã¡ø•m nR´I©W(¤.Û_טBé¤Ãƒ^¨z*p“ª§ lUL°Br 2p%j%ÉÒÅ&$èA(QxxÐÂHu˜@• ±ºZ† X%3VÅï³ë«AUõÔqU5åœ#:AMÎZ›ˆYk ¾’DfD‘׳VŸ!¨êÑ0ë¡t\ÙQº€¥Rážîõ)CTáeˆö9c+%¹R„CP}M2x¼¢2æLPÓ€@!jŒÑÃrÉpj+¿] `² ¥@îOôryóÄ·S†»è‰:c‡`±ýIU|„2];2ÕÜœZŽýßPQ•Ÿ­¬ŽjV:ƒnJÊ„PÁÁOÔ7$ãö  `€¾AQ‚œH5ÒÀ¯Ö^WÅ×ItìM#°%ˆ>+ËN`L’þüF<‰~®¨*•ÊOuÆÕÑV,ÇqÑk¦,Ý~‰ü€2y„÷aÕéò”å/Ï“äÄpUA•\†‰qÄaZ²¡¤(+ƒ¢ü$g ^%O"p®¢€¥ãã£áH¡P»Á-”•HůÞÍ'7ɉ»0kúr|¿~OÜ j'Ъ¨ Òâ @$Àe:±‘ÉJÀyÙ«Wû ø2™Þ†/«*eØWeÐ;Е”@2"Ô`H`¸BUTQ¦â£„j°Y #ª‚в©ÈXÉ}r§ªEŠD Y®¨¬¤ˆO ‚l|ð>Ìi/Ìit …®¬Pš¼bBf¸h©‰J$°Í{@z%ðo°Â°™"a-ÐK1`hp_T!?pØ4 ‚"e7>7|ʇ‰ÊÄ]¸ù¥à£ò‰F$*ª ±”IeØ ñáÝD"®„×—@Ýl!D¨ƒçD€„Z0­ K]ðè’@+ü¯Ûp'h¬H\1xp•€+ …!q-¾T‰Ou™T*´3>‹a2µA20pÁª¬yEK¡ì‚± ]N&?IìˆÏl€?×Àµõ`ÚnD¡Q1A„9IG¹°u ?}7vêZ„MᘠLÅà ÄŠAFTÚ>ïké@¨€ å*Ð÷Á?©4b=v*`I¢UCÐ)µrw‚ D…ÌZŒVJ&CAN܇^)ƒÏW&ÕÉ¡øp|U~8¹­P¨„®A2E¡Z‹NÂ~·~Ëä ‹Y6‚7Ó)`MHÍ7Š4…ð î(ˆ B! hð(%:EAI‘ ªÒ‰ë¡B0‚ ¯ÆÆ¥ª4af$lCHd¸_Žq3©`5Háø| Uj¯<úË›ˆ‚Ï¡ Ñähª}¸•±ò¡¼7X#OE½r3C»QϦƒST‰½ØttÀD|Ò…"Æ)Pû±eHòŒQˆÁÀ|êNä•pŠÃš,Šø*‘Fw¢ÀÔ€4Š ç(*…PŒOö ÀÿIšTÐŽ@S–g/ŠI~I™†oPñ+Ø“!@Q>¼òùmìD|~¾:¦Fr€D‡q88>T !?¹_÷±$Ð… ãpªôÞ’üòb0/é."ÓÕ©òcCZw c߃ŽL0ÕßxCx(¾À©JˆŠ0?pê/ÁûÔi˜¸ñHPU .…ià–•a ó˜€Fý‰Àø)"ÒI…pClþ˜=™ö5îXHXsñ¢Ò±¢d* ±IJ4ˆ‡ØŠTÒ÷øö_Ö%ˆ'?»Äý=Ÿ]ò±ÈœH$ü_ 'Ó•Õ44ÔU”•”h2‰H"‘ɤÿ‰JDªšîˆQãÆŽ¶2755ij<\oˆ¶¦–Î!ÚÊÔ®ªaêÏ+.Ég†Ì‰Š‰š7Õg’½í„‰NNvcFè(’>°|²Úˆà®'ß~ûüvoËéëŸ^9ÚY»¹€³°rÛöí+ãýÆë)?¬õ•†{Vÿ×¹?<ºõðûüéÅÁ¼™†Ò>d hC'?~ÝÿéàOµRû-@Ö°L¸òú;¾Ü’ä6\áÀ¨lìWÿãß|ÙÄÁÂùc5ÉÎúºŽeOþîÈ’Çû˜>&JÊÉšVŒÏþþŒ•kåöC©¦HÊÆSÚÞpˆÌ9Ó,?Œ ‚õ*^¼éÔ›û['Ð Ä÷­’ß|˜ð¹c4ÈÄ÷ê~|ó9Á_ì`x¿ÿ,H ë:­zòÎ)þé슰‰:Ô÷ïûÖ)×ÿÑAÉßµeN±P%½oë›Lýøäÿüù¦„ÉÈïÙ÷Ö<ÿ‡'Eÿtzé‚ Úï3 À÷ã/ÿ㣪¿•òFªÿ÷¾ÿK¹]ë¤÷þ:bð}çõÏÞâ¬îºòf¾ÇŽgž·;–üÞæ¤IúïËD%C¿·±¾¼#Ì´T}?@ ±]ú¶_)s·2ÆNûýda²ºyÔ…·=­ýÖæTW]Êû±¾‘oÍÞRüw‡*R]†RÞï;¬|ò¶Õ¿S_i£õ>€¢9ŠñéÛŠÿþÈ–œ©fÊïÁÿˆ*#ft¾õYý_ˆKㇾ‡>  ï²þåÛŠÿWßü=$`MgLÊ[[ÿÇkµ%±ï¡úІå|éÛúþÏZ׿Ÿþ‡¤:b–ôÛ·¶þÑÁÐÿ¾»ï)sßñý[;ßúUÉïcüsM›¢Ço-þyϦ¬©ïaüE jYÇûX¯8Ânõ=øžùLÙo-ÿYû:ö{˜(ê#gÕ½|ûê_ÚS<î§À ÞtjÍwoÿ-%Z*˜ž†ïºâGîûæíÅÿçLUÁü1¤wï»åÅÛ‹ÿù¾dMªÛðwœ~‚ë™NÙõô_ˆÿúÀÖ…³¬ßqà âGN­~ù/ÄÿxiÉ;¼‰4M³©ÿ¦íþùqÛzž¿é;uû’‚ŽåŒ'þ?çv…LÐz—Q¬¬?>ZôoŒÿóÏ_Jצ¿[ì¨jFÎ Ïüø¯ÄÿçäNáÜÑê¤w¨¼¢Ž™gɽùI$«S&¿ÃÒ‘¦>Ü&lǃ)þûãÛÍú÷“>Yiˆ¹ïòsßÿKñ?ÝlX•àòoc@¤ªÚ%5>ùùß–}›s¦ýË1'DSÕµô*¾öÓ¿ÿz¬ÏjKbþU·O ÑÕôÌãªü{é?{psfàÈ·O=UIs˜å¤øm—|ñ?ßmXc?„ò¶Â)Šz¦ã½Rv\ýÏ»HÿùåÁ-ÙSÞfÂE ’(te ]“1îÑÅ 7ßM:žo®„åÕ™L¡ÒTÔµu GŽu™“_sù›Ÿßµüp|[îTóP}è^Ôtô †›˜µŸä»dÇÁ'?¿‡ò¤¥<ÉY—úºv}+çÉnÞ x‚-{ÅW_üôó{)7öÌõæåYÍØCX¿­bÏñGOþóó{+?ÝÈõ6|ó>;IÙÈ·êéÏ?¼|²åƒ^Iiì?Xm‚ɼóºo~~ÿåê.Á, •7f~ŠÖ˜Œ;@üŽ~ÂñN{£õUFÌìýߌø¢cÕ?0?QÁÀ¹âŇ¿®hžµ*áK)ãøŸ}o†¼²#'ÐDáM¡§n{úÃ|3åÙOXnÔ7­àÈ>ŒøŸN¬MrÔyø‹:Ä~õ×Fþ¯Š±ÑüûäGP2 ¿ò¾ô»îácÕÿÞýˆêÖ™?üoÛ—…Œ~ƒû5Æ&ùñÉo[2ßú Ù¨f5{ù‰>ˆü—­…s,•ß~ŠÃÝV_ú@ò f[(¿qÃÂ?móÍÿ3ùš–u sËõŸ>DûÎ}“ý±Ú£¦°6_yÿNø}ïÒ7úß £§²6œýî½ç¿£%¡cÔÿ`~«3zJzy×—ï[S«¢Þ”ÿ k[û%V_Ïmp¹2ÉqÈ?Yñ$Ò´ÌÜÂs¶œyù^徃åaðfžx}Å~6«¼óþû4Á qN©â?]eÐX¸çÂ÷ïOþ‡–.£öç~Dº–¹[XÖú#ï±7þt}¢ó?Þì„60œ8#}…ìÎïfßýưü›Ìõµ83ÐT韮¼ÈŠCGùÆ ¶ºóäéÓ§O?¼{åH÷Á¯Áw·î¿^ƒK¥á¶o±ÛM¤i˜ºÌç,ÛZÛ(‹êöíܼá“ÝþM¸ÚÑÿú=ø¯ë¸~#ÞbÏæ¡ÃÆûE0s…Pò¹,ÎÂU³óE{]Íñ×÷ßWE¾ÕžÌõGØxÍœ eÖô/7ω…½?¼~qoïÆ5;n¼¾uÚ²‚ÌÞjñ‹@QÒ6ÂÌŠùHãáúÃ,Ý£JN¿.-Ün¬XÄÎÝÿúÅ‚[±Žºo·úE Ó””¡()Òišªñ䘲S¾;¼uQøÔ༃¯õošs¦[¾Ó¦L=JüeZxд*Ám¬sXÅÝ×`SâäáïòØ¢næ_,û‹îñ‡“ÛΰÒ5ñL{ýÊüO§–†Øé)¼›#=¢Õ·ÿìüMåI.zŠÖ3Ç^Û/ÛófÛè)ÞE5—œ]Ÿý—ŒÏî̲R%Ñt"Ö¾~ û¼cál[=ÅwR@e¸ÝœŒ-'žýãŠ47¨dâ•ZõúíoûϨÿN õÆOg”6ÿa™ä³ýE Æà} ²†ÕTÞ¾Ï_Ÿúó&ê¿ÓÎ;QaÈ(¿8ÁžÏ~|y>Fx[‡@Ó?;»öõ¹ïçÚ ¥¿“4Í‘®Á™Û/~ûÛÒrIÔÄÁÞ…¨ 7qþÂŽoÿÆy3Æh½Ó£‡Šê0ÛÌ5í7ÅüçÄ–œ)¿¬¬ B—z}Wù|?3ÀRƒòN †Ž H,ØÒ~ '£ûM¥q¿=ËCRî½òèëGO7·¦øŒT§¼ã(Œ‘‚ÙK66Ÿ½u¹uCæ”ßí«TL<V}½îlIðñŽ_Àiøx裂|ó¦òœ¶¿ëZ d53ïÄÒ¯_I»¾:Úå]?!´ŒÇỷc°’f;ÿýÐÒ¤¹wÂò®×> ûÓÙâùãµÞõÙ7¥i·¶›ìî4Ê@™Lø¯<í»´ýµ„~Û€x÷§ŸÈtUm}ý¡ dŸOp‹*z­?õ/ža®üþ$É …Dø‹5™ôz^´εRù ¯ÁUŒAÖ¿üÒá/ïZ8ÍL郾%W "¿îê_$‚Ï¥kÓ݆}à·þ°.¡9›/üi<ðÝ‘Âyä „ÿV`¸ýîæ?=ø°¹ž§áÖFÿß¾™ ™ÈÈ9$oßÕ¯>ëܼpö(õÿmõåm w˜Ç¯Ø»«Rá¨Oÿß¿˜LRÒ·™–‘Í v5V!¡ÿ}!) ±tö ðo¨Jù¿z/ûcùX>–åï‹QÉ«‘9éáéI$]êÍ™ _S¿é­3ôXéæã=~y%ƒ·²¼Á@Ð ½ÐŽùB§ÿНz»`]C†×–åcùX>–åcùX>–åcùX>–ÿׂgFÜ„ÔáO¼€?ÑÒ¿&¥¿úýS!þî“ ç‘†¢Ñt4-@cÿ¡«Šôïñш…X,^Ì” .#—0î´Ó^Ñþ ÕǦÿX>–åcùXþÿ>xÕ¿+}4ÅÇò±|,‘Œ_}º¿ú ~^Ý'¾ú$ÿ£þêÓøÕ§û«OÁà'áñÕ'ùÕ'ýÕ§ú«OãWŸî¯>ƒŸ¯’áÕäƒðJ2áÕ … þêÓøÕ§ûÇvüX>–¿*¯’RÇý¿ÏëçÿËÇò±ü¹Ÿ'{ÏööD¯¨…øj õÇÁÁ_ˆƒ‹…º¿£û8øX>–åcùX>–åcùX>–ÿÃ’Ëà"T47™gkS<÷—]çJ$¼¹äFþ§èºàšÂÕ+W._¾téâ… ‚ó:çΞ=súô©Ç:ÐÓÕÙ"ijél[Ô7?+ºI¾q~ò?¥^¿~íÀ—‡aØùóçä°S'O9x ·«£¥YT_ÓÜÝ‹Š?#Þüì3ÁMÁ ô©à:ñÚÕ«Â+Ã…aÐ :vh ¯«½E"ªÛWÝ¿¾nÝ*ú ݾv°·«]ÖÜP³goçên$¼Eøì–à3! 7ÿyòä‘C½mRQÝþª}]©]¨Ÿåâ„7Ÿ’píW(¿E ×îäñ£‡z:Zšê÷ïÙ!îJíD+Þˆ8r°¿»MÚX³{ÇŽŽîÔ´èfþÿÅZDµ»wl®9ÔÒŽJo o¡Ï„7Ñ/á,ã"¶ùÙ³§O?<ÐÓ&©ß·}Ó†¾#]ÉmhÕ#Pýß gNŸ8z°¿KÖ°çÆŠýgÒŠÊäÁMúŸ~zý¯0Çènïß¹iíšëÓ‚Ê_a„7T嘫Wó!MŒ8Ü×Þ\³sãÚ•Ñ™$C«Eà†1þB.ãäÑ.iÝ®kKß•#¤hÍám-J¾y4lLÁýWŠ;{êøÁž–†Ý›×¬è|4ˆ‘ µƒö?}ôíݲv¹øëALb3ªx…4šñ kËU;îÌÉc]’ýÛ*–ïýþDª|-âܬ•´n{eÉ'?ÿŠ£uw…wÐmÜ¿k½Ë—A-Ъ·µ¾j]IåÏ¿aDhý_cT._ºpþìÉ#}m»7¬\)ø™þ+¦QŽ!Üþ3HùÒ¥ gOékïÙXZ*ü¦mø #„¸ÑlOðÌs§ŽhoÚ»¹lIþo€¤zD¸w¯è.º·ê8 9Ìpþ̱ƒÍû·”üV‡ŸÞCŸ—ÝÞ%ܹ#NãÀ|P§C=’ê­k–þV‹ >ÜËÿ¼ô¿ajiΞ8Ü-«Ù¶vYÑïP5¨èst¯èsâ½{Ÿ/û=RpS üä]:êhŸ¬n{Ų%¿á’«QÅçKþHor º|áô‘¾–ºëJ|#_ .ßQßuú¶<ö£Õ÷‰Ÿ~éçÂ{„»wòVù¸ ®Ù…ÓÇúÛ«6”ærÓ’âââ“ÓY¼Õ5‡ºUþú]½tæÄ4Ö¦ÕÅ‹³¸Œ´””Ô4›ËÏY\°µ³3u/B_|r¿à÷@íÏÀã¯_»|þäánIÍöu¥Kçdò\eŸ·HX¸leU[êT@˜TÔ½}ûÖ-~zíÊE¨`kÞMkW.-.Ê,T^¼X_¸tÙŠ²òÍ-1»QÑè¾ð‹µÞC¿a?½~õâÙã:›««6U”¯\¾lYqþ2…å+JËÊ×®[·£k7ZþeÅ„û÷…Ð"» «¨k—ίíßµuã:a… RP¡P¹~ݺ7o®•ìB«¾\A‚ÏÁÙwµî€°Ïn\¿rþôñ®qí>H©Âí‚ÊÛ·oÛ†ÿÛ¾cg·*˜àþèÏ?¿wïîÝ;wnÝý.Ÿ?ul §]&nl¨­«­«¯«¯¯©©Þ¿wßž={wïn©ªB‚å_–Žð9F€·w4< ¼£­5¿E­µµE&i‹êë\×^… ¾$\ñ`Õ—‚/†Ü¿u½¡.]8wöäñcGU=räðÁþžîζVi“XZ…J–<(ýRø…Îý{XÿÆ p” ƒïé‚SJ'Ž9Ôßp«DR…V‚Œ ƒôù­«gç ç. ®Ò¯\Á‰Jž©•ÏA¾:iOg«¬ =*!%_ª}qÿöÅ®ææ–Ö–¶Î§®®£k‚«z|Uy…óŒz» >ÂÇ¥J.{`õå½Ë½û¥µÕ½U[›š;N]“'áO¯½Êõ;{æÄ±Ã½ÝU¨ð1éѣǗ?Zþpé«/nªÙw°£àhCïµ²5nÞú »å«”rYžYqg×W…–?.y´ìaáë/n=ÞÚÙuTÚ~¼-aÁþƒWoÉa7^õHWp¦”wÃUh…%|0êËÏ/wnë=ÖÒs Güò摚ÝÇÛ;ºŽ5tÚ?Kß¥ÛØW~…¾Bž:FàòÇÅF?¼w¶ec_SkÇ‘6É‘Œˆ˜èèññOïü ÄéÁ«ž¾"ÔÜÙv¼©õdSDD´ Š^wþ–à®Æ/ȯ¬{ñ<ø ‹ ©=¼wNºþp—¤­O"êÈ DDE‡óº.ݑԡW.‚Ï<{¶òi1À}qµ{[뀸­ý@uDZM!QÑ nìŒ}GnÜ»ãQpGª¼}ºµ¢¾cöVÉ¡m’–³ûx{úÕ×7®kèX_(kî¯ÞÒ!;YžÅc%ÆL¯?}Oø½b@ ÷(ƒU¨BË^,ûºð¹Ù3®»j½´u]ÚþÖÖþb‘¬ëÐ’Åy™\FÄâþ›Ÿ|õÕã_tPú­·où€ƒùóç`½/n]<(©ÜÙÖZTØÞ|¬bE‡xàÀ’‚Å90R€š=z$g$ø‚2È<úåÊo¬^|ýèÓÃMÍUÛ«ö64ÉÄEú¹ ½Û‚3!“t”¯^V´(·çÆWÏžå?>¡ÿŽYμû%é›o^¾\úÅ‹§·nÛ½¯º®N,mZ;×r¬Ét‰¸E’²  CÚÜs¸bmÙòÜÍGî=>òzü /æ)áeÑ7æÏÞP»¿¦±¹zù̱ãíœ6·ˆ:‹"#‹;$’–“;×®-ËÚwú‹9ô•à1ù"0ë|³âeþ7æO?íX×TW»³$Ás¢«·¿‡Í–úΩ)ñ…mRIÓ)ÉÆ5•üÚóŠž ~áòh á>0YõRðÅWWò™üø9.î3æÏžæ?9¤¡A$Ëe°by-ÍRñÁÃU•Š.=†È <ý/&è~"¾üöÛU/ žÞ쎜—±`þì)3¶6×µ–&³¸ÑáÒ&„v¦yó'MW žýÍCÌצà[âË—ß¿4ÿúÁÅî\n.+9.&,8xz¡¬¶eoj ##Ì­¶¹IÚÔs|Ïæ%ÍWç#$w`„À‰à;˜Qñ·K^šóüÁÕžå©Yìäø˜ˆ9IuÒ¼˜”TnÉ'-¢&©øPßîeMÊÓ§Ožü„ðàKàñ¢äÛ¢—f_?ºq¸6‹ŸÁHŽ‹Ú)­•UÆ%$&$9èp»DâfIóÑîU{Î|ñ¬èyÁY X‹Òo ^Ž|ñäîÙ®üÔ´øÐ¨BQkuzl<ô4c‡Ùí—‰DÀáPËšþ[O–BÆ@Öûå—}›ÿÒì›ç_^?ÖÒÔ$/™¿¡0,:2*&ÔÜT{¾ †<Í’¦ƒ;šÎ~ñìë%>•[æô×ÂïV}+¼øêþ-HÍöD'„GEFÅÍ3ÓÉʶ‹0^*Íï¸üàÙ×_ 2x äø‚ïHß~ûÝw%À„øÍ‹ç‚gÃß9)JŽŽˆŠ®çÝX¿°ªU <ÚöÎLì¹öð¹xå<žà*‹çË]øÒð›g÷϶°££Ã¢|†Õ?ݹ´N"‹ey~®K|úè¹€’ÁzîÙŠï–ƒá ¿yþÅ¥îâˆð¸ ™‡o߿Զj²­3=ý\JÞxô<pÐÇ Ÿ’0pOKAžp_?üôð~î,—öëŸ}y^º\"sÜý}ý]V¾õÕóÀ!€ùúé÷e NøÒàÅ“{‰¥—¿üú›ç÷ψx’ ^~¾¾~“?9ûåH©h°rxè!ü~ˆÒyùò›çî~vçáóo¾yñìóÓ 9©~~_ŠŸGï½ç/Šä‚OÆ|Uð=é»ï¾ÿ¾€4~ýüù‹o/i/žÞ?Óëî'ô%{Fûü¹`…ÏIÏž=}ŠQË䀥/© ÓùöxO`îïZwþÁ×ù@Wðœt@ö¸äû•ß-—Ww¹Ô™êæçë‘:pçiåc#ašÒïWMÑK%°Ï•ÞœÉþ“k/>*~QHNP²–Cƒ)¼xt­_èÂ9r÷¹ðÌBø@X-¿_ð’þâñã[>}ü¢à›%/ ¾þØ;¸¦®|Ÿ›EˆJED­Ë³VÜÄX\ZTFìÐvlU,©šKU–,¬z³B°T}¶:Ÿi«ÓYž¦VQÐú*öµé´ÓvZì«Óš€Õ*.„MTÈMî;÷&BØ’Bé¼Þ ÜsÎïüþçÜî÷ó¿ƒÍð·‘eo»ŽÚò»~§E[ÕwÕª²0ÚÛ-%pÙãÞÝf8ýûZJO¶ë`[!] /­šV%UWd)†u:8{²£êJuö~ö±_µèḰŸþÎT¿}°_5žöž’êǨÇq²Vçè©p¨•8fx)ƒl!û3Z[Éõ¨/€µÅíù”›öž} aÒn)‚ƒÀµÔÜÔúëñ2˪.^©n.…]‹ œTá¨Óà +nÅp|'¿3›««›0 ·à‹ºÝ¿H¤ooÿZ$ú kíÊ6ÅÐF^ÀUgÜ»Oä eV¤¥X"ª:®¶øëEz‹¥Z$ú:ZiÉ˧£×ðb=\q@\ãŽÕâÊξÕ:ª/u’6”Z™&=†Y9x3ŽëQ½n±ttµXÈÎjª3£Áf+¶2/ÂUVö11*ÖÅpöŠ0bø'ÑßdˆDE_«Ûµp€¼ 4(m{¬ì1ôjQXœÂ=ŽEQ§Žr~(Ö‹Tz(¿®†Îp ÈKiCMk0_PX'£ÅV+^¢x3Š¥Ô¸C]Ýd±4mÒ@5fW7­È§b å¼ÖbµB5fy E)[•]“jµ…¡·Q3< ”z› .øa e¿æ2àÂbúP8‘‡B…¶M§U ã´ÅBªí®%P .b(ë¦]É‚Êâb…~”³°I%½yz»è´Â¢m×´òWOã^fõƒ½/Ú…ÌÃ(z³*ðÐ~U‘KuZ uj‡®Ô†Üº…Ùü[r¡js1ûîRZ=ñ ýÔbQ‰N«¡V鈶ÔõMŠº²2/=fµV¢èkð4†U‡s­ÖNõ§(š[‘+©ªI¹¢Cθ{X‚¥p$•6›µ¥C1+R)V A¹äÂ=ãoÁõ¨¨‰NkàJ1ÚÚnÛç˨ù¦FmcܼxSiÅ.‚µUƒûÕUÃCÒX}#ú öžoØJ­{ðXa·} nâ:xòÛH#qÄV+ ,*Gq˜ªÉ·(Û©±QM 6â x$“• XI€®/Ì╵š~¡xU­ÅákIÏ2^†74Øwþ—þõ¯o)˜Š]I±xûýùûg+Ê,©¥H]¿P¼ú |SºFê=aóey¯(ËŠ±Â#y]ý˜{Û]¹;Ȳßz©Ðc0_‘º7?;ûU•¬¤ˆ7ïϘ¯u æ'`^»ó`vV&Ùuè騨­]Á›½}ŸL–õªDªUÇÀeò~l'Iãow£ñÔ5ÖAãuÍ£š(Ÿ#Þ)•It;Ä9G6Æ.äa|Öü'{ÂøkÝ`üH ÆË3r6gdælËÊ/[±r)Æ÷‹þß»„ñÌÖÖ»­EN8>{[Nò¦lYáËÙ!é“ñ+Ÿàóg¯¯êÇÿ`ÇñØ]ЪëDòïHR³“³¤ÊÌ9Y{×.[È‹z§$ÿC$P$‘ cÓ²sT¿•Ê·kVÆÇ/›-wä¯tGò§·o’gmxì™Yþ†5¹ÒÝ»ÉQ–ÇV¸BòW»#ù*ô›¶H3ž›Ä—‹ó²¢Sr¤Š¼çžûM|üâýAògç¡)bÙÖ%aaÛäE‰—‘&ÎNx꩘r™\Š)D“ãÉû5ÕV%ÌZƒ-ˆàÍ‹šµ¿ë—,_)É”gî‘nÞ¸Ö$p÷ö¥ ¢e qOD+øc¢ž•nËL[¼xYü‚GÓ¥R¹ìuÊæ$ψüîÅ+—ÇÆðøó¥¦¥g­Š^¼$nfð&¹X*—*_A7”w#òlûN"Çè òÿµ&.~™€7•lËÆ,,\É^ž+–Èä2õöµG\ù’ÈŸO_¶|ñ‚e‰™iK¢ðùÑaÃ"Ò2Åb,“­”aýШmQ=Dê=|eùÉòr,:9q.Jç‡sfJ%bY¦lwFy@k+}€Ýçvù?,Ž™ñG/˜=‚½]ùL–˜ÔËe[úòÊ6ìÒÈ¿»zÇ_0‹{â¸x³\"gfo›±Þ ŸÄçób¦†@>5U&–Hä Ó"}ù=pêv ÿ o® LNù÷ÒÄ2q¦hÖäi‘®€üh ÈÿqìÇì@¾B(É”ÆM¦±Çéÿ~Õ ·ÂäO$J…Ó§L6mê„ý=€<5½ùµ±“§N…FS¦|à!çP@~õxÅ4öô‰ÏºòÏLTLcM4ôÂã‹(ølçñI¦M›˜ÜÇÛa¸ö!y|zÄÔIG¿­o¥˜y¯D>;BÔ‘×ÁvŠÈ¿þ1Eä5PÿÈÛÛ•D^Kµ”È?¬ë$òºJÿÈÛ9{A"¯£êÜù}}Ðx=5BWoïéÅÛë¢x†·*pŽ·Zqò'¿I[,8nÁ€c$éW´è€òíðx!jÅuÞsÅä«}Àä[ú`òÚ6—L^~¹L¾Ô¦tËäñ_$“?=&_F!wg&O2z;“g4„ÒûÊ÷7?^[˼RC’n…)ðòeêÆ‘$òØÿ2¾ùæ"V ETvüݳãkû™~ÐD¾¿ÙñØ*šÆÓ4ž¦ñƒNãÕ?·þâxäÆ×ÊÄø¢Ÿ )Þk¯õ†¾3nÖÝ|½Né-'û‘qíšCç9{ß[ǼoÉû ß oíë7|×ßBnvåïלø»‹¬xp»ÔK_z«¬ ¿2è^»¸·¼ø¯ÝøyñßV^üÇ'ÊOõ¿oa͘³6qav~7ö†ßUf¬q΋?ư@CÙ¿_꿟 1€Á€;þÑüNåÅ A8á#ZþÖ}^|A=v‡{«öÓƒÈØ€„ûQÁ‹ìýðÒÕk]ðû÷=ð{ÐëÕ•‘# 8c8á!}"éûf0¬0 óS1]Ð{MWô^ØP`VÕso_ùìéÀÈ@03íÈAhÀXù‡T"|]ÝMǤóÀ°£÷Âf6EÞ㔀Ía$’x²ûx6ÉÜÏ-…* `ò¶³IØ~ö)`“Ÿç̉sCÙɤw?;aÿËl@€CeÜ£u?;Zש`(@ànEÝõÀ¢~r…ªt€TáAZûðN†~2}ø^ÀLó˜ÚùÿTî]á§$'¨,öI·„<€$äËß‘°€{°—x–ÎjmºúÉ-œÓ«€Yày3[ê¾|-`H)`q—lÎl2U¨ JpÔ%Äf4|·FTH `ùŸpǪ™MµçùZ*æO˜4ëîíKUKµäbjÈ7-`ŸràÙƒ—Àµ‡4üOô^ô@}ŸMòæ#Sþpà5ãPßdYûRd9‘Á@Ãáa!t‘Ø=ŒâȧŽ?QžÇÉH ?ŒfØ»N츱K2wñÔt°ã7µ€±}7œgÉyO1Ë|íKÃDxN-8q|°V»ÄÄlWòà „Ä‹  ÏfSxøeàPtø_ÈàU¸BÃ!~cõ>…†OUÀÝ/³Z`8˜ÆS0ünF^ø¯Äc0<‘ú_°6à\èO¦ö™ypB ,v†ÏÅPƒ#Ç(2¬†ý:É0ÙÍA†ß_N†ý´k2œó/.Ép Xã’ —}d2·*)}'.ü‰rµ ¨:u+r· ¶å÷Іó;’µá™‚ï0&G͇zu.!‘nO:\å]µU8°ª©/§m;V´³XÚ‹DEv(¬jc··µ=hkS>ðƒßï?€W&…;2<˜ÙÚÞ“áek«à²þ'Ãÿ®ÙÚÛ‡Œ ÷ÌÖî$þÊÖ–/HO`IOHA,NÀ0nPppˆç%888ˆ;<ПÃb"ûˆQ„Áö熆…GDŽŸàq?>2r\ĘÑ#¸~,Æ@@–Ðh›b¹s*.|$7€Ã@“Ã=‘ð²Øþ3&dØ@@X¡‘3 ¯K{FDè@@ØÃ¦ð½÷',¯DŽ@‡>#vþDÛº€08A³âˆ°>Òë]ýƒ#çÄÈŸÀ“ÆyÂð ?oÕÀü ëzo€þ!æ% "4Л|äïuvÿÕÄÀHò*Ÿù{€ïü½ À‡þ„uCÿð¥¿7øÔß‹|ëßÿ|ìßï|íßß|îßÏ|ïß¿ëÀ ø÷+€ÁðïOƒâßÇŸúuìÑ$ƒäïqƒåïéŸdƒæOX< `ðüá}€››ÓAô'ÚVDŒ`»`0ý‰¦iáÁþ¬¡ó'>~4l¸ë=0¸þmO ` ?ñæ´G\/À û_žâÏ:ÿ¶èÉ£YCço‹þÈ0öÐùOÎËå ¡ÿЍqAÆÐùÇω vu ¶ÿ¯ç­ÿªyã‡Ô?aèýCü†ÔÂ/Ú5íOûÓþ´?íOûÓþ´?íOûÓþ´?íOûÓþ´?íOûÓþ´?íOûÓþ´?íOûÓþ´?íOûÓþ´ÿOâŸ0hþ ?<Õw!ó\ûûàù3Å}þ×ÀŸ¿sUâfE¹NÀðó‡.KìŒp—ùŽç/ã“¶ÊóvíÆ|WvïÊ“oMŠçO s™ÿèxþT¿æÅMhŠ/ ºéÅ5ñ‚™‘îp©çogòcãâW%$¬öUIHXËŸ9q4×uºýùãÈ)3fÍ™çÛ2gÖŒ)‘£ƒüYâóç¯=yD;2"<,”ëÏf¸MÁ÷âùsOžPâ àxðt8‚0Yl‡ãçÛGd{ötº!ŒP×[ˆ:Ø Hyoúª#õ½Ž¾N ´«{^'—ÝÝÔK36 …)·ÉóÌœsæÌ™yfæ¹Ï<—w$¤§e/ao!zÇ®wõõ÷槤§çL†¼ºsýÃíWçf¦gGl!úüšÁÃÝ#ÍWª%ÉF›‰¾ÕÖ¡úæÑƳc½%ââ€ÍÄ ¼i¨pëðà¶î ­ªÕʽ ĈëU=zfIjÏhýÎ ë«+£Ö3ãs²†«ý\O7¥Ÿì;ß¼¥®Úf™ »SÝ7ÚµaáŒiUƒ}òŒ¶ÞÑþ;œZ2-ë>¹K¼À?È;½kpOVQk_ß•CûŠ ?©xżyK–ÅÌ;ÖÓ,eï뺢>XjøñeÅÙÉ«mîé©Ê“/ÜÞßÕåLq1åD•ŠóSËÔÝû³ò³ÄÃꮑ‹k7ç´¤Qw›03+ÍÞ»½»³ë|—ùFbÄ$$b]JZFâ?ÒÑÙu¥h+Ñ÷ÈËÈXn@ø»‡;:‡vèÀûÔ¼!ög:;²}x[ Óx®s%áy¶®õã6žÛ‘ÄШ8/VáNŒˆŒñeí!l㹱ѦûK'Ì—ñaèè%NÓ]-§é@˜ÕmTí(}ÉB€™»[V·zƒp¶„€ÏÎ2U}Y¯3 SU¥|“rÛ*7o?sFÆ6IÍÚʲÙÞÞ~3iøî,)«•n óðö˜!0¡vdl}¦›··¯ j\»h‹híZùºOooc¨qîªr‘¼Z¸IäãíçÌ€ç.SdHT"ù¶EQs¼}tàˆq¢riq…8¿¢":&jŽÄÀŒ"EȪҲU²ÕÂù±±!|ˆÎÔ%%ùn¾Òòe«”kŠ—,˜?*Gw¢Sp²B¶ÐÆ,O)ôÊ“¯­\¶ÐDSŸBI‰xÙÌ  Špo‘¬\™˜Æ`ÅŠsÃ]'ÛMö)Ò‚r¹*35 òpüæÎvž>{–ËŒ± :Â?W.­g…‚Žï¼`o¯Y+EÒEÁÑ3dR¥ª b€5#.Üß;F Î𠱌(IÊW/†°šãç)„úøxÙˆ$bÉj™ÑbÌ€ ˜±ÄÃÛÇÃø+…b©*ª|J ïlá¦Â‘’$¨r} ß é–E2‘8À–A ãh A`'*Y6Íy*‚À&ÇÓÎÑņ A`âèäèlË„ еwvÖƒ à;ØÒ àñ5AÀÑfpØLËX—aÌ2æÓ Ð1!zZZ„ AÀ5asŒ& ¤AÀÒÕ",=>]‡ßFxL-}Â×féUŸŒ-„Ïàè±:DŸUIk+á±µxD›¥¥õßól°¹LS=³Øô–ÑÕÑ$ØL,ŽŠ°YL¢ÃPƒ GØl8B÷!gBc#a29ß¿ŽÔÃ9›ÍØòÖ“E×ÐUpv==»³¨.8Ï`2évö,º:| þͬ‚¿5­£I4拓 ÕTÙz(4 ìf°˜u„Ë`²à‡ža2¨½ì  œ "« 3(Í¢",a±4©¶>S³“:áÐl8V1éþêt« ƒ ­•°ª 6£γT ’5%a2÷&‹ÅÜOm; ú<˜Ø0£<–×\‡ï,§Ÿß6ÒϯVh~¿›O§&h†A¯ºÒÿ}0˜{Ó•ôH—~¿»b€ h^M3Ý I¾j¦G¾XNÇœ·ée´à«/épú,ÈüNñ6¤yçóÂP÷÷…÷Ûýñ½Ý;{}í½ï¾S~g…?rïîÂf8;<ü˜P¬ü¦$ }N¥•klûø_¯S-wèïßÝÑ\¬ï~¨)’pü Kí¼7ô“¢þû1CßûæA¬{㟄§ù4¸7úçͽOà3øÞß~ø\«ù¼G?÷èÙñOÖ=šž§ù4¸GåØh>ƒ5 a©IxW“ä?šÃÿ¡¿Â'¤¾÷õ÷Ÿ6šÏàŸü>~œ§ùdi>šOIå04ŸäÞëw©–­T—Ízª×@S"CS ¢)Y«ù Ö±Ñ|¨4…×|2~˜æÁÄ]÷Œw‹ï´|ñí‡+ÀkPzü¡Ïáè­ûç51pæî—óñ_übÌ|›ŠÿÅ„‰Š§bþ|ÿÄéÕÏaFùå÷+¦³L÷~ùÕˆ¹ûå÷[£™¦~ñÅýb¨ñyòo©t*y_ð~sËÏaFz¿õ·©5·~!þs˜ëÒÙð}b`NKFÍù¹R˜êÒ÷‰)ïtëçÇï~~ûcðý·vü[jà=sÚÛ·oÿÄéàÄ»w ­&ý¢iš/o}þ…ÆA_ü0§‡YuË]ú?šþögeÔ_Òù3tþcz:3‡¹¸ÆróCzÈ@Ï@Â/¾ Ë?FuáçŸCýÝÓ8ôÞOOÐÕ ˜èß¾ýÓ(¼«™úCú;´Æîóþ]PÜ[?Ÿ>BÜÕTñç÷M+¿ õ}çö­[÷G‰Æ‘þÓwZwnßþEø9[wØÉÝ_}ù KÀ—_~q÷Áë<÷¾|`þò‹‡- =¤Íù<¿ný/!Zü{ÿOQÓ9o=Ì÷žlõIª[|€—[@€Qõ¥Oõ„9¨'LSS`Âú .^tY&Î^0E~k i€—W@€gê퇬’ü :%OÕdyðÂÄým¯°Ü3•&ÈBÇÏ}ó}/¯–M¸pò³EMaAƒF:ü<Ò æõ á¿â›ëÍ‘×÷Ò]Þzš<ž.ÚT?‰õÕ´ `|ª—ÿ÷Òo=ÚøÔTð;üsû¯õ²†®À¤Äk¬×”ôa‹d?,7¥¦~ïÔúqûÿühcê©oè‚Pj6dh~Dð|R?ž<ÜÿUgÃÏ#‚³Ò¥ÞÒ,NeÓp€@N­Om~hó£Ó5!Ð1¾¢¤Yôz`â?5S3Bêÿ¤¦k{õ4“ÍVý ß«›ÁTv@u³úÍr\}u@<ȯ¦‹b÷—öãÔTÍ‚Xþqó'š…¥úÛ´¸´©¿¨«?§jª ÿøãÛÓ•0Z©Ùš%ÃÔêÔûͯOѬV7ßj†ägõš´ñgߟžÖ \ñêérØíúx0¤œ­7 TüRþ½ÿF8Da}Ȭÿ~¡mÜC!¿HÿIuê÷aØœí5Þ^«ëoiÜ4.}@µŽGa}=]s¥ÿ¯¿ýqöø"(¨{PdkâPÓ¤4š>þDcPüCÒßûíaÔÕšµÇñÞ ùûZ h~\®‘?Þ†©†ÔGõjß{êO?,ãÂÏ£úNõíµ9ÞKã£ÔGvÎoþØ^›ÇåW7?º¯ú±3j&ì;?¾ýߤ˨õ·›o77?á‚‘.JÞjV?iBÍÏ'O˜áãzõÓȇ ·¨ü§¸jòÈëÁë°ŸÜ{ª ê{ÿ#òóè¬ö¿¾#Zsv¦¥‹ãgø.³8J´ÍZÞ¼ôê›]×ÿ\p„è2+ßí¹Þ5üFOÎÄ—‰^ô›×zG/t]yE™¶œuˆèO8ózÿðèõÖÑ7ö'dæÏc/1Y4:ÚÚÝsµ¥kðæÖ¼œ4že‡cG^îè>;pþ¼BRœ™––°—˜Æ ï:ÚßsùPoïÍ2¹$?3%Q¯˜±“†w®ëï¼tòðpÿë[JK¤¢Ü\ï2ÁríùíEm}ƒ£ëºzÆ.Õ¨*RaŠÖn2!òÄùÞ-чº^ݲmH}u¬¦fm™¬Äk'±dÎRõ ´¬ñKïïkÎ:; ¾Ö[¿¾zuyÖvbe·±s°ÿx–½WSO×yInwoçÕέ›ÖUÖÆm&6öÞóSÖîïïk_6mbÍpÛ…—V”ö¨¯ lÛQ_[3u±uoíèìéêîkß4Ïa¦ÍªþŽÁŽœU뇻;Ï_Ù½kÛ¦þFb«»½£±EÝu²2vÆl?9ÇzÕCkRS7 uw¼ql×ÎÝ™ÉNÙpKÓË5ÉAžs"¢CÜkûZFçf­ìîî|³{ÿÎIH_ K[470tñÊ¥ó£Ó;[;»”BQº¢¿«G}ùʱ݇Wm":+òÒsrs’W­\2oɉΖþ ybYJjŸZÕÍ~«óÀË+¡`“„*Q^vFÒªø…{›ûNä«BÚ»:{:Ç^=y,y ™¬µd­4?;#eIqQ™QP(˜z¸J«¾r¾©h™ä¡¬çå7õ4÷nËÈËÍÉuŸP:ÚÞÑÕÝuýüzî62Ñjyò²0OIÇÀ©‚Ìlˆ³éÖ®gú:h‚«£N{ȯÃkÓSÓ2W9˜è¡ÎuWwçkë{ˆYˆ %-5-kÙdaWt¨!Oo¿Ë^Âs/ÊLIÍ\`¨"ÚŽíju×À©(æ^µOÍMJcV­¸Þž°Ríº°–d¸U­Ä±î޾}óÃb÷sJ¨a5Ñfåô¶ΉŒs:N´ãGwE†EEFÆNe#ZËE!QQ‘Qüã„9-6ZɈqH¡LX¬W 3ŠË#c¢#üü¦B«7^R.Oœ#’—¨–Heå5 çEÇÄ„zswsÆÌ¼2Ù*ç iýŠU¥âÊò…‹â¢câ¦Ðfo»X"-^01@!(y(ÅU%K–.Œ‰ çm#Ö £Ù+E2iN€‘e±D¬ ó•ÉÅÕŠ+–,XàÍÃÒÎ=hYžD"ÄÙó+‹×f͈.‘‰+Kãã—-^`í~J±@(‰$Â宆fº³B¥ÄÏuq©L²¦29qÕŠX.´{~’  P(Î[ìdf=ÅÚ&G**[àé¹¢T&UÔf§ÄÇÏ&Í^¨(.ÌZìe3qг‹ƒõiayvpˆÿ¥L*©g¤¤úC"­ÈßSmfyΚî<ÅOT(’ÅD„ûÆÈ%2IeeVz†7XÄõöðóóõò˜5Ó=WX¨Xíã+IeÒâŒßÍ„c±("ȧÒÛÌm…$_ž?'84ÆË^(ËÄ5ÙyAÐì¹ £  ½Ýç Ò(ŸààgÃl™’TUDA³·‰]1Ç7°@\ Kò ð÷°âÆ–‚3d’ÚòåœmD×Ð'ÐÓÉ&V$+˜ãã«òÖ5Õ±.’ …©´ªlâB•dÂÔ¬y³½¼½}ݵÉ,¥Hg%5‰Ì=„éâ©ò6ðsÓgÖ2èÝ@°L1šþ”/o?W¾Š0­Är•ˆ-UäÍ MßÒ×ßËß ¤j»Ë$B¡Hí4¢’­ëî<Úùœ2‰P–>}š‹e1Íœuh㇋ÊÜ©ŽNÓ-¡…û—%©ØŽŽ.¦´ñû„Osppttrd‡†í\éÈp6‡¶oáìäèäÀ¶oàìälmßÐÙ‘ mßÀHÓö9zúL¦6ŸÁáBÛçr­y„5‘˰օ¶ÏæXb¢G Í ë0Ñgðt¬Ѳ€,0é¤ç@z¦—LÐSÂ>HtØ#B ‰–½•Âdí': ϘÞÂ4çTÑû/mÇŒCˆ)ŸèëÓD³ ‘³8úú0Ñ#lÍÍö^ÈÊç€ L1æ×|¡Ícé³ Ñã-C8ÄbA2WK4è†%‹Š£YY<½]¤Ã Ff4ôÐL&Îá± s"[£Vs ú_“GˆŽF£0Y|fÕ÷ﻦé˜,8Ææ1ª¾•5« »›0\Î_RMïÛ°vÑT¬Jz†¾€š°w6ƒÍã2¶S[4·r¸<½‹CßÍ`36Â1›ËeƒÙ„Þña°6&c•·‘Þ–¡ïPÞ ¿0é½$}Y3ƒ©9¢w—X,Í=$¢ORÐ7_¯¿_9j5¯_¯m¢ kòjeP½ŠÉBº-ôæs÷øÍ£m„ÇbqX(þ:8Φ7¼˜Üí„ITX ¤c1Ù ‰ÞAb2ÙPxúü ›Moq÷hUiÖþ\š›ÍÒhQ{VB5æÁQ6TÒ›_,í*z·©Å¢ÁΦî`°¹P/ 8¯Þ /xÖaÒÛv´°Lã(d¦g+ÁeÌc`7— ¿ö PÀcÒ{YÌ“Mo”†\ó,5åw$Oó†I-þóýÒ›žƒ™…ŸÃç<ѳ,&Ç>{õÜ+ýû÷7U;>ɳ7å?™¢›=>}èç?¦ÿ0Žý¸äÆ~:-8bû˜ä̵?¿E‘¡õèô!÷­öžózd‘͇î_w®3”oVÿbbó~ô#6óúË/Òÿ1“÷Ðäc¿œ8õ†=T>û«³¿-y¸ý©ÿüEòoŽù¸°k?PòßÊM”šqîÁ7šükóÿýÁSâOÅF?¿‡«cá:¿ö•o6…î ü™øÉ;›¯þþë‡Ï¸ÿQkùÓäüC™¡¿Ïýiú´o“¾×÷§É}û¸€£Ó~Ú¬7<.ù݆‰? õå=.ý6‹Ÿuz¹Y ¹»ógî!¦™¯=:ÃË6?¯Xø–?*}ŸÛýqã^÷Ù#n겘uo31³ù¹þ?êùææ×?ÀêÁ¦ëè;=àØéß©üQÁBÖCz5¯Sߌ'ùîˆÏÒ?üáØÔ‡u´;4tt¿˜ð‚Zì<žàŠÊ hþÞawÔ>Or æxìÏð‘é]â.ßmõ{Â1sZ%ôa¿“™<ñ(brùï´>ÅÓ°Öù»žfœbióß&–/£«šoqüðs‘°´M y_s¿u‡÷×/œì²¤ 0)t¦-há˜ZO´äþ–XZÖ]»ñÎ[ê£í—^ãÊHÿžÅáâCÍ}J½O‰•Vj÷ù‹7¯t]»tñÜØå÷Þ8ÙqõÆëïýõzȧÄÚ÷Ðù‘ =ÃÇÆFνñÎÐIõÕW.^~ÿVšÖ'd¢©bðâ…¡ÖÖÁ±s££#×?¼væäÐÕ çnܾ¸#Çùc2Y7¥ãòë7Gšº/œ>wóí®c].Œ^ùðÆ YúR³[Ä–Ótùê{oõuŽ^¼úöèÉæó—GG^§«&+%+œ÷̃·\¼üú»cm}cçÇÆ†ÆÞ¼ÒxjðÒ…‘kïÛ^”šåò!™ªŸÛwñêû¯t´ž{ãfÏ õ¥ó#ßyótIjrzVþ"ÝÈÔ9/_¼øæ»Ãíý£#££C—Þ¾ÔØ4råܹïöÕ禤efæäÌxŸL6‘÷ƒ¾Ë]}£##ÃÃn¾Òz¢çüù‘+\ÛWœœš¡Êdæ-Ò{—LÖŽo9wóõîÎaH80|ã½þ#M£FFÞ¸ÑZ–œ”^™ÉÊÎög¿C|_¸Ø×Ú;:2<4põ£ëgŽ÷?7úê{ÛsÒ223³2Ó2Óß&“Íý/œS7u@ÒÁ±wßé:¦>~øâûoœ§¦€jnVfJzþB·ˆ‹vRÛÈØ+#g[Ç íàõ÷F¹tnìÆû=u¹)é™™©i©é™i¾ìd’÷¡óCç/¶œíÉC—Þ¹Öx¤óü¹áë½r@˜’ªÊÔOž•nÿ&™a&ï=©ëŒzxhhx`ô°£mtläÂÛoµ­MO΀t©é©éié¹±ü׉«AzÛðà塯¶áÑÁ¡¡þk]9}føÜÐØÍ÷zêóSRÓÒRirø?]v|L <|~øü¥öæ¡sTÁ¹wÞTŸê=72øÊǯ¾$LNIINËR¥³ uº*™³@÷Uâf*ë½øÆX£ztlh°ðÍ÷µ{ïƒÎµéIÉ) Jœ–A3¥ee»¾Bìø«ZÇÆ^¥«¥ghxd¨kôëgõžî»ôÞ…ÉàϬÔUšvjº&ONžã:qôxéüÅ7oô5÷ ÷ ô_ºÒv´mllpäÕ+'ÊÒ“!JÒÁQY™©ªtø6?Þê:™m"î¾þþå–ÖþÁþþÞ¡W®·:=x~xô7[kr“AA dùÞ¶Œì\Ö52[;¡exøµ«êæžÁÁþ¾þ+ï^8v¤ûÜHßÅ÷®4%%¦eeÐ*IMIÓØš,®wFÄ©sc¯¼ÒÕØ94<8Ð;òÖëmGÚÏxõ-µ*#>…¦Í¤kåã…ÊΛþFìmÖŽ^ÿRSËÀàÀ@×…·ú_>546Øù­áíÅ©Iù™iªt¾ÆÄ¬üe–׈nzûÈù÷nö5w@©º{®\8sD=6Ô=ôƵ%é))ªtvZFj Ôr¥çeÌ`@©|ö ½õÑ…u_ÿ`_ßÀå«­GÚÇÆz¯¼Úº.'%99Mc|B«LWó “©H=üêí×Ô­½¥·÷ê;玟<74pñÆÐ–"¨Û4ãÒi%C=ç¯4¿FœM³šÏ}ð^_sWß@_÷Ø»o´¾Ü1:20úö3%é iÜÝà U'#='Ëq•Ød‚×o|t±¹c  ¯«ï÷Ÿîï}û®ÂdHk¹¨ß©ÂŒÌü…W‰;oyÓhÿå_ëhîèëí¾üÁÕS/w õ´^>[ž-"59#=}\%üš“árØí}ûíÞ³à÷žîá›o¶jîëºÒ·C‘ž‘•–¬J'àxäJÉÊÓ]“ª‡‡ú_½9ÜÔÚÓ×;ÐÝsíFÏáã½#C=o¼Þ¨*ÈËÍÊú>¨i¹)ŽWÉÓ|õHß¹×F[zzº{zÆnž;úr÷jÀò•.ïWæåäfÐ eû Wn÷ q1Joëï¿4rúTwoww_ïà­/5Žôu~x«{£´¨  ?3b øôÌœøÉWˆ§Aró¹!pû™#­ý¯·÷ò»cGŽôŒ ÷w^úÍc‰¸¨0/+3c\cZjfš7ç2ñÔ‹?{n¸··óøþÓ½}=Ýê‘›¯œ=Ô>UÑýÊíó»dÅR…¸¸ —f„8†xÉšgù ãÏŒBcTÝuPÝßÛÓÝÑýÊ[]/§Ù5ôögk¥"‰B*•ЛB_š””–dw™x&Ÿèê;¶egS?(Tw^¸9z ¡e‚³÷õO.ìY-•Jd2IqAvFfzRjrrff(÷dL8 >èï?µaý‘Þþžž®°ôÄÖcƒ#}=cÚ¿¥T¡”Kerqq~´Ôä„äì›KÄÛ$2vvvŸ©/ß¡èíéQ÷¼v³sËŽŽ±¡nõÅOß>S[RVQ*“Ê¥‚"(hfZBRf(ï"ñ6ÏlîíêéiÜ"_{j¨¿§tÞm¨=öôt^½}ieYyE©\*‹Š¡¨YÉi‰¶ˆ;ÇMÑ8Ø×ÙÝÓ²S"ièì…¬}¯¾z²fs+ô,ƒ=½o~0°cMYYyY‰L*–ˆ9•™ŒPÞyâ«··o¨´6ï–æ¯kƒØìQw^ygpËšP'ƒ]ïÜlÙ°zÍêòŠr…B.çge篜xžø,;1<ÐÓ×Õ~v§$«ìäð uÓðÍW—WŸê…àíýàµcµ•5U`¶R.“‰‹ ó rf³Æˆ oVñ©¡ž®Îî¶£[ʼny ½C´zz_}«½J¶³w°§²{µ/¿T]U[©Z]Q†Ëd¢â"á ƒ1`¼t?”RÝÝÛvlsñâÅÍ=]WÞ=¿CT~j:+ˆå›Ÿo¨®ª©ªTõ ‰²‹Š}#$ç.= UÓÕÝÓq|caÜÜä½Ð¤AûÐÍ×Ï–lê¦u ¼ÿÙð®uëjÁ€5åeR üÈâMGÈãE/õôv´w÷ö´¬+ˆñ‰©ìììèêì¹~³gCàÀÐ@e·y{ÿ‡Ÿôl¯ßTWS[%X]*“)ÊÄ>Ì!2GÏKzª¿§½µܾgmv”G@ñ©ÁÞŽµzä­Kû„e´=ÝíƒÝêØ¾iÓúÚõëªTåJ©¢$e ™«ïQt¸§·³­­CÝzl‹41ÂÍ=io?½YÕÚsíêéò”ôº.(£}èÖ{Û6n\__Oí(//“•È™}$”5!Hp°»¿»£µMÝݺO•¿8ÐÙ1f}ç`O‡º½íÂkësWfí€ðш¾õöÉm[¶o¨¯«­©®„)_]0¹‡D0tUéé1­mÝ-{K’¢½§MôœìéìèhïýÂ>YÚÊ‚Cã‚:†oÝ<µ}מ­uêj×ת*Ê×T.åw’(jXá¾ö>ˆ'¤îé>½I¼bÎ [s»å{¡åwt´u^~µU•”(=> ­£‡Êúè-Õ°mÓfð2TSEåjßvh“Y‘Û[ºûzÔmm­mÝÝ-ûפÆúO·µž¤êêÃÚ†_‚ñcbêš–á¾nU¸ûÛ§wìÜ âÖÕÔT·j…Ï?®6_ËÔÉ#(béÚmýÔÀ––¶öÎÞ®cµÙóf:9M™èšyt°¯£]ÝÖ}íÊÉ2è2ê:‡ûªºMÛ>x¯eçöÝ»wìØ°±®¶¶º²z1ï4Y:) ZbíÁ“g[Ú{úÀSm­­-PìÞî³;Eó½fΜfco3uÞæ®þÎvPuñZûG%eoï¢n„ éÿãÞ=;v74lß´¹¾v]íúr·Ó„g¬T«ÛZZ;+;&·Ÿi¤2[Û»z{Zö•­òwœ2ÝÓÙ~ŠM@I3تjw~¥o§Ff‰yû vÆ]Úóö'#wíj Nݲ¾fÝ&Ù¤S$€¹¬µ»¹¥©ùìÉÆ³M-§Á©í]}=-/©RÂ\m§:{úÌv¶qÍxy°OÝÑÖÑwõâñ’4¸¾'TuO“Õ]¯}réÄÞ]»voݺsCuÝÖÃSD×±¡§édccÓ™“ SÕ2½MÝÕ×ÛÔPš9ÛÁÎqv€¿—“}ì¦îA5ø¶cøb[}NbjFZRñËÃý•ÝfÐê;.üjë¡Ý;wïiضeSÝÆúXöI¨SØÑ|êdãéSM§O656··uõvœÝ£\êïæh?ÃÝ×?ÐßÛcÆEc_DV{÷ùî’´” ,>:ܯ‚p0îjýè­Îûwîlس{ÛæÍÛªfŸ$+X±ÇÚÏ6m¶¯aÏË2½3DwRfÕÚR™˜¡r²T™ai)‰«Àà„„•KflƒQt}í½c½Êrs ‹¡H¬'úϘ·c8pyé¥-búöÍîÆS÷ì?Rfv–L7Ÿ¯¨*“AåÜÌÌô”„•«âW-I¨l¢®mmn>Y'ÈÌ+ª,œ*ËÅ‹½ü+û¨wÁ¿ãÁÜýú‡ZO>x´fR#qæÍ,¨.WHE"T ¦''Ä'įXZ¸<Z»ú[·J²² TEªÂ)B…0ÎÕÚU¦†>¤ý{Ïvu ܸ9ÒÚtúàÑMÍÄ×&½Z¥K„yy™™ÙÙ鉫–/M¯kéÒÔ×úPEvFv~~A!´¡,gÎÔ ö™§»Ul5ýŒªG§³cì½·››Žß1«…,˜°°´ºT*À/##+#iÅâ„5§é…½J=tj£0-;';'7?¯°XX¼Üm’Õä¸]ê¶ÎN¸hÚZgç¥÷ßìk‰~Û*$¤@dfEL³™f\E -òÎvuÁ ²Òöš¹êþk£ÉìóÄÒ|¾L™“¨™·¦Ž¯d§‡ØÙNdW.Ãu­j£Rm0^d]]ƒc[.s“‘8#I³â”ªqzFv*Ô¡^ ±Ò]xp¸JJÔ­êNM£íí8¹˜uLÐ Èfk^Æ šž•â7e§–X:ÈÛ‡º5þUwªéWÌ@a_oÛþ “‹Ä”í’.ËMK/!èËHò±5^¾ Ü>¾@Ï´·Óë]oo×ñšt˜eOMWe¤Ð©t‘l™»5{=Ñ6H<=ÒßÕE•¨ÔºÔ+½}­ ¢¥!“X—ˆ¡m¼¤(fÆ©‰ )©ófÕÎ4yÇhŸºªÃ€êPÃ4þdUrL\˜5ã10òOf''%'&'¦¦ÍwæBr–[yó`o¥Ú\N›ZoËöÂ…‘ó™1/=æÔY~RBBRRzZìäÄš5CÖ8ÔKSÒuoÏÁÒĨȘoæežÉSUI¬ô´`½MÄší[Ýl5x˜FRc]öˆÐЈèX_šZÛ":» +=%3Ù™¹™°õæïPušÐ¯ßõ¶î‘/ …KoT\¬ ë2ásmÓ3³òWšm%ÖÆ+C„ƒ=½'jsbƒÃçÇEE„GÅÜ+„˰<}®Ö6be¼ìàðPض[¼4<4rþ¼˜ˆÐȸXoÃk„Å2ž¤»ƒXéÏk€ JW×1UjTHXdLDDTddDôÇ_._ªÉÇ«"Ù‘Q¡F¿#|÷Å ©}áÑÑTW„ NEE91OÌXf3£b"#áØþˆ†D¼?¶‘t\Œ*’@b.."*ÌìÏD‹99d~l$U]ÉŒñáþ…p˜6Áq±Që"¶Ÿc‚KH”©*’åÃû’°ö`|e$+"*|Ò߉ޖKD\ äŠöâýÑâÚ…-ˆ Š ŸøOÂg9ÅÌ‹‰†_®¶sd\LÔä{jH¬7ïkð½õ4½{?¹{±þ'¿_EZzÜ ÆôUÙ…‚¹f“¼##œm,õ áès~K,MãWWn¬Í¯­®ªU6(ýfÆåõ):ô^Æ\IÙ¦³Ê•Uk*JªŽ·mÈW¯«y©¿ëoÈDÆôœ²Êý/W‹å«+JÊ·­®¬¨;ÓQíÏù„L4š/¯ÚsxXQZR^V²¹ñ 4W±F¹æ º!ÙׂÞ̬ÙÛÔ ”¯.+U¬yùLuŽhm¹bsëqa¨‡›þ-bËò*,ÙÐtºJ¨¨(/“Ë6ŸÚQœ_¶F±æHsõ|Ow_gÎGÄÖ*¡Tu¨y«XV^VZ"YûòAeŽ|mié®–Ý)þnî>~ÖôfF˜¨tkóA¥°¬¬¤DVºçt]nñêÕŠÚSÇ¥³=½}gi}@&ÍÌRVm¬)ÊKK•ò §_’”®-Y½ïÌú¥~³=UÞ _ë÷Éd£yRÕ¾¦Ý )˜¤TT9R‘+_[¦ØxjOF »»—Ê›é;S‹ÞÌ”l9{¸BTJ—*4mÌɯX£¨XR$W*Kå²/o)ÊQ–K¤›OmM òpÿÞCÐéÛ‡ËjOª*+KK¤âªcäéÂòñš£ÇdQТ¨Lÿ)ôö€~„HQq y›P(—+eeÉڬle™D¸±igbÀ,wMfé\%¶ü@Q‰rëÙýʉL*•H7Ø!È•*ʽG•Qž³@(3ÀÏú*™ÂpÍ/—©^[ ”ÁÜB¼ö𡲬â’±xÓñ͉s¼½¨¥¾A®¼«dªùŠR…|Ó¾Úâ"™\&H¶®É̓Q¥`õ±ãò¸À  _ˆ8–¿Ÿã ™f))“•o¬,.”‚`qqå¡­™’’©bzwZÔœà`?O¯:à¹Bì ÃDåŠUyAžDéІC¥)ù\¢šÖö5‹ÃÃæúx­§^ó1»BõçŠW—Ê%yÅ4½H´îð†œLyy™X²«û`vTXtdhp´<ðÞ4Îeâ¤$€RQ^J.˜/“*ö5ˆÓDåJ¥¸ühSÕŠˆˆ˜X˜ûyÕR7ºi_&.ùа¢ì„4‘‚Z%Ýz`Mj¦²~ßÐt p~xdL\tXp€í2üýÌ/;ý¹EJ…B)Ï_±2Ÿ®Iƒeûê²éAiÙaõæ¤èð(U ¬ƒòWÑò;s.‘™úAÅ%R LZ—/L“R]Š½Û Wä”(d IMkKÙ’ðH¸,ÇÄF†ù{C—Çô÷6»D¼‚‹ ФEK¢âE O&’mÚ[¾j¥¸jS²¡å@Á#Àu/6:,„ªôöÜ ÄžaZ\*“Àì~UXlA©‚Î,WïZ—¶(C©”J¡•œXŸº F­ŠÑ‰Œè Yý}&\ N\»ùErP*$„†&+JèÊ»|Ó6Á¢åBÍï¥û(—ÃвêÂp!2tŽŸ—Ô3—®é{¥ËR±D"H X".¥ ïâêݪUqi´£“ Ê^ÚU´(&rÇh~Âçøxûyšž'3ôý •2hŸ¢âä0Ÿ˜ÂrH/–nÝœ³°¸TS¥«_Úš³hÁ¢±ÑÑ•1|¨Î¹Aþ~“Ycd2Ï.*_)•ÐynRè,ÿ…F³¬n«lAX’R©’éJDUûjÓ.\¼`~,XÎŽ…‘ÙÜ`wQbÌ0ôÍ”*%B‰´8;!|ÆŒ¸b¹J6A,©ÚQ¹jnlí5dbIýÞòxȯš¯K Žü¡sí˜tQß>6_&gKE9ËB]¦ø¤ËáO\I7†¬Ô#É6ï)Y±xÉbj¦ø10¬ò1&S†>ébq±š²0cÉ\×IN‹¥ ‘P*‘×m/Yâ”^%°ŠäÛdË/ ç@DܼÈiÌA2¡ë›+ $’â”ùΧ„–H…"‘xõÖš´9³#ŠÊ*™9ÈØ¾[¼b ÈX²§Q %.6Ðh€80tí£2ÄbAQQ±¨871ÒÓÁÜÂ7S)EÒÚu…±³g/––Ê©¡bÇNÁÊe«–-]ºd¼01ócœ™½$ŒÁ1v‰ÊI`ž\$ ’„yØè9®’Ë¥‘°hõzéR¿žñ Í=*ÁòÄ•K¡H‹æÓ0^1¡‡D°t&{/Í1Ô˜!§Fz8ÙsLCJ±H(Èê+ÓÃÝgøƒc4‚D¥»¶®\Ÿ°|é’%KÍ‹ŽŽ[àÍë¤[ûXÍŒHˆÅ"ªÈþŸ·*ÒÝÆX_[ofšR¢Š…•uÒ…¾³ÜBòÊ•23*j[a||BüJŸ!XæÇÙ·=ƒË5´s N,“*‹¦À¼Ì8ï™öfº:º6 eJ‰H(”m¨Hœ3ÛÍc¾¨T®'ß¶­(!)qùòKArA˜éâËÓæñ &ÛOwó^œ+‚}ÅEE…E Sœµ4Èi’¥™‰¾¶‰_®R&ŠŠ%ëÖÇyΚåµB^R¥ºu»011))~å²ešh˜?›{šN†Xž•O‰ ÈEªB{ðŸD\âhajf o¬«ë¼R* ŠÂ55²øàÙ³¼Ê*™)5u·,59%5qUüJˆE‹bmN–þá9¥Ð˜iÚ|Ë6YNNFbZZüÊ+YŸ sÓ3ùyù9àÜ"4^AöŠ(olj&&VvÓ§;;N›jcke1;A"*‚w˫ŠásBBç…e*äT´”Þª]·£]üKKMOÒ9IBt]<=¼}üƒæÌ ðñõõöñööšåá5DϘí9ËÑ;‰z¢¨ PZ.N‰ £kQ‘ás§ÌW(èÓG W"*ß¹C™Ÿ—§eÇhŸ„ÞÑrîb¸.ÇDG„…ûÔz»úøxC×2}¶‡›Ç¢bI14ð‚"¥2oIXP0È ‹ˆ‰ ´± À:e¨?q{!2r³23Ò²çéœ&úæs—,š>wî??©|t4ƺ»ºFæH ,Š‹e¥‚„È  à°ˆˆðˆØ¸À©æžÙЫ„êM_*TnÛUFMÍLËš§s†è›/\0/62,dN Œë¼ª½^ —ë1Ã?Z„ªp’fD1Á!¡¡ 46ÖÛÎÊ%±Th‘ š‡¾T,Z»s£('7+#=w±áY¢o4+.1Qá!Aô®aµ·ßk¶çÂ"1tZùEÊòâåÁ>A!•s Ã"¢#]mÌm)àò?`¥žT­m54ØìŒœUfÄ€kºp]ê€Y€¯ ?9Òh‘§ŠÂÄ?2wnðÜðèð™Öºæ1òR!tàM)Œv Ü›6•@›™›<±™è›.X0gŽ/˜r=gy/.UÚŠK¥Ùq0›MunÈÜШ9ö†\ƒ€â±Pc¡„Ê‹+¶m–çååä§Ùµ}÷hzÓ'ôy{ÂTž µ—/§—”LJzùÑþ „†„†xZêhi;&+âb:ΑTÉ´ÅbÕö RèªÓ]Z‰9orЂùq0ú ! E=fÏM—Á<žH!Jòóõ¯ 0ôw5ÕÕã[/‚A½P$€p”TÊtÀ{ªõâœüÌ@^15ðZ¾‹‡Áaķלx¡jA¯ X!ÎY2ÇËßNP@€Ê×ÌËÇ×ÁHÏ@ËÈ¿P!–ŠÅ¡ˆ:OVo_'ÊÍ]dÜN‚´]£é.:ÇßÇ/6GIï(‰Åñ‘ÐÜ}!8aøìçk«§o¤§5u%”l×Qû´$"iõÖZqQÊÔâÍž7?<à9}ÊT¿1ýî@&J‹ñó ÐH¢#qk}#cŸÂr™HT)dÁx¢OK*’ª6Ö(s}8jb£míàhoocii¦Ë"L“À ?Èd¹K‚½|4‚ª¼Í}ýg›ëë0 BŠK$ãU ‘R)ãC§¶z}ýêef]¤’±Žèq§„Ä KD«æúxyzÁ<ÉÞ׿]Cc}ºã<àH"XÀ€ ¦2‰D\R·µÌŸužhz.)ȉöðð„)Ï×ÏÅTÏЈ¥"lÞÌŒ2y¥ˆŽÕÄf«"åú¹Vç ë´dy]áùøùÚêéT+“b%L=Ä4 ´9ßA¡*׆Áü‚käãçîE³øûÚ°ª—i³P¯@É„͈P*Q”'Oº@¸ú³#Ã|<À..ä°Õ7à×CÏÌ2 ZE0žƒ6Èj®72h;……CY|'ê°kˆcRŒXù½ïÄ D.¤ê]$\öäà¨@ê0šÃZO—QK¬xމ¥ °_B@@¨`¹ßd.ä`XÌ Ò4k_?wK}Öz¢­PTF} ÒU"&äTɹ‚´¨YŽX—×" <Л¶[¶¯Ÿ›…vá1&Ï“”Á¿Rh@P“rú8Ít5e@z=§€¹PˆJHïïfή'¶ÝBBZ ¢…Ð9êˆe‚„àévήFLHÏ2Œ¤í˜åççl°‘X³§ÆÓÑ×x™EYÖÃÇ?0Ø[+±6 ‚ÁŽ„Z!•®t˜êàâäàèìâlgLÞ9¦^A3xÛˆ•¡_V©B,B±R"\§Lsœîhïäâh?ÝAŸ.¼ë™jí &z©J˜œŠ$ùà(;{G'•#ËÙeŠögÄJË%Y síâ”ööŽvŽ.Ó@„Ãôɼψ×1^^®È™7Ûv Ø:ÍÞÁ©Ò‘í<ÝÑ‚C×ݧ-•É“ƒl Ž4›ƒ½ÓtgkögÄ’=eIþ2_°²99;‚RÍ?Ýß‚ççEÏvv¢Ùì×;2íµGÌùö.Óœí§ÑŠ“£Ý%ÕŠñ{bÆ6‚á¡3$vrþï?ÇÉœ?¾ž““=¤sR9r5õÿL8L {gg8Dà†•NSØ!–¹Ëtg(qªr$fŸC2ck‡ÿ&c:Má| ‡Ì]œœª‰É߉¢‹ éç軕½ƒ³³½½³)]x·r€A¥³ç+ÂÔ²vP9ºðnáâ:…MÞM-´¾ð®Ãäò5/”£û”þX°ù<]+}ЕÇár8 }ç‹ù[Â×åbîbÌbVÝiÖ<—É`šZ°?%ëCbÀ' KWËšd¯§Mܬ@1“¥Åø€ðôt Û˜ÙÄÅ ÎrœøÕ„Ác¿ÖN`–­‹äÕr°eÓçƒ'8ÓgùpVO›0ÌgX0h!'Q£X|{kºg,ó.˜ ½´ŽËT65Ù܉º€9ÑI‡>˜«Å|›ðXfšì¤[£q ¸eèjM7¡eó߆îB›cGj3s¢3•̱wÒª' >û-p®>!ZvÖ,0YgšY5aB%lÐ<ý&È3-§jÑâZ[³!«¶ƒ5“>TÌäjA½ØÐ'LƒÞÅž4•¿,f½å¡7W&M  ë:QA"º™-ÿ5ê 6aL˜ª­ñã4êGm{+ú43õªÆDßÞ ò2 í ªhÖÉümô‰^Æõq‹Ù6“9—*¨‚Zµ5ÜAÀ×ÀbljG=Á4›Ä£yÍ'ó¶S‹!+µØ`Š ¬?I k`£·:‘Yµ!,86V´òØVÆàiž­9}d›Ã‡“S!†“´j!§—úß–Jù¬«ãQA¸–zp’k©bõ¦Pƒ4uA*ÓÔœ¥1È‚ºmmÉ¥L-æÕqý‰:U×Z›šk2Y‹šÄcSÁúôyv+ƒZ(ª¥!-ª¶­±FòUÂghD›2©h“ p­d±&Úp4å¡¢u!fú–<*ÚœO ;Ýòr¹pN‹^õ9ôág‚9[gQŒ+P|c6D¼¶.•Ì00‚†Â4rµ¤zÙpJ«Ò<] ™ÙzœjM<ñ·kªç2==¾2œeèÁõ˜i6sU ½?‹¡¯G·PæÒ@æ:8p·Óx 'ôô5{+Ò Îfãi:ºŒMA6~¦Õd6­Î%šA‡žàèÀœÉµ1¢Ö×§ÇY| cð%¨¾¿ëj2@sg²¬&Ð'âYü‹pD_g‹fWgZSíí´]\ %ÓÕ<k37o\ÀeÐÍ ÌJF%s=Ô@wu\.Ô3Ý‹€ÐdãÉÀ= …š²óû´Î Ûð5É4;I€éž ðëN8¶üÂ;I8<.M° š9K“04Êö€ýü“48¸»Ý6¡’чÀ]´Áìß¹{\—w†¶÷]„M·t`ì&ô5›Ôþø“Ëc¶Ò ‘,^#TŸÓ¬ '8ÀÔj¢¹M hÇø¦äàrp\Ñ™gÈ÷ÆÐ=ÇuY-š¬tszT³9¹¯p¸Œ‘ñd ŽV;ÔŸEãîüÛ¦©X*²¢™ÏoB× íF›Çã0^¢×ÎnÂÐãu#¨ˆ(>GKG› ¦ò™{¡@0‚`ï ÎåêuRa,êCè$Øp~;ѦÕÀä‚×´  §ûKèsÏiZÿöñ*âÐ}(x<žþyZËÔxN¥æj°SÓÓ¸ê3¾78œ£ÏŠËaÔÑ=8ðÉ2æ‚u ž®¦÷âh±4ÛÁƒ™\C;û$ãR!t z&ǘ·UÙLm}z Z^í÷[‰ðÍÙ[àrBÃæ<´Ÿäréæ\&§o¹u4cÂ?=èxY,¾›6}.”ÉÀ`Ñ…–9‰ã xà1>tp:]]èvt˜ÿ U–¾.ŒË¡A@wÍbèè@wÄc04»ÍCkƒ!…®ãS0ŠÇ [“è‘ñø†ó,]=Á¥{¬ÐH†JªéæПFÃI÷Ï7¤©‰&ƒ&Æá\tSp„fç~œ§šÀ6ŒÃ¹:,úòdÍäuà^Öï›oÈÕlBÈ:8=öïáB¦Ålú?ʆæ¡Åúíª*I-•Aýgˆ>C¡Ãü hÐ×b®‡?ؼÏá”— a ó%¸€Çû™ øï„ÉÓfÕÀq& ±ió§âÙ¼Ò ‹ZÎc~E¸|j(› Cl–ÅcÒ!¶6—õ-݇ý‡õF"Óì]2÷9ï]‚h*œÉüõbhRºFF†z:ÚÚ::ÚZ<›Åd±ØlÖÿÄ$&×Àbêt·™3œììì¦ÙÙN²œ`jlb6a‚©‘.÷…›ÀàÙEËê6V –&¤e¤­˜äí1ÛÓÇÏÏËuª™6ëëgLùÛ×_ÿã³s}oÞºýÁõáæƒÕ’Õ /9²9;j–¥6óÅz_gRhã}ûN|÷ù§ýöλ_]®X<Ûœ÷"k€Á3÷¬ûâafügH1ßÙàEÖÛÈ)烇ïØñçCyÁ“´^œ˜º¶Q­wñ²‰Ë5+g³_œ÷-|·ýíQ[–|qF1EçE… ÛØYð›Gï±òÑöosî‹©–®í¼Çl"óÝpÙ§‚à}¿Ý_=n×›?Ê ²æ3^Hì;ç?~3á;—*—»±_HìÇ´Üyü>Á:*³}þ½ ƒoá·õoO°OñÝ·6%yšqŸì»Üz¢’¿PÎsÔg=oïO™ßqç‰ôßûÜ9“´˜Ï9ö}vþã wоûæúU³MŸg'À€ØÏ~ÿ‰·ªþºG3Mù¿ýÿòYC¦Ÿåó»Cìûïý¿§Ø«û»‘ŠÅÏñBL{ž§Û–ü÷󂬞—˜:“£žÆûš ±j±“þó‰w‚Çú§}¥Ìï2¼LŸO/Ì6tH{çiwkÿô`a çùxß&²é?O©þ›+» Ì9Ï'ö}6ÿíi‹ÿÛÖ©î&Ï£pŒ§ n?­úo¯*›o¯ûâ©7uÑðSïÕÿ'õ–l_óçp dhYìý÷Óªÿšßá9tÀ ž™kÁS{ÿÎGÍ3}žCñ#§•=Oû÷þÒ¿÷ù\XúS—ô|ýÔÞ¿~¬:®¿Ï{Úçýö©ƒïãÖ­ùÏcüsM÷Ú/žZý?Æ”Ìã/×Ä%ëí§ßà»gêR¼&pŸCì9,î½óÔúÿopø9LÃiKZþýôÅïTM¼Û3OA½Ýü¦ožþ-%Ÿ÷í†N~Ö%P?5öÌ¿ž^ýn¯^éjÄzvõ‘‡¾zzõ÷þؽ³0xÒ3N?!ôìæøû¯PÿÏ‹‡W/qyÆ'¨Ÿ6¿ñß¿Bý÷În|æ7“gl?ÿ×Ôý½{_ ì•EÛ=ÓeŸÁÒ2sZôëÔÿçæÉÚ„Ù&Ï2êb°u­f¥wüçß»÷çž]ÅÏÖö\ÿÕ7îü*õÿyýXåò†¬g(¼¶™}èÆßÿÊ$ý¥{GÁœgXúaò '¹'ý˯Tÿí«GÖ,ùõ“>[g‚C䆛ßþJõw?iÛšðkÛƒÉ5œì•×þ·{¿–¯Î,[ð+Çœ OßÂ)¬î£»¿þõX¿iÞ˜áó«.û ßÀÒÁ?«ñ/¿^û½¯/TÆN{ú®‡ÁâêOt Ê~ùý;Ï þÞïÚ6exOà<­r޶‘¥Ý¬°‚£þçY´ßû÷åC¥óžfÂÅ`²8|]#‹)®sÓëÚ>y6ít¾¹fœ'*3›ÃåiéšZLž63`YUÓûÿº÷¬|÷êËåóž øpy10³´ž4Åa¦wPt溣—ÿvï9ð·¾íyþÜ'¸´ëY9ûÏ _%S:­þð«»÷ž Ÿ©^>ýñË= ¶mHeëË»O½úùßþsï¹ñÝõýÒðÉ¿ÏÎÒµ‰<þ÷{ßýû9êÖ z»·d>ÁjLæý÷üëÞóçê%Žzíù9&®òß¾õÿ¹þ’$tï±Þ×›ºøÜ‹x3âWC[ŸÀýL-kÿÝ_½ýl©]á¢ÏxìRŠ›â7/äÍ-‹¢õ¸¦gè˜ùæ‹y3å[/‰‚­¹[Á·‰é}1êï¾¶+Ï×ì1ã.îïÿ|1úÿsuk†»ñ£;?†Î”ä^ЋA¿Ý”<ÓðÑáÇ4tQ~ñ‚ô=XŸ0ã1áÏ4š™wíÎ Ò?°n¥Ëcz?¦óÒ ¯}÷Bôÿ»¿f™“îcšŸö¤àœï½ ýÕKu{Ã1ºèà'ÿÏô3x&.±ÂC·î¾ˆú¯Yþ8ÿSL§Ïüàùá·çÖ?6þÆ ˜1_´ï­ož{ÿw}c¢«ã æ·f3æoùóó6à­iëÿÆ à›ºDåÔ4ÞzÎuð~Cžï„'YñdòL샓ËÝø÷sÕÿ‡£¢ë'šyÒõ異íÃ|ž.øJ]g§ý¤« 3crkN½óíóÓçÊúU®O8÷còM‚“Jö^{ŽWãÛ{sýŸøf'ÔÁdÏEÅ›zû“YÀ·ÿ|l³|DÏõOµ2ÖNçIW^lmóé‘™ª#W~û·¿ÿýïû⯿ûàÚèåmÁ7Ÿþñá¼·%Ùã)îv3yFv+%õ‡›ÛÕꎶ–3Çî{éäå¿>¢ˆß}8táá÷àÿÙ"šú÷<`:qVTа¼²¨R•ËE’Õ[Û±ó§Á–¦W~ý~wkêSÝóy¸éT÷¸ÅK% c‚CåÖœûîá‹{§÷ï<úñÃkg $Îþ©¿“‰Sí‡i¶“¬&:ÍMÛøæÃº…ÏÚw¯—Ÿ}øbÁ§»3}-žnõ‹Áæiéè:Ú|‡§o;'cÛî¾¹zxMòüøŠËu•-tz¦›~0= ÍÙrñÝÂ_:·æÏôOÚý»‡;à@îœIÏòµ7ÇÐ>,»®÷—Çï^?²z‘³Å”Т‡¯Ìß}c}‚—¥Ö³0-$]ÕøÙ/ƒ¿s{^€¥¶‘Ë"Õ+­V,u·Ôb=‹SÊNüæ>wÞ:¦Zâ¬ÏâYø¤ìzøöC«—zXj?“z“¼–ɽö÷ Þ]lÍc0u¦„øí¯Ï¯]îiõL°´-g-léúÙ2ÉoÎÖ®r¥÷5ØFÎóegþðð^à‚j…§Õ3ÝygjM˜•¥:õ›Ÿ6¾ý²z[‡Á3›µ´´ùá¹o.V.w7ç?“<ãiñÊ#ï~ýãÒòÆ4Ïñ« SËÒsåꡯáŠE®&ÏôÕCG¢Ç"áÎÁOÆÕüçµCeóþ»²ÎÔ¶öI\åá—ÊœÆ8qžÉ––¹kLnõ¡ÁhgôÇÎ-Y?~—‡¥3) }óõ‡ž>9\1ÍóŒ·@aŒ/^·¿ë­Oßïß§œ÷“û*,½)!9[¯?Ü¿=”2õ¿~c¤I³Â„ªíl/[åñ“K+ƒm`ž»åâÃWÒníHxÖ¯Ÿ0ØZ&¶n!˲¢¼¥¾“~:´€nÒ!|@Gð‡ž]ÅÁ_ðSÔ€€Ä²ƒïüb<ð͵£•+^È÷0É{™ôà/¾ø×®íùs&ò_ø£p –Žå¬¢Ã·ïÞ÷  £k¿Ø‡ ~h|³ó„oü¬'ú¼gG~ ïòp"]Rš'Ø6ô“vxçæqÕR&ùŸÀä™MÉß0ü£íÛ¥«‘ÿ•&ŽaYëúÿþCퟨZñ,ßAyú+¥¡]pZMÿ÷ø¼wwñÜIüÿᣩ ¶¾mPju¯¦+¼ûÿ™¿þö”@O˜¬jû#§ÑÚŸÈÿß>™ =‘BÅ™¿üÍðÁÕK§þo‹¯ùÒÖ$ŸŠÝ§O4¨R|­øÿû“Y:Vî rä¥Âø@[=ùßÃÒšàä2k²>çÿÕsÙ‚ Æfã÷#sÖ__›Ë 1å~b>vûÆÒ,u­ù¢€¥–®3f4ÌÊ0Ú±-Þ-sÑ?§%ï¹Ê)¬á Þs6mji}éÞÐáß¼½óïʹó÷®Íu¿¹xöjóʿӶÆòwž«'É>û¶Ýà–Ô­å𷢯Õk=Ï6ö:ïoxä¿UôŽîþßuøÇ¿ò¡§P*?ôŸ ¼n­^ûŸVºñÖ®ü¬ÉÔ{DçÍ]ß|øEËwÆÝß%—¸ýÆöKúõV!|Þ»Ç"gþP¸I³« ‚ ‚ ‚ ‚üÿoþ­]«:Í´öMs­?mþ"môÜk3l§®úCꥩÒ÷ú7T¯Ê3yEûœß­¡Šì—ýå?{SŒ¶'[­ÿ禦»3#¬¾íôï;>S;<Þ¿kòŒ6µxãõ?¨gžÄ‰:‚ ‚ ‚ ‚<Ïùÿ•v£ðE¦sߌ ®(Û¶÷ýMÜM³íþ•øž»÷âÑ“Kš·ç;°óÖ‡ú‡¿H<±vC]ÙG'gú]¼}ï57©é¿çªszÆ/Z©”ýd|Úo ÇžÓ~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAþ?öà@ÈÿµTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU؃ ÿ×FPUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUioŽq¢0¿euŠu‰„B"ë4B§u‰Û¸ˆÎ ®à†!*"±ïKÞ¼™Ì¼þÙlm1­'õí|èû‡îe–÷¹gUªQZ†ƒˆ^™Fâ^ùâ©x÷O¹[ÆÃÍü•U=ߟæ¾RžsE,Rµ½¡¼ö¾Ù¼Xþœ ¹Ò®:’qstella-3.9.3/src/macosx/SDLMain.nib/0000755000175000001440000000000012267274566016477 5ustar stephenusersstella-3.9.3/src/macosx/SDLMain.nib/designable.nib0000644000175000001440000011146211562251763021262 0ustar stephenusers 1060 10J869 823 1038.35 461.00 com.apple.InterfaceBuilder.CocoaPlugin 823 YES YES com.apple.InterfaceBuilder.CocoaPlugin PluginDependencyRecalculationVersion YES NSApplication FirstResponder NSApplication SDLMain YES SDL App 1048576 2147483647 NSImage NSMenuCheckmark NSImage NSMenuMixedState submenuAction: SDL App YES About SDL App 2147483647 YES YES 1048576 2147483647 Quit SDL App q 1048576 2147483647 _NSAppleMenu Help 1048576 2147483647 submenuAction: Help YES Stella Help ? 1048576 2147483647 _NSMainMenu SDLMain NSFontManager AboutBox YES delegate 195 terminate: 292 showHelp: 469 showPanel: 720 YES 0 YES -2 File's Owner -1 First Responder 29 YES MainMenu 56 YES 57 YES 136 196 717 103 YES 106 YES 111 194 SDLMain 253 Font Manager 719 AboutBox -3 Application YES YES 103.IBPluginDependency 103.ImportedFromIB2 106.IBEditorWindowLastContentRect 106.IBPluginDependency 106.ImportedFromIB2 111.IBPluginDependency 111.ImportedFromIB2 136.IBPluginDependency 136.ImportedFromIB2 194.ImportedFromIB2 196.IBPluginDependency 196.ImportedFromIB2 253.ImportedFromIB2 29.IBEditorWindowLastContentRect 29.IBPluginDependency 29.ImportedFromIB2 56.IBPluginDependency 56.ImportedFromIB2 57.IBEditorWindowLastContentRect 57.IBPluginDependency 57.ImportedFromIB2 717.IBPluginDependency 717.ImportedFromIB2 719.ImportedFromIB2 YES com.apple.InterfaceBuilder.CocoaPlugin {{420, 691}, {143, 23}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{329, 714}, {152, 20}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{341, 661}, {179, 53}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin YES YES YES YES 747 YES AboutBox NSObject YES YES OK: showPanel: YES id id YES YES OK: showPanel: YES OK: id showPanel: id YES YES appNameField creditsField versionField YES id id id YES YES appNameField creditsField versionField YES appNameField id creditsField id versionField id IBProjectSource AboutBox.h AboutBox NSObject IBUserSource FirstResponder NSObject IBUserSource SDLMain NSObject IBProjectSource SDLMain.h SDLMain NSObject IBUserSource YES NSApplication NSResponder IBFrameworkSource AppKit.framework/Headers/NSApplication.h NSApplication IBFrameworkSource AppKit.framework/Headers/NSApplicationScripting.h NSApplication IBFrameworkSource AppKit.framework/Headers/NSColorPanel.h NSApplication IBFrameworkSource AppKit.framework/Headers/NSHelpManager.h NSApplication IBFrameworkSource AppKit.framework/Headers/NSPageLayout.h NSApplication IBFrameworkSource AppKit.framework/Headers/NSUserInterfaceItemSearching.h NSFontManager NSObject IBFrameworkSource AppKit.framework/Headers/NSFontManager.h NSMenu NSObject IBFrameworkSource AppKit.framework/Headers/NSMenu.h NSMenuItem NSObject IBFrameworkSource AppKit.framework/Headers/NSMenuItem.h NSObject IBFrameworkSource AppKit.framework/Headers/NSAccessibility.h NSObject NSObject NSObject NSObject IBFrameworkSource AppKit.framework/Headers/NSControl.h NSObject IBFrameworkSource AppKit.framework/Headers/NSDictionaryController.h NSObject IBFrameworkSource AppKit.framework/Headers/NSDragging.h NSObject NSObject IBFrameworkSource AppKit.framework/Headers/NSFontPanel.h NSObject IBFrameworkSource AppKit.framework/Headers/NSKeyValueBinding.h NSObject NSObject IBFrameworkSource AppKit.framework/Headers/NSNibLoading.h NSObject IBFrameworkSource AppKit.framework/Headers/NSOutlineView.h NSObject IBFrameworkSource AppKit.framework/Headers/NSPasteboard.h NSObject IBFrameworkSource AppKit.framework/Headers/NSSavePanel.h NSObject IBFrameworkSource AppKit.framework/Headers/NSTableView.h NSObject IBFrameworkSource AppKit.framework/Headers/NSToolbarItem.h NSObject IBFrameworkSource AppKit.framework/Headers/NSView.h NSObject IBFrameworkSource Foundation.framework/Headers/NSArchiver.h NSObject IBFrameworkSource Foundation.framework/Headers/NSClassDescription.h NSObject IBFrameworkSource Foundation.framework/Headers/NSError.h NSObject IBFrameworkSource Foundation.framework/Headers/NSFileManager.h NSObject IBFrameworkSource Foundation.framework/Headers/NSKeyValueCoding.h NSObject IBFrameworkSource Foundation.framework/Headers/NSKeyValueObserving.h NSObject IBFrameworkSource Foundation.framework/Headers/NSKeyedArchiver.h NSObject IBFrameworkSource Foundation.framework/Headers/NSObject.h NSObject IBFrameworkSource Foundation.framework/Headers/NSObjectScripting.h NSObject IBFrameworkSource Foundation.framework/Headers/NSPortCoder.h NSObject IBFrameworkSource Foundation.framework/Headers/NSRunLoop.h NSObject IBFrameworkSource Foundation.framework/Headers/NSScriptClassDescription.h NSObject IBFrameworkSource Foundation.framework/Headers/NSScriptKeyValueCoding.h NSObject IBFrameworkSource Foundation.framework/Headers/NSScriptObjectSpecifiers.h NSObject IBFrameworkSource Foundation.framework/Headers/NSScriptWhoseTests.h NSObject IBFrameworkSource Foundation.framework/Headers/NSThread.h NSObject IBFrameworkSource Foundation.framework/Headers/NSURL.h NSObject IBFrameworkSource Foundation.framework/Headers/NSURLConnection.h NSObject IBFrameworkSource Foundation.framework/Headers/NSURLDownload.h NSObject IBFrameworkSource PrintCore.framework/Headers/PDEPluginInterface.h NSResponder IBFrameworkSource AppKit.framework/Headers/NSInterfaceStyle.h NSResponder NSObject IBFrameworkSource AppKit.framework/Headers/NSResponder.h NSView IBFrameworkSource AppKit.framework/Headers/NSClipView.h NSView NSView IBFrameworkSource AppKit.framework/Headers/NSRulerView.h NSView NSResponder 0 IBCocoaFramework com.apple.InterfaceBuilder.CocoaPlugin.macosx com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 YES stella_intel.xcodeproj 3 YES YES NSMenuCheckmark NSMenuMixedState YES {9, 8} {7, 2} stella-3.9.3/src/macosx/SDLMain.nib/keyedobjects.nib0000644000175000001440000000766011562251763021644 0ustar stephenusersbplist00Ô¬­X$versionX$objectsY$archiverT$top† ¯i-15<?@DHOWZ[\`euz{|‚ƒ†Š‹Ž“— ¦§¨©®¶·¸»¼½ÁÑÞãäåëøùüÿ    0ARSTUVWXYZ[\]^adyŽ‘’“”•–—˜™š›œžŸ £¦©U$nullß  !"#$%&'()*+,_NSAccessibilityOidsKeys_NSVisibleWindows]NSObjectsKeys_NSClassesValues[NSFrameworkVNSRoot_NSAccessibilityOidsValues]NSClassesKeys\NSOidsValuesV$classYNSNextOidZNSOidsKeys]NSConnections_NSObjectsValues[NSNamesKeys_NSAccessibilityConnectors]NSFontManager]NSNamesValues€f€€+€P€€€g€O€R€hí€Q€ €@€A€e€€BÒ./0[NSClassName€€Ò234YNS.string€]NSApplicationÒ6789Z$classnameX$classes_NSMutableString£8:;XNSStringXNSObjectÒ67=>^NSCustomObject¢=;_IBCocoaFrameworkÒABCZNS.objects€ Ò67EF\NSMutableSet£EG;UNSSetÒAIJ€*¤KLMN€ €€€#ÔPQRSTU WNSLabel]NSDestinationXNSSource€€ € €Ò./Y€€ WSDLMainXdelegateÒ67]^_NSNibOutletConnector£]_;^NSNibConnectorÔPQRab d€€€€Øfghijklmnopqrst_NSKeyEquivModMaskVNSMenuYNSOnImageZNSKeyEquiv]NSMnemonicLoc\NSMixedImageWNSTitle€€€€ÿÿÿ€€Óvlwxy[NSMenuItems€:€3€9[Stella HelpQ?Ó}.~€^NSResourceName€€€WNSImage_NSMenuCheckmarkÒ67„…_NSCustomResource¢„;Ó}.~ˆ€€€€_NSMenuMixedStateÒ67ŒZNSMenuItem¢Œ;YshowHelp:Ò67‘_NSNibControlConnector£’;^NSNibConnectorÓPRa•–€€"€Øfghijkl˜™opœsŸ€€€€!ÿÿÿ€€ Ôv¡l¢x¤¥VNSName€0€3€2€.\Quit SDL AppQqZterminate:ÔPQRa«¬­€€)€'€$×ghijkl™op²³sµ€€€€&ÿÿÿ€€%]About SDL AppPÒ./º€€(XAboutBoxZshowPanel:Ò67¾¿^NSMutableArray£¾À;WNSArrayÒAÂÀ?­­ÅÆÇÈ–nUÌ™¬Ïd€$€,€4€6€1€€€ €-€€'€=€ÚÒfÓghijklÔÕ™Ìop²Ûs¥XNSActionYNSSubmenu€/€€-€€€&ÿÿÿ€€.Ôv¡lßxáY€;€3€<€ WSDL App^submenuAction:ÒAIç€*£­È–€$€1€Úkfghiìíjlsï™op²ôôö²]NSIsSeparator\NSIsDisabled€€€€€& ÿÿÿ€&\_NSAppleMenuÒ67úûVNSMenu¢ú;Ò./þ€€5]NSApplicationÚÒfÓghijklnÌop²s €8€€-€€€&ÿÿÿ€€7THelp^submenuAction:Ò23€THelpÒAI€*¡d€ÒAI€*¢ÅÇ€,€6[_NSMainMenuÒ./€€>]NSFontManagerÒ67À¢À;ÒAÂ"€?­™Ì Ì™™Ç Å n€€-€€-€€€6€€€,€€€ÒAÂ2€?®­ÅÆÇÈ–ÌUn™¬ Ïd€$€,€4€6€1€€-€ €€€'€€=€ÒAÂC€?®DEFGHIJYLMºOPQ€C€D€E€F€G€H€I€ €J€K€(€L€M€N_Menu Item (About SDL App)_Menu Item (SDL App)[Application_Menu Item (Help)YSeparator_Menu Item (Quit SDL App)XMainMenu[Menu (Help)^Menu (SDL App)\File's Owner\Font Manager_Menu Item (Stella Help)ÒAÂ`€? ÒAÂc€? ÒAÂf€?¯­NMLÅÆÇKÈ–nÌ™U ¬Ïd€$€#€€€,€4€6€ €1€€€-€€ €€'€=€ÒAÂ{€?¯|}~€‚ƒ„…†‡ˆ‰Š‹Œ€S€T€U€V€W€X€Y€Z€[€\€]€^€_€`€a€b€c€dÍÐ$Õ8ÿÿÿÿÿÿÿýgÃĈj9ÂìÏýoÒAI¢€* ÒAÂ¥€? ÒA¨€? Ò67ª«^NSIBObjectData¢ª;_NSKeyedArchiverÑ®¯]IB.objectdata€"+5:?e’ ²¾Åáïü &8D`n|~€‚„†ˆŠŒŽ“•—™›Ÿ¡ª¶¸ºÃÍÏÝæñú %.=BU^iklu‚‰˜š£¥§©«¼ÄÒÛÝßáãìîðø !(7HJLNPq…Œ–¡¯¼ÄÉËÍÏÑÖØÚçóõ÷ù#%')1CL_dqsuwŠ“ž£­¶ÎÕäñóõ÷!#%*,.?FHJLN[]hy{}ž ¢¤¦«­¯½¾ÇÉËÔßè÷þ,.02468:<>@BDFox‚„‰‹‘“˜šœ­¯±³µ½ÌÕ×Þàâä (*/135789>@MV]bkmo}¦¨­¯±³µ·¼¾ÀÅÔÝßäíïòôýÿ       ! / 8 = F H c e g i k m o q s u w y { } † ˆ ¥ § © « ­ ¯ ± ³ µ · ¹ » ½ ¿ Á Ê Ì é ë í ï ñ ó õ ÷ ù û ý ÿ    ! 7 C V ` { „ Ÿ ¬ ¹ Ó Ü Þ ß è ê ë ô ö   ! # % ' ) + - / 1 3 5 7 9 ; = ? A J L s u w y { }  ƒ … ‡ ‰ ‹ ‘ “ • — š   £ ¥ ® ° ² ´ ¶ ¸ º ¼ ¾ Á Ä Æ È Ñ Ó Ô Ý ß à é ë ì õ   .° 0stella-3.9.3/src/macosx/Preferences.m0000644000175000001440000000417512266336753017123 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Preferences.m 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 { defaults = [NSUserDefaults standardUserDefaults]; sharedInstance = self; return(self); } - (void)setString:(const char *)key:(const char *)value { NSString* theKey = [NSString stringWithCString:key encoding:NSASCIIStringEncoding]; NSString* theValue = [NSString stringWithCString:value encoding:NSASCIIStringEncoding]; [defaults setObject:theValue forKey:theKey]; [theKey release]; [theValue release]; } - (void)getString:(const char *)key:(char *)value:(int)size { NSString* theKey = [NSString stringWithCString:key encoding:NSASCIIStringEncoding]; NSString* theValue = [defaults objectForKey:theKey]; if (theValue != nil) strncpy(value, [theValue cStringUsingEncoding: NSASCIIStringEncoding], size); else value[0] = 0; [theKey release]; [theValue release]; } - (void)save { [defaults synchronize]; } @end stella-3.9.3/src/macosx/Create_build.sh0000755000175000001440000000206312114210212017364 0ustar stephenusers#!/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 build/Deployment/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-3.9.3/src/macosx/AboutBox.nib/0000755000175000001440000000000012267274566016773 5ustar stephenusersstella-3.9.3/src/macosx/AboutBox.nib/classes.nib0000644000175000001440000000055310250207077021104 0ustar stephenusers{ 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-3.9.3/src/macosx/AboutBox.nib/keyedobjects.nib0000644000175000001440000001675610250207077022136 0ustar stephenusersbplist00Ô Y$archiverX$versionT$topX$objects_NSKeyedArchiver† Ñ ]IB.objectdata€¯± 156<=AEMUcijz{ƒ„‡‘’“˜šŸ £§®¯³¸ÌÝëìíîïðñòóôõö÷ !#%47kˆ@EFKLOYшÿZ`acgjklpqv}~z…Š‹§z¨©¬´¾ïíòÇìÉÊËÖÛÜÝáåè÷ý #$%(/0CDFJMNPQRSVWC\_jlw‹ŒŽL‘”—¨¹º»¼½¾¿ÀÁÂÃÄÅÆÉÌÏU$nullß  !"#$%&'()*+,-./0_NSObjectsValues_NSAccessibilityConnectors_NSClassesValuesZNSOidsKeys[NSNamesKeys]NSClassesKeys_NSAccessibilityOidsValues\NSOidsValues_NSVisibleWindowsV$class]NSConnections]NSNamesValues]NSObjectsKeys_NSAccessibilityOidsKeys[NSFramework]NSFontManagerYNSNextOidVNSRoot€’€­€€ž€“€œ€¯€Ÿ€€°€€”€€®€€>€Ò234[NSClassName€€XAboutBoxÒ789:X$classesZ$classname¢:;^NSCustomObjectXNSObject_IBCocoaFrameworkÒ>?@ZNS.objects €Ò78BC£CD;\NSMutableSetUNSSetÒ>FL¥GHIJK€ €€P€W€€5ÔNOPQRS0]NSDestinationWNSLabelXNSSource€ €€€×VWXYZ[\\^_`ab_NSNextResponder[NSSuperviewWNSFrameYNSEnabledXNSvFlagsVNSCell€ € € €€ ÔdVXe.ghZNSSubviews€]€€†€‡_{{69, 328}, {380, 29}}ØklmnopqrstuQwxy_NSBackgroundColor[NSTextColorYNSSupportZNSContents]NSControlView[NSCellFlags\NSCellFlags2€€€€€ €þ@_<>Ô|}~€‚VNSSizeVNSNameXNSfFlags"AÀ€€\LucidaGrandeÒ78…†¢†;VNSFontÕˆ‰Š‹ŒŽWNSColor[NSColorName\NSColorSpace]NSCatalogName€€€€VSystem\controlColorӔЕ–WNSWhiteK0.66666669€Ò78™ˆ¢ˆ;Õˆ‰Š‹›œŽ€€€€_controlTextColorӔС–B0€Ò78¤¥¤¥¦[;_NSTextFieldCell\NSActionCellÒ78¨©¦©ª«¬­;[NSTextField\%NSTextFieldYNSControlVNSView[NSResponder\appNameFieldÒ78°±£±²;_NSNibOutletConnector^NSNibConnectorÔNOP´µS0€€O€€ܹVWº»¼½¾Z¿ÀÁÂÂÄÅÆ.ŽÈÉÊË[NSFrameSizeXNSMinize\NSSharedDataYNSMaxSizeZNSDelegateYNSTVFlags[NSDragTypes_NSTextContainer€-€ € €M€8€L€ €N€!€.ÛdVWÍÎÏÐÑXZÒÓÓ´Ö´ØÙÚÛÜ]NSNextKeyViewYNSBGColorYNSDocViewYNScvFlagsXNSCursor€p€n€n€€9€€r€q €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_NSTextContainers€0€€6€4Ó½ .  XNSString€€3€1ÒYNS.stringP€2Ò78£ ;_NSMutableStringÒ78¤;_NSMutableAttributedString_NSAttributedStringÒ>L¡Ë€.€5Ò78£ ;^NSMutableArrayWNSArrayÒ78"ú¢ú;Ò78$À¢À;Ø&'()*+k,-.›01.Ö_NSSelectedAttributesWNSFlags_NSDefaultParagraphStyle_NSInsertionColor_NSLinkAttributes_NSMarkedAttributes€: m€€€B€K€€9Ó”Š5–B1€Ó>89<?WNS.keys¢:;€=€?¢=>€;€<€AÕˆ‰Š‹ŒBŽ€€>€€_selectedTextBackgroundColorÕˆ‰Š‹›HŽ€€@€€_selectedTextColorÒ78MN¢N;\NSDictionaryÓ>8PT?£QRS€F€G€J£UVW€C€D€E€A[NSUnderlineÓ[\]^_YNSHotSpot\NSCursorType€H €IW{8, -8}Ò78bÑ¢Ñ;ÓdŠeÿUNSRGBF0 0 1€Ò78hi¢i;_NSTextViewSharedData\{390, 1e+07}Z{373, 245}Ò78mù¦ùno¬­;[%NSTextViewVNSText\creditsFieldÔNOPrsS0€Q€V€€×VWXYZ[\\y_`a|€ € €R €€S_{{69, 310}, {380, 16}}Øklmnopqrs‚rwxy€€€U€T€Q€Ô|}~†€‰"AP€€\versionFieldÔNOP0S€€Œ€€XÜ‘’“”•–—¼˜™š›œžŸ ¡¢\¤¥¦_NSWindowStyleMask_NSWindowBackingYNSMinSize]NSWindowTitle]NSWindowClass\NSWindowRect\NSScreenRect\NSWindowViewYNSWTFlags[NSViewClass€‰€Z€[€Y€ˆ€Š€ px€‹€\_{{273, 279}, {531, 370}}XNSWindowÒªTView€2Ò>­L¥®rQÓ²€^€Q€ €n€~€5ÙVWXYZ[¿µ\\¸_`º»¼_ZNSEditable€ € €f €m€g€_ Ò>¿@¦ÀÁÂÃÄÅ€`€a€b€c€d€e€Òð€2_Apple PNG pasteboard type_{{12, 310}, {48, 48}}ÙÌÍmnÎÏpqÐÐÒÓÐÔxÕWNSScaleWNSStyleZNSAnimatesWNSAlign€U€h€lÓ×2ØÙÚ^NSResourceName€j€k€iWNSImage_NSApplicationIconÒ78Þߣßà;_NSCustomResource_%NSCustomResourceÒ78âã¤ãä[;[NSImageCell\%NSImageCellÒ78æç¥竬­;[NSImageViewÛdVWÍXéZêëìí\\Âñò`óôÂö[NSHScrollerXNSsFlags[NSVScroller]NSContentView€o€ € € €|€y€u€ €}Ò>øL£Âôò€ €u€y€5Ò>þL¡´€€5_{{1, 1}, {391, 245}}Ó[\ÿ_€s€IW{4, -5}Ò78¤¬­;ZNSClipViewØVW XZ  ÓÓÓ`XNSTargetYNSPercentXNSAction€n€n€n€v€x"?"¢£€w_{{392, 1}, {15, 245}}\_doScroller:Ò78¥«¬­;ZNSScrollerÚVW XZê  ÓÓÓ`ÿ!"ZNSCurValue€n€n"?€€n€z€x"?rC€{_{{-100, -100}, {87, 18}}_{{69, 55}, {408, 247}}Ò78&'¤'¬­;\NSScrollView×VWXYZ[\\+_`-.€ € € €…€€_{{224, 12}, {82, 32}}Ý12mno3456p7q8;²ÿ=>?@xAB_NSKeyEquivalent_NSAlternateImage^NSButtonFlags2_NSPeriodicInterval]NSButtonFlags_NSPeriodicDelay_NSAlternateContents€ƒ€U€U€€~ÿÿÿÿ†‚@ÿ€„È€‚ROKÒ€2Ò78GH¥HI¦[;\NSButtonCell]%NSButtonCellÒ78KL¥L«¬­;XNSButton_{{1, 9}, {531, 370}}Ò78O¬£¬­;_{{0, 0}, {1280, 1002}}Z{213, 129}_{3.40282e+38, 3.40282e+38}Ò78TU¢U;_NSWindowTemplateXdelegateÔNOP0YZ²€€Ž€€~Ò78]^£^²;_NSNibControlConnectorÒ>`i¨rÓ\²Q®´€Q€n€ €X€~€ €^€€‘Ò78k ¢ ;Ò>mi¨\\0\\\Ó€ € €X€€ € € €n€‘Ò>xi§rÓ0²®´€Q€n€X€€~€^€€‘Ò>‚i§ƒ„…†‡ˆ‰€•€–€—€˜€™€š€›€‘Q1Q5VWindow\File's OwnerQ2Q6Ò>’i €‘Ò>•i €‘Ò>˜i®\JGHIÓ²KQ®r0´€ €W€ €€P€n€~€€ €^€Q€X€€€‘Ò>©i®ª«¬­®¯°±²³´µQ·€ €¡€¢€£€¤€¥€¦€§€¨€©€ª€«€F€¬€‘.*,-);=(&'$Ò>ÇL €5Ò>Êi €‘Ò>Íi €‘Ò78ÐÑ¢Ñ;^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:<>@ACHUdfhjr†–©½ÆÏÛèñü5AJVdfhjlnprtvxˆŠŒŽ™œž ·ÄÆÈÐÙâí!*,.0249;S`it¨³µ·¼¾ÀÂÇÉäý9;=?@BD\‘£¶ÅÚèú%')+03<>GR_mvŠ¡ª±ÊÕòû-/135>E]fwy{}ƒ…‡‰’— ±³µ·¹»½¿ÁÃÌÛÝßáãåçéëô   +-/89;DEGPmoqsuwy{}ƒ…‡‰‹”±³µ·¹»½¿ÁÃÅÇÉËÍÏÑÓÕ×ÙÛÝßáãåçéòóõþÿ   Ò*stella-3.9.3/src/macosx/AboutBox.nib/info.nib0000644000175000001440000000076310250207077020405 0ustar stephenusers IBDocumentLocation 345 699 356 240 0 0 1280 1002 IBFramework Version 437.0 IBOldestOS 2 IBOpenObjects 20 IBSystem Version 8B15 stella-3.9.3/src/macosx/AboutBox.nib/objects.nib0000644000175000001440000000536410250207077021105 0ustar stephenusers typedstreamè„@„„„NSIBObjectDataà„„NSObject…’„„„NSCustomObject)”„@@„„„NSString”„+AboutBox†…†„i–„„„ NSTextField„„ NSControl)„„NSView)„„ NSResponder”’„œ’…™„ @@@@ffffffff„„„NSMutableArray„„NSArray”™’„„„ NSImageView›’ž™‚€ž………„„„ NSMutableSet„„NSSet”„I’„˜˜Apple PDF pasteboard type†’„˜˜1NeXT Encapsulated PostScript v1.2 pasteboard type†’„˜˜NeXT TIFF v4.0 pasteboard type†’„„„NSMutableString˜˜NSFilenamesPboardType†’„˜˜Apple PICT pasteboard type†’„˜˜Apple PNG pasteboard type†† 60000’ž’…’…’…„icc@„„„ NSImageCell)„„NSCellA”„ii‚þ‚„@@@@„„„NSCustomResource)”–„˜˜NSImage†„˜˜NSApplicationIcon††„„„NSFont”™$„[36c]þÿLucidaGrande„f „c¯¯¯†……„iii†¯†’™’„š’ž™‚€ž…………EH||’ž’…’…’…¦„„„NSTextFieldCell>„„ NSActionCell°©‚þ‚@ª„˜˜<>†„¶™$­þÿLucidaGrande®¯¯¯¯†……„i:…’…’·„c@@„„„NSColor”¯„@@@„˜˜System†„˜˜ controlColor†„¾¯„ffƒ?*ª«††„¾¯¶¿„˜˜controlTextColor†„¾¯·†††’…„:…†’„„„ NSScrollView✒ž™‚€ž„ ™’„„„ NSClipView:œ’Å™‚Àž„ ™’„„„NSTextViewTemplateÆ„„NSViewTemplate.œ’È™‚Àž………„¥¤ ’„˜˜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 type†††õ†õ’È’…’…’…’„˜˜ NSTextView†’…’„¾¯·†’„„„ NSDictionary”™’„˜˜NSBackgroundColor†’„¾¯¶¿„˜˜selectedTextBackgroundColor†Á†’„˜˜NSColor†’„¾¯¶¿„˜˜selectedTextColor†Ä††’Ä·†‚˜–€·uõ·†‚˜–€’…¯¯¯¯¯¯¯¯¯¯¯¯¯¯’…††………‡õ‡õ’Å’…’Ë’…’Ë„@@cccÛ„„„NSCursor”·û’…¯¯††’„„„ NSScrollerÓ›’Å™‚€ž…………ˆõõ’Å’…’…’…¦…’Å„ff:ƒ?"¢£„ _doScroller:¯¯†’„ç’Å™‚€ž…………œœWW’Å’…’…’…¦…’ÅÁƒ?rC¯¯††………E7˜÷˜÷’ž’…’È’…’æ’è’È’…’…„ffffi ‚„†’„„„NSButton›’ž™‚€ž…………à R R ’ž’…’…’…¦„„„ NSButtonCell?º©‚þ‚ª„˜˜OK†µ……³…’…’é„ ssii@@@@@È‚†‚@ÿ„˜˜†„«˜†…µ…†††……… rr’…’…’…’…†™‚€ž…………E6||’ž’…’…’…¦„¹©‚þ‚@ª„˜˜<>†µ……³…’…’™´½Â†’…¸…†ž–Åž–ž„„„NSWindowTemplateø”„ iiffffi@@@@@cr‚px„˜˜<>†„˜˜NSWindow†„«˜View†ž…„ffff꯷Ւ…¯·ƒÿîƒÿò•–éž–·ž–¢ž–ËÅ™–™„˜˜1†–Å„˜˜5†–ò„˜˜Window†–•„˜˜ File's Owner†–鄘˜NSButton†–¢„˜˜2†–Ë„˜˜6†’„¥¤†’„ ™’„„„NSNibOutletConnectorÏ„„NSNibConnector”¶•·„˜˜ appNameField††’„¶•Ë„˜˜ creditsField††’„¶•™„˜˜ versionField††’„¶ò•„˜˜delegate††’„„„NSNibControlConnector϶镄˜˜OK†††’…™„@ižÍ.Í*Í,Í-ÍÅ)Íé;Í =Í·(Í¢&Í™'ÍòÍ•ÍË$™>™’„˜˜IBCocoaFramework††stella-3.9.3/src/macosx/Preferences.h0000644000175000001440000000226012266336753017107 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Preferences.h 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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-3.9.3/src/macosx/OSystemMACOSX.hxx0000644000175000001440000000255712266336753017555 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: OSystemMACOSX.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: OSystemMACOSX.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class OSystemMACOSX : public OSystem { public: /** Create a new MACOSX-specific operating system object */ OSystemMACOSX(); /** Destructor */ virtual ~OSystemMACOSX(); /** Returns the default paths for the snapshot directory. */ string defaultSnapSaveDir(); string defaultSnapLoadDir(); }; #endif stella-3.9.3/src/macosx/Cart.icns0000644000175000001440000010252510404601104016222 0ustar stephenusersicns…Uit32EEÿÿà†ß‚ÞÝ€Ü ÛÚÚÙÙØØ×ÖÖ€ÕÔÓÓÒÑÑÐÎÍÊÈÅÁ¿¾¹¶´¹¾»~Äàá…àßàßàß‚ÞÝÝÜÜÛÚÚ€ÙØ×ÖÖÕÕÔÔÓÓÒÑÐÏÎÊÇÅ¿½¹µ²¯¬µ»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©–è‡çæåå€äã€â$áààÞÝÜÛØÒÎÆ¼³§œ’ˆxsnljjklnqsvzƒŸ¾¾k¨éšèƒçæåå€äã€âáàßßÝÜÙÕÏÉÀ¶¬¡—ކzwt€s 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^·Õèïðð€ïîí€ìëëêêééèèçææåääãâ¤ö„õ&ôóñíêçâÛÑŸ ™®·°…@Z¶³¿³f¥»´È¼Šˆƒ}yj‡Æâïñ€ðïî€íììëëêêééèççæååã¤÷öõ&óíã×ÐÉû¬›¡¬µ¸¨l+0§¹³Åzc³¹´È·Œ†g´Õëð‚ñ€ð ïïîííììëëê€éèççæå夂÷ö)õôíÞÉ´µ¤¡¤¨°´¸³…I'{½°Â Ywº·´Æ½‘’‰…~{Áßïòò‚ñðïîííììëëê€éèççæå¤„÷öö÷÷‡ö'õñãÇ ¦©«®®³·´”U(.!O¶³¹¶jXƒ½·µÁÉ•”Š{Êæñòñðïîîíììëëê€éèççæ¤Š÷…ö&óèÏ«™­ª¬±µ«ŠQ.0859¹²¾…__ˆ½¶¶¹Ï£””x©Ñéƒòñðï€îììëëê€éèçç¤öŒ÷‚ö&ñÞ½—´®­£‹fB4Z°°²¸{npct¹µ·³Çɤ–™}²Øîó†òññðï€îíìëëê€éè¤÷øø÷ñàÀ_Va_dfe^XWSLPŸµ®ºŽipsa]·´€¶Òµšƒ´Úî€ó…òññðï€îíììëê€é¤öƒø÷÷øˆ÷&ôë×À{s{pidb\YYO„¸­¹¨kjnu\?­µ´·´Áͧ†µÚî‚ó…òñ€ðïï€îí€ìêéé¤öˆø†÷&öóëÛÁŠ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;’Éâïóƒô…óòñððï¤ñúùŠø÷õðæÖȳ·ÙêôöóèÒ²t¶™JCGFFG>šÓê†ô„óòñðð¤ðúù‹ø÷÷öóíåáäìóööõòçѰzkAGG€FGAÂæóõ…ô…óò€ñð¤ïƒúùùúú‹ù‹ø÷÷öôóóõö€÷õñèÒ¹c@GFB_Ìçó€õ…ô„óòòññ¤ï‰ú‹ù‹ø‡÷öóèÕ¼eB€FH<®Õëô‚õ…ôƒóòòñ¤î‹úù‰ø†÷ öóêØ¾k?GFAkÆäñ…õ…ô‚óòò¤îŽúŒù‰ø…÷ öôìÚÂz>H>­×íˆõ„ô‚óò¤î‘ú‹ùŠø„÷ õíÜÄ;rÊåóö…õ…ôó¤íû’ú‹ùŠøƒ÷õîßÍžÆÞîõƒö†õƒô€ó¤íû“ú‰ù‹ø÷õïèâæìó…ö†õ„ôó¤íƒûúúûú‹ù‰ø÷öôòóõö÷†ö†õƒô¤í‰ûúŠùŠø†÷‡ö…õ‚ô¤íŒûŽúŠù‰ø‡÷‡ö…õ€ô¤íûŽúŠù‰ø†÷‡ö…õó¤í’ûú‹ùˆø‡÷…ö„õô¤í”ûŽúˆùŠø†÷†ö‚õó¤íüü”ûŽú‰ùˆø‡÷…öõó¤í‚ü€ûüûú‰ùˆø†÷†öõõò¤íˆüûŽú‡ù‰ø†÷†öò¤îŠüûúûŒúˆùˆø…÷…öñ¤îü‘û‹úˆùˆø‡÷‚öð¤îüûŒú‡ùˆø†÷öð¤î…üýüý€üýüýüý€üòÓÓñ€ûüûü…û„úŒdúúÒddÑ€ùú‚ùøùƒø÷øøƒ÷ö÷î¤ï‘ýóŽeƒè‰ü„ûdûûÓddÒ‡ú‡ù†ø÷÷î¤ï‘ý Žee¢¶—oÓüüÀ««†ü‚ûdûûÓddÓ‰ú‡ù†øí¤ïýÞee¬€ýüòüüe‰ü ûûdûûÓddÓûû‰ú‡ù„øí¤ïþþŽýÔee¢ƒý¬oeo«€üÀƒee—Ý€üdûûÓddÓûûÉ—nddŒÒ„ú†ùƒøì¤ï‚þ‹ýóoee¬óýŽeüü«eeƒoeoèüüeûûÓddÓûûdƒnddæ„ú‡ùøë¤ïˆþ†ýÀ€eoÀý#ŽeŽýýüÓee¶üòee«üüeüûÓddÓûûÓñûûñxd´…ú‡ù€øë¤ð‹þ„ýÊo€e˜óýýŽeŽ€ý¬eeèüüeƒüüeüüÓddÓ„ûdµ‡ú†ùøøë¤ðþƒýó¢€e˜ýýŽeŽ€ýŽee€oeeüüeüüÓeeÓûûñµƒdµûû‡ú†ùë¤ðþƒýÔ€eéýŽeŽ€ýŽeeŽŽüüeüüÓeeÓûñƒdd µxdµû†ú…ùê¤ð“þ€ýŽeeÔýŽeŽ€ý¢eeé€ýüeüüÓeeÓüÀed¿ûûdµ‚û†ú„ùê¤ðþêê€þóyeeéýŽey€ýÔee¢‚ýüüeüüÓeeÓü¶eeÊûûƒdµ„û†ú‚ùë¤ðþ/Õf„··zfe¬ýý·ee˜¬ýý¢ee„··¢yýýeüüÓeeÓüÊeey¶yddƒÓ„û†úùë¤ðþô¢p€fp·þþýóŽ€e€ý·oeyýýŽeüüÓeeÓüü¡€e¶¶ddµ…û‡úùùë¤ð“þßÕß„þéÔé‚ý€Ôó„ý…üèÓòüüÝÓç‡û†úùë¤ðŸþý‹üˆû†úë¤ð¡þýŠü‰û„úë¤ðÿ£þýŠüˆûƒúë¤ðÿ¢þýŠü‡û‚úì¤ð„ÿþÿŸþŽýŠü‡ûúìÿÿÿÿÿÿÿÿ€ÿÿ‚à…ß‚ÞÝ€Ü ÛÚÚÙÙØØ×ÖÖ€ÕÔÓÓÒÑÑÐÎÍÊÈÅÁ¿¾¹¶´¹¾»~ăàßàßàßààß‚ÞÝÜÝÝÜ€ÚØÙÙ××ÖÖÕÕ€ÔÓÒÑÐÏÍÊÈÅ¿½¹¶³¯­µ»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©—èçè„çæåå€äã€â$áààÞÝÜÛØÒÎÆ¼³§œ’ˆxsnljjklnqsvzƒŸ¾¾k¨éšèƒçæåå€äã€âáàßßÝÜÙÕÏÉÀ¶¬¡—ކzwt€s ttvy|~„‰¤»k§ƒé—èçèç€æåå€äããââáàßÞÜÚ×ÑÊú°§œ”‡ƒ~|€} €‚„‡‰Œ‘¹b¦…éèé”èçèçæå€äããââáßÞÝÛ×ÓÍžµ«¤œ•‘Љ‰ˆ‚‰ ŠŒŽ‘”——¢¿¦Œê’é€èçæåä€ãáàÞÜØÔÐɺ²ª¥Ÿ›—•€–€• –˜——››­¶¥ê’éèè€ç€æååäããâáßÝÚÖÑÍÆ¿º³­©¦£¢¡€¢ ¡¡  ¡  ¡¡¢£ÀH¤‘ê’é€è,ççææååääââàÞÝÙÕÐÌÆÁ¼¸³±°­®­®¯®¯¯¬¬«ª¨©§§¨¦¦¹¤¤€ë‘êé€èçç€æååäãâàÞÛØÔÐÌÇÄÀ½»º‚¹ºº¹¸¶µ³²°¯®¬¬«®¼¤ƒë€êëë‹êéèç€æååããáàÞÜØÕÑÎÌÈÆÄÃÂÃÂà ÂÀÀ¾½»¸¶µ²±¯±»¤…ìëììŒëê€éèèççææääãâßßÜØÖÔÓÏÍÌËËÊËÊÊÉÇÆÄÁÀ¾»º·´³·¤‹ìŒëê€éèèæååããââáßßÜÛØÖÔÔÓÓÒÑÑÐ ÏÐÎÌÊÈÄÄ¿½º¶¶¤Žì‹ëŒê€éçâÛÖ€Ó€Õ ÔØÚÛÛÚÚØØ×Ö×ÖÖ€Õ ÔÔÒÐÎÌÈÇÄÁ¾º¸¤ííŽì‹ë‹êéèãׯ»´´·¹¹»¾ÅÐÚ€ÝÜ€ÛÚ€ÙØ××ÖÖÔÒÐÍÊÈÅ¿»¤îíŠì‰ë)êæÙ‘zˆ|‚‘ހУ½ÐÜààßßÞÞÜÜÛÛÚÙÙØ×ÖÖÓÒÎÌÉÆÂÀ¤„îííîî‰í‹ì‡ë)éßÈ¥j—~y}—rv¡`оÖàâááàßÞÞÝÝÜÛÚÙÙØ×ÖÔÒÏÍÉÆÃ¤Šî‹í‰ì„ë*êäÒ¶k“‡vv’ƒrŒ53¨ÇÛââáààßßÞÝÝÜÛÛÚÚÙØÖÕÒÏÍÊǤŒî‹í‰ìëêçÙ¾†}švw€‘p~›N//i·ÑàããââáààßÞÞÝ€ÜÚÚÙ×ÕÒÏÍʤðï‹î‰í-ììêàÊ¥hœwz™vv—o.56.šÃØãåäããâáààßÞÞÝÜÛÚÚÙ×ÕÒÐΤðïŠîˆí,ìæÓ¸j‹…suŽŠo†”>2663@²ÍÞäåäãââááàßßÞÝÜÛÛÚÙ×ÕÒФƒð€ïðð‰ï‰î…íìéÛ¿ˆtrv~”pzœ^/€67-}ÁØãååäããâááàßÞÞÝÜÜÛÚÙ×ÕÒ¤Šð‰ï‰îƒíëáË¥h˜{vt—|r’‚1465=«Õâ€åäããâááàßßÞÝÝÜÛÚÙ×Õ¤ðˆï‰î€íìæÔ¶iŒŒqu‡†l~•G1‚60c¿ØäæååääããâááàßßÞÝÜÜÛÚÚפòòñˆð‰ïíéÛÀ…u•rvx‘nt•k/‚6 7-¨Êßæèçææå€ä ãââáàßßÞÝÝÛÛÚ¤‚òŒñˆð‡ïëáÈ¥d›tsŒzq…Š:36 7/t¿Ùåçèèçææå€ä ãâááààßÞÝÜÜÛ¤„òññòòˆñ‰ðƒïíãαa‹‘pt„Šmu™W/ƒ67²Ðäéé€èçææå€ä ãââáààßÞÝÝܤŠòˆñðñƒðïìåÒ¹vx”rru’pq†„9467+}ÄÝèêëé€èçææå€ä ãââááàßßÝݤ‹ô‡ó‰òññîçÕ¼wo}qrp‰{ow£a>:5€64C¹×æìë€êéèèçææåääãâááàßÞ¤ôˆó†òñîåÔ¼tnwcnszˆju‡‘GHA€67)žÊâìíí€ìë€êéèèçææåääãâááàߤõõôõŒôˆó‚òñìãѺvjw^bvrŠgpr›qCIH=660Z¿Ùéíîíìë€ê éèèçææååäãââáःõ€ôõ‰ô‡óòñïéÝÉ®pkv^Puq‚sawu“XFIIE:5/®Ñæîíìë€êéèèç€æåäãââᤉõ‰ô„ó%òñìãÔÀšdpt_>lvwƒTqtx†PLHIIB0tÄàìðïïîîíìë€ê éèèçææåääããᤋõ‰ô&óóòñîéâ×ǵxbtu\+Qwr‡\Uyq~PPLHIF>¶Õèïðð€ïîí€ìëëêêééèèçææåääãã¤ö„õ&ôóñíêçâÛÑĶbhqnS"6tozu7fwqzSSOII?}Æâïñ€ðïî€íììëëêêééèççæååã¤÷öõ&óíã×ÐÉù¢zefori@jtpI5rvq‚xVVRNIA³Õëð‚ñ€ð ïïîííììëëê€éèççæå夂÷ö)õôíÞÉ¢ž„ykdimqoP(Jwm}h/Ewtr€{ZYUQHcÁßïòò‚ñðïîîíììëëê€éèççæå¤„÷öö÷÷‡ö'õñãdž`dgikmqp[2 +souu<-Nytr}‚^[XUG•Êæñòñðïîîíììëëê€éèççæ¤Š÷…ö&óèϤ^jijmqkW- ato{S44Sytsu…f^ZVI§Ñé„ò€ñðï€îììëëê€éèçç¤öŒ÷‚ö&ñÞ»bonleU;"(*&Mrkyh@@:Pvttq‡rb^[I¬Õë…ò€ñðï€îíìëëê€éèç¤÷€ö'ïÚp>G;/"$/40+("5nlovLDD9Gtrtq€da^O²Øîó†òññðï€îíìëëê€éè¤÷øø÷ñà¿L.:99€853/./cpkvZ@FG97spsts‹qcaX´Úî€ó…òññðï€îíììëê€é¤öƒø÷÷øˆ÷ ôëØÀdBLE=76/Rqjsl??BI8$mqqtr|„fc[µÚî‚ó…òñ€ðïï€îí€ìêéé¤öˆø†÷&öóëÛÁ?HF>9563±¯octpposvj*ZÁÜìó€ô…óòñðð€îí¤ó‰ù‹ø„÷öòèÓ¹[6659&­ÍѾkkropptL'ÅÞíóô…ó€òñððïîî¤òŒù‹ø‚÷öóéØÀ|52;tÉãèØºlorosd.#'ˆÇßíó‚ô…óòòñððïî¤ñŽù‹ø÷öôìÞɦ\.+¼ÝîòêÕ¶_psqE"€'Éãïóƒô…óòñððï¤ñúùŠø÷õðæÖȰ¶ÙêôöóèÒ±Pq_(%&''&•Óê†ô„óòñðð¤ð€úù‹ø÷÷öóíåáäìóööõòçѰX>#&&€'%%Áæóõ…ô…óò€ñð¤ïƒúùùúú‹ù‹ø÷÷öôóóõö€÷õñèÒ¹M'( RÌçó€õ…ô„óòòññ¤ï‰ú‹ù‹ø‡÷öóèÕ¼Q ' ­Õëô‚õ…ôƒóòòñ¤î‹úŒùŠø†÷ öóêØ¾['' ^Æäñ…õ…ô‚óòò¤îú‹ù‰ø…÷ öôìÚÂm&"«×íõö†õ„ô‚óò¤î‘ú‹ùŠø„÷ õíÜÄvdÊåóö…õ…ôó¤íû’ú‹ù‰ø„÷õîßÍ™ÅÞîõƒö…õ„ô€ó¤íû’ú‹ù‰ø‚÷õïèâæìó†ö…õ„ôó¤íƒûúúûú‹ù‰ø÷öôòóõö÷†ö†õƒô¤í‰ûúŠùŠø†÷‡ö…õ‚ô¤íŒûŽúŠùŠø†÷‡ö…õ€ô¤íûŽú‰ù‰ø‡÷‡ö…õó¤í’ûŽú‰ùˆøˆ÷…ö„õô¤í”ûŽúˆù‰øˆ÷…ö‚õó¤íüü”ûŽú‰ùˆø‡÷…öõó¤í‚ü”ûú‰ùˆø†÷†öõõò¤íˆüûúˆù‰ø†÷†öò¤îŠüûú‰ùˆø…÷…öñ¤îü‘û‹úˆùˆø‡÷‚öð¤îüû‹úˆùˆø†÷öð¤îüýüýüýýüüýüýü òÓÓñüûûüüûüûü€ûúûúŒdúúÒddÑúùùúùùúúù‰ø÷ø€÷ööî¤ï‘ýóŽeƒè‰ü„ûdûûÓddÓ‡ú‡ù†ø÷÷î¤ï‘ý Žee¢¶—oÓüüÀ««†ü‚ûdûûÓddÓ‰ú‡ù†øí¤ïýÞee¬€ýüóüüe‰ü ûûdûûÓddÓûû‰ú†ù…øí¤ïþþŽýÔee¢ƒý¬oeo«€üÀƒee—Ý€üdûûÓddÓûûÉ—nddŒÒƒú‡ùƒøì¤ï‚þ‹ýóoee¬óýŽeüü«eeƒoeoèüüeûûÓddÓûûdƒnddæ„ú‡ùøë¤ïˆþ†ýÀ€eoÀý#ŽeŽýýüÓee¶üòee«üüeüûÓddÓûûÓñûûñxd´…ú‡ù€øë¤ð‹þ„ýÊo€e˜óýýŽeŽ€ý¬eeèüüeƒüüeüüÓddÓ„ûdµ‡ú†ùøøë¤ðþƒýó¢€e˜ýýŽeŽ€ýŽee€oeeüüeüüÓeeÓûûñµƒdµûû‡ú†ùë¤ðþ‚ýÔ€eéýŽeŽ€ýŽeeŽŽüüeüüÓeeÓüñƒdd µxdµû†ú…ùê¤ð“þ€ýŽeeÔýŽeŽ€ý¢eeé€ýüeüüÓeeÓüÀed¿ûûdµ‚û†ú„ùê¤ðþêê€þóyeeéýŽey€ýÔee¢‚ýüüeüüÓeeÓü¶eeÊûûƒdµ„û†ú‚ùë¤ðþ/Õf„··zfe¬ýý·ee˜¬ýý¢ee„··¢yýýeüüÓeeÓüÊeey¶yddƒÓ„û†úùë¤ðþô¢p€fp·þþýóŽ€e€ý·oeyýýŽeüüÓeeÓüü¡€e¶µddµ…û‡úùùë¤ð“þßÕß„þéÔé‚ý€Ôó„ý…üèÓòüüÝÓç‡û†úùë¤ðŸþ‘ýŠüˆû†úë¤ð¡þý‹üˆû„úë¤ðÿÿ¡þýŠüˆûƒúë¤ðÿ¢þýŠü‡û‚úì¤ð„ÿþÿŸþŽýŠü‡ûúìÿÿÿÿÿÿÿÿ€ÿÿà†ß‚ÞÝ€Ü ÛÚÚÙÙØØ×ÖÖ€ÕÔÓÓÒÑÑÐÎÍÊÈÅÁ¿¾¹¶´¹¾»~Ćàáßàà€ßÞ ÜÜÝÜÛÛÚØÙÙ×€ÖÕÕÔ€ÓÒÑÑÏÎÊÇÅÁ¿½¹µ²¯¬µ»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©—è†çæåå€äã€â$áààÞÝÜÛØÒÎÆ¼³§œ’ˆxsnljjklnqsvzƒŸ¾¾k¨éèé™è‚çæåå€äã€âáàßßÝÜÙÕÏÉÀ¶¬¡—ކzwt€s ttvy|~„‰¤»k§ƒé—èƒç€æ€åääã€âáàßÞÜÚ×ÑÊú°§œ”‡ƒ~|€} €‚„‡‰Œ‘¹b¦…éèé“èçèççæå€äããââáßÞÝÛ×ÓÍžµ«¤œ•‘Љ‰ˆ‚‰ ŠŒŽ‘”——¢¿¦Šê”é€èçæåä€ãáàÞÜØÔÐɺ²ª¥Ÿ›—•€–€• –˜——››­¶¥êéê’éèè€ç€æååääãâáßÝÚÖÑÍÆ¿¹³­©¦¢¢¡€¢ ¡¡  ¡  ¡¡¢£ÀH¤ëê’é€è,ççææååääââàÞÝÙÕÐÌÆÁ¼¸³±°­®­®¯®¯¯¬¬«ª¨©§§¨¦¦¹¤¤€ëê‘é€èçç€æååäãáàÞÛØÔÐÌÇÄÀ½»º‚¹ºº¹¸¶µ³²°¯®¬¬«®¼¤ƒë€êëë‹êéèç€æååããáàÞÜØÕÑÎÌÈÆÄÃÂÃÂà ÂÀÀ¾½»¸¶µ²±¯±»¤…ìëììëŽê€éèèççææääãâßÞÜØÖÔÒÏÍÌËËÊËÊÊÉÇÆÄÁÀ¾»º·´³·¤‹ìŒëêéèæååããââáßßÜÛØ×ÔÔÓÓÒÑуРÎÌÊÈÄÄ¿½º¶¶¤ìŒëŒê€éçâÛÖ€Ó€ÕÔØ€ÛÚÚØØ×Ö×ÖÖ€Õ ÔÔÒÐÎÌÈÇÄÁ¾º¸¤ííŽì‹ë‹êéèã×Ŷ±³´¹¹»¾ÅÐÚ€ÝÜ€ÛÚ€ÙØ××ÖÖÔÒÐÍÊÈÅ¿»¤îíŠì‰ë)êæÙÂh*(9XP:v½ÐÜààßßÞÞÝÜÛÛÚÙÙØ×ÖÖÓÒÎÌÉÆÂÀ¤ƒî€íîîŠíŠì‡ë)éßÈ›‚¾ÖàâááàßÞÞÝÝÜÛÚÙÙØØÖÔÒÏÍÉÆÃ¤Šî‹í‰ì„ë*êäÒ´  ¦ÇÛââáààßßÞÝÝÜÛÛÚÚÙØÖÕÒÏÍÊǤŒî‹í‰ìë+êçÙ¾_T·ÑàããââáààßÞÞÝÜÜÛÚÚÙ×ÕÒÏÍʤðï‹îˆí€ì êàÊš €“ÃØãääããâáààßÞÞÝÜÛÛÚÙ×ÕÒÐΤðïŠîˆíìæÓ· ±ÍÞäåäãââááàßßÞÝÜÛÛÚÙ×ÕÒФƒð€ïðð‰ï‰î…íìéÛ¿cƒnÁØãååäããâááàßßÞÝÜÜÛÚÙ×ÕÒ¤ŠðŠïˆîƒí ëáË› „§Õâ€åäããâááàßßÞÝÝÜÛÚÙ×Õ¤ðˆï‰î€íìæÔµ „M¾ØäæååääããâááàßßÞÝÜÜÛÚÚפòòŒñ‰ð‰ïíéÛÀ\ „ ¥Êßæèçææå€ä ãââáàßßÞÝÜÛÛÚ¤òñ‰ð†ï ëáÈš  … g¿Ùåçèèçææå€ä ãâááààßÞÝÜÜÛ¤„òññòòˆñ‰ðƒïíãά  „²Ðäéé€èçææå€ä ãââáààßÞÝÝܤ€òóòóòòó‚òƒñ òññòððñððñ‚ðïìåÓ¸1 …tÃÝèêêéèèéçææååääãââáààßÞÞݤ‹ô‡óŠòñîçÕ¼E‚„#¹×æìë€êéèèçææåäããâááàßÞ¤ôˆó†òñîåÔ»A‚ …›Êâìíí€ìë€êéèèçææåääãâááàߤõõôõŒôˆó‚òñìãѹDƒ„E¿Ùéíîíìë€ê éèèçææååäãââáःõô‡óòñïéÝÉ©0ƒ€„­Ñæîíìë€êéèèç€æåäãââᤉõ‰ô„óòñìãÔÀ‰„„ eÄàìðïïîîíìë€ê éèèçææåääããᤋõ‰ô óóòñîéâ×DzG…‰¶Õèïðð€ïîí€ìëëêêééèèçææåääãâ¤ö„õ ôóñíêçâÛÑIJm “lÆâïñ€ðïî€íììëëêêééèççæååã¤÷öõ óíã×ÐÉ·“G‚²Õëð‚ñ€ð ïïîííììëëê€éèççæå夂÷ö õôíÞLJ{L8 —@Áßïòò‚ñðïîííììëëê€éèççæå¤„÷öö÷÷‡öõñãÈ\†’ˆÊæñòñðïîîíììëëê€éèççæ¤Š÷…öóèϘ‡€£Ñéƒòñðï€îììëëê€éèçç¤öŒ÷‚öñÞ¶ „€«Õë…ò€ñðï€îíìëëê€éèç¤÷€öïÚU…ƒ±Øîó†òññðï€îíìëëê€éè¤÷øø÷ñà¾6†€´Úî€ó…òññðï€îíììëê€é¤öƒø÷÷øˆ÷ôëØ¿A†…†´Úî‚ó…òñ€ðïï€îí€ìêéé¤öˆø†÷öóëÛÁo…±×íƒó…òññððïï€îí€ìëê¤õŒø„÷ôíßÉ£%–›Òéò…óƒòññððïï€îí€ìë¤öø„÷ õðåÓ¾P “_Äâð‡ó‚ò€ñðïï€îí€ì¤õø‚÷ öóêÝÌ´¯¯±³z‡ … °Óéòô†ó‚òñðï€îíìì¤ôùŽø÷ öõïèâÞÝÜÖÆ  †x…@¾Ùëòôô…ó‚òñðï€îíì¤ô‚ù€øùù‹ø€÷öõó€òîäÏ­ „8±¯Y†MÁÜìó€ô…óòñðð€îí¤ó‰ù‹ø„÷öòèÓ·5‚ ­ÍѾ<†zÅÞíóô…ó€òñððïîî¤òŒù‹ø‚÷öóéØÀgtÉãèØ»6ƒÇßíó‚ô…óòòñððïî¤ñŽù‹ø÷öôìÞÉŸ<½ÝîòêÕ´€†Éãïóƒô…óòñððï¤ñúùŠø÷õðæÖÈ­´ÙêôöóèÒ°€Óê†ô„óòñðð¤ð€úù‹ø÷÷öóíåáäìóööõòçѰ €Àæóõ…ô…óò€ñð¤ïƒúùùúú‹ù‹ø÷÷öôóóõö€÷õñèÒ¸3?Ìçó€õ…ô„óòòññ¤ï‰ú‹ù‹ø‡÷öóèÕ»9€¬Õëô‚õ„ô„óòòñ¤î‹ú‹ù‹ø†÷ öóêØ½FNÆäñ…õ…ô‚óòò¤îú‹ù‰ø…÷ öôìÚÂ[©×íõö†õ„ô‚óò¤î‘ú‹ùŠø„÷ õíÜÄfUÊåóö…õ…ôó¤íû’ú‹ù‰ø„÷õîßÍ‘ÄÞîõ‚ö†õ„ô€ó¤íû’úŠù‹ø÷õïèâæìó…ö†õ„ôó¤íƒûúúûú‹ù‰ø÷öôòóõö÷†ö†õƒô¤í‰ûúŠùŠø†÷‡ö…õ‚ô¤íŒûŽúŠù‰ø‡÷‡ö…õ€ô¤íûŽúŠùˆø‡÷‡ö„õôó¤í’ûŽúŠù‡øˆ÷…ö„õô¤í”ûŽúˆù‰ø‡÷†ö‚õó¤í€ü“ûŽú‰ùˆø‡÷…öõó¤í‚ü”ûú‰ùˆø†÷†öõõò¤íˆüûúˆù‰ø†÷†öò¤îŠüûŽúˆù‡ø‡÷„öñ¤îüûúû‹úˆùˆø‡÷‚öð¤îüûú‡ùˆø†÷öð¤îƒüý„üý„üòÓÓñ€ûüûüûü€ûú ûûúŒdŒúúÒddуùúùùøùù‚øùùø÷ø÷÷ø÷ööî¤ï‘ýóŽeƒè‰ü„ûdûûÓddÒ‡ú‡ù†ø÷÷î¤ï‘ý Žee¢¶—oÓüüÀ««†ü‚ûdûûÓddÓ‰ú‡ù†øí¤ïýÞee¬€ýüòüüe‰ü ûûdûûÓddÓûû‰ú†ù…øí¤ïþþŽýÔee¢ƒý¬oeo«€üÀƒee—Ý€üdûûÓddÓûûÉ—nddŒÒ„ú†ùƒøì¤ï‚þ‹ýóoee¬óýŽeüü«eeƒoeoèüüeûûÓddÓûûdƒnddæƒúˆùøë¤ïˆþ†ýÀ€eoÀý#ŽeŽýýüÓee¶üòee«üüeüûÓddÓûûÓñûûñxd´…ú‡ù€øë¤ð‹þ„ýÊo€e˜óýýŽeŽ€ý¬eeèüüeƒüüeüüÓddÓ„ûdµ‡ú†ùøøë¤ðþƒýó¢€e˜ýýŽeŽ€ýŽee€oeeüüeüüÓeeÓûûñµƒdµûû‡ú†ùë¤ðþ‚ýÔ€eéýŽeŽ€ýŽeeŽŽüüeüüÓeeÓûñƒdd µxdµû†ú…ùê¤ð“þ€ýŽeeÔýŽeŽ€ý¢eeé€ýüeüüÓeeÓüÀed¿ûûdµ‚û†ú„ùê¤ðþêê€þóyeeéýŽey€ýÔee¢‚ýüüeüüÓeeÓü¶eeÊûûƒdµ„û†ú‚ùë¤ðþ/Õf„··zfe¬ýý·ee˜¬ýý¢ee„··¢yýýeüüÓeeÓüÊeey¶xddƒÓ„û†úùë¤ðþô¢p€fp·þþýóŽ€e€ý·oeyýýŽeüüÓeeÓüü¡€e¶µddµ…û‡úùùë¤ð“þßÕß„þéÔé‚ý€Ôó„ý…üèÓòüüÝÓç‡û†úùë¤ðŸþý‹üˆû†úë¤ð¡þý‹üˆû„úë¤ðÿ£þýŠüˆûƒúë¤ðÿ¢þýŠü‡û‚úì¤ð„ÿþÿŸþŽýŠü‡ûúìÿÿÿÿÿÿÿÿ€t8mk@    ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûì´E   ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÇ9  ,ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿún  %6ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿû|  *>ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùY .EÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùZ 1Iÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿü[ 3KÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýZ 3LÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýZ 3LÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýZ 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý[ 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý[ 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý[ 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý\ 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý\ 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý\ 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý\ 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý\ 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý\ 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý\ 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý[ 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý[ 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý[ 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý[ 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýZ 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýZ 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýZ 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûZ 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùY 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùG 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿñ'3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÅ$ 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùD 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ' 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÜ03Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿù7# 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ>( 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿC, 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿG/3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿI13MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJ23MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿK33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿL33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿL33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿL33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿL33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33LÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿL33LÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿL33KÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿK31IÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿI1.EÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿE. *>ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ>*  %6I[itz~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~zti[I6%  ,;IU]befffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb]UI;,   ,6>EIKLLMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLKIE>6,  %*.133333333333333333333333333333333333333333333333333333333333333333333333333333331.*%    stella-3.9.3/src/macosx/SDLMain.m0000644000175000001440000003112711361062110016060 0ustar stephenusers/* SDLMain.m - main entry point for our Cocoa-ized SDL app Initial Version: Darrell Walisser Non-NIB-Code & other changes: Max Horn Feel free to customize this file to suit your needs */ /* $Id: SDLMain.m 2007 2010-04-13 12:32:08Z stephena $ */ #import "SDL.h" #import "SDLMain.h" #import "Preferences.h" #import /* for MAXPATHLEN */ #import #define SDL_main stellaMain extern int stellaMain(int argc, char* argv[]); void macOpenConsole(char *romname); /* For some reaon, Apple removed setAppleMenu from the headers in 10.4, but the method still is there and works. To avoid warnings, we declare it ourselves here. */ @interface NSApplication(SDL_Missing_Methods) - (void)setAppleMenu:(NSMenu *)menu; @end /* Use this flag to determine whether we use SDLMain.nib or not */ #define SDL_USE_NIB_FILE 1 /* Use this flag to determine whether we use CPS (docking) or not */ #define SDL_USE_CPS 1 #ifdef SDL_USE_CPS /* Portions of CPS.h */ typedef struct CPSProcessSerNum { UInt32 lo; UInt32 hi; } CPSProcessSerNum; extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); #endif /* SDL_USE_CPS */ static int gArgc; static char **gArgv; static BOOL gFinderLaunch; static BOOL gCalledAppMainline = FALSE; int fileToLoad = FALSE; char parentdir[MAXPATHLEN]; // -------------------------------------------------------------------------------- static NSString *getApplicationName(void) { const NSDictionary *dict; NSString *appName = 0; /* Determine the application name */ dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); if (dict) appName = [dict objectForKey: @"CFBundleName"]; if (![appName length]) appName = [[NSProcessInfo processInfo] processName]; return appName; } #if SDL_USE_NIB_FILE // -------------------------------------------------------------------------------- /* A helper category for NSString */ @interface NSString (ReplaceSubString) - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; @end #endif // -------------------------------------------------------------------------------- @interface NSApplication (SDLApplication) @end // -------------------------------------------------------------------------------- @implementation NSApplication (SDLApplication) /* Invoked from the Quit menu item */ - (void)terminate:(id)sender { /* Post a SDL_QUIT event */ SDL_Event event; event.type = SDL_QUIT; SDL_PushEvent(&event); } @end /* 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); } } #if SDL_USE_NIB_FILE // -------------------------------------------------------------------------------- /* Fix menu to contain the real app name instead of "SDL App" */ - (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName { NSRange aRange; NSEnumerator *enumerator; NSMenuItem *menuItem; aRange = [[aMenu title] rangeOfString:@"SDL App"]; if (aRange.length != 0) [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; enumerator = [[aMenu itemArray] objectEnumerator]; while ((menuItem = [enumerator nextObject])) { aRange = [[menuItem title] rangeOfString:@"SDL App"]; if (aRange.length != 0) [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; if ([menuItem hasSubmenu]) [self fixMenu:[menuItem submenu] withAppName:appName]; } } #else // -------------------------------------------------------------------------------- static void setApplicationMenu(void) { /* warning: this code is very odd */ NSMenu *appleMenu; NSMenuItem *menuItem; NSString *title; NSString *appName; appName = getApplicationName(); appleMenu = [[NSMenu alloc] initWithTitle:@""]; /* Add menu items */ title = [@"About " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Hide " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Quit " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; /* Put menu into the menubar */ menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; [menuItem setSubmenu:appleMenu]; [[NSApp mainMenu] addItem:menuItem]; /* Tell the application object that this is now the application menu */ [NSApp setAppleMenu:appleMenu]; /* Finally give up our references to the objects */ [appleMenu release]; [menuItem release]; } // -------------------------------------------------------------------------------- /* Create a window menu */ static void setupWindowMenu(void) { NSMenu *windowMenu; NSMenuItem *windowMenuItem; NSMenuItem *menuItem; windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; /* "Minimize" item */ menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; [windowMenu addItem:menuItem]; [menuItem release]; /* Put menu into the menubar */ windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; [windowMenuItem setSubmenu:windowMenu]; [[NSApp mainMenu] addItem:windowMenuItem]; /* Tell the application object that this is now the window menu */ [NSApp setWindowsMenu:windowMenu]; /* Finally give up our references to the objects */ [windowMenu release]; [windowMenuItem release]; } // -------------------------------------------------------------------------------- /* Replacement for NSApplicationMain */ static void CustomApplicationMain (int argc, char **argv) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDLMain *sdlMain; /* Ensure the application object is initialised */ [NSApplication sharedApplication]; #ifdef SDL_USE_CPS { CPSProcessSerNum PSN; /* Tell the dock about us */ if (!CPSGetCurrentProcess(&PSN)) if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) if (!CPSSetFrontProcess(&PSN)) [NSApplication sharedApplication]; } #endif /* SDL_USE_CPS */ /* Set up the menubar */ [NSApp setMainMenu:[[NSMenu alloc] init]]; setApplicationMenu(); setupWindowMenu(); /* Create SDLMain and make it the app delegate */ sdlMain = [[SDLMain alloc] init]; [NSApp setDelegate:sdlMain]; /* Start the main event loop */ [NSApp run]; [sdlMain release]; [pool release]; } #endif // -------------------------------------------------------------------------------- /* * 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]; #if SDL_USE_NIB_FILE /* Set the main menu to contain the real app name instead of "SDL App" */ [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; #endif /* Hand off to main application code */ gCalledAppMainline = TRUE; status = SDL_main (gArgc, gArgv); /* We're done, thank you for playing */ exit(status); } @end @implementation NSString (ReplaceSubString) - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString { unsigned int bufferSize; unsigned int selfLen = [self length]; unsigned int aStringLen = [aString length]; unichar *buffer; NSRange localRange; NSString *result; bufferSize = selfLen + aStringLen - aRange.length; buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar)); /* Get first part into buffer */ localRange.location = 0; localRange.length = aRange.location; [self getCharacters:buffer range:localRange]; /* Get middle part into buffer */ localRange.location = 0; localRange.length = aStringLen; [aString getCharacters:(buffer+aRange.location) range:localRange]; /* Get last part into buffer */ localRange.location = aRange.location + aRange.length; localRange.length = selfLen - localRange.location; [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; /* Build output string */ result = [NSString stringWithCharacters:buffer length:bufferSize]; NSDeallocateMemoryPages(buffer, bufferSize); return result; } @end // -------------------------------------------------------------------------------- /* Routine to center the application window */ void centerAppWindow(void) { [[[NSApplication sharedApplication] keyWindow] center]; } #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 ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { gArgv = (char **) SDL_malloc(sizeof (char *) * 2); gArgv[0] = argv[0]; gArgv[1] = NULL; gArgc = 1; gFinderLaunch = YES; } else { int i; gArgc = argc; gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); for (i = 0; i <= argc; i++) gArgv[i] = argv[i]; gFinderLaunch = NO; } myPrefs = [Preferences sharedInstance]; #if SDL_USE_NIB_FILE NSApplicationMain (argc, (const char **)argv); #else CustomApplicationMain (argc, argv); #endif return 0; } stella-3.9.3/src/macosx/SettingsMACOSX.hxx0000644000175000001440000000302312266336753017737 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SettingsMACOSX.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef SETTINGS_MAC_OSX_HXX #define SETTINGS_MAX_OSX_HXX class OSystem; #include "Settings.hxx" /** This class defines Macintosh OSX system specific settings. @author Mark Grebe @version $Id: SettingsMACOSX.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class SettingsMACOSX : public Settings { public: /** Create a new UNIX settings object */ SettingsMACOSX(OSystem* osystem); /** Destructor */ virtual ~SettingsMACOSX(); public: /** This method should be called to load the current settings from the standard Mac preferences. */ void loadConfig(); /** This method should be called to save the current settings to the standard Mac preferences. */ void saveConfig(); }; #endif stella-3.9.3/src/macosx/stella.xcodeproj/0000755000175000001440000000000012267274566017761 5ustar stephenusersstella-3.9.3/src/macosx/stella.xcodeproj/project.pbxproj0000644000175000001440000073615012267227155023041 0ustar stephenusers// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 2D28DDE509DC2D9F00A17585 /* MenusEvents.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D28DDE409DC2D9F00A17585 /* MenusEvents.h */; }; 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 */; }; 2D9173DF09BA90380026E9FF /* CartMC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF370627AE07006BEC99 /* CartMC.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 */; }; 2D9173F109BA90380026E9FF /* TIA.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF910627AE34006BEC99 /* TIA.hxx */; }; 2D9173F709BA90380026E9FF /* FrameBufferGL.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D733D5E062893E7006265D9 /* FrameBufferGL.hxx */; }; 2D9173F809BA90380026E9FF /* FrameBufferSoft.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D733D62062893E7006265D9 /* FrameBufferSoft.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 */; }; 2D9173FD09BA90380026E9FF /* SoundSDL.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDA34030665817D00CDD299 /* SoundSDL.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 */; }; 2D91745409BA90380026E9FF /* ColorWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20F9E508C603EC00A73076 /* ColorWidget.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 */; }; 2D91746809BA90380026E9FF /* MediaFactory.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D05FF5B096E261E00A518FE /* MediaFactory.hxx */; }; 2D91746909BA90380026E9FF /* EventMappingWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D05FF5F096E269100A518FE /* EventMappingWidget.hxx */; }; 2D91746A09BA90380026E9FF /* InputDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D05FF61096E269100A518FE /* InputDialog.hxx */; }; 2D91746D09BA90380026E9FF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 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 */; }; 2D91748809BA90380026E9FF /* CartMC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF360627AE07006BEC99 /* CartMC.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 */; }; 2D91749609BA90380026E9FF /* Random.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF880627AE34006BEC99 /* Random.cxx */; }; 2D91749709BA90380026E9FF /* Serializer.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF8A0627AE34006BEC99 /* Serializer.cxx */; }; 2D91749809BA90380026E9FF /* Switches.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF8E0627AE34006BEC99 /* Switches.cxx */; }; 2D91749909BA90380026E9FF /* TIA.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF900627AE34006BEC99 /* TIA.cxx */; }; 2D91749F09BA90380026E9FF /* FrameBufferGL.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D733D5D062893E7006265D9 /* FrameBufferGL.cxx */; }; 2D9174A009BA90380026E9FF /* FrameBufferSoft.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D733D61062893E7006265D9 /* FrameBufferSoft.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 */; }; 2D9174A509BA90380026E9FF /* SoundSDL.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDA34020665817D00CDD299 /* SoundSDL.cxx */; }; 2D9174A709BA90380026E9FF /* mainSDL.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEA0A0845700300812C11 /* mainSDL.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 */; }; 2D9174CB09BA90380026E9FF /* PackedBitArray.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D403BCE08611A69001E31A1 /* PackedBitArray.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 */; }; 2D9174DC09BA90380026E9FF /* Expression.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DF971DE0892CEA400F64D23 /* Expression.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 */; }; 2D9174F609BA90380026E9FF /* ColorWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20F9E408C603EC00A73076 /* ColorWidget.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 */; }; 2D91751109BA90380026E9FF /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D4764C806683C5F00F63D87 /* SDL.framework */; }; 2D91751209BA90380026E9FF /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D17D98E08BC398400E47F69 /* ApplicationServices.framework */; }; 2D91751409BA90380026E9FF /* SDL.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 2D4764C806683C5F00F63D87 /* SDL.framework */; }; 2DEFB40C09C3386F00754289 /* Cart.icns in Resources */ = {isa = PBXBuildFile; fileRef = 2DEFB40B09C3386F00754289 /* Cart.icns */; }; DC07A3C80CAD738A009B4BC9 /* StateManager.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC07A3C60CAD738A009B4BC9 /* StateManager.cxx */; }; DC07A3C90CAD738A009B4BC9 /* StateManager.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC07A3C70CAD738A009B4BC9 /* StateManager.hxx */; }; DC0984850D3985160073C852 /* CartSB.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC0984830D3985160073C852 /* CartSB.cxx */; }; DC0984860D3985160073C852 /* CartSB.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC0984840D3985160073C852 /* CartSB.hxx */; }; DC0B000014BA2BEB00CF5E7E /* JoystickWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC0BFFF214BA2BEB00CF5E7E /* JoystickWidget.cxx */; }; DC0B000114BA2BEB00CF5E7E /* JoystickWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC0BFFF314BA2BEB00CF5E7E /* JoystickWidget.hxx */; }; DC0B000214BA2BEB00CF5E7E /* KeyboardWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC0BFFF414BA2BEB00CF5E7E /* KeyboardWidget.cxx */; }; DC0B000314BA2BEB00CF5E7E /* KeyboardWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC0BFFF514BA2BEB00CF5E7E /* KeyboardWidget.hxx */; }; DC0B000414BA2BEB00CF5E7E /* NullControlWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC0BFFF614BA2BEB00CF5E7E /* NullControlWidget.hxx */; }; DC0B000514BA2BEB00CF5E7E /* PaddleWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC0BFFF714BA2BEB00CF5E7E /* PaddleWidget.cxx */; }; DC0B000614BA2BEB00CF5E7E /* PaddleWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC0BFFF814BA2BEB00CF5E7E /* PaddleWidget.hxx */; }; DC0BFFF914BA2BEB00CF5E7E /* BoosterWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC0BFFEB14BA2BEB00CF5E7E /* BoosterWidget.cxx */; }; DC0BFFFA14BA2BEB00CF5E7E /* BoosterWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC0BFFEC14BA2BEB00CF5E7E /* BoosterWidget.hxx */; }; DC0BFFFB14BA2BEB00CF5E7E /* ControllerWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC0BFFED14BA2BEB00CF5E7E /* ControllerWidget.hxx */; }; DC0BFFFC14BA2BEB00CF5E7E /* DrivingWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC0BFFEE14BA2BEB00CF5E7E /* DrivingWidget.cxx */; }; DC0BFFFD14BA2BEB00CF5E7E /* DrivingWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC0BFFEF14BA2BEB00CF5E7E /* DrivingWidget.hxx */; }; DC0BFFFE14BA2BEB00CF5E7E /* GenesisWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC0BFFF014BA2BEB00CF5E7E /* GenesisWidget.cxx */; }; DC0BFFFF14BA2BEB00CF5E7E /* GenesisWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC0BFFF114BA2BEB00CF5E7E /* GenesisWidget.hxx */; }; DC0D76A6177259C3005C7805 /* ConfigPathDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC0D76A2177259C3005C7805 /* ConfigPathDialog.cxx */; }; DC0D76A7177259C3005C7805 /* ConfigPathDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC0D76A3177259C3005C7805 /* ConfigPathDialog.hxx */; }; DC0D76A8177259C3005C7805 /* SnapshotDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC0D76A4177259C3005C7805 /* SnapshotDialog.cxx */; }; DC0D76A9177259C3005C7805 /* SnapshotDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC0D76A5177259C3005C7805 /* SnapshotDialog.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 */; }; DC173F760E2CAC1E00320F94 /* ContextMenu.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC173F740E2CAC1E00320F94 /* ContextMenu.cxx */; }; DC173F770E2CAC1E00320F94 /* ContextMenu.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC173F750E2CAC1E00320F94 /* ContextMenu.hxx */; }; DC17E8091361FDB500397A9E /* pngdebug.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17E8051361FDB500397A9E /* pngdebug.h */; }; DC17E80A1361FDB500397A9E /* pnginfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17E8061361FDB500397A9E /* pnginfo.h */; }; DC17E80B1361FDB500397A9E /* pnglibconf.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17E8071361FDB500397A9E /* pnglibconf.h */; }; DC17E80C1361FDB500397A9E /* pngstruct.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17E8081361FDB500397A9E /* pngstruct.h */; }; DC1FC18A0DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC1FC1880DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx */; }; DC1FC18B0DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1FC1890DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx */; }; DC20D6F3138EB130002A7428 /* StringList.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC20D6F1138EB130002A7428 /* StringList.hxx */; }; DC20D6F4138EB130002A7428 /* StringParser.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC20D6F2138EB130002A7428 /* StringParser.hxx */; }; DC3C3CDC173B1EB2009FFE61 /* Variant.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3C3CDB173B1EB2009FFE61 /* Variant.hxx */; }; DC3C3CE1173B1EC8009FFE61 /* FileListWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3C3CDF173B1EC8009FFE61 /* FileListWidget.cxx */; }; DC3C3CE2173B1EC8009FFE61 /* FileListWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3C3CE0173B1EC8009FFE61 /* FileListWidget.hxx */; }; DC3E4A6614B25EB30071D7BC /* CartCM.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3E4A6014B25EB30071D7BC /* CartCM.cxx */; }; DC3E4A6714B25EB30071D7BC /* CartCM.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3E4A6114B25EB30071D7BC /* CartCM.hxx */; }; DC3E4A6814B25EB30071D7BC /* CompuMate.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3E4A6214B25EB30071D7BC /* CompuMate.cxx */; }; DC3E4A6914B25EB30071D7BC /* CompuMate.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3E4A6314B25EB30071D7BC /* CompuMate.hxx */; }; DC3E4A6A14B25EB30071D7BC /* MindLink.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3E4A6414B25EB30071D7BC /* MindLink.cxx */; }; DC3E4A6B14B25EB30071D7BC /* MindLink.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3E4A6514B25EB30071D7BC /* MindLink.hxx */; }; DC3F601717C9140100A1977D /* ConsoleBFont.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3F601517C9140100A1977D /* ConsoleBFont.hxx */; }; DC3F601817C9140100A1977D /* ConsoleMediumBFont.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3F601617C9140100A1977D /* ConsoleMediumBFont.hxx */; }; DC3FE47C11C7D35600C91C72 /* png.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE46A11C7D35600C91C72 /* png.c */; }; DC3FE47D11C7D35600C91C72 /* png.h in Headers */ = {isa = PBXBuildFile; fileRef = DC3FE46B11C7D35600C91C72 /* png.h */; }; DC3FE47E11C7D35600C91C72 /* pngconf.h in Headers */ = {isa = PBXBuildFile; fileRef = DC3FE46C11C7D35600C91C72 /* pngconf.h */; }; DC3FE47F11C7D35600C91C72 /* pngerror.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE46D11C7D35600C91C72 /* pngerror.c */; }; DC3FE48011C7D35600C91C72 /* pngget.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE46E11C7D35600C91C72 /* pngget.c */; }; DC3FE48111C7D35600C91C72 /* pngmem.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE46F11C7D35600C91C72 /* pngmem.c */; }; DC3FE48211C7D35600C91C72 /* pngpread.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE47011C7D35600C91C72 /* pngpread.c */; }; DC3FE48311C7D35600C91C72 /* pngpriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC3FE47111C7D35600C91C72 /* pngpriv.h */; }; DC3FE48411C7D35600C91C72 /* pngread.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE47211C7D35600C91C72 /* pngread.c */; }; DC3FE48511C7D35600C91C72 /* pngrio.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE47311C7D35600C91C72 /* pngrio.c */; }; DC3FE48611C7D35600C91C72 /* pngrtran.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE47411C7D35600C91C72 /* pngrtran.c */; }; DC3FE48711C7D35600C91C72 /* pngrutil.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE47511C7D35600C91C72 /* pngrutil.c */; }; DC3FE48811C7D35600C91C72 /* pngset.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE47611C7D35600C91C72 /* pngset.c */; }; DC3FE48911C7D35600C91C72 /* pngtrans.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE47711C7D35600C91C72 /* pngtrans.c */; }; DC3FE48A11C7D35600C91C72 /* pngwio.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE47811C7D35600C91C72 /* pngwio.c */; }; DC3FE48B11C7D35600C91C72 /* pngwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE47911C7D35600C91C72 /* pngwrite.c */; }; DC3FE48C11C7D35600C91C72 /* pngwtran.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE47A11C7D35600C91C72 /* pngwtran.c */; }; DC3FE48D11C7D35600C91C72 /* pngwutil.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE47B11C7D35600C91C72 /* pngwutil.c */; }; DC3FE49F11C7D3FE00C91C72 /* PNGLibrary.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC3FE49D11C7D3FE00C91C72 /* PNGLibrary.cxx */; }; DC3FE4A011C7D3FE00C91C72 /* PNGLibrary.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3FE49E11C7D3FE00C91C72 /* PNGLibrary.hxx */; }; DC449CAF176FF512004FA2D4 /* RomListSettings.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC449CAD176FF512004FA2D4 /* RomListSettings.cxx */; }; DC449CB0176FF512004FA2D4 /* RomListSettings.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC449CAE176FF512004FA2D4 /* RomListSettings.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 */; }; DC49F90514F7D0DB000704B0 /* NTSCFilter.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC49F90314F7D0DB000704B0 /* NTSCFilter.cxx */; }; DC49F90614F7D0DB000704B0 /* NTSCFilter.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC49F90414F7D0DB000704B0 /* NTSCFilter.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 */; }; DC4AF1F312E39F700090B82E /* Thumbulator.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC4AF1F112E39F700090B82E /* Thumbulator.cxx */; }; DC4AF1F412E39F700090B82E /* Thumbulator.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC4AF1F212E39F700090B82E /* Thumbulator.hxx */; }; DC5C76B014C2709E0031EBC7 /* StellaKeys.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5C76AF14C2709E0031EBC7 /* 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 */; }; DC64EB201152F9C000DC9140 /* CartDPCPlus.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC64EB1E1152F9C000DC9140 /* CartDPCPlus.cxx */; }; DC64EB211152F9C000DC9140 /* CartDPCPlus.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC64EB1F1152F9C000DC9140 /* CartDPCPlus.hxx */; }; DC752D951513E9F7005B0D24 /* atari_ntsc_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = DC752D921513E9F7005B0D24 /* atari_ntsc_impl.h */; }; DC752D961513E9F7005B0D24 /* atari_ntsc.c in Sources */ = {isa = PBXBuildFile; fileRef = DC752D931513E9F7005B0D24 /* atari_ntsc.c */; }; DC752D971513E9F7005B0D24 /* atari_ntsc.h in Headers */ = {isa = PBXBuildFile; fileRef = DC752D941513E9F7005B0D24 /* atari_ntsc.h */; }; DC7A769A13FEA40300ED8633 /* LoggerDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC7A769813FEA40300ED8633 /* LoggerDialog.cxx */; }; DC7A769B13FEA40300ED8633 /* LoggerDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC7A769913FEA40300ED8633 /* LoggerDialog.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 */; }; DC84E11C1135988E00CA7C9D /* Genesis.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC84E11A1135988E00CA7C9D /* Genesis.cxx */; }; DC84E11D1135988E00CA7C9D /* Genesis.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC84E11B1135988E00CA7C9D /* Genesis.hxx */; }; DC8AE5C31417804C00335D45 /* FBSurfaceGL.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC8AE5BF1417804C00335D45 /* FBSurfaceGL.cxx */; }; DC8AE5C41417804C00335D45 /* FBSurfaceGL.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC8AE5C01417804C00335D45 /* FBSurfaceGL.hxx */; }; DC8AE5C51417804C00335D45 /* FBSurfaceTIA.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC8AE5C11417804C00335D45 /* FBSurfaceTIA.cxx */; }; DC8AE5C61417804C00335D45 /* FBSurfaceTIA.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC8AE5C21417804C00335D45 /* FBSurfaceTIA.hxx */; }; DC922D0614CAFB1E006EB471 /* CartFA2.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC922D0414CAFB1E006EB471 /* CartFA2.cxx */; }; DC922D0714CAFB1E006EB471 /* CartFA2.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC922D0514CAFB1E006EB471 /* CartFA2.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 */; }; DC932D470F278A5200FEFEFC /* TIATables.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC932D420F278A5200FEFEFC /* TIATables.cxx */; }; DC932D480F278A5200FEFEFC /* TIATables.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC932D430F278A5200FEFEFC /* TIATables.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 */; }; DCA23AE90D75B22500F77B33 /* CartX07.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCA23AE70D75B22500F77B33 /* CartX07.cxx */; }; DCA23AEA0D75B22500F77B33 /* CartX07.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCA23AE80D75B22500F77B33 /* CartX07.hxx */; }; DCA6276116CB0D1C004E9AF0 /* FSNodePOSIX.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCA6276016CB0D1C004E9AF0 /* FSNodePOSIX.hxx */; }; DCA6277416CB0D45004E9AF0 /* FSNodeFactory.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCA6276F16CB0D45004E9AF0 /* FSNodeFactory.hxx */; }; DCA6277516CB0D45004E9AF0 /* FSNodeZIP.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCA6277016CB0D45004E9AF0 /* FSNodeZIP.cxx */; }; DCA6277616CB0D45004E9AF0 /* FSNodeZIP.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCA6277116CB0D45004E9AF0 /* FSNodeZIP.hxx */; }; DCA6277716CB0D45004E9AF0 /* ZipHandler.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCA6277216CB0D45004E9AF0 /* ZipHandler.cxx */; }; DCA6277816CB0D45004E9AF0 /* ZipHandler.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCA6277316CB0D45004E9AF0 /* ZipHandler.hxx */; }; DCAE2A9314CCCCBD004327BB /* MouseControl.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAE2A9114CCCCBD004327BB /* MouseControl.cxx */; }; DCAE2A9414CCCCBD004327BB /* MouseControl.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAE2A9214CCCCBD004327BB /* MouseControl.hxx */; }; DCB29727188D655000B7BEB8 /* Cart4KSC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCB2971D188D655000B7BEB8 /* Cart4KSC.cxx */; }; DCB29728188D655000B7BEB8 /* Cart4KSC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCB2971E188D655000B7BEB8 /* Cart4KSC.hxx */; }; DCB29729188D655000B7BEB8 /* CartBF.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCB2971F188D655000B7BEB8 /* CartBF.cxx */; }; DCB2972A188D655000B7BEB8 /* CartBF.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCB29720188D655000B7BEB8 /* CartBF.hxx */; }; DCB2972B188D655000B7BEB8 /* CartBFSC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCB29721188D655000B7BEB8 /* CartBFSC.cxx */; }; DCB2972C188D655000B7BEB8 /* CartBFSC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCB29722188D655000B7BEB8 /* CartBFSC.hxx */; }; DCB2972D188D655000B7BEB8 /* CartDF.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCB29723188D655000B7BEB8 /* CartDF.cxx */; }; DCB2972E188D655000B7BEB8 /* CartDF.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCB29724188D655000B7BEB8 /* CartDF.hxx */; }; DCB2972F188D655000B7BEB8 /* CartDFSC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCB29725188D655000B7BEB8 /* CartDFSC.cxx */; }; DCB29730188D655000B7BEB8 /* CartDFSC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCB29726188D655000B7BEB8 /* CartDFSC.hxx */; }; DCB2973D188D657B00B7BEB8 /* Cart4KSCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCB29733188D657B00B7BEB8 /* Cart4KSCWidget.cxx */; }; DCB2973E188D657B00B7BEB8 /* Cart4KSCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCB29734188D657B00B7BEB8 /* Cart4KSCWidget.hxx */; }; DCB2973F188D657B00B7BEB8 /* CartBFSCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCB29735188D657B00B7BEB8 /* CartBFSCWidget.cxx */; }; DCB29740188D657B00B7BEB8 /* CartBFSCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCB29736188D657B00B7BEB8 /* CartBFSCWidget.hxx */; }; DCB29741188D657B00B7BEB8 /* CartBFWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCB29737188D657B00B7BEB8 /* CartBFWidget.cxx */; }; DCB29742188D657B00B7BEB8 /* CartBFWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCB29738188D657B00B7BEB8 /* CartBFWidget.hxx */; }; DCB29743188D657B00B7BEB8 /* CartDFSCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCB29739188D657B00B7BEB8 /* CartDFSCWidget.cxx */; }; DCB29744188D657B00B7BEB8 /* CartDFSCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCB2973A188D657B00B7BEB8 /* CartDFSCWidget.hxx */; }; DCB29745188D657B00B7BEB8 /* CartDFWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCB2973B188D657B00B7BEB8 /* CartDFWidget.cxx */; }; DCB29746188D657B00B7BEB8 /* CartDFWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCB2973C188D657B00B7BEB8 /* CartDFWidget.hxx */; }; DCB31D3E17C2D667002C0868 /* ConsoleMediumFont.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCB31D3D17C2D667002C0868 /* ConsoleMediumFont.hxx */; }; DCB5CEE711F5B78C00C68D09 /* MessageBox.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCB5CEE511F5B78C00C68D09 /* MessageBox.cxx */; }; DCB5CEE811F5B78C00C68D09 /* MessageBox.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCB5CEE611F5B78C00C68D09 /* MessageBox.hxx */; }; DCBD96891210314C0087CEFD /* ComboDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCBD96871210314C0087CEFD /* ComboDialog.cxx */; }; DCBD968A1210314C0087CEFD /* ComboDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCBD96881210314C0087CEFD /* ComboDialog.hxx */; }; DCD56D380B247D920092F9F8 /* Cart4A50.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCD56D360B247D920092F9F8 /* Cart4A50.cxx */; }; DCD56D390B247D920092F9F8 /* Cart4A50.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCD56D370B247D920092F9F8 /* Cart4A50.hxx */; }; DCD56D3C0B247DB40092F9F8 /* RectList.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCD56D3A0B247DB40092F9F8 /* RectList.cxx */; }; DCD56D3D0B247DB40092F9F8 /* RectList.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCD56D3B0B247DB40092F9F8 /* RectList.hxx */; }; DCDBD3181556F60C00308CC4 /* CartCTY.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCDBD3151556F60C00308CC4 /* CartCTY.cxx */; }; DCDBD3191556F60C00308CC4 /* CartCTY.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCDBD3161556F60C00308CC4 /* CartCTY.hxx */; }; DCDBD31A1556F60C00308CC4 /* CartCTYTunes.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCDBD3171556F60C00308CC4 /* CartCTYTunes.hxx */; }; DCE3BBF90C95CEDC00A671DF /* RomInfoWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCE3BBF50C95CEDC00A671DF /* RomInfoWidget.cxx */; }; DCE3BBFA0C95CEDC00A671DF /* RomInfoWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCE3BBF60C95CEDC00A671DF /* RomInfoWidget.hxx */; }; DCE6EB220DD9ADA00047AC28 /* TrackBall.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCE6EB200DD9ADA00047AC28 /* TrackBall.cxx */; }; DCE6EB230DD9ADA00047AC28 /* TrackBall.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCE6EB210DD9ADA00047AC28 /* TrackBall.hxx */; }; DCE9CC2A1103812700C86671 /* CartDebug.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCE9CC261103812700C86671 /* CartDebug.cxx */; }; DCE9CC2B1103812700C86671 /* CartDebug.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCE9CC271103812700C86671 /* CartDebug.hxx */; }; DCE9CC2C1103812700C86671 /* DiStella.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCE9CC281103812700C86671 /* DiStella.cxx */; }; DCE9CC2D1103812700C86671 /* DiStella.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCE9CC291103812700C86671 /* DiStella.hxx */; }; DCECD7A917A88E51000A9753 /* Base.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCECD7A717A88E51000A9753 /* Base.cxx */; }; DCECD7AA17A88E51000A9753 /* Base.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCECD7A817A88E51000A9753 /* Base.hxx */; }; DCECDAFB10B9DBDC00AF4E1B /* Device.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCECDAF310B9DBDC00AF4E1B /* Device.hxx */; }; DCECDAFC10B9DBDC00AF4E1B /* M6502.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCECDAF410B9DBDC00AF4E1B /* M6502.cxx */; }; DCECDAFD10B9DBDC00AF4E1B /* M6502.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCECDAF510B9DBDC00AF4E1B /* M6502.hxx */; }; DCECDAFE10B9DBDC00AF4E1B /* NullDev.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCECDAF610B9DBDC00AF4E1B /* NullDev.cxx */; }; DCECDAFF10B9DBDC00AF4E1B /* NullDev.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCECDAF710B9DBDC00AF4E1B /* NullDev.hxx */; }; DCECDB0010B9DBDC00AF4E1B /* System.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCECDAF810B9DBDC00AF4E1B /* System.cxx */; }; DCECDB0110B9DBDC00AF4E1B /* System.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCECDAF910B9DBDC00AF4E1B /* System.hxx */; }; DCECDB0510B9DC0400AF4E1B /* bspf.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCECDB0210B9DC0400AF4E1B /* bspf.hxx */; }; DCEECE560B5E5E540021D754 /* Cart0840.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCEECE540B5E5E540021D754 /* Cart0840.cxx */; }; DCEECE570B5E5E540021D754 /* Cart0840.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCEECE550B5E5E540021D754 /* Cart0840.hxx */; }; DCF28EE91729A5CD00DD0CA9 /* Cart2KWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EAC1729A5CD00DD0CA9 /* Cart2KWidget.cxx */; }; DCF28EEA1729A5CD00DD0CA9 /* Cart2KWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EAD1729A5CD00DD0CA9 /* Cart2KWidget.hxx */; }; DCF28EEB1729A5CD00DD0CA9 /* Cart3EWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EAE1729A5CD00DD0CA9 /* Cart3EWidget.cxx */; }; DCF28EEC1729A5CD00DD0CA9 /* Cart3EWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EAF1729A5CD00DD0CA9 /* Cart3EWidget.hxx */; }; DCF28EED1729A5CD00DD0CA9 /* Cart3FWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EB01729A5CD00DD0CA9 /* Cart3FWidget.cxx */; }; DCF28EEE1729A5CD00DD0CA9 /* Cart3FWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EB11729A5CD00DD0CA9 /* Cart3FWidget.hxx */; }; DCF28EEF1729A5CD00DD0CA9 /* Cart4A50Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EB21729A5CD00DD0CA9 /* Cart4A50Widget.cxx */; }; DCF28EF01729A5CD00DD0CA9 /* Cart4A50Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EB31729A5CD00DD0CA9 /* Cart4A50Widget.hxx */; }; DCF28EF11729A5CD00DD0CA9 /* Cart4KWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EB41729A5CD00DD0CA9 /* Cart4KWidget.cxx */; }; DCF28EF21729A5CD00DD0CA9 /* Cart4KWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EB51729A5CD00DD0CA9 /* Cart4KWidget.hxx */; }; DCF28EF31729A5CD00DD0CA9 /* Cart0840Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EB61729A5CD00DD0CA9 /* Cart0840Widget.cxx */; }; DCF28EF41729A5CD00DD0CA9 /* Cart0840Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EB71729A5CD00DD0CA9 /* Cart0840Widget.hxx */; }; DCF28EF51729A5CD00DD0CA9 /* CartARWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EB81729A5CD00DD0CA9 /* CartARWidget.cxx */; }; DCF28EF61729A5CD00DD0CA9 /* CartARWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EB91729A5CD00DD0CA9 /* CartARWidget.hxx */; }; DCF28EF71729A5CD00DD0CA9 /* CartCMWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EBA1729A5CD00DD0CA9 /* CartCMWidget.cxx */; }; DCF28EF81729A5CD00DD0CA9 /* CartCMWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EBB1729A5CD00DD0CA9 /* CartCMWidget.hxx */; }; DCF28EF91729A5CD00DD0CA9 /* CartCTYWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EBC1729A5CD00DD0CA9 /* CartCTYWidget.cxx */; }; DCF28EFA1729A5CD00DD0CA9 /* CartCTYWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EBD1729A5CD00DD0CA9 /* CartCTYWidget.hxx */; }; DCF28EFB1729A5CD00DD0CA9 /* CartCVWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EBE1729A5CD00DD0CA9 /* CartCVWidget.cxx */; }; DCF28EFC1729A5CD00DD0CA9 /* CartCVWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EBF1729A5CD00DD0CA9 /* CartCVWidget.hxx */; }; DCF28EFD1729A5CD00DD0CA9 /* CartDebugWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EC01729A5CD00DD0CA9 /* CartDebugWidget.hxx */; }; DCF28EFE1729A5CD00DD0CA9 /* CartDPCPlusWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EC11729A5CD00DD0CA9 /* CartDPCPlusWidget.cxx */; }; DCF28EFF1729A5CD00DD0CA9 /* CartDPCPlusWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EC21729A5CD00DD0CA9 /* CartDPCPlusWidget.hxx */; }; DCF28F001729A5CD00DD0CA9 /* CartDPCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EC31729A5CD00DD0CA9 /* CartDPCWidget.cxx */; }; DCF28F011729A5CD00DD0CA9 /* CartDPCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EC41729A5CD00DD0CA9 /* CartDPCWidget.hxx */; }; DCF28F021729A5CD00DD0CA9 /* CartE0Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EC51729A5CD00DD0CA9 /* CartE0Widget.cxx */; }; DCF28F031729A5CD00DD0CA9 /* CartE0Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EC61729A5CD00DD0CA9 /* CartE0Widget.hxx */; }; DCF28F041729A5CD00DD0CA9 /* CartE7Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EC71729A5CD00DD0CA9 /* CartE7Widget.cxx */; }; DCF28F051729A5CD00DD0CA9 /* CartE7Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EC81729A5CD00DD0CA9 /* CartE7Widget.hxx */; }; DCF28F061729A5CD00DD0CA9 /* CartEFSCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EC91729A5CD00DD0CA9 /* CartEFSCWidget.cxx */; }; DCF28F071729A5CD00DD0CA9 /* CartEFSCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28ECA1729A5CD00DD0CA9 /* CartEFSCWidget.hxx */; }; DCF28F081729A5CD00DD0CA9 /* CartEFWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28ECB1729A5CD00DD0CA9 /* CartEFWidget.cxx */; }; DCF28F091729A5CD00DD0CA9 /* CartEFWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28ECC1729A5CD00DD0CA9 /* CartEFWidget.hxx */; }; DCF28F0A1729A5CD00DD0CA9 /* CartF0Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28ECD1729A5CD00DD0CA9 /* CartF0Widget.cxx */; }; DCF28F0B1729A5CD00DD0CA9 /* CartF0Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28ECE1729A5CD00DD0CA9 /* CartF0Widget.hxx */; }; DCF28F0C1729A5CD00DD0CA9 /* CartF4SCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28ECF1729A5CD00DD0CA9 /* CartF4SCWidget.cxx */; }; DCF28F0D1729A5CD00DD0CA9 /* CartF4SCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28ED01729A5CD00DD0CA9 /* CartF4SCWidget.hxx */; }; DCF28F0E1729A5CD00DD0CA9 /* CartF4Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28ED11729A5CD00DD0CA9 /* CartF4Widget.cxx */; }; DCF28F0F1729A5CD00DD0CA9 /* CartF4Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28ED21729A5CD00DD0CA9 /* CartF4Widget.hxx */; }; DCF28F101729A5CD00DD0CA9 /* CartF6SCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28ED31729A5CD00DD0CA9 /* CartF6SCWidget.cxx */; }; DCF28F111729A5CD00DD0CA9 /* CartF6SCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28ED41729A5CD00DD0CA9 /* CartF6SCWidget.hxx */; }; DCF28F121729A5CD00DD0CA9 /* CartF6Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28ED51729A5CD00DD0CA9 /* CartF6Widget.cxx */; }; DCF28F131729A5CD00DD0CA9 /* CartF6Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28ED61729A5CD00DD0CA9 /* CartF6Widget.hxx */; }; DCF28F141729A5CD00DD0CA9 /* CartF8SCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28ED71729A5CD00DD0CA9 /* CartF8SCWidget.cxx */; }; DCF28F151729A5CD00DD0CA9 /* CartF8SCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28ED81729A5CD00DD0CA9 /* CartF8SCWidget.hxx */; }; DCF28F161729A5CD00DD0CA9 /* CartF8Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28ED91729A5CD00DD0CA9 /* CartF8Widget.cxx */; }; DCF28F171729A5CD00DD0CA9 /* CartF8Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EDA1729A5CD00DD0CA9 /* CartF8Widget.hxx */; }; DCF28F181729A5CD00DD0CA9 /* CartFA2Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EDB1729A5CD00DD0CA9 /* CartFA2Widget.cxx */; }; DCF28F191729A5CD00DD0CA9 /* CartFA2Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EDC1729A5CD00DD0CA9 /* CartFA2Widget.hxx */; }; DCF28F1A1729A5CD00DD0CA9 /* CartFAWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EDD1729A5CD00DD0CA9 /* CartFAWidget.cxx */; }; DCF28F1B1729A5CD00DD0CA9 /* CartFAWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EDE1729A5CD00DD0CA9 /* CartFAWidget.hxx */; }; DCF28F1C1729A5CD00DD0CA9 /* CartFEWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EDF1729A5CD00DD0CA9 /* CartFEWidget.cxx */; }; DCF28F1D1729A5CD00DD0CA9 /* CartFEWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EE01729A5CD00DD0CA9 /* CartFEWidget.hxx */; }; DCF28F1E1729A5CD00DD0CA9 /* CartMCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EE11729A5CD00DD0CA9 /* CartMCWidget.cxx */; }; DCF28F1F1729A5CD00DD0CA9 /* CartMCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EE21729A5CD00DD0CA9 /* CartMCWidget.hxx */; }; DCF28F201729A5CD00DD0CA9 /* CartSBWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EE31729A5CD00DD0CA9 /* CartSBWidget.cxx */; }; DCF28F211729A5CD00DD0CA9 /* CartSBWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EE41729A5CD00DD0CA9 /* CartSBWidget.hxx */; }; DCF28F221729A5CD00DD0CA9 /* CartUAWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EE51729A5CD00DD0CA9 /* CartUAWidget.cxx */; }; DCF28F231729A5CD00DD0CA9 /* CartUAWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EE61729A5CD00DD0CA9 /* CartUAWidget.hxx */; }; DCF28F241729A5CD00DD0CA9 /* CartX07Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF28EE71729A5CD00DD0CA9 /* CartX07Widget.cxx */; }; DCF28F251729A5CD00DD0CA9 /* CartX07Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF28EE81729A5CD00DD0CA9 /* CartX07Widget.hxx */; }; DCF467B50F93993B00B25D7A /* Array.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF467B10F93993B00B25D7A /* Array.hxx */; }; DCF467B60F93993B00B25D7A /* SharedPtr.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF467B20F93993B00B25D7A /* SharedPtr.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 */; }; 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 */; }; /* End PBXBuildFile section */ /* Begin PBXBuildRule section */ 2D91751B09BA90380026E9FF /* PBXBuildRule */ = { isa = PBXBuildRule; compilerSpec = com.apple.compilers.gcc.4_0; fileType = sourcecode.c; isEditable = 1; outputFiles = ( ); }; 2D91751C09BA90380026E9FF /* PBXBuildRule */ = { isa = PBXBuildRule; compilerSpec = com.apple.compilers.gcc.4_0; fileType = sourcecode.cpp; isEditable = 1; outputFiles = ( ); }; 2D91751D09BA90390026E9FF /* PBXBuildRule */ = { isa = PBXBuildRule; compilerSpec = com.apple.compilers.gcc.4_0; fileType = sourcecode.asm; isEditable = 1; outputFiles = ( ); }; /* End PBXBuildRule section */ /* Begin PBXCopyFilesBuildPhase section */ 2D91751309BA90380026E9FF /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( 2D91751409BA90380026E9FF /* SDL.framework in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; DCCC0C9609C354660088BFF1 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 7; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 2D02207F08A301F200B9C76B /* InputTextDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = InputTextDialog.cxx; path = ../gui/InputTextDialog.cxx; sourceTree = SOURCE_ROOT; }; 2D02208008A301F200B9C76B /* InputTextDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = InputTextDialog.hxx; path = ../gui/InputTextDialog.hxx; sourceTree = SOURCE_ROOT; }; 2D05FF5B096E261E00A518FE /* MediaFactory.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MediaFactory.hxx; path = ../emucore/MediaFactory.hxx; sourceTree = SOURCE_ROOT; }; 2D05FF5E096E269100A518FE /* EventMappingWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = EventMappingWidget.cxx; path = ../gui/EventMappingWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D05FF5F096E269100A518FE /* EventMappingWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = EventMappingWidget.hxx; path = ../gui/EventMappingWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D05FF60096E269100A518FE /* InputDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = InputDialog.cxx; path = ../gui/InputDialog.cxx; sourceTree = SOURCE_ROOT; }; 2D05FF61096E269100A518FE /* InputDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = InputDialog.hxx; path = ../gui/InputDialog.hxx; sourceTree = SOURCE_ROOT; }; 2D113E090672BF2100317017 /* ../../docs */ = {isa = PBXFileReference; explicitFileType = folder; 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 = ""; }; 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; }; 2D20F9E408C603EC00A73076 /* ColorWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ColorWidget.cxx; path = ../debugger/gui/ColorWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9E508C603EC00A73076 /* ColorWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = ColorWidget.hxx; path = ../debugger/gui/ColorWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9E608C603EC00A73076 /* CpuWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CpuWidget.cxx; path = ../debugger/gui/CpuWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9E708C603EC00A73076 /* CpuWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CpuWidget.hxx; path = ../debugger/gui/CpuWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9E808C603EC00A73076 /* DataGridOpsWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DataGridOpsWidget.cxx; path = ../debugger/gui/DataGridOpsWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9E908C603EC00A73076 /* DataGridOpsWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = DataGridOpsWidget.hxx; path = ../debugger/gui/DataGridOpsWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9EA08C603EC00A73076 /* DataGridWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DataGridWidget.cxx; path = ../debugger/gui/DataGridWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9EB08C603EC00A73076 /* DataGridWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = DataGridWidget.hxx; path = ../debugger/gui/DataGridWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9EC08C603EC00A73076 /* DebuggerDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DebuggerDialog.cxx; path = ../debugger/gui/DebuggerDialog.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9ED08C603EC00A73076 /* DebuggerDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = DebuggerDialog.hxx; path = ../debugger/gui/DebuggerDialog.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9EE08C603EC00A73076 /* PromptWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PromptWidget.cxx; path = ../debugger/gui/PromptWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9EF08C603EC00A73076 /* PromptWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = PromptWidget.hxx; path = ../debugger/gui/PromptWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9F008C603EC00A73076 /* RamWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RamWidget.cxx; path = ../debugger/gui/RamWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9F108C603EC00A73076 /* RamWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RamWidget.hxx; path = ../debugger/gui/RamWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9F208C603EC00A73076 /* RomListWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RomListWidget.cxx; path = ../debugger/gui/RomListWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9F308C603EC00A73076 /* RomListWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RomListWidget.hxx; path = ../debugger/gui/RomListWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9F408C603EC00A73076 /* RomWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RomWidget.cxx; path = ../debugger/gui/RomWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9F508C603EC00A73076 /* RomWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RomWidget.hxx; path = ../debugger/gui/RomWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9F608C603EC00A73076 /* TiaInfoWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TiaInfoWidget.cxx; path = ../debugger/gui/TiaInfoWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9F708C603EC00A73076 /* TiaInfoWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TiaInfoWidget.hxx; path = ../debugger/gui/TiaInfoWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9F808C603EC00A73076 /* TiaOutputWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TiaOutputWidget.cxx; path = ../debugger/gui/TiaOutputWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9F908C603EC00A73076 /* TiaOutputWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TiaOutputWidget.hxx; path = ../debugger/gui/TiaOutputWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9FA08C603EC00A73076 /* TiaWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TiaWidget.cxx; path = ../debugger/gui/TiaWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9FB08C603EC00A73076 /* TiaWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TiaWidget.hxx; path = ../debugger/gui/TiaWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9FC08C603EC00A73076 /* ToggleBitWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ToggleBitWidget.cxx; path = ../debugger/gui/ToggleBitWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9FD08C603EC00A73076 /* ToggleBitWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = ToggleBitWidget.hxx; path = ../debugger/gui/ToggleBitWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20F9FE08C603EC00A73076 /* TogglePixelWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TogglePixelWidget.cxx; path = ../debugger/gui/TogglePixelWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20F9FF08C603EC00A73076 /* TogglePixelWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TogglePixelWidget.hxx; path = ../debugger/gui/TogglePixelWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D20FA0008C603EC00A73076 /* ToggleWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ToggleWidget.cxx; path = ../debugger/gui/ToggleWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D20FA0108C603EC00A73076 /* ToggleWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = ToggleWidget.hxx; path = ../debugger/gui/ToggleWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D23318F0900B5EF00613B1F /* AudioWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AudioWidget.cxx; path = ../debugger/gui/AudioWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D2331900900B5EF00613B1F /* AudioWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = AudioWidget.hxx; path = ../debugger/gui/AudioWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D28DDE409DC2D9F00A17585 /* MenusEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenusEvents.h; sourceTree = ""; }; 2D30F8750868A4DB00938B9D /* TIADebug.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TIADebug.cxx; path = ../debugger/TIADebug.cxx; sourceTree = SOURCE_ROOT; }; 2D30F8760868A4DB00938B9D /* TIADebug.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TIADebug.hxx; path = ../debugger/TIADebug.hxx; sourceTree = SOURCE_ROOT; }; 2D313F0A0879C4C0005BD3E5 /* YaccParser.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = YaccParser.cxx; path = ../yacc/YaccParser.cxx; sourceTree = SOURCE_ROOT; }; 2D313F0B0879C4C0005BD3E5 /* YaccParser.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = YaccParser.hxx; path = ../yacc/YaccParser.hxx; sourceTree = SOURCE_ROOT; }; 2D403BA0086116D1001E31A1 /* EditableWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = EditableWidget.cxx; path = ../gui/EditableWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D403BA1086116D1001E31A1 /* EditableWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = EditableWidget.hxx; path = ../gui/EditableWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D403BA4086116D1001E31A1 /* EditTextWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = EditTextWidget.cxx; path = ../gui/EditTextWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D403BA5086116D1001E31A1 /* EditTextWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = EditTextWidget.hxx; path = ../gui/EditTextWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D403BCE08611A69001E31A1 /* PackedBitArray.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PackedBitArray.cxx; path = ../debugger/PackedBitArray.cxx; sourceTree = SOURCE_ROOT; }; 2D403BCF08611A69001E31A1 /* PackedBitArray.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = PackedBitArray.hxx; path = ../debugger/PackedBitArray.hxx; sourceTree = SOURCE_ROOT; }; 2D4764C806683C5F00F63D87 /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SDL.framework; sourceTree = SOURCE_ROOT; }; 2D659E2D085D3DD6005D96C8 /* Debugger.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Debugger.cxx; path = ../debugger/Debugger.cxx; sourceTree = SOURCE_ROOT; }; 2D659E2E085D3DD6005D96C8 /* Debugger.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Debugger.hxx; path = ../debugger/Debugger.hxx; sourceTree = SOURCE_ROOT; }; 2D659E31085D3DD6005D96C8 /* DebuggerParser.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DebuggerParser.cxx; path = ../debugger/DebuggerParser.cxx; sourceTree = SOURCE_ROOT; }; 2D659E32085D3DD6005D96C8 /* DebuggerParser.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = DebuggerParser.hxx; path = ../debugger/DebuggerParser.hxx; sourceTree = SOURCE_ROOT; }; 2D6CC10308C811A600B8F642 /* TiaZoomWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TiaZoomWidget.cxx; path = ../debugger/gui/TiaZoomWidget.cxx; sourceTree = SOURCE_ROOT; }; 2D6CC10408C811A600B8F642 /* TiaZoomWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TiaZoomWidget.hxx; path = ../debugger/gui/TiaZoomWidget.hxx; sourceTree = SOURCE_ROOT; }; 2D733D5D062893E7006265D9 /* FrameBufferGL.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = FrameBufferGL.cxx; path = ../common/FrameBufferGL.cxx; sourceTree = SOURCE_ROOT; }; 2D733D5E062893E7006265D9 /* FrameBufferGL.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FrameBufferGL.hxx; path = ../common/FrameBufferGL.hxx; sourceTree = SOURCE_ROOT; }; 2D733D61062893E7006265D9 /* FrameBufferSoft.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = FrameBufferSoft.cxx; path = ../common/FrameBufferSoft.cxx; sourceTree = SOURCE_ROOT; }; 2D733D62062893E7006265D9 /* FrameBufferSoft.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FrameBufferSoft.hxx; path = ../common/FrameBufferSoft.hxx; sourceTree = SOURCE_ROOT; }; 2D733D6E062895B2006265D9 /* EventHandler.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = EventHandler.cxx; path = ../emucore/EventHandler.cxx; sourceTree = SOURCE_ROOT; }; 2D733D6F062895B2006265D9 /* EventHandler.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = EventHandler.hxx; path = ../emucore/EventHandler.hxx; sourceTree = SOURCE_ROOT; }; 2D733D70062895B2006265D9 /* FrameBuffer.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = FrameBuffer.cxx; path = ../emucore/FrameBuffer.cxx; sourceTree = SOURCE_ROOT; }; 2D733D71062895B2006265D9 /* FrameBuffer.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FrameBuffer.hxx; path = ../emucore/FrameBuffer.hxx; sourceTree = SOURCE_ROOT; }; 2D733D77062895F1006265D9 /* Settings.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Settings.hxx; path = ../emucore/Settings.hxx; sourceTree = SOURCE_ROOT; }; 2D73959308C3EB4E0060BB99 /* CommandDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CommandDialog.cxx; path = ../gui/CommandDialog.cxx; sourceTree = SOURCE_ROOT; }; 2D73959408C3EB4E0060BB99 /* CommandDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CommandDialog.hxx; path = ../gui/CommandDialog.hxx; sourceTree = SOURCE_ROOT; }; 2D73959508C3EB4E0060BB99 /* CommandMenu.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CommandMenu.cxx; path = ../gui/CommandMenu.cxx; sourceTree = SOURCE_ROOT; }; 2D73959608C3EB4E0060BB99 /* CommandMenu.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CommandMenu.hxx; path = ../gui/CommandMenu.hxx; sourceTree = SOURCE_ROOT; }; 2D7B4F6C063B513200579B93 /* Credits.html */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.html; path = Credits.html; sourceTree = SOURCE_ROOT; }; 2D91751E09BA90390026E9FF /* Stella.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Stella.app; sourceTree = BUILT_PRODUCTS_DIR; }; 2D9217FA0857CC88001D664B /* ConsoleFont.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = ConsoleFont.hxx; path = ../gui/ConsoleFont.hxx; sourceTree = SOURCE_ROOT; }; 2D9217FB0857CC88001D664B /* Font.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Font.cxx; path = ../gui/Font.cxx; sourceTree = SOURCE_ROOT; }; 2D9217FC0857CC88001D664B /* Font.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Font.hxx; path = ../gui/Font.hxx; sourceTree = SOURCE_ROOT; }; 2D944848062904E800DD9879 /* Settings.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Settings.cxx; path = ../emucore/Settings.cxx; sourceTree = SOURCE_ROOT; }; 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; name = Cart3E.cxx; path = ../emucore/Cart3E.cxx; sourceTree = SOURCE_ROOT; }; 2D9555DA0880E78000466554 /* Cart3E.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cart3E.hxx; path = ../emucore/Cart3E.hxx; sourceTree = SOURCE_ROOT; }; 2D9555DD0880E79600466554 /* CpuDebug.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CpuDebug.cxx; path = ../debugger/CpuDebug.cxx; sourceTree = SOURCE_ROOT; }; 2D9555DE0880E79600466554 /* CpuDebug.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CpuDebug.hxx; path = ../debugger/CpuDebug.hxx; sourceTree = SOURCE_ROOT; }; 2DDA34020665817D00CDD299 /* SoundSDL.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SoundSDL.cxx; path = ../common/SoundSDL.cxx; sourceTree = SOURCE_ROOT; }; 2DDA34030665817D00CDD299 /* SoundSDL.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = SoundSDL.hxx; path = ../common/SoundSDL.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEA0A0845700300812C11 /* mainSDL.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = mainSDL.cxx; path = ../common/mainSDL.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEA0C0845708800812C11 /* FSNodePOSIX.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = FSNodePOSIX.cxx; path = ../unix/FSNodePOSIX.cxx; sourceTree = SOURCE_ROOT; }; 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; name = AboutDialog.cxx; path = ../gui/AboutDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAA4084578BF00812C11 /* AboutDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = AboutDialog.hxx; path = ../gui/AboutDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAA6084578BF00812C11 /* AudioDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AudioDialog.cxx; path = ../gui/AudioDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAA7084578BF00812C11 /* AudioDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = AudioDialog.hxx; path = ../gui/AudioDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAA8084578BF00812C11 /* BrowserDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = BrowserDialog.cxx; path = ../gui/BrowserDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAA9084578BF00812C11 /* BrowserDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = BrowserDialog.hxx; path = ../gui/BrowserDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAAA084578BF00812C11 /* Command.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Command.hxx; path = ../gui/Command.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAAB084578BF00812C11 /* Dialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Dialog.cxx; path = ../gui/Dialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAAC084578BF00812C11 /* Dialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Dialog.hxx; path = ../gui/Dialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAAD084578BF00812C11 /* DialogContainer.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DialogContainer.cxx; path = ../gui/DialogContainer.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAAE084578BF00812C11 /* DialogContainer.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = DialogContainer.hxx; path = ../gui/DialogContainer.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAB2084578BF00812C11 /* GameInfoDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = GameInfoDialog.cxx; path = ../gui/GameInfoDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAB3084578BF00812C11 /* GameInfoDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = GameInfoDialog.hxx; path = ../gui/GameInfoDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAB4084578BF00812C11 /* GameList.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = GameList.cxx; path = ../gui/GameList.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAB5084578BF00812C11 /* GameList.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = GameList.hxx; path = ../gui/GameList.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAB6084578BF00812C11 /* GuiObject.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = GuiObject.hxx; path = ../gui/GuiObject.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAB8084578BF00812C11 /* HelpDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = HelpDialog.cxx; path = ../gui/HelpDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAB9084578BF00812C11 /* HelpDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = HelpDialog.hxx; path = ../gui/HelpDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEABA084578BF00812C11 /* Launcher.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Launcher.cxx; path = ../gui/Launcher.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEABB084578BF00812C11 /* Launcher.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Launcher.hxx; path = ../gui/Launcher.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEABC084578BF00812C11 /* LauncherDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = LauncherDialog.cxx; path = ../gui/LauncherDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEABD084578BF00812C11 /* LauncherDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = LauncherDialog.hxx; path = ../gui/LauncherDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC0084578BF00812C11 /* ListWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ListWidget.cxx; path = ../gui/ListWidget.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC1084578BF00812C11 /* ListWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = ListWidget.hxx; path = ../gui/ListWidget.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC2084578BF00812C11 /* Menu.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Menu.cxx; path = ../gui/Menu.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC3084578BF00812C11 /* Menu.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Menu.hxx; path = ../gui/Menu.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC4084578BF00812C11 /* OptionsDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = OptionsDialog.cxx; path = ../gui/OptionsDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC5084578BF00812C11 /* OptionsDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = OptionsDialog.hxx; path = ../gui/OptionsDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC6084578BF00812C11 /* PopUpWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PopUpWidget.cxx; path = ../gui/PopUpWidget.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC7084578BF00812C11 /* PopUpWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = PopUpWidget.hxx; path = ../gui/PopUpWidget.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC8084578BF00812C11 /* ProgressDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ProgressDialog.cxx; path = ../gui/ProgressDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAC9084578BF00812C11 /* ProgressDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = ProgressDialog.hxx; path = ../gui/ProgressDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEACA084578BF00812C11 /* ScrollBarWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ScrollBarWidget.cxx; path = ../gui/ScrollBarWidget.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEACB084578BF00812C11 /* ScrollBarWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = ScrollBarWidget.hxx; path = ../gui/ScrollBarWidget.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAD0084578BF00812C11 /* TabWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TabWidget.cxx; path = ../gui/TabWidget.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAD1084578BF00812C11 /* TabWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TabWidget.hxx; path = ../gui/TabWidget.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAD2084578BF00812C11 /* VideoDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = VideoDialog.cxx; path = ../gui/VideoDialog.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAD3084578BF00812C11 /* VideoDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = VideoDialog.hxx; path = ../gui/VideoDialog.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEAD4084578BF00812C11 /* Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Widget.cxx; path = ../gui/Widget.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEAD5084578BF00812C11 /* Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Widget.hxx; path = ../gui/Widget.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEB7008457B7D00812C11 /* CartUA.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartUA.cxx; path = ../emucore/CartUA.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEB7108457B7D00812C11 /* CartUA.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartUA.hxx; path = ../emucore/CartUA.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEB7208457B7D00812C11 /* FSNode.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = FSNode.cxx; path = ../emucore/FSNode.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEB7308457B7D00812C11 /* FSNode.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FSNode.hxx; path = ../emucore/FSNode.hxx; sourceTree = SOURCE_ROOT; }; 2DDBEB7408457B7D00812C11 /* OSystem.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = OSystem.cxx; path = ../emucore/OSystem.cxx; sourceTree = SOURCE_ROOT; }; 2DDBEB7508457B7D00812C11 /* OSystem.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = OSystem.hxx; path = ../emucore/OSystem.hxx; sourceTree = SOURCE_ROOT; }; 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; name = Booster.cxx; path = ../emucore/Booster.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF110627AE07006BEC99 /* Booster.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Booster.hxx; path = ../emucore/Booster.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF120627AE07006BEC99 /* Cart.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Cart.cxx; path = ../emucore/Cart.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF130627AE07006BEC99 /* Cart.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cart.hxx; path = ../emucore/Cart.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF140627AE07006BEC99 /* Cart2K.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Cart2K.cxx; path = ../emucore/Cart2K.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF150627AE07006BEC99 /* Cart2K.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cart2K.hxx; path = ../emucore/Cart2K.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF160627AE07006BEC99 /* Cart3F.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Cart3F.cxx; path = ../emucore/Cart3F.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF170627AE07006BEC99 /* Cart3F.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cart3F.hxx; path = ../emucore/Cart3F.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF180627AE07006BEC99 /* Cart4K.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Cart4K.cxx; path = ../emucore/Cart4K.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF190627AE07006BEC99 /* Cart4K.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cart4K.hxx; path = ../emucore/Cart4K.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF1A0627AE07006BEC99 /* CartAR.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartAR.cxx; path = ../emucore/CartAR.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF1B0627AE07006BEC99 /* CartAR.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartAR.hxx; path = ../emucore/CartAR.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF1C0627AE07006BEC99 /* CartCV.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartCV.cxx; path = ../emucore/CartCV.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF1D0627AE07006BEC99 /* CartCV.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartCV.hxx; path = ../emucore/CartCV.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF1E0627AE07006BEC99 /* CartDPC.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartDPC.cxx; path = ../emucore/CartDPC.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF1F0627AE07006BEC99 /* CartDPC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartDPC.hxx; path = ../emucore/CartDPC.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF200627AE07006BEC99 /* CartE0.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartE0.cxx; path = ../emucore/CartE0.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF210627AE07006BEC99 /* CartE0.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartE0.hxx; path = ../emucore/CartE0.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF220627AE07006BEC99 /* CartE7.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartE7.cxx; path = ../emucore/CartE7.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF230627AE07006BEC99 /* CartE7.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartE7.hxx; path = ../emucore/CartE7.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF240627AE07006BEC99 /* CartF4.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartF4.cxx; path = ../emucore/CartF4.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF250627AE07006BEC99 /* CartF4.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartF4.hxx; path = ../emucore/CartF4.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF260627AE07006BEC99 /* CartF4SC.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartF4SC.cxx; path = ../emucore/CartF4SC.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF270627AE07006BEC99 /* CartF4SC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartF4SC.hxx; path = ../emucore/CartF4SC.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF280627AE07006BEC99 /* CartF6.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartF6.cxx; path = ../emucore/CartF6.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF290627AE07006BEC99 /* CartF6.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartF6.hxx; path = ../emucore/CartF6.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF2A0627AE07006BEC99 /* CartF6SC.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartF6SC.cxx; path = ../emucore/CartF6SC.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF2B0627AE07006BEC99 /* CartF6SC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartF6SC.hxx; path = ../emucore/CartF6SC.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF2C0627AE07006BEC99 /* CartF8.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartF8.cxx; path = ../emucore/CartF8.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF2D0627AE07006BEC99 /* CartF8.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartF8.hxx; path = ../emucore/CartF8.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF2E0627AE07006BEC99 /* CartF8SC.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartF8SC.cxx; path = ../emucore/CartF8SC.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF2F0627AE07006BEC99 /* CartF8SC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartF8SC.hxx; path = ../emucore/CartF8SC.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF320627AE07006BEC99 /* CartFE.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartFE.cxx; path = ../emucore/CartFE.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF330627AE07006BEC99 /* CartFE.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartFE.hxx; path = ../emucore/CartFE.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF360627AE07006BEC99 /* CartMC.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartMC.cxx; path = ../emucore/CartMC.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF370627AE07006BEC99 /* CartMC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartMC.hxx; path = ../emucore/CartMC.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF380627AE07006BEC99 /* Console.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Console.cxx; path = ../emucore/Console.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF390627AE07006BEC99 /* Console.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Console.hxx; path = ../emucore/Console.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF3A0627AE07006BEC99 /* Control.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Control.cxx; path = ../emucore/Control.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF3B0627AE07006BEC99 /* Control.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Control.hxx; path = ../emucore/Control.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF3E0627AE07006BEC99 /* Driving.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Driving.cxx; path = ../emucore/Driving.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF3F0627AE07006BEC99 /* Driving.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Driving.hxx; path = ../emucore/Driving.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF410627AE07006BEC99 /* Event.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Event.hxx; path = ../emucore/Event.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF420627AE07006BEC99 /* Joystick.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Joystick.cxx; path = ../emucore/Joystick.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF430627AE07006BEC99 /* Joystick.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Joystick.hxx; path = ../emucore/Joystick.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF440627AE07006BEC99 /* Keyboard.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Keyboard.cxx; path = ../emucore/Keyboard.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF450627AE07006BEC99 /* Keyboard.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Keyboard.hxx; path = ../emucore/Keyboard.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF7C0627AE33006BEC99 /* M6532.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = M6532.cxx; path = ../emucore/M6532.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF7D0627AE33006BEC99 /* M6532.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = M6532.hxx; path = ../emucore/M6532.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF7E0627AE33006BEC99 /* MD5.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = MD5.cxx; path = ../emucore/MD5.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF7F0627AE34006BEC99 /* MD5.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MD5.hxx; path = ../emucore/MD5.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF820627AE34006BEC99 /* Paddles.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Paddles.cxx; path = ../emucore/Paddles.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF830627AE34006BEC99 /* Paddles.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Paddles.hxx; path = ../emucore/Paddles.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF840627AE34006BEC99 /* Props.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Props.cxx; path = ../emucore/Props.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF850627AE34006BEC99 /* Props.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Props.hxx; path = ../emucore/Props.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF860627AE34006BEC99 /* PropsSet.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PropsSet.cxx; path = ../emucore/PropsSet.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF870627AE34006BEC99 /* PropsSet.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = PropsSet.hxx; path = ../emucore/PropsSet.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF880627AE34006BEC99 /* Random.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Random.cxx; path = ../emucore/Random.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF890627AE34006BEC99 /* Random.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Random.hxx; path = ../emucore/Random.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF8A0627AE34006BEC99 /* Serializer.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Serializer.cxx; path = ../emucore/Serializer.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF8B0627AE34006BEC99 /* Serializer.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Serializer.hxx; path = ../emucore/Serializer.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF8D0627AE34006BEC99 /* Sound.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Sound.hxx; path = ../emucore/Sound.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF8E0627AE34006BEC99 /* Switches.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Switches.cxx; path = ../emucore/Switches.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF8F0627AE34006BEC99 /* Switches.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Switches.hxx; path = ../emucore/Switches.hxx; sourceTree = SOURCE_ROOT; }; 2DE2DF900627AE34006BEC99 /* TIA.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TIA.cxx; path = ../emucore/TIA.cxx; sourceTree = SOURCE_ROOT; }; 2DE2DF910627AE34006BEC99 /* TIA.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TIA.hxx; path = ../emucore/TIA.hxx; sourceTree = SOURCE_ROOT; }; 2DE7242D08CE910900C889A8 /* TIASnd.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TIASnd.cxx; path = ../emucore/TIASnd.cxx; sourceTree = SOURCE_ROOT; }; 2DE7242E08CE910900C889A8 /* TIASnd.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TIASnd.hxx; path = ../emucore/TIASnd.hxx; sourceTree = SOURCE_ROOT; }; 2DEB3D4C0629BD24007EBBD3 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; 2DEF21F808BC033500B246B4 /* CheckListWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CheckListWidget.cxx; path = ../gui/CheckListWidget.cxx; sourceTree = SOURCE_ROOT; }; 2DEF21F908BC033500B246B4 /* CheckListWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CheckListWidget.hxx; path = ../gui/CheckListWidget.hxx; sourceTree = SOURCE_ROOT; }; 2DEF21FA08BC033500B246B4 /* StringListWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = StringListWidget.cxx; path = ../gui/StringListWidget.cxx; sourceTree = SOURCE_ROOT; }; 2DEF21FB08BC033500B246B4 /* StringListWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = StringListWidget.hxx; path = ../gui/StringListWidget.hxx; sourceTree = SOURCE_ROOT; }; 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; name = DebuggerSystem.hxx; path = ../debugger/DebuggerSystem.hxx; sourceTree = SOURCE_ROOT; }; 2DF971DE0892CEA400F64D23 /* Expression.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Expression.cxx; path = ../debugger/Expression.cxx; sourceTree = SOURCE_ROOT; }; 2DF971DF0892CEA400F64D23 /* Expression.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Expression.hxx; path = ../debugger/Expression.hxx; sourceTree = SOURCE_ROOT; }; B2F367C504C7ADC700A80002 /* SDLMain.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; path = SDLMain.nib; sourceTree = ""; }; DC07A3C60CAD738A009B4BC9 /* StateManager.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = StateManager.cxx; path = ../emucore/StateManager.cxx; sourceTree = SOURCE_ROOT; }; DC07A3C70CAD738A009B4BC9 /* StateManager.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = StateManager.hxx; path = ../emucore/StateManager.hxx; sourceTree = SOURCE_ROOT; }; DC0984830D3985160073C852 /* CartSB.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartSB.cxx; path = ../emucore/CartSB.cxx; sourceTree = SOURCE_ROOT; }; DC0984840D3985160073C852 /* CartSB.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartSB.hxx; path = ../emucore/CartSB.hxx; sourceTree = SOURCE_ROOT; }; DC0BFFEB14BA2BEB00CF5E7E /* BoosterWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BoosterWidget.cxx; path = ../debugger/gui/BoosterWidget.cxx; sourceTree = SOURCE_ROOT; }; DC0BFFEC14BA2BEB00CF5E7E /* BoosterWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = BoosterWidget.hxx; path = ../debugger/gui/BoosterWidget.hxx; sourceTree = SOURCE_ROOT; }; DC0BFFED14BA2BEB00CF5E7E /* ControllerWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ControllerWidget.hxx; path = ../debugger/gui/ControllerWidget.hxx; sourceTree = SOURCE_ROOT; }; DC0BFFEE14BA2BEB00CF5E7E /* DrivingWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DrivingWidget.cxx; path = ../debugger/gui/DrivingWidget.cxx; sourceTree = SOURCE_ROOT; }; DC0BFFEF14BA2BEB00CF5E7E /* DrivingWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = DrivingWidget.hxx; path = ../debugger/gui/DrivingWidget.hxx; sourceTree = SOURCE_ROOT; }; DC0BFFF014BA2BEB00CF5E7E /* GenesisWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GenesisWidget.cxx; path = ../debugger/gui/GenesisWidget.cxx; sourceTree = SOURCE_ROOT; }; DC0BFFF114BA2BEB00CF5E7E /* GenesisWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = GenesisWidget.hxx; path = ../debugger/gui/GenesisWidget.hxx; sourceTree = SOURCE_ROOT; }; DC0BFFF214BA2BEB00CF5E7E /* JoystickWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JoystickWidget.cxx; path = ../debugger/gui/JoystickWidget.cxx; sourceTree = SOURCE_ROOT; }; DC0BFFF314BA2BEB00CF5E7E /* JoystickWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = JoystickWidget.hxx; path = ../debugger/gui/JoystickWidget.hxx; sourceTree = SOURCE_ROOT; }; DC0BFFF414BA2BEB00CF5E7E /* KeyboardWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = KeyboardWidget.cxx; path = ../debugger/gui/KeyboardWidget.cxx; sourceTree = SOURCE_ROOT; }; DC0BFFF514BA2BEB00CF5E7E /* KeyboardWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = KeyboardWidget.hxx; path = ../debugger/gui/KeyboardWidget.hxx; sourceTree = SOURCE_ROOT; }; DC0BFFF614BA2BEB00CF5E7E /* NullControlWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = NullControlWidget.hxx; path = ../debugger/gui/NullControlWidget.hxx; sourceTree = SOURCE_ROOT; }; DC0BFFF714BA2BEB00CF5E7E /* PaddleWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PaddleWidget.cxx; path = ../debugger/gui/PaddleWidget.cxx; sourceTree = SOURCE_ROOT; }; DC0BFFF814BA2BEB00CF5E7E /* PaddleWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = PaddleWidget.hxx; path = ../debugger/gui/PaddleWidget.hxx; sourceTree = SOURCE_ROOT; }; DC0D76A2177259C3005C7805 /* ConfigPathDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ConfigPathDialog.cxx; path = ../gui/ConfigPathDialog.cxx; sourceTree = SOURCE_ROOT; }; DC0D76A3177259C3005C7805 /* ConfigPathDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ConfigPathDialog.hxx; path = ../gui/ConfigPathDialog.hxx; sourceTree = SOURCE_ROOT; }; DC0D76A4177259C3005C7805 /* SnapshotDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SnapshotDialog.cxx; path = ../gui/SnapshotDialog.cxx; sourceTree = SOURCE_ROOT; }; DC0D76A5177259C3005C7805 /* SnapshotDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = SnapshotDialog.hxx; path = ../gui/SnapshotDialog.hxx; sourceTree = SOURCE_ROOT; }; DC0DF8670F0DAAF500B0F1F3 /* GlobalPropsDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GlobalPropsDialog.cxx; path = ../gui/GlobalPropsDialog.cxx; sourceTree = SOURCE_ROOT; }; DC0DF8680F0DAAF500B0F1F3 /* GlobalPropsDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = GlobalPropsDialog.hxx; path = ../gui/GlobalPropsDialog.hxx; sourceTree = SOURCE_ROOT; }; DC11F78B0DB36933003B505E /* MT24LC256.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = MT24LC256.cxx; path = ../emucore/MT24LC256.cxx; sourceTree = SOURCE_ROOT; }; DC11F78C0DB36933003B505E /* MT24LC256.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MT24LC256.hxx; path = ../emucore/MT24LC256.hxx; sourceTree = SOURCE_ROOT; }; DC173F740E2CAC1E00320F94 /* ContextMenu.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ContextMenu.cxx; path = ../gui/ContextMenu.cxx; sourceTree = SOURCE_ROOT; }; DC173F750E2CAC1E00320F94 /* ContextMenu.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = ContextMenu.hxx; path = ../gui/ContextMenu.hxx; sourceTree = SOURCE_ROOT; }; DC17E8051361FDB500397A9E /* pngdebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pngdebug.h; path = ../libpng/pngdebug.h; sourceTree = SOURCE_ROOT; }; DC17E8061361FDB500397A9E /* pnginfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pnginfo.h; path = ../libpng/pnginfo.h; sourceTree = SOURCE_ROOT; }; DC17E8071361FDB500397A9E /* pnglibconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pnglibconf.h; path = ../libpng/pnglibconf.h; sourceTree = SOURCE_ROOT; }; DC17E8081361FDB500397A9E /* pngstruct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pngstruct.h; path = ../libpng/pngstruct.h; sourceTree = SOURCE_ROOT; }; 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 = ""; }; DC20D6F1138EB130002A7428 /* StringList.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = StringList.hxx; path = ../common/StringList.hxx; sourceTree = SOURCE_ROOT; }; DC20D6F2138EB130002A7428 /* StringParser.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = StringParser.hxx; path = ../common/StringParser.hxx; sourceTree = SOURCE_ROOT; }; DC3C3CDB173B1EB2009FFE61 /* Variant.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Variant.hxx; path = ../common/Variant.hxx; sourceTree = SOURCE_ROOT; }; DC3C3CDF173B1EC8009FFE61 /* FileListWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FileListWidget.cxx; path = ../gui/FileListWidget.cxx; sourceTree = SOURCE_ROOT; }; DC3C3CE0173B1EC8009FFE61 /* FileListWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FileListWidget.hxx; path = ../gui/FileListWidget.hxx; sourceTree = SOURCE_ROOT; }; DC3E4A6014B25EB30071D7BC /* CartCM.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartCM.cxx; path = ../emucore/CartCM.cxx; sourceTree = SOURCE_ROOT; }; DC3E4A6114B25EB30071D7BC /* CartCM.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartCM.hxx; path = ../emucore/CartCM.hxx; sourceTree = SOURCE_ROOT; }; DC3E4A6214B25EB30071D7BC /* CompuMate.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompuMate.cxx; path = ../emucore/CompuMate.cxx; sourceTree = SOURCE_ROOT; }; DC3E4A6314B25EB30071D7BC /* CompuMate.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CompuMate.hxx; path = ../emucore/CompuMate.hxx; sourceTree = SOURCE_ROOT; }; DC3E4A6414B25EB30071D7BC /* MindLink.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MindLink.cxx; path = ../emucore/MindLink.cxx; sourceTree = SOURCE_ROOT; }; DC3E4A6514B25EB30071D7BC /* MindLink.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = MindLink.hxx; path = ../emucore/MindLink.hxx; sourceTree = SOURCE_ROOT; }; DC3F601517C9140100A1977D /* ConsoleBFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ConsoleBFont.hxx; path = ../gui/ConsoleBFont.hxx; sourceTree = SOURCE_ROOT; }; DC3F601617C9140100A1977D /* ConsoleMediumBFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ConsoleMediumBFont.hxx; path = ../gui/ConsoleMediumBFont.hxx; sourceTree = SOURCE_ROOT; }; DC3FE46A11C7D35600C91C72 /* png.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = png.c; path = ../libpng/png.c; sourceTree = SOURCE_ROOT; }; DC3FE46B11C7D35600C91C72 /* png.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = png.h; path = ../libpng/png.h; sourceTree = SOURCE_ROOT; }; DC3FE46C11C7D35600C91C72 /* pngconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pngconf.h; path = ../libpng/pngconf.h; sourceTree = SOURCE_ROOT; }; DC3FE46D11C7D35600C91C72 /* pngerror.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngerror.c; path = ../libpng/pngerror.c; sourceTree = SOURCE_ROOT; }; DC3FE46E11C7D35600C91C72 /* pngget.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngget.c; path = ../libpng/pngget.c; sourceTree = SOURCE_ROOT; }; DC3FE46F11C7D35600C91C72 /* pngmem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngmem.c; path = ../libpng/pngmem.c; sourceTree = SOURCE_ROOT; }; DC3FE47011C7D35600C91C72 /* pngpread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngpread.c; path = ../libpng/pngpread.c; sourceTree = SOURCE_ROOT; }; DC3FE47111C7D35600C91C72 /* pngpriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pngpriv.h; path = ../libpng/pngpriv.h; sourceTree = SOURCE_ROOT; }; DC3FE47211C7D35600C91C72 /* pngread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngread.c; path = ../libpng/pngread.c; sourceTree = SOURCE_ROOT; }; DC3FE47311C7D35600C91C72 /* pngrio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngrio.c; path = ../libpng/pngrio.c; sourceTree = SOURCE_ROOT; }; DC3FE47411C7D35600C91C72 /* pngrtran.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngrtran.c; path = ../libpng/pngrtran.c; sourceTree = SOURCE_ROOT; }; DC3FE47511C7D35600C91C72 /* pngrutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngrutil.c; path = ../libpng/pngrutil.c; sourceTree = SOURCE_ROOT; }; DC3FE47611C7D35600C91C72 /* pngset.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngset.c; path = ../libpng/pngset.c; sourceTree = SOURCE_ROOT; }; DC3FE47711C7D35600C91C72 /* pngtrans.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngtrans.c; path = ../libpng/pngtrans.c; sourceTree = SOURCE_ROOT; }; DC3FE47811C7D35600C91C72 /* pngwio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngwio.c; path = ../libpng/pngwio.c; sourceTree = SOURCE_ROOT; }; DC3FE47911C7D35600C91C72 /* pngwrite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngwrite.c; path = ../libpng/pngwrite.c; sourceTree = SOURCE_ROOT; }; DC3FE47A11C7D35600C91C72 /* pngwtran.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngwtran.c; path = ../libpng/pngwtran.c; sourceTree = SOURCE_ROOT; }; DC3FE47B11C7D35600C91C72 /* pngwutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pngwutil.c; path = ../libpng/pngwutil.c; sourceTree = SOURCE_ROOT; }; DC3FE49D11C7D3FE00C91C72 /* PNGLibrary.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PNGLibrary.cxx; path = ../common/PNGLibrary.cxx; sourceTree = SOURCE_ROOT; }; DC3FE49E11C7D3FE00C91C72 /* PNGLibrary.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = PNGLibrary.hxx; path = ../common/PNGLibrary.hxx; sourceTree = SOURCE_ROOT; }; DC419D81108E10A3006E8687 /* Info-Stella.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Stella.plist"; sourceTree = ""; }; DC449CAD176FF512004FA2D4 /* RomListSettings.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RomListSettings.cxx; path = ../debugger/gui/RomListSettings.cxx; sourceTree = SOURCE_ROOT; }; DC449CAE176FF512004FA2D4 /* RomListSettings.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = RomListSettings.hxx; path = ../debugger/gui/RomListSettings.hxx; sourceTree = SOURCE_ROOT; }; DC4613650D92C03600D8DAB9 /* RomAuditDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RomAuditDialog.cxx; path = ../gui/RomAuditDialog.cxx; sourceTree = SOURCE_ROOT; }; DC4613660D92C03600D8DAB9 /* RomAuditDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RomAuditDialog.hxx; path = ../gui/RomAuditDialog.hxx; sourceTree = SOURCE_ROOT; }; DC47454A09C34BFA00EDDA3A /* BankRomCheat.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = BankRomCheat.cxx; path = ../cheat/BankRomCheat.cxx; sourceTree = SOURCE_ROOT; }; DC47454B09C34BFA00EDDA3A /* BankRomCheat.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = BankRomCheat.hxx; path = ../cheat/BankRomCheat.hxx; sourceTree = SOURCE_ROOT; }; DC47454C09C34BFA00EDDA3A /* Cheat.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cheat.hxx; path = ../cheat/Cheat.hxx; sourceTree = SOURCE_ROOT; }; DC47454D09C34BFA00EDDA3A /* CheatCodeDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CheatCodeDialog.cxx; path = ../cheat/CheatCodeDialog.cxx; sourceTree = SOURCE_ROOT; }; DC47454E09C34BFA00EDDA3A /* CheatCodeDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CheatCodeDialog.hxx; path = ../cheat/CheatCodeDialog.hxx; sourceTree = SOURCE_ROOT; }; DC47454F09C34BFA00EDDA3A /* CheatManager.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CheatManager.cxx; path = ../cheat/CheatManager.cxx; sourceTree = SOURCE_ROOT; }; DC47455009C34BFA00EDDA3A /* CheatManager.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CheatManager.hxx; path = ../cheat/CheatManager.hxx; sourceTree = SOURCE_ROOT; }; DC47455109C34BFA00EDDA3A /* CheetahCheat.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CheetahCheat.cxx; path = ../cheat/CheetahCheat.cxx; sourceTree = SOURCE_ROOT; }; DC47455209C34BFA00EDDA3A /* CheetahCheat.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CheetahCheat.hxx; path = ../cheat/CheetahCheat.hxx; sourceTree = SOURCE_ROOT; }; DC47455309C34BFA00EDDA3A /* RamCheat.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RamCheat.cxx; path = ../cheat/RamCheat.cxx; sourceTree = SOURCE_ROOT; }; DC47455409C34BFA00EDDA3A /* RamCheat.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RamCheat.hxx; path = ../cheat/RamCheat.hxx; sourceTree = SOURCE_ROOT; }; DC487FB40DA5350900E12499 /* AtariVox.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AtariVox.cxx; path = ../emucore/AtariVox.cxx; sourceTree = SOURCE_ROOT; }; DC487FB50DA5350900E12499 /* AtariVox.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = AtariVox.hxx; path = ../emucore/AtariVox.hxx; sourceTree = SOURCE_ROOT; }; DC49F90314F7D0DB000704B0 /* NTSCFilter.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NTSCFilter.cxx; path = ../common/tv_filters/NTSCFilter.cxx; sourceTree = SOURCE_ROOT; }; DC49F90414F7D0DB000704B0 /* NTSCFilter.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = NTSCFilter.hxx; path = ../common/tv_filters/NTSCFilter.hxx; sourceTree = SOURCE_ROOT; }; DC4AC6ED0DC8DACB00CD3AD2 /* RiotWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RiotWidget.cxx; path = ../debugger/gui/RiotWidget.cxx; sourceTree = SOURCE_ROOT; }; DC4AC6EE0DC8DACB00CD3AD2 /* RiotWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RiotWidget.hxx; path = ../debugger/gui/RiotWidget.hxx; sourceTree = SOURCE_ROOT; }; DC4AC6F10DC8DAEF00CD3AD2 /* SaveKey.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SaveKey.cxx; path = ../emucore/SaveKey.cxx; sourceTree = SOURCE_ROOT; }; DC4AC6F20DC8DAEF00CD3AD2 /* SaveKey.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = SaveKey.hxx; path = ../emucore/SaveKey.hxx; sourceTree = SOURCE_ROOT; }; DC4AF1F112E39F700090B82E /* Thumbulator.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Thumbulator.cxx; path = ../emucore/Thumbulator.cxx; sourceTree = SOURCE_ROOT; }; DC4AF1F212E39F700090B82E /* Thumbulator.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Thumbulator.hxx; path = ../emucore/Thumbulator.hxx; sourceTree = SOURCE_ROOT; }; DC5C76AF14C2709E0031EBC7 /* StellaKeys.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = StellaKeys.hxx; path = ../common/StellaKeys.hxx; sourceTree = SOURCE_ROOT; }; DC5D1AA6102C6FC900E59AC1 /* Stack.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Stack.hxx; path = ../common/Stack.hxx; sourceTree = SOURCE_ROOT; }; DC5D2C4E0F117CFD004D1660 /* Rect.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Rect.hxx; path = ../gui/Rect.hxx; sourceTree = SOURCE_ROOT; }; DC5D2C4F0F117CFD004D1660 /* StellaFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = StellaFont.hxx; path = ../gui/StellaFont.hxx; sourceTree = SOURCE_ROOT; }; DC5D2C500F117CFD004D1660 /* StellaLargeFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = StellaLargeFont.hxx; path = ../gui/StellaLargeFont.hxx; sourceTree = SOURCE_ROOT; }; DC5D2C510F117CFD004D1660 /* StellaMediumFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = StellaMediumFont.hxx; path = ../gui/StellaMediumFont.hxx; sourceTree = SOURCE_ROOT; }; DC5D2C5E0F129B1E004D1660 /* LauncherFilterDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LauncherFilterDialog.cxx; path = ../gui/LauncherFilterDialog.cxx; sourceTree = SOURCE_ROOT; }; DC5D2C5F0F129B1E004D1660 /* LauncherFilterDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = LauncherFilterDialog.hxx; path = ../gui/LauncherFilterDialog.hxx; sourceTree = SOURCE_ROOT; }; DC64EB1E1152F9C000DC9140 /* CartDPCPlus.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDPCPlus.cxx; path = ../emucore/CartDPCPlus.cxx; sourceTree = SOURCE_ROOT; }; DC64EB1F1152F9C000DC9140 /* CartDPCPlus.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDPCPlus.hxx; path = ../emucore/CartDPCPlus.hxx; sourceTree = SOURCE_ROOT; }; DC752D921513E9F7005B0D24 /* atari_ntsc_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = atari_ntsc_impl.h; path = ../common/tv_filters/atari_ntsc_impl.h; sourceTree = SOURCE_ROOT; }; DC752D931513E9F7005B0D24 /* atari_ntsc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = atari_ntsc.c; path = ../common/tv_filters/atari_ntsc.c; sourceTree = SOURCE_ROOT; }; DC752D941513E9F7005B0D24 /* atari_ntsc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = atari_ntsc.h; path = ../common/tv_filters/atari_ntsc.h; sourceTree = SOURCE_ROOT; }; DC7A769813FEA40300ED8633 /* LoggerDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LoggerDialog.cxx; path = ../gui/LoggerDialog.cxx; sourceTree = SOURCE_ROOT; }; DC7A769913FEA40300ED8633 /* LoggerDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = LoggerDialog.hxx; path = ../gui/LoggerDialog.hxx; sourceTree = SOURCE_ROOT; }; DC8078DA0B4BD5F3005E9305 /* DebuggerExpressions.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = DebuggerExpressions.hxx; path = ../debugger/DebuggerExpressions.hxx; sourceTree = SOURCE_ROOT; }; DC8078E60B4BD697005E9305 /* UIDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = UIDialog.cxx; path = ../gui/UIDialog.cxx; sourceTree = SOURCE_ROOT; }; DC8078E70B4BD697005E9305 /* UIDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = UIDialog.hxx; path = ../gui/UIDialog.hxx; sourceTree = SOURCE_ROOT; }; DC84E11A1135988E00CA7C9D /* Genesis.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Genesis.cxx; path = ../emucore/Genesis.cxx; sourceTree = SOURCE_ROOT; }; DC84E11B1135988E00CA7C9D /* Genesis.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Genesis.hxx; path = ../emucore/Genesis.hxx; sourceTree = SOURCE_ROOT; }; DC8AE5BF1417804C00335D45 /* FBSurfaceGL.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FBSurfaceGL.cxx; path = ../common/FBSurfaceGL.cxx; sourceTree = SOURCE_ROOT; }; DC8AE5C01417804C00335D45 /* FBSurfaceGL.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FBSurfaceGL.hxx; path = ../common/FBSurfaceGL.hxx; sourceTree = SOURCE_ROOT; }; DC8AE5C11417804C00335D45 /* FBSurfaceTIA.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FBSurfaceTIA.cxx; path = ../common/FBSurfaceTIA.cxx; sourceTree = SOURCE_ROOT; }; DC8AE5C21417804C00335D45 /* FBSurfaceTIA.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FBSurfaceTIA.hxx; path = ../common/FBSurfaceTIA.hxx; sourceTree = SOURCE_ROOT; }; DC922D0414CAFB1E006EB471 /* CartFA2.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartFA2.cxx; path = ../emucore/CartFA2.cxx; sourceTree = SOURCE_ROOT; }; DC922D0514CAFB1E006EB471 /* CartFA2.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartFA2.hxx; path = ../emucore/CartFA2.hxx; sourceTree = SOURCE_ROOT; }; DC932D3F0F278A5200FEFEFC /* DefProps.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = DefProps.hxx; path = ../emucore/DefProps.hxx; sourceTree = SOURCE_ROOT; }; DC932D400F278A5200FEFEFC /* Serializable.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Serializable.hxx; path = ../emucore/Serializable.hxx; sourceTree = SOURCE_ROOT; }; DC932D410F278A5200FEFEFC /* SerialPort.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = SerialPort.hxx; path = ../emucore/SerialPort.hxx; sourceTree = SOURCE_ROOT; }; DC932D420F278A5200FEFEFC /* TIATables.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TIATables.cxx; path = ../emucore/TIATables.cxx; sourceTree = SOURCE_ROOT; }; DC932D430F278A5200FEFEFC /* TIATables.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = TIATables.hxx; path = ../emucore/TIATables.hxx; sourceTree = SOURCE_ROOT; }; DC9EA8850F729A36000452B5 /* KidVid.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = KidVid.cxx; path = ../emucore/KidVid.cxx; sourceTree = SOURCE_ROOT; }; DC9EA8860F729A36000452B5 /* KidVid.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = KidVid.hxx; path = ../emucore/KidVid.hxx; sourceTree = SOURCE_ROOT; }; DCA00FF50DBABCAD00C3823D /* RiotDebug.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RiotDebug.cxx; path = ../debugger/RiotDebug.cxx; sourceTree = SOURCE_ROOT; }; DCA00FF60DBABCAD00C3823D /* RiotDebug.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = RiotDebug.hxx; path = ../debugger/RiotDebug.hxx; sourceTree = SOURCE_ROOT; }; DCA23AE70D75B22500F77B33 /* CartX07.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CartX07.cxx; path = ../emucore/CartX07.cxx; sourceTree = SOURCE_ROOT; }; DCA23AE80D75B22500F77B33 /* CartX07.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = CartX07.hxx; path = ../emucore/CartX07.hxx; sourceTree = SOURCE_ROOT; }; DCA6276016CB0D1C004E9AF0 /* FSNodePOSIX.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FSNodePOSIX.hxx; path = ../unix/FSNodePOSIX.hxx; sourceTree = SOURCE_ROOT; }; DCA6276F16CB0D45004E9AF0 /* FSNodeFactory.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FSNodeFactory.hxx; path = ../common/FSNodeFactory.hxx; sourceTree = SOURCE_ROOT; }; DCA6277016CB0D45004E9AF0 /* FSNodeZIP.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FSNodeZIP.cxx; path = ../common/FSNodeZIP.cxx; sourceTree = SOURCE_ROOT; }; DCA6277116CB0D45004E9AF0 /* FSNodeZIP.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = FSNodeZIP.hxx; path = ../common/FSNodeZIP.hxx; sourceTree = SOURCE_ROOT; }; DCA6277216CB0D45004E9AF0 /* ZipHandler.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ZipHandler.cxx; path = ../common/ZipHandler.cxx; sourceTree = SOURCE_ROOT; }; DCA6277316CB0D45004E9AF0 /* ZipHandler.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ZipHandler.hxx; path = ../common/ZipHandler.hxx; sourceTree = SOURCE_ROOT; }; DCAE2A9114CCCCBD004327BB /* MouseControl.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MouseControl.cxx; path = ../common/MouseControl.cxx; sourceTree = SOURCE_ROOT; }; DCAE2A9214CCCCBD004327BB /* MouseControl.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = MouseControl.hxx; path = ../common/MouseControl.hxx; sourceTree = SOURCE_ROOT; }; DCB2971D188D655000B7BEB8 /* Cart4KSC.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart4KSC.cxx; path = ../emucore/Cart4KSC.cxx; sourceTree = SOURCE_ROOT; }; DCB2971E188D655000B7BEB8 /* Cart4KSC.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart4KSC.hxx; path = ../emucore/Cart4KSC.hxx; sourceTree = SOURCE_ROOT; }; DCB2971F188D655000B7BEB8 /* CartBF.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartBF.cxx; path = ../emucore/CartBF.cxx; sourceTree = SOURCE_ROOT; }; DCB29720188D655000B7BEB8 /* CartBF.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartBF.hxx; path = ../emucore/CartBF.hxx; sourceTree = SOURCE_ROOT; }; DCB29721188D655000B7BEB8 /* CartBFSC.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartBFSC.cxx; path = ../emucore/CartBFSC.cxx; sourceTree = SOURCE_ROOT; }; DCB29722188D655000B7BEB8 /* CartBFSC.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartBFSC.hxx; path = ../emucore/CartBFSC.hxx; sourceTree = SOURCE_ROOT; }; DCB29723188D655000B7BEB8 /* CartDF.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDF.cxx; path = ../emucore/CartDF.cxx; sourceTree = SOURCE_ROOT; }; DCB29724188D655000B7BEB8 /* CartDF.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDF.hxx; path = ../emucore/CartDF.hxx; sourceTree = SOURCE_ROOT; }; DCB29725188D655000B7BEB8 /* CartDFSC.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDFSC.cxx; path = ../emucore/CartDFSC.cxx; sourceTree = SOURCE_ROOT; }; DCB29726188D655000B7BEB8 /* CartDFSC.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDFSC.hxx; path = ../emucore/CartDFSC.hxx; sourceTree = SOURCE_ROOT; }; DCB29733188D657B00B7BEB8 /* Cart4KSCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart4KSCWidget.cxx; path = ../debugger/gui/Cart4KSCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCB29734188D657B00B7BEB8 /* Cart4KSCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart4KSCWidget.hxx; path = ../debugger/gui/Cart4KSCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCB29735188D657B00B7BEB8 /* CartBFSCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartBFSCWidget.cxx; path = ../debugger/gui/CartBFSCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCB29736188D657B00B7BEB8 /* CartBFSCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartBFSCWidget.hxx; path = ../debugger/gui/CartBFSCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCB29737188D657B00B7BEB8 /* CartBFWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartBFWidget.cxx; path = ../debugger/gui/CartBFWidget.cxx; sourceTree = SOURCE_ROOT; }; DCB29738188D657B00B7BEB8 /* CartBFWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartBFWidget.hxx; path = ../debugger/gui/CartBFWidget.hxx; sourceTree = SOURCE_ROOT; }; DCB29739188D657B00B7BEB8 /* CartDFSCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDFSCWidget.cxx; path = ../debugger/gui/CartDFSCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCB2973A188D657B00B7BEB8 /* CartDFSCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDFSCWidget.hxx; path = ../debugger/gui/CartDFSCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCB2973B188D657B00B7BEB8 /* CartDFWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDFWidget.cxx; path = ../debugger/gui/CartDFWidget.cxx; sourceTree = SOURCE_ROOT; }; DCB2973C188D657B00B7BEB8 /* CartDFWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDFWidget.hxx; path = ../debugger/gui/CartDFWidget.hxx; sourceTree = SOURCE_ROOT; }; DCB31D3D17C2D667002C0868 /* ConsoleMediumFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ConsoleMediumFont.hxx; path = ../gui/ConsoleMediumFont.hxx; sourceTree = SOURCE_ROOT; }; DCB5CEE511F5B78C00C68D09 /* MessageBox.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MessageBox.cxx; path = ../gui/MessageBox.cxx; sourceTree = SOURCE_ROOT; }; DCB5CEE611F5B78C00C68D09 /* MessageBox.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = MessageBox.hxx; path = ../gui/MessageBox.hxx; sourceTree = SOURCE_ROOT; }; DCBD96871210314C0087CEFD /* ComboDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ComboDialog.cxx; path = ../gui/ComboDialog.cxx; sourceTree = SOURCE_ROOT; }; DCBD96881210314C0087CEFD /* ComboDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ComboDialog.hxx; path = ../gui/ComboDialog.hxx; sourceTree = SOURCE_ROOT; }; DCD56D360B247D920092F9F8 /* Cart4A50.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Cart4A50.cxx; path = ../emucore/Cart4A50.cxx; sourceTree = SOURCE_ROOT; }; DCD56D370B247D920092F9F8 /* Cart4A50.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cart4A50.hxx; path = ../emucore/Cart4A50.hxx; sourceTree = SOURCE_ROOT; }; DCD56D3A0B247DB40092F9F8 /* RectList.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RectList.cxx; path = ../common/RectList.cxx; sourceTree = SOURCE_ROOT; }; DCD56D3B0B247DB40092F9F8 /* RectList.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RectList.hxx; path = ../common/RectList.hxx; sourceTree = SOURCE_ROOT; }; DCDBD3151556F60C00308CC4 /* CartCTY.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartCTY.cxx; path = ../emucore/CartCTY.cxx; sourceTree = SOURCE_ROOT; }; DCDBD3161556F60C00308CC4 /* CartCTY.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartCTY.hxx; path = ../emucore/CartCTY.hxx; sourceTree = SOURCE_ROOT; }; DCDBD3171556F60C00308CC4 /* CartCTYTunes.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartCTYTunes.hxx; path = ../emucore/CartCTYTunes.hxx; sourceTree = SOURCE_ROOT; }; DCE3BBF50C95CEDC00A671DF /* RomInfoWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RomInfoWidget.cxx; path = ../gui/RomInfoWidget.cxx; sourceTree = SOURCE_ROOT; }; DCE3BBF60C95CEDC00A671DF /* RomInfoWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = RomInfoWidget.hxx; path = ../gui/RomInfoWidget.hxx; sourceTree = SOURCE_ROOT; }; DCE6EB200DD9ADA00047AC28 /* TrackBall.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TrackBall.cxx; path = ../emucore/TrackBall.cxx; sourceTree = SOURCE_ROOT; }; DCE6EB210DD9ADA00047AC28 /* TrackBall.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TrackBall.hxx; path = ../emucore/TrackBall.hxx; sourceTree = SOURCE_ROOT; }; DCE9CC261103812700C86671 /* CartDebug.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDebug.cxx; path = ../debugger/CartDebug.cxx; sourceTree = SOURCE_ROOT; }; DCE9CC271103812700C86671 /* CartDebug.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDebug.hxx; path = ../debugger/CartDebug.hxx; sourceTree = SOURCE_ROOT; }; DCE9CC281103812700C86671 /* DiStella.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DiStella.cxx; path = ../debugger/DiStella.cxx; sourceTree = SOURCE_ROOT; }; DCE9CC291103812700C86671 /* DiStella.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = DiStella.hxx; path = ../debugger/DiStella.hxx; sourceTree = SOURCE_ROOT; }; DCECD7A717A88E51000A9753 /* Base.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Base.cxx; path = ../common/Base.cxx; sourceTree = SOURCE_ROOT; }; DCECD7A817A88E51000A9753 /* Base.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Base.hxx; path = ../common/Base.hxx; sourceTree = SOURCE_ROOT; }; DCECDAF310B9DBDC00AF4E1B /* Device.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Device.hxx; path = ../emucore/Device.hxx; sourceTree = SOURCE_ROOT; }; DCECDAF410B9DBDC00AF4E1B /* M6502.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = M6502.cxx; path = ../emucore/M6502.cxx; sourceTree = SOURCE_ROOT; }; DCECDAF510B9DBDC00AF4E1B /* M6502.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = M6502.hxx; path = ../emucore/M6502.hxx; sourceTree = SOURCE_ROOT; }; DCECDAF610B9DBDC00AF4E1B /* NullDev.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NullDev.cxx; path = ../emucore/NullDev.cxx; sourceTree = SOURCE_ROOT; }; DCECDAF710B9DBDC00AF4E1B /* NullDev.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = NullDev.hxx; path = ../emucore/NullDev.hxx; sourceTree = SOURCE_ROOT; }; DCECDAF810B9DBDC00AF4E1B /* System.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = System.cxx; path = ../emucore/System.cxx; sourceTree = SOURCE_ROOT; }; DCECDAF910B9DBDC00AF4E1B /* System.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = System.hxx; path = ../emucore/System.hxx; sourceTree = SOURCE_ROOT; }; DCECDB0210B9DC0400AF4E1B /* bspf.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = bspf.hxx; path = ../common/bspf.hxx; sourceTree = SOURCE_ROOT; }; DCEECE540B5E5E540021D754 /* Cart0840.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Cart0840.cxx; path = ../emucore/Cart0840.cxx; sourceTree = SOURCE_ROOT; }; DCEECE550B5E5E540021D754 /* Cart0840.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Cart0840.hxx; path = ../emucore/Cart0840.hxx; sourceTree = SOURCE_ROOT; }; DCF28EAC1729A5CD00DD0CA9 /* Cart2KWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart2KWidget.cxx; path = ../debugger/gui/Cart2KWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EAD1729A5CD00DD0CA9 /* Cart2KWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart2KWidget.hxx; path = ../debugger/gui/Cart2KWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EAE1729A5CD00DD0CA9 /* Cart3EWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart3EWidget.cxx; path = ../debugger/gui/Cart3EWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EAF1729A5CD00DD0CA9 /* Cart3EWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart3EWidget.hxx; path = ../debugger/gui/Cart3EWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EB01729A5CD00DD0CA9 /* Cart3FWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart3FWidget.cxx; path = ../debugger/gui/Cart3FWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EB11729A5CD00DD0CA9 /* Cart3FWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart3FWidget.hxx; path = ../debugger/gui/Cart3FWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EB21729A5CD00DD0CA9 /* Cart4A50Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart4A50Widget.cxx; path = ../debugger/gui/Cart4A50Widget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EB31729A5CD00DD0CA9 /* Cart4A50Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart4A50Widget.hxx; path = ../debugger/gui/Cart4A50Widget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EB41729A5CD00DD0CA9 /* Cart4KWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart4KWidget.cxx; path = ../debugger/gui/Cart4KWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EB51729A5CD00DD0CA9 /* Cart4KWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart4KWidget.hxx; path = ../debugger/gui/Cart4KWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EB61729A5CD00DD0CA9 /* Cart0840Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cart0840Widget.cxx; path = ../debugger/gui/Cart0840Widget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EB71729A5CD00DD0CA9 /* Cart0840Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Cart0840Widget.hxx; path = ../debugger/gui/Cart0840Widget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EB81729A5CD00DD0CA9 /* CartARWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartARWidget.cxx; path = ../debugger/gui/CartARWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EB91729A5CD00DD0CA9 /* CartARWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartARWidget.hxx; path = ../debugger/gui/CartARWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EBA1729A5CD00DD0CA9 /* CartCMWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartCMWidget.cxx; path = ../debugger/gui/CartCMWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EBB1729A5CD00DD0CA9 /* CartCMWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartCMWidget.hxx; path = ../debugger/gui/CartCMWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EBC1729A5CD00DD0CA9 /* CartCTYWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartCTYWidget.cxx; path = ../debugger/gui/CartCTYWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EBD1729A5CD00DD0CA9 /* CartCTYWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartCTYWidget.hxx; path = ../debugger/gui/CartCTYWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EBE1729A5CD00DD0CA9 /* CartCVWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartCVWidget.cxx; path = ../debugger/gui/CartCVWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EBF1729A5CD00DD0CA9 /* CartCVWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartCVWidget.hxx; path = ../debugger/gui/CartCVWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EC01729A5CD00DD0CA9 /* CartDebugWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDebugWidget.hxx; path = ../debugger/gui/CartDebugWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EC11729A5CD00DD0CA9 /* CartDPCPlusWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDPCPlusWidget.cxx; path = ../debugger/gui/CartDPCPlusWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EC21729A5CD00DD0CA9 /* CartDPCPlusWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDPCPlusWidget.hxx; path = ../debugger/gui/CartDPCPlusWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EC31729A5CD00DD0CA9 /* CartDPCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartDPCWidget.cxx; path = ../debugger/gui/CartDPCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EC41729A5CD00DD0CA9 /* CartDPCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartDPCWidget.hxx; path = ../debugger/gui/CartDPCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EC51729A5CD00DD0CA9 /* CartE0Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartE0Widget.cxx; path = ../debugger/gui/CartE0Widget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EC61729A5CD00DD0CA9 /* CartE0Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartE0Widget.hxx; path = ../debugger/gui/CartE0Widget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EC71729A5CD00DD0CA9 /* CartE7Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartE7Widget.cxx; path = ../debugger/gui/CartE7Widget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EC81729A5CD00DD0CA9 /* CartE7Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartE7Widget.hxx; path = ../debugger/gui/CartE7Widget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EC91729A5CD00DD0CA9 /* CartEFSCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartEFSCWidget.cxx; path = ../debugger/gui/CartEFSCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28ECA1729A5CD00DD0CA9 /* CartEFSCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartEFSCWidget.hxx; path = ../debugger/gui/CartEFSCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28ECB1729A5CD00DD0CA9 /* CartEFWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartEFWidget.cxx; path = ../debugger/gui/CartEFWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28ECC1729A5CD00DD0CA9 /* CartEFWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartEFWidget.hxx; path = ../debugger/gui/CartEFWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28ECD1729A5CD00DD0CA9 /* CartF0Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF0Widget.cxx; path = ../debugger/gui/CartF0Widget.cxx; sourceTree = SOURCE_ROOT; }; DCF28ECE1729A5CD00DD0CA9 /* CartF0Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF0Widget.hxx; path = ../debugger/gui/CartF0Widget.hxx; sourceTree = SOURCE_ROOT; }; DCF28ECF1729A5CD00DD0CA9 /* CartF4SCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF4SCWidget.cxx; path = ../debugger/gui/CartF4SCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28ED01729A5CD00DD0CA9 /* CartF4SCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF4SCWidget.hxx; path = ../debugger/gui/CartF4SCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28ED11729A5CD00DD0CA9 /* CartF4Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF4Widget.cxx; path = ../debugger/gui/CartF4Widget.cxx; sourceTree = SOURCE_ROOT; }; DCF28ED21729A5CD00DD0CA9 /* CartF4Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF4Widget.hxx; path = ../debugger/gui/CartF4Widget.hxx; sourceTree = SOURCE_ROOT; }; DCF28ED31729A5CD00DD0CA9 /* CartF6SCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF6SCWidget.cxx; path = ../debugger/gui/CartF6SCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28ED41729A5CD00DD0CA9 /* CartF6SCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF6SCWidget.hxx; path = ../debugger/gui/CartF6SCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28ED51729A5CD00DD0CA9 /* CartF6Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF6Widget.cxx; path = ../debugger/gui/CartF6Widget.cxx; sourceTree = SOURCE_ROOT; }; DCF28ED61729A5CD00DD0CA9 /* CartF6Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF6Widget.hxx; path = ../debugger/gui/CartF6Widget.hxx; sourceTree = SOURCE_ROOT; }; DCF28ED71729A5CD00DD0CA9 /* CartF8SCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF8SCWidget.cxx; path = ../debugger/gui/CartF8SCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28ED81729A5CD00DD0CA9 /* CartF8SCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF8SCWidget.hxx; path = ../debugger/gui/CartF8SCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28ED91729A5CD00DD0CA9 /* CartF8Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF8Widget.cxx; path = ../debugger/gui/CartF8Widget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EDA1729A5CD00DD0CA9 /* CartF8Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF8Widget.hxx; path = ../debugger/gui/CartF8Widget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EDB1729A5CD00DD0CA9 /* CartFA2Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartFA2Widget.cxx; path = ../debugger/gui/CartFA2Widget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EDC1729A5CD00DD0CA9 /* CartFA2Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartFA2Widget.hxx; path = ../debugger/gui/CartFA2Widget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EDD1729A5CD00DD0CA9 /* CartFAWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartFAWidget.cxx; path = ../debugger/gui/CartFAWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EDE1729A5CD00DD0CA9 /* CartFAWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartFAWidget.hxx; path = ../debugger/gui/CartFAWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EDF1729A5CD00DD0CA9 /* CartFEWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartFEWidget.cxx; path = ../debugger/gui/CartFEWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EE01729A5CD00DD0CA9 /* CartFEWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartFEWidget.hxx; path = ../debugger/gui/CartFEWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EE11729A5CD00DD0CA9 /* CartMCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartMCWidget.cxx; path = ../debugger/gui/CartMCWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EE21729A5CD00DD0CA9 /* CartMCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartMCWidget.hxx; path = ../debugger/gui/CartMCWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EE31729A5CD00DD0CA9 /* CartSBWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartSBWidget.cxx; path = ../debugger/gui/CartSBWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EE41729A5CD00DD0CA9 /* CartSBWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartSBWidget.hxx; path = ../debugger/gui/CartSBWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EE51729A5CD00DD0CA9 /* CartUAWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartUAWidget.cxx; path = ../debugger/gui/CartUAWidget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EE61729A5CD00DD0CA9 /* CartUAWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartUAWidget.hxx; path = ../debugger/gui/CartUAWidget.hxx; sourceTree = SOURCE_ROOT; }; DCF28EE71729A5CD00DD0CA9 /* CartX07Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartX07Widget.cxx; path = ../debugger/gui/CartX07Widget.cxx; sourceTree = SOURCE_ROOT; }; DCF28EE81729A5CD00DD0CA9 /* CartX07Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartX07Widget.hxx; path = ../debugger/gui/CartX07Widget.hxx; sourceTree = SOURCE_ROOT; }; DCF467B10F93993B00B25D7A /* Array.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Array.hxx; path = ../common/Array.hxx; sourceTree = SOURCE_ROOT; }; DCF467B20F93993B00B25D7A /* SharedPtr.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = SharedPtr.hxx; path = ../common/SharedPtr.hxx; sourceTree = SOURCE_ROOT; }; DCF467B40F93993B00B25D7A /* SoundNull.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = SoundNull.hxx; path = ../common/SoundNull.hxx; sourceTree = SOURCE_ROOT; }; DCF467BC0F9399F500B25D7A /* Version.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Version.hxx; path = ../common/Version.hxx; sourceTree = SOURCE_ROOT; }; DCF467BE0F939A1400B25D7A /* CartEF.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartEF.cxx; path = ../emucore/CartEF.cxx; sourceTree = SOURCE_ROOT; }; DCF467BF0F939A1400B25D7A /* CartEF.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartEF.hxx; path = ../emucore/CartEF.hxx; sourceTree = SOURCE_ROOT; }; DCF467C00F939A1400B25D7A /* CartEFSC.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartEFSC.cxx; path = ../emucore/CartEFSC.cxx; sourceTree = SOURCE_ROOT; }; DCF467C10F939A1400B25D7A /* CartEFSC.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartEFSC.hxx; path = ../emucore/CartEFSC.hxx; sourceTree = SOURCE_ROOT; }; DCF7B0D910A762FC007A2870 /* CartF0.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartF0.cxx; path = ../emucore/CartF0.cxx; sourceTree = SOURCE_ROOT; }; DCF7B0DA10A762FC007A2870 /* CartF0.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartF0.hxx; path = ../emucore/CartF0.hxx; sourceTree = SOURCE_ROOT; }; DCF7B0DB10A762FC007A2870 /* CartFA.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartFA.cxx; path = ../emucore/CartFA.cxx; sourceTree = SOURCE_ROOT; }; DCF7B0DC10A762FC007A2870 /* CartFA.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartFA.hxx; path = ../emucore/CartFA.hxx; sourceTree = SOURCE_ROOT; }; 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 = ( 2D91750F09BA90380026E9FF /* Cocoa.framework in Frameworks */, 2D91751009BA90380026E9FF /* OpenGL.framework in Frameworks */, 2D91751109BA90380026E9FF /* SDL.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 = ""; }; 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, ); name = "Linked Frameworks"; sourceTree = ""; }; 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { isa = PBXGroup; children = ( 2D17D98E08BC398400E47F69 /* ApplicationServices.framework */, 2D4764C806683C5F00F63D87 /* SDL.framework */, 2DEB3D4C0629BD24007EBBD3 /* OpenGL.framework */, 29B97325FDCFA39411CA2CEA /* Foundation.framework */, 29B97324FDCFA39411CA2CEA /* AppKit.framework */, ); name = "Other Frameworks"; sourceTree = ""; }; 19C28FACFE9D520D11CA2CBB /* Products */ = { isa = PBXGroup; children = ( 2D91751E09BA90390026E9FF /* Stella.app */, ); name = Products; sourceTree = ""; }; 29B97314FDCFA39411CA2CEA /* «PROJECTNAMEASXML» */ = { isa = PBXGroup; children = ( DC419D81108E10A3006E8687 /* Info-Stella.plist */, 080E96DDFE201D6D7F000001 /* Classes */, 29B97315FDCFA39411CA2CEA /* Other Sources */, 29B97317FDCFA39411CA2CEA /* Resources */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, ); name = "«PROJECTNAMEASXML»"; sourceTree = ""; }; 29B97315FDCFA39411CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( DCCC0C9109C3541E0088BFF1 /* cheat */, 2D6050C5089876F300C6DE89 /* common */, 2D605130089879BA00C6DE89 /* debugger */, 2D6050CC0898776500C6DE89 /* emucore */, 2D6050FA0898786C00C6DE89 /* gui */, DC3FE46711C7D32500C91C72 /* libpng */, 2D6050C60898771C00C6DE89 /* macosx */, 2D6050C90898774B00C6DE89 /* unix */, 2D60513708987A5400C6DE89 /* yacc */, ); name = "Other Sources"; sourceTree = ""; }; 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( 2D113E090672BF2100317017 /* ../../docs */, 2D16A8E106324136005DF364 /* Stella.icns */, 2DEFB40B09C3386F00754289 /* Cart.icns */, 2D7B4F6C063B513200579B93 /* Credits.html */, 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, B2F367C504C7ADC700A80002 /* SDLMain.nib */, 2D1A6CD808513610007CDBA8 /* AboutBox.nib */, ); name = Resources; sourceTree = ""; }; 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; 2D20F9E308C603C500A73076 /* gui */ = { isa = PBXGroup; children = ( 2D23318F0900B5EF00613B1F /* AudioWidget.cxx */, 2D2331900900B5EF00613B1F /* AudioWidget.hxx */, DC0BFFEB14BA2BEB00CF5E7E /* BoosterWidget.cxx */, DC0BFFEC14BA2BEB00CF5E7E /* BoosterWidget.hxx */, DCF28EB61729A5CD00DD0CA9 /* Cart0840Widget.cxx */, DCF28EB71729A5CD00DD0CA9 /* Cart0840Widget.hxx */, DCF28EAC1729A5CD00DD0CA9 /* Cart2KWidget.cxx */, DCF28EAD1729A5CD00DD0CA9 /* Cart2KWidget.hxx */, DCF28EAE1729A5CD00DD0CA9 /* Cart3EWidget.cxx */, DCF28EAF1729A5CD00DD0CA9 /* Cart3EWidget.hxx */, DCF28EB01729A5CD00DD0CA9 /* Cart3FWidget.cxx */, DCF28EB11729A5CD00DD0CA9 /* Cart3FWidget.hxx */, DCF28EB21729A5CD00DD0CA9 /* Cart4A50Widget.cxx */, DCF28EB31729A5CD00DD0CA9 /* Cart4A50Widget.hxx */, DCB29733188D657B00B7BEB8 /* Cart4KSCWidget.cxx */, DCB29734188D657B00B7BEB8 /* Cart4KSCWidget.hxx */, DCF28EB41729A5CD00DD0CA9 /* Cart4KWidget.cxx */, DCF28EB51729A5CD00DD0CA9 /* Cart4KWidget.hxx */, DCF28EB81729A5CD00DD0CA9 /* CartARWidget.cxx */, DCF28EB91729A5CD00DD0CA9 /* CartARWidget.hxx */, DCB29735188D657B00B7BEB8 /* CartBFSCWidget.cxx */, DCB29736188D657B00B7BEB8 /* CartBFSCWidget.hxx */, DCB29737188D657B00B7BEB8 /* CartBFWidget.cxx */, DCB29738188D657B00B7BEB8 /* CartBFWidget.hxx */, DCF28EBA1729A5CD00DD0CA9 /* CartCMWidget.cxx */, DCF28EBB1729A5CD00DD0CA9 /* CartCMWidget.hxx */, DCF28EBC1729A5CD00DD0CA9 /* CartCTYWidget.cxx */, DCF28EBD1729A5CD00DD0CA9 /* CartCTYWidget.hxx */, DCF28EBE1729A5CD00DD0CA9 /* CartCVWidget.cxx */, DCF28EBF1729A5CD00DD0CA9 /* CartCVWidget.hxx */, DCF28EC01729A5CD00DD0CA9 /* CartDebugWidget.hxx */, DCB29739188D657B00B7BEB8 /* CartDFSCWidget.cxx */, DCB2973A188D657B00B7BEB8 /* CartDFSCWidget.hxx */, DCB2973B188D657B00B7BEB8 /* CartDFWidget.cxx */, DCB2973C188D657B00B7BEB8 /* CartDFWidget.hxx */, DCF28EC11729A5CD00DD0CA9 /* CartDPCPlusWidget.cxx */, DCF28EC21729A5CD00DD0CA9 /* CartDPCPlusWidget.hxx */, DCF28EC31729A5CD00DD0CA9 /* CartDPCWidget.cxx */, DCF28EC41729A5CD00DD0CA9 /* CartDPCWidget.hxx */, DCF28EC51729A5CD00DD0CA9 /* CartE0Widget.cxx */, DCF28EC61729A5CD00DD0CA9 /* CartE0Widget.hxx */, DCF28EC71729A5CD00DD0CA9 /* CartE7Widget.cxx */, DCF28EC81729A5CD00DD0CA9 /* CartE7Widget.hxx */, DCF28EC91729A5CD00DD0CA9 /* CartEFSCWidget.cxx */, DCF28ECA1729A5CD00DD0CA9 /* CartEFSCWidget.hxx */, DCF28ECB1729A5CD00DD0CA9 /* CartEFWidget.cxx */, DCF28ECC1729A5CD00DD0CA9 /* CartEFWidget.hxx */, DCF28ECD1729A5CD00DD0CA9 /* CartF0Widget.cxx */, DCF28ECE1729A5CD00DD0CA9 /* CartF0Widget.hxx */, DCF28ECF1729A5CD00DD0CA9 /* CartF4SCWidget.cxx */, DCF28ED01729A5CD00DD0CA9 /* CartF4SCWidget.hxx */, DCF28ED11729A5CD00DD0CA9 /* CartF4Widget.cxx */, DCF28ED21729A5CD00DD0CA9 /* CartF4Widget.hxx */, DCF28ED31729A5CD00DD0CA9 /* CartF6SCWidget.cxx */, DCF28ED41729A5CD00DD0CA9 /* CartF6SCWidget.hxx */, DCF28ED51729A5CD00DD0CA9 /* CartF6Widget.cxx */, DCF28ED61729A5CD00DD0CA9 /* CartF6Widget.hxx */, DCF28ED71729A5CD00DD0CA9 /* CartF8SCWidget.cxx */, DCF28ED81729A5CD00DD0CA9 /* CartF8SCWidget.hxx */, DCF28ED91729A5CD00DD0CA9 /* CartF8Widget.cxx */, DCF28EDA1729A5CD00DD0CA9 /* CartF8Widget.hxx */, DCF28EDB1729A5CD00DD0CA9 /* CartFA2Widget.cxx */, DCF28EDC1729A5CD00DD0CA9 /* CartFA2Widget.hxx */, DCF28EDD1729A5CD00DD0CA9 /* CartFAWidget.cxx */, DCF28EDE1729A5CD00DD0CA9 /* CartFAWidget.hxx */, DCF28EDF1729A5CD00DD0CA9 /* CartFEWidget.cxx */, DCF28EE01729A5CD00DD0CA9 /* CartFEWidget.hxx */, DCF28EE11729A5CD00DD0CA9 /* CartMCWidget.cxx */, DCF28EE21729A5CD00DD0CA9 /* CartMCWidget.hxx */, DCF28EE31729A5CD00DD0CA9 /* CartSBWidget.cxx */, DCF28EE41729A5CD00DD0CA9 /* CartSBWidget.hxx */, DCF28EE51729A5CD00DD0CA9 /* CartUAWidget.cxx */, DCF28EE61729A5CD00DD0CA9 /* CartUAWidget.hxx */, DCF28EE71729A5CD00DD0CA9 /* CartX07Widget.cxx */, DCF28EE81729A5CD00DD0CA9 /* CartX07Widget.hxx */, 2D20F9E408C603EC00A73076 /* ColorWidget.cxx */, 2D20F9E508C603EC00A73076 /* ColorWidget.hxx */, DC0BFFED14BA2BEB00CF5E7E /* 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 */, DC0BFFEE14BA2BEB00CF5E7E /* DrivingWidget.cxx */, DC0BFFEF14BA2BEB00CF5E7E /* DrivingWidget.hxx */, DC0BFFF014BA2BEB00CF5E7E /* GenesisWidget.cxx */, DC0BFFF114BA2BEB00CF5E7E /* GenesisWidget.hxx */, DC0BFFF214BA2BEB00CF5E7E /* JoystickWidget.cxx */, DC0BFFF314BA2BEB00CF5E7E /* JoystickWidget.hxx */, DC0BFFF414BA2BEB00CF5E7E /* KeyboardWidget.cxx */, DC0BFFF514BA2BEB00CF5E7E /* KeyboardWidget.hxx */, DC0BFFF614BA2BEB00CF5E7E /* NullControlWidget.hxx */, DC0BFFF714BA2BEB00CF5E7E /* PaddleWidget.cxx */, DC0BFFF814BA2BEB00CF5E7E /* PaddleWidget.hxx */, 2D20F9EE08C603EC00A73076 /* PromptWidget.cxx */, 2D20F9EF08C603EC00A73076 /* PromptWidget.hxx */, 2D20F9F008C603EC00A73076 /* RamWidget.cxx */, 2D20F9F108C603EC00A73076 /* RamWidget.hxx */, DC4AC6ED0DC8DACB00CD3AD2 /* RiotWidget.cxx */, DC4AC6EE0DC8DACB00CD3AD2 /* RiotWidget.hxx */, DC449CAD176FF512004FA2D4 /* RomListSettings.cxx */, DC449CAE176FF512004FA2D4 /* RomListSettings.hxx */, 2D20F9F208C603EC00A73076 /* RomListWidget.cxx */, 2D20F9F308C603EC00A73076 /* RomListWidget.hxx */, 2D20F9F408C603EC00A73076 /* RomWidget.cxx */, 2D20F9F508C603EC00A73076 /* RomWidget.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 */, ); name = gui; sourceTree = ""; }; 2D6050C5089876F300C6DE89 /* common */ = { isa = PBXGroup; children = ( DCF467B10F93993B00B25D7A /* Array.hxx */, DCECD7A717A88E51000A9753 /* Base.cxx */, DCECD7A817A88E51000A9753 /* Base.hxx */, DCECDB0210B9DC0400AF4E1B /* bspf.hxx */, DC8AE5BF1417804C00335D45 /* FBSurfaceGL.cxx */, DC8AE5C01417804C00335D45 /* FBSurfaceGL.hxx */, DC8AE5C11417804C00335D45 /* FBSurfaceTIA.cxx */, DC8AE5C21417804C00335D45 /* FBSurfaceTIA.hxx */, 2D733D5D062893E7006265D9 /* FrameBufferGL.cxx */, 2D733D5E062893E7006265D9 /* FrameBufferGL.hxx */, 2D733D61062893E7006265D9 /* FrameBufferSoft.cxx */, 2D733D62062893E7006265D9 /* FrameBufferSoft.hxx */, DCA6276F16CB0D45004E9AF0 /* FSNodeFactory.hxx */, DCA6277016CB0D45004E9AF0 /* FSNodeZIP.cxx */, DCA6277116CB0D45004E9AF0 /* FSNodeZIP.hxx */, 2DDBEA0A0845700300812C11 /* mainSDL.cxx */, DCAE2A9114CCCCBD004327BB /* MouseControl.cxx */, DCAE2A9214CCCCBD004327BB /* MouseControl.hxx */, DC3FE49D11C7D3FE00C91C72 /* PNGLibrary.cxx */, DC3FE49E11C7D3FE00C91C72 /* PNGLibrary.hxx */, DCD56D3A0B247DB40092F9F8 /* RectList.cxx */, DCD56D3B0B247DB40092F9F8 /* RectList.hxx */, DCF467B20F93993B00B25D7A /* SharedPtr.hxx */, DCF467B40F93993B00B25D7A /* SoundNull.hxx */, 2DDA34020665817D00CDD299 /* SoundSDL.cxx */, 2DDA34030665817D00CDD299 /* SoundSDL.hxx */, DC5D1AA6102C6FC900E59AC1 /* Stack.hxx */, DC5C76AF14C2709E0031EBC7 /* StellaKeys.hxx */, DC20D6F1138EB130002A7428 /* StringList.hxx */, DC20D6F2138EB130002A7428 /* StringParser.hxx */, DC881B87151676A200021371 /* tv_filters */, DC3C3CDB173B1EB2009FFE61 /* Variant.hxx */, DCF467BC0F9399F500B25D7A /* Version.hxx */, DCA6277216CB0D45004E9AF0 /* ZipHandler.cxx */, DCA6277316CB0D45004E9AF0 /* ZipHandler.hxx */, ); name = common; sourceTree = ""; }; 2D6050C60898771C00C6DE89 /* macosx */ = { isa = PBXGroup; children = ( 2D28DDE409DC2D9F00A17585 /* MenusEvents.h */, 2DDBEA0E0845709700812C11 /* OSystemMACOSX.cxx */, 2DDBEA0F0845709700812C11 /* OSystemMACOSX.hxx */, DC1FC1880DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx */, DC1FC1890DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx */, 2D944866062911CD00DD9879 /* SettingsMACOSX.cxx */, 2D94486C0629124700DD9879 /* SettingsMACOSX.hxx */, ); name = macosx; sourceTree = ""; }; 2D6050C90898774B00C6DE89 /* unix */ = { isa = PBXGroup; children = ( 2DDBEA0C0845708800812C11 /* FSNodePOSIX.cxx */, DCA6276016CB0D1C004E9AF0 /* FSNodePOSIX.hxx */, ); name = unix; sourceTree = ""; }; 2D6050CC0898776500C6DE89 /* emucore */ = { isa = PBXGroup; children = ( DC487FB40DA5350900E12499 /* AtariVox.cxx */, DC487FB50DA5350900E12499 /* AtariVox.hxx */, 2DE2DF100627AE07006BEC99 /* Booster.cxx */, 2DE2DF110627AE07006BEC99 /* Booster.hxx */, 2DE2DF120627AE07006BEC99 /* Cart.cxx */, 2DE2DF130627AE07006BEC99 /* Cart.hxx */, DCEECE540B5E5E540021D754 /* Cart0840.cxx */, DCEECE550B5E5E540021D754 /* Cart0840.hxx */, 2DE2DF140627AE07006BEC99 /* Cart2K.cxx */, 2DE2DF150627AE07006BEC99 /* Cart2K.hxx */, 2D9555D90880E78000466554 /* Cart3E.cxx */, 2D9555DA0880E78000466554 /* Cart3E.hxx */, 2DE2DF160627AE07006BEC99 /* Cart3F.cxx */, 2DE2DF170627AE07006BEC99 /* Cart3F.hxx */, DCD56D360B247D920092F9F8 /* Cart4A50.cxx */, DCD56D370B247D920092F9F8 /* Cart4A50.hxx */, 2DE2DF180627AE07006BEC99 /* Cart4K.cxx */, 2DE2DF190627AE07006BEC99 /* Cart4K.hxx */, DCB2971D188D655000B7BEB8 /* Cart4KSC.cxx */, DCB2971E188D655000B7BEB8 /* Cart4KSC.hxx */, 2DE2DF1A0627AE07006BEC99 /* CartAR.cxx */, 2DE2DF1B0627AE07006BEC99 /* CartAR.hxx */, DCB2971F188D655000B7BEB8 /* CartBF.cxx */, DCB29720188D655000B7BEB8 /* CartBF.hxx */, DCB29721188D655000B7BEB8 /* CartBFSC.cxx */, DCB29722188D655000B7BEB8 /* CartBFSC.hxx */, DC3E4A6014B25EB30071D7BC /* CartCM.cxx */, DC3E4A6114B25EB30071D7BC /* CartCM.hxx */, DCDBD3151556F60C00308CC4 /* CartCTY.cxx */, DCDBD3161556F60C00308CC4 /* CartCTY.hxx */, DCDBD3171556F60C00308CC4 /* CartCTYTunes.hxx */, 2DE2DF1C0627AE07006BEC99 /* CartCV.cxx */, 2DE2DF1D0627AE07006BEC99 /* CartCV.hxx */, DCB29723188D655000B7BEB8 /* CartDF.cxx */, DCB29724188D655000B7BEB8 /* CartDF.hxx */, DCB29725188D655000B7BEB8 /* CartDFSC.cxx */, DCB29726188D655000B7BEB8 /* CartDFSC.hxx */, 2DE2DF1E0627AE07006BEC99 /* CartDPC.cxx */, 2DE2DF1F0627AE07006BEC99 /* CartDPC.hxx */, DC64EB1E1152F9C000DC9140 /* CartDPCPlus.cxx */, DC64EB1F1152F9C000DC9140 /* CartDPCPlus.hxx */, 2DE2DF200627AE07006BEC99 /* CartE0.cxx */, 2DE2DF210627AE07006BEC99 /* CartE0.hxx */, 2DE2DF220627AE07006BEC99 /* CartE7.cxx */, 2DE2DF230627AE07006BEC99 /* CartE7.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 */, DC922D0414CAFB1E006EB471 /* CartFA2.cxx */, DC922D0514CAFB1E006EB471 /* CartFA2.hxx */, 2DE2DF320627AE07006BEC99 /* CartFE.cxx */, 2DE2DF330627AE07006BEC99 /* CartFE.hxx */, 2DE2DF360627AE07006BEC99 /* CartMC.cxx */, 2DE2DF370627AE07006BEC99 /* CartMC.hxx */, DC0984830D3985160073C852 /* CartSB.cxx */, DC0984840D3985160073C852 /* CartSB.hxx */, 2DDBEB7008457B7D00812C11 /* CartUA.cxx */, 2DDBEB7108457B7D00812C11 /* CartUA.hxx */, DCA23AE70D75B22500F77B33 /* CartX07.cxx */, DCA23AE80D75B22500F77B33 /* CartX07.hxx */, DC3E4A6214B25EB30071D7BC /* CompuMate.cxx */, DC3E4A6314B25EB30071D7BC /* CompuMate.hxx */, 2DE2DF380627AE07006BEC99 /* Console.cxx */, 2DE2DF390627AE07006BEC99 /* Console.hxx */, 2DE2DF3A0627AE07006BEC99 /* Control.cxx */, 2DE2DF3B0627AE07006BEC99 /* Control.hxx */, DC932D3F0F278A5200FEFEFC /* DefProps.hxx */, DCECDAF310B9DBDC00AF4E1B /* Device.hxx */, 2DE2DF3E0627AE07006BEC99 /* Driving.cxx */, 2DE2DF3F0627AE07006BEC99 /* Driving.hxx */, 2DE2DF410627AE07006BEC99 /* Event.hxx */, 2D733D6E062895B2006265D9 /* EventHandler.cxx */, 2D733D6F062895B2006265D9 /* EventHandler.hxx */, 2D733D70062895B2006265D9 /* FrameBuffer.cxx */, 2D733D71062895B2006265D9 /* FrameBuffer.hxx */, 2DDBEB7208457B7D00812C11 /* FSNode.cxx */, 2DDBEB7308457B7D00812C11 /* FSNode.hxx */, DC84E11A1135988E00CA7C9D /* Genesis.cxx */, DC84E11B1135988E00CA7C9D /* Genesis.hxx */, 2DE2DF420627AE07006BEC99 /* Joystick.cxx */, 2DE2DF430627AE07006BEC99 /* Joystick.hxx */, 2DE2DF440627AE07006BEC99 /* Keyboard.cxx */, 2DE2DF450627AE07006BEC99 /* Keyboard.hxx */, DC9EA8850F729A36000452B5 /* KidVid.cxx */, DC9EA8860F729A36000452B5 /* KidVid.hxx */, DCECDAF410B9DBDC00AF4E1B /* M6502.cxx */, DCECDAF510B9DBDC00AF4E1B /* M6502.hxx */, 2DE2DF7C0627AE33006BEC99 /* M6532.cxx */, 2DE2DF7D0627AE33006BEC99 /* M6532.hxx */, 2DE2DF7E0627AE33006BEC99 /* MD5.cxx */, 2DE2DF7F0627AE34006BEC99 /* MD5.hxx */, 2D05FF5B096E261E00A518FE /* MediaFactory.hxx */, DC3E4A6414B25EB30071D7BC /* MindLink.cxx */, DC3E4A6514B25EB30071D7BC /* MindLink.hxx */, DC11F78B0DB36933003B505E /* MT24LC256.cxx */, DC11F78C0DB36933003B505E /* MT24LC256.hxx */, DCECDAF610B9DBDC00AF4E1B /* NullDev.cxx */, DCECDAF710B9DBDC00AF4E1B /* NullDev.hxx */, 2DDBEB7408457B7D00812C11 /* OSystem.cxx */, 2DDBEB7508457B7D00812C11 /* OSystem.hxx */, 2DE2DF820627AE34006BEC99 /* Paddles.cxx */, 2DE2DF830627AE34006BEC99 /* Paddles.hxx */, 2DE2DF840627AE34006BEC99 /* Props.cxx */, 2DE2DF850627AE34006BEC99 /* Props.hxx */, 2DE2DF860627AE34006BEC99 /* PropsSet.cxx */, 2DE2DF870627AE34006BEC99 /* PropsSet.hxx */, 2DE2DF880627AE34006BEC99 /* Random.cxx */, 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 */, DC07A3C60CAD738A009B4BC9 /* StateManager.cxx */, DC07A3C70CAD738A009B4BC9 /* StateManager.hxx */, 2DE2DF8E0627AE34006BEC99 /* Switches.cxx */, 2DE2DF8F0627AE34006BEC99 /* Switches.hxx */, DCECDAF810B9DBDC00AF4E1B /* System.cxx */, DCECDAF910B9DBDC00AF4E1B /* System.hxx */, DC4AF1F112E39F700090B82E /* Thumbulator.cxx */, DC4AF1F212E39F700090B82E /* Thumbulator.hxx */, 2DE2DF900627AE34006BEC99 /* TIA.cxx */, 2DE2DF910627AE34006BEC99 /* TIA.hxx */, 2DE7242D08CE910900C889A8 /* TIASnd.cxx */, 2DE7242E08CE910900C889A8 /* TIASnd.hxx */, DC932D420F278A5200FEFEFC /* TIATables.cxx */, DC932D430F278A5200FEFEFC /* TIATables.hxx */, DCE6EB200DD9ADA00047AC28 /* TrackBall.cxx */, DCE6EB210DD9ADA00047AC28 /* TrackBall.hxx */, ); name = 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 */, DCBD96871210314C0087CEFD /* ComboDialog.cxx */, DCBD96881210314C0087CEFD /* ComboDialog.hxx */, 2DDBEAAA084578BF00812C11 /* Command.hxx */, 2D73959308C3EB4E0060BB99 /* CommandDialog.cxx */, 2D73959408C3EB4E0060BB99 /* CommandDialog.hxx */, 2D73959508C3EB4E0060BB99 /* CommandMenu.cxx */, 2D73959608C3EB4E0060BB99 /* CommandMenu.hxx */, DC0D76A2177259C3005C7805 /* ConfigPathDialog.cxx */, DC0D76A3177259C3005C7805 /* ConfigPathDialog.hxx */, DC3F601517C9140100A1977D /* ConsoleBFont.hxx */, 2D9217FA0857CC88001D664B /* ConsoleFont.hxx */, DC3F601617C9140100A1977D /* ConsoleMediumBFont.hxx */, DCB31D3D17C2D667002C0868 /* ConsoleMediumFont.hxx */, DC173F740E2CAC1E00320F94 /* ContextMenu.cxx */, DC173F750E2CAC1E00320F94 /* ContextMenu.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 */, DC3C3CDF173B1EC8009FFE61 /* FileListWidget.cxx */, DC3C3CE0173B1EC8009FFE61 /* 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 */, 2DDBEABA084578BF00812C11 /* Launcher.cxx */, 2DDBEABB084578BF00812C11 /* Launcher.hxx */, 2DDBEABC084578BF00812C11 /* LauncherDialog.cxx */, 2DDBEABD084578BF00812C11 /* LauncherDialog.hxx */, DC5D2C5E0F129B1E004D1660 /* LauncherFilterDialog.cxx */, DC5D2C5F0F129B1E004D1660 /* LauncherFilterDialog.hxx */, 2DDBEAC0084578BF00812C11 /* ListWidget.cxx */, 2DDBEAC1084578BF00812C11 /* ListWidget.hxx */, DC7A769813FEA40300ED8633 /* LoggerDialog.cxx */, DC7A769913FEA40300ED8633 /* LoggerDialog.hxx */, 2DDBEAC2084578BF00812C11 /* Menu.cxx */, 2DDBEAC3084578BF00812C11 /* Menu.hxx */, DCB5CEE511F5B78C00C68D09 /* MessageBox.cxx */, DCB5CEE611F5B78C00C68D09 /* MessageBox.hxx */, 2DDBEAC4084578BF00812C11 /* OptionsDialog.cxx */, 2DDBEAC5084578BF00812C11 /* OptionsDialog.hxx */, 2DDBEAC6084578BF00812C11 /* PopUpWidget.cxx */, 2DDBEAC7084578BF00812C11 /* PopUpWidget.hxx */, 2DDBEAC8084578BF00812C11 /* ProgressDialog.cxx */, 2DDBEAC9084578BF00812C11 /* ProgressDialog.hxx */, DC5D2C4E0F117CFD004D1660 /* Rect.hxx */, DC4613650D92C03600D8DAB9 /* RomAuditDialog.cxx */, DC4613660D92C03600D8DAB9 /* RomAuditDialog.hxx */, DCE3BBF50C95CEDC00A671DF /* RomInfoWidget.cxx */, DCE3BBF60C95CEDC00A671DF /* RomInfoWidget.hxx */, 2DDBEACA084578BF00812C11 /* ScrollBarWidget.cxx */, 2DDBEACB084578BF00812C11 /* ScrollBarWidget.hxx */, DC0D76A4177259C3005C7805 /* SnapshotDialog.cxx */, DC0D76A5177259C3005C7805 /* SnapshotDialog.hxx */, DC5D2C4F0F117CFD004D1660 /* StellaFont.hxx */, DC5D2C500F117CFD004D1660 /* StellaLargeFont.hxx */, DC5D2C510F117CFD004D1660 /* StellaMediumFont.hxx */, 2DEF21FA08BC033500B246B4 /* StringListWidget.cxx */, 2DEF21FB08BC033500B246B4 /* StringListWidget.hxx */, 2DDBEAD0084578BF00812C11 /* TabWidget.cxx */, 2DDBEAD1084578BF00812C11 /* TabWidget.hxx */, DC8078E60B4BD697005E9305 /* UIDialog.cxx */, DC8078E70B4BD697005E9305 /* UIDialog.hxx */, 2DDBEAD2084578BF00812C11 /* VideoDialog.cxx */, 2DDBEAD3084578BF00812C11 /* VideoDialog.hxx */, 2DDBEAD4084578BF00812C11 /* Widget.cxx */, 2DDBEAD5084578BF00812C11 /* Widget.hxx */, ); name = gui; sourceTree = ""; }; 2D605130089879BA00C6DE89 /* debugger */ = { isa = PBXGroup; children = ( 2D20F9E308C603C500A73076 /* gui */, DCE9CC261103812700C86671 /* CartDebug.cxx */, DCE9CC271103812700C86671 /* 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 */, DCE9CC281103812700C86671 /* DiStella.cxx */, DCE9CC291103812700C86671 /* DiStella.hxx */, 2DF971DE0892CEA400F64D23 /* Expression.cxx */, 2DF971DF0892CEA400F64D23 /* Expression.hxx */, 2D403BCE08611A69001E31A1 /* PackedBitArray.cxx */, 2D403BCF08611A69001E31A1 /* PackedBitArray.hxx */, DCA00FF50DBABCAD00C3823D /* RiotDebug.cxx */, DCA00FF60DBABCAD00C3823D /* RiotDebug.hxx */, 2D30F8750868A4DB00938B9D /* TIADebug.cxx */, 2D30F8760868A4DB00938B9D /* TIADebug.hxx */, 2D6CC10308C811A600B8F642 /* TiaZoomWidget.cxx */, 2D6CC10408C811A600B8F642 /* TiaZoomWidget.hxx */, ); name = debugger; sourceTree = ""; }; 2D60513708987A5400C6DE89 /* yacc */ = { isa = PBXGroup; children = ( 2D313F0A0879C4C0005BD3E5 /* YaccParser.cxx */, 2D313F0B0879C4C0005BD3E5 /* YaccParser.hxx */, ); name = yacc; sourceTree = ""; }; DC3FE46711C7D32500C91C72 /* libpng */ = { isa = PBXGroup; children = ( DC3FE46A11C7D35600C91C72 /* png.c */, DC3FE46B11C7D35600C91C72 /* png.h */, DC3FE46C11C7D35600C91C72 /* pngconf.h */, DC17E8051361FDB500397A9E /* pngdebug.h */, DC3FE46D11C7D35600C91C72 /* pngerror.c */, DC3FE46E11C7D35600C91C72 /* pngget.c */, DC17E8061361FDB500397A9E /* pnginfo.h */, DC17E8071361FDB500397A9E /* pnglibconf.h */, DC3FE46F11C7D35600C91C72 /* pngmem.c */, DC3FE47011C7D35600C91C72 /* pngpread.c */, DC3FE47111C7D35600C91C72 /* pngpriv.h */, DC3FE47211C7D35600C91C72 /* pngread.c */, DC3FE47311C7D35600C91C72 /* pngrio.c */, DC3FE47411C7D35600C91C72 /* pngrtran.c */, DC3FE47511C7D35600C91C72 /* pngrutil.c */, DC3FE47611C7D35600C91C72 /* pngset.c */, DC17E8081361FDB500397A9E /* pngstruct.h */, DC3FE47711C7D35600C91C72 /* pngtrans.c */, DC3FE47811C7D35600C91C72 /* pngwio.c */, DC3FE47911C7D35600C91C72 /* pngwrite.c */, DC3FE47A11C7D35600C91C72 /* pngwtran.c */, DC3FE47B11C7D35600C91C72 /* pngwutil.c */, ); name = libpng; sourceTree = ""; }; DC881B87151676A200021371 /* tv_filters */ = { isa = PBXGroup; children = ( DC752D931513E9F7005B0D24 /* atari_ntsc.c */, DC752D941513E9F7005B0D24 /* atari_ntsc.h */, DC752D921513E9F7005B0D24 /* atari_ntsc_impl.h */, DC49F90314F7D0DB000704B0 /* NTSCFilter.cxx */, DC49F90414F7D0DB000704B0 /* NTSCFilter.hxx */, ); name = 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 */, ); name = cheat; 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 */, 2D9173D009BA90380026E9FF /* Cart4K.hxx in Headers */, 2D9173D109BA90380026E9FF /* CartAR.hxx in Headers */, 2D9173D209BA90380026E9FF /* CartCV.hxx in Headers */, 2D9173D309BA90380026E9FF /* CartDPC.hxx in Headers */, 2D9173D409BA90380026E9FF /* CartE0.hxx in Headers */, 2D9173D509BA90380026E9FF /* CartE7.hxx in Headers */, 2D9173D609BA90380026E9FF /* CartF4.hxx in Headers */, 2D9173D709BA90380026E9FF /* CartF4SC.hxx in Headers */, 2D9173D809BA90380026E9FF /* CartF6.hxx in Headers */, 2D9173D909BA90380026E9FF /* CartF6SC.hxx in Headers */, 2D9173DA09BA90380026E9FF /* CartF8.hxx in Headers */, 2D9173DB09BA90380026E9FF /* CartF8SC.hxx in Headers */, 2D9173DD09BA90380026E9FF /* CartFE.hxx in Headers */, 2D9173DF09BA90380026E9FF /* CartMC.hxx in Headers */, 2D9173E009BA90380026E9FF /* Console.hxx in Headers */, 2D9173E109BA90380026E9FF /* Control.hxx in Headers */, 2D9173E309BA90380026E9FF /* Driving.hxx in Headers */, 2D9173E409BA90380026E9FF /* Event.hxx in Headers */, 2D9173E509BA90380026E9FF /* Joystick.hxx in Headers */, 2D9173E609BA90380026E9FF /* Keyboard.hxx in Headers */, 2D9173E709BA90380026E9FF /* M6532.hxx in Headers */, 2D9173E809BA90380026E9FF /* MD5.hxx in Headers */, 2D9173EA09BA90380026E9FF /* Paddles.hxx in Headers */, 2D9173EB09BA90380026E9FF /* Props.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 */, 2D9173F109BA90380026E9FF /* TIA.hxx in Headers */, 2D9173F709BA90380026E9FF /* FrameBufferGL.hxx in Headers */, 2D9173F809BA90380026E9FF /* FrameBufferSoft.hxx in Headers */, 2D9173F909BA90380026E9FF /* EventHandler.hxx in Headers */, 2D9173FA09BA90380026E9FF /* FrameBuffer.hxx in Headers */, 2D9173FB09BA90380026E9FF /* Settings.hxx in Headers */, 2D9173FC09BA90380026E9FF /* SettingsMACOSX.hxx in Headers */, 2D9173FD09BA90380026E9FF /* SoundSDL.hxx in Headers */, 2D9173FF09BA90380026E9FF /* OSystemMACOSX.hxx in Headers */, 2D91740009BA90380026E9FF /* AboutDialog.hxx in Headers */, 2D91740109BA90380026E9FF /* AudioDialog.hxx in Headers */, 2D91740209BA90380026E9FF /* BrowserDialog.hxx in Headers */, 2D91740309BA90380026E9FF /* Command.hxx in Headers */, 2D91740409BA90380026E9FF /* Dialog.hxx in Headers */, 2D91740509BA90380026E9FF /* DialogContainer.hxx in Headers */, 2D91740609BA90380026E9FF /* GameInfoDialog.hxx in Headers */, 2D91740709BA90380026E9FF /* GameList.hxx in Headers */, 2D91740809BA90380026E9FF /* GuiObject.hxx in Headers */, 2D91740A09BA90380026E9FF /* HelpDialog.hxx in Headers */, 2D91740B09BA90380026E9FF /* Launcher.hxx in Headers */, 2D91740C09BA90380026E9FF /* LauncherDialog.hxx in Headers */, 2D91740E09BA90380026E9FF /* ListWidget.hxx in Headers */, 2D91740F09BA90380026E9FF /* Menu.hxx in Headers */, 2D91741009BA90380026E9FF /* OptionsDialog.hxx in Headers */, 2D91741109BA90380026E9FF /* PopUpWidget.hxx in Headers */, 2D91741209BA90380026E9FF /* ProgressDialog.hxx in Headers */, 2D91741309BA90380026E9FF /* ScrollBarWidget.hxx in Headers */, 2D91741609BA90380026E9FF /* TabWidget.hxx in Headers */, 2D91741709BA90380026E9FF /* VideoDialog.hxx in Headers */, 2D91741809BA90380026E9FF /* Widget.hxx in Headers */, 2D91741909BA90380026E9FF /* CartUA.hxx in Headers */, 2D91741A09BA90380026E9FF /* FSNode.hxx in Headers */, 2D91741B09BA90380026E9FF /* OSystem.hxx in Headers */, 2D91741D09BA90380026E9FF /* Preferences.h 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 */, 2D91742509BA90380026E9FF /* EditTextWidget.hxx in Headers */, 2D91742809BA90380026E9FF /* PackedBitArray.hxx in Headers */, 2D91742909BA90380026E9FF /* TIADebug.hxx in Headers */, 2D91742A09BA90380026E9FF /* YaccParser.hxx in Headers */, 2D91742B09BA90380026E9FF /* Cart3E.hxx in Headers */, 2D91742C09BA90380026E9FF /* CpuDebug.hxx in Headers */, 2D91743609BA90380026E9FF /* DebuggerSystem.hxx in Headers */, 2D91743A09BA90380026E9FF /* Expression.hxx in Headers */, 2D91744F09BA90380026E9FF /* InputTextDialog.hxx in Headers */, 2D91745009BA90380026E9FF /* CheckListWidget.hxx in Headers */, 2D91745109BA90380026E9FF /* StringListWidget.hxx in Headers */, 2D91745209BA90380026E9FF /* CommandDialog.hxx in Headers */, 2D91745309BA90380026E9FF /* CommandMenu.hxx in Headers */, 2D91745409BA90380026E9FF /* ColorWidget.hxx in Headers */, 2D91745509BA90380026E9FF /* CpuWidget.hxx in Headers */, 2D91745609BA90380026E9FF /* DataGridOpsWidget.hxx in Headers */, 2D91745709BA90380026E9FF /* DataGridWidget.hxx in Headers */, 2D91745809BA90380026E9FF /* DebuggerDialog.hxx in Headers */, 2D91745909BA90380026E9FF /* PromptWidget.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 */, 2D91746809BA90380026E9FF /* MediaFactory.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 */, 2D28DDE509DC2D9F00A17585 /* MenusEvents.h in Headers */, DCD56D390B247D920092F9F8 /* Cart4A50.hxx in Headers */, DCD56D3D0B247DB40092F9F8 /* RectList.hxx in Headers */, DC8078DB0B4BD5F3005E9305 /* DebuggerExpressions.hxx in Headers */, DC8078EB0B4BD697005E9305 /* UIDialog.hxx in Headers */, DCEECE570B5E5E540021D754 /* Cart0840.hxx in Headers */, DCE3BBFA0C95CEDC00A671DF /* RomInfoWidget.hxx in Headers */, DC07A3C90CAD738A009B4BC9 /* StateManager.hxx in Headers */, DC0984860D3985160073C852 /* CartSB.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 */, DCE6EB230DD9ADA00047AC28 /* TrackBall.hxx in Headers */, DC173F770E2CAC1E00320F94 /* ContextMenu.hxx in Headers */, DC0DF86A0F0DAAF500B0F1F3 /* GlobalPropsDialog.hxx in Headers */, DC5D2C520F117CFD004D1660 /* Rect.hxx in Headers */, DC5D2C530F117CFD004D1660 /* StellaFont.hxx in Headers */, DC5D2C540F117CFD004D1660 /* StellaLargeFont.hxx in Headers */, DC5D2C550F117CFD004D1660 /* StellaMediumFont.hxx in Headers */, DC5D2C610F129B1E004D1660 /* LauncherFilterDialog.hxx in Headers */, DC932D440F278A5200FEFEFC /* DefProps.hxx in Headers */, DC932D450F278A5200FEFEFC /* Serializable.hxx in Headers */, DC932D460F278A5200FEFEFC /* SerialPort.hxx in Headers */, DC932D480F278A5200FEFEFC /* TIATables.hxx in Headers */, DC9EA8880F729A36000452B5 /* KidVid.hxx in Headers */, DCF467B50F93993B00B25D7A /* Array.hxx in Headers */, DCF467B60F93993B00B25D7A /* SharedPtr.hxx in Headers */, DCF467B80F93993B00B25D7A /* SoundNull.hxx in Headers */, DCF467BD0F9399F500B25D7A /* Version.hxx in Headers */, DCF467C30F939A1400B25D7A /* CartEF.hxx in Headers */, DCF467C50F939A1400B25D7A /* CartEFSC.hxx in Headers */, DC5D1AA7102C6FC900E59AC1 /* Stack.hxx in Headers */, DCF7B0DE10A762FC007A2870 /* CartF0.hxx in Headers */, DCF7B0E010A762FC007A2870 /* CartFA.hxx in Headers */, DCECDAFB10B9DBDC00AF4E1B /* Device.hxx in Headers */, DCECDAFD10B9DBDC00AF4E1B /* M6502.hxx in Headers */, DCECDAFF10B9DBDC00AF4E1B /* NullDev.hxx in Headers */, DCECDB0110B9DBDC00AF4E1B /* System.hxx in Headers */, DCECDB0510B9DC0400AF4E1B /* bspf.hxx in Headers */, DCE9CC2B1103812700C86671 /* CartDebug.hxx in Headers */, DCE9CC2D1103812700C86671 /* DiStella.hxx in Headers */, DC84E11D1135988E00CA7C9D /* Genesis.hxx in Headers */, DC64EB211152F9C000DC9140 /* CartDPCPlus.hxx in Headers */, DC3FE47D11C7D35600C91C72 /* png.h in Headers */, DC3FE47E11C7D35600C91C72 /* pngconf.h in Headers */, DC3FE48311C7D35600C91C72 /* pngpriv.h in Headers */, DC3FE4A011C7D3FE00C91C72 /* PNGLibrary.hxx in Headers */, DCB5CEE811F5B78C00C68D09 /* MessageBox.hxx in Headers */, DCBD968A1210314C0087CEFD /* ComboDialog.hxx in Headers */, DC4AF1F412E39F700090B82E /* Thumbulator.hxx in Headers */, DC17E8091361FDB500397A9E /* pngdebug.h in Headers */, DC17E80A1361FDB500397A9E /* pnginfo.h in Headers */, DC17E80B1361FDB500397A9E /* pnglibconf.h in Headers */, DC17E80C1361FDB500397A9E /* pngstruct.h in Headers */, DC20D6F3138EB130002A7428 /* StringList.hxx in Headers */, DC20D6F4138EB130002A7428 /* StringParser.hxx in Headers */, DC7A769B13FEA40300ED8633 /* LoggerDialog.hxx in Headers */, DC8AE5C41417804C00335D45 /* FBSurfaceGL.hxx in Headers */, DC8AE5C61417804C00335D45 /* FBSurfaceTIA.hxx in Headers */, DC3E4A6714B25EB30071D7BC /* CartCM.hxx in Headers */, DC3E4A6914B25EB30071D7BC /* CompuMate.hxx in Headers */, DC3E4A6B14B25EB30071D7BC /* MindLink.hxx in Headers */, DC0BFFFA14BA2BEB00CF5E7E /* BoosterWidget.hxx in Headers */, DC0BFFFB14BA2BEB00CF5E7E /* ControllerWidget.hxx in Headers */, DC0BFFFD14BA2BEB00CF5E7E /* DrivingWidget.hxx in Headers */, DC0BFFFF14BA2BEB00CF5E7E /* GenesisWidget.hxx in Headers */, DC0B000114BA2BEB00CF5E7E /* JoystickWidget.hxx in Headers */, DC0B000314BA2BEB00CF5E7E /* KeyboardWidget.hxx in Headers */, DC0B000414BA2BEB00CF5E7E /* NullControlWidget.hxx in Headers */, DC0B000614BA2BEB00CF5E7E /* PaddleWidget.hxx in Headers */, DC5C76B014C2709E0031EBC7 /* StellaKeys.hxx in Headers */, DC922D0714CAFB1E006EB471 /* CartFA2.hxx in Headers */, DCAE2A9414CCCCBD004327BB /* MouseControl.hxx in Headers */, DC49F90614F7D0DB000704B0 /* NTSCFilter.hxx in Headers */, DC752D951513E9F7005B0D24 /* atari_ntsc_impl.h in Headers */, DC752D971513E9F7005B0D24 /* atari_ntsc.h in Headers */, DCDBD3191556F60C00308CC4 /* CartCTY.hxx in Headers */, DCDBD31A1556F60C00308CC4 /* CartCTYTunes.hxx in Headers */, DCA6276116CB0D1C004E9AF0 /* FSNodePOSIX.hxx in Headers */, DCA6277416CB0D45004E9AF0 /* FSNodeFactory.hxx in Headers */, DCA6277616CB0D45004E9AF0 /* FSNodeZIP.hxx in Headers */, DCA6277816CB0D45004E9AF0 /* ZipHandler.hxx in Headers */, DCF28EEA1729A5CD00DD0CA9 /* Cart2KWidget.hxx in Headers */, DCF28EEC1729A5CD00DD0CA9 /* Cart3EWidget.hxx in Headers */, DCF28EEE1729A5CD00DD0CA9 /* Cart3FWidget.hxx in Headers */, DCF28EF01729A5CD00DD0CA9 /* Cart4A50Widget.hxx in Headers */, DCF28EF21729A5CD00DD0CA9 /* Cart4KWidget.hxx in Headers */, DCF28EF41729A5CD00DD0CA9 /* Cart0840Widget.hxx in Headers */, DCF28EF61729A5CD00DD0CA9 /* CartARWidget.hxx in Headers */, DCF28EF81729A5CD00DD0CA9 /* CartCMWidget.hxx in Headers */, DCF28EFA1729A5CD00DD0CA9 /* CartCTYWidget.hxx in Headers */, DCF28EFC1729A5CD00DD0CA9 /* CartCVWidget.hxx in Headers */, DCF28EFD1729A5CD00DD0CA9 /* CartDebugWidget.hxx in Headers */, DCF28EFF1729A5CD00DD0CA9 /* CartDPCPlusWidget.hxx in Headers */, DCF28F011729A5CD00DD0CA9 /* CartDPCWidget.hxx in Headers */, DCF28F031729A5CD00DD0CA9 /* CartE0Widget.hxx in Headers */, DCF28F051729A5CD00DD0CA9 /* CartE7Widget.hxx in Headers */, DCF28F071729A5CD00DD0CA9 /* CartEFSCWidget.hxx in Headers */, DCF28F091729A5CD00DD0CA9 /* CartEFWidget.hxx in Headers */, DCF28F0B1729A5CD00DD0CA9 /* CartF0Widget.hxx in Headers */, DCF28F0D1729A5CD00DD0CA9 /* CartF4SCWidget.hxx in Headers */, DCF28F0F1729A5CD00DD0CA9 /* CartF4Widget.hxx in Headers */, DCF28F111729A5CD00DD0CA9 /* CartF6SCWidget.hxx in Headers */, DCF28F131729A5CD00DD0CA9 /* CartF6Widget.hxx in Headers */, DCF28F151729A5CD00DD0CA9 /* CartF8SCWidget.hxx in Headers */, DCF28F171729A5CD00DD0CA9 /* CartF8Widget.hxx in Headers */, DCF28F191729A5CD00DD0CA9 /* CartFA2Widget.hxx in Headers */, DCF28F1B1729A5CD00DD0CA9 /* CartFAWidget.hxx in Headers */, DCF28F1D1729A5CD00DD0CA9 /* CartFEWidget.hxx in Headers */, DCF28F1F1729A5CD00DD0CA9 /* CartMCWidget.hxx in Headers */, DCF28F211729A5CD00DD0CA9 /* CartSBWidget.hxx in Headers */, DCF28F231729A5CD00DD0CA9 /* CartUAWidget.hxx in Headers */, DCF28F251729A5CD00DD0CA9 /* CartX07Widget.hxx in Headers */, DC3C3CDC173B1EB2009FFE61 /* Variant.hxx in Headers */, DC3C3CE2173B1EC8009FFE61 /* FileListWidget.hxx in Headers */, DC449CB0176FF512004FA2D4 /* RomListSettings.hxx in Headers */, DC0D76A7177259C3005C7805 /* ConfigPathDialog.hxx in Headers */, DC0D76A9177259C3005C7805 /* SnapshotDialog.hxx in Headers */, DCECD7AA17A88E51000A9753 /* Base.hxx in Headers */, DCB31D3E17C2D667002C0868 /* ConsoleMediumFont.hxx in Headers */, DC3F601717C9140100A1977D /* ConsoleBFont.hxx in Headers */, DC3F601817C9140100A1977D /* ConsoleMediumBFont.hxx in Headers */, DCB29728188D655000B7BEB8 /* Cart4KSC.hxx in Headers */, DCB2972A188D655000B7BEB8 /* CartBF.hxx in Headers */, DCB2972C188D655000B7BEB8 /* CartBFSC.hxx in Headers */, DCB2972E188D655000B7BEB8 /* CartDF.hxx in Headers */, DCB29730188D655000B7BEB8 /* CartDFSC.hxx in Headers */, DCB2973E188D657B00B7BEB8 /* Cart4KSCWidget.hxx in Headers */, DCB29740188D657B00B7BEB8 /* CartBFSCWidget.hxx in Headers */, DCB29742188D657B00B7BEB8 /* CartBFWidget.hxx in Headers */, DCB29744188D657B00B7BEB8 /* CartDFSCWidget.hxx in Headers */, DCB29746188D657B00B7BEB8 /* CartDFWidget.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 = ( 2D91751B09BA90380026E9FF /* PBXBuildRule */, 2D91751C09BA90380026E9FF /* PBXBuildRule */, 2D91751D09BA90390026E9FF /* PBXBuildRule */, ); dependencies = ( ); name = Stella; productInstallPath = "$(HOME)/Applications"; productName = "«PROJECTNAME»"; productReference = 2D91751E09BA90390026E9FF /* Stella.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; buildConfigurationList = 2D91752109BA903B0026E9FF /* Build configuration list for PBXProject "stella" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, Japanese, French, German, ); mainGroup = 29B97314FDCFA39411CA2CEA /* «PROJECTNAMEASXML» */; projectDirPath = ""; projectRoot = ""; targets = ( 2D9173C809BA90380026E9FF /* Stella */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 2D91746C09BA90380026E9FF /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 2D91746D09BA90380026E9FF /* InfoPlist.strings in Resources */, 2D91746E09BA90380026E9FF /* SDLMain.nib 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 = ( 2D91747409BA90380026E9FF /* SDLMain.m in Sources */, 2D91747509BA90380026E9FF /* Booster.cxx 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 */, 2D91747C09BA90380026E9FF /* CartDPC.cxx in Sources */, 2D91747D09BA90380026E9FF /* CartE0.cxx in Sources */, 2D91747E09BA90380026E9FF /* CartE7.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 */, 2D91748609BA90380026E9FF /* CartFE.cxx in Sources */, 2D91748809BA90380026E9FF /* CartMC.cxx in Sources */, 2D91748909BA90380026E9FF /* Console.cxx in Sources */, 2D91748A09BA90380026E9FF /* Control.cxx in Sources */, 2D91748C09BA90380026E9FF /* Driving.cxx in Sources */, 2D91748E09BA90380026E9FF /* Joystick.cxx in Sources */, 2D91748F09BA90380026E9FF /* Keyboard.cxx in Sources */, 2D91749009BA90380026E9FF /* M6532.cxx in Sources */, 2D91749109BA90380026E9FF /* MD5.cxx in Sources */, 2D91749309BA90380026E9FF /* Paddles.cxx in Sources */, 2D91749409BA90380026E9FF /* Props.cxx in Sources */, 2D91749509BA90380026E9FF /* PropsSet.cxx in Sources */, 2D91749609BA90380026E9FF /* Random.cxx in Sources */, 2D91749709BA90380026E9FF /* Serializer.cxx in Sources */, 2D91749809BA90380026E9FF /* Switches.cxx in Sources */, 2D91749909BA90380026E9FF /* TIA.cxx in Sources */, 2D91749F09BA90380026E9FF /* FrameBufferGL.cxx in Sources */, 2D9174A009BA90380026E9FF /* FrameBufferSoft.cxx in Sources */, 2D9174A109BA90380026E9FF /* EventHandler.cxx in Sources */, 2D9174A209BA90380026E9FF /* FrameBuffer.cxx in Sources */, 2D9174A309BA90380026E9FF /* Settings.cxx in Sources */, 2D9174A409BA90380026E9FF /* SettingsMACOSX.cxx in Sources */, 2D9174A509BA90380026E9FF /* SoundSDL.cxx in Sources */, 2D9174A709BA90380026E9FF /* mainSDL.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 */, 2D9174B709BA90380026E9FF /* OptionsDialog.cxx in Sources */, 2D9174B809BA90380026E9FF /* PopUpWidget.cxx in Sources */, 2D9174B909BA90380026E9FF /* ProgressDialog.cxx in Sources */, 2D9174BA09BA90380026E9FF /* ScrollBarWidget.cxx in Sources */, 2D9174BB09BA90380026E9FF /* TabWidget.cxx in Sources */, 2D9174BC09BA90380026E9FF /* VideoDialog.cxx in Sources */, 2D9174BD09BA90380026E9FF /* Widget.cxx in Sources */, 2D9174BE09BA90380026E9FF /* CartUA.cxx in Sources */, 2D9174BF09BA90380026E9FF /* FSNode.cxx in Sources */, 2D9174C009BA90380026E9FF /* OSystem.cxx in Sources */, 2D9174C209BA90380026E9FF /* Preferences.m in Sources */, 2D9174C409BA90380026E9FF /* AboutBox.m 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 */, 2D9174CB09BA90380026E9FF /* PackedBitArray.cxx in Sources */, 2D9174CC09BA90380026E9FF /* TIADebug.cxx in Sources */, 2D9174CD09BA90380026E9FF /* YaccParser.cxx in Sources */, 2D9174CE09BA90380026E9FF /* Cart3E.cxx in Sources */, 2D9174CF09BA90380026E9FF /* CpuDebug.cxx in Sources */, 2D9174DC09BA90380026E9FF /* Expression.cxx in Sources */, 2D9174F109BA90380026E9FF /* InputTextDialog.cxx in Sources */, 2D9174F209BA90380026E9FF /* CheckListWidget.cxx in Sources */, 2D9174F309BA90380026E9FF /* StringListWidget.cxx in Sources */, 2D9174F409BA90380026E9FF /* CommandDialog.cxx in Sources */, 2D9174F509BA90380026E9FF /* CommandMenu.cxx in Sources */, 2D9174F609BA90380026E9FF /* ColorWidget.cxx in Sources */, 2D9174F709BA90380026E9FF /* CpuWidget.cxx in Sources */, 2D9174F809BA90380026E9FF /* DataGridOpsWidget.cxx in Sources */, 2D9174F909BA90380026E9FF /* DataGridWidget.cxx in Sources */, 2D9174FA09BA90380026E9FF /* DebuggerDialog.cxx in Sources */, 2D9174FB09BA90380026E9FF /* PromptWidget.cxx in Sources */, 2D9174FC09BA90380026E9FF /* RamWidget.cxx in Sources */, 2D9174FD09BA90380026E9FF /* RomListWidget.cxx in Sources */, 2D9174FE09BA90380026E9FF /* RomWidget.cxx in Sources */, 2D9174FF09BA90380026E9FF /* TiaInfoWidget.cxx in Sources */, 2D91750009BA90380026E9FF /* TiaOutputWidget.cxx in Sources */, 2D91750109BA90380026E9FF /* TiaWidget.cxx in Sources */, 2D91750209BA90380026E9FF /* ToggleBitWidget.cxx in Sources */, 2D91750309BA90380026E9FF /* TogglePixelWidget.cxx in Sources */, 2D91750409BA90380026E9FF /* ToggleWidget.cxx in Sources */, 2D91750609BA90380026E9FF /* TiaZoomWidget.cxx in Sources */, 2D91750709BA90380026E9FF /* TIASnd.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 */, DC47455E09C34BFA00EDDA3A /* RamCheat.cxx in Sources */, DCD56D380B247D920092F9F8 /* Cart4A50.cxx in Sources */, DCD56D3C0B247DB40092F9F8 /* RectList.cxx in Sources */, DC8078EA0B4BD697005E9305 /* UIDialog.cxx in Sources */, DCEECE560B5E5E540021D754 /* Cart0840.cxx in Sources */, DCE3BBF90C95CEDC00A671DF /* RomInfoWidget.cxx in Sources */, DC07A3C80CAD738A009B4BC9 /* StateManager.cxx in Sources */, DC0984850D3985160073C852 /* CartSB.cxx in Sources */, DCA23AE90D75B22500F77B33 /* CartX07.cxx 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 */, DC4AC6EF0DC8DACB00CD3AD2 /* RiotWidget.cxx in Sources */, DC4AC6F30DC8DAEF00CD3AD2 /* SaveKey.cxx in Sources */, DCE6EB220DD9ADA00047AC28 /* TrackBall.cxx in Sources */, DC173F760E2CAC1E00320F94 /* ContextMenu.cxx in Sources */, DC0DF8690F0DAAF500B0F1F3 /* GlobalPropsDialog.cxx in Sources */, DC5D2C600F129B1E004D1660 /* LauncherFilterDialog.cxx in Sources */, DC932D470F278A5200FEFEFC /* TIATables.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 */, DCECDAFC10B9DBDC00AF4E1B /* M6502.cxx in Sources */, DCECDAFE10B9DBDC00AF4E1B /* NullDev.cxx in Sources */, DCECDB0010B9DBDC00AF4E1B /* System.cxx in Sources */, DCE9CC2A1103812700C86671 /* CartDebug.cxx in Sources */, DCE9CC2C1103812700C86671 /* DiStella.cxx in Sources */, DC84E11C1135988E00CA7C9D /* Genesis.cxx in Sources */, DC64EB201152F9C000DC9140 /* CartDPCPlus.cxx in Sources */, DC3FE47C11C7D35600C91C72 /* png.c in Sources */, DC3FE47F11C7D35600C91C72 /* pngerror.c in Sources */, DC3FE48011C7D35600C91C72 /* pngget.c in Sources */, DC3FE48111C7D35600C91C72 /* pngmem.c in Sources */, DC3FE48211C7D35600C91C72 /* pngpread.c in Sources */, DC3FE48411C7D35600C91C72 /* pngread.c in Sources */, DC3FE48511C7D35600C91C72 /* pngrio.c in Sources */, DC3FE48611C7D35600C91C72 /* pngrtran.c in Sources */, DC3FE48711C7D35600C91C72 /* pngrutil.c in Sources */, DC3FE48811C7D35600C91C72 /* pngset.c in Sources */, DC3FE48911C7D35600C91C72 /* pngtrans.c in Sources */, DC3FE48A11C7D35600C91C72 /* pngwio.c in Sources */, DC3FE48B11C7D35600C91C72 /* pngwrite.c in Sources */, DC3FE48C11C7D35600C91C72 /* pngwtran.c in Sources */, DC3FE48D11C7D35600C91C72 /* pngwutil.c in Sources */, DC3FE49F11C7D3FE00C91C72 /* PNGLibrary.cxx in Sources */, DCB5CEE711F5B78C00C68D09 /* MessageBox.cxx in Sources */, DCBD96891210314C0087CEFD /* ComboDialog.cxx in Sources */, DC4AF1F312E39F700090B82E /* Thumbulator.cxx in Sources */, DC7A769A13FEA40300ED8633 /* LoggerDialog.cxx in Sources */, DC8AE5C31417804C00335D45 /* FBSurfaceGL.cxx in Sources */, DC8AE5C51417804C00335D45 /* FBSurfaceTIA.cxx in Sources */, DC3E4A6614B25EB30071D7BC /* CartCM.cxx in Sources */, DC3E4A6814B25EB30071D7BC /* CompuMate.cxx in Sources */, DC3E4A6A14B25EB30071D7BC /* MindLink.cxx in Sources */, DC0BFFF914BA2BEB00CF5E7E /* BoosterWidget.cxx in Sources */, DC0BFFFC14BA2BEB00CF5E7E /* DrivingWidget.cxx in Sources */, DC0BFFFE14BA2BEB00CF5E7E /* GenesisWidget.cxx in Sources */, DC0B000014BA2BEB00CF5E7E /* JoystickWidget.cxx in Sources */, DC0B000214BA2BEB00CF5E7E /* KeyboardWidget.cxx in Sources */, DC0B000514BA2BEB00CF5E7E /* PaddleWidget.cxx in Sources */, DC922D0614CAFB1E006EB471 /* CartFA2.cxx in Sources */, DCAE2A9314CCCCBD004327BB /* MouseControl.cxx in Sources */, DC49F90514F7D0DB000704B0 /* NTSCFilter.cxx in Sources */, DC752D961513E9F7005B0D24 /* atari_ntsc.c in Sources */, DCDBD3181556F60C00308CC4 /* CartCTY.cxx in Sources */, DCA6277516CB0D45004E9AF0 /* FSNodeZIP.cxx in Sources */, DCA6277716CB0D45004E9AF0 /* ZipHandler.cxx in Sources */, DCF28EE91729A5CD00DD0CA9 /* Cart2KWidget.cxx in Sources */, DCF28EEB1729A5CD00DD0CA9 /* Cart3EWidget.cxx in Sources */, DCF28EED1729A5CD00DD0CA9 /* Cart3FWidget.cxx in Sources */, DCF28EEF1729A5CD00DD0CA9 /* Cart4A50Widget.cxx in Sources */, DCF28EF11729A5CD00DD0CA9 /* Cart4KWidget.cxx in Sources */, DCF28EF31729A5CD00DD0CA9 /* Cart0840Widget.cxx in Sources */, DCF28EF51729A5CD00DD0CA9 /* CartARWidget.cxx in Sources */, DCF28EF71729A5CD00DD0CA9 /* CartCMWidget.cxx in Sources */, DCF28EF91729A5CD00DD0CA9 /* CartCTYWidget.cxx in Sources */, DCF28EFB1729A5CD00DD0CA9 /* CartCVWidget.cxx in Sources */, DCF28EFE1729A5CD00DD0CA9 /* CartDPCPlusWidget.cxx in Sources */, DCF28F001729A5CD00DD0CA9 /* CartDPCWidget.cxx in Sources */, DCF28F021729A5CD00DD0CA9 /* CartE0Widget.cxx in Sources */, DCF28F041729A5CD00DD0CA9 /* CartE7Widget.cxx in Sources */, DCF28F061729A5CD00DD0CA9 /* CartEFSCWidget.cxx in Sources */, DCF28F081729A5CD00DD0CA9 /* CartEFWidget.cxx in Sources */, DCF28F0A1729A5CD00DD0CA9 /* CartF0Widget.cxx in Sources */, DCF28F0C1729A5CD00DD0CA9 /* CartF4SCWidget.cxx in Sources */, DCF28F0E1729A5CD00DD0CA9 /* CartF4Widget.cxx in Sources */, DCF28F101729A5CD00DD0CA9 /* CartF6SCWidget.cxx in Sources */, DCF28F121729A5CD00DD0CA9 /* CartF6Widget.cxx in Sources */, DCF28F141729A5CD00DD0CA9 /* CartF8SCWidget.cxx in Sources */, DCF28F161729A5CD00DD0CA9 /* CartF8Widget.cxx in Sources */, DCF28F181729A5CD00DD0CA9 /* CartFA2Widget.cxx in Sources */, DCF28F1A1729A5CD00DD0CA9 /* CartFAWidget.cxx in Sources */, DCF28F1C1729A5CD00DD0CA9 /* CartFEWidget.cxx in Sources */, DCF28F1E1729A5CD00DD0CA9 /* CartMCWidget.cxx in Sources */, DCF28F201729A5CD00DD0CA9 /* CartSBWidget.cxx in Sources */, DCF28F221729A5CD00DD0CA9 /* CartUAWidget.cxx in Sources */, DCF28F241729A5CD00DD0CA9 /* CartX07Widget.cxx in Sources */, DC3C3CE1173B1EC8009FFE61 /* FileListWidget.cxx in Sources */, DC449CAF176FF512004FA2D4 /* RomListSettings.cxx in Sources */, DC0D76A6177259C3005C7805 /* ConfigPathDialog.cxx in Sources */, DC0D76A8177259C3005C7805 /* SnapshotDialog.cxx in Sources */, DCECD7A917A88E51000A9753 /* Base.cxx in Sources */, DCB29727188D655000B7BEB8 /* Cart4KSC.cxx in Sources */, DCB29729188D655000B7BEB8 /* CartBF.cxx in Sources */, DCB2972B188D655000B7BEB8 /* CartBFSC.cxx in Sources */, DCB2972D188D655000B7BEB8 /* CartDF.cxx in Sources */, DCB2972F188D655000B7BEB8 /* CartDFSC.cxx in Sources */, DCB2973D188D657B00B7BEB8 /* Cart4KSCWidget.cxx in Sources */, DCB2973F188D657B00B7BEB8 /* CartBFSCWidget.cxx in Sources */, DCB29741188D657B00B7BEB8 /* CartBFWidget.cxx in Sources */, DCB29743188D657B00B7BEB8 /* CartDFSCWidget.cxx in Sources */, DCB29745188D657B00B7BEB8 /* CartDFWidget.cxx in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 089C165DFE840E0CC02AAC07 /* English */, ); name = InfoPlist.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 2D91751709BA90380026E9FF /* Development */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = ( i386, ppc, ); FRAMEWORK_SEARCH_PATHS = ( ., "$(HOME)/Library/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_INTTYPES, HAVE_GETTIMEOFDAY, DISPLAY_OPENGL, CHEATCODE_SUPPORT, DEBUGGER_SUPPORT, JOYSTICK_SUPPORT, SOUND_SUPPORT, THUMB_SUPPORT, WINDOWED_SUPPORT, BSPF_MAC_OSX, MAC_OSX, ); GCC_VERSION = 4.0; HEADER_SEARCH_PATHS = ( ./SDL.framework/Headers, ../cheat, ../common, ../common/tv_filters, ../debugger, ../debugger/gui, ../emucore, ../gui, ../yacc, ., ); INFOPLIST_FILE = "Info-Stella.plist"; INSTALL_PATH = ""; LD_RUNPATH_SEARCH_PATHS = ""; LIBRARY_SEARCH_PATHS = "$(LIBRARY_SEARCH_PATHS)"; OTHER_CFLAGS = ""; OTHER_LDFLAGS = ( "-framework", SDL, "-lz", ); PRODUCT_NAME = Stella; SECTORDER_FLAGS = ""; VALID_ARCHS = "i386 ppc"; WARNING_CFLAGS = ( "-Wmost", "-Wno-four-char-constants", "-Wno-unknown-pragmas", ); WRAPPER_EXTENSION = app; }; name = Development; }; 2D91751809BA90380026E9FF /* Deployment */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = ( i386, ppc, ); FRAMEWORK_SEARCH_PATHS = ( ., "$(HOME)/Library/Frameworks", ); GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( HAVE_INTTYPES, HAVE_GETTIMEOFDAY, DISPLAY_OPENGL, CHEATCODE_SUPPORT, DEBUGGER_SUPPORT, JOYSTICK_SUPPORT, SOUND_SUPPORT, THUMB_SUPPORT, WINDOWED_SUPPORT, BSPF_MAC_OSX, MAC_OSX, ); GCC_VERSION = 4.0; HEADER_SEARCH_PATHS = ( ./SDL.framework/Headers, ../cheat, ../common, ../common/tv_filters, ../debugger, ../debugger/gui, ../emucore, ../gui, ../yacc, ., ); INFOPLIST_FILE = "Info-Stella.plist"; INSTALL_PATH = ""; LD_RUNPATH_SEARCH_PATHS = ""; LIBRARY_SEARCH_PATHS = "$(LIBRARY_SEARCH_PATHS)"; OTHER_CFLAGS = ""; OTHER_LDFLAGS = ( "-framework", SDL, "-lz", ); PRODUCT_NAME = Stella; SECTORDER_FLAGS = ""; VALID_ARCHS = "i386 ppc"; WARNING_CFLAGS = ( "-Wmost", "-Wno-four-char-constants", "-Wno-unknown-pragmas", ); WRAPPER_EXTENSION = app; }; name = Deployment; }; 2D91751909BA90380026E9FF /* Default */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = ( i386, ppc, ); FRAMEWORK_SEARCH_PATHS = ( "$(HOME)/Library/Frameworks", ., ); GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( HAVE_INTTYPES, HAVE_GETTIMEOFDAY, DISPLAY_OPENGL, CHEATCODE_SUPPORT, DEBUGGER_SUPPORT, JOYSTICK_SUPPORT, SOUND_SUPPORT, THUMB_SUPPORT, WINDOWED_SUPPORT, BSPF_MAC_OSX, MAC_OSX, ); GCC_VERSION = 4.0; HEADER_SEARCH_PATHS = ( ./SDL.framework/Headers, ../cheat, ../common, ../common/tv_filters, ../debugger, ../debugger/gui, ../emucore, ../gui, ../yacc, ., ); INFOPLIST_FILE = "Info-Stella.plist"; INSTALL_PATH = ""; LD_RUNPATH_SEARCH_PATHS = ""; LIBRARY_SEARCH_PATHS = .; OTHER_CFLAGS = ""; OTHER_LDFLAGS = ( "-framework", SDL, "-lz", ); PRODUCT_NAME = Stella; SECTORDER_FLAGS = ""; VALID_ARCHS = "i386 ppc"; WARNING_CFLAGS = ( "-Wmost", "-Wno-four-char-constants", "-Wno-unknown-pragmas", ); WRAPPER_EXTENSION = app; }; name = Default; }; 2D91752209BA903B0026E9FF /* Development */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = ( i386, ppc, ); DEBUG_INFORMATION_FORMAT = dwarf; FRAMEWORK_SEARCH_PATHS = ( ., "$(HOME)/Library/Frameworks", ); GCC_OPTIMIZATION_LEVEL = 0; GCC_VERSION = 4.0; MACOSX_DEPLOYMENT_TARGET = 10.4; SDKROOT = macosx10.4; VALID_ARCHS = "i386 ppc"; }; name = Development; }; 2D91752309BA903B0026E9FF /* Deployment */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = ( i386, ppc, ); FRAMEWORK_SEARCH_PATHS = ( ., "$(HOME)/Library/Frameworks", ); GCC_ENABLE_CPP_RTTI = NO; GCC_OPTIMIZATION_LEVEL = 3; GCC_VERSION = 4.0; MACOSX_DEPLOYMENT_TARGET = 10.4; SDKROOT = macosx10.4; VALID_ARCHS = "i386 ppc"; }; name = Deployment; }; 2D91752409BA903B0026E9FF /* Default */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = ( i386, ppc, ); FRAMEWORK_SEARCH_PATHS = ( ., "$(HOME)/Library/Frameworks", ); GCC_OPTIMIZATION_LEVEL = 3; GCC_VERSION = 4.0; MACOSX_DEPLOYMENT_TARGET = 10.4; SDKROOT = macosx10.4; VALID_ARCHS = "i386 ppc"; }; name = Default; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 2D91751609BA90380026E9FF /* Build configuration list for PBXNativeTarget "Stella" */ = { isa = XCConfigurationList; buildConfigurations = ( 2D91751709BA90380026E9FF /* Development */, 2D91751809BA90380026E9FF /* Deployment */, 2D91751909BA90380026E9FF /* Default */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Default; }; 2D91752109BA903B0026E9FF /* Build configuration list for PBXProject "stella" */ = { isa = XCConfigurationList; buildConfigurations = ( 2D91752209BA903B0026E9FF /* Development */, 2D91752309BA903B0026E9FF /* Deployment */, 2D91752409BA903B0026E9FF /* Default */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Default; }; /* End XCConfigurationList section */ }; rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; } stella-3.9.3/src/macosx/stella.xcodeproj/TemplateInfo.plist0000644000175000001440000000062310403717551023410 0ustar stephenusers Description This project builds an SDL-based application with Cocoa menus. FilesToMacroExpand English.lproj/InfoPlist.strings stella-3.9.3/src/macosx/OSystemMACOSX.cxx0000644000175000001440000000344512266336753017545 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: OSystemMACOSX.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OSystemMACOSX::~OSystemMACOSX() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string OSystemMACOSX::defaultSnapSaveDir() { FilesystemNode desktop("~/Desktop"); return desktop.isDirectory() ? desktop.getShortPath() : "~"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string OSystemMACOSX::defaultSnapLoadDir() { return defaultSnapSaveDir(); } stella-3.9.3/src/macosx/Stella.icns0000644000175000001440000012616310407045562016576 0ustar stephenusersicns¬sICN#ÿÿÿÿÿÿÿÿÿÿò¿ÿÿíÿÿõÿÿêïÿÿ•¿ÿÿêÿÿÿ5ßÿÿkÿþ—¿ÿýmÿÿûVÿÿö»ÿÿÝÍÿþº¶ÿõ{«ÿëöÕÿÿÛ®ÿý·uÿ÷ÍÛÿÿ¿êÿÿëÕÿÿþûÿÿõÿÿÿþ¿ÿÿýÿÿÿÿÿÿÿÿ¿ÿÿÿÿÿÿÿÿÿÿÿÿicl4ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþúÿÿÿÿÿÿÿÿÿÿÿÿÿÝÝÝïÿÿÿÿÿÿÿÿÿÿÿýÝÝÞïÿÿÿÿÿÿÿÿÿÿÿ­ÝÝÞþÿÿÿÿÿÿÿÿÿÿÿÝÝÝïîÿÿÿÿÿÿÿÿÿÿþÝÞÝîïïÿÿÿÿÿÿÿÿÿíÞÝÞïîÿÿÿÿÿÿÿÿÿÿÝÝÝîþêÿÿÿÿÿÿÿÿÿýÝÝíïîïÿÿÿÿÿÿÿÿÿííÝÞîïïÿÿÿÿÿÿÿÿþÞÝíÞîþÿÿÿÿÿÿÿÿÿÝíÞÝÞîïÿÿÿÿÿÿÿÿýêíÞÞÞîïÿÿÿÿÿÿÿ®ÝþÞííîîïÿÿÿÿÿ¯îÝïîÝîÝÞÞÿÿÿÿÿþÝÝïÿíßíÝÞîÿÿÿÿÿíîïþþÝîîÞÝîÿÿÿÿÿîïîïííîííÞÞÿÿÿÿÿþîþþîÞîþÝÝîÿÿÿÿÿÿîîîÝîþîÞÝÞÿÿÿÿÿÿÿîþÞîîÿíÞÝÿÿÿÿÿÿÿÿÿýþïïííÝïÿÿÿÿÿÿÿÿÿîþÿþÝíïÿÿÿÿÿÿÿÿÿþïÿÿÞÝïÿÿÿÿÿÿÿÿÿÿþÿÿýÞúïÿÿÿÿÿÿÿÿÿÿÿÿÿßïþÿÿÿÿÿÿÿÿÿÿÿÿÿþþïÿÿÿÿÿÿÿÿÿÿÿÿÿÿïïÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿicl8ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­‰­³ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿß^5;5Y5‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ_5_5_5_‰àÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­5Y5^;^‰­­ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³5_5Y;;_‰‰‰ßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ_5;;;;_­‰­‰³ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰;;_5Y5_‰‰‰‰ßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿß;5_5_5e‰­‰­‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ_5Y;_5_‰‰‰‰‰³ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰;_;_;;_­‰­‰Þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰5_;___5‰‰‰‰‰àÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà‰;‰_5_;;Y‰_‰‰­ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­_5ƒ__;ƒ;__ƒ‰ƒ‰êÿÿÿÿÿÿÿÿÿÿÿÿÿÿß_5_³‰_;‰__;;_ƒeÞÿÿÿÿÿÿÿÿÿÿàß­‰ƒ5_e­ß_5_‰_5__e_ƒàÿÿÿÿÿÿÿÿÿà__;5;‰­­ßƒ;_‰­;_;__e‰ÿÿÿÿÿÿÿÿÿÿeY_ƒ‰‰ÞÞ߉;__‰‰_5_5__ƒÿÿÿÿÿÿÿÿÿÿ­‰­­Ý‰­­Ý___ƒ‰­__;;;e‰ÿÿÿÿÿÿÿÿÿÿÿ‰‰‰‰‰‰­_Y;‰‰ƒ­ƒ5Y5;_ƒÿÿÿÿÿÿÿÿÿÿÿÿÞ‰‰‰­‰_;e‰‰‰­‰Y;_;5ƒÿÿÿÿÿÿÿÿÿÿÿÿÿ­‰‰­_;_‰‰‰‰ß­;Y;Y;YàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞ_­‰­‰éÿ­;_;_5ƒÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³‰‰‰­ÿÿÿƒ5_;__ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿщ‰­ÿÿÿß;;_;­­ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà­­ÿÿÿÿ­Y;‰­‰­ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßA‰Þ­Ý³ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÝ­Ý­ÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÞ­ÝàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÝ­ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿil32Á±d–½¼ƒ9-¨¾¬a¦¹Ã­Žˆƒ† “³¹ÀµŠO,$‚¼¹ub°¸Àº““v…t¶¦”qN:=6aµ¼—dl¯¹¹Èž™l†\mVLLRTIL£·­spb¤¹µÈ³j‡Yzme]XP··‚huO‘ºµºÈ©mˆGyqi_z³¶›din0q¾³µ¿ÅŠ)`\Ep¶°ocd`%6±¶´µÃµ‹E†^`b[!Y¿²´µÈl3hbbU•¾²´½’ %_hI%ª»´²e7@)4°À‡BJ9–/¡[BGK5–EJFI8—@JH™ C8š ¢±(;+-$ •ˆ‹€’yš3” g•tˆ}Šo1 “ 7“z€‰zˆ87)‘ €uŒwX/69 br„z1669. 8“xz…sŒC366; …†r†t‡c/668/Ž lŽpu†;466:ŽX{puƒoŒn=769)Tvbr€puPG>67 [wSm|qi||HIG>#,lvAXyzXt}oMJJAŠ"Rxi/8s{TXw~mRNM.‡ (?]vtOhwo5hu~pWTO†\orxqT.OvvD6pt{w[ZI…Jqg[D-#9pv`;?nuu€c_C†9@1)+10*,fqnHE:gus‚qdB‡8L?7650WpsP?H.Ztsw€jFˆ,KD:6Inqb9=AExpr{}QŠ>9'FqnB776prqr}tŠ,R3673:woqs€H!<781_woqx\8=+ltpq;  '#pxT$)"–f4#'*–'(') — %)) ™& 𢱠• ”   “ ‘      Ž     ŽŽ € €€‹„‰Š‡€‡†Š…€‰…‚€‰†‚‚ƒ‡ŽˆƒŠ‚€€–‚–€—™›¢ich#Hÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ‰ÿÿÿÿýUÿÿÿÿú«ÿÿÿÿõVÿÿÿÿú·ÿÿÿÿåM¿ÿÿÿÚßÿÿÿÿÍ-ßÿÿÿÚ¿ÿÿÿ+wÿÿÿÿµoÿÿþV»ÿÿÿý­}ÿÿÿúÒßÿÿÿõ­»ÿÿÿîUïÿÿÿÝ«_ÿÿÿjõïÿÿþݪ·ÿÿûvÕßÿÿÖík¿ÿú«óÙoÿý_×¶ßÿöÿªËÿûûwÜßÿÿoæ¿ÿþýk­oÿý¾¾Ö¿ÿÿmwù¯ÿÿþ½í_ÿÿÿ{ú·ÿÿÿßöÏÿÿÿîý·ÿÿÿûý_ÿÿÿÿþÛÿÿÿÿÿoÿÿÿÿÿßÿÿÿÿ½ÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿ€ÿÀÿÀÿà?ÿð?ÿðÿðÿÿðÿÿàÿÿàÿÿÀÿÿÀÿÿ€ÿÿ€?ÿÿÿþÿÿþÿÿü?ÿÿüÿÿÿüÿÿÿøÿÿÿøÿÿÿø?ÿÿÿøÿÿÿøÿÿÿøÿÿÿøÿÿÿøÿÿÿøÿÿüÿÿüÿÏþÿ‡ÿ€ÿ€ÿÀÿàà?ÀÀ€€ich4ˆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý®îúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÝÝÝÝÎÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÝÝÝÝÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíÝÝÞÝïïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÝÝíÝÝþïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÝÝÝÝßîîÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­ÞÝÝÝÞþþïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíÝÝÝÝþïêïÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÍíÝíÞïîïïÿÿÿÿÿÿÿÿÿÿÿÿÿÿíÞÝÞÝßîþîÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿìÝÝÝÝþþïîÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÝÞÝíÞîîîïÿÿÿÿÿÿÿÿÿÿÿÿÿÿíÝíÝÝßïïîÿÿÿÿÿÿÿÿÿÿÿÿÿÿúÝÝÝÞÝîþîþÿÿÿÿÿÿÿÿÿÿÿÿÿÿíîÞÝíÝîîþïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÞÝÞÝÝîîîïÿÿÿÿÿÿÿÿÿÿÿÿÿíÞííÞÝÞîîþÿÿÿÿÿÿÿÿÿÿÿÿÿþÝîÝÝíÝÞîîîÿÿÿÿÿÿÿÿÿÿÿÿúÝîîÞÞííÞîîïÿÿÿÿÿÿÿÿÿÿÿÿííîýíÞíÝÞîîïÿÿÿÿÿÿÿÿÿÿþíÞßÿÝÝîÞÝÞîîïÿÿÿÿÿÿÿÿúîÞÝíÿîÞÞþÝíÞÞÞÿÿÿÿÿÿÿÿ­ÞÝíÞïþýÝÞîÞÝÞîîÿÿÿÿÿÿÿÿííÞÞÿÿïÝíîþÝÞÝíîÿÿÿÿÿÿÿþÞÞîþ®þþÞÞîîÞÝÞÞßÿÿÿÿÿÿÿþîþÿïïïííÞîþÝíÝíîÿÿÿÿÿÿÿÿîïîîþþíÞîîïÝÞÝÞßÿÿÿÿÿÿÿÿþîîïîîÝíîîîííÝÞÞÿÿÿÿÿÿÿÿÿîîþïííßîþÿÞÝíÝîÿÿÿÿÿÿÿÿÿÿîîþÞÝîïîïíÞÞÝÞÿÿÿÿÿÿÿÿÿÿþîïííîîþÿýÝíÝÝÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞþþîÿÿÞÞÞÝßÿÿÿÿÿÿÿÿÿÿÿÿÿþïîþÿÿíÝííßÿÿÿÿÿÿÿÿÿÿÿÿÿÿîïîÿÿýÞÝÝîÿÿÿÿÿÿÿÿÿÿÿÿÿÿþîïÿÿÿÝííïïÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿÿýÞÞïïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïÿÿÿþÝÞþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýïïïïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþïïîþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïîÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿich8 ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³_ƒ‰‰‰à­­àÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà_/Y;5/;;ƒÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ_45_;4;_5^‰éÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­55_;;5Y55e‰‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà;5Y;55;;4_Þ‰‰ßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿƒ5Y5_5Y;55‰‰‰‰‰àÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞ5^;_54_55‰‰­‰­‰Þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà_5;_55;_5_‰‰‰‰‰‰‰³ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰55_;;5_54‰­‰­‰­‰­àÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­;5Y5_5_55_‰‰‰‰‰‰‰­ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà;5Y;_5;;;5­‰­‰­‰­‰àÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰5Y;_Y___5ƒ‰‰‰‰‰‰‰³ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿƒ55;_;5__5:‰­‰­‰­‰Ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­;__Y;5_Y;/_‰‰‰‰‰‰‰àÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰;___;Y5;;;5‰‰‰‰­‰­­ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰5___5Y5_5_5_‰ƒ‰‰‰‰‰êÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­;__‰;_5;__;5_e‰ƒ‰­‰ßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà‰;__‰;_;;_Y;_Yƒeƒeƒ‰‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­;;__Ý__;;_e;_55e‰‰_‰_­ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³__5_‰­‰_;__‰__;;;e_ƒ‰ƒ‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿé­‰;_;A‰é³;;_5‰‰_;_5__‰_ƒeÝÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³­‰‰‰__5_;ƒ­³à‰5_;_‰ƒ;Y;;;ƒ_e_ƒßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿß__;_;_;__Ýß­à­;_;_‰Þ_Y;_;;_e_‰‰àÿÿÿÿÿÿÿÿÿÿÿÿÿÿê____;Y_‰­ßßÞß­__;_‰‰‰e;Y;_5__ƒ_‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰__;_‰‰­³³­Ý­­___Y_‰‰­__;_;;;e_e‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿƒ‰‰‰ÝÞ݉­‰‰­Þ‰Y_Y;ƒ‰_‰ƒ5Y;YY;_ƒ_‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­‰­‰­‰­‰­‰Ý‰A;;;‰‰‰‰­‰_;_;_5__A‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàƒ__‰‰‰‰‰‰­e5_5_‰‰‰ƒ‰Ý;Y;Y;_5__‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­‰‰‰­‰­‰‰;;;_‰­‰‰‰Þße;_;_;;;;‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­eƒ‰‰‰‰_Y___‰‰‰‰‰ßà‰_;_;Y;;;‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ鉭‰Þ³ƒ;__‰‰­‰­‰­à­__;_;_;;;­ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³_ƒ‰‰‰‰‰‰ßàÿ‰5Y;_;Y;;_ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞ‰­‰­‰­‰éÿÿÿ‰;_;_;_;_ßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³‰‰‰‰‰‰àÿÿÿ­Y5Y;Y;__‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿщ­‰­­ÿÿÿÿÿ­_;_;_;ƒ­­ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà‰‰‰­ÿÿÿÿÿÿ‰_;_5_­Ý­­ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßÞàÿÿÿÿÿÿÿ‰Y;_‰Þ­Þ­­ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰__Ý­Ý­Ý­³ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰‰­Þ­Þ­Þ­àÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ߉³Ý­Ý­³ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßÝ­Þ­Þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà‰­‰ßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÝ­àÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà³ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿih32 öû >“`aqY,8T¢ ®ÑÆÍÒÔµËêj¡ ×¹¿¿Ëµ¾Ð·f  HÑʸÀÆ¿µÈÌw`Už©Ïº¾À˯ÀЛZci.ž{ͳ»½Ë··ÌÁh^bc_œBļµ½ÅƯÄÒ‡Za``gFš«Ë´¿¼Ì²»Ð­\^a`aafšvÔ½·»Ä´³ÆÃq[a`a`ca™HÉų»½Ã«¾Î–X`aa``i:™ª×¸¸ºÄ®ºÅ³d]a``_eW˜ ƒÔĵ¸Æ¾¯½ËY`a€`h#™nÍʱº»ÇªºÂ­fa`a``fM˜PÀÀ¯¶·É®µ¼Ôhf``aad˜JÀ» ²¶¿¾ª»ÃÃvrmc``d;˜K»¾”¢º·Çž¸¸Ô¥turic^[ –]»¾“†º´Æ¦Ÿ¾ºÏŽyxspgg6–û‘l°¹¼À†µ·ÁÆ„€|vso^ •F¥Ã¸ŽH‹½µÍ޽³ÉÁ„„ztx5“0€¹»®~9aº²Á­dª»³Ê¸‰‡ƒ}{j ‘K‹´¼º¤d%5¬·µÃrg¶¸´É´Œ†…K%6M^†¨ºº¹±}C$„¾°ÄšV{¼·³È»’‰…„"Œ 2¯²´·µ¶¹±ŒL&.Xº²¼²fX‡¾¶´ÃÈ•”Œx‹ ‘²«®³µ¦J,193>£¸³½~__Œ½¶¶»Ð£”“•c‹!z¾®¬ „]=4>EHA2…¹®¿Ÿikd†¼¶¶´Ñ¶›“œ\‹!nt`P@F@##:¢ r ƒˆ w€®K¡ Qž„vv”s“ˆ6  -Œ™uw„p›H20žnž|w|šsw˜h.69žM–‚su‘†o‰82676 œ *ƒŽqu“o}V/€69)š n›xvu˜yr–{/56:™ K˜ˆquŠ‚k“A1677 ™ .…”quzmu˜e.‚6;#™ lŸ{tsŽwq‰„64683˜ T–ps‡‡lw™O/‚6;™ H†’qqw’oq‰€7469.˜6{|osp‹wpy£[>95€6:˜1{vbor}†ju‹EHA€6;$˜3vw[dvt‹ersžlBIG=577 –=vwZQwqƒocvv’UFIHE99"–R{u[>pux€Rst{„OLHIIB6”.hztX)Vvs‰VXyq{OPKHIK!“ QrsmN;vn{p5jwq‚xRSOIJD1Wptsf;mrq€C8tuqƒvVVRNN/#2=ThrrsnK#Qwmd,HxtqyYYTQNŒ !mnorpproU- 1vowr9-Qytr~][XVJ‹ \njkoqhQ(!fspzN44Vytsv…e^YY>‹!OvmkdQ5!)*&Rsk{e?A:Rwtsrˆqb^_:‹! FE8,"&040+)!9pkptIED8Iurtrdab6Œ 3?:;998530.2gokvW?FH78upsts‹qbf8EPE=76/Vriui>?BI5%oqqtq|„eh=Ž3OG>9562@nknsG7??E)etoqtq‚|jGJNE>878€6  ltoorss‚z’"dL156682 0wpporsr„[—*A4€69/Twoporttv˜!A7569-€qu€psvh,˜8:5:( 2troopsH(˜ 2:?ƒ >zrota+$*˜) ƒ Dxsp@"'(+¤:z\€&''*£ 7D$&&''('¤)')¦)('(&§)()©)'ªåû   ¢  ¡  Ÿ  ž  €  €› ‚š ƒ™  ƒ˜ „˜   „˜   ƒ˜  „—ƒ— „–‚ƒ–‚€„•„ƒ”‰’‘Ž‹ƒŽŒ™‹†€Š„€Š€€…†‹…€Œ……†˜Ž•†„‘„…–ƒ„—‚€„˜€€ƒ˜‚ ‚ ˜ƒ ™… ¢£¥€¦¨€ªåh8mk  &£ãÍÂ̺››¬ƒ'{ÿÿÿÿÿÿÿÿÿÿƒBíÿÿÿÿÿÿÿÿÿÿÛKÁÿÿÿÿÿÿÿÿÿÿÿÿ¡ ÿÿÿÿÿÿÿÿÿÿÿÿÿìb AîÿÿÿÿÿÿÿÿÿÿÿÿÿÿÂ5½ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýˆ}ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙH=ëÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿècÁÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¸Cƒÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿäx_ôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿù£76âÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÐ] ,Íÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿö”&,ÆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÆT/ÊÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿéM×ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿµBíÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿäuEÂÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ¬9M¤ñÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿâq -M…Ìúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ´<“­Éæøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿó…žÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ×Y`úÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¸88äÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¢$Šÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ–UÜÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþgàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ“cÎÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ K®÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¹/2ˆãÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàQc­Äº¥»÷ÿÿÿÿÿÿÿÿÿùÔøÿÿÿÿÿÿÿÿþ“ *;<8+;£ÿÿÿÿÿÿÿÿÿÖƒ¼ÿÿÿÿÿÿÿÿÿàO5§ùÿÿÿÿÿÿû¡7Sçÿÿÿÿÿÿÿÿÿ£"/‘ðÿÿÿÿÿÞh ‡ûÿÿÿÿÿÿÿÿöŠ$wÚÿÿÿÿ²8*¢ÿÿÿÿÿÿÿÿÿøZ»òÿìz5¶ÿÿÿÿÿÿÿÿÿöy 7u«—=A·ÿÿÿÿÿÿÿÿÿëj'& =¯ÿÿÿÿÿÿÿÿÿÆ3;­ùÿÿÿÿÿÿý³73˜ùÿÿÿÿÿáp*‘ðÿÿÿþ¯9$íÿÿåt{èý¯<i•[it32;´ÿÿÿÿÿÅ ø9†Ÿ›‰O*Rjk\B. äˆÊÒÖÓ³¢±ÆÏÐÈ¿ºº—QDqž­²¹w â _¶ÃÅÔȶÁÊÆÅÂÁÇØØ»¦²ÉÒÏØìËAâ8žÃ»¿Ä·´¾ÅÁÁ¿ÂÐÖ½¦³ÉÌÅÇÙݺ` àv¼ÅĽ¯¯¼ÁÂÀÀ¿ËÛÊ©¦½ÉÄÂÒÞÅ’f)ß ^²ÇÏÔ¿¬¶ÄÂÁÀ¾ÂÔÕµ£µÄÄÀÈÛÒ¥taSÝ I¬ÇÉØÓ¹´ÀÄÀÁ¾¼ÉÕÀ¦­ÃÇÀ¿ÏÖµ„d^dDÜ !ŽÅÇÏ×Á°¹ÁÃÁÁ½ÁÑÈ«§¼ÆÄ¿ÊØÂ‘j\_ed*Û"g¹ÅÉÙ̲±¾ÀÃÁÀÁÐÔ·¥³ÆÃ¿ÅÖѨx_]adiP Ú"> ÅÅÑ×¾±ºÀ¿ÀÀ½ÆÕÆ«¬¿ÈÂÂÒ×¹‰g^`ccff,ÙuºÇÏ×ǵ¹À¿¿¾¾ÄÔ̯¥·ÃÿÈÚÊ™m]_b€chP × Y¯¿ÂÔ϶´¾À¿¿»¾Òغ¡¬ÀÄ¿¿ÐÒ¯z]\acee:Ö&8ŸÄ»»Å¹¯¸À¿¾½»ÉÜË©¤¹ÃÂÀÍØ¾fZ`bccdc`c`'ÕvºÅij¬µ¿À¿¾¼Á×Öµ£³ÃþÅÙÐ¥u_^b€cdc^aiO Ó* \°¿ÁÌ¿ª®¼Á¿¾¼¼ËØÀ£¨¿ÆÂÁÒÙ·ˆg^acc_`_ac`bb8Ò6žÃ½ÃÅ®ª¸¿À¿½»ÆÖÊ«¡´Ã¾ËÜÌœo^_€c _`_ac`ada%Ñ,u¹ÀÃÆµ©³¾½½¾»ÀÖÖµ£°ÀÁ¿ÄÕÓ°a]bc`ab_a_a`bagJÏ-a°¾¼Ç½«°¾À¼½½ºÊÜȨ©¾Â½ÁÔØ·‰i^_``__a_a_``a`ca'Ï!<ŸÃ¾ÃƱ­½Â½½¾»ÂÖѳ§¸Â¿¼ÌßÍšo]^^]`d€a`a`a€`fN Í/t¸ÀÅÐÁ«³ÀÁ½¼º¼ÑÙ¼£°ÂÁ¼ÁØÚ´a\]^a`cc_``b`a`a`de-Ì#X¯ÁÁÏ̵®·½¾¿½µÀÖ˪£¸Â¾¹ÆØÄ’j]_^bd_^€` _a`a`a`fh5Ë'3šÃÅÑÒ¹­·¾º»½»ºÆÈ°¢°ÁÁ¼¿ÍÈ¥za]^`ca`_adc_€a`bbiYË1qµ¾ËÙÇ®¯º¼ºº¸½Ì˰ž¨¼Ã¾ÀÐѯ„g[]_a`^adc`b`a`a`beg:Ê1 Z®¾¾Îɳ­·¼¼º¹ºÈ×Ä£¡¶Â¿¹ÅØÈ–l\[`db_`_a_^`_a`a`biYÊ2E§ÂÁÌ̵«´½¾¼»¸¿Óϰ¡±Âû»ÍÓ³€bY^_a`ac`a``_a`a`aeh>Ê%‡ÀÀËÙÆ¬®»¼»»ºµÄÓº §½Á¼ºÇÓ¾‘m_\a`a`bc`€a`b`a`diTÊ a±¿ÃØÔ¹­¶»¼ºº¶·ÈÄ©¡³Á½¶½ÐÊ¥xa^^€a`b_^a€`b`aahb,Ê17™½ÁÓÜÄ®³¹º¼¹¹»Çɯ¡±ÁÁ»¸Èͯ†f^]]``a``_``a_]aabeg?Ê1p³¾ÍÞγ¯¸¹¹»¸¸ÉÖ¤¦¼Â½»ÅÒ½Žl\]^``a`a`aa_a_]a`ciWÊ)d¬¼ÂÚØ¹­µ¹»º¹¶Á×Я ²À¿»ÀÕÒ©xa]]`b`a`a``_a€`bafd2Éc®¾¾ÒÜÅ­²»º»¹µ¹ÐÙ»Ÿ¦»¾ºµÀÕÄ”k]a€`a`a_a_^a`aabciOÉ2U¬ÀºÇÛβ­¸¾»¹¸¶ÇÚɧ ²½½·±¼Çª{b]bc_]baa`b`a`a_]bfb*Ê#<£ÀºÀÕÕ¸ª´»¼»·¶¾Ôѱž­¾¾¹·½È¹’nbabd`]€a`€a`a_^diK É2ƒ¾½ºÍÔ¾¬¯·¹¸»¶·ÊÒ·Ÿ¤¸¿½·»ÐÏ«€jhgddb`a`a`b_^a``bg^'Éi³¿¹Âο«®··¶·»·ÁÔ¢ ¶½€»ÌÜÇ›whijgba_a`aab_]b`bggAÈ*a¯ÁººÆ¿¨§¶¸¶¶¹¸¼ÒÒ¯š«Á¿¹µÀÛݶ‹sljjica_`_a`€a`acfYÈ4]­Â½¹»º©¡¯º¸¶¶¸¸Ç×Á¡¡·¿¾º´ÆáÒ£|nrqlkhdcb_a`aab`_c`6Ç4 YªÂ¾¸¸´¤›¨¸¹·¶´³¿Ô̪ž±¿º»¹¶ÌÞÔtmsvqmjgcb_aac`^]]dLÇ4Y©À½»º³¢”³º¸·¶²¶Ìӵ𤻼ººµ½ÕЪ…sprvsokhdbcc`c`\\`\#Ç5]ª¿»º½¹£Ž“¬º¹·¶³´ÄÔÀœ–®¾º¼¹¸ÏàÄ—}ssrttrmjebca\_]]ccBÆ5Zª¿¹µºº§Š‡¡¸º··µ²¿ÔÌ¥£¼¿»¹·Áß⺎yvwustuqmifdb_]Z]eZÆ6^ª¿¹´´¶©‰{’³»¸··³·ÎÔ´Ž’²Á½»¶³ÅâÕ©…xz|ytsusnljgcc`Z\cBÅ6c«¾¸µ··«Žu§½º·¶µ²¿ÒÀ–…žº½¹»·´ÉÞÆ›z{|yussqpmkhddb]`[ Ä2/v«¼¹´¶·®“rr–¸¼¸¶µ²¹Íͦ„¯¼º¹¼·¸ÑÚ»’~zz{zxtsqrqnjfcBÃ8 K˜¹½¹µ··­•si†°¾¹··³´ÈÖ¼Ž~œº»¹¼»µ»ÖÔ®Š}~}{|{vvutsokideiWÃ9T¥¾»·¹µ±ª“rdz¦¾¼··µ²¾ÔÌŸ{ƒª½¸·¹¸´ÀÚΣ…„‚|{|ywuttqmkijf1Á0m§½·µ´¶°¢q[h–¸½¹·¶³¸ÍÓ±‚t“¸¼·¶ÊßÇšƒ‚…€}||xtsttpmloVÁ;S›¸¼¸³¶¸°£mQQ|­º¸··´µÈ×Ã’p{§¿º¶·¶¶¹ÔãÖƒ‚„‚€~}{vrstpmpm7¿<2s¨»¸·µ¶·²¤‹kK@]˜¹¸¶·¶³½ÔϪzjŒ¶¾¸¶·¶²»Ùã¾”††……€~{|zsrsrstY¿!P𷏲±¶¸·¯ˆjI7I²¼´²µ´·ËÔ·Šjnœ½»¶±ºÛà·‘‰Œˆ„…‚€}|}yttvzq7½> 5s§º·±¯±··­—eG3;m§¼¸²²³³¿ÓÆ™obz«¿º¶··¶±¼Üݲ‘ŒŒ‡…‡†‚€||{wsvx^¼@3lŸ·¸´°°²³¯£Žs[E/2\˜º»²³³¯·Êɨ{^aˆµ¾¸¶¶·¶±½ÝØ«‹‹‡‰‰…‚€}{{ztxu<¹B=n¶º¶²¯°³¶¯™€iQ<)'I‡´¼·²³±°Äβ‡gWd’¹¼·¶¶·¶±¾ÝզޑЉˆ…„ƒ}||{}j·E )P‚©·¹¶²¯¯°´¶®˜x\H6$3n©¼·´²²±ºÏÄ™t`Wjœ½¼·¶¶·¶²¾ÝÔ§‘”—ˆŠˆ…‡…€|{~S´G"Ck™±¹¹µ±¯¯°³·¶¨ŒqV>, #U˜»º³²²°´Çͯ€e\[s¤¾º·¶··¶²¾ÜÓ§‘”–Œˆ„…€~|}8±20Fb‘®¶¹·³°°¯°²¶¶®›~_J:+ =€´½µ²²±°¾Î½‘j\[_~®¾¹¶€·¶±¼ÛÔ¨’“•Œ†„„‚‚€}…o©9  (3=ES¥°´º¹µ±¯®®°±´¸µ£…eL;.((!-c¢¼¹²±³°¶ÊȦz`\\bˆ´¾¹‚¶±»ÚØ®“‘••’’Š‹ˆ……ƒƒQ¨S`sqr…¦ª®±·¹·´²°¯¯®¯°³¸¶ª“pM5..$%"Lµº´±°±´ÅʱŠi^_\e‘¹½·¶¶··¶±ºÙ߸—’•––‘Œ‰…†…‡{/¨w³³°®¯´²±©«¯¯®¯¯±µ¸·®™zX:'!+4)%!;x­¼¹²€±&¾Ì¹“o__a[h™½¼··¶··¶²·Õà¿””––ŒŽ‡„†Œt§;T¯¶­®¬­ª¦«ª¬®¨«°¯°±µ¹·®š€^C- ")471)-b ¼¹³²°²¹ÉŤx`]aa[jž¿¼€¶·¶¶³µÎàÆ¥˜”•–•“Šƒˆf§ '–·¬¦««¬©¦«°¯€®+°³µ¹¸¬–y]F1&#'1;:75(%JŒ¶¼³±³°²¾Å°‰f[_b`\m ¾º¶··´²Çßͯž•“•—–ŽŒˆ‹‰J¦< k²­§¦«¨§¬¨¦¬«­±°µ¸²ª—wS:/'%,28:<:63,>v«¹µ³²²±¶Ã¶“r`^bb`\q¢¾º€¶€·µ±ÀÜÓ´¥›““–—•‚1¦VJ£±ª¬ª«©¥¬©¨¯°µ¶°«Ÿ‡mS9($&+6C@<;796-8dž¸³±µ²¯´ÀÁ¥hceghear¡¼º·¶·¶··¶²»ÙÚ»«¡˜•–”’”‘‘€'¥W<™±©§ª¦©¬ª°²µµ³®Ÿv\D3('.8;@GKHC<5724W³¶°±³²°¿Æ°qgikkiieqžº¹¸··¶¶·¶³¶Ïݬ§ž—”“”–“€!¥ #º±©©ªª¯µ€²'¬›‹w^I7)&*3@GJHFHGGIA<81G€¯¸²¯±°³¸Ç¿™yki€kikel›»¹··¶·´²Æßβ«§™““”–—’–}¤Xoµº´°²°­¬©Ÿ‘…u\H8,((/70+-29BJRY]__YRRSNMLHIHDC=Hw¨¸²®¯®­´Ã¾¡omqssojmnUQ‹»º²²¶¶··¶¶´²ÃßÖ¶ª¨Ÿ˜•”•™¡r ¥ ,@=9879;<@GNV^cd`[[\ZUWTQ%POGB?Ehœ·µ¯®¯®°¼Â®umnnpsqlnlMI„¸¹°²·¸€¶·¶³¸ÑßÈ­¦¤™–••™¢q ¦VH\ZWZ_bdglmjhhfc][YWSXZVVROPOLIG]޳·±®¯®®¶¿²“xkmpqpprqqiE>y´»³²³¶¶·¶·¶´²ÀÛÙ»¬¬Ÿšš–˜¡p ¦V$d{wvurpokeddedaZXYY[[TTSNNRLW­¸²¯®®­¯»»¢€lgiosqoptug@4l¬»¶²±´´µ¶¶·¶²µÎàᬨŸ›˜˜¡q ¨"%c§¼¶€²³²³µ¶€· ´²ÁØÕ¼­¬¡¤’0®NOyƒysqnkjkidbbdb\VQZ~¨¶²¯¯®­°¼½§‹o`efefgihkmomU/K”»»³°´´°±µ··¶·¶´´ÆÙѹ«§¨–<¯.d|uspmlkiecbc`YWo·µ¯€® ¯µ»°•vecfhh‚g#hjeL*6¶¼³²³±²²³µ¶¶·¶¶²µÇÙÏ·«§œX°LU€xuspmkihffgcm’´·±¯®®­±»³žƒi`ggiihhfgd_d`F( "'b¦¼¶µ±±´µ²²´µ··¶¶²·ÊÙз¨¦z±Gw‚~{yuroqmjgg{¢¼¼´°¯®¯¶º¦‹scc€hfgedd_]gb=! #BŠº¼µ²²³³²³³µ€· ¶µ³·É×θ°”/²6+\vyvspnkcWE34V‰¯º¹´¯³º±•wecfefecb^ac_^g`7 $#U¤¿º³³²³²¶¸··¶µ²¶ÅÒÍÀ§P³I (6633-&$Z—°¶·»º¥ƒjbdecdc`__``acgX1!%$c¨½¶³³²³²³²±µ·¶¶·µ³µ¿ÐÓÃÂ0c¯¼¯o€b€c!`]`c`^adfO*#%#w²½¶µ±´±³³°²´µ·€¶´´ÀÒ׸QÃVˆ¦Ÿx`]]`_``]``a`a`aeI&$€E™¾»´³³²³³´²³µ··¶¶µ´´½ÏÒ— Ã;h…ˆlY\^`_`_]`_^bc`cdE$$‚hª¼µµ±³²³´²²³¶··€¶´³ºÊÀ]ÃMtwfZ[a_a`a_^``a`aeaA# ‚-³¼µ²³²³²±µ··¶·¶µµ¼Á&ÄIpqb\a_``a_^ac_^be_=! „ O¾¸´±³±³±³³¯³´¶·¶¶·¸¹»¦QÄ ;ioe_`_a_]``a`aad^9!…&u±½¶²³²³²³´³²²µ¶·¶·¹¸°›bÅ*atg`^`_]`_^ac_b\7 †<‘½»´³¶µ³²³µ±±µ¶··¸¸µ¤„a3Æ"awlb^`_^a_^_``T2‡ [¨¿ºµµ´³²²€³ ²³¶·¸¹¯–pSAÆ Yrla`^]b_[Z^_L,‰$u²À¹³‚²³µ±±³¶¹¸¦‚]IKCÆ:aoe]\][][_`M)‰/{­¼¸³²²³²²³µ¸®‘kOFMN=Æ "^ti\ZZ\\a`J‹,t«½¸³²²³²³²³³¸·y[GAFII6Ç!^ti_€\a`? Œ8ƒ·½µ²³´±³²´µ·«ˆeOEBBEHJ8Ç Hejda^c]) M˜½»€´²³²µ¸¯—uUBBHDCGKJ7Ç D]cdiWWŸ¾½¶³²²³·¸¥…fJ?DMKGEDGK8È;Ua@ T¾½µ³²µ¸°•qSDBFMLIEBFKJ6Ê ’L–»¼·´µµ£€_GACFIEEGFFEHL5 ã ?ޏ¿ºµ®“jOCBEGIECGIECGKI.ã9Š·Àº¤~WECCDGIHGEFFGFDFG)ã5ƒ³µ–jJACDGHFGHECGHECGKH*ã3ƒ¢‡\DBEHIHFEFEEFFEEFFIFä:uuVCBGHFGHFFE‚FEFGBå2QOGFFEDHHFFGFE€FEGG(æ.GIFFHHFDGIEDGHEDH3é:HKI€FE€FEGFEGCê AMJFFEFEƒFI7ë?KJG†FE í*AKHGE‚FG7ï%GKHFEGDñ *EKIFEFGH5ò #CNGDGJDô(ILIHH5õ )FKIG÷"AJ6ø$ ÿÿÿÿÿÿ‡ÿÿÿÿÿÄ  ÷+Xekn@6FE;) äY}ƒŸ«…eqƒ‚|t–w9.Kfnv‰^ â @rzŒªœ{v‚~|x‚¤°Šiqƒ†„šº›-á+fz› ƒqu|}|x{–«‘ml}|ˆ©²ƒ:àMu‚—Ÿ†qvyx{zx«sgv~w~³–]8ß ?n~˜¬–sn{}zyv~ ©ƒfp{v¯¤oB3/Ý 5kxЬ¨‚ov|{zut§’miz~v~¡­ƒM428)Ü Zy€ž­qt{zyxr wfuyy”®•^:/279Û"Cpy­wozzxxty—¨ˆgm}}v…§¤sE314680 Ú.dw‚¢«ˆpv{yywuЍštjyx}™©‡S914€68ÙLs€™¬•vs|{zwvƒ¡¡|guzv‹§—b<225€68. × =nxŽªŸ|py{{zt|œ¬‹fi|~v¡¢uC025678%Õ*exš¢„nuzwxwv°Ÿrdt|wy–®ŽU4/4ƒ678ÕMq|“¡Šonzxyyt€¥¬„fn}xs†¨¢pC215„69/Ó ?owŠ¥–tiszwyvv‘©’li{}t}ª…R924…678#Ò(bx› €jrxywvs„¡™tdtvu’¯›d>225†678ÑLpxŽˆnnyyxvr|œ¤‚gn}|s„¦¦xJ414ˆ69-ÏBnu„žrluyxwst«—pj{}u~«‡S913Š67Ï.fy~™¢ltyyvsrƒ¥¤~hr|wv“°e=125Š69/ÍNtz¨–snxyzwpx™«‹imz{t¦«~K414‹68:Ì mvˆ¦œzjrxwwus‹¨•kbt|urŒ«™c;03Œ67;5Ê2hw~œ£‚jo{zxuqz™ž|dn|zq| ¦{K305Œ69;&ÊWvv¨“pkwzuwsq‰ ˆffyyqu‘§ŽZ<34Œ68<2Ê Bou„¤£~jszustq}›˜sbq~up„£škD33Œ67::Ê)bv}œ­onvwwuqvžfmzyr{›£}P923Œ69;(ÊIox’­xluwwyut‹ Žlfw{rs§\=325‹67;4ÊDmt…§§‚mqwyxsq‚£œuao{xq~¢£tG314Œ69:!ÉEpv|œ­oouuwtnw–¥…dewzro‹¬“[;02Œ68<0 É 655‹68=-É"VyvuŒ™…mltutsnrŽŸ„ghvyvn}£¤uK<==85Š6:9È$Frzt{‹mksttsqmžjcrxxsv—³•`G>??945ˆ68;*È%Cp{vx€{jhruttsnv–žy^ixytp„¯±~QDC@?<75‡67;7È'@q}yuvxhbmuttspp†ŸŠfcu{zqr”¶eGCHFB?=75†69:$Ç( =n}yusph^gtuttrn|™–q`p{wwq{¢¬‚VEEIJGB?95…689558;*Ã8 5atvsqrrn]C;Rqyuttqqƒ•€XK`xwstsnzš”lPIJHGHIHIHIHD@;7694Ã,9kwtstqpm]C7Ik{wstroygIOmyuttrn}šfPNPNJHHIJGB@=:9Á#Giwsrppnj\B0:^vyuttqtˆtNC\ww€t rp‚™…`OOQNMJH€IHJIEB@?2 À8cswrorsmeZD,,Kmu€tqr‚’X@Jlzusttqr‰˜{YOOQ€M IHIHHIIEBB@#¿<%JitrtrsspfTB*!7autrttpyŒkD;Wvyuttspt—xVQRQQNMJGHIHIIGFF7¾"7aqqmnsrsobR@-(Qsvposruˆ‘xR9=azw€tspu–tUQURQQOLJHHIHIKLF$¼$ &Jgtqmlnrrm^M<)!Bkxsoppq}„`>1El{v€tspu‘•qVRURQRQMLIGHHIKJ<»& %Gbqqnllmpmg[F4&8cwuoppls…†kJ11Qsyu€tsov’“nWTXTSSRNMJGHIIMI)¸C*Gcprpmkloqn]NC3  'Xuusnpol}‡sS9,4Yvxtsttsov’‘kVU[WSRQQPMIHHJOE·E 6Shprpnllmoqm_F3( Bnwqpoont‰aD2,:azwtsttspy”‘kWVYZUSRRSPLHHKN6´  .E_nqqpn€lnqqhXF2 .`wupoomoˆsO80/Ahzvtspy”kYYZYWURQQOMJHMK%¯ #/?[lpqqnl!nprpcK6.% OtwrponnzŠ|[>1/3MpyutspulZ\[UUVSQQOPMINC©8 %+/6QgnoqqpmllklnprqdS=( 9gwtoopmr†‡mK4005Vux‚tspu‘o[[\\YWTTRQQOLM1¨?IHIUdiklnppqpnl€k%lmorqj\A' )Wsupnmno~„tY?1306Zvw‚tspu•t_]^_[XYWRQRPPJ¨Lnm€kmmonomii‚k&mosrk^K8  Iovtonnmz…v\D424/8_yw‚tsptŽ˜yb`^[Y[[WYUPQTG§;8mpkljihhjiklhjkklmorsoaN9' 6fxspomot„eF41440;d{wƒtqrˆ—~ga[[]]WU\VPSXA §`qkh€jgfj‚l-mnprso_I4%#  'Xtvononnz€rU8/3530?fzvtstrq“‚kb^`^ZXVUVRTT0¦< Fpkghkjgihgjiknmpspm`J/! " Hnsppoonst]F425530Ah{wƒtspx‰nddb\\^ZTUVXP!¦3go€i6kifjigkmqspmeVH2 #(''$!:esmnrnlq}lP=9:;;:7Dfyw€tsttsouŽtffb[``YWVVZP¥>+bnihifihhlnoppneVG6'#++)'$" 1Zrplopom{ƒqZD<>AA<>=Ccvu€tsstsqr†’{igd^^_[YXU[P¥?[rmiijkmonnqnbUH6%#)(,+'')&%"&Pprmlnmpuƒ|_I@>?@A<=;>bwtuƒtsr}‘‰ohhd_^]\^Z\O¤) IrsonqonmleYSI6& )-/..0*%(-)*& ;fun€kjo|oQADCCAA?<69\vsr€tsstspw‘•whifc_^_][^M¤3%ankeb`ZQKC8*"!(.75..0.,''&(*(#,Urqlkkiit~r]IA€G C@@<24YusqqstsqsŠ˜jgheb`^XX`H ¤B9C@;60*#&/16::;70.3+'(-("%#)Fisnklkjq€{cOEDGGHD?AA20Ywtoos‚tsq|“Žqffec`^^]`H ¥ €  $,/3:;9€86231--,,/-*'"?drp€kjlxoVFDECDGFAAB0*Svtmotu‚tqsˆ–iefec`_aaG ¦A *43679<<=>>;78867665035131-,140'6\rqlkljks{q^JACFFEEGFD@'!Mvvoops‚trp{“’wihfc`^`eI ¦ @QPNJIHECB?7…6-776130+13/3PmrmkkljlwwhRC=?EGFCEIG<Bntronqqr€tsqr†˜‰ohgdcb`eL ¨@RPMJID@@>99756€7 503512--Ffrn€kmmtynZF==?CEEDEJK<"4ewrp€ostsow”zihfcc`dL ©?ONLJFCA><;755ƒ656€73,:]rpl€kns}wbI<>845‚6406Qkplk qyseK769>>?@@A@BG>%;mxqopopopr€t sqq|uhhfi`#®2HOLIGD@?@=645€6512Kiqn€k"jmxzmYB599:;;>>?ABA4 ']wvqmqqmnr‚t qq€‘Šsgfja*¯=NMKJFAA@=:756631@arolkpvp_G98:…;<:- Pwwqopnooprt spr€“‰qfic<°5NOLKHDB@=;8675>Yorm€k jmvqfR>5::>=;;€8578&  :kvqrnmqropqs€t sprƒ‘†pggP±= -HOPOLHDBB>:79JfwuollklqvmYF::;<<897565698  "Wwvqooppopprt rpsƒ…ql^"²6;KMKIGDB;4+!"9Zqvsokntp`I98;8975665667:7  7k{tppoposu€t sps€‹„wg7³ &'%% F;7667:9#Œ +Tvwqoprnpn€q mW<,#%(('(#Ç 0>=977;8 7byupqqnpoqsobJ0%"$))&%*$Ç,7: 7“óÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþчX1)eÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿø·tI$  I®ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿã–c9:˜òÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿû¿|Q))iàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿæh= G®ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÇ€Q(3‡ïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿå–b5&`Öÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿâk< F¬üÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùÈ•k;7ðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ䯋_2+nÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúÊžzM%  "P¾ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ鳎e8 ;˜÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÊžzM& -jÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÜ­‹c7(W·üÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ뺘tI$ "R·øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøË£ƒY1 @¢úÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ߯i> 2…îÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóÁœxM'*dÕÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýשˆ^5&Q¸ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿò¼—qE! $R®÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýا„Y/#M¬ùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿí¹•oB "J©öÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÒ¤ƒW-"Fžõÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿè¶“k?#L¥ñÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôÅŸ}R*$M«÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýت‹c9%M©öÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿtH#  (P©öÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÔ¦…Z1 0a²÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿê·”mB :}ÒýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÏ£U, %B‹æÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿë¶’j>2\¢ëÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúÍ¡~R) &FŠÔúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþà°f;5h±ðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõÃzN& (CˆÜþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿá­‹b7&:d«ëÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÇwJ$  (=e Ùýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿå°Œb6 #0Cj¢Ûüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÇžyL%  !-@aˆ°àüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿä¯c7 $.;T‚¬ÙöÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûÍ {M&  !&.6=Hc†¢Çðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿð¹‘h: ):>?DXt€ž¨³Ûõþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿß©ƒU+ A¯ •§ÍíðüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûË›sD F¤ñÿû÷üÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿí¶Žc5 :—öÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛ¥€R' -uäÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüËšrB "QÂÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõ½c5 :•õÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿè®…V*/váÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÚ¢zJ! 'cÑÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÓšp? I¸ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþΔh86’ôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÉb2 !]ÚÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùÀŒ].*wîÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿø¼‰Z,.hÊýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿø»†W* )SŠÎûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷º„T(  ?f’Øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ºƒS' 'Hlàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ºƒS' *JožÝþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿø»„U( +LpÚýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿú‡W* ,Mp™ÓùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþË‹[-,Lm‘¿êÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÐ`2*Gf„«ÝýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ–h8%?]zžÒ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿç¢pA6Sp‘¾èýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõ³zK#  .Ig„§ÖúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýȇX-&?\x˜ÊôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞ˜g:4PmŒ¸äüÿÿÿÿÿÿÿÿÿÿúôùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿô³wJ#  +Fc€¡ÈäðñññðîìåÚÊÀÇßùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùâèþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿØŽ]3#;Wr‰Ÿ­±³³²°®©£™š¦ÇìþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûÛ½Äïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿô®sG"  0G^o{ƒƒƒƒ‚€{upr}±ëÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿé¼®¬Íûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ×_5 "2AKQSSSSROIC?BPg„Âûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúͨ›“¢ßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿù»xK%  "%''''&$ (@`‹Ñýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ㱕~q{ªðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿâ•c8  >bÐúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùÉŸ~]MY|ÇþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿöµzO( "BfŽÅôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿë´f?.:\•åÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿâœg> %Ceˆ¸êÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûÏ¡}P)!Bl²÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþЇZ5 $Aa€«ãÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿé´‘h; *P€Ìþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷¼|S2 !;Zz¥áþÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÓ£€R)7^”áÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿó½}S3  5TužÎòÿÿÿÿÿÿÿÿÿÿÿÿÿó½•l? !Ck¤æÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÃU4  0On޵äÿÿÿÿÿÿÿÿÿÿÿÿ᪅X-)Mt©çÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùÄ€V4  +Gd€§áÿÿÿÿÿÿÿÿÿÿùÉ›tE 0Sy­îÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùÅU2$@9+ $Bc‡¼òÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿø°oB  "?`…¼òÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÄP& !=`…¼òÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõº„U)  =`…ºíÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÙ¥}N%  =^‚®Ûúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿç·”m? ;[zÖþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùÊ¢V- 6TsÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ쵑i> 0NpŸÞþÿÿÿÿÿÿÿÿÿÿÿÿÿüÒ¢~Q),LoÒóÿÿÿÿÿÿÿÿÿÿÿÿí·’i<,Ln½òÿÿÿÿÿÿÿÿÿÿýÔ¤€S*+Iiоòÿÿÿÿÿÿÿÿÿì¹”l?'Cd†ºñÿÿÿÿÿÿÿüÒ¥‚V,#?`„ºòÿÿÿÿÿÿí¸•m@ =_ƒ¸íÿÿÿÿþÖ¥‚V- <]€°èÿÿÿë¹”l? :Z|©Ûïá¾}S+ 7Vv•¨¥–€^8 2NfuyoY<  (:FIA0stella-3.9.3/src/common/0000755000175000001440000000000012267274566014477 5ustar stephenusersstella-3.9.3/src/common/FrameBufferGL.hxx0000644000175000001440000002332612266336753017641 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FrameBufferGL.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef FRAMEBUFFER_GL_HXX #define FRAMEBUFFER_GL_HXX #ifdef DISPLAY_OPENGL #include #include #include class OSystem; class FBSurfaceGL; class FBSurfaceTIA; class TIA; #include "bspf.hxx" #include "FrameBuffer.hxx" /** This class implements an SDL OpenGL framebuffer. @author Stephen Anthony @version $Id: FrameBufferGL.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class FrameBufferGL : public FrameBuffer { friend class FBSurfaceGL; friend class FBSurfaceTIA; public: /** Creates a new OpenGL framebuffer */ FrameBufferGL(OSystem* osystem); /** Destructor */ virtual ~FrameBufferGL(); /** Check if OpenGL is available on this system, and then opens it. If any errors occur, we shouldn't attempt to instantiate a FrameBufferGL object. @param library The filename of the OpenGL library */ static bool loadLibrary(const string& library); ////////////////////////////////////////////////////////////////////// // The following are derived from public methods in FrameBuffer.hxx ////////////////////////////////////////////////////////////////////// /** Enable/disable phosphor effect. */ void enablePhosphor(bool enable, int blend); /** Enable/disable NTSC filtering effects. */ void enableNTSC(bool enable); bool ntscEnabled() const { return myFilterType & 0x10; } /** Set up the TIA/emulation palette for a screen of any depth > 8. @param palette The array of colors */ void setTIAPalette(const uInt32* palette); /** 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 */ void getRGB(Uint32 pixel, Uint8* r, Uint8* g, Uint8* b) const { SDL_GetRGB(pixel, (SDL_PixelFormat*)&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. */ Uint32 mapRGB(Uint8 r, Uint8 g, Uint8 b) const { return SDL_MapRGB((SDL_PixelFormat*)&myPixelFormat, r, g, b); } /** This method is called to query the type of the FrameBuffer. */ BufferType type() const { return kDoubleBuffer; } /** This method is called to query the TV effects in use by the FrameBuffer. */ string effectsInfo() const; /** This method is called to get the specified scanline data. @param row The row we are looking for @param data The actual pixel data (in bytes) */ void scanline(uInt32 row, uInt8* data) const; protected: ////////////////////////////////////////////////////////////////////// // The following are derived from protected methods in FrameBuffer.hxx ////////////////////////////////////////////////////////////////////// /** This method is called to initialize the video subsystem with the given video mode. Normally, it will also call setVidMode(). @param mode The video mode to use @return False on any errors, else true */ bool initSubsystem(VideoMode& mode); /** This method is called to change to the given video mode. If the mode is successfully changed, 'mode' holds the actual dimensions used. @param mode The video mode to use @return False on any errors (in which case 'mode' is invalid), else true */ bool setVidMode(VideoMode& mode); /** 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(); /** This method is called to create a surface compatible with the one currently in use, but having the given dimensions. @param w The requested width of the new surface. @param h The requested height of the new surface. @param useBase Use the base surface instead of creating a new one */ FBSurface* createSurface(int w, int h, bool useBase = false) const; /** This method should be called anytime the TIA needs to be redrawn to the screen (full indicating that a full redraw is required). */ void drawTIA(bool full); /** This method is called to provide information about the FrameBuffer. */ string about() const; /** This method is called after any drawing is done (per-frame). */ void postFrameUpdate(); /** 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); private: enum GLFunctionality { kGL_BASIC, kGL_VBO }; bool loadFuncs(GLFunctionality functionality); // Enumeration created such that phosphor off/on is in LSB, // and Blargg off/on is in MSB enum FilterType { kNormal = 0x00, kPhosphor = 0x01, kBlarggNormal = 0x10, kBlarggPhosphor = 0x11 }; FilterType myFilterType; static uInt32 power_of_two(uInt32 input) { uInt32 value = 1; while( value < input ) value <<= 1; return value; } private: // The lower-most base surface (will always be a TIA surface, // since Dialog surfaces are allocated by the Dialog class directly). FBSurfaceTIA* myTiaSurface; // Used by mapRGB (when palettes are created) SDL_PixelFormat myPixelFormat; // The depth of the texture buffer uInt32 myDepth; // The size of color components for OpenGL Int32 myRGB[4]; // Indicates that the texture has been modified, and should be redrawn bool myDirtyFlag; // Indicates if the OpenGL library has been properly loaded static bool myLibraryLoaded; // Indicates whether Vertex Buffer Objects (VBO) are available static bool myVBOAvailable; // Structure containing dynamically-loaded OpenGL function pointers #define OGL_DECLARE(NAME,RET,FUNC,PARAMS) RET (APIENTRY* NAME) PARAMS typedef struct { OGL_DECLARE(Clear,void,glClear,(GLbitfield)); OGL_DECLARE(Enable,void,glEnable,(GLenum)); OGL_DECLARE(Disable,void,glDisable,(GLenum)); OGL_DECLARE(PushAttrib,void,glPushAttrib,(GLbitfield)); OGL_DECLARE(GetString,const GLubyte*,glGetString,(GLenum)); OGL_DECLARE(Hint,void,glHint,(GLenum, GLenum)); OGL_DECLARE(ShadeModel,void,glShadeModel,(GLenum)); OGL_DECLARE(MatrixMode,void,glMatrixMode,(GLenum)); OGL_DECLARE(Ortho,void,glOrtho,(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble)); OGL_DECLARE(Viewport,void,glViewport,(GLint, GLint, GLsizei, GLsizei)); OGL_DECLARE(LoadIdentity,void,glLoadIdentity,(void)); OGL_DECLARE(Translatef,void,glTranslatef,(GLfloat,GLfloat,GLfloat)); OGL_DECLARE(EnableClientState,void,glEnableClientState,(GLenum)); OGL_DECLARE(DisableClientState,void,glDisableClientState,(GLenum)); OGL_DECLARE(VertexPointer,void,glVertexPointer,(GLint,GLenum,GLsizei,const GLvoid*)); OGL_DECLARE(TexCoordPointer,void,glTexCoordPointer,(GLint,GLenum,GLsizei,const GLvoid*)); OGL_DECLARE(DrawArrays,void,glDrawArrays,(GLenum,GLint,GLsizei)); OGL_DECLARE(ReadPixels,void,glReadPixels,(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid*)); OGL_DECLARE(PixelStorei,void,glPixelStorei,(GLenum, GLint)); OGL_DECLARE(TexEnvf,void,glTexEnvf,(GLenum, GLenum, GLfloat)); OGL_DECLARE(GenTextures,void,glGenTextures,(GLsizei, GLuint*)); OGL_DECLARE(DeleteTextures,void,glDeleteTextures,(GLsizei, const GLuint*)); OGL_DECLARE(ActiveTexture,void,glActiveTexture,(GLenum)); OGL_DECLARE(BindTexture,void,glBindTexture,(GLenum, GLuint)); OGL_DECLARE(TexImage2D,void,glTexImage2D,(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*)); OGL_DECLARE(TexSubImage2D,void,glTexSubImage2D,(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*)); OGL_DECLARE(TexParameteri,void,glTexParameteri,(GLenum, GLenum, GLint)); OGL_DECLARE(GetError,GLenum,glGetError,(void)); OGL_DECLARE(Color4f,void,glColor4f,(GLfloat,GLfloat,GLfloat,GLfloat)); OGL_DECLARE(BlendFunc,void,glBlendFunc,(GLenum,GLenum)); OGL_DECLARE(GenBuffers,void,glGenBuffers,(GLsizei,GLuint*)); OGL_DECLARE(BindBuffer,void,glBindBuffer,(GLenum,GLuint)); OGL_DECLARE(BufferData,void,glBufferData,(GLenum,GLsizei,const void*,GLenum)); OGL_DECLARE(DeleteBuffers,void,glDeleteBuffers,(GLsizei, const GLuint*)); } GLpointers; GLpointers p_gl; }; #endif // DISPLAY_OPENGL #endif stella-3.9.3/src/common/FSNodeFactory.hxx0000644000175000001440000000331212266336753017671 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FSNodeFactory.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef FSNODE_FACTORY_HXX #define FSNODE_FACTORY_HXX class AbstractFSNode; #if defined(UNIX) || defined(MAC_OSX) #include "FSNodePOSIX.hxx" #elif defined(WIN32) #include "FSNodeWin32.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(UNIX) || defined(MAC_OSX) return new FilesystemNodePOSIX(path); #elif defined(WIN32) return new FilesystemNodeWin32(path); #endif break; case ZIP: return new FilesystemNodeZIP(path); break; } return 0; } }; #endif stella-3.9.3/src/common/PNGLibrary.cxx0000644000175000001440000003353512266336753017201 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: PNGLibrary.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include #include #include #include "bspf.hxx" #include "FrameBuffer.hxx" #include "Props.hxx" #include "TIA.hxx" #include "Version.hxx" #include "PNGLibrary.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PNGLibrary::PNGLibrary() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PNGLibrary::~PNGLibrary() { delete[] ReadInfo.buffer; delete[] ReadInfo.line; delete[] ReadInfo.row_pointers; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PNGLibrary::loadImage(const string& filename, const FrameBuffer& fb, FBSurface& surface) { #define readImageERROR(s) { err_message = s; goto done; } png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_uint_32 iwidth, iheight; int bit_depth, color_type, interlace_type; const char* err_message = NULL; ifstream in(filename.c_str(), ios_base::binary); if(!in.is_open()) readImageERROR("No image found"); // Create the PNG loading context structure png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, png_user_error, png_user_warn); if(png_ptr == NULL) readImageERROR("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 == NULL) readImageERROR("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, NULL, NULL); // 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) { readImageERROR("Greyscale PNG images not supported"); } else if(color_type == PNG_COLOR_TYPE_PALETTE) { readImageERROR("Paletted PNG images not supported"); } else if(color_type != PNG_COLOR_TYPE_RGB) { readImageERROR("Unknown format in PNG image"); } // Create/initialize storage area for the current image if(!allocateStorage(iwidth, iheight)) readImageERROR("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) (uInt8*)ReadInfo.buffer + offset; // Read the entire image in one go png_read_image(png_ptr, ReadInfo.row_pointers); // We're finished reading png_read_end(png_ptr, info_ptr); // Scale image to surface dimensions scaleImagetoSurface(fb, surface); // Cleanup done: if(png_ptr) png_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : (png_infopp)0, (png_infopp)0); if(err_message) throw err_message; else return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string PNGLibrary::saveImage(const string& filename, const FrameBuffer& framebuffer, const Properties& props) { ofstream out(filename.c_str(), ios_base::binary); if(!out.is_open()) return "ERROR: Couldn't create snapshot file"; // Get actual image dimensions. which are not always the same // as the framebuffer dimensions const GUI::Rect& image = framebuffer.imageRect(); uInt32 width = image.width(), height = image.height(), pitch = width * 3; uInt8* buffer = new uInt8[(pitch + 1) * height]; // Fill the buffer with scanline data uInt8* buf_ptr = buffer; for(uInt32 row = 0; row < height; row++) { *buf_ptr++ = 0; // first byte of row is filter type framebuffer.scanline(row, buf_ptr); // get another scanline buf_ptr += pitch; // add pitch } return saveBufferToPNG(out, buffer, width, height, props, framebuffer.effectsInfo()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string PNGLibrary::saveImage(const string& filename, const FrameBuffer& framebuffer, const TIA& tia, const Properties& props) { ofstream out(filename.c_str(), ios_base::binary); if(!out.is_open()) return "ERROR: Couldn't create snapshot file"; uInt32 width = tia.width(), height = tia.height(); uInt8* buffer = new uInt8[(width*3*2 + 1) * height]; // Fill the buffer with pixels from the mediasrc uInt8 r, g, b; uInt8* buf_ptr = buffer; for(uInt32 y = 0; y < height; ++y) { *buf_ptr++ = 0; // first byte of row is filter type for(uInt32 x = 0; x < width; ++x) { uInt32 pixel = framebuffer.tiaPixel(y*width+x); framebuffer.getRGB(pixel, &r, &g, &b); *buf_ptr++ = r; *buf_ptr++ = g; *buf_ptr++ = b; *buf_ptr++ = r; *buf_ptr++ = g; *buf_ptr++ = b; } } return saveBufferToPNG(out, buffer, width << 1, height, props, framebuffer.effectsInfo()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string PNGLibrary::saveBufferToPNG(ofstream& out, uInt8* buffer, uInt32 width, uInt32 height, const Properties& props, const string& effectsInfo) { uInt8* compmem = (uInt8*) NULL; try { // PNG file header uInt8 header[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; out.write((const char*)header, 8); // PNG IHDR uInt8 ihdr[13]; ihdr[0] = width >> 24; // width ihdr[1] = width >> 16; ihdr[2] = width >> 8; ihdr[3] = width & 0xFF; ihdr[4] = height >> 24; // height ihdr[5] = height >> 16; ihdr[6] = height >> 8; ihdr[7] = height & 0xFF; ihdr[8] = 8; // 8 bits per sample (24 bits per pixel) ihdr[9] = 2; // PNG_COLOR_TYPE_RGB ihdr[10] = 0; // PNG_COMPRESSION_TYPE_DEFAULT ihdr[11] = 0; // PNG_FILTER_TYPE_DEFAULT ihdr[12] = 0; // PNG_INTERLACE_NONE writePNGChunk(out, "IHDR", ihdr, 13); // Compress the data with zlib uLongf compmemsize = (uLongf)((height * (width + 1) * 3 * 1.001 + 1) + 12); compmem = new uInt8[compmemsize]; if(compmem == NULL || (compress(compmem, &compmemsize, buffer, height * (width * 3 + 1)) != Z_OK)) throw "ERROR: Couldn't compress PNG"; // Write the compressed framebuffer data writePNGChunk(out, "IDAT", compmem, compmemsize); // Add some info about this snapshot ostringstream text; text << "Stella " << STELLA_VERSION << " (Build " << STELLA_BUILD << ") [" << BSPF_ARCH << "]"; writePNGText(out, "Software", text.str()); writePNGText(out, "ROM Name", props.get(Cartridge_Name)); writePNGText(out, "ROM MD5", props.get(Cartridge_MD5)); writePNGText(out, "TV Effects", effectsInfo); // Finish up writePNGChunk(out, "IEND", 0, 0); // Clean up if(buffer) delete[] buffer; if(compmem) delete[] compmem; out.close(); return "Snapshot saved"; } catch(const char* msg) { if(buffer) delete[] buffer; if(compmem) delete[] compmem; out.close(); return msg; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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) { delete[] ReadInfo.buffer; ReadInfo.buffer = new uInt8[req_buffer_size]; if(ReadInfo.buffer == NULL) return false; ReadInfo.buffer_size = req_buffer_size; } uInt32 req_line_size = w * 3; if(req_line_size > ReadInfo.line_size) { delete[] ReadInfo.line; ReadInfo.line = new uInt32[req_line_size]; if(ReadInfo.line == NULL) return false; ReadInfo.line_size = req_line_size; } uInt32 req_row_size = h; if(req_row_size > ReadInfo.row_size) { delete[] ReadInfo.row_pointers; ReadInfo.row_pointers = new png_bytep[req_row_size]; if(ReadInfo.row_pointers == NULL) return false; ReadInfo.row_size = req_row_size; } ReadInfo.width = w; ReadInfo.height = h; ReadInfo.pitch = w * 3; return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::scaleImagetoSurface(const FrameBuffer& fb, FBSurface& surface) { // Figure out the original zoom level of the snapshot // All snapshots generated by Stella are at most some multiple of 320 // pixels wide // The only complication is when the aspect ratio is changed, the width // can range from 256 (80%) to 320 (100%) // The following calculation will work up to approx. 16x zoom level, // but since Stella only generates snapshots at up to 10x, we should // be fine for a while ... uInt32 izoom = uInt32(ceil(ReadInfo.width/320.0)), szoom = surface.getWidth()/320; uInt32 sw = ReadInfo.width / izoom * szoom, sh = ReadInfo.height / izoom * szoom; sw = BSPF_min(sw, surface.getWidth()); sh = BSPF_min(sh, surface.getHeight()); surface.setWidth(sw); surface.setHeight(sh); // Decompress the image, and scale it correctly uInt32 buf_offset = ReadInfo.pitch * izoom; uInt32 i_offset = 3 * izoom; // We can only scan at most the height of the image to the constraints of // the surface height (some multiple of 256) uInt32 iheight = BSPF_min((uInt32)ReadInfo.height, izoom * 256); // Grab each non-duplicate row of data from the image uInt8* buffer = ReadInfo.buffer; for(uInt32 irow = 0, srow = 0; irow < iheight; irow += izoom, buffer += buf_offset) { // Scale the image data into the temporary line buffer uInt8* i_ptr = buffer; uInt32* l_ptr = ReadInfo.line; for(uInt32 icol = 0; icol < ReadInfo.width; icol += izoom, i_ptr += i_offset) { uInt32 pixel = fb.mapRGB(*i_ptr, *(i_ptr+1), *(i_ptr+2)); uInt32 xstride = szoom; while(xstride--) *l_ptr++ = pixel; } // Then fill the surface with those bytes uInt32 ystride = szoom; while(ystride--) surface.drawPixels(ReadInfo.line, 0, srow++, sw); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::writePNGChunk(ofstream& out, const char* type, uInt8* data, int size) { // Stuff the length/type into the buffer uInt8 temp[8]; temp[0] = size >> 24; temp[1] = size >> 16; temp[2] = size >> 8; temp[3] = size; temp[4] = type[0]; temp[5] = type[1]; temp[6] = type[2]; temp[7] = type[3]; // Write the header out.write((const char*)temp, 8); // Append the actual data uInt32 crc = crc32(0, temp + 4, 4); if(size > 0) { out.write((const char*)data, size); crc = crc32(crc, data, size); } // Write the CRC temp[0] = crc >> 24; temp[1] = crc >> 16; temp[2] = crc >> 8; temp[3] = crc; out.write((const char*)temp, 4); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::writePNGText(ofstream& out, const string& key, const string& text) { int length = key.length() + 1 + text.length() + 1; uInt8* data = new uInt8[length]; strcpy((char*)data, key.c_str()); strcpy((char*)data + key.length() + 1, text.c_str()); writePNGChunk(out, "tEXt", data, length-1); delete[] data; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::png_read_data(png_structp ctx, png_bytep area, png_size_t size) { ifstream* stream = (ifstream *) png_get_io_ptr(ctx); stream->read((char *)area, size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::png_write_data(png_structp ctx, png_bytep area, png_size_t size) { ofstream* stream = (ofstream *) png_get_io_ptr(ctx); stream->write((const char *)area, size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::png_io_flush(png_structp ctx) { ofstream* stream = (ofstream *) png_get_io_ptr(ctx); stream->flush(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::png_user_warn(png_structp ctx, png_const_charp str) { const string& msg = string("PNGLibrary warning: ") + str; throw msg.c_str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::png_user_error(png_structp ctx, png_const_charp str) { const string& msg = string("PNGLibrary error: ") + str; throw msg.c_str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PNGLibrary::ReadInfoType PNGLibrary::ReadInfo = { NULL, NULL, 0, 0, 0, NULL, 0, 0, 0 }; stella-3.9.3/src/common/FrameBufferGL.cxx0000644000175000001440000004051512266336753017633 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FrameBufferGL.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifdef DISPLAY_OPENGL #include #include #include #include #include #include "bspf.hxx" #include "Console.hxx" #include "Font.hxx" #include "OSystem.hxx" #include "Settings.hxx" #include "TIA.hxx" #include "FBSurfaceGL.hxx" #include "FBSurfaceTIA.hxx" #include "FrameBufferGL.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBufferGL::FrameBufferGL(OSystem* osystem) : FrameBuffer(osystem), myFilterType(kNormal), myTiaSurface(NULL), myDirtyFlag(true) { // We need a pixel format for palette value calculations // It's done this way (vs directly accessing a FBSurfaceGL object) // since the structure may be needed before any FBSurface's have // been created // Note: alpha disabled for now, since it's not used SDL_Surface* s = SDL_CreateRGBSurface(SDL_SWSURFACE, 1, 1, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000); myPixelFormat = *(s->format); SDL_FreeSurface(s); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBufferGL::~FrameBufferGL() { // We're taking responsibility for this surface delete myTiaSurface; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferGL::loadLibrary(const string& library) { if(myLibraryLoaded) return true; // Try both the specified library and auto-detection bool libLoaded = (library != "" && SDL_GL_LoadLibrary(library.c_str()) >= 0); bool autoLoaded = false; if(!libLoaded) autoLoaded = (SDL_GL_LoadLibrary(0) >= 0); if(!libLoaded && !autoLoaded) return false; return myLibraryLoaded = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferGL::loadFuncs(GLFunctionality functionality) { #define OGL_INIT(NAME,RET,FUNC,PARAMS) \ p_gl.NAME = (RET(APIENTRY*)PARAMS) SDL_GL_GetProcAddress(#FUNC); if(!p_gl.NAME) return false if(myLibraryLoaded) { // Fill the function pointers for GL functions // If anything fails, we'll know it immediately, and return false switch(functionality) { case kGL_BASIC: OGL_INIT(Clear,void,glClear,(GLbitfield)); OGL_INIT(Enable,void,glEnable,(GLenum)); OGL_INIT(Disable,void,glDisable,(GLenum)); OGL_INIT(PushAttrib,void,glPushAttrib,(GLbitfield)); OGL_INIT(GetString,const GLubyte*,glGetString,(GLenum)); OGL_INIT(Hint,void,glHint,(GLenum, GLenum)); OGL_INIT(ShadeModel,void,glShadeModel,(GLenum)); OGL_INIT(MatrixMode,void,glMatrixMode,(GLenum)); OGL_INIT(Ortho,void,glOrtho,(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble)); OGL_INIT(Viewport,void,glViewport,(GLint, GLint, GLsizei, GLsizei)); OGL_INIT(LoadIdentity,void,glLoadIdentity,(void)); OGL_INIT(Translatef,void,glTranslatef,(GLfloat,GLfloat,GLfloat)); OGL_INIT(EnableClientState,void,glEnableClientState,(GLenum)); OGL_INIT(DisableClientState,void,glDisableClientState,(GLenum)); OGL_INIT(VertexPointer,void,glVertexPointer,(GLint,GLenum,GLsizei,const GLvoid*)); OGL_INIT(TexCoordPointer,void,glTexCoordPointer,(GLint,GLenum,GLsizei,const GLvoid*)); OGL_INIT(DrawArrays,void,glDrawArrays,(GLenum,GLint,GLsizei)); OGL_INIT(ReadPixels,void,glReadPixels,(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid*)); OGL_INIT(PixelStorei,void,glPixelStorei,(GLenum, GLint)); OGL_INIT(TexEnvf,void,glTexEnvf,(GLenum, GLenum, GLfloat)); OGL_INIT(GenTextures,void,glGenTextures,(GLsizei, GLuint*)); OGL_INIT(DeleteTextures,void,glDeleteTextures,(GLsizei, const GLuint*)); OGL_INIT(ActiveTexture,void,glActiveTexture,(GLenum)); OGL_INIT(BindTexture,void,glBindTexture,(GLenum, GLuint)); OGL_INIT(TexImage2D,void,glTexImage2D,(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*)); OGL_INIT(TexSubImage2D,void,glTexSubImage2D,(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*)); OGL_INIT(TexParameteri,void,glTexParameteri,(GLenum, GLenum, GLint)); OGL_INIT(GetError,GLenum,glGetError,(void)); OGL_INIT(Color4f,void,glColor4f,(GLfloat,GLfloat,GLfloat,GLfloat)); OGL_INIT(BlendFunc,void,glBlendFunc,(GLenum,GLenum)); break; // kGL_Full case kGL_VBO: OGL_INIT(GenBuffers,void,glGenBuffers,(GLsizei,GLuint*)); OGL_INIT(BindBuffer,void,glBindBuffer,(GLenum,GLuint)); OGL_INIT(BufferData,void,glBufferData,(GLenum,GLsizei,const void*,GLenum)); OGL_INIT(DeleteBuffers,void,glDeleteBuffers,(GLsizei, const GLuint*)); break; // kGL_VBO } } else return false; return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferGL::initSubsystem(VideoMode& mode) { mySDLFlags |= SDL_OPENGL; // Set up the OpenGL attributes myDepth = SDL_GetVideoInfo()->vfmt->BitsPerPixel; switch(myDepth) { case 15: case 16: myRGB[0] = 5; myRGB[1] = 5; myRGB[2] = 5; myRGB[3] = 0; break; case 24: case 32: myRGB[0] = 8; myRGB[1] = 8; myRGB[2] = 8; myRGB[3] = 0; break; default: // This should never happen return false; break; } // Create the screen if(!setVidMode(mode)) return false; // Now check to see what color components were actually created SDL_GL_GetAttribute( SDL_GL_RED_SIZE, &myRGB[0] ); SDL_GL_GetAttribute( SDL_GL_GREEN_SIZE, &myRGB[1] ); SDL_GL_GetAttribute( SDL_GL_BLUE_SIZE, &myRGB[2] ); SDL_GL_GetAttribute( SDL_GL_ALPHA_SIZE, &myRGB[3] ); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string FrameBufferGL::about() const { ostringstream out; out << "Video rendering: OpenGL mode" << endl << " Vendor: " << p_gl.GetString(GL_VENDOR) << endl << " Renderer: " << p_gl.GetString(GL_RENDERER) << endl << " Version: " << p_gl.GetString(GL_VERSION) << endl << " Color: " << myDepth << " bit, " << myRGB[0] << "-" << myRGB[1] << "-" << myRGB[2] << "-" << myRGB[3] << ", " << "GL_BGRA" << endl << " Extensions: VBO " << (myVBOAvailable ? "enabled" : "disabled") << endl; return out.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferGL::setVidMode(VideoMode& mode) { bool inTIAMode = myOSystem->eventHandler().state() != EventHandler::S_LAUNCHER && myOSystem->eventHandler().state() != EventHandler::S_DEBUGGER; // Grab the initial height before it's updated below // We need it for the creating the TIA surface uInt32 baseHeight = mode.image_h / mode.gfxmode.zoom; // Aspect ratio and fullscreen stretching only applies to the TIA if(inTIAMode) { // Aspect ratio (depends on whether NTSC or PAL is detected) // Not available in 'small' resolutions if(myOSystem->desktopWidth() >= 640) { const string& frate = myOSystem->console().about().InitialFrameRate; int aspect = myOSystem->settings().getInt(frate == "60" ? "gl_aspectn" : "gl_aspectp"); mode.image_w = (uInt16)(float(mode.image_w * aspect) / 100.0); } // Fullscreen mode stretching if(fullScreen() && (mode.image_w < mode.screen_w) && (mode.image_h < mode.screen_h)) { float stretchFactor = 1.0; float scaleX = float(mode.image_w) / mode.screen_w; float scaleY = float(mode.image_h) / mode.screen_h; // Scale to actual or integral factors if(myOSystem->settings().getBool("gl_fsscale")) { // Scale to full (non-integral) available space if(scaleX > scaleY) stretchFactor = float(mode.screen_w) / mode.image_w; else stretchFactor = float(mode.screen_h) / mode.image_h; } else { // Only scale to an integral amount if(scaleX > scaleY) { int bw = mode.image_w / mode.gfxmode.zoom; stretchFactor = float(int(mode.screen_w / bw) * bw) / mode.image_w; } else { int bh = mode.image_h / mode.gfxmode.zoom; stretchFactor = float(int(mode.screen_h / bh) * bh) / mode.image_h; } } mode.image_w = (Uint16) (stretchFactor * mode.image_w); mode.image_h = (Uint16) (stretchFactor * mode.image_h); } } // Now re-calculate the dimensions if(!fullScreen()) mode.screen_w = mode.image_w; mode.image_x = (mode.screen_w - mode.image_w) >> 1; mode.image_y = (mode.screen_h - mode.image_h) >> 1; SDL_GL_SetAttribute( SDL_GL_RED_SIZE, myRGB[0] ); SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, myRGB[1] ); SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, myRGB[2] ); SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, myRGB[3] ); SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // There's no guarantee this is supported on all hardware // We leave it to the user to test and decide int vsync = myOSystem->settings().getBool("gl_vsync") ? 1 : 0; SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, vsync ); // Create screen containing GL context myScreen = SDL_SetVideoMode(mode.screen_w, mode.screen_h, 0, mySDLFlags); if(myScreen == NULL) { cerr << "ERROR: Unable to open SDL window: " << SDL_GetError() << endl; return false; } // Make sure the flags represent the current screen state mySDLFlags = myScreen->flags; // Load OpenGL function pointers if(loadFuncs(kGL_BASIC)) myVBOAvailable = myOSystem->settings().getBool("gl_vbo") && loadFuncs(kGL_VBO); else return false; // Optimization hints p_gl.ShadeModel(GL_FLAT); p_gl.Disable(GL_CULL_FACE); p_gl.Disable(GL_DEPTH_TEST); p_gl.Disable(GL_ALPHA_TEST); p_gl.Disable(GL_LIGHTING); p_gl.Hint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); // Initialize GL display p_gl.Viewport(0, 0, mode.screen_w, mode.screen_h); p_gl.MatrixMode(GL_PROJECTION); p_gl.LoadIdentity(); p_gl.Ortho(0.0, mode.screen_w, mode.screen_h, 0.0, -1.0, 1.0); p_gl.MatrixMode(GL_MODELVIEW); p_gl.LoadIdentity(); p_gl.Translatef(0.375, 0.375, 0.0); // fix scanline mis-draw issues //cerr << "dimensions: " << (fullScreen() ? "(full)" : "") << endl << mode << endl; // The framebuffer only takes responsibility for TIA surfaces // Other surfaces (such as the ones used for dialogs) are allocated // in the Dialog class if(inTIAMode) { // Since we have free hardware stretching, the base TIA surface is created // only once, and its texture coordinates changed when we want to draw a // smaller or larger image if(!myTiaSurface) myTiaSurface = new FBSurfaceTIA(*this); myTiaSurface->updateCoords(baseHeight, mode.image_x, mode.image_y, mode.image_w, mode.image_h); myTiaSurface->enableScanlines(ntscEnabled()); myTiaSurface->setScanIntensity(myOSystem->settings().getInt("tv_scanlines")); myTiaSurface->setTexInterpolation(myOSystem->settings().getBool("gl_inter")); myTiaSurface->setScanInterpolation(myOSystem->settings().getBool("tv_scaninter")); myTiaSurface->setTIA(myOSystem->console().tia()); } // Any previously allocated textures currently in use by various UI items // need to be refreshed as well (only seems to be required for OSX) resetSurfaces(myTiaSurface); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferGL::invalidate() { p_gl.Clear(GL_COLOR_BUFFER_BIT); if(myTiaSurface) myTiaSurface->invalidate(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferGL::drawTIA(bool fullRedraw) { // The TIA surface takes all responsibility for drawing myTiaSurface->update(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferGL::postFrameUpdate() { if(myDirtyFlag) { // Now show all changes made to the texture(s) SDL_GL_SwapBuffers(); myDirtyFlag = false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferGL::enablePhosphor(bool enable, int blend) { if(myTiaSurface) { myUsePhosphor = enable; myPhosphorBlend = blend; myFilterType = FilterType(enable ? myFilterType | 0x01 : myFilterType & 0x10); myRedrawEntireFrame = true; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferGL::enableNTSC(bool enable) { if(myTiaSurface) { myFilterType = FilterType(enable ? myFilterType | 0x10 : myFilterType & 0x01); myTiaSurface->updateCoords(); myTiaSurface->enableScanlines(ntscEnabled()); myTiaSurface->setScanIntensity(myOSystem->settings().getInt("tv_scanlines")); myTiaSurface->setTexInterpolation(myOSystem->settings().getBool("gl_inter")); myTiaSurface->setScanInterpolation(myOSystem->settings().getBool("tv_scaninter")); myRedrawEntireFrame = true; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 FrameBufferGL::enableScanlines(int relative, int absolute) { int intensity = myTiaSurface->myScanlineIntensityI; if(myTiaSurface) { if(relative == 0) intensity = absolute; else intensity += relative; intensity = BSPF_max(0, intensity); intensity = BSPF_min(100, intensity); myTiaSurface->setScanIntensity(intensity); myRedrawEntireFrame = true; } return intensity; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferGL::enableScanlineInterpolation(bool enable) { if(myTiaSurface) { myTiaSurface->setScanInterpolation(enable); myRedrawEntireFrame = true; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferGL::setTIAPalette(const uInt32* palette) { FrameBuffer::setTIAPalette(palette); myTiaSurface->setTIAPalette(palette); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurface* FrameBufferGL::createSurface(int w, int h, bool isBase) const { // Ignore 'isBase' argument; all GL surfaces are separate // Also, this method will only be called for use in external dialogs. // and never used for TIA surfaces return new FBSurfaceGL((FrameBufferGL&)*this, w, h); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferGL::scanline(uInt32 row, uInt8* data) const { // Invert the row, since OpenGL rows start at the bottom // of the framebuffer const GUI::Rect& image = imageRect(); row = image.height() + image.y() - row - 1; p_gl.PixelStorei(GL_PACK_ALIGNMENT, 1); p_gl.ReadPixels(image.x(), row, image.width(), 1, GL_RGB, GL_UNSIGNED_BYTE, data); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string FrameBufferGL::effectsInfo() const { ostringstream buf; switch(myFilterType) { case kNormal: buf << "Disabled, normal mode"; break; case kPhosphor: buf << "Disabled, phosphor mode"; break; case kBlarggNormal: buf << myNTSCFilter.getPreset() << ", scanlines=" << myTiaSurface->myScanlineIntensityI << "/" << (myTiaSurface->myTexFilter[1] == GL_LINEAR ? "inter" : "nointer"); break; case kBlarggPhosphor: buf << myNTSCFilter.getPreset() << ", phosphor, scanlines=" << myTiaSurface->myScanlineIntensityI << "/" << (myTiaSurface->myTexFilter[1] == GL_LINEAR ? "inter" : "nointer"); break; } return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferGL::myLibraryLoaded = false; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferGL::myVBOAvailable = false; #endif // DISPLAY_OPENGL stella-3.9.3/src/common/stella.png0000644000175000001440000000043410651645403016455 0ustar stephenusers‰PNG  IHDR #ꦷbKGDÿÿÿÿÿÿ X÷Ü pHYsHHFÉk>¼IDAThÞí–Ñ€ E£õÿ¿L-Ì! bóž—Ö”+ƒ+ó8;C}å˜'§Îÿœ›ðz +33óóí½¾|þ @6(@vÙ Ù dsÅÂg¿ü´óí/C8À¶½ÞñÑ/6©ODTöÛî8À¨uü»CíÈxy^›#tà€÷¯ÿG;nÕo›9Ú"8 ¶ÐgªKOXÛã½3 ð޾óÖó½ŽÝÞÁ;ZÈ)žˆÎ€¨^©¿½{sGyr¨¨GëIEND®B`‚stella-3.9.3/src/common/ZipHandler.hxx0000644000175000001440000002366212266336753017275 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ZipHandler.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef ZIP_HANDLER_HXX #define ZIP_HANDLER_HXX #include #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(); virtual ~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(uInt8*& 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(void); /* ----- 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) { return (buf[1] << 8) | buf[0]; } 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]; }; #endif /* ZIP_HANDLER_HXX */ stella-3.9.3/src/common/FBSurfaceTIA.hxx0000644000175000001440000000527212266336753017370 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FBSurfaceTIA.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef FB_SURFACE_TIA_HXX #define FB_SURFACE_TIA_HXX #ifdef DISPLAY_OPENGL #include "bspf.hxx" #include "FrameBuffer.hxx" #include "FrameBufferGL.hxx" /** A surface suitable for OpenGL rendering mode, but specifically for rendering from a TIA source. It doesn't implement most of the drawing primitives, since it's concerned with TIA images only. This class extends FrameBuffer::FBSurface. @author Stephen Anthony */ class FBSurfaceTIA : public FBSurface { friend class FrameBufferGL; public: FBSurfaceTIA(FrameBufferGL& buffer); virtual ~FBSurfaceTIA(); // TIA surfaces don't implement most of the drawing primitives, // only the methods absolutely necessary for dealing with drawing // a TIA image void getPos(uInt32& x, uInt32& y) const; uInt32 getWidth() const { return myImageW; } uInt32 getHeight() const { return myImageH; } void translateCoords(Int32& x, Int32& y) const; void update(); void invalidate(); void free(); void reload(); private: void setTIA(const TIA& tia) { myTIA = &tia; } void setTIAPalette(const uInt32* palette); void enableScanlines(bool enable) { myScanlinesEnabled = enable; } void setScanIntensity(uInt32 intensity); void setTexInterpolation(bool enable); void setScanInterpolation(bool enable); void updateCoords(uInt32 baseH, uInt32 imgX, uInt32 imgY, uInt32 imgW, uInt32 imgH); void updateCoords(); private: FrameBufferGL& myFB; const FrameBufferGL::GLpointers& myGL; const TIA* myTIA; SDL_Surface* myTexture; uInt32 myPitch; GLuint myTexID[2], myVBOID; GLsizei myTexWidth; GLsizei myTexHeight; GLuint myBaseW, myBaseH; GLuint myImageX, myImageY, myImageW, myImageH; GLfloat myTexCoordW, myTexCoordH; GLfloat myCoord[32]; GLint myTexFilter[2]; bool myScanlinesEnabled; GLuint myScanlineIntensityI; GLfloat myScanlineIntensityF; }; #endif // DISPLAY_OPENGL #endif stella-3.9.3/src/common/stella-128x128.png0000644000175000001440000004410211676222762017417 0ustar stephenusers‰PNG  IHDR€€Ã>aËîiCCPICC Profilex…TÏkAþ6n©Ð"Zk²x"IY«hEÔ6ýbk Û¶Ed3IÖn6ëî&µ¥ˆäâÑ*ÞEí¡ÿ€zðd/J…ZE(Þ«(b¡-ñÍnL¶¥êÀÎ~óÞ7ï}ovß rÒ4õ€ä ÇR¢il|BjüˆŽ¢ A4%UÛìN$Aƒsù{çØz[VÃ{ûw²w­šÒ¶š„ý@àGšÙ*°ïq Yˆ<ß¡)ÇtßãØòì9NyxÁµ+=ÄY"|@5-ÎM¸SÍ%Ó@ƒH8”õqR>œ×‹”×infÆÈ½O¦»Ìî«b¡œNö½ô~N³Þ>Â! ­?F¸žõŒÕ?âaá¤æÄ†=5ôø`·©ø5Â_M'¢TqÙ. ñ˜®ýVòJ‚p8Êda€sZHO×Lnøº‡}&ׯâwVQáygÞÔÝïEÚ¯0  š HPEa˜°P@†<14²r?#«“{2u$j»tbD±A{6Ü=·Q¤Ý<þ("q”Cµ’üAþ*¯ÉOåyùË\°ØV÷”­›šºòà;Å噹×ÓÈãsM^|•Ôv“WG–¬yz¼šì?ìW—1æ‚5Äs°ûñ-_•Ì—)ŒÅãUóêK„uZ17ߟl;=â.Ï.µÖs­‰‹7V›—gýjHû“æUùO^õñügÍÄcâ)1&vŠç!‰—Å.ñ’ØK« â`mÇ•†)Òm‘ú$Õ``š¼õ/]?[x½F õQ”ÌÒT‰÷Â*d4¹oúÛÇüä÷ŠçŸ(/làÈ™ºmSqï¡e¥ns®¿Ñ}ð¶nk£~8üX<«­R5Ÿ ¼v‡zè)˜Ó––Í9R‡,Ÿ“ºéÊbRÌPÛCRR×%×eK³™UbévØ™Ón¡9B÷ħJe“ú¯ñ°ý°Rùù¬RÙ~NÖ—úoÀ¼ýEÀx‹‰ IDATxí½W›Ü×™àw*‡Î $ÀL0j´£•Fi¤‘(QCޤÙÙ‹ ^ûÊi¿Å^øÂ7{aû±ŸÇ¾ð>ïìH È:Ǫîê ûû½U§ÙÄ€$Càô?øæóžP)„œ@àÛ Â··ëO¼çÂò~xxgüʆûü•mèW´a¯D,¢÷E¢AÄ÷ˆýÑ=—#É„á·ü=¿Ë8É×ü>_-牅\É+ð[TˆñQlŽ®¾Y"VÈ‘ÛÂÜïù}wtŸ‰Áï–q“Ë9ä]‡hú'F 6ö$<:Dް#ΦBñÅf½üz£Zœïõû¥öA¯}Ð鯧¾€Ë±Ê³ˆ¡ƒ×6qIs$-”"Ç%‰7ÝqgtÍéyürá„~"HΟI…ò÷~peò~ÿÖwÎN êÝj5­—&ÿï8Øü/ÿ¸}m¼^h¿r693Ý/ …­V¹{g½¿µÚ*ìlw[{isc»{‡²6*•ÒØT}p¶Vî7¡°B¯PLk;ƒÕÎaÿ÷|¿I¼7Š[\% ¥Ã— 'ðèà“‹áè4I¼tv®þw¿y³õW?{a?Õáñò…éÔŸ®]9}w|ãÅþ…©ñAZ˜ì§. ¸÷;½Ôu‡ã)-œIßhwÿóÿ¹º½³—öÞ¸8h¾q¾;9UO¥J½js3…ÿíËíÿøŸVÿag¯û¿Rß?•>Y-¨TNàÑ@'ð+D°—N7ÍwÞy}ð×ožÝOhôÃÆxš›O{°u©µ•žé¥J¢K®¼§ðG ×'Kéìss”2– »ëå©·fÇëiöô,bÙbºÆ©fš¿t*ÍÎî5ÿŸÿRþóÿýÿïª6² ÷³ýÀíã…x4¸)ú5öýöÖsÍ¿ûÉK›3u°Q«¤òÔ|ÚlõÒÎÒJêsíÝC/ȧ}ÐU¢„ÆüdêׯÓÒå´rk#Mðî$Uñ;h÷âx95§ÒÖ~!mÜ]OÏNôJJéöaï%mâ.W BBxl) 8; aªÓñÙùéú»?~nïùg¦º©X/Á±gR¿<–Vî,§ýõ½TGN” €HÈùDCc¶žÆæÒîv+­Þ\…ƒÔ”¤ ’}x¼W,Ä÷Js*ݽ½–~ÿÁNªö{éÒ\‘Qx•”ˆgˆ3Dí‰ò±Ã <èäá,úÏŒ½ûë7 ?ýÑåvq 4Oͦ酅Tlï¦ÞÚfª¡$€íþàþj!5æfR§_„PVRgç0M‘¿F<$O>®b4f!ÔÈõ?¬¦›‹J‘~ºrº_\˜¬¼L;^$J§‰£öÈcãñ±3Ré·)Èeùf ¥ê÷þòÕæïþöõ½©8·ˆònÌ/ Û÷Sgu%Õ»ýÔTN@2ý׋|ïk`»P›H+÷¶ÓÖònjRê$e”@|U1¨S²Àwºum9]»ÚM›üßg‡é­óÅ™Z¥ô]JŽx–¸@ÔQ•K¤Nà‹A&òE)VáùK§ïÿâÅgÎbÙ',õêüLJi}é^jo´REÎ'*ò ÄõÃÝ•±RªÏÍ¥Ö ­,n¥º~J½Oڞȧ–±S3©11“Vïn¦>ÜIwð$ìóMÌ2„L—¦Óó§ªÏòô¯îW…ËÇÊDåß– ìå.¹ììääø»ï¼Úû‹×NiwÁýSMŒµ™´›nÝÝ„Wt÷À±1PãªÕ_FHO™N¥úDÚXÙLÍvç’B‹_ñ_¯¤qä uî\]OKKƒ´‘à HE¢eV½ôÒB¿<Þ(]¡†ˆÇ¥¤ôèRà„€Úç¹_ ƒ«üöÛ—¿þÁåvSä9^«Ï-„hß^YOƒÆú¼Ç† dõŽ]+3T™™KÛ~»«©F©ãT /Õ iIR(–ÒÝ[ËéÆõý´¯qÔé¨Rb9Uï¦K³eEÿ+ÄsDígžûŒ lýZ—æf¿ø—Ïì>snª—ŠBjžžOÕæxÚ\^OíõÝÄ@ áŽÇ@¾:¿×ÖóO’¶ 7ßÃêïìtÓÖD™´Eju²†o`*í¬o§ën¦Û÷ðÈý”#A倠ÀÚë¥æʼnFåy/•§ˆ¶“RÍ ÁKs‡ —øþñ<1«¥–U£Fæ}RíÜEô;7ÐċԜÅðÛÚJ‹×6¦DŠ6â¸áÇãƒu&¼ºÐ-\^¨¾L¢·‰ˆª‚i¢c•Vý—æšïþä…½ÎOvƒ«ÈïR±š6ﮥÃõvLïVqŸ\êl¢Ç¯Âaú nûRß&†b7Dÿ¸DqhV§˜ìÁ6h·»éöÇkéÖþû)£4R#$ Ž—"yR&Ä?÷k½UTÁ‹óƒZ½ZRÓAp"]„{=ò³WcJ9Ýì¦gç*rþ«DGY HÐVý™ás?~f®oÞ  ‡Ï[o\jüêÇ/´&æTÁÑ5Œ¹¦þîÖ.zœþUœË¥º{aÂ0ÌêS¥4NÚ½ƒnZYÚHƒýAbn'••Ø ®c 467•ö¶wÓ­«Û‰Éô‹ŠO8²Lƒ¬›‘ãUdçgY:‚é+Å^zùÔ <^/© .5ÊÈe’þ[„ú>MÏÌãðùþ¥Ý‹gý@º6;‘&¦¦ÒáîNêl·S•ÔNóDQ.tÅßÔ©‰T´Âz€ÍÔXÔÝ«”PôWàþñ¹q@¬XO‹w‰"£¬˜5¤¬<ˆÏ?.øü©Ÿœ;L—çË ¾p…DJ ÀUKö-'åöÓáÛNF˜Ëë õFó¯~þZá§?¼Ü*6@ha]Íôm÷à í2AS‚£óKr^ÀëÐ9ŠåéJªLM`øí¤õ;LáÁñ.Ó¬tM€y*àó™ïW?ÚO+ˆ~‰G½¯Ï߆d¯Õos„ñAA$–Põj±X(žáQÏ ë$j[a’†ÏüðÀÔß¼—Â[««¹ôÆkÏ4~ó³[Óóà©ÌLßô9&p*å´¶´žö7c¹V pj|‰œ>X2VÆ‹©Êa{/¥Åë[i5Bq C>Ã*Ü_C’lîôÓkítѯ{Ø ÷‹‘‘î½1·2Aøà½#‡[rZÜ m %׫ҼZÄñl<~¾Í`ß>t|ýÍ÷Ðû/g…^Y¦yñÐM¤½Í´·²—ŠÈb‡|Š[ÁéDÍ!ˆ-RÂìÙñT©×YÁ³‘Öï„á7Y‰u?î€4sv’k=-ÝÙH×®°Ú7ɺ1æC"?@¶¨"8?cð~) ôèÓ [•toëÚÒ¢V…Áä÷g‰ùÏ·•„§¢Qy¦Ùlþò—o¤Ÿÿåsí’¢?MUR‰qüææAZeÍÞ =HuÏfN/è«›+§±™ñt°»—vðõ»®oÍëÄâ]×me†ÉHm¬½¥»é.c~§z%$h±6HL‰ŠBùÞˆE2é2Þ†û¯®°3z+$]"âRJ»D,ŒX8j ßVP,*úç ÅÊ¿üá+Íß½¥5…ëž9{ÈP®Ï4Ý*ܺ¿Ùo_ê0MLiù+Ú+ÅCû-Ò.톚$‹„"îÞ".á:S½Îü­ÜÜJËw©Êé"_Äz/†,š bàWßeÂðš Åkο¸UJ«;ÖÜe‘Œx«b#‰¤ö@úáýg~ü†a ŠÔû…Ÿ9ÝüíÏ^ܽ|v²â½9SMxm:››Ló¶S H×H–< ö*÷‹´Êl^c!èr‹iáNŒôøé8к‡ÌÆð 0w°‚yõÚ~Zs²‡¼Ž$,[DæpüÞw>9W‘_†ZVÛ•ô!|ßíöDú=â&QI`Ä•Ã'@„'|¢ÿ,‹;õ³Wû?¸rf?[š,¦ fç\„¹³ÒJ-yIE¶ùr>ØcÙk‹©Œ+w‹‘Á†iáöp÷"Ïå|Ü©„ǯ1;‰ ÑÿñvZÂðÛ ûBšPìýH'kH.Á¶b]ç ýx~¿RNw7;rù ¢HGÁ¤»D%€ªÀ"?3È ß– ¬ÕðzûôÕ¾õÚÅú;߿Ԯ»Â§¢§ÏŒ§r£ž6WwÙÜÑKU¹ä‹te¥Öº÷® ˜žk2˘Ÿžº{§ÇPÚÝŠv¸¿±ÓSp;óü·˜ç_ì'V‹ÝÆ$±9r!³©Hñ› öjõùÙw"|¼÷ß=dv¸›×·ˆkD¥¤–5îK<¢'nÿy°®oC¸ÑÑÐû€öÊüÌØû?¸ÔzæÜD7Æàã µ0æÇoÜÛccÞPÇ‹…@”@§oN.TÒÔôD:Ød?¸1J–3u÷šgb¶‘šLÿIL×ö¹À³…D DR–BÅ`Ã2r}!ùÏÇC¤ã£°yPN¿¿[`rª+§_%Êý"ÿQBøBî'Í·Æ®ò'Î?;ù?ýö»ƒŸþè…;nè„¢"u:VìâñƒS«¼Ï 2Elä9žo &&ÏL2ÏßÃ?°“º{ƒäDO¸†!‡‰®ž^`ª—µ«”· jö@‡Æ£wxhƒDò(ÙaH,…Q݈ûñõrZÞ Ñ×"^X$*þµ¾ûIó™íðÛ7%kõ>ƒ³ôÌÔäØoóÝÁ_ÿúõÝLŠèÇász<ÁøÚ½´»ÖÇ· þa`C‹ßuûHüäP¡X,‡èßܪ ´F ÞQxGì¹ñ“=Û #W–Ó2‡„Î ˆ@ƒÉDhæþãϾË!#ÞgíUÒJ«’>^îéôYâµâ_½/çKÞCŸ¯ûùaÔœüø» ?x9Œ¾Sµzãï¼Y|ïÝ×v*³u–wñµÁ8¾1YOÛ(èµ%˜D;ƒçf @®×øs­¿¢¿É´ðæÚnZ½·Ôð1‰.ß.«C»,ñÚfhxçöÎÑ<¿U¢ÈÍ"X½~¹ùÞkN㽄A±DþA¯ˆÕ_J[{‡Žóo³Þ—”ê~Hñóu?ß#|“ @ø‰ü¡ÑÇfÎ?±ñÛ¿}£53?6@„ƒh$À$>üòyùö.Æ¢‚r©€7(Òõq–ncøµÓÝ»íÔF¤ëî1?ß•bnœQÄ8º›õÿwoãÒCyÎ!ˆqe4HǃÏùÛñ÷¾ î§œ{»¥t}Õ½C®¸ÏÜï½CA½€Ò×CÝ723ûjñ^¾xjìïùjë•óÓÌò‰,RL0”°_yu?í®E¸{ùæx?8Bqß8S½}þݹÓJë¨ U„ûÃ>P÷+âñ α|€Ùf£È:šØ!£ GDnÔKºã+~Ž#ÝF‹9ß—ÞK”{Ýbúh­ˆ1©•â^P®W<’è'}ŠýÆ…û‘ÿ:FßÿðÞ[ÝŸ¼}aŸÙ²!Rœ©s&oån'­Ý퇯_w¯!¯ðQ ˜¦9Å>€é®áC6u²8¢˜Åê×VpCg ;`†É£qÒío­3¼ŸXð ^)¦ÎaO ÿQî—”Š~•ä‘Â7‰„WF>c°ÂËS“ãÿþ½·Ó¯ß{s·:7¢Õœ@ZãÎU8ËðÏW·rëV=Žìü›.²Î¯ž6PÛkݰÜÖÕ'½‹Aôè ªÂùUö ì±õkm©“¶°œr8Y“XHotu±â¼Ì·Ï¾1H&êPÑÇ û–6%©ý"^û½Çz ÃO:z¤ À¾ á>ä§&Æ›ÿë·ï½ÿæncsztÏÊýBÕã\6A|6äÜ©#ä2ôÓnÙgà81WM{í^ºÇpΩݹi$†$å)6X09–z­½´µ¸‘Xè›Ø7„!ë#­Þ:$‰ñx°„6F[xáæ‘Õrú G»êùÛD9^ä•rÿ}%òæ!‚u~ÝCF>|ߕ驉ÿÎÿW¿}}¯y ‹_d)ÎÙîÄÕ%ë¾{-k ¹ÆeìsU¬k NÌU¿¥t«s1?ÈhB,–%–b^€2júü›•X ´t¯›¶ô÷SŽ:?ŠåήüU£ºñ£´1ºånĤù$”}†}ÿš·Z‡~ùêü%¢Üï„fmTÅõ‘Â×]Oû‘ÿêôäøxÿ;…÷Þ½U_ù"Š"C®Ã7Û¯*<Çéps6ʼ¡øÉ9vÿr‚Ãêj‡EÝ Í Ê¡,Ë‘hLëÎÞÙ…ñX%|{k8Ûçž~C&7Š* LJÈ·p2‘ßàÒò,D>1³èÍÍrºµ®< Î_䪸C”ò°Ïï$¾¯k°í /œ<ó€ äýû_¿Õÿ›÷ߨ©+ö뎂ͷá˜a‰_LܸjÇ R ^$‚1Æüӳ崿ßc"OùÜÓ7 ™9*yâÎ| æû§§ë©xÈ’ñ5,t¿ê&ô¼H•É%¦€Uñ«;„% Ë4XÑDX›¥I¯†á§sç1û$¥€ºÿ±¹Ÿ¼Á=^¿NAÉÈÏœÿÊÜÌÄ¿ù›7{ï¿÷Æ:ÄÝ%bU3²é&Óu{îÈšE—Ë‘ùrp8çLßÔ´UôY·‡îÇPÔ…;(5Bw“'z’ªÌàÒ {6X“çÐOãÐ<Š}"ÈVrİðCN(ÆòbSJ¥ÂÝJº»†Ÿ¯¸wØç½j@ÝÿPþ~Ò}f°Þ¯S,Á,u®˜h¬~-”¿sz¶ñ»÷ÞêÿâW¯íÕYuÍ Àùršlµ ˜W‡¢_ÎÒýØÖ¥ñròµŽMPfØ*:ÿ&S¸êÈ>Ž0üD¾ã~‹ I ×009jk¥Ä¥Àaª ¾g­,âÉCumŽà~ˆÐ‘„ ,WIºŸaßÕ5fû:=¹>s6ü$dÍ‘—˜ÛÇ _'ùðgÌêÁ¿é|¥Zÿë+ëÿú—Wö_ûóg÷‹3EœË@]²­Å€g×- TI8_%|ð¬M*18\›œ*b4Ò–néÉs¶pÝÜ,¢(SäKXŠó:“IÝö!ÇÄ@, $¼}|— "-éEªñŽkHÞÇr`Ýá¡÷–«¡ºî_Ú Fqù~ÊéƒRz¼aù>¾¨† '\»"ÿb³Ùx÷§¯UþÝû¯ïž½<Ç}©°”K5¾b  â‘Mט.Á¾xš}_X Ù‘1©ÒB¤L!S éî¬(þ±!$í#…£²E¦ÄƒôµÐaUG½ÆN~‹¤5\-§{oeÁý\-Ïm`¡¸Æ=ïTëÌõ°ܯ‘—=žñK~”q¾ê ü2×Çnz,]™šl¼ó‹×Ò»¿û³ù³{r¯Þ8¹Ôà”¬c}ré“]X‰£ü8ØÇðs˜§(!^ísAÇ8Æ_ dÞâ€&×î9Þw_Ÿ¼8*?ˆìnù€»‡…´‡@]¯‡Qn¹ 1“b-Ã*µ ">œC¾$î^UA—,ãôÙü7ùªîW(þ½§7_Îð#ÿQøª€`R¢±¸þR­Vÿù«*¿þ˺/ýÅsû•S ŸmxÁ]±^Ä~Ú‘Ö’7A¾;¹'@îHgCÎt1¨¢™28Láï@‹K=¡nò•`¢l›E“úsrm`ê·MzË ½>*[ï¢éÍogÌq”NBÑÍkˆó¬ÓçêZÀoZÿ)Ý/÷CÒ1Û'Ù<‘ðU#á`´]€> ½Ózߪ¿ûÓW?ùÕk­©‹Ó½Ð¿YßkÍ÷A‚Ö>û8Òõå¬÷ é2Fßé©AØæ †X»GmÓˆþ&´ãÅM7n‡‹J„yÄ?Þݰ+äúlÌY€ÈÓ ,ã òçX 6,6Ê;磱¿y¨K">£v4ÕFÓÿK¼·ÛŒ)‡Èר“ëŸ ÷[÷W…„ ˆöÈõ"ð§óÇò‹×ž©üýO_ì<‡¡WpÇ®¬H– \^mfU€Ö~è|¸þ: ÛŒOÁýDçí¾¢YñËmèaWóŒ³$LâYZF÷#l¾ý麚´Q‰WHTü³k,ž£-Ô/Q˜Î<¶+pVÄ»¨—[u| ý¸7(I$ þ³³§È¸ŸÉ¾~O‘ ùû3÷ÓÃè6—'þÔ`¿Â4ĽˆW×ÏÃõWf§¿üñËé¯~}eo^®7±ÆœzÔñ:8DîÃRë¸DXƒ‘8j']cøäó,žÀÎ Ò9ô¿@ÖC'x/’Ôדˆ~[p—YÁëˆ~Öy†t™¦%5 £}aÃè2$³Ñ‘©òj{äø0Fy •rÏÿ¡*àFãщ";$¡Hª«kÚëüÿŠû¬û•È™/?죌O…?ÐÝ@ºð:Žøqž@ü+cµ¾r®øƒ¿Ð}á_\Ü/:“'"²¾×ØSÄ CWÚ.c°ÉùläI7nÅ ß çRz‰¨®vÊ7I^E¿ÀwÍ¿ÓÀÛ;ƒt“aŸ¾‚}TÈF :~bèg%Ãäq=FT "^ ÈäÙ`o£W8¼òA{@Š·ó¡ ¸*ÖZÌõÓö~ߟš9²öÿþ'Îý”ùGSê³ïé€?Dý×9ÿòäXíû/ž-ýàÏu/÷ü^éÌ”ÛÉ 9€È}ˆKJ‘›wyÏA]i09ÖçðŽ †ÔqùBJ¯]¦`ÈÊI-rfÐU+âÇhA‹}7áü›Ü GÄèòU¿‹¬ãÜ?ÊÎÆžF§#¥’¼,–œî5’GÍCòöCºQè¸ÊtïêÖ!äëüèMŒûUûä~“?ñð4$€ÝÍ1ƒÄz2âÜb‘^º\*W^ž›(½òò™ÂÛ߹ػðÖ…véìD8®Zr—:_à…±G‰œCºÒœÏ~vÆÒÊC7@%7=׿v =ŽèwWov Û*jãhx݆¿®Ý…ÍÈ«ÑÓ?<ÔAñmZUÅKs›ƒe²=b‘jÍã"ÑœWU¡Ä2OHï‰5ê—\ì¡äê÷{r?­ ¤‹|%ÀSã~Ê~l `_hú¢}ÎïD¶ŒäÕÈh:" W¿ÎJ•79ßîÊŹÒ/Ÿ\ü³‹ÆË ‡i’•ºÁ M½Ã52i´‰,¿ù^N×¹Ãï)¤U`¾Yß.°Is€µÏ¡yç! ?<ºÉ¥ÚŠi[—"‚Ç Á=ò±õ?ÆüNÜÕ@ËcQÈðõ§þ†$±‡”ošè<쨻ƒ],â1nŸAÖ ßWÛ ²IA0ÜÜÃò_Þòmˆ~È:Œ? @O‡û)÷‘ #9#Õ«H½—ÓqD©ãøÒùB©ô|­Zºpn¦üâåùÁ«¯œîM½y®•Îpö®çìäEµ\l°2'7 0S¹ ç/‚´ÅÕBº ×kìí’± ×ûpÿ ]y9c9™ã,Ïg i2”»W $ €£BÅX‹CbyéƒpÌHClËýÁ6QùATr·õ˜G{Ã4Ög[|)!ÛûÖehq£”öº"y˺•F¹>ÒÜ>Ù Â6ØÓ‹ãp‡ IDAT\@+0ÂŽw~ñE¬÷Òº<^©T@à9Ù,Ž]œ+¾‚ӿ܅éAã­ û…‹3ÝTGIÊÀ!†p™ÛG0 DÛ&‘*ÜB8Þ@(®ð[:›íB,»ÚcfìÁ'Ö¾zÿFœY™Í Âávˆ(êkBŽ5ˆcÐÞ¤Yë•^?Ï÷§X0^‡5}÷¯®â– &QØ”åᦋŒfÝï>ùë§@"yœ[0¿}±žÀÁ]¼  <‹t œÅ=¢Í¼3ýÍõ’(Ä¿Ü/ò%‰’ºÜOù­lº|1Mw^ºxªþþúÕÂûsÍîdPìÒùîÜø rfªÃ^»áÄŒÈ.1%'ÂÍ,'ˆP¹Rd<ƒ—à ‰x,fýÌÆÛôñ"ñ–s(˵F\ïÚü@,ùžEç+úµú}—'{¬Çº•&þB‡HñžÉ¯ˆÖp“X”Hžëã¼ä#y¼Š0jö>x©¯Àa¦Ò#ŒMÞÙGJ&O‰FÔkð›DbúÝN!]…:‡"ò¤Kî§ž‡"šöÍ$×󳓵ßýÛï þîGϵBÊ.Ó7¥YLhD?ö³Cn“Ó}"ý“OÜ}Âí:Dºçä¯@ûœ¡óá79JMëÞ ¹ÓßÕó ë OïÏB–¯_JéܯëVn“ˆ ܶp´ªÁ™Nò(ú:²†ó!  0¯vhe>ŒþúNbvhj}î&R ÈíæS"IhÙÏï½RAµátqH Ò´‹±>‘”X"Áõ‚ÜïU³T9òT`ÿÂ`Eÿ\±TþáÏ®ßÿþåvC`1 ”ã4|8>7ƽÎl‰LŹõ^ ÈÀô]p ïb¸Å³S·«tÛmÔWW0ŒÉòN!6V)Ü…ÎÍ’0=õh0ò[ éå ü|ÆE8œ4XoÈmpž_߾ģÙ8å=Cî·þ´ÁášFÛ-Ùìã!žGm·ÏN¹¨TpqH”¦sï¯ØyÄÒêu !¡æø¾Ý)ñ;á–’ë5E¼÷*&sÞß^=ÙðE xýSÄ^<[yÿg¯œ×€súS@Ç®Û`‚kl2”#¼5*ª#FQ!”ZÌêsÇô˜nÕêf;{xÿ`cÛNÖ8äêÁª1*Ѫ}ýWžcºWù cA¥Y¦¸8é[äÞEêÒ®pRH1,!“\)dÛ$œ,A†ØöÃ" æQÄ10cùšÄX‰D¿ÛwX¤NÖŒ&$}âlÈ!çóMUc;o³àswß/x @ѯîw2hDÆÜ=Å@³?3ÐÔ#Ñf¬Qûùϯ ¾{Ÿ¼îWulx ‘“9_ç ¯80ÀÔïê[ ghÙ;k÷Ñ"Ã1t²“7a#°5·†Ã\"r\ždä¼!rȯŽåG¶Òë—‡úßݼr¤GÝ£æÉyrµC½[#øÙ©D²£ QJ¹_ñÁ£Ëðž‰]ß¶ƒ{ÿ웎žÒ‰oŠû0ö€0fQHšHJ±m¬ÿ%&º‡=.âåzï%{BÉO?|Ø_À»ùR©ò£Ÿ\)¿÷ýË­¦Ü¡xÙ\"(þåˆ |&•ký:c& Dº*‚ÓÔ »ƒãÆsrï¬pÆ©xt-Ç©Žq>/¿¥0Ô³+qbQqfÔá`@¿ta(úM«»8Œ=ʈ›¶‘÷þ*§íÜÀ¨tŽ ‘¹æ_CoT\Ôãb Û+b•0êV^Ø£÷ö9{)µ-T3Uêן€‡}àYi"˜ÇïÂÃ*Zq˜À@±yâ½Êý°GTÍå醀ý¦¹±ön¶P(ý‹¼Rûw¿y«ýÌ$ 6 ñH*‘fÂØKO§ä 8K׈vR·­Ü·+Þ°Ñ¢ßØc ~x]¦ŠPÏØ)øøÕlò•ÁBq$õªNxà =òìYݽü2÷ߨC€`MHÝ"K½¯qQˆs® ’€æ©ï žôvÏAÜ”•7vãxðûÐW À#ßœ;$ *õ;Ü;à>ìáÀ3ÿY<2"ô(Øeë’Ã@@)!þ¨ÜOؼ¬÷Ÿ{îLõ_ÿýÛo^Fôkô²~ ñJÏDzP¼é¸ 1Xá¸à:½m_ü¸VÚVlˆ2ÐðÈõ‰i¹Ç¥Õ~{·ÄU€Ã9¹' V%m8S(: ,<‡¾õÙAâǵCL)]H&Ðï1ÓG/ö©ïõëëWô+â£ý‘Áóì=ù´ ‚¨ZI bÁ~q0| "Ø9´áW‰×mdñcOÔçPRPÅ™¤ ÕBYæQ({ :=eB$UäKÃMüS× @©ïàV«¾ûÞÛý½xšîÐhu—F™Ü£˜XÆ]9¦ËaÎÐm¢Í–°æW1¸œ_w¡F;…Êíq‚ Ö³†“ebïA7„?Ÿ1~3J] Çæ¬XøxßD ]\H|G®ÄÉ{8~(K$ëÎUZhg¸8Z;Á>e‘®tè@eJ1- TuaÉf˜6cÆï>ëãð'ß§•f°Í6'A˜‘^ Þ¶©ņ ò,Âý{udñ‡Ð°Zb®†Û§>‹àÏÁ¹¥îüÿõûršn²3Ä(ÒŒr‰Ö‡îÐ'G{ ¡&…ãf‰5€0ò,8ìBAÎàÀ‹è®";ÖêMÅ㓺€Ñ7ÀHbŽNC °½g’¡à‹çÐÿóüNéDZ I¨Š,®êbݽ–'h`º['Œ.†@ºõ'T‚á½RJŒÈõ–j€[E¸±šQUqc^™a‹:<.ÆI¦:ROC7K ÕHΫ=r$hYù$)FµV-ò´p?X±}ôýÖ­ÕÎGÿËNå»—çjÅùê” D«]A+W`™“Úq¶³hŠ÷bP_|{½_Ò˜G·¨\`>EÖê÷dÎL$‚Z„HpxÒÛYÕË>º¨‰[µïi¯é$£åäàwûî+%¡[Î<$Ú-gî&’˜‚HGuD>S·yº È"ìI&€cµD®§úçA@·ƒ!5§ÿcïà°¼¸]|ãÂ3•ò<¿X)z´]N•Ó˜$ŒgÞI"&t%Y˜sä":òòìUb0¯N"Y@hvU PKAe ô*xQЍË8…+ꥋÌ÷dA&€…”ˆ‘S…ªãqËtë7ÛôáԂµÍ7‰Ãâ}§ª°p}û ñ³‹¶Ç1½eÖe¹ÖÁÿxÇ%‚õ«64ziœ™A%`)L¨„Pº4­_âVµqoñF{pœ|÷G ÷€Û^ø'æ¦?âZßÜë4?Ú¨½|áT5]œEh¹CØ@9¨"wÞ‡ÁÐ1!zˆÖ¤)3@E„?ÇÜ ߆ªõo’ .î|àŠ³,úMÃçˆr£>Ûįµ%Nr;2>3ˆP!í0Ïë‘'Ž=dCˆj-vøðì¸^¤k'Ø/m𪊰^_Y¯ýU ì@³³Ø'DN BÌH¨*³Q±¯xV:ŽBîÆÑ‹üái_D€!G2³A£âŒo"8[ýÖåR¨Ü/€·ÅÎ)8"‰ŸO õÚ›ê}Ffä|¢/¦ƒ"“_†È`û`¢ášÛnY–êÅsô=¸ t›¸$%XRF)aŸ-KøØ×á—?a÷‡Ü7±l+}ö¾½¹×›ZÞ-OO— ÓÌ¿KÐ~4QÜŒ.v0ÆÐô6¤€Ï|Ë€ÏÉ…i¼ç~xZcš"…èÂI4?Y`¢g.Àýb*ìfn¤A¤Ë­züœìqª×™> Á–?i2à}'qú,‡[¿«ŠÖ™™ÛGOik¸ d]!¾K(·u™çx?,Çh°~™ÚÑ€RÍãaõPš@»BÕ'Çé?ÙÄü7‹½Ö~÷&¯‰Ë£¨ò0×%І` ¾ˆx£pR0·9sâÎvi¦Àˆv¹>†§&,]:é˜Znó’€k––’%eE¡ÁX¦1òNŠ|îñù3¬íÇá£NùÑt‰Ë|q¤;W'‘bD 1'Q’£Ìa{"?im‡Q¯“j‹FÎOhÜŸsÞ›¼£ïöCä{=êßr‚àÙ²U_ª" Ri¥AhRGH#ŒZÛÿw£8Ønõ”´·‰÷ˆnL ” OO9H 43¨Þˆ`F]tïmtþó^ù¥Õêžï¥³œgç‰À3îcÖŽ43°å*aá³Ô'u™GÀ$ÓX?¿›ÎÁùÉfY ›.#E` xÏãÕãçÌ¢ºÜÆf˜‚HUðGâÊg™*îqð3š$ÆõÚcB‡²¬+ìÒdàË'„νýQÚˆtÜs…§1\%RûãZ†=;HÚ:žÐFM×T¨Y¯FA’›ÍíÓVøyfI©Òæ{Ýêõú{[½1TÂØ4gé,4Ù¯GÓä f1ÊK¥ƒ†È Îå›f¯íqäãª~7ÇîÅò®‹p£ÆßÉ2D$7Š~ý :c4úîÀ?ëpsØÔ^>a0£—x½ÈÕþvÏBZãt7…H¸®,v3©+}l«E-"Kn‡DÄËQÑG×pZ‘O㵉¨pæÐ: IL¸Ó]¬înÊõ7‰^™=Z ’[Ϋ§hÊç†Üw™”nDÜqUWínµzõ;[¥)Ö÷fY•›U‚"Y<ú(ð‚0*%PGÐ3½Ã$­ãèòéáònç ‚(H`Òh¢+„DèF›º_׳.él¨±‘6ì2ûl¶ÃvY×*“RwX]¬áç;ÓjlªæpìH|¡¿Ik¦ÉÆnîEõ%ŒzÜ_h÷çâÎŒ$“åh/üán•ckzÀ1¶ã<"@~<ÙÀ¶ã³Â€ùèN0¨ˆ·[ðÉ!`æ0r:èUø!Ì©õv¥¿ "¡íëœà7öºë/¶¨‘ÐrV9öýÃ{TÝëÝ&¥@"€ŒÜÃÜ>Ýð0` Mu`·$c&ΰ •мµUl6kåÂv÷¸^ÎLr…HÉòÆ{WJÐ6Æ™5÷ô]Ä3OˆSk)¢4ü\¶ ª÷‡àF”éÕÒÇE$r/7Ë}¾÷¢ÇÐèûàvlî >‡PH„ö!8ßtÔoÛD"Ã?Tb}Öåû¦är(ê½§Œ¹l,$íV]j3ý·¥Rq¯ÝÕÔÄŠ9Z&lŸzæèÒ§ˆš>R ª„­ÖA¿|{³8Íû¥¹&£ŒfŒ!™À!¡Y™ºÒb†Ýºê_ÏåÑF eî ‘@švà†èG8!å;ód1ÞHòdŽ·=sŽÇ%NŸ]£àRó@ï C¤bÅÑé™!²D~4cÔŽ(¤Í’ ?úþx•$L~Ò5AÚ-®[ô›å}°\+ÝÛ8”ëï±`‚ É`.“<Õ0êò#Õ!Ž#îWHR,š4mö lÓž^kUªUæFãwxùà·{ö†=Sç·ñ’l1ev§UKoT9·ÈR?ã™7¡$‰ÈÙ4×&¸EÌig­ì r¥-£\¯¦—³3+‰$‘/ôó”¬ä™þ€ÿ´«˜6»5ŒÖBº8ßÇŽ¢Ì²,##Ÿ¤¢\¾KœFƒÕøÇoª‰À|1AFŸ\ƒàÛâN­ðá2 '‚dpô%L)õé†Ç![D󃔢6TÄéfÏ$QŒÃ‹M+•ÜÞÅÓÓ¬jBgQ¯§ÎÏ\.Â3H|5íˆ l›£›f UGÓÁZ»^ýo‹,„êu…I&a'#IO%<)ȳo–z¥b™‘yœ$‚‘á¿ÍÕ{`ž(Kc~ùüäX±8Vë…AåD‹@«.¼ÈçM Úk~— ¢E’ A·Nðé:üÐïZ«çÏp~D2Û¡enÜf“ÊÌA¿6=ß8Œu çD¾å[¶e™L“¿GþÄó(ÄÒG‚Õúñj}rmÛÂÂIØe) L­î‰‡'M6Ð†Šš¬2háª2·gî?~õ»Q1(áÀãÁ ½ýÞäÚ^i¡Z­¦Ñ›!žÖ¾C?ÅzÞfhëà~ä;ÓʵŽ@\0ê/{(F6°öCÿ7J! Ñë6lÝC \hÖJõ üè?ÓàÖ™m¼@<¼³¤ø”„à»T }ÒƒÇX+ˆu¹²[,}x¯PaD chC) l¡p° O<< È”á²4PHvÈŽ!jGï2Õ›Þ˜ À²Úíƒ^óîvqÎÅds“ÂE;x=\Ml¼¿sƒ “Pè:Þ¼=,ÿ̓~‡¥j’â&Q p(ئC~)tfP;(œA8<鹤9’™²z8JcÝ&¤nÓd#ÑQˆ£×1ÜX+VÛø] ™@ä[¿°x*Rà~QÏâBêµJÕÃñè;£ßMw<}~Çëø¶Ã&–6³»‡•*?ÑÇÁÏü˜•Û¸!Á{îÕ½7:2Ðn €’ÙEïïr¦ º_ õQ¤_'^%ʉŸ\ƒ26Ç…Á 2q~ U0=D`øøšW‘öÈbXÊ;ïƒ0,ltoÃl÷6½_¤-ë[}†ŠµÊZ»XÇ=œ¥`fa&|ìÒ  ø2=N ù~Ní¬l÷§¶÷Ëcîäl‚XFîª!$gñ? •;hæ €ïÕ)cUÀö!þV¿‹ßâ#^_'.¯o5FµCP8,Uìu›[•g9 £|UQþ Y®‡ïGˆ÷>‡, ŽK‹#B sžÉtXë9‡¶³“j“{û}öÊôU‡ÖŸF†È]áöˇ Ÿ/_ÒÓ)A\‰Ó,%¼7¢J­Ýþäæ~y’chÒ´LñAu ˆÌ¨Ž¶ƒ¹3 |±¶ÃÐ5|®juâǘ~χ¡7ˆ€÷ª'n.L?öqögÚiâìT ßçÅqrìÐÐz†¼ëË’ F$²°ÿ\]@êaFW1UYdÃ’²Â~·6½Û¹¦1œ%¤m1ZUTÇõK…¯:Ø9;*î‚6A…rF{s·?µ¸Yœ<`?Îdc'Ém‚õšYâ0乂6'|¯íêñÃäê®óɨø¿J¼E”û¿f7+â`°µ×;³sØœ«ôÙ3Ѻº©'„™ë#×±?Ç9_5 Z‚ëý%¹ß‰"G4Uö–7ªÅr«_?µßé³&³¯ â3¼§‡_ž¾@?ˆ@ä'ïwËÀã[û¥Z¨ DwÅêasTþGÌó nÞðt®õv÷>+úû׉r¿†j´À6¨ p÷úx7Ö&&ê¬yŸ›è…«ØVJÁé¤ isÿ•†Ø¥“'¡x> RÛH~ŰP«W­Vª¶ûµsl j@ÐOœ¾.@߃€D£¡$ØÄº·±×on”'ç™QœaA"!G ‡ˆËlO¿¶îV°¾†Þ‡ÄlüIY÷f.³”…YwÐïw×wsÝÒôølý žæ÷„ùþR·ƒh¥QïTÙ>ÙEžÝÆìt«{ ä~÷ ¸AVqU ác¥.*¦¬$8ÔpP"s¹}ôðu"{'Dz&%€@ ä½Í½þä½íòT‘™#·kÕÙ‹H#r®Ûd®U9 ¡ÏÒ¿püˆôãC?u¿åæ`½Úº½·ÈCh ‡Ô9S©5§Æ÷c¸ûéÜ›:K‘/zÆ2­ußâ]¶öÈ;'™ÜTê¦ØŠ€jUT ¾èv¯v†P–ùö[XØ6ÛõÈáëFv0#C HJ£Ïêì½Ýý^ Ñ:±Òª”l4pqh:TÓ´Ë)SÿxG·oWGψrÿ ¢„ £Êñ·@=r½ß‚:ƒúj«z®X®•Æâ÷ˆœ²–óK‰À¹3mƒ6uÿ=äÌÇÜz†B½PcŽÚmòftʼ+µà%/´µÓ½’€ÜGªPd"àöÑÂבìaFF–">Kï71ìÜÇPâÆÆJ«\îâê­"^Ýsp{§š®-˜õé]%í5¢àU) på,ë8r@xA{¿ÓXÚ®œêö«¥ù±Ã MÕA`œœâRà*&Ï*ò<¤»èg3 |ôH=Î]R éÝ!mô¼Á6Ax½^)ívJ³ûí“,¥lk–÷·™OŸ¾®{e‡3H"K´Öë÷·¶[ÝÁÍ~Å«ÕÛ¬¾zsŽöc5®Ü¯ñw}•ÙâæöŸë­ÖiÌ?hïÖooUÚ‡•ÒLwñÄÐØ#M9oÑJ‡|.dYg=¢¿äz¶Â@1œz çâ‘qp¹{¼ãmš("%*UÐŒö”zJ*Ûaß½Jœ¹MÜ~qøº€=´Ã"%#^À 9z#që1:ݾˆþ€¨ÈϺ߫Þ@ó~s}Ûhð]›5 µÛ›¥ùV©4ÚHO2q—´ÈW¸1Î@ ûöŠ*!B:P@­r¾AJªî‡ÏÏ vd•ËÕé­ýÂóÖ¡òÈ*ò3ñ{o{*|ÀŽÚáÌ™"PΓÃ0ÝëZÕâÑ7ˆŠýÌý>;)õyÜÏçO…L™ë¬ï°Û-.m•æ6ZåÊ,«£=¹Ô-ëýý‡wk……'È'ˆ2<_/zO£œï‰"ƒ>{¦€_³M0Qb[^¡4¹}P˜R‘Db—ì»Ñ¶<|S€þF8N™;TF‰Á«„ ¡'1(nîý& p£t"_É#×Y·Ï{øñ9«0¿ÞªU'8#y–SM,ÔÕËשÙC«ôQ°Â…yÎGBô‡”Ð ( bHȳR ¾‘ÎB‰…$eJ›duT©\žæ—ÊÇ û$Ñí·m²=_¾i`‡3"DfVÇ‘öi^¹ß(çg«ú¡€FúÄk±@÷IDAT&ëóÞØbnapo»°°ÙªÔÜHë¾€xÕ±ÿSÏ üe“2VÜËêqf@Ìñ<|äèûx¶6¢#„"™&ʃ«š¦8nÎöë»Ð8´¯ö[¢ü€†úFA%D†ˆ‘3• !"—£oKŽ1­ù%äzT†L|–ÅâžÃô· ß«U›?ìP nÑ ¨œW§[£[Ó ¨€"’@ÑŸƒœŸA&©…>…¸z™Y,û4Oœ&NëDÛ,–ð¹á›J¹Óà8!Þ!; Sˆ0ãj˜üsA.Ëk„CVþ¿7ŠßÛïOL<;ÙJ}–—ã8Xdu=#[y¬Úñû¼Bð›-'J,äHwX>¿Õöl“ ð WcF>·_¾‰*à³z-Ô2ÂóÕwO*X–œ¯49.QÚÝnw°¼Ý›ÁÑpÖp‚óÕKø$D°ÈUÏâœDĽ’ah~â<þ\‚ûq>±¬¾ƒ/²¬Ùd•¦=c¾0|›à ñ<ˆ$Šsmƒ¨tRubr¬\ªáçWüÆÐ®=$›†ˆÏ.±Èþ"Ìœ¬ø ðdþ¯òˆæ&÷4š9! ö„ÃýDUvÈç¥êØüdeP¨1œ±u3z§p„|?Œï; Ç­N%]_ë25ø€W"]¸F¼EÔÈÕ®9RCÜf8!€ÏÍ—úpœ—kˆJ‡ŒývÚÝ™~©1Ó`!K [@üš!‡Œü#*ÈHÅŒFºÉ)ãk»]- @ä_'JNc?´ø'mH¯'áÉC@œÒ¹f"Éœ}Ä÷+§9<ŠígìxRÉ0~twD ÃÆ¹ÁTîÿh™YŒþà*oEºzß{%Á#q?éO@ <åpœ4ÌÍÜ€í=&V÷X•êKÁʸüÂxâ%ç z ë:~¶ÓÉý¿'Êý7ˆ‚Ž-ýÖ÷ÐáD<4¨;¡ø“ó3!xõjaBè¶{åùb¥Zó—Õ*H1A¶z 7àþ«+]—°]ã³Qî÷šu¿CBR?|8!€‡‡Õ—M)bD~&‰ÂÈ0±ç¥ù>‹ Æ1 ër;ΡðøáI‡yv}ƒ ,»]ݾ ÊýŠýëĬû-ï‘ <¸¾Tb ܯ]Uóýþvk°€ ¨MºãÐea*Œ+EåþkËœ&3Ôý×É›-ÿÇÒýäpBœ«   ŒÞû®íì`«[>•ÊÕÚ8Î"mÙßéŸë,é~¹_Žñ×F÷Zþ–óÈá„dO$C&%€D è–8ÚL'÷7ÛýÙ^©Þð ÏA\o•ÓÇËÝܯÁw•˜u¿Dà$ºß29œÀ#ƒì‰ea"^"0zï;fívŸÉ•qìâúš¿ÔÖwˆ'÷‹üLªÇæ~òž Ÿ0Èõlj@1î³ê ½ÓêÖÖw{E¼‡ºwöÉñǹ_¢xlî'o¸£½ž„? 2ˆD‘™¥ÂÈF(Þ爅ÓÙ‚Ü/¸|í¡]¾¤}`ø¦O?°Ó_±—Ïcø,D®Ÿ)¢xr.A¸EÌNU‡ù;œÀcƒî‰gñ™£%®'j«ùM®× aä´Üž„œ@àÿñÊ¿ÂF©SIEND®B`‚stella-3.9.3/src/common/SoundSDL.hxx0000644000175000001440000001756412266336753016674 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SoundSDL.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifdef SOUND_SUPPORT #ifndef SOUND_SDL_HXX #define SOUND_SDL_HXX class OSystem; #include #include "bspf.hxx" #include "TIASnd.hxx" #include "Sound.hxx" /** This class implements the sound API for SDL. @author Stephen Anthony and Bradford W. Mott @version $Id: SoundSDL.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class SoundSDL : public Sound { public: /** Create a new sound object. The init method must be invoked before using the object. */ SoundSDL(OSystem* osystem); /** Destructor */ virtual ~SoundSDL(); public: /** Enables/disables the sound subsystem. @param state True or false, to enable or disable the sound system */ void setEnabled(bool state); /** The system cycle counter is being adjusting by the specified amount. Any members using the system cycle counter should be adjusted as needed. @param amount The amount the cycle counter is being adjusted by */ void adjustCycleCounter(Int32 amount); /** 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); /** 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); /** Initializes the sound device. This must be called before any calls are made to derived methods. */ void open(); /** Should be called to close the sound device. Once called the sound device can be started again using the open method. */ void close(); /** 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); /** Reset the sound device. */ void reset(); /** 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, Int32 cycle); /** 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); /** 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); 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; /** 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); /** Get a descriptor for this console class (used in error checking). @return The name of the object */ string name() const { 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; }; /** 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); /** Destroy this queue instance. */ virtual ~RegWriteQueue(); 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(); /** Enqueue the specified object. */ void enqueue(const RegWrite& info); /** Return the item at the front on the queue. @return The item at the front of the queue. */ RegWrite& front(); /** 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: uInt32 myCapacity; RegWrite* myBuffer; uInt32 mySize; uInt32 myHead; uInt32 myTail; }; 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 Int32 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); }; #endif #endif // SOUND_SUPPORT stella-3.9.3/src/common/ZipHandler.cxx0000644000175000001440000004705712266336753017274 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ZipHandler.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include #include "ZipHandler.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ZipHandler::ZipHandler() : myZip(NULL) { for (int cachenum = 0; cachenum < ZIP_CACHE_SIZE; cachenum++) myZipCache[cachenum] = NULL; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 = NULL; 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(uInt8*& image) { static const char* 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 = new uInt8[length]; ZipHandler::zip_error err = zip_file_decompress(myZip, image, length); if(err == ZIPERR_NONE) return length; else { delete[] image; image = 0; length = 0; throw zip_error_s[err]; } } else throw "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 = NULL; length = 0; return false; } else { in->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit ); *stream = in; in->seekg(0, ios::end); length = in->tellg(); in->seekg(0, ios::beg); return true; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ZipHandler::stream_close(fstream** stream) { if(*stream) { if((*stream)->is_open()) (*stream)->close(); delete *stream; *stream = NULL; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ZipHandler::stream_read(fstream* stream, void* buffer, uInt64 offset, uInt32 length, uInt32& actual) { try { stream->seekg(offset); stream->read((char*)buffer, length); actual = stream->gcount(); return true; } catch(...) { return false; } 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 = NULL; /* 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 != NULL && cached->filename != NULL && strcmp(filename, cached->filename) == 0) { *zip = cached; myZipCache[cachenum] = NULL; return ZIPERR_NONE; } } /* allocate memory for the zip_file structure */ newzip = (zip_file *)malloc(sizeof(*newzip)); if (newzip == NULL) 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 == NULL) { 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 == NULL) { 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] == NULL) 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(void) { /* clear call cache entries */ for (int cachenum = 0; cachenum < ZIP_CACHE_SIZE; cachenum++) if (myZipCache[cachenum] != NULL) { free_zip_file(myZipCache[cachenum]); myZipCache[cachenum] = NULL; } } /*************************************************************************** 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 != NULL) { zip->header.raw[ZIPCFN + zip->header.filename_length] = zip->header.saved; zip->header.raw = NULL; } /* if we're at or past the end, we're done */ if (zip->cd_pos >= zip->ecd.cd_size) return NULL; /* 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 NULL; /* NULL terminate the filename */ zip->header.saved = zip->header.raw[ZIPCFN + zip->header.filename_length]; zip->header.raw[ZIPCFN + zip->header.filename_length] = 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 != NULL) { if (zip->file) stream_close(&zip->file); if (zip->filename != NULL) free((void *)zip->filename); if (zip->ecd.raw != NULL) free(zip->ecd.raw); if (zip->cd != NULL) 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 = zip->length; /* allocate buffer */ buffer = (uInt8 *)malloc(buflen + 1); if (buffer == NULL) 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 == NULL && !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 */ while (1) { /* read in the next chunk of data */ bool success = stream_read(zip->file, zip->buffer, offset, BSPF_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-3.9.3/src/common/bspf.hxx0000644000175000001440000001370612266336753016165 0ustar stephenusers//============================================================================ // // 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-2014 by Bradford W. Mott, Stephen Anthony // and 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: bspf.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: bspf.hxx 2838 2014-01-17 23:34:03Z stephena $ */ #ifdef HAVE_INTTYPES #include // Types for 8-bit signed and unsigned integers typedef int8_t Int8; typedef uint8_t uInt8; // Types for 16-bit signed and unsigned integers typedef int16_t Int16; typedef uint16_t uInt16; // Types for 32-bit signed and unsigned integers typedef int32_t Int32; typedef uint32_t uInt32; // Types for 64-bit signed and unsigned integers typedef int64_t Int64; typedef uint64_t uInt64; #elif defined BSPF_WIN32 // Types for 8-bit signed and unsigned integers typedef signed char Int8; typedef unsigned char uInt8; // Types for 16-bit signed and unsigned integers typedef signed short Int16; typedef unsigned short uInt16; // Types for 32-bit signed and unsigned integers typedef signed int Int32; typedef unsigned int uInt32; // Types for 64-bit signed and unsigned integers typedef __int64 Int64; typedef unsigned __int64 uInt64; #else #error Update src/common/bspf.hxx for datatypes #endif // 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 using namespace std; // Defines to help with path handling #if (defined(BSPF_UNIX) || defined(BSPF_MAC_OSX)) #define BSPF_PATH_SEPARATOR "/" #elif (defined(BSPF_DOS) || defined(BSPF_WIN32) || defined(BSPF_OS2)) #define BSPF_PATH_SEPARATOR "\\" #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) #define BSPF_ARCH "i386" #elif defined(__x86_64__) || defined(_WIN64) #define BSPF_ARCH "x86_64" #elif defined(__powerpc__) || defined(__ppc__) #define BSPF_ARCH "ppc" #else #define BSPF_ARCH "NOARCH" #endif // I wish Windows had a complete POSIX layer #if defined BSPF_WIN32 && !defined __GNUG__ #define BSPF_snprintf _snprintf #define BSPF_vsnprintf _vsnprintf #else #define HAVE_UNISTD_H // needed for building zlib #include #define BSPF_snprintf snprintf #define BSPF_vsnprintf vsnprintf #endif static const string EmptyString(""); ////////////////////////////////////////////////////////////////////// // Some convenience functions template inline void BSPF_swap(T& a, T& b) { T tmp = a; a = b; b = tmp; } template inline T BSPF_abs (T x) { return (x>=0) ? x : -x; } template inline T BSPF_min (T a, T b) { return (a inline T BSPF_max (T a, T b) { return (a>b) ? a : b; } template inline T BSPF_clamp (T a, T l, T u) { return (au) ? u : a; } // Test whether two characters are equal (case insensitive) static bool BSPF_equalsIgnoreCaseChar(char ch1, char ch2) { return toupper((unsigned char)ch1) == toupper((unsigned char)ch2); } // Compare two strings, ignoring case inline int BSPF_compareIgnoreCase(const string& s1, const string& s2) { #if defined WIN32 && !defined __GNUG__ return _stricmp(s1.c_str(), s2.c_str()); #else return strcasecmp(s1.c_str(), s2.c_str()); #endif } inline int BSPF_compareIgnoreCase(const char* s1, const char* s2) { #if defined WIN32 && !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 BSPF_startsWithIgnoreCase(const string& s1, const string& s2) { #if defined WIN32 && !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 BSPF_startsWithIgnoreCase(const char* s1, const char* s2) { #if defined WIN32 && !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 BSPF_equalsIgnoreCase(const string& s1, const string& s2) { return BSPF_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 BSPF_findIgnoreCase(const string& s1, const string& s2, int startpos = 0) { string::const_iterator pos = std::search(s1.begin()+startpos, s1.end(), s2.begin(), s2.end(), BSPF_equalsIgnoreCaseChar); return pos == s1.end() ? string::npos : pos - (s1.begin()+startpos); } // Test whether the first string ends with the second one (case insensitive) inline bool BSPF_endsWithIgnoreCase(const string& s1, const string& s2) { if(s1.length() >= s2.length()) { const char* end = s1.c_str() + s1.length() - s2.length(); return BSPF_compareIgnoreCase(end, s2.c_str()) == 0; } return false; } // Test whether the first string contains the second one (case insensitive) inline bool BSPF_containsIgnoreCase(const string& s1, const string& s2) { return BSPF_findIgnoreCase(s1, s2) != string::npos; } #endif stella-3.9.3/src/common/FBSurfaceTIA.cxx0000644000175000001440000003214712266336753017364 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FBSurfaceTIA.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifdef DISPLAY_OPENGL #include #include "Font.hxx" #include "FrameBufferGL.hxx" #include "TIA.hxx" #include "NTSCFilter.hxx" #include "FBSurfaceTIA.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurfaceTIA::FBSurfaceTIA(FrameBufferGL& buffer) : myFB(buffer), myGL(myFB.p_gl), myTexture(NULL), myVBOID(0), myBaseW(0), myBaseH(0), myScanlinesEnabled(false), myScanlineIntensityI(50), myScanlineIntensityF(0.5) { myTexID[0] = myTexID[1] = 0; // Texture width is set to contain all possible sizes for a TIA image, // including Blargg filtering myTexWidth = FrameBufferGL::power_of_two(ATARI_NTSC_OUT_WIDTH(160)); myTexHeight = FrameBufferGL::power_of_two(320); // Create a surface in the same format as the parent GL class const SDL_PixelFormat& pf = myFB.myPixelFormat; myTexture = SDL_CreateRGBSurface(SDL_SWSURFACE, myTexWidth, myTexHeight, pf.BitsPerPixel, pf.Rmask, pf.Gmask, pf.Bmask, pf.Amask); myPitch = myTexture->pitch / pf.BytesPerPixel; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurfaceTIA::~FBSurfaceTIA() { if(myTexture) SDL_FreeSurface(myTexture); free(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceTIA::getPos(uInt32& x, uInt32& y) const { x = myImageX; y = myImageY; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceTIA::translateCoords(Int32& x, Int32& y) const { x -= myImageX; y -= myImageY; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceTIA::update() { // Copy the mediasource framebuffer to the RGB texture // In OpenGL mode, it's faster to just assume that the screen is dirty // and always do an update uInt8* currentFrame = myTIA->currentFrameBuffer(); uInt8* previousFrame = myTIA->previousFrameBuffer(); uInt32 width = myTIA->width(); uInt32 height = myTIA->height(); uInt32* buffer = (uInt32*) myTexture->pixels; // TODO - Eventually 'phosphor' won't be a separate mode, and will become // a post-processing filter by blending several frames. switch(myFB.myFilterType) { case FrameBufferGL::kNormal: { uInt32 bufofsY = 0; uInt32 screenofsY = 0; for(uInt32 y = 0; y < height; ++y) { uInt32 pos = screenofsY; for(uInt32 x = 0; x < width; ++x) buffer[pos++] = (uInt32) myFB.myDefPalette[currentFrame[bufofsY + x]]; bufofsY += width; screenofsY += myPitch; } break; } case FrameBufferGL::kPhosphor: { uInt32 bufofsY = 0; uInt32 screenofsY = 0; for(uInt32 y = 0; y < height; ++y) { uInt32 pos = screenofsY; for(uInt32 x = 0; x < width; ++x) { const uInt32 bufofs = bufofsY + x; buffer[pos++] = (uInt32) myFB.myAvgPalette[currentFrame[bufofs]][previousFrame[bufofs]]; } bufofsY += width; screenofsY += myPitch; } break; } case FrameBufferGL::kBlarggNormal: { myFB.myNTSCFilter.blit_single(currentFrame, width, height, buffer, myTexture->pitch); break; } case FrameBufferGL::kBlarggPhosphor: { myFB.myNTSCFilter.blit_double(currentFrame, previousFrame, width, height, buffer, myTexture->pitch); break; } } myGL.EnableClientState(GL_VERTEX_ARRAY); myGL.EnableClientState(GL_TEXTURE_COORD_ARRAY); // Update TIA image (texture 0), then blend scanlines (texture 1) myGL.ActiveTexture(GL_TEXTURE0); myGL.BindTexture(GL_TEXTURE_2D, myTexID[0]); myGL.PixelStorei(GL_UNPACK_ALIGNMENT, 1); myGL.PixelStorei(GL_UNPACK_ROW_LENGTH, myPitch); myGL.TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myBaseW, myBaseH, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, myTexture->pixels); if(myFB.myVBOAvailable) { myGL.BindBuffer(GL_ARRAY_BUFFER, myVBOID); myGL.VertexPointer(2, GL_FLOAT, 0, (const GLvoid*)0); myGL.TexCoordPointer(2, GL_FLOAT, 0, (const GLvoid*)(8*sizeof(GLfloat))); myGL.DrawArrays(GL_TRIANGLE_STRIP, 0, 4); if(myScanlinesEnabled) { myGL.Enable(GL_BLEND); myGL.Color4f(1.0f, 1.0f, 1.0f, myScanlineIntensityF); myGL.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); myGL.BindTexture(GL_TEXTURE_2D, myTexID[1]); myGL.VertexPointer(2, GL_FLOAT, 0, (const GLvoid*)(16*sizeof(GLfloat))); myGL.TexCoordPointer(2, GL_FLOAT, 0, (const GLvoid*)(24*sizeof(GLfloat))); myGL.DrawArrays(GL_TRIANGLE_STRIP, 0, 4); myGL.Disable(GL_BLEND); } } else { myGL.VertexPointer(2, GL_FLOAT, 0, myCoord); myGL.TexCoordPointer(2, GL_FLOAT, 0, myCoord+8); myGL.DrawArrays(GL_TRIANGLE_STRIP, 0, 4); if(myScanlinesEnabled) { myGL.Enable(GL_BLEND); myGL.Color4f(1.0f, 1.0f, 1.0f, myScanlineIntensityF); myGL.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); myGL.BindTexture(GL_TEXTURE_2D, myTexID[1]); myGL.VertexPointer(2, GL_FLOAT, 0, myCoord+16); myGL.TexCoordPointer(2, GL_FLOAT, 0, myCoord+24); myGL.DrawArrays(GL_TRIANGLE_STRIP, 0, 4); myGL.Disable(GL_BLEND); } } myGL.DisableClientState(GL_VERTEX_ARRAY); myGL.DisableClientState(GL_TEXTURE_COORD_ARRAY); // Let postFrameUpdate() know that a change has been made myFB.myDirtyFlag = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceTIA::invalidate() { SDL_FillRect(myTexture, NULL, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceTIA::free() { myGL.DeleteTextures(2, myTexID); if(myFB.myVBOAvailable) myGL.DeleteBuffers(1, &myVBOID); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceTIA::reload() { // This does a 'soft' reset of the surface // It seems that on some system (notably, OSX), creating a new SDL window // destroys the GL context, requiring a reload of all textures // However, destroying the entire FBSurfaceGL object is wasteful, since // it will also regenerate SDL software surfaces (which are not required // to be regenerated) // Basically, all that needs to be done is to re-call glTexImage2D with a // new texture ID, so that's what we do here myGL.ActiveTexture(GL_TEXTURE0); myGL.Enable(GL_TEXTURE_2D); // TIA surfaces also use a scanline texture myGL.GenTextures(2, myTexID); // Base texture (@ index 0) myGL.BindTexture(GL_TEXTURE_2D, myTexID[0]); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myTexFilter[0]); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myTexFilter[0]); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Create the texture in the most optimal format myGL.PixelStorei(GL_UNPACK_ALIGNMENT, 1); myGL.PixelStorei(GL_UNPACK_ROW_LENGTH, myPitch); myGL.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myTexWidth, myTexHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, myTexture->pixels); // Scanline texture (@ index 1) myGL.BindTexture(GL_TEXTURE_2D, myTexID[1]); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myTexFilter[1]); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myTexFilter[1]); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); static uInt32 const scanline[2] = { 0x00000000, 0xff000000 }; myGL.PixelStorei(GL_UNPACK_ALIGNMENT, 1); myGL.PixelStorei(GL_UNPACK_ROW_LENGTH, 1); myGL.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 2, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, scanline); // Cache vertex and texture coordinates using vertex buffer object if(myFB.myVBOAvailable) { myGL.GenBuffers(1, &myVBOID); myGL.BindBuffer(GL_ARRAY_BUFFER, myVBOID); myGL.BufferData(GL_ARRAY_BUFFER, 32*sizeof(GLfloat), myCoord, GL_STATIC_DRAW); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceTIA::setScanIntensity(uInt32 intensity) { myScanlineIntensityI = (GLuint)intensity; myScanlineIntensityF = (GLfloat)intensity / 100; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceTIA::setTexInterpolation(bool enable) { myTexFilter[0] = enable ? GL_LINEAR : GL_NEAREST; myGL.BindTexture(GL_TEXTURE_2D, myTexID[0]); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myTexFilter[0]); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myTexFilter[0]); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceTIA::setScanInterpolation(bool enable) { myTexFilter[1] = enable ? GL_LINEAR : GL_NEAREST; myGL.BindTexture(GL_TEXTURE_2D, myTexID[1]); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myTexFilter[1]); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myTexFilter[1]); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceTIA::updateCoords(uInt32 baseH, uInt32 imgX, uInt32 imgY, uInt32 imgW, uInt32 imgH) { myBaseH = baseH; myImageX = imgX; myImageY = imgY; myImageW = imgW; myImageH = imgH; updateCoords(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceTIA::updateCoords() { // Normal TIA rendering and TV effects use different widths // We use the same buffer, and only pick the width we need myBaseW = myFB.ntscEnabled() ? ATARI_NTSC_OUT_WIDTH(160) : 160; myTexCoordW = (GLfloat) myBaseW / myTexWidth; myTexCoordH = (GLfloat) myBaseH / myTexHeight; // Vertex coordinates for texture 0 (main texture) // Upper left (x,y) myCoord[0] = (GLfloat)myImageX; myCoord[1] = (GLfloat)myImageY; // Upper right (x+w,y) myCoord[2] = (GLfloat)(myImageX + myImageW); myCoord[3] = (GLfloat)myImageY; // Lower left (x,y+h) myCoord[4] = (GLfloat)myImageX; myCoord[5] = (GLfloat)(myImageY + myImageH); // Lower right (x+w,y+h) myCoord[6] = (GLfloat)(myImageX + myImageW); myCoord[7] = (GLfloat)(myImageY + myImageH); // Texture coordinates for texture 0 (main texture) // Upper left (x,y) myCoord[8] = 0.0f; myCoord[9] = 0.0f; // Upper right (x+w,y) myCoord[10] = myTexCoordW; myCoord[11] = 0.0f; // Lower left (x,y+h) myCoord[12] = 0.0f; myCoord[13] = myTexCoordH; // Lower right (x+w,y+h) myCoord[14] = myTexCoordW; myCoord[15] = myTexCoordH; // Vertex coordinates for texture 1 (scanline texture) // Upper left (x,y) myCoord[16] = (GLfloat)myImageX; myCoord[17] = (GLfloat)myImageY; // Upper right (x+w,y) myCoord[18] = (GLfloat)(myImageX + myImageW); myCoord[19] = (GLfloat)myImageY; // Lower left (x,y+h) myCoord[20] = (GLfloat)myImageX; myCoord[21] = (GLfloat)(myImageY + myImageH); // Lower right (x+w,y+h) myCoord[22] = (GLfloat)(myImageX + myImageW); myCoord[23] = (GLfloat)(myImageY + myImageH); // Texture coordinates for texture 1 (scanline texture) // Upper left (x,y) myCoord[24] = 0.0f; myCoord[25] = 0.0f; // Upper right (x+w,y) myCoord[26] = 1.0f; myCoord[27] = 0.0f; // 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 // Lower left (x,y+h) myCoord[28] = 0.0f; myCoord[29] = GLfloat(myImageH) / floor(((float)myImageH / myBaseH) + 0.5); // Lower right (x+w,y+h) myCoord[30] = 1.0f; myCoord[31] = myCoord[29]; // Cache vertex and texture coordinates using vertex buffer object if(myFB.myVBOAvailable) { myGL.BindBuffer(GL_ARRAY_BUFFER, myVBOID); myGL.BufferData(GL_ARRAY_BUFFER, 32*sizeof(GLfloat), myCoord, GL_STATIC_DRAW); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceTIA::setTIAPalette(const uInt32* palette) { myFB.myNTSCFilter.setTIAPalette(myFB, palette); } #endif stella-3.9.3/src/common/RectList.hxx0000644000175000001440000000214712266336753016761 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RectList.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef RECTLIST_HXX #define RECTLIST_HXX #include class RectList { public: RectList(Uint32 size = 256); ~RectList(); void add(SDL_Rect* rect); SDL_Rect* rects(); Uint32 numRects(); void start(); void print(int boundWidth, int boundHeight); private: Uint32 currentSize, currentRect; SDL_Rect* rectArray; }; #endif stella-3.9.3/src/common/SoundSDL.cxx0000644000175000001440000003625012266336753016660 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SoundSDL.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifdef SOUND_SUPPORT #include #include #include #include #include "TIASnd.hxx" #include "FrameBuffer.hxx" #include "Settings.hxx" #include "System.hxx" #include "OSystem.hxx" #include "Console.hxx" #include "SoundSDL.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SoundSDL::SoundSDL(OSystem* osystem) : Sound(osystem), myIsEnabled(false), myIsInitializedFlag(false), myLastRegisterSetCycle(0), myNumChannels(0), myFragmentSizeLogBase2(0), myIsMuted(true), myVolume(100) { myOSystem->logMessage("SoundSDL::SoundSDL 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 = (void*)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((double)myHardwareSpec.samples) / log(2.0); myFragmentSizeLogDiv1 = myFragmentSizeLogBase2 / 60.0; myFragmentSizeLogDiv2 = (myFragmentSizeLogBase2 - 1) / 60.0; myIsInitializedFlag = true; SDL_PauseAudio(1); myOSystem->logMessage("SoundSDL::SoundSDL initialized", 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SoundSDL::~SoundSDL() { // Close the SDL audio system if it's initialized if(myIsInitializedFlag) { SDL_CloseAudio(); myIsEnabled = myIsInitializedFlag = false; } myOSystem->logMessage("SoundSDL destroyed", 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::setEnabled(bool state) { myOSystem->settings().setValue("sound", state); myOSystem->logMessage(state ? "SoundSDL::setEnabled(true)" : "SoundSDL::setEnabled(false)", 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::open() { myOSystem->logMessage("SoundSDL::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: " << (int)myVolume << endl << " Frag size: " << (int)myHardwareSpec.samples << endl << " Frequency: " << (int)myHardwareSpec.freq << endl << " Channels: " << (int)myHardwareSpec.channels << " (" << chanResult << ")" << endl << endl; myOSystem->logMessage(buf.str(), 1); // And start the SDL sound subsystem ... myIsEnabled = true; mute(false); myOSystem->logMessage("SoundSDL::open finished", 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::close() { if(myIsInitializedFlag) { myIsEnabled = false; SDL_PauseAudio(1); myLastRegisterSetCycle = 0; myTIASound.reset(); myRegWriteQueue.clear(); myOSystem->logMessage("SoundSDL::close", 2); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::mute(bool state) { if(myIsInitializedFlag) { myIsMuted = state; SDL_PauseAudio(myIsMuted ? 1 : 0); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::reset() { if(myIsInitializedFlag) { SDL_PauseAudio(1); myLastRegisterSetCycle = 0; myTIASound.reset(); myRegWriteQueue.clear(); mute(myIsMuted); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::setVolume(Int32 percent) { if(myIsInitializedFlag && (percent >= 0) && (percent <= 100)) { myOSystem->settings().setValue("volume", percent); SDL_LockAudio(); myVolume = percent; myTIASound.volume(percent); SDL_UnlockAudio(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::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 SoundSDL::adjustCycleCounter(Int32 amount) { myLastRegisterSetCycle += amount; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::setChannels(uInt32 channels) { if(channels == 1 || channels == 2) myNumChannels = channels; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::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 SoundSDL::set(uInt16 addr, uInt8 value, Int32 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. RegWrite info; info.addr = addr; info.value = value; info.delta = delta; myRegWriteQueue.enqueue(info); // Update last cycle counter to the current cycle myLastRegisterSetCycle = cycle; SDL_UnlockAudio(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::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 / (double)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 SoundSDL::callback(void* udata, uInt8* stream, int len) { SoundSDL* sound = (SoundSDL*)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((Int16*)stream, (uInt32)len >> 1); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SoundSDL::save(Serializer& out) const { try { out.putString(name()); uInt8 reg1 = 0, reg2 = 0, reg3 = 0, reg4 = 0, reg5 = 0, reg6 = 0; // Only get the TIA sound registers if sound is enabled if(myIsInitializedFlag) { reg1 = myTIASound.get(0x15); reg2 = myTIASound.get(0x16); reg3 = myTIASound.get(0x17); reg4 = myTIASound.get(0x18); reg5 = myTIASound.get(0x19); reg6 = myTIASound.get(0x1a); } out.putByte(reg1); out.putByte(reg2); out.putByte(reg3); out.putByte(reg4); out.putByte(reg5); out.putByte(reg6); out.putInt(myLastRegisterSetCycle); } catch(...) { myOSystem->logMessage("ERROR: SoundSDL::save", 0); return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SoundSDL::load(Serializer& in) { try { if(in.getString() != name()) return false; uInt8 reg1 = in.getByte(), reg2 = in.getByte(), reg3 = in.getByte(), reg4 = in.getByte(), reg5 = in.getByte(), reg6 = in.getByte(); myLastRegisterSetCycle = (Int32) in.getInt(); // 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(0x15, reg1); myTIASound.set(0x16, reg2); myTIASound.set(0x17, reg3); myTIASound.set(0x18, reg4); myTIASound.set(0x19, reg5); myTIASound.set(0x1a, reg6); if(!myIsMuted) SDL_PauseAudio(0); } } catch(...) { myOSystem->logMessage("ERROR: SoundSDL::load", 0); return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SoundSDL::RegWriteQueue::RegWriteQueue(uInt32 capacity) : myCapacity(capacity), myBuffer(0), mySize(0), myHead(0), myTail(0) { myBuffer = new RegWrite[myCapacity]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SoundSDL::RegWriteQueue::~RegWriteQueue() { delete[] myBuffer; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::RegWriteQueue::clear() { myHead = myTail = mySize = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::RegWriteQueue::dequeue() { if(mySize > 0) { myHead = (myHead + 1) % myCapacity; --mySize; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - double SoundSDL::RegWriteQueue::duration() { double duration = 0.0; for(uInt32 i = 0; i < mySize; ++i) { duration += myBuffer[(myHead + i) % myCapacity].delta; } return duration; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::RegWriteQueue::enqueue(const RegWrite& info) { // 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(); myBuffer[myTail] = info; myTail = (myTail + 1) % myCapacity; ++mySize; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SoundSDL::RegWrite& SoundSDL::RegWriteQueue::front() { assert(mySize != 0); return myBuffer[myHead]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 SoundSDL::RegWriteQueue::size() const { return mySize; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL::RegWriteQueue::grow() { RegWrite* buffer = new RegWrite[myCapacity * 2]; for(uInt32 i = 0; i < mySize; ++i) { buffer[i] = myBuffer[(myHead + i) % myCapacity]; } myHead = 0; myTail = mySize; myCapacity = myCapacity * 2; delete[] myBuffer; myBuffer = buffer; } #endif // SOUND_SUPPORT stella-3.9.3/src/common/RectList.cxx0000644000175000001440000000526012266336753016753 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RectList.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "bspf.hxx" #include "RectList.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RectList::RectList(Uint32 size) { currentSize = size; currentRect = 0; rectArray = new SDL_Rect[currentSize]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RectList::~RectList() { delete[] rectArray; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RectList::add(SDL_Rect* newRect) { if(currentRect >= currentSize) { currentSize = currentSize * 2; SDL_Rect *temp = new SDL_Rect[currentSize]; for(Uint32 i = 0; i < currentRect; ++i) temp[i] = rectArray[i]; delete[] rectArray; rectArray = temp; } rectArray[currentRect].x = newRect->x; rectArray[currentRect].y = newRect->y; rectArray[currentRect].w = newRect->w; rectArray[currentRect].h = newRect->h; ++currentRect; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SDL_Rect* RectList::rects() { return rectArray; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Uint32 RectList::numRects() { return currentRect; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RectList::start() { currentRect = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RectList::print(int boundWidth, int boundHeight) { cerr << "RectList: rects = " << numRects() << endl; for(Uint32 i = 0; i < currentRect; ++i) { cerr << "Rect " << i << endl << " x = " << rectArray[i].x << endl << " y = " << rectArray[i].y << endl << " w = " << rectArray[i].w << endl << " h = " << rectArray[i].h << endl; if((rectArray[i].x + rectArray[i].w) > boundWidth || (rectArray[i].y + rectArray[i].h) > boundHeight) cerr << " TOO LARGE" << endl; cerr << endl; } } stella-3.9.3/src/common/stella-16x16.png0000644000175000001440000000123111676222762017243 0ustar stephenusers‰PNG  IHDRóÿasRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÛ /Ë›:IDAT8Ë“OHÓqÆ?ïïÏÔé~Í”Œ¢ ±,H¤²ôP$j Á¢‚ ƒP $¢?ç.±`‡ :$Ø%(±$™‰‚ÒÁ•…Æ ‡ikó»íÛÁ^Rë¹¼¼¼¼žÞ×dƒ:w¼øÄ¡JåË"¥_î%PËÝ¥«Õ:;rôä]~òèæjó3c­ÅöcÕ@áæ@³;œMþÐ*“apD±ÏOÓ¦" ¬ è}ñp·ô9fÒXÆ’ùE!Ma°«‚nkMëmö…;U£R '1-t| ‹êkÚÛ@½º“úŽV9$mØXd`Šg@ÿ_#\ Z×OQO–’èÅb $¾&qÜèhB²±ùûÆËÛ`{kìÖžvóæãËò­ª,sõùÚ·™Ž‚eN2¥ˆäðà¢LúËumdÞFÐ3sHϘþ¼bqRYøƒó÷8 <Í,-ãz··D@ ät+¤Ì% È9À[ J[×øššÙ™ö:Bi‰Pã‡ñ)Ȥ¡\&üLCm%€¹m5Àü]çßÏŠ06ü‘p|AŽ–˜xUzGy³£B |e¸]’ÉÛ'fôýõ®×i¨âUG½h  ¬¦G— =x\çA´¿Ü¾µÑ7hðþqìjÝYG.¸ 4ñ¯ÃliÛKºÎGðð’:—I0ßýµ™·3tÝëIEND®B`‚stella-3.9.3/src/common/StringParser.hxx0000644000175000001440000000447612266336753017662 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: StringParser.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef STRING_PARSER_HXX #define STRING_PARSER_HXX #include "StringList.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) { stringstream 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, uInt16 maxlen) { stringstream 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; }; #endif stella-3.9.3/src/common/mainSDL.cxx0000644000175000001440000001504012266336753016506 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: mainSDL.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "bspf.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" #if defined(UNIX) #include "SettingsUNIX.hxx" #include "OSystemUNIX.hxx" #elif defined(WIN32) #include "SettingsWin32.hxx" #include "OSystemWin32.hxx" #elif defined(MAC_OSX) #include "SettingsMACOSX.hxx" #include "OSystemMACOSX.hxx" extern "C" { int stellaMain(int argc, char* argv[]); } #else #error Unsupported platform! #endif #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #endif #ifdef CHEATCODE_SUPPORT #include "CheatManager.hxx" #endif // Pointer to the main parent osystem object or the null pointer OSystem* theOSystem = (OSystem*) NULL; // Does general Cleanup in case any operation failed (or at end of program) int Cleanup() { theOSystem->logMessage("Cleanup from mainSDL", 2); theOSystem->saveConfig(); if(theOSystem) delete theOSystem; if(SDL_WasInit(SDL_INIT_VIDEO) & SDL_INIT_VIDEO) SDL_Quit(); return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #if defined(MAC_OSX) int stellaMain(int argc, char* argv[]) #else int main(int argc, char* argv[]) #endif { ios_base::sync_with_stdio(false); // Create the parent OSystem object and settings #if defined(UNIX) theOSystem = new OSystemUNIX(); SettingsUNIX settings(theOSystem); #elif defined(WIN32) theOSystem = new OSystemWin32(); SettingsWin32 settings(theOSystem); #elif defined(MAC_OSX) theOSystem = new OSystemMACOSX(); SettingsMACOSX settings(theOSystem); #else #error Unsupported platform! #endif theOSystem->loadConfig(); theOSystem->logMessage("Loading config options ...", 2); // 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(); } #ifdef BSPF_UNIX // Nvidia cards under UNIX don't currently support SDL_GL_SWAP_CONTROL // So we need to do it with an Nvidia-specific environment variable // This also means the setting can only be changed by restarting Stella // This functionality should really be integrated into SDL directly if(theOSystem->settings().getBool("gl_vsync")) putenv((char*)"__GL_SYNC_TO_VBLANK=1"); #endif //// 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 } // Swallow any spurious events in the queue // These are normally caused by joystick/mouse jitter SDL_Event event; while(SDL_PollEvent(&event)) /* swallow event */ ; // 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-3.9.3/src/common/stella-32x32.png0000644000175000001440000000331411676222762017243 0ustar stephenusers‰PNG  IHDR szzôsRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÛ .#îƒÀªLIDATXÃÅ—[l\W†¿}.sÎ\ìÉØžØq.umH"·Öq‰.ªÚ hÚ´ø¥\^ BE”ˆ(B*<ÀBª„Ä }H+-—@š´¥ M|Iì'vì8ŒíØ1ñ=ãñeÆžÛ9gñp&ÈDnµ)ëe­½×¿×^ë_ÿ†ÿ³© ÞO?üyýE»2ZcfSó™¼Y8=  íoÈÇŽžt//NÎêÆFzßS:üõë;N>GÀ»¶š¯³e÷VÒ™©ôk|èú7Äç>²óåoæþ«)Rʈ”17»L$bÐ;¬ÈήX‰¤Ïæå$¿µJÛ ïæó‡ Gê÷lѳÊÓ oF°Ý,^¤ŠsgSˆBk”C­^¸nrhþòçôýó“It¡xœÌäåµ1ZÏÌ Lpµ%*Zsúpï†PÍvý -ù%T&–›CHÍ­P„é-¢(®Ÿ¨c'ðô­X/ãû-Þ¯î ÌÈNÎ*×/h£g– ÖTòö[ó˜U §!½ª,­;?=uáï}å€ìÏÌ­`އYšZ"Xes¡;C®JÀD ]PªcÈ;¼ Ⱥü°-øèK_]ù‰V⤠è,f „t(Ø›èËcè~ `™ðV?Ià—ÀÈ:#`5½ü­âñhPdîzA‰€Y®#é"vU9Ã7 F}ÇR:ýõ”b䦜N­³ ¬æ#ßvÚ>ºÙ±Ç¦P–‘ s± Ç`t$‹mƒeûW ›p¼‡àU`áƒP;ªí/}¾Ø±«Ö þí*j[5x̤ ×…Åé%4 t`L¹2¡‘ÎÉk@Çí›Þ%µù™G8ò\î7µ1Ï<щŠoO`S †¯AÈÓ‚tÊ?y@¦CY9êÔ¹ ¼¾šï¦˜¸ÿ ûä™'š¼g·ìÅøÝY”® ®4Ú»!õkÜ4 ç€U*=7ço(òŽüè[³Žo}ì­C%WŒ'ë«åÁš˜¶ww­×øñíÅúx¹ é…?ƒÉøùw!WC‡þAh9à'š”NmึáÂÿ(•]ñŽº¯ëûÞxÁ9 €à"‚X™‚ã¨Ó <×âA$ 'Z! CÐÏ…B*"0·¶ W1z“àêû2YiÜô‹gåõ…ˆB-.CïêÒäV ƒx쨀ûê@é0< Ž‚@Øwާ±2 ¤Rry5ó­ À4ÔÁ+×e[ÿ ²˜ö³9º vTC. Ù"ˆO}rØ04¶ ÓI(º`h i>ë•Ûs}@@ÿ÷š¦8޼óJ+¿ÞWêÁFdç= øD°Á²àñý¾x… ;^ÑŸ_ÈÀÜ¢só°u „L0üdtï(¡JãŠãqþÌveX57lEs”ãSYeìýˆÏjÉ4$®ùɦ‡ü°×Õø•`èPp †Å¬Îä= õŽÀ§ËiàGÏË7^}WM¸º†XÉ´N0¢0 D7 'º…,,¯@&ƒœèRLDág¿SOÁC .ш٠DþSnYèY¢½íªd;ò÷ËãÒqºs7’úžŠ˜ÓI”[âwW``uiš.¥´xSƒè®‡|†D!±¨¾½µßû+0v7(õ‰RÓ8 ¼ œ¾6#ó9G{¤¡JŒ‚ãßÞE:†ÔRÞãÇGô©CͲ/dù; *¤yæ±÷ŒxoÊLx'Qê•$´WJ¤ÞÑYIÜ\VŸüØ6ʲ.²”Euqøx]Ý£Ö£O>äU¯Öû';‘šrv'f MáuŠå¤Š]` ™¦½w\í*ª{Fç”79ÏKÀY`1•v/^ <Ôä”{ƒ“p9 "÷ÆõO%fTQ)é\ý6øoe¹ãù"ï NÓ?9Ïeà·Àbi~b"éôµ'´‡ß+Ñãí~.(S÷d{Œ‡‡f.­÷]°ôm·÷w`4¹$Ýï^1>Sö*þ¥<•w5†ge¶ÔÜ¥îûD©mlÖùâÙóR©‰®AÏ ™~¿V[þ_Y£Ðþòt“’ƒ÷)^¢öë·>hiÇ¢A¹íUôaZ%° Ü>ñOxw«6Q¤IIEND®B`‚stella-3.9.3/src/common/Array.hxx0000644000175000001440000001060512266336753016304 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Array.hxx 2838 2014-01-17 23:34:03Z stephena $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #ifndef ARRAY_HXX #define ARRAY_HXX #include #include "bspf.hxx" namespace Common { template class Array { protected: uInt32 _capacity; uInt32 _size; T *_data; public: typedef T *iterator; typedef const T *const_iterator; public: Array() : _capacity(0), _size(0), _data(0) {} Array(const Array& array) : _capacity(0), _size(0), _data(0) { _size = array._size; _capacity = _size + 128; _data = new T[_capacity]; for(uInt32 i = 0; i < _size; i++) _data[i] = array._data[i]; } ~Array() { if (_data) delete [] _data; } void reserve(uInt32 capacity) { if(capacity <= _capacity) return; ensureCapacity(capacity - 128); } void push_back(const T& element) { ensureCapacity(_size + 1); _data[_size++] = element; } void push_back(const Array& array) { ensureCapacity(_size + array._size); for(uInt32 i = 0; i < array._size; i++) _data[_size++] = array._data[i]; } void insert_at(uInt32 idx, const T& element) { assert(idx >= 0 && idx <= _size); ensureCapacity(_size + 1); // The following loop is not efficient if you can just memcpy things around. // e.g. if you have a list of ints. But for real objects (String...), memcpy // usually isn't correct (specifically, for any class which has a non-default // copy behaviour. E.g. the String class uses a refCounter which has to be // updated whenever a String is copied. for(uInt32 i = _size; i > idx; i--) _data[i] = _data[i-1]; _data[idx] = element; _size++; } T remove_at(uInt32 idx) { assert(idx >= 0 && idx < _size); T tmp = _data[idx]; for(uInt32 i = idx; i < _size - 1; i++) _data[i] = _data[i+1]; _size--; return tmp; } T& operator [](uInt32 idx) { assert(idx >= 0 && idx < _size); return _data[idx]; } const T& operator [](uInt32 idx) const { assert(idx >= 0 && idx < _size); return _data[idx]; } Array& operator =(const Array& array) { if (_data) delete [] _data; _size = array._size; _capacity = _size + 128; _data = new T[_capacity]; for(uInt32 i = 0; i < _size; i++) _data[i] = array._data[i]; return *this; } uInt32 size() const { return _size; } uInt32 capacity() const { return _capacity; } void clear(bool fullerase = true) { if(fullerase) { if(_data) { delete [] _data; _data = 0; } _capacity = 0; } _size = 0; } bool isEmpty() const { return (_size == 0); } iterator begin() { return _data; } iterator end() { return _data + _size; } const_iterator begin() const { return _data; } const_iterator end() const { return _data + _size; } protected: void ensureCapacity(uInt32 new_len) { if (new_len <= _capacity) return; T *old_data = _data; _capacity = new_len + 128; _data = new T[_capacity]; if (old_data) { // Copy old data for (uInt32 i = 0; i < _size; i++) _data[i] = old_data[i]; delete [] old_data; } } }; } // Namespace Common typedef Common::Array IntArray; typedef Common::Array BoolArray; typedef Common::Array ByteArray; #endif stella-3.9.3/src/common/Base.hxx0000644000175000001440000000643612266336753016107 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Base.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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_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_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 1/2/4 byte format */ static inline std::ostream& HEX2(std::ostream& os) { os.flags(myHexflags); return os << std::setw(2) << 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: // Make sure this class is never instantiated Base() { } 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 const char* myLowerFmt[4]; static const char* myUpperFmt[4]; static const char** myFmt; }; } // Namespace Common #endif stella-3.9.3/src/common/Stack.hxx0000644000175000001440000000337512266336753016301 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Stack.hxx 2838 2014-01-17 23:34:03Z stephena $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #ifndef STACK_HXX #define STACK_HXX #include /** * Simple fixed size stack class. */ namespace Common { template class FixedStack { public: FixedStack() : _size(0) {} bool empty() const { return _size <= 0; } bool full() const {return _size >= MAX_SIZE; } void clear() { _size = 0; } void push(const T& x) { assert(_size < MAX_SIZE); _stack[_size++] = x; } T top() const { if(_size > 0) return _stack[_size - 1]; else return 0; } T pop() { T tmp; assert(_size > 0); tmp = _stack[--_size]; return tmp; } int size() const { return _size; } T operator [](int i) const { assert(0 <= i && i < MAX_SIZE); return _stack[i]; } protected: T _stack[MAX_SIZE]; int _size; }; } // Namespace Common #endif stella-3.9.3/src/common/Base.cxx0000644000175000001440000000666512266336753016106 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Base.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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; 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) BSPF_snprintf(vToS_buf, 4, "%3d", value); else BSPF_snprintf(vToS_buf, 6, "%5d", value); break; case Base::F_16_1: // base 16: 1 byte wide BSPF_snprintf(vToS_buf, 2, myFmt[0], value); break; case Base::F_16_2: // base 16: 2 bytes wide BSPF_snprintf(vToS_buf, 3, myFmt[1], value); break; case Base::F_16_4: // base 16: 4 bytes wide BSPF_snprintf(vToS_buf, 5, myFmt[2], value); break; case Base::F_16_8: // base 16: 8 bytes wide BSPF_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) BSPF_snprintf(vToS_buf, 3, myFmt[1], value); else if(value < 0x10000) BSPF_snprintf(vToS_buf, 5, myFmt[2], value); else BSPF_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* Base::myLowerFmt[4] = { "%1x", "%02x", "%04x", "%08x" }; const char* Base::myUpperFmt[4] = { "%1X", "%02X", "%04X", "%08X" }; const char** Base::myFmt = Base::myLowerFmt; } // Namespace Common stella-3.9.3/src/common/Variant.hxx0000644000175000001440000000613112266336753016631 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Variant.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef VARIANT_HXX #define VARIANT_HXX #include "Array.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() : data("") { } Variant(const string& s) : data(s) { } Variant(const char* s) : data(s) { } Variant(int i) { buf().str(""); buf() << i; data = buf().str(); } Variant(unsigned int 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* toCString() const { return data.c_str(); } const int toInt() const { return atoi(data.c_str()); } const float toFloat() const { return 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) { os << v.data; return os; } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static const Variant EmptyVariant(""); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class VariantList : public Common::Array< pair > { public: void push_back(const Variant& name, const Variant& tag = EmptyVariant) { ensureCapacity(_size + 1); _data[_size++] = make_pair(name.toString(), tag); } }; #endif stella-3.9.3/src/common/StringList.hxx0000644000175000001440000000316212266336753017330 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: StringList.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef STRING_LIST_HXX #define STRING_LIST_HXX #include "Array.hxx" #include "bspf.hxx" class StringList : public Common::Array { public: void push_back(const char *str) { ensureCapacity(_size + 1); _data[_size++] = str; } void push_back(const string& str) { ensureCapacity(_size + 1); _data[_size++] = str; } static string removePattern(const string& str, const string& pattern) { // This can probably be made more efficient ... string tmp; for(unsigned int i = 0; i < str.length(); ++i) { bool match = false; for(unsigned int j = 0; j < pattern.length(); ++j) { if(str[i] == pattern[j]) { match = true; break; } } if(!match) tmp += str[i]; } return tmp; } }; #endif stella-3.9.3/src/common/FSNodeZIP.hxx0000644000175000001440000000622012266336753016725 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FSNodeZIP.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef FS_NODE_ZIP_HXX #define FS_NODE_ZIP_HXX #include "StringList.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. * @param node Raw pointer to use for the internal FSNode */ FilesystemNodeZIP(const string& path); bool exists() const { return _realNode && _realNode->exists(); } const string& getName() const { return _virtualFile; } const string& getPath() const { return _path; } string getShortPath() const { return _shortPath; } bool isDirectory() const { return _numFiles > 1; } bool isFile() const { return _numFiles == 1; } 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(uInt8*& image) const; private: FilesystemNodeZIP(const string& zipfile, const string& virtualfile, Common::SharedPtr realnode); void setFlags(const string& zipfile, const string& virtualfile, Common::SharedPtr realnode); private: /* Error types */ enum zip_error { ZIPERR_NONE = 0, ZIPERR_NOT_A_FILE, ZIPERR_NOT_READABLE, ZIPERR_NO_ROMS }; Common::SharedPtr _realNode; string _zipFile, _virtualFile; string _path, _shortPath; zip_error _error; uInt32 _numFiles; }; #endif stella-3.9.3/src/common/stella-48x48.png0000644000175000001440000000626511676222762017271 0ustar stephenusers‰PNG  IHDR00Wù‡sRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÛ )ÍAù[ 5IDAThÞÕš[l\×u†¿½ÏmÎÌpHФEZ”EI¶n´l˶,;¾Eq8MP'"¤H‘ 6Z Hkô¡-‚ mQ(Ú—}оm$i‚pìT²eY²R],R$Åûœámî3çìÕ‡}˜®ËMi98àÌppÎú×ùÿ­½öÀ¯ùá܉›ØåªBÑ䀽@€À4à&¯–ŒcM‘[]Kݡĵå“á·_úœÿÉ7YÎÊFuGZÒ3Õ–Õ³ƒf²•r|`Óõ7SWƦËÿ ñû]ȽÁ}=¹oüÞsåSwwò›Î\Gà ‚âÉ=½<{ïÇ»rÐqpÙpöäŸþ uà€…÷»˜þˆƒ×í­™“ßz±ôÇ÷ìVâ˜z tk'Ӄㄮ Ù×ey²â>¸[x4¡ÔÜýÒ3ñŸ;âvD^NÌF^ií¹Ô"Ÿ45\Ï!rÓœ;›WJÁ±^é=~ è»Ó£{9ýDó¹lï½¬Ž¨À…&îí¥¸”ÇsÀiËqãÝ"ù‚Áq]­Â¡ý"ð$»ƒÒõY¾uàP+sSâÁDëÞÁJ¾„ÕñÒ>‘ÛÁµw×p4PMƒÕÅ<é ¤wõráÌ(Å2F P/ôËqP_º>RuOμôå'ªÇÝîbŠ%廀€×ž£0»L[Ò]mܘg`XP.hJV(#°#” —ú ptkýÚV÷õ Â”ûðé•ßß¹o‡[/Õõ:Q n. °R%%18ŠbÃáÂÛ5œ$x“”.Ù,VÖ«´»ï#02OשOý©Gè­Å†êÂ*žk#òsYš«E\^g;#7*¬–퀛ýM¾‹ŒåxfÅ @c[tZâgúzr¯|õ™ÊәΌTæ7R`bHw·1?½Aè€nó)V]Þ­¢´ Þ(›yÐ)GJýð²,?³­òuüƒ÷„§ÿì •Wvíö(—›hc°Ý§Rj ªMZº{yç%JÕ$µ¥¿Qˆ£Q?ºª±1¯gü¶Š¸-ëª0ÐG_:óØþ¨ÅIŲ>_UŽJòÀz¾B.nk“£+,.ƒïÿïÎL+ÔXA1™7—ÿÞ¢í ×Jñ‘SO†ÿôÔ¡Æ~ÏA¦‡cåjˆcH·*VòmÄhZ:¦ÇŠ8!¸‰3ɦrÅRè¿§YoÄ\ÎÛYÈ4¤ýáç¼oýÓ•ã29Á¦e† ¾&*”'tX_©PXI§ÁO“ÐGå #ye†çåZB‰mk%2èþ?ú|ô_z¼ñ„Ä"Ó òP® JCK'Œ ÆdChFÐvWÈÒìNÂß· ´± •zõ:à'Iö«Û îs_ÿ¬÷ï_z¼qÂÑÈBU¬¢r-H·ÀÐ0x¸Ú¦X™ KŽ'1{?ÇCRõö˜¦\—·€7¹[Ýüÿ¼È*TIè}æþàåÓŸˆ¿q|½³!“K0<O?l9ìhh4a~:Í<â Têà8 bÊ?@-¯).›‰$økïî¯ )íé’ø¾ü¼þÛSÇk·fÑCýø<<24"èì„‹W¡³ÝR%Ȧ Q±ï=š pcˆ)X$*×åmà-`ù—ÅóQ)k€n×®9¸¯ÛýS'Ìï>¶¯æ×#¤ZƒiÔkáà^èß•d2_…ÑI8yÂÒI ¸6ûÄ€+PŠàÚŒš¹ Üj)yK¡ÕHYÁÙ©]oïÓÍcõ™§ôðàžz6íCÓ «Ô›Wá­Èùð@½a¹îûð“ó 5øž¥ÊžÍ|×>‘XÀq!##+Úä7Ìuà°úA vß“mUußÉ£Î_dSfǾ½§=dçý½õ %”ÐÓ8JÙÌÅ —n Î\¹U¨”áô‹ºȵÀà$,,ÃÞ^›éÍúo ¤\P.’4nÚA¤ \ƶ¶ ·@ ýk'Õ7¿öLó+Ž‘DÑ‚ÒÚÞlb^»Šº|r¨×áÑûà‘ƒÐlZ‘®áêx.„ÍŽ$\¬7!ZW2b©ƒ‚zC1¼ fë@áv4¹€Û×í½ðì‘èËÍšÊò5ðÁ÷Qk%›‚Ÿ ÀtÞ>òžˆš°; ¿ý¼å1€ãÁõá$8ϾßÚWk°#é”kàið@näeL4Lmí8o€uÿ+Ÿÿþ`·db]­Ò€‘I¸2 ã³à¥ —†îN qŠ1|ñ$´¥lfs9˜]†ü:¤Bû8NÀ%½NllWº£1ÔßCmT ÀR’}óa¸;[õËÍØÜõƬ¬ÁÒ ,¬XµµÂ¡ýöŠÍ†¥L3¶æ|ìí¶–éº6»ÃÓÖMlÏõJÂscõã(ûY.%«WA©,ë·ªº·¬ÄŽF/®ÇgÿòßÔ¡0 ÕÙÇÀñû`—u…åtàC¶,<õ€ Laérc Šå„J®õÀ¥UËI«¡Õ‡ï‚vÁ8IÑŠ?€ØP^/ÖÍßýtXÝlÉ(zº0mB¡9ÉÔ2A8q:²–¾+E˜Y°KÂ8²k ˜)ØÀ7)›ŽQ*AW¤”µÚlh6cR @r,?[”¿ùóïredVI@:c¹ïy¶0Q»Úáà.Û˜9Ú¦ìÆ8D dƒÄ°¼7§ ÜH¬ÔØÿ¡ \åÀ]h¤{‡h½Õîv¦ÓåÄF.4šj÷½=*H§e[]å ´„ðôC6 Ø@*“K05Ú‰l&†wÇ`©÷톾n ~3½ÚJÅÖ ÏAÅüà‚.€œ½Õ,ôvÆë`žÈ³>0£öçB×U«˜\uy{\п[p5²^E]²Ž#14Í´Æ£QWg>uLð4"b1(Û[Q­CBO«ðöÍÀ_XΣ·£…[í4E`¬Tcâò„Dç‡Ìê¥q™œ3C kæÜ™ë’¿6éÜ}´O¼‘ deÍ'õCi¨E0<‡Zk¨ÆÍ‚¹œ/:]Ïö‹cÄ‚ä{ ¨Õ ›Aúz$ýýsNÌ•÷[}˜ Ö’’~xx x8\˜_UoêÛR¢MDé_dÖÑP®!£s0We(~4¿¢Ê÷ö¨ûîée¶ˆY)K§j ÕŠ3¶¨Û&—ÍõäÞñ¯ºCSO>L'ç0'07œ‰yäÒŠd6 (QHW&+Mç‘•²L% ªÛ¹ÍZOÄ>ü,YU µ÷¡Þ"Èäù!Õ^k¸•ˆ^\CÜ$~£A J@v·“¾>K§ØñÊÂV=lÇ>±$YZNDÞü€Z338#Áòš>ГWÄ68›.×A]šrX.ÉætnæŽoto9"`ÑSKEMk‹$ÆžI\IÕšŠ‹“f42|/©?¥€Ÿƒ™˜*]jè½=92ÚŽÚÕH^Å3«¼|/¡¦|Ül:Y]«H©9ý{Ú$ ¼3­§êMùàÕ¤Ùäã`+ˆéµŠTÖ#ïÈF gº`Þ¾›üÜ@>.¿•ø€á»>Îÿ™Ô~lÆå%köè—M(þˆxÞ“j!èIEND®B`‚stella-3.9.3/src/common/SharedPtr.hxx0000644000175000001440000001573012266336753017126 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SharedPtr.hxx 2838 2014-01-17 23:34:03Z stephena $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #ifndef SHARED_PTR_HXX #define SHARED_PTR_HXX #include namespace Common { class SharedPtrDeletionInternal { public: virtual ~SharedPtrDeletionInternal() {} }; template class SharedPtrDeletionImpl : public SharedPtrDeletionInternal { public: SharedPtrDeletionImpl(T *ptr) : _ptr(ptr) {} ~SharedPtrDeletionImpl() { // Checks if the supplied type is not just a plain // forward definition, taken from boost::checked_delete // This makes the user really aware what he tries to do // when using this with an incomplete type. typedef char completeCheck[sizeof(T) ? 1 : -1]; (void)sizeof(completeCheck); delete _ptr; } private: T *_ptr; }; template class SharedPtrDeletionDeleterImpl : public SharedPtrDeletionInternal { public: SharedPtrDeletionDeleterImpl(T *ptr, D d) : _ptr(ptr), _deleter(d) {} ~SharedPtrDeletionDeleterImpl() { _deleter(_ptr); } private: T *_ptr; D _deleter; }; /** * A simple shared pointer implementation modelled after boost. * * This object keeps track of the assigned pointer and automatically * frees it when no more SharedPtr references to it exist. * * To achieve that the object implements an internal reference counting. * Thus you should try to avoid using the plain pointer after assigning * it to a SharedPtr object for the first time. If you still use the * plain pointer be sure you do not delete it on your own. You may also * not use the plain pointer to create a new SharedPtr object, since that * would result in a double deletion of the pointer sooner or later. * * Example creation: * Common::SharedPtr pointer(new int(1)); * would create a pointer to int. Later on usage via *pointer is the same * as for a normal pointer. If you need to access the plain pointer value * itself later on use the get method. The class also supplies a operator * ->, which does the same as the -> operator on a normal pointer. * * Be sure you are using new to initialize the pointer you want to manage. * If you do not use new for allocating, you have to supply a deleter as * second parameter when creating a SharedPtr object. The deleter has to * implement operator() which takes the pointer it should free as argument. * * Note that you have to specify the type itself not the pointer type as * template parameter. * * When creating a SharedPtr object from a normal pointer you need a real * definition of the type you want SharedPtr to manage, a simple forward * definition is not enough. * * The class has implicit upcast support, so if you got a class B derived * from class A, you can assign a pointer to B without any problems to a * SharedPtr object with template parameter A. The very same applies to * assignment of a SharedPtr object to a SharedPtr object. * * There are also operators != and == to compare two SharedPtr objects * with compatible pointers. Comparison between a SharedPtr object and * a plain pointer is only possible via SharedPtr::get. */ template class SharedPtr { #if !((__GNUC__ == 2) && (__GNUC_MINOR__ >= 95)) template friend class SharedPtr; #endif public: typedef int RefValue; typedef T ValueType; typedef T *Pointer; SharedPtr() : _refCount(0), _deletion(0), _pointer(0) {} template explicit SharedPtr(T2 *p) : _refCount(new RefValue(1)), _deletion(new SharedPtrDeletionImpl(p)), _pointer(p) {} template SharedPtr(T2 *p, D d) : _refCount(new RefValue(1)), _deletion(new SharedPtrDeletionDeleterImpl(p, d)), _pointer(p) {} SharedPtr(const SharedPtr &r) : _refCount(r._refCount), _deletion(r._deletion), _pointer(r._pointer) { if (_refCount) ++(*_refCount); } template SharedPtr(const SharedPtr &r) : _refCount(r._refCount), _deletion(r._deletion), _pointer(r._pointer) { if (_refCount) ++(*_refCount); } ~SharedPtr() { decRef(); } SharedPtr &operator =(const SharedPtr &r) { if (r._refCount) ++(*r._refCount); decRef(); _refCount = r._refCount; _deletion = r._deletion; _pointer = r._pointer; return *this; } template SharedPtr &operator =(const SharedPtr &r) { if (r._refCount) ++(*r._refCount); decRef(); _refCount = r._refCount; _deletion = r._deletion; _pointer = r._pointer; return *this; } ValueType &operator *() const { assert(_pointer); return *_pointer; } Pointer operator ->() const { assert(_pointer); return _pointer; } /** * Returns the plain pointer value. Be sure you know what you * do if you are continuing to use that pointer. * * @return the pointer the SharedPtr object manages */ Pointer get() const { return _pointer; } /** * Implicit conversion operator to bool for convenience, to make * checks like "if (sharedPtr) ..." possible. */ operator bool() const { return _pointer != 0; } /** * Checks if the SharedPtr object is the only object refering * to the assigned pointer. This should just be used for * debugging purposes. */ bool unique() const { return refCount() == 1; } /** * Returns the number of references to the assigned pointer. * This should just be used for debugging purposes. */ RefValue refCount() const { return _refCount ? *_refCount : 0; } #if !((__GNUC__ == 2) && (__GNUC_MINOR__ >= 95)) private: #endif void decRef() { if (_refCount) { --(*_refCount); if (!*_refCount) { delete _refCount; delete _deletion; _deletion = 0; _refCount = 0; _pointer = 0; } } } RefValue *_refCount; SharedPtrDeletionInternal *_deletion; T *_pointer; }; } // end of namespace Common template bool operator ==(const Common::SharedPtr &l, const Common::SharedPtr &r) { return l.get() == r.get(); } template bool operator !=(const Common::SharedPtr &l, const Common::SharedPtr &r) { return l.get() != r.get(); } #endif stella-3.9.3/src/common/FSNodeZIP.cxx0000644000175000001440000001140612266336753016722 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FSNodeZIP.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "OSystem.hxx" #include "FSNodeFactory.hxx" #include "FSNodeZIP.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNodeZIP::FilesystemNodeZIP() { // We need a name, else the node is invalid _path = _shortPath = _virtualFile = ""; _error = ZIPERR_NOT_A_FILE; _numFiles = 0; AbstractFSNode* tmp = 0; _realNode = Common::SharedPtr(tmp); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNodeZIP::FilesystemNodeZIP(const string& p) { _path = _shortPath = _virtualFile = ""; _error = ZIPERR_NOT_A_FILE; // 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 = OSystem::zip(_zipFile); _numFiles = zip.romFiles(); if(_numFiles == 0) { _error = ZIPERR_NO_ROMS; return; } // We always need a virtual file // Either one is given, or we use the first one if(pos+5 < p.length()) _virtualFile = p.substr(pos+5); else if(_numFiles == 1) { bool found = false; while(zip.hasNext() && !found) { const std::string& file = zip.next(); if(BSPF_endsWithIgnoreCase(file, ".a26") || BSPF_endsWithIgnoreCase(file, ".bin") || BSPF_endsWithIgnoreCase(file, ".rom")) { _virtualFile = file; found = true; } } if(!found) return; } AbstractFSNode* tmp = FilesystemNodeFactory::create(_zipFile, FilesystemNodeFactory::SYSTEM); _realNode = Common::SharedPtr(tmp); setFlags(_zipFile, _virtualFile, _realNode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNodeZIP::FilesystemNodeZIP(const string& zipfile, const string& virtualfile, Common::SharedPtr realnode) { setFlags(zipfile, virtualfile, realnode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FilesystemNodeZIP::setFlags(const string& zipfile, const string& virtualfile, Common::SharedPtr realnode) { _zipFile = zipfile; _virtualFile = virtualfile; _realNode = realnode; _path = _realNode->getPath(); _shortPath = _realNode->getShortPath(); // Is a file component present? if(_virtualFile.size() != 0) { _path += ("/" + _virtualFile); _shortPath += ("/" + _virtualFile); _numFiles = 1; } _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; ZipHandler& zip = OSystem::zip(_zipFile); while(zip.hasNext()) { FilesystemNodeZIP entry(_path, zip.next(), _realNode); myList.push_back(new FilesystemNodeZIP(entry)); } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 FilesystemNodeZIP::read(uInt8*& image) const { switch(_error) { case ZIPERR_NONE: break; case ZIPERR_NOT_A_FILE: throw "ZIP file contains errors/not found"; case ZIPERR_NOT_READABLE: throw "ZIP file not readable"; case ZIPERR_NO_ROMS: throw "ZIP file doesn't contain any ROMs"; } ZipHandler& zip = OSystem::zip(_zipFile); bool found = false; while(zip.hasNext() && !found) found = zip.next() == _virtualFile; return found ? zip.decompress(image) : 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AbstractFSNode* FilesystemNodeZIP::getParent() const { return _realNode ? _realNode->getParent() : 0; } stella-3.9.3/src/common/stella-64x64.png0000644000175000001440000001150111676222762017252 0ustar stephenusers‰PNG  IHDR@@ªiqÞsRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÛ -98ÌjÁIDATxÚí›il\×uÇ÷m³pî‹$’’,˲eÙ–lËqb;¶Ó8±Ó¸iÀmƒ6nZ$h“6H‘´(P EŠ$- 4]>uA?ôKû-º!)²ÈNäM¶$J")qßwÎp83œyïÝ{ûáÞ1i—ÞmYvû€ÁP3CÎ;ÿó?çüÏ9Wðüï{tÏÞ«äŽ÷ôŽÇû€èïVˆSÀ*P±€(ûsˆìç] JÀæËÀÚõò®qÏw}ìŽÌßýɧË=øþO–‹­Aµ¾¿CçVÖE¸D~ãÙa9¿¼TY¼÷ˆº.õ½ýipep¼òOÀsÀâk±ãZ 9›Íþw*}ÜkI’È6ñÐ •æ¦ DôuéTö†Ã¹»Î<×××mGÓ×5}ããÀ–eBåµP¾¯ˆã_ùXýëû÷ôgiø‰¢:¨ò2yñ‚„&ÜZÚXY©37º©íqîö½–×".ÐóèÝùoÿÊjùdïõ¢¾•Å®oÓžÙÞY§£Âšû0=<Ê•Qð|ð”Ö÷Ç{ƒ€ÿ^ âÄo>PýrO—ÖM½ÇX"“2o†šö1;1M…àå|âØçé' „18ÄqÛ)Z›ÜG€[ŽWªxÎ5Fý½÷Ëÿñcwn5‡íûÄÜô8Ô$B›¸Oµ%AŽòÜ:ù Èšûnfàù –ÖÀ÷Œ•Ž€ºDöN7ék€æLSîs¿ÿ‰Ò=2h×OR›[#€Öæ‘éÜËøù!ZšMåÏö·±¶´Â¥Á×! F8 ZRßwƒû àC@ÿnUϹv¨ïÞñÕO„_ÛÓ¢tжG¬Œ’o2ªFFÐÒßÁúê&~,Iøà4¹8™NÎ<9ËFbm - Vˆ»ÈDÒw~¸È_‹8@÷½·äþèS'jyo§(o–hÒÆ("ð3àdÛYZ¡% qm×÷2r~”Ë pµðÞÞžûÖ¯~¨Üª=ðý: Wª$&†ãÚzf¦‹¸@:€8†¶þ97Êf ü8Vý¯Kƒ pQ4¼?øJm±sµ?Ü—ÿ³¯ÿüæ}‘D'0~I‘ôAjSâÒYˆ´`eZÒ‘…zùÞ|6Xœq¬:l¤{±ÃøÀ…©‚#Æ–Õ40 œVÞífÈöôwg¾ù—o~º%£µVˆ™<ÇX¡4ïI0;R§­¤}-ÓÓÉüàëUÈ4™Ž/H‚»ƒóyé¢ÿí,Ò&¾A›ýÃwè=¸7÷çûxås¥µD¬” \6Im²~®–WCª%Lßâ@\fbRá8&Ö}\w»–*mþ†ïÂS£B+ê‚Íúç€õwsúíÍ|û¯ß|¬#¯u!ÖJ0»Ýmææ5JC†+—4Ýfð)hëÊRYZfc’®‰}Ç?‰ô6ý¥©O‰2pxÁz?~·È·}ð¦Ìß÷ñêcí­¥DlÕa`z: aå®’o‡K— ðÁsÍëž³Áüd„²r×±<\< Iž™p‰buÞÆþ…ÝÊÞÕŠúZ5Þ¿øpðÝ/ÜWî× c‰¨ÅpfÈÐ~_D¡‰ñ\¶j05 Ço)¡1¬-(c5 \Žù, ÊuÁS#jÃRÿ<°ðzöÞ;àõû:Ó_ýú£áç?p¨êÖ# [pî2‹p÷- csw®¹<üø445AS`2¿š’ ªP©YÍo%Ÿ¯¡fë½çA¢ þýY©äs6ñ Û}Wa›šVð?ôËö¿õø½ÕëšèHšx]Û€çGàì|êHxKãÑ®v˜žƒ©Y¸ç$ÄVÐ+™‡Fûîv½SêÚ„ÑZI00£V!ëý¥×»-z+vÌÔ ÞíwI|é×î­?p¢¿êÔcˆ$ÂÑ0³ç¯À™a8y ŽöC½nÊW*mfüÏœ7¥0Ÿ¶”†ÖŽ [±¡:ÂÞ¬góC ®0¡ñ£!€` CÞ.CÏ>’@8”J¦zàfõð'OÈc·öU„Tè­ÐÐ2Rpvfaà"ôuÀGï´Ô·Mi> Ï^„¹¸®ÏP:Ž·=í¨‡ÆP?€ZÍ =ƒêÒx TpnR¬÷/¾šèy#ëÝ ÉR|xýÍYÿÀáxèVy䮃[éμ‰Ù­\$`½Ï^ó£06i´ý£BÖ7ŸÓòyX)b&:Z[_*jÛí­ãƒPÆÛqlГ_œu‰c94µ· €€ŒÆýð#w8ßqQa—ÓÑ™ûr -nÞ·E&2F‡6kÆS‰Âž¹?€ÅTCÓ=7ôojÛ§û ¸0•²ñ|k”zià* iÛ!ºÞö¬/ AÛõè©!0j_{£q¼†#øiñžˆºë1h%ͤE˜-WͨÉqŒb‹+³ðÄ œ0tͦ \ƒþVxä>“Ȥ2`µ´ÀàŒU'¥Íø¶¾7XP—ϘD‡v¢ HA­jþ=»Î:0m»½ê[À:n;|ãáãa÷zÕÐe¤fÂ5Ôxf {aN¿£sjhk‡têH øäÏA[j¡1.HÂJ'ÌàC¸æ;׎¿w 4jUèÈ™Ð)"„” µ’ -ÔÂpÑn—yëðW@òédâ±oüBôÙZˆö¢ÁÉ„g¨«XÝ€áxa¦'ŒQ-=÷ ª×#øÐmpü9ŽÝ%00aŒÈäÒ‚ámK[! ŠØO'LÉÛŠÍÜ?¡Ìóꦘ·e¯ôfJÙNRZsû7‹þôºv¥+Ï”§Z 5¸2 ƒã05g²og;ÜxÄ0"¬=žöLì6åá¡»MC£CK+Ì.Áâ²Éä`¨Õ.¼—ε´€zšÛ \€znhæº 3Ý«Å7šüv Û×î¹%¥ÏNú­nÀjæVa³jn(ŸƒÃ×CÎÒZÆ&)!À A:€ûï€\Ò§¤RP­šPžilêu“Ü E€VvÿigÛŽëeØÓË ÐäBÙ3C“´¥²l°õò™è› ˜^.~í½‡=5…ð\“Ýû:!„„c¼\UV±Ù¤æàHsˆ¥R†›÷Ãm‡!´]¸ëB" ÓP²[©Œ^ÐʹCF¿´9@µf6Àmí°¼b~ד |"À¼Køv°œÚ¨Å݃Eï7¾ô`¬+"ŠŒ§¤4¬ÐR¶4xvZÖmc. -÷7JM*ˉ„aÓÄ¢¹Ý”ÍŽkØ^X‡•uèÉo—J×þ=×åeèíƒ È„°é›ßs\Õ˜ó«7+gw¶Ã>ú{ÏÅÿüWÿåJ/9ž‘£n–"m´¸°ÕÁO ·†\ "iZàƒÀø T+VÌ„L£ú0>gŒÎKg}Ž0 s£]ç@˜Ïµ4ia¡wßÊrbçUÃTœÒJIWO ;t‹Tw^ëJ@ ‰#Lí‰#hk‚“7šŒ®Å¶÷§áÊ„5Ð~£R¦ÁY+ÃÀe£N³õ^lÏ„0¹ \1úA24ÚciÓã™ËjÜN~fÞLÜ ¹æ8ÚšTzá©Ýå:nÇѽZK¸ÆÓŽc…G¡àþöÍëH&¡›Ê±e£RÆÃŽaxÚЫ 8©„y½Q~Û‰a@èé6a"#ج{üp@.Ú™ÿÄ«ÍþÞÚ‚°b˜¿² ¹4ãôß}/•ØîÍ=»œH7_{LeÀzÍõ`dæ–Ì¢BØý•Š`+2ß46kÂ¥\…Þ.8Ømò°†km@hœ’¬” a 2 É÷j¡";cŸµ“—a;„¸dŸ¯Ø÷6‡æÔ~ß÷zõ(]«"„Øne]K+×…ÒÌ/ÃxI¯?ž=>µ–ºëÁc‘Ÿ L(°c ô",aÑäÅî¼à¤@Zl½4œZFTØ>¬\³¯7)¯\žSùRèößyƒ¦VEè;,ÓT7apÉ¡é³À“À€•B9Êk»ç¨ÔR"¢Û+1á 6k04….V’=Kñ²`íµöo€×ЦÕ+óëZά;7íC¸ÚŠ#{ŠËu`~ÎÏQÒÆûOØ‘Ö/ú7쇺Q´£KtlNÑæoŒÍÂÀÄž¶X”ÂôáB9Z±ß_|= ¼Ý`e馭ëk›ºôÔˆØwËõdZP ¾k4ÀôÃÖû?³y¦Ô•Œ+§†Gíñr×÷Ä„ñ6„•È…*œ¹lFk2†¾–8Yˆr'K•zaÑÕ BÅ´¢5 gFEžÓÚß*ð…ÆõÑÿyÁ‰ë±>üÔnrêrT¥Œ7..dOÜ}C”lÏhbeÎ8&Ÿ ÎÀ¥Q»\µƒ›íQP¨çî,Uë[½ ¯¦ß)^^=V5ÌM®èè™qÑR ÌZÅÃójÒRÿI;ØÐ/+¿ÕÍJ-<}%}ÛÉë¥ß™ÕÄ–úKð ”*vŽ A9 bÍÎØ_,§®«Ô¢›J¯Ô0½“ì¬óJëñ…¢^žXÖëÀ³Ài»Ì¨îò{% ²Y*ß?ï½õ  öwµy~ ƦAàÆfUæ*.köwªÜäª{$’jÚ ¤Ònåñj°Ó£ó¶VOîØá{Wo4ga¤Šÿ}Þ½éH©Tž¹hät`+ŠÀïIûkwë–Ë ¢]™½°›HºZ4B¢nÓÛÇÖ ¯ÑÏ×,7b©7~:ÜÜ™wREeFmŽñ¼vì±™ÏR»\œWØü2º[¯p5Ø DluCô:U[ƒ å0–ÅÓ—Ùßœrò-i­…Bh»9n,Tà¸è;ªê',Ó†wHïoö -Ð e¿¿¿ÃkOùRKmÕñή1tÅÙ9¶#ÉNíÆ´÷;;Ô‚”rmd…ýJ‹Ž}y­•6°g‡õé ¡7kúI Às¯Ô*¿×À†Ï°¡•^Z*‘`oZéH \ ÅØ/L©ikü¯äý÷*ªRl°a±¨2A"q]OZjáÀéq¡Ë5}ʪË3V™ò~`gi-Åù¢L†NâP]i18§f¬çb+z?Ðù²mÓ×VK2œ^Ó¡W§íœbóµ?¼.èÄü·˜}sv>óÿ×+_ÿU{µ“Å1M;IEND®B`‚stella-3.9.3/src/common/MouseControl.hxx0000644000175000001440000000633612266336753017665 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: MouseControl.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef MOUSE_CONTROL_HXX #define MOUSE_CONTROL_HXX class Console; class Properties; #include "bspf.hxx" #include "Array.hxx" #include "Control.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); /** Destructor */ virtual ~MouseControl(); public: /** 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 xtype, int xid, Controller::Type ytype, int yid, const string& msg) : xtype(xtype), ytype(ytype), xid(xid), yid(yid), 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; Common::Array myModeList; }; #endif stella-3.9.3/src/common/module.mk0000644000175000001440000000067612175044631016310 0ustar stephenusersMODULE := src/common MODULE_OBJS := \ src/common/mainSDL.o \ src/common/Base.o \ src/common/SoundSDL.o \ src/common/FrameBufferSoft.o \ src/common/FrameBufferGL.o \ src/common/FBSurfaceGL.o \ src/common/FBSurfaceTIA.o \ src/common/FSNodeZIP.o \ src/common/PNGLibrary.o \ src/common/MouseControl.o \ src/common/RectList.o \ src/common/ZipHandler.o MODULE_DIRS += \ src/common # Include common rules include $(srcdir)/common.rules stella-3.9.3/src/common/Version.hxx0000644000175000001440000000160712266336753016655 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Version.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef VERSION_HXX #define VERSION_HXX #include #define STELLA_VERSION "3.9.3" #define STELLA_BUILD atoi("$Rev: 2838 $" + 6) #endif stella-3.9.3/src/common/MouseControl.cxx0000644000175000001440000001656512266336753017665 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: MouseControl.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Console.hxx" #include "Control.hxx" #include "Props.hxx" #include "MouseControl.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MouseControl::MouseControl(Console& console, const string& mode) : myProps(console.properties()), myLeftController(console.controller(Controller::Left)), myRightController(console.controller(Controller::Right)), myCurrentModeNum(0) { if(BSPF_equalsIgnoreCase(mode, "none")) { myModeList.push_back(MouseMode("Mouse input is disabled")); return; } else if(!BSPF_equalsIgnoreCase(mode, "auto") && mode.length() == 2 && mode[0] >= '0' && mode[0] <= '8' && mode[1] >= '0' && mode[1] <= '8') { Axis xaxis = (Axis) ((int)mode[0] - '0'); Axis yaxis = (Axis) ((int)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; default: 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; default: 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); } // 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(unsigned int i = 0; i < myModeList.size(); ++i) cerr << myModeList[i] << endl; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MouseControl::~MouseControl() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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-3.9.3/src/common/FBSurfaceGL.hxx0000644000175000001440000000512312266336753017250 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FBSurfaceGL.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef FB_SURFACE_GL_HXX #define FB_SURFACE_GL_HXX #ifdef DISPLAY_OPENGL #include "bspf.hxx" #include "FrameBuffer.hxx" #include "FrameBufferGL.hxx" /** A surface suitable for OpenGL rendering mode, used for various UI dialogs. This class extends FrameBuffer::FBSurface. @author Stephen Anthony */ class FBSurfaceGL : public FBSurface { friend class FrameBufferGL; public: FBSurfaceGL(FrameBufferGL& buffer, uInt32 width, uInt32 height); virtual ~FBSurfaceGL(); // Normal surfaces need all drawing primitives void hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color); void vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color); void fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color); void drawChar(const GUI::Font& font, uInt8 c, uInt32 x, uInt32 y, uInt32 color); void drawBitmap(uInt32* bitmap, uInt32 x, uInt32 y, uInt32 color, uInt32 h = 8); void drawPixels(uInt32* data, uInt32 x, uInt32 y, uInt32 numpixels); void drawSurface(const FBSurface* surface, uInt32 x, uInt32 y); void addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h); void getPos(uInt32& x, uInt32& y) const; void setPos(uInt32 x, uInt32 y); uInt32 getWidth() const { return myImageW; } uInt32 getHeight() const { return myImageH; } void setWidth(uInt32 w); void setHeight(uInt32 h); void translateCoords(Int32& x, Int32& y) const; void update(); void free(); void reload(); private: void updateCoords(); private: FrameBufferGL& myFB; const FrameBufferGL::GLpointers& myGL; SDL_Surface* myTexture; GLuint myTexID, myVBOID; GLsizei myTexWidth; GLsizei myTexHeight; GLuint myImageX, myImageY, myImageW, myImageH; GLfloat myTexCoordW, myTexCoordH; GLfloat myCoord[16]; bool mySurfaceIsDirty; uInt32 myPitch; }; #endif // DISPLAY_OPENGL #endif stella-3.9.3/src/common/SoundNull.hxx0000644000175000001440000001161412266336753017152 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SoundNull.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef SOUND_NULL_HXX #define SOUND_NULL_HXX class OSystem; #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 @version $Id: SoundNull.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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(); public: /** Enables/disables the sound subsystem. @param enable Either true or false, to enable or disable the sound system @return Whether the sound system was enabled or disabled */ void setEnabled(bool enable) { } /** The system cycle counter is being adjusting by the specified amount. Any members using the system cycle counter should be adjusted as needed. @param amount The amount the cycle counter is being adjusted by */ void adjustCycleCounter(Int32 amount) { } /** Sets the number of channels (mono or stereo sound). @param channels The number of channels */ void setChannels(uInt32 channels) { } /** 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) { } /** Initializes the sound device. This must be called before any calls are made to derived methods. */ void open() { } /** Should be called to close the sound device. Once called the sound device can be started again using the initialize method. */ void close() { } /** 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) { } /** Reset the sound device. */ void reset() { } /** 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, Int32 cycle) { } /** 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) { } /** 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) { } 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 { out.putString("TIASound"); for(int = 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) { if(in.getString() != "TIASound") return false; // Read sound registers and discard for(int = 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 { return "TIASound"; } }; #endif stella-3.9.3/src/common/stella-24x24.png0000644000175000001440000000230211676222762017241 0ustar stephenusers‰PNG  IHDRàw=øsRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÛ  Ÿ^]BIDATHǵ”[lTU†¿uΙ3éL[¦´¥I)ű–‹Å¢†Û‹B‚††_ÔÄHäI£‰1˜ø¤O$’&D / b ‚¡€ŠA 7°7¦÷™^æt.göò¡6Á Uüwöþ¿½Ö¿÷þƒšžwJƒaÇ"—õ/tع²ˆ¯—:&«³{œùš®y²‚Ÿo Á対8ikVá¢Ìæú‰±øT$ÛÖ7õ^2Åoÿ0c^é~±øËå¯0ãiÒøT»¤®åYÁK¦h|k>æª ^~{E]lmzhHý@˜@Þc8åN—ÇÆeìšfÏÌ "ÔÕk76¼k&Ží:brìhçÎŽ€ÆÂÊËõÖÇ@ͼM8²¤,_)¹&Äu„s?M1QDŸ& Äæ ع®àƒtkÎËh°$ÄtÒc iÑ÷±,T,J çÛÍ7Àïó yÏ&w÷ë›3Óž¨…‘©‰ ¡PöNP ¨ÂéÜ™‡®`u­»uÏúÜQ/¥®É²¬œÁ‰H&\iGÏ\…T ÞÙ„BÐr‚.d³° ‰ 4™éРn›÷•óáÀ¥·{ѱ)$ž€T ‰¶g ª úF m@Èç!o ¤ CH÷ˆ\¿_ލü¢¶v âg1>º ÊÂÕPÿä tõÍÜ~xRé™öxÓPV–-Þ?0ã͇NqàzŸŒFŠP ,XY ¡ ܉ÃèøY¸Õñ0f¦’P­)@Ý`ÏÎ1àòõ^.xY)öÄt J?¶èÂÑkm(Šdsè•NÔ3xkjqUÁ¤2¦t¬Î¸91;EçfÕÛ?Æ·w†8ÞŸàXk­SiÙ¾¸„Âlõ òc‡ô\þÃ:¼¥Ncì¼A(tµâÔ/ö5жøë‹OS@gçS>U1ÊG¦àrÇ@?ºÔå.ÙR§«Ã®’óÑÓ­]Ç®š” y£ÌUo<ÉwC“âô&ÄOz| ôLzù³NÍÊÅæ©[ÝÈí~4V¨eÁÏõ'µeöÃÙ9ëIï“'má¶Îd–‰™–›w튜Ǫ€¸6‹Ú‡ZxD*ŠEGw`X¡â°\[-žkóYÕþ8÷.þ "èᄃ·IEND®B`‚stella-3.9.3/src/common/stella.xpm0000644000175000001440000000235010702307370016467 0ustar stephenusers/* XPM */ static const char * stella_icon[] = { "32 32 3 1", " c None", ". c #000000", "+ c #FFFFFF", " ", " ", " ", " ", " .............. ", " .............. ", " ..++..++..++.. ", " ..++..++..++.. ", " ..++..++..++.. ", " ..++..++..++.. ", " ..++..++..++.. ", " ..++..++..++.. ", " ..++..++..++.. ", " ..++..++..++.. ", " ....++..++..++.... ", " ....++..++..++.... ", " ....++++..++..++++.... ", " ....++++..++..++++.... ", " ..++++....++....++++.. ", " ..++++....++....++++.. ", " ......++......++......++...... ", " ......++......++......++...... ", " ..++++++.. ..++.. ..++++++.. ", " ..++++++.. ..++.. ..++++++.. ", " ..++++.... ..++.. ....++++.. ", " ..++++.... ..++.. ....++++.. ", " ........ ...... ........ ", " ........ ...... ........ ", " ", " ", " ", " "}; stella-3.9.3/src/common/FrameBufferSoft.hxx0000644000175000001440000001557412266336753020260 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FrameBufferSoft.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef FRAMEBUFFER_SOFT_HXX #define FRAMEBUFFER_SOFT_HXX #include class OSystem; class RectList; #include "bspf.hxx" #include "FrameBuffer.hxx" /** This class implements an SDL software framebuffer. @author Stephen Anthony @version $Id: FrameBufferSoft.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class FrameBufferSoft : public FrameBuffer { friend class FBSurfaceSoft; public: /** Creates a new software framebuffer */ FrameBufferSoft(OSystem* osystem); /** Destructor */ virtual ~FrameBufferSoft(); ////////////////////////////////////////////////////////////////////// // The following are derived from public methods in FrameBuffer.hxx ////////////////////////////////////////////////////////////////////// /** Enable/disable phosphor effect. */ void enablePhosphor(bool enable, int blend); /** 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 */ void getRGB(Uint32 pixel, Uint8* r, Uint8* g, Uint8* b) const { SDL_GetRGB(pixel, myScreen->format, 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. */ Uint32 mapRGB(Uint8 r, Uint8 g, Uint8 b) const { return SDL_MapRGB(myScreen->format, r, g, b); } /** This method is called to query the type of the FrameBuffer. */ BufferType type() const { return kSoftBuffer; } /** This method is called to get the specified scanline data. @param row The row we are looking for @param data The actual pixel data (in bytes) */ void scanline(uInt32 row, uInt8* data) const; protected: ////////////////////////////////////////////////////////////////////// // The following are derived from protected methods in FrameBuffer.hxx ////////////////////////////////////////////////////////////////////// /** This method is called to initialize the video subsystem with the given video mode. Normally, it will also call setVidMode(). @param mode The video mode to use @return False on any errors, else true */ bool initSubsystem(VideoMode& mode); /** This method is called to change to the given video mode. If the mode is successfully changed, 'mode' holds the actual dimensions used. @param mode The video mode to use @return False on any errors (in which case 'mode' is invalid), else true */ bool setVidMode(VideoMode& mode); /** 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(); /** This method is called to create a surface compatible with the one currently in use, but having the given dimensions. @param w The requested width of the new surface. @param h The requested height of the new surface. @param useBase Use the base surface instead of creating a new one */ FBSurface* createSurface(int w, int h, bool useBase = false) const; /** This method should be called anytime the TIA needs to be redrawn to the screen (full indicating that a full redraw is required). */ void drawTIA(bool full); /** This method is called after any drawing is done (per-frame). */ void postFrameUpdate(); /** This method is called to provide information about the FrameBuffer. */ string about() const; private: int myZoomLevel; int myBytesPerPixel; int myBaseOffset; int myPitch; SDL_PixelFormat* myFormat; enum RenderType { kSoftZoom_16, kSoftZoom_24, kSoftZoom_32, kPhosphor_16, kPhosphor_24, kPhosphor_32 }; RenderType myRenderType; // Indicates if the TIA image has been modified bool myTiaDirty; // Indicates if we're in a purely UI mode bool myInUIMode; // Used in the dirty update of rectangles in non-TIA modes RectList* myRectList; }; /** A surface suitable for software rendering mode. @author Stephen Anthony @version $Id: FrameBufferSoft.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class FBSurfaceSoft : public FBSurface { public: FBSurfaceSoft(const FrameBufferSoft& buffer, SDL_Surface* surface, uInt32 w, uInt32 h, bool isBase); virtual ~FBSurfaceSoft(); void hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color); void vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color); void fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color); void drawChar(const GUI::Font& font, uInt8 c, uInt32 x, uInt32 y, uInt32 color); void drawBitmap(uInt32* bitmap, uInt32 x, uInt32 y, uInt32 color, uInt32 h = 8); void drawPixels(uInt32* data, uInt32 x, uInt32 y, uInt32 numpixels); void drawSurface(const FBSurface* surface, uInt32 x, uInt32 y); void addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h); void getPos(uInt32& x, uInt32& y) const; void setPos(uInt32 x, uInt32 y); uInt32 getWidth() const { return myWidth; } uInt32 getHeight() const { return myHeight; } void setWidth(uInt32 w); void setHeight(uInt32 h); void translateCoords(Int32& x, Int32& y) const; void update(); void free() { } // Not required for software mode void reload(); private: void* getBasePtr(uInt32 x, uInt32 y) { return static_cast(static_cast(mySurface->pixels) + (myYOffset + y) * mySurface->pitch + (myXOffset + x) * mySurface->format->BytesPerPixel); } private: const FrameBufferSoft& myFB; SDL_Surface* mySurface; uInt32 myWidth, myHeight; bool myIsBaseSurface; bool mySurfaceIsDirty; int myPitch; uInt32 myXOrig, myYOrig; uInt32 myXOffset, myYOffset; }; #endif stella-3.9.3/src/common/StellaKeys.hxx0000644000175000001440000001614412266336753017312 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: StellaKeys.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef STELLA_KEYS_HXX #define STELLA_KEYS_HXX #include /** 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. Once the codebase is ported to SDL2, 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_keysym.h typedef enum { /** @name ASCII mapped keysyms * The keyboard syms have been cleverly chosen to map to ASCII */ /*@{*/ KBDK_UNKNOWN = 0, KBDK_FIRST = 0, KBDK_BACKSPACE = 8, KBDK_TAB = 9, KBDK_CLEAR = 12, KBDK_RETURN = 13, KBDK_PAUSE = 19, KBDK_ESCAPE = 27, KBDK_SPACE = 32, KBDK_EXCLAIM = 33, KBDK_QUOTEDBL = 34, KBDK_HASH = 35, KBDK_DOLLAR = 36, KBDK_AMPERSAND = 38, KBDK_QUOTE = 39, KBDK_LEFTPAREN = 40, KBDK_RIGHTPAREN = 41, KBDK_ASTERISK = 42, KBDK_PLUS = 43, KBDK_COMMA = 44, KBDK_MINUS = 45, KBDK_PERIOD = 46, KBDK_SLASH = 47, KBDK_0 = 48, KBDK_1 = 49, KBDK_2 = 50, KBDK_3 = 51, KBDK_4 = 52, KBDK_5 = 53, KBDK_6 = 54, KBDK_7 = 55, KBDK_8 = 56, KBDK_9 = 57, KBDK_COLON = 58, KBDK_SEMICOLON = 59, KBDK_LESS = 60, KBDK_EQUALS = 61, KBDK_GREATER = 62, KBDK_QUESTION = 63, KBDK_AT = 64, /* Skip uppercase letters */ KBDK_LEFTBRACKET = 91, KBDK_BACKSLASH = 92, KBDK_RIGHTBRACKET = 93, KBDK_CARET = 94, KBDK_UNDERSCORE = 95, KBDK_BACKQUOTE = 96, KBDK_a = 97, KBDK_b = 98, KBDK_c = 99, KBDK_d = 100, KBDK_e = 101, KBDK_f = 102, KBDK_g = 103, KBDK_h = 104, KBDK_i = 105, KBDK_j = 106, KBDK_k = 107, KBDK_l = 108, KBDK_m = 109, KBDK_n = 110, KBDK_o = 111, KBDK_p = 112, KBDK_q = 113, KBDK_r = 114, KBDK_s = 115, KBDK_t = 116, KBDK_u = 117, KBDK_v = 118, KBDK_w = 119, KBDK_x = 120, KBDK_y = 121, KBDK_z = 122, KBDK_DELETE = 127, /* End of ASCII mapped keysyms */ /*@}*/ /** @name International keyboard syms */ /*@{*/ KBDK_WORLD_0 = 160, /* 0xA0 */ KBDK_WORLD_1 = 161, KBDK_WORLD_2 = 162, KBDK_WORLD_3 = 163, KBDK_WORLD_4 = 164, KBDK_WORLD_5 = 165, KBDK_WORLD_6 = 166, KBDK_WORLD_7 = 167, KBDK_WORLD_8 = 168, KBDK_WORLD_9 = 169, KBDK_WORLD_10 = 170, KBDK_WORLD_11 = 171, KBDK_WORLD_12 = 172, KBDK_WORLD_13 = 173, KBDK_WORLD_14 = 174, KBDK_WORLD_15 = 175, KBDK_WORLD_16 = 176, KBDK_WORLD_17 = 177, KBDK_WORLD_18 = 178, KBDK_WORLD_19 = 179, KBDK_WORLD_20 = 180, KBDK_WORLD_21 = 181, KBDK_WORLD_22 = 182, KBDK_WORLD_23 = 183, KBDK_WORLD_24 = 184, KBDK_WORLD_25 = 185, KBDK_WORLD_26 = 186, KBDK_WORLD_27 = 187, KBDK_WORLD_28 = 188, KBDK_WORLD_29 = 189, KBDK_WORLD_30 = 190, KBDK_WORLD_31 = 191, KBDK_WORLD_32 = 192, KBDK_WORLD_33 = 193, KBDK_WORLD_34 = 194, KBDK_WORLD_35 = 195, KBDK_WORLD_36 = 196, KBDK_WORLD_37 = 197, KBDK_WORLD_38 = 198, KBDK_WORLD_39 = 199, KBDK_WORLD_40 = 200, KBDK_WORLD_41 = 201, KBDK_WORLD_42 = 202, KBDK_WORLD_43 = 203, KBDK_WORLD_44 = 204, KBDK_WORLD_45 = 205, KBDK_WORLD_46 = 206, KBDK_WORLD_47 = 207, KBDK_WORLD_48 = 208, KBDK_WORLD_49 = 209, KBDK_WORLD_50 = 210, KBDK_WORLD_51 = 211, KBDK_WORLD_52 = 212, KBDK_WORLD_53 = 213, KBDK_WORLD_54 = 214, KBDK_WORLD_55 = 215, KBDK_WORLD_56 = 216, KBDK_WORLD_57 = 217, KBDK_WORLD_58 = 218, KBDK_WORLD_59 = 219, KBDK_WORLD_60 = 220, KBDK_WORLD_61 = 221, KBDK_WORLD_62 = 222, KBDK_WORLD_63 = 223, KBDK_WORLD_64 = 224, KBDK_WORLD_65 = 225, KBDK_WORLD_66 = 226, KBDK_WORLD_67 = 227, KBDK_WORLD_68 = 228, KBDK_WORLD_69 = 229, KBDK_WORLD_70 = 230, KBDK_WORLD_71 = 231, KBDK_WORLD_72 = 232, KBDK_WORLD_73 = 233, KBDK_WORLD_74 = 234, KBDK_WORLD_75 = 235, KBDK_WORLD_76 = 236, KBDK_WORLD_77 = 237, KBDK_WORLD_78 = 238, KBDK_WORLD_79 = 239, KBDK_WORLD_80 = 240, KBDK_WORLD_81 = 241, KBDK_WORLD_82 = 242, KBDK_WORLD_83 = 243, KBDK_WORLD_84 = 244, KBDK_WORLD_85 = 245, KBDK_WORLD_86 = 246, KBDK_WORLD_87 = 247, KBDK_WORLD_88 = 248, KBDK_WORLD_89 = 249, KBDK_WORLD_90 = 250, KBDK_WORLD_91 = 251, KBDK_WORLD_92 = 252, KBDK_WORLD_93 = 253, KBDK_WORLD_94 = 254, KBDK_WORLD_95 = 255, /* 0xFF */ /*@}*/ /** @name Numeric keypad */ /*@{*/ KBDK_KP0 = 256, KBDK_KP1 = 257, KBDK_KP2 = 258, KBDK_KP3 = 259, KBDK_KP4 = 260, KBDK_KP5 = 261, KBDK_KP6 = 262, KBDK_KP7 = 263, KBDK_KP8 = 264, KBDK_KP9 = 265, KBDK_KP_PERIOD = 266, KBDK_KP_DIVIDE = 267, KBDK_KP_MULTIPLY = 268, KBDK_KP_MINUS = 269, KBDK_KP_PLUS = 270, KBDK_KP_ENTER = 271, KBDK_KP_EQUALS = 272, /*@}*/ /** @name Arrows + Home/End pad */ /*@{*/ KBDK_UP = 273, KBDK_DOWN = 274, KBDK_RIGHT = 275, KBDK_LEFT = 276, KBDK_INSERT = 277, KBDK_HOME = 278, KBDK_END = 279, KBDK_PAGEUP = 280, KBDK_PAGEDOWN = 281, /*@}*/ /** @name Function keys */ /*@{*/ KBDK_F1 = 282, KBDK_F2 = 283, KBDK_F3 = 284, KBDK_F4 = 285, KBDK_F5 = 286, KBDK_F6 = 287, KBDK_F7 = 288, KBDK_F8 = 289, KBDK_F9 = 290, KBDK_F10 = 291, KBDK_F11 = 292, KBDK_F12 = 293, KBDK_F13 = 294, KBDK_F14 = 295, KBDK_F15 = 296, /*@}*/ /** @name Key state modifier keys */ /*@{*/ KBDK_NUMLOCK = 300, KBDK_CAPSLOCK = 301, KBDK_SCROLLOCK = 302, KBDK_RSHIFT = 303, KBDK_LSHIFT = 304, KBDK_RCTRL = 305, KBDK_LCTRL = 306, KBDK_RALT = 307, KBDK_LALT = 308, KBDK_RMETA = 309, KBDK_LMETA = 310, KBDK_LSUPER = 311, /**< Left "Windows" key */ KBDK_RSUPER = 312, /**< Right "Windows" key */ KBDK_MODE = 313, /**< "Alt Gr" key */ KBDK_COMPOSE = 314, /**< Multi-key compose key */ /*@}*/ /** @name Miscellaneous function keys */ /*@{*/ KBDK_HELP = 315, KBDK_PRINT = 316, KBDK_SYSREQ = 317, KBDK_BREAK = 318, KBDK_MENU = 319, KBDK_POWER = 320, /**< Power Macintosh power key */ KBDK_EURO = 321, /**< Some european keyboards */ KBDK_UNDO = 322, /**< Atari keyboard has Undo */ /*@}*/ /* Add any other keys here */ KBDK_LAST } StellaKey; // Just pass SDLMod directly as int (placeholder for now) // The underlying code doesn't need to know how it's implemented typedef int StellaMod; #endif /* StellaKeys */ stella-3.9.3/src/common/stella-22x22.png0000644000175000001440000000207611676222762017245 0ustar stephenusers‰PNG  IHDRÄ´l;sRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÛ &DåÕ‹¾IDAT8Ë­ÕKlÔUÇñïùÿÿóf(SZ •hÑ‚ÆG-R_È£Á¨‰ШÑh”•˜¨ 7&nX£1š5D$a£‰èFÁ’"ZS¢4R–´ÐRœÒÒÇt¦ÎëÿÇE!)"U~ÉMÎâÞOî9¹ÉþCâ>¬GÖDªƒšu;|¥¸¯¤ßg`²xa3pmÃ5üÔz†Uõáçž_gè//:þB¢<®Ãï~q°›Í€Èìï®Ùû=qƒø˜R‘“É€îlJìjgÍd‘ãÖ•r¯jë„Ñ š3H6‡Ø6Ü} ÔVÃÈ8ä]0xˆñ¤&ÀS¯ÈÌ„-ð&·ìÕ­©"¥²¹HÜÆ£h, uh ǺÀHOuäyB,Ž#ð.£ÀÖ÷¿cCK—œð…EP‘ÅP5iïEÓiÈçàHƒ1h6U ¨NHHh&lO«»ºØÕÜ9ØKÛíüâXR?9ŽÏ(êäÀI²}i\w+q× ž"±ˆÌßÓ¦­%Cçå`€4Ðìš:ûˆGX]#8Q€ý'iê´Þ¨,³ž\¶HýÆ …‚JwÒ^‘L9{À½|QŠ.‡;ÏÒœÎ˪±œ•èÑ7Aw·÷IײEÖúsÕj>ŠXFçE‚ö½É”~ dÿ>Ÿ¿ÎeØÑ7¢ûýûŒ‡›/jǾcšªNX§úÔQÐXÐ[˜L.¸ìæF‚~Ùpß Væ™;Ðû—áúm^âêEm\*ƒµ•*¸š±,¹Í±h˜þÕý 8ɘB©§ËIEND®B`‚stella-3.9.3/src/common/FBSurfaceGL.cxx0000644000175000001440000002635712266336753017257 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FBSurfaceGL.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifdef DISPLAY_OPENGL #include "Font.hxx" #include "FrameBufferGL.hxx" #include "FBSurfaceGL.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurfaceGL::FBSurfaceGL(FrameBufferGL& buffer, uInt32 width, uInt32 height) : myFB(buffer), myGL(myFB.p_gl), myTexture(NULL), myTexID(0), myVBOID(0), myImageX(0), myImageY(0), myImageW(width), myImageH(height) { // Fill buffer struct with valid data myTexWidth = FrameBufferGL::power_of_two(myImageW); myTexHeight = FrameBufferGL::power_of_two(myImageH); myTexCoordW = (GLfloat) myImageW / myTexWidth; myTexCoordH = (GLfloat) myImageH / myTexHeight; // Create a surface in the same format as the parent GL class const SDL_PixelFormat& pf = myFB.myPixelFormat; myTexture = SDL_CreateRGBSurface(SDL_SWSURFACE, myTexWidth, myTexHeight, pf.BitsPerPixel, pf.Rmask, pf.Gmask, pf.Bmask, pf.Amask); myPitch = myTexture->pitch / pf.BytesPerPixel; // Associate the SDL surface with a GL texture object updateCoords(); reload(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurfaceGL::~FBSurfaceGL() { if(myTexture) SDL_FreeSurface(myTexture); free(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color) { uInt32* buffer = (uInt32*) myTexture->pixels + y * myPitch + x; while(x++ <= x2) *buffer++ = (uInt32) myFB.myDefPalette[color]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color) { uInt32* buffer = (uInt32*) myTexture->pixels + y * myPitch + x; while(y++ <= y2) { *buffer = (uInt32) myFB.myDefPalette[color]; buffer += myPitch; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::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(myTexture, &tmp, myFB.myDefPalette[color]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::drawChar(const GUI::Font& font, uInt8 chr, uInt32 tx, uInt32 ty, uInt32 color) { 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 = (uInt32*) myTexture->pixels + (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) myFB.myDefPalette[color]; buffer += myPitch; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::drawBitmap(uInt32* bitmap, uInt32 tx, uInt32 ty, uInt32 color, uInt32 h) { uInt32* buffer = (uInt32*) myTexture->pixels + ty * myPitch + tx; for(uInt32 y = 0; y < h; ++y) { uInt32 mask = 0xF0000000; for(uInt32 x = 0; x < 8; ++x, mask >>= 4) if(bitmap[y] & mask) buffer[x] = (uInt32) myFB.myDefPalette[color]; buffer += myPitch; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::drawPixels(uInt32* data, uInt32 tx, uInt32 ty, uInt32 numpixels) { uInt32* buffer = (uInt32*) myTexture->pixels + ty * myPitch + tx; for(uInt32 i = 0; i < numpixels; ++i) *buffer++ = (uInt32) data[i]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::drawSurface(const FBSurface* surface, uInt32 tx, uInt32 ty) { const FBSurfaceGL* s = (const FBSurfaceGL*) surface; SDL_Rect dstrect; dstrect.x = tx; dstrect.y = ty; SDL_Rect srcrect; srcrect.x = 0; srcrect.y = 0; srcrect.w = s->myImageW; srcrect.h = s->myImageH; SDL_BlitSurface(s->myTexture, &srcrect, myTexture, &dstrect); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) { // OpenGL mode doesn't make use of dirty rectangles // It's faster to just update the entire surface mySurfaceIsDirty = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::getPos(uInt32& x, uInt32& y) const { x = myImageX; y = myImageY; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::setPos(uInt32 x, uInt32 y) { if(myImageX != x || myImageY != y) { myImageX = x; myImageY = y; updateCoords(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::setWidth(uInt32 w) { // This method can't be used with 'scaled' surface (aka TIA surfaces) // That shouldn't really matter, though, as all the UI stuff isn't scaled, // and it's the only thing that uses it if(myImageW != w) { myImageW = BSPF_min(w, (uInt32)myTexWidth); myTexCoordW = (GLfloat) myImageW / myTexWidth; updateCoords(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::setHeight(uInt32 h) { // This method can't be used with 'scaled' surface (aka TIA surfaces) // That shouldn't really matter, though, as all the UI stuff isn't scaled, // and it's the only thing that uses it if(myImageH != h) { myImageH = BSPF_min(h, (uInt32)myTexHeight); myTexCoordH = (GLfloat) myImageH / myTexHeight; updateCoords(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::translateCoords(Int32& x, Int32& y) const { x -= myImageX; y -= myImageY; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::update() { if(mySurfaceIsDirty) { // Texturemap complete texture to surface so we have free scaling // and antialiasing myGL.ActiveTexture(GL_TEXTURE0); myGL.BindTexture(GL_TEXTURE_2D, myTexID); myGL.PixelStorei(GL_UNPACK_ALIGNMENT, 1); myGL.PixelStorei(GL_UNPACK_ROW_LENGTH, myPitch); myGL.TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myImageW, myImageH, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, myTexture->pixels); myGL.EnableClientState(GL_VERTEX_ARRAY); myGL.EnableClientState(GL_TEXTURE_COORD_ARRAY); if(myFB.myVBOAvailable) { myGL.BindBuffer(GL_ARRAY_BUFFER, myVBOID); myGL.VertexPointer(2, GL_FLOAT, 0, (const GLvoid*)0); myGL.TexCoordPointer(2, GL_FLOAT, 0, (const GLvoid*)(8*sizeof(GLfloat))); } else { myGL.VertexPointer(2, GL_FLOAT, 0, myCoord); myGL.TexCoordPointer(2, GL_FLOAT, 0, myCoord+8); } myGL.DrawArrays(GL_TRIANGLE_STRIP, 0, 4); myGL.DisableClientState(GL_VERTEX_ARRAY); myGL.DisableClientState(GL_TEXTURE_COORD_ARRAY); mySurfaceIsDirty = false; // Let postFrameUpdate() know that a change has been made myFB.myDirtyFlag = true; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::free() { myGL.DeleteTextures(1, &myTexID); if(myFB.myVBOAvailable) myGL.DeleteBuffers(1, &myVBOID); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::reload() { // This does a 'soft' reset of the surface // It seems that on some system (notably, OSX), creating a new SDL window // destroys the GL context, requiring a reload of all textures // However, destroying the entire FBSurfaceGL object is wasteful, since // it will also regenerate SDL software surfaces (which are not required // to be regenerated) // Basically, all that needs to be done is to re-call glTexImage2D with a // new texture ID, so that's what we do here myGL.ActiveTexture(GL_TEXTURE0); myGL.Enable(GL_TEXTURE_2D); myGL.GenTextures(1, &myTexID); myGL.BindTexture(GL_TEXTURE_2D, myTexID); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Create the texture in the most optimal format myGL.PixelStorei(GL_UNPACK_ALIGNMENT, 1); myGL.PixelStorei(GL_UNPACK_ROW_LENGTH, myPitch); myGL.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myTexWidth, myTexHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, myTexture->pixels); // Cache vertex and texture coordinates using vertex buffer object if(myFB.myVBOAvailable) { myGL.GenBuffers(1, &myVBOID); myGL.BindBuffer(GL_ARRAY_BUFFER, myVBOID); myGL.BufferData(GL_ARRAY_BUFFER, 16*sizeof(GLfloat), myCoord, GL_STATIC_DRAW); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceGL::updateCoords() { // Vertex coordinates for texture // Upper left (x,y) myCoord[0] = (GLfloat)myImageX; myCoord[1] = (GLfloat)myImageY; // Upper right (x+w,y) myCoord[2] = (GLfloat)(myImageX + myImageW); myCoord[3] = (GLfloat)myImageY; // Lower left (x,y+h) myCoord[4] = (GLfloat)myImageX; myCoord[5] = (GLfloat)(myImageY + myImageH); // Lower right (x+w,y+h) myCoord[6] = (GLfloat)(myImageX + myImageW); myCoord[7] = (GLfloat)(myImageY + myImageH); // Texture coordinates for texture // Upper left (x,y) myCoord[8] = 0.0f; myCoord[9] = 0.0f; // Upper right (x+w,y) myCoord[10] = myTexCoordW; myCoord[11] = 0.0f; // Lower left (x,y+h) myCoord[12] = 0.0f; myCoord[13] = myTexCoordH; // Lower right (x+w,y+h) myCoord[14] = myTexCoordW; myCoord[15] = myTexCoordH; // Cache vertex and texture coordinates using vertex buffer object if(myFB.myVBOAvailable) { myGL.BindBuffer(GL_ARRAY_BUFFER, myVBOID); myGL.BufferData(GL_ARRAY_BUFFER, 16*sizeof(GLfloat), myCoord, GL_STATIC_DRAW); } } #endif stella-3.9.3/src/common/tv_filters/0000755000175000001440000000000012267274566016660 5ustar stephenusersstella-3.9.3/src/common/tv_filters/atari_ntsc_impl.h0000644000175000001440000003214412266336753022201 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: atari_ntsc_impl.h 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ /* Based on nes_ntsc 0.2.2. http://www.slack.net/~ant/ */ /* Common implementation of NTSC filters */ #include #include /* 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 */ #ifndef DISABLE_CORRECTION #define DISABLE_CORRECTION 0 #endif #undef PI #define PI 3.14159265358979323846f #ifndef LUMA_CUTOFF #define LUMA_CUTOFF 0.20 #endif #ifndef gamma_size #define gamma_size 1 #endif #ifndef rgb_bits #define rgb_bits 8 #endif #ifndef artifacts_max #define artifacts_max (artifacts_mid * 1.5f) #endif #ifndef fringing_max #define fringing_max (fringing_mid * 2) #endif #ifndef STD_HUE_CONDITION #define STD_HUE_CONDITION( setup ) 1 #endif #define ext_decoder_hue (std_decoder_hue + 15) #define rgb_unit (1 << rgb_bits) #define rgb_offset (rgb_unit * 2 + 0.5f) enum { burst_size = atari_ntsc_entry_size / burst_count }; enum { kernel_half = 16 }; enum { kernel_size = kernel_half * 2 + 1 }; typedef 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; #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;\ } static void init_filters( init_t* impl, atari_ntsc_setup_t const* setup ) { #if rescale_out > 1 float kernels [kernel_size * 2]; #else float* const kernels = impl->kernel; #endif /* generate luma (y) filter using sinc kernel */ { /* sinc with rolloff (dsf) */ float const rolloff = 1 + (float) setup->sharpness * (float) 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 > (float) 1.056 || pow_a_n < (float) 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 - (float) 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; assert( kernels [x] == kernels [x] ); /* catch numerical instability */ } } /* 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; assert( kernels [x] == kernels [x] ); /* catch numerical instability */ } } } /* printf( "luma:\n" ); for ( i = kernel_size; i < kernel_size * 2; i++ ) printf( "%f\n", kernels [i] ); printf( "chroma:\n" ); for ( i = 0; i < kernel_size; i++ ) printf( "%f\n", kernels [i] ); */ /* generate linear rescale kernels */ #if rescale_out > 1 { 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 ); } #endif } static float const default_decoder [6] = { 0.9563f, 0.6210f, -0.2721f, -0.6474f, -1.1070f, 1.7046f }; static void init( init_t* impl, atari_ntsc_setup_t const* 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; init_filters( 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; float const* decoder = setup->decoder_matrix; if ( !decoder ) { decoder = default_decoder; if ( STD_HUE_CONDITION( setup ) ) 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 = decoder; int n = 3; do { float i = *in++; float q = *in++; *out++ = i * c - q * s; *out++ = i * s + q * c; } while ( --n ); if ( burst_count <= 1 ) break; ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */ } while ( --n ); } } } /* kernel generation */ #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 enum { rgb_kernel_size = burst_size / alignment_count }; enum { rgb_bias = rgb_unit * 2 * atari_ntsc_rgb_builder }; typedef struct pixel_info_t { int offset; float negate; float kernel [4]; } pixel_info_t; #if rescale_in > 1 #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)) #else #define PIXEL_OFFSET( ntsc, scaled ) \ (kernel_size / 2 + (ntsc) - (scaled)),\ (1.0f - (((ntsc) + 100) & 2)) #endif extern pixel_info_t const atari_ntsc_pixels [alignment_count]; /* Generate pixel at all burst phases and column alignments */ static void gen_kernel( init_t* impl, float y, float i, float q, atari_ntsc_rgb_t* 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 i = k[0]*ic0 + k[2]*ic2; float q = k[1]*qc1 + k[3]*qc3; float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 + k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset; if ( rescale_out <= 1 ) k--; else 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( y, i, q, to_rgb, int, r, g ); *out++ = PACK_RGB( r, g, b ) - rgb_bias; } } } while ( alignment_count > 1 && --alignment_remain ); if ( burst_count <= 1 ) break; to_rgb += 6; ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */ } while ( --burst_remain ); } static void correct_errors( atari_ntsc_rgb_t color, atari_ntsc_rgb_t* out ); #if DISABLE_CORRECTION #define CORRECT_ERROR( a ) { out [i] += rgb_bias; } #define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; } #else #define CORRECT_ERROR( a ) { out [a] += error; } #define DISTRIBUTE_ERROR( a, b, c ) {\ atari_ntsc_rgb_t fourth = (error + 2 * atari_ntsc_rgb_builder) >> 2;\ fourth &= (rgb_bias >> 1) - atari_ntsc_rgb_builder;\ fourth -= rgb_bias >> 2;\ out [a] += fourth;\ out [b] += fourth;\ out [c] += fourth;\ out [i] += error - (fourth * 3);\ } #endif #define RGB_PALETTE_OUT( rgb, out_ )\ {\ unsigned char* out = (out_);\ atari_ntsc_rgb_t 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);\ } /* 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 stella-3.9.3/src/common/tv_filters/NTSCFilter.cxx0000644000175000001440000002421112266336753021315 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: NTSCFilter.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "FrameBuffer.hxx" #include "Settings.hxx" #include "NTSCFilter.hxx" #define SCALE_FROM_100(x) ((x/50.0)-1.0) #define SCALE_TO_100(x) (uInt32)(50*(x+1.0)) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NTSCFilter::NTSCFilter() : mySetup(atari_ntsc_composite), myPreset(PRESET_OFF), myCurrentAdjustable(0) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NTSCFilter::~NTSCFilter() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void NTSCFilter::setTIAPalette(const FrameBuffer& fb, const uInt32* palette) { // Normal TIA palette contains 256 colours, where every odd indexed colour // is used for PAL colour-loss effect // This can't be emulated here, since the memory requirements would be too // great (a 4x increase) // Therefore, we need to skip every second index, since the array passed to // the Blargg code assumes 128 colours uInt8* ptr = myTIAPalette; // Set palette for phosphor effect for(int i = 0; i < 256; i+=2) { for(int j = 0; j < 256; j+=2) { uInt8 ri = (palette[i] >> 16) & 0xff; uInt8 gi = (palette[i] >> 8) & 0xff; uInt8 bi = palette[i] & 0xff; uInt8 rj = (palette[j] >> 16) & 0xff; uInt8 gj = (palette[j] >> 8) & 0xff; uInt8 bj = palette[j] & 0xff; *ptr++ = fb.getPhosphor(ri, rj); *ptr++ = fb.getPhosphor(gi, gj); *ptr++ = fb.getPhosphor(bi, bj); } } // Set palette for normal fill for(int i = 0; i < 256; i+=2) { *ptr++ = (palette[i] >> 16) & 0xff; *ptr++ = (palette[i] >> 8) & 0xff; *ptr++ = palette[i] & 0xff; } updateFilter(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string NTSCFilter::setPreset(Preset preset) { myPreset = preset; string msg = "disabled"; switch(myPreset) { case PRESET_COMPOSITE: mySetup = atari_ntsc_composite; msg = "COMPOSITE"; break; case PRESET_SVIDEO: mySetup = atari_ntsc_svideo; msg = "S-VIDEO"; break; case PRESET_RGB: mySetup = atari_ntsc_rgb; msg = "RGB"; break; case PRESET_BAD: mySetup = atari_ntsc_bad; msg = "BAD ADJUST"; break; case PRESET_CUSTOM: mySetup = myCustomSetup; msg = "CUSTOM"; break; default: return msg; } updateFilter(); 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 = SCALE_TO_100(*ourCustomAdjustables[myCurrentAdjustable].value); newval += 2; if(newval > 100) newval = 100; *ourCustomAdjustables[myCurrentAdjustable].value = SCALE_FROM_100(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 = SCALE_TO_100(*ourCustomAdjustables[myCurrentAdjustable].value); if(newval < 2) newval = 0; else newval -= 2; *ourCustomAdjustables[myCurrentAdjustable].value = SCALE_FROM_100(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) { switch(preset) { case PRESET_COMPOSITE: convertToAdjustable(adjustable, atari_ntsc_composite); break; case PRESET_SVIDEO: convertToAdjustable(adjustable, atari_ntsc_svideo); break; case PRESET_RGB: convertToAdjustable(adjustable, atari_ntsc_rgb); break; case PRESET_BAD: convertToAdjustable(adjustable, atari_ntsc_bad); break; case PRESET_CUSTOM: convertToAdjustable(adjustable, myCustomSetup); break; default: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void NTSCFilter::setCustomAdjustables(Adjustable& adjustable) { myCustomSetup.hue = SCALE_FROM_100(adjustable.hue); myCustomSetup.saturation = SCALE_FROM_100(adjustable.saturation); myCustomSetup.contrast = SCALE_FROM_100(adjustable.contrast); myCustomSetup.brightness = SCALE_FROM_100(adjustable.brightness); myCustomSetup.sharpness = SCALE_FROM_100(adjustable.sharpness); myCustomSetup.gamma = SCALE_FROM_100(adjustable.gamma); myCustomSetup.resolution = SCALE_FROM_100(adjustable.resolution); myCustomSetup.artifacts = SCALE_FROM_100(adjustable.artifacts); myCustomSetup.fringing = SCALE_FROM_100(adjustable.fringing); myCustomSetup.bleed = SCALE_FROM_100(adjustable.bleed); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void NTSCFilter::convertToAdjustable(Adjustable& adjustable, const atari_ntsc_setup_t& setup) const { adjustable.hue = SCALE_TO_100(setup.hue); adjustable.saturation = SCALE_TO_100(setup.saturation); adjustable.contrast = SCALE_TO_100(setup.contrast); adjustable.brightness = SCALE_TO_100(setup.brightness); adjustable.sharpness = SCALE_TO_100(setup.sharpness); adjustable.gamma = SCALE_TO_100(setup.gamma); adjustable.resolution = SCALE_TO_100(setup.resolution); adjustable.artifacts = SCALE_TO_100(setup.artifacts); adjustable.fringing = SCALE_TO_100(setup.fringing); adjustable.bleed = SCALE_TO_100(setup.bleed); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - atari_ntsc_setup_t NTSCFilter::myCustomSetup = atari_ntsc_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-3.9.3/src/common/tv_filters/atari_ntsc.h0000644000175000001440000001464512266336753021166 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: atari_ntsc.h 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ /* Atari TIA, CTIA, GTIA and MARIA NTSC video filter */ #ifndef ATARI_NTSC_H #define ATARI_NTSC_H typedef unsigned char atari_ntsc_in_t; typedef unsigned int atari_ntsc_out_t; #ifdef __cplusplus extern "C" { #endif /* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown in parenthesis and should remain fairly stable in future versions. */ typedef struct atari_ntsc_setup_t { /* 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) */ float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */ } atari_ntsc_setup_t; /* Video format presets */ extern atari_ntsc_setup_t const atari_ntsc_composite; /* color bleeding + artifacts */ extern atari_ntsc_setup_t const atari_ntsc_svideo; /* color bleeding only */ extern atari_ntsc_setup_t const atari_ntsc_rgb; /* crisp image */ extern atari_ntsc_setup_t const atari_ntsc_bad; /* badly adjusted TV */ enum { atari_ntsc_palette_size = 129 * 128 }; /* Initializes and adjusts parameters. Can be called multiple times on the same atari_ntsc_t object. Can pass NULL for either parameter. */ typedef struct atari_ntsc_t atari_ntsc_t; void atari_ntsc_init( atari_ntsc_t* ntsc, atari_ntsc_setup_t const* setup, atari_ntsc_in_t const* palette ); /* 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 atari_ntsc_blit_single( atari_ntsc_t const* ntsc, atari_ntsc_in_t const* atari_in, long in_row_width, int in_width, int in_height, void* rgb_out, long out_pitch ); void atari_ntsc_blit_double( atari_ntsc_t const* ntsc, atari_ntsc_in_t const* atari_in1, atari_ntsc_in_t const* atari_in2, long in_row_width, int in_width, int in_height, void* rgb_out, long out_pitch ); /* Number of output pixels written by blitter for given input width. Width might be rounded down slightly; use ATARI_NTSC_IN_WIDTH() on result to find rounded value. Guaranteed not to round 160 down at all. */ #define ATARI_NTSC_OUT_WIDTH( in_width ) \ ((((in_width) - 1) / atari_ntsc_in_chunk + 1)* atari_ntsc_out_chunk) /* Number of input pixels that will fit within given output width. Might be rounded down slightly; use ATARI_NTSC_OUT_WIDTH() on result to find rounded value. */ #define ATARI_NTSC_IN_WIDTH( out_width ) \ (((out_width) / atari_ntsc_out_chunk - 1) * atari_ntsc_in_chunk + 1) /* Interface for user-defined custom blitters. */ enum { atari_ntsc_in_chunk = 2 }; /* number of input pixels read per chunk */ enum { atari_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */ enum { atari_ntsc_black = 0 }; /* palette index for black */ /* Begins outputting row and starts two pixels. First pixel will be cut off a bit. Use atari_ntsc_black for unused pixels. Declares variables, so must be before first statement in a block (unless you're using C++). */ #define ATARI_NTSC_BEGIN_ROW( ntsc, pixel0, pixel1 ) \ ATARI_NTSC_BEGIN_ROW_6_( pixel0, pixel1, ATARI_NTSC_ENTRY_, ntsc ) /* Begins input pixel */ #define ATARI_NTSC_COLOR_IN( in_index, ntsc, color_in ) \ ATARI_NTSC_COLOR_IN_( in_index, color_in, ATARI_NTSC_ENTRY_, ntsc ) /* 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 ) {\ atari_ntsc_rgb_t 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);\ } /* private */ enum { atari_ntsc_entry_size = 2 * 14 }; typedef unsigned long atari_ntsc_rgb_t; struct atari_ntsc_t { atari_ntsc_rgb_t table [atari_ntsc_palette_size] [atari_ntsc_entry_size]; }; #define ATARI_NTSC_ENTRY_( ntsc, n ) (ntsc)->table [n] /* common 3->7 ntsc macros */ #define ATARI_NTSC_BEGIN_ROW_6_( pixel0, pixel1, ENTRY, table ) \ unsigned const atari_ntsc_pixel0_ = (pixel0);\ atari_ntsc_rgb_t const* kernel0 = ENTRY( table, atari_ntsc_pixel0_ );\ unsigned const atari_ntsc_pixel1_ = (pixel1);\ atari_ntsc_rgb_t const* kernel1 = ENTRY( table, atari_ntsc_pixel1_ );\ atari_ntsc_rgb_t const* kernelx0;\ atari_ntsc_rgb_t const* kernelx1 = kernel0 /* common ntsc macros */ #define atari_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1)) #define atari_ntsc_clamp_mask (atari_ntsc_rgb_builder * 3 / 2) #define atari_ntsc_clamp_add (atari_ntsc_rgb_builder * 0x101) #define ATARI_NTSC_CLAMP_( io, shift ) {\ atari_ntsc_rgb_t sub = (io) >> (9-(shift)) & atari_ntsc_clamp_mask;\ atari_ntsc_rgb_t clamp = atari_ntsc_clamp_add - sub;\ io |= clamp;\ clamp -= sub;\ io &= clamp;\ } #define ATARI_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\ unsigned color_;\ kernelx##index = kernel##index;\ kernel##index = (color_ = (color), ENTRY( table, color_ ));\ } #ifdef __cplusplus } #endif #endif stella-3.9.3/src/common/tv_filters/module.mk0000644000175000001440000000033511722500341020451 0ustar stephenusersMODULE := src/common/tv_filters MODULE_OBJS := \ src/common/tv_filters/NTSCFilter.o \ src/common/tv_filters/atari_ntsc.o MODULE_DIRS += \ src/common/tv_filters # Include common rules include $(srcdir)/common.rules stella-3.9.3/src/common/tv_filters/atari_ntsc.c0000644000175000001440000001656312266336753021162 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: atari_ntsc.c 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "atari_ntsc.h" /* 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 */ atari_ntsc_setup_t const atari_ntsc_composite = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.15, 0.0, 0.0, 0.0, 0 }; atari_ntsc_setup_t const atari_ntsc_svideo = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.45, -1.0, -1.0, 0.0, 0 }; atari_ntsc_setup_t const atari_ntsc_rgb = { 0.0, 0.0, 0.0, 0.0, 0.2, 0.0, 0.70, -1.0, -1.0, -1.0, 0 }; atari_ntsc_setup_t const atari_ntsc_bad = { 0.1, -0.3, 0.3, 0.25, 0.2, 0.0, 0.1, 0.5, 0.5, 0.5, 0 }; #define alignment_count 2 #define burst_count 1 #define rescale_in 8 #define rescale_out 7 #define artifacts_mid 1.5f #define artifacts_max 2.5f #define fringing_mid 1.0f #define std_decoder_hue 0 #define gamma_size 256 #include "atari_ntsc_impl.h" /* 2 input pixels -> 8 composite samples */ pixel_info_t const atari_ntsc_pixels [alignment_count] = { { PIXEL_OFFSET( -4, -9 ), { 1, 1, 1, 1 } }, { PIXEL_OFFSET( 0, -5 ), { 1, 1, 1, 1 } }, }; static void correct_errors( atari_ntsc_rgb_t color, atari_ntsc_rgb_t* out ) { unsigned i; for ( i = 0; i < rgb_kernel_size / 2; i++ ) { atari_ntsc_rgb_t error = color - out [i ] - out [(i+10)%14+14] - out [i + 7] - out [i + 3 +14]; CORRECT_ERROR( i + 3 + 14 ); } } void atari_ntsc_init( atari_ntsc_t* ntsc, atari_ntsc_setup_t const* setup, atari_ntsc_in_t const* palette ) { int entry; init_t impl; if ( !setup ) setup = &atari_ntsc_composite; init( &impl, setup ); // Palette stores R/G/B data for 'atari_ntsc_palette_size' entries for ( entry = 0; entry < atari_ntsc_palette_size; entry++ ) { float r = impl.to_float [*palette++]; float g = impl.to_float [*palette++]; float b = impl.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, impl.to_rgb, int, ir, ig ); atari_ntsc_rgb_t rgb = PACK_RGB( ir, ig, ib ); if ( ntsc ) { atari_ntsc_rgb_t* kernel = ntsc->table [entry]; gen_kernel( &impl, y, i, q, kernel ); correct_errors( rgb, kernel ); } } } void atari_ntsc_blit_single( atari_ntsc_t const* ntsc, atari_ntsc_in_t const* atari_in, long in_row_width, int in_width, int in_height, void* rgb_out, long out_pitch ) { #define TO_SINGLE(pixel) ((1<<14)+(pixel>>1)) int const chunk_count = (in_width - 1) / atari_ntsc_in_chunk; while ( in_height-- ) { atari_ntsc_in_t const* line_in = atari_in; ATARI_NTSC_BEGIN_ROW( ntsc, TO_SINGLE(atari_ntsc_black), TO_SINGLE(line_in[0]) ); atari_ntsc_out_t* restrict line_out = (atari_ntsc_out_t*) rgb_out; int n; ++line_in; for ( n = chunk_count; n; --n ) { /* order of input and output pixels must not be altered */ ATARI_NTSC_COLOR_IN( 0, ntsc, TO_SINGLE(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, TO_SINGLE(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, ntsc, TO_SINGLE(atari_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, TO_SINGLE(atari_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] ); atari_in += in_row_width; rgb_out = (char*) rgb_out + out_pitch; } } void atari_ntsc_blit_double( atari_ntsc_t const* ntsc, atari_ntsc_in_t const* atari_in1, atari_ntsc_in_t const* atari_in2, long in_row_width, int in_width, int in_height, void* rgb_out, long out_pitch ) { #define TO_DOUBLE(pixel1, pixel2) (((pixel1>>1)<<7)+(pixel2>>1)) int const chunk_count = (in_width - 1) / atari_ntsc_in_chunk; while ( in_height-- ) { atari_ntsc_in_t const* line_in1 = atari_in1; atari_ntsc_in_t const* line_in2 = atari_in2; ATARI_NTSC_BEGIN_ROW( ntsc, TO_DOUBLE(atari_ntsc_black, atari_ntsc_black), TO_DOUBLE(line_in1[0], line_in2[0]) ); atari_ntsc_out_t* restrict line_out = (atari_ntsc_out_t*) rgb_out; int n; ++line_in1; ++line_in2; for ( n = chunk_count; n; --n ) { /* order of input and output pixels must not be altered */ ATARI_NTSC_COLOR_IN( 0, ntsc, TO_DOUBLE(line_in1[0], line_in2[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, TO_DOUBLE(line_in1[1], line_in2[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_in1 += 2; line_in2 += 2; line_out += 7; } /* finish final pixels */ ATARI_NTSC_COLOR_IN( 0, ntsc, TO_DOUBLE(atari_ntsc_black, atari_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, TO_DOUBLE(atari_ntsc_black, atari_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] ); atari_in1 += in_row_width; atari_in2 += in_row_width; rgb_out = (char*) rgb_out + out_pitch; } } stella-3.9.3/src/common/tv_filters/NTSCFilter.hxx0000644000175000001440000001321412266336753021323 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: NTSCFilter.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef NTSC_FILTER_HXX #define NTSC_FILTER_HXX class FrameBuffer; class Settings; #include "bspf.hxx" #include "atari_ntsc.h" /** 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 atari_ntsc_xxx structs and methods, so that the rest of the codebase isn't affected by updated versions of Blargg code. */ class NTSCFilter { public: NTSCFilter(); virtual ~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. */ void setTIAPalette(const FrameBuffer& fb, const uInt32* 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; // Reinitialises the NTSC filter (automatically called after settings // have changed) inline void updateFilter() { atari_ntsc_init(&myFilter, &mySetup, myTIAPalette); } // 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); // 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 // In the current implementation, the source pitch is always the // same as the actual width inline void blit_single(uInt8* src_buf, int src_width, int src_height, uInt32* dest_buf, long dest_pitch) { atari_ntsc_blit_single(&myFilter, src_buf, src_width, src_width, src_height, dest_buf, dest_pitch); } inline void blit_double(uInt8* src_buf, uInt8* src_back_buf, int src_width, int src_height, uInt32* dest_buf, long dest_pitch) { atari_ntsc_blit_double(&myFilter, src_buf, src_back_buf, src_width, src_width, src_height, dest_buf, dest_pitch); } private: // Convert from atari_ntsc_setup_t values to equivalent adjustables void convertToAdjustable(Adjustable& adjustable, const atari_ntsc_setup_t& setup) const; private: // The NTSC filter structure atari_ntsc_t myFilter; // Contains controls used to adjust the palette in the NTSC filter // This is the main setup object used by the underlying ntsc code atari_ntsc_setup_t mySetup; // This setup is used only in custom mode (after it is modified, // it is copied to mySetup) static atari_ntsc_setup_t myCustomSetup; // Current preset in use Preset myPreset; // The base 2600 palette contains 128 colours // However, 'phosphor' mode needs a 128x128 matrix to simulate // low-flicker output, so we need 128x128 + 128, or 129x128 // Note that this is a huge hack, which hopefully will go // away once the phosphor effect can be more properly emulated // Memory layout is as follows: // // 128x128 in first bytes of array // 128 in last bytes of array // Each colour is represented by 3 bytes, in R,G,B order uInt8 myTIAPalette[atari_ntsc_palette_size * 3]; struct AdjustableTag { const char* type; double* value; }; uInt32 myCurrentAdjustable; static const AdjustableTag ourCustomAdjustables[10]; }; #endif stella-3.9.3/src/common/FrameBufferSoft.cxx0000644000175000001440000005735012266336753020251 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FrameBufferSoft.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "bspf.hxx" #include "Console.hxx" #include "Font.hxx" #include "OSystem.hxx" #include "RectList.hxx" #include "Settings.hxx" #include "TIA.hxx" #include "FrameBufferSoft.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBufferSoft::FrameBufferSoft(OSystem* osystem) : FrameBuffer(osystem), myZoomLevel(2), myRenderType(kSoftZoom_16), myTiaDirty(false), myInUIMode(false), myRectList(NULL) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBufferSoft::~FrameBufferSoft() { delete myRectList; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferSoft::initSubsystem(VideoMode& mode) { // Set up the rectangle list to be used in the dirty update delete myRectList; myRectList = new RectList(); if(!myRectList) { myOSystem->logMessage("ERROR: Unable to get memory for SDL rects", 0); return false; } // Create the screen return setVidMode(mode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string FrameBufferSoft::about() const { ostringstream buf; buf << "Video rendering: Software mode" << endl << setfill('0') << " Color: " << (int)myFormat->BitsPerPixel << " bit" << endl << " Rmask = " << hex << setw(8) << (int)myFormat->Rmask << ", Rshift = "<< dec << setw(2) << (int)myFormat->Rshift << ", Rloss = " << dec << setw(2) << (int)myFormat->Rloss << endl << " Gmask = " << hex << setw(8) << (int)myFormat->Gmask << ", Gshift = "<< dec << setw(2) << (int)myFormat->Gshift << ", Gloss = " << dec << setw(2) << (int)myFormat->Gloss << endl << " Bmask = " << hex << setw(8) << (int)myFormat->Bmask << ", Bshift = "<< dec << setw(2) << (int)myFormat->Bshift << ", Bloss = " << dec << setw(2) << (int)myFormat->Bloss << endl; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferSoft::setVidMode(VideoMode& mode) { // Make sure to clear the screen if(myScreen) { SDL_FillRect(myScreen, NULL, 0); SDL_UpdateRect(myScreen, 0, 0, 0, 0); } myScreen = SDL_SetVideoMode(mode.screen_w, mode.screen_h, 0, mySDLFlags); if(myScreen == NULL) { ostringstream buf; buf << "ERROR: Unable to open SDL window: " << SDL_GetError() << endl; myOSystem->logMessage(buf.str(), 0); return false; } myFormat = myScreen->format; myBytesPerPixel = myFormat->BytesPerPixel; // Make sure the flags represent the current screen state mySDLFlags = myScreen->flags; // Make sure drawTIA() knows which renderer to use switch(myBytesPerPixel) { case 2: // 16-bit myPitch = myScreen->pitch >> 1; myRenderType = myUsePhosphor ? kPhosphor_16 : kSoftZoom_16; break; case 3: // 24-bit myPitch = myScreen->pitch; myRenderType = myUsePhosphor ? kPhosphor_24 : kSoftZoom_24; break; case 4: // 32-bit myPitch = myScreen->pitch >> 2; myRenderType = myUsePhosphor ? kPhosphor_32 : kSoftZoom_32; break; } myBaseOffset = mode.image_y * myPitch + mode.image_x; // If software mode can open the given screen, it will always be in the // requested format, or not at all; we only update mode when the screen // is successfully created mode.screen_w = myScreen->w; mode.screen_h = myScreen->h; myZoomLevel = mode.gfxmode.zoom; // Erase old rects, since they've probably been scaled for // a different sized screen myRectList->start(); // Any previously allocated surfaces have probably changed as well, // so we should refresh them resetSurfaces(); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSoft::invalidate() { if(myScreen) SDL_FillRect(myScreen, NULL, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSoft::drawTIA(bool fullRedraw) { const TIA& tia = myOSystem->console().tia(); uInt8* currentFrame = tia.currentFrameBuffer(); uInt8* previousFrame = tia.previousFrameBuffer(); uInt32 width = tia.width(); uInt32 height = tia.height(); switch(myRenderType) { case kSoftZoom_16: { SDL_LockSurface(myScreen); uInt16* buffer = (uInt16*)myScreen->pixels + myBaseOffset; uInt32 bufofsY = 0; uInt32 screenofsY = 0; for(uInt32 y = 0; y < height; ++y) { uInt32 ystride = myZoomLevel; while(ystride--) { uInt32 pos = screenofsY; for(uInt32 x = 0; x < width; ++x) { const uInt32 bufofs = bufofsY + x; uInt32 xstride = myZoomLevel; uInt8 v = currentFrame[bufofs]; uInt8 w = previousFrame[bufofs]; if(v != w || fullRedraw) { while(xstride--) { buffer[pos++] = (uInt16) myDefPalette[v]; buffer[pos++] = (uInt16) myDefPalette[v]; } myTiaDirty = true; } else pos += xstride + xstride; } screenofsY += myPitch; } bufofsY += width; } SDL_UnlockSurface(myScreen); break; // kSoftZoom_16 } case kSoftZoom_24: { SDL_LockSurface(myScreen); uInt8* buffer = (uInt8*)myScreen->pixels + myBaseOffset; uInt32 bufofsY = 0; uInt32 screenofsY = 0; for(uInt32 y = 0; y < height; ++y) { uInt32 ystride = myZoomLevel; while(ystride--) { uInt32 pos = screenofsY; for(uInt32 x = 0; x < width; ++x) { const uInt32 bufofs = bufofsY + x; uInt32 xstride = myZoomLevel; uInt8 v = currentFrame[bufofs]; uInt8 w = previousFrame[bufofs]; if(v != w || fullRedraw) { uInt8 a = myDefPalette24[v][0], b = myDefPalette24[v][1], c = myDefPalette24[v][2]; while(xstride--) { buffer[pos++] = a; buffer[pos++] = b; buffer[pos++] = c; buffer[pos++] = a; buffer[pos++] = b; buffer[pos++] = c; } myTiaDirty = true; } else // try to eliminate multiply whereever possible pos += xstride + xstride + xstride + xstride + xstride + xstride; } screenofsY += myPitch; } bufofsY += width; } SDL_UnlockSurface(myScreen); break; // kSoftZoom_24 } case kSoftZoom_32: { SDL_LockSurface(myScreen); uInt32* buffer = (uInt32*)myScreen->pixels + myBaseOffset; uInt32 bufofsY = 0; uInt32 screenofsY = 0; for(uInt32 y = 0; y < height; ++y) { uInt32 ystride = myZoomLevel; while(ystride--) { uInt32 pos = screenofsY; for(uInt32 x = 0; x < width; ++x) { const uInt32 bufofs = bufofsY + x; uInt32 xstride = myZoomLevel; uInt8 v = currentFrame[bufofs]; uInt8 w = previousFrame[bufofs]; if(v != w || fullRedraw) { while(xstride--) { buffer[pos++] = (uInt32) myDefPalette[v]; buffer[pos++] = (uInt32) myDefPalette[v]; } myTiaDirty = true; } else pos += xstride + xstride; } screenofsY += myPitch; } bufofsY += width; } SDL_UnlockSurface(myScreen); break; // kSoftZoom_32 } case kPhosphor_16: { SDL_LockSurface(myScreen); uInt16* buffer = (uInt16*)myScreen->pixels + myBaseOffset; uInt32 bufofsY = 0; uInt32 screenofsY = 0; for(uInt32 y = 0; y < height; ++y) { uInt32 ystride = myZoomLevel; while(ystride--) { uInt32 pos = screenofsY; for(uInt32 x = 0; x < width; ++x) { const uInt32 bufofs = bufofsY + x; uInt32 xstride = myZoomLevel; uInt8 v = currentFrame[bufofs]; uInt8 w = previousFrame[bufofs]; while(xstride--) { buffer[pos++] = (uInt16) myAvgPalette[v][w]; buffer[pos++] = (uInt16) myAvgPalette[v][w]; } } screenofsY += myPitch; } bufofsY += width; } SDL_UnlockSurface(myScreen); myTiaDirty = true; break; // kPhosphor_16 } case kPhosphor_24: { SDL_LockSurface(myScreen); uInt8* buffer = (uInt8*)myScreen->pixels + myBaseOffset; uInt32 bufofsY = 0; uInt32 screenofsY = 0; for(uInt32 y = 0; y < height; ++y) { uInt32 ystride = myZoomLevel; while(ystride--) { uInt32 pos = screenofsY; for(uInt32 x = 0; x < width; ++x) { const uInt32 bufofs = bufofsY + x; uInt32 xstride = myZoomLevel; uInt8 v = currentFrame[bufofs]; uInt8 w = previousFrame[bufofs]; uInt8 a, b, c; uInt32 pixel = myAvgPalette[v][w]; if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { a = (pixel & myFormat->Bmask) >> myFormat->Bshift; b = (pixel & myFormat->Gmask) >> myFormat->Gshift; c = (pixel & myFormat->Rmask) >> myFormat->Rshift; } else { a = (pixel & myFormat->Rmask) >> myFormat->Rshift; b = (pixel & myFormat->Gmask) >> myFormat->Gshift; c = (pixel & myFormat->Bmask) >> myFormat->Bshift; } while(xstride--) { buffer[pos++] = a; buffer[pos++] = b; buffer[pos++] = c; buffer[pos++] = a; buffer[pos++] = b; buffer[pos++] = c; } } screenofsY += myPitch; } bufofsY += width; } SDL_UnlockSurface(myScreen); myTiaDirty = true; break; // kPhosphor_24 } case kPhosphor_32: { SDL_LockSurface(myScreen); uInt32* buffer = (uInt32*)myScreen->pixels + myBaseOffset; uInt32 bufofsY = 0; uInt32 screenofsY = 0; for(uInt32 y = 0; y < height; ++y) { uInt32 ystride = myZoomLevel; while(ystride--) { uInt32 pos = screenofsY; for(uInt32 x = 0; x < width; ++x) { const uInt32 bufofs = bufofsY + x; uInt32 xstride = myZoomLevel; uInt8 v = currentFrame[bufofs]; uInt8 w = previousFrame[bufofs]; while(xstride--) { buffer[pos++] = (uInt32) myAvgPalette[v][w]; buffer[pos++] = (uInt32) myAvgPalette[v][w]; } } screenofsY += myPitch; } bufofsY += width; } SDL_UnlockSurface(myScreen); myTiaDirty = true; break; // kPhosphor_32 } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSoft::postFrameUpdate() { if(myTiaDirty && !myInUIMode) { SDL_UpdateRect(myScreen, 0, 0, 0, 0); myTiaDirty = false; } else if(myRectList->numRects() > 0) { //myRectList->print(myScreen->w, myScreen->h); SDL_UpdateRects(myScreen, myRectList->numRects(), myRectList->rects()); } myRectList->start(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSoft::enablePhosphor(bool enable, int blend) { myUsePhosphor = enable; myPhosphorBlend = blend; // Make sure drawMediaSource() knows which renderer to use switch(myBytesPerPixel) { case 2: // 16-bit myRenderType = myUsePhosphor ? kPhosphor_16 : kSoftZoom_16; break; case 3: // 24-bit myRenderType = myUsePhosphor ? kPhosphor_24 : kSoftZoom_24; break; case 4: // 32-bit myRenderType = myUsePhosphor ? kPhosphor_32 : kSoftZoom_32; break; } myRedrawEntireFrame = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurface* FrameBufferSoft::createSurface(int w, int h, bool isBase) const { // For some unknown reason, OSX in software fullscreen mode doesn't like // to use the underlying surface directly // I suspect it's an SDL compatibility thing, since I get errors // referencing Quartz vs. QuickDraw, and then a program crash // For now, we'll just always use entire surfaces for OSX // I don't think this will have much effect, since OpenGL mode is the // preferred method in OSX (basically, all OSX installations have OpenGL // support) #ifdef MAC_OSX isBase = false; #endif SDL_Surface* surface = isBase ? myScreen : SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, myFormat->BitsPerPixel, myFormat->Rmask, myFormat->Gmask, myFormat->Bmask, myFormat->Amask); return new FBSurfaceSoft(*this, surface, w, h, isBase); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSoft::scanline(uInt32 row, uInt8* data) const { // Make sure no pixels are being modified SDL_LockSurface(myScreen); uInt32 pixel = 0; uInt8 *p, r, g, b; // Row will be offset by the amount the actual image is shifted down const GUI::Rect& image = imageRect(); row += image.y(); for(Int32 x = 0; x < myScreen->w; ++x) { p = (Uint8*) ((uInt8*)myScreen->pixels + // Start at top of RAM (row * myScreen->pitch) + // Go down 'row' lines ((x + image.x()) * myBytesPerPixel)); // Go in 'x' pixels switch(myBytesPerPixel) { case 1: pixel = *p; break; case 2: pixel = *(Uint16*) p; break; case 3: if(SDL_BYTEORDER == SDL_BIG_ENDIAN) pixel = p[0] << 16 | p[1] << 8 | p[2]; else pixel = p[0] | p[1] << 8 | p[2] << 16; break; case 4: pixel = *(Uint32*) p; break; } SDL_GetRGB(pixel, myScreen->format, &r, &g, &b); data[x * 3 + 0] = r; data[x * 3 + 1] = g; data[x * 3 + 2] = b; } SDL_UnlockSurface(myScreen); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // FBSurfaceSoft implementation follows ... // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurfaceSoft::FBSurfaceSoft(const FrameBufferSoft& buffer, SDL_Surface* surface, uInt32 w, uInt32 h, bool isBase) : myFB(buffer), mySurface(surface), myWidth(w), myHeight(h), myIsBaseSurface(isBase), mySurfaceIsDirty(false), myPitch(0), myXOrig(0), myYOrig(0), myXOffset(0), myYOffset(0) { reload(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurfaceSoft::~FBSurfaceSoft() { if(!myIsBaseSurface) SDL_FreeSurface(mySurface); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSoft::hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color) { // Horizontal line SDL_Rect tmp; tmp.x = x + myXOffset; tmp.y = y + myYOffset; tmp.w = x2 - x + 1; tmp.h = 1; SDL_FillRect(mySurface, &tmp, myFB.myDefPalette[color]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSoft::vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color) { // Vertical line SDL_Rect tmp; tmp.x = x + myXOffset; tmp.y = y + myYOffset; tmp.w = 1; tmp.h = y2 - y + 1; SDL_FillRect(mySurface, &tmp, myFB.myDefPalette[color]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSoft::fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color) { // Fill the rectangle SDL_Rect tmp; tmp.x = x + myXOffset; tmp.y = y + myYOffset; tmp.w = w; tmp.h = h; SDL_FillRect(mySurface, &tmp, myFB.myDefPalette[color]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSoft::drawChar(const GUI::Font& font, uInt8 chr, uInt32 tx, uInt32 ty, uInt32 color) { 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)); switch(myFB.myBytesPerPixel) { case 2: { // Get buffer position where upper-left pixel of the character will be drawn uInt16* buffer = (uInt16*)getBasePtr(tx + bbx, ty + desc.ascent - bby - bbh); 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] = (uInt16) myFB.myDefPalette[color]; buffer += myPitch; } break; } case 3: { // Get buffer position where upper-left pixel of the character will be drawn uInt8* buffer = (uInt8*)getBasePtr(tx + bbx, ty + desc.ascent - bby - bbh); uInt8 a = myFB.myDefPalette24[color][0], b = myFB.myDefPalette24[color][1], c = myFB.myDefPalette24[color][2]; for(int y = 0; y < bbh; y++, buffer += myPitch) { const uInt16 ptr = *tmp++; uInt16 mask = 0x8000; uInt8* buf_ptr = buffer; for(int x = 0; x < bbw; x++, mask >>= 1) { if(ptr & mask) { *buf_ptr++ = a; *buf_ptr++ = b; *buf_ptr++ = c; } else buf_ptr += 3; } } break; } case 4: { // Get buffer position where upper-left pixel of the character will be drawn uInt32* buffer = (uInt32*)getBasePtr(tx + bbx, ty + desc.ascent - bby - bbh); for(int y = 0; y < bbh; y++, buffer += myPitch) { const uInt16 ptr = *tmp++; uInt16 mask = 0x8000; for(int x = 0; x < bbw; x++, mask >>= 1) if(ptr & mask) buffer[x] = (uInt32) myFB.myDefPalette[color]; } break; } default: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSoft::drawBitmap(uInt32* bitmap, uInt32 tx, uInt32 ty, uInt32 color, uInt32 h) { SDL_Rect rect; rect.y = ty + myYOffset; rect.w = rect.h = 1; for(uInt32 y = 0; y < h; y++) { rect.x = tx + myXOffset; uInt32 mask = 0xF0000000; for(uInt32 x = 0; x < 8; x++, mask >>= 4) { if(bitmap[y] & mask) SDL_FillRect(mySurface, &rect, myFB.myDefPalette[color]); rect.x++; } rect.y++; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSoft::drawPixels(uInt32* data, uInt32 tx, uInt32 ty, uInt32 numpixels) { SDL_Rect rect; rect.x = tx + myXOffset; rect.y = ty + myYOffset; rect.w = rect.h = 1; for(uInt32 x = 0; x < numpixels; ++x) { SDL_FillRect(mySurface, &rect, data[x]); rect.x++; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSoft::drawSurface(const FBSurface* surface, uInt32 tx, uInt32 ty) { const FBSurfaceSoft* s = (const FBSurfaceSoft*) surface; SDL_Rect dstrect; dstrect.x = tx + myXOffset; dstrect.y = ty + myYOffset; SDL_Rect srcrect; srcrect.x = 0; srcrect.y = 0; srcrect.w = s->myWidth; srcrect.h = s->myHeight; SDL_BlitSurface(s->mySurface, &srcrect, mySurface, &dstrect); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSoft::addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) { //cerr << " -> addDirtyRect: x = " << x << ", y = " << y << ", w = " << w << ", h = " << h << endl; // Base surfaces use dirty-rectangle updates, since they can be quite // large, and updating the entire surface each frame would be too slow // Non-base surfaces are usually smaller, and can be updated entirely if(myIsBaseSurface) { // Add a dirty rect to the UI rectangle list SDL_Rect temp; temp.x = x + myXOrig; temp.y = y + myYOrig; temp.w = w; temp.h = h; myFB.myRectList->add(&temp); } else { SDL_Rect temp; temp.x = myXOrig; temp.y = myYOrig; temp.w = myWidth; temp.h = myHeight; myFB.myRectList->add(&temp); // Indicate that at least one dirty rect has been added // This is an optimization for the update() method mySurfaceIsDirty = true; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSoft::getPos(uInt32& x, uInt32& y) const { // Return the origin of the 'usable' area of a surface if(myIsBaseSurface) { x = myXOffset; y = myYOffset; } else { x = myXOrig; y = myYOrig; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSoft::setPos(uInt32 x, uInt32 y) { myXOrig = x; myYOrig = y; if(myIsBaseSurface) { myXOffset = myFB.imageRect().x(); myYOffset = myFB.imageRect().y(); } else { myXOffset = myYOffset = 0; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSoft::setWidth(uInt32 w) { myWidth = BSPF_min(w, (uInt32)mySurface->w); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSoft::setHeight(uInt32 h) { myHeight = BSPF_min(h, (uInt32)mySurface->h); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSoft::translateCoords(Int32& x, Int32& y) const { x -= myXOrig; y -= myYOrig; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSoft::update() { // Since this method is called each frame, we only blit the surfaces when // absolutely necessary if(mySurfaceIsDirty /* && !myIsBaseSurface */) { SDL_Rect srcrect; srcrect.x = 0; srcrect.y = 0; srcrect.w = myWidth; srcrect.h = myHeight; SDL_Rect dstrect; dstrect.x = myXOrig; dstrect.y = myYOrig; dstrect.w = myWidth; dstrect.h = myHeight; SDL_BlitSurface(mySurface, &srcrect, myFB.myScreen, &dstrect); mySurfaceIsDirty = false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSoft::reload() { switch(mySurface->format->BytesPerPixel) { case 2: // 16-bit myPitch = mySurface->pitch >> 1; break; case 3: // 24-bit myPitch = mySurface->pitch; break; case 4: // 32-bit myPitch = mySurface->pitch >> 2; break; } } stella-3.9.3/src/common/PNGLibrary.hxx0000644000175000001440000001133412266336753017177 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: PNGLibrary.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef PNGLIBRARY_HXX #define PNGLIBRARY_HXX #include class FrameBuffer; class FBSurface; class Properties; class TIA; #include #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(); virtual ~PNGLibrary(); /** 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 fb The main framebuffer of the application @param surface The FBSurface into which to place the PNG data @return On success, the FBSurface containing image data and a result of true, otherwise a const char* exception is thrown containing a more detailed error message. */ bool loadImage(const string& filename, const FrameBuffer& fb, FBSurface& surface); /** Save the current TIA image to a PNG file using data from the Framebuffer. Any postprocessing/filtering will be included. @param filename The filename to save the PNG image @param framebuffer The framebuffer containing the image data @param props The properties object containing info about the ROM */ string saveImage(const string& filename, const FrameBuffer& framebuffer, const Properties& props); /** Save the current TIA image to a PNG file using data directly from the TIA framebuffer. No filtering or scaling will be included. @param filename The filename to save the PNG image @param framebuffer The framebuffer containing the image data @param mediasrc Source of the raw TIA data @param props The properties object containing info about the ROM */ string saveImage(const string& filename, const FrameBuffer& framebuffer, const TIA& tia, const Properties& props); private: // The following data remains between invocations of allocateStorage, // and is only changed when absolutely necessary. typedef struct { uInt8* buffer; png_bytep* row_pointers; png_uint_32 width, height, pitch; uInt32* line; uInt32 buffer_size, line_size, row_size; } ReadInfoType; 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. */ bool allocateStorage(png_uint_32 iwidth, png_uint_32 iheight); /** Scale the PNG data from 'ReadInfo' into the FBSurface. For now, scaling is done on integer boundaries only (ie, 1x, 2x, etc up or down). @param fb The main framebuffer of the application @param surface The FBSurface into which to place the PNG data */ void scaleImagetoSurface(const FrameBuffer& fb, FBSurface& surface); string saveBufferToPNG(ofstream& out, uInt8* buffer, uInt32 width, uInt32 height, const Properties& props, const string& effectsInfo); void writePNGChunk(ofstream& out, const char* type, uInt8* data, int size); void writePNGText(ofstream& out, const string& key, const string& text); 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); static void png_user_warn(png_structp ctx, png_const_charp str); static void png_user_error(png_structp ctx, png_const_charp str); }; #endif stella-3.9.3/src/gui/0000755000175000001440000000000012267274566013773 5ustar stephenusersstella-3.9.3/src/gui/StringListWidget.hxx0000644000175000001440000000240412266336753017766 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: StringListWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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(); void setList(const StringList& list); protected: void drawWidget(bool hilite); GUI::Rect getEditRect() const; protected: bool _hilite; }; #endif stella-3.9.3/src/gui/GameInfoDialog.hxx0000644000175000001440000000543212266336753017331 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: GameInfoDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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(); protected: void loadConfig(); void saveConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); private: void setDefaults(); void loadView(); private: TabWidget* myTab; // Cartridge properties EditTextWidget* myName; StaticTextWidget* myMD5; EditTextWidget* myManufacturer; EditTextWidget* myModelNo; EditTextWidget* myRarity; EditTextWidget* myNote; PopUpWidget* mySound; PopUpWidget* myType; // Console properties PopUpWidget* myLeftDiff; PopUpWidget* myRightDiff; PopUpWidget* myTVType; // Controller properties PopUpWidget* myP0Controller; PopUpWidget* myP1Controller; PopUpWidget* mySwapPaddles; PopUpWidget* myLeftPort; PopUpWidget* myRightPort; PopUpWidget* myMouseControl; PopUpWidget* myMouseX; PopUpWidget* myMouseY; // Display properties PopUpWidget* myFormat; EditTextWidget* myYStart; EditTextWidget* myHeight; PopUpWidget* myPhosphor; SliderWidget* myPPBlend; StaticTextWidget* myPPBlendLabel; enum { kLeftCChanged = 'LCch', kRightCChanged = 'RCch', kPhosphorChanged = 'PPch', kPPBlendChanged = 'PBch', kMCtrlChanged = 'MCch' }; // 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; }; #endif stella-3.9.3/src/gui/GameList.hxx0000644000175000001440000000414112266336753016225 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: GameList.hxx 2838 2014-01-17 23:34:03Z stephena $ // // Based on code from KStella - Stella frontend // Copyright (C) 2003-2005 Stephen Anthony //============================================================================ #ifndef GAME_LIST_HXX #define GAME_LIST_HXX #include #include "bspf.hxx" /** Holds the list of game info for the ROM launcher. */ class GameList { public: GameList(); ~GameList(); 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; } int size() const { return myArray.size(); } void clear() { myArray.clear(); } void appendGame(const string& name, const string& path, const string& md5, bool isDir = false); 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; } bool operator < (const Entry& a) const; }; vector myArray; }; #endif stella-3.9.3/src/gui/BrowserDialog.hxx0000644000175000001440000000434712266336753017273 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: BrowserDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef BROWSER_DIALOG_HXX #define BROWSER_DIALOG_HXX class GuiObject; class ButtonWidget; class EditTextWidget; class FileListWidget; class StaticTextWidget; #include "Dialog.hxx" #include "Command.hxx" #include "FSNode.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(); /** 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; protected: virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); 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; }; #endif stella-3.9.3/src/gui/CommandMenu.hxx0000644000175000001440000000234612266336753016730 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CommandMenu.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: CommandMenu.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class CommandMenu : public DialogContainer { public: /** Create a new menu stack */ CommandMenu(OSystem* osystem); /** Destructor */ virtual ~CommandMenu(); }; #endif stella-3.9.3/src/gui/ConfigPathDialog.hxx0000644000175000001440000000501712266336753017665 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ConfigPathDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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, int max_w, int max_h); ~ConfigPathDialog(); void handleCommand(CommandSender* sender, int cmd, int data, int id); private: void loadConfig(); void saveConfig(); void setDefaults(); 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 }; BrowserDialog* myBrowser; // Config paths EditTextWidget* myRomPath; EditTextWidget* myStatePath; EditTextWidget* myNVRamPath; EditTextWidget* myCheatFile; EditTextWidget* myPaletteFile; EditTextWidget* myPropsFile; // Indicates if this dialog is used for global (vs. in-game) settings bool myIsGlobal; }; #endif stella-3.9.3/src/gui/GlobalPropsDialog.cxx0000644000175000001440000003401412266336753020061 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: GlobalPropsDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "Control.hxx" #include "Dialog.hxx" #include "OSystem.hxx" #include "PopUpWidget.hxx" #include "Settings.hxx" #include "StringList.hxx" #include "Widget.hxx" #include "LauncherDialog.hxx" #include "GlobalPropsDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GlobalPropsDialog::GlobalPropsDialog(GuiObject* boss, const GUI::Font& font) : Dialog(&boss->instance(), &boss->parent(), 0, 0, 0, 0), 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().infoFont(); // Set real dimensions _w = lwidth + pwidth + fontWidth*3 + 15; _h = 17 * (lineHeight + 4) + buttonHeight + 20; xpos = 10; ypos = 10; //////////////////////////////////////////////////////////////////// // The following items are also present in GameInfoDialog // If any changes are ever made here, GameInfoDialog should also // be updated accordingly //////////////////////////////////////////////////////////////////// // Bankswitch type new StaticTextWidget(this, font, xpos, ypos+1, lwidth, fontHeight, "Bankswitch type:", kTextAlignLeft); items.clear(); items.push_back("Auto-detect", "AUTO" ); items.push_back("0840 (8K ECONObank)", "0840" ); items.push_back("2IN1 Multicart (4-32K)", "2IN1" ); items.push_back("4IN1 Multicart (8-32K)", "4IN1" ); items.push_back("8IN1 Multicart (16-64K)", "8IN1" ); items.push_back("16IN1 Multicart (32-128K)", "16IN1" ); items.push_back("32IN1 Multicart (64/128K)", "32IN1" ); items.push_back("64IN1 Multicart (128/256K)", "64IN1" ); items.push_back("128IN1 Multicart (256/512K)", "128IN1"); items.push_back("2K (64-2048 bytes Atari)", "2K" ); items.push_back("3E (32K Tigervision)", "3E" ); items.push_back("3F (512K Tigervision)", "3F" ); items.push_back("4A50 (64K 4A50 + ram)", "4A50" ); items.push_back("4K (4K Atari)", "4K" ); items.push_back("4KSC (CPUWIZ 4K + ram)", "4KSC" ); items.push_back("AR (Supercharger)", "AR" ); items.push_back("BF (CPUWIZ 256K)", "BF" ); items.push_back("BFSC (CPUWIZ 256K + ram)", "BFSC" ); items.push_back("CV (Commavid extra ram)", "CV" ); items.push_back("CM (SpectraVideo CompuMate)", "CM" ); items.push_back("DF (CPUWIZ 128K)", "DF" ); items.push_back("DFSC (CPUWIZ 128K + ram)", "DFSC" ); items.push_back("DPC (Pitfall II)", "DPC" ); items.push_back("DPC+ (Enhanced DPC)", "DPC+" ); items.push_back("E0 (8K Parker Bros)", "E0" ); items.push_back("E7 (16K M-network)", "E7" ); items.push_back("EF (64K H. Runner)", "EF" ); items.push_back("EFSC (64K H. Runner + ram)", "EFSC" ); items.push_back("F0 (Dynacom Megaboy)", "F0" ); items.push_back("F4 (32K Atari)", "F4" ); items.push_back("F4SC (32K Atari + ram)", "F4SC" ); items.push_back("F6 (16K Atari)", "F6" ); items.push_back("F6SC (16K Atari + ram)", "F6SC" ); items.push_back("F8 (8K Atari)", "F8" ); items.push_back("F8SC (8K Atari + ram)", "F8SC" ); items.push_back("FA (CBS RAM Plus)", "FA" ); items.push_back("FA2 (CBS RAM Plus 24/28K)", "FA2" ); items.push_back("FE (8K Decathlon)", "FE" ); items.push_back("MC (C. Wilkson Megacart)", "MC" ); items.push_back("SB (128-256K SUPERbank)", "SB" ); items.push_back("UA (8K UA Ltd.)", "UA" ); items.push_back("X07 (64K AtariAge)", "X07" ); 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:", kTextAlignLeft); items.clear(); items.push_back("Default", "DEFAULT"); items.push_back("B", "B"); items.push_back("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:", kTextAlignLeft); // ... 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:", kTextAlignLeft); items.clear(); items.push_back("Default", "DEFAULT"); items.push_back("Color", "COLOR"); items.push_back("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:", kTextAlignLeft); items.clear(); items.push_back("Console", "false"); items.push_back("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:", kTextAlignLeft); xpos += 10; ypos += lineHeight; new StaticTextWidget(this, infofont, xpos, ypos+1, _w - 40, infofont.getFontHeight(), "(*) Buttons are automatically released shortly", kTextAlignLeft); ypos += infofont.getLineHeight(); new StaticTextWidget(this, infofont, xpos, ypos+1, _w - 40, infofont.getFontHeight(), " after emulation has started", kTextAlignLeft); // 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", kTextAlignLeft); ypos += infofont.getLineHeight(); new StaticTextWidget(this, infofont, xpos, ypos, _w - 20, infofont.getFontHeight(), " further ROMs until clicking 'Defaults'", kTextAlignLeft); // Add Defaults, OK and Cancel buttons ButtonWidget* b; b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Defaults", kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font, "Load ROM", "Close"); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GlobalPropsDialog::~GlobalPropsDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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:", kTextAlignLeft); 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:", kTextAlignLeft); 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:", kTextAlignLeft); 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 kOKCmd: saveConfig(); close(); // Inform parent to load the ROM sendCommand(LauncherDialog::kLoadROMCmd, 0, 0); break; case kDefaultsCmd: setDefaults(); saveConfig(); break; default: Dialog::handleCommand(sender, cmd, data, 0); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* GlobalPropsDialog::ourJoyState[10] = { "U", "D", "L", "R", "F", "U", "D", "L", "R", "F" }; stella-3.9.3/src/gui/Menu.cxx0000644000175000001440000000313112266336753015415 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Menu.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Dialog.hxx" #include "OptionsDialog.hxx" #include "bspf.hxx" #include "Menu.hxx" class Properties; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Menu::Menu(OSystem* osystem) : DialogContainer(osystem) { // This dialog is overlaid on the main TIA screen; we make sure it will fit // If the TIA can use 1x mode, it implies that the overlay can be no larger // than 320x240 // Otherwise we can use 2x mode, in which 640x420 is the minimum TIA size int dw = osystem->desktopWidth(), dh = osystem->desktopHeight(); if(dw < 640 || dh < 480) { dw = 320; dh = 240; } else { dw = 480; dh = 380; } myBaseDialog = new OptionsDialog(myOSystem, this, 0, dw, dh, false); // in game mode } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Menu::~Menu() { } stella-3.9.3/src/gui/LoggerDialog.cxx0000644000175000001440000001102712266336753017053 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: LoggerDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "bspf.hxx" #include "Dialog.hxx" #include "DialogContainer.hxx" #include "FSNode.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "Settings.hxx" #include "PopUpWidget.hxx" #include "StringListWidget.hxx" #include "StringParser.hxx" #include "Widget.hxx" #include "LoggerDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LoggerDialog::LoggerDialog(OSystem* osystem, DialogContainer* parent, const GUI::Font& font, int max_w, int max_h) : Dialog(osystem, parent, 0, 0, 0, 0), myLogInfo(NULL) { 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 = BSPF_min(max_w, 480); _h = BSPF_min(max_h, 380); // Test listing of the log output xpos = 10; ypos = 10; myLogInfo = new StringListWidget(this, instance().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; items.clear(); items.push_back("None", "0"); items.push_back("Basic", "1"); items.push_back("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", kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LoggerDialog::~LoggerDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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().c_str(), ios::out); if(out.is_open()) { out << instance().logMessages(); out.close(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LoggerDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case kOKCmd: saveConfig(); close(); break; case kDefaultsCmd: saveLogFile(); break; default: Dialog::handleCommand(sender, cmd, data, 0); break; } } stella-3.9.3/src/gui/ConsoleFont.hxx0000644000175000001440000011310212266336753016747 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ConsoleFont.hxx 2838 2014-01-17 23:34:03Z stephena $ // // 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 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, 0x2400, 0x1800, 0x7e00, 0x1800, 0x2400, 0x0000, 0x0000, 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, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 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, 30, 97, console_font_bits, 0, /* no encode table*/ 0, /* fixed width*/ 0, /* fixed bbox*/ 32, // Originally 30 sizeof(console_font_bits)/sizeof(uInt16) }; } // End of namespace GUI #endif stella-3.9.3/src/gui/LauncherFilterDialog.hxx0000644000175000001440000000456712266336753020563 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: LauncherFilterDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef LAUNCHER_FILTER_DIALOG_HXX #define LAUNCHER_FILTER_DIALOG_HXX class CommandSender; class DialogContainer; class CheckboxWidget; class PopUpWidget; class OSystem; class StringList; #include "Dialog.hxx" #include "FSNode.hxx" #include "Settings.hxx" #include "bspf.hxx" class LauncherFilterDialog : public Dialog, public CommandSender { public: LauncherFilterDialog(GuiObject* boss, const GUI::Font& font); virtual ~LauncherFilterDialog(); /** 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(); void saveConfig(); void setDefaults(); void handleFileTypeChange(const string& type); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); private: PopUpWidget* myFileType; CheckboxWidget* myRomType[5]; enum { kFileTypeChanged = 'LFDc' }; // Holds static strings representing ROM types static const char* ourRomTypes[2][5]; }; #endif stella-3.9.3/src/gui/AboutDialog.cxx0000644000175000001440000001754712266336753016723 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: AboutDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Dialog.hxx" #include "OSystem.hxx" #include "Version.hxx" #include "Widget.hxx" #include "AboutDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AboutDialog::AboutDialog(OSystem* osystem, DialogContainer* parent, const GUI::Font& font) : Dialog(osystem, parent, 0, 0, 0, 0), myPage(1), myNumPages(4), myLinesPerPage(12) { 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 = 52 * fontWidth + 8; _h = 14 * lineHeight + 20; // Add Previous, Next and Close buttons xpos = 10; ypos = _h - buttonHeight - 10; myPrevButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Previous", kPrevCmd); myPrevButton->clearFlags(WIDGET_ENABLED); wid.push_back(myPrevButton); xpos += buttonWidth + 7; myNextButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Next", kNextCmd); wid.push_back(myNextButton); xpos = _w - buttonWidth - 10; ButtonWidget* b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Close", kCloseCmd); wid.push_back(b); addOKWidget(b); addCancelWidget(b); xpos = 5; ypos = 5; myTitle = new StaticTextWidget(this, font, xpos, ypos, _w - 10, fontHeight, "", kTextAlignCenter); 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, "", kTextAlignLeft)); myDescStr.push_back(""); ypos += fontHeight; } addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AboutDialog::~AboutDialog() { myDesc.clear(); myDescStr.clear(); } // 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) { #define ADD_ATEXT(d) do { myDescStr[i] = d; i++; } while(0) #define ADD_ALINE ADD_ATEXT("") int i = 0; 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-2014 The Stella Team"); ADD_ATEXT("\\C(http://stella.sf.net)"); ADD_ALINE; ADD_ATEXT("\\CStella is now DonationWare!"); ADD_ATEXT("\\C(http://stella.sf.net/donations.php)"); 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"" Bradford W. Mott"); ADD_ATEXT("\\L\\c2"" Original author"); ADD_ATEXT("\\L\\c0"" Stephen Anthony"); ADD_ATEXT("\\L\\c2"" Lead developer, Linux/MacOS X/Win32 maintainer"); ADD_ATEXT("\\L\\c0"" Eckhard Stolberg"); ADD_ATEXT("\\L\\c2"" Emulation core development"); ADD_ATEXT("\\L\\c0"" Brian Watson"); ADD_ATEXT("\\L\\c2"" Emulation core enhancement, debugger support"); break; case 3: title = "Contributors"; ADD_ATEXT("\\L\\c0"" See http://stella.sf.net/credits.php 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(); TextAlignment align = kTextAlignCenter; uInt32 color = kTextColor; while (str[0] == '\\') { switch (str[1]) { case 'C': align = kTextAlignCenter; break; case 'L': align = kTextAlignLeft; break; case 'R': align = kTextAlignRight; 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 kNextCmd: myPage++; if(myPage >= myNumPages) myNextButton->clearFlags(WIDGET_ENABLED); if(myPage >= 2) myPrevButton->setFlags(WIDGET_ENABLED); displayInfo(); break; case 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-3.9.3/src/gui/InputTextDialog.hxx0000644000175000001440000000427512266336753017614 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: InputTextDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef INPUT_TEXT_DIALOG_HXX #define INPUT_TEXT_DIALOG_HXX class GuiObject; class StaticTextWidget; class EditTextWidget; #include "Dialog.hxx" #include "Command.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(); /** 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 setEmitSignal(int cmd) { myCmd = cmd; } void setTitle(const string& title); void setFocus(int idx = 0); /** This dialog uses its own positioning, so we override Dialog::center() */ void center(); protected: void initialize(const GUI::Font& lfont, const GUI::Font& nfont, const StringList& labels); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); private: typedef Common::Array InputWidget; InputWidget myInput; StaticTextWidget* myTitle; bool myEnableCenter; bool myErrorFlag; int myCmd; uInt32 myXOrig, myYOrig; }; #endif stella-3.9.3/src/gui/Widget.hxx0000644000175000001440000002125412266336753015747 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Widget.hxx 2838 2014-01-17 23:34:03Z stephena $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #include "Dialog.hxx" #ifndef WIDGET_HXX #define WIDGET_HXX #include #include "bspf.hxx" #include "Array.hxx" #include "Event.hxx" #include "Font.hxx" #include "FrameBuffer.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "Rect.hxx" #include "StellaKeys.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 @version $Id: Widget.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 { return _x + _boss->getChildX(); } virtual int getAbsY() const { return _y + _boss->getChildY(); } virtual bool handleKeyDown(StellaKey key, StellaMod mod, char ascii) { return false; } virtual bool handleKeyUp(StellaKey key, StellaMod mod, char ascii) { return false; } virtual void handleMouseDown(int x, int y, int button, int clickCount) {} virtual void handleMouseUp(int x, int y, int button, int clickCount) {} virtual void handleMouseEntered(int button) {} virtual void handleMouseLeft(int button) {} virtual void handleMouseMoved(int x, int y, int button) {} virtual void handleMouseWheel(int x, int y, int direction) {} virtual bool handleMouseClicks(int x, int y, int button) { 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, int value) { return false; } virtual bool handleEvent(Event::Type event) { return false; } void draw(); void receivedFocus(); void lostFocus(); void addFocusWidget(Widget* w) { _focusList.push_back(w); } /** Set/clear WIDGET_ENABLED flag and immediately redraw */ void setEnabled(bool e); void setFlags(int flags) { _flags |= flags; } void clearFlags(int flags) { _flags &= ~flags; } int getFlags() const { return _flags; } bool isEnabled() const { return _flags & WIDGET_ENABLED; } bool isVisible() const { return !(_flags & WIDGET_INVISIBLE); } 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; } 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() { assert(_boss); _boss->releaseFocus(); } // By default, delegate unhandled commands to the boss void handleCommand(CommandSender* sender, int cmd, int data, int id) { 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; 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); /** Sets all widgets in this chain to be dirty (must be redrawn) */ static void setDirtyInChain(Widget* start); }; /* StaticTextWidget */ class StaticTextWidget : public Widget { public: StaticTextWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const string& text, TextAlignment align); void setValue(int value); void setLabel(const string& label); void setAlign(TextAlignment align) { _align = align; } const string& getLabel() const { return _label; } protected: void drawWidget(bool hilite); protected: string _label; bool _editable; TextAlignment _align; }; /* 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); void setCmd(int cmd) { _cmd = cmd; } int getCmd() const { return _cmd; } virtual void handleMouseUp(int x, int y, int button, int clickCount); virtual void handleMouseEntered(int button); virtual void handleMouseLeft(int button); virtual bool handleEvent(Event::Type event); protected: void drawWidget(bool hilite); protected: int _cmd; }; /* CheckboxWidget */ class CheckboxWidget : public ButtonWidget { public: enum FillType { Normal, Inactive, Circle }; public: CheckboxWidget(GuiObject* boss, const GUI::Font& font, int x, int y, const string& label, int cmd = 0); void handleMouseUp(int x, int y, int button, int clickCount); virtual void handleMouseEntered(int button) {} virtual void handleMouseLeft(int button) {} void setEditable(bool editable); void setFill(FillType type); void setState(bool state); void toggleState() { setState(!_state); } bool getState() const { return _state; } static int boxSize() { return 14; } // box is square protected: void drawWidget(bool hilite); protected: bool _state; bool _holdFocus; bool _drawBox; uInt32* _img; uInt32 _fillColor; private: int _boxY; int _textY; }; /* 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; } virtual void handleMouseMoved(int x, int y, int button); virtual void handleMouseDown(int x, int y, int button, int clickCount); virtual void handleMouseUp(int x, int y, int button, int clickCount); virtual void handleMouseWheel(int x, int y, int direction); virtual bool handleEvent(Event::Type event); protected: void drawWidget(bool hilite); int valueToPos(int value); int posToValue(int pos); protected: int _value, _stepValue; int _valueMin, _valueMax; bool _isDragging; int _labelWidth; }; #endif stella-3.9.3/src/gui/SnapshotDialog.hxx0000644000175000001440000000374212266336753017445 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SnapshotDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef SNAPSHOT_DIALOG_HXX #define SNAPSHOT_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 SnapshotDialog : public Dialog { public: SnapshotDialog(OSystem* osystem, DialogContainer* parent, const GUI::Font& font, GuiObject* boss, int max_w, int max_h); ~SnapshotDialog(); void handleCommand(CommandSender* sender, int cmd, int data, int id); private: void loadConfig(); void saveConfig(); void setDefaults(); 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) }; BrowserDialog* myBrowser; // Config paths EditTextWidget* mySnapSavePath; EditTextWidget* mySnapLoadPath; PopUpWidget* mySnapName; PopUpWidget* mySnapInterval; CheckboxWidget* mySnapSingle; CheckboxWidget* mySnap1x; }; #endif stella-3.9.3/src/gui/ProgressDialog.cxx0000644000175000001440000000624112266336753017442 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ProgressDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #include "Widget.hxx" #include "Dialog.hxx" #include "DialogContainer.hxx" #include "ProgressDialog.hxx" #include "bspf.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ProgressDialog::ProgressDialog(GuiObject* boss, const GUI::Font& font, const string& message) : Dialog(&boss->instance(), &boss->parent(), 0, 0, 16, 16), myMessage(NULL), mySlider(NULL), 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, kTextAlignCenter); 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(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ProgressDialog::~ProgressDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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-3.9.3/src/gui/ComboDialog.hxx0000644000175000001440000000275712266336753016712 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ComboDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef COMBO_DIALOG_HXX #define COMBO_DIALOG_HXX class PopUpWidget; class EditTextWidget; class StaticTextWidget; class VariantList; class OSystem; #include "Dialog.hxx" #include "bspf.hxx" class ComboDialog : public Dialog { public: ComboDialog(GuiObject* boss, const GUI::Font& font, const VariantList& combolist); ~ComboDialog(); /** Place the dialog onscreen and center it */ void show(Event::Type event, const string& name); private: void loadConfig(); void saveConfig(); void setDefaults(); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); private: Event::Type myComboEvent; StaticTextWidget* myComboName; PopUpWidget* myEvents[8]; }; #endif stella-3.9.3/src/gui/EditableWidget.hxx0000644000175000001440000000522212266336753017376 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: EditableWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef EDITABLE_WIDGET_HXX #define EDITABLE_WIDGET_HXX #include "Widget.hxx" #include "Rect.hxx" /** * Base class for widgets which need to edit text, like ListWidget and * EditTextWidget. */ class EditableWidget : public Widget, public CommandSender { public: 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(); virtual void setText(const string& str, bool changed = false); virtual const string& getText() const { return _editString; } bool isEditable() const { return _editable; } void setEditable(bool editable); virtual bool handleKeyDown(StellaKey key, StellaMod mod, char ascii); // We only want to focus this widget when we can edit its contents virtual bool wantsFocus() { return _editable; } 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(); virtual bool tryInsertChar(char c, int pos); private: // Line editing bool specialKeys(StellaKey key, char ascii); bool killChar(int direction); bool killLine(int direction); bool killLastWord(); bool moveWord(int direction); // Clipboard void copySelectedText(); void pasteSelectedText(); protected: bool _editable; string _editString; bool _caretVisible; int _caretTime; int _caretPos; bool _caretInverse; int _editScrollOffset; static string _clippedText; }; #endif stella-3.9.3/src/gui/StellaMediumFont.hxx0000644000175000001440000014365112266336753017746 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: StellaMediumFont.hxx 2838 2014-01-17 23:34:03Z stephena $ // // 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 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, 30, 97, stellaMedium_font_bits, 0, /* no encode table*/ 0, /* fixed width*/ 0, /* fixed bbox*/ 32, // Originally 30 sizeof(stellaMedium_font_bits)/sizeof(uInt16) }; } // End of namespace GUI #endif stella-3.9.3/src/gui/LauncherDialog.cxx0000644000175000001440000004501012266336753017374 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: LauncherDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #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 "Props.hxx" #include "PropsSet.hxx" #include "RomInfoWidget.hxx" #include "Settings.hxx" #include "StringList.hxx" #include "StringListWidget.hxx" #include "Widget.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, true), // use base surface myStartButton(NULL), myPrevDirButton(NULL), myOptionsButton(NULL), myQuitButton(NULL), myList(NULL), myGameList(NULL), myRomInfoWidget(NULL), myMenu(NULL), myGlobalProps(NULL), myFilters(NULL), myFirstRunMsg(NULL), myRomDir(NULL), mySelectedItem(0) { const GUI::Font& font = instance().launcherFont(); const int fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), bwidth = (_w - 2 * 10 - 8 * (4 - 1)) / 4, bheight = font.getLineHeight() + 4; int xpos = 0, ypos = 0, lwidth = 0, lwidth2 = 0, fwidth = 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 ...", kTextAlignLeft); lwidth2 = font.getStringWidth("XXXX items found"); xpos = _w - lwidth2 - 10; myRomCount = new StaticTextWidget(this, font, xpos, ypos, lwidth2, fontHeight, "", kTextAlignRight); // Add filter that can narrow the results shown in the listing // It has to fit between both labels if(w >= 640) { fwidth = BSPF_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 - 28 - 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().smallFont() : instance().infoFont(), xpos, ypos, romWidth, myList->getHeight()); } // Add note textwidget to show any notes for the currently selected ROM xpos = 10; xpos += 5; ypos += myList->getHeight() + 4; lwidth = font.getStringWidth("Note:"); myDirLabel = new StaticTextWidget(this, font, xpos, ypos, lwidth, fontHeight, "Dir:", kTextAlignLeft); xpos += lwidth + 5; myDir = new StaticTextWidget(this, font, xpos, ypos, _w - xpos - 10, fontHeight, "", kTextAlignLeft); // Add four buttons at the bottom xpos = 10; ypos += myDir->getHeight() + 4; #ifndef 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", kOptionsCmd); wid.push_back(myOptionsButton); xpos += bwidth + 8; myQuitButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight, "Quit", kQuitCmd); wid.push_back(myQuitButton); xpos += bwidth + 8; #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", 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); xpos += bwidth + 8; #endif mySelectedItem = 0; // Highlight 'Rom Listing' // Create an options dialog, similar to the in-game one myOptions = new OptionsDialog(osystem, parent, this, int(w * 0.8), int(h * 0.8), true); // Create a game list, which contains all the information about a ROM that // the launcher needs myGameList = new GameList(); addToFocusList(wid); // Create context menu for ROM list options VariantList l; l.push_back("Power-on options", "override"); l.push_back("Filter listing", "filter"); l.push_back("Reload listing", "reload"); myMenu = new ContextMenu(this, osystem->font(), l); // Create global props dialog, which is used to temporarily overrride // ROM properties myGlobalProps = new GlobalPropsDialog(this, osystem->font()); // Create dialog whereby the files shown in the ROM listing can be customized myFilters = new LauncherFilterDialog(this, osystem->font()); // Figure out which filters are needed for the ROM listing setListFilters(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LauncherDialog::~LauncherDialog() { delete myOptions; delete myGameList; delete myMenu; delete myGlobalProps; delete myFilters; delete myRomDir; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(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 = new GUI::MessageBox(this, instance().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().isEmpty()) { 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::enableButtons(bool enable) { myStartButton->setEnabled(enable); myPrevDirButton->setEnabled(enable); myOptionsButton->setEnabled(enable); myQuitButton->setEnabled(enable); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::updateListing(const string& nameToSelect) { // Start with empty list myGameList->clear(); myDir->setLabel(""); loadDirListing(); // Only hilite the 'up' button if there's a parent directory myPrevDirButton->setEnabled(myCurrentNode.hasParent()); // Show current directory myDir->setLabel(myCurrentNode.getShortPath()); // Now fill the list widget with the contents of the GameList StringList l; for (int i = 0; i < (int) 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(unsigned int idx = 0; idx < files.size(); idx++) { bool isDir = files[idx].isDirectory(); const string& name = isDir ? (" [" + files[idx].getName() + "]") : files[idx].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, files[idx].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(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(); unsigned char b = tolower((unsigned char) *needle); needle++; for (;; haystack++) { if (*haystack == '\0') /* No match */ return false; /* The first character matches */ if (tolower ((unsigned char) *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 ((unsigned char) *rhaystack) != tolower ((unsigned char) *rneedle)) break; } } } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::handleKeyDown(StellaKey key, StellaMod mod, char ascii) { // Grab the key before passing it to the actual dialog and check for // Control-R (reload ROM listing) if(instance().eventHandler().kbdControl(mod) && key == KBDK_r) updateListing(); else Dialog::handleKeyDown(key, mod, ascii); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::handleMouseDown(int x, int y, int button, int clickCount) { // Grab right mouse button for context menu, send left to base class if(button == 2) { // Add menu at current x,y mouse location myMenu->show(x + getAbsX(), y + getAbsY()); } else Dialog::handleMouseDown(x, y, button, 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, kMiddleCenter, 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 = new BrowserDialog(this, instance().font(), _w, _h); myRomDir->show("Select ROM directory:", "~", BrowserDialog::Directories, kStartupRomDirChosenCmd); break; case kStartupRomDirChosenCmd: { FilesystemNode dir(myRomDir->getResult()); instance().settings().setValue("romdir", dir.getShortPath()); // fall through to the next case } 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-3.9.3/src/gui/OptionsDialog.hxx0000644000175000001440000000505712266336753017302 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: OptionsDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef OPTIONS_DIALOG_HXX #define OPTIONS_DIALOG_HXX class CommandSender; class DialogContainer; class GuiObject; class VideoDialog; class AudioDialog; class InputDialog; class UIDialog; class SnapshotDialog; class ConfigPathDialog; class RomAuditDialog; class GameInfoDialog; class CheatCodeDialog; class HelpDialog; class AboutDialog; class LoggerDialog; class OSystem; #include "Dialog.hxx" #include "bspf.hxx" class OptionsDialog : public Dialog { public: OptionsDialog(OSystem* osystem, DialogContainer* parent, GuiObject* boss, int max_w, int max_h, bool global); virtual ~OptionsDialog(); private: void loadConfig(); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); private: VideoDialog* myVideoDialog; AudioDialog* myAudioDialog; InputDialog* myInputDialog; UIDialog* myUIDialog; SnapshotDialog* mySnapshotDialog; ConfigPathDialog* myConfigPathDialog; RomAuditDialog* myRomAuditDialog; GameInfoDialog* myGameInfoDialog; CheatCodeDialog* myCheatCodeDialog; LoggerDialog* myLoggerDialog; HelpDialog* myHelpDialog; AboutDialog* myAboutDialog; ButtonWidget* myRomAuditButton; ButtonWidget* myGameInfoButton; ButtonWidget* myCheatCodeButton; // Indicates if this dialog is used for global (vs. in-game) settings bool myIsGlobal; enum { kVidCmd = 'VIDO', kAudCmd = 'AUDO', kInptCmd = 'INPT', kUsrIfaceCmd = 'URIF', kSnapCmd = 'SNAP', kCfgPathsCmd = 'CFGP', kAuditCmd = 'RAUD', kInfoCmd = 'INFO', kCheatCmd = 'CHET', kLoggerCmd = 'LOGG', kHelpCmd = 'HELP', kAboutCmd = 'ABOU', kExitCmd = 'EXIM' }; }; #endif stella-3.9.3/src/gui/TabWidget.hxx0000644000175000001440000000577412266336753016407 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TabWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef TAB_WIDGET_HXX #define TAB_WIDGET_HXX #include "bspf.hxx" #include "Array.hxx" #include "Command.hxx" #include "Widget.hxx" class TabWidget : public Widget, public CommandSender { public: TabWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h); ~TabWidget(); virtual int getChildY() const; // 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; } virtual void handleMouseDown(int x, int y, int button, int clickCount); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); virtual bool handleEvent(Event::Type event); virtual void loadConfig(); protected: virtual void drawWidget(bool hilite); virtual Widget* findWidget(int x, int y); private: struct Tab { string title; Widget* firstWidget; Widget* parentWidget; bool enabled; Tab(const string& t = "", Widget* first = 0, Widget* parent = 0, bool e = true) : title(t), firstWidget(first), parentWidget(parent), enabled(e) { } }; typedef Common::Array TabList; TabList _tabs; int _tabWidth; int _tabHeight; int _activeTab; bool _firstTime; enum { kTabLeftOffset = 4, kTabSpacing = 2, kTabPadding = 3 }; private: void box(int x, int y, int width, int height, uInt32 colorA, uInt32 colorB, bool omitBottom); void updateActiveTab(); }; #endif stella-3.9.3/src/gui/FileListWidget.cxx0000644000175000001440000000761012266336753017376 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FileListWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FileListWidget::~FileListWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(unsigned int idx = 0; idx < content.size(); idx++) { string name = content[idx].getName(); bool isDir = content[idx].isDirectory(); if(isDir) name = " [" + name + "]"; else if(!BSPF_endsWithIgnoreCase(name, _extension)) continue; _gameList.appendGame(name, content[idx].getPath(), "", isDir); } _gameList.sortByName(); // Now fill the list widget with the contents of the GameList StringList l; for (int i = 0; i < (int) _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-3.9.3/src/gui/ListWidget.cxx0000644000175000001440000003077212266336753016603 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ListWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "OSystem.hxx" #include "Widget.hxx" #include "ScrollBarWidget.hxx" #include "Dialog.hxx" #include "FrameBuffer.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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ListWidget::~ListWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::setSelected(int item) { if(item < -1 || item >= (int)_list.size()) 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.isEmpty()) { if(item == "") selected = 0; else { uInt32 itemToSelect = 0; StringList::const_iterator iter; for(iter = _list.begin(); iter != _list.end(); ++iter, ++itemToSelect) { if(item == *iter) { selected = itemToSelect; break; } } 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 = _list.size(); if (item >= size) item = size - 1; if (item < 0) item = 0; if(_currentPos != item) { _currentPos = item; scrollBarRecalc(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::recalc() { int size = _list.size(); if (_currentPos >= size) _currentPos = size - 1; if (_currentPos < 0) _currentPos = 0; if(_selectedItem < 0 || _selectedItem >= size) _selectedItem = 0; _editMode = false; _scrollBar->_numEntries = _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, int button, 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(); draw(); } // 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, int button, 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(_editable && !_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::handleKeyDown(StellaKey key, StellaMod mod, char ascii) { // Ignore all Alt-mod keys if(instance().eventHandler().kbdAlt(mod)) return true; bool handled = true; int oldSelectedItem = _selectedItem; if (!_editMode && _quickSelect && ((isalnum(ascii)) || isspace(ascii))) { // 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 = ascii; else _quickSelectStr += ascii; _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 (StringList::const_iterator i = _list.begin(); i != _list.end(); ++i) { 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::handleKeyDown(key, mod, ascii); } else { // not editmode 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) { _scrollBar->draw(); scrollToSelected(); sendCommand(ListWidget::kSelectionChangedCmd, _selectedItem, _id); } _currentKeyDown = key; return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ListWidget::handleKeyUp(StellaKey key, StellaMod mod, char ascii) { 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; switch(e) { case Event::UISelect: if (_selectedItem >= 0) { if (_editable) startEditMode(); else sendCommand(ListWidget::kActivatedCmd, _selectedItem, _id); } break; case Event::UIUp: if (_selectedItem > 0) _selectedItem--; break; case Event::UIDown: if (_selectedItem < (int)_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)_list.size() ) _selectedItem = _list.size() - 1; break; case Event::UIHome: _selectedItem = 0; break; case Event::UIEnd: _selectedItem = _list.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 kSetPositionCmd: if (_currentPos != (int)data) { _currentPos = data; setDirty(); draw(); // 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 = _list.size() - _rows; int oldScrollPos = _scrollBar->_currentPos; _scrollBar->_currentPos = _currentPos; _scrollBar->recalc(); setDirty(); draw(); if(oldScrollPos != _currentPos) sendCommand(ListWidget::kScrolledCmd, _currentPos, _id); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::startEditMode() { if (_editable && !_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-3.9.3/src/gui/RomInfoWidget.cxx0000644000175000001440000001345712266336753017242 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RomInfoWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "FrameBuffer.hxx" #include "OSystem.hxx" #include "Settings.hxx" #include "Widget.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), mySurface(NULL), mySurfaceID(-1), myZoomLevel(w > 400 ? 2 : 1), mySurfaceIsValid(false), myHaveProperties(false) { _flags = WIDGET_ENABLED; _bgcolor = _bgcolorhi = kWidColor; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RomInfoWidget::~RomInfoWidget() { myRomInfo.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(); setDirty(); draw(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomInfoWidget::setProperties(const Properties& props) { myHaveProperties = true; myProperties = props; // Decide whether the information should be shown immediately if(instance().eventHandler().state() == EventHandler::S_LAUNCHER) { parseProperties(); setDirty(); draw(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomInfoWidget::clearProperties() { myHaveProperties = mySurfaceIsValid = false; // Decide whether the information should be shown immediately if(instance().eventHandler().state() == EventHandler::S_LAUNCHER) { setDirty(); draw(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 mySurface = instance().frameBuffer().surface(mySurfaceID); if(mySurface == NULL) { mySurfaceID = instance().frameBuffer().allocateSurface( 320*myZoomLevel, 256*myZoomLevel, false); mySurface = instance().frameBuffer().surface(mySurfaceID); } else { mySurface->setWidth(320*myZoomLevel); mySurface->setHeight(256*myZoomLevel); } // Initialize to empty properties entry mySurfaceErrorMsg = ""; mySurfaceIsValid = false; 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 { mySurfaceIsValid = instance().png().loadImage(filename, instance().frameBuffer(), *mySurface); } catch(const char* msg) { mySurfaceIsValid = false; mySurfaceErrorMsg = msg; } // 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)); myRomInfo.push_back("Controllers: " + myProperties.get(Controller_Left) + " (left), " + myProperties.get(Controller_Right) + " (right)"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomInfoWidget::drawWidget(bool hilite) { FBSurface& s = dialog().surface(); const int yoff = myZoomLevel > 1 ? 260*2 + 10 : 275; 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) { uInt32 x = _x + ((_w - mySurface->getWidth()) >> 1); uInt32 y = _y + ((yoff - mySurface->getHeight()) >> 1); s.drawSurface(mySurface, x, y); } else if(mySurfaceErrorMsg != "") { const GUI::Font& font = instance().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(unsigned int i = 0; i < myRomInfo.size(); ++i) { s.drawString(_font, myRomInfo[i], xpos, ypos, _w - 10, _textcolor); ypos += _font.getLineHeight(); } } /* cerr << "surface:" << endl << " w = " << sw << endl << " h = " << sh << endl << " szoom = " << myZoomLevel << endl << " spitch = " << spitch << endl << endl; cerr << "image:" << endl << " width = " << width << endl << " height = " << height << endl << " izoom = " << izoom << endl << " ipitch = " << ipitch << endl << " bufsize = " << bufsize << endl << " buf_offset = " << buf_offset << endl << " i_offset = " << i_offset << endl << endl; */ stella-3.9.3/src/gui/CheckListWidget.cxx0000644000175000001440000001374512266336753017542 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CheckListWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "CheckListWidget.hxx" #include "Widget.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 = BSPF_max(_fontHeight, CheckboxWidget::boxSize()); _rows = h / _fontHeight; // Create a CheckboxWidget for each row in the list CheckboxWidget* t; for(int i = 0; i < _rows; ++i) { t = new CheckboxWidget(boss, font, _x + 2, ypos, "", kCheckActionCmd); t->setTextColor(kTextColor); t->setTarget(this); t->setID(i); ypos += _fontHeight; _checkList.push_back(t); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CheckListWidget::~CheckListWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 = _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 = _list.size(); string buffer; int deltax; // 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; 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); else s.frameRect(_x + r.left - 3, _y + 1 + _fontHeight * i, _w - r.left, _fontHeight, kTextColorHi); } if (_selectedItem == pos && _editMode) { buffer = _editString; adjustOffset(); deltax = -_editScrollOffset; s.drawString(_font, buffer, _x + r.left, y, r.width(), kTextColor, kTextAlignLeft, deltax, false); } else { buffer = _list[pos]; deltax = 0; s.drawString(_font, buffer, _x + r.left, y, r.width(), kTextColor); } } // 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, 1, 0); return true; break; default: return ListWidget::handleEvent(e); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheckListWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case kCheckActionCmd: { // Figure out which line has been checked int line = _currentPos + id; _stateList[line] = bool(data); // Let the boss know about it sendCommand(kListItemChecked, line, _id); break; } default: ListWidget::handleCommand(sender, cmd, data, id); break; } } stella-3.9.3/src/gui/HelpDialog.hxx0000644000175000001440000000326412266336753016535 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: HelpDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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); ~HelpDialog(); protected: 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: virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); virtual void updateStrings(uInt8 page, uInt8 lines, string& title); void displayInfo(); void loadConfig() { displayInfo(); } }; #endif stella-3.9.3/src/gui/RomAuditDialog.hxx0000644000175000001440000000412712266336753017370 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RomAuditDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef ROM_AUDIT_DIALOG_HXX #define ROM_AUDIT_DIALOG_HXX class OSystem; class GuiObject; class DialogContainer; class BrowserDialog; class EditTextWidget; class StaticTextWidget; #include "Dialog.hxx" #include "Command.hxx" #include "FSNode.hxx" #include "MessageBox.hxx" class RomAuditDialog : public Dialog { public: RomAuditDialog(OSystem* osystem, DialogContainer* parent, const GUI::Font& font, int max_w, int max_h); ~RomAuditDialog(); void handleCommand(CommandSender* sender, int cmd, int data, int id); private: void loadConfig(); void auditRoms(); void openBrowser(const string& title, const string& startpath, FilesystemNode::ListMode mode, int cmd); private: enum { kChooseAuditDirCmd = 'RAsl', // audit dir select kAuditDirChosenCmd = 'RAch', // audit dir changed kConfirmAuditCmd = 'RAcf' // confirm rom audit }; // ROM audit path EditTextWidget* myRomPath; // Show the results of the ROM audit StaticTextWidget* myResults1; StaticTextWidget* myResults2; // Select a new ROM audit path BrowserDialog* myBrowser; // Show a message about the dangers of using this function GUI::MessageBox* myConfirmMsg; // Maximum width and height for this dialog int myMaxWidth, myMaxHeight; }; #endif stella-3.9.3/src/gui/PopUpWidget.cxx0000644000175000001440000001222212266336753016721 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: PopUpWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "FrameBuffer.hxx" #include "ContextMenu.hxx" #include "DialogContainer.hxx" #include "PopUpWidget.hxx" #define UP_DOWN_BOX_HEIGHT 10 // Little up/down arrow static unsigned int up_down_arrows[8] = { 0x00000000, 0x00001000, 0x00011100, 0x00111110, 0x00000000, 0x00111110, 0x00011100, 0x00001000, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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) { _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS; _bgcolor = kDlgColor; _bgcolorhi = kWidColor; _textcolor = kTextColor; _textcolorhi = kTextColor; if(!_label.empty() && _labelWidth == 0) _labelWidth = _font.getStringWidth(_label); _w = w + _labelWidth + 15; // vertically center the arrows and text myTextY = (_h - _font.getFontHeight()) / 2; myArrowsY = (_h - 8) / 2; myMenu = new ContextMenu(this, font, list, cmd); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PopUpWidget::~PopUpWidget() { delete myMenu; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PopUpWidget::handleMouseDown(int x, int y, int button, int clickCount) { if(isEnabled() && !myMenu->isVisible()) { // Add menu just underneath parent widget const GUI::Rect& image = instance().frameBuffer().imageRect(); uInt32 tx, ty; dialog().surface().getPos(tx, ty); 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(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PopUpWidget::handleEvent(Event::Type e) { if(!isEnabled()) return false; switch(e) { case Event::UISelect: handleMouseDown(0, 0, 1, 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; // Draw the label, if any if (_labelWidth > 0) s.drawString(_font, _label, _x, _y + myTextY, _labelWidth, isEnabled() ? _textcolor : kColor, kTextAlignRight); // 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, 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); // Draw the selected entry, if any const string& name = myMenu->getSelectedName(); TextAlignment align = (_font.getStringWidth(name) > w-6) ? kTextAlignRight : kTextAlignLeft; s.drawString(_font, name, x+2, _y+myTextY, w-6, !isEnabled() ? kColor : kTextColor, align); } stella-3.9.3/src/gui/Font.cxx0000644000175000001440000000374212266336753015427 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Font.cxx 2838 2014-01-17 23:34:03Z stephena $ // // 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 * str.size(); else { int space = 0; for(unsigned int i = 0; i < str.size(); ++i) space += getCharWidth(str[i]); return space; } } } // namespace GUI stella-3.9.3/src/gui/Dialog.hxx0000644000175000001440000001076512266336753015730 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Dialog.hxx 2838 2014-01-17 23:34:03Z stephena $ // // 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; #include "Command.hxx" #include "Widget.hxx" #include "GuiObject.hxx" #include "StellaKeys.hxx" #include "bspf.hxx" /** This is the base class for all dialog boxes. @author Stephen Anthony @version $Id: Dialog.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class Dialog : public GuiObject { friend class DialogContainer; public: Dialog(OSystem* instance, DialogContainer* parent, int x, int y, int w, int h, bool isBase = false); virtual ~Dialog(); void open(bool refresh = true); void close(bool refresh = true); bool isVisible() const { return _visible; } bool isBase() const { return _isBase; } virtual void center(); virtual void drawDialog(); virtual void loadConfig() {} virtual void saveConfig() {} virtual void setDefaults() {} void addFocusWidget(Widget* w); void addToFocusList(WidgetArray& list); void addToFocusList(WidgetArray& list, TabWidget* w, int tabId); void addBGroupToFocusList(WidgetArray& list) { _buttonGroup = list; } void redrawFocus(); void addTabWidget(TabWidget* w); void addOKWidget(Widget* w) { _okWidget = w; } void addCancelWidget(Widget* w) { _cancelWidget = w; } void setFocus(Widget* w); FBSurface& surface() const { return *_surface; } protected: virtual void draw(); void releaseFocus(); virtual void handleKeyDown(StellaKey key, StellaMod modifiers, char ascii); virtual void handleKeyUp(StellaKey key, StellaMod modifiers, char ascii); virtual void handleMouseDown(int x, int y, int button, int clickCount); virtual void handleMouseUp(int x, int y, int button, int clickCount); virtual void handleMouseWheel(int x, int y, int direction); virtual void handleMouseMoved(int x, int y, int button); virtual bool handleMouseClicks(int x, int y, int button); 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, int value); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); Widget* findWidget(int x, int y); // Find the widget at pos x,y if any void addOKCancelBGroup(WidgetArray& wid, const GUI::Font& font, const string& okText = "", const string& cancelText = ""); 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 _isBase; bool _processCancel; private: struct Focus { Widget* widget; WidgetArray list; Focus(Widget* w = 0); virtual ~Focus(); }; typedef Common::Array FocusList; struct TabFocus { TabWidget* widget; FocusList focus; uInt32 currentTab; TabFocus(TabWidget* w = 0); virtual ~TabFocus(); void appendFocusList(WidgetArray& list); void saveCurrentFocus(Widget* w); Widget* getNewFocus(); }; typedef Common::Array TabFocusList; Focus _myFocus; // focus for base dialog TabFocusList _myTabList; // focus for each tab (if any) WidgetArray _buttonGroup; FBSurface* _surface; int _tabID; }; #endif stella-3.9.3/src/gui/CommandDialog.hxx0000644000175000001440000000332212266336753017216 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CommandDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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); ~CommandDialog(); protected: virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); 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 }; }; #endif stella-3.9.3/src/gui/DialogContainer.cxx0000644000175000001440000002503112266336753017556 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DialogContainer.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #include "Dialog.hxx" #include "Stack.hxx" #include "EventHandler.hxx" #include "Joystick.hxx" #include "bspf.hxx" #include "DialogContainer.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DialogContainer::DialogContainer(OSystem* osystem) : myOSystem(osystem), myBaseDialog(NULL), myTime(0) { reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DialogContainer::~DialogContainer() { if(myBaseDialog) 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, myCurrentKeyDown.ascii); myKeyRepeatTime = myTime + kRepeatSustainDelay; } // Mouse button still pressed if(myCurrentMouseDown.button != -1 && myClickRepeatTime < myTime) { activeDialog->handleMouseDown(myCurrentMouseDown.x - activeDialog->_x, myCurrentMouseDown.y - activeDialog->_y, myCurrentMouseDown.button, 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) { for(int i = 0; i < myDialogStack.size(); i++) { myDialogStack[i]->center(); myDialogStack[i]->setDirty(); myDialogStack[i]->drawDialog(); } } else if(!myDialogStack.empty()) myDialogStack.top()->drawDialog(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::addDialog(Dialog* d) { const GUI::Rect& screen = myOSystem->frameBuffer().screenRect(); assert(d->getWidth() <= screen.width() && d->getHeight() <= screen.height()); 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 myOSystem->frameBuffer().refresh(); // Reset all continuous events reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::handleKeyEvent(StellaKey key, StellaMod mod, char ascii, 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; myCurrentKeyDown.ascii = ascii; myKeyRepeatTime = myTime + kRepeatInitialDelay; activeDialog->handleKeyDown(key, mod, ascii); } else { activeDialog->handleKeyUp(key, mod, ascii); // 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, int button) { 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, button); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::handleMouseButtonEvent(MouseButton b, int x, int y, uInt8 state) { 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); int button = (b == EVENT_LBUTTONDOWN || b == EVENT_LBUTTONUP) ? 1 : 2; switch(b) { case EVENT_LBUTTONDOWN: case EVENT_RBUTTONDOWN: // 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) && BSPF_abs(myLastClick.x - x) < 3 && BSPF_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, button)) { myCurrentMouseDown.x = x; myCurrentMouseDown.y = y; myCurrentMouseDown.button = button; myClickRepeatTime = myTime + kRepeatInitialDelay; } else myCurrentMouseDown.button = -1; activeDialog->handleMouseDown(x - activeDialog->_x, y - activeDialog->_y, button, myLastClick.count); break; case EVENT_LBUTTONUP: case EVENT_RBUTTONUP: activeDialog->handleMouseUp(x - activeDialog->_x, y - activeDialog->_y, button, myLastClick.count); if(button == myCurrentMouseDown.button) myCurrentMouseDown.button = -1; break; case EVENT_WHEELUP: activeDialog->handleMouseWheel(x - activeDialog->_x, y - activeDialog->_y, -1); break; case EVENT_WHEELDOWN: activeDialog->handleMouseWheel(x - activeDialog->_x, y - activeDialog->_y, 1); 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 == EVENT_HATCENTER) { myCurrentHatDown.stick = myCurrentHatDown.hat = -1; } else if(value != EVENT_HATCENTER) // 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.button = -1; 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-3.9.3/src/gui/Launcher.cxx0000644000175000001440000000515412266336753016261 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Launcher.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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"); myWidth = s.w; myHeight = s.h; // The launcher dialog is resizable, within certain bounds // We check those bounds now myWidth = BSPF_max(myWidth, osystem->desktopWidth() >= 640 ? 640u : 320u); myHeight = BSPF_max(myHeight, osystem->desktopHeight() >= 480 ? 480u : 240u); myWidth = BSPF_min(myWidth, osystem->desktopWidth()); myHeight = BSPF_min(myHeight, osystem->desktopHeight()); myOSystem->settings().setValue("launcherres", GUI::Size(myWidth, myHeight)); myBaseDialog = new LauncherDialog(myOSystem, this, 0, 0, myWidth, myHeight); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Launcher::~Launcher() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBInitStatus Launcher::initializeVideo() { string title = string("Stella ") + STELLA_VERSION; return myOSystem->frameBuffer().initialize(title, myWidth, myHeight); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& Launcher::selectedRomMD5() { return ((LauncherDialog*)myBaseDialog)->selectedRomMD5(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const FilesystemNode& Launcher::currentNode() const { return ((LauncherDialog*)myBaseDialog)->currentNode(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Launcher::reload() { ((LauncherDialog*)myBaseDialog)->reload(); } stella-3.9.3/src/gui/ConsoleMediumBFont.hxx0000644000175000001440000012662012266336753020223 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ConsoleMediumBFont.hxx 2838 2014-01-17 23:34:03Z stephena $ // // 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 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, 30, 97, consoleMediumB_font_bits, 0, /* no encode table*/ 0, /* fixed width*/ 0, /* fixed bbox*/ 32, // Originally 30 sizeof(consoleMediumB_font_bits)/sizeof(uInt16) }; } // End of namespace GUI #endif stella-3.9.3/src/gui/EventMappingWidget.cxx0000644000175000001440000003031012266336753020251 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: EventMappingWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "bspf.hxx" #include "EventHandler.hxx" #include "Event.hxx" #include "OSystem.hxx" #include "EditTextWidget.hxx" #include "StringListWidget.hxx" #include "Widget.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), myEventMode(mode), myActionSelected(-1), myRemapStatus(false), 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", 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", kComboCmd); myComboButton->setTarget(this); addFocusWidget(myComboButton); VariantList combolist; instance().eventHandler().getComboList(mode, combolist); myComboDialog = new ComboDialog(boss, font, combolist); } else myComboButton = NULL; // Show message for currently selected event xpos = 10; ypos = 5 + myActionsList->getHeight() + 5; StaticTextWidget* t; t = new StaticTextWidget(boss, font, xpos, ypos, font.getStringWidth("Action:"), fontHeight, "Action:", kTextAlignLeft); t->setFlags(WIDGET_CLEARBG); myKeyMapping = new EditTextWidget(boss, font, xpos + t->getWidth() + 5, ypos, _w - xpos - t->getWidth() - 15, lineHeight, ""); myKeyMapping->setEditable(false); myKeyMapping->clearFlags(WIDGET_RETAIN_FOCUS); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventMappingWidget::~EventMappingWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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, char ascii) { // 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, int 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 != EVENT_HATCENTER) { myLastStick = stick; myLastHat = hat; myLastValue = 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 == EVENT_HATCENTER) { value = 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-3.9.3/src/gui/EditTextWidget.cxx0000644000175000001440000000717412266336753017422 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: EditTextWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "OSystem.hxx" #include "FrameBuffer.hxx" #include "Dialog.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), _editable(true), _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; setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditTextWidget::handleMouseDown(int x, int y, int button, int clickCount) { if(!_editable) return; x += _editScrollOffset; int width = 0; unsigned int i; for (i = 0; i < _editString.size(); ++i) { width += _font.getCharWidth(_editString[i]); if (width >= x) break; } if (setCaretPos(i)) { setDirty(); draw(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditTextWidget::drawWidget(bool hilite) { //cerr << "EditTextWidget::drawWidget\n"; FBSurface& s = _boss->dialog().surface(); // Highlight changes if(_changed) s.fillRect(_x, _y, _w, _h, kDbgChangedColor); // 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); // Draw the text adjustOffset(); s.drawString(_font, _editString, _x + 2, _y + 2, getEditRect().width(), !_changed ? _textcolor : kDbgChangedTextColor, kTextAlignLeft, -_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-3.9.3/src/gui/MessageBox.cxx0000644000175000001440000000660112266336753016553 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: MessageBox.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Dialog.hxx" #include "OSystem.hxx" #include "Version.hxx" #include "Widget.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) : 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); 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) : Dialog(&boss->instance(), &boss->parent(), 0, 0, max_w, max_h), CommandSender(boss), myCmd(cmd) { StringParser p(text); addText(font, p.stringList()); WidgetArray wid; addOKCancelBGroup(wid, font, okText, cancelText); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MessageBox::~MessageBox() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(uInt32 i = 0; i < text.size(); ++i) str_w = BSPF_max((int)text[i].length(), str_w); _w = BSPF_min(str_w * fontWidth + 20, _w); _h = BSPF_min(((text.size() + 2) * lineHeight + 20), (uInt32)_h); xpos = 10; ypos = 10; for(uInt32 i = 0; i < text.size(); ++i) { new StaticTextWidget(this, font, xpos, ypos, _w - 20, fontHeight, text[i], kTextAlignLeft); ypos += fontHeight; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MessageBox::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case 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-3.9.3/src/gui/UIDialog.cxx0000644000175000001440000004334312266336753016157 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: UIDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "bspf.hxx" #include "Dialog.hxx" #include "DebuggerDialog.hxx" #include "OSystem.hxx" #include "ListWidget.hxx" #include "PopUpWidget.hxx" #include "ScrollBarWidget.hxx" #include "Settings.hxx" #include "StringList.hxx" #include "TabWidget.hxx" #include "Widget.hxx" #include "UIDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - UIDialog::UIDialog(OSystem* osystem, DialogContainer* parent, const GUI::Font& font) : Dialog(osystem, parent, 0, 0, 0, 0) { const GUI::Font& ifont = instance().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; // 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 wid.clear(); 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); if(instance().desktopWidth() < 640) { myLauncherWidthSlider->setMinValue(320); myLauncherWidthSlider->setMaxValue(instance().desktopWidth()); } else { myLauncherWidthSlider->setMinValue(640); myLauncherWidthSlider->setMaxValue(1920); } myLauncherWidthSlider->setStepValue(10); wid.push_back(myLauncherWidthSlider); myLauncherWidthLabel = new StaticTextWidget(myTab, font, xpos + myLauncherWidthSlider->getWidth() + 4, ypos + 1, 4*fontWidth, fontHeight, "", kTextAlignLeft); myLauncherWidthLabel->setFlags(WIDGET_CLEARBG); ypos += lineHeight + 4; myLauncherHeightSlider = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight, "Launcher Height: ", lwidth, kLHeightChanged); if(instance().desktopHeight() < 480) { myLauncherHeightSlider->setMinValue(240); myLauncherHeightSlider->setMaxValue(instance().desktopHeight()); } else { myLauncherHeightSlider->setMinValue(480); myLauncherHeightSlider->setMaxValue(1200); } myLauncherHeightSlider->setStepValue(10); wid.push_back(myLauncherHeightSlider); myLauncherHeightLabel = new StaticTextWidget(myTab, font, xpos + myLauncherHeightSlider->getWidth() + 4, ypos + 1, 4*fontWidth, fontHeight, "", kTextAlignLeft); myLauncherHeightLabel->setFlags(WIDGET_CLEARBG); ypos += lineHeight + 4; // Launcher font pwidth = font.getStringWidth("2x (1000x760)"); items.clear(); items.push_back("Small", "small"); items.push_back("Medium", "medium"); items.push_back("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(); items.push_back("Off", "0"); items.push_back("1x (640x480) ", "1"); items.push_back("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(); items.push_back("If in use", "0"); items.push_back("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, BSPF_min(lwidth, _w-20), fontHeight, "(*) Changes require application restart", kTextAlignLeft); // Add items for tab 0 addToFocusList(wid, myTab, tabID); ////////////////////////////////////////////////////////// // 2) Debugger options wid.clear(); tabID = myTab->addTab(" Debugger "); lwidth = font.getStringWidth("Debugger Height: "); xpos = ypos = vBorder; // Debugger width and height myDebuggerWidthSlider = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight, "Debugger Width: ", lwidth, kDWidthChanged); myDebuggerWidthSlider->setMinValue(DebuggerDialog::kSmallFontMinW); myDebuggerWidthSlider->setMaxValue(osystem->desktopWidth()); myDebuggerWidthSlider->setStepValue(10); wid.push_back(myDebuggerWidthSlider); myDebuggerWidthLabel = new StaticTextWidget(myTab, font, xpos + myDebuggerWidthSlider->getWidth() + 4, ypos + 1, 4*fontWidth, fontHeight, "", kTextAlignLeft); myDebuggerWidthLabel->setFlags(WIDGET_CLEARBG); ypos += lineHeight + 4; myDebuggerHeightSlider = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight, "Debugger Height: ", lwidth, kDHeightChanged); myDebuggerHeightSlider->setMinValue(DebuggerDialog::kSmallFontMinH); myDebuggerHeightSlider->setMaxValue(osystem->desktopHeight()); myDebuggerHeightSlider->setStepValue(10); wid.push_back(myDebuggerHeightSlider); myDebuggerHeightLabel = new StaticTextWidget(myTab, font, xpos + myDebuggerHeightSlider->getWidth() + 4, ypos + 1, 4*fontWidth, fontHeight, "", kTextAlignLeft); myDebuggerHeightLabel->setFlags(WIDGET_CLEARBG); // Add minimum window size buttons for different fonts int fbwidth = font.getStringWidth("Set window size for medium font") + 20; xpos = (_w - fbwidth - 2*vBorder)/2; ypos += 2*lineHeight + 4; b = new ButtonWidget(myTab, font, xpos, ypos, fbwidth, buttonHeight, "Set window size for small font", kDSmallSize); wid.push_back(b); ypos += b->getHeight() + 4; b = new ButtonWidget(myTab, font, xpos, ypos, fbwidth, buttonHeight, "Set window size for medium font", kDMediumSize); wid.push_back(b); ypos += b->getHeight() + 4; b = new ButtonWidget(myTab, font, xpos, ypos, fbwidth, buttonHeight, "Set window size for large font", kDLargeSize); wid.push_back(b); ypos += b->getHeight() + 12; // Font style (bold label vs. text, etc) lwidth = font.getStringWidth("Font Style: "); pwidth = font.getStringWidth("Bold non-labels only"); xpos = vBorder; items.clear(); items.push_back("All Normal font", "0"); items.push_back("Bold labels only", "1"); items.push_back("Bold non-labels only", "2"); items.push_back("All Bold font", "3"); myDebuggerFontStyle = new PopUpWidget(myTab, font, xpos, ypos+1, pwidth, lineHeight, items, "Font Style: ", lwidth); wid.push_back(myDebuggerFontStyle); // 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) (instance().desktopWidth() >= 800 && instance().desktopHeight() >= 600); #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); ////////////////////////////////////////////////////////// // 3) Misc. options wid.clear(); tabID = myTab->addTab(" Misc. "); lwidth = font.getStringWidth("Mouse wheel scroll: "); pwidth = font.getStringWidth("Standard"); xpos = ypos = vBorder; // UI Palette ypos += 1; items.clear(); items.push_back("Standard", "1"); items.push_back("Classic", "2"); 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(); items.push_back("300 ms", "300"); items.push_back("400 ms", "400"); items.push_back("500 ms", "500"); items.push_back("600 ms", "600"); items.push_back("700 ms", "700"); items.push_back("800 ms", "800"); items.push_back("900 ms", "900"); items.push_back("1 sec", "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(); items.push_back("1 line", "1"); items.push_back("2 lines", "2"); items.push_back("3 lines", "3"); items.push_back("4 lines", "4"); items.push_back("5 lines", "5"); items.push_back("6 lines", "6"); items.push_back("7 lines", "7"); items.push_back("8 lines", "8"); items.push_back("9 lines", "9"); items.push_back("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 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", kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addBGroupToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - UIDialog::~UIDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void UIDialog::loadConfig() { // Launcher size const GUI::Size& ls = instance().settings().getSize("launcherres"); int w = ls.w, h = ls.h; w = BSPF_max(w, 320); h = BSPF_max(h, 240); w = BSPF_min(w, 1920); h = BSPF_min(h, 1200); 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"); #ifdef DEBUGGER_SUPPORT // Debugger size const GUI::Size& ds = instance().settings().getSize("dbg.res"); w = ds.w, h = ds.h; w = BSPF_max(w, (int)DebuggerDialog::kSmallFontMinW); h = BSPF_max(h, (int)DebuggerDialog::kSmallFontMinH); w = BSPF_min(w, (int)instance().desktopWidth()); h = BSPF_min(h, (int)instance().desktopHeight()); myDebuggerWidthSlider->setValue(w); myDebuggerWidthLabel->setValue(w); myDebuggerHeightSlider->setValue(h); myDebuggerHeightLabel->setValue(h); // Debugger font style int style = instance().settings().getInt("dbg.fontstyle"); myDebuggerFontStyle->setSelected(style, "0"); #endif // UI palette const string& pal = instance().settings().getString("uipalette"); myPalettePopup->setSelected(pal, "1"); // 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()); // Debugger size instance().settings().setValue("dbg.res", GUI::Size(myDebuggerWidthSlider->getValue(), myDebuggerHeightSlider->getValue())); // Debugger font style instance().settings().setValue("dbg.fontstyle", myDebuggerFontStyle->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 { int w = BSPF_min(instance().desktopWidth(), 640u); int h = BSPF_min(instance().desktopHeight(), 480u); myLauncherWidthSlider->setValue(w); myLauncherWidthLabel->setValue(w); myLauncherHeightSlider->setValue(h); myLauncherHeightLabel->setValue(h); myLauncherFontPopup->setSelected("medium", ""); myRomViewerPopup->setSelected("0", ""); myLauncherExitPopup->setSelected("0", ""); break; } case 1: // Debugger options { int w = BSPF_min(instance().desktopWidth(), (uInt32)DebuggerDialog::kMediumFontMinW); int h = BSPF_min(instance().desktopHeight(), (uInt32)DebuggerDialog::kMediumFontMinH); myDebuggerWidthSlider->setValue(w); myDebuggerWidthLabel->setValue(w); myDebuggerHeightSlider->setValue(h); myDebuggerHeightLabel->setValue(h); myDebuggerFontStyle->setSelected("0"); break; } case 2: // Misc. options myPalettePopup->setSelected("1"); 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 kDWidthChanged: myDebuggerWidthLabel->setValue(myDebuggerWidthSlider->getValue()); break; case kDHeightChanged: myDebuggerHeightLabel->setValue(myDebuggerHeightSlider->getValue()); break; case kDSmallSize: myDebuggerWidthSlider->setValue(DebuggerDialog::kSmallFontMinW); myDebuggerWidthLabel->setValue(DebuggerDialog::kSmallFontMinW); myDebuggerHeightSlider->setValue(DebuggerDialog::kSmallFontMinH); myDebuggerHeightLabel->setValue(DebuggerDialog::kSmallFontMinH); break; case kDMediumSize: myDebuggerWidthSlider->setValue(DebuggerDialog::kMediumFontMinW); myDebuggerWidthLabel->setValue(DebuggerDialog::kMediumFontMinW); myDebuggerHeightSlider->setValue(DebuggerDialog::kMediumFontMinH); myDebuggerHeightLabel->setValue(DebuggerDialog::kMediumFontMinH); break; case kDLargeSize: myDebuggerWidthSlider->setValue(DebuggerDialog::kLargeFontMinW); myDebuggerWidthLabel->setValue(DebuggerDialog::kLargeFontMinW); myDebuggerHeightSlider->setValue(DebuggerDialog::kLargeFontMinH); myDebuggerHeightLabel->setValue(DebuggerDialog::kLargeFontMinH); break; case kOKCmd: saveConfig(); close(); instance().setUIPalette(); break; case kDefaultsCmd: setDefaults(); break; default: Dialog::handleCommand(sender, cmd, data, 0); break; } } stella-3.9.3/src/gui/module.mk0000644000175000001440000000224112160412171015562 0ustar stephenusersMODULE := src/gui MODULE_OBJS := \ src/gui/AboutDialog.o \ src/gui/AudioDialog.o \ src/gui/BrowserDialog.o \ src/gui/ComboDialog.o \ src/gui/CommandDialog.o \ src/gui/CommandMenu.o \ src/gui/ContextMenu.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/ConfigPathDialog.o \ src/gui/SnapshotDialog.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/Launcher.o \ src/gui/LauncherDialog.o \ src/gui/LauncherFilterDialog.o \ src/gui/LoggerDialog.o \ src/gui/ListWidget.o \ src/gui/Menu.o \ src/gui/MessageBox.o \ src/gui/OptionsDialog.o \ src/gui/PopUpWidget.o \ src/gui/ProgressDialog.o \ src/gui/RomAuditDialog.o \ src/gui/RomInfoWidget.o \ src/gui/ScrollBarWidget.o \ src/gui/CheckListWidget.o \ src/gui/StringListWidget.o \ src/gui/TabWidget.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-3.9.3/src/gui/ScrollBarWidget.cxx0000644000175000001440000002006012266336753017540 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ScrollBarWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #include "Dialog.hxx" #include "FrameBuffer.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 unsigned int up_arrow[8] = { 0x00011000, 0x00011000, 0x00111100, 0x00111100, 0x01111110, 0x01111110, 0x11111111, 0x11111111 }; // Down arrow static unsigned int down_arrow[8] = { 0x11111111, 0x11111111, 0x01111110, 0x01111110, 0x00111100, 0x00111100, 0x00011000, 0x00011000 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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, int button, 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, int button, 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, int button) { // 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(); draw(); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ScrollBarWidget::handleMouseClicks(int x, int y, int button) { // 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(); // This takes care of the required refresh setDirty(); draw(); sendCommand(kSetPositionCmd, _currentPos, _id); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ScrollBarWidget::handleMouseEntered(int button) { setFlags(WIDGET_HILITED); setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ScrollBarWidget::handleMouseLeft(int button) { _part = kNoPart; clearFlags(WIDGET_HILITED); setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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-3.9.3/src/gui/AudioDialog.hxx0000644000175000001440000000321612266336753016703 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: AudioDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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); ~AudioDialog(); protected: SliderWidget* myVolumeSlider; StaticTextWidget* myVolumeLabel; PopUpWidget* myFragsizePopup; PopUpWidget* myFreqPopup; CheckboxWidget* mySoundEnableCheckbox; private: void loadConfig(); void saveConfig(); void setDefaults(); void handleSoundEnableChange(bool active); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); enum { kVolumeChanged = 'ADvc', kSoundEnableChanged = 'ADse' }; }; #endif stella-3.9.3/src/gui/VideoDialog.cxx0000644000175000001440000007053612266336753016714 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: VideoDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #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 "StringList.hxx" #include "Widget.hxx" #include "TabWidget.hxx" #include "FrameBufferGL.hxx" #include "NTSCFilter.hxx" #include "VideoDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VideoDialog::VideoDialog(OSystem* osystem, DialogContainer* parent, const GUI::Font& font, int max_w, int max_h) : Dialog(osystem, parent, 0, 0, 0, 0) { 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("GL Aspect (P): "), pwidth = font.getStringWidth("1920x1200"), fwidth = font.getStringWidth("Renderer: "); WidgetArray wid; VariantList items; // Set real dimensions _w = BSPF_min(52 * fontWidth + 10, max_w); _h = BSPF_min(14 * (lineHeight + 4) + 10, max_h); // The tab widget xpos = ypos = 5; myTab = new TabWidget(this, font, xpos, ypos, _w - 2*xpos, _h - buttonHeight - 20); addTabWidget(myTab); ////////////////////////////////////////////////////////// // 1) General options wid.clear(); tabID = myTab->addTab(" General "); // Video renderer new StaticTextWidget(myTab, font, xpos + (lwidth-fwidth), ypos, fwidth, fontHeight, "Renderer:", kTextAlignLeft); myRenderer = new StaticTextWidget(myTab, font, xpos+lwidth, ypos, fwidth, fontHeight, "", kTextAlignLeft); ypos += lineHeight + 4; items.clear(); items.push_back("Software", "soft"); #ifdef DISPLAY_OPENGL items.push_back("OpenGL", "gl"); #endif myRendererPopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "(*) ", lwidth); wid.push_back(myRendererPopup); ypos += lineHeight + 4; // TIA filters (will be dynamically filled later) items.clear(); myTIAFilterPopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "TIA Filter: ", lwidth); wid.push_back(myTIAFilterPopup); ypos += lineHeight + 4; // TIA Palette items.clear(); items.push_back("Standard", "standard"); items.push_back("Z26", "z26"); items.push_back("User", "user"); myTIAPalettePopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "TIA Palette: ", lwidth); wid.push_back(myTIAPalettePopup); ypos += lineHeight + 4; // Fullscreen resolution items.clear(); items.push_back("Auto", "auto"); for(uInt32 i = 0; i < instance().supportedResolutions().size(); ++i) items.push_back(instance().supportedResolutions()[i].name, instance().supportedResolutions()[i].name); myFSResPopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Fullscrn Res: ", lwidth); wid.push_back(myFSResPopup); ypos += lineHeight + 4; // Timing to use between frames items.clear(); items.push_back("Sleep", "sleep"); items.push_back("Busy-wait", "busy"); myFrameTimingPopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Timing (*): ", lwidth); wid.push_back(myFrameTimingPopup); ypos += lineHeight + 4; // GL Video filter items.clear(); items.push_back("Linear", "linear"); items.push_back("Nearest", "nearest"); myGLFilterPopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "GL Filter: ", lwidth); wid.push_back(myGLFilterPopup); ypos += lineHeight + 4; // GL aspect ratio (NTSC mode) myNAspectRatioSlider = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight, "GL Aspect (N): ", lwidth, kNAspectRatioChanged); myNAspectRatioSlider->setMinValue(80); myNAspectRatioSlider->setMaxValue(120); wid.push_back(myNAspectRatioSlider); myNAspectRatioLabel = new StaticTextWidget(myTab, font, xpos + myNAspectRatioSlider->getWidth() + 4, ypos + 1, fontWidth * 3, fontHeight, "", kTextAlignLeft); myNAspectRatioLabel->setFlags(WIDGET_CLEARBG); ypos += lineHeight + 4; // GL aspect ratio (PAL mode) myPAspectRatioSlider = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight, "GL Aspect (P): ", lwidth, kPAspectRatioChanged); myPAspectRatioSlider->setMinValue(80); myPAspectRatioSlider->setMaxValue(120); wid.push_back(myPAspectRatioSlider); myPAspectRatioLabel = new StaticTextWidget(myTab, font, xpos + myPAspectRatioSlider->getWidth() + 4, ypos + 1, fontWidth * 3, fontHeight, "", kTextAlignLeft); myPAspectRatioLabel->setFlags(WIDGET_CLEARBG); ypos += lineHeight + 4; // Framerate myFrameRateSlider = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight, "Framerate: ", lwidth, kFrameRateChanged); myFrameRateSlider->setMinValue(0); myFrameRateSlider->setMaxValue(300); myFrameRateSlider->setStepValue(10); wid.push_back(myFrameRateSlider); myFrameRateLabel = new StaticTextWidget(myTab, font, xpos + myFrameRateSlider->getWidth() + 4, ypos + 1, fontWidth * 4, fontHeight, "", kTextAlignLeft); myFrameRateLabel->setFlags(WIDGET_CLEARBG); // Add message concerning usage const GUI::Font& infofont = instance().infoFont(); ypos = myTab->getHeight() - 5 - fontHeight - infofont.getFontHeight() - 10; new StaticTextWidget(myTab, infofont, 10, ypos, font.getStringWidth("(*) Requires application restart"), fontHeight, "(*) Requires application restart", kTextAlignLeft); // Move over to the next column xpos += myNAspectRatioSlider->getWidth() + myNAspectRatioLabel->getWidth() + 14; ypos = 10; // Fullscreen items.clear(); items.push_back("On", "1"); items.push_back("Off", "0"); items.push_back("Never", "-1"); lwidth = font.getStringWidth("Fullscreen: "); pwidth = font.getStringWidth("Never"), myFullscreenPopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Fullscreen: ", lwidth, kFullScrChanged); wid.push_back(myFullscreenPopup); ypos += lineHeight + 4; // GL FS stretch myGLStretchCheckbox = new CheckboxWidget(myTab, font, xpos, ypos, "GL FS Stretch"); wid.push_back(myGLStretchCheckbox); ypos += lineHeight + 4; // Use sync to vblank in OpenGL myUseVSyncCheckbox = new CheckboxWidget(myTab, font, xpos, ypos, "GL VSync"); wid.push_back(myUseVSyncCheckbox); ypos += lineHeight + 4; ypos += lineHeight; // PAL color-loss effect myColorLossCheckbox = new CheckboxWidget(myTab, font, xpos, ypos, "PAL color-loss"); wid.push_back(myColorLossCheckbox); ypos += lineHeight + 4; // Skip progress load bars for SuperCharger ROMs // Doesn't really belong here, but I couldn't find a better place for it myFastSCBiosCheckbox = new CheckboxWidget(myTab, font, xpos, ypos, "Fast SC/AR BIOS"); wid.push_back(myFastSCBiosCheckbox); ypos += lineHeight + 4; // Show UI messages onscreen myUIMessagesCheckbox = new CheckboxWidget(myTab, font, xpos, ypos, "Show UI messages"); wid.push_back(myUIMessagesCheckbox); ypos += lineHeight + 4; // Center window (in windowed mode) myCenterCheckbox = new CheckboxWidget(myTab, font, xpos, ypos, "Center window"); wid.push_back(myCenterCheckbox); ypos += lineHeight + 4; // Add items for tab 0 addToFocusList(wid, myTab, tabID); ////////////////////////////////////////////////////////// // 2) TV effects options wid.clear(); tabID = myTab->addTab(" TV Effects "); xpos = ypos = 8; // TV Mode items.clear(); items.push_back("Disabled", NTSCFilter::PRESET_OFF); items.push_back("Composite", NTSCFilter::PRESET_COMPOSITE); items.push_back("S-Video", NTSCFilter::PRESET_SVIDEO); items.push_back("RGB", NTSCFilter::PRESET_RGB); items.push_back("Bad adjust", NTSCFilter::PRESET_BAD); items.push_back("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 + 4; // Custom adjustables (using macro voodoo) xpos += 8; ypos += 4; int orig_ypos = ypos; pwidth = lwidth; lwidth = font.getStringWidth("Saturation: "); #define CREATE_CUSTOM_SLIDERS(obj, desc) \ myTV ## obj = \ new SliderWidget(myTab, font, xpos, ypos, 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, "", kTextAlignLeft);\ myTV ## obj->setFlags(WIDGET_CLEARBG); \ ypos += lineHeight + 4 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() + 20; ypos = orig_ypos; // Scanline intensity and interpolation myTVScanLabel = new StaticTextWidget(myTab, font, xpos, ypos, font.getStringWidth("Scanline settings:"), fontHeight, "Scanline settings:", kTextAlignLeft); ypos += lineHeight; xpos += 20; lwidth = font.getStringWidth("Intensity: "); pwidth = font.getMaxCharWidth() * 6; CREATE_CUSTOM_SLIDERS(ScanIntense, "Intensity: "); myTVScanInterpolate = new CheckboxWidget(myTab, font, xpos, ypos, "Interpolation"); wid.push_back(myTVScanInterpolate); ypos += lineHeight + 4; // Adjustable presets xpos -= 20; 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 + 10 ypos += lineHeight; 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", kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addBGroupToFocusList(wid); // Disable certain functions when we know they aren't present #ifndef DISPLAY_OPENGL myGLFilterPopup->clearFlags(WIDGET_ENABLED); myNAspectRatioSlider->clearFlags(WIDGET_ENABLED); myNAspectRatioLabel->clearFlags(WIDGET_ENABLED); myPAspectRatioSlider->clearFlags(WIDGET_ENABLED); myPAspectRatioLabel->clearFlags(WIDGET_ENABLED); myGLStretchCheckbox->clearFlags(WIDGET_ENABLED); myUseVSyncCheckbox->clearFlags(WIDGET_ENABLED); myTVMode->clearFlags(WIDGET_ENABLED); myTVSharp->clearFlags(WIDGET_ENABLED); myTVSharpLabel->clearFlags(WIDGET_ENABLED); myTVHue->clearFlags(WIDGET_ENABLED); myTVHueLabel->clearFlags(WIDGET_ENABLED); myTVRes->clearFlags(WIDGET_ENABLED); myTVResLabel->clearFlags(WIDGET_ENABLED); myTVArtifacts->clearFlags(WIDGET_ENABLED); myTVArtifactsLabel->clearFlags(WIDGET_ENABLED); myTVFringe->clearFlags(WIDGET_ENABLED); myTVFringeLabel->clearFlags(WIDGET_ENABLED); myTVBleed->clearFlags(WIDGET_ENABLED); myTVBleedLabel->clearFlags(WIDGET_ENABLED); myTVBright->clearFlags(WIDGET_ENABLED); myTVBrightLabel->clearFlags(WIDGET_ENABLED); myTVContrast->clearFlags(WIDGET_ENABLED); myTVContrastLabel->clearFlags(WIDGET_ENABLED); myTVSatur->clearFlags(WIDGET_ENABLED); myTVSaturLabel->clearFlags(WIDGET_ENABLED); myTVGamma->clearFlags(WIDGET_ENABLED); myTVGammaLabel->clearFlags(WIDGET_ENABLED); myTVScanLabel->clearFlags(WIDGET_ENABLED); myTVScanIntense->clearFlags(WIDGET_ENABLED); myTVScanIntenseLabel->clearFlags(WIDGET_ENABLED); myTVScanInterpolate->clearFlags(WIDGET_ENABLED); myCloneComposite->clearFlags(WIDGET_ENABLED); myCloneSvideo->clearFlags(WIDGET_ENABLED); myCloneRGB->clearFlags(WIDGET_ENABLED); myCloneBad->clearFlags(WIDGET_ENABLED); myCloneCustom->clearFlags(WIDGET_ENABLED); #endif #ifndef WINDOWED_SUPPORT myFullscreenCheckbox->clearFlags(WIDGET_ENABLED); myCenterCheckbox->clearFlags(WIDGET_ENABLED); #endif #if !(defined(BSPF_WIN32) || (defined(BSPF_UNIX) && defined(HAVE_X11))) myCenterCheckbox->clearFlags(WIDGET_ENABLED); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VideoDialog::~VideoDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void VideoDialog::loadConfig() { bool gl = (instance().frameBuffer().type() == kDoubleBuffer); // Renderer settings myRenderer->setLabel(gl ? "OpenGL" : "Software"); myRendererPopup->setSelected( instance().settings().getString("video"), "soft"); // 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().supportedTIAFilters(gl ? "gl" : "soft"); myTIAFilterPopup->addItems(items); myTIAFilterPopup->setSelected(instance().settings().getString("tia_filter"), instance().desktopWidth() < 640 ? "zoom1x" : "zoom2x"); // TIA Palette myTIAPalettePopup->setSelected( instance().settings().getString("palette"), "standard"); // Fullscreen resolution myFSResPopup->setSelected( instance().settings().getString("fullres"), "auto"); // Wait between frames myFrameTimingPopup->setSelected( instance().settings().getString("timing"), "sleep"); // GL Filter setting const string& gl_inter = instance().settings().getBool("gl_inter") ? "linear" : "nearest"; myGLFilterPopup->setSelected(gl_inter, "nearest"); myGLFilterPopup->setEnabled(gl); // GL aspect ratio setting (NTSC and PAL) myNAspectRatioSlider->setValue(instance().settings().getInt("gl_aspectn")); myNAspectRatioSlider->setEnabled(gl); myNAspectRatioLabel->setLabel(instance().settings().getString("gl_aspectn")); myNAspectRatioLabel->setEnabled(gl); myPAspectRatioSlider->setValue(instance().settings().getInt("gl_aspectp")); myPAspectRatioSlider->setEnabled(gl); myPAspectRatioLabel->setLabel(instance().settings().getString("gl_aspectp")); myPAspectRatioLabel->setEnabled(gl); // Framerate (0 or -1 means automatic framerate calculation) int rate = instance().settings().getInt("framerate"); myFrameRateSlider->setValue(rate < 0 ? 0 : rate); myFrameRateLabel->setLabel(rate <= 0 ? "Auto" : instance().settings().getString("framerate")); // Fullscreen const string& fullscreen = instance().settings().getString("fullscreen"); myFullscreenPopup->setSelected(fullscreen, "0"); handleFullscreenChange(fullscreen == "0" || fullscreen == "1"); // PAL color-loss effect myColorLossCheckbox->setState(instance().settings().getBool("colorloss")); // GL stretch setting (GL mode only) myGLStretchCheckbox->setState(instance().settings().getBool("gl_fsscale")); myGLStretchCheckbox->setEnabled(gl); // Use sync to vertical blank (GL mode only) myUseVSyncCheckbox->setState(instance().settings().getBool("gl_vsync")); myUseVSyncCheckbox->setEnabled(gl); // Show UI messages myUIMessagesCheckbox->setState(instance().settings().getBool("uimessages")); // Center window myCenterCheckbox->setState(instance().settings().getBool("center")); // Fast loading of Supercharger BIOS myFastSCBiosCheckbox->setState(instance().settings().getBool("fastscbios")); // 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 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", myRendererPopup->getSelectedTag().toString()); // TIA Filter instance().settings().setValue("tia_filter", myTIAFilterPopup->getSelectedTag().toString()); // TIA Palette instance().settings().setValue("palette", myTIAPalettePopup->getSelectedTag().toString()); // Fullscreen resolution instance().settings().setValue("fullres", myFSResPopup->getSelectedTag().toString()); // Wait between frames instance().settings().setValue("timing", myFrameTimingPopup->getSelectedTag().toString()); // GL Filter setting instance().settings().setValue("gl_inter", myGLFilterPopup->getSelectedTag().toString() == "linear" ? true : false); // GL aspect ratio setting (NTSC and PAL) instance().settings().setValue("gl_aspectn", myNAspectRatioLabel->getLabel()); instance().settings().setValue("gl_aspectp", myPAspectRatioLabel->getLabel()); // Framerate int i = myFrameRateSlider->getValue(); instance().settings().setValue("framerate", i); if(&instance().console()) { // Make sure auto-frame calculation is only enabled when necessary instance().console().tia().enableAutoFrame(i <= 0); instance().console().setFramerate(float(i)); } // Fullscreen instance().settings().setValue("fullscreen", myFullscreenPopup->getSelectedTag().toString()); // PAL color-loss effect instance().settings().setValue("colorloss", myColorLossCheckbox->getState()); if(&instance().console()) instance().console().toggleColorLoss(myColorLossCheckbox->getState()); // GL stretch setting instance().settings().setValue("gl_fsscale", myGLStretchCheckbox->getState()); // Use sync to vertical blank (GL mode only) instance().settings().setValue("gl_vsync", myUseVSyncCheckbox->getState()); // Show UI messages instance().settings().setValue("uimessages", myUIMessagesCheckbox->getState()); // Center window instance().settings().setValue("center", myCenterCheckbox->getState()); // Fast loading of Supercharger BIOS instance().settings().setValue("fastscbios", myFastSCBiosCheckbox->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().ntsc().setCustomAdjustables(adj); // 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 { myRendererPopup->setSelected("soft", ""); myTIAFilterPopup->setSelected( instance().desktopWidth() < 640 ? "zoom1x" : "zoom2x", ""); myTIAPalettePopup->setSelected("standard", ""); myFSResPopup->setSelected("auto", ""); myFrameTimingPopup->setSelected("sleep", ""); myGLFilterPopup->setSelected("nearest", ""); myNAspectRatioSlider->setValue(90); myNAspectRatioLabel->setLabel("90"); myPAspectRatioSlider->setValue(100); myPAspectRatioLabel->setLabel("100"); myFrameRateSlider->setValue(0); myFrameRateLabel->setLabel("Auto"); myFullscreenPopup->setSelected("0", ""); myColorLossCheckbox->setState(true); myGLStretchCheckbox->setState(true); myUseVSyncCheckbox->setState(true); myUIMessagesCheckbox->setState(true); myCenterCheckbox->setState(false); myFastSCBiosCheckbox->setState(false); break; } case 1: // TV effects { myTVMode->setSelected("0", "0"); // 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 handleFullscreenChange(true); handleTVModeChange(NTSCFilter::PRESET_OFF); loadTVAdjustables(NTSCFilter::PRESET_CUSTOM); break; } } _dirty = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void VideoDialog::handleFullscreenChange(bool enable) { #ifdef WINDOWED_SUPPORT myFSResPopup->setEnabled(enable); _dirty = true; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void VideoDialog::handleTVModeChange(NTSCFilter::Preset preset) { bool enable = true, scanenable = true; if(!instance().frameBuffer().type() == kDoubleBuffer) { enable = scanenable = false; myTVMode->setEnabled(enable); } else { enable = preset == NTSCFilter::PRESET_CUSTOM; 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().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 kOKCmd: saveConfig(); close(); break; case kDefaultsCmd: setDefaults(); break; case kNAspectRatioChanged: myNAspectRatioLabel->setValue(myNAspectRatioSlider->getValue()); break; case kPAspectRatioChanged: myPAspectRatioLabel->setValue(myPAspectRatioSlider->getValue()); break; case kFrameRateChanged: if(myFrameRateSlider->getValue() == 0) myFrameRateLabel->setLabel("Auto"); else myFrameRateLabel->setValue(myFrameRateSlider->getValue()); break; case kFullScrChanged: handleFullscreenChange(myFullscreenPopup->getSelectedTag().toString() != "-1"); break; case kTVModeChanged: handleTVModeChange((NTSCFilter::Preset)myTVMode->getSelectedTag().toInt()); 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 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-3.9.3/src/gui/InputDialog.hxx0000644000175000001440000000447612266336753016752 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: InputDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef INPUT_DIALOG_HXX #define INPUT_DIALOG_HXX class OSystem; class GuiObject; class TabWidget; class EventMappingWidget; class CheckboxWidget; class EditTextWidget; class PopUpWidget; class SliderWidget; class StaticTextWidget; #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); ~InputDialog(); protected: virtual void handleKeyDown(StellaKey key, StellaMod mod, char ascii); virtual void handleJoyDown(int stick, int button); virtual void handleJoyAxis(int stick, int axis, int value); virtual bool handleJoyHat(int stick, int hat, int value); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); void loadConfig(); void saveConfig(); void setDefaults(); private: void addDevicePortTab(const GUI::Font& font); private: enum { kDeadzoneChanged = 'DZch', kDPSpeedChanged = 'PDch', kMPSpeedChanged = 'PMch' }; TabWidget* myTab; EventMappingWidget* myEmulEventMapper; EventMappingWidget* myMenuEventMapper; PopUpWidget* mySAPort; PopUpWidget* myMouseControl; EditTextWidget* myAVoxPort; SliderWidget* myDeadzone; StaticTextWidget* myDeadzoneLabel; SliderWidget* myDPaddleSpeed; SliderWidget* myMPaddleSpeed; StaticTextWidget* myDPaddleLabel; StaticTextWidget* myMPaddleLabel; CheckboxWidget* myAllowAll4; CheckboxWidget* myGrabMouse; }; #endif stella-3.9.3/src/gui/StellaFont.hxx0000644000175000001440000007057312266336753016607 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: StellaFont.hxx 2838 2014-01-17 23:34:03Z stephena $ // // 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, 0, /* no encode table*/ 0, /* fixed width*/ 0, /* fixed bbox*/ 32, sizeof(stella_font_bits)/sizeof(uInt16) }; } // End of namespace GUI #endif stella-3.9.3/src/gui/Menu.hxx0000644000175000001440000000225112266336753015424 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Menu.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef MENU_HXX #define MENU_HXX class OSystem; #include "DialogContainer.hxx" /** The base dialog for all configuration menus in Stella. @author Stephen Anthony @version $Id: Menu.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class Menu : public DialogContainer { public: /** Create a new menu stack */ Menu(OSystem* osystem); /** Destructor */ virtual ~Menu(); }; #endif stella-3.9.3/src/gui/GlobalPropsDialog.hxx0000644000175000001440000000344412266336753020071 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: GlobalPropsDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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(); private: int addHoldWidgets(const GUI::Font& font, int x, int y, WidgetArray& wid); void loadConfig(); void saveConfig(); void setDefaults(); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); 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* ourJoyState[10]; }; #endif stella-3.9.3/src/gui/ContextMenu.cxx0000644000175000001440000004033412266336753016770 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ContextMenu.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #include "FrameBuffer.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) : Dialog(&boss->instance(), &boss->parent(), 0, 0, 16, 16), 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) { addItems(items); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ContextMenu::~ContextMenu() { _entries.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::addItems(const VariantList& items) { _entries.clear(); _entries = items; // Resize to largest string int maxwidth = 0; for(unsigned int i = 0; i < _entries.size(); ++i) { int length = _font.getStringWidth(_entries[i].first); if(length > maxwidth) maxwidth = length; } _x = _y = 0; _w = maxwidth + 10; _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().setPos(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 int maxentries = BSPF_min(18, (image.height() - 4) / _rowHeight); if((int)_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 = _entries.size(); _h = _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(unsigned int 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(unsigned int item = 0; item < _entries.size(); ++item) { if(BSPF_equalsIgnoreCase(_entries[item].second.toString(), defaultTag.toString())) { setSelectedIndex(item); return; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::setSelectedMax() { setSelectedIndex(_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 = _entries.size() - 1; sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::handleMouseDown(int x, int y, int button, 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(button == 1) { if(item != -1) { _isScrolling = _showScroll && ((item == 0) || (item == _numEntries+1)); sendSelection(); } else close(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::handleMouseMoved(int x, int y, int button) { // 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, int button) { // 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, char ascii) { 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, int 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 = _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 = _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 = BSPF_max(_firstEntry - distance, 0); _scrollUpColor = _firstEntry > 0 ? kScrollColor : kColor; _scrollDnColor = kScrollColor; setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::scrollDown(int distance) { int max_offset = _entries.size() - _numEntries; if(_firstEntry == max_offset) return; _firstEntry = BSPF_min(_firstEntry + distance, max_offset); _scrollUpColor = kScrollColor; _scrollDnColor = _firstEntry < max_offset ? kScrollColor : kColor; setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::drawDialog() { static uInt32 up_arrow[8] = { 0x00011000, 0x00011000, 0x00111100, 0x00111100, 0x01111110, 0x01111110, 0x11111111, 0x11111111 }; static uInt32 down_arrow[8] = { 0x11111111, 0x11111111, 0x01111110, 0x01111110, 0x00111100, 0x00111100, 0x00011000, 0x00011000 }; // 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); 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; // 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.addDirtyRect(_x, _y, _w, _h); _dirty = false; } // Commit surface changes to screen s.update(); } stella-3.9.3/src/gui/StringListWidget.cxx0000644000175000001440000000644412266336753017771 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: StringListWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "ScrollBarWidget.hxx" #include "StringListWidget.hxx" #include "bspf.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), _hilite(hilite) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StringListWidget::~StringListWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StringListWidget::setList(const StringList& list) { _list = list; ListWidget::recalc(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StringListWidget::drawWidget(bool hilite) { //cerr << "StringListWidget::drawWidget\n"; FBSurface& s = _boss->dialog().surface(); int i, pos, len = _list.size(); string buffer; int deltax; // 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; // 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); else s.frameRect(_x + 1, _y + 1 + _fontHeight * i, _w - 1, _fontHeight, kTextColorHi); } GUI::Rect r(getEditRect()); if (_selectedItem == pos && _editMode) { buffer = _editString; adjustOffset(); deltax = -_editScrollOffset; s.drawString(_font, buffer, _x + r.left, y, r.width(), kTextColor, kTextAlignLeft, deltax, false); } else { buffer = _list[pos]; deltax = 0; s.drawString(_font, buffer, _x + r.left, y, r.width(), kTextColor); } } // 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-3.9.3/src/gui/GameList.cxx0000644000175000001440000000446312266336753016227 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: GameList.cxx 2838 2014-01-17 23:34:03Z stephena $ // // Based on code from KStella - Stella frontend // Copyright (C) 2003-2005 Stephen Anthony //============================================================================ #include #include #include "GameList.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GameList::GameList() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GameList::~GameList() { clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GameList::appendGame(const string& name, const string& path, const string& md5, bool isDir) { myArray.push_back(Entry(name, path, md5, isDir)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GameList::sortByName() { if(myArray.size() <= 1) return; sort(myArray.begin(), myArray.end()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool GameList::Entry::operator< (const Entry& g) const { string::const_iterator it1 = _name.begin(); string::const_iterator it2 = g._name.begin(); // Account for ending ']' character in directory entries string::const_iterator end1 = _isdir ? _name.end() - 1 : _name.end(); string::const_iterator end2 = g._isdir ? g._name.end() - 1 : g._name.end(); // 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 _name.size() < g._name.size(); } stella-3.9.3/src/gui/GameInfoDialog.cxx0000644000175000001440000005750512266336753017334 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: GameInfoDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Console.hxx" #include "MouseControl.hxx" #include "Dialog.hxx" #include "EditTextWidget.hxx" #include "Launcher.hxx" #include "OSystem.hxx" #include "PopUpWidget.hxx" #include "Props.hxx" #include "PropsSet.hxx" #include "StringList.hxx" #include "TabWidget.hxx" #include "Widget.hxx" #include "GameInfoDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GameInfoDialog::GameInfoDialog( OSystem* osystem, DialogContainer* parent, const GUI::Font& font, GuiObject* boss) : Dialog(osystem, parent, 0, 0, 0, 0), CommandSender(boss), myPropertiesLoaded(false), myDefaultsSelected(false) { const GUI::Font& ifont = instance().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; int xpos, ypos, lwidth, fwidth, pwidth, tabID; WidgetArray wid; VariantList items, ports, ctrls; // Set real dimensions _w = 52 * fontWidth + 8; _h = 12 * (lineHeight + 4) + 10; //////////////////////////////////////////////////////////////////// // Some of the following items are also present in GlobalPropsDialog // If any changes are ever made here, GlobalPropsDialog should also // be updated accordingly //////////////////////////////////////////////////////////////////// // The tab widget xpos = 2; ypos = vBorder; myTab = new TabWidget(this, font, xpos, ypos, _w - 2*xpos, _h - buttonHeight - fontHeight - ifont.getLineHeight() - 20); addTabWidget(myTab); // 1) Cartridge properties wid.clear(); tabID = myTab->addTab("Cartridge"); xpos = 10; lwidth = font.getStringWidth("Manufacturer: "); fwidth = _w - xpos - lwidth - 10; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Name:", kTextAlignLeft); myName = new EditTextWidget(myTab, font, xpos+lwidth, ypos, fwidth, fontHeight, ""); wid.push_back(myName); ypos += lineHeight + 3; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "MD5:", kTextAlignLeft); myMD5 = new StaticTextWidget(myTab, font, xpos+lwidth, ypos, fwidth, fontHeight, "", kTextAlignLeft); ypos += lineHeight + 3; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Manufacturer:", kTextAlignLeft); myManufacturer = new EditTextWidget(myTab, font, xpos+lwidth, ypos, fwidth, fontHeight, ""); wid.push_back(myManufacturer); ypos += lineHeight + 3; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Model:", kTextAlignLeft); myModelNo = new EditTextWidget(myTab, font, xpos+lwidth, ypos, fwidth, fontHeight, ""); wid.push_back(myModelNo); ypos += lineHeight + 3; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Rarity:", kTextAlignLeft); myRarity = new EditTextWidget(myTab, font, xpos+lwidth, ypos, fwidth, fontHeight, ""); wid.push_back(myRarity); ypos += lineHeight + 3; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Note:", kTextAlignLeft); myNote = new EditTextWidget(myTab, font, xpos+lwidth, ypos, fwidth, fontHeight, ""); wid.push_back(myNote); ypos += lineHeight + 3; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Sound:", kTextAlignLeft); pwidth = font.getStringWidth("Stereo"); items.clear(); items.push_back("Mono", "MONO"); items.push_back("Stereo", "STEREO"); mySound = new PopUpWidget(myTab, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(mySound); ypos += lineHeight + 3; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Type:", kTextAlignLeft); pwidth = font.getStringWidth("CM (SpectraVideo CompuMate)"); items.clear(); items.push_back("Auto-detect", "AUTO" ); items.push_back("0840 (8K ECONObank)", "0840" ); items.push_back("2IN1 Multicart (4-32K)", "2IN1" ); items.push_back("4IN1 Multicart (8-32K)", "4IN1" ); items.push_back("8IN1 Multicart (16-64K)", "8IN1" ); items.push_back("16IN1 Multicart (32-128K)", "16IN1" ); items.push_back("32IN1 Multicart (64/128K)", "32IN1" ); items.push_back("64IN1 Multicart (128/256K)", "64IN1" ); items.push_back("128IN1 Multicart (256/512K)", "128IN1"); items.push_back("2K (64-2048 bytes Atari)", "2K" ); items.push_back("3E (32K Tigervision)", "3E" ); items.push_back("3F (512K Tigervision)", "3F" ); items.push_back("4A50 (64K 4A50 + ram)", "4A50" ); items.push_back("4K (4K Atari)", "4K" ); items.push_back("4KSC (CPUWIZ 4K + ram)", "4KSC" ); items.push_back("AR (Supercharger)", "AR" ); items.push_back("BF (CPUWIZ 256K)", "BF" ); items.push_back("BFSC (CPUWIZ 256K + ram)", "BFSC" ); items.push_back("CV (Commavid extra ram)", "CV" ); items.push_back("CM (SpectraVideo CompuMate)", "CM" ); items.push_back("DF (CPUWIZ 128K)", "DF" ); items.push_back("DFSC (CPUWIZ 128K + ram)", "DFSC" ); items.push_back("DPC (Pitfall II)", "DPC" ); items.push_back("DPC+ (Enhanced DPC)", "DPC+" ); items.push_back("E0 (8K Parker Bros)", "E0" ); items.push_back("E7 (16K M-network)", "E7" ); items.push_back("EF (64K H. Runner)", "EF" ); items.push_back("EFSC (64K H. Runner + ram)", "EFSC" ); items.push_back("F0 (Dynacom Megaboy)", "F0" ); items.push_back("F4 (32K Atari)", "F4" ); items.push_back("F4SC (32K Atari + ram)", "F4SC" ); items.push_back("F6 (16K Atari)", "F6" ); items.push_back("F6SC (16K Atari + ram)", "F6SC" ); items.push_back("F8 (8K Atari)", "F8" ); items.push_back("F8SC (8K Atari + ram)", "F8SC" ); items.push_back("FA (CBS RAM Plus)", "FA" ); items.push_back("FA2 (CBS RAM Plus 24/28K)", "FA2" ); items.push_back("FE (8K Decathlon)", "FE" ); items.push_back("MC (C. Wilkson Megacart)", "MC" ); items.push_back("SB (128-256K SUPERbank)", "SB" ); items.push_back("UA (8K UA Ltd.)", "UA" ); items.push_back("X07 (64K AtariAge)", "X07" ); 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 = 10; ypos = vBorder; lwidth = font.getStringWidth("Right Difficulty: "); pwidth = font.getStringWidth("B & W"); new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Left Difficulty:", kTextAlignLeft); items.clear(); items.push_back("B", "B"); items.push_back("A", "A"); myLeftDiff = new PopUpWidget(myTab, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(myLeftDiff); ypos += lineHeight + 5; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Right Difficulty:", kTextAlignLeft); // ... use same items as above myRightDiff = new PopUpWidget(myTab, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(myRightDiff); ypos += lineHeight + 5; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "TV Type:", kTextAlignLeft); items.clear(); items.push_back("Color", "COLOR"); items.push_back("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"); xpos = 10; ypos = vBorder; lwidth = font.getStringWidth("P0 Controller: "); pwidth = font.getStringWidth("CX-22 Trakball"); new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "P0 Controller:", kTextAlignLeft); ctrls.clear(); ctrls.push_back("Joystick", "JOYSTICK" ); ctrls.push_back("Paddles", "PADDLES" ); ctrls.push_back("Paddles_IAxis", "PADDLES_IAXIS"); ctrls.push_back("Paddles_IDir", "PADDLES_IDIR" ); ctrls.push_back("Paddles_IAxDr", "PADDLES_IAXDR"); ctrls.push_back("BoosterGrip", "BOOSTERGRIP" ); ctrls.push_back("Driving", "DRIVING" ); ctrls.push_back("Keyboard", "KEYBOARD" ); ctrls.push_back("CX-22 Trakball", "TRACKBALL22" ); ctrls.push_back("CX-80 Mouse", "TRACKBALL80" ); ctrls.push_back("AmigaMouse", "AMIGAMOUSE" ); ctrls.push_back("AtariVox", "ATARIVOX" ); ctrls.push_back("SaveKey", "SAVEKEY" ); ctrls.push_back("Sega Genesis", "GENESIS" ); ctrls.push_back("CompuMate", "COMPUMATE" ); // ctrls.push_back("KidVid", "KIDVID" ); ctrls.push_back("MindLink", "MINDLINK" ); myP0Controller = new PopUpWidget(myTab, font, xpos+lwidth, ypos, pwidth, lineHeight, ctrls, "", 0, 0); wid.push_back(myP0Controller); xpos += lwidth+myP0Controller->getWidth() + 4; new StaticTextWidget(myTab, font, xpos, ypos+1, font.getStringWidth("in "), fontHeight, "in ", kTextAlignLeft); xpos += font.getStringWidth("in "); pwidth = font.getStringWidth("right port"); ports.clear(); ports.push_back("left port", "L"); ports.push_back("right port", "R"); myLeftPort = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, ports, "", 0, kLeftCChanged); wid.push_back(myLeftPort); xpos = 10; ypos += lineHeight + 5; pwidth = font.getStringWidth("CX-22 Trakball"); new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "P1 Controller:", kTextAlignLeft); myP1Controller = new PopUpWidget(myTab, font, xpos+lwidth, ypos, pwidth, lineHeight, ctrls, "", 0, 0); wid.push_back(myP1Controller); xpos += lwidth+myP1Controller->getWidth() + 4; pwidth = font.getStringWidth("right port"); new StaticTextWidget(myTab, font, xpos, ypos+1, font.getStringWidth("in "), fontHeight, "in ", kTextAlignLeft); xpos += font.getStringWidth("in "); myRightPort = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, ports, "", 0, kRightCChanged); wid.push_back(myRightPort); xpos = 10; ypos += lineHeight + 5; pwidth = font.getStringWidth("Yes"); new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Swap Paddles:", kTextAlignLeft); items.clear(); items.push_back("Yes", "YES"); items.push_back("No", "NO"); mySwapPaddles = new PopUpWidget(myTab, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(mySwapPaddles); ypos += lineHeight + 8; lwidth = font.getStringWidth("Mouse axis mode: "); pwidth = font.getStringWidth("Specific axis"); items.clear(); items.push_back("Automatic", "auto"); items.push_back("Specific axis", "specific"); myMouseControl = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Mouse axis mode: ", lwidth, kMCtrlChanged); wid.push_back(myMouseControl); // Mouse controller specific axis lwidth = font.getStringWidth("X-Axis is: "); pwidth = font.getStringWidth("MindLink 0"); items.clear(); items.push_back("None", MouseControl::NoControl); items.push_back("Paddle 0", MouseControl::Paddle0); items.push_back("Paddle 1", MouseControl::Paddle1); items.push_back("Paddle 2", MouseControl::Paddle2); items.push_back("Paddle 3", MouseControl::Paddle3); items.push_back("Driving 0", MouseControl::Driving0); items.push_back("Driving 1", MouseControl::Driving1); items.push_back("MindLink 0", MouseControl::MindLink0); items.push_back("MindLink 1", MouseControl::MindLink1); xpos = 45; ypos += lineHeight + 4; myMouseX = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "X-Axis is: ", lwidth); wid.push_back(myMouseX); ypos += lineHeight + 4; myMouseY = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Y-Axis is: ", lwidth); wid.push_back(myMouseY); // Add items for tab 2 addToFocusList(wid, myTab, tabID); // 4) Display properties wid.clear(); tabID = myTab->addTab("Display"); xpos = 10; ypos = vBorder; lwidth = font.getStringWidth("Use Phosphor: "); pwidth = font.getStringWidth("Auto-detect"); new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Format:", kTextAlignLeft); items.clear(); items.push_back("Auto-detect", "AUTO"); items.push_back("NTSC", "NTSC"); items.push_back("PAL", "PAL"); items.push_back("SECAM", "SECAM"); items.push_back("NTSC50", "NTSC50"); items.push_back("PAL60", "PAL60"); items.push_back("SECAM60", "SECAM60"); myFormat = new PopUpWidget(myTab, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(myFormat); ypos += lineHeight + 5; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "YStart:", kTextAlignLeft); myYStart = new EditTextWidget(myTab, font, xpos+lwidth, ypos, 4*fontWidth, fontHeight, ""); wid.push_back(myYStart); ypos += lineHeight + 5; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Height:", kTextAlignLeft); myHeight = new EditTextWidget(myTab, font, xpos+lwidth, ypos, 4*fontWidth, fontHeight, ""); wid.push_back(myHeight); ypos += lineHeight + 5; pwidth = font.getStringWidth("Yes"); new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Use Phosphor:", kTextAlignLeft); items.clear(); items.push_back("Yes", "YES"); items.push_back("No", "NO"); myPhosphor = new PopUpWidget(myTab, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, kPhosphorChanged); wid.push_back(myPhosphor); myPPBlend = new SliderWidget(myTab, font, xpos + lwidth + myPhosphor->getWidth() + 10, ypos, 8*fontWidth, lineHeight, "Blend: ", font.getStringWidth("Blend: "), kPPBlendChanged); myPPBlend->setMinValue(1); myPPBlend->setMaxValue(100); wid.push_back(myPPBlend); myPPBlendLabel = new StaticTextWidget(myTab, font, xpos + lwidth + myPhosphor->getWidth() + 10 + \ myPPBlend->getWidth() + 4, ypos+1, 3*fontWidth, fontHeight, "", kTextAlignLeft); myPPBlendLabel->setFlags(WIDGET_CLEARBG); // 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, 10, _h - buttonHeight - fontHeight - 20, lwidth, fontHeight, "(*) Changes to properties require a ROM reload", kTextAlignLeft); // Add Defaults, OK and Cancel buttons wid.clear(); ButtonWidget* b; b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Defaults", kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addBGroupToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GameInfoDialog::~GameInfoDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GameInfoDialog::loadConfig() { myPropertiesLoaded = false; myDefaultsSelected = false; if(&instance().console()) { myGameProperties = instance().console().properties(); myPropertiesLoaded = true; loadView(); } else if(&instance().launcher()) { const string& md5 = instance().launcher().selectedRomMD5(); if(md5 != "") { instance().propSet().getMD5(md5, myGameProperties); myPropertiesLoaded = true; loadView(); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GameInfoDialog::loadView() { if(!myPropertiesLoaded) return; // Cartridge properties myName->setText(myGameProperties.get(Cartridge_Name)); myMD5->setLabel(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"); const string& swap = myGameProperties.get(Console_SwapPorts); myLeftPort->setSelected((swap == "NO" ? "L" : "R"), "L"); myRightPort->setSelected((swap == "NO" ? "R" : "L"), "R"); // Controller properties myP0Controller->setSelected(myGameProperties.get(Controller_Left), "JOYSTICK"); myP1Controller->setSelected(myGameProperties.get(Controller_Right), "JOYSTICK"); mySwapPaddles->setSelected(myGameProperties.get(Controller_SwapPaddles), "NO"); const string& mcontrol = myGameProperties.get(Controller_MouseAxis); bool autoAxis = BSPF_equalsIgnoreCase(mcontrol, "auto"); if(autoAxis) { myMouseControl->setSelectedIndex(0); myMouseX->setSelectedIndex(0); myMouseY->setSelectedIndex(0); } else { myMouseControl->setSelectedIndex(1); myMouseX->setSelected(mcontrol[0] - '0'); myMouseY->setSelected(mcontrol[1] - '0'); } myMouseX->setEnabled(!autoAxis); myMouseY->setEnabled(!autoAxis); // Display properties myFormat->setSelected(myGameProperties.get(Display_Format), "AUTO"); myYStart->setText(myGameProperties.get(Display_YStart)); myHeight->setText(myGameProperties.get(Display_Height)); const string& phos = myGameProperties.get(Display_Phosphor); myPhosphor->setSelected(phos, "NO"); myPPBlend->setEnabled(phos != "NO"); myPPBlendLabel->setEnabled(phos != "NO"); const string& blend = myGameProperties.get(Display_PPBlend); myPPBlend->setValue(atoi(blend.c_str())); myPPBlendLabel->setLabel(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, myLeftPort->getSelectedTag().toString() == "L" ? "NO" : "YES"); myGameProperties.set(Controller_SwapPaddles, mySwapPaddles->getSelectedTag().toString()); string mcontrol = myMouseControl->getSelectedTag().toString(); if(mcontrol != "auto") mcontrol = myMouseX->getSelectedTag().toString() + myMouseY->getSelectedTag().toString(); myGameProperties.set(Controller_MouseAxis, mcontrol); // Display properties myGameProperties.set(Display_Format, myFormat->getSelectedTag().toString()); myGameProperties.set(Display_YStart, myYStart->getText()); myGameProperties.set(Display_Height, myHeight->getText()); myGameProperties.set(Display_Phosphor, myPhosphor->getSelectedTag().toString()); myGameProperties.set(Display_PPBlend, 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 and save the properties if(&instance().console()) instance().console().setProperties(myGameProperties); instance().propSet().save(instance().propertiesFile()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case kOKCmd: saveConfig(); close(); break; case kDefaultsCmd: setDefaults(); break; case kLeftCChanged: myRightPort->setSelectedIndex( myLeftPort->getSelected() == 1 ? 0 : 1); break; case kRightCChanged: myLeftPort->setSelectedIndex( myRightPort->getSelected() == 1 ? 0 : 1); break; case kPhosphorChanged: { bool status = myPhosphor->getSelectedTag().toString() == "YES"; myPPBlend->setEnabled(status); myPPBlendLabel->setEnabled(status); break; } case kPPBlendChanged: myPPBlendLabel->setValue(myPPBlend->getValue()); break; case kMCtrlChanged: { bool state = myMouseControl->getSelectedTag().toString() != "auto"; myMouseX->setEnabled(state); myMouseY->setEnabled(state); break; } default: Dialog::handleCommand(sender, cmd, data, 0); break; } } stella-3.9.3/src/gui/LoggerDialog.hxx0000644000175000001440000000265412266336753017066 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: LoggerDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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); virtual ~LoggerDialog(); protected: void loadConfig(); void saveConfig(); void saveLogFile(); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); private: StringListWidget* myLogInfo; PopUpWidget* myLogLevel; CheckboxWidget* myLogToConsole; }; #endif stella-3.9.3/src/gui/CommandMenu.cxx0000644000175000001440000000223012266336753016713 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CommandMenu.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Dialog.hxx" #include "CommandDialog.hxx" #include "CommandMenu.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CommandMenu::CommandMenu(OSystem* osystem) : DialogContainer(osystem) { myBaseDialog = new CommandDialog(myOSystem, this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CommandMenu::~CommandMenu() { } stella-3.9.3/src/gui/BrowserDialog.cxx0000644000175000001440000001572212266336753017265 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: BrowserDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "Dialog.hxx" #include "DialogContainer.hxx" #include "FSNode.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "EditTextWidget.hxx" #include "FileListWidget.hxx" #include "Widget.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(), 0, 0, 0, 0), CommandSender(boss) { // 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, "", kTextAlignCenter); // Current path - TODO: handle long paths ? ypos += lineHeight + 4; _currentPath = new StaticTextWidget(this, font, xpos, ypos, _w - 2 * xpos, lineHeight, "", kTextAlignLeft); // 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, font.getStringWidth("Name: "), lineHeight, "Name:", kTextAlignCenter); _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 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", kCloseCmd); addFocusWidget(b); addCancelWidget(b); #else b = new ButtonWidget(this, font, _w - 2 * (buttonWidth + 7), _h - buttonHeight - 10, buttonWidth, buttonHeight, "Cancel", 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 } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BrowserDialog::~BrowserDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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-3.9.3/src/gui/ConfigPathDialog.cxx0000644000175000001440000002243612266336753017664 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ConfigPathDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "BrowserDialog.hxx" #include "EditTextWidget.hxx" #include "FSNode.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, int max_w, int max_h) : Dialog(osystem, parent, 0, 0, 0, 0), CommandSender(boss), myBrowser(NULL), myIsGlobal(boss != 0) { const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), buttonWidth = font.getStringWidth("Properties file:") + 20, buttonHeight = font.getLineHeight() + 4; const int vBorder = 8; int xpos, ypos; WidgetArray wid; ButtonWidget* b; // Set real dimensions _w = 56 * fontWidth + 8; _h = 9 * (lineHeight + 4) + 10; xpos = vBorder; ypos = vBorder; // ROM path ButtonWidget* romButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Rom path:", 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 = vBorder; ypos += romButton->getHeight() + 3; b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Cheat file:", 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 = vBorder; ypos += b->getHeight() + 3; b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Palette file:", 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 = vBorder; ypos += b->getHeight() + 3; b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Properties file:", 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 = vBorder; ypos += b->getHeight() + 3; b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "State path:", 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 = vBorder; ypos += b->getHeight() + 3; b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "NVRAM path:", 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", 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); } // Create file browser dialog myBrowser = new BrowserDialog(this, font, max_w, max_h); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ConfigPathDialog::~ConfigPathDialog() { delete myBrowser; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 kOKCmd: saveConfig(); close(); if(myIsGlobal) // Let the boss know romdir has changed sendCommand(LauncherDialog::kRomDirChosenCmd, 0, 0); break; case kDefaultsCmd: setDefaults(); break; case kChooseRomDirCmd: myBrowser->show("Select ROM directory:", myRomPath->getText(), BrowserDialog::Directories, LauncherDialog::kRomDirChosenCmd); break; case kChooseCheatFileCmd: myBrowser->show("Select cheat file:", myCheatFile->getText(), BrowserDialog::FileLoad, kCheatFileChosenCmd); break; case kChoosePaletteFileCmd: myBrowser->show("Select palette file:", myPaletteFile->getText(), BrowserDialog::FileLoad, kPaletteFileChosenCmd); break; case kChoosePropsFileCmd: myBrowser->show("Select properties file:", myPropsFile->getText(), BrowserDialog::FileLoad, kPropsFileChosenCmd); break; case kChooseNVRamDirCmd: myBrowser->show("Select NVRAM directory:", myNVRamPath->getText(), BrowserDialog::Directories, kNVRamDirChosenCmd); break; case kChooseStateDirCmd: 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; } } stella-3.9.3/src/gui/Rect.hxx0000644000175000001440000001413612266336753015422 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Rect.hxx 2838 2014-01-17 23:34:03Z stephena $ // // 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 { int x; //!< The horizontal part of the point int y; //!< The vertical part of the point Point() : x(0), y(0) {}; Point(const Point & p) : x(p.x), y(p.y) {}; explicit Point(int x1, int y1) : x(x1), y(y1) {}; Point(const string& p) { char c = '\0'; x = y = -1; 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 { int w; //!< The width part of the size int h; //!< The height part of the size Size() : w(0), h(0) {}; Size(const Size & s) : w(s.w), h(s.h) {}; explicit Size(int w1, int h1) : w(w1), h(h1) {}; Size(const string& s) { char c = '\0'; w = h = -1; istringstream buf(s); buf >> w >> c >> h; if(c != 'x') w = h = -1; } 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; }; 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 { int top, left; //!< The point at the top left of the rectangle (part of the rect). int 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(int w, int h) : top(0), left(0), bottom(h), right(w) {} Rect(int x1, int y1, int x2, int y2) : top(y1), left(x1), bottom(y2), right(x2) { assert(isValidRect()); } int x() const { return left; } int y() const { return top; } Point point() const { return Point(x(), y()); } int width() const { return right - left; } int height() const { return bottom - top; } Size size() const { return Size(width(), height()); } void setWidth(int aWidth) { right = left + aWidth; } void setHeight(int aHeight) { bottom = top + aHeight; } void setSize(const Size& size) { setWidth(size.w); setHeight(size.h); } /* @param x the horizontal position to check @param y the vertical position to check @return true if the given position is inside this rectangle, false otherwise */ bool contains(int x, int y) const { return (left <= x) && (x < right) && (top <= y) && (y < bottom); } /* @param p the point to check @return true if the given point is inside this rectangle, false otherwise */ bool contains(const Point & p) const { return contains(p.x, p.y); } /* @param r the rectangle to check @return true if the given rectangle is inside the rectangle, false otherwise */ bool intersects(const Rect & r) const { return (left < r.right) && (r.left < right) && (top < r.bottom) && (r.top < bottom); } /* @param r the rectangle to extend by */ void extend(const Rect & r) { left = BSPF_min(left, r.left); right = BSPF_max(right, r.right); top = BSPF_min(top, r.top); bottom = BSPF_max(bottom, r.bottom); } /* Extend this rectangle in all four directions by the given number of pixels @param offset the size to grow by */ void grow(int offset) { top -= offset; left -= offset; bottom += offset; right += offset; } void clip(const Rect & r) { assert(isValidRect()); assert(r.isValidRect()); if (top < r.top) top = r.top; else if (top > r.bottom) top = r.bottom; if (left < r.left) left = r.left; else if (left > r.right) left = r.right; if (bottom > r.bottom) bottom = r.bottom; else if (bottom < r.top) bottom = r.top; if (right > r.right) right = r.right; else if (right < r.left) right = r.left; } void clip(int maxw, int maxh) { clip(Rect(0, 0, maxw, maxh)); } bool isValidRect() const { return (left <= right && top <= bottom); } void moveTo(int x, int 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 << "Point: " << r.point() << ", Size: " << r.size(); return os; } }; } // End of namespace GUI #endif stella-3.9.3/src/gui/AboutDialog.hxx0000644000175000001440000000311412266336753016711 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: AboutDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef ABOUT_DIALOG_HXX #define ABOUT_DIALOG_HXX #include "Array.hxx" class OSystem; class DialogContainer; class CommandSender; class ButtonWidget; class StaticTextWidget; class AboutDialog : public Dialog { public: AboutDialog(OSystem* osystem, DialogContainer* parent, const GUI::Font& font); ~AboutDialog(); protected: ButtonWidget* myNextButton; ButtonWidget* myPrevButton; StaticTextWidget* myTitle; Common::Array myDesc; Common::Array myDescStr; int myPage; int myNumPages; int myLinesPerPage; private: virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); virtual void updateStrings(int page, int lines, string& title); void displayInfo(); void loadConfig() { displayInfo(); } }; #endif stella-3.9.3/src/gui/ProgressDialog.hxx0000644000175000001440000000253512266336753017451 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ProgressDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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(); void setMessage(const string& message); void setRange(int begin, int end, int step); void setProgress(int progress); protected: StaticTextWidget* myMessage; SliderWidget* mySlider; int myStart, myFinish, myStep, myCurrentStep; }; #endif stella-3.9.3/src/gui/LauncherFilterDialog.cxx0000644000175000001440000001670712266336753020555 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: LauncherFilterDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "bspf.hxx" #include "Control.hxx" #include "Dialog.hxx" #include "OSystem.hxx" #include "PopUpWidget.hxx" #include "Settings.hxx" #include "StringList.hxx" #include "Widget.hxx" #include "LauncherDialog.hxx" #include "LauncherFilterDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LauncherFilterDialog::LauncherFilterDialog(GuiObject* boss, const GUI::Font& font) : Dialog(&boss->instance(), &boss->parent(), 0, 0, 0, 0), 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 items.clear(); items.push_back("All files", "allfiles"); items.push_back("All roms", "allroms"); items.push_back("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", kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LauncherFilterDialog::~LauncherFilterDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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* ext = name.c_str() + idx + 1; for(uInt32 i = 0; i < exts.size(); ++i) if(BSPF_equalsIgnoreCase(ext, exts[i])) 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* 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 kOKCmd: saveConfig(); close(); break; case kDefaultsCmd: setDefaults(); break; case kFileTypeChanged: handleFileTypeChange(myFileType->getSelectedTag().toString()); break; default: Dialog::handleCommand(sender, cmd, data, 0); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* LauncherFilterDialog::ourRomTypes[2][5] = { { ".a26", ".bin", ".rom", ".zip", ".gz" }, { "a26", "bin", "rom", "zip", "gz" } }; stella-3.9.3/src/gui/LauncherDialog.hxx0000644000175000001440000000724012266336753017404 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: LauncherDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef LAUNCHER_DIALOG_HXX #define LAUNCHER_DIALOG_HXX #include "bspf.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; #include "Dialog.hxx" #include "FSNode.hxx" #include "StringList.hxx" #include "Stack.hxx" #include "MessageBox.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); ~LauncherDialog(); /** 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(); } protected: virtual void handleKeyDown(StellaKey key, StellaMod mod, char ascii); virtual void handleMouseDown(int x, int y, int button, int clickCount); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); void loadConfig(); void updateListing(const string& nameToSelect = ""); private: void enableButtons(bool enable); void loadDirListing(); void loadRomInfo(); void handleContextMenu(); void setListFilters(); bool matchPattern(const string& s, const string& pattern) const; private: ButtonWidget* myStartButton; ButtonWidget* myPrevDirButton; ButtonWidget* myOptionsButton; ButtonWidget* myQuitButton; StringListWidget* myList; StaticTextWidget* myDirLabel; StaticTextWidget* myDir; StaticTextWidget* myRomCount; EditTextWidget* myPattern; GameList* myGameList; OptionsDialog* myOptions; RomInfoWidget* myRomInfoWidget; ContextMenu* myMenu; GlobalPropsDialog* myGlobalProps; LauncherFilterDialog* myFilters; GUI::MessageBox* myFirstRunMsg; BrowserDialog* myRomDir; int mySelectedItem; FilesystemNode myCurrentNode; Common::FixedStack myNodeNames; StringList myRomExts; enum { kPrevDirCmd = 'PRVD', kOptionsCmd = 'OPTI', kQuitCmd = 'QUIT', kFirstRunMsgChosenCmd = 'frmc', kStartupRomDirChosenCmd = 'rmsc' }; }; #endif stella-3.9.3/src/gui/InputTextDialog.cxx0000644000175000001440000001453212266336753017604 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: InputTextDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "Dialog.hxx" #include "DialogContainer.hxx" #include "EditTextWidget.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "Widget.hxx" #include "InputTextDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - InputTextDialog::InputTextDialog(GuiObject* boss, const GUI::Font& font, const StringList& labels) : Dialog(&boss->instance(), &boss->parent(), 0, 0, 16, 16), 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(), 0, 0, 16, 16), CommandSender(boss), myEnableCenter(false), myErrorFlag(false), myXOrig(0), myYOrig(0) { initialize(lfont, nfont, labels); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - InputTextDialog::~InputTextDialog() { myInput.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(); unsigned int xpos, ypos, i, lwidth = 0, maxIdx = 0; WidgetArray wid; // Calculate real dimensions _w = fontWidth * 30; _h = lineHeight * 4 + labels.size() * (lineHeight + 5); // Determine longest label for(i = 0; i < labels.size(); ++i) { if(labels[i].length() > lwidth) { lwidth = 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, lwidth, fontHeight, labels[i], kTextAlignLeft); 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, "", kTextAlignCenter); 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().setPos(x, y); } else Dialog::center(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputTextDialog::setTitle(const string& title) { myTitle->setLabel(title); myErrorFlag = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& InputTextDialog::getResult(int idx) { if((unsigned int)idx < myInput.size()) return myInput[idx]->getText(); else return EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputTextDialog::setText(const string& str, int idx) { if((unsigned int)idx < myInput.size()) myInput[idx]->setText(str); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputTextDialog::setFocus(int idx) { if((unsigned int)idx < myInput.size()) Dialog::setFocus(getFocusList()[idx]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputTextDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case 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, kCloseCmd, data, id); break; default: Dialog::handleCommand(sender, cmd, data, id); break; } } stella-3.9.3/src/gui/ListWidget.hxx0000644000175000001440000000752012266336753016603 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ListWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef LIST_WIDGET_HXX #define LIST_WIDGET_HXX class GuiObject; class StringList; #include "Widget.hxx" #include "Command.hxx" #include "EditableWidget.hxx" #include "ScrollBarWidget.hxx" #include "Rect.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 = true); virtual ~ListWidget(); 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); virtual void handleMouseDown(int x, int y, int button, int clickCount); virtual void handleMouseUp(int x, int y, int button, int clickCount); virtual void handleMouseWheel(int x, int y, int direction); virtual bool handleKeyDown(StellaKey key, StellaMod mod, char ascii); virtual bool handleKeyUp(StellaKey key, StellaMod mod, char ascii); virtual bool handleEvent(Event::Type e); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); // Account for the extra width of embedded scrollbar virtual int getWidth() const { return _w + kScrollBarWidth; } void startEditMode(); void endEditMode(); static void setQuickSelectDelay(uInt64 time) { _QUICK_SELECT_DELAY = time; } protected: virtual void drawWidget(bool hilite) = 0; virtual GUI::Rect getEditRect() const = 0; int findItem(int x, int y) const; void recalc(); void scrollBarRecalc(); void abortEditMode(); void lostFocusWidget(); 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; }; #endif stella-3.9.3/src/gui/FileListWidget.hxx0000644000175000001440000000515212266336753017402 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FileListWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef FILE_LIST_WIDGET_HXX #define FILE_LIST_WIDGET_HXX #include "Command.hxx" #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(); /** 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); private: FilesystemNode::ListMode _fsmode; FilesystemNode _node, _selected; string _extension; GameList _gameList; }; #endif stella-3.9.3/src/gui/Widget.cxx0000644000175000001440000004306012266336753015741 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Widget.cxx 2838 2014-01-17 23:34:03Z stephena $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #include "bspf.hxx" #include "Command.hxx" #include "DialogContainer.hxx" #include "Dialog.hxx" #include "EditableWidget.hxx" #include "Font.hxx" #include "FrameBuffer.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 = NULL; _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, oldW = _w, oldH = _h; // 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; } s.fillRect(x, y, w, h, (_flags & WIDGET_HILITED) ? _bgcolorhi : _bgcolor); } // Draw border if(hasBorder) { s.box(_x, _y, _w, _h, kColor, kShadowColor); _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.addDirtyRect(getAbsX(), getAbsY(), oldW, oldH); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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); setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(int i = 0; i < (int)list.size(); ++i) if(list[i] == find) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Widget* Widget::setFocusForChain(GuiObject* boss, WidgetArray& arr, Widget* wid, int direction) { FBSurface& s = boss->dialog().surface(); int size = 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) { tmp->lostFocus(); s.frameRect(x, y, w, h, kDlgColor); tmp->setDirty(); tmp->draw(); s.addDirtyRect(x, y, w, h); } } // Figure out which which should be active if(pos == -1) return 0; else { 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; } } // 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; tmp->receivedFocus(); s.frameRect(x, y, w, h, kWidFrameColor, kDashLine); tmp->setDirty(); tmp->draw(); s.addDirtyRect(x, y, w, h); 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, TextAlignment align) : Widget(boss, font, x, y, w, h), _align(align) { _flags = WIDGET_ENABLED | WIDGET_CLEARBG; _bgcolor = kDlgColor; _bgcolorhi = kDlgColor; _textcolor = kTextColor; _textcolorhi = kTextColor; _label = text; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StaticTextWidget::setValue(int value) { char buf[256]; BSPF_snprintf(buf, 255, "%d", value); _label = buf; setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StaticTextWidget::setLabel(const string& label) { _label = label; setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StaticTextWidget::drawWidget(bool hilite) { FBSurface& s = _boss->dialog().surface(); s.drawString(_font, _label, _x, _y, _w, isEnabled() ? _textcolor : kColor, _align); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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, kTextAlignCenter), CommandSender(boss), _cmd(cmd) { _flags = WIDGET_ENABLED | WIDGET_BORDER | WIDGET_CLEARBG; _bgcolor = kBtnColor; _bgcolorhi = kBtnColorHi; _textcolor = kBtnTextColor; _textcolorhi = kBtnTextColorHi; _editable = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ButtonWidget::handleMouseEntered(int button) { setFlags(WIDGET_HILITED); setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ButtonWidget::handleMouseLeft(int button) { clearFlags(WIDGET_HILITED); setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ButtonWidget::handleEvent(Event::Type e) { if(!isEnabled()) return false; switch(e) { case Event::UISelect: // Simulate mouse event handleMouseUp(0, 0, 1, 0); return true; default: return false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ButtonWidget::handleMouseUp(int x, int y, int button, 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(); s.drawString(_font, _label, _x, _y + (_h - _fontHeight)/2 + 1, _w, !isEnabled() ? kColor : hilite ? _textcolorhi : _textcolor, _align); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* 8x8 checkbox bitmap */ static unsigned int checked_img_active[8] = { 0x11111111, 0x11111111, 0x11111111, 0x11111111, 0x11111111, 0x11111111, 0x11111111, 0x11111111 }; static unsigned int checked_img_inactive[8] = { 0x11111111, 0x11111111, 0x11100111, 0x11000011, 0x11000011, 0x11100111, 0x11111111, 0x11111111 }; static unsigned int checked_img_circle[8] = { 0x00011000, 0x01111110, 0x01111110, 0x11111111, 0x11111111, 0x01111110, 0x01111110, 0x00011000 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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), _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::handleMouseUp(int x, int y, int button, 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) 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) { if(_state != state) { _state = state; setDirty(); draw(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheckboxWidget::drawWidget(bool hilite) { FBSurface& s = _boss->dialog().surface(); // 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, _bgcolor); if(isEnabled()) { if(_state) s.drawBitmap(_img, _x + 3, _y + _boxY + 3, kCheckColor); } else s.fillRect(_x + 2, _y + _boxY + 2, 10, 10, kColor); // 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 | WIDGET_CLEARBG; _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(); draw(); 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, int button) { // 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, int button, int clickCount) { if(isEnabled()) { _isDragging = true; handleMouseMoved(x, y, button); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SliderWidget::handleMouseUp(int x, int y, int button, 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; break; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SliderWidget::drawWidget(bool hilite) { FBSurface& s = _boss->dialog().surface(); // Draw the label, if any if(_labelWidth > 0) s.drawString(_font, _label, _x, _y + 2, _labelWidth, isEnabled() ? kTextColor : kColor, kTextAlignRight); // 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() ? kColor : kWidColor); // Draw the 'bar' s.fillRect(_x + _labelWidth + 2, _y + 2, valueToPos(_value), _h - 4, !isEnabled() ? kColor : hilite ? kSliderColorHi : kSliderColor); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int SliderWidget::valueToPos(int value) { if(value < _valueMin) value = _valueMin; else if(value > _valueMax) value = _valueMax; int range = BSPF_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-3.9.3/src/gui/RomInfoWidget.hxx0000644000175000001440000000372612266336753017245 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RomInfoWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef ROM_INFO_WIDGET_HXX #define ROM_INFO_WIDGET_HXX #include #include "Props.hxx" #include "Widget.hxx" #include "Command.hxx" #include "StringList.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(); void setProperties(const Properties& props); void clearProperties(); void loadConfig(); protected: void drawWidget(bool hilite); private: void parseProperties(); private: // Surface id and pointer holding the scaled PNG image FBSurface* mySurface; int mySurfaceID; // How much to zoom the PNG image int myZoomLevel; // 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; }; #endif stella-3.9.3/src/gui/CheckListWidget.hxx0000644000175000001440000000350112266336753017534 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CheckListWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CHECK_LIST_WIDGET_HXX #define CHECK_LIST_WIDGET_HXX class CheckboxWidget; #include "ListWidget.hxx" typedef Common::Array CheckboxArray; /** 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(); 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); } bool handleEvent(Event::Type e); void handleCommand(CommandSender* sender, int cmd, int data, int id); protected: void drawWidget(bool hilite); GUI::Rect getEditRect() const; protected: BoolArray _stateList; CheckboxArray _checkList; }; #endif stella-3.9.3/src/gui/GuiObject.hxx0000644000175000001440000000632012266336753016374 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: GuiObject.hxx 2838 2014-01-17 23:34:03Z stephena $ // // 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; #include "Command.hxx" #include "OSystem.hxx" #include "Array.hxx" typedef Common::Array WidgetArray; // The commands generated by various widgets enum { kOKCmd = 'OK ', kCloseCmd = 'CLOS', kNextCmd = 'NEXT', kPrevCmd = 'PREV', kEditCmd = 'EDIT', kDefaultsCmd = 'DEFA', kSetPositionCmd = 'SETP', kTabChangedCmd = 'TBCH', kCheckActionCmd = 'CBAC', kRefreshAllCmd = 'REFA' }; /** This is the base class for all GUI objects/widgets. @author Stephen Anthony @version $Id: GuiObject.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class GuiObject : public CommandReceiver { friend class Widget; friend class DialogContainer; 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(0) {} virtual ~GuiObject() {} OSystem& instance() { return myOSystem; } DialogContainer& parent() { return myParent; } Dialog& dialog() { return myDialog; } 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 void setDirty() { _dirty = true; } virtual bool isVisible() const = 0; virtual void draw() = 0; /** Add given widget to the focus list */ virtual void addFocusWidget(Widget* w) = 0; /** Return focus list for this object */ WidgetArray& getFocusList() { return _focusList; } /** Redraw the focus list */ virtual void redrawFocus() {} protected: virtual void releaseFocus() = 0; private: OSystem& myOSystem; DialogContainer& myParent; Dialog& myDialog; protected: int _x, _y; int _w, _h; bool _dirty; Widget* _firstWidget; WidgetArray _focusList; }; #endif stella-3.9.3/src/gui/SnapshotDialog.cxx0000644000175000001440000001670312266336753017441 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SnapshotDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "BrowserDialog.hxx" #include "EditTextWidget.hxx" #include "FSNode.hxx" #include "LauncherDialog.hxx" #include "PopUpWidget.hxx" #include "Settings.hxx" #include "SnapshotDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SnapshotDialog::SnapshotDialog( OSystem* osystem, DialogContainer* parent, const GUI::Font& font, GuiObject* boss, int max_w, int max_h) : Dialog(osystem, parent, 0, 0, 0, 0), myBrowser(NULL) { const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), buttonWidth = font.getStringWidth("Save path:") + 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:", 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:", 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; items.push_back("actual ROM name", "rom"); items.push_back("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(); items.push_back("1 second", "1"); items.push_back("2 seconds", "2"); items.push_back("3 seconds", "3"); items.push_back("4 seconds", "4"); items.push_back("5 seconds", "5"); items.push_back("6 seconds", "6"); items.push_back("7 seconds", "7"); items.push_back("8 seconds", "8"); items.push_back("9 seconds", "9"); items.push_back("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:", kTextAlignLeft); // 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, "Disable image filtering (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", kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addToFocusList(wid); // Create file browser dialog myBrowser = new BrowserDialog(this, font, max_w, max_h); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SnapshotDialog::~SnapshotDialog() { delete myBrowser; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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().defaultSnapSaveDir()); mySnapLoadPath->setText(instance().defaultSnapLoadDir()); mySnapSingle->setState(false); mySnap1x->setState(false); mySnapInterval->setSelected("2", "2"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SnapshotDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case kOKCmd: saveConfig(); close(); break; case kDefaultsCmd: setDefaults(); break; case kChooseSnapSaveDirCmd: myBrowser->show("Select snapshot save directory:", mySnapSavePath->getText(), BrowserDialog::Directories, kSnapSaveDirChosenCmd); break; case kChooseSnapLoadDirCmd: 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; } } stella-3.9.3/src/gui/ComboDialog.cxx0000644000175000001440000001146512266336753016701 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ComboDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "bspf.hxx" #include "Control.hxx" #include "Dialog.hxx" #include "DialogContainer.hxx" #include "EventHandler.hxx" #include "OSystem.hxx" #include "EditTextWidget.hxx" #include "PopUpWidget.hxx" #include "StringList.hxx" #include "Widget.hxx" #include "ComboDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ComboDialog::ComboDialog(GuiObject* boss, const GUI::Font& font, const VariantList& combolist) : Dialog(&boss->instance(), &boss->parent(), 0, 0, 0, 0), myComboEvent(Event::NoType) { #define ADD_EVENT_POPUP(IDX, LABEL) \ myEvents[IDX] = new PopUpWidget(this, font, xpos, ypos, \ pwidth, lineHeight, combolist, LABEL); \ wid.push_back(myEvents[IDX]); \ ypos += lineHeight + 4; 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(uInt32 i = 0; i < combolist.size(); ++i) pwidth = BSPF_max(font.getStringWidth(combolist[i].first), pwidth); // Label for dialog, indicating which combo is being changed myComboName = new StaticTextWidget(this, font, xpos, ypos, _w - xpos - 10, fontHeight, "", kTextAlignCenter); ypos += (lineHeight + 4) + 5; // Add event popup for 8 events xpos = 10; ADD_EVENT_POPUP(0, "Event 1: "); ADD_EVENT_POPUP(1, "Event 2: "); ADD_EVENT_POPUP(2, "Event 3: "); ADD_EVENT_POPUP(3, "Event 4: "); ADD_EVENT_POPUP(4, "Event 5: "); ADD_EVENT_POPUP(5, "Event 6: "); ADD_EVENT_POPUP(6, "Event 7: "); 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", kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ComboDialog::~ComboDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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, events); int size = BSPF_min(events.size(), 8u); for(int i = 0; i < size; ++i) myEvents[i]->setSelected("", events[i]); // Fill any remaining items to 'None' if(size < 8) for(int 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 kOKCmd: saveConfig(); close(); break; case kDefaultsCmd: setDefaults(); break; default: Dialog::handleCommand(sender, cmd, data, 0); break; } } stella-3.9.3/src/gui/EditableWidget.cxx0000644000175000001440000002471612266336753017402 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: EditableWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Dialog.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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EditableWidget::~EditableWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditableWidget::setText(const string& str, bool) { // TODO: We probably should filter the input string here, // e.g. using tryInsertChar. _editString = str; _caretPos = _editString.size(); _editScrollOffset = (_font.getStringWidth(_editString) - (getEditRect().width())); if (_editScrollOffset < 0) _editScrollOffset = 0; if(_editable) startEditMode(); // Make sure the new string is seen onscreen setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditableWidget::setEditable(bool editable) { _editable = editable; if(_editable) setFlags(WIDGET_WANTS_RAWDATA|WIDGET_RETAIN_FOCUS); else clearFlags(WIDGET_WANTS_RAWDATA|WIDGET_RETAIN_FOCUS); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EditableWidget::tryInsertChar(char c, int pos) { if(isprint(c) && c != '\"') { _editString.insert(pos, 1, c); return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EditableWidget::handleKeyDown(StellaKey key, StellaMod mod, char ascii) { if(!_editable) return true; // Ignore all alt-mod keys if(instance().eventHandler().kbdAlt(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, ascii, _id); break; case KBDK_DELETE: dirty = killChar(+1); if(dirty) sendCommand(EditableWidget::kChangedCmd, ascii, _id); break; case KBDK_LEFT: if(instance().eventHandler().kbdControl(mod)) dirty = specialKeys(key, ascii); else if(_caretPos > 0) dirty = setCaretPos(_caretPos - 1); break; case KBDK_RIGHT: if(instance().eventHandler().kbdControl(mod)) dirty = specialKeys(key, ascii); else if(_caretPos < (int)_editString.size()) dirty = setCaretPos(_caretPos + 1); break; case KBDK_HOME: dirty = setCaretPos(0); break; case KBDK_END: dirty = setCaretPos(_editString.size()); break; default: if (instance().eventHandler().kbdControl(mod)) { dirty = specialKeys(key, ascii); } else if (tryInsertChar(ascii, _caretPos)) { _caretPos++; sendCommand(EditableWidget::kChangedCmd, ascii, _id); dirty = true; } else handled = false; } if (dirty) { setDirty(); draw(); } 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() { //cerr << "EditableWidget::drawCaret()\n"; // 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, char ascii) { bool handled = true; switch (key) { case KBDK_a: setCaretPos(0); break; case KBDK_c: copySelectedText(); if(handled) sendCommand(EditableWidget::kChangedCmd, ascii, _id); break; case KBDK_e: setCaretPos(_editString.size()); break; case KBDK_d: handled = killChar(+1); if(handled) sendCommand(EditableWidget::kChangedCmd, ascii, _id); break; case KBDK_k: handled = killLine(+1); if(handled) sendCommand(EditableWidget::kChangedCmd, ascii, _id); break; case KBDK_u: handled = killLine(-1); if(handled) sendCommand(EditableWidget::kChangedCmd, ascii, _id); break; case KBDK_v: pasteSelectedText(); if(handled) sendCommand(EditableWidget::kChangedCmd, ascii, _id); break; case KBDK_w: handled = killLastWord(); if(handled) sendCommand(EditableWidget::kChangedCmd, ascii, _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 = _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-3.9.3/src/gui/PopUpWidget.hxx0000644000175000001440000000553512266336753016737 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: PopUpWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef POPUP_WIDGET_HXX #define POPUP_WIDGET_HXX class GUIObject; #include "bspf.hxx" #include "Array.hxx" #include "Command.hxx" #include "ContextMenu.hxx" #include "StringList.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); ~PopUpWidget(); /** Add the given items to the widget. */ /** Various selection methods passed directly to the underlying menu See ContextMenu.hxx for more information. */ void addItems(const VariantList& items) { myMenu->addItems(items); } void setSelected(const Variant& tag, const Variant& def = EmptyVariant) { myMenu->setSelected(tag, def); } void setSelectedIndex(int idx) { myMenu->setSelectedIndex(idx); } void setSelectedMax() { myMenu->setSelectedMax(); } void clearSelection() { myMenu->clearSelection(); } int getSelected() const { return myMenu->getSelected(); } const string& getSelectedName() const { return myMenu->getSelectedName(); } const Variant& getSelectedTag() const { return myMenu->getSelectedTag(); } bool wantsFocus() { return true; } protected: void handleMouseDown(int x, int y, int button, int clickCount); void handleMouseWheel(int x, int y, int direction); bool handleEvent(Event::Type e); void handleCommand(CommandSender* sender, int cmd, int data, int id); void drawWidget(bool hilite); private: ContextMenu* myMenu; int myArrowsY; int myTextY; string _label; int _labelWidth; }; #endif stella-3.9.3/src/gui/OptionsDialog.cxx0000644000175000001440000001575212266336753017300 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: OptionsDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #include "Dialog.hxx" #include "DialogContainer.hxx" #include "Widget.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 "HelpDialog.hxx" #include "AboutDialog.hxx" #include "OptionsDialog.hxx" #include "Launcher.hxx" #ifdef CHEATCODE_SUPPORT #include "CheatCodeDialog.hxx" #endif #include "bspf.hxx" #define addODButton(label, cmd) \ new ButtonWidget(this, font, xoffset, yoffset, buttonWidth, buttonHeight, label, cmd); yoffset += rowHeight // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OptionsDialog::OptionsDialog(OSystem* osystem, DialogContainer* parent, GuiObject* boss, int max_w, int max_h, bool global) : Dialog(osystem, parent, 0, 0, 0, 0), myVideoDialog(NULL), myAudioDialog(NULL), myInputDialog(NULL), myUIDialog(NULL), mySnapshotDialog(NULL), myConfigPathDialog(NULL), myGameInfoDialog(NULL), myCheatCodeDialog(NULL), myLoggerDialog(NULL), myHelpDialog(NULL), myAboutDialog(NULL), myIsGlobal(global) { const GUI::Font& font = instance().font(); const int buttonWidth = font.getStringWidth("Snapshot Settings") + 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 = NULL; b = addODButton("Video Settings", kVidCmd); wid.push_back(b); b = addODButton("Audio Settings", kAudCmd); #ifndef SOUND_SUPPORT b->clearFlags(WIDGET_ENABLED); #endif wid.push_back(b); b = addODButton("Input Settings", kInptCmd); wid.push_back(b); b = addODButton("UI Settings", kUsrIfaceCmd); wid.push_back(b); b = addODButton("Snapshot Settings", kSnapCmd); wid.push_back(b); b = addODButton("Config Paths", kCfgPathsCmd); wid.push_back(b); myRomAuditButton = addODButton("Audit ROMs", kAuditCmd); wid.push_back(myRomAuditButton); // Move to second column xoffset += buttonWidth + 10; yoffset = 10; myGameInfoButton = addODButton("Game Properties", kInfoCmd); wid.push_back(myGameInfoButton); myCheatCodeButton = addODButton("Cheat Code", kCheatCmd); #ifndef CHEATCODE_SUPPORT myCheatCodeButton->clearFlags(WIDGET_ENABLED); #endif wid.push_back(myCheatCodeButton); b = addODButton("System Logs", kLoggerCmd); wid.push_back(b); b = addODButton("Help", kHelpCmd); wid.push_back(b); b = addODButton("About", kAboutCmd); wid.push_back(b); b = addODButton("Exit Menu", kExitCmd); wid.push_back(b); addCancelWidget(b); // Now create all the dialogs attached to each menu button myVideoDialog = new VideoDialog(osystem, parent, font, max_w, max_h); myAudioDialog = new AudioDialog(osystem, parent, font); myInputDialog = new InputDialog(osystem, parent, font, max_w, max_h); myUIDialog = new UIDialog(osystem, parent, font); mySnapshotDialog = new SnapshotDialog(osystem, parent, font, boss, max_w, max_h); myConfigPathDialog = new ConfigPathDialog(osystem, parent, font, boss, max_w, max_h); myRomAuditDialog = new RomAuditDialog(osystem, parent, font, max_w, max_h); myGameInfoDialog = new GameInfoDialog(osystem, parent, font, this); #ifdef CHEATCODE_SUPPORT myCheatCodeDialog = new CheatCodeDialog(osystem, parent, font); #endif myLoggerDialog = new LoggerDialog(osystem, parent, font, max_w, max_h); myHelpDialog = new HelpDialog(osystem, parent, font); myAboutDialog = new AboutDialog(osystem, parent, font); addToFocusList(wid); // Certain buttons are disabled depending on mode if(myIsGlobal) { myCheatCodeButton->clearFlags(WIDGET_ENABLED); } else { myRomAuditButton->clearFlags(WIDGET_ENABLED); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OptionsDialog::~OptionsDialog() { delete myVideoDialog; delete myAudioDialog; delete myInputDialog; delete myUIDialog; delete mySnapshotDialog; delete myConfigPathDialog; delete myRomAuditDialog; delete myGameInfoDialog; #ifdef CHEATCODE_SUPPORT delete myCheatCodeDialog; #endif delete myLoggerDialog; delete myHelpDialog; delete myAboutDialog; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 EventHandler::S_EMULATE: myGameInfoButton->setFlags(WIDGET_ENABLED); break; case EventHandler::S_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: myLoggerDialog->open(); break; case kHelpCmd: myHelpDialog->open(); break; case kAboutCmd: myAboutDialog->open(); break; case kExitCmd: if(myIsGlobal) close(); else instance().eventHandler().leaveMenuMode(); break; default: Dialog::handleCommand(sender, cmd, data, 0); } } stella-3.9.3/src/gui/Font.hxx0000644000175000001440000000473712266336753015441 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Font.hxx 2838 2014-01-17 23:34:03Z stephena $ // // 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 */ typedef struct { const 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 */ const uInt16* bits; /* 16-bit right-padded bitmap data */ const uInt32* offset; /* offsets into bitmap data*/ const uInt8* width; /* character widths or NULL if fixed */ const BBX* bbx; /* character bounding box or NULL if fixed */ int defaultchar; /* default char (not glyph index) */ long bits_size; /* # words of bitmap_t bits */ } FontDesc; 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; }; } // namespace GUI #endif stella-3.9.3/src/gui/TabWidget.cxx0000644000175000001440000002171512266336753016373 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TabWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "Dialog.hxx" #include "FrameBuffer.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 (unsigned int i = 0; i < _tabs.size(); ++i) { delete _tabs[i].firstWidget; _tabs[i].firstWidget = 0; // _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 = _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(kTabChangedCmd, _activeTab, _id); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::updateActiveTab() { if(_activeTab < 0) return; if(_tabs[_activeTab].parentWidget) _tabs[_activeTab].parentWidget->loadConfig(); setDirty(); draw(); // Redraw focused areas _boss->redrawFocus(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::activateTabs() { for(unsigned int i = 0; i <_tabs.size(); ++i) sendCommand(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, int button, 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::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(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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; // Draw horizontal line s.hLine(left1, _y + _tabHeight - 2, right1, kShadowColor); s.hLine(left2, _y + _tabHeight - 2, right2, kShadowColor); // 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; 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, kTextAlignCenter); x += _tabWidth + kTabSpacing; } // 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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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-3.9.3/src/gui/HelpDialog.cxx0000644000175000001440000001524312266336753016530 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: HelpDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "Dialog.hxx" #include "OSystem.hxx" #include "Widget.hxx" #include "HelpDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HelpDialog::HelpDialog(OSystem* osystem, DialogContainer* parent, const GUI::Font& font) : Dialog(osystem, parent, 0, 0, 0, 0), myPage(1), myNumPages(5) { 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", kPrevCmd); myPrevButton->clearFlags(WIDGET_ENABLED); wid.push_back(myPrevButton); xpos += buttonWidth + 7; myNextButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Next", kNextCmd); wid.push_back(myNextButton); xpos = _w - buttonWidth - 10; ButtonWidget* b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Close", kCloseCmd); wid.push_back(b); addOKWidget(b); addCancelWidget(b); xpos = 5; ypos = 5; myTitle = new StaticTextWidget(this, font, xpos, ypos, _w - 10, fontHeight, "", kTextAlignCenter); int lwidth = 15 * 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, "", kTextAlignLeft); myDesc[i] = new StaticTextWidget(this, font, xpos+lwidth, ypos, _w - xpos - lwidth - 5, fontHeight, "", kTextAlignLeft); ypos += fontHeight; } addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HelpDialog::~HelpDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void HelpDialog::updateStrings(uInt8 page, uInt8 lines, string& title) { #define ADD_BIND(k,d) do { myKeyStr[i] = k; myDescStr[i] = d; i++; } while(0) #define ADD_TEXT(d) ADD_BIND("",d) #define ADD_LINE ADD_BIND("","") #ifdef MAC_OSX #define ALT_ "Cmd" #else #define ALT_ "Alt" #endif uInt8 i = 0; switch(page) { case 1: title = "Common commands:"; #ifndef 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"); ADD_BIND("", " to a 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"); break; case 5: title = "All other commands:"; ADD_LINE; ADD_BIND("Remapped Events", ""); ADD_TEXT("Most other commands can be"); ADD_TEXT("remapped. Please consult the"); ADD_TEXT("'Input Settings' section 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 kNextCmd: myPage++; if(myPage >= myNumPages) myNextButton->clearFlags(WIDGET_ENABLED); if(myPage >= 2) myPrevButton->setFlags(WIDGET_ENABLED); displayInfo(); break; case 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-3.9.3/src/gui/DialogContainer.hxx0000644000175000001440000001235712266336753017572 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DialogContainer.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef DIALOG_CONTAINER_HXX #define DIALOG_CONTAINER_HXX class Dialog; class OSystem; #include "EventHandler.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 @version $Id: DialogContainer.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class DialogContainer { friend class EventHandler; friend class Dialog; public: /** Create a new DialogContainer stack */ DialogContainer(OSystem* osystem); /** Destructor */ 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 event. @param key Actual key symbol @param mod Modifiers @param ascii ASCII translation @param state Pressed (true) or released (false) */ void handleKeyEvent(StellaKey key, StellaMod mod, char ascii, bool state); /** Handle a mouse motion event. @param x The x location @param y The y location @param button The currently pressed button */ void handleMouseMotionEvent(int x, int y, int button); /** Handle a mouse button event. @param b The mouse button @param x The x location @param y The y location @param state The state (pressed or released) */ void handleMouseButtonEvent(MouseButton b, int x, int y, uInt8 state); /** 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 axis 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; } 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; char ascii; int flags; } myCurrentKeyDown; uInt64 myKeyRepeatTime; // For continuous 'mouse down' events struct { int x; int y; int button; } 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; int 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; }; #endif stella-3.9.3/src/gui/EventMappingWidget.hxx0000644000175000001440000000643012266336753020264 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: EventMappingWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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); ~EventMappingWidget(); bool handleKeyDown(StellaKey key, StellaMod mod, char ascii); void handleJoyDown(int stick, int button); void handleJoyAxis(int stick, int axis, int value); bool handleJoyHat(int stick, int hat, int value); bool remapMode() { return myRemapStatus; } void setDefaults(); private: enum { kStartMapCmd = 'map ', kStopMapCmd = 'smap', kEraseCmd = 'eras', kResetCmd = 'rest', kComboCmd = 'cmbo' }; virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); void startRemapping(); void eraseRemapping(); void resetRemapping(); void stopRemapping(); void loadConfig(); void saveConfig(); 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; }; #endif stella-3.9.3/src/gui/Launcher.hxx0000644000175000001440000000340612266336753016264 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Launcher.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef LAUNCHER_HXX #define LAUNCHER_HXX class Properties; class OSystem; class FilesystemNode; #include "DialogContainer.hxx" #include "FrameBuffer.hxx" /** The base dialog for the ROM launcher in Stella. @author Stephen Anthony @version $Id: Launcher.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class Launcher : public DialogContainer { public: /** Create a new menu stack */ Launcher(OSystem* osystem); /** Destructor */ virtual ~Launcher(); /** 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; }; #endif stella-3.9.3/src/gui/RomAuditDialog.cxx0000644000175000001440000001653412266336753017370 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RomAuditDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 "MessageBox.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, 0, 0, 0, 0), myBrowser(NULL), myConfirmMsg(NULL), myMaxWidth(max_w), myMaxHeight(max_h) { const int vBorder = 8; const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), buttonWidth = font.getStringWidth("Audit path:") + 20, buttonHeight = font.getLineHeight() + 4, lwidth = font.getStringWidth("ROMs without properties (skipped): "); int xpos = vBorder, ypos = vBorder; WidgetArray wid; // Set real dimensions _w = 44 * fontWidth + 10; _h = 7 * (lineHeight + 4) + 10; // Audit path ButtonWidget* romButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Audit path:", kChooseAuditDirCmd); wid.push_back(romButton); xpos += buttonWidth + 10; myRomPath = new EditTextWidget(this, font, xpos, ypos + 2, _w - xpos - 10, lineHeight, ""); wid.push_back(myRomPath); // Show results of ROM audit xpos = vBorder + 10; ypos += buttonHeight + 10; new StaticTextWidget(this, font, xpos, ypos, lwidth, fontHeight, "ROMs with properties (renamed): ", kTextAlignLeft); myResults1 = new StaticTextWidget(this, font, xpos + lwidth, ypos, _w - lwidth - 20, fontHeight, "", kTextAlignLeft); myResults1->setFlags(WIDGET_CLEARBG); ypos += buttonHeight; new StaticTextWidget(this, font, xpos, ypos, lwidth, fontHeight, "ROMs without properties (skipped): ", kTextAlignLeft); myResults2 = new StaticTextWidget(this, font, xpos + lwidth, ypos, _w - lwidth - 20, fontHeight, "", kTextAlignLeft); myResults2->setFlags(WIDGET_CLEARBG); ypos += buttonHeight + 8; new StaticTextWidget(this, font, xpos, ypos, _w - 20, fontHeight, "(*) WARNING: operation cannot be undone", kTextAlignLeft); // Add OK and Cancel buttons addOKCancelBGroup(wid, font, "Audit", "Done"); addBGroupToFocusList(wid); // Create file browser dialog myBrowser = new BrowserDialog(this, font, myMaxWidth, myMaxHeight); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RomAuditDialog::~RomAuditDialog() { delete myBrowser; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomAuditDialog::loadConfig() { const string& currentdir = instance().launcher().currentNode().getShortPath(); const string& path = currentdir == "" ? instance().settings().getString("romdir") : currentdir; myRomPath->setText(path); myResults1->setLabel(""); myResults2->setLabel(""); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomAuditDialog::auditRoms() { const string& auditPath = myRomPath->getText(); myResults1->setLabel(""); myResults2->setLabel(""); 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().font(), "Auditing ROM files ..."); progress.setRange(0, files.size() - 1, 5); // Create a entry for the GameList for each file Properties props; int renamed = 0, notfound = 0; for(unsigned int idx = 0; idx < files.size(); idx++) { 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(files[idx]); 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)) renamed++; } else notfound++; } // Update the progress bar, indicating one more ROM has been processed progress.setProgress(idx); } progress.close(); myResults1->setValue(renamed); myResults2->setValue(notfound); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomAuditDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case 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 = new GUI::MessageBox(this, instance().font(), msg, myMaxWidth, myMaxHeight, kConfirmAuditCmd); } 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->setLabel(""); myResults2->setLabel(""); break; } default: Dialog::handleCommand(sender, cmd, data, 0); break; } } stella-3.9.3/src/gui/EditTextWidget.hxx0000644000175000001440000000275112266336753017423 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: EditTextWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 = ""); void setText(const string& str, bool changed = false); void handleMouseDown(int x, int y, int button, int clickCount); protected: void drawWidget(bool hilite); void lostFocusWidget(); void startEditMode(); void endEditMode(); void abortEditMode(); GUI::Rect getEditRect() const; protected: string _backupString; int _editable; bool _changed; }; #endif stella-3.9.3/src/gui/MessageBox.hxx0000644000175000001440000000362012266336753016556 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: MessageBox.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef MESSAGE_BOX_HXX #define MESSAGE_BOX_HXX class GuiObject; class StaticTextWidget; #include "Dialog.hxx" #include "Command.hxx" #include "DialogContainer.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 = "", const string& cancelText = ""); MessageBox(GuiObject* boss, const GUI::Font& font, const string& text, int max_w, int max_h, int cmd = 0, const string& okText = "", const string& cancelText = ""); virtual ~MessageBox(); /** 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); private: int myCmd; }; } // namespace GUI #endif stella-3.9.3/src/gui/UIDialog.hxx0000644000175000001440000000442512266336753016162 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: UIDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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); ~UIDialog(); protected: TabWidget* myTab; // Launcher options SliderWidget* myLauncherWidthSlider; StaticTextWidget* myLauncherWidthLabel; SliderWidget* myLauncherHeightSlider; StaticTextWidget* myLauncherHeightLabel; PopUpWidget* myLauncherExitPopup; PopUpWidget* myLauncherFontPopup; PopUpWidget* myRomViewerPopup; // Debugger options SliderWidget* myDebuggerWidthSlider; StaticTextWidget* myDebuggerWidthLabel; SliderWidget* myDebuggerHeightSlider; StaticTextWidget* myDebuggerHeightLabel; PopUpWidget* myDebuggerFontStyle; // Misc options PopUpWidget* myPalettePopup; PopUpWidget* myListDelayPopup; PopUpWidget* myWheelLinesPopup; private: void loadConfig(); void saveConfig(); void setDefaults(); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); enum { kLWidthChanged = 'UIlw', kLHeightChanged = 'UIlh', kDWidthChanged = 'UIdw', kDHeightChanged = 'UIdh', kDSmallSize = 'UIds', kDMediumSize = 'UIdm', kDLargeSize = 'UIdl' }; }; #endif stella-3.9.3/src/gui/ConsoleBFont.hxx0000644000175000001440000011311112266336753017051 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ConsoleBFont.hxx 2838 2014-01-17 23:34:03Z stephena $ // // 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 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, 30, 97, consoleB_font_bits, 0, /* no encode table*/ 0, /* fixed width*/ 0, /* fixed bbox*/ 32, // Originally 30 sizeof(consoleB_font_bits)/sizeof(uInt16) }; } // End of namespace GUI #endif stella-3.9.3/src/gui/ConsoleMediumFont.hxx0000644000175000001440000012661112266336753020121 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ConsoleMediumFont.hxx 2838 2014-01-17 23:34:03Z stephena $ // // 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 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, 0x0800, 0x4900, 0x2a00, 0x1c00, 0x2a00, 0x4900, 0x0800, 0x0000, 0x0000, 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, 30, 97, consoleMedium_font_bits, 0, /* no encode table*/ 0, /* fixed width*/ 0, /* fixed bbox*/ 32, // Originally 30 sizeof(consoleMedium_font_bits)/sizeof(uInt16) }; } // End of namespace GUI #endif stella-3.9.3/src/gui/Dialog.cxx0000644000175000001440000005146312266336753015723 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Dialog.cxx 2838 2014-01-17 23:34:03Z stephena $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #include "OSystem.hxx" #include "FrameBuffer.hxx" #include "Menu.hxx" #include "Dialog.hxx" #include "Widget.hxx" #include "TabWidget.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, bool isBase) : GuiObject(*instance, *parent, *this, x, y, w, h), _mouseWidget(0), _focusedWidget(0), _dragWidget(0), _okWidget(0), _cancelWidget(0), _visible(false), _isBase(isBase), _processCancel(false), _surface(0), _tabID(0) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Dialog::~Dialog() { _myFocus.list.clear(); _myTabList.clear(); delete _firstWidget; _firstWidget = NULL; _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() // Base surfaces are typically large, and will probably cause slow // performance if we update the whole area each frame // Instead, dirty rectangle updates should be performed // However, this policy is left entirely to the framebuffer // We suggest the hint here, but specific framebuffers are free to // ignore it if(_surface == NULL) { uInt32 surfaceID = instance().frameBuffer().allocateSurface(_w, _h, _isBase); _surface = instance().frameBuffer().surface(surfaceID); } parent().addDialog(this); center(); loadConfig(); // (Re)-build the focus list to use for the widgets which are currently // onscreen buildCurrentFocusList(); _visible = true; if(refresh) instance().frameBuffer().refresh(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::close(bool refresh) { if (_mouseWidget) { _mouseWidget->handleMouseLeft(0); _mouseWidget = 0; } releaseFocus(); _visible = false; parent().removeDialog(); if(refresh) instance().frameBuffer().refresh(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::center() { if(_surface) { const GUI::Rect& screen = instance().frameBuffer().screenRect(); uInt32 x = (screen.width() - getWidth()) >> 1; uInt32 y = (screen.height() - getHeight()) >> 1; _surface->setPos(x, y); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::releaseFocus() { if(_focusedWidget) { _focusedWidget->lostFocus(); _focusedWidget = 0; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(uInt32 i = 0; i < list.size(); ++i) list[i]->setFlags(WIDGET_RETAIN_FOCUS); _myFocus.list.push_back(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(uInt32 i = 0; i < list.size(); ++i) list[i]->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()) focus[id].list.push_back(list); else { // Make sure the array is large enough while(focus.size() <= id) focus.push_back(Focus()); focus[id].list.push_back(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 = 0; 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(uInt32 id = 0; id < _myTabList.size(); ++id) _myTabList[id].appendFocusList(_focusList); // Add remaining items from main focus list _focusList.push_back(_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) _focusList.push_back(_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::redrawFocus() { if(_focusedWidget) _focusedWidget = Widget::setFocusForChain(this, getFocusList(), _focusedWidget, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::draw() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::drawDialog() { if(!isVisible()) return; FBSurface& s = surface(); if(_dirty) { // cerr << "Dialog::drawDialog(): w = " << _w << ", h = " << _h << " @ " << &s << endl << endl; s.fillRect(_x, _y, _w, _h, kDlgColor); s.box(_x, _y, _w, _h, kColor, kShadowColor); // 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 redrawFocus(); // Tell the surface this area is dirty s.addDirtyRect(_x, _y, _w, _h); _dirty = false; } // Commit surface changes to screen s.update(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleKeyDown(StellaKey key, StellaMod mod, char ascii) { // Test for TAB character // Shift-left/shift-right cursor selects next 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 // For some strange reason, 'tab' needs to be interpreted as keycode, // not ascii?? if(instance().eventHandler().kbdShift(mod)) { if(key == KBDK_LEFT && cycleTab(-1)) return; else if(key == KBDK_RIGHT && cycleTab(+1)) return; else if(key == KBDK_TAB) e = Event::UINavPrev; } else if(key == KBDK_TAB) 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, ascii); else _focusedWidget->handleEvent(e); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleKeyUp(StellaKey key, StellaMod mod, char ascii) { // Focused widget receives keyup events if(_focusedWidget) _focusedWidget->handleKeyUp(key, mod, ascii); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleMouseDown(int x, int y, int button, int clickCount) { Widget* w = findWidget(x, y); _dragWidget = w; setFocus(w); if(w) w->handleMouseDown(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), button, clickCount); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleMouseUp(int x, int y, int button, 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), button, clickCount); _dragWidget = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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, int button) { 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(button); _mouseWidget = w; w->handleMouseEntered(button); } else if (!mouseInFocusedWidget && _mouseWidget == w) { _mouseWidget = 0; w->handleMouseLeft(button); } w->handleMouseMoved(x - wx, y - wy, button); } // 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(button); if (w) w->handleMouseEntered(button); _mouseWidget = w; } if (w && (w->getFlags() & WIDGET_TRACK_MOUSE)) w->handleMouseMoved(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), button); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Dialog::handleMouseClicks(int x, int y, int button) { Widget* w = findWidget(x, y); if(w) return w->handleMouseClicks(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), button); 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, int 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; break; } 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 kTabChangedCmd: if(_visible) buildCurrentFocusList(id); break; case 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) { return Widget::findWidgetInChain(_firstWidget, x, y); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::addOKCancelBGroup(WidgetArray& wid, const GUI::Font& font, const string& okText, const string& cancelText) { int buttonWidth = BSPF_max(font.getStringWidth("Cancel"), BSPF_max(font.getStringWidth(okText), font.getStringWidth(okText))) + 15; int buttonHeight = font.getLineHeight() + 4; ButtonWidget* b; #ifndef MAC_OSX b = new ButtonWidget(this, font, _w - 2 * (buttonWidth + 7), _h - buttonHeight - 10, buttonWidth, buttonHeight, okText == "" ? "OK" : okText, kOKCmd); wid.push_back(b); addOKWidget(b); b = new ButtonWidget(this, font, _w - (buttonWidth + 10), _h - buttonHeight - 10, buttonWidth, buttonHeight, cancelText == "" ? "Cancel" : cancelText, kCloseCmd); wid.push_back(b); addCancelWidget(b); #else b = new ButtonWidget(this, font, _w - 2 * (buttonWidth + 7), _h - buttonHeight - 10, buttonWidth, buttonHeight, cancelText == "" ? "Cancel" : cancelText, kCloseCmd); wid.push_back(b); addCancelWidget(b); b = new ButtonWidget(this, font, _w - (buttonWidth + 10), _h - buttonHeight - 10, buttonWidth, buttonHeight, okText == "" ? "OK" : okText, kOKCmd); wid.push_back(b); addOKWidget(b); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Dialog::Focus::Focus(Widget* w) : widget(w) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Dialog::Focus::~Focus() { list.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Dialog::TabFocus::TabFocus(TabWidget* w) : widget(w), currentTab(0) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Dialog::TabFocus::~TabFocus() { focus.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::TabFocus::appendFocusList(WidgetArray& list) { int active = widget->getActiveTab(); if(active >= 0 && active < (int)focus.size()) list.push_back(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 : 0; } stella-3.9.3/src/gui/CommandDialog.cxx0000644000175000001440000001275212266336753017220 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CommandDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Console.hxx" #include "TIA.hxx" #include "Switches.hxx" #include "DialogContainer.hxx" #include "Dialog.hxx" #include "EventHandler.hxx" #include "OSystem.hxx" #include "Widget.hxx" #include "CommandDialog.hxx" #define addCDButton(label, cmd) \ new ButtonWidget(this, font, xoffset, yoffset, buttonWidth, buttonHeight, label, cmd); xoffset += buttonWidth + 6 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CommandDialog::CommandDialog(OSystem* osystem, DialogContainer* parent) : Dialog(osystem, parent, 0, 0, 16, 16) { const GUI::Font& font = instance().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]; // Row 1 int xoffset = 10, yoffset = 10; b[0] = addCDButton("Select", kSelectCmd); b[4] = addCDButton("Left Diff A", kLeftDiffACmd); b[8] = addCDButton("Save State", kSaveStateCmd); // Row 2 xoffset = 10; yoffset += buttonHeight + 3; b[1] = addCDButton("Reset", kResetCmd); b[5] = addCDButton("Left Diff B", kLeftDiffBCmd); b[9] = addCDButton("State Slot", kStateSlotCmd); // Row 3 xoffset = 10; yoffset += buttonHeight + 3; b[2] = addCDButton("Color TV", kColorCmd); b[6] = addCDButton("Right Diff A", kRightDiffACmd); b[10] = addCDButton("Load State", kLoadStateCmd); // Row 4 xoffset = 10; yoffset += buttonHeight + 3; b[3] = addCDButton("B/W TV", kBWCmd); b[7] = addCDButton("Right Diff B", kRightDiffBCmd); b[11] = addCDButton("Snapshot", kSnapshotCmd); // Row 5 xoffset = 10; yoffset += buttonHeight + 3; b[12] = addCDButton("NTSC/PAL", kFormatCmd); b[13] = addCDButton("Palette", kPaletteCmd); b[14] = addCDButton("Reload ROM", kReloadRomCmd); // Row 6 xoffset = 10 + buttonWidth + 6; yoffset += buttonHeight + 3; b[15] = addCDButton("Exit Game", kExitCmd); for(uInt8 i = 0; i < 16; ++i) wid.push_back(b[i]); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CommandDialog::~CommandDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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().frameBuffer().refresh(); 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); instance().frameBuffer().refresh(); } else if(stateCmd) { instance().eventHandler().handleEvent(event, 1); } } stella-3.9.3/src/gui/ScrollBarWidget.hxx0000644000175000001440000000430112266336753017545 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ScrollBarWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 { protected: public: ScrollBarWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h); virtual void handleMouseDown(int x, int y, int button, int clickCount); virtual void handleMouseUp(int x, int y, int button, int clickCount); virtual void handleMouseWheel(int x, int y, int direction); virtual void handleMouseMoved(int x, int y, int button); virtual bool handleMouseClicks(int x, int y, int button); virtual void handleMouseEntered(int button); virtual void handleMouseLeft(int button); void recalc(); static void setWheelLines(int lines) { _WHEEL_LINES = lines; } static int getWheelLines() { return _WHEEL_LINES; } private: void drawWidget(bool hilite); void checkBounds(int old_pos); public: int _numEntries; int _entriesPerPage; int _currentPos; int _wheel_lines; private: typedef enum { kNoPart, kUpArrowPart, kDownArrowPart, kSliderPart, kPageUpPart, kPageDownPart } Part; Part _part; Part _draggingPart; int _sliderHeight; int _sliderPos; int _sliderDeltaMouseDownPos; static int _WHEEL_LINES; }; #endif stella-3.9.3/src/gui/StellaLargeFont.hxx0000644000175000001440000015646312266336753017565 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: StellaLargeFont.hxx 2838 2014-01-17 23:34:03Z stephena $ // // 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[] = { /* 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, 32, 95, stellaLarge_font_bits, 0, /* no encode table*/ 0, /* fixed width*/ 0, /* fixed bbox*/ 32, sizeof(stellaLarge_font_bits)/sizeof(uInt16) }; } // End of namespace GUI #endif stella-3.9.3/src/gui/VideoDialog.hxx0000644000175000001440000001055412266336753016713 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: VideoDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 "bspf.hxx" class VideoDialog : public Dialog { public: VideoDialog(OSystem* osystem, DialogContainer* parent, const GUI::Font& font, int max_w, int max_h); ~VideoDialog(); private: void loadConfig(); void saveConfig(); void setDefaults(); void handleFullscreenChange(bool enable); void handleTVModeChange(NTSCFilter::Preset); void loadTVAdjustables(NTSCFilter::Preset preset); void handleCommand(CommandSender* sender, int cmd, int data, int id); private: TabWidget* myTab; // General options StaticTextWidget* myRenderer; PopUpWidget* myRendererPopup; PopUpWidget* myTIAFilterPopup; PopUpWidget* myTIAPalettePopup; PopUpWidget* myFSResPopup; PopUpWidget* myFrameTimingPopup; PopUpWidget* myGLFilterPopup; SliderWidget* myNAspectRatioSlider; StaticTextWidget* myNAspectRatioLabel; SliderWidget* myPAspectRatioSlider; StaticTextWidget* myPAspectRatioLabel; SliderWidget* myFrameRateSlider; StaticTextWidget* myFrameRateLabel; PopUpWidget* myFullscreenPopup; CheckboxWidget* myColorLossCheckbox; CheckboxWidget* myGLStretchCheckbox; CheckboxWidget* myUseVSyncCheckbox; CheckboxWidget* myUIMessagesCheckbox; CheckboxWidget* myCenterCheckbox; CheckboxWidget* myFastSCBiosCheckbox; // 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 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', kFullScrChanged = 'VDfs', kTVModeChanged = 'VDtv', kTVSharpChanged = 'TVsh', kTVHueChanged = 'TVhu', kTVResChanged = 'TVrs', kTVArtifactsChanged = 'TVar', kTVFringeChanged = 'TVfr', kTVBleedChanged = 'TVbl', kTVBrightChanged = 'TVbr', kTVContrastChanged = 'TVct', kTVSaturChanged = 'TVsa', kTVGammaChanged = 'TVga', kTVScanIntenseChanged= 'TVsc', kCloneCompositeCmd = 'CLcp', kCloneSvideoCmd = 'CLsv', kCloneRGBCmd = 'CLrb', kCloneBadCmd = 'CLbd', kCloneCustomCmd = 'CLcu' }; }; #endif stella-3.9.3/src/gui/Command.hxx0000644000175000001440000000357712266336753016112 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Command.hxx 2838 2014-01-17 23:34:03Z stephena $ // // 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 @version $Id: Command.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class CommandReceiver; class CommandSender; class CommandReceiver { friend class CommandSender; public: virtual ~CommandReceiver() {} 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() {} 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-3.9.3/src/gui/AudioDialog.cxx0000644000175000001440000001620412266336753016677 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: AudioDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "bspf.hxx" #include "Console.hxx" #include "Control.hxx" #include "Dialog.hxx" #include "Menu.hxx" #include "OSystem.hxx" #include "PopUpWidget.hxx" #include "StringList.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, 0, 0, 0, 0) { 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, "", kTextAlignLeft); myVolumeLabel->setFlags(WIDGET_CLEARBG); ypos += lineHeight + 4; // Fragment size items.clear(); items.push_back("128 bytes", "128"); items.push_back("256 bytes", "256"); items.push_back("512 bytes", "512"); items.push_back("1 KB", "1024"); items.push_back("2 KB", "2048"); items.push_back("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(); items.push_back("11025 Hz", "11025"); items.push_back("22050 Hz", "22050"); items.push_back("31400 Hz", "31400"); items.push_back("44100 Hz", "44100"); items.push_back("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().infoFont(); new StaticTextWidget(this, infofont, 10, ypos, font.getStringWidth("(*) Requires application restart"), fontHeight, "(*) Requires application restart", kTextAlignLeft); // Add Defaults, OK and Cancel buttons ButtonWidget* b; b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Defaults", kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AudioDialog::~AudioDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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().console()) 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 kOKCmd: saveConfig(); close(); break; case 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-3.9.3/src/gui/InputDialog.cxx0000644000175000001440000003324312266336753016737 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: InputDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "Array.hxx" #include "OSystem.hxx" #include "Joystick.hxx" #include "Paddles.hxx" #include "Settings.hxx" #include "StringList.hxx" #include "EventMappingWidget.hxx" #include "EditTextWidget.hxx" #include "PopUpWidget.hxx" #include "TabWidget.hxx" #include "Widget.hxx" #include "InputDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - InputDialog::InputDialog(OSystem* osystem, DialogContainer* parent, const GUI::Font& font, int max_w, int max_h) : Dialog(osystem, parent, 0, 0, 0, 0) { 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; WidgetArray wid; StringList actions; // Set real dimensions _w = BSPF_min(50 * fontWidth + 10, max_w); _h = BSPF_min(14 * (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"); instance().eventHandler().getActionList(kEmulationMode, actions); 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.clear(); instance().eventHandler().getActionList(kMenuMode, actions); 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 wid.clear(); ButtonWidget* b; b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Defaults", 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; // Devices/ports tabID = myTab->addTab("Devices & Ports"); // Stelladaptor mappings xpos = 5; ypos = 5; lwidth = font.getStringWidth("Use mouse as a controller: "); pwidth = font.getStringWidth("Analog devices"); items.clear(); items.push_back("Left / Right", "lr"); items.push_back("Right / Left", "rl"); mySAPort = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Stelladaptor port order: ", lwidth); wid.push_back(mySAPort); // Use mouse as controller ypos += lineHeight + 5; items.clear(); items.push_back("Always", "always"); items.push_back("Analog devices", "analog"); items.push_back("Never", "never"); myMouseControl = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Use mouse as a controller: ", lwidth); wid.push_back(myMouseControl); // Add AtariVox serial port ypos += lineHeight + 5; lwidth = font.getStringWidth("AVox serial port: "); int fwidth = _w - xpos - lwidth - 20; new StaticTextWidget(myTab, font, xpos, ypos, lwidth, fontHeight, "AVox serial port: ", kTextAlignLeft); myAVoxPort = new EditTextWidget(myTab, font, xpos+lwidth, ypos, fwidth, fontHeight, ""); wid.push_back(myAVoxPort); lwidth = font.getStringWidth("Digital paddle sensitivity: "); pwidth = font.getMaxCharWidth() * 8; // Add joystick deadzone setting ypos += lineHeight + 8; myDeadzone = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight, "Joystick deadzone size: ", lwidth, kDeadzoneChanged); myDeadzone->setMinValue(0); myDeadzone->setMaxValue(29); xpos += myDeadzone->getWidth() + 5; myDeadzoneLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 5*fontWidth, lineHeight, "", kTextAlignLeft); myDeadzoneLabel->setFlags(WIDGET_CLEARBG); wid.push_back(myDeadzone); // Add paddle speed (digital emulation) xpos = 5; ypos += lineHeight + 4; myDPaddleSpeed = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight, "Digital paddle sensitivity: ", lwidth, kDPSpeedChanged); myDPaddleSpeed->setMinValue(1); myDPaddleSpeed->setMaxValue(10); xpos += myDPaddleSpeed->getWidth() + 5; myDPaddleLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 24, lineHeight, "", kTextAlignLeft); myDPaddleLabel->setFlags(WIDGET_CLEARBG); wid.push_back(myDPaddleSpeed); // Add paddle speed (mouse emulation) xpos = 5; ypos += lineHeight + 4; myMPaddleSpeed = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight, "Mouse paddle sensitivity: ", lwidth, kMPSpeedChanged); myMPaddleSpeed->setMinValue(1); myMPaddleSpeed->setMaxValue(15); xpos += myMPaddleSpeed->getWidth() + 5; myMPaddleLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 24, lineHeight, "", kTextAlignLeft); myMPaddleSpeed->setFlags(WIDGET_CLEARBG); wid.push_back(myMPaddleSpeed); // Add 'allow all 4 directions' for joystick xpos = 10; ypos += lineHeight + 12; myAllowAll4 = new CheckboxWidget(myTab, font, xpos, ypos, "Allow all 4 directions on joystick"); wid.push_back(myAllowAll4); // Grab mouse (in windowed mode) ypos += lineHeight + 4; myGrabMouse = new CheckboxWidget(myTab, font, xpos, ypos, "Grab mouse in emulation mode"); wid.push_back(myGrabMouse); #ifndef WINDOWED_SUPPORT myGrabMouse->clearFlags(WIDGET_ENABLED); #endif // 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"); // Joystick deadzone myDeadzone->setValue(instance().settings().getInt("joydeadzone")); myDeadzoneLabel->setValue(Joystick::deadzone()); // Grab mouse myGrabMouse->setState(instance().settings().getBool("grabmouse")); // 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")); // AtariVox serial port myAVoxPort->setText(instance().settings().getString("avoxport")); // Allow all 4 joystick directions myAllowAll4->setState(instance().settings().getBool("joyallow4")); 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); // Grab mouse instance().settings().setValue("grabmouse", myGrabMouse->getState()); instance().frameBuffer().setCursorState(); // 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); // 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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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"); // Joystick deadzone myDeadzone->setValue(0); myDeadzoneLabel->setValue(3200); // Grab mouse myGrabMouse->setState(true); // Paddle speed (digital and mouse) myDPaddleSpeed->setValue(5); myDPaddleLabel->setLabel("5"); myMPaddleSpeed->setValue(6); myMPaddleLabel->setLabel("6"); // AtariVox serial port myAVoxPort->setText(""); // Allow all 4 joystick directions myAllowAll4->setState(false); break; } default: break; } _dirty = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::handleKeyDown(StellaKey key, StellaMod mod, char ascii) { // Remap key events in remap mode, otherwise pass to parent dialog if(myEmulEventMapper->remapMode()) myEmulEventMapper->handleKeyDown(key, mod, ascii); else if(myMenuEventMapper->remapMode()) myMenuEventMapper->handleKeyDown(key, mod, ascii); else Dialog::handleKeyDown(key, mod, ascii); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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, int 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::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case kOKCmd: saveConfig(); close(); break; case kCloseCmd: // Revert changes made to event mapping close(); break; case 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; default: Dialog::handleCommand(sender, cmd, data, 0); } } stella-3.9.3/src/gui/ContextMenu.hxx0000644000175000001440000001010112266336753016762 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ContextMenu.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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); virtual ~ContextMenu(); /** 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(); /** 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(); protected: void handleMouseDown(int x, int y, int button, int clickCount); void handleMouseMoved(int x, int y, int button); bool handleMouseClicks(int x, int y, int button); void handleMouseWheel(int x, int y, int direction); void handleKeyDown(StellaKey key, StellaMod mod, char ascii); void handleJoyDown(int stick, int button); void handleJoyAxis(int stick, int axis, int value); bool handleJoyHat(int stick, int hat, int value); void handleEvent(Event::Type e); void drawDialog(); private: 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; }; #endif stella-3.9.3/src/debugger/0000755000175000001440000000000012267274564014771 5ustar stephenusersstella-3.9.3/src/debugger/DebuggerParser.hxx0000644000175000001440000001274512266336753020432 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DebuggerParser.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef DEBUGGER_PARSER_HXX #define DEBUGGER_PARSER_HXX #include class Debugger; class FilesystemNode; struct Command; #include "bspf.hxx" #include "Array.hxx" #include "FrameBuffer.hxx" #include "Settings.hxx" class DebuggerParser { public: DebuggerParser(Debugger& debugger, Settings& settings); ~DebuggerParser(); /** Run the given command, and return the result */ string run(const string& command); /** Execute parser commands given in 'file' */ string exec(const FilesystemNode& file); /** 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(kDbgChangedColor) + 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 trapStatus(int addr); bool saveScriptFile(string file); private: enum { kNumCommands = 70, kMAX_ARG_TYPES = 10 }; // Constants for argument processing enum { kIN_COMMAND, kIN_SPACE, kIN_BRACE, kIN_ARG }; typedef enum { kARG_WORD, // single 16-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 } parameters; // Pointer to DebuggerParser instance method, no args, returns void. typedef void (DebuggerParser::*METHOD)(); struct Command { string cmdString; string description; bool parmsRequired; bool refreshRequired; parameters parms[kMAX_ARG_TYPES]; METHOD executor; }; // 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; // Arguments in 'int' and 'string' format for the currently running command IntArray args; StringList argStrings; int argCount; StringList watches; // List of available command methods void executeA(); void executeBank(); void executeBase(); void executeBreak(); void executeBreakif(); void executeC(); void executeCheat(); void executeClearbreaks(); void executeClearconfig(); void executeCleartraps(); void executeClearwatches(); void executeCls(); void executeCode(); void executeColortest(); void executeD(); void executeData(); void executeDefine(); void executeDelbreakif(); void executeDelfunction(); void executeDelwatch(); void executeDisasm(); void executeDump(); void executeExec(); void executeExitRom(); void executeFrame(); void executeFunction(); void executeGfx(); void executeHelp(); void executeJump(); void executeListbreaks(); void executeListconfig(); void executeListfunctions(); void executeListtraps(); void executeLoadconfig(); void executeLoadstate(); void executeN(); 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 executeSavestate(); void executeScanline(); void executeStep(); void executeTia(); void executeTrace(); void executeTrap(); void executeTrapread(); void executeTrapwrite(); void executeType(); void executeUHex(); void executeUndef(); void executeV(); void executeWatch(); void executeX(); void executeY(); void executeZ(); // List of commands available static Command commands[kNumCommands]; }; #endif stella-3.9.3/src/debugger/DiStella.hxx0000644000175000001440000001472012266336753017225 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DiStella.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef DISTELLA_HXX #define DISTELLA_HXX #include #include #include "Array.hxx" #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 all commandline options. Over time, some of the configurability of Distella may be added again. @author Stephen Anthony */ 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 typedef struct { Common::Base::Format gfx_format; bool resolve_code; // Attempt to detect code vs. data sections bool show_addresses; // 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) int bwidth; // Number of bytes to use per line (with .byte xxx) } Settings; 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); ~DiStella(); 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); bool check_range(uInt16 start, uInt16 end) const; int mark(uInt32 address, uInt8 mask, bool directive = false); bool check_bit(uInt16 address, uInt8 mask) const; // 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; queue myAddressQueue; uInt16 myOffset, myPC, myPCBeg, myPCEnd; 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* mnemonic; AddressingMode addr_mode; AccessMode source; ReadWriteMode rw_mode; uInt8 cycles; }; static const Instruction_tag ourLookup[256]; }; #endif stella-3.9.3/src/debugger/CartDebug.hxx0000644000175000001440000003342612266336753017370 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDebug.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CART_DEBUG_HXX #define CART_DEBUG_HXX class Settings; class CartDebugWidget; #include #include #include #include "bspf.hxx" #include "Array.hxx" #include "Base.hxx" #include "Cart.hxx" #include "DebuggerSystem.hxx" #include "System.hxx" // pointer types for CartDebug instance methods class CartDebug; typedef int (CartDebug::*CARTDEBUG_INT_METHOD)(); // call the pointed-to method on the (global) CPU debugger object. #define CALL_CARTDEBUG_METHOD(method) ( ( Debugger::debugger().cartDebug().*method)() ) class CartState : public DebuggerState { public: IntArray ram; // The actual data values IntArray rport; // Address for reading from RAM IntArray 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, /* code somewhere in the program references it, i.e. LDA $F372 referenced $F372 */ VALID_ENTRY = 1 << 1, /* 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, // disassemble-able code segments TCODE = 1 << 6, // (tentative) disassemble-able code segments GFX = 1 << 5, // addresses loaded into GRPx registers PGFX = 1 << 4, // addresses loaded into PFx registers DATA = 1 << 3, // addresses loaded into registers other than GRPx / PFx ROW = 1 << 2 // all other addresses }; struct DisassemblyTag { DisasmType type; uInt16 address; string label; string disasm; string ccount; string bytes; bool hllabel; }; typedef Common::Array DisassemblyList; struct Disassembly { DisassemblyList list; int fieldwidth; }; public: CartDebug(Debugger& dbg, Console& console, const OSystem& osystem); virtual ~CartDebug(); const DebuggerState& getState(); const DebuggerState& getOldState() { return myOldState; } void saveOldState(); string toString(); // Used to get/set the debug widget, which contains cart-specific // functionality CartDebugWidget* getDebugWidget() const { return myDebugWidget; } void setDebugWidget(CartDebugWidget* w) { myDebugWidget = w; } // The following assume that the given addresses are using the // correct read/write port ranges; no checking will be done to // confirm this. uInt8 peek(uInt16 addr) { return mySystem.peek(addr); } uInt16 dpeek(uInt16 addr) { return mySystem.peek(addr) | (mySystem.peek(addr+1) << 8); } void poke(uInt16 addr, uInt8 value) { mySystem.poke(addr, value); } // 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(); /** Let the Cart debugger subsystem treat this area as addressable memory. @param start The beginning of the RAM area (0x0000 - 0x2000) @param size Total number of bytes of area @param roffset Offset to use when reading from RAM (read port) @param woffset Offset to use when writing to RAM (write port) */ void addRamArea(uInt16 start, uInt16 size, uInt16 roffset, uInt16 woffset); // 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. */ int getBank(); // non-const because of use in YaccParser /** Get the total number of banks supported by the cartridge. */ int bankCount() const; /** Get the name/type of the cartridge. */ string getCartType() 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: typedef map AddrToLabel; typedef map LabelToAddr; // 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; struct DirectiveTag { DisasmType type; uInt16 start; uInt16 end; }; typedef list AddressList; typedef list DirectiveList; struct BankInfo { uInt16 start; // start of address space uInt16 end; // end of address space uInt16 offset; // ORG value uInt16 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) { } #if 0 friend ostream& operator<<(ostream& os, const BankInfo& b) { os << "start=$" << HEX4 << b.start << ", end=$" << HEX4 << b.end << ", offset=$" << HEX4 << b.offset << ", size=" << dec << b.size << endl << "addrlist: "; AddressList::const_iterator i; for(i = b.addressList.begin(); i != b.addressList.end(); ++i) os << HEX4 << *i << " "; return os; } #endif }; // 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; }; 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 Common::Array myBankInfo; // Used for the disassembly display, and mapping from addresses // to corresponding lines of text in that display Disassembly myDisassembly; 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* ourTIAMnemonicR[16]; // read mode static const char* ourTIAMnemonicW[64]; // write mode static const char* ourIOMnemonic[24]; static const char* ourZPMnemonic[128]; }; #endif stella-3.9.3/src/debugger/Expression.hxx0000644000175000001440000000300612266336753017656 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Expression.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef EXPRESSION_HXX #define EXPRESSION_HXX #include "bspf.hxx" // define this to count Expression instances. Only useful for debugging // Stella itself. //#define EXPR_REF_COUNT /** 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 @version $Id: Expression.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class Expression { public: Expression(Expression* lhs, Expression* rhs); virtual ~Expression(); virtual uInt16 evaluate() const = 0; protected: Expression* myLHS; Expression* myRHS; }; #endif stella-3.9.3/src/debugger/CpuDebug.hxx0000644000175000001440000000545312266336753017225 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CpuDebug.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CPU_DEBUG_HXX #define CPU_DEBUG_HXX class EquateList; #include "Array.hxx" #include "M6502.hxx" #include "System.hxx" #include "DebuggerSystem.hxx" // pointer types for CpuDebug instance methods typedef int (CpuDebug::*CPUDEBUG_INT_METHOD)(); // call the pointed-to method on the (global) CPU debugger object. #define CALL_CPUDEBUG_METHOD(method) ( ( Debugger::debugger().cpuDebug().*method)() ) 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(); const DebuggerState& getOldState() { return myOldState; } void saveOldState(); string toString() { return ""; } // Not needed, since CPU stuff is always visible // I know, we ain't supposed to do this... M6502& m6502() { return mySystem.m6502(); } int pc() { return mySystem.m6502().PC; } int sp() { return mySystem.m6502().SP; } int a() { return mySystem.m6502().A; } int x() { return mySystem.m6502().X; } int y() { return mySystem.m6502().Y; } // These return int, not boolean! int n() { return mySystem.m6502().N; } int v() { return mySystem.m6502().V; } int b() { return mySystem.m6502().B; } int d() { return mySystem.m6502().D; } int i() { return mySystem.m6502().I; } int z() { return !mySystem.m6502().notZ; } int c() { return mySystem.m6502().C; } 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 toggleN(); void toggleV(); void toggleB(); void toggleD(); void toggleI(); void toggleZ(); void toggleC(); private: M6502& my6502; CpuState myState; CpuState myOldState; }; #endif stella-3.9.3/src/debugger/DebuggerParser.cxx0000644000175000001440000015155212266336753020425 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DebuggerParser.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "bspf.hxx" #include "Dialog.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "CpuDebug.hxx" #include "RiotDebug.hxx" #include "TIADebug.hxx" #include "DebuggerParser.hxx" #include "YaccParser.hxx" #include "M6502.hxx" #include "Expression.hxx" #include "FSNode.hxx" #include "PromptWidget.hxx" #include "RomWidget.hxx" #include "ProgressDialog.hxx" #include "PackedBitArray.hxx" #include "Base.hxx" using namespace Common; #ifdef CHEATCODE_SUPPORT #include "Cheat.hxx" #include "CheatManager.hxx" #endif #include "DebuggerParser.hxx" // Call the pointed-to method on the this object. Whew. #define CALL_METHOD(method) ( (this->*method)() ) // TODO - use C++ streams instead of nasty C-strings and pointers // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DebuggerParser::DebuggerParser(Debugger& d, Settings& s) : debugger(d), settings(s) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DebuggerParser::~DebuggerParser() { args.clear(); argStrings.clear(); watches.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // main entry point: PromptWidget calls this method. string DebuggerParser::run(const string& command) { /* // 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; } */ string verb; getArgs(command, verb); #ifdef EXPR_REF_COUNT extern int refCount; cerr << "Expression count: " << refCount << endl; #endif commandResult.str(""); for(int i = 0; i < kNumCommands; ++i) { if(BSPF_equalsIgnoreCase(verb, commands[i].cmdString)) { if(validateArgs(i)) CALL_METHOD(commands[i].executor); if(commands[i].refreshRequired) debugger.myBaseDialog->loadConfig(); return commandResult.str(); } } return "No such command (try \"help\")"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string DebuggerParser::exec(const FilesystemNode& file) { if(file.exists()) { ifstream in(file.getPath().c_str()); if(!in.is_open()) return red("autoexec file \'" + file.getShortPath() + "\' not found"); ostringstream buf; int count = 0; string command; while( !in.eof() ) { if(!getline(in, command)) break; run(command); count++; } buf << "Executed " << count << " commands from \"" << file.getShortPath() << "\""; return buf.str(); } else return red("autoexec file \'" + file.getShortPath() + "\' not found"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 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_startsWithIgnoreCase(commands[i].cmdString.c_str(), 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) == "\\") { bin = true; dec = false; 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); } // sanity check mutually exclusive options: if(derefByte && derefWord) return -1; if(lobyte && hibyte) return -1; if(bin && dec) return -1; // Special cases (registers): CpuState& state = (CpuState&) debugger.cpuDebug().getState(); if(arg == "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(unsigned int i = 0; i < watches.size(); i++) { if(watches[i] != "") { // Clear the args, since we're going to pass them to eval() argStrings.clear(); args.clear(); argCount = 1; argStrings.push_back(watches[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 = 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 = argStrings.size(); /* cerr << "verb = " << verb << endl; cerr << "arguments (" << argCount << "):\n"; for(int x = 0; x < argCount; x++) cerr << "command " << x << ": " << argStrings[x] << endl; */ /* // Now decipher each argument, in turn. for(int i=0; ievaluate() ); delete e; } } 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(red("missing required argument(s)")); 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 int 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; int curCount = 0; do { if(curCount >= argCount) break; int curArgInt = args[curCount]; string& curArgStr = argStrings[curCount]; switch(*p) { case kARG_WORD: if(curArgInt < 0 || curArgInt > 0xffff) { commandResult.str(red("invalid word argument (must be 0-$ffff)")); return false; } break; case kARG_BYTE: if(curArgInt < 0 || 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(red("missing required argument(s)")); return false; } else if(argCount > curCount) { commandResult.str(red("too many arguments")); return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string DebuggerParser::eval() { ostringstream buf; for(int i = 0; i < argCount; ++i) { 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): "; if(args[i] < 0x100) buf << "$" << Base::toString(args[i], Base::F_16_2) << " %" << Base::toString(args[i], Base::F_2_8); else buf << "$" << Base::toString(args[i], Base::F_16_4) << " %" << Base::toString(args[i], Base::F_2_16); buf << " #" << (int) args[i]; if(i != argCount - 1) buf << endl; } return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string DebuggerParser::trapStatus(int addr) { string result; result += Base::toString(addr); result += ": "; bool r = debugger.readTrap(addr); bool w = debugger.writeTrap(addr); if(r && w) result += "read|write"; else if(r) result += "read"; else if(w) result += " write"; else result += " none "; // TODO - technically, we should determine if the label is read or write const string& l = debugger.cartDebug().getLabel(addr, true); if(l != "") { result += " ("; result += l; result += ")"; } return result; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool DebuggerParser::saveScriptFile(string file) { if( file.find_last_of('.') == string::npos ) { file += ".stella"; } ofstream out(file.c_str()); FunctionDefMap funcs = debugger.getFunctionDefMap(); for(FunctionDefMap::const_iterator i = funcs.begin(); i != funcs.end(); ++i) out << "function " << i->first << " { " << i->second << " }" << endl; for(unsigned int i=0; i= banks) commandResult << red("invalid bank number (must be 0 to ") << (banks - 1) << ")"; else if(debugger.setBank(args[0])) commandResult << "switched bank OK"; else commandResult << red("error switching banks (bankswitching may not be supported)"); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "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 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() { int 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) { uInt32 ret = debugger.cpuDebug().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) { commandResult << red("Missing cheat code"); return; } for(int arg = 0; arg < argCount; arg++) { const string& cheat = argStrings[arg]; const Cheat* c = debugger.myOSystem->cheat().add("DBG", cheat); if(c && c->enabled()) 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.cpuDebug().m6502().clearCondBreaks(); commandResult << "all breakpoints cleared"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "clearconfig" void DebuggerParser::executeClearconfig() { if(argCount == 1) commandResult << debugger.cartDebug().clearConfig(args[0]); else commandResult << debugger.cartDebug().clearConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "cleartraps" void DebuggerParser::executeCleartraps() { debugger.clearAllTraps(); commandResult << "all traps cleared"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "clearwatches" void DebuggerParser::executeClearwatches() { watches.clear(); commandResult << "all watches cleared"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "cls" void DebuggerParser::executeCls() { debugger.prompt().clearScreen(); commandResult << ""; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "code" void DebuggerParser::executeCode() { if(argCount != 2) { commandResult << red("Specify start and end of range only"); 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) { commandResult << red("Specify start and end of range only"); 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(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "define" void DebuggerParser::executeDefine() { // TODO: check if label already defined? debugger.cartDebug().addLabel(argStrings[0], args[1]); debugger.rom().invalidate(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "delbreakif" void DebuggerParser::executeDelbreakif() { debugger.cpuDebug().m6502().delCondBreak(args[0]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "delfunction" void DebuggerParser::executeDelfunction() { if(debugger.delFunction(argStrings[0])) commandResult << "removed function " << argStrings[0]; else commandResult << "function " << argStrings[0] << " not found"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "delwatch" void DebuggerParser::executeDelwatch() { int which = args[0] - 1; if(which >= 0 && which < (int)watches.size()) { watches.remove_at(which); commandResult << "removed watch"; } else commandResult << "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 { commandResult << "wrong number of arguments"; return; } commandResult << debugger.cartDebug().disassemble(start, lines); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "dump" void DebuggerParser::executeDump() { for(int i=0; i<8; i++) { int start = args[0] + i*16; commandResult << Base::toString(start) << ": "; for(int j = 0; j < 16; j++) { commandResult << Base::toString(debugger.peek(start+j)) << " "; if(j == 7) commandResult << "- "; } if(i != 7) commandResult << endl; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "exec" void DebuggerParser::executeExec() { FilesystemNode file(argStrings[0]); commandResult << exec(file); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "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) { commandResult << red("Specify start and end of range only"); 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() { // 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(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "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 & 0xFFF) >= 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(unsigned int i = 0; i < 0x10000; i++) { if(debugger.breakpoints().isSet(i)) { buf << debugger.cartDebug().getLabel(i, true, 4) << " "; if(! (++count % 8) ) buf << "\n"; } } /* if(count) return ret; else return "no breakpoints set"; */ if(count) commandResult << "breaks:\n" << buf.str(); StringList conds = debugger.cpuDebug().m6502().getCondBreakNames(); if(conds.size() > 0) { commandResult << "\nbreakifs:\n"; for(unsigned int i = 0; i < conds.size(); i++) { commandResult << 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) { FunctionDefMap::const_iterator iter; for(iter = functions.begin(); iter != functions.end(); ++iter) commandResult << iter->first << " -> " << iter->second << endl; } else commandResult << "no user-defined functions"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "listtraps" void DebuggerParser::executeListtraps() { int count = 0; for(unsigned int i=0; i<0x10000; i++) { if(debugger.readTrap(i) || debugger.writeTrap(i)) { commandResult << trapStatus(i) << endl; count++; } } if(!count) 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]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "pc" void DebuggerParser::executePc() { debugger.cpuDebug().setPC(args[0]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "pgfx" void DebuggerParser::executePGfx() { if(argCount != 2) { commandResult << red("Specify start and end of range only"); 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(); commandResult << "reset CPU"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "rewind" void DebuggerParser::executeRewind() { if(debugger.rewindState()) { debugger.rom().invalidate(); commandResult << "rewind by one level"; } else commandResult << "no states left to rewind"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "riot" void DebuggerParser::executeRiot() { commandResult << debugger.riotDebug().toString(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "rom" void DebuggerParser::executeRom() { int addr = args[0]; for(int i=1; i= 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]); ++count; } 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() { if(saveScriptFile(argStrings[0])) commandResult << "saved script to file " << argStrings[0]; else commandResult << red("I/O error"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "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() { if(debugger.prompt().saveBuffer(argStrings[0])) commandResult << "saved session to file " << argStrings[0]; else commandResult << red("I/O error"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "savestate" void DebuggerParser::executeSavestate() { if(args[0] >= 0 && args[0] <= 9) debugger.saveState(args[0]); else commandResult << red("invalid slot (must be 0-9)"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "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"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "tia" void DebuggerParser::executeTia() { commandResult << debugger.tiaDebug().toString(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "trace" void DebuggerParser::executeTrace() { commandResult << "executed " << dec << debugger.trace() << " cycles"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "trap" void DebuggerParser::executeTrap() { uInt32 beg = args[0]; uInt32 end = argCount >= 2 ? args[1] : beg; if(beg > end) BSPF_swap(beg, end); for(uInt32 i = beg; i <= end; ++i) { debugger.toggleReadTrap(i); debugger.toggleWriteTrap(i); commandResult << trapStatus(i) << endl; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "trapread" void DebuggerParser::executeTrapread() { uInt32 beg = args[0]; uInt32 end = argCount >= 2 ? args[1] : beg; if(beg > end) BSPF_swap(beg, end); for(uInt32 i = beg; i <= end; ++i) { debugger.toggleReadTrap(i); commandResult << trapStatus(i) << endl; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "trapwrite" void DebuggerParser::executeTrapwrite() { uInt32 beg = args[0]; uInt32 end = argCount >= 2 ? args[1] : beg; if(beg > end) BSPF_swap(beg, end); for(uInt32 i = beg; i <= end; ++i) { debugger.toggleWriteTrap(i); commandResult << trapStatus(i) << endl; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "type" void DebuggerParser::executeType() { uInt32 beg = args[0]; uInt32 end = argCount >= 2 ? args[1] : beg; if(beg > end) BSPF_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"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "v" void DebuggerParser::executeV() { if(argCount == 0) debugger.cpuDebug().toggleV(); else if(argCount == 1) debugger.cpuDebug().setV(args[0]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "watch" void DebuggerParser::executeWatch() { watches.push_back(argStrings[0]); commandResult << "added watch \"" << argStrings[0] << "\""; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "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 value xx", true, true, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeA }, { "bank", "Show # of banks, or switch to bank xx", false, true, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeBank }, { "base", "Set default base (hex, dec, or bin)", true, true, { kARG_BASE_SPCL, kARG_END_ARGS }, &DebuggerParser::executeBase }, { "break", "Set/clear breakpoint at address xx (default=PC)", false, true, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeBreak }, { "breakif", "Set breakpoint on condition xx", true, false, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeBreakif }, { "c", "Carry Flag: set (0 or 1), or toggle (no arg)", false, true, { kARG_BOOL, kARG_END_ARGS }, &DebuggerParser::executeC }, { "cheat", "Use a cheat code (see manual for cheat types)", false, false, { kARG_LABEL, kARG_END_ARGS }, &DebuggerParser::executeCheat }, { "clearbreaks", "Clear all breakpoints", false, true, { kARG_END_ARGS }, &DebuggerParser::executeClearbreaks }, { "clearconfig", "Clear Distella config directives [bank xx]", false, false, { kARG_WORD, kARG_MULTI_BYTE }, &DebuggerParser::executeClearconfig }, { "cleartraps", "Clear all traps", false, false, { kARG_END_ARGS }, &DebuggerParser::executeCleartraps }, { "clearwatches", "Clear all watches", false, false, { kARG_END_ARGS }, &DebuggerParser::executeClearwatches }, { "cls", "Clear prompt area of text and erase history", false, false, { kARG_END_ARGS }, &DebuggerParser::executeCls }, { "code", "Mark 'CODE' range in disassembly", true, false, { kARG_WORD, kARG_MULTI_BYTE }, &DebuggerParser::executeCode }, { "colortest", "Show value xx as TIA color", true, false, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeColortest }, { "d", "Decimal Flag: set (0 or 1), or toggle (no arg)", false, true, { kARG_BOOL, kARG_END_ARGS }, &DebuggerParser::executeD }, { "data", "Mark 'DATA' range in disassembly", true, false, { kARG_WORD, kARG_MULTI_BYTE }, &DebuggerParser::executeData }, { "define", "Define label xx for address yy", true, true, { kARG_LABEL, kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeDefine }, { "delbreakif", "Delete conditional breakif xx", true, false, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeDelbreakif }, { "delfunction", "Delete function with label xx", true, false, { kARG_LABEL, kARG_END_ARGS }, &DebuggerParser::executeDelfunction }, { "delwatch", "Delete watch xx", true, false, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeDelwatch }, { "disasm", "Disassemble address xx [yy lines] (default=PC)", false, false, { kARG_WORD, kARG_MULTI_BYTE }, &DebuggerParser::executeDisasm }, { "dump", "Dump 128 bytes of memory at address xx", true, false, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeDump }, { "exec", "Execute script file xx", true, true, { kARG_FILE, kARG_END_ARGS }, &DebuggerParser::executeExec }, { "exitrom", "Exit emulator, return to ROM launcher", false, false, { kARG_END_ARGS }, &DebuggerParser::executeExitRom }, { "frame", "Advance emulation by xx frames (default=1)", false, true, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeFrame }, { "function", "Define function name xx for expression yy", true, false, { kARG_LABEL, kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeFunction }, { "gfx", "Mark 'CFX' range in disassembly", true, false, { kARG_WORD, kARG_MULTI_BYTE }, &DebuggerParser::executeGfx }, { "help", "This cruft", false, false, { kARG_END_ARGS }, &DebuggerParser::executeHelp }, { "jump", "Scroll disassembly to address xx", true, false, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeJump }, { "listbreaks", "List breakpoints", false, false, { kARG_END_ARGS }, &DebuggerParser::executeListbreaks }, { "listconfig", "List Distella config directives [bank xx]", false, false, { kARG_WORD, kARG_MULTI_BYTE }, &DebuggerParser::executeListconfig }, { "listfunctions", "List user-defined functions", false, false, { kARG_END_ARGS }, &DebuggerParser::executeListfunctions }, { "listtraps", "List traps", false, false, { kARG_END_ARGS }, &DebuggerParser::executeListtraps }, { "loadconfig", "Load Distella config file", false, true, { kARG_END_ARGS }, &DebuggerParser::executeLoadconfig }, { "loadstate", "Load emulator state xx (0-9)", true, true, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeLoadstate }, { "n", "Negative Flag: set (0 or 1), or toggle (no arg)", false, true, { kARG_BOOL, kARG_END_ARGS }, &DebuggerParser::executeN }, { "pc", "Set Program Counter to address xx", true, true, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executePc }, { "pgfx", "Mark 'PGFX' range in disassembly", true, false, { kARG_WORD, kARG_MULTI_BYTE }, &DebuggerParser::executePGfx }, { "print", "Evaluate/print expression xx in hex/dec/binary", true, false, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executePrint }, { "ram", "Show ZP RAM, or set address xx to yy1 [yy2 ...]", false, true, { kARG_WORD, kARG_MULTI_BYTE }, &DebuggerParser::executeRam }, { "reset", "Reset 6507 to init vector (excluding TIA/RIOT)", false, true, { kARG_END_ARGS }, &DebuggerParser::executeReset }, { "rewind", "Rewind state to last step/trace/scanline/frame", false, true, { kARG_END_ARGS }, &DebuggerParser::executeRewind }, { "riot", "Show RIOT timer/input status", false, false, { kARG_END_ARGS }, &DebuggerParser::executeRiot }, { "rom", "Set ROM address xx to yy1 [yy2 ...]", true, true, { kARG_WORD, kARG_MULTI_BYTE }, &DebuggerParser::executeRom }, { "row", "Mark 'ROW' range in disassembly", true, false, { kARG_WORD, kARG_MULTI_BYTE }, &DebuggerParser::executeRow }, { "run", "Exit debugger, return to emulator", false, false, { kARG_END_ARGS }, &DebuggerParser::executeRun }, { "runto", "Run until string xx in disassembly", true, true, { kARG_LABEL, kARG_END_ARGS }, &DebuggerParser::executeRunTo }, { "runtopc", "Run until PC is set to value xx", true, true, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeRunToPc }, { "s", "Set Stack Pointer to value xx", true, true, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeS }, { "save", "Save breaks, watches, traps to file xx", true, false, { kARG_FILE, kARG_END_ARGS }, &DebuggerParser::executeSave }, { "saveconfig", "Save Distella config file", false, false, { kARG_END_ARGS }, &DebuggerParser::executeSaveconfig }, { "savedis", "Save Distella disassembly", false, false, { kARG_END_ARGS }, &DebuggerParser::executeSavedisassembly }, { "saverom", "Save (possibly patched) ROM", false, false, { kARG_END_ARGS }, &DebuggerParser::executeSaverom }, { "saveses", "Save console session to file xx", true, false, { kARG_FILE, kARG_END_ARGS }, &DebuggerParser::executeSaveses }, { "savestate", "Save emulator state xx (valid args 0-9)", true, false, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeSavestate }, { "scanline", "Advance emulation by xx scanlines (default=1)", false, true, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeScanline }, { "step", "Single step CPU [with count xx]", false, true, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeStep }, { "tia", "Show TIA state (NOT FINISHED YET)", false, false, { kARG_END_ARGS }, &DebuggerParser::executeTia }, { "trace", "Single step CPU over subroutines [with count xx]", false, true, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeTrace }, { "trap", "Trap read/write access to address(es) xx [to yy]", true, false, { kARG_WORD, kARG_MULTI_BYTE }, &DebuggerParser::executeTrap }, { "trapread", "Trap read access to address(es) xx [to yy]", true, false, { kARG_WORD, kARG_MULTI_BYTE }, &DebuggerParser::executeTrapread }, { "trapwrite", "Trap write access to address(es) xx [to yy]", true, false, { kARG_WORD, kARG_MULTI_BYTE }, &DebuggerParser::executeTrapwrite }, { "type", "Show disassembly type for address xx [to yy]", true, false, { kARG_WORD, kARG_MULTI_BYTE }, &DebuggerParser::executeType }, { "uhex", "Toggle upper/lowercase HEX display", false, true, { kARG_END_ARGS }, &DebuggerParser::executeUHex }, { "undef", "Undefine label xx (if defined)", true, true, { kARG_LABEL, kARG_END_ARGS }, &DebuggerParser::executeUndef }, { "v", "Overflow Flag: set (0 or 1), or toggle (no arg)", false, true, { kARG_BOOL, kARG_END_ARGS }, &DebuggerParser::executeV }, { "watch", "Print contents of address xx before every prompt", true, false, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeWatch }, { "x", "Set X Register to value xx", true, true, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeX }, { "y", "Set Y Register to value xx", true, true, { kARG_WORD, kARG_END_ARGS }, &DebuggerParser::executeY }, { "z", "Zero Flag: set (0 or 1), or toggle (no arg)", false, true, { kARG_BOOL, kARG_END_ARGS }, &DebuggerParser::executeZ } }; stella-3.9.3/src/debugger/DiStella.cxx0000644000175000001440000014625412266336753017230 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DiStella.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "Debugger.hxx" #include "DiStella.hxx" using namespace Common; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list, CartDebug::BankInfo& info, const DiStella::Settings& settings, uInt8* labels, uInt8* directives, CartDebug::ReservedEquates& reserved) : myDbg(dbg), myList(list), mySettings(settings), myReserved(reserved), myLabels(labels), myDirectives(directives) { CartDebug::AddressList& addresses = info.addressList; if(addresses.size() == 0) return; while(!myAddressQueue.empty()) myAddressQueue.pop(); bool resolve_code = mySettings.resolve_code; CartDebug::AddressList::iterator it = addresses.begin(); uInt16 start = *it++; myOffset = info.offset; if(start & 0x1000) { if(info.size == 4096) // 4K ROM space { /*============================================ The offset is the address where the code segment starts. For a 4K game, it is usually 0xf000. Example: Start address = $D973, so therefore Offset to code = $D000 Code range = $D000-$DFFF =============================================*/ info.start = myAppData.start = 0x0000; info.end = myAppData.end = 0x0FFF; // Keep previous offset; it may be different between banks if(info.offset == 0) info.offset = myOffset = (start - (start % 0x1000)); } else // 2K ROM space (also includes 'Sub2K' ROMs) { /*============================================ The offset is the address where the code segment starts. For a 2K game, it is usually 0xf800, but can also be 0xf000. =============================================*/ info.start = myAppData.start = 0x0000; info.end = myAppData.end = info.size - 1; 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); myAddressQueue.push(start); // Process any directives first, as they override automatic code determination processDirectives(info.directiveList); if(resolve_code) { // After we've disassembled from all addresses in the address list, // use all access points determined by Stella during emulation int codeAccessPoint = 0; while(!myAddressQueue.empty()) { myPC = myAddressQueue.front(); myPCBeg = myPC; myAddressQueue.pop(); disasm(myPC, 1); if(myPCBeg <= 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 = myPCBeg; k <= myPCEnd; k++) { if(Debugger::debugger().getAccessFlags(k) & (CartDebug::DATA|CartDebug::GFX|CartDebug::PGFX)) { 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 if(myAddressQueue.empty()) { while(it != addresses.end()) { uInt16 addr = *it; if(!check_bit(addr-myOffset, CartDebug::CODE)) { myAddressQueue.push(addr); ++it; break; } else // remove this address, it is redundant it = addresses.erase(it); } // Stella itself can provide hints on whether an address has ever // been referenced as CODE while(it == addresses.end() && codeAccessPoint <= myAppData.end) { if((Debugger::debugger().getAccessFlags(codeAccessPoint+myOffset) & CartDebug::CODE) && !(myLabels[codeAccessPoint & myAppData.end] & CartDebug::CODE)) { myAddressQueue.push(codeAccessPoint+myOffset); ++codeAccessPoint; break; } ++codeAccessPoint; } } } for (int k = 0; k <= myAppData.end; k++) { // Let the emulation core know about tentative code if(check_bit(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 (!check_bit(k, CartDebug::CODE | CartDebug::GFX | CartDebug::PGFX | CartDebug::DATA)) mark(k+myOffset, CartDebug::ROW); } } // 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.insert(make_pair(k+myOffset, reservedLabel.str())); } } } // Third pass disasm(myOffset, 3); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DiStella::~DiStella() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DiStella::disasm(uInt32 distart, int pass) { #define LABEL_A12_HIGH(address) labelA12High(nextline, op, address, labfound) #define LABEL_A12_LOW(address) labelA12Low(nextline, op, address, labfound) uInt8 op, d1; uInt16 ad; AddressingMode addr_mode; int bytes=0, labfound=0, addbranch=0; stringstream nextline, nextlinebytes; myDisasmBuf.str(""); /* pc=myAppData.start; */ myPC = distart - myOffset; while(myPC <= myAppData.end) { if(check_bit(myPC, CartDebug::GFX|CartDebug::PGFX) && !check_bit(myPC, CartDebug::CODE)) { mark(myPC+myOffset, CartDebug::VALID_ENTRY); if (pass == 3) { if (check_bit(myPC, CartDebug::REFERENCED)) myDisasmBuf << Base::HEX4 << myPC+myOffset << "'L" << Base::HEX4 << myPC+myOffset << "'"; else myDisasmBuf << Base::HEX4 << myPC+myOffset << "' '"; bool isPGfx = check_bit(myPC, CartDebug::PGFX); const string& bit_string = isPGfx ? "\x1f" : "\x1e"; uInt8 byte = Debugger::debugger().peek(myPC+myOffset); myDisasmBuf << ".byte $" << Base::HEX2 << (int)byte << " |"; for(uInt8 i = 0, c = byte; i < 8; ++i, c <<= 1) myDisasmBuf << ((c > 127) ? bit_string : " "); myDisasmBuf << "| $" << Base::HEX4 << myPC+myOffset << "'"; if(mySettings.gfx_format == Base::F_2) myDisasmBuf << Base::toString(byte, Base::F_2_8); else myDisasmBuf << Base::HEX2 << (int)byte; addEntry(isPGfx ? CartDebug::PGFX : CartDebug::GFX); } myPC++; } else if (check_bit(myPC, CartDebug::DATA) && !check_bit(myPC, CartDebug::CODE|CartDebug::GFX|CartDebug::PGFX)) { if (pass == 2) mark(myPC+myOffset, CartDebug::VALID_ENTRY); else if (pass == 3) { if (check_bit(myPC, CartDebug::REFERENCED)) myDisasmBuf << Base::HEX4 << myPC+myOffset << "'L" << Base::HEX4 << myPC+myOffset << "'"; else myDisasmBuf << Base::HEX4 << myPC+myOffset << "' '"; uInt8 byte = Debugger::debugger().peek(myPC+myOffset); myDisasmBuf << ".byte $" << Base::HEX2 << (int)byte << " $" << Base::HEX4 << myPC+myOffset << "'" << Base::HEX2 << (int)byte; addEntry(CartDebug::DATA); } myPC++; } else if (check_bit(myPC, CartDebug::ROW) && !check_bit(myPC, CartDebug::CODE|CartDebug::DATA|CartDebug::GFX|CartDebug::PGFX)) { if (pass == 2) mark(myPC+myOffset, CartDebug::VALID_ENTRY); if (pass == 3) { bool row = check_bit(myPC, CartDebug::ROW) && !check_bit(myPC, CartDebug::CODE | CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX); bool referenced = check_bit(myPC, CartDebug::REFERENCED); bool line_empty = true; while (row && myPC <= myAppData.end) { if(referenced) // start a new line with a label { if(!line_empty) { addEntry(CartDebug::ROW); line_empty = true; } myDisasmBuf << Base::HEX4 << myPC+myOffset << "'L" << Base::HEX4 << myPC+myOffset << "'.byte " << "$" << Base::HEX2 << (int)Debugger::debugger().peek(myPC+myOffset); myPC++; bytes = 1; line_empty = false; } else if(line_empty) // start a new line without a label { myDisasmBuf << " ' '.byte $" << Base::HEX2 << (int)Debugger::debugger().peek(myPC+myOffset); myPC++; bytes = 1; line_empty = false; } // Otherwise, append bytes to the current line, up until the maximum else if(++bytes == mySettings.bwidth) { addEntry(CartDebug::ROW); line_empty = true; } else { myDisasmBuf << ",$" << Base::HEX2 << (int)Debugger::debugger().peek(myPC+myOffset); myPC++; } row = check_bit(myPC, CartDebug::ROW) && !check_bit(myPC, CartDebug::CODE | CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX); referenced = check_bit(myPC, CartDebug::REFERENCED); } if(!line_empty) addEntry(CartDebug::ROW); myDisasmBuf << " ' ' "; addEntry(CartDebug::NONE); } else myPC++; } else // The following sections must be CODE { // Add label (if any) // op = Debugger::debugger().peek(myPC+myOffset); /* version 2.1 bug fix */ if (pass == 2) mark(myPC+myOffset, CartDebug::VALID_ENTRY); else if (pass == 3) { if (check_bit(myPC, CartDebug::REFERENCED)) myDisasmBuf << Base::HEX4 << myPC+myOffset << "'L" << Base::HEX4 << myPC+myOffset << "'"; else myDisasmBuf << Base::HEX4 << myPC+myOffset << "' '"; } // Add opcode mneumonic // addr_mode = ourLookup[op].addr_mode; myPC++; // Undefined opcodes start with a '.' // These are undefined wrt DASM if (ourLookup[op].mnemonic[0] == '.') { addr_mode = IMPLIED; if (pass == 3) nextline << ".byte $" << Base::HEX2 << (int)op << " ;"; } if (pass == 1) { /* M_REL covers BPL, BMI, BVC, BVS, BCC, BCS, BNE, BEQ M_ADDR = JMP $NNNN, JSR $NNNN M_AIND = JMP Abs, Indirect */ switch(ourLookup[op].source) { case M_REL: case M_ADDR: case M_AIND: addbranch = 1; break; default: addbranch = 0; break; } } else if (pass == 3) { nextline << ourLookup[op].mnemonic; nextlinebytes << Base::HEX2 << (int)op << " "; } // Add operand(s) for PC values outside the app data range // if (myPC >= myAppData.end) { switch(addr_mode) { 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)op << " $" << Base::HEX4 << myPC+myOffset << "'" << Base::HEX2 << (int)op; addEntry(CartDebug::DATA); if (myPC == myAppData.end) { if (check_bit(myPC, CartDebug::REFERENCED)) myDisasmBuf << Base::HEX4 << myPC+myOffset << "'L" << Base::HEX4 << myPC+myOffset << "'"; else myDisasmBuf << Base::HEX4 << myPC+myOffset << "' '"; op = Debugger::debugger().peek(myPC+myOffset); myPC++; myDisasmBuf << ".byte $" << Base::HEX2 << (int)op << " $" << Base::HEX4 << myPC+myOffset << "'" << Base::HEX2 << (int)op; addEntry(CartDebug::DATA); } } myPCEnd = myAppData.end + myOffset; return; } case ZERO_PAGE: case IMMEDIATE: case ZERO_PAGE_X: case ZERO_PAGE_Y: case RELATIVE: { if (myPC > myAppData.end) { 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)op; addEntry(CartDebug::ROW); nextline.str(""); nextlinebytes.str(""); } myPC++; myPCEnd = myAppData.end + myOffset; return; } } default: break; } // end switch(addr_mode) } // Add operand(s) // /* Version 2.1 added the extensions to mnemonics */ switch(addr_mode) { #if 0 case IMPLIED: { if (op == 0x40 || op == 0x60) if (pass == 3) nextline << "\n"; break; } #endif case ACCUMULATOR: { if (pass == 3 && mySettings.aflag) nextline << " A"; break; } case ABSOLUTE: { ad = Debugger::debugger().dpeek(myPC+myOffset); myPC+=2; labfound = mark(ad, CartDebug::REFERENCED); if (pass == 1) { if (addbranch) { if (!check_bit(ad & myAppData.end, CartDebug::CODE)) { if (ad > 0xfff) myAddressQueue.push((ad & myAppData.end) + myOffset); mark(ad, CartDebug::CODE); } } else if(ad > 0xfff) { mark(ad, CartDebug::DATA); } } else if (pass == 3) { if (ad < 0x100 && mySettings.fflag) nextline << ".w "; else nextline << " "; if (labfound == 1) { LABEL_A12_HIGH(ad); nextlinebytes << Base::HEX2 << (int)(ad&0xff) << " " << Base::HEX2 << (int)(ad>>8); } else if (labfound == 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++; labfound = 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; labfound = mark(ad, CartDebug::REFERENCED); if (pass == 2 && !check_bit(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 (labfound == 1) { LABEL_A12_HIGH(ad); nextline << ",X"; nextlinebytes << Base::HEX2 << (int)(ad&0xff) << " " << Base::HEX2 << (int)(ad>>8); } else if (labfound == 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; labfound = mark(ad, CartDebug::REFERENCED); if (pass == 2 && !check_bit(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 (labfound == 1) { LABEL_A12_HIGH(ad); nextline << ",Y"; nextlinebytes << Base::HEX2 << (int)(ad&0xff) << " " << Base::HEX2 << (int)(ad>>8); } else if (labfound == 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) { labfound = 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) { labfound = 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++; labfound = 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++; labfound = 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; labfound = mark(ad, CartDebug::REFERENCED); if (pass == 1) { if ((addbranch) && !check_bit(ad-myOffset, CartDebug::CODE)) { myAddressQueue.push(ad); mark(ad, CartDebug::CODE); } } else if (pass == 3) { if (labfound == 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; labfound = mark(ad, CartDebug::REFERENCED); if (pass == 2 && !check_bit(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 (labfound == 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 == 1) { // RTS/JMP/RTI always indicate the end of a block of CODE if (!strcmp(ourLookup[op].mnemonic,"RTS") || !strcmp(ourLookup[op].mnemonic,"JMP") || /* !strcmp(ourLookup[op].mnemonic,"BRK") || */ !strcmp(ourLookup[op].mnemonic,"RTI")) { myPCEnd = (myPC-1) + myOffset; return; } } else if (pass == 3) { // A complete line of disassembly (text, cycle count, and bytes) myDisasmBuf << nextline.str() << "'" << ";" << dec << (int)ourLookup[op].cycles << "'" << nextlinebytes.str(); addEntry(CartDebug::CODE); if (op == 0x40 || op == 0x60) { myDisasmBuf << " ' ' "; addEntry(CartDebug::NONE); } 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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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::check_bit(uInt16 address, uInt8 mask) 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 else if((debugger | lastbits) & mask) return true; // Otherwise, default to static analysis from Distella else return label & mask; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool DiStella::check_range(uInt16 beg, uInt16 end) const { if(beg > end) { cerr << "Beginning of range greater than end: start = " << hex << beg << ", end = " << hex << end << endl; return false; } else if(beg > myAppData.end + myOffset) { cerr << "Beginning of range out of range: start = " << hex << beg << ", range = " << hex << (myAppData.end + myOffset) << endl; return false; } else if(beg < myOffset) { cerr << "Beginning of range out of range: start = " << hex << beg << ", offset = " << hex << myOffset << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DiStella::addEntry(CartDebug::DisasmType type) { CartDebug::DisassemblyTag tag; // Type tag.type = type; // Address myDisasmBuf.seekg(0, ios::beg); if(myDisasmBuf.peek() == ' ') tag.address = 0; else myDisasmBuf >> setw(4) >> 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, 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.show_addresses && 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, ios::beg); switch(tag.type) { case CartDebug::CODE: getline(myDisasmBuf, tag.disasm, '\''); getline(myDisasmBuf, tag.ccount, '\''); 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; default: // should never happen tag.disasm = " "; break; } myList.push_back(tag); DONE_WITH_ADD: myDisasmBuf.clear(); myDisasmBuf.str(""); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DiStella::processDirectives(const CartDebug::DirectiveList& directives) { for(CartDebug::DirectiveList::const_iterator i = directives.begin(); i != directives.end(); ++i) { const CartDebug::DirectiveTag& tag = *i; 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, // gfx_format true, // resolve_code (opposite of -d in Distella) true, // show_addresses (not used externally; always off) false, // aflag (-a in Distella) true, // fflag (-f in Distella) false, // rflag (-r in Distella) 9 // number of bytes to use with .byte directive }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const DiStella::Instruction_tag DiStella::ourLookup[256] = { /**** Positive ****/ /* 00 */ { "BRK", IMPLIED, M_NONE, NONE, 7 }, /* Pseudo Absolute */ /* 01 */ { "ORA", INDIRECT_X, M_INDX, READ, 6 }, /* (Indirect,X) */ /* 02 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */ /* 03 */ { "slo", INDIRECT_X, M_INDX, WRITE, 8 }, /* 04 */ { "nop", ZERO_PAGE, M_NONE, NONE, 3 }, /* 05 */ { "ORA", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */ /* 06 */ { "ASL", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* Zeropage */ /* 07 */ { "slo", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* 08 */ { "PHP", IMPLIED, M_SR, NONE, 3 }, /* 09 */ { "ORA", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */ /* 0a */ { "ASL", ACCUMULATOR, M_AC, WRITE, 2 }, /* Accumulator */ /* 0b */ { "anc", IMMEDIATE, M_ACIM, READ, 2 }, /* 0c */ { "nop", ABSOLUTE, M_NONE, NONE, 4 }, /* 0d */ { "ORA", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */ /* 0e */ { "ASL", ABSOLUTE, M_ABS, WRITE, 6 }, /* Absolute */ /* 0f */ { "slo", ABSOLUTE, M_ABS, WRITE, 6 }, /* 10 */ { "BPL", RELATIVE, M_REL, READ, 2 }, /* 11 */ { "ORA", INDIRECT_Y, M_INDY, READ, 5 }, /* (Indirect),Y */ /* 12 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */ /* 13 */ { "slo", INDIRECT_Y, M_INDY, WRITE, 8 }, /* 14 */ { "nop", ZERO_PAGE_X, M_NONE, NONE, 4 }, /* 15 */ { "ORA", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */ /* 16 */ { "ASL", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* Zeropage,X */ /* 17 */ { "slo", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* 18 */ { "CLC", IMPLIED, M_NONE, NONE, 2 }, /* 19 */ { "ORA", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */ /* 1a */ { ".nop",IMPLIED, M_NONE, NONE, 2 }, /* 1b */ { "slo", ABSOLUTE_Y, M_ABSY, WRITE, 7 }, /* 1c */ { "nop", ABSOLUTE_X, M_NONE, NONE, 4 }, /* 1d */ { "ORA", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */ /* 1e */ { "ASL", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* Absolute,X */ /* 1f */ { "slo", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* 20 */ { "JSR", ABSOLUTE, M_ADDR, READ, 6 }, /* 21 */ { "AND", INDIRECT_X, M_INDX, READ, 6 }, /* (Indirect ,X) */ /* 22 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */ /* 23 */ { "rla", INDIRECT_X, M_INDX, WRITE, 8 }, /* 24 */ { "BIT", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */ /* 25 */ { "AND", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */ /* 26 */ { "ROL", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* Zeropage */ /* 27 */ { "rla", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* 28 */ { "PLP", IMPLIED, M_NONE, NONE, 4 }, /* 29 */ { "AND", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */ /* 2a */ { "ROL", ACCUMULATOR, M_AC, WRITE, 2 }, /* Accumulator */ /* 2b */ { ".anc",IMMEDIATE, M_ACIM, READ, 2 }, /* 2c */ { "BIT", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */ /* 2d */ { "AND", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */ /* 2e */ { "ROL", ABSOLUTE, M_ABS, WRITE, 6 }, /* Absolute */ /* 2f */ { "rla", ABSOLUTE, M_ABS, WRITE, 6 }, /* 30 */ { "BMI", RELATIVE, M_REL, READ, 2 }, /* 31 */ { "AND", INDIRECT_Y, M_INDY, READ, 5 }, /* (Indirect),Y */ /* 32 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */ /* 33 */ { "rla", INDIRECT_Y, M_INDY, WRITE, 8 }, /* 34 */ { ".nop",ZERO_PAGE_X, M_NONE, NONE, 4 }, /* 35 */ { "AND", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */ /* 36 */ { "ROL", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* Zeropage,X */ /* 37 */ { "rla", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* 38 */ { "SEC", IMPLIED, M_NONE, NONE, 2 }, /* 39 */ { "AND", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */ /* 3a */ { ".nop",IMPLIED, M_NONE, NONE, 2 }, /* 3b */ { "rla", ABSOLUTE_Y, M_ABSY, WRITE, 7 }, /* 3c */ { ".nop",ABSOLUTE_X, M_NONE, NONE, 4 }, /* 3d */ { "AND", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */ /* 3e */ { "ROL", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* Absolute,X */ /* 3f */ { "rla", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* 40 */ { "RTI", IMPLIED, M_NONE, NONE, 6 }, /* 41 */ { "EOR", INDIRECT_X, M_INDX, READ, 6 }, /* (Indirect,X) */ /* 42 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */ /* 43 */ { "sre", INDIRECT_X, M_INDX, WRITE, 8 }, /* 44 */ { ".nop",ZERO_PAGE, M_NONE, NONE, 3 }, /* 45 */ { "EOR", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */ /* 46 */ { "LSR", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* Zeropage */ /* 47 */ { "sre", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* 48 */ { "PHA", IMPLIED, M_AC, NONE, 3 }, /* 49 */ { "EOR", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */ /* 4a */ { "LSR", ACCUMULATOR, M_AC, WRITE, 2 }, /* Accumulator */ /* 4b */ { "asr", IMMEDIATE, M_ACIM, READ, 2 }, /* (AC & IMM) >>1 */ /* 4c */ { "JMP", ABSOLUTE, M_ADDR, READ, 3 }, /* Absolute */ /* 4d */ { "EOR", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */ /* 4e */ { "LSR", ABSOLUTE, M_ABS, WRITE, 6 }, /* Absolute */ /* 4f */ { "sre", ABSOLUTE, M_ABS, WRITE, 6 }, /* 50 */ { "BVC", RELATIVE, M_REL, READ, 2 }, /* 51 */ { "EOR", INDIRECT_Y, M_INDY, READ, 5 }, /* (Indirect),Y */ /* 52 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */ /* 53 */ { "sre", INDIRECT_Y, M_INDY, WRITE, 8 }, /* 54 */ { ".nop",ZERO_PAGE_X, M_NONE, NONE, 4 }, /* 55 */ { "EOR", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */ /* 56 */ { "LSR", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* Zeropage,X */ /* 57 */ { "sre", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* 58 */ { "CLI", IMPLIED, M_NONE, NONE, 2 }, /* 59 */ { "EOR", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */ /* 5a */ { ".nop",IMPLIED, M_NONE, NONE, 2 }, /* 5b */ { "sre", ABSOLUTE_Y, M_ABSY, WRITE, 7 }, /* 5c */ { ".nop",ABSOLUTE_X, M_NONE, NONE, 4 }, /* 5d */ { "EOR", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */ /* 5e */ { "LSR", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* Absolute,X */ /* 5f */ { "sre", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* 60 */ { "RTS", IMPLIED, M_NONE, NONE, 6 }, /* 61 */ { "ADC", INDIRECT_X, M_INDX, READ, 6 }, /* (Indirect,X) */ /* 62 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */ /* 63 */ { "rra", INDIRECT_X, M_INDX, WRITE, 8 }, /* 64 */ { ".nop",ZERO_PAGE, M_NONE, NONE, 3 }, /* 65 */ { "ADC", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */ /* 66 */ { "ROR", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* Zeropage */ /* 67 */ { "rra", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* 68 */ { "PLA", IMPLIED, M_NONE, NONE, 4 }, /* 69 */ { "ADC", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */ /* 6a */ { "ROR", ACCUMULATOR, M_AC, WRITE, 2 }, /* Accumulator */ /* 6b */ { "arr", IMMEDIATE, M_ACIM, READ, 2 }, /* ARR isn't typo */ /* 6c */ { "JMP", ABS_INDIRECT,M_AIND, READ, 5 }, /* Indirect */ /* 6d */ { "ADC", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */ /* 6e */ { "ROR", ABSOLUTE, M_ABS, WRITE, 6 }, /* Absolute */ /* 6f */ { "rra", ABSOLUTE, M_ABS, WRITE, 6 }, /* 70 */ { "BVS", RELATIVE, M_REL, READ, 2 }, /* 71 */ { "ADC", INDIRECT_Y, M_INDY, READ, 5 }, /* (Indirect),Y */ /* 72 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT relative? */ /* 73 */ { "rra", INDIRECT_Y, M_INDY, WRITE, 8 }, /* 74 */ { ".nop",ZERO_PAGE_X, M_NONE, NONE, 4 }, /* 75 */ { "ADC", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */ /* 76 */ { "ROR", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* Zeropage,X */ /* 77 */ { "rra", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* 78 */ { "SEI", IMPLIED, M_NONE, NONE, 2 }, /* 79 */ { "ADC", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */ /* 7a */ { ".nop",IMPLIED, M_NONE, NONE, 2 }, /* 7b */ { "rra", ABSOLUTE_Y, M_ABSY, WRITE, 7 }, /* 7c */ { ".nop",ABSOLUTE_X, M_NONE, NONE, 4 }, /* 7d */ { "ADC", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */ /* 7e */ { "ROR", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* Absolute,X */ /* 7f */ { "rra", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /**** Negative ****/ /* 80 */ { "nop", IMMEDIATE, M_NONE, NONE, 2 }, /* 81 */ { "STA", INDIRECT_X, M_AC, WRITE, 6 }, /* (Indirect,X) */ /* 82 */ { ".nop",IMMEDIATE, M_NONE, NONE, 2 }, /* 83 */ { "sax", INDIRECT_X, M_ANXR, WRITE, 6 }, /* 84 */ { "STY", ZERO_PAGE, M_YR, WRITE, 3 }, /* Zeropage */ /* 85 */ { "STA", ZERO_PAGE, M_AC, WRITE, 3 }, /* Zeropage */ /* 86 */ { "STX", ZERO_PAGE, M_XR, WRITE, 3 }, /* Zeropage */ /* 87 */ { "sax", ZERO_PAGE, M_ANXR, WRITE, 3 }, /* 88 */ { "DEY", IMPLIED, M_YR, NONE, 2 }, /* 89 */ { ".nop",IMMEDIATE, M_NONE, NONE, 2 }, /* 8a */ { "TXA", IMPLIED, M_XR, NONE, 2 }, /**** very abnormal: usually AC = AC | #$EE & XR & #$oper ****/ /* 8b */ { "ane", IMMEDIATE, M_AXIM, READ, 2 }, /* 8c */ { "STY", ABSOLUTE, M_YR, WRITE, 4 }, /* Absolute */ /* 8d */ { "STA", ABSOLUTE, M_AC, WRITE, 4 }, /* Absolute */ /* 8e */ { "STX", ABSOLUTE, M_XR, WRITE, 4 }, /* Absolute */ /* 8f */ { "sax", ABSOLUTE, M_ANXR, WRITE, 4 }, /* 90 */ { "BCC", RELATIVE, M_REL, READ, 2 }, /* 91 */ { "STA", INDIRECT_Y, M_AC, WRITE, 6 }, /* (Indirect),Y */ /* 92 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT relative? */ /* 93 */ { "sha", INDIRECT_Y, M_ANXR, WRITE, 6 }, /* 94 */ { "STY", ZERO_PAGE_X, M_YR, WRITE, 4 }, /* Zeropage,X */ /* 95 */ { "STA", ZERO_PAGE_X, M_AC, WRITE, 4 }, /* Zeropage,X */ /* 96 */ { "STX", ZERO_PAGE_Y, M_XR, WRITE, 4 }, /* Zeropage,Y */ /* 97 */ { "sax", ZERO_PAGE_Y, M_ANXR, WRITE, 4 }, /* 98 */ { "TYA", IMPLIED, M_YR, NONE, 2 }, /* 99 */ { "STA", ABSOLUTE_Y, M_AC, WRITE, 5 }, /* Absolute,Y */ /* 9a */ { "TXS", IMPLIED, M_XR, NONE, 2 }, /*** This is very mysterious comm AND ... */ /* 9b */ { "shs", ABSOLUTE_Y, M_ANXR, WRITE, 5 }, /* 9c */ { "shy", ABSOLUTE_X, M_YR, WRITE, 5 }, /* 9d */ { "STA", ABSOLUTE_X, M_AC, WRITE, 5 }, /* Absolute,X */ /* 9e */ { "shx", ABSOLUTE_Y, M_XR , WRITE, 5 }, /* 9f */ { "sha", ABSOLUTE_Y, M_ANXR, WRITE, 5 }, /* a0 */ { "LDY", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */ /* a1 */ { "LDA", INDIRECT_X, M_INDX, READ, 6 }, /* (indirect,X) */ /* a2 */ { "LDX", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */ /* a3 */ { "lax", INDIRECT_X, M_INDX, READ, 6 }, /* (indirect,X) */ /* a4 */ { "LDY", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */ /* a5 */ { "LDA", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */ /* a6 */ { "LDX", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */ /* a7 */ { "lax", ZERO_PAGE, M_ZERO, READ, 3 }, /* a8 */ { "TAY", IMPLIED, M_AC, NONE, 2 }, /* a9 */ { "LDA", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */ /* aa */ { "TAX", IMPLIED, M_AC, NONE, 2 }, /* ab */ { "lxa", IMMEDIATE, M_ACIM, READ, 2 }, /* LXA isn't a typo */ /* ac */ { "LDY", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */ /* ad */ { "LDA", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */ /* ae */ { "LDX", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */ /* af */ { "lax", ABSOLUTE, M_ABS, READ, 4 }, /* b0 */ { "BCS", RELATIVE, M_REL, READ, 2 }, /* b1 */ { "LDA", INDIRECT_Y, M_INDY, READ, 5 }, /* (indirect),Y */ /* b2 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */ /* b3 */ { "lax", INDIRECT_Y, M_INDY, READ, 5 }, /* b4 */ { "LDY", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */ /* b5 */ { "LDA", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */ /* b6 */ { "LDX", ZERO_PAGE_Y, M_ZERY, READ, 4 }, /* Zeropage,Y */ /* b7 */ { "lax", ZERO_PAGE_Y, M_ZERY, READ, 4 }, /* b8 */ { "CLV", IMPLIED, M_NONE, NONE, 2 }, /* b9 */ { "LDA", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */ /* ba */ { "TSX", IMPLIED, M_SP, NONE, 2 }, /* bb */ { "las", ABSOLUTE_Y, M_SABY, READ, 4 }, /* bc */ { "LDY", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */ /* bd */ { "LDA", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */ /* be */ { "LDX", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */ /* bf */ { "lax", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* c0 */ { "CPY", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */ /* c1 */ { "CMP", INDIRECT_X, M_INDX, READ, 6 }, /* (Indirect,X) */ /* c2 */ { ".nop",IMMEDIATE, M_NONE, NONE, 2 }, /* occasional TILT */ /* c3 */ { "dcp", INDIRECT_X, M_INDX, WRITE, 8 }, /* c4 */ { "CPY", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */ /* c5 */ { "CMP", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */ /* c6 */ { "DEC", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* Zeropage */ /* c7 */ { "dcp", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* c8 */ { "INY", IMPLIED, M_YR, NONE, 2 }, /* c9 */ { "CMP", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */ /* ca */ { "DEX", IMPLIED, M_XR, NONE, 2 }, /* cb */ { "sbx", IMMEDIATE, M_IMM, READ, 2 }, /* cc */ { "CPY", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */ /* cd */ { "CMP", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */ /* ce */ { "DEC", ABSOLUTE, M_ABS, WRITE, 6 }, /* Absolute */ /* cf */ { "dcp", ABSOLUTE, M_ABS, WRITE, 6 }, /* d0 */ { "BNE", RELATIVE, M_REL, READ, 2 }, /* d1 */ { "CMP", INDIRECT_Y, M_INDY, READ, 5 }, /* (Indirect),Y */ /* d2 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */ /* d3 */ { "dcp", INDIRECT_Y, M_INDY, WRITE, 8 }, /* d4 */ { ".nop",ZERO_PAGE_X, M_NONE, NONE, 4 }, /* d5 */ { "CMP", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */ /* d6 */ { "DEC", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* Zeropage,X */ /* d7 */ { "dcp", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* d8 */ { "CLD", IMPLIED, M_NONE, NONE, 2 }, /* d9 */ { "CMP", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */ /* da */ { ".nop",IMPLIED, M_NONE, NONE, 2 }, /* db */ { "dcp", ABSOLUTE_Y, M_ABSY, WRITE, 7 }, /* dc */ { ".nop",ABSOLUTE_X, M_NONE, NONE, 4 }, /* dd */ { "CMP", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */ /* de */ { "DEC", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* Absolute,X */ /* df */ { "dcp", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* e0 */ { "CPX", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */ /* e1 */ { "SBC", INDIRECT_X, M_INDX, READ, 6 }, /* (Indirect,X) */ /* e2 */ { ".nop",IMMEDIATE, M_NONE, NONE, 2 }, /* e3 */ { "isb", INDIRECT_X, M_INDX, WRITE, 8 }, /* e4 */ { "CPX", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */ /* e5 */ { "SBC", ZERO_PAGE, M_ZERO, READ, 3 }, /* Zeropage */ /* e6 */ { "INC", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* Zeropage */ /* e7 */ { "isb", ZERO_PAGE, M_ZERO, WRITE, 5 }, /* e8 */ { "INX", IMPLIED, M_XR, NONE, 2 }, /* e9 */ { "SBC", IMMEDIATE, M_IMM, READ, 2 }, /* Immediate */ /* ea */ { "NOP", IMPLIED, M_NONE, NONE, 2 }, /* eb */ { ".sbc",IMMEDIATE, M_IMM, READ, 2 }, /* same as e9 */ /* ec */ { "CPX", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */ /* ed */ { "SBC", ABSOLUTE, M_ABS, READ, 4 }, /* Absolute */ /* ee */ { "INC", ABSOLUTE, M_ABS, WRITE, 6 }, /* Absolute */ /* ef */ { "isb", ABSOLUTE, M_ABS, WRITE, 6 }, /* f0 */ { "BEQ", RELATIVE, M_REL, READ, 2 }, /* f1 */ { "SBC", INDIRECT_Y, M_INDY, READ, 5 }, /* (Indirect),Y */ /* f2 */ { ".jam",IMPLIED, M_NONE, NONE, 0 }, /* TILT */ /* f3 */ { "isb", INDIRECT_Y, M_INDY, WRITE, 8 }, /* f4 */ { ".nop",ZERO_PAGE_X, M_NONE, NONE, 4 }, /* f5 */ { "SBC", ZERO_PAGE_X, M_ZERX, READ, 4 }, /* Zeropage,X */ /* f6 */ { "INC", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* Zeropage,X */ /* f7 */ { "isb", ZERO_PAGE_X, M_ZERX, WRITE, 6 }, /* f8 */ { "SED", IMPLIED, M_NONE, NONE, 2 }, /* f9 */ { "SBC", ABSOLUTE_Y, M_ABSY, READ, 4 }, /* Absolute,Y */ /* fa */ { ".nop",IMPLIED, M_NONE, NONE, 2 }, /* fb */ { "isb", ABSOLUTE_Y, M_ABSY, WRITE, 7 }, /* fc */ { ".nop",ABSOLUTE_X, M_NONE, NONE, 4 }, /* fd */ { "SBC", ABSOLUTE_X, M_ABSX, READ, 4 }, /* Absolute,X */ /* fe */ { "INC", ABSOLUTE_X, M_ABSX, WRITE, 7 }, /* Absolute,X */ /* ff */ { "isb", ABSOLUTE_X, M_ABSX, WRITE, 7 } }; stella-3.9.3/src/debugger/CartDebug.cxx0000644000175000001440000013552112266336753017362 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDebug.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "bspf.hxx" #include "Array.hxx" #include "System.hxx" #include "FSNode.hxx" #include "DiStella.hxx" #include "Debugger.hxx" #include "CpuDebug.hxx" #include "OSystem.hxx" #include "Settings.hxx" #include "Version.hxx" #include "CartDebug.hxx" #include "CartDebugWidget.hxx" using namespace Common; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem) : DebuggerSystem(dbg, console), myOSystem(osystem), myDebugWidget(0), myRWPortAddress(0), myLabelLength(8) // longest pre-defined label { // Zero-page RAM is always present addRamArea(0x80, 128, 0, 0); // Add extended RAM const RamAreaList& areas = console.cartridge().ramAreas(); for(RamAreaList::const_iterator i = areas.begin(); i != areas.end(); ++i) addRamArea(i->start, i->size, i->roffset, i->woffset); // 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 int banksize = 0; myConsole.cartridge().getImage(banksize); BankInfo info; info.size = BSPF_min(banksize, 4096); for(int 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_back(myDebugger.dpeek(0xfffc)); addLabel("START", myDebugger.dpeek(0xfffc)); // Add system equates for(uInt16 addr = 0x00; addr <= 0x0F; ++addr) { if(ourTIAMnemonicR[addr]) mySystemAddresses.insert(make_pair(ourTIAMnemonicR[addr], addr)); myReserved.TIARead[addr] = false; } for(uInt16 addr = 0x00; addr <= 0x3F; ++addr) { if(ourTIAMnemonicW[addr]) mySystemAddresses.insert(make_pair(ourTIAMnemonicW[addr], addr)); myReserved.TIAWrite[addr] = false; } for(uInt16 addr = 0x280; addr <= 0x297; ++addr) { if(ourIOMnemonic[addr-0x280]) mySystemAddresses.insert(make_pair(ourIOMnemonic[addr-0x280], addr)); myReserved.IOReadWrite[addr-0x280] = false; } for(uInt16 addr = 0x80; addr <= 0xFF; ++addr) { mySystemAddresses.insert(make_pair(ourZPMnemonic[addr-0x80], addr)); myReserved.ZPRAM[addr-0x80] = false; } myReserved.Label.clear(); myDisassembly.list.reserve(2048); // Add settings for Distella DiStella::settings.gfx_format = myOSystem.settings().getInt("dis.gfxformat") == 16 ? Base::F_16 : Base::F_2; DiStella::settings.resolve_code = myOSystem.settings().getBool("dis.resolve"); DiStella::settings.show_addresses = 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.bwidth = 9; // TODO - configure based on window size } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartDebug::~CartDebug() { myUserLabels.clear(); myUserAddresses.clear(); myUserCLabels.clear(); // myUserCAddresses.clear(); mySystemAddresses.clear(); for(uInt32 i = 0; i < myBankInfo.size(); ++i) { myBankInfo[i].addressList.clear(); myBankInfo[i].directiveList.clear(); } myBankInfo.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartDebug::addRamArea(uInt16 start, uInt16 size, uInt16 roffset, uInt16 woffset) { // First make sure this area isn't already present for(uInt32 i = 0; i < myState.rport.size(); ++i) if(myState.rport[i] == start + roffset || myState.wport[i] == start + woffset) return; // Otherwise, add a new area for(uInt32 i = 0; i < size; ++i) { myState.rport.push_back(i + start + roffset); myState.wport.push_back(i + start + woffset); myOldState.rport.push_back(i + start + roffset); myOldState.wport.push_back(i + start + woffset); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const DebuggerState& CartDebug::getState() { myState.ram.clear(); for(uInt32 i = 0; i < myState.rport.size(); ++i) myState.ram.push_back(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(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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 = (CartState&) getState(); const CartState& oldstate = (CartState&) 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]; BSPF_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 = (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(list::iterator i = addresses.begin(); i != addresses.end(); ++i) *i = (*i & 0xFFF) + offset; // Only add addresses when absolutely necessary, to cut down on the // work that Distella has to do // Distella expects the addresses to be unique and in sorted order if(bankChanged || !pcfound) { AddressList::iterator i; for(i = addresses.begin(); i != addresses.end(); ++i) { if(PC < *i) { addresses.insert(i, PC); break; } else 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.resolve_code) { // Temporarily turn off code resolution DiStella::settings.resolve_code = false; fillDisassemblyList(info, PC); DiStella::settings.resolve_code = true; } } return changed; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDebug::fillDisassemblyList(BankInfo& info, uInt16 search) { myDisassembly.list.clear(false); myDisassembly.fieldwidth = 14 + 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; // Addresses marked as 'ROW' normally won't have an address if(address) { // Create a mapping from addresses to line numbers myAddrToLineList.insert(make_pair(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; map::const_iterator 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 = 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 = BSPF_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 << uppercase << hex << setw(4) << setfill('0') << tag.address << ": "; else buffer << " "; buffer << tag.disasm << setw(length - tag.disasm.length() + 2) << setfill(' ') << " " << setw(4) << left << tag.ccount << " " << tag.bytes << endl; } return buffer.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDebug::addDirective(CartDebug::DisasmType type, uInt16 start, uInt16 end, int bank) { #define PRINT_TAG(tag) \ disasmTypeAsString(cerr, tag.type); \ cerr << ": start = " << tag.start << ", end = " << tag.end << endl; #define PRINT_LIST(header) \ cerr << header << endl; \ for(DirectiveList::const_iterator d = list.begin(); d != list.end(); ++d) { \ PRINT_TAG((*d)); } \ cerr << endl; 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() : myBankInfo.size()-1; bank = BSPF_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().bank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CartDebug::bankCount() const { return myConsole.cartridge().bankCount(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::getCartType() const { return myConsole.cartridge().name(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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.insert(make_pair(label, address)); myUserLabels.insert(make_pair(address, label)); myLabelLength = BSPF_max(myLabelLength, (uInt16)label.size()); mySystem.setDirtyPage(address); return true; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDebug::removeLabel(const string& label) { // Only user-defined labels can be removed LabelToAddr::iterator iter = myUserAddresses.find(label); if(iter != myUserAddresses.end()) { // Erase the label myUserAddresses.erase(iter); mySystem.setDirtyPage(iter->second); // And also erase the address assigned to it AddrToLabel::iterator iter2 = myUserLabels.find(iter->second); if(iter2 != myUserLabels.end()) myUserLabels.erase(iter2); 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 AddrToLabel::const_iterator iter; if((iter = myUserLabels.find(addr)) != 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 AddrToLabel::const_iterator iter; if((iter = myUserLabels.find(addr)) != 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() { // Currently, the default naming/location for list files is: // 1) ROM dir based on properties entry name if(myListFile == "") { const string& propsname = myConsole.properties().get(Cartridge_Name) + ".lst"; FilesystemNode case1(myOSystem.romFile().getParent().getPath() + propsname); if(case1.isFile() && case1.isReadable()) myListFile = case1.getPath(); else return DebuggerParser::red("list file not found in:\n " + case1.getShortPath()); } FilesystemNode node(myListFile); ifstream in(node.getPath().c_str()); if(!in.is_open()) return DebuggerParser::red("list file '" + node.getShortPath() + "' not readable"); myUserCLabels.clear(); while(!in.eof()) { string line, addr_s; int addr = -1; 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' 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 = strtoul(p, NULL, 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.insert(make_pair(xx*256+yy, line)); } } } in.close(); myDebugger.rom().invalidate(); return "loaded " + node.getShortPath() + " OK"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::loadSymbolFile() { // Currently, the default naming/location for symbol files is: // 1) ROM dir based on properties entry name if(mySymbolFile == "") { const string& propsname = myConsole.properties().get(Cartridge_Name) + ".sym"; FilesystemNode case1(myOSystem.romFile().getParent().getPath() + propsname); if(case1.isFile() && case1.isReadable()) mySymbolFile = case1.getPath(); else return DebuggerParser::red("symbol file not found in:\n " + case1.getShortPath()); } FilesystemNode node(mySymbolFile); ifstream in(node.getPath().c_str()); 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 AddrToLabel::const_iterator iter = myUserCLabels.find(value); if(iter == myUserCLabels.end() || !BSPF_equalsIgnoreCase(label, iter->second)) { // Check for period, and strip leading number if(string::size_type pos = label.find_first_of(".", 0) != string::npos) addLabel(label.substr(pos), value); else addLabel(label, value); } } } in.close(); myDebugger.rom().invalidate(); return "loaded " + node.getShortPath() + " OK"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::loadConfigFile() { if(myConsole.cartridge().bankCount() > 1) return DebuggerParser::red("config file for multi-bank ROM not yet supported"); // 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().c_str()); if(!in.is_open()) return "Unable to load directives from " + node.getPath(); // Erase all previous directives for(Common::Array::iterator bi = myBankInfo.begin(); bi != myBankInfo.end(); ++bi) { 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); } } } in.close(); myDebugger.rom().invalidate(); return "loaded " + node.getShortPath() + " OK"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::saveConfigFile() { if(myConsole.cartridge().bankCount() > 1) return DebuggerParser::red("config file for multi-bank ROM not yet supported"); // 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().c_str()); 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]); } out.close(); return "saved " + node.getShortPath() + " OK"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::saveDisassembly() { if(myConsole.cartridge().bankCount() > 1) return DebuggerParser::red("disassembly for multi-bank ROM not yet supported"); // Currently, the default naming/location for disassembly files is: // 1) ROM dir based on properties entry name if(myDisasmFile == "") { const string& propsname = myConsole.properties().get(Cartridge_Name) + ".asm"; FilesystemNode case0(myOSystem.romFile().getParent().getPath() + propsname); if(case0.getParent().isWritable()) myDisasmFile = case0.getPath(); else return DebuggerParser::red("disassembly file not writable:\n " + case0.getShortPath()); } FilesystemNode node(myDisasmFile); ofstream out(node.getPath().c_str()); 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" << "; MAIN PROGRAM\n" << ";\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.gfx_format = DiStella::settings.gfx_format; settings.resolve_code = true; settings.show_addresses = false; settings.aflag = false; // Otherwise DASM gets confused settings.fflag = DiStella::settings.fflag; settings.rflag = DiStella::settings.rflag; settings.bwidth = 17; // default from Distella Disassembly disasm; disasm.list.reserve(2048); for(int bank = 0; bank < myConsole.cartridge().bankCount(); ++bank) { BankInfo& info = myBankInfo[bank]; // Disassemble bank disasm.list.clear(false); // don't fully de-allocate space DiStella distella(*this, disasm.list, info, settings, myDisLabels, myDisDirectives, myReserved); 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(7) << (tag.label+":") << endl; buf << " "; switch(tag.type) { case CartDebug::CODE: { buf << ALIGN(25) << tag.disasm << tag.ccount << "\n"; break; } case CartDebug::NONE: { buf << "\n"; break; } case CartDebug::ROW: { buf << tag.disasm << "\n"; break; } case CartDebug::GFX: { buf << ".byte " << (settings.gfx_format == Base::F_2 ? "%" : "$") << tag.bytes << " ; |"; for(int i = 12; i < 20; ++i) buf << ((tag.disasm[i] == '\x1e') ? "#" : " "); buf << "| $" << Base::HEX4 << tag.address << " (G)\n"; break; } case CartDebug::PGFX: { buf << ".byte " << (settings.gfx_format == Base::F_2 ? "%" : "$") << tag.bytes << " ; |"; for(int i = 12; i < 20; ++i) buf << ((tag.disasm[i] == '\x1f') ? "*" : " "); buf << "| $" << Base::HEX4 << tag.address << " (P)\n"; break; } case CartDebug::DATA: { buf << tag.disasm.substr(0, 9) << " ; $" << Base::HEX4 << tag.address << " (D)\n"; break; } default: { buf << "\n"; break; } } } } // 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\n" << " processor 6502\n\n"; bool addrUsed = false; for(uInt16 addr = 0x00; addr <= 0x0F; ++addr) addrUsed = addrUsed || myReserved.TIARead[addr]; for(uInt16 addr = 0x00; addr <= 0x3F; ++addr) addrUsed = addrUsed || myReserved.TIAWrite[addr]; for(uInt16 addr = 0x00; addr <= 0x17; ++addr) addrUsed = addrUsed || myReserved.IOReadWrite[addr]; if(addrUsed) { out << ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n" << "; TIA AND IO CONSTANTS\n" << ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n"; for(uInt16 addr = 0x00; addr <= 0x0F; ++addr) if(myReserved.TIARead[addr] && ourTIAMnemonicR[addr]) out << ALIGN(6) << ourTIAMnemonicR[addr] << " = $" << Base::HEX2 << right << addr << " ; (R)\n"; for(uInt16 addr = 0x00; addr <= 0x3F; ++addr) if(myReserved.TIAWrite[addr] && ourTIAMnemonicW[addr]) out << ALIGN(6) << ourTIAMnemonicW[addr] << " = $" << Base::HEX2 << right << addr << " ; (W)\n"; for(uInt16 addr = 0x00; addr <= 0x17; ++addr) if(myReserved.IOReadWrite[addr] && ourIOMnemonic[addr]) out << ALIGN(6) << ourIOMnemonic[addr] << " = $" << Base::HEX4 << right << (addr+0x280) << "\n"; } addrUsed = false; for(uInt16 addr = 0x80; addr <= 0xFF; ++addr) addrUsed = addrUsed || myReserved.ZPRAM[addr-0x80]; if(addrUsed) { out << "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n" << "; RIOT RAM (zero-page)\n" << ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n"; for(uInt16 addr = 0x80; addr <= 0xFF; ++addr) { if(myReserved.ZPRAM[addr-0x80] && myUserLabels.find(addr) == myUserLabels.end()) { out << ALIGN(6) << ourZPMnemonic[addr-0x80] << " = $" << Base::HEX2 << right << (addr) << "\n"; } } } AddrToLabel::const_iterator iter; if(myReserved.Label.size() > 0) { out << "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n" << "; NON LOCATABLE\n" << ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n"; for(iter = myReserved.Label.begin(); iter != myReserved.Label.end(); ++iter) out << ALIGN(10) << iter->second << " = $" << iter->first << "\n"; } if(myUserLabels.size() > 0) { out << "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n" << "; USER DEFINED\n" << ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n"; int max_len = 0; for(iter = myUserLabels.begin(); iter != myUserLabels.end(); ++iter) max_len = BSPF_max(max_len, (int)iter->second.size()); for(iter = myUserLabels.begin(); iter != myUserLabels.end(); ++iter) out << ALIGN(max_len) << iter->second << " = $" << iter->first << "\n"; } // And finally, output the disassembly out << buf.str(); out.close(); return "saved " + node.getShortPath() + " OK"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::saveRom() { const string& path = "~" BSPF_PATH_SEPARATOR + myConsole.properties().get(Cartridge_Name) + ".a26"; FilesystemNode node(path); ofstream out(node.getPath().c_str(), ios::out | ios::binary); if(out.is_open() && myConsole.cartridge().save(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(DirectiveList::const_iterator i = info.directiveList.begin(); i != info.directiveList.end(); ++i) { 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_startsWithIgnoreCase(ourTIAMnemonicR[addr], in)) completions.push_back(ourTIAMnemonicR[addr]); for(uInt16 addr = 0x00; addr <= 0x3F; ++addr) if(ourTIAMnemonicW[addr] && BSPF_startsWithIgnoreCase(ourTIAMnemonicW[addr], in)) completions.push_back(ourTIAMnemonicW[addr]); for(uInt16 addr = 0; addr <= 0x297-0x280; ++addr) if(ourIOMnemonic[addr] && BSPF_startsWithIgnoreCase(ourIOMnemonic[addr], in)) completions.push_back(ourIOMnemonic[addr]); for(uInt16 addr = 0; addr <= 0x7F; ++addr) if(ourZPMnemonic[addr] && BSPF_startsWithIgnoreCase(ourZPMnemonic[addr], in)) completions.push_back(ourZPMnemonic[addr]); // Now scan user-defined labels LabelToAddr::const_iterator iter; for(iter = myUserAddresses.begin(); iter != myUserAddresses.end(); ++iter) { const char* l = iter->first.c_str(); if(BSPF_startsWithIgnoreCase(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* CartDebug::ourTIAMnemonicR[16] = { "CXM0P", "CXM1P", "CXP0FB", "CXP1FB", "CXM0FB", "CXM1FB", "CXBLPF", "CXPPMM", "INPT0", "INPT1", "INPT2", "INPT3", "INPT4", "INPT5", 0, 0 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* 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", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* CartDebug::ourIOMnemonic[24] = { "SWCHA", "SWACNT", "SWCHB", "SWBCNT", "INTIM", "TIMINT", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "TIM1T", "TIM8T", "TIM64T", "T1024T" }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* 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-3.9.3/src/debugger/Expression.cxx0000644000175000001440000000253312266336753017655 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Expression.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Expression.hxx" #ifdef EXPR_REF_COUNT #include "bspf.hxx" int refCount = 0; #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Expression::Expression(Expression* lhs, Expression* rhs) : myLHS(lhs), myRHS(rhs) { #ifdef EXPR_REF_COUNT refCount++; cerr << "new Expression::Expression()" << endl; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Expression::~Expression() { #ifdef EXPR_REF_COUNT refCount--; cerr << "~Expression::Expression()" << endl; #endif delete myLHS; delete myRHS; } stella-3.9.3/src/debugger/DebuggerSystem.hxx0000644000175000001440000000333012266336753020450 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DebuggerSystem.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } ~DebuggerState() { } }; /** 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() { } 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; }; #endif stella-3.9.3/src/debugger/CpuDebug.cxx0000644000175000001440000001133112266336753017210 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CpuDebug.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "Array.hxx" #include "M6502.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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setPC(int pc) { my6502.PC = pc; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setSP(int sp) { my6502.SP = sp; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setPS(int ps) { my6502.PS(ps); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setA(int a) { my6502.A = a; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setX(int x) { my6502.X = x; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setY(int y) { my6502.Y = y; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setN(bool on) { my6502.N = on; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setV(bool on) { my6502.V = on; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setB(bool on) { // 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::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-3.9.3/src/debugger/DebuggerExpressions.hxx0000644000175000001440000002574712266336753021526 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DebuggerExpressions.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef DEBUGGER_EXPRESSIONS_HXX #define DEBUGGER_EXPRESSIONS_HXX #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) {} uInt16 evaluate() const { return myLHS->evaluate() & myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class BinNotExpression : public Expression { public: BinNotExpression(Expression* left) : Expression(left, 0) {} uInt16 evaluate() const { return ~(myLHS->evaluate()); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class BinOrExpression : public Expression { public: BinOrExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return myLHS->evaluate() | myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class BinXorExpression : public Expression { public: BinXorExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return myLHS->evaluate() ^ myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class ByteDerefExpression : public Expression { public: ByteDerefExpression(Expression* left): Expression(left, 0) {} uInt16 evaluate() const { return Debugger::debugger().peek(myLHS->evaluate()); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class ByteDerefOffsetExpression : public Expression { public: ByteDerefOffsetExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return Debugger::debugger().peek(myLHS->evaluate() + myRHS->evaluate()); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class ConstExpression : public Expression { public: ConstExpression(const int value) : Expression(0, 0), myValue(value) {} uInt16 evaluate() const { return myValue; } private: int myValue; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class CpuMethodExpression : public Expression { public: CpuMethodExpression(CPUDEBUG_INT_METHOD method) : Expression(0, 0), myMethod(method) {} uInt16 evaluate() const { return CALL_CPUDEBUG_METHOD(myMethod); } private: CPUDEBUG_INT_METHOD myMethod; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class DivExpression : public Expression { public: DivExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { int denom = myRHS->evaluate(); return denom == 0 ? 0 : myLHS->evaluate() / denom; } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class EqualsExpression : public Expression { public: EqualsExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return myLHS->evaluate() == myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class EquateExpression : public Expression { public: EquateExpression(const string& label) : Expression(0, 0), myLabel(label) {} uInt16 evaluate() const { return Debugger::debugger().cartDebug().getAddress(myLabel); } private: string myLabel; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class FunctionExpression : public Expression { public: FunctionExpression(const string& label) : Expression(0, 0), myLabel(label) {} uInt16 evaluate() const { const Expression* exp = Debugger::debugger().getFunction(myLabel); if(exp) return exp->evaluate(); else return 0; } private: string myLabel; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class GreaterEqualsExpression : public Expression { public: GreaterEqualsExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return myLHS->evaluate() >= myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class GreaterExpression : public Expression { public: GreaterExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return myLHS->evaluate() > myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class HiByteExpression : public Expression { public: HiByteExpression(Expression* left) : Expression(left, 0) {} uInt16 evaluate() const { return 0xff & (myLHS->evaluate() >> 8); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class LessEqualsExpression : public Expression { public: LessEqualsExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return myLHS->evaluate() <= myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class LessExpression : public Expression { public: LessExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return myLHS->evaluate() < myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class LoByteExpression : public Expression { public: LoByteExpression(Expression* left) : Expression(left, 0) {} uInt16 evaluate() const { return 0xff & myLHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class LogAndExpression : public Expression { public: LogAndExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return myLHS->evaluate() && myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class LogNotExpression : public Expression { public: LogNotExpression(Expression* left) : Expression(left, 0) {} uInt16 evaluate() const { return !(myLHS->evaluate()); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class LogOrExpression : public Expression { public: LogOrExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return myLHS->evaluate() || myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class MinusExpression : public Expression { public: MinusExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return myLHS->evaluate() - myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class ModExpression : public Expression { public: ModExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { int rhs = myRHS->evaluate(); return rhs == 0 ? 0 : myLHS->evaluate() % rhs; } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class MultExpression : public Expression { public: MultExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return myLHS->evaluate() * myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class NotEqualsExpression : public Expression { public: NotEqualsExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return myLHS->evaluate() != myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class PlusExpression : public Expression { public: PlusExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return myLHS->evaluate() + myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class CartMethodExpression : public Expression { public: CartMethodExpression(CARTDEBUG_INT_METHOD method) : Expression(0, 0), myMethod(method) {} uInt16 evaluate() const { return CALL_CARTDEBUG_METHOD(myMethod); } private: CARTDEBUG_INT_METHOD myMethod; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class ShiftLeftExpression : public Expression { public: ShiftLeftExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return myLHS->evaluate() << myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class ShiftRightExpression : public Expression { public: ShiftRightExpression(Expression* left, Expression* right) : Expression(left, right) {} uInt16 evaluate() const { return myLHS->evaluate() >> myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class TiaMethodExpression : public Expression { public: TiaMethodExpression(TIADEBUG_INT_METHOD method) : Expression(0, 0), myMethod(method) {} uInt16 evaluate() const { return CALL_TIADEBUG_METHOD(myMethod); } private: TIADEBUG_INT_METHOD myMethod; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class UnaryMinusExpression : public Expression { public: UnaryMinusExpression(Expression* left) : Expression(left, 0) {} uInt16 evaluate() const { return -(myLHS->evaluate()); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class WordDerefExpression : public Expression { public: WordDerefExpression(Expression* left) : Expression(left, 0) {} uInt16 evaluate() const { return Debugger::debugger().dpeek(myLHS->evaluate()); } }; #endif stella-3.9.3/src/debugger/PackedBitArray.hxx0000644000175000001440000000240712266336753020350 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: PackedBitArray.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef PACKEDBITARRAY_HXX #define PACKEDBITARRAY_HXX #include "bspf.hxx" #define wordSize ( (sizeof(unsigned int)) * 8) class PackedBitArray { public: PackedBitArray(uInt32 length); ~PackedBitArray(); uInt32 isSet(uInt32 bit) const; uInt32 isClear(uInt32 bit) const; void set(uInt32 bit); void clear(uInt32 bit); void toggle(uInt32 bit); private: // number of unsigned ints (size/wordSize): uInt32 words; // the array itself: uInt32* bits; }; #endif stella-3.9.3/src/debugger/module.mk0000644000175000001440000000060211324637555016601 0ustar stephenusersMODULE := src/debugger MODULE_OBJS := \ src/debugger/Debugger.o \ src/debugger/DebuggerParser.o \ src/debugger/Expression.o \ src/debugger/PackedBitArray.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-3.9.3/src/debugger/Debugger.hxx0000644000175000001440000002307612266336753017254 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Debugger.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef DEBUGGER_HXX #define DEBUGGER_HXX class OSystem; class Console; class CartDebug; class CpuDebug; class RiotDebug; class TIADebug; class M6502; class TiaInfoWidget; class TiaOutputWidget; class TiaZoomWidget; class EditTextWidget; class RomWidget; class Expression; class Serializer; class PackedBitArray; class PromptWidget; class ButtonWidget; #include #include "Array.hxx" #include "Base.hxx" #include "DialogContainer.hxx" #include "DebuggerDialog.hxx" #include "DebuggerParser.hxx" #include "System.hxx" #include "Stack.hxx" #include "bspf.hxx" typedef map FunctionMap; typedef map FunctionDefMap; /* // These will probably turn out to be unneeded, left for reference for now // pointer types for Debugger instance methods typedef uInt8 (Debugger::*DEBUGGER_BYTE_METHOD)(); typedef uInt16 (Debugger::*DEBUGGER_WORD_METHOD)(); // call the pointed-to method on the (static) debugger object. #define CALL_DEBUGGER_METHOD(method) ( ( Debugger::debugger().*method)() ) */ /** 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 @version $Id: Debugger.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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; public: /** Create a new debugger parent object */ Debugger(OSystem& osystem, Console& console); /** Destructor */ 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 data An address associated with the message */ bool start(const string& message = "", int address = -1); 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 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; } PackedBitArray& breakpoints() const { return *myBreakPoints; } PackedBitArray& readtraps() const { return *myReadTraps; } PackedBitArray& writetraps() const { return *myWriteTraps; } PromptWidget& prompt() const { return myDialog->prompt(); } RomWidget& rom() const { return myDialog->rom(); } /** Run the debugger command and return the result. */ const string run(const string& command); /** The current cycle count of the System. */ int cycles(); string autoExec(); string showWatches(); /** Convert between string->integer and integer->string, taking into account the current base format. */ int stringToValue(const string& stringval) { return myParser->decipher_arg(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 input | (1 << bit); else return 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(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; } /* These are now exposed so Expressions can use them. */ int peek(int addr) { return mySystem.peek(addr); } int dpeek(int addr) { return mySystem.peek(addr) | (mySystem.peek(addr+1) << 8); } int getAccessFlags(uInt16 addr) { return mySystem.getAccessFlags(addr); } void setAccessFlags(uInt16 addr, uInt8 flags) { mySystem.setAccessFlags(addr, flags); } void setBreakPoint(int bp, bool set); bool setBank(int bank); bool patchROM(int addr, int value); /** Normally, accessing RAM or ROM during emulation can possibly trigger bankswitching. However, when we're in the debugger, we'd like to inspect values without actually triggering bankswitches. The read/write state must therefore be locked before accessing values, and unlocked for normal emulation to occur. (takes mediasource into account) */ void lockBankswitchState(); void unlockBankswitchState(); private: /** Save state of each debugger subsystem. */ void saveOldState(bool addrewind = true); /** 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); bool rewindState(); void toggleBreakPoint(int bp); bool breakPoint(int bp); void toggleReadTrap(int t); void toggleWriteTrap(int t); void toggleTrap(int t); bool readTrap(int t); bool writeTrap(int 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; DebuggerParser* myParser; CartDebug* myCartDebug; CpuDebug* myCpuDebug; RiotDebug* myRiotDebug; TIADebug* myTiaDebug; PackedBitArray* myBreakPoints; PackedBitArray* myReadTraps; PackedBitArray* myWriteTraps; static Debugger* myStaticDebugger; FunctionMap functions; FunctionDefMap functionDefs; // Dimensions of the entire debugger window uInt32 myWidth; uInt32 myHeight; // Class holding all rewind state functionality in the debugger // Essentially, it's a modified circular array-based stack // that cleverly deals with allocation/deallocation of memory class RewindManager { public: RewindManager(OSystem& system, ButtonWidget& button); virtual ~RewindManager(); public: bool addState(); bool rewindState(); bool isEmpty(); void clear(); private: enum { MAX_SIZE = 100 }; OSystem& myOSystem; ButtonWidget& myRewindButton; Serializer* myStateList[MAX_SIZE]; uInt32 mySize, myTop; }; RewindManager* myRewindManager; }; #endif stella-3.9.3/src/debugger/RiotDebug.hxx0000644000175000001440000000576412266336753017420 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RiotDebug.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef RIOT_DEBUG_HXX #define RIOT_DEBUG_HXX class Debugger; class RiotDebug; #include "Array.hxx" #include "M6532.hxx" #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; }; class RiotDebug : public DebuggerSystem { public: RiotDebug(Debugger& dbg, Console& console); const DebuggerState& getState(); const DebuggerState& getOldState() { return myOldState; } void saveOldState(); string toString(); /* 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 { return mySystem.m6532().intim(); } uInt8 timint() const { return mySystem.m6532().timint(); } Int32 timClocks() const { return mySystem.m6532().timerClocks(); } Int32 intimClocks() const { return mySystem.m6532().intimClocks(); } /* 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; }; #endif stella-3.9.3/src/debugger/TIADebug.hxx0000644000175000001440000001352212266336753017107 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TIADebug.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef TIA_DEBUG_HXX #define TIA_DEBUG_HXX class Debugger; class TiaDebug; class TIA; #include "Array.hxx" #include "DebuggerSystem.hxx" // pointer types for TIADebug instance methods // (used by TiaMethodExpression) class TIADebug; typedef int (TIADebug::*TIADEBUG_INT_METHOD)(); // call the pointed-to method on the (global) debugger object. #define CALL_TIADEBUG_METHOD(method) ( ( Debugger::debugger().tiaDebug().*method)() ) // Indices for various IntArray in TiaState enum { P0, P1, M0, M1, BL }; class TiaState : public DebuggerState { public: IntArray ram; IntArray coluRegs; IntArray gr; IntArray pos; IntArray hm; IntArray pf; IntArray size; IntArray aud; }; class TIADebug : public DebuggerSystem { public: TIADebug(Debugger& dbg, Console& console); TIA& tia() const { return myTIA; } const DebuggerState& getState(); const DebuggerState& getOldState() { return myOldState; } void saveOldState(); string toString(); // 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); // 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); // Collision registers bool collM0_P1(int newVal = -1) { return collision(0, newVal); } bool collM0_P0(int newVal = -1) { return collision(1, newVal); } bool collM1_P0(int newVal = -1) { return collision(2, newVal); } bool collM1_P1(int newVal = -1) { return collision(3, newVal); } bool collP0_PF(int newVal = -1) { return collision(4, newVal); } bool collP0_BL(int newVal = -1) { return collision(5, newVal); } bool collP1_PF(int newVal = -1) { return collision(6, newVal); } bool collP1_BL(int newVal = -1) { return collision(7, newVal); } bool collM0_PF(int newVal = -1) { return collision(8, newVal); } bool collM0_BL(int newVal = -1) { return collision(9, newVal); } bool collM1_PF(int newVal = -1) { return collision(10, newVal); } bool collM1_BL(int newVal = -1) { return collision(11, newVal); } bool collBL_PF(int newVal = -1) { return collision(12, newVal); } bool collP0_P1(int newVal = -1) { return collision(13, newVal); } bool collM0_M1(int newVal = -1) { return collision(14, newVal); } // TIA strobe registers void strobeWsync() { mySystem.poke(WSYNC, 0); } void strobeRsync() { mySystem.poke(RSYNC, 0); } // not emulated! void strobeResP0() { mySystem.poke(RESP0, 0); } void strobeResP1() { mySystem.poke(RESP1, 0); } void strobeResM0() { mySystem.poke(RESM0, 0); } void strobeResM1() { mySystem.poke(RESM1, 0); } void strobeResBL() { mySystem.poke(RESBL, 0); } void strobeHmove() { mySystem.poke(HMOVE, 0); } void strobeHmclr() { mySystem.poke(HMCLR, 0); } void strobeCxclr() { mySystem.poke(CXCLR, 0); } // Read-only internal TIA state int scanlines(); int frameCount(); int clocksThisLine(); bool vsync(); bool vblank(); int vsyncAsInt() { return int(vsync()); } // so we can use _vsync pseudo-register int vblankAsInt() { return int(vblank()); } // so we can use _vblank pseudo-register private: /** Display a color patch for color at given index in the palette */ string colorSwatch(uInt8 c); /** Get/set specific bits in the collision register (used by collXX_XX) */ bool collision(int collID, int newVal); string audFreq(uInt8 div); string booleanWithLabel(string label, bool value); private: TiaState myState; TiaState myOldState; TIA& myTIA; string nusizStrings[8]; }; #endif stella-3.9.3/src/debugger/PackedBitArray.cxx0000644000175000001440000000433012266336753020340 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: PackedBitArray.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "PackedBitArray.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PackedBitArray::PackedBitArray(uInt32 length) : words(length / wordSize + 1) { bits = new uInt32[ words ]; for(uInt32 i = 0; i < words; ++i) bits[i] = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PackedBitArray::~PackedBitArray() { delete[] bits; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 PackedBitArray::isSet(uInt32 bit) const { uInt32 word = bit / wordSize; bit %= wordSize; return (bits[word] & (1 << bit)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 PackedBitArray::isClear(uInt32 bit) const { uInt32 word = bit / wordSize; bit %= wordSize; return !(bits[word] & (1 << bit)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PackedBitArray::toggle(uInt32 bit) { uInt32 word = bit / wordSize; bit %= wordSize; bits[word] ^= (1 << bit); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PackedBitArray::set(uInt32 bit) { uInt32 word = bit / wordSize; bit %= wordSize; bits[word] |= (1 << bit); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PackedBitArray::clear(uInt32 bit) { uInt32 word = bit / wordSize; bit %= wordSize; bits[word] &= (~(1 << bit)); } stella-3.9.3/src/debugger/Debugger.cxx0000644000175000001440000005362012266336753017245 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Debugger.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include #include #include #include #include "Version.hxx" #include "OSystem.hxx" #include "FrameBuffer.hxx" #include "FSNode.hxx" #include "Settings.hxx" #include "DebuggerDialog.hxx" #include "DebuggerParser.hxx" #include "StateManager.hxx" #include "Console.hxx" #include "System.hxx" #include "M6502.hxx" #include "Cart.hxx" #include "TIA.hxx" #include "CartDebug.hxx" #include "CartDebugWidget.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 "Debugger.hxx" Debugger* Debugger::myStaticDebugger = 0; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static const char* builtin_functions[][3] = { // { "name", "definition", "help text" } // 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)" }, // empty string marks end of list, do not remove { 0, 0, 0 } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Names are defined here, but processed in YaccParser static const char* pseudo_registers[][2] = { // { "name", "help text" } { "_bank", "Currently selected bank" }, { "_rwport", "Address at which a read from a write port occurred" }, { "_scan", "Current scanline count" }, { "_fcount", "Number of frames since emulation started" }, { "_cclocks", "Color clocks on current scanline" }, { "_vsync", "Whether vertical sync is enabled (1 or 0)" }, { "_vblank", "Whether vertical blank is enabled (1 or 0)" }, // empty string marks end of list, do not remove { 0, 0 } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Debugger::Debugger(OSystem& osystem, Console& console) : DialogContainer(&osystem), myConsole(console), mySystem(console.system()), myDialog(NULL), myParser(NULL), myCartDebug(NULL), myCpuDebug(NULL), myRiotDebug(NULL), myTiaDebug(NULL), myBreakPoints(NULL), myReadTraps(NULL), myWriteTraps(NULL), myWidth(DebuggerDialog::kSmallFontMinW), myHeight(DebuggerDialog::kSmallFontMinH), myRewindManager(NULL) { // Init parser myParser = new DebuggerParser(*this, osystem.settings()); // Create debugger subsystems myCpuDebug = new CpuDebug(*this, myConsole); myCartDebug = new CartDebug(*this, myConsole, osystem); myRiotDebug = new RiotDebug(*this, myConsole); myTiaDebug = new TIADebug(*this, myConsole); myBreakPoints = new PackedBitArray(0x10000); myReadTraps = new PackedBitArray(0x10000); myWriteTraps = new PackedBitArray(0x10000); // 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() { delete myParser; delete myCartDebug; delete myCpuDebug; delete myRiotDebug; delete myTiaDebug; delete myBreakPoints; delete myReadTraps; delete myWriteTraps; delete myRewindManager; myStaticDebugger = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::initialize() { // Get the dialog size const GUI::Size& size = myOSystem->settings().getSize("dbg.res"); myWidth = BSPF_max(size.w, 0); myHeight = BSPF_max(size.h, 0); myWidth = BSPF_max(myWidth, (uInt32)DebuggerDialog::kSmallFontMinW); myHeight = BSPF_max(myHeight, (uInt32)DebuggerDialog::kSmallFontMinH); myOSystem->settings().setValue("dbg.res", GUI::Size(myWidth, myHeight)); delete myBaseDialog; myBaseDialog = myDialog = NULL; myDialog = new DebuggerDialog(myOSystem, this, 0, 0, myWidth, myHeight); myBaseDialog = myDialog; myRewindManager = new RewindManager(*myOSystem, myDialog->rewindButton()); myCartDebug->setDebugWidget(&(myDialog->cartDebug())); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBInitStatus Debugger::initializeVideo() { string title = string("Stella ") + STELLA_VERSION + ": Debugger mode"; return myOSystem->frameBuffer().initialize(title, myWidth, myHeight); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::start(const string& message, int address) { 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 << Common::Base::HEX4 << address; 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() { ostringstream buf; // autoexec.stella is always run FilesystemNode autoexec(myOSystem->baseDir() + "autoexec.stella"); buf << "autoExec():" << endl << myParser->exec(autoexec) << endl; // Also, "romname.stella" if present FilesystemNode romname(myOSystem->romFile().getPathWithExt(".stella")); buf << myParser->exec(romname) << endl; // Init builtins for(int i = 0; builtin_functions[i][0] != 0; i++) { // TODO - check this for memory leaks int res = YaccParser::parse(builtin_functions[i][1]); if(res != 0) cerr << "ERROR in builtin function!" << endl; Expression* exp = YaccParser::getResult(); addFunction(builtin_functions[i][0], builtin_functions[i][1], exp, true); } return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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() { myCpuDebug->setPC(dpeek(0xfffc)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* 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 = 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) { mySystem.clearDirtyPages(); unlockBankswitchState(); myOSystem->state().saveState(state); lockBankswitchState(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::loadState(int state) { mySystem.clearDirtyPages(); unlockBankswitchState(); myOSystem->state().loadState(state); lockBankswitchState(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Debugger::step() { saveOldState(); mySystem.clearDirtyPages(); int cyc = mySystem.cycles(); unlockBankswitchState(); myOSystem->console().tia().updateScanlineByStep(); lockBankswitchState(); return mySystem.cycles() - cyc; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 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(); mySystem.clearDirtyPages(); int cyc = mySystem.cycles(); int targetPC = myCpuDebug->pc() + 3; // return address unlockBankswitchState(); myOSystem->console().tia().updateScanlineByTrace(targetPC); lockBankswitchState(); return mySystem.cycles() - cyc; } else return step(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::toggleBreakPoint(int bp) { mySystem.m6502().setBreakPoints(myBreakPoints); if(bp < 0) bp = myCpuDebug->pc(); myBreakPoints->toggle(bp); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::setBreakPoint(int bp, bool set) { mySystem.m6502().setBreakPoints(myBreakPoints); if(bp < 0) bp = myCpuDebug->pc(); if(set) myBreakPoints->set(bp); else myBreakPoints->clear(bp); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::breakPoint(int bp) { if(bp < 0) bp = myCpuDebug->pc(); return myBreakPoints->isSet(bp) != 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::toggleReadTrap(int t) { mySystem.m6502().setTraps(myReadTraps, myWriteTraps); myReadTraps->toggle(t); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::toggleWriteTrap(int t) { mySystem.m6502().setTraps(myReadTraps, myWriteTraps); myWriteTraps->toggle(t); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::toggleTrap(int t) { toggleReadTrap(t); toggleWriteTrap(t); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::readTrap(int t) { return myReadTraps->isSet(t) != 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::writeTrap(int t) { return myWriteTraps->isSet(t) != 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Debugger::cycles() { return mySystem.cycles(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::nextScanline(int lines) { saveOldState(); mySystem.clearDirtyPages(); unlockBankswitchState(); while(lines) { myOSystem->console().tia().updateScanline(); --lines; } lockBankswitchState(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::nextFrame(int frames) { saveOldState(); mySystem.clearDirtyPages(); unlockBankswitchState(); while(frames) { myOSystem->console().tia().update(); --frames; } lockBankswitchState(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::rewindState() { mySystem.clearDirtyPages(); unlockBankswitchState(); bool result = myRewindManager->rewindState(); lockBankswitchState(); return result; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::clearAllBreakPoints() { delete myBreakPoints; myBreakPoints = new PackedBitArray(0x10000); mySystem.m6502().setBreakPoints(NULL); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::clearAllTraps() { delete myReadTraps; delete myWriteTraps; myReadTraps = new PackedBitArray(0x10000); myWriteTraps = new PackedBitArray(0x10000); mySystem.m6502().setTraps(NULL, NULL); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Debugger::showWatches() { return myParser->showWatches(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::setBank(int bank) { if(myConsole.cartridge().bankCount() > 1) { myConsole.cartridge().unlockBank(); bool status = myConsole.cartridge().bank(bank); myConsole.cartridge().lockBank(); return status; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::patchROM(int addr, int value) { return myConsole.cartridge().patch(addr, value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::saveOldState(bool addrewind) { myCartDebug->saveOldState(); myCpuDebug->saveOldState(); myRiotDebug->saveOldState(); myTiaDebug->saveOldState(); // Add another rewind level to the Undo list if(addrewind) myRewindManager->addState(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::setStartState() { // Lock the bus each time the debugger is entered, so we don't disturb anything lockBankswitchState(); // Start a new rewind list myRewindManager->clear(); // Save initial state, but don't add it to the rewind list saveOldState(false); // Set the 're-disassemble' flag, but don't do it until the next scheduled time myDialog->rom().invalidate(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::setQuitState() { // Bus must be unlocked for normal operation when leaving debugger mode unlockBankswitchState(); // 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(myBreakPoints->isSet(myCpuDebug->pc())) mySystem.m6502().execute(1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::addFunction(const string& name, const string& definition, Expression* exp, bool builtin) { functions.insert(make_pair(name, exp)); if(!builtin) functionDefs.insert(make_pair(name, definition)); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::delFunction(const string& name) { FunctionMap::iterator iter = functions.find(name); if(iter == functions.end()) return false; functions.erase(name); delete iter->second; FunctionDefMap::iterator def_iter = functionDefs.find(name); if(def_iter == functionDefs.end()) return false; functionDefs.erase(name); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Expression* Debugger::getFunction(const string& name) const { FunctionMap::const_iterator iter = functions.find(name); if(iter == functions.end()) return 0; else return iter->second; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& Debugger::getFunctionDef(const string& name) const { FunctionDefMap::const_iterator iter = functionDefs.find(name); if(iter == functionDefs.end()) return EmptyString; else return iter->second; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const FunctionDefMap Debugger::getFunctionDefMap() const { return functionDefs; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Debugger::builtinHelp() const { ostringstream buf; uInt16 len, c_maxlen = 0, i_maxlen = 0; // Get column widths for aligned output (functions) for(int i = 0; builtin_functions[i][0] != 0; ++i) { len = strlen(builtin_functions[i][0]); if(len > c_maxlen) c_maxlen = len; len = strlen(builtin_functions[i][1]); if(len > i_maxlen) i_maxlen = len; } buf << setfill(' ') << endl << "Built-in functions:" << endl; for(int i = 0; builtin_functions[i][0] != 0; ++i) { buf << setw(c_maxlen) << left << builtin_functions[i][0] << setw(2) << right << "{" << setw(i_maxlen) << left << builtin_functions[i][1] << setw(4) << "}" << builtin_functions[i][2] << endl; } // Get column widths for aligned output (pseudo-registers) c_maxlen = 0; for(int i = 0; pseudo_registers[i][0] != 0; ++i) { len = strlen(pseudo_registers[i][0]); if(len > c_maxlen) c_maxlen = len; } buf << endl << "Pseudo-registers:" << endl; for(int i = 0; pseudo_registers[i][0] != 0; ++i) { buf << setw(c_maxlen) << left << pseudo_registers[i][0] << setw(2) << " " << setw(i_maxlen) << left << pseudo_registers[i][1] << endl; } return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::getCompletions(const char* in, StringList& list) const { FunctionMap::const_iterator iter; for(iter = functions.begin(); iter != functions.end(); ++iter) { const char* l = iter->first.c_str(); if(BSPF_equalsIgnoreCase(l, in)) list.push_back(l); } for(int i = 0; pseudo_registers[i][0] != 0; ++i) if(BSPF_equalsIgnoreCase(pseudo_registers[i][0], in)) list.push_back(pseudo_registers[i][0]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::lockBankswitchState() { mySystem.lockDataBus(); myConsole.cartridge().lockBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::unlockBankswitchState() { mySystem.unlockDataBus(); myConsole.cartridge().unlockBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Debugger::RewindManager::RewindManager(OSystem& system, ButtonWidget& button) : myOSystem(system), myRewindButton(button), mySize(0), myTop(0) { for(int i = 0; i < MAX_SIZE; ++i) myStateList[i] = (Serializer*) NULL; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Debugger::RewindManager::~RewindManager() { for(int i = 0; i < MAX_SIZE; ++i) delete myStateList[i]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::RewindManager::addState() { // Create a new Serializer object if we need one if(myStateList[myTop] == NULL) myStateList[myTop] = new Serializer(); Serializer& s = *(myStateList[myTop]); if(s.isValid()) { s.reset(); if(myOSystem.state().saveState(s) && myOSystem.console().tia().saveDisplay(s)) { // Are we still within the allowable size, or are we overwriting an item? mySize++; if(mySize > MAX_SIZE) mySize = MAX_SIZE; myTop = (myTop + 1) % MAX_SIZE; myRewindButton.setEnabled(true); return true; } } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::RewindManager::rewindState() { if(mySize > 0) { mySize--; myTop = myTop == 0 ? MAX_SIZE - 1 : myTop - 1; Serializer& s = *(myStateList[myTop]); s.reset(); myOSystem.state().loadState(s); myOSystem.console().tia().loadDisplay(s); if(mySize == 0) myRewindButton.setEnabled(false); return true; } else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::RewindManager::isEmpty() { return mySize == 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::RewindManager::clear() { for(int i = 0; i < MAX_SIZE; ++i) if(myStateList[i] != NULL) myStateList[i]->reset(); myTop = mySize = 0; // We use Widget::clearFlags here instead of Widget::setEnabled(), // since the latter implies an immediate draw/update, but this method // might be called before any UI exists // TODO - fix this deficiency in the UI core; we shouldn't have to worry // about such things at this level myRewindButton.clearFlags(WIDGET_ENABLED); } stella-3.9.3/src/debugger/RiotDebug.cxx0000644000175000001440000002545512266336753017412 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RiotDebug.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "System.hxx" #include "TIA.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); // 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); // 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 mySystem.tia().myVBLANK & 0x40; else if(bit == 7) // dump to ground return mySystem.tia().myDumpEnabled; 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]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Controller& RiotDebug::controller(Controller::Jack jack) const { return myConsole.controller(jack); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 = (RiotState&) getState(); const RiotState& oldstate = (RiotState&) 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-3.9.3/src/debugger/TIADebug.cxx0000644000175000001440000005456512266336753017116 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TIADebug.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Base.hxx" #include "System.hxx" #include "Debugger.hxx" #include "TIA.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() { myState.ram.clear(); for(int i = 0; i < 0x010; ++i) myState.ram.push_back(myTIA.peek(i)); // 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()); // Player 1 & 2 graphics registers myState.gr.clear(); myState.gr.push_back(grP0()); myState.gr.push_back(grP1()); // 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()); // 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()); return myState; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIADebug::saveOldState() { myOldState.ram.clear(); for(int i = 0; i < 0x010; ++i) myOldState.ram.push_back(myTIA.peek(i)); // 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()); // Player 1 & 2 graphics registers myOldState.gr.clear(); myOldState.gr.push_back(grP0()); myOldState.gr.push_back(grP1()); // 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()); // 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()); } /* 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 vdelP0(int newVal = -1); // bool vdelP1(int newVal = -1); // bool vdelBL(int newVal = -1); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::vdelP0(int newVal) { if(newVal > -1) mySystem.poke(VDELP0, ((bool)newVal)); return myTIA.myVDELP0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::vdelP1(int newVal) { if(newVal > -1) mySystem.poke(VDELP1, ((bool)newVal)); return myTIA.myVDELP1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::vdelBL(int newVal) { if(newVal > -1) mySystem.poke(VDELBL, ((bool)newVal)); return myTIA.myVDELBL; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::enaM0(int newVal) { if(newVal > -1) mySystem.poke(ENAM0, ((bool)newVal) << 1); return myTIA.myENAM0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::enaM1(int newVal) { if(newVal > -1) mySystem.poke(ENAM1, ((bool)newVal) << 1); return myTIA.myENAM1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::enaBL(int newVal) { if(newVal > -1) mySystem.poke(ENABL, ((bool)newVal) << 1); return myTIA.myENABL; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::resMP0(int newVal) { if(newVal > -1) mySystem.poke(RESMP0, ((bool)newVal) << 1); return myTIA.myRESMP0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::resMP1(int newVal) { if(newVal > -1) mySystem.poke(RESMP1, ((bool)newVal) << 1); return myTIA.myRESMP1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::refP0(int newVal) { if(newVal > -1) mySystem.poke(REFP0, ((bool)newVal) << 3); return myTIA.myREFP0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::refP1(int newVal) { if(newVal > -1) mySystem.poke(REFP1, ((bool)newVal) << 3); return myTIA.myREFP1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::refPF(int newVal) { if(newVal > -1) { int tmp = myTIA.myCTRLPF; if(newVal) tmp |= 0x01; else tmp &= ~0x01; mySystem.poke(CTRLPF, tmp); } return myTIA.myCTRLPF & 0x01; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::scorePF(int newVal) { if(newVal > -1) { int tmp = myTIA.myCTRLPF; if(newVal) tmp |= 0x02; else tmp &= ~0x02; mySystem.poke(CTRLPF, tmp); } return myTIA.myCTRLPF & 0x02; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::priorityPF(int newVal) { if(newVal > -1) { int tmp = myTIA.myCTRLPF; if(newVal) tmp |= 0x04; else tmp &= ~0x04; mySystem.poke(CTRLPF, tmp); } return myTIA.myCTRLPF & 0x04; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::collision(int collID, int newVal) { unsigned int mask = 1 << collID; if(newVal > -1) { if(newVal) myTIA.myCollision |= mask; else myTIA.myCollision &= ~mask; } return myTIA.myCollision & mask; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::audC0(int newVal) { if(newVal > -1) mySystem.poke(AUDC0, newVal); return myTIA.myAUDC0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::audC1(int newVal) { if(newVal > -1) mySystem.poke(AUDC1, newVal); return myTIA.myAUDC1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::audV0(int newVal) { if(newVal > -1) mySystem.poke(AUDV0, newVal); return myTIA.myAUDV0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::audV1(int newVal) { if(newVal > -1) mySystem.poke(AUDV1, newVal); return myTIA.myAUDV1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::audF0(int newVal) { if(newVal > -1) mySystem.poke(AUDF0, newVal); return myTIA.myAUDF0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::audF1(int newVal) { if(newVal > -1) mySystem.poke(AUDF1, newVal); return myTIA.myAUDF1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::pf0(int newVal) { if(newVal > -1) mySystem.poke(PF0, newVal << 4); return myTIA.myPF & 0x0f; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::pf1(int newVal) { if(newVal > -1) mySystem.poke(PF1, newVal); return (myTIA.myPF & 0xff0) >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::pf2(int newVal) { if(newVal > -1) mySystem.poke(PF2, newVal); return (myTIA.myPF & 0xff000) >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::coluP0(int newVal) { if(newVal > -1) mySystem.poke(COLUP0, newVal); return myTIA.myColor[P0Color] & 0xff; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::coluP1(int newVal) { if(newVal > -1) mySystem.poke(COLUP1, newVal); return myTIA.myColor[P1Color] & 0xff; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::coluPF(int newVal) { if(newVal > -1) mySystem.poke(COLUPF, newVal); return myTIA.myColor[PFColor] & 0xff; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::coluBK(int newVal) { if(newVal > -1) mySystem.poke(COLUBK, newVal); return myTIA.myColor[BKColor] & 0xff; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::nusiz0(int newVal) { if(newVal > -1) mySystem.poke(NUSIZ0, newVal); return myTIA.myNUSIZ0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::nusiz1(int newVal) { if(newVal > -1) mySystem.poke(NUSIZ1, newVal); return myTIA.myNUSIZ1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::nusizP0(int newVal) { if(newVal > -1) { uInt8 tmp = myTIA.myNUSIZ0 & ~0x07; tmp |= (newVal & 0x07); mySystem.poke(NUSIZ0, tmp); } return myTIA.myNUSIZ0 & 0x07; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::nusizP1(int newVal) { if(newVal > -1) { uInt8 tmp = myTIA.myNUSIZ1 & ~0x07; tmp |= newVal & 0x07; mySystem.poke(NUSIZ1, tmp); } return myTIA.myNUSIZ1 & 0x07; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::nusizM0(int newVal) { if(newVal > -1) { uInt8 tmp = myTIA.myNUSIZ0 & ~0x30; tmp |= (newVal & 0x04) << 4; mySystem.poke(NUSIZ0, tmp); } return (myTIA.myNUSIZ0 & 0x30) >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::nusizM1(int newVal) { if(newVal > -1) { uInt8 tmp = myTIA.myNUSIZ1 & ~0x30; tmp |= (newVal & 0x04) << 4; mySystem.poke(NUSIZ1, tmp); } return (myTIA.myNUSIZ1 & 0x30) >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::grP0(int newVal) { if(newVal > -1) mySystem.poke(GRP0, newVal); return myTIA.myGRP0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::grP1(int newVal) { if(newVal > -1) mySystem.poke(GRP1, newVal); return myTIA.myGRP1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::posP0(int newVal) { if(newVal > -1) myTIA.myPOSP0 = newVal; return myTIA.myPOSP0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::posP1(int newVal) { if(newVal > -1) myTIA.myPOSP1 = newVal; return myTIA.myPOSP1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::posM0(int newVal) { if(newVal > -1) myTIA.myPOSM0 = newVal; return myTIA.myPOSM0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::posM1(int newVal) { if(newVal > -1) myTIA.myPOSM1 = newVal; return myTIA.myPOSM1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::posBL(int newVal) { if(newVal > -1) myTIA.myPOSBL = newVal; return myTIA.myPOSBL; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::ctrlPF(int newVal) { if(newVal > -1) mySystem.poke(CTRLPF, newVal); return myTIA.myCTRLPF; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::sizeBL(int newVal) { if(newVal > -1) { uInt8 tmp = myTIA.myCTRLPF & ~0x30; tmp |= (newVal & 0x04) << 4; mySystem.poke(CTRLPF, tmp); } return (myTIA.myCTRLPF & 0x30) >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::hmP0(int newVal) { if(newVal > -1) mySystem.poke(HMP0, newVal << 4); return myTIA.myHMP0 >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::hmP1(int newVal) { if(newVal > -1) mySystem.poke(HMP1, newVal << 4); return myTIA.myHMP1 >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::hmM0(int newVal) { if(newVal > -1) mySystem.poke(HMM0, newVal << 4); return myTIA.myHMM0 >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::hmM1(int newVal) { if(newVal > -1) mySystem.poke(HMM1, newVal << 4); return myTIA.myHMM1 >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::hmBL(int newVal) { if(newVal > -1) mySystem.poke(HMBL, newVal << 4); return myTIA.myHMBL >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int TIADebug::frameCount() { return myTIA.myFrameCounter; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int TIADebug::scanlines() { return myTIA.scanlines(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int TIADebug::clocksThisLine() { return myTIA.clocksThisLine(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::vsync() { return (myTIA.myVSYNC & 2) == 2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::vblank() { return (myTIA.myVBLANK & 2) == 2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string TIADebug::colorSwatch(uInt8 c) { string ret; ret += char((c >> 1) | 0x80); ret += "\177 "; ret += "\177\003 "; return ret; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string TIADebug::audFreq(uInt8 div) { string ret; char buf[10]; double hz = 30000.0; if(div) hz /= div; BSPF_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::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 = (TiaState&) getState(); // const TiaState& oldstate = (TiaState&) getOldState(); // build up output, then return it. buf << "scanline " << 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.myDumpEnabled) << 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=#" << 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=#" << dec << state.pos[P1] << " HM=$" << Common::Base::HEX2 << state.hm[P1] << " " << nusizP1String() << " " << booleanWithLabel("refl", refP1()) << " " << booleanWithLabel("delay", vdelP1()) << endl << "M0: " << (myTIA.myENAM0 ? " ENABLED" : "disabled") << " pos=#" << dec << state.pos[M0] << " HM=$" << Common::Base::HEX2 << state.hm[M0] << " size=" << dec << state.size[M0] << " " << booleanWithLabel("reset", resMP0()) << endl << "M1: " << (myTIA.myENAM1 ? " ENABLED" : "disabled") << " pos=#" << dec << state.pos[M1] << " HM=$" << Common::Base::HEX2 << state.hm[M1] << " size=" << dec << state.size[M1] << " " << booleanWithLabel("reset", resMP0()) << endl << "BL: " << (myTIA.myENABL ? " ENABLED" : "disabled") << " pos=#" << dec << state.pos[BL] << " HM=$" << Common::Base::HEX2 << state.hm[BL] << " size=" << 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)myTIA.myAUDF0 << "/" << audFreq(myTIA.myAUDF0) << " " << "AUDC0: $" << Common::Base::HEX2 << (int)myTIA.myAUDC0 << " " << "AUDV0: $" << Common::Base::HEX2 << (int)myTIA.myAUDV0 << endl << "AUDF1: $" << Common::Base::HEX2 << (int)myTIA.myAUDF1 << "/" << audFreq(myTIA.myAUDF1) << " " << "AUDC1: $" << Common::Base::HEX2 << (int)myTIA.myAUDC1 << " " << "AUDV1: $" << Common::Base::HEX2 << (int)myTIA.myAUDV1 ; // note: last line should not contain \n, caller will add. return buf.str(); } stella-3.9.3/src/debugger/gui/0000755000175000001440000000000012267274564015555 5ustar stephenusersstella-3.9.3/src/debugger/gui/CartMCWidget.cxx0000644000175000001440000001131612266336753020556 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartMCWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "CartMC.hxx" #include "PopUpWidget.hxx" #include "CartMCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeMCWidget::CartridgeMCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeMC& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { #define ROM_BLOCKS uInt32 size = 128 * 1024; string info = "MC cartridge, 128 1K slices ROM + 32 1K RAM\n" "Write $80 - $FF into a hotspot for ROM (128)\n" "Write $00 - $3F into a hotspot for RAM (32)\n" "Segment 0 @ $F000 - $F3FF (hotspot = $3C)\n" "Segment 1 @ $F400 - $F7FF (hotspot = $3D)\n" "Segment 2 @ $F800 - $FBFF (hotspot = $3E)\n" "Segment 3 @ $FC00 - $FFFF (hotspot = $3F)\n" "\nTHIS SCHEME IS NOT FULLY IMPLEMENTED OR TESTED\n"; int xpos = 10, ypos = addBaseInformation(size, "Chris Wilkson's Megacart", info) + myLineHeight; VariantList items; // Add 128 1K 'ROM' blocks for(uInt32 i = 0x80; i <= 0xFF; ++i) { const string& b = Variant(i).toString(); items.push_back(b + " (ROM)", b); } // Add 64 512B 'RAM' blocks for(uInt32 i = 0x00; i <= 0x3F; ++i) { const string& b = Variant(i).toString(); items.push_back(b + " (RAM)", b); } const int lwidth = _font.getStringWidth("Set slice for segment X ($3X): "), fwidth = _font.getStringWidth("255 (ROM)"); mySlice0 = new PopUpWidget(boss, _font, xpos, ypos-2, fwidth, myLineHeight, items, "Set slice for segment 0 ($3C): ", lwidth, kSlice0Changed); mySlice0->setTarget(this); addFocusWidget(mySlice0); ypos += mySlice0->getHeight() + 4; mySlice1 = new PopUpWidget(boss, _font, xpos, ypos-2, fwidth, myLineHeight, items, "Set slice for segment 1 ($3D): ", lwidth, kSlice1Changed); mySlice1->setTarget(this); addFocusWidget(mySlice1); ypos += mySlice1->getHeight() + 4; mySlice2 = new PopUpWidget(boss, _font, xpos, ypos-2, fwidth, myLineHeight, items, "Set slice for segment 2 ($3E): ", lwidth, kSlice2Changed); mySlice2->setTarget(this); addFocusWidget(mySlice2); ypos += mySlice2->getHeight() + 4; mySlice3 = new PopUpWidget(boss, _font, xpos, ypos-2, fwidth, myLineHeight, items, "Set slice for segment 3 ($3F): ", lwidth, kSlice3Changed); mySlice3->setTarget(this); addFocusWidget(mySlice3); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMCWidget::loadConfig() { mySlice0->setSelectedIndex(myCart.myCurrentBlock[0]); mySlice1->setSelectedIndex(myCart.myCurrentBlock[1]); mySlice2->setSelectedIndex(myCart.myCurrentBlock[2]); mySlice3->setSelectedIndex(myCart.myCurrentBlock[3]); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMCWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { myCart.unlockBank(); switch(cmd) { case kSlice0Changed: myCart.myCurrentBlock[0] = mySlice0->getSelectedTag().toInt(); break; case kSlice1Changed: myCart.myCurrentBlock[1] = mySlice1->getSelectedTag().toInt(); break; case kSlice2Changed: myCart.myCurrentBlock[2] = mySlice2->getSelectedTag().toInt(); break; case kSlice3Changed: myCart.myCurrentBlock[3] = mySlice3->getSelectedTag().toInt(); break; } myCart.lockBank(); invalidate(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeMCWidget::bankState() { ostringstream& buf = buffer(); buf << "Slices: " << dec << myCart.myCurrentBlock[0] << " / " << myCart.myCurrentBlock[1] << " / " << myCart.myCurrentBlock[2] << " / " << myCart.myCurrentBlock[3]; return buf.str(); } stella-3.9.3/src/debugger/gui/CartEFWidget.hxx0000644000175000001440000000264412266336753020562 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartEFWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeEF& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/CartF4SCWidget.cxx0000644000175000001440000000656712266336753020772 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF4SCWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 << "\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 = $" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Atari", info.str(), 15) + myLineHeight; VariantList items; items.push_back("0 ($FF4)"); items.push_back("1 ($FF5)"); items.push_back("2 ($FF6)"); items.push_back("3 ($FF7)"); items.push_back("4 ($FF8)"); items.push_back("5 ($FF9)"); items.push_back("6 ($FFA)"); items.push_back("7 ($FFB)"); 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 CartridgeF4SCWidget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$FF4", "$FF5", "$FF6", "$FF7", "$FF8", "$FF9", "$FFA", "$FFB" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/DrivingWidget.hxx0000644000175000001440000000303312266336753021051 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DrivingWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef DRIVING_WIDGET_HXX #define DRIVING_WIDGET_HXX class ButtonWidget; class CheckboxWidget; class DataGridWidget; #include "Control.hxx" #include "Event.hxx" #include "ControllerWidget.hxx" class DrivingWidget : public ControllerWidget { public: DrivingWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~DrivingWidget(); void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); private: enum { kGreyUpCmd = 'DWup', kGreyDownCmd = 'DWdn', kFireCmd = 'DWfr' }; ButtonWidget *myGreyUp, *myGreyDown; DataGridWidget* myGreyValue; CheckboxWidget* myFire; int myGreyIndex; static uInt8 ourGreyTable[4]; }; #endif stella-3.9.3/src/debugger/gui/KeyboardWidget.hxx0000644000175000001440000000252212266336753021211 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: KeyboardWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef KEYBOARD_WIDGET_HXX #define KEYBOARD_WIDGET_HXX #include "Control.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(); void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); private: CheckboxWidget* myBox[12]; Event::Type* myEvent; static Event::Type ourLeftEvents[12], ourRightEvents[12]; }; #endif stella-3.9.3/src/debugger/gui/CartDebugWidget.hxx0000644000175000001440000001042112266336753021306 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDebugWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CART_DEBUG_WIDGET_HXX #define CART_DEBUG_WIDGET_HXX class GuiObject; class ButtonWidget; #include "Base.hxx" #include "Font.hxx" #include "Command.hxx" #include "Debugger.hxx" #include "RomWidget.hxx" #include "Widget.hxx" #include "EditTextWidget.hxx" #include "StringListWidget.hxx" #include "StringParser.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) : Widget(boss, lfont, x, y, w, h), CommandSender(boss), _nfont(nfont), myFontWidth(lfont.getMaxCharWidth()), myFontHeight(lfont.getFontHeight()), myLineHeight(lfont.getLineHeight()), myButtonHeight(myLineHeight + 4) { } virtual ~CartDebugWidget() { }; public: int addBaseInformation(int bytes, const string& manufacturer, const string& desc, const uInt16 maxlines = 10) { const int lwidth = _font.getStringWidth("Manufacturer: "), fwidth = _w - lwidth - 20; EditTextWidget* w = 0; ostringstream buf; int x = 10, y = 10; // Add ROM size, manufacturer and bankswitch info new StaticTextWidget(_boss, _font, x, y, lwidth, myFontHeight, "ROM Size: ", kTextAlignLeft); 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: ", kTextAlignLeft); w = new EditTextWidget(_boss, _nfont, x+lwidth, y, fwidth, myLineHeight, manufacturer); w->setEditable(false); y += myLineHeight + 4; StringParser bs(desc, (fwidth - kScrollBarWidth) / myFontWidth); const StringList& sl = bs.stringList(); uInt32 lines = sl.size(); if(lines < 3) lines = 3; if(lines > maxlines) lines = maxlines; new StaticTextWidget(_boss, _font, x, y, lwidth, myFontHeight, "Description: ", kTextAlignLeft); 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; } // Inform the ROM Widget that the underlying cart has somehow changed void invalidate() { sendCommand(RomWidget::kInvalidateListing, -1, -1); } // 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() { myDesc->setSelected(0); } virtual void handleCommand(CommandSender* sender, int cmd, int data, int id) { }; // Query internal state of the cart (usually just bankswitching info) virtual string bankState() { return "0 (non-bankswitched)"; } 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; ostringstream& buffer() { myBuffer.str(""); return myBuffer; } private: StringListWidget* myDesc; ostringstream myBuffer; }; #endif stella-3.9.3/src/debugger/gui/JoystickWidget.hxx0000644000175000001440000000254112266336753021251 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: JoystickWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef JOYSTICK_WIDGET_HXX #define JOYSTICK_WIDGET_HXX #include "Control.hxx" #include "Event.hxx" #include "ControllerWidget.hxx" class JoystickWidget : public ControllerWidget { public: JoystickWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~JoystickWidget(); void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); private: enum { kJUp = 0, kJDown, kJLeft, kJRight, kJFire }; CheckboxWidget* myPins[5]; static Controller::DigitalPin ourPinNo[5]; }; #endif stella-3.9.3/src/debugger/gui/TiaOutputWidget.hxx0000644000175000001440000000415712266336753021415 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TiaOutputWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef TIA_OUTPUT_WIDGET_HXX #define TIA_OUTPUT_WIDGET_HXX class GuiObject; class ContextMenu; class TiaZoomWidget; #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(); void loadConfig(); void setZoomWidget(TiaZoomWidget* w) { myZoom = w; } // 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). /* virtual void handleMouseUp(int x, int y, int button, int clickCount); virtual void handleMouseWheel(int x, int y, int direction); virtual bool handleKeyDown(StellaKey key, StellaMod mod, char ascii); virtual bool handleKeyUp(StellaKey key, StellaMod mod, char ascii); */ protected: void handleMouseDown(int x, int y, int button, int clickCount); void handleCommand(CommandSender* sender, int cmd, int data, int id); void drawWidget(bool hilite); bool wantsFocus() { return false; } private: ContextMenu* myMenu; TiaZoomWidget* myZoom; int myClickX, myClickY; // Create this buffer once, instead of allocating it each time the // TIA image is redrawn uInt32 myLineBuffer[320]; }; #endif stella-3.9.3/src/debugger/gui/RomWidget.hxx0000644000175000001440000000351612266336753020212 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RomWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef ROM_WIDGET_HXX #define ROM_WIDGET_HXX class GuiObject; class EditTextWidget; #include "Base.hxx" #include "Command.hxx" #include "RomListWidget.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(); void invalidate(bool forcereload = true) { myListIsDirty = true; if(forcereload) loadConfig(); } void scrollTo(int line) { myRomList->setSelected(line); } void handleCommand(CommandSender* sender, int cmd, int data, int id); void loadConfig(); private: 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; }; #endif stella-3.9.3/src/debugger/gui/DebuggerDialog.cxx0000644000175000001440000003512112266336753021145 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DebuggerDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Widget.hxx" #include "Dialog.hxx" #include "TabWidget.hxx" #include "TiaInfoWidget.hxx" #include "TiaOutputWidget.hxx" #include "TiaZoomWidget.hxx" #include "AudioWidget.hxx" #include "PromptWidget.hxx" #include "CpuWidget.hxx" #include "RamWidget.hxx" #include "RiotWidget.hxx" #include "RomWidget.hxx" #include "TiaWidget.hxx" #include "CartDebugWidget.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 "DebuggerDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DebuggerDialog::DebuggerDialog(OSystem* osystem, DialogContainer* parent, int x, int y, int w, int h) : Dialog(osystem, parent, x, y, w, h, true), // use base surface myTab(NULL), myRomTab(NULL), myLFont(NULL), myNFont(NULL), myFatalError(NULL) { 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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DebuggerDialog::~DebuggerDialog() { delete myLFont; delete myNFont; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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, char ascii) { bool handled = instance().eventHandler().kbdAlt(mod); if(handled) { switch(ascii) { case 's': doStep(); break; case 't': doTrace(); break; case 'f': doAdvance(); break; case 'l': doScanlineAdvance(); break; case 'r': doRewind(); break; default: handled = false; break; } } if(!handled) Dialog::handleKeyDown(key, mod, ascii); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 kDDExitCmd: doExitDebugger(); break; case kDDExitFatalCmd: doExitRom(); break; case RomWidget::kInvalidateListing: myRom->invalidate(); 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::doExitDebugger() { instance().debugger().parser().run("run"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::doExitRom() { instance().debugger().parser().run("exitrom"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::createFont() { int fontstyle = instance().settings().getInt("dbg.fontstyle"); // For now, these sizes are hardcoded based on actual font size if(_w >= kLargeFontMinW && _h >= kLargeFontMinH) { // Large font doesn't use fontstyle at all myLFont = new GUI::Font(GUI::stellaMediumDesc); myNFont = new GUI::Font(GUI::stellaMediumDesc); } else if(_w >= kMediumFontMinW && _h >= kMediumFontMinH) { if(fontstyle == 1) { myLFont = new GUI::Font(GUI::consoleMediumBDesc); myNFont = new GUI::Font(GUI::consoleMediumDesc); } else if(fontstyle == 2) { myLFont = new GUI::Font(GUI::consoleMediumDesc); myNFont = new GUI::Font(GUI::consoleMediumBDesc); } else if(fontstyle == 3) { myLFont = new GUI::Font(GUI::consoleMediumBDesc); myNFont = new GUI::Font(GUI::consoleMediumBDesc); } else // default to zero { myLFont = new GUI::Font(GUI::consoleMediumDesc); myNFont = new GUI::Font(GUI::consoleMediumDesc); } } else { if(fontstyle == 1) { myLFont = new GUI::Font(GUI::consoleBDesc); myNFont = new GUI::Font(GUI::consoleDesc); } else if(fontstyle == 2) { myLFont = new GUI::Font(GUI::consoleDesc); myNFont = new GUI::Font(GUI::consoleBDesc); } else if(fontstyle == 3) { myLFont = new GUI::Font(GUI::consoleBDesc); myNFont = new GUI::Font(GUI::consoleBDesc); } else // default to zero { myLFont = new GUI::Font(GUI::consoleDesc); myNFont = new GUI::Font(GUI::consoleDesc); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::showFatalMessage(const string& msg) { delete myFatalError; myFatalError = new GUI::MessageBox(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 tabID = myTab->addTab(" Prompt "); myPrompt = new PromptWidget(myTab, *myNFont, 2, 2, widWidth, widHeight); 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); myMessageBox->clearFlags(WIDGET_RETAIN_FOCUS); myMessageBox->setTextColor(kTextColorEm); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::addRomArea() { const GUI::Rect& r = getRomBounds(); const int vBorder = 4; 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 = myLFont->getStringWidth("< ") + 4; bheight = bheight * 5 + 4*4; buttonX -= (bwidth + 5); buttonY = r.top + 5; myRewindButton = new ButtonWidget(this, *myLFont, buttonX, buttonY, bwidth, bheight, "<", kDDRewindCmd); myRewindButton->clearFlags(WIDGET_ENABLED); int xpos = buttonX - 8*myLFont->getMaxCharWidth() - 20, ypos = 20; 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 RamWidget(this, *myLFont, *myNFont, xpos, ypos); 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); } 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, BSPF_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-3.9.3/src/debugger/gui/CartEFSCWidget.cxx0000644000175000001440000000737712266336753021013 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartEFSCWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 " << dec << i << " @ $" << Common::Base::HEX4 << (start + 0x100) << " - " << "$" << (start + 0xFFF) << " (hotspot = $" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Paul Slocum / Homestar Runner", info.str()) + myLineHeight; VariantList items; items.push_back(" 0 ($FE0)"); items.push_back(" 1 ($FE1)"); items.push_back(" 2 ($FE2)"); items.push_back(" 3 ($FE3)"); items.push_back(" 4 ($FE4)"); items.push_back(" 5 ($FE5)"); items.push_back(" 6 ($FE6)"); items.push_back(" 7 ($FE7)"); items.push_back(" 8 ($FE8)"); items.push_back(" 9 ($FE9)"); items.push_back("10 ($FEA)"); items.push_back("11 ($FEB)"); items.push_back("12 ($FEC)"); items.push_back("13 ($FED)"); items.push_back("14 ($FEE)"); items.push_back("15 ($FEF)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("15 ($FE0) "), myLineHeight, items, "Set bank: ", _font.getStringWidth("Set bank: "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEFSCWidget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$FE0", "$FE1", "$FE2", "$FE3", "$FE4", "$FE5", "$FE6", "$FE7", "$FE8", "$FE9", "$FEA", "$FEB", "$FEC", "$FED", "$FEE", "$FEF" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/RomListWidget.cxx0000644000175000001440000004210012266336753021031 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RomListWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "Debugger.hxx" #include "DiStella.hxx" #include "PackedBitArray.hxx" #include "Widget.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), myMenu(NULL), _rows(0), _cols(0), _currentPos(0), _selectedItem(-1), _highlightedItem(-1), _editMode(false), _currentKeyDown(KBDK_UNKNOWN) { _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 = new RomListSettings(this, lfont); // Take advantage of a wide debugger window when possible const int fontWidth = lfont.getMaxCharWidth(), numchars = w / fontWidth; _labelWidth = BSPF_max(16, int(0.20 * (numchars - 12))) * fontWidth - 1; _bytesWidth = 12 * 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 = BSPF_max(_fontHeight, CheckboxWidget::boxSize()); _rows = h / _fontHeight; // Create a CheckboxWidget for each row in the list CheckboxWidget* t; for(int i = 0; i < _rows; ++i) { t = new CheckboxWidget(boss, lfont, _x + 2, ypos, "", kCheckActionCmd); t->setTarget(this); t->setID(i); t->setFill(CheckboxWidget::Circle); t->setTextColor(kTextColorEm); ypos += _fontHeight; myCheckList.push_back(t); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RomListWidget::~RomListWidget() { delete myMenu; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 = myDisasm->list.size(); i < _rows; ++i) myCheckList[i]->clearFlags(WIDGET_ENABLED); recalc(); setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& RomListWidget::getText() const { if(_selectedItem < -1 || _selectedItem >= (int)myDisasm->list.size()) return EmptyString; else return _editString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int RomListWidget::findItem(int x, int y) const { return (y - 1) / _fontHeight + _currentPos; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::recalc() { int size = 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 = myDisasm->list.size(); myScrollBar->_entriesPerPage = _rows; // Reset to normal data entry abortEditMode(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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; } if (_currentPos < 0 || _rows > (int)myDisasm->list.size()) _currentPos = 0; else if (_currentPos + _rows > (int)myDisasm->list.size()) _currentPos = myDisasm->list.size() - _rows; myScrollBar->_currentPos = _currentPos; myScrollBar->recalc(); setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::handleMouseDown(int x, int y, int button, int clickCount) { if (!isEnabled()) return; // Grab right mouse button for context menu, left for selection/edit mode if(button == 2) { // 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(); draw(); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::handleMouseUp(int x, int y, int button, 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(_editable && !_editMode) startEditMode(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::handleMouseWheel(int x, int y, int direction) { myScrollBar->handleMouseWheel(x, y, direction); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RomListWidget::handleKeyDown(StellaKey key, StellaMod mod, char ascii) { // Ignore all Alt-mod keys if(instance().eventHandler().kbdAlt(mod)) return true; bool handled = true; int oldSelectedItem = _selectedItem; if (_editMode) { // Class EditableWidget handles all text editing related key presses for us handled = EditableWidget::handleKeyDown(key, mod, ascii); } else { // not editmode 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, char ascii) { 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 (_editable) 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 = myDisasm->list.size() - 1; break; case Event::UIHome: _selectedItem = 0; break; case Event::UIEnd: _selectedItem = 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 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 kSetPositionCmd: if (_currentPos != (int)data) { _currentPos = data; setDirty(); draw(); } 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) { //cerr << "RomListWidget::drawWidget\n"; FBSurface& s = _boss->dialog().surface(); const CartDebug::DisassemblyList& dlist = myDisasm->list; int i, pos, xpos, ypos, len = dlist.size(); int deltax; 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 ccountw = _fontWidth << 2, large_disasmw = _w - l.x() - _labelWidth, medium_disasmw = large_disasmw - r.width(), small_disasmw = medium_disasmw - (ccountw << 1), actualwidth = myDisasm->fieldwidth * _fontWidth; if(actualwidth < small_disasmw) small_disasmw = actualwidth; xpos = _x + CheckboxWidget::boxSize() + 10; ypos = _y + 2; for (i = 0, pos = _currentPos; i < _rows && pos < len; i++, pos++, ypos += _fontHeight) { // 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); 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 disassembly and cycle count s.drawString(_font, dlist[pos].disasm, xpos + _labelWidth, ypos, small_disasmw, kTextColor); s.drawString(_font, dlist[pos].ccount, xpos + _labelWidth + small_disasmw, ypos, ccountw, kTextColor); } else { // Draw disassembly only s.drawString(_font, dlist[pos].disasm, xpos + _labelWidth, ypos, medium_disasmw, kTextColor); } // Draw separator s.vLine(_x + r.x() - 7, ypos, ypos + _fontHeight - 1, kColor); // Draw bytes { if (_selectedItem == pos && _editMode) { adjustOffset(); deltax = -_editScrollOffset; s.drawString(_font, _editString, _x + r.x(), ypos, r.width(), kTextColor, kTextAlignLeft, deltax, false); drawCaret(); } else { deltax = 0; s.drawString(_font, dlist[pos].bytes, _x + r.x(), ypos, r.width(), kTextColor); } } } else { // Draw disassembly, giving it all remaining horizontal space s.drawString(_font, dlist[pos].disasm, xpos + _labelWidth, ypos, large_disasmw, 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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RomListWidget::tryInsertChar(char c, int pos) { // Not sure how efficient this is, or should we even care? bool insert = false; c = tolower(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: insert = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || c == ' '; break; case Common::Base::F_2: case Common::Base::F_2_8: case Common::Base::F_2_16: insert = c == '0' || c == '1' || c == ' '; break; case Common::Base::F_10: if((c >= '0' && c <= '9') || c == ' ') insert = true; break; case Common::Base::F_DEFAULT: break; } if(insert) _editString.insert(pos, 1, c); return insert; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::startEditMode() { if (_editable && !_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.gfx_format; 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-3.9.3/src/debugger/gui/PaddleWidget.cxx0000644000175000001440000000750712266336753020645 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: PaddleWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #include "EventHandler.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 = myController.jack() == Controller::Left; const string& label = leftport ? "Left (Paddles):" : "Right (Paddles):"; 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, kTextAlignLeft); 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(1400000); myP0Resistance->setStepValue(1400000/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(1400000); myP1Resistance->setStepValue(1400000/100); myP1Resistance->setTarget(this); xpos += 20; ypos += myP1Resistance->getHeight() + 4; myP1Fire = new CheckboxWidget(boss, font, xpos, ypos, "Fire", kP1Fire); myP1Fire->setTarget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaddleWidget::~PaddleWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaddleWidget::loadConfig() { myP0Resistance->setValue(1400000 - (Int32)myController.read(Controller::Nine)); myP1Resistance->setValue(1400000 - (Int32)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, 1400000 - myP0Resistance->getValue()); break; case kP1Changed: myController.set(Controller::Five, 1400000 - myP1Resistance->getValue()); break; case kP0Fire: myController.set(Controller::Four, !myP0Fire->getState()); break; case kP1Fire: myController.set(Controller::Three, !myP1Fire->getState()); break; } } stella-3.9.3/src/debugger/gui/TogglePixelWidget.hxx0000644000175000001440000000306112266336753021673 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TogglePixelWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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(); void setColor(int color) { _pixelColor = (color >= 0 && color <= 255) ? color : kDlgColor; } void setBackgroundColor(int color) { _backgroundColor = (color >= 0 && color <= 255) ? color : kDlgColor; } void setState(const BoolArray& state); void setIntState(int value, bool swap); int getIntState(); protected: void drawWidget(bool hilite); private: int _pixelColor, _backgroundColor; bool _swapBits; }; #endif stella-3.9.3/src/debugger/gui/TiaZoomWidget.hxx0000644000175000001440000000355212266336753021037 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TiaZoomWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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(); void loadConfig(); void setPos(int x, int y); protected: void handleMouseDown(int x, int y, int button, int clickCount); void handleMouseUp(int x, int y, int button, int clickCount); void handleMouseWheel(int x, int y, int direction); void handleMouseMoved(int x, int y, int button); void handleMouseLeft(int button); bool handleEvent(Event::Type event); void handleCommand(CommandSender* sender, int cmd, int data, int id); void drawWidget(bool hilite); bool wantsFocus() { return true; } private: void zoom(int level); void recalc(); private: ContextMenu* myMenu; int myZoomLevel; int myNumCols, myNumRows; int myXOff, myYOff; bool myMouseMoving; int myXClick, myYClick; }; #endif stella-3.9.3/src/debugger/gui/CartFA2Widget.hxx0000644000175000001440000000314112266336753020631 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartFA2Widget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeFA2& myCart; PopUpWidget* myBank; ButtonWidget *myFlashErase, *myFlashLoad, *myFlashSave; enum { kBankChanged = 'bkCH', kFlashErase = 'flER', kFlashLoad = 'flLD', kFlashSave = 'flSV' }; }; #endif stella-3.9.3/src/debugger/gui/Cart3EWidget.hxx0000644000175000001440000000304012266336753020526 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart3EWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: Cartridge3E& myCart; const uInt32 myNumRomBanks; const uInt32 myNumRamBanks; PopUpWidget *myROMBank, *myRAMBank; enum { kROMBankChanged = 'rmCH', kRAMBankChanged = 'raCH' }; }; #endif stella-3.9.3/src/debugger/gui/ToggleBitWidget.hxx0000644000175000001440000000255612266336753021340 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ToggleBitWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef TOGGLE_BIT_WIDGET_HXX #define TOGGLE_BIT_WIDGET_HXX class StringList; #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(); void setList(const StringList& off, const StringList& on); void setState(const BoolArray& state, const BoolArray& changed); protected: void drawWidget(bool hilite); protected: StringList _offList; StringList _onList; }; #endif stella-3.9.3/src/debugger/gui/CartDPCWidget.hxx0000644000175000001440000000354712266336753020701 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDPCWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void saveOldState(); void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: struct CartState { ByteArray tops; ByteArray bottoms; IntArray counters; ByteArray flags; BoolArray music; uInt8 random; }; private: CartridgeDPC& myCart; PopUpWidget* myBank; DataGridWidget* myTops; DataGridWidget* myBottoms; DataGridWidget* myCounters; DataGridWidget* myFlags; DataGridWidget* myMusicMode; DataGridWidget* myRandom; CartState myOldState; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/CartE7Widget.cxx0000644000175000001440000001030412266336753020526 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartE7Widget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "CartE7.hxx" #include "PopUpWidget.hxx" #include "CartE7Widget.hxx" static const char* spot_lower[] = { "0 - ROM ($FE0)", "1 - ROM ($FE1)", "2 - ROM ($FE2)", "3 - ROM ($FE3)", "4 - ROM ($FE4)", "5 - ROM ($FE5)", "6 - ROM ($FE6)", "7 - RAM ($FE7)" }; static const char* spot_upper[] = { "0 - RAM ($FE8)", "1 - RAM ($FE9)", "2 - RAM ($FEA)", "3 - RAM ($FEB)" }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeE7Widget::CartridgeE7Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeE7& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = 8 * 2048; 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 0 (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" << " $F400 - $F7FF (R), $F000 - $F3FF (W)\n" << "Upper 1.5K ROM accessible @ $FA00 - $FFFF\n" << " Always points to last 1.5K of ROM\n" << "Startup slices = " << cart.myStartBank << " / 0\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, "M-Network", info.str(), 15) + myLineHeight; VariantList items0, items1; for(int i = 0; i < 8; ++i) items0.push_back(spot_lower[i]); for(int i = 0; i < 4; ++i) items1.push_back(spot_upper[i]); const int lwidth = _font.getStringWidth("Set slice for upper 256B: "), fwidth = _font.getStringWidth("3 - RAM ($FEB)"); 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 CartridgeE7Widget::loadConfig() { myLower2K->setSelectedIndex(myCart.myCurrentSlice[0]); myUpper256B->setSelectedIndex(myCart.myCurrentRAM); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE7Widget::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 CartridgeE7Widget::bankState() { ostringstream& buf = buffer(); buf << "Slices: " << dec << spot_lower[myCart.myCurrentSlice[0]] << " / " << spot_upper[myCart.myCurrentRAM]; return buf.str(); } stella-3.9.3/src/debugger/gui/DataGridWidget.hxx0000644000175000001440000001035512266336753021133 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DataGridWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef DATA_GRID_WIDGET_HXX #define DATA_GRID_WIDGET_HXX class DataGridOpsWidget; class ScrollBarWidget; #include "Widget.hxx" #include "Command.hxx" #include "Debugger.hxx" #include "EditableWidget.hxx" #include "Array.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(); 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 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, manually specifying if the value changed */ void setValue(int position, int value, bool changed); int getSelectedAddr() const { return _addrList[_selectedItem]; } int getSelectedValue() const { return _valueList[_selectedItem]; } void setRange(int lower, int upper); virtual void handleMouseDown(int x, int y, int button, int clickCount); virtual void handleMouseUp(int x, int y, int button, int clickCount); virtual void handleMouseWheel(int x, int y, int direction); virtual bool handleKeyDown(StellaKey key, StellaMod mod, char ascii); virtual bool handleKeyUp(StellaKey key, StellaMod mod, char ascii); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); virtual bool wantsFocus() { return true; } // Account for the extra width of embedded scrollbar virtual int getWidth() const; void startEditMode(); void endEditMode(); int colWidth() { return _colWidth; } void setOpsWidget(DataGridOpsWidget* w) { _opsWidget = w; } protected: void drawWidget(bool hilite); int findItem(int x, int y); void abortEditMode(); GUI::Rect getEditRect() const; void receivedFocusWidget(); void lostFocusWidget(); bool tryInsertChar(char c, int pos); protected: int _rows; int _cols; int _currentRow; int _currentCol; int _rowHeight; int _colWidth; int _bits; int _lowerBound; int _upperBound; 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(); }; #endif stella-3.9.3/src/debugger/gui/CartDPCPlusWidget.cxx0000644000175000001440000002671512266336753021542 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDPCPlusWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 $FF6 to $FFB\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; items.push_back("0 ($FF6)"); items.push_back("1 ($FF7)"); items.push_back("2 ($FF8)"); items.push_back("3 ($FF9)"); items.push_back("4 ($FFA)"); items.push_back("5 ($FFB)"); 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); // Top registers int lwidth = _font.getStringWidth("Counter Registers: "); xpos = 10; ypos += myLineHeight + 8; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Top Registers: ", kTextAlignLeft); 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: ", kTextAlignLeft); 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: ", kTextAlignLeft); 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: ", kTextAlignLeft); 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: ", kTextAlignLeft); 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: ", kTextAlignLeft); 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: ", kTextAlignLeft); 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: ", kTextAlignLeft); 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: ", kTextAlignLeft); 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: ", kTextAlignLeft); 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(); for(int 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(int 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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCPlusWidget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); // 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* spot[] = { "$FF6", "$FF7", "$FF8", "$FF9", "$FFA", "$FFB" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/CartE0Widget.hxx0000644000175000001440000000300612266336753020525 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartE0Widget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeE0& myCart; PopUpWidget *mySlice0, *mySlice1, *mySlice2; enum { kSlice0Changed = 's0CH', kSlice1Changed = 's1CH', kSlice2Changed = 's2CH' }; }; #endif stella-3.9.3/src/debugger/gui/RiotWidget.hxx0000644000175000001440000000474412266336753020376 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RiotWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef RIOT_WIDGET_HXX #define RIOT_WIDGET_HXX class GuiObject; class ButtonWidget; class DataGridWidget; class PopUpWidget; class ToggleBitWidget; class ControllerWidget; #include "Array.hxx" #include "Control.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(); void handleCommand(CommandSender* sender, int cmd, int data, int id); void loadConfig(); private: ControllerWidget* addControlWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); 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* myRandomizeCPU; CheckboxWidget* myRandomizeRAM; // 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, kRandCPUID, kRandRAMID }; }; #endif stella-3.9.3/src/debugger/gui/BoosterWidget.hxx0000644000175000001440000000256112266336753021071 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: BoosterWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef BOOSTER_WIDGET_HXX #define BOOSTER_WIDGET_HXX #include "Control.hxx" #include "Event.hxx" #include "ControllerWidget.hxx" class BoosterWidget : public ControllerWidget { public: BoosterWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~BoosterWidget(); void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); private: enum { kJUp = 0, kJDown, kJLeft, kJRight, kJFire, kJBooster, kJTrigger }; CheckboxWidget* myPins[7]; static Controller::DigitalPin ourPinNo[5]; }; #endif stella-3.9.3/src/debugger/gui/Cart3FWidget.cxx0000644000175000001440000000604212266336753020527 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart3FWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 << "\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) items.push_back(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() { myBank->setSelectedIndex(myCart.myCurrentBank); 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 = " << dec << myCart.myCurrentBank << ", hotspot = $3F"; return buf.str(); } stella-3.9.3/src/debugger/gui/ToggleWidget.cxx0000644000175000001440000001230712266336753020667 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ToggleWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #include "Widget.hxx" #include "ToggleWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ToggleWidget::ToggleWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int cols, int rows) : Widget(boss, font, x, y, 16, 16), CommandSender(boss), _rows(rows), _cols(cols), _currentRow(0), _currentCol(0), _selectedItem(0), _editable(true) { _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | WIDGET_WANTS_RAWDATA; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ToggleWidget::~ToggleWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ToggleWidget::handleMouseDown(int x, int y, int button, 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(); draw(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ToggleWidget::handleMouseUp(int x, int y, int button, 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 == 2 && (_selectedItem == findItem(x, y))) { _stateList[_selectedItem] = !_stateList[_selectedItem]; _changedList[_selectedItem] = !_changedList[_selectedItem]; sendCommand(ToggleWidget::kItemDataChangedCmd, _selectedItem, _id); setDirty(); draw(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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, char ascii) { // Ignore all mod keys if(instance().eventHandler().kbdControl(mod) || instance().eventHandler().kbdAlt(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(); draw(); } return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ToggleWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case kSetPositionCmd: if (_selectedItem != (int)data) { _selectedItem = data; setDirty(); draw(); } break; } } stella-3.9.3/src/debugger/gui/RamWidget.cxx0000644000175000001440000003542112266336753020167 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RamWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "DataGridWidget.hxx" #include "EditTextWidget.hxx" #include "FrameBuffer.hxx" #include "GuiObject.hxx" #include "InputTextDialog.hxx" #include "OSystem.hxx" #include "CartDebug.hxx" #include "Widget.hxx" #include "RamWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RamWidget::RamWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y) : Widget(boss, lfont, x, y, 16, 16), CommandSender(boss), myUndoAddress(-1), myUndoValue(-1), myCurrentRamBank(0) { const int fontWidth = lfont.getMaxCharWidth(), fontHeight = lfont.getFontHeight(), lineHeight = lfont.getLineHeight(), bwidth = lfont.getStringWidth("Compare "), bheight = lineHeight + 2; int xpos, ypos, lwidth; // Create a 16x8 grid holding byte values (16 x 8 = 128 RAM bytes) with labels // Add a scrollbar, since there may be more than 128 bytes of RAM available xpos = x; ypos = y + lineHeight; lwidth = 4 * fontWidth; myRamGrid = new DataGridWidget(boss, nfont, xpos + lwidth, ypos, 16, 8, 2, 8, Common::Base::F_16, true); myRamGrid->setTarget(this); addFocusWidget(myRamGrid); // Create actions buttons to the left of the RAM grid xpos += lwidth + myRamGrid->getWidth() + 4; myUndoButton = new ButtonWidget(boss, lfont, xpos, ypos, bwidth, bheight, "Undo", kUndoCmd); myUndoButton->setTarget(this); ypos += bheight + 4; myRevertButton = new ButtonWidget(boss, lfont, xpos, ypos, bwidth, bheight, "Revert", kRevertCmd); myRevertButton->setTarget(this); ypos += 2 * bheight + 2; mySearchButton = new ButtonWidget(boss, lfont, xpos, ypos, bwidth, bheight, "Search", kSearchCmd); mySearchButton->setTarget(this); ypos += bheight + 4; myCompareButton = new ButtonWidget(boss, lfont, xpos, ypos, bwidth, bheight, "Compare", kCmpCmd); myCompareButton->setTarget(this); ypos += bheight + 4; myRestartButton = new ButtonWidget(boss, lfont, xpos, ypos, bwidth, bheight, "Reset", kRestartCmd); myRestartButton->setTarget(this); // Remember position of right side of buttons int xpos_r = xpos + bwidth ; // Labels for RAM grid xpos = x; ypos = y + lineHeight; myRamStart = new StaticTextWidget(boss, lfont, xpos, ypos - lineHeight, lfont.getStringWidth("xxxx"), fontHeight, "00xx", kTextAlignLeft); for(int col = 0; col < 16; ++col) { new StaticTextWidget(boss, lfont, xpos + col*myRamGrid->colWidth() + lwidth + 8, ypos - lineHeight, fontWidth, fontHeight, Common::Base::toString(col, Common::Base::F_16_1), kTextAlignLeft); } for(int row = 0; row < 8; ++row) { myRamLabels[row] = new StaticTextWidget(boss, lfont, xpos + 8, ypos + row*lineHeight + 2, 3*fontWidth, fontHeight, "", kTextAlignLeft); } ypos += 9 * lineHeight; // We need to define these widgets from right to left since the leftmost // one resizes as much as possible xpos = xpos_r - 13*fontWidth - 5; new StaticTextWidget(boss, lfont, xpos, ypos, 4*fontWidth, fontHeight, "Bin:", kTextAlignLeft); myBinValue = new EditTextWidget(boss, nfont, xpos + 4*fontWidth + 5, ypos-2, 9*fontWidth, lineHeight, ""); myBinValue->setEditable(false); xpos -= 8*fontWidth + 5 + 20; new StaticTextWidget(boss, lfont, xpos, ypos, 4*fontWidth, fontHeight, "Dec:", kTextAlignLeft); myDecValue = new EditTextWidget(boss, nfont, xpos + 4*fontWidth + 5, ypos-2, 4*fontWidth, lineHeight, ""); myDecValue->setEditable(false); xpos_r = xpos - 20; xpos = x + 10; new StaticTextWidget(boss, lfont, xpos, ypos, 6*fontWidth, fontHeight, "Label:", kTextAlignLeft); xpos += 6*fontWidth + 5; myLabel = new EditTextWidget(boss, nfont, xpos, ypos-2, xpos_r-xpos, lineHeight, ""); myLabel->setEditable(false); // Calculate real dimensions _w = lwidth + myRamGrid->getWidth(); _h = ypos + lineHeight - y; // Inputbox which will pop up when searching RAM StringList labels; labels.push_back("Search: "); myInputBox = new InputTextDialog(boss, lfont, nfont, labels); myInputBox->setTarget(this); // Start with these buttons disabled myCompareButton->clearFlags(WIDGET_ENABLED); myRestartButton->clearFlags(WIDGET_ENABLED); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RamWidget::~RamWidget() { delete myInputBox; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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, value; CartDebug& dbg = instance().debugger().cartDebug(); const CartState& state = (CartState&) dbg.getState(); switch(cmd) { case DataGridWidget::kItemDataChangedCmd: { addr = myRamGrid->getSelectedAddr(); value = myRamGrid->getSelectedValue(); // Attempt the write, and revert if it didn't succeed uInt8 oldval = dbg.peek(state.rport[addr]); dbg.poke(state.wport[addr], value); uInt8 newval = dbg.peek(state.rport[addr]); if(value != newval) { myRamGrid->setValue(addr - myCurrentRamBank*128, newval, false); break; } myUndoAddress = addr; myUndoValue = oldval; myDecValue->setText(Common::Base::toString(value, Common::Base::F_10)); myBinValue->setText(Common::Base::toString(value, Common::Base::F_2)); myRevertButton->setEnabled(true); myUndoButton->setEnabled(true); break; } case DataGridWidget::kSelectionChangedCmd: { addr = myRamGrid->getSelectedAddr(); value = myRamGrid->getSelectedValue(); myLabel->setText(dbg.getLabel(state.rport[addr], true)); myDecValue->setText(Common::Base::toString(value, Common::Base::F_10)); myBinValue->setText(Common::Base::toString(value, Common::Base::F_2)); break; } case kRevertCmd: for(uInt32 i = 0; i < myOldValueList.size(); ++i) dbg.poke(state.wport[i], myOldValueList[i]); fillGrid(true); break; case kUndoCmd: dbg.poke(state.wport[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 kSetPositionCmd: myCurrentRamBank = data; showSearchResults(); fillGrid(false); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RamWidget::setOpsWidget(DataGridOpsWidget* w) { myRamGrid->setOpsWidget(w); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RamWidget::loadConfig() { fillGrid(true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RamWidget::fillGrid(bool updateOld) { IntArray alist; IntArray vlist; BoolArray changed; if(updateOld) myOldValueList.clear(); CartDebug& dbg = instance().debugger().cartDebug(); const CartState& state = (CartState&) dbg.getState(); const CartState& oldstate = (CartState&) dbg.getOldState(); // Jump to the correct 128 byte 'window' in the RAM area // This assumes that the RAM areas are aligned on 128 byte boundaries // TODO - the boundary restriction may not always apply ... uInt32 start = myCurrentRamBank * 128; assert(start+128 <= state.ram.size()); if(updateOld) myOldValueList = state.ram; for(uInt32 i = start; i < start + 16*8; ++i) { alist.push_back(i); vlist.push_back(state.ram[i]); changed.push_back(state.ram[i] != oldstate.ram[i]); } myRamGrid->setNumRows(state.ram.size() / 128); myRamGrid->setList(alist, vlist, changed); if(updateOld) { myRevertButton->setEnabled(false); myUndoButton->setEnabled(false); } // Update RAM labels char buf[5]; BSPF_snprintf(buf, 5, "%04X", state.rport[start] & 0xff00); buf[2] = buf[3] = 'x'; myRamStart->setLabel(buf); for(uInt32 i = start, row = 0; i < start + 16*8; i += 16, ++row) { BSPF_snprintf(buf, 3, "%02X", state.rport[i] & 0x00ff); myRamLabels[row]->setLabel(buf); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 bool hitfound = false; CartDebug& dbg = instance().debugger().cartDebug(); const CartState& state = (CartState&) dbg.getState(); for(uInt32 addr = 0; addr < state.ram.size(); ++addr) { int value = state.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 ""; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string RamWidget::doCompare(const string& str) { bool comparitiveSearch = false; int searchVal = 0, offset = 0; if(str.length() == 0) return "Enter an absolute or comparitive 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 comparitive search searches memory for locations that have changed by // the specified amount, vs. for exact values if(str[0] == '+' || str[0] == '-') { comparitiveSearch = 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 bool hitfound = false; CartDebug& dbg = instance().debugger().cartDebug(); const CartState& state = (CartState&) dbg.getState(); IntArray tempAddrList, tempValueList; mySearchState.clear(); for(uInt32 i = 0; i < state.rport.size(); ++i) mySearchState.push_back(false); for(unsigned int i = 0; i < mySearchAddr.size(); ++i) { if(comparitiveSearch) { searchVal = mySearchValue[i] + offset; if(searchVal < 0 || searchVal > 255) continue; } int addr = mySearchAddr[i]; if(dbg.peek(state.rport[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 ""; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 * 128; if(mySearchState.size() == 0 || start > mySearchState.size()) { for(uInt32 i = 0; i < 128; ++i) temp.push_back(false); } else { for(uInt32 i = start; i < start + 128; ++i) temp.push_back(mySearchState[i]); } myRamGrid->setHiliteList(temp); } stella-3.9.3/src/debugger/gui/ColorWidget.cxx0000644000175000001440000000375312266336753020531 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ColorWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "Command.hxx" #include "FrameBuffer.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) { _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ColorWidget::~ColorWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ColorWidget::setColor(int color) { _color = color; setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ColorWidget::drawWidget(bool hilite) { FBSurface& s = dialog().surface(); // Draw a thin frame around us. 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); // Show the currently selected color s.fillRect(_x+1, _y+1, _w-2, _h-1, _color); } stella-3.9.3/src/debugger/gui/TiaWidget.cxx0000644000175000001440000007533512266336753020175 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TiaWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "ColorWidget.hxx" #include "DataGridWidget.hxx" #include "EditTextWidget.hxx" #include "FrameBuffer.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "CartDebug.hxx" #include "TIA.hxx" #include "TIADebug.hxx" #include "ToggleBitWidget.hxx" #include "TogglePixelWidget.hxx" #include "Widget.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(); int xpos = 10, ypos = 15 + lineHeight, lwidth = 4 * fontWidth; StaticTextWidget* t; // Color registers const char* regNames[] = { "COLUP0:", "COLUP1:", "COLUPF:", "COLUBK:" }; for(int row = 0; row < 4; ++row) { t = new StaticTextWidget(boss, lfont, xpos, ypos + row*lineHeight + 2, 7*fontWidth, fontHeight, regNames[row], kTextAlignLeft); } xpos += 7*fontWidth + 5; 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, 20, lineHeight - 4); myCOLUP0Color->setTarget(this); ypos += lineHeight; myCOLUP1Color = new ColorWidget(boss, nfont, xpos, ypos+2, 20, lineHeight - 4); myCOLUP1Color->setTarget(this); ypos += lineHeight; myCOLUPFColor = new ColorWidget(boss, nfont, xpos, ypos+2, 20, lineHeight - 4); myCOLUPFColor->setTarget(this); ypos += lineHeight; myCOLUBKColor = new ColorWidget(boss, nfont, xpos, ypos+2, 20, lineHeight - 4); myCOLUBKColor->setTarget(this); //////////////////////////// // Collision register bits //////////////////////////// // Add horizontal labels xpos += myCOLUBKColor->getWidth() + 2*fontWidth + 30; ypos -= 4*lineHeight + 5; t = new StaticTextWidget(boss, lfont, xpos, ypos, 14*fontWidth, fontHeight, "PF BL M1 M0 P1", kTextAlignLeft); // Add label for Strobes; buttons will be added later t = new StaticTextWidget(boss, lfont, xpos + t->getWidth() + 9*fontWidth, ypos, 8*fontWidth, fontHeight, "Strobes:", kTextAlignLeft); // Add vertical labels xpos -= 2*fontWidth + 5; ypos += lineHeight; const char* collLabel[] = { "P0", "P1", "M0", "M1", "BL" }; for(int row = 0; row < 5; ++row) { t = new StaticTextWidget(boss, lfont, xpos, ypos + row*(lineHeight+3), 2*fontWidth, fontHeight, collLabel[row], kTextAlignLeft); } // Finally, add all 15 collision bits xpos += 2 * fontWidth + 5; unsigned int collX = xpos, collY = ypos, idx = 0; for(unsigned int row = 0; row < 5; ++row) { for(unsigned int col = 0; col < 5 - row; ++col) { myCollision[idx] = new CheckboxWidget(boss, lfont, collX, collY, "", kCheckActionCmd); myCollision[idx]->setTarget(this); myCollision[idx]->setID(idx); // TODO - make collisions editable in TIA // myCollision[idx]->setEditable(false); // addFocusWidget(myCollision[idx]); //////////////////////////////////////////// collX += myCollision[idx]->getWidth() + 10; idx++; } collX = xpos; collY += lineHeight+3; } //////////////////////////// // Strobe buttons //////////////////////////// ButtonWidget* b; unsigned int buttonX, buttonY, buttonW; buttonX = collX + 20*fontWidth; buttonY = ypos; buttonW = 7 * fontWidth; b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight, "WSync", kWsyncCmd); b->setTarget(this); buttonY += lineHeight + 3; b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight, "ResP0", kResP0Cmd); b->setTarget(this); buttonY += lineHeight + 3; b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight, "ResM0", kResM0Cmd); b->setTarget(this); buttonY += lineHeight + 3; b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight, "ResBL", kResBLCmd); b->setTarget(this); buttonY += lineHeight + 3; b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight, "HmClr", kHmclrCmd); b->setTarget(this); buttonX += buttonW + 4; buttonY = ypos; b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight, "RSync", kRsyncCmd); b->setTarget(this); buttonY += lineHeight + 3; b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight, "ResP1", kResP1Cmd); b->setTarget(this); buttonY += lineHeight + 3; b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight, "ResM1", kResM1Cmd); b->setTarget(this); buttonY += lineHeight + 3; b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight, "HMove", kHmoveCmd); b->setTarget(this); buttonY += lineHeight + 3; b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight, "CxClr", kCxclrCmd); b->setTarget(this); //////////////////////////// // P0 register info //////////////////////////// // grP0 xpos = 10; ypos = buttonY + 2*lineHeight; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 7*fontWidth, fontHeight, "P0: GR:", kTextAlignLeft); xpos += 7*fontWidth + 5; myGRP0 = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 8, 1); myGRP0->setTarget(this); myGRP0->setID(kGRP0ID); addFocusWidget(myGRP0); // posP0 xpos += myGRP0->getWidth() + 8; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 6*fontWidth, fontHeight, "Pos: #", kTextAlignLeft); 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() + 8; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 3*fontWidth, fontHeight, "HM:", kTextAlignLeft); xpos += 3*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 and delay xpos += myHMP0->getWidth() + 15; myRefP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Reflect", kCheckActionCmd); myRefP0->setTarget(this); myRefP0->setID(kRefP0ID); addFocusWidget(myRefP0); xpos += myRefP0->getWidth() + 15; myDelP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Delay", kCheckActionCmd); myDelP0->setTarget(this); myDelP0->setID(kDelP0ID); addFocusWidget(myDelP0); // NUSIZ0 (player portion) xpos = 10 + lwidth; ypos += myGRP0->getHeight() + 5; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 8*fontWidth, fontHeight, "NusizP0:", kTextAlignLeft); xpos += 8*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, 23*fontWidth, lineHeight, ""); myNusizP0Text->setEditable(false); //////////////////////////// // P1 register info //////////////////////////// // grP1 xpos = 10; ypos += 2*lineHeight; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 7*fontWidth, fontHeight, "P1: GR:", kTextAlignLeft); xpos += 7*fontWidth + 5; myGRP1 = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 8, 1); myGRP1->setTarget(this); myGRP1->setID(kGRP1ID); addFocusWidget(myGRP1); // posP1 xpos += myGRP1->getWidth() + 8; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 6*fontWidth, fontHeight, "Pos: #", kTextAlignLeft); 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() + 8; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 3*fontWidth, fontHeight, "HM:", kTextAlignLeft); xpos += 3*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 and delay xpos += myHMP1->getWidth() + 15; myRefP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Reflect", kCheckActionCmd); myRefP1->setTarget(this); myRefP1->setID(kRefP1ID); addFocusWidget(myRefP1); xpos += myRefP1->getWidth() + 15; myDelP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Delay", kCheckActionCmd); myDelP1->setTarget(this); myDelP1->setID(kDelP1ID); addFocusWidget(myDelP1); // NUSIZ1 (player portion) xpos = 10 + lwidth; ypos += myGRP1->getHeight() + 5; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 8*fontWidth, fontHeight, "NusizP1:", kTextAlignLeft); xpos += 8*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, 23*fontWidth, lineHeight, ""); myNusizP1Text->setEditable(false); //////////////////////////// // M0 register info //////////////////////////// // enaM0 xpos = 10; ypos += 2*lineHeight; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 3*fontWidth, fontHeight, "M0:", kTextAlignLeft); xpos += 3*fontWidth + 8; myEnaM0 = new CheckboxWidget(boss, lfont, xpos, ypos+2, "Enable", kCheckActionCmd); myEnaM0->setTarget(this); myEnaM0->setID(kEnaM0ID); addFocusWidget(myEnaM0); // posM0 xpos += myEnaM0->getWidth() + 12; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 6*fontWidth, fontHeight, "Pos: #", kTextAlignLeft); 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() + 8; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 3*fontWidth, fontHeight, "HM:", kTextAlignLeft); xpos += 3*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() + 8; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 5*fontWidth, fontHeight, "Size:", kTextAlignLeft); xpos += 5*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 xpos += myNusizM0->getWidth() + 15; myResMP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Reset", kCheckActionCmd); myResMP0->setTarget(this); myResMP0->setID(kResMP0ID); addFocusWidget(myResMP0); //////////////////////////// // M1 register info //////////////////////////// // enaM1 xpos = 10; ypos += lineHeight + 6; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 3*fontWidth, fontHeight, "M1:", kTextAlignLeft); xpos += 3*fontWidth + 8; myEnaM1 = new CheckboxWidget(boss, lfont, xpos, ypos+2, "Enable", kCheckActionCmd); myEnaM1->setTarget(this); myEnaM1->setID(kEnaM1ID); addFocusWidget(myEnaM1); // posM0 xpos += myEnaM1->getWidth() + 12; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 6*fontWidth, fontHeight, "Pos: #", kTextAlignLeft); 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() + 8; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 3*fontWidth, fontHeight, "HM:", kTextAlignLeft); xpos += 3*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() + 8; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 5*fontWidth, fontHeight, "Size:", kTextAlignLeft); xpos += 5*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 xpos += myNusizM1->getWidth() + 15; myResMP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Reset", kCheckActionCmd); myResMP1->setTarget(this); myResMP1->setID(kResMP1ID); addFocusWidget(myResMP1); //////////////////////////// // BL register info //////////////////////////// // enaBL xpos = 10; ypos += lineHeight + 6; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 3*fontWidth, fontHeight, "BL:", kTextAlignLeft); xpos += 3*fontWidth + 8; myEnaBL = new CheckboxWidget(boss, lfont, xpos, ypos+2, "Enable", kCheckActionCmd); myEnaBL->setTarget(this); myEnaBL->setID(kEnaBLID); addFocusWidget(myEnaBL); // posBL xpos += myEnaBL->getWidth() + 12; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 6*fontWidth, fontHeight, "Pos: #", kTextAlignLeft); 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() + 8; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 3*fontWidth, fontHeight, "HM:", kTextAlignLeft); xpos += 3*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() + 8; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 5*fontWidth, fontHeight, "Size:", kTextAlignLeft); xpos += 5*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); // BL delay xpos += mySizeBL->getWidth() + 15; myDelBL = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Delay", kCheckActionCmd); myDelBL->setTarget(this); myDelBL->setID(kDelBLID); addFocusWidget(myDelBL); //////////////////////////// // PF 0/1/2 registers //////////////////////////// // PF0 xpos = 10; ypos += lineHeight + 6; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight, "PF:", kTextAlignLeft); xpos += 4*fontWidth; 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]); // PF reflect, score, priority xpos = 10 + 4*fontWidth; ypos += lineHeight + 6; myRefPF = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Reflect", kCheckActionCmd); myRefPF->setTarget(this); myRefPF->setID(kRefPFID); addFocusWidget(myRefPF); xpos += myRefPF->getWidth() + 15; myScorePF = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Score", kCheckActionCmd); myScorePF->setTarget(this); myScorePF->setID(kScorePFID); addFocusWidget(myScorePF); xpos += myScorePF->getWidth() + 15; myPriorityPF = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Priority", kCheckActionCmd); myPriorityPF->setTarget(this); myPriorityPF->setID(kPriorityPFID); addFocusWidget(myPriorityPF); // How to handle undriven pins xpos = 10; ypos += 2*lineHeight; myUndrivenPins = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Drive unused TIA pins randomly on a read/peek", kPPinCmd); myUndrivenPins->setTarget(this); addFocusWidget(myUndrivenPins); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TiaWidget::~TiaWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 kPPinCmd: tia.tia().driveUnusedPinsRandom(myUndrivenPins->getState()); 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 kGRP1ID: tia.grP1(myGRP1->getIntState()); 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 kCheckActionCmd: switch(id) { case kP0_PFID: tia.collP0_PF(myCollision[kP0_PFID]->getState() ? 1 : 0); break; case kP0_BLID: tia.collP0_BL(myCollision[kP0_BLID]->getState() ? 1 : 0); break; case kP0_M1ID: tia.collM1_P0(myCollision[kP0_M1ID]->getState() ? 1 : 0); break; case kP0_M0ID: tia.collM0_P0(myCollision[kP0_M0ID]->getState() ? 1 : 0); break; case kP0_P1ID: tia.collP0_P1(myCollision[kP0_P1ID]->getState() ? 1 : 0); break; case kP1_PFID: tia.collP1_PF(myCollision[kP1_PFID]->getState() ? 1 : 0); break; case kP1_BLID: tia.collP1_BL(myCollision[kP1_BLID]->getState() ? 1 : 0); break; case kP1_M1ID: tia.collM1_P1(myCollision[kP1_M1ID]->getState() ? 1 : 0); break; case kP1_M0ID: tia.collM0_P1(myCollision[kP1_M0ID]->getState() ? 1 : 0); break; case kM0_PFID: tia.collM0_PF(myCollision[kM0_PFID]->getState() ? 1 : 0); break; case kM0_BLID: tia.collM0_BL(myCollision[kM0_BLID]->getState() ? 1 : 0); break; case kM0_M1ID: tia.collM0_M1(myCollision[kM0_M1ID]->getState() ? 1 : 0); break; case kM1_PFID: tia.collM1_PF(myCollision[kM1_PFID]->getState() ? 1 : 0); break; case kM1_BLID: tia.collM1_BL(myCollision[kM1_BLID]->getState() ? 1 : 0); break; case kBL_PFID: tia.collBL_PF(myCollision[kBL_PFID]->getState() ? 1 : 0); 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(); TiaState& state = (TiaState&) tia.getState(); TiaState& oldstate = (TiaState&) tia.getOldState(); // Color registers alist.clear(); vlist.clear(); changed.clear(); for(unsigned int 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); myCOLUP0Color->setColor(state.coluRegs[0]); myCOLUP1Color->setColor(state.coluRegs[1]); myCOLUPFColor->setColor(state.coluRegs[2]); myCOLUBKColor->setColor(state.coluRegs[3]); //////////////////////////// // Collision register bits //////////////////////////// myCollision[kP0_PFID]->setState(tia.collP0_PF()); myCollision[kP0_BLID]->setState(tia.collP0_BL()); myCollision[kP0_M1ID]->setState(tia.collM1_P0()); myCollision[kP0_M0ID]->setState(tia.collM0_P0()); myCollision[kP0_P1ID]->setState(tia.collP0_P1()); myCollision[kP1_PFID]->setState(tia.collP1_PF()); myCollision[kP1_BLID]->setState(tia.collP1_BL()); myCollision[kP1_M1ID]->setState(tia.collM1_P1()); myCollision[kP1_M0ID]->setState(tia.collM0_P1()); myCollision[kM0_PFID]->setState(tia.collM0_PF()); myCollision[kM0_BLID]->setState(tia.collM0_BL()); myCollision[kM0_M1ID]->setState(tia.collM0_M1()); myCollision[kM1_PFID]->setState(tia.collM1_PF()); myCollision[kM1_BLID]->setState(tia.collM1_BL()); myCollision[kBL_PFID]->setState(tia.collBL_PF()); //////////////////////////// // P0 register info //////////////////////////// // grP0 myGRP0->setColor(state.coluRegs[0]); myGRP0->setBackgroundColor(-1); myGRP0->setIntState(state.gr[P0], 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()); myDelP0->setState(tia.vdelP0()); // 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 myGRP1->setColor(state.coluRegs[1]); myGRP1->setBackgroundColor(tia.priorityPF() ? state.coluRegs[3] : -1); myGRP1->setIntState(state.gr[P1], 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()); myDelP1->setState(tia.vdelP1()); // 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->setState(tia.enaM0()); // 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()); //////////////////////////// // M1 register info //////////////////////////// // enaM1 myEnaM1->setState(tia.enaM1()); // 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()); //////////////////////////// // BL register info //////////////////////////// // enaBL myEnaBL->setState(tia.enaBL()); // 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()); //////////////////////////// // PF register info //////////////////////////// int pfx_bgcolor = !tia.priorityPF() ? state.coluRegs[3] : -1; // PF0 myPF[0]->setColor(state.coluRegs[2]); myPF[0]->setBackgroundColor(pfx_bgcolor); myPF[0]->setIntState(state.pf[0], true); // reverse bit order // PF1 myPF[1]->setColor(state.coluRegs[2]); myPF[1]->setBackgroundColor(pfx_bgcolor); myPF[1]->setIntState(state.pf[1], false); // PF2 myPF[2]->setColor(state.coluRegs[2]); myPF[2]->setBackgroundColor(pfx_bgcolor); myPF[2]->setIntState(state.pf[2], true); // reverse bit order // Reflect myRefPF->setState(tia.refPF()); // Score myScorePF->setState(tia.scorePF()); // Priority myPriorityPF->setState(tia.priorityPF()); // Undriven pins myUndrivenPins->setState(tia.tia().driveUnusedPinsRandom()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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-3.9.3/src/debugger/gui/Cart0840Widget.hxx0000644000175000001440000000267412266336753020666 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart0840Widget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: Cartridge0840& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/DataGridOpsWidget.hxx0000644000175000001440000000312312266336753021610 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DataGridOpsWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() {} void setTarget(CommandReceiver* target); void setEnabled(bool e); private: ButtonWidget* _zeroButton; ButtonWidget* _invButton; ButtonWidget* _negButton; ButtonWidget* _incButton; ButtonWidget* _decButton; ButtonWidget* _shiftLeftButton; ButtonWidget* _shiftRightButton; }; #endif stella-3.9.3/src/debugger/gui/CartBFWidget.hxx0000644000175000001440000000264412266336753020557 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartBFWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeBF& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/AudioWidget.hxx0000644000175000001440000000277312266336753020522 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: AudioWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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(); 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 }; void handleCommand(CommandSender* sender, int cmd, int data, int id); void loadConfig(); private: DataGridWidget* myAudF; DataGridWidget* myAudC; DataGridWidget* myAudV; }; #endif stella-3.9.3/src/debugger/gui/CartFEWidget.cxx0000644000175000001440000000354512266336753020556 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartFEWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "CartFE.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" "Doesn't support bankswitching with hotspots, " "but instead watches A13 of called addresses:\n" "Bank 0 @ $F000 - $FFFF (A13 = 1)\n" "Bank 1 @ $D000 - $DFFF (A13 = 0)\n" "\n" "Changing banks is not currently supported, since it " "would immediately switch on the next address change\n"; addBaseInformation(2 * 4096, "Activision", info); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeFEWidget::bankState() { ostringstream& buf = buffer(); static const char* range[] = { "$F000", "$D000" }; buf << "Bank = " << dec << myCart.bank() << ", address range = " << range[myCart.bank()]; return buf.str(); } stella-3.9.3/src/debugger/gui/CartDFWidget.cxx0000644000175000001440000001031312266336753020544 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDFWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 " << dec << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << " (hotspot = $" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "CPUWIZ", info.str()) + myLineHeight; VariantList items; items.push_back(" 0 ($FC0)"); items.push_back(" 1 ($FC1)"); items.push_back(" 2 ($FC2)"); items.push_back(" 3 ($FC3)"); items.push_back(" 4 ($FC4)"); items.push_back(" 5 ($FC5)"); items.push_back(" 6 ($FC6)"); items.push_back(" 7 ($FC7)"); items.push_back(" 8 ($FC8)"); items.push_back(" 9 ($FC9)"); items.push_back("10 ($FCA)"); items.push_back("11 ($FCB)"); items.push_back("12 ($FCC)"); items.push_back("13 ($FCD)"); items.push_back("14 ($FCE)"); items.push_back("15 ($FCF)"); items.push_back("16 ($FD0)"); items.push_back("17 ($FD1)"); items.push_back("18 ($FD2)"); items.push_back("19 ($FD3)"); items.push_back("20 ($FD4)"); items.push_back("21 ($FD5)"); items.push_back("22 ($FD6)"); items.push_back("23 ($FD7)"); items.push_back("24 ($FD8)"); items.push_back("25 ($FD9)"); items.push_back("26 ($FDA)"); items.push_back("27 ($FDB)"); items.push_back("28 ($FDC)"); items.push_back("29 ($FDD)"); items.push_back("30 ($FDE)"); items.push_back("31 ($FDF)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("31 ($FDF) "), myLineHeight, items, "Set bank: ", _font.getStringWidth("Set bank: "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDFWidget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$FC0", "$FC1", "$FC2", "$FC3", "$FC4", "$FC5", "$FC6", "$FC7", "$FC8", "$FC9", "$FCA", "$FCB", "$FCC", "$FCD", "$FCE", "$FCF", "$FD0", "$FD1", "$FD2", "$FD3", "$FD4", "$FD5", "$FD6", "$FD7", "$FD8", "$FD9", "$FDA", "$FDB", "$FDC", "$FDD", "$FDE", "$FDF" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/GenesisWidget.hxx0000644000175000001440000000254212266336753021050 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: GenesisWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef GENESIS_WIDGET_HXX #define GENESIS_WIDGET_HXX #include "Control.hxx" #include "Event.hxx" #include "ControllerWidget.hxx" class GenesisWidget : public ControllerWidget { public: GenesisWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~GenesisWidget(); void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); private: enum { kJUp = 0, kJDown, kJLeft, kJRight, kJBbtn, kJCbtn }; CheckboxWidget* myPins[6]; static Controller::DigitalPin ourPinNo[5]; }; #endif stella-3.9.3/src/debugger/gui/CartFAWidget.cxx0000644000175000001440000000622412266336753020547 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartFAWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 << "\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 = $" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "CBS", info.str()) + myLineHeight; VariantList items; items.push_back("0 ($FF8)"); items.push_back("1 ($FF9)"); items.push_back("2 ($FFA)"); 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 CartridgeFAWidget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$FF8", "$FF9", "$FFA" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/TiaInfoWidget.hxx0000644000175000001440000000313612266336753021004 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TiaInfoWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef TIA_INFO_WIDGET_HXX #define TIA_INFO_WIDGET_HXX class GuiObject; class EditTextWidget; #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(); void loadConfig(); protected: void handleMouseDown(int x, int y, int button, int clickCount); void handleCommand(CommandSender* sender, int cmd, int data, int id); private: EditTextWidget* myFrameCount; EditTextWidget* myFrameCycles; EditTextWidget* myScanlineCount; EditTextWidget* myScanlineCycles; EditTextWidget* myPixelPosition; EditTextWidget* myColorClocks; CheckboxWidget* myVSync; CheckboxWidget* myVBlank; }; #endif stella-3.9.3/src/debugger/gui/CartX07Widget.hxx0000644000175000001440000000266012266336753020644 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartX07Widget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeX07& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/Cart4KWidget.hxx0000644000175000001440000000251512266336753020543 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart4KWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } // No implementation for non-bankswitched ROMs void loadConfig() { } void handleCommand(CommandSender* sender, int cmd, int data, int id) { } }; #endif stella-3.9.3/src/debugger/gui/CpuWidget.hxx0000644000175000001440000000401112266336753020173 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CpuWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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(); void setOpsWidget(DataGridOpsWidget* w); void loadConfig(); private: void handleCommand(CommandSender* sender, int cmd, int data, int id); 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 }; 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; }; #endif stella-3.9.3/src/debugger/gui/CartBFSCWidget.hxx0000644000175000001440000000267412266336753021010 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartBFSCWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeBFSC& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/CartF8Widget.hxx0000644000175000001440000000264412266336753020545 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF8Widget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeF8& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/CartF6Widget.hxx0000644000175000001440000000264412266336753020543 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF6Widget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeF6& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/CartDFSCWidget.cxx0000644000175000001440000001051012266336753020771 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDFSCWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 " << dec << i << " @ $" << Common::Base::HEX4 << (start + 0x100) << " - " << "$" << (start + 0xFFF) << " (hotspot = $" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "CPUWIZ", info.str()) + myLineHeight; VariantList items; items.push_back(" 0 ($FC0)"); items.push_back(" 1 ($FC1)"); items.push_back(" 2 ($FC2)"); items.push_back(" 3 ($FC3)"); items.push_back(" 4 ($FC4)"); items.push_back(" 5 ($FC5)"); items.push_back(" 6 ($FC6)"); items.push_back(" 7 ($FC7)"); items.push_back(" 8 ($FC8)"); items.push_back(" 9 ($FC9)"); items.push_back("10 ($FCA)"); items.push_back("11 ($FCB)"); items.push_back("12 ($FCC)"); items.push_back("13 ($FCD)"); items.push_back("14 ($FCE)"); items.push_back("15 ($FCF)"); items.push_back("16 ($FD0)"); items.push_back("17 ($FD1)"); items.push_back("18 ($FD2)"); items.push_back("19 ($FD3)"); items.push_back("20 ($FD4)"); items.push_back("21 ($FD5)"); items.push_back("22 ($FD6)"); items.push_back("23 ($FD7)"); items.push_back("24 ($FD8)"); items.push_back("25 ($FD9)"); items.push_back("26 ($FDA)"); items.push_back("27 ($FDB)"); items.push_back("28 ($FDC)"); items.push_back("29 ($FDD)"); items.push_back("30 ($FDE)"); items.push_back("31 ($FDF)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("31 ($FE0) "), myLineHeight, items, "Set bank: ", _font.getStringWidth("Set bank: "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDFSCWidget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$FC0", "$FC1", "$FC2", "$FC3", "$FC4", "$FC5", "$FC6", "$FC7", "$FC8", "$FC9", "$FCA", "$FCB", "$FCC", "$FCD", "$FCE", "$FCF", "$FD0", "$FD1", "$FD2", "$FD3", "$FD4", "$FD5", "$FD6", "$FE7", "$FD8", "$FD9", "$FDA", "$FDB", "$FDC", "$FDD", "$FDE", "$FDF" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/Cart4A50Widget.hxx0000644000175000001440000000333212266336753020674 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart4A50Widget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); 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' }; }; #endif stella-3.9.3/src/debugger/gui/CartF4Widget.hxx0000644000175000001440000000264412266336753020541 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF4Widget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeF4& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/CartCVWidget.hxx0000644000175000001440000000251512266336753020575 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartCVWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } // No implementation for non-bankswitched ROMs void loadConfig() { } void handleCommand(CommandSender* sender, int cmd, int data, int id) { } }; #endif stella-3.9.3/src/debugger/gui/module.mk0000644000175000001440000000434712266246257017400 0ustar stephenusersMODULE := src/debugger/gui MODULE_OBJS := \ src/debugger/gui/AudioWidget.o \ src/debugger/gui/CpuWidget.o \ src/debugger/gui/PromptWidget.o \ src/debugger/gui/RamWidget.o \ src/debugger/gui/RiotWidget.o \ src/debugger/gui/RomWidget.o \ src/debugger/gui/RomListWidget.o \ src/debugger/gui/RomListSettings.o \ src/debugger/gui/TiaWidget.o \ src/debugger/gui/TiaInfoWidget.o \ src/debugger/gui/TiaOutputWidget.o \ src/debugger/gui/TiaZoomWidget.o \ src/debugger/gui/ColorWidget.o \ src/debugger/gui/DataGridOpsWidget.o \ src/debugger/gui/DataGridWidget.o \ src/debugger/gui/DebuggerDialog.o \ src/debugger/gui/ToggleBitWidget.o \ src/debugger/gui/TogglePixelWidget.o \ src/debugger/gui/ToggleWidget.o \ src/debugger/gui/Cart0840Widget.o \ src/debugger/gui/Cart2KWidget.o \ src/debugger/gui/Cart3EWidget.o \ src/debugger/gui/Cart3FWidget.o \ src/debugger/gui/Cart4A50Widget.o \ src/debugger/gui/Cart4KWidget.o \ src/debugger/gui/Cart4KSCWidget.o \ src/debugger/gui/CartARWidget.o \ src/debugger/gui/CartCMWidget.o \ src/debugger/gui/CartCTYWidget.o \ src/debugger/gui/CartCVWidget.o \ src/debugger/gui/CartDPCWidget.o \ src/debugger/gui/CartDPCPlusWidget.o \ src/debugger/gui/CartE0Widget.o \ src/debugger/gui/CartE7Widget.o \ src/debugger/gui/CartEFWidget.o \ src/debugger/gui/CartEFSCWidget.o \ src/debugger/gui/CartBFWidget.o \ src/debugger/gui/CartBFSCWidget.o \ src/debugger/gui/CartDFWidget.o \ src/debugger/gui/CartDFSCWidget.o \ src/debugger/gui/CartF0Widget.o \ src/debugger/gui/CartF4Widget.o \ src/debugger/gui/CartF6Widget.o \ src/debugger/gui/CartF8Widget.o \ src/debugger/gui/CartF4SCWidget.o \ src/debugger/gui/CartF6SCWidget.o \ src/debugger/gui/CartF8SCWidget.o \ src/debugger/gui/CartFAWidget.o \ src/debugger/gui/CartFA2Widget.o \ src/debugger/gui/CartFEWidget.o \ src/debugger/gui/CartMCWidget.o \ src/debugger/gui/CartSBWidget.o \ src/debugger/gui/CartUAWidget.o \ src/debugger/gui/CartX07Widget.o \ src/debugger/gui/JoystickWidget.o \ src/debugger/gui/PaddleWidget.o \ src/debugger/gui/BoosterWidget.o \ src/debugger/gui/DrivingWidget.o \ src/debugger/gui/KeyboardWidget.o \ src/debugger/gui/GenesisWidget.o MODULE_DIRS += \ src/debugger/gui # Include common rules include $(srcdir)/common.rules stella-3.9.3/src/debugger/gui/PromptWidget.hxx0000644000175000001440000000633712266336753020742 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: PromptWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef PROMPT_WIDGET_HXX #define PROMPT_WIDGET_HXX #include class ScrollBarWidget; #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(); public: int printf(const char *format, ...); int vprintf(const char *format, va_list argptr); #undef putchar void putchar(int c); void print(const string& str); void printPrompt(); bool saveBuffer(string& filename); // Clear screen and erase all history void clearScreen(); protected: int& buffer(int idx) { return _buffer[idx % kBufferSize]; } void drawWidget(bool hilite); void drawCaret(); void putcharIntern(int c); void insertIntoPrompt(const char *str); void updateScrollBuffer(); void scrollToCurrent(); // Line editing void specialKeys(int keycode); void nextLine(); void killChar(int direction); void killLine(int direction); void killLastWord(); // History void addToHistory(const char *str); void historyScroll(int direction); void handleMouseDown(int x, int y, int button, int clickCount); void handleMouseWheel(int x, int y, int direction); bool handleKeyDown(StellaKey key, StellaMod mod, char ascii); void handleCommand(CommandSender* sender, int cmd, int data, int id); // Account for the extra width of embedded scrollbar virtual int getWidth() const; virtual bool wantsFocus() { return true; } void loadConfig(); private: // Get the longest prefix (initially 's') that is in every string in the list string getCompletionPrefix(const StringList& completions, string s); 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); }; #endif stella-3.9.3/src/debugger/gui/Cart2KWidget.cxx0000644000175000001440000000300512266336753020527 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart2KWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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-3.9.3/src/debugger/gui/CartUAWidget.hxx0000644000175000001440000000264412266336753020575 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartUAWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeUA& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/CartF0Widget.hxx0000644000175000001440000000264412266336753020535 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF0Widget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeF0& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/CartSBWidget.hxx0000644000175000001440000000264412266336753020574 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartSBWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeSB& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/CartF8SCWidget.hxx0000644000175000001440000000267412266336753020776 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF8SCWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeF8SC& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/CartF6SCWidget.hxx0000644000175000001440000000267412266336753020774 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF6SCWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeF6SC& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/CartMCWidget.hxx0000644000175000001440000000306012266336753020560 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartMCWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CARTRIDGEMC_WIDGET_HXX #define CARTRIDGEMC_WIDGET_HXX class CartridgeMC; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeMCWidget : public CartDebugWidget { public: CartridgeMCWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeMC& cart); virtual ~CartridgeMCWidget() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeMC& myCart; PopUpWidget *mySlice0, *mySlice1, *mySlice2, *mySlice3; enum { kSlice0Changed = 's0CH', kSlice1Changed = 's1CH', kSlice2Changed = 's2CH', kSlice3Changed = 's3CH' }; }; #endif stella-3.9.3/src/debugger/gui/Cart4KSCWidget.cxx0000644000175000001440000000315212266336753020762 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart4KSCWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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) { // 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()); } stella-3.9.3/src/debugger/gui/CartF4SCWidget.hxx0000644000175000001440000000267412266336753020772 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF4SCWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeF4SC& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/CartARWidget.cxx0000644000175000001440000000640512266336753020564 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartARWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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; items.push_back(" 0"); items.push_back(" 1"); items.push_back(" 2"); items.push_back(" 3"); items.push_back(" 4"); items.push_back(" 5"); items.push_back(" 6"); items.push_back(" 7"); items.push_back(" 8"); items.push_back(" 9"); items.push_back(" 10"); items.push_back(" 11"); items.push_back(" 12"); items.push_back(" 13"); items.push_back(" 14"); items.push_back(" 15"); items.push_back(" 16"); items.push_back(" 17"); items.push_back(" 18"); items.push_back(" 19"); items.push_back(" 20"); items.push_back(" 21"); items.push_back(" 22"); items.push_back(" 23"); items.push_back(" 24"); items.push_back(" 25"); items.push_back(" 26"); items.push_back(" 27"); items.push_back(" 28"); items.push_back(" 29"); items.push_back(" 30"); items.push_back(" 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() { myBank->setSelectedIndex(myCart.myCurrentBank); 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 = " << dec << myCart.myCurrentBank; return buf.str(); } stella-3.9.3/src/debugger/gui/CartCMWidget.cxx0000644000175000001440000001671412266336753020565 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartCMWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "CartCM.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; items.push_back(" 0 "); items.push_back(" 1 "); items.push_back(" 2 "); items.push_back(" 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: ", kTextAlignLeft); 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: ", kTextAlignLeft); 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: ", kTextAlignLeft); myRAM = new EditTextWidget(boss, _nfont, xpos+lwidth, ypos-1, _nfont.getStringWidth(" Write-only "), myLineHeight, ""); myRAM->setEditable(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCMWidget::saveOldState() { myOldState.swcha = myCart.mySWCHA; myOldState.column = myCart.myColumn; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCMWidget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); RiotDebug& riot = Debugger::debugger().riotDebug(); const RiotState& state = (RiotState&) 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.myColumn, myCart.myColumn != 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 = " << dec << myCart.myCurrentBank << ", RAM is" << (myCart.mySWCHA & 0x10 ? " Inactive" : myCart.mySWCHA & 0x20 ? " Read-only" : " Write-only"); return buf.str(); } stella-3.9.3/src/debugger/gui/CartCTYWidget.cxx0000644000175000001440000000564212266336753020723 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartCTYWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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; items.push_back("1 ($FF5)"); items.push_back("2 ($FF6)"); items.push_back("3 ($FF7)"); items.push_back("4 ($FF8)"); items.push_back("5 ($FF9)"); items.push_back("6 ($FFA)"); items.push_back("7 ($FFB)"); 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 CartridgeCTYWidget::loadConfig() { myBank->setSelectedIndex(myCart.bank()-1); 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* spot[] = { "", "$FF5", "$FF6", "$FF7", "$FF8", "$FF9", "$FFA", "$FFB" }; uInt16 bank = myCart.bank(); buf << "Bank = " << dec << bank << ", hotspot = " << spot[bank]; return buf.str(); } stella-3.9.3/src/debugger/gui/RomListSettings.cxx0000644000175000001440000001365412266336753021422 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RomListSettings.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #include "FrameBuffer.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(), 0, 0, 16, 16), CommandSender(boss), _xorig(0), _yorig(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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RomListSettings::~RomListSettings() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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().setPos(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, int button, 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, button, 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-3.9.3/src/debugger/gui/DebuggerDialog.hxx0000644000175000001440000000704612266336753021157 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DebuggerDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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; #include "Dialog.hxx" #include "MessageBox.hxx" #include "Rect.hxx" class DebuggerDialog : public Dialog { public: enum { kSmallFontMinW = 1080, kSmallFontMinH = 720, kMediumFontMinW = 1280, kMediumFontMinH = 860, kLargeFontMinW = 1300, kLargeFontMinH = 940 }; DebuggerDialog(OSystem* osystem, DialogContainer* parent, int x, int y, int w, int h); ~DebuggerDialog(); 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; } EditTextWidget& message() const { return *myMessageBox; } ButtonWidget& rewindButton() const { return *myRewindButton; } void showFatalMessage(const string& msg); private: void loadConfig(); void handleKeyDown(StellaKey key, StellaMod mod, char ascii); void handleCommand(CommandSender* sender, int cmd, int data, int id); void doStep(); void doTrace(); void doScanlineAdvance(); void doAdvance(); void doRewind(); 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', kDDExitCmd = 'DDex', kDDExitFatalCmd = 'DDer' }; TabWidget *myTab, *myRomTab; GUI::Font* myLFont; // used for labels GUI::Font* myNFont; // used for normal text PromptWidget* myPrompt; TiaInfoWidget* myTiaInfo; TiaOutputWidget* myTiaOutput; TiaZoomWidget* myTiaZoom; CpuWidget* myCpu; RamWidget* myRam; RomWidget* myRom; CartDebugWidget* myCartDebug; EditTextWidget* myMessageBox; ButtonWidget* myRewindButton; GUI::MessageBox* myFatalError; }; #endif stella-3.9.3/src/debugger/gui/CartEFWidget.cxx0000644000175000001440000000720412266336753020552 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartEFWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 " << dec << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << " (hotspot = $" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Paul Slocum / Homestar Runner", info.str()) + myLineHeight; VariantList items; items.push_back(" 0 ($FE0)"); items.push_back(" 1 ($FE1)"); items.push_back(" 2 ($FE2)"); items.push_back(" 3 ($FE3)"); items.push_back(" 4 ($FE4)"); items.push_back(" 5 ($FE5)"); items.push_back(" 6 ($FE6)"); items.push_back(" 7 ($FE7)"); items.push_back(" 8 ($FE8)"); items.push_back(" 9 ($FE9)"); items.push_back("10 ($FEA)"); items.push_back("11 ($FEB)"); items.push_back("12 ($FEC)"); items.push_back("13 ($FED)"); items.push_back("14 ($FEE)"); items.push_back("15 ($FEF)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("15 ($FE0) "), myLineHeight, items, "Set bank: ", _font.getStringWidth("Set bank: "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEFWidget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$FE0", "$FE1", "$FE2", "$FE3", "$FE4", "$FE5", "$FE6", "$FE7", "$FE8", "$FE9", "$FEA", "$FEB", "$FEC", "$FED", "$FEE", "$FEF" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/DrivingWidget.cxx0000644000175000001440000000772112266336753021054 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DrivingWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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), myGreyIndex(0) { bool leftport = myController.jack() == Controller::Left; const string& label = leftport ? "Left (Driving):" : "Right (Driving):"; const int fontHeight = font.getFontHeight(), bwidth = font.getStringWidth("Grey 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, kTextAlignLeft); ypos += t->getHeight() + 20; myGreyUp = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight, "Grey code +", kGreyUpCmd); myGreyUp->setTarget(this); ypos += myGreyUp->getHeight() + 5; myGreyDown = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight, "Grey code -", kGreyDownCmd); myGreyDown->setTarget(this); xpos += myGreyDown->getWidth() + 10; ypos -= 10; myGreyValue = new DataGridWidget(boss, font, xpos, ypos, 1, 1, 2, 8, Common::Base::F_16); myGreyValue->setTarget(this); myGreyValue->setEditable(false); xpos = x + 30; ypos += myGreyDown->getHeight() + 20; myFire = new CheckboxWidget(boss, font, xpos, ypos, "Fire", kFireCmd); myFire->setTarget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DrivingWidget::~DrivingWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DrivingWidget::loadConfig() { uInt8 grey = 0; if(myController.read(Controller::One)) grey += 1; if(myController.read(Controller::Two)) grey += 2; for(myGreyIndex = 0; myGreyIndex < 4; ++myGreyIndex) if(ourGreyTable[myGreyIndex] == grey) break; myFire->setState(!myController.read(Controller::Six)); myGreyValue->setList(0, grey); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DrivingWidget::handleCommand( CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case kGreyUpCmd: myGreyIndex = (myGreyIndex + 1) % 4; myController.set(Controller::One, (ourGreyTable[myGreyIndex] & 0x1) != 0); myController.set(Controller::Two, (ourGreyTable[myGreyIndex] & 0x2) != 0); myGreyValue->setList(0, ourGreyTable[myGreyIndex]); break; case kGreyDownCmd: myGreyIndex = myGreyIndex == 0 ? 3 : myGreyIndex - 1; myController.set(Controller::One, (ourGreyTable[myGreyIndex] & 0x1) != 0); myController.set(Controller::Two, (ourGreyTable[myGreyIndex] & 0x2) != 0); myGreyValue->setList(0, ourGreyTable[myGreyIndex]); break; case kFireCmd: myController.set(Controller::Six, !myFire->getState()); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 DrivingWidget::ourGreyTable[4] = { 0x03, 0x01, 0x00, 0x02 }; stella-3.9.3/src/debugger/gui/KeyboardWidget.cxx0000644000175000001440000000656412266336753021216 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: KeyboardWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #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 = myController.jack() == Controller::Left; 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, kTextAlignLeft); xpos += 30; ypos += t->getHeight() + 20; for(int i = 0; i < 12; ++i) { myBox[i] = new CheckboxWidget(boss, font, xpos, ypos, "", 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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - KeyboardWidget::~KeyboardWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 == 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-3.9.3/src/debugger/gui/CartEFSCWidget.hxx0000644000175000001440000000267412266336753021013 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartEFSCWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeEFSC& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/JoystickWidget.cxx0000644000175000001440000000716212266336753021250 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: JoystickWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #include "EventHandler.hxx" #include "JoystickWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - JoystickWidget::JoystickWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : ControllerWidget(boss, font, x, y, controller) { bool leftport = myController.jack() == Controller::Left; const string& label = leftport ? "Left (Joystick):" : "Right (Joystick):"; 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, kTextAlignLeft); xpos += t->getWidth()/2 - 5; ypos += t->getHeight() + 20; myPins[kJUp] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd); myPins[kJUp]->setID(kJUp); myPins[kJUp]->setTarget(this); ypos += myPins[kJUp]->getHeight() * 2 + 10; myPins[kJDown] = new CheckboxWidget(boss, font, xpos, ypos, "", 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, "", kCheckActionCmd); myPins[kJLeft]->setID(kJLeft); myPins[kJLeft]->setTarget(this); xpos += (myPins[kJUp]->getWidth() + 5) * 2; myPins[kJRight] = new CheckboxWidget(boss, font, xpos, ypos, "", 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", kCheckActionCmd); myPins[kJFire]->setID(kJFire); myPins[kJFire]->setTarget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - JoystickWidget::~JoystickWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 == kCheckActionCmd) myController.set(ourPinNo[id], !myPins[id]->getState()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Controller::DigitalPin JoystickWidget::ourPinNo[5] = { Controller::One, Controller::Two, Controller::Three, Controller::Four, Controller::Six }; stella-3.9.3/src/debugger/gui/PaddleWidget.hxx0000644000175000001440000000261712266336753020647 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: PaddleWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef PADDLE_WIDGET_HXX #define PADDLE_WIDGET_HXX #include "Control.hxx" #include "Event.hxx" #include "ControllerWidget.hxx" class PaddleWidget : public ControllerWidget { public: PaddleWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~PaddleWidget(); void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); private: enum { kP0Changed = 'P0ch', kP1Changed = 'P1ch', kP0Fire = 'P0fr', kP1Fire = 'P1fr' }; SliderWidget *myP0Resistance, *myP1Resistance; CheckboxWidget *myP0Fire, *myP1Fire; }; #endif stella-3.9.3/src/debugger/gui/RomListWidget.hxx0000644000175000001440000000730212266336753021043 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RomListWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef ROM_LIST_WIDGET_HXX #define ROM_LIST_WIDGET_HXX class RomListSettings; class ScrollBarWidget; class PackedBitArray; class CheckListWidget; #include "Array.hxx" #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(); 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); const string& getText() const; void startEditMode(); void endEditMode(); protected: void handleMouseDown(int x, int y, int button, int clickCount); void handleMouseUp(int x, int y, int button, int clickCount); void handleMouseWheel(int x, int y, int direction); bool handleKeyDown(StellaKey key, StellaMod mod, char ascii); bool handleKeyUp(StellaKey key, StellaMod mod, char ascii); bool handleEvent(Event::Type e); void handleCommand(CommandSender* sender, int cmd, int data, int id); void drawWidget(bool hilite); GUI::Rect getLineRect() const; GUI::Rect getEditRect() const; int findItem(int x, int y) const; void recalc(); bool tryInsertChar(char c, int pos); void abortEditMode(); void lostFocusWidget(); void scrollToSelected() { scrollToCurrent(_selectedItem); } void scrollToHighlighted() { scrollToCurrent(_highlightedItem); } private: void scrollToCurrent(int item); private: RomListSettings* 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; Common::Array myCheckList; }; #endif stella-3.9.3/src/debugger/gui/TiaOutputWidget.cxx0000644000175000001440000001114312266336753021401 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TiaOutputWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "OSystem.hxx" #include "FrameBuffer.hxx" #include "Widget.hxx" #include "GuiObject.hxx" #include "ContextMenu.hxx" #include "TiaZoomWidget.hxx" #include "Debugger.hxx" #include "DebuggerParser.hxx" #include "TIADebug.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), myMenu(NULL), myZoom(NULL) { // Create context menu for commands VariantList l; l.push_back("Fill to scanline", "scanline"); l.push_back("Set breakpoint", "bp"); l.push_back("Set zoom position", "zoom"); l.push_back("Toggle fixed debug colors (from beam pos)", "fixed"); myMenu = new ContextMenu(this, font, l); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TiaOutputWidget::~TiaOutputWidget() { delete myMenu; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaOutputWidget::loadConfig() { setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaOutputWidget::handleMouseDown(int x, int y, int button, int clickCount) { // Grab right mouse button for command context menu if(button == 2) { 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) { int ystart = atoi(instance().console().properties().get(Display_YStart).c_str()); switch(cmd) { case ContextMenu::kItemSelectedCmd: { const string& rmb = myMenu->getSelectedTag().toString(); if(rmb == "scanline") { ostringstream command; int lines = myClickY + ystart; if(instance().console().tia().partialFrame()) lines -= instance().console().tia().scanlines(); if(lines > 0) { command << "scanline #" << lines; instance().debugger().parser().run(command.str()); } } else if(rmb == "bp") { ostringstream command; int scanline = myClickY + ystart; command << "breakif _scan==#" << scanline; instance().debugger().parser().run(command.str()); } else if(rmb == "zoom") { if(myZoom) myZoom->setPos(myClickX, myClickY); } else if(rmb == "fixed") { instance().console().tia().toggleFixedColors(); } break; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaOutputWidget::drawWidget(bool hilite) { //cerr << "TiaOutputWidget::drawWidget\n"; FBSurface& s = dialog().surface(); const uInt32 width = instance().console().tia().width(), height = instance().console().tia().height(); // Get current scanline position // This determines where the frame greying should start, and where a // scanline 'pointer' should be drawn uInt16 scanx, scany, scanoffset; bool visible = instance().console().tia().scanlinePos(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().tiaPixel(i, shift); *line_ptr++ = pixel; *line_ptr++ = pixel; } s.drawPixels(myLineBuffer, _x, _y+y, width << 1); } // Show electron beam position if(visible && scanx < width && scany+2u < height) { s.fillRect(_x+(scanx<<1), _y+scany, 3, 3, kBtnTextColor); } } stella-3.9.3/src/debugger/gui/RomWidget.cxx0000644000175000001440000001656712266336753020217 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RomWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "Debugger.hxx" #include "CartDebug.hxx" #include "DiStella.hxx" #include "CpuDebug.hxx" #include "GuiObject.hxx" #include "DataGridWidget.hxx" #include "EditTextWidget.hxx" #include "PopUpWidget.hxx" #include "StringList.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 state: "), lfont.getFontHeight(), "Bank state: ", kTextAlignLeft); xpos += t->getWidth() + 5; myBank = new EditTextWidget(boss, nfont, xpos, ypos-1, _w - 2 - xpos, nfont.getLineHeight()); // 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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RomWidget::~RomWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomWidget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = (CartState&) cart.getState(); const CartState& oldstate = (CartState&) 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.resolve_code = data; instance().settings().setValue("dis.resolve", DiStella::settings.resolve_code); invalidate(); break; } case RomListWidget::kPCAddressesCmd: // 'data' is the boolean value DiStella::settings.show_addresses = data; instance().settings().setValue("dis.showaddr", DiStella::settings.show_addresses); invalidate(); break; case RomListWidget::kGfxAsBinaryCmd: // 'data' is the boolean value if(data) { DiStella::settings.gfx_format = Common::Base::F_2; instance().settings().setValue("dis.gfxformat", "2"); } else { DiStella::settings.gfx_format = 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); } } stella-3.9.3/src/debugger/gui/CartE7Widget.hxx0000644000175000001440000000273612266336753020545 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartE7Widget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CARTRIDGEE7_WIDGET_HXX #define CARTRIDGEE7_WIDGET_HXX class CartridgeE7; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeE7Widget : public CartDebugWidget { public: CartridgeE7Widget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeE7& cart); virtual ~CartridgeE7Widget() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeE7& myCart; PopUpWidget *myLower2K, *myUpper256B; enum { kLowerChanged = 'lwCH', kUpperChanged = 'upCH' }; }; #endif stella-3.9.3/src/debugger/gui/CartDPCPlusWidget.hxx0000644000175000001440000000437412266336753021544 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDPCPlusWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void saveOldState(); void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: struct CartState { ByteArray tops; ByteArray bottoms; IntArray counters; IntArray fraccounters; ByteArray fracinc; ByteArray param; IntArray mcounters; IntArray mfreqs; IntArray mwaves; uInt32 random; }; private: 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 myState, myOldState; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/Cart3FWidget.hxx0000644000175000001440000000264412266336753020540 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart3FWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: Cartridge3F& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/ToggleWidget.hxx0000644000175000001440000000422612266336753020675 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ToggleWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef TOGGLE_WIDGET_HXX #define TOGGLE_WIDGET_HXX #include "Widget.hxx" #include "Command.hxx" #include "Array.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); virtual ~ToggleWidget(); const BoolArray& getState() { return _stateList; } bool getSelectedState() const { return _stateList[_selectedItem]; } virtual void handleMouseDown(int x, int y, int button, int clickCount); virtual void handleMouseUp(int x, int y, int button, int clickCount); virtual bool handleKeyDown(StellaKey key, StellaMod mod, char ascii); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); virtual bool wantsFocus() { return true; } int colWidth() const { return _colWidth; } void setEditable(bool editable) { _editable = editable; } protected: void drawWidget(bool hilite) = 0; int findItem(int x, int y); protected: int _rows; int _cols; int _currentRow; int _currentCol; int _rowHeight; int _colWidth; int _selectedItem; bool _editable; BoolArray _stateList; BoolArray _changedList; }; #endif stella-3.9.3/src/debugger/gui/RamWidget.hxx0000644000175000001440000000455312266336753020176 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RamWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef RAM_WIDGET_HXX #define RAM_WIDGET_HXX class GuiObject; class InputTextDialog; class ButtonWidget; class DataGridOpsWidget; class EditTextWidget; class StaticTextWidget; #include "Array.hxx" #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); virtual ~RamWidget(); void handleCommand(CommandSender* sender, int cmd, int data, int id); void loadConfig(); void setOpsWidget(DataGridOpsWidget* w); private: void fillGrid(bool updateOld); void showInputBox(int cmd); string doSearch(const string& str); string doCompare(const string& str); void doRestart(); void showSearchResults(); private: enum { kUndoCmd = 'RWud', kRevertCmd = 'RWrv', kSearchCmd = 'RWse', kCmpCmd = 'RWcp', kRestartCmd = 'RWrs', kSValEntered = 'RWsv', kCValEntered = 'RWcv' }; int myUndoAddress; int myUndoValue; int myCurrentRamBank; StaticTextWidget* myRamStart; StaticTextWidget* myRamLabels[8]; DataGridWidget* myRamGrid; EditTextWidget* myBinValue; EditTextWidget* myDecValue; EditTextWidget* myLabel; ButtonWidget* myRevertButton; ButtonWidget* myUndoButton; ButtonWidget* mySearchButton; ButtonWidget* myCompareButton; ButtonWidget* myRestartButton; InputTextDialog* myInputBox; IntArray myOldValueList; IntArray mySearchAddr; IntArray mySearchValue; BoolArray mySearchState; }; #endif stella-3.9.3/src/debugger/gui/ColorWidget.hxx0000644000175000001440000000304012266336753020523 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ColorWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: ColorWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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); ~ColorWidget(); void setColor(int color); int getColor() const { return _color; } protected: void drawWidget(bool hilite); protected: int _color; int _cmd; }; #endif stella-3.9.3/src/debugger/gui/TogglePixelWidget.cxx0000644000175000001440000001030412266336753021664 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TogglePixelWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #include "Widget.hxx" #include "Dialog.hxx" #include "Debugger.hxx" #include "FrameBuffer.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), _pixelColor(0), _backgroundColor(kDlgColor) { _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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TogglePixelWidget::~TogglePixelWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TogglePixelWidget::setState(const BoolArray& state) { _stateList.clear(); _stateList = state; setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TogglePixelWidget::setIntState(int value, bool swap) { unsigned int 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(unsigned int 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 unsigned int value = 0, size = _stateList.size(); for(unsigned int 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); } } } stella-3.9.3/src/debugger/gui/CartFA2Widget.cxx0000644000175000001440000001117712266336753020634 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartFA2Widget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 $FF4\n" << "Startup bank = " << cart.myStartBank << "\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 = $" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Chris D. Walton (Star Castle 2600)", info.str(), 15) + myLineHeight; VariantList items; items.push_back("0 ($FF5)"); items.push_back("1 ($FF6)"); items.push_back("2 ($FF7)"); items.push_back("3 ($FF8)"); items.push_back("4 ($FF9)"); items.push_back("5 ($FFA)"); if(cart.bankCount() == 7) items.push_back("6 ($FFB)"); 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); 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: ", kTextAlignLeft); 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::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$FF5", "$FF6", "$FF7", "$FF8", "$FF9", "$FFA", "$FFB" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/TiaWidget.hxx0000644000175000001440000000766712266336753020205 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TiaWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef TIA_WIDGET_HXX #define TIA_WIDGET_HXX class GuiObject; class ButtonWidget; class DataGridWidget; class StaticTextWidget; class ToggleBitWidget; class TogglePixelWidget; class EditTextWidget; class ColorWidget; #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(); void handleCommand(CommandSender* sender, int cmd, int data, int id); void loadConfig(); private: void changeColorRegs(); private: DataGridWidget* myColorRegs; ColorWidget* myCOLUP0Color; ColorWidget* myCOLUP1Color; ColorWidget* myCOLUPFColor; ColorWidget* myCOLUBKColor; TogglePixelWidget* myGRP0; TogglePixelWidget* myGRP1; 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; CheckboxWidget* myEnaM0; CheckboxWidget* myEnaM1; CheckboxWidget* myEnaBL; CheckboxWidget* myResMP0; CheckboxWidget* myResMP1; /** Collision register bits */ CheckboxWidget* myCollision[15]; TogglePixelWidget* myPF[3]; CheckboxWidget* myRefPF; CheckboxWidget* myScorePF; CheckboxWidget* myPriorityPF; CheckboxWidget* myUndrivenPins; // 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, kGRP1ID, kPosP0ID, kPosP1ID, kPosM0ID, kPosM1ID, kPosBLID, kHMP0ID, kHMP1ID, kHMM0ID, kHMM1ID, kHMBLID, kRefP0ID, kRefP1ID, kDelP0ID, kDelP1ID, kDelBLID, kNusizP0ID, kNusizP1ID, kNusizM0ID, kNusizM1ID, kSizeBLID, kEnaM0ID, kEnaM1ID, kEnaBLID, 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', kCxclrCmd = 'Scxl', kPPinCmd = 'PPin' }; // Color registers enum { kCOLUP0Addr, kCOLUP1Addr, kCOLUPFAddr, kCOLUBKAddr }; }; #endif stella-3.9.3/src/debugger/gui/TiaZoomWidget.cxx0000644000175000001440000001570412266336753021034 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TiaZoomWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #include "Console.hxx" #include "TIA.hxx" #include "FrameBuffer.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), myMenu(NULL) { _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 = BSPF_min(w, 320); _h = BSPF_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; l.push_back("2x zoom", "2"); l.push_back("4x zoom", "4"); l.push_back("8x zoom", "8"); myMenu = new ContextMenu(this, font, l); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TiaZoomWidget::~TiaZoomWidget() { delete myMenu; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaZoomWidget::loadConfig() { setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaZoomWidget::handleMouseDown(int x, int y, int button, int clickCount) { // Button 1 is for 'drag'/movement of the image // Button 2 is for context menu if(button == 1) { // Indicate mouse drag started/in progress myMouseMoving = true; myXClick = x; myYClick = y; } else if(button == 2) { // Add menu at current x,y mouse location myMenu->show(x + getAbsX(), y + getAbsY()); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaZoomWidget::handleMouseUp(int x, int y, int button, 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, int button) { // 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(int button) { 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); s.box(_x, _y, _w, _h, kColor, kShadowColor); // 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().currentFrameBuffer(); const int width = instance().console().tia().width(), wzoom = myZoomLevel << 1, hzoom = myZoomLevel; // Get current scanline position // This determines where the frame greying should start uInt16 scanx, scany, scanoffset; instance().console().tia().scanlinePos(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); s.fillRect(_x + col + 2, _y + row + 2, wzoom, hzoom, color); } } } stella-3.9.3/src/debugger/gui/Cart3EWidget.cxx0000644000175000001440000001161712266336753020532 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart3EWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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) romitems.push_back(i); romitems.push_back("Inactive", ""); VariantList ramitems; for(uInt32 i = 0; i < myNumRamBanks; ++i) ramitems.push_back(i); ramitems.push_back("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(), kTextAlignLeft); 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::loadConfig() { if(myCart.myCurrentBank < 256) { myROMBank->setSelectedIndex(myCart.myCurrentBank % myNumRomBanks); myRAMBank->setSelectedMax(); } else { myROMBank->setSelectedMax(); myRAMBank->setSelectedIndex(myCart.myCurrentBank - 256); } 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 " << dec << bank % myNumRomBanks << ", RAM inactive"; else buf << "ROM inactive, RAM bank " << bank % myNumRomBanks; return buf.str(); } stella-3.9.3/src/debugger/gui/CartDPCWidget.cxx0000644000175000001440000001736212266336753020674 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDPCWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 << "\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 = $" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Activision (Pitfall II)", info.str()) + myLineHeight; VariantList items; items.push_back("0 ($FF8)"); items.push_back("1 ($FF9)"); 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); ypos += myLineHeight + 8; // Data fetchers int lwidth = _font.getStringWidth("Data Fetchers: "); new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Data Fetchers: ", kTextAlignLeft); // Top registers lwidth = _font.getStringWidth("Counter Registers: "); xpos = 18; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Top Registers: ", kTextAlignLeft); 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: ", kTextAlignLeft); 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: ", kTextAlignLeft); 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: ", kTextAlignLeft); 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): ", kTextAlignLeft); 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: ", kTextAlignLeft); 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(int 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(int i = 0; i < 3; ++i) { myOldState.music.push_back(myCart.myMusicMode[i]); } myOldState.random = myCart.myRandomNumber; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCWidget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); // 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* spot[] = { "$FF8", "$FF9" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/ToggleBitWidget.cxx0000644000175000001440000000734112266336753021330 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ToggleBitWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #include "Widget.hxx" #include "Dialog.hxx" #include "Debugger.hxx" #include "FrameBuffer.hxx" #include "StringList.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) { _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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ToggleBitWidget::~ToggleBitWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ToggleBitWidget::setList(const StringList& off, const StringList& on) { _offList.clear(); _offList = off; _onList.clear(); _onList = on; int size = _offList.size(); // assume _onList is the same size assert(size == _rows * _cols); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ToggleBitWidget::setState(const BoolArray& state, const BoolArray& changed) { _stateList.clear(); _stateList = state; _changedList.clear(); _changedList = changed; setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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; 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 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; // 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); if(_stateList[pos]) buffer = _onList[pos]; else buffer = _offList[pos]; // 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, kTextColor); } } } stella-3.9.3/src/debugger/gui/DataGridWidget.cxx0000644000175000001440000005122212266336753021124 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DataGridWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #include "Widget.hxx" #include "Dialog.hxx" #include "Debugger.hxx" #include "FrameBuffer.hxx" #include "DataGridWidget.hxx" #include "DataGridOpsWidget.hxx" #include "RamWidget.hxx" #include "ScrollBarWidget.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), _base(base), _selectedItem(0), _currentKeyDown(KBDK_UNKNOWN), _opsWidget(NULL), _scrollBar(NULL) { _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; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DataGridWidget::~DataGridWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 = 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; */ _editMode = false; // Send item selected signal for starting with cell 0 sendCommand(DataGridWidget::kSelectionChangedCmd, _selectedItem, _id); setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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::setHiliteList(const BoolArray& hilitelist) { assert(hilitelist.size() == uInt32(_rows * _cols)); _hiliteList.clear(); _hiliteList = hilitelist; setDirty(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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::setValue(int position, int value, bool changed) { 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; sendCommand(DataGridWidget::kItemDataChangedCmd, position, _id); setDirty(); draw(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::setRange(int lower, int upper) { _lowerBound = BSPF_max(0, lower); _upperBound = BSPF_min(1 << _bits, upper); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::handleMouseDown(int x, int y, int button, 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(); draw(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::handleMouseUp(int x, int y, int button, 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(_editable && !_editMode) startEditMode(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::handleMouseWheel(int x, int y, int direction) { if(_scrollBar) _scrollBar->handleMouseWheel(x, y, direction); else if(_editable) { 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::handleKeyDown(StellaKey key, StellaMod mod, char ascii) { // Ignore all mod keys if(instance().eventHandler().kbdControl(mod) || instance().eventHandler().kbdAlt(mod)) return true; bool handled = true; bool dirty = false; if (_editMode) { // Class EditableWidget handles all text editing related key presses for us handled = EditableWidget::handleKeyDown(key, mod, ascii); if(handled) setDirty(); draw(); } else { // not editmode 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(instance().eventHandler().kbdShift(mod) && _scrollBar) handleMouseWheel(0, 0, -1); else if (_currentRow > 0) { _currentRow = 0; dirty = true; } break; case KBDK_PAGEDOWN: if(instance().eventHandler().kbdShift(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(_editable) negateCell(); break; default: handled = false; } if(!handled) { handled = true; switch(ascii) { case 'i': // invert case '!': if(_editable) invertCell(); break; case '-': // decrement if(_editable) decrementCell(); break; case '+': // increment case '=': if(_editable) incrementCell(); break; case '<': // shift left case ',': if(_editable) lshiftCell(); break; case '>': // shift right case '.': if(_editable) rshiftCell(); break; case 'z': // zero if(_editable) zeroCell(); break; default: handled = false; } } } if (dirty) { int oldItem = _selectedItem; _selectedItem = _currentRow*_cols + _currentCol; if(_selectedItem != oldItem) sendCommand(DataGridWidget::kSelectionChangedCmd, _selectedItem, _id); setDirty(); draw(); } _currentKeyDown = key; return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool DataGridWidget::handleKeyUp(StellaKey key, StellaMod mod, char ascii) { 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() { _editMode = false; // Disable the operations widget if(_opsWidget) _opsWidget->setEnabled(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case kSetPositionCmd: // Chain access; pass to parent sendCommand(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) { //cerr << "DataGridWidget::drawWidget\n"; FBSurface& s = _boss->dialog().surface(); int row, col, deltax; // 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 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; // 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); if (_selectedItem == pos && _editMode) { adjustOffset(); deltax = -_editScrollOffset; s.drawString(_font, _editString, x, y, _colWidth, kTextColor, kTextAlignLeft, deltax, false); } else { deltax = 0; uInt32 color = kTextColor; if(_changedList[pos]) { s.fillRect(x - 3, y - 1, _colWidth-1, _rowHeight-1, kDbgChangedColor); if(_hiliteList[pos]) color = kDbgColorHi; else color = kDbgChangedTextColor; } else if(_hiliteList[pos]) color = kDbgColorHi; s.drawString(_font, _valueStringList[pos], x, y, _colWidth, color); } } } // 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 } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 (_editable && !_editMode && _selectedItem >= 0) { _editMode = true; setText("", true ); // Erase current entry when starting editing } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::endEditMode() { if (!_editMode) return; _editMode = 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: break; } } int value = instance().debugger().stringToValue(_editString); if(value < _lowerBound || value >= _upperBound) { abortEditMode(); return; } setSelectedValue(value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::abortEditMode() { // undo any changes made assert(_selectedItem >= 0); _editMode = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool DataGridWidget::tryInsertChar(char c, int pos) { // Input is very strict here, to eliminate time-consuming error checking // elsewhere, and includes the following restrictions: // Cannot contain spaces // Starts with leading specifier ($, #, \), or with a base character // Only one specifier is allowed // If starting with a specifier, only allow numbers applicable to that // base to follow c = tolower(c); bool isBin = c == '0' || c == '1', isDec = c >= '0' && c <= '9', isHex = isDec || (c >= 'a' && c <= 'f'), isOp = c == '$' || c == '#' || c == '\\', insert = false; if(BSPF_startsWithIgnoreCase(_editString, "$")) insert = isHex && pos > 0; else if(BSPF_startsWithIgnoreCase(_editString, "#")) insert = isDec && pos > 0; else if(BSPF_startsWithIgnoreCase(_editString, "\\")) insert = isBin && pos > 0; else insert = isHex || isDec || isBin || isOp; if(insert) _editString.insert(pos, 1, c); return insert; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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-3.9.3/src/debugger/gui/CartE0Widget.cxx0000644000175000001440000001111012266336753020513 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartE0Widget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "CartE0.hxx" #include "PopUpWidget.hxx" #include "CartE0Widget.hxx" static const char* seg0[] = { "0 ($FE0)", "1 ($FE1)", "2 ($FE2)", "3 ($FE3)", "4 ($FE4)", "5 ($FE5)", "6 ($FE6)", "7 ($FE7)" }; static const char* seg1[] = { "0 ($FE8)", "1 ($FE9)", "2 ($FEA)", "3 ($FEB)", "4 ($FEC)", "5 ($FED)", "6 ($FEE)", "7 ($FEF)" }; static const char* seg2[] = { "0 ($FF0)", "1 ($FF1)", "2 ($FF2)", "3 ($FF3)", "4 ($FF4)", "5 ($FF5)", "6 ($FF6)", "7 ($FF7)" }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 = 0 / 1 / 2\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) { items0.push_back(seg0[i]); items1.push_back(seg1[i]); items2.push_back(seg2[i]); } const int lwidth = _font.getStringWidth("Set slice for segment X: "); mySlice0 = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("7 ($FF7)"), 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 ($FF7)"), 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 ($FF7)"), 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: " << dec << seg0[myCart.myCurrentSlice[0]] << " / " << seg1[myCart.myCurrentSlice[1]] << " / " << seg2[myCart.myCurrentSlice[2]]; return buf.str(); } stella-3.9.3/src/debugger/gui/BoosterWidget.cxx0000644000175000001440000001145212266336753021063 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: BoosterWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #include "EventHandler.hxx" #include "BoosterWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BoosterWidget::BoosterWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : ControllerWidget(boss, font, x, y, controller) { bool leftport = myController.jack() == Controller::Left; const string& label = leftport ? "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, kTextAlignLeft); xpos += t->getWidth()/2 - 5; ypos += t->getHeight() + 10; myPins[kJUp] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd); myPins[kJUp]->setID(kJUp); myPins[kJUp]->setTarget(this); ypos += myPins[kJUp]->getHeight() * 2 + 10; myPins[kJDown] = new CheckboxWidget(boss, font, xpos, ypos, "", 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, "", kCheckActionCmd); myPins[kJLeft]->setID(kJLeft); myPins[kJLeft]->setTarget(this); xpos += (myPins[kJUp]->getWidth() + 5) * 2; myPins[kJRight] = new CheckboxWidget(boss, font, xpos, ypos, "", 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", kCheckActionCmd); myPins[kJFire]->setID(kJFire); myPins[kJFire]->setTarget(this); ypos += myPins[kJFire]->getHeight() + 5; myPins[kJBooster] = new CheckboxWidget(boss, font, xpos, ypos, "Booster", kCheckActionCmd); myPins[kJBooster]->setID(kJBooster); myPins[kJBooster]->setTarget(this); ypos += myPins[kJBooster]->getHeight() + 5; myPins[kJTrigger] = new CheckboxWidget(boss, font, xpos, ypos, "Trigger", kCheckActionCmd); myPins[kJTrigger]->setID(kJTrigger); myPins[kJTrigger]->setTarget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BoosterWidget::~BoosterWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 == 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-3.9.3/src/debugger/gui/RiotWidget.cxx0000644000175000001440000004020412266336753020360 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RiotWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Settings.hxx" #include "DataGridWidget.hxx" #include "EditTextWidget.hxx" #include "FrameBuffer.hxx" #include "GuiObject.hxx" #include "OSystem.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 "RiotWidget.hxx" #define CREATE_IO_REGS(desc, bits, bitsID, editable) \ t = new StaticTextWidget(boss, lfont, xpos, ypos+2, lwidth, fontHeight,\ desc, kTextAlignLeft); \ 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); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 = 9 * 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"); } // 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, 0, false); // 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* 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, 9*fontWidth, fontHeight, writeNames[row], kTextAlignLeft); } xpos += 9*fontWidth + 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* 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, 11*fontWidth, fontHeight, readNames[row], kTextAlignLeft); } 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* 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, 6*fontWidth, fontHeight, contLeftReadNames[row], kTextAlignLeft); } xpos += 6*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* 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, 6*fontWidth, fontHeight, contRightReadNames[row], kTextAlignLeft); } xpos += 6*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(); items.push_back("B/easy", "b"); items.push_back("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(); items.push_back("B&W", "bw"); items.push_back("Color", "color"); myTVType = new PopUpWidget(boss, lfont, xpos, ypos, pwidth, lineHeight, items, "TV Type: ", lwidth, kTVTypeChanged); myTVType->setTarget(this); addFocusWidget(myTVType); // Select and Reset xpos += myP0Diff->getWidth() + 20; ypos = col2_ypos + lineHeight; mySelect = new CheckboxWidget(boss, lfont, xpos, ypos, "Select", kCheckActionCmd); mySelect->setID(kSelectID); mySelect->setTarget(this); addFocusWidget(mySelect); ypos += mySelect->getHeight() + 5; myReset = new CheckboxWidget(boss, lfont, xpos, ypos, "Reset", kCheckActionCmd); myReset->setID(kResetID); myReset->setTarget(this); addFocusWidget(myReset); // Randomize items xpos = 10; ypos += 3*lineHeight; new StaticTextWidget(boss, lfont, xpos, ypos, lfont.getStringWidth("When loading a ROM:"), fontHeight, "When loading a ROM:", kTextAlignLeft); // Randomize CPU xpos += 30; ypos += lineHeight + 4; myRandomizeCPU = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Randomize CPU registers (A/X/Y/PS)", kCheckActionCmd); myRandomizeCPU->setID(kRandCPUID); myRandomizeCPU->setTarget(this); addFocusWidget(myRandomizeCPU); // Randomize RAM ypos += lineHeight + 4; myRandomizeRAM = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Randomize zero-page and extended RAM", kCheckActionCmd); myRandomizeRAM->setID(kRandRAMID); myRandomizeRAM->setTarget(this); addFocusWidget(myRandomizeRAM); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RiotWidget::~RiotWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RiotWidget::loadConfig() { #define IO_REGS_UPDATE(bits, s_bits) \ changed.clear(); \ for(unsigned int 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 = (RiotState&) riot.getState(); const RiotState& oldstate = (RiotState&) 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)); myINPTDump->setState(riot.vblank(7)); // 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((int)riot.diffP0()); myP1Diff->setSelectedIndex((int)riot.diffP1()); myTVType->setSelectedIndex((int)riot.tvType()); mySelect->setState(!riot.select()); myReset->setState(!riot.reset()); myLeftControl->loadConfig(); myRightControl->loadConfig(); myRandomizeCPU->setState(instance().settings().getBool("cpurandom")); myRandomizeRAM->setState(instance().settings().getBool("ramrandom")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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((BoolArray&)mySWCHAWriteBits->getState()); riot.swcha(value & 0xff); break; case kSWACNTBitsID: value = Debugger::get_bits((BoolArray&)mySWACNTBits->getState()); riot.swacnt(value & 0xff); break; case kSWCHBBitsID: value = Debugger::get_bits((BoolArray&)mySWCHBWriteBits->getState()); riot.swchb(value & 0xff); break; case kSWBCNTBitsID: value = Debugger::get_bits((BoolArray&)mySWBCNTBits->getState()); riot.swbcnt(value & 0xff); break; } break; case kCheckActionCmd: switch(id) { case kSelectID: riot.select(!mySelect->getState()); break; case kResetID: riot.reset(!myReset->getState()); break; case kRandCPUID: instance().settings().setValue("cpurandom", myRandomizeCPU->getState()); break; case kRandRAMID: instance().settings().setValue("ramrandom", myRandomizeRAM->getState()); break; } break; case kP0DiffChanged: riot.diffP0(myP0Diff->getSelectedTag().toString() != "b"); break; case kP1DiffChanged: riot.diffP1(myP1Diff->getSelectedTag().toString() != "b"); break; case kTVTypeChanged: riot.tvType((bool)myTVType->getSelected()); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ControllerWidget* RiotWidget::addControlWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) { switch(controller.type()) { case Controller::Joystick: return new JoystickWidget(boss, font, x, y, controller); case Controller::Paddles: return new PaddleWidget(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::Keyboard: return new KeyboardWidget(boss, font, x, y, controller); default: return new NullControlWidget(boss, font, x, y, controller); } } stella-3.9.3/src/debugger/gui/CartFEWidget.hxx0000644000175000001440000000261312266336753020556 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartFEWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CARTRIDGEFE_WIDGET_HXX #define CARTRIDGEFE_WIDGET_HXX class CartridgeFE; #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() { } // No implementation for non-bankswitched ROMs void loadConfig() { } void handleCommand(CommandSender* sender, int cmd, int data, int id) { } string bankState(); private: CartridgeFE& myCart; }; #endif stella-3.9.3/src/debugger/gui/CartDFWidget.hxx0000644000175000001440000000264412266336753020561 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDFWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeDF& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/CartFAWidget.hxx0000644000175000001440000000264412266336753020556 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartFAWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeFA& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/Cart0840Widget.cxx0000644000175000001440000000605112266336753020652 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart0840Widget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 = (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; items.push_back("0 ($800)"); items.push_back("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() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$800", "$840" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/DataGridOpsWidget.cxx0000644000175000001440000000742612266336753021615 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DataGridOpsWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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(NULL), _invButton(NULL), _negButton(NULL), _incButton(NULL), _decButton(NULL), _shiftLeftButton(NULL), _shiftRightButton(NULL) { const int bwidth = _font.getMaxCharWidth() * 4, bheight = _font.getFontHeight() + 3, space = 6; 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-3.9.3/src/debugger/gui/CartBFWidget.cxx0000644000175000001440000001273112266336753020550 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartBFWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 " << dec << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << " (hotspot = $" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "CPUWIZ", info.str()) + myLineHeight; VariantList items; items.push_back(" 0 ($F80)"); items.push_back(" 1 ($F81)"); items.push_back(" 2 ($F82)"); items.push_back(" 3 ($F83)"); items.push_back(" 4 ($F84)"); items.push_back(" 5 ($F85)"); items.push_back(" 6 ($F86)"); items.push_back(" 7 ($F87)"); items.push_back(" 8 ($F88)"); items.push_back(" 9 ($F89)"); items.push_back("10 ($F8A)"); items.push_back("11 ($F8B)"); items.push_back("12 ($F8C)"); items.push_back("13 ($F8D)"); items.push_back("14 ($F8E)"); items.push_back("15 ($F8F)"); items.push_back("16 ($F90)"); items.push_back("17 ($F91)"); items.push_back("18 ($F92)"); items.push_back("19 ($F93)"); items.push_back("20 ($F94)"); items.push_back("21 ($F95)"); items.push_back("22 ($F96)"); items.push_back("23 ($F97)"); items.push_back("24 ($F98)"); items.push_back("25 ($F99)"); items.push_back("26 ($F9A)"); items.push_back("27 ($F9B)"); items.push_back("28 ($F9C)"); items.push_back("29 ($F9D)"); items.push_back("30 ($F9E)"); items.push_back("31 ($F9F)"); items.push_back("32 ($FA0)"); items.push_back("33 ($FA1)"); items.push_back("34 ($FA2)"); items.push_back("35 ($FA3)"); items.push_back("36 ($FA4)"); items.push_back("37 ($FA5)"); items.push_back("38 ($FA6)"); items.push_back("39 ($FA7)"); items.push_back("40 ($FA8)"); items.push_back("41 ($FA9)"); items.push_back("42 ($FAA)"); items.push_back("43 ($FAB)"); items.push_back("44 ($FAC)"); items.push_back("45 ($FAD)"); items.push_back("46 ($FAE)"); items.push_back("47 ($FAF)"); items.push_back("48 ($FB0)"); items.push_back("49 ($FB1)"); items.push_back("50 ($FB2)"); items.push_back("51 ($FB3)"); items.push_back("52 ($FB4)"); items.push_back("53 ($FB5)"); items.push_back("54 ($FB6)"); items.push_back("55 ($FB7)"); items.push_back("56 ($FB8)"); items.push_back("57 ($FB9)"); items.push_back("58 ($FBA)"); items.push_back("59 ($FBB)"); items.push_back("60 ($FBC)"); items.push_back("61 ($FBD)"); items.push_back("62 ($FBE)"); items.push_back("63 ($FBF)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("64 ($FBF) "), myLineHeight, items, "Set bank: ", _font.getStringWidth("Set bank: "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBFWidget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$F80", "$F81", "$F82", "$F83", "$F84", "$F85", "$F86", "$F87", "$F88", "$F89", "$F8A", "$F8B", "$F8C", "$F8D", "$F8E", "$F8F", "$F90", "$F91", "$F92", "$F93", "$F94", "$F95", "$F96", "$F97", "$F98", "$F99", "$F9A", "$F9B", "$F9C", "$F9D", "$F9E", "$F9F", "$FA0", "$FA1", "$FA2", "$FA3", "$FA4", "$FA5", "$FA6", "$FA7", "$FA8", "$FA9", "$FAA", "$FAB", "$FAC", "$FAD", "$FAE", "$FAF", "$FB0", "$FB1", "$FB2", "$FB3", "$FB4", "$FB5", "$FB6", "$FB7", "$FB8", "$FB9", "$FBA", "$FBB", "$FBC", "$FBD", "$FBE", "$FBF" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/AudioWidget.cxx0000644000175000001440000001065512266336753020513 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: AudioWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "DataGridWidget.hxx" #include "FrameBuffer.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "TIADebug.hxx" #include "Widget.hxx" #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:", kTextAlignLeft); xpos += lwidth; myAudF = new DataGridWidget(boss, nfont, xpos, ypos, 2, 1, 2, 5, Common::Base::F_16); myAudF->setTarget(this); myAudF->setID(kAUDFID); myAudF->setEditable(false); addFocusWidget(myAudF); for(int col = 0; col < 2; ++col) { new StaticTextWidget(boss, lfont, xpos + col*myAudF->colWidth() + 7, ypos - lineHeight, fontWidth, fontHeight, Common::Base::toString(col, Common::Base::F_16_1), kTextAlignLeft); } // AudC registers xpos = 10; ypos += lineHeight + 5; new StaticTextWidget(boss, lfont, xpos, ypos+2, lwidth, fontHeight, "AUDC:", kTextAlignLeft); xpos += lwidth; myAudC = new DataGridWidget(boss, nfont, xpos, ypos, 2, 1, 2, 4, Common::Base::F_16); myAudC->setTarget(this); myAudC->setID(kAUDCID); myAudC->setEditable(false); addFocusWidget(myAudC); // AudV registers xpos = 10; ypos += lineHeight + 5; new StaticTextWidget(boss, lfont, xpos, ypos+2, lwidth, fontHeight, "AUDV:", kTextAlignLeft); xpos += lwidth; myAudV = new DataGridWidget(boss, nfont, xpos, ypos, 2, 1, 2, 4, Common::Base::F_16); myAudV->setTarget(this); myAudV->setID(kAUDVID); myAudV->setEditable(false); addFocusWidget(myAudV); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AudioWidget::~AudioWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AudioWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { // TODO - implement this } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AudioWidget::loadConfig() { IntArray alist; IntArray vlist; BoolArray blist, changed, grNew, grOld; Debugger& dbg = instance().debugger(); TIADebug& tia = dbg.tiaDebug(); TiaState state = (TiaState&) tia.getState(); TiaState oldstate = (TiaState&) tia.getOldState(); // AUDF0/1 alist.clear(); vlist.clear(); changed.clear(); for(unsigned int 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(unsigned int 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(unsigned int 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); } stella-3.9.3/src/debugger/gui/CartDFSCWidget.hxx0000644000175000001440000000267412266336753021012 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDFSCWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeDFSC& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/GenesisWidget.cxx0000644000175000001440000001040312266336753021036 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: GenesisWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "OSystem.hxx" #include "EventHandler.hxx" #include "GenesisWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GenesisWidget::GenesisWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : ControllerWidget(boss, font, x, y, controller) { bool leftport = myController.jack() == Controller::Left; const string& label = leftport ? "Left (Genesis):" : "Right (Genesis):"; 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, kTextAlignLeft); xpos += t->getWidth()/2 - 5; ypos += t->getHeight() + 20; myPins[kJUp] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd); myPins[kJUp]->setID(kJUp); myPins[kJUp]->setTarget(this); ypos += myPins[kJUp]->getHeight() * 2 + 10; myPins[kJDown] = new CheckboxWidget(boss, font, xpos, ypos, "", 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, "", kCheckActionCmd); myPins[kJLeft]->setID(kJLeft); myPins[kJLeft]->setTarget(this); xpos += (myPins[kJUp]->getWidth() + 5) * 2; myPins[kJRight] = new CheckboxWidget(boss, font, xpos, ypos, "", 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", kCheckActionCmd); myPins[kJBbtn]->setID(kJBbtn); myPins[kJBbtn]->setTarget(this); ypos += myPins[kJBbtn]->getHeight() + 5; myPins[kJCbtn] = new CheckboxWidget(boss, font, xpos, ypos, "C button", kCheckActionCmd); myPins[kJCbtn]->setID(kJCbtn); myPins[kJCbtn]->setTarget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GenesisWidget::~GenesisWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 == 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-3.9.3/src/debugger/gui/Cart2KWidget.hxx0000644000175000001440000000251512266336753020541 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart2KWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } // No implementation for non-bankswitched ROMs void loadConfig() { } void handleCommand(CommandSender* sender, int cmd, int data, int id) { } }; #endif stella-3.9.3/src/debugger/gui/TiaInfoWidget.cxx0000644000175000001440000001266112266336753021002 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TiaInfoWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Base.hxx" #include "OSystem.hxx" #include "FrameBuffer.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; int lwidth = lfont.getStringWidth(longstr ? "Frame Cycle:" : "F. Cycle:"); int fwidth = 5 * lfont.getMaxCharWidth() + 4; // Add frame info xpos = x; ypos = y + 10; new StaticTextWidget(boss, lfont, xpos, ypos, lwidth, lineHeight, longstr ? "Frame Count:" : "Frame:", kTextAlignLeft); xpos += lwidth; myFrameCount = new EditTextWidget(boss, nfont, xpos, ypos-1, fwidth, lineHeight, ""); myFrameCount->setEditable(false); xpos = x; ypos += lineHeight + 5; new StaticTextWidget(boss, lfont, xpos, ypos, lwidth, lineHeight, longstr ? "Frame Cycle:" : "F. Cycle:", kTextAlignLeft); xpos += lwidth; myFrameCycles = new EditTextWidget(boss, nfont, xpos, ypos-1, fwidth, lineHeight, ""); myFrameCycles->setEditable(false); 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, lwidth, lineHeight, "Scanline:", kTextAlignLeft); myScanlineCount = new EditTextWidget(boss, nfont, xpos+lwidth, ypos-1, fwidth, lineHeight, ""); myScanlineCount->setEditable(false); ypos += lineHeight + 5; new StaticTextWidget(boss, lfont, xpos, ypos, lwidth, lineHeight, longstr ? "Scan Cycle:" : "S. Cycle:", kTextAlignLeft); myScanlineCycles = new EditTextWidget(boss, nfont, xpos+lwidth, ypos-1, fwidth, lineHeight, ""); myScanlineCycles->setEditable(false); ypos += lineHeight + 5; new StaticTextWidget(boss, lfont, xpos, ypos, lwidth, lineHeight, "Pixel Pos:", kTextAlignLeft); myPixelPosition = new EditTextWidget(boss, nfont, xpos+lwidth, ypos-1, fwidth, lineHeight, ""); myPixelPosition->setEditable(false); ypos += lineHeight + 5; new StaticTextWidget(boss, lfont, xpos, ypos, lwidth, lineHeight, longstr ? "Color Clock:" : "Color Clk:", kTextAlignLeft); myColorClocks = new EditTextWidget(boss, nfont, xpos+lwidth, ypos-1, fwidth, lineHeight, ""); myColorClocks->setEditable(false); // Calculate actual dimensions _w = myColorClocks->getAbsX() + myColorClocks->getWidth() - x; _h = ypos + lineHeight; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TiaInfoWidget::~TiaInfoWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaInfoWidget::handleMouseDown(int x, int y, int button, 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(); myFrameCount->setText(Common::Base::toString(tia.frameCount(), Common::Base::F_10)); myFrameCycles->setText(Common::Base::toString(dbg.cycles(), Common::Base::F_10)); myVSync->setState(tia.vsync()); myVBlank->setState(tia.vblank()); int clk = tia.clocksThisLine(); myScanlineCount->setText(Common::Base::toString(tia.scanlines(), Common::Base::F_10)); myScanlineCycles->setText(Common::Base::toString(clk/3, Common::Base::F_10)); myPixelPosition->setText(Common::Base::toString(clk-68, Common::Base::F_10)); myColorClocks->setText(Common::Base::toString(clk, Common::Base::F_10)); } stella-3.9.3/src/debugger/gui/ControllerWidget.hxx0000644000175000001440000000277012266336753021601 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: ControllerWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CONTROLLER_WIDGET_HXX #define CONTROLLER_WIDGET_HXX class GuiObject; class ButtonWidget; #include "Widget.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() { }; virtual void loadConfig() { }; virtual void handleCommand(CommandSender* sender, int cmd, int data, int id) { }; protected: Controller& myController; }; #endif stella-3.9.3/src/debugger/gui/CartX07Widget.cxx0000644000175000001440000000657212266336753020645 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartX07Widget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 " << 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; items.push_back(" 0"); items.push_back(" 1"); items.push_back(" 2"); items.push_back(" 3"); items.push_back(" 4"); items.push_back(" 5"); items.push_back(" 6"); items.push_back(" 7"); items.push_back(" 8"); items.push_back(" 9"); items.push_back(" 10"); items.push_back(" 11"); items.push_back(" 12"); items.push_back(" 13"); items.push_back(" 14"); items.push_back(" 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() { myBank->setSelectedIndex(myCart.myCurrentBank); 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 = " << dec << myCart.myCurrentBank; return buf.str(); } stella-3.9.3/src/debugger/gui/Cart4KWidget.cxx0000644000175000001440000000275412266336753020543 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart4KWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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-3.9.3/src/debugger/gui/CpuWidget.cxx0000644000175000001440000002372312266336753020201 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CpuWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "OSystem.hxx" #include "GuiObject.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "CpuDebug.hxx" #include "Widget.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:", kTextAlignLeft); 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); // 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->setEditable(false); xpos += myCpuGridDecValue->getWidth() + 5; myCpuGridBinValue = new DataGridWidget(boss, nfont, xpos, ypos, 1, 4, 8, 8, Common::Base::F_2); myCpuGridBinValue->setEditable(false); // 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); 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", kTextAlignCenter); // 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], kTextAlignLeft); } // 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:", kTextAlignLeft); 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* offstr[] = { "n", "v", "-", "b", "d", "i", "z", "c" }; const char* 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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CpuWidget::~CpuWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuWidget::setOpsWidget(DataGridOpsWidget* w) { myPCGrid->setOpsWidget(w); myCpuGrid->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; } 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); myCpuGridDecValue->setValue(0, value); myCpuGridBinValue->setValue(0, value); break; case kARegAddr: dbg.setA(value); myCpuGridDecValue->setValue(1, value); myCpuGridBinValue->setValue(1, value); break; case kXRegAddr: dbg.setX(value); myCpuGridDecValue->setValue(2, value); myCpuGridBinValue->setValue(2, value); break; case kYRegAddr: dbg.setY(value); myCpuGridDecValue->setValue(3, value); myCpuGridBinValue->setValue(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 = (CpuState&) cpu.getState(); const CpuState& oldstate = (CpuState&) 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(unsigned int 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-3.9.3/src/debugger/gui/CartBFSCWidget.cxx0000644000175000001440000001313012266336753020770 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartBFSCWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 " << dec << i << " @ $" << Common::Base::HEX4 << (start + 0x100) << " - " << "$" << (start + 0xFFF) << " (hotspot = $" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "CPUWIZ", info.str()) + myLineHeight; VariantList items; items.push_back(" 0 ($F80)"); items.push_back(" 1 ($F81)"); items.push_back(" 2 ($F82)"); items.push_back(" 3 ($F83)"); items.push_back(" 4 ($F84)"); items.push_back(" 5 ($F85)"); items.push_back(" 6 ($F86)"); items.push_back(" 7 ($F87)"); items.push_back(" 8 ($F88)"); items.push_back(" 9 ($F89)"); items.push_back("10 ($F8A)"); items.push_back("11 ($F8B)"); items.push_back("12 ($F8C)"); items.push_back("13 ($F8D)"); items.push_back("14 ($F8E)"); items.push_back("15 ($F8F)"); items.push_back("16 ($F90)"); items.push_back("17 ($F91)"); items.push_back("18 ($F92)"); items.push_back("19 ($F93)"); items.push_back("20 ($F94)"); items.push_back("21 ($F95)"); items.push_back("22 ($F96)"); items.push_back("23 ($F97)"); items.push_back("24 ($F98)"); items.push_back("25 ($F99)"); items.push_back("26 ($F9A)"); items.push_back("27 ($F9B)"); items.push_back("28 ($F9C)"); items.push_back("29 ($F9D)"); items.push_back("30 ($F9E)"); items.push_back("31 ($F9F)"); items.push_back("32 ($FA0)"); items.push_back("33 ($FA1)"); items.push_back("34 ($FA2)"); items.push_back("35 ($FA3)"); items.push_back("36 ($FA4)"); items.push_back("37 ($FA5)"); items.push_back("38 ($FA6)"); items.push_back("39 ($FA7)"); items.push_back("40 ($FA8)"); items.push_back("41 ($FA9)"); items.push_back("42 ($FAA)"); items.push_back("43 ($FAB)"); items.push_back("44 ($FAC)"); items.push_back("45 ($FAD)"); items.push_back("46 ($FAE)"); items.push_back("47 ($FAF)"); items.push_back("48 ($FB0)"); items.push_back("49 ($FB1)"); items.push_back("50 ($FB2)"); items.push_back("51 ($FB3)"); items.push_back("52 ($FB4)"); items.push_back("53 ($FB5)"); items.push_back("54 ($FB6)"); items.push_back("55 ($FB7)"); items.push_back("56 ($FB8)"); items.push_back("57 ($FB9)"); items.push_back("58 ($FBA)"); items.push_back("59 ($FBB)"); items.push_back("60 ($FBC)"); items.push_back("61 ($FBD)"); items.push_back("62 ($FBE)"); items.push_back("63 ($FBF)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("63 ($FBF) "), myLineHeight, items, "Set bank: ", _font.getStringWidth("Set bank: "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBFSCWidget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$F80", "$F81", "$F82", "$F83", "$F84", "$F85", "$F86", "$F87", "$F88", "$F89", "$F8A", "$F8B", "$F8C", "$F8D", "$F8E", "$F8F", "$F90", "$F91", "$F92", "$F93", "$F94", "$F95", "$F96", "$F97", "$F98", "$F99", "$F9A", "$F9B", "$F9C", "$F9D", "$F9E", "$F9F", "$FA0", "$FA1", "$FA2", "$FA3", "$FA4", "$FA5", "$FA6", "$FA7", "$FA8", "$FA9", "$FAA", "$FAB", "$FAC", "$FAD", "$FAE", "$FAF", "$FB0", "$FB1", "$FB2", "$FB3", "$FB4", "$FB5", "$FB6", "$FB7", "$FB8", "$FB9", "$FBA", "$FBB", "$FBC", "$FBD", "$FBE", "$FBF" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/CartF8Widget.cxx0000644000175000001440000000600212266336753020530 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF8Widget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 << "\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 = $" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Atari", info.str()) + myLineHeight; VariantList items; items.push_back("0 ($FF8)"); items.push_back("1 ($FF9)"); 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 CartridgeF8Widget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$FF8", "$FF9" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/CartF6Widget.cxx0000644000175000001440000000612112266336753020530 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF6Widget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 << "\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 = $" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Atari", info.str()) + myLineHeight; VariantList items; items.push_back("0 ($FF6)"); items.push_back("1 ($FF7)"); items.push_back("2 ($FF8)"); items.push_back("3 ($FF9)"); 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 CartridgeF6Widget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$FF6", "$FF7", "$FF8", "$FF9" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/CartF4Widget.cxx0000644000175000001440000000637012266336753020534 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF4Widget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 << "\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 = $" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Atari", info.str(), 15) + myLineHeight; VariantList items; items.push_back("0 ($FF4)"); items.push_back("1 ($FF5)"); items.push_back("2 ($FF6)"); items.push_back("3 ($FF7)"); items.push_back("4 ($FF8)"); items.push_back("5 ($FF9)"); items.push_back("6 ($FFA)"); items.push_back("7 ($FFB)"); 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 CartridgeF4Widget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$FF4", "$FF5", "$FF6", "$FF7", "$FF8", "$FF9", "$FFA", "$FFB" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/Cart4KSCWidget.hxx0000644000175000001440000000253512266336753020773 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart4KSCWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } // No implementation for non-bankswitched ROMs void loadConfig() { } void handleCommand(CommandSender* sender, int cmd, int data, int id) { } }; #endif stella-3.9.3/src/debugger/gui/Cart4A50Widget.cxx0000644000175000001440000002066312266336753020675 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart4A50Widget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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) items16.push_back(i); items16.push_back("Inactive", ""); for(uInt32 i = 0; i < 32; ++i) items32.push_back(i); items32.push_back("Inactive", ""); for(uInt32 i = 0; i < 128; ++i) items128.push_back(i); items128.push_back("Inactive", ""); for(uInt32 i = 0; i < 256; ++i) items256.push_back(i); items256.push_back("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, kTextAlignLeft); 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, kTextAlignLeft); 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, kTextAlignLeft); 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 = " << 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-3.9.3/src/debugger/gui/CartCVWidget.cxx0000644000175000001440000000316412266336753020571 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartCVWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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) { // 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()); } stella-3.9.3/src/debugger/gui/CartARWidget.hxx0000644000175000001440000000264412266336753020572 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartARWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeAR& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/PromptWidget.cxx0000644000175000001440000005674612266336753020746 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: PromptWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include #include "ScrollBarWidget.hxx" #include "FrameBuffer.hxx" #include "EventHandler.hxx" #include "Version.hxx" #include "Debugger.hxx" #include "DebuggerDialog.hxx" #include "DebuggerParser.hxx" #include "StringList.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), _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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PromptWidget::~PromptWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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, int button, 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::handleKeyDown(StellaKey key, StellaMod mod, char ascii) { int i; 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 (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 > 256) len = 256; int lastDelimPos = -1; char delimiter = '\0'; char str[256]; for (i = 0; i < len; i++) { str[i] = buffer(_promptStartPos + i) & 0x7f; if(strchr("{*@<> ", str[i]) != NULL ) { lastDelimPos = i; delimiter = str[i]; } } str[len] = '\0'; StringList list; string completionList; string prefix; if(lastDelimPos < 0) { // no delimiters, do command completion: const DebuggerParser& parser = instance().debugger().parser(); parser.getCompletions(str, 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, str); } else { // we got a delimiter, so this must be a label or a function const Debugger& dbg = instance().debugger(); dbg.cartDebug().getCompletions(str + lastDelimPos + 1, list); dbg.getCompletions(str + 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, str + lastDelimPos + 1); } 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; for(i=0; i 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 (instance().eventHandler().kbdShift(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 (instance().eventHandler().kbdShift(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 (instance().eventHandler().kbdShift(mod)) { _scrollLine = _firstLineInBuffer + _linesPerPage - 1; updateScrollBuffer(); } else _currentPos = _promptStartPos; dirty = true; break; case KBDK_END: if (instance().eventHandler().kbdShift(mod)) { _scrollLine = _promptEndPos / _lineWidth; if (_scrollLine < _linesPerPage - 1) _scrollLine = _linesPerPage - 1; updateScrollBuffer(); } else _currentPos = _promptEndPos; dirty = true; break; case KBDK_UP: if (instance().eventHandler().kbdShift(mod)) { if(_scrollLine <= _firstLineInBuffer + _linesPerPage - 1) break; _scrollLine -= 1; updateScrollBuffer(); dirty = true; } else historyScroll(+1); break; case KBDK_DOWN: if (instance().eventHandler().kbdShift(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 (instance().eventHandler().kbdControl(mod)) { specialKeys(key); } else if (instance().eventHandler().kbdAlt(mod)) { } else if (isprint(ascii)) { for (i = _promptEndPos - 1; i >= _currentPos; i--) buffer(i + 1) = buffer(i); _promptEndPos++; putchar(ascii); scrollToCurrent(); } else handled = false; break; } // Take care of changes made above if(dirty) { setDirty(); draw(); } // 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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::insertIntoPrompt(const char* str) { unsigned int l = strlen(str); for (int i = _promptEndPos - 1; i >= _currentPos; i--) buffer(i + l) = buffer(i); for (unsigned int j = 0; j < l; ++j) { _promptEndPos++; putcharIntern(str[j]); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case kSetPositionCmd: int newPos = (int)data + _linesPerPage - 1 + _firstLineInBuffer; if (newPos != _scrollLine) { _scrollLine = newPos; setDirty(); draw(); } 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) { // Display greetings & prompt string version = string("Stella ") + STELLA_VERSION + "\n"; print(version.c_str()); print(PROMPT); // Take care of one-time debugger stuff print(instance().debugger().autoExec().c_str()); print(instance().debugger().cartDebug().loadConfigFile() + "\n"); print(instance().debugger().cartDebug().loadListFile() + "\n"); print(instance().debugger().cartDebug().loadSymbolFile() + "\n"); print(PROMPT); _promptStartPos = _promptEndPos = _currentPos; _firstTime = false; _exitedEarly = false; } else if(_exitedEarly) { printPrompt(); _exitedEarly = false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int PromptWidget::getWidth() const { return _w + kScrollBarWidth; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::specialKeys(int keycode) { bool handled = false; switch (keycode) { case 'a': _currentPos = _promptStartPos; handled = true; break; case 'd': killChar(+1); handled = true; break; case 'e': _currentPos = _promptEndPos; handled = true; break; case 'k': killLine(+1); handled = true; break; case 'u': killLine(-1); handled = true; break; case 'w': killLastWord(); handled = true; break; } if(handled) { setDirty(); draw(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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::addToHistory(const char *str) { strcpy(_history[_historyIndex], str); _historyIndex = (_historyIndex + 1) % kHistorySize; _historyLine = 0; if (_historySize < kHistorySize) _historySize++; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int PromptWidget::compareHistory(const char *histLine) { return 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 ((direction < 0 && line < 0) || (direction > 0 && line > _historySize)) return; // 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(); draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 = BSPF_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]; int count = BSPF_vsnprintf(buf, sizeof(buf), format, argptr); print(buf); return count; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::putchar(int c) { putcharIntern(c); setDirty(); draw(); // FIXME - not nice to redraw the full console just for one char! } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 < 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 { buffer(_currentPos) = c | (_textcolor << 8) | (_inverse << 17); _currentPos++; if ((_scrollLine + 1) * _lineWidth == _currentPos) { _scrollLine++; updateScrollBuffer(); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::print(const string& str) { const char* c = str.c_str(); while(*c) 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(string& filename) { ofstream out(filename.c_str()); 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; } out.close(); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string PromptWidget::getCompletionPrefix(const StringList& completions, string prefix) { // Search for prefix in every string, progressively growing it // Once a mismatch is found or length is past one of the strings, we're done // We *could* use the longest common string algorithm, but for the lengths // of the strings we're dealing with, it's probably not worth it for(;;) { for(uInt32 i = 0; i < completions.size(); ++i) { const string& s = completions[i]; if(s.length() < prefix.length()) return prefix; // current prefix is the best we're going to get else if(!BSPF_startsWithIgnoreCase(s, prefix)) { prefix.erase(prefix.length()-1); return prefix; } } if(completions[0].length() > prefix.length()) prefix = completions[0].substr(0, prefix.length() + 1); else return prefix; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::clearScreen() { // Initialize start position and history _currentPos = 0; _scrollLine = _linesPerPage - 1; _firstLineInBuffer = 0; _promptStartPos = _promptEndPos = -1; memset(_buffer, 0, kBufferSize * sizeof(int)); _historyIndex = 0; _historyLine = 0; _historySize = 0; for (int i = 0; i < kHistorySize; i++) _history[i][0] = '\0'; if(!_firstTime) updateScrollBuffer(); } stella-3.9.3/src/debugger/gui/NullControlWidget.hxx0000644000175000001440000000376312266336753021734 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: NullControlWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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) { bool leftport = controller.jack() == Controller::Left; ostringstream buf; buf << (leftport ? "Left (" : "Right (") << controller.name() << "):"; const int fontHeight = font.getFontHeight(), lineHeight = font.getLineHeight(), lwidth = BSPF_max(font.getStringWidth(buf.str()), font.getStringWidth("Controller input")); new StaticTextWidget(boss, font, x, y+2, lwidth, fontHeight, buf.str(), kTextAlignLeft); new StaticTextWidget(boss, font, x, y+2+2*lineHeight, lwidth, fontHeight, "Controller input", kTextAlignCenter); new StaticTextWidget(boss, font, x, y+2+3*lineHeight, lwidth, fontHeight, "not available", kTextAlignCenter); } virtual ~NullControlWidget() { }; }; #endif stella-3.9.3/src/debugger/gui/CartF0Widget.cxx0000644000175000001440000000651212266336753020526 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF0Widget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 << "\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 " << dec << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << "\n"; } int xpos = 10, ypos = addBaseInformation(size, "Dynacom Megaboy", info.str()) + myLineHeight; VariantList items; items.push_back(" 0"); items.push_back(" 1"); items.push_back(" 2"); items.push_back(" 3"); items.push_back(" 4"); items.push_back(" 5"); items.push_back(" 6"); items.push_back(" 7"); items.push_back(" 8"); items.push_back(" 9"); items.push_back(" 10"); items.push_back(" 11"); items.push_back(" 12"); items.push_back(" 13"); items.push_back(" 14"); items.push_back(" 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() { myBank->setSelectedIndex(myCart.myCurrentBank); 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 = " << dec << myCart.myCurrentBank << ", hotspot = $FF0"; return buf.str(); } stella-3.9.3/src/debugger/gui/CartUAWidget.cxx0000644000175000001440000000602112266336753020561 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartUAWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 << "\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; items.push_back("0 ($220)"); items.push_back("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() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$200", "$240" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/CartCMWidget.hxx0000644000175000001440000000353612266336753020570 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartCMWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void saveOldState(); void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: struct CartState { uInt8 swcha; uInt8 column; }; private: 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' }; }; #endif stella-3.9.3/src/debugger/gui/CartCTYWidget.hxx0000644000175000001440000000266012266336753020725 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartCTYWidget.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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() { } void loadConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id); string bankState(); private: CartridgeCTY& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; }; #endif stella-3.9.3/src/debugger/gui/CartSBWidget.cxx0000644000175000001440000000646012266336753020567 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartSBWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 = " << 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 " << dec << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << " (hotspot = $" << spot << ")\n"; bank << dec << setw(2) << setfill(' ') << i << " ($" << Common::Base::HEX2 << spot << ")"; items.push_back(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() { myBank->setSelectedIndex(myCart.myCurrentBank); 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 = " << dec << myCart.myCurrentBank << ", hotspot = $" << Common::Base::HEX2 << (myCart.myCurrentBank + 0x800); return buf.str(); } stella-3.9.3/src/debugger/gui/CartF8SCWidget.cxx0000644000175000001440000000617512266336753020771 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF8SCWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 << "\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 = $" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Atari", info.str()) + myLineHeight; VariantList items; items.push_back("0 ($FF8)"); items.push_back("1 ($FF9)"); 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 CartridgeF8SCWidget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$FF8", "$FF9" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/CartF6SCWidget.cxx0000644000175000001440000000632012266336753020757 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF6SCWidget.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 << "\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 = $" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Atari", info.str()) + myLineHeight; VariantList items; items.push_back("0 ($FF6)"); items.push_back("1 ($FF7)"); items.push_back("2 ($FF8)"); items.push_back("3 ($FF9)"); 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 CartridgeF6SCWidget::loadConfig() { myBank->setSelectedIndex(myCart.myCurrentBank); 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* spot[] = { "$FF6", "$FF7", "$FF8", "$FF9" }; buf << "Bank = " << dec << myCart.myCurrentBank << ", hotspot = " << spot[myCart.myCurrentBank]; return buf.str(); } stella-3.9.3/src/debugger/gui/RomListSettings.hxx0000644000175000001440000000367612266336753021432 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RomListSettings.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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(); /** 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(); private: void loadConfig(); void handleMouseDown(int x, int y, int button, int clickCount); void handleCommand(CommandSender* sender, int cmd, int data, int id); private: uInt32 _xorig, _yorig; int _item; // currently selected line number in the disassembly list CheckboxWidget* myShowTentative; CheckboxWidget* myShowAddresses; CheckboxWidget* myShowGFXBinary; CheckboxWidget* myUseRelocation; }; #endif stella-3.9.3/src/cheat/0000755000175000001440000000000012267274562014267 5ustar stephenusersstella-3.9.3/src/cheat/CheetahCheat.hxx0000644000175000001440000000223512266336753017330 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CheetahCheat.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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); ~CheetahCheat(); virtual bool enable(); virtual bool disable(); virtual void evaluate(); private: uInt8 savedRom[16]; uInt16 address; uInt8 value; uInt8 count; }; #endif stella-3.9.3/src/cheat/module.mk0000644000175000001440000000040410335471710016067 0ustar stephenusersMODULE := 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-3.9.3/src/cheat/RamCheat.hxx0000644000175000001440000000214212266336753016503 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RamCheat.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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(); virtual bool enable(); virtual bool disable(); virtual void evaluate(); private: uInt16 address; uInt8 value; }; #endif stella-3.9.3/src/cheat/Cheat.hxx0000644000175000001440000000356612266336753016056 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cheat.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CHEAT_HXX #define CHEAT_HXX class OSystem; #include "StringList.hxx" #include "bspf.hxx" class Cheat { public: Cheat(OSystem* osystem, const string& name, const string& code) : myOSystem(osystem), myName(name), myCode(code), myEnabled(false) { if(name == "") myName = code; myName = StringList::removePattern(myName, "\":"); } virtual ~Cheat() { } 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(unsigned int i=0; i= '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; }; #endif stella-3.9.3/src/cheat/CheetahCheat.cxx0000644000175000001440000000412012266336753017316 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CheetahCheat.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CheetahCheat::~CheetahCheat() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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-3.9.3/src/cheat/RamCheat.cxx0000644000175000001440000000355512266336753016507 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: RamCheat.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RamCheat::~RamCheat() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RamCheat::enable() { if(!myEnabled) { myEnabled = true; myOSystem->cheat().addPerFrame(this, myEnabled); } return myEnabled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RamCheat::disable() { if(myEnabled) { myEnabled = false; myOSystem->cheat().addPerFrame(this, myEnabled); } return myEnabled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RamCheat::evaluate() { myOSystem->console().system().poke(address, value); } stella-3.9.3/src/cheat/CheatManager.hxx0000644000175000001440000001124512266336753017342 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CheatManager.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CHEAT_MANAGER_HXX #define CHEAT_MANAGER_HXX #include class Cheat; class OSystem; #include "bspf.hxx" #include "Array.hxx" typedef Common::Array CheatList; typedef map CheatCodeMap; /** 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 @version $Id: CheatManager.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class CheatManager { public: CheatManager(OSystem* osystem); virtual ~CheatManager(); /** 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 The cheat (if was created), else NULL. */ const Cheat* add(const string& name, const string& code, bool enable = true, int idx = -1); /** Remove the cheat at 'idx' from the cheat list(s). @param index 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 cheat The actual cheat object @param enable Add or remove the cheat to the per-frame list */ void addPerFrame(Cheat* cheat, 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); 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 NULL. */ const Cheat* createCheat(const string& name, const string& code); /** 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); /** Clear all per-ROM cheats lists. */ void clear(); private: OSystem* myOSystem; CheatList myCheatList; CheatList myPerFrameList; CheatCodeMap 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; }; #endif stella-3.9.3/src/cheat/CheatCodeDialog.hxx0000644000175000001440000000360312266336753017761 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CheatCodeDialog.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 InputTextDialog; class OptionsDialog; class OSystem; #include "Dialog.hxx" class CheatCodeDialog : public Dialog { public: CheatCodeDialog(OSystem* osystem, DialogContainer* parent, const GUI::Font& font); ~CheatCodeDialog(); protected: virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); void loadConfig(); void saveConfig(); private: void addCheat(); void editCheat(); void removeCheat(); void addOneShotCheat(); private: CheckListWidget* myCheatList; InputTextDialog* myCheatInput; ButtonWidget* myEditButton; ButtonWidget* myRemoveButton; enum { kAddCheatCmd = 'CHTa', kEditCheatCmd = 'CHTe', kAddOneShotCmd = 'CHTo', kCheatAdded = 'CHad', kCheatEdited = 'CHed', kOneShotCheatAdded = 'CHoa', kRemCheatCmd = 'CHTr' }; }; #endif stella-3.9.3/src/cheat/BankRomCheat.hxx0000644000175000001440000000226012266336753017316 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: BankRomCheat.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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); ~BankRomCheat(); virtual bool enable(); virtual bool disable(); virtual void evaluate(); private: uInt8 savedRom[16]; uInt16 address; uInt8 value; uInt8 count; int bank; }; #endif stella-3.9.3/src/cheat/CheatManager.cxx0000644000175000001440000002266412266336753017344 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CheatManager.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "OSystem.hxx" #include "Console.hxx" #include "Cheat.hxx" #include "Settings.hxx" #include "CheetahCheat.hxx" #include "BankRomCheat.hxx" #include "RamCheat.hxx" #include "CheatManager.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CheatManager::CheatManager(OSystem* osystem) : myOSystem(osystem), myCurrentCheat(""), myListIsDirty(false) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CheatManager::~CheatManager() { saveCheatDatabase(); myCheatMap.clear(); clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Cheat* CheatManager::add(const string& name, const string& code, bool enable, int idx) { Cheat* cheat = (Cheat*) createCheat(name, code); if(!cheat) return NULL; // Delete duplicate entries for(unsigned int i = 0; i < myCheatList.size(); i++) { if(myCheatList[i]->name() == name || myCheatList[i]->code() == code) { myCheatList.remove_at(i); break; } } // Add the cheat to the main cheat list if(idx == -1) myCheatList.push_back(cheat); else myCheatList.insert_at(idx, cheat); // And enable/disable it (the cheat knows how to enable or disable itself) if(enable) cheat->enable(); else cheat->disable(); return cheat; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::remove(int idx) { if((unsigned int)idx >= myCheatList.size()) return; Cheat* c = myCheatList[idx]; // First remove it from the per-frame list addPerFrame(c, false); // Then remove it from the cheatlist entirely myCheatList.remove_at(idx); c->disable(); delete c; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::addPerFrame(Cheat* cheat, bool enable) { if(!cheat) return; // Make sure there are no duplicates bool found = false; unsigned int 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) myPerFrameList.remove_at(i); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::addOneShot(const string& name, const string& code) { Cheat* cheat = (Cheat*) createCheat(name, code); if(!cheat) return; // Evaluate this cheat once, and then immediately delete it cheat->evaluate(); delete cheat; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Cheat* CheatManager::createCheat(const string& name, const string& code) { if(!isValidCode(code)) return NULL; // Create new cheat based on string length switch(code.size()) { case 4: return new RamCheat(myOSystem, name, code); break; case 6: return new CheetahCheat(myOSystem, name, code); break; case 8: return new BankRomCheat(myOSystem, name, code); break; default: return NULL; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(unsigned int i = 0; i < myCheatList.size(); i++) { if(myCheatList[i]->code() == code) { if(enable) myCheatList[i]->enable(); else myCheatList[i]->disable(); break; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::loadCheatDatabase() { const string& cheatfile = myOSystem->cheatFile(); ifstream in(cheatfile.c_str(), ios::in); 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.insert(make_pair(md5, cheat)); } in.close(); myListIsDirty = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::saveCheatDatabase() { if(!myListIsDirty) return; const string& cheatfile = myOSystem->cheatFile(); ofstream out(cheatfile.c_str(), ios::out); if(!out) return; CheatCodeMap::iterator iter; for(iter = myCheatMap.begin(); iter != myCheatMap.end(); ++iter) out << "\"" << iter->first << "\" " << "\"" << iter->second << "\"" << endl; out.close(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::loadCheats(const string& md5sum) { 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", ""); CheatCodeMap::iterator 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(unsigned int 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) { CheatCodeMap::iterator 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.insert(make_pair(md5sum, cheats.str())); } // Update the dirty flag myListIsDirty = myListIsDirty || changed; clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::clear() { // Don't delete the items from per-frame list, since it will be done in // the following loop myPerFrameList.clear(); for(unsigned int i = 0; i < myCheatList.size(); i++) delete myCheatList[i]; myCheatList.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CheatManager::isValidCode(const string& code) { for(unsigned int i = 0; i < code.size(); i++) if(!isxdigit(code[i])) return false; int length = code.length(); return (length == 4 || length == 6 || length == 8); } stella-3.9.3/src/cheat/CheatCodeDialog.cxx0000644000175000001440000001742312266336753017761 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CheatCodeDialog.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "bspf.hxx" #include "Cheat.hxx" #include "CheatManager.hxx" #include "CheckListWidget.hxx" #include "DialogContainer.hxx" #include "Dialog.hxx" #include "InputTextDialog.hxx" #include "OSystem.hxx" #include "Props.hxx" #include "StringList.hxx" #include "Widget.hxx" #include "CheatCodeDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CheatCodeDialog::CheatCodeDialog(OSystem* osystem, DialogContainer* parent, const GUI::Font& font) : Dialog(osystem, parent, 0, 0, 0, 0) { 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", kAddCheatCmd); wid.push_back(b); ypos += lineHeight + 10; myEditButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Edit", 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", 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: "); myCheatInput = new InputTextDialog(this, font, labels); myCheatInput->setTarget(this); addToFocusList(wid); // Add OK and Cancel buttons wid.clear(); addOKCancelBGroup(wid, font); addBGroupToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CheatCodeDialog::~CheatCodeDialog() { delete myCheatInput; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(unsigned int i = 0; i < list.size(); ++i) { l.push_back(list[i]->name()); b.push_back(bool(list[i]->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(unsigned int 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 kOKCmd: saveConfig(); close(); break; case 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-3.9.3/src/cheat/BankRomCheat.cxx0000644000175000001440000000475412266336753017323 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: BankRomCheat.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BankRomCheat::~BankRomCheat() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool BankRomCheat::enable() { evaluate(); return myEnabled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool BankRomCheat::disable() { int oldBank = myOSystem->console().cartridge().bank(); 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().bank(); 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-3.9.3/src/unix/0000755000175000001440000000000012267274562014166 5ustar stephenusersstella-3.9.3/src/unix/SerialPortUNIX.hxx0000644000175000001440000000341112266336753017506 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SerialPortUNIX.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: SerialPortUNIX.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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); /** Close a previously opened serial port. */ void closePort(); /** 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); private: // File descriptor for serial connection int myHandle; }; #endif stella-3.9.3/src/unix/stella.spec0000644000175000001440000001351712267025147016326 0ustar stephenusers%define name stella %define version 3.9.3 %define rel 1 %define enable_gl 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: http://stella.sourceforge.net Source: %{name}-%{version}.tar.bz2 BuildRoot: %_tmppath/%name-%version-%release-root BuildRequires: SDL-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_gl --enable-gl \ %else --disable-gl \ %endif %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 --force-builtin-zlib \ --docdir=%{_docdir}/stella \ --x-libraries=%{_prefix}/X11R6/%{_lib} %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 * 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-3.9.3/src/unix/OSystemUNIX.hxx0000644000175000001440000000261012266336753017025 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: OSystemUNIX.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef OSYSTEM_UNIX_HXX #define OSYSTEM_UNIX_HXX #include "bspf.hxx" /** This class defines UNIX-like OS's (Linux) system specific settings. @author Stephen Anthony @version $Id: OSystemUNIX.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class OSystemUNIX : public OSystem { public: /** Create a new UNIX-specific operating system object */ OSystemUNIX(); /** Destructor */ virtual ~OSystemUNIX(); public: /** Move X11 window to given position. Width and height are not used (or modified). */ void setAppWindowPos(int x, int y, /* not used*/ int, int); }; #endif stella-3.9.3/src/unix/stella.desktop0000644000175000001440000000026112172763165017041 0ustar stephenusers[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-3.9.3/src/unix/module.mk0000644000175000001440000000034310774033562015776 0ustar stephenusersMODULE := 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-3.9.3/src/unix/SettingsUNIX.hxx0000644000175000001440000000235012266336753017223 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SettingsUNIX.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef SETTINGS_UNIX_HXX #define SETTINGS_UNIX_HXX class OSystem; #include "bspf.hxx" /** This class defines UNIX-like OS's (Linux) system specific settings. @author Stephen Anthony @version $Id: SettingsUNIX.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class SettingsUNIX : public Settings { public: /** Create a new UNIX settings object */ SettingsUNIX(OSystem* osystem); /** Destructor */ virtual ~SettingsUNIX(); }; #endif stella-3.9.3/src/unix/SerialPortUNIX.cxx0000644000175000001440000000426312266336753017507 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SerialPortUNIX.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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-3.9.3/src/unix/OSystemUNIX.cxx0000644000175000001440000000460412266336753017025 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: OSystemUNIX.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #if defined(HAVE_X11) #include #include #endif #include "bspf.hxx" #include "OSystem.hxx" #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() { setBaseDir("~/.stella"); setConfigFile("~/.stella/stellarc"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OSystemUNIX::~OSystemUNIX() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystemUNIX::setAppWindowPos(int x, int y, int, int) { #if defined(HAVE_X11) // TODO: This functionality is deprecated, since the x/y fields // of XSizeHints are obsolete. SDL2 will provide native methods // for app centering (which is all this is currently used for). SDL_SysWMinfo sdl_info; memset(&sdl_info, 0, sizeof(sdl_info)); SDL_VERSION (&sdl_info.version); if(SDL_GetWMInfo(&sdl_info) > 0 && sdl_info.subsystem == SDL_SYSWM_X11) { Display* display = sdl_info.info.x11.display; Window window = sdl_info.info.x11.wmwindow; XSizeHints hints; long supplied_return; XGetWMNormalHints(display, window, &hints, &supplied_return); // Change X/Y position hints.x = x; hints.y = y; XMoveWindow(display, window, hints.x, hints.y); // Flush the resize event so we don't catch it later XSync(display, True); XSetWMNormalHints(display, window, &hints); } #endif } stella-3.9.3/src/unix/FSNodePOSIX.hxx0000644000175000001440000000537212266336753016667 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FSNodePOSIX.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 #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 { return access(_path.c_str(), F_OK) == 0; } const string& getName() const { return _displayName; } const string& getPath() const { return _path; } string getShortPath() const; bool isDirectory() const { return _isDirectory; } bool isFile() const { return _isFile; } bool isReadable() const { return access(_path.c_str(), R_OK) == 0; } bool isWritable() const { return access(_path.c_str(), W_OK) == 0; } bool makeDir(); bool rename(const string& newfile); bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const; AbstractFSNode* getParent() const; protected: string _displayName; string _path; bool _isDirectory; bool _isFile; bool _isValid; private: /** * Tests and sets the _isValid and _isDirectory/_isFile flags, * using the stat() function. */ virtual void setFlags(); }; #endif stella-3.9.3/src/unix/SettingsUNIX.cxx0000644000175000001440000000233612266336753017222 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SettingsUNIX.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "Settings.hxx" #include "SettingsUNIX.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SettingsUNIX::SettingsUNIX(OSystem* osystem) : Settings(osystem) { setInternal("gl_lib", "libGL.so"); // Most Linux GL implementations don't support this yet setInternal("gl_vsync", "false"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SettingsUNIX::~SettingsUNIX() { } stella-3.9.3/src/unix/FSNodePOSIX.cxx0000644000175000001440000001551312266336753016660 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FSNodePOSIX.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "FSNodePOSIX.hxx" /** * 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. */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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() { // The root dir. _path = "/"; _displayName = _path; _isValid = true; _isDirectory = true; _isFile = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNodePOSIX::FilesystemNodePOSIX(const string& p, bool verify) { // 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 != NULL) _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 != NULL && 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 == NULL) return false; // loop over dir entries using readdir while ((dp = readdir(dirp)) != NULL) { // 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.push_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 0; const char *start = _path.c_str(); const char *end = lastPathComponent(_path); return new FilesystemNodePOSIX(string(start, end - start)); } stella-3.9.3/src/win32/0000755000175000001440000000000012267274562014145 5ustar stephenusersstella-3.9.3/src/win32/Stella.vcxproj0000644000175000001440000012156612267274277017024 0ustar stephenusers Debug Win32 Debug x64 Release Win32 Release x64 {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD} Stella Win32Proj Application MultiByte v110_xp Application MultiByte v110_xp Application MultiByte v110 Application MultiByte v110 <_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 C:\Users\stephen\Source\sdl\include;$(IncludePath) C:\Users\stephen\Source\sdl\lib64;$(LibraryPath) C:\Users\stephen\Source\sdl\include;$(IncludePath) C:\Users\stephen\Source\sdl\lib32;$(LibraryPath) C:\Users\stephen\Source\sdl\include;$(IncludePath) C:\Users\stephen\Source\sdl\lib32;$(LibraryPath) C:\Users\stephen\Source\sdl\include;$(IncludePath) C:\Users\stephen\Source\sdl\lib64;$(LibraryPath) /MP %(AdditionalOptions) Disabled ..\yacc;..\emucore;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\win32;..\cheat;..\zlib;..\libpng;%(AdditionalIncludeDirectories) BSPF_WIN32;WIN32;NDEBUG;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;THUMB_SUPPORT;DISPLAY_OPENGL;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions) false EnableFastChecks MultiThreaded Level2 EditAndContinue SDL.lib SDLmain.lib %(AdditionalOptions) sdl.lib;sdlmain.lib;%(AdditionalDependencies) $(OutDir)Stella.exe true $(OutDir)Stella.pdb Console false MachineX86 X64 /MP %(AdditionalOptions) Disabled ..\yacc;..\emucore;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\win32;..\cheat;..\zlib;..\libpng;%(AdditionalIncludeDirectories) BSPF_WIN32;WIN32;NDEBUG;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;THUMB_SUPPORT;DISPLAY_OPENGL;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions) false EnableFastChecks MultiThreaded Level2 ProgramDatabase SDL.lib SDLmain.lib %(AdditionalOptions) sdl.lib;sdlmain.lib;%(AdditionalDependencies) $(OutDir)Stella.exe true $(OutDir)Stella.pdb Console false MachineX64 /MP %(AdditionalOptions) true false ..\yacc;..\emucore;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\win32;..\cheat;..\zlib;..\libpng;%(AdditionalIncludeDirectories) BSPF_WIN32;WIN32;NDEBUG;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;THUMB_SUPPORT;DISPLAY_OPENGL;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions) MultiThreaded false Level2 ProgramDatabase SDL.lib SDLmain.lib %(AdditionalOptions) sdl.lib;sdlmain.lib;%(AdditionalDependencies) $(OutDir)Stella.exe true Windows true true false MachineX86 X64 /MP %(AdditionalOptions) Full Default true ..\yacc;..\emucore;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\win32;..\cheat;..\zlib;..\libpng;%(AdditionalIncludeDirectories) BSPF_WIN32;WIN32;NDEBUG;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;THUMB_SUPPORT;DISPLAY_OPENGL;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions) MultiThreaded false Level2 ProgramDatabase SDL.lib SDLmain.lib %(AdditionalOptions) sdl.lib;sdlmain.lib;%(AdditionalDependencies) $(OutDir)Stella.exe false Windows true true false MachineX64 Full true true stella-3.9.3/src/win32/SerialPortWin32.hxx0000644000175000001440000000332012266336753017603 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SerialPortWin32.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef SERIALPORT_WIN32_HXX #define SERIALPORT_WIN32_HXX #include #include "SerialPort.hxx" /** Implement reading and writing from a serial port under Windows systems. @author Stephen Anthony @version $Id: SerialPortWin32.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class SerialPortWin32 : public SerialPort { public: SerialPortWin32(); virtual ~SerialPortWin32(); /** 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); /** Close a previously opened serial port. */ void closePort(); /** 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); private: // Handle to serial port HANDLE myHandle; }; #endif stella-3.9.3/src/win32/resource.h0000644000175000001440000000060511202550534016126 0ustar stephenusers//{{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-3.9.3/src/win32/Create_Builds.bat0000644000175000001440000000727311666751506017353 0ustar stephenusers@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%\SDL.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%\SDL.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-3.9.3/src/win32/SerialPortWin32.cxx0000644000175000001440000000442112266336753017601 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SerialPortWin32.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "SerialPortWin32.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SerialPortWin32::SerialPortWin32() : SerialPort(), myHandle(NULL) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SerialPortWin32::~SerialPortWin32() { closePort(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SerialPortWin32::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 SerialPortWin32::closePort() { if(myHandle) { CloseHandle(myHandle); myHandle = NULL; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SerialPortWin32::writeByte(const uInt8* data) { if(myHandle) { DWORD written; return WriteFile(myHandle, data, 1, &written, 0) == TRUE; } return false; } stella-3.9.3/src/win32/FSNodeWin32.hxx0000644000175000001440000000735612266336753016652 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FSNodeWin32.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef FS_NODE_WIN32_HXX #define FS_NODE_WIN32_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 FilesystemNodeWin32 : public AbstractFSNode { public: /** * Creates a FilesystemNodeWin32 with the root node as path. * * In regular windows systems, a virtual root path is used "". * In windows CE, the "\" root is used instead. */ FilesystemNodeWin32(); /** * Creates a FilesystemNodeWin32 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. */ FilesystemNodeWin32(const string& path); bool exists() const; const string& getName() const { return _displayName; } const string& getPath() const { return _path; } string getShortPath() const; bool isDirectory() const { return _isDirectory; } bool isFile() const { return _isFile; } bool isReadable() const; bool isWritable() const; bool makeDir(); bool rename(const string& newfile); bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const; AbstractFSNode* getParent() const; 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 FilesystemNodeWin32 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-3.9.3/src/win32/FSNodeWin32.cxx0000644000175000001440000002212312266336753016632 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FSNodeWin32.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #ifdef ARRAYSIZE #undef ARRAYSIZE #endif #ifdef _WIN32_WCE #include // winnt.h defines ARRAYSIZE, but we want our own one... #undef ARRAYSIZE #undef GetCurrentDirectory #endif #include #include #ifndef _WIN32_WCE #include // winnt.h defines ARRAYSIZE, but we want our own one... #undef ARRAYSIZE #endif // 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 "FSNodeWin32.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 FilesystemNodeWin32::exists() const { return _access(_path.c_str(), F_OK) == 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodeWin32::isReadable() const { return _access(_path.c_str(), R_OK) == 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodeWin32::isWritable() const { return _access(_path.c_str(), W_OK) == 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FilesystemNodeWin32::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 FilesystemNodeWin32::addFile(AbstractFSList& list, ListMode mode, const char* base, WIN32_FIND_DATA* find_data) { FilesystemNodeWin32 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.push_back(new FilesystemNodeWin32(entry)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - char* FilesystemNodeWin32::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* FilesystemNodeWin32::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 } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNodeWin32::FilesystemNodeWin32() { // Create a virtual root directory for standard Windows system _isDirectory = true; _isFile = false; _isValid = false; _path = ""; _isPseudoRoot = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNodeWin32::FilesystemNodeWin32(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 FilesystemNodeWin32::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 FilesystemNodeWin32:: 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) { FilesystemNodeWin32 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.push_back(new FilesystemNodeWin32(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 FilesystemNodeWin32::makeDir() { if(!_isPseudoRoot && CreateDirectory(_path.c_str(), NULL) != 0) { setFlags(); return true; } else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodeWin32::rename(const string& newfile) { if(!_isPseudoRoot && MoveFile(_path.c_str(), newfile.c_str()) != 0) { setFlags(); return true; } else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AbstractFSNode* FilesystemNodeWin32::getParent() const { if (!_isValid || _isPseudoRoot) return 0; FilesystemNodeWin32* p = new FilesystemNodeWin32(); if (_path.size() > 3) { const char *start = _path.c_str(); const char *end = lastPathComponent(_path); p->_path = string(start, end - start); p->_isValid = true; p->_isDirectory = true; p->_isFile = false; p->_displayName = lastPathComponent(p->_path); p->_isPseudoRoot = false; } return p; } stella-3.9.3/src/win32/stella.ico0000644000175000001440000030736611704125055016127 0ustar stephenusers€€ (f@@ (BŽ00 ¨%¶J  ¨^p ˆ  hŽŠ(€  (:FIA0 2NfuyoY<  7Vv•¨¥–€^8 :Z|©Ûïá¾}S+ <]€°è ÿ$ÿ ÿë¹”l? =_ƒ¸í "ÿ*Aÿ-Jÿ!6ÿþÖ¥‚V-#?`„º ò )ÿ&Fÿ)Kÿ)Iÿ)Gÿÿí¸•m@'Cd†ºñ (ÿ&Iÿ)Lÿ'Iÿ$Hÿ)Hÿ#5ÿüÒ¥‚V,+Iiоò#ÿ%Cÿ&Nÿ)Gÿ)Dÿ%Gÿ%Jÿ)Dÿÿì¹”l?,Ln½ ò *ÿ*Eÿ*Kÿ'Iÿ'Fÿ(Eÿ'Fÿ&Gÿ(Hÿ!5ÿýÔ¤€S*,LoÒó%ÿ'Gÿ*Kÿ(Hÿ(Fÿ'Fÿ'Fÿ'Fÿ'Eÿ'Gÿ'Dÿÿí·’i< 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ÿ!7ÿùÊ¢V- =^‚®Û ú#:ÿ(Hÿ(Kÿ%Iÿ&Fÿ'Fÿ(Fÿ(Eÿ'Fÿ'Fÿ'Fÿ(Eÿ&Gÿ'Fÿ'Eÿ(Gÿ'Cÿÿç·”m? =`…ºí ÿ.ÿ#Gÿ(Iÿ)Fÿ'Fÿ&Hÿ%Hÿ(Fÿ)Dÿ&Gÿ%Iÿ(Eÿ)Dÿ&Gÿ%Hÿ(Eÿ)Dÿ'Hÿ 3ÿýÙ¥}N% !=`…¼ò%2ÿ3Qÿ*Oÿ$Gÿ&Fÿ'Fÿ(Eÿ)Dÿ%Hÿ$Hÿ'Fÿ'Fÿ&Gÿ(Fÿ(Eÿ'Fÿ&Fÿ'Fÿ(Eÿ'Gÿ)Gÿ (ÿõº„U)  "?`…¼ò ':ÿLuÿHuÿ1Vÿ)Cÿ(Bÿ&Gÿ%Hÿ'Fÿ&Gÿ%Hÿ'Fÿ'Fÿ'Eÿ'Fÿ'Fÿ'Fÿ'Fÿ'Fÿ'Eÿ'Fÿ)Gÿ%Bÿ þÄP&  *5>@9+ $Bc‡¼ò!3ÿRƒÿi¢ÿT‡ÿ8\ÿ(Dÿ&Bÿ'Eÿ&Hÿ$Iÿ%Hÿ(Fÿ)Eÿ'Fÿ'Eÿ(Eÿ&Fÿ'Fÿ'Eÿ(Eÿ&Fÿ'Fÿ*Iÿ&Fÿ ø°oB   /ATdnphS8 &DfŠ¿ó $5ÿSƒÿt³ÿuµÿ]–ÿ?jÿ&JÿAÿ&Cÿ)Dÿ&Gÿ%Hÿ'Fÿ&Gÿ$Hÿ(Eÿ*Cÿ&Gÿ%Hÿ(Eÿ+Cÿ&Gÿ&Kÿ)Hÿ*þÓˆW00DZo€‘œ‘zX3%DgŽÅõ'9ÿYŠÿu·ÿ{Àÿvºÿf¤ÿL~ÿ1Wÿ Eÿ!Cÿ)Cÿ)Dÿ&Gÿ$Iÿ%Hÿ&Gÿ(Eÿ'Fÿ'Fÿ'Gÿ'Fÿ)Dÿ+Fÿ'Gÿ)ÿÝ’a; &?Yq†›µÓâÙº™wL&  !AfË ù*?ÿ]Žÿw¸ÿy¿ÿtºÿqµÿm®ÿ^“ÿAjÿ,Oÿ%Cÿ%Bÿ'Eÿ&Gÿ#Iÿ'Eÿ*Cÿ&Gÿ$Iÿ(Eÿ*Cÿ'Gÿ&Kÿ+Iÿ .ÿäžfA" -Igƒž¼Üô ÿÿ ÿè´Žd8 ;aË ú 3Lÿ_–ÿw»ÿv¼ÿs·ÿq´ÿpµÿrµÿi£ÿO€ÿ7_ÿ(Gÿ#Aÿ&Cÿ&Fÿ%Iÿ'Eÿ(Eÿ&Gÿ'Fÿ'Fÿ'Eÿ)Hÿ*Lÿ !5ÿ àŸjE$3Po“¼àøÿ&;ÿ5Uÿ=aÿ ,@ÿ üΞzL$  7[‡È ù 9Tÿdÿy¾ÿv½ÿqµÿq³ÿo²ÿqµÿt¸ÿn°ÿ^•ÿEqÿ-Sÿ!Dÿ$Bÿ'Fÿ+Mÿ'Lÿ%Iÿ(Eÿ*Bÿ'Fÿ%Kÿ+Jÿ&6ÿ óªoI($<Yw¡×ø ÿ ,Dÿ7]ÿ:cÿeÿ=jÿ9dÿ7aÿ7^ÿ;cÿ8]ÿ)ÿùÉ›tE 0Sy­ î7Mÿb˜ÿy½ÿu»ÿp´ÿq´ÿq´ÿn²ÿp³ÿo²ÿqµÿs¸ÿo¯ÿb—ÿJuÿ0Uÿ%Bÿ"Bÿ$Hÿ)Dÿ)Cÿ&Gÿ%Kÿ*Jÿ $7ÿùÅU2 0On޵ä!ÿ>^ÿFtÿ;iÿ7_ÿ6\ÿ6\ÿ7\ÿ:aÿ9`ÿ#?ÿ ÿ᪅X-)Mt©ç+8ÿTƒÿv·ÿw½ÿqµÿo²ÿp³ÿr´ÿn±ÿp³ÿn²ÿq´ÿqµÿq·ÿm«ÿWˆÿ   >bÐ ú(;ÿCiÿDoÿ8eÿ4_ÿ5`ÿ6_ÿ6aÿ6_ÿ6]ÿ6`ÿ6`ÿ6aÿ6`ÿ6aÿ7aÿ;dÿ8^ÿ9ÿ !ÿÿùÉŸ~]MY|Ç&þIuÿq±ÿw½ÿr¶ÿo²ÿp³ÿo²ÿp³ÿo²ÿp³ÿq´ÿp³ÿo²ÿo²ÿrµÿt¶ÿt·ÿs¶ÿt·ÿu¹ÿt¸ÿn°ÿ_›ÿmÿ:jÿ7gÿ9gÿJ{ÿf¢ÿw¼ÿu¼ÿo´ÿl°ÿl¯ÿk®ÿl¯ÿq¶ÿvºÿm¦ÿY‹ÿFsÿ:cÿ:cÿ;hÿmÿY’ÿo´ÿr·ÿm±ÿk¯ÿk®ÿk®ÿj­ÿm±ÿv»ÿq³ÿfžÿRƒÿ>iÿ5`ÿ:gÿ:gÿ>iÿ=iÿ;hÿ;hÿ8fÿ8gÿ8dÿ5_ÿ7dÿ8`ÿ&Fÿ(ÿ ÿ"ÿ ÿ'ÿ:bÿk¦ÿv¼ÿq¶ÿrµÿn±ÿm±ÿq´ÿrµÿo²ÿp²ÿq´ÿsµÿt·ÿt·ÿt¶ÿs¶ÿp²ÿr·ÿƒÊÿ‘Ùÿ†Ðÿp·ÿg¨ÿg¦ÿPzÿ õ³zK# %?]zžÒ÷.ÿ=dÿNÿM|ÿKuÿJsÿFpÿAmÿAlÿ@kÿ=iÿ:eÿ7cÿ5bÿ6cÿ6`ÿ3Yÿ1Wÿ@oÿaÿr·ÿoµÿl¯ÿk®ÿk®ÿk®ÿk¯ÿpµÿv»ÿp°ÿ_•ÿGvÿ9eÿ8cÿ:fÿ;hÿ;hÿ;gÿ;gÿ;gÿ;gÿ;gÿ;hÿiÿ>hÿ?kÿAmÿBoÿAmÿ4Uÿ/ÿ ÿ ÿ ÿ'Kÿ]”ÿw»ÿv»ÿq³ÿm°ÿq´ÿq´ÿm°ÿn±ÿrµÿt·ÿt·ÿt¶ÿt·ÿt¶ÿq´ÿq´ÿ€Æÿ‘ÙÿŠÑÿs¹ÿg«ÿf§ÿj¨ÿa–ÿ *<ÿÙ–h8,Lm‘¿êÿjÿ>hÿ8cÿ4bÿ5cÿ6eÿ6eÿ6aÿ6[ÿ6Xÿ4Uÿ0Sÿ6aÿQˆÿk®ÿpµÿl±ÿk®ÿk¯ÿk®ÿk®ÿqµÿy½ÿs³ÿežÿK|ÿ7eÿ6bÿ9eÿ>iÿ>iÿ?jÿ@kÿ@kÿAlÿ@kÿBoÿGtÿ>fÿ%>ÿ"ÿÿ%ÿ;cÿm§ÿx¼ÿq¶ÿo²ÿp²ÿo²ÿp³ÿo²ÿp³ÿrµÿt¶ÿt·ÿt·ÿs·ÿq´ÿq²ÿ|ÁÿØÿÕÿu¼ÿh­ÿh¬ÿf¡ÿi¤ÿ`’ÿ #0ÿÐ`2,Mp™Óù.ÿBjÿOƒÿL{ÿKvÿIsÿFpÿEpÿBnÿ@jÿjÿjÿ9fÿ9eÿ7dÿ5cÿ6eÿ6bÿ6]ÿ6]ÿ7[ÿ7Zÿ7Zÿ5Yÿ0Tÿ3Wÿ5Yÿ1Qÿ2Rÿ-Nÿ-NÿFoÿf¡ÿr¸ÿn´ÿk¯ÿk®ÿk®ÿm°ÿm±ÿt·ÿy½ÿn®ÿZŽÿFrÿ=gÿ=gÿ?jÿCnÿEpÿEqÿDpÿEpÿJvÿKwÿlÿ>mÿ;jÿ7hÿ8hÿ8fÿ6cÿ7]ÿ6[ÿ6Yÿ5Wÿ0Sÿ3Xÿ5Zÿ1Vÿ3Vÿ1Rÿ-Oÿ,Pÿ1Oÿ4Lÿ0Iÿ'Gÿ6]ÿ\Žÿr³ÿq·ÿl±ÿk®ÿl¯ÿj®ÿk®ÿs¶ÿ{¿ÿq²ÿ^“ÿJxÿAkÿCmÿFpÿFqÿEpÿEpÿGrÿFqÿDqÿ@iÿ'Eÿ!>ÿMyÿv´ÿv»ÿo³ÿo²ÿp³ÿs¶ÿt¶ÿt·ÿt¶ÿt·ÿt¶ÿr´ÿp²ÿ{Àÿ“Ûÿ’Ùÿw»ÿi¬ÿh¬ÿfŸÿcšÿ`šÿ^–ÿ`˜ÿe¡ÿ Ipÿ ÷º„T( .hÊ ý,ÿ @ÿ=ÿ9ÿ8ÿ7ÿ9ÿ;ÿ<ÿ @ÿ$Gÿ,Nÿ/Vÿ3^ÿ:cÿ;dÿ9`ÿ8[ÿ8[ÿ8\ÿ6Zÿ2Uÿ3Wÿ1Tÿ-Qÿ-Qÿ,Qÿ,Qÿ/Pÿ-Oÿ*Gÿ'Bÿ?ÿ"Eÿ?hÿdœÿr·ÿpµÿk¯ÿk®ÿk¯ÿj®ÿl°ÿx¼ÿÂÿo®ÿVÿFuÿDmÿEnÿCnÿDpÿGsÿFqÿAlÿAnÿBlÿ0Mÿ*IÿS„ÿv¸ÿt¹ÿm°ÿo²ÿt·ÿu¸ÿt¶ÿt¶ÿt¶ÿt·ÿt¶ÿq³ÿs¸ÿˆÑÿ–ßÿÈÿi­ÿe¦ÿf¤ÿe™ÿc–ÿ`•ÿ_•ÿa™ÿa¢ÿGqÿ ø»†W* *wî9ZÿCjÿ@gÿ;cÿ6_ÿ0Xÿ*Nÿ#Eÿ>ÿ7ÿ0ÿ+ÿ-ÿ2ÿ9ÿ&Bÿ/Jÿ1Rÿ6Yÿ:]ÿ:_ÿ;_ÿ7Yÿ0Rÿ.Rÿ3Sÿ+Nÿ'Mÿ(Lÿ-Hÿ(Iÿ"Hÿ%Dÿ#Cÿ=ÿ)HÿFwÿi¨ÿs¸ÿn²ÿk®ÿl¯ÿk®ÿj­ÿq´ÿ€Ãÿ{¾ÿc¡ÿOÿEoÿDmÿGqÿGsÿHsÿDoÿ?jÿAmÿAnÿ2Uÿ0QÿY‹ÿw»ÿtºÿo²ÿo²ÿs¶ÿt¶ÿt·ÿt·ÿt¶ÿt¶ÿs´ÿq²ÿ|Ãÿ“ßÿŽÖÿq¶ÿfªÿf¨ÿeŸÿc˜ÿ`•ÿ^”ÿ^•ÿ]™ÿ`¡ÿHrÿ ø¼‰Z, !] %4Úa—ÿn¨ÿk¤ÿe¡ÿbžÿ`™ÿZÿQ…ÿK{ÿCpÿ8`ÿ*Mÿ"Aÿ8ÿ.ÿ)ÿ+ÿ2ÿ!=ÿ(Gÿ.Qÿ7[ÿ5Vÿ.Sÿ.Sÿ0Pÿ.Pÿ,Oÿ'Iÿ'Dÿ&Eÿ(Dÿ*Eÿ(Dÿ#:ÿ8ÿ,RÿU‰ÿr³ÿq¶ÿl°ÿk¯ÿk®ÿi¬ÿi­ÿt·ÿ~Âÿr²ÿ]’ÿIxÿAmÿGqÿGsÿGrÿCoÿ@kÿ@lÿiÿ?kÿ@kÿAkÿlÿb›ÿw»ÿt¹ÿu·ÿt·ÿt¶ÿt¶ÿt¶ÿt¶ÿt·ÿs´ÿr²ÿ}Æÿ‘ßÿ‰Îÿo²ÿh«ÿh§ÿd™ÿ_“ÿ^“ÿ]”ÿ\–ÿ^—ÿZ’ÿ\–ÿO}ÿþΔh8'c ):Ñb™ÿn±ÿi©ÿh§ÿiªÿf¦ÿi©ÿh¬ÿhªÿl°ÿn²ÿoµÿpµÿp³ÿn®ÿeŸÿVÿGvÿ6\ÿ'Dÿ3ÿ(ÿ'ÿ.ÿ8ÿ#;ÿ+@ÿ+Gÿ)Kÿ'Hÿ$Cÿ"<ÿ5ÿ 7ÿ2ÿ4ÿ1WÿZÿr³ÿp¶ÿl°ÿo±ÿp³ÿo²ÿm°ÿ{¿ÿƒÆÿq°ÿZÿDqÿiÿAkÿAkÿiÿ=eÿCqÿcžÿvºÿu¹ÿt¸ÿt·ÿt·ÿs¶ÿs¶ÿt·ÿs¶ÿq³ÿr¶ÿ†Ïÿ’Ýÿ{Âÿi¬ÿg§ÿdžÿ^—ÿ^”ÿ_“ÿ[ÿY”ÿX–ÿUÿ[“ÿP€ÿ!ÿÓšp?/v 1Hág£ÿo±ÿiªÿi¬ÿiªÿk«ÿi©ÿf¥ÿj¬ÿi©ÿg¨ÿk¯ÿm°ÿqµÿs¶ÿp°ÿm«ÿeŸÿV‡ÿHmÿ2Sÿ9ÿ(ÿ $ÿ&ÿ+ÿ#6ÿ(Cÿ'@ÿ'<ÿ$;ÿ7ÿ!9ÿ6ÿ-ÿ8ÿ:dÿežÿs¸ÿm³ÿn±ÿrµÿn²ÿl¯ÿq´ÿ}ÀÿÁÿl¥ÿPÿ=hÿ9cÿ:eÿ;gÿ;hÿ:eÿ7aÿDrÿf¡ÿy¼ÿwºÿt·ÿt¶ÿt·ÿs¶ÿt·ÿt·ÿs¶ÿo²ÿu»ÿŽÙÿÚÿt»ÿf«ÿf¡ÿb˜ÿ[•ÿ`–ÿ`”ÿY’ÿW”ÿV‘ÿVÿZ‘ÿP€ÿ 'ÿÚ¢zJ!  : •Dkõp²ÿk­ÿg§ÿh¦ÿk«ÿj¨ÿg§ÿi¬ÿh¨ÿg¦ÿj¬ÿi«ÿk­ÿn±ÿm°ÿpµÿs¸ÿp²ÿmªÿ`—ÿJwÿ/Sÿ:ÿ/ÿ'ÿ%ÿ,ÿ2ÿ!8ÿ :ÿ"<ÿ :ÿ6ÿ3ÿ,ÿ>ÿHvÿn«ÿs¹ÿpµÿp³ÿo²ÿo²ÿn±ÿs¶ÿÃÿt¶ÿ]“ÿFrÿ4`ÿ2^ÿ5bÿ5bÿ3`ÿ0\ÿAqÿh¢ÿ{¾ÿwºÿt¶ÿt¶ÿt¶ÿt·ÿt·ÿt·ÿsµÿp±ÿxÀÿÜÿ‰Óÿn´ÿd¥ÿd›ÿb“ÿ\“ÿ\–ÿ^—ÿZ•ÿTÿUÿVÿXÿP‚ÿ !1ÿè®…V* "Q 'Â`–ÿq·ÿk¬ÿh¦ÿj«ÿj«ÿj¬ÿg©ÿf¦ÿj«ÿl°ÿl¯ÿl®ÿl®ÿl®ÿm°ÿn³ÿpµÿr¹ÿs¸ÿo¬ÿ_–ÿIyÿ4]ÿ%Fÿ1ÿ&ÿ#ÿ'ÿ1ÿ#;ÿ :ÿ7ÿ5ÿ(ÿ %ÿ'JÿXŒÿt¶ÿv¼ÿo³ÿn±ÿo³ÿn°ÿn²ÿz¾ÿ€Åÿr°ÿU‰ÿ8fÿ/[ÿ3_ÿ5bÿ3`ÿ0\ÿ?mÿf ÿz¾ÿvºÿt¶ÿs¶ÿt¶ÿt¶ÿt·ÿt·ÿr´ÿq²ÿÇÿ“ßÿ‚Íÿk¯ÿbžÿ^•ÿ`“ÿ^•ÿZ—ÿX–ÿVÿUŽÿVŒÿRˆÿT‹ÿT‰ÿ 0Jÿõ½c5-u 6Räm¯ÿp¶ÿk­ÿl®ÿj¬ÿi­ÿhªÿh¦ÿj«ÿiªÿk¬ÿl®ÿh¨ÿj«ÿk°ÿk¯ÿl°ÿm±ÿoµÿr¹ÿs·ÿo®ÿašÿN€ÿ9^ÿ'Cÿ-ÿ ÿ"ÿ)ÿ4ÿ7ÿ1ÿ)ÿ ÿ-ÿ6bÿf ÿx¼ÿs¹ÿp³ÿo²ÿm°ÿo²ÿt¹ÿ„ÉÿÅÿe¤ÿFxÿ4`ÿ1]ÿ4aÿ4aÿ0[ÿ;jÿdžÿ{¿ÿw¼ÿt¶ÿt¶ÿt¶ÿt·ÿt¶ÿt¶ÿq³ÿrµÿˆÎÿ—àÿ~Æÿg¥ÿa˜ÿ[”ÿ[•ÿ]–ÿ]•ÿWÿUÿ\“ÿVŠÿPƒÿSˆÿXÿAfÿ üËšrB : —Jwön³ÿm³ÿk°ÿk®ÿk¯ÿm´ÿm²ÿo²ÿn²ÿo²ÿm±ÿi©ÿi«ÿk¯ÿk¯ÿk®ÿk¯ÿk¯ÿm±ÿoµÿs¸ÿr·ÿk®ÿ^™ÿKzÿ8Xÿ:ÿ 'ÿ !ÿ+ÿ4ÿ)ÿ%ÿ!ÿ ÿ;ÿIxÿo­ÿv¼ÿt¹ÿo²ÿn±ÿn±ÿm±ÿz¾ÿ…Ìÿv¹ÿ\“ÿDoÿ4_ÿ2_ÿ4aÿ/[ÿ8hÿ_™ÿy½ÿw¼ÿt·ÿt·ÿt¶ÿt·ÿt·ÿs¶ÿp²ÿt·ÿŽÕÿ˜àÿy¿ÿbÿ`”ÿ^”ÿ[–ÿY–ÿ[ÿ[ŒÿWÿYŽÿU‡ÿP„ÿQ†ÿTŒÿGtÿ ÿÛ¥€R'  F ¤ ?`ñIsÿHoûIp÷Sƒüdÿi¦ÿkªÿl®ÿn±ÿp·ÿp¹ÿq·ÿp´ÿn²ÿl°ÿk¯ÿk¯ÿk®ÿl¯ÿm°ÿo³ÿr¸ÿq¶ÿjªÿ\“ÿApÿ'Mÿ5ÿ.ÿ.ÿ$ÿÿ%ÿ ÿ "ÿ)LÿWÿsµÿuºÿp´ÿn±ÿm°ÿn±ÿo´ÿ~Åÿ„Êÿt±ÿYŠÿ?iÿ1^ÿ3_ÿ0\ÿ6eÿZ‘ÿv¹ÿw½ÿt·ÿt¶ÿt¶ÿt·ÿt·ÿs¶ÿp±ÿuºÿÙÿ•ßÿt¸ÿ_—ÿ]’ÿ^•ÿ_–ÿ[–ÿX‘ÿYŒÿWÿR‰ÿQ…ÿR†ÿP…ÿP‡ÿJ{ÿ /ÿí¶Žc5 A ¯ •§ &Í #1í *;ð -Cü 6SÿQÿg¥ÿn°ÿo´ÿqºÿq¹ÿpµÿm±ÿl¯ÿl®ÿk®ÿl°ÿn±ÿp´ÿr¸ÿqµÿd£ÿS…ÿ=eÿ(Lÿ;ÿ.ÿ(ÿ(ÿ!ÿ ÿ-ÿ9cÿg¢ÿw¼ÿt¹ÿo²ÿo±ÿp³ÿm°ÿr¶ÿ†Êÿ‡Èÿm¦ÿKzÿ4`ÿ0\ÿ0\ÿ5bÿVˆÿu´ÿx¾ÿt¹ÿt¶ÿt¶ÿt¶ÿt¶ÿs¶ÿp±ÿu»ÿÚÿ‘Øÿo®ÿ[“ÿ[‘ÿ\•ÿ\•ÿY’ÿW’ÿTŠÿT‹ÿRˆÿQ…ÿQ…ÿOƒÿLÿMƒÿ1QÿûË›sD ):>?DXt€ ž¨³ !.Û -Dõ ?bþ[‘ÿl®ÿp¶ÿq¹ÿq·ÿn³ÿl°ÿl°ÿl¯ÿl°ÿn²ÿp¶ÿr¶ÿp®ÿc›ÿK~ÿ6_ÿ.Jÿ%:ÿ+ÿ ÿ ÿ ÿ=ÿO€ÿt´ÿw½ÿrµÿp²ÿo²ÿn±ÿn°ÿz¾ÿŠÎÿ|½ÿ[‘ÿ>jÿ1\ÿ/[ÿ3_ÿM~ÿp®ÿy¾ÿu¹ÿt¶ÿt·ÿt·ÿt·ÿs¶ÿp±ÿu¼ÿÛÿÔÿl¨ÿZ’ÿ\“ÿ[•ÿUÿUŒÿVÿS†ÿQ„ÿQ„ÿO‚ÿP‚ÿM€ÿI}ÿN…ÿCoÿÿß©ƒU+ !&.6=Hc† ¢ "Ç ,Að Ekÿ_™ÿn±ÿq¹ÿq¹ÿpµÿn±ÿl¯ÿl¯ÿl°ÿn³ÿq·ÿq¶ÿh¨ÿXŒÿFqÿ2Vÿ>ÿ,ÿ ÿ ÿ #ÿ.Uÿ`˜ÿw»ÿuºÿp³ÿo²ÿo²ÿm°ÿo´ÿÇÿˆÍÿs¯ÿO€ÿ8eÿ0\ÿ/[ÿAsÿh¤ÿz¾ÿvºÿt·ÿt¶ÿt·ÿt·ÿs¶ÿp²ÿy¾ÿ”ÜÿÓÿk§ÿY‘ÿY”ÿZ–ÿYÿWŒÿUÿRˆÿQ„ÿQ…ÿOÿM€ÿJ~ÿH|ÿMÿK}ÿ %8ÿð¹‘h: $.;T‚ ¬ )Ù 4NöS‚ÿh©ÿp·ÿr¹ÿp¶ÿn²ÿl¯ÿl¯ÿm°ÿo´ÿq¶ÿm®ÿ_˜ÿFxÿ3\ÿ(Hÿ 6ÿ$ÿÿ3ÿBnÿn©ÿw¼ÿq·ÿp´ÿo²ÿo²ÿn±ÿtºÿ‰ÏÿÄÿa™ÿDtÿ2`ÿ,Wÿ:jÿaœÿz½ÿw¼ÿt·ÿs¶ÿt¶ÿt·ÿs¶ÿp²ÿy¾ÿ”Ýÿ‘Ôÿk§ÿW‘ÿV”ÿY—ÿZÿUˆÿSŠÿRˆÿR…ÿS‡ÿP…ÿL€ÿH|ÿH{ÿK~ÿNÿ6SÿûÍ {M&  !-@aˆ ° *=à Enücÿp¶ÿrºÿp¶ÿm²ÿk¯ÿl°ÿo³ÿq¶ÿn¯ÿ]™ÿN€ÿCiÿ3Qÿ <ÿ)ÿ 'ÿ'IÿX‡ÿu´ÿu¼ÿs·ÿn²ÿp³ÿo±ÿl°ÿ}Äÿ‡Îÿs²ÿS‡ÿ9gÿ,Wÿ4dÿY’ÿv¹ÿx¼ÿt·ÿs¶ÿt¶ÿt·ÿs¶ÿo±ÿv¾ÿ’Ýÿ‘Õÿk¦ÿVÿUŽÿ[‘ÿWŠÿS‰ÿRˆÿQ…ÿQ„ÿPƒÿMÿI}ÿH|ÿH|ÿJ{ÿO}ÿEjÿÿä¯c7 #0Cj ¢ %3Û ElübŸÿq·ÿq¸ÿn´ÿl°ÿl°ÿm²ÿp³ÿm¯ÿg£ÿ[ŽÿFsÿ4[ÿ&Eÿ/ÿ2ÿ8\ÿc˜ÿwºÿu»ÿo²ÿp³ÿp³ÿl¯ÿs·ÿ…Êÿ†Éÿk¨ÿJ{ÿ1^ÿ1aÿQˆÿsµÿy¾ÿu¸ÿt¶ÿt¶ÿt·ÿs¶ÿo±ÿv½ÿ’Ýÿ“Øÿn«ÿWÿT‹ÿX‹ÿT‡ÿS‰ÿS‰ÿR…ÿN‚ÿM€ÿJ}ÿG{ÿH{ÿIzÿItÿMxÿIuÿ)<ÿ÷ÇžyL%  (=e   $3Ù Hqýg§ÿtºÿq·ÿm±ÿl¯ÿn±ÿr·ÿr·ÿm­ÿ^—ÿMÿoÿ1bÿEzÿl«ÿ{¿ÿvºÿt¶ÿt·ÿt·ÿs¶ÿp±ÿu¼ÿ‘Üÿ•Ýÿq²ÿV‘ÿRŒÿUŒÿR‡ÿQ…ÿR‡ÿQ†ÿM‚ÿL€ÿI|ÿG|ÿH{ÿHwÿIsÿKvÿJxÿ<^ÿÿå°Œb6&:d « 7Pëašÿq·ÿq¸ÿm²ÿn±ÿs¶ÿr¸ÿs·ÿo¯ÿbÿRˆÿ@jÿ-Iÿ7ÿ(IÿQÿs²ÿv¼ÿp´ÿo²ÿsµÿr´ÿu·ÿˆËÿ‘Ôÿx·ÿRŠÿ9jÿ=nÿaœÿz½ÿw»ÿt¶ÿt¶ÿt¶ÿs¶ÿp±ÿuºÿÛÿ–àÿt·ÿU‘ÿQ‰ÿUŒÿRˆÿQ„ÿQ…ÿO‚ÿL€ÿJ}ÿH|ÿH}ÿIyÿHtÿItÿKvÿLzÿFqÿ$7ÿøÇwJ$ (C ˆ %0ÜJsþi¨ÿt»ÿr¸ÿt·ÿrµÿs¶ÿs·ÿp²ÿf¤ÿT‹ÿBkÿ*Kÿ!@ÿ7]ÿa˜ÿu¹ÿt¸ÿr¶ÿt·ÿt¶ÿp³ÿy½ÿÔÿŒÏÿkªÿDzÿ;jÿWŒÿv¶ÿy¾ÿu¸ÿt¶ÿt·ÿs¶ÿp²ÿt»ÿÙÿ—ãÿx¾ÿV”ÿQ†ÿR†ÿQ…ÿQ…ÿNÿM€ÿJ~ÿG{ÿH|ÿIzÿHsÿIrÿIsÿGrÿFsÿFtÿ7Yÿÿá­‹b75h ± 8Qðc›ÿs¸ÿw¼ÿr¸ÿo³ÿr¶ÿs¸ÿm°ÿe£ÿZÿDmÿ,Qÿ,QÿK|ÿm­ÿuºÿt¸ÿt·ÿt·ÿq´ÿrµÿ‚Èÿ’×ÿÃÿX’ÿ@pÿJ{ÿl§ÿz¿ÿuºÿs¶ÿt·ÿt¶ÿq¶ÿr¹ÿ‰Ôÿ˜ãÿ{ÃÿY–ÿOƒÿO‚ÿQ„ÿM‚ÿMÿM€ÿI~ÿH}ÿI{ÿHvÿHrÿIsÿItÿEpÿBmÿBpÿ@mÿ#7ÿõÃzN&  &FŠ !0Ô Gmúi§ÿw½ÿs·ÿrµÿp´ÿp¶ÿn°ÿj¢ÿ\ÿBqÿ0[ÿ:hÿ^–ÿv¸ÿy½ÿu¹ÿt·ÿt¶ÿq³ÿt¸ÿˆÍÿÓÿt±ÿN‚ÿCtÿ\“ÿw¸ÿw¼ÿt·ÿt¶ÿt¶ÿr¶ÿp¶ÿ‚Êÿ™ßÿ…Çÿ`šÿOƒÿO‚ÿQ…ÿNÿM€ÿJ}ÿH|ÿI|ÿIxÿItÿHsÿJtÿItÿEpÿBmÿ@lÿ?oÿ2Vÿ þà°f;2\ ¢ 9Rëk¥ÿw¾ÿt»ÿs·ÿt¹ÿqµÿp±ÿmªÿ]“ÿCrÿ7dÿIzÿk¦ÿ{¾ÿw¼ÿs·ÿt·ÿrµÿo²ÿy¾ÿÔÿÌÿgŸÿI{ÿOƒÿmªÿy½ÿu¸ÿt·ÿt¹ÿr¸ÿn´ÿ}ÀÿšÚÿÎÿf£ÿP…ÿNÿP„ÿN‚ÿJ|ÿH{ÿH|ÿIyÿIwÿIuÿItÿJtÿGqÿBmÿ@kÿ=iÿ:jÿ9fÿ1ÿúÍ¡~R) %B ‹5Kæa˜ÿt¹ÿv½ÿs¹ÿqµÿr·ÿr·ÿn­ÿ]•ÿCsÿ;iÿR†ÿq°ÿy¾ÿu¹ÿt·ÿt·ÿq³ÿq´ÿƒÈÿ•Öÿ€¼ÿXŽÿK~ÿ`œÿxºÿw»ÿs¹ÿt¼ÿs»ÿnµÿz»ÿšÖÿ”Ôÿl®ÿPŠÿI}ÿJ~ÿH}ÿG{ÿH|ÿI{ÿHvÿIvÿHuÿItÿHsÿDoÿ@kÿ;iÿ7dÿ6eÿ9iÿ4Wÿ ÿë¶’j>:}#/ÒKtýl«ÿu¼ÿt¹ÿq´ÿp¶ÿq·ÿn®ÿZ“ÿBrÿBrÿ]–ÿv¸ÿx¼ÿu¸ÿt¶ÿsµÿo²ÿu¹ÿŒÍÿÍÿn¦ÿP„ÿUÿo¯ÿx¼ÿuºÿt¹ÿs¼ÿo·ÿy¸ÿ™ÑÿœÚÿw»ÿU’ÿI~ÿHzÿGzÿH{ÿIzÿIxÿItÿHsÿFqÿGrÿFqÿBnÿ>jÿ9fÿ5cÿ5cÿ8cÿ;cÿ*BÿüÏ£U, 0a ² Bc÷m«ÿy¾ÿt¸ÿrµÿs·ÿq·ÿl«ÿXŽÿCuÿJÿj§ÿy½ÿvºÿt·ÿs¶ÿrµÿo²ÿ}¿ÿ”Òÿ†Àÿ`–ÿP…ÿbžÿwºÿw½ÿs¹ÿs»ÿq·ÿu´ÿ‘Éÿ¥Þÿ‡Æÿ_›ÿNÿIzÿH{ÿH|ÿHyÿIuÿIsÿIsÿFqÿEpÿBmÿ@kÿhÿ?iÿ?jÿ9gÿ4bÿ5aÿ6_ÿ6aÿ6`ÿ6aÿ6aÿ6bÿ6_ÿ6]ÿ6bÿ6`ÿ6bÿ8gÿ;gÿ*Aÿýا„Y/&Q¸Tƒýy¾ÿv½ÿuºÿŒÍÿ™Ôÿ…¾ÿm¬ÿl¯ÿt·ÿu¹ÿt¸ÿs»ÿn¶ÿr·ÿŽÊÿ ŸÒÿ„·ÿgŸÿh¤ÿv¸ÿy¿ÿv½ÿn·ÿ}»ÿ%£Ðÿ(¤Ïÿu«ÿK€ÿnÿ6bÿ5aÿ5bÿ6dÿ6`ÿ6]ÿ6aÿ6aÿ6aÿ6`ÿ6aÿ6aÿ6aÿ6`ÿ6aÿ6_ÿ6^ÿ8dÿ=iÿ-Kÿ ýשˆ^52 … :Sîp¬ÿxÀÿwºÿÇÿªÛÿ›Îÿw²ÿj­ÿr¸ÿt¾ÿs»ÿs¹ÿr¸ÿs¶ÿŒÇÿ¥Úÿ ’Éÿn§ÿd ÿp²ÿy½ÿv½ÿn·ÿw±ÿ ˜¼ÿ)¢Çÿ wªÿG{ÿ4bÿ0]ÿ4bÿ6cÿ6_ÿ6]ÿ6bÿ6aÿ6aÿ6`ÿ6bÿ6`ÿ6aÿ6`ÿ6aÿ6_ÿ6]ÿ6bÿ;fÿ9bÿ *ÿóÁœxM' @ ¢Eaúp®ÿv¾ÿ|¾ÿœÒÿ­ÜÿÅÿo­ÿo²ÿu»ÿuºÿw»ÿt¹ÿnµÿw¹ÿ –Ðÿ¥Ùÿ…»ÿdŸÿe¦ÿw»ÿz¾ÿrºÿoµÿ‹Àÿ+¬Õÿ“Äÿ[”ÿ;kÿ0]ÿ2aÿ6`ÿ6`ÿ6`ÿ6aÿ6`ÿ6aÿ6_ÿ6aÿ6_ÿ6^ÿ6aÿ6`ÿ6aÿ6aÿ6bÿ8cÿ "R· Bbøm¬ÿt¼ÿ…Âÿ§Úÿ§Øÿ‚¹ÿm­ÿqµÿw¹ÿy»ÿxºÿs¹ÿq¶ÿ‚Áÿ£×ÿœÐÿu¯ÿa ÿo²ÿ{Àÿx¿ÿq»ÿ~Àÿ¢Õÿ£Òÿt©ÿGxÿ3aÿ1]ÿ4]ÿ6`ÿ6bÿ6`ÿ6aÿ6`ÿ6aÿ6`ÿ6`ÿ6_ÿ6aÿ6`ÿ6`ÿ6`ÿ6bÿ6aÿ9fÿ:dÿ !2ÿøË£ƒY1(W · Gpüo³ÿx¾ÿ’Íÿ­ÞÿÎÿx³ÿl¯ÿu¸ÿw¹ÿw¹ÿy»ÿu¸ÿt¸ÿ‹Éÿ ÖÿŽÂÿl¤ÿf¦ÿw¼ÿ{Âÿr½ÿs»ÿ Åÿ §Òÿ½ÿ\Žÿ=lÿ3\ÿ2]ÿ5^ÿ6`ÿ6`ÿ6aÿ6`ÿ6aÿ6`ÿ6aÿ6aÿ6_ÿ6aÿ6_ÿ6]ÿ6aÿ6`ÿ7cÿ;iÿ4Wÿÿ뺘tI$ -j)7Þb™ÿv½ÿ}ÁÿœÓÿ­Üÿ Äÿo®ÿn³ÿv¹ÿwºÿw¼ÿu¹ÿq¹ÿv»ÿ ÇÿžÉÿ ¯ÿf¡ÿm±ÿzÁÿyÁÿr»ÿ{¸ÿ›Èÿ£Íÿ }¯ÿP†ÿ9fÿ2^ÿ3]ÿ6]ÿ6`ÿ6`ÿ6aÿ6`ÿ6`ÿ6_ÿ6`ÿ6`ÿ6aÿ6_ÿ6]ÿ6aÿ6aÿ6bÿ9eÿ;gÿ(?ÿýÜ­‹c7 ; ˜ Ba÷o±ÿu¿ÿ„Ãÿ¤Øÿ£Ôÿ~¹ÿj­ÿs¶ÿz»ÿu¼ÿsºÿtºÿq¶ÿ}·ÿ›Èÿ˜Äÿs©ÿb¡ÿq³ÿ~Áÿu½ÿp¶ÿ„½ÿ£ÐÿšÊÿk¥ÿDxÿ3aÿ3^ÿ6^ÿ6aÿ6aÿ6aÿ6`ÿ6bÿ6_ÿ6^ÿ6aÿ6`ÿ6`ÿ6`ÿ6bÿ6`ÿ6aÿ7aÿ:hÿ:bÿ ,ÿøÊžzM&  "P ¾W‡ÿvÀÿvÀÿËÿ¨Ùÿ “Æÿp¬ÿk®ÿw»ÿz¼ÿu»ÿw»ÿsºÿqµÿ‰Äÿ Óÿˆºÿf ÿf§ÿy½ÿyÁÿq¼ÿuºÿ ‘Çÿ!§Óÿ޾ÿZ‘ÿÿúÊžzM% 7 oÿ2^ÿ2_ÿ5cÿ6cÿ6cÿ6_ÿ6`ÿ6_ÿ6aÿ6cÿ6`ÿ6aÿ7dÿ8aÿ%ø·tI$ 7  “ =\óo°ÿw¿ÿ ŠÁÿ#¥Ìÿ–¿ÿtªÿi®ÿs¼ÿzÁÿw¿ÿy¾ÿv¼ÿv¼ÿ ‘Ëÿ$©Øÿ’Àÿl£ÿi¨ÿ{¿ÿ}ÆÿtÂÿ}ÁÿÒÿ*ªÙÿ…·ÿRˆÿ9gÿ2^ÿ4aÿ6cÿ6cÿ6_ÿ6`ÿ6_ÿ6aÿ6cÿ6`ÿ7bÿ8bÿ#8þчX1 !M ² Ktýqºÿ|Åÿ“Äÿ'¡Âÿгÿo¬ÿnµÿz¿ÿxÀÿy¿ÿy¾ÿt¼ÿ€Áÿ¥×ÿ)¬Öÿ „µÿf£ÿn³ÿ}ÃÿxÃÿs¾ÿ†Åÿ%¨Ùÿ(¢Ðÿ p¥ÿCuÿ2_ÿ1^ÿ5bÿ6cÿ6cÿ6cÿ6dÿ6cÿ6^ÿ6aÿ9iÿ/Oÿ çœf> *j)8ÝeŸÿxÄÿ»ÿš»ÿ(¢Åÿ „¹ÿn¯ÿu¸ÿzÀÿw¿ÿx¾ÿw½ÿv»ÿ Éÿ*°ÜÿŸËÿr©ÿd¤ÿt¹ÿ|ÃÿwÂÿyÀÿ–Íÿ-®Øÿ޾ÿUÿ4fÿ/Zÿ4`ÿ6bÿ6cÿ6cÿ6dÿ6cÿ6`ÿ7cÿ8`ÿ%ù»wL'9 ;Yðn¯ÿx¿ÿ ŽÂÿ*ªÔÿ"ŸÏÿ|¶ÿp´ÿy¾ÿ{Àÿ{¿ÿz¿ÿt»ÿ|¾ÿœÒÿ(¬Øÿ‹ºÿf¡ÿi¬ÿ|Àÿ~Äÿv¿ÿ¿ÿ¡Ðÿ(¢Òÿ u¯ÿCzÿ0]ÿ2\ÿ5aÿ6cÿ6cÿ6cÿ6cÿ7eÿ8eÿ %:þÓŒ\4 I ® Jsýsºÿ€Çÿ™Ïÿ,¬×ÿ•Çÿvµÿs¹ÿ|Àÿ{¿ÿz¿ÿw¾ÿv¾ÿƒÄÿ¡Ôÿ&¡Ìÿ |¯ÿg¥ÿu·ÿÃÿzÃÿv¿ÿ‹Èÿ%§Úÿ—Êÿb™ÿ^ÿ4Oÿ&ÿ$ýW}ÿ…Äþ‚Ãÿ†Èÿv­ÿL{ÿHxÿFxÿEvÿErÿEuÿFsÿIxÿ4ÿ.ÿ)ÿ#ÿ}²þ†Æÿ‚Àÿ‚Áÿ‚Áÿ‚Áÿ†Åÿ†Äÿ„Âÿ†Äÿ˜Øÿ‹Îþ /?ø‡- 2j´ø[Œÿ`ÿ\ŠÿTƒÿP€ÿJ}ÿG|ÿhŸÿˆÊÿ~¾ÿ~½ÿ¾ÿ†ÄÿhšÿHuÿL|ÿM|ÿJ{ÿFyÿErÿIyÿ@ÿ-ÿ %ÿZŠÿˆÉÿ‚Áÿ‚ÁÿƒÁÿƒÁÿ…Äÿ…Äÿ…Âÿ†Æÿžßÿ„Åÿw±ÿ ÞgCÖ2Lÿ`‘þ[ˆÿW‚ÿPÿL|ÿFvÿEvÿDnÿ@kÿw²ÿÂÿ}½ÿ}¼ÿ…Åÿ‚»ÿW‡ÿGvÿJzÿKzÿM{ÿN~ÿP€ÿ-Nÿ %ÿ6ÿ}¶ÿ†Äÿ‚ÀÿÀÿ‚Áÿ…Äÿ†Äÿ…Ãÿ…ÃÿŸàÿ†Æÿz¸ÿ]†ÿ¾S L™îJrÿ`‘þY…ÿV„ÿN|ÿM{ÿDuÿEwÿFsÿFmÿAiÿJyÿ¿ÿ~¿ÿ~½ÿ~¾ÿ‡Çÿq¨ÿHxÿK{ÿQ~ÿQÿP~ÿW‡ÿFmÿ&ÿ4Yÿ‹ÇÿÀÿ‚Áÿ‚Àÿ„Âÿ†Äÿ†Äÿ‚ÁÿœÜÿŠËÿzºÿy±ÿNnÿ­EJ (û[ÿ_ŽÿX…ÿSÿN{ÿHxÿEwÿFtÿEnÿEkÿGmÿFmÿ=dÿgšÿ„Äÿ}½ÿ}½ÿƒÃÿŒÈÿa•ÿJxÿQÿQ€ÿTÿY‡ÿNzÿ$<ÿKwÿ‰ÊÿƒÁÿÀÿ…Äÿ†Äÿ†Åÿ‚Àÿ”Öÿ•Öÿy¹ÿw¯ÿx±ÿ>Yÿ > D›#3þe˜þ`ÿ[ŠÿTƒÿQ€ÿGxÿEwÿFwÿEnÿGmÿFnÿ?hÿ>fÿ?cÿAgÿ{¶ÿ€Âÿ}¼ÿ~½ÿ†Åÿ~·ÿU‚ÿN{ÿW„ÿV„ÿY†ÿV…ÿBÿf™ÿ‡ÇÿÀÿ‚Áÿ…Äÿ†Äÿ…Ãÿ‡Èÿ¥åÿ¿ÿy¶ÿv©ÿv°ÿ3Hþ;ƒø3]þ1Uÿ4Yÿ:`ÿ>jÿFtÿH{ÿIxÿGnÿFmÿ@iÿ?hÿ>fÿ;cÿ>_ÿ2TÿJvÿ„Âÿ¿ÿ~½ÿ¾ÿËÿm£ÿSÿVƒÿW„ÿV„ÿTƒÿ1Sÿx®ÿƒÃÿƒÂÿ†Äÿ†Äÿ†ÄÿƒÀÿÞÿŽÎÿy¸ÿwªÿq¨ÿv±ÿ0Fÿž=¯lžÿf—ÿ\ÿM{ÿÿ-Mÿ>cÿHqÿBiÿ>fÿ8aÿ5Zÿ1Yÿ3Vÿ*Jÿ^’ÿ…Åÿ~½ÿ|»ÿ…Äÿ‡Åÿ_ÿV‚ÿY‡ÿR€ÿQ‚ÿ=eÿ|·ÿ„Äÿ„Âÿ†Äÿ…Äÿ…Âÿ‹Êÿ¢äÿz»ÿy´ÿt¨ÿo¤ÿq°ÿ/Iÿ£C D^ŒõƒÆþ€½ÿ½ÿƒÁÿ|¹ÿv¬ÿV†ÿ4\ÿ=ÿ7ÿ+Mÿ:^ÿ;`ÿ4Zÿ7Wÿ4Xÿ-Lÿ-Rÿ}·ÿ€Âÿ½ÿ¾ÿ‘Ïÿz³ÿRÿQÿQÿM~ÿGvÿ»ÿ†Åÿ†Äÿ…Äÿ†ÄÿƒÀÿ—Üÿ“Ñÿz»ÿv©ÿp¦ÿq¦ÿo©ÿ;Wÿ®L rq¥ÿ}¸þ{¹ÿ|¹ÿ{¹ÿ~½ÿ‚Âÿ„Áÿu­ÿX…ÿ3Sÿ5ÿ;ÿ2Kÿ6Zÿ0Nÿ*Gÿ?ÿDqÿ…Ãÿ¿ÿƒÁÿ‚ÁÿÎÿh™ÿKyÿO}ÿM|ÿN{ÿ‚¿ÿ†Æÿ†Äÿ†Äÿ†Äÿ‚Áÿ¡ãÿ€Áÿx°ÿp§ÿo£ÿj¦ÿk¢ÿBbÿ¹\"0ªƒÂÿzµÿ}¹ÿ{¹ÿz¶ÿ}½ÿ½ÿ€¿ÿ„ÅÿƒÁÿf˜ÿ4^ÿ:ÿ4ÿ$Cÿ.Mÿ#Fÿ6ÿa’ÿ‡ÈÿÀÿÀÿ‰Çÿ„ÀÿPÿ@qÿCtÿDvÿ†Áÿ†Åÿ†Ãÿ†Äÿ…Ãÿ†Æÿžãÿy·ÿt¦ÿn§ÿl§ÿgŸÿhŸÿOvÿÓs5Pyç„Çÿ€Àÿ~¿ÿ~¼ÿ½ÿ|ºÿ|¼ÿ}½ÿ¿ÿ„Åÿ„Áÿhžÿ>`ÿ0ÿ5ÿBÿ.ÿEÿ}µÿ†Æÿ€¿ÿÁÿ•Õÿq«ÿDsÿDuÿArÿƒ¿ÿ‡Æÿ†Äÿ†Äÿ„ÂÿÎÿœÝÿtªÿn¦ÿn¦ÿižÿlŸÿb—ÿd˜ÿë‹4 L2HÓ4MÍJlâZ€þaÿ}¼ÿ†Èÿ€Ãþ¿ÿ~¼ÿ¾ÿ„Äÿ€¾ÿZÿ,Rÿ:ÿ0ÿ &ÿ?kÿ‡Åÿ‚Âÿ¿ÿ„Äÿ–Óÿf–ÿ?pÿ?qÿ{´ÿˆÈÿ…Ãÿ†Äÿ„Áÿ“Õÿ”Ôÿm£ÿp§ÿk¥ÿižÿc™ÿc˜ÿa˜ÿ$ý©S  '0Lk Œ&5ÍUzõw³ÿ†ÉÿÂÿ~½ÿ€Àÿ…Äÿw²ÿQ|ÿ-Mÿ *ÿ)ÿižÿˆÉÿ‚Àÿ€¿ÿÎÿˆÃÿK{ÿ=nÿl¢ÿŠÊÿ…Äÿ†Åÿ„Áÿ–×ÿÊÿl£ÿk¤ÿhŸÿd—ÿb•ÿ_“ÿ]“ÿAcÿÍt  B  ˆ4JÑf•þ„Æÿ€Áþ~¾ÿ‚Âÿ€½ÿZŽÿ>`ÿ2ÿ'Pÿƒ¼ÿ…ÅÿÀÿ€Àÿ˜Øÿl¢ÿpÿEvÿEwÿFxÿEsþ@gÿ­D DSwïŽÎþ5¶ÞÿŒÄÿ‹ËÿŒÌÿ‡Èÿ¬Üÿ“Áÿ¿ÿÏÿ˜Ðÿ'©ØÿQ‡ÿAqÿEvÿEvÿHzÿ Ûc„y·ÿ™Óÿ,±Úÿ‚¿ÿŒÌÿŠÎÿŠÌÿ0´Ýÿ¸ÿŒÎÿŠÌÿ"­Üÿ¿ÿEwÿCtÿFzþ.Jþ‘4"9MÉŒÓÿ'±ÜÿšÊÿ‡ÉÿŒÎÿˆÌÿ—Ðÿ$¥Îÿ{¹ÿÒÿÌÿ5·Ýÿiÿ>pÿHvÿÍT CRyð’Òþ9°Ñÿ„»ÿŒÎÿ‹Íÿ‰Ëÿ"²àÿ Œ¾ÿ…ÄÿŠÐÿ¥×ÿ$ªÕÿQƒþ-òy' |z´ÿ—Ëÿ,¬Òÿ†Çÿ’ÒÿÍÿ‘Ñÿ6¶Üþ„¾ÿ“Öÿ”×ÿ+¿êÿ u ÿ°E  3G·†Çÿ!ŸÈÿ ]ïe“èz³öhžðh…á @OÇ':¯QxÒ^€Ö !*°NMVB7;9.$"ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿüÿÿÿÿÿø?ÿÿÿÿÿð?ÿÿÿÿÿàÿÿÿÿÿÀÿÿÿð€ÿÿÿÀ?ÿÿÿ€>ÿÿÿ?ÿÿüÿÿøÿÿÿðÿÿÿàÿÿàÿÿÀÿÿÿþÿøÿðÿàÿÀÿÀÿÀÿÀÿÀÿàÿàÿðÿøÿøÿÿÿÿüÿÿÿÿÿÿàÿÿÿðÿÿÿüÿÿÿþÿÿÿÿÿÿÿ€ÿÿÿÀ?ÿÿÿà?ÿÿÿðÿÿÿøÿÿÿøÿÿÿüÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÀÿÿÿÿÀÿÿÿÿàÿÿÿÿð?ÿÿÿÿðÿÿÿÿøÿÿÿÿüÿÿÿÿÿüÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ(0` €% k”Z"{ç*ö®=(}é4[ÿ2Vÿ ßu.“ê2Uÿ4Xþ3Yÿ.üª<8˜&<õ5Xÿ4Yþ3Xþ4Yÿ0RÿÜr ?¥,ø3Zÿ2Yÿ4Yÿ4Yÿ3Xÿ6\ÿ(ÿ¬8*( A®>YýSÿ3Vþ3Zÿ2Yÿ4Wÿ3Yÿ4Yþ6[ÿÆ4<r¦“@D¶LpúˆÇÿk þ3[ÿ3Wÿ2Zÿ3Yÿ4Xþ6[ÿ"ìe[´ò/Hÿ ê{9 ­Nqÿ‡ÈÿƒÁÿ½ÿO{ÿ.Tÿ4[ÿ4Xþ4Yÿ"4ïs(wÕ;\ÿJvÿN|ÿ2ÿ®;.¡ Gdþ‰ÉÿÀþÀÿ…Äÿtªÿ9aÿ1Vþ6\ÿ $4öŒ#4-òHsÿFsÿEqþIsþ1Rÿßh‰Fdö†ÄÿÀþ‚Àÿ‚Áÿ‚Áÿ…ÄÿZŠþ7^ÿ"3÷ƒ#7¢%9ùV†ÿEtþFsÿEsÿHvÿ9aþù¢:T%6àƒ¿ÿƒÃÿƒÁÿ‚Áÿ‚Àÿ…Ãÿ‡Æÿz³ÿ6Tÿœ(-<=:0@œ3MüN}ÿCqþFtÿFsÿEtÿHwÿ>hþ&þÔ† µ`ÿ…Åÿ‚Àÿ‚Àÿ‚Áÿ„Ãÿ†Äÿ„Ãÿ…Ãÿ+?ÙP!b¬Ä¹¢¼%5÷t«ÿX‰þCrÿEuÿFsÿEtÿGuÿDoÿ+ÿ ùÌ4Kú‡Æÿ¿þ‚Àÿ‚Àÿ…Ãÿ…ÄÿƒÂÿ‘Óþt£ú“ 5„ä@`ÿNqÿCfÿ4Rÿ 1ÿV}ÿˆÉÿ‚Äþ|¶ÿN}ÿGxÿFxÿFtÿFtÿIyÿ3þ)ÿ/ÿƒ¾ÿ‚Âþ‚ÁÿƒÁÿ„Ãÿ…Äÿ…Ãÿ‘ÐÿŽÑÿ!1ãRM¬)@òY‡ÿ^ŠþU‚þM~ÿH|ÿNÿ~»ÿ€Àÿ}¼ÿ†Åÿo¤ÿJyÿL{ÿJ{ÿJyÿM}ÿ!Aÿ $ÿ_‘ÿˆÉÿÀÿ‚Áÿ„Âÿ†Äÿ„Âÿ”Õÿ‹Ìÿm¡ÿ¼2dÐBgý\ŒÿX†ÿO}ÿJzÿFwÿErÿBiÿN~ÿ‚Âÿ~¾ÿ¿ÿ„ÁÿY‹ÿIzÿP~ÿP~ÿV†ÿ:]ÿ4ÿ|´ÿ‚Âÿ‚ÀÿƒÁÿ†ÄÿƒÂÿ–Õÿ‹Ìÿ|¸þX|ÿŸ#e ÛU‚ÿ_ŒþUƒÿM|ÿGxÿEuÿFoÿFkÿFmÿ=cÿg›ÿ‚Ãÿ}¼ÿ„Äÿz³ÿO~ÿQÿSÿY‡ÿHrÿ6Xÿ‚¿ÿ‚Àÿ„Âÿ†Äÿ…ÄÿÍÿ“Ôÿx¶ÿz³ÿFdÿV ×=bÿJuÿJuÿKzÿI{ÿHyÿFqÿDlÿBkÿ=fÿ?aÿ>dÿv°ÿ¿ÿ~¾ÿ‡ÅÿgšÿP}ÿW„ÿX…ÿNzÿItÿƒÁÿ‚Áÿ…Ãÿ†Äÿ†Äÿ™Ùÿ€¿ÿw®ÿx±ÿ=XÿŽ“^‰ÿY‰ÿIwþ7aÿ%Iÿ$Fÿ3VÿDmÿDkÿ>fÿ7_ÿ4Zÿ2TÿHtÿ¿ÿ~½ÿ‚Áÿ…Âÿ[ŠÿW„ÿT‚ÿN}ÿZŠÿ„ÂÿƒÂÿ†Åÿ„ÃÿŽÍÿÒÿy¶ÿs¨ÿt¯ÿ:Zÿ’0aŽéƒÅÿ€½þ‚Àÿ|¶ÿb•ÿÿ0ÿ5aÿ†ÅÿÀÿ†Åÿ‚¾ÿIyÿCtÿb™ÿ‡Æÿ…Ãÿ„ÃÿÌÿ–×ÿp¨ÿo¦ÿk ÿhœÿb•ÿØY!-A¤5M¶LoÕWìs¬ó|¹ü~¾ÿ¿ÿ‚ÂÿÀþ[ÿ,Qÿ7ÿ-ÿ_’ÿ„Äÿ‚ÀÿÎÿs§ÿ?oÿ[ÿ†Æÿ…Äÿ„Âÿ’ÓÿŽËÿm£ÿl¥ÿgœÿc˜ÿbšÿ&ó„1 R+?ˆKnÄb•ó}»ÿƒÅÿÁþw°ÿIuÿ<ÿ%Jÿ€»ÿƒÂÿƒÃÿ’ÐÿT‡ÿLÿ†Äÿ…Äÿ„Âÿ”ÕÿŠÃÿi¢ÿhžÿd˜ÿ_”ÿ\‘þAfü³=D*?c’ù…Èÿ¿þ~¼ÿa’ÿ,PÿMwÿ‰Éÿ¿ÿŒÊÿ†ÁÿJ}ÿ¾ÿ†ÅÿƒÂÿ“ÕÿÈÿeœÿe›ÿa–ÿ[‘ÿZ‹ÿUÿ Þs ?EcËx¶ý†ÅÿƒÁþk ÿ3Yÿjžÿ‡ÇÿƒÁÿ—Õÿi ÿs«ÿˆÈÿ„ÁÿÑÿ’Òÿb™ÿc—ÿ]’ÿZŽÿ[‡ÿY‡ÿ(Aû¨=+=€d’ë‰ÉÿƒÂþo£þNÿ€¼ÿ†Åÿ‡ÆÿŽÉÿb—ÿˆÇÿ…ÅÿˆÉÿœØÿb˜ÿ]’ÿZÿZŠÿZ‡ÿQ€ÿAkÿ ßv FIiׄÂÿƒÂþr¬ÿe›ÿ‡Æÿ…Ãÿ“Ïÿz°ÿu¯ÿˆÊÿƒÄÿ¦Ûÿi¢ÿZÿZ‹ÿY†ÿUƒÿJzþHyÿ(>ÿ±E-LlȃÁÿƒÂþn¦þz¸ÿ‡Æÿ†Åÿ ×ÿrªÿ†Æÿ„Äÿ¨ÚÿµÿYŒÿ[ˆÿX†ÿN}ÿEwÿFqþJuÿ ê€ 3IlƈÅÿ„Ãþu®þƒÂÿ„ÄÿŒÊÿ›Ïÿ}ºÿˆÉÿ’ÊÿšËÿY‰ÿ[‡ÿR€ÿFwÿFuÿEsÿHuþ2MýÃV + @\ʇÅÿÍþ»ÿ…ÄÿƒÅÿ•Ðÿоÿ‡Èÿ‰Çÿ¬ÚÿhœÿQ}ÿJzÿEtÿFtÿEtÿEtÿFtÿ&ð“) 3_‡ÜŒÊÿ£ÖþƒÀÿ†Èÿ†ÆÿžÐÿ€¸ÿ‰Êÿ˜ÍÿйÿHzÿFvÿFtÿFuÿFtÿFtÿGuÿ6WÿÉa'ai—òÕÿ šÍþ…ÅÿˆÆÿ—Ðÿ ”Çÿ~¼ÿ‰Éÿ"­Øÿ]‘ÿ@pÿEtÿFuÿFtÿFtÿFsþIyÿ#ù :  „€ºÿ¥Øþ‡Ãÿ‰Çÿ†Çÿ Ñÿ‡»ÿ„Æÿ•Ëÿ™ÅÿI|ÿErÿEuÿFsÿFtÿEsÿGvþEoÿäw @\“Ïÿ ÍÿÀÿ‰ÉÿˆÇÿ¤Ôÿ½ÿ…Éÿ¢Òÿ u¦ÿCqÿFtÿEuÿFuÿFtÿEtÿIzþ0Oü·A;_ã£Õÿ™Éÿ…Äÿ‡Çÿ–Îÿ ’Âÿ„ÅÿŽÍÿËÿO‚ÿCrÿFtÿEtÿFtÿFtÿEtÿFsÿàa (6~¼û£ÎþŒÄÿŠËÿˆÊÿ¤Õÿ…½ÿ‹Íÿ£Øÿ †¸ÿ?oÿErÿFvÿFtÿFuÿEsÿDsÿ)ÑF HdÆÌÿ—Äþ†Åÿ‰Êÿ“Ðÿ Ðÿ€½ÿŽÎÿ"°Üÿe™ÿAqÿEtÿEsÿEsþFuÿ9_øŠ A`‰ï Òÿ Œ¾þ‡Éÿ‡Êÿ¢×ÿ—ÆÿƒÄÿ•Òÿ$£ÏÿL~ÿDvÿFuÿFvþFtÿÃ9 !,rx¬ÿ*®Úÿ‰Åÿ‹ÌÿŠÉÿ «Øÿ‡¿ÿ‹ÍÿŸÓÿx«ÿBsÿFwþH{ÿ1éa Ms¼’Îÿ&©Ôþ‡ÅÿŠÎÿÎÿÌÿˆÈÿÐÿ¤ÓÿU‡ÿCtÿ9`ÿš& Hf›ì¦Úÿ“Åþ‹ÌÿŠÌÿ¡Ôÿˆ¾ÿŠÌÿ ×ÿ¿þBsÿ-ÔL |ƒ¼ÿ¥ÐÿŽÌÿ’Óÿ’Òÿ)±Ûÿ†Ãÿ”Øÿ%»ëÿ _ˆû„>Z¬‹½ìb‚×`ŽÎk Ø a‚Ç 9G¨9V¥V{º "‹)(  ÿÿÿÿøÿÿÿÿð?ÿÿÿÿàÿÿÿÿÀÿÿÿÿ€ÿÿÿÿÿÿÿþÿÿð|ÿÿà8ÿÿ€0ÿÿÿþ?ÿ„ÿÿüÿøÿðÿàÿÀÿ€ÿ€ÿ€ÿÀÿàÿàÿøÿÿ€ÿÿðÿüÿÿ?ÿÿ€?ÿÿÀÿÿàÿÿðÿÿøÿÿüÿÿþÿÿþÿÿÿÿÿÿ€ÿÿÿÀÿÿÿÀÿÿÿàÿÿÿàÿÿÿð?ÿÿÿø?ÿÿÿøÿÿÿÿÿÿ( @ €'"° ÚI*º2Vÿ+Jÿ 3Î2Tÿ4Xþ5[ÿæH>Ü2Wÿ2Yÿ4Xÿ3Xÿ,Iÿ›aE'â‚Àÿ9aÿ2Yÿ3Xÿ4Xþ+Iÿd8 Â0Lÿ"4ýi6(5ä‡ÈÿƒÂÿiœÿ/Vÿ4Yþ0Nÿ€X)æL{ÿEnþ:_ÿ·$уÀÿ‚Àÿ‚Áÿ„ÃÿCmþ1Qÿ‰ l-C÷L}ÿErÿEtÿBlþ ð_’w¯ÿƒÁÿ‚ÁÿƒÁÿ‡Æÿr«ÿ°7’ ”.Fób”þDrÿFsÿEtÿFsÿ(ÿÈCcø„Ãþ‚ÀÿƒÁÿ…Äÿ‡ÇþY{õ? b,äS{ÿNvÿ8]ÿ[†ÿƒÄþƒÂÿO~ÿIzÿFwÿIxÿ1þ:ÿ†Æþ‚ÁÿƒÁÿ…ÄÿŒËÿŒÎÿ ³ “7Xü^ÿP~ÿGwÿEqÿO}ÿÂÿ¿ÿv®ÿGwÿO}ÿSƒÿ =ÿV…ÿƒÂÿ‚Àÿ†ÅÿŠÈÿ‹Íÿi™ÿ £Tÿ\‰þN}ÿEwÿFoÿElÿ?dÿl¡ÿ~¾ÿ‡Æÿ^ÿQ€ÿW…ÿ7\ÿs¬ÿÀÿ†Äÿ„Âÿ–×ÿw°ÿYƒÿlZEjÿ?iþ2Zÿ/Wÿ?fÿFnÿ=fÿ8]ÿ2Vÿ~»ÿ}¼ÿ…ÂÿV‚ÿW„ÿClÿ‚¿ÿ„Ãÿ…Äÿ•Õÿ}¼ÿr¦ÿSÿoe•ã¼þ¿ÿv°ÿQÿ/Pÿ%Hÿ6Wÿ/NÿAlÿƒÄÿ†Åÿr§ÿO|ÿKxÿ…Äÿ†ÄÿƒÂÿ•×ÿu®ÿo¥ÿXƒÿƒ8y´ÿÀÿ¿ÿ~¼þ„Åÿk£ÿ3Vÿ9ÿ8ÿc™ÿ‚ÁÿŒËÿN€ÿ@rÿˆÆÿ…ÄÿˆÆÿ‹Êÿo¥ÿj¡ÿb•ÿ± O-A€>X³VÝu°ÿƒÅÿ‚Âþc™ÿ)Jÿ0ÿ„Âÿ¿ÿ‰Ãÿ=lÿ½ÿ…ÄÿÌÿ¸ÿl¤ÿe™ÿb™ÿá916P’iš÷„Æÿz·ÿAiÿBlÿ†ÇÿŠÉÿc˜ÿoªÿ†ÅÿŒÍÿ|¶ÿhÿb–ÿZŽÿ:Uÿ€Aa¯€½ÿ‚ÀþO{ÿn§ÿ…Ãÿ–Ôÿ`•ÿˆÈÿŠÊÿ€¾ÿb–ÿ[‘ÿ[ˆÿW‡ÿÑ2Xq¦ù…Äþ^’ÿ†Åÿ…Äÿƒ¹ÿ¾ÿƒÅÿ’ËÿZÿZ‹ÿX†ÿIzþ/Kÿ‡4mŸõ…Åþo©ÿ‡Æÿ•Ðÿ{³ÿ†ÈÿªÚÿXÿ[ˆÿN}ÿEuÿJvÿ ÝB2o ö†Æþ€¿ÿƒÄÿšÏÿ‚Áÿ™Ïÿ z®ÿS€ÿFvÿFtÿEsÿ8Zÿ¡C¹ÿžÐþ„ÅÿŒÊÿÂÿ…ÇÿžÉÿDwÿFuÿFuÿFtÿJzÿ ëT *x•Ðÿ‘ÉÿˆÇÿ ›Ñÿ‚½ÿ–Ïÿq¡ÿCqÿEuÿFsÿEsÿAjÿº"QtŤÕÿ„Âÿ†Æÿ›Ëÿ‚Æÿ¤ÕÿIyÿFtÿFuÿFtÿGwþ#;úi"r§ûœÉþˆÉÿ’Íÿ ŽÃÿŒÌÿ‘Àÿ@oÿFuÿFtÿEtÿ@jÿw "/p ”Ìÿ‹ÂÿˆÊÿ¡Õÿƒ¿ÿ¡Øÿa“ÿEtÿEsÿGwÿ2Ù!LsÅ¥Óÿ‡ÇÿŒËÿËÿ‡Êÿ¡Ñÿ@sÿFwþ8\ýW &x±ü ÎþŠÍÿ ˜Òÿ ŠÂÿ•Óÿ­ÿExÿ° ,n™Îÿ ’ÊÿŽÐÿ¨Øÿ‰Ìÿ±åÿ6Vò7GkŽZs¦Rw•Il!(jDc{ Hÿÿÿÿÿÿÿÿþÿÿøÿþðÿøpÿà ÿÀüð?à?À?€€€?À?À?üÿ€ÿÀÿðÿøÿüÿþÿþÿÿÿÿ€ÿÿ€ÿÿÀÿÿàÿÿàÿÿÿÿ(0 ` 8  €1ö‹ ,Mû5\ÿ!ä0) 2Uÿ3Zþ4Yþ-Mÿ~" ” Å5$2§q¦ÿZ‹ÿ0Uþ4Xÿ4Ñ);!3ÕEoÿ8[ÿ’žy±ÿ„Ãÿ€¾þ #include #define WIN32_LEAN_AND_MEAN #include #ifdef _WIN32_WCE # define DIR_SEPERATOR TEXT("\\") # undef _getcwd # define _getcwd(str,len) wcscpy(str,TEXT("")) # define setbuf(f,b) # define setvbuf(w,x,y,z) # define fopen _wfopen # define freopen _wfreopen # define remove(x) DeleteFile(x) #else # define DIR_SEPERATOR TEXT("/") # include #endif /* Include the SDL main definition header */ #include "SDL.h" #include "SDL_main.h" #ifdef main # ifndef _WIN32_WCE_EMULATION # undef main # endif /* _WIN32_WCE_EMULATION */ #endif /* main */ /* The standard output files */ #define STDOUT_FILE TEXT("stdout.txt") #define STDERR_FILE TEXT("stderr.txt") #ifndef NO_STDIO_REDIRECT # ifdef _WIN32_WCE static wchar_t stdoutPath[MAX_PATH]; static wchar_t stderrPath[MAX_PATH]; # else static char stdoutPath[MAX_PATH]; static char stderrPath[MAX_PATH]; # endif #endif #if defined(_WIN32_WCE) && _WIN32_WCE < 300 /* seems to be undefined in Win CE although in online help */ #define isspace(a) (((CHAR)a == ' ') || ((CHAR)a == '\t')) #endif /* _WIN32_WCE < 300 */ static void UnEscapeQuotes( char *arg ) { char *last = NULL; while( *arg ) { if( *arg == '"' && *last == '\\' ) { char *c_curr = arg; char *c_last = last; while( *c_curr ) { *c_last = *c_curr; c_last = c_curr; c_curr++; } *c_last = '\0'; } last = arg; arg++; } } /* Parse a command line buffer into arguments */ static int ParseCommandLine(char *cmdline, char **argv) { char *bufp; char *lastp = NULL; int argc, last_argc; argc = last_argc = 0; for ( bufp = cmdline; *bufp; ) { /* Skip leading whitespace */ while ( isspace(*bufp) ) { ++bufp; } /* Skip over argument */ if ( *bufp == '"' ) { ++bufp; if ( *bufp ) { if ( argv ) { argv[argc] = bufp; } ++argc; } /* Skip over word */ while ( *bufp && ( *bufp != '"' || *lastp == '\\' ) ) { lastp = bufp; ++bufp; } } else { if ( *bufp ) { if ( argv ) { argv[argc] = bufp; } ++argc; } /* Skip over word */ while ( *bufp && ! isspace(*bufp) ) { ++bufp; } } if ( *bufp ) { if ( argv ) { *bufp = '\0'; } ++bufp; } /* Strip out \ from \" sequences */ if( argv && last_argc != argc ) { UnEscapeQuotes( argv[last_argc] ); } last_argc = argc; } if ( argv ) { argv[argc] = NULL; } return(argc); } /* Show an error message */ static void ShowError(const char *title, const char *message) { /* If USE_MESSAGEBOX is defined, you need to link with user32.lib */ #ifdef USE_MESSAGEBOX MessageBox(NULL, message, title, MB_ICONEXCLAMATION|MB_OK); #else fprintf(stderr, "%s: %s\n", title, message); #endif } /* Pop up an out of memory message, returns to Windows */ static BOOL OutOfMemory(void) { ShowError("Fatal Error", "Out of memory - aborting"); return FALSE; } /* SDL_Quit() shouldn't be used with atexit() directly because calling conventions may differ... */ static void cleanup(void) { SDL_Quit(); } /* Remove the output files if there was no output written */ static void cleanup_output(void) { #ifndef NO_STDIO_REDIRECT FILE *file; int empty; #endif /* Flush the output in case anything is queued */ fclose(stdout); fclose(stderr); #ifndef NO_STDIO_REDIRECT /* See if the files have any output in them */ if ( stdoutPath[0] ) { file = fopen(stdoutPath, TEXT("rb")); if ( file ) { empty = (fgetc(file) == EOF) ? 1 : 0; fclose(file); if ( empty ) { remove(stdoutPath); } } } if ( stderrPath[0] ) { file = fopen(stderrPath, TEXT("rb")); if ( file ) { empty = (fgetc(file) == EOF) ? 1 : 0; fclose(file); if ( empty ) { remove(stderrPath); } } } #endif } #if defined(_MSC_VER) && !defined(_WIN32_WCE) /* The VC++ compiler needs main defined */ #define console_main main #endif /* This is where execution begins [console apps] */ int console_main(int argc, char *argv[]) { size_t n; char *bufp, *appname; int status; /* Get the class name from argv[0] */ appname = argv[0]; if ( (bufp=SDL_strrchr(argv[0], '\\')) != NULL ) { appname = bufp+1; } else if ( (bufp=SDL_strrchr(argv[0], '/')) != NULL ) { appname = bufp+1; } if ( (bufp=SDL_strrchr(appname, '.')) == NULL ) n = SDL_strlen(appname); else n = (bufp-appname); bufp = SDL_stack_alloc(char, n+1); if ( bufp == NULL ) { return OutOfMemory(); } SDL_strlcpy(bufp, appname, n+1); appname = bufp; /* Load SDL dynamic link library */ if ( SDL_Init(SDL_INIT_NOPARACHUTE) < 0 ) { ShowError("WinMain() error", SDL_GetError()); return(FALSE); } atexit(cleanup_output); atexit(cleanup); /* Sam: We still need to pass in the application handle so that DirectInput will initialize properly when SDL_RegisterApp() is called later in the video initialization. */ SDL_SetModuleHandle(GetModuleHandle(NULL)); /* Run the application main() code */ status = SDL_main(argc, argv); /* Exit cleanly, calling atexit() functions */ exit(status); /* Hush little compiler, don't you cry... */ return 0; } /* This is where execution begins [windowed apps] */ #ifdef _WIN32_WCE int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPWSTR szCmdLine, int sw) #else int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) #endif { HINSTANCE handle; char **argv; int argc; char *cmdline; #ifdef _WIN32_WCE wchar_t *bufp; int nLen; #else char *bufp; size_t nLen; #endif #ifndef NO_STDIO_REDIRECT DWORD pathlen; #ifdef _WIN32_WCE wchar_t path[MAX_PATH]; #else char path[MAX_PATH]; #endif FILE *newfp; #endif /* Start up DDHELP.EXE before opening any files, so DDHELP doesn't keep them open. This is a hack.. hopefully it will be fixed someday. DDHELP.EXE starts up the first time DDRAW.DLL is loaded. */ handle = LoadLibrary(TEXT("DDRAW.DLL")); if ( handle != NULL ) { FreeLibrary(handle); } #ifndef NO_STDIO_REDIRECT pathlen = GetModuleFileName(NULL, path, SDL_arraysize(path)); while ( pathlen > 0 && path[pathlen] != '\\' ) { --pathlen; } path[pathlen] = '\0'; #ifdef _WIN32_WCE wcsncpy( stdoutPath, path, SDL_arraysize(stdoutPath) ); wcsncat( stdoutPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) ); #else SDL_strlcpy( stdoutPath, path, SDL_arraysize(stdoutPath) ); SDL_strlcat( stdoutPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) ); #endif /* Redirect standard input and standard output */ newfp = freopen(stdoutPath, TEXT("w"), stdout); #ifndef _WIN32_WCE if ( newfp == NULL ) { /* This happens on NT */ #if !defined(stdout) stdout = fopen(stdoutPath, TEXT("w")); #else newfp = fopen(stdoutPath, TEXT("w")); if ( newfp ) { *stdout = *newfp; } #endif } #endif /* _WIN32_WCE */ #ifdef _WIN32_WCE wcsncpy( stderrPath, path, SDL_arraysize(stdoutPath) ); wcsncat( stderrPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) ); #else SDL_strlcpy( stderrPath, path, SDL_arraysize(stderrPath) ); SDL_strlcat( stderrPath, DIR_SEPERATOR STDERR_FILE, SDL_arraysize(stderrPath) ); #endif newfp = freopen(stderrPath, TEXT("w"), stderr); #ifndef _WIN32_WCE if ( newfp == NULL ) { /* This happens on NT */ #if !defined(stderr) stderr = fopen(stderrPath, TEXT("w")); #else newfp = fopen(stderrPath, TEXT("w")); if ( newfp ) { *stderr = *newfp; } #endif } #endif /* _WIN32_WCE */ setvbuf(stdout, NULL, _IOLBF, BUFSIZ); /* Line buffered */ setbuf(stderr, NULL); /* No buffering */ #endif /* !NO_STDIO_REDIRECT */ #ifdef _WIN32_WCE nLen = wcslen(szCmdLine)+128+1; bufp = SDL_stack_alloc(wchar_t, nLen*2); wcscpy (bufp, TEXT("\"")); GetModuleFileName(NULL, bufp+1, 128-3); wcscpy (bufp+wcslen(bufp), TEXT("\" ")); wcsncpy(bufp+wcslen(bufp), szCmdLine,nLen-wcslen(bufp)); nLen = wcslen(bufp)+1; cmdline = SDL_stack_alloc(char, nLen); if ( cmdline == NULL ) { return OutOfMemory(); } WideCharToMultiByte(CP_ACP, 0, bufp, -1, cmdline, nLen, NULL, NULL); #else /* Grab the command line */ bufp = GetCommandLine(); nLen = SDL_strlen(bufp)+1; cmdline = SDL_stack_alloc(char, nLen); if ( cmdline == NULL ) { return OutOfMemory(); } SDL_strlcpy(cmdline, bufp, nLen); #endif /* Parse it into argv and argc */ argc = ParseCommandLine(cmdline, NULL); argv = SDL_stack_alloc(char*, argc+1); if ( argv == NULL ) { return OutOfMemory(); } ParseCommandLine(cmdline, argv); /* Run the main program (after a little SDL initialization) */ console_main(argc, argv); /* Hush little compiler, don't you cry... */ return 0; } stella-3.9.3/src/win32/OSystemWin32.cxx0000644000175000001440000000732212266336753017123 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: OSystemWin32.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "bspf.hxx" #include "FSNode.hxx" #include "HomeFinder.hxx" #include "OSystem.hxx" #include "OSystemWin32.hxx" /** Each derived class is responsible for calling the following methods in its constructor: setBaseDir() setConfigFile() See OSystem.hxx for a further explanation */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OSystemWin32::OSystemWin32() : 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().c_str()); if(in && in.is_open()) { getline(in, basedir); in.close(); // 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"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OSystemWin32::~OSystemWin32() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string OSystemWin32::defaultSnapSaveDir() { HomeFinder homefinder; FilesystemNode desktop(homefinder.getDesktopPath()); return desktop.isDirectory() ? desktop.getShortPath() : "~"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string OSystemWin32::defaultSnapLoadDir() { return defaultSnapSaveDir(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystemWin32::setAppWindowPos(int x, int y, int w, int h) { SDL_SysWMinfo sdl_info; memset(&sdl_info, 0, sizeof(sdl_info)); SDL_VERSION (&sdl_info.version); if(SDL_GetWMInfo(&sdl_info) <= 0) return; // The following mostly comes from SDL_dx5video.c HWND window = sdl_info.window; RECT bounds; bounds.left = x; bounds.top = y; bounds.right = x + w; bounds.bottom = y + h; AdjustWindowRectEx(&bounds, GetWindowLong(window, GWL_STYLE), (GetMenu(window) != NULL), 0); SetWindowPos(window, HWND_NOTOPMOST, x, y, bounds.right-bounds.left, bounds.bottom-bounds.top, SWP_NOCOPYBITS | SWP_SHOWWINDOW); } stella-3.9.3/src/win32/stella.rc0000755000175000001440000000526512267025147015763 0ustar stephenusers// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winresrc.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_ICON ICON "stella.ico" ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 3,9,3,0 PRODUCTVERSION 3,9,3,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "Comments", "The multi-platform Atari 2600 emulator. Stella is released under the GPLv2." VALUE "CompanyName", "The Stella Team (http://stella.sourceforge.net)" VALUE "FileDescription", "Stella" VALUE "FileVersion", "3.9.3" VALUE "InternalName", "Stella" VALUE "LegalCopyright", "Copyright (C) 1995-2014 The Stella Team" VALUE "OriginalFilename", "Stella.exe" VALUE "ProductName", "Stella" VALUE "ProductVersion", "3.9.3" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winresrc.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED stella-3.9.3/src/win32/HomeFinder.hxx0000644000175000001440000000757612266336753016735 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: HomeFinder.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef __HOME_FINDER_ #define __HOME_FINDER_ #include /* * Used to determine the location of the various Win32 user/system folders. * * Win98 and earlier don't have SHGetFolderPath in shell32.dll. * Microsoft recommend that we load shfolder.dll at run time and * access the function through that. * * shfolder.dll is loaded dynamically in the constructor, and unloaded in * the destructor * * The class makes SHGetFolderPath available through its function operator. * It will work on all versions of Windows >= Win95. * * This code was borrowed from the Lyx project. */ class HomeFinder { public: HomeFinder() : myFolderModule(0), myFolderPathFunc(0) { myFolderModule = LoadLibrary("shfolder.dll"); if(myFolderModule) myFolderPathFunc = reinterpret_cast (::GetProcAddress(myFolderModule, "SHGetFolderPathA")); } ~HomeFinder() { if(myFolderModule) FreeLibrary(myFolderModule); } /** Wrapper for SHGetFolderPathA, returning the 'HOME/User' folder (or an empty string if the folder couldn't be determined. */ const string& getHomePath() const { if(ourHomePath == "") { if(!myFolderPathFunc) ourHomePath = ""; else { char folder_path[MAX_PATH]; HRESULT const result = (myFolderPathFunc) (NULL, CSIDL_PROFILE | CSIDL_FLAG_CREATE, NULL, 0, folder_path); ourHomePath = (result == 0) ? folder_path : ""; } } return ourHomePath; } /** Wrapper for SHGetFolderPathA, returning the 'APPDATA' folder (or an empty string if the folder couldn't be determined. */ const string& getAppDataPath() const { if(ourAppDataPath == "") { if(!myFolderPathFunc) ourAppDataPath = ""; else { char folder_path[MAX_PATH]; HRESULT const result = (myFolderPathFunc) (NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, folder_path); ourAppDataPath = (result == 0) ? folder_path : ""; } } return ourAppDataPath; } /** Wrapper for SHGetFolderPathA, returning the 'DESKTOPDIRECTORY' folder (or an empty string if the folder couldn't be determined. */ const string& getDesktopPath() const { if(ourDesktopPath == "") { if(!myFolderPathFunc) ourDesktopPath = ""; else { char folder_path[MAX_PATH]; HRESULT const result = (myFolderPathFunc) (NULL, CSIDL_DESKTOPDIRECTORY | CSIDL_FLAG_CREATE, NULL, 0, folder_path); ourDesktopPath = (result == 0) ? folder_path : ""; } } return ourDesktopPath; } private: typedef HRESULT (__stdcall * function_pointer)(HWND, int, HANDLE, DWORD, LPCSTR); HMODULE myFolderModule; function_pointer myFolderPathFunc; static string ourHomePath, ourAppDataPath, ourDesktopPath; }; __declspec(selectany) string HomeFinder::ourHomePath = ""; __declspec(selectany) string HomeFinder::ourAppDataPath = ""; __declspec(selectany) string HomeFinder::ourDesktopPath = ""; #endif stella-3.9.3/src/win32/Stella.vcxproj.filters0000644000175000001440000016326612267274277020476 0ustar stephenusers {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 Source Files Source Files Source Files Source Files 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\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\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 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 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\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 Header Files Header Files Header Files Header Files Header Files 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\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\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\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 Header Files\gui Header Files 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 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\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 Resource Files Resource Files stella-3.9.3/src/win32/SettingsWin32.cxx0000644000175000001440000000225412266336753017317 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SettingsWin32.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "bspf.hxx" #include "Settings.hxx" #include "SettingsWin32.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SettingsWin32::SettingsWin32(OSystem* osystem) : Settings(osystem) { setInternal("gl_lib", "opengl32.dll"); setInternal("fragsize", "512"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SettingsWin32::~SettingsWin32() { } stella-3.9.3/src/win32/stella.iss0000755000175000001440000000265511364631215016151 0ustar stephenusers; Script generated by the Inno Setup Script Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! [Setup] AppName=Stella AppVerName=Stella {#STELLA_VER} AppPublisher=The Stella Team AppPublisherURL=http://stella.sourceforge.net AppSupportURL=http://stella.sourceforge.net AppUpdatesURL=http://stella.sourceforge.net DefaultDirName={pf}\Stella DefaultGroupName=Stella OutputBaseFilename="Stella-{#STELLA_VER}-{#STELLA_ARCH}" Compression=lzma SolidCompression=yes #if STELLA_ARCH == "x64" ArchitecturesInstallIn64BitMode=x64 ArchitecturesAllowed=x64 #endif [Languages] Name: "eng"; MessagesFile: "compiler:Default.isl" [Tasks] Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked [Files] Source: "{#STELLA_PATH}\Stella.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "{#STELLA_PATH}\SDL.dll"; DestDir: "{app}"; Flags: ignoreversion Source: "{#STELLA_DOCPATH}\*"; DestDir: "{app}\docs"; Flags: ignoreversion recursesubdirs createallsubdirs ; NOTE: Don't use "Flags: ignoreversion" on any shared system files [Icons] Name: "{group}\Stella"; Filename: "{app}\Stella.exe"; WorkingDir: "{app}" Name: "{userdesktop}\Stella"; Filename: "{app}\Stella.exe"; WorkingDir: "{app}"; Tasks: desktopicon Name: "{group}\Documentation"; Filename: "{app}\docs\index.html" Name: "{group}\Uninstall Stella"; Filename: "{uninstallexe}" stella-3.9.3/src/win32/Stella.sln0000755000175000001440000000231311436517457016111 0ustar stephenusersMicrosoft 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-3.9.3/src/zlib/0000755000175000001440000000000012267274562014143 5ustar stephenusersstella-3.9.3/src/zlib/infback.c0000644000175000001440000005421212142211542015665 0ustar stephenusers/* infback.c -- inflate using a call-back interface * Copyright (C) 1995-2011 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 = 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-3.9.3/src/zlib/adler32.c0000644000175000001440000001151012102267706015527 0ustar stephenusers/* adler32.c -- compute the Adler-32 checksum of a data stream * Copyright (C) 1995-2011 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id: adler32.c 2594 2013-01-30 19:08:54Z stephena $ */ #include "zutil.h" #define local static local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); #define BASE 65521 /* 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( uLong adler, const Bytef *buf, uInt 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); } /* ========================================================================= */ 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 >= (BASE << 1)) sum2 -= (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-3.9.3/src/zlib/compress.c0000644000175000001440000000467612142211542016134 0ustar stephenusers/* compress.c -- compress a memory buffer * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id: compress.c 2723 2013-05-07 14:44:50Z stephena $ */ #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; stream.next_in = (z_const Bytef *)source; stream.avail_in = (uInt)sourceLen; #ifdef MAXSEG_64K /* Check for source > 64K on 16-bit machine: */ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; #endif stream.next_out = dest; stream.avail_out = (uInt)*destLen; if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; stream.opaque = (voidpf)0; err = deflateInit(&stream, level); if (err != Z_OK) return err; err = deflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { deflateEnd(&stream); return err == Z_OK ? Z_BUF_ERROR : err; } *destLen = stream.total_out; err = deflateEnd(&stream); return 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-3.9.3/src/zlib/gzwrite.c0000644000175000001440000003736212142211542015772 0ustar stephenusers/* gzwrite.c -- zlib functions for writing gzip files * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 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)); /* Initialize state for writing a gzip file. Mark initialization by setting state->size to non-zero. Return -1 on failure or 0 on success. */ local int gz_init( gz_statep state) { int ret; z_streamp strm = &(state->strm); /* allocate input buffer */ state->in = (unsigned char *)malloc(state->want); 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; } } /* 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, 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, got; unsigned have; 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) { got = write(state->fd, strm->next_in, strm->avail_in); if (got < 0 || (unsigned)got != strm->avail_in) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } strm->avail_in = 0; 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))) { have = (unsigned)(strm->next_out - state->x.next); if (have && ((got = write(state->fd, state->x.next, have)) < 0 || (unsigned)got != have)) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } if (strm->avail_out == 0) { strm->avail_out = state->size; strm->next_out = state->out; } state->x.next = strm->next_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 error, 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; } /* -- see zlib.h -- */ int ZEXPORT gzwrite( gzFile file, voidpc buf, unsigned len) { unsigned put = len; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return 0; 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 0; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids the flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); return 0; } /* 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 (strm->avail_in == 0) strm->next_in = state->in; have = (unsigned)((strm->next_in + strm->avail_in) - state->in); copy = state->size - have; if (copy > len) copy = len; memcpy(state->in + have, buf, copy); 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 (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* directly compress user buffer to file */ strm->avail_in = len; strm->next_in = (z_const Bytef *)buf; state->x.pos += len; if (gz_comp(state, Z_NO_FLUSH) == -1) return 0; } /* input was all buffered or compressed (put will fit in int) */ return (int)put; } /* -- 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] = c; strm->avail_in++; state->x.pos++; return c & 0xff; } } /* no room in buffer or not initialized, use gz_write() */ buf[0] = c; if (gzwrite(file, buf, 1) != 1) return -1; return c & 0xff; } /* -- see zlib.h -- */ int ZEXPORT gzputs( gzFile file, const char *str) { int ret; unsigned len; /* write string */ len = (unsigned)strlen(str); ret = gzwrite(file, 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 size, len; 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 0; /* make sure we have some buffer space */ 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; } /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* do the printf() into the input buffer, put length in len */ size = (int)(state->size); state->in[size - 1] = 0; #ifdef NO_vsnprintf # ifdef HAS_vsprintf_void (void)vsprintf((char *)(state->in), format, va); for (len = 0; len < size; len++) if (state->in[len] == 0) break; # else len = vsprintf((char *)(state->in), format, va); # endif #else # ifdef HAS_vsnprintf_void (void)vsnprintf((char *)(state->in), size, format, va); len = strlen((char *)(state->in)); # else len = vsnprintf((char *)(state->in), size, format, va); # endif #endif /* check that printf() results fit in buffer */ if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) return 0; /* update buffer and position, defer compression until needed */ strm->avail_in = (unsigned)len; strm->next_in = state->in; state->x.pos += len; 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) { int size, len; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that can really pass pointer in ints */ if (sizeof(int) != sizeof(void *)) return 0; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* make sure we have some buffer space */ 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; } /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* do the printf() into the input buffer, put length in len */ size = (int)(state->size); state->in[size - 1] = 0; #ifdef NO_snprintf # ifdef HAS_sprintf_void sprintf((char *)(state->in), 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 (state->in[len] == 0) break; # else len = sprintf((char *)(state->in), 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((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); len = strlen((char *)(state->in)); # else len = snprintf((char *)(state->in), 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 >= (int)size || state->in[size - 1] != 0) return 0; /* update buffer and position, defer compression until needed */ strm->avail_in = (unsigned)len; strm->next_in = state->in; state->x.pos += len; return len; } #endif /* -- see zlib.h -- */ int ZEXPORT gzflush( gzFile file, int flush) { 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 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 -1; } /* compress remaining data with requested flush */ 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 -1; } /* 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_PARTIAL_FLUSH) == -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-3.9.3/src/zlib/inffast.c0000644000175000001440000003211612142211542015721 0ustar stephenusers/* inffast.c -- fast decoding * Copyright (C) 1995-2008, 2010, 2013 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" #ifndef ASMINF /* Allow machine dependent optimization for post-increment or pre-increment. Based on testing to date, Pre-increment preferred for: - PowerPC G3 (Adler) - MIPS R5000 (Randers-Pehrson) Post-increment preferred for: - none No measurable difference: - Pentium III (Anderson) - M68060 (Nikl) */ #ifdef POSTINC # define OFF 0 # define PUP(a) *(a)++ #else # define OFF 1 # define PUP(a) *++(a) #endif /* 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 - OFF; last = in + (strm->avail_in - 5); out = strm->next_out - OFF; 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)(PUP(in)) << bits; bits += 8; hold += (unsigned long)(PUP(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)); PUP(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)(PUP(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)(PUP(in)) << bits; bits += 8; hold += (unsigned long)(PUP(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)(PUP(in)) << bits; bits += 8; if (bits < op) { hold += (unsigned long)(PUP(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 { PUP(out) = 0; } while (--len); continue; } len -= op - whave; do { PUP(out) = 0; } while (--op > whave); if (op == 0) { from = out - dist; do { PUP(out) = PUP(from); } while (--len); continue; } #endif } from = window - OFF; if (wnext == 0) { /* very common case */ from += wsize - op; if (op < len) { /* some from window */ len -= op; do { PUP(out) = PUP(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 { PUP(out) = PUP(from); } while (--op); from = window - OFF; if (wnext < len) { /* some from start of window */ op = wnext; len -= op; do { PUP(out) = PUP(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 { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } while (len > 2) { PUP(out) = PUP(from); PUP(out) = PUP(from); PUP(out) = PUP(from); len -= 3; } if (len) { PUP(out) = PUP(from); if (len > 1) PUP(out) = PUP(from); } } else { from = out - dist; /* copy direct from output */ do { /* minimum length is three */ PUP(out) = PUP(from); PUP(out) = PUP(from); PUP(out) = PUP(from); len -= 3; } while (len > 2); if (len) { PUP(out) = PUP(from); if (len > 1) PUP(out) = PUP(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 + OFF; strm->next_out = out + OFF; 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-3.9.3/src/zlib/gzguts.h0000644000175000001440000001463012142211542015620 0ustar stephenusers/* gzguts.h -- zlib internal header definitions for gz* operations * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 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 #include #ifdef _WIN32 # include #endif #if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) # include #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, yet still not supported by Microsoft more than a decade later!), _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 */ #ifdef _MSC_VER # define snprintf _snprintf #endif #ifndef local # define local static #endif /* 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 */ 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-3.9.3/src/zlib/trees.h0000644000175000001440000002043011416156702015423 0ustar stephenusers/* 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-3.9.3/src/zlib/inflate.h0000644000175000001440000001437711416156702015740 0ustar stephenusers/* inflate.h -- internal inflate state definition * Copyright (C) 1995-2009 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, /* 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 10K bytes. */ struct inflate_state { 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 */ 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-3.9.3/src/zlib/zconf.h0000644000175000001440000003650512142211542015421 0ustar stephenusers/* zconf.h -- configuration of the zlib compression library * Copyright (C) 1995-2013 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id: zconf.h 2723 2013-05-07 14:44:50Z stephena $ */ #ifndef ZCONF_H #define ZCONF_H /** Added by SA *********/ #ifdef HAVE_INTTYPES #define Z_HAVE_UNISTD_H #endif #define ZLIB_CONST /**************************/ /* * 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 */ # 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 # 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 deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # 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 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 gzvprintf z_gzvprintf # 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 gzwrite z_gzwrite # endif # define inflate z_inflate # define inflateBack z_inflateBack # define inflateBackEnd z_inflateBackEnd # define inflateBackInit_ z_inflateBackInit_ # define inflateCopy z_inflateCopy # define inflateEnd z_inflateEnd # define inflateGetHeader z_inflateGetHeader # 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 inflateSetDictionary z_inflateSetDictionary # define inflateGetDictionary z_inflateGetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint # define inflateUndermine z_inflateUndermine # define inflateResetKeep z_inflateResetKeep # 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 # 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 /* Some Mac compilers merge all .h files incorrectly: */ #if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) # define NO_DUMMY_DECL #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 a few 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-3.9.3/src/zlib/inftrees.h0000644000175000001440000000556011416156702016127 0ustar stephenusers/* 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-3.9.3/src/zlib/uncompr.c0000644000175000001440000000374112142211542015754 0ustar stephenusers/* uncompr.c -- decompress a memory buffer * Copyright (C) 1995-2003, 2010 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id: uncompr.c 2723 2013-05-07 14:44:50Z stephena $ */ #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 actual size of the compressed buffer. 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. */ int ZEXPORT uncompress ( Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen) { z_stream stream; int err; stream.next_in = (z_const Bytef *)source; stream.avail_in = (uInt)sourceLen; /* Check for source > 64K on 16-bit machine: */ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; stream.next_out = dest; stream.avail_out = (uInt)*destLen; if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; err = inflateInit(&stream); if (err != Z_OK) return err; err = inflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { inflateEnd(&stream); if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) return Z_DATA_ERROR; return err; } *destLen = stream.total_out; err = inflateEnd(&stream); return err; } stella-3.9.3/src/zlib/trees.c0000644000175000001440000012403012142211542015406 0ustar stephenusers/* trees.c -- output deflated data using Huffman coding * Copyright (C) 1995-2012 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: trees.c 2723 2013-05-07 14:44:50Z stephena $ */ /* #define GEN_TREES_H */ #include "deflate.h" #ifdef DEBUG # include #endif /* =========================================================================== * 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 static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; local static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; local 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)); local void copy_block OF((deflate_state *s, charf *buf, unsigned len, int header)); #ifdef GEN_TREES_H local void gen_trees_header OF((void)); #endif #ifndef 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 /* 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 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 /* !DEBUG */ #define send_bits(s, value, length) \ { int len = length;\ if (s->bi_valid > (int)Buf_size - len) {\ int val = 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 /* 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 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 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 * (bits + xbits); if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); } if (overflow == 0) return; Trace((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) { Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); s->opt_len += ((long)bits - (long)tree[m].Len) *(long)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 */ ush 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++) { next_code[bits] = code = (code + bl_count[bits-1]) << 1; } /* 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*(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 */ #ifdef DEBUG s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; #endif copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ } /* =========================================================================== * 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 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 output the encoded block to the zip file. */ 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 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 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 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 -= 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 DEBUG s->bits_sent = (s->bits_sent+7) & ~7; #endif } /* =========================================================================== * Copy a stored block, storing first the length and its * one's complement if requested. */ local void copy_block( deflate_state *s, charf *buf, unsigned len, int header) { bi_windup(s); /* align on byte boundary */ if (header) { put_short(s, (ush)len); put_short(s, (ush)~len); #ifdef DEBUG s->bits_sent += 2*16; #endif } #ifdef DEBUG s->bits_sent += (ulg)len<<3; #endif while (len--) { put_byte(s, *buf++); } } stella-3.9.3/src/zlib/inflate.c0000644000175000001440000015022012142211542015706 0ustar stephenusers/* inflate.c -- zlib decompression * Copyright (C) 1995-2012 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 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)); int ZEXPORT inflateResetKeep( z_streamp strm) { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) 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 (strm == Z_NULL || strm->state == Z_NULL) 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 (strm == Z_NULL || strm->state == Z_NULL) 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) + 1; #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->window = Z_NULL; 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 (strm == Z_NULL || strm->state == Z_NULL) 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 + bits > 32) return Z_STREAM_ERROR; value &= (1L << bits) - 1; state->hold += value << state->bits; state->bits += 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 (strm == Z_NULL || strm->state == Z_NULL || 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 */ 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; else if (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) 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) 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) 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) 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->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++] = len; } while (len && copy < have); if (state->flags & 0x0200) 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++] = len; } while (len && copy < have); if (state->flags & 0x0200) 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 (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 (out) strm->adler = state->check = UPDATE(state->check, put - out, out); out = left; if (( #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 && out) strm->adler = state->check = UPDATE(state->check, strm->next_out - out, out); strm->data_type = 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 (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) 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 (strm == Z_NULL || strm->state == Z_NULL) 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 (strm == Z_NULL || strm->state == Z_NULL) 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 (strm == Z_NULL || strm->state == Z_NULL) 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 (strm == Z_NULL || strm->state == Z_NULL) 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 (strm == Z_NULL || strm->state == Z_NULL) 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 (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) 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)); 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 (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; state->sane = !subvert; #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR return Z_OK; #else state->sane = 1; return Z_DATA_ERROR; #endif } long ZEXPORT inflateMark( z_streamp strm) { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16; state = (struct inflate_state FAR *)strm->state; return ((long)(state->back) << 16) + (state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)); } stella-3.9.3/src/zlib/crc32.h0000644000175000001440000007354212102267706015231 0ustar stephenusers/* 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-3.9.3/src/zlib/inftrees.c0000644000175000001440000003132712142211542016111 0ustar stephenusers/* inftrees.c -- generate Huffman trees for efficient decoding * Copyright (C) 1995-2013 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.8 Copyright 1995-2013 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 */ int end; /* use base and extra for symbol > end */ 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, 72, 78}; 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 */ end = 19; break; case LENS: base = lbase; base -= 257; extra = lext; extra -= 257; end = 256; break; default: /* DISTS */ base = dbase; extra = dext; end = -1; } /* 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 ((int)(work[sym]) < end) { here.op = (unsigned char)0; here.val = work[sym]; } else if ((int)(work[sym]) > end) { here.op = (unsigned char)(extra[work[sym]]); here.val = base[work[sym]]; } 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-3.9.3/src/zlib/gzread.c0000644000175000001440000004422712142211542015551 0ustar stephenusers/* gzread.c -- zlib functions for reading gzip files * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 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)); /* 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; *have = 0; do { ret = read(state->fd, buf + *have, len - *have); if (ret <= 0) break; *have += 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) { if (state->out != NULL) free(state->out); if (state->in != NULL) 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; } /* -- see zlib.h -- */ int ZEXPORT gzread( gzFile file, voidp buf, unsigned len) { unsigned got, n; 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 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 the flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); return -1; } /* 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 -1; } /* get len bytes to buf, or less than len if at the end */ got = 0; do { /* first just try copying data from the output buffer */ if (state->x.have) { n = state->x.have > len ? len : 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 && 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 || len < (state->size << 1)) { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) return -1; 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, len, &n) == -1) return -1; } /* large len -- decompress directly into user buffer */ else { /* state->how == GZIP */ strm->avail_out = len; strm->next_out = (unsigned char *)buf; if (gz_decomp(state) == -1) return -1; 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 (will fit in int) */ return (int)got; } /* -- 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 gzread() */ ret = gzread(file, 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] = 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] = 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-3.9.3/src/zlib/crc32.c0000644000175000001440000003144612102267706015221 0ustar stephenusers/* crc32.c -- compute the CRC-32 of a data stream * Copyright (C) 1995-2006, 2010, 2011, 2012 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: crc32.c 2594 2013-01-30 19:08:54Z stephena $ */ /* 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 */ #define local static /* 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 *, unsigned)); local unsigned long crc32_big OF((unsigned long, const unsigned char FAR *, unsigned)); # 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( unsigned long crc, const unsigned char FAR *buf, uInt 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; } #ifdef BYFOUR /* ========================================================================= */ #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, unsigned len) { register z_crc_t c; register 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, unsigned len) { register z_crc_t c; register 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; buf4--; while (len >= 32) { DOBIG32; len -= 32; } while (len >= 4) { DOBIG4; len -= 4; } buf4++; 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-3.9.3/src/zlib/README0000644000175000001440000001210112142211542014773 0ustar stephenusersZLIB DATA COMPRESSION LIBRARY zlib 1.2.8 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.8 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-2013 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-3.9.3/src/zlib/zutil.h0000644000175000001440000001523312142211542015444 0ustar stephenusers/* zutil.h -- internal interface and configuration of the compression library * Copyright (C) 1995-2013 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: zutil.h 2723 2013-05-07 14:44:50Z stephena $ */ #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 /* 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 0x01 #endif #if defined(VAXC) || defined(VMS) # define OS_CODE 0x02 # define F_OPEN(name, mode) \ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") #endif #if defined(ATARI) || defined(atarist) # define OS_CODE 0x05 #endif #ifdef OS2 # define OS_CODE 0x06 # if defined(M_I86) && !defined(Z_SOLO) # include # endif #endif #if defined(MACOS) || defined(TARGET_OS_MAC) # define OS_CODE 0x07 # 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 TOPS20 # define OS_CODE 0x0a #endif #ifdef WIN32 # ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ # define OS_CODE 0x0b # endif #endif #ifdef __50SERIES /* Prime/PRIMOS */ # define OS_CODE 0x0f #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 0x03 /* 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 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 */ stella-3.9.3/src/zlib/module.mk0000644000175000001440000000067211416156702015754 0ustar stephenusersMODULE := 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-3.9.3/src/zlib/deflate.h0000644000175000001440000003102512142211542015676 0ustar stephenusers/* deflate.h -- internal compression state * Copyright (C) 1995-2012 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: deflate.h 2723 2013-05-07 14:44:50Z stephena $ */ #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 #define EXTRA_STATE 69 #define NAME_STATE 73 #define COMMENT_STATE 91 #define HCRC_STATE 103 #define BUSY_STATE 113 #define FINISH_STATE 666 /* 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 */ 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 */ uInt 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 */ uInt 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 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++] = (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 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 = (length); \ ush dist = (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-3.9.3/src/zlib/gzlib.c0000644000175000001440000003754412142211542015410 0ustar stephenusers/* gzlib.c -- zlib functions common to reading and writing gzip files * Copyright (C) 2004, 2010, 2011, 2012, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" #if defined(_WIN32) && !defined(__BORLANDC__) # 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; 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 _WIN32 if (fd == -2) { len = wcstombs(NULL, path, 0); if (len == (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 _WIN32 if (fd == -2) if (len) wcstombs(state->path, path, len + 1); else *(state->path) = 0; else #endif #if !defined(NO_snprintf) && !defined(NO_vsnprintf) 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 _WIN32 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) 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) snprintf(path, 7 + 3 * sizeof(int), "", fd); /* for debugging */ #else sprintf(path, "", fd); /* for debugging */ #endif gz = gz_open(path, fd, mode); free(path); return gz; } /* -- see zlib.h -- */ #ifdef _WIN32 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 < 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) 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 return; } #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-3.9.3/src/zlib/zutil.c0000644000175000001440000001632512142211542015442 0ustar stephenusers/* zutil.c -- target dependent utility functions for the compression library * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id: zutil.c 2723 2013-05-07 14:44:50Z stephena $ */ #include "zutil.h" #ifndef Z_SOLO # include "gzguts.h" #endif #ifndef NO_DUMMY_DECL struct internal_state {int dummy;}; /* for buggy compilers */ #endif z_const char * const z_errmsg[10] = { "need dictionary", /* Z_NEED_DICT 2 */ "stream end", /* Z_STREAM_END 1 */ "", /* Z_OK 0 */ "file error", /* Z_ERRNO (-1) */ "stream error", /* Z_STREAM_ERROR (-2) */ "data error", /* Z_DATA_ERROR (-3) */ "insufficient memory", /* Z_MEM_ERROR (-4) */ "buffer error", /* Z_BUF_ERROR (-5) */ "incompatible version",/* Z_VERSION_ERROR (-6) */ ""}; 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 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 DEBUG # 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 = opaque; /* just to make some compilers happy */ ulg bsize = (ulg)items*size; /* 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; 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; } ptr = opaque; /* just to make some compilers happy */ 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) { if (opaque) opaque = 0; /* to make compiler happy */ return _halloc((long)items, size); } void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { if (opaque) opaque = 0; /* to make compiler happy */ _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) { if (opaque) items += size - size; /* make compiler happy */ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : (voidpf)calloc(items, size); } void ZLIB_INTERNAL zcfree ( voidpf opaque, voidpf ptr) { free(ptr); if (opaque) return; /* make compiler happy */ } #endif /* MY_ZCALLOC */ #endif /* !Z_SOLO */ stella-3.9.3/src/zlib/gzclose.c0000644000175000001440000000124111416202310015724 0ustar stephenusers/* 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-3.9.3/src/zlib/zlib.h0000644000175000001440000025351312142211542015242 0ustar stephenusers/* zlib.h -- interface of the 'zlib' general purpose compression library version 1.2.8, April 28th, 2013 Copyright (C) 1995-2013 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.8" #define ZLIB_VERNUM 0x1280 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 #define ZLIB_VER_REVISION 8 #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 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 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 should be put there */ 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 */ uLong adler; /* adler32 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. 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 in 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 (though see inflate()) */ #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(). - Provide 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 (in interactive applications). Some output may be provided even if flush is not set. 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. 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 code 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, 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 immediately after deflateInit if all the compression is to be done in a single step. In this case, 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 adler32 checksum of all input read so far (that is, total_in bytes). deflate() may update strm->data_type if it can make a good guess about the input data type (Z_BINARY or Z_TEXT). 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), 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. If next_in is not Z_NULL and avail_in is large enough (the exact value depends on the compression method), inflateInit determines the compression method from the zlib header and allocates all data structures accordingly; otherwise the allocation will be deferred to the first call of inflate. 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 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 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), next_in is updated and processing will resume at this point for the next call of inflate(). - Provide 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. 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. Also to assist in this, on return inflate() will set 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 adler32 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, so applications that need that information should instead use raw inflate, see inflateInit2() below, or inflateBack() and perform their own processing of the gzip header and trailer. When processing gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output producted so far. The CRC-32 is checked against the gzip trailer. 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), Z_STREAM_ERROR if the stream structure was inconsistent (for example next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no progress is 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 desired. */ 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, Z_STREAM_ERROR if the stream state was inconsistent. In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* 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. 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 an adler32 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 255 (unknown). If a gzip stream is being written, strm->adler is a crc32 instead of an adler32. 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 adler32 value of the dictionary; the decompressor may later use this value to determine which dictionary has been used by the compressor. (The adler32 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 adler32 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 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 all the internal compression state. The stream will keep the same compression level and any other attributes that may have been set by deflateInit2. 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 level is changed, the input available so far is compressed with the old level (and may be flushed); the new level will take effect only at the next call of deflate(). Before the call of deflateParams, the stream state must be set as for a call of deflate(), since the currently available input may have to be compressed and flushed. In particular, strm->avail_out must be non-zero. deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if strm->avail_out was zero. */ 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 adler32 or a crc32 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 crc32 instead of an adler32. 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 adler32 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 adler32 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 all 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. 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 -1 << 16 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 normal behavior of inflate(), which expects either a zlib or gzip 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: 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 buffer. 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 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. */ 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 buffer. 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. */ /* 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. Two buffers are allocated, either both of the specified size when writing, or one of the specified size and the other twice that size when reading. 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. gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not opened for writing. */ 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. */ 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 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 0 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 concatented 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 CRC32 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_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_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)); #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)) #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 */ /* hack for buggy compilers */ #if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) struct internal_state {int dummy;}; #endif /* 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 inflateResetKeep OF((z_streamp)); ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); #if defined(_WIN32) && !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-3.9.3/src/zlib/deflate.c0000644000175000001440000021250112142211542015671 0ustar stephenusers/* deflate.c -- compress data using the deflation algorithm * Copyright (C) 1995-2013 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: deflate.c 2723 2013-05-07 14:44:50Z stephena $ */ #include "deflate.h" const char deflate_copyright[] = " deflate 1.2.8 Copyright 1995-2013 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 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 int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); #ifdef ASMV 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 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. */ #define EQUAL 0 /* result of memcmp for equal strings */ #ifndef NO_DUMMY_DECL struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ #endif /* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ #define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0)) /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to 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 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)); /* ========================================================================= */ 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) { 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->wrap = wrap; s->gzhead = Z_NULL; s->w_bits = windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; s->hash_bits = 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); } /* ========================================================================= */ 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 (strm == Z_NULL || strm->state == Z_NULL || 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 deflateResetKeep ( z_streamp strm) { deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { 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 = 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 (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; if (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 (strm == Z_NULL || strm->state == Z_NULL) 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 (strm == Z_NULL || strm->state == Z_NULL) 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; int err = Z_OK; if (strm == Z_NULL || strm->state == Z_NULL) 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) && strm->total_in != 0) { /* Flush the last buffer: */ err = deflate(strm, Z_BLOCK); if (err == Z_BUF_ERROR && s->pending == 0) err = Z_OK; } if (s->level != level) { 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 err; } /* ========================================================================= */ int ZEXPORT deflateTune( z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain) { deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; s = strm->state; s->good_match = good_length; s->max_lazy_match = max_lazy; s->nice_match = nice_length; s->max_chain_length = 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; Bytef *str; /* 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 (strm == Z_NULL || strm->state == Z_NULL) 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; case 2: /* gzip wrapper */ wraplen = 18; if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ 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; 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 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; } } /* ========================================================================= */ int ZEXPORT deflate ( z_streamp strm, int flush) { int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL || flush > Z_BLOCK || flush < 0) { return Z_STREAM_ERROR; } s = strm->state; if (strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0) || (s->status == FINISH_STATE && flush != Z_FINISH)) { ERR_RETURN(strm, Z_STREAM_ERROR); } if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); s->strm = strm; /* just in case */ old_flush = s->last_flush; s->last_flush = flush; /* Write the header */ if (s->status == INIT_STATE) { #ifdef GZIP if (s->wrap == 2) { 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; } 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; } } else #endif { 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); s->status = BUSY_STATE; 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); } } #ifdef GZIP if (s->status == EXTRA_STATE) { if (s->gzhead->extra != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) break; } put_byte(s, s->gzhead->extra[s->gzindex]); s->gzindex++; } if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (s->gzindex == s->gzhead->extra_len) { s->gzindex = 0; s->status = NAME_STATE; } } else s->status = NAME_STATE; } if (s->status == NAME_STATE) { if (s->gzhead->name != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) { val = 1; break; } } val = s->gzhead->name[s->gzindex++]; put_byte(s, val); } while (val != 0); if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (val == 0) { s->gzindex = 0; s->status = COMMENT_STATE; } } else s->status = COMMENT_STATE; } if (s->status == COMMENT_STATE) { if (s->gzhead->comment != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) { val = 1; break; } } val = s->gzhead->comment[s->gzindex++]; put_byte(s, val); } while (val != 0); if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (val == 0) s->status = HCRC_STATE; } else 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 + 2 <= s->pending_buf_size) { 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; } } else s->status = BUSY_STATE; } #endif /* 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); } /* 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->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; } } } Assert(strm->avail_out > 0, "bug2"); 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 (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; status = strm->state->status; if (status != INIT_STATE && status != EXTRA_STATE && status != NAME_STATE && status != COMMENT_STATE && status != HCRC_STATE && status != BUSY_STATE && status != FINISH_STATE) { return Z_STREAM_ERROR; } /* 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 (source == Z_NULL || dest == Z_NULL || source->state == 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 int 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 (int)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 = 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 = 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 DEBUG /* =========================================================================== * 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 /* 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) { register unsigned n, m; register Posf *p; 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); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; /* Slide the hash table (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. (Using level 0 permanently is not an optimal usage of zlib, so we don't care about this pathological case.) */ 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 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; \ } /* =========================================================================== * Copy without compression as much as possible from the input stream, return * the current block state. * This function does not insert new strings in the dictionary since * uncompressible data is probably not useful. This function is used * only for the level=0 compression option. * NOTE: this function should be optimized to avoid extra copying from * window to pending_buf. */ local block_state deflate_stored( deflate_state *s, int flush) { /* Stored blocks are limited to 0xffff bytes, pending_buf is limited * to pending_buf_size, and each stored block has a 5 byte header: */ ulg max_block_size = 0xffff; ulg max_start; if (max_block_size > s->pending_buf_size - 5) { max_block_size = s->pending_buf_size - 5; } /* Copy as much as possible from input to output: */ for (;;) { /* Fill the window as much as possible: */ if (s->lookahead <= 1) { Assert(s->strstart < s->w_size+MAX_DIST(s) || s->block_start >= (long)s->w_size, "slide too late"); fill_window(s); if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; if (s->lookahead == 0) break; /* flush the current block */ } Assert(s->block_start >= 0L, "block gone"); s->strstart += s->lookahead; s->lookahead = 0; /* Emit a stored block if pending_buf will be full: */ max_start = s->block_start + max_block_size; if (s->strstart == 0 || (ulg)s->strstart >= max_start) { /* strstart == 0 is possible when wraparound on 16-bit machine */ s->lookahead = (uInt)(s->strstart - max_start); s->strstart = (uInt)max_start; FLUSH_BLOCK(s, 0); } /* Flush if we may have to slide, otherwise block_start may become * negative and the data will be gone: */ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { FLUSH_BLOCK(s, 0); } } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if ((long)s->strstart > s->block_start) FLUSH_BLOCK(s, 0); return block_done; } /* =========================================================================== * 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 - (int)(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-3.9.3/src/zlib/inffixed.h0000644000175000001440000001427412102267706016106 0ustar stephenusers /* 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-3.9.3/src/zlib/inffast.h0000644000175000001440000000065311416156702015740 0ustar stephenusers/* 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-3.9.3/src/tools/0000755000175000001440000000000012267274562014343 5ustar stephenusersstella-3.9.3/src/tools/check-sig.cxx0000644000175000001440000000354412201165033016706 0ustar stephenusers#include #include #include #include #include #include #include using namespace std; typedef unsigned char uInt8; typedef unsigned int uInt32; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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[]) { if(ac != 3) { cout << "usage: " << av[0] << " \n"; exit(0); } ifstream in(av[1], ios_base::binary); in.seekg(0, ios::end); int i_size = (int) in.tellg(); in.seekg(0, ios::beg); uInt8* image = new uInt8[i_size]; in.read((char*)(image), i_size); in.close(); int s_size = 0; uInt8* sig = new uInt8[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, i_size, sig, s_size, locations); if(result > 0) { cout << setw(3) << result << " hits: \'" << av[2] << "\' - \"" << av[1] << "\" @"; for(list::iterator it = locations.begin(); it != locations.end(); ++it) cout << ' ' << hex << (int)*it; cout << endl; } delete[] image; delete[] sig; return 0; } stella-3.9.3/src/tools/update_stella_date.pl0000755000175000001440000000072612266336753020533 0ustar stephenusers#!/usr/bin/perl die if(@ARGV != 1); open( FILES, $ARGV[0]); @files = ; close( FILES ); foreach $infile (@files) { chomp $infile; print "Processing file $infile\n"; $outfile = $infile . "___"; open(IN, "$infile"); open(OUT, ">$outfile"); # Update date foreach $line () { $line =~ s/1995-2014/1995-2013/; print OUT $line; } close(IN); close(OUT); # Put back into original file system( "mv \"$outfile\" \"$infile\"" ); } stella-3.9.3/src/tools/merge_props.pl0000755000175000001440000000316312117162320017206 0ustar stephenusers#!/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}/.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-3.9.3/src/tools/PropSet.pm0000755000175000001440000000727112000340371016260 0ustar stephenuserspackage PropSet; # NOTE: If the property types ever change in Stella, the following hashmap # and array must be updated (and stay in sequence) my %prop_type = ( "Cartridge.MD5" => 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", "34", "210", "NO", "77" ); # 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"); while (($md5, $props) = each(%$hashref)) { 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-3.9.3/src/tools/romtohex.cxx0000644000175000001440000000247411747314740016736 0ustar stephenusers/** Simple program that produces a hex list of a binary object file @author Bradford W. Mott @version $Id: romtohex.cxx 2453 2012-04-29 19:43:28Z stephena $ */ #include #include #include #include using namespace std; 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; in.open(av[1]); if(in.is_open()) { in.seekg(0, ios::end); int len = (int)in.tellg(); in.seekg(0, ios::beg); unsigned char* data = new unsigned char[len]; in.read((char*)data, 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; delete[] data; } } stella-3.9.3/src/tools/prune_snapshots.pl0000755000175000001440000000355312117162320020122 0ustar stephenusers#!/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-3.9.3/src/tools/scrom.asm0000644000175000001440000001225212266336753016172 0ustar stephenusers;;============================================================================ ;; ;; SSSS tt lll lll ;; SS SS tt ll ll ;; SS tttttt eeee ll ll aaaa ;; SSSS tt ee ee ll ll aa ;; SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" ;; SS SS tt ee ll ll aa aa ;; SSSS ttt eeeee llll llll aaaaa ;; ;; Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony ;; and 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: scrom.asm,v 1.3 2005-06-16 01:11:29 stephena Exp $ ;;============================================================================ ;; ;; 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-3.9.3/src/tools/convbdf.c0000644000175000001440000006132612266336753016140 0ustar stephenusers/* * 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. * * $Id: convbdf.c 2838 2014-01-17 23:34:03Z stephena $ * */ #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-2014 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" "// $Id: convbdf.c 2838 2014-01-17 23:34:03Z stephena $\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"); return 0; } stella-3.9.3/src/tools/create_props.pl0000755000175000001440000000551512266336753017377 0ustar stephenusers#!/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-2014 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 "// \$Id\$\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* 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-3.9.3/src/tools/rom_diff.pl0000755000175000001440000000425311713242756016467 0ustar stephenusers#!/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-3.9.3/src/yacc/0000755000175000001440000000000012267274561014121 5ustar stephenusersstella-3.9.3/src/yacc/y.tab.c0000644000175000001440000015463411355673273015317 0ustar stephenusers /* A Bison parser, made by GNU Bison 2.4.1. */ /* Skeleton implementation for Bison's Yacc-like parsers in C Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 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 "2.4.1" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Using locations. */ #define YYLSP_NEEDED 0 /* Copy the first part of user declarations. */ /* Line 189 of yacc.c */ #line 1 "stella.y" #include Expression* lastExp = 0; #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 && dynamic_cast(lastExp)) delete lastExp; lastExp = 0; } /* Line 189 of yacc.c */ #line 101 "y.tab.c" /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 0 #endif /* Enabling the token table. */ #ifndef YYTOKEN_TABLE # define YYTOKEN_TABLE 0 #endif /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ 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, SHL = 268, SHR = 269, EQ = 270, NE = 271, LTE = 272, GTE = 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 SHL 268 #define SHR 269 #define EQ 270 #define NE 271 #define LTE 272 #define GTE 273 #define DEREF 274 #define UMINUS 275 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE { /* Line 214 of yacc.c */ #line 28 "stella.y" int val; char *equate; CARTDEBUG_INT_METHOD cartMethod; CPUDEBUG_INT_METHOD cpuMethod; TIADEBUG_INT_METHOD tiaMethod; Expression *exp; char *function; /* Line 214 of yacc.c */ #line 189 "y.tab.c" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif /* Copy the second part of user declarations. */ /* Line 264 of yacc.c */ #line 201 "y.tab.c" #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; #elif (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) typedef signed char yytype_int8; #else typedef short int 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 && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # 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 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 /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(e) ((void) (e)) #else # define YYUSE(e) /* empty */ #endif /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint # define YYID(n) (n) #else #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int YYID (int yyi) #else static int YYID (yyi) int yyi; #endif { return yyi; } #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 _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # ifndef _STDLIB_H # define _STDLIB_H 1 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (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 _STDLIB_H \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef _STDLIB_H # define _STDLIB_H 1 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) 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) /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else # define YYCOPY(To, From, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ } \ while (YYID (0)) # endif # endif /* 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 (YYID (0)) #endif /* 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 /* YYNRULES -- Number of states. */ #define YYNSTATES 67 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 275 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ 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 /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ static const yytype_uint8 yyprhs[] = { 0, 0, 3, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, 73, 77, 80, 83, 86, 89, 92, 95, 98, 102, 107, 109, 111, 113, 115, 117, 119 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { 39, 0, -1, 40, -1, 40, 11, 40, -1, 40, 10, 40, -1, 40, 12, 40, -1, 40, 13, 40, -1, 40, 14, 40, -1, 40, 20, 40, -1, 40, 18, 40, -1, 40, 19, 40, -1, 40, 23, 40, -1, 40, 24, 40, -1, 40, 28, 40, -1, 40, 27, 40, -1, 40, 26, 40, -1, 40, 25, 40, -1, 40, 22, 40, -1, 40, 21, 40, -1, 40, 15, 40, -1, 40, 16, 40, -1, 10, 40, -1, 32, 40, -1, 33, 40, -1, 12, 40, -1, 34, 40, -1, 23, 40, -1, 24, 40, -1, 35, 40, 36, -1, 40, 31, 40, 37, -1, 3, -1, 5, -1, 7, -1, 6, -1, 8, -1, 9, -1, 4, -1 }; /* 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 || YYTOKEN_TABLE /* 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", "'|'", "'^'", "'&'", "SHL", "SHR", "'<'", "'>'", "EQ", "NE", "LTE", "GTE", "DEREF", "UMINUS", "'['", "'~'", "'!'", "'@'", "'('", "')'", "']'", "$accept", "statement", "expression", 0 }; #endif # ifdef YYPRINT /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to token YYLEX-NUM. */ 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 /* 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 composing 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 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state STATE-NUM when YYTABLE doesn't 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, 18, 17, 11, 12, 16, 15, 14, 13, 0, 29 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { -1, 16, 17 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ #define YYPACT_NINF -15 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 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -15, -15, -8 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -1 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 }; #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 /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ { \ yychar = (Token); \ yylval = (Value); \ yytoken = YYTRANSLATE (yychar); \ YYPOPSTACK (1); \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ #define YYRHSLOC(Rhs, K) ((Rhs)[K]) #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (YYID (N)) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ while (YYID (0)) #endif /* YY_LOCATION_PRINT -- Print the location on the stream. This macro was not mandated originally: define only if we know we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT # if YYLTYPE_IS_TRIVIAL # define YY_LOCATION_PRINT(File, Loc) \ fprintf (File, "%d.%d-%d.%d", \ (Loc).first_line, (Loc).first_column, \ (Loc).last_line, (Loc).last_column) # else # define YY_LOCATION_PRINT(File, Loc) ((void) 0) # endif #endif /* YYLEX -- calling `yylex' with the right arguments. */ #ifdef YYLEX_PARAM # define YYLEX yylex (YYLEX_PARAM) #else # define YYLEX yylex () #endif /* 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 (YYID (0)) # 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 (YYID (0)) /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_value_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # else YYUSE (yyoutput); # endif switch (yytype) { default: break; } } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (yytype < YYNTOKENS) YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); else YYFPRINTF (yyoutput, "nterm %s (", 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). | `------------------------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) #else static void yy_stack_print (yybottom, yytop) yytype_int16 *yybottom; yytype_int16 *yytop; #endif { 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 (YYID (0)) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_reduce_print (YYSTYPE *yyvsp, int yyrule) #else static void yy_reduce_print (yyvsp, yyrule) YYSTYPE *yyvsp; int yyrule; #endif { int yynrhs = yyr2[yyrule]; int yyi; unsigned long int yylno = yyrline[yyrule]; 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, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) ); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyvsp, Rule); \ } while (YYID (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. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static YYSIZE_T yystrlen (const char *yystr) #else static YYSIZE_T yystrlen (yystr) const char *yystr; #endif { 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. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static char * yystpcpy (char *yydest, const char *yysrc) #else static char * yystpcpy (yydest, yysrc) char *yydest; const char *yysrc; #endif { 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 YYRESULT an error message about the unexpected token YYCHAR while in state YYSTATE. Return the number of bytes copied, including the terminating null byte. If YYRESULT is null, do not copy anything; just return the number of bytes that would be copied. As a special case, return 0 if an ordinary "syntax error" message will do. Return YYSIZE_MAXIMUM if overflow occurs during size calculation. */ static YYSIZE_T yysyntax_error (char *yyresult, int yystate, int yychar) { int yyn = yypact[yystate]; if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) return 0; else { int yytype = YYTRANSLATE (yychar); YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); YYSIZE_T yysize = yysize0; YYSIZE_T yysize1; int yysize_overflow = 0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; int yyx; # if 0 /* This is so xgettext sees the translatable formats that are constructed on the fly. */ YY_("syntax error, unexpected %s"); YY_("syntax error, unexpected %s, expecting %s"); YY_("syntax error, unexpected %s, expecting %s or %s"); YY_("syntax error, unexpected %s, expecting %s or %s or %s"); YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); # endif char *yyfmt; char const *yyf; static char const yyunexpected[] = "syntax error, unexpected %s"; static char const yyexpecting[] = ", expecting %s"; static char const yyor[] = " or %s"; char yyformat[sizeof yyunexpected + sizeof yyexpecting - 1 + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) * (sizeof yyor - 1))]; char const *yyprefix = yyexpecting; /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. */ 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 yycount = 1; yyarg[0] = yytname[yytype]; yyfmt = yystpcpy (yyformat, yyunexpected); for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; yyformat[sizeof yyunexpected - 1] = '\0'; break; } yyarg[yycount++] = yytname[yyx]; yysize1 = yysize + yytnamerr (0, yytname[yyx]); yysize_overflow |= (yysize1 < yysize); yysize = yysize1; yyfmt = yystpcpy (yyfmt, yyprefix); yyprefix = yyor; } yyf = YY_(yyformat); yysize1 = yysize + yystrlen (yyf); yysize_overflow |= (yysize1 < yysize); yysize = yysize1; if (yysize_overflow) return YYSIZE_MAXIMUM; if (yyresult) { /* 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 = yyresult; int yyi = 0; while ((*yyp = *yyf) != '\0') { if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyf += 2; } else { yyp++; yyf++; } } } return yysize; } } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) #else static void yydestruct (yymsg, yytype, yyvaluep) const char *yymsg; int yytype; YYSTYPE *yyvaluep; #endif { YYUSE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); switch (yytype) { default: break; } } /* Prevent warnings from -Wmissing-prototypes. */ #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); #else int yyparse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus int yyparse (void); #else int yyparse (); #endif #endif /* ! YYPARSE_PARAM */ /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*-------------------------. | yyparse or yypush_parse. | `-------------------------*/ #ifdef YYPARSE_PARAM #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void *YYPARSE_PARAM) #else int yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM; #endif #else /* ! YYPARSE_PARAM */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void) #else int yyparse () #endif #endif { 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 thru 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; /* 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; yytoken = 0; yyss = yyssa; yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; 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 (yyn == YYPACT_NINF) 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 (yyn == 0 || yyn == YYTABLE_NINF) 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; *++yyvsp = yylval; 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 1455 of yacc.c */ #line 66 "stella.y" { if(DEBUG_EXP) fprintf(stderr, "\ndone\n"); result.exp = (yyvsp[(1) - (1)].exp); } break; case 3: /* Line 1455 of yacc.c */ #line 69 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " +"); (yyval.exp) = new PlusExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 4: /* Line 1455 of yacc.c */ #line 70 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " -"); (yyval.exp) = new MinusExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 5: /* Line 1455 of yacc.c */ #line 71 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " *"); (yyval.exp) = new MultExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 6: /* Line 1455 of yacc.c */ #line 72 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " /"); (yyval.exp) = new DivExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 7: /* Line 1455 of yacc.c */ #line 73 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " %%"); (yyval.exp) = new ModExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 8: /* Line 1455 of yacc.c */ #line 74 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " &"); (yyval.exp) = new BinAndExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 9: /* Line 1455 of yacc.c */ #line 75 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " |"); (yyval.exp) = new BinOrExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 10: /* Line 1455 of yacc.c */ #line 76 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " ^"); (yyval.exp) = new BinXorExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 11: /* Line 1455 of yacc.c */ #line 77 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " <"); (yyval.exp) = new LessExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 12: /* Line 1455 of yacc.c */ #line 78 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " >"); (yyval.exp) = new GreaterExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 13: /* Line 1455 of yacc.c */ #line 79 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " >="); (yyval.exp) = new GreaterEqualsExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 14: /* Line 1455 of yacc.c */ #line 80 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " <="); (yyval.exp) = new LessEqualsExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 15: /* Line 1455 of yacc.c */ #line 81 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " !="); (yyval.exp) = new NotEqualsExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 16: /* Line 1455 of yacc.c */ #line 82 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " =="); (yyval.exp) = new EqualsExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 17: /* Line 1455 of yacc.c */ #line 83 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " >>"); (yyval.exp) = new ShiftRightExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 18: /* Line 1455 of yacc.c */ #line 84 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " <<"); (yyval.exp) = new ShiftLeftExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 19: /* Line 1455 of yacc.c */ #line 85 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " ||"); (yyval.exp) = new LogOrExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 20: /* Line 1455 of yacc.c */ #line 86 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " &&"); (yyval.exp) = new LogAndExpression((yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp)); lastExp = (yyval.exp); } break; case 21: /* Line 1455 of yacc.c */ #line 87 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " U-"); (yyval.exp) = new UnaryMinusExpression((yyvsp[(2) - (2)].exp)); lastExp = (yyval.exp); } break; case 22: /* Line 1455 of yacc.c */ #line 88 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " ~"); (yyval.exp) = new BinNotExpression((yyvsp[(2) - (2)].exp)); lastExp = (yyval.exp); } break; case 23: /* Line 1455 of yacc.c */ #line 89 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " !"); (yyval.exp) = new LogNotExpression((yyvsp[(2) - (2)].exp)); lastExp = (yyval.exp); } break; case 24: /* Line 1455 of yacc.c */ #line 90 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " U*"); (yyval.exp) = new ByteDerefExpression((yyvsp[(2) - (2)].exp)); lastExp = (yyval.exp); } break; case 25: /* Line 1455 of yacc.c */ #line 91 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " U@"); (yyval.exp) = new WordDerefExpression((yyvsp[(2) - (2)].exp)); lastExp = (yyval.exp); } break; case 26: /* Line 1455 of yacc.c */ #line 92 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " U<"); (yyval.exp) = new LoByteExpression((yyvsp[(2) - (2)].exp)); lastExp = (yyval.exp); } break; case 27: /* Line 1455 of yacc.c */ #line 93 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " U>"); (yyval.exp) = new HiByteExpression((yyvsp[(2) - (2)].exp)); lastExp = (yyval.exp); } break; case 28: /* Line 1455 of yacc.c */ #line 94 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " ()"); (yyval.exp) = (yyvsp[(2) - (3)].exp); lastExp = (yyval.exp); } break; case 29: /* Line 1455 of yacc.c */ #line 95 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " []"); (yyval.exp) = new ByteDerefOffsetExpression((yyvsp[(1) - (4)].exp), (yyvsp[(3) - (4)].exp)); lastExp = (yyval.exp); } break; case 30: /* Line 1455 of yacc.c */ #line 96 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " %d", (yyvsp[(1) - (1)].val)); (yyval.exp) = new ConstExpression((yyvsp[(1) - (1)].val)); lastExp = (yyval.exp); } break; case 31: /* Line 1455 of yacc.c */ #line 97 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " %s", (yyvsp[(1) - (1)].equate)); (yyval.exp) = new EquateExpression((yyvsp[(1) - (1)].equate)); lastExp = (yyval.exp); } break; case 32: /* Line 1455 of yacc.c */ #line 98 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " (CpuMethod)"); (yyval.exp) = new CpuMethodExpression((yyvsp[(1) - (1)].cpuMethod)); lastExp = (yyval.exp); } break; case 33: /* Line 1455 of yacc.c */ #line 99 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " (CartMethod)"); (yyval.exp) = new CartMethodExpression((yyvsp[(1) - (1)].cartMethod)); lastExp = (yyval.exp); } break; case 34: /* Line 1455 of yacc.c */ #line 100 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " (TiaMethod)"); (yyval.exp) = new TiaMethodExpression((yyvsp[(1) - (1)].tiaMethod)); lastExp = (yyval.exp); } break; case 35: /* Line 1455 of yacc.c */ #line 101 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " (function)"); (yyval.exp) = new FunctionExpression((yyvsp[(1) - (1)].function)); lastExp = (yyval.exp); } break; case 36: /* Line 1455 of yacc.c */ #line 102 "stella.y" { if(DEBUG_EXP) fprintf(stderr, " ERR: "); yyerror((char*)"Invalid label or constant"); return 1; } break; /* Line 1455 of yacc.c */ #line 1717 "y.tab.c" default: break; } 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: /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else { YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) { YYSIZE_T yyalloc = 2 * yysize; if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) yyalloc = YYSTACK_ALLOC_MAXIMUM; if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yyalloc); if (yymsg) yymsg_alloc = yyalloc; else { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; } } if (0 < yysize && yysize <= yymsg_alloc) { (void) yysyntax_error (yymsg, yystate, yychar); yyerror (yymsg); } else { yyerror (YY_("syntax error")); if (yysize != 0) goto yyexhaustedlab; } } #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 which 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 (yyn != YYPACT_NINF) { 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); } *++yyvsp = yylval; /* 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) yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); /* Do not reclaim the symbols of the rule which 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 /* Make sure YYID is used. */ return YYID (yyresult); } /* Line 1675 of yacc.c */ #line 104 "stella.y" stella-3.9.3/src/yacc/YaccParser.cxx0000644000175000001440000002203712266336753016706 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: YaccParser.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ //#include "YaccParser.hxx" //#ifdef __cplusplus //extern "C" { //#endif #include "Base.hxx" #include "Expression.hxx" #include "CartDebug.hxx" #include "CpuDebug.hxx" #include "TIADebug.hxx" #include "DebuggerExpressions.hxx" namespace YaccParser { #include #include #include "y.tab.h" yystype result; string errMsg; #include "y.tab.c" const string& errorMessage() { return errMsg; } Expression* getResult() { lastExp = 0; return result.exp; } const char *input, *c; enum { ST_DEFAULT, ST_IDENTIFIER, ST_OPERATOR, ST_SPACE }; int state = ST_DEFAULT; //extern int yylval; // bison provides this void setInput(const char *in) { input = c = in; state = ST_DEFAULT; } int parse(const char *in) { lastExp = 0; 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 *c) { // what base is the input in? Common::Base::Format format = Common::Base::format(); switch(*c) { case '\\': format = Common::Base::F_2; c++; break; case '#': format = Common::Base::F_10; c++; break; case '$': format = Common::Base::F_16; c++; break; default: // not a base_prefix, use default base break; } int ret = 0; switch(format) { case Common::Base::F_2: while(*c) { if(*c != '0' && *c != '1') return -1; ret *= 2; ret += (*c - '0'); c++; } return ret; case Common::Base::F_10: while(*c) { if(!isdigit(*c)) return -1; ret *= 10; ret += (*c - '0'); c++; } return ret; case Common::Base::F_16: while(*c) { // FIXME: error check! if(!isxdigit(*c)) return -1; int dig = (*c - '0'); if(dig > 9) dig = tolower(*c) - 'a' + 10; ret *= 16; ret += dig; c++; } return ret; default: fprintf(stderr, "INVALID BASE in lexer!"); return 0; } } // special methods that get e.g. CPU registers CPUDEBUG_INT_METHOD getCpuSpecial(char *c) { if(BSPF_equalsIgnoreCase(c, "a")) return &CpuDebug::a; else if(BSPF_equalsIgnoreCase(c, "x")) return &CpuDebug::x; else if(BSPF_equalsIgnoreCase(c, "y")) return &CpuDebug::y; else if(BSPF_equalsIgnoreCase(c, "pc")) return &CpuDebug::pc; else if(BSPF_equalsIgnoreCase(c, "sp")) return &CpuDebug::sp; else if(BSPF_equalsIgnoreCase(c, "c")) return &CpuDebug::c; else if(BSPF_equalsIgnoreCase(c, "z")) return &CpuDebug::z; else if(BSPF_equalsIgnoreCase(c, "n")) return &CpuDebug::n; else if(BSPF_equalsIgnoreCase(c, "v")) return &CpuDebug::v; else if(BSPF_equalsIgnoreCase(c, "d")) return &CpuDebug::d; else if(BSPF_equalsIgnoreCase(c, "i")) return &CpuDebug::i; else if(BSPF_equalsIgnoreCase(c, "b")) return &CpuDebug::b; else return 0; } // special methods that get Cart RAM/ROM internal state CARTDEBUG_INT_METHOD getCartSpecial(char *c) { if(BSPF_equalsIgnoreCase(c, "_bank")) return &CartDebug::getBank; else if(BSPF_equalsIgnoreCase(c, "_rwport")) return &CartDebug::readFromWritePort; else return 0; } // special methods that get TIA internal state TIADEBUG_INT_METHOD getTiaSpecial(char *c) { if(BSPF_equalsIgnoreCase(c, "_scan")) return &TIADebug::scanlines; else if(BSPF_equalsIgnoreCase(c, "_fcount")) return &TIADebug::frameCount; else if(BSPF_equalsIgnoreCase(c, "_cclocks")) return &TIADebug::clocksThisLine; else if(BSPF_equalsIgnoreCase(c, "_vsync")) return &TIADebug::vsyncAsInt; else if(BSPF_equalsIgnoreCase(c, "_vblank")) return &TIADebug::vblankAsInt; else return 0; } int yylex() { static char idbuf[255]; char o, p; yylval.val = 0; while(*c != '\0') { //fprintf(stderr, "looking at %c, state %d\n", *c, state); switch(state) { case ST_SPACE: yylval.val = 0; if(isspace(*c)) { c++; } else if(is_identifier(*c) || is_base_prefix(*c)) { state = ST_IDENTIFIER; } else if(is_operator(*c)) { state = ST_OPERATOR; } else { state = ST_DEFAULT; } break; case ST_IDENTIFIER: { CARTDEBUG_INT_METHOD cartMeth; CPUDEBUG_INT_METHOD cpuMeth; TIADEBUG_INT_METHOD tiaMeth; char *bufp = idbuf; *bufp++ = *c++; // might be a base prefix while(is_identifier(*c)) { // may NOT be base prefixes *bufp++ = *c++; //fprintf(stderr, "yylval==%d, *c==%c\n", yylval, *c); } *bufp = '\0'; state = ST_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().getFunction(idbuf) != 0) { yylval.function = idbuf; return FUNCTION; } else { yylval.val = const_to_int(idbuf); if(yylval.val >= 0) return NUMBER; else return ERR; } } case ST_OPERATOR: o = *c++; if(!*c) return o; if(isspace(*c)) { state = ST_SPACE; return o; } else if(is_identifier(*c) || is_base_prefix(*c)) { state = ST_IDENTIFIER; return o; } else { state = ST_DEFAULT; p = *c++; //fprintf(stderr, "o==%c, p==%c\n", o, p); 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; case ST_DEFAULT: default: yylval.val = 0; if(isspace(*c)) { state = ST_SPACE; } else if(is_identifier(*c) || is_base_prefix(*c)) { state = ST_IDENTIFIER; } else if(is_operator(*c)) { state = ST_OPERATOR; } else { yylval.val = *c++; return yylval.val; } break; } } //fprintf(stderr, "end of input\n"); return 0; // hit NUL, end of input. } #if 0 int main(int argc, char **argv) { int l; set_input(argv[1]); while( (l = yylex()) != 0 ) printf("ret %d, %d\n", l, yylval); printf("%d\n", yylval); } #endif } //#ifdef __cplusplus //} //#endif stella-3.9.3/src/yacc/stella.y0000644000175000001440000001205711355673273015604 0ustar stephenusers%{ #include Expression* lastExp = 0; #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 && dynamic_cast(lastExp)) delete lastExp; lastExp = 0; } %} %union { int val; char *equate; CARTDEBUG_INT_METHOD cartMethod; CPUDEBUG_INT_METHOD cpuMethod; TIADEBUG_INT_METHOD tiaMethod; Expression *exp; char *function; } /* 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, " %d", $1); $$ = new ConstExpression($1); lastExp = $$; } | EQUATE { if(DEBUG_EXP) fprintf(stderr, " %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, " (function)"); $$ = new FunctionExpression($1); lastExp = $$; } | ERR { if(DEBUG_EXP) fprintf(stderr, " ERR: "); yyerror((char*)"Invalid label or constant"); return 1; } ; %% stella-3.9.3/src/yacc/module.mk0000644000175000001440000000022010261143236015713 0ustar stephenusersMODULE := src/yacc MODULE_OBJS := \ src/yacc/YaccParser.o MODULE_DIRS += \ src/yacc # Include common rules include $(srcdir)/common.rules stella-3.9.3/src/yacc/README.txt0000644000175000001440000000230111355634140015601 0ustar stephenusersMakefile.yacc - Not part of the regular stella build! YaccParser.cxx - C++ wrapper for generated parser, includes hand-coded lexer YaccParser.hxx - Include in user code, declares public "methods" (actually functions) calctest.c - Not part of stella! Used for testing the lexel/parser. module.mk - Used for regular Stella build stella.y - Yacc/Bison source for parser y.tab.c, y.tab.h - Generated parser. NOT BUILT AUTOMATICALLY! I've only tested stella.y with GNU bison 1.35 and (once) with Berkeley Yacc 1.9. Hopefully your favorite version will work, too :) Even though they're generated, y.tab.c and .h are in SVN. This is so that people who don't have a local copy of bison or yacc can still compile Stella. If you modify stella.y, you MUST run "make -f Makefile.yacc" in this directory. This will regenerate y.tab.c and y.tab.h. Do this before "svn commit". If you're hacking the parser, you can test it without the rest of Stella by running "make -f Makefile.yacc calctest" in this directory, then running calctest with an expression as its argument: ./calctest '2+2' = 4 If you're trying to benchmark the lexer/parser, try adding -DBM to the g++ command that builds calctest. stella-3.9.3/src/yacc/Makefile.yacc0000644000175000001440000000073410314023774016470 0ustar stephenusers ### Note: this Makefile not used in building the main Stella binary! # can use "yacc" instead of "bison -y" all: stella.y bison -y -d stella.y calctest: stella.y calctest.c YaccParser.cxx YaccParser.hxx bison -y -d stella.y g++ -DPRINT -I../debugger -O2 -c YaccParser.cxx g++ -DBM -I../debugger -O2 -c calctest.c g++ -I../debugger -O2 -Wall -o calctest calctest.o YaccParser.o ../debugger/*Expression.o strip calctest #clean: # rm -f y.tab.* lex.yy.* *.o calctest stella-3.9.3/src/yacc/y.tab.h0000644000175000001440000000562711355634140015307 0ustar stephenusers /* A Bison parser, made by GNU Bison 2.4.1. */ /* Skeleton interface for Bison's Yacc-like parsers in C Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 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. */ /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ 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, SHL = 268, SHR = 269, EQ = 270, NE = 271, LTE = 272, GTE = 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 SHL 268 #define SHR 269 #define EQ 270 #define NE 271 #define LTE 272 #define GTE 273 #define DEREF 274 #define UMINUS 275 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE { /* Line 1676 of yacc.c */ #line 28 "stella.y" int val; char *equate; CARTDEBUG_INT_METHOD cartMethod; CPUDEBUG_INT_METHOD cpuMethod; TIADEBUG_INT_METHOD tiaMethod; Expression *exp; char *function; /* Line 1676 of yacc.c */ #line 104 "y.tab.h" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE yylval; stella-3.9.3/src/yacc/calctest.c0000644000175000001440000000103710265500466016060 0ustar stephenusers #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-3.9.3/src/yacc/YaccParser.hxx0000644000175000001440000000200712266336753016706 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: YaccParser.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef PARSER_HXX #define PARSER_HXX class Expression; //#ifdef __cplusplus //extern "C" { //#endif namespace YaccParser { int parse(const char *); Expression* getResult(); const string& errorMessage(); } //#ifdef __cplusplus //} //#endif #endif stella-3.9.3/src/emucore/0000755000175000001440000000000012267274561014641 5ustar stephenusersstella-3.9.3/src/emucore/StateManager.cxx0000644000175000001440000002324712266336753017751 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: StateManager.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #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 "StateManager.hxx" #define STATE_HEADER "03090100state" #define MOVIE_HEADER "03030000movie" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StateManager::StateManager(OSystem* osystem) : myOSystem(osystem), myCurrentSlot(0), myActiveMode(kOffMode) { reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StateManager::~StateManager() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool StateManager::isActive() { return myActiveMode != kOffMode; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool StateManager::toggleRecordMode() { #if 0 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; #endif return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool StateManager::toggleRewindMode() { // FIXME - For now, I'm going to use this to activate movie playback #if 0 // 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; } return myActiveMode == kMoviePlaybackMode; #endif return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StateManager::update() { #if 0 switch(myActiveMode) { case kMovieRecordMode: myOSystem->console().controller(Controller::Left).save(myMovieWriter); myOSystem->console().controller(Controller::Right).save(myMovieWriter); myOSystem->console().switches().save(myMovieWriter); break; case kMoviePlaybackMode: myOSystem->console().controller(Controller::Left).load(myMovieReader); myOSystem->console().controller(Controller::Right).load(myMovieReader); myOSystem->console().switches().load(myMovieReader); break; default: break; } #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StateManager::loadState(int slot) { if(&myOSystem->console()) { 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.isValid()) { 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(""); if(in.getString() != STATE_HEADER) buf << "Incompatible state " << slot << " file"; else { if(in.getString() == myOSystem->console().cartridge().name()) { if(myOSystem->console().load(in)) buf << "State " << slot << " loaded"; else buf << "Invalid data in state " << slot << " file"; } else buf << "State " << slot << " file doesn't match current ROM"; } myOSystem->frameBuffer().showMessage(buf.str()); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StateManager::saveState(int slot) { if(&myOSystem->console()) { 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.isValid()) { buf.str(""); buf << "Can't open/save to state file " << slot; myOSystem->frameBuffer().showMessage(buf.str()); return; } // 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 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) { if(&myOSystem->console()) { // Make sure the file can be opened for reading if(in.isValid()) { // 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); } } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool StateManager::saveState(Serializer& out) { try { if(&myOSystem->console()) { // Make sure the file can be opened for writing if(out.isValid()) { // 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() { #if 0 myCurrentSlot = 0; switch(myActiveMode) { case kMovieRecordMode: myMovieWriter.close(); break; case kMoviePlaybackMode: myMovieReader.close(); break; default: break; } myActiveMode = kOffMode; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StateManager::StateManager(const StateManager&) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StateManager& StateManager::operator = (const StateManager&) { assert(false); return *this; } stella-3.9.3/src/emucore/NullDev.cxx0000644000175000001440000000371512266336753016745 0ustar stephenusers//============================================================================ // // 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-2014 by Bradford W. Mott, Stephen Anthony // and 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: NullDev.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Serializer.hxx" #include "NullDev.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NullDevice::NullDevice() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NullDevice::~NullDevice() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void NullDevice::reset() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void NullDevice::install(System& system) { mySystem = &system; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 NullDevice::peek(uInt16 address) { cerr << hex << "NullDevice: peek(" << address << ")" << endl; return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool NullDevice::poke(uInt16 address, uInt8 value) { cerr << hex << "NullDevice: poke(" << address << "," << value << ")" << endl; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool NullDevice::save(Serializer& out) const { return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool NullDevice::load(Serializer& in) { return true; } stella-3.9.3/src/emucore/OSystem.hxx0000644000175000001440000005003012266336753016774 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: OSystem.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef OSYSTEM_HXX #define OSYSTEM_HXX class Cartridge; class CheatManager; class CommandMenu; class Console; class Debugger; class Launcher; class Menu; class Properties; class PropertiesSet; class SerialPort; class Settings; class Sound; class StateManager; class VideoDialog; namespace GUI { class Font; } #include "Array.hxx" #include "FSNode.hxx" #include "FrameBuffer.hxx" #include "PNGLibrary.hxx" #include "ZipHandler.hxx" #include "bspf.hxx" struct Resolution { uInt32 width; uInt32 height; string name; }; typedef Common::Array ResolutionList; 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 @version $Id: OSystem.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class OSystem { friend class EventHandler; friend class VideoDialog; public: /** Create a new OSystem abstract class */ OSystem(); /** Destructor */ virtual ~OSystem(); /** Create all child objects which belong to this OSystem */ virtual bool create(); public: /** Adds the specified settings object to the system. @param settings The settings object to add */ void attach(Settings* settings) { mySettings = settings; } /** 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 set of game properties for the system @return The properties set object */ PropertiesSet& propSet() const { return *myPropSet; } /** Get the console of the system. @return The console object */ Console& console() const { return *myConsole; } /** 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 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; } /** Get the ZIP handler of the system. @return The ZIP object, using the given file */ static ZipHandler& zip(const string& file) { myZipHandler->open(file); return *myZipHandler; } /** 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 /** Create all child objects which belong to this OSystem */ void createDebugger(Console& console); /** 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 /** Get the font object of the system @return The font reference */ const GUI::Font& font() const { return *myFont; } /** Get the info font object of the system @return The font reference */ const GUI::Font& infoFont() const { return *myInfoFont; } /** Get the small font object of the system @return The font reference */ const GUI::Font& smallFont() const { return *mySmallFont; } /** Get the launcher font object of the system @return The font reference */ const GUI::Font& launcherFont() const { return *myLauncherFont; } /** 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(); /** Set the user-interface palette which is specified in current settings. */ void setUIPalette(); /** Get the current framerate for the video system. @return The video framerate currently in use */ float frameRate() const { return myDisplayFrameRate; } /** Get the maximum dimensions of a window for the video hardware. */ uInt32 desktopWidth() const { return myDesktopWidth; } uInt32 desktopHeight() const { return myDesktopHeight; } /** Get the supported fullscreen resolutions for the video hardware. @return An array of supported resolutions */ const ResolutionList& supportedResolutions() const { return myResolutions; } /** 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); /** Deletes the currently defined console, if it exists. Also prints some statistics (fps, total frames, etc). */ void deleteConsole(); /** 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 on success, 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 (SDL 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(); /** This method determines the default mapping of joystick actions to Stella events for a specific system/platform. @param event The event which to (re)set (Event::NoType resets all) @param mode The mode for which the defaults are set */ virtual void setDefaultJoymap(Event::Type event, EventMode mode); /** This method creates events from platform-specific hardware. */ virtual void pollEvent() { } /** Informs the OSystem of a change in EventHandler state. */ virtual void stateChanged(EventHandler::State state) { } /** Returns the default save and load paths for the snapshot directory. 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 defaultSnapSaveDir() { return "~" BSPF_PATH_SEPARATOR; } virtual string defaultSnapLoadDir() { return "~" BSPF_PATH_SEPARATOR; } /** Set the position of the application window, generally using platform-specific code. Note that this method is only ever called for windowed mode, so no provisions need be made for fullscreen mode. */ virtual void setAppWindowPos(int x, int y, int w, int h) { }; protected: /** Query the OSystem video hardware for resolution information. */ virtual bool queryVideoHardware(); /** 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 EventHandler* myEventHandler; // Pointer to the FrameBuffer object FrameBuffer* myFrameBuffer; // Pointer to the Sound object Sound* mySound; // Pointer to the Settings object Settings* mySettings; // Pointer to the PropertiesSet object PropertiesSet* myPropSet; // Pointer to the (currently defined) Console object Console* myConsole; // Pointer to the serial port object SerialPort* mySerialPort; // Pointer to the Menu object Menu* myMenu; // Pointer to the CommandMenu object CommandMenu* myCommandMenu; // Pointer to the Launcher object Launcher* myLauncher; bool myLauncherUsed; // Pointer to the Debugger object Debugger* myDebugger; // Pointer to the CheatManager object CheatManager* myCheatManager; // Pointer to the StateManager object StateManager* myStateManager; // PNG object responsible for loading/saving PNG images PNGLibrary* myPNGLib; // The list of log messages string myLogMessages; // Maximum dimensions of the desktop area uInt32 myDesktopWidth, myDesktopHeight; // Supported fullscreen resolutions ResolutionList myResolutions; // 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; // ZIP static reference variable responsible for accessing ZIP files static ZipHandler* myZipHandler; private: enum { kNumUIPalettes = 2 }; 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; // The font object to use for the normal in-game GUI GUI::Font* myFont; // The info font object to use for the normal in-game GUI GUI::Font* myInfoFont; // The font object to use when space is very limited GUI::Font* mySmallFont; // The font object to use for the ROM launcher GUI::Font* myLauncherFont; // Indicates whether the main processing loop should proceed TimingInfo myTimingInfo; // Table of RGB values for GUI elements static uInt32 ourGUIColors[kNumUIPalettes][kNumColors-256]; private: /** Creates the various framebuffers/renderers available in this system (for now, that means either 'software' or 'opengl'). Note that it will only create one type per run of Stella. @return Success or failure of the framebuffer creation Note that if OpenGL mode fails because OpenGL is not available, rendering will attempt to fall back to software mode */ FBInitStatus createFrameBuffer(); /** Creates the various sound devices available in this system (for now, that means either 'SDL' or 'Null'). */ 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 @param type The bankswitch type of the ROM @param id The additional id (if any) used by the ROM @return The actual Console object, otherwise NULL (calling method is responsible for deleting it) */ Console* openConsole(const FilesystemNode& romfile, string& md5, string& type, string& id); /** 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 Pointer to the array, with size >=0 indicating valid data (calling method is responsible for deleting it) */ uInt8* 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); // Copy constructor isn't supported by this class so make it private OSystem(const OSystem&); // Assignment operator isn't supported by this class so make it private OSystem& operator = (const OSystem&); }; #endif stella-3.9.3/src/emucore/Cart0840.cxx0000644000175000001440000001436112266336753016600 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart0840.cxx,v 1.0 2006/11/17 //============================================================================ #include #include #include "System.hxx" #include "Cart0840.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge0840::Cartridge0840(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(8192u, size)); createCodeAccessBase(8192); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge0840::~Cartridge0840() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge0840::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge0840::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mask) == 0); // 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 >> shift); myHotSpotPageAccess[1] = mySystem->getPageAccess(0x0900 >> shift); myHotSpotPageAccess[2] = mySystem->getPageAccess(0x0A00 >> shift); myHotSpotPageAccess[3] = mySystem->getPageAccess(0x0B00 >> shift); myHotSpotPageAccess[4] = mySystem->getPageAccess(0x0C00 >> shift); myHotSpotPageAccess[5] = mySystem->getPageAccess(0x0D00 >> shift); myHotSpotPageAccess[6] = mySystem->getPageAccess(0x0E00 >> shift); myHotSpotPageAccess[7] = mySystem->getPageAccess(0x0F00 >> shift); // Set the page accessing methods for the hot spots System::PageAccess access(0, 0, 0, this, System::PA_READ); for(uInt32 i = 0x0800; i < 0x0FFF; i += (1 << shift)) mySystem->setPageAccess(i >> shift, 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; } 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 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; } 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 Cartridge0840::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myCurrentBank = bank; uInt16 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); // Setup the page access methods for the current bank System::PageAccess access(0, 0, 0, this, System::PA_READ); // Map ROM image into the system for(uInt32 address = 0x1000; address < 0x2000; address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge0840::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge0840::bankCount() const { return 2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge0840::patch(uInt16 address, uInt8 value) { myImage[(myCurrentBank << 12) + (address & 0x0fff)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* Cartridge0840::getImage(int& size) const { size = 8192; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge0840::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); } catch(...) { cerr << "ERROR: Cartridge0840::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge0840::load(Serializer& in) { try { if(in.getString() != name()) return false; myCurrentBank = in.getShort(); } catch(...) { cerr << "ERROR: Cartridge0840::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/MindLink.cxx0000644000175000001440000000600112266336753017070 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: MindLink.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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; // Analog pins are never used by the MindLink myAnalogPinValue[Five] = myAnalogPinValue[Nine] = maximumResistance; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MindLink::~MindLink() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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-3.9.3/src/emucore/CartFE.cxx0000644000175000001440000001277312266336753016504 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartFE.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartFE.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFE::CartridgeFE(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings), myLastAddress1(0), myLastAddress2(0), myLastAddressChanged(false) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(8192u, size)); // We use System::PageAccess.codeAccessBase, but don't allow its use // through a pointer, since the address space of FE 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(8192); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFE::~CartridgeFE() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFE::reset() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFE::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mask) == 0); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Map all of the accesses to call peek and poke for(uInt32 i = 0x1000; i < 0x2000; i += (1 << shift)) mySystem->setPageAccess(i >> shift, access); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeFE::peek(uInt16 address) { // The bank is determined by A13 of the processor // We keep track of the two most recent accesses to determine which bank // we're in, and when the values actually changed myLastAddress2 = myLastAddress1; myLastAddress1 = address; myLastAddressChanged = true; return myImage[(address & 0x0FFF) + (((address & 0x2000) == 0) ? 4096 : 0)]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFE::poke(uInt16, uInt8) { return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeFE::getAccessFlags(uInt16 address) { return myCodeAccessBase[(address & 0x0FFF) + (((address & 0x2000) == 0) ? 4096 : 0)]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFE::setAccessFlags(uInt16 address, uInt8 flags) { myCodeAccessBase[(address & 0x0FFF) + (((address & 0x2000) == 0) ? 4096 : 0)] |= flags; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFE::bank(uInt16) { // Doesn't support bankswitching in the normal sense return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeFE::bank() const { // The current bank depends on the last address accessed return ((myLastAddress1 & 0x2000) == 0) ? 1 : 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeFE::bankCount() const { return 2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFE::bankChanged() { if(myLastAddressChanged) { // A bankswitch occurs when the addresses transition from state to another myBankChanged = ((myLastAddress1 & 0x2000) == 0) != ((myLastAddress2 & 0x2000) == 0); myLastAddressChanged = false; } else myBankChanged = false; // In any event, let the base class know about it return Cartridge::bankChanged(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFE::patch(uInt16 address, uInt8 value) { myImage[(address & 0x0FFF) + (((address & 0x2000) == 0) ? 4096 : 0)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeFE::getImage(int& size) const { size = 8192; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFE::save(Serializer& out) const { try { out.putString(name()); out.putShort(myLastAddress1); out.putShort(myLastAddress2); } catch(...) { cerr << "ERROR: CartridgeFE::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFE::load(Serializer& in) { try { if(in.getString() != name()) return false; myLastAddress1 = in.getShort(); myLastAddress2 = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeF8SC::load" << endl; return false; } return true; } stella-3.9.3/src/emucore/Device.hxx0000644000175000001440000000676712266336753016612 0ustar stephenusers//============================================================================ // // 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-2014 by Bradford W. Mott, Stephen Anthony // and 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: Device.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef DEVICE_HXX #define DEVICE_HXX class System; #include "Serializable.hxx" #include "bspf.hxx" /** Abstract base class for devices which can be attached to a 6502 based system. @author Bradford W. Mott @version $Id: Device.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class Device : public Serializable { public: /** Create a new device */ Device() : mySystem(0) { } /** Destructor */ virtual ~Device() { } 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 right before the system resets its cycle counter to zero. It may be necessary to override this method for devices that remember cycle counts. */ virtual void systemCyclesReset() { } /** 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 = 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) = 0; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ virtual string name() const = 0; public: /** Get the byte at the specified address @return The byte at the specified address */ virtual uInt8 peek(uInt16 address) = 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) = 0; /** Query/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 uInt8 getAccessFlags(uInt16 address) { return 0; } virtual void setAccessFlags(uInt16 address, uInt8 flags) { } protected: /// Pointer to the system the device is installed in or the null pointer System* mySystem; }; #endif stella-3.9.3/src/emucore/MT24LC256.cxx0000644000175000001440000002435112266336753016535 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: MT24LC256.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include #include #include "System.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) { // Load the data from an external file (if it exists) ifstream in; in.open(myDataFile.c_str(), ios_base::binary); if(in.is_open()) { // Get length of file; it must be 32768 in.seekg(0, ios::end); if((int)in.tellg() == 32768) { in.seekg(0, ios::beg); in.read((char*)myData, 32768); myDataFileExists = true; } in.close(); } 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; out.open(myDataFile.c_str(), ios_base::binary); if(out.is_open()) { out.write((char*)myData, 32768); out.close(); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool MT24LC256::readSDA() { return jpee_mdat && jpee_sdat; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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::systemCyclesReset() { // System cycles are being reset to zero so we need to adjust // the cycle counts we remembered uInt32 cycles = mySystem.cycles(); myCyclesWhenSDASet -= cycles; myCyclesWhenSCLSet -= cycles; myCyclesWhenTimerSet -= cycles; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MT24LC256::jpee_init() { jpee_sdat = 1; jpee_address = 0; jpee_state=0; jpee_sizemask = 32767; jpee_pagemask = 63; jpee_smallmode = 0; jpee_logmode = -1; if(!myDataFileExists) memset(myData, 0xff, 32768); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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() { int i; 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 (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] = (unsigned char)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++] = (unsigned char)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; jpee_nb = (myData[jpee_address & jpee_sizemask] << 1) | 1; /* Fall through */ JPEE_LOG2("I2C_READ(%04X=%02X)",jpee_address,jpee_nb/2); 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 = mySystem.cycles() - myCyclesWhenTimerSet; myTimerActive = elapsed < (uInt32)(5000000.0 / 838.0); } return myTimerActive; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int MT24LC256::jpee_logproc(char const *st) { cerr << " " << st << endl; return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MT24LC256::MT24LC256(const MT24LC256& c) : mySystem(c.mySystem), myDataFile(c.myDataFile) { assert(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MT24LC256& MT24LC256::operator = (const MT24LC256&) { assert(false); return *this; } stella-3.9.3/src/emucore/CartBF.cxx0000644000175000001440000001131012266336753016463 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartBF.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartBF.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeBF::CartridgeBF(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(262144u, size)); createCodeAccessBase(262144); // Remember startup bank myStartBank = 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeBF::~CartridgeBF() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBF::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBF::install(System& system) { mySystem = &system; // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mySystem->pageMask()) == 0); // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeBF::peek(uInt16 address) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0F80) && (address <= 0x0FBF)) bank(address - 0x0F80); return myImage[(myCurrentBank << 12) + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBF::poke(uInt16 address, uInt8) { 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 myCurrentBank = bank; uInt32 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1F80 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1000; address < (0x1F80U & ~mask); address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeBF::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeBF::bankCount() const { return 64; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBF::patch(uInt16 address, uInt8 value) { myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeBF::getImage(int& size) const { size = 262144; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBF::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); } catch(...) { cerr << "ERROR: CartridgeBF::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBF::load(Serializer& in) { try { if(in.getString() != name()) return false; myCurrentBank = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeBF::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/Settings.cxx0000644000175000001440000006222412266336753017174 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Settings.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include #include #include "bspf.hxx" #include "DebuggerDialog.hxx" #include "OSystem.hxx" #include "Version.hxx" #include "Settings.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Settings::Settings(OSystem* osystem) : myOSystem(osystem) { // Add this settings object to the OSystem myOSystem->attach(this); // Add options that are common to all versions of Stella setInternal("video", "soft"); // OpenGL specific options setInternal("gl_inter", "false"); setInternal("gl_aspectn", "90"); setInternal("gl_aspectp", "100"); setInternal("gl_fsscale", "false"); setInternal("gl_lib", "libGL.so"); setInternal("gl_vsync", "true"); setInternal("gl_vbo", "true"); // Framebuffer-related options setInternal("tia_filter", "zoom2x"); setInternal("fullscreen", "0"); setInternal("fullres", "auto"); setInternal("center", "false"); setInternal("grabmouse", "true"); setInternal("palette", "standard"); setInternal("colorloss", "true"); setInternal("timing", "sleep"); setInternal("uimessages", "true"); // TV filtering options setInternal("tv_filter", "0"); 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("dsense", "5"); setInternal("msense", "7"); 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(640, 480)); setInternal("launcherfont", "medium"); setInternal("launcherexts", "allroms"); setInternal("romviewer", "0"); setInternal("lastrom", ""); // UI-related options setInternal("dbg.res", GUI::Size(DebuggerDialog::kMediumFontMinW, DebuggerDialog::kMediumFontMinH)); setInternal("uipalette", "0"); setInternal("listdelay", "300"); setInternal("mwheel", "4"); // Misc options setInternal("autoslot", "false"); setInternal("loglevel", "1"); setInternal("logtoconsole", "0"); setInternal("tiadriven", "false"); setInternal("cpurandom", "true"); setInternal("ramrandom", "true"); setInternal("avoxport", ""); setInternal("stats", "false"); setInternal("fastscbios", "false"); setExternal("romloadcount", "0"); setExternal("maxres", ""); // Debugger/disassembly options setInternal("dbg.fontstyle", "0"); setInternal("dbg.uhex", "true"); setInternal("dis.resolve", "true"); setInternal("dis.gfxformat", "2"); setInternal("dis.showaddr", "true"); setInternal("dis.relocate", "false"); // Thumb ARM emulation options setInternal("thumb.trapfatal", "true"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Settings::~Settings() { myInternalSettings.clear(); myExternalSettings.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Settings::loadConfig() { string line, key, value; string::size_type equalPos, garbage; ifstream in(myOSystem->configFile().c_str()); 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); } in.close(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 ""; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Settings::validate() { string s; int i; s = getString("video"); if(s != "soft" && s != "gl") setInternal("video", "soft"); s = getString("timing"); if(s != "sleep" && s != "busy") setInternal("timing", "sleep"); #ifdef DISPLAY_OPENGL i = getInt("gl_aspectn"); if(i < 80 || i > 120) setInternal("gl_aspectn", "100"); i = getInt("gl_aspectp"); if(i < 80 || i > 120) setInternal("gl_aspectp", "100"); i = getInt("tv_filter"); if(i < 0 || i > 5) setInternal("tv_filter", "0"); #endif #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"); if(i < 1) setInternal("dsense", "1"); else if(i > 10) setInternal("dsense", "10"); i = getInt("dsense"); if(i < 1) setInternal("dsense", "1"); else if(i > 10) setInternal("dsense", "10"); i = getInt("msense"); if(i < 1) setInternal("msense", "1"); else if(i > 15) setInternal("msense", "15"); 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"); 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() { 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" << " soft SDL software mode\n" #ifdef DISPLAY_OPENGL << " gl SDL OpenGL mode\n" << endl << " -gl_lib Specify the OpenGL library\n" << " -gl_inter <1|0> Enable interpolated (smooth) scaling\n" << " -gl_aspectn Scale the TIA width by the given percentage in NTSC mode\n" << " -gl_aspectp Scale the TIA width by the given percentage in PAL mode\n" << " -gl_fsscale <1|0> Stretch GL image in fullscreen emulation mode to max/integer scale\n" << " -gl_vsync <1|0> Enable 'synchronize to vertical blank interrupt'\n" << " -gl_vbo <1|0> Enable 'vertex buffer objects'\n" << endl << " -tv_filter <0-5> Set TV effects off (0) or to specified mode (1-5)\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 #endif << " -tia_filter Use the specified filter in emulation mode\n" << " -fullscreen <1|0|-1> Use fullscreen mode (1 or 0), or disable switching to fullscreen entirely\n" << " -fullres The resolution to use in fullscreen mode\n" << " -center <1|0> Centers game window (if possible)\n" << " -grabmouse <1|0> Keeps the mouse in the game window\n" << " -palette \n" << " -colorloss <1|0> Enable PAL color-loss effect\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 << " -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" << " -dsense Sensitivity of digital emulated paddle movement (1-10)\n" << " -msense Sensitivity of mouse emulated paddle movement (1-15)\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" << " -stats <1|0> Overlay console info during emulation\n" << " -fastscbios <1|0> Disable Supercharger BIOS progress loading bars\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" << " -uipalette <1|2> Used the specified palette for UI elements\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" << " -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" << " -maxres Used by developers to force the maximum size of the application window\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" << " -tiadriven <1|0> Drive unused TIA pins randomly on a read/peek\n" << " -cpurandom <1|0> Randomize the contents of CPU registers on reset\n" << " -ramrandom <1|0> Randomize the contents of RAM on reset\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.fontstyle <0-3> Font style to use in debugger window (bold vs. normal)\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" #endif << endl << 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(unsigned int i = 0; i < myInternalSettings.size(); ++i) { if(myInternalSettings[i].value != myInternalSettings[i].initialValue) { settingsChanged = true; break; } } if(!settingsChanged) return; ofstream out(myOSystem->configFile().c_str()); 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 << "; Commmands 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(unsigned int i = 0; i < myInternalSettings.size(); ++i) { out << myInternalSettings[i].key << " = " << myInternalSettings[i].value << endl; } out.close(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Settings::getInternalPos(const string& key) const { for(unsigned int i = 0; i < myInternalSettings.size(); ++i) if(myInternalSettings[i].key == key) return i; return -1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Settings::getExternalPos(const string& key) const { for(unsigned int 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 != -1 && pos >= 0 && pos < (int)myInternalSettings.size() && myInternalSettings[pos].key == key) { idx = pos; } else { for(unsigned int 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; setting.key = key; setting.value = value; if(useAsInitial) setting.initialValue = value; myInternalSettings.push_back(setting); idx = 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 != -1 && pos >= 0 && pos < (int)myExternalSettings.size() && myExternalSettings[pos].key == key) { idx = pos; } else { for(unsigned int 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; setting.key = key; setting.value = value; if(useAsInitial) setting.initialValue = value; myExternalSettings.push_back(setting); idx = myExternalSettings.size() - 1; /*cerr << "insert external: key = " << key << ", value = " << value << " @ index = " << idx << endl;*/ } return idx; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Settings::Settings(const Settings&) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Settings& Settings::operator = (const Settings&) { assert(false); return *this; } stella-3.9.3/src/emucore/CartFA.cxx0000644000175000001440000001621412266336753016472 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartFA.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartFA.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFA::CartridgeFA(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(12288u, size)); createCodeAccessBase(12288); // This cart contains 256 bytes extended RAM @ 0x1000 registerRamArea(0x1000, 256, 0x100, 0x00); // Remember startup bank myStartBank = 2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFA::~CartridgeFA() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA::reset() { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 256; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 256); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert(((0x1100 & mask) == 0) && ((0x1200 & mask) == 0)); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt32 j = 0x1000; j < 0x1100; j += (1 << shift)) { access.directPokeBase = &myRAM[j & 0x00FF]; access.codeAccessBase = &myCodeAccessBase[j & 0x00FF]; mySystem->setPageAccess(j >> shift, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = 0; access.type = System::PA_READ; for(uInt32 k = 0x1100; k < 0x1200; k += (1 << shift)) { access.directPeekBase = &myRAM[k & 0x00FF]; access.codeAccessBase = &myCodeAccessBase[0x100 + (k & 0x00FF)]; mySystem->setPageAccess(k >> shift, 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[(myCurrentBank << 12) + 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 myCurrentBank = bank; uInt16 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1FF8 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1200; address < (0x1FF8U & ~mask); address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeFA::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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[(myCurrentBank << 12) + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeFA::getImage(int& size) const { size = 12288; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFA::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); 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; myCurrentBank = in.getShort(); in.getByteArray(myRAM, 256); } catch(...) { cerr << "ERROR: CartridgeFA::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/Cart.hxx0000644000175000001440000003303212266336753016265 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CARTRIDGE_HXX #define CARTRIDGE_HXX #include #include class Cartridge; class Properties; class CartDebugWidget; class GuiObject; #include "bspf.hxx" #include "Array.hxx" #include "Device.hxx" #include "Settings.hxx" #include "Font.hxx" struct RamArea { uInt16 start; uInt16 size; uInt16 roffset; uInt16 woffset; }; typedef Common::Array RamAreaList; /** 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 @version $Id: Cart.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class Cartridge : public Device { 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 id Any extra info about the ROM (currently which part of a multiload game is being accessed @param system The osystem associated with the system @param settings The settings associated with the system @return Pointer to the new cartridge object allocated on the heap */ static Cartridge* create(const uInt8* image, uInt32 size, string& md5, string& dtype, string& id, const OSystem& system, Settings& settings); /** Create a new cartridge @param settings A reference to the various settings (read-only) */ Cartridge(const Settings& settings); /** Destructor */ virtual ~Cartridge(); /** Query some information about this cartridge. */ static const string& about() { return myAboutString; } /** Save the internal (patched) ROM image. @param out The output file stream to save the image */ bool save(ofstream& out); /** 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() { 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(); /** 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(); const RamAreaList& ramAreas() { return myRamAreaList; } public: ////////////////////////////////////////////////////////////////////// // The following methods are cart-specific and must be implemented // in derived classes. ////////////////////////////////////////////////////////////////////// /** Set the specified bank. */ virtual bool bank(uInt16 bank) = 0; /** Get the current bank. */ virtual uInt16 bank() const = 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 = 0; /** 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(int& size) const = 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 = 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) = 0; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ virtual string name() 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) { } /** 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 NULL; } protected: /** Add the given area to the RamArea list for this cart. @param start The beginning of the RAM area (0x0000 - 0x2000) @param size Total number of bytes of area @param roffset Offset to use when reading from RAM (read port) @param woffset Offset to use when writing to RAM (write port) */ void registerRamArea(uInt16 start, uInt16 size, uInt16 roffset, uInt16 woffset); /** 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); private: /** Get an image pointer and size for a ROM that is part of a larger, multi-ROM image. @param image A pointer to the ROM image @param size The size of the ROM image @param numroms The number of ROMs in the multicart @param md5 The md5sum for the specific cart in the ROM image @param id The ID for the specific cart in the ROM image @param settings The settings associated with the system @return The bankswitch type for the specific cart in the ROM image */ static string createFromMultiCart(const uInt8*& image, uInt32& size, uInt32 numroms, string& md5, string& id, Settings& settings); /** 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 string autodetectType(const uInt8* 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 (256 bytes RAM) */ static bool isProbablySC(const uInt8* image, uInt32 size); /** Returns true if the image is probably a 4K SuperChip (256 bytes RAM) */ static bool isProbably4KSC(const uInt8* image, uInt32 size); /** Returns true if the image probably contains ARM code in the first 1K */ static bool isProbablyARM(const uInt8* image, uInt32 size); /** Returns true if the image is probably a 0840 bankswitching cartridge */ static bool isProbably0840(const uInt8* image, uInt32 size); /** Returns true if the image is probably a 3E bankswitching cartridge */ static bool isProbably3E(const uInt8* image, uInt32 size); /** Returns true if the image is probably a 3F bankswitching cartridge */ static bool isProbably3F(const uInt8* image, uInt32 size); /** Returns true if the image is probably a 4A50 bankswitching cartridge */ static bool isProbably4A50(const uInt8* image, uInt32 size); /** Returns true if the image is probably a CTY bankswitching cartridge */ static bool isProbablyCTY(const uInt8* image, uInt32 size); /** Returns true if the image is probably a CV bankswitching cartridge */ static bool isProbablyCV(const uInt8* image, uInt32 size); /** Returns true if the image is probably a DPC+ bankswitching cartridge */ static bool isProbablyDPCplus(const uInt8* image, uInt32 size); /** Returns true if the image is probably a E0 bankswitching cartridge */ static bool isProbablyE0(const uInt8* image, uInt32 size); /** Returns true if the image is probably a E7 bankswitching cartridge */ static bool isProbablyE7(const uInt8* image, uInt32 size); /** Returns true if the image is probably an EF/EFSC bankswitching cartridge */ static bool isProbablyEF(const uInt8* image, uInt32 size, const char*& type); /** Returns true if the image is probably a BF/BFSC bankswitching cartridge */ static bool isProbablyBF(const uInt8* image, uInt32 size, const char*& type); /** Returns true if the image is probably a DF/DFSC bankswitching cartridge */ static bool isProbablyDF(const uInt8* image, uInt32 size, const char*& type); /** Returns true if the image is probably an F6 bankswitching cartridge */ static bool isProbablyF6(const uInt8* image, uInt32 size); /** Returns true if the image is probably an FA2 bankswitching cartridge */ static bool isProbablyFA2(const uInt8* image, uInt32 size); /** Returns true if the image is probably an FE bankswitching cartridge */ static bool isProbablyFE(const uInt8* image, uInt32 size); /** Returns true if the image is probably a SB bankswitching cartridge */ static bool isProbablySB(const uInt8* image, uInt32 size); /** Returns true if the image is probably a UA bankswitching cartridge */ static bool isProbablyUA(const uInt8* image, uInt32 size); /** Returns true if the image is probably an X07 bankswitching cartridge */ static bool isProbablyX07(const uInt8* image, uInt32 size); 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. uInt8* myCodeAccessBase; private: // Contains RamArea entries for those carts with accessible RAM. RamAreaList myRamAreaList; // If myBankLocked is true, ignore attempts at bankswitching. This is used // by the debugger, when disassembling/dumping ROM. bool myBankLocked; // Contains info about this cartridge in string format static string myAboutString; // Copy constructor isn't supported by cartridges so make it private Cartridge(const Cartridge&); // Assignment operator isn't supported by cartridges so make it private Cartridge& operator = (const Cartridge&); }; #endif stella-3.9.3/src/emucore/AtariVox.cxx0000644000175000001440000001176212266336753017132 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: AtariVox.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "MT24LC256.hxx" #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) : Controller(jack, event, system, Controller::AtariVox), mySerialPort((SerialPort&)port), myEEPROM(NULL), myShiftCount(0), myShiftRegister(0), myLastDataWriteCycle(0) { if(mySerialPort.openPort(portname)) myAboutString = " (using serial port \'" + portname + "\')"; else myAboutString = " (invalid serial port \'" + portname + "\')"; myEEPROM = new MT24LC256(eepromfile, system); myDigitalPinState[One] = myDigitalPinState[Two] = myDigitalPinState[Three] = myDigitalPinState[Four] = true; myAnalogPinValue[Five] = myAnalogPinValue[Nine] = maximumResistance; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AtariVox::~AtariVox() { mySerialPort.closePort(); delete myEEPROM; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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; // 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 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; // 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 AtariVox::clockDataIn(bool value) { uInt32 cycle = mySystem.cycles(); 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. if(cycle < myLastDataWriteCycle) { myShiftRegister = 0; myShiftCount = 0; } else if(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::systemCyclesReset() { myLastDataWriteCycle -= mySystem.cycles(); // The EEPROM keeps track of cycle counts, and needs to know when the // cycles are reset myEEPROM->systemCyclesReset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string AtariVox::about() const { return Controller::about() + myAboutString; } stella-3.9.3/src/emucore/Cart4K.hxx0000644000175000001440000001012712266336753016464 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart4K.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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. */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~Cartridge4K(); public: /** Reset cartridge to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { return new Cartridge4KWidget(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); /** 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); private: // The 4K ROM image for the cartridge uInt8 myImage[4096]; }; #endif stella-3.9.3/src/emucore/CartX07.hxx0000644000175000001440000001125112266336753016563 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartX07.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: CartX07.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeX07(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 64K ROM image of the cartridge uInt8 myImage[65536]; }; #endif stella-3.9.3/src/emucore/System.hxx0000644000175000001440000003542212266336753016665 0ustar stephenusers//============================================================================ // // 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-2014 by Bradford W. Mott, Stephen Anthony // and 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: System.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: System.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class System : public Serializable { public: /** Create a new system with an addressing space of 2^n bytes and pages of 2^m bytes. @param n Log base 2 of the addressing space size @param m Log base 2 of the page size */ System(uInt16 n, uInt16 m); /** Destructor */ virtual ~System(); public: /** 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); /** Attach the specified device and claim ownership of it. The device will be asked to install itself. @param device The device to attach to the system */ void attach(Device* device); /** Attach the specified processor and claim ownership of it. The processor will be asked to install itself. @param m6502 The 6502 microprocessor to attach to the system */ void attach(M6502* m6502); /** Attach the specified processor and claim ownership of it. The processor will be asked to install itself. @param m6532 The 6532 microprocessor to attach to the system */ void attach(M6532* m6532); /** Attach the specified TIA device and claim ownership of it. The device will be asked to install itself. @param tia The TIA device to attach to the system */ void attach(TIA* tia); public: /** 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() { 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() { return *myM6532; } /** Answer the TIA device attached to the system. @return The attached TIA device */ TIA& tia() { return *myTIA; } /** Answer the random generator attached to the system. @return The random generator */ Random& randGenerator() { return *myRandom; } /** 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 */ NullDevice& nullDevice() { return myNullDevice; } /** Get the total number of pages available in the system. @return The total number of pages available */ uInt16 numberOfPages() const { return myNumberOfPages; } /** Get the amount to right shift an address by to obtain its page. @return The amount to right shift an address by to get its page */ uInt16 pageShift() const { return myPageShift; } /** Get the mask to apply to an address to obtain its page offset. @return The mask to apply to an address to obtain its page offset */ uInt16 pageMask() const { return myPageMask; } public: /** Get the number of system cycles which have passed since the last time cycles were reset or the system was reset. @return The number of system cycles which have passed */ uInt32 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; } /** Reset the system cycle count to zero. The first thing that happens is that all devices are notified of the reset by invoking their systemCyclesReset method then the system cycle count is reset to zero. */ void resetCycles(); /** 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) { // For the pins that are floating, randomly decide which are high or low // Otherwise, they're specifically driven high return (myDataBusState | (myRandom->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); /** 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(); void unlockDataBus(); /** 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); 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(0), directPokeBase(0), codeAccessBase(0), device(0), type(System::PA_READ) { } PageAccess(uInt8* peek, uInt8* poke, uInt8* code, Device* dev, PageAccessType access) : directPeekBase(peek), directPokeBase(poke), codeAccessBase(code), device(dev), type(access) { } }; /** Set the page accessing method for the specified page. @param page The page accessing methods should be set for @param access The accessing methods to be used by the page */ void setPageAccess(uInt16 page, const PageAccess& access); /** Get the page accessing method for the specified page. @param page The page to get accessing methods for @return The accessing methods used by the page */ const PageAccess& getPageAccess(uInt16 page) const; /** 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; /** Mark the page containing this address as being dirty. @param addr Determines the page that is dirty */ void setDirtyPage(uInt16 addr); /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { return "System"; } private: // Mask to apply to an address before accessing memory const uInt16 myAddressMask; // Amount to shift an address by to determine what page it's on const uInt16 myPageShift; // Mask to apply to an address to obtain its page offset const uInt16 myPageMask; // Number of pages in the system const uInt16 myNumberOfPages; // Pointer to a dynamically allocated array of PageAccess structures PageAccess* myPageAccessTable; // Pointer to a dynamically allocated array for dirty pages bool* myPageIsDirtyTable; // Array of all the devices attached to the system Device* myDevices[100]; // Number of devices attached to the system uInt32 myNumberOfDevices; // 6502 processor attached to the system or the null pointer M6502* myM6502; // 6532 processor attached to the system or the null pointer M6532* myM6532; // TIA device attached to the system or the null pointer TIA* myTIA; // Many devices need a source of random numbers, usually for emulating // unknown/undefined behaviour Random* myRandom; // Number of system cycles executed since the last reset uInt32 myCycles; // Null device to use for page which are not installed NullDevice myNullDevice; // 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: // Copy constructor isn't supported by this class so make it private System(const System&); // Assignment operator isn't supported by this class so make it private System& operator = (const System&); }; #endif stella-3.9.3/src/emucore/CartCV.hxx0000644000175000001440000001070712266336753016522 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartCV.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: CartCV.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeCV(); public: /** Reset cartridge to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Pointer to the initial RAM data from the cart // This doesn't always exist, so we don't pre-allocate it uInt8* 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]; }; #endif stella-3.9.3/src/emucore/DefProps.hxx0000644000175000001440000226701312267025147017121 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: DefProps.hxx 2839 2014-01-19 19:41:27Z stephena $ //============================================================================ #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 3250 static const char* 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, Steve Beck, Phat Ho - Beck-Tech - Teldec", "006-01", "Congo Bongo (1983) (Sega)", "", "", "", "", "", "", "", "", "", "", "", "", "", "36", "", "", "" }, { "00ce0bdd43aed84a983bef38fe7f5ee3", "20th Century Fox, Bill Aspromonte", "11012", "Bank Heist (1983) (20th Century Fox)", "AKA Bonnie and Clyde, 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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "TVS1002", "Save Our Ship (1983) (TechnoVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "012b8e6ef3b5fd5aabc94075c527709d", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix (1983) (Arcadia)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01", "", "24", "", "", "" }, { "0164f26f6b38a34208cd4a2d0212afc3", "Coleco, Ed English", "2656", "Mr. Do! (1983) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "26", "", "YES", "" }, { "0173675d40a8d975763ee493377ca87d", "CBS Electronics, Ed English", "4L1751", "Roc 'n Rope (1984) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "50", "", "", "" }, { "01abcc1d2d3cba87a3aa0eb97a9d7b9c", "Jone Yuan Telephonic Enterprise Co", "", "Topy (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "01b09872dcd9556427761f0ed64aa42a", "Galaga Games", "", "River Raid (1984) (Galaga Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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, 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, Steve 'Jessica' Kitchen", "2468", "Carnival (1982) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "26", "214", "", "" }, { "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, Dan Thompson", "11020", "Earth Dies Screaming, The (1983) (20th Century Fox)", "The Day the Earth Stood Still", "", "", "", "", "", "", "", "", "", "", "", "", "29", "", "", "" }, { "034c1434280b0f2c9f229777d790d1e1", "Telegames", "5665 A016", "Baseball (1989) (Telegames) (PAL)", "AKA Super Challenge Baseball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0375f589f7da06d2d2be532e0d4d4b94", "", "", "Push (V0.04) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0383dc02cb82302da3d155fd108bfe3a", "AtariAge, Chris Spry", "26200", "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", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "26", "", "", "" }, { "045035f995272eb2deb8820111745a07", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1983) (Arcadia)", "AKA Jungle Raid", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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.", "VCS83107", "Tennis (1983) (Home Vision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "04dfb4acac1d0909e4c360fd2ac04480", "", "", "Jammed (2001) (XYPE) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "04e737c9d53cd84bfd5ee679954e4706", "Jone Yuan Telephonic Enterprise Co", "", "Checkers (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "04fccc7735155a6c1373d453b110c640", "HES, 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", "", "", "", "", "" }, { "05c60458ec69e7fe8b1be973852d84f1", "", "", "Test (1996) (J.V. Matthews) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "05ccf96247af12eef59698f1a060a54f", "Quelle", "600273", "King Arthur (1983) (Quelle) (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! (1982) (Activision) (PAL)", "AKA Das Schweinchen und der Wolf", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "06cfd57f0559f38b9293adae9128ff88", "Telegames", "4317 A009", "Adventures on GX-12 (1989) (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", "", "", "", "", "", "", "", "", "", "", "", "", "10", "", "", "" }, { "074ec425ec20579e64a7ded592155d48", "Atari - Sculptured Software, Steve Aguirre", "CX26162", "Fatal Run (Ultimate Driving) (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "075069ad80cde15eca69e3c98bd66714", "CCE", "C-803", "Bobby Is Going Home (1983) (CCE)", "AKA Bobby Vai Para Casa", "", "", "", "", "", "", "", "", "", "", "", "", "31", "", "", "" }, { "0751f342ee4cf28f2c9a6e8467c901be", "Atari, 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", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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", "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 Harland 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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 - Teldec", "USC1012", "M.A.D. (1983) (Carrere Video) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "09274c3fc1c43bf1e362fda436651fd8", "Thomas Jentzsch", "", "Acid Drop (TJ)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "8", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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, Jeff Corsiglia, Paul Allen Newell", "VC1009", "Towering Inferno (1982) (U.S. Games)", "Uses the Joystick Controllers (swapped)", "", "", "", "", "", "", "YES", "", "", "", "", "", "30", "220", "YES", "" }, { "0abf64ca504a116adca80f77f85e00fb", "", "", "Cube Conquest (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0ac0d491763153fac75f5337ce32a9d6", "", "", "SPAM Image Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0acaf71e60b89f6b6eab63db6ab84510", "", "", "This Planet Sucks (Greg Troutman) [a2]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "" }, { "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, Karl T. Olinger - Teldec", "7-001 - 3.60001 VE", "King Kong (1982) (Tigervision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "20", "", "", "" }, { "0b17ed42984000da8b727ca46143f87a", "Atari, Christopher H. Omarzu - Children's Computer Workshop", "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 'Willy' Aguilar, Michael Becker, Rob Fulop", "720111-1A, 03205", "Fathom (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "0b577e63b0c64f9779f315dca8967587", "Videospielkassette - Ariola", "PGP236", "Raketen-Angriff (Ariola) (PAL)", "AKA Missile Control", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0b8d3002d8f744a753ba434a4d39249a", "Sears Tele-Games, Robert Zdybel", "CX2619 - 49-75159", "Stellar Track (1980) (Sears)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "0bf19e40d5cd8aa5afb33b16569313e6", "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira", "CX26118", "Millipede (01-04-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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, 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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0c7926d660f903a2d6910c254660c32c", "Atari, Larry Kaplan", "CX2602, CX2602P", "Air-Sea Battle (1977) (Atari) (PAL)", "AKA Anti-Aircraft", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "38", "256", "", "" }, { "0c7bd935d9a7f2522155e48315f44fa0", "Carrere Video, Jeff Corsiglia, Paul Allen Newell - Teldec", "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", "", "", "", "", "" }, { "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, Adam Clayton, John Howard Palevich", "CX26151, CX26151P", "Dark Chambers (1988) (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, 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.", "VCS83105", "Panda Chase (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "" }, { "0ec93f519bb769e0d9f80e61f6cc8023", "Atari - GCC, Mike Feinstein, John Allred", "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, Steve Mayer, Larry Wagner", "CX26163P", "Combat (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "39", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "0", "", "YES", "" }, { "0f39fc03d579d0d93a6b729a3746843e", "Atari, 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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "0fcff6fe3b0769ad5d0cf82814d2a6d9", "Suntek", "SS-027", "Zoo Fun (Suntek) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "Quelle", "732.174 8", "Go Go Home Monster (1983) (Quelle) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "104468e44898b8e9fa4a1500fde8d4cb", "AtariAge, Chris Spry", "26200", "Princess Rescue (2013) (Sprybug)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "106326c262dfd3e8eaeabd961d2a0519", "", "", "PAL-NTSC Detector (15-11-2002) (CT)[a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "106855474c69d08c8ffa308d47337269", "Atari, Adam Clayton, John Howard Palevich", "CX26151", "Dark Chambers (1988) (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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "11cf751bc8173db105eabd119c5844ba", "", "", "Star Fire - Crosshair (12-02-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "11e7e0d9437ec98fa085284cf16d0eb4", "", "", "Bowling (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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 (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1267e3c6ca951ff1df6f222c8f813d97", "", "", "Dragonfire (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1278f74ca1dfaa9122df3eca3c5bcaad", "Quelle", "719.013 5", "Ungeheuer der Tiefe (Quelle) (PAL)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "38", "", "", "" }, { "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.", "VCS83109", "World End (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "133456269a03e3fdae6cddd65754c50d", "Tigervision - Teldec", "7-006 - 3.60008 VG", "Springer (1982) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "133a4234512e8c4e9e8c5651469d4a09", "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee", "CX26117", "Obelix (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "133b56de011d562cbab665968bde352b", "Activision, John Van Ryzin", "AG-038-04", "Cosmic Commuter (1984) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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, 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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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, Christopher H. Omarzu - Children's Computer Workshop", "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", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "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", "CX26169", "Shooting Arcade (09-19-1989) (Atari) (Prototype)", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "15dd21c2608e0d7d9f54c0d3f08cca1f", "Data Age", "112-008", "Frankenstein's Monster (1983) (Data Age)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "15fe28d0c8893be9223e8cb2d032e557", "", "", "Towering Inferno (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "52", "", "YES", "" }, { "1619bc27632f9148d8480cd813aa74c3", "Thomas Jentzsch", "", "Steeple Chase (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "A", "", "", "", "", "", "", "", "20", "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-218C", "Bumper Bash (1983) (Spectravideo) (PAL)", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "54", "", "", "" }, { "16f494f20af5dc803bc35939ef924020", "Mark De Smet", "", "Video Simon (Mark De Smet)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "16fbb36a6124567405a235821e8f69ee", "", "", "Star Fire (28-11-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "170e7589a48739cfb9cc782cbb0fe25a", "M Network, Hal Finney - INTV", "MT5666", "Astroblast (1982) (M Network) [fixed]", "Can also use left joystick", "Uncommon", "", "", "", "", "", "", "PADDLES", "", "YES", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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, Hal Finney, Bruce Pedersen - INTV", "MT5659", "Space Attack (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "28", "", "", "" }, { "17bbe288c3855c235950fea91c9504e9", "Dismac", "", "Pega Ladrao (Dismac)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "17c0a63f9a680e7a61beba81692d9297", "U.S. Games Corporation, Tom Sloper", "VC2004", "Picnic (1982) (U.S. Games)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "17d000a2882f9fdaa8b4a391ad367f00", "Atari - GCC", "CX2676", "Centipede (1982) (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", "", "", "", "", "", "", "", "", "", "", "", "54", "", "", "" }, { "1802cc46b879b229272501998c5de04f", "Atari, Christopher H. Omarzu - Children's Computer Workshop", "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.", "VCS83111", "Asteroid Fire (1983) (Home Vision) (PAL)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "25", "", "YES", "" }, { "19d9b5f8428947eae6f8e97c7f33bf44", "", "", "Fortress (Dual Version) (20-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "19e739c2764a5ab9ed08f9095aa2af0b", "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee", "CX26117", "Obelix (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "19e761e53e5ec8e9f2fceea62715ca06", "Panda", "104", "Scuba Diver (1983) (Panda)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1a23540d91f87584a04f184304a00648", "", "", "Race Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1a613ce60fc834d4970e1e674b9196b3", "Home Vision - Gem International Corp.", "VCS83135", "Tanks War (1983) (Home Vision) (PAL)", "AKA Phantom Tank", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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 Harland Landrum", "6 AR-4400", "Excalibur (Dragonstomper Beta) (1982) (Arcadia) (Prototype) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1b8c3c0bfb815b2a1010bba95998b66e", "Telegames", "", "Frogs and Flies (1989) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1b8d35d93697450ea26ebf7ff17bd4d1", "Quelle", "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, 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "26", "", "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, 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", "686.561 2 - 781627", "Mein Weg (1983) (Quelle) (PAL)", "AKA Challenge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1e1290ea102e12d7ac52820961457e2b", "Parker Brothers, Wilfredo 'Willy' Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (12-15-1983) (Parker Bros) (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, Tod Frye", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "64", "", "", "" }, { "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 (1982) (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)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1fa58679d4a39052bd9db059e8cda4ad", "Imagic, Dan Oliver", "720118-1A, 03208", "Laser Gates (1983) (Imagic)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1fa7a42c2c7d6b7a0c6a05d38c7508f4", "Coleco, 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", "", "", "", "", "", "", "", "", "", "", "", "29", "", "", "" }, { "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 Dancing Plate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "205070b6a0d454961dd9196a8e81d877", "", "", "Hangman Monkey Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2091af29b4e7b86914d79d9aaa4cbd20", "CBS Electronics, Harley H. Puthuff Jr.", "4L1802", "Donkey Kong Junior (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "20ae62fb69c6cc6e8098cca8cd080487", "Zirok", "", "Tennis (Zirok)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "20d4457ba22517253fcb62967af11b37", "Atari, Eric Manghise, Joseph Tung", "CX2640", "RealSports Baseball (1982) (Atari) (Prototype)", "AKA Foxbat", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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, Glenn Parker", "CX2684", "Galaxian (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "211f76dff0b7dad3f6fcac9d938ee61a", "JSK", "", "Custer's Viagra (JSK) (Hack) [a]", "Hack of Custer's Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "32", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "25", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "40", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "235436ab0832370e73677c9c6f0c8b06", "", "", "Beast Invaders (Double Shot) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2365e1534d67f94d8670394ab99150ce", "Thomas Jentzsch", "", "Missile Command (CX-80 Trackball) (2002) (TJ)", "Uses CX-80 Trackball Controller", "Homebrew", "", "", "", "", "", "", "TRACKBALL80", "", "", "", "", "", "", "YES", "" }, { "23d445ea19a18fb78d5035878d9fb649", "CBS Electronics, Sylvia Day, Henry Will IV", "4L1818, 4L1819, 4L1820", "Mouse Trap (1982) (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", "", "", "", "", "", "26", "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, Tom Sloper - Teldec", "USC2004", "Picnic (1983) (Carrere Video) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "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 (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "25bb080457351be724aac8a02021aa92", "CBS Electronics", "4L1784, 4L1786, 4L1787, 4L2277", "Zaxxon (1982) (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", "", "", "", "", "", "36", "", "", "" }, { "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", "", "", "", "", "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", "", "", "", "30", "", "", "" }, { "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", "Quelle", "311388", "Black Hole (1983) (Quelle) (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", "Goliath", "5", "Open Sesame (1983) (Goliath) (PAL) [a]", "AKA Open, Sesame!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "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", "", "", "", "", "", "", "", "", "", "42", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "42", "", "", "" }, { "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 (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2982e655dffc89d218a0a3072cfc6811", "", "", "Mini Golf 812631 (Hack)", "Hack of Miniature Golf", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "298387b0637173d2002770a649b4fbca", "", "", "S.I.PLIX 2 (Hack) [a]", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "28", "", "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, Todd Marshall, Wes Trager, Henry Will IV - Teldec", "USC2003", "Eggomania (1983) (Carrere Video) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "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, Mike Feinstein, John Allred", "CX2688", "Jungle Hunt (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2bc26619e31710a9884c110d8430c1da", "Atari, Bob Whitehead", "CX2652, CX2652P", "Casino (1979) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "60", "", "", "" }, { "2bc6c53b19e0097a242f22375a6a60ff", "", "", "Droid Demo 2 (David Conrad Schweinsberg) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2bee7f226d506c217163bad4ab1768c0", "Xonox - K-Tel Software - Beck-Tech", "6210, 06002, 06004, 99002", "Ghost Manor (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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 Harland 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "24", "", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2d2c5f0761e609e3c5228766f446f7f8", "Atari - Axlon, Steve DeFrisco", "CX26170, CX26170P", "Secret Quest (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2d405da70af82b20a6b3ecc3d1d2c4ec", "Genus", "", "Pitfall (Genus)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2d6741cda3000230f6bbdd5e31941c01", "CBS Electronics", "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, Ernie Runyon, Ed Salvo", "AP-2004", "Lost Luggage (1981) (Apollo) [no opening scene]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2d9e5d8d083b6367eda880e80dfdfaeb", "Selchow & Righter - QDI", "87", "Glib (1983) (Selchow & Righter)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2d9e65959808a6098c16c82a59c9d9dc", "Arcadia Corporation, Stephen Harland Landrum", "AR-4400", "Dragonstomper (1 of 3) (1982) (Arcadia) (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]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "0701-157", "2 Pak Special - Motocross, Boom Bang (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2eaf8fa9e9fdf1fcfc896926a4bdbf85", "Arcadia Corporation, Stephen Harland Landrum", "6 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "31", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "30516cfbaa1bc3b5335ee53ad811f17a", "Wizard Video Games, 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", "", "", "", "28", "", "", "" }, { "30e0ab8be713208ae9a978b34e9e8e8c", "Atari, Mike Lorenzen", "CX2630, CX2630P", "Circus Atari (1980) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01", "", "", "", "", "" }, { "30f0b49661cfcfd4ec63395fab837dc3", "Sega, Jeff Lorenz - Teldec", "004-01", "Star Trek - Strategic Operations Simulator (1983) (Sega) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3105967f7222cc36a5ac6e5f6e89a0b4", "Sega, Jeff Lorenz - Bally Midway", "011-01, 011-02", "Spy Hunter (1984) (Sega)", "Uses Joystick Coupler (Dual Control Module)", "", "", "", "", "", "", "", "", "", "", "", "", "29", "", "", "" }, { "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", "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", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "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)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "32199271dc980eb31a2cc96e10a9e244", "", "", "Radial Pong - Version 12 (Jeffry Johnston) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "321c3451129357af42a375d12afd4450", "Atari", "CX26177", "Ikari Warriors (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "32244e55ce6ec6bfbd763f33384bdc2e", "Activision, Steve Cartwright", "AX-027", "Plaque Attack (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3225676f5c0c577aeccfaa7e6bedd765", "CCE", "C-1002", "Pole Position (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "322b29e84455aa41e7cc9af463bffa89", "Atari, Robert C. Polaro", "CX2663", "Road Runner (06-25-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "44", "", "", "" }, { "324cb4a749bcac4f3db9da842b85d2f7", "Dennis Debro", "", "Climber 5 (01-05-2003) (Dennis Debro)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "28", "", "", "" }, { "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", "" }, { "327fe8cf94f3a45c35a840a453df1235", "", "", "Spice Girls Rule Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "328949872e454181223a80389d03c122", "", "", "Home Run (Unknown) (PAL)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "32d1260ea682e1bb10850fa94c04ec5f", "Atari, Alan Miller", "CX26163P", "Basketball (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "32dcd1b535f564ee38143a70a8146efe", "Xonox - K-Tel Software, Anthony R. Henderson", "99007, 6240", "Tomarc the Barbarian (1983) (Xonox)", "AKA Thundarr the Barbarian", "", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "0", "", "YES", "" }, { "3347a6dd59049b15a38394aa2dafa585", "Parker Brothers, Robert Jaeger", "PB5760", "Montezuma's Revenge (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "335793736cbf6fc99c9359ed2a32a49d", "", "", "Analog Clock (V0.0) (20-01-2003) (AD) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "335a7c5cfa6fee0f35f5824d1fa09aed", "Sega, Steve Beck, Phat Ho - Beck-Tech - 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "32", "", "YES", "" }, { "33ed6dfac4b9ea2f81f778ceddbb4a75", "Activision", "", "River Raid (1982) (SpkSoft) [t1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "340f546d59e72fb358c49ac2ca8482bb", "Sancho - Tang's Electronic Co.", "TEC003", "Skindiver (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "39", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "31", "", "", "" }, { "345758747b893e4c9bdde8877de47788", "CBS Electronics, Joseph Biel", "4L1802, 4L1803, 4L1804, 4L2278", "Venture (1982) (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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "TVS1003", "Pharaoh's Curse (1983) (TechnoVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "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", "", "", "", "", "", "", "", "", "", "", "NTSC50", "", "", "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, Dan Kitchen", "EAK-050-04", "Double Dragon (1989) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "36306070f0c90a72461551a7a4f3a209", "U.S. Games Corporation, Roger Booth, Sylvia Day, Ron Dubren, Todd Marshall, Wes Trager, Henry Will IV", "VC1007", "Name This Game (1982) (U.S. Games)", "AKA Guardians of Treasure, 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 (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "36c31bb5daeb103f488c66de67ac5075", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Bop a Buggy (1 of 3) (1983) (Arcadia)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01", "", "30", "", "", "" }, { "36c993dc328933e4dd6374a8ffe224f4", "Gameworld", "133-007", "Bermuda Triangle (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "48", "", "", "" }, { "36e47ed74968c365121eab60f48c6517", "Quelle", "343.373 7", "Master Builder (1983) (Quelle) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "36edef446ab4c2395666efc672b92ed0", "Atari - Axlon", "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 (1990) (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 (1982) (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)", "", "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, 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", "", "", "", "", "", "", "YES", "" }, { "393948436d1f4cc3192410bb918f9724", "Activision, Carol Shaw", "AX-020, AX-020-04", "River Raid (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "393e41ca8bdd35b52bf6256a968a9b89", "U.S. Games Corporation", "VC1012", "M.A.D. (1982) (U.S. Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3947eb7305b0c904256cdbc5c5956c0f", "Jone Yuan Telephonic Enterprise Co", "", "Lilly Adventure (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "30", "230", "", "" }, { "396f7bc90ab4fa4975f8c74abe4e81f0", "Atari, Larry Kaplan - Sears", "CX2612 - 99804, 49-75103", "Street Racer (1977) (Atari)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "PADDLES", "", "YES", "10", "", "", "", "", "" }, { "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 (1988) (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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "3ad58b53a1e972396890bd86c735e78d", "Arcadia Corporation, Stephen Harland Landrum", "6 AR-4400", "Excalibur Version 36 (Dragonstomper Beta) (1982) (Arcadia) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3b040ed7d1ef8acb4efdeebebdaa2052", "Tigervision", "7-008", "Miner 2049er (1982) (Tigervision) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "31", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "38", "", "", "" }, { "3b69f8929373598e1752f43f8da61aa4", "Apollo - Games by Apollo - RCA Video Jeux", "AP-2006", "Infiltrate (1981) (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", "", "", "", "", "", "", "", "25", "", "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", "", "", "", "", "", "", "", "", "", "", "", "", "27", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "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 (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3cbdf71bb9fd261fbc433717f547d738", "CCE", "C-803", "Bobby Is Going Home (1983) (CCE) (PAL)", "AKA Bobby Vai Para Casa", "Rare", "", "", "", "", "", "", "", "", "", "", "", "42", "", "", "" }, { "3cdd91e1c28d28e856c0063d602da166", "", "", "Stell-A-Sketch (03-11-1997) (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "20", "", "YES", "" }, { "3d1e83afdb4265fa2fb84819c9cfd39c", "Coleco, Henry Will IV", "2465", "Smurf - Rescue in Gargamel's Castle (1982) (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", "", "", "", "", "", "", "", "", "", "", "", "", "26", "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", "", "", "", "", "" }, { "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, Joe Gaucher, Alex Leavens", "4L1751, 4L1752, 4L1753, 4L2275", "Gorf (1982) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3e1682ddaec486d8b6b90b527aaa0fc4", "Thomas Jentzsch", "", "Robot City (V0.12) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "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, Tod Frye", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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 (1982) (Atari)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3f58f972276d1e4e0e09582521ed7a5b", "Telegames", "6082 A145", "Kung Fu Superkicks (1989) (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 (1989) (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", "Quelle", "311377", "Pygmy (1983) (Quelle) (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 (1989) (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 Monster (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", "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]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "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", "CX2681", "Battlezone (1983) (Atari)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4209e9dcdf05614e290167a1c033cfd2", "CommaVid, John Bronstein", "CM-002", "Video Life (1981) (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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "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, Todd Marshall, Wes Trager, Henry Will IV", "VC2003", "Eggomania (1982) (U.S. Games)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "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, 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, 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "457e7d4fcd56ebc47f5925dbea3ee427", "Carrere Video, Garry Kitchen - Teldec", "USC1001", "Space Jockey (1983) (Carrere Video) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "59", "", "", "" }, { "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, Roger Booth, Sylvia Day, Todd Marshall, Wes Trager, Henry Will IV - Teldec", "USC1007", "Octopus (1983) (Carrere Video) (PAL)", "AKA Name This Game", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4605a00f5b44a9cbd5803a7a55de150e", "Coleco, 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 Harland Landrum", "AR-4102", "Suicide Mission (Preview) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "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", "", "", "", "", "", "", "", "", "", "", "", "23", "", "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 (1989) (Telegames) (PAL)", "Can also use left joystick", "", "", "", "", "", "", "", "PADDLES", "", "YES", "", "", "", "", "", "" }, { "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", "CX2685", "Gravitar (04-12-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "47711c44723da5d67047990157dcb5dd", "CCE", "", "Ice Hockey (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "47911752bf113a2496dbb66c70c9e70c", "Atari, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (1983) (Atari) (PAL)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "4799a40b6e889370b7ee55c17ba65141", "Konami", "RC 100-X 02", "Pooyan (1983) (Konami)", "", "", "", "", "", "", "", "", "", "", "", "", "", "26", "220", "", "" }, { "47aad247cce2534fd70c412cb483c7e0", "Rainbow Vision - Suntek", "SS-010", "Mafia (Rainbow Vision) (PAL)", "AKA Gangster Alley", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "47abfb993ff14f502f88cf988092e055", "Zellers", "", "Inca Gold (Zellers)", "AKA Spider Kong", "", "", "", "", "", "", "", "", "", "", "", "", "29", "", "", "" }, { "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 'Willy' Aguilar, Michael Becker, Rob Fulop", "720111-2A, 13205", "Fathom (1983) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "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 'Donyo' Ruffcorn, Jack Woodman", "1003", "Fast Food (1982) (Telesys) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "484b0076816a104875e00467d431c2d2", "Atari", "CX26150", "Q-bert (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "40", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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 (1982) (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 (1989) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4947c9de2e28b2f5f3b0c40ce7e56d93", "", "", "3-D Corridor Demo 2 (29-03-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "49571b26f46620a85f93448359324c28", "", "", "Save Our Ship (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "NTSC", "38", "", "", "" }, { "497f3d2970c43e5224be99f75e97cbbb", "CommaVid, John Bronstein", "CM-002", "Video Life (1981) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4981cefe5493ea512284e7f9f27d1e54", "Home Vision - Gem International Corp.", "VCS83136", "Cosmic War (1983) (Home Vision) (PAL)", "AKA Space Tunnel", "", "", "", "", "", "", "", "", "", "", "", "", "", "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "CX26135, CX26135P", "RealSports Boxing (1987) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4ac9f40ddfcf194bd8732a75b3f2f214", "Atari, Stephan R. Keith, Preston Stuart", "CX26106", "Grover's Music Maker (12-29-1982) (Atari) (Prototype)", "Uses Kids/Keypad Controllers", "Prototype", "", "", "", "", "", "", "KEYBOARD", "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, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (12-03-1982) (Atari) (Prototype)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "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", "", "", "", "24", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "28", "", "", "" }, { "4c4ce802cbfd160f7b3ec0f13f2a29df", "", "", "Beta Demo (V1.1) (26-09-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4c606235f4ec5d2a4b89139093a69437", "Andrew Davies", "", "Andrew Davies early notBoulderDash demo (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4c6afb8a44adf8e28f49164c84144bfe", "Bit Corporation", "PG207", "Mission 3,000 A.D. (1983) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4c8832ed387bbafc055320c05205bc08", "Atari, Joe Decuir, Steve Mayer, Larry Wagner - Sears", "CX2601 - 99801, 6-99801, 49-75124", "Combat (1977) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4c8970f6c294a0a54c9c45e5e8445f93", "Xonox - K-Tel Software, 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", "7-006", "Springer (1982) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "Quelle", "781698", "Volleyball (1983) (Quelle) (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", "", "", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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 (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4f6702c3ba6e0ee2e2868d054b00c064", "Activision, Steve 'Jessica' Kitchen - Ariola", "EAZ-033 - 711 033-725", "Space Shuttle (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4f781f0476493c50dc578336f1132a67", "", "", "Indy 500 (Unknown) (PAL) (4K)", "Uses Driving Controllers", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "45", "", "", "", "", "" }, { "4f7b07ec2bef5ccffe06403a142f80db", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2003", "Racquetball (1981) (Apollo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4f82d8d78099dd71e8e169646e799d05", "", "", "Miniature Golf (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4f89b897444e7c3b36aed469b8836839", "Atari", "CX26190", "BMX Air Master (1990) (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", "", "", "", "30", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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, Todd Marshall", "PB5550", "Q-bert's Qubes (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "32", "", "", "" }, { "517923e655755086a3b72c0b17b430e6", "Tron", "", "Super Tennis (Tron)", "AKA RealSports Tennis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5188fee071d3c5ef0d66fb45c123e4a5", "Gameworld", "133-001", "Encounter at L-5 (1983) (Gameworld) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "31", "", "", "" }, { "522c9cf684ecd72db2f85053e6f6f720", "Rainbow Vision - Suntek", "SS-008", "Year 1999, The (Rainbow Vision) (PAL)", "AKA Condor Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "52385334ac9e9b713e13ffa4cc5cb940", "CCE", "C-804", "Open, Sesame! (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "523f5cbb992f121e2d100f0f9965e33f", "Joe Grand", "", "SCSIcide (1.30) (CGE 2001 Release) (Joe Grand)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "", "", "", "", "", "" }, { "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", "Arcadia Corporation, Stephen Harland Landrum, Jon Leupp", "AR-4201", "Sword of Saros (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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, Ray Miller, Todd Marshall", "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", "", "", "", "", "" }, { "542c6dd5f7280179b51917a4cba4faff", "ZiMAG - Emag - Vidco", "GN-080", "Spinning Fireball (1983) (ZiMAG) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "40", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "28", "", "", "" }, { "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", "", "", "", "", "", "", "", "" }, { "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", "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, Joe Gaucher, Alex Leavens", "CX2683", "Crazy Climber (1982) (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", "", "", "", "", "56", "", "", "" }, { "57939b326df86b74ca6404f64f89fce9", "Atari, 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, Gary Stark", "CX26102", "Cookie Monster Munch (1983) (Atari)", "Uses Kids/Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "5835a78a88f97acea38c964980b7dbc6", "", "", "Cosmic Creeps (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "5846b1d34c296bf7afc2fa05bbc16e98", "Atari, Larry Kaplan - 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "32", "", "", "" }, { "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, Steve 'Jessica' Kitchen", "AZ-033, AZ-033-04", "Space Shuttle (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "589c73bbcd77db798cb92a992b4c06c3", "Xonox - K-Tel Software, John Perkins", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "20", "", "", "" }, { "58a82e1da64a692fd727c25faef2ecc9", "CCE", "C-824", "Jaw Breaker (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "28", "", "", "" }, { "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, Glenn Parker", "CX2684", "Galaxian (01-05-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "59135f13985b84c4f13cc9e55eec869a", "", "", "Multi-Sprite Game V2.0 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5961d259115e99c30b64fe7058256bcf", "Universal Gamex Corporation, Alan Roberts, H.K. Poon", "GX-001", "X-Man (1983) (Universal)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "59734e1cc41822373845a09c51e6ba21", "Activision, John Van Ryzin", "AG-038-04", "Cosmic Commuter (1984) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "598a4e6e12f8238b7e7555f5a7777b46", "Tigervision", "7-008", "Miner 2049er (1982) (Tigervision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "40", "", "", "" }, { "59e96de9628e8373d1c685f5e57dcf10", "PlayAround - J.H.M.", "204", "Beat 'Em & Eat 'Em (1982) (PlayAround)", "Uses the Paddle Controllers", "Extremely Rare", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "59f596285d174233c84597dee6f34f1f", "CCE", "C-811", "River Raid (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a17e30e6e911e74ccd7b716d02b16c6", "Activision, Dan Kitchen", "AX-029", "Crackpots (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a272012a62becabcd52920348c7c60b", "Star Game", "", "Pitfall (Star Game)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a2f2dcd775207536d9299e768bcd2df", "Quelle", "781698", "Flippern (Double-Game Package) (1983) (Quelle) (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, Robert C. Polaro", "CX26155", "Sprint Master (1988) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5acf9865a72c0ce944979f76ff9610f0", "", "", "Dodge Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5ae73916fa1da8d38ceff674fa25a78a", "CCE", "", "Barnstorming (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5aea9974b975a6a844e6df10d2b861c4", "Atari, Dan Hitchens", "CX2656", "SwordQuest - EarthWorld (1982) (Atari)", "AKA Adventure I, SwordQuest I - EarthWorld", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5af9cd346266a1f2515e1fbc86f5186a", "Sega", "002-01", "Sub-Scan (1982) (Sega)", "AKA Subterfuge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5b124850de9eea66781a50b2e9837000", "PlayAround - J.H.M.", "205", "Bachelor Party (1982) (PlayAround)", "Uses the paddle controllers", "Extremely Rare", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "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", "Arcadia Corporation, Stephen Harland Landrum", "AR-4400", "Dragonstomper (2 of 3) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5b85e987e2b1618769d97ba9182333d0", "Atari - GCC, Mike Feinstein", "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, Ed Temple", "2654", "Looping (1983) (Coleco) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "29", "", "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, 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, Steve 'Jessica' Kitchen", "EAZ-033", "Space Shuttle (1983) (Activision) (SECAM)", "", "", "", "FE", "", "", "", "", "", "", "", "", "SECAM", "", "", "", "" }, { "5d2cc33ca798783dee435eb29debf6d6", "Activision, Mike Riedel", "AK-043-04", "Commando (1988) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5d799bfa9e1e7b6224877162accada0d", "Spectravision, Spectravideo, 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", "", "", "", "30", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5db9e5bf663cad6bf159bc395f6ead53", "Goliath - Hot Shot", "83-212", "Time Race (1983) (Goliath) (PAL)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "48", "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, Ed Salvo", "5667 A106", "Glacier Patrol (1989) (Telegames)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5e1b4629426f4992cf3b2905a696e1a7", "Activision, 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, Alan Roberts, 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, 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, Betty Ryan Tylko, Douglas B. Macrae", "CX2694", "Pole Position (1983) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5f46d1ff6d7cdeb4b09c39d04dfd50a1", "Atari, Gary Palmer", "CX2661P", "Fun with Numbers (1980) (Atari) (PAL)", "AKA Basic Math", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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 (1988) (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", "", "", "", "", "", "", "", "", "", "", "", "28", "", "YES", "" }, { "5f9b62350b31be8bd270d9a241cbd50e", "Telegames", "5658 A088", "Football (1989) (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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "38", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "36", "", "", "" }, { "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", "", "38", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "" }, { "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, Mike Riedel", "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", "" }, { "62921652f6634eb1a0940ed5489c7e18", "", "", "SCSIcide (V1.09) (2001) (Joe Grand)", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "", "", "", "", "", "" }, { "62992392ea651a16aa724a92e4596ed6", "Eric Mooney", "", "Invaders by Erik Mooney (Beta) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "28", "", "", "" }, { "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 'Willy' 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 (1982) (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", "6230, 6250", "Super Kung-Fu (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6468d744be9984f2a39ca9285443a2b2", "Atari", "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]", "", "", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "6522717cfd75d1dba252cbde76992090", "Home Vision - Gem International Corp.", "VCS83102", "War 2000 (1983) (Home Vision) (PAL)", "AKA Astrowar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6538e454b0498ad2befe1ef0f87815c0", "Joe Grand", "", "SCSIcide (v1.2) (2001) (Joe Grand)", "", "New Release", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "" }, { "65917ae29a8c9785bb1f2acb0d6aafd0", "", "", "Junkosoft One Year Demo (1999) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6596b3737ae4b976e4aadb68d836c5c7", "Digivision", "", "Defender (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "659a20019de4a23c748ec2292ea5f221", "Retroactive", "", "Qb (V2.05) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "65b106eba3e45f3dab72ea907f39f8b4", "Sparrow - HomeComputer Software Co., Dan Schafer, Glenn Stohel, Jon Tedesco", "GCG 1001T", "Music Machine, The (1983) (Sparrow)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "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, Joe Hellesen", "4L1720, 4L1721, 4L2276", "Wizard of Wor (1982) (CBS Electronics) (PAL)", "Uses the Joystick Controllers (swapped)", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "YES", "" }, { "6651e2791d38edc02c5a5fd7b47a1627", "Parker Brothers, Wilfredo 'Willy' Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (04-05-1984) (Parker Bros) (Prototype) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "665b8f8ead0eef220ed53886fbd61ec9", "Telesys, Don 'Donyo' 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, Stephan R. Keith, 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", "Arcadia Corporation, Stephen Harland Landrum", "AR-4400", "Dragonstomper (2 of 3) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "66fcf7643d554f5e15d4d06bab59fe70", "Coleco, 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", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "24", "", "YES", "" }, { "679d30c7886b283cbe1db4e7dbe5f2a6", "Colin Hughes", "", "Puzzle (Colin Hughes) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "679e910b27406c6a2072f9569ae35fc8", "Data Age", "DA1002", "Warplock (1982) (Data Age)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01", "", "", "", "YES", "" }, { "67bd3d4dc5ac6a42a99950b4245bdc81", "Retroactive", "", "Qb (2.11) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "67c05ae94bf8b83a666c3ae2c4bc14de", "Atari", "CX26163P", "NFL Football (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "68489e60268a5e6e052bad9c62681635", "Bit Corporation", "PG201", "Sea Monster (1982) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "36", "256", "", "" }, { "68597264c8e57ada93be3a5be4565096", "Data Age", "DA1005", "Bugs (1982) (Data Age)", "Uses the Paddle Controllers", "Uncommon", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "24", "230", "", "" }, { "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", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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 Phantom-Panzer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6b4eb5b3df80995b8d9117cb7e9aeb3c", "Gameworld", "133-006", "Journey Escape (1983) (Gameworld) (PAL)", "AKA Rock 'n' Roll Escape", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6b683be69f92958abe0e2a9945157ad5", "U.S. Games Corporation, Paul Allen Newell, Steve Sidley, Tom Sloper", "VC2007", "Entombed (1982) (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", "", "24", "", "", "" }, { "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", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6cf054cd23a02e09298d2c6f787eb21d", "Parker Brothers, Wilfredo 'Willy' 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 (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6d8a04ee15951480cb7c466e5951eee0", "Zirok", "", "Kanguru (1983) (Zirok)", "AKA Kangaroo", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6d9afd70e9369c2a6bff96c4964413b7", "", "", "Time Warp (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6dda84fb8e442ecf34241ac0d1d91d69", "Atari - GCC, Douglas B. Macrae", "CX2677", "Dig Dug (1983) (Atari)", "", "", "", "F6SC", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6de924c2297c8733524952448d54a33c", "CCE", "C-1006", "Moon Patrol (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6dfad2dd2c7c16ac0fa257b6ce0be2f0", "Parker Brothers, Larry Gelberg, Gary Goltz", "PB5065", "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6e179eee3d4631a7434d40cf7aeea6e8", "Wizard Video Games, 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "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", "", "30", "", "", "" }, { "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, Garry Kitchen - Vidtec", "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", "", "", "", "", "" }, { "6ffc95108e5add6f9b8abcaf330be835", "Charles Morgan", "", "TP Bug (Charles Morgan) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "700a786471c8a91ec09e2f8e47f14a04", "Activision", "", "Unknown Activision Game #2 (1983) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "37", "", "", "" }, { "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 (1982) (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, Bruce Pedersen - INTV", "MT5663", "Lock 'n' Chase (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "714e13c08508ee9a7785ceac908ae831", "Home Vision - Gem International Corp.", "VCS83123", "Parachute (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "112-006", "Journey Escape (1982) (Data Age)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "230", "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", "", "", "" }, { "72a46e0c21f825518b7261c267ab886e", "Xonox - K-Tel Software", "99005, 6220, 6250", "Robin Hood (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "222", "", "" }, { "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", "CX26163P", "Miniaturer Golf (32 in 1) (1988) (Atari) (PAL)", "AKA Miniature Golf", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "736388d73198552d77d423962000006f", "Dactari", "", "Tennis (Dactari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "73a710e621d44e97039d640071908aef", "", "", "Barber Pole Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "73aa02458b413091ac940c0489301710", "Quelle", "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, Henry Will IV", "4L1767, 4L1768, 4L1769, 4L1770", "Smurf (1982) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "24", "", "YES", "" }, { "73e66e82ac22b305eb4d9578e866236e", "Jone Yuan Telephonic Enterprise Co", "", "Unknown Datatech Game (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "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", "", "", "Phantom Tank (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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "29", "", "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 and the Seven Dwarfs (02-09-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7511c34518a9a124ea773f5b0b5c9a48", "", "", "Donkey Kong (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "75169c08b56e4e6c36681e599c4d8cc5", "M Network, Hal Finney - INTV", "MT5666", "Astroblast (1982) (M Network)", "Can also use left joystick", "Uncommon", "", "", "", "", "", "", "PADDLES", "", "YES", "", "", "", "", "", "" }, { "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 (1983) (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]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "75ee371ccfc4f43e7d9b8f24e1266b55", "Atari, Greg Easter, Mimi Nyden", "CX26107", "Snow White and the Seven Dwarfs (11-09-1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7608abdfd9b26f4a0ecec18b232bea54", "Atari", "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", "Quelle", "311377", "Fox & Goat (Double-Game Package) (1983) (Quelle) (PAL)", "AKA Nuts", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "30", "", "YES", "" }, { "77057d9d14b99e465ea9e29783af0ae3", "Activision, David Crane", "AG-001", "Dragster (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "22", "", "", "" }, { "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", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "24", "", "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", "Arcadia Corporation, Stephen Harland Landrum", "AR-4400", "Dragonstomper (1 of 3) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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, 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", "", "", "", "", "", "", "", "" }, { "7996b8d07462a19259baa4c811c2b4b4", "", "", "Math Gran Prix (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "79ab4123a83dc11d468fb2108ea09e2e", "Activision, David Rolfe - Cheshire Engineering", "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 (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7a09299f473105ae1ef3ad6f9f2cd807", "Atari, Steve Wright", "CX2616P", "Pele's Soccer (1981) (Atari) (PAL)", "AKA Championship Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7a2af383014f5d810ad26d322823549d", "", "", "FlickerSort Demo (20-04-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7a5463545dfb2dcfdafa6074b2f2c15e", "20th Century Fox Video Games, 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", "", "", "", "", "", "", "", "" }, { "7ab210f448de518fa61a5924120ba872", "", "", "Fortress (20-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7ab2f190d4e59e8742e76a6e870b567e", "Apollo, Larry Martin", "AP-2008", "Guardian (1982) (Apollo)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01", "", "", "", "", "" }, { "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, Joseph Tung", "CX26152", "Super Baseball (1988) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "7af40c1485ce9f29b1a7b069a2eb04a7", "Amiga", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "32", "", "", "" }, { "7b43c32e3d4ff5932f39afcb4c551627", "Syncro, Dan Wolf", "", "Kamikaze Saucers (1983) (Syncro) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "38", "220", "", "" }, { "7b5207e68ee85b16998bea861987c690", "Atari, Carol Shaw", "CX26163P", "3-D Tic-Tac-Toe (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "62", "", "", "" }, { "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", "Arcadia Corporation, Stephen Harland 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, Ernie Runyon, Ed Salvo", "AP-2004", "Lost Luggage (1981) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7c4a499d343fca0cef2d59dd16af621a", "", "", "Poker Card Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7c757bb151269b2a626c907a22f5dae7", "TNT Games, 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7cd379da92c93679f3b6d2548617746a", "", "", "Demo Image Series #5 - Clown (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7cd900e9eccbb240fe9c37fa28f917b5", "Jone Yuan Telephonic Enterprise Co", "", "Bi! Bi! (Jone Yuan) (PAL)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "38", "", "", "" }, { "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", "133-008", "Frankenstein's Monster (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7d3cdde63b16fa637c4484e716839c94", "CCE", "", "Road Runner (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "20", "", "", "" }, { "7d483b702c44ee65cd2df22cbcc8b7ed", "Atari, Warren Robinett", "", "Elf Adventure (05-25-83) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7d5c3b7b908752b98e30690e2a3322c2", "Dactari - Milmar", "", "Freeway (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7d726fa494f706784bafeb1b50d87f23", "Coleco, 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "24", "", "YES", "" }, { "7dd9c5284422f729066ab22a284c8283", "CCE", "C-833", "Target Practice (1983) (CCE) [a]", "AKA Carnival", "", "", "", "", "", "", "", "", "", "", "", "", "26", "214", "", "" }, { "7dfd100bda9abb0f3744361bc7112681", "Telesys, Don 'Donyo' Ruffcorn", "1006", "Demolition Herby (1983) (Telesys) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "7e2fe40a788e56765fe56a3576019968", "Activision, 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", "CX26139P", "Crossbow (1987) (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 (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7e7c4c59d55494e66eef5e04ec1c6157", "Baroque Gaming (Brian Eno)", "", "Warring Worms (2002) (Baroque Gaming)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7e8aa18bc9502eb57daaf5e7c1e94da7", "CBS Electronics", "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, Betty Ryan Tylko, Douglas B. Macrae", "CX2694", "Pole Position (05-15-1983) (Atari) (Prototype)", "AKA RealSports Driving", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7f07cd2e89dda5a3a90d3ab064bfd1f6", "Videospielkassette - Ariola", "PGP234", "Boxen (Ariola) (PAL)", "AKA Boxing", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7f430c33044e0354815392b53a9a772d", "HES", "", "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "7fcd5fb59e88fc7b8473c641f44226c3", "CCE", "C-807", "Space Tunnel (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "215", "", "" }, { "7ff53f6922708119e7bf478d7d618c86", "Suntek", "SS-032", "Walker (Suntek) (PAL)", "AKA Clown Down Town", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7ffc2d80fd49a124808315306d19868e", "Ishido", "", "Domino (Ishido) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "801ba40f3290fc413e8c816c467c765c", "Hozer Video Games", "", "Gunfight 2600 - Westward Ho! (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "803393ed29a9e9346569dd1bf209907b", "Atari - GCC, Mark Ackerman, 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "46", "", "", "" }, { "80e52315919bd8a8b82a407ccd9bb13f", "", "", "Euchre (Jul 28) (2002) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "80e5400470ac788143e6db9bc8dd88cf", "Coleco, 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", "", "", "", "PAL60", "", "", "", "" }, { "8108162bc88b5a14adc3e031cf4175ad", "Quelle", "719.941 7", "Vom Himmel durch die Hoelle (1983) (Quelle) (PAL)", "AKA Parachute", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8108ad2679bd055afec0a35a1dca46a4", "", "", "Maze Craze (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "20", "230", "", "" }, { "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", "7062 A305", "Universal Chaos (1989) (Telegames)", "AKA Targ", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "81b3bf17cf01039d311b4cd738ae608e", "CBS Electronics, 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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, Douglas 'Dallas North' Neubauer", "11011", "M.A.S.H (1983) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8372eec01a08c60dbed063c5524cdfb1", "", "", "Cross Force (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8388d6fe59c38c0b3a6ab2c58420036a", "Atari, Frank Hausman, 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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "841b7bc1cad05f5408302308777d49dc", "Activision", "", "Unknown Activision Game #1 (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", "", "", "", "", "", "", "", "" }, { "84535afb9a69712ec0af4947329e08b8", "CCE", "C-868", "Bingo (1983) (CCE) (PAL)", "AKA Dice Puzzle", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "84df0704e6c777e1f9a16ec92ad80df0", "Gray Games & AtariAge", "", "E.T. Book Cart (PAL60)", "Charles F. Gray & Michael Rideout", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "15", "240", "YES", "55" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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 World End (Perry Rhodan-Serie)", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "YES", "" }, { "8556b42aa05f94bc29ff39c39b11bff4", "Atari, Craig Nelson - Sears", "CX2617 - 49-75183", "Backgammon (1979) (Atari)", "Uses the Paddle Controllers", "Extremely Rare", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "" }, { "85bbefb90e16bf386b304c1e9a1f6084", "Champ Games", "", "Conquest Of Mars (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" }, { "85e48d68c8d802e3ba9d494a47d6e016", "", "", "Ship Demo (V 15) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "85e564dae5687e431955056fbda10978", "Milton Bradley Company", "4362", "Survival Run (1983) (Milton Bradley)", "AKA Cosmic Commander", "", "", "", "", "", "", "", "", "", "", "", "", "29", "225", "YES", "" }, { "86128001e69ab049937f265911ce7e8a", "Apollo - Games by Apollo, Steve Stringfellow", "AP-2005", "Lochjaw (1981) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "862cf669cbced78f9ed31a5d375b2ebe", "", "", "Gunfight 2600 - Flicker acceptance (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8644352b806985efde499ae6fc7b0fec", "CCE", "C-801", "Mr. Postman (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8654d7f0fb351960016e06646f639b02", "Home Vision - Gem International Corp. - R.J.P.G.", "VCS83106", "Ski Hunt (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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 (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8786f4609a66fbea2cd9aa48ca7aa11c", "Goliath", "5", "Open Sesame (1983) (Goliath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "87b460df21b7bbcfc57b1c082c6794b0", "Dennis Debro", "", "Climber 5 (20-03-2003) (Dennis Debro)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "28", "", "", "" }, { "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 (1982) (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", "", "", "", "", "" }, { "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 Spider Kong", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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, 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, Steve 'Jessica' 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "44", "", "", "" }, { "89a65b83203980d5d4d60f52a584a5b8", "", "", "Marble Craze (PAL) (02-02-2003) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "89a68746eff7f266bbf08de2483abe55", "Atari, Jerome Domurat, Steve Woita", "CX2696", "Asterix (1983) (Atari)", "AKA Taz", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "89afff4a10807093c105740c73e9b544", "", "", "Pooyan (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "89eaba47a59cbfd26e74aad32f553cd7", "Apollo - Games by Apollo, Ed Salvo, Bryson Park", "AP-2001", "Spacechase (1981) (Apollo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8a159ee58b2f0a54805162984b0f07e5", "Atari - Sculptured Software, Inc., Steve Aguirre", "CX26162", "Fatal Run (1989) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8a183b6357987db5170c5cf9f4a113e5", "Atari, 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", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "20", "230", "YES", "" }, { "8a9d953ac3db52a313a90d6a9b139c76", "", "", "Hangman Invader Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8aad33da907bed78b76b87fceaa838c1", "Atari, Larry Kaplan", "CX26163P", "Air-Sea Battle (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "40", "256", "", "" }, { "8ac18076d01a6b63acf6e2cab4968940", "Atari, Dan Hitchens", "CX2685", "Gravitar (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8af58a9b90b25907da0251ec0facf3b8", "Jone Yuan Telephonic Enterprise Co", "", "Cosmic Swarm (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "8b04e9d132b8e30d447acaa6bd049c32", "Arcadia Corporation, Stephen Harland Landrum", "AR-4400", "Dragonstomper (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8b40a9ca1cfcd14822e2547eaa9df5c1", "Parker Brothers, 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, Dan Kitchen, Garry Kitchen", "4L1700, 4L1701, 4L1702, 4L1802, 4L2274", "Donkey Kong (1982) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8b7ca29a55432f886cee3d452fb00481", "Arcadia Corporation, Stephen Harland Landrum, Jon Leupp", "AR-4201", "Sword of Saros (1983) (Arcadia) (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", "", "", "", "", "", "", "", "", "", "", "", "32", "", "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 (CX-22 Trackball) (2002) (TJ) (PAL)", "Uses CX-22 Trackball Controller", "Homebrew", "", "", "", "", "", "", "TRACKBALL22", "", "", "", "", "", "", "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.", "VCS83137", "Teddy Apple (1983) (Home Vision) (PAL)", "AKA Open Sesame", "", "", "", "", "", "", "", "", "", "", "", "", "42", "", "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", "CX26139", "Crossbow (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8ce9126066f2ddd5173e9f1f9ce1494e", "Thomas Jentzsch", "", "Missile Command (CX-22 Trackball) (2002) (TJ)", "Uses CX-22 Trackball Controller", "Homebrew", "", "", "", "", "", "", "TRACKBALL22", "", "", "", "", "", "", "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, David Lubar", "CX26183", "Sentinel (1990) (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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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, 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 Dark Green) (1983) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "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", "Arcadia Corporation, Stephen Harland Landrum", "AR-4400", "Dragonstomper (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "91191666186117f5bf78b40623d79039", "Gray Games & AtariAge", "", "E.T. Book Cart (PAL)", "Charles F. Gray & Michael Rideout", "", "", "", "", "", "", "", "", "", "", "", "", "23", "280", "YES", "55" }, { "911d385ee0805ff5b8f96c5a63da7de5", "Hozer Video Games", "", "Jammed (V0.1) (Demo) (2001) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "91c2098e88a6b13f977af8c003e0bca5", "Atari - GCC", "CX2676", "Centipede (1982) (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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "YES", "" }, { "9245a84e9851565d565cb6c9fac5802b", "Bomb - Onbase", "CA282", "Great Escape (1983) (Bomb)", "AKA Asteroid Fire", "", "", "", "", "", "", "", "", "", "", "", "", "28", "", "", "" }, { "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 (1989) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "929e8a84ed50601d9af8c49b0425c7ea", "Bit Corporation", "PG205", "Dancing Plate (1982) (BitCorp) (PAL)", "AKA Dancing Plates, Tanzende Teller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "92a1a605b7ad56d863a56373a866761b", "U.S. Games Corporation, Dave Hampton", "VC2006", "Raft Rider (1982) (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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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 Spider Kong", "", "", "", "", "", "", "", "", "", "", "", "", "24", "220", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "32", "", "", "" }, { "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, Adam Clayton, John Howard Palevich", "CX26151, CX26151P", "Dark Chambers (1988) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9526e3db3bdfbc27989a9cbfd0ee34bf", "", "", "Atari Logo Demo 6 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "95351b46fa9c45471d852d28b9b4e00b", "Atari", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "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", "Atari", "CX26190", "BMX Air Master (1990) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "96eccc2277043508a6c481ea432d7dd9", "Thomas Jentzsch", "", "Missile Command (CX-80 Trackball) (2002) (TJ) (PAL)", "Uses CX-80 Trackball Controller", "Homebrew", "", "", "", "", "", "", "TRACKBALL80", "", "", "", "", "", "", "YES", "" }, { "96f806fc62005205d851e758d050dfca", "", "", "Push (V0.05) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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 'Willy' Aguilar, Michael Becker, Dennis Koble", "720113-1A, 03206", "Solar Storm (1983) (Imagic)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "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", "CX26168", "Off the Wall (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "98fa3ad778a668a79449350de4b3b95b", "", "", "Thrust (V1.1) (2000) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9905f9f4706223dadee84f6867ede8e3", "HES", "", "Challenge (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "CX26177", "Ikari Warriors (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9a25b3cfe2bbb847b66a97282200cca2", "Atari, Brad Stewart - Sears", "CX2622 - 6-99813, 49-75107", "Breakout (1978) (Atari) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01", "", "", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "30", "218", "", "" }, { "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, David Rolfe - INTV", "MT5665", "Super Challenge Baseball (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9d4bc7c6fe9a7c8c4aa24a237c340adb", "Dennis Debro", "", "Climber 5 (16-04-2003) (Dennis Debro)", "For Philly Classic 4", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "28", "", "", "" }, { "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, 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", "", "", "", "", "", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "" }, { "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 (1982) (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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9fc2d1627dcdd8925f4c042e38eb0bc9", "Atari - GCC, Mike Feinstein, John Allred", "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, 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 (1989) (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, 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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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 (1982) (American Videogame)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a1f9159121142d42e63e6fb807d337aa", "Quelle", "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", "719.383 2 - 649635, 781393, 781784", "Motocross (1983) (Quelle) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a20d931a8fddcd6f6116ed21ff5c4832", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2003", "Racquetball (1981) (Apollo) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "a2170318a8ef4b50a1b1d38567c220d6", "Amiga", "3125", "Surf's Up (1983) (Amiga) (Prototype) [a1]", "Uses the Amiga Joyboard", "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", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "a2eb84cfeed55acd7fece7fefdc83fbb", "", "", "Kool Aid Man (Fixed) (15-11-2002) (CT)", "HMOVE handling fixed in this version", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a2f296ea2d6d4b59979bac5dfbf4edf0", "", "", "Warring Worms (28-01-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a302b922a8dbec47743f28b7f91d4cd8", "Arcadia Corporation, Stephen Harland Landrum", "AR-4400", "Dragonstomper (Preview) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "29", "", "", "" }, { "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 (1982) (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", "", "", "", "", "", "", "", "", "", "", "", "", "52", "", "", "" }, { "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, 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, Larry Kaplan", "CX2643", "Codebreaker (1978) (Atari) (PAL)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "57", "", "", "" }, { "a499d720e7ee35c62424de882a3351b6", "Sega, Phat Ho - Bally Midway - Beck-Tech", "009-01", "Up 'n Down (1984) (Sega)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "30", "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", "6210, 7210, 06003. 99001", "Spike's Peak (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "217", "", "" }, { "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, Betty Ryan Tylko, Douglas B. Macrae", "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, Sylvia Day, Henry Will IV - Teldec", "USC2001", "Gopher (1983) (Carrere Video) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a5855d73d304d83ef07dde03e379619f", "Atari, David Crane", "", "Boggle (08-07-1978) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "27", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "a74689a08746a667a299b0507e1e6dd9", "Arcadia Corporation, Stephen Harland Landrum", "AR-4105", "Official Frogger, The (1983) (Arcadia) (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", "", "", "", "", "", "", "", "", "", "", "", "24", "", "YES", "" }, { "a7b584937911d60c120677fe0d47f36f", "M Network, 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", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "27", "", "", "" }, { "a875f0a919129b4f1b5103ddd200d2fe", "Atari, Dan Hitchens", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "29", "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", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "38", "", "", "" }, { "a995b6cbdb1f0433abc74050808590e6", "Imagic, Rob Fulop, Bob Smith", "720106-1A, IA3600", "Riddle of the Sphinx (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a9cb638cd2cb2e8e0643d7a67db4281c", "M Network, Larry Zwick - INTV", "MT5861", "Air Raiders (1982) (M Network)", "AKA Air Battle", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "aab840db22075aa0f6a6b83a597f8890", "Home Vision - Gem International Corp. - R.J.P.G.", "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", "", "30", "", "", "" }, { "aafc79ffc32c4c9b2d73c8ada7602cfe", "", "", "Planet Patrol (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ab10f2974dee73dab4579f0cab35fca6", "ITT Family Games", "", "Wilma Wanderer (1983) (ITT Family Games) (PAL)", "AKA Lilly Adventure", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "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, 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 (1989) (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-930004, 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 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", "495.463 2 - 746381", "Angriff der Luftflotten (1983) (Quelle) (PAL)", "AKA Paris Attack, M.A.D.", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "adfbd2e8a38f96e03751717f7422851d", "Champ Games", "", "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 'Willy' Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (12-23-1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ae465044dfba287d344ba468820995d7", "", "", "Spider Kong (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", "3125", "Surf's Up (1983) (Amiga) (Prototype)", "Uses the Amiga Joyboard", "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", "", "", "", "", "" }, { "afb3bc45c6a82739cc82582127cd96e6", "Atari, John Howard Palevich", "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, Christopher H. Omarzu - Children's Computer Workshop", "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 (1981) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "29", "", "YES", "" }, { "aff8cba0f2d2eb239953dd7116894a08", "Arcadia Corporation, Stephen Harland Landrum", "AR-4400", "Dragonstomper (3 of 3) (1982) (Arcadia) (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, 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", "", "", "", "", "" }, { "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", "CX26156", "Combat Two (1982) (Atari) (Prototype)", "", "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", "", "", "", "", "", "", "", "", "", "", "", "", "44", "256", "", "" }, { "b1486e12de717013376447ac6f7f3a80", "Quelle", "292.542 8", "Marspatrouille (1983) (Quelle) (PAL)", "AKA Gas Hog", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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 (1990) (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", "Puzzy - Bit Corporation", "PG203", "Phantom Tank (1982) (Puzzy) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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, Robert C. Polaro", "CX26155P", "Sprint Master (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b2f0d7217147160b2f481954cedf814b", "", "", "Marquee Drawer (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b3017e397f74efd53caf8fae0a38e3fe", "Retroactive", "", "Qb (2.12) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b311ab95e85bc0162308390728a7361d", "Parker Brothers", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "b37f0fe822b92ca8f5e330bf62d56ea9", "Xonox - K-Tel Software - Beck-Tech", "6210, 7210, 06003. 99001", "Spike's Peak (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b392964e8b1c9c2bed12246f228011b2", "", "", "Name This Game (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b4030c38a720dd84b84178b6ce1fc749", "M Network, Kevin Miller", "MT5687", "International Soccer (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b40dea357d41c5408546e4e4d5f27779", "Digivision", "", "Spider Fighter (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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 (1989) (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]", "", "", "", "", "", "", "", "", "", "", "", "", "", "36", "", "", "" }, { "b4e2fd27d3180f0f4eb1065afc0d7fc9", "Avalon Hill, Jean Baer, Bill 'Rebecca Ann' Heineman, William O. Sheppard", "5002002", "London Blitz (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b4f05e544834d0238a0c263491775edf", "Arcadia Corporation, Steve Hales, Stephen Harland Landrum", "AR-4102", "Suicide Mission (Preview) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b4f31ea8a6cc9f1fd4d5585a87c3b487", "Mystique - American Multiple Industries, Joel H. Martin", "", "Beat 'Em & Eat 'Em (1982) (Mystique) (PAL)", "Uses the Paddle Controller (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "b4f87ce75f7329c18301a2505fe59cd3", "Videospielkassett - Ariola", "PGP232", "Autorennen (Ariola) (PAL)", "AKA Grand Prix", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b5110f55ed99d5279f18266d001a8cd5", "Eckhard Stolberg", "", "Auto-mobile Demo (2001) (Eckhard Stolberg)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b56264f738b2eb2c8f7cf5a2a75e5fdc", "Atari - GCC, Betty Ryan Tylko, Douglas B. Macrae", "CX2694, CX2694P", "Pole Position (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b5657d4c1c732fbb6af150668464247f", "Arcadia Corporation, Stephen Harland Landrum", "6 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 (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "29", "", "", "" }, { "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", "3130", "Off Your Rocker (1983) (Amiga) (Prototype)", "Uses the Amiga Joyboard", "", "", "", "", "", "", "", "", "", "", "", "", "27", "", "", "" }, { "b64426e787f04ff23ee629182c168603", "Dynacom", "", "Plaque Attack (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b65d4a38d6047735824ee99684f3515e", "Dynacom", "", "MegaBoy (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "b676a9b7094e0345a76ef027091d916b", "Thomas Jentzsch", "", "Mission Survive (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "A", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b6812eaf87127f043e78f91f2028f9f4", "Simage", "", "Eli's Ladder (1982) (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! (1982) (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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "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, David Lubar", "11008", "Fantastic Voyage (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "28", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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", "112-007", "Bermuda Triangle (1982) (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", "", "", "NTSC", "", "", "YES", "" }, { "b9b4612358a0b2c1b4d66bb146767306", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "20", "230", "", "" }, { "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", "", "", "", "", "" }, { "b9f9c0fed0db08c34346317f3957a945", "SuperVision", "405, 427, 806, 808, 813, 816", "Chopper Command (SuperVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ba257438f8a78862a9e014d831143690", "U.S. Games Corporation, Henry Will IV", "VC2002", "Squeeze Box (1982) (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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "bc33c685e6ffced83abe7a43f30df7f9", "Dynacom", "", "Seaquest (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bc4cf38a4bee45752dc466c98ed7ad09", "Atari, Douglas Neubauer", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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, Carol Shaw", "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 (1989) (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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "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", "", "", "", "", "" }, { "bf976cf80bcf52c5f164c1d45f2b316b", "Atari, Tod Frye", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "" }, { "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 - Bally Midway - Beck-Tech", "010-01", "Tapper (1984) (Sega)", "", "", "", "", "", "", "", "", "", "", "", "", "", "24", "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, Sylvia Day, Henry Will IV", "VC2001", "Gopher (1982) (U.S. Games)", "AKA Gopher Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c16fbfdbfdf5590cc8179e4b0f5f5aeb", "", "", "Wall Break (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "c1f209d80f0624dada5866ce05dd3399", "Telegames", "", "Deadly Discs (1989) (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", "", "", "", "", "30", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "22", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "230", "", "" }, { "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, Paul Crowley", "PB5320", "Super Cobra (1982) (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", "", "Conquest Of Mars (NTSC)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c31a17942d162b80962cb1f7571cd1d5", "Home Vision - Gem International Corp.", "VCS83112", "Sky Alien (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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, 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", "", "", "", "", "", "", "", "", "", "", "", "25", "220", "YES", "" }, { "c41e7735f6701dd50e84ee71d3ed1d8f", "Dynacom", "", "Spider Fighter (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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", "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 (1982) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c529e63013698064149b9e0468afd941", "", "", "S.I.PLIX 2 (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "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", "", "28", "", "", "" }, { "c5387fc1aa71f11d2fa82459e189a5f0", "Bit Corporation", "PG202", "Space Tunnel (1982) (BitCorp) (PAL)", "AKA 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 (1989) (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 (1982) (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", "", "", "", "", "", "", "", "", "", "", "", "26", "", "", "" }, { "c6db733e0b108c2580a1d65211f06dbf", "Atari, Eric Manghise, Joseph Tung", "CX2640", "RealSports Baseball (07-09-1982) (Atari) (Prototype)", "AKA Foxbat", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "c738fc3f5aae1e8f86f7249f6c82ac81", "Atari, Brad Stewart - Sears", "CX2622 - 6-99813, 49-75107", "Breakout (1978) (Atari) (16K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01", "", "", "", "", "" }, { "c73ae5ba5a0a3f3ac77f0a9e14770e73", "Arcadia Corporation, Stephen Harland Landrum", "AR-4105", "Official Frogger, The (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "32", "", "", "" }, { "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, John Perkins", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "20", "", "", "" }, { "c77d3b47f2293e69419b92522c6f6647", "Panda", "101", "Tank Brigade (1983) (Panda)", "AKA Phantom Tank", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "c7900a7fe95a47eef3b325072ad2c232", "Larry Petit", "", "Super Congo Bongo (2003) (Larry Petit) (Hack)", "Hack of Bongo", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c7d5819b26b480a49eb26aeb63cc831e", "Bit Corporation", "PGP210", "Ice Hockey (4 Game in One Light Green) (1983) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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, 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! (1982) (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", "", "30", "", "", "" }, { "ca09fa7406b7d2aea10d969b6fc90195", "Activision, Matthew L. Hubbard, Bob Whitehead", "AX-024", "Dolphin (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ca4f8c5b4d6fb9d608bb96bc7ebd26c7", "M Network, Hal Finney, Glenn Hightower, Peter Kaminski - INTV", "MT4317", "Adventures of TRON (1982) (M Network)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ca50cc4b21b0155255e066fcd6396331", "Suntek", "SS-031", "UFO Patrol (Suntek) (PAL)", "AKA X'Mission", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ca53fc8fd8b3c4a7df89ac86b222eba0", "CCE", "C-812", "Pac Man (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "ca54de69f7cdf4d7996e86f347129892", "PlayAround - J.H.M.", "201", "Philly Flasher (1982) (PlayAround)", "Uses the Paddle Controllers, AKA Beat 'Em & Eat 'Em", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "ca7aaebd861a9ef47967d31c5a6c4555", "Atari", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "" }, { "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, Ray Miller, Todd Marshall", "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 (1981) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "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", "", "", "", "", "", "", "" }, { "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, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (03-30-1983) (Atari) (Prototype)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "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", "", "", "", "", "", "", "", "", "", "", "", "", "40", "", "", "" }, { "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", "Quelle", "746422", "Hot Wave (Double-Game Package) (1983) (Quelle) (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", "", "", "", "", "", "", "", "", "", "", "", "", "14", "", "", "" }, { "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-01", "Buck Rogers - Planet of Zoom (1983) (Sega) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "PAL", "", "", "YES", "" }, { "cd8fa2e9f6255ef3d3b9b5a4f24a54f7", "", "", "Daredevil (V2) (Stunt_Cycle_Rules!) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cd98be8a48ebf610c9609a688b9c57f2", "Arcadia Corporation, Steve Hales, Stephen Harland Landrum", "4 AR-4102", "Suicide Mission (1982) (Arcadia) (Prototype)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cd9fea12051e414a6dfe17052067da8e", "Paul Slocum", "", "Marble Craze Demo (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "24", "", "", "" }, { "ce17325834bf8b0a0d0d8de08478d436", "", "", "Boring Freeway (Hack)", "Hack of Freeway", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ce243747bf34a2de366f846b3f4ca772", "Home Vision - Gem International Corp.", "", "Jacky Jump (1983) (Home Vision) (PAL)", "AKA Bobby Is Going Home", "", "", "", "", "", "", "", "", "", "", "", "", "39", "256", "", "" }, { "ce4bbe11d682c15a490ae15a4a8716cf", "", "", "Okie Dokie (Older) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ce5cc62608be2cd3ed8abd844efb8919", "Atari, Robert C. Polaro", "CX2663", "Road Runner (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "20", "", "", "" }, { "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 (1989) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cea9f72036dc6f7af5eff52459066290", "Retroactive", "", "Qb (2.07) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cedbd67d1ff321c996051eec843f8716", "Ultravision", "1044", "Karate (1982) (Ultravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "25", "", "", "" }, { "cef01595000627ee50863d4290372c27", "", "", "Many Blue Bars and Text Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cef2287d5fd80216b2200fb2ef1adfa8", "Milton Bradley Company", "4363", "Spitfire Attack (1983) (Milton Bradley)", "AKA Flight Commander)", "", "", "", "", "", "", "", "", "", "", "", "", "28", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "01", "", "", "", "", "" }, { "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) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "30", "", "YES", "" }, { "d078674afdf24a4547b4b32890fdc614", "Jone Yuan Telephonic Enterprise Co", "", "Laser Blast (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d078d25873c5b99f78fa267245a2af02", "Sega, Steve Beck, Phat Ho - Beck-Tech", "006-01", "Congo Bongo (1983) (Sega) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "36", "", "", "" }, { "d08fccfbebaa531c4a4fa7359393a0a9", "Activision, David Crane", "", "Venetian Blinds Demo (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d090836f0a4ea8db9ac7abb7d6adf61e", "Hozer Video Games", "", "Yahtzee (Hozer Video Games)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "d09935802d6760ae58253685ff649268", "Telesys, Don 'Donyo' 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 (1989) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d0b26e908370683ad99bc6b52137a784", "Apollo - Games by Apollo, Ernie Runyon, Ed Salvo - RCA Video Jeux", "AP-2004", "Lost Luggage (1981) (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", "732.273 8 - 600273, 781644", "Lilly Adventure (1983) (Quelle) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d0e15a3ce322c5af60f07343594392af", "Amiga", "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]", "AKA Clown Down Town", "", "", "", "", "", "", "", "", "", "", "", "", "", "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, Paul Crowley", "931505", "Super Cobra (1982) (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", "VC2005", "Piece o' Cake (1982) (U.S. Games)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "38", "", "YES", "" }, { "d44d90e7c389165f5034b5844077777f", "Parker Brothers, Larry Gelberg, Gary Goltz", "PB5065", "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d45bf71871b196022829aa3b96bfcfd4", "Activision, Steve Cartwright", "AX-017, AX-017-04", "MegaMania (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d45ebf130ed9070ea8ebd56176e48a38", "Sega", "001-01", "Tac-Scan (1982) (Sega)", "Uses the Paddle Controllers (right only)", "", "", "", "", "", "", "YES", "PADDLES", "", "YES", "", "", "", "215", "YES", "" }, { "d47387658ed450db77c3f189b969cc00", "PlayAround - J.H.M.", "206", "Westward Ho (1982) (PlayAround) (PAL)", "AKA Custer's Revenge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d4806775693fcaaa24cf00fc00edcdf3", "Atari, Robert C. Polaro", "CX26140, CX26140P", "Desert Falcon (1987) (Atari) (PAL)", "AKA Nile Flyer, Sphinx", "", "", "", "", "", "", "", "", "", "", "", "PAL", "22", "", "", "" }, { "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 Harland Landrum", "AR-4101", "Communist Mutants from Space (Preview) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "32", "", "", "" }, { "d597d35c6022c590d6e75e865738558a", "", "", "Sprite Color Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d5aa7472e7f2cc17e893a1a36f8dadf0", "", "", "Overhead Adventure Demo 5 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d5c6b81212ad86fd9542a1fedaf57cae", "", "", "Sprite Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d5d2d44fb73785996ccc24ae3a0f5cef", "Robby", "", "Grand Prix (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "Game Select (208 in 1) (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", "Puzzy - Bit Corporation", "PG202", "Space Tunnel (1982) (Puzzy) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "28", "", "", "" }, { "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 (1981) (Apollo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "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 (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "da79aad11572c80a96e261e4ac6392d0", "Salu - Ubi Soft, Dennis M. Kiss", "460673", "Pick 'n' Pile (1990) (Salu) (PAL)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "38", "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, 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "" }, { "dbdaf82f4f0c415a94d1030271a9ef44", "CCE", "", "Kaboom! (CCE)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "01", "", "", "", "", "" }, { "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! (1982) (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, David Rolfe - INTV", "MT5664", "Frogs and Flies (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dcec46a98f45b193f07239611eb878c2", "", "", "Bars and Text Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dd08e18cfee87a0e7fc19a684b36e124", "Atari - GCC, Kevin Osborn", "CX2689, CX2689P", "Kangaroo (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dd0cbe5351551a538414fb9e37fc56e8", "Xonox - K-Tel Software, 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", "99005, 6220, 6250", "Robin Hood (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "dd7884b4f93cab423ac471aa1935e3df", "Atari, Brad Stewart - Sears", "CX2649, 49-75163", "Asteroids (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "dd8a2124d4eda200df715c698a6ea887", "Arcadia Corporation, Stephen Harland Landrum", "AR-4400", "Dragonstomper (3 of 3) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dd92d6ad50976f881d86b52d38616118", "SpkSoft", "", "River Raid (SpkSoft) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "10", "", "", "" }, { "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, 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, Mike Riedel", "EAK-043-04I", "Commando (1988) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "de24f700fd28d5b8381de13abd091db9", "CCE", "", "Plaque Attack (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "de29e46dbea003c3c09c892d668b9413", "CBS Electronics, Steve 'Jessica' Kitchen", "4L1717, 4L1718, 4L2277", "Carnival (1982) (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 Spider Kong", "", "", "", "", "", "", "", "", "", "", "", "", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "de7bca4e569ad9d3fd08ff1395e53d2d", "Thomas Jentzsch", "", "Thrust (V1.22) (2000) (TJ)", "Won't work with Stella < V1.2, supports Booster Grip", "New Release", "", "", "", "", "", "", "BOOSTERGRIP", "", "", "", "", "", "", "", "" }, { "de8443ff47283e7b274a7838cb071fb6", "Atari, Tod Frye", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "df2745d585238780101df812d00b49f4", "Bit Corporation", "PG202", "Space Tunnel (1982) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "215", "", "" }, { "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 - Sears", "CX2626 - 6-99829, 49-75116", "Miniature Golf (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "df6a28a89600affe36d94394ef597214", "Apollo - Games by Apollo, Dan Oliver", "AP-2002", "Space Cavern (1981) (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, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (06-03-1983) (Atari) (Prototype) (PAL)", "Uses Keypad Controllers", "Prototype", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "dfad86dd85a11c80259f3ddb6151f48f", "HES, 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", "", "", "", "", "", "", "", "", "", "", "", "37", "", "", "" }, { "dff33523ccd2fdc8912e84cab8e0d982", "", "", "Fu Kung! (V0.03) (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e01e00504e6d4b88fa743c0bbe8a96e5", "", "", "Qb (Special Edition, some bugfixes) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e020f612255e266a8a6a9795a4df0c0f", "Telegames", "7062 A305", "Universal Chaos (1989) (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", "4L1845, 4L1852, 4L1853, 4L1854", "Solar Fox (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e040df95a055b18ebdb094e904cb71b2", "", "", "Score Demo (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e04f1c1e4401d584d3f4343410a5bcc4", "Wizard Video Games, Robert Barber, Tim Martin", "007", "Halloween (1983) (Wizard Video Games) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e0b24c3f40a46cda52e29835ab7ad660", "Quelle", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "25", "225", "", "" }, { "e1143b72a30d4d3fee385eec38b4aa4d", "", "", "Word Zapper (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e12e32dee68201b6765fcd0ed54d6646", "Atari, Larry Kaplan", "CX2612, CX2612P", "Street Racer (1977) (Atari) (PAL)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "PADDLES", "", "YES", "10", "", "", "", "", "" }, { "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, 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", "", "", "", "", "" }, { "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, Karl T. Olinger", "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", "", "", "", "", "", "", "", "", "", "", "", "26", "", "", "" }, { "e25e173740f7ecc0e23025445c4591f3", "Greg Zumwalt", "", "Comitoid (Greg Zumwalt)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e275cbe7d4e11e62c3bfcfb38fca3d49", "M Network, Ken Smith - INTV", "MT5658", "Super Challenge Football (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "Arcadia Corporation, Stephen Harland Landrum", "AR-4101", "Communist Mutants from Space (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e2ca84a2bb63d1a210ebb659929747a9", "Telesys, Don 'Donyo' Ruffcorn", "1002", "Cosmic Creeps (1982) (Telesys) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "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-720", "Pitfall II (1983) (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", "", "", "", "", "", "", "", "", "", "", "", "44", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "25", "215", "", "" }, { "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", "TVS1001", "Nuts (1983) (TechnoVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e3ed4ba3361756970f076e46e9cad1d2", "", "", "Tennis (Unknown) (PAL) (4K) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e40a818dac4dd851f3b4aafbe2f1e0c1", "Atari, Bill Aspromonte, Dr. Lee Salk", "CX26137", "Peek-A-Boo (1984) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "e42b937c30c617241ca9e01e4510c3f6", "", "", "Pitfall! (No Walls Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e434c0e161dd3c3fb435eb6bad2e182c", "Atari - GCC, Mike Feinstein", "CX2681", "Battlezone (05-02-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e49ac0ec879a0d7820bc2598fc2cfcd4", "CCE", "", "Kaboom! (CCE) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "01", "", "", "", "", "" }, { "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 Harland Landrum", "AR-4102", "Suicide Mission (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "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, Joe Gaucher, Louis Marbel", "PB5110", "James Bond 007 (1983) (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, 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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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 (1989) (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", "" }, { "e5f84930aa468db33c0d0f7b26dd8293", "CCE", "C-826", "Grand Prix (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e5fcc62e1d73706be7b895e887e90f84", "", "", "Air-Sea Battle (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "40", "260", "", "" }, { "e600f5e98a20fafa47676198efe6834d", "Parker Brothers", "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", "", "", "", "", "", "", "", "" }, { "e62e60a3e6cb5563f72982fcd83de25a", "Jone Yuan Telephonic Enterprise Co", "", "World End (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "240", "", "" }, { "e63a87c231ee9a506f9599aa4ef7dfb9", "Tigervision, Warren Schwader", "7-003", "Threshold (1982) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "21", "214", "", "" }, { "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 'Willy' Aguilar, Michael Becker, Dennis Koble", "720113-2A, 13206", "Solar Storm (1983) (Imagic) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "" }, { "e72eb8d4410152bdcb69e7fba327b420", "Atari, Douglas Neubauer", "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 Open Sesame", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "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", "", "", "", "", "COMPUMATE", "COMPUMATE", "", "", "PAL", "", "", "YES", "" }, { "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 'Willy' Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "", "Star Wars - The Arcade Game (12-05-1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e8aa36e3d49e9bfa654c25dcc19c74e6", "Atari, Joe Decuir, Steve Mayer, Larry Wagner", "CX2601, CX2601P", "Combat (1977) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "36", "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 Phantom Tank", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "e908611d99890733be31733a979c62d8", "Atari, Dan Hitchens", "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, Robert C. Polaro", "CX26140, CX26140P", "Desert Falcon (05-27-1987) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ea38fcfc06ad87a0aed1a3d1588744e4", "Atari, Tod Frye", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "43", "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 (1990) (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, Joseph Tung", "CX2640", "RealSports Baseball (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "26", "", "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", "Arcadia Corporation, Steve Hales, Stephen Harland Landrum", "AR-4102", "Suicide Mission (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "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", "", "", "", "", "", "", "", "", "", "", "", "", "31", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "30", "220", "", "" }, { "ebf9038e927e6a0db3e0d170c59911e6", "", "", "Pac-2600 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ec26fdc87b1d35f1d60ea89cda4f4dd4", "", "", "Star Fire - Crash Scene (04-11-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ec3beb6d8b5689e867bafb5d5f507491", "U.S. Games Corporation, Henry Will IV - Vidtec", "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 (1981) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ece463abde92e8b89bcd867ec71751b8", "Puzzy - Bit Corporation", "PG205", "Dancing Plate (1982) (Puzzy) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ece908d77ab944f7bac84322b9973549", "", "", "Tom Boy (Unknown) (PAL60)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "24", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "38", "", "", "" }, { "ed2218b3075d15eaa34e3356025ccca3", "Atari, Richard Maurer", "CX2635, CX2635P", "Maze Craze (1980) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "PAL", "", "", "", "" }, { "ed5ccfc93ad4561075436ee42a15438a", "Atari", "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", "", "", "", "", "" }, { "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]", "", "", "", "", "", "", "", "", "", "", "", "", "", "10", "", "", "" }, { "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", "", "", "", "", "" }, { "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 #1 (10-29-1982) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ee6cbedf6c0aac90faa0a8dbc093ffbe", "CCE", "", "My Golf (CCE) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ee84bdc5dae268e227e407c7b5e6b6b7", "", "", "Marilyn Monroe Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ee9caee4eb958284fb10c277b14537f1", "Carrere Video, Garry Kitchen - Teldec", "USC1001", "Space Jockey (1983) (Carrere Video) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "59", "", "", "" }, { "eea0da9b987d661264cce69a7c13c3bd", "Coleco", "2454", "Zaxxon (1982) (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 (1990) (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 (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ef5c02c95a1e7ed24f24193935755cd3", "Thomas Jentzsch", "", "Jammed Demo (1999) (Hozer Video Games)", "Won't work with Stella < V1.2", "New Release", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "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 (1990) (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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "Lady Bug (PAL60)", "", "Homebrew", "", "", "", "A", "", "", "", "", "", "", "PAL60", "", "", "YES", "" }, { "f14d5e96ec3380aef57a4b70132c6677", "Goliath", "6", "Spider Kong (1983) (Goliath) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f1554569321dc933c87981cf5c239c43", "Atari, Glenn Axworthy", "CX26129", "Midnight Magic (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "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", "" }, { "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, Christopher H. Omarzu - Children's Computer Workshop", "CX26104", "Big Bird's Egg Catch (1983) (Atari) (PAL)", "Uses Kids/Keypad Controllers", "Rare", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "f2d40c70cf3e1d03bc112796315888d9", "Atari, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (1983) (Atari) (PAL)", "", "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", "", "", "", "", "", "", "", "", "", "", "", "", "31", "", "", "" }, { "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", "", "", "", "", "" }, { "f367e58667a30e7482175809e3cec4d4", "ZiMAG - Emag - Vidco", "708-111 - GN-040", "Cosmic Corridor (1983) (ZiMAG)", "AKA Space Tunnel", "", "", "", "", "", "", "", "", "", "", "", "", "", "220", "", "" }, { "f38358cd8f5ecfedffd5aca1aa939f18", "Universal Gamex Corporation, Alan Roberts", "1005", "X-Man (1983) (Universal) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "f39e4bc99845edd8621b0f3c7b8c4fd9", "AtariAge", "", "Toyshop Trouble (AtariAge)", "F8 Emulator Release", "", "", "", "", "", "", "", "", "PADDLES", "", "", "", "33", "", "", "" }, { "f3c431930e035a457fe370ed4d230659", "", "", "Crackpots (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f3cd0f886201d1376f3abab2df53b1b9", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f3dfae774f3bd005a026e29894db40d3", "Quelle", "649635", "See Saw (Double-Game Package) (1983) (Quelle) (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, 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", "", "", "", "", "", "", "YES", "" }, { "f48735115ec302ba8bb2d2f3a442e814", "", "", "Dancing Plate (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 'Willy' 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f4dabd5bcc603e8464a478208037d423", "Coleco, 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", "Arcadia Corporation, Stephen Harland Landrum", "AR-4105", "Official Frogger, The (Preview) (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "32", "", "", "" }, { "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)", "AKA Open Sesame", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f6a9ea814d15b85bffe980c927df606b", "", "", "Missile Command (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f6b5ebb65cbb2981af4d546c470629d7", "Coleco, 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", "", "", "", "", "", "", "", "", "", "", "", "26", "", "", "" }, { "f714a223954c28eccf459295517dcae6", "", "", "Big - Move This Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f71694bd8e89d5a28daa73bf856635df", "Gray Games & AtariAge", "", "E.T. Book Cart (NTSC)", "Charles F. Gray & Michael Rideout", "", "", "", "", "", "", "", "", "", "", "", "", "15", "240", "YES", "55" }, { "f724d3dd2471ed4cf5f191dbb724b69f", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2659", "Raiders of the Lost Ark (1982) (Atari)", "Console ports are swapped", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "f736864442164b29235e8872013180cd", "Telegames", "6057 A227", "Quest for Quintana Roo (1989) (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", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "33", "217", "", "" }, { "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", "", "01", "", "", "", "", "" }, { "f802fa61011dd9eb6f80b271bac479d0", "Suntek", "SS-023", "Mole Hunter (Suntek) (PAL)", "AKA Topy", "", "", "", "", "", "", "", "", "", "", "", "", "60", "", "", "" }, { "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f844f4c6f3baaaf5322657442d6f29eb", "Atari, 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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f8648d0c6ad1266434f6c485ff69ec40", "CCE", "", "Oink! (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f8811d45a9935cca90c62f924712f8e6", "Jone Yuan Telephonic Enterprise Co", "", "Chopper Command (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f8bfd99163d2c4ec688357786e6fba28", "", "", "Eckhard Stolberg's Scrolling Text Demo 2 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f8c1c4a41303bd40b0d6c81bfaf8573b", "HES", "", "2 Pak Special - Dungeon Master, Creature Strike (1992) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f8ff34b53d86f55bd52d7a520af6d1dc", "", "", "Big Dig (04-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "", "", "", "", "" }, { "f93d7fee92717e161e6763a88a293ffa", "20th Century Fox Video Games - Lazer Micro Systems - Dunhill Electronic Media Corp., 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", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "f9655ed51462ecfc690c7b97cec649f9", "Andrew Wallace", "", "Laseresal 2002 (PAL) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f965cc981cbb0822f955641f8d84e774", "Answer Software Corporation - TY Associates", "ASC2001", "Confrontation (1983) (Answer) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "30", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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", "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", "", "", "", "", "" }, { "fa0570561aa80896f0ead05c46351389", "Tigervision", "7-008", "Miner 2049er (1982) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "31", "", "", "" }, { "fa1b060fd8e0bca0c2a097dcffce93d3", "Atari, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (1983) (Atari)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "fa2be8125c3c60ab83e1c0fe56922fcb", "DSD-Camelot - Johnson & Johnson, Michael Doherty, Clyde Hager", "", "Tooth Protectors (1983) (DSD-Camelot)", "", "", "", "", "", "", "", "", "", "", "", "", "", "26", "", "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", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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 (1983) (Atari) (PAL)", "AKA Taz", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "faed2ef6b44894f8c83f2b50891c35c6", "CCE", "", "Super Baseball (CCE)", "AKA RealSports Baseball", "", "", "", "", "", "", "", "", "", "", "", "", "26", "", "", "" }, { "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, Jeff Ronne, Brett Stutz - INTV", "MT5662", "TRON - Deadly Discs (1982) (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", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "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", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "fb91da78455d9b1606913fbf8c859772", "", "", "Split Screen (Ballblazer) Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fb91dfc36cddaa54b09924ae8fd96199", "Parker Brothers, Mark Lesser", "PB5590", "Frogger II (1984) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "fbac6476e7b2b20d246202af81662c88", "Arcadia Corporation, Stephen Harland Landrum", "AR-4400", "Dragonstomper (Preview) (1982) (Arcadia) (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", "CX2681, CX2681P", "Battlezone (1983) (Atari) (PAL)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fbfebee9c14694719e3eda4854dc42ee", "Jake Patterson", "", "Baubles 3 (Jake Patterson) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fc2104dd2dadf9a6176c1c1c8f87ced9", "Coleco, 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", "" }, { "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, Mike Feinstein, John Allred", "CX2688", "Jungle Hunt (02-03-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fd4f5536fd80f35c64d365df85873418", "Atari, Robert C. Polaro", "CX26140", "Desert Falcon (1987) (Atari)", "AKA Nile Flyer, Sphinx", "", "", "", "", "", "", "", "", "", "", "", "", "22", "", "", "" }, { "fd6e507b5df68beeeddeaf696b6828fa", "", "", "Boxing (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fd7464edaa8cc264b97ba0d13e7f0678", "HES", "771-333", "2 Pak Special - Challenge, Surfing (1990) (HES) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fd78f186bdff83fbad7f97cb583812fe", "Amiga", "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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "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, Randy Bowker", "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, David Rolfe - Cheshire Engineering", "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", "", "", "", "", "", "", "YES", "" }, { "feedcc20bc3ca34851cd5d9e38aa2ca6", "Atari, David Crane - Sears", "CX2607 - 6-99828, 49-75115", "Canyon Bomber (1979) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "10", "", "42", "", "", "" }, { "ff3bd0c684f7144aeaa18758d8281a78", "Atari, Bob Whitehead", "CX2651", "Blackjack (1977) (Atari) (PAL)", "Uses the Paddle Controllers", "Rare", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "48", "", "", "" }, { "ff5a9e340d96df6f5a5b6eb038e923bd", "", "", "Space Shuttle (1983) (Activision) [t1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ff7627207e8aa03730c35c735a82c26c", "Atari, Bob Whitehead", "CX26163P", "Blackjack (32 in 1) (1988) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "63", "", "", "" }, { "ff86fc8ffa717bb095e8471638c1c31c", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Bop a Buggy (1 of 3) (1983) (Arcadia) (PAL)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01", "", "", "", "", "" }, { "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]", "", "", "", "", "", "", "", "", "", "", "", "", "", "28", "", "", "" } }; #endif stella-3.9.3/src/emucore/Cart4A50.cxx0000644000175000001440000003525712266336753016625 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart4A50.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "M6532.hxx" #include "TIA.hxx" #include "Cart4A50.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge4A50::Cartridge4A50(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size) { // 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, 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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge4A50::~Cartridge4A50() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4A50::reset() { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 32768; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 32768); mySliceLow = mySliceMiddle = mySliceHigh = 0; myIsRomLow = myIsRomMiddle = myIsRomHigh = true; myLastData = 0xff; myLastAddress = 0xffff; myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4A50::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mask) == 0); // Map all of the accesses to call peek and poke (We don't yet indicate RAM areas) System::PageAccess access(0, 0, 0, this, System::PA_READ); for(uInt32 i = 0x1000; i < 0x2000; i += (1 << shift)) mySystem->setPageAccess(i >> shift, 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().install(system, *this); mySystem->m6532().install(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) { 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::bank(uInt16) { // Doesn't support bankswitching in the normal sense return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge4A50::bank() const { // Doesn't support bankswitching in the normal sense return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge4A50::bankCount() const { // Doesn't support bankswitching in the normal sense // There is one 'virtual' bank that can change in many different ways return 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(int& 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-3.9.3/src/emucore/CartSB.hxx0000644000175000001440000001067712266336753016524 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartSB.hxx,v 1.0 2007/10/11 //============================================================================ #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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeSB(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // The 128-256K ROM image and size of the cartridge uInt8* myImage; uInt32 mySize; // Indicates which bank is currently active uInt16 myCurrentBank; // Previous Device's page access System::PageAccess myHotSpotPageAccess[8]; }; #endif stella-3.9.3/src/emucore/TIASnd.cxx0000644000175000001440000002477712266336753016471 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TIASnd.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "System.hxx" #include "TIASnd.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TIASound::TIASound(Int32 outputFrequency) : myChannelMode(Hardware2Stereo), myOutputFrequency(outputFrequency), myOutputCounter(0), myVolumePercentage(100) { reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TIASound::~TIASound() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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"; default: return EmptyString; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASound::set(uInt16 address, uInt8 value) { int chan = ~address & 0x1; switch(address) { case 0x15: // AUDC0 case 0x16: // AUDC1 myAUDC[chan] = value & 0x0f; break; case 0x17: // AUDF0 case 0x18: // AUDF1 myAUDF[chan] = value & 0x1f; break; case 0x19: // AUDV0 case 0x1a: // 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 0x15: // AUDC0 return myAUDC[0]; case 0x16: // AUDC1 return myAUDC[1]; case 0x17: // AUDF0 return myAUDF[0]; case 0x18: // AUDF1 return myAUDF[1]; case 0x19: // AUDV0 return myAUDV[0] >> AUDV_SHIFT; case 0x1a: // 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-3.9.3/src/emucore/Serializer.hxx0000644000175000001440000001340212266336753017504 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Serializer.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef SERIALIZER_HXX #define SERIALIZER_HXX #include #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), strings are written as characters prepended by the length of the string, boolean values are written using a special character pattern. All bytes, shorts and ints should be cast to their appropriate data type upon method return. @author Stephen Anthony @version $Id: Serializer.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 isValid() method must immediately be called to verify the stream was correctly initialized. */ Serializer(const string& filename, bool readonly = false); Serializer(void); /** Destructor */ virtual ~Serializer(void); public: /** Answers whether the serializer is currently initialized for reading and writing. */ bool isValid(void); /** Resets the read/write location to the beginning of the stream. */ void reset(void); /** 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(void); /** 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); /** 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(void); /** 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); /** 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(void); /** 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); /** Reads a string from the current input stream. @result The string which has been read from the stream. */ string getString(void); /** Reads a boolean value from the current input stream. @result The boolean value which has been read from the stream. */ bool getBool(void); /** 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 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. iostream* myStream; bool myUseFilestream; enum { TruePattern = 0xfe, FalsePattern = 0x01 }; }; #endif stella-3.9.3/src/emucore/Cart4KSC.cxx0000644000175000001440000001330412266336753016705 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart4KSC.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "Cart4KSC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge4KSC::Cartridge4KSC(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(4096u, size)); createCodeAccessBase(4096); // This cart contains 128 bytes extended RAM @ 0x1000 registerRamArea(0x1000, 128, 0x80, 0x00); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge4KSC::~Cartridge4KSC() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4KSC::reset() { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 128; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 128); myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4KSC::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert(((0x1080 & mask) == 0) && ((0x1100 & mask) == 0)); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt32 j = 0x1000; j < 0x1080; j += (1 << shift)) { access.directPokeBase = &myRAM[j & 0x007F]; access.codeAccessBase = &myCodeAccessBase[j & 0x007F]; mySystem->setPageAccess(j >> shift, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = 0; access.type = System::PA_READ; for(uInt32 k = 0x1080; k < 0x1100; k += (1 << shift)) { access.directPeekBase = &myRAM[k & 0x007F]; access.codeAccessBase = &myCodeAccessBase[0x80 + (k & 0x007F)]; mySystem->setPageAccess(k >> shift, access); } // Map ROM image into the system for(uInt32 address = 0x1100; address < 0x2000; address += (1 << shift)) { access.directPeekBase = &myImage[address & 0x0FFF]; access.codeAccessBase = &myCodeAccessBase[address & 0x0FFF]; mySystem->setPageAccess(address >> mySystem->pageShift(), access); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge4KSC::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; 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[address & 0x0FFF]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge4KSC::poke(uInt16 address, uInt8) { // 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 Cartridge4KSC::bank(uInt16 bank) { // Doesn't support bankswitching return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge4KSC::bank() const { return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge4KSC::bankCount() const { return 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(int& size) const { size = 4096; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge4KSC::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); 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; myCurrentBank = in.getShort(); in.getByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: Cartridge4KSC::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/CartCTY.hxx0000644000175000001440000002423712266336753016654 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartCTY.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CARTRIDGECHETIRY_HXX #define CARTRIDGECHETIRY_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartCTYWidget.hxx" #endif /** 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 @version $Id: CartCTY.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const OSystem& osystem); /** Destructor */ virtual ~CartridgeCTY(); public: /** Reset device to its power-on state */ void reset(); /** Notification method invoked by the system right before the system resets its cycle counter to zero. It may be necessary to override this method for devices that remember cycle counts. */ void systemCyclesReset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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); #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) { 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); /** 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); 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; // Indicates which bank is currently active uInt16 myCurrentBank; // 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 when the last update to music data fetchers occurred Int32 mySystemCycles; // Fractional DPC music OSC clocks unused during the last update double myFractionalClocks; }; #endif stella-3.9.3/src/emucore/FSNode.cxx0000644000175000001440000001411112266336753016502 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FSNode.cxx 2838 2014-01-17 23:34:03Z stephena $ // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #include #include "bspf.hxx" #include "SharedPtr.hxx" #include "FSNodeFactory.hxx" #include "FSNode.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNode::FilesystemNode() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNode::FilesystemNode(AbstractFSNode *realNode) : _realNode(realNode) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNode::FilesystemNode(const string& p) { AbstractFSNode* tmp = 0; // 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 = Common::SharedPtr(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 (AbstractFSList::iterator i = tmp.begin(); i != tmp.end(); ++i) fslist.push_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() != 0) : false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNode FilesystemNode::getParent() const { if (_realNode == 0) return *this; AbstractFSNode* node = _realNode->getParent(); return (node == 0) ? *this : FilesystemNode(node); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(uInt8*& 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 "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 = new uInt8[512 * 1024]; size = gzread(f, image, 512 * 1024); gzclose(f); if(size == 0) { delete[] image; image = 0; throw "Zero-byte file"; } return size; } else throw "ZLIB open/read error"; } stella-3.9.3/src/emucore/M6502.hxx0000644000175000001440000002774012266336753016116 0ustar stephenusers//============================================================================ // // 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-2014 by Bradford W. Mott, Stephen Anthony // and 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: M6502.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef M6502_HXX #define M6502_HXX class M6502; class Debugger; class CpuDebug; class Expression; class PackedBitArray; class Settings; #include "bspf.hxx" #include "System.hxx" #include "Array.hxx" #include "StringList.hxx" #include "Serializable.hxx" typedef Common::Array ExpressionList; /** 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 @version $Id: M6502.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class M6502 : public Serializable { // The 6502 and Cart debugger classes are friends who need special access friend class CartDebug; friend class CpuDebug; public: /** Create a new 6502 microprocessor with the specified cycle multiplier. The cycle multiplier is the number of system cycles per processor cycle. @param systemCyclesPerProcessorCycle The cycle multiplier */ M6502(uInt32 systemCyclesPerProcessorCycle, const Settings& settings); /** Destructor */ virtual ~M6502(); 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; } /** 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; } /** Answer true iff the last memory access was a read. @return true iff last access was a read */ bool lastAccessWasRead() const { return myLastAccessWasRead; } /** 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 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 total number of instructions executed so far. @return The number of executed instructions */ int totalInstructionCount() const { return myTotalInstructionCount; } /** 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; /** 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); /** Get a null terminated string which is the processor's name (i.e. "M6532") @return The name of the device */ string name() const { return "M6502"; } #ifdef DEBUGGER_SUPPORT public: /** Attach the specified debugger. @param debugger The debugger to attach to the microprocessor. */ void attach(Debugger& debugger); void setBreakPoints(PackedBitArray* bp); void setTraps(PackedBitArray* read, PackedBitArray* write); uInt32 addCondBreak(Expression* e, const string& name); void delCondBreak(uInt32 brk); void clearCondBreaks(); const StringList& getCondBreakNames() const; Int32 evalCondBreaks(); #endif 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); /** 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(); private: 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 /** 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; /// Indicates the number of system cycles per processor cycle const uInt32 mySystemCyclesPerProcessorCycle; /// Table of system cycles for each instruction uInt32 myInstructionSystemCycleTable[256]; /// Indicates if the last memory access was a read or not bool myLastAccessWasRead; /// The total number of instructions executed so far int myTotalInstructionCount; /// 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 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; #ifdef DEBUGGER_SUPPORT /// Pointer to the debugger for this processor or the null pointer Debugger* myDebugger; PackedBitArray* myBreakPoints; PackedBitArray* myReadTraps; PackedBitArray* myWriteTraps; // Did we just now hit a trap? bool myJustHitTrapFlag; struct HitTrapInfo { string message; int address; }; HitTrapInfo myHitTrapInfo; StringList myBreakCondNames; ExpressionList myBreakConds; #endif private: /** Table of instruction processor cycle times. In some cases additional cycles will be added during the execution of an instruction. */ static uInt32 ourInstructionCycleTable[256]; }; #endif stella-3.9.3/src/emucore/CartF6SC.cxx0000644000175000001440000001656312266336753016714 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF6SC.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartF6SC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF6SC::CartridgeF6SC(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(16384u, size)); createCodeAccessBase(16384); // This cart contains 128 bytes extended RAM @ 0x1000 registerRamArea(0x1000, 128, 0x80, 0x00); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF6SC::~CartridgeF6SC() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF6SC::reset() { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 128; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 128); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF6SC::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert(((0x1080 & mask) == 0) && ((0x1100 & mask) == 0)); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt32 j = 0x1000; j < 0x1080; j += (1 << shift)) { access.directPokeBase = &myRAM[j & 0x007F]; access.codeAccessBase = &myCodeAccessBase[j & 0x007F]; mySystem->setPageAccess(j >> shift, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = 0; access.type = System::PA_READ; for(uInt32 k = 0x1080; k < 0x1100; k += (1 << shift)) { access.directPeekBase = &myRAM[k & 0x007F]; access.codeAccessBase = &myCodeAccessBase[0x80 + (k & 0x007F)]; mySystem->setPageAccess(k >> shift, 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[(myCurrentBank << 12) + 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 myCurrentBank = bank; uInt16 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1FF6 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1100; address < (0x1FF6U & ~mask); address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF6SC::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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[(myCurrentBank << 12) + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeF6SC::getImage(int& size) const { size = 16384; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF6SC::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); 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; myCurrentBank = in.getShort(); in.getByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeF6SC::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/Thumbulator.cxx0000644000175000001440000013126512266336753017704 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Thumbulator.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ //============================================================================ // 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 //============================================================================ #ifdef THUMB_SUPPORT #include "bspf.hxx" #include "Base.hxx" #include "Thumbulator.hxx" using namespace Common; // 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 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Thumbulator::Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, bool traponfatal) : rom(rom_ptr), ram(ram_ptr) { trapFatalErrors(traponfatal); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Thumbulator::~Thumbulator() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Thumbulator::run( void ) { reset(); for(;;) { if (execute()) break; if (instructions > 500000) // way more than would otherwise be possible throw "instructions > 500000"; } #if defined(THUMB_DISS) || defined(THUMB_DBUG) dump_counters(); cout << statusMsg.str() << endl; #endif return statusMsg.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 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 statusMsg.str(); return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::dump_counters ( void ) { cout << endl << endl << "instructions " << instructions << endl << "fetches " << fetches << endl << "reads " << reads << endl << "writes " << writes << endl << "memcycles " << (fetches+reads+writes) << endl; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::dump_regs( void ) { for (int cnt = 1; cnt < 14; cnt++) { statusMsg << "R" << cnt << " = " << Base::HEX8 << reg_sys[cnt-1] << " "; if(cnt % 4 == 0) statusMsg << endl; } statusMsg << endl << "SP = " << Base::HEX8 << reg_svc[13] << " " << "LR = " << Base::HEX8 << reg_svc[14] << " " << "PC = " << Base::HEX8 << reg_sys[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; #ifdef __BIG_ENDIAN__ data=((rom[addr]>>8)|(rom[addr]<<8))&0xffff; #else data=rom[addr]; #endif DO_DBUG(statusMsg << "fetch16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl); return(data); case 0x40000000: //RAM addr &= RAMADDMASK; addr>>=1; #ifdef __BIG_ENDIAN__ data=((ram[addr]>>8)|(ram[addr]<<8))&0xffff; #else data=ram[addr]; #endif 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); fatalError("fetch32", addr, "abort"); } case 0x40000000: //RAM data =fetch16(addr+2); data<<=16; data|=fetch16(addr+0); 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"); else if((addr>0x40000028)&&(addr<0x40000c00)) fatalError("write16", addr, "to bankswitch code 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; #ifdef __BIG_ENDIAN__ ram[addr]=(((data&0xFFFF)>>8)|((data&0xffff)<<8))&0xffff; #else ram[addr]=data&0xFFFF; #endif 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"); DO_DBUG(statusMsg << "write32(" << Base::HEX8 << addr << "," << Base::HEX8 << data << ")" << endl); switch(addr&0xF0000000) { case 0xF0000000: //halt dump_counters(); throw "HALT";// exit(0); case 0xE0000000: //periph switch(addr) { case 0xE0000000: DO_DISS(statusMsg << "uart: [" << char(data&0xFF) << "]" << endl); break; } return; case 0xD0000000: //debug statusMsg << "[" << Base::HEX8 << read_register(14) << "][" << addr << "] " << data << endl; return; case 0x40000000: //RAM write16(addr+0,(data>> 0)&0xFFFF); write16(addr+2,(data>>16)&0xFFFF); return; } fatalError("write32", addr, data, "abort"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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; #ifdef __BIG_ENDIAN__ data=((rom[addr]>>8)|(rom[addr]<<8))&0xffff; #else data=rom[addr]; #endif DO_DBUG(statusMsg << "read16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl); return(data); case 0x40000000: //RAM addr&=RAMADDMASK; addr>>=1; #ifdef __BIG_ENDIAN__ data=((ram[addr]>>8)|(ram[addr]<<8))&0xffff; #else data=ram[addr]; #endif 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+2); data<<=16; data|=read16(addr+0); DO_DBUG(statusMsg << "read32(" << Base::HEX8 << addr << ")=" << Base::HEX8 << data << endl); return(data); } return fatalError("read32", addr, "abort"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Thumbulator::read_register ( uInt32 reg ) { reg&=0xF; uInt32 data; switch(cpsr&0x1F) { case MODE_SVC: switch(reg) // TODO (SA) - does this do anything other than default? { default: data=reg_sys[reg]; break; case 13: case 14: data=reg_svc[reg]; break; } DO_DBUG(statusMsg << "read_register(" << dec << reg << ")=" << Base::HEX8 << data << endl); return(data); } return fatalError("read_register", cpsr, "invalid cpsr mode"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Thumbulator::write_register ( uInt32 reg, uInt32 data ) { reg&=0xF; DO_DBUG(statusMsg << "write_register(" << dec << reg << "," << Base::HEX8 << data << ")" << endl); switch(cpsr&0x1F) { case MODE_SVC: switch(reg) // TODO (SA) - does this do anything other than default? { default: reg_sys[reg]=data; break; case 13: case 14: reg_svc[reg]=data; break; } return(data); } return fatalError("write_register", cpsr, "invalid cpsr mode"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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_sub_vflag ( uInt32 a, uInt32 b, uInt32 c ) { cpsr&=~CPSR_V; //if the sign bits are different if((a&0x80000000)^(b&0x80000000)) { //and result matches b if((b&0x80000000)==(c&0x80000000)) cpsr|=CPSR_V; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::do_add_vflag ( uInt32 a, uInt32 b, uInt32 c ) { cpsr&=~CPSR_V; //if sign bits are the same if((a&0x80000000)==(b&0x80000000)) { //and the result is different if((b&0x80000000)!=(c&0x80000000)) 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 ( void ) { uInt32 pc, sp, inst, ra,rb,rc, rm,rd,rn,rs, op; pc=read_register(15); 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); else do_cflag(ra,rb,0); do_add_vflag(ra,rb,rc); 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_add_vflag(ra,rb,rc); 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_add_vflag(ra,-rb,rc); 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_add_vflag(ra,rb,rc); 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; //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&(~3))+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|=(~0)<<(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|=(~0)<<(32-rb); } } else { if(rc&0x80000000) { do_cflag_bit(1); rc=(~0); } 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|=(~0)<<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|=(~0)<<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); halfadd=inst; return(0); } else if((inst&0x1800)==0x1800) //H=b11 { //branch to thumb rb=halfadd&((1<<11)-1); if(rb&1<<10) rb|=(~((1<<11)-1)); //sign extend rb<<=11; rb|=inst&((1<<11)-1); rb<<=1; rb+=pc; DO_DISS(statusMsg << "bl 0x" << Base::HEX8 << (rb-3) << endl); write_register(14,pc-2); 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 return(1); } } //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); 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) { write_register(15,rc); return(0); } else { //fprintf(stderr,"cannot branch to arm 0x%08X 0x%04X\n",pc,inst); // fxq: or maybe this one?? 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_add_vflag(ra,rb,rc); 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_sub_vflag(ra,rb,rc); 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_sub_vflag(ra,rb,rc); 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_sub_vflag(ra,rb,rc); #if 0 if(cpsr&CPSR_N) statusMsg << "N"; else statusMsg << "n"; if(cpsr&CPSR_Z) statusMsg << "Z"; else statusMsg << "z"; if(cpsr&CPSR_C) statusMsg << "C"; else statusMsg << "c"; if(cpsr&CPSR_V) statusMsg << "V"; else statusMsg << "v"; statusMsg << " -- 0x" << Base::HEX8 << ra << " 0x" << Base::HEX8 << rb << endl; #endif 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; } } 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&(~1)); 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&(~1)); 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&(~1)); if(rb&1) { rc>>=8; } else { } rc&=0xFF; if(rc&0x80) rc|=((~0)<<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|=((~0)<<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 unnaffected //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<<(32-rb))); 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==15) rc+=2; // fxq fix for MOV R15 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_sub_vflag(0,ra,rc); 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) { write32(rd,read_register(14)); } 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); do_cflag(ra,rb,0); do_sub_vflag(ra,rb,rc); 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&(~1)); if(rb&1) { ra&=0x00FF; ra|=rc<<8; } else { ra&=0xFF00; ra|=rc&0x00FF; } write16(rb&(~1),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&(~1)); if(rb&1) { ra&=0x00FF; ra|=rc<<8; } else { ra&=0xFF00; ra|=rc&0x00FF; } write16(rb&(~1),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)&7; rn=(inst>>3)&7; rb=(inst>>6)&7; 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_sub_vflag(ra,rb,rc); 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_sub_vflag(ra,rb,rc); 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_sub_vflag(ra,rb,rc); 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); 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|=(~0)<<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|=(~0)<<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 ( void ) { //memset(ram,0xFF,sizeof(ram)); cpsr=CPSR_T|CPSR_I|CPSR_F|MODE_SVC; reg_svc[13]=0x40001fb4; //sp reg_svc[14]=0x00000c00; //lr (duz this use odd addrs) reg_sys[15]=0x00000c0b; // entry point of 0xc09+2 // reg_sys[15]+=2; mamcr = 0; // fxq: don't care about below so much (maybe to guess timing???) instructions=0; fetches=0; reads=0; writes=0; statusMsg.str(""); return(0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Thumbulator::trapOnFatal = true; #endif stella-3.9.3/src/emucore/CartEF.cxx0000644000175000001440000001130512266336753016472 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartEF.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartEF.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeEF::CartridgeEF(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(65536u, size)); createCodeAccessBase(65536); // Remember startup bank myStartBank = 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeEF::~CartridgeEF() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEF::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEF::install(System& system) { mySystem = &system; // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mySystem->pageMask()) == 0); // 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[(myCurrentBank << 12) + 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 myCurrentBank = bank; uInt16 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1FE0 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1000; address < (0x1FE0U & ~mask); address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeEF::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeEF::bankCount() const { return 16; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEF::patch(uInt16 address, uInt8 value) { myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeEF::getImage(int& size) const { size = 65536; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEF::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); } catch(...) { cerr << "ERROR: CartridgeEF::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEF::load(Serializer& in) { try { if(in.getString() != name()) return false; myCurrentBank = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeEF::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/Driving.cxx0000644000175000001440000001304512266336753016773 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Driving.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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), 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; // Analog pins are not connected myAnalogPinValue[Five] = myAnalogPinValue[Nine] = maximumResistance; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Driving::~Driving() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 const 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-3.9.3/src/emucore/Console.cxx0000644000175000001440000012113512266336753016773 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Console.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #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 "Paddles.hxx" #include "Props.hxx" #include "PropsSet.hxx" #include "SaveKey.hxx" #include "Settings.hxx" #include "Sound.hxx" #include "Switches.hxx" #include "System.hxx" #include "TIA.hxx" #include "TrackBall.hxx" #include "FrameBuffer.hxx" #include "OSystem.hxx" #include "Menu.hxx" #include "CommandMenu.hxx" #include "Serializable.hxx" #include "Version.hxx" #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #endif #ifdef CHEATCODE_SUPPORT #include "CheatManager.hxx" #endif #include "Console.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props) : myOSystem(osystem), myEvent(osystem->eventHandler().event()), myProperties(props), myTIA(0), mySwitches(0), mySystem(0), myCart(cart), myCMHandler(0), myDisplayFormat(""), // Unknown TV format @ start myFramerate(0.0), // Unknown framerate @ start myCurrentFormat(0), // Unknown format @ start myUserPaletteDefined(false) { // Load user-defined palette for this ROM loadUserPalette(); // Create switches for the console mySwitches = new Switches(myEvent, myProperties); // Construct the system and components mySystem = new System(13, 6); // 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 // Note that the controllers must be added directly after the system // has been created, and before any other device is added // (particularly the M6532) myControllers[0] = new Joystick(Controller::Left, myEvent, *mySystem); myControllers[1] = new Joystick(Controller::Right, myEvent, *mySystem); M6502* m6502 = new M6502(1, myOSystem->settings()); myRiot = new M6532(*this, myOSystem->settings()); myTIA = new TIA(*this, myOSystem->sound(), myOSystem->settings()); mySystem->attach(m6502); mySystem->attach(myRiot); mySystem->attach(myTIA); mySystem->attach(myCart); // Auto-detect NTSC/PAL mode if it's requested string autodetected = ""; myDisplayFormat = myProperties.get(Display_Format); if(myDisplayFormat == "AUTO" || myOSystem->settings().getBool("rominfo")) { // 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); mySystem->reset(true); // autodetect in reset enabled for(int i = 0; i < 60; ++i) myTIA->update(); myDisplayFormat = myTIA->isPAL() ? "PAL" : "NTSC"; if(myProperties.get(Display_Format) == "AUTO") { autodetected = "*"; myCurrentFormat = 0; } // Don't forget to reset the SC progress bars again myOSystem->settings().setValue("fastscbios", fastscbios); } 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; else if(myDisplayFormat == "PAL") myCurrentFormat = 2; else if(myDisplayFormat == "SECAM") myCurrentFormat = 3; else if(myDisplayFormat == "NTSC50") myCurrentFormat = 4; else if(myDisplayFormat == "PAL60") myCurrentFormat = 5; else if(myDisplayFormat == "SECAM60") myCurrentFormat = 6; // 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); // Bumper Bash always requires all 4 directions // Other ROMs can use it if the setting is enabled bool joyallow4 = md5 == "aa1c41f86ec44c0a44eb64c332ce08af" || md5 == "1bf503c724001b09be79c515ecfcbd03" || 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); myConsoleInfo.Control0 = myControllers[0]->about(); myConsoleInfo.Control1 = myControllers[1]->about(); myConsoleInfo.BankSwitch = cart->about(); myCart->setRomName(myConsoleInfo.CartName); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Console::~Console() { delete mySystem; delete mySwitches; delete myCMHandler; delete myControllers[0]; delete myControllers[1]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(!(myControllers[0]->save(out) && myControllers[1]->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(!(myControllers[0]->load(in) && myControllers[1]->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->isPAL() ? "PAL" : "NTSC"; message = "Auto-detect mode: " + myDisplayFormat; saveformat = "AUTO"; break; case 1: saveformat = myDisplayFormat = "NTSC"; message = "NTSC mode"; break; case 2: saveformat = myDisplayFormat = "PAL"; message = "PAL mode"; break; case 3: saveformat = myDisplayFormat = "SECAM"; message = "SECAM mode"; break; case 4: saveformat = myDisplayFormat = "NTSC50"; message = "NTSC50 mode"; break; case 5: saveformat = myDisplayFormat = "PAL60"; message = "PAL60 mode"; break; case 6: saveformat = myDisplayFormat = "SECAM60"; 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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleColorLoss() { bool colorloss = !myOSystem->settings().getBool("colorloss"); myOSystem->settings().setValue("colorloss", colorloss); myTIA->enableColorLoss(colorloss); string message = string("PAL color-loss ") + (colorloss ? "enabled" : "disabled"); myOSystem->frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleColorLoss(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 uInt32* palettes[3][3] = { { &ourNTSCPalette[0], &ourPALPalette[0], &ourSECAMPalette[0] }, { &ourNTSCPaletteZ26[0], &ourPALPaletteZ26[0], &ourSECAMPaletteZ26[0] }, { 0, 0, 0 } }; if(myUserPaletteDefined) { palettes[2][0] = &ourUserNTSCPalette[0]; palettes[2][1] = &ourUserPALPalette[0]; palettes[2][2] = &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().setTIAPalette(palette); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::togglePhosphor() { const string& phosphor = myProperties.get(Display_Phosphor); int blend = atoi(myProperties.get(Display_PPBlend).c_str()); bool enable; if(phosphor == "YES") { myProperties.set(Display_Phosphor, "No"); enable = false; myOSystem->frameBuffer().showMessage("Phosphor effect disabled"); } else { myProperties.set(Display_Phosphor, "Yes"); enable = true; myOSystem->frameBuffer().showMessage("Phosphor effect enabled"); } myOSystem->frameBuffer().enablePhosphor(enable, blend); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::setProperties(const Properties& props) { myProperties = props; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBInitStatus Console::initializeVideo(bool full) { FBInitStatus fbstatus = kSuccess; if(full) { const string& title = string("Stella ") + STELLA_VERSION + ": \"" + myProperties.get(Cartridge_Name) + "\""; fbstatus = myOSystem->frameBuffer().initialize(title, myTIA->width() << 1, myTIA->height()); if(fbstatus != kSuccess) return fbstatus; myOSystem->frameBuffer().showFrameStats(myOSystem->settings().getBool("stats")); setColorLossPalette(); } bool enable = myProperties.get(Display_Phosphor) == "YES"; int blend = atoi(myProperties.get(Display_PPBlend).c_str()); myOSystem->frameBuffer().enablePhosphor(enable, blend); myOSystem->frameBuffer().setNTSC( (NTSCFilter::Preset)myOSystem->settings().getInt("tv_filter"), false); 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 ZPmem=0; ZPmem<0x100; ZPmem += rand() % 4) mySystem->poke(ZPmem, mySystem->peek(ZPmem) & (uInt8)rand() % 256); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::changeYStart(int direction) { uInt32 ystart = myTIA->ystart(); if(direction == +1) // increase YStart { if(ystart >= 64) { myOSystem->frameBuffer().showMessage("YStart at maximum"); return; } ystart++; } else if(direction == -1) // decrease YStart { if(ystart == 0) { myOSystem->frameBuffer().showMessage("YStart at minimum"); return; } ystart--; } else return; myTIA->setYStart(ystart); myTIA->frameReset(); myOSystem->frameBuffer().refresh(); ostringstream val; val << ystart; myOSystem->frameBuffer().showMessage("YStart " + val.str()); myProperties.set(Display_YStart, val.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::changeHeight(int direction) { uInt32 height = myTIA->height(); if(direction == +1) // increase Height { height++; if(height > 256 || height > myOSystem->desktopHeight()) { myOSystem->frameBuffer().showMessage("Height at maximum"); return; } } else if(direction == -1) // decrease Height { height--; if(height < 210) { myOSystem->frameBuffer().showMessage("Height at minimum"); return; } } 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() { // TODO - query these values directly from the TIA if value is 'AUTO' uInt32 ystart = atoi(myProperties.get(Display_YStart).c_str()); if(ystart > 64) ystart = 64; uInt32 height = atoi(myProperties.get(Display_Height).c_str()); if(height < 210) height = 210; else if(height > 256) height = 256; if(myDisplayFormat == "NTSC" || myDisplayFormat == "PAL60" || myDisplayFormat == "SECAM60") { // Assume we've got ~262 scanlines (NTSC-like format) myFramerate = 60.0; myConsoleInfo.InitialFrameRate = "60"; } else { // Assume we've got ~312 scanlines (PAL-like format) myFramerate = 50.0; myConsoleInfo.InitialFrameRate = "50"; // PAL ROMs normally need at least 250 lines height = BSPF_max(height, 250u); } // Make sure these values fit within the bounds of the desktop // If not, attempt to center vertically if(height > myOSystem->desktopHeight()) { ystart += height - myOSystem->desktopHeight(); ystart = BSPF_min(ystart, 64u); height = myOSystem->desktopHeight(); } myTIA->setYStart(ystart); myTIA->setHeight(height); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::setControllers(const string& rommd5) { delete myControllers[0]; delete myControllers[1]; // Setup the controllers based on properties const string& left = myProperties.get(Controller_Left); const string& right = myProperties.get(Controller_Right); // Check for CompuMate controllers; they are special in that a handler // creates them for us, and also that they must be used in both ports if(left == "COMPUMATE" || right == "COMPUMATE") { delete myCMHandler; myCMHandler = new CompuMate(*((CartridgeCM*)myCart), myEvent, *mySystem); myControllers[0] = myCMHandler->leftController(); myControllers[1] = myCMHandler->rightController(); return; } // Swap the ports if necessary int leftPort, rightPort; if(myProperties.get(Console_SwapPorts) == "NO") { leftPort = 0; rightPort = 1; } else { leftPort = 1; rightPort = 0; } // Also check if we should swap the paddles plugged into a jack bool swapPaddles = myProperties.get(Controller_SwapPaddles) == "YES"; // Construct left controller if(left == "BOOSTERGRIP") { myControllers[leftPort] = new BoosterGrip(Controller::Left, myEvent, *mySystem); } else if(left == "DRIVING") { myControllers[leftPort] = new Driving(Controller::Left, myEvent, *mySystem); } else if((left == "KEYBOARD") || (left == "KEYPAD")) { myControllers[leftPort] = new Keyboard(Controller::Left, myEvent, *mySystem); } else if(BSPF_startsWithIgnoreCase(left, "PADDLES")) { bool swapAxis = false, swapDir = false; if(left == "PADDLES_IAXIS") swapAxis = true; else if(left == "PADDLES_IDIR") swapDir = true; else if(left == "PADDLES_IAXDR") swapAxis = swapDir = true; myControllers[leftPort] = new Paddles(Controller::Left, myEvent, *mySystem, swapPaddles, swapAxis, swapDir); } else if(left == "TRACKBALL22") { myControllers[leftPort] = new TrackBall(Controller::Left, myEvent, *mySystem, Controller::TrackBall22); } else if(left == "TRACKBALL80") { myControllers[leftPort] = new TrackBall(Controller::Left, myEvent, *mySystem, Controller::TrackBall80); } else if(left == "AMIGAMOUSE") { myControllers[leftPort] = new TrackBall(Controller::Left, myEvent, *mySystem, Controller::AmigaMouse); } else if(left == "GENESIS") { myControllers[leftPort] = new Genesis(Controller::Left, myEvent, *mySystem); } else if(left == "MINDLINK") { myControllers[leftPort] = new MindLink(Controller::Left, myEvent, *mySystem); } else { myControllers[leftPort] = new Joystick(Controller::Left, myEvent, *mySystem); } // Construct right controller if(right == "BOOSTERGRIP") { myControllers[rightPort] = new BoosterGrip(Controller::Right, myEvent, *mySystem); } else if(right == "DRIVING") { myControllers[rightPort] = new Driving(Controller::Right, myEvent, *mySystem); } else if((right == "KEYBOARD") || (right == "KEYPAD")) { myControllers[rightPort] = new Keyboard(Controller::Right, myEvent, *mySystem); } else if(BSPF_startsWithIgnoreCase(right, "PADDLES")) { bool swapAxis = false, swapDir = false; if(right == "PADDLES_IAXIS") swapAxis = true; else if(right == "PADDLES_IDIR") swapDir = true; else if(right == "PADDLES_IAXDR") swapAxis = swapDir = true; myControllers[rightPort] = new Paddles(Controller::Right, myEvent, *mySystem, swapPaddles, swapAxis, swapDir); } else if(right == "TRACKBALL22") { myControllers[rightPort] = new TrackBall(Controller::Left, myEvent, *mySystem, Controller::TrackBall22); } else if(right == "TRACKBALL80") { myControllers[rightPort] = new TrackBall(Controller::Left, myEvent, *mySystem, Controller::TrackBall80); } else if(right == "AMIGAMOUSE") { myControllers[rightPort] = new TrackBall(Controller::Left, myEvent, *mySystem, Controller::AmigaMouse); } else if(right == "ATARIVOX") { const string& nvramfile = myOSystem->nvramDir() + "atarivox_eeprom.dat"; myControllers[rightPort] = new AtariVox(Controller::Right, myEvent, *mySystem, myOSystem->serialPort(), myOSystem->settings().getString("avoxport"), nvramfile); } else if(right == "SAVEKEY") { const string& nvramfile = myOSystem->nvramDir() + "savekey_eeprom.dat"; myControllers[rightPort] = new SaveKey(Controller::Right, myEvent, *mySystem, nvramfile); } else if(right == "GENESIS") { myControllers[rightPort] = new Genesis(Controller::Right, myEvent, *mySystem); } else if(right == "KIDVID") { myControllers[rightPort] = new KidVid(Controller::Right, myEvent, *mySystem, rommd5); } else if(right == "MINDLINK") { myControllers[rightPort] = new MindLink(Controller::Right, myEvent, *mySystem); } else { myControllers[rightPort] = new Joystick(Controller::Right, myEvent, *mySystem); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::loadUserPalette() { const string& palette = myOSystem->paletteFile(); ifstream in(palette.c_str(), 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, ios::end); streampos length = in.tellg(); in.seekg(0, ios::beg); if(length < 128 * 3 * 2 + 8 * 3) { in.close(); 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((char*)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((char*)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((char*)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++; } in.close(); myUserPaletteDefined = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::setColorLossPalette() { // 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], 0, 0, 0 }; if(myUserPaletteDefined) { palette[6] = &ourUserNTSCPalette[0]; palette[7] = &ourUserPALPalette[0]; palette[8] = &ourUserSECAMPalette[0]; } for(int i = 0; i < 9; ++i) { if(palette[i] == 0) 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) (((float)r * 0.2989) + ((float)g * 0.5870) + ((float)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::toggleHMOVE() const { if(myTIA->toggleHMOVEBlank()) myOSystem->frameBuffer().showMessage("HMOVE blanking enabled"); else myOSystem->frameBuffer().showMessage("HMOVE blanking disabled"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleFixedColors() const { if(myTIA->toggleFixedColors()) myOSystem->frameBuffer().showMessage("Fixed debug colors enabled"); else myOSystem->frameBuffer().showMessage("Fixed debug colors disabled"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::addDebugger() { #ifdef DEBUGGER_SUPPORT myOSystem->createDebugger(*this); mySystem->m6502().attach(myOSystem->debugger()); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::stateChanged(EventHandler::State state) { // For now, only the CompuMate cares about state changes if(myCMHandler) myCMHandler->enableKeyHandling(state == EventHandler::S_EMULATE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Console::Console(const Console& console) : myOSystem(console.myOSystem), myEvent(console.myEvent) { assert(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Console& Console::operator = (const Console&) { assert(false); return *this; } stella-3.9.3/src/emucore/M6502.ins0000644000175000001440000024627612266336753016107 0ustar stephenusers//============================================================================ // // 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-2014 by Bradford W. Mott, Stephen Anthony // and 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 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + X) > 0xFF) { intermediateAddress = (high | low) + 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 0x79: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = ((uInt16)peek(PC++, DISASM_CODE) << 8); intermediateAddress = high | (uInt8)(low + Y); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; 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 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; case 0x0b: case 0x2b: { operand = peek(PC++, DISASM_CODE); } { A &= operand; notZ = A; N = A & 0x80; C = N; } break; 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + X) > 0xFF) { intermediateAddress = (high | low) + X; 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } } { A &= operand; notZ = A; N = A & 0x80; } break; case 0x21: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } } { A &= operand; notZ = A; N = A & 0x80; } break; 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; 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; 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); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand); notZ = operand; N = operand & 0x80; } break; case 0x16: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand); 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); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand); 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_DATA); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand); notZ = operand; N = operand & 0x80; } break; 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 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; 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 0x00: { peek(PC++, DISASM_CODE); B = true; poke(0x0100 + SP--, PC >> 8); poke(0x0100 + SP--, PC & 0x00ff); poke(0x0100 + SP--, PS()); I = true; PC = peek(0xfffe, DISASM_NONE); PC |= ((uInt16)peek(0xffff, DISASM_NONE) << 8); } 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; case 0x18: { peek(PC, DISASM_NONE); } { C = false; } break; case 0xd8: { peek(PC, DISASM_NONE); } { D = false; } break; case 0x58: { peek(PC, DISASM_NONE); } { I = false; } break; case 0xb8: { peek(PC, DISASM_NONE); } { V = false; } break; 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + X) > 0xFF) { intermediateAddress = (high | low) + X; 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } } { uInt16 value = (uInt16)A - (uInt16)operand; notZ = value; N = value & 0x0080; C = !(value & 0x0100); } break; 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; 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; case 0xcf: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= ((uInt16)peek(PC++, DISASM_CODE) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = operand - 1; poke(operandAddress, value); 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_DATA); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = operand - 1; poke(operandAddress, value); 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_DATA); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = operand - 1; poke(operandAddress, value); 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); } { uInt8 value = operand - 1; poke(operandAddress, value); 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_DATA); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = operand - 1; poke(operandAddress, value); 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_DATA); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= ((uInt16)peek(pointer, DISASM_DATA) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = operand - 1; poke(operandAddress, value); 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_DATA); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = operand - 1; poke(operandAddress, value); uInt16 value2 = (uInt16)A - (uInt16)value; notZ = value2; N = value2 & 0x0080; C = !(value2 & 0x0100); } break; case 0xc6: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = operand - 1; poke(operandAddress, value); notZ = value; N = value & 0x80; } break; case 0xd6: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = operand - 1; poke(operandAddress, value); 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); } { uInt8 value = operand - 1; poke(operandAddress, value); 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_DATA); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = operand - 1; poke(operandAddress, value); notZ = value; N = value & 0x80; } break; case 0xca: { peek(PC, DISASM_NONE); } { X--; notZ = X; N = X & 0x80; } break; case 0x88: { peek(PC, DISASM_NONE); } { Y--; notZ = Y; N = Y & 0x80; } break; 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + X) > 0xFF) { intermediateAddress = (high | low) + X; 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } } { A ^= operand; notZ = A; N = A & 0x80; } break; case 0x41: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } } { A ^= operand; notZ = A; N = A & 0x80; } break; case 0xe6: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = operand + 1; poke(operandAddress, value); notZ = value; N = value & 0x80; } break; case 0xf6: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = operand + 1; poke(operandAddress, value); 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); } { uInt8 value = operand + 1; poke(operandAddress, value); 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_DATA); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = operand + 1; poke(operandAddress, value); notZ = value; N = value & 0x80; } break; case 0xe8: { peek(PC, DISASM_NONE); } { X++; notZ = X; N = X & 0x80; } break; case 0xc8: { peek(PC, DISASM_NONE); } { Y++; notZ = Y; N = Y & 0x80; } break; case 0xef: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= ((uInt16)peek(PC++, DISASM_CODE) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { operand = operand + 1; poke(operandAddress, operand); // 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_DATA); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { operand = operand + 1; poke(operandAddress, operand); // 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_DATA); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { operand = operand + 1; poke(operandAddress, operand); // 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); } { operand = operand + 1; poke(operandAddress, operand); // 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_DATA); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { operand = operand + 1; poke(operandAddress, operand); // 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_DATA); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= ((uInt16)peek(pointer, DISASM_DATA) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { operand = operand + 1; poke(operandAddress, operand); // 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_DATA); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { operand = operand + 1; poke(operandAddress, operand); // 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 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; 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); poke(0x0100 + SP--, PC & 0xff); PC = (low | ((uInt16)peek(PC, DISASM_CODE) << 8)); } break; case 0xbb: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = ((uInt16)peek(PC++, DISASM_CODE) << 8); intermediateAddress = high | (uInt8)(low + Y); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; 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_DATA); 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + X) > 0xFF) { intermediateAddress = (high | low) + X; 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + X) > 0xFF) { intermediateAddress = (high | low) + X; operand = peek(intermediateAddress, DISASM_DATA); } } SET_LAST_PEEK(myLastSrcAddressY, intermediateAddress) { Y = operand; notZ = Y; N = Y & 0x80; } break; ////////////////////////////////////////////////// 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); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand); notZ = operand; N = operand & 0x80; } break; case 0x56: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand); 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); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand); 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_DATA); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand); notZ = operand; N = operand & 0x80; } break; 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; 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + X) > 0xFF) { intermediateAddress = (high | low) + X; 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + X) > 0xFF) { intermediateAddress = (high | low) + X; 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) { A |= operand; notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// case 0x48: { peek(PC, DISASM_NONE); } // TODO - add tracking for this opcode { poke(0x0100 + SP--, A); } break; case 0x08: { peek(PC, DISASM_NONE); } // TODO - add tracking for this opcode { poke(0x0100 + SP--, PS()); } break; case 0x68: { peek(PC, DISASM_NONE); } // TODO - add tracking for this opcode { peek(0x0100 + SP++, DISASM_NONE); A = peek(0x0100 + SP, DISASM_NONE); notZ = A; N = A & 0x80; } break; case 0x28: { peek(PC, DISASM_NONE); } // TODO - add tracking for this opcode { peek(0x0100 + SP++, DISASM_NONE); PS(peek(0x0100 + SP, DISASM_NONE)); } break; case 0x2f: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= ((uInt16)peek(PC++, DISASM_CODE) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value); 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_DATA); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value); 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_DATA); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value); 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); } { uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value); A &= value; C = operand & 0x80; notZ = A; N = A & 0x80; } break; case 0x37: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value); A &= value; C = operand & 0x80; notZ = A; N = A & 0x80; } break; case 0x23: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_DATA); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= ((uInt16)peek(pointer, DISASM_DATA) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value); 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_DATA); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value); A &= value; C = operand & 0x80; notZ = A; N = A & 0x80; } break; 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); } { 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); notZ = operand; N = operand & 0x80; } break; case 0x36: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { 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); 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); } { 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); 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_DATA); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { 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); notZ = operand; N = operand & 0x80; } break; 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); } { 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); notZ = operand; N = operand & 0x80; } break; case 0x76: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { 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); 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); } { 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); 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_DATA); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { 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); notZ = operand; N = operand & 0x80; } break; case 0x6f: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= ((uInt16)peek(PC++, DISASM_CODE) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { 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); 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_DATA); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { 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); 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_DATA); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { 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); 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); } { 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); 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_DATA); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { 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); 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_DATA); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= ((uInt16)peek(pointer, DISASM_DATA) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { 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); 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_DATA); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { 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); 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 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; 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_CODE); } break; case 0x8f: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= ((uInt16)peek(PC++, DISASM_CODE) << 8); } { poke(operandAddress, A & X); } break; case 0x87: { operandAddress = peek(PC++, DISASM_CODE); } { poke(operandAddress, A & X); } break; case 0x97: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + Y) & 0xFF; } { poke(operandAddress, A & X); } break; case 0x83: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_DATA); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= ((uInt16)peek(pointer, DISASM_DATA) << 8); } { poke(operandAddress, A & X); } break; 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + X) > 0xFF) { intermediateAddress = (high | low) + 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 0xf9: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = ((uInt16)peek(PC++, DISASM_CODE) << 8); intermediateAddress = high | (uInt8)(low + Y); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; 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_DATA); 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; 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 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; case 0x38: { peek(PC, DISASM_NONE); } { C = true; } break; case 0xf8: { peek(PC, DISASM_NONE); } { D = true; } break; case 0x78: { peek(PC, DISASM_NONE); } { I = true; } break; case 0x9f: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = ((uInt16)peek(PC++, DISASM_CODE) << 8); peek(high | (uInt8)(low + Y), DISASM_DATA); operandAddress = (high | low) + Y; } { // NOTE: There are mixed reports on the actual operation // of this instruction! poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1)); } 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_DATA); operandAddress = (high | low) + Y; } { // NOTE: There are mixed reports on the actual operation // of this instruction! poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1)); } break; case 0x9b: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = ((uInt16)peek(PC++, DISASM_CODE) << 8); peek(high | (uInt8)(low + Y), DISASM_DATA); 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)); } break; case 0x9e: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = ((uInt16)peek(PC++, DISASM_CODE) << 8); peek(high | (uInt8)(low + Y), DISASM_DATA); operandAddress = (high | low) + Y; } { // NOTE: There are mixed reports on the actual operation // of this instruction! poke(operandAddress, X & (((operandAddress >> 8) & 0xff) + 1)); } break; case 0x9c: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = ((uInt16)peek(PC++, DISASM_CODE) << 8); peek(high | (uInt8)(low + X), DISASM_DATA); operandAddress = (high | low) + X; } { // NOTE: There are mixed reports on the actual operation // of this instruction! poke(operandAddress, Y & (((operandAddress >> 8) & 0xff) + 1)); } break; case 0x0f: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= ((uInt16)peek(PC++, DISASM_CODE) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand); 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_DATA); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand); 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_DATA); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand); A |= operand; notZ = A; N = A & 0x80; } break; case 0x07: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand); A |= operand; notZ = A; N = A & 0x80; } break; case 0x17: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand); A |= operand; notZ = A; N = A & 0x80; } break; case 0x03: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_DATA); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= ((uInt16)peek(pointer, DISASM_DATA) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand); 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_DATA); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand); A |= operand; notZ = A; N = A & 0x80; } break; case 0x4f: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= ((uInt16)peek(PC++, DISASM_CODE) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand); 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_DATA); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand); 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_DATA); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand); A ^= operand; notZ = A; N = A & 0x80; } break; case 0x47: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand); A ^= operand; notZ = A; N = A & 0x80; } break; case 0x57: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand); A ^= operand; notZ = A; N = A & 0x80; } break; case 0x43: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_DATA); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= ((uInt16)peek(pointer, DISASM_DATA) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand); 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_DATA); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand); A ^= operand; notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// // STA case 0x85: { operandAddress = peek(PC++, DISASM_CODE); } SET_LAST_POKE(myLastSrcAddressA) { poke(operandAddress, A); } break; case 0x95: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + X) & 0xFF; } { poke(operandAddress, A); } break; case 0x8d: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= ((uInt16)peek(PC++, DISASM_CODE) << 8); } { poke(operandAddress, A); } break; case 0x9d: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = ((uInt16)peek(PC++, DISASM_CODE) << 8); peek(high | (uInt8)(low + X), DISASM_DATA); operandAddress = (high | low) + X; } { poke(operandAddress, A); } break; case 0x99: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = ((uInt16)peek(PC++, DISASM_CODE) << 8); peek(high | (uInt8)(low + Y), DISASM_DATA); operandAddress = (high | low) + Y; } { poke(operandAddress, A); } break; case 0x81: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_DATA); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= ((uInt16)peek(pointer, DISASM_DATA) << 8); } { poke(operandAddress, A); } 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_DATA); operandAddress = (high | low) + Y; } { poke(operandAddress, A); } break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // STX case 0x86: { operandAddress = peek(PC++, DISASM_CODE); } SET_LAST_POKE(myLastSrcAddressX) { poke(operandAddress, X); } break; case 0x96: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + Y) & 0xFF; } { poke(operandAddress, X); } break; case 0x8e: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= ((uInt16)peek(PC++, DISASM_CODE) << 8); } { poke(operandAddress, X); } break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // STY case 0x84: { operandAddress = peek(PC++, DISASM_CODE); } SET_LAST_POKE(myLastSrcAddressY) { poke(operandAddress, Y); } break; case 0x94: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + X) & 0xFF; } { poke(operandAddress, Y); } break; case 0x8c: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= ((uInt16)peek(PC++, DISASM_CODE) << 8); } { poke(operandAddress, Y); } 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-3.9.3/src/emucore/CompuMate.hxx0000644000175000001440000001212312266336753017264 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CompuMate.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef COMPUMATE_HXX #define COMPUMATE_HXX #include "bspf.hxx" #include "CartCM.hxx" #include "Control.hxx" #include "Event.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 @version $Id: CompuMate.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 cart The CompuMate cartridge @param event The event object to use for events @param system The system using this controller */ CompuMate(CartridgeCM& cart, const Event& event, const System& system); /** Destructor Controllers are deleted outside this class */ virtual ~CompuMate() { } /** Return the left and right CompuMate controllers */ Controller* leftController() { return myLeftController; } Controller* 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); 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) { } /** Destructor */ virtual ~CMControl() { } public: /** Called after *all* digital pins have been written on Port A. @param value The entire contents of the SWCHA register */ void controlWrite(uInt8) { myHandler.update(); } /** Update the entire digital and analog pin state according to the events currently set. */ void update() { } private: class CompuMate& myHandler; }; private: // Cart, Event and System objects CartridgeCM& myCart; const Event& myEvent; const System& mySystem; // Left and right controllers CMControl *myLeftController, *myRightController; // 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]; // System cycle at which the update() method is called // Multiple calls at the same cycle should be ignored uInt32 myCycleAtLastUpdate; }; #endif stella-3.9.3/src/emucore/module.mk0000644000175000001440000000356212266246257016465 0ustar stephenusersMODULE := src/emucore MODULE_OBJS := \ src/emucore/AtariVox.o \ src/emucore/Booster.o \ src/emucore/Cart.o \ src/emucore/Cart0840.o \ src/emucore/Cart2K.o \ src/emucore/Cart3E.o \ src/emucore/Cart3F.o \ src/emucore/Cart4A50.o \ src/emucore/Cart4K.o \ src/emucore/Cart4KSC.o \ src/emucore/CartAR.o \ src/emucore/CartCM.o \ src/emucore/CartCTY.o \ src/emucore/CartCV.o \ src/emucore/CartDPC.o \ src/emucore/CartDPCPlus.o \ src/emucore/CartE0.o \ src/emucore/CartE7.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/CartMC.o \ src/emucore/CartSB.o \ src/emucore/CartUA.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/FrameBuffer.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/NullDev.o \ src/emucore/MD5.o \ src/emucore/OSystem.o \ src/emucore/Paddles.o \ src/emucore/Props.o \ src/emucore/PropsSet.o \ src/emucore/Random.o \ src/emucore/SaveKey.o \ src/emucore/Serializer.o \ src/emucore/Settings.o \ src/emucore/Switches.o \ src/emucore/StateManager.o \ src/emucore/System.o \ src/emucore/TIA.o \ src/emucore/TIASnd.o \ src/emucore/TIATables.o \ src/emucore/TrackBall.o \ src/emucore/Thumbulator.o MODULE_DIRS += \ src/emucore # Include common rules include $(srcdir)/common.rules stella-3.9.3/src/emucore/CartDPCPlus.hxx0000644000175000001440000001607112266336753017464 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDPCPlus.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CARTRIDGE_DPC_PLUS_HXX #define CARTRIDGE_DPC_PLUS_HXX class System; #ifdef THUMB_SUPPORT class Thumbulator; #endif #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). For complete details on the DPC chip see David P. Crane's United States Patent Number 4,644,495. @author Darrell Spice Jr, Fred Quimby, Stephen Anthony, Bradford W. Mott @version $Id: CartDPCPlus.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class CartridgeDPCPlus : public Cartridge { friend class CartridgeDPCPlusWidget; 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeDPCPlus(); public: /** Reset device to its power-on state */ void reset(); /** Notification method invoked by the system right before the system resets its cycle counter to zero. It may be necessary to override this method for devices that remember cycle counts. */ void systemCyclesReset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); 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; 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 uInt8 myDPCRAM[8192]; #ifdef THUMB_SUPPORT // Pointer to the Thumb ARM emulator object Thumbulator* myThumbEmulator; #endif // Pointer to the 1K frequency table uInt8* myFrequencyImage; // Indicates which bank is currently active uInt16 myCurrentBank; // 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 when the last update to music data fetchers occurred Int32 mySystemCycles; // Fractional DPC music OSC clocks unused during the last update double myFractionalClocks; }; #endif stella-3.9.3/src/emucore/SerialPort.hxx0000644000175000001440000000372312266336753017464 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SerialPort.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: SerialPort.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class SerialPort { public: SerialPort() { } virtual ~SerialPort() { } /** 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; } /** Close a previously opened serial port. */ virtual void closePort() { } /** 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; } }; #endif stella-3.9.3/src/emucore/M6502.m40000644000175000001440000010614312266336753015622 0ustar stephenusers//============================================================================ // // 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-2014 by Bradford W. Mott, Stephen Anthony // and 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); }') define(M6502_ABSOLUTEX_READ, `{ uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = ((uInt16)peek(PC++, DISASM_CODE) << 8); intermediateAddress = high | (uInt8)(low + X); operand = peek(intermediateAddress, DISASM_DATA); if((low + X) > 0xFF) { intermediateAddress = (high | low) + X; 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_DATA); 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_DATA); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); }') define(M6502_ABSOLUTEY_READ, `{ uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = ((uInt16)peek(PC++, DISASM_CODE) << 8); intermediateAddress = high | (uInt8)(low + Y); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; 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_DATA); 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_DATA); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); }') 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); }') define(M6502_ZEROX_READ, `{ intermediateAddress = peek(PC++, DISASM_CODE); peek(intermediateAddress, DISASM_DATA); intermediateAddress += X; operand = peek(intermediateAddress, DISASM_DATA); }') define(M6502_ZEROX_WRITE, `{ operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + X) & 0xFF; }') define(M6502_ZEROX_READMODIFYWRITE, `{ operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); }') define(M6502_ZEROY_READ, `{ intermediateAddress = peek(PC++, DISASM_CODE); peek(intermediateAddress, DISASM_DATA); intermediateAddress += Y; operand = peek(intermediateAddress, DISASM_DATA); }') define(M6502_ZEROY_WRITE, `{ operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + Y) & 0xFF; }') define(M6502_ZEROY_READMODIFYWRITE, `{ operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_DATA); operandAddress = (operandAddress + Y) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); }') 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_DATA); 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_DATA); 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_DATA); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= ((uInt16)peek(pointer, DISASM_DATA) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); }') 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); operand = peek(intermediateAddress, DISASM_DATA); if((low + Y) > 0xFF) { intermediateAddress = (high | low) + Y; 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_DATA); 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_DATA); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand); }') 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); 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_CODE); B = true; poke(0x0100 + SP--, PC >> 8); poke(0x0100 + SP--, PC & 0x00ff); poke(0x0100 + SP--, PS()); I = true; PC = peek(0xfffe, DISASM_NONE); PC |= ((uInt16)peek(0xffff, DISASM_NONE) << 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); uInt16 value2 = (uInt16)A - (uInt16)value; notZ = value2; N = value2 & 0x0080; C = !(value2 & 0x0100); }') define(M6502_DEC, `{ uInt8 value = operand - 1; poke(operandAddress, value); 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); 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); // 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); poke(0x0100 + SP--, PC & 0xff); 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); 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); }') define(M6502_PHP, `{ poke(0x0100 + SP--, PS()); }') define(M6502_PLA, `{ peek(0x0100 + SP++, DISASM_NONE); A = peek(0x0100 + SP, DISASM_NONE); notZ = A; N = A & 0x80; }') define(M6502_PLP, `{ peek(0x0100 + SP++, DISASM_NONE); PS(peek(0x0100 + SP, DISASM_NONE)); }') define(M6502_RLA, `{ uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value); 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); 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); 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); 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_CODE); }') define(M6502_SAX, `{ poke(operandAddress, A & X); }') 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)); }') 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)); }') define(M6502_SHX, `{ // NOTE: There are mixed reports on the actual operation // of this instruction! poke(operandAddress, X & (((operandAddress >> 8) & 0xff) + 1)); }') define(M6502_SHY, `{ // NOTE: There are mixed reports on the actual operation // of this instruction! poke(operandAddress, Y & (((operandAddress >> 8) & 0xff) + 1)); }') define(M6502_SLO, `{ // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand); 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); A ^= operand; notZ = A; N = A & 0x80; }') define(M6502_STA, `{ poke(operandAddress, A); }') define(M6502_STX, `{ poke(operandAddress, X); }') define(M6502_STY, `{ poke(operandAddress, Y); }') 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; }') 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; case 0x4b: M6502_IMMEDIATE_READ M6502_ASR break; case 0x0b: case 0x2b: M6502_IMMEDIATE_READ M6502_ANC break; 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; case 0x8b: M6502_IMMEDIATE_READ M6502_ANE break; case 0x6b: M6502_IMMEDIATE_READ M6502_ARR break; 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; 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 0x24: M6502_ZERO_READ M6502_BIT break; case 0x2C: M6502_ABSOLUTE_READ M6502_BIT 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 0x00: M6502_BRK break; case 0x50: M6502_IMMEDIATE_READ M6502_BVC break; case 0x70: M6502_IMMEDIATE_READ M6502_BVS break; case 0x18: M6502_IMPLIED M6502_CLC break; case 0xd8: M6502_IMPLIED M6502_CLD break; case 0x58: M6502_IMPLIED M6502_CLI break; case 0xb8: M6502_IMPLIED M6502_CLV break; 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; case 0xe0: M6502_IMMEDIATE_READ M6502_CPX break; case 0xe4: M6502_ZERO_READ M6502_CPX break; case 0xec: M6502_ABSOLUTE_READ M6502_CPX break; case 0xc0: M6502_IMMEDIATE_READ M6502_CPY break; case 0xc4: M6502_ZERO_READ M6502_CPY break; case 0xcc: M6502_ABSOLUTE_READ M6502_CPY break; 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; 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; case 0xca: M6502_IMPLIED M6502_DEX break; case 0x88: M6502_IMPLIED M6502_DEY break; 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; 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; case 0xe8: M6502_IMPLIED M6502_INX break; case 0xc8: M6502_IMPLIED M6502_INY break; 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; case 0x4c: M6502_ABSOLUTE_WRITE M6502_JMP break; case 0x6c: M6502_INDIRECT M6502_JMP break; case 0x20: M6502_JSR break; 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; ////////////////////////////////////////////////// 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; case 0xab: M6502_IMMEDIATE_READ M6502_LXA break; 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; ////////////////////////////////////////////////// case 0x48: M6502_IMPLIED // TODO - add tracking for this opcode M6502_PHA break; case 0x08: M6502_IMPLIED // TODO - add tracking for this opcode M6502_PHP break; case 0x68: M6502_IMPLIED // TODO - add tracking for this opcode M6502_PLA break; case 0x28: M6502_IMPLIED // TODO - add tracking for this opcode M6502_PLP break; 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; 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; 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; 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; case 0x40: M6502_IMPLIED M6502_RTI break; case 0x60: M6502_IMPLIED M6502_RTS break; 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; 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; case 0xcb: M6502_IMMEDIATE_READ M6502_SBX break; case 0x38: M6502_IMPLIED M6502_SEC break; case 0xf8: M6502_IMPLIED M6502_SED break; case 0x78: M6502_IMPLIED M6502_SEI break; case 0x9f: M6502_ABSOLUTEY_WRITE M6502_SHA break; case 0x93: M6502_INDIRECTY_WRITE M6502_SHA break; case 0x9b: M6502_ABSOLUTEY_WRITE M6502_SHS break; case 0x9e: M6502_ABSOLUTEY_WRITE M6502_SHX break; case 0x9c: M6502_ABSOLUTEX_WRITE M6502_SHY break; 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; 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-3.9.3/src/emucore/Cart3F.hxx0000644000175000001440000001140512266336753016456 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart3F.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: Cart3F.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~Cartridge3F(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active for the first segment uInt16 myCurrentBank; // Pointer to a dynamically allocated ROM image of the cartridge uInt8* myImage; // Size of the ROM image uInt32 mySize; }; #endif stella-3.9.3/src/emucore/EventHandler.hxx0000644000175000001440000003460512266336753017762 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: EventHandler.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef EVENTHANDLER_HXX #define EVENTHANDLER_HXX #include #include class Console; class OSystem; class DialogContainer; class EventMappingWidget; class MouseControl; class StringList; class VariantList; #include "Array.hxx" #include "Event.hxx" #include "StellaKeys.hxx" #include "bspf.hxx" enum MouseButton { EVENT_LBUTTONDOWN, EVENT_LBUTTONUP, EVENT_RBUTTONDOWN, EVENT_RBUTTONUP, EVENT_WHEELDOWN, EVENT_WHEELUP }; enum JoyHat { EVENT_HATUP = 0, // make sure these are set correctly, EVENT_HATDOWN = 1, // since they'll be used as array indices EVENT_HATLEFT = 2, EVENT_HATRIGHT = 3, EVENT_HATCENTER = 4 }; enum EventMode { kEmulationMode = 0, // make sure these are set correctly, kMenuMode = 1, // since they'll be used as array indices kNumModes = 2 }; /** 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 @version $Id: EventHandler.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class EventHandler { public: /** Create a new event handler object */ EventHandler(OSystem* osystem); /** Destructor */ virtual ~EventHandler(); // Enumeration representing the different states of operation enum State { S_NONE, S_EMULATE, S_PAUSE, S_LAUNCHER, S_MENU, S_CMDMENU, S_DEBUGGER }; /** Returns the event object associated with this handler class. @return The event object */ Event& event() { return myEvent; } /** Initialize state of this eventhandler. */ void initialize(); /** Set up any joysticks on the system. This must be called *after* the framebuffer has been created, since SDL requires the video to be intialized before joysticks can be probed. */ void setupJoysticks(); /** 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(); /** 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 State type */ State state() const { return myState; } /** Resets the state machine of the EventHandler to the defaults @param state The current state to set */ void reset(State 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); inline bool kbdAlt(int mod) const { #ifndef MAC_OSX return (mod & KMOD_ALT); #else return (mod & KMOD_META); #endif } inline bool kbdControl(int mod) const { return (mod & KMOD_CTRL) > 0; } inline bool kbdShift(int mod) const { return (mod & KMOD_SHIFT); } void enterMenuMode(State state); void leaveMenuMode(); bool enterDebugMode(); void leaveDebugMode(); 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); bool frying() const { return myFryingFlag; } void getActionList(EventMode mode, StringList& list) const; void getComboList(EventMode mode, VariantList& map) const; /** Used to access the list of events assigned to a specific combo event. */ void getComboListForEvent(Event::Type event, StringList& list) 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 { return myJoysticks[stick].axisTable[axis][(value > 0)][mode]; } Event::Type eventForJoyButton(int stick, int button, EventMode mode) const { return myJoysticks[stick].btnTable[button][mode]; } Event::Type eventForJoyHat(int stick, int hat, int value, EventMode mode) const { return myJoysticks[stick].hatTable[hat][value][mode]; } 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 axis 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, int 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; } private: enum { kComboSize = 16, kEventsPerCombo = 8, kEmulActionListSize = 75 + 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 setSDLMappings(); void setKeymap(); void setJoymap(); void setDefaultKeymap(Event::Type, EventMode mode); void setDefaultJoymap(Event::Type, EventMode mode); void saveKeyMapping(); void saveJoyMapping(); void saveComboMapping(); void setMouseAsPaddle(int paddle, const string& message); /** 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(State state); // Callback function invoked by the event-reset SDL Timer static uInt32 resetEventsCallback(uInt32 interval, void* param); private: // Structure used for action menu items struct ActionList { Event::Type event; const char* action; char* key; bool allow_combo; }; struct JoyMouse { // Used for joystick to mouse emulation bool active; int x, y, x_amt, y_amt, amt, val, old_val; }; // Global OSystem object OSystem* myOSystem; // 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 MouseControl* 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]; // Array of strings which correspond to the given StellaKey string ourKBDKMapping[KBDK_LAST]; // Indicates the current state of the system (ie, which mode is current) State 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; // A bug in the SDL video handler creates an extraneous mouse motion // event after a video state change // We detect when this happens and discard the event bool mySkipMouseMotion; // 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]; // Thin wrapper holding all information about an SDL 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. class StellaJoystick { public: StellaJoystick(); virtual ~StellaJoystick(); string setStick(int i); string getMap() const; bool setMap(const string& map); void eraseMap(EventMode mode); void eraseEvent(Event::Type event, EventMode mode); string about() const; public: 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; string name; SDL_Joystick* stick; 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); }; StellaJoystick* myJoysticks; uInt32 myNumJoysticks; map myJoystickMap; }; #endif stella-3.9.3/src/emucore/Booster.hxx0000644000175000001440000000561012266336753017012 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Booster.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: Booster.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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); /** Destructor */ virtual ~BoosterGrip(); public: /** Update the entire digital and analog pin state according to the events currently set. */ void update(); /** 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); 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; }; #endif stella-3.9.3/src/emucore/TIA.hxx0000644000175000001440000005120312266336753016011 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TIA.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef TIA_HXX #define TIA_HXX class Console; class Settings; class Sound; #include "bspf.hxx" #include "Device.hxx" #include "System.hxx" #include "TIATables.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 Bradford W. Mott @version $Id: TIA.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class TIA : public Device { 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); /** Destructor */ virtual ~TIA(); public: /** Reset device to its power-on state */ void reset(); /** Reset frame to current YStart/Height properties */ void frameReset(); /** Notification method invoked by the system right before the system resets its cycle counter to zero. It may be necessary to override this method for devices that remember cycle counts. */ void systemCyclesReset(); /** 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); /** 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 install(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; /** 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); /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { return "TIA"; } /** Get the byte at the specified address @return The byte at the specified address */ uInt8 peek(uInt16 address); /** 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); /** 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(); /** Answers the current frame buffer @return Pointer to the current frame buffer */ uInt8* currentFrameBuffer() const { return myCurrentFrameBuffer + myFramePointerOffset; } /** Answers the previous frame buffer @return Pointer to the previous frame buffer */ uInt8* previousFrameBuffer() const { return myPreviousFrameBuffer + myFramePointerOffset; } /** Answers the width and height of the frame buffer */ inline uInt32 width() const { return 160; } inline uInt32 height() const { return myFrameHeight; } inline uInt32 ystart() const { return myFrameYStart; } /** 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) { myFrameHeight = height; } void setYStart(uInt32 ystart) { myFrameYStart = ystart; } /** Enables/disables auto-frame calculation. If enabled, the TIA re-adjusts the framerate at regular intervals. @param mode Whether to enable or disable all auto-frame calculation */ void enableAutoFrame(bool mode) { myAutoFrameEnabled = mode; } /** Enables/disables color-loss for PAL modes only. @param mode Whether to enable or disable PAL color-loss mode */ void enableColorLoss(bool mode) { myColorLossEnabled = myFramerate <= 55 ? mode : false; } /** Answers whether this TIA runs at NTSC or PAL scanrates, based on how many frames of out the total count are PAL frames. */ bool isPAL() { return float(myPALFrameCounter) / myFrameCounter >= (25.0/60.0); } /** Answers the current color clock we've gotten to on this scanline. @return The current color clock */ uInt32 clocksThisLine() const { return ((mySystem->cycles() * 3) - myClockWhenFrameStarted) % 228; } /** Answers the scanline at which the current frame began drawing. @return The starting scanline */ uInt32 startLine() const { return myStartScanline; } /** 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 ((mySystem->cycles() * 3) - myClockWhenFrameStarted) / 228; } /** Answers whether the TIA is currently in 'partial frame' mode (we're in between a call of startFrame and endFrame). @return If we're in partial frame mode */ bool partialFrame() const { return myPartialFrameFlag; } /** Answers the first scanline at which drawing occured in the last frame. @return The starting scanline */ uInt32 startScanline() const { return myStartScanline; } /** Answers the current position of the virtual 'electron beam' used to draw the TIA image. If not in partial frame mode, the position is defined to be in the lower right corner (@ width/height of the screen). Note that the coordinates are with respect to currentFrameBuffer(), taking any YStart values into account. @return The x/y coordinates of the scanline electron beam, and whether it is in the visible/viewable area of the screen */ bool scanlinePos(uInt16& x, uInt16& 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(); /** Toggle the display of HMOVE blanks. @return Whether the HMOVE blanking was enabled or disabled */ bool toggleHMOVEBlank(); /** Enables/disable/toggle 'fixed debug colors' mode. @param mode 1/0 indicates on/off, otherwise flip from its current state @return Whether the mode was enabled or disabled */ bool toggleFixedColors(uInt8 mode = 2); /** 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); #ifdef DEBUGGER_SUPPORT /** This method should be called to update the TIA with a new scanline. */ void updateScanline(); /** This method should be called to update the TIA with a new partial scanline by stepping one CPU instruction. */ void updateScanlineByStep(); /** This method should be called to update the TIA with a new partial scanline by tracing to target address. */ void updateScanlineByTrace(int target); #endif private: /** Enables/disables all TIABit bits. Note that disabling a graphical object also disables its collisions. @param mode Whether to enable or disable all bits */ void enableBits(bool mode); /** Enables/disables all TIABit collisions. @param mode Whether to enable or disable all collisions */ void enableCollisions(bool mode); // Update the current frame buffer to the specified color clock void updateFrame(Int32 clock); // Waste cycles until the current scanline is finished void waitHorizontalSync(); // Reset horizontal sync counter void waitHorizontalRSync(); // Clear both internal TIA buffers to black (palette color 0) void clearBuffers(); // Set up bookkeeping for the next frame void startFrame(); // Update bookkeeping at end of frame void endFrame(); // Convert resistance from ports to dumped value uInt8 dumpedInputPort(int resistance); // Write the specified value to the HMOVE registers at the given clock void pokeHMP0(uInt8 value, Int32 clock); void pokeHMP1(uInt8 value, Int32 clock); void pokeHMM0(uInt8 value, Int32 clock); void pokeHMM1(uInt8 value, Int32 clock); void pokeHMBL(uInt8 value, Int32 clock); // Apply motion to registers when HMOVE is currently active void applyActiveHMOVEMotion(int hpos, Int16& pos, Int32 motionClock); // Apply motion to registers when HMOVE was previously active void applyPreviousHMOVEMotion(int hpos, Int16& pos, uInt8 motion); private: // Console the TIA is associated with Console& myConsole; // Sound object the TIA is associated with Sound& mySound; // Settings object the TIA is associated with Settings& mySettings; // Pointer to the current frame buffer uInt8* myCurrentFrameBuffer; // Pointer to the previous frame buffer uInt8* myPreviousFrameBuffer; // Pointer to the next pixel that will be drawn in the current frame buffer uInt8* myFramePointer; // Indicates offset used by the exported frame buffer // (the exported frame buffer is a vertical 'sliding window' of the actual buffer) uInt32 myFramePointerOffset; // Indicates the number of 'colour clocks' offset from the base // frame buffer pointer // (this is used when loading state files with a 'partial' frame) uInt32 myFramePointerClocks; // Indicated what scanline the frame should start being drawn at uInt32 myFrameYStart; // Indicates the height of the frame in scanlines uInt32 myFrameHeight; // Indicates offset in color clocks when display should stop uInt32 myStopDisplayOffset; // Indicates color clocks when the current frame began Int32 myClockWhenFrameStarted; // Indicates color clocks when frame should begin to be drawn Int32 myClockStartDisplay; // Indicates color clocks when frame should stop being drawn Int32 myClockStopDisplay; // Indicates color clocks when the frame was last updated Int32 myClockAtLastUpdate; // Indicates how many color clocks remain until the end of // current scanline. This value is valid during the // displayed portion of the frame. Int32 myClocksToEndOfScanLine; // Indicates the total number of scanlines generated by the last frame uInt32 myScanlineCountForLastFrame; // Indicates the maximum number of scanlines to be generated for a frame uInt32 myMaximumNumberOfScanlines; // Indicates potentially the first scanline at which drawing occurs uInt32 myStartScanline; // Color clock when VSYNC ending causes a new frame to be started Int32 myVSYNCFinishClock; uInt8 myVSYNC; // Holds the VSYNC register value uInt8 myVBLANK; // Holds the VBLANK register value uInt8 myNUSIZ0; // Number and size of player 0 and missle 0 uInt8 myNUSIZ1; // Number and size of player 1 and missle 1 uInt8 myPlayfieldPriorityAndScore; uInt8 myPriorityEncoder[2][256]; uInt8 myColor[8]; uInt8 myFixedColor[8]; uInt8* myColorPtr; uInt8 myCTRLPF; // Playfield control register bool myREFP0; // Indicates if player 0 is being reflected bool myREFP1; // Indicates if player 1 is being reflected uInt32 myPF; // Playfield graphics (19-12:PF2 11-4:PF1 3-0:PF0) uInt8 myGRP0; // Player 0 graphics register uInt8 myGRP1; // Player 1 graphics register uInt8 myDGRP0; // Player 0 delayed graphics register uInt8 myDGRP1; // Player 1 delayed graphics register bool myENAM0; // Indicates if missle 0 is enabled bool myENAM1; // Indicates if missle 1 is enabled bool myENABL; // Indicates if the ball is enabled bool myDENABL; // Indicates if the vertically delayed ball is enabled uInt8 myHMP0; // Player 0 horizontal motion register uInt8 myHMP1; // Player 1 horizontal motion register uInt8 myHMM0; // Missle 0 horizontal motion register uInt8 myHMM1; // Missle 1 horizontal motion register uInt8 myHMBL; // Ball horizontal motion register bool myVDELP0; // Indicates if player 0 is being vertically delayed bool myVDELP1; // Indicates if player 1 is being vertically delayed bool myVDELBL; // Indicates if the ball is being vertically delayed bool myRESMP0; // Indicates if missle 0 is reset to player 0 bool myRESMP1; // Indicates if missle 1 is reset to player 1 uInt16 myCollision; // Collision register // Determines whether specified collisions are enabled or disabled // The lower 16 bits are and'ed with the collision register to mask out // any collisions we don't want to be processed // The upper 16 bits are used to store which objects is currently // enabled or disabled // This is necessary since there are 15 collision combinations which // are controlled by 6 objects uInt32 myCollisionEnabledMask; // Note that these position registers contain the color clock // on which the object's serial output should begin (0 to 159) Int16 myPOSP0; // Player 0 position register Int16 myPOSP1; // Player 1 position register Int16 myPOSM0; // Missle 0 position register Int16 myPOSM1; // Missle 1 position register Int16 myPOSBL; // Ball position register // The color clocks elapsed so far for each of the graphical objects, // as denoted by 'MOTCK' line described in A. Towers TIA Hardware Notes Int32 myMotionClockP0; Int32 myMotionClockP1; Int32 myMotionClockM0; Int32 myMotionClockM1; Int32 myMotionClockBL; // Indicates 'start' signal for each of the graphical objects as // described in A. Towers TIA Hardware Notes Int32 myStartP0; Int32 myStartP1; Int32 myStartM0; Int32 myStartM1; // Index into the player mask arrays indicating whether display // of the first copy should be suppressed uInt8 mySuppressP0; uInt8 mySuppressP1; // Latches for 'more motion required' as described in A. Towers TIA // Hardware Notes bool myHMP0mmr; bool myHMP1mmr; bool myHMM0mmr; bool myHMM1mmr; bool myHMBLmmr; // Graphics for Player 0 that should be displayed. This will be // reflected if the player is being reflected. uInt8 myCurrentGRP0; // Graphics for Player 1 that should be displayed. This will be // reflected if the player is being reflected. uInt8 myCurrentGRP1; // It's VERY important that the BL, M0, M1, P0 and P1 current // mask pointers are always on a uInt32 boundary. Otherwise, // the TIA code will fail on a good number of CPUs. const uInt8* myP0Mask; const uInt8* myM0Mask; const uInt8* myM1Mask; const uInt8* myP1Mask; const uInt8* myBLMask; const uInt32* myPFMask; // Audio values; only used by TIADebug uInt8 myAUDV0, myAUDV1, myAUDC0, myAUDC1, myAUDF0, myAUDF1; // Indicates when the dump for paddles was last set Int32 myDumpDisabledCycle; // Indicates if the dump is current enabled for the paddles bool myDumpEnabled; // Latches for INPT4 and INPT5 uInt8 myINPT4, myINPT5; // Indicates if HMOVE blanks are currently or previously enabled, // and at which horizontal position the HMOVE was initiated Int32 myCurrentHMOVEPos; Int32 myPreviousHMOVEPos; bool myHMOVEBlankEnabled; bool myAllowHMOVEBlanks; // Indicates if unused TIA pins are randomly driven high or low // Otherwise, they take on the value previously on the databus bool myTIAPinsDriven; // Bitmap of the objects that should be considered while drawing uInt8 myEnabledObjects; // Determines whether specified bits (from TIABit) are enabled or disabled // This is and'ed with the enabled objects each scanline to mask out any // objects we don't want to be processed uInt8 myDisabledObjects; // Indicates if color loss should be enabled or disabled. Color loss // occurs on PAL (and maybe SECAM) systems when the previous frame // contains an odd number of scanlines. bool myColorLossEnabled; // Indicates whether we're done with the current frame. poke() clears this // when VSYNC is strobed or the max scanlines/frame limit is hit. bool myPartialFrameFlag; // Automatic framerate correction based on number of scanlines bool myAutoFrameEnabled; // Number of total frames displayed by this TIA uInt32 myFrameCounter; // Number of PAL frames displayed by this TIA uInt32 myPALFrameCounter; // The framerate currently in use by the Console float myFramerate; // Whether TIA bits/collisions are currently enabled/disabled bool myBitsEnabled, myCollisionsEnabled; private: // Copy constructor isn't supported by this class so make it private TIA(const TIA&); // Assignment operator isn't supported by this class so make it private TIA& operator = (const TIA&); }; #endif stella-3.9.3/src/emucore/Paddles.hxx0000644000175000001440000001142112266336753016746 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Paddles.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: Paddles.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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); /** Destructor */ virtual ~Paddles(); public: /** Update the entire digital and analog pin state according to the events currently set. */ void update(); /** 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); /** 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 10, 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 10, with larger values causing more movement */ static void setMouseSensitivity(int sensitivity); private: // Range of values over which digital and mouse movement is scaled // to paddle resistance enum { TRIGRANGE = 4096, TRIGMAX = 3856, TRIGMIN = 1 }; // 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; 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]; }; #endif stella-3.9.3/src/emucore/M6532.hxx0000644000175000001440000001353212266336753016113 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: M6532.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef M6532_HXX #define M6532_HXX class Console; class RiotDebug; class Settings; #include "bspf.hxx" #include "Device.hxx" #include "System.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 @version $Id: M6532.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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); /** Destructor */ virtual ~M6532(); public: /** Reset cartridge to its power-on state */ void reset(); /** Notification method invoked by the system right before the system resets its cycle counter to zero. It may be necessary to override this method for devices that remember cycle counts. */ void systemCyclesReset(); /** 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); /** 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 install(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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { return "M6532"; } public: /** Get the byte at the specified address @return The byte at the specified address */ uInt8 peek(uInt16 address); /** 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); private: Int32 timerClocks() const { return myTimer - (mySystem->cycles() - myCyclesWhenTimerSet); } 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() const; uInt8 timint() const; Int32 intimClocks() const; 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 uInt32 myTimer; // Log base 2 of the number of cycles in a timer interval uInt32 myIntervalShift; // Indicates the number of cycles when the timer was last set Int32 myCyclesWhenTimerSet; // 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; // Whether the timer flag (as currently set) can be used // If it isn't valid, it will be updated as required bool myTimerFlagValid; // 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]; private: // Copy constructor isn't supported by this class so make it private M6532(const M6532&); // Assignment operator isn't supported by this class so make it private M6532& operator = (const M6532&); }; #endif stella-3.9.3/src/emucore/CartDPC.cxx0000644000175000001440000003441712266336753016617 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDPC.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartDPC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDPC::CartridgeDPC(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size), mySystemCycles(0), myFractionalClocks(0.0) { // Make a copy of the entire image memcpy(myImage, image, BSPF_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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDPC::~CartridgeDPC() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPC::reset() { // Update cycles to the current system cycles mySystemCycles = mySystem->cycles(); myFractionalClocks = 0.0; // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPC::systemCyclesReset() { // Get the current system cycle uInt32 cycles = mySystem->cycles(); // Adjust the cycle counter so that it reflects the new value mySystemCycles -= cycles; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPC::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert(((0x1080 & mask) == 0) && ((0x1100 & mask) == 0)); System::PageAccess access(0, 0, 0, this, System::PA_READWRITE); // Set the page accessing method for the DPC reading & writing pages for(uInt32 j = 0x1000; j < 0x1080; j += (1 << shift)) mySystem->setPageAccess(j >> shift, 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 const 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 Int32 cycles = mySystem->cycles() - mySystemCycles; mySystemCycles = mySystem->cycles(); // Calculate the number of DPC OSC clocks since the last update double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks; Int32 wholeClocks = (Int32)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[(myCurrentBank << 12) + 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 const 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[(myCurrentBank << 12) + 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 myCurrentBank = bank; uInt16 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1FF8 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1080; address < (0x1FF8U & ~mask); address += (1 << shift)) { access.directPeekBase = &myProgramImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeDPC::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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[(myCurrentBank << 12) + (address & 0x0FFF)] = value; return myBankChanged = true; } else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeDPC::getImage(int& size) const { size = mySize; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDPC::save(Serializer& out) const { try { out.putString(name()); // Indicates which bank is currently active out.putShort(myCurrentBank); // 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.putInt(mySystemCycles); out.putInt((uInt32)(myFractionalClocks * 100000000.0)); } 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 myCurrentBank = 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 mySystemCycles = (Int32)in.getInt(); myFractionalClocks = (double)in.getInt() / 100000000.0; } catch(...) { cerr << "ERROR: CartridgeDPC::load" << endl; return false; } // Now, go to the current bank bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/CartE0.cxx0000644000175000001440000001666612266336753016463 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartE0.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartE0.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeE0::CartridgeE0(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(8192u, size)); createCodeAccessBase(8192); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeE0::~CartridgeE0() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0::reset() { // Setup segments to some default slices segmentZero(4); segmentOne(5); segmentTwo(6); myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert(((0x1000 & mask) == 0) && ((0x1400 & mask) == 0) && ((0x1800 & mask) == 0) && ((0x1C00 & mask) == 0)); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page acessing methods for the first part of the last segment for(uInt32 i = 0x1C00; i < (0x1FE0U & ~mask); i += (1 << shift)) { access.directPeekBase = &myImage[7168 + (i & 0x03FF)]; access.codeAccessBase = &myCodeAccessBase[7168 + (i & 0x03FF)]; mySystem->setPageAccess(i >> shift, access); } myCurrentSlice[3] = 7; // Set the page accessing methods for the hot spots in the last segment access.directPeekBase = 0; access.codeAccessBase = &myCodeAccessBase[8128]; access.type = System::PA_READ; for(uInt32 j = (0x1FE0 & ~mask); j < 0x2000; j += (1 << shift)) mySystem->setPageAccess(j >> shift, access); // Install some default slices for the other segments segmentZero(4); segmentOne(5); segmentTwo(6); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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; uInt16 shift = mySystem->pageShift(); // Setup the page access methods for the current bank System::PageAccess access(0, 0, 0, this, System::PA_READ); for(uInt32 address = 0x1000; address < 0x1400; address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x03FF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x03FF)]; mySystem->setPageAccess(address >> shift, access); } myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0::segmentOne(uInt16 slice) { if(bankLocked()) return; // Remember the new slice myCurrentSlice[1] = slice; uInt16 offset = slice << 10; uInt16 shift = mySystem->pageShift(); // Setup the page access methods for the current bank System::PageAccess access(0, 0, 0, this, System::PA_READ); for(uInt32 address = 0x1400; address < 0x1800; address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x03FF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x03FF)]; mySystem->setPageAccess(address >> shift, access); } myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0::segmentTwo(uInt16 slice) { if(bankLocked()) return; // Remember the new slice myCurrentSlice[2] = slice; uInt16 offset = slice << 10; uInt16 shift = mySystem->pageShift(); // Setup the page access methods for the current bank System::PageAccess access(0, 0, 0, this, System::PA_READ); for(uInt32 address = 0x1800; address < 0x1C00; address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x03FF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x03FF)]; mySystem->setPageAccess(address >> shift, access); } myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeE0::bank(uInt16) { // Doesn't support bankswitching in the normal sense return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeE0::bank() const { // Doesn't support bankswitching in the normal sense return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeE0::bankCount() const { // Doesn't support bankswitching in the normal sense // There is one 'virtual' bank that can change in many different ways return 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeE0::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; myImage[(myCurrentSlice[address >> 10] << 10) + (address & 0x03FF)] = value; return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeE0::getImage(int& 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-3.9.3/src/emucore/KidVid.cxx0000644000175000001440000003231312266336753016542 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: KidVid.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #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), myFileOpened(false), mySongCounter(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; // Analog pins are never used by the KidVid controller // (at least not in this implementation) myAnalogPinValue[Five] = myAnalogPinValue[Nine] = maximumResistance; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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* 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 != NULL) { cerr << "opened file: " << kvNameTable[i] << endl; mySharedSampleFile = fopen("kvshared.wav", "rb"); if(mySharedSampleFile == NULL) { 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(mySharedData) fseek(mySharedSampleFile, ourSongStart[temp], SEEK_SET); else fseek(mySampleFile, ourSongStart[temp], SEEK_SET); myFilePointer++; myTapeBusy = true; } else { myBeep = true; myTapeBusy = true; mySongCounter = 80*262; /* delay needed for Harmony without tape */ } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void KidVid::getNextSampleByte() { #if 1 static int oddeven = 0; if(mySongCounter == 0) mySampleByte = 0x80; 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-3.9.3/src/emucore/OSystem.cxx0000644000175000001440000010724512266336753017002 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: OSystem.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #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 "SerialPort.hxx" #if defined(UNIX) #include "SerialPortUNIX.hxx" #elif defined(WIN32) #include "SerialPortWin32.hxx" #elif defined(MAC_OSX) #include "SerialPortMACOSX.hxx" #endif #include "FSNode.hxx" #include "MD5.hxx" #include "Cart.hxx" #include "Settings.hxx" #include "PropsSet.hxx" #include "EventHandler.hxx" #include "Menu.hxx" #include "CommandMenu.hxx" #include "Launcher.hxx" #include "Font.hxx" #include "StellaFont.hxx" #include "StellaMediumFont.hxx" #include "StellaLargeFont.hxx" #include "ConsoleFont.hxx" #include "Widget.hxx" #include "Console.hxx" #include "Random.hxx" #include "StateManager.hxx" #include "Version.hxx" #include "OSystem.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OSystem::OSystem() : myEventHandler(NULL), myFrameBuffer(NULL), mySound(NULL), mySettings(NULL), myPropSet(NULL), myConsole(NULL), mySerialPort(NULL), myMenu(NULL), myCommandMenu(NULL), myLauncher(NULL), myLauncherUsed(false), myDebugger(NULL), myCheatManager(NULL), myStateManager(NULL), myPNGLib(NULL), myQuitLoop(false), myRomFile(""), myRomMD5(""), myFeatures(""), myBuildInfo(""), myFont(NULL) { // Calculate startup time myMillisAtStart = (uInt32)(time(NULL) * 1000); // Get built-in features #ifdef DISPLAY_OPENGL myFeatures += "OpenGL "; #endif #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; const SDL_version* ver = SDL_Linked_Version(); info << "Build " << STELLA_BUILD << ", using SDL " << (int)ver->major << "." << (int)ver->minor << "."<< (int)ver->patch << " [" << BSPF_ARCH << "]"; myBuildInfo = info.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OSystem::~OSystem() { delete myMenu; delete myCommandMenu; delete myLauncher; delete myFont; delete myInfoFont; delete mySmallFont; delete myLauncherFont; // Remove any game console that is currently attached deleteConsole(); // OSystem takes responsibility for framebuffer and sound, // since it created them delete myFrameBuffer; delete mySound; // These must be deleted after all the others // This is a bit hacky, since it depends on ordering // of d'tor calls #ifdef DEBUGGER_SUPPORT delete myDebugger; #endif #ifdef CHEATCODE_SUPPORT delete myCheatManager; #endif delete myStateManager; delete myPropSet; delete myEventHandler; delete mySerialPort; delete myPNGLib; delete myZipHandler; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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); // 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 if(!queryVideoHardware()) return false; //////////////////////////////////////////////////////////////////// // 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 = myDesktopWidth < 640 || myDesktopHeight < 480; // 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 = new GUI::Font(GUI::stellaDesc); // The general font used in all UI elements // This is determined by the size of the framebuffer myFont = new GUI::Font(smallScreen ? GUI::stellaDesc : GUI::stellaMediumDesc); // The info font used in all UI elements // This is determined by the size of the framebuffer myInfoFont = new GUI::Font(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) { if(mySettings->getString("launcherfont") == "small") myLauncherFont = new GUI::Font(GUI::consoleDesc); else if(mySettings->getString("launcherfont") == "medium") myLauncherFont = new GUI::Font(GUI::stellaMediumDesc); else myLauncherFont = new GUI::Font(GUI::stellaLargeDesc); } else myLauncherFont = new GUI::Font(GUI::stellaDesc); // Create the event handler for the system myEventHandler = new EventHandler(this); myEventHandler->initialize(); // Create a properties set for us to use and set it up myPropSet = new PropertiesSet(this); #ifdef CHEATCODE_SUPPORT myCheatManager = new CheatManager(this); myCheatManager->loadCheatDatabase(); #endif // Create menu and launcher GUI objects myMenu = new Menu(this); myCommandMenu = new CommandMenu(this); myLauncher = new Launcher(this); myStateManager = new StateManager(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 #if defined(UNIX) mySerialPort = new SerialPortUNIX(); #elif defined(WIN32) mySerialPort = new SerialPortWin32(); #elif defined(MAC_OSX) mySerialPort = new SerialPortMACOSX(); #else // Create an 'empty' serial port mySerialPort = new SerialPort(); #endif // Let the random class know about us; it needs access to getTicks() Random::setSystem(this); // Create PNG handler myPNGLib = new PNGLibrary(); // Create ZIP handler myZipHandler = new ZipHandler(); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::loadConfig() { mySettings->loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::saveConfig() { // Ask all subsystems to save their settings if(myFrameBuffer) myFrameBuffer->ntsc().saveConfig(*mySettings); mySettings->saveConfig(); } #ifdef DEBUGGER_SUPPORT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::createDebugger(Console& console) { delete myDebugger; myDebugger = NULL; myDebugger = new Debugger(*this, console); myDebugger->initialize(); } #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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", defaultSnapSaveDir()); validatePath(mySnapshotLoadDir, "snaploaddir", defaultSnapLoadDir()); 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::setUIPalette() { int palette = mySettings->getInt("uipalette") - 1; if(palette < 0 || palette >= kNumUIPalettes) palette = 0; myFrameBuffer->setUIPalette(&ourGUIColors[palette][0]); myFrameBuffer->refresh(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::setBaseDir(const string& basedir) { FilesystemNode node(basedir); if(!node.isDirectory()) node.makeDir(); myBaseDir = node.getPath(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::setConfigFile(const string& file) { FilesystemNode node(file); myConfigFile = node.getPath(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::setFramerate(float framerate) { if(framerate > 0.0) { myDisplayFrameRate = framerate; myTimePerFrame = (uInt32)(1000000.0 / myDisplayFrameRate); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBInitStatus OSystem::createFrameBuffer() { // There is only ever one FrameBuffer created per run of Stella // Due to the multi-surface nature of the FrameBuffer, repeatedly // creating and destroying framebuffer objects causes crashes which // are far too invasive to fix right now // Besides, how often does one really switch between software and // OpenGL rendering modes, and even when they do, does it really // need to be dynamic? bool firstTime = (myFrameBuffer == NULL); if(firstTime) myFrameBuffer = MediaFactory::createVideo(this); // Re-initialize the framebuffer to current settings FBInitStatus fbstatus = kFailComplete; switch(myEventHandler->state()) { case EventHandler::S_EMULATE: case EventHandler::S_PAUSE: case EventHandler::S_MENU: case EventHandler::S_CMDMENU: fbstatus = myConsole->initializeVideo(); if(fbstatus != kSuccess) goto fallback; break; // S_EMULATE, S_PAUSE, S_MENU, S_CMDMENU case EventHandler::S_LAUNCHER: fbstatus = myLauncher->initializeVideo(); if(fbstatus != kSuccess) goto fallback; break; // S_LAUNCHER #ifdef DEBUGGER_SUPPORT case EventHandler::S_DEBUGGER: fbstatus = myDebugger->initializeVideo(); if(fbstatus != kSuccess) goto fallback; break; // S_DEBUGGER #endif default: // Should never happen logMessage("ERROR: Unknown emulation state in createFrameBuffer()", 0); break; } // The following only need to be done once if(firstTime) { // Setup the SDL joysticks (must be done after FrameBuffer is created) myEventHandler->setupJoysticks(); // Update the UI palette setUIPalette(); } return fbstatus; // GOTO are normally considered evil, unless well documented :) // If initialization of video system fails while in OpenGL mode // because OpenGL is unavailable, attempt to fallback to software mode // Otherwise, pass the error to the parent fallback: if(fbstatus == kFailNotSupported && myFrameBuffer && myFrameBuffer->type() == kDoubleBuffer) { logMessage("ERROR: OpenGL mode failed, fallback to software", 0); delete myFrameBuffer; myFrameBuffer = NULL; mySettings->setValue("video", "soft"); FBInitStatus newstatus = createFrameBuffer(); if(newstatus == kSuccess) { setFramerate(60); myFrameBuffer->showMessage("OpenGL mode failed, fallback to software", kMiddleCenter, true); } return newstatus; } else 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) { // Do a little error checking; it shouldn't be necessary if(myConsole) deleteConsole(); 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; string type, id; try { myConsole = openConsole(myRomFile, myRomMD5, type, id); } catch(const char* err_msg) { myConsole = 0; buf << "ERROR: Couldn't create console (" << err_msg << ")"; logMessage(buf.str(), 0); return buf.str(); } if(myConsole) { #ifdef DEBUGGER_SUPPORT myConsole->addDebugger(); #endif #ifdef CHEATCODE_SUPPORT myCheatManager->loadCheats(myRomMD5); #endif ////////////////////////////////////////////////////////////////////////// // For some reason, ATI video drivers for OpenGL in Win32 cause problems // if the sound isn't initialized before the video // According to the SDL documentation, it shouldn't matter what order the // systems are initialized, but apparently it *does* matter // For now, I'll just reverse the ordering, as suggested by 'zagon' at // http://www.atariage.com/forums/index.php?showtopic=126090&view=findpost&p=1648693 // Hopefully it won't break anything else ////////////////////////////////////////////////////////////////////////// myConsole->initializeAudio(); myEventHandler->reset(EventHandler::S_EMULATE); myEventHandler->setMouseControllerMode(mySettings->getString("usemouse")); if(createFrameBuffer() != kSuccess) // Takes care of initializeVideo() { logMessage("ERROR: Couldn't create framebuffer for console", 0); myEventHandler->reset(EventHandler::S_LAUNCHER); return "ERROR: Couldn't create framebuffer for console"; } if(showmessage) { if(id == "") myFrameBuffer->showMessage("New console created"); else myFrameBuffer->showMessage("Multicart " + type + ", 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 if(mySettings->getBool("holdreset")) myEventHandler->handleEvent(Event::ConsoleReset, 1); if(mySettings->getBool("holdselect")) myEventHandler->handleEvent(Event::ConsoleSelect, 1); const string& holdjoy0 = mySettings->getString("holdjoy0"); if(BSPF_containsIgnoreCase(holdjoy0, "U")) myEventHandler->handleEvent(Event::JoystickZeroUp, 1); if(BSPF_containsIgnoreCase(holdjoy0, "D")) myEventHandler->handleEvent(Event::JoystickZeroDown, 1); if(BSPF_containsIgnoreCase(holdjoy0, "L")) myEventHandler->handleEvent(Event::JoystickZeroLeft, 1); if(BSPF_containsIgnoreCase(holdjoy0, "R")) myEventHandler->handleEvent(Event::JoystickZeroRight, 1); if(BSPF_containsIgnoreCase(holdjoy0, "F")) myEventHandler->handleEvent(Event::JoystickZeroFire, 1); const string& holdjoy1 = mySettings->getString("holdjoy1"); if(BSPF_containsIgnoreCase(holdjoy1, "U")) myEventHandler->handleEvent(Event::JoystickOneUp, 1); if(BSPF_containsIgnoreCase(holdjoy1, "D")) myEventHandler->handleEvent(Event::JoystickOneDown, 1); if(BSPF_containsIgnoreCase(holdjoy1, "L")) myEventHandler->handleEvent(Event::JoystickOneLeft, 1); if(BSPF_containsIgnoreCase(holdjoy1, "R")) myEventHandler->handleEvent(Event::JoystickOneRight, 1); if(BSPF_containsIgnoreCase(holdjoy1, "F")) myEventHandler->handleEvent(Event::JoystickOneFire, 1); #ifdef DEBUGGER_SUPPORT if(mySettings->getBool("debug")) myEventHandler->enterDebugMode(); #endif } return EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::deleteConsole() { if(myConsole) { mySound->close(); #ifdef CHEATCODE_SUPPORT myCheatManager->saveCheats(myConsole->properties().get(Cartridge_MD5)); #endif ostringstream buf; double executionTime = (double) myTimingInfo.totalTime / 1000000.0; double framesPerSecond = (double) myTimingInfo.totalFrames / executionTime; buf << "Game console stats:" << endl << " Total frames drawn: " << myTimingInfo.totalFrames << endl << " Total time (sec): " << executionTime << endl << " Frames per second: " << framesPerSecond << endl << endl; logMessage(buf.str(), 1); delete myConsole; myConsole = NULL; #ifdef DEBUGGER_SUPPORT delete myDebugger; myDebugger = NULL; #endif } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool OSystem::reloadConsole() { deleteConsole(); return createConsole(myRomFile, myRomMD5, false) == EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool OSystem::createLauncher(const string& startdir) { mySettings->setValue("tmpromdir", startdir); bool status = false; myEventHandler->reset(EventHandler::S_LAUNCHER); if(createFrameBuffer() == kSuccess) { myLauncher->reStack(); myFrameBuffer->setCursorState(); myFrameBuffer->refresh(); setFramerate(60); resetLoopTiming(); status = true; } else logMessage("ERROR: Couldn't create launcher", 0); myLauncherUsed = myLauncherUsed || status; return status; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string OSystem::getROMInfo(const FilesystemNode& romfile) { string md5, type, id, result = ""; Console* console = 0; try { console = openConsole(romfile, md5, type, id); } catch(const char* err_msg) { ostringstream buf; buf << "ERROR: Couldn't get ROM info (" << err_msg << ")"; return buf.str(); } result = getROMInfo(console); delete console; return result; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::logMessage(const string& message, uInt8 level) { if(level == 0) { cout << message << endl << flush; myLogMessages += message + "\n"; } else if(level <= (uInt8)mySettings->getInt("loglevel")) { if(mySettings->getBool("logtoconsole")) cout << message << endl << flush; myLogMessages += message + "\n"; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Console* OSystem::openConsole(const FilesystemNode& romfile, string& md5, string& type, string& id) { #define CMDLINE_PROPS_UPDATE(cl_name, prop_name) \ s = mySettings->getString(cl_name); \ if(s != "") props.set(prop_name, s); Console* console = (Console*) NULL; // Open the cartridge image and read it in uInt8* image = 0; uInt32 size = 0; if((image = openROM(romfile, md5, size)) != 0) { // 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); string s = ""; CMDLINE_PROPS_UPDATE("bs", Cartridge_Type); CMDLINE_PROPS_UPDATE("type", Cartridge_Type); // Now create the cartridge string cartmd5 = md5; type = props.get(Cartridge_Type); Cartridge* cart = Cartridge::create(image, size, cartmd5, type, id, *this, *mySettings); // 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)+id); 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); 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 = new Console(this, cart, props); } // Free the image since we don't need it any longer if(image != 0 && size > 0) delete[] image; return console; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8* 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 uInt8* image = 0; if((size = rom.read(image)) == 0) { delete[] image; return (uInt8*) 0; } // 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(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()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::setDefaultJoymap(Event::Type event, EventMode mode) { #define SET_DEFAULT_AXIS(sda_event, sda_mode, sda_stick, sda_axis, sda_val, sda_cmp_event) \ if(eraseAll || sda_cmp_event == sda_event) \ myEventHandler->addJoyAxisMapping(sda_event, sda_mode, sda_stick, sda_axis, sda_val, false); #define SET_DEFAULT_BTN(sdb_event, sdb_mode, sdb_stick, sdb_button, sdb_cmp_event) \ if(eraseAll || sdb_cmp_event == sdb_event) \ myEventHandler->addJoyButtonMapping(sdb_event, sdb_mode, sdb_stick, sdb_button, false); #define SET_DEFAULT_HAT(sdh_event, sdh_mode, sdh_stick, sdh_hat, sdh_dir, sdh_cmp_event) \ if(eraseAll || sdh_cmp_event == sdh_event) \ myEventHandler->addJoyHatMapping(sdh_event, sdh_mode, sdh_stick, sdh_hat, sdh_dir, false); bool eraseAll = (event == Event::NoType); switch(mode) { case kEmulationMode: // Default emulation events // Left joystick left/right directions (assume joystick zero) SET_DEFAULT_AXIS(Event::JoystickZeroLeft, mode, 0, 0, 0, event); SET_DEFAULT_AXIS(Event::JoystickZeroRight, mode, 0, 0, 1, event); // Left joystick up/down directions (assume joystick zero) SET_DEFAULT_AXIS(Event::JoystickZeroUp, mode, 0, 1, 0, event); SET_DEFAULT_AXIS(Event::JoystickZeroDown, mode, 0, 1, 1, event); // Right joystick left/right directions (assume joystick one) SET_DEFAULT_AXIS(Event::JoystickOneLeft, mode, 1, 0, 0, event); SET_DEFAULT_AXIS(Event::JoystickOneRight, mode, 1, 0, 1, event); // Right joystick left/right directions (assume joystick one) SET_DEFAULT_AXIS(Event::JoystickOneUp, mode, 1, 1, 0, event); SET_DEFAULT_AXIS(Event::JoystickOneDown, mode, 1, 1, 1, event); // Left joystick (assume joystick zero, button zero) SET_DEFAULT_BTN(Event::JoystickZeroFire, mode, 0, 0, event); // Right joystick (assume joystick one, button zero) SET_DEFAULT_BTN(Event::JoystickOneFire, mode, 1, 0, event); // Left joystick left/right directions (assume joystick zero and hat 0) SET_DEFAULT_HAT(Event::JoystickZeroLeft, mode, 0, 0, EVENT_HATLEFT, event); SET_DEFAULT_HAT(Event::JoystickZeroRight, mode, 0, 0, EVENT_HATRIGHT, event); // Left joystick up/down directions (assume joystick zero and hat 0) SET_DEFAULT_HAT(Event::JoystickZeroUp, mode, 0, 0, EVENT_HATUP, event); SET_DEFAULT_HAT(Event::JoystickZeroDown, mode, 0, 0, EVENT_HATDOWN, event); break; case kMenuMode: // Default menu/UI events SET_DEFAULT_AXIS(Event::UILeft, mode, 0, 0, 0, event); SET_DEFAULT_AXIS(Event::UIRight, mode, 0, 0, 1, event); SET_DEFAULT_AXIS(Event::UIUp, mode, 0, 1, 0, event); SET_DEFAULT_AXIS(Event::UIDown, mode, 0, 1, 1, event); // Left joystick (assume joystick zero, button zero) SET_DEFAULT_BTN(Event::UISelect, mode, 0, 0, event); // Right joystick (assume joystick one, button zero) SET_DEFAULT_BTN(Event::UISelect, mode, 1, 0, event); SET_DEFAULT_HAT(Event::UILeft, mode, 0, 0, EVENT_HATLEFT, event); SET_DEFAULT_HAT(Event::UIRight, mode, 0, 0, EVENT_HATRIGHT, event); SET_DEFAULT_HAT(Event::UIUp, mode, 0, 0, EVENT_HATUP, event); SET_DEFAULT_HAT(Event::UIDown, mode, 0, 0, EVENT_HATDOWN, event); break; default: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt64 OSystem::getTicks() const { #ifdef HAVE_GETTIMEOFDAY // Gettimeofday natively refers to the UNIX epoch (a set time in the past) timeval now; gettimeofday(&now, 0); 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.start = myTimingInfo.current = myTimingInfo.virt = getTicks(); } if(myTimingInfo.current < myTimingInfo.virt) SDL_Delay((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++; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool OSystem::queryVideoHardware() { // Go ahead and open the video hardware; we're going to need it eventually if(SDL_WasInit(SDL_INIT_VIDEO) == 0) if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) return false; // First get the maximum windowed desktop resolution // Check the 'maxres' setting, which is an undocumented developer feature // that specifies the desktop size // Normally, this wouldn't be set, and we ask SDL directly const GUI::Size& s = mySettings->getSize("maxres"); if(s.w <= 0 || s.h <= 0) { const SDL_VideoInfo* info = SDL_GetVideoInfo(); myDesktopWidth = info->current_w; myDesktopHeight = info->current_h; } else { myDesktopWidth = BSPF_max(s.w, 320); myDesktopHeight = BSPF_max(s.h, 240); } // Various parts of the codebase assume a minimum screen size of 320x240 if(!(myDesktopWidth >= 320 && myDesktopHeight >= 240)) { logMessage("ERROR: queryVideoHardware failed, " "window 320x240 or larger required", 0); return false; } // Then get the valid fullscreen modes // If there are any errors, just use the desktop resolution ostringstream buf; SDL_Rect** modes = SDL_ListModes(NULL, SDL_FULLSCREEN); if((modes == (SDL_Rect**)0) || (modes == (SDL_Rect**)-1)) { Resolution r; r.width = myDesktopWidth; r.height = myDesktopHeight; buf << r.width << "x" << r.height; r.name = buf.str(); myResolutions.push_back(r); } else { // All modes must fit between the lower and upper limits of the desktop // For 'small' desktop, this means larger than 320x240 // For 'large'/normal desktop, exclude all those less than 640x480 bool largeDesktop = myDesktopWidth >= 640 && myDesktopHeight >= 480; uInt32 lowerWidth = largeDesktop ? 640 : 320, lowerHeight = largeDesktop ? 480 : 240; for(uInt32 i = 0; modes[i]; ++i) { if(modes[i]->w >= lowerWidth && modes[i]->w <= myDesktopWidth && modes[i]->h >= lowerHeight && modes[i]->h <= myDesktopHeight) { Resolution r; r.width = modes[i]->w; r.height = modes[i]->h; buf.str(""); buf << r.width << "x" << r.height; r.name = buf.str(); myResolutions.insert_at(0, r); // insert in opposite (of descending) order } } // If no modes were valid, use the desktop dimensions if(myResolutions.size() == 0) { Resolution r; r.width = myDesktopWidth; r.height = myDesktopHeight; buf << r.width << "x" << r.height; r.name = buf.str(); myResolutions.push_back(r); } } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* Palette is defined as follows: // Base colors kColor Normal foreground color (non-text) kBGColor Normal background color (non-text) kShadowColor Item is disabled kTextColor Normal text color kTextColorHi Highlighted text color kTextColorEm Emphasized text color // 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 // Debugger colors kDbgChangedColor Background color for changed cells kDbgChangedTextColor Text color for changed cells kDbgColorHi Highlighted color in debugger data cells */ uInt32 OSystem::ourGUIColors[kNumUIPalettes][kNumColors-256] = { // Standard { 0x686868, 0x000000, 0x404040, 0x000000, 0x62a108, 0x9f0000, 0xc9af7c, 0xf0f0cf, 0xc80000, 0xac3410, 0xd55941, 0xffffff, 0xffd652, 0xac3410, 0xac3410, 0xd55941, 0xac3410, 0xd55941, 0xc80000, 0x00ff00, 0xc8c8ff }, // Classic { 0x686868, 0x000000, 0x404040, 0x20a020, 0x00ff00, 0xc80000, 0x000000, 0x000000, 0xc80000, 0x000000, 0x000000, 0x20a020, 0x00ff00, 0x20a020, 0x20a020, 0x00ff00, 0x20a020, 0x00ff00, 0xc80000, 0x00ff00, 0xc8c8ff } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OSystem::OSystem(const OSystem& osystem) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OSystem& OSystem::operator = (const OSystem&) { assert(false); return *this; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ZipHandler* OSystem::myZipHandler = 0; stella-3.9.3/src/emucore/Genesis.hxx0000644000175000001440000000551712266336753017000 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Genesis.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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); /** Destructor */ virtual ~Genesis(); public: /** Update the entire digital and analog pin state according to the events currently set. */ void update(); /** 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); 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; }; #endif stella-3.9.3/src/emucore/CartCTYTunes.hxx0000644000175000001440000053547112266336753017702 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartCTYTunes.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 const 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-3.9.3/src/emucore/CartBFSC.hxx0000644000175000001440000001052412266336753016724 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartBFSC.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CARTRIDGEBFSC_HXX #define CARTRIDGEBFSC_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartBFSCWidget.hxx" #endif /** There are 32 4K banks (total of 128K ROM) with 128 bytes of RAM. Accessing $1FD0 - $1FEF switches to each bank. @author Stephen Anthony @version $Id: CartBFSC.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeBFSC(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 64K ROM image of the cartridge uInt8 myImage[131072*2]; // The 128 bytes of RAM uInt8 myRAM[128]; }; #endif stella-3.9.3/src/emucore/CartF8.hxx0000644000175000001440000001051212266336753016461 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF8.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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. @author Bradford W. Mott @version $Id: CartF8.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const string& md5, const Settings& settings); /** Destructor */ virtual ~CartridgeF8(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 8K ROM image of the cartridge uInt8 myImage[8192]; }; #endif stella-3.9.3/src/emucore/Cart2K.hxx0000644000175000001440000001061612266336753016465 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart2K.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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. @author Bradford W. Mott @version $Id: Cart2K.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~Cartridge2K(); public: /** Reset cartridge to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { return new Cartridge2KWidget(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); /** 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); private: // Pointer to a dynamically allocated ROM image of the cartridge uInt8* myImage; // Size of the ROM image uInt32 mySize; // Mask to use for mirroring uInt32 myMask; }; #endif stella-3.9.3/src/emucore/CartF6.hxx0000644000175000001440000001037512266336753016466 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF6.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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. @author Bradford W. Mott @version $Id: CartF6.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeF6(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 16K ROM image of the cartridge uInt8 myImage[16384]; }; #endif stella-3.9.3/src/emucore/Cart.cxx0000644000175000001440000006623112267025147016260 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart.cxx 2839 2014-01-19 19:41:27Z stephena $ //============================================================================ #include #include #include #include "bspf.hxx" #include "Cart.hxx" #include "Cart0840.hxx" #include "Cart2K.hxx" #include "Cart3E.hxx" #include "Cart3F.hxx" #include "Cart4A50.hxx" #include "Cart4K.hxx" #include "Cart4KSC.hxx" #include "CartAR.hxx" #include "CartCM.hxx" #include "CartCTY.hxx" #include "CartCV.hxx" #include "CartDPC.hxx" #include "CartDPCPlus.hxx" #include "CartE0.hxx" #include "CartE7.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 "CartMC.hxx" #include "CartSB.hxx" #include "CartUA.hxx" #include "CartX07.hxx" #include "MD5.hxx" #include "Props.hxx" #include "Settings.hxx" #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #include "CartDebug.hxx" #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge* Cartridge::create(const uInt8* image, uInt32 size, string& md5, string& dtype, string& id, const OSystem& osystem, Settings& settings) { Cartridge* cartridge = 0; string type = dtype; // 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 string autodetect = ""; if(type == "AUTO" || settings.getBool("rominfo")) { const string& detected = autodetectType(image, size); autodetect = "*"; if(type != "AUTO" && type != detected) cerr << "Auto-detection not consistent: " << type << ", " << detected << endl; type = detected; } buf << type << autodetect; // Check for multicart first; if found, get the correct part of the image if(type == "2IN1") { // Make sure we have a valid sized image if(size == 2*2048 || size == 2*4096 || size == 2*8192 || size == 2*16384) { dtype = type; type = createFromMultiCart(image, size, 2, md5, id, settings); buf << id; } else dtype = "WRONG_SIZE"; } else if(type == "4IN1") { // Make sure we have a valid sized image if(size == 4*2048 || size == 4*4096 || size == 4*8192) { dtype = type; type = createFromMultiCart(image, size, 4, md5, id, settings); buf << id; } else dtype = "WRONG_SIZE"; } else if(type == "8IN1") { // Make sure we have a valid sized image if(size == 8*2048 || size == 8*4096 || size == 8*8192) { dtype = type; type = createFromMultiCart(image, size, 8, md5, id, settings); buf << id; } else dtype = "WRONG_SIZE"; } else if(type == "16IN1") { // Make sure we have a valid sized image if(size == 16*2048 || size == 16*4096 || size == 16*8192) { dtype = type; type = createFromMultiCart(image, size, 16, md5, id, settings); buf << id; } else dtype = "WRONG_SIZE"; } else if(type == "32IN1") { // Make sure we have a valid sized image if(size == 32*2048 || size == 32*4096) { dtype = type; type = createFromMultiCart(image, size, 32, md5, id, settings); buf << id; } else dtype = "WRONG_SIZE"; } else if(type == "64IN1") { // Make sure we have a valid sized image if(size == 64*2048 || size == 64*4096) { dtype = type; type = createFromMultiCart(image, size, 64, md5, id, settings); buf << id; } else dtype = "WRONG_SIZE"; } else if(type == "128IN1") { // Make sure we have a valid sized image if(size == 128*2048 || size == 128*4096) { dtype = type; type = createFromMultiCart(image, size, 128, md5, id, settings); buf << id; } else dtype = "WRONG_SIZE"; } // We should know the cart's type by now so let's create it if(type == "0840") cartridge = new Cartridge0840(image, size, settings); else if(type == "2K") cartridge = new Cartridge2K(image, size, settings); else if(type == "3E") cartridge = new Cartridge3E(image, size, settings); else if(type == "3F") cartridge = new Cartridge3F(image, size, settings); else if(type == "4A50") cartridge = new Cartridge4A50(image, size, settings); else if(type == "4K") cartridge = new Cartridge4K(image, size, settings); else if(type == "4KSC") cartridge = new Cartridge4KSC(image, size, settings); else if(type == "AR") cartridge = new CartridgeAR(image, size, settings); else if(type == "CM") cartridge = new CartridgeCM(image, size, settings); else if(type == "CTY") cartridge = new CartridgeCTY(image, size, osystem); else if(type == "CV") cartridge = new CartridgeCV(image, size, settings); else if(type == "DPC") cartridge = new CartridgeDPC(image, size, settings); else if(type == "DPC+") cartridge = new CartridgeDPCPlus(image, size, settings); else if(type == "E0") cartridge = new CartridgeE0(image, size, settings); else if(type == "E7") cartridge = new CartridgeE7(image, size, settings); else if(type == "EF") cartridge = new CartridgeEF(image, size, settings); else if(type == "EFSC") cartridge = new CartridgeEFSC(image, size, settings); else if(type == "BF") cartridge = new CartridgeBF(image, size, settings); else if(type == "BFSC") cartridge = new CartridgeBFSC(image, size, settings); else if(type == "DF") cartridge = new CartridgeDF(image, size, settings); else if(type == "DFSC") cartridge = new CartridgeDFSC(image, size, settings); else if(type == "F0" || type == "MB") cartridge = new CartridgeF0(image, size, settings); else if(type == "F4") cartridge = new CartridgeF4(image, size, settings); else if(type == "F4SC") cartridge = new CartridgeF4SC(image, size, settings); else if(type == "F6") cartridge = new CartridgeF6(image, size, settings); else if(type == "F6SC") cartridge = new CartridgeF6SC(image, size, settings); else if(type == "F8") cartridge = new CartridgeF8(image, size, md5, settings); else if(type == "F8SC") cartridge = new CartridgeF8SC(image, size, settings); else if(type == "FA" || type == "FASC") cartridge = new CartridgeFA(image, size, settings); else if(type == "FA2") cartridge = new CartridgeFA2(image, size, osystem); else if(type == "FE") cartridge = new CartridgeFE(image, size, settings); else if(type == "MC") cartridge = new CartridgeMC(image, size, settings); else if(type == "UA") cartridge = new CartridgeUA(image, size, settings); else if(type == "SB") cartridge = new CartridgeSB(image, size, settings); else if(type == "X07") cartridge = new CartridgeX07(image, size, settings); else if(dtype == "WRONG_SIZE") { string err = "Invalid cart size for type '" + type + "'"; throw err.c_str(); } else { string err = "Invalid cart type '" + type + "'"; throw err.c_str(); } if(size < 1024) buf << " (" << size << "B) "; else buf << " (" << (size/1024) << "K) "; myAboutString = buf.str(); return cartridge; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Cartridge::createFromMultiCart(const uInt8*& image, uInt32& size, uInt32 numroms, string& md5, string& id, Settings& settings) { // Get a piece of the larger image uInt32 i = settings.getInt("romloadcount"); size /= numroms; image += i*size; // We need a new md5 and name md5 = MD5(image, size); ostringstream buf; buf << " [G" << (i+1) << "]"; id = buf.str(); // Move to the next game the next time this ROM is loaded settings.setValue("romloadcount", (i+1)%numroms); if(size <= 2048) return "2K"; else if(size == 4096) return "4K"; else if(size == 8192) return "F8"; else /* default */ return "4K"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge::Cartridge(const Settings& settings) : mySettings(settings), myStartBank(0), myBankChanged(true), myCodeAccessBase(NULL), myBankLocked(false) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge::~Cartridge() { if(myCodeAccessBase) delete[] myCodeAccessBase; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::save(ofstream& out) { int size = -1; const uInt8* image = getImage(size); if(image == 0 || size <= 0) { cerr << "save not supported" << endl; return false; } for(int i=0; iautodetectMode()) Debugger::debugger().cartDebug().triggerReadFromWritePort(address); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge::createCodeAccessBase(uInt32 size) { #ifdef DEBUGGER_SUPPORT myCodeAccessBase = new uInt8[size]; memset(myCodeAccessBase, CartDebug::ROW, size); #else myCodeAccessBase = NULL; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Cartridge::autodetectType(const uInt8* image, uInt32 size) { // Guess type based on size const char* type = 0; if((size % 8448) == 0 || size == 6144) { type = "AR"; } else if(size < 2048) // Sub2K images { type = "2K"; } else if((size == 2048) || (size == 4096 && memcmp(image, image + 2048, 2048) == 0)) { type = isProbablyCV(image, size) ? "CV" : "2K"; } else if(size == 4096) { if(isProbablyCV(image,size)) type = "CV"; else if(isProbably4KSC(image,size)) type = "4KSC"; else type = "4K"; } else if(size == 8*1024) // 8K { // First check for *potential* F8 uInt8 signature[] = { 0x8D, 0xF9, 0x1F }; // STA $1FF9 bool f8 = searchForBytes(image, size, signature, 3, 2); if(isProbablySC(image, size)) type = "F8SC"; else if(memcmp(image, image + 4096, 4096) == 0) type = "4K"; else if(isProbablyE0(image, size)) type = "E0"; else if(isProbably3E(image, size)) type = "3E"; else if(isProbably3F(image, size)) type = "3F"; else if(isProbablyUA(image, size)) type = "UA"; else if(isProbablyFE(image, size) && !f8) type = "FE"; else if(isProbably0840(image, size)) type = "0840"; else type = "F8"; } else if(size >= 10240 && size <= 10496) // ~10K - Pitfall2 { type = "DPC"; } else if(size == 12*1024) // 12K { type = "FA"; } else if(size == 16*1024) // 16K { if(isProbablySC(image, size)) type = "F6SC"; else if(isProbablyE7(image, size)) type = "E7"; else if(isProbably3E(image, size)) type = "3E"; /* no known 16K 3F ROMS else if(isProbably3F(image, size)) type = "3F"; */ else type = "F6"; } else if(size == 24*1024 || size == 28*1024) // 24K & 28K { type = "FA2"; } else if(size == 29*1024) // 29K { if(isProbablyARM(image, size)) type = "FA2"; else /*if(isProbablyDPCplus(image, size))*/ type = "DPC+"; } else if(size == 32*1024) // 32K { if(isProbablySC(image, size)) type = "F4SC"; else if(isProbably3E(image, size)) type = "3E"; else if(isProbably3F(image, size)) type = "3F"; else if(isProbablyDPCplus(image, size)) type = "DPC+"; else if(isProbablyCTY(image, size)) type = "CTY"; else if(isProbablyFA2(image, size)) type = "FA2"; else type = "F4"; } else if(size == 64*1024) // 64K { if(isProbably3E(image, size)) type = "3E"; else if(isProbably3F(image, size)) type = "3F"; else if(isProbably4A50(image, size)) type = "4A50"; else if(isProbablyEF(image, size, type)) ; // type has been set directly in the function else if(isProbablyX07(image, size)) type = "X07"; else type = "F0"; } else if(size == 128*1024) // 128K { if(isProbably3E(image, size)) type = "3E"; else if(isProbablyDF(image, size, type)) ; // type has been set directly in the function else if(isProbably3F(image, size)) type = "3F"; else if(isProbably4A50(image, size)) type = "4A50"; else if(isProbablySB(image, size)) type = "SB"; else type = "MC"; } else if(size == 256*1024) // 256K { if(isProbably3E(image, size)) type = "3E"; else if(isProbablyBF(image, size, type)) ; // type has been set directly in the function else if(isProbably3F(image, size)) type = "3F"; else /*if(isProbablySB(image, size))*/ type = "SB"; } else // what else can we do? { if(isProbably3E(image, size)) type = "3E"; else if(isProbably3F(image, size)) type = "3F"; else type = "4K"; // Most common bankswitching type } return type; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::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 Cartridge::isProbablySC(const uInt8* image, uInt32 size) { // We assume a Superchip cart contains the same bytes for its entire // RAM area; obviously this test will fail if it doesn't // The RAM area will be the first 256 bytes of each 4K bank uInt32 banks = size / 4096; for(uInt32 i = 0; i < banks; ++i) { uInt8 first = image[i*4096]; for(uInt32 j = 0; j < 256; ++j) { if(image[i*4096+j] != first) return false; } } return true; } bool Cartridge::isProbably4KSC(const uInt8* 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 Cartridge::isProbablyARM(const uInt8* 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, 1024, signature[0], 4, 1)) return true; else return searchForBytes(image, 1024, signature[1], 4, 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::isProbably0840(const uInt8* 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, 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, size, signature2[i], 4, 2)) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::isProbably3E(const uInt8* 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, size, signature, 4, 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::isProbably3F(const uInt8* 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, size, signature, 2, 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::isProbably4A50(const uInt8* 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 Cartridge::isProbablyCTY(const uInt8* image, uInt32 size) { return false; // TODO - add autodetection } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::isProbablyCV(const uInt8* 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, size, signature[0], 3, 1)) return true; else return searchForBytes(image, size, signature[1], 3, 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::isProbablyDPCplus(const uInt8* image, uInt32 size) { // DPC+ ARM code has 2 occurrences of the string DPC+ uInt8 signature[] = { 'D', 'P', 'C', '+' }; return searchForBytes(image, size, signature, 4, 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::isProbablyE0(const uInt8* 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, size, signature[i], 3, 1)) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::isProbablyE7(const uInt8* 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, size, signature[i], 3, 1)) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::isProbablyEF(const uInt8* image, uInt32 size, const char*& 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+size-8, 8, efef, 4, 1)) { type = "EF"; return true; } else if(searchForBytes(image+size-8, 8, efsc, 4, 1)) { type = "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, 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) ? "EFSC" : "EF"; return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::isProbablyBF(const uInt8* image, uInt32 size, const char*& 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+size-8, 8, bf, 4, 1)) { type = "BF"; return true; } else if(searchForBytes(image+size-8, 8, bfsc, 4, 1)) { type = "BFSC"; return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::isProbablyDF(const uInt8* image, uInt32 size, const char*& 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+size-8, 8, df, 4, 1)) { type = "DF"; return true; } else if(searchForBytes(image+size-8, 8, dfsc, 4, 1)) { type = "DFSC"; return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::isProbablyFA2(const uInt8* image, uInt32 size) { // 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 Cartridge::isProbablyFE(const uInt8* 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, size, signature[i], 5, 1)) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::isProbablySB(const uInt8* 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, size, signature[0], 3, 1)) return true; else return searchForBytes(image, size, signature[1], 3, 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::isProbablyUA(const uInt8* 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, size, signature[i], 3, 1)) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::isProbablyX07(const uInt8* 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, size, signature[i], 3, 1)) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge::Cartridge(const Cartridge& cart) : mySettings(cart.mySettings) { assert(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge& Cartridge::operator = (const Cartridge&) { assert(false); return *this; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Cartridge::myAboutString= ""; stella-3.9.3/src/emucore/CartX07.cxx0000644000175000001440000001311612266336753016560 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartX07.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "M6532.hxx" #include "TIA.hxx" #include "CartX07.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeX07::CartridgeX07(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(65536u, size)); createCodeAccessBase(65536); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeX07::~CartridgeX07() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeX07::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeX07::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mask) == 0); // 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(0, 0, 0, this, System::PA_READWRITE); for(uInt32 i = 0x00; i < 0x1000; i += (1 << shift)) mySystem->setPageAccess(i >> shift, 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; uInt16 shift = mySystem->pageShift(); // Setup the page access methods for the current bank System::PageAccess access(0, 0, 0, this, System::PA_READ); // Map ROM image into the system for(uInt32 address = 0x1000; address < 0x2000; address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeX07::bank() 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(int& 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-3.9.3/src/emucore/Cart4K.cxx0000644000175000001440000000744012266336753016463 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart4K.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "Cart4K.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge4K::Cartridge4K(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(4096u, size)); createCodeAccessBase(4096); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge4K::~Cartridge4K() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4K::reset() { myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4K::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mask) == 0); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Map ROM image into the system for(uInt32 address = 0x1000; address < 0x2000; address += (1 << shift)) { access.directPeekBase = &myImage[address & 0x0FFF]; access.codeAccessBase = &myCodeAccessBase[address & 0x0FFF]; mySystem->setPageAccess(address >> mySystem->pageShift(), access); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge4K::peek(uInt16 address) { return myImage[address & 0x0FFF]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge4K::poke(uInt16, uInt8) { // This is ROM so poking has no effect :-) return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge4K::bank(uInt16) { // Doesn't support bankswitching return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge4K::bank() const { // Doesn't support bankswitching return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge4K::bankCount() const { return 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge4K::patch(uInt16 address, uInt8 value) { myImage[address & 0x0FFF] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* Cartridge4K::getImage(int& 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-3.9.3/src/emucore/CartF4.hxx0000644000175000001440000001037612266336753016465 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF4.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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. @author Bradford W. Mott @version $Id: CartF4.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeF4(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 32K ROM image of the cartridge uInt8 myImage[32768]; }; #endif stella-3.9.3/src/emucore/Control.hxx0000644000175000001440000002072612266336753017022 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Control.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CONTROLLER_HXX #define CONTROLLER_HXX class Controller; class Event; class System; #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 @version $Id: Control.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 { BoosterGrip, Driving, Keyboard, Paddles, Joystick, TrackBall22, TrackBall80, AmigaMouse, AtariVox, SaveKey, KidVid, Genesis, MindLink, CompuMate }; 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 type The type for this controller @param system The system using this controller */ Controller(Jack jack, const Event& event, const System& system, Type type); /** Destructor */ virtual ~Controller(); /** 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 right before the system resets its cycle counter to zero. It may be necessary to override this method for controllers that remember cycle counts. */ virtual void systemCyclesReset() { }; /** 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 the name of this controller. */ virtual string name() const; /** Returns more detailed information about this controller. */ virtual string about() const; /** 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; /** 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); public: /// Constant which represents maximum resistance for analog pins static const Int32 maximumResistance; /// Constant which represents minimum resistance for analog pins static const Int32 minimumResistance; 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 analog value on each analog pin Int32 myAnalogPinValue[2]; protected: // Copy constructor isn't supported by controllers so make it private Controller(const Controller&); // Assignment operator isn't supported by controllers so make it private Controller& operator = (const Controller&); }; #endif stella-3.9.3/src/emucore/CartUA.hxx0000644000175000001440000001052312266336753016513 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartUA.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CARTRIDGEUA_HXX #define CARTRIDGEUA_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartUAWidget.hxx" #endif /** Cartridge class used for UA Limited's 8K bankswitched games. There are two 4K banks. @author Bradford W. Mott @version $Id: CartUA.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeUA(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 8K ROM image of the cartridge uInt8 myImage[8192]; // Previous Device's page access System::PageAccess myHotSpotPageAccess; }; #endif stella-3.9.3/src/emucore/CartF0.hxx0000644000175000001440000001054512266336753016457 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF0.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: CartF0.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeF0(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: /** Install pages for the next bank in the system */ void incbank(); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 64K ROM image of the cartridge uInt8 myImage[65536]; }; #endif stella-3.9.3/src/emucore/System.cxx0000644000175000001440000002325012266336753016654 0ustar stephenusers//============================================================================ // // 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-2014 by Bradford W. Mott, Stephen Anthony // and 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: System.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "Device.hxx" #include "M6502.hxx" #include "M6532.hxx" #include "TIA.hxx" #include "System.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - System::System(uInt16 n, uInt16 m) : myAddressMask((1 << n) - 1), myPageShift(m), myPageMask((1 << m) - 1), myNumberOfPages(1 << (n - m)), myNumberOfDevices(0), myM6502(0), myTIA(0), myCycles(0), myDataBusState(0), myDataBusLocked(false), mySystemInAutodetect(false) { // Make sure the arguments are reasonable assert((1 <= m) && (m <= n) && (n <= 16)); // Create a new random number generator myRandom = new Random(); // Allocate page table and dirty list myPageAccessTable = new PageAccess[myNumberOfPages]; myPageIsDirtyTable = new bool[myNumberOfPages]; // Initialize page access table PageAccess access; access.directPeekBase = 0; access.directPokeBase = 0; access.device = &myNullDevice; for(int page = 0; page < myNumberOfPages; ++page) { setPageAccess(page, access); myPageIsDirtyTable[page] = false; } // Bus starts out unlocked (in other words, peek() changes myDataBusState) myDataBusLocked = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - System::~System() { // Free the devices attached to me, since I own them for(uInt32 i = 0; i < myNumberOfDevices; ++i) { delete myDevices[i]; } // Free the M6502 that I own delete myM6502; // Free my page access table and dirty list delete[] myPageAccessTable; delete[] myPageIsDirtyTable; // Free the random number generator delete myRandom; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::reset(bool autodetect) { // Provide hint to devices that autodetection is active (or not) mySystemInAutodetect = autodetect; // Reset system cycle counter resetCycles(); // First we reset the devices attached to myself for(uInt32 i = 0; i < myNumberOfDevices; ++i) myDevices[i]->reset(); // Now we reset the processor if it exists if(myM6502 != 0) myM6502->reset(); // There are no dirty pages upon startup clearDirtyPages(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::attach(Device* device) { assert(myNumberOfDevices < 100); // Add device to my collection of devices myDevices[myNumberOfDevices++] = device; // Ask the device to install itself device->install(*this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::attach(M6502* m6502) { // Remember the processor myM6502 = m6502; // Ask the processor to install itself myM6502->install(*this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::attach(M6532* m6532) { // Remember the processor myM6532 = m6532; // Attach it as a normal device attach((Device*) m6532); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::attach(TIA* tia) { myTIA = tia; attach((Device*) tia); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::resetCycles() { // First we let all of the device attached to me know about the reset for(uInt32 i = 0; i < myNumberOfDevices; ++i) { myDevices[i]->systemCyclesReset(); } // Now, we reset cycle count to zero myCycles = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::setPageAccess(uInt16 page, const PageAccess& access) { // Make sure the page is within range assert(page < myNumberOfPages); // Make sure the access methods make sense assert(access.device != 0); myPageAccessTable[page] = access; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const System::PageAccess& System::getPageAccess(uInt16 page) const { // Make sure the page is within range assert(page < myNumberOfPages); return myPageAccessTable[page]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - System::PageAccessType System::getPageAccessType(uInt16 addr) const { return myPageAccessTable[(addr & myAddressMask) >> myPageShift].type; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::setDirtyPage(uInt16 addr) { myPageIsDirtyTable[(addr & myAddressMask) >> myPageShift] = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool System::isPageDirty(uInt16 start_addr, uInt16 end_addr) const { uInt16 start_page = (start_addr & myAddressMask) >> myPageShift; uInt16 end_page = (end_addr & myAddressMask) >> myPageShift; for(uInt16 page = start_page; page <= end_page; ++page) if(myPageIsDirtyTable[page]) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::clearDirtyPages() { for(uInt32 i = 0; i < myNumberOfPages; ++i) myPageIsDirtyTable[i] = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 System::peek(uInt16 addr, uInt8 flags) { PageAccess& access = myPageAccessTable[(addr & myAddressMask) >> myPageShift]; #ifdef DEBUGGER_SUPPORT // Set access type if(access.codeAccessBase) *(access.codeAccessBase + (addr & myPageMask)) |= 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 & myPageMask)); else result = access.device->peek(addr); #ifdef DEBUGGER_SUPPORT if(!myDataBusLocked) #endif myDataBusState = result; return result; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::poke(uInt16 addr, uInt8 value) { uInt16 page = (addr & myAddressMask) >> myPageShift; PageAccess& access = myPageAccessTable[page]; // 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 & myPageMask)) = 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) { #ifdef DEBUGGER_SUPPORT PageAccess& access = myPageAccessTable[(addr & myAddressMask) >> myPageShift]; if(access.codeAccessBase) return *(access.codeAccessBase + (addr & myPageMask)); else return access.device->getAccessFlags(addr); #else return 0; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::setAccessFlags(uInt16 addr, uInt8 flags) { #ifdef DEBUGGER_SUPPORT PageAccess& access = myPageAccessTable[(addr & myAddressMask) >> myPageShift]; if(access.codeAccessBase) *(access.codeAccessBase + (addr & myPageMask)) |= flags; else access.device->setAccessFlags(addr, flags); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::lockDataBus() { myDataBusLocked = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::unlockDataBus() { myDataBusLocked = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool System::save(Serializer& out) const { try { out.putString(name()); out.putInt(myCycles); out.putByte(myDataBusState); if(!myM6502->save(out)) return false; // Now save the state of each device for(uInt32 i = 0; i < myNumberOfDevices; ++i) if(!myDevices[i]->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.getInt(); myDataBusState = in.getByte(); // Next, load state for the CPU if(!myM6502->load(in)) return false; // Now load the state of each device for(uInt32 i = 0; i < myNumberOfDevices; ++i) if(!myDevices[i]->load(in)) return false; } catch(...) { cerr << "ERROR: System::load" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - System::System(const System& s) : myAddressMask(s.myAddressMask), myPageShift(s.myPageShift), myPageMask(s.myPageMask), myNumberOfPages(s.myNumberOfPages) { assert(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - System& System::operator = (const System&) { assert(false); return *this; } stella-3.9.3/src/emucore/CartCV.cxx0000644000175000001440000001430412266336753016512 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartCV.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartCV.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCV::CartridgeCV(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings), myInitialRAM(0), mySize(size) { if(mySize == 2048) { // Copy the ROM data into my buffer memcpy(myImage, image, 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 + 2048, 2048); // Copy the RAM image into a buffer for use in reset() myInitialRAM = new uInt8[1024]; memcpy(myInitialRAM, image, 1024); } createCodeAccessBase(2048+1024); // This cart contains 1024 bytes extended RAM @ 0x1000 registerRamArea(0x1000, 1024, 0x00, 0x400); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCV::~CartridgeCV() { delete[] myInitialRAM; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCV::reset() { if(myInitialRAM) { // Copy the RAM image into my buffer memcpy(myRAM, myInitialRAM, 1024); } else { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 1024; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 1024); } myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCV::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1800 & mask) == 0); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Map ROM image into the system for(uInt32 address = 0x1800; address < 0x2000; address += (1 << shift)) { access.directPeekBase = &myImage[address & 0x07FF]; access.codeAccessBase = &myCodeAccessBase[address & 0x07FF]; mySystem->setPageAccess(address >> mySystem->pageShift(), access); } // Set the page accessing method for the RAM writing pages access.directPeekBase = 0; access.codeAccessBase = 0; access.type = System::PA_WRITE; for(uInt32 j = 0x1400; j < 0x1800; j += (1 << shift)) { access.directPokeBase = &myRAM[j & 0x03FF]; mySystem->setPageAccess(j >> shift, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = 0; access.type = System::PA_READ; for(uInt32 k = 0x1000; k < 0x1400; k += (1 << shift)) { access.directPeekBase = &myRAM[k & 0x03FF]; access.codeAccessBase = &myCodeAccessBase[2048 + (k & 0x03FF)]; mySystem->setPageAccess(k >> shift, access); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCV::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]; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCV::poke(uInt16, uInt8) { // 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 CartridgeCV::bank(uInt16 bank) { // Doesn't support bankswitching return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeCV::bank() const { // Doesn't support bankswitching return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeCV::bankCount() const { return 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(int& 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-3.9.3/src/emucore/CartF8SC.hxx0000644000175000001440000001053012266336753016707 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF8SC.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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. @author Bradford W. Mott @version $Id: CartF8SC.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeF8SC(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 8K ROM image of the cartridge uInt8 myImage[8192]; // The 128 bytes of RAM uInt8 myRAM[128]; }; #endif stella-3.9.3/src/emucore/CartAR.hxx0000644000175000001440000001520312266336753016510 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartAR.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CARTRIDGEAR_HXX #define CARTRIDGEAR_HXX class M6502; class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartARWidget.hxx" #endif /** 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 @version $Id: CartAR.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeAR(); public: /** Reset device to its power-on state */ void reset(); /** Notification method invoked by the system right before the system resets its cycle counter to zero. It may be necessary to override this method for devices that remember cycle counts. */ void systemCyclesReset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: /** Query/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 */ uInt8 getAccessFlags(uInt16 address); void setAccessFlags(uInt16 address, uInt8 flags); // 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: // Pointer to the 6502 processor in the system M6502* my6502; // 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 uInt8* 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; // Indicates when the power was last turned on Int32 myPowerRomCycle; // 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; 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]; }; #endif stella-3.9.3/src/emucore/CartSB.cxx0000644000175000001440000001405012266336753016504 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartSB.cxx,v 1.0 2007/10/11 //============================================================================ #include #include #include "System.hxx" #include "CartSB.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeSB::CartridgeSB(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size) { // Allocate array for the ROM image myImage = new uInt8[mySize]; // Copy the ROM image into my buffer memcpy(myImage, image, mySize); createCodeAccessBase(mySize); // Remember startup bank myStartBank = bankCount() - 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeSB::~CartridgeSB() { delete[] myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeSB::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeSB::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mask) == 0); // 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 >> shift); myHotSpotPageAccess[1] = mySystem->getPageAccess(0x0900 >> shift); myHotSpotPageAccess[2] = mySystem->getPageAccess(0x0A00 >> shift); myHotSpotPageAccess[3] = mySystem->getPageAccess(0x0B00 >> shift); myHotSpotPageAccess[4] = mySystem->getPageAccess(0x0C00 >> shift); myHotSpotPageAccess[5] = mySystem->getPageAccess(0x0D00 >> shift); myHotSpotPageAccess[6] = mySystem->getPageAccess(0x0E00 >> shift); myHotSpotPageAccess[7] = mySystem->getPageAccess(0x0F00 >> shift); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = 0x0800; i < 0x0FFF; i += (1 << shift)) mySystem->setPageAccess(i >> shift, 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 myCurrentBank = bank; uInt32 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); // Setup the page access methods for the current bank System::PageAccess access(0, 0, 0, this, System::PA_READ); // Map ROM image into the system for(uInt32 address = 0x1000; address < 0x2000; address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeSB::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeSB::bankCount() const { return mySize >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeSB::patch(uInt16 address, uInt8 value) { myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeSB::getImage(int& size) const { size = mySize; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeSB::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); } catch(...) { cerr << "ERROR: CartridgeSB::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeSB::load(Serializer& in) { try { if(in.getString() != name()) return false; myCurrentBank = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeSB::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/CartMC.hxx0000644000175000001440000002105412266336753016506 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartMC.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CARTRIDGEMC_HXX #define CARTRIDGEMC_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartMCWidget.hxx" #endif /** This is the cartridge class for Chris Wilkson's Megacart. It does not handle battery-backed RAM at this time and the code could use some serious speed improvements. It is based on the following Megacart specification: Megacart Specification, Rev1.1 (c) 1997 Chris Wilkson cwilkson@mit.edu Description ----------- The Megacart is an external memory cartridge for the Atari 2600 and compatible home video game consoles. It plugs into the standard cartridge port, and contains a total of 128K bytes of ROM storage and 32K bytes of battery-backed RAM storage. General Operation ----------------- The Megacart uses "bank switching" to fit the 160K bytes of physical memory into the console's available 4K address space. Physical memory is divided into 64 RAM blocks of 512 bytes each, and 128 ROM blocks of 1K bytes each. RAM blocks are numbered $00 through $3F, and ROM blocks are numbered $80 through $FF. The console's address space is divided into 4 slots of 1K each. Any physical memory block can be switched into any memory slot by writing its block number to the "hot address" for the desired slot. Memory locations $3C through $3F serve as "hot addresses" for memory slots 0 through 3, respectively. Example: To make ROM addresses $1A400-$1A7FF (block $E9) available to the console at memory locations $F800-$FBFF (slot 2), write $E9 to memory location $3e. Caution: Note that these memory locations are write only. Trying to read the contents of memory locations $3C through $3F will not only return invalid data, but will also corrupt the contents causing the software to crash. Reading these addresses should not be attempted. Special Case - RAM ------------------- RAM blocks differ from ROM blocks in that one of the console's address lines, A9 in this case, must be used as a read/write select. Because of this, RAM blocks are limited to 512 bytes each, yet still occupy an entire 1K slot. To store a value A9 must be low. To retrieve a value A9 must high. Example: First, let's set slot 0 (console addresses $F000-$F3FF) to point to RAM block $9 (RAM $1200-$13ff). To do this, write $9 to console address $3c. To store the value $69 in RAM location $1234, write $69 to console address $F034 (A9=0). To retrieve the value of RAM location $1234, read from console address $F234 (A9=1). Special Case - Powerup ----------------------- Because the console's memory is randomized at powerup, there is no way to predict the data initially contained in the "hot addresses". Therefore, hardware will force slot 3 to always point to ROM block $FF immediately after any read or write to the RESET vector at $FFFC-$FFFD. Block $FF must contain code to initialize the 4 memory slots to point to the desired physical memory blocks before any other code can be executed. After program execution jumps out of the boot code, the hardware will release slot 3 and it will function just like any other slot. Example (the first column is the physical ROM address): $00C00 JUNK ... ; random code and data ... ... ... ... $1F400 START ... ; program starts here ... ; slot 3 now points to rom block $83 ... ... ... $1FFDD BOOT SEI ; disable interrupts $1FFDE CLD ; set hexadecimal arithmetic mode $1FFDF LDX #$FF ; $1FFE1 TXS ; set stack pointer to $ff $1FFE2 LDA #$00 $1FFE4 ZERO STA 00,X ; clear RIOT and TIA -BEFORE- setting $1FFE6 DEX ; up banks $1FFE7 BNE ZERO $1FFE9 BANKS LDA #$00 ; ram block 0 ($0000-$01ff) $1FFEB STA SLOT0 ; slot 0 points to ram block 0 $1FFED LDA #$34 ; ram block $34 ($6800-$69ff) $1FFEF STA SLOT1 ; slot 1 points to ram block $34 $1FFF1 LDA #$FD ; rom block $fd ($1f400-$1f7ff) $1FFF3 STA SLOT2 ; slot 2 points to rom block $fd $1FFF5 LDA #$83 ; rom block $83 ($00C00-$01000) $1FFF7 STA SLOT3 ; slot 3 points to bootcode ; (rom block $ff) ; until jumping out of slot 3 $1FFF9 JMP $F800 ; jump to slot 2 $1FFFC RESET .WORD $FFDD ; powerup reset vector $1FFFE SWI .WORD $FFDD ; software interrupt vector (BRK) @author Bradford W. Mott @version $Id: CartMC.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class CartridgeMC : public Cartridge { friend class CartridgeMCWidget; public: /** Create a new cartridge using the specified image and size. If the size of the image is less than 128K then the cartridge will pad the beginning of the 128K ROM with zeros. @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) */ CartridgeMC(const uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeMC(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { return "CartridgeMC"; } #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) { return new CartridgeMCWidget(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); /** 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); private: // The 128K ROM image for the cartridge uInt8 myImage[131072]; // The 32K of RAM for the cartridge uInt8 myRAM[32768]; // Indicates which block is currently active for the four segments uInt8 myCurrentBlock[4]; // Indicates if slot 3 is locked to block $FF or not bool mySlot3Locked; }; #endif stella-3.9.3/src/emucore/CartF4SC.hxx0000644000175000001440000001053512266336753016710 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF4SC.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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. @author Bradford W. Mott @version $Id: CartF4SC.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeF4SC(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 32K ROM image of the cartridge uInt8 myImage[32768]; // The 128 bytes of RAM uInt8 myRAM[128]; }; #endif stella-3.9.3/src/emucore/SaveKey.hxx0000644000175000001440000000532512266336753016747 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SaveKey.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: SaveKey.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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); /** Destructor */ virtual ~SaveKey(); 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); /** 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); /** Update the entire digital and analog pin state according to the events currently set. */ void update() { } /** Notification method invoked by the system right before the system resets its cycle counter to zero. It may be necessary to override this method for devices that remember cycle counts. */ void systemCyclesReset(); private: // The EEPROM used in the SaveKey MT24LC256* myEEPROM; }; #endif stella-3.9.3/src/emucore/Serializable.hxx0000644000175000001440000000345212266336753020005 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Serializable.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: Serializable.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class Serializable { public: Serializable() { } virtual ~Serializable() { } /** 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-3.9.3/src/emucore/M6502.cxx0000644000175000001440000003616012266336753016105 0ustar stephenusers//============================================================================ // // 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-2014 by Bradford W. Mott, Stephen Anthony // and 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: M6502.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ //#define DEBUG_OUTPUT #define debugStream cout #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #include "Expression.hxx" #include "CartDebug.hxx" #include "PackedBitArray.hxx" // Flags for disassembly types #define DISASM_CODE CartDebug::CODE #define DISASM_GFX CartDebug::GFX #define DISASM_PGFX CartDebug::PGFX #define DISASM_DATA CartDebug::DATA #define DISASM_ROW CartDebug::ROW #define DISASM_NONE 0 #else // Flags for disassembly types #define DISASM_CODE 0 #define DISASM_GFX 0 #define DISASM_PGFX 0 #define DISASM_DATA 0 #define DISASM_ROW 0 #define DISASM_NONE 0 #endif #include "Settings.hxx" #include "M6502.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - M6502::M6502(uInt32 systemCyclesPerProcessorCycle, const Settings& settings) : myExecutionStatus(0), mySystem(0), mySettings(settings), mySystemCyclesPerProcessorCycle(systemCyclesPerProcessorCycle), myLastAccessWasRead(true), myTotalInstructionCount(0), myNumberOfDistinctAccesses(0), myLastAddress(0), myLastPeekAddress(0), myLastPokeAddress(0), myLastSrcAddressS(-1), myLastSrcAddressA(-1), myLastSrcAddressX(-1), myLastSrcAddressY(-1), myDataAddressForPoke(0) { #ifdef DEBUGGER_SUPPORT myDebugger = NULL; myBreakPoints = NULL; myReadTraps = NULL; myWriteTraps = NULL; myJustHitTrapFlag = false; #endif // Compute the System Cycle table for(uInt32 t = 0; t < 256; ++t) { myInstructionSystemCycleTable[t] = ourInstructionCycleTable[t] * mySystemCyclesPerProcessorCycle; } #ifdef DEBUG_OUTPUT debugStream << "( Fm Ln Cyc Clk) ( P0 P1 M0 M1 BL) " << "flags A X Y SP Code Disasm" << endl << endl; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - M6502::~M6502() { #ifdef DEBUGGER_SUPPORT myBreakConds.clear(); myBreakCondNames.clear(); #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 default values SP = 0xff; if(mySettings.getBool("cpurandom")) { A = mySystem->randGenerator().next(); X = mySystem->randGenerator().next(); Y = mySystem->randGenerator().next(); PS(mySystem->randGenerator().next()); } else { A = X = Y = 0; PS(0x20); } // Reset access flag myLastAccessWasRead = true; // Load PC from the reset vector PC = (uInt16)mySystem->peek(0xfffc) | ((uInt16)mySystem->peek(0xfffd) << 8); myTotalInstructionCount = 0; myLastAddress = myLastPeekAddress = myLastPokeAddress = 0; myLastSrcAddressS = myLastSrcAddressA = myLastSrcAddressX = myLastSrcAddressY = -1; myDataAddressForPoke = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline uInt8 M6502::peek(uInt16 address, uInt8 flags) { //////////////////////////////////////////////// // TODO - move this logic directly into CartAR if(address != myLastAddress) { myNumberOfDistinctAccesses++; myLastAddress = address; } //////////////////////////////////////////////// mySystem->incrementCycles(mySystemCyclesPerProcessorCycle); #ifdef DEBUGGER_SUPPORT if(myReadTraps != NULL && myReadTraps->isSet(address)) { myJustHitTrapFlag = true; myHitTrapInfo.message = "RTrap: "; myHitTrapInfo.address = address; } //cerr << "addr = " << HEX4 << address << ", flags = " << Debugger::to_bin_8(flags) << endl; #endif uInt8 result = mySystem->peek(address, flags); myLastAccessWasRead = true; myLastPeekAddress = address; return result; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void M6502::poke(uInt16 address, uInt8 value) { //////////////////////////////////////////////// // TODO - move this logic directly into CartAR if(address != myLastAddress) { myNumberOfDistinctAccesses++; myLastAddress = address; } //////////////////////////////////////////////// mySystem->incrementCycles(mySystemCyclesPerProcessorCycle); #ifdef DEBUGGER_SUPPORT if(myWriteTraps != NULL && myWriteTraps->isSet(address)) { myJustHitTrapFlag = true; myHitTrapInfo.message = "WTrap: "; myHitTrapInfo.address = address; } #endif mySystem->poke(address, value); myLastAccessWasRead = false; myLastPokeAddress = address; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool M6502::execute(uInt32 number) { // Clear all of the execution status bits except for the fatal error bit myExecutionStatus &= FatalErrorBit; // Loop until execution is stopped or a fatal error occurs for(;;) { for(; !myExecutionStatus && (number != 0); --number) { #ifdef DEBUGGER_SUPPORT if(myJustHitTrapFlag) { if(myDebugger && myDebugger->start(myHitTrapInfo.message, myHitTrapInfo.address)) { myJustHitTrapFlag = false; return true; } } if(myBreakPoints != NULL) { if(myBreakPoints->isSet(PC)) { if(myDebugger && myDebugger->start("BP: ", PC)) return true; } } int cond = evalCondBreaks(); if(cond > -1) { string buf = "CBP: " + myBreakCondNames[cond]; if(myDebugger && myDebugger->start(buf)) return true; } #endif uInt16 operandAddress = 0, intermediateAddress = 0; uInt8 operand = 0; // Reset the peek/poke address pointers myLastPeekAddress = myLastPokeAddress = myDataAddressForPoke = 0; // Fetch instruction at the program counter IR = peek(PC++, DISASM_CODE); // This address represents a code section #ifdef DEBUG_OUTPUT debugStream << ::hex << setw(2) << (int)A << " " << ::hex << setw(2) << (int)X << " " << ::hex << setw(2) << (int)Y << " " << ::hex << setw(2) << (int)SP << " " << setw(4) << (PC-1) << ": " << setw(2) << (int)IR << " " // << "<" << ourAddressingModeTable[IR] << " "; // debugStream << hex << setw(4) << operandAddress << " "; // << setw(3) << ourInstructionMnemonicTable[IR] // debugStream << "PS=" << ::hex << setw(2) << (int)PS() << " "; // debugStream << "Cyc=" << dec << mySystem->cycles(); << endl; #endif // 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; } myTotalInstructionCount++; } // 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 * mySystemCyclesPerProcessorCycle); 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 * mySystemCyclesPerProcessorCycle); 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); } 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(); } catch(...) { cerr << "ERROR: M6502::laod" << 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) { myBreakConds.push_back(e); myBreakCondNames.push_back(name); return myBreakConds.size() - 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6502::delCondBreak(uInt32 brk) { if(brk < myBreakConds.size()) { delete myBreakConds[brk]; myBreakConds.remove_at(brk); myBreakCondNames.remove_at(brk); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6502::clearCondBreaks() { for(uInt32 i = 0; i < myBreakConds.size(); i++) delete myBreakConds[i]; myBreakConds.clear(); myBreakCondNames.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const StringList& M6502::getCondBreakNames() const { return myBreakCondNames; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Int32 M6502::evalCondBreaks() { for(uInt32 i = 0; i < myBreakConds.size(); i++) if(myBreakConds[i]->evaluate()) return i; return -1; // no break hit } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6502::setBreakPoints(PackedBitArray *bp) { myBreakPoints = bp; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6502::setTraps(PackedBitArray *read, PackedBitArray *write) { myReadTraps = read; myWriteTraps = write; } #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 M6502::ourInstructionCycleTable[256] = { // 0 1 2 3 4 5 6 7 8 9 a b c d e f 7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, // 0 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, // 1 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, // 2 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, // 3 6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6, // 4 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, // 5 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6, // 6 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, // 7 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, // 8 2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5, // 9 2, 6, 2, 6, 3, 3, 3, 4, 2, 2, 2, 2, 4, 4, 4, 4, // a 2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4, // b 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, // c 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, // d 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, // e 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7 // f }; stella-3.9.3/src/emucore/CartCTY.cxx0000644000175000001440000003565012266336753016650 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartCTY.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "OSystem.hxx" #include "Serializer.hxx" #include "System.hxx" #include "CartCTYTunes.hxx" #include "CartCTY.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCTY::CartridgeCTY(const uInt8* image, uInt32 size, const OSystem& osystem) : Cartridge(osystem.settings()), myOSystem(osystem), myOperationType(0), myCounter(0), myLDAimmediate(false), myRandomNumber(0x2B435044), myRamAccessTimeout(0), mySystemCycles(0), myFractionalClocks(0.0) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(32768u, size)); createCodeAccessBase(32768); // This cart contains 64 bytes extended RAM @ 0x1000 registerRamArea(0x1000, 64, 0x40, 0x00); // Point to the first tune myFrequencyImage = CartCTYTunes; // Remember startup bank (not bank 0, since that's ARM code) myStartBank = 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCTY::~CartridgeCTY() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTY::reset() { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 64; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 64); myRAM[0] = myRAM[1] = myRAM[2] = myRAM[3] = 0xFF; // Update cycles to the current system cycles mySystemCycles = mySystem->cycles(); myFractionalClocks = 0.0; // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTY::systemCyclesReset() { // Adjust the cycle counter so that it reflects the new value mySystemCycles -= mySystem->cycles(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTY::install(System& system) { mySystem = &system; uInt16 mask = mySystem->pageMask(); uInt16 shift = mySystem->pageShift(); // Make sure the system we're being installed in has a page size that'll work assert(((0x1000 & mask) == 0) && ((0x1080 & mask) == 0)); // Map all RAM accesses to call peek and poke System::PageAccess access(0, 0, 0, this, System::PA_READ); for(uInt32 i = 0x1000; i < 0x1080; i += (1 << shift)) mySystem->setPageAccess(i >> shift, access); // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCTY::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; uInt8 peekValue = myImage[myCurrentBank + 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 myCurrentBank = bank << 12; uInt16 shift = mySystem->pageShift(); // Setup the page access methods for the current bank System::PageAccess access(0, 0, 0, this, System::PA_READ); for(uInt32 address = 0x1080; address < 0x2000; address += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[myCurrentBank + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeCTY::bank() const { return myCurrentBank >> 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[myCurrentBank + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeCTY::getImage(int& size) const { size = 32768; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCTY::save(Serializer& out) const { try { out.putString(name()); out.putShort(bank()); out.putByteArray(myRAM, 64); out.putByte(myOperationType); out.putShort(myCounter); out.putBool(myLDAimmediate); out.putInt(myRandomNumber); out.putInt(mySystemCycles); out.putInt((uInt32)(myFractionalClocks * 100000000.0)); } 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(); mySystemCycles = (Int32)in.getInt(); myFractionalClocks = (double)in.getInt() / 100000000.0; } 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[myCurrentBank + 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[myCurrentBank + 0xFF4] & ~0x40; } else // Bit 6 is 1, busy return myImage[myCurrentBank + 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.isValid()) { 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.isValid()) { // 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.reset(); 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.isValid()) { // 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 Int32 cycles = mySystem->cycles() - mySystemCycles; mySystemCycles = mySystem->cycles(); // Calculate the number of DPC OSC clocks since the last update double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks; Int32 wholeClocks = (Int32)clocks; myFractionalClocks = clocks - (double)wholeClocks; if(wholeClocks <= 0) return; // Let's update counters and flags of the music mode data fetchers for(int x = 0; x <= 2; ++x) { // myMusicCounters[x] += myMusicFrequencies[x]; } } stella-3.9.3/src/emucore/Serializer.cxx0000644000175000001440000001421112266336753017476 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Serializer.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "FSNode.hxx" #include "Serializer.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Serializer::Serializer(const string& filename, bool readonly) : myStream(NULL), myUseFilestream(true) { if(readonly) { FilesystemNode node(filename); if(node.isFile() && node.isReadable()) { fstream* str = new fstream(filename.c_str(), ios::in | ios::binary); if(str && str->is_open()) { myStream = str; myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit ); reset(); } else delete str; } } 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.c_str(), ios::out | ios::app); temp.close(); fstream* str = new fstream(filename.c_str(), ios::in | ios::out | ios::binary); if(str && str->is_open()) { myStream = str; myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit ); reset(); } else delete str; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Serializer::Serializer(void) : myStream(NULL), myUseFilestream(false) { myStream = new stringstream(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); reset(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Serializer::~Serializer(void) { if(myStream != NULL) { if(myUseFilestream) ((fstream*)myStream)->close(); delete myStream; myStream = NULL; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Serializer::isValid(void) { return myStream != NULL; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::reset(void) { myStream->clear(); myStream->seekg(ios_base::beg); myStream->seekp(ios_base::beg); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Serializer::getByte(void) { char buf; myStream->read(&buf, 1); return buf; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::getByteArray(uInt8* array, uInt32 size) { myStream->read((char*)array, size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Serializer::getShort(void) { uInt16 val = 0; myStream->read((char*)&val, sizeof(uInt16)); return val; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::getShortArray(uInt16* array, uInt32 size) { myStream->read((char*)array, sizeof(uInt16)*size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Serializer::getInt(void) { uInt32 val = 0; myStream->read((char*)&val, sizeof(uInt32)); return val; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::getIntArray(uInt32* array, uInt32 size) { myStream->read((char*)array, sizeof(uInt32)*size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Serializer::getString(void) { int len = getInt(); string str; str.resize(len); myStream->read(&str[0], len); return str; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Serializer::getBool(void) { return getByte() == TruePattern; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putByte(uInt8 value) { myStream->write((char*)&value, 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putByteArray(const uInt8* array, uInt32 size) { myStream->write((char*)array, size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putShort(uInt16 value) { myStream->write((char*)&value, sizeof(uInt16)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putShortArray(const uInt16* array, uInt32 size) { myStream->write((char*)array, sizeof(uInt16)*size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putInt(uInt32 value) { myStream->write((char*)&value, sizeof(uInt32)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putIntArray(const uInt32* array, uInt32 size) { myStream->write((char*)array, sizeof(uInt32)*size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putString(const string& str) { int len = str.length(); putInt(len); myStream->write(str.data(), len); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putBool(bool b) { putByte(b ? TruePattern: FalsePattern); } stella-3.9.3/src/emucore/Keyboard.hxx0000644000175000001440000000444412266336753017141 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Keyboard.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: Keyboard.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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); /** Destructor */ virtual ~Keyboard(); 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); /** Update the entire digital and analog pin state according to the events currently set. */ void update() { } 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; }; #endif stella-3.9.3/src/emucore/TrackBall.hxx0000644000175000001440000000776712266336753017253 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TrackBall.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef TRACKBALL_HXX #define TRACKBALL_HXX #include "bspf.hxx" #include "Control.hxx" #include "Event.hxx" /** The various trackball-like controllers supported by the Atari 2600. They're all placed in one class, since other than a few minor differences, they work almost exactly the same. This code was heavily borrowed from z26. The supported controllers include: TrackBall22: Atari 2600 CX-22 Trakball TrackBall80: Atari ST CX-80 Trakball AmigaMouse: Amiga Mouse @author Stephen Anthony & z26 team @version $Id: TrackBall.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class TrackBall : public Controller { public: /** Create a new TrackBall 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 of trackball controller */ TrackBall(Jack jack, const Event& event, const System& system, Type type); /** Destructor */ virtual ~TrackBall(); 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(); /** Update the entire digital and analog pin state according to the events currently set. */ void update(); /** 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); private: // Counter to iterate through the gray codes int myHCounter, myVCounter; // How many new horizontal and vertical values this frame int myTrakBallCountH, myTrakBallCountV; // How many lines to wait before sending new horz and vert val int myTrakBallLinesH, myTrakBallLinesV; // Was TrakBall moved left or moved right instead int myTrakBallLeft; // Was TrakBall moved down or moved up instead int myTrakBallDown; int myScanCountH, myScanCountV, myCountH, myCountV; // Whether to use the mouse to emulate this controller int myMouseEnabled; // CX-22 static const uInt32 ourTrakBallTableTB_H[2][2]; static const uInt32 ourTrakBallTableTB_V[2][2]; // ST mouse / CX-80 static const uInt32 ourTrakBallTableST_H[4]; static const uInt32 ourTrakBallTableST_V[4]; // Amiga mouse static const uInt32 ourTrakBallTableAM_H[4]; static const uInt32 ourTrakBallTableAM_V[4]; }; #endif stella-3.9.3/src/emucore/CompuMate.cxx0000644000175000001440000002243312266336753017264 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CompuMate.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Control.hxx" #include "System.hxx" #include "StellaKeys.hxx" #include "CompuMate.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CompuMate::CompuMate(CartridgeCM& cart, const Event& event, const System& system) : myCart(cart), myEvent(event), mySystem(system), myLeftController(0), myRightController(0), myCycleAtLastUpdate(0) { myLeftController = new CMControl(*this, Controller::Left, event, system); myRightController = new CMControl(*this, Controller::Right, event, system); myLeftController->myAnalogPinValue[Controller::Nine] = Controller::maximumResistance; myLeftController->myAnalogPinValue[Controller::Five] = Controller::minimumResistance; myRightController->myAnalogPinValue[Controller::Nine] = Controller::minimumResistance; myRightController->myAnalogPinValue[Controller::Five] = Controller::maximumResistance; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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() { uInt32 cycle = mySystem.cycles(); // Only perform update once for both ports in the same cycle if(myCycleAtLastUpdate != cycle) { myCycleAtLastUpdate = cycle; return; } myCycleAtLastUpdate = cycle; // Handle SWCHA changes - the following comes almost directly from z26 Controller& lp = *myLeftController; Controller& rp = *myRightController; 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(myCart.column()) { 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_QUOTE] && (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; } } stella-3.9.3/src/emucore/CartE7.hxx0000644000175000001440000001347212266336753016467 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartE7.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CARTRIDGEE7_HXX #define CARTRIDGEE7_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartE7Widget.hxx" #endif /** This is the 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. @author Bradford W. Mott @version $Id: CartE7.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class CartridgeE7 : public Cartridge { friend class CartridgeE7Widget; 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeE7(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { return new CartridgeE7Widget(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); /** 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); private: /** 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); private: // Indicates which slice is in the segment uInt16 myCurrentSlice[2]; // Indicates which 256 byte bank of RAM is being used uInt16 myCurrentRAM; // The 16K ROM image of the cartridge uInt8 myImage[16384]; // The 2048 bytes of RAM uInt8 myRAM[2048]; }; #endif stella-3.9.3/src/emucore/FrameBuffer.hxx0000644000175000001440000006305012266336753017563 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FrameBuffer.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef FRAMEBUFFER_HXX #define FRAMEBUFFER_HXX #include #include class FBSurface; class OSystem; class Console; class Settings; namespace GUI { class Font; struct Rect; } #include "EventHandler.hxx" #include "Rect.hxx" #include "StringList.hxx" #include "NTSCFilter.hxx" #include "Variant.hxx" #include "bspf.hxx" // Different types of framebuffer derived objects enum BufferType { kSoftBuffer, kDoubleBuffer }; // Return values for initialization of framebuffer window enum FBInitStatus { kSuccess, kFailComplete, kFailTooLarge, kFailNotSupported, }; // Positions for onscreen/overlaid messages enum MessagePosition { kTopLeft, kTopCenter, kTopRight, kMiddleLeft, kMiddleCenter, kMiddleRight, kBottomLeft, kBottomCenter, kBottomRight }; // Colors indices to use for the various GUI elements enum { kColor = 256, kBGColor, kShadowColor, kTextColor, kTextColorHi, kTextColorEm, kDlgColor, kWidColor, kWidFrameColor, kBtnColor, kBtnColorHi, kBtnTextColor, kBtnTextColorHi, kCheckColor, kScrollColor, kScrollColorHi, kSliderColor, kSliderColorHi, kDbgChangedColor, kDbgChangedTextColor, kDbgColorHi, kNumColors }; /** 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 @version $Id: FrameBuffer.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class FrameBuffer { public: /** Creates a new Frame Buffer */ FrameBuffer(OSystem* osystem); /** Destructor */ virtual ~FrameBuffer(); /** (Re)initializes the framebuffer display. This must be called before any calls are made to derived methods. @param title The title of the window @param width The width of the framebuffer @param height The height of the framebuffer @return Status of initialization (see FBInitStatus 'enum') */ FBInitStatus initialize(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 = kBottomCenter, 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); /** Allocate a new surface with a unique ID. 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 useBase Use the base surface instead of creating a new one @return A unique ID used to identify this surface */ uInt32 allocateSurface(int w, int h, bool useBase = false); /** Retrieve the surface associated with the given ID. @param id The ID for the surface to retrieve. @return A pointer to a valid surface object, or NULL. */ FBSurface* surface(uInt32 id) const; /** 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::Rect& screenRect() const { return myScreenRect; } /** Refresh display according to the current state, taking single vs. double-buffered modes into account, and redrawing accordingly. */ void refresh(); /** Toggles between fullscreen and window mode. Grabmouse activated when in fullscreen mode. */ void toggleFullscreen(); /** Enables/disables fullscreen mode. Grabmouse activated when in fullscreen mode. @param enable Set the fullscreen mode to this value */ void setFullscreen(bool enable); /** This method is called when the user wants to switch to the next available video mode (functionality depends on fullscreen or windowed mode). direction = -1 means go to the next lower video mode direction = 0 means to reload the current video mode direction = +1 means go to the next higher video mode @param direction Described above */ bool changeVidMode(int direction); /** Sets the state of the cursor (hidden or grabbed) based on the current mode. */ void setCursorState(); /** Toggles the use of grabmouse (only has effect in emulation mode). The method changes the 'grabmouse' setting and saves it. */ void toggleGrabMouse(); /** Shows or hides the cursor based on the given boolean value. */ virtual void showCursor(bool show); /** Answers if the display is currently in fullscreen mode. */ bool fullScreen() const; /** Set the title for the main SDL window. */ void setWindowTitle(const string& title); /** Get the supported TIA filters for the given framebuffer type. */ const VariantList& supportedTIAFilters(const string& type); /** Get the TIA pixel associated with the given TIA buffer index, shifting by the given offset (for greyscale values). */ uInt32 tiaPixel(uInt32 idx, uInt8 shift = 0) const; /** Set up the TIA/emulation palette for a screen of any depth > 8. @param palette The array of colors */ virtual void setTIAPalette(const uInt32* palette); /** Set up the user interface palette for a screen of any depth > 8. @param palette The array of colors */ virtual void setUIPalette(const uInt32* palette); /** Informs the Framebuffer of a change in EventHandler state. */ void stateChanged(EventHandler::State state); /** 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(); /** 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 */ uInt8 getPhosphor(uInt8 c1, uInt8 c2) const; ////////////////////////////////////////////////////////////////////// // The following methods are system-specific and *may* be implemented // in derived classes. ////////////////////////////////////////////////////////////////////// public: /** Enable/disable NTSC filtering effects. */ virtual void enableNTSC(bool enable) { } virtual bool ntscEnabled() const { return false; } /** This method is called to query the TV effects in use by the FrameBuffer. */ virtual string effectsInfo() const { return "None / not available"; } private: /** Change scanline intensity and interpolation. @param relative If non-zero, change current intensity by 'relative' amount, otherwise set to 'absolute' @return New current intensity */ virtual uInt32 enableScanlines(int relative, int absolute = 50) { return absolute; } virtual void enableScanlineInterpolation(bool enable) { } ////////////////////////////////////////////////////////////////////// // The following methods are system-specific and *must* be implemented // in derived classes. ////////////////////////////////////////////////////////////////////// public: /** Enable/disable phosphor effect. */ virtual void enablePhosphor(bool enable, int blend) = 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 query the type of the FrameBuffer. */ virtual BufferType type() const = 0; /** This method is called to get the specified scanline 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 row The row we are looking for @param data The actual pixel data (in bytes) */ virtual void scanline(uInt32 row, uInt8* data) const = 0; protected: // Different types of graphic filters to apply to the TIA image enum GfxID { GFX_Zoom1x, GFX_Zoom2x, GFX_Zoom3x, GFX_Zoom4x, GFX_Zoom5x, GFX_Zoom6x, GFX_Zoom7x, GFX_Zoom8x, GFX_Zoom9x, GFX_Zoom10x, GFX_NumModes }; struct GraphicsMode { GfxID type; const char* name; const char* description; uInt32 zoom; uInt8 avail; // 0x1 bit -> software, 0x2 bit -> opengl }; // Contains all relevant info for the dimensions of an SDL screen // Also takes care of the case when the SDL image should be 'centered' // within the given screen // image_XXX are the image offsets into the SDL screen // screen_XXX are the dimensions of the SDL screen itself // Also contains relevant info for the graphics mode/filter to use // when rendering the image struct VideoMode { uInt32 image_x, image_y, image_w, image_h; uInt32 screen_w, screen_h; GraphicsMode gfxmode; friend ostream& operator<<(ostream& os, const VideoMode& vm) { os << "image_x=" << vm.image_x << " image_y=" << vm.image_y << " image_w=" << vm.image_w << " image_h=" << vm.image_h << endl << "screen_w=" << vm.screen_w << " screen_h=" << vm.screen_h; return os; } }; /** This method is called to initialize the video subsystem with the given video mode. Normally, it will also call setVidMode(). @param mode The video mode to use @return False on any errors, else true */ virtual bool initSubsystem(VideoMode& mode) = 0; /** This method is called to change to the given video mode. If the mode is successfully changed, 'mode' holds the actual dimensions used. @param mode The video mode to use @return False on any errors (in which case 'mode' is invalid), else true */ virtual bool setVidMode(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 compatible with the one currently in use, but having the given dimensions. @param w The requested width of the new surface. @param h The requested height of the new surface. @param useBase Use the base surface instead of creating a new one */ virtual FBSurface* createSurface(int w, int h, bool useBase = false) const = 0; /** This method should be called anytime the TIA needs to be redrawn to the screen (full indicating that a full redraw is required). */ virtual void drawTIA(bool full) = 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; /** Issues a 'free' and 'reload' instruction to all surfaces that the framebuffer knows about. */ void resetSurfaces(FBSurface* tiasurface = (FBSurface*)0); protected: // The parent system for the framebuffer OSystem* myOSystem; // The SDL video buffer SDL_Surface* myScreen; // SDL initialization flags // This is set by the base FrameBuffer class, and read by the derived classes // If a FrameBuffer is successfully created, the derived classes must modify // it to point to the actual flags used by the SDL_Surface uInt32 mySDLFlags; // Indicates if the entire frame need to redrawn bool myRedrawEntireFrame; // NTSC object to use in TIA rendering mode NTSCFilter myNTSCFilter; // Use phosphor effect (aka no flicker on 30Hz screens) bool myUsePhosphor; // Amount to blend when using phosphor effect int myPhosphorBlend; // TIA palettes for normal and phosphor modes // 'myDefPalette' also contains the UI palette // The '24' version of myDefPalette is used in 24-bit colour mode, // eliminating having to deal with endian and shift issues // Phosphor mode doesn't have a corresponding '24' mode, since it // would require a 192KB lookup table Uint32 myDefPalette[256+kNumColors]; Uint32 myAvgPalette[256][256]; Uint8 myDefPalette24[256+kNumColors][3]; // Names of the TIA filters that can be used for this framebuffer VariantList myTIAFilters; private: /** Grabs or ungrabs the mouse based on the given boolean value. */ void grabMouse(bool grab); /** Set the icon for the main SDL window. */ void setWindowIcon(); /** Draw pending messages. */ void drawMessage(); /** 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); /** 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); /** Adds the given video mode to both windowed and fullscreen lists. In the case of fullscreen, we make sure a valid resolution exists. */ void addVidMode(VideoMode& mode); /** Returns an appropriate video mode based on the current eventhandler state, taking into account the maximum size of the window. @return A valid VideoMode for this framebuffer */ VideoMode getSavedVidMode(); /** Attempt to center the application window in windowed mode. */ void centerAppWindow(const VideoMode& mode); private: /** This class implements an iterator around an array of VideoMode objects. */ class VideoModeList { public: VideoModeList(); ~VideoModeList(); void add(VideoMode mode); void clear(); bool isEmpty() const; uInt32 size() const; void previous(); const FrameBuffer::VideoMode current(const Settings& settings, bool isFullscreen) const; void next(); void setByGfxMode(GfxID id); void setByGfxMode(const string& name); void print(); static void print(const VideoMode& mode); private: void set(const GraphicsMode& gfxmode); private: Common::Array myModeList; int myIdx; }; private: // Indicates the number of times the framebuffer was initialized uInt32 myInitializedCount; // Used to set intervals between messages while in pause mode uInt32 myPausedCount; // Dimensions of the actual image, after zooming, and taking into account // any image 'centering' GUI::Rect myImageRect; // Dimensions of the SDL window (not always the same as the image) GUI::Rect myScreenRect; // 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; FBSurface* surface; bool enabled; }; Message myMsg; Message myStatsMsg; // The list of all available video modes for this framebuffer VideoModeList myWindowedModeList; VideoModeList myFullscreenModeList; VideoModeList* myCurrentModeList; // Holds a reference to all the surfaces that have been created map mySurfaceList; // Holds static strings for the remap menu (emulation and menu events) static GraphicsMode ourGraphicsModes[GFX_NumModes]; }; /** This class is basically a thin wrapper around an SDL_Surface structure. We do it this way so the SDL stuff 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 @version $Id: FrameBuffer.hxx 2838 2014-01-17 23:34:03Z stephena $ */ // Text alignment modes for drawString() enum TextAlignment { kTextAlignLeft, kTextAlignCenter, kTextAlignRight }; // Line types for drawing rectangular frames enum FrameStyle { kSolidLine, kDashLine }; class FBSurface { public: /** Creates a new FBSurface object */ FBSurface() { } /** Destructor */ virtual ~FBSurface() { } /** 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 */ 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) { } /** 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 character @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 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 row The row of the surface the data should be placed in @param rowbytes The number of bytes in row of 'data' */ virtual void drawPixels(uInt32* data, uInt32 x, uInt32 y, uInt32 numpixels) { } /** This method should be called copy the contents of the given surface into the FrameBuffer surface. @param surface The data to draw @param x The x coordinate @param y The y coordinate */ virtual void drawSurface(const FBSurface* surface, uInt32 x, uInt32 y) { } /** This method should be called to add a dirty rectangle (ie, an area of the screen that has changed) @param x The x coordinate @param y The y coordinate @param w The width of the area @param h The height of the area */ virtual void addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) { } /** This method answers the current position of the surface. */ virtual void getPos(uInt32& x, uInt32& y) const { } /** This method should be called to set the position of the surface. */ virtual void setPos(uInt32 x, uInt32 y) { } /** This method answers the current dimensions of the surface. */ virtual uInt32 getWidth() const { return 0; } virtual uInt32 getHeight() const { return 0; } /** This method sets the width of the drawable area of the surface. */ virtual void setWidth(uInt32 w) { } /** This method sets the width of the drawable area of the surface. */ virtual void setHeight(uInt32 h) { } /** This method should be called to translate the given coordinates to the surface coordinates. @param x X coordinate to translate @param y Y coordinate to translate */ virtual void translateCoords(Int32& x, Int32& y) const { } /** This method should be called to draw the surface to the screen. */ virtual void update() { } /** This method should be called to reset the surface to empty pixels / colour black. */ virtual void invalidate() { } /** This method should be called to free any resources being used by the surface. */ virtual void free() { } /** This method should be called to reload the surface data/state. It will normally be called after free(). */ virtual void reload() { } /** 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. I'm not exactly sure what it is, so I can't explain it :) @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 */ virtual void frameRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color, FrameStyle style = kSolidLine); /** This method should be called to draw the specified string. @param font The font to draw the string with @param str The string to draw @param x The x coordinate @param y The y coordinate @param w The width of the string area @param h The height 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 @param useEllipsis Whether to use '...' when the string is too long */ virtual void drawString( const GUI::Font& font, const string& str, int x, int y, int w, uInt32 color, TextAlignment align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true); }; #endif stella-3.9.3/src/emucore/CartFA2.hxx0000644000175000001440000001372212266336753016562 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartFA2.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 and 256 bytes of RAM. The 256 bytes of RAM can be loaded/saved to Harmony cart flash, which is emulated by storing in a file. 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. @author Chris D. Walton @version $Id: CartFA2.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const OSystem& osystem); /** Destructor */ virtual ~CartridgeFA2(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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); #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) { 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); /** 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); 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; // Indicates which bank is currently active uInt16 myCurrentBank; // The 24K/28K ROM image of the cartridge uInt8* myImage; // 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; // Size of the ROM image uInt32 mySize; }; #endif stella-3.9.3/src/emucore/Event.hxx0000644000175000001440000001007012266336753016452 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Event.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef EVENT_HXX #define EVENT_HXX #include "bspf.hxx" #include "StellaKeys.hxx" /** @author Bradford W. Mott @version $Id: Event.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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, 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, MenuMode, CmdMenuMode, 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]; }; #endif stella-3.9.3/src/emucore/Random.hxx0000644000175000001440000000366212266336753016622 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Random.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef RANDOM_HXX #define RANDOM_HXX class OSystem; #include "bspf.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 @version $Id: Random.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class Random { public: /** Create a new random number generator */ Random(); public: /** Re-initialize the random number generator with a new seed, to generate a different set of random numbers. */ void initSeed(); /** Answer the next random number from the random number generator @return A random number */ uInt32 next(); /** Class method which sets the OSystem in use; the constructor will use this to reseed the random number generator every time a new instance is created @param system The system currently in use */ static void setSystem(const OSystem* system) { ourSystem = system; } private: // Indicates the next random number uInt32 myValue; // Set the OSystem we're using static const OSystem* ourSystem; }; #endif stella-3.9.3/src/emucore/CartDPCPlus.cxx0000644000175000001440000005172512266336753017464 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDPCPlus.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #endif #include "System.hxx" #include "Thumbulator.hxx" #include "CartDPCPlus.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings), myFastFetch(false), myLDAimmediate(false), myParameterPointer(0), mySystemCycles(0), myFractionalClocks(0.0) { // Store image, making sure it's at least 29KB uInt32 minsize = 4096 * 6 + 4096 + 1024 + 255; mySize = BSPF_max(minsize, size); myImage = new uInt8[mySize]; memcpy(myImage, image, size); createCodeAccessBase(4096 * 6); // Pointer to the program ROM (24K @ 0 byte offset) myProgramImage = myImage; // Pointer to the display RAM myDisplayImage = myDPCRAM + 0xC00; // Pointer to the Frequency RAM myFrequencyImage = myDisplayImage + 0x1000; // If the image is larger than 29K, we assume any excess at the // beginning is ARM code, and skip over it if(size > 29 * 1024) myProgramImage += (size - 29 * 1024); #ifdef THUMB_SUPPORT // Create Thumbulator ARM emulator myThumbEmulator = new Thumbulator((uInt16*)(myProgramImage-0xC00), (uInt16*)myDPCRAM, settings.getBool("thumb.trapfatal")); #endif setInitialState(); // DPC+ always starts in bank 5 myStartBank = 5; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDPCPlus::~CartridgeDPCPlus() { delete[] myImage; #ifdef THUMB_SUPPORT delete myThumbEmulator; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCPlus::reset() { // Update cycles to the current system cycles mySystemCycles = mySystem->cycles(); 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::systemCyclesReset() { // Get the current system cycle uInt32 cycles = mySystem->cycles(); // Adjust the cycle counter so that it reflects the new value mySystemCycles -= cycles; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCPlus::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert(((0x1080 & mask) == 0) && ((0x1100 & mask) == 0)); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Map all of the accesses to call peek and poke for(uInt32 i = 0x1000; i < 0x1080; i += (1 << shift)) mySystem->setPageAccess(i >> shift, 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 & (1<<31)) ? ((0x10adab1e^myRandomNumber) << 11) | ((0x10adab1e^myRandomNumber) >> 21) : (myRandomNumber << 11) | (myRandomNumber >> 21)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void CartridgeDPCPlus::updateMusicModeDataFetchers() { // Calculate the number of cycles since the last update Int32 cycles = mySystem->cycles() - mySystemCycles; mySystemCycles = mySystem->cycles(); // Calculate the number of DPC OSC clocks since the last update double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks; Int32 wholeClocks = (Int32)clocks; myFractionalClocks = clocks - (double)wholeClocks; if(wholeClocks <= 0) { return; } // Let's update counters and flags of the music mode data fetchers for(int x = 0; x <= 2; ++x) { myMusicCounters[x] += myMusicFrequencies[x]; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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; #ifdef THUMB_SUPPORT case 254: case 255: // Call user written ARM code (most likely be C compiled for ARM) try { myThumbEmulator->run(); } catch(const string& error) { if(!mySystem->autodetectMode()) { #ifdef DEBUGGER_SUPPORT Debugger::debugger().startWithFatalError(error); #else cout << error << endl; #endif } } break; #endif // reserved } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeDPCPlus::peek(uInt16 address) { address &= 0x0FFF; uInt8 peekvalue = myProgramImage[(myCurrentBank << 12) + 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] & 0x0F0000) | ((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 #pageShift(); // Setup the page access methods for the current bank System::PageAccess access(0, 0, 0, this, System::PA_READ); // Map Program ROM image into the system for(uInt32 address = 0x1080; address < 0x2000; address += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeDPCPlus::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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[(myCurrentBank << 12) + (address & 0x0FFF)] = value; return myBankChanged = true; } else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeDPCPlus::getImage(int& size) const { size = mySize; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDPCPlus::save(Serializer& out) const { try { out.putString(name()); // Indicates which bank is currently active out.putShort(myCurrentBank); // 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); out.putInt(mySystemCycles); out.putInt((uInt32)(myFractionalClocks * 100000000.0)); } 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 myCurrentBank = 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 system cycles and fractional clocks mySystemCycles = (Int32)in.getInt(); myFractionalClocks = (double)in.getInt() / 100000000.0; } catch(...) { cerr << "ERROR: CartridgeDPCPlus::load" << endl; return false; } // Now, go to the current bank bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/Cart3F.cxx0000644000175000001440000001415712266336753016460 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart3F.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "TIA.hxx" #include "Cart3F.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3F::Cartridge3F(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size) { // Allocate array for the ROM image myImage = new uInt8[mySize]; // Copy the ROM image into my buffer memcpy(myImage, image, mySize); createCodeAccessBase(mySize); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3F::~Cartridge3F() { delete[] myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3F::reset() { // We'll map the startup bank into the first segment upon reset bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3F::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1800 & mask) == 0); System::PageAccess access(0, 0, 0, this, System::PA_READWRITE); // Set the page accessing methods for the hot spots (for 100% emulation // we need to chain any accesses below 0x40 to the TIA. Our poke() method // does this via mySystem->tiaPoke(...), at least until we come up with a // cleaner way to do it). for(uInt32 i = 0x00; i < 0x40; i += (1 << shift)) mySystem->setPageAccess(i >> shift, access); // Setup the second segment to always point to the last ROM slice access.type = System::PA_READ; for(uInt32 j = 0x1800; j < 0x2000; j += (1 << shift)) { access.directPeekBase = &myImage[(mySize - 2048) + (j & 0x07FF)]; access.codeAccessBase = &myCodeAccessBase[(mySize - 2048) + (j & 0x07FF)]; mySystem->setPageAccess(j >> shift, 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); } // Pass the poke through to the TIA. In a real Atari, both the cart and the // TIA see the address lines, and both react accordingly. In Stella, each // 64-byte chunk of address space is "owned" by only one device. If we // don't chain the poke to the TIA, then the TIA can't see it... 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; uInt16 shift = mySystem->pageShift(); // Setup the page access methods for the current bank System::PageAccess access(0, 0, 0, this, System::PA_READ); // Map ROM image into the system for(uInt32 address = 0x1000; address < 0x1800; address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x07FF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x07FF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge3F::bank() 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(int& size) const { size = mySize; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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-3.9.3/src/emucore/EventHandler.cxx0000644000175000001440000030347612266336753017762 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: EventHandler.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include #include #include "bspf.hxx" #include "Base.hxx" #include "CommandMenu.hxx" #include "Console.hxx" #include "DialogContainer.hxx" #include "Event.hxx" #include "FrameBuffer.hxx" #include "FSNode.hxx" #include "Launcher.hxx" #include "Menu.hxx" #include "OSystem.hxx" #include "Joystick.hxx" #include "Paddles.hxx" #include "PropsSet.hxx" #include "ListWidget.hxx" #include "ScrollBarWidget.hxx" #include "Settings.hxx" #include "Sound.hxx" #include "StateManager.hxx" #include "M6532.hxx" #include "MouseControl.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(NULL), myMouseControl(NULL), myState(S_NONE), myAllowAllDirectionsFlag(false), myFryingFlag(false), mySkipMouseMotion(true), myJoysticks(NULL), myNumJoysticks(0) { // Erase the key mapping array for(int i = 0; i < KBDK_LAST; ++i) { ourKBDKMapping[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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::~EventHandler() { // Free strings created with strdup for(uInt32 i = 0; i < kEmulActionListSize; ++i) if(ourEmulActionList[i].key) free(ourEmulActionList[i].key); for(uInt32 i = 0; i < kMenuActionListSize; ++i) if(ourMenuActionList[i].key) free(ourMenuActionList[i].key); delete myMouseControl; delete[] myJoysticks; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::initialize() { // Make sure the event/action mappings are correctly set, // and fill the ActionList structure with valid values setSDLMappings(); 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")); // 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")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::reset(State state) { setEventState(state); myOSystem->state().reset(); setContinuousSnapshots(0); // Reset events almost immediately after starting emulation mode // We wait a little while, since 'hold' events may be present, and we want // time for the ROM to process them if(state == S_EMULATE) SDL_AddTimer(500, resetEventsCallback, (void*)this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setupJoysticks() { #ifdef JOYSTICK_SUPPORT // Initialize the joystick subsystem if((SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) || (SDL_NumJoysticks() <= 0)) { myOSystem->logMessage("No joysticks present.", 1); return; } // We need unique names for mappable devices set joyNames; // Keep track of how many Stelladaptors we've found int saCount = 0; // Open all SDL joysticks (only the first 2 Stelladaptor devices are used) if((myNumJoysticks = SDL_NumJoysticks()) > 0) myJoysticks = new StellaJoystick[myNumJoysticks]; for(uInt32 i = 0; i < myNumJoysticks; ++i) { string name = myJoysticks[i].setStick(i); // Skip if we couldn't open it for any reason if(name == "None") continue; // Figure out what type of joystick this is if(name.find("2600-daptor", 0) != string::npos) { saCount++; if(saCount > 2) // Ignore more than 2 2600-daptors { myJoysticks[i].type = StellaJoystick::JT_NONE; continue; } // 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(myJoysticks[i].numAxes == 3) { // TODO - stubbed out for now, until we find a way to reliably get info // from the Z axis myJoysticks[i].name = "2600-daptor II"; } else myJoysticks[i].name = "2600-daptor"; } else if(name.find("Stelladaptor", 0) != string::npos) { saCount++; if(saCount > 2) // Ignore more than 2 Stelladaptors continue; else // Type will be set by mapStelladaptors() myJoysticks[i].name = "Stelladaptor"; } else { // Names must be unique ostringstream namebuf; pair::iterator,bool> ret; string actualName = name; int j = 2; do { ret = joyNames.insert(actualName); namebuf.str(""); namebuf << name << " " << j++; actualName = namebuf.str(); } while(ret.second == false); name = *ret.first; myJoysticks[i].name = name; myJoysticks[i].type = StellaJoystick::JT_REGULAR; } } // Map the stelladaptors we've found according to the specified ports mapStelladaptors(myOSystem->settings().getString("saport")); setJoymap(); setActionMappings(kEmulationMode); setActionMappings(kMenuMode); ostringstream buf; buf << "Joystick devices found:" << endl; for(uInt32 i = 0; i < myNumJoysticks; ++i) buf << " " << i << ": " << myJoysticks[i].about() << endl << endl; myOSystem->logMessage(buf.str(), 1); #else myOSystem->logMessage("No joysticks present.", 1); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::mapStelladaptors(const string& saport) { #ifdef JOYSTICK_SUPPORT // 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]; if(BSPF_equalsIgnoreCase(saport, "lr")) { saOrder[0] = 1; saOrder[1] = 2; } else { saOrder[0] = 2; saOrder[1] = 1; } for(uInt32 i = 0; i < myNumJoysticks; i++) { if(BSPF_startsWithIgnoreCase(myJoysticks[i].name, "Stelladaptor")) { saCount++; if(saOrder[saCount-1] == 1) { myJoysticks[i].name += " (emulates left joystick port)"; myJoysticks[i].type = StellaJoystick::JT_STELLADAPTOR_LEFT; } else if(saOrder[saCount-1] == 2) { myJoysticks[i].name += " (emulates right joystick port)"; myJoysticks[i].type = StellaJoystick::JT_STELLADAPTOR_RIGHT; } } else if(BSPF_startsWithIgnoreCase(myJoysticks[i].name, "2600-daptor")) { saCount++; if(saOrder[saCount-1] == 1) { myJoysticks[i].name += " (emulates left joystick port)"; myJoysticks[i].type = StellaJoystick::JT_2600DAPTOR_LEFT; } else if(saOrder[saCount-1] == 2) { myJoysticks[i].name += " (emulates right joystick port)"; myJoysticks[i].type = StellaJoystick::JT_2600DAPTOR_RIGHT; } } } myOSystem->settings().setValue("saport", saport); // 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::toggleSAPortOrder() { 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"); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::poll(uInt64 time) { // Synthesize events for platform-specific hardware myOSystem->pollEvent(); // Check for an event SDL_Event event; while(SDL_PollEvent(&event)) { switch(event.type) { // keyboard events case SDL_KEYUP: case SDL_KEYDOWN: { StellaKey key = (StellaKey)event.key.keysym.sym; StellaMod mod = event.key.keysym.mod; bool state = event.key.type == SDL_KEYDOWN; bool handled = true; // Immediately store the key state myEvent.setKey(key, state); // An attempt to speed up event processing // All SDL-specific event actions are accessed by either // Control or Alt/Cmd keys. So we quickly check for those. if(kbdAlt(mod) && state) { #ifdef MAC_OSX // These keys work in all states if(key == KBDK_q) { handleEvent(Event::Quit, 1); } else #endif if(key == KBDK_RETURN) { myOSystem->frameBuffer().toggleFullscreen(); } // These only work when in emulation mode else if(myState == S_EMULATE) { switch(key) { case KBDK_EQUALS: myOSystem->frameBuffer().changeVidMode(+1); break; case KBDK_MINUS: myOSystem->frameBuffer().changeVidMode(-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().setNTSC(NTSCFilter::PRESET_OFF); break; case KBDK_2: // Alt-2 turns on 'composite' NTSC filtering myOSystem->frameBuffer().setNTSC(NTSCFilter::PRESET_COMPOSITE); break; case KBDK_3: // Alt-3 turns on 'svideo' NTSC filtering myOSystem->frameBuffer().setNTSC(NTSCFilter::PRESET_SVIDEO); break; case KBDK_4: // Alt-4 turns on 'rgb' NTSC filtering myOSystem->frameBuffer().setNTSC(NTSCFilter::PRESET_RGB); break; case KBDK_5: // Alt-5 turns on 'bad' NTSC filtering myOSystem->frameBuffer().setNTSC(NTSCFilter::PRESET_BAD); break; case KBDK_6: // Alt-6 turns on 'custom' NTSC filtering myOSystem->frameBuffer().setNTSC(NTSCFilter::PRESET_CUSTOM); break; case KBDK_7: // Alt-7 changes scanline intensity for NTSC filtering if(mod & KMOD_SHIFT) myOSystem->frameBuffer().setScanlineIntensity(-5); else myOSystem->frameBuffer().setScanlineIntensity(+5); break; case KBDK_8: // Alt-8 turns toggles scanline interpolation myOSystem->frameBuffer().toggleScanlineInterpolation(); break; case KBDK_9: // Alt-9 selects various custom adjustables for NTSC filtering if(myOSystem->frameBuffer().ntscEnabled()) { if(mod & KMOD_SHIFT) myOSystem->frameBuffer().showMessage( myOSystem->frameBuffer().ntsc().setPreviousAdjustable()); else myOSystem->frameBuffer().showMessage( myOSystem->frameBuffer().ntsc().setNextAdjustable()); } break; case KBDK_0: // Alt-0 changes custom adjustables for NTSC filtering if(myOSystem->frameBuffer().ntscEnabled()) { if(mod & KMOD_SHIFT) myOSystem->frameBuffer().showMessage( myOSystem->frameBuffer().ntsc().decreaseAdjustable()); else myOSystem->frameBuffer().showMessage( myOSystem->frameBuffer().ntsc().increaseAdjustable()); } break; case KBDK_z: if(mod & KMOD_SHIFT) myOSystem->console().toggleP0Collision(); else myOSystem->console().toggleP0Bit(); break; case KBDK_x: if(mod & KMOD_SHIFT) myOSystem->console().toggleP1Collision(); else myOSystem->console().toggleP1Bit(); break; case KBDK_c: if(mod & KMOD_SHIFT) myOSystem->console().toggleM0Collision(); else myOSystem->console().toggleM0Bit(); break; case KBDK_v: if(mod & KMOD_SHIFT) myOSystem->console().toggleM1Collision(); else myOSystem->console().toggleM1Bit(); break; case KBDK_b: if(mod & KMOD_SHIFT) myOSystem->console().toggleBLCollision(); else myOSystem->console().toggleBLBit(); break; case KBDK_n: if(mod & KMOD_SHIFT) myOSystem->console().togglePFCollision(); else myOSystem->console().togglePFBit(); break; case KBDK_m: myOSystem->console().toggleHMOVE(); break; case KBDK_COMMA: myOSystem->console().toggleFixedColors(); break; case KBDK_PERIOD: if(mod & KMOD_SHIFT) myOSystem->console().toggleCollisions(); else myOSystem->console().toggleBits(); break; case KBDK_p: // Alt-p toggles phosphor effect myOSystem->console().togglePhosphor(); break; case KBDK_l: myOSystem->frameBuffer().toggleFrameStats(); break; case KBDK_s: if(myContSnapshotInterval == 0) { ostringstream buf; uInt32 interval = myOSystem->settings().getInt("ssinterval"); buf << "Enabling shotshots in " << interval << " second intervals"; 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; #if 0 // these will be removed when a UI is added for event recording case KBDK_e: // Alt-e starts/stops event recording if(myOSystem->state().toggleRecordMode()) myOSystem->frameBuffer().showMessage("Recording started"); else myOSystem->frameBuffer().showMessage("Recording stopped"); break; case KBDK_r: // Alt-r starts/stops rewind mode if(myOSystem->state().toggleRewindMode()) myOSystem->frameBuffer().showMessage("Rewind mode started"); else myOSystem->frameBuffer().showMessage("Rewind mode stopped"); break; /* case KBDK_l: // Alt-l loads a recording if(myEventStreamer->loadRecording()) myOSystem->frameBuffer().showMessage("Playing recording"); else myOSystem->frameBuffer().showMessage("Playing recording error"); return; break; */ //////////////////////////////////////////////////////////////////////// #endif default: handled = false; break; } } else handled = false; } else if(kbdControl(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 == S_EMULATE) { 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 & KMOD_SHIFT ? -1 : 1); break; case KBDK_g: // Ctrl-g (un)grabs mouse if(!myOSystem->frameBuffer().fullScreen()) myOSystem->frameBuffer().toggleGrabMouse(); 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.c_str(), ios::out); if(out) { myOSystem->console().properties().save(out); out.close(); 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) break; // Handle keys which switch eventhandler state // Arrange the logic to take advantage of short-circuit evaluation if(!(kbdControl(mod) || kbdShift(mod) || kbdAlt(mod)) && state && eventStateChange(myKeyTable[key][kEmulationMode])) return; // Otherwise, let the event handler deal with it if(myState == S_EMULATE) handleEvent(myKeyTable[key][kEmulationMode], state); else if(myOverlay != NULL) myOverlay->handleKeyEvent(key, mod, event.key.keysym.unicode & 0x7f, state); break; // SDL_KEYUP, SDL_KEYDOWN } case SDL_MOUSEMOTION: // Determine which mode we're in, then send the event to the appropriate place if(myState == S_EMULATE) { if(!mySkipMouseMotion) { myEvent.set(Event::MouseAxisXValue, event.motion.xrel); myEvent.set(Event::MouseAxisYValue, event.motion.yrel); } mySkipMouseMotion = false; } else if(myOverlay) myOverlay->handleMouseMotionEvent(event.motion.x, event.motion.y, 0); break; // SDL_MOUSEMOTION case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONDOWN: { uInt8 state = event.button.type == SDL_MOUSEBUTTONDOWN ? 1 : 0; // Determine which mode we're in, then send the event to the appropriate place if(myState == S_EMULATE) { switch(event.button.button) { case SDL_BUTTON_LEFT: myEvent.set(Event::MouseButtonLeftValue, state); break; case SDL_BUTTON_RIGHT: myEvent.set(Event::MouseButtonRightValue, state); break; default: break; } } else if(myOverlay) { Int32 x = event.button.x, y = event.button.y; switch(event.button.button) { case SDL_BUTTON_LEFT: myOverlay->handleMouseButtonEvent( state ? EVENT_LBUTTONDOWN : EVENT_LBUTTONUP, x, y, state); break; case SDL_BUTTON_RIGHT: myOverlay->handleMouseButtonEvent( state ? EVENT_RBUTTONDOWN : EVENT_RBUTTONUP, x, y, state); break; case SDL_BUTTON_WHEELDOWN: if(state) myOverlay->handleMouseButtonEvent(EVENT_WHEELDOWN, x, y, 1); break; case SDL_BUTTON_WHEELUP: if(state) myOverlay->handleMouseButtonEvent(EVENT_WHEELUP, x, y, 1); break; default: break; } } break; // SDL_MOUSEBUTTONUP, SDL_MOUSEBUTTONDOWN } case SDL_ACTIVEEVENT: if((event.active.state & SDL_APPACTIVE) && (event.active.gain == 0)) if(myState == S_EMULATE) enterMenuMode(S_MENU); break; // SDL_ACTIVEEVENT case SDL_QUIT: handleEvent(Event::Quit, 1); break; // SDL_QUIT case SDL_VIDEOEXPOSE: myOSystem->frameBuffer().refresh(); break; // SDL_VIDEOEXPOSE #ifdef JOYSTICK_SUPPORT case SDL_JOYBUTTONUP: case SDL_JOYBUTTONDOWN: { if(event.jbutton.which >= myNumJoysticks) break; // Stelladaptors handle buttons differently than regular joysticks const StellaJoystick& joy = myJoysticks[event.jbutton.which]; int button = event.jbutton.button; int state = event.jbutton.state == SDL_PRESSED ? 1 : 0; 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 == S_EMULATE) handleEvent(joy.btnTable[button][kEmulationMode], state); else if(myOverlay != NULL) myOverlay->handleJoyEvent(event.jbutton.which, 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 == S_EMULATE) { switch(myOSystem->console().controller(Controller::Left).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().controller(Controller::Right).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; } break; // SDL_JOYBUTTONUP, SDL_JOYBUTTONDOWN } case SDL_JOYAXISMOTION: { if(event.jaxis.which >= myNumJoysticks) break; // Stelladaptors handle axis differently than regular joysticks const StellaJoystick& joy = myJoysticks[event.jaxis.which]; int type = myJoysticks[event.jaxis.which].type; int axis = event.jaxis.axis; int value = event.jaxis.value; switch(type) { case StellaJoystick::JT_REGULAR: if(myState == S_EMULATE) { // 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 != NULL) { // 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(event.jaxis.which, 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[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[type-4][axis], value); break; // 26000daptor axis } break; // SDL_JOYAXISMOTION } case SDL_JOYHATMOTION: { if(event.jhat.which >= myNumJoysticks) break; const StellaJoystick& joy = myJoysticks[event.jhat.which]; int stick = event.jhat.which; int hat = event.jhat.hat; int value = event.jhat.value; // 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 == S_EMULATE) { handleEvent(joy.hatTable[hat][EVENT_HATUP][kEmulationMode], value & SDL_HAT_UP); handleEvent(joy.hatTable[hat][EVENT_HATRIGHT][kEmulationMode], value & SDL_HAT_RIGHT); handleEvent(joy.hatTable[hat][EVENT_HATDOWN][kEmulationMode], value & SDL_HAT_DOWN); handleEvent(joy.hatTable[hat][EVENT_HATLEFT][kEmulationMode], value & SDL_HAT_LEFT); } else if(myOverlay != NULL) { if(value == SDL_HAT_CENTERED) myOverlay->handleJoyHatEvent(stick, hat, EVENT_HATCENTER); else { if(value & SDL_HAT_UP) myOverlay->handleJoyHatEvent(stick, hat, EVENT_HATUP); if(value & SDL_HAT_RIGHT) myOverlay->handleJoyHatEvent(stick, hat, EVENT_HATRIGHT); if(value & SDL_HAT_DOWN) myOverlay->handleJoyHatEvent(stick, hat, EVENT_HATDOWN); if(value & SDL_HAT_LEFT) myOverlay->handleJoyHatEvent(stick, hat, EVENT_HATLEFT); } } break; // SDL_JOYHATMOTION } #endif // JOYSTICK_SUPPORT } } // Update controllers and console switches, and in general all other things // related to emulation if(myState == S_EMULATE) { myOSystem->console().riot().update(); #if 0 // Now check if the StateManager should be saving or loading state // Per-frame cheats are disabled if the StateManager is active, since // it would interfere with proper playback if(myOSystem->state().isActive()) { myOSystem->state().update(); } else #endif { #ifdef CHEATCODE_SUPPORT const CheatList& cheats = myOSystem->cheat().perFrame(); for(uInt32 i = 0; i < cheats.size(); i++) cheats[i]->evaluate(); #endif // Handle continuous snapshots if(myContSnapshotInterval > 0 && (++myContSnapshotCounter % myContSnapshotInterval == 0)) takeSnapshot(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::handleEvent(Event::Type event, int 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 == S_EMULATE || myState == S_CMDMENU || myState == S_DEBUGGER) && state) { // Go back to the launcher, or immediately quit if(myOSystem->settings().getBool("exitlauncher") || myOSystem->launcherUsed()) { myOSystem->deleteConsole(); 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 generate messages case Event::ConsoleColor: if(state) myOSystem->frameBuffer().showMessage("Color Mode"); break; case Event::ConsoleBlackWhite: if(state) myOSystem->frameBuffer().showMessage("BW Mode"); break; case Event::ConsoleLeftDiffA: if(state) myOSystem->frameBuffer().showMessage("Left Difficulty A"); break; case Event::ConsoleLeftDiffB: if(state) myOSystem->frameBuffer().showMessage("Left Difficulty B"); break; case Event::ConsoleRightDiffA: if(state) myOSystem->frameBuffer().showMessage("Right Difficulty A"); break; case Event::ConsoleRightDiffB: if(state) myOSystem->frameBuffer().showMessage("Right Difficulty B"); break; case Event::NoType: // Ignore unmapped events return; default: break; } // Otherwise, pass it to the emulation core myEvent.set(event, state); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::eventStateChange(Event::Type type) { bool handled = true; switch(type) { case Event::PauseMode: if(myState == S_EMULATE) setEventState(S_PAUSE); else if(myState == S_PAUSE) setEventState(S_EMULATE); else handled = false; break; case Event::MenuMode: if(myState == S_EMULATE) enterMenuMode(S_MENU); else handled = false; break; case Event::CmdMenuMode: if(myState == S_EMULATE) enterMenuMode(S_CMDMENU); else if(myState == S_CMDMENU) leaveMenuMode(); else handled = false; break; case Event::DebuggerMode: if(myState == S_EMULATE) enterDebugMode(); else if(myState == S_DEBUGGER) leaveDebugMode(); else handled = false; break; default: handled = false; } return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setActionMappings(EventMode mode) { int listsize = 0; ActionList* list = NULL; switch(mode) { case kEmulationMode: listsize = kEmulActionListSize; list = ourEmulActionList; break; case kMenuMode: listsize = kMenuActionListSize; list = ourMenuActionList; break; default: return; break; } 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; free(list[i].key); list[i].key = NULL; list[i].key = strdup("None"); string key = ""; for(int j = 0; j < KBDK_LAST; ++j) // key mapping { if(myKeyTable[j][mode] == event) { if(key == "") key = key + ourKBDKMapping[j]; else key = key + ", " + ourKBDKMapping[j]; } } #ifdef JOYSTICK_SUPPORT for(uInt32 stick = 0; stick < myNumJoysticks; ++stick) { const StellaJoystick& joy = myJoysticks[stick]; // 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(dir) { case EVENT_HATUP: buf << "/up"; break; case EVENT_HATDOWN: buf << "/down"; break; case EVENT_HATLEFT: buf << "/left"; break; case EVENT_HATRIGHT: buf << "/right"; 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 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 != "") { free(list[i].key); list[i].key = NULL; list[i].key = strdup(key.c_str()); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 IntArray::const_iterator event = map.begin(); for(int mode = 0; mode < kNumModes; ++mode) for(int i = 0; i < KBDK_LAST; ++i) myKeyTable[i][mode] = (Event::Type) *event++; } else { setDefaultKeymap(Event::NoType, kEmulationMode); setDefaultKeymap(Event::NoType, kMenuMode); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setJoymap() { #ifdef JOYSTICK_SUPPORT setDefaultJoymap(Event::NoType, kEmulationMode); setDefaultJoymap(Event::NoType, kMenuMode); // Get all mappings from the settings istringstream buf(myOSystem->settings().getString("joymap")); string joymap; // First check the event type, and disregard the entire mapping if it's invalid getline(buf, joymap, '^'); if(atoi(joymap.c_str()) != Event::LastType) return; // Otherwise, put each joystick mapping entry into a hashmap while(getline(buf, joymap, '^')) { istringstream namebuf(joymap); string joyname; getline(namebuf, joyname, '|'); if(joyname.length() != 0) myJoystickMap.insert(make_pair(joyname, joymap)); } // Next try to match the mappings to the specific joystick (by name) // We do it this way since a joystick may be unplugged and replugged, // but it's settings should stay the same for(uInt32 i = 0; i < myNumJoysticks; ++i) { StellaJoystick& joy = myJoysticks[i]; if(joy.type == StellaJoystick::JT_REGULAR) { map::const_iterator iter = myJoystickMap.find(joy.name); if(iter != myJoystickMap.end()) joy.setMap(iter->second); } } #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 if(stick >= 0 && stick < (int)myNumJoysticks) { const StellaJoystick& joy = myJoysticks[stick]; if(axis >= 0 && axis < joy.numAxes && event >= 0 && 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; } } return false; #else return false; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::addJoyButtonMapping(Event::Type event, EventMode mode, int stick, int button, bool updateMenus) { #ifdef JOYSTICK_SUPPORT if(stick >= 0 && stick < (int)myNumJoysticks && !eventIsAnalog(event)) { const StellaJoystick& joy = myJoysticks[stick]; if(button >= 0 && button < joy.numButtons && event >= 0 && event < Event::LastType) { joy.btnTable[button][mode] = event; if(updateMenus) setActionMappings(mode); return true; } } return false; #else return false; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::addJoyHatMapping(Event::Type event, EventMode mode, int stick, int hat, int value, bool updateMenus) { #ifdef JOYSTICK_SUPPORT if(stick >= 0 && stick < (int)myNumJoysticks && !eventIsAnalog(event)) { const StellaJoystick& joy = myJoysticks[stick]; if(hat >= 0 && hat < joy.numHats && event >= 0 && event < Event::LastType && value != EVENT_HATCENTER) { joy.hatTable[hat][value][mode] = event; if(updateMenus) setActionMappings(mode); return true; } } return false; #else return false; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 for(uInt32 i = 0; i < myNumJoysticks; ++i) myJoysticks[i].eraseMap(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) { #define SET_DEFAULT_KEY(sdk_key, sdk_mode, sdk_event, sdk_cmp_event) \ if(eraseAll || sdk_cmp_event == sdk_event) \ myKeyTable[sdk_key][sdk_mode] = sdk_event; // 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; } switch(mode) { case kEmulationMode: SET_DEFAULT_KEY(KBDK_1, mode, Event::KeyboardZero1, event); SET_DEFAULT_KEY(KBDK_2, mode, Event::KeyboardZero2, event); SET_DEFAULT_KEY(KBDK_3, mode, Event::KeyboardZero3, event); SET_DEFAULT_KEY(KBDK_q, mode, Event::KeyboardZero4, event); SET_DEFAULT_KEY(KBDK_w, mode, Event::KeyboardZero5, event); SET_DEFAULT_KEY(KBDK_e, mode, Event::KeyboardZero6, event); SET_DEFAULT_KEY(KBDK_a, mode, Event::KeyboardZero7, event); SET_DEFAULT_KEY(KBDK_s, mode, Event::KeyboardZero8, event); SET_DEFAULT_KEY(KBDK_d, mode, Event::KeyboardZero9, event); SET_DEFAULT_KEY(KBDK_z, mode, Event::KeyboardZeroStar, event); SET_DEFAULT_KEY(KBDK_x, mode, Event::KeyboardZero0, event); SET_DEFAULT_KEY(KBDK_c, mode, Event::KeyboardZeroPound, event); SET_DEFAULT_KEY(KBDK_8, mode, Event::KeyboardOne1, event); SET_DEFAULT_KEY(KBDK_9, mode, Event::KeyboardOne2, event); SET_DEFAULT_KEY(KBDK_0, mode, Event::KeyboardOne3, event); SET_DEFAULT_KEY(KBDK_i, mode, Event::KeyboardOne4, event); SET_DEFAULT_KEY(KBDK_o, mode, Event::KeyboardOne5, event); SET_DEFAULT_KEY(KBDK_p, mode, Event::KeyboardOne6, event); SET_DEFAULT_KEY(KBDK_k, mode, Event::KeyboardOne7, event); SET_DEFAULT_KEY(KBDK_l, mode, Event::KeyboardOne8, event); SET_DEFAULT_KEY(KBDK_SEMICOLON, mode, Event::KeyboardOne9, event); SET_DEFAULT_KEY(KBDK_COMMA, mode, Event::KeyboardOneStar, event); SET_DEFAULT_KEY(KBDK_PERIOD, mode, Event::KeyboardOne0, event); SET_DEFAULT_KEY(KBDK_SLASH, mode, Event::KeyboardOnePound, event); SET_DEFAULT_KEY(KBDK_UP, mode, Event::JoystickZeroUp, event); SET_DEFAULT_KEY(KBDK_DOWN, mode, Event::JoystickZeroDown, event); SET_DEFAULT_KEY(KBDK_LEFT, mode, Event::JoystickZeroLeft, event); SET_DEFAULT_KEY(KBDK_RIGHT, mode, Event::JoystickZeroRight, event); SET_DEFAULT_KEY(KBDK_SPACE, mode, Event::JoystickZeroFire, event); SET_DEFAULT_KEY(KBDK_LCTRL, mode, Event::JoystickZeroFire, event); SET_DEFAULT_KEY(KBDK_4, mode, Event::JoystickZeroFire5, event); SET_DEFAULT_KEY(KBDK_5, mode, Event::JoystickZeroFire9, event); SET_DEFAULT_KEY(KBDK_y, mode, Event::JoystickOneUp, event); SET_DEFAULT_KEY(KBDK_h, mode, Event::JoystickOneDown, event); SET_DEFAULT_KEY(KBDK_g, mode, Event::JoystickOneLeft, event); SET_DEFAULT_KEY(KBDK_j, mode, Event::JoystickOneRight, event); SET_DEFAULT_KEY(KBDK_f, mode, Event::JoystickOneFire, event); SET_DEFAULT_KEY(KBDK_6, mode, Event::JoystickOneFire5, event); SET_DEFAULT_KEY(KBDK_7, mode, Event::JoystickOneFire9, event); SET_DEFAULT_KEY(KBDK_F1, mode, Event::ConsoleSelect, event); SET_DEFAULT_KEY(KBDK_F2, mode, Event::ConsoleReset, event); SET_DEFAULT_KEY(KBDK_F3, mode, Event::ConsoleColor, event); SET_DEFAULT_KEY(KBDK_F4, mode, Event::ConsoleBlackWhite, event); SET_DEFAULT_KEY(KBDK_F5, mode, Event::ConsoleLeftDiffA, event); SET_DEFAULT_KEY(KBDK_F6, mode, Event::ConsoleLeftDiffB, event); SET_DEFAULT_KEY(KBDK_F7, mode, Event::ConsoleRightDiffA, event); SET_DEFAULT_KEY(KBDK_F8, mode, Event::ConsoleRightDiffB, event); SET_DEFAULT_KEY(KBDK_F9, mode, Event::SaveState, event); SET_DEFAULT_KEY(KBDK_F10, mode, Event::ChangeState, event); SET_DEFAULT_KEY(KBDK_F11, mode, Event::LoadState, event); SET_DEFAULT_KEY(KBDK_F12, mode, Event::TakeSnapshot, event); SET_DEFAULT_KEY(KBDK_BACKSPACE, mode, Event::Fry, event); SET_DEFAULT_KEY(KBDK_PAUSE, mode, Event::PauseMode, event); SET_DEFAULT_KEY(KBDK_TAB, mode, Event::MenuMode, event); SET_DEFAULT_KEY(KBDK_BACKSLASH, mode, Event::CmdMenuMode, event); SET_DEFAULT_KEY(KBDK_BACKQUOTE, mode, Event::DebuggerMode, event); SET_DEFAULT_KEY(KBDK_ESCAPE, mode, Event::LauncherMode, event); break; case kMenuMode: SET_DEFAULT_KEY(KBDK_UP, mode, Event::UIUp, event); SET_DEFAULT_KEY(KBDK_DOWN, mode, Event::UIDown, event); SET_DEFAULT_KEY(KBDK_LEFT, mode, Event::UILeft, event); SET_DEFAULT_KEY(KBDK_RIGHT, mode, Event::UIRight, event); SET_DEFAULT_KEY(KBDK_HOME, mode, Event::UIHome, event); SET_DEFAULT_KEY(KBDK_END, mode, Event::UIEnd, event); SET_DEFAULT_KEY(KBDK_PAGEUP, mode, Event::UIPgUp, event); SET_DEFAULT_KEY(KBDK_PAGEDOWN, mode, Event::UIPgDown, event); SET_DEFAULT_KEY(KBDK_RETURN, mode, Event::UISelect, event); SET_DEFAULT_KEY(KBDK_ESCAPE, mode, Event::UICancel, event); SET_DEFAULT_KEY(KBDK_BACKSPACE, mode, Event::UIPrevDir, event); break; default: return; break; } setActionMappings(mode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setDefaultJoymap(Event::Type event, EventMode mode) { #ifdef JOYSTICK_SUPPORT // If event is 'NoType', erase and reset all mappings // Otherwise, only reset the given event for(uInt32 i = 0; i < myNumJoysticks; ++i) { if(event == Event::NoType) myJoysticks[i].eraseMap(mode); // erase *all* mappings else myJoysticks[i].eraseEvent(event, mode); // only reset the specific event } myOSystem->setDefaultJoymap(event, mode); setActionMappings(mode); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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() { #ifdef JOYSTICK_SUPPORT // Don't update the joymap at all if it hasn't been modified during the // program run if(myNumJoysticks == 0) return; // Save the joystick mapping hash table, making sure to update it with // any changes that have been made during the program run for(uInt32 i = 0; i < myNumJoysticks; ++i) { const StellaJoystick& joy = myJoysticks[i]; if(joy.type == StellaJoystick::JT_REGULAR) { // Update hashmap, removing the joystick entry (if it exists) // and adding the most recent mapping from the joystick itself map::iterator iter = myJoystickMap.find(joy.name); if(iter != myJoystickMap.end()) myJoystickMap.erase(iter); myJoystickMap.insert(make_pair(joy.name, joy.getMap())); } } // Now save the contents of the hashmap ostringstream joybuf; joybuf << Event::LastType; map::const_iterator iter; for(iter = myJoystickMap.begin(); iter != myJoystickMap.end(); ++iter) joybuf << "^" << iter->second; myOSystem->settings().setValue("joymap", joybuf.str()); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::getActionList(EventMode mode, StringList& l) const { 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; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::getComboList(EventMode, VariantList& l) const { // For now, this only works in emulation mode ostringstream buf; l.push_back("None", "-1"); for(uInt32 i = 0; i < kEmulActionListSize; ++i) if(EventHandler::ourEmulActionList[i].allow_combo) { buf << i; l.push_back(EventHandler::ourEmulActionList[i].action, buf.str()); buf.str(""); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::getComboListForEvent(Event::Type event, StringList& l) const { 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"); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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; break; case kMenuMode: if(idx < 0 || idx >= kMenuActionListSize) return Event::NoType; else return ourMenuActionList[idx].event; break; default: return Event::NoType; break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string EventHandler::actionAtIndex(int idx, EventMode mode) const { switch(mode) { case kEmulationMode: if(idx < 0 || idx >= kEmulActionListSize) return EmptyString; else return ourEmulActionList[idx].action; break; case kMenuMode: if(idx < 0 || idx >= kMenuActionListSize) return EmptyString; else return ourMenuActionList[idx].action; break; default: return EmptyString; break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string EventHandler::keyAtIndex(int idx, EventMode mode) const { switch(mode) { case kEmulationMode: if(idx < 0 || idx >= kEmulActionListSize) return EmptyString; else return ourEmulActionList[idx].key; break; case kMenuMode: if(idx < 0 || idx >= kMenuActionListSize) return EmptyString; else return ourMenuActionList[idx].key; break; default: return EmptyString; break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 << "_" << hex << setw(8) << 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"; // Now create a PNG snapshot if(myOSystem->settings().getBool("ss1x")) { string msg = myOSystem->png().saveImage(filename, myOSystem->frameBuffer(), myOSystem->console().tia(), myOSystem->console().properties()); if(showmessage) myOSystem->frameBuffer().showMessage(msg); } else { // Make sure we have a 'clean' image, with no onscreen messages myOSystem->frameBuffer().enableMessages(false); string msg = myOSystem->png().saveImage(filename, myOSystem->frameBuffer(), myOSystem->console().properties()); // Re-enable old messages myOSystem->frameBuffer().enableMessages(true); if(showmessage) myOSystem->frameBuffer().showMessage(msg); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setMouseControllerMode(const string& enable) { if(&myOSystem->console()) { delete myMouseControl; myMouseControl = NULL; bool usemouse = false; if(BSPF_equalsIgnoreCase(enable, "always")) usemouse = true; else if(BSPF_equalsIgnoreCase(enable, "never")) usemouse = false; else // 'analog' { switch(myOSystem->console().controller(Controller::Left).type()) { case Controller::Paddles: case Controller::Driving: case Controller::TrackBall22: case Controller::TrackBall80: case Controller::AmigaMouse: case Controller::MindLink: usemouse = true; break; default: break; } switch(myOSystem->console().controller(Controller::Right).type()) { case Controller::Paddles: case Controller::Driving: case Controller::TrackBall22: case Controller::TrackBall80: case Controller::AmigaMouse: case Controller::MindLink: usemouse = true; break; default: break; } } const string& control = usemouse ? myOSystem->console().properties().get(Controller_MouseAxis) : "none"; myMouseControl = new MouseControl(myOSystem->console(), control); myMouseControl->next(); // set first available mode } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setContinuousSnapshots(uInt32 interval) { myContSnapshotInterval = (uInt32) myOSystem->frameRate() * interval; myContSnapshotCounter = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::enterMenuMode(State state) { setEventState(state); myOverlay->reStack(); myOSystem->sound().mute(true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::leaveMenuMode() { setEventState(S_EMULATE); myOSystem->sound().mute(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::enterDebugMode() { #ifdef DEBUGGER_SUPPORT if(myState == S_DEBUGGER || !(&myOSystem->console())) 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(S_DEBUGGER); FBInitStatus fbstatus = myOSystem->createFrameBuffer(); if(fbstatus != kSuccess) { myOSystem->debugger().setQuitState(); setEventState(S_EMULATE); if(fbstatus == kFailTooLarge) myOSystem->frameBuffer().showMessage("Debugger window too large for screen", kBottomCenter, true); return false; } myOverlay->reStack(); myOSystem->sound().mute(true); #else myOSystem->frameBuffer().showMessage("Debugger support not included", kBottomCenter, true); #endif return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::leaveDebugMode() { #ifdef DEBUGGER_SUPPORT // paranoia: this should never happen: if(myState != S_DEBUGGER) return; // Make sure debugger quits in a consistent state myOSystem->debugger().setQuitState(); setEventState(S_EMULATE); myOSystem->createFrameBuffer(); myOSystem->sound().mute(false); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setEventState(State 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 Unicode in GUI modes, since there we need it for ascii data // Otherwise, it causes a performance hit, so leave it off switch(myState) { case S_EMULATE: myOverlay = NULL; myOSystem->sound().mute(false); SDL_EnableUNICODE(0); if(myOSystem->console().controller(Controller::Left).type() == Controller::CompuMate) myUseCtrlKeyFlag = false; break; case S_PAUSE: myOverlay = NULL; myOSystem->sound().mute(true); SDL_EnableUNICODE(0); break; case S_MENU: myOverlay = &myOSystem->menu(); SDL_EnableUNICODE(1); break; case S_CMDMENU: myOverlay = &myOSystem->commandMenu(); SDL_EnableUNICODE(1); break; case S_LAUNCHER: myOverlay = &myOSystem->launcher(); SDL_EnableUNICODE(1); break; #ifdef DEBUGGER_SUPPORT case S_DEBUGGER: myOverlay = &myOSystem->debugger(); SDL_EnableUNICODE(1); break; #endif default: myOverlay = NULL; break; } // Inform various subsystems about the new state myOSystem->stateChanged(myState); if(&myOSystem->frameBuffer()) { myOSystem->frameBuffer().stateChanged(myState); myOSystem->frameBuffer().setCursorState(); } if(&myOSystem->console()) { myOSystem->console().stateChanged(myState); } // Always clear any pending events when changing states myEvent.clear(); // Sometimes an extraneous mouse motion event is generated // after a state change, which should be supressed mySkipMouseMotion = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 EventHandler::resetEventsCallback(uInt32 interval, void* param) { ((EventHandler*)param)->myEvent.clear(); return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setSDLMappings() { ourKBDKMapping[ KBDK_BACKSPACE ] = "BACKSPACE"; ourKBDKMapping[ KBDK_TAB ] = "TAB"; ourKBDKMapping[ KBDK_CLEAR ] = "CLEAR"; ourKBDKMapping[ KBDK_RETURN ] = "RETURN"; ourKBDKMapping[ KBDK_PAUSE ] = "PAUSE"; ourKBDKMapping[ KBDK_ESCAPE ] = "ESCAPE"; ourKBDKMapping[ KBDK_SPACE ] = "SPACE"; ourKBDKMapping[ KBDK_EXCLAIM ] = "!"; ourKBDKMapping[ KBDK_QUOTEDBL ] = "\""; ourKBDKMapping[ KBDK_HASH ] = "#"; ourKBDKMapping[ KBDK_DOLLAR ] = "$"; ourKBDKMapping[ KBDK_AMPERSAND ] = "&"; ourKBDKMapping[ KBDK_QUOTE ] = "\'"; ourKBDKMapping[ KBDK_LEFTPAREN ] = "("; ourKBDKMapping[ KBDK_RIGHTPAREN ] = ")"; ourKBDKMapping[ KBDK_ASTERISK ] = "*"; ourKBDKMapping[ KBDK_PLUS ] = "+"; ourKBDKMapping[ KBDK_COMMA ] = "COMMA"; ourKBDKMapping[ KBDK_MINUS ] = "-"; ourKBDKMapping[ KBDK_PERIOD ] = "."; ourKBDKMapping[ KBDK_SLASH ] = "/"; ourKBDKMapping[ KBDK_0 ] = "0"; ourKBDKMapping[ KBDK_1 ] = "1"; ourKBDKMapping[ KBDK_2 ] = "2"; ourKBDKMapping[ KBDK_3 ] = "3"; ourKBDKMapping[ KBDK_4 ] = "4"; ourKBDKMapping[ KBDK_5 ] = "5"; ourKBDKMapping[ KBDK_6 ] = "6"; ourKBDKMapping[ KBDK_7 ] = "7"; ourKBDKMapping[ KBDK_8 ] = "8"; ourKBDKMapping[ KBDK_9 ] = "9"; ourKBDKMapping[ KBDK_COLON ] = ":"; ourKBDKMapping[ KBDK_SEMICOLON ] = ";"; ourKBDKMapping[ KBDK_LESS ] = "<"; ourKBDKMapping[ KBDK_EQUALS ] = "="; ourKBDKMapping[ KBDK_GREATER ] = ">"; ourKBDKMapping[ KBDK_QUESTION ] = "?"; ourKBDKMapping[ KBDK_AT ] = "@"; ourKBDKMapping[ KBDK_LEFTBRACKET ] = "["; ourKBDKMapping[ KBDK_BACKSLASH ] = "\\"; ourKBDKMapping[ KBDK_RIGHTBRACKET ] = "]"; ourKBDKMapping[ KBDK_CARET ] = "^"; ourKBDKMapping[ KBDK_UNDERSCORE ] = "_"; ourKBDKMapping[ KBDK_BACKQUOTE ] = "`"; ourKBDKMapping[ KBDK_a ] = "A"; ourKBDKMapping[ KBDK_b ] = "B"; ourKBDKMapping[ KBDK_c ] = "C"; ourKBDKMapping[ KBDK_d ] = "D"; ourKBDKMapping[ KBDK_e ] = "E"; ourKBDKMapping[ KBDK_f ] = "F"; ourKBDKMapping[ KBDK_g ] = "G"; ourKBDKMapping[ KBDK_h ] = "H"; ourKBDKMapping[ KBDK_i ] = "I"; ourKBDKMapping[ KBDK_j ] = "J"; ourKBDKMapping[ KBDK_k ] = "K"; ourKBDKMapping[ KBDK_l ] = "L"; ourKBDKMapping[ KBDK_m ] = "M"; ourKBDKMapping[ KBDK_n ] = "N"; ourKBDKMapping[ KBDK_o ] = "O"; ourKBDKMapping[ KBDK_p ] = "P"; ourKBDKMapping[ KBDK_q ] = "Q"; ourKBDKMapping[ KBDK_r ] = "R"; ourKBDKMapping[ KBDK_s ] = "S"; ourKBDKMapping[ KBDK_t ] = "T"; ourKBDKMapping[ KBDK_u ] = "U"; ourKBDKMapping[ KBDK_v ] = "V"; ourKBDKMapping[ KBDK_w ] = "W"; ourKBDKMapping[ KBDK_x ] = "X"; ourKBDKMapping[ KBDK_y ] = "Y"; ourKBDKMapping[ KBDK_z ] = "Z"; ourKBDKMapping[ KBDK_DELETE ] = "DELETE"; ourKBDKMapping[ KBDK_WORLD_0 ] = "WORLD_0"; ourKBDKMapping[ KBDK_WORLD_1 ] = "WORLD_1"; ourKBDKMapping[ KBDK_WORLD_2 ] = "WORLD_2"; ourKBDKMapping[ KBDK_WORLD_3 ] = "WORLD_3"; ourKBDKMapping[ KBDK_WORLD_4 ] = "WORLD_4"; ourKBDKMapping[ KBDK_WORLD_5 ] = "WORLD_5"; ourKBDKMapping[ KBDK_WORLD_6 ] = "WORLD_6"; ourKBDKMapping[ KBDK_WORLD_7 ] = "WORLD_7"; ourKBDKMapping[ KBDK_WORLD_8 ] = "WORLD_8"; ourKBDKMapping[ KBDK_WORLD_9 ] = "WORLD_9"; ourKBDKMapping[ KBDK_WORLD_10 ] = "WORLD_10"; ourKBDKMapping[ KBDK_WORLD_11 ] = "WORLD_11"; ourKBDKMapping[ KBDK_WORLD_12 ] = "WORLD_12"; ourKBDKMapping[ KBDK_WORLD_13 ] = "WORLD_13"; ourKBDKMapping[ KBDK_WORLD_14 ] = "WORLD_14"; ourKBDKMapping[ KBDK_WORLD_15 ] = "WORLD_15"; ourKBDKMapping[ KBDK_WORLD_16 ] = "WORLD_16"; ourKBDKMapping[ KBDK_WORLD_17 ] = "WORLD_17"; ourKBDKMapping[ KBDK_WORLD_18 ] = "WORLD_18"; ourKBDKMapping[ KBDK_WORLD_19 ] = "WORLD_19"; ourKBDKMapping[ KBDK_WORLD_20 ] = "WORLD_20"; ourKBDKMapping[ KBDK_WORLD_21 ] = "WORLD_21"; ourKBDKMapping[ KBDK_WORLD_22 ] = "WORLD_22"; ourKBDKMapping[ KBDK_WORLD_23 ] = "WORLD_23"; ourKBDKMapping[ KBDK_WORLD_24 ] = "WORLD_24"; ourKBDKMapping[ KBDK_WORLD_25 ] = "WORLD_25"; ourKBDKMapping[ KBDK_WORLD_26 ] = "WORLD_26"; ourKBDKMapping[ KBDK_WORLD_27 ] = "WORLD_27"; ourKBDKMapping[ KBDK_WORLD_28 ] = "WORLD_28"; ourKBDKMapping[ KBDK_WORLD_29 ] = "WORLD_29"; ourKBDKMapping[ KBDK_WORLD_30 ] = "WORLD_30"; ourKBDKMapping[ KBDK_WORLD_31 ] = "WORLD_31"; ourKBDKMapping[ KBDK_WORLD_32 ] = "WORLD_32"; ourKBDKMapping[ KBDK_WORLD_33 ] = "WORLD_33"; ourKBDKMapping[ KBDK_WORLD_34 ] = "WORLD_34"; ourKBDKMapping[ KBDK_WORLD_35 ] = "WORLD_35"; ourKBDKMapping[ KBDK_WORLD_36 ] = "WORLD_36"; ourKBDKMapping[ KBDK_WORLD_37 ] = "WORLD_37"; ourKBDKMapping[ KBDK_WORLD_38 ] = "WORLD_38"; ourKBDKMapping[ KBDK_WORLD_39 ] = "WORLD_39"; ourKBDKMapping[ KBDK_WORLD_40 ] = "WORLD_40"; ourKBDKMapping[ KBDK_WORLD_41 ] = "WORLD_41"; ourKBDKMapping[ KBDK_WORLD_42 ] = "WORLD_42"; ourKBDKMapping[ KBDK_WORLD_43 ] = "WORLD_43"; ourKBDKMapping[ KBDK_WORLD_44 ] = "WORLD_44"; ourKBDKMapping[ KBDK_WORLD_45 ] = "WORLD_45"; ourKBDKMapping[ KBDK_WORLD_46 ] = "WORLD_46"; ourKBDKMapping[ KBDK_WORLD_47 ] = "WORLD_47"; ourKBDKMapping[ KBDK_WORLD_48 ] = "WORLD_48"; ourKBDKMapping[ KBDK_WORLD_49 ] = "WORLD_49"; ourKBDKMapping[ KBDK_WORLD_50 ] = "WORLD_50"; ourKBDKMapping[ KBDK_WORLD_51 ] = "WORLD_51"; ourKBDKMapping[ KBDK_WORLD_52 ] = "WORLD_52"; ourKBDKMapping[ KBDK_WORLD_53 ] = "WORLD_53"; ourKBDKMapping[ KBDK_WORLD_54 ] = "WORLD_54"; ourKBDKMapping[ KBDK_WORLD_55 ] = "WORLD_55"; ourKBDKMapping[ KBDK_WORLD_56 ] = "WORLD_56"; ourKBDKMapping[ KBDK_WORLD_57 ] = "WORLD_57"; ourKBDKMapping[ KBDK_WORLD_58 ] = "WORLD_58"; ourKBDKMapping[ KBDK_WORLD_59 ] = "WORLD_59"; ourKBDKMapping[ KBDK_WORLD_60 ] = "WORLD_60"; ourKBDKMapping[ KBDK_WORLD_61 ] = "WORLD_61"; ourKBDKMapping[ KBDK_WORLD_62 ] = "WORLD_62"; ourKBDKMapping[ KBDK_WORLD_63 ] = "WORLD_63"; ourKBDKMapping[ KBDK_WORLD_64 ] = "WORLD_64"; ourKBDKMapping[ KBDK_WORLD_65 ] = "WORLD_65"; ourKBDKMapping[ KBDK_WORLD_66 ] = "WORLD_66"; ourKBDKMapping[ KBDK_WORLD_67 ] = "WORLD_67"; ourKBDKMapping[ KBDK_WORLD_68 ] = "WORLD_68"; ourKBDKMapping[ KBDK_WORLD_69 ] = "WORLD_69"; ourKBDKMapping[ KBDK_WORLD_70 ] = "WORLD_70"; ourKBDKMapping[ KBDK_WORLD_71 ] = "WORLD_71"; ourKBDKMapping[ KBDK_WORLD_72 ] = "WORLD_72"; ourKBDKMapping[ KBDK_WORLD_73 ] = "WORLD_73"; ourKBDKMapping[ KBDK_WORLD_74 ] = "WORLD_74"; ourKBDKMapping[ KBDK_WORLD_75 ] = "WORLD_75"; ourKBDKMapping[ KBDK_WORLD_76 ] = "WORLD_76"; ourKBDKMapping[ KBDK_WORLD_77 ] = "WORLD_77"; ourKBDKMapping[ KBDK_WORLD_78 ] = "WORLD_78"; ourKBDKMapping[ KBDK_WORLD_79 ] = "WORLD_79"; ourKBDKMapping[ KBDK_WORLD_80 ] = "WORLD_80"; ourKBDKMapping[ KBDK_WORLD_81 ] = "WORLD_81"; ourKBDKMapping[ KBDK_WORLD_82 ] = "WORLD_82"; ourKBDKMapping[ KBDK_WORLD_83 ] = "WORLD_83"; ourKBDKMapping[ KBDK_WORLD_84 ] = "WORLD_84"; ourKBDKMapping[ KBDK_WORLD_85 ] = "WORLD_85"; ourKBDKMapping[ KBDK_WORLD_86 ] = "WORLD_86"; ourKBDKMapping[ KBDK_WORLD_87 ] = "WORLD_87"; ourKBDKMapping[ KBDK_WORLD_88 ] = "WORLD_88"; ourKBDKMapping[ KBDK_WORLD_89 ] = "WORLD_89"; ourKBDKMapping[ KBDK_WORLD_90 ] = "WORLD_90"; ourKBDKMapping[ KBDK_WORLD_91 ] = "WORLD_91"; ourKBDKMapping[ KBDK_WORLD_92 ] = "WORLD_92"; ourKBDKMapping[ KBDK_WORLD_93 ] = "WORLD_93"; ourKBDKMapping[ KBDK_WORLD_94 ] = "WORLD_94"; ourKBDKMapping[ KBDK_WORLD_95 ] = "WORLD_95"; ourKBDKMapping[ KBDK_KP0 ] = "KP0"; ourKBDKMapping[ KBDK_KP1 ] = "KP1"; ourKBDKMapping[ KBDK_KP2 ] = "KP2"; ourKBDKMapping[ KBDK_KP3 ] = "KP3"; ourKBDKMapping[ KBDK_KP4 ] = "KP4"; ourKBDKMapping[ KBDK_KP5 ] = "KP5"; ourKBDKMapping[ KBDK_KP6 ] = "KP6"; ourKBDKMapping[ KBDK_KP7 ] = "KP7"; ourKBDKMapping[ KBDK_KP8 ] = "KP8"; ourKBDKMapping[ KBDK_KP9 ] = "KP9"; ourKBDKMapping[ KBDK_KP_PERIOD ] = "KP ."; ourKBDKMapping[ KBDK_KP_DIVIDE ] = "KP /"; ourKBDKMapping[ KBDK_KP_MULTIPLY ] = "KP *"; ourKBDKMapping[ KBDK_KP_MINUS ] = "KP -"; ourKBDKMapping[ KBDK_KP_PLUS ] = "KP +"; ourKBDKMapping[ KBDK_KP_ENTER ] = "KP ENTER"; ourKBDKMapping[ KBDK_KP_EQUALS ] = "KP ="; ourKBDKMapping[ KBDK_UP ] = "UP"; ourKBDKMapping[ KBDK_DOWN ] = "DOWN"; ourKBDKMapping[ KBDK_RIGHT ] = "RIGHT"; ourKBDKMapping[ KBDK_LEFT ] = "LEFT"; ourKBDKMapping[ KBDK_INSERT ] = "INS"; ourKBDKMapping[ KBDK_HOME ] = "HOME"; ourKBDKMapping[ KBDK_END ] = "END"; ourKBDKMapping[ KBDK_PAGEUP ] = "PGUP"; ourKBDKMapping[ KBDK_PAGEDOWN ] = "PGDN"; ourKBDKMapping[ KBDK_F1 ] = "F1"; ourKBDKMapping[ KBDK_F2 ] = "F2"; ourKBDKMapping[ KBDK_F3 ] = "F3"; ourKBDKMapping[ KBDK_F4 ] = "F4"; ourKBDKMapping[ KBDK_F5 ] = "F5"; ourKBDKMapping[ KBDK_F6 ] = "F6"; ourKBDKMapping[ KBDK_F7 ] = "F7"; ourKBDKMapping[ KBDK_F8 ] = "F8"; ourKBDKMapping[ KBDK_F9 ] = "F9"; ourKBDKMapping[ KBDK_F10 ] = "F10"; ourKBDKMapping[ KBDK_F11 ] = "F11"; ourKBDKMapping[ KBDK_F12 ] = "F12"; ourKBDKMapping[ KBDK_F13 ] = "F13"; ourKBDKMapping[ KBDK_F14 ] = "F14"; ourKBDKMapping[ KBDK_F15 ] = "F15"; ourKBDKMapping[ KBDK_NUMLOCK ] = "NUMLOCK"; ourKBDKMapping[ KBDK_CAPSLOCK ] = "CAPSLOCK"; ourKBDKMapping[ KBDK_SCROLLOCK ] = "SCROLLOCK"; ourKBDKMapping[ KBDK_RSHIFT ] = "RSHIFT"; ourKBDKMapping[ KBDK_LSHIFT ] = "LSHIFT"; ourKBDKMapping[ KBDK_RCTRL ] = "RCTRL"; ourKBDKMapping[ KBDK_LCTRL ] = "LCTRL"; ourKBDKMapping[ KBDK_RALT ] = "RALT"; ourKBDKMapping[ KBDK_LALT ] = "LALT"; ourKBDKMapping[ KBDK_RMETA ] = "RMETA"; ourKBDKMapping[ KBDK_LMETA ] = "LMETA"; ourKBDKMapping[ KBDK_LSUPER ] = "LSUPER"; ourKBDKMapping[ KBDK_RSUPER ] = "RSUPER"; ourKBDKMapping[ KBDK_MODE ] = "MODE"; ourKBDKMapping[ KBDK_COMPOSE ] = "COMPOSE"; ourKBDKMapping[ KBDK_HELP ] = "HELP"; ourKBDKMapping[ KBDK_PRINT ] = "PRINT"; ourKBDKMapping[ KBDK_SYSREQ ] = "SYSREQ"; ourKBDKMapping[ KBDK_BREAK ] = "BREAK"; ourKBDKMapping[ KBDK_MENU ] = "MENU"; ourKBDKMapping[ KBDK_POWER ] = "POWER"; ourKBDKMapping[ KBDK_EURO ] = "EURO"; ourKBDKMapping[ KBDK_UNDO ] = "UNDO"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::ActionList EventHandler::ourEmulActionList[kEmulActionListSize] = { { Event::ConsoleSelect, "Select", 0, true }, { Event::ConsoleReset, "Reset", 0, true }, { Event::ConsoleColor, "Color TV", 0, true }, { Event::ConsoleBlackWhite, "Black & White TV", 0, true }, { Event::ConsoleLeftDiffA, "P0 Difficulty A", 0, true }, { Event::ConsoleLeftDiffB, "P0 Difficulty B", 0, true }, { Event::ConsoleRightDiffA, "P1 Difficulty A", 0, true }, { Event::ConsoleRightDiffB, "P1 Difficulty B", 0, true }, { Event::SaveState, "Save State", 0, false }, { Event::ChangeState, "Change State", 0, false }, { Event::LoadState, "Load State", 0, false }, { Event::TakeSnapshot, "Snapshot", 0, false }, { Event::Fry, "Fry cartridge", 0, false }, { Event::VolumeDecrease, "Decrease volume", 0, false }, { Event::VolumeIncrease, "Increase volume", 0, false }, { Event::PauseMode, "Pause", 0, false }, { Event::MenuMode, "Enter options menu mode", 0, false }, { Event::CmdMenuMode, "Toggle command menu mode", 0, false }, { Event::DebuggerMode, "Toggle debugger mode", 0, false }, { Event::LauncherMode, "Enter ROM launcher", 0, false }, { Event::Quit, "Quit", 0, false }, { Event::JoystickZeroUp, "P0 Joystick Up", 0, true }, { Event::JoystickZeroDown, "P0 Joystick Down", 0, true }, { Event::JoystickZeroLeft, "P0 Joystick Left", 0, true }, { Event::JoystickZeroRight, "P0 Joystick Right", 0, true }, { Event::JoystickZeroFire, "P0 Joystick Fire", 0, true }, { Event::JoystickZeroFire5, "P0 Booster Top Trigger", 0, true }, { Event::JoystickZeroFire9, "P0 Booster Handle Grip", 0, true }, { Event::JoystickOneUp, "P1 Joystick Up", 0, true }, { Event::JoystickOneDown, "P1 Joystick Down", 0, true }, { Event::JoystickOneLeft, "P1 Joystick Left", 0, true }, { Event::JoystickOneRight, "P1 Joystick Right", 0, true }, { Event::JoystickOneFire, "P1 Joystick Fire", 0, true }, { Event::JoystickOneFire5, "P1 Booster Top Trigger", 0, true }, { Event::JoystickOneFire9, "P1 Booster Handle Grip", 0, true }, { Event::PaddleZeroAnalog, "Paddle 0 Analog", 0, true }, { Event::PaddleZeroDecrease, "Paddle 0 Decrease", 0, true }, { Event::PaddleZeroIncrease, "Paddle 0 Increase", 0, true }, { Event::PaddleZeroFire, "Paddle 0 Fire", 0, true }, { Event::PaddleOneAnalog, "Paddle 1 Analog", 0, true }, { Event::PaddleOneDecrease, "Paddle 1 Decrease", 0, true }, { Event::PaddleOneIncrease, "Paddle 1 Increase", 0, true }, { Event::PaddleOneFire, "Paddle 1 Fire", 0, true }, { Event::PaddleTwoAnalog, "Paddle 2 Analog", 0, true }, { Event::PaddleTwoDecrease, "Paddle 2 Decrease", 0, true }, { Event::PaddleTwoIncrease, "Paddle 2 Increase", 0, true }, { Event::PaddleTwoFire, "Paddle 2 Fire", 0, true }, { Event::PaddleThreeAnalog, "Paddle 3 Analog", 0, true }, { Event::PaddleThreeDecrease, "Paddle 3 Decrease", 0, true }, { Event::PaddleThreeIncrease, "Paddle 3 Increase", 0, true }, { Event::PaddleThreeFire, "Paddle 3 Fire", 0, true }, { Event::KeyboardZero1, "P0 Keyboard 1", 0, true }, { Event::KeyboardZero2, "P0 Keyboard 2", 0, true }, { Event::KeyboardZero3, "P0 Keyboard 3", 0, true }, { Event::KeyboardZero4, "P0 Keyboard 4", 0, true }, { Event::KeyboardZero5, "P0 Keyboard 5", 0, true }, { Event::KeyboardZero6, "P0 Keyboard 6", 0, true }, { Event::KeyboardZero7, "P0 Keyboard 7", 0, true }, { Event::KeyboardZero8, "P0 Keyboard 8", 0, true }, { Event::KeyboardZero9, "P0 Keyboard 9", 0, true }, { Event::KeyboardZeroStar, "P0 Keyboard *", 0, true }, { Event::KeyboardZero0, "P0 Keyboard 0", 0, true }, { Event::KeyboardZeroPound, "P0 Keyboard #", 0, true }, { Event::KeyboardOne1, "P1 Keyboard 1", 0, true }, { Event::KeyboardOne2, "P1 Keyboard 2", 0, true }, { Event::KeyboardOne3, "P1 Keyboard 3", 0, true }, { Event::KeyboardOne4, "P1 Keyboard 4", 0, true }, { Event::KeyboardOne5, "P1 Keyboard 5", 0, true }, { Event::KeyboardOne6, "P1 Keyboard 6", 0, true }, { Event::KeyboardOne7, "P1 Keyboard 7", 0, true }, { Event::KeyboardOne8, "P1 Keyboard 8", 0, true }, { Event::KeyboardOne9, "P1 Keyboard 9", 0, true }, { Event::KeyboardOneStar, "P1 Keyboard *", 0, true }, { Event::KeyboardOne0, "P1 Keyboard 0", 0, true }, { Event::KeyboardOnePound, "P1 Keyboard #", 0, true }, { Event::Combo1, "Combo 1", 0, false }, { Event::Combo2, "Combo 2", 0, false }, { Event::Combo3, "Combo 3", 0, false }, { Event::Combo4, "Combo 4", 0, false }, { Event::Combo5, "Combo 5", 0, false }, { Event::Combo6, "Combo 6", 0, false }, { Event::Combo7, "Combo 7", 0, false }, { Event::Combo8, "Combo 8", 0, false }, { Event::Combo9, "Combo 9", 0, false }, { Event::Combo10, "Combo 10", 0, false }, { Event::Combo11, "Combo 11", 0, false }, { Event::Combo12, "Combo 12", 0, false }, { Event::Combo13, "Combo 13", 0, false }, { Event::Combo14, "Combo 14", 0, false }, { Event::Combo15, "Combo 15", 0, false }, { Event::Combo16, "Combo 16", 0, false } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::ActionList EventHandler::ourMenuActionList[kMenuActionListSize] = { { Event::UIUp, "Move Up", 0, false }, { Event::UIDown, "Move Down", 0, false }, { Event::UILeft, "Move Left", 0, false }, { Event::UIRight, "Move Right", 0, false }, { Event::UIHome, "Home", 0, false }, { Event::UIEnd, "End", 0, false }, { Event::UIPgUp, "Page Up", 0, false }, { Event::UIPgDown, "Page Down", 0, false }, { Event::UIOK, "OK", 0, false }, { Event::UICancel, "Cancel", 0, false }, { Event::UISelect, "Select item", 0, false }, { Event::UINavPrev, "Previous object", 0, false }, { Event::UINavNext, "Next object", 0, false }, { Event::UIPrevDir, "Parent directory", 0, 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 } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::StellaJoystick::StellaJoystick() : type(JT_NONE), name("None"), stick(NULL), numAxes(0), numButtons(0), numHats(0), axisTable(NULL), btnTable(NULL), hatTable(NULL), axisLastValue(NULL) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::StellaJoystick::~StellaJoystick() { delete[] axisTable; axisTable = NULL; delete[] btnTable; btnTable = NULL; delete[] hatTable; hatTable = NULL; delete[] axisLastValue; axisLastValue = NULL; if(stick) SDL_JoystickClose(stick); stick = NULL; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string EventHandler::StellaJoystick::setStick(int index) { stick = SDL_JoystickOpen(index); if(stick) { // Dynamically create the various mapping arrays for this joystick, // based on its specific attributes numAxes = SDL_JoystickNumAxes(stick); numButtons = SDL_JoystickNumButtons(stick); numHats = SDL_JoystickNumHats(stick); axisTable = new Event::Type[numAxes][2][kNumModes]; btnTable = new Event::Type[numButtons][kNumModes]; 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; name = SDL_JoystickName(index); } return name; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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& m) { istringstream buf(m); 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 IntArray::const_iterator event = map.begin(); 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) { IntArray::const_iterator event = map.begin(); 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) { IntArray::const_iterator event = map.begin(); 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) { 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:" << endl << " " << numAxes << " axes, " << numButtons << " buttons, " << numHats << " hats"; return buf.str(); } stella-3.9.3/src/emucore/Booster.cxx0000644000175000001440000001213512266336753017005 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Booster.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BoosterGrip::~BoosterGrip() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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. myAnalogPinValue[Five] = (myEvent.get(myTriggerEvent) != 0) ? minimumResistance : maximumResistance; myAnalogPinValue[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)) myAnalogPinValue[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-3.9.3/src/emucore/TIA.cxx0000644000175000001440000021705512266336753016015 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TIA.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include #include "bspf.hxx" #ifdef DEBUGGER_SUPPORT #include "CartDebug.hxx" #endif #include "Console.hxx" #include "Control.hxx" #include "Device.hxx" #include "M6502.hxx" #include "Settings.hxx" #include "Sound.hxx" #include "System.hxx" #include "TIATables.hxx" #include "TIA.hxx" #define HBLANK 68 #define CLAMP_POS(reg) if(reg < 0) { reg += 160; } reg %= 160; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TIA::TIA(Console& console, Sound& sound, Settings& settings) : myConsole(console), mySound(sound), mySettings(settings), myFrameYStart(34), myFrameHeight(210), myMaximumNumberOfScanlines(262), myStartScanline(0), myColorLossEnabled(false), myPartialFrameFlag(false), myAutoFrameEnabled(false), myFrameCounter(0), myPALFrameCounter(0), myBitsEnabled(true), myCollisionsEnabled(true) { // Allocate buffers for two frame buffers myCurrentFrameBuffer = new uInt8[160 * 320]; myPreviousFrameBuffer = new uInt8[160 * 320]; // Make sure all TIA bits are enabled enableBits(true); // Turn off debug colours (this also sets up the PriorityEncoder) toggleFixedColors(0); // Compute all of the mask tables TIATables::computeAllTables(); // Zero audio registers myAUDV0 = myAUDV1 = myAUDF0 = myAUDF1 = myAUDC0 = myAUDC1 = 0; // Should undriven pins be randomly pulled high or low? myTIAPinsDriven = mySettings.getBool("tiadriven"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TIA::~TIA() { delete[] myCurrentFrameBuffer; delete[] myPreviousFrameBuffer; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::reset() { // Reset the sound device mySound.reset(); // Currently no objects are enabled or selectively disabled myEnabledObjects = 0; myDisabledObjects = 0xFF; myAllowHMOVEBlanks = true; // Some default values for the registers myVSYNC = myVBLANK = 0; myNUSIZ0 = myNUSIZ1 = 0; myColor[P0Color] = myColor[P1Color] = myColor[PFColor] = myColor[BKColor] = 0; myColor[M0Color] = myColor[M1Color] = myColor[BLColor] = myColor[HBLANKColor] = 0; myPlayfieldPriorityAndScore = 0; myCTRLPF = 0; myREFP0 = myREFP1 = false; myPF = 0; myGRP0 = myGRP1 = myDGRP0 = myDGRP1 = 0; myENAM0 = myENAM1 = myENABL = myDENABL = false; myHMP0 = myHMP1 = myHMM0 = myHMM1 = myHMBL = 0; myVDELP0 = myVDELP1 = myVDELBL = myRESMP0 = myRESMP1 = false; myCollision = 0; myCollisionEnabledMask = 0xFFFFFFFF; myPOSP0 = myPOSP1 = myPOSM0 = myPOSM1 = myPOSBL = 0; // Some default values for the "current" variables myCurrentGRP0 = 0; myCurrentGRP1 = 0; myMotionClockP0 = 0; myMotionClockP1 = 0; myMotionClockM0 = 0; myMotionClockM1 = 0; myMotionClockBL = 0; mySuppressP0 = mySuppressP1 = 0; myHMP0mmr = myHMP1mmr = myHMM0mmr = myHMM1mmr = myHMBLmmr = false; myCurrentHMOVEPos = myPreviousHMOVEPos = 0x7FFFFFFF; myHMOVEBlankEnabled = false; enableBits(true); myDumpEnabled = false; myDumpDisabledCycle = 0; myINPT4 = myINPT5 = 0x80; myFrameCounter = myPALFrameCounter = 0; myScanlineCountForLastFrame = 0; myP0Mask = &TIATables::PxMask[0][0][0]; myP1Mask = &TIATables::PxMask[0][0][0]; myM0Mask = &TIATables::MxMask[0][0][0]; myM1Mask = &TIATables::MxMask[0][0][0]; myBLMask = &TIATables::BLMask[0][0]; myPFMask = TIATables::PFMask[0]; // Recalculate the size of the display toggleFixedColors(0); frameReset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::frameReset() { // Clear frame buffers clearBuffers(); // Reset pixel pointer and drawing flag myFramePointer = myCurrentFrameBuffer; // Calculate color clock offsets for starting and stopping frame drawing // Note that although we always start drawing at scanline zero, the // framebuffer that is exposed outside the class actually starts at 'ystart' myFramePointerOffset = 160 * myFrameYStart; myAutoFrameEnabled = (mySettings.getInt("framerate") <= 0); myFramerate = myConsole.getFramerate(); if(myFramerate > 55.0) // NTSC { myFixedColor[P0Color] = 0x30; myFixedColor[P1Color] = 0x16; myFixedColor[M0Color] = 0x38; myFixedColor[M1Color] = 0x12; myFixedColor[BLColor] = 0x7e; myFixedColor[PFColor] = 0x76; myFixedColor[BKColor] = 0x0a; myFixedColor[HBLANKColor] = 0x0e; myColorLossEnabled = false; myMaximumNumberOfScanlines = 290; } else { myFixedColor[P0Color] = 0x62; myFixedColor[P1Color] = 0x26; myFixedColor[M0Color] = 0x68; myFixedColor[M1Color] = 0x2e; myFixedColor[BLColor] = 0xde; myFixedColor[PFColor] = 0xd8; myFixedColor[BKColor] = 0x1c; myFixedColor[HBLANKColor] = 0x0e; myColorLossEnabled = mySettings.getBool("colorloss"); myMaximumNumberOfScanlines = 342; } // NTSC screens will process at least 262 scanlines, // while PAL will have at least 312 // In any event, at most 320 lines can be processed uInt32 scanlines = myFrameYStart + myFrameHeight; if(myMaximumNumberOfScanlines == 290) scanlines = BSPF_max(scanlines, 262u); // NTSC else scanlines = BSPF_max(scanlines, 312u); // PAL myStopDisplayOffset = 228 * BSPF_min(scanlines, 320u); // Reasonable values to start and stop the current frame drawing myClockWhenFrameStarted = mySystem->cycles() * 3; myClockStartDisplay = myClockWhenFrameStarted; myClockStopDisplay = myClockWhenFrameStarted + myStopDisplayOffset; myClockAtLastUpdate = myClockWhenFrameStarted; myClocksToEndOfScanLine = 228; myVSYNCFinishClock = 0x7FFFFFFF; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::systemCyclesReset() { // Get the current system cycle uInt32 cycles = mySystem->cycles(); // Adjust the sound cycle indicator mySound.adjustCycleCounter(-1 * cycles); // Adjust the dump cycle myDumpDisabledCycle -= cycles; // Get the current color clock the system is using uInt32 clocks = cycles * 3; // Adjust the clocks by this amount since we're reseting the clock to zero myClockWhenFrameStarted -= clocks; myClockStartDisplay -= clocks; myClockStopDisplay -= clocks; myClockAtLastUpdate -= clocks; myVSYNCFinishClock -= clocks; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::install(System& system) { install(system, *this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::install(System& system, Device& device) { // Remember which system I'm installed in mySystem = &system; uInt16 shift = mySystem->pageShift(); mySystem->resetCycles(); // All accesses are to the given device System::PageAccess access(0, 0, 0, &device, System::PA_READWRITE); // We're installing in a 2600 system for(uInt32 i = 0; i < 8192; i += (1 << shift)) if((i & 0x1080) == 0x0000) mySystem->setPageAccess(i >> shift, access); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::save(Serializer& out) const { const string& device = name(); try { out.putString(device); out.putInt(myClockWhenFrameStarted); out.putInt(myClockStartDisplay); out.putInt(myClockStopDisplay); out.putInt(myClockAtLastUpdate); out.putInt(myClocksToEndOfScanLine); out.putInt(myScanlineCountForLastFrame); out.putInt(myVSYNCFinishClock); out.putByte(myEnabledObjects); out.putByte(myDisabledObjects); out.putByte(myVSYNC); out.putByte(myVBLANK); out.putByte(myNUSIZ0); out.putByte(myNUSIZ1); out.putByteArray(myColor, 8); out.putByte(myCTRLPF); out.putByte(myPlayfieldPriorityAndScore); out.putBool(myREFP0); out.putBool(myREFP1); out.putInt(myPF); out.putByte(myGRP0); out.putByte(myGRP1); out.putByte(myDGRP0); out.putByte(myDGRP1); out.putBool(myENAM0); out.putBool(myENAM1); out.putBool(myENABL); out.putBool(myDENABL); out.putByte(myHMP0); out.putByte(myHMP1); out.putByte(myHMM0); out.putByte(myHMM1); out.putByte(myHMBL); out.putBool(myVDELP0); out.putBool(myVDELP1); out.putBool(myVDELBL); out.putBool(myRESMP0); out.putBool(myRESMP1); out.putShort(myCollision); out.putInt(myCollisionEnabledMask); out.putByte(myCurrentGRP0); out.putByte(myCurrentGRP1); out.putBool(myDumpEnabled); out.putInt(myDumpDisabledCycle); out.putShort(myPOSP0); out.putShort(myPOSP1); out.putShort(myPOSM0); out.putShort(myPOSM1); out.putShort(myPOSBL); out.putInt(myMotionClockP0); out.putInt(myMotionClockP1); out.putInt(myMotionClockM0); out.putInt(myMotionClockM1); out.putInt(myMotionClockBL); out.putInt(myStartP0); out.putInt(myStartP1); out.putInt(myStartM0); out.putInt(myStartM1); out.putByte(mySuppressP0); out.putByte(mySuppressP1); out.putBool(myHMP0mmr); out.putBool(myHMP1mmr); out.putBool(myHMM0mmr); out.putBool(myHMM1mmr); out.putBool(myHMBLmmr); out.putInt(myCurrentHMOVEPos); out.putInt(myPreviousHMOVEPos); out.putBool(myHMOVEBlankEnabled); out.putInt(myFrameCounter); out.putInt(myPALFrameCounter); // Save the sound sample stuff ... mySound.save(out); } catch(...) { cerr << "ERROR: TIA::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::load(Serializer& in) { const string& device = name(); try { if(in.getString() != device) return false; myClockWhenFrameStarted = (Int32) in.getInt(); myClockStartDisplay = (Int32) in.getInt(); myClockStopDisplay = (Int32) in.getInt(); myClockAtLastUpdate = (Int32) in.getInt(); myClocksToEndOfScanLine = (Int32) in.getInt(); myScanlineCountForLastFrame = in.getInt(); myVSYNCFinishClock = (Int32) in.getInt(); myEnabledObjects = in.getByte(); myDisabledObjects = in.getByte(); myVSYNC = in.getByte(); myVBLANK = in.getByte(); myNUSIZ0 = in.getByte(); myNUSIZ1 = in.getByte(); in.getByteArray(myColor, 8); myCTRLPF = in.getByte(); myPlayfieldPriorityAndScore = in.getByte(); myREFP0 = in.getBool(); myREFP1 = in.getBool(); myPF = in.getInt(); myGRP0 = in.getByte(); myGRP1 = in.getByte(); myDGRP0 = in.getByte(); myDGRP1 = in.getByte(); myENAM0 = in.getBool(); myENAM1 = in.getBool(); myENABL = in.getBool(); myDENABL = in.getBool(); myHMP0 = in.getByte(); myHMP1 = in.getByte(); myHMM0 = in.getByte(); myHMM1 = in.getByte(); myHMBL = in.getByte(); myVDELP0 = in.getBool(); myVDELP1 = in.getBool(); myVDELBL = in.getBool(); myRESMP0 = in.getBool(); myRESMP1 = in.getBool(); myCollision = in.getShort(); myCollisionEnabledMask = in.getInt(); myCurrentGRP0 = in.getByte(); myCurrentGRP1 = in.getByte(); myDumpEnabled = in.getBool(); myDumpDisabledCycle = (Int32) in.getInt(); myPOSP0 = (Int16) in.getShort(); myPOSP1 = (Int16) in.getShort(); myPOSM0 = (Int16) in.getShort(); myPOSM1 = (Int16) in.getShort(); myPOSBL = (Int16) in.getShort(); myMotionClockP0 = (Int32) in.getInt(); myMotionClockP1 = (Int32) in.getInt(); myMotionClockM0 = (Int32) in.getInt(); myMotionClockM1 = (Int32) in.getInt(); myMotionClockBL = (Int32) in.getInt(); myStartP0 = (Int32) in.getInt(); myStartP1 = (Int32) in.getInt(); myStartM0 = (Int32) in.getInt(); myStartM1 = (Int32) in.getInt(); mySuppressP0 = in.getByte(); mySuppressP1 = in.getByte(); myHMP0mmr = in.getBool(); myHMP1mmr = in.getBool(); myHMM0mmr = in.getBool(); myHMM1mmr = in.getBool(); myHMBLmmr = in.getBool(); myCurrentHMOVEPos = (Int32) in.getInt(); myPreviousHMOVEPos = (Int32) in.getInt(); myHMOVEBlankEnabled = in.getBool(); myFrameCounter = in.getInt(); myPALFrameCounter = in.getInt(); // Load the sound sample stuff ... mySound.load(in); // Reset TIA bits to be on enableBits(true); toggleFixedColors(0); myAllowHMOVEBlanks = true; } catch(...) { cerr << "ERROR: TIA::load" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::saveDisplay(Serializer& out) const { try { out.putBool(myPartialFrameFlag); out.putInt(myFramePointerClocks); out.putByteArray(myCurrentFrameBuffer, 160*320); } catch(...) { cerr << "ERROR: TIA::saveDisplay" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::loadDisplay(Serializer& in) { try { myPartialFrameFlag = in.getBool(); myFramePointerClocks = in.getInt(); // Reset frame buffer pointer and data clearBuffers(); myFramePointer = myCurrentFrameBuffer; in.getByteArray(myCurrentFrameBuffer, 160*320); memcpy(myPreviousFrameBuffer, myCurrentFrameBuffer, 160*320); // If we're in partial frame mode, make sure to re-create the screen // as it existed when the state was saved if(myPartialFrameFlag) myFramePointer += myFramePointerClocks; } catch(...) { cerr << "ERROR: TIA::loadDisplay" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::update() { // if we've finished a frame, start a new one if(!myPartialFrameFlag) startFrame(); // Partial frame flag starts out true here. When then 6502 strobes VSYNC, // TIA::poke() will set this flag to false, so we'll know whether the // frame got finished or interrupted by the debugger hitting a break/trap. myPartialFrameFlag = true; // Execute instructions until frame is finished, or a breakpoint/trap hits mySystem->m6502().execute(25000); // TODO: have code here that handles errors.... endFrame(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void TIA::startFrame() { // This stuff should only happen at the beginning of a new frame. uInt8* tmp = myCurrentFrameBuffer; myCurrentFrameBuffer = myPreviousFrameBuffer; myPreviousFrameBuffer = tmp; // Remember the number of clocks which have passed on the current scanline // so that we can adjust the frame's starting clock by this amount. This // is necessary since some games position objects during VSYNC and the // TIA's internal counters are not reset by VSYNC. uInt32 clocks = ((mySystem->cycles() * 3) - myClockWhenFrameStarted) % 228; // Ask the system to reset the cycle count so it doesn't overflow mySystem->resetCycles(); // Setup clocks that'll be used for drawing this frame myClockWhenFrameStarted = -1 * clocks; myClockStartDisplay = myClockWhenFrameStarted; myClockStopDisplay = myClockWhenFrameStarted + myStopDisplayOffset; myClockAtLastUpdate = myClockStartDisplay; myClocksToEndOfScanLine = 228; // Reset frame buffer pointer myFramePointer = myCurrentFrameBuffer; myFramePointerClocks = 0; // If color loss is enabled then update the color registers based on // the number of scanlines in the last frame that was generated if(myColorLossEnabled) { if(myScanlineCountForLastFrame & 0x01) { myColor[P0Color] |= 0x01; myColor[P1Color] |= 0x01; myColor[PFColor] |= 0x01; myColor[BKColor] |= 0x01; myColor[M0Color] |= 0x01; myColor[M1Color] |= 0x01; myColor[BLColor] |= 0x01; } else { myColor[P0Color] &= 0xfe; myColor[P1Color] &= 0xfe; myColor[PFColor] &= 0xfe; myColor[BKColor] &= 0xfe; myColor[M0Color] &= 0xfe; myColor[M1Color] &= 0xfe; myColor[BLColor] &= 0xfe; } } myStartScanline = 0; // Stats counters myFrameCounter++; if(myScanlineCountForLastFrame >= 287) myPALFrameCounter++; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void TIA::endFrame() { uInt32 currentlines = scanlines(); // The TIA may generate frames that are 'invisible' to TV (they complete // before the first visible scanline) // Such 'short' frames can't simply be eliminated, since they're running // code at that point; however, they are not shown at all, otherwise the // double-buffering of the video output will get confused if(currentlines <= myStartScanline) { // Skip display of this frame, as if it wasn't generated at all startFrame(); myFrameCounter--; // This frame doesn't contribute to frame count return; } // Compute the number of scanlines in the frame uInt32 previousCount = myScanlineCountForLastFrame; myScanlineCountForLastFrame = currentlines; // The following handle cases where scanlines either go too high or too // low compared to the previous frame, in which case certain portions // of the framebuffer are cleared to zero (black pixels) // Due to the FrameBuffer class (potentially) doing dirty-rectangle // updates, each internal buffer must be set slightly differently, // otherwise they won't know anything has changed // Hence, the front buffer is set to pixel 0, and the back to pixel 1 // Did we generate too many scanlines? // (usually caused by VBLANK/VSYNC taking too long or not occurring at all) // If so, blank entire viewable area if(myScanlineCountForLastFrame > myMaximumNumberOfScanlines+1) { myScanlineCountForLastFrame = myMaximumNumberOfScanlines; if(previousCount < myMaximumNumberOfScanlines) { memset(myCurrentFrameBuffer, 0, 160 * 320); memset(myPreviousFrameBuffer, 1, 160 * 320); } } // Did the number of scanlines decrease? // If so, blank scanlines that weren't rendered this frame else if(myScanlineCountForLastFrame < previousCount && myScanlineCountForLastFrame < 320 && previousCount < 320) { uInt32 offset = myScanlineCountForLastFrame * 160, stride = (previousCount - myScanlineCountForLastFrame) * 160; memset(myCurrentFrameBuffer + offset, 0, stride); memset(myPreviousFrameBuffer + offset, 1, stride); } // Recalculate framerate. attempting to auto-correct for scanline 'jumps' if(myAutoFrameEnabled) { myFramerate = (myScanlineCountForLastFrame > 285 ? 15600.0 : 15720.0) / myScanlineCountForLastFrame; myConsole.setFramerate(myFramerate); // Adjust end-of-frame pointer // We always accommodate the highest # of scanlines, up to the maximum // size of the buffer (currently, 320 lines) uInt32 offset = 228 * myScanlineCountForLastFrame; if(offset > myStopDisplayOffset && offset < 228 * 320) myStopDisplayOffset = offset; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::scanlinePos(uInt16& x, uInt16& y) const { if(myPartialFrameFlag) { // We only care about the scanline position when it's in the viewable area if(myFramePointerClocks >= myFramePointerOffset) { x = (myFramePointerClocks - myFramePointerOffset) % 160; y = (myFramePointerClocks - myFramePointerOffset) / 160; return true; } else { x = 0; y = 0; return false; } } else { x = width(); y = height(); return false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::enableBits(bool mode) { toggleBit(P0Bit, mode ? 1 : 0); toggleBit(P1Bit, mode ? 1 : 0); toggleBit(M0Bit, mode ? 1 : 0); toggleBit(M1Bit, mode ? 1 : 0); toggleBit(BLBit, mode ? 1 : 0); toggleBit(PFBit, mode ? 1 : 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::toggleBit(TIABit b, uInt8 mode) { // If mode is 0 or 1, use it as a boolean (off or on) // Otherwise, flip the state bool on = (mode == 0 || mode == 1) ? bool(mode) : !(myDisabledObjects & b); if(on) myDisabledObjects |= b; else myDisabledObjects &= ~b; return on; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::toggleBits() { myBitsEnabled = !myBitsEnabled; enableBits(myBitsEnabled); return myBitsEnabled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::enableCollisions(bool mode) { toggleCollision(P0Bit, mode ? 1 : 0); toggleCollision(P1Bit, mode ? 1 : 0); toggleCollision(M0Bit, mode ? 1 : 0); toggleCollision(M1Bit, mode ? 1 : 0); toggleCollision(BLBit, mode ? 1 : 0); toggleCollision(PFBit, mode ? 1 : 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::toggleCollision(TIABit b, uInt8 mode) { uInt16 enabled = myCollisionEnabledMask >> 16; // If mode is 0 or 1, use it as a boolean (off or on) // Otherwise, flip the state bool on = (mode == 0 || mode == 1) ? bool(mode) : !(enabled & b); if(on) enabled |= b; else enabled &= ~b; // Assume all collisions are on, then selectively turn the desired ones off uInt16 mask = 0xffff; if(!(enabled & P0Bit)) mask &= ~(Cx_M0P0 | Cx_M1P0 | Cx_P0PF | Cx_P0BL | Cx_P0P1); if(!(enabled & P1Bit)) mask &= ~(Cx_M0P1 | Cx_M1P1 | Cx_P1PF | Cx_P1BL | Cx_P0P1); if(!(enabled & M0Bit)) mask &= ~(Cx_M0P0 | Cx_M0P1 | Cx_M0PF | Cx_M0BL | Cx_M0M1); if(!(enabled & M1Bit)) mask &= ~(Cx_M1P0 | Cx_M1P1 | Cx_M1PF | Cx_M1BL | Cx_M0M1); if(!(enabled & BLBit)) mask &= ~(Cx_P0BL | Cx_P1BL | Cx_M0BL | Cx_M1BL | Cx_BLPF); if(!(enabled & PFBit)) mask &= ~(Cx_P0PF | Cx_P1PF | Cx_M0PF | Cx_M1PF | Cx_BLPF); // Now combine the masks myCollisionEnabledMask = (enabled << 16) | mask; return on; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::toggleCollisions() { myCollisionsEnabled = !myCollisionsEnabled; enableCollisions(myCollisionsEnabled); return myCollisionsEnabled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::toggleHMOVEBlank() { myAllowHMOVEBlanks = myAllowHMOVEBlanks ? false : true; return myAllowHMOVEBlanks; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::toggleFixedColors(uInt8 mode) { // If mode is 0 or 1, use it as a boolean (off or on) // Otherwise, flip the state bool on = (mode == 0 || mode == 1) ? bool(mode) : (myColorPtr == myColor ? true : false); if(on) myColorPtr = myFixedColor; else myColorPtr = myColor; // Set PriorityEncoder // This needs to be done here, since toggling debug colours also changes // how colours are interpreted in PF 'score' mode for(uInt16 x = 0; x < 2; ++x) { for(uInt16 enabled = 0; enabled < 256; ++enabled) { if(enabled & PriorityBit) { // Priority from highest to lowest: // PF/BL => P0/M0 => P1/M1 => BK uInt8 color = BKColor; if((enabled & M1Bit) != 0) color = M1Color; if((enabled & P1Bit) != 0) color = P1Color; if((enabled & M0Bit) != 0) color = M0Color; if((enabled & P0Bit) != 0) color = P0Color; if((enabled & BLBit) != 0) color = BLColor; if((enabled & PFBit) != 0) color = PFColor; // NOTE: Playfield has priority so ScoreBit isn't used myPriorityEncoder[x][enabled] = color; } else { // Priority from highest to lowest: // P0/M0 => P1/M1 => PF/BL => BK uInt8 color = BKColor; if((enabled & BLBit) != 0) color = BLColor; if((enabled & PFBit) != 0) color = (!on && (enabled & ScoreBit)) ? ((x == 0) ? P0Color : P1Color) : PFColor; if((enabled & M1Bit) != 0) color = M1Color; if((enabled & P1Bit) != 0) color = P1Color; if((enabled & M0Bit) != 0) color = M0Color; if((enabled & P0Bit) != 0) color = P0Color; myPriorityEncoder[x][enabled] = color; } } } return on; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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("tiadriven", myTIAPinsDriven); } return myTIAPinsDriven; } #ifdef DEBUGGER_SUPPORT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::updateScanline() { // Start a new frame if the old one was finished if(!myPartialFrameFlag) startFrame(); // true either way: myPartialFrameFlag = true; int totalClocks = (mySystem->cycles() * 3) - myClockWhenFrameStarted; int endClock = ((totalClocks + 228) / 228) * 228; int clock; do { mySystem->m6502().execute(1); clock = mySystem->cycles() * 3; updateFrame(clock); } while(clock < endClock); // if we finished the frame, get ready for the next one if(!myPartialFrameFlag) endFrame(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::updateScanlineByStep() { // Start a new frame if the old one was finished if(!myPartialFrameFlag) startFrame(); // true either way: myPartialFrameFlag = true; // Update frame by one CPU instruction/color clock mySystem->m6502().execute(1); updateFrame(mySystem->cycles() * 3); // if we finished the frame, get ready for the next one if(!myPartialFrameFlag) endFrame(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::updateScanlineByTrace(int target) { // Start a new frame if the old one was finished if(!myPartialFrameFlag) startFrame(); // true either way: myPartialFrameFlag = true; while(mySystem->m6502().getPC() != target) { mySystem->m6502().execute(1); updateFrame(mySystem->cycles() * 3); } // if we finished the frame, get ready for the next one if(!myPartialFrameFlag) endFrame(); } #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::updateFrame(Int32 clock) { // See if we've already updated this portion of the screen if((clock < myClockStartDisplay) || (myClockAtLastUpdate >= myClockStopDisplay) || (myClockAtLastUpdate >= clock)) return; // Truncate the number of cycles to update to the stop display point if(clock > myClockStopDisplay) clock = myClockStopDisplay; // Determine how many scanlines to process // It's easier to think about this in scanlines rather than color clocks uInt32 startLine = (myClockAtLastUpdate - myClockWhenFrameStarted) / 228; uInt32 endLine = (clock - myClockWhenFrameStarted) / 228; // Update frame one scanline at a time for(uInt32 line = startLine; line <= endLine; ++line) { // Only check for inter-line changes after the current scanline // The ideas for much of the following code was inspired by MESS // (used with permission from Wilbert Pol) if(line != startLine) { // We're no longer concerned with previously issued HMOVE's myPreviousHMOVEPos = 0x7FFFFFFF; bool posChanged = false; // Apply pending motion clocks from a HMOVE initiated during the scanline if(myCurrentHMOVEPos != 0x7FFFFFFF) { if(myCurrentHMOVEPos >= 97 && myCurrentHMOVEPos < 157) { myPOSP0 -= myMotionClockP0; if(myPOSP0 < 0) myPOSP0 += 160; myPOSP1 -= myMotionClockP1; if(myPOSP1 < 0) myPOSP1 += 160; myPOSM0 -= myMotionClockM0; if(myPOSM0 < 0) myPOSM0 += 160; myPOSM1 -= myMotionClockM1; if(myPOSM1 < 0) myPOSM1 += 160; myPOSBL -= myMotionClockBL; if(myPOSBL < 0) myPOSBL += 160; myPreviousHMOVEPos = myCurrentHMOVEPos; } // Indicate that the HMOVE has been completed myCurrentHMOVEPos = 0x7FFFFFFF; posChanged = true; } // Apply extra clocks for 'more motion required/mmr' if(myHMP0mmr) { myPOSP0 -= 17; if(myPOSP0 < 0) myPOSP0 += 160; posChanged = true; } if(myHMP1mmr) { myPOSP1 -= 17; if(myPOSP1 < 0) myPOSP1 += 160; posChanged = true; } if(myHMM0mmr) { myPOSM0 -= 17; if(myPOSM0 < 0) myPOSM0 += 160; posChanged = true; } if(myHMM1mmr) { myPOSM1 -= 17; if(myPOSM1 < 0) myPOSM1 += 160; posChanged = true; } if(myHMBLmmr) { myPOSBL -= 17; if(myPOSBL < 0) myPOSBL += 160; posChanged = true; } // Scanline change, so reset PF mask based on current CTRLPF reflection state myPFMask = TIATables::PFMask[myCTRLPF & 0x01]; // TODO - handle changes to player timing if(posChanged) { } } // Compute the number of clocks we're going to update Int32 clocksToUpdate = 0; // Remember how many clocks we are from the left side of the screen Int32 clocksFromStartOfScanLine = 228 - myClocksToEndOfScanLine; // See if we're updating more than the current scanline if(clock > (myClockAtLastUpdate + myClocksToEndOfScanLine)) { // Yes, we have more than one scanline to update so finish current one clocksToUpdate = myClocksToEndOfScanLine; myClocksToEndOfScanLine = 228; myClockAtLastUpdate += clocksToUpdate; } else { // No, so do as much of the current scanline as possible clocksToUpdate = clock - myClockAtLastUpdate; myClocksToEndOfScanLine -= clocksToUpdate; myClockAtLastUpdate = clock; } Int32 startOfScanLine = HBLANK; // Skip over as many horizontal blank clocks as we can if(clocksFromStartOfScanLine < startOfScanLine) { uInt32 tmp; if((startOfScanLine - clocksFromStartOfScanLine) < clocksToUpdate) tmp = startOfScanLine - clocksFromStartOfScanLine; else tmp = clocksToUpdate; clocksFromStartOfScanLine += tmp; clocksToUpdate -= tmp; } // Remember frame pointer in case HMOVE blanks need to be handled uInt8* oldFramePointer = myFramePointer; // Update as much of the scanline as we can if(clocksToUpdate != 0) { // Calculate the ending frame pointer value uInt8* ending = myFramePointer + clocksToUpdate; myFramePointerClocks += clocksToUpdate; // See if we're in the vertical blank region if(myVBLANK & 0x02) { memset(myFramePointer, 0, clocksToUpdate); } // Handle all other possible combinations else { // Update masks myP0Mask = &TIATables::PxMask[mySuppressP0] [myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFF)]; myP1Mask = &TIATables::PxMask[mySuppressP1] [myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFF)]; myBLMask = &TIATables::BLMask[(myCTRLPF & 0x30) >> 4] [160 - (myPOSBL & 0xFF)]; // TODO - 08-27-2009: Simulate the weird effects of Cosmic Ark and // Stay Frosty. The movement itself is well understood, but there // also seems to be some widening and blanking occurring as well. // This doesn't properly emulate the effect at a low level; it only // simulates the behaviour as visually seen in the aforementioned // ROMs. Other ROMs may break this simulation; more testing is // required to figure out what's really going on here. if(myHMM0mmr) { switch(myPOSM0 % 4) { case 3: // Stretch this missle so it's 2 pixels wide and shifted one // pixel to the left myM0Mask = &TIATables::MxMask[myNUSIZ0 & 0x07] [((myNUSIZ0 & 0x30) >> 4)|1][160 - ((myPOSM0-1) & 0xFF)]; break; case 2: // Missle is disabled on this line myM0Mask = &TIATables::DisabledMask[0]; break; default: myM0Mask = &TIATables::MxMask[myNUSIZ0 & 0x07] [(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFF)]; break; } } else myM0Mask = &TIATables::MxMask[myNUSIZ0 & 0x07] [(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFF)]; if(myHMM1mmr) { switch(myPOSM1 % 4) { case 3: // Stretch this missle so it's 2 pixels wide and shifted one // pixel to the left myM1Mask = &TIATables::MxMask[myNUSIZ1 & 0x07] [((myNUSIZ1 & 0x30) >> 4)|1][160 - ((myPOSM1-1) & 0xFF)]; break; case 2: // Missle is disabled on this line myM1Mask = &TIATables::DisabledMask[0]; break; default: myM1Mask = &TIATables::MxMask[myNUSIZ1 & 0x07] [(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFF)]; break; } } else myM1Mask = &TIATables::MxMask[myNUSIZ1 & 0x07] [(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFF)]; uInt8 enabledObjects = myEnabledObjects & myDisabledObjects; uInt32 hpos = clocksFromStartOfScanLine - HBLANK; for(; myFramePointer < ending; ++myFramePointer, ++hpos) { uInt8 enabled = ((enabledObjects & PFBit) && (myPF & myPFMask[hpos])) ? PFBit : 0; if((enabledObjects & BLBit) && myBLMask[hpos]) enabled |= BLBit; if((enabledObjects & P1Bit) && (myCurrentGRP1 & myP1Mask[hpos])) enabled |= P1Bit; if((enabledObjects & M1Bit) && myM1Mask[hpos]) enabled |= M1Bit; if((enabledObjects & P0Bit) && (myCurrentGRP0 & myP0Mask[hpos])) enabled |= P0Bit; if((enabledObjects & M0Bit) && myM0Mask[hpos]) enabled |= M0Bit; myCollision |= TIATables::CollisionMask[enabled]; *myFramePointer = myColorPtr[myPriorityEncoder[hpos < 80 ? 0 : 1] [enabled | myPlayfieldPriorityAndScore]]; } } myFramePointer = ending; } // Handle HMOVE blanks if they are enabled if(myHMOVEBlankEnabled && (startOfScanLine < HBLANK + 8) && (clocksFromStartOfScanLine < (HBLANK + 8))) { Int32 blanks = (HBLANK + 8) - clocksFromStartOfScanLine; memset(oldFramePointer, myColorPtr[HBLANKColor], blanks); if((clocksToUpdate + clocksFromStartOfScanLine) >= (HBLANK + 8)) myHMOVEBlankEnabled = false; } // TODO - this needs to be updated to actually do as the comment suggests #if 1 // See if we're at the end of a scanline if(myClocksToEndOfScanLine == 228) { // TODO - 01-21-99: These should be reset right after the first copy // of the player has passed. However, for now we'll just reset at the // end of the scanline since the other way would be too slow. mySuppressP0 = mySuppressP1 = 0; } #endif } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void TIA::waitHorizontalSync() { uInt32 cyclesToEndOfLine = 76 - ((mySystem->cycles() - (myClockWhenFrameStarted / 3)) % 76); if(cyclesToEndOfLine < 76) mySystem->incrementCycles(cyclesToEndOfLine); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void TIA::waitHorizontalRSync() { // 02-23-2013: RSYNC has now been updated to work correctly with // Extra-Terrestrials. Fatal Run also uses RSYNC (in its VSYNC routine), // and the NTSC prototype now displays 262 scanlines instead of 261. // What is not emulated correctly is the "real time" effects. For example // the VSYNC signal may not be 3 complete scanlines, although Stella will // now count it as such. // // There are two extreme cases to demonstrate this "real time" variance // effect over a proper three line VSYNC. 3*76 = 228 cycles properly needed: // // ====== SHORT TIME CASE ====== // // lda #3 ;2 @67 // sta VSYNC ;3 @70 vsync starts // sta RSYNC ;3 @73 +3 // sta WSYNC ;3 @76 +6 // ------------------------------ // sta WSYNC ;3 @76 +82 // ------------------------------ // lda #0 ;2 @2 +84 // sta VSYNC vsync ends // // ====== LONG TIME CASE ====== // // lda #3 ;2 @70 // sta VSYNC ;3 @73 vsync starts // sta RSYNC ;3 @74 +3 // sta WSYNC ;3 @.. +81 2 cycles are added to previous line, and then // WSYNC halts the new line delaying 78 cycles total! //------------------------------ // sta WSYNC ;3 @76 +157 //------------------------------ // lda #0 ;2 @2 +159 // sta VSYNC vsync ends // The significance of the 'magic numbers' below is as follows (thanks to // Eckhard Stolberg and Omegamatrix for explanation and implementation) // // Objects always get positioned three pixels further to the right after a // WSYNC than they do after a RSYNC, but this is to be expected. Triggering // WSYNC will halt the CPU until the horizontal sync counter wraps around to zero. // Triggering RSYNC will reset the horizontal sync counter to zero immediately. // But the warp-around will actually happen after one more cycle of this counter. // Since the horizontal sync counter counts once every 4 pixels, one more CPU // cycle occurs before the counter warps around to zero. Therefore the positioning // code will hit RESPx one cycle sooner after a RSYNC than after a WSYNC. uInt32 cyclesToEndOfLine = 76 - ((mySystem->cycles() - (myClockWhenFrameStarted / 3)) % 76); mySystem->incrementCycles(cyclesToEndOfLine-1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::clearBuffers() { memset(myCurrentFrameBuffer, 0, 160 * 320); memset(myPreviousFrameBuffer, 0, 160 * 320); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline uInt8 TIA::dumpedInputPort(int resistance) { if(resistance == Controller::minimumResistance) { return 0x80; } else if((resistance == Controller::maximumResistance) || myDumpEnabled) { return 0x00; } else { // Constant here is derived from '1.6 * 0.01e-6 * 228 / 3' uInt32 needed = (uInt32) (1.216e-6 * resistance * myScanlineCountForLastFrame * myFramerate); if((mySystem->cycles() - myDumpDisabledCycle) > needed) return 0x80; else return 0x00; } return 0x00; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIA::peek(uInt16 addr) { // Update frame to current color clock before we look at anything! updateFrame(mySystem->cycles() * 3); // 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 value = 0x3F & (!myTIAPinsDriven ? mySystem->getDataBusState() : mySystem->getDataBusState(0xFF)); uInt16 collision = myCollision & (uInt16)myCollisionEnabledMask; switch(addr & 0x000f) { case CXM0P: value |= ((collision & Cx_M0P1) ? 0x80 : 0x00) | ((collision & Cx_M0P0) ? 0x40 : 0x00); break; case CXM1P: value |= ((collision & Cx_M1P0) ? 0x80 : 0x00) | ((collision & Cx_M1P1) ? 0x40 : 0x00); break; case CXP0FB: value |= ((collision & Cx_P0PF) ? 0x80 : 0x00) | ((collision & Cx_P0BL) ? 0x40 : 0x00); break; case CXP1FB: value |= ((collision & Cx_P1PF) ? 0x80 : 0x00) | ((collision & Cx_P1BL) ? 0x40 : 0x00); break; case CXM0FB: value |= ((collision & Cx_M0PF) ? 0x80 : 0x00) | ((collision & Cx_M0BL) ? 0x40 : 0x00); break; case CXM1FB: value |= ((collision & Cx_M1PF) ? 0x80 : 0x00) | ((collision & Cx_M1BL) ? 0x40 : 0x00); break; case CXBLPF: value = (value & 0x7F) | ((collision & Cx_BLPF) ? 0x80 : 0x00); break; case CXPPMM: value |= ((collision & Cx_P0P1) ? 0x80 : 0x00) | ((collision & Cx_M0M1) ? 0x40 : 0x00); break; case INPT0: value = (value & 0x7F) | dumpedInputPort(myConsole.controller(Controller::Left).read(Controller::Nine)); break; case INPT1: value = (value & 0x7F) | dumpedInputPort(myConsole.controller(Controller::Left).read(Controller::Five)); break; case INPT2: value = (value & 0x7F) | dumpedInputPort(myConsole.controller(Controller::Right).read(Controller::Nine)); break; case INPT3: value = (value & 0x7F) | dumpedInputPort(myConsole.controller(Controller::Right).read(Controller::Five)); break; case INPT4: { uInt8 button = (myConsole.controller(Controller::Left).read(Controller::Six) ? 0x80 : 0x00); myINPT4 = (myVBLANK & 0x40) ? (myINPT4 & button) : button; value = (value & 0x7F) | myINPT4; break; } case INPT5: { uInt8 button = (myConsole.controller(Controller::Right).read(Controller::Six) ? 0x80 : 0x00); myINPT5 = (myVBLANK & 0x40) ? (myINPT5 & button) : button; value = (value & 0x7F) | myINPT5; break; } default: // This shouldn't happen, but if it does, we essentially just // return the last databus value with bits D6 and D7 zeroed out break; } return value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::poke(uInt16 addr, uInt8 value) { addr = addr & 0x003f; Int32 clock = mySystem->cycles() * 3; Int16 delay = TIATables::PokeDelay[addr]; // See if this is a poke to a PF register if(delay == -1) { static uInt32 d[4] = {4, 5, 2, 3}; Int32 x = ((clock - myClockWhenFrameStarted) % 228); delay = d[(x / 3) & 3]; } // Update frame to current CPU cycle before we make any changes! updateFrame(clock + delay); // If a VSYNC hasn't been generated in time go ahead and end the frame if(((clock - myClockWhenFrameStarted) / 228) >= (Int32)myMaximumNumberOfScanlines) { mySystem->m6502().stop(); myPartialFrameFlag = false; } switch(addr) { case VSYNC: // Vertical sync set-clear { myVSYNC = value; if(myVSYNC & 0x02) { // Indicate when VSYNC should be finished. This should really // be 3 * 228 according to Atari's documentation, however, some // games don't supply the full 3 scanlines of VSYNC. myVSYNCFinishClock = clock + 228; } else if(!(myVSYNC & 0x02) && (clock >= myVSYNCFinishClock)) { // We're no longer interested in myVSYNCFinishClock myVSYNCFinishClock = 0x7FFFFFFF; // Since we're finished with the frame tell the processor to halt mySystem->m6502().stop(); myPartialFrameFlag = false; } break; } case VBLANK: // Vertical blank set-clear { // Is the dump to ground path being set for I0, I1, I2, and I3? if(!(myVBLANK & 0x80) && (value & 0x80)) { myDumpEnabled = true; } // Is the dump to ground path being removed from I0, I1, I2, and I3? else if((myVBLANK & 0x80) && !(value & 0x80)) { myDumpEnabled = false; myDumpDisabledCycle = mySystem->cycles(); } // Are the latches for I4 and I5 being reset? if (!(myVBLANK & 0x40)) myINPT4 = myINPT5 = 0x80; // Check for the first scanline at which VBLANK is disabled. // Usually, this will be the first scanline to start drawing. if(myStartScanline == 0 && !(value & 0x10)) myStartScanline = scanlines(); myVBLANK = value; break; } case WSYNC: // Wait for leading edge of HBLANK { // It appears that the 6507 only halts during a read cycle so // we test here for follow-on writes which should be ignored as // far as halting the processor is concerned. // // TODO - 08-30-2006: This halting isn't correct since it's // still halting on the original write. The 6507 emulation // should be expanded to include a READY line. if(mySystem->m6502().lastAccessWasRead()) { // Tell the cpu to waste the necessary amount of time waitHorizontalSync(); } break; } case RSYNC: // Reset horizontal sync counter { waitHorizontalRSync(); break; } case NUSIZ0: // Number-size of player-missle 0 { // TODO - 08-11-2009: determine correct delay instead of always // using '8' in TIATables::PokeDelay updateFrame(clock + 8); myNUSIZ0 = value; mySuppressP0 = 0; break; } case NUSIZ1: // Number-size of player-missle 1 { // TODO - 08-11-2009: determine correct delay instead of always // using '8' in TIATables::PokeDelay updateFrame(clock + 8); myNUSIZ1 = value; mySuppressP1 = 0; break; } case COLUP0: // Color-Luminance Player 0 { uInt8 color = value & 0xfe; if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01)) color |= 0x01; myColor[P0Color] = myColor[M0Color] = color; break; } case COLUP1: // Color-Luminance Player 1 { uInt8 color = value & 0xfe; if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01)) color |= 0x01; myColor[P1Color] = myColor[M1Color] = color; break; } case COLUPF: // Color-Luminance Playfield { uInt8 color = value & 0xfe; if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01)) color |= 0x01; myColor[PFColor] = myColor[BLColor] = color; break; } case COLUBK: // Color-Luminance Background { uInt8 color = value & 0xfe; if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01)) color |= 0x01; myColor[BKColor] = color; break; } case CTRLPF: // Control Playfield, Ball size, Collisions { myCTRLPF = value; // The playfield priority and score bits from the control register // are accessed when the frame is being drawn. We precompute the // necessary value here so we can save time while drawing. myPlayfieldPriorityAndScore = ((myCTRLPF & 0x06) << 5); // Update the playfield mask based on reflection state if // we're still on the left hand side of the playfield if(((clock - myClockWhenFrameStarted) % 228) < (68 + 79)) myPFMask = TIATables::PFMask[myCTRLPF & 0x01]; break; } case REFP0: // Reflect Player 0 { // See if the reflection state of the player is being changed if(((value & 0x08) && !myREFP0) || (!(value & 0x08) && myREFP0)) { myREFP0 = (value & 0x08); myCurrentGRP0 = TIATables::GRPReflect[myCurrentGRP0]; } break; } case REFP1: // Reflect Player 1 { // See if the reflection state of the player is being changed if(((value & 0x08) && !myREFP1) || (!(value & 0x08) && myREFP1)) { myREFP1 = (value & 0x08); myCurrentGRP1 = TIATables::GRPReflect[myCurrentGRP1]; } break; } case PF0: // Playfield register byte 0 { myPF = (myPF & 0x000FFFF0) | ((value >> 4) & 0x0F); if(myPF == 0) myEnabledObjects &= ~PFBit; else myEnabledObjects |= PFBit; #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) mySystem->setAccessFlags(dataAddr, CartDebug::PGFX); #endif break; } case PF1: // Playfield register byte 1 { myPF = (myPF & 0x000FF00F) | ((uInt32)value << 4); if(myPF == 0) myEnabledObjects &= ~PFBit; else myEnabledObjects |= PFBit; #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) mySystem->setAccessFlags(dataAddr, CartDebug::PGFX); #endif break; } case PF2: // Playfield register byte 2 { myPF = (myPF & 0x00000FFF) | ((uInt32)value << 12); if(myPF == 0) myEnabledObjects &= ~PFBit; else myEnabledObjects |= PFBit; #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) mySystem->setAccessFlags(dataAddr, CartDebug::PGFX); #endif break; } case RESP0: // Reset Player 0 { Int32 hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; Int16 newx; // Check if HMOVE is currently active if(myCurrentHMOVEPos != 0x7FFFFFFF) { newx = hpos < 7 ? 3 : ((hpos + 5) % 160); // If HMOVE is active, adjust for any remaining horizontal move clocks applyActiveHMOVEMotion(hpos, newx, myMotionClockP0); } else { newx = hpos < -2 ? 3 : ((hpos + 5) % 160); applyPreviousHMOVEMotion(hpos, newx, myHMP0); } if(myPOSP0 != newx) { // TODO - update player timing // Find out under what condition the player is being reset delay = TIATables::PxPosResetWhen[myNUSIZ0 & 7][myPOSP0][newx]; switch(delay) { // Player is being reset during the display of one of its copies case 1: // TODO - 08-20-2009: determine whether we really need to update // the frame here, and also come up with a way to eliminate the // 200KB PxPosResetWhen table. updateFrame(clock + 11); mySuppressP0 = 1; break; // Player is being reset in neither the delay nor display section case 0: mySuppressP0 = 1; break; // Player is being reset during the delay section of one of its copies case -1: mySuppressP0 = 0; break; } myPOSP0 = newx; } break; } case RESP1: // Reset Player 1 { Int32 hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; Int16 newx; // Check if HMOVE is currently active if(myCurrentHMOVEPos != 0x7FFFFFFF) { newx = hpos < 7 ? 3 : ((hpos + 5) % 160); // If HMOVE is active, adjust for any remaining horizontal move clocks applyActiveHMOVEMotion(hpos, newx, myMotionClockP1); } else { newx = hpos < -2 ? 3 : ((hpos + 5) % 160); applyPreviousHMOVEMotion(hpos, newx, myHMP1); } if(myPOSP1 != newx) { // TODO - update player timing // Find out under what condition the player is being reset delay = TIATables::PxPosResetWhen[myNUSIZ1 & 7][myPOSP1][newx]; switch(delay) { // Player is being reset during the display of one of its copies case 1: // TODO - 08-20-2009: determine whether we really need to update // the frame here, and also come up with a way to eliminate the // 200KB PxPosResetWhen table. updateFrame(clock + 11); mySuppressP1 = 1; break; // Player is being reset in neither the delay nor display section case 0: mySuppressP1 = 1; break; // Player is being reset during the delay section of one of its copies case -1: mySuppressP1 = 0; break; } myPOSP1 = newx; } break; } case RESM0: // Reset Missle 0 { Int32 hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; Int16 newx; // Check if HMOVE is currently active if(myCurrentHMOVEPos != 0x7FFFFFFF) { newx = hpos < 7 ? 2 : ((hpos + 4) % 160); // If HMOVE is active, adjust for any remaining horizontal move clocks applyActiveHMOVEMotion(hpos, newx, myMotionClockM0); } else { newx = hpos < -1 ? 2 : ((hpos + 4) % 160); applyPreviousHMOVEMotion(hpos, newx, myHMM0); } if(newx != myPOSM0) { myPOSM0 = newx; } break; } case RESM1: // Reset Missle 1 { Int32 hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; Int16 newx; // Check if HMOVE is currently active if(myCurrentHMOVEPos != 0x7FFFFFFF) { newx = hpos < 7 ? 2 : ((hpos + 4) % 160); // If HMOVE is active, adjust for any remaining horizontal move clocks applyActiveHMOVEMotion(hpos, newx, myMotionClockM1); } else { newx = hpos < -1 ? 2 : ((hpos + 4) % 160); applyPreviousHMOVEMotion(hpos, newx, myHMM1); } if(newx != myPOSM1) { myPOSM1 = newx; } break; } case RESBL: // Reset Ball { Int32 hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; // Check if HMOVE is currently active if(myCurrentHMOVEPos != 0x7FFFFFFF) { myPOSBL = hpos < 7 ? 2 : ((hpos + 4) % 160); // If HMOVE is active, adjust for any remaining horizontal move clocks applyActiveHMOVEMotion(hpos, myPOSBL, myMotionClockBL); } else { myPOSBL = hpos < 0 ? 2 : ((hpos + 4) % 160); applyPreviousHMOVEMotion(hpos, myPOSBL, myHMBL); } break; } case AUDC0: // Audio control 0 { myAUDC0 = value & 0x0f; mySound.set(addr, value, mySystem->cycles()); break; } case AUDC1: // Audio control 1 { myAUDC1 = value & 0x0f; mySound.set(addr, value, mySystem->cycles()); break; } case AUDF0: // Audio frequency 0 { myAUDF0 = value & 0x1f; mySound.set(addr, value, mySystem->cycles()); break; } case AUDF1: // Audio frequency 1 { myAUDF1 = value & 0x1f; mySound.set(addr, value, mySystem->cycles()); break; } case AUDV0: // Audio volume 0 { myAUDV0 = value & 0x0f; mySound.set(addr, value, mySystem->cycles()); break; } case AUDV1: // Audio volume 1 { myAUDV1 = value & 0x0f; mySound.set(addr, value, mySystem->cycles()); break; } case GRP0: // Graphics Player 0 { // Set player 0 graphics myGRP0 = value; // Copy player 1 graphics into its delayed register myDGRP1 = myGRP1; // Get the "current" data for GRP0 base on delay register and reflect uInt8 grp0 = myVDELP0 ? myDGRP0 : myGRP0; myCurrentGRP0 = myREFP0 ? TIATables::GRPReflect[grp0] : grp0; // Get the "current" data for GRP1 base on delay register and reflect uInt8 grp1 = myVDELP1 ? myDGRP1 : myGRP1; myCurrentGRP1 = myREFP1 ? TIATables::GRPReflect[grp1] : grp1; // Set enabled object bits if(myCurrentGRP0 != 0) myEnabledObjects |= P0Bit; else myEnabledObjects &= ~P0Bit; if(myCurrentGRP1 != 0) myEnabledObjects |= P1Bit; else myEnabledObjects &= ~P1Bit; #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) mySystem->setAccessFlags(dataAddr, CartDebug::GFX); #endif break; } case GRP1: // Graphics Player 1 { // Set player 1 graphics myGRP1 = value; // Copy player 0 graphics into its delayed register myDGRP0 = myGRP0; // Copy ball graphics into its delayed register myDENABL = myENABL; // Get the "current" data for GRP0 base on delay register uInt8 grp0 = myVDELP0 ? myDGRP0 : myGRP0; myCurrentGRP0 = myREFP0 ? TIATables::GRPReflect[grp0] : grp0; // Get the "current" data for GRP1 base on delay register uInt8 grp1 = myVDELP1 ? myDGRP1 : myGRP1; myCurrentGRP1 = myREFP1 ? TIATables::GRPReflect[grp1] : grp1; // Set enabled object bits if(myCurrentGRP0 != 0) myEnabledObjects |= P0Bit; else myEnabledObjects &= ~P0Bit; if(myCurrentGRP1 != 0) myEnabledObjects |= P1Bit; else myEnabledObjects &= ~P1Bit; if(myVDELBL ? myDENABL : myENABL) myEnabledObjects |= BLBit; else myEnabledObjects &= ~BLBit; #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) mySystem->setAccessFlags(dataAddr, CartDebug::GFX); #endif break; } case ENAM0: // Enable Missile 0 graphics { myENAM0 = value & 0x02; if(myENAM0 && !myRESMP0) myEnabledObjects |= M0Bit; else myEnabledObjects &= ~M0Bit; break; } case ENAM1: // Enable Missile 1 graphics { myENAM1 = value & 0x02; if(myENAM1 && !myRESMP1) myEnabledObjects |= M1Bit; else myEnabledObjects &= ~M1Bit; break; } case ENABL: // Enable Ball graphics { myENABL = value & 0x02; if(myVDELBL ? myDENABL : myENABL) myEnabledObjects |= BLBit; else myEnabledObjects &= ~BLBit; break; } case HMP0: // Horizontal Motion Player 0 { pokeHMP0(value, clock); break; } case HMP1: // Horizontal Motion Player 1 { pokeHMP1(value, clock); break; } case HMM0: // Horizontal Motion Missle 0 { pokeHMM0(value, clock); break; } case HMM1: // Horizontal Motion Missle 1 { pokeHMM1(value, clock); break; } case HMBL: // Horizontal Motion Ball { pokeHMBL(value, clock); break; } case VDELP0: // Vertical Delay Player 0 { myVDELP0 = value & 0x01; uInt8 grp0 = myVDELP0 ? myDGRP0 : myGRP0; myCurrentGRP0 = myREFP0 ? TIATables::GRPReflect[grp0] : grp0; if(myCurrentGRP0 != 0) myEnabledObjects |= P0Bit; else myEnabledObjects &= ~P0Bit; break; } case VDELP1: // Vertical Delay Player 1 { myVDELP1 = value & 0x01; uInt8 grp1 = myVDELP1 ? myDGRP1 : myGRP1; myCurrentGRP1 = myREFP1 ? TIATables::GRPReflect[grp1] : grp1; if(myCurrentGRP1 != 0) myEnabledObjects |= P1Bit; else myEnabledObjects &= ~P1Bit; break; } case VDELBL: // Vertical Delay Ball { myVDELBL = value & 0x01; if(myVDELBL ? myDENABL : myENABL) myEnabledObjects |= BLBit; else myEnabledObjects &= ~BLBit; break; } case RESMP0: // Reset missle 0 to player 0 { if(myRESMP0 && !(value & 0x02)) { uInt16 middle = 4; switch(myNUSIZ0 & 0x07) { // 1-pixel delay is taken care of in TIATables::PxMask case 0x05: middle = 8; break; // double size case 0x07: middle = 16; break; // quad size } myPOSM0 = myPOSP0 + middle; if(myCurrentHMOVEPos != 0x7FFFFFFF) { myPOSM0 -= (8 - myMotionClockP0); myPOSM0 += (8 - myMotionClockM0); } CLAMP_POS(myPOSM0); } myRESMP0 = value & 0x02; if(myENAM0 && !myRESMP0) myEnabledObjects |= M0Bit; else myEnabledObjects &= ~M0Bit; break; } case RESMP1: // Reset missle 1 to player 1 { if(myRESMP1 && !(value & 0x02)) { uInt16 middle = 4; switch(myNUSIZ1 & 0x07) { // 1-pixel delay is taken care of in TIATables::PxMask case 0x05: middle = 8; break; // double size case 0x07: middle = 16; break; // quad size } myPOSM1 = myPOSP1 + middle; if(myCurrentHMOVEPos != 0x7FFFFFFF) { myPOSM1 -= (8 - myMotionClockP1); myPOSM1 += (8 - myMotionClockM1); } CLAMP_POS(myPOSM1); } myRESMP1 = value & 0x02; if(myENAM1 && !myRESMP1) myEnabledObjects |= M1Bit; else myEnabledObjects &= ~M1Bit; break; } case HMOVE: // Apply horizontal motion { int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; myCurrentHMOVEPos = hpos; // See if we need to enable the HMOVE blank bug myHMOVEBlankEnabled = myAllowHMOVEBlanks ? TIATables::HMOVEBlankEnableCycles[((clock - myClockWhenFrameStarted) % 228) / 3] : false; // Do we have to undo some of the already applied cycles from an // active graphics latch? if(hpos + HBLANK < 17 * 4) { Int16 cycle_fix = 17 - ((hpos + HBLANK + 7) / 4); if(myHMP0mmr) myPOSP0 = (myPOSP0 + cycle_fix) % 160; if(myHMP1mmr) myPOSP1 = (myPOSP1 + cycle_fix) % 160; if(myHMM0mmr) myPOSM0 = (myPOSM0 + cycle_fix) % 160; if(myHMM1mmr) myPOSM1 = (myPOSM1 + cycle_fix) % 160; if(myHMBLmmr) myPOSBL = (myPOSBL + cycle_fix) % 160; } myHMP0mmr = myHMP1mmr = myHMM0mmr = myHMM1mmr = myHMBLmmr = false; // Can HMOVE activities be ignored? if(hpos >= -5 && hpos < 97 ) { myMotionClockP0 = 0; myMotionClockP1 = 0; myMotionClockM0 = 0; myMotionClockM1 = 0; myMotionClockBL = 0; myHMOVEBlankEnabled = false; myCurrentHMOVEPos = 0x7FFFFFFF; break; } myMotionClockP0 = (myHMP0 ^ 0x80) >> 4; myMotionClockP1 = (myHMP1 ^ 0x80) >> 4; myMotionClockM0 = (myHMM0 ^ 0x80) >> 4; myMotionClockM1 = (myHMM1 ^ 0x80) >> 4; myMotionClockBL = (myHMBL ^ 0x80) >> 4; // Adjust number of graphics motion clocks for active display if(hpos >= 97 && hpos < 151) { Int16 skip_motclks = (160 - myCurrentHMOVEPos - 6) >> 2; myMotionClockP0 -= skip_motclks; myMotionClockP1 -= skip_motclks; myMotionClockM0 -= skip_motclks; myMotionClockM1 -= skip_motclks; myMotionClockBL -= skip_motclks; if(myMotionClockP0 < 0) myMotionClockP0 = 0; if(myMotionClockP1 < 0) myMotionClockP1 = 0; if(myMotionClockM0 < 0) myMotionClockM0 = 0; if(myMotionClockM1 < 0) myMotionClockM1 = 0; if(myMotionClockBL < 0) myMotionClockBL = 0; } if(hpos >= -56 && hpos < -5) { Int16 max_motclks = (7 - (myCurrentHMOVEPos + 5)) >> 2; if(myMotionClockP0 > max_motclks) myMotionClockP0 = max_motclks; if(myMotionClockP1 > max_motclks) myMotionClockP1 = max_motclks; if(myMotionClockM0 > max_motclks) myMotionClockM0 = max_motclks; if(myMotionClockM1 > max_motclks) myMotionClockM1 = max_motclks; if(myMotionClockBL > max_motclks) myMotionClockBL = max_motclks; } // Apply horizontal motion if(hpos < -5 || hpos >= 157) { myPOSP0 += 8 - myMotionClockP0; myPOSP1 += 8 - myMotionClockP1; myPOSM0 += 8 - myMotionClockM0; myPOSM1 += 8 - myMotionClockM1; myPOSBL += 8 - myMotionClockBL; } // Make sure positions are in range CLAMP_POS(myPOSP0); CLAMP_POS(myPOSP1); CLAMP_POS(myPOSM0); CLAMP_POS(myPOSM1); CLAMP_POS(myPOSBL); // TODO - handle late HMOVE's mySuppressP0 = mySuppressP1 = 0; break; } case HMCLR: // Clear horizontal motion registers { pokeHMP0(0, clock); pokeHMP1(0, clock); pokeHMM0(0, clock); pokeHMM1(0, clock); pokeHMBL(0, clock); break; } case CXCLR: // Clear collision latches { myCollision = 0; break; } default: { #ifdef DEBUG_ACCESSES cerr << "BAD TIA Poke: " << hex << addr << endl; #endif break; } } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Note that the following methods to change the horizontal motion registers // are not completely accurate. We should be taking care of the following // explanation from A. Towers Hardware Notes: // // Much more interesting is this: if the counter has not yet // reached the value in HMxx (or has reached it but not yet // commited the comparison) and a value with at least one bit // in common with all remaining internal counter states is // written (zeros or ones), the stopping condition will never be // reached and the object will be moved a full 15 pixels left. // In addition to this, the HMOVE will complete without clearing // the "more movement required" latch, and so will continue to send // an additional clock signal every 4 CLK (during visible and // non-visible parts of the scanline) until another HMOVE operation // clears the latch. The HMCLR command does not reset these latches. // // This condition is what causes the 'starfield effect' in Cosmic Ark, // and the 'snow' in Stay Frosty. Ideally, we'd trace the counter and // do a compare every colour clock, updating the horizontal positions // when applicable. We can save time by cheating, and noting that the // effect only occurs for 'magic numbers' 0x70 and 0x80. // // Most of the ideas in these methods come from MESS. // (used with permission from Wilbert Pol) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::pokeHMP0(uInt8 value, Int32 clock) { value &= 0xF0; if(myHMP0 == value) return; int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; // Check if HMOVE is currently active if(myCurrentHMOVEPos != 0x7FFFFFFF && hpos < BSPF_min(myCurrentHMOVEPos + 6 + myMotionClockP0 * 4, 7)) { Int32 newMotion = (value ^ 0x80) >> 4; // Check if new horizontal move can still be applied normally if(newMotion > myMotionClockP0 || hpos <= BSPF_min(myCurrentHMOVEPos + 6 + newMotion * 4, 7)) { myPOSP0 -= (newMotion - myMotionClockP0); myMotionClockP0 = newMotion; } else { myPOSP0 -= (15 - myMotionClockP0); myMotionClockP0 = 15; if(value != 0x70 && value != 0x80) myHMP0mmr = true; } CLAMP_POS(myPOSP0); // TODO - adjust player timing } myHMP0 = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::pokeHMP1(uInt8 value, Int32 clock) { value &= 0xF0; if(myHMP1 == value) return; int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; // Check if HMOVE is currently active if(myCurrentHMOVEPos != 0x7FFFFFFF && hpos < BSPF_min(myCurrentHMOVEPos + 6 + myMotionClockP1 * 4, 7)) { Int32 newMotion = (value ^ 0x80) >> 4; // Check if new horizontal move can still be applied normally if(newMotion > myMotionClockP1 || hpos <= BSPF_min(myCurrentHMOVEPos + 6 + newMotion * 4, 7)) { myPOSP1 -= (newMotion - myMotionClockP1); myMotionClockP1 = newMotion; } else { myPOSP1 -= (15 - myMotionClockP1); myMotionClockP1 = 15; if(value != 0x70 && value != 0x80) myHMP1mmr = true; } CLAMP_POS(myPOSP1); // TODO - adjust player timing } myHMP1 = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::pokeHMM0(uInt8 value, Int32 clock) { value &= 0xF0; if(myHMM0 == value) return; int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; // Check if HMOVE is currently active if(myCurrentHMOVEPos != 0x7FFFFFFF && hpos < BSPF_min(myCurrentHMOVEPos + 6 + myMotionClockM0 * 4, 7)) { Int32 newMotion = (value ^ 0x80) >> 4; // Check if new horizontal move can still be applied normally if(newMotion > myMotionClockM0 || hpos <= BSPF_min(myCurrentHMOVEPos + 6 + newMotion * 4, 7)) { myPOSM0 -= (newMotion - myMotionClockM0); myMotionClockM0 = newMotion; } else { myPOSM0 -= (15 - myMotionClockM0); myMotionClockM0 = 15; if(value != 0x70 && value != 0x80) myHMM0mmr = true; } CLAMP_POS(myPOSM0); } myHMM0 = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::pokeHMM1(uInt8 value, Int32 clock) { value &= 0xF0; if(myHMM1 == value) return; int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; // Check if HMOVE is currently active if(myCurrentHMOVEPos != 0x7FFFFFFF && hpos < BSPF_min(myCurrentHMOVEPos + 6 + myMotionClockM1 * 4, 7)) { Int32 newMotion = (value ^ 0x80) >> 4; // Check if new horizontal move can still be applied normally if(newMotion > myMotionClockM1 || hpos <= BSPF_min(myCurrentHMOVEPos + 6 + newMotion * 4, 7)) { myPOSM1 -= (newMotion - myMotionClockM1); myMotionClockM1 = newMotion; } else { myPOSM1 -= (15 - myMotionClockM1); myMotionClockM1 = 15; if(value != 0x70 && value != 0x80) myHMM1mmr = true; } CLAMP_POS(myPOSM1); } myHMM1 = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::pokeHMBL(uInt8 value, Int32 clock) { value &= 0xF0; if(myHMBL == value) return; int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; // Check if HMOVE is currently active if(myCurrentHMOVEPos != 0x7FFFFFFF && hpos < BSPF_min(myCurrentHMOVEPos + 6 + myMotionClockBL * 4, 7)) { Int32 newMotion = (value ^ 0x80) >> 4; // Check if new horizontal move can still be applied normally if(newMotion > myMotionClockBL || hpos <= BSPF_min(myCurrentHMOVEPos + 6 + newMotion * 4, 7)) { myPOSBL -= (newMotion - myMotionClockBL); myMotionClockBL = newMotion; } else { myPOSBL -= (15 - myMotionClockBL); myMotionClockBL = 15; if(value != 0x70 && value != 0x80) myHMBLmmr = true; } CLAMP_POS(myPOSBL); } myHMBL = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // The following two methods apply extra clocks when a horizontal motion // register (HMxx) is modified during an HMOVE, before waiting for the // documented time of at least 24 CPU cycles. The applicable explanation // from A. Towers Hardware Notes is as follows: // // In theory then the side effects of modifying the HMxx registers // during HMOVE should be quite straight-forward. If the internal // counter has not yet reached the value in HMxx, a new value greater // than this (in 0-15 terms) will work normally. Conversely, if // the counter has already reached the value in HMxx, new values // will have no effect because the latch will have been cleared. // // Most of the ideas in these methods come from MESS. // (used with permission from Wilbert Pol) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void TIA::applyActiveHMOVEMotion(int hpos, Int16& pos, Int32 motionClock) { if(hpos < BSPF_min(myCurrentHMOVEPos + 6 + 16 * 4, 7)) { Int32 decrements_passed = (hpos - (myCurrentHMOVEPos + 4)) >> 2; pos += 8; if((motionClock - decrements_passed) > 0) { pos -= (motionClock - decrements_passed); if(pos < 0) pos += 160; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void TIA::applyPreviousHMOVEMotion(int hpos, Int16& pos, uInt8 motion) { if(myPreviousHMOVEPos != 0x7FFFFFFF) { uInt8 motclk = (motion ^ 0x80) >> 4; if(hpos <= myPreviousHMOVEPos - 228 + 5 + motclk * 4) { uInt8 motclk_passed = (hpos - (myPreviousHMOVEPos - 228 + 6)) >> 2; pos -= (motclk - motclk_passed); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TIA::TIA(const TIA& c) : myConsole(c.myConsole), mySound(c.mySound), mySettings(c.mySettings) { assert(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TIA& TIA::operator = (const TIA&) { assert(false); return *this; } stella-3.9.3/src/emucore/TIATables.hxx0000644000175000001440000002025712266336753017151 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TIATables.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef TIA_TABLES_HXX #define TIA_TABLES_HXX #include "bspf.hxx" 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 CollisionBit { Cx_M0P1 = 1 << 0, // Missle0 - Player1 collision Cx_M0P0 = 1 << 1, // Missle0 - Player0 collision Cx_M1P0 = 1 << 2, // Missle1 - Player0 collision Cx_M1P1 = 1 << 3, // Missle1 - Player1 collision Cx_P0PF = 1 << 4, // Player0 - Playfield collision Cx_P0BL = 1 << 5, // Player0 - Ball collision Cx_P1PF = 1 << 6, // Player1 - Playfield collision Cx_P1BL = 1 << 7, // Player1 - Ball collision Cx_M0PF = 1 << 8, // Missle0 - Playfield collision Cx_M0BL = 1 << 9, // Missle0 - Ball collision Cx_M1PF = 1 << 10, // Missle1 - Playfield collision Cx_M1BL = 1 << 11, // Missle1 - Ball collision Cx_BLPF = 1 << 12, // Ball - Playfield collision Cx_P0P1 = 1 << 13, // Player0 - Player1 collision Cx_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 }; /** The TIA class uses some static tables that aren't dependent on the actual TIA state. For code organization, it's better to place that functionality here. @author Stephen Anthony @version $Id: TIATables.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class TIATables { public: /** Compute all static tables used by the TIA */ static void computeAllTables(); // Player mask table // [suppress mode][nusiz][pixel] static uInt8 PxMask[2][8][320]; // Missle mask table (entries are true or false) // [number][size][pixel] // There are actually only 4 possible size combinations on a real system // The fifth size is used for simulating the starfield effect in // Cosmic Ark and Stay Frosty static uInt8 MxMask[8][5][320]; // Ball mask table (entries are true or false) // [size][pixel] static uInt8 BLMask[4][320]; // Playfield mask table for reflected and non-reflected playfields // [reflect, pixel] static uInt32 PFMask[2][160]; // A mask table which can be used when an object is disabled static uInt8 DisabledMask[640]; // Used to set the collision register to the correct value static uInt16 CollisionMask[64]; // Indicates the update delay associated with poking at a TIA address static const Int16 PokeDelay[64]; #if 0 // Used to convert value written in a motion register into // its internal representation static const Int32 CompleteMotion[76][16]; #endif // Indicates if HMOVE blanks should occur for the corresponding cycle static const bool HMOVEBlankEnableCycles[76]; // Used to reflect a players graphics static uInt8 GRPReflect[256]; // Indicates if player is being reset during delay, display or other times // [nusiz][old pixel][new pixel] static Int8 PxPosResetWhen[8][160][160]; private: // Compute the collision decode table static void buildCollisionMaskTable(); // Compute the player mask table static void buildPxMaskTable(); // Compute the missle mask table static void buildMxMaskTable(); // Compute the ball mask table static void buildBLMaskTable(); // Compute playfield mask table static void buildPFMaskTable(); // Compute the player reflect table static void buildGRPReflectTable(); // Compute the player position reset when table static void buildPxPosResetWhenTable(); }; #endif stella-3.9.3/src/emucore/Paddles.cxx0000644000175000001440000003763512266336753016760 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Paddles.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #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) { // 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; // Paranoid mode: defaults for the global variables should be set // before the first instance of this class is instantiated assert(_DIGITAL_SENSITIVITY != -1 && _MOUSE_SENSITIVITY != -1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Paddles::~Paddles() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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) { myAnalogPinValue[Nine] = (Int32)(1400000 * (float)(32767 - (Int16)sa_xaxis) / 65536.0); sa_changed = true; } if(abs(myLastAxisY - sa_yaxis) > 10) { myAnalogPinValue[Five] = (Int32)(1400000 * (float)(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] -= ((myEvent.get(myAxisMouseMotion) >> 1) * _MOUSE_SENSITIVITY); if(myCharge[myMPaddleID] < TRIGMIN) myCharge[myMPaddleID] = TRIGMIN; if(myCharge[myMPaddleID] > TRIGMAX) myCharge[myMPaddleID] = TRIGMAX; 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] -= ((myEvent.get(Event::MouseAxisXValue) >> 1) * _MOUSE_SENSITIVITY); if(myCharge[myMPaddleIDX] < TRIGMIN) myCharge[myMPaddleIDX] = TRIGMIN; if(myCharge[myMPaddleIDX] > TRIGMAX) myCharge[myMPaddleIDX] = TRIGMAX; if(myEvent.get(Event::MouseButtonLeftValue)) myDigitalPinState[ourButtonPin[myMPaddleIDX]] = false; } if(myMPaddleIDY > -1) { myCharge[myMPaddleIDY] -= ((myEvent.get(Event::MouseAxisYValue) >> 1) * _MOUSE_SENSITIVITY); if(myCharge[myMPaddleIDY] < TRIGMIN) myCharge[myMPaddleIDY] = TRIGMIN; if(myCharge[myMPaddleIDY] > TRIGMAX) myCharge[myMPaddleIDY] = TRIGMAX; 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) < TRIGMAX) 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) < TRIGMAX) myCharge[myAxisDigitalOne] += myPaddleRepeat1; } // Only change state if the charge has actually changed if(myCharge[1] != myLastCharge[1]) myAnalogPinValue[Five] = (Int32)(1400000 * (myCharge[1] / float(TRIGRANGE))); if(myCharge[0] != myLastCharge[0]) myAnalogPinValue[Nine] = (Int32)(1400000 * (myCharge[0] / float(TRIGRANGE))); 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) { if(sensitivity < 1) sensitivity = 1; else if(sensitivity > 10) sensitivity = 10; _DIGITAL_SENSITIVITY = sensitivity; _DIGITAL_DISTANCE = 20 + (sensitivity << 3); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Paddles::setMouseSensitivity(int sensitivity) { if(sensitivity < 1) sensitivity = 1; else if(sensitivity > 15) sensitivity = 15; _MOUSE_SENSITIVITY = sensitivity; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Paddles::_DIGITAL_SENSITIVITY = -1; int Paddles::_DIGITAL_DISTANCE = -1; int Paddles::_MOUSE_SENSITIVITY = -1; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Controller::DigitalPin Paddles::ourButtonPin[2] = { Four, Three }; stella-3.9.3/src/emucore/M6532.cxx0000644000175000001440000003174712266336753016116 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: M6532.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "Console.hxx" #include "Settings.hxx" #include "Switches.hxx" #include "System.hxx" #include "M6532.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - M6532::M6532(const Console& console, const Settings& settings) : myConsole(console), mySettings(settings) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - M6532::~M6532() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6532::reset() { // Initialize the 128 bytes of memory if(mySettings.getBool("ramrandom")) for(uInt32 t = 0; t < 128; ++t) myRAM[t] = mySystem->randGenerator().next(); else memset(myRAM, 0, 128); // The timer absolutely cannot be initialized to zero; some games will // loop or hang (notably Solaris and H.E.R.O.) myTimer = (0xff - (mySystem->randGenerator().next() % 0xfe)) << 10; myIntervalShift = 10; myCyclesWhenTimerSet = 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; myTimerFlagValid = false; // Edge-detect set to negative (high to low) myEdgeDetectPositive = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6532::systemCyclesReset() { // System cycles are being reset to zero so we need to adjust // the cycle count we remembered when the timer was last set myCyclesWhenTimerSet -= mySystem->cycles(); // We should also inform any 'smart' controllers as well myConsole.controller(Controller::Left).systemCyclesReset(); myConsole.controller(Controller::Right).systemCyclesReset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6532::update() { Controller& port0 = myConsole.controller(Controller::Left); Controller& port1 = myConsole.controller(Controller::Right); // 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::install(System& system) { install(system, *this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6532::install(System& system, Device& device) { // Remember which system I'm installed in mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1080 & mask) == 0); // All accesses are to the given device System::PageAccess access(0, 0, 0, &device, System::PA_READWRITE); // We're installing in a 2600 system for(int address = 0; address < 8192; address += (1 << shift)) if((address & 0x1080) == 0x0080) mySystem->setPageAccess(address >> shift, access); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 M6532::peek(uInt16 addr) { // Access RAM directly. Originally, accesses to RAM could bypass // this method and its pages could be installed directly into the // system. However, certain cartridges (notably 4A50) can mirror // the RAM address space, making it necessary to chain accesses. if((addr & 0x1080) == 0x0080 && (addr & 0x0200) == 0x0000) { return myRAM[addr & 0x007f]; } switch(addr & 0x07) { case 0x00: // SWCHA - Port A I/O Register (Joystick) { uInt8 value = (myConsole.controller(Controller::Left).read() << 4) | myConsole.controller(Controller::Right).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 myInterruptFlag &= ~TimerBit; // Get number of clocks since timer was set Int32 timer = timerClocks(); // Note that this constant comes from z26, and corresponds to // 256 intervals of T1024T (ie, the maximum that the timer should hold) // I'm not sure why this is required, but quite a few ROMs fail // if we just check >= 0. if(!(timer & 0x40000)) { // Return at 'divide by TIMxT' interval rate return (timer >> myIntervalShift) & 0xff; } else { // Return at 'divide by 1' rate uInt8 divByOne = timer & 0xff; // Timer flag has been updated; don't update it again on TIMINT read if(divByOne != 0 && divByOne != 255) myTimerFlagValid = true; return divByOne; } } case 0x05: // TIMINT/INSTAT - Interrupt Flag case 0x07: { // Update timer flag if it is invalid and timer has expired if(!myTimerFlagValid && timerClocks() < 0) { myInterruptFlag |= TimerBit; myTimerFlagValid = true; } // 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) { // Access RAM directly. Originally, accesses to RAM could bypass // this method and its pages could be installed directly into the // system. However, certain cartridges (notably 4A50) can mirror // the RAM address space, making it necessary to chain accesses. if((addr & 0x1080) == 0x0080 && (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 const uInt8 shift[] = { 0, 3, 6, 10 }; myIntervalShift = shift[interval]; myOutTimer[interval] = value; myTimer = value << myIntervalShift; myCyclesWhenTimerSet = mySystem->cycles(); // Interrupt timer flag is cleared (and invalid) when writing to the timer myInterruptFlag &= ~TimerBit; myTimerFlagValid = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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.controller(Controller::Left); Controller& port1 = myConsole.controller(Controller::Right); 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(myIntervalShift); out.putInt(myCyclesWhenTimerSet); out.putByte(myDDRA); out.putByte(myDDRB); out.putByte(myOutA); out.putByte(myOutB); out.putByte(myInterruptFlag); out.putBool(myTimerFlagValid); 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(); myIntervalShift = in.getInt(); myCyclesWhenTimerSet = in.getInt(); myDDRA = in.getByte(); myDDRB = in.getByte(); myOutA = in.getByte(); myOutB = in.getByte(); myInterruptFlag = in.getByte(); myTimerFlagValid = in.getBool(); myEdgeDetectPositive = in.getBool(); in.getByteArray(myOutTimer, 4); } catch(...) { cerr << "ERROR: M6532::load" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 M6532::intim() const { // This method is documented in ::peek(0x284), and exists so that the // debugger can read INTIM without changing the state of the system // Get number of clocks since timer was set Int32 timer = timerClocks(); if(!(timer & 0x40000)) return (timer >> myIntervalShift) & 0xff; else return timer & 0xff; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 M6532::timint() const { // This method is documented in ::peek(0x285), and exists so that the // debugger can read TIMINT without changing the state of the system // Update timer flag if it is invalid and timer has expired uInt8 interrupt = myInterruptFlag; if(timerClocks() < 0) interrupt |= TimerBit; return interrupt; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Int32 M6532::intimClocks() const { // 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 // Get number of clocks since timer was set Int32 timer = timerClocks(); if(!(timer & 0x40000)) return timerClocks() & ((1 << myIntervalShift) - 1); else return timer & 0xff; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - M6532::M6532(const M6532& c) : myConsole(c.myConsole), mySettings(c.mySettings) { assert(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - M6532& M6532::operator = (const M6532&) { assert(false); return *this; } stella-3.9.3/src/emucore/CartDF.hxx0000644000175000001440000001046712266336753016506 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDF.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: CartDF.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeDF(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 64K ROM image of the cartridge uInt8 myImage[131072]; }; #endif stella-3.9.3/src/emucore/CartDFSC.hxx0000644000175000001440000001052212266336753016724 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDFSC.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 $1FD0 - $1FEF switches to each bank. @author Stephen Anthony @version $Id: CartDFSC.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeDFSC(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 64K ROM image of the cartridge uInt8 myImage[131072]; // The 128 bytes of RAM uInt8 myRAM[128]; }; #endif stella-3.9.3/src/emucore/Sound.hxx0000644000175000001440000000756612266336753016501 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Sound.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: Sound.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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; } /** Destructor */ virtual ~Sound() { }; 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; /** The system cycle counter is being adjusting by the specified amount. Any members using the system cycle counter should be adjusted as needed. @param amount The amount the cycle counter is being adjusted by */ virtual void adjustCycleCounter(Int32 amount) = 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, Int32 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; }; #endif stella-3.9.3/src/emucore/Genesis.cxx0000644000175000001440000001046112266336753016765 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Genesis.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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; } // Analog pin 9 is not connected to this controller at all // Analog pin 5 corresponds to button 'C' on the gamepad, and corresponds // to the 'booster' button on a BoosterGrip controller myAnalogPinValue[Five] = myAnalogPinValue[Nine] = maximumResistance; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Genesis::~Genesis() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 myAnalogPinValue[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)) myAnalogPinValue[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-3.9.3/src/emucore/CartF8.cxx0000644000175000001440000001304212266336753016455 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF8.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartF8.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF8::CartridgeF8(const uInt8* image, uInt32 size, const string& md5, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_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 ? 0 : 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF8::~CartridgeF8() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF8::reset() { // Upon reset we switch to the reset bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF8::install(System& system) { mySystem = &system; // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mySystem->pageMask()) == 0); // 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[(myCurrentBank << 12) + 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 myCurrentBank = bank; uInt16 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1FF8 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1000; address < (0x1FF8U & ~mask); address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF8::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF8::bankCount() const { return 2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF8::patch(uInt16 address, uInt8 value) { myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeF8::getImage(int& size) const { size = 8192; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF8::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); } catch(...) { cerr << "ERROR: CartridgeF8::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF8::load(Serializer& in) { try { if(in.getString() != name()) return false; myCurrentBank = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeF8SC::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/CartBFSC.cxx0000644000175000001440000001516412266336753016724 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartBFSC.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartBFSC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeBFSC::CartridgeBFSC(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(262144u, size)); createCodeAccessBase(262144); // This cart contains 128 bytes extended RAM @ 0x1000 registerRamArea(0x1000, 128, 0x80, 0x00); // Remember startup bank myStartBank = 15; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeBFSC::~CartridgeBFSC() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBFSC::reset() { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 128; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 128); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBFSC::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mask) == 0); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt32 j = 0x1000; j < 0x1080; j += (1 << shift)) { access.directPokeBase = &myRAM[j & 0x007F]; access.codeAccessBase = &myCodeAccessBase[j & 0x007F]; mySystem->setPageAccess(j >> shift, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = 0; access.type = System::PA_READ; for(uInt32 k = 0x1080; k < 0x1100; k += (1 << shift)) { access.directPeekBase = &myRAM[k & 0x007F]; access.codeAccessBase = &myCodeAccessBase[0x80 + (k & 0x007F)]; mySystem->setPageAccess(k >> shift, 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[(myCurrentBank << 12) + 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 function // 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 myCurrentBank = bank; uInt32 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1F80 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1100; address < (0x1F80U & ~mask); address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeBFSC::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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[(myCurrentBank << 12) + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeBFSC::getImage(int& size) const { size = 256*1024; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBFSC::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); 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; myCurrentBank = in.getShort(); in.getByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeBFSC::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/Cart2K.cxx0000644000175000001440000001067712266336753016467 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart2K.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "Cart2K.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge2K::Cartridge2K(const uInt8* 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; // The smallest addressable area by Stella is 64 bytes // This should really be read from the System, but for now I'm going // to cheat a little and hard-code it to 64 (aka 2^6) if(mySize < 64) mySize = 64; // Initialize ROM with illegal 6502 opcode that causes a real 6502 to jam myImage = new uInt8[mySize]; memset(myImage, 0x02, mySize); // Copy the ROM image into my buffer memcpy(myImage, image, 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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge2K::~Cartridge2K() { delete[] myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge2K::reset() { myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge2K::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mask) == 0); // Map ROM image into the system System::PageAccess access(0, 0, 0, this, System::PA_READ); for(uInt32 address = 0x1000; address < 0x2000; address += (1 << shift)) { access.directPeekBase = &myImage[address & myMask]; access.codeAccessBase = &myCodeAccessBase[address & myMask]; mySystem->setPageAccess(address >> shift, access); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge2K::peek(uInt16 address) { return myImage[address & myMask]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge2K::poke(uInt16, uInt8) { // This is ROM so poking has no effect :-) return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge2K::bank(uInt16 bank) { // Doesn't support bankswitching return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge2K::bank() const { // Doesn't support bankswitching return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge2K::bankCount() const { return 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge2K::patch(uInt16 address, uInt8 value) { myImage[address & myMask] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* Cartridge2K::getImage(int& size) const { size = mySize; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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-3.9.3/src/emucore/CartF6.cxx0000644000175000001440000001266312266336753016463 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF6.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartF6.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF6::CartridgeF6(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(16384u, size)); createCodeAccessBase(16384); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF6::~CartridgeF6() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF6::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF6::install(System& system) { mySystem = &system; // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mySystem->pageMask()) == 0); // 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[(myCurrentBank << 12) + 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 myCurrentBank = bank; uInt16 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1FF6 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1000; address < (0x1FF6U & ~mask); address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF6::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF6::bankCount() const { return 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF6::patch(uInt16 address, uInt8 value) { myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeF6::getImage(int& size) const { size = 16384; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF6::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); } catch(...) { cerr << "ERROR: CartridgeF6::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF6::load(Serializer& in) { try { if(in.getString() != name()) return false; myCurrentBank = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeF6::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/PropsSet.hxx0000644000175000001440000001040212266336753017147 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: PropsSet.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef PROPERTIES_SET_HXX #define PROPERTIES_SET_HXX #include #include "bspf.hxx" #include "FSNode.hxx" #include "Props.hxx" class OSystem; /** 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 an empty properties set object using the md5 as the key to the BST. */ PropertiesSet(OSystem* osystem); /** Destructor */ virtual ~PropertiesSet(); 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 defaults 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 file The node representing the @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 defaults Use the built-in defaults, ignoring any properties from an external file */ 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: typedef map PropsList; // The parent system for this object OSystem* myOSystem; // 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; }; #endif stella-3.9.3/src/emucore/CartF4.cxx0000644000175000001440000001137312266336753016456 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF4.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "Random.hxx" #include "System.hxx" #include "CartF4.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF4::CartridgeF4(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(32768u, size)); createCodeAccessBase(32768); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF4::~CartridgeF4() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF4::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF4::install(System& system) { mySystem = &system; // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mySystem->pageMask()) == 0); // 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[(myCurrentBank << 12) + 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 myCurrentBank = bank; uInt16 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1FF4 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1000; address < (0x1FF4U & ~mask); address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF4::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF4::bankCount() const { return 8; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF4::patch(uInt16 address, uInt8 value) { myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeF4::getImage(int& size) const { size = 32768; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF4::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); } catch(...) { cerr << "ERROR: CartridgeF4::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF4::load(Serializer& in) { try { if(in.getString() != name()) return false; myCurrentBank = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeF4::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/Control.cxx0000644000175000001440000001254312266336753017013 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Control.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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) { 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 TrackBall22: myName = "TrackBall22"; break; case TrackBall80: myName = "TrackBall80"; break; case AmigaMouse: myName = "AmigaMouse"; 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; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Controller::~Controller() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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) { myAnalogPinValue[pin] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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] = (Int32) in.getInt(); myAnalogPinValue[Nine] = (Int32) in.getInt(); } catch(...) { cerr << "ERROR: Controller::load() exception\n"; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Controller::name() const { return myName; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Controller::about() const { return name() + " in " + (myJack == Left ? "left port" : "right port"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Int32 Controller::maximumResistance = 0x7FFFFFFF; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Int32 Controller::minimumResistance = 0x00000000; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Controller::Controller(const Controller& c) : myJack(c.myJack), myEvent(c.myEvent), mySystem(c.mySystem), myType(c.myType) { assert(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Controller& Controller::operator = (const Controller&) { assert(false); return *this; } stella-3.9.3/src/emucore/CartF0.cxx0000644000175000001440000001154112266336753016447 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF0.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartF0.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF0::CartridgeF0(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(65536u, size)); createCodeAccessBase(65536); // Remember startup bank myStartBank = 15; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF0::~CartridgeF0() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF0::reset() { // Upon reset we switch to bank 15 myCurrentBank = 14; incbank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF0::install(System& system) { mySystem = &system; // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mySystem->pageMask()) == 0); // Install pages for bank 1 myCurrentBank = 0; incbank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeF0::peek(uInt16 address) { address &= 0x0FFF; // Switch to next bank if(address == 0x0FF0) incbank(); return myImage[(myCurrentBank << 12) + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF0::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch to next bank if(address == 0x0FF0) incbank(); return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF0::incbank() { if(bankLocked()) return; // Remember what bank we're in myCurrentBank++; myCurrentBank &= 0x0F; uInt16 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1FF0 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1000; address < (0x1FF0U & ~mask); address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF0::bank(uInt16 bank) { if(bankLocked()) return false; myCurrentBank = bank - 1; incbank(); return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF0::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF0::bankCount() const { return 16; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF0::patch(uInt16 address, uInt8 value) { myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeF0::getImage(int& size) const { size = 65536; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF0::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); } catch(...) { cerr << "ERROR: CartridgeF0::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF0::load(Serializer& in) { try { if(in.getString() != name()) return false; myCurrentBank = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeF0::load" << endl; return false; } // Remember what bank we were in --myCurrentBank; incbank(); return true; } stella-3.9.3/src/emucore/CartUA.cxx0000644000175000001440000001264212266336753016512 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartUA.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartUA.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeUA::CartridgeUA(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(8192u, size)); createCodeAccessBase(8192); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeUA::~CartridgeUA() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeUA::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeUA::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mask) == 0); // 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 >> shift); // Set the page accessing methods for the hot spots System::PageAccess access(0, 0, 0, this, System::PA_READ); mySystem->setPageAccess(0x0220 >> shift, access); mySystem->setPageAccess(0x0240 >> shift, 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; } if(!(address & 0x1000)) { return myHotSpotPageAccess.device->peek(address); } else { return 0; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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; } 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 myCurrentBank = bank; uInt16 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); // Setup the page access methods for the current bank System::PageAccess access(0, 0, 0, this, System::PA_READ); // Map ROM image into the system for(uInt32 address = 0x1000; address < 0x2000; address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeUA::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeUA::bankCount() const { return 2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeUA::patch(uInt16 address, uInt8 value) { myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeUA::getImage(int& size) const { size = 8192; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeUA::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); } catch(...) { cerr << "ERROR: CartridgeUA::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeUA::load(Serializer& in) { try { if(in.getString() != name()) return false; myCurrentBank = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeUA::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/CartCM.hxx0000644000175000001440000001777712266336753016527 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartCM.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CARTRIDGECM_HXX #define CARTRIDGECM_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartCMWidget.hxx" #endif /** 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 @version $Id: CartCM.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeCM(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); /** Get the current keybord column @return The column referenced by SWCHA D6 and D5 */ uInt8 column() const { return myColumn; } private: // Indicates which bank is currently active uInt16 myCurrentBank; // 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; // Column currently active uInt8 myColumn; }; #endif stella-3.9.3/src/emucore/CartF8SC.cxx0000644000175000001440000001576012266336753016714 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF8SC.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartF8SC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF8SC::CartridgeF8SC(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(8192u, size)); createCodeAccessBase(8192); // This cart contains 128 bytes extended RAM @ 0x1000 registerRamArea(0x1000, 128, 0x80, 0x00); // Remember startup bank myStartBank = 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF8SC::~CartridgeF8SC() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF8SC::reset() { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 128; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 128); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF8SC::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert(((0x1080 & mask) == 0) && ((0x1100 & mask) == 0)); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt32 j = 0x1000; j < 0x1080; j += (1 << shift)) { access.directPokeBase = &myRAM[j & 0x007F]; access.codeAccessBase = &myCodeAccessBase[j & 0x007F]; mySystem->setPageAccess(j >> shift, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = 0; access.type = System::PA_READ; for(uInt32 k = 0x1080; k < 0x1100; k += (1 << shift)) { access.directPeekBase = &myRAM[k & 0x007F]; access.codeAccessBase = &myCodeAccessBase[0x80 + (k & 0x007F)]; mySystem->setPageAccess(k >> shift, 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[(myCurrentBank << 12) + 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 myCurrentBank = bank; uInt16 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1FF8 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1100; address < (0x1FF8U & ~mask); address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF8SC::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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[(myCurrentBank << 12) + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeF8SC::getImage(int& size) const { size = 8192; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF8SC::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); 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; myCurrentBank = in.getShort(); in.getByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeF8SC::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/CartAR.cxx0000644000175000001440000004756112266336753016517 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartAR.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "M6502.hxx" #include "System.hxx" #include "CartAR.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeAR::CartridgeAR(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings), my6502(0), mySize(BSPF_max(size, 8448u)) { // Create a load image buffer and copy the given image myLoadImages = new uInt8[mySize]; myNumberOfLoadImages = mySize / 8448; memcpy(myLoadImages, image, size); // Add header if image doesn't include it if(size < 8448) memcpy(myLoadImages+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); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeAR::~CartridgeAR() { delete[] myLoadImages; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeAR::reset() { // Initialize RAM #if 0 // TODO - figure out actual behaviour of the real cart if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 6 * 1024; ++i) myImage[i] = mySystem->randGenerator().next(); else #endif memset(myImage, 0, 6 * 1024); // Initialize SC BIOS ROM initializeROM(); myPower = true; myPowerRomCycle = mySystem->cycles(); myWriteEnabled = false; myDataHoldRegister = 0; myNumberOfDistinctAccesses = 0; myWritePending = false; // Set bank configuration upon reset so ROM is selected and powered up bankConfiguration(0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeAR::systemCyclesReset() { // Get the current system cycle uInt32 cycles = mySystem->cycles(); // Adjust cycle values myPowerRomCycle -= cycles; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeAR::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); my6502 = &(mySystem->m6502()); // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mask) == 0); // Map all of the accesses to call peek and poke (we don't yet indicate RAM areas) System::PageAccess access(0, 0, 0, this, System::PA_READ); for(uInt32 i = 0x1000; i < 0x2000; i += (1 << shift)) mySystem->setPageAccess(i >> shift, 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 && (my6502->distinctAccesses() > myNumberOfDistinctAccesses + 5)) { myWritePending = false; } // Is the data hold register being set? if(!(addr & 0x0F00) && (!myWriteEnabled || !myWritePending)) { myDataHoldRegister = addr; myNumberOfDistinctAccesses = my6502->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 && (my6502->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 && (my6502->distinctAccesses() > myNumberOfDistinctAccesses + 5)) { myWritePending = false; } // Is the data hold register being set? if(!(addr & 0x0F00) && (!myWriteEnabled || !myWritePending)) { myDataHoldRegister = addr; myNumberOfDistinctAccesses = my6502->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 && (my6502->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) { 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); if(myPower) { myPowerRomCycle = mySystem->cycles(); } 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 + (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 + (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::bank() 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(int& size) const { size = mySize; return myLoadImages; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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, 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); // Indicates when the power was last turned on out.putInt(myPowerRomCycle); // 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, 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(); // Indicates when the power was last turned on myPowerRomCycle = (Int32) in.getInt(); // 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-3.9.3/src/emucore/CartF4SC.cxx0000644000175000001440000001546512266336753016712 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF4SC.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartF4SC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF4SC::CartridgeF4SC(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(32768u, size)); createCodeAccessBase(32768); // This cart contains 128 bytes extended RAM @ 0x1000 registerRamArea(0x1000, 128, 0x80, 0x00); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF4SC::~CartridgeF4SC() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF4SC::reset() { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 128; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 128); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF4SC::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert(((0x1080 & mask) == 0) && ((0x1100 & mask) == 0)); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt32 j = 0x1000; j < 0x1080; j += (1 << shift)) { access.directPokeBase = &myRAM[j & 0x007F]; access.codeAccessBase = &myCodeAccessBase[j & 0x007F]; mySystem->setPageAccess(j >> shift, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = 0; access.type = System::PA_READ; for(uInt32 k = 0x1080; k < 0x1100; k += (1 << shift)) { access.directPeekBase = &myRAM[k & 0x007F]; access.codeAccessBase = &myCodeAccessBase[0x80 + (k & 0x007F)]; mySystem->setPageAccess(k >> shift, 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[(myCurrentBank << 12) + 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 myCurrentBank = bank; uInt16 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1FF4 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1100; address < (0x1FF4U & ~mask); address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF4SC::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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[(myCurrentBank << 12) + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeF4SC::getImage(int& size) const { size = 32768; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF4SC::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); 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; myCurrentBank = in.getShort(); in.getByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeF4SC::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/CartMC.cxx0000644000175000001440000001720512266336753016504 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartMC.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartMC.hxx" // TODO - much more testing of this scheme is required // No test ROMs exist as of 2009-11-08, so we can't be sure how // accurate the emulation is // Bankchange and RAM modification cannot be completed until // adequate test ROMs are available // TODO (2010-10-03) - support CodeAccessBase functionality somehow // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeMC::CartridgeMC(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings), mySlot3Locked(false) { // Make sure size is reasonable assert(size <= 131072); // Set the contents of the entire ROM to 0 memset(myImage, 0, 131072); // Copy the ROM image to the end of the ROM buffer memcpy(myImage + 131072 - size, image, size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeMC::~CartridgeMC() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMC::reset() { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 32768; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 32768); myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMC::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert(((0x1000 & mask) == 0) && ((0x1400 & mask) == 0) && ((0x1800 & mask) == 0) && ((0x1C00 & mask) == 0)); // Set the page accessing methods for the hot spots in the TIA. For // correct emulation I would need to chain any accesses below 0x40 to // the TIA but for now I'll just forget about them. // // TODO: These TIA accesses may need to be chained, however, at this // point Chris isn't sure if the hardware will allow it or not // System::PageAccess access(0, 0, 0, this, System::PA_READWRITE); for(uInt32 i = 0x00; i < 0x40; i += (1 << shift)) mySystem->setPageAccess(i >> shift, access); // Map the cartridge into the system access.type = System::PA_READ; // We don't yet indicate RAM areas for(uInt32 j = 0x1000; j < 0x2000; j += (1 << shift)) mySystem->setPageAccess(j >> shift, access); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeMC::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x1FFF; // Accessing the RESET vector so lets handle the powerup special case if((address == 0x1FFC) || (address == 0x1FFD)) { // Indicate that slot 3 is locked for now mySlot3Locked = true; } // Should we unlock slot 3? else if(mySlot3Locked && (address >= 0x1000) && (address <= 0x1BFF)) { // Indicate that slot 3 is unlocked now mySlot3Locked = false; } // Handle reads made to the TIA addresses if(address < 0x1000) { return 0; } else { uInt8 block; if(mySlot3Locked && ((address & 0x0C00) == 0x0C00)) { block = 0xFF; } else { block = myCurrentBlock[(address & 0x0C00) >> 10]; } // Is this a RAM or a ROM access if(block & 0x80) { // ROM access return myImage[(uInt32)((block & 0x7F) << 10) + (address & 0x03FF)]; } else { // This is a RAM access, however, is it to the read or write port? if(address & 0x0200) { // Reading from the read port of the RAM block return myRAM[(uInt32)((block & 0x3F) << 9) + (address & 0x01FF)]; } else { // Oops, reading from the write port of the RAM block! // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); return myRAM[(uInt32)((block & 0x3F) << 9) + (address & 0x01FF)] = value; } } } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMC::poke(uInt16 address, uInt8 value) { address &= 0x1FFF; // Accessing the RESET vector so lets handle the powerup special case if((address == 0x1FFC) || (address == 0x1FFD)) { // Indicate that slot 3 is locked for now mySlot3Locked = true; } // Should we unlock slot 3? else if(mySlot3Locked && (address >= 0x1000) && (address <= 0x1BFF)) { // Indicate that slot 3 is unlocked now mySlot3Locked = false; } // Handle bank-switching writes if((address >= 0x003C) && (address <= 0x003F)) { myCurrentBlock[address - 0x003C] = value; } else { uInt8 block; if(mySlot3Locked && ((address & 0x0C00) == 0x0C00)) { block = 0xFF; } else { block = myCurrentBlock[(address & 0x0C00) >> 10]; } // Is this a RAM write access if(!(block & 0x80) && !(address & 0x0200)) { // Handle the write to RAM myRAM[(uInt32)((block & 0x3F) << 9) + (address & 0x01FF)] = value; return true; } } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMC::bank(uInt16 b) { // Doesn't support bankswitching in the normal sense return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeMC::bank() const { // TODO - add support for debugger return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeMC::bankCount() const { // TODO - add support for debugger return 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMC::patch(uInt16 address, uInt8 value) { // TODO - add support for debugger return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeMC::getImage(int& size) const { size = 128 * 1024; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMC::save(Serializer& out) const { try { out.putString(name()); // The currentBlock array out.putByteArray(myCurrentBlock, 4); // The 32K of RAM out.putByteArray(myRAM, 32 * 1024); } catch(...) { cerr << "ERROR: CartridgeMC::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMC::load(Serializer& in) { try { if(in.getString() != name()) return false; // The currentBlock array in.getByteArray(myCurrentBlock, 4); // The 32K of RAM in.getByteArray(myRAM, 32 * 1024); } catch(...) { cerr << "ERROR: CartridgeMC::load" << endl; return false; } return true; } stella-3.9.3/src/emucore/Props.hxx0000644000175000001440000001160612266336753016502 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Props.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: Props.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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); /** Destructor */ virtual ~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; /** 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 in The input stream to use */ void load(istream& in); /** Save properties to the specified output stream @param out The output stream to use */ void save(ostream& out) const; /** Print the attributes of this properties object */ void print() const; /** Resets all properties to their defaults */ void setDefaults(); public: /** 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); 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 const char* ourDefaultProperties[LastPropType]; // The text strings associated with each property type static const char* ourPropertyNames[LastPropType]; }; #endif stella-3.9.3/src/emucore/SaveKey.cxx0000644000175000001440000000544012266336753016740 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: SaveKey.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "MT24LC256.hxx" #include "System.hxx" #include "SaveKey.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SaveKey::SaveKey(Jack jack, const Event& event, const System& system, const string& eepromfile) : Controller(jack, event, system, Controller::SaveKey), myEEPROM(NULL) { myEEPROM = new MT24LC256(eepromfile, system); myDigitalPinState[One] = myDigitalPinState[Two] = true; myAnalogPinValue[Five] = myAnalogPinValue[Nine] = maximumResistance; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SaveKey::~SaveKey() { delete myEEPROM; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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::systemCyclesReset() { // The EEPROM keeps track of cycle counts, and needs to know when the // cycles are reset myEEPROM->systemCyclesReset(); } stella-3.9.3/src/emucore/Joystick.hxx0000644000175000001440000000605512266336753017200 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Joystick.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: Joystick.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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); /** Destructor */ virtual ~Joystick(); public: /** Update the entire digital and analog pin state according to the events currently set. */ void update(); /** 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); /** 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; }; #endif stella-3.9.3/src/emucore/Keyboard.cxx0000644000175000001440000000677012266336753017140 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Keyboard.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Keyboard::~Keyboard() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Keyboard::write(DigitalPin pin, bool value) { myDigitalPinState[pin] = value; // Set defaults myDigitalPinState[Six] = true; myAnalogPinValue[Five] = minimumResistance; myAnalogPinValue[Nine] = minimumResistance; // Now scan the rows and columns if(!myDigitalPinState[Four]) { myDigitalPinState[Six] = (myEvent.get(myPoundEvent) == 0); if(myEvent.get(myZeroEvent) != 0) myAnalogPinValue[Five] = maximumResistance; if(myEvent.get(myStarEvent) != 0) myAnalogPinValue[Nine] = maximumResistance; } if(!myDigitalPinState[Three]) { myDigitalPinState[Six] = (myEvent.get(myNineEvent) == 0); if(myEvent.get(myEightEvent) != 0) myAnalogPinValue[Five] = maximumResistance; if(myEvent.get(mySevenEvent) != 0) myAnalogPinValue[Nine] = maximumResistance; } if(!myDigitalPinState[Two]) { myDigitalPinState[Six] = (myEvent.get(mySixEvent) == 0); if(myEvent.get(myFiveEvent) != 0) myAnalogPinValue[Five] = maximumResistance; if(myEvent.get(myFourEvent) != 0) myAnalogPinValue[Nine] = maximumResistance; } if(!myDigitalPinState[One]) { myDigitalPinState[Six] = (myEvent.get(myThreeEvent) == 0); if(myEvent.get(myTwoEvent) != 0) myAnalogPinValue[Five] = maximumResistance; if(myEvent.get(myOneEvent) != 0) myAnalogPinValue[Nine] = maximumResistance; } } stella-3.9.3/src/emucore/TrackBall.cxx0000644000175000001440000001333312266336753017230 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TrackBall.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "Event.hxx" #include "System.hxx" #include "TIA.hxx" #include "TrackBall.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TrackBall::TrackBall(Jack jack, const Event& event, const System& system, Type type) : Controller(jack, event, system, type), myHCounter(0), myVCounter(0), myMouseEnabled(false) { // This 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 myTrakBallCountH = myTrakBallCountV = 0; myTrakBallLinesH = myTrakBallLinesV = 1; myTrakBallLeft = myTrakBallDown = myScanCountV = myScanCountH = myCountV = myCountH = 0; // Analog pins are never used by the trackball controller myAnalogPinValue[Five] = myAnalogPinValue[Nine] = maximumResistance; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TrackBall::~TrackBall() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TrackBall::read() { int scanline = ((System&)mySystem).tia().scanlines(); if(myScanCountV > scanline) myScanCountV = 0; if(myScanCountH > scanline) myScanCountH = 0; while((myScanCountV + myTrakBallLinesV) < scanline) { if(myTrakBallCountV) { if(myTrakBallDown) myCountV--; else myCountV++; myTrakBallCountV--; } myScanCountV += myTrakBallLinesV; } while((myScanCountH + myTrakBallLinesH) < scanline) { if(myTrakBallCountH) { if(myTrakBallLeft) myCountH--; else myCountH++; myTrakBallCountH--; } myScanCountH += myTrakBallLinesH; } myCountV &= 0x03; myCountH &= 0x03; uInt8 IOPortA = 0x00; switch(myType) { case Controller::TrackBall80: IOPortA = IOPortA | ourTrakBallTableST_V[myCountV] | ourTrakBallTableST_H[myCountH]; break; case Controller::TrackBall22: IOPortA = IOPortA | ourTrakBallTableTB_V[myCountV & 0x01][myTrakBallDown] | ourTrakBallTableTB_H[myCountH & 0x01][myTrakBallLeft]; break; case Controller::AmigaMouse: IOPortA = IOPortA | ourTrakBallTableAM_V[myCountV] | ourTrakBallTableAM_H[myCountH]; break; default: break; } myDigitalPinState[One] = IOPortA & 0x10; myDigitalPinState[Two] = IOPortA & 0x20; myDigitalPinState[Three] = IOPortA & 0x40; myDigitalPinState[Four] = IOPortA & 0x80; return (IOPortA >> 4); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TrackBall::update() { if(!myMouseEnabled) return; // Get the current mouse position myHCounter = myEvent.get(Event::MouseAxisXValue); myVCounter = myEvent.get(Event::MouseAxisYValue); if(myVCounter < 0) myTrakBallLeft = 1; else myTrakBallLeft = 0; if(myHCounter < 0) myTrakBallDown = 0; else myTrakBallDown = 1; myTrakBallCountH = abs(myVCounter >> 1); myTrakBallCountV = abs(myHCounter >> 1); myTrakBallLinesH = 200 /*LinesInFrame*/ / (myTrakBallCountH + 1); if(myTrakBallLinesH == 0) myTrakBallLinesH = 1; myTrakBallLinesV = 200 /*LinesInFrame*/ / (myTrakBallCountV + 1); if(myTrakBallLinesV == 0) myTrakBallLinesV = 1; // Get mouse button state myDigitalPinState[Six] = (myEvent.get(Event::MouseButtonLeftValue) == 0) && (myEvent.get(Event::MouseButtonRightValue) == 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TrackBall::setMouseControl( Controller::Type xtype, int xid, Controller::Type ytype, int yid) { // Currently, the various trackball 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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt32 TrackBall::ourTrakBallTableTB_H[2][2] = { { 0x40, 0x00 }, { 0xc0, 0x80 } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt32 TrackBall::ourTrakBallTableTB_V[2][2] = { { 0x00, 0x10 }, { 0x20, 0x30 } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt32 TrackBall::ourTrakBallTableST_H[4] = { 0x00, 0x80, 0xc0, 0x40 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt32 TrackBall::ourTrakBallTableST_V[4] = { 0x00, 0x10, 0x30, 0x20 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt32 TrackBall::ourTrakBallTableAM_H[4] = { 0x00, 0x10, 0x50, 0x40 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt32 TrackBall::ourTrakBallTableAM_V[4] = { 0x00, 0x80, 0xa0, 0x20 }; stella-3.9.3/src/emucore/CartEFSC.hxx0000644000175000001440000001101212266336753016720 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartEFSC.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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. This interpretation is based on analysis of the z26 assembly code, as this scheme doesn't seem to be documented anywhere. @author Stephen Anthony @version $Id: CartEFSC.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeEFSC(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 64K ROM image of the cartridge uInt8 myImage[65536]; // The 128 bytes of RAM uInt8 myRAM[128]; }; #endif stella-3.9.3/src/emucore/Switches.hxx0000644000175000001440000000473112266336753017171 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Switches.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef SWITCHES_HXX #define SWITCHES_HXX class Event; class Properties; #include "Serializable.hxx" #include "bspf.hxx" /** This class represents the console switches of the game console. @author Bradford W. Mott @version $Id: Switches.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 */ Switches(const Event& event, const Properties& properties); /** Destructor */ virtual ~Switches(); 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { return "Switches"; } private: // Reference to the event object to use const Event& myEvent; // State of the console switches uInt8 mySwitches; }; #endif stella-3.9.3/src/emucore/MD5.hxx0000644000175000001440000000257112266336753015765 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: MD5.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef MD5_HXX #define MD5_HXX #include "FSNode.hxx" #include "bspf.hxx" /** 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 MD5(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 MD5(const FilesystemNode& node); #endif stella-3.9.3/src/emucore/Cart3E.hxx0000644000175000001440000001361612266336753016463 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart3E.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: Cart3E.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~Cartridge3E(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active for the first segment uInt16 myCurrentBank; // Pointer to a dynamically allocated ROM image of the cartridge uInt8* myImage; // RAM contents. For now every ROM gets all 32K of potential RAM uInt8 myRAM[32 * 1024]; // Size of the ROM image uInt32 mySize; }; #endif stella-3.9.3/src/emucore/CartE7.cxx0000644000175000001440000002342412266336753016460 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartE7.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartE7.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeE7::CartridgeE7(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(16384u, size)); createCodeAccessBase(16384 + 2048); // This cart can address a 1024 byte bank of RAM @ 0x1000 // and 256 bytes @ 0x1800 // However, it may not be addressable all the time (it may be swapped out) // so probably most of the time, the area will point to ROM instead registerRamArea(0x1000, 1024, 0x400, 0x00); // 1024 bytes RAM @ 0x1000 registerRamArea(0x1800, 256, 0x100, 0x00); // 256 bytes RAM @ 0x1800 // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeE7::~CartridgeE7() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE7::reset() { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 2048; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 2048); // Install some default banks for the RAM and first segment bankRAM(0); bank(myStartBank); myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE7::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert(((0x1400 & mask) == 0) && ((0x1800 & mask) == 0) && ((0x1900 & mask) == 0) && ((0x1A00 & mask) == 0)); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1FE0 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[8128]; mySystem->setPageAccess(i >> shift, access); } // Setup the second segment to always point to the last ROM slice for(uInt32 j = 0x1A00; j < (0x1FE0U & ~mask); j += (1 << shift)) { access.directPeekBase = &myImage[7 * 2048 + (j & 0x07FF)]; access.codeAccessBase = &myCodeAccessBase[7 * 2048 + (j & 0x07FF)]; mySystem->setPageAccess(j >> shift, access); } myCurrentSlice[1] = 7; // Install some default banks for the RAM and first segment bankRAM(0); bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeE7::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FE0) && (address <= 0x0FE7)) { bank(address & 0x0007); } else if((address >= 0x0FE8) && (address <= 0x0FEB)) { bankRAM(address & 0x0003); } if((myCurrentSlice[0] == 7) && (address < 0x0400)) { // 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 & 0x03FF] = 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 & 0x07FF)]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeE7::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FE0) && (address <= 0x0FE7)) { bank(address & 0x0007); } else if((address >= 0x0FE8) && (address <= 0x0FEB)) { bankRAM(address & 0x0003); } // NOTE: This does not handle writing to RAM, however, this // function should never be called for RAM because of the // way page accessing has been setup return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE7::bankRAM(uInt16 bank) { if(bankLocked()) return; // Remember what bank we're in myCurrentRAM = bank; uInt16 offset = bank << 8; uInt16 shift = mySystem->pageShift(); // Setup the page access methods for the current bank System::PageAccess access(0, 0, 0, this, System::PA_WRITE); // Set the page accessing method for the 256 bytes of RAM writing pages for(uInt32 j = 0x1800; j < 0x1900; j += (1 << shift)) { access.directPokeBase = &myRAM[1024 + offset + (j & 0x00FF)]; access.codeAccessBase = &myCodeAccessBase[8192 + 1024 + offset + (j & 0x00FF)]; mySystem->setPageAccess(j >> shift, access); } // Set the page accessing method for the 256 bytes of RAM reading pages access.directPokeBase = 0; access.type = System::PA_READ; for(uInt32 k = 0x1900; k < 0x1A00; k += (1 << shift)) { access.directPeekBase = &myRAM[1024 + offset + (k & 0x00FF)]; access.codeAccessBase = &myCodeAccessBase[8192 + 1024 + offset + (k & 0x00FF)]; mySystem->setPageAccess(k >> shift, access); } myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeE7::bank(uInt16 slice) { if(bankLocked()) return false; // Remember what bank we're in myCurrentSlice[0] = slice; uInt16 offset = slice << 11; uInt16 shift = mySystem->pageShift(); // Setup the page access methods for the current bank if(slice != 7) { System::PageAccess access(0, 0, 0, this, System::PA_READ); // Map ROM image into first segment for(uInt32 address = 0x1000; address < 0x1800; address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x07FF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x07FF)]; mySystem->setPageAccess(address >> shift, access); } } else { System::PageAccess access(0, 0, 0, this, System::PA_WRITE); // Set the page accessing method for the 1K slice of RAM writing pages for(uInt32 j = 0x1000; j < 0x1400; j += (1 << shift)) { access.directPokeBase = &myRAM[j & 0x03FF]; access.codeAccessBase = &myCodeAccessBase[8192 + (j & 0x03FF)]; mySystem->setPageAccess(j >> shift, access); } // Set the page accessing method for the 1K slice of RAM reading pages access.directPokeBase = 0; access.type = System::PA_READ; for(uInt32 k = 0x1400; k < 0x1800; k += (1 << shift)) { access.directPeekBase = &myRAM[k & 0x03FF]; access.codeAccessBase = &myCodeAccessBase[8192 + (k & 0x03FF)]; mySystem->setPageAccess(k >> shift, access); } } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeE7::bank() const { return myCurrentSlice[0]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeE7::bankCount() const { return 8; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeE7::patch(uInt16 address, uInt8 value) { address = address & 0x0FFF; if(address < 0x0800) { if(myCurrentSlice[0] == 7) { // 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 & 0x07FF)] = 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 & 0x07FF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeE7::getImage(int& size) const { size = 16384; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeE7::save(Serializer& out) const { try { out.putString(name()); out.putShortArray(myCurrentSlice, 2); out.putShort(myCurrentRAM); out.putByteArray(myRAM, 2048); } catch(...) { cerr << "ERROR: CartridgeE7::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeE7::load(Serializer& in) { try { if(in.getString() != name()) return false; in.getShortArray(myCurrentSlice, 2); myCurrentRAM = in.getShort(); in.getByteArray(myRAM, 2048); } catch(...) { cerr << "ERROR: CartridgeE7::load" << endl; return false; } // Set up the previously used banks for the RAM and segment bankRAM(myCurrentRAM); bank(myCurrentSlice[0]); return true; } stella-3.9.3/src/emucore/FrameBuffer.cxx0000644000175000001440000012447412266336753017566 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FrameBuffer.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "bspf.hxx" #include "CommandMenu.hxx" #include "Console.hxx" #include "EventHandler.hxx" #include "Event.hxx" #include "Font.hxx" #include "Launcher.hxx" #include "Menu.hxx" #include "OSystem.hxx" #include "Settings.hxx" #include "TIA.hxx" #include "FrameBuffer.hxx" #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBuffer::FrameBuffer(OSystem* osystem) : myOSystem(osystem), myScreen(0), mySDLFlags(0), myRedrawEntireFrame(true), myUsePhosphor(false), myPhosphorBlend(77), myInitializedCount(0), myPausedCount(0) { myMsg.surface = myStatsMsg.surface = NULL; myMsg.enabled = myStatsMsg.enabled = false; // Load NTSC filter settings myNTSCFilter.loadConfig(myOSystem->settings()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBuffer::~FrameBuffer(void) { // Free all allocated surfaces while(!mySurfaceList.empty()) { delete (*mySurfaceList.begin()).second; mySurfaceList.erase(mySurfaceList.begin()); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBInitStatus FrameBuffer::initialize(const string& title, uInt32 width, uInt32 height) { ostringstream buf; // Now (re)initialize the SDL video system // These things only have to be done one per FrameBuffer creation if(SDL_WasInit(SDL_INIT_VIDEO) == 0) { if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) { buf << "ERROR: Couldn't initialize SDL: " << SDL_GetError() << endl; myOSystem->logMessage(buf.str(), 0); return kFailComplete; } } myInitializedCount++; // 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 uInt32 flags = mySDLFlags; #ifdef WINDOWED_SUPPORT // We assume that a desktop size of at least 640x480 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(myOSystem->desktopWidth() < 640 && myOSystem->desktopHeight() < 480 && (myOSystem->desktopWidth() < width || myOSystem->desktopHeight() < height)) return kFailTooLarge; if(myOSystem->settings().getString("fullscreen") == "1") { if(myOSystem->desktopWidth() < width || myOSystem->desktopHeight() < height) return kFailTooLarge; flags |= SDL_FULLSCREEN; } else flags &= ~SDL_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(myOSystem->desktopWidth() < width || myOSystem->desktopHeight() < height) return kFailTooLarge; #endif // Only update the actual flags if no errors were detected mySDLFlags = flags; // Set the available video modes for this framebuffer setAvailableVidModes(width, height); // Initialize video subsystem (make sure we get a valid mode) VideoMode mode = getSavedVidMode(); if(width <= mode.screen_w && height <= mode.screen_h) { // Set window title and icon setWindowTitle(title); if(myInitializedCount == 1) setWindowIcon(); if(initSubsystem(mode)) { centerAppWindow(mode); myImageRect.setWidth(mode.image_w); myImageRect.setHeight(mode.image_h); myImageRect.moveTo(mode.image_x, mode.image_y); myScreenRect.setWidth(mode.screen_w); myScreenRect.setHeight(mode.screen_h); // Did we get the requested fullscreen state? const string& fullscreen = myOSystem->settings().getString("fullscreen"); if(fullscreen != "-1") myOSystem->settings().setValue("fullscreen", fullScreen() ? "1" : "0"); setCursorState(); } else { myOSystem->logMessage("ERROR: Couldn't initialize video subsystem", 0); return kFailNotSupported; } } else return kFailTooLarge; // Erase any messages from a previous run myMsg.counter = 0; // Create surfaces for TIA statistics and general messages myStatsMsg.color = kBtnTextColor; myStatsMsg.w = myOSystem->infoFont().getMaxCharWidth() * 24 + 2; myStatsMsg.h = (myOSystem->infoFont().getFontHeight() + 2) * 2; if(myStatsMsg.surface == NULL) { uInt32 surfaceID = allocateSurface(myStatsMsg.w, myStatsMsg.h); myStatsMsg.surface = surface(surfaceID); } if(myMsg.surface == NULL) { uInt32 surfaceID = allocateSurface(640, myOSystem->font().getFontHeight()+10); myMsg.surface = surface(surfaceID); } // Finally, show some information about the framebuffer, // but only on the first initialization if(myInitializedCount == 1) myOSystem->logMessage(about(), 1); return kSuccess; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 switch(myOSystem->eventHandler().state()) { case EventHandler::S_EMULATE: { // 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() != EventHandler::S_EMULATE) break; #endif if(myOSystem->eventHandler().frying()) myOSystem->console().fry(); // And update the screen drawTIA(myRedrawEntireFrame); // Show frame statistics if(myStatsMsg.enabled) { const ConsoleInfo& info = myOSystem->console().about(); char msg[30]; BSPF_snprintf(msg, 30, "%3u @ %3.2ffps => %s", myOSystem->console().tia().scanlines(), myOSystem->console().getFramerate(), info.DisplayFormat.c_str()); myStatsMsg.surface->fillRect(0, 0, myStatsMsg.w, myStatsMsg.h, kBGColor); myStatsMsg.surface->drawString(myOSystem->infoFont(), msg, 1, 1, myStatsMsg.w, myStatsMsg.color, kTextAlignLeft); myStatsMsg.surface->drawString(myOSystem->infoFont(), info.BankSwitch, 1, 15, myStatsMsg.w, myStatsMsg.color, kTextAlignLeft); myStatsMsg.surface->addDirtyRect(0, 0, 0, 0); // force a full draw myStatsMsg.surface->setPos(myImageRect.x() + 1, myImageRect.y() + 1); myStatsMsg.surface->update(); } break; // S_EMULATE } case EventHandler::S_PAUSE: { // Only update the screen if it's been invalidated if(myRedrawEntireFrame) drawTIA(true); // Show a pause message every 5 seconds if(myPausedCount++ >= 7*myOSystem->frameRate()) { myPausedCount = 0; showMessage("Paused", kMiddleCenter); } break; // S_PAUSE } case EventHandler::S_MENU: { // When onscreen messages are enabled in double-buffer mode, // a full redraw is required myOSystem->menu().draw(myMsg.enabled && type() == kDoubleBuffer); break; // S_MENU } case EventHandler::S_CMDMENU: { // When onscreen messages are enabled in double-buffer mode, // a full redraw is required myOSystem->commandMenu().draw(myMsg.enabled && type() == kDoubleBuffer); break; // S_CMDMENU } case EventHandler::S_LAUNCHER: { // When onscreen messages are enabled in double-buffer mode, // a full redraw is required myOSystem->launcher().draw(myMsg.enabled && type() == kDoubleBuffer); break; // S_LAUNCHER } #ifdef DEBUGGER_SUPPORT case EventHandler::S_DEBUGGER: { // When onscreen messages are enabled in double-buffer mode, // a full redraw is required myOSystem->debugger().draw(myMsg.enabled && type() == kDoubleBuffer); break; // S_DEBUGGER } #endif default: return; } // Draw any pending messages if(myMsg.enabled) drawMessage(); // Do any post-frame stuff postFrameUpdate(); // The frame doesn't need to be completely redrawn anymore myRedrawEntireFrame = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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; // Erase old messages on the screen if(myMsg.counter > 0) { myRedrawEntireFrame = true; refresh(); } // Precompute the message coordinates myMsg.text = message; myMsg.counter = uInt32(myOSystem->frameRate()) << 1; // Show message for 2 seconds myMsg.color = kBtnTextColor; myMsg.w = myOSystem->font().getStringWidth(myMsg.text) + 10; myMsg.h = myOSystem->font().getFontHeight() + 8; myMsg.surface->setWidth(myMsg.w); myMsg.surface->setHeight(myMsg.h); myMsg.position = position; myMsg.enabled = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::toggleFrameStats() { showFrameStats(!myOSystem->settings().getBool("stats")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::showFrameStats(bool enable) { myOSystem->settings().setValue("stats", enable); myStatsMsg.enabled = enable; refresh(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::enableMessages(bool enable) { if(enable) { // Only re-enable frame stats if they were already enabled before myStatsMsg.enabled = myOSystem->settings().getBool("stats"); } else { // Temporarily disable frame stats myStatsMsg.enabled = false; // Erase old messages on the screen myMsg.enabled = false; myMsg.counter = 0; refresh(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void FrameBuffer::drawMessage() { // Draw the bounded box and text switch(myMsg.position) { case kTopLeft: myMsg.x = 5; myMsg.y = 5; break; case kTopCenter: myMsg.x = (myImageRect.width() - myMsg.w) >> 1; myMsg.y = 5; break; case kTopRight: myMsg.x = myImageRect.width() - myMsg.w - 5; myMsg.y = 5; break; case kMiddleLeft: myMsg.x = 5; myMsg.y = (myImageRect.height() - myMsg.h) >> 1; break; case kMiddleCenter: myMsg.x = (myImageRect.width() - myMsg.w) >> 1; myMsg.y = (myImageRect.height() - myMsg.h) >> 1; break; case kMiddleRight: myMsg.x = myImageRect.width() - myMsg.w - 5; myMsg.y = (myImageRect.height() - myMsg.h) >> 1; break; case kBottomLeft: myMsg.x = 5; myMsg.y = myImageRect.height() - myMsg.h - 5; break; case kBottomCenter: myMsg.x = (myImageRect.width() - myMsg.w) >> 1; myMsg.y = myImageRect.height() - myMsg.h - 5; break; case kBottomRight: myMsg.x = myImageRect.width() - myMsg.w - 5; myMsg.y = myImageRect.height() - myMsg.h - 5; break; } myMsg.surface->setPos(myMsg.x + myImageRect.x(), myMsg.y + myImageRect.y()); myMsg.surface->fillRect(1, 1, myMsg.w-2, myMsg.h-2, kBtnColor); myMsg.surface->box(0, 0, myMsg.w, myMsg.h, kColor, kShadowColor); myMsg.surface->drawString(myOSystem->font(), myMsg.text, 4, 4, myMsg.w, myMsg.color, kTextAlignLeft); myMsg.counter--; // Either erase the entire message (when time is reached), // or show again this frame if(myMsg.counter == 0) // Force an immediate update { myMsg.enabled = false; refresh(); } else { myMsg.surface->addDirtyRect(0, 0, 0, 0); myMsg.surface->update(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::refresh() { // This method partly duplicates the behaviour in ::update() // Here, however, make sure to redraw *all* surfaces applicable to the // current EventHandler state // We also check for double-buffered modes, and when present // update both buffers accordingly // // This method is in essence a FULL refresh, putting all rendering // buffers in a known, fully redrawn state bool doubleBuffered = (type() == kDoubleBuffer); switch(myOSystem->eventHandler().state()) { case EventHandler::S_EMULATE: case EventHandler::S_PAUSE: invalidate(); drawTIA(true); if(doubleBuffered) { postFrameUpdate(); invalidate(); drawTIA(true); } break; case EventHandler::S_MENU: invalidate(); drawTIA(true); myOSystem->menu().draw(true); if(doubleBuffered) { postFrameUpdate(); invalidate(); drawTIA(true); myOSystem->menu().draw(true); } break; case EventHandler::S_CMDMENU: invalidate(); drawTIA(true); myOSystem->commandMenu().draw(true); if(doubleBuffered) { postFrameUpdate(); invalidate(); drawTIA(true); myOSystem->commandMenu().draw(true); } break; case EventHandler::S_LAUNCHER: invalidate(); myOSystem->launcher().draw(true); if(doubleBuffered) { postFrameUpdate(); invalidate(); myOSystem->launcher().draw(true); } break; #ifdef DEBUGGER_SUPPORT case EventHandler::S_DEBUGGER: invalidate(); myOSystem->debugger().draw(true); if(doubleBuffered) { postFrameUpdate(); invalidate(); myOSystem->debugger().draw(true); } break; #endif default: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::setNTSC(NTSCFilter::Preset preset, bool show) { ostringstream buf; if(type() == kDoubleBuffer) { 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); } else buf << "TV filtering not available in software mode"; if(show) showMessage(buf.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::setScanlineIntensity(int amount) { ostringstream buf; if(type() == kDoubleBuffer) { 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"; } else buf << "Scanlines not available in software mode"; showMessage(buf.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::toggleScanlineInterpolation() { ostringstream buf; if(type() == kDoubleBuffer) { 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"; } else buf << "Scanlines not available in software mode"; showMessage(buf.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 FrameBuffer::allocateSurface(int w, int h, bool useBase) { // Create a new surface FBSurface* surface = createSurface(w, h, useBase); // Add it to the list mySurfaceList.insert(make_pair((uInt32)mySurfaceList.size(), surface)); // Return a reference to it return mySurfaceList.size() - 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurface* FrameBuffer::surface(uInt32 id) const { map::const_iterator iter = mySurfaceList.find(id); return iter != mySurfaceList.end() ? iter->second : NULL; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::resetSurfaces(FBSurface* tiasurface) { // 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 map::iterator iter; for(iter = mySurfaceList.begin(); iter != mySurfaceList.end(); ++iter) iter->second->free(); if(tiasurface) tiasurface->free(); for(iter = mySurfaceList.begin(); iter != mySurfaceList.end(); ++iter) iter->second->reload(); if(tiasurface) tiasurface->reload(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 FrameBuffer::tiaPixel(uInt32 idx, uInt8 shift) const { uInt8 c = *(myOSystem->console().tia().currentFrameBuffer() + idx) | shift; uInt8 p = *(myOSystem->console().tia().previousFrameBuffer() + idx) | shift; return (!myUsePhosphor ? myDefPalette[c] : myAvgPalette[c][p]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::setTIAPalette(const uInt32* palette) { int i, j; // Set palette for normal fill for(i = 0; i < 256; ++i) { Uint8 r = (palette[i] >> 16) & 0xff; Uint8 g = (palette[i] >> 8) & 0xff; Uint8 b = palette[i] & 0xff; myDefPalette[i] = mapRGB(r, g, b); if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { myDefPalette24[i][0] = b; myDefPalette24[i][1] = g; myDefPalette24[i][2] = r; } else { myDefPalette24[i][0] = r; myDefPalette24[i][1] = g; myDefPalette24[i][2] = b; } } // Set palette for phosphor effect for(i = 0; i < 256; ++i) { for(j = 0; j < 256; ++j) { uInt8 ri = (palette[i] >> 16) & 0xff; uInt8 gi = (palette[i] >> 8) & 0xff; uInt8 bi = palette[i] & 0xff; uInt8 rj = (palette[j] >> 16) & 0xff; uInt8 gj = (palette[j] >> 8) & 0xff; uInt8 bj = palette[j] & 0xff; Uint8 r = (Uint8) getPhosphor(ri, rj); Uint8 g = (Uint8) getPhosphor(gi, gj); Uint8 b = (Uint8) getPhosphor(bi, bj); myAvgPalette[i][j] = mapRGB(r, g, b); } } myRedrawEntireFrame = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::setUIPalette(const uInt32* palette) { // Set palette for GUI for(int i = 0, j = 256; i < kNumColors-256; ++i, ++j) { Uint8 r = (palette[i] >> 16) & 0xff; Uint8 g = (palette[i] >> 8) & 0xff; Uint8 b = palette[i] & 0xff; myDefPalette[j] = mapRGB(r, g, b); if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { myDefPalette24[j][0] = b; myDefPalette24[j][1] = g; myDefPalette24[j][2] = r; } else { myDefPalette24[j][0] = r; myDefPalette24[j][1] = g; myDefPalette24[j][2] = b; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::stateChanged(EventHandler::State state) { // Make sure any onscreen messages are removed myMsg.enabled = false; myMsg.counter = 0; myRedrawEntireFrame = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::toggleFullscreen() { setFullscreen(!fullScreen()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::setFullscreen(bool enable) { #ifdef WINDOWED_SUPPORT // '-1' means fullscreen mode is completely disabled if(enable && myOSystem->settings().getString("fullscreen") != "-1" ) mySDLFlags |= SDL_FULLSCREEN; else mySDLFlags &= ~SDL_FULLSCREEN; // Do a dummy call to getSavedVidMode to set up the modelists // and have it point to the correct 'current' mode getSavedVidMode(); // Do a mode change to the 'current' mode by not passing a '+1' or '-1' // to changeVidMode() changeVidMode(0); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBuffer::changeVidMode(int direction) { EventHandler::State state = myOSystem->eventHandler().state(); bool inUIMode = (state == EventHandler::S_DEBUGGER || state == EventHandler::S_LAUNCHER); // Ignore any attempts to change video size while in UI mode if(inUIMode && direction != 0) return false; // Only save mode changes in TIA mode with a valid selector bool saveModeChange = !inUIMode && (direction == -1 || direction == +1); if(direction == +1) myCurrentModeList->next(); else if(direction == -1) myCurrentModeList->previous(); VideoMode vidmode = myCurrentModeList->current(myOSystem->settings(), fullScreen()); if(setVidMode(vidmode)) { centerAppWindow(vidmode); myImageRect.setWidth(vidmode.image_w); myImageRect.setHeight(vidmode.image_h); myImageRect.moveTo(vidmode.image_x, vidmode.image_y); myScreenRect.setWidth(vidmode.screen_w); myScreenRect.setHeight(vidmode.screen_h); // Did we get the requested fullscreen state? const string& fullscreen = myOSystem->settings().getString("fullscreen"); if(fullscreen != "-1") myOSystem->settings().setValue("fullscreen", fullScreen() ? "1" : "0"); setCursorState(); if(!inUIMode) { if(direction != 0) // only show message when mode actually changes showMessage(vidmode.gfxmode.description); } if(saveModeChange) myOSystem->settings().setValue("tia_filter", vidmode.gfxmode.name); refresh(); } else return false; return true; /* cerr << "New mode:" << endl << " screen w = " << newmode.screen_w << endl << " screen h = " << newmode.screen_h << endl << " image x = " << newmode.image_x << endl << " image y = " << newmode.image_y << endl << " image w = " << newmode.image_w << endl << " image h = " << newmode.image_h << endl << " zoom = " << newmode.zoom << endl << " name = " << newmode.name << endl << endl; */ } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::setCursorState() { // Always grab mouse in fullscreen or during emulation (if enabled), // and don't show the cursor during emulation bool emulation = myOSystem->eventHandler().state() == EventHandler::S_EMULATE; grabMouse(fullScreen() || (emulation && myOSystem->settings().getBool("grabmouse"))); showCursor(!emulation); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::toggleGrabMouse() { bool state = myOSystem->settings().getBool("grabmouse"); myOSystem->settings().setValue("grabmouse", !state); setCursorState(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::showCursor(bool show) { SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::grabMouse(bool grab) { SDL_WM_GrabInput(grab ? SDL_GRAB_ON : SDL_GRAB_OFF); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBuffer::fullScreen() const { #ifdef WINDOWED_SUPPORT return mySDLFlags & SDL_FULLSCREEN; #else return true; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::setWindowTitle(const string& title) { SDL_WM_SetCaption(title.c_str(), "stella"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::setWindowIcon() { #if !defined(BSPF_MAC_OSX) && !defined(BSPF_UNIX) #include "stella.xpm" // The Stella icon // Set the window icon uInt32 w, h, ncols, nbytes; uInt32 rgba[256], icon[32 * 32]; uInt8 mask[32][4]; sscanf(stella_icon[0], "%u %u %u %u", &w, &h, &ncols, &nbytes); if((w != 32) || (h != 32) || (ncols > 255) || (nbytes > 1)) { myOSystem->logMessage("ERROR: Couldn't load the application icon.", 0); return; } for(uInt32 i = 0; i < ncols; i++) { unsigned char code; char color[32]; uInt32 col; sscanf(stella_icon[1 + i], "%c c %s", &code, color); if(!strcmp(color, "None")) col = 0x00000000; else if(!strcmp(color, "black")) col = 0xFF000000; else if (color[0] == '#') { sscanf(color + 1, "%06x", &col); col |= 0xFF000000; } else { myOSystem->logMessage("ERROR: Couldn't load the application icon.", 0); return; } rgba[code] = col; } memset(mask, 0, sizeof(mask)); for(h = 0; h < 32; h++) { const char* line = stella_icon[1 + ncols + h]; for(w = 0; w < 32; w++) { icon[w + 32 * h] = rgba[(int)line[w]]; if(rgba[(int)line[w]] & 0xFF000000) mask[h][w >> 3] |= 1 << (7 - (w & 0x07)); } } SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(icon, 32, 32, 32, 32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000); SDL_WM_SetIcon(surface, (unsigned char *) mask); SDL_FreeSurface(surface); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 FrameBuffer::getPhosphor(uInt8 c1, uInt8 c2) const { if(c2 > c1) BSPF_swap(c1, c2); return ((c1 - c2) * myPhosphorBlend)/100 + c2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const VariantList& FrameBuffer::supportedTIAFilters(const string& type) { uInt32 max_zoom = maxWindowSizeForScreen(320, 210, myOSystem->desktopWidth(), myOSystem->desktopHeight()); uInt8 mask = (type == "soft" ? 0x1 : 0x2); uInt32 firstmode = 1; if(myOSystem->desktopWidth() < 640 || myOSystem->desktopHeight() < 480) firstmode = 0; myTIAFilters.clear(); for(uInt32 i = firstmode; i < GFX_NumModes; ++i) { // For now, just include all filters // This will change once OpenGL-only filters are added if((ourGraphicsModes[i].avail & mask) && ourGraphicsModes[i].zoom <= max_zoom) { myTIAFilters.push_back(ourGraphicsModes[i].description, ourGraphicsModes[i].name); } } return myTIAFilters; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 FrameBuffer::maxWindowSizeForScreen(uInt32 baseWidth, uInt32 baseHeight, uInt32 screenWidth, uInt32 screenHeight) { 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) { // Modelists are different depending on what state we're in EventHandler::State state = myOSystem->eventHandler().state(); bool inUIMode = (state == EventHandler::S_DEBUGGER || state == EventHandler::S_LAUNCHER); myWindowedModeList.clear(); myFullscreenModeList.clear(); // In UI/windowed mode, there's only one valid video mode we can use // We don't use maxWindowSizeForScreen here, since UI mode has to open its // window at the requested size if(inUIMode) { VideoMode m; m.image_x = m.image_y = 0; m.image_w = m.screen_w = baseWidth; m.image_h = m.screen_h = baseHeight; m.gfxmode = ourGraphicsModes[0]; // this should be zoom1x addVidMode(m); } else { // Scan list of filters, adding only those which are appropriate // for the given dimensions uInt32 max_zoom = maxWindowSizeForScreen(baseWidth, baseHeight, myOSystem->desktopWidth(), myOSystem->desktopHeight()); // Figure our the smallest zoom level we can use uInt32 firstmode = 1; if(myOSystem->desktopWidth() < 640 || myOSystem->desktopHeight() < 480) firstmode = 0; for(uInt32 i = firstmode; i < GFX_NumModes; ++i) { uInt32 zoom = ourGraphicsModes[i].zoom; if(zoom <= max_zoom) { VideoMode m; m.image_x = m.image_y = 0; m.image_w = m.screen_w = baseWidth * zoom; m.image_h = m.screen_h = baseHeight * zoom; m.gfxmode = ourGraphicsModes[i]; addVidMode(m); } } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::addVidMode(VideoMode& mode) { // The are minimum size requirements on a screen, no matter is in fullscreen // or windowed mode // Various part of the UI system depend on having at least 320x240 pixels // available, so we must enforce it here // Windowed modes can be sized exactly as required, since there's normally // no restriction on window size (between the minimum and maximum size) mode.screen_w = BSPF_max(mode.screen_w, 320u); mode.screen_h = BSPF_max(mode.screen_h, 240u); mode.image_x = (mode.screen_w - mode.image_w) >> 1; mode.image_y = (mode.screen_h - mode.image_h) >> 1; myWindowedModeList.add(mode); // There are often stricter requirements on fullscreen modes, and they're // normally different depending on the OSystem in use // As well, we usually can't get fullscreen modes in the exact size // we want, so we need to calculate image offsets const ResolutionList& res = myOSystem->supportedResolutions(); for(uInt32 i = 0; i < res.size(); ++i) { if(mode.screen_w <= res[i].width && mode.screen_h <= res[i].height) { // Auto-calculate 'smart' centering; platform-specific framebuffers are // free to ignore or augment it mode.screen_w = BSPF_max(res[i].width, 320u); mode.screen_h = BSPF_max(res[i].height, 240u); mode.image_x = (mode.screen_w - mode.image_w) >> 1; mode.image_y = (mode.screen_h - mode.image_h) >> 1; break; } } myFullscreenModeList.add(mode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBuffer::VideoMode FrameBuffer::getSavedVidMode() { EventHandler::State state = myOSystem->eventHandler().state(); if(fullScreen()) myCurrentModeList = &myFullscreenModeList; 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 == EventHandler::S_DEBUGGER || state == EventHandler::S_LAUNCHER) { myCurrentModeList->setByGfxMode(GFX_Zoom1x); } else { const string& name = myOSystem->settings().getString("tia_filter"); myCurrentModeList->setByGfxMode(name); } return myCurrentModeList->current(myOSystem->settings(), fullScreen()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::centerAppWindow(const VideoMode& mode) { // Attempt to center the application window in non-fullscreen mode if(!fullScreen() && myOSystem->settings().getBool("center")) { int x = mode.screen_w >= myOSystem->desktopWidth() ? 0 : ((myOSystem->desktopWidth() - mode.screen_w) >> 1); int y = mode.screen_h >= myOSystem->desktopHeight() ? 0 : ((myOSystem->desktopHeight() - mode.screen_h) >> 1); myOSystem->setAppWindowPos(x, y, mode.screen_w, mode.screen_h); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBuffer::VideoModeList::VideoModeList() : myIdx(-1) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBuffer::VideoModeList::~VideoModeList() { clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::VideoModeList::add(VideoMode mode) { myModeList.push_back(mode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::VideoModeList::clear() { myModeList.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBuffer::VideoModeList::isEmpty() const { return myModeList.isEmpty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 FrameBuffer::VideoModeList::size() const { return myModeList.size(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::VideoModeList::previous() { --myIdx; if(myIdx < 0) myIdx = myModeList.size() - 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const FrameBuffer::VideoMode FrameBuffer:: VideoModeList::current(const Settings& settings, bool isFullscreen) const { // Fullscreen modes are related to the 'fullres' setting // If it's 'auto', we just use the mode as already previously defined // If it's not 'auto', attempt to fit the mode into the resolution // specified by 'fullres' (if possible) if(isFullscreen && !BSPF_equalsIgnoreCase(settings.getString("fullres"), "auto")) { // Only use 'fullres' if it's *bigger* than the requested mode const GUI::Size& s = settings.getSize("fullres"); if(s.w != -1 && s.h != -1 && (uInt32)s.w >= myModeList[myIdx].screen_w && (uInt32)s.h >= myModeList[myIdx].screen_h) { VideoMode mode = myModeList[myIdx]; mode.screen_w = s.w; mode.screen_h = s.h; mode.image_x = (mode.screen_w - mode.image_w) >> 1; mode.image_y = (mode.screen_h - mode.image_h) >> 1; return mode; } } // Otherwise, we just use the mode has it was defined in ::addVidMode() return myModeList[myIdx]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::VideoModeList::next() { myIdx = (myIdx + 1) % myModeList.size(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::VideoModeList::setByGfxMode(GfxID id) { // First we determine which graphics mode is being requested bool found = false; GraphicsMode gfxmode; for(uInt32 i = 0; i < GFX_NumModes; ++i) { if(ourGraphicsModes[i].type == id) { gfxmode = ourGraphicsModes[i]; found = true; break; } } if(!found) gfxmode = ourGraphicsModes[0]; // Now we scan the list for the applicable video mode set(gfxmode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::VideoModeList::setByGfxMode(const string& name) { // First we determine which graphics mode is being requested bool found = false; GraphicsMode gfxmode; for(uInt32 i = 0; i < GFX_NumModes; ++i) { if(BSPF_equalsIgnoreCase(ourGraphicsModes[i].name, name) || BSPF_equalsIgnoreCase(ourGraphicsModes[i].description, name)) { gfxmode = ourGraphicsModes[i]; found = true; break; } } if(!found) gfxmode = ourGraphicsModes[0]; // Now we scan the list for the applicable video mode set(gfxmode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::VideoModeList::set(const GraphicsMode& gfxmode) { // Attempt to point the current mode to the one given myIdx = -1; // First search for the given gfx id for(unsigned int i = 0; i < myModeList.size(); ++i) { if(myModeList[i].gfxmode.type == gfxmode.type) { myIdx = i; return; } } // If we get here, then the gfx type couldn't be found, so we search // for the first mode with the same zoomlevel (making sure that the // requested mode can fit inside the current screen) if(gfxmode.zoom > myModeList[myModeList.size()-1].gfxmode.zoom) { myIdx = myModeList.size()-1; return; } else { for(unsigned int i = 0; i < myModeList.size(); ++i) { if(myModeList[i].gfxmode.zoom == gfxmode.zoom) { myIdx = i; return; } } } // Finally, just pick the lowest video mode myIdx = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::VideoModeList::print() { cerr << "VideoModeList: " << endl << endl; for(Common::Array::const_iterator i = myModeList.begin(); i != myModeList.end(); ++i) { cerr << " Mode " << i << endl; print(*i); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::VideoModeList::print(const VideoMode& mode) { cerr << " screen w = " << mode.screen_w << endl << " screen h = " << mode.screen_h << endl << " image x = " << mode.image_x << endl << " image y = " << mode.image_y << endl << " image w = " << mode.image_w << endl << " image h = " << mode.image_h << endl << " gfx id = " << mode.gfxmode.type << endl << " gfx name = " << mode.gfxmode.name << endl << " gfx desc = " << mode.gfxmode.description << endl << " gfx zoom = " << mode.gfxmode.zoom << endl << endl; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 kSolidLine: 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 kDashLine: unsigned int i, skip, lwidth = 1; 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); } } break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurface::drawString(const GUI::Font& font, const string& s, int x, int y, int w, uInt32 color, TextAlignment align, int deltax, bool useEllipsis) { const int leftX = x, rightX = x + w; unsigned int 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 unless we want to // make this configurable, replacing the middle probably is a good // compromise. const int ellipsisWidth = font.getStringWidth("..."); // SLOW algorithm to remove enough of the middle. But it is good enough for now. const int halfWidth = (w - ellipsisWidth) / 2; int w2 = 0; for(i = 0; i < s.size(); ++i) { int charWidth = font.getCharWidth(s[i]); if(w2 + charWidth > halfWidth) break; w2 += charWidth; str += s[i]; } // At this point we know that the first 'i' chars are together 'w2' // pixels wide. We took the first i-1, and add "..." to them. str += "..."; // The original string is width wide. Of those we already skipped past // w2 pixels, which means (width - w2) remain. // The new str is (w2+ellipsisWidth) wide, so we can accomodate about // (w - (w2+ellipsisWidth)) more pixels. // Thus we skip ((width - w2) - (w - (w2+ellipsisWidth))) = // (width + ellipsisWidth - w) int skip = width + ellipsisWidth - w; for(; i < s.size() && skip > 0; ++i) skip -= font.getCharWidth(s[i]); // Append the remaining chars, if any for(; i < s.size(); ++i) str += s[i]; width = font.getStringWidth(str); } else str = s; if(align == kTextAlignCenter) x = x + (w - width - 1)/2; else if(align == kTextAlignRight) 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); x += w; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBuffer::GraphicsMode FrameBuffer::ourGraphicsModes[GFX_NumModes] = { { GFX_Zoom1x, "zoom1x", "Zoom 1x", 1, 0x3 }, { GFX_Zoom2x, "zoom2x", "Zoom 2x", 2, 0x3 }, { GFX_Zoom3x, "zoom3x", "Zoom 3x", 3, 0x3 }, { GFX_Zoom4x, "zoom4x", "Zoom 4x", 4, 0x3 }, { GFX_Zoom5x, "zoom5x", "Zoom 5x", 5, 0x3 }, { GFX_Zoom6x, "zoom6x", "Zoom 6x", 6, 0x3 }, { GFX_Zoom7x, "zoom7x", "Zoom 7x", 7, 0x3 }, { GFX_Zoom8x, "zoom8x", "Zoom 8x", 8, 0x3 }, { GFX_Zoom9x, "zoom9x", "Zoom 9x", 9, 0x3 }, { GFX_Zoom10x, "zoom10x", "Zoom 10x", 10, 0x3 } }; stella-3.9.3/src/emucore/stella.pro0000644000175000001440000231341712267025147016654 0ustar stephenusers"Cartridge.MD5" "1367e41858be525710eb04d0dab53505" "Cartridge.Manufacturer" "Kyle Pittman" "Cartridge.Name" "Zelda (2003) (Kyle Pittman) (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "007d18dedc1f0565f09c42aa61a6f585" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-843" "Cartridge.Name" "Worm War I (1983) (CCE)" "" "Cartridge.MD5" "faebcb2ef1f3831b2fc1dbd39d36517c" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Steve Woita" "Cartridge.ModelNo" "CX2696" "Cartridge.Name" "Asterix (1983) (Atari) (PAL)" "Cartridge.Note" "AKA Taz" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "5864cab0bc21a60be3853b6bcd50c59f" "Cartridge.Name" "Commando Raid (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "2d9e5d8d083b6367eda880e80dfdfaeb" "Cartridge.Manufacturer" "Selchow & Righter - QDI" "Cartridge.ModelNo" "87" "Cartridge.Name" "Glib (1983) (Selchow & Righter)" "" "Cartridge.MD5" "b86552198f52cfce721bafb496363099" "Cartridge.Manufacturer" "Apollo, Tim Martin" "Cartridge.ModelNo" "AP-2007" "Cartridge.Name" "Kyphus (1982) (Apollo) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "c31a17942d162b80962cb1f7571cd1d5" "Cartridge.Manufacturer" "Home Vision - Gem International Corp." "Cartridge.ModelNo" "VCS83112" "Cartridge.Name" "Sky Alien (1983) (Home Vision) (PAL)" "" "Cartridge.MD5" "542c6dd5f7280179b51917a4cba4faff" "Cartridge.Manufacturer" "ZiMAG - Emag - Vidco" "Cartridge.ModelNo" "GN-080" "Cartridge.Name" "Spinning Fireball (1983) (ZiMAG) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "40" "" "Cartridge.MD5" "613abf596c304ef6dbd8f3351920c37a" "Cartridge.Name" "Boring Pac-Man (Hack)" "Cartridge.Note" "Hack of Pac-Man" "Cartridge.Rarity" "Hack" "Display.YStart" "33" "" "Cartridge.MD5" "71f8bacfbdca019113f3f0801849057e" "Cartridge.Manufacturer" "Atari, Dan Hitchens" "Cartridge.ModelNo" "CX26126" "Cartridge.Name" "Elevator Action (1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "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" "841b7bc1cad05f5408302308777d49dc" "Cartridge.Manufacturer" "Activision" "Cartridge.Name" "Unknown Activision Game #1 (10-22-1982) (Activision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "72a5b5052272ac785fa076709d16cef4" "Cartridge.Name" "KC Munckin (29-01-2003) (J. Parlee)" "" "Cartridge.MD5" "d605ed12f4eaaaec3dcd5aa909a4bad7" "Cartridge.Name" "Chronocolor Frame Demo (10-01-2003) (AD)" "" "Cartridge.MD5" "008543ae43497af015e9428a5e3e874e" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.09) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0fc161704c46e16f7483f92b06c1558d" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-853" "Cartridge.Name" "Spider Fighter (1983) (CCE)" "Display.YStart" "30" "" "Cartridge.MD5" "fb09ee4ccd47ae74a3c314f0d8a40344" "Cartridge.Name" "Titans (SnailSoft)" "" "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" "65bd29e8ab1b847309775b0de6b2e4fe" "Cartridge.Manufacturer" "Coleco, Ed English" "Cartridge.ModelNo" "2667" "Cartridge.Name" "Roc 'n Rope (1984) (Coleco)" "" "Cartridge.MD5" "47cd61f83457a0890de381e478f5cf5f" "Cartridge.Manufacturer" "Imagic, Wilfredo 'Willy' Aguilar, Michael Becker, Rob Fulop" "Cartridge.ModelNo" "720111-2A, 13205" "Cartridge.Name" "Fathom (1983) (Imagic) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7dcbfd2acc013e817f011309c7504daa" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4000, AR-4100" "Cartridge.Name" "Phaser Patrol (1982) (Arcadia)" "Display.YStart" "24" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2b42da79a682ed6e2d735facbf70107e" "Cartridge.Name" "DKjr Improved (Hack)" "Cartridge.Note" "Hack of Donkey Kong Jr." "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "d2c305a443dfc49e8430964d7c1bd1b7" "Cartridge.Name" "Star Fire - Advice on radar needed (16-10-2002) (MP)" "" "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" "62ffd175cac3f781ef6e4870136a2520" "Cartridge.Name" "2600 Digital Clock (V x.xx) (PD)" "" "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" "69fac82cd2312dd9ce5d90e22e2f070a" "Cartridge.Manufacturer" "Spectravision, Spectravideo - Quelle" "Cartridge.ModelNo" "SA-202 - 412.851 8" "Cartridge.Name" "Planet Patrol (1982) (Spectravision) (PAL)" "" "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" "" "Cartridge.MD5" "4d7517ae69f95cfbc053be01312b7dba" "Cartridge.Manufacturer" "Atari, Alan Miller - Sears" "Cartridge.ModelNo" "CX2641 - 99807, 49-75105" "Cartridge.Name" "Surround (1977) (Atari)" "" "Cartridge.MD5" "3ff5165378213dab531ffa4f1a41ae45" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "311377" "Cartridge.Name" "Pygmy (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Lock 'n' Chase (Double-Game Package)" "" "Cartridge.MD5" "e4bff1d5df70163c0428a1ead309c22d" "Cartridge.Manufacturer" "Atari, Robert C. Polaro, Alan J. Murphy" "Cartridge.ModelNo" "CX2609, CX2609P" "Cartridge.Name" "Defender (1982) (Atari) (PAL)" "" "Cartridge.MD5" "235436ab0832370e73677c9c6f0c8b06" "Cartridge.Name" "Beast Invaders (Double Shot) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "de3d0e37729d85afcb25a8d052a6e236" "Cartridge.Manufacturer" "Spectravision, Spectravideo" "Cartridge.ModelNo" "SA-204" "Cartridge.Name" "Tapeworm (1982) (Spectravision)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d339b95f273f8c3550dc4daa67a4aa94" "Cartridge.Name" "Laser Blast (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "1e1817d9cbcc3ba75043b7db4e6c228f" "Cartridge.Name" "Star Fire (07-10-2002) (MP)" "" "Cartridge.MD5" "36b20c427975760cb9cf4a47e41369e4" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26143" "Cartridge.Name" "Donkey Kong (1987) (Atari)" "" "Cartridge.MD5" "7f6533386644c7d6358f871666c86e79" "Cartridge.Manufacturer" "CommaVid, Irwin Gaines" "Cartridge.ModelNo" "CM-008" "Cartridge.Name" "Cakewalk (1983) (CommaVid)" "" "Cartridge.MD5" "977294ae6526c31c7f9a166ee00964ad" "Cartridge.Manufacturer" "Atari - GCC, Douglas B. Macrae" "Cartridge.ModelNo" "CX2677, CX2677P" "Cartridge.Name" "Dig Dug (1983) (Atari) (PAL)" "" "Cartridge.MD5" "be929419902e21bd7830a7a7d746195d" "Cartridge.Manufacturer" "Activision, Garry Kitchen" "Cartridge.ModelNo" "AX-025, AX-025-04" "Cartridge.Name" "Keystone Kapers (1983) (Activision)" "" "Cartridge.MD5" "155fa7f479dcba3b10b1494e236d6010" "Cartridge.Manufacturer" "Skyworks" "Cartridge.Name" "Tomcat (2002) (Skyworks) (PAL)" "Cartridge.Note" "AKA The F-14 Flight Simulator" "" "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" "3f9431cc8c5e2f220b2ac14bbc8231f4" "Cartridge.Name" "Colors Demo (PD)" "" "Cartridge.MD5" "f0d393dbf4164a688b2346770c9bbd12" "Cartridge.Name" "Racquetball (Unknown)" "Display.Phosphor" "YES" "" "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" "bfcabc6995ef42d0b6c06786993dc4d6" "Cartridge.Name" "Star Fire - Creating a Universe (09-09-2002) (MP)" "" "Cartridge.MD5" "99a24d7bb31d49b720b422550b32c35f" "Cartridge.Name" "Hangman Ghost Biglist1 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "3eae062a9b722bda1255d474a87eca5c" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.ModelNo" "CX2605, CX2605P" "Cartridge.Name" "Outlaw (1978) (Atari) (PAL) (4K)" "" "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" "" "Cartridge.MD5" "598a4e6e12f8238b7e7555f5a7777b46" "Cartridge.Manufacturer" "Tigervision" "Cartridge.ModelNo" "7-008" "Cartridge.Name" "Miner 2049er (1982) (Tigervision) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "30" "" "Cartridge.MD5" "7f430c33044e0354815392b53a9a772d" "Cartridge.Manufacturer" "HES" "Cartridge.Name" "2 Pak Special - Cavern Blaster, City War (1992) (HES) (PAL)" "" "Cartridge.MD5" "30997031b668e37168d4d0e299ccc46f" "Cartridge.Name" "John K Harvey's Equalizer (PAL) (PD)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "85e48d68c8d802e3ba9d494a47d6e016" "Cartridge.Name" "Ship Demo (V 15) (PD)" "" "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" "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" "9d4bc7c6fe9a7c8c4aa24a237c340adb" "Cartridge.Manufacturer" "Dennis Debro" "Cartridge.Name" "Climber 5 (16-04-2003) (Dennis Debro)" "Cartridge.Note" "For Philly Classic 4" "Cartridge.Rarity" "Homebrew" "Display.YStart" "28" "" "Cartridge.MD5" "f39e4bc99845edd8621b0f3c7b8c4fd9" "Cartridge.Manufacturer" "AtariAge" "Cartridge.Name" "Toyshop Trouble (AtariAge)" "Cartridge.Note" "F8 Emulator Release" "Controller.Right" "PADDLES" "Display.YStart" "33" "" "Cartridge.MD5" "78963290052fd17c6c7998305ab3a6a0" "Cartridge.Name" "Push (V0.08) (2001) (AD)" "" "Cartridge.MD5" "cd9fea12051e414a6dfe17052067da8e" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "Marble Craze Demo (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "2c9fadd510509cc7f28f1ccba931855f" "Cartridge.Name" "Hangman Invader Biglist1 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "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" "c1b1049b88bcd98437d8872d1d62ba31" "Cartridge.Name" "Demo Image Series #4 - Donald (19-02-2003) (AD)" "" "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" "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" "01" "" "Cartridge.MD5" "f1beca5a198cf08190487e5c27b8e540" "Cartridge.Name" "Fu Kung! (V0.16) (2003) (AD)" "" "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" "230" "" "Cartridge.MD5" "7b5207e68ee85b16998bea861987c690" "Cartridge.Manufacturer" "Atari, Carol Shaw" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "3-D Tic-Tac-Toe (32 in 1) (1988) (Atari) (PAL)" "Display.YStart" "62" "" "Cartridge.MD5" "cba56e939252b05df7b7de87307d12ca" "Cartridge.Name" "Playfield Text Demo (2001) (Roger Williams)" "" "Cartridge.MD5" "0173675d40a8d975763ee493377ca87d" "Cartridge.Manufacturer" "CBS Electronics, Ed English" "Cartridge.ModelNo" "4L1751" "Cartridge.Name" "Roc 'n Rope (1984) (CBS Electronics) (PAL)" "Display.YStart" "50" "" "Cartridge.MD5" "3f01bd6d059396f495a4cde7de0ab180" "Cartridge.Name" "Qb (Special Edition) (NTSC) (Retroactive)" "Display.Phosphor" "YES" "" "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" "Display.YStart" "30" "" "Cartridge.MD5" "e25e173740f7ecc0e23025445c4591f3" "Cartridge.Manufacturer" "Greg Zumwalt" "Cartridge.Name" "Comitoid (Greg Zumwalt)" "" "Cartridge.MD5" "539d26b6e9df0da8e7465f0f5ad863b7" "Cartridge.Manufacturer" "Atari, Carol Shaw - Sears" "Cartridge.ModelNo" "CX2636 - 49-75156" "Cartridge.Name" "Video Checkers (1980) (Atari)" "" "Cartridge.MD5" "681206a6bde73e71c19743607e96c4bb" "Cartridge.Name" "Casino (Unknown) (PAL)" "Controller.Left" "PADDLES" "Display.YStart" "49" "" "Cartridge.MD5" "75b557be7f08db84ec5b242207b9f241" "Cartridge.Name" "Space Treat (30-12-2002) (Fabrizio Zavagli) [a1]" "" "Cartridge.MD5" "c3aeb796fdaf9429e8cd6af6346f337e" "Cartridge.Name" "If It's Not One Thing It's Another (1997) (Chris Cracknell)" "" "Cartridge.MD5" "6354f9c7588a27109c66905b0405825b" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Amidar DS (2003) (TJ) (Hack)" "Cartridge.Note" "Hack of Amidar" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "68cd2adc6b1fc9a1f263ab4561112f30" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Boulderdash Demo (09-12-2002) (TJ)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "dcc2956c7a39fdbf1e861fc5c595da0d" "Cartridge.Manufacturer" "M Network, David Rolfe - INTV" "Cartridge.ModelNo" "MT5664" "Cartridge.Name" "Frogs and Flies (1982) (M Network)" "" "Cartridge.MD5" "1351c67b42770c1bd758c3e42f553fea" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Keystone Kapers (Digivision)" "" "Cartridge.MD5" "be1922bd8e09d74da471287e1e968653" "Cartridge.Manufacturer" "Cropsy" "Cartridge.Name" "Hangman Pacman Demo (Cropsy) (Hack)" "Cartridge.Note" "Hack of Hangman" "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" "f6a282374441012b01714e19699fc62a" "Cartridge.Manufacturer" "ZiMAG - Emag - Vidco" "Cartridge.ModelNo" "710-111 - GN-010" "Cartridge.Name" "I Want My Mommy (1983) (ZiMAG)" "Cartridge.Note" "AKA Open Sesame" "Display.Phosphor" "YES" "" "Cartridge.MD5" "575c0fb61e66a31d982c95c9dea6865c" "Cartridge.Name" "Blackjack (Unknown) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXIS" "Display.YStart" "56" "" "Cartridge.MD5" "1e0ef01e330e5b91387f75f700ccaf8f" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "686.561 2 - 781627" "Cartridge.Name" "Mein Weg (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Challenge" "" "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" "a310494ad5ba2b5b221a30d7180a0336" "Cartridge.Name" "Demo Image Series #6 - Mario (19-02-2003) (AD)" "" "Cartridge.MD5" "85227160f37aaa29f5e3a6c7a3219f54" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-004" "Cartridge.Name" "Fishing Derby (1980) (Activision) (4K)" "" "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" "438968a26b7cfe14a499f5bbbbf844db" "Cartridge.Name" "Raft Rider (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "f066bea7ab0a37b83c83c924a87c5b67" "Cartridge.Name" "Air Raiders (1982) (Unknown)" "" "Cartridge.MD5" "8101efafcf0af32fedda4579c941e6f4" "Cartridge.Name" "Okie Dokie (4K) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "52bae1726d2d7a531c9ca81e25377fc3" "Cartridge.Name" "Space Instigators (V1.8 Fixed) (20-10-2002) (CT)" "" "Cartridge.MD5" "c16fbfdbfdf5590cc8179e4b0f5f5aeb" "Cartridge.Name" "Wall Break (Unknown)" "Display.YStart" "30" "" "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" "" "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" "Display.YStart" "24" "" "Cartridge.MD5" "c73ae5ba5a0a3f3ac77f0a9e14770e73" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4105" "Cartridge.Name" "Official Frogger, The (1983) (Arcadia)" "Display.YStart" "32" "" "Cartridge.MD5" "31512cdfadfd82bfb6f196e3b0fd83cd" "Cartridge.Manufacturer" "Tigervision" "Cartridge.ModelNo" "7-004" "Cartridge.Name" "River Patrol (1984) (Tigervision)" "" "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.YStart" "30" "Display.Height" "218" "" "Cartridge.MD5" "ab60ea7b707c58d356cad858eb18db43" "Cartridge.Name" "Tazer (John K. Harvey)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "a58b11148c18d85e4c2aef4ff46ade67" "Cartridge.Name" "Video Chess (Unknown) (PAL)" "" "Cartridge.MD5" "f9da42f91a1c5cfa344d2ff440c6f8d4" "Cartridge.Manufacturer" "ZUT" "Cartridge.Name" "Pac Invaders (ZUT)" "" "Cartridge.MD5" "ff5a9e340d96df6f5a5b6eb038e923bd" "Cartridge.Name" "Space Shuttle (1983) (Activision) [t1]" "" "Cartridge.MD5" "e7864caaf9ec49ed67b1904ce8602690" "Cartridge.Name" "Donkey Kong 2K3 Pic (PD)" "" "Cartridge.MD5" "4f82d8d78099dd71e8e169646e799d05" "Cartridge.Name" "Miniature Golf (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "f5a2f6efa33a3e5541bc680e9dc31d5b" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-022" "Cartridge.Name" "Motocross (Suntek) (PAL)" "" "Cartridge.MD5" "d483f65468d9a265661917bae1a54f3e" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide Pre-release 3 (Joe Grand)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "81341f00b61ab37d19d1529f483d496d" "Cartridge.Name" "Fu Kung! (V0.04) (10-01-2003) (AD)" "" "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" "43f8459d39fb4eddf9186d62722ff795" "Cartridge.Name" "Skeleton+ (17-04-2003) (Eric Ball) (PAL)" "Cartridge.Sound" "STEREO" "" "Cartridge.MD5" "f1929bb9b5db22d98dd992aa3fe72920" "Cartridge.Name" "Cube Conquest (Improved Interlace) (Billy Eno) (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d763e3a9cdcdd56c715ec826106fab6a" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-001" "Cartridge.Name" "Dragster (1980) (Activision) (16K)" "Display.YStart" "27" "" "Cartridge.MD5" "25bb080457351be724aac8a02021aa92" "Cartridge.Manufacturer" "CBS Electronics" "Cartridge.ModelNo" "4L1784, 4L1786, 4L1787, 4L2277" "Cartridge.Name" "Zaxxon (1982) (CBS Electronics) (PAL)" "" "Cartridge.MD5" "f69bb58b815a6bdca548fa4d5e0d5a75" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Bowling (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "749fec9918160921576f850b2375b516" "Cartridge.Manufacturer" "Spectravision, Spectravideo" "Cartridge.ModelNo" "SA-205" "Cartridge.Name" "China Syndrome (1982) (Spectravision)" "Display.YStart" "29" "Display.Phosphor" "YES" "" "Cartridge.MD5" "72fd08deed1d6195942e0c6f392e9848" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "0701-406" "Cartridge.Name" "2 Pak Special - Wall Defender, Planet Patrol (1990) (HES) (PAL)" "" "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" "" "Cartridge.MD5" "484b0076816a104875e00467d431c2d2" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26150" "Cartridge.Name" "Q-bert (1987) (Atari)" "Display.YStart" "40" "" "Cartridge.MD5" "1e587ca91518a47753a28217cd4fd586" "Cartridge.Manufacturer" "Telesys, Jim Rupp, Jack Woodman" "Cartridge.ModelNo" "1001" "Cartridge.Name" "Coco Nuts (1982) (Telesys)" "" "Cartridge.MD5" "7b7b4ac05232490c28f9b680c72998f9" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Freeway (Zellers)" "" "Cartridge.MD5" "e5f84930aa468db33c0d0f7b26dd8293" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-826" "Cartridge.Name" "Grand Prix (1983) (CCE) [a]" "" "Cartridge.MD5" "61dbe94f110f30ca4ec524ae5ce2d026" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-820" "Cartridge.Name" "Space Invaders (1983) (CCE)" "" "Cartridge.MD5" "2f66ebf037321ed0442ac4b89ce22633" "Cartridge.Manufacturer" "Baroque Gaming (Brian Eno)" "Cartridge.Name" "Warring Worms (Beta 2) (2002) (Baroque Gaming)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "cd568d6acb2f14477ebf7e59fb382292" "Cartridge.Manufacturer" "Videospielkassette - Ariola" "Cartridge.ModelNo" "PGP235" "Cartridge.Name" "Fussball (Ariola) (PAL)" "Cartridge.Note" "AKA International Soccer" "" "Cartridge.MD5" "bdf1996e2dd64baf8eff5511811ca6ca" "Cartridge.Manufacturer" "Tron" "Cartridge.Name" "H.E.R.O. (Tron)" "" "Cartridge.MD5" "81414174f1816d5c1e583af427ac89fc" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Treasure Below (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Console.RightDifficulty" "A" "Display.YStart" "20" "Display.Height" "230" "" "Cartridge.MD5" "521f4dd1eb84a09b2b19959a41839aad" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG206" "Cartridge.Name" "Bobby Is Going Home (1983) (BitCorp)" "Cartridge.Note" "AKA Bobby geht Heim" "Display.YStart" "31" "" "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" "5894c9c0c1e7e29f3ab86c6d3f673361" "Cartridge.Manufacturer" "Activision, Steve 'Jessica' Kitchen" "Cartridge.ModelNo" "AZ-033, AZ-033-04" "Cartridge.Name" "Space Shuttle (1983) (Activision)" "" "Cartridge.MD5" "585f73010e205ae5b04ee5c1a67e632d" "Cartridge.Name" "Daredevil (V3) (Stunt_Cycle_Rules!) (PD)" "" "Cartridge.MD5" "dca90ea1084a2fdbe300d7178ca1a138" "Cartridge.Manufacturer" "Imagic, Dennis Koble" "Cartridge.ModelNo" "IA3000P" "Cartridge.Name" "Trick Shot (1982) (Imagic) (PAL) [a]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e62e60a3e6cb5563f72982fcd83de25a" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "World End (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "Display.Height" "240" "" "Cartridge.MD5" "683dc64ef7316c13ba04ee4398e2b93a" "Cartridge.Manufacturer" "Ed Federmeyer" "Cartridge.Name" "Edtris (1995) (Ed Federmeyer)" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "2bee7f226d506c217163bad4ab1768c0" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Beck-Tech" "Cartridge.ModelNo" "6210, 06002, 06004, 99002" "Cartridge.Name" "Ghost Manor (1983) (Xonox)" "Display.YStart" "30" "" "Cartridge.MD5" "b7a7e34e304e4b7bc565ec01ba33ea27" "Cartridge.Manufacturer" "Parker Brothers" "Cartridge.ModelNo" "PB5820" "Cartridge.Name" "Mr. Do!'s Castle (1984) (Parker Bros)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "fc24a94d4371c69bc58f5245ada43c44" "Cartridge.Manufacturer" "Atari - Axlon, Steve DeFrisco" "Cartridge.ModelNo" "CX26170" "Cartridge.Name" "Secret Quest (1989) (Atari)" "" "Cartridge.MD5" "792b1d93eb1d8045260c840b0688ec8f" "Cartridge.Manufacturer" "Kroko" "Cartridge.Name" "3E Bankswitch Test (TIA @ $00)" "" "Cartridge.MD5" "585600522b1f22f617652c962e358a5d" "Cartridge.Name" "Multi-Sprite Game V2.2 (Piero Cavina) (PD)" "" "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" "ede7e8bf865b0afb4744f86d13624f9a" "Cartridge.Name" "Demo Image Series #2 - Clown (19-02-2003) (AD)" "" "Cartridge.MD5" "7ed7130a6e4020161836414332b11983" "Cartridge.Name" "Fu Kung! (V0.05 Cuttle Card Compatible) (13-01-2003) (AD)" "" "Cartridge.MD5" "e150f0d14f013a104b032305c0ce23ef" "Cartridge.Manufacturer" "Spectravision, Spectravideo" "Cartridge.ModelNo" "SA-205" "Cartridge.Name" "China Syndrome (1982) (Spectravision) (PAL)" "Display.Phosphor" "YES" "" "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" "" "Cartridge.MD5" "62992392ea651a16aa724a92e4596ed6" "Cartridge.Manufacturer" "Eric Mooney" "Cartridge.Name" "Invaders by Erik Mooney (Beta) (PD)" "Cartridge.Rarity" "New Release" "" "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" "f0536303f49006806bac3aec15738336" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (4 of 4) (1982) (Arcadia)" "" "Cartridge.MD5" "dac38b4dd3da73bb7b2e9d70c61d2b7c" "Cartridge.Name" "Hangman Monkey Biglist3 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "13a37cf8170a3a34ce311b89bde82032" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker" "Cartridge.ModelNo" "CX2684, CX2684P" "Cartridge.Name" "Galaxian (1983) (Atari) (PAL)" "" "Cartridge.MD5" "c3ef5c4653212088eda54dc91d787870" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-002, CAG-002, AG-002-04" "Cartridge.Name" "Boxing (1980) (Activision)" "" "Cartridge.MD5" "346555779a2d51b48833463b5433472f" "Cartridge.Name" "Thrust (V0.1) (2000) (TJ)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "17512d0c38f448712f49f36f9d185c4e" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (Release Candidate #1) (Retroactive)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d5f965c159e26a1fb49a22a47fbd1dd0" "Cartridge.Manufacturer" "Supergame" "Cartridge.Name" "River Raid II (Supergame)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "e923001015bedd7901569f035d9c592c" "Cartridge.Name" "Adventure II (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "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" "211774f4c5739042618be8ff67351177" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker" "Cartridge.ModelNo" "CX2684" "Cartridge.Name" "Galaxian (1983) (Atari)" "" "Cartridge.MD5" "2903896d88a341511586d69fcfc20f7d" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AX-014, AX-014-04" "Cartridge.Name" "Grand Prix (1982) (Activision)" "" "Cartridge.MD5" "659a20019de4a23c748ec2292ea5f221" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.05) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9853089672116117258097dbbdb939b7" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - Cowboy Hair (2001) (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "551ef75593ec18d078e8f5cc0229e1c4" "Cartridge.Name" "Star Fire - New Paulstar WIP (MP)" "" "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" "40d8ed6a5106245aa79f05642a961485" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Beck-Tech" "Cartridge.ModelNo" "6210, 06002, 06004, 99002" "Cartridge.Name" "Ghost Manor (1983) (Xonox) (PAL)" "Display.YStart" "30" "" "Cartridge.MD5" "d632b74fea533d593af82cf16e7c5e4a" "Cartridge.Name" "Fu Kung! (V0.13) (01-02-2003) (AD)" "" "Cartridge.MD5" "1bef389e3dd2d4ca4f2f60d42c932509" "Cartridge.Manufacturer" "Dimax - Sinmax" "Cartridge.ModelNo" "SM8001" "Cartridge.Name" "Space Robot (1983) (Dimax - Sinmax) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9e192601829f5f5c2d3b51f8ae25dbe5" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "201" "Cartridge.Name" "Cathouse Blues (1982) (PlayAround)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "53b66f11f67c3b53b2995e0e02017bd7" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1005" "Cartridge.Name" "Super Tennis (1983) (CCE)" "Cartridge.Note" "AKA RealSports Tennis" "" "Cartridge.MD5" "a189f280521f4e5224d345efb4e75506" "Cartridge.Manufacturer" "Atari - Thomas Jentzsch" "Cartridge.Name" "Obelix (1983) (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "373b8a081acd98a895db0cb02df35673" "Cartridge.Name" "Demo Image Series #5 - Boofly (19-02-2003) (AD)" "" "Cartridge.MD5" "d0af33865512e9b6900714c26db5fa23" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Armor Ambush (1989) (Telegames) (PAL)" "" "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" "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" "8ac18076d01a6b63acf6e2cab4968940" "Cartridge.Manufacturer" "Atari, Dan Hitchens" "Cartridge.ModelNo" "CX2685" "Cartridge.Name" "Gravitar (1983) (Atari)" "" "Cartridge.MD5" "7096a198531d3f16a99d518ac0d7519a" "Cartridge.Manufacturer" "Telesys, Jim Rupp" "Cartridge.ModelNo" "1004" "Cartridge.Name" "Ram It (1982) (Telesys)" "" "Cartridge.MD5" "78b84cfb1c57b0488d674d2374e656e6" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (1 of 3) (1982) (Arcadia)" "" "Cartridge.MD5" "7af40c1485ce9f29b1a7b069a2eb04a7" "Cartridge.Manufacturer" "Amiga" "Cartridge.ModelNo" "3120" "Cartridge.Name" "Mogul Maniac (1983) (Amiga)" "Cartridge.Note" "Uses the Amiga Joyboard" "" "Cartridge.MD5" "ebcb084a91d41865b2c1915779001ca7" "Cartridge.Manufacturer" "JVP" "Cartridge.Name" "Bob Is Going Home (JVP)" "Cartridge.Note" "AKA Bobby Is Going Home" "Display.YStart" "31" "" "Cartridge.MD5" "a34560841e0878c7b14cc65f79f6967d" "Cartridge.Manufacturer" "Multivision, Michael Case" "Cartridge.Name" "Harem (1982) (Multivision)" "Display.YStart" "29" "" "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" "4066d7d88ec4a2c656127a67fa52dcf1" "Cartridge.Name" "Overhead Adventure Demo 2 (PD)" "Display.YStart" "64" "" "Cartridge.MD5" "dff33523ccd2fdc8912e84cab8e0d982" "Cartridge.Name" "Fu Kung! (V0.03) (10-01-2003) (AD)" "" "Cartridge.MD5" "cc03c68b8348b62331964d7a3dbec381" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Marauder (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "9f9ee0f60c119c831e80694b6678ca1a" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 8 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "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" "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" "e80a4026d29777c3c7993fbfaee8920f" "Cartridge.Name" "Frisco (Unknown)" "" "Cartridge.MD5" "0e0808227ef41f6825c06f25082c2e56" "Cartridge.Name" "Candi (Hack) [a]" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "a779b9fa02c62d00d7c31ed51268f18a" "Cartridge.Manufacturer" "Arcadia Corporation, Brian McGhie" "Cartridge.ModelNo" "AR-4104" "Cartridge.Name" "Rabbit Transit (1983) (Arcadia) [a]" "" "Cartridge.MD5" "6b683be69f92958abe0e2a9945157ad5" "Cartridge.Manufacturer" "U.S. Games Corporation, Paul Allen Newell, Steve Sidley, Tom Sloper" "Cartridge.ModelNo" "VC2007" "Cartridge.Name" "Entombed (1982) (U.S. Games)" "Cartridge.Note" "Released as Name That Game for a contest (winning name was Entombed)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e5d5085123a98c1e61818caa2971e999" "Cartridge.Name" "Euchre (PAL) (Erik Eid) (PD)" "" "Cartridge.MD5" "4e2c884d04b57b43f23a5a2f4e9d9750" "Cartridge.Name" "Baby Center Animation (PD)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4f0071946e80ca68edfdccbac86dcce0" "Cartridge.Name" "Virtual Pet Demo 1 (CRACKERS) (PD)" "" "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" "2783006ee6519f15cbc96adae031c9a9" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Night Stalker (1989) (Telegames) (PAL) [a]" "Cartridge.Note" "AKA Dark Cavern" "" "Cartridge.MD5" "b15026b43c6758609667468434766dd8" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (0.06) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f4c2e50b01dff99bddbe037b3489511c" "Cartridge.Name" "Hypnotic (V0.04) (2001) (Inkling) (PD)" "" "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" "081e2c114c9c20b61acf25fc95c71bf4" "Cartridge.Manufacturer" "Parker Brothers, Ed English, David Lamkins" "Cartridge.ModelNo" "PB5300" "Cartridge.Name" "Frogger (1982) (Parker Bros)" "" "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" "06b0194ce992584c365278e0d7323279" "Cartridge.Manufacturer" "Activision" "Cartridge.Name" "Unknown Activision Game #2 (Prototype) (PAL)" "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" "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" "7197b6cbde6ecd10376155e6b848e80d" "Cartridge.Manufacturer" "Piero Cavina" "Cartridge.Name" "Multi-Sprite Game V2.1 (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "a23ffc86804240ce77134a1c91926685" "Cartridge.Name" "Star Fire - Paulstar WIP (MP)" "" "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" "3f58f972276d1e4e0e09582521ed7a5b" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "6082 A145" "Cartridge.Name" "Kung Fu Superkicks (1989) (Telegames)" "Cartridge.Note" "AKA Chuck Norris Superkicks" "" "Cartridge.MD5" "292f2446a0325b7b423e88a2ebfeb5a0" "Cartridge.Name" "Cube Conquest (Non Interlaced) (Billy Eno) (PD)" "Display.Phosphor" "YES" "" "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" "8f613ea7c32a587d6741790e32872ddd" "Cartridge.Name" "Troll Demo (PD)" "" "Cartridge.MD5" "50ef88f9a5e0e1e6b86e175362a27fdb" "Cartridge.Name" "Multi-Sprite Game V2.4 (Piero Cavina) (PD)" "" "Cartridge.MD5" "15c11ab6e4502b2010b18366133fc322" "Cartridge.Manufacturer" "Atari - Axlon, Tod Frye" "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" "54da3b0b3f43f5b37911c135b9432b49" "Cartridge.Name" "Halloween III Revision (Hack)" "Cartridge.Note" "Hack of Kaboom!" "Cartridge.Rarity" "Hack" "Controller.Left" "PADDLES" "" "Cartridge.MD5" "69df0411d4d176e558017f961f5c5849" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-831" "Cartridge.Name" "Cosmic Ark (1983) (CCE) [a]" "" "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" "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" "Display.YStart" "22" "Display.Height" "222" "Display.Phosphor" "YES" "" "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" "8749a0d088df25218c149dc325abc7ca" "Cartridge.Manufacturer" "Commavid, Ben Burch" "Cartridge.ModelNo" "CM-010" "Cartridge.Name" "Rush Hour (1983) (Commavid) (Prototype) [a5]" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "40d7ccd460c9b1198238af6ceea1737d" "Cartridge.Name" "Star Fire - Enemy Mine (2002) (MP)" "" "Cartridge.MD5" "47711c44723da5d67047990157dcb5dd" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Ice Hockey (CCE)" "" "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" "a2424c1a0c783d7585d701b1c71b5fdc" "Cartridge.Name" "Video Pinball (Unknown) (PAL)" "" "Cartridge.MD5" "01abcc1d2d3cba87a3aa0eb97a9d7b9c" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Topy (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "Display.YStart" "30" "" "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" "" "Cartridge.MD5" "3f540a30fdee0b20aed7288e4a5ea528" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2670" "Cartridge.Name" "Atari Video Cube (1982) (Atari)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "52e9db3fe8b5d336843acac234aaea79" "Cartridge.Name" "Fu Kung! (V0.11) (28-01-2003) (AD)" "" "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" "83fafd7bd12e3335166c6314b3bde528" "Cartridge.Manufacturer" "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite" "Cartridge.ModelNo" "80561-00251" "Cartridge.Name" "Winter Games (1987) (Epyx)" "" "Cartridge.MD5" "81a010abdba1a640f7adf7f84e13d307" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "7062 A305" "Cartridge.Name" "Universal Chaos (1989) (Telegames)" "Cartridge.Note" "AKA Targ" "Display.Phosphor" "YES" "" "Cartridge.MD5" "203b1efc6101d4b9d83bb6cc1c71f67f" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "685.996 1" "Cartridge.Name" "Teller-Jonglieren! (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Dancing Plate" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0cfdd2f3b243cac21f38a0f09f54bead" "Cartridge.Name" "Overhead Adventure Demo 4 (PD)" "" "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" "481f9a742052801cc5f3defb41cb638e" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 4 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "36f9a953ebdd9a8be97ccf27a2041903" "Cartridge.Name" "Chinese Character Demo (PD)" "" "Cartridge.MD5" "f71694bd8e89d5a28daa73bf856635df" "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" "f8bfd99163d2c4ec688357786e6fba28" "Cartridge.Name" "Eckhard Stolberg's Scrolling Text Demo 2 (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "47abfb993ff14f502f88cf988092e055" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Inca Gold (Zellers)" "Cartridge.Note" "AKA Spider Kong" "Display.YStart" "29" "" "Cartridge.MD5" "f0b7db930ca0e548c41a97160b9f6275" "Cartridge.Manufacturer" "Atari, Larry Wagner, Bob Whitehead - Sears" "Cartridge.ModelNo" "CX2645 - 49-75181" "Cartridge.Name" "Video Chess (1979) (Atari)" "" "Cartridge.MD5" "0f341d1f4e144e3163d9a5fc5a662b79" "Cartridge.Name" "RUN Platform Demo (PD)" "Display.YStart" "0" "Display.Phosphor" "YES" "" "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)" "" "Cartridge.MD5" "89eaba47a59cbfd26e74aad32f553cd7" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Ed Salvo, Bryson Park" "Cartridge.ModelNo" "AP-2001" "Cartridge.Name" "Spacechase (1981) (Apollo) (PAL)" "" "Cartridge.MD5" "fac28963307b6e85082ccd77c88325e7" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Berzerk (CCE)" "" "Cartridge.MD5" "85e564dae5687e431955056fbda10978" "Cartridge.Manufacturer" "Milton Bradley Company" "Cartridge.ModelNo" "4362" "Cartridge.Name" "Survival Run (1983) (Milton Bradley)" "Cartridge.Note" "AKA Cosmic Commander" "Display.YStart" "29" "Display.Height" "225" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0eebfb60d437796d536039701ec43845" "Cartridge.Manufacturer" "Fabrizio Zavagli" "Cartridge.Name" "Cakewalk (Fabrizio Zavagli)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "5360693f1eb90856176bd1c0a7b17432" "Cartridge.Name" "Oystron (V2.85) (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "df2745d585238780101df812d00b49f4" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG202" "Cartridge.Name" "Space Tunnel (1982) (BitCorp)" "Display.Height" "215" "" "Cartridge.MD5" "fa529ec88eca679f6d5fd0ccb2120e46" "Cartridge.Name" "20 Sprites at Once Demo 1 (PD)" "" "Cartridge.MD5" "c5d2834bf98e90245e545573eb7e6bbc" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Snoopy and the Red Baron (CCE)" "" "Cartridge.MD5" "f0a6e99f5875891246c3dbecbf2d2cea" "Cartridge.Manufacturer" "Atari, James Andreasen - Sears" "Cartridge.ModelNo" "CX2654 - 49-75141" "Cartridge.Name" "Haunted House (1982) (Atari)" "" "Cartridge.MD5" "027a59a575b78860aed780b2ae7d001d" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Pressure Cooker (CCE)" "" "Cartridge.MD5" "db76f7a0819659d9e585f2cdde9175c7" "Cartridge.Manufacturer" "Xonox" "Cartridge.ModelNo" "99005, 6220, 6250" "Cartridge.Name" "Robin Hood (1983) (Xonox) (PAL) [a]" "Display.YStart" "30" "" "Cartridge.MD5" "acaa27d214039d89d7031609aafa55c3" "Cartridge.Name" "Sprite Demo 6 (PD)" "" "Cartridge.MD5" "890c13590e0d8d5d6149737d930e4d95" "Cartridge.Manufacturer" "Atari, David Crane - Sears" "Cartridge.ModelNo" "CX2605 - 6-99822, 49-75109" "Cartridge.Name" "Outlaw (1978) (Atari)" "" "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" "205070b6a0d454961dd9196a8e81d877" "Cartridge.Name" "Hangman Monkey Biglist2 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "41f252a66c6301f1e8ab3612c19bc5d4" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein" "Cartridge.ModelNo" "CX2681" "Cartridge.Name" "Battlezone (1983) (Atari)" "Cartridge.Rarity" "Uncommon" "" "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" "Display.YStart" "24" "" "Cartridge.MD5" "36306070f0c90a72461551a7a4f3a209" "Cartridge.Manufacturer" "U.S. Games Corporation, Roger Booth, Sylvia Day, Ron Dubren, Todd Marshall, Wes Trager, Henry Will IV" "Cartridge.ModelNo" "VC1007" "Cartridge.Name" "Name This Game (1982) (U.S. Games)" "Cartridge.Note" "AKA Guardians of Treasure, Octopussy" "" "Cartridge.MD5" "ae6cb335470788b94beb5787976e8818" "Cartridge.Name" "Mortal Kurling (02-01-2003) (CT)" "" "Cartridge.MD5" "6b7a56b6ac2ca4bf9254474bf6ed7d80" "Cartridge.Name" "Horizonal Color Bars Demo (PD)" "" "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" "cff578e5c60de8caecbee7f2c9bbb57b" "Cartridge.Manufacturer" "George Veeder" "Cartridge.Name" "Suicide Adventure (George Veeder) (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "de07e9cb43ad8d06a35f6506e22c62e9" "Cartridge.Name" "Oh No! (Version 4) (22-01-2003) (AD)" "" "Cartridge.MD5" "19abaf2144b6a7b281c4112cff154904" "Cartridge.Manufacturer" "Atari, Brad Stewart" "Cartridge.ModelNo" "CX2649, CX2649P" "Cartridge.Name" "Asteroids (1981) (Atari) (PAL) [a2]" "Display.Phosphor" "YES" "" "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" "d3456b4cf1bd1a7b8fb907af1a80ee15" "Cartridge.Manufacturer" "Avalon Hill, Duncan Scott" "Cartridge.ModelNo" "5003002" "Cartridge.Name" "Wall Ball (1983) (Avalon Hill)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0d07d2c1be1a5eaaea235a533bcda781" "Cartridge.Name" "Scrolling Playfield 1 (Junkosoft) (PD)" "" "Cartridge.MD5" "12d7e0d6b187889f8d150bf7034d1db2" "Cartridge.Name" "Poker Squares (V0.0e) (2001) (B. Watson)" "" "Cartridge.MD5" "fb0e84cee4c108d24253bcb7e382cffd" "Cartridge.Name" "Interleaved ChronoColour Demo (SECAM) (05-03-2003) (AD)" "" "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" "5fb71cc60e293fe10a5023f11c734e55" "Cartridge.Name" "This Planet Sucks (Fix) (27-12-2002) (Greg Troutman)" "Display.YStart" "38" "" "Cartridge.MD5" "e6d5948f451a24994dfaaca51dfdb4e1" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Football (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "3b80b8f52a0939e16b5059f93a3fc19a" "Cartridge.Manufacturer" "V007" "Cartridge.Name" "Virtual Pet (V007) (after Demo 2) (CRACKERS) (PD)" "" "Cartridge.MD5" "bb579404924c40ca378b4aff6ccf302d" "Cartridge.Name" "Lightbulb Lightens, The (PD) (Non Functional)" "" "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" "fc2104dd2dadf9a6176c1c1c8f87ced9" "Cartridge.Manufacturer" "Coleco, Harley H. Puthuff Jr." "Cartridge.ModelNo" "2663" "Cartridge.Name" "Time Pilot (1983) (Coleco)" "" "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" "ce243747bf34a2de366f846b3f4ca772" "Cartridge.Manufacturer" "Home Vision - Gem International Corp." "Cartridge.Name" "Jacky Jump (1983) (Home Vision) (PAL)" "Cartridge.Note" "AKA Bobby Is Going Home" "Display.YStart" "39" "Display.Height" "256" "" "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" "6d8a04ee15951480cb7c466e5951eee0" "Cartridge.Manufacturer" "Zirok" "Cartridge.Name" "Kanguru (1983) (Zirok)" "Cartridge.Note" "AKA Kangaroo" "" "Cartridge.MD5" "81f4f0285f651399a12ff2e2f35bab77" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (1982) (Arcadia)" "" "Cartridge.MD5" "8c2fa33048f055f38358d51eefe417db" "Cartridge.Manufacturer" "Home Vision - Gem International Corp." "Cartridge.ModelNo" "VCS83137" "Cartridge.Name" "Teddy Apple (1983) (Home Vision) (PAL)" "Cartridge.Note" "AKA Open Sesame" "Display.YStart" "42" "Display.Phosphor" "YES" "" "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" "3eb21313ea5d5764c5ed9160a5a55a83" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AX-012, CAX-012, AX-012-04" "Cartridge.Name" "Ice Hockey (1981) (Activision) (8K)" "" "Cartridge.MD5" "557e893616648c37a27aab5a47acbf10" "Cartridge.Manufacturer" "Atari - Axlon, Tod Frye" "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" "7996b8d07462a19259baa4c811c2b4b4" "Cartridge.Name" "Math Gran Prix (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "e42b937c30c617241ca9e01e4510c3f6" "Cartridge.Name" "Pitfall! (No Walls Hack)" "" "Cartridge.MD5" "25d4be3309b89583c6b39d9f93bf654f" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AX-015, AX-015-04" "Cartridge.Name" "Chopper Command (1982) (Activision) (16K)" "" "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" "faed2ef6b44894f8c83f2b50891c35c6" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Super Baseball (CCE)" "Cartridge.Note" "AKA RealSports Baseball" "Display.YStart" "26" "" "Cartridge.MD5" "5ae73916fa1da8d38ceff674fa25a78a" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Barnstorming (CCE)" "" "Cartridge.MD5" "718ae62c70af4e5fd8e932fee216948a" "Cartridge.Manufacturer" "Data Age" "Cartridge.ModelNo" "112-006" "Cartridge.Name" "Journey Escape (1982) (Data Age)" "Display.Height" "230" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7d9c96b215d1941e87b6fb412eb9204f" "Cartridge.Name" "Othello (Unknown) (PAL) (4K)" "" "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" "" "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" "0f8043715d66a4bbed394ef801d99862" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "684.733 9" "Cartridge.Name" "Robin Hood (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Save Our Ship" "" "Cartridge.MD5" "3947eb7305b0c904256cdbc5c5956c0f" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Lilly Adventure (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "Display.YStart" "30" "Display.Height" "230" "" "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" "b392964e8b1c9c2bed12246f228011b2" "Cartridge.Name" "Name This Game (Unknown) (PAL)" "" "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" "19d6956ff17a959c48fcd8f4706a848d" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "202" "Cartridge.Name" "Burning Desire (1982) (PlayAround)" "Display.YStart" "25" "Display.Phosphor" "YES" "" "Cartridge.MD5" "55ef6ab2321ca0c3d369e63d59c059c8" "Cartridge.Name" "Pitfall! (Unknown) (PAL)" "" "Cartridge.MD5" "ca4f8c5b4d6fb9d608bb96bc7ebd26c7" "Cartridge.Manufacturer" "M Network, Hal Finney, Glenn Hightower, Peter Kaminski - INTV" "Cartridge.ModelNo" "MT4317" "Cartridge.Name" "Adventures of TRON (1982) (M Network)" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "07c76f2d88552d20ad2c0ed7aef406c6" "Cartridge.Manufacturer" "Cody Pittman" "Cartridge.Name" "Blob (Cody Pittman) (Hack)" "Cartridge.Note" "Hack of Halloween" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "d912312349d90e9d41a9db0d5cd3db70" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-818" "Cartridge.Name" "Star Voyager (1983) (CCE)" "" "Cartridge.MD5" "11330eaa5dd2629052fac37cfe1a0b7d" "Cartridge.Manufacturer" "128-in-1 Junior Console" "Cartridge.Name" "Human Cannonball (128-in-1 Junior Console) (PAL)" "" "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" "" "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" "80e5400470ac788143e6db9bc8dd88cf" "Cartridge.Manufacturer" "Coleco, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (06-XX-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "4afe528a082f0d008e7319ebd481248d" "Cartridge.Name" "Multi-Color Demo 1 (Bob Colbert) (PD)" "" "Cartridge.MD5" "a60598ad7ee9c5ccad42d5b0df1570a1" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Surround (32 in 1) (1988) (Atari) (PAL)" "" "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" "f34dd3b8156aaf113cb621b2e51d90b8" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide Pre-release 5 (Joe Grand)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "a4b9423877a0b86ca35b52ca3c994ac5" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-805" "Cartridge.Name" "Sea Monster (1983) (CCE)" "Cartridge.Note" "O Monstro Marinho" "Display.YStart" "30" "Display.Height" "220" "" "Cartridge.MD5" "0f6676b05621f80c670966e2995b227a" "Cartridge.Name" "Globe Trotter Demo 1 (24-03-2003) (Weston)" "" "Cartridge.MD5" "7dc03a1f56d0e6a8aae3e3e50d654a08" "Cartridge.Name" "Hozer Video Demo (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "cff1e9170bdbc29859b815203edf18fa" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Push (V0.01) (1998) (AD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e38dc1f81a02e325562cd285123f579b" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein" "Cartridge.ModelNo" "CX2681, CX2681P" "Cartridge.Name" "Battlezone (1983) (Atari) (PAL) [a1]" "" "Cartridge.MD5" "34e37eaffc0d34e05e40ed883f848b40" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.15) (Retroactive) (Stella)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "eb92193f06b645df0b2a15d077ce435f" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Hales, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4102" "Cartridge.Name" "Suicide Mission (1982) (Arcadia) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9245a84e9851565d565cb6c9fac5802b" "Cartridge.Manufacturer" "Bomb - Onbase" "Cartridge.ModelNo" "CA282" "Cartridge.Name" "Great Escape (1983) (Bomb)" "Cartridge.Note" "AKA Asteroid Fire" "Display.YStart" "28" "" "Cartridge.MD5" "96eccc2277043508a6c481ea432d7dd9" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Missile Command (CX-80 Trackball) (2002) (TJ) (PAL)" "Cartridge.Note" "Uses CX-80 Trackball Controller" "Cartridge.Rarity" "Homebrew" "Controller.Left" "TRACKBALL80" "Display.Phosphor" "YES" "" "Cartridge.MD5" "54a1c1255ed45eb8f71414dadb1cf669" "Cartridge.Manufacturer" "Spectravideo" "Cartridge.ModelNo" "SA-212" "Cartridge.Name" "Mangia' (1983) (Spectravideo)" "Display.YStart" "28" "" "Cartridge.MD5" "3b2c32fcd331664d037952bcaa62df94" "Cartridge.Manufacturer" "Xonox" "Cartridge.ModelNo" "6230, 6250" "Cartridge.Name" "Super Kung-Fu (1983) (Xonox) (PAL) [a]" "" "Cartridge.MD5" "c529e63013698064149b9e0468afd941" "Cartridge.Name" "S.I.PLIX 2 (Hack)" "Cartridge.Note" "Hack of Kaboom!" "Cartridge.Rarity" "Hack" "Controller.Left" "PADDLES" "" "Cartridge.MD5" "dd8a2124d4eda200df715c698a6ea887" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (3 of 3) (1982) (Arcadia)" "" "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" "30" "Display.Height" "220" "" "Cartridge.MD5" "742de93b8d849220f266b627fbabba82" "Cartridge.Name" "SCSIcide (25-02-2001) (Chris Wilkson) (PD)" "" "Cartridge.MD5" "335a7c5cfa6fee0f35f5824d1fa09aed" "Cartridge.Manufacturer" "Sega, Steve Beck, Phat Ho - Beck-Tech - Teldec" "Cartridge.ModelNo" "006-01 - 3.60105 VG" "Cartridge.Name" "Congo Bongo (1983) (Sega) (PAL)" "" "Cartridge.MD5" "a539b9fd1ba57e46442b3e9351e6383b" "Cartridge.Name" "River Raid (208 in 1) (Unknown) (PAL) (Hack) [a]" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "b9d1e3be30b131324482345959aed5e5" "Cartridge.Manufacturer" "Activision, Rex Bradford" "Cartridge.Name" "Kabobber (07-25-1983) (Activision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "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" "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" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d8df256c0d89e494a9fb3e9abb8e44ac" "Cartridge.Manufacturer" "Imagic, Michael Greene" "Cartridge.ModelNo" "IA3312P" "Cartridge.Name" "No Escape! (1982) (Imagic) (PAL) [a]" "" "Cartridge.MD5" "bd1bd6f6b928df17a702def0302f46f4" "Cartridge.Name" "Binary To Decimal Routine (2001) (AD)" "" "Cartridge.MD5" "265a85f66544eaf95fda06c3d9e48abf" "Cartridge.Name" "Tunnel Demo (Cycling Colours) (29-03-2003) (AD)" "" "Cartridge.MD5" "4dcc7e7c2ec0738e26c817b9383091af" "Cartridge.Name" "Unknown Title (bin00026 (200110)) (PD)" "" "Cartridge.MD5" "fc668a2251dd79cbd903d4fa0e558f96" "Cartridge.Name" "Thrust (V1.1) (2000) (TJ) [a1]" "" "Cartridge.MD5" "f4b8a47a95b61895e671c3ec86ffd461" "Cartridge.Manufacturer" "Parker Brothers, Wilfredo 'Willy' 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" "072a6ea2181ca0df88ac0dedc67b239d" "Cartridge.Name" "Multiple Missiles Demo (19-12-2002) (CT)" "" "Cartridge.MD5" "d2c4f8a4a98a905a9deef3ba7380ed64" "Cartridge.Manufacturer" "Mythicon, Bill Bryner, Bruce de Graaf" "Cartridge.ModelNo" "MA1001" "Cartridge.Name" "Sorcerer (1983) (Mythicon)" "" "Cartridge.MD5" "8b7ca29a55432f886cee3d452fb00481" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum, Jon Leupp" "Cartridge.ModelNo" "AR-4201" "Cartridge.Name" "Sword of Saros (1983) (Arcadia) (PAL)" "" "Cartridge.MD5" "2179dfd7edee76efafe698c1bc763735" "Cartridge.Name" "Yellow Submarine (Cody Pittman) (PD)" "" "Cartridge.MD5" "7cc77f6745e1f2b20df4a4327d350545" "Cartridge.Manufacturer" "Atari, Richard Maurer" "Cartridge.ModelNo" "CX2632, CX2632P" "Cartridge.Name" "Space Invaders (1980) (Atari) (PAL) [fixed]" "" "Cartridge.MD5" "d100b11be34a1e5b7832b1b53f711497" "Cartridge.Name" "Robotfindskitten2600 (26-04-2003) (Jeremy Penner) [a2]" "" "Cartridge.MD5" "161ded4a85d3c78e44fffd40426f537f" "Cartridge.Name" "JtzBall (Alpha) (TJ)" "" "Cartridge.MD5" "a0675883f9b09a3595ddd66a6f5d3498" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "6057 A227" "Cartridge.Name" "Quest for Quintana Roo (1989) (Telegames)" "" "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" "4a2fe6f0f6317f006fd6d4b34515448b" "Cartridge.Name" "Warring Worms (Midwest Classic Edition) (08-06-2002) (Billy Eno)" "" "Cartridge.MD5" "e4a0b28befaaa2915df1fa01238b1e29" "Cartridge.Name" "Gunfight 2600 - Red River (MP)" "" "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" "Display.YStart" "42" "" "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" "b77468d586957d1b7fb4cccda2684f47" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Boxing (32 in 1) (1988) (Atari) (PAL) (4K)" "" "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" "0b01909ba84512fdaf224d3c3fd0cf8d" "Cartridge.Name" "Revenge of the Apes (Hack)" "Cartridge.Note" "Hack of Planet of the Apes" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "8c8a26ed57870daba8e13162d497bad1" "Cartridge.Manufacturer" "HES" "Cartridge.Name" "2 Pak Special - Dolphin, Oink (1990) (HES) (PAL)" "" "Cartridge.MD5" "bf5e2079586cb307bf5eb2413e2e61af" "Cartridge.Name" "Star Fire - 1LK Intro (13-11-2002) (TJ)" "" "Cartridge.MD5" "1542662f665d2ffaa77b4b897dd2e2af" "Cartridge.Name" "Starfield (V1.0) (2002) (MP)" "" "Cartridge.MD5" "2365e1534d67f94d8670394ab99150ce" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Missile Command (CX-80 Trackball) (2002) (TJ)" "Cartridge.Note" "Uses CX-80 Trackball Controller" "Cartridge.Rarity" "Homebrew" "Controller.Left" "TRACKBALL80" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ac5f78bae0638cf3f2a0c8d07eb4df69" "Cartridge.Name" "Minesweeper (V.99) (Soren Gust) (PD)" "" "Cartridge.MD5" "240bfbac5163af4df5ae713985386f92" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-022" "Cartridge.Name" "Seaquest (1983) (Activision)" "" "Cartridge.MD5" "fb5c8af97bd8ffe88323656f462645a7" "Cartridge.Name" "Interlace Demo (Glenn Saunders)" "Display.Phosphor" "YES" "" "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" "09e1ecf9bd2a3030d5670dba7a65e78d" "Cartridge.Manufacturer" "Atari, James Andreasen" "Cartridge.ModelNo" "CX2654" "Cartridge.Name" "Haunted House (1982) (Atari) (PAL)" "" "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" "92ede72ed8f61d255bc58d2f166dc6b6" "Cartridge.Name" "Star Fire - Shootable (26-09-2002) (MP)" "" "Cartridge.MD5" "26bc2bdf447a17376aea7ef187ff6e44" "Cartridge.Name" "Amanda Invaders (PD)" "" "Cartridge.MD5" "8f98519a91dbbf4864f135a10050d9ed" "Cartridge.Manufacturer" "Silvio Mogno" "Cartridge.Name" "Rainbow Invaders (non-playable demo) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "fd16949913aaab5beaefed73bf2ca67c" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, John Allred" "Cartridge.ModelNo" "CX2688" "Cartridge.Name" "Jungle Hunt (02-03-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "26f4f8b098609164effef7809e0121e1" "Cartridge.Name" "Oystron (V2.7) (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "ce64812eb83c95723b04fb56d816910b" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.04) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "98ea10c47c13f1b3306c7b13db304865" "Cartridge.Name" "Jam Demo 1 (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" "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" "cbced209dd0575a27212d3eee6aee3bc" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Ed Salvo, Byron Parks" "Cartridge.ModelNo" "AP-2003" "Cartridge.Name" "Racquetball (1981) (Apollo)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "98555b95cb38e0e0b22b482b2b60a5b6" "Cartridge.Name" "Spinning Fireball (Unknown) (PAL)" "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" "f8c1c4a41303bd40b0d6c81bfaf8573b" "Cartridge.Manufacturer" "HES" "Cartridge.Name" "2 Pak Special - Dungeon Master, Creature Strike (1992) (HES) (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" "7c4a499d343fca0cef2d59dd16af621a" "Cartridge.Name" "Poker Card Demo (PD)" "" "Cartridge.MD5" "034c1434280b0f2c9f229777d790d1e1" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "5665 A016" "Cartridge.Name" "Baseball (1989) (Telegames) (PAL)" "Cartridge.Note" "AKA Super Challenge Baseball" "" "Cartridge.MD5" "30e012e8d50330c8972f126b8e913bc4" "Cartridge.Name" "Indy 500 (Hack) [a2]" "Cartridge.Note" "Hack of Indy 500" "Cartridge.Rarity" "Hack" "Controller.Left" "DRIVING" "Controller.Right" "DRIVING" "Display.YStart" "28" "" "Cartridge.MD5" "ae465044dfba287d344ba468820995d7" "Cartridge.Name" "Spider Kong (Unknown) (PAL)" "" "Cartridge.MD5" "324cb4a749bcac4f3db9da842b85d2f7" "Cartridge.Manufacturer" "Dennis Debro" "Cartridge.Name" "Climber 5 (01-05-2003) (Dennis Debro)" "Cartridge.Rarity" "Homebrew" "Display.YStart" "28" "" "Cartridge.MD5" "7608abdfd9b26f4a0ecec18b232bea54" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "NFL Football (32 in 1) (1988) (Atari) (PAL)" "Cartridge.Note" "AKA Football" "" "Cartridge.MD5" "a936d80083e99d48752ad15c2b5f7c96" "Cartridge.Name" "Room of Doom (208 in 1) (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "be2870a0120fd28d25284e9ccdcbdc99" "Cartridge.Name" "Tomb Raider 2600 [REV 01] (Montezuma's Revenge Hack)" "" "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" "528400fad9a77fd5ad7fc5fdc2b7d69d" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum, Jon Leupp" "Cartridge.ModelNo" "AR-4201" "Cartridge.Name" "Sword of Saros (1983) (Arcadia)" "" "Cartridge.MD5" "dab844deed4c752632b5e786b0f47999" "Cartridge.Name" "Super Challenge Baseball (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "9ad362179c2eea4ea115c7640b4b003e" "Cartridge.Name" "Barnstorming (Unknown) (PAL)" "Display.Format" "NTSC50" "" "Cartridge.MD5" "e5a6e0bb7d56e2f08b237e15076e5699" "Cartridge.Name" "Color Table Display Helper (PD)" "" "Cartridge.MD5" "fc6052438f339aea373bbc999433388a" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.ModelNo" "CX2653P" "Cartridge.Name" "Slot Machine (1979) (Atari) (PAL)" "" "Cartridge.MD5" "6a03c28d505bab710bf20b954e14d521" "Cartridge.Name" "Pressure Gauge 2 Beta (Hozer Video Games)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "ccb807eb79b0ed0f5fdc460445ef703a" "Cartridge.Name" "Superman (Stunt_Cycle_Rules!) (Hack)" "Cartridge.Note" "Hack of Superman" "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" "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" "" "Cartridge.MD5" "130c5742cd6cbe4877704d733d5b08ca" "Cartridge.Manufacturer" "Home Vision - Gem International Corp." "Cartridge.ModelNo" "VCS83109" "Cartridge.Name" "World End (1983) (Home Vision) (PAL)" "" "Cartridge.MD5" "490e3cc59d82f85fae817cdf767ea7a0" "Cartridge.Name" "Berzerk (Unknown) (PAL) [a]" "" "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" "33ed6dfac4b9ea2f81f778ceddbb4a75" "Cartridge.Manufacturer" "Activision" "Cartridge.Name" "River Raid (1982) (SpkSoft) [t1]" "" "Cartridge.MD5" "55ace3c775f42eb46f08bb1dca9114e7" "Cartridge.Name" "Shadow Keep (04-03-2003) (Andrew Towers)" "" "Cartridge.MD5" "c2778507b83d9540e9be5713758ff945" "Cartridge.Name" "Island Flyer Demo 2 (PD)" "" "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" "6596b3737ae4b976e4aadb68d836c5c7" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Defender (Digivision)" "" "Cartridge.MD5" "cf507910d6e74568a68ac949537bccf9" "Cartridge.Manufacturer" "Sega, Jeff Lorenz" "Cartridge.ModelNo" "003-01" "Cartridge.Name" "Thunderground (1983) (Sega)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f1b2ea568b3e156e3f2849dac83591f6" "Cartridge.Name" "Sprite Demo (1997) (Bob Colbert) (PD)" "" "Cartridge.MD5" "e9034b41741dcee64ab6605aba9de455" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Phanton Tank (Digivision)" "Cartridge.Note" "AKA Phantom Tank" "Display.YStart" "30" "" "Cartridge.MD5" "ca7aaebd861a9ef47967d31c5a6c4555" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Homerun (32 in 1) (1988) (Atari) (PAL)" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "23e4ca038aba11982e1694559f3be10f" "Cartridge.Name" "Big Dig (V3) (20-10-2002) (CT)" "" "Cartridge.MD5" "151c33a71b99e6bcffb34b43c6f0ec23" "Cartridge.Manufacturer" "Parker Brothers, Laura Nikolich" "Cartridge.Name" "Care Bears (1983) (Parker Bros) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "6913c90002636c1487538d4004f7cac2" "Cartridge.Manufacturer" "Atari" "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" "f7d6592dcb773c81c278140ed4d01669" "Cartridge.Manufacturer" "Activision, David Crane, Dan Kitchen" "Cartridge.ModelNo" "EAG-108-04, EAZ-108-04B" "Cartridge.Name" "Ghostbusters (1985) (Activision) (PAL)" "" "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" "Display.YStart" "30" "" "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" "d09935802d6760ae58253685ff649268" "Cartridge.Manufacturer" "Telesys, Don 'Donyo' Ruffcorn" "Cartridge.ModelNo" "1006" "Cartridge.Name" "Demolition Herby (1983) (Telesys)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f45644ff82b533a781a1ee50f2e95f3c" "Cartridge.Name" "Overhead Adventure Demo 6 (PD)" "" "Cartridge.MD5" "c77c35a6fc3c0f12bf9e8bae48cba54b" "Cartridge.Manufacturer" "Xonox - K-Tel Software, John Perkins" "Cartridge.ModelNo" "6230, 7210, 06004, 99004" "Cartridge.Name" "Artillery Duel (1983) (Xonox)" "Cartridge.Rarity" "Extremely Rare" "Display.YStart" "20" "" "Cartridge.MD5" "ad42e3ca3144e2159e26be123471bffc" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Human Cannonball (32 in 1) (1988) (Atari) (PAL)" "" "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" "93b9229fc0ea4fb959d604f83f8f603c" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Amidar DS (Fast Enemies) (2003) (TJ) (Hack)" "Cartridge.Note" "Hack of Amidar" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "5a734779d797ccef25dc8acfa47244c7" "Cartridge.Name" "Oh No! (Version 2) (18-01-2003) (AD)" "" "Cartridge.MD5" "303242c239474f2d7763b843de58c1c3" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Laser Blast (CCE)" "" "Cartridge.MD5" "a867b76098786c4091dba2fcee5084c3" "Cartridge.Name" "Dragrace (Hack)" "Cartridge.Note" "Hack of Dragster" "Cartridge.Rarity" "Hack" "Display.YStart" "27" "" "Cartridge.MD5" "32244e55ce6ec6bfbd763f33384bdc2e" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-027" "Cartridge.Name" "Plaque Attack (1983) (Activision) (16K)" "" "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" "32d1260ea682e1bb10850fa94c04ec5f" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Basketball (32 in 1) (1988) (Atari) (PAL) (4K)" "" "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" "b2d5d200f0af8485413fad957828582a" "Cartridge.Manufacturer" "Atari, Robert C. Polaro" "Cartridge.ModelNo" "CX26155P" "Cartridge.Name" "Sprint Master (1988) (Atari) (PAL)" "" "Cartridge.MD5" "8bd8f65377023bdb7c5fcf46ddda5d31" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-019" "Cartridge.Name" "Sky Jinks (1982) (Activision) (4K)" "" "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.Format" "NTSC" "Display.Phosphor" "YES" "" "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" "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" "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" "ea86176b27ab0da8cce8f0179884bfaa" "Cartridge.Name" "Demo Image Series #10 - It's Art (28-02-2003) (AD)" "" "Cartridge.MD5" "7f07cd2e89dda5a3a90d3ab064bfd1f6" "Cartridge.Manufacturer" "Videospielkassette - Ariola" "Cartridge.ModelNo" "PGP234" "Cartridge.Name" "Boxen (Ariola) (PAL)" "Cartridge.Note" "AKA Boxing" "" "Cartridge.MD5" "1d2a28eb8c95da0d6d6b18294211839f" "Cartridge.Name" "Fishing Derby (Unknown) (PAL) (4K)" "" "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" "d86deb100c6abed1588aa84b2f7b3a98" "Cartridge.Manufacturer" "Atari, Bob Whitehead - Sears" "Cartridge.ModelNo" "CX2625 - 6-99827, 49-75114" "Cartridge.Name" "Football (1979) (Atari) (4K)" "" "Cartridge.MD5" "9e5007131695621d06902ab3c960622a" "Cartridge.Manufacturer" "Sega" "Cartridge.Name" "Tac Scan (1983) (Sega) [h1]" "Controller.Left" "PADDLES" "Display.Height" "215" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9dec0be14d899e1aac4337acef5ab94a" "Cartridge.Manufacturer" "CommaVid, John Bronstein" "Cartridge.ModelNo" "CM-003" "Cartridge.Name" "Cosmic Swarm (1982) (CommaVid) (4K)" "Display.Phosphor" "YES" "" "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" "8388d6fe59c38c0b3a6ab2c58420036a" "Cartridge.Manufacturer" "Atari, Frank Hausman, Steve Woita" "Cartridge.ModelNo" "CX2686" "Cartridge.Name" "Quadrun (12-06-1982) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "5bbab3f3e4b47e3e23f9820765dbb45c" "Cartridge.Name" "Pitfall! (says 1985) [h1]" "" "Cartridge.MD5" "319a142aab6260842ab616382848c204" "Cartridge.Name" "Marble Craze (05-02-2002) (Paul Slocum)" "" "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" "a91d0858a52de3a2e6468437212d93e8" "Cartridge.Name" "Q-bert (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "a7ed7dc5cbc901388afa59030fb11d26" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.ModelNo" "CX2606, CX2606P" "Cartridge.Name" "Slot Racers (1978) (Atari) (PAL)" "" "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" "33cac5e767a534c95d292b04f439dc37" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Tapeworm (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "8190b403d67bf9792fe22fa5d22f3556" "Cartridge.Name" "Sky Diver (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "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" "1e1290ea102e12d7ac52820961457e2b" "Cartridge.Manufacturer" "Parker Brothers, Wilfredo 'Willy' 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)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "07a3af1e18b63765b6807876366f5e8a" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide Pre-release 2 (Joe Grand)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "f2e4fb2d3600c0f76d05864e658cc57b" "Cartridge.Name" "Marble Craze (Kernel) (17-02-2002) (Paul Slocum)" "" "Cartridge.MD5" "bccb4e2cfad5efc93f6d55dc992118ce" "Cartridge.Manufacturer" "Activision, Carol Shaw" "Cartridge.ModelNo" "AX-020, AX-020-04" "Cartridge.Name" "River Raid (1982) (Activision) (8K)" "" "Cartridge.MD5" "66362890eb78d6ea65301592cce65f5b" "Cartridge.Name" "Euchre (13-07-2001) (Eric Eid) (PD)" "" "Cartridge.MD5" "41810dd94bd0de1110bedc5092bef5b0" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Dragon Treasure (Funvision)" "Cartridge.Note" "AKA Dragonfire" "" "Cartridge.MD5" "0e08cd2c5bcf11c6a7e5a009a7715b6a" "Cartridge.Name" "Boing! (PD) [a1]" "Cartridge.Rarity" "New Release" "" "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" "b00088418fc891f3faa3d4ddde6ace94" "Cartridge.Name" "Unknown Title (bin00007 (200102)) (PD)" "" "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" "59f596285d174233c84597dee6f34f1f" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-811" "Cartridge.Name" "River Raid (1983) (CCE)" "" "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" "4e37992a37ea36489283f7eb90913bbc" "Cartridge.Manufacturer" "Kris" "Cartridge.Name" "Hangman Ghost Halloween (Kris) (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "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" "fdd4995a50395db14f518f63c2d63438" "Cartridge.Name" "Oh No! (Version 3) (18-01-2003) (AD)" "" "Cartridge.MD5" "fb531febf8e155328ec0cd39ef77a122" "Cartridge.Name" "Worm War I (208 in 1) (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0aa208060d7c140f20571e3341f5a3f8" "Cartridge.Manufacturer" "U.S. Games Corporation, Jeff Corsiglia, Paul Allen Newell" "Cartridge.ModelNo" "VC1009" "Cartridge.Name" "Towering Inferno (1982) (U.S. Games)" "Cartridge.Note" "Uses the Joystick Controllers (swapped)" "Console.SwapPorts" "YES" "Display.YStart" "30" "Display.Height" "220" "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" "6a9e0c72fab92df70084eccd9061fdbd" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-835" "Cartridge.Name" "Beany Bopper (1983) (CCE)" "" "Cartridge.MD5" "ace319dc4f76548659876741a6690d57" "Cartridge.Manufacturer" "Atari, Steve Wright" "Cartridge.ModelNo" "CX2616" "Cartridge.Name" "Pele's Soccer (1981) (Atari)" "Cartridge.Note" "AKA Championship Soccer" "" "Cartridge.MD5" "b2a6f31636b699aeda900f07152bab6e" "Cartridge.Name" "Space Instigators (Public Release 2) (06-01-2003) (CT)" "" "Cartridge.MD5" "39fe316952134b1277b6a81af8e05776" "Cartridge.Manufacturer" "Robby" "Cartridge.ModelNo" "18" "Cartridge.Name" "River Raid (Robby)" "" "Cartridge.MD5" "3e5ca1afaa27c5da3c54c9942fec528b" "Cartridge.Name" "2600 Digital Clock (Demo 2) (PD)" "" "Cartridge.MD5" "111029770226b319524134193886a10e" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - One Limit Reached! (2001) (MP)" "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" "48287a9323a0ae6ab15e671ac2a87598" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Laser Volley (Zellers)" "Cartridge.Note" "AKA Innerspace" "" "Cartridge.MD5" "3e88cca5b860d0bd8947479e74c44284" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.ModelNo" "CX26122" "Cartridge.Name" "Sinistar (01-23-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "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" "d09a7504ee8c8717ac3e24d263e7814d" "Cartridge.Manufacturer" "Activision, Matthew L. Hubbard, Bob Whitehead" "Cartridge.ModelNo" "AX-024" "Cartridge.Name" "Dolphin (1983) (Activision) (16K)" "" "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" "c2fbef02b6eea37d8df3e91107f89950" "Cartridge.Manufacturer" "Champ Games" "Cartridge.Name" "Conquest Of Mars (NTSC)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "fa1b060fd8e0bca0c2a097dcffce93d3" "Cartridge.Manufacturer" "Atari, Christopher H. Omarzu, Preston Stuart, Bruce Williams" "Cartridge.ModelNo" "CX26101" "Cartridge.Name" "Oscar's Trash Race (1983) (Atari)" "Cartridge.Note" "Uses the Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "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" "1266b3fd632c981f3ef9bdbf9f86ce9a" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "EAZ-034-04, EAZ-034-04I" "Cartridge.Name" "Private Eye (1983) (Activision) (PAL)" "" "Cartridge.MD5" "61ef8c2fc43be9a04fe13fdb79ff2bd9" "Cartridge.Name" "Gas Gauge Demo - Revisited (2001) (Joe Grand) (PD)" "" "Cartridge.MD5" "55ef7b65066428367844342ed59f956c" "Cartridge.Manufacturer" "Atari, Joe Gaucher, Alex Leavens" "Cartridge.ModelNo" "CX2683" "Cartridge.Name" "Crazy Climber (1982) (Atari)" "" "Cartridge.MD5" "456453a54ca65191781aef316343ae00" "Cartridge.Name" "Full Screen Bitmap (3-D Green) (PD)" "" "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" "5e2495d43b981010304af55efed1e798" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Math Gran Prix (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "aa8e4b2cb8a78ffe6b20580033f4dec9" "Cartridge.Name" "Bitmap Demo (13-01-2003) (AD)" "" "Cartridge.MD5" "a3873d7c544af459f40d58dfcfb78887" "Cartridge.Name" "Tennis (Unknown)" "" "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" "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" "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" "feba8686fd0376015258d1152923958a" "Cartridge.Name" "Super Circus (Unknown) (PAL)" "Cartridge.Note" "AKA Circus Atari" "" "Cartridge.MD5" "7eaf009a892f03d90682dc1e67e85f07" "Cartridge.Manufacturer" "Fabrizio Zavagli" "Cartridge.Name" "Bounce! (18-03-2003) (Fabrizio Zavagli)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "34fd4fcb40ff5babce67f8b806d5969c" "Cartridge.Name" "Boxing (Dactari) (4K)" "" "Cartridge.MD5" "c225abfb584960efe1f359fc94b73379" "Cartridge.Name" "Joustpong (21-09-2002) (Kirk Israel) (PD)" "" "Cartridge.MD5" "9ca2deb61318eba4fb784d4bf7441d8b" "Cartridge.Name" "Purple Bar Demo 2 (PD)" "Cartridge.Rarity" "New Release" "" "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" "" "Cartridge.MD5" "5385cf2a04de1d36ab55c73174b84db0" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "Combat Rock (PD) (Hack)" "Cartridge.Note" "Hack of Combat" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "f0cacae1d1b79ee92f0dc035f42e0560" "Cartridge.Name" "Boring Donkey Kong (Hack)" "Cartridge.Note" "Hack of Donkey Kong" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "c3472fa98c3b452fa2fd37d1c219fb6f" "Cartridge.Manufacturer" "Atari, Carla Meninsky - Sears" "Cartridge.ModelNo" "CX2637 - 49-75158" "Cartridge.Name" "Dodge 'Em (1980) (Atari) [a]" "" "Cartridge.MD5" "dd17711a30ad60109c8beace0d4a76e8" "Cartridge.Name" "Karate (Unknown) (PAL)" "Display.YStart" "20" "" "Cartridge.MD5" "6d74ebaba914a5cfc868de9dd1a5c434" "Cartridge.Name" "Fortress (Smooth Version) (20-04-2003) (CT)" "" "Cartridge.MD5" "fe67087f9c22655ce519616fc6c6ef4d" "Cartridge.Manufacturer" "Atari, Randy Bowker" "Cartridge.ModelNo" "CX26142" "Cartridge.Name" "Crack'ed (11-28-1988) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "5524718a19107a04ec3265c93136a7b5" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "RealSports Basketball (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "bce4c291d0007f16997faa5c4db0a6b8" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "292.651 7" "Cartridge.Name" "Weltraumtunnel (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Innerspace" "" "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" "e02156294393818ff872d4314fc2f38e" "Cartridge.Manufacturer" "Sancho - Tang's Electronic Co." "Cartridge.ModelNo" "TEC005" "Cartridge.Name" "Dice Puzzle (1983) (Sancho) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b65d4a38d6047735824ee99684f3515e" "Cartridge.Manufacturer" "Dynacom" "Cartridge.Name" "MegaBoy (Dynacom)" "Display.YStart" "30" "" "Cartridge.MD5" "143918368f4f4dfff90999188c0197c9" "Cartridge.Name" "Unknown Title (bin00016 (200110)) (PD)" "" "Cartridge.MD5" "7a64b5a6e90619c6aacf244cdd7502f8" "Cartridge.Manufacturer" "Baroque Gaming (Brian Eno)" "Cartridge.Name" "Warring Worms (Beta 1) (2002) (Baroque Gaming)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "09d19274c20768f842e8fae84b766abe" "Cartridge.Name" "Star Fire - Animated Patricles (06-10-2002) (MP)" "" "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" "808c3b1e60ee0e7c65205fa4bd772221" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Defender (CCE)" "" "Cartridge.MD5" "7b43c32e3d4ff5932f39afcb4c551627" "Cartridge.Manufacturer" "Syncro, Dan Wolf" "Cartridge.Name" "Kamikaze Saucers (1983) (Syncro) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "38" "Display.Height" "220" "" "Cartridge.MD5" "9333172e3c4992ecf548d3ac1f2553eb" "Cartridge.Manufacturer" "Konami" "Cartridge.ModelNo" "RC 101-X 02" "Cartridge.Name" "Strategy X (1983) (Konami)" "Display.YStart" "30" "" "Cartridge.MD5" "aafc79ffc32c4c9b2d73c8ada7602cfe" "Cartridge.Name" "Planet Patrol (Unknown) (PAL)" "" "Cartridge.MD5" "5e1b7a6078af428ef056fe85a37a95ca" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AX-014, AX-014-04" "Cartridge.Name" "Grand Prix (1982) (Activision) (8K)" "" "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" "8bbfd951c89cc09c148bfabdefa08bec" "Cartridge.Manufacturer" "UA Limited" "Cartridge.Name" "Pleiades (1983) (UA Limited) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "32" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f2d4d6187903cac2d5ea8ed90dad120d" "Cartridge.Manufacturer" "Digimax" "Cartridge.Name" "River Raid II (Digimax)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "103f1756d9dc0dd2b16b53ad0f0f1859" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "732.174 8" "Cartridge.Name" "Go Go Home Monster (1983) (Quelle) (PAL)" "" "Cartridge.MD5" "4abb4c87a4c5f5d0c14ead2bb36251be" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26135, CX26135P" "Cartridge.Name" "RealSports Boxing (1987) (Atari) (PAL)" "" "Cartridge.MD5" "02dcba28c614fec7ca25955327128abb" "Cartridge.Manufacturer" "Andrew Wallace" "Cartridge.Name" "Laseresal 2002 (PAL) (PD) [a]" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "1b8c3c0bfb815b2a1010bba95998b66e" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Frogs and Flies (1989) (Telegames) (PAL)" "" "Cartridge.MD5" "91a3749ff7b7e72b7fa09e05396a0e7b" "Cartridge.Name" "Gunfight 2600 - Final Run Part 2 (2002) (MP)" "" "Cartridge.MD5" "e4e9125a8741977583776729359614e1" "Cartridge.Manufacturer" "SnailSoft" "Cartridge.Name" "Comitoid beta 4 (SnailSoft)" "" "Cartridge.MD5" "d2f713c78a9ebba9da6d10aeefc6f20f" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Enduro (Digivision) [a]" "" "Cartridge.MD5" "0546f4e6b946f38956799dd00caab3b1" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "My Golf (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "724613effaf7743cbcd695fab469c2a8" "Cartridge.Name" "Super-Ferrari (Unknown)" "Cartridge.Note" "AKA Enduro" "" "Cartridge.MD5" "e17699a54c90f3a56ae4820f779f72c4" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "465.302 8" "Cartridge.Name" "Vogel Flieh (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Dolphin" "" "Cartridge.MD5" "05824fcbe615dbca836d061a140a50e0" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 9 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "d2c957dd7746521b51bb09fde25c5774" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Cubis (6K) (1997) (Eckhard Stolberg)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "3b64a00ce147c3c29f7f8f8e531d08d8" "Cartridge.Name" "This Planet Sucks (16K) (Greg Troutman)" "Cartridge.Rarity" "New Release" "Display.YStart" "38" "" "Cartridge.MD5" "2ba02f509a4991aa176ba8d9e540df3d" "Cartridge.Manufacturer" "Atari, Mark R. Hahn" "Cartridge.ModelNo" "CX2678" "Cartridge.Name" "Dukes of Hazzard (1983) (Atari) [a]" "" "Cartridge.MD5" "d9ab6b67a17da51e5ad13717e93fa2e2" "Cartridge.Name" "Turbo (Coleco) Prototype Fake v0.1 (TJ)" "" "Cartridge.MD5" "8b8152d6081f31365406cb716bd95567" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX2626, CX2626P" "Cartridge.Name" "Miniature Golf (1979) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "151fa3218d8d7600114eb5bcd79c85cb" "Cartridge.Manufacturer" "Atari, Christopher H. Omarzu - Children's Computer Workshop" "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" "756ca07a65a4fbbedeb5f0ddfc04d0be" "Cartridge.Manufacturer" "Atari, Jim Huether" "Cartridge.ModelNo" "CX2629, CX2629P" "Cartridge.Name" "Sky Diver (1979) (Atari) (PAL)" "" "Cartridge.MD5" "e10d2c785aadb42c06390fae0d92f282" "Cartridge.Manufacturer" "Parker Brothers, Dawn Stockbridge" "Cartridge.ModelNo" "PB5910" "Cartridge.Name" "Strawberry Shortcake - Musical Match-Ups (1983) (Parker Bros)" "Display.YStart" "25" "Display.Height" "225" "" "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" "" "Cartridge.MD5" "01e5c81258860dd82f77339d58bc5f5c" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Corrida da Matematica (CCE)" "Cartridge.Note" "AKA Math Gran Prix" "" "Cartridge.MD5" "6a2c68f7a77736ba02c0f21a6ba0985b" "Cartridge.Manufacturer" "Atari, Larry Wagner, Bob Whitehead" "Cartridge.Name" "Computer Chess (07-07-1978) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7511c34518a9a124ea773f5b0b5c9a48" "Cartridge.Name" "Donkey Kong (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "cfb83a3b0513acaf8be4cae1512281dc" "Cartridge.Manufacturer" "Starpath Corporation" "Cartridge.Name" "Going-Up (1983) (Starpath) (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" "a4ab331e8768eafdc20ce8b0411ff77a" "Cartridge.Name" "Demo Image Series #1 - Sam (19-02-2003) (AD)" "" "Cartridge.MD5" "b0e1ee07fbc73493eac5651a52f90f00" "Cartridge.Manufacturer" "Colin Hughes" "Cartridge.Name" "Tetris 2600 (Colin Hughes)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "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" "9469d18238345d87768e8965f9f4a6b2" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Ms. Pac-Man (CCE)" "" "Cartridge.MD5" "5641c0ff707630d2dd829b26a9f2e98f" "Cartridge.Manufacturer" "Joystik" "Cartridge.Name" "Motocross (Joystik)" "Cartridge.Note" "AKA Motocross Racer" "" "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" "39a6a5a2e1f6297cceaa48bb03af02e9" "Cartridge.Name" "Pitfall 2 Plus (Hack)" "Cartridge.Note" "Hack of Pitfall 2" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "853c11c4d07050c22ef3e0721533e0c5" "Cartridge.Name" "Oink! (Unknown) (PAL)" "" "Cartridge.MD5" "8874b68751fd2ba6d3306a263ae57a7d" "Cartridge.Manufacturer" "Eric Mooney" "Cartridge.Name" "Invaders by Erik Mooney (Alpha 1) (PD)" "Cartridge.Rarity" "New Release" "" "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" "" "Cartridge.MD5" "b2f0d7217147160b2f481954cedf814b" "Cartridge.Name" "Marquee Drawer (2001) (B. Watson)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "163e7e757e2dc44469123ff0e5daec5e" "Cartridge.Name" "Many Blue Bars and Text Demo 2 (PD)" "" "Cartridge.MD5" "a8633050a686270fcf6c0cc4dcbad630" "Cartridge.Manufacturer" "Zirok" "Cartridge.Name" "Phoenix (Zirok)" "" "Cartridge.MD5" "d82c8a58098a6b46c5b81c16180354d1" "Cartridge.Manufacturer" "Dennis Debro" "Cartridge.Name" "Climber 5 (30-10-2002) (Dennis Debro) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "28" "" "Cartridge.MD5" "3ac6c50a8e62d4ce71595134cbd8035e" "Cartridge.Manufacturer" "Absolute Entertainment, Dan Kitchen" "Cartridge.ModelNo" "AK-046-04" "Cartridge.Name" "Tomcat (1988) (Absolute)" "Display.YStart" "24" "" "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" "Display.YStart" "24" "" "Cartridge.MD5" "b83579c4450fcbdf2b108903731fa734" "Cartridge.Name" "Mission 3,000 A.D. (208 in 1) (Unknown) (PAL)" "Display.Phosphor" "YES" "" "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" "93420cc4cb1af1f2175c63e52ec18332" "Cartridge.Manufacturer" "Tim Snider" "Cartridge.Name" "Blair Witch Project (Tim Snider) (Hack)" "Cartridge.Note" "Hack of Haunted House" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "05eb4347f0ec8f4783983ca35ffd8d1b" "Cartridge.Name" "Qb (2.06) (Retroactive) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f20675c8b98518367b9f5b8ee6f7c8ea" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Stampede (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "17bbe288c3855c235950fea91c9504e9" "Cartridge.Manufacturer" "Dismac" "Cartridge.Name" "Pega Ladrao (Dismac)" "Cartridge.Note" "AKA Keystone Kapers" "" "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" "9c6d65bd3b477aace0376f705b354d68" "Cartridge.Name" "RPG Kernal (18-04-2003) (Paul Slocum) (PD)" "Display.Phosphor" "YES" "" "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" "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" "2d16a8b59a225ea551667be45f554652" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "802.744 3" "Cartridge.Name" "Der Geheimkurier (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Mr. Postman" "" "Cartridge.MD5" "9e904e2eaa471c050c491289b8b80f60" "Cartridge.Name" "How to Draw a Playfield II (1997) (Erik Mooney) (PD)" "" "Cartridge.MD5" "1c3f3133a3e5b023c77ecba94fd65995" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-830" "Cartridge.Name" "Planet Patrol (1983) (CCE) [a]" "" "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" "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" "603c7a0d12c935df5810f400f3971b67" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG209" "Cartridge.Name" "Mr. Postman (1983) (BitCorp) (PAL)" "" "Cartridge.MD5" "75169c08b56e4e6c36681e599c4d8cc5" "Cartridge.Manufacturer" "M Network, 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" "" "Cartridge.MD5" "db971b6afc9d243f614ebf380af0ac60" "Cartridge.Manufacturer" "Gammation, Robert L. Esken Jr." "Cartridge.Name" "Gamma-Attack (1983) (Gammation)" "" "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" "103d4c890c2108cb536372c98d093e5f" "Cartridge.Name" "Star Fire - Star Background (MP)" "" "Cartridge.MD5" "7a93d0c029eaa72236523eedc3f19645" "Cartridge.Name" "20 Sprites at Once Demo 2 (PD)" "" "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" "bf9ddc5dd9056633d4ac0dac8b871dfe" "Cartridge.Name" "Star Fire - Cockpit View (10-10-2002) (MP)" "" "Cartridge.MD5" "490eed07d4691b27f473953fbea6541a" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AB-035-04" "Cartridge.Name" "Pitfall II (1983) (Activision) [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" "" "Cartridge.MD5" "1b4b06c2a14ed3ee73b7d0fd61b6aaf5" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "6 AR-4400" "Cartridge.Name" "Excalibur (Dragonstomper Beta) (1982) (Arcadia) (Prototype) [a]" "" "Cartridge.MD5" "a14d8a388083c60283e00592b18d4c6c" "Cartridge.Name" "Tunnel Demo (28-03-2003) (AD)" "" "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" "" "Cartridge.MD5" "c5387fc1aa71f11d2fa82459e189a5f0" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG202" "Cartridge.Name" "Space Tunnel (1982) (BitCorp) (PAL)" "Cartridge.Note" "AKA Weltraum-Tunnel" "Display.Height" "256" "" "Cartridge.MD5" "f3c431930e035a457fe370ed4d230659" "Cartridge.Name" "Crackpots (Unknown) (PAL)" "" "Cartridge.MD5" "eb9f8b84c193d9d93a58fca112aa39ed" "Cartridge.Name" "Register Twiddler Demo (PD)" "" "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" "" "Cartridge.MD5" "19098c46da0640f2b5763167dea6c716" "Cartridge.Manufacturer" "Andrew Wallace" "Cartridge.Name" "Laseresal 2002 (NTSC) (PD)" "Cartridge.Rarity" "New Release" "" "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" "2e3728f3086dc3e71047ffd6b2d9f015" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Outlaw (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "a41450333f8dd0e96e5e9f0af3770ae9" "Cartridge.Name" "Basic Math (208 in 1) (Unknown) (PAL)" "" "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" "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" "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" "327fe8cf94f3a45c35a840a453df1235" "Cartridge.Name" "Spice Girls Rule Demo (PD)" "" "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" "32dcd1b535f564ee38143a70a8146efe" "Cartridge.Manufacturer" "Xonox - K-Tel Software, Anthony R. Henderson" "Cartridge.ModelNo" "99007, 6240" "Cartridge.Name" "Tomarc the Barbarian (1983) (Xonox)" "Cartridge.Note" "AKA Thundarr the Barbarian" "Display.YStart" "24" "" "Cartridge.MD5" "25472dfdeef6a42581a231d631d6b04d" "Cartridge.Name" "Gunfight 2600 - Design thoughts (MP)" "" "Cartridge.MD5" "4d77f291dca1518d7d8e47838695f54b" "Cartridge.Manufacturer" "Data Age" "Cartridge.ModelNo" "DA1004" "Cartridge.Name" "Airlock (1982) (Data Age)" "Cartridge.Rarity" "Common" "" "Cartridge.MD5" "63166867f75869a3592b7a94ea62d147" "Cartridge.Name" "Indy 500 (Hack) [a1]" "Cartridge.Note" "Hack of Indy 500" "Cartridge.Rarity" "Hack" "Controller.Left" "DRIVING" "Controller.Right" "DRIVING" "Display.YStart" "28" "" "Cartridge.MD5" "c1e6e4e7ef5f146388a090f1c469a2fa" "Cartridge.Manufacturer" "Bomb - Onbase" "Cartridge.ModelNo" "CA283" "Cartridge.Name" "Z-Tack (1983) (Bomb)" "Cartridge.Note" "AKA Base Attack" "Display.YStart" "30" "" "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" "1e750000af77cc76232f4d040f4ab060" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Raft Rider (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "2228c67d25e507603d4873d3934f0757" "Cartridge.Name" "Fu Kung! (V0.10) (28-01-2003) (AD)" "" "Cartridge.MD5" "69ebf910ab9b63e5b8345f016095003b" "Cartridge.Name" "Maze Demo 1 (PD)" "" "Cartridge.MD5" "baf4ce885aa281fd31711da9b9795485" "Cartridge.Manufacturer" "Atari, Douglas Neubauer" "Cartridge.ModelNo" "CX26176" "Cartridge.Name" "Radar Lock (1989) (Atari)" "" "Cartridge.MD5" "e5fcc62e1d73706be7b895e887e90f84" "Cartridge.Name" "Air-Sea Battle (Unknown) (PAL) (4K)" "Display.YStart" "40" "Display.Height" "260" "" "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" "92d1f6ac179ebe5963868d6bc1bdda8d" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "498" "Cartridge.Name" "Smash Hit Pak - Frogger, Boxing, Seaquest, Skiing, Stampede (HES) (PAL)" "" "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" "6058e40ce79d7434c7f7477b29abd4a5" "Cartridge.Name" "Rubik's Cube Demo (23-12-2002) (CT)" "" "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" "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" "Display.YStart" "30" "" "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" "2a1b454a5c3832b0240111e7fd73de8a" "Cartridge.Manufacturer" "Tigervision, Bill Hogue" "Cartridge.ModelNo" "7-011" "Cartridge.Name" "Miner 2049er Volume II (1983) (Tigervision)" "Display.YStart" "28" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4947c9de2e28b2f5f3b0c40ce7e56d93" "Cartridge.Name" "3-D Corridor Demo 2 (29-03-2003) (MP)" "" "Cartridge.MD5" "493e90602a4434b117c91c95e73828d1" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Lock 'n' Chase (1989) (Telegames) (PAL)" "" "Cartridge.MD5" "afc194534c1b346609ef05eff6d3cef6" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Boxing (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "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" "" "Cartridge.MD5" "c02e1afa0671e438fd526055c556d231" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "A-Team (Atari) (Prototype) (PAL60)" "Cartridge.Rarity" "Prototype" "Display.Format" "PAL60" "" "Cartridge.MD5" "94e7cc6342d11e508e7e8b2ddf53c255" "Cartridge.Name" "Missile Command (208 in 1) (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "7f790939f7eaa8c47a246c4283981f84" "Cartridge.Name" "This Planet Sucks Demo 3 (Greg Troutman) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "968efc79d500dce52a906870a97358ab" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26190" "Cartridge.Name" "BMX Air Master (1990) (Atari)" "" "Cartridge.MD5" "44f71e70b89dcc7cf39dfd622cfb9a27" "Cartridge.Manufacturer" "Tigervision, Robert H. O'Neil" "Cartridge.ModelNo" "7-007" "Cartridge.Name" "Polaris (1983) (Tigervision)" "" "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" "90b1799dddb8bf748ee286d22e609480" "Cartridge.Name" "Ship Demo (PD)" "" "Cartridge.MD5" "dd92d6ad50976f881d86b52d38616118" "Cartridge.Manufacturer" "SpkSoft" "Cartridge.Name" "River Raid (SpkSoft) [h1]" "Display.YStart" "10" "" "Cartridge.MD5" "562acb1b7ff182aba133bda8e21ad7c1" "Cartridge.Name" "Space Treat Deluxe (08-03-2003) (Fabrizio Zavagli)" "" "Cartridge.MD5" "3e03086da53ecc29d855d8edf10962cb" "Cartridge.Manufacturer" "CBS Electronics, Joe Gaucher, Alex Leavens" "Cartridge.ModelNo" "4L1751, 4L1752, 4L1753, 4L2275" "Cartridge.Name" "Gorf (1982) (CBS Electronics) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "63a6eda1da30446569ac76211d0f861c" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-001" "Cartridge.Name" "Dragster (1980) (Activision) (4K)" "Display.YStart" "27" "" "Cartridge.MD5" "a8916734ff8c64ec3342f4c73fd5b57d" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "Stand Alone Test Cart (1982) (Atari) [a]" "" "Cartridge.MD5" "40b59249e05135bca33861e383735e9e" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Skiing (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "4e99ebd65a967cabf350db54405d577c" "Cartridge.Manufacturer" "Coleco" "Cartridge.ModelNo" "2663" "Cartridge.Name" "Time Pilot (1983) (Coleco) [b1]" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "a8d4a9500b18b0a067a1f272f869e094" "Cartridge.Name" "Red And White Checkerboard Demo (PD)" "" "Cartridge.MD5" "a29df35557f31dfea2e2ae4609c6ebb7" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "Circus Atari (1980) (Atari) (Joystick)" "" "Cartridge.MD5" "103e9d616328969f5d7b4e0a381b25d5" "Cartridge.Name" "Playfield Illustration and Logo Demo (2001) (Jake Patterson) (PD)" "" "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" "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" "bc3057a35319aae3a5cd87a203736abe" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-845" "Cartridge.Name" "Time Warp (1983) (CCE)" "Display.YStart" "30" "" "Cartridge.MD5" "abb740bea0a6842831b4f53112fb8145" "Cartridge.Name" "Qb (V1.01) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "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" "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" "6a3b0c33cf74b1e213a629e3c142b73c" "Cartridge.Manufacturer" "Cody Pittman" "Cartridge.Name" "Cory The Interviewer (Cody Pittman) (Hack)" "Cartridge.Note" "Hack of Ghostbusters" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "2bb0a1f1dee5226de648eb5f1c97f067" "Cartridge.Manufacturer" "Robby" "Cartridge.Name" "Enduro (Robby)" "" "Cartridge.MD5" "91c2098e88a6b13f977af8c003e0bca5" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2676" "Cartridge.Name" "Centipede (1982) (Atari)" "" "Cartridge.MD5" "d57913088e0c49ac3a716bf9837b284f" "Cartridge.Manufacturer" "Activision, Garry Kitchen" "Cartridge.ModelNo" "EAZ-032" "Cartridge.Name" "Pressure Cooker (1983) (Activision) (PAL) [a]" "" "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" "5a6febb9554483d8c71c86a84a0aa74e" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1003" "Cartridge.Name" "Donkey Kong Jr (1983) (CCE)" "Cartridge.Note" "AKA Donkey Kong Junior" "" "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" "7ba07d4ea18bf3b3245c374d8720ad30" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4101" "Cartridge.Name" "Communist Mutants from Space (Preview) (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "e03b0b091bea5bc9d3f14ee0221e714d" "Cartridge.Manufacturer" "CBS Electronics, Bob Curtiss" "Cartridge.ModelNo" "4L1845, 4L1852, 4L1853, 4L1854" "Cartridge.Name" "Solar Fox (1983) (CBS Electronics) (PAL)" "" "Cartridge.MD5" "1738b2e3f25ab3eef3cecb95e1d0d957" "Cartridge.Name" "Hangman Monkey Biglist1 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "1f40eefc7447336ae6cd8ffa5eb325be" "Cartridge.Manufacturer" "Atari, Chris Crawford" "Cartridge.Name" "Wizard (1980) (Atari) (Prototype) (4K) [a]" "Cartridge.Rarity" "Prototype" "" "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" "0d35618b6d76ddd46d2626e9e3e40db5" "Cartridge.Name" "X-Doom V.26 (PD)" "" "Cartridge.MD5" "497f3d2970c43e5224be99f75e97cbbb" "Cartridge.Manufacturer" "CommaVid, John Bronstein" "Cartridge.ModelNo" "CM-002" "Cartridge.Name" "Video Life (1981) (CommaVid)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3fd1f9d66a418c9f787fc5799174ddb7" "Cartridge.Manufacturer" "Aaron Curtis" "Cartridge.Name" "AStar (PAL)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "cfd6a8b23d12b0462baf6a05ef347cd8" "Cartridge.Manufacturer" "Activision, Larry Kaplan" "Cartridge.ModelNo" "AX-006" "Cartridge.Name" "Bridge (1980) (Activision)" "" "Cartridge.MD5" "8aad33da907bed78b76b87fceaa838c1" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Air-Sea Battle (32 in 1) (1988) (Atari) (PAL)" "Display.YStart" "40" "Display.Height" "256" "" "Cartridge.MD5" "cb8399dc0d409ff1f531ef86b3b34953" "Cartridge.Name" "Demo Image Series #12 - Luigi And Mario (01-03-2003) (AD)" "" "Cartridge.MD5" "cfe2185f84ce8501933beb5c5e1fd053" "Cartridge.Name" "Football (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "f661f129644f338b13d9f4510d816c03" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Outlaw (32 in 1) (1988) (Atari) (PAL) (4K)" "" "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" "" "Cartridge.MD5" "17badbb3f54d1fc01ee68726882f26a6" "Cartridge.Manufacturer" "M Network, Hal Finney, Bruce Pedersen - INTV" "Cartridge.ModelNo" "MT5659" "Cartridge.Name" "Space Attack (1982) (M Network)" "Display.YStart" "28" "" "Cartridge.MD5" "3d9c2fccf8b11630762ff00811c19277" "Cartridge.Name" "Challenge of.... Nexar, The (Unknown) (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" "" "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" "328949872e454181223a80389d03c122" "Cartridge.Name" "Home Run (Unknown) (PAL)" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "dd4f4e0fbd81762533e39e6f5b55bb3a" "Cartridge.Name" "Turbo WIP (TJ)" "" "Cartridge.MD5" "de1e9fb700baf8d2e5ae242bffe2dbda" "Cartridge.Manufacturer" "Activision, Mike Riedel" "Cartridge.ModelNo" "EAK-043-04I" "Cartridge.Name" "Commando (1988) (Activision) (PAL)" "" "Cartridge.MD5" "f98d869f287d2ce4f8fb36e0686929d9" "Cartridge.Name" "Skeleton+ (17-04-2003) (Eric Ball) (NTSC)" "Cartridge.Sound" "STEREO" "" "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" "f5aa6bd10f662199c42e43863a30106c" "Cartridge.Name" "Music Kit (V1.0) - Song Player (Paul Slocum)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3a51a6860848e36e6d06ffe01b71fb13" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.07) (Retroactive) (NTSC)" "Display.Phosphor" "YES" "" "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" "3b8aacf5f5638492b926b5124de19f18" "Cartridge.Manufacturer" "Atari, Tod Frye - Sears" "Cartridge.ModelNo" "CX2646 - 49-75185" "Cartridge.Name" "Pac-Man (1981) (Atari) (8K)" "" "Cartridge.MD5" "19e739c2764a5ab9ed08f9095aa2af0b" "Cartridge.Manufacturer" "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee" "Cartridge.ModelNo" "CX26117" "Cartridge.Name" "Obelix (1983) (Atari) (PAL)" "" "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" "14dbb3686dd31964332dc2ef0c55cad0" "Cartridge.Name" "Demo Image Series #15 - Three Marios (PAL) (Non-Interleave) (06-03-2003) (AD)" "" "Cartridge.MD5" "3276c777cbe97cdd2b4a63ffc16b7151" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, Kevin Osborn" "Cartridge.ModelNo" "CX2691" "Cartridge.Name" "Joust (1983) (Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "65c6406f5af934590097c8c032ebb482" "Cartridge.Name" "Three Hugger (Pave Demo) (20-12-2002) (Billy Eno)" "" "Cartridge.MD5" "02ced7ea2b7cb509748db6bfa227ebec" "Cartridge.Manufacturer" "Parker Brothers, Ed English, David Lamkins" "Cartridge.ModelNo" "931502" "Cartridge.Name" "Frogger (1982) (Parker Bros) (PAL)" "" "Cartridge.MD5" "3f5a43602f960ede330cd2f43a25139e" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AG-003" "Cartridge.Name" "Checkers (1980) (Activision)" "" "Cartridge.MD5" "10958cd0a1a81d599005f1797ab0e51d" "Cartridge.Name" "Centipede 2k (2000) (PD) (Hack)" "Cartridge.Note" "Hack of Centipede" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "aa2c4b32656bde9a75042a4d158583e1" "Cartridge.Name" "Oystron X (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "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" "a3b9d2be822eab07e7f4b10593fb5eaa" "Cartridge.Name" "GREGXM Demo (PD)" "" "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" "e9be3e8e4a7e73dd63ed4235a3a1a25f" "Cartridge.Name" "MMetall (Hack)" "Cartridge.Note" "Hack of Miniature Golf" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "81073d0377a2badef8d5e74fc44fc323" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Sadoom (TJ) (PAL60) (Hack)" "Cartridge.Note" "Hack of Kaboom!" "Cartridge.Rarity" "Hack" "Controller.Left" "PADDLES" "Display.Format" "PAL60" "" "Cartridge.MD5" "58c396323ea3e85671e34c98eb54e2a4" "Cartridge.Manufacturer" "Brian Watson" "Cartridge.Name" "Color Tweaker (B. Watson)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "e6508b878145187b87b9cded097293e7" "Cartridge.Name" "Oystron (V2.8) (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "50568c80ac61cab789d9923c9b05b68e" "Cartridge.Manufacturer" "Ebivision" "Cartridge.Name" "Merlin's Walls - Standard Edition (1999) (Ebivision)" "Cartridge.Note" "Image rotated 90 degrees CW" "" "Cartridge.MD5" "6337927ad909aa739d6d0044699a916d" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 2 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "3c82e808fe0e6a006dc0c4e714d36209" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-004" "Cartridge.Name" "Fishing Derby (1980) (Activision) (16K)" "" "Cartridge.MD5" "5aea9974b975a6a844e6df10d2b861c4" "Cartridge.Manufacturer" "Atari, Dan Hitchens" "Cartridge.ModelNo" "CX2656" "Cartridge.Name" "SwordQuest - EarthWorld (1982) (Atari)" "Cartridge.Note" "AKA Adventure I, SwordQuest I - EarthWorld" "" "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" "Display.YStart" "26" "" "Cartridge.MD5" "b676a9b7094e0345a76ef027091d916b" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Mission Survive (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Console.RightDifficulty" "A" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3b91c347d8e6427edbe942a7a405290d" "Cartridge.Manufacturer" "Parker Brothers" "Cartridge.ModelNo" "PB5350" "Cartridge.Name" "Sky Skipper (1983) (Parker Bros)" "" "Cartridge.MD5" "9e437229136f1c5e6ef4c5f36178ed18" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Grand Prize (Funvision)" "Cartridge.Note" "AKA Enduro" "" "Cartridge.MD5" "87b460df21b7bbcfc57b1c082c6794b0" "Cartridge.Manufacturer" "Dennis Debro" "Cartridge.Name" "Climber 5 (20-03-2003) (Dennis Debro)" "Cartridge.Rarity" "Homebrew" "Display.YStart" "28" "" "Cartridge.MD5" "d82675ce67caf16afe5ed6b6fac8aa37" "Cartridge.Name" "Robot City (V0.23) (13-11-2002) (TJ)" "" "Cartridge.MD5" "f539e32bf6ce39c8ca47cb0cdd2c5cb8" "Cartridge.Manufacturer" "Control Video Corporation" "Cartridge.Name" "GameLine Master Module ROM (1983) (Control Video)" "" "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" "c6c63da3bc2e47291f63280e057061d0" "Cartridge.Manufacturer" "128-in-1 Junior Console" "Cartridge.Name" "Human Cannonball (128-in-1 Junior Console) (PAL) (4K)" "" "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" "" "Cartridge.MD5" "d0e9beb2347595c6c7d158e9d83d2da8" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.00) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "30685b9b6ebd9ba71536dd7632a1e3b6" "Cartridge.Manufacturer" "Dactari - Milmar" "Cartridge.Name" "Tennis (Dactari)" "" "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" "0fcff6fe3b0769ad5d0cf82814d2a6d9" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-027" "Cartridge.Name" "Zoo Fun (Suntek) (PAL)" "" "Cartridge.MD5" "0dd4c69b5f9a7ae96a7a08329496779a" "Cartridge.Manufacturer" "Tigervision, Karl T. Olinger - Teldec" "Cartridge.ModelNo" "7-001 - 3.60001 VE" "Cartridge.Name" "King Kong (1982) (Tigervision) (PAL)" "" "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" "fc2233fc116faef0d3c31541717ca2db" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.ModelNo" "CX2646" "Cartridge.Name" "Pac-Man (1982) (Atari) (PAL)" "" "Cartridge.MD5" "38de7b68379770b9bd3f7bf000136eb0" "Cartridge.Manufacturer" "Imagic, Mark Klein" "Cartridge.ModelNo" "EIZ-003-04I" "Cartridge.Name" "Subterranea (1983) (Imagic) (PAL)" "" "Cartridge.MD5" "dba2692a216cb6c262c78f8b111a813e" "Cartridge.Name" "Star Fire (08-10-2002) (MP)" "" "Cartridge.MD5" "0956285e24a18efa10c68a33846ca84d" "Cartridge.Manufacturer" "Dismac" "Cartridge.Name" "Viagem Espacial (Dismac)" "Cartridge.Note" "AKA Star Voyager" "" "Cartridge.MD5" "5f39353f7c6925779b0169a87ff86f1e" "Cartridge.Manufacturer" "Atari - GCC, Betty Ryan Tylko, Douglas B. Macrae" "Cartridge.ModelNo" "CX2694" "Cartridge.Name" "Pole Position (1983) (Atari) [a]" "" "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" "4e15ddfd48bca4f0bf999240c47b49f5" "Cartridge.Manufacturer" "Avalon Hill, Jean Baer, Jim Jacob" "Cartridge.ModelNo" "5001002" "Cartridge.Name" "Death Trap (1983) (Avalon Hill)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "29949f893ef6cb9e8ecb368b9e99eee4" "Cartridge.Manufacturer" "Erik Eid" "Cartridge.Name" "Euchre (Alpha) (NTSC) (31-08-2002) (Erik Eid)" "Cartridge.Rarity" "New Release" "" "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" "34f4b1d809aa705ace6e46b13253fd3b" "Cartridge.Manufacturer" "Aaron Bergstrom" "Cartridge.Name" "Nothern Alliance (Aaron Bergstrom) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "d8acaa980cda94b65066568dd04d9eb0" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Sea Hunt (CCE)" "Cartridge.Note" "AKA Skindiver" "" "Cartridge.MD5" "e0221c95aa657f5764eeeb64c8429258" "Cartridge.Name" "Tomb Raider 2600 [REV 02] (Montezuma's Revenge Hack)" "" "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" "13d8326bf5648db4dafce45d25e62ddd" "Cartridge.Name" "Atari Logo Demo 2 (PD)" "" "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" "a499d720e7ee35c62424de882a3351b6" "Cartridge.Manufacturer" "Sega, Phat Ho - Bally Midway - Beck-Tech" "Cartridge.ModelNo" "009-01" "Cartridge.Name" "Up 'n Down (1984) (Sega)" "Display.YStart" "30" "" "Cartridge.MD5" "966b11d3c147d894dd9e4ebb971ea309" "Cartridge.Name" "Marble Craze Song (Paul Slocum) (PD)" "" "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" "db5073bd75eb05f7d62a7268396d1e77" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Golf (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "afb3bc45c6a82739cc82582127cd96e6" "Cartridge.Manufacturer" "Atari, John Howard Palevich" "Cartridge.ModelNo" "CX26151, CX26151P" "Cartridge.Name" "Dungeon (11-22-1985) (Atari) (Prototype)" "Cartridge.Note" "Dark Chambers Beta" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "069c17beb1e8e0557adb8539fdcf6cba" "Cartridge.Name" "Phantom II & Pirate (PAL60)" "Cartridge.Rarity" "Homebrew" "Display.Format" "PAL60" "" "Cartridge.MD5" "b3203e383b435f7e43f9492893c7469f" "Cartridge.Manufacturer" "Gameworld" "Cartridge.ModelNo" "133-003" "Cartridge.Name" "Sssnake (1983) (Gameworld) (PAL)" "" "Cartridge.MD5" "fb833ed50c865a9a505a125fc9d79a7e" "Cartridge.Manufacturer" "ITT Family Games" "Cartridge.Name" "Pumuckl I (1983) (ITT Family Games) (PAL)" "Cartridge.Note" "AKA Panda Chase" "Display.YStart" "30" "" "Cartridge.MD5" "98f63949e656ff309cefa672146dc1b8" "Cartridge.Manufacturer" "Atari - Axlon" "Cartridge.ModelNo" "CX26168" "Cartridge.Name" "Off the Wall (1989) (Atari)" "" "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" "3624e5568368929fabb55d7f9df1022e" "Cartridge.Manufacturer" "Activision, Dan Kitchen" "Cartridge.ModelNo" "EAK-050-04" "Cartridge.Name" "Double Dragon (1989) (Activision) (PAL)" "" "Cartridge.MD5" "106855474c69d08c8ffa308d47337269" "Cartridge.Manufacturer" "Atari, Adam Clayton, John Howard Palevich" "Cartridge.ModelNo" "CX26151" "Cartridge.Name" "Dark Chambers (1988) (Atari)" "Display.Phosphor" "YES" "" "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" "7eab0284a0cd1043461d446a08d08cec" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Basic Math (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "9a21fba9ee9794e0fadd7c7eb6be4e12" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26177" "Cartridge.Name" "Ikari Warriors (1989) (Atari)" "" "Cartridge.MD5" "df62a658496ac98a3aa4a6ee5719c251" "Cartridge.Manufacturer" "Atari - Sears" "Cartridge.ModelNo" "CX2626 - 6-99829, 49-75116" "Cartridge.Name" "Miniature Golf (1979) (Atari)" "" "Cartridge.MD5" "7e8aa18bc9502eb57daaf5e7c1e94da7" "Cartridge.Manufacturer" "CBS Electronics" "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" "d17a671029b1532b197defca5f3649a7" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - Limit broken again! (2001) (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "91f0a708eeb93c133e9672ad2c8e0429" "Cartridge.Name" "Oystron (V2.9) (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "9d2f05d0fe8b2dfcf770b02eda066fc1" "Cartridge.Name" "Push (V0.06) (2001) (AD)" "" "Cartridge.MD5" "a6737c81542a99ee71cb5f5ff14703d9" "Cartridge.Name" "Scrolling Playfield 3 (Junkosoft) (PD)" "" "Cartridge.MD5" "66c4e0298d4120df333bc2f3e163657e" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (2 of 3) (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "9fc2d1627dcdd8925f4c042e38eb0bc9" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, John Allred" "Cartridge.ModelNo" "CX2688, CX2688P" "Cartridge.Name" "Jungle Hunt (1983) (Atari) (PAL)" "" "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" "6672de8f82c4f7b8f7f1ef8b6b4f614d" "Cartridge.Manufacturer" "Videospielkassette - Ariola" "Cartridge.ModelNo" "PGP237" "Cartridge.Name" "Angeln I (Ariola) (PAL)" "Cartridge.Note" "AKA Fishing Derby" "" "Cartridge.MD5" "5846b1d34c296bf7afc2fa05bbc16e98" "Cartridge.Manufacturer" "Atari, Larry Kaplan - Sears" "Cartridge.ModelNo" "CX2643 - 6-99815" "Cartridge.Name" "Codebreaker (1978) (Atari)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "227532d82505c3c185a878273c285d5f" "Cartridge.Name" "Hangman Man Original Words (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "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" "ee6cbedf6c0aac90faa0a8dbc093ffbe" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "My Golf (CCE) (PAL)" "" "Cartridge.MD5" "fc9c1652fe3a2cade6188f4d3692481f" "Cartridge.Manufacturer" "Andrew Davies" "Cartridge.Name" "Andrew Davies early notBoulderDash demo (NTSC)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0832fb2ee654bf9382bc57d2b16d2ffc" "Cartridge.Manufacturer" "Apollo, Ed Salvo" "Cartridge.ModelNo" "AP-1001" "Cartridge.Name" "Skeet Shoot (1981) (Apollo) (PAL)" "" "Cartridge.MD5" "1278f74ca1dfaa9122df3eca3c5bcaad" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "719.013 5" "Cartridge.Name" "Ungeheuer der Tiefe (Quelle) (PAL)" "Cartridge.Note" "AKA Skindiver" "Display.YStart" "38" "" "Cartridge.MD5" "a1ead9c181d67859aa93c44e40f1709c" "Cartridge.Manufacturer" "American Videogame - Dunhill Electronics, Darrell Wagner, Todd Clark Holm, John Simonds" "Cartridge.Name" "Tax Avoiders (1982) (American Videogame)" "" "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" "ad8072675109d13fdd31a2e0403d5cff" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Tank City (Funvision)" "Cartridge.Note" "AKA Thunderground" "" "Cartridge.MD5" "17515a4d0b7ea5029ffff7dfa8456671" "Cartridge.Manufacturer" "Piero Cavina" "Cartridge.Name" "Multi-Sprite Demo V1.1 (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "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" "9b21d8fc78cc4308990d99a4d906ec52" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-838" "Cartridge.Name" "Immies & Aggies (1983) (CCE)" "Display.YStart" "18" "Display.Height" "223" "" "Cartridge.MD5" "35163b56f4a692a232ae96ad3e23310f" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.12) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "59734e1cc41822373845a09c51e6ba21" "Cartridge.Manufacturer" "Activision, John Van Ryzin" "Cartridge.ModelNo" "AG-038-04" "Cartridge.Name" "Cosmic Commuter (1984) (Activision) (8K)" "" "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" "961112b74a920a5242e233480326c356" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AG-007, CAG-007" "Cartridge.Name" "Tennis (1981) (Activision) (16K)" "" "Cartridge.MD5" "3c4a6f613ca8ba27ce9e43c6c92a3128" "Cartridge.Name" "Qb (V0.04) (Non-Lax Version) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "98ef1593624b409b9fb83a1c272a0aa7" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-831" "Cartridge.Name" "Cosmic Ark (1983) (CCE)" "" "Cartridge.MD5" "d5aa7472e7f2cc17e893a1a36f8dadf0" "Cartridge.Name" "Overhead Adventure Demo 5 (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" "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" "" "Cartridge.MD5" "e4c2077a18e3c27f4819aa7757903aa0" "Cartridge.Name" "Many Blue Bars Demo (PD)" "" "Cartridge.MD5" "04e737c9d53cd84bfd5ee679954e4706" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Checkers (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "6076b187a5d8ea7a2a05111c19b5d5cd" "Cartridge.Name" "Fu Kung! (V0.14) (01-02-2003) (AD)" "" "Cartridge.MD5" "c225379e7c4fb6f886ef9c8c522275b4" "Cartridge.Manufacturer" "Video Mania" "Cartridge.Name" "Frostbite (1983) (Video Mania)" "" "Cartridge.MD5" "cd4423bd9f0763409bae9111f888f7c2" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "River Raid (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "08bd4c1dcc843f6a0b563d9fd80b3b11" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "343.273 9" "Cartridge.Name" "Phantompanzer II (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Thunderground" "" "Cartridge.MD5" "c7d5819b26b480a49eb26aeb63cc831e" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PGP210" "Cartridge.Name" "Ice Hockey (4 Game in One Light Green) (1983) (BitCorp) (PAL)" "" "Cartridge.MD5" "7a7f6ab9215a3a6b5940b8737f116359" "Cartridge.Manufacturer" "Arcadia Corporation, Kevin Norman" "Cartridge.ModelNo" "AR-4103" "Cartridge.Name" "Killer Satellites (1983) (Arcadia)" "" "Cartridge.MD5" "8f5ac5139419c5d49bacc296e342a247" "Cartridge.Manufacturer" "Atari, 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" "60358edf0c2cc76b1e549e031e50e130" "Cartridge.Manufacturer" "Manuel Polik" "Cartridge.Name" "Cyber Goth Galaxian (Manuel Polik) (Hack)" "Cartridge.Note" "Hack of Galaxian" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "3c7a96978f52b2b15426cdd50f2c4048" "Cartridge.Name" "Overhead Adventure Demo 3 (PD)" "" "Cartridge.MD5" "18b28b386abdadb3a700ac8fb68e639a" "Cartridge.Manufacturer" "Manuel Polik" "Cartridge.Name" "Gunfight 2600 (MP) (PAL)" "Cartridge.Rarity" "New Release" "" "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" "1fa7a42c2c7d6b7a0c6a05d38c7508f4" "Cartridge.Manufacturer" "Coleco, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (09-04-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "08f853e8e01e711919e734d85349220d" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Michael Sierchio" "Cartridge.ModelNo" "CX2667" "Cartridge.Name" "RealSports Soccer (1983) (Atari)" "" "Cartridge.MD5" "292a0bb975b2587f9ac784c960e1b453" "Cartridge.Name" "Qb (05-02-2001) (AD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "332f01fd18e99c6584f61aa45ee7791e" "Cartridge.Name" "X'Mission (Unknown) (PAL)" "Display.YStart" "0" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4b143d7dcf6c96796c37090cba045f4f" "Cartridge.Manufacturer" "Atari, Jim Huether - Sears" "Cartridge.ModelNo" "CX2644 - 6-99824" "Cartridge.Name" "Flag Capture (1978) (Atari) (4K)" "" "Cartridge.MD5" "0cdd9cc692e8b04ba8eb31fc31d72e5e" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Wing War (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "736388d73198552d77d423962000006f" "Cartridge.Manufacturer" "Dactari" "Cartridge.Name" "Tennis (Dactari) (4K)" "" "Cartridge.MD5" "2b71a59a53be5883399917bf582b7772" "Cartridge.Manufacturer" "Greg Troutman" "Cartridge.Name" "Dark Mage (final beta) (Greg Troutman) (PD)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6a091b8ffeacd0939850da2094b51564" "Cartridge.Name" "Vertically Scrolling Playfield (02-02-2003) (Aaron Bergstrom)" "" "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" "cb24210dc86d92df97b38cf2a51782da" "Cartridge.Manufacturer" "Video Gems" "Cartridge.ModelNo" "VG-01" "Cartridge.Name" "Missile Control (1983) (Video Gems) (PAL)" "" "Cartridge.MD5" "a0d502dc8b90b1d7daa5f6effb10d349" "Cartridge.Name" "Demo Image Series #5 - Sam (19-02-2003) (AD)" "" "Cartridge.MD5" "b3017e397f74efd53caf8fae0a38e3fe" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.12) (Retroactive) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2d69a5f23784f1c2230143292a073b53" "Cartridge.Name" "Qb (Fixed background animation) (2001) (AD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "42b3ab3cf661929bdc77b621a8c37574" "Cartridge.Manufacturer" "Robby" "Cartridge.Name" "Volleyball (Robby)" "Cartridge.Note" "AKA RealSports Volleyball" "" "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" "" "Cartridge.MD5" "3556e125681aea864e17b09f3f3b2a75" "Cartridge.Name" "Incoming (2 Player Demo) (PD)" "" "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" "24b9adac1b4f85b0bac9bf9b9e180906" "Cartridge.Manufacturer" "Angelino" "Cartridge.Name" "Space 2002 (Angelino) (Hack)" "Cartridge.Note" "Hack of Space Jockey" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "aeb104f1e7b166bc0cbaca0a968fde51" "Cartridge.Name" "Ms. Pac-Man (1999) (Hack)" "Cartridge.Note" "Hack of Ms. Pac-Man" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "0ae3497e731ca0bf6a77b23441d9d9f9" "Cartridge.Name" "Analog Clock (V0.0) (20-01-2003) (AD)" "" "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" "ef60b06fddb675b0d783afbfa5fc5232" "Cartridge.Name" "Many Blue Bars and Text Demo 4 (PD)" "" "Cartridge.MD5" "10a3cd14e5dcfdde6ff216a14ce7b7dd" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX262, CX2627P" "Cartridge.Name" "Human Cannonball (1979) (Atari) (PAL)" "" "Cartridge.MD5" "59e53894b3899ee164c91cfa7842da66" "Cartridge.Manufacturer" "Data Age" "Cartridge.Name" "Survival Run (1983) (Data Age) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "40" "" "Cartridge.MD5" "93acd5020ae8eb5673601e2edecbc158" "Cartridge.Manufacturer" "Chris Cracknell" "Cartridge.Name" "Video Time Machine (Chris Cracknell)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "692202772d8b38ccf85a90c8003a1324" "Cartridge.Name" "Zi - The Flie Buster (2002) (Fernando Mora) (PD)" "" "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" "2aba6a1b01a5859e96d6a66d2286772f" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-027" "Cartridge.Name" "Plaque Attack (1983) (Activision) (8K)" "" "Cartridge.MD5" "3e1682ddaec486d8b6b90b527aaa0fc4" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Robot City (V0.12) (TJ)" "Cartridge.Rarity" "New Release" "Display.YStart" "24" "" "Cartridge.MD5" "e9cb18770a41a16de63b124c1e8bd493" "Cartridge.Manufacturer" "Parker Brothers, Joe Gaucher" "Cartridge.ModelNo" "931519" "Cartridge.Name" "Popeye (1983) (Parker Bros) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "04dfb4acac1d0909e4c360fd2ac04480" "Cartridge.Name" "Jammed (2001) (XYPE) (NTSC)" "Display.YStart" "24" "" "Cartridge.MD5" "d0cdafcb000b9ae04ac465f17788ad11" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "732.273 8 - 600273, 781644" "Cartridge.Name" "Lilly Adventure (1983) (Quelle) (PAL)" "" "Cartridge.MD5" "e6e5bb0e4f4350da573023256268313d" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Missile Control (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "dfcdd6f593bb7b05dbc2e8e1fc6ee0de" "Cartridge.Name" "Gunfight 2600 - Scenarios complete (MP)" "" "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" "79c27f90591e3fdc7d2ed020ecbedeb3" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-815" "Cartridge.Name" "Seaquest (1983) (CCE) [a]" "" "Cartridge.MD5" "ee84bdc5dae268e227e407c7b5e6b6b7" "Cartridge.Name" "Marilyn Monroe Demo (PD)" "" "Cartridge.MD5" "f6daebc0424fa0f8d9aaf26c86df50f4" "Cartridge.Manufacturer" "Brian Watson" "Cartridge.Name" "Color Tweaker (V1.0) (2001) (B. Watson)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "ab5bf1ef5e463ad1cbb11b6a33797228" "Cartridge.Manufacturer" "Imagic, Rob Fulop" "Cartridge.ModelNo" "720104-1A, 720104-1B, IA3204" "Cartridge.Name" "Cosmic Ark (1982) (Imagic)" "" "Cartridge.MD5" "9c27ef3bd01c611cdb80182a59463a82" "Cartridge.Manufacturer" "Arcadia Corporation, Kevin Norman" "Cartridge.ModelNo" "AR-4103" "Cartridge.Name" "Killer Satellites (1983) (Arcadia) [a]" "" "Cartridge.MD5" "698f569eab5a9906eec3bc7c6b3e0980" "Cartridge.Manufacturer" "SpkLeader" "Cartridge.Name" "Demons! (2003) (SpkLeader) (Hack)" "Cartridge.Note" "Hack of Phoenix" "Cartridge.Rarity" "Hack" "" "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" "40aa851e8d0f1c555176a5e209a5fabb" "Cartridge.Name" "Euchre (More for less) (NTSC) (22-08-2002) (Erik Eid)" "" "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" "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" "ba257438f8a78862a9e014d831143690" "Cartridge.Manufacturer" "U.S. Games Corporation, Henry Will IV" "Cartridge.ModelNo" "VC2002" "Cartridge.Name" "Squeeze Box (1982) (U.S. Games)" "" "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" "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" "" "Cartridge.MD5" "87e79cd41ce136fd4f72cc6e2c161bee" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker" "Cartridge.ModelNo" "CX2675" "Cartridge.Name" "Ms. Pac-Man (1982) (Atari)" "" "Cartridge.MD5" "ffebb0070689b9d322687edd9c0a2bae" "Cartridge.Name" "Spitfire Attack (1983) (Milton Bradley) [h1]" "Display.YStart" "28" "" "Cartridge.MD5" "a3f2a0fcf74bbc5fa763b0ee979b05b1" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "873.790 0" "Cartridge.Name" "Eishockey-Fieber (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Ice Hockey" "Display.YStart" "52" "" "Cartridge.MD5" "9718b85ac5a55cbc7348963c63ffa35a" "Cartridge.Manufacturer" "Robby" "Cartridge.Name" "Demon Attack (Robby)" "" "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" "33" "" "Cartridge.MD5" "e7f005ddb6902c648de098511f6ae2e5" "Cartridge.Manufacturer" "Spectravideo - Universum" "Cartridge.ModelNo" "SV-010" "Cartridge.Name" "CompuMate (1983) (Spectravideo) (PAL)" "Cartridge.Type" "CM" "Controller.Left" "COMPUMATE" "Controller.Right" "COMPUMATE" "Display.Format" "PAL" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e9c5d04643855949a23ff29349af74ea" "Cartridge.Name" "SCSIcide (Score Hack 2) (24-02-2001) (Joe Grand) (PD)" "" "Cartridge.MD5" "969b968383d9f0e9d8ffd1056bcaef49" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX2628, CX2628P" "Cartridge.Name" "Bowling (1979) (Atari) (PAL)" "Cartridge.Rarity" "Common" "" "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" "8c7e5e2329f4f4e06cbcc994a30fd352" "Cartridge.Manufacturer" "Data Age" "Cartridge.ModelNo" "DA1004" "Cartridge.Name" "Airlock (1982) (Data Age) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "62921652f6634eb1a0940ed5489c7e18" "Cartridge.Name" "SCSIcide (V1.09) (2001) (Joe Grand)" "Controller.Left" "PADDLES_IAXDR" "" "Cartridge.MD5" "b4f05e544834d0238a0c263491775edf" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Hales, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4102" "Cartridge.Name" "Suicide Mission (Preview) (1982) (Arcadia) (PAL)" "Display.Phosphor" "YES" "" "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" "3347a6dd59049b15a38394aa2dafa585" "Cartridge.Manufacturer" "Parker Brothers, Robert Jaeger" "Cartridge.ModelNo" "PB5760" "Cartridge.Name" "Montezuma's Revenge (1984) (Parker Bros)" "" "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" "fe0bc4bb92c1c4de7d5706aaa8d8c10d" "Cartridge.Name" "Sprite Demo 2 (PD)" "" "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" "3619786f6a32efc1e4a262d5aca8a070" "Cartridge.Manufacturer" "Atari, John Dunn - Sears" "Cartridge.ModelNo" "CX2631 - 49-75152" "Cartridge.Name" "Superman (1979) (Atari) (8K)" "" "Cartridge.MD5" "b6d52a0cf53ad4216feb04147301f87d" "Cartridge.Manufacturer" "Imagic, Michael Greene" "Cartridge.ModelNo" "720055-1A, IA3312" "Cartridge.Name" "No Escape! (1982) (Imagic)" "" "Cartridge.MD5" "dbabb80e92ff18d8eecf615c0539151e" "Cartridge.Name" "Sprite Demo 3 (PD)" "" "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" "4ae8c76cd6f24a2e181ae874d4d2aa3d" "Cartridge.Name" "Flash Gordon (Unknown) (PAL)" "" "Cartridge.MD5" "f047df70d3d08e331122cd2de61d6af8" "Cartridge.Manufacturer" "Dave Neuman" "Cartridge.Name" "Space Battle (NTSC)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "adb79f9ac1a633cdd44954e2eac14774" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Frostbite (Digivision)" "" "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" "ae2f1f69bb38355395c1c75c81acc644" "Cartridge.Manufacturer" "Parker Brothers, Wilfredo 'Willy' 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" "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" "b438a6aa9d4b9b8f0b2ddb51323b21e4" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "5861 A030" "Cartridge.Name" "Bogey Blaster (1989) (Telegames) (PAL)" "Cartridge.Note" "AKA Air Raiders" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "00b7b4cbec81570642283e7fc1ef17af" "Cartridge.Manufacturer" "Sega, Steve Beck, Phat Ho - Beck-Tech - Teldec" "Cartridge.ModelNo" "006-01" "Cartridge.Name" "Congo Bongo (1983) (Sega)" "Display.YStart" "36" "" "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" "" "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" "e1d5c8213e82820128fa9c4775f1e166" "Cartridge.Manufacturer" "Jess Ragan" "Cartridge.Name" "Jungle King (2003) (Jess Ragan) (Hack)" "Cartridge.Note" "Hack of Jungle Hunt" "Cartridge.Rarity" "Hack" "" "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" "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" "0f39fc03d579d0d93a6b729a3746843e" "Cartridge.Manufacturer" "Atari, 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" "cc74ddb45d7bc4d04c2e6f1907416699" "Cartridge.Name" "Colour Display Programme (1997) (Chris Cracknell)" "" "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" "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" "6a76d5f0ed721639474aa9bbde69ebf0" "Cartridge.Name" "Play Demo (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5acf9865a72c0ce944979f76ff9610f0" "Cartridge.Name" "Dodge Demo 2 (PD)" "" "Cartridge.MD5" "8bebac614571135933116045204f0f00" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Missile Command (CX-22 Trackball) (2002) (TJ) (PAL)" "Cartridge.Note" "Uses CX-22 Trackball Controller" "Cartridge.Rarity" "Homebrew" "Controller.Left" "TRACKBALL22" "Display.Phosphor" "YES" "" "Cartridge.MD5" "71464c54da46adae9447926fdbfc1abe" "Cartridge.Manufacturer" "M Network, Bruce Pedersen - INTV" "Cartridge.ModelNo" "MT5663" "Cartridge.Name" "Lock 'n' Chase (1982) (M Network)" "" "Cartridge.MD5" "64b8e19c767191ccdc97acc6904c397b" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 6 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "b6960be26bee87d53ba4e2e71cfe772f" "Cartridge.Name" "3-D Corridor (Spiral Words) (31-03-2003) (AD)" "" "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" "dc6aa0bb21a6e66e80e75ba5edc5c0dd" "Cartridge.Name" "Star Fire - Kernel Done (MP)" "" "Cartridge.MD5" "193f060553ba0a2a2676f91d9ec0c555" "Cartridge.Manufacturer" "Atari, Carol Shaw" "Cartridge.ModelNo" "CX2636, CX2636P" "Cartridge.Name" "Video Checkers (1980) (Atari) (PAL)" "" "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" "" "Cartridge.MD5" "afd2cf258d51ae4965ee21abba3627ab" "Cartridge.Manufacturer" "Atari, Christopher H. Omarzu - Children's Computer Workshop" "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" "61728c6cfb052e62a9ed088c5bf407ba" "Cartridge.Name" "Sprite Demo 4 (PD)" "" "Cartridge.MD5" "568371fbae6f5e5b936af80031cd8888" "Cartridge.Name" "Robotfindskitten2600 (26-04-2003) (Jeremy Penner)" "" "Cartridge.MD5" "4191b671bcd8237fc8e297b4947f2990" "Cartridge.Manufacturer" "Exus Corporation" "Cartridge.Name" "Video Jogger (1983) (Exus)" "Cartridge.Note" "AKA Foot Craz" "" "Cartridge.MD5" "92c5abb7a8bb1c3fc66c92ba353a3d21" "Cartridge.Name" "Star Fire - Sorting Fixed (MP)" "" "Cartridge.MD5" "cb9b2e9806a7fbab3d819cfe15f0f05a" "Cartridge.Manufacturer" "Parker Brothers, Ray Miller, Todd Marshall" "Cartridge.ModelNo" "931513" "Cartridge.Name" "Star Wars - Death Star Battle (1983) (Parker Bros) (PAL)" "" "Cartridge.MD5" "393e41ca8bdd35b52bf6256a968a9b89" "Cartridge.Manufacturer" "U.S. Games Corporation" "Cartridge.ModelNo" "VC1012" "Cartridge.Name" "M.A.D. (1982) (U.S. Games)" "" "Cartridge.MD5" "2e2885e68fa1045871ce1382b68f6efc" "Cartridge.Name" "Star Fire - Return of the Crosshair (MP)" "" "Cartridge.MD5" "199eb0b8dce1408f3f7d46411b715ca9" "Cartridge.Manufacturer" "Parker Brothers, David Lamkins, Laura Nikolich" "Cartridge.ModelNo" "PB5900" "Cartridge.Name" "Spider-Man (1982) (Parker Bros)" "Display.YStart" "30" "" "Cartridge.MD5" "c63a98ca404aa5ee9fcff1de488c3f43" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26145" "Cartridge.Name" "Venture (1987) (Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6e372f076fb9586aff416144f5cfe1cb" "Cartridge.Manufacturer" "Atari, Tod Frye - Sears" "Cartridge.ModelNo" "CX2646 - 49-75185" "Cartridge.Name" "Pac-Man (1982) (Atari)" "Display.YStart" "33" "" "Cartridge.MD5" "4b9581c3100a1ef05eac1535d25385aa" "Cartridge.Name" "IQ 180 (Unknown)" "Display.YStart" "20" "Display.Height" "235" "" "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" "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" "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" "1f349dd41c3f93c4214e5e308dccb056" "Cartridge.Name" "Virtual Pet Demo 2 (CRACKERS) (PD)" "" "Cartridge.MD5" "afe88aae81d99e0947c0cfb687b16251" "Cartridge.Manufacturer" "Apollo - Games by Apollo" "Cartridge.ModelNo" "AP-2006" "Cartridge.Name" "Infiltrate (1981) (Apollo)" "Display.YStart" "29" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7fcd5fb59e88fc7b8473c641f44226c3" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-807" "Cartridge.Name" "Space Tunnel (1983) (CCE)" "Display.Height" "215" "" "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" "873fb75a7788ba0f4ae715229a05545e" "Cartridge.Name" "Euchre (Improved Colors) (PAL) (26-09-2002) (Erik Eid)" "" "Cartridge.MD5" "3c57748c8286cf9e821ecd064f21aaa9" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira" "Cartridge.ModelNo" "CX26118" "Cartridge.Name" "Millipede (1984) (Atari)" "" "Cartridge.MD5" "95fd6097dc27c20666f039cfe34f7c69" "Cartridge.Name" "Oh No! (Version 1) (17-01-2003) (AD)" "" "Cartridge.MD5" "e5d72ff8bab4450be57785cc9e83f3c0" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "6082 A145" "Cartridge.Name" "Kung Fu Superkicks (1989) (Telegames) (PAL)" "Cartridge.Note" "AKA Chuck Norris Superkicks" "" "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" "f8240e62d8c0a64a61e19388414e3104" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-013" "Cartridge.Name" "Barnstorming (1982) (Activision)" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "d1d704a7146e95709b57b6d4cac3f788" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Slot Racers (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "8c941fa32c7718a10061d8c328909577" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "River Raid (Digivision)" "" "Cartridge.MD5" "db4eb44bc5d652d9192451383d3249fc" "Cartridge.Manufacturer" "CBS Electronics, E.F. Dreyer, Ed Salvo" "Cartridge.ModelNo" "4L 2738 0000" "Cartridge.Name" "Mountain King (1983) (CBS Electronics)" "Display.Phosphor" "YES" "" "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" "67cf913d1df0bf2d7ae668060d0b6694" "Cartridge.Name" "Hangman Monkey 4letter (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "90f502cbf4438a95f69f848cef36eb64" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "River Raid II (1985) (Digitel)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "cbad928e10aeee848786cc55394fb692" "Cartridge.Name" "Fu Kung! (V0.06a Cuttle Cart Compatible) (15-01-2003) (AD)" "" "Cartridge.MD5" "88ed87c011f699dd27321dbe404db6c8" "Cartridge.Manufacturer" "Activision, Dan Kitchen" "Cartridge.ModelNo" "AX-029" "Cartridge.Name" "Crackpots (1983) (Activision) (16K)" "" "Cartridge.MD5" "bdc381baf7c252c63739c5e9ed087a5c" "Cartridge.Name" "Vertical Ship Demo 1 (PD)" "" "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" "e434c0e161dd3c3fb435eb6bad2e182c" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein" "Cartridge.ModelNo" "CX2681" "Cartridge.Name" "Battlezone (05-02-1983) (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" "" "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" "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" "" "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" "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" "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" "f4204fc92d17ed4cb567c40361ad58f1" "Cartridge.Manufacturer" "Inky" "Cartridge.Name" "Beanie Baby Bash (Inky) (Hack)" "Cartridge.Note" "Hack of Beany Bopper" "Cartridge.Rarity" "Hack" "" "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" "89a65b83203980d5d4d60f52a584a5b8" "Cartridge.Name" "Marble Craze (PAL) (02-02-2003) (Paul Slocum)" "" "Cartridge.MD5" "dcec46a98f45b193f07239611eb878c2" "Cartridge.Name" "Bars and Text Demo (PD)" "" "Cartridge.MD5" "92e72f7cc569584c44c9530d645ae04e" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Spider Fighter (Canal 3)" "Display.YStart" "30" "" "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" "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.YStart" "24" "Display.Phosphor" "YES" "" "Cartridge.MD5" "93eb1795c8b1065b1b3d62bb9ec0ccdc" "Cartridge.Manufacturer" "JSK" "Cartridge.Name" "Custer's Viagra (JSK) (Hack)" "Cartridge.Note" "Hack of Custer's Revenge" "Cartridge.Rarity" "Hack" "Display.YStart" "32" "" "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" "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" "47bb1c677fe7ba5f376372ae7358e790" "Cartridge.Name" "Star Fire (10-10-2002) (MP)" "" "Cartridge.MD5" "e558be88eef569f33716e8e330d2f5bc" "Cartridge.Manufacturer" "Shock Vision" "Cartridge.Name" "Keystone Kapers (Shock Vision)" "" "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" "7cd900e9eccbb240fe9c37fa28f917b5" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Bi! Bi! (Jone Yuan) (PAL)" "Cartridge.Note" "AKA Skindiver" "Display.YStart" "38" "" "Cartridge.MD5" "ee659ae50e9df886ac4f8d7ad10d046a" "Cartridge.Manufacturer" "Exus Corporation" "Cartridge.Name" "Video Reflex (1983) (Exus)" "Cartridge.Note" "AKA Foot Craz" "" "Cartridge.MD5" "6fc394dbf21cf541a60e3b3631b817f1" "Cartridge.Manufacturer" "Imagic, Bob Smith" "Cartridge.ModelNo" "720020-2A, IA3611P" "Cartridge.Name" "Dragonfire (1982) (Imagic) (PAL)" "" "Cartridge.MD5" "36a701c60a9f9768d057bc2a83526a80" "Cartridge.Name" "Cube Conquest (Interlaced) (Billy Eno) (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "bb6a5a2f7b67bee5d1f237f62f1e643f" "Cartridge.Name" "Demo Image Series #5 - Animegirl (19-02-2003) (AD)" "" "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" "2e82a1628ef6c735c0ab8fa92927e9b0" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira" "Cartridge.ModelNo" "CX26109" "Cartridge.Name" "Sorcerer's Apprentice (1983) (Atari) (PAL)" "" "Cartridge.MD5" "a2170318a8ef4b50a1b1d38567c220d6" "Cartridge.Manufacturer" "Amiga" "Cartridge.ModelNo" "3125" "Cartridge.Name" "Surf's Up (1983) (Amiga) (Prototype) [a1]" "Cartridge.Note" "Uses the Amiga Joyboard" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "5c86e938e0845b9d61f458539e9a552b" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Surround (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "c033dc1d7b6fde41b9cadce9638909bb" "Cartridge.Name" "Skeleton (V1.1) (06-09-2002) (Eric Ball)" "" "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" "662eca7e3d89175ba0802e8e3425dedb" "Cartridge.Name" "Hangman Pac-Man Biglist3 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "a00ec89d22fcc0c1a85bb542ddcb1178" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1012" "Cartridge.Name" "Phoenix (1983) (CCE)" "" "Cartridge.MD5" "3e6dab92009d6034618cb6b7844c5216" "Cartridge.Name" "Ed Invaders (Hack)" "Cartridge.Note" "Hack of Pepsi Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "6b01a519b413f8cfa2f399f4d2841b42" "Cartridge.Name" "Aphex Invaders (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "4b753a97aee91e4b3e4e02f5e9758c72" "Cartridge.Manufacturer" "Glenn Saunders, Roger Williams" "Cartridge.Name" "Asymmetric Reflected Playfield (Glenn Saunders)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "9c40bf810f761ffc9c1b69c4647a8b84" "Cartridge.Name" "2 in 1 - Frostbite, River Raid (Unknown)" "Cartridge.Type" "2IN1" "" "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" "b2d1e63f7f22864096b7b6c154151d55" "Cartridge.Manufacturer" "Fabrizio Zavagli" "Cartridge.Name" "Bounce! (17-03-2003) (Fabrizio Zavagli)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8ed73106e2f42f91447fb90b6f0ea4a4" "Cartridge.Manufacturer" "Spectravision, Spectravideo" "Cartridge.ModelNo" "SA-204" "Cartridge.Name" "Tapeworm (1982) (Spectravision) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5835a78a88f97acea38c964980b7dbc6" "Cartridge.Name" "Cosmic Creeps (Unknown) (PAL)" "Display.Phosphor" "YES" "" "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" "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" "42cdd6a9e42a3639e190722b8ea3fc51" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AG-007, CAG-007" "Cartridge.Name" "Tennis (1981) (Activision)" "" "Cartridge.MD5" "16cc6d1b4ddce51c767a1ba8e5ff196c" "Cartridge.Name" "Big - Move This Demo 2 (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f7e07080ed8396b68f2e5788a5c245e2" "Cartridge.Manufacturer" "Video Game Cartridge - Ariola" "Cartridge.ModelNo" "TP-617" "Cartridge.Name" "Farmyard Fun (Ariola)" "Cartridge.Note" "AKA Play Farm" "Display.YStart" "33" "Display.Height" "217" "" "Cartridge.MD5" "dfe034297200dff672df9533ed1449a9" "Cartridge.Name" "Sprite Movement Demo 1 (2001) (Roger Williams)" "" "Cartridge.MD5" "7f819454734ddf93f83fefcffcd3e212" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Outlaw (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "61621a556ad3228f0234f5feb3ab135c" "Cartridge.Name" "Fu Kung! (V0.05 Cuttle Card Compattle Revision) (14-01-2003) (AD)" "" "Cartridge.MD5" "61631c2f96221527e7da9802b4704f93" "Cartridge.Manufacturer" "Activision, Mike Riedel" "Cartridge.ModelNo" "AK-043-04" "Cartridge.Name" "Commando (1988) (Activision) [different logo]" "" "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" "05aff8f626ef870432ae3b3d9d5aa301" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-019" "Cartridge.Name" "Sky Jinks (1982) (Activision) (16K)" "" "Cartridge.MD5" "2a10053fd08664c7cfbbb104386ed77f" "Cartridge.Name" "Alpha Demo - The Beta Demo (2000) (MP)" "" "Cartridge.MD5" "645bf7f9146f0e4811ff9c7898f5cd93" "Cartridge.Manufacturer" "Xonox - K-Tel Software" "Cartridge.ModelNo" "6230, 6250" "Cartridge.Name" "Super Kung-Fu (1983) (Xonox) (PAL)" "" "Cartridge.MD5" "25f9cf703575c5d63048c222f5463758" "Cartridge.Name" "Multi-Sprite Demo 1 (PD)" "" "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" "54" "" "Cartridge.MD5" "7adbcf78399b19596671edbffc3d34aa" "Cartridge.Manufacturer" "Atari, Joseph Tung" "Cartridge.ModelNo" "CX26152" "Cartridge.Name" "Super Baseball (1988) (Atari)" "Display.YStart" "30" "" "Cartridge.MD5" "3d2652cbea462a886a41791dd7c8d073" "Cartridge.Name" "Ritorno dei frattelli di Mario (Mario Bros Hack)" "" "Cartridge.MD5" "2ef36341d1bf42e02c7ea2f71e024982" "Cartridge.Name" "Space Invaders (Explosion Hack)" "Cartridge.Note" "Hack of Space Invaders (Atari)" "" "Cartridge.MD5" "bac28d06dfc03d3d2f4a7c13383e84ee" "Cartridge.Manufacturer" "Supergame" "Cartridge.Name" "Demon Attack (Supergame)" "" "Cartridge.MD5" "83f05ececae8be59ba1e51135f4bdcbf" "Cartridge.Name" "Demo Image Series #13 - Mario (4K Interleaved Chronocolour) (05-03-2003) (AD)" "" "Cartridge.MD5" "fd6e507b5df68beeeddeaf696b6828fa" "Cartridge.Name" "Boxing (Unknown) (PAL)" "" "Cartridge.MD5" "1428029e762797069ad795ce7c6a1a93" "Cartridge.Name" "Thunderground (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "bc33c685e6ffced83abe7a43f30df7f9" "Cartridge.Manufacturer" "Dynacom" "Cartridge.Name" "Seaquest (1983) (Dynacom)" "" "Cartridge.MD5" "a0028f057d496f22b549fd8deecc6f78" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide Pre-release 6 (Joe Grand)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "2bc6c53b19e0097a242f22375a6a60ff" "Cartridge.Name" "Droid Demo 2 (David Conrad Schweinsberg) (PD)" "" "Cartridge.MD5" "a35d47898b2b16ec641d1dfa8a45c2b7" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-017, AX-017-04" "Cartridge.Name" "MegaMania (1982) (Activision) (16K)" "" "Cartridge.MD5" "f992a39b46aa48188fab12ad3809ae4a" "Cartridge.Name" "Sky Jinks (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "ac7c2260378975614192ca2bc3d20e0b" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-930004, AZ-030" "Cartridge.Name" "Decathlon (1983) (Activision)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "5eeb81292992e057b290a5cd196f155d" "Cartridge.Manufacturer" "Wizard Video Games, Ed Salvo" "Cartridge.ModelNo" "008" "Cartridge.Name" "Texas Chainsaw Massacre, The (1983) (Wizard Video)" "" "Cartridge.MD5" "c689148ad9275667924ab334107b517e" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Space Raid (Jone Yuan)" "Cartridge.Note" "AKA MegaMania" "" "Cartridge.MD5" "87662815bc4f3c3c86071dc994e3f30e" "Cartridge.Manufacturer" "Intellivision Productions - M Network, Patricia Lewis Du Long, Stephen Tatsumi" "Cartridge.Name" "Swordfight (1983) (Intellivision)" "" "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" "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" "76a9bf05a6de8418a3ebc7fc254b71b4" "Cartridge.Manufacturer" "VideoSoft, Jerry Lawson, Dan McElroy" "Cartridge.ModelNo" "VS1008" "Cartridge.Name" "Color Bar Generator (1984) (VideoSoft)" "" "Cartridge.MD5" "8a183b6357987db5170c5cf9f4a113e5" "Cartridge.Manufacturer" "Atari, Joe Gaucher" "Cartridge.ModelNo" "CX2679" "Cartridge.Name" "RealSports Basketball (1983) (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "ee681f566aad6c07c61bbbfc66d74a27" "Cartridge.Manufacturer" "Activision" "Cartridge.Name" "Unknown Activision Game #1 (10-29-1982) (Activision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "cfdb4d0427a1ea8085c6bc6eb90259d8" "Cartridge.Name" "Gunfight 2600 - Release Candidate (2001) (MP)" "" "Cartridge.MD5" "874c76726f68c166fcfac48ce78eef95" "Cartridge.Name" "Red Pong Number 2 Demo (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4a45c6d75b1ba131f94a9c13194d8e46" "Cartridge.Name" "How to Draw a Playfield II (Joystick Hack) (1997) (Eric Bacher) (PD)" "" "Cartridge.MD5" "5a9685c4d51a6c1d6a9544946d9e8dc3" "Cartridge.Manufacturer" "AtariAge" "Cartridge.Name" "Grandma's Revenge (AtariAge)" "Cartridge.Note" "Can use driving controller in right port" "" "Cartridge.MD5" "aab840db22075aa0f6a6b83a597f8890" "Cartridge.Manufacturer" "Home Vision - Gem International Corp. - R.J.P.G." "Cartridge.ModelNo" "VCS83124" "Cartridge.Name" "Racing Car (1983) (Home Vision) (PAL)" "Console.SwapPorts" "YES" "" "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" "442b7863683e5f084716fda050474feb" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Frame Timed Sound Effects-EM (Eckhard Stolberg)" "Cartridge.Rarity" "New Release" "" "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" "5f9b62350b31be8bd270d9a241cbd50e" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "5658 A088" "Cartridge.Name" "Football (1989) (Telegames) (PAL)" "Cartridge.Note" "AKA Super Challenge Football" "" "Cartridge.MD5" "72d0acb5de0db662de0360a6fc59334d" "Cartridge.Name" "Cosmic Ark (Unknown) (PAL)" "" "Cartridge.MD5" "543b4b8ff1d616fa250c648be428a75c" "Cartridge.Manufacturer" "Warren Robinett" "Cartridge.Name" "Adventure (1978) (Warren Robinett) (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "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" "9afdfe1cff7f37f1c971fe3f0c900606" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Plug Attack (Funvision)" "Cartridge.Note" "AKA Plaque Attack" "" "Cartridge.MD5" "5b574faa56836da0866ba32ae32547f2" "Cartridge.Name" "Tomb Raider 2600 [REV 03] (Montezuma's Revenge Hack)" "" "Cartridge.MD5" "1c85c0fc480bbd69dc301591b6ecb422" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Super Box (CCE)" "Cartridge.Note" "AKA RealSports Boxing" "" "Cartridge.MD5" "cef2287d5fd80216b2200fb2ef1adfa8" "Cartridge.Manufacturer" "Milton Bradley Company" "Cartridge.ModelNo" "4363" "Cartridge.Name" "Spitfire Attack (1983) (Milton Bradley)" "Cartridge.Note" "AKA Flight Commander)" "Display.YStart" "28" "" "Cartridge.MD5" "e1143b72a30d4d3fee385eec38b4aa4d" "Cartridge.Name" "Word Zapper (Unknown)" "" "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" "801ba40f3290fc413e8c816c467c765c" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - Westward Ho! (2001) (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "97d079315c09796ff6d95a06e4b70171" "Cartridge.Manufacturer" "Activision, Garry Kitchen" "Cartridge.ModelNo" "AZ-032" "Cartridge.Name" "Pressure Cooker (1983) (Activision)" "" "Cartridge.MD5" "5df559a36347d8572f9a6e8075a31322" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Enduro (Digivision)" "" "Cartridge.MD5" "13584411da0a8d431991035423fdc0dc" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Skiing (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "6f74ed915ffe73b524ef0f63819e2a1d" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "An Exercise In Minimalism (V2) (1999) (Eckhard Stolberg)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "cad982c9b45bc5eff34e4ea982d5f1ca" "Cartridge.Name" "Song (17-02-2003) (Paul Slocum)" "Display.Phosphor" "YES" "" "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" "Display.YStart" "31" "" "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" "43adf60ebdd6b5a0fae21594ecf17154" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Stampede (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "f2f2cb35fdef063c966c1f5481050ea2" "Cartridge.Name" "Ram It (Unknown) (PAL)" "" "Cartridge.MD5" "02e3f4ba156fb578bef7d7a0bf3400c1" "Cartridge.Name" "Booster (Junkosoft) (PD)" "" "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" "adfbd2e8a38f96e03751717f7422851d" "Cartridge.Manufacturer" "Champ Games" "Cartridge.Name" "Lady Bug (NTSC)" "Cartridge.Rarity" "Homebrew" "Console.RightDifficulty" "A" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6fac680fc9a72e0e54255567c72afe34" "Cartridge.Name" "Superman (Unknown) (PAL)" "" "Cartridge.MD5" "78297db7f416af3052dd793b53ff014e" "Cartridge.Name" "Poker Squares (V0.17) (2001) (B. Watson)" "" "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" "c1b038ce5cb6d85e956c5509b0e0d0d8" "Cartridge.Name" "Rotating Colors Demo 2 (Junkosoft) (PD)" "" "Cartridge.MD5" "619de46281eb2e0adbb98255732483b4" "Cartridge.Name" "Time Warp (Unknown)" "Display.YStart" "20" "" "Cartridge.MD5" "b5110f55ed99d5279f18266d001a8cd5" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Auto-mobile Demo (2001) (Eckhard Stolberg)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "93c8d9d24f9c5f1f570694848d087df7" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Galaxian (Digivision)" "" "Cartridge.MD5" "24b5f4bbdb853eca38ea0cae2dfe73a1" "Cartridge.Name" "Home Run (Unknown) (PAL) (4K)" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "f1554569321dc933c87981cf5c239c43" "Cartridge.Manufacturer" "Atari, Glenn Axworthy" "Cartridge.ModelNo" "CX26129" "Cartridge.Name" "Midnight Magic (1984) (Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ab2ea35dcc1098c87455bb8210b018cf" "Cartridge.Name" "Fu Kung! (V0.04 Single Line Resolution) (10-01-2003) (AD)" "" "Cartridge.MD5" "72ffbef6504b75e69ee1045af9075f66" "Cartridge.Manufacturer" "Atari, Richard Maurer - Sears" "Cartridge.ModelNo" "CX2632 - 49-75153" "Cartridge.Name" "Space Invaders (1980) (Atari)" "" "Cartridge.MD5" "1b8d35d93697450ea26ebf7ff17bd4d1" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "176.764 9 - 781644" "Cartridge.Name" "Marineflieger (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Seahawk" "" "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" "cca33ae30a58f39e3fc5d80f94dc0362" "Cartridge.Name" "Okie Dokie (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "2327456f86d7e0deda94758c518d05b3" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Mr. Postman (Digitel)" "" "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" "" "Cartridge.MD5" "b897f9e3f939b9f21566d56db812a84e" "Cartridge.Manufacturer" "Atari, Jim Huether" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Flag Capture (32 in 1) (1988) (Atari) (PAL) (4K)" "" "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" "04014d563b094e79ac8974366f616308" "Cartridge.Manufacturer" "Atari, Andrew Fuchs, Courtney Granner, Jeffrey Gusman, Mark R. Hahn" "Cartridge.ModelNo" "CX2690" "Cartridge.Name" "Pengo (1984) (Atari)" "" "Cartridge.MD5" "e957eb4612d6bd5940d3492dfa749668" "Cartridge.Name" "Tunnel Demo (27-03-2003) (CT)" "" "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" "84535afb9a69712ec0af4947329e08b8" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-868" "Cartridge.Name" "Bingo (1983) (CCE) (PAL)" "Cartridge.Note" "AKA Dice Puzzle" "" "Cartridge.MD5" "98fa3ad778a668a79449350de4b3b95b" "Cartridge.Name" "Thrust (V1.1) (2000) (TJ)" "" "Cartridge.MD5" "fe870018332a0221eb59fb18b0c6bccc" "Cartridge.Name" "Incoming (08-11-2002) (Ben Larson) (PD)" "" "Cartridge.MD5" "8a9d874a38608964f33ec0c35cab618d" "Cartridge.Manufacturer" "Chris Cracknell" "Cartridge.Name" "Rescue Bira Bira (Chris Cracknell)" "Cartridge.Note" "Hack of Jungle Fever" "Cartridge.Rarity" "Hack" "Display.YStart" "20" "Display.Height" "230" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a4b99aa5ed85cfdb7d101923147de035" "Cartridge.Manufacturer" "Jim Goebel" "Cartridge.Name" "Pac-Law (Jim Goebel) (Hack)" "Cartridge.Note" "Hack of Outlaw" "Cartridge.Rarity" "Hack" "" "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.YStart" "28" "Display.Phosphor" "YES" "" "Cartridge.MD5" "60a61da9b2f43dd7e13a5093ec41a53d" "Cartridge.Manufacturer" "VentureVision, Dan Oliver" "Cartridge.ModelNo" "VV2001" "Cartridge.Name" "Rescue Terra I (1982) (VentureVision)" "" "Cartridge.MD5" "cc12581e079cd18330a89902625b8347" "Cartridge.Manufacturer" "Dave Neuman" "Cartridge.Name" "Space Battle (PAL)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "38bd172da8b2a3a176e517c213fcd5a6" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "MA017600" "Cartridge.Name" "Diagnostic Test Cartridge 2.6 (1982) (Atari)" "" "Cartridge.MD5" "6604f72a966ca6b2df6a94ee4a68eb82" "Cartridge.Name" "MegaMania (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "9f93734c68f6479eb022cab40814142e" "Cartridge.Name" "Push (V0.07) (2001) (AD)" "" "Cartridge.MD5" "15bcd74f2f1f2a63e1aa93e90d2c0555" "Cartridge.Name" "Incoming (22-08-2002) (Ben Larson) (PD)" "" "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" "9222b25a0875022b412e8da37e7f6887" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "106" "Cartridge.Name" "Dice Puzzle (1983) (Panda)" "Display.YStart" "30" "Display.Phosphor" "YES" "" "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" "bda1463e02ae3a6e1107ffe1b572efd2" "Cartridge.Manufacturer" "Atari, Nick 'Sandy Maiwald' Turner" "Cartridge.ModelNo" "CX26111" "Cartridge.Name" "Snoopy and the Red Baron (1983) (Atari) (PAL) [a]" "" "Cartridge.MD5" "7fcd1766de75c614a3ccc31b25dd5b7a" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "203" "Cartridge.Name" "Knight on the Town (1982) (PlayAround)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f2d40c70cf3e1d03bc112796315888d9" "Cartridge.Manufacturer" "Atari, Michael Callahan, Preston Stuart" "Cartridge.ModelNo" "CX26103" "Cartridge.Name" "Alpha Beam with Ernie (1983) (Atari) (PAL)" "Cartridge.Rarity" "Rare" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "d25018349c544320bf3fd5092ee072bc" "Cartridge.Manufacturer" "Activision, Larry Miller" "Cartridge.ModelNo" "AX-021" "Cartridge.Name" "Spider Fighter (1983) (Activision) (8K)" "Display.YStart" "30" "" "Cartridge.MD5" "70d14c66c319683b4c19abbe0e3db57c" "Cartridge.Name" "Oystron (V2.82) (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "936f555b4b1a2cd061b659ff63f4f5f2" "Cartridge.Manufacturer" "HES, David Lubar" "Cartridge.ModelNo" "535" "Cartridge.Name" "My Golf (1990) (HES) (PAL) [a1]" "" "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" "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" "" "Cartridge.MD5" "c1f209d80f0624dada5866ce05dd3399" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Deadly Discs (1989) (Telegames) (PAL)" "Cartridge.Note" "AKA TRON - Deadly Discs" "" "Cartridge.MD5" "b4030c38a720dd84b84178b6ce1fc749" "Cartridge.Manufacturer" "M Network, Kevin Miller" "Cartridge.ModelNo" "MT5687" "Cartridge.Name" "International Soccer (1982) (M Network)" "" "Cartridge.MD5" "07f42847a79e4f5ae55cc03304b18c25" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Sea Hawk (Zellers)" "Cartridge.Note" "AKA Seahawk" "" "Cartridge.MD5" "2880c6b59bd54b153174676e465167c7" "Cartridge.Manufacturer" "Tron" "Cartridge.Name" "Donkey Kong Jr. (Tron)" "Cartridge.Note" "AKA Donkey Kong Junior" "" "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" "7d93071b3e3616093a6b5a98b0315751" "Cartridge.Name" "Gunfight 2600 - Music & Bugfixes 2 (2001) (MP)" "" "Cartridge.MD5" "4c030667d07d1438f0e5c458a90978d8" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.03) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c9e721eb29c940c2e743485b044c0a3f" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "35fa32256982774a4f134c3347882dff" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.05) (Macintosh) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9d522a3759aa855668e75962c84546f7" "Cartridge.Manufacturer" "Atari, Tom Rudadahl" "Cartridge.ModelNo" "CX2634, CX2634P" "Cartridge.Name" "Golf (1980) (Atari) (PAL)" "" "Cartridge.MD5" "75ee371ccfc4f43e7d9b8f24e1266b55" "Cartridge.Manufacturer" "Atari, Greg Easter, Mimi Nyden" "Cartridge.ModelNo" "CX26107" "Cartridge.Name" "Snow White and the Seven Dwarfs (11-09-1982) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "e1a51690792838c5c687da80cd764d78" "Cartridge.Manufacturer" "20th Century Fox, John Russell" "Cartridge.Name" "Alligator People (1983) (20th Century Fox) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "110ac8ecaf1b69f41bc94c59dfcb8b2d" "Cartridge.Name" "Demon Attack (Unknown)" "" "Cartridge.MD5" "457e7d4fcd56ebc47f5925dbea3ee427" "Cartridge.Manufacturer" "Carrere Video, Garry Kitchen - Teldec" "Cartridge.ModelNo" "USC1001" "Cartridge.Name" "Space Jockey (1983) (Carrere Video) (PAL)" "Display.YStart" "59" "" "Cartridge.MD5" "4a6be79310f86f0bebc7dfcba4d74161" "Cartridge.Name" "Demolition Herby (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b56264f738b2eb2c8f7cf5a2a75e5fdc" "Cartridge.Manufacturer" "Atari - GCC, Betty Ryan Tylko, Douglas B. Macrae" "Cartridge.ModelNo" "CX2694, CX2694P" "Cartridge.Name" "Pole Position (1983) (Atari) (PAL)" "" "Cartridge.MD5" "ece463abde92e8b89bcd867ec71751b8" "Cartridge.Manufacturer" "Puzzy - Bit Corporation" "Cartridge.ModelNo" "PG205" "Cartridge.Name" "Dancing Plate (1982) (Puzzy) (PAL)" "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" "acb6787b938079f4e74313a905ec3ceb" "Cartridge.Name" "Chronocolor Donkey Kong (PD)" "" "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" "512e874a240731d7378586a05f28aec6" "Cartridge.Manufacturer" "Tigervision, Rorke Weigandt - Teldec" "Cartridge.ModelNo" "7-005" "Cartridge.Name" "Marauder (1982) (Tigervision) (PAL)" "" "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" "" "Cartridge.MD5" "ef66af190840871409fe1702d2483554" "Cartridge.Manufacturer" "Andrew Davie, Paul Slocum, Christopher Tumber" "Cartridge.Name" "DiscoTech (12-02-2003) (Andrew Davie)" "" "Cartridge.MD5" "4fae08027365d31c558e400b687adf21" "Cartridge.Name" "Qb (V2.17) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "88d8a1accab58cf1abb043613cf185e9" "Cartridge.Manufacturer" "Ultravison" "Cartridge.Name" "Sabotage (Ultravison)" "" "Cartridge.MD5" "18bebbbd41c234f82b1717b1905e6027" "Cartridge.Name" "Space Instigators (Public Release) (02-01-2003) (CT)" "" "Cartridge.MD5" "89a68746eff7f266bbf08de2483abe55" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Steve Woita" "Cartridge.ModelNo" "CX2696" "Cartridge.Name" "Asterix (1983) (Atari)" "Cartridge.Note" "AKA Taz" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "18a970bea7ac4d29707c8d5cd559d03a" "Cartridge.Name" "Bridge (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "2319922df4d0c820b3e5f15faa870cc3" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein" "Cartridge.ModelNo" "CX2681, CX2681P" "Cartridge.Name" "Battlezone (1983) (Atari) (PAL) [a]" "" "Cartridge.MD5" "cd88ef1736497288c4533bcca339f881" "Cartridge.Manufacturer" "Sega - Teldec" "Cartridge.ModelNo" "005-01" "Cartridge.Name" "Buck Rogers - Planet of Zoom (1983) (Sega) (PAL)" "Display.Format" "PAL" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9b150a42fc788960fbb4cbe250259ee2" "Cartridge.Manufacturer" "Kroko" "Cartridge.Name" "3E Bankswitch Test (TIA @ $40)" "" "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" "3b040ed7d1ef8acb4efdeebebdaa2052" "Cartridge.Manufacturer" "Tigervision" "Cartridge.ModelNo" "7-008" "Cartridge.Name" "Miner 2049er (1982) (Tigervision) [fixed]" "Display.YStart" "31" "" "Cartridge.MD5" "dbb10b904242fcfb8428f372e00c01af" "Cartridge.Manufacturer" "Atari, John Dunn" "Cartridge.ModelNo" "CX2631, CX2631P" "Cartridge.Name" "Superman (1979) (Atari) (PAL)" "" "Cartridge.MD5" "931b91a8ea2d39fe4dca1a23832b591a" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-008" "Cartridge.Name" "Laser Blast (1981) (Activision)" "" "Cartridge.MD5" "318046ae3711c05fd16e479b298e5fcc" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.08) (Stella) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "713fde2af865b6ec464dfd72e2ebb83e" "Cartridge.Name" "Challenge (208 in 1) (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "28148a52b1955ce12c7a74d3a3e620a4" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Freeway (CCE) (4K)" "" "Cartridge.MD5" "589c73bbcd77db798cb92a992b4c06c3" "Cartridge.Manufacturer" "Xonox - K-Tel Software, John Perkins" "Cartridge.ModelNo" "6230, 7210, 06004, 99004" "Cartridge.Name" "Artillery Duel (1983) (Xonox) (PAL)" "Display.YStart" "20" "" "Cartridge.MD5" "869abe0426e6e9fcb6d75a3c2d6e05d1" "Cartridge.Name" "Stampede (Unknown) (PAL)" "" "Cartridge.MD5" "106326c262dfd3e8eaeabd961d2a0519" "Cartridge.Name" "PAL-NTSC Detector (15-11-2002) (CT)[a1]" "" "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" "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" "cc724ebe74a109e39c0b2784ddc980ca" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Dave Staugas" "Cartridge.ModelNo" "CX2682" "Cartridge.Name" "Krull (05-27-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "6a882fb1413912d2ce5cf5fa62cf3875" "Cartridge.Manufacturer" "Video Game Cartridge - Ariola" "Cartridge.ModelNo" "TP-605" "Cartridge.Name" "Dragon Defender (Ariola) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "45a095645696a217e416e4bd2baea723" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Snoopy (Digivision)" "Cartridge.Note" "AKA Snoopy and the Red Baron" "" "Cartridge.MD5" "25710bde8fa181b0c5cf0846b983bec1" "Cartridge.Name" "Demo Image Series #15 - Three Marios (NTSC) (06-03-2003) (AD)" "" "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" "f80cf77164079d774b9b0fae33dffca9" "Cartridge.Name" "Fu Kung! (V0.15) (Negative Version) (05-02-2003) (AD)" "" "Cartridge.MD5" "57a66b6db7efc5df17b0b0f2f2c2f078" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.08) (NTSC) (2001) (Retroactive)" "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" "16f494f20af5dc803bc35939ef924020" "Cartridge.Manufacturer" "Mark De Smet" "Cartridge.Name" "Video Simon (Mark De Smet)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "e74022cfe31ec8908844718dfbdedf7a" "Cartridge.Name" "Space Treat (30-12-2002) (Fabrizio Zavagli) [a2]" "" "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" "6aa66e9c3eea76a0c40ef05513497c40" "Cartridge.Name" "Hangman Ghost Biglist2 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "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" "678c1d71a1616d9d022f03d8545b64bb" "Cartridge.Name" "Demo Image Series #11 - Donald And Mario (28-02-2003) (AD)" "" "Cartridge.MD5" "d62d7d1a974c31c5803f96a8c1552510" "Cartridge.Name" "StarMaster (Unknown) (PAL)" "Cartridge.Note" "Use Color/BW switch to change between galactic chart and front views" "" "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" "b1c14b5ac896400cc91c8e5dd67acb59" "Cartridge.Name" "River Raid (208 in 1) (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "9281eccd7f6ef4b3ebdcfd2204c9763a" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.15) (Retroactive) (PAL)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "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" "ab10f2974dee73dab4579f0cab35fca6" "Cartridge.Manufacturer" "ITT Family Games" "Cartridge.Name" "Wilma Wanderer (1983) (ITT Family Games) (PAL)" "Cartridge.Note" "AKA Lilly Adventure" "" "Cartridge.MD5" "76ee917d817ef9a654bc4783e0273ac4" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "311377" "Cartridge.Name" "Fox & Goat (Double-Game Package) (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Nuts" "" "Cartridge.MD5" "991d57bbcd529ad62925098e0aec1241" "Cartridge.Name" "Gunfight 2600 - The Final Kernel (MP) [a1]" "" "Cartridge.MD5" "b451307b8b5e29f1c5f2cf064f6c7227" "Cartridge.Name" "Demo Image Series #6 - Mario (Fixed) (26-02-2003) (AD)" "" "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" "651d2b6743a3a18b426bce2c881af212" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-812" "Cartridge.Name" "Pac Man (1983) (CCE) [a]" "Display.YStart" "33" "" "Cartridge.MD5" "0b17ed42984000da8b727ca46143f87a" "Cartridge.Manufacturer" "Atari, Christopher H. Omarzu - Children's Computer Workshop" "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" "525f2dfc8b21b0186cff2568e0509bfc" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-930-04, AZ-030" "Cartridge.Name" "Decathlon (1983) (Activision) [fixed]" "" "Cartridge.MD5" "4cd796b5911ed3f1062e805a3df33d98" "Cartridge.Manufacturer" "Tigervision" "Cartridge.ModelNo" "7-006" "Cartridge.Name" "Springer (1982) (Tigervision)" "" "Cartridge.MD5" "9c7fa3cfcaaafb4e6daf1e2517d43d88" "Cartridge.Name" "PIEROXM Demo (PD)" "" "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" "c74bfd02c7f1877bbe712c1da5c4c194" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "River Raid Tanks (Thomas Jentzsch) (Hack)" "Cartridge.Note" "Hack of River Raid" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "d0e15a3ce322c5af60f07343594392af" "Cartridge.Manufacturer" "Amiga" "Cartridge.ModelNo" "3125" "Cartridge.Name" "Surf's Up (1983) (Amiga) (Prototype) (4K)" "Cartridge.Note" "Uses the Joyboard controller" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "755fed16b48e81de05130708a905d00d" "Cartridge.Manufacturer" "SnailSoft" "Cartridge.Name" "Comitoid beta 3 (SnailSoft)" "" "Cartridge.MD5" "8530caaaf40acbdcd118c282b5f8a37a" "Cartridge.Name" "This Planet Sucks Demo 2 (Greg Troutman) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "74ca9bdc91ee387a5bd929b73aec5c2c" "Cartridge.Name" "Star Fire - New Shields (03-04-2003) (MP)" "" "Cartridge.MD5" "5e0c37f534ab5ccc4661768e2ddf0162" "Cartridge.Manufacturer" "Telegames, Ed Salvo" "Cartridge.ModelNo" "5667 A106" "Cartridge.Name" "Glacier Patrol (1989) (Telegames)" "" "Cartridge.MD5" "24544ee5d76f579992d9522e9b238955" "Cartridge.Manufacturer" "Carrere Video, Tom Sloper - Teldec" "Cartridge.ModelNo" "USC2004" "Cartridge.Name" "Picnic (1983) (Carrere Video) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "" "Cartridge.MD5" "2ca6445204ffb7686ddee3e33ba64d5b" "Cartridge.Manufacturer" "Alex Herbert" "Cartridge.Name" "AtariVox Test ROM" "Cartridge.Note" "Uses the AtariVox controller" "Controller.Right" "ATARIVOX" "" "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" "378a62af6e9c12a760795ff4fc939656" "Cartridge.Manufacturer" "Atari - Axlon, Steve DeFrisco" "Cartridge.ModelNo" "CX26171" "Cartridge.Name" "MotoRodeo (1990) (Atari)" "Display.Phosphor" "YES" "" "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" "46c43fdcbce8fde3a91ebeafc05b7cbd" "Cartridge.Name" "Invaders Demo (PAL) (2001) (Eckhard Stolberg)" "" "Cartridge.MD5" "d078d25873c5b99f78fa267245a2af02" "Cartridge.Manufacturer" "Sega, Steve Beck, Phat Ho - Beck-Tech" "Cartridge.ModelNo" "006-01" "Cartridge.Name" "Congo Bongo (1983) (Sega) [a]" "Display.YStart" "36" "" "Cartridge.MD5" "8490e1014c2baa0d3a3a08854e5d68b3" "Cartridge.Manufacturer" "Xonox, Anthony R. Henderson" "Cartridge.ModelNo" "99006, 6220" "Cartridge.Name" "Sir Lancelot (1983) (Xonox) [a2]" "" "Cartridge.MD5" "cd8fa2e9f6255ef3d3b9b5a4f24a54f7" "Cartridge.Name" "Daredevil (V2) (Stunt_Cycle_Rules!) (PD)" "" "Cartridge.MD5" "91d1c82ceaf8af2add3973a3c34bc0cb" "Cartridge.Name" "Starfield Demo 1 (20-12-2002) (CT)" "" "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" "d1a9478b99d6a55e13a9fd4262da7cd4" "Cartridge.Manufacturer" "U.S. Games Corporation, Garry Kitchen - Vidtec" "Cartridge.ModelNo" "VC1001" "Cartridge.Name" "Space Jockey (1982) (U.S. Games) (4K)" "" "Cartridge.MD5" "7187118674ff3c0bb932e049d9dbb379" "Cartridge.Manufacturer" "Zirok" "Cartridge.Name" "Keystone Keypers (1983) (Zirok)" "Cartridge.Note" "AKA Keystone Kapers" "" "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" "Display.YStart" "24" "" "Cartridge.MD5" "7bc4fd254ec8c0a25a13f02fd3f762ff" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V1.00) (Stella) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "693137592a7f5ccc9baae2d1041b7a85" "Cartridge.Name" "Qb (V2.02) (Stella) (2001) (Retroactive) [a1]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ba3b0eebccc7b791107de5b4abb671b4" "Cartridge.Name" "Thrust (V0.9) (2000) (TJ)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "98e5e4d5c4dd9a986d30fd62bd2f75ae" "Cartridge.Name" "Air-Sea Battle (Unknown) (Hack) (4K)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "675ae9c23fa1aae376cea86cad96f9a5" "Cartridge.Name" "Poker Squares (V0.25) (2001) (B. Watson)" "" "Cartridge.MD5" "8f33bce5ba1053dcf4cea9c1c69981e4" "Cartridge.Name" "Jawbreaker (Unknown) (PAL) [a]" "" "Cartridge.MD5" "ea7e25ade3fe68f5b786ee0aa82b1fe5" "Cartridge.Name" "Galatic (208 in 1) (Unknown) (PAL)" "Cartridge.Note" "AKA Challenge of.... Nexar, The" "" "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" "cc7138202cd8f6776212ebfc3a820ecc" "Cartridge.Manufacturer" "Atari, 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" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "6205855cc848d1f6c4551391b9bfa279" "Cartridge.Name" "Euchre (Release Candidate 2) (NTSC) (01-10-2002) (Erik Eid)" "" "Cartridge.MD5" "1733772165d7b886a94e2b4ed0f74ccd" "Cartridge.Name" "Boring Journey Escape (Hack)" "Cartridge.Note" "Hack of Journey - Escape" "Cartridge.Rarity" "Hack" "Display.Height" "230" "" "Cartridge.MD5" "4baada22435320d185c95b7dd2bcdb24" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Dave Staugas" "Cartridge.ModelNo" "CX2682" "Cartridge.Name" "Krull (1983) (Atari)" "" "Cartridge.MD5" "0614ed51acd027d531e7c85c4f435292" "Cartridge.Name" "Narnia (Glenn Saunders) (PD)" "" "Cartridge.MD5" "d49aff83f77a1b9041ad7185df3c2277" "Cartridge.Name" "Space Treat (60% complete) (PD)" "" "Cartridge.MD5" "35ae903dff7389755ad4a07f2fb7400c" "Cartridge.Name" "Colored Wall Demo (PD)" "" "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" "340f546d59e72fb358c49ac2ca8482bb" "Cartridge.Manufacturer" "Sancho - Tang's Electronic Co." "Cartridge.ModelNo" "TEC003" "Cartridge.Name" "Skindiver (1983) (Sancho) (PAL)" "Display.YStart" "39" "" "Cartridge.MD5" "866e5150c995c4ae5172e5207ba948c7" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Stampede (Canal 3) (16K)" "" "Cartridge.MD5" "59b70658f9dd0e2075770b07be1a35cf" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Surfer's Paradise (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "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" "90ccf4f30a5ad8c801090b388ddd5613" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (1982) (Arcadia)" "" "Cartridge.MD5" "c1cb228470a87beb5f36e90ac745da26" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AX-015, AX-015-04" "Cartridge.Name" "Chopper Command (1982) (Activision)" "" "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" "a94528ae05dd051894e945d4d2349b3b" "Cartridge.Manufacturer" "Genus" "Cartridge.Name" "River Raid (Genus)" "" "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" "Display.YStart" "24" "" "Cartridge.MD5" "35be55426c1fec32dfb503b4f0651572" "Cartridge.Manufacturer" "Men-A-Vision" "Cartridge.Name" "Air Raid (Men-A-Vision) (PAL)" "Cartridge.Rarity" "Extremely Rare" "Display.Format" "NTSC50" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3f251c50aa7237e61a38ab42315ebed4" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Ikari Warriors (1990) (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "ba3a17efd26db8b4f09c0cf7afdf84d1" "Cartridge.Manufacturer" "Activision, Larry Miller" "Cartridge.ModelNo" "AX-021" "Cartridge.Name" "Spider Fighter (1983) (Activision) (16K)" "Display.YStart" "30" "" "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" "b00a8bc9d7fe7080980a514005cbad13" "Cartridge.Manufacturer" "K-Tel Vision" "Cartridge.Name" "Vulture Attack (1982) (K-Tel Vision) (PAL)" "Cartridge.Note" "AKA Condor Attack" "" "Cartridge.MD5" "c3bbc673acf2701b5275e85d9372facf" "Cartridge.Manufacturer" "Atari, Robert C. Polaro" "Cartridge.ModelNo" "CX26157" "Cartridge.Name" "Stunt Cycle (07-21-1980) (Atari) (Prototype)" "" "Cartridge.MD5" "fbe554aa8f759226d251ba6b64a9cce4" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein" "Cartridge.ModelNo" "CX2681, CX2681P" "Cartridge.Name" "Battlezone (1983) (Atari) (PAL)" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "798b8921276eec9e332dfcb47a2dbb17" "Cartridge.Manufacturer" "Atari, 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" "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" "14163eb2a3ddd35576bd8527eae3b45e" "Cartridge.Name" "Multi-Color Demo 6 (Bob Colbert) (PD)" "" "Cartridge.MD5" "dac5c0fe74531f077c105b396874a9f1" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2680" "Cartridge.Name" "RealSports Tennis (1983) (Atari)" "" "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" "6847ce70819b74febcfd03e99610243b" "Cartridge.Name" "Ruby Runner 4A50" "" "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" "65917ae29a8c9785bb1f2acb0d6aafd0" "Cartridge.Name" "Junkosoft One Year Demo (1999) (PD)" "" "Cartridge.MD5" "f8ff34b53d86f55bd52d7a520af6d1dc" "Cartridge.Name" "Big Dig (04-04-2003) (CT)" "" "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" "1267e3c6ca951ff1df6f222c8f813d97" "Cartridge.Name" "Dragonfire (Unknown) (PAL)" "" "Cartridge.MD5" "ad7e97c19bd25d5aa3999430845c755b" "Cartridge.Name" "Sprite Demo 5 (PD)" "" "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" "eb634650c3912132092b7aee540bbce3" "Cartridge.Manufacturer" "Atari, Eric Manghise, Joseph Tung" "Cartridge.ModelNo" "CX2640" "Cartridge.Name" "RealSports Baseball (1982) (Atari)" "Display.YStart" "26" "Display.Phosphor" "YES" "" "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" "" "Cartridge.MD5" "7732e4e4cc2644f163d6650ddcc9d9df" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "771-333" "Cartridge.Name" "2 Pak Special - Challenge, Surfing (1990) (HES) (PAL)" "" "Cartridge.MD5" "10eae73a07b3da044b72473d8d366267" "Cartridge.Manufacturer" "Funvision - Fund. Int'l Co." "Cartridge.Name" "Karate (1982) (Funvision) (PAL)" "" "Cartridge.MD5" "5c0520c00163915a4336e481ca4e7ef4" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "262.794 1" "Cartridge.Name" "Wuestenschlacht (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Chopper Command" "" "Cartridge.MD5" "3eccf9f363f5c5de0c8b174a535dc83b" "Cartridge.Name" "Plaque Attack (Unknown) (PAL)" "Cartridge.Rarity" "Rare" "" "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" "c2c7a11717e255593e54d0acaf653ee5" "Cartridge.Name" "Chopper Command (208 in 1) (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "68feb6d6ff63e80df1302d8547979aec" "Cartridge.Name" "Starfield Demo 2 (20-12-2002) (CT)" "" "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" "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" "e39a13b13dc82c5fdbfbbfd55ba1230e" "Cartridge.Name" "Analog Clock (Additional Frame Info) (V0.0) (20-01-2003) (AD)" "" "Cartridge.MD5" "4543b7691914dfd69c3755a5287a95e1" "Cartridge.Manufacturer" "CommaVid, Irwin Gaines" "Cartridge.ModelNo" "CM-005" "Cartridge.Name" "Mines of Minos (1982) (CommaVid)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5dccf215fdb9bbf5d4a6d0139e5e8bcb" "Cartridge.Manufacturer" "Froggo" "Cartridge.ModelNo" "FG1009" "Cartridge.Name" "Sea Hunt (1987) (Froggo)" "Cartridge.Note" "AKA Skindiver" "" "Cartridge.MD5" "a4790224bd5afabd53cbe93e46a7f241" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-019" "Cartridge.Name" "Sky Jinks (1982) (Activision) (8K)" "" "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" "30" "" "Cartridge.MD5" "7edc8fcb319b3fb61cac87614afd4ffa" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AG-003" "Cartridge.Name" "Checkers (1980) (Activision) (4K)" "" "Cartridge.MD5" "e4c666ca0c36928b95b13d33474dbb44" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Hales, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4102" "Cartridge.Name" "Suicide Mission (1982) (Arcadia)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "eb3d680699f8762f71f38e28e321234d" "Cartridge.Name" "Fu Kung! (V0.01) (08-01-2003) (AD)" "" "Cartridge.MD5" "c504a71c411a601d1fc3173369cfdca4" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.02) (Stella) (2001) (Retroactive)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4c39a2c97917d3d71739b3e21f60bba5" "Cartridge.Name" "Whale (Sub Scan Hack)" "" "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" "Display.YStart" "30" "" "Cartridge.MD5" "f0631c6675033428238408885d7e4fde" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "Test Cart (2002) (Paul Slocum)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f9677b2ec8728a703eb710274474613d" "Cartridge.Manufacturer" "Atari, Ian Shepard" "Cartridge.ModelNo" "CX2604, CX2604P" "Cartridge.Name" "Space War (1978) (Atari) (PAL)" "" "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" "6982854657a2cc87d712f718e402bf85" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Earth Attack (Zellers)" "Cartridge.Note" "AKA Defender" "" "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" "Display.YStart" "30" "" "Cartridge.MD5" "f7a138eed69665b5cd1bfa796a550b01" "Cartridge.Manufacturer" "Tigervision - Teldec" "Cartridge.ModelNo" "7-012 - 3.60016 VC" "Cartridge.Name" "Espial (1984) (Tigervision) (PAL)" "" "Cartridge.MD5" "1e89f722494608d6ea15a00d99f81337" "Cartridge.Name" "River Raid (Unknown) (PAL)" "Display.Format" "NTSC50" "" "Cartridge.MD5" "270229c6d5578446e6a588492e4e5910" "Cartridge.Name" "Space Invaders 2 (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "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" "18dc28bc22402f21e1c9b81344b3b8c5" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker" "Cartridge.ModelNo" "CX2684, CX2684P" "Cartridge.Name" "Galaxian (1983) (Atari) (PAL) [a1]" "" "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" "0443cfa9872cdb49069186413275fa21" "Cartridge.Manufacturer" "M Network, Patricia Lewis Du Long, Ron Surratt - INTV" "Cartridge.ModelNo" "MT4518" "Cartridge.Name" "BurgerTime (1983) (M Network)" "Display.YStart" "26" "" "Cartridge.MD5" "18d26111cef66dff0c8af8cf0e117843" "Cartridge.Name" "Tunnel Demo (Cycling Colours 2) (29-03-2003) (AD)" "" "Cartridge.MD5" "a8b3ea6836b99bea77c8f603cf1ea187" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-861" "Cartridge.Name" "Boxing (1983) (CCE)" "" "Cartridge.MD5" "a591b5e8587aae0d984a0f6fe2cc7d1c" "Cartridge.Name" "Globe Trotter Demo (24-03-2003) (Weston)" "" "Cartridge.MD5" "604e09724555807c28108049efe34a13" "Cartridge.Name" "Sokoban (01-01-2003) (Adam Wozniak)" "Display.YStart" "36" "" "Cartridge.MD5" "152c253478b009c275e18cd731b48561" "Cartridge.Name" "Quest (11-10-2002) (Chris Larkin)" "" "Cartridge.MD5" "4edb251f5f287c22efc64b3a2d095504" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "Atari VCS Point-of-Purchase ROM (1982) (Atari)" "" "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" "dfafa3fa58f5cc3f0342cca475df6095" "Cartridge.Name" "Space Treat (V1.1 Beta) (24-12-2002) (Fabrizio Zavagli)" "" "Cartridge.MD5" "0f95264089c99fc2a839a19872552004" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-009, AG-009-04" "Cartridge.Name" "Freeway (1981) (Activision) (8K)" "" "Cartridge.MD5" "7f9fbe3e00a21ea06e6ae5e0e5db2143" "Cartridge.Name" "Skate Boardin' (2002) (Skyworks)" "" "Cartridge.MD5" "9d0befa555f003069a21d2f6847ad962" "Cartridge.Manufacturer" "Atari - GCC, Dave Payne" "Cartridge.ModelNo" "CX2669" "Cartridge.Name" "Vanguard (1982) (Atari) (PAL) [a]" "" "Cartridge.MD5" "0f2e09c71cc216f79d22a804152ba24b" "Cartridge.Manufacturer" "Bob Colbert" "Cartridge.Name" "Scroller Demo (Bob Colbert) (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b06050f686c6b857d0df1b79fea47bb4" "Cartridge.Manufacturer" "Activision" "Cartridge.ModelNo" "AIZ-001" "Cartridge.Name" "Moonsweeper (1988) (Activision)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e01e00504e6d4b88fa743c0bbe8a96e5" "Cartridge.Name" "Qb (Special Edition, some bugfixes) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "20edcc3aa6c189259fa7e2f044a99c49" "Cartridge.Manufacturer" "Spectravision, Spectravideo" "Cartridge.ModelNo" "SA-201" "Cartridge.Name" "Gangster Alley (1982) (Spectravision)" "" "Cartridge.MD5" "310ba30e25ea8957e58180b663503c0c" "Cartridge.Manufacturer" "Ed Federmeyer" "Cartridge.Name" "Sound X6 (1994) (Ed Federmeyer)" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "e2ca84a2bb63d1a210ebb659929747a9" "Cartridge.Manufacturer" "Telesys, Don 'Donyo' Ruffcorn" "Cartridge.ModelNo" "1002" "Cartridge.Name" "Cosmic Creeps (1982) (Telesys) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f457674cef449cfd85f21db2b4f631a7" "Cartridge.Manufacturer" "U.S. Games Corporation, Wes Trager, Henry Will IV" "Cartridge.ModelNo" "VC1004" "Cartridge.Name" "Commando Raid (1982) (U.S. Games)" "" "Cartridge.MD5" "041b5e56bbc650db574bd8db3fae2696" "Cartridge.Name" "Thrust (V1.0) (2000) (TJ)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "1c6eb740d3c485766cade566abab8208" "Cartridge.Manufacturer" "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira" "Cartridge.ModelNo" "CX26110" "Cartridge.Name" "Crystal Castles (1984) (Atari)" "" "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" "f5a3e051730d45fea518f2e8b926565b" "Cartridge.Manufacturer" "Robby" "Cartridge.Name" "Keystone Kapers (Robby)" "" "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" "7cd379da92c93679f3b6d2548617746a" "Cartridge.Name" "Demo Image Series #5 - Clown (19-02-2003) (AD)" "" "Cartridge.MD5" "66fcf7643d554f5e15d4d06bab59fe70" "Cartridge.Manufacturer" "Coleco, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (09-13-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "ee28424af389a7f3672182009472500c" "Cartridge.Manufacturer" "Atari, Carol Shaw - Ralph Lauren" "Cartridge.Name" "Polo (1978) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "5f1b7d5fa73aa071ba0a3c2819511505" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Cosmic Commuter (CCE)" "" "Cartridge.MD5" "a4e885726af9d97b12bb5a36792eab63" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Beck-Tech" "Cartridge.ModelNo" "6210, 7210, 06003. 99001" "Cartridge.Name" "Spike's Peak (1983) (Xonox)" "Display.Height" "217" "" "Cartridge.MD5" "ec3beb6d8b5689e867bafb5d5f507491" "Cartridge.Manufacturer" "U.S. Games Corporation, Henry Will IV - Vidtec" "Cartridge.ModelNo" "VC1003" "Cartridge.Name" "Word Zapper (1982) (U.S. Games)" "Cartridge.Note" "AKA Word Grabber" "" "Cartridge.MD5" "1201c18cf00d2c236f42e4d7d8c86aa1" "Cartridge.Name" "Nick Bensema Demo (Nick Bensema)" "" "Cartridge.MD5" "c67ff409f28f44883bd5251cea79727d" "Cartridge.Name" "Gunfight 2600 - Music & Bugfixes 1 (2001) (MP)" "" "Cartridge.MD5" "b5a1a189601a785bdb2f02a424080412" "Cartridge.Manufacturer" "Imagic, Dennis Koble" "Cartridge.ModelNo" "720021-1A, IA3410" "Cartridge.Name" "Shootin' Gallery (1982) (Imagic)" "Display.YStart" "29" "" "Cartridge.MD5" "b40dea357d41c5408546e4e4d5f27779" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Spider Fighter (Digivision)" "Display.YStart" "30" "" "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" "13a991bc9c2ff03753aeb322d3e3e2e5" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Galactic (Funvision) (PAL)" "Cartridge.Note" "AKA Condor Attack" "" "Cartridge.MD5" "35b10a248a7e67493ec43aeb9743538c" "Cartridge.Manufacturer" "Dor-x" "Cartridge.Name" "Defender (Dor-x) (Hack)" "Cartridge.Note" "Hack of Defender" "" "Cartridge.MD5" "7a64a8b727c8215d945e37d565ca95a5" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.ModelNo" "CX2606" "Cartridge.Name" "Slot Racers (1978) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "524693b337f7ecc9e8b9126e04a232af" "Cartridge.Name" "Euchre (19-08-2001) (Eric Eid) (PD)" "" "Cartridge.MD5" "b00e8217633e870bf39d948662a52aac" "Cartridge.Manufacturer" "Konami" "Cartridge.ModelNo" "RC 102-X 02" "Cartridge.Name" "Marine Wars (1983) (Konami)" "" "Cartridge.MD5" "8f90590dba143d783df5a6cff2000e4d" "Cartridge.Name" "Gopher (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "2f7949f71076db42480d3f5036b4a332" "Cartridge.Name" "Name This Game (208 in 1) (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "17ba72433dd41383065d4aa6dedb3d91" "Cartridge.Name" "SCSIcide (09-06-2001) (Joe Grand)" "" "Cartridge.MD5" "67bd3d4dc5ac6a42a99950b4245bdc81" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.11) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ae83541cf4a4c0bce0adccd2c1bf6288" "Cartridge.Name" "Maze 003 Demo (PD)" "" "Cartridge.MD5" "f060826626aac9e0d8cda0282f4b7fc3" "Cartridge.Manufacturer" "Atari, David Crane - Sears" "Cartridge.ModelNo" "CX2605 - 6-99822, 49-75109" "Cartridge.Name" "Outlaw (1978) (Atari) (4K)" "" "Cartridge.MD5" "eddef10fdc0029301064115ae0cd41d4" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Freeway (CCE)" "" "Cartridge.MD5" "3aad0ef62885736a5b8c6ccac0dbe00c" "Cartridge.Manufacturer" "Dynacom" "Cartridge.Name" "Atlantis (1983) (Dynacom)" "" "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" "dba270850ae997969a18ee0001675821" "Cartridge.Manufacturer" "Greg Troutman" "Cartridge.Name" "Dark Mage (Greg Troutman) (PD) (4K)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "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" "ece908d77ab944f7bac84322b9973549" "Cartridge.Name" "Tom Boy (Unknown) (PAL60)" "Cartridge.Note" "AKA Pitfall!" "Display.Format" "PAL60" "Display.YStart" "24" "" "Cartridge.MD5" "18ed63e3ce5bc3dd2d8bd188b807f1a2" "Cartridge.Name" "Stell-A-Sketch (Bob Colbert) (PD) [a1]" "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" "38" "Display.Height" "256" "Display.Phosphor" "YES" "" "Cartridge.MD5" "24385ba7f5109fbe76aadc0a375de573" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Xevious (CCE)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "bb745c893999b0efc96ea9029e3c62ca" "Cartridge.Manufacturer" "Play Video" "Cartridge.Name" "Planet Patrol (1982) (Play Video) (PAL)" "" "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" "d078674afdf24a4547b4b32890fdc614" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Laser Blast (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "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" "956b99511c0f47b3a11d18e8b7ac8d47" "Cartridge.Name" "Bones (Arcade Golf Hack)" "" "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" "e0de3773f5b867795db557be7b8a703e" "Cartridge.Name" "Boulderdash (13 Blocks Wide) (02-04-2003) (AD)" "" "Cartridge.MD5" "e6de4ef9ab62e2196962aa6b0dedac59" "Cartridge.Manufacturer" "Imagic, Wilfredo 'Willy' 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" "" "Cartridge.MD5" "0b55399cf640a2a00ba72dd155a0c140" "Cartridge.Manufacturer" "Imagic, Wilfredo 'Willy' Aguilar, Michael Becker, Rob Fulop" "Cartridge.ModelNo" "720111-1A, 03205" "Cartridge.Name" "Fathom (1983) (Imagic)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4767356fa0ed3ebe21437b4473d4ee28" "Cartridge.Manufacturer" "Atari, Dan Hitchens" "Cartridge.ModelNo" "CX2685" "Cartridge.Name" "Gravitar (04-12-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "30" "" "Cartridge.MD5" "6c658b52d03e01828b9d2d4718a998ac" "Cartridge.Name" "Hangman Invader Biglist2 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "04fccc7735155a6c1373d453b110c640" "Cartridge.Manufacturer" "HES, David Lubar" "Cartridge.ModelNo" "535" "Cartridge.Name" "My Golf (1990) (HES) (PAL)" "" "Cartridge.MD5" "85502d69fe46b7f54ef2598225678b47" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Super-Ferrari (Jone Yuan)" "Cartridge.Note" "AKA Enduro" "" "Cartridge.MD5" "75e8d8b9e9c5c67c2226dbfd77dcfa7d" "Cartridge.Name" "2600 Digital Clock (V b1) (PD)" "" "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" "f1b7edff81ceef5af7ae1fa76c8590fc" "Cartridge.Manufacturer" "Atari, Richard Maurer" "Cartridge.ModelNo" "CX2632, CX2632P" "Cartridge.Name" "Space Invaders (1980) (Atari) (PAL)" "" "Cartridge.MD5" "5e99aa93d0acc741dcda8752c4e813ce" "Cartridge.Name" "2600 Digital Clock (V b2) (PD)" "" "Cartridge.MD5" "79004f84bdeee78d142e445057883169" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-830" "Cartridge.Name" "Planet Patrol (1983) (CCE)" "" "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" "" "Cartridge.MD5" "b1339c56a9ea63122232fe4328373ac5" "Cartridge.Manufacturer" "Goliath - Hot Shot" "Cartridge.ModelNo" "83-215" "Cartridge.Name" "Dream Flight (1983) (Goliath) (PAL)" "Cartridge.Note" "AKA Nightmare" "Display.YStart" "44" "Display.Height" "256" "" "Cartridge.MD5" "22319be7a640af5314ec3c482cceb676" "Cartridge.Name" "Joustpong (05-07-2002) (Kirk Israel) (PD)" "" "Cartridge.MD5" "9b246683f44c963a50e41d6b485bee77" "Cartridge.Name" "Boring (PAL) (AD)" "" "Cartridge.MD5" "e28113d10c0c14cc3b5f430b0d142fcb" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-816" "Cartridge.Name" "Keystone Kappers (1983) (CCE) [a]" "Cartridge.Note" "AKA Keystone Kapers" "" "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" "c41e7735f6701dd50e84ee71d3ed1d8f" "Cartridge.Manufacturer" "Dynacom" "Cartridge.Name" "Spider Fighter (1983) (Dynacom)" "Display.YStart" "30" "" "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" "dd10b5ee37fdbf909423f2998a1f3179" "Cartridge.Name" "Space Instigators (V1.9) (21-10-2002) (CT)" "" "Cartridge.MD5" "97842fe847e8eb71263d6f92f7e122bd" "Cartridge.Manufacturer" "Imagic, Wilfredo 'Willy' 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" "" "Cartridge.MD5" "02066b17f29082412c6754c1a2d6302e" "Cartridge.Name" "Demo Image Series #3 - Baboon (19-02-2003) (AD)" "" "Cartridge.MD5" "910dd9bf98cc5bc080943e5128b15bf5" "Cartridge.Name" "Gunfight 2600 - Improved AI (MP)" "" "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" "4cabc895ea546022c2ecaa5129036634" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Ocean City (Funvision)" "Cartridge.Note" "AKA Atlantis" "" "Cartridge.MD5" "10af8728f975aa35a99d0965de8f714c" "Cartridge.Manufacturer" "Dinatronic" "Cartridge.Name" "Seaquest (Dinatronic)" "" "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" "5c1b1aa78b7609d43c5144c3b3b60adf" "Cartridge.Name" "Demo Image Series #8 - Two Marios (Different Interlacing) (27-02-2003) (AD)" "" "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" "b0c9cf89a6d4e612524f4fd48b5bb562" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX26156" "Cartridge.Name" "Combat Two (1982) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "9912d06eea42200a198dd3e2be18c601" "Cartridge.Manufacturer" "Imagic, Michael Greene" "Cartridge.ModelNo" "IA3312" "Cartridge.Name" "No Escape! (1982) (Imagic) [a]" "" "Cartridge.MD5" "f303630a2d7316787aecd67fff6b2e33" "Cartridge.Manufacturer" "AtariAge - Fred Quimby" "Cartridge.Name" "Gingerbread Man (Fred Quimby)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "01b09872dcd9556427761f0ed64aa42a" "Cartridge.Manufacturer" "Galaga Games" "Cartridge.Name" "River Raid (1984) (Galaga Games)" "Display.YStart" "30" "" "Cartridge.MD5" "0f738dc44437557624eb277ed7ad91c9" "Cartridge.Name" "Grand Prix (Unknown) (PAL)" "Cartridge.Note" "AKA Grand Prix" "" "Cartridge.MD5" "7f73ac39e5e3e13e40fd8ad885561a0f" "Cartridge.Name" "Star Fire - Warping Star (13-04-2003) (MP)" "" "Cartridge.MD5" "ffb1cd548563158ce33f9d10268187e7" "Cartridge.Manufacturer" "Erik Eid" "Cartridge.Name" "Euchre (Beta) (NTSC) (12-09-2002) (Erik Eid)" "Cartridge.Rarity" "New Release" "" "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" "e37c8055d70979af354251ebe9f1b7dd" "Cartridge.Manufacturer" "HES" "Cartridge.Name" "Mega Funpak - Gorf, P. Patrol, Pacman, Skeet Shoot (HES) (PAL)" "" "Cartridge.MD5" "0acaf71e60b89f6b6eab63db6ab84510" "Cartridge.Name" "This Planet Sucks (Greg Troutman) [a2]" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "fadb89f9b23beb4d43a7895c532757e2" "Cartridge.Manufacturer" "Galaga Games" "Cartridge.Name" "River Raid (1984) (Galaga Games) (PAL)" "" "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" "7b24bfe1b61864e758ada1fe9adaa098" "Cartridge.Manufacturer" "Atari, Chris Crawford" "Cartridge.Name" "Wizard (1980) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7550b821ee56fb5833dca2be88622d5a" "Cartridge.Name" "Multiple Moving Objects Demo (B. Watson)" "" "Cartridge.MD5" "ef3a4f64b6494ba770862768caf04b86" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-034-04" "Cartridge.Name" "Private Eye (1983) (Activision)" "" "Cartridge.MD5" "d782543818b6320e4f60d77da2b596de" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Fishing Derby (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "3ad58b53a1e972396890bd86c735e78d" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "6 AR-4400" "Cartridge.Name" "Excalibur Version 36 (Dragonstomper Beta) (1982) (Arcadia) (Prototype)" "" "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" "" "Cartridge.MD5" "090f0a7ef8a3f885048d213faa59b2f8" "Cartridge.Manufacturer" "Carrere Video - Teldec" "Cartridge.ModelNo" "USC1012" "Cartridge.Name" "M.A.D. (1983) (Carrere Video) (PAL)" "" "Cartridge.MD5" "5409d20c1aea0b89c56993aec5dc5740" "Cartridge.Name" "Carnival Shooter (PD)" "" "Cartridge.MD5" "b36040a2f9ecafa73d835d804a572dbf" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Pac Man (1983) (Digitel)" "Display.YStart" "33" "" "Cartridge.MD5" "2124cf92978c46684b6c39ccc2e33713" "Cartridge.Name" "Sea Monster (Unknown) (PAL)" "" "Cartridge.MD5" "eb6d6e22a16f30687ade526d7a6f05c5" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26150P" "Cartridge.Name" "Q-bert (1987) (Atari) (PAL)" "" "Cartridge.MD5" "e34c236630c945089fcdef088c4b6e06" "Cartridge.Manufacturer" "Activision, David Crane - Ariola" "Cartridge.ModelNo" "EAB-035-04 - 711 035-720" "Cartridge.Name" "Pitfall II (1983) (Activision) (PAL)" "Cartridge.Note" "Lost Caverns" "" "Cartridge.MD5" "9295570a141cdec18074c55dc7229d08" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "7045 A015" "Cartridge.Name" "Bump 'n' Jump (1989) (Telegames) (PAL)" "" "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" "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" "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" "0906c6e0e4bda9c10cfa4c5fc64d2f4b" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.12) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "345488d3b014b684a181108f0ef823cb" "Cartridge.Manufacturer" "CBS Electronics, Tom DiDomenico" "Cartridge.ModelNo" "4L 2486 5000" "Cartridge.Name" "Blueprint (1983) (CBS Electronics) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "31" "" "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" "101ab60f4000a5d13792ef0abad5f74b" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira" "Cartridge.ModelNo" "CX26109" "Cartridge.Name" "Sorcerer's Apprentice (1983) (Atari) [a]" "" "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" "a1f9159121142d42e63e6fb807d337aa" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "700.223 1 - 781627" "Cartridge.Name" "Der moderne Ritter (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Fast Eddie" "" "Cartridge.MD5" "97cd63c483fe3c68b7ce939ab8f7a318" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Robot City (V0.21) (15-09-2002) (TJ)" "Cartridge.Rarity" "New Release" "Display.YStart" "24" "" "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" "3caa902ac0ce4509308990645876426a" "Cartridge.Manufacturer" "Atari - GCC, Dave Payne" "Cartridge.ModelNo" "CX2669, CX2669P" "Cartridge.Name" "Vanguard (1982) (Atari) (PAL)" "" "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" "25b6dc012cdba63704ea9535c6987beb" "Cartridge.Manufacturer" "Avalon Hill, Jean Baer, Bill Hood" "Cartridge.ModelNo" "5004002" "Cartridge.Name" "Shuttle Orbiter (1983) (Avalon Hill)" "Display.YStart" "24" "" "Cartridge.MD5" "a2eb84cfeed55acd7fece7fefdc83fbb" "Cartridge.Name" "Kool Aid Man (Fixed) (15-11-2002) (CT)" "Cartridge.Note" "HMOVE handling fixed in this version" "" "Cartridge.MD5" "d816fea559b47f9a672604df06f9d2e3" "Cartridge.Manufacturer" "Atari, Gary Palmer" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Fun with Numbers (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "0e713d4e272ea7322c5b27d645f56dd0" "Cartridge.Manufacturer" "Home Vision - Gem International Corp." "Cartridge.ModelNo" "VCS83105" "Cartridge.Name" "Panda Chase (1983) (Home Vision) (PAL)" "" "Cartridge.MD5" "60d304582d33e2957b73eb300a7495bb" "Cartridge.Name" "Jam Demo 2 (PD)" "" "Cartridge.MD5" "8712cceec5644aacc2c21203d9ebe2ec" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.10) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "34b269387fa1aa5a396636f5ecdd63dd" "Cartridge.Name" "Marble Craze (mc7_23) (Paul Slocum)" "" "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" "f6676e3fe901eb8515fc7ae310302c3c" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-008" "Cartridge.Name" "Laser Blast (1981) (Activision) (8K)" "" "Cartridge.MD5" "05aedf04803c43eb5e09dfd098d3fd01" "Cartridge.Name" "Keystone Kapers (Unknown) (PAL)" "" "Cartridge.MD5" "ef76ea05655a0b62cb1018c92b9b4b7d" "Cartridge.Manufacturer" "Gakken" "Cartridge.ModelNo" "010" "Cartridge.Name" "Strategy X (1983) (Gakken) (PAL)" "" "Cartridge.MD5" "f7af41a87533524d9a478575b0d873d0" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "495.663 7" "Cartridge.Name" "Spiderman (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Spider-Man" "" "Cartridge.MD5" "079fe9103515d15bc108577e234a484d" "Cartridge.Name" "Multi-Color Demo 0 (Bob Colbert) (PD)" "" "Cartridge.MD5" "211f76dff0b7dad3f6fcac9d938ee61a" "Cartridge.Manufacturer" "JSK" "Cartridge.Name" "Custer's Viagra (JSK) (Hack) [a]" "Cartridge.Note" "Hack of Custer's Revenge" "Cartridge.Rarity" "Hack" "Display.YStart" "32" "" "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" "04856e3006a4f5f7b4638da71dad3d88" "Cartridge.Manufacturer" "Atari, Douglas Neubauer" "Cartridge.ModelNo" "CX26176" "Cartridge.Name" "Radar Lock (1989) (Atari) (PAL)" "Cartridge.Note" "AKA Dog Fight" "" "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" "345758747b893e4c9bdde8877de47788" "Cartridge.Manufacturer" "CBS Electronics, Joseph Biel" "Cartridge.ModelNo" "4L1802, 4L1803, 4L1804, 4L2278" "Cartridge.Name" "Venture (1982) (CBS Electronics) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d4aa89e96d2902692f5c45f36903d336" "Cartridge.Name" "Euchre (NTSC) (Erik Eid) (PD)" "" "Cartridge.MD5" "fd4f5536fd80f35c64d365df85873418" "Cartridge.Manufacturer" "Atari, Robert C. Polaro" "Cartridge.ModelNo" "CX26140" "Cartridge.Name" "Desert Falcon (1987) (Atari)" "Cartridge.Note" "AKA Nile Flyer, Sphinx" "Display.YStart" "22" "" "Cartridge.MD5" "6651e2791d38edc02c5a5fd7b47a1627" "Cartridge.Manufacturer" "Parker Brothers, Wilfredo 'Willy' 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)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cade123747426df69570a2bc871d3baf" "Cartridge.Manufacturer" "Gakken" "Cartridge.ModelNo" "011" "Cartridge.Name" "Marine Wars (1983) (Gakken) (PAL)" "" "Cartridge.MD5" "2e663eaa0d6b723b645e643750b942fd" "Cartridge.Manufacturer" "Atari, Tom Rudadahl - Sears" "Cartridge.ModelNo" "CX2634 - 49-75121" "Cartridge.Name" "Golf (1980) (Atari)" "" "Cartridge.MD5" "e2c89f270f72cd256ed667507fa038a2" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4101" "Cartridge.Name" "Communist Mutants from Space (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "05c60458ec69e7fe8b1be973852d84f1" "Cartridge.Name" "Test (1996) (J.V. Matthews) (PD)" "" "Cartridge.MD5" "1a613ce60fc834d4970e1e674b9196b3" "Cartridge.Manufacturer" "Home Vision - Gem International Corp." "Cartridge.ModelNo" "VCS83135" "Cartridge.Name" "Tanks War (1983) (Home Vision) (PAL)" "Cartridge.Note" "AKA Phantom Tank" "" "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" "a302b922a8dbec47743f28b7f91d4cd8" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (Preview) (1982) (Arcadia)" "" "Cartridge.MD5" "e7a758bb0b43d0f7004e92b9abf4bc83" "Cartridge.Name" "Troll's Adventure (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "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" "545048ccb045f9efc6cf2b125cd0dfa8" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum, Jon Leupp" "Cartridge.ModelNo" "AR-4201" "Cartridge.Name" "Sword of Saros (1983) (Arcadia) [a]" "" "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" "6697f177847c70505824422e76aad586" "Cartridge.Name" "Tennis (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "517592e6e0c71731019c0cebc2ce044f" "Cartridge.Manufacturer" "Parker Brothers, Todd Marshall" "Cartridge.ModelNo" "PB5550" "Cartridge.Name" "Q-bert's Qubes (1984) (Parker Bros)" "Display.YStart" "32" "" "Cartridge.MD5" "cd4ded1ede63c4dd09f3dd01bda7458c" "Cartridge.Manufacturer" "Future Video Games" "Cartridge.Name" "Laser Gate (Future Video Games) (PAL)" "Cartridge.Note" "AKA Innerspace" "Display.YStart" "14" "" "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" "c9c25fc536de9a7cdc5b9a916c459110" "Cartridge.Manufacturer" "Activision, Mike Lorenzen" "Cartridge.ModelNo" "AX-023" "Cartridge.Name" "Oink! (1982) (Activision)" "" "Cartridge.MD5" "c221607529cabc93450ef25dbac6e8d2" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Color Test (26-09-2002) (Eckhard Stolberg)" "Cartridge.Rarity" "Homebrew" "Console.RightDifficulty" "A" "" "Cartridge.MD5" "5de8803a59c36725888346fdc6e7429d" "Cartridge.Manufacturer" "Atari, John Dunn - Sears" "Cartridge.ModelNo" "CX2631 - 49-75152" "Cartridge.Name" "Superman (1979) (Atari) [fixed]" "" "Cartridge.MD5" "97327d6962f8c64e6f926f79cd01c6b9" "Cartridge.Name" "Jawbreaker (Unknown) (PAL)" "" "Cartridge.MD5" "0abf64ca504a116adca80f77f85e00fb" "Cartridge.Name" "Cube Conquest (Billy Eno) (PD)" "" "Cartridge.MD5" "211fbbdbbca1102dc5b43dc8157c09b3" "Cartridge.Manufacturer" "Apollo" "Cartridge.ModelNo" "AP-2009" "Cartridge.Name" "Final Approach (1982) (Apollo)" "" "Cartridge.MD5" "2cfb188c1091cc7ec2a7e60064d2a758" "Cartridge.Name" "Space Invaders Hack Demo (2003) (SnailSoft)" "" "Cartridge.MD5" "fc92d74f073a44bc6e46a3b3fa8256a2" "Cartridge.Name" "Megademo (19xx) (PD)" "" "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" "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" "d175258b2973b917a05b46df4e1cf15d" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-032" "Cartridge.Name" "Walker (Suntek) (PAL) [a]" "Cartridge.Note" "AKA Clown Down Town" "Display.Height" "230" "" "Cartridge.MD5" "655c84e5b951258c9d20f0bf2b9d496d" "Cartridge.Name" "2600_2003 Demo (PD)" "" "Cartridge.MD5" "911d385ee0805ff5b8f96c5a63da7de5" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Jammed (V0.1) (Demo) (2001) (TJ)" "Cartridge.Rarity" "New Release" "Display.YStart" "24" "" "Cartridge.MD5" "c7eab66576696e11e3c11ffff92e13cc" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2680, CX2680P" "Cartridge.Name" "RealSports Tennis (1983) (Atari) (PAL) [a2]" "" "Cartridge.MD5" "5a2f2dcd775207536d9299e768bcd2df" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "781698" "Cartridge.Name" "Flippern (Double-Game Package) (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Video Pinball" "" "Cartridge.MD5" "0e4b2b6e014a93ef8be896823da0d4ec" "Cartridge.Name" "Skiing (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "73efa9f3cbe197f26e0fb87132829232" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-858" "Cartridge.Name" "Tennis (1983) (CCE) (4K)" "" "Cartridge.MD5" "e8e7b9bdf4bf04930c2bcaa0278ee637" "Cartridge.Name" "Boring Taz (Hack)" "Cartridge.Note" "Hack of Taz" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "45c4413dd703b9cfea49a13709d560eb" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Challenge of.... Nexar, The (Jone Yuan) (Hack)" "Cartridge.Note" "Hack" "" "Cartridge.MD5" "eae0c06ee61c63b81cd016096fc901b0" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide (v1.0) (2001) (Joe Grand)" "Cartridge.Rarity" "New Release" "" "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" "360c0dcb11506e73bd0b77207c81bc62" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Enduro (1983) (Digitel)" "" "Cartridge.MD5" "5da8fd0b5ed33a360bff37f8b5d0cd58" "Cartridge.Manufacturer" "Tron" "Cartridge.Name" "Pole Position (Tron)" "" "Cartridge.MD5" "30512e0e83903fc05541d2f6a6a62654" "Cartridge.Manufacturer" "Atari, Jim Huether - Sears" "Cartridge.ModelNo" "CX2644 - 6-99824" "Cartridge.Name" "Flag Capture (1978) (Atari)" "" "Cartridge.MD5" "fb4ca865abc02d66e39651bd9ade140a" "Cartridge.Manufacturer" "Arcadia Corporation, Brian McGhie" "Cartridge.ModelNo" "AR-4104" "Cartridge.Name" "Rabbit Transit (1983) (Arcadia)" "" "Cartridge.MD5" "6803fa7c2c094b428b859a58dc1dd06a" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (0.11) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d6a44277c3eb4f9d039185e0ecf7bfa6" "Cartridge.Name" "Trick (1997) (Eckhard Stolberg)" "" "Cartridge.MD5" "21a96301bb0df27fde2e7eefa49e0397" "Cartridge.Manufacturer" "Data Age" "Cartridge.ModelNo" "DA1003" "Cartridge.Name" "Sssnake (1982) (Data Age)" "" "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" "Display.YStart" "30" "" "Cartridge.MD5" "c4d888bcf532e7c9c5fdeafbb145266a" "Cartridge.Name" "Space Robot (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "499b612f6544ae71d4915aa63e403e10" "Cartridge.Manufacturer" "Atari, Carol Shaw" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Checkers (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "104468e44898b8e9fa4a1500fde8d4cb" "Cartridge.Manufacturer" "AtariAge, Chris Spry" "Cartridge.ModelNo" "26200" "Cartridge.Name" "Princess Rescue (2013) (Sprybug)" "Cartridge.Note" "Compatible with Genesis controller" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "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" "05ebd183ea854c0a1b56c218246fbbae" "Cartridge.Manufacturer" "Atari, Dan Hitchens" "Cartridge.ModelNo" "CX2656" "Cartridge.Name" "SwordQuest - EarthWorld (1982) (Atari) [a]" "" "Cartridge.MD5" "469473ff6fed8cc8d65f3c334f963aab" "Cartridge.Manufacturer" "Atari, Bruce Poehlman, Gary Stark" "Cartridge.Name" "Dune (07-10-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "23" "Display.Phosphor" "YES" "" "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" "Display.YStart" "42" "" "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" "a7b584937911d60c120677fe0d47f36f" "Cartridge.Manufacturer" "M Network, Hal Finney - INTV" "Cartridge.ModelNo" "MT5661" "Cartridge.Name" "Armor Ambush (1982) (M Network)" "Cartridge.Note" "AKA Tank Battle" "Cartridge.Rarity" "Common" "" "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" "Display.YStart" "30" "" "Cartridge.MD5" "6f2aaffaaf53d23a28bf6677b86ac0e3" "Cartridge.Manufacturer" "U.S. Games Corporation, Garry Kitchen - Vidtec" "Cartridge.ModelNo" "VC1001" "Cartridge.Name" "Space Jockey (1982) (U.S. Games)" "" "Cartridge.MD5" "65b106eba3e45f3dab72ea907f39f8b4" "Cartridge.Manufacturer" "Sparrow - HomeComputer Software Co., 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" "" "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" "da64f33d0521d5c9958e5d2d4434ff95" "Cartridge.Name" "Star Fire - Return of the Starfield (MP)" "" "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" "74ebaca101cc428cf219f15dda84b6f8" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AG-007, CAG-007" "Cartridge.Name" "Tennis (1981) (Activision) (8K)" "" "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" "eed9eaf1a0b6a2b9bc4c8032cb43e3fb" "Cartridge.Manufacturer" "Atari - Axlon, Steve DeFrisco" "Cartridge.ModelNo" "CX26192" "Cartridge.Name" "Klax (1990) (Atari) (PAL)" "" "Cartridge.MD5" "31d08cb465965f80d3541a57ec82c625" "Cartridge.Manufacturer" "Atari, Alan Miller - Sears" "Cartridge.ModelNo" "CX2641 - 99807, 49-75105" "Cartridge.Name" "Surround (1977) (Atari) (4K)" "" "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" "a7673809068062106db8e9d10b56a5b3" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira" "Cartridge.ModelNo" "CX26118, CX26118P" "Cartridge.Name" "Millipede (1984) (Atari) (PAL)" "" "Cartridge.MD5" "6b7e1c11448c4d3f28160d2de884ebc8" "Cartridge.Manufacturer" "Zirok" "Cartridge.Name" "Fast Food (Zirok)" "" "Cartridge.MD5" "9ab72d3fd2cc1a0c9adb504502579037" "Cartridge.Manufacturer" "Epyx, Steven A. Baker, Peter Engelbrite" "Cartridge.ModelNo" "80561-00286" "Cartridge.Name" "California Games (1988) (Epyx)" "" "Cartridge.MD5" "dca941dab5c6f859b71883b13ade9744" "Cartridge.Name" "Hangman Pac-Man Biglist2 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "8b5b1e3a434ebbdc2c2a49dc68f46360" "Cartridge.Manufacturer" "CBS Electronics, Dan Kitchen, Garry Kitchen" "Cartridge.ModelNo" "4L1700, 4L1701, 4L1702, 4L1802, 4L2274" "Cartridge.Name" "Donkey Kong (1982) (CBS Electronics) (PAL)" "" "Cartridge.MD5" "20dca534b997bf607d658e77fbb3c0ee" "Cartridge.Manufacturer" "Mythicon, Bill Bryner, Bruce de Graaf" "Cartridge.ModelNo" "MA1002" "Cartridge.Name" "Fire Fly (1983) (Mythicon)" "" "Cartridge.MD5" "dcba0e33aa4aed67630a4b292386f405" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.08) (Half Speed Version) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4c205f166157154df2f1ef60d87e552f" "Cartridge.Name" "Single-Scanline Positioning Demo 2 (2001) (Roger Williams)" "" "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" "7f54fa6aa824001af415503c313262f2" "Cartridge.Manufacturer" "HES" "Cartridge.Name" "Boom Bang (HES) (PAL)" "Cartridge.Note" "AKA Crackpots" "" "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" "0d27c7f5db349b592f70f68daf5e8f3b" "Cartridge.Name" "Space Instigators (21-10-2002) (CT)" "" "Cartridge.MD5" "4dd6c7ab9ef77f2b4950d8fc7cd42ee1" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.04) (Stella) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "02a5fc90a0d183f870e8eebac1f16591" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "771-422" "Cartridge.Name" "2 Pak Special - Star Warrior, Frogger (1990) (HES) (PAL)" "" "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.YStart" "38" "Display.Height" "256" "" "Cartridge.MD5" "4d8396deeabb40b5e8578276eb5a8b6d" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "781698" "Cartridge.Name" "Volleyball (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA RealSports Volleyball (Double-Game Package)" "" "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" "03ff9e8a7af437f16447fe88cea3226c" "Cartridge.Manufacturer" "Bomb - Onbase" "Cartridge.ModelNo" "CA285" "Cartridge.Name" "Wall-Defender (1983) (Bomb)" "Cartridge.Note" "AKA Wall Break" "Display.YStart" "30" "" "Cartridge.MD5" "c370c3268ad95b3266d6e36ff23d1f0c" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX2641, CX2641P" "Cartridge.Name" "Surround (1977) (Atari) (PAL)" "" "Cartridge.MD5" "e2389c0be5b5b84e0d3ca36ec7e67514" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.09) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "eb71743c6c7ccce5b108fad70a326ad9" "Cartridge.Name" "Euchre (25-11-2001) (Erik Eid) (PD)" "" "Cartridge.MD5" "8f60551db6d1535ef0030f155018c738" "Cartridge.Name" "Space War (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "247fa1a29ad90e64069ee13d96fea6d6" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-867" "Cartridge.Name" "Radar (1983) (CCE)" "Cartridge.Note" "AKA Exocet" "" "Cartridge.MD5" "64ca518905311d2d9aeb56273f6caa04" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Cubo Magico (CCE)" "Cartridge.Note" "AKA Cubicolor" "" "Cartridge.MD5" "107cc025334211e6d29da0b6be46aec7" "Cartridge.Manufacturer" "Atari, Bob Smith - Sears" "Cartridge.ModelNo" "CX2648 - 49-75161" "Cartridge.Name" "Video Pinball (1981) (Atari)" "" "Cartridge.MD5" "fbfebee9c14694719e3eda4854dc42ee" "Cartridge.Manufacturer" "Jake Patterson" "Cartridge.Name" "Baubles 3 (Jake Patterson) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "3b097a7ed5bd2a84dc3d3ed361e9c31c" "Cartridge.Name" "Interleaved ChronoColour Demo (PAL) (05-03-2003) (AD)" "" "Cartridge.MD5" "7b33407b2b198af74906b936ce1eecbb" "Cartridge.Manufacturer" "King Atari" "Cartridge.Name" "Ghostbuster 2 (King Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5a5390f91437af9951a5f8455b61cd43" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (0.11) (Retroactive) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "bc97d544f1d4834cc72bcc92a37b8c1b" "Cartridge.Name" "Sky Demo (PD)" "" "Cartridge.MD5" "fdf6680b2b1e8054293a39700a765692" "Cartridge.Name" "Alpha Demo - The Beta Demo 2 (2000) (MP)" "" "Cartridge.MD5" "ab434f4c942d6472e75d5490cc4dd128" "Cartridge.Manufacturer" "HES" "Cartridge.Name" "2 Pak Special - Hoppy, Alien Force (1992) (HES) (PAL)" "" "Cartridge.MD5" "133b56de011d562cbab665968bde352b" "Cartridge.Manufacturer" "Activision, John Van Ryzin" "Cartridge.ModelNo" "AG-038-04" "Cartridge.Name" "Cosmic Commuter (1984) (Activision)" "" "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" "c9d02d3cfeef8b48fb71cb4520a4aa84" "Cartridge.Name" "Euchre (More for less) (PAL) (22-08-2002) (Erik Eid)" "" "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" "eb503cc64c3560cd78b7051188b7ba56" "Cartridge.Manufacturer" "Star Game" "Cartridge.ModelNo" "043" "Cartridge.Name" "Moto Laser (Star Game)" "Cartridge.Note" "AKA Mega Force" "" "Cartridge.MD5" "9c729017dd2f9ccbadcb511187f80e6b" "Cartridge.Name" "J-Pac (Hack)" "Cartridge.Note" "Hack of Pac-Man" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "f02ba8b5292bf3017d10553c9b7b2861" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26172" "Cartridge.Name" "Xenophobe (1990) (Atari) (PAL)" "" "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" "4689081b7363721858756fe781cc7713" "Cartridge.Name" "Oystron (V2.6) (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "9905f9f4706223dadee84f6867ede8e3" "Cartridge.Manufacturer" "HES" "Cartridge.Name" "Challenge (HES) (PAL)" "" "Cartridge.MD5" "7f0209cfcc3d181715463f4d6451cecf" "Cartridge.Manufacturer" "Atari - GCC, Betty Ryan Tylko, Douglas B. Macrae" "Cartridge.ModelNo" "CX2694" "Cartridge.Name" "Pole Position (05-15-1983) (Atari) (Prototype)" "Cartridge.Note" "AKA RealSports Driving" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "02cee0b140d2f1a1efcfb1d482a5c392" "Cartridge.Manufacturer" "Atari, Ed Logg, Carol Shaw - Sears" "Cartridge.ModelNo" "CX2639 - 49-75162" "Cartridge.Name" "Othello (1981) (Atari) (4K)" "" "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" "bd430c2193045c68d1a20a018a976248" "Cartridge.Name" "Pac Ghost Sprite Demo 2 (PD)" "" "Cartridge.MD5" "dd0cbe5351551a538414fb9e37fc56e8" "Cartridge.Manufacturer" "Xonox - K-Tel Software, Anthony R. Henderson" "Cartridge.ModelNo" "99006, 6220" "Cartridge.Name" "Sir Lancelot (1983) (Xonox) (PAL)" "" "Cartridge.MD5" "86128001e69ab049937f265911ce7e8a" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Steve Stringfellow" "Cartridge.ModelNo" "AP-2005" "Cartridge.Name" "Lochjaw (1981) (Apollo)" "" "Cartridge.MD5" "84df0704e6c777e1f9a16ec92ad80df0" "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" "3e49da621193d2611a4ea152d5d5ca3a" "Cartridge.Name" "Atari Logo Demo 3 (PD)" "" "Cartridge.MD5" "6d475019ea30d0b29f695e9dcfd8f730" "Cartridge.Manufacturer" "Eric Mooney" "Cartridge.Name" "Invaders by Erik Mooney (Alpha 2) (PD)" "Cartridge.Rarity" "New Release" "" "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" "96f806fc62005205d851e758d050dfca" "Cartridge.Name" "Push (V0.05) (2001) (AD)" "" "Cartridge.MD5" "d010e3dfe7366e47561c088079a59439" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.10) (Stella) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "47911752bf113a2496dbb66c70c9e70c" "Cartridge.Manufacturer" "Atari, Christopher H. Omarzu, Preston Stuart, Bruce Williams" "Cartridge.ModelNo" "CX26101" "Cartridge.Name" "Oscar's Trash Race (1983) (Atari) (PAL)" "Cartridge.Note" "Uses the Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "d3bb42228a6cd452c111c1932503cc03" "Cartridge.Manufacturer" "UA Limited" "Cartridge.Name" "Funky Fish (1983) (UA Limited) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "38" "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" "73aa02458b413091ac940c0489301710" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "463.574 4 - 781393, 986153" "Cartridge.Name" "Kampf dem Steinfresser (1983) (Quelle) (PAL)" "Cartridge.Note" "Boom Bang (AKA Crackpots)" "" "Cartridge.MD5" "2e7e9c6dcfcceaffc6fa73f0d08a402a" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-818" "Cartridge.Name" "Star Voyager (1983) (CCE) [a]" "" "Cartridge.MD5" "9f2d58dce1b81c6ba201ed103507c025" "Cartridge.Name" "Fu Kung! (V0.02) (2003) (AD)" "" "Cartridge.MD5" "bc5389839857612cfabeb810ba7effdc" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.ModelNo" "CX2671" "Cartridge.Name" "SwordQuest - WaterWorld (1983) (Atari)" "" "Cartridge.MD5" "fb91da78455d9b1606913fbf8c859772" "Cartridge.Name" "Split Screen (Ballblazer) Demo (PD)" "" "Cartridge.MD5" "0866e22f6f56f92ea1a14c8d8d01d29c" "Cartridge.Manufacturer" "Western Technologies, Michael Case, Lenny Carlson" "Cartridge.Name" "AndroMan on the Moon (1984) (Western Tech) (Prototype)" "Cartridge.Rarity" "Prototype" "" "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" "Display.YStart" "22" "Display.Height" "222" "Display.Phosphor" "YES" "" "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" "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" "d08fccfbebaa531c4a4fa7359393a0a9" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.Name" "Venetian Blinds Demo (1982) (Activision)" "" "Cartridge.MD5" "687c23224e26f81c56e431c24faea36d" "Cartridge.Name" "Qb (Simple Background Animation) (2001) (AD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cd98be8a48ebf610c9609a688b9c57f2" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Hales, Stephen Harland Landrum" "Cartridge.ModelNo" "4 AR-4102" "Cartridge.Name" "Suicide Mission (1982) (Arcadia) (Prototype)" "Cartridge.Note" "AKA Meteoroids" "Display.Phosphor" "YES" "" "Cartridge.MD5" "637efac676ff063f2fbb0abff77c4fa5" "Cartridge.Name" "Noize Maker Demo (PD)" "" "Cartridge.MD5" "d61629bbbe035f45552e31cef7d591b2" "Cartridge.Name" "Atari Logo Demo (PD) (PAL)" "" "Cartridge.MD5" "f10e3f45fb01416c87e5835ab270b53a" "Cartridge.Manufacturer" "Video Game Cartridge - Ariola" "Cartridge.ModelNo" "TP-607" "Cartridge.Name" "Ski Run (Ariola) (PAL)" "" "Cartridge.MD5" "e9e646f730b8400cd5da08c849ef3e3b" "Cartridge.Manufacturer" "Tron" "Cartridge.Name" "Enduro (Tron)" "" "Cartridge.MD5" "49571b26f46620a85f93448359324c28" "Cartridge.Name" "Save Our Ship (Unknown)" "Display.Format" "NTSC" "Display.YStart" "38" "" "Cartridge.MD5" "eb9712e423b57f0b07ccd315bb9abf61" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.04) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "becd908f9d7bb361982c3dc02d6475c6" "Cartridge.Manufacturer" "Kyle Pittman" "Cartridge.Name" "THX-1138 (Kyle Pittman) (Hack)" "Cartridge.Note" "Hack of Berserk" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "a7ef44ccb5b9000caf02df3e6da71a92" "Cartridge.Manufacturer" "Atari, Ian Shepard - Sears" "Cartridge.ModelNo" "CX2604 - 6-99812, 49-75106" "Cartridge.Name" "Space War (1978) (Atari)" "" "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" "c43bd363e1f128e73ba5f0380b6fd7e3" "Cartridge.Manufacturer" "Atari, Chris Crawford" "Cartridge.Name" "Wizard (1980) (Atari) (Prototype) [a]" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "157bddb7192754a45372be196797f284" "Cartridge.Manufacturer" "Atari, Warren Robinett - Sears" "Cartridge.ModelNo" "CX2613, 49-75154" "Cartridge.Name" "Adventure (1980) (Atari)" "Cartridge.Rarity" "Common" "" "Cartridge.MD5" "407a0c6cc0ff777f67b669440d68a242" "Cartridge.Manufacturer" "Erik Eid" "Cartridge.Name" "Euchre (Alpha) (PAL) (31-08-2002) (Erik Eid)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "5af9cd346266a1f2515e1fbc86f5186a" "Cartridge.Manufacturer" "Sega" "Cartridge.ModelNo" "002-01" "Cartridge.Name" "Sub-Scan (1982) (Sega)" "Cartridge.Note" "AKA Subterfuge" "" "Cartridge.MD5" "c8fa5d69d9e555eb16068ef87b1c9c45" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26144" "Cartridge.Name" "Donkey Kong Junior (1987) (Atari)" "" "Cartridge.MD5" "43e6c5159c3a093fca88656628c6ef34" "Cartridge.Name" "Star Fire (17-02-2003) (MP)" "" "Cartridge.MD5" "e39843c56b7a4a08b18fa7949ec3ee6b" "Cartridge.Name" "Joshua Invaders (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "8786f229b974c393222874f73a9f3206" "Cartridge.Manufacturer" "Activision, Larry Miller - Ariola" "Cartridge.ModelNo" "EAX-021, EAX-021-04I - 711 021-720" "Cartridge.Name" "Spider Fighter (1982) (Activision) (PAL)" "" "Cartridge.MD5" "7d0b49ea4fe3a5f1e119a6d14843db17" "Cartridge.Manufacturer" "Gameworld" "Cartridge.ModelNo" "133-008" "Cartridge.Name" "Frankenstein's Monster (1983) (Gameworld) (PAL)" "" "Cartridge.MD5" "18760f1f9ca5e18610115cf7b815b824" "Cartridge.Name" "Star Fire (23-10-2002) (MP)" "" "Cartridge.MD5" "fb884ffd89013331a6f01ae3f6abd214" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.Name" "Venetian Blinds Demo (1982) (Activision) (PAL)" "" "Cartridge.MD5" "bc526185ad324241782dc68ba5d0540b" "Cartridge.Name" "Dodge Demo 1 (PD)" "" "Cartridge.MD5" "14a56b493a8d9d10e94a3e100362e3a2" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - Early Play-kernel (2001) (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "f4469178cd8998cb437fa110a228eaca" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Frostbite (1983) (Digitel)" "" "Cartridge.MD5" "4209e9dcdf05614e290167a1c033cfd2" "Cartridge.Manufacturer" "CommaVid, John Bronstein" "Cartridge.ModelNo" "CM-002" "Cartridge.Name" "Video Life (1981) (CommaVid) [higher sounds]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ed1a784875538c7871d035b7a98c2433" "Cartridge.Name" "Save Our Ship (Unknown) (Hack)" "Cartridge.Rarity" "Hack" "Display.YStart" "38" "" "Cartridge.MD5" "f6a9ea814d15b85bffe980c927df606b" "Cartridge.Name" "Missile Command (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2447e17a4e18e6b609de498fe4ab52ba" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Super Futebol (CCE)" "Cartridge.Note" "AKA RealSports Soccer" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3e7d10d0a911afc4b492d06c99863e65" "Cartridge.Manufacturer" "VGS" "Cartridge.Name" "Super Tenis (VGS)" "Cartridge.Note" "AKA RealSports Tennis" "" "Cartridge.MD5" "88d300a38bdd7cab9edad271c18cd02b" "Cartridge.Manufacturer" "Funvision - Fund. Int'l Co." "Cartridge.Name" "Pac Kong (Funvision) (PAL)" "Cartridge.Note" "AKA Spider Kong" "" "Cartridge.MD5" "0d7e630a14856f4d52c9666040961d4d" "Cartridge.Name" "Wavy Line Test (PD)" "" "Cartridge.MD5" "f5d103a9ae36d1d4ee7eef657b75d2b3" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4105" "Cartridge.Name" "Official Frogger, The (Preview) (1983) (Arcadia)" "Display.YStart" "32" "" "Cartridge.MD5" "51e390424f20e468d2b480030ce95d7b" "Cartridge.Manufacturer" "Video Game Program" "Cartridge.Name" "Fire Bird (Video Game Program) (PAL)" "Cartridge.Note" "AKA Phoenix" "" "Cartridge.MD5" "a47878a760f5fa3aa99f95c3fdc70a0b" "Cartridge.Name" "Demo Image Series #5 - Baboon (19-02-2003) (AD)" "" "Cartridge.MD5" "52e1954dc01454c03a336b30c390fb8d" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.14) (Retroactive) (Stella)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6e4521989a60a0ddf4ff1fc6e6e5fc3d" "Cartridge.Name" "Star Fire (01-05-2002) (MP)" "" "Cartridge.MD5" "7860716fa5dbc0fffab93fb9a4cb4132" "Cartridge.Name" "Hangman Monkey Wordlist (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "adb770ff70e9adf08bbb907a7eccd240" "Cartridge.Name" "Inv Demo 3 (2001) (Erik Mooney) (PD)" "" "Cartridge.MD5" "0d786a41695e5fc8cffd05a6dbb3f659" "Cartridge.Name" "Scrolling Playfield With Score (10-02-2003) (Aaron Bergstrom)" "" "Cartridge.MD5" "318a9d6dda791268df92d72679914ac3" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-017, AX-017-04" "Cartridge.Name" "MegaMania (1982) (Activision)" "" "Cartridge.MD5" "de24f700fd28d5b8381de13abd091db9" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Plaque Attack (CCE)" "" "Cartridge.MD5" "42249ec8043a9a0203dde0b5bb46d8c4" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Resgate Espacial (CCE)" "Cartridge.Note" "AKA Moonsweeper" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ba657d940a11e807ff314bba2c8b389b" "Cartridge.Manufacturer" "Activision, John Van Ryzin" "Cartridge.ModelNo" "AG-038-04" "Cartridge.Name" "Cosmic Commuter (1984) (Activision) (16K)" "" "Cartridge.MD5" "4e86866d9cde738d1630e2e35d7288ce" "Cartridge.Manufacturer" "Supergame" "Cartridge.Name" "River Raid III (Supergame)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "85478bb289dfa5c63726b9153992a920" "Cartridge.Name" "Candi (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "70a8480cfaf08776e5420365732159d2" "Cartridge.Manufacturer" "Rob Kudla" "Cartridge.Name" "Horizontally Scrolling Playfield Thing (Rob Kudla) (PD)" "" "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" "19e761e53e5ec8e9f2fceea62715ca06" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "104" "Cartridge.Name" "Scuba Diver (1983) (Panda)" "Cartridge.Note" "AKA Skindiver" "" "Cartridge.MD5" "6fbd05b0ad65b2a261fa154b34328a7f" "Cartridge.Name" "Boardgame Demo (20-12-2002) (CT)" "" "Cartridge.MD5" "8da51e0c4b6b46f7619425119c7d018e" "Cartridge.Manufacturer" "Atari, David Lubar" "Cartridge.ModelNo" "CX26183" "Cartridge.Name" "Sentinel (1990) (Atari)" "Cartridge.Note" "Uses the Light Gun Controller (left only)" "" "Cartridge.MD5" "c517144e3d3ac5c06f2f682ebf212dd7" "Cartridge.Manufacturer" "Tigervision - Teldec" "Cartridge.ModelNo" "7-008 - 3.60006 VG" "Cartridge.Name" "Miner 2049er (1982) (Tigervision) (PAL)" "" "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" "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" "42e0ec5ab8f5deba53e4169ff2a5efbe" "Cartridge.Name" "Atari Logo Demo 5 (PD)" "" "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" "6041f400b45511aa3a69fab4b8fc8f41" "Cartridge.Manufacturer" "Apollo, Ban Tran" "Cartridge.ModelNo" "AP-2010" "Cartridge.Name" "Wabbit (1982) (Apollo)" "" "Cartridge.MD5" "37f42ab50018497114f6b0f4f01aa9a1" "Cartridge.Name" "Droid Demo 2-M (David Conrad Schweinsberg) (PD)" "" "Cartridge.MD5" "aed82052f7589df05a3f417bb4e45f0c" "Cartridge.Manufacturer" "Atari, Warren Robinett - Sears" "Cartridge.ModelNo" "CX2606 - 6-99825, 49-75112" "Cartridge.Name" "Slot Racers (1978) (Atari)" "" "Cartridge.MD5" "17c0a63f9a680e7a61beba81692d9297" "Cartridge.Manufacturer" "U.S. Games Corporation, Tom Sloper" "Cartridge.ModelNo" "VC2004" "Cartridge.Name" "Picnic (1982) (U.S. Games)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "" "Cartridge.MD5" "e94632b0d863dd76459d689a9865bb33" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Combat (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "c6db733e0b108c2580a1d65211f06dbf" "Cartridge.Manufacturer" "Atari, Eric Manghise, Joseph Tung" "Cartridge.ModelNo" "CX2640" "Cartridge.Name" "RealSports Baseball (07-09-1982) (Atari) (Prototype)" "Cartridge.Note" "AKA Foxbat" "Cartridge.Rarity" "Prototype" "Display.YStart" "30" "" "Cartridge.MD5" "f9d51a4e5f8b48f68770c89ffd495ed1" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.ModelNo" "CX2657" "Cartridge.Name" "SwordQuest - FireWorld (1982) (Atari)" "Cartridge.Note" "AKA Adventure II, SwordQuest II - FireWorld" "" "Cartridge.MD5" "58513bae774360b96866a07ca0e8fd8e" "Cartridge.Manufacturer" "Mystique - American Multiple Industries, Joel H. Martin" "Cartridge.ModelNo" "1001" "Cartridge.Name" "Custer's Revenge (1982) (Mystique)" "Display.YStart" "32" "" "Cartridge.MD5" "d6b8beeb05e5b730084d4b8f381bbf8d" "Cartridge.Name" "Game Select (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "7e7c4c59d55494e66eef5e04ec1c6157" "Cartridge.Manufacturer" "Baroque Gaming (Brian Eno)" "Cartridge.Name" "Warring Worms (2002) (Baroque Gaming)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "4ab4af3adcdae8cdacc3d06084fc8d6a" "Cartridge.Manufacturer" "Nick Bensema" "Cartridge.Name" "Sucky Zepplin (Nick Bensema) (PD)" "Cartridge.Rarity" "New Release" "" "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" "8d00a38f4c8f8800f1c237215ac243fc" "Cartridge.Name" "3-D Corridor (Green) (30-03-2003) (AD)" "" "Cartridge.MD5" "840a5a2eaea24d95d289f514fd12f9bb" "Cartridge.Name" "GBImprov (Hack)" "Cartridge.Note" "Hack of Ghostbusters" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "3c72ddaf41158fdd66e4f1cb90d4fd29" "Cartridge.Manufacturer" "Dismac" "Cartridge.Name" "Comando Suicida (Dismac)" "Cartridge.Note" "AKA Chopper Command" "" "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" "9e2c7299c69b602443d327c7dad51cbf" "Cartridge.Manufacturer" "Charles Morgan" "Cartridge.Name" "Xaxyrax Road (Charles Morgan) (Hack)" "Cartridge.Note" "Hack of Freeway" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "54785fa29e28aae6038929ba29d33d38" "Cartridge.Name" "Poker Squares (V0.19) (2001) (B. Watson)" "" "Cartridge.MD5" "e171558c51bb3bac97bfa79fa2c1a19c" "Cartridge.Name" "Warring Worms (Tim Strauss Edition) (20-12-2002) (Billy Eno)" "" "Cartridge.MD5" "f9420173efcb4b9f2b01c2a7b595cca7" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Laser Blast (CCE) (4K)" "" "Cartridge.MD5" "fd10915633aea4f9cd8b518a25d62b55" "Cartridge.Manufacturer" "Atari, John Dunn" "Cartridge.ModelNo" "CX2631, CX2631P" "Cartridge.Name" "Superman (1979) (Atari) (PAL) [a]" "" "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" "dafc3945677ccc322ce323d1e9930beb" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "A-Team (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "94e3fbc19107a169909e274187247a9d" "Cartridge.ModelNo" "2402-044-01" "Cartridge.Name" "2-in-1 Freeway and Tennis (Unknown)" "Cartridge.Type" "2IN1" "" "Cartridge.MD5" "2a33e21447bf9e13dcfed85077ff6b40" "Cartridge.Name" "Backwards Cannonball v2 (Hack)" "Cartridge.Note" "Hack of Human Cannonball" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "65490d61922f3e3883ee1d583ce10855" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Noellie Alito" "Cartridge.ModelNo" "CX2692, CX2692P" "Cartridge.Name" "Moon Patrol (1983) (Atari) (PAL)" "" "Cartridge.MD5" "a7523db9a33e9417637be0e71fa4377c" "Cartridge.Manufacturer" "Videospielkassette - Ariola" "Cartridge.ModelNo" "PGP238" "Cartridge.Name" "Gangster (Ariola) (PAL)" "Cartridge.Note" "AKA Outlaw" "" "Cartridge.MD5" "a62e3e19280ff958407e05ca0a2d5ec7" "Cartridge.Name" "Hangman Ghost Biglist3 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "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" "40b1832177c63ebf81e6c5b61aaffd3a" "Cartridge.Manufacturer" "Atari, Peter C. Niday" "Cartridge.Name" "Rubik's Cube 3-D (1982) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "9057694dce8449521e6164d263702185" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-011" "Cartridge.Name" "Stampede (1981) (Activision) (16K)" "" "Cartridge.MD5" "e2904748da63dfefc8816652b924b642" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Catch Time (Jone Yuan)" "Cartridge.Note" "AKA Plaque Attack" "" "Cartridge.MD5" "00f7985c20b8bdf3c557fac4d3f26775" "Cartridge.Manufacturer" "Aaron Curtis" "Cartridge.Name" "AStar (NTSC)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "24fbf8250a71611e40ef18552e61b009" "Cartridge.Name" "Movable Grid Demo (PD)" "" "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" "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" "3b966bf3c2ca34ac6ca1de4cf6383582" "Cartridge.Name" "Double-Height 6-Digit Score Display (2001) (AD)" "" "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" "Display.YStart" "30" "" "Cartridge.MD5" "2cccc079c15e9af94246f867ffc7e9bf" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "203" "Cartridge.Name" "Jungle Fever (1982) (PlayAround)" "Display.YStart" "24" "Display.Phosphor" "YES" "" "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" "9193b6fff6897d43274741d4f9855b6d" "Cartridge.Name" "M.A.S.H (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "282a77841cb3d33af5b56151acba770e" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "311388" "Cartridge.Name" "Black Hole (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Cosmic Ark (Double-Game Package)" "" "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" "6efe876168e2d45d4719b6a61355e5fe" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG207" "Cartridge.Name" "Mission 3,000 A.D. (1983) (BitCorp) (PAL)" "Display.Phosphor" "YES" "" "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" "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" "37252757a79dc5b174e3c03d6ea0bdcb" "Cartridge.Name" "Sky Diver (Unknown) (PAL) (4K) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "f344ac1279152157d63e64aa39479599" "Cartridge.Manufacturer" "Tigervision" "Cartridge.ModelNo" "7-012" "Cartridge.Name" "Espial (1984) (Tigervision)" "" "Cartridge.MD5" "24ad538291eb5f5cac4b9998f3b851c3" "Cartridge.Name" "Gunfight 2600 - This time it's your decission! (2001) (MP)" "" "Cartridge.MD5" "e0cf2dcc4c1348c468f5bb1e421c9164" "Cartridge.Name" "Invader Sprites in a Line Demo (PD)" "" "Cartridge.MD5" "e14feddeb82f5160ed5cf9ca4078e58d" "Cartridge.Name" "SpaceMaster X-7 (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "f4dabd5bcc603e8464a478208037d423" "Cartridge.Manufacturer" "Coleco, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (08-21-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "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" "4066309eb3fa3e7a725585b9814bc375" "Cartridge.Name" "Multi Ball Demo (PD)" "" "Cartridge.MD5" "bf52327c2197d9d2c4544be053caded1" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "AG-930-04, AZ-030" "Cartridge.Name" "Decathlon (HES) (PAL) (16K)" "" "Cartridge.MD5" "a422194290c64ef9d444da9d6a207807" "Cartridge.Manufacturer" "M Network, Hal Finney" "Cartridge.ModelNo" "MT5667" "Cartridge.Name" "Dark Cavern (1982) (M Network)" "" "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" "e879b7093ac4cfad74c88d636ca97d00" "Cartridge.Name" "Poker Squares (V0.0f) (2001) (B. Watson)" "" "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" "9c6fd6ed3599978ab7b6f900484b9be6" "Cartridge.Manufacturer" "Andrew Wallace" "Cartridge.Name" "Laseresal 2002 (PAL60) (PD)" "Cartridge.Rarity" "New Release" "Display.Format" "PAL60" "" "Cartridge.MD5" "a0563dd6d8215c38c488fbbd61435626" "Cartridge.Name" "Ship Demo (V 1501) (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" "32ecb5a652eb73d287e883eea751d99c" "Cartridge.Manufacturer" "Dactar - Milmar" "Cartridge.Name" "Bowling (Dactar - Milmar)" "" "Cartridge.MD5" "f73d2d0eff548e8fc66996f27acf2b4b" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-813" "Cartridge.Name" "Pitfall (1983) (CCE)" "" "Cartridge.MD5" "493de059b32f84ab29cde6213964aeee" "Cartridge.Manufacturer" "Atari, Bill Aspromonte, Andrew Fuchs" "Cartridge.ModelNo" "CX26120" "Cartridge.Name" "Stargate (1984) (Atari) (PAL)" "" "Cartridge.MD5" "877a5397f3f205bf6750398c98f33de1" "Cartridge.Manufacturer" "Erik Eid" "Cartridge.Name" "Euchre (Beta) (PAL) (12-09-2002) (Erik Eid)" "Cartridge.Rarity" "New Release" "" "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" "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" "9813b9e4b8a6fd919c86a40c6bda8c93" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26177" "Cartridge.Name" "Ikari Warriors (1989) (Atari) (PAL) [a]" "" "Cartridge.MD5" "ca53fc8fd8b3c4a7df89ac86b222eba0" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-812" "Cartridge.Name" "Pac Man (1983) (CCE)" "Display.YStart" "33" "" "Cartridge.MD5" "66b89ba44e7ae0b51f9ef000ebba1eb7" "Cartridge.Manufacturer" "Atari, Stephan R. Keith, 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" "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.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" "481d20ec22e7a63e818d5ef9679d548b" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Freeway Rabbit (32 in 1) (1988) (Atari) (PAL)" "Cartridge.Note" "AKA Freeway" "" "Cartridge.MD5" "c82ec00335cbb4b74494aecf31608fa1" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "E.T. - The Extra-Terrestrial (CCE)" "" "Cartridge.MD5" "c3e4aa718f46291311f1cce53e6ccd79" "Cartridge.Name" "Hangman Ghost 4letter (Hack)" "Cartridge.Note" "Hack of Hangman" "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" "06e5dc181a8eda1c31cc7c581c68b6ef" "Cartridge.Name" "Tac-Scan (Unknown) (PAL)" "Display.Phosphor" "YES" "" "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" "c126656df6badfa519cc63e681fb3596" "Cartridge.Manufacturer" "Ron Corcoran" "Cartridge.Name" "Space Invaders (2002) (Ron Corcoran) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "6468d744be9984f2a39ca9285443a2b2" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Reversi (32 in 1) (1988) (Atari) (PAL)" "Cartridge.Note" "AKA Othello" "" "Cartridge.MD5" "14d365bbfaac3d20c6119591f57acca4" "Cartridge.Name" "Video Life (Unknown) (4K) (Hack)" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "dfad86dd85a11c80259f3ddb6151f48f" "Cartridge.Manufacturer" "HES, David Lubar" "Cartridge.ModelNo" "535" "Cartridge.Name" "My Golf (1990) (HES) (PAL) [fixed]" "" "Cartridge.MD5" "b16cd9784589219391c839cb68c47b9c" "Cartridge.Manufacturer" "Video Soft, Jerry Lawson, Dan McElroy" "Cartridge.Name" "Golf Diagnostic (1983) (Video Soft) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "2825f4d068feba6973e61c84649489fe" "Cartridge.Name" "Boom Bang (Unknown) (PAL)" "Cartridge.Note" "AKA Crackpots" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "a2f296ea2d6d4b59979bac5dfbf4edf0" "Cartridge.Name" "Warring Worms (28-01-2002) (Billy Eno)" "" "Cartridge.MD5" "9f8fad4badcd7be61bbd2bcaeef3c58f" "Cartridge.Manufacturer" "Parker Brothers, Charlie Heath" "Cartridge.ModelNo" "PB5330" "Cartridge.Name" "Reactor (1982) (Parker Bros)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "1802cc46b879b229272501998c5de04f" "Cartridge.Manufacturer" "Atari, Christopher H. Omarzu - Children's Computer Workshop" "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" "e66e5af5dea661d58420088368e4ef0d" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-011" "Cartridge.Name" "Stampede (1981) (Activision) (4K)" "" "Cartridge.MD5" "f613aad84d2163d6b197b220bfec1b7e" "Cartridge.Name" "X-Doom V.27 (PD)" "" "Cartridge.MD5" "a5b7f420ca6cc1384da0fed523920d8e" "Cartridge.Name" "Adventure (New Graphics) (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "9526e3db3bdfbc27989a9cbfd0ee34bf" "Cartridge.Name" "Atari Logo Demo 6 (PD)" "" "Cartridge.MD5" "b7e459d5416eeb196aaa8e092db14463" "Cartridge.Name" "Push (V0.02) (1998) (AD)" "" "Cartridge.MD5" "77057d9d14b99e465ea9e29783af0ae3" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-001" "Cartridge.Name" "Dragster (1980) (Activision)" "Display.YStart" "22" "" "Cartridge.MD5" "6538e454b0498ad2befe1ef0f87815c0" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide (v1.2) (2001) (Joe Grand)" "Cartridge.Rarity" "New Release" "Controller.Left" "PADDLES_IAXDR" "" "Cartridge.MD5" "a3fee8ce15525ea00d45a06f04c215d1" "Cartridge.Manufacturer" "Aaron Curtis" "Cartridge.Name" "AStar (PAL60)" "Cartridge.Rarity" "Homebrew" "Display.Format" "PAL60" "" "Cartridge.MD5" "eea0da9b987d661264cce69a7c13c3bd" "Cartridge.Manufacturer" "Coleco" "Cartridge.ModelNo" "2454" "Cartridge.Name" "Zaxxon (1982) (Coleco)" "" "Cartridge.MD5" "06b6c5031b8353f3a424a5b86b8fe409" "Cartridge.Manufacturer" "Activision, Mike Lorenzen - Ariola" "Cartridge.ModelNo" "EAX-023 - 711 023-720" "Cartridge.Name" "Oink! (1982) (Activision) (PAL)" "Cartridge.Note" "AKA Das Schweinchen und der Wolf" "" "Cartridge.MD5" "ccb5fa954fb76f09caae9a8c66462190" "Cartridge.Manufacturer" "Answer Software Corporation - TY Associates" "Cartridge.ModelNo" "ASC1001" "Cartridge.Name" "Malagai (1983) (Answer Software)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e72eb8d4410152bdcb69e7fba327b420" "Cartridge.Manufacturer" "Atari, Douglas Neubauer" "Cartridge.ModelNo" "CX26136" "Cartridge.Name" "Solaris (1986) (Atari)" "Cartridge.Note" "AKA Universe, Star Raiders II, The Last Starfighter" "" "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" "6342afe9c9ad1b6120b8f6fb040d0926" "Cartridge.Name" "Move a Blue Blob Demo (PD)" "" "Cartridge.MD5" "f1489e27a4539a0c6c8529262f9f7e18" "Cartridge.Manufacturer" "Champ Games" "Cartridge.Name" "Lady Bug (PAL60)" "Cartridge.Rarity" "Homebrew" "Console.RightDifficulty" "A" "Display.Format" "PAL60" "Display.Phosphor" "YES" "" "Cartridge.MD5" "026180bf641ff17d8577c33facf0edea" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-022" "Cartridge.Name" "Seaquest (1983) (Activision) (8K)" "" "Cartridge.MD5" "b4daedb43511521db9036d503b3c1b69" "Cartridge.Name" "Sokoban (01-01-2003) (Adam Wozniak) [a1]" "Display.YStart" "36" "" "Cartridge.MD5" "b311ab95e85bc0162308390728a7361d" "Cartridge.Manufacturer" "Parker Brothers" "Cartridge.ModelNo" "PB5080" "Cartridge.Name" "Gyruss (1984) (Parker Bros)" "Display.Phosphor" "YES" "" "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" "6d842c96d5a01967be9680080dd5be54" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AB-035-04" "Cartridge.Name" "Pitfall II (1983) (Activision)" "" "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" "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" "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" "4a9009620038f7f30aaeb2a00ae58fde" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Mundry, Scott Nelson" "Cartridge.ModelNo" "AR-4401" "Cartridge.Name" "Survival Island (3 of 3) (1983) (Arcadia)" "" "Cartridge.MD5" "777aece98d7373998ffb8bc0b5eff1a2" "Cartridge.Name" "2600 Collison Demo 2 (Piero Cavina) (PD)" "" "Cartridge.MD5" "fa0570561aa80896f0ead05c46351389" "Cartridge.Manufacturer" "Tigervision" "Cartridge.ModelNo" "7-008" "Cartridge.Name" "Miner 2049er (1982) (Tigervision)" "Display.YStart" "31" "" "Cartridge.MD5" "f542b5d0193a3959b54f3c4c803ba242" "Cartridge.Manufacturer" "Atari, Tom Rudadahl - Sears" "Cartridge.ModelNo" "CX2634 - 49-75121" "Cartridge.Name" "Golf (1980) (Atari) (4K)" "" "Cartridge.MD5" "c469151655e333793472777052013f4f" "Cartridge.Name" "Base Attack (Unknown) (Hack)" "Cartridge.Rarity" "Hack" "Display.YStart" "30" "" "Cartridge.MD5" "e959b5a2c882ccaacb43c32790957c2d" "Cartridge.Name" "Phantom II & Pirate (NTSC)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "7eafc9827e8d5b1336905939e097aae7" "Cartridge.Manufacturer" "Atari, Mark R. Hahn" "Cartridge.Name" "Elk Attack (1987) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "9989f974c3cf9c641db6c8a70a2a2267" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Colours Selector (Eckhard Stolberg)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "787ebc2609a31eb5c57c4a18837d1aee" "Cartridge.Manufacturer" "Prescott" "Cartridge.Name" "Vault Assault (19xx) (Prescott)" "" "Cartridge.MD5" "7e2fe40a788e56765fe56a3576019968" "Cartridge.Manufacturer" "Activision, Dan Kitchen" "Cartridge.ModelNo" "AK-050-04" "Cartridge.Name" "Double Dragon (1989) (Activision)" "" "Cartridge.MD5" "6362396c8344eec3e86731a700b13abf" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "109" "Cartridge.Name" "Exocet (1983) (Panda)" "" "Cartridge.MD5" "e40a818dac4dd851f3b4aafbe2f1e0c1" "Cartridge.Manufacturer" "Atari, Bill Aspromonte, Dr. Lee Salk" "Cartridge.ModelNo" "CX26137" "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" "c4b73c35bc2f54b66cd786f55b668a82" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4101" "Cartridge.Name" "Communist Mutants from Space (1982) (Arcadia) [a]" "" "Cartridge.MD5" "5d799bfa9e1e7b6224877162accada0d" "Cartridge.Manufacturer" "Spectravision, Spectravideo, David Lubar" "Cartridge.ModelNo" "SA-206" "Cartridge.Name" "Challenge of.... Nexar, The (1982) (Spectravision)" "" "Cartridge.MD5" "06953ed762220dba63d63930d4ad0cc3" "Cartridge.Name" "Star Fire - Eckhard WIP (MP)" "" "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" "22675cacd9b71dea21800cbf8597f000" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.ModelNo" "CX2605, CX2605P" "Cartridge.Name" "Outlaw (1978) (Atari) (PAL)" "" "Cartridge.MD5" "4702d8d9b48a332724af198aeac9e469" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Steve Woita" "Cartridge.ModelNo" "CX2699" "Cartridge.Name" "Taz (1983) (Atari) [a]" "" "Cartridge.MD5" "d81bb6965e6c99b3be99ffd8978740e4" "Cartridge.Name" "Gunfight 2600 - The Final Kernel Part 3 (MP)" "" "Cartridge.MD5" "88dce4037471424bb38ab6841aaa8cab" "Cartridge.Name" "Double-Height 6-Digit Score Display (Two Background Color Change) (2001) (AD)" "" "Cartridge.MD5" "f16c709df0a6c52f47ff52b9d95b7d8d" "Cartridge.Manufacturer" "Atari, Alan Miller - Sears" "Cartridge.ModelNo" "CX2662 - 6-99811" "Cartridge.Name" "Hangman (1978) (Atari)" "" "Cartridge.MD5" "da0fb2a484d0d2d8f79d6e063c94063d" "Cartridge.Name" "Air Raiders (1982) (Unknown) [a]" "" "Cartridge.MD5" "1cf59fc7b11cdbcefe931e41641772f6" "Cartridge.Manufacturer" "Sega" "Cartridge.ModelNo" "005-01" "Cartridge.Name" "Buck Rogers - Planet of Zoom (1983) (Sega)" "Display.YStart" "26" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f1127ade54037236e75a133b1dfc389d" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (Preview) (1982) (Arcadia)" "" "Cartridge.MD5" "e0eff071f578ecf19edc2ab276644e46" "Cartridge.Name" "Gas Gauge Demo (2001) (Joe Grand) (PD)" "" "Cartridge.MD5" "18f299edb5ba709a64c80c8c9cec24f2" "Cartridge.Manufacturer" "Home Vision - Gem International Corp." "Cartridge.ModelNo" "VCS83111" "Cartridge.Name" "Asteroid Fire (1983) (Home Vision) (PAL)" "Cartridge.Rarity" "Extremely Rare" "Display.YStart" "24" "" "Cartridge.MD5" "2f11ba54609777e2c6a5da9b302c98e8" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2676" "Cartridge.Name" "Centipede (1982) (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "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" "d026716b3c5be2c951cc4c064317c524" "Cartridge.Name" "Fu Kung! (V0.06) (14-01-2003) (AD)" "" "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" "8febdd9142960d084ab6eeb1d3e88969" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Howard Scott Warshaw" "Cartridge.ModelNo" "CX2674" "Cartridge.Name" "E.T. - The Extra-Terrestrial (1982) (Atari) (PAL)" "" "Cartridge.MD5" "7ab0917107b6ec768a5ebaadf28c497a" "Cartridge.Name" "Santa's Helper (Hack)" "Cartridge.Note" "Hack of Kaboom!" "Cartridge.Rarity" "Hack" "Controller.Left" "PADDLES" "" "Cartridge.MD5" "b1fd0b71de9f6eeb5143a97963674cb6" "Cartridge.Name" "Multi-Color Demo 7 (Bob Colbert) (PD)" "" "Cartridge.MD5" "709910c2e83361bc4bf8cd0c20c34fbf" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-006" "Cartridge.Name" "Netmaker (Rainbow Vision) (PAL)" "Cartridge.Note" "AKA Amidar" "" "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" "a957dbe7d85ea89133346ad56fbda03f" "Cartridge.Manufacturer" "Atari, Brad Stewart" "Cartridge.ModelNo" "CX2649, CX2649P" "Cartridge.Name" "Asteroids (1981) (Atari) (PAL) [a1]" "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" "ea832e2cb6aae6f525f07452c381fa48" "Cartridge.Name" "Polar to Cartesian and VV (2001) (Roger Williams)" "" "Cartridge.MD5" "ed014beeeb77dbb2bbcf9b5f6850b2f4" "Cartridge.Name" "Green Bar Text Demo (PD)" "" "Cartridge.MD5" "ccd6ce508eee4b3fca67212833edcd85" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "746422" "Cartridge.Name" "Hot Wave (Double-Game Package) (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Ram It" "" "Cartridge.MD5" "b702641d698c60bcdc922dbd8c9dd49c" "Cartridge.Manufacturer" "Atari, Ian Shepard" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Space War (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "24759be31e8fe55d2829fd86bdf3181f" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - Worst Nightmare... (2001) (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "16fbb36a6124567405a235821e8f69ee" "Cartridge.Name" "Star Fire (28-11-2002) (MP)" "" "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" "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" "3f3ad2765c874ca13c015ca6a44a40a1" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-862" "Cartridge.Name" "Crackpots (1983) (CCE)" "" "Cartridge.MD5" "ed9999911b406dc5f75c850dcc17bdf4" "Cartridge.Name" "Star Fire - Shootable (Friendlier Collision Detection) (26-09-2002) (MP)" "" "Cartridge.MD5" "c830f6ae7ee58bcc2a6712fb33e92d55" "Cartridge.Manufacturer" "Atari, Carla Meninsky" "Cartridge.ModelNo" "CX2687" "Cartridge.Name" "Tempest (01-05-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "8764462d7d19a33b0717af22b99fc88f" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Sky Jinks (CCE) (4K)" "" "Cartridge.MD5" "6b8fb021bb2e1f1e9bd7ee57f2a8e709" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "3-D Corridor (29-03-2003) (Paul Slocum) (PD) [a]" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "176d3fba7d687f2b23158098e103c34a" "Cartridge.Manufacturer" "Zach Matley" "Cartridge.Name" "Combat AI (16-02-2003) (Zach Matley)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "5e201d6bfc520424a28f129ee5e56835" "Cartridge.Manufacturer" "Universal Gamex Corporation, Alan Roberts, H.K. Poon" "Cartridge.ModelNo" "GX-001" "Cartridge.Name" "X-Man (1983) (Universal) (PAL)" "" "Cartridge.MD5" "fcea12625c071ddc49f4e409f4038c60" "Cartridge.Manufacturer" "Fabrizio Zavagli" "Cartridge.Name" "Balls! (16-09-2002) (Fabrizio Zavagli)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "63811ed69bdbc35c69d8aa7806c3d6e9" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Homerun (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "074ec425ec20579e64a7ded592155d48" "Cartridge.Manufacturer" "Atari - Sculptured Software, Steve Aguirre" "Cartridge.ModelNo" "CX26162" "Cartridge.Name" "Fatal Run (Ultimate Driving) (1989) (Atari) (PAL)" "" "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" "4f89b897444e7c3b36aed469b8836839" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26190" "Cartridge.Name" "BMX Air Master (1990) (Atari) (PAL)" "" "Cartridge.MD5" "31e518debba46df6226b535fa8bd2543" "Cartridge.Manufacturer" "Atari, Douglas 'Solaris' Neubauer" "Cartridge.ModelNo" "CX26134" "Cartridge.Name" "Last Starfighter (1984) (Atari) (Prototype)" "Cartridge.Note" "Solaris Beta" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "6c85098518d3f94f7622c42fd1d819ac" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-028" "Cartridge.Name" "Firebug (Suntek) (PAL)" "Cartridge.Note" "AKA Spinning Fireball" "" "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" "8cd26dcf249456fe4aeb8db42d49df74" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26139" "Cartridge.Name" "Crossbow (1987) (Atari)" "" "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" "09274c3fc1c43bf1e362fda436651fd8" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Acid Drop (TJ)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Display.YStart" "8" "Display.Height" "240" "" "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" "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" "cd399bc422992a361ba932cc50f48b65" "Cartridge.Manufacturer" "Arcadia Corporation, Brian McGhie" "Cartridge.ModelNo" "AR-4104" "Cartridge.Name" "Rabbit Transit (Preview) (1983) (Arcadia)" "" "Cartridge.MD5" "d3423d7600879174c038f53e5ebbf9d3" "Cartridge.Manufacturer" "U.S. Games Corporation" "Cartridge.ModelNo" "VC2005" "Cartridge.Name" "Piece o' Cake (1982) (U.S. Games)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "" "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" "" "Cartridge.MD5" "a74689a08746a667a299b0507e1e6dd9" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4105" "Cartridge.Name" "Official Frogger, The (1983) (Arcadia) (PAL)" "" "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" "71f09f128e76eb14e244be8f44848759" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Time Race (Funvision) (PAL)" "Cartridge.Note" "AKA Time Warp" "" "Cartridge.MD5" "8fbabaa87941cdf3a377c15e95bdb0f3" "Cartridge.Name" "Meteor Smasher (SnailSoft)" "" "Cartridge.MD5" "8290daea8391f96d7c8e1482e184d19c" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Frame Timed Sound Effects (Eckhard Stolberg)" "Cartridge.Rarity" "New Release" "" "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" "0b33252b680b65001e91a411e56e72e9" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-832" "Cartridge.Name" "Atlantis (1983) (CCE) [a]" "" "Cartridge.MD5" "dd08e18cfee87a0e7fc19a684b36e124" "Cartridge.Manufacturer" "Atari - GCC, Kevin Osborn" "Cartridge.ModelNo" "CX2689, CX2689P" "Cartridge.Name" "Kangaroo (1983) (Atari) (PAL) [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.YStart" "24" "Display.Phosphor" "YES" "" "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" "7628d3cadeee0fd2e41e68b3b8fbe229" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Fishing Derby (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "67631ea5cfe44066a1e76ddcb6bcb512" "Cartridge.Name" "Termool (Unknown) (PAL)" "Cartridge.Note" "AKA Turmoil" "" "Cartridge.MD5" "ed1492d4cafd7ebf064f0c933249f5b0" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Video Cube (CCE)" "Cartridge.Note" "AKA Atari Video Cube" "" "Cartridge.MD5" "278155fc9956e9b6ef2359eb238f7c7f" "Cartridge.Name" "Donkey Kong Junior (Unknown) (Hack)" "Cartridge.Note" "Hack of Donkey Kong Junior" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "4df9d7352a56a458abb7961bf10aba4e" "Cartridge.Name" "Racing Car (Unknown)" "Console.SwapPorts" "YES" "" "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" "efb47d70b2965ce689e2c5757616b286" "Cartridge.Name" "Time Test Demo (Eckhard Stolberg) (PAL) (PD)" "" "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" "" "Cartridge.MD5" "d1b4075925e8d3031a7616d2f02fdd1f" "Cartridge.Name" "Demo Image Series #7 - Two Marios (27-02-2003) (AD)" "" "Cartridge.MD5" "0164f26f6b38a34208cd4a2d0212afc3" "Cartridge.Manufacturer" "Coleco, Ed English" "Cartridge.ModelNo" "2656" "Cartridge.Name" "Mr. Do! (1983) (Coleco)" "Display.YStart" "26" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b1a6c96e9093352106bc335e96caa154" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide Pre-release 1 (Joe Grand)" "Cartridge.Rarity" "New Release" "Display.YStart" "38" "" "Cartridge.MD5" "367411b78119299234772c08df10e134" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Skiing (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "ce904c0ae58d36d085cd506989116b0b" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "5687 A279" "Cartridge.Name" "International Soccer (1989) (Telegames) (PAL)" "" "Cartridge.MD5" "170e7589a48739cfb9cc782cbb0fe25a" "Cartridge.Manufacturer" "M Network, 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" "" "Cartridge.MD5" "047ac3b9faea64522b7a23c4465a7aa8" "Cartridge.Name" "Defender (Unknown) (PAL)" "" "Cartridge.MD5" "59135f13985b84c4f13cc9e55eec869a" "Cartridge.Name" "Multi-Sprite Game V2.0 (Piero Cavina) (PD)" "" "Cartridge.MD5" "2dfec1615c49501fefc02165c81955e6" "Cartridge.Name" "Song (05-11-2002) (Paul Slocum)" "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" "40e12c008037a323a1290c8fa4d2fe7f" "Cartridge.Name" "Skeleton (NTSC) (06-09-2002) (Eric Ball)" "Cartridge.Sound" "STEREO" "" "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" "b5efe0271d2214e4d5dc798881486884" "Cartridge.Manufacturer" "Atari - Axlon, Steve DeFrisco" "Cartridge.ModelNo" "CX26192" "Cartridge.Name" "Klax (06-14-1990) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "e643aaec9a9e1c8ab7fe1eae90bc77d7" "Cartridge.Manufacturer" "Roger Williams" "Cartridge.Name" "Asymmetric Playfield (Roger Williams)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "de5aab22e5aba5edcb29a3e7491ff319" "Cartridge.Manufacturer" "Star Game" "Cartridge.ModelNo" "001" "Cartridge.Name" "Donkey Kong (Star Game)" "Cartridge.Note" "AKA Spider Kong" "Display.YStart" "30" "" "Cartridge.MD5" "9bd4e0d5f28ba6da417c26649171f8e4" "Cartridge.Name" "Hangman Pac-Man Original Words (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "7b3cf0256e1fa0fdc538caf3d5d86337" "Cartridge.Manufacturer" "CommaVid, Joseph Biel" "Cartridge.ModelNo" "CM-009" "Cartridge.Name" "Stronghold (1983) (CommaVid)" "Display.YStart" "32" "" "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" "53d181cde2e0219b5754caad246fcb66" "Cartridge.Name" "Missile Demo (1998) (Ruffin Bailey) (PD)" "" "Cartridge.MD5" "1ee9c1ba95cef2cf987d63f176c54ac3" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker" "Cartridge.ModelNo" "CX2675, CX2675P" "Cartridge.Name" "Ms. Pac-Man (1982) (Atari) (PAL)" "" "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" "30" "" "Cartridge.MD5" "8b40a9ca1cfcd14822e2547eaa9df5c1" "Cartridge.Manufacturer" "Parker Brothers, Dave Hampton, Tom Sloper" "Cartridge.ModelNo" "931517" "Cartridge.Name" "Q-bert (1983) (Parker Bros) (PAL)" "" "Cartridge.MD5" "c2410d03820e0ff0a449fa6170f51211" "Cartridge.Name" "Pac-Man (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "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" "7ca7a471d70305c673fedd08174a81e8" "Cartridge.Manufacturer" "Tim Snider" "Cartridge.Name" "Venture II (2001) (Tim Snider)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ae18c11e4d7ed2437f0bf5d167c0e96c" "Cartridge.Name" "Multi-Color Demo 3 (Bob Colbert) (PD)" "" "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" "fd7464edaa8cc264b97ba0d13e7f0678" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "771-333" "Cartridge.Name" "2 Pak Special - Challenge, Surfing (1990) (HES) (PAL) [a]" "" "Cartridge.MD5" "d73ad614f1c2357997c88f37e75b18fe" "Cartridge.Manufacturer" "Puzzy - Bit Corporation" "Cartridge.ModelNo" "PG202" "Cartridge.Name" "Space Tunnel (1982) (Puzzy) (PAL)" "" "Cartridge.MD5" "27c6a2ca16ad7d814626ceea62fa8fb4" "Cartridge.Manufacturer" "Parker Brothers, Mark Lesser" "Cartridge.ModelNo" "PB5590" "Cartridge.Name" "Frogger II (1984) (Parker Bros)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "82bf0dff20cee6a1ed4bb834b00074e6" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-035" "Cartridge.Name" "Panda (Quest) (Suntek) (PAL)" "Cartridge.Note" "AKA Panda Chase" "" "Cartridge.MD5" "a5262fe6d01d6a1253692682a47f79dd" "Cartridge.Name" "JKH Text Scrolling Demo (PD)" "" "Cartridge.MD5" "7e4783a59972ae2cd8384f231757ea0b" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26139P" "Cartridge.Name" "Crossbow (1987) (Atari) (PAL)" "" "Cartridge.MD5" "e932f44fad2a66b6d5faec9addec208e" "Cartridge.Name" "Atari Logo Demo 1 (PD)" "" "Cartridge.MD5" "8068e07b484dfd661158b3771d6621ca" "Cartridge.Manufacturer" "Epyx, Steven A. Baker, Peter Engelbrite" "Cartridge.ModelNo" "80561-00286" "Cartridge.Name" "California Games (1988) (Epyx) (PAL)" "" "Cartridge.MD5" "c6ae21caceaad734987cb24243793bd5" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Frostbite (CCE)" "" "Cartridge.MD5" "5b85e987e2b1618769d97ba9182333d0" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein" "Cartridge.ModelNo" "CX2681" "Cartridge.Name" "Battlezone (05-12-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "e18abe87035379c56b435bfe8175077b" "Cartridge.Manufacturer" "Grimlock" "Cartridge.Name" "Rumble 2600 (Grimlock) (Hack)" "Cartridge.Note" "Hack of Mario Bros." "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "d7891b0faa4c7f764482762d0ed427a5" "Cartridge.Name" "Bars and Text Demo 2 (PD)" "" "Cartridge.MD5" "7e52a95074a66640fcfde124fffd491a" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, John Mracek" "Cartridge.ModelNo" "CX2673" "Cartridge.Name" "Phoenix (1982) (Atari)" "" "Cartridge.MD5" "99f7c6c26046bbe95f1c604b25da8360" "Cartridge.Manufacturer" "SnailSoft" "Cartridge.Name" "Comitoid beta 2 (SnailSoft)" "" "Cartridge.MD5" "6de924c2297c8733524952448d54a33c" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1006" "Cartridge.Name" "Moon Patrol (1983) (CCE)" "" "Cartridge.MD5" "8786f4609a66fbea2cd9aa48ca7aa11c" "Cartridge.Manufacturer" "Goliath" "Cartridge.ModelNo" "5" "Cartridge.Name" "Open Sesame (1983) (Goliath) (PAL)" "Display.Phosphor" "YES" "" "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.YStart" "29" "Display.Phosphor" "YES" "" "Cartridge.MD5" "335793736cbf6fc99c9359ed2a32a49d" "Cartridge.Name" "Analog Clock (V0.0) (20-01-2003) (AD) [a]" "" "Cartridge.MD5" "7481f0771bff13885b2ff2570cf90d7b" "Cartridge.Manufacturer" "Arcadia Corporation, Brian McGhie" "Cartridge.ModelNo" "AR-4104" "Cartridge.Name" "Rabbit Transit (1983) (Arcadia) (PAL)" "" "Cartridge.MD5" "171cd6b55267573e6a9c2921fb720794" "Cartridge.Manufacturer" "Kurt Howe" "Cartridge.Name" "Adventure 34 (Kurt Howe) (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "fece458a8023a809a5006867feca40e8" "Cartridge.Name" "SCSIcide (24-02-2001) (Joe Grand) (PD)" "" "Cartridge.MD5" "cb96b0cf90ab7777a2f6f05e8ad3f694" "Cartridge.Manufacturer" "Silvio Mogno" "Cartridge.Name" "Rainbow Invaders" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "39790a2e9030751d7db414e13f1b6960" "Cartridge.Name" "Robotfindskitten2600 (26-04-2003) (Jeremy Penner) [a1]" "" "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" "68878250e106eb6c7754bc2519d780a0" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-809" "Cartridge.Name" "Squirrel (1983) (CCE)" "Cartridge.Note" "AKA Snail Against Squirrel" "Display.YStart" "24" "Display.Height" "230" "" "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" "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" "82efe7984783e23a7c55266a5125c68e" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-837" "Cartridge.Name" "Pizza Chef (1983) (CCE)" "" "Cartridge.MD5" "ddd1efc1862cd3eb3baf4cba81ff5050" "Cartridge.Name" "Max3 (2001) (Maxime Beauvais) (PD)" "" "Cartridge.MD5" "d74a81fcd89c5cf0bd4c88eb207ebd62" "Cartridge.Name" "Poker Squares (V0.00a) (2001) (B. Watson)" "" "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" "606c2c1753051e03c1f1ac096c9d2832" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Crackpots (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "e73838c43040bcbc83e4204a3e72eef4" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Apples and Dolls (CCE)" "Cartridge.Note" "AKA Open Sesame" "Display.Phosphor" "YES" "" "Cartridge.MD5" "21d7334e406c2407e69dbddd7cec3583" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-011" "Cartridge.Name" "Stampede (1981) (Activision)" "" "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" "c4bc8c2e130d76346ebf8eb544991b46" "Cartridge.Manufacturer" "Imagic" "Cartridge.Name" "Imagic Selector ROM (1982) (Imagic) [a]" "" "Cartridge.MD5" "457f4ad2cda5f4803f122508bfbde3f5" "Cartridge.Name" "Canyon Bomber (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "2b1589c7e1f394ae6a1c046944f06688" "Cartridge.Manufacturer" "Carrere Video, Todd Marshall, Wes Trager, Henry Will IV - Teldec" "Cartridge.ModelNo" "USC2003" "Cartridge.Name" "Eggomania (1983) (Carrere Video) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "" "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" "15bf2ef7583bfcbbba630847a1dc5539" "Cartridge.Manufacturer" "Erik Eid" "Cartridge.Name" "Euchre (Jul 15) (2002) (Eric Eid) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "3685060707df27d4091ba0ea2dc4b059" "Cartridge.Name" "PezZerk - PezMan in Ghost Manor (Hack)" "Cartridge.Note" "Hack of Berzerk" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "071f84d10b343c7c05ce3e32af631687" "Cartridge.Manufacturer" "Videospielkassette - Ariola" "Cartridge.ModelNo" "PGP233" "Cartridge.Name" "Krieg der Sterne (Ariola) (PAL)" "Cartridge.Note" "AKA Atlantis" "" "Cartridge.MD5" "ebf9038e927e6a0db3e0d170c59911e6" "Cartridge.Name" "Pac-2600 (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "4476c39736090dabac09f6caf835fc49" "Cartridge.Name" "Text Screen (25-01-2003) (AD)" "" "Cartridge.MD5" "37ab3affc7987995784b59fcd3fcbd31" "Cartridge.Name" "Sprite Test (29-11-2002) (Eric Ball)" "" "Cartridge.MD5" "4565c1a7abce773e53c75b35414adefd" "Cartridge.Manufacturer" "Arcadia Corporation" "Cartridge.Name" "Supercharger BIOS (1982) (Arcadia)" "" "Cartridge.MD5" "413c925c5fdcea62842a63a4c671a5f2" "Cartridge.Manufacturer" "Activision, Larry Kaplan" "Cartridge.ModelNo" "AX-006" "Cartridge.Name" "Bridge (1980) (Activision) [fixed]" "" "Cartridge.MD5" "b59fd465abf76f64c85652ff29d5952d" "Cartridge.Manufacturer" "VentureVision, Dan Oliver" "Cartridge.Name" "Innerspace (1983) (VentureVision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "f4ab6bd5f80d8988141edde4c84b23b5" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX2624, CX2624P" "Cartridge.Name" "Basketball (1978) (Atari) (PAL) (4K)" "" "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" "6e19428387686a77d8c8d2f731cb09e0" "Cartridge.Name" "Purple Cross Demo (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "75ea60884c05ba496473c23a58edf12f" "Cartridge.Manufacturer" "Atari, Howard Scott Warshaw - Sears" "Cartridge.ModelNo" "CX2655 - 49-75167" "Cartridge.Name" "Yars' Revenge (1982) (Atari) (PAL) [a]" "Display.Phosphor" "YES" "" "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" "73c545db2afd5783d37c46004e4024c2" "Cartridge.Manufacturer" "CBS Electronics, Henry Will IV" "Cartridge.ModelNo" "4L1767, 4L1768, 4L1769, 4L1770" "Cartridge.Name" "Smurf (1982) (CBS Electronics) (PAL)" "" "Cartridge.MD5" "0805366f1b165a64b6d4df20d2c39d25" "Cartridge.Manufacturer" "Atari, Dan Hitchens" "Cartridge.ModelNo" "CX2650" "Cartridge.Name" "Berzerk (1982) (Atari) (PAL)" "Cartridge.Rarity" "Common" "" "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" "133456269a03e3fdae6cddd65754c50d" "Cartridge.Manufacturer" "Tigervision - Teldec" "Cartridge.ModelNo" "7-006 - 3.60008 VG" "Cartridge.Name" "Springer (1982) (Tigervision) (PAL)" "" "Cartridge.MD5" "bf976cf80bcf52c5f164c1d45f2b316b" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.ModelNo" "CX2657" "Cartridge.Name" "SwordQuest - FireWorld (1982) (Atari) (PAL)" "Cartridge.Note" "AKA Adventure II, SwordQuest II - FireWorld" "" "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" "7c7a4a2d505c2d0c75337c44711d8d54" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.Name" "Elf Adventure (04-22-83) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "de29e46dbea003c3c09c892d668b9413" "Cartridge.Manufacturer" "CBS Electronics, Steve 'Jessica' Kitchen" "Cartridge.ModelNo" "4L1717, 4L1718, 4L2277" "Cartridge.Name" "Carnival (1982) (CBS Electronics) (PAL)" "" "Cartridge.MD5" "c47b7389e76974fd0de3f088fea35576" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Mighty Mouse (Funvision)" "Cartridge.Note" "AKA Gopher" "" "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" "fec0c2e2ab0588ed20c750b58cf3baa3" "Cartridge.Manufacturer" "Activision, David Rolfe - Cheshire Engineering" "Cartridge.ModelNo" "EAZ-037-04, EAZ-037-04I" "Cartridge.Name" "Beamrider (1984) (Activision) (PAL)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "7450ae4e10ba8380c55b259d7c2b13e8" "Cartridge.Name" "Register Twiddler Demo 2 (PD)" "" "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" "53f147b9746fdc997c62f3dd67888ee5" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-011" "Cartridge.Name" "Stampede (1981) (Activision) (8K)" "" "Cartridge.MD5" "c150c76cbde2c9b5a97eb5399d46c64f" "Cartridge.Name" "Unknown Title (xxx00000 (200203)) (PD)" "" "Cartridge.MD5" "eb4252faff7a4f2ba5284a98b8f78d1a" "Cartridge.Name" "John K Harvey's Equalizer (NTSC) (PD)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "72097e9dc366900ba2da73a47e3e80f5" "Cartridge.Name" "Euchre (15-06-2001) (Eric Eid) (PD)" "" "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" "" "Cartridge.MD5" "da5096000db5fdaa8d02db57d9367998" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "River Raid (1983) (Digitel)" "" "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" "2d6741cda3000230f6bbdd5e31941c01" "Cartridge.Manufacturer" "CBS Electronics" "Cartridge.ModelNo" "80110" "Cartridge.Name" "Targ (1983) (CBS Electronics) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "befce0de2012b24fd6cb8b53c17c8271" "Cartridge.Name" "Push (V0.03) (No Illegal Opcodes) (1998) (AD)" "" "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" "2854e5dfb84173fafc5bf485c3e69d5a" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.ModelNo" "C 3004" "Cartridge.Name" "Moon Patrol (Canal 3)" "" "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" "6cd506509e8fd5627f55603780e862a8" "Cartridge.Manufacturer" "Greg Troutman" "Cartridge.Name" "Dark Mage (SuperCharger) (Greg Troutman) (PD)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d6dc9b4508da407e2437bfa4de53d1b2" "Cartridge.Manufacturer" "Bomb - Onbase" "Cartridge.ModelNo" "CA283" "Cartridge.Name" "Z-Tack (1983) (Bomb) (PAL)" "Cartridge.Note" "AKA Base Attack" "" "Cartridge.MD5" "cbc373fbcb1653b4c56bfabba33ea50d" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Super Voleyball (CCE)" "Cartridge.Note" "AKA RealSports Volleyball" "" "Cartridge.MD5" "91191666186117f5bf78b40623d79039" "Cartridge.Manufacturer" "Gray Games & AtariAge" "Cartridge.Name" "E.T. Book Cart (PAL)" "Cartridge.Note" "Charles F. Gray & Michael Rideout" "Display.YStart" "23" "Display.Height" "280" "Display.Phosphor" "YES" "Display.PPBlend" "55" "" "Cartridge.MD5" "384db97670817103dd8c0bbdef132445" "Cartridge.Manufacturer" "Atari - Sears" "Cartridge.ModelNo" "CX2626 - 6-99829, 49-75116" "Cartridge.Name" "Miniature Golf (1979) (Atari) (4K)" "" "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" "082fdc8bd47fef01482ce5883c4ffdb8" "Cartridge.Manufacturer" "Charles Morgan" "Cartridge.Name" "Tanks DX (Charles Morgan) (Hack)" "Cartridge.Note" "Hack of Tanks But No Tanks" "Cartridge.Rarity" "Hack" "Display.YStart" "30" "" "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" "61719a8bdafbd8dab3ca9ce7b171b9e2" "Cartridge.Name" "Enduro (Unknown) (PAL)" "" "Cartridge.MD5" "d20e61c86ed729780feca162166912ca" "Cartridge.Manufacturer" "Supergame" "Cartridge.ModelNo" "32" "Cartridge.Name" "Pitfall (1984) (Supergame)" "Cartridge.Note" "AKA Pitfall!" "" "Cartridge.MD5" "faffd84f3a8eceee2fa5ea5b0a3e6678" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-025" "Cartridge.Name" "Spectracube Invasion (Suntek) (PAL)" "Cartridge.Note" "AKA Immies & Aggies" "" "Cartridge.MD5" "2683d29a282dd059535ac3bb250f540d" "Cartridge.Name" "Space Treat (12-01-2003) (Fabrizio Zavagli)" "" "Cartridge.MD5" "1619bc27632f9148d8480cd813aa74c3" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Steeple Chase (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Console.RightDifficulty" "A" "Display.YStart" "20" "Display.Height" "220" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b6812eaf87127f043e78f91f2028f9f4" "Cartridge.Manufacturer" "Simage" "Cartridge.Name" "Eli's Ladder (1982) (Simage)" "" "Cartridge.MD5" "5c73693a89b06e5a09f1721a13176f95" "Cartridge.Name" "Wavy Line Test 2 (PD)" "" "Cartridge.MD5" "813985a940aa739cc28df19e0edd4722" "Cartridge.Manufacturer" "Imagic, Bob Smith" "Cartridge.ModelNo" "720000-201, 720102-1B, IA3201" "Cartridge.Name" "Star Voyager (1982) (Imagic)" "" "Cartridge.MD5" "1c8c42d1aee5010b30e7f1992d69216e" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "205" "Cartridge.Name" "Gigolo (1982) (PlayAround)" "Display.Phosphor" "YES" "" "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" "" "Cartridge.MD5" "b879e13fd99382e09bcaf1d87ad84add" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Time Warp (Zellers)" "Display.YStart" "30" "" "Cartridge.MD5" "850ffd5849c911946b24544ea1e60496" "Cartridge.Name" "Invasion (07-10-2002) (CT)" "" "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" "Display.YStart" "38" "" "Cartridge.MD5" "273ce50db5a0d6da7ea827a54f44dee9" "Cartridge.Name" "Island Flyer Demo (PD)" "" "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" "40" "" "Cartridge.MD5" "ead60451c28635b55ca8fea198444e16" "Cartridge.Manufacturer" "Sancho - Tang's Electronic Co." "Cartridge.ModelNo" "TEC004" "Cartridge.Name" "Nightmare (1983) (Sancho) (PAL)" "Display.YStart" "43" "Display.Height" "256" "" "Cartridge.MD5" "b64426e787f04ff23ee629182c168603" "Cartridge.Manufacturer" "Dynacom" "Cartridge.Name" "Plaque Attack (1983) (Dynacom)" "" "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" "ae047e9468bda961d8e9e9d8ff52980f" "Cartridge.Name" "Tunnel Demo (Red Spiral) (30-03-2003) (AD)" "" "Cartridge.MD5" "78c2de58e42cd1faac2ea7df783eaeb3" "Cartridge.Name" "Fu Kung! (V0.07) (25-01-2003) (AD)" "" "Cartridge.MD5" "ed2218b3075d15eaa34e3356025ccca3" "Cartridge.Manufacturer" "Atari, Richard Maurer" "Cartridge.ModelNo" "CX2635, CX2635P" "Cartridge.Name" "Maze Craze (1980) (Atari) (PAL)" "Display.Format" "PAL" "" "Cartridge.MD5" "2516f4f4b811ede4ecf6fbeb5d54a299" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "701.134 9" "Cartridge.Name" "Schiessbude (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Carnival" "" "Cartridge.MD5" "30c92c685224dc7a72b9bbe5eb62d004" "Cartridge.Name" "Hangman Monkey Original Words (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "c7900a7fe95a47eef3b325072ad2c232" "Cartridge.Manufacturer" "Larry Petit" "Cartridge.Name" "Super Congo Bongo (2003) (Larry Petit) (Hack)" "Cartridge.Note" "Hack of Bongo" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "b731d35e4ac6b3b47eba5dd0991f452f" "Cartridge.Name" "Rubik's Cube 3D Demo (Final) (08-01-2003) (TJ)" "" "Cartridge.MD5" "3d1e83afdb4265fa2fb84819c9cfd39c" "Cartridge.Manufacturer" "Coleco, Henry Will IV" "Cartridge.ModelNo" "2465" "Cartridge.Name" "Smurf - Rescue in Gargamel's Castle (1982) (Coleco)" "Cartridge.Note" "AKA Smurf, Smurf Action" "" "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" "d5e5b3ec074fff8976017ef121d26129" "Cartridge.Manufacturer" "Star Game" "Cartridge.ModelNo" "003" "Cartridge.Name" "River Raid (Star Game)" "" "Cartridge.MD5" "02811151906e477d47c135db5b1699c6" "Cartridge.Name" "FlickerSort Demo (Updated) (20-04-2002) (MP)" "" "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" "75ea128ba96ac6db8edf54b071027c4e" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Slot Machine (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "572d0a4633d6a9407d3ba83083536e0f" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Busy Police (Funvision)" "Cartridge.Note" "AKA Keystone Kapers" "" "Cartridge.MD5" "cf0c593c563c84fdaf0f741adb367445" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.05) (2001) (Retroactive)" "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" "1bc2427ac9b032a52fe527c7b26ce22c" "Cartridge.Manufacturer" "Intellivision Productions - M Network, Bruce Pedersen, Larry Zwick" "Cartridge.ModelNo" "MT5860" "Cartridge.Name" "Sea Battle (1983) (M Network)" "Cartridge.Note" "High Seas" "" "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" "29dfa26b7988af9984d617708e4fc6e2" "Cartridge.Name" "Boulderdash Demo (05-04-2003) (AD)" "" "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" "3eb1e34a4f0eec36f12e7336badcecf2" "Cartridge.Manufacturer" "Jake Patterson" "Cartridge.Name" "Baubles (V0.001) (2001) (Jake Patterson) (PD)" "Cartridge.Rarity" "Homebrew" "" "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" "de7a64108074098ba333cc0c70eef18a" "Cartridge.Name" "Nuts (Unknown)" "" "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" "ac0ddbcff34d064009591607746e33b8" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Atlantis FH (2003) (TJ) (Hack)" "Cartridge.Note" "Hack of Atlantis" "Cartridge.Rarity" "Hack" "" "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" "Display.YStart" "30" "" "Cartridge.MD5" "3a53963f053b22599db6ac9686f7722f" "Cartridge.Name" "Word Zapper (208 in 1) (Unknown) (PAL)" "" "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" "f6f1b27efc247a0e8d473ddb4269ff9e" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "429.663 8" "Cartridge.Name" "Schnapp die Apfeldiebe (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Plaque Attack" "" "Cartridge.MD5" "a875f0a919129b4f1b5103ddd200d2fe" "Cartridge.Manufacturer" "Atari, Dan Hitchens" "Cartridge.ModelNo" "CX2656" "Cartridge.Name" "SwordQuest - EarthWorld (1982) (Atari) (PAL)" "Cartridge.Note" "AKA Adventure I, SwordQuest I - EarthWorld" "" "Cartridge.MD5" "94102febc53b4a78342d11b645342ed4" "Cartridge.Name" "Joustpong (14-07-2002) (Kirk Israel) (PD)" "" "Cartridge.MD5" "eae6a5510055341d3abeb45667bb3e9b" "Cartridge.Manufacturer" "HES" "Cartridge.Name" "Wall Defender (HES) (PAL)" "Cartridge.Note" "AKA Wall Break" "" "Cartridge.MD5" "a406d2f6d84e61d842f4cb13b2b1cfa7" "Cartridge.Manufacturer" "Tigervision, John Harris - Teldec" "Cartridge.ModelNo" "7-002" "Cartridge.Name" "Jawbreaker (1982) (Tigervision) (PAL)" "" "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" "41818738ab1745e879024a17784d71f5" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-832" "Cartridge.Name" "Atlantis (1983) (CCE)" "" "Cartridge.MD5" "826481f6fc53ea47c9f272f7050eedf7" "Cartridge.Manufacturer" "Imagic, Dennis Koble" "Cartridge.ModelNo" "720103-1A, IA3203" "Cartridge.Name" "Atlantis II (1982) (Imagic)" "" "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" "402b1ca3c230a60fb279d4a2a10fa677" "Cartridge.Name" "3-D Tic-Tac-Toe (Unknown) (PAL) (4K)" "Display.YStart" "62" "" "Cartridge.MD5" "7dfd100bda9abb0f3744361bc7112681" "Cartridge.Manufacturer" "Telesys, Don 'Donyo' Ruffcorn" "Cartridge.ModelNo" "1006" "Cartridge.Name" "Demolition Herby (1983) (Telesys) (PAL)" "Display.Phosphor" "YES" "" "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" "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" "1a23540d91f87584a04f184304a00648" "Cartridge.Name" "Race Demo (PD)" "" "Cartridge.MD5" "e3c35eac234537396a865d23bafb1c84" "Cartridge.Manufacturer" "TechnoVision" "Cartridge.ModelNo" "TVS1001" "Cartridge.Name" "Nuts (1983) (TechnoVision) (PAL)" "" "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" "5ef303b9f0aa8cf20720c560e5f9baa1" "Cartridge.Manufacturer" "Atari, Jim Huether" "Cartridge.ModelNo" "CX2629, CX2629P" "Cartridge.Name" "Sky Diver (1979) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "efd387430a35a659ff569a9a0ec22209" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX26118" "Cartridge.Name" "Millipede (1984) (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "ef71e9fb0d8d477226d8d42261fbf0a7" "Cartridge.Manufacturer" "Piero Cavina" "Cartridge.Name" "Multi-Sprite Demo V2.0 (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "c8c7da12f087e8d16d3e6a21b371a5d3" "Cartridge.Name" "Demo Image Series #9 - Genius (28-02-2003) (AD)" "" "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" "dd1422ffd538e2e33b339ebeef4f259d" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.Name" "Red Vs. Blue (1981) (Atari) (Prototype)" "Cartridge.Note" "RealSports Football Beta" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "5babe0cad3ec99d76b0aa1d36a695d2f" "Cartridge.Manufacturer" "Coleco, Ed Temple" "Cartridge.ModelNo" "2654" "Cartridge.Name" "Looping (1983) (Coleco) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "24" "" "Cartridge.MD5" "2c3b2843295c9d6b16996971180a3fe9" "Cartridge.Manufacturer" "HES - Activision" "Cartridge.Name" "Sports Action Pak - Enduro, Ice Hockey, Fishing Derby, Dragster (1988) (HES) (PAL)" "" "Cartridge.MD5" "3ab5d138e26d88c8190e7cc629a89493" "Cartridge.Name" "Phased Color Demo (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a20d931a8fddcd6f6116ed21ff5c4832" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Ed Salvo, Byron Parks" "Cartridge.ModelNo" "AP-2003" "Cartridge.Name" "Racquetball (1981) (Apollo) [a]" "Display.Phosphor" "YES" "" "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" "fbb4f3debf48dc961b559384467f2057" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "River Raid III (1985) (Digitel)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "75b22fdf632d76e246433db1ebccd3c4" "Cartridge.Name" "Skeleton+ (05-05-2003) (Eric Ball) (PAL)" "Cartridge.Sound" "STEREO" "" "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" "fae0b86934a7c5a362281dffebdb43a0" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.07) (Retroactive) (PAL)" "Display.Phosphor" "YES" "" "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" "65562f686b267b21b81c4dddc129d724" "Cartridge.Name" "Euchre (28-07-2001) (Eric Eid) (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" "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" "3b5751a8d20f7de41eb069f76fecd5d7" "Cartridge.Name" "Eckhard Stolberg's Scrolling Text Demo 4 (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "3889351c6c2100b9f3aef817a7e17a7a" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Dolphin (CCE)" "" "Cartridge.MD5" "f7a651972d78f9ba485b14690452d4be" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "Homestar Runner Demo #2 (2004-03-29)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cd3e26786136a4692fd2cb2dfbc1927e" "Cartridge.Name" "Multiple Moving Objects Demo 2 (B. Watson)" "" "Cartridge.MD5" "8af58a9b90b25907da0251ec0facf3b8" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Cosmic Swarm (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "Display.YStart" "30" "" "Cartridge.MD5" "21b09c40295c2d7074a83ae040f22edf" "Cartridge.Name" "Marble Craze (V0.90) (Easy Version) (Paul Slocum)" "" "Cartridge.MD5" "136f75c4dd02c29283752b7e5799f978" "Cartridge.Manufacturer" "Atari, Dan Hitchens - Sears" "Cartridge.ModelNo" "CX2650 - 49-75168" "Cartridge.Name" "Berzerk (1982) (Atari)" "Cartridge.Rarity" "Common" "" "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" "be561b286b6432cac71bccbae68002f7" "Cartridge.Name" "Counter Demo (PD)" "" "Cartridge.MD5" "8905d54f48b8024fc718ed643e9033f7" "Cartridge.Manufacturer" "Coleco, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (05-24-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "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" "e8a3473bf786cf796d1336d2d03a0008" "Cartridge.Manufacturer" "Parker Brothers, Wilfredo 'Willy' Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart" "Cartridge.Name" "Star Wars - The Arcade Game (12-05-1983) (Parker Bros) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f74ad642552385c3daa203a2a6fc2291" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Cubis (1997) (Eckhard Stolberg)" "Cartridge.Rarity" "New Release" "" "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" "6c449db9bbbd90972ad1932d6af87330" "Cartridge.Name" "20 Sprites at Once Demo 3 (PD)" "" "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" "11e7e0d9437ec98fa085284cf16d0eb4" "Cartridge.Name" "Bowling (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "f77f5fc3893da5d00198e4cd96544aad" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Stampede (Canal 3)" "" "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" "Display.YStart" "42" "" "Cartridge.MD5" "deb39482e77f984d4ce73be9fd8adabd" "Cartridge.Manufacturer" "Activision, David Lubar" "Cartridge.ModelNo" "AK-048-04" "Cartridge.Name" "River Raid II (1988) (Activision) [a]" "" "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" "2450dfa1df70d12b60683185775efed8" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 7 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "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" "" "Cartridge.MD5" "297c405afd01f3ac48cdb67b00d273fe" "Cartridge.Manufacturer" "Atari - GCC, Ava-Robin Cohen" "Cartridge.ModelNo" "CX26123, CX26123P" "Cartridge.Name" "Jr. Pac-Man (1984) (Atari) (PAL)" "" "Cartridge.MD5" "d17a8c440d6be79fae393a4b46661164" "Cartridge.Name" "Warring Worms (Beta 3) (2002) (Billy Eno)" "" "Cartridge.MD5" "dea0ade296f7093e71185e802b500db8" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Fishing Derby (CCE)" "" "Cartridge.MD5" "40d9f5709877ecf3dd1184f9791dd35e" "Cartridge.Manufacturer" "Dactari - Milmar" "Cartridge.Name" "Skiing (Dactari - Milmar)" "" "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" "8a49cf1785e3dea2012d331a3ad476e1" "Cartridge.Name" "Boulderdash (10 Blocks Wide) (02-04-2003) (AD)" "" "Cartridge.MD5" "34340c8eecd1e557314789cc6477e650" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide Pre-release 4 (Joe Grand)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "45040679d72b101189c298a864a5b5ba" "Cartridge.Manufacturer" "20th Century Fox Video Games, David Lubar" "Cartridge.ModelNo" "11022" "Cartridge.Name" "SpaceMaster X-7 (1983) (20th Century Fox)" "" "Cartridge.MD5" "3b86a27132fb74d9b35d4783605a1bcb" "Cartridge.Manufacturer" "Atari, Chris Crawford" "Cartridge.Name" "Wizard (1980) (Atari) (Prototype) (4K)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "ffdc0eb3543404eb4c353fbdddfa33b6" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-827" "Cartridge.Name" "Chopper Command (1983) (CCE) [a]" "" "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" "Display.YStart" "36" "" "Cartridge.MD5" "75e276ba12dc4504659481c31345703a" "Cartridge.Manufacturer" "Arcadia Corporation, Kevin Norman" "Cartridge.ModelNo" "AR-4103" "Cartridge.Name" "Killer Satellites (1983) (Arcadia) (PAL)" "" "Cartridge.MD5" "b24f6a5820a4b7763a3d547e3e07441d" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-823" "Cartridge.Name" "Demon Attack (1983) (CCE)" "" "Cartridge.MD5" "703d32062436e4c20c48313dff30e257" "Cartridge.Name" "Moving Maze Demo (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b8ed78afdb1e6cfe44ef6e3428789d5f" "Cartridge.Manufacturer" "Data Age" "Cartridge.ModelNo" "112-007" "Cartridge.Name" "Bermuda Triangle (1982) (Data Age)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "4093382187f8387e6d011883e8ea519b" "Cartridge.Name" "Go Go Home Monster (Unknown)" "Display.Height" "220" "" "Cartridge.MD5" "5b92a93b23523ff16e2789b820e2a4c5" "Cartridge.Manufacturer" "Activision, Dan Kitchen" "Cartridge.ModelNo" "AG-039-04" "Cartridge.Name" "Kung-Fu Master (1987) (Activision)" "" "Cartridge.MD5" "ed5ccfc93ad4561075436ee42a15438a" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX2626, CX2626P" "Cartridge.Name" "Miniature Golf (1979) (Atari) (PAL)" "" "Cartridge.MD5" "b95a6274ca0e0c773bfdc06b4c3daa42" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "3-D Corridor (29-03-2003) (Paul Slocum)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "9ea8ed9dec03082973244a080941e58a" "Cartridge.Manufacturer" "Eric Mooney, Piero Cavina" "Cartridge.Name" "INV+" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "9364ad51c321e0f15c96a8c0aff47ceb" "Cartridge.Manufacturer" "Atari, Rob Fulop" "Cartridge.ModelNo" "CX2638" "Cartridge.Name" "Missile Command (1981) (Atari) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5df32450b9fbcaf43f9d83bd66bd5a81" "Cartridge.Manufacturer" "Eric Ball" "Cartridge.Name" "Atari Logo Playfield Demo (2001) (Eric Ball) (PD)" "Cartridge.Rarity" "Homebrew" "" "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" "dd7598b8bcb81590428900f71b720efb" "Cartridge.Manufacturer" "Xonox - K-Tel Software" "Cartridge.ModelNo" "99005, 6220, 6250" "Cartridge.Name" "Robin Hood (1983) (Xonox) (PAL)" "Display.YStart" "30" "" "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" "abc64037ca5d5b04ae8a7eedbca3ed74" "Cartridge.Name" "Green and Yellow Number 1 Demo (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "191ac4eec767358ee3ec3756c120423a" "Cartridge.Name" "Checkers (208 in 1) (Unknown) (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" "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" "ba317f83cdfcd58cbc65aac1ccb87bc5" "Cartridge.Name" "Jammed (2001) (XYPE) [a1]" "" "Cartridge.MD5" "de1a636d098349be11bbc2d090f4e9cf" "Cartridge.Name" "Pressure Gauge (Hozer Video Games)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "94b92a882f6dbaa6993a46e2dcc58402" "Cartridge.Manufacturer" "Activision, Larry Miller" "Cartridge.ModelNo" "AX-026, AX-026-04" "Cartridge.Name" "Enduro (1983) (Activision)" "" "Cartridge.MD5" "5f786b67e05fb9985b77d4beb35e06ee" "Cartridge.Manufacturer" "Atari, Bill Aspromonte, Andrew Fuchs" "Cartridge.ModelNo" "CX26120" "Cartridge.Name" "Defender II (1988) (Atari) (PAL)" "Cartridge.Note" "AKA Stargate" "" "Cartridge.MD5" "e9e6ad30549a6e2cd89fe93b7691d447" "Cartridge.Manufacturer" "Atari, Robert C. Polaro" "Cartridge.ModelNo" "CX26140, CX26140P" "Cartridge.Name" "Desert Falcon (05-27-1987) (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "12937db3d4a80da5c4452b752891252d" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Megamania (1983) (Digitel)" "" "Cartridge.MD5" "8d8b7d7b983f75debbdaac651e814768" "Cartridge.Name" "Demo Image Series #15 - Three Marios (PAL) (06-03-2003) (AD)" "" "Cartridge.MD5" "3c853d864a1d5534ed0d4b325347f131" "Cartridge.Manufacturer" "Telesys, Don 'Donyo' Ruffcorn" "Cartridge.ModelNo" "1002" "Cartridge.Name" "Cosmic Creeps (1982) (Telesys)" "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" "5b6f5bcbbde42fc77d0bdb3146693565" "Cartridge.Name" "Seaquest (Unknown) (PAL)" "" "Cartridge.MD5" "dc905b22de0f191a029df13eddfcabc4" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.Name" "Elf Adventure (05-02-83) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "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" "c3f53993ade534b0982ca3a286c85bb5" "Cartridge.Name" "Full Screen Bitmap Drawing System (12-02-2003) (AD)" "" "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" "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" "" "Cartridge.MD5" "75028162bfc4cc8e74b04e320f9e6a3f" "Cartridge.Manufacturer" "Atari, Greg Easter, Mimi Nyden" "Cartridge.ModelNo" "CX26107" "Cartridge.Name" "Snow White and the Seven Dwarfs (02-09-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7ed61a18cebdeca0a93be1f5461731e5" "Cartridge.Manufacturer" "Dactari" "Cartridge.Name" "Skiing (Dactari) (4K)" "" "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" "0b4e793c9425175498f5a65a3e960086" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Kung Fu Master (CCE)" "" "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" "728152f5ae6fdd0d3a9b88709bee6c7a" "Cartridge.Manufacturer" "Spectravideo, Mark Turmell" "Cartridge.ModelNo" "SA-217" "Cartridge.Name" "Gas Hog (1983) (Spectravideo)" "" "Cartridge.MD5" "3025bdc30b5aec9fb40668787f67d24c" "Cartridge.Name" "Demo Image Series #14 - Two Marios (4K Interleaved Chronocolour Vertical Movement) (05-03-2003) (AD)" "" "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.Rarity" "Prototype" "" "Cartridge.MD5" "b9f9c0fed0db08c34346317f3957a945" "Cartridge.Manufacturer" "SuperVision" "Cartridge.ModelNo" "405, 427, 806, 808, 813, 816" "Cartridge.Name" "Chopper Command (SuperVision) (PAL)" "" "Cartridge.MD5" "1cad3b56cc0e6e858554e46d08952861" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Chopper Command (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "c16c79aad6272baffb8aae9a7fff0864" "Cartridge.Manufacturer" "U.S. Games Corporation, Sylvia Day, Henry Will IV" "Cartridge.ModelNo" "VC2001" "Cartridge.Name" "Gopher (1982) (U.S. Games)" "Cartridge.Note" "AKA Gopher Attack" "" "Cartridge.MD5" "9a4274409216ff09ecde799f2a56ac73" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-801" "Cartridge.Name" "Mr. Postman (1983) (CCE) [a]" "" "Cartridge.MD5" "7454786af7126ccc7a0c31fcf5af40f1" "Cartridge.Name" "Phantom Tank (Unknown) (PAL)" "" "Cartridge.MD5" "e314b42761cd13c03def744b4afc7b1b" "Cartridge.Manufacturer" "Activision, David Crane, Dan Kitchen" "Cartridge.ModelNo" "AZ-108-04" "Cartridge.Name" "Ghostbusters (1985) (Activision)" "" "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" "cd38ad19f51b1048d8e5e99c86a2a655" "Cartridge.Name" "Demo Image Series #5 - Flag (19-02-2003) (AD)" "" "Cartridge.MD5" "22b22c4ce240303012e8a9596ae8d189" "Cartridge.Name" "Skeleton+ (03-05-2003) (Eric Ball) (PAL)" "Cartridge.Sound" "STEREO" "" "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" "b958d5fd9574c5cf9ece4b9421c28ecd" "Cartridge.Manufacturer" "Piero Cavina" "Cartridge.Name" "Multi-Sprite Game V1.0 (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "4799a40b6e889370b7ee55c17ba65141" "Cartridge.Manufacturer" "Konami" "Cartridge.ModelNo" "RC 100-X 02" "Cartridge.Name" "Pooyan (1983) (Konami)" "Display.YStart" "26" "Display.Height" "220" "" "Cartridge.MD5" "df6a46714960a3e39b57b3c3983801b5" "Cartridge.Manufacturer" "Puzzy - Bit Corporation" "Cartridge.ModelNo" "PG201" "Cartridge.Name" "Sea Monster (1982) (Puzzy) (PAL)" "" "Cartridge.MD5" "38c362dcd5cad5a62e73ae52631bd9d8" "Cartridge.Manufacturer" "Jake Patterson" "Cartridge.Name" "Baubles (14-11-2001) (Jake Patterson) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "f5445b52999e229e3789c39e7ee99947" "Cartridge.Manufacturer" "Atari, Jim Huether" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Flag Capture (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "8e42674972d6805068fc653e014370fd" "Cartridge.Name" "Skeleton (PAL) (15-10-2002) (Eric Ball)" "" "Cartridge.MD5" "14b1e30982962c72f426e2e763eb4274" "Cartridge.Manufacturer" "Atari, Carol Shaw - Ralph Lauren" "Cartridge.Name" "Polo (1978) (Atari) (Prototype) (4K)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "3105967f7222cc36a5ac6e5f6e89a0b4" "Cartridge.Manufacturer" "Sega, Jeff Lorenz - Bally Midway" "Cartridge.ModelNo" "011-01, 011-02" "Cartridge.Name" "Spy Hunter (1984) (Sega)" "Cartridge.Note" "Uses Joystick Coupler (Dual Control Module)" "Display.YStart" "29" "" "Cartridge.MD5" "5d0e8a25cbd23e76f843c75a86b7e15b" "Cartridge.Manufacturer" "Coleco, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (09-07-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "039cf18b459d33b8a8fca31d06c4c244" "Cartridge.Name" "Demo Image Series #0 (12-02-2003) (AD)" "" "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" "b4a4c87840613f102acb5b3a647d0a67" "Cartridge.Name" "Mobile 48 Sprite Kernel (04-01-2003) (Eric Ball)" "" "Cartridge.MD5" "c4060a31d61ba857e756430a0a15ed2e" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Pick 'n Pile (2003) (TJ)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Display.YStart" "25" "Display.Height" "220" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8372eec01a08c60dbed063c5524cdfb1" "Cartridge.Name" "Cross Force (Unknown) (PAL)" "" "Cartridge.MD5" "947317a89af38a49c4864d6bdd6a91fb" "Cartridge.Manufacturer" "CBS Electronics, Bob Curtiss" "Cartridge.ModelNo" "4L 2487 5000" "Cartridge.Name" "Solar Fox (1983) (CBS Electronics)" "" "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" "c05f367fa4767ceb27abadf0066df7f4" "Cartridge.Name" "TomInv (31-07-2001) (TJ)" "" "Cartridge.MD5" "ded26e1cb17f875a9c17515c900f9933" "Cartridge.Name" "Space Treat (29-12-2002) (Fabrizio Zavagli)" "" "Cartridge.MD5" "be3f0e827e2f748819dac2a22d6ac823" "Cartridge.Manufacturer" "Puzzy - Bit Corporation" "Cartridge.ModelNo" "PG202" "Cartridge.Name" "Space Tunnel (1982) (Puzzy)" "Display.Height" "215" "" "Cartridge.MD5" "5336f86f6b982cc925532f2e80aa1e17" "Cartridge.Manufacturer" "Parker Brothers, Ray Miller, Todd Marshall" "Cartridge.ModelNo" "PB5060" "Cartridge.Name" "Star Wars - Death Star Battle (1983) (Parker Bros)" "Display.Phosphor" "YES" "" "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" "3882224adbd0ca7c748b2a1c9b87263e" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.ModelNo" "CX2657" "Cartridge.Name" "SwordQuest - FireWorld (1982) (Atari) (PAL) [a]" "" "Cartridge.MD5" "463dd4770506e6c0ef993a40c52c47be" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Hales, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4102" "Cartridge.Name" "Suicide Mission (Preview) (1982) (Arcadia)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "63d6247f35902ba32aa49e7660b0ecaa" "Cartridge.Name" "Space War (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "8a42e2c7266439d8997a55d0124c912c" "Cartridge.Name" "Hangman Invader Wordlist (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "590ac71fa5f71d3eb29c41023b09ade9" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker" "Cartridge.ModelNo" "CX2684" "Cartridge.Name" "Galaxian (01-05-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "98ec0fa4199b9c01f7b8fa3732e43372" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AX-018, AX-018-04" "Cartridge.Name" "Pitfall! (1982) (Activision) (8K)" "" "Cartridge.MD5" "199985cae1c0123ab1aef921daace8be" "Cartridge.Name" "Euchre (Release Candidate 2) (PAL) (01-10-2002) (Erik Eid)" "" "Cartridge.MD5" "cfe62ed7125ff9fae99b4c8a367c0399" "Cartridge.Manufacturer" "Activision, Larry Miller" "Cartridge.ModelNo" "AX-026, AX-026-04" "Cartridge.Name" "Enduro (1983) (Activision) (16K)" "" "Cartridge.MD5" "1bb91bae919ddbd655fa25c54ea6f532" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-026" "Cartridge.Name" "Treasure Island (Suntek) (PAL)" "Cartridge.Note" "AKA Treasure Discovery" "" "Cartridge.MD5" "8454ed9787c9d8211748ccddb673e920" "Cartridge.Manufacturer" "Froggo" "Cartridge.ModelNo" "FG1002" "Cartridge.Name" "Spiderdroid (1987) (Froggo)" "Cartridge.Note" "AKA Amidar" "" "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" "3177cc5c04c1a4080a927dfa4099482b" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26135" "Cartridge.Name" "RealSports Boxing (1987) (Atari)" "" "Cartridge.MD5" "0ef64cdbecccb7049752a3de0b7ade14" "Cartridge.Manufacturer" "Atari, Joe Decuir, Steve Mayer, Larry Wagner" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Combat (32 in 1) (1988) (Atari) (PAL)" "Display.YStart" "39" "Display.Height" "256" "" "Cartridge.MD5" "bc4cf38a4bee45752dc466c98ed7ad09" "Cartridge.Manufacturer" "Atari, Douglas Neubauer" "Cartridge.ModelNo" "CX26136" "Cartridge.Name" "Solaris (1986) (Atari) (PAL)" "Cartridge.Note" "AKA Universe, Star Raiders II, The Last Starfighter" "" "Cartridge.MD5" "814210c0e121f7dbc25661b93c06311c" "Cartridge.Name" "Joustpong (16-09-2002) (Kirk Israel) (PD)" "" "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" "cdc1a5c61d7488eadc9aba36166b253d" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.12) (Stella) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7ead257e8b5a44cac538f5f54c7a0023" "Cartridge.Manufacturer" "Xonox, Anthony R. Henderson" "Cartridge.ModelNo" "99006, 6220" "Cartridge.Name" "Sir Lancelot (1983) (Xonox) [a1]" "" "Cartridge.MD5" "9a165c39af3f050fdee6583fdfcdc9be" "Cartridge.Manufacturer" "Zirok" "Cartridge.Name" "Mario Bros. (Zirok)" "" "Cartridge.MD5" "4d0a28443f7df5f883cf669894164cfa" "Cartridge.Name" "Beast Invaders (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "3a35d7f1dc2a33565c8dca52baa86bc4" "Cartridge.Name" "Rubik's Cube Demo 2 (23-12-2002) (CT)" "" "Cartridge.MD5" "0ac0d491763153fac75f5337ce32a9d6" "Cartridge.Name" "SPAM Image Demo (PD)" "" "Cartridge.MD5" "a8101cb667e50a46165c6fb48c608b6b" "Cartridge.Name" "Kung Fu Sprite Demo (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "218b76f5a4142dc2ea9051a768583d70" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker" "Cartridge.ModelNo" "CX2684, CX2684P" "Cartridge.Name" "Galaxian (1983) (Atari) (PAL) [a2]" "" "Cartridge.MD5" "dad2ab5f66f98674f12c92abcfbf3a20" "Cartridge.Name" "Blue and White Sprite Demo (PD)" "" "Cartridge.MD5" "9e01f7f95cb8596765e03b9a36e8e33c" "Cartridge.Manufacturer" "Atari, 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" "fabca526d57de46768b392f758f1a008" "Cartridge.Name" "Laseresal 2600 (16-12-2001) (Andrew Wallace) (PD)" "" "Cartridge.MD5" "00dc28b881989c39a6cf87a892bd3c6b" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Krull (CCE)" "" "Cartridge.MD5" "7ffc2d80fd49a124808315306d19868e" "Cartridge.Manufacturer" "Ishido" "Cartridge.Name" "Domino (Ishido) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "efffafc17b7cb01b9ca35324aa767364" "Cartridge.Name" "Circus Atari (Unknown)" "" "Cartridge.MD5" "a25bb76e9e773117e567fd4300b1bb23" "Cartridge.Name" "Interleaved ChronoColour Demo (NTSC) (05-03-2003) (AD)" "" "Cartridge.MD5" "72db1194b1cc7d45b242f25eb1c148d3" "Cartridge.Name" "Pac-Man (1981) (Atari) (Hack)" "Cartridge.Note" "Hack of Pac-Man" "Cartridge.Rarity" "Hack" "Display.YStart" "33" "" "Cartridge.MD5" "707ecd80030e85751ef311ced66220bc" "Cartridge.Name" "Double-Height 6-Digit Score Display (Background Color Change) (2001) (AD)" "" "Cartridge.MD5" "700a786471c8a91ec09e2f8e47f14a04" "Cartridge.Manufacturer" "Activision" "Cartridge.Name" "Unknown Activision Game #2 (1983) (Activision) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "37" "" "Cartridge.MD5" "2d76c5d1aad506442b9e9fb67765e051" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Ernie Runyon, Ed Salvo" "Cartridge.ModelNo" "AP-2004" "Cartridge.Name" "Lost Luggage (1981) (Apollo) [no opening scene]" "" "Cartridge.MD5" "8fffc8f15bb2e6d24e211884a5479aa5" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V1.00) (PAL) (2001) (Retroactive)" "Display.Phosphor" "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" "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" "9671b658286e276cc4a3d02aa25931d2" "Cartridge.Name" "Hangman Ghost Wordlist (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "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" "Display.YStart" "30" "" "Cartridge.MD5" "adf1afac3bdd7b36d2eda5949f1a0fa3" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "495.463 2 - 746381" "Cartridge.Name" "Angriff der Luftflotten (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Paris Attack, M.A.D." "" "Cartridge.MD5" "0519f395d5f7d76be813b834aa51c0be" "Cartridge.Manufacturer" "Atari, Ian Shepard" "Cartridge.ModelNo" "CX2604" "Cartridge.Name" "Space War (1978) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "17d000a2882f9fdaa8b4a391ad367f00" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2676" "Cartridge.Name" "Centipede (1982) (Atari) (PAL)" "" "Cartridge.MD5" "2d6da0eb85eabc93270e5bb8a466ca51" "Cartridge.Name" "Sprite Demo 7 (PD)" "" "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" "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" "6c128bc950fcbdbcaf0d99935da70156" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Volleyball (1983) (Digitel)" "Cartridge.Note" "AKA RealSports Volleyball" "" "Cartridge.MD5" "15dd21c2608e0d7d9f54c0d3f08cca1f" "Cartridge.Manufacturer" "Data Age" "Cartridge.ModelNo" "112-008" "Cartridge.Name" "Frankenstein's Monster (1983) (Data Age)" "" "Cartridge.MD5" "d0498baca989e792db4b8270a02b9624" "Cartridge.Name" "Pac Ghost Sprite Demo (PD)" "" "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" "82337e5fe0f418ca9484ca851dfc226a" "Cartridge.Name" "Robot City (V1.0) (Alpha) (TJ)" "Display.YStart" "24" "" "Cartridge.MD5" "ce5cc62608be2cd3ed8abd844efb8919" "Cartridge.Manufacturer" "Atari, Robert C. Polaro" "Cartridge.ModelNo" "CX2663" "Cartridge.Name" "Road Runner (1989) (Atari)" "Display.YStart" "20" "" "Cartridge.MD5" "32e65d1e4dfcbcd9b57fee72cafe074c" "Cartridge.Name" "Eckhard Stolberg's Scrolling Text Demo 3 (PD)" "Cartridge.Rarity" "New Release" "" "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" "c77d3b47f2293e69419b92522c6f6647" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "101" "Cartridge.Name" "Tank Brigade (1983) (Panda)" "Cartridge.Note" "AKA Phantom Tank" "Display.YStart" "30" "" "Cartridge.MD5" "52615ae358a68de6e76467e95eb404c7" "Cartridge.Name" "DJdsl-wopd (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8ed5a746c59571feb255eaa7d6d0cf98" "Cartridge.Name" "Carnival (208 in 1) (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "83d15fb9843d9f84aa3710538403f434" "Cartridge.Name" "Gunfight 2600 - Release Candidate (2001) (MP) (PAL)" "" "Cartridge.MD5" "de8443ff47283e7b274a7838cb071fb6" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.ModelNo" "CX26122" "Cartridge.Name" "Sinistar (01-04-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "6c1553ca90b413bf762dfc65f2b881c7" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "343.073 3" "Cartridge.Name" "Winterjagd (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Ski Hunt" "" "Cartridge.MD5" "fcf8e306f6615f74feba5cb25550038c" "Cartridge.Name" "Blue Dot Demo (PD)" "" "Cartridge.MD5" "c5dd8399257d8862f3952be75c23e0eb" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2680" "Cartridge.Name" "RealSports Tennis (1982) (Atari) (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" "67931b0d37dc99af250dd06f1c095e8d" "Cartridge.Manufacturer" "CommaVid, Irwin Gaines" "Cartridge.ModelNo" "CM-004" "Cartridge.Name" "Room of Doom (1982) (CommaVid)" "Display.YStart" "24" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f137211537438b1fce3d811baef25457" "Cartridge.Name" "Incoming (02-10-2002) (Ben Larson) (PD)" "" "Cartridge.MD5" "177504abd4260c4265e1338955e9fa47" "Cartridge.Manufacturer" "HCC Software" "Cartridge.Name" "Pitfall! (Steroids Hack)" "Cartridge.Note" "Hack of Pitfall! (Activision)" "" "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" "0856f202b18cd46e44fd1dc3b42e9bfb" "Cartridge.Name" "Frame Counter 1 (2001) (Jake Patterson) (PD)" "" "Cartridge.MD5" "8e0ab801b1705a740b476b7f588c6d16" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-009, AG-009-04" "Cartridge.Name" "Freeway (1981) (Activision)" "" "Cartridge.MD5" "4b205ef73a5779acc5759bde3f6d33ed" "Cartridge.Name" "Berzerk (Unknown) (PAL)" "" "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" "4c9307de724c36fd487af6c99ca078f2" "Cartridge.Manufacturer" "Imagic, Brad Stewart" "Cartridge.ModelNo" "720106-1A, IA3409" "Cartridge.Name" "Sky Patrol (1982) (Imagic) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "79d6f61da3c64688ac8e075667f8a39f" "Cartridge.Name" "Tie-Fighters (MP)" "" "Cartridge.MD5" "e363e467f605537f3777ad33e74e113a" "Cartridge.Manufacturer" "Atari, Bob Whitehead - Sears" "Cartridge.ModelNo" "CX2603 - 99803, 49-75601" "Cartridge.Name" "Star Ship (1977) (Atari)" "" "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" "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" "6e179eee3d4631a7434d40cf7aeea6e8" "Cartridge.Manufacturer" "Wizard Video Games, Robert Barber, Tim Martin" "Cartridge.ModelNo" "007" "Cartridge.Name" "Halloween (1983) (Wizard Video Games) (Prototype)" "Cartridge.Rarity" "Prototype" "" "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" "51f211c8fc879391fee26edfa7d3f11c" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AX-015, AX-015-04" "Cartridge.Name" "Chopper Command (1982) (Activision) (8K)" "" "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" "" "Cartridge.MD5" "936ef1d6f8a57b9ff575dc195ee36b80" "Cartridge.Name" "Pac Kong (Unknown)" "Cartridge.Note" "AKA Spider Kong" "Display.YStart" "24" "Display.Height" "220" "" "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" "4b27f5397c442d25f0c418ccdacf1926" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.ModelNo" "CX2613, 49-75154" "Cartridge.Name" "Adventure (1980) (Atari) (PAL)" "Cartridge.Rarity" "Common" "" "Cartridge.MD5" "5b7ea6aa6b35dc947c65ce665fde624b" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (2 of 3) (1982) (Arcadia)" "" "Cartridge.MD5" "2facd460a6828e0e476d3ac4b8c5f4f7" "Cartridge.Manufacturer" "Sancho - Tang's Electronic Co." "Cartridge.Name" "Words-Attack (1983) (Sancho) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4b71197153d651480830638cb6a03249" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Bowling (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" "1086ff69f82b68d6776634f336fb4857" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-009" "Cartridge.Name" "Bloody Human Freeway (Activision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "415c11fcac66bbd2ace2096687774b5a" "Cartridge.Name" "Fu Kung! (V0.00) (07-01-2003) (AD)" "" "Cartridge.MD5" "f526d0c519f5001adb1fc7948bfbb3ce" "Cartridge.Manufacturer" "Mythicon, Bill Bryner, Bruce de Graaf" "Cartridge.ModelNo" "MA1003" "Cartridge.Name" "Star Fox (1983) (Mythicon)" "" "Cartridge.MD5" "4690fdb70c86604bb35da26696818667" "Cartridge.Name" "Euchre (Release Candidate) (NTSC) (28-09-2002) (Erik Eid)" "" "Cartridge.MD5" "599cbf919d47a05af975ad447df29497" "Cartridge.Manufacturer" "Jake Patterson" "Cartridge.Name" "Baubles (V0.002) (2001) (Jake Patterson) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "46258bd92b1f66f4cb47864d7654f542" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Turmoil (Zellers)" "" "Cartridge.MD5" "b42df8d92e3118dc594cecd575f515d7" "Cartridge.Manufacturer" "Mystique - American Multiple Industries" "Cartridge.ModelNo" "1003" "Cartridge.Name" "Burning Desire (1982) (Mystique) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "fd78f186bdff83fbad7f97cb583812fe" "Cartridge.Manufacturer" "Amiga" "Cartridge.ModelNo" "3125" "Cartridge.Name" "Surf's Up (1983) (Amiga) (Prototype) [a2]" "Cartridge.Note" "Uses the Joyboard controller" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "0b1056f1091cfdc5eb0e2301f47ac6c3" "Cartridge.Manufacturer" "Tigervision, Karl T. Olinger - Teldec" "Cartridge.ModelNo" "7-001 - 3.60001 VE" "Cartridge.Name" "King Kong (1982) (Tigervision) (PAL) [a]" "Display.YStart" "20" "" "Cartridge.MD5" "cd139ae6d09f3665ad09eb79da3f9e49" "Cartridge.Manufacturer" "Eric Mooney" "Cartridge.Name" "Invaders by Erik Mooney (4-24-97) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "517923e655755086a3b72c0b17b430e6" "Cartridge.Manufacturer" "Tron" "Cartridge.Name" "Super Tennis (Tron)" "Cartridge.Note" "AKA RealSports Tennis" "" "Cartridge.MD5" "2240655247d6de1c585564004a853ab7" "Cartridge.Name" "Fu Kung! (V0.17) (07-02-2003) (AD)" "" "Cartridge.MD5" "4c606235f4ec5d2a4b89139093a69437" "Cartridge.Manufacturer" "Andrew Davies" "Cartridge.Name" "Andrew Davies early notBoulderDash demo (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2bf34b6ad7d2317a2d0808b3fb93571b" "Cartridge.Name" "Easy Playfield Graphics (1997) (Chris Cracknell)" "" "Cartridge.MD5" "e040df95a055b18ebdb094e904cb71b2" "Cartridge.Name" "Score Demo (B. Watson)" "" "Cartridge.MD5" "e908611d99890733be31733a979c62d8" "Cartridge.Manufacturer" "Atari, Dan Hitchens" "Cartridge.ModelNo" "CX2697" "Cartridge.Name" "Mario Bros. (1983) (Atari)" "" "Cartridge.MD5" "d88691c995008b9ab61a44bb686b32e4" "Cartridge.Name" "Warring Worms (07-02-2002) (Billy Eno)" "" "Cartridge.MD5" "2dbc92688f9ba92a7e086d62be9df79d" "Cartridge.Name" "How to Draw a Playfield (1997) (Jim Crawford) (PD)" "" "Cartridge.MD5" "5d8fb14860c2f198472b233874f6b0c9" "Cartridge.Name" "Boing! (PD) [a2]" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "e723ad8f406cb258b89681ef4cef0eff" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Sadoom (TJ) (PAL) (Hack)" "Cartridge.Note" "Hack of Kaboom!" "Cartridge.Rarity" "Hack" "Controller.Left" "PADDLES" "" "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, Holdup, Rooring 20's" "Cartridge.Rarity" "Rare" "" "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" "73e66e82ac22b305eb4d9578e866236e" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Unknown Datatech Game (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "Display.YStart" "24" "" "Cartridge.MD5" "6cbe945e16d9f827d0d295546ac11b22" "Cartridge.Name" "Gunfight 2600 - AI (MP)" "" "Cartridge.MD5" "6fd7c7057eeab273b29c7aafc7429a96" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AX-018, AX-018-04" "Cartridge.Name" "Pitfall! (1982) (Activision) (16K)" "" "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" "d5e27051512c1e7445a9bf91501bda09" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-008" "Cartridge.Name" "Laser Blast (1981) (Activision) (4K)" "" "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" "e77f332b71f13884c84771e7a121182d" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Hey! Stop! (Jone Yuan)" "Cartridge.Note" "AKA Keystone Kapers" "" "Cartridge.MD5" "85bbefb90e16bf386b304c1e9a1f6084" "Cartridge.Manufacturer" "Champ Games" "Cartridge.Name" "Conquest Of Mars (PAL60)" "Cartridge.Rarity" "Homebrew" "Display.Format" "PAL60" "" "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" "7ab210f448de518fa61a5924120ba872" "Cartridge.Name" "Fortress (20-04-2003) (CT)" "" "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" "Display.YStart" "42" "" "Cartridge.MD5" "073d7aff37b7601431e4f742c36c0dc1" "Cartridge.Name" "Bermuda (Unknown) (PAL)" "Cartridge.Note" "AKA River Raid" "Display.YStart" "10" "" "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" "e275cbe7d4e11e62c3bfcfb38fca3d49" "Cartridge.Manufacturer" "M Network, Ken Smith - INTV" "Cartridge.ModelNo" "MT5658" "Cartridge.Name" "Super Challenge Football (1982) (M Network)" "" "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" "a83b070b485cf1fb4d5a48da153fdf1a" "Cartridge.Manufacturer" "Apollo" "Cartridge.ModelNo" "AP-2011" "Cartridge.Name" "Pompeii (1983) (Apollo) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "dd7884b4f93cab423ac471aa1935e3df" "Cartridge.Manufacturer" "Atari, Brad Stewart - Sears" "Cartridge.ModelNo" "CX2649, 49-75163" "Cartridge.Name" "Asteroids (1981) (Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5f316973ffd107f7ab9117e93f50e4bd" "Cartridge.Name" "Commando Raid (Unknown) (PAL)" "" "Cartridge.MD5" "740f39e71104e90416c29a73560b9c6b" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "TE016643" "Cartridge.Name" "Diagnostic Test Cartridge 2.6P (1982) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "f69a39b215852a0c2764d2a923c1e463" "Cartridge.Name" "Move a Blue Blob Demo 2 (PD)" "" "Cartridge.MD5" "bb756aa98b847dddc8fc170bc79f92b2" "Cartridge.Name" "Golf (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "7ac4f4fb425db38288fa07fb8ff4b21d" "Cartridge.Manufacturer" "Goliath" "Cartridge.ModelNo" "83-213" "Cartridge.Name" "Space Eagle (1983) (Goliath) (PAL)" "Cartridge.Note" "AKA Exocet" "" "Cartridge.MD5" "19a9d3f9fa1b1358fb53009444247aaf" "Cartridge.Name" "Blackjack (Unknown) (PAL) (4K)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXIS" "Display.YStart" "56" "" "Cartridge.MD5" "e5359cbbbff9c6d7fe8aeff5fb471b46" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-849" "Cartridge.Name" "Boom Bang (1983) (CCE)" "Cartridge.Note" "AKA Crackpots" "" "Cartridge.MD5" "f965cc981cbb0822f955641f8d84e774" "Cartridge.Manufacturer" "Answer Software Corporation - TY Associates" "Cartridge.ModelNo" "ASC2001" "Cartridge.Name" "Confrontation (1983) (Answer) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "30" "Display.Height" "220" "Display.Phosphor" "YES" "" "Cartridge.MD5" "aa1c41f86ec44c0a44eb64c332ce08af" "Cartridge.Manufacturer" "Spectravideo, David Lubar" "Cartridge.ModelNo" "SA-218" "Cartridge.Name" "Bumper Bash (1983) (Spectravideo)" "Controller.Left" "PADDLES_IAXIS" "Display.YStart" "20" "" "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" "028024fb8e5e5f18ea586652f9799c96" "Cartridge.Manufacturer" "Coleco, Steve 'Jessica' Kitchen" "Cartridge.ModelNo" "2468" "Cartridge.Name" "Carnival (1982) (Coleco)" "Display.YStart" "26" "Display.Height" "214" "" "Cartridge.MD5" "43f33c6dfdeaf5138ce6e6968ad7c5ce" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 11 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "0c35806ff0019a270a7acae68de89d28" "Cartridge.Manufacturer" "Froggo" "Cartridge.ModelNo" "FG1003" "Cartridge.Name" "Task Force (1987) (Froggo)" "Cartridge.Note" "AKA Gangster Alley" "" "Cartridge.MD5" "45beef9da1a7e45f37f3f445f769a0b3" "Cartridge.Manufacturer" "Atari, Suki Lee" "Cartridge.ModelNo" "CX2658" "Cartridge.Name" "Math Gran Prix (1982) (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" "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" "5305f69fbf772fac4760cdcf87f1ab1f" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Ski Run (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "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" "f9655ed51462ecfc690c7b97cec649f9" "Cartridge.Manufacturer" "Andrew Wallace" "Cartridge.Name" "Laseresal 2002 (PAL) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "097074f24cde141fe6a0f26a10333265" "Cartridge.Name" "Marble Craze (V0.90) (Paul Slocum)" "" "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" "191449e40b0c56411c70772706f79224" "Cartridge.Name" "Multi-Color Demo 2 (Bob Colbert) (PD)" "" "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" "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" "493daaf9fb1ba450eba6b8ed53ffb37d" "Cartridge.Name" "3-D Corridor Demo (27-03-2003) (MP)" "" "Cartridge.MD5" "835759ff95c2cdc2324d7c1e7c5fa237" "Cartridge.Manufacturer" "20th Century Fox Video Games, Douglas 'Dallas North' Neubauer" "Cartridge.ModelNo" "11011" "Cartridge.Name" "M.A.S.H (1983) (20th Century Fox)" "" "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" "2016726db38ad6a68b4c48ba6fe51557" "Cartridge.Manufacturer" "Piero Cavina, Erik Mooney" "Cartridge.Name" "INV 2 (Piero Cavina, Erik Mooney)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "b5657d4c1c732fbb6af150668464247f" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "6 AR-4400" "Cartridge.Name" "Excalibur (Dragonstomper Beta) (1982) (Arcadia) (Prototype)" "" "Cartridge.MD5" "2e5b184da8a27c4d362b5a81f0b4a68f" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "Rabbit Transit (08-29-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "0277c449fae63f6f1c8f94dedfcf0058" "Cartridge.Name" "Laser Demo (B. Watson)" "" "Cartridge.MD5" "da4e3396aa2db3bd667f83a1cb9e4a36" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-027" "Cartridge.Name" "Plaque Attack (1983) (Activision)" "" "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" "Display.Phosphor" "YES" "" "Cartridge.MD5" "42ae81ae8ac51e5c238639f9f77d91ae" "Cartridge.Name" "Multi-Sprite Demo 2 (Piero Cavina) (PD)" "" "Cartridge.MD5" "a4f1cea2c8479284e2a2292f8d51b5fa" "Cartridge.Name" "Gunfight 2600 - The Final Kernel Part 2 (MP)" "" "Cartridge.MD5" "c9196e28367e46f8a55e04c27743148f" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Stampede (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "13aa1f9ac4249947e4af61319d9a08f2" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2680, CX2680P" "Cartridge.Name" "RealSports Tennis (1983) (Atari) (PAL) [a1]" "" "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" "36e47ed74968c365121eab60f48c6517" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "343.373 7" "Cartridge.Name" "Master Builder (1983) (Quelle) (PAL)" "" "Cartridge.MD5" "4ca90ba45eced6f5ad560ea8938641b2" "Cartridge.Name" "Hangman Man Wordlist (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "f9660ebed66fee8bdfdf07b4faa22941" "Cartridge.Manufacturer" "VGS" "Cartridge.Name" "Vanguard (VGS)" "" "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" "6e5d5ba193d2540aec2e847aafb2a5fb" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.14) (Retroactive) (NTSC)" "Display.Phosphor" "YES" "" "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" "0cb7af80fd0ddef84844481d85e5d29b" "Cartridge.Name" "Mr. Pac-Man (El Destructo)" "" "Cartridge.MD5" "281ff9bd0470643853de5cbd6d9e17f5" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Cubis (EM) (1997) (Eckhard Stolberg)" "Cartridge.Rarity" "New Release" "" "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" "Display.YStart" "25" "Display.Height" "215" "" "Cartridge.MD5" "898143773824663efe88d0a3a0bb1ba4" "Cartridge.Manufacturer" "Activision, Steve 'Jessica' Kitchen" "Cartridge.ModelNo" "AZ-033, AZ-033-04" "Cartridge.Name" "Space Shuttle (1983) (Activision) [FE]" "Cartridge.Note" "A Journey Into Space" "" "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" "d5618464dbdc2981f6aa8b955828eeb4" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-829" "Cartridge.Name" "Megamania (1983) (CCE)" "" "Cartridge.MD5" "03b1051c9374678363c899914412cfc5" "Cartridge.Name" "Incoming (30-10-2002) (Ben Larson) (PD)" "" "Cartridge.MD5" "29630a20d356fb58685b150bfa8f00c3" "Cartridge.Manufacturer" "M Network, Kevin Miller" "Cartridge.ModelNo" "MT5687" "Cartridge.Name" "International Soccer (1982) (Mattel) [a]" "" "Cartridge.MD5" "d8b2c81cea5af04f795eb3dc6573d72b" "Cartridge.Name" "Tunnel Demo 2 (27-03-2003) (CT)" "" "Cartridge.MD5" "ebcbc8a181a738e13df6216e5c329230" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-022" "Cartridge.Name" "Seaquest (1983) (Activision) (16K)" "" "Cartridge.MD5" "96bcb3d97ce4ff7586326d183ac338a2" "Cartridge.Name" "Revenge of the Apes (Hack) [h2]" "Cartridge.Note" "Hack of Planet of the Apes" "Cartridge.Rarity" "Hack" "" "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" "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" "1b22a3d79ddd79335b69c94dd9b3e44e" "Cartridge.Manufacturer" "Tron" "Cartridge.Name" "Moon Patrol (Tron)" "" "Cartridge.MD5" "8108ad2679bd055afec0a35a1dca46a4" "Cartridge.Name" "Maze Craze (Unknown)" "" "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" "01cb3e8dfab7203a9c62ba3b94b4e59f" "Cartridge.Manufacturer" "Atari, Mimi Nyden, Scott Smith, Robert Vieira" "Cartridge.ModelNo" "CX26127" "Cartridge.Name" "Gremlins (1984) (Atari)" "" "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" "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" "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" "ed0ab909cf7b30aff6fc28c3a4660b8e" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "105" "Cartridge.Name" "Stunt Man (1983) (Panda)" "Cartridge.Note" "AKA Nightmare" "" "Cartridge.MD5" "0c7bd935d9a7f2522155e48315f44fa0" "Cartridge.Manufacturer" "Carrere Video, Jeff Corsiglia, Paul Allen Newell - Teldec" "Cartridge.ModelNo" "USC1009" "Cartridge.Name" "Infernal Tower (1983) (Carrere Video) (PAL)" "Cartridge.Note" "AKA Towering Inferno" "Console.SwapPorts" "YES" "Display.Phosphor" "YES" "" "Cartridge.MD5" "372bddf113d088bc572f94e98d8249f5" "Cartridge.Manufacturer" "Bomb - Onbase" "Cartridge.ModelNo" "CA285" "Cartridge.Name" "Wall-Defender (1983) (Bomb) (PAL)" "Cartridge.Note" "AKA Wall Break" "" "Cartridge.MD5" "25265d0e7f88b3026003809f25ee025e" "Cartridge.Manufacturer" "Atari - GCC, Ava-Robin Cohen" "Cartridge.ModelNo" "CX26123" "Cartridge.Name" "Jr. Pac-Man (1984) (Atari) [a]" "" "Cartridge.MD5" "294762000e853b4319f9991c1ced5dfc" "Cartridge.Name" "T.F. Space Invaders (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "313243fc41e49ef6bd3aa9ebc0d372dd" "Cartridge.Name" "Fast Food (Unknown) (PAL)" "" "Cartridge.MD5" "71b193f46c88fb234329855452dfac5b" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Atlantis (1983) (Digitel)" "" "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" "898748d5eaac3164b0391a64ae1e0e32" "Cartridge.Name" "Hangman Man 4letter (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "41c4e3d45a06df9d21b7aae6ae7e9912" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-826" "Cartridge.Name" "Grand Prix (1983) (CCE)" "" "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" "d45bf71871b196022829aa3b96bfcfd4" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-017, AX-017-04" "Cartridge.Name" "MegaMania (1982) (Activision) (8K)" "" "Cartridge.MD5" "225522777dc7155627808bde0c1d0ef0" "Cartridge.Name" "This Planet Sucks Demo 1 (Greg Troutman) (PD)" "Cartridge.Rarity" "New Release" "Display.YStart" "40" "" "Cartridge.MD5" "bc703ea6afb20bc089f04d8c9d79a2bd" "Cartridge.Name" "Gunfight 2600 - Not mergeable with Colbert wizardry... (2001) (MP)" "" "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" "19162393786098d50587827588198a86" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Flag Capture (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "6e59dd52f88c00d5060eac56c1a0b0d3" "Cartridge.Manufacturer" "Atari, Bob Smith" "Cartridge.ModelNo" "CX2648" "Cartridge.Name" "Video Pinball (1981) (Atari) (PAL)" "" "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" "7dd9c5284422f729066ab22a284c8283" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-833" "Cartridge.Name" "Target Practice (1983) (CCE) [a]" "Cartridge.Note" "AKA Carnival" "Display.YStart" "26" "Display.Height" "214" "" "Cartridge.MD5" "6141c095d0aee4e734bebfaac939030a" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-017" "Cartridge.Name" "Mariana (Rainbow Vision) (PAL)" "Cartridge.Note" "AKA Seaquest" "" "Cartridge.MD5" "a3c1c70024d7aabb41381adbfb6d3b25" "Cartridge.Manufacturer" "Telesys, Alex Leavens" "Cartridge.ModelNo" "1005" "Cartridge.Name" "Stargunner (1982) (Telesys)" "" "Cartridge.MD5" "2f0546c4d238551c7d64d884b618100c" "Cartridge.Manufacturer" "Sega, Jeff Lorenz" "Cartridge.Name" "Ixion (1984) (Sega) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "200a9d2a7cb4441ce4f002df6aa47e38" "Cartridge.Name" "Doomzerk (PD) (Hack)" "Cartridge.Note" "Hack of Berzerk" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "cf63ffac9da89ef09c6c973083061a47" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-859" "Cartridge.Name" "MASH (1983) (CCE)" "Cartridge.Note" "AKA M.A.S.H" "" "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" "706e3cc4931f984447213b92d1417aff" "Cartridge.Name" "Joustpong (06-07-2002) (Kirk Israel) (PD)" "" "Cartridge.MD5" "10f62443f1ae087dc588a77f9e8f43e9" "Cartridge.Manufacturer" "Atari, Carla Meninsky" "Cartridge.ModelNo" "CX2637, CX2637P" "Cartridge.Name" "Dodge 'Em (1980) (Atari) (PAL) [fixed]" "" "Cartridge.MD5" "bfa58198c6b9cd8062ee76a2b38e9b33" "Cartridge.Name" "20 Sprites at Once Demo 4 (PD)" "" "Cartridge.MD5" "e0b24c3f40a46cda52e29835ab7ad660" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "626.502 9 - 746381" "Cartridge.Name" "Top Gun (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Air Raiders" "" "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" "77be57d872e3f5b7ecf8d19d97f73281" "Cartridge.Name" "Basketball (208 in 1) (Unknown) (PAL)" "Cartridge.Note" "Console ports are swapped" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "6bb22efa892b89b69b9bf5ea547e62b8" "Cartridge.Manufacturer" "Dynacom" "Cartridge.Name" "Megamania (1982) (Dynacom)" "" "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" "Display.YStart" "30" "" "Cartridge.MD5" "06742cf522f23797157f215a1dc8a1a9" "Cartridge.Name" "Healthbars (PD)" "" "Cartridge.MD5" "f367e58667a30e7482175809e3cec4d4" "Cartridge.Manufacturer" "ZiMAG - Emag - Vidco" "Cartridge.ModelNo" "708-111 - GN-040" "Cartridge.Name" "Cosmic Corridor (1983) (ZiMAG)" "Cartridge.Note" "AKA Space Tunnel" "Display.Height" "220" "" "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" "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" "72bda70c75dfa2365b3f8894bace9e6a" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Atlantis (TJ) (Hack)" "Cartridge.Note" "Hack of Atlantis" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "972486110933623039a3581db308fda6" "Cartridge.Name" "Xeno Plus (Hack)" "Cartridge.Note" "Hack of Xenophobe" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "ec26fdc87b1d35f1d60ea89cda4f4dd4" "Cartridge.Name" "Star Fire - Crash Scene (04-11-2002) (MP)" "" "Cartridge.MD5" "b1d1e083dc9e7d9a5dc1627869d2ade7" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1004" "Cartridge.Name" "Mario's Bros. (1983) (CCE)" "Cartridge.Note" "AKA Mario Bros." "" "Cartridge.MD5" "0b577e63b0c64f9779f315dca8967587" "Cartridge.Manufacturer" "Videospielkassette - Ariola" "Cartridge.ModelNo" "PGP236" "Cartridge.Name" "Raketen-Angriff (Ariola) (PAL)" "Cartridge.Note" "AKA Missile Control" "" "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" "d326db524d93fa2897ab69c42d6fb698" "Cartridge.Manufacturer" "Parker Brothers, Paul Crowley" "Cartridge.ModelNo" "931505" "Cartridge.Name" "Super Cobra (1982) (Parker Bros) (PAL)" "" "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" "" "Cartridge.MD5" "f777444fc21a5925e066b68b1d350575" "Cartridge.Name" "Marble Craze (Kernel Works) (Paul Slocum)" "" "Cartridge.MD5" "da66d75e4b47fab99733529743f86f4f" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Chopper Command (1983) (Digitel)" "" "Cartridge.MD5" "2f2f9061398a74c80420b99ddecf6448" "Cartridge.Manufacturer" "Rentacom - Brazil" "Cartridge.Name" "Bobby Is Going Home (Rentacom)" "Display.YStart" "31" "" "Cartridge.MD5" "0d09cff0d28033c02c3290edfc3a5cea" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Steve Woita" "Cartridge.ModelNo" "CX2699" "Cartridge.Name" "Taz (1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "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" "67ce6cdf788d324935fd317d064ed842" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.09) (Stella) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2091af29b4e7b86914d79d9aaa4cbd20" "Cartridge.Manufacturer" "CBS Electronics, Harley H. Puthuff Jr." "Cartridge.ModelNo" "4L1802" "Cartridge.Name" "Donkey Kong Junior (1983) (CBS Electronics) (PAL)" "" "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" "2008c76deba5953201ef75a09b2ff7dc" "Cartridge.Name" "Fortress (21-04-2003) (CT)" "" "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" "aca09ffea77174b148b96b205109db4d" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AG-007, CAG-007" "Cartridge.Name" "Tennis (1981) (Activision) (4K)" "" "Cartridge.MD5" "376944889dcfa96c73d3079f308e3d32" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (0.11) (Retroactive) (Stella)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "68449e4aaba677abcd7cde4264e02168" "Cartridge.Name" "Horizonal Color Bars Demo 2 (PD)" "" "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" "Display.Phosphor" "YES" "" "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" "" "Cartridge.MD5" "2bb9f4686f7e08c5fcc69ec1a1c66fe7" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, John Allred" "Cartridge.ModelNo" "CX2688" "Cartridge.Name" "Jungle Hunt (1983) (Atari)" "" "Cartridge.MD5" "e04f1c1e4401d584d3f4343410a5bcc4" "Cartridge.Manufacturer" "Wizard Video Games, Robert Barber, Tim Martin" "Cartridge.ModelNo" "007" "Cartridge.Name" "Halloween (1983) (Wizard Video Games) (Prototype) [a]" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "3a771876e4b61d42e3a3892ad885d889" "Cartridge.Manufacturer" "Atari, Bill Aspromonte, Andrew Fuchs" "Cartridge.ModelNo" "CX26120" "Cartridge.Name" "Defender II (1988) (Atari)" "Cartridge.Note" "AKA Stargate" "" "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" "Display.YStart" "32" "" "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" "98e7caaab8ec237558378d2776c66616" "Cartridge.Manufacturer" "Bradford W. Mott" "Cartridge.Name" "HMOVE Test (Bradford W. Mott) (1998) (PD)" "Cartridge.Rarity" "Homebrew" "" "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" "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" "39d36366ae7e6dfd53393fb9ebab02a0" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-811" "Cartridge.Name" "River Raid (1983) (CCE) [a]" "" "Cartridge.MD5" "862cf669cbced78f9ed31a5d375b2ebe" "Cartridge.Name" "Gunfight 2600 - Flicker acceptance (2001) (MP)" "" "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" "3da7cc7049d73d34920bb73817bd05a9" "Cartridge.Manufacturer" "Activision, Mike Lorenzen" "Cartridge.ModelNo" "AX-023" "Cartridge.Name" "Oink! (1983) (Activision) (16K)" "" "Cartridge.MD5" "aed0b7bd64cc384f85fdea33e28daf3b" "Cartridge.Manufacturer" "Atari, Alan J. Murphy, Robert C. Polaro" "Cartridge.ModelNo" "CX2666" "Cartridge.Name" "RealSports Volleyball (1982) (Atari)" "" "Cartridge.MD5" "f954381f9e0f2009d1ac40dedd777b1a" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Robot City (V0.18) (01-09-2002) (TJ)" "Cartridge.Rarity" "New Release" "Display.YStart" "24" "" "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" "718ee85ea7ec27d5bea60d11f6d40030" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Ghostbusters II (1992) (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0cc8224ff1edfe458e8629e9e5fe3f5b" "Cartridge.Name" "Trick 12 (2001) (TJ)" "" "Cartridge.MD5" "8db152458abaef3cfa7a4e420ddbda59" "Cartridge.Name" "Keystone Kapers (Unknown)" "" "Cartridge.MD5" "b095009004df341386d22b2a3fae3c81" "Cartridge.Name" "Sub-Scan (Unknown) (PAL)" "" "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" "93dc15d15e77a7b23162467f95a5f22d" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Sky Jinks (CCE)" "" "Cartridge.MD5" "a8c48b4e0bf35fe97cc84fdd2c507f78" "Cartridge.Manufacturer" "Puzzy - Bit Corporation" "Cartridge.ModelNo" "PG201" "Cartridge.Name" "Seamonster (1982) (Puzzy)" "Display.YStart" "29" "Display.Height" "220" "" "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" "368d88a6c071caba60b4f778615aae94" "Cartridge.Manufacturer" "Atari, Matthew L. Hubbard" "Cartridge.ModelNo" "CX26159" "Cartridge.Name" "Double Dunk (1989) (Atari)" "Cartridge.Note" "AKA Super Basketball" "" "Cartridge.MD5" "51f15b39d9f502c2361b6ba6a73464d4" "Cartridge.Name" "Amanda Invaders (PD) [a]" "" "Cartridge.MD5" "e1b90f1e01b1a316d7bbf141525cc00e" "Cartridge.Name" "Sky Jinks (Unknown) (PAL) (4K) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "9ed0f2aa226c34d4f55f661442e8f22a" "Cartridge.Name" "Nuts (Unknown) (PAL)" "" "Cartridge.MD5" "df6a28a89600affe36d94394ef597214" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Dan Oliver" "Cartridge.ModelNo" "AP-2002" "Cartridge.Name" "Space Cavern (1981) (Apollo)" "" "Cartridge.MD5" "df95e4af466c809619299f49ece92365" "Cartridge.Manufacturer" "Atari, 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" "bb07f917611cde42b7d83746ee27147d" "Cartridge.Name" "Star Fire - Warping!! (13-04-2003) (MP)" "" "Cartridge.MD5" "64198bb6470c78ac24fcf13fe76ab28c" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (1982) (Arcadia) [a]" "" "Cartridge.MD5" "1ec5bef77b91e59313cba205f15b06d7" "Cartridge.Name" "Overhead Adventure Demo 1 (PD)" "Display.YStart" "64" "" "Cartridge.MD5" "32199271dc980eb31a2cc96e10a9e244" "Cartridge.Name" "Radial Pong - Version 12 (Jeffry Johnston) (PD)" "" "Cartridge.MD5" "672012d40336b403edea4a98ce70c76d" "Cartridge.Name" "Spider Kong (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "6b71f20c857574b732e7a8e840bd3cb2" "Cartridge.Name" "Frostbite (Unknown) (PAL)" "" "Cartridge.MD5" "d0a379946ed77b1b126230ca68461333" "Cartridge.Manufacturer" "Ataripoll" "Cartridge.Name" "Atari Invaders (Ataripoll) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "55949cb7884f9db0f8dfcf8707c7e5cb" "Cartridge.Manufacturer" "Atari, Ed Logg, Carol Shaw - Sears" "Cartridge.ModelNo" "CX2639 - 49-75162" "Cartridge.Name" "Othello (1981) (Atari)" "" "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" "ee456542b93fa8d7e6a8c689b5a0413c" "Cartridge.Name" "Chronocolor Donkey Kong Clean (PD)" "" "Cartridge.MD5" "9848b5ef7a0c02fe808b920a2ac566d2" "Cartridge.Manufacturer" "Skyworks Technology Inc." "Cartridge.Name" "Baseball (2002) (Skyworks)" "" "Cartridge.MD5" "d39e29b03af3c28641084dd1528aae05" "Cartridge.Manufacturer" "Funvision - Fund. Int'l Co." "Cartridge.Name" "Spider Monster (1982) (Funvision) (PAL)" "Cartridge.Note" "AKA Spider Kong" "" "Cartridge.MD5" "df3e6a9b6927cf59b7afb626f6fd7eea" "Cartridge.Name" "Tuby Bird (208 in 1) (Unknown) (PAL)" "Cartridge.Note" "AKA Dolphin" "" "Cartridge.MD5" "cda38714267978b9a8b0b24bee3529ae" "Cartridge.Name" "Space Instigators (V1.6) (17-10-2002) (CT)" "" "Cartridge.MD5" "6339d28c9a7f92054e70029eb0375837" "Cartridge.Manufacturer" "Parker Brothers, Wilfredo 'Willy' 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" "c473b222b7c5308d0773326416094272" "Cartridge.Name" "Star Fire (28-11-2002) (MP) [a1]" "" "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" "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" "Display.YStart" "63" "" "Cartridge.MD5" "0383dc02cb82302da3d155fd108bfe3a" "Cartridge.Manufacturer" "AtariAge, Chris Spry" "Cartridge.ModelNo" "26200" "Cartridge.Name" "Princess Rescue (2013) (Sprybug) (PAL60)" "Cartridge.Note" "Compatible with Genesis controller" "Cartridge.Rarity" "Homebrew" "Display.Format" "PAL60" "Display.Phosphor" "YES" "" "Cartridge.MD5" "265c74a956500bd31efd24adc6d5ccf6" "Cartridge.Manufacturer" "Activision, Larry Miller" "Cartridge.ModelNo" "AX-026, AX-026-04" "Cartridge.Name" "Enduro (1983) (Activision) (8K)" "" "Cartridge.MD5" "cea9f72036dc6f7af5eff52459066290" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.07) (Retroactive) (Stella)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "dfe6aa7443bb813cefa35a4cf4887422" "Cartridge.Name" "This Planet Sucks (Greg Troutman) [a1]" "Cartridge.Rarity" "New Release" "Display.YStart" "37" "" "Cartridge.MD5" "ac26d7d37248d1d8eac5eccacdbef8db" "Cartridge.Name" "Snail Against Squirrel (Unknown) (PAL)" "" "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" "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.YStart" "25" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ad2e6bfb3b9b9b36ba8bf493ce764c49" "Cartridge.Name" "2600 Collison Demo 1 (Piero Cavina) (PD)" "" "Cartridge.MD5" "8055b9c2622136fd91edfea6df642daf" "Cartridge.Manufacturer" "Activision" "Cartridge.Name" "Unknown Activision Game #1 (1983) (Activision) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "46c021a3e9e2fd00919ca3dd1a6b76d8" "Cartridge.Manufacturer" "Atari, Jim Huether - Sears" "Cartridge.ModelNo" "CX2629 - 6-99843, 49-75118" "Cartridge.Name" "Sky Diver (1979) (Atari)" "" "Cartridge.MD5" "63e42d576800086488679490a833e097" "Cartridge.Manufacturer" "Telesys, Jim Rupp" "Cartridge.ModelNo" "1004" "Cartridge.Name" "Ram It (1982) (Telesys) (PAL)" "" "Cartridge.MD5" "ce6c4270f605ad3ce5e82678b0fc71f8" "Cartridge.Name" "Vertical Rainbow Demo (PD)" "" "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" "bae1a23f9b6acdadf465cfb330ba0acb" "Cartridge.Manufacturer" "Atari - GCC, Doug Macrae" "Cartridge.ModelNo" "CX2677" "Cartridge.Name" "Dig Dug (1983) (Atari) [a]" "" "Cartridge.MD5" "82c25d1c35e6ac6f893d1d7c2fc2f9c8" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX2628, CX2628P" "Cartridge.Name" "Bowling (1979) (Atari) (PAL) (4K)" "" "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" "83b8c01c72306d60dd9b753332ebd276" "Cartridge.Name" "Bank Heist (208 in 1) (Unknown) (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" "f2f59629d7341c97644405daeac08845" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Bobby Is Going Home (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "Display.YStart" "31" "" "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" "4d5f6db55f7f44fd0253258e810bde21" "Cartridge.Manufacturer" "Fabrizio Zavagli" "Cartridge.Name" "Betterblast (Fabrizio Zavagli) (Hack)" "Cartridge.Note" "Hack of Astroblast" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "e9c71f8cdba6037521c9a3c70819d171" "Cartridge.Manufacturer" "Action Hi Tech - Hi-Score" "Cartridge.Name" "Bank Heist (PAL)" "" "Cartridge.MD5" "a29fc854838e08c247553a7d883dd65b" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-013" "Cartridge.Name" "Barnstorming (1982) (Activision) (16K)" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "d36308387241e98f813646f346e7f9f7" "Cartridge.Manufacturer" "King Atari" "Cartridge.Name" "Ghostbuster 2 (King Atari) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3316ee2f887e9cb9b54dd23c5b98c3e2" "Cartridge.Name" "Texas Golf (miniature Gold Hack)" "" "Cartridge.MD5" "135708b9a7dd20576c1b66ab2a41860d" "Cartridge.Name" "Hangman Man Biglist1 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "79fcdee6d71f23f6cf3d01258236c3b9" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, John Mracek" "Cartridge.ModelNo" "CX2673, CX2673P" "Cartridge.Name" "Phoenix (1982) (Atari) (PAL)" "" "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" "0685bd0bcb975ceef7041749a5454a48" "Cartridge.Manufacturer" "Piero Cavina" "Cartridge.Name" "11 Sprite Demo (Piero Cavina) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "c450a285daa7a3b65188c2c3cf04fb3e" "Cartridge.Manufacturer" "Wizard Video Games" "Cartridge.ModelNo" "007" "Cartridge.Name" "Halloween (1983) (Wizard Video Games) [a]" "" "Cartridge.MD5" "96670d0bf3610da2afcabd8e21d8eabf" "Cartridge.Name" "Boring Pitfall (Hack)" "Cartridge.Note" "Hack of Pitfall!" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "b86a12e53ab107b6caedd4e0272aa034" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Treasure Hunting (Funvision)" "Cartridge.Note" "AKA Pitfall!" "" "Cartridge.MD5" "a5855d73d304d83ef07dde03e379619f" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.Name" "Boggle (08-07-1978) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "27" "Display.Height" "215" "Display.Phosphor" "YES" "" "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" "83bdc819980db99bf89a7f2ed6a2de59" "Cartridge.Manufacturer" "Atari, Carla Meninsky - Sears" "Cartridge.ModelNo" "CX2637 - 49-75158" "Cartridge.Name" "Dodge 'Em (1980) (Atari) [fixed]" "" "Cartridge.MD5" "ce17325834bf8b0a0d0d8de08478d436" "Cartridge.Name" "Boring Freeway (Hack)" "Cartridge.Note" "Hack of Freeway" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "a69f5b1761a8a11c98e706ec7204937f" "Cartridge.Name" "Pharaoh's Curse (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "bff8f8f53a8aeb1ee804004ccbb08313" "Cartridge.Name" "Droid Demo 22 (David Conrad Schweinsberg) (PD)" "" "Cartridge.MD5" "67684a1d18c85ffa5d82dab48fd1cb51" "Cartridge.Manufacturer" "Tigervision, Warren Schwader - Teldec" "Cartridge.ModelNo" "7-003" "Cartridge.Name" "Threshold (1982) (Tigervision) (PAL)" "" "Cartridge.MD5" "6333ef5b5cbb77acd47f558c8b7a95d3" "Cartridge.Manufacturer" "Greg Troutman" "Cartridge.Name" "Dark Mage (Greg Troutman) (PD) (8K)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0e7e73421606873b544e858c59dc283e" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Super Soccer (Digivision)" "Cartridge.Note" "AKA RealSports Soccer" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6cea35ded079863a846159c3a1101cc7" "Cartridge.Name" "Atlantis (208 in 1) (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "7dbc8fa2e488e3f6b87fbe0f76c5b89f" "Cartridge.Manufacturer" "Ed Federmeyer" "Cartridge.Name" "Sound X (1996) (Ed Federmeyer)" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "9be58a14e055b0e7581fc4d6c2f6b31d" "Cartridge.Name" "Adventure (Color Scrolling) (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "463e66ad98806a49106cffa49c08e2ed" "Cartridge.Name" "Interlace Game Demo (01-09-2002) (Billy Eno)" "" "Cartridge.MD5" "913d5d959b5021f879033c89797bab5e" "Cartridge.Name" "Robot Player Graphic (1996) (J.V. Matthews) (PD)" "" "Cartridge.MD5" "c446288fe62c0c2737639fd788ae4a21" "Cartridge.Name" "Mark's Sound Demo (PD)" "Display.Phosphor" "YES" "" "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" "" "Cartridge.MD5" "321c3451129357af42a375d12afd4450" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26177" "Cartridge.Name" "Ikari Warriors (1989) (Atari) (PAL)" "" "Cartridge.MD5" "f283cc294ece520c2badf9da20cfc025" "Cartridge.Manufacturer" "Atari, Christopher H. Omarzu - Children's Computer Workshop" "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" "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" "9d2938eb2b17bb73e9a79bbc06053506" "Cartridge.Manufacturer" "Imagic, Michael Greene" "Cartridge.ModelNo" "EIZ-002-04I" "Cartridge.Name" "Wing War (1983) (Imagic) (PAL) [a]" "" "Cartridge.MD5" "f032b2f2d8323404a6b4541f92dd1825" "Cartridge.Name" "Many Blue Bars and Text Demo 3 (PD)" "" "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" "805f9a32ef97ac25f999a25014dc5c23" "Cartridge.Manufacturer" "SnailSoft" "Cartridge.Name" "Balthazar (SnailSoft)" "Cartridge.Note" "AKA Babylon 5" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e3ed4ba3361756970f076e46e9cad1d2" "Cartridge.Name" "Tennis (Unknown) (PAL) (4K) [a]" "" "Cartridge.MD5" "73a710e621d44e97039d640071908aef" "Cartridge.Name" "Barber Pole Demo (PD)" "" "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" "929e8a84ed50601d9af8c49b0425c7ea" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG205" "Cartridge.Name" "Dancing Plate (1982) (BitCorp) (PAL)" "Cartridge.Note" "AKA Dancing Plates, Tanzende Teller" "Display.Phosphor" "YES" "" "Cartridge.MD5" "de0173ed6be9de6fd049803811e5f1a8" "Cartridge.Manufacturer" "Xonox - K-Tel Software, Anthony R. Henderson" "Cartridge.ModelNo" "99008, 6240" "Cartridge.Name" "Motocross Racer (1983) (Xonox)" "" "Cartridge.MD5" "2a0ba55e56e7a596146fa729acf0e109" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-019" "Cartridge.Name" "Sky Jinks (1982) (Activision)" "" "Cartridge.MD5" "378c118b3bda502c73e76190ca089eef" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX2662P" "Cartridge.Name" "Hangman (1978) (Atari) (PAL)" "" "Cartridge.MD5" "085322bae40d904f53bdcc56df0593fc" "Cartridge.Manufacturer" "Parker Brothers, Dave Engman, Dawn Stockbridge" "Cartridge.ModelNo" "PB5340" "Cartridge.Name" "Tutankham (1983) (Parker Bros)" "" "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" "21d2c435bcccde7792d82844b3cf60f4" "Cartridge.Manufacturer" "Atari - GCC, Doug Macrae" "Cartridge.ModelNo" "CX2677, CX2677P" "Cartridge.Name" "Dig Dug (1983) (Atari) (PAL) [a]" "" "Cartridge.MD5" "810d8952af5a6036fca8d0c4e1b23db6" "Cartridge.Manufacturer" "Tiger Vision - Eram" "Cartridge.Name" "Keystone (Tiger Vision)" "Cartridge.Note" "AKA Keystone Kapers" "" "Cartridge.MD5" "3e899eba0ca8cd2972da1ae5479b4f0d" "Cartridge.Manufacturer" "Coleco, Joseph Biel" "Cartridge.ModelNo" "2457" "Cartridge.Name" "Venture (1982) (Coleco)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "600d48eef5c0ec27db554b7328b3251c" "Cartridge.Name" "Bars and Text Demo 3 (PD)" "" "Cartridge.MD5" "2e0aed5bb619edcefa3fafb4fbe7c551" "Cartridge.Name" "Qb (2.06) (Retroactive) (NTSC)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b1486e12de717013376447ac6f7f3a80" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "292.542 8" "Cartridge.Name" "Marspatrouille (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Gas Hog" "" "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" "a30ece6dc4787e474fbc4090512838dc" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Circus (Zellers)" "Cartridge.Note" "AKA Circus Atari" "" "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" "94e4c9b924286038527f49cdc20fda69" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.12) (Stella) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d6d1ddd21e9d17ea5f325fa09305069c" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Time Warp (1982) (Funvision) (PAL)" "" "Cartridge.MD5" "f844f4c6f3baaaf5322657442d6f29eb" "Cartridge.Manufacturer" "Atari, Richard Dobbis, Nick 'Sandy Maiwald' Turner" "Cartridge.ModelNo" "CX26111" "Cartridge.Name" "Snoopy and the Red Baron (1983) (Atari) (PAL)" "" "Cartridge.MD5" "ff87d58125ae517eb7b09a0475a1ccdc" "Cartridge.Name" "SCSIcide (Score Hack 1) (24-02-2001) (Joe Grand) (PD)" "" "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" "" "Cartridge.MD5" "244c6de27faff527886fc7699a41c3be" "Cartridge.Name" "Matt Demo (PD)" "" "Cartridge.MD5" "81b3bf17cf01039d311b4cd738ae608e" "Cartridge.Manufacturer" "CBS Electronics, Joe Gaucher, Alex Leavens" "Cartridge.ModelNo" "M8776, M8793" "Cartridge.Name" "Gorf (1982) (CBS Electronics)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4c4ce802cbfd160f7b3ec0f13f2a29df" "Cartridge.Name" "Beta Demo (V1.1) (26-09-2002) (MP)" "" "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" "77887e4192a6b0a781530e6cf9be7199" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX2604" "Cartridge.Name" "Space War (1978) (Atari) [b1]" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "66706459e62514d0c39c3797cbf73ff1" "Cartridge.Manufacturer" "Video Gems" "Cartridge.ModelNo" "VG-05" "Cartridge.Name" "Treasure Below (1983) (Video Gems) (PAL)" "Console.RightDifficulty" "A" "" "Cartridge.MD5" "784176346e9422733d55c427230e5bad" "Cartridge.Manufacturer" "Activision, Alex DeMeo" "Cartridge.Name" "Title Match Pro Wrestling (1989) (Activision)" "" "Cartridge.MD5" "a20b7abbcdf90fbc29ac0fafa195bd12" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "719.383 2 - 649635, 781393, 781784" "Cartridge.Name" "Motocross (1983) (Quelle) (PAL)" "" "Cartridge.MD5" "e51030251e440cffaab1ac63438b44ae" "Cartridge.Manufacturer" "Parker Brothers, Joe Gaucher, Louis Marbel" "Cartridge.ModelNo" "PB5110" "Cartridge.Name" "James Bond 007 (1983) (Parker Bros)" "Cartridge.Rarity" "Rare" "Display.Phosphor" "YES" "" "Cartridge.MD5" "1442d1b35a6478fba22ae7dd1fcb5634" "Cartridge.Name" "Thrust (V0.2) (2000) (TJ)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "2a9f9001540c55a302befd8e9d54b47b" "Cartridge.Manufacturer" "Atari, Dan Hitchens" "Cartridge.ModelNo" "CX2697, CX2697P" "Cartridge.Name" "Mario Bros. (1983) (Atari) (PAL) [a]" "" "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" "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" "283dee88f295834c4c077d788f151125" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.11) (Retroactive) (PAL)" "Display.Phosphor" "YES" "" "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" "951e8cec7a1a1d6c01fd649e7ff7743a" "Cartridge.Manufacturer" "Atari, Adam Clayton, John Howard Palevich" "Cartridge.ModelNo" "CX26151, CX26151P" "Cartridge.Name" "Dark Chambers (1988) (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7991e1797e5e9f311fd957e62d889dff" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide (v1.1) (2001) (Joe Grand)" "Cartridge.Rarity" "New Release" "Controller.Left" "PADDLES_IAXDR" "" "Cartridge.MD5" "9d37a1be4a6e898026414b8fee2fc826" "Cartridge.Manufacturer" "M Network, David Rolfe - INTV" "Cartridge.ModelNo" "MT5665" "Cartridge.Name" "Super Challenge Baseball (1982) (M Network)" "" "Cartridge.MD5" "d8e4c8e2d210270cd1e0f6d1b4582b91" "Cartridge.Manufacturer" "Imagic, Mark Klein" "Cartridge.ModelNo" "EIZ-003-04I" "Cartridge.Name" "Subterranea (1983) (Imagic) (PAL) [a]" "" "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" "43c6cfffeddab6b3787357fed9d44529" "Cartridge.Manufacturer" "20th Century Fox Video Games, Douglas 'Dallas North' Neubauer" "Cartridge.ModelNo" "11111" "Cartridge.Name" "M.A.S.H (1983) (20th Century Fox) (PAL)" "" "Cartridge.MD5" "d44d90e7c389165f5034b5844077777f" "Cartridge.Manufacturer" "Parker Brothers, Larry Gelberg, Gary Goltz" "Cartridge.ModelNo" "PB5065" "Cartridge.Name" "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "665b8f8ead0eef220ed53886fbd61ec9" "Cartridge.Manufacturer" "Telesys, Don 'Donyo' Ruffcorn, Jack Woodman" "Cartridge.ModelNo" "1003" "Cartridge.Name" "Fast Food (1982) (Telesys)" "" "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" "f9cef637ea8e905a10e324e582dd39c2" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Private Eye (CCE)" "" "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" "4fbe0f10a6327a76f83f83958c3cbeff" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-816" "Cartridge.Name" "Keystone Kappers (1983) (CCE)" "Cartridge.Note" "AKA Keystone Kapers" "" "Cartridge.MD5" "a4aa7630e4c0ad7ebb9837d2d81de801" "Cartridge.Name" "Atari 2600 Invaders (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "d071d2ec86b9d52b585cc0382480b351" "Cartridge.Manufacturer" "UA Limited" "Cartridge.Name" "Cat Trax (1983) (UA Limited) (Prototype) [a]" "Cartridge.Rarity" "Prototype" "Display.YStart" "30" "Display.Phosphor" "YES" "" "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" "e600f5e98a20fafa47676198efe6834d" "Cartridge.Manufacturer" "Parker Brothers" "Cartridge.ModelNo" "PB5080" "Cartridge.Name" "Gyruss (1984) (Parker Bros) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f8582bc6ca7046adb8e18164e8cecdbc" "Cartridge.Name" "Panda Chase (Unknown) (PAL)" "" "Cartridge.MD5" "955c408265ad6994f61f9b66657bbae9" "Cartridge.Name" "Quadrun (Video Conversion) (Fabrizio Zavagli)" "" "Cartridge.MD5" "798cc114f1623c14085868cd3494fe8e" "Cartridge.Name" "Pins Revenge (Atari Freak 1)" "" "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" "e5bacf526036d3c8c99db5b030cf00e7" "Cartridge.Name" "Starmaster (Genesis)" "Cartridge.Note" "Genesis controller (C switches to map mode)" "Cartridge.Rarity" "Hack of Starmaster" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "bd39598f067a1193ae81bd6182e756d1" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Night Stalker (1989) (Telegames) (PAL)" "Cartridge.Note" "AKA Dark Cavern" "" "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" "aa5cfe3b20395aba1d479135943ad85c" "Cartridge.Name" "Defender (Hack) (Unknown)" "Cartridge.Rarity" "Hack of Defender" "" "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" "a47e26096de6f6487bf5dd2d1cced294" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX2643" "Cartridge.Name" "Codebreaker (1978) (Atari) (PAL)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "Display.YStart" "57" "" "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" "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" "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" "d85f1e35c5445ac898746719a3d93f09" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "731.503 9" "Cartridge.Name" "Tom's Eierjagd (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Play Farm" "" "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" "f3dfae774f3bd005a026e29894db40d3" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "649635" "Cartridge.Name" "See Saw (Double-Game Package) (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Circus Atari" "" "Cartridge.MD5" "2808dc745ff4321dc5c8122abef6711f" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.11) (Retroactive) (Stella)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "33d68c3cd74e5bc4cf0df3716c5848bc" "Cartridge.Manufacturer" "CBS Electronics, Tom DiDomenico" "Cartridge.ModelNo" "4L 2486 5000" "Cartridge.Name" "Blueprint (1983) (CBS Electronics)" "Display.YStart" "32" "Display.Phosphor" "YES" "" "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" "58d331c23297ed98663d11b869636f16" "Cartridge.Name" "Fu Kung! (V0.09) (26-01-2003) (AD)" "" "Cartridge.MD5" "8b504b417c8626167a7e02f44229f0e7" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V1.00) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f69d4fcf76942fcd9bdf3fd8fde790fb" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Aquaventure (CCE)" "" "Cartridge.MD5" "169d4c7bd3a4d09e184a3b993823d048" "Cartridge.Name" "Superman (Unknown) (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" "29396db58406084e416032c372734a3e" "Cartridge.Name" "Gunfight 2600 - Fixed Beta Release! (2001) (MP)" "" "Cartridge.MD5" "c49fe437800ad7fd9302f3a90a38fb7d" "Cartridge.Manufacturer" "Atari, Dan Hitchens" "Cartridge.ModelNo" "CX2697, CX2697P" "Cartridge.Name" "Mario Bros. (1983) (Atari) (PAL)" "" "Cartridge.MD5" "024365007a87f213cbe8ef5f2e8e1333" "Cartridge.Manufacturer" "Atari, Frank Hausman, Steve Woita" "Cartridge.ModelNo" "CX2686" "Cartridge.Name" "Quadrun (1983) (Atari)" "" "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" "5f2b4c155949f01c06507fb32369d42a" "Cartridge.Manufacturer" "Apollo, Ed Salvo" "Cartridge.ModelNo" "AP-1001" "Cartridge.Name" "Skeet Shoot (1981) (Apollo) (4K)" "" "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" "5e2928f089490017e88e9f9e5a881a25" "Cartridge.Name" "Star Fire - Faster Skipping 1 (24-10-2002) (MP)" "" "Cartridge.MD5" "d7b58303ec8d8c4dbcbf54d3b9734c7e" "Cartridge.Name" "Paddle Demo (Joe Grand) (PD)" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "" "Cartridge.MD5" "69974dd5d6420b90898cde50aec5ef39" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-009, AG-009-04" "Cartridge.Name" "Freeway (1981) (Activision) (16K)" "" "Cartridge.MD5" "888debb162d7d1ae71025b4ab794257f" "Cartridge.Name" "Interleaved ChronoColour - Nude Art (17-04-2003) (AD)" "" "Cartridge.MD5" "61426cee013306e7f7367534ab124747" "Cartridge.Name" "One Blue Bar Demo (PD)" "" "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" "7a2af383014f5d810ad26d322823549d" "Cartridge.Name" "FlickerSort Demo (20-04-2002) (MP)" "" "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" "" "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" "7ccf350354ee15cd9b85564a2014b08c" "Cartridge.Name" "Big Dig (13-04-2003) (CT)" "" "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" "73cb1f1666f3fd30b52b4f3d760c928f" "Cartridge.Name" "Mines of Minos (Unknown) (PAL)" "Display.YStart" "24" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4bdae9246d6ee258c26665512c1c8de3" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Human Cannonball (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "6cd1dc960e3e8d5c5e0fbe67ab49087a" "Cartridge.Name" "Vertical Playfield Demo 1 (PD)" "" "Cartridge.MD5" "e77ec259e1387bc308b0534647a89198" "Cartridge.Manufacturer" "Parker Brothers, David Lamkins, Laura Nikolich" "Cartridge.ModelNo" "931503" "Cartridge.Name" "Spider-Man (1982) (Parker Bros) (PAL)" "" "Cartridge.MD5" "e3c0451d29dad724231bc5818ec4bae0" "Cartridge.Name" "Single-Scanline Positioning Demo 1 (2001) (Roger Williams)" "" "Cartridge.MD5" "42dcc02777b0bcfacd85aeb61d33558a" "Cartridge.Name" "Human Cannonball (Unknown) (PAL) (4K)" "" "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" "6a9b30ca46b0dba9e719f4cbd340e01c" "Cartridge.Name" "Frostbite (Unknown) (PAL) (Hack)" "" "Cartridge.MD5" "a98b649912b6ca19eaf5c2d2faf38562" "Cartridge.Name" "This Planet Sucks (Greg Troutman) (PAL) [!]" "Cartridge.Rarity" "New Release" "Display.YStart" "38" "" "Cartridge.MD5" "57c5b351d4de021785cf8ed8191a195c" "Cartridge.Manufacturer" "Atari, 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" "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" "f9de91d868d6ebfb0076af9063d7195e" "Cartridge.Name" "Maze Demo 2 (PD)" "" "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" "7b938c7ddf18e8362949b62c7eaa660a" "Cartridge.Manufacturer" "Atari, Bob Whitehead - Sears" "Cartridge.ModelNo" "CX2603 - 99803, 49-75601" "Cartridge.Name" "Star Ship (1977) (Atari) (4K)" "" "Cartridge.MD5" "b8865f05676e64f3bec72b9defdacfa7" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-004" "Cartridge.Name" "Fishing Derby (1980) (Activision)" "" "Cartridge.MD5" "23d445ea19a18fb78d5035878d9fb649" "Cartridge.Manufacturer" "CBS Electronics, Sylvia Day, Henry Will IV" "Cartridge.ModelNo" "4L1818, 4L1819, 4L1820" "Cartridge.Name" "Mouse Trap (1982) (CBS Electronics) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "212d0b200ed8b45d8795ad899734d7d7" "Cartridge.Manufacturer" "Atari, Richard Maurer, Christopher H. Omarzu - Coca Cola" "Cartridge.Name" "Pepsi Invaders (1983) (Atari)" "" "Cartridge.MD5" "2496d404bfc561a40a80bea6a69695c3" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1007" "Cartridge.Name" "Jungle Hunt (1983) (CCE) [a]" "" "Cartridge.MD5" "425ee444a41d218598893d6b6e03431a" "Cartridge.Name" "Invaders Demo (2001) (TJ)" "" "Cartridge.MD5" "cf3a9ada2692bb42f81192897752b912" "Cartridge.Name" "Air Raiders (Unknown) (PAL)" "" "Cartridge.MD5" "f49a34f1fdd7dc147cbf96ce2ce71b76" "Cartridge.Name" "Qb (Special Edition) (PAL) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2f77f015fc880b05f28e84156f989a0c" "Cartridge.Name" "Plane Demo (Gonzalo) (PD)" "" "Cartridge.MD5" "a0e2d310e3e98646268200c8f0f08f46" "Cartridge.Manufacturer" "Atari, Ed Logg, Carol Shaw" "Cartridge.ModelNo" "CX2639, CX2639P" "Cartridge.Name" "Othello (1981) (Atari) (PAL)" "" "Cartridge.MD5" "87bea777a34278d29b3b6029833c5422" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Polaris (1983) (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "ec5c861b487a5075876ab01155e74c6c" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Ed Salvo, Byron Parks" "Cartridge.ModelNo" "AP-2001" "Cartridge.Name" "Spacechase (1981) (Apollo)" "" "Cartridge.MD5" "59d33e00c07665395209c1e55da0b139" "Cartridge.Name" "Imagic Selector ROM (1982) (Imagic)" "" "Cartridge.MD5" "f6efa00ae99aaf33e427b674bcfd834d" "Cartridge.Name" "2600 Digital Clock (Demo 3) (PD)" "" "Cartridge.MD5" "dbdaf82f4f0c415a94d1030271a9ef44" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Kaboom! (CCE)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01" "" "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" "5faffe1c4c57430978dec5ced32b9f4a" "Cartridge.Manufacturer" "Dactari - Milmar" "Cartridge.Name" "Volleyball (Dactari - Milmar)" "Cartridge.Note" "AKA RealSports Volleyball" "" "Cartridge.MD5" "3ef9573536730dcd6d9c20b6822dbdc4" "Cartridge.Manufacturer" "Atari, Larry Wagner, Bob Whitehead" "Cartridge.ModelNo" "CX2645, CX2645P" "Cartridge.Name" "Video Chess (1979) (Atari) (PAL)" "" "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" "91fdb6541f70c40b16aabf8308123be8" "Cartridge.Name" "Interlacing Game (19-08-2002) (Billy Eno)" "" "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" "f687ec4b69611a7f78bd69b8a567937a" "Cartridge.Manufacturer" "Activision, Alan Miller - Ariola" "Cartridge.ModelNo" "EAZ-028 - 711 028-725" "Cartridge.Name" "Robot Tank (1983) (Activision) (PAL)" "" "Cartridge.MD5" "2351d26d0bfdee3095bec9c05cbcf7b0" "Cartridge.Name" "Warring Worms (19-01-2002) (Billy Eno)" "" "Cartridge.MD5" "4f7b07ec2bef5ccffe06403a142f80db" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Ed Salvo, Byron Parks" "Cartridge.ModelNo" "AP-2003" "Cartridge.Name" "Racquetball (1981) (Apollo) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e97eafd0635651d3999cece953c06bd5" "Cartridge.Name" "M.A.S.H (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "20ae62fb69c6cc6e8098cca8cd080487" "Cartridge.Manufacturer" "Zirok" "Cartridge.Name" "Tennis (Zirok)" "" "Cartridge.MD5" "8786c1e56ef221d946c64f6b65b697e9" "Cartridge.Manufacturer" "20th Century Fox Video Games, David Lubar" "Cartridge.ModelNo" "11015" "Cartridge.Name" "AKA Space Adventure" "" "Cartridge.MD5" "08bf437d012db07b05ff57a0c745c49e" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Hales, Stephen Harland 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" "4f634893d54e9cabe106e0ec0b7bdcdf" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.14) (Retroactive) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "956496f81775de0b69a116a0d1ad41cc" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Alien (CCE)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b29359f7de62fed6e6ad4c948f699df8" "Cartridge.Manufacturer" "Puzzy - Bit Corporation" "Cartridge.ModelNo" "PG203" "Cartridge.Name" "Phantom Tank (1982) (Puzzy) (PAL)" "" "Cartridge.MD5" "298387b0637173d2002770a649b4fbca" "Cartridge.Name" "S.I.PLIX 2 (Hack) [a]" "Cartridge.Note" "Hack of Kaboom!" "Cartridge.Rarity" "Hack" "Controller.Left" "PADDLES" "" "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" "d2d8c4f1ea7f347c8bcc7d24f45aa338" "Cartridge.Name" "20 Sprites at Once Demo 5 (PD)" "" "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" "Display.YStart" "48" "" "Cartridge.MD5" "dc81c4805bf23959fcf2c649700b82bf" "Cartridge.Manufacturer" "Imagic, Michael Greene" "Cartridge.ModelNo" "720055-2A, IA3312P" "Cartridge.Name" "No Escape! (1982) (Imagic) (PAL)" "" "Cartridge.MD5" "46e9428848c9ea71a4d8f91ff81ac9cc" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Astroblast (1989) (Telegames) (PAL)" "Cartridge.Note" "Can also use left joystick" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "" "Cartridge.MD5" "5bba254e18257e578c245ed96f6b003b" "Cartridge.Name" "Music Effects Demo (21-01-2003) (Paul Slocum)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "635cc7a0db33773959d739d04eff96c2" "Cartridge.Name" "Minesweeper (V.90) (Soren Gust) (PD)" "" "Cartridge.MD5" "0d5af65ad3f19558e6f8e29bf2a9d0f8" "Cartridge.Manufacturer" "Atari, Adam Clayton, John Howard Palevich" "Cartridge.ModelNo" "CX26151, CX26151P" "Cartridge.Name" "Dark Chambers (1988) (Atari) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "fe0b7f27e3ad50bbf9ff468ee56d553d" "Cartridge.Name" "Lines Demo (Eckhard Stolberg) (PAL) (PD)" "" "Cartridge.MD5" "2abc3d46b3f2140160759e2e10bc86d9" "Cartridge.Name" "Gunfight 2600 - Beta Release! (2001) (MP)" "" "Cartridge.MD5" "2d405da70af82b20a6b3ecc3d1d2c4ec" "Cartridge.Manufacturer" "Genus" "Cartridge.Name" "Pitfall (Genus)" "Cartridge.Note" "AKA Pitfall!" "" "Cartridge.MD5" "7ef74879d7cb9fa0ef161b91ad55b3bb" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Vanguard (CCE)" "" "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" "9e792a59f8795664cbaaff1ba152d731" "Cartridge.Name" "Bullet Demo (20-12-2002) (CT)" "" "Cartridge.MD5" "f6d512bef1bf253dc935d0e13c3d1462" "Cartridge.Name" "Slot Racers (Unknown) (PAL) (4K)" "" "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" "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" "f750b5d613796963acecab1690f554ae" "Cartridge.Manufacturer" "Manuel Polik" "Cartridge.Name" "Gunfight 2600 (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "58e313e2b5613b2439b5f12bb41e3eef" "Cartridge.Name" "Cube Conquest (Demo Interlace) (Billy Eno) (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cfef1a2d1f6a5ee7a5e1f43f3056f112" "Cartridge.Name" "Skeleton+ (05-05-2003) (Eric Ball) (NTSC)" "Cartridge.Sound" "STEREO" "" "Cartridge.MD5" "1d284d6a3f850bafb25635a12b316f3d" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "H.E.R.O. (CCE)" "" "Cartridge.MD5" "b4f87ce75f7329c18301a2505fe59cd3" "Cartridge.Manufacturer" "Videospielkassett - Ariola" "Cartridge.ModelNo" "PGP232" "Cartridge.Name" "Autorennen (Ariola) (PAL)" "Cartridge.Note" "AKA Grand Prix" "" "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" "5a17e30e6e911e74ccd7b716d02b16c6" "Cartridge.Manufacturer" "Activision, Dan Kitchen" "Cartridge.ModelNo" "AX-029" "Cartridge.Name" "Crackpots (1983) (Activision) (8K)" "" "Cartridge.MD5" "e927ecf80f3784d745abd8368d78f2f3" "Cartridge.Name" "Space Instigators (V1.8) (19-10-2002) (CT) [a1]" "" "Cartridge.MD5" "d245e2f27c84016041e9496b66b722fe" "Cartridge.Name" "Gunfight 2600 - The Final Kernel (MP)" "" "Cartridge.MD5" "4e66c8e7c670532569c70d205f615dad" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2680, CX2680P" "Cartridge.Name" "RealSports Tennis (1983) (Atari) (PAL)" "" "Cartridge.MD5" "3b9480bb6fb1e358c9c0a64e86945aee" "Cartridge.Name" "Title Match Pro Wrestling (2002) (Skyworks)" "" "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" "a56b642a3d3ab9bbeee63cd44eb73216" "Cartridge.Manufacturer" "Carrere Video, Sylvia Day, Henry Will IV - Teldec" "Cartridge.ModelNo" "USC2001" "Cartridge.Name" "Gopher (1983) (Carrere Video) (PAL)" "" "Cartridge.MD5" "b49331b237c8f11d5f36fe2054a7b92b" "Cartridge.Name" "Condor Attack (Unknown) (PAL)" "" "Cartridge.MD5" "c032c2bd7017fdfbba9a105ec50f800e" "Cartridge.Manufacturer" "Activision, Charlie Heath" "Cartridge.Name" "Thwocker (04-09-1984) (Activision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "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" "" "Cartridge.MD5" "a3f8aebb38182749cb8da85cfbc63d7c" "Cartridge.Name" "Tennis (208 in 1) (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "09abfe9a312ce7c9f661582fdf12eab6" "Cartridge.Manufacturer" "Atari, Douglas Neubauer" "Cartridge.ModelNo" "CX26154" "Cartridge.Name" "Super Football (1988) (Atari)" "" "Cartridge.MD5" "262ccb882ff617d9b4b51f24aee02cbe" "Cartridge.Manufacturer" "Atari, Douglas Neubauer" "Cartridge.ModelNo" "CX26154, CX26154P" "Cartridge.Name" "Super Football (1988) (Atari) (PAL)" "" "Cartridge.MD5" "36edef446ab4c2395666efc672b92ed0" "Cartridge.Manufacturer" "Atari - Axlon" "Cartridge.ModelNo" "CX26168" "Cartridge.Name" "Off the Wall (1989) (Atari) (PAL)" "" "Cartridge.MD5" "2982e655dffc89d218a0a3072cfc6811" "Cartridge.Name" "Mini Golf 812631 (Hack)" "Cartridge.Note" "Hack of Miniature Golf" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "95956108289a917f80667eccd3ce98a9" "Cartridge.Manufacturer" "Atari, Ed Logg, Carol Shaw" "Cartridge.ModelNo" "CX2639, CX2639P" "Cartridge.Name" "Othello (1981) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "d4806775693fcaaa24cf00fc00edcdf3" "Cartridge.Manufacturer" "Atari, Robert C. Polaro" "Cartridge.ModelNo" "CX26140, CX26140P" "Cartridge.Name" "Desert Falcon (1987) (Atari) (PAL)" "Cartridge.Note" "AKA Nile Flyer, Sphinx" "Display.Format" "PAL" "Display.YStart" "22" "" "Cartridge.MD5" "3ec12372ca3e870b11ca70edc7ec26a4" "Cartridge.Manufacturer" "CommaVid, John Bronstein" "Cartridge.ModelNo" "CM-002" "Cartridge.Name" "Video Life (1981) (CommaVid) (4K)" "Display.Phosphor" "YES" "" "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" "a4c08c4994eb9d24fb78be1793e82e26" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AX-012, CAX-012, AX-012-04" "Cartridge.Name" "Ice Hockey (1981) (Activision)" "" "Cartridge.MD5" "470878b9917ea0348d64b5750af149aa" "Cartridge.Manufacturer" "Atari, Suki Lee - Sears" "Cartridge.ModelNo" "CX2658 - 49-75128" "Cartridge.Name" "Math Gran Prix (1982) (Atari)" "" "Cartridge.MD5" "dbdd21e1ee3d72119e8cd14d943c585b" "Cartridge.Name" "Slot Machine (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "133a4234512e8c4e9e8c5651469d4a09" "Cartridge.Manufacturer" "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee" "Cartridge.ModelNo" "CX26117" "Cartridge.Name" "Obelix (1983) (Atari)" "" "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" "c47244f5557ae12c61e8e01c140e2173" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, John Allred" "Cartridge.ModelNo" "CX2688, CX2688P" "Cartridge.Name" "Jungle Hunt (1983) (Atari) (PAL) [a1]" "" "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" "50200f697aeef38a3ce31c4f49739551" "Cartridge.Manufacturer" "Mystique - American Multiple Industries, Joel H. Martin" "Cartridge.Name" "Custer's Revenge (1982) (Mystique) (PAL60)" "Display.Format" "PAL60" "" "Cartridge.MD5" "95351b46fa9c45471d852d28b9b4e00b" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Golf (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "435fd469f088468c4d66be6b5204d887" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2680, CX2680P" "Cartridge.Name" "RealSports Tennis (1983) (Atari) (PAL) [a]" "" "Cartridge.MD5" "b6821ac51c4c1dcb283f01be2f047dc1" "Cartridge.Name" "Rubik's Cube 3D Demo (25-11-2002) (TJ)" "" "Cartridge.MD5" "e609e8a007127b8fcff79ffc380da6b1" "Cartridge.Name" "Multi-Sprite Game V2.3 (Piero Cavina) (PD)" "" "Cartridge.MD5" "f0daaa966199ef2b49403e9a29d12c50" "Cartridge.Name" "Mr. Postman (Unknown)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "4ac9f40ddfcf194bd8732a75b3f2f214" "Cartridge.Manufacturer" "Atari, Stephan R. Keith, Preston Stuart" "Cartridge.ModelNo" "CX26106" "Cartridge.Name" "Grover's Music Maker (12-29-1982) (Atari) (Prototype)" "Cartridge.Note" "Uses Kids/Keypad Controllers" "Cartridge.Rarity" "Prototype" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "0dfbdadf8f1bc718e7e1bb3ccd5fef3d" "Cartridge.Name" "Mr. Pac-Man (New start tune) (El Destructo)" "" "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" "1db3bc4601f22cf43be7ce015d74f59a" "Cartridge.Name" "Ship Demo (V 10) (PD)" "" "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" "da7a17dcdaa62d6971393c0a6faf202a" "Cartridge.Name" "Flag Capture (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "668dc528b7ea9345140f4fcfbecf7066" "Cartridge.Manufacturer" "Gakken" "Cartridge.ModelNo" "001" "Cartridge.Name" "Pooyan (1983) (Gakken) (PAL)" "" "Cartridge.MD5" "537ed1e0d80e6c9f752b33ea7acbe079" "Cartridge.Name" "A-VCS-tec Challenge (beta 5) (PD)" "" "Cartridge.MD5" "f6b5ebb65cbb2981af4d546c470629d7" "Cartridge.Manufacturer" "Coleco, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (09-13-1984) (Coleco) (Prototype) [a]" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "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" "3c4223316c835ceaad619651e25df0f9" "Cartridge.Name" "Defender (Genesis)" "Cartridge.Note" "Genesis controller (C is smartbomb)" "Cartridge.Rarity" "Hack of Defender" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "e21ee3541ebd2c23e817ffb449939c37" "Cartridge.Manufacturer" "Tigervision, Karl T. Olinger" "Cartridge.ModelNo" "7-001" "Cartridge.Name" "King Kong (1982) (Tigervision)" "Display.YStart" "28" "" "Cartridge.MD5" "b049fc8ac50be7c2f28418817979c637" "Cartridge.Manufacturer" "Activision, David Lubar" "Cartridge.ModelNo" "EAK-048-04, EAK-048-04B" "Cartridge.Name" "River Raid II (1988) (Activision) (PAL)" "" "Cartridge.MD5" "8644352b806985efde499ae6fc7b0fec" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-801" "Cartridge.Name" "Mr. Postman (1983) (CCE)" "" "Cartridge.MD5" "d0b26e908370683ad99bc6b52137a784" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Ernie Runyon, Ed Salvo - RCA Video Jeux" "Cartridge.ModelNo" "AP-2004" "Cartridge.Name" "Lost Luggage (1981) (Apollo) (PAL)" "Cartridge.Note" "AKA La valise piegee" "" "Cartridge.MD5" "7c9b3b8b25acf2fe3b8da834f69629c6" "Cartridge.Name" "I Robot (1984) (Atari) (Prototype) [!]" "" "Cartridge.MD5" "e63efdfda9a4003dcd77a854a781a06a" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "Combat Rock (PD) (Hack) [a]" "Cartridge.Note" "Hack of Combat" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "4f6702c3ba6e0ee2e2868d054b00c064" "Cartridge.Manufacturer" "Activision, Steve 'Jessica' Kitchen - Ariola" "Cartridge.ModelNo" "EAZ-033 - 711 033-725" "Cartridge.Name" "Space Shuttle (1983) (Activision) (PAL)" "" "Cartridge.MD5" "0375f589f7da06d2d2be532e0d4d4b94" "Cartridge.Name" "Push (V0.04) (2001) (AD)" "" "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" "c58708c09ccb61625cda9d15ddcd8be6" "Cartridge.Manufacturer" "SPIKE the Percussionist" "Cartridge.Name" "NOIZ Invaders (SPIKE) (2002) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "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" "803393ed29a9e9346569dd1bf209907b" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker" "Cartridge.ModelNo" "CX2684" "Cartridge.Name" "Galaxian (02-04-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "c569e57dca93d3bee115a49923057fd7" "Cartridge.Name" "Pac-Space (Pac-Man Hack)" "Display.YStart" "33" "" "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" "e61210293b14c9c4ecc91705072c6a7e" "Cartridge.Manufacturer" "Gameworld" "Cartridge.ModelNo" "133-005" "Cartridge.Name" "Bugs (1983) (Gameworld) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "" "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" "ac53b83e1b57a601eeae9d3ce1b4a458" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.15) (Retroactive) (NTSC)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3750f2375252b6a20e4628692e94e8b1" "Cartridge.Manufacturer" "Dismac" "Cartridge.Name" "Ases do Ar (Dismac)" "Cartridge.Note" "AKA Sky Jinks" "" "Cartridge.MD5" "8e887d1ba5f3a71ae8a0ea16a4af9fc9" "Cartridge.Name" "Skeleton (V1.1) (PAL) (24-10-2002) (Eric Ball)" "" "Cartridge.MD5" "b1e2d5dc1353af6d56cd2fe7cfe75254" "Cartridge.Manufacturer" "Atari - Axlon, Steve DeFrisco" "Cartridge.ModelNo" "CX26171" "Cartridge.Name" "MotoRodeo (1990) (Atari) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "68489e60268a5e6e052bad9c62681635" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG201" "Cartridge.Name" "Sea Monster (1982) (BitCorp) (PAL)" "Display.YStart" "36" "Display.Height" "256" "" "Cartridge.MD5" "4311a4115fb7bc68477c96cf44cebacf" "Cartridge.Name" "Challenge (Unknown)" "Display.YStart" "14" "Display.Height" "240" "" "Cartridge.MD5" "0ec93f519bb769e0d9f80e61f6cc8023" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, John Allred" "Cartridge.ModelNo" "CX2688" "Cartridge.Name" "Jungle Hunt (02-25-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "1e85f8bccb4b866d4daa9fcf89306474" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.ModelNo" "CX26122" "Cartridge.Name" "Sinistar (02-13-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "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" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5d2cc33ca798783dee435eb29debf6d6" "Cartridge.Manufacturer" "Activision, Mike Riedel" "Cartridge.ModelNo" "AK-043-04" "Cartridge.Name" "Commando (1988) (Activision)" "" "Cartridge.MD5" "76f66ce3b83d7a104a899b4b3354a2f2" "Cartridge.Manufacturer" "UA Limited" "Cartridge.Name" "Cat Trax (1983) (UA Limited) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "30" "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" "f90b5da189f24d7e1a2117d8c8abc952" "Cartridge.Manufacturer" "Atari, David Crane - Sears" "Cartridge.ModelNo" "CX2653 - 6-99823, 49-75111" "Cartridge.Name" "Slot Machine (1979) (Atari)" "" "Cartridge.MD5" "73158ea51d77bf521e1369311d26c27b" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Challenge (Zellers)" "Display.YStart" "25" "" "Cartridge.MD5" "c482f8eebd45e0b8d479d9b71dd72bb8" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Push (V0.03) (1998) (AD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "bb9f06b288b5275bc0d38b6731b2526a" "Cartridge.Name" "Star Fire - Meteor Dance 2 (18-11-2002) (MP)" "" "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" "740b47df422372fbef700b42cea4e0bf" "Cartridge.Name" "Dizzy Wiz (2001) (B. Watson)" "" "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" "fd8b4ee0d57605b35e236e814f706ff1" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, John Mracek" "Cartridge.ModelNo" "CX2673, CX2673P" "Cartridge.Name" "Phoenix (1982) (Atari) (PAL) [a]" "" "Cartridge.MD5" "3225676f5c0c577aeccfaa7e6bedd765" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1002" "Cartridge.Name" "Pole Position (1983) (CCE)" "" "Cartridge.MD5" "2e842c2ee22e9dad9df16eed091315c4" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "0701-157" "Cartridge.Name" "2 Pak Special - Motocross, Boom Bang (1990) (HES) (PAL)" "" "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" "8a9d953ac3db52a313a90d6a9b139c76" "Cartridge.Name" "Hangman Invader Biglist3 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "a8435ec570141de5d833c4abec499e55" "Cartridge.Name" "Happy Birthday Demo (2001) (Dennis Debro) (PD)" "" "Cartridge.MD5" "b9b4612358a0b2c1b4d66bb146767306" "Cartridge.Manufacturer" "Commavid, Ben Burch" "Cartridge.ModelNo" "CM-010" "Cartridge.Name" "Rush Hour (1983) (Commavid) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "20" "Display.Height" "230" "" "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" "7eba20c2291a982214cc7cbe8d0b47cd" "Cartridge.Manufacturer" "Imagic, Dave Johnson" "Cartridge.ModelNo" "720119-1A, 03211" "Cartridge.Name" "Quick Step! (1983) (Imagic)" "" "Cartridge.MD5" "21299c8c3ac1d54f8289d88702a738fd" "Cartridge.Manufacturer" "K-Tel Vision" "Cartridge.Name" "Spider Maze (1982) (K-Tel Vision)" "Cartridge.Note" "AKA Spider Kong" "Display.YStart" "25" "Display.Height" "220" "" "Cartridge.MD5" "07f91e33e76f53bb9d2731fd5d8a35a5" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX2632" "Cartridge.Name" "Space Invaders (1978) (Atari) [t1]" "Cartridge.Rarity" "Common" "" "Cartridge.MD5" "c2a37f1c7603c5fd97df47d6c562abfa" "Cartridge.Manufacturer" "Roger Williams" "Cartridge.Name" "Bar-Score Demo (2001) (Roger Williams)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "4a7eee19c2dfb6aeb4d9d0a01d37e127" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Crazy Valet (Hozer Video Games)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "ae682886058cd6981c4b8e93e7b019cf" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.12) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0b24658714f8dff110a693a2052cc207" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-815" "Cartridge.Name" "Seaquest (1983) (CCE)" "" "Cartridge.MD5" "f8648d0c6ad1266434f6c485ff69ec40" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Oink! (CCE)" "" "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" "Display.YStart" "26" "" "Cartridge.MD5" "b80d50ecee73919a507498d0a4d922ae" "Cartridge.Manufacturer" "20th Century Fox Video Games, David Lubar" "Cartridge.ModelNo" "11008" "Cartridge.Name" "Fantastic Voyage (1982) (20th Century Fox)" "Display.YStart" "28" "" "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" "6522717cfd75d1dba252cbde76992090" "Cartridge.Manufacturer" "Home Vision - Gem International Corp." "Cartridge.ModelNo" "VCS83102" "Cartridge.Name" "War 2000 (1983) (Home Vision) (PAL)" "Cartridge.Note" "AKA Astrowar" "" "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" "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" "c7f13ef38f61ee2367ada94fdcc6d206" "Cartridge.Manufacturer" "Parker Brothers, Joe Gaucher" "Cartridge.ModelNo" "PB5370" "Cartridge.Name" "Popeye (1983) (Parker Bros)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d597d35c6022c590d6e75e865738558a" "Cartridge.Name" "Sprite Color Demo (PD)" "" "Cartridge.MD5" "aff8cba0f2d2eb239953dd7116894a08" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (3 of 3) (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "0890a5b089191f45d0f08dd1e3235687" "Cartridge.Name" "Star Fire - 4K Version (25-10-2002) (MP)" "" "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" "a537879d8e82e1061d3ad800479d3b84" "Cartridge.Manufacturer" "Andrew Wallace" "Cartridge.Name" "Brooni (2001) (Andrew Wallace) (PD) (PAL)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "ce89529d6e98a13ddf3d84827bbdfe68" "Cartridge.Name" "Kung Fu Sprite Demo 2 (PD)" "Display.Phosphor" "YES" "" "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" "" "Cartridge.MD5" "9ec1b259a1bcffa63042a3c2b3b90f0a" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-008" "Cartridge.Name" "Laser Blast (1981) (Activision) (16K)" "" "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" "049626cbfb1a5f7a5dc885a0c4bb758e" "Cartridge.Name" "MegaMania (Unknown) (PAL)" "" "Cartridge.MD5" "7b6f3348dbf71ada88db0fdaf7feefe0" "Cartridge.Name" "3-D Corridor (Pink Spiral) (31-03-2003) (AD)" "" "Cartridge.MD5" "d34b933660e29c0a0a04004f15d7e160" "Cartridge.Name" "Multi-Color Demo 5 (Bob Colbert) (PD)" "" "Cartridge.MD5" "7d3cdde63b16fa637c4484e716839c94" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Road Runner (CCE)" "Display.YStart" "20" "" "Cartridge.MD5" "8ccaa442d26b09139685f5b22bf189c4" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V1.01) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "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" "6f75d72e4cf996100ccdd163d57bdac2" "Cartridge.Name" "Star Fire (200203) (MP)" "" "Cartridge.MD5" "7d5c3b7b908752b98e30690e2a3322c2" "Cartridge.Manufacturer" "Dactari - Milmar" "Cartridge.Name" "Freeway (Dactari - Milmar)" "" "Cartridge.MD5" "e88340f5bd2f03e2e9ce5ecfa9c644f5" "Cartridge.Name" "Lock 'n' Chase (Unknown) (PAL)" "" "Cartridge.MD5" "5c0227ad63300670a647fcebf595ea37" "Cartridge.Manufacturer" "Josh" "Cartridge.Name" "Battle for Naboo (Josh) (Hack)" "Cartridge.Note" "Hack of Atlantis" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "c28b29764c2338b0cf95537cc9aad8c9" "Cartridge.Name" "Multi-Color Demo 4 (Bob Colbert) (PD)" "" "Cartridge.MD5" "15fe28d0c8893be9223e8cb2d032e557" "Cartridge.Name" "Towering Inferno (208 in 1) (Unknown) (PAL)" "Display.YStart" "52" "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 (1982) (20th Century Fox)" "" "Cartridge.MD5" "7574480ae2ab0d282c887e9015fdb54c" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Steve Woita" "Cartridge.ModelNo" "CX2699" "Cartridge.Name" "Taz (1983) (Atari)" "" "Cartridge.MD5" "c866c995c0d2ca7d017fef0fc0c2e268" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.00) (Retroactive) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "1f562b89d081e36d58e6fc943512ec05" "Cartridge.Name" "Hangman Man Biglist2 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "5c3a6d27c026f59a96b7af91e8b1bf26" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.Name" "PlayAround Demo (PlayAround) (1982)" "" "Cartridge.MD5" "98e6e34af45a0664597972c3bb31180f" "Cartridge.Name" "Space Instigators (V1.7) (17-10-2002) (CT)" "" "Cartridge.MD5" "cd032ab6764b55438a7b0bfb5e78595a" "Cartridge.Name" "Hangman Pac-Man 4letter (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "3fd53bfeee39064c945a769f17815a7f" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Sea Hawk (CCE)" "Cartridge.Note" "AKA Seahawk" "" "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" "3fe43915e5655cf69485364e9f464097" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-863" "Cartridge.Name" "Fisher Price (1983) (CCE)" "Cartridge.Note" "AKA Skindiver" "" "Cartridge.MD5" "4ca73eb959299471788f0b685c3ba0b5" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-031" "Cartridge.Name" "Frostbite (1983) (Activision)" "" "Cartridge.MD5" "a1403fef01641dcd3980cac9f24d63f9" "Cartridge.Manufacturer" "Dactari - Milmar" "Cartridge.Name" "Atlantis (Dactari - Milmar)" "" "Cartridge.MD5" "d090836f0a4ea8db9ac7abb7d6adf61e" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Yahtzee (Hozer Video Games)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "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" "1aa7344b563c597eecfbfcf8e7093c27" "Cartridge.Manufacturer" "David Marli" "Cartridge.Name" "Slot Invaders (David Marli) (Hack)" "Cartridge.Note" "Hack of Slot Machine" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "f802fa61011dd9eb6f80b271bac479d0" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-023" "Cartridge.Name" "Mole Hunter (Suntek) (PAL)" "Cartridge.Note" "AKA Topy" "Display.YStart" "60" "" "Cartridge.MD5" "4c6afb8a44adf8e28f49164c84144bfe" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG207" "Cartridge.Name" "Mission 3,000 A.D. (1983) (BitCorp)" "" "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" "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" "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" "24aff972d58990f9b88a6d787c796f1e" "Cartridge.Manufacturer" "CBS Electronics" "Cartridge.ModelNo" "4L1767, 4L1768, 4L1769, 4L1770" "Cartridge.Name" "Smurf (1982) (CBS Electronics) (PAL) [a]" "" "Cartridge.MD5" "eada0dd61ce13f8317de774dc1e68604" "Cartridge.Name" "2600 Digital Clock (Demo 1) (PD)" "" "Cartridge.MD5" "e5f17b3e62a21d0df1ca9aee1aa8c7c5" "Cartridge.Manufacturer" "CommaVid, John Bronstein" "Cartridge.ModelNo" "CM-003" "Cartridge.Name" "Cosmic Swarm (1982) (CommaVid)" "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" "" "Cartridge.MD5" "d79df06894e3c1585a47c2807332b319" "Cartridge.Name" "Star Fire - Explosions! (10-10-2002) (MP)" "" "Cartridge.MD5" "4c8970f6c294a0a54c9c45e5e8445f93" "Cartridge.Manufacturer" "Xonox - K-Tel Software, Anthony R. Henderson" "Cartridge.ModelNo" "99006, 6220" "Cartridge.Name" "Sir Lancelot (1983) (Xonox)" "" "Cartridge.MD5" "f1e375d921858467166e53bcec05803f" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 3 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "268f46038e29301568fa9e443e16e960" "Cartridge.Manufacturer" "Atarius Maximum" "Cartridge.Name" "Pitfall Unlimited (Atarius Maximus) (Hack)" "Cartridge.Note" "Hack of Pitfall" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "b7f184013991823fc02a6557341d2a7a" "Cartridge.Name" "Blue Rod Demo (PD)" "" "Cartridge.MD5" "2942680c47beb9bf713a910706ffabfe" "Cartridge.Name" "Blue Line Demo (PD)" "" "Cartridge.MD5" "f93d7fee92717e161e6763a88a293ffa" "Cartridge.Manufacturer" "20th Century Fox Video Games - Lazer Micro Systems - Dunhill Electronic Media Corp., 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" "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" "8ee3f64dc0f349adc893fe93df5245d8" "Cartridge.Name" "Euchre (20-07-2001) (Eric Eid) (PD)" "" "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.Rarity" "Prototype" "" "Cartridge.MD5" "76c88341017eae660efc6e49c4b6ab40" "Cartridge.Name" "Indiana Pitfall (Hack)" "Cartridge.Note" "Hack of Pitfall!" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "f3f92aad3a335f0a1ead24a0214ff446" "Cartridge.Name" "Spectrum Color Demo (PD)" "" "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" "4233eb824c2b4811abef9b6d00355ae9" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.10) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a97733b0852ee3096300102cb0689175" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-834" "Cartridge.Name" "Fast Eddie (1983) (CCE)" "" "Cartridge.MD5" "13448eb5ba575e8d7b8d5b280ea6788f" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Crackpots (Digivision)" "" "Cartridge.MD5" "73b4e8f8b04515d91937510e680214bc" "Cartridge.Name" "Rubik's Cube Demo 3 (24-12-2002) (CT)" "" "Cartridge.MD5" "cfb3260c603b0341d49ddfc94051ec10" "Cartridge.Manufacturer" "Dactari - Milmar" "Cartridge.Name" "Boxing (Dactari - Milmar)" "" "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" "Display.YStart" "44" "" "Cartridge.MD5" "51de328e79d919d7234cf19c1cd77fbc" "Cartridge.Manufacturer" "Atari, Mark R. Hahn" "Cartridge.ModelNo" "CX2678" "Cartridge.Name" "Dukes of Hazzard (1983) (Atari)" "" "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" "e800e4aec7c6c54c9cf3db0d1d030058" "Cartridge.Name" "Qb (2.06) (Retroactive) (Stella)" "Display.Phosphor" "YES" "" "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" "0f14c03050b35d6b1d8850b07578722d" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 10 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "073cb76b006af034fd150be3f5e0e7e6" "Cartridge.Name" "Mobile 48 Sprite Kernel (Bug Fixed) (10-01-2003) (Eric Ball)" "" "Cartridge.MD5" "80e1410ec98089e0733cc09e584dba4b" "Cartridge.Manufacturer" "Dynamics" "Cartridge.ModelNo" "DY-293005" "Cartridge.Name" "Jumping Jack (1983) (Dynamics) (PAL)" "Cartridge.Note" "AKA Bobby Is Going Home" "Display.YStart" "46" "" "Cartridge.MD5" "6cf054cd23a02e09298d2c6f787eb21d" "Cartridge.Manufacturer" "Parker Brothers, Wilfredo 'Willy' 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" "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" "9048ccb7e0802cd8fa5bfc2609f292d8" "Cartridge.Manufacturer" "Tigervision, Robert H. O'Neil" "Cartridge.ModelNo" "7-007" "Cartridge.Name" "Polaris (1983) (Tigervision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "291cc37604bc899e8e065c30153fc4b9" "Cartridge.Manufacturer" "Activision, Carol Shaw" "Cartridge.ModelNo" "AX-020, AX-020-04" "Cartridge.Name" "River Raid (1982) (Activision) (16K)" "" "Cartridge.MD5" "08d60a58a691c7f690162850302dc0e1" "Cartridge.Name" "Poker Squares (V0.27) (PAL) (2001) (B. Watson)" "" "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" "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" "57939b326df86b74ca6404f64f89fce9" "Cartridge.Manufacturer" "Atari, Richard Dobbis, Nick 'Sandy Maiwald' Turner" "Cartridge.ModelNo" "CX26111" "Cartridge.Name" "Snoopy and the Red Baron (1983) (Atari)" "" "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" "e556e07cc06c803f2955986f53ef63ed" "Cartridge.Manufacturer" "Coleco, Ed Temple" "Cartridge.ModelNo" "2665" "Cartridge.Name" "Front Line (1984) (Coleco)" "" "Cartridge.MD5" "4afa7f377eae1cafb4265c68f73f2718" "Cartridge.Manufacturer" "Ed Fries" "Cartridge.Name" "Halo 2600 (2010) (Ed Fries)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "c17bdc7d14a36e10837d039f43ee5fa3" "Cartridge.Manufacturer" "Spectravision, Spectravideo" "Cartridge.ModelNo" "SA-203" "Cartridge.Name" "Cross Force (1982) (Spectravision)" "" "Cartridge.MD5" "8b8789c6669a4cee86c579a65332f852" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Plaque Attack (Digivision)" "" "Cartridge.MD5" "a9531c763077464307086ec9a1fd057d" "Cartridge.Manufacturer" "Atari, John Dunn - Sears" "Cartridge.ModelNo" "CX2631 - 49-75152" "Cartridge.Name" "Superman (1979) (Atari)" "" "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" "06cfd57f0559f38b9293adae9128ff88" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "4317 A009" "Cartridge.Name" "Adventures on GX-12 (1989) (Telegames) (PAL)" "Cartridge.Note" "AKA Adventures of Tron" "" "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" "92a1a605b7ad56d863a56373a866761b" "Cartridge.Manufacturer" "U.S. Games Corporation, Dave Hampton" "Cartridge.ModelNo" "VC2006" "Cartridge.Name" "Raft Rider (1982) (U.S. Games)" "" "Cartridge.MD5" "be41463cd918daef107d249f8cde3409" "Cartridge.Name" "Berzerk (Voice Enhanced) (Hack)" "Cartridge.Note" "Hack of Berzerk" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "515046e3061b7b18aa3a551c3ae12673" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Noellie Alito" "Cartridge.ModelNo" "CX2692" "Cartridge.Name" "Moon Patrol (1983) (Atari)" "" "Cartridge.MD5" "06db908011065e5ebb37f4e253c2a0b0" "Cartridge.Name" "Gopher (Unknown) (PAL)" "" "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" "6b6ca32228ae352b4267e4bd2cddf10c" "Cartridge.Name" "Pac-Man 4 (Pac-Man Hack)" "Display.YStart" "33" "" "Cartridge.MD5" "3bb9793c60c92911895cf44530846136" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Dragster (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "Display.YStart" "27" "" "Cartridge.MD5" "7836794b79e8060c2b8326a2db74eef0" "Cartridge.Name" "RIOT RAM Test (26-11-2002) (Dennis Debro)" "" "Cartridge.MD5" "61e0f5e1cc207e98704d0758c68df317" "Cartridge.Manufacturer" "Star Game" "Cartridge.ModelNo" "007" "Cartridge.Name" "Tennis (Star Game)" "" "Cartridge.MD5" "63c5fef3208bb1424d26cf1ab984b40c" "Cartridge.Name" "Analog Clock (V0.1) (20-01-2003) (AD)" "" "Cartridge.MD5" "a11099b6ec24e4b00b8795744fb12005" "Cartridge.Manufacturer" "Activision, Robert C. Polaro" "Cartridge.ModelNo" "EAK-049-04B" "Cartridge.Name" "Rampage! (1989) (Activision) (PAL)" "" "Cartridge.MD5" "cfee10bd7119f10b136921ced2ee8972" "Cartridge.Name" "Space Instigators (V1.8) (19-10-2002) (CT)" "" "Cartridge.MD5" "5f69453a69f21dc49697a80d2e933491" "Cartridge.Name" "Star Fire - Reduced Flickering (06-10-2002) (MP)" "" "Cartridge.MD5" "68760b82fc5dcf3fedf84376a4944bf9" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-860" "Cartridge.Name" "Laser Gate (1983) (CCE)" "Cartridge.Note" "AKA Innerspace" "" "Cartridge.MD5" "ca09fa7406b7d2aea10d969b6fc90195" "Cartridge.Manufacturer" "Activision, Matthew L. Hubbard, Bob Whitehead" "Cartridge.ModelNo" "AX-024" "Cartridge.Name" "Dolphin (1983) (Activision)" "" "Cartridge.MD5" "405f8591b6941cff56c9b392c2d5e4e5" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Star Strike (1989) (Telegames) (PAL)" "" "Cartridge.MD5" "6fe67f525c39200a798985e419431805" "Cartridge.Manufacturer" "Atari - GCC, Kevin Osborn" "Cartridge.ModelNo" "CX2689, CX2689P" "Cartridge.Name" "Kangaroo (1983) (Atari) (PAL)" "" "Cartridge.MD5" "f33f1d0f7819c74148dacb48cbf1c597" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.00) (Retroactive) (Stella)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "95a69cf8c08ef1522b050529464f0bca" "Cartridge.Name" "Grid Pattern Demo 1 (20-12-2002) (CT)" "" "Cartridge.MD5" "cedbd67d1ff321c996051eec843f8716" "Cartridge.Manufacturer" "Ultravision" "Cartridge.ModelNo" "1044" "Cartridge.Name" "Karate (1982) (Ultravision)" "Display.YStart" "25" "" "Cartridge.MD5" "9eca521db1959156a115dee85a405194" "Cartridge.Name" "Fu Kung! (V0.08) (2003) (AD)" "" "Cartridge.MD5" "44560e324ffb30741a483218ba5b4342" "Cartridge.Name" "Star Fire - Faster Skipping 2 (24-10-2002) (MP)" "" "Cartridge.MD5" "c54b4207ce1d4bf72fadbb1a805d4a39" "Cartridge.Manufacturer" "Billy Eno" "Cartridge.Name" "Sniper (Feb 30) (2001) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "d45ebf130ed9070ea8ebd56176e48a38" "Cartridge.Manufacturer" "Sega" "Cartridge.ModelNo" "001-01" "Cartridge.Name" "Tac-Scan (1982) (Sega)" "Cartridge.Note" "Uses the Paddle Controllers (right only)" "Console.SwapPorts" "YES" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "Display.Height" "215" "Display.Phosphor" "YES" "" "Cartridge.MD5" "fd9b321cee5fbb32c39ba3ca5d9ec7cf" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 5 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "e237ee91514d5ed535c95a14fc608c11" "Cartridge.Manufacturer" "Activision, Matthew L. Hubbard, Bob Whitehead" "Cartridge.ModelNo" "AX-024" "Cartridge.Name" "Dolphin (1983) (Activision) (8K)" "" "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" "e15b5525cf8f77297b322838df8d999c" "Cartridge.Name" "Sprite Demo 0 (PD)" "" "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" "2c3b9c171e214e9e46bbaa12bdf8977e" "Cartridge.Manufacturer" "Atari, Ed Logg, Carol Shaw - Sears" "Cartridge.ModelNo" "CX2639 - 49-75162" "Cartridge.Name" "Othello (1981) (Atari) (4K) [a]" "" "Cartridge.MD5" "f20bd756f3990e06c492f53cd0168e68" "Cartridge.Name" "Skeleton+ (03-05-2003) (Eric Ball) (NTSC)" "Cartridge.Sound" "STEREO" "" "Cartridge.MD5" "a81697b0c8bbc338ae4d0046ede0646b" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Gravitar (CCE)" "" "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" "ae97cf8ed21f4154b4360a3cf6c95c5e" "Cartridge.Name" "Teleterm 2600 (John K. Harvey) (PD)" "" "Cartridge.MD5" "de62f8a30298e2325249fe112ecb5c10" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-810" "Cartridge.Name" "Enduro (1983) (CCE)" "" "Cartridge.MD5" "12123b534bdee79ed7563b9ad74f1cbd" "Cartridge.Manufacturer" "Absolute Entertainment, Alex DeMeo" "Cartridge.ModelNo" "AG-041-04" "Cartridge.Name" "Title Match Pro Wrestling (1987) (Absolute)" "" "Cartridge.MD5" "6b72b691ea86f61438ed0d84c4d711de" "Cartridge.Name" "Fishing Derby (Unknown) (PAL) (4K) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "5a272012a62becabcd52920348c7c60b" "Cartridge.Manufacturer" "Star Game" "Cartridge.Name" "Pitfall (Star Game)" "Cartridge.Note" "AKA Pitfall!" "" "Cartridge.MD5" "e1efe2ef7664bb6758b1a22ff8ea16a1" "Cartridge.Manufacturer" "Dynacom" "Cartridge.Name" "Enduro (1983) (Dynacom)" "" "Cartridge.MD5" "7778ac65d775a079f537e97cbdad541c" "Cartridge.Name" "Spider Fighter (Unknown) (PAL)" "" "Cartridge.MD5" "01297d9b450455dd716db9658efb2fae" "Cartridge.Manufacturer" "TechnoVision" "Cartridge.ModelNo" "TVS1002" "Cartridge.Name" "Save Our Ship (1983) (TechnoVision) (PAL)" "" "Cartridge.MD5" "6f084daf265599f65422ef4173b69bc7" "Cartridge.Name" "Music Kit (V2.0) - Song Player (Paul Slocum)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "663ef22eb399504d5204c543b8a86bcd" "Cartridge.Manufacturer" "CBS Electronics, Joe Hellesen" "Cartridge.ModelNo" "4L1720, 4L1721, 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" "32f4e47a71601ab06cfb59e1c6a0b846" "Cartridge.Manufacturer" "Ed Federmeyer" "Cartridge.Name" "Sound X (1994) (Ed Federmeyer)" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "7c757bb151269b2a626c907a22f5dae7" "Cartridge.Manufacturer" "TNT Games, Adam Clayton" "Cartridge.ModelNo" "26192" "Cartridge.Name" "BMX Air Master (1989) (TNT Games) (PAL)" "Cartridge.Rarity" "Extremely Rare" "" "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" "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" "7d726fa494f706784bafeb1b50d87f23" "Cartridge.Manufacturer" "Coleco, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (07-27-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "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" "4605a00f5b44a9cbd5803a7a55de150e" "Cartridge.Manufacturer" "Coleco, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (07-03-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "cbeafd37f15e0dddb0540dbe15c545a4" "Cartridge.Name" "Black and White Fast Scolling Demo (PD)" "" "Cartridge.MD5" "1fab68fd67fe5a86b2c0a9227a59bb95" "Cartridge.Manufacturer" "20th Century Fox Video Games - Videa, Lee Actor" "Cartridge.Name" "Lasercade (1983) (20th Century Fox) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "29" "" "Cartridge.MD5" "28a4cd87fb9de4ee91693a38611cb53c" "Cartridge.Name" "Skeleton (V1.1) (NTSC) (24-10-2002) (Eric Ball)" "" "Cartridge.MD5" "2eaf8fa9e9fdf1fcfc896926a4bdbf85" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "6 AR-4400" "Cartridge.Name" "Excalibur Version 39 (Dragonstomper Beta) (1982) (Arcadia) (Prototype)" "" "Cartridge.MD5" "5b98e0536c3f60547dd708ae22adb04b" "Cartridge.Manufacturer" "Ben Hudman" "Cartridge.Name" "Donkey Kong Gingerbread Man (Ben Hudman) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "d8295eff5dcc43360afa87221ea6021f" "Cartridge.Manufacturer" "Spectravideo" "Cartridge.ModelNo" "SA-212" "Cartridge.Name" "Mangia' (1983) (Spectravideo) (PAL)" "" "Cartridge.MD5" "62f74a2736841191135514422b20382d" "Cartridge.Name" "Pharaoh's Curse (Unknown)" "Display.Format" "PAL60" "Display.YStart" "20" "Display.Height" "225" "Display.Phosphor" "YES" "" "Cartridge.MD5" "88d7b6b3967de0db24cdae1c7f7181bd" "Cartridge.Manufacturer" "Atari - GCC, Dave Payne" "Cartridge.ModelNo" "CX2669" "Cartridge.Name" "Vanguard (1982) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "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" "0d1b3abf681a2fc9a6aa31a9b0e8b445" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Laser Blast (32 in 1) (1988) (Atari) (PAL)" "" "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" "ea38fcfc06ad87a0aed1a3d1588744e4" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.ModelNo" "CX26122" "Cartridge.Name" "Sinistar (1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "ae0d4f3396cb49de0fabdff03cb2756f" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.02) (PAL) (2001) (Retroactive)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ae4be3a36b285c1a1dff202157e2155d" "Cartridge.Manufacturer" "Spectravideo" "Cartridge.ModelNo" "SA-210" "Cartridge.Name" "Master Builder (1983) (Spectravideo)" "" "Cartridge.MD5" "2c8835aed7f52a0da9ade5226ee5aa75" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4101" "Cartridge.Name" "Communist Mutants from Space (1982) (Arcadia)" "" "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" "1b1daaa9aa5cded3d633bfcbeb06479c" "Cartridge.Name" "Ship Demo (V 1502) (PD)" "" "Cartridge.MD5" "b6166f15720fdf192932f1f76df5b65d" "Cartridge.Manufacturer" "Amiga" "Cartridge.ModelNo" "3130" "Cartridge.Name" "Off Your Rocker (1983) (Amiga) (Prototype)" "Cartridge.Note" "Uses the Amiga Joyboard" "Display.YStart" "27" "" "Cartridge.MD5" "d65900fefa7dc18ac3ad99c213e2fa4e" "Cartridge.Name" "Grid and Purple Dot Demo (PD)" "" "Cartridge.MD5" "cccfe9e9a11b1dad04beba46eefb7351" "Cartridge.Name" "Poker Squares (V0.25) (PAL) (2001) (B. Watson)" "" "Cartridge.MD5" "5b9c2e0012fbfd29efd3306359bbfc4a" "Cartridge.Manufacturer" "HES" "Cartridge.Name" "2 Pak Special - Hoppy, Alien Force (1992) (HES) (PAL) [a]" "" "Cartridge.MD5" "5cbd7c31443fb9c308e9f0b54d94a395" "Cartridge.Manufacturer" "Spectravideo, Mark Turmell" "Cartridge.ModelNo" "SA-217" "Cartridge.Name" "Gas Hog (1983) (Spectravideo) [fixed]" "" "Cartridge.MD5" "3091af0ef1a61e801f4867783c21d45c" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-862" "Cartridge.Name" "Crackpots (1983) (CCE) [a]" "" "Cartridge.MD5" "58746219d8094edff869f0f5c2aeaad5" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Bowling (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "c29f8db680990cb45ef7fef6ab57a2c2" "Cartridge.Manufacturer" "Parker Brothers, Paul Crowley" "Cartridge.ModelNo" "PB5320" "Cartridge.Name" "Super Cobra (1982) (Parker Bros)" "" "Cartridge.MD5" "d5d2d44fb73785996ccc24ae3a0f5cef" "Cartridge.Manufacturer" "Robby" "Cartridge.Name" "Grand Prix (Robby)" "" "Cartridge.MD5" "3d7749fb9c2f91a276dfe494495234c5" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Checkers (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "c0d2434348de72fa6edcc6d8e40f28d7" "Cartridge.Manufacturer" "Sega - Bally Midway - Beck-Tech" "Cartridge.ModelNo" "010-01" "Cartridge.Name" "Tapper (1984) (Sega)" "Display.YStart" "24" "Display.Height" "225" "" "Cartridge.MD5" "8538c5e3ee83267774480649f83fa8d6" "Cartridge.Name" "Escape Demo (PD)" "" "Cartridge.MD5" "d28afe0517a046265c418181fa9dd9a1" "Cartridge.Name" "Dodge 'Em (Unknown) (PAL)" "" "Cartridge.MD5" "679d30c7886b283cbe1db4e7dbe5f2a6" "Cartridge.Manufacturer" "Colin Hughes" "Cartridge.Name" "Puzzle (Colin Hughes) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "804ed85eadf1ce3e93721547cbea7592" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Fishing Derby (CCE) (4K)" "" "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 World End (Perry Rhodan-Serie)" "Display.YStart" "30" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a0185c06297b2818f786d11a3f9e42c3" "Cartridge.Name" "International Soccer (Unknown) (PAL)" "" "Cartridge.MD5" "c7e43ad79c5e5c029d9f5ffde23e32cf" "Cartridge.Name" "PAL-NTSC Detector (15-11-2002) (CT)" "" "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" "19d9b5f8428947eae6f8e97c7f33bf44" "Cartridge.Name" "Fortress (Dual Version) (20-04-2003) (CT)" "" "Cartridge.MD5" "a8d0a4a77cd71ac601bd71df5a060e4c" "Cartridge.Name" "Space Shuttle (1983) (Activision) [t2] (Fuel)" "" "Cartridge.MD5" "e8aa36e3d49e9bfa654c25dcc19c74e6" "Cartridge.Manufacturer" "Atari, Joe Decuir, Steve Mayer, Larry Wagner" "Cartridge.ModelNo" "CX2601, CX2601P" "Cartridge.Name" "Combat (1977) (Atari) (PAL)" "Display.YStart" "36" "Display.Height" "260" "" "Cartridge.MD5" "851cc1f3c64eaedd10361ea26345acea" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-009, AG-009-04" "Cartridge.Name" "Freeway (1981) (Activision) (4K)" "" "Cartridge.MD5" "ce4bbe11d682c15a490ae15a4a8716cf" "Cartridge.Name" "Okie Dokie (Older) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "8654d7f0fb351960016e06646f639b02" "Cartridge.Manufacturer" "Home Vision - Gem International Corp. - R.J.P.G." "Cartridge.ModelNo" "VCS83106" "Cartridge.Name" "Ski Hunt (1983) (Home Vision) (PAL)" "" "Cartridge.MD5" "5961d259115e99c30b64fe7058256bcf" "Cartridge.Manufacturer" "Universal Gamex Corporation, Alan Roberts, H.K. Poon" "Cartridge.ModelNo" "GX-001" "Cartridge.Name" "X-Man (1983) (Universal)" "Display.YStart" "30" "" "Cartridge.MD5" "07f84db31e97ef8d08dc9fa8a5250755" "Cartridge.Manufacturer" "Supergame" "Cartridge.Name" "Enduro (1984) (Supergame)" "" "Cartridge.MD5" "0751f342ee4cf28f2c9a6e8467c901be" "Cartridge.Manufacturer" "Atari, Joseph Tung" "Cartridge.ModelNo" "CX26152" "Cartridge.Name" "Super Baseball (1988) (Atari) (PAL)" "" "Cartridge.MD5" "2c45c3eb819a797237820a1816c532eb" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Boxing (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "ee67dc0b01746372d2b983d88f48e24f" "Cartridge.Name" "Scroller Demo (02-01-2003) (CT)" "" "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" "" "Cartridge.MD5" "ef263d40a23483ab339cac44d9515a56" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Fatal Run (TJ)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "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" "5db9e5bf663cad6bf159bc395f6ead53" "Cartridge.Manufacturer" "Goliath - Hot Shot" "Cartridge.ModelNo" "83-212" "Cartridge.Name" "Time Race (1983) (Goliath) (PAL)" "Cartridge.Note" "AKA Space Jockey" "Display.YStart" "48" "Display.Height" "256" "" "Cartridge.MD5" "36547bc6faa5132b87504e18d088e1d7" "Cartridge.Name" "Cosmic Swarm (Unknown) (PAL) (4K)" "Display.Phosphor" "YES" "" "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" "16e04823887c547dc24bc70dff693df4" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Tennis (32 in 1) (1988) (Atari) (PAL)" "" "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" "b822fba8b7c8a97ea4e92aeb2c455ef9" "Cartridge.Manufacturer" "Dactari" "Cartridge.Name" "Freeway (Dactari) (4K)" "" "Cartridge.MD5" "cae8f83c06831ec7bb6a3c07e98e9342" "Cartridge.Manufacturer" "Colin Hughes" "Cartridge.Name" "Tetris 2600 (Colin Hughes) [o1]" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "876a953daae0e946620cf05ed41989f4" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.08) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "63e9e612bbee31045f8d184a4e53f8ec" "Cartridge.Manufacturer" "ATARITALIA" "Cartridge.Name" "Moby Blues (2002) (ATARITALIA) (Hack)" "Cartridge.Note" "Hack of Mario Bros" "Cartridge.Rarity" "Hack" "" "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" "4279485e922b34f127a88904b31ce9fa" "Cartridge.Name" "Enduro (Unknown)" "" "Cartridge.MD5" "2cf20f82abcae2decff88db99331e071" "Cartridge.Manufacturer" "Activision, Mike Lorenzen" "Cartridge.ModelNo" "AX-023" "Cartridge.Name" "Oink! (1983) (Activision) (8K)" "" "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" "140909d204abd6841c64cdad4d7765b4" "Cartridge.Name" "Moving Blue Ladder Demo (PD)" "" "Cartridge.MD5" "1d5eac85e67b8cff1377c8dba1136929" "Cartridge.Name" "Chronocolor Donkey Kong Sideways (PD)" "" "Cartridge.MD5" "295f3679bdf91ca5e37da3f787b29997" "Cartridge.Name" "Exorcise (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "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" "Display.YStart" "60" "" "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" "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" "4326edb70ff20d0ee5ba58fa5cb09d60" "Cartridge.Manufacturer" "Atari - GCC, Kevin Osborn" "Cartridge.ModelNo" "CX2689" "Cartridge.Name" "Kangaroo (1983) (Atari)" "" "Cartridge.MD5" "3d6fc7a19be76d808aa233415cb583fc" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-833" "Cartridge.Name" "Target Practice (1983) (CCE)" "Cartridge.Note" "AKA Carnival" "Display.YStart" "26" "Display.Height" "214" "" "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" "297236cb9156be35679f83c4e38ee169" "Cartridge.Manufacturer" "Exus Corporation" "Cartridge.Name" "Video Reflex (1983) (Exus) [no roman numbers]" "Cartridge.Note" "AKA Foot Craz (no roman numbers)" "" "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" "2dcf9ce486393cd36ca0928cd53b96cb" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, John Allred" "Cartridge.ModelNo" "CX2688, CX2688P" "Cartridge.Name" "Jungle Hunt (1983) (Atari) (PAL) [a2]" "" "Cartridge.MD5" "48411c9ef7e2cef1d6b2bee0e6055c27" "Cartridge.Manufacturer" "Telesys, Don 'Donyo' Ruffcorn, Jack Woodman" "Cartridge.ModelNo" "1003" "Cartridge.Name" "Fast Food (1982) (Telesys) (PAL)" "" "Cartridge.MD5" "82e7aab602c378cffdd8186a099e807e" "Cartridge.Name" "Space Robot (Unknown)" "" "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" "c20f15282a1aa8724d70c117e5c9709e" "Cartridge.Manufacturer" "Video Gems" "Cartridge.ModelNo" "VG-02" "Cartridge.Name" "Surfer's Paradise (1983) (Video Gems) (PAL)" "" "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" "a1ca372388b6465a693e4626cc98b865" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "176.543 7" "Cartridge.Name" "Der Vielfrass (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Fast Food" "" "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" "f1eeeccc4bba6999345a2575ae96508e" "Cartridge.Manufacturer" "Video Gems" "Cartridge.ModelNo" "VG-03" "Cartridge.Name" "Steeplechase (1983) (Video Gems) (PAL)" "Console.RightDifficulty" "A" "Display.Phosphor" "YES" "" "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" "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" "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" "24d018c4a6de7e5bd19a36f2b879b335" "Cartridge.Manufacturer" "Activision, Larry Miller" "Cartridge.ModelNo" "AX-021" "Cartridge.Name" "Spider Fighter (1982) (Activision)" "Display.YStart" "30" "" "Cartridge.MD5" "6fa0ac6943e33637d8e77df14962fbfc" "Cartridge.Manufacturer" "Imagic, Rob Fulop" "Cartridge.Name" "Cubicolor (1982) (Imagic) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "8b04e9d132b8e30d447acaa6bd049c32" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "c4bbbb0c8fe203cbd3be2e318e55bcc0" "Cartridge.Name" "Atlantis (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "72a46e0c21f825518b7261c267ab886e" "Cartridge.Manufacturer" "Xonox - K-Tel Software" "Cartridge.ModelNo" "99005, 6220, 6250" "Cartridge.Name" "Robin Hood (1983) (Xonox)" "Display.YStart" "30" "Display.Height" "222" "" "Cartridge.MD5" "322b29e84455aa41e7cc9af463bffa89" "Cartridge.Manufacturer" "Atari, Robert C. Polaro" "Cartridge.ModelNo" "CX2663" "Cartridge.Name" "Road Runner (06-25-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "44" "" "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" "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" "2d2c5f0761e609e3c5228766f446f7f8" "Cartridge.Manufacturer" "Atari - Axlon, Steve DeFrisco" "Cartridge.ModelNo" "CX26170, CX26170P" "Cartridge.Name" "Secret Quest (1989) (Atari) (PAL)" "" "Cartridge.MD5" "d7dd56677e4ec1e6627419478a4a9668" "Cartridge.Name" "Shadow Keep (Fixed) (04-03-2003) (Andrew Towers)" "" "Cartridge.MD5" "d541b20eae221a8ee321375e5971e766" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4101" "Cartridge.Name" "Communist Mutants from Space (Preview) (1982) (Arcadia)" "" "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" "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" "7ad257833190bc60277c1ca475057051" "Cartridge.Manufacturer" "Atari, Alan J. Murphy, Robert Zdybel" "Cartridge.ModelNo" "CX2668" "Cartridge.Name" "RealSports Football (1982) (Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "84290e333ff7567c2380f179430083b8" "Cartridge.Manufacturer" "Imagic, Dave Johnson" "Cartridge.ModelNo" "13211, EIX-004-04I" "Cartridge.Name" "Quick Step! (1983) (Imagic) (PAL) [a]" "" "Cartridge.MD5" "8f53a3b925f0fd961d9b8c4d46ee6755" "Cartridge.Name" "Astrowar (Unknown)" "" "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" "20d4457ba22517253fcb62967af11b37" "Cartridge.Manufacturer" "Atari, Eric Manghise, Joseph Tung" "Cartridge.ModelNo" "CX2640" "Cartridge.Name" "RealSports Baseball (1982) (Atari) (Prototype)" "Cartridge.Note" "AKA Foxbat" "Cartridge.Rarity" "Prototype" "Display.YStart" "30" "" "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" "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" "fb0c32ef7af5b45486db663510094be8" "Cartridge.Name" "Demo Image Series #15 - Three Marios (NTSC) (Non-Interleave) (06-03-2003) (AD)" "" "Cartridge.MD5" "fbd6102e17a5c02c6e1911381b7203f9" "Cartridge.Name" "Star Fire - Warping!! (10-04-2003) (MP)" "" "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" "c5930d0e8cdae3e037349bfa08e871be" "Cartridge.Manufacturer" "Atari, Howard Scott Warshaw - Sears" "Cartridge.ModelNo" "CX2655 - 49-75167" "Cartridge.Name" "Yars' Revenge (1982) (Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "42b2c3b4545f1499a083cfbc4a3b7640" "Cartridge.Manufacturer" "U.S. Games Corporation, Todd Marshall, Wes Trager, Henry Will IV" "Cartridge.ModelNo" "VC2003" "Cartridge.Name" "Eggomania (1982) (U.S. Games)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "" "Cartridge.MD5" "f98d2276d4a25b286135566255aea9d0" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Name This Game (1983) (Digitel)" "" "Cartridge.MD5" "f714a223954c28eccf459295517dcae6" "Cartridge.Name" "Big - Move This Demo (PD)" "" "Cartridge.MD5" "4981cefe5493ea512284e7f9f27d1e54" "Cartridge.Manufacturer" "Home Vision - Gem International Corp." "Cartridge.ModelNo" "VCS83136" "Cartridge.Name" "Cosmic War (1983) (Home Vision) (PAL)" "Cartridge.Note" "AKA Space Tunnel" "Display.Height" "256" "" "Cartridge.MD5" "b9232c1de494875efe1858fc8390616d" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "110" "Cartridge.Name" "Harbor Escape (1983) (Panda)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "86f5e55ca9a9bde7338a157570828e79" "Cartridge.Name" "Star Fire - Creating a Universe (09-09-2002) (MP) [a1]" "" "Cartridge.MD5" "b76fbadc8ffb1f83e2ca08b6fb4d6c9f" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-005, CAG-005, AG-005-04" "Cartridge.Name" "Skiing (1980) (Activision)" "" "Cartridge.MD5" "056ff67dd9715fafa91fb8b0ddcc4a46" "Cartridge.Name" "Frisco (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "2c0dc885d5ede94aa664bf3081add34e" "Cartridge.Name" "Earth Dies Screaming, The (Unknown) (PAL)" "" "Cartridge.MD5" "4e02880beeb8dbd4da724a3f33f0971f" "Cartridge.Manufacturer" "Imagic, Michael Greene" "Cartridge.ModelNo" "EIZ-002-04I" "Cartridge.Name" "Wing War (1983) (Imagic) (PAL)" "" "Cartridge.MD5" "13dfb095e519a555a5b60b7d9d7169f9" "Cartridge.Name" "Red Line Demo (PD)" "" "Cartridge.MD5" "f48735115ec302ba8bb2d2f3a442e814" "Cartridge.Name" "Dancing Plate (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "db339aea2b65b84c7cfe0eeab11e110a" "Cartridge.Name" "Chronocolor Frame Demo 2 (10-01-2003) (AD)" "" "Cartridge.MD5" "8e822b39a71c84ac875f0107fb61d6f0" "Cartridge.Name" "Hangman Ghost Original Words (Hack)" "Cartridge.Note" "Hack of Hangman" "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" "edf69b123e06eaf8663cc78d8aeba06e" "Cartridge.Manufacturer" "SpkSoft 98" "Cartridge.Name" "River Raid (SpkSoft 98) [h1]" "Display.YStart" "10" "" "Cartridge.MD5" "1f5a2927a0b2faf87540b01d9d7d7fd1" "Cartridge.Manufacturer" "Pet Boat" "Cartridge.Name" "Tennis (Pet Boat) (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" "28d5df3ed036ed63d33a31d0d8b85c47" "Cartridge.Manufacturer" "Goliath" "Cartridge.ModelNo" "5" "Cartridge.Name" "Open Sesame (1983) (Goliath) (PAL) [a]" "Cartridge.Note" "AKA Open, Sesame!" "Display.Phosphor" "YES" "" "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" "4b94fd272785d7ec6c95fb7279d0f522" "Cartridge.Manufacturer" "Atari, 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" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "d5c6b81212ad86fd9542a1fedaf57cae" "Cartridge.Name" "Sprite Demo 1 (PD)" "" "Cartridge.MD5" "1e272d09c0e55f5ef14fcb76a735f6d7" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Slot Machine (32 in 1) (1988) (Atari) (PAL) (4K)" "" "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" "1345e972dbe08ea3e70850902e20e1a5" "Cartridge.Manufacturer" "Greg Troutman" "Cartridge.Name" "Dark Mage (rough beta) (Greg Troutman) (PD)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6dda84fb8e442ecf34241ac0d1d91d69" "Cartridge.Manufacturer" "Atari - GCC, Douglas B. Macrae" "Cartridge.ModelNo" "CX2677" "Cartridge.Name" "Dig Dug (1983) (Atari)" "Cartridge.Type" "F6SC" "" "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" "200309c8fba0f248c13751ed4fc69bab" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 1 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "a94b8ca630f467b574b614808d813919" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "773-883" "Cartridge.Name" "2 Pak Special - Space Voyage, Fire Alert (1992) (HES) (PAL)" "" "Cartridge.MD5" "45a4f55bb9a5083d470ad479afd8bca2" "Cartridge.Manufacturer" "CommaVid, Joseph Biel" "Cartridge.Name" "Frog Demo (1983) (CommaVid)" "" "Cartridge.MD5" "6d218dafbf5a691045cdc1f67ceb6a8f" "Cartridge.Manufacturer" "Robin Harbron" "Cartridge.Name" "6 Digit Score Display (1998) (Robin Harbron) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "c216b91f5db21a093ded6a5aaec85709" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Dragster (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "Display.YStart" "22" "" "Cartridge.MD5" "b1b20536aef4eed9c79dc5804f077862" "Cartridge.Name" "Euchre (NTSC) (09-11-2001) (Erik Eid)" "" "Cartridge.MD5" "6b1fc959e28bd71aed7b89014574bdc2" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG203" "Cartridge.Name" "Phantom Tank (1982) (BitCorp) (PAL)" "Cartridge.Note" "AKA Phantom-Panzer" "" "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" "c92cfa54b5d022637fdcbdc1ef640d82" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.05) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f6c13e816e58c8c62f82b2c8b91a2d67" "Cartridge.Name" "Scrolling Playfield 2 (Junkosoft) (PD)" "" "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" "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" "a184846d8904396830951217b47d13d9" "Cartridge.Manufacturer" "Activision, Dan Kitchen" "Cartridge.ModelNo" "AX-029" "Cartridge.Name" "Crackpots (1983) (Activision)" "" "Cartridge.MD5" "c118854d670289a8b5d5156aa74b0c49" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Skiing (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "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" "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" "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" "30" "" "Cartridge.MD5" "f3cd0f886201d1376f3abab2df53b1b9" "Cartridge.Manufacturer" "Commavid, Ben Burch" "Cartridge.ModelNo" "CM-010" "Cartridge.Name" "Rush Hour (1983) (Commavid) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "3367eeba3269aa04720abe6169767502" "Cartridge.Name" "Space Treat (30-12-2002) (Fabrizio Zavagli)" "" "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" "d7f5bf138cfc7feab7b8ef1534c8b477" "Cartridge.Name" "Eric Bergstrom's KC-135 (Radar Map) (Aaron Bergstrom)" "" "Cartridge.MD5" "79b649fb812c50b4347d12e7ddbb8400" "Cartridge.Name" "Red Pong Number 2 Demo 2 (PD)" "Display.Phosphor" "YES" "" "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" "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" "eaf744185d5e8def899950ba7c6e7bb5" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26172" "Cartridge.Name" "Xenophobe (1990) (Atari)" "" "Cartridge.MD5" "b7345220a0c587f3b0c47af33ebe533c" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "176.433 1" "Cartridge.Name" "Landungskommando (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Strategy X" "" "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" "e8f7679359c4f532f5d5e93af7d8a985" "Cartridge.Name" "Hangman Invader Original Words (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "c6d48c6ae6461e0e82753540a985ac9e" "Cartridge.Manufacturer" "Ed Federmeyer" "Cartridge.Name" "Edtris (1994) (Ed Federmeyer)" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "4faeb04b1b7fb0fa25db05753182a898" "Cartridge.Name" "2600 Digital Clock (V x.xx) (PD) [a1]" "" "Cartridge.MD5" "95a89d1bf767d7cc9d0d5093d579ba61" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "204" "Cartridge.Name" "Lady in Wading (1982) (PlayAround)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c6cedb25b7d390b580ea8edb614b168b" "Cartridge.Name" "Star Fire - Radar Completed (22-10-2002) (MP)" "" "Cartridge.MD5" "00e55b27fe2e96354cd21b8b698d1e31" "Cartridge.Name" "Phoenix (Unknown)" "" "Cartridge.MD5" "5a8afe5422abbfb0a342fb15afd7415f" "Cartridge.Manufacturer" "Atari, Robert C. Polaro" "Cartridge.ModelNo" "CX26155" "Cartridge.Name" "Sprint Master (1988) (Atari)" "Display.YStart" "24" "" "Cartridge.MD5" "d9548ad44e67edec202d1b8b325e5adf" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Dan Oliver - RCA Video Jeux" "Cartridge.ModelNo" "AP-2002" "Cartridge.Name" "Space Cavern (1981) (Apollo) (PAL)" "" "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" "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" "9aeb5206c5bf974892a9cc59f1478db3" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-013" "Cartridge.Name" "Barnstorming (1982) (Activision) (8K)" "" "Cartridge.MD5" "562bf02f5031d51c6b53b03972a56b22" "Cartridge.Name" "Star Fire - Framework Done (30-10-2002) (MP)" "" "Cartridge.MD5" "4d2cef8f19cafeec72d142e34a1bbc03" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "771-422" "Cartridge.Name" "2 Pak Special - Star Warrior, Frogger (1990) (HES) (PAL) [a]" "" "Cartridge.MD5" "73521c6b9fed6a243d9b7b161a0fb793" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Miniaturer Golf (32 in 1) (1988) (Atari) (PAL)" "Cartridge.Note" "AKA Miniature Golf" "" "Cartridge.MD5" "d89fedded0436fdeda7c3c37e2fb7cf1" "Cartridge.Name" "Surround (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "2f0a8bb4e18839f9b1dcaa2f5d02fd1d" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Super Futebol (CCE) [a]" "Cartridge.Note" "AKA RealSports Football" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a2aae759e4e76f85c8afec3b86529317" "Cartridge.Name" "Boom Bang (Unknown)" "Cartridge.Note" "AKA Crackpots" "" "Cartridge.MD5" "3577e19714921912685bb0e32ddf943c" "Cartridge.Manufacturer" "TechnoVision" "Cartridge.ModelNo" "TVS1003" "Cartridge.Name" "Pharaoh's Curse (1983) (TechnoVision) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ea6d40db5498d6386571a76df448aa4c" "Cartridge.Name" "Vertical Playfield Demo 2 (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" "52385334ac9e9b713e13ffa4cc5cb940" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-804" "Cartridge.Name" "Open, Sesame! (1983) (CCE)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "15b498199ed0ed28057bf0dbdce9b8d8" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Jammed (V0.2) (Demo) (2001) (TJ)" "Cartridge.Rarity" "New Release" "Display.YStart" "24" "" "Cartridge.MD5" "6ce2110ac5dd89ab398d9452891752ab" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Persian Gulf War (Funvision)" "Cartridge.Note" "AKA River Raid" "" "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" "89afff4a10807093c105740c73e9b544" "Cartridge.Name" "Pooyan (Unknown) (PAL)" "" "Cartridge.MD5" "90578a63441de4520be5324e8f015352" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PGP204" "Cartridge.Name" "Open Sesame (4 Game in One Dark Green) (1983) (BitCorp) (PAL)" "Display.Height" "256" "Display.Phosphor" "YES" "" "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" "4e4895c3381aa4220f8c2795d6338237" "Cartridge.Name" "Backwards Cannonball v1 (Hack)" "Cartridge.Note" "Hack of Human Cannonball" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "b37f0fe822b92ca8f5e330bf62d56ea9" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Beck-Tech" "Cartridge.ModelNo" "6210, 7210, 06003. 99001" "Cartridge.Name" "Spike's Peak (1983) (Xonox) (PAL)" "" "Cartridge.MD5" "abb741c83f665d73c86d90a7d9292a9b" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Space Attack (1989) (Telegames) (PAL)" "" "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" "626d67918f4b5e3f961e4b2af2f41f1d" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "50008" "Cartridge.Name" "Diagnostic Test Cartridge 2.0 (1980) (Atari) (Prototype)" "" "Cartridge.MD5" "8ce9126066f2ddd5173e9f1f9ce1494e" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Missile Command (CX-22 Trackball) (2002) (TJ)" "Cartridge.Note" "Uses CX-22 Trackball Controller" "Cartridge.Rarity" "Homebrew" "Controller.Left" "TRACKBALL22" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ed1306436ce237afc5a7ed3f77134202" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "771-341" "Cartridge.Name" "2 Pak Special - Dolphin, Pigs 'n' Wolf (1990) (HES) (PAL)" "" "Cartridge.MD5" "2d9e65959808a6098c16c82a59c9d9dc" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (1 of 3) (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "4999b45be0ab5a85bac1b7c0e551542b" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Double Dragon (CCE) (PAL)" "" "Cartridge.MD5" "8d9a06101ebb0f147936356e645309b8" "Cartridge.Name" "Grid Pattern Demo 2 (20-12-2002) (CT)" "" "Cartridge.MD5" "4c462b2b6fb0a19a1437eb2c3dc20783" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Mundry, Scott Nelson" "Cartridge.ModelNo" "AR-4401" "Cartridge.Name" "Survival Island (1 of 3) (1983) (Arcadia)" "Display.YStart" "28" "" "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" "cbb0ee17c1308148823cc6da85bff25c" "Cartridge.Name" "Rotating Colors Demo 1 (Junkosoft) (PD)" "" "Cartridge.MD5" "c3a9550f6345f4c25b372c42dc865703" "Cartridge.Manufacturer" "Atari, Robert C. Polaro" "Cartridge.ModelNo" "CX2663" "Cartridge.Name" "Road Runner (1989) (Atari) (PAL)" "" "Cartridge.MD5" "fa2be8125c3c60ab83e1c0fe56922fcb" "Cartridge.Manufacturer" "DSD-Camelot - Johnson & Johnson, Michael Doherty, Clyde Hager" "Cartridge.Name" "Tooth Protectors (1983) (DSD-Camelot)" "Display.YStart" "26" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f21813aa050437f0dbc8479864acec6d" "Cartridge.Name" "Sneak 'n Peek (Unknown) (PAL)" "" "Cartridge.MD5" "822a950f27ff0122870558a89a49cad3" "Cartridge.Name" "Space Jockey (Unknown) (PAL)" "" "Cartridge.MD5" "1bf503c724001b09be79c515ecfcbd03" "Cartridge.Name" "Bumper Bash (Unknown) (PAL)" "Display.YStart" "54" "" "Cartridge.MD5" "0b8d3002d8f744a753ba434a4d39249a" "Cartridge.Manufacturer" "Sears Tele-Games, Robert Zdybel" "Cartridge.ModelNo" "CX2619 - 49-75159" "Cartridge.Name" "Stellar Track (1980) (Sears)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7ff53f6922708119e7bf478d7d618c86" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-032" "Cartridge.Name" "Walker (Suntek) (PAL)" "Cartridge.Note" "AKA Clown Down Town" "" "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" "539b7038acec0ccedeae40f238998579" "Cartridge.Name" "Star Fire (25-10-2002) (MP)" "" "Cartridge.MD5" "6dfad2dd2c7c16ac0fa257b6ce0be2f0" "Cartridge.Manufacturer" "Parker Brothers, Larry Gelberg, Gary Goltz" "Cartridge.ModelNo" "PB5065" "Cartridge.Name" "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "88a6c9c88cb329ee5fa7d168bd6c7c63" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1007" "Cartridge.Name" "Jungle Hunt (1983) (CCE)" "" "Cartridge.MD5" "3dfb7c1803f937fadc652a3e95ff7dc6" "Cartridge.Manufacturer" "Dimax - Sinmax" "Cartridge.ModelNo" "SM8001" "Cartridge.Name" "Space Robot (Dimax - Sinmax)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7a5463545dfb2dcfdafa6074b2f2c15e" "Cartridge.Manufacturer" "20th Century Fox Video Games, Mark Turmell" "Cartridge.ModelNo" "11007" "Cartridge.Name" "Turmoil (1982) (20th Century Fox)" "" "Cartridge.MD5" "033e21521e0bf4e54e8816873943406d" "Cartridge.Manufacturer" "20th Century Fox Video Games, Dan Thompson" "Cartridge.ModelNo" "11020" "Cartridge.Name" "Earth Dies Screaming, The (1983) (20th Century Fox)" "Cartridge.Note" "The Day the Earth Stood Still" "Display.YStart" "29" "" "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" "8917f7c1ac5eb05b82331cf01c495af2" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG202" "Cartridge.Name" "Space Tunnel (1982) (BitCorp) (PAL) [a]" "Display.Height" "256" "" "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" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e1486c7822c07117b4f94a32e5ed68c1" "Cartridge.Manufacturer" "Coleco, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (06-14-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "22f6b40fc82110d68e50a1208ae0bb97" "Cartridge.Name" "Purple Bar Demo (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "461029ab23800833e9645be3e472d470" "Cartridge.Name" "Combat TC (v0.1)" "" "Cartridge.MD5" "5ce98f22ade915108860424d8dde0d35" "Cartridge.Name" "Hangman Man Biglist3 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "043f165f384fbea3ea89393597951512" "Cartridge.Manufacturer" "Spectravision, Spectravideo" "Cartridge.ModelNo" "SA-202" "Cartridge.Name" "Planet Patrol (1982) (Spectravision)" "" "Cartridge.MD5" "0945081a6bd00345ff3d58eb7a07330a" "Cartridge.Name" "Stampede (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "52b448757081fd9fabf859f4e2f91f6b" "Cartridge.Name" "Worm War I (Unknown) (PAL)" "" "Cartridge.MD5" "8726c17ee7b559cb7bf2330d20972ad0" "Cartridge.Name" "Cave Demo (21-04-2003) (CT)" "" "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" "05ccf96247af12eef59698f1a060a54f" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "600273" "Cartridge.Name" "King Arthur (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Dragonfire (Double-Game Package)" "" "Cartridge.MD5" "a4ff39d513b993159911efe01ac12eba" "Cartridge.Manufacturer" "Atari - GCC, Betty Ryan Tylko, Douglas B. Macrae" "Cartridge.ModelNo" "CX2694" "Cartridge.Name" "Pole Position (1983) (Atari)" "Cartridge.Note" "AKA RealSports Driving" "" "Cartridge.MD5" "27f9e2e1b92af9dc17c6155605c38e49" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Nightmare (CCE)" "" "Cartridge.MD5" "da732c57697ad7d7af414998fa527e75" "Cartridge.Manufacturer" "Atari, Glenn Axworthy" "Cartridge.ModelNo" "CX26129" "Cartridge.Name" "Midnight Magic (1984) (Atari) (PAL)" "Display.Phosphor" "YES" "" "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" "75a303fd46ad12457ed8e853016815a0" "Cartridge.Manufacturer" "ZiMAG - Emag - Vidco" "Cartridge.ModelNo" "715-111 - GN-060" "Cartridge.Name" "Immies & Aggies (1983) (ZiMAG) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "2b27eb194e13f3b38d23c879cc1e3abf" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "402.272 9" "Cartridge.Name" "Super-Ferrari (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Enduro" "" "Cartridge.MD5" "80e52315919bd8a8b82a407ccd9bb13f" "Cartridge.Name" "Euchre (Jul 28) (2002) (Eric Eid) (PD)" "" "Cartridge.MD5" "5a9d188245aff829efde816fcade0b16" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-808" "Cartridge.Name" "Phantom Tank (1983) (CCE) (PAL)" "" "Cartridge.MD5" "9962034ea7b3d4a905d0991804670087" "Cartridge.Name" "Grid Demo (PD)" "" "Cartridge.MD5" "23fad5a125bcd4463701c8ad8a0043a9" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-840" "Cartridge.Name" "Stone Age (1983) (CCE)" "Cartridge.Note" "Uses the Joystick Controllers (swapped)" "Console.SwapPorts" "YES" "Console.LeftDifficulty" "A" "Console.RightDifficulty" "A" "Display.YStart" "26" "Display.Height" "220" "Display.Phosphor" "YES" "" "Cartridge.MD5" "45cb0f41774b78def53331e4c3bf3362" "Cartridge.Manufacturer" "Carrere Video, Roger Booth, Sylvia Day, Todd Marshall, Wes Trager, Henry Will IV - Teldec" "Cartridge.ModelNo" "USC1007" "Cartridge.Name" "Octopus (1983) (Carrere Video) (PAL)" "Cartridge.Note" "AKA Name This Game" "" "Cartridge.MD5" "97a9bb5c3679d67f5c2cd17f30b85d95" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "Colors (1980) (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "fb27afe896e7c928089307b32e5642ee" "Cartridge.Manufacturer" "M Network, Jeff Ronne, Brett Stutz - INTV" "Cartridge.ModelNo" "MT5662" "Cartridge.Name" "TRON - Deadly Discs (1982) (M Network)" "" "Cartridge.MD5" "bffe34516aaa3cbf5d307eab382a7e95" "Cartridge.Name" "Euchre (Release Candidate) (PAL) (28-09-2002) (Erik Eid)" "" "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" "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" "" "Cartridge.MD5" "392d34c0498075dd58df0ce7cd491ea2" "Cartridge.Manufacturer" "Atari, Frank Hausman, Steve Woita" "Cartridge.ModelNo" "CX2686" "Cartridge.Name" "Quadrun (1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "393948436d1f4cc3192410bb918f9724" "Cartridge.Manufacturer" "Activision, Carol Shaw" "Cartridge.ModelNo" "AX-020, AX-020-04" "Cartridge.Name" "River Raid (1982) (Activision)" "" "Cartridge.MD5" "a9784c24cddb33bd0d14442b97784f3d" "Cartridge.Name" "Omega Race DC (2003) (TJ) (Omega Race Hack)" "" "Cartridge.MD5" "bce93984b920e9b56cf24064f740fe78" "Cartridge.Manufacturer" "Atari, Carol Shaw" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Checkers (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "428b2d36f5d716765460701f7016ac91" "Cartridge.Manufacturer" "Andrew Wallace" "Cartridge.Name" "Brooni (2001) (Andrew Wallace) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "a0297c4788f9e91d43e522f4c561b4ad" "Cartridge.Manufacturer" "Atari, 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" "9e6fa031ece07919c816fba5dc8de43e" "Cartridge.Name" "Star Fire - Meteor Dance (13-11-2002) (MP)" "" "Cartridge.MD5" "e63a87c231ee9a506f9599aa4ef7dfb9" "Cartridge.Manufacturer" "Tigervision, Warren Schwader" "Cartridge.ModelNo" "7-003" "Cartridge.Name" "Threshold (1982) (Tigervision)" "Display.YStart" "21" "Display.Height" "214" "" "Cartridge.MD5" "4251b4557ea6953e88afb22a3a868724" "Cartridge.Name" "Robot City (V1.1) (TJ)" "Display.YStart" "24" "" "Cartridge.MD5" "01293bd90a4579abb7aed2f7d440681f" "Cartridge.Manufacturer" "Century" "Cartridge.Name" "Snoopy (1983) (Century) (PAL)" "Cartridge.Note" "AKA Snoopy and the Red Baron" "" "Cartridge.MD5" "384f5fbf57b5e92ed708935ebf8a8610" "Cartridge.Manufacturer" "20th Century Fox Video Games, John W.S. Marvin" "Cartridge.ModelNo" "11009" "Cartridge.Name" "Crypts of Chaos (1982) (20th Century Fox)" "" "Cartridge.MD5" "86b4aa76bbeb70e1a4f9211a9880ba8e" "Cartridge.Name" "Incoming (1 Player Version) (05-11-2002) (Ben Larson)" "" "Cartridge.MD5" "37527966823ee9243d34c7da8302774f" "Cartridge.Name" "Word Zapper (Unknown) (PAL)" "" "Cartridge.MD5" "47464694e9cce07fdbfd096605bf39d4" "Cartridge.Manufacturer" "Activision, Dan Kitchen" "Cartridge.ModelNo" "EAK-050-04" "Cartridge.Name" "Double Dragon (1989) (Activision) (PAL) [a]" "" "Cartridge.MD5" "7b79beb378d1b4471def90ceccf413de" "Cartridge.Name" "Pitfall Cupcake (Hack)" "Cartridge.Note" "Hack of Pitfall" "Cartridge.Rarity" "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" "" "Cartridge.MD5" "93c52141d3c4e1b5574d072f1afde6cd" "Cartridge.Manufacturer" "Imagic, Mark Klein" "Cartridge.ModelNo" "720112-1A, 03213" "Cartridge.Name" "Subterranea (1983) (Imagic)" "" "Cartridge.MD5" "e6f49a1053c79211f82be4d90dc9fe3d" "Cartridge.Name" "Gunfight 2600 - Little progress... (2001) (MP)" "" "Cartridge.MD5" "3f9cb1aba8ec20e2c243ae642f9942bf" "Cartridge.Name" "New Questions (1998) (John K. Harvey) (PD)" "" "Cartridge.MD5" "97933c9f20873446e4c1f8a4da21575f" "Cartridge.Name" "Racquetball (Unknown) (PAL)" "Display.Phosphor" "YES" "" "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" "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" "dfc3dbbb39f05d7dd8ee3ac987478970" "Cartridge.Name" "Imagic Selector ROM (1982) (Imagic) (PAL)" "" "Cartridge.MD5" "514f911ecff2be5eeff2f39c49a9725c" "Cartridge.Manufacturer" "Parker Brothers" "Cartridge.ModelNo" "931510" "Cartridge.Name" "Sky Skipper (1983) (Parker Bros) (PAL)" "" "Cartridge.MD5" "a1770ef47146ab7b12e2c4beccd68806" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Kaystone Kapers (1983) (Digitel)" "Cartridge.Note" "AKA Keystone Kapers" "" "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" "79d4af56036ec28f298cad964a2e2494" "Cartridge.Name" "Hangman Pac-Man Wordlist (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "8a159ee58b2f0a54805162984b0f07e5" "Cartridge.Manufacturer" "Atari - Sculptured Software, Inc., Steve Aguirre" "Cartridge.ModelNo" "CX26162" "Cartridge.Name" "Fatal Run (1989) (Atari) (PAL) [a]" "" "Cartridge.MD5" "d09f1830fb316515b90694c45728d702" "Cartridge.Manufacturer" "Imagic, Brad Stewart" "Cartridge.ModelNo" "720105-1A, IA3400" "Cartridge.Name" "Fire Fighter (1982) (Imagic)" "" "Cartridge.MD5" "4f618c2429138e0280969193ed6c107e" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AZ-028, AG-028-04" "Cartridge.Name" "Robot Tank (1983) (Activision)" "" "Cartridge.MD5" "f825c538481f9a7a46d1e9bc06200aaf" "Cartridge.Manufacturer" "Atari, Richard Maurer - Sears" "Cartridge.ModelNo" "CX2635 - 49-75157" "Cartridge.Name" "Maze Craze (1980) (Atari)" "" "Cartridge.MD5" "5131ab3797fe8c127e3e135b18b4d2c8" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-004" "Cartridge.Name" "Fishing Derby (1980) (Activision) (8K)" "" "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" "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" "0c0392db94a20e4d006d885abbe60d8e" "Cartridge.Name" "Dodge Demo 3 (PD)" "" "Cartridge.MD5" "2d1cf85fbc732856bf76470cd4060f4a" "Cartridge.Name" "Daredevil (V1) (Stunt_Cycle_Rules!) (PD)" "" "Cartridge.MD5" "05d61b925d3d2474bab83f0a79bb5df1" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Cosmic Ark Stars (1997) (Eckhard Stolberg)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "6e7ed74082f39ad4166c823765a59909" "Cartridge.Name" "Poker Squares (V0.14) (2001) (B. Watson)" "" "Cartridge.MD5" "898b5467551d32af48a604802407b6e8" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG208" "Cartridge.Name" "Snail Against Squirrel (1983) (BitCorp) (PAL)" "Display.YStart" "44" "" "Cartridge.MD5" "8c8b15b3259e60757987ed13cdd74d41" "Cartridge.Manufacturer" "Supergame" "Cartridge.ModelNo" "71" "Cartridge.Name" "River Raid (1984) (Supergame)" "" "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" "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" "1da2da7974d2ca73a823523f82f517b3" "Cartridge.Manufacturer" "Spectravision, Spectravideo, David Lubar" "Cartridge.ModelNo" "SA-206" "Cartridge.Name" "Challenge of.... Nexar, The (1982) (Spectravision) (PAL)" "" "Cartridge.MD5" "e549f1178e038fa88dc6d657dc441146" "Cartridge.Manufacturer" "Atari, Bob Whitehead - Sears" "Cartridge.ModelNo" "CX2625 - 6-99827, 49-75114" "Cartridge.Name" "Football (1979) (Atari)" "" "Cartridge.MD5" "714e13c08508ee9a7785ceac908ae831" "Cartridge.Manufacturer" "Home Vision - Gem International Corp." "Cartridge.ModelNo" "VCS83123" "Cartridge.Name" "Parachute (1983) (Home Vision) (PAL)" "" "Cartridge.MD5" "3b69f8929373598e1752f43f8da61aa4" "Cartridge.Manufacturer" "Apollo - Games by Apollo - RCA Video Jeux" "Cartridge.ModelNo" "AP-2006" "Cartridge.Name" "Infiltrate (1981) (Apollo) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a443d8557d712845c8cd3699363a42e6" "Cartridge.Name" "Star Fire (07-01-2003) (MP)" "" "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" "0f24ca5668b4ab5dfaf217933c505926" "Cartridge.Name" "Fantastic Voyage (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "30516cfbaa1bc3b5335ee53ad811f17a" "Cartridge.Manufacturer" "Wizard Video Games, Robert Barber, Tim Martin" "Cartridge.ModelNo" "007" "Cartridge.Name" "Halloween (1983) (Wizard Video Games)" "" "Cartridge.MD5" "7c00e7a205d3fda98eb20da7c9c50a55" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Ernie Runyon, Ed Salvo" "Cartridge.ModelNo" "AP-2004" "Cartridge.Name" "Lost Luggage (1981) (Apollo)" "" "Cartridge.MD5" "58a82e1da64a692fd727c25faef2ecc9" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-824" "Cartridge.Name" "Jaw Breaker (1983) (CCE)" "Display.YStart" "28" "" "Cartridge.MD5" "13895ef15610af0d0f89d588f376b3fe" "Cartridge.Manufacturer" "Tigervision, Rorke Weigandt" "Cartridge.ModelNo" "7-005" "Cartridge.Name" "Marauder (1982) (Tigervision)" "" "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" "e64a8008812327853877a37befeb6465" "Cartridge.Manufacturer" "Answer Software Corporation - TY Associates" "Cartridge.ModelNo" "ASC1002" "Cartridge.Name" "Gauntlet (1983) (Answer Software)" "" "Cartridge.MD5" "e56da674188ba2f02c7a0a343a01236f" "Cartridge.Name" "This Planet Sucks Demo 4 (Greg Troutman) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "78821ef76ebc3934850d1bc1b9e4f4b0" "Cartridge.Manufacturer" "HES - Activision" "Cartridge.ModelNo" "542" "Cartridge.Name" "Hot Action Pak - Ghostbusters, Tennis, Plaque Attack (1990) (HES) (PAL)" "" "Cartridge.MD5" "5e1b4629426f4992cf3b2905a696e1a7" "Cartridge.Manufacturer" "Activision, Robert C. Polaro" "Cartridge.ModelNo" "AK-049-04" "Cartridge.Name" "Rampage! (1989) (Activision)" "" "Cartridge.MD5" "e1d79e4e7c150f3861256c541ec715a1" "Cartridge.Name" "Space Jockey (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "f14d5e96ec3380aef57a4b70132c6677" "Cartridge.Manufacturer" "Goliath" "Cartridge.ModelNo" "6" "Cartridge.Name" "Spider Kong (1983) (Goliath) (PAL) [a]" "" "Cartridge.MD5" "6d9afd70e9369c2a6bff96c4964413b7" "Cartridge.Name" "Time Warp (Unknown) (PAL)" "" "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" "84db818cd4111542a15c2a795369a256" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Mundry, Scott Nelson" "Cartridge.ModelNo" "AR-4401" "Cartridge.Name" "Survival Island (1983) (Arcadia) (PAL)" "" "Cartridge.MD5" "e505bd8e59e31aaed20718d47b15c61b" "Cartridge.Manufacturer" "Funvision - Fund. Int'l Co." "Cartridge.Name" "Space War (1982) (Funvision) (PAL)" "Cartridge.Note" "AKA Condor 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.YStart" "26" "" "Cartridge.MD5" "11cf751bc8173db105eabd119c5844ba" "Cartridge.Name" "Star Fire - Crosshair (12-02-2002) (MP)" "" "Cartridge.MD5" "647162cceb550fd49820e2206d9ee7e8" "Cartridge.Name" "Skeleton (NTSC) (2002) (Eric Ball)" "" "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" "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" "3c3a2bb776dec245c7d6678b5a56ac10" "Cartridge.Name" "Unknown Title (bin00003) (PD)" "" "Cartridge.MD5" "9cbb07f1993a027bc2f87d5205457ec9" "Cartridge.Name" "Eckhard Stolberg's Scrolling Text Demo 1 (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "36c29ceee2c151b23a1ad7aa04bd529d" "Cartridge.Manufacturer" "Atari - GCC, Ava-Robin Cohen" "Cartridge.ModelNo" "CX26123" "Cartridge.Name" "Jr. Pac-Man (1984) (Atari)" "" "Cartridge.MD5" "b59417d083b0be2d49a7d93769880a4b" "Cartridge.Manufacturer" "Pet Boat" "Cartridge.Name" "Donkey Kong (1983) (Pet Boat) (PAL)" "" "Cartridge.MD5" "74f623833429d35341b7a84bc09793c0" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Radar (Zellers)" "Cartridge.Note" "AKA Exocet" "" "Cartridge.MD5" "8c136e97c0a4af66da4a249561ed17db" "Cartridge.Name" "Poker Squares (V0.27) (2001) (B. Watson)" "" "Cartridge.MD5" "98ba601a60172cb46c5bf9a962fd5b1f" "Cartridge.Name" "Gorilla Kong (Hack)" "Cartridge.Note" "Hack of Donkey Kong" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "6706a00f9635508cfeda20639156e66e" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Michael Sierchio" "Cartridge.ModelNo" "CX2667" "Cartridge.Name" "RealSports Soccer (1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "30" "" "Cartridge.MD5" "36c993dc328933e4dd6374a8ffe224f4" "Cartridge.Manufacturer" "Gameworld" "Cartridge.ModelNo" "133-007" "Cartridge.Name" "Bermuda Triangle (1983) (Gameworld) (PAL)" "Display.YStart" "48" "" "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" "39c78d682516d79130b379fa9deb8d1c" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Ed Salvo" "Cartridge.ModelNo" "AP-1001" "Cartridge.Name" "Skeet Shoot (1981) (Apollo)" "" "Cartridge.MD5" "3cdd91e1c28d28e856c0063d602da166" "Cartridge.Name" "Stell-A-Sketch (03-11-1997) (Bob Colbert) (PD)" "Display.YStart" "20" "Display.Phosphor" "YES" "" "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" "" "Cartridge.MD5" "e2b682f6e6d76b35c180c7d847e93b4f" "Cartridge.Name" "Dodge Demo 4 (PD)" "" "Cartridge.MD5" "559317712f989f097ea464517f1a8318" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "100" "Cartridge.Name" "Space Canyon (1983) (Panda)" "Cartridge.Note" "AKA Space Cavern" "" "Cartridge.MD5" "d65028524761ef52fbbdebab46f79d0f" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Galaxian (CCE)" "" "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" "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" "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" "7d483b702c44ee65cd2df22cbcc8b7ed" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.Name" "Elf Adventure (05-25-83) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "85a4133f6dcf4180e36e70ad0fca0921" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-827" "Cartridge.Name" "Chopper Command (1983) (CCE)" "" "Cartridge.MD5" "79ab4123a83dc11d468fb2108ea09e2e" "Cartridge.Manufacturer" "Activision, David Rolfe - Cheshire Engineering" "Cartridge.ModelNo" "AZ-037-04" "Cartridge.Name" "Beamrider (1984) (Activision)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "ef5c02c95a1e7ed24f24193935755cd3" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Jammed Demo (1999) (Hozer Video Games)" "Cartridge.Note" "Won't work with Stella < V1.2" "Cartridge.Rarity" "New Release" "Display.YStart" "24" "" "Cartridge.MD5" "458883f1d952cd772cf0057abca57497" "Cartridge.Name" "Fishing Derby (Unknown) (PAL) (Hack)" "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" "c59633dbebd926c150fb6d30b0576405" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "5861 A030" "Cartridge.Name" "Bogey Blaster (1989) (Telegames)" "Cartridge.Note" "AKA Air Raiders" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "f736864442164b29235e8872013180cd" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "6057 A227" "Cartridge.Name" "Quest for Quintana Roo (1989) (Telegames) (PAL)" "" "Cartridge.MD5" "502044b1ac111b394e6fbb0d821fca41" "Cartridge.Name" "Hangman Invader 4letter (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "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" "331938989f0f33ca39c10af4c09ff640" "Cartridge.Manufacturer" "Zach Matley" "Cartridge.Name" "Combat - Tank AI (19-04-2003) (Zach Matley)" "Cartridge.Rarity" "Homebrew" "" "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" "66c2380c71709efa7b166621e5bb4558" "Cartridge.Manufacturer" "Parker Brothers, Dave Engman, Dawn Stockbridge" "Cartridge.ModelNo" "931509" "Cartridge.Name" "Tutankham (1983) (Parker Bros) (PAL)" "" "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" "c6556e082aac04260596b4045bc122de" "Cartridge.Manufacturer" "Atari - GCC, Dave Payne" "Cartridge.ModelNo" "CX2669" "Cartridge.Name" "Vanguard (1982) (Atari)" "" "Cartridge.MD5" "b41fdd4a522e1d5a2721840028684ac2" "Cartridge.Name" "Green and Yellow Number 1 Demo 2 (PD)" "Display.Phosphor" "YES" "" "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" "Display.YStart" "28" "" "Cartridge.MD5" "ab56f1b2542a05bebc4fbccfc4803a38" "Cartridge.Manufacturer" "Activision, David Lubar" "Cartridge.ModelNo" "AK-048-04" "Cartridge.Name" "River Raid II (1988) (Activision)" "" "Cartridge.MD5" "fa3de71841c0841db6a741884a6b6b2f" "Cartridge.Name" "Warring Worms (17-02-2002) (Billy Eno)" "" "Cartridge.MD5" "fbac6476e7b2b20d246202af81662c88" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (Preview) (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "bae66907c3200bc63592efe5a9a69dbb" "Cartridge.Manufacturer" "Spectravision, Spectravideo - Quelle" "Cartridge.ModelNo" "SA-201 - 412.783 3" "Cartridge.Name" "Gangster Alley (1982) (Spectravision) (PAL)" "" "Cartridge.MD5" "05f11fb2e45c4e47424d3cb25414d278" "Cartridge.Name" "Boring (NTSC) (AD)" "" "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" "c3205e3707f646e1a106e09c5c49c1bf" "Cartridge.Name" "Unknown Title (bin00003 (200206)) (PD)" "" "Cartridge.MD5" "7a09299f473105ae1ef3ad6f9f2cd807" "Cartridge.Manufacturer" "Atari, Steve Wright" "Cartridge.ModelNo" "CX2616P" "Cartridge.Name" "Pele's Soccer (1981) (Atari) (PAL)" "Cartridge.Note" "AKA Championship Soccer" "" "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" "0c48e820301251fbb6bcdc89bd3555d9" "Cartridge.Manufacturer" "Atari, Andrew Fuchs" "Cartridge.ModelNo" "CX26120" "Cartridge.Name" "Stargate (1984) (Atari)" "" "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" "" "Cartridge.MD5" "aec9b885d0e8b24e871925630884095c" "Cartridge.Manufacturer" "Amiga" "Cartridge.ModelNo" "3125" "Cartridge.Name" "Surf's Up (1983) (Amiga) (Prototype)" "Cartridge.Note" "Uses the Amiga Joyboard" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "442602713cb45b9321ee93c6ea28a5d0" "Cartridge.Name" "Demon Attack (Unknown) (PAL)" "" "Cartridge.MD5" "e020f612255e266a8a6a9795a4df0c0f" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "7062 A305" "Cartridge.Name" "Universal Chaos (1989) (Telegames) (PAL)" "Cartridge.Note" "AKA Targ" "" "Cartridge.MD5" "e3533684a7ef930a7fbd0c4dd8ec4847" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-856" "Cartridge.Name" "Pimball (1983) (CCE)" "Cartridge.Note" "AKA Video Pinball" "" "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" "d4c590ccfb611a73b3331359700c01a3" "Cartridge.Name" "Sprite Movement Demo 2 (2001) (Roger Williams)" "" "Cartridge.MD5" "3f6dbf448f25e2bd06dea44248eb122d" "Cartridge.ModelNo" "5687 A279" "Cartridge.Name" "Soccer (1989) (Telegames)" "Cartridge.Note" "AKA International Soccer" "" "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" "2f16663b01591539624d0ef52934a17d" "Cartridge.Manufacturer" "M Network" "Cartridge.Name" "Rocky and Bullwinkle" "Cartridge.Rarity" "Prototype" "" "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" "" "Cartridge.MD5" "cef01595000627ee50863d4290372c27" "Cartridge.Name" "Many Blue Bars and Text Demo (PD)" "" "Cartridge.MD5" "04b488d4eef622d022a0021375e7e339" "Cartridge.Manufacturer" "Home Vision - Gem International Corp." "Cartridge.ModelNo" "VCS83107" "Cartridge.Name" "Tennis (1983) (Home Vision) (PAL) (4K)" "" "Cartridge.MD5" "74d072e8a34560c36cacbc57b2462360" "Cartridge.Manufacturer" "Sancho - Tang's Electronic Co." "Cartridge.ModelNo" "TEC002" "Cartridge.Name" "Seahawk (1982) (Sancho) (PAL)" "" "Cartridge.MD5" "157356f80c709ab675961d8b8b207e20" "Cartridge.Name" "Multi-Sprite Game V2.5 (Piero Cavina) (PD)" "" "Cartridge.MD5" "149b543c917c180a1b02d33c12415206" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-857" "Cartridge.Name" "Superman (1983) (CCE)" "" "Cartridge.MD5" "624e0a77f9ec67d628211aaf24d8aea6" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "108" "Cartridge.Name" "Sea Hawk (1983) (Panda)" "Cartridge.Note" "AKA Seahawk" "" "Cartridge.MD5" "0a1b98937911d621b004b1617446d124" "Cartridge.Name" "Hangman Pac-Man Biglist1 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "3f75a5da3e40d486b21dfc1c8517adc0" "Cartridge.Manufacturer" "Atari, Jim Huether" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Sky Diver (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "0fba7d8c3520bdb681f75494e498ec36" "Cartridge.Name" "Gunfight 2600 - Final Run (MP)" "" "Cartridge.MD5" "98ccd15345b1aee6caf51e05955f0261" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.03) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6ccd8ca17a0e4429b446cdcb66327bf1" "Cartridge.Name" "RPG Engine (12-05-2003) (Paul Slocum) (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a5e9ed3033fb2836e80aa7a420376788" "Cartridge.Manufacturer" "Atari, Carla Meninsky" "Cartridge.ModelNo" "CX2637, CX2637P" "Cartridge.Name" "Dodge 'Em (1980) (Atari) (PAL)" "" "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" "a9cb638cd2cb2e8e0643d7a67db4281c" "Cartridge.Manufacturer" "M Network, Larry Zwick - INTV" "Cartridge.ModelNo" "MT5861" "Cartridge.Name" "Air Raiders (1982) (M Network)" "Cartridge.Note" "AKA Air Battle" "" "Cartridge.MD5" "db1753cc702c18d3917ec7f3b0e8659f" "Cartridge.Name" "Frame Counter 2 (2001) (Jake Patterson) (PD)" "" "Cartridge.MD5" "6b4eb5b3df80995b8d9117cb7e9aeb3c" "Cartridge.Manufacturer" "Gameworld" "Cartridge.ModelNo" "133-006" "Cartridge.Name" "Journey Escape (1983) (Gameworld) (PAL)" "Cartridge.Note" "AKA Rock 'n' Roll Escape" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b0c47e426c7f799aee2c40422df8f56a" "Cartridge.Name" "Space Treat (PAL) (Fabrizio Zavagli)" "" "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" "4904a2550759b9b4570e886374f9d092" "Cartridge.Manufacturer" "Parker Brothers, Charlie Heath" "Cartridge.ModelNo" "931506" "Cartridge.Name" "Reactor (1982) (Parker Bros) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d6d5dd8fd322d3cf874e651e7b6c1657" "Cartridge.Name" "How to Draw a Playfield (1997) (Nick Bensema) (PD)" "" "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" "01" "" "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" "" "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" "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" "6fc27a9233fc69d28d3f190b4ff80f03" "Cartridge.Name" "UFO #6 (Charles Morgan) (Hack)" "Cartridge.Note" "Hack of Pepsi Invaders" "Cartridge.Rarity" "Hack" "" "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" "94d90f63678e086f6b6d5e1bc6c4c8c2" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Seaquest (Digivision)" "" "Cartridge.MD5" "16ee443c990215f61f7dd1e55a0d2256" "Cartridge.Manufacturer" "Spectravideo, David Lubar" "Cartridge.ModelNo" "SA-218C" "Cartridge.Name" "Bumper Bash (1983) (Spectravideo) (PAL)" "Controller.Left" "PADDLES_IAXIS" "Display.YStart" "54" "" "Cartridge.MD5" "ede4ab11ca346bd023b2c21d941e0c50" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "EAZ-030" "Cartridge.Name" "Decathlon (1983) (Activision) (SECAM)" "Display.Format" "SECAM" "" "Cartridge.MD5" "5d25df9dc2cde746ceac48e834cf84a7" "Cartridge.Manufacturer" "Activision, Steve 'Jessica' Kitchen" "Cartridge.ModelNo" "EAZ-033" "Cartridge.Name" "Space Shuttle (1983) (Activision) (SECAM)" "Cartridge.Type" "FE" "Display.Format" "SECAM" "" "Cartridge.MD5" "25f879ff678130fea615ac418e7943f1" "Cartridge.Manufacturer" "Activision, Garry Kitchen" "Cartridge.ModelNo" "EAX-025" "Cartridge.Name" "Keystone Kapers (1983) (Activision) (SECAM)" "Display.Format" "SECAM" "" "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" "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" "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" "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" "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" "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" "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" "5079bfbc7b8f5770f84215ed2e3bdd1b" "Cartridge.Manufacturer" "Omegamatrix (2012)" "Cartridge.Name" "Genesis Button Tester" "Cartridge.Rarity" "Homebrew" "Controller.Left" "GENESIS" "Controller.Right" "GENESIS" "" stella-3.9.3/src/emucore/CartFA2.cxx0000644000175000001440000002763312266336753016563 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartFA2.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "OSystem.hxx" #include "Serializer.hxx" #include "System.hxx" #include "CartFA2.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFA2::CartridgeFA2(const uInt8* image, uInt32 size, const OSystem& osystem) : Cartridge(osystem.settings()), myOSystem(osystem), myRamAccessTimeout(0), mySize(size) { // 29/32K version of FA2 has valid data @ 1K - 29K if(size >= 29 * 1024) { image += 1024; mySize = 28 * 1024; } // Allocate array for the ROM image myImage = new uInt8[mySize]; // Copy the ROM image into my buffer memcpy(myImage, image, mySize); createCodeAccessBase(mySize); // This cart contains 256 bytes extended RAM @ 0x1000 registerRamArea(0x1000, 256, 0x100, 0x00); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFA2::~CartridgeFA2() { delete[] myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA2::reset() { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 256; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 256); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA2::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert(((0x1100 & mask) == 0) && ((0x1200 & mask) == 0)); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt32 j = 0x1000; j < 0x1100; j += (1 << shift)) { access.directPokeBase = &myRAM[j & 0x00FF]; access.codeAccessBase = &myCodeAccessBase[j & 0x00FF]; mySystem->setPageAccess(j >> shift, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = 0; access.type = System::PA_READ; for(uInt32 k = 0x1100; k < 0x1200; k += (1 << shift)) { access.directPeekBase = &myRAM[k & 0x00FF]; access.codeAccessBase = &myCodeAccessBase[0x100 + (k & 0x00FF)]; mySystem->setPageAccess(k >> shift, 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[(myCurrentBank << 12) + 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 myCurrentBank = bank; uInt16 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1FF4 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1200; address < (0x1FF4U & ~mask); address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeFA2::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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[(myCurrentBank << 12) + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeFA2::getImage(int& size) const { size = mySize; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFA2::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); 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; myCurrentBank = in.getShort(); in.getByteArray(myRAM, 256); } catch(...) { cerr << "ERROR: CartridgeFA2::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); 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.isValid()) { 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[(myCurrentBank << 12) + 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[(myCurrentBank << 12) + 0xFF4] & ~0x40; } else // Bit 6 is 1, busy return myImage[(myCurrentBank << 12) + 0xFF4] | 0x40; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA2::flash(uInt8 operation) { Serializer serializer(myFlashFile); if(serializer.isValid()) { 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-3.9.3/src/emucore/StateManager.hxx0000644000175000001440000000664512266336753017761 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: StateManager.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef STATE_MANAGER_HXX #define STATE_MANAGER_HXX class OSystem; #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 @version $Id: StateManager.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class StateManager { public: /** Create a new statemananger class */ StateManager(OSystem* osystem); /** Destructor */ virtual ~StateManager(); public: /** Answers whether the manager is in record or playback mode */ bool isActive(); bool toggleRecordMode(); bool toggleRewindMode(); /** 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(); private: // Copy constructor isn't supported by this class so make it private StateManager(const StateManager&); // Assignment operator isn't supported by this class so make it private StateManager& operator = (const StateManager&); private: enum Mode { kOffMode, kMoviePlaybackMode, kMovieRecordMode, kRewindPlaybackMode, kRewindRecordMode }; 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; }; #endif stella-3.9.3/src/emucore/Random.cxx0000644000175000001440000000261412266336753016611 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Random.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "OSystem.hxx" #include "Random.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Random::Random() { initSeed(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Random::initSeed() { if(ourSystem) myValue = ourSystem->getTicks(); else myValue = (uInt32)time(0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Random::next() { return (myValue = (myValue * 2416 + 374441) % 1771875); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const OSystem* Random::ourSystem = NULL; stella-3.9.3/src/emucore/NullDev.hxx0000644000175000001440000000526312266336753016752 0ustar stephenusers//============================================================================ // // 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-2014 by Bradford W. Mott, Stephen Anthony // and 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: NullDev.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: NullDev.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class NullDevice : public Device { public: /** Create a new null device */ NullDevice(); /** Destructor */ virtual ~NullDevice(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { return "NullDevice"; } public: /** Get the byte at the specified address @return The byte at the specified address */ uInt8 peek(uInt16 address); /** 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); }; #endif stella-3.9.3/src/emucore/MindLink.hxx0000644000175000001440000000755312266336753017112 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: MindLink.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: MindLink.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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); /** Destructor */ virtual ~MindLink(); 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) { myDigitalPinState[pin] = value; } /** Called after *all* digital pins have been written on Port A. @param value The entire contents of the SWCHA register */ void controlWrite(uInt8) { nextMindlinkBit(); } /** Update the entire digital and analog pin state according to the events currently set. */ void update(); /** 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); 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; }; #endif stella-3.9.3/src/emucore/Cart0840.hxx0000644000175000001440000001044212266336753016601 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart0840.hxx,v 1.0 2006/11/14 //============================================================================ #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. @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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~Cartridge0840(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // The 8K ROM image of the cartridge uInt8 myImage[8192]; // Indicates which bank is currently active uInt16 myCurrentBank; // Previous Device's page access System::PageAccess myHotSpotPageAccess[8]; }; #endif stella-3.9.3/src/emucore/CartFE.hxx0000644000175000001440000001311012266336753016473 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartFE.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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. Kevin Horton describes FE as follows: Used only on two carts (Robot Tank and Decathlon). These carts are very weird. It does not use accesses to the stack like was previously thought. Instead, if you watch the called addresses very carefully, you can see that they are either Dxxx or Fxxx. This determines the bank to use. Just monitor A13 of the processor and use it to determine your bank! :-) Of course the 6507 in the 2600 does not have an A13, so the cart must have an extra bit in the ROM matrix to tell when to switch banks. There is *no* way to determine which bank you want to be in from monitoring the bus. This cart reports having 2 banks, even though this cannot be determined on a real system. @author Bradford W. Mott @version $Id: CartFE.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeFE(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** Answer whether the bank has changed since the last time this method was called. @return Whether the bank was changed */ bool bankChanged(); /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: /** Query/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 */ uInt8 getAccessFlags(uInt16 address); void setAccessFlags(uInt16 address, uInt8 flags); private: // The 8K ROM image of the cartridge uInt8 myImage[8192]; // Previous two addresses accessed by peek() uInt16 myLastAddress1, myLastAddress2; // Last two addresses have been modified by peek() bool myLastAddressChanged; }; #endif stella-3.9.3/src/emucore/TIATables.cxx0000644000175000001440000006566112266336753017154 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TIATables.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include "bspf.hxx" #include "TIATables.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIATables::computeAllTables() { memset(DisabledMask, 0, 640); buildCollisionMaskTable(); buildPxMaskTable(); buildMxMaskTable(); buildBLMaskTable(); buildPFMaskTable(); buildGRPReflectTable(); buildPxPosResetWhenTable(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIATables::buildCollisionMaskTable() { for(uInt8 i = 0; i < 64; ++i) { CollisionMask[i] = 0; if((i & M0Bit) && (i & P1Bit)) // M0-P1 CollisionMask[i] |= Cx_M0P1; if((i & M0Bit) && (i & P0Bit)) // M0-P0 CollisionMask[i] |= Cx_M0P0; if((i & M1Bit) && (i & P0Bit)) // M1-P0 CollisionMask[i] |= Cx_M1P0; if((i & M1Bit) && (i & P1Bit)) // M1-P1 CollisionMask[i] |= Cx_M1P1; if((i & P0Bit) && (i & PFBit)) // P0-PF CollisionMask[i] |= Cx_P0PF; if((i & P0Bit) && (i & BLBit)) // P0-BL CollisionMask[i] |= Cx_P0BL; if((i & P1Bit) && (i & PFBit)) // P1-PF CollisionMask[i] |= Cx_P1PF; if((i & P1Bit) && (i & BLBit)) // P1-BL CollisionMask[i] |= Cx_P1BL; if((i & M0Bit) && (i & PFBit)) // M0-PF CollisionMask[i] |= Cx_M0PF; if((i & M0Bit) && (i & BLBit)) // M0-BL CollisionMask[i] |= Cx_M0BL; if((i & M1Bit) && (i & PFBit)) // M1-PF CollisionMask[i] |= Cx_M1PF; if((i & M1Bit) && (i & BLBit)) // M1-BL CollisionMask[i] |= Cx_M1BL; if((i & BLBit) && (i & PFBit)) // BL-PF CollisionMask[i] |= Cx_BLPF; if((i & P0Bit) && (i & P1Bit)) // P0-P1 CollisionMask[i] |= Cx_P0P1; if((i & M0Bit) && (i & M1Bit)) // M0-M1 CollisionMask[i] |= Cx_M0M1; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // [suppress mode:2][nusiz:8][pixel:320] // suppress=1: suppress on // suppress=0: suppress off void TIATables::buildPxMaskTable() { Int32 x, suppress, nusiz; // Set the player mask table to all zeros for(nusiz = 0; nusiz < 8; ++nusiz) for(x = 0; x < 160; ++x) PxMask[0][nusiz][x] = PxMask[1][nusiz][x] = 0x00; // Now, compute the player mask table for(suppress = 0; suppress < 2; ++suppress) { for(nusiz = 0; nusiz < 8; ++nusiz) { for(x = 0; x < 160 + 72; ++x) { // nusiz: // 0: one copy // 1: two copies-close // 2: two copies-med // 3: three copies-close // 4: two copies-wide // 5: double size player // 6: 3 copies medium // 7: quad sized player switch(nusiz) { case 0x00: if((suppress == 0) && (x >= 0) && (x < 8)) PxMask[suppress][nusiz][x % 160] = 0x80 >> x; break; case 0x01: if((suppress == 0) && (x >= 0) && (x < 8)) PxMask[suppress][nusiz][x % 160] = 0x80 >> x; else if(((x - 16) >= 0) && ((x - 16) < 8)) PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 16); break; case 0x02: if((suppress == 0) && (x >= 0) && (x < 8)) PxMask[suppress][nusiz][x % 160] = 0x80 >> x; else if(((x - 32) >= 0) && ((x - 32) < 8)) PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 32); break; case 0x03: if((suppress == 0) && (x >= 0) && (x < 8)) PxMask[suppress][nusiz][x % 160] = 0x80 >> x; else if(((x - 16) >= 0) && ((x - 16) < 8)) PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 16); else if(((x - 32) >= 0) && ((x - 32) < 8)) PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 32); break; case 0x04: if((suppress == 0) && (x >= 0) && (x < 8)) PxMask[suppress][nusiz][x % 160] = 0x80 >> x; else if(((x - 64) >= 0) && ((x - 64) < 8)) PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 64); break; case 0x05: // For some reason in double size nusiz the player's output // is delayed by one pixel thus we use > instead of >= if((suppress == 0) && (x > 0) && (x <= 16)) PxMask[suppress][nusiz][x % 160] = 0x80 >> ((x - 1)/2); break; case 0x06: if((suppress == 0) && (x >= 0) && (x < 8)) PxMask[suppress][nusiz][x % 160] = 0x80 >> x; else if(((x - 32) >= 0) && ((x - 32) < 8)) PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 32); else if(((x - 64) >= 0) && ((x - 64) < 8)) PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 64); break; case 0x07: // For some reason in quad size nusiz the player's output // is delayed by one pixel thus we use > instead of >= if((suppress == 0) && (x > 0) && (x <= 32)) PxMask[suppress][nusiz][x % 160] = 0x80 >> ((x - 1)/4); break; } } // Copy data into wrap-around area for(x = 0; x < 160; ++x) PxMask[suppress][nusiz][x + 160] = PxMask[suppress][nusiz][x]; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // [number:8][size:5][pixel:320] void TIATables::buildMxMaskTable() { Int32 x, size, number; // Clear the missle table to start with for(number = 0; number < 8; ++number) for(size = 0; size < 5; ++size) for(x = 0; x < 160; ++x) MxMask[number][size][x] = false; for(number = 0; number < 8; ++number) { for(size = 0; size < 5; ++size) { for(x = 0; x < 160 + 72; ++x) { // For the following, size index = 4 is almost exactly the same as // index = 2; that is, 1 << 2, or 4 colour clocks wide // To simulate the weirdness in the Cosmic Ark starfield effect, // each group of 4 pixels has its 3rd pixel blanked switch(number) { // Only one copy of the missle case 0x00: case 0x05: case 0x07: if(size != 4) { if((x >= 0) && (x < (1 << size))) MxMask[number][size][x % 160] = true; } else { if((x >= 0) && (x < (1 << 2))) MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); } break; // Two copies - close case 0x01: if(size != 4) { if((x >= 0) && (x < (1 << size))) MxMask[number][size][x % 160] = true; else if(((x - 16) >= 0) && ((x - 16) < (1 << size))) MxMask[number][size][x % 160] = true; } else { if((x >= 0) && (x < (1 << 2))) MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); else if(((x - 16) >= 0) && ((x - 16) < (1 << 2))) MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); } break; // Two copies - medium case 0x02: if(size != 4) { if((x >= 0) && (x < (1 << size))) MxMask[number][size][x % 160] = true; else if(((x - 32) >= 0) && ((x - 32) < (1 << size))) MxMask[number][size][x % 160] = true; } else { if((x >= 0) && (x < (1 << 2))) MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); else if(((x - 32) >= 0) && ((x - 32) < (1 << 2))) MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); } break; // Three copies - close case 0x03: if(size != 4) { if((x >= 0) && (x < (1 << size))) MxMask[number][size][x % 160] = true; else if(((x - 16) >= 0) && ((x - 16) < (1 << size))) MxMask[number][size][x % 160] = true; else if(((x - 32) >= 0) && ((x - 32) < (1 << size))) MxMask[number][size][x % 160] = true; } else { if((x >= 0) && (x < (1 << 2))) MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); else if(((x - 16) >= 0) && ((x - 16) < (1 << 2))) MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); else if(((x - 32) >= 0) && ((x - 32) < (1 << 2))) MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); } break; // Two copies - wide case 0x04: if(size != 4) { if((x >= 0) && (x < (1 << size))) MxMask[number][size][x % 160] = true; else if(((x - 64) >= 0) && ((x - 64) < (1 << size))) MxMask[number][size][x % 160] = true; } else { if((x >= 0) && (x < (1 << 2))) MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); else if(((x - 64) >= 0) && ((x - 64) < (1 << 2))) MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); } break; // Three copies - medium case 0x06: if(size != 4) { if((x >= 0) && (x < (1 << size))) MxMask[number][size][x % 160] = true; else if(((x - 32) >= 0) && ((x - 32) < (1 << size))) MxMask[number][size][x % 160] = true; else if(((x - 64) >= 0) && ((x - 64) < (1 << size))) MxMask[number][size][x % 160] = true; } else { if((x >= 0) && (x < (1 << 2))) MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); else if(((x - 32) >= 0) && ((x - 32) < (1 << 2))) MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); else if(((x - 64) >= 0) && ((x - 64) < (1 << 2))) MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); } break; } } // Copy data into wrap-around area for(x = 0; x < 160; ++x) MxMask[number][size][x + 160] = MxMask[number][size][x]; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // [size:4][pixel:320] void TIATables::buildBLMaskTable() { for(Int32 size = 0; size < 4; ++size) { Int32 x; // Set all of the masks to false to start with for(x = 0; x < 160; ++x) BLMask[size][x] = false; // Set the necessary fields true for(x = 0; x < 160 + 8; ++x) if((x >= 0) && (x < (1 << size))) BLMask[size][x % 160] = true; // Copy fields into the wrap-around area of the mask for(x = 0; x < 160; ++x) BLMask[size][x + 160] = BLMask[size][x]; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // [reflect:2][pixel:160] // reflect=1: reflection on // reflect=0: reflection off void TIATables::buildPFMaskTable() { Int32 x; // Compute playfield mask table for non-reflected mode for(x = 0; x < 160; ++x) { if(x < 16) PFMask[0][x] = 0x00001 << (x >> 2); else if(x < 48) PFMask[0][x] = 0x00800 >> ((x - 16) >> 2); else if(x < 80) PFMask[0][x] = 0x01000 << ((x - 48) >> 2); else if(x < 96) PFMask[0][x] = 0x00001 << ((x - 80) >> 2); else if(x < 128) PFMask[0][x] = 0x00800 >> ((x - 96) >> 2); else if(x < 160) PFMask[0][x] = 0x01000 << ((x - 128) >> 2); } // Compute playfield mask table for reflected mode for(x = 0; x < 160; ++x) { if(x < 16) PFMask[1][x] = 0x00001 << (x >> 2); else if(x < 48) PFMask[1][x] = 0x00800 >> ((x - 16) >> 2); else if(x < 80) PFMask[1][x] = 0x01000 << ((x - 48) >> 2); else if(x < 112) PFMask[1][x] = 0x80000 >> ((x - 80) >> 2); else if(x < 144) PFMask[1][x] = 0x00010 << ((x - 112) >> 2); else if(x < 160) PFMask[1][x] = 0x00008 >> ((x - 144) >> 2); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIATables::buildGRPReflectTable() { for(uInt16 i = 0; i < 256; ++i) { uInt8 r = 0; for(uInt16 t = 1; t <= 128; t <<= 1) r = (r << 1) | ((i & t) ? 0x01 : 0x00); GRPReflect[i] = r; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // [nusiz:8][old pixel:160][new pixel:160] void TIATables::buildPxPosResetWhenTable() { uInt32 nusiz, oldx, newx; // Loop through all player nusizs, all old player positions, and all new // player positions and determine where the new position is located: // 1 means the new position is within the display of an old copy of the // player, -1 means the new position is within the delay portion of an // old copy of the player, and 0 means it's neither of these two for(nusiz = 0; nusiz < 8; ++nusiz) { for(oldx = 0; oldx < 160; ++oldx) { // Set everything to 0 for non-delay/non-display section for(newx = 0; newx < 160; ++newx) PxPosResetWhen[nusiz][oldx][newx] = 0; // Now, we'll set the entries for non-delay/non-display section for(newx = 0; newx < 160 + 72 + 5; ++newx) { // nusiz: // 0: one copy // 1: two copies-close // 2: two copies-med // 3: three copies-close // 4: two copies-wide // 5: double size player // 6: 3 copies medium // 7: quad sized player switch(nusiz) { case 0x00: if((newx >= oldx) && (newx < (oldx + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; break; case 0x01: if((newx >= oldx) && (newx < (oldx + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; else if((newx >= (oldx + 16)) && (newx < (oldx + 16 + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; else if((newx >= oldx + 16 + 4) && (newx < (oldx + 16 + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; break; case 0x02: if((newx >= oldx) && (newx < (oldx + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; break; case 0x03: if((newx >= oldx) && (newx < (oldx + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; else if((newx >= (oldx + 16)) && (newx < (oldx + 16 + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; else if((newx >= oldx + 16 + 4) && (newx < (oldx + 16 + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; break; case 0x04: if((newx >= oldx) && (newx < (oldx + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; else if((newx >= (oldx + 64)) && (newx < (oldx + 64 + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; else if((newx >= oldx + 64 + 4) && (newx < (oldx + 64 + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; break; case 0x05: if((newx >= oldx) && (newx < (oldx + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; else if((newx >= oldx + 4) && (newx < (oldx + 4 + 16))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; break; case 0x06: if((newx >= oldx) && (newx < (oldx + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; else if((newx >= (oldx + 64)) && (newx < (oldx + 64 + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; else if((newx >= oldx + 64 + 4) && (newx < (oldx + 64 + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; break; case 0x07: if((newx >= oldx) && (newx < (oldx + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; else if((newx >= oldx + 4) && (newx < (oldx + 4 + 32))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; break; } } // Let's do a sanity check on table entries uInt32 s1 = 0, s2 = 0; for(newx = 0; newx < 160; ++newx) { if(PxPosResetWhen[nusiz][oldx][newx] == -1) ++s1; if(PxPosResetWhen[nusiz][oldx][newx] == 1) ++s2; } assert((s1 % 4 == 0) && (s2 % 8 == 0)); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Int16 TIATables::PokeDelay[64] = { 0, // VSYNC 1, // VBLANK (0) / 1 0, // WSYNC 0, // RSYNC 0, // NUSIZ0 0, // NUSIZ1 0, // COLUP0 0, // COLUP1 0, // COLUPF 0, // COLUBK 0, // CTRLPF 1, // REFP0 1, // REFP1 -1, // PF0 (4) / -1 -1, // PF1 (4) / -1 -1, // PF2 (4) / -1 0, // RESP0 0, // RESP1 8, // RESM0 (0) / 8 8, // RESM1 (0) / 8 0, // RESBL 0, // AUDC0 (-1) / 0 0, // AUDC1 (-1) / 0 0, // AUDF0 (-1) / 0 0, // AUDF1 (-1) / 0 0, // AUDV0 (-1) / 0 0, // AUDV1 (-1) / 0 1, // GRP0 1, // GRP1 1, // ENAM0 1, // ENAM1 1, // ENABL 0, // HMP0 0, // HMP1 0, // HMM0 0, // HMM1 0, // HMBL 0, // VDELP0 0, // VDELP1 0, // VDELBL 0, // RESMP0 0, // RESMP1 3, // HMOVE 0, // HMCLR 0, // CXCLR // remaining values are undefined TIA write locations 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const bool TIATables::HMOVEBlankEnableCycles[76] = { true, true, true, true, true, true, true, true, true, true, // 00 true, true, true, true, true, true, true, true, true, true, // 10 true, false, false, false, false, false, false, false, false, false, // 20 false, false, false, false, false, false, false, false, false, false, // 30 false, false, false, false, false, false, false, false, false, false, // 40 false, false, false, false, false, false, false, false, false, false, // 50 false, false, false, false, false, false, false, false, false, false, // 60 false, false, false, false, false, true // 70 }; #if 0 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Int32 TIATables::CompleteMotion[76][16] = { { 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK { 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK { 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK { 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK { 0, -1, -2, -3, -4, -5, -6, -6, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK { 0, -1, -2, -3, -4, -5, -5, -5, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK { 0, -1, -2, -3, -4, -5, -5, -5, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK { 0, -1, -2, -3, -4, -4, -4, -4, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK { 0, -1, -2, -3, -3, -3, -3, -3, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK { 0, -1, -2, -2, -2, -2, -2, -2, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK { 0, -1, -2, -2, -2, -2, -2, -2, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK { 0, -1, -1, -1, -1, -1, -1, -1, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK { 0, 0, 0, 0, 0, 0, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK { 1, 1, 1, 1, 1, 1, 1, 1, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK { 1, 1, 1, 1, 1, 1, 1, 1, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK { 2, 2, 2, 2, 2, 2, 2, 2, 8, 7, 6, 5, 4, 3, 2, 2}, // HBLANK { 3, 3, 3, 3, 3, 3, 3, 3, 8, 7, 6, 5, 4, 3, 3, 3}, // HBLANK { 4, 4, 4, 4, 4, 4, 4, 4, 8, 7, 6, 5, 4, 4, 4, 4}, // HBLANK { 4, 4, 4, 4, 4, 4, 4, 4, 8, 7, 6, 5, 4, 4, 4, 4}, // HBLANK { 5, 5, 5, 5, 5, 5, 5, 5, 8, 7, 6, 5, 5, 5, 5, 5}, // HBLANK { 6, 6, 6, 6, 6, 6, 6, 6, 8, 7, 6, 6, 6, 6, 6, 6}, // HBLANK { 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, 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, 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, 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, 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, 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, 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, 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, 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, -1, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, -1, -2, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, -1, -2, -3, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, -1, -2, -3, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, -1, -2, -3, -4, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, -1, -2, -3, -4, -5, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, -1, -2, -3, -4, -5, -6, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, -1, -2, -3, -4, -5, -6, 0, 0, 0, 0, 0, 0, 0, 0}, { 0, -1, -2, -3, -4, -5, -6, -7, 0, 0, 0, 0, 0, 0, 0, 0}, {-1, -2, -3, -4, -5, -6, -7, -8, 0, 0, 0, 0, 0, 0, 0, 0}, {-2, -3, -4, -5, -6, -7, -8, -9, 0, 0, 0, 0, 0, 0, 0, -1}, {-2, -3, -4, -5, -6, -7, -8, -9, 0, 0, 0, 0, 0, 0, 0, -1}, {-3, -4, -5, -6, -7, -8, -9,-10, 0, 0, 0, 0, 0, 0, -1, -2}, {-4, -5, -6, -7, -8, -9,-10,-11, 0, 0, 0, 0, 0, -1, -2, -3}, {-5, -6, -7, -8, -9,-10,-11,-12, 0, 0, 0, 0, -1, -2, -3, -4}, {-5, -6, -7, -8, -9,-10,-11,-12, 0, 0, 0, 0, -1, -2, -3, -4}, {-6, -7, -8, -9,-10,-11,-12,-13, 0, 0, 0, -1, -2, -3, -4, -5}, {-7, -8, -9,-10,-11,-12,-13,-14, 0, 0, -1, -2, -3, -4, -5, -6}, {-8, -9,-10,-11,-12,-13,-14,-15, 0, -1, -2, -3, -4, -5, -6, -7}, {-8, -9,-10,-11,-12,-13,-14,-15, 0, -1, -2, -3, -4, -5, -6, -7}, { 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1} // HBLANK }; #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIATables::PxMask[2][8][320]; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIATables::MxMask[8][5][320]; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIATables::BLMask[4][320]; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 TIATables::PFMask[2][160]; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIATables::GRPReflect[256]; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 TIATables::CollisionMask[64]; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIATables::DisabledMask[640]; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Int8 TIATables::PxPosResetWhen[8][160][160]; stella-3.9.3/src/emucore/MT24LC256.hxx0000644000175000001440000000666512266336753016552 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: MT24LC256.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: MT24LC256.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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); /** Destructor */ virtual ~MT24LC256(); public: /** Read boolean data from the SDA line */ bool readSDA(); /** Write boolean data to the SDA and SCL lines */ void writeSDA(bool state); void writeSCL(bool state); /** Notification method invoked by the system right before the system resets its cycle counter to zero. It may be necessary to override this method for devices that remember cycle counts. */ void systemCyclesReset(); 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: // The system of the parent controller const System& mySystem; // The EEPROM data uInt8 myData[32768]; // 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 uInt32 myCyclesWhenTimerSet; // Indicates when the SDA and SCL pins were set/written uInt32 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 int jpee_mdat, jpee_sdat, jpee_mclk; int jpee_sizemask, jpee_pagemask, jpee_smallmode, jpee_logmode; int jpee_pptr, jpee_state, jpee_nb; unsigned int jpee_address, jpee_ad_known; uInt8 jpee_packet[70]; private: // Copy constructor isn't supported by this class so make it private MT24LC256(const MT24LC256&); // Assignment operator isn't supported by this class so make it private MT24LC256& operator = (const MT24LC256&); }; #endif stella-3.9.3/src/emucore/CartBF.hxx0000644000175000001440000001046712266336753016504 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartBF.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 32 4K banks (total of 128K ROM). Accessing $1FC0 - $1FDF switches to each bank. @author Mike Saarna @version $Id: CartBF.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeBF(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 64K ROM image of the cartridge uInt8 myImage[262144]; }; #endif stella-3.9.3/src/emucore/CartFA.hxx0000644000175000001440000001052112266336753016472 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartFA.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 and 256 bytes of RAM. @author Bradford W. Mott @version $Id: CartFA.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeFA(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 12K ROM image of the cartridge uInt8 myImage[12288]; // The 256 bytes of RAM on the cartridge uInt8 myRAM[256]; }; #endif stella-3.9.3/src/emucore/Settings.hxx0000644000175000001440000001131012266336753017167 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Settings.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef SETTINGS_HXX #define SETTINGS_HXX class OSystem; #include "Array.hxx" #include "Variant.hxx" #include "bspf.hxx" /** This class provides an interface for accessing frontend specific settings. @author Stephen Anthony @version $Id: Settings.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class Settings { friend class OSystem; public: /** Create a new settings abstract class */ Settings(OSystem* osystem); /** Destructor */ virtual ~Settings(); 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(); /** 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(); private: // Copy constructor isn't supported by this class so make it private Settings(const Settings&); // Assignment operator isn't supported by this class so make it private Settings& operator = (const Settings&); // 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; }; typedef Common::Array SettingsArray; 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; }; #endif stella-3.9.3/src/emucore/CartDF.cxx0000644000175000001440000001131012266336753016465 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDF.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartDF.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDF::CartridgeDF(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(131072u, size)); createCodeAccessBase(131072); // Remember startup bank myStartBank = 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDF::~CartridgeDF() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDF::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDF::install(System& system) { mySystem = &system; // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mySystem->pageMask()) == 0); // 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[(myCurrentBank << 12) + 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 myCurrentBank = bank; uInt32 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1FC0 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1000; address < (0x1FC0U & ~mask); address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeDF::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeDF::bankCount() const { return 32; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDF::patch(uInt16 address, uInt8 value) { myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeDF::getImage(int& size) const { size = 131072; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDF::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); } catch(...) { cerr << "ERROR: CartridgeDF::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDF::load(Serializer& in) { try { if(in.getString() != name()) return false; myCurrentBank = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeDF::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/AtariVox.hxx0000644000175000001440000000735012266336753017135 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: AtariVox.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef ATARIVOX_HXX #define ATARIVOX_HXX class SerialPort; class MT24LC256; #include "Control.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 @version $Id: AtariVox.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class AtariVox : public Controller { 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); /** Destructor */ virtual ~AtariVox(); 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); /** 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); /** Update the entire digital and analog pin state according to the events currently set. */ void update() { } /** Notification method invoked by the system right before the system resets its cycle counter to zero. It may be necessary to override this method for devices that remember cycle counts. */ void systemCyclesReset(); string about() const; private: void clockDataIn(bool value); void shiftIn(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; // The EEPROM used in the AtariVox MT24LC256* myEEPROM; // 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". uInt32 myLastDataWriteCycle; // Holds information concerning serial port usage string myAboutString; }; #endif stella-3.9.3/src/emucore/CartDFSC.cxx0000644000175000001440000001516212266336753016724 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDFSC.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartDFSC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDFSC::CartridgeDFSC(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(131072u, size)); createCodeAccessBase(131072); // This cart contains 128 bytes extended RAM @ 0x1000 registerRamArea(0x1000, 128, 0x80, 0x00); // Remember startup bank myStartBank = 15; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDFSC::~CartridgeDFSC() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDFSC::reset() { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 128; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 128); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDFSC::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mask) == 0); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt32 j = 0x1000; j < 0x1080; j += (1 << shift)) { access.directPokeBase = &myRAM[j & 0x007F]; access.codeAccessBase = &myCodeAccessBase[j & 0x007F]; mySystem->setPageAccess(j >> shift, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = 0; access.type = System::PA_READ; for(uInt32 k = 0x1080; k < 0x1100; k += (1 << shift)) { access.directPeekBase = &myRAM[k & 0x007F]; access.codeAccessBase = &myCodeAccessBase[0x80 + (k & 0x007F)]; mySystem->setPageAccess(k >> shift, 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[(myCurrentBank << 12) + 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 function // 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 myCurrentBank = bank; uInt32 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1FC0 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1100; address < (0x1FC0U & ~mask); address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeDFSC::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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[(myCurrentBank << 12) + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeDFSC::getImage(int& size) const { size = 131072; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDFSC::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); 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; myCurrentBank = in.getShort(); in.getByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeDFSC::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/Cart4A50.hxx0000644000175000001440000001624012266336753016621 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart4A50.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 http://www.casperkitty.com/stella/cartfmt.htm. 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. @author Eckhard Stolberg & Stephen Anthony @version $Id: Cart4A50.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~Cartridge4A50(); public: /** Reset cartridge to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: /** Query/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 */ uInt8 getAccessFlags(uInt16 address); void setAccessFlags(uInt16 address, uInt8 flags); /** 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; }; #endif stella-3.9.3/src/emucore/TIASnd.hxx0000644000175000001440000001312112266336753016453 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: TIASnd.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: TIASnd.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class TIASound { public: /** Create a new TIA Sound object using the specified output frequency */ TIASound(Int32 outputFrequency = 31400); /** Destructor */ virtual ~TIASound(); 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 PURE = 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]; }; #endif stella-3.9.3/src/emucore/FSNode.hxx0000644000175000001440000003125712266336753016521 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: FSNode.hxx 2838 2014-01-17 23:34:03Z stephena $ // // 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 "Array.hxx" #include "SharedPtr.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 Common::Array { }; /** * 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() {} /** * 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; } /** * 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 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(uInt8*& 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; private: Common::SharedPtr _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. */ typedef Common::Array AbstractFSList; class AbstractFSNode { protected: friend class FilesystemNode; typedef FilesystemNode::ListMode ListMode; public: /** * Destructor. */ virtual ~AbstractFSNode() {} /* * 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(uInt8*& 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-3.9.3/src/emucore/Cart4KSC.hxx0000644000175000001440000001034712266336753016716 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart4KSC.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 4KSC games with 128 bytes of RAM. There are two 4K banks. */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~Cartridge4KSC(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 8K ROM image of the cartridge uInt8 myImage[4096]; // The 128 bytes of RAM uInt8 myRAM[128]; }; #endif stella-3.9.3/src/emucore/CartF6SC.hxx0000644000175000001440000001053412266336753016711 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartF6SC.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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. @author Bradford W. Mott @version $Id: CartF6SC.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeF6SC(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 16K ROM image of the cartridge uInt8 myImage[16384]; // The 128 bytes of RAM uInt8 myRAM[128]; }; #endif stella-3.9.3/src/emucore/PropsSet.cxx0000644000175000001440000001563112266336753017153 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: PropsSet.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include #include "bspf.hxx" #include "DefProps.hxx" #include "OSystem.hxx" #include "Props.hxx" #include "Settings.hxx" #include "PropsSet.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PropertiesSet::PropertiesSet(OSystem* osystem) : myOSystem(osystem) { load(myOSystem->propertiesFile()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PropertiesSet::~PropertiesSet() { myExternalProps.clear(); myTempProps.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PropertiesSet::load(const string& filename) { ifstream in(filename.c_str(), ios::in); // Loop reading properties for(;;) { // Make sure the stream is still good or we're done if(!in) break; // Get the property list associated with this profile Properties prop; prop.load(in); // If the stream is still good then insert the properties if(in) insert(prop); } if(in) in.close(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PropertiesSet::save(const string& filename) const { ofstream out(filename.c_str(), ios::out); if(!out) return false; // Only save those entries in the external list for(PropsList::const_iterator i = myExternalProps.begin(); i != myExternalProps.end(); ++i) i->second.save(out); 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 PropsList::const_iterator iter = myExternalProps.find(md5); if(iter != myExternalProps.end()) { properties = iter->second; found = true; } else // Search temp list { iter = myTempProps.find(md5); if(iter != myTempProps.end()) { properties = iter->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; // The status of 'save' determines which list to save to PropsList& list = save ? myExternalProps : myTempProps; pair ret; ret = list.insert(make_pair(md5, properties)); if(ret.second == false) { // Remove old item and insert again list.erase(ret.first); list.insert(make_pair(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) PropsList list; // First insert all external props 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.insert(make_pair(DefProps[i][Cartridge_MD5], properties)); } // Now, print the resulting list Properties::printHeader(); for(PropsList::const_iterator i = list.begin(); i != list.end(); ++i) i->second.print(); } stella-3.9.3/src/emucore/MediaFactory.hxx0000644000175000001440000000461012266336753017743 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: MediaFactory.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef MEDIA_FACTORY_HXX #define MEDIA_FACTORY_HXX #include "OSystem.hxx" #include "Settings.hxx" #include "FrameBuffer.hxx" #include "FrameBufferSoft.hxx" #ifdef DISPLAY_OPENGL #include "FrameBufferGL.hxx" #endif #include "Sound.hxx" #ifdef SOUND_SUPPORT #include "SoundSDL.hxx" #else #include "SoundNull.hxx" #endif /** This class deals with the different framebuffer/sound implementations for the various ports of Stella, and always returns a valid media object based on the specific port and restrictions on that port. I think you can see why this mess was put into a factory class :) @author Stephen Anthony @version $Id: MediaFactory.hxx 2838 2014-01-17 23:34:03Z stephena $ */ class MediaFactory { public: static FrameBuffer* createVideo(OSystem* osystem) { FrameBuffer* fb = (FrameBuffer*) NULL; // OpenGL mode *may* fail, so we check for it first #ifdef DISPLAY_OPENGL if(osystem->settings().getString("video") == "gl") { const string& gl_lib = osystem->settings().getString("gl_lib"); if(FrameBufferGL::loadLibrary(gl_lib)) fb = new FrameBufferGL(osystem); } #endif // If OpenGL failed, or if it wasn't requested, create the appropriate // software framebuffer if(!fb) fb = new FrameBufferSoft(osystem); // This should never happen assert(fb != NULL); return fb; } static Sound* createAudio(OSystem* osystem) { Sound* sound = (Sound*) NULL; #ifdef SOUND_SUPPORT sound = new SoundSDL(osystem); #else sound = new SoundNull(osystem); #endif return sound; } }; #endif stella-3.9.3/src/emucore/Thumbulator.hxx0000644000175000001440000001125712266336753017707 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Thumbulator.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ //============================================================================ // 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 //============================================================================ #ifdef THUMB_SUPPORT #include "bspf.hxx" #define ROMADDMASK 0x7FFF #define RAMADDMASK 0x1FFF #define ROMSIZE (ROMADDMASK+1) #define RAMSIZE (RAMADDMASK+1) //0b10000 User PC, R14 to R0, CPSR //0b10001 FIQ PC, R14_fiq to R8_fiq, R7 to R0, CPSR, SPSR_fiq //0b10010 IRQ PC, R14_irq, R13_irq, R12 to R0, CPSR, SPSR_irq //0b10011 Supervisor PC, R14_svc, R13_svc, R12 to R0, CPSR, SPSR_svc //0b10111 Abort PC, R14_abt, R13_abt, R12 to R0, CPSR, SPSR_abt //0b11011 Undefined PC, R14_und, R13_und, R12 to R0, CPSR, SPSR_und //0b11111 System #define MODE_USR 0x10 #define MODE_FIQ 0x11 #define MODE_IRQ 0x12 #define MODE_SVC 0x13 #define MODE_ABT 0x17 #define MODE_UND 0x1B #define MODE_SYS 0x1F #define CPSR_T (1<<5) #define CPSR_F (1<<6) #define CPSR_I (1<<7) #define CPSR_N (1<<31) #define CPSR_Z (1<<30) #define CPSR_C (1<<29) #define CPSR_V (1<<28) #define CPSR_Q (1<<27) class Thumbulator { public: Thumbulator(const uInt16* rom, uInt16* ram, bool traponfatal); ~Thumbulator(); /** Run the ARM code, and return when finished. A string 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(); /** 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; } private: uInt32 read_register ( uInt32 reg ); uInt32 write_register ( uInt32 reg, uInt32 data ); uInt32 fetch16 ( uInt32 addr ); uInt32 fetch32 ( uInt32 addr ); uInt32 read16 ( uInt32 addr ); uInt32 read32 ( uInt32 ); void write16 ( uInt32 addr, uInt32 data ); void write32 ( uInt32 addr, uInt32 data ); void do_zflag ( uInt32 x ); void do_nflag ( uInt32 x ); void do_cflag ( uInt32 a, uInt32 b, uInt32 c ); void do_sub_vflag ( uInt32 a, uInt32 b, uInt32 c ); void do_add_vflag ( uInt32 a, uInt32 b, uInt32 c ); void do_cflag_bit ( uInt32 x ); void do_vflag_bit ( uInt32 x ); // Throw a string 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 ); void dump_regs( void ); int execute ( void ); int reset ( void ); private: const uInt16* rom; uInt16* ram; //Int32 copydata; uInt32 halfadd; uInt32 cpsr; //uInt32 reg_usr[16]; //User mode uInt32 reg_sys[16]; //System mode uInt32 reg_svc[16]; //Supervisor mode //uInt32 reg_abt[16]; //Abort mode //uInt32 reg_und[16]; //Undefined mode //uInt32 reg_irq[16]; //Interrupt mode //uInt32 reg_fiq[16]; //Fast Interrupt mode uInt32 mamcr; uInt64 instructions; uInt64 fetches; uInt64 reads; uInt64 writes; ostringstream statusMsg; static bool trapOnFatal; }; #endif stella-3.9.3/src/emucore/CartEF.hxx0000644000175000001440000001065312266336753016504 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartEF.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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. This interpretation is based on analysis of the z26 assembly code, as this scheme doesn't seem to be documented anywhere. @author Stephen Anthony @version $Id: CartEF.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeEF(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); private: // Indicates which bank is currently active uInt16 myCurrentBank; // The 64K ROM image of the cartridge uInt8 myImage[65536]; }; #endif stella-3.9.3/src/emucore/CartCM.cxx0000644000175000001440000001561212266336753016504 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartCM.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "M6532.hxx" #include "CartCM.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCM::CartridgeCM(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(16384u, size)); createCodeAccessBase(16384); // This cart contains 2048 bytes extended RAM @ 0x1800 // This RAM scheme is unique in that it doesn't require separate read/write ports registerRamArea(0x1800, 2048, 0x00, 0x00); // On powerup, portA is all 1's, so the last bank of ROM is enabled and // RAM is disabled mySWCHA = 0xff; myStartBank = mySWCHA & 0x3; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCM::~CartridgeCM() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCM::reset() { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 2048; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 2048); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCM::install(System& system) { mySystem = &system; uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mask) == 0); // Mirror all access in RIOT; by doing so we're taking responsibility // for that address space in peek and poke below. mySystem->m6532().install(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 function // 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(value & 0x20) myColumn = 0; if(value & 0x40) myColumn = (myColumn + 1) % 10; } mySystem->m6532().poke(address, value); } return myBankChanged; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCM::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myCurrentBank = bank; uInt16 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); // 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(0, 0, 0, this, System::PA_READ); // Lower 2K (always ROM) for(uInt32 address = 0x1000; address < 0x1800; address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } // Upper 2K (RAM or ROM) for(uInt32 address = 0x1800; address < 0x2000; address += (1 << shift)) { access.type = System::PA_READWRITE; if(mySWCHA & 0x10) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; } else { access.directPeekBase = &myRAM[address & 0x7FF]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x07FF)]; } if((mySWCHA & 0x30) == 0x20) access.directPokeBase = &myRAM[address & 0x7FF]; else access.directPokeBase = 0; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeCM::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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[(myCurrentBank << 12) + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeCM::getImage(int& size) const { size = 16384; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCM::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); out.putByte(mySWCHA); out.putByte(myColumn); 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; myCurrentBank = in.getShort(); mySWCHA = in.getByte(); myColumn = in.getByte(); in.getByteArray(myRAM, 2048); } catch(...) { cerr << "ERROR: CartridgeCM::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/Console.hxx0000644000175000001440000002517712266336753017011 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Console.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef CONSOLE_HXX #define CONSOLE_HXX class Controller; class Event; class Switches; class System; class TIA; class M6532; class Cartridge; class CompuMate; #include "bspf.hxx" #include "Control.hxx" #include "Props.hxx" #include "TIATables.hxx" #include "FrameBuffer.hxx" #include "Serializable.hxx" #include "NTSCFilter.hxx" /** Contains detailed info about a console. */ struct ConsoleInfo { string BankSwitch; string CartName; string CartMD5; string Control0; string Control1; string DisplayFormat; string InitialFrameRate; }; /** This class represents the entire game console. @author Bradford W. Mott @version $Id: Console.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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, Cartridge* cart, const Properties& props); /** Create a new console object by copying another one @param console The object to copy */ Console(const Console& console); /** Destructor */ virtual ~Console(); public: /** Get the controller plugged into the specified jack @return The specified controller */ Controller& controller(Controller::Jack jack) const { return *myControllers[jack]; } /** 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; } /** Get the CompuMate handler used by the console (only valid for CompuMate ROMs) @return The CompuMate handler for this console (if it exists), otherwise 0 */ CompuMate* compumate() const { return myCMHandler; } /** 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; /** 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); /** Get a descriptor for this console class (used in error checking). @return The name of the object */ string name() const { return "Console"; } /** Set the properties to those given @param 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; } /** Set up the console to use the debugger. */ void addDebugger(); /** Informs the Console of a change in EventHandler state. */ void stateChanged(EventHandler::State state); public: /** Overloaded assignment operator @param console The console object to set myself equal to @return Myself after assignment has taken place */ Console& operator = (const Console& console); 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(); /** Toggles the PAL color-loss effect. */ void toggleColorLoss(); void toggleColorLoss(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 toggleHMOVE() const; 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; private: /** 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); /** 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 setColorLossPalette(); /** 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: // Pointer to the osystem object OSystem* myOSystem; // Reference to the event object to use Event& myEvent; // Properties for the game Properties myProperties; // Pointers to the left and right controllers Controller* myControllers[2]; // Pointer to the TIA object TIA* myTIA; // Pointer to the switches on the front of the console Switches* mySwitches; // Pointer to the 6502 based system being emulated System* mySystem; // Pointer to the Cartridge (the debugger needs it) Cartridge* myCart; // Pointer to the 6532 (aka RIOT) (the debugger needs it) // A RIOT of my own! (...with apologies to The Clash...) M6532* myRiot; // Pointer to CompuMate handler (only used in CompuMate ROMs) CompuMate* 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; // Indicates whether an external palette was found and // successfully loaded bool myUserPaletteDefined; // Contains detailed info about this console ConsoleInfo myConsoleInfo; // 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]; }; #endif stella-3.9.3/src/emucore/Driving.hxx0000644000175000001440000000606412266336753017003 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Driving.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef DRIVING_HXX #define DRIVING_HXX #include "bspf.hxx" #include "Control.hxx" #include "Event.hxx" /** The standard Atari 2600 Indy 500 driving controller. @author Bradford W. Mott @version $Id: Driving.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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); /** Destructor */ virtual ~Driving(); public: /** Update the entire digital and analog pin state according to the events currently set. */ void update(); /** 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); 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; }; #endif stella-3.9.3/src/emucore/Props.cxx0000644000175000001440000002247412266336753016502 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Props.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include #include "bspf.hxx" #include "Props.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Properties::Properties() { setDefaults(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Properties::Properties(const Properties& properties) { copy(properties); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Properties::~Properties() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& Properties::get(PropertyType key) const { if(key >= 0 && key < LastPropType) return myProperties[key]; else return EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Properties::set(PropertyType key, const string& value) { if(key >= 0 && key < LastPropType) { myProperties[key] = value; switch(key) { case Cartridge_Type: case Display_Format: if(BSPF_equalsIgnoreCase(myProperties[key], "AUTO-DETECT")) myProperties[key] = "AUTO"; 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(), (int(*)(int)) toupper); break; } case Display_PPBlend: { int blend = atoi(myProperties[key].c_str()); if(blend < 0 || blend > 100) blend = 77; ostringstream buf; buf << blend; myProperties[key] = buf.str(); break; } default: break; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Properties::load(istream& in) { setDefaults(); // Loop reading properties string key, value; for(;;) { // Get the key associated with this property key = readQuotedString(in); // Make sure the stream is still okay if(!in) return; // A null key signifies the end of the property list if(key == "") break; // Get the value associated with this property value = readQuotedString(in); // Make sure the stream is still okay if(!in) return; // Set the property PropertyType type = getPropertyType(key); set(type, value); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Properties::save(ostream& out) const { // 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(myProperties[i] != ourDefaultProperties[i]) { writeQuotedString(out, ourPropertyNames[i]); out.put(' '); writeQuotedString(out, myProperties[i]); out.put('\n'); changed = true; } } if(changed) { // Put a trailing null string so we know when to stop reading writeQuotedString(out, ""); out.put('\n'); out.put('\n'); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Properties::readQuotedString(istream& in) { char c; // Read characters until we see a quote 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('"'); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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::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; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* 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 "34", // Display.YStart "210", // Display.Height "NO", // Display.Phosphor "77" // Display.PPBlend }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* 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-3.9.3/src/emucore/Joystick.cxx0000644000175000001440000001157012266336753017171 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Joystick.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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; } // Analog pins are never used by the joystick myAnalogPinValue[Five] = myAnalogPinValue[Nine] = maximumResistance; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Joystick::~Joystick() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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) { if(deadzone < 0) deadzone = 0; if(deadzone > 29) deadzone = 29; _DEAD_ZONE = 3200 + deadzone * 1000; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Joystick::_DEAD_ZONE = 3200; stella-3.9.3/src/emucore/CartEFSC.cxx0000644000175000001440000001515712266336753016731 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartEFSC.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "CartEFSC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeEFSC::CartridgeEFSC(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image, BSPF_min(65536u, size)); createCodeAccessBase(65536); // This cart contains 128 bytes extended RAM @ 0x1000 registerRamArea(0x1000, 128, 0x80, 0x00); // Remember startup bank myStartBank = 15; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeEFSC::~CartridgeEFSC() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEFSC::reset() { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 128; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 128); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEFSC::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1000 & mask) == 0); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt32 j = 0x1000; j < 0x1080; j += (1 << shift)) { access.directPokeBase = &myRAM[j & 0x007F]; access.codeAccessBase = &myCodeAccessBase[j & 0x007F]; mySystem->setPageAccess(j >> shift, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = 0; access.type = System::PA_READ; for(uInt32 k = 0x1080; k < 0x1100; k += (1 << shift)) { access.directPeekBase = &myRAM[k & 0x007F]; access.codeAccessBase = &myCodeAccessBase[0x80 + (k & 0x007F)]; mySystem->setPageAccess(k >> shift, 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[(myCurrentBank << 12) + 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 myCurrentBank = bank; uInt16 offset = myCurrentBank << 12; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); System::PageAccess access(0, 0, 0, this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt32 i = (0x1FE0 & ~mask); i < 0x2000; i += (1 << shift)) { access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)]; mySystem->setPageAccess(i >> shift, access); } // Setup the page access methods for the current bank for(uInt32 address = 0x1100; address < (0x1FE0U & ~mask); address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)]; mySystem->setPageAccess(address >> shift, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeEFSC::bank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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[(myCurrentBank << 12) + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeEFSC::getImage(int& size) const { size = 65536; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEFSC::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); 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; myCurrentBank = in.getShort(); in.getByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeEFSC::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-3.9.3/src/emucore/Switches.cxx0000644000175000001440000000554212266336753017165 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Switches.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include "Event.hxx" #include "Props.hxx" #include "Switches.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Switches::Switches(const Event& event, const Properties& properties) : myEvent(event), mySwitches(0xFF) { 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; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Switches::~Switches() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Switches::update() { 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; } stella-3.9.3/src/emucore/CartDPC.hxx0000644000175000001440000001375212266336753016623 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartDPC.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: CartDPC.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeDPC(); public: /** Reset device to its power-on state */ void reset(); /** Notification method invoked by the system right before the system resets its cycle counter to zero. It may be necessary to override this method for devices that remember cycle counts. */ void systemCyclesReset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); 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; // Indicates which bank is currently active uInt16 myCurrentBank; // 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 when the last update to music data fetchers occurred Int32 mySystemCycles; // Fractional DPC music OSC clocks unused during the last update double myFractionalClocks; }; #endif stella-3.9.3/src/emucore/MD5.cxx0000644000175000001440000002741612266336753015765 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 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. // // $Id: MD5.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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. */ // Setup the types used by the MD5 routines typedef unsigned char* POINTER; typedef uInt16 UINT2; typedef uInt32 UINT4; // MD5 context. typedef struct { UINT4 state[4]; /* state (ABCD) */ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ unsigned char buffer[64]; /* input buffer */ } MD5_CTX; // 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 unsigned char*, unsigned int); static void MD5Final(unsigned char[16], MD5_CTX*); static void MD5Transform(UINT4 [4], const unsigned char [64]); static void Encode(unsigned char*, UINT4*, unsigned int); static void Decode(UINT4*, const unsigned char*, unsigned int); static void MD5_memcpy(POINTER, POINTER, unsigned int); static void MD5_memset(POINTER, int, unsigned int); static unsigned char 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) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define GG(a, b, c, d, x, s, ac) { \ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define HH(a, b, c, d, x, s, ac) { \ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define II(a, b, c, d, x, s, ac) { \ (a) += I ((b), (c), (d)) + (x) + (UINT4)(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 unsigned char* input, unsigned int inputLen) { unsigned int i, index, partLen; /* Compute number of bytes mod 64 */ index = (unsigned int)((context->count[0] >> 3) & 0x3F); /* Update number of bits */ if ((context->count[0] += ((UINT4)inputLen << 3)) < ((UINT4)inputLen << 3)) context->count[1]++; context->count[1] += ((UINT4)inputLen >> 29); partLen = 64 - index; /* Transform as many times as possible. */ if (inputLen >= partLen) { MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)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 */ MD5_memcpy((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i); } // MD5 finalization. Ends an MD5 message-digest operation, writing the // the message digest and zeroizing the context. static void MD5Final(unsigned char digest[16], MD5_CTX* context) { unsigned char bits[8]; unsigned int index, padLen; /* Save number of bits */ Encode (bits, context->count, 8); /* Pad out to 56 mod 64. */ index = (unsigned int)((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. */ MD5_memset ((POINTER)context, 0, sizeof (*context)); } // MD5 basic transformation. Transforms state based on block. static void MD5Transform(UINT4 state[4], const unsigned char block[64]) { UINT4 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. */ MD5_memset ((POINTER)x, 0, sizeof (x)); } // Encodes input (UINT4) into output (unsigned char). Assumes len is // a multiple of 4. static void Encode(unsigned char* output, UINT4* input, unsigned int len) { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) { output[j] = (unsigned char)(input[i] & 0xff); output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); } } // Decodes input (unsigned char) into output (UINT4). Assumes len is // a multiple of 4. static void Decode(UINT4* output, const unsigned char* input, unsigned int len) { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); } // Note: Replace "for loop" with standard memcpy if possible. static void MD5_memcpy(POINTER output, POINTER input, unsigned int len) { unsigned int i; for (i = 0; i < len; i++) output[i] = input[i]; } // Note: Replace "for loop" with standard memset if possible. static void MD5_memset(POINTER output, int value, unsigned int len) { unsigned int i; for (i = 0; i < len; i++) ((char *)output)[i] = (char)value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string MD5(const uInt8* buffer, uInt32 length) { char hex[] = "0123456789abcdef"; MD5_CTX context; unsigned char 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 MD5(const FilesystemNode& node) { uInt8* image = 0; uInt32 size = 0; try { size = node.read(image); } catch(...) { return EmptyString; } const string& md5 = MD5(image, size); delete[] image; return md5; } stella-3.9.3/src/emucore/CartE0.hxx0000644000175000001440000001235712266336753016461 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: CartE0.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #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 @version $Id: CartE0.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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 uInt8* image, uInt32 size, const Settings& settings); /** Destructor */ virtual ~CartridgeE0(); public: /** Reset device to its power-on state */ void reset(); /** 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); /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank); /** Get the current bank. */ uInt16 bank() const; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const; /** 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); /** 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(int& size) const; /** 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; /** 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); /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const { 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) { 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); /** 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); 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]; }; #endif stella-3.9.3/src/emucore/Cart3E.cxx0000644000175000001440000002147012266336753016453 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: Cart3E.cxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #include #include #include "System.hxx" #include "TIA.hxx" #include "Cart3E.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3E::Cartridge3E(const uInt8* image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size) { // Allocate array for the ROM image myImage = new uInt8[mySize]; // Copy the ROM image into my buffer memcpy(myImage, image, mySize); createCodeAccessBase(mySize + 32768); // This cart can address a 1024 byte bank of RAM @ 0x1000 // However, it may not be addressable all the time (it may be swapped out) // so probably most of the time, the area will point to ROM instead registerRamArea(0x1000, 1024, 0x00, 0x400); // 1024 bytes RAM @ 0x1000 // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3E::~Cartridge3E() { delete[] myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3E::reset() { // Initialize RAM if(mySettings.getBool("ramrandom")) for(uInt32 i = 0; i < 32768; ++i) myRAM[i] = mySystem->randGenerator().next(); else memset(myRAM, 0, 32768); // We'll map the startup bank into the first segment upon reset bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3E::install(System& system) { mySystem = &system; uInt16 shift = mySystem->pageShift(); uInt16 mask = mySystem->pageMask(); // Make sure the system we're being installed in has a page size that'll work assert((0x1800 & mask) == 0); System::PageAccess access(0, 0, 0, this, System::PA_READWRITE); // Set the page accessing methods for the hot spots (for 100% emulation // we need to chain any accesses below 0x40 to the TIA. Our poke() method // does this via mySystem->tiaPoke(...), at least until we come up with a // cleaner way to do it). for(uInt32 i = 0x00; i < 0x40; i += (1 << shift)) mySystem->setPageAccess(i >> shift, access); // Setup the second segment to always point to the last ROM slice access.type = System::PA_READ; for(uInt32 j = 0x1800; j < 0x2000; j += (1 << shift)) { access.directPeekBase = &myImage[(mySize - 2048) + (j & 0x07FF)]; access.codeAccessBase = &myCodeAccessBase[(mySize - 2048) + (j & 0x07FF)]; mySystem->setPageAccess(j >> shift, 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); } // Pass the poke through to the TIA. In a real Atari, both the cart and the // TIA see the address lines, and both react accordingly. In Stella, each // 64-byte chunk of address space is "owned" by only one device. If we // don't chain the poke to the TIA, then the TIA can't see it... 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) < uInt32(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; uInt16 shift = mySystem->pageShift(); // Setup the page access methods for the current bank System::PageAccess access(0, 0, 0, this, System::PA_READ); // Map ROM image into the system for(uInt32 address = 0x1000; address < 0x1800; address += (1 << shift)) { access.directPeekBase = &myImage[offset + (address & 0x07FF)]; access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x07FF)]; mySystem->setPageAccess(address >> shift, access); } } else { bank -= 256; bank %= 32; myCurrentBank = bank + 256; uInt32 offset = bank << 10; uInt16 shift = mySystem->pageShift(); uInt32 address; // Setup the page access methods for the current bank System::PageAccess access(0, 0, 0, this, System::PA_READ); // Map read-port RAM image into the system for(address = 0x1000; address < 0x1400; address += (1 << shift)) { access.directPeekBase = &myRAM[offset + (address & 0x03FF)]; access.codeAccessBase = &myCodeAccessBase[mySize + offset + (address & 0x03FF)]; mySystem->setPageAccess(address >> shift, access); } access.directPeekBase = 0; access.type = System::PA_WRITE; // Map write-port RAM image into the system for(address = 0x1400; address < 0x1800; address += (1 << shift)) { access.directPokeBase = &myRAM[offset + (address & 0x03FF)]; access.codeAccessBase = &myCodeAccessBase[mySize + offset + (address & 0x03FF)]; mySystem->setPageAccess(address >> shift, access); } } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge3E::bank() 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(int& size) const { size = mySize; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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-3.9.3/src/emucore/KidVid.hxx0000644000175000001440000000623012266336753016546 0ustar stephenusers//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony // and 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: KidVid.hxx 2838 2014-01-17 23:34:03Z stephena $ //============================================================================ #ifndef KIDVID_HXX #define KIDVID_HXX #include #include "bspf.hxx" #include "Control.hxx" #include "Event.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 @version $Id: KidVid.hxx 2838 2014-01-17 23:34:03Z stephena $ */ 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); /** Destructor */ virtual ~KidVid(); public: /** Update the entire digital and analog pin state according to the events currently set. */ void update(); 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]; }; #endif stella-3.9.3/Copyright.txt0000644000175000001440000000721212266336753015127 0ustar stephenusers=========================================================================== SSSS tt lll lll SS SS tt ll ll SS tttttt eeee ll ll aaaa SSSS tt ee ee ll ll aa SS 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-2014 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-3.9.3/Changes.txt0000644000175000001440000034425612267025147014534 0ustar stephenusers=========================================================================== SSSS tt lll lll SS SS tt ll ll SS tttttt eeee ll ll aaaa SSSS tt ee ee ll ll aa SS 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 =========================================================================== 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. -Have fun! 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 comparitive 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-3.9.3/Announce.txt0000644000175000001440000000402312267025147014713 0ustar stephenusers=========================================================================== SSSS tt lll lll SS SS tt ll ll SS tttttt eeee ll ll aaaa SSSS tt ee ee ll ll aa SS 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 3.9.3 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 3.9.3 release of Stella for Linux, Mac OSX and Windows. The distributions currently available are: * Binaries for Windows XP/Vista/7/8 : Stella-3.9.3-win32.exe (32-bit EXE installer) Stella-3.9.3-x64.exe (64-bit EXE installer) Stella-3.9.3-windows.zip (32/64 bit versions) * Binary distribution for MacOS X 32-bit & 64-bit : Stella-3.9.3-macosx.dmg (32-bit Universal Binary) Stella-3.9.3_intel-macosx.dmg (32/64-bit Intel/OSX 10.6+) * Binary distribution in 32-bit & 64-bit Ubuntu DEB format : stella_3.9.3-1_i386.deb stella_3.9.3-1_amd64.deb * Binary distribution in 32-bit & 64-bit RPM format : stella-3.9.3-2.i386.rpm stella-3.9.3-2.x86_64.rpm * Source code distribution for all platforms : stella-3.9.3-src.tar.gz Distribution Site ================= The Stella distributions can be obtained from the Stella Website at: http://stella.sourceforge.net stella-3.9.3/Todo.txt0000644000175000001440000000147111677702424014062 0ustar stephenusers=========================================================================== SSSS tt lll lll SS SS tt ll ll SS tttttt eeee ll ll aaaa SSSS tt ee ee ll ll aa SS 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: http://stella.sf.net/todo.php If you would like to contribute to Stella's development then feel free to contact me by email: Stephen Anthony (stephena@users.sf.net). stella-3.9.3/debian/0000755000175000001440000000000012267274556013641 5ustar stephenusersstella-3.9.3/debian/rules0000755000175000001440000000266411405747625014724 0ustar stephenusers#!/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 --force-builtin-zlib 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-3.9.3/debian/docs0000644000175000001440000000015111335601441014467 0ustar stephenusersAnnounce.txt Changes.txt Copyright.txt README-SDL.txt Readme.txt docs/*.html doc/graphics/*.png Todo.txt stella-3.9.3/debian/copyright0000644000175000001440000000222211322244064015550 0ustar stephenusersThis 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-3.9.3/debian/changelog0000644000175000001440000001403012267025147015477 0ustar stephenusersstella (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-3.9.3/debian/watch0000644000175000001440000000007010663570271014656 0ustar stephenusersversion=3 http://sf.net/stella/stella-(.*)-src\.tar\.gz stella-3.9.3/debian/compat0000644000175000001440000000000210663570271015026 0ustar stephenusers5 stella-3.9.3/debian/dirs0000644000175000001440000000001010663570271014503 0ustar stephenusersusr/bin stella-3.9.3/debian/control0000644000175000001440000000112610663570271015233 0ustar stephenusersSource: stella Section: games Priority: optional Maintainer: Stephen Anthony Standards-Version: 3.7.2 Build-Depends: debhelper (>= 5.0.0), libsdl1.2-dev, zlib1g-dev Package: stella Architecture: any Depends: ${shlibs:Depends} Description: Atari 2600 Emulator for SDL & X windows 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: http://stella.sf.net/ stella-3.9.3/configure0000755000175000001440000004762612133534420014322 0ustar stephenusers#!/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 sdl-config) # * .... # use environment vars if set CXXFLAGS="$CXXFLAGS $CPPFLAGS" # default lib behaviour yes/no/auto _opengl=auto _libpng=auto _zlib=auto # default option behaviour yes/no _build_gl=yes _build_windowed=yes _build_sound=yes _build_debugger=yes _build_snapshot=yes _build_joystick=yes _build_cheats=yes _build_thumb=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 _win32path="" _windres=windres _sdlconfig=sdl-config _sdlpath="$PATH" _prefix=/usr/local X_LIBS="/usr/X11R6/lib" _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 $LDFLAGS -o $TMPO$EXEEXT $@" >> "$TMPLOG" rm -f "$TMPO$EXEEXT" ( $CXX "$TMPC" $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 class Foo { int a; }; int main(int argc, char **argv) { Foo *a = new Foo(); delete a; return 0; } EOF if test -n "$_host"; then # In cross-compiling mode, we cannot run the result eval "$1 $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 $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 sdl-config # # TODO: small bit of code to test sdl useability find_sdlconfig() { echo_n "Looking for sdl-config... " sdlconfigs="$_sdlconfig:sdl-config:sdl11-config:sdl12-config" _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 # # TODO: # * Change --disable-mad / --enable-mad to the way it's done in autoconf: # That is, --without-mad / --with-mad=/prefix/to/mad. Useful for people # who have Mad/Vorbis/ALSA installed in a non-standard locations. # 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-gl enable/disable OpenGL rendering support [enabled] --disable-gl --enable-windowed enable/disable windowed rendering modes [enabled] --disable-windowed --enable-sound enable/disable sound support [enabled] --disable-sound --enable-debugger enable/disable all debugger options [enabled] --disable-debugger --enable-joystick enable/disable joystick support [enabled] --disable-joystick --enable-cheats enable/disable cheatcode support [enabled] --disable-cheats --enable-thumb enable/disable Thumb ARM support [enabled] --disable-thumb --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] --force-builtin-zlib force use of built-in zlib library [auto] Optional Libraries: --with-sdl-prefix=DIR Prefix where the sdl-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) --x-libraries Path to X11 libraries [${X_LIBS}] 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-gl) _build_gl=yes ;; --disable-gl) _build_gl=no ;; --enable-windowed) _build_windowed=yes ;; --disable-windowed) _build_windowed=no ;; --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-thumb) _build_thumb=yes ;; --disable-thumb) _build_thumb=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 ;; --force-builtin-zlib) _zlib=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" ;; --x-libraries=*) arg=`echo $ac_option | cut -d '=' -f 2` X_LIBS="$arg" ;; --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; 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_gcc=no cc_check_define __GNUC__ && have_gcc=yes if 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 2.95.[2-9]|2.95.[2-9][-.]*|3.[0-9]|3.[0-9].[0-9]|3.[0-9].[0-9][-.]*|4.[0-9]|4.[0-9].[0-9]|4.[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 ;; # whacky beos version strings 2.9-beos-991026*|2.9-beos-000224*) _cxx_major=2 _cxx_minor=95 cxx_version="$cxx_version, ok" cxx_verc_fail=no ;; 3_4) _cxx_major=3 _mxx_minor=4 ;; 'not found') cxx_verc_fail=yes ;; *) cxx_version="$cxx_version, bad" cxx_verc_fail=yes ;; esac if test "$_cxx_major" -ge "3" ; then 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' fi; _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 2.95.x or GCC 3.x" #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 # linupy|arm-riscos-aof) # echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes" # DEFINES="$DEFINES -DUNIX" # _def_endianness='#define SCUMM_LITTLE_ENDIAN' # _def_align='#define SCUMM_NEED_ALIGNMENT' # _def_linupy="#define DLINUPY" # type_1_byte='char' # type_2_byte='short' # type_4_byte='int' # ;; # ppc-amigaos) # echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes" # _def_endianness='#define SCUMM_BIG_ENDIAN' # _def_align='#define SCUMM_NEED_ALIGNMENT' # type_1_byte='char' # type_2_byte='short' # type_4_byte='long' # CXXFLAGS="$CFLAGS -newlib -mstrict-align -mcpu=750 -mtune=7400" # LDFLAGS="$LDFLAGS -newlib" # ;; gp2x) echo "Cross-compiling to $_host, forcing static build, and disabling OpenGL." _build_static=yes _build_gl=no _build_windowed=no ;; mingw32-cross) echo "Cross-compiling for Win32 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.3 | sunos* | hpux* | beos*) DEFINES="$DEFINES -DUNIX" _host_os=unix ;; 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" _windres="$_host_prefix-$_windres" 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 echo "$_libpng" else echo "none found, using built-in version" fi # # Check for ZLib # echocheck "zlib" if test "$_zlib" = auto ; then _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 fi if test "$_zlib" = yes ; then echo "$_zlib" else echo "none found, using built-in version" fi # # Check for GL # echocheck "opengl" if test "$_opengl" = auto ; then _opengl=no cat > $TMPC << EOF #include #include #include int main(void) { return 0; } EOF cc_check $LDFLAGS $CXXFLAGS && _opengl=yes fi echo "$_opengl" # # 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_gl" = "yes" ; then if test "$_opengl" = "yes" ; then echo_n " OpenGL rendering enabled" echo else echo_n " OpenGL rendering disabled (missing OpenGL headers)" echo _build_gl=no fi else echo_n " OpenGL rendering 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_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_snapshot" = "yes" ; then echo_n " Snapshot support enabled" echo else echo_n " Snapshot 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_thumb" = yes ; then echo_n " Thumb ARM emulation support enabled" echo else echo_n " Thumb ARM emulation support 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" 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" 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 -DHAVE_INTTYPES" MODULES="$MODULES $SRC/unix" INCLUDES="$INCLUDES -I$SRC/unix" # # Check for X11 # _x11=no cat > $TMPC << EOF #include int main(void) { return 0; } EOF cc_check $LDFLAGS $CXXFLAGS -lX11 && _x11=yes if test "$_x11" = yes ; then DEFINES="$DEFINES -DHAVE_X11" LIBS="$LIBS -lX11" fi ;; win32) DEFINES="$DEFINES -DBSPF_WIN32 -DHAVE_GETTIMEOFDAY -DHAVE_INTTYPES" MODULES="$MODULES $SRC/win32" INCLUDES="$INCLUDES -I$SRC/win32" LIBS="$LIBS -lmingw32 -lwinmm" ;; gp2x) # -O3 hangs the GP2X, do not use. CXXFLAGS="-O2 -finline-functions -mtune=arm920t" DEFINES="$DEFINES -DBSPF_GP2X -DGP2X -DHAVE_GETTIMEOFDAY -DHAVE_INTTYPES" MODULES="$MODULES $SRC/gp2x" INCLUDES="$INCLUDES -I$SRC/gp2x $ZLIB_CFLAGS" _ranlib="arm-linux-ranlib" _ar="arm-linux-ar cru" ;; *) echo "WARNING: host system not currenty 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_gl" = yes ; then DEFINES="$DEFINES -DDISPLAY_OPENGL" 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_snapshot" = yes ; then DEFINES="$DEFINES -DSNAPSHOT_SUPPORT" 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_thumb" = yes ; then DEFINES="$DEFINES -DTHUMB_SUPPORT" 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 WIN32PATH=$_win32path STRIP := $_strip WINDRES := $_windres 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 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* stella-3.9.3/common.rules0000644000175000001440000000211611205247262014744 0ustar stephenusers# 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-3.9.3/License.txt0000644000175000001440000004311511205247262014527 0ustar stephenusers 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.