initial fce ultra 0.81 import
authornotaz <notasas@gmail.com>
Sat, 7 Apr 2007 13:46:21 +0000 (13:46 +0000)
committernotaz <notasas@gmail.com>
Sat, 7 Apr 2007 13:46:21 +0000 (13:46 +0000)
git-svn-id: file:///home/notaz/opt/svn/fceu@90 be3aeb3a-fb24-0410-a615-afba39da0efa

322 files changed:
Documentation/AUTHORS [new file with mode: 0644]
Documentation/COPYING [new file with mode: 0644]
Documentation/ChangeLog [new file with mode: 0644]
Documentation/FAQ [new file with mode: 0644]
Documentation/README [new file with mode: 0644]
Documentation/RELEASE-NOTES [new file with mode: 0644]
Documentation/TODO [new file with mode: 0644]
Documentation/cheat.txt [new file with mode: 0644]
Documentation/fcs.txt [new file with mode: 0644]
Documentation/porting.txt [new file with mode: 0644]
Documentation/rel/1.0 [new file with mode: 0644]
Documentation/rel/1.1.dos [new file with mode: 0644]
Documentation/rel/1.1.linux [new file with mode: 0644]
Documentation/rel/1.1.win [new file with mode: 0644]
Documentation/rel/2.0.dos [new file with mode: 0644]
Documentation/rel/2.0.linux [new file with mode: 0644]
Documentation/rel/2.0.win [new file with mode: 0644]
Documentation/rel/2.1.dos [new file with mode: 0644]
Documentation/rel/2.1.linux [new file with mode: 0644]
Documentation/rel/2.1.win [new file with mode: 0644]
Documentation/rel/3.0.dos [new file with mode: 0644]
Documentation/rel/3.0.linux [new file with mode: 0644]
Documentation/rel/3.0.win [new file with mode: 0644]
Documentation/rel/3.1 [new file with mode: 0644]
Documentation/rel/3.2 [new file with mode: 0644]
Documentation/rel/3.3 [new file with mode: 0644]
Documentation/rel/3.4 [new file with mode: 0644]
Documentation/rel/3.5 [new file with mode: 0644]
Documentation/rel/3.6 [new file with mode: 0644]
Documentation/rel/3.7 [new file with mode: 0644]
Documentation/rel/4.0 [new file with mode: 0644]
Documentation/rel/4.1 [new file with mode: 0644]
Documentation/rel/d [new file with mode: 0644]
Documentation/rel/da.sh [new file with mode: 0644]
Documentation/rel/new [new file with mode: 0644]
Documentation/rel/new.dos [new file with mode: 0644]
Documentation/rel/new.linux [new file with mode: 0644]
Documentation/rel/new.win [new file with mode: 0644]
Documentation/rel/readme-dos.txt [new file with mode: 0644]
Documentation/rel/readme-linux.txt [new file with mode: 0644]
Documentation/rel/readme-win.txt [new file with mode: 0644]
Documentation/rel/toc [new file with mode: 0644]
Documentation/rel/top.dos [new file with mode: 0644]
Documentation/rel/top.linux [new file with mode: 0644]
Documentation/rel/top.win [new file with mode: 0644]
Documentation/tech/README.now [new file with mode: 0644]
Documentation/tech/README.sound [new file with mode: 0644]
Documentation/tech/UNIF_current.txt [new file with mode: 0644]
Documentation/tech/cpu/4017.txt [new file with mode: 0644]
Documentation/tech/cpu/6502_cpu.txt [new file with mode: 0644]
Documentation/tech/cpu/NESSOUND.txt [new file with mode: 0644]
Documentation/tech/cpu/dmc.txt [new file with mode: 0644]
Documentation/tech/exp/mmc5-e.txt [new file with mode: 0644]
Documentation/tech/exp/mmc5_bank_switch.txt [new file with mode: 0644]
Documentation/tech/nsfspec.txt [new file with mode: 0644]
Documentation/tech/ppu/loopy1.txt [new file with mode: 0644]
Documentation/tech/ppu/loopy2.txt [new file with mode: 0644]
Documentation/tech/ppu/timing.txt [new file with mode: 0644]
Makefile.base [new file with mode: 0644]
Makefile.beos [new file with mode: 0644]
Makefile.common [new file with mode: 0644]
Makefile.dos [new file with mode: 0644]
Makefile.linuxvga [new file with mode: 0644]
Makefile.unixsdl [new file with mode: 0644]
Makefile.win [new file with mode: 0644]
banksw.h [new file with mode: 0644]
boards/Makefile [new file with mode: 0644]
boards/h2288.c [new file with mode: 0644]
boards/malee.c [new file with mode: 0644]
boards/mapinc.h [new file with mode: 0644]
boards/novel.c [new file with mode: 0644]
boards/sachen.c [new file with mode: 0644]
boards/simple.c [new file with mode: 0644]
boards/super24.c [new file with mode: 0644]
boards/supervision.c [new file with mode: 0644]
cart.c [new file with mode: 0644]
cart.h [new file with mode: 0644]
cheat.c [new file with mode: 0644]
cheat.h [new file with mode: 0644]
crc32.c [new file with mode: 0644]
crc32.h [new file with mode: 0644]
debug.c [new file with mode: 0644]
debug.h [new file with mode: 0644]
drawing.h [new file with mode: 0644]
driver.h [new file with mode: 0644]
drivers/cli/dface.h [new file with mode: 0644]
drivers/cli/dos-joystick.c [new file with mode: 0644]
drivers/cli/dos-joystick.h [new file with mode: 0644]
drivers/cli/dos-keyboard.c [new file with mode: 0644]
drivers/cli/dos-mouse.c [new file with mode: 0644]
drivers/cli/dos-sound.c [new file with mode: 0644]
drivers/cli/dos-sound.h [new file with mode: 0644]
drivers/cli/dos-video.c [new file with mode: 0644]
drivers/cli/dos-video.h [new file with mode: 0644]
drivers/cli/dos.c [new file with mode: 0644]
drivers/cli/dos.h [new file with mode: 0644]
drivers/cli/input.c [new file with mode: 0644]
drivers/cli/keyscan.h [new file with mode: 0644]
drivers/cli/lnx-joystick.c [new file with mode: 0644]
drivers/cli/lnx-joystick.h [new file with mode: 0644]
drivers/cli/main.c [new file with mode: 0644]
drivers/cli/main.h [new file with mode: 0644]
drivers/cli/sdl-joystick.c [new file with mode: 0644]
drivers/cli/sdl-netplay.c [new file with mode: 0644]
drivers/cli/sdl-netplay.h [new file with mode: 0644]
drivers/cli/sdl-sound.c [new file with mode: 0644]
drivers/cli/sdl-video.c [new file with mode: 0644]
drivers/cli/sdl-video.h [new file with mode: 0644]
drivers/cli/sdl.c [new file with mode: 0644]
drivers/cli/sdl.h [new file with mode: 0644]
drivers/cli/svga-video.c [new file with mode: 0644]
drivers/cli/svga-video.h [new file with mode: 0644]
drivers/cli/svgalib.c [new file with mode: 0644]
drivers/cli/svgalib.h [new file with mode: 0644]
drivers/cli/throttle.c [new file with mode: 0644]
drivers/cli/throttle.h [new file with mode: 0644]
drivers/cli/unix-basedir.h [new file with mode: 0644]
drivers/cli/unix-netplay.c [new file with mode: 0644]
drivers/cli/unix-netplay.h [new file with mode: 0644]
drivers/cli/usage.h [new file with mode: 0644]
drivers/cli/vgatweak.c [new file with mode: 0644]
drivers/common/args.c [new file with mode: 0644]
drivers/common/args.h [new file with mode: 0644]
drivers/common/cheat.c [new file with mode: 0644]
drivers/common/cheat.h [new file with mode: 0644]
drivers/common/config.c [new file with mode: 0644]
drivers/common/config.h [new file with mode: 0644]
drivers/common/unixdsp.c [new file with mode: 0644]
drivers/common/unixdsp.h [new file with mode: 0644]
drivers/common/vidblit.c [new file with mode: 0644]
drivers/common/vidblit.h [new file with mode: 0644]
drivers/win/cheat.c [new file with mode: 0644]
drivers/win/cheat.h [new file with mode: 0644]
drivers/win/common.h [new file with mode: 0644]
drivers/win/config.c [new file with mode: 0644]
drivers/win/input.c [new file with mode: 0644]
drivers/win/input.h [new file with mode: 0644]
drivers/win/joystick.c [new file with mode: 0644]
drivers/win/joystick.h [new file with mode: 0644]
drivers/win/keyboard.c [new file with mode: 0644]
drivers/win/keyboard.h [new file with mode: 0644]
drivers/win/keyscan.h [new file with mode: 0644]
drivers/win/main.c [new file with mode: 0644]
drivers/win/netplay.c [new file with mode: 0644]
drivers/win/res.res [new file with mode: 0644]
drivers/win/sound.c [new file with mode: 0644]
drivers/win/throttle.c [new file with mode: 0644]
drivers/win/video.c [new file with mode: 0644]
drivers/win/wave.c [new file with mode: 0644]
drivers/win/window.c [new file with mode: 0644]
endian.c [new file with mode: 0644]
endian.h [new file with mode: 0644]
fce.c [new file with mode: 0644]
fce.h [new file with mode: 0644]
fceline.h [new file with mode: 0644]
fds.c [new file with mode: 0644]
fds.h [new file with mode: 0644]
file.c [new file with mode: 0644]
file.h [new file with mode: 0644]
general.c [new file with mode: 0644]
general.h [new file with mode: 0644]
git.h [new file with mode: 0644]
ines.c [new file with mode: 0644]
ines.h [new file with mode: 0644]
input.c [new file with mode: 0644]
input.h [new file with mode: 0644]
input/Makefile [new file with mode: 0644]
input/arkanoid.c [new file with mode: 0644]
input/cursor.c [new file with mode: 0644]
input/fkb.c [new file with mode: 0644]
input/fkb.h [new file with mode: 0644]
input/powerpad.c [new file with mode: 0644]
input/shadow.c [new file with mode: 0644]
input/share.h [new file with mode: 0644]
input/zapper.c [new file with mode: 0644]
mappers/105.c [new file with mode: 0644]
mappers/112.c [new file with mode: 0644]
mappers/113.c [new file with mode: 0644]
mappers/117.c [new file with mode: 0644]
mappers/15.c [new file with mode: 0644]
mappers/151.c [new file with mode: 0644]
mappers/16.c [new file with mode: 0644]
mappers/17.c [new file with mode: 0644]
mappers/18.c [new file with mode: 0644]
mappers/180.c [new file with mode: 0644]
mappers/182.c [new file with mode: 0644]
mappers/184.c [new file with mode: 0644]
mappers/189.c [new file with mode: 0644]
mappers/19.c [new file with mode: 0644]
mappers/21.c [new file with mode: 0644]
mappers/22.c [new file with mode: 0644]
mappers/225.c [new file with mode: 0644]
mappers/226.c [new file with mode: 0644]
mappers/227.c [new file with mode: 0644]
mappers/228.c [new file with mode: 0644]
mappers/229.c [new file with mode: 0644]
mappers/23.c [new file with mode: 0644]
mappers/232.c [new file with mode: 0644]
mappers/234.c [new file with mode: 0644]
mappers/240.c [new file with mode: 0644]
mappers/242.c [new file with mode: 0644]
mappers/245.c [new file with mode: 0644]
mappers/246.c [new file with mode: 0644]
mappers/248.c [new file with mode: 0644]
mappers/249.c [new file with mode: 0644]
mappers/24and26.c [new file with mode: 0644]
mappers/25.c [new file with mode: 0644]
mappers/32.c [new file with mode: 0644]
mappers/33.c [new file with mode: 0644]
mappers/40.c [new file with mode: 0644]
mappers/41.c [new file with mode: 0644]
mappers/42.c [new file with mode: 0644]
mappers/43.c [new file with mode: 0644]
mappers/46.c [new file with mode: 0644]
mappers/51.c [new file with mode: 0644]
mappers/6.c [new file with mode: 0644]
mappers/64.c [new file with mode: 0644]
mappers/65.c [new file with mode: 0644]
mappers/67.c [new file with mode: 0644]
mappers/68.c [new file with mode: 0644]
mappers/69.c [new file with mode: 0644]
mappers/71.c [new file with mode: 0644]
mappers/72.c [new file with mode: 0644]
mappers/73.c [new file with mode: 0644]
mappers/75.c [new file with mode: 0644]
mappers/76.c [new file with mode: 0644]
mappers/77.c [new file with mode: 0644]
mappers/79.c [new file with mode: 0644]
mappers/8.c [new file with mode: 0644]
mappers/80.c [new file with mode: 0644]
mappers/82.c [new file with mode: 0644]
mappers/83.c [new file with mode: 0644]
mappers/85.c [new file with mode: 0644]
mappers/86.c [new file with mode: 0644]
mappers/88.c [new file with mode: 0644]
mappers/89.c [new file with mode: 0644]
mappers/90.c [new file with mode: 0644]
mappers/92.c [new file with mode: 0644]
mappers/95.c [new file with mode: 0644]
mappers/97.c [new file with mode: 0644]
mappers/99.c [new file with mode: 0644]
mappers/Makefile [new file with mode: 0644]
mappers/fmopl.c [new file with mode: 0644]
mappers/fmopl.h [new file with mode: 0644]
mappers/mapinc.h [new file with mode: 0644]
mappers/mapshare.h [new file with mode: 0644]
mappers/mmc2and4.c [new file with mode: 0644]
mappers/simple.c [new file with mode: 0644]
mappers/vrc7snd.c [new file with mode: 0644]
mbshare/Makefile [new file with mode: 0644]
mbshare/mapinc.h [new file with mode: 0644]
mbshare/mmc1.c [new file with mode: 0644]
mbshare/mmc3.c [new file with mode: 0644]
mbshare/mmc5.c [new file with mode: 0644]
memory.c [new file with mode: 0644]
memory.h [new file with mode: 0644]
netplay.c [new file with mode: 0644]
netplay.h [new file with mode: 0644]
nsf.c [new file with mode: 0644]
nsf.h [new file with mode: 0644]
nsfbgnew.h [new file with mode: 0644]
ops.h [new file with mode: 0644]
palette.h [new file with mode: 0644]
palettes/nsfnew.h [new file with mode: 0644]
palettes/rp2c04001.h [new file with mode: 0644]
palettes/vscv.h [new file with mode: 0644]
palettes/vseb.h [new file with mode: 0644]
palettes/vsgoonies.h [new file with mode: 0644]
palettes/vsgrad.h [new file with mode: 0644]
palettes/vsmar.h [new file with mode: 0644]
palettes/vsplatoon.h [new file with mode: 0644]
palettes/vsslalom.h [new file with mode: 0644]
palettes/vssmb.h [new file with mode: 0644]
sound.c [new file with mode: 0644]
sound.h [new file with mode: 0644]
state.c [new file with mode: 0644]
state.h [new file with mode: 0644]
svga.c [new file with mode: 0644]
svga.h [new file with mode: 0644]
types.h [new file with mode: 0644]
unif.c [new file with mode: 0644]
unif.h [new file with mode: 0644]
version.h [new file with mode: 0644]
video.c [new file with mode: 0644]
video.h [new file with mode: 0644]
x6502.c [new file with mode: 0644]
x6502.h [new file with mode: 0644]
zlib/ChangeLog [new file with mode: 0644]
zlib/Makefile [new file with mode: 0644]
zlib/adler32.c [new file with mode: 0644]
zlib/algorithm.txt [new file with mode: 0644]
zlib/compress.c [new file with mode: 0644]
zlib/crc32.c [new file with mode: 0644]
zlib/deflate.c [new file with mode: 0644]
zlib/deflate.h [new file with mode: 0644]
zlib/descrip.mms [new file with mode: 0644]
zlib/example.c [new file with mode: 0644]
zlib/faq [new file with mode: 0644]
zlib/gzio.c [new file with mode: 0644]
zlib/infblock.c [new file with mode: 0644]
zlib/infblock.h [new file with mode: 0644]
zlib/infcodes.c [new file with mode: 0644]
zlib/infcodes.h [new file with mode: 0644]
zlib/inffast.c [new file with mode: 0644]
zlib/inffast.h [new file with mode: 0644]
zlib/inffixed.h [new file with mode: 0644]
zlib/inflate.c [new file with mode: 0644]
zlib/inftrees.c [new file with mode: 0644]
zlib/inftrees.h [new file with mode: 0644]
zlib/infutil.c [new file with mode: 0644]
zlib/infutil.h [new file with mode: 0644]
zlib/maketree.c [new file with mode: 0644]
zlib/readme [new file with mode: 0644]
zlib/trees.c [new file with mode: 0644]
zlib/trees.h [new file with mode: 0644]
zlib/uncompr.c [new file with mode: 0644]
zlib/unzip.c [new file with mode: 0644]
zlib/unzip.h [new file with mode: 0644]
zlib/zconf.h [new file with mode: 0644]
zlib/zlib.h [new file with mode: 0644]
zlib/zutil.c [new file with mode: 0644]
zlib/zutil.h [new file with mode: 0644]

diff --git a/Documentation/AUTHORS b/Documentation/AUTHORS
new file mode 100644 (file)
index 0000000..c34fcae
--- /dev/null
@@ -0,0 +1,25 @@
+A list of people who have contributed code to FCE Ultra follows.
+Please note that the "Code Contributions" field may not be all inclusive;
+the coder may have done more than what is listed.
+
+Name/Alias     Code Contributions              Contact Information
+------------------------------------------------------------------------------
+Aaron Oneal    Many changes to compile         support@pocketgb.com
+               with MSVC and first frame
+               skipping code.
+
+Ben Parnell    Most of the FCE Ultra code.     xodnizel@users.sourceforge.net
+
+BERO           Base FCE code.                  bero@geocities.co.jp
+
+\Firebug\      VGA register setting code.      ??
+
+LULU           SDL network play code.          ??
+
+Paul           Various code for the official   kuliniew@purdue.edu
+ Kuliniewicz   SDL port.
+
+Quietust       VRC7 "translation" code.        quietust@ircN.org
+
+Tatsuyuki      OPL2 emulator.                  ??
+ Satoh
diff --git a/Documentation/COPYING b/Documentation/COPYING
new file mode 100644 (file)
index 0000000..afd5a94
--- /dev/null
@@ -0,0 +1,341 @@
+
+                   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.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+           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.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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-1307  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) year 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.
+
+  <signature of Ty Coon>, 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.
diff --git a/Documentation/ChangeLog b/Documentation/ChangeLog
new file mode 100644 (file)
index 0000000..9712202
--- /dev/null
@@ -0,0 +1,823 @@
+.81:
+----
+
+       More SDL goodies.
+
+       Renamed "Makefile.olinuxsdl" to "Makefile.unixsdl"
+
+       More SDL fixes and cleanups.
+
+       BeOS port is now compiled with the "-no-fpic" flag, which allows
+       me to use my inline assembly.  The executable work fine as far as
+       I can tell.
+
+       Added "Makefile.beos".  gcc doesn't like my inline assembly
+       used in RefreshLine(),so this port will likely be slightly slower than
+       other x86 ports.
+
+       Added a check to make sure SIGBUS is not equal to SIGSEGV in
+       drivers/cli/main.c.  Needed for compiling under BeOS.
+
+       Renamed the "PI" member of the X6502 structure due to conflicts with
+       a defined symbol with some math header files.
+
+       Merged fcelineasm.h into fceline.h
+
+       Fixed(possibly) a possible problem in fcelineasm.h with input register
+       clobbering.
+
+       More SDL changes.
+
+       Added speed throttling code to the CLI code, and added a command
+       line switch "-nothrottle".
+
+       Lots of restructuring/rewriting/merging of the MMC3 code.
+
+       Updated DOS code to use the generic CLI wrapper.
+
+       Reads from $4090 and $4092 now return the current envelope setting
+       in FDS sound emulation.  I'm not sure if this is correct...  Affects
+       "Ai Senshi Nicole" and "Bio Miracle Bokutte Upa".
+
+       Added native SDL sound support to the SDL code.  the "olinuxsdl"
+       now uses this code by default instead of the unixdsp sound code.
+
+        Modified MMC3 IRQ counter emulation.  I'll need to watch out to see
+        if it breaks any games.  Fixes:  MegaMan 3, Gun Nac, Klax(Japanese).
+
+       Changed a few memory reads in x6502.c to use RdRAM instead of RdMem,
+       resulting in a slight speed increase.
+
+       Cleaned up mapper 250 emulation code.
+
+       Added support for iNES mapper 51(thanks to Kevin Horton for the
+       information).
+
+       Merged some iNES mappers corresponding to bootleg multicarts
+       based on MMC3s with mbshare/mmc3.c.
+
+       Added support for iNES mapper 52(thanks to Kevin Horton for the
+        information).
+
+       Made some hacks to the MMC3 emulation code so that I can add support
+       for pirate MMC3 multicarts more easily.  I should clean it up later.
+       Moved mapper 44 emulation code to mbshare/mmc3.c.
+
+       Saving screen snapshots will no longer corrupt the frame buffer
+       for one frame(unless memory couldn't be allocated).
+
+       Fixed screen snapshot saving(it was sort of broken due to the
+       changes made to the driver<->emulator interface code; status
+       messages were being saved to the image).  FCEUI_SaveSnapshot()
+       no longer returns a value(the request to save a screen snapshot is
+       serviced before status information would be written in the next frame).
+
+       nosprites is now set to 0 before RefreshSprite() returns, to prevent
+       problems if a game turns off the bg and sprites when FetchSpriteData()
+       for the next scanline is called but then turns on sprites when
+       the actual scanline is drawn.
+
+       PPU_hook() is now called more often if PPU_hook is non-null.
+       Made changes to mappers 118, 95, 9, and 10 to compensate.
+       No games seem to be broken, and I added support for mapper 96
+       (though the games aren't very playable because the special controller
+       isn't emulated).
+
+       Romance of the 3 Kingdoms is now recognized to use 16KB ex-WRAM.
+
+       Added support for mapper 185...sort of.  I think this is another
+       instance of incompatible hardware being lumped onto one mapper number.
+       Sigh.
+
+       Added support for "Famicom Jump 2" as iNES mapper 153.
+       If a good(as far as I can tell) dump is loaded, FCE Ultra will
+       automatically fix the mapper number.
+       I also made some changes to the mapper 16 IRQ emulation code.
+
+       BRK now sets the I flag.
+
+       Reads from $4015 no longer reset DPCM IRQ.
+
+       Changed emulation of RTI instruction slightly.
+
+       X.IRQlow is now set to 0 in PowerNES().
+
+       The VS Unisystem bit in the iNES header is no longer looked at(
+       I was having too many problems with this bit being set when it
+       shouldn't have been).  Now, VS Unisystem emulation is enabled
+       when a known VS Unisystem game is loaded.  I also rewrote the VS 
+       Unisystem detection function.
+
+       iNES mapper 1 now supports pageable CHR RAM if no CHR ROM is present.
+       Fixes "Family School".
+
+       Mapper 70 no longer has a mirroring control emulated, and I extended
+       the number of 8KB CHR pages supported to 16.
+
+       Cleaned up iNES MMC5 save RAM loading/saving code and added
+       support for MMC1 games with 16KB of RAM(the second 8KB are saved),
+       via CRC32s(currently only Genghis Khan(USA) and Nobunaga's Ambition(
+       USA and Japan) are recognized).
+
+       Added support for the MMC5 Koei game "Ishin no Arashi", in the iNES
+       format(I added an entry with its CRC32 value and the number of 8KB
+       WRAM banks it needs). 
+
+       Better iNES mapper 33/48 IRQ counter emulation.
+
+       Added the game "Uchuusen - Cosmo Carrier" to this list.  I'm
+       beginning to hate the iNES format more and more...or maybe
+       just Fanwen. :)
+
+       Added the mapper 32 game "Major League" to the list of games
+       that usually need iNES header correction...but in this case, the
+       iNES header cannot specify that this game needs to have one-screen
+       mirroring.
+
+       iNES header information is now printed before any header corrections
+       are made based on a database.
+
+       Fixed a bug in mapper 32 emulation.  "Ai Sensei no Oshiete"
+       works now.
+
+       Tried to add support for iNES mappers 245 and 249.
+
+       Fixed the MMC5 read handler to return the data last on the data
+       bus instead of 0xFF when a read was made to an unmapped address.
+       This seems to fix the lockup problems in "Bandit Kings of Ancient
+       China".
+
+       Reversed "Modified the time at which the "y scroll" register is updated
+        during hblank."  The changes broke Klax.
+
+       Added an unsigned 64-bit base timestamp variable "timestampbase".
+       Adding this to the 32-bit variable "timestamp" will return
+       the number of cycles executed since emulation started(in the future
+       I'll probably change it to since reset or power toggle).
+       This allowed me to replace "lastn" hack in the MMC1 code with
+       something better.
+
+       Changed my mind and undid the removal of support for old save states.
+
+       Removed support for old save states and in general I won't
+       try to support save states made with previous versions.
+
+       MMC1:  Writes to $8000-$FFFF with D7 set will now cause
+       the first MMC1 register to be OR'ed with 0x0C.  I'm not sure
+       if this is correct, but it doesn't seem to break anything
+       and it fixes Robocop 3.  I'll see if anyone reports games
+       not working in .81 that worked in .80.
+       
+       Worked on a generic driver interface wrapper very similar
+       to the driver interface FCE Ultra used to use(I'm getting
+       tired of all of the duplicated driver code).  Eventually,
+       the DOS, SVGAlib, and SDL ports will use this wrapper.
+
+       Similar change to the argument parsing code.
+
+       Changed configuration file saving-loading routines and the
+       configuration structure to allow for linking config structures
+       to each other).
+
+       Small fix to the emulation of the MMC5 split screen mode.
+
+       Made Linux SDL code compilable again.
+
+       Changes to MMC5 EXRAM emulation(read/write).
+
+       Fixes to the emulation of the MMC5's split screen mode, based on
+       observations while using CastleVania 3 and a Game Genie(on a real
+       NES).
+
+       Fixed a bug in ines.c that caused any calls to AddExState() from
+       a mapper initialization function to be effectively "erased"(ResetExState()
+       was called after the mapper was initialized).  Fixes the VRC7 sound 
+       state saving/loading stuff.
+
+       Finished adding support for the MMC5's split screen mode(this does
+       not mean that the support is complete, but at least the intro in
+       "Uchuu Keibitai SDF" works correctly now).
+
+       Worked on adding support for the MMC5's split screen mode.  Not
+       completed.
+
+       Reverted to .80's FDS sound code.
+
+       Modified the time at which the "y scroll" register is updated
+       during hblank.
+
+       NSF playing code will now disable FDS sound output on song init
+       (fixes some problems with the Zelda no Densetsu NSF rip).
+
+       Increased the emulated clock speed of the FDS sound emulation code
+       to give better quality output.
+
+       Modified NMI to occur a few cycles later.  Fixes BattleToads...but
+       it may have broken other games.  Also modified the way NMI's are
+       handled in x6502.c.
+
+       Modified ines.c to memset() GameMemBlock to 0 on virtual power toggle.
+       Also, trainers are now loaded into their own buffer instead of
+       directly into emulated WRAM and copied into emulated WRAM on
+       power toggle; I've been meaning to do this for quite some time.
+
+       Changes to the way the zapper cursor is drawn on the screen.
+
+       FCEUD_WriteSoundData(), FCEUD_BlitScreen(), and FCEUD_UpdateInput()
+       have been combined into one function: FCEUD_Update().
+
+       More fixes to the network play code, and a fix to the Windows network
+       play driver code that fixes(hopefully) a rather evil bug that caused
+       lockups when the remote stopped network play.
+
+       Added code to set the battery-backed bit in RAM if a game needs it,
+       based on CRC32.
+
+       Added more games to the list of games that commonly have bad iNES
+       headers, in ines.c
+
+       Updated docs and usage.h for DOS and Linux regarding the new video
+       mode and the new refresh rates.
+
+       Linux:  Fixed a bug with video mode 6(a few upper scanlines were being
+       cut off).  Increased the refresh rate of video mode 3 to 120hz.
+
+       Increased the refresh rate of video mode 2 to 65 hz in the Linux port.
+
+       Screen snapshots can now be taken while playing an NSF.
+       
+       Added a new sexy tweaked vga mode that I created to the Linux svgalib 
+       port.  It's 256x224 at a refresh rate of 103hz.  Hopefully it won't
+       blow up anyone's monitor. ;)
+       DOS port will follow eventually.
+
+       Modified Makefile.base to produce an executable named "fceu" instead
+       of "fce".
+
+       The plans(cycle-accurate ppu emulation) for .90 were a bit ambitious, 
+       and I still need to make other fixes before then.
+
+       Fixed some minor(usually) bugs with setting 256x240 tweaked VGA mode
+       in DOS and Linux ports.
+
+.80:
+----
+
+       Cleaned/fixed a few things in the mapper 19 emulation code.
+       Family Circuit '91 still doesn't work quite right...  I wonder if
+       it's a bad dump.
+
+       Added input override code to Windows port.
+
+       Added code to fix iNES header information in RAM and suggest
+       changes to the user.
+
+       Added support for iNES mapper 152(to be used with games set to 
+       mapper 70, that use one-screen mirroring instead of h/v mirroring).
+
+       Blits using the DirectX blitting function(method?) to the primary
+       surface are now done with the asynchronous flag set(if that
+       fails, a "normal" blit is tried).
+       
+       The DirectX blit buffer(secondary surface that FCE Ultra writes to
+       directly and then uses the DirectDraw blit function on to blit
+       to the primary buffer) is now created without specifying it
+       should be in system memory or video memory, except in the case
+       when no hardware blitting is available, and then DDraw is explicitly
+       told to create the surface in system memory.
+
+       Added Family Keyboard support to the DOS port.
+
+       Cleaned up the VRC7 sound emulation code.  I need to find a way
+       to save the current sound state in a save state.
+
+       Found out the real name of the "Space Shadow" gun; it's
+       called the "Hyper Shot".  I'm still not sure who made it, though.
+       Possibly Bandai did.  The interesting thing is that Konami
+       also made a Famicom accessory(dual square boxy things with two buttons
+       on each) with the same name(though there might not be a space in the
+       name).
+
+       Only the upper two bits read from $4016/$4017 are undefined.
+        Bit5 is always 0, though.  Fixed the bug in "input.c".
+       Silly kevtris' old documents.  New kevtris' brain is always good.
+
+       Family Keyboard support for the Windows port.
+
+       Added support for the Family Basic Keyboard to the Linux port, other
+       ports todo.
+       Might want to add support for the tape recorder at some time.
+       Also mapped the "Scroll Lock" key to disable/enable command keys
+       so that the FBK is more useable.  It doesn't disable CTRL C, 
+       though...
+
+       Changed a lot of inlined functions in x6502.c to macros so that
+       I could test out some optimization ideas.
+
+       DOS code updates for game input override support.
+
+       Small optimzation to opcode $4c, and relative jumps.
+
+       Added some code to ines.c to set controller information in 
+       FCEUGameInfo(returned by FCEUI_LoadGame()) based on crc32 values.
+
+       Updated user documentation and usage.h for DOS and SVGAlib input 
+       command-line changes.
+
+       Added an option to disable the four-score(to Windows and Linux ports
+       so far).
+
+       Updated Windows interface to support the new Famicom expansion
+       devices.
+
+       (Re)Added support for the Famicom 4-player device.
+
+       Improved Zapper emulation...sort of.  It still needs a lot of work. :/
+
+       Added *partial* support for the "Space Shadow" gun.
+
+       Added support for the Arkanoid controller(both NES and Famicom style).  
+
+       Added code to support the extension Famicom input devices.
+
+       Added PAL scanline start/end drawing settings to Windows port.
+
+       Added pause emulation key(F2) to Windows port.
+       
+       In the process of rewriting/fixing up input code stuff.
+
+       Minor bug fix to Power Pad emulation code.
+
+       VS Hogan's Alley and VS Duck Hunt automatically select the zapper
+       now(though it only works on the SVGAlib port).
+
+       Undid some FDS sound code changes introduced in 0.76 that totally
+       screwed up sound.  Oops.
+
+       Added code to allow different settings for first/last scanline
+       drawn while in PAL emulation mode, to the Linux and DOS ports.
+
+       Added convenience(it's not necessary, but it reduces redundant and
+       confusing code in the driver code) function 
+       FCEUI_GetCurrentVidSystem(int *slstart, int *slend).
+
+       Updated file "TODO".
+
+       Changed #include <unzip.h> to #include "zlib/unzip.h"
+       in file.c.
+
+       NSF 6502 player now initialized the stack pointer on reset.
+
+       Worked on de-emphasis emulation code quite a bit.  
+       The deemphasized palette calculated at the end of the frame is now
+       based on what deemphasis bits were set for the longest during
+       the screen(sampling interval is a scanline) update loop.
+       Added a "static" deemphasized palette at $40-$7F in the palette table.
+       This corresponds to the colors when all of the deemphasis bits are set.
+       I did this to fix the PAL game "Noah's Ark", without breaking
+       anything else.  The only downside is a slight speed loss(~2% on
+       my system when sound is disabled), but this is acceptable to me,
+       at least.
+       Maybe it's time to write hi/true-color ppu drawing code...
+
+
+       Fixed an out of bounds array access in svga.c in SetNESDeemph().
+       The variable "lastd" in svga.c was being initialized to the wrong value.
+       Thanks to "Jarod CANAL" for pointing this out.
+
+       Removed FCEUI_SetFirstRenderedLine or whatever it was called and
+       the function to set the last line.  Replaced with:
+        void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall);
+
+       Changed SetVidSys(int w) to ResetVidSys() in fce.c.  Reenabled
+       PAL/NTSC emulation overrides based on game loaded(really only useful
+       for NSFs and UNIFs now).  
+
+       UNIF loading code now recognizes the chunk "CTRL" and tries
+       to use it.  Only the svgalib code supports overriding of input
+       settings based on game loaded, now, though...
+       The user is still going to have to configure powerpad settings
+       on his/her own.
+
+       Fixed return values of FCEU_fseek() and fixed a problem in unif.c
+       related to it.
+
+       Changed mechanism for how FCE Ultra tells the driver
+       code what type of system is being emulated.  A structure of
+       type "FCEUGI" is returned from FCEUI_LoadGame().
+
+       Fixed a major mapper 64 emulation bug introduced in 0.76.
+
+       Modified BlitVidHi() in drivers/win/video.c to speed it up.
+
+       Added support for loading the iNES-format Game Genie ROM image.
+
+       Removed ggrom.h and added code to load the Game Genie ROM
+       image from a file.
+
+       Added Windows netplay.c.  (new: the user exiting the emulator
+       while stuck in a blocking recv() or send() loop now works.)
+
+       Fixed a vram address register bug in fce.c that I created when I got 
+       rid of the pair/dpair data types.
+
+       Added new mappers/92.c
+
+       Removed mappers/92.c until I can contact LULU or rewrite it.
+
+       drivers/win changes.  Removed netplay.c until I can rewrite it.
+
+       Got rid of pair/dpair data types.
+
+       Got rid of silly "TempArray" thing.
+
+       Began adding GPL headers to files.  FCE Ultra is going to be in
+       a state of legal limbo for the next few days...
+
+       Replaced crc32.c and crc32.h, and added some #ifdef's and #defines
+       to use the crc32 code in zlib instead if zlib is linked with
+       FCE Ultra.
+
+       More fixes to sb.c.
+
+       Cleaned up drawing.h and ggrom.h(even though ggrom.h will *probably*
+       be removed before the next release).
+
+       Redid frameskip code.
+
+       Rewrote necessary pieces of sb.c and sb.h and fixed quite a few
+       bugs.  I still need to test it on various other sound cards, though.
+
+       Rewrote(more like "recreated in my own image") DOS keyboard driver.
+       Removed unused "keyscan.h" from drivers/svgalib
+
+       Rewrote part of(the parts that Marat wrote - the connection and
+       closing parts) the Linux TCP/IP network play code.  I guess it works, 
+       but I haven't tested it very much.  In any case, it's still dangerous
+       to use network play in FCE Ultra with SVGAlib, since recv() or send() 
+       might block and since the keyboard is in raw mode, you have a problem.
+       Maybe a future SVGAlib will fix the general problem of lockups if
+       keyboard_update() isn't called, though it is only partly SVGAlib's 
+       problem...
+
+       Fixed FCEU_fseek() when used with a compressed file in the PKZIP
+       format that has been loaded.  Fixes a UNIF loading problem.
+       Also added a check to the return value of FCEU_fseek() in unif.c.
+
+       Replaced Marat's 6502 emulation core with my own.  
+       It should be fully functional, but as always, I don't know if
+       I implemented the undocumented instructions correctly.
+       Several things are correct in this new core that were not in
+       Marat's(D flag is no longer cleared by interrupts, for example).
+
+       Altered mapper 16 irq counter emulation slightly.
+
+       Fixed the behavior of the SXA, SYA, and XAS opcodes based on the
+       documentation I have.  I'm not sure what happens when page crossing
+       occurs with those instructions on a real NES, though.
+       Also CHANGED(not fixed) emulation of opcode $8B("XAA").
+
+       Changed some of the M* functions(absolute indexed and maybe some others)
+       to perform dummy reads.
+
+       Changed some of the macros in m6502.c to inlined functions so
+       that I can modify and examine them more easily.
+
+.77:
+----
+
+       Fixed a silly network play bug(in the global network play code)
+       that caused excessive lag.
+
+       Added a "niceness" setting to the sound configuration dialog.
+       Removed obsolete information from the dialog.
+
+       Fixed speed throttling code in Windows port when PAL emulation is
+       disabled/enabled and a new game hasn't been loaded yet.
+
+       Commented out a printf() to debug stuff in fds.c(oops).
+
+       Applied PK's joystick patch to the osdl code.  It allows the user
+       to map axes and it fixes a joystick button mapping configuration saving
+       bug.
+
+       Added two command line options new to Linux port to DOS port.
+       Just need to test them...
+
+       Added some stuff to unif.c to allow for boards that can support
+       CHR RAM instead of CHR ROM(darn Sachen boards...).  Fixes UNIF
+       version of "Q-Boy". 
+
+       Added command line option "-snapname" to Linux port.  I'll add it
+       to the Windows port as well, but probably not to the DOS port.
+
+       Added clip option to Linux port.
+
+       Fixed sound logging(in Windows port) so that multiple recording
+       sessions now work.
+
+       Added an option to clip the leftmost and rightmost 8 columns
+       of graphics in the Windows port.
+
+       Added a submenu that lists recently opened files, in the Windows
+       port.
+               
+.76:
+----   
+
+       Updated porting.txt.
+
+       Added speed throttling code to Windows port that's used when sound is
+       disabled(and an option in the "Miscellaneous" 
+       configuration window to disable it).
+
+       Added cheat interface to DOS build.  
+
+       A few tweaks to the text cheat interface code in the cheat listing code.
+       Added a command to quickly toggle the status of the cheat(though a 
+       cheat can still be disabled/enabled by (M)odifying the cheat).
+
+       Support for UNIF UNL-TC-U01-1.5M board added. Same credits as below.
+
+       Rewrote mapper 228 code just for the heck of it(actually, I couldn't
+       figure out why some(about two) of the games in the Action 52 cart 
+       weren't working in .75(and .76).  I traced it back to .71, where an apparent bug in
+       the undocumented 6502 opcode emulation allowed it to work, which
+       was later fixed for the .72 release(opcode 0x7C)).  I'm thinking        
+       that the dump is bad...
+
+       Added a few crc32 checks to ines.c to check for and report when
+       a known(by me) bad(hacked or bad dump) game is loaded.
+
+       Added support for the following UNIF boards.  Thanks to Quietust
+       and Kevin Horton for the information.  Some problems still exist
+       with a few games that use these boards, though...
+
+               UNL-Sachen-8259B
+               UNL-Sachen-8259A
+               UNL-Sachen-74LS374N
+               UNL-SA-016-1M
+               UNL-SA-72007
+               UNL-SA-72008
+               UNL-SA-0036
+               UNL-SA-0037
+
+       Fixes to some stuff in cart.c(for example, calling setprg32() when 
+       only 16kb of prg data is present now works).
+
+       Added support for iNES mapper 189.
+
+       Tried to add support for the UNIF board "UNL-H2288".  Failed.
+
+       Updated "cheat.txt" to fix a few typos and added an example of finding
+       and adding a cheat using the Linux port's text interface.  The actual
+       section on the Linux cheat interface still needs to be written, however.
+
+       Changed network play code in the Windows port and fixed a bug.
+       Fixed a similar bug in the Linux netplay code....sort of.
+
+       A few cosmetic changes to the dialogs in the Windows port.
+
+       Fixed sound initialization on the Windows port(it was being initialized
+       when FCE Ultra started even if it was disabled by the user.  Oops.).
+
+       Joystick button configuration code in Windows port changed slightly
+       to be more useable.
+
+       Changed reference to video mode 5 in the linux port to "1 per 4".
+       It may not be very meaningful, but it is certainly better
+       than "TV Emulation".  I'll change the Windows port reference later.
+
+       Documented video mode 7(320x240) for the Linux port.  Also added
+       a check for the FBDev driver in order to use this mode instead
+       of a tweaked vga mode if that driver is being used.
+
+       Added/Fixed cheat interface for Linux port.  It's still not perfect,
+       though.  The code is ugly...
+
+       Callback function for FCEUI_ListCheats() now receives
+       status information(enabled/disabled).
+
+       Callback functions for cheat functions now must return 0 to
+       stop listing cheats or 1 to continue.  
+
+       Fixed a problem(the cheat code was reading in cheats
+       for address $0000 from cheat files if any blank lines were present).
+
+       SDL port zlib changes(linked dynamically to zlib now).
+
+       More changes to envelope decay + looping on code.  No longer
+       depends on value @ $4017.  It now sounds correct based on some
+       tests I did with SMB3 and a GG, but Goonies 2 doesn't sound right(
+       based on a sound file sent to me by another person).
+
+       Added support for iNES mapper 140.  Thanks to Quietust for the
+       information.
+
+       I need to figure out how to deal with the problem of so many
+       bad NSFs that most people consider good...
+
+       Changed envelope decays a bit.  Their behavior now depends on bit
+       7 of $4017.  I don't know if this is right...
+
+       Addition of debug.c for some debugging stuff.
+
+       Updated zlib to 1.1.4.
+
+       Modified code in various files to allow UNIF games to override
+       current selected video system emulation(NTSC or PAL).  Need to
+       make sure this really works.
+
+       Changed sound.c to prevent desynchronization during network play.
+       This might slow down sound emulation slightly, especially when
+       sound emulation is disabled.  I really don't care...
+
+       Updating network play code.  More info later...
+
+       Moved the sound/video/etc output code in EmLoop() to the top of the
+       for(;;) loop so that initialization prior to calling EmLoop() will
+       be the same as initialization done during a call to a FCEUD_* function.
+
+       A few very small changes to sound emulation in fds.c.
+
+       Changed unlink() to remove() in cheat.c and removed the including
+       of the header file unistd.h.
+
+       Split up the cc=... statement in RefreshLine() to make it easier
+       to read and not ambiguous(to Borland's C compiler).
+
+       Changed a lot of the function declarations in cheat.c.  I'll need
+       to verify that cheat searching still works ok and that cheats still work
+       ok.  I'll also need to update the Windows(and Linux console) cheat code
+       to prevent compiler warnings.
+
+       Fixed various minor code problems(not minor if you want to use a
+       compiler besides gcc).   This is an ongoing process...  
+
+       Removed bit fields after reading about and thinking about possible
+       portability problems, though I kept some optimizations in fceline.h
+
+       Minor code simplification in drivers/win/joystick.c(replaced
+       "case 200 ... 207" and "case 208 ... 215".
+
+       Modified some code to use bit-fields in the graphics rendering code 
+       in fce.c and fceline.h.  gcc seems to be able to optimize the new
+       code to run faster.
+
+       Fixed m6502.c and fce.c to initialize variables on virtual power
+       toggle.  This should fix network play on the Windows port.
+       I'm also in the process of cleaning up fce.c. 
+
+.75:
+----
+       Fixed directories configuration stuff in Windows port(corresponds
+       to .75r2).
+
+       More changes to square wave channel envelope/volume emulation...
+       Changes described in the large paragraph some lines down have been
+       abandoned.
+
+       Added a command line switch to set the volume in the dos port.
+
+       Changed Windows sound configuration dialog.  Now buffer length is
+       specified in time, not samples.  I also added a volume control.
+
+       Reduced the volume on 8-bit sound output on all ports by 1/2.
+
+       Added a function FCEUI_SetSoundVolume().  Added support for setting
+       the volume via the command line in the Linux port, other ports coming
+       soon.
+
+       Changed FCEUD_WriteSoundData() again.  No longer has a "Check"
+       argument.  All clipping(ugh) is done internally now.
+
+       Added a directories configuration dialog to the Windows port.  I worked
+       on it too long and I became a zombie, so it might have a few bugs.
+       That's what guine...err...users are for. ;)  Don't expect me to do
+       anything like this for any other port, though.  I don't feel like
+       doing it on the DOS port, and the Linux and other UNIXy ports shouldn't
+       really need it.
+
+       Made some changes to the rectangle/square wave channel emulation to
+       fix the pops in SMB.  I have no idea if what I did is correct.  To
+       be honest, I'm not sure I know EXACTLY what I did, but it's something
+       like this:  Writes to $4003/$4007 now reset the duty cycle count
+       and reload the cycle counter with the current wavelength.  Writes to
+       $4003/$4007 now do not update the amplitude output of the channels; they
+       will be updated after the cycle counter hits 0(or below).
+
+       More information in iNES informational output.
+       
+       Minor changes to mappers/16.c.
+
+       Increased the volume of the VRC6's sawtooth wave channel.
+
+       Added more information to the RAM cheat guide.
+
+       Changed the triangle wave generation code slightly.  I decided
+       to remove support for the higher-frequency triangle waves, as they
+       are too cpu-costly to create and are probably not very audible on a 
+       real NES anyway.
+
+       Major changes to how sound is mixed.  This necessitated a high pass
+       DC-offset removing filter, and a low-pass filter just to make things
+       sound better. ^_^ 
+       Note:  FCEUD_WriteSoundData() no longer needs to clear the waveform
+       data referenced by the passed pointer; it's done internally now.
+
+       Fixed JMP ($xxxx) - now handles wrapping like it occurs on a real 6502
+       (hopefully; I'm assuming that the same holds true for the NES' cpu).
+
+       Added the ability to load a custom global palette in the DOS port.
+
+       Fixed bug in drivers/common/unixdsp.c(wrong return value if sample
+       rate was out of range).
+
+       Many sound fixes...     - Frequency sweeps, length counter stuff,...
+
+       Changed Windows port to use IDirectInput7 and IDirectInputDevice7
+       interfaces.
+
+       Fixed a Game Genie bug in the core emulation code.  It only appeared 
+       in the Windows port, though.  (Enabling gg emulation, loading a game,
+       and then disabling gg emulation and loading a new game while in the
+       gg code entry screen would cause the new loaded game to not work
+       correctly).
+
+       Modified windows port to use the config saving/loading stuff in
+       drivers/common/config.c
+
+       Mapper 45 cleanups/fixes.
+
+       Added the ability to load a custom global palette in the Linux port.
+       Yay.
+
+       Fixed a large number of overcomplicated code and silly bugs in
+       drivers/common/config.c.  This changes the format of the configuration
+       structure, too.  Also added support for saving/loading strings with
+       automatic memory allocation when strings are loaded.
+
+       Minor change in InitNetplay().
+
+       Fixed bad type conversions for pointers to functions and fixed
+       some bad declarations of functions.
+
+       Reenabled zlib support for the sdl build.  I need to pay attention
+       to patches that modify lines than don't fit on my screen.
+
+       Fixed vidblit.c to not emit so many warnings when compiling.
+
+.74:
+----
+
+       Stop sound in Windows port when user clicks l/m/r mouse buttons
+       in the non-client area of the window.
+
+       Added "Drag and drop" file open support to Windows port.
+
+       Various code cleanups.
+
+       mappers/33.c optimization.
+
+       Rewrote the function "FCEU_MakeFName()".
+
+       Removed crc32.h from mappers directory.
+
+       Modified some of the window resizing code in the Windows port.
+
+       Added support for waiting for vblank/double buffering to the Windows
+       port.
+
+       Added/Fixed support for iNES mapper 248.
+
+       After an NSF file is loaded, information about its header is now
+       displayed.
+
+       Fixed a typo in the Namco 106 extra ram handling code. 
+
+       Improved the quality of the Namco 106's extra sound channels. 
+       - Thank Mamiya and Applepie(real name?) for info.
+
+       When an NSF file is being played, FCE Ultra will no longer go through
+       its scanline rendering loop.  This speeds up NSF playback considerably. 
+
+       Updated "porting.txt".
+
+       Moved some stuff from DriverInterface() to their own functions.
+
+       Fixed some iNES mapper 18 IRQ counter emulation bugs.  "Ninja Jajamaru -
+       Ginga Dai Sakusen" now works.
+
+       Rewrote large pieces of the mapper 64 code.  "Skull and Crossbones" 
+       still doesn't work, though.
+
+       Changed format of iNES header information output, added "ROM CRC32" info.       
+
+       Modified the way cycle timing is done slightly.  No change
+        for NTSC emulation, but PAL emulation is a little more accurate.
+
+       Changed the behavior of indirect indexed(I hope I got that right ;))
+       instructions to behave more like a real 6502(junk reads are now 
+       performed).
+
+       A few optimizations/cleanups in m6502.c.
diff --git a/Documentation/FAQ b/Documentation/FAQ
new file mode 100644 (file)
index 0000000..0ce51b5
--- /dev/null
@@ -0,0 +1,45 @@
+FCE Ultra General User's FAQ
+ preliminary version
+------------------
+
+
+Q: Why doesn't the NSF <insert name here> work(correctly) on FCE Ultra?
+A: Some NSF rips are bad.  Some read from addresses that are not specified
+   in the NSF specifications, expecting certain values to be returned.
+   Others execute undocumented instructions that have no affect on
+   less-accurate software NSF players, but will cause problems on NSF players 
+   that emulate these instructions.  Also, the playback rate specified
+   in the NSF header is currently ignored, though I haven't encountered
+   any problems in doing this.
+
+
+Q: Why doesn't the game <insert name here> work(correctly) on FCE Ultra?
+A: Many factors can make a game not work on FCE Ultra:
+
+       - If the ROM image is in the iNES format(typically files that have 
+         the extension "nes"), its header may be incorrect.  This 
+         incorrectness may also be because of garbage in the 
+         header.  Certain utilities used to put text in the reserved 
+         bytes of the iNES header, then those reserved bytes were 
+         later assigned functions.  FCE Ultra recognizes and 
+         automatically removes(from the ROM image in RAM, not on the 
+         storage medium) SOME header junk.
+
+         If the game has graphical errors while scrolling, chances are
+         the mirroring is set incorrectly in the header.  
+         
+         You can try to edit the header with a utility(in the NES 
+         utilities section at http://zophar.net ) or a hex editor.
+
+       - The on-cart hardware the game uses may not be emulated 
+         correctly.
+
+       - Limitations of the ROM image format may prevent a game from
+         being emulated correctly without special code to recognize that
+         game.  This occurs quite often with many Koei MMC5(iNES mapper 5) 
+         and MMC1(iNES mapper 1) games in the iNES format.  FCE Ultra identifies
+         and emulates some of these games based on the ROM CRC32 value.
+
+       - The ROM image may be encrypted.  The author of SMYNES seems to
+         have done this intentionally to block other emulators from 
+         playing "SMYNES only" games. 
diff --git a/Documentation/README b/Documentation/README
new file mode 100644 (file)
index 0000000..71e5c8b
--- /dev/null
@@ -0,0 +1,31 @@
+FCE Ultra was developed with gcc and GNU make in mind.  MSVC will probably
+compile the Windows source code with a few modifications, but you'll still 
+need to make a project file.
+
+Several pre-made makefiles are provided:
+       Makefile.beos           - BeOS(with SDL and SDL_net)
+       Makefile.unixsdl        - UN*X(FreeBSD/Linux/etc, with SDL)
+       Makefile.linuxvga       - Linux(with svgalib)
+       Makefile.dos            - (MS/PC/DR) DOS
+       Makefile.win            - MS Windows 9x/Me/Xp/2000/etc.(with DirectX).
+
+If you want to use Makefile.beos or Makefile.unixsdl for a cpu type other
+than 80x86, you will need to remove "-DC80x86" from the defines line
+and also remove "-DLSB_FIRST" if your target cpu uses MSB first ordering.
+You'll also need to remove/change "-mcpu=xxx".
+
+For the Windows port, I use MINGW32.  http://www.mingw.org
+
+To compile the DOS port, you'll need to download the DJGPP package.
+Any version of gcc >=2.95.3 should compile the code without changes, BUT
+the DJGPP versions of gcc have some problems:
+  gcc 2.95.3 sometimes breaks when compiling the code.  gcc 3.0.2 seems to 
+  produce bad code for sound.c.  So, I recommend using gcc 3.0.4 for
+  compiling the DOS version.
+
+Modifying the "-mcpu=i686" string in the makefiles, to optimize more effectively
+for your cpu type, is a good idea.
+
+Always do a "make -f Makefile.<platform> clean" before compiling for a 
+different platform or if you update via cvs and if you have stale object 
+files lying around.
diff --git a/Documentation/RELEASE-NOTES b/Documentation/RELEASE-NOTES
new file mode 100644 (file)
index 0000000..64d343c
--- /dev/null
@@ -0,0 +1,36 @@
+----June 29, 2001:
+ -Added the source code for zlib.  The makefile in the zlib directory should
+  be included by the platform makefile(such as Makefile.win) or zlib should
+  be linked in some other way.  If you use the zlib that comes with this
+  source distribution, you'll need to set up your compiler to recognize
+  the zlib subdirectory as a global include directory(like "-Izlib" with gcc).
+ -Changed the expected behavior of FCEUD_BlitScreen().  Added two new functions,
+  FCEUI_SetFirstRenderedLine() and FCEUI_SetLastRenderedLine().  See
+  porting.txt for details.
+
+
+----May 25, 2001:
+ -A few deobfuscations of the code(more will come in the future).
+ -Defined some macros to declare functions using different(faster) calling
+  conventions.  After redeclaring memory map emulation functions,
+  there was a somewhat significant speed increase.  Using the new calling conventions
+  for PPU_hook and MapIRQHook type functions resulted in a more significant
+  speed increase.
+ -Some of the driver<->emulator interface code has changed.  Much more
+  will change in the future.
+ -Added some stuff in types.h to (possibly) help people with compiling
+  FCE Ultra with MSVC++.
+
+----May 5, 2001:
+ -Optimized RAM reading/writing emulation in fce.c a little.
+ -Moved the UNIF board emulation code to the "boards" subdir.  UNIF support
+  isn't even near being done, though.  Not a high priority either.
+
+----April 16, 2001:
+ -Much of the driver interface code was restructured/rewritten, especially the
+  input-related code.  
+ -All driver functions called by the emulator are now prefixed with "FCEUD_".
+  (I may do something similar with the names of the driver interface functions).
+ -The core emulation code has been updated slightly since the Windows .53
+  release, but the changes are so minor that another binary release is not
+  necessary.
diff --git a/Documentation/TODO b/Documentation/TODO
new file mode 100644 (file)
index 0000000..95b8b77
--- /dev/null
@@ -0,0 +1,60 @@
+*** First, things that are not on the TODO list(Don't bug me about these
+       things if you're an idiot.  I don't like listening to idiots.
+       If you are not an idiot, and you can make decent arguments for why
+       these should be on the TODO list, then you can bug me.).
+
+ Remappable command keys:  Too much work would be involved, demand isn't
+  very high, and I don't need this feature.  Maybe in the distant future, if
+  input devices have changed significantly and if FCE Ultra is still around.
+
+ High-level Game Genie support(like the RAM cheats):  This would be fairly
+  simple to do, after doing the RAM cheat stuff, but I think that FCE Ultra
+  already has too many ways to "cheat" and that this would just be code bloat.
+
+
+*** General Features:
+
+ Windows Port:
+  Support for command-line options(so that one crazy guy will quit bugging
+  me).
+
+ SDL Port:
+  Make the code better.
+  Add a GTK+ interface using GLADE.
+
+ Figure out a good way to add "turbo" button support and then do it.
+
+ Make default svgalib video mode a non-tweaked VGA mode.
+
+ Finish the software video blitting "library", add support for 2xsai, eagle,
+ interpolation, etc. effects.
+
+ Rewrite network play code.  Add security features(such as only allowing
+ connections from a specified ip address).
+
+
+*** Emulation:
+
+ Fix DPCM playback and IRQ at end of playback.
+
+ Improve the sound filters.  They work, but not very well.
+
+ Fix frame IRQ(if it even exists...) and $4017.
+
+ Fix some 6502 emulation bugs(undocumented opcodes might not be implemented 
+ correctly and I'm not sure if the IRQ flag latency is implemented correctly).
+
+ Fix MMC3 IRQ emulation.  Check if this fixes the PAL version of "Star Wars".
+
+ Figure out correct timing for when the PPU refresh address register is
+ updated by the PPU(for the next scanline).
+
+ Vertical blank period might be too short?  Or maybe something is wrong 
+ with my mapper 16 IRQ emulation code. Probably the latter.  
+ See SD Gundam Knight 3 or SD GK 2.
+
+ Sound frame count stuff on PAL games(is it correct?).
+ Fix FDS sound emulation.
+
+ Fix Zapper emulation(Chiller still doesn't always work correctly).
diff --git a/Documentation/cheat.txt b/Documentation/cheat.txt
new file mode 100644 (file)
index 0000000..55b1129
--- /dev/null
@@ -0,0 +1,249 @@
+FCE Ultra Cheat Guide
+ version .4
+---------------------------
+
+Table of Contents:
+
+ 1:  Introduction
+  1.0) Introduction
+  1.1) Cheat Files
+
+ 2:  The Windows Interface
+  2.0) The Main Cheat Window
+  2.1) The Add Cheat Window
+   2.1.1) The Cheat Search Interface
+
+ 3:  The DOS/Linux Interface - UNFINISHED(read "The Windows Interface" for now)
+  3.0) The Main Cheat Menu
+   3.0.1) The Cheat List
+  3.1) The Add Cheat Menu
+   3.1.1) The Cheat Search Interface
+
+ 4:  Finding Cheats
+  4.0) "Mega Man 3" Windows Example
+  4.1) "Over Horizon" DOS/Linux Example
+  4.2) Hints
+
+/******** Section 1.0:   */
+
+ FCE Ultra allows cheating by the periodic "patching" of arbitrary addresses
+ in the 6502's memory space with arbitrary values.  Currently, only RAM
+ patching is allowed(trying to patch an address where ROM is will silently
+ fail).
+
+ The patches are all applied a short time before the emulated
+ vertical blanking period.  This detail shouldn't concern most people, though.
+ However, this does mean that cheating with games that use
+ bank-switched RAM may be problematic.  Fortunately, such games are not very
+ common(in relation to the total number of NES and Famicom games).
+
+/******** Section 1.1:   */
+
+ Cheats are stored in the "cheats" subdirectory under the base FCE Ultra
+ directory.  The files are in a simple plain-text format.  Each line represents
+ a one-byte memory patch.  The format is:
+
+       Address(hex):Value(hex):Description
+       
+  Example:
+
+       040e:05:Infinite super power.
+
+ A colon(:) can be prefixed to the beginning of a line to disable that cheat.
+       
+
+/******** Section 2.0   */
+
+ All addresses listed in the Cheats and Add Cheat windows are in a
+ 16-bit hexadecimal format and all values in these windows are in an
+ unsigned 8-bit decimal format(the range for values is 0 through 255).
+
+
+ The main Cheats window contains the list of cheats for the currently
+ loaded game, places to view and edit the attributes of the selected cheat,
+ a button to delete the selected cheat, a button to open the Add Cheat
+ window, and a button to close the Cheats window.
+
+/******** Section 2.1   */
+
+ To the left in the Add Cheat window are text edit boxes for inputting
+ attributes of a cheat and a button to add that cheat.  To the right is
+ the cheat searching interface.
+
+ /******* Section 2.1.1 */
+ The cheat search interface consists of several components:  a list of
+ addresses and associated data for a search, several command buttons,
+ and the search paramters.
+
+ The list of addresses is in the format of:
+  "Address:Original Value:Current Value".
+
+ The address is the location in the 6502's address space, the original
+ value is the value that was stored at this address when the search was
+ reset, and the current value is the value that is currently stored at
+ that address.  Selecting an item in this list will automatically cause
+ the "Address" field in the "Add Cheat" box to be updated with the
+ selected address.
+
+ The "Reset Search" button resets the search process; all valid addresses
+ are displayed in the cheat list and the data values at those addresses noted.
+
+ The "Do Search" buttons performs a search based on the search parameters
+ and removes any non-matching addresses from the address list.
+
+ The "Set Original to Current" button sets the remembered original values
+ to the current values.  It is like the "Reset Search" button, but it does
+ not affect which addresses are shown in the address list.  This command is
+ especially useful when used in conjunction with the "O!=C" search filter.
+
+ The "Unhide Excluded" button shows all addresses that are excluded as a
+ result of any previous searches.  It is like the "Reset Search" button
+ except that it does not affect the remembered original values.
+
+ The numbers assigned the names "V1" and "V2" have different meanings based
+ on which filter is selected.  A list of the names of the filters and detailed
+ information on what they do follows("original value" corresponds to the value
+ remembered for a given addres and "current value" is the value currently
+ at that address. Also, if a value is not explicitly said to be shown
+ under a certain condition, then it is obviously excluded.):
+
+  "O==V1 && C==V2":
+                 Show the address if the original value is equal to "V1" AND
+                 the current value is equal to "V2".
+
+  "O==V1 && |O-C|==V2":
+                 Show the address if the original value is equal to "V1" AND
+                 the difference between the current value and the original
+                 value is equal to "V2".
+
+  "|O-C|==V2":
+                 Show the address if the difference between the current value
+                 and the original value is equal to "V2".
+  "O!=C":
+                 Show the address if the original value does not equal the
+                 current value.
+
+/******** Section 4.0   */
+
+ This example will give Mega Man unlimited energy.
+ Immediately after entering the Top Man stage, make your way to the
+ "Add Cheat" window.  Push "Reset Search".
+ Go back to playing and move right until the first enemy appears.  Allow
+ yourself to be hit twice.  Each hit does "2" damage, so you've lost 4 energy
+ bars.  Go to the "Add Cheat" window again and select the third filter
+ ("|O-C|==V2") and enter the value 4 next to "V2".  Then push "Do Search".
+
+ Several addresses will appear in the address list.  You can try to find
+ the address you want through trial and error, or you can narrow the results
+ down further.  We will do the latter.
+
+ Go back to playing MM3 and get hit one more time and make your way back
+ to the "Add Cheat" window.  Your damage is now "6".  You can probably
+ see which address that contains your life(it is 00A2).  If now, change
+ V2 to 6 and push "Do Search" again.  This should leave only 00A2.
+
+ Select that entry in the address list.  Shift your attention to the "Add
+ Cheat" box to the left.  Type in a meaningful name and the desired value(156;
+ it was the value when you had no damage, so it's safe to assume it's the
+ maximum value you can use).  Push the "Add" button and a confirmation box
+ will come up.  The cheat has been added.
+
+
+/******** Section 4.1   */
+
+ This example will give you infinite lives in the NTSC(Japanese) version
+ of "Over Horizon".
+
+ Start a new game.  Notice that when you press "Start" during gameplay,
+ the number of lives you have left is indicated.  With no cheating, you
+ start with 3 lives(2 lives left).
+
+ Activate the cheat interface immediately after starting a new game.
+ Select the "New Cheats" menu and "Reset Search".
+
+ I'll assume that the number of lives left shown in the game is the same number
+ that's stored in RAM.  Now, "Do Search".  You're going to use the first search
+ filter.  For V1, enter the value 2.  For V2, enter the same value.  This, 
+ coupled with the fact that you just reset the search, will allow you to search 
+ for a value "absolutely"(as opposed to changes in the value).  
+
+ Now, "Show Results".  When I did it, I received 11 results:
+
+        1) $0000:002:002
+        2) $001c:002:002
+        3) $001e:002:002
+        4) $009d:002:002
+        5) $00b9:002:002
+        6) $00e3:002:002
+        7) $0405:002:002
+        8) $0406:002:002
+        9) $0695:002:002
+       10) $07d5:002:002       
+       11) $07f8:002:002
+
+ You really can't do much yet(unless you want to spend time doing trial
+ and error cheat additions).  Return to the game.
+
+ After losing a life, go back to the cheat interface, to the "New Cheats"
+ menu, and "Show Results".  Here are my results:
+
+        1) $0000:002:002
+        2) $001c:002:002
+        3) $001e:002:002
+        4) $009d:002:002
+        5) $00b9:002:041
+        6) $00e3:002:002
+        7) $0405:002:001
+        8) $0406:002:002
+        9) $0695:002:002
+       10) $07d5:002:001
+       11) $07f8:002:002
+
+ Notice that two addresses seem to hold the number of lives($0405 and
+ $07d5).  You can lose another life and go "Show Results" again, and you
+ should see that $07d5 is the address that holds the number of lives.
+
+ Now that you know the address that holds the number of lives, you can
+ add a cheat.  You can either type in the number from the cheat results list
+ corresponding to the address you want to add a cheat for, or you can
+ remember the address and select "Add Cheat" from the "New Cheats" menu.
+ Do the former.
+
+ Now you will need to enter a name for the cheat.  I suggest something short,
+ but descriptive.  "Infinite lives" will work fine.  Next, a prompt for
+ the address will show up.  Since you selected an item from the list, you
+ can press enter to use the associated address($07d5).  Next, you will
+ need to enter a value.  It doesn't need to be large(in fact, it probably
+ shouldn't be; abnormally high numbers can cause some games to misbehave).
+ I suggest a value of 2.  After this, you should get a prompt that looks like
+ this:
+
+   Add cheat "Infinite lives" for address $07d5 with value 002?(Y/N)[N]:
+
+ Answer "Y".  You now have infinite lives.
+
+/******** Section 4.2   */
+
+ Games store player information in many different ways.  For example,
+ if you have "3" lives in Super Wacky Dodgeball 1989, the game might store
+ it in memory as 2, 3, or 4, or perhaps a different number all together.
+ Also, say that you have 69 life points out of 200 in Mole Mashers.  The
+ game might store how many life points you have, or how much damage you have
+ taken. Relative value searches are very valuable because you probably 
+ don't know the way that the game stores its player data.
+
+ Some games, especially RPGs, deal with individual numbers greater than
+ 8-bits in size.  Most that I've seen seem to store the multiple-byte data
+ least significant byte(lower byte of number) first in memory, though 
+ conceivably, it could be stored most significant byte first, or the component 
+ bytes of the number could be non-contiguous, though the latter is very unlikely.
+ For example, say I have 5304 experience points in Boring Quest for the 
+ Overused Plot Device.  To split the number into two eight bit decimal numbers,
+ take 5304 %(modulus) 256.  This will give a number that is the lower 8 bits.
+ Next, take 5304 / 256.  The integral component of your answer will be the 
+ upper 8 bits(or the next 8 bits, if the number is or can be larger than 16 
+ bits) of 5304.  Now you will need to search for these numbers.  Fortunately, 
+ most(all?) RPGs seem to store large numbers exactly as they are shown in the
+ game.
diff --git a/Documentation/fcs.txt b/Documentation/fcs.txt
new file mode 100644 (file)
index 0000000..d269301
--- /dev/null
@@ -0,0 +1,143 @@
+FCE Ultra Save State Format
+(preliminary document - AKA *very incomplete*)
+---------------------------------------
+
+FCE Ultra's save state format is now designed to be as forward and backwards
+compatible as possible.  This is achieved through the (over)use of chunks.
+All multiple-byte variables are stored LSB(least significant byte)-first.
+Data types:
+
+       (u)int8 - (un)signed 8 bit variable(also referred to as "byte")
+       (u)int16 - (un)signed 16 bit variable
+       (u)int32 - (un)signed 32 bit variable
+
+-- Main File Header:
+
+The main file header is 16-bytes in length.  The first three bytes contain
+the string "FCS".  The next byte contains the version of FCE Ultra that saved
+this save state.  This document only applies to version "53"(.53) and higher.
+After the version byte, the size of the entire file in bytes(minus the 16 byte
+main file header) is stored.  The rest of the header is currently unused
+and should be nulled out.  Graphical example of relevant parts:
+
+       FCS <uint8 version> <uint32 totalsize>
+
+-- Section Chunks:
+
+Sections chunk headers are 5-bytes in length.  The first byte defines what 
+section it  is, the next four bytes define the total size of the section
+(including the section chunk header).
+
+       <uint8 section> <uint32 size>
+
+Section definitions:
+
+       1       -       "CPU"
+       2       -       "CPUC"
+       3       -       "PPU"
+       4       -       "CTLR"
+       5       -       "SND"
+       16      -       "EXTRA"
+
+-- Subsection Chunks
+
+Subsection chunks are stored within section chunks.  They contain the actual
+state data.  Each subsection chunk is composed of an 8-byte header and the data.
+The header contains a description(a name) and the size of the data contained 
+in the chunk:
+               <uint8 description[4]> <uint32 size>
+
+The name is a four-byte string.  It does not need to be null-terminated.
+If the string is less than four bytes in length, the remaining unused bytes
+must be null.
+
+-- Subsection Chunk Description Definitions
+
+Note that not all subsection chunk description definitions listed below
+are guaranteed to be in the section chunk.  It's just a list of what CAN
+be in a section chunk.  This especially applies to the "EXTRA" subsection.
+
+---- Section "CPU"
+
+       Name:   Type:           Description:
+       
+       PC      uint16          Program Counter
+       A       uint8           Accumulator
+       P       uint8           Processor status register
+       X       uint8           X register
+       Y       uint8           Y register
+       S       uint8           Stack pointer
+       RAM     uint8[0x800]    2KB work RAM
+
+---- Section "CPUC" (emulator specific)
+
+        Name:   Type:           Description:
+
+       JAMM    uint8           Non-zero value if CPU in a "jammed" state
+       IRQL    uint8           Non-zero value if IRQs are to be generated constantly
+       ICoa    int32           Temporary cycle counter
+       ICou    int32           Cycle counter
+
+---- Section "PPU"
+
+        Name:   Type:           Description:
+
+       NTAR    uint8[0x800]    2 KB of name/attribute table RAM
+       PRAM    uint8[32]       32 bytes of palette index RAM
+       SPRA    uint8[0x100]    256 bytes of sprite RAM
+       PPU     uint8[4]        Last values written to $2000 and $2001, the PPU
+                               status register, and the last value written to
+                               $2003.
+       XOFF    uint8           Tile X-offset.
+       VTOG    uint8           Toggle used by $2005 and $2006.
+       RADD    uint16          PPU Address Register(address written to/read from
+                               when $2007 is accessed).
+       TADD    uint16          PPU Address Register
+       VBUF    uint8           VRAM Read Buffer
+       PGEN    uint8           PPU "general" latch.  See Ki's document.
+
+---- Section "CTLR" (somewhat emulator specific)
+
+        Name:   Type:           Description:
+
+       J1RB    uint8           Bit to be returned when first joystick is read.
+       J2RB    uint8           Bit to be returned when second joystick is read.
+
+---- Section "SND" (somewhat emulator specific)
+
+       <to be written>
+
+---- Section "EXTRA" (varying emulator specificness)
+
+       For iNES-format games(incomplete):
+
+        Name:   Type:           Description:
+
+       WRAM    uint8[0x2000]   8KB of WRAM at $6000-$7fff
+       MEXR    uint8[0x8000]   (very emulator specific)
+       CHRR    uint8[0x2000]   8KB of CHR RAM at $0000-$1fff(in PPU address space).
+       EXNR    uint8[0x800]    Extra 2KB of name/attribute table RAM.
+       MPBY    uint8[32]       (very emulator specific)
+       MIRR    uint8           Current mirroring:
+                                       0 = "Horizontal"
+                                       1 = "Vertical"
+                                       $10 = Mirror from $2000
+                                       $11 = Mirror from $2400
+       IRQC    uint32          Generic IRQ counter
+       IQL1    uint32          Generic IRQ latch
+       IQL2    uint32          Generic IRQ latch
+       IRQA    uint8           Generic IRQ on/off register.
+       PBL     uint8[4]        List of 4 8KB ROM banks paged in at $8000-$FFFF
+       CBL     uint8[8]        List of 8 1KB VROM banks page in at $0000-$1FFF(PPU).
+
+       For FDS games(incomplete):
+
+        Name:   Type:           Description:
+
+        DDT<x>  uint8[65500]    Disk data for side x(0-3).
+       FDSR    uint8[0x8000]   32 KB of work RAM
+       CHRR    uint8[0x2000]   8 KB of CHR RAM
+        IRQC    uint32          IRQ counter
+        IQL1    uint32          IRQ latch
+        IRQA    uint8           IRQ on/off.
+
diff --git a/Documentation/porting.txt b/Documentation/porting.txt
new file mode 100644 (file)
index 0000000..72fefca
--- /dev/null
@@ -0,0 +1,229 @@
+*Incomplete*
+
+
+***Driver-supplied functions:
+       These functions will only be called after the driver code calls
+       FCEUI_LoadGame() or FCEUI_Emulate().
+
+void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count);
+       Called by FCE Ultra on every emulated frame.  This function should 
+       perform the following three things(in any order):
+
+       1.
+         Update the data pointed to by the pointers passed to
+         FCEUI_SetInput() and FCEUI_SetInputFC().
+       2.
+          Copy contents of XBuf over to video memory(or whatever needs to be 
+         done to make the contents of XBuf visible on screen).
+          Each line is 256 pixels(and bytes) in width, and there can be 240
+          lines.  The pitch for each line is 272 bytes.
+         XBuf will be 0 if the symbol FRAMESKIP is defined and this frame
+         was skipped.
+       3.
+          Write the contents of "Buffer" to the sound device.  "Count" is the
+          number of samples to write.  Only the lower 16-bits of each
+          sample are used, so each 32-bit sample in "Buffer" can be converted to
+          signed 16-bit by dropping the upper 16 bits.
+         When sound was disabled for the frame, "Count" will be 0.
+
+void FCEUD_SetPalette(uint8 index, uint8 r, uint8 g, uint8 b);
+       Set palette entry "index" to specified RGB values(value: min=0, max=255).
+
+void FCEUD_GetPalette(uint8 index, uint8 *r, uint8 *g, uint8 *b);
+       Get palette entry "index" data.
+
+void FCEUD_PrintError(char *s);
+       Print/Display an error message string pointed to by "s".
+
+int FCEUD_NetworkConnect(void);
+       Initialize a network connection.  Return 0 if an error occurs.
+
+int FCEUD_NetworkRecvData(uint8 *data, uint32 len, int block);
+       Receive "len" bytes of data to "data".  If block is 0 and "len" amount
+       of data is not available, return -1.  If block is 1, wait until the
+       requested amount of data is available.
+       Return 0 on failure.
+
+int FCEUD_NetworkSendData(uint8 *data, uint32 len);
+       Send "len" bytes of "data".  Return 0 on failure.
+
+void FCEUD_NetworkClose(void);
+       Close the network connection.
+
+
+***FCE Ultra functions(called by the driver code):
+       The FCEUI_* functions may only be called before FCEUI_Emulate() is 
+       called or after it returns and before it is called again, or after the
+       following functions are called and before they return:
+               FCEUD_Update();
+       Calling the FCEUI_* functions at any other time may result in 
+       undefined behavior.
+       
+void FCEUI_SetInput(int port, int type, void *ptr, int attrib);
+void FCEUI_SetInputFC(int type, void *ptr, int attrib);
+void FCEUI_DisableFourScore(int s);
+
+void FCEUI_SetSnapName(int a);
+
+void FCEUI_DisableSpriteLimitation(int a);
+       Disables the 8-sprite-per-scanline limitation of the NES if "a"
+       is nonzero.  The default behavior is the limitation is enabled.
+
+void FCEUI_SaveExtraDataUnderBase(int a);
+       If "a" is nonzero, save extra non-volatile game data(battery-backed
+       RAM) under FCE Ultra's base directory.  Otherwise, the behavior is
+       to save it under the same directory the game is located in(this is
+       the default behavior).
+
+FCEUGI *FCEUI_LoadGame(char *name);
+       Loads a new file.  "name" is the full path of the file to load.
+       Returns 0 on failure, or a pointer to data type "FCEUGI":
+       See file "git.h" for more details on this structure.
+
+int FCEUI_Initialize(void);
+       Allocates and initializes memory.  Should only be called once, before
+       any calls to other FCEU functions.
+       
+void FCEUI_SetBaseDirectory(void);
+        Specifies the base FCE Ultra directory.  This should be called
+        immediately after FCEUI_Initialize() and any time afterwards.
+
+void FCEUI_SetDirOverride(int which, char *n);
+
+        FCEUIOD_CHEATS  - Cheats
+        FCEUIOD_MISC    - Miscellaneous stuff(custom game palettes)
+        FCEUIOD_NV      - Non-volatile game data(battery backed RAM)
+        FCEUIOD_SNAPS   - Screen snapshots
+        FCEUIOD_STATE   - Save states
+
+void FCEUI_Emulate(void);
+       Enters the emulation loop.  This loop will be exited when FCEUI_CloseGame()
+       is called.  This function obviously shouldn't be called if FCEUI_LoadGame()
+       wasn't called or FCEUI_CloseGame() was called after FCEUI_LoadGame().
+
+void FCEUI_CloseGame(void);
+       Closes the loaded game and frees all memory used to load it.
+       Also causes FCEUI_Emulate() to return.
+
+void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall);
+        Sets the first(minimum is 0) and last(NOT the last scanline plus one; 
+       maximum is 239) scanlines of background data to draw, for both NTSC 
+       emulation mode and PAL emulation mode.
+
+       Defaults are as if this function were called with the variables set
+       up as follows:
+               ntscf=8, ntscl=239, palf=0, pall=239
+               
+void FCEUI_SetNetworkPlay(int type);
+       Sets status of network play according to "type".  If type is 0,
+       then network play is disabled.  If type is 1, then we are server.  
+       If type is 2, then we are a client.
+
+void FCEUI_SelectState(int w);
+       Selects the state "slot" to save to and load from.
+
+void FCEUI_SaveState(void);
+       Saves the current virtual NES state from the "slot" selected by 
+       FCEUI_SelectState().
+
+void FCEUI_LoadState(void);
+        Loads the current virtual NES state from the "slot" selected by
+        FCEUI_SelectState().
+
+void FCEUI_SaveSnapshot(void);
+       Saves a screen snapshot.  
+
+void FCEUI_DispMessage(char *msg);
+       Displays a short, one-line message using FCE Ultra's built-in
+       functions and ASCII font data.
+
+int32 FCEUI_GetDesiredFPS(void);
+       Returns the desired FPS based on whether NTSC or PAL emulation is
+       enabled, shifted left by 24 bits(this is necessary because the real
+       FPS value is not a whole integer).  This function should only be 
+       necessary if sound emulation is disabled.  
+
+int FCEUI_GetCurrentVidSystem(int *slstart, int *slend);
+       Convenience function(not strictly necessary, but reduces excessive code
+       duplication); returns currently emulated video system
+       (0=NTSC, 1=PAL).  It will also set the variables pointed to by slstart
+       and slend to the first and last scanlines to be rendered, respectively,
+       if slstart and slend are not 0.
+
+int FCEUI_AddCheat(char *name, uint16 addr, uint8 val);
+       Adds a RAM cheat with the specified name to patch the address "addr"
+       with the value "val".
+
+int FCEUI_DelCheat(uint32 which);
+       Deletes the specified(by number) cheat.
+
+void FCEUI_ListCheats(void (*callb)(char *name, uint16 a, uint8 v));
+       Causes FCE Ultra to go through the list of all cheats loaded for
+       the current game and call callb() for each cheat with the cheat 
+       information.
+
+int FCEUI_GetCheat(uint32 which, char **name, int32 *a, int32 *v, int *s);
+       Gets information on the cheat referenced by "which".
+
+int FCEUI_SetCheat(uint32 which, char *name, int32 a, int32 v, int s);
+       Sets information for the cheat referenced by "which".
+
+void FCEUI_CheatSearchBegin(void);
+       Begins the cheat search process.  Current RAM values are copied
+       to a buffer to later be processed by the other cheat search functions.
+
+void FCEUI_CheatSearchEnd(int type, int v1, int v2);
+       Searches the buffer using the search method specified by "type"
+       and the parameters "v1" and "v2".
+
+int32 FCEUI_CheatSearchGetCount(void);
+       Returns the number of matches from the cheat search.    
+
+void FCEUI_CheatSearchGet(void (*callb)(uint16 a, int last, int current));
+
+void FCEUI_CheatSearchGetRange(int first, int last, void (*callb)(uint16 a, int last, int current));
+       Like FCEUI_CheatSearchGet(), but you can specify the first and last
+       matches to get.
+
+void FCEUI_CheatSearchShowExcluded(void);
+       Undos any exclusions of valid addresses done by FCEUI_CheatSearchEnd().
+
+void FCEUI_CheatSearchSetCurrentAsOriginal(void);
+       Copies the current values in RAM into the cheat search buffer.
+
+***Recognized defined symbols:
+
+The following defined symbols affect the way FCE Ultra is compiled:
+
+       C80x86
+       - Include 80x86 inline assembly in AT&T syntax.
+
+       FRAMESKIP
+       - Include frame skipping code.
+
+       NETWORK
+       - Include network play code.
+
+       FPS
+       - Compile code that prints out a number when FCE Ultra exits 
+         that represents the average fps.
+       
+       ZLIB
+       - Compile support for compressed PKZIP-style files AND gzip compressed
+         files.  "unzip.c" will need to be compiled and linked in by you if 
+         this is defined(it's in the zlib subdirectory).
+
+       LSB_FIRST
+       - Compile code to expect that variables that are greater than 8 bits
+         in size are stored Least Significant Byte First in memory.
+
+       PSS_STYLE x
+       - Sets the path separator style to the integer 'x'.  Valid styles are:
+         1: Only "/" - For UNIX platforms.
+         2: Both "/" and "\" - For Windows and MSDOS platforms.
+         3: Only "\" - For ???.
+         4: Only ":" - For Macintoshes and Apple IIs ^_^.
+
+
+
+
diff --git a/Documentation/rel/1.0 b/Documentation/rel/1.0
new file mode 100644 (file)
index 0000000..d791845
--- /dev/null
@@ -0,0 +1,178 @@
+/******************************************************************************/
+/*  1.0)       What FCE Ultra is:                                            */
+/******************************************************************************/
+
+        FCE Ultra is an NTSC and PAL Famicom/NES emulator for various 
+        platforms. It is based upon Bero's original FCE source code.  Current
+       features include good PPU, CPU, pAPU, expansion chip, and joystick
+       emulation.  Also a feature unique to this emulator(at the current
+        time) is authentic Game Genie emulation.  Save states and snapshot
+       features also have been implemented.  The VS Unisystem is emulated
+        as well.  FCE Ultra supports iNES format ROM images, UNIF format ROM
+       images, headerless and FWNES style FDS disk images, and NSF files.
+
+        FCE Ultra currently supports the following iNES mappers(many partially):
+
+Number:         Description:                    Game Examples:
+--------------------------------------------------------------------------------
+  0             No Mapper                       Donkey Kong, Mario Bros
+  1             Nintendo MMC1                   MegaMan 2, Final Fantasy
+  2             Simple 16KB PRG Switch          MegaMan 1, Archon, 1944
+  3             Simple 8KB CHR Switch           Spy Hunter, Gradius
+  4             Nintendo MMC3                   Recca, TMNT 2, Final Fantasy 3
+  5             Nintendo MMC5                   Castlevania 3, Just Breed, Uchuu Keibitai SDF
+  6             FFE F4 Series(hacked)           Saint Seiya, Ganbare Goemon
+  7             AOROM                           Battle Toads, Lion King
+  8             FFE F3 Series(hacked)           Doraemon Kaitakuhen
+  9             Nintendo MMC2                   Punchout!
+ 10             Nintendo MMC4                   Fire Emblem, Fire Emblem Gaiden
+ 11             Color Dreams                    Crystal Mines, Bible Adventures
+ 13             CPROM                           Videomation
+ 15             Multi-cart(pirate)              100-in-1: Contra Function 16
+ 16             Bandai                          Dragon Ball Z, Gundam Knight
+ 17             FFE F8 Series(hacked)           Parodius, Last Armageddon
+ 18             Jaleco SS806                    Pizza Pop, Plazma Ball
+ 19             Namco 106                       Splatter House, Mappy Kids                
+ 21             Konami VRC4 2A                  WaiWai World 2, Ganbare Goemon Gaiden 2
+ 22             Konami VRC4 1B                  Twinbee 3
+ 23             Konami VRC2B                    WaiWai World, Getsufuu Maden
+ 24             Konami VRC6                     Akumajo Densetsu(Dracula 3)
+ 25             Konami VRC4                     Gradius 2, Bio Miracle: Boku tte Upa
+ 26             Konami VRC6 A0-A1 Inverse       Esper Dream 2, Madara
+ 32             Irem G-101                      Image Fight 2, Perman
+ 33             Taito TC0190/TC0350             Don Doko Don 1&2
+ 34             NINA-001 and BNROM             Impossible Mission 2, Deadly Towers, Bug Honey
+ 40             (pirate)                        Super Mario Bros. 2
+ 41             Caltron 6-in-1                  Caltron 6-in-1
+ 42            (pirate)                        "Mario Baby"
+ 43            Multi-cart(pirate)              Golden Game 150 in 1
+ 44            Multi-cart(pirate)              Super HiK 7 in 1        
+ 45            Multi-cart(pirate)              Super 1000000 in 1
+ 46            Game Station                    Rumble Station
+ 47            NES-QJ                          Nintendo World Cup/Super Spike V.B.
+ 48            Taito TC190V                    Flintstones
+ 49             Multi-cart(pirate)              Super HiK 4 in 1
+ 51            Multi-cart(pirate)              11 in 1 Ball Games
+ 52            Multi-cart(pirate)              Mario Party 7 in 1
+ 64             Tengen RAMBO-1                  Shinobi, Klax
+ 65             Irem H-3001                     Daiku no Gensan 2
+ 66             GNROM                           SMB + Duck Hunt
+ 67             Sunsoft Mapper "3"              Fantasy Zone 2
+ 68             Sunsoft Mapper "4"              After Burner 2, Nantetta Baseball 
+ 69             Sunsoft FME-7                   Batman: ROTJ, Gimmick!
+ 70            ??                              Kamen Rider Club
+ 71             Camerica                        Fire Hawk, Linus Spacehead
+ 72            Jaleco ??                       Pinball Quest
+ 73             Konami VRC3                     Salamander
+ 75             Jaleco SS8805/Konami VRC1       Tetsuwan Atom, King Kong 2
+ 76             Namco 109                       Megami Tenshi 1
+ 77             Irem ??                         Napoleon Senki
+ 78             Irem 74HC161/32                 Holy Diver
+ 79             NINA-06                                F15 City War, Krazy Kreatures
+ 80             Taito X-005                     Minelvation Saga
+ 82            Taito ??                        Kyuukyoku Harikiri Stadium - Heisei Gannen Ban                  
+ 83            Multi-cart(pirate)              Dragon Ball Party
+ 85             Konami VRC7                     Lagrange Point
+ 86            Jaleco ??                       More Pro Baseball
+ 87            ??                              Argus
+ 89            Sunsoft ??                      Mito Koumon
+ 90            Pirate                          Super Mario World, Mortal Kombat
+ 92             Jaleco ??                       MOERO Pro Soccer, MOERO Pro Yakyuu '88
+ 93            ??                              Fantasy Zone
+ 94            ??                              Senjou no Ookami
+ 95            Namco ??                        Dragon Buster
+ 97            ??                              Kaiketsu Yanchamaru
+ 99             VS System 8KB CHR Switch        VS SMB, VS Excite Bike
+105             NES-EVENT                       Nintendo World Championships
+112             Asder                          Sango Fighter, Hwang Di
+113            MB-91                           Deathbots
+118            MMC3-TLSROM/TKSROM Board        Ys 3, Goal! 2, NES Play Action Football
+119             MMC3-TQROM Board                High Speed, Pin*Bot
+140            Jaleco ??                       Bio Senshi Dan
+151             Konami VS System Expansion      VS The Goonies, VS Gradius
+152            ??                              Arkanoid 2, Saint Seiya Ougon Densetsu
+153             Bandai ??                       Famicom Jump 2
+180             ??                              Crazy Climber
+182            ??                              Super Donkey Kong
+184            ??                              Wing of Madoola, The
+189             Micro Genius TXC ??             Thunder Warrior
+225             Multi-cart(pirate)              58-in-1/110-in-1/52 Games
+226             Multi-cart(pirate)              76-in-1
+227            Multi-cart(pirate)              1200-in-1
+228             Action 52                       Action 52, Cheetahmen 2
+229             Multi-cart(pirate)              31-in-1
+232            BIC-48                          Quattro Arcade, Quattro Sports
+234            Multi-cart ??                   Maxi-15
+240             ??                              Gen Ke Le Zhuan, Shen Huo Le Zhuan
+242            ??                              Wai Xing Zhan Shi
+246            ??                              Fong Shen Ban
+248            ??                              Bao Qing Tian
+250            ??                              Time Diver Avenger
+
+       FCE Ultra currently supports the following UNIF boards(minus the 
+        prefixes HVC-, NES-, BTL-, and BMC-, as they are currently ignored):
+        
+Group: Name:                   Game Examples:
+--------------------------------------------------------------------------------
+Bootleg:
+        MARIO1-MALEE2          Super Mario Bros. Malee 2
+        NovelDiamond9999999in1 Novel Diamond 999999 in 1
+       Super24in1SC03          Super 24 in 1
+        Supervision16in1       Supervision 16-in-1
+
+Unlicensed:
+        Sachen-8259A           Super Cartridge Version 1
+        Sachen-8259B           Silver Eagle
+        Sachen-74LS374N                Auto Upturn
+        SA-016-1M              Master Chu and the Drunkard Hu
+        SA-72007               Sidewinder
+        SA-72008               Jovial Race
+        SA-0036                        Mahjong 16
+        SA-0037                        Mahjong Trap
+       TC-U01-1.5M             Challenge of the Dragon
+
+MMC1:
+       SAROM                   Dragon Warrior
+       SBROM                   Dance Aerobics
+       SCROM                   Orb 3D
+       SEROM                   Boulderdash
+       SGROM                   Defender of the Crown
+       SKROM                   Dungeon Magic
+       SLROM                   Castlevania 2
+       SL1ROM                  Sky Shark
+       SNROM                   Shingen the Ruler
+       SOROM                   Nobunaga's Ambition
+
+MMC3:
+       TFROM                   Legacy of the Wizard
+       TGROM                   Megaman 4
+       TKROM                   Kirby's Adventure
+       TKSROM                  Ys 3
+       TLROM                   Super Spike V'Ball
+       TLSROM                  Goal! 2
+       TR1ROM                  Gauntlet
+       TQROM                   Pinbot
+       TSROM                   Super Mario Bros. 3
+       TVROM                   Rad Racer 2
+
+MMC5:
+       EKROM                   Gemfire
+       ELROM                   Castlevania 3
+       ETROM                   Nobunaga's Ambition 2
+       EWROM                   Romance of the Three Kingdoms 2
+
+MMC6:
+       HKROM                   Star Tropics
+
+Nintendo
+discrete
+logic:
+        CNROM                  Gotcha
+        CPROM                  Videomation
+        MHROM
+        NROM-128               Mario Bros.
+        NROM-256               Super Mario Bros.
+        RROM-128
+        UNROM                  Megaman
+
+
diff --git a/Documentation/rel/1.1.dos b/Documentation/rel/1.1.dos
new file mode 100644 (file)
index 0000000..003a7d8
--- /dev/null
@@ -0,0 +1,22 @@
+/******************************************************************************/
+/*  1.1)        System requirements:                                          */
+/******************************************************************************/
+
+        Minimum system requirements:
+
+        Pentium 60 MHz
+        8 MB RAM
+        400 KB free disk space
+        Linux 2.0.36
+        VGA adapter
+
+        Recommended system specifications(at least):
+
+        Pentium 233 MHz
+        16 MB RAM
+        5 MB free disk space
+        Windows 9x/Me/2000/XP(long filename support)
+       VGA adapter
+        Sound Blaster Pro or newer sound card(or compatible)
+
+
diff --git a/Documentation/rel/1.1.linux b/Documentation/rel/1.1.linux
new file mode 100644 (file)
index 0000000..b84d391
--- /dev/null
@@ -0,0 +1,22 @@
+/******************************************************************************/
+/*  1.1)        System requirements:                                          */
+/******************************************************************************/
+
+        Minimum system requirements:
+
+        Pentium 60 MHz
+        8 MB RAM
+        400 KB free disk space
+        Linux 2.0.36
+        VGA adapter
+
+        Recommended system specifications(at least):
+
+        Pentium 233 MHz
+        16 MB RAM
+        5 MB free disk space
+        Linux 2.2.x
+        SVGA adapter with 512 KB of RAM
+        Sound device capable of handling a sample rate of about 44100 hz.
+
+
diff --git a/Documentation/rel/1.1.win b/Documentation/rel/1.1.win
new file mode 100644 (file)
index 0000000..af57dc7
--- /dev/null
@@ -0,0 +1,26 @@
+/******************************************************************************/
+/*  1.1)       System requirements:                                          */
+/******************************************************************************/
+
+        Minimum system specifications:
+
+        Pentium 60 MHz
+        8 MB RAM
+        400 KB free disk space
+       Windows 95
+       DirectX 7.0
+        Video adapter
+
+        Recommended minimum system specifications:
+
+        Pentium 233 MHz
+        16 MB RAM
+        5 MB free disk space
+       Windows 98SE
+        Video adapter with 2D acceleration abilities
+       DirectX 8.0
+       Joystick
+       Mouse
+        Sound device capable of handling a sample rate of 44100 hz.
+
+
diff --git a/Documentation/rel/2.0.dos b/Documentation/rel/2.0.dos
new file mode 100644 (file)
index 0000000..c837350
--- /dev/null
@@ -0,0 +1,93 @@
+/******************************************************************************/
+/*  2.0) Starting FCE Ultra                                                   */
+/******************************************************************************/
+
+        Start FCE Ultra using the following format:
+
+        fceu <arguments> romimage.nes
+
+        <arguments> can be one or more of the following:
+
+        -vmode x        Select video mode(all are 8 bpp).
+                         1 = 256x240 @ 72 hz   <Default>
+                         2 = 256x256 @ 65 hz
+                         3 = 256x256(with scanlines) @ 120 hz
+                         6 = 256x224(with scanlines) @ 120 hz
+                         8 = 256x224 @ 103 hz
+       -vsync x        Wait for the screen's vertical retrace before updating 
+                       the screen.  This *may* cause sound distortion.
+                        0 = Disabled.  <Default>
+                        1 = Enabled.
+        -cpalette x     Load a custom global palette from file x.
+                        The filename x is saved in the configuration file,
+                        not the data from the file.  Note that you should
+                        probably use an absolute("C:\nes\test.pal") filename
+                        rather than a relative("test.pal") filename.  If x is 0,
+                       the default (built in) global palette will be used.
+        -ntsccol        Emulate an NTSC's TV's colors based on user-supplied
+                        hue and tint values.
+                         0 = Disabled.
+                         1 = Enabled.
+        -sound   x      Sound.         <Default=44100>
+                         0 = Disabled.
+                         Otherwise, x = playback rate in samples per second.
+        -soundvol x     Sound volume. x is an integral percentage value.
+                        The default value is, obviously, 100.
+                        Setting it higher will increase the likelihood that
+                        sound clipping will occur.  This shouldn't be noticeable
+                       if the volume is reasonable(200% or lower; perhaps even
+                        higher for many games).
+        -f8bit x        Force 8-bit sound.  Enabling this will decrease
+                        sound quality noticeably without increasing
+                        performance noticeably.  Only use when 16-bit sound
+                        is problematic.
+                         0 = Disabled. <Default>
+                         1 = Enabled.
+       -nothrottle x   Disables speed throttling used when sound is disabled
+                       if x is non-zero.  The default value of x is 0.
+        -joy x          Joystick mapped to virtual joystick x.
+                         0 = Disabled, reset configuration.
+        -inputx str     Select device mapped to virtual NES-style input port
+                        x(1-2).
+                        The default for both virtual input ports is "gamepad".
+                         str may be: none, gamepad, zapper, powerpada,
+                                     powerpadb, arkanoid
+        -fcexp str      Select Famicom expansion port device.  If you select
+                        a device other than "none", you should enable the
+                        "gamepad" on both NES-style virtual input ports.
+                        The default is "none".
+                         str may be: none, shadow, arkanoid, 4player, fkb
+        -nofs x         Disables Four-Score emulation if x is 1.  Default is 0.
+                        Note that Four-Score emulation will only be active
+                        if "gamepad" is mapped to one or both virtual input
+                        ports.
+       -gg             Enable Game Genie emulation.
+        -pal            Emulate a PAL NES.
+        -no8lim x       Disables the 8 sprites per scanline limitation.
+                         0 = Limitation enabled.       <Default>
+                         1 = Limitation disabled.
+        -subase x       Save extra game data files(such as battery-backed RAM)
+                        under the base directory if enabled.
+                         0 = Disabled. <Default>
+                         1 = Enabled.
+        -snapname x     Selects what type of file name screen snapshots will
+                        have.
+                         0 = Numeric(0.png)     <Default>
+                         1 = File base and numeric(mario-0.png)
+        -clipsides x    Clip leftmost and rightmost 8 columns of pixels of
+                        video output.
+                         0 = Disabled.  <Default>
+                         1 = Enabled.
+        -slstart x      Set the first drawn emulated scanline for NTSC emulation
+                        mode.  Valid values for x are 0 through 239.
+                        The default value is 8.
+        -slend x        Set the last drawn emulated scanline for NTSC emulation
+                        mode. Valid values for x are 0 through 239.
+                        The default value is 239.
+        -slstartp x     Set the first drawn emulated scanline for PAL emulation
+                       mode.  Valid values for x are 0 through 239.  
+                       The default value is 0.
+        -slendp x       Set the last drawn emulated scanline for PAL emulation
+                       mode. Valid values for x are 0 through 239.
+                       The default value is 239.
+
diff --git a/Documentation/rel/2.0.linux b/Documentation/rel/2.0.linux
new file mode 100644 (file)
index 0000000..bace00f
--- /dev/null
@@ -0,0 +1,109 @@
+/******************************************************************************/
+/*  2.0) Starting FCE Ultra                                                   */
+/******************************************************************************/
+
+        Start FCE Ultra using the following format:
+
+        ./fceu <arguments> romimage.nes
+
+        <arguments> can be one or more of the following:
+
+        -vmode x        Select video mode(all are 8 bpp).
+                         1 = 256x240 @ 72 hz   <Default>
+                         2 = 256x256 @ 65 hz
+                         3 = 256x256(with scanlines) @ 120 hz
+                         4 = 640x480(with scanlines)
+                         5 = 640x480("1 per 4")
+                         6 = 256x224(with scanlines) @ 120 hz
+                        7 = 320x240
+                        8 = 256x224 @ 103 hz
+       -vsync x        Wait for the screen's vertical retrace before updating 
+                       the screen.  If you have sound enabled and enable this,
+                       you may have to increase the number of sound fragments
+                       from the default of 8, to reduce buffer underruns.
+                       Buffer underruns will not be preventable if the 
+                       current video refresh rate is < ~60 hz (or < ~50 hz 
+                       if PAL emulation is enabled).
+                        0 = Disabled.  <Default>
+                        1 = Enabled.
+       -cpalette x     Load a custom global palette from file x.  
+                       The filename x is saved in the configuration file,
+                       not the data from the file.  Note that you should
+                       probably use an absolute("/home/jp/test.pal") filename
+                       rather than a relative("test.pal") filename.  If x is 0,
+                       the default (built in) global palette will be used.
+        -ntsccol        Emulate an NTSC's TV's colors based on user-supplied
+                        hue and tint values.
+                         0 = Disabled. <Default>
+                         1 = Enabled.
+        -sound   x      Sound.          <Default=48000>
+                         0 = Disabled.
+                         Otherwise, x = playback rate in samples per second.
+       -soundvol x     Sound volume. x is an integral percentage value.
+                       The default value is, obviously, 100.
+                       Setting it higher will increase the likelihood that
+                       sound clipping will occur.  This shouldn't be noticeable
+                       if the volume is reasonable(200% or lower; perhaps even
+                       higher for many games).
+       -sfragsize x    Set sound fragment size to 2^x(2 to the power of x)
+                       SAMPLES.  The default value is 7.
+       -snfrags x      Set number of sound fragments to x.  The default value
+                       is 8.
+        -f8bit x        Force 8-bit sound.  Enabling this will decrease
+                        sound quality noticeably without increasing
+                        performance noticeably.  Only use when 16-bit sound
+                        is problematic.
+                         0 = Disabled. <Default>
+                         1 = Enabled.
+        -nothrottle x   Disables speed throttling used when sound is disabled
+                        if x is non-zero.  The default value of x is 0.
+       -joyx y         Joystick mapped to virtual joystick x(1-4).
+                        0 = Disabled, reset configuration.     <Default>
+                        Otherwise, y(1-inf) = joystick number.
+        -inputx str     Select device mapped to virtual NES-style input port 
+                       x(1-2).
+                       The default for both virtual input ports is "gamepad".
+                         str may be: none, gamepad, zapper, powerpada, 
+                                    powerpadb, arkanoid
+       -fcexp str      Select Famicom expansion port device.  If you select
+                       a device other than "none", you should enable the
+                       "gamepad" on both NES-style virtual input ports.
+                       The default is "none".
+                        str may be: none, shadow, arkanoid, 4player, fkb
+       -nofs x         Disables Four-Score emulation if x is 1.  Default is 0.
+                       Note that Four-Score emulation will only be active
+                       if "gamepad" is mapped to one or both virtual input
+                       ports.
+       -gg             Enable Game Genie emulation.
+        -pal            Emulate a PAL NES.
+        -no8lim x       Disables the 8 sprites per scanline limitation.
+                         0 = Limitation enabled.       <Default>
+                         1 = Limitation disabled.
+        -subase x       Save extra game data files(such as battery-backed RAM)
+                        under the base directory if enabled.
+                         0 = Disabled. <Default>
+                         1 = Enabled.
+       -snapname x     Selects what type of file name screen snapshots will 
+                       have.
+                        0 = Numeric(0.png)     <Default>
+                        1 = File base and numeric(mario-0.png)
+       -clipsides x    Clip leftmost and rightmost 8 columns of pixels of 
+                       video output.
+                        0 = Disabled.  <Default>
+                        1 = Enabled.
+        -slstart x      Set the first drawn emulated scanline for NTSC emulation
+                        mode.  Valid values for x are 0 through 239.
+                        The default value is 8.
+        -slend x        Set the last drawn emulated scanline for NTSC emulation
+                        mode. Valid values for x are 0 through 239.
+                        The default value is 239.
+        -slstartp x     Set the first drawn emulated scanline for PAL emulation
+                        mode.  Valid values for x are 0 through 239.
+                        The default value is 0.
+        -slendp x       Set the last drawn emulated scanline for PAL emulation
+                        mode. Valid values for x are 0 through 239.
+                        The default value is 239.
+        -connect   s    Connect to server 's' for TCP/IP network play.
+        -server         Be a host/server for TCP/IP network play.
+       -netport x      Use TCP/IP port x for network play.  The default
+                       port is 4046.
diff --git a/Documentation/rel/2.0.win b/Documentation/rel/2.0.win
new file mode 100644 (file)
index 0000000..15bc082
--- /dev/null
@@ -0,0 +1,8 @@
+/******************************************************************************/
+/*  2.0)        Starting FCE Ultra                                            */
+/******************************************************************************/
+
+        FCE Ultra can be started by running the executable "fceu.exe".
+        I do not recommend running it from a DOS "box".
+
+
diff --git a/Documentation/rel/2.1.dos b/Documentation/rel/2.1.dos
new file mode 100644 (file)
index 0000000..31f5995
--- /dev/null
@@ -0,0 +1,59 @@
+/******************************************************************************/
+/*  2.1)        General Keyoard Key Mapping:                                  */
+/******************************************************************************/
+
+        Default Key Mapping:
+
+        For emulated Family BASIC Keyboard:
+         Enable/Disable Keyboard Input         Scroll Lock
+               (enabling emulated keyboard input will disable
+                commands keys)
+         All emulated keys are mapped to the closest open key on the PC
+         keyboard, with a few exceptions.  The emulated "@" key is
+         mapped to the "`"(grave) key, and the emulated "kana" key
+         is mapped to the "Insert" key(in the 3x2 key block above the
+         cursor keys).
+
+         For emulated game pads:
+          Left Control             B
+          Left Alt                 A
+          Enter/Return             Start
+          Tab                      Select
+          Cursor Down              Down
+          Cursor Up                Up
+          Cursor Left              Left
+          Cursor Right             Right
+
+         For emulated power pads(keys correspond to button locations on
+         side "B"):
+          O P [ ]
+          K L ; '
+          M , . /
+
+         For FDS games:
+          I                        Insert disk.
+          E                        Eject disk.
+          S                        Select disk/disk side.
+        
+        For VS Unisystem games:
+         C                        Insert coin.
+         V                        Show/Hide dip switches.
+           1-8                      Toggle dip switches(when dip switches 
+                                   are shown).
+
+         T                        Select tint to adjust.
+         H                        Select hue to adjust.
+         +/-                      Increase/decrease tint or hue.
+
+         0-9                      Select save state.
+         Caps Lock                Select virtual joystick.
+
+         F2                       Activate cheat interface.
+
+         F5/F7                    Save/Load state.
+         F9                       Save screen snapshot.
+         F10                      Reset.
+        F11                      Power off/on.
+         ESC/F12                  Exit.
+
+
diff --git a/Documentation/rel/2.1.linux b/Documentation/rel/2.1.linux
new file mode 100644 (file)
index 0000000..85915f3
--- /dev/null
@@ -0,0 +1,62 @@
+/******************************************************************************/
+/*  2.1)        General Keyoard Key Mapping:                                  */
+/******************************************************************************/
+
+        Default Key Mapping:
+
+         For emulated Family BASIC Keyboard:
+          Enable/Disable Keyboard Input         Scroll Lock
+                (enabling emulated keyboard input will disable
+                 commands keys)
+          All emulated keys are mapped to the closest open key on the PC
+          keyboard, with a few exceptions.  The emulated "@" key is
+          mapped to the "`"(grave) key, and the emulated "kana" key
+          is mapped to the "Insert" key(in the 3x2 key block above the
+          cursor keys).
+
+         For emulated game pads:
+          Left Control             B
+          Left Alt                 A
+          Enter/Return             Start
+          Tab                      Select
+          Cursor Down              Down
+          Cursor Up                Up
+          Cursor Left              Left
+          Cursor Right             Right
+
+         For emulated power pads(keys correspond to button locations on
+         side "B"):
+          O P [ ]
+          K L ; '
+          M , . /
+
+         For FDS games:
+          I                        Insert disk.
+          E                        Eject disk.
+          S                        Select disk/disk side.
+        
+         For VS Unisystem games:
+          C                        Insert coin.
+          V                        Show/Hide dip switches.
+           1-8                      Toggle dip switches(when dip switches
+                                    are shown).
+
+         T                        Select tint to adjust.
+         H                        Select hue to adjust.
+         +/-                      Increase/decrease tint or hue.
+
+         0-9                      Select save state.
+         Caps Lock                Select virtual joystick.
+
+        F2                       Activate cheat interface.
+
+         F3                       Lock virtual console.
+         F4                       Unlock virtual console.
+
+         F5/F7                    Save/Load state.
+         F9                       Save screen snapshot.
+         F10                      Reset.
+        F11                      Power off/on.
+         ESC/F12                  Exit.
+
+
diff --git a/Documentation/rel/2.1.win b/Documentation/rel/2.1.win
new file mode 100644 (file)
index 0000000..4676385
--- /dev/null
@@ -0,0 +1,125 @@
+/******************************************************************************/
+/*  2.1)        Using FCE Ultra:                                              */
+/******************************************************************************/
+
+        After starting FCE Ultra, you'll probably want to load a game.  Do
+        this by going to File/Open.
+
+        Menu descriptions:
+
+        File
+         Open           - Loads a new game.                
+         Save State     - Saves the current NES state.
+         Load State     - Loads a saved NES state.
+         Log Sound As   - Logs sound to a file.  It will not work if sound
+                          is disabled.                               
+         Exit           - Exit the emulator.
+
+        NES
+         Reset          - Resets the virtual NES.
+         Power          - Power cycles the virtual NES.
+         Cheats         - Activates the cheat interface.  See "cheat.txt" for
+                          more details.
+
+        Config
+         Hide Menu      - Hides the menu.
+         Game Genie     - If checked, enable Game Genie emulation.
+                          Game Genie emulation will only begin or end when a new
+                          game is loaded.
+         PAL Emulation  - If checked, enable PAL emulation.  Changes take effect
+                          immediately, though I recommend resetting the virtual
+                          NES afterward PAL emulation is enabled or disabled.  
+         Directories    - Configure the directories that FCE Ultra will store
+                          its files in.
+         Input          - Enter input configuration dialog.
+                          Note that not all virtual devices are configurable.
+         Miscellaneous  - Enter miscellaneous configuration dialog.
+         Network Play   - Enter network play configuration dialog.
+         Palette        - Enter palette configuration dialog.
+         Sound          - Enter sound configuration dialog.
+          Sound enabled:
+                Sound emulation and output are enabled when this is checked.
+          Force 8-bit sound:
+                Forces 8-bit sound output.  Use only when absolutely
+                necessary(very rare).                        
+          Sample rate:
+                Specifies how many sound samples will be played back per
+                second.  Unless you know what you are doing, you probably
+                don't need to change this setting.
+          Use secondary sound buffer:
+                Uses a secondary sound buffer.  This option may be required
+                for sound to work with certain sound cards/devices.
+                Selecting "with global focus" will cause sound to be played
+                while FCE Ultra has lost window focus, but you will probably
+                also want to select "Active While Focus Lost" in the Config
+                menu as well, otherwise you will just get repeating sound
+                when FCE Ultra loses focus.
+          Length of sound buffer:
+                Specifies what length of sound(in milliseconds) should be
+                buffered by FCE Ultra.  DirectSound and the Windows kernel
+                may or may not cause a little more latency than what you
+                might expect(usually not any more than a few milliseconds),
+                depending on your setup.
+                Use larger values if you have sound problems such as popping
+                or gaps, though.  Larger values will increase the latency of
+                the sound, however.  Finally, larger values are ideal for
+                background music listening.
+          Volume:
+                Specifies the volume of FCE Ultra's sound output.  Setting
+                the volume too high MIGHT cause noticeable clipping on some
+                sounds(loud drums, for example), but don't let that possibility
+                stop you from experimenting.
+
+         Video          - Enter video configuration dialog.
+
+        Default Key Mapping:
+
+         For emulated Family BASIC Keyboard:
+          Enable/Disable Keyboard Input         Scroll Lock
+                (enabling emulated keyboard input will disable
+                 commands keys)
+          All emulated keys are mapped to the closest open key on the PC
+          keyboard, with a few exceptions.  The emulated "@" key is
+          mapped to the "`"(grave) key, and the emulated "kana" key
+          is mapped to the "Insert" key(in the 3x2 key block above the
+          cursor keys).
+
+         For emulated game pads:
+          Left Control             B
+          Left Alt                 A
+          Enter/Return             Start
+          Tab                      Select
+          Cursor Down              Down
+          Cursor Up                Up
+          Cursor Left              Left
+          Cursor Right             Right
+        
+         For emulated power pads(keys correspond to button locations on
+         side "B"):
+          O P [ ]
+          K L ; '
+          M , . /
+
+         For FDS games:
+          I                        Insert disk.
+          E                        Eject disk.
+          S                        Select disk/disk side.
+
+         For VS Unisystem games:
+          C                        Insert coin.
+          V                        Show/Hide dip switches.
+           1-8                      Toggle dip switches(when dip switches
+                                    are shown).
+
+         0-9                      Select save state.
+      
+         F5/F7                    Save/Load state.
+         F9                       Save screen snapshot.
+
+         F3                       Hide/Show menu.
+         F4                       Toggle between windowed/full screen modes.
+         F10                      Reset.
+         F11                      Power off/on.
+         F12                      Exit.
+
+
diff --git a/Documentation/rel/3.0.dos b/Documentation/rel/3.0.dos
new file mode 100644 (file)
index 0000000..73aa6ad
--- /dev/null
@@ -0,0 +1,19 @@
+/******************************************************************************/
+/*  3.0)        Platform Specific Notes                                       */
+/******************************************************************************/
+
+        FCE Ultra's base directory is the directory in which the executable
+        is located.
+
+        Sound Blaster sound output requires that the 'BLASTER' environment
+        variable is set.  To set it(permanently), add the following line
+        to your autoexec.bat file:
+
+        set BLASTER=A240 I5 D1 H7
+
+        Where 240(hexadecimal) is the Sound Blaster's base I/O address, 5
+        is the IRQ number, 1 is the 8-bit DMA channel, and 7 is the 16-bit
+       DMA channel(if applicable).  
+                       *DO NOT GUESS THE SETTINGS*  
+       Invalid settings can result in very bad things happening.
+
diff --git a/Documentation/rel/3.0.linux b/Documentation/rel/3.0.linux
new file mode 100644 (file)
index 0000000..faa5407
--- /dev/null
@@ -0,0 +1,37 @@
+/******************************************************************************/
+/*  3.0)        Platform Specific Notes                                       */
+/******************************************************************************/
+
+        1.  FCE Ultra uses SVGAlib, so you'll obviously need to have it
+        installed.
+
+        2.  Be careful when using the non-VGA video modes(such as 640x480).
+        SVGAlib doesn't always handle virtual terminal switching well when
+        one of these modes is being used.  Also, since FCE Ultra enables a
+        a linear frame buffer for these modes, heed this warning from
+        the SVGAlib documentation:
+
+               Furthermore, some cards (Cirrus) just enable  this  buffer
+               at  a  fixed hardware address.  For Cirrus it is mapped at
+               14MB so you should never used it if  you  have  more  than
+               14MB  of  memory (But how does an application know?).  The
+               Mach32 support for this is smarter. It makes this  feature
+               only available when it is safe to be used.
+
+        3.  FCE Ultra must be run as root in order to get access to the
+        VGA hardware.  SVGAlib will drop root privileges if you are running
+        the program as a normal user and the suid root bit is set and the
+        executable is owned by root. Example:
+                chown root fceu ; chmod 4755 fceu
+        Make sure you have the latest stable release of SVGAlib, though.
+
+        4.  FCE Ultra will save all data(state saves/screen snapshots) in
+        ~/.fceultra, so make sure your "HOME" environment variable is set
+        correctly.
+
+        If you believe FCE Ultra is too slow, you can try the following:
+         * Kill some of the other processes.
+         * Disable sound emulation.
+        * Raise the priority of FCE Ultra with the 'nice' command. 
+          Ex:  nice -n -20 ./fceu
+
diff --git a/Documentation/rel/3.0.win b/Documentation/rel/3.0.win
new file mode 100644 (file)
index 0000000..1fb9dd2
--- /dev/null
@@ -0,0 +1,11 @@
+/******************************************************************************/
+/*  3.0)       Platform Specific Notes                                       */
+/******************************************************************************/
+
+        Your desktop color depth must be 16bpp, 24bpp, or 32bpp for FCE Ultra
+        to run properly in windowed mode.
+
+       FCE Ultra's base directory is the directory in which the executable
+       is located.
+
+
diff --git a/Documentation/rel/3.1 b/Documentation/rel/3.1
new file mode 100644 (file)
index 0000000..68b3afc
--- /dev/null
@@ -0,0 +1,20 @@
+/******************************************************************************/
+/*  3.1)        Network Play Notes                                            */
+/******************************************************************************/
+
+        In TCP/IP network play, the server will be player one, and the
+        client will be player 2.
+
+        Zapper emulation and power pad emulation currently do not work with
+        network play.
+
+        Having Game Genie or PAL emulation enabled on only one side
+        will cause problems.
+
+        Both players MUST use the same ROM/disk image and SRAM
+        file(if applicable).
+
+       When using FDS or VS Unisystem games with network play, only player
+       1 will be able to insert disk, eject disk, insert coins, toggle dip
+       switches, etc.
+
diff --git a/Documentation/rel/3.2 b/Documentation/rel/3.2
new file mode 100644 (file)
index 0000000..725374f
--- /dev/null
@@ -0,0 +1,28 @@
+/******************************************************************************/
+/*  3.2)       VS Unisystem Notes                                            */
+/******************************************************************************/
+
+        FCE Ultra currently only supports VS Unisystem ROM images in the
+        iNES format. 
+
+        ROM Images:
+
+         * VS Unisystem games that are about 49,000 bytes in size most likely
+           use mapper 99.
+         * Other VS Unisystem games will use other mappers.  Here is a short
+           list of games and the mappers they use:
+
+               CastleVania - 2
+               Dr. Mario   - 1
+               Goonies     - 151
+               Gradius     - 151
+              Ice Climber - 99
+               Platoon     - 68
+
+        Palette(s):
+
+         * The colors in many VS Unisystem games may be incorrect.  This
+           is due to each game having its own PPU, and thus using a
+           different palette than games that use a different PPU.
+
+
diff --git a/Documentation/rel/3.3 b/Documentation/rel/3.3
new file mode 100644 (file)
index 0000000..5cf33f1
--- /dev/null
@@ -0,0 +1,18 @@
+/******************************************************************************/
+/*  3.3)        Famicom Disk System Notes                                     */
+/******************************************************************************/
+
+       You will need the FDS BIOS ROM image in the base FCE Ultra directory.
+       It must be named "disksys.rom".  I will not give this file to you, so
+       don't ask.
+
+       Two types of FDS disk images are supported:  disk images with the 
+       FWNES-style header, and disk images with no header.
+
+       You should make backups of all of your FDS games you use with FCE 
+       Ultra.  This is because FCE Ultra will write the disk image back to 
+       the storage medium, and the disk image in RAM might have been corrupted
+        because of inaccurate emulation(this case is not likely to occur, but 
+       it could occur).
+
+
diff --git a/Documentation/rel/3.4 b/Documentation/rel/3.4
new file mode 100644 (file)
index 0000000..4d014dd
--- /dev/null
@@ -0,0 +1,23 @@
+/******************************************************************************/
+/*  3.4)        Light Gun Notes                                               */
+/******************************************************************************/
+
+       Currently, the NES Zapper and the light gun used with the VS
+       Unisystem(I will call both the same name, Zapper) are supported.
+       Most(all?) NES games expect the Zapper to be plugged into port 2.
+       and most(all?) VS Unisystem games expect the Zapper to be plugged 
+       into port(?) 1.
+
+       The LEFT mouse button is the emulated trigger button for the
+       Zapper.  The RIGHT mouse button is also emulated as the trigger,
+       but as long as you have the RIGHT mouse button held down, no color
+       detection will take place, which is effectively like pulling the
+       trigger while the Zapper is pointed away from the television screen.
+       Note that you must hold the RIGHT button down for a short
+       time(greater than just a fast click, shorter than a second).
+       
+       Zapper emulation currently does NOT work with network play, so
+       don't even try it. I may add support in the future if enough
+       people want it or if I want it.
+
+
diff --git a/Documentation/rel/3.5 b/Documentation/rel/3.5
new file mode 100644 (file)
index 0000000..474c4c9
--- /dev/null
@@ -0,0 +1,35 @@
+/******************************************************************************/
+/*  3.5)        Palette Notes                                                 */
+/******************************************************************************/
+
+       Palettes files are expected to contain 64 8-bit RGB triplets(each in
+       that order; red comes first in the triplet in the file, then green, 
+       then blue).  Each 8-bit value represents brightness for that particular
+       color.  0 is minimum, 255 is maximum.
+
+       Palettes can be set on a per-game basis.  To do this, put a palette
+       file in the "gameinfo" directory with the same base filename
+       as the game you wish to associate with and the extension "pal".  
+       Examples:
+
+               File name:              Palette file name:
+                BigBad.nes              BigBad.pal
+                BigBad.zip              BigBad.pal
+                BigBad.Better.nes       BigBad.Better.pal
+
+
+        With so many ways to choose a palette, figuring out which one will
+        be active may be difficult.  Here's a list of what palettes will
+        be used, in order from highest priority to least priority(if a condition
+        doesn't exist for a higher priority palette, the emulator will
+        continue down its list of palettes).
+
+        NSF Palette(for NSFs only)
+         Palette loaded from the "gameinfo" directory.
+          NTSC Color Emulation(only for NTSC NES games).
+           VS Unisystem palette(if the game is a VS Unisystem game and a palette
+           is available).
+            Custom global palette.
+             Default NES palette.
+
+
diff --git a/Documentation/rel/3.6 b/Documentation/rel/3.6
new file mode 100644 (file)
index 0000000..0c0ff57
--- /dev/null
@@ -0,0 +1,19 @@
+/******************************************************************************/
+/*  3.6)        Compressed File Notes                                         */
+/******************************************************************************/
+
+        FCE Ultra can load data from both PKZIP-format files and
+        gzip-format files.  Only one type of (de)compression algorithm is
+        supported:  "deflate"; this seems to be the most popular compression
+        algorithm, though.
+
+        A compressed FDS disk image will only be saved back to disk if it
+        uses the gzip format.
+
+        All files in a PKZIP format file will be scanned for the
+        followings extensions:  .nes, .fds, .nsf, .unf, .nez, .unif
+        The first compressed file to have one of these extensions will be
+        loaded. If no compressed file has one of these extensions, the
+        first compressed file will be loaded.
+
+
diff --git a/Documentation/rel/3.7 b/Documentation/rel/3.7
new file mode 100644 (file)
index 0000000..483a030
--- /dev/null
@@ -0,0 +1,15 @@
+/******************************************************************************/
+/*  3.7)        Game Genie Notes                                             */
+/******************************************************************************/
+
+       The Game Genie ROM image is loaded from the file "gg.rom" in the
+       base directory the first time Game Genie emulation is enabled and
+       a ROM image is loaded since the time FCE Ultra has run.
+
+       The ROM image may either be the 24592 byte iNES-format image, or
+       the 4352 raw ROM image.
+
+       Remember that enabling/disabling Game Genie emulation will not take
+       effect until a new game is loaded(this statement shouldn't concern
+       any of the "run once" command-line driven ports).
+
diff --git a/Documentation/rel/4.0 b/Documentation/rel/4.0
new file mode 100644 (file)
index 0000000..d22245c
--- /dev/null
@@ -0,0 +1,12 @@
+/******************************************************************************/
+/*  4.0)        Contacting the author                                         */
+/******************************************************************************/
+
+        I can be reached via email at xodnizel@users.sourceforge.net.
+        Bero can be reached via email at 9bero9@geocities.co.jp
+         (Note that Bero can not and will not answer any questions
+          regarding the operation of FCE Ultra, so please don't ask him.
+          If you understand this, remove the 9's from the email address
+         provided to get his real email address.)
+
+
diff --git a/Documentation/rel/4.1 b/Documentation/rel/4.1
new file mode 100644 (file)
index 0000000..e177ee2
--- /dev/null
@@ -0,0 +1,36 @@
+/******************************************************************************/
+/*  4.1)        Credits                                                       */
+/******************************************************************************/
+
+\Firebug\       -       High-level mapper information.
+Bero            -       Original FCE source code.
+Brad Taylor    -       NES sound channel guide.
+Chris Hickman  -       Archaic Ruins.
+Donald Moore    -       DC PasoFami NES packs.
+Fredrik Olson  -       NES four-player adapter information.
+Gilles Vollant -       PKZIP file loading functions.
+goroh           -       Various documents.
+Jeff Tamer      -       Insaniacal fun.
+Jeremy Chadwick -       General NES information.
+Justin Smith    -       Giving me obscure ROM images in the "dark ages of
+                        NES emulation".
+Kevin Horton    -       Low level NES information and sound information.
+Ki             -       Various technical information.
+Mark Knibbs     -       Various NES information.
+Marat Fayzullin -       General NES information.
+Matthew Conte   -       Sound information.
+N. Andou       -       Awesome NES/SNES emulators, at the time...
+nori           -       FDS sound information.
+Quietust        -       VRC7 sound translation code by The Quietust
+                        (quietust@ircN.org).
+                       Ideas and corrections.
+R. Hoelscher   -       Famicom four-player adapter information.
+Rob Mocca       -       DC PasoFami NES packs, testing.
+Sean Whalen    -       Node99.
+Tatsuyuki Satoh -       OPL2 emulator
+TheRedEye      -       ROM images, testing.
+
+
+Info-ZIP       -       ZLIB
+
+...and everyone else who has helped me.
diff --git a/Documentation/rel/d b/Documentation/rel/d
new file mode 100644 (file)
index 0000000..028eaef
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+./da.sh linux
+./da.sh win
+./da.sh dos
diff --git a/Documentation/rel/da.sh b/Documentation/rel/da.sh
new file mode 100644 (file)
index 0000000..a0e5e3a
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+cat top.$1 new new.$1 toc 1.0 1.1.$1 2.0.$1 2.1.$1 3.0.$1 3.1 3.2 3.3 3.4 3.5 3.6 3.7 4.0 4.1 > readme-$1.txt
diff --git a/Documentation/rel/new b/Documentation/rel/new
new file mode 100644 (file)
index 0000000..c18f25f
--- /dev/null
@@ -0,0 +1,56 @@
+       *  Screen snapshots can now be taken while playing an NSF.
+       *  Saving screen snapshots will no longer corrupt the frame buffer.
+       *  Added many more games to the list of games that usually are found
+          with bad iNES headers.
+       *  Fixed more network play bugs.  It should now work correctly(how
+          many times have I said or implied that...).
+       *  The NSF player will now disable the FDS sound channel on song
+          initialization(fixes a problem with the Zelda no Densetsu
+          rip).
+       *  Reads from $4090 and $4092 while emulating the FDS will now return
+          the current envelope settings.  Affects "Ai Senshi Nicole" 
+          and "Bio Miracle Bokutte Upa", at least.
+       *  Merged a lot of pirate MMC3 multicart emulation code with the main
+          MMC3 emulation code.
+       *  Added support for the MMC5's split-screen mode.  This fixes the
+          introduction in "Uchuu Keibitai SDF".
+       *  Writes to $8000-$FFFF with D7 set during MMC1 emulation will
+          cause the MMC1 mode register to be OR'd with $C.  This fixes
+          "Robocop 3".
+       *  Replaced an MMC1 hack that I used to get "Bill and Ted's Excellent
+          Video Game Adventure" to work with something more accurate.
+       *  Fixed the MMC5 read handler to return the data last on the data
+          bus instead of $FF when a read occured to an unmapped address.
+          This fixes the lockup problem in "Bandit Kings of Ancient China"
+          and possibly other games.
+       *  Added support for the game "Ishin no Arashi" in the iNES format
+          (I added an entry with its CRC32 value and the number of 8KB
+           WRAM banks it needs into the MMC5 WRAM size table).
+       *  Added support for MMC1 games in the iNES format with 16KB of RAM
+           via CRC32 comparisons(currently only Genghis Khan(USA), Romance
+          of the 3 Kingdoms(USA), and Nobunaga's Ambition(USA and Japan) are 
+           recognized).
+       *  iNES mapper 1 now supports pageable CHR RAM if CHR ROM is not
+          present.  Fixes "Family School".
+       *  Added support for iNES mappers 51 and 52.  Thanks to Kevin Horton
+          for the information.
+       *  Modified MMC3(iNES mapper 4/118/119) IRQ counter emulation.  Fixes
+          problems in "MegaMan 3", "Gun Nac", and the Japanese version of
+          "Klax", but it *might* cause problems with other games.
+       *  Fixed an iNES mapper 32 emulation bug.  "Ai Sensei no Oshiete"
+          works now.
+       *  Fixed iNES mapper 33/48 IRQ emulation.
+       *  Fixed iNES mapper 16 IRQ emulation.
+       *  Added support for "Famicom Jump 2" as iNES mapper 153.
+           If a good(as far as I can tell) dump is loaded, FCE Ultra will
+           automatically fix the mapper number.
+       *  The VS Unisystem bit in iNES headers is no longer recognized.
+          Too many games have this bit set when it shouldn't be set.
+          Now VS Unisystem games are recognized by CRC32 value.
+       *  Reads from $4015 no longer reset DMC IRQ.  This fixes the
+          title screen of "Romancia".
+       *  PPU NMI now occurs a few cycles later.  Fixes the "BattleToads"
+          lockup problem.
+       *  BRK emulation now sets the I flag.
+       *  Changed a few zero-page address mode functions to read directly
+          from emulated RAM.
diff --git a/Documentation/rel/new.dos b/Documentation/rel/new.dos
new file mode 100644 (file)
index 0000000..9a69443
--- /dev/null
@@ -0,0 +1,5 @@
+       *  Added a new video mode(256x224 at a refresh rate of 103 Hz).
+       *  Increased the refresh rate of video mode 2 to 65 Hz.
+       *  Increased the refresh rate of video mode 3 to 120 Hz.
+       *  Added speed throttling used when sound is disabled, and a
+          command-line switch to control it.
diff --git a/Documentation/rel/new.linux b/Documentation/rel/new.linux
new file mode 100644 (file)
index 0000000..abaee9f
--- /dev/null
@@ -0,0 +1,6 @@
+        *  Added a new video mode(256x224 at a refresh rate of 103 Hz).
+        *  Increased the refresh rate of video mode 2 to 65 Hz.
+        *  Increased the refresh rate of video mode 3 to 120 Hz.
+        *  Added speed throttling used when sound is disabled, and a
+           command-line switch to control it.
+
diff --git a/Documentation/rel/new.win b/Documentation/rel/new.win
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Documentation/rel/readme-dos.txt b/Documentation/rel/readme-dos.txt
new file mode 100644 (file)
index 0000000..150c566
--- /dev/null
@@ -0,0 +1,646 @@
+                                   FCE Ultra
+                                     0.81
+
+                         http://fceultra.sourceforge.net/
+
+
+What is new:
+
+       *  Screen snapshots can now be taken while playing an NSF.
+       *  Saving screen snapshots will no longer corrupt the frame buffer.
+       *  Added many more games to the list of games that usually are found
+          with bad iNES headers.
+       *  The NSF player will now disable the FDS sound channel on song
+          initialization(fixes a problem with the Zelda no Densetsu
+          rip).
+       *  Reads from $4090 and $4092 while emulating the FDS will now return
+          the current envelope settings.  Affects "Ai Senshi Nicole" 
+          and "Bio Miracle Bokutte Upa", at least.
+       *  Merged a lot of pirate MMC3 multicart emulation code with the main
+          MMC3 emulation code.
+       *  Added support for the MMC5's split-screen mode.  This fixes the
+          introduction in "Uchuu Keibitai SDF".
+       *  Writes to $8000-$FFFF with D7 set during MMC1 emulation will
+          cause the MMC1 mode register to be OR'd with $C.  This fixes
+          "Robocop 3".
+       *  Replaced an MMC1 hack that I used to get "Bill and Ted's Excellent
+          Video Game Adventure" to work with something more accurate.
+       *  Fixed the MMC5 read handler to return the data last on the data
+          bus instead of $FF when a read occured to an unmapped address.
+          This fixes the lockup problem in "Bandit Kings of Ancient China"
+          and possibly other games.
+       *  Added support for the game "Ishin no Arashi" in the iNES format
+          (I added an entry with its CRC32 value and the number of 8KB
+           WRAM banks it needs into the MMC5 WRAM size table).
+       *  Added support for MMC1 games in the iNES format with 16KB of RAM
+           via CRC32 comparisons(currently only Genghis Khan(USA), Romance
+          of the 3 Kingdoms(USA), and Nobunaga's Ambition(USA and Japan) are 
+           recognized).
+       *  iNES mapper 1 now supports pageable CHR RAM if CHR ROM is not
+          present.  Fixes "Family School".
+       *  Added support for iNES mappers 51 and 52.  Thanks to Kevin Horton
+          for the information.
+       *  Modified MMC3(iNES mapper 4/118/119) IRQ counter emulation.  Fixes
+          problems in "MegaMan 3", "Gun Nac", and the Japanese version of
+          "Klax", but it *might* cause problems with other games.
+       *  Fixed an iNES mapper 32 emulation bug.  "Ai Sensei no Oshiete"
+          works now.
+       *  Fixed iNES mapper 33/48 IRQ emulation.
+       *  Fixed iNES mapper 16 IRQ emulation.
+       *  Added support for "Famicom Jump 2" as iNES mapper 153.
+           If a good(as far as I can tell) dump is loaded, FCE Ultra will
+           automatically fix the mapper number.
+       *  The VS Unisystem bit in iNES headers is no longer recognized.
+          Too many games have this bit set when it shouldn't be set.
+          Now VS Unisystem games are recognized by CRC32 value.
+       *  Reads from $4015 no longer reset DMC IRQ.  This fixes the
+          title screen of "Romancia".
+       *  PPU NMI now occurs a few cycles later.  Fixes the "BattleToads"
+          lockup problem.
+       *  BRK emulation now sets the I flag.
+       *  Changed a few zero-page address mode functions to read directly
+          from emulated RAM.
+       *  Added a new video mode(256x224 at a refresh rate of 103 Hz).
+       *  Increased the refresh rate of video mode 2 to 65 Hz.
+       *  Increased the refresh rate of video mode 3 to 120 Hz.
+       *  Added speed throttling used when sound is disabled, and a
+          command-line switch to control it.
+
+
+Contents:
+
+  1.  Basic information
+        1.0 What FCE Ultra is.
+        1.1 System requirements.
+  2.  How to use
+        2.0 Starting FCE Ultra
+        2.1 Using FCE Ultra
+  3.  Notes
+        3.0 Platform Specific Notes
+        3.2 VS Unisystem Notes
+        3.3 Famicom Disk System Notes
+        3.4 Light Gun Notes
+        3.5 Palette Notes
+        3.6 Compressed File Notes
+       3.7 Game Genie Notes
+  4.  Extra
+        4.0 Contacting the author
+        4.1 Credits
+
+/******************************************************************************/
+/*  1.0)       What FCE Ultra is:                                            */
+/******************************************************************************/
+
+        FCE Ultra is an NTSC and PAL Famicom/NES emulator for various 
+        platforms. It is based upon Bero's original FCE source code.  Current
+       features include good PPU, CPU, pAPU, expansion chip, and joystick
+       emulation.  Also a feature unique to this emulator(at the current
+        time) is authentic Game Genie emulation.  Save states and snapshot
+       features also have been implemented.  The VS Unisystem is emulated
+        as well.  FCE Ultra supports iNES format ROM images, UNIF format ROM
+       images, headerless and FWNES style FDS disk images, and NSF files.
+
+        FCE Ultra currently supports the following iNES mappers(many partially):
+
+Number:         Description:                    Game Examples:
+--------------------------------------------------------------------------------
+  0             No Mapper                       Donkey Kong, Mario Bros
+  1             Nintendo MMC1                   MegaMan 2, Final Fantasy
+  2             Simple 16KB PRG Switch          MegaMan 1, Archon, 1944
+  3             Simple 8KB CHR Switch           Spy Hunter, Gradius
+  4             Nintendo MMC3                   Recca, TMNT 2, Final Fantasy 3
+  5             Nintendo MMC5                   Castlevania 3, Just Breed, Uchuu Keibitai SDF
+  6             FFE F4 Series(hacked)           Saint Seiya, Ganbare Goemon
+  7             AOROM                           Battle Toads, Lion King
+  8             FFE F3 Series(hacked)           Doraemon Kaitakuhen
+  9             Nintendo MMC2                   Punchout!
+ 10             Nintendo MMC4                   Fire Emblem, Fire Emblem Gaiden
+ 11             Color Dreams                    Crystal Mines, Bible Adventures
+ 13             CPROM                           Videomation
+ 15             Multi-cart(pirate)              100-in-1: Contra Function 16
+ 16             Bandai                          Dragon Ball Z, Gundam Knight
+ 17             FFE F8 Series(hacked)           Parodius, Last Armageddon
+ 18             Jaleco SS806                    Pizza Pop, Plazma Ball
+ 19             Namco 106                       Splatter House, Mappy Kids                
+ 21             Konami VRC4 2A                  WaiWai World 2, Ganbare Goemon Gaiden 2
+ 22             Konami VRC4 1B                  Twinbee 3
+ 23             Konami VRC2B                    WaiWai World, Getsufuu Maden
+ 24             Konami VRC6                     Akumajo Densetsu(Dracula 3)
+ 25             Konami VRC4                     Gradius 2, Bio Miracle: Boku tte Upa
+ 26             Konami VRC6 A0-A1 Inverse       Esper Dream 2, Madara
+ 32             Irem G-101                      Image Fight 2, Perman
+ 33             Taito TC0190/TC0350             Don Doko Don 1&2
+ 34             NINA-001 and BNROM             Impossible Mission 2, Deadly Towers, Bug Honey
+ 40             (pirate)                        Super Mario Bros. 2
+ 41             Caltron 6-in-1                  Caltron 6-in-1
+ 42            (pirate)                        "Mario Baby"
+ 43            Multi-cart(pirate)              Golden Game 150 in 1
+ 44            Multi-cart(pirate)              Super HiK 7 in 1        
+ 45            Multi-cart(pirate)              Super 1000000 in 1
+ 46            Game Station                    Rumble Station
+ 47            NES-QJ                          Nintendo World Cup/Super Spike V.B.
+ 48            Taito TC190V                    Flintstones
+ 49             Multi-cart(pirate)              Super HiK 4 in 1
+ 51            Multi-cart(pirate)              11 in 1 Ball Games
+ 52            Multi-cart(pirate)              Mario Party 7 in 1
+ 64             Tengen RAMBO-1                  Shinobi, Klax
+ 65             Irem H-3001                     Daiku no Gensan 2
+ 66             GNROM                           SMB + Duck Hunt
+ 67             Sunsoft Mapper "3"              Fantasy Zone 2
+ 68             Sunsoft Mapper "4"              After Burner 2, Nantetta Baseball 
+ 69             Sunsoft FME-7                   Batman: ROTJ, Gimmick!
+ 70            ??                              Kamen Rider Club
+ 71             Camerica                        Fire Hawk, Linus Spacehead
+ 72            Jaleco ??                       Pinball Quest
+ 73             Konami VRC3                     Salamander
+ 75             Jaleco SS8805/Konami VRC1       Tetsuwan Atom, King Kong 2
+ 76             Namco 109                       Megami Tenshi 1
+ 77             Irem ??                         Napoleon Senki
+ 78             Irem 74HC161/32                 Holy Diver
+ 79             NINA-06                                F15 City War, Krazy Kreatures
+ 80             Taito X-005                     Minelvation Saga
+ 82            Taito ??                        Kyuukyoku Harikiri Stadium - Heisei Gannen Ban                  
+ 83            Multi-cart(pirate)              Dragon Ball Party
+ 85             Konami VRC7                     Lagrange Point
+ 86            Jaleco ??                       More Pro Baseball
+ 87            ??                              Argus
+ 89            Sunsoft ??                      Mito Koumon
+ 90            Pirate                          Super Mario World, Mortal Kombat
+ 92             Jaleco ??                       MOERO Pro Soccer, MOERO Pro Yakyuu '88
+ 93            ??                              Fantasy Zone
+ 94            ??                              Senjou no Ookami
+ 95            Namco ??                        Dragon Buster
+ 97            ??                              Kaiketsu Yanchamaru
+ 99             VS System 8KB CHR Switch        VS SMB, VS Excite Bike
+105             NES-EVENT                       Nintendo World Championships
+112             Asder                          Sango Fighter, Hwang Di
+113            MB-91                           Deathbots
+118            MMC3-TLSROM/TKSROM Board        Ys 3, Goal! 2, NES Play Action Football
+119             MMC3-TQROM Board                High Speed, Pin*Bot
+140            Jaleco ??                       Bio Senshi Dan
+151             Konami VS System Expansion      VS The Goonies, VS Gradius
+152            ??                              Arkanoid 2, Saint Seiya Ougon Densetsu
+153             Bandai ??                       Famicom Jump 2
+180             ??                              Crazy Climber
+182            ??                              Super Donkey Kong
+184            ??                              Wing of Madoola, The
+189             Micro Genius TXC ??             Thunder Warrior
+225             Multi-cart(pirate)              58-in-1/110-in-1/52 Games
+226             Multi-cart(pirate)              76-in-1
+227            Multi-cart(pirate)              1200-in-1
+228             Action 52                       Action 52, Cheetahmen 2
+229             Multi-cart(pirate)              31-in-1
+232            BIC-48                          Quattro Arcade, Quattro Sports
+234            Multi-cart ??                   Maxi-15
+240             ??                              Gen Ke Le Zhuan, Shen Huo Le Zhuan
+242            ??                              Wai Xing Zhan Shi
+246            ??                              Fong Shen Ban
+248            ??                              Bao Qing Tian
+250            ??                              Time Diver Avenger
+
+       FCE Ultra currently supports the following UNIF boards(minus the 
+        prefixes HVC-, NES-, BTL-, and BMC-, as they are currently ignored):
+        
+Group: Name:                   Game Examples:
+--------------------------------------------------------------------------------
+Bootleg:
+        MARIO1-MALEE2          Super Mario Bros. Malee 2
+        NovelDiamond9999999in1 Novel Diamond 999999 in 1
+       Super24in1SC03          Super 24 in 1
+        Supervision16in1       Supervision 16-in-1
+
+Unlicensed:
+        Sachen-8259A           Super Cartridge Version 1
+        Sachen-8259B           Silver Eagle
+        Sachen-74LS374N                Auto Upturn
+        SA-016-1M              Master Chu and the Drunkard Hu
+        SA-72007               Sidewinder
+        SA-72008               Jovial Race
+        SA-0036                        Mahjong 16
+        SA-0037                        Mahjong Trap
+       TC-U01-1.5M             Challenge of the Dragon
+
+MMC1:
+       SAROM                   Dragon Warrior
+       SBROM                   Dance Aerobics
+       SCROM                   Orb 3D
+       SEROM                   Boulderdash
+       SGROM                   Defender of the Crown
+       SKROM                   Dungeon Magic
+       SLROM                   Castlevania 2
+       SL1ROM                  Sky Shark
+       SNROM                   Shingen the Ruler
+       SOROM                   Nobunaga's Ambition
+
+MMC3:
+       TFROM                   Legacy of the Wizard
+       TGROM                   Megaman 4
+       TKROM                   Kirby's Adventure
+       TKSROM                  Ys 3
+       TLROM                   Super Spike V'Ball
+       TLSROM                  Goal! 2
+       TR1ROM                  Gauntlet
+       TQROM                   Pinbot
+       TSROM                   Super Mario Bros. 3
+       TVROM                   Rad Racer 2
+
+MMC5:
+       EKROM                   Gemfire
+       ELROM                   Castlevania 3
+       ETROM                   Nobunaga's Ambition 2
+       EWROM                   Romance of the Three Kingdoms 2
+
+MMC6:
+       HKROM                   Star Tropics
+
+Nintendo
+discrete
+logic:
+        CNROM                  Gotcha
+        CPROM                  Videomation
+        MHROM
+        NROM-128               Mario Bros.
+        NROM-256               Super Mario Bros.
+        RROM-128
+        UNROM                  Megaman
+
+
+/******************************************************************************/
+/*  1.1)        System requirements:                                          */
+/******************************************************************************/
+
+        Minimum system requirements:
+
+        Pentium 60 MHz
+        8 MB RAM
+        400 KB free disk space
+        Linux 2.0.36
+        VGA adapter
+
+        Recommended system specifications(at least):
+
+        Pentium 233 MHz
+        16 MB RAM
+        5 MB free disk space
+        Windows 9x/Me/2000/XP(long filename support)
+       VGA adapter
+        Sound Blaster Pro or newer sound card(or compatible)
+
+
+/******************************************************************************/
+/*  2.0) Starting FCE Ultra                                                   */
+/******************************************************************************/
+
+        Start FCE Ultra using the following format:
+
+        fceu <arguments> romimage.nes
+
+        <arguments> can be one or more of the following:
+
+        -vmode x        Select video mode(all are 8 bpp).
+                         1 = 256x240 @ 72 hz   <Default>
+                         2 = 256x256 @ 65 hz
+                         3 = 256x256(with scanlines) @ 120 hz
+                         6 = 256x224(with scanlines) @ 120 hz
+                         8 = 256x224 @ 103 hz
+       -vsync x        Wait for the screen's vertical retrace before updating 
+                       the screen.  This *may* cause sound distortion.
+                        0 = Disabled.  <Default>
+                        1 = Enabled.
+        -cpalette x     Load a custom global palette from file x.
+                        The filename x is saved in the configuration file,
+                        not the data from the file.  Note that you should
+                        probably use an absolute("C:\nes\test.pal") filename
+                        rather than a relative("test.pal") filename.  If x is 0,
+                       the default (built in) global palette will be used.
+        -ntsccol        Emulate an NTSC's TV's colors based on user-supplied
+                        hue and tint values.
+                         0 = Disabled.
+                         1 = Enabled.
+        -sound   x      Sound.         <Default=44100>
+                         0 = Disabled.
+                         Otherwise, x = playback rate in samples per second.
+        -soundvol x     Sound volume. x is an integral percentage value.
+                        The default value is, obviously, 100.
+                        Setting it higher will increase the likelihood that
+                        sound clipping will occur.  This shouldn't be noticeable
+                       if the volume is reasonable(200% or lower; perhaps even
+                        higher for many games).
+        -f8bit x        Force 8-bit sound.  Enabling this will decrease
+                        sound quality noticeably without increasing
+                        performance noticeably.  Only use when 16-bit sound
+                        is problematic.
+                         0 = Disabled. <Default>
+                         1 = Enabled.
+       -nothrottle x   Disables speed throttling used when sound is disabled
+                       if x is non-zero.  The default value of x is 0.
+        -joy x          Joystick mapped to virtual joystick x.
+                         0 = Disabled, reset configuration.
+        -inputx str     Select device mapped to virtual NES-style input port
+                        x(1-2).
+                        The default for both virtual input ports is "gamepad".
+                         str may be: none, gamepad, zapper, powerpada,
+                                     powerpadb, arkanoid
+        -fcexp str      Select Famicom expansion port device.  If you select
+                        a device other than "none", you should enable the
+                        "gamepad" on both NES-style virtual input ports.
+                        The default is "none".
+                         str may be: none, shadow, arkanoid, 4player, fkb
+        -nofs x         Disables Four-Score emulation if x is 1.  Default is 0.
+                        Note that Four-Score emulation will only be active
+                        if "gamepad" is mapped to one or both virtual input
+                        ports.
+       -gg             Enable Game Genie emulation.
+        -pal            Emulate a PAL NES.
+        -no8lim x       Disables the 8 sprites per scanline limitation.
+                         0 = Limitation enabled.       <Default>
+                         1 = Limitation disabled.
+        -subase x       Save extra game data files(such as battery-backed RAM)
+                        under the base directory if enabled.
+                         0 = Disabled. <Default>
+                         1 = Enabled.
+        -snapname x     Selects what type of file name screen snapshots will
+                        have.
+                         0 = Numeric(0.png)     <Default>
+                         1 = File base and numeric(mario-0.png)
+        -clipsides x    Clip leftmost and rightmost 8 columns of pixels of
+                        video output.
+                         0 = Disabled.  <Default>
+                         1 = Enabled.
+        -slstart x      Set the first drawn emulated scanline for NTSC emulation
+                        mode.  Valid values for x are 0 through 239.
+                        The default value is 8.
+        -slend x        Set the last drawn emulated scanline for NTSC emulation
+                        mode. Valid values for x are 0 through 239.
+                        The default value is 239.
+        -slstartp x     Set the first drawn emulated scanline for PAL emulation
+                       mode.  Valid values for x are 0 through 239.  
+                       The default value is 0.
+        -slendp x       Set the last drawn emulated scanline for PAL emulation
+                       mode. Valid values for x are 0 through 239.
+                       The default value is 239.
+
+/******************************************************************************/
+/*  2.1)        General Keyoard Key Mapping:                                  */
+/******************************************************************************/
+
+        Default Key Mapping:
+
+        For emulated Family BASIC Keyboard:
+         Enable/Disable Keyboard Input         Scroll Lock
+               (enabling emulated keyboard input will disable
+                commands keys)
+         All emulated keys are mapped to the closest open key on the PC
+         keyboard, with a few exceptions.  The emulated "@" key is
+         mapped to the "`"(grave) key, and the emulated "kana" key
+         is mapped to the "Insert" key(in the 3x2 key block above the
+         cursor keys).
+
+         For emulated game pads:
+          Left Control             B
+          Left Alt                 A
+          Enter/Return             Start
+          Tab                      Select
+          Cursor Down              Down
+          Cursor Up                Up
+          Cursor Left              Left
+          Cursor Right             Right
+
+         For emulated power pads(keys correspond to button locations on
+         side "B"):
+          O P [ ]
+          K L ; '
+          M , . /
+
+         For FDS games:
+          I                        Insert disk.
+          E                        Eject disk.
+          S                        Select disk/disk side.
+        
+        For VS Unisystem games:
+         C                        Insert coin.
+         V                        Show/Hide dip switches.
+           1-8                      Toggle dip switches(when dip switches 
+                                   are shown).
+
+         T                        Select tint to adjust.
+         H                        Select hue to adjust.
+         +/-                      Increase/decrease tint or hue.
+
+         0-9                      Select save state.
+         Caps Lock                Select virtual joystick.
+
+         F2                       Activate cheat interface.
+
+         F5/F7                    Save/Load state.
+         F9                       Save screen snapshot.
+         F10                      Reset.
+        F11                      Power off/on.
+         ESC/F12                  Exit.
+
+
+/******************************************************************************/
+/*  3.0)        Platform Specific Notes                                       */
+/******************************************************************************/
+
+        FCE Ultra's base directory is the directory in which the executable
+        is located.
+
+        Sound Blaster sound output requires that the 'BLASTER' environment
+        variable is set.  To set it(permanently), add the following line
+        to your autoexec.bat file:
+
+        set BLASTER=A240 I5 D1 H7
+
+        Where 240(hexadecimal) is the Sound Blaster's base I/O address, 5
+        is the IRQ number, 1 is the 8-bit DMA channel, and 7 is the 16-bit
+       DMA channel(if applicable).  
+                       *DO NOT GUESS THE SETTINGS*  
+       Invalid settings can result in very bad things happening.
+
+/******************************************************************************/
+/*  3.2)       VS Unisystem Notes                                            */
+/******************************************************************************/
+
+        FCE Ultra currently only supports VS Unisystem ROM images in the
+        iNES format. 
+
+        ROM Images:
+
+         * VS Unisystem games that are about 49,000 bytes in size most likely
+           use mapper 99.
+         * Other VS Unisystem games will use other mappers.  Here is a short
+           list of games and the mappers they use:
+
+               CastleVania - 2
+               Dr. Mario   - 1
+               Goonies     - 151
+               Gradius     - 151
+              Ice Climber - 99
+               Platoon     - 68
+
+        Palette(s):
+
+         * The colors in many VS Unisystem games may be incorrect.  This
+           is due to each game having its own PPU, and thus using a
+           different palette than games that use a different PPU.
+
+
+/******************************************************************************/
+/*  3.3)        Famicom Disk System Notes                                     */
+/******************************************************************************/
+
+       You will need the FDS BIOS ROM image in the base FCE Ultra directory.
+       It must be named "disksys.rom".  I will not give this file to you, so
+       don't ask.
+
+       Two types of FDS disk images are supported:  disk images with the 
+       FWNES-style header, and disk images with no header.
+
+       You should make backups of all of your FDS games you use with FCE 
+       Ultra.  This is because FCE Ultra will write the disk image back to 
+       the storage medium, and the disk image in RAM might have been corrupted
+        because of inaccurate emulation(this case is not likely to occur, but 
+       it could occur).
+
+
+/******************************************************************************/
+/*  3.4)        Light Gun Notes                                               */
+/******************************************************************************/
+
+       Currently, the NES Zapper and the light gun used with the VS
+       Unisystem(I will call both the same name, Zapper) are supported.
+       Most(all?) NES games expect the Zapper to be plugged into port 2.
+       and most(all?) VS Unisystem games expect the Zapper to be plugged 
+       into port(?) 1.
+
+       The LEFT mouse button is the emulated trigger button for the
+       Zapper.  The RIGHT mouse button is also emulated as the trigger,
+       but as long as you have the RIGHT mouse button held down, no color
+       detection will take place, which is effectively like pulling the
+       trigger while the Zapper is pointed away from the television screen.
+       Note that you must hold the RIGHT button down for a short
+       time(greater than just a fast click, shorter than a second).
+       
+       Zapper emulation currently does NOT work with network play, so
+       don't even try it. I may add support in the future if enough
+       people want it or if I want it.
+
+
+/******************************************************************************/
+/*  3.5)        Palette Notes                                                 */
+/******************************************************************************/
+
+       Palettes files are expected to contain 64 8-bit RGB triplets(each in
+       that order; red comes first in the triplet in the file, then green, 
+       then blue).  Each 8-bit value represents brightness for that particular
+       color.  0 is minimum, 255 is maximum.
+
+       Palettes can be set on a per-game basis.  To do this, put a palette
+       file in the "gameinfo" directory with the same base filename
+       as the game you wish to associate with and the extension "pal".  
+       Examples:
+
+               File name:              Palette file name:
+                BigBad.nes              BigBad.pal
+                BigBad.zip              BigBad.pal
+                BigBad.Better.nes       BigBad.Better.pal
+
+
+        With so many ways to choose a palette, figuring out which one will
+        be active may be difficult.  Here's a list of what palettes will
+        be used, in order from highest priority to least priority(if a condition
+        doesn't exist for a higher priority palette, the emulator will
+        continue down its list of palettes).
+
+        NSF Palette(for NSFs only)
+         Palette loaded from the "gameinfo" directory.
+          NTSC Color Emulation(only for NTSC NES games).
+           VS Unisystem palette(if the game is a VS Unisystem game and a palette
+           is available).
+            Custom global palette.
+             Default NES palette.
+
+
+/******************************************************************************/
+/*  3.6)        Compressed File Notes                                         */
+/******************************************************************************/
+
+        FCE Ultra can load data from both PKZIP-format files and
+        gzip-format files.  Only one type of (de)compression algorithm is
+        supported:  "deflate"; this seems to be the most popular compression
+        algorithm, though.
+
+        A compressed FDS disk image will only be saved back to disk if it
+        uses the gzip format.
+
+        All files in a PKZIP format file will be scanned for the
+        followings extensions:  .nes, .fds, .nsf, .unf, .nez, .unif
+        The first compressed file to have one of these extensions will be
+        loaded. If no compressed file has one of these extensions, the
+        first compressed file will be loaded.
+
+
+/******************************************************************************/
+/*  3.7)        Game Genie Notes                                             */
+/******************************************************************************/
+
+       The Game Genie ROM image is loaded from the file "gg.rom" in the
+       base directory the first time Game Genie emulation is enabled and
+       a ROM image is loaded since the time FCE Ultra has run.
+
+       The ROM image may either be the 24592 byte iNES-format image, or
+       the 4352 raw ROM image.
+
+       Remember that enabling/disabling Game Genie emulation will not take
+       effect until a new game is loaded(this statement shouldn't concern
+       any of the "run once" command-line driven ports).
+
+/******************************************************************************/
+/*  4.0)        Contacting the author                                         */
+/******************************************************************************/
+
+        I can be reached via email at xodnizel@users.sourceforge.net.
+        Bero can be reached via email at 9bero9@geocities.co.jp
+         (Note that Bero can not and will not answer any questions
+          regarding the operation of FCE Ultra, so please don't ask him.
+          If you understand this, remove the 9's from the email address
+         provided to get his real email address.)
+
+
+/******************************************************************************/
+/*  4.1)        Credits                                                       */
+/******************************************************************************/
+
+\Firebug\       -       High-level mapper information.
+Bero            -       Original FCE source code.
+Brad Taylor    -       NES sound channel guide.
+Chris Hickman  -       Archaic Ruins.
+Donald Moore    -       DC PasoFami NES packs.
+Fredrik Olson  -       NES four-player adapter information.
+Gilles Vollant -       PKZIP file loading functions.
+goroh           -       Various documents.
+Jeff Tamer      -       Insaniacal fun.
+Jeremy Chadwick -       General NES information.
+Justin Smith    -       Giving me obscure ROM images in the "dark ages of
+                        NES emulation".
+Kevin Horton    -       Low level NES information and sound information.
+Ki             -       Various technical information.
+Mark Knibbs     -       Various NES information.
+Marat Fayzullin -       General NES information.
+Matthew Conte   -       Sound information.
+N. Andou       -       Awesome NES/SNES emulators, at the time...
+nori           -       FDS sound information.
+Quietust        -       VRC7 sound translation code by The Quietust
+                        (quietust@ircN.org).
+                       Ideas and corrections.
+R. Hoelscher   -       Famicom four-player adapter information.
+Rob Mocca       -       DC PasoFami NES packs, testing.
+Sean Whalen    -       Node99.
+Tatsuyuki Satoh -       OPL2 emulator
+TheRedEye      -       ROM images, testing.
+
+
+Info-ZIP       -       ZLIB
+
+...and everyone else who has helped me.
diff --git a/Documentation/rel/readme-linux.txt b/Documentation/rel/readme-linux.txt
new file mode 100644 (file)
index 0000000..880e919
--- /dev/null
@@ -0,0 +1,707 @@
+                                   FCE Ultra
+                                     0.81
+
+                         http://fceultra.sourceforge.net/
+
+
+What is new:
+
+       *  Screen snapshots can now be taken while playing an NSF.
+       *  Saving screen snapshots will no longer corrupt the frame buffer.
+       *  Added many more games to the list of games that usually are found
+          with bad iNES headers.
+       *  Fixed more network play bugs.  It should now work correctly(how
+          many times have I said or implied that...).
+       *  The NSF player will now disable the FDS sound channel on song
+          initialization(fixes a problem with the Zelda no Densetsu
+          rip).
+       *  Reads from $4090 and $4092 while emulating the FDS will now return
+          the current envelope settings.  Affects "Ai Senshi Nicole" 
+          and "Bio Miracle Bokutte Upa", at least.
+       *  Merged a lot of pirate MMC3 multicart emulation code with the main
+          MMC3 emulation code.
+       *  Added support for the MMC5's split-screen mode.  This fixes the
+          introduction in "Uchuu Keibitai SDF".
+       *  Writes to $8000-$FFFF with D7 set during MMC1 emulation will
+          cause the MMC1 mode register to be OR'd with $C.  This fixes
+          "Robocop 3".
+       *  Replaced an MMC1 hack that I used to get "Bill and Ted's Excellent
+          Video Game Adventure" to work with something more accurate.
+       *  Fixed the MMC5 read handler to return the data last on the data
+          bus instead of $FF when a read occured to an unmapped address.
+          This fixes the lockup problem in "Bandit Kings of Ancient China"
+          and possibly other games.
+       *  Added support for the game "Ishin no Arashi" in the iNES format
+          (I added an entry with its CRC32 value and the number of 8KB
+           WRAM banks it needs into the MMC5 WRAM size table).
+       *  Added support for MMC1 games in the iNES format with 16KB of RAM
+           via CRC32 comparisons(currently only Genghis Khan(USA), Romance
+          of the 3 Kingdoms(USA), and Nobunaga's Ambition(USA and Japan) are 
+           recognized).
+       *  iNES mapper 1 now supports pageable CHR RAM if CHR ROM is not
+          present.  Fixes "Family School".
+       *  Added support for iNES mappers 51 and 52.  Thanks to Kevin Horton
+          for the information.
+       *  Modified MMC3(iNES mapper 4/118/119) IRQ counter emulation.  Fixes
+          problems in "MegaMan 3", "Gun Nac", and the Japanese version of
+          "Klax", but it *might* cause problems with other games.
+       *  Fixed an iNES mapper 32 emulation bug.  "Ai Sensei no Oshiete"
+          works now.
+       *  Fixed iNES mapper 33/48 IRQ emulation.
+       *  Fixed iNES mapper 16 IRQ emulation.
+       *  Added support for "Famicom Jump 2" as iNES mapper 153.
+           If a good(as far as I can tell) dump is loaded, FCE Ultra will
+           automatically fix the mapper number.
+       *  The VS Unisystem bit in iNES headers is no longer recognized.
+          Too many games have this bit set when it shouldn't be set.
+          Now VS Unisystem games are recognized by CRC32 value.
+       *  Reads from $4015 no longer reset DMC IRQ.  This fixes the
+          title screen of "Romancia".
+       *  PPU NMI now occurs a few cycles later.  Fixes the "BattleToads"
+          lockup problem.
+       *  BRK emulation now sets the I flag.
+       *  Changed a few zero-page address mode functions to read directly
+          from emulated RAM.
+        *  Added a new video mode(256x224 at a refresh rate of 103 Hz).
+        *  Increased the refresh rate of video mode 2 to 65 Hz.
+        *  Increased the refresh rate of video mode 3 to 120 Hz.
+        *  Added speed throttling used when sound is disabled, and a
+           command-line switch to control it.
+
+
+
+Contents:
+
+  1.  Basic information
+        1.0 What FCE Ultra is.
+        1.1 System requirements.
+  2.  How to use
+        2.0 Starting FCE Ultra
+        2.1 Using FCE Ultra
+  3.  Notes
+        3.0 Platform Specific Notes
+        3.1 Network Play Notes
+        3.2 VS Unisystem Notes
+        3.3 Famicom Disk System Notes
+        3.4 Light Gun Notes
+        3.5 Palette Notes
+        3.6 Compressed File Notes
+       3.7 Game Genie Notes
+  4.  Extra
+        4.0 Contacting the author
+        4.1 Credits
+
+/******************************************************************************/
+/*  1.0)       What FCE Ultra is:                                            */
+/******************************************************************************/
+
+        FCE Ultra is an NTSC and PAL Famicom/NES emulator for various 
+        platforms. It is based upon Bero's original FCE source code.  Current
+       features include good PPU, CPU, pAPU, expansion chip, and joystick
+       emulation.  Also a feature unique to this emulator(at the current
+        time) is authentic Game Genie emulation.  Save states and snapshot
+       features also have been implemented.  The VS Unisystem is emulated
+        as well.  FCE Ultra supports iNES format ROM images, UNIF format ROM
+       images, headerless and FWNES style FDS disk images, and NSF files.
+
+        FCE Ultra currently supports the following iNES mappers(many partially):
+
+Number:         Description:                    Game Examples:
+--------------------------------------------------------------------------------
+  0             No Mapper                       Donkey Kong, Mario Bros
+  1             Nintendo MMC1                   MegaMan 2, Final Fantasy
+  2             Simple 16KB PRG Switch          MegaMan 1, Archon, 1944
+  3             Simple 8KB CHR Switch           Spy Hunter, Gradius
+  4             Nintendo MMC3                   Recca, TMNT 2, Final Fantasy 3
+  5             Nintendo MMC5                   Castlevania 3, Just Breed, Uchuu Keibitai SDF
+  6             FFE F4 Series(hacked)           Saint Seiya, Ganbare Goemon
+  7             AOROM                           Battle Toads, Lion King
+  8             FFE F3 Series(hacked)           Doraemon Kaitakuhen
+  9             Nintendo MMC2                   Punchout!
+ 10             Nintendo MMC4                   Fire Emblem, Fire Emblem Gaiden
+ 11             Color Dreams                    Crystal Mines, Bible Adventures
+ 13             CPROM                           Videomation
+ 15             Multi-cart(pirate)              100-in-1: Contra Function 16
+ 16             Bandai                          Dragon Ball Z, Gundam Knight
+ 17             FFE F8 Series(hacked)           Parodius, Last Armageddon
+ 18             Jaleco SS806                    Pizza Pop, Plazma Ball
+ 19             Namco 106                       Splatter House, Mappy Kids                
+ 21             Konami VRC4 2A                  WaiWai World 2, Ganbare Goemon Gaiden 2
+ 22             Konami VRC4 1B                  Twinbee 3
+ 23             Konami VRC2B                    WaiWai World, Getsufuu Maden
+ 24             Konami VRC6                     Akumajo Densetsu(Dracula 3)
+ 25             Konami VRC4                     Gradius 2, Bio Miracle: Boku tte Upa
+ 26             Konami VRC6 A0-A1 Inverse       Esper Dream 2, Madara
+ 32             Irem G-101                      Image Fight 2, Perman
+ 33             Taito TC0190/TC0350             Don Doko Don 1&2
+ 34             NINA-001 and BNROM             Impossible Mission 2, Deadly Towers, Bug Honey
+ 40             (pirate)                        Super Mario Bros. 2
+ 41             Caltron 6-in-1                  Caltron 6-in-1
+ 42            (pirate)                        "Mario Baby"
+ 43            Multi-cart(pirate)              Golden Game 150 in 1
+ 44            Multi-cart(pirate)              Super HiK 7 in 1        
+ 45            Multi-cart(pirate)              Super 1000000 in 1
+ 46            Game Station                    Rumble Station
+ 47            NES-QJ                          Nintendo World Cup/Super Spike V.B.
+ 48            Taito TC190V                    Flintstones
+ 49             Multi-cart(pirate)              Super HiK 4 in 1
+ 51            Multi-cart(pirate)              11 in 1 Ball Games
+ 52            Multi-cart(pirate)              Mario Party 7 in 1
+ 64             Tengen RAMBO-1                  Shinobi, Klax
+ 65             Irem H-3001                     Daiku no Gensan 2
+ 66             GNROM                           SMB + Duck Hunt
+ 67             Sunsoft Mapper "3"              Fantasy Zone 2
+ 68             Sunsoft Mapper "4"              After Burner 2, Nantetta Baseball 
+ 69             Sunsoft FME-7                   Batman: ROTJ, Gimmick!
+ 70            ??                              Kamen Rider Club
+ 71             Camerica                        Fire Hawk, Linus Spacehead
+ 72            Jaleco ??                       Pinball Quest
+ 73             Konami VRC3                     Salamander
+ 75             Jaleco SS8805/Konami VRC1       Tetsuwan Atom, King Kong 2
+ 76             Namco 109                       Megami Tenshi 1
+ 77             Irem ??                         Napoleon Senki
+ 78             Irem 74HC161/32                 Holy Diver
+ 79             NINA-06                                F15 City War, Krazy Kreatures
+ 80             Taito X-005                     Minelvation Saga
+ 82            Taito ??                        Kyuukyoku Harikiri Stadium - Heisei Gannen Ban                  
+ 83            Multi-cart(pirate)              Dragon Ball Party
+ 85             Konami VRC7                     Lagrange Point
+ 86            Jaleco ??                       More Pro Baseball
+ 87            ??                              Argus
+ 89            Sunsoft ??                      Mito Koumon
+ 90            Pirate                          Super Mario World, Mortal Kombat
+ 92             Jaleco ??                       MOERO Pro Soccer, MOERO Pro Yakyuu '88
+ 93            ??                              Fantasy Zone
+ 94            ??                              Senjou no Ookami
+ 95            Namco ??                        Dragon Buster
+ 97            ??                              Kaiketsu Yanchamaru
+ 99             VS System 8KB CHR Switch        VS SMB, VS Excite Bike
+105             NES-EVENT                       Nintendo World Championships
+112             Asder                          Sango Fighter, Hwang Di
+113            MB-91                           Deathbots
+118            MMC3-TLSROM/TKSROM Board        Ys 3, Goal! 2, NES Play Action Football
+119             MMC3-TQROM Board                High Speed, Pin*Bot
+140            Jaleco ??                       Bio Senshi Dan
+151             Konami VS System Expansion      VS The Goonies, VS Gradius
+152            ??                              Arkanoid 2, Saint Seiya Ougon Densetsu
+153             Bandai ??                       Famicom Jump 2
+180             ??                              Crazy Climber
+182            ??                              Super Donkey Kong
+184            ??                              Wing of Madoola, The
+189             Micro Genius TXC ??             Thunder Warrior
+225             Multi-cart(pirate)              58-in-1/110-in-1/52 Games
+226             Multi-cart(pirate)              76-in-1
+227            Multi-cart(pirate)              1200-in-1
+228             Action 52                       Action 52, Cheetahmen 2
+229             Multi-cart(pirate)              31-in-1
+232            BIC-48                          Quattro Arcade, Quattro Sports
+234            Multi-cart ??                   Maxi-15
+240             ??                              Gen Ke Le Zhuan, Shen Huo Le Zhuan
+242            ??                              Wai Xing Zhan Shi
+246            ??                              Fong Shen Ban
+248            ??                              Bao Qing Tian
+250            ??                              Time Diver Avenger
+
+       FCE Ultra currently supports the following UNIF boards(minus the 
+        prefixes HVC-, NES-, BTL-, and BMC-, as they are currently ignored):
+        
+Group: Name:                   Game Examples:
+--------------------------------------------------------------------------------
+Bootleg:
+        MARIO1-MALEE2          Super Mario Bros. Malee 2
+        NovelDiamond9999999in1 Novel Diamond 999999 in 1
+       Super24in1SC03          Super 24 in 1
+        Supervision16in1       Supervision 16-in-1
+
+Unlicensed:
+        Sachen-8259A           Super Cartridge Version 1
+        Sachen-8259B           Silver Eagle
+        Sachen-74LS374N                Auto Upturn
+        SA-016-1M              Master Chu and the Drunkard Hu
+        SA-72007               Sidewinder
+        SA-72008               Jovial Race
+        SA-0036                        Mahjong 16
+        SA-0037                        Mahjong Trap
+       TC-U01-1.5M             Challenge of the Dragon
+
+MMC1:
+       SAROM                   Dragon Warrior
+       SBROM                   Dance Aerobics
+       SCROM                   Orb 3D
+       SEROM                   Boulderdash
+       SGROM                   Defender of the Crown
+       SKROM                   Dungeon Magic
+       SLROM                   Castlevania 2
+       SL1ROM                  Sky Shark
+       SNROM                   Shingen the Ruler
+       SOROM                   Nobunaga's Ambition
+
+MMC3:
+       TFROM                   Legacy of the Wizard
+       TGROM                   Megaman 4
+       TKROM                   Kirby's Adventure
+       TKSROM                  Ys 3
+       TLROM                   Super Spike V'Ball
+       TLSROM                  Goal! 2
+       TR1ROM                  Gauntlet
+       TQROM                   Pinbot
+       TSROM                   Super Mario Bros. 3
+       TVROM                   Rad Racer 2
+
+MMC5:
+       EKROM                   Gemfire
+       ELROM                   Castlevania 3
+       ETROM                   Nobunaga's Ambition 2
+       EWROM                   Romance of the Three Kingdoms 2
+
+MMC6:
+       HKROM                   Star Tropics
+
+Nintendo
+discrete
+logic:
+        CNROM                  Gotcha
+        CPROM                  Videomation
+        MHROM
+        NROM-128               Mario Bros.
+        NROM-256               Super Mario Bros.
+        RROM-128
+        UNROM                  Megaman
+
+
+/******************************************************************************/
+/*  1.1)        System requirements:                                          */
+/******************************************************************************/
+
+        Minimum system requirements:
+
+        Pentium 60 MHz
+        8 MB RAM
+        400 KB free disk space
+        Linux 2.0.36
+        VGA adapter
+
+        Recommended system specifications(at least):
+
+        Pentium 233 MHz
+        16 MB RAM
+        5 MB free disk space
+        Linux 2.2.x
+        SVGA adapter with 512 KB of RAM
+        Sound device capable of handling a sample rate of about 44100 hz.
+
+
+/******************************************************************************/
+/*  2.0) Starting FCE Ultra                                                   */
+/******************************************************************************/
+
+        Start FCE Ultra using the following format:
+
+        ./fceu <arguments> romimage.nes
+
+        <arguments> can be one or more of the following:
+
+        -vmode x        Select video mode(all are 8 bpp).
+                         1 = 256x240 @ 72 hz   <Default>
+                         2 = 256x256 @ 65 hz
+                         3 = 256x256(with scanlines) @ 120 hz
+                         4 = 640x480(with scanlines)
+                         5 = 640x480("1 per 4")
+                         6 = 256x224(with scanlines) @ 120 hz
+                        7 = 320x240
+                        8 = 256x224 @ 103 hz
+       -vsync x        Wait for the screen's vertical retrace before updating 
+                       the screen.  If you have sound enabled and enable this,
+                       you may have to increase the number of sound fragments
+                       from the default of 8, to reduce buffer underruns.
+                       Buffer underruns will not be preventable if the 
+                       current video refresh rate is < ~60 hz (or < ~50 hz 
+                       if PAL emulation is enabled).
+                        0 = Disabled.  <Default>
+                        1 = Enabled.
+       -cpalette x     Load a custom global palette from file x.  
+                       The filename x is saved in the configuration file,
+                       not the data from the file.  Note that you should
+                       probably use an absolute("/home/jp/test.pal") filename
+                       rather than a relative("test.pal") filename.  If x is 0,
+                       the default (built in) global palette will be used.
+        -ntsccol        Emulate an NTSC's TV's colors based on user-supplied
+                        hue and tint values.
+                         0 = Disabled. <Default>
+                         1 = Enabled.
+        -sound   x      Sound.          <Default=48000>
+                         0 = Disabled.
+                         Otherwise, x = playback rate in samples per second.
+       -soundvol x     Sound volume. x is an integral percentage value.
+                       The default value is, obviously, 100.
+                       Setting it higher will increase the likelihood that
+                       sound clipping will occur.  This shouldn't be noticeable
+                       if the volume is reasonable(200% or lower; perhaps even
+                       higher for many games).
+       -sfragsize x    Set sound fragment size to 2^x(2 to the power of x)
+                       SAMPLES.  The default value is 7.
+       -snfrags x      Set number of sound fragments to x.  The default value
+                       is 8.
+        -f8bit x        Force 8-bit sound.  Enabling this will decrease
+                        sound quality noticeably without increasing
+                        performance noticeably.  Only use when 16-bit sound
+                        is problematic.
+                         0 = Disabled. <Default>
+                         1 = Enabled.
+        -nothrottle x   Disables speed throttling used when sound is disabled
+                        if x is non-zero.  The default value of x is 0.
+       -joyx y         Joystick mapped to virtual joystick x(1-4).
+                        0 = Disabled, reset configuration.     <Default>
+                        Otherwise, y(1-inf) = joystick number.
+        -inputx str     Select device mapped to virtual NES-style input port 
+                       x(1-2).
+                       The default for both virtual input ports is "gamepad".
+                         str may be: none, gamepad, zapper, powerpada, 
+                                    powerpadb, arkanoid
+       -fcexp str      Select Famicom expansion port device.  If you select
+                       a device other than "none", you should enable the
+                       "gamepad" on both NES-style virtual input ports.
+                       The default is "none".
+                        str may be: none, shadow, arkanoid, 4player, fkb
+       -nofs x         Disables Four-Score emulation if x is 1.  Default is 0.
+                       Note that Four-Score emulation will only be active
+                       if "gamepad" is mapped to one or both virtual input
+                       ports.
+       -gg             Enable Game Genie emulation.
+        -pal            Emulate a PAL NES.
+        -no8lim x       Disables the 8 sprites per scanline limitation.
+                         0 = Limitation enabled.       <Default>
+                         1 = Limitation disabled.
+        -subase x       Save extra game data files(such as battery-backed RAM)
+                        under the base directory if enabled.
+                         0 = Disabled. <Default>
+                         1 = Enabled.
+       -snapname x     Selects what type of file name screen snapshots will 
+                       have.
+                        0 = Numeric(0.png)     <Default>
+                        1 = File base and numeric(mario-0.png)
+       -clipsides x    Clip leftmost and rightmost 8 columns of pixels of 
+                       video output.
+                        0 = Disabled.  <Default>
+                        1 = Enabled.
+        -slstart x      Set the first drawn emulated scanline for NTSC emulation
+                        mode.  Valid values for x are 0 through 239.
+                        The default value is 8.
+        -slend x        Set the last drawn emulated scanline for NTSC emulation
+                        mode. Valid values for x are 0 through 239.
+                        The default value is 239.
+        -slstartp x     Set the first drawn emulated scanline for PAL emulation
+                        mode.  Valid values for x are 0 through 239.
+                        The default value is 0.
+        -slendp x       Set the last drawn emulated scanline for PAL emulation
+                        mode. Valid values for x are 0 through 239.
+                        The default value is 239.
+        -connect   s    Connect to server 's' for TCP/IP network play.
+        -server         Be a host/server for TCP/IP network play.
+       -netport x      Use TCP/IP port x for network play.  The default
+                       port is 4046.
+/******************************************************************************/
+/*  2.1)        General Keyoard Key Mapping:                                  */
+/******************************************************************************/
+
+        Default Key Mapping:
+
+         For emulated Family BASIC Keyboard:
+          Enable/Disable Keyboard Input         Scroll Lock
+                (enabling emulated keyboard input will disable
+                 commands keys)
+          All emulated keys are mapped to the closest open key on the PC
+          keyboard, with a few exceptions.  The emulated "@" key is
+          mapped to the "`"(grave) key, and the emulated "kana" key
+          is mapped to the "Insert" key(in the 3x2 key block above the
+          cursor keys).
+
+         For emulated game pads:
+          Left Control             B
+          Left Alt                 A
+          Enter/Return             Start
+          Tab                      Select
+          Cursor Down              Down
+          Cursor Up                Up
+          Cursor Left              Left
+          Cursor Right             Right
+
+         For emulated power pads(keys correspond to button locations on
+         side "B"):
+          O P [ ]
+          K L ; '
+          M , . /
+
+         For FDS games:
+          I                        Insert disk.
+          E                        Eject disk.
+          S                        Select disk/disk side.
+        
+         For VS Unisystem games:
+          C                        Insert coin.
+          V                        Show/Hide dip switches.
+           1-8                      Toggle dip switches(when dip switches
+                                    are shown).
+
+         T                        Select tint to adjust.
+         H                        Select hue to adjust.
+         +/-                      Increase/decrease tint or hue.
+
+         0-9                      Select save state.
+         Caps Lock                Select virtual joystick.
+
+        F2                       Activate cheat interface.
+
+         F3                       Lock virtual console.
+         F4                       Unlock virtual console.
+
+         F5/F7                    Save/Load state.
+         F9                       Save screen snapshot.
+         F10                      Reset.
+        F11                      Power off/on.
+         ESC/F12                  Exit.
+
+
+/******************************************************************************/
+/*  3.0)        Platform Specific Notes                                       */
+/******************************************************************************/
+
+        1.  FCE Ultra uses SVGAlib, so you'll obviously need to have it
+        installed.
+
+        2.  Be careful when using the non-VGA video modes(such as 640x480).
+        SVGAlib doesn't always handle virtual terminal switching well when
+        one of these modes is being used.  Also, since FCE Ultra enables a
+        a linear frame buffer for these modes, heed this warning from
+        the SVGAlib documentation:
+
+               Furthermore, some cards (Cirrus) just enable  this  buffer
+               at  a  fixed hardware address.  For Cirrus it is mapped at
+               14MB so you should never used it if  you  have  more  than
+               14MB  of  memory (But how does an application know?).  The
+               Mach32 support for this is smarter. It makes this  feature
+               only available when it is safe to be used.
+
+        3.  FCE Ultra must be run as root in order to get access to the
+        VGA hardware.  SVGAlib will drop root privileges if you are running
+        the program as a normal user and the suid root bit is set and the
+        executable is owned by root. Example:
+                chown root fceu ; chmod 4755 fceu
+        Make sure you have the latest stable release of SVGAlib, though.
+
+        4.  FCE Ultra will save all data(state saves/screen snapshots) in
+        ~/.fceultra, so make sure your "HOME" environment variable is set
+        correctly.
+
+        If you believe FCE Ultra is too slow, you can try the following:
+         * Kill some of the other processes.
+         * Disable sound emulation.
+        * Raise the priority of FCE Ultra with the 'nice' command. 
+          Ex:  nice -n -20 ./fceu
+
+/******************************************************************************/
+/*  3.1)        Network Play Notes                                            */
+/******************************************************************************/
+
+        In TCP/IP network play, the server will be player one, and the
+        client will be player 2.
+
+        Zapper emulation and power pad emulation currently do not work with
+        network play.
+
+        Having Game Genie or PAL emulation enabled on only one side
+        will cause problems.
+
+        Both players MUST use the same ROM/disk image and SRAM
+        file(if applicable).
+
+       When using FDS or VS Unisystem games with network play, only player
+       1 will be able to insert disk, eject disk, insert coins, toggle dip
+       switches, etc.
+
+/******************************************************************************/
+/*  3.2)       VS Unisystem Notes                                            */
+/******************************************************************************/
+
+        FCE Ultra currently only supports VS Unisystem ROM images in the
+        iNES format. 
+
+        ROM Images:
+
+         * VS Unisystem games that are about 49,000 bytes in size most likely
+           use mapper 99.
+         * Other VS Unisystem games will use other mappers.  Here is a short
+           list of games and the mappers they use:
+
+               CastleVania - 2
+               Dr. Mario   - 1
+               Goonies     - 151
+               Gradius     - 151
+              Ice Climber - 99
+               Platoon     - 68
+
+        Palette(s):
+
+         * The colors in many VS Unisystem games may be incorrect.  This
+           is due to each game having its own PPU, and thus using a
+           different palette than games that use a different PPU.
+
+
+/******************************************************************************/
+/*  3.3)        Famicom Disk System Notes                                     */
+/******************************************************************************/
+
+       You will need the FDS BIOS ROM image in the base FCE Ultra directory.
+       It must be named "disksys.rom".  I will not give this file to you, so
+       don't ask.
+
+       Two types of FDS disk images are supported:  disk images with the 
+       FWNES-style header, and disk images with no header.
+
+       You should make backups of all of your FDS games you use with FCE 
+       Ultra.  This is because FCE Ultra will write the disk image back to 
+       the storage medium, and the disk image in RAM might have been corrupted
+        because of inaccurate emulation(this case is not likely to occur, but 
+       it could occur).
+
+
+/******************************************************************************/
+/*  3.4)        Light Gun Notes                                               */
+/******************************************************************************/
+
+       Currently, the NES Zapper and the light gun used with the VS
+       Unisystem(I will call both the same name, Zapper) are supported.
+       Most(all?) NES games expect the Zapper to be plugged into port 2.
+       and most(all?) VS Unisystem games expect the Zapper to be plugged 
+       into port(?) 1.
+
+       The LEFT mouse button is the emulated trigger button for the
+       Zapper.  The RIGHT mouse button is also emulated as the trigger,
+       but as long as you have the RIGHT mouse button held down, no color
+       detection will take place, which is effectively like pulling the
+       trigger while the Zapper is pointed away from the television screen.
+       Note that you must hold the RIGHT button down for a short
+       time(greater than just a fast click, shorter than a second).
+       
+       Zapper emulation currently does NOT work with network play, so
+       don't even try it. I may add support in the future if enough
+       people want it or if I want it.
+
+
+/******************************************************************************/
+/*  3.5)        Palette Notes                                                 */
+/******************************************************************************/
+
+       Palettes files are expected to contain 64 8-bit RGB triplets(each in
+       that order; red comes first in the triplet in the file, then green, 
+       then blue).  Each 8-bit value represents brightness for that particular
+       color.  0 is minimum, 255 is maximum.
+
+       Palettes can be set on a per-game basis.  To do this, put a palette
+       file in the "gameinfo" directory with the same base filename
+       as the game you wish to associate with and the extension "pal".  
+       Examples:
+
+               File name:              Palette file name:
+                BigBad.nes              BigBad.pal
+                BigBad.zip              BigBad.pal
+                BigBad.Better.nes       BigBad.Better.pal
+
+
+        With so many ways to choose a palette, figuring out which one will
+        be active may be difficult.  Here's a list of what palettes will
+        be used, in order from highest priority to least priority(if a condition
+        doesn't exist for a higher priority palette, the emulator will
+        continue down its list of palettes).
+
+        NSF Palette(for NSFs only)
+         Palette loaded from the "gameinfo" directory.
+          NTSC Color Emulation(only for NTSC NES games).
+           VS Unisystem palette(if the game is a VS Unisystem game and a palette
+           is available).
+            Custom global palette.
+             Default NES palette.
+
+
+/******************************************************************************/
+/*  3.6)        Compressed File Notes                                         */
+/******************************************************************************/
+
+        FCE Ultra can load data from both PKZIP-format files and
+        gzip-format files.  Only one type of (de)compression algorithm is
+        supported:  "deflate"; this seems to be the most popular compression
+        algorithm, though.
+
+        A compressed FDS disk image will only be saved back to disk if it
+        uses the gzip format.
+
+        All files in a PKZIP format file will be scanned for the
+        followings extensions:  .nes, .fds, .nsf, .unf, .nez, .unif
+        The first compressed file to have one of these extensions will be
+        loaded. If no compressed file has one of these extensions, the
+        first compressed file will be loaded.
+
+
+/******************************************************************************/
+/*  3.7)        Game Genie Notes                                             */
+/******************************************************************************/
+
+       The Game Genie ROM image is loaded from the file "gg.rom" in the
+       base directory the first time Game Genie emulation is enabled and
+       a ROM image is loaded since the time FCE Ultra has run.
+
+       The ROM image may either be the 24592 byte iNES-format image, or
+       the 4352 raw ROM image.
+
+       Remember that enabling/disabling Game Genie emulation will not take
+       effect until a new game is loaded(this statement shouldn't concern
+       any of the "run once" command-line driven ports).
+
+/******************************************************************************/
+/*  4.0)        Contacting the author                                         */
+/******************************************************************************/
+
+        I can be reached via email at xodnizel@users.sourceforge.net.
+        Bero can be reached via email at 9bero9@geocities.co.jp
+         (Note that Bero can not and will not answer any questions
+          regarding the operation of FCE Ultra, so please don't ask him.
+          If you understand this, remove the 9's from the email address
+         provided to get his real email address.)
+
+
+/******************************************************************************/
+/*  4.1)        Credits                                                       */
+/******************************************************************************/
+
+\Firebug\       -       High-level mapper information.
+Bero            -       Original FCE source code.
+Brad Taylor    -       NES sound channel guide.
+Chris Hickman  -       Archaic Ruins.
+Donald Moore    -       DC PasoFami NES packs.
+Fredrik Olson  -       NES four-player adapter information.
+Gilles Vollant -       PKZIP file loading functions.
+goroh           -       Various documents.
+Jeff Tamer      -       Insaniacal fun.
+Jeremy Chadwick -       General NES information.
+Justin Smith    -       Giving me obscure ROM images in the "dark ages of
+                        NES emulation".
+Kevin Horton    -       Low level NES information and sound information.
+Ki             -       Various technical information.
+Mark Knibbs     -       Various NES information.
+Marat Fayzullin -       General NES information.
+Matthew Conte   -       Sound information.
+N. Andou       -       Awesome NES/SNES emulators, at the time...
+nori           -       FDS sound information.
+Quietust        -       VRC7 sound translation code by The Quietust
+                        (quietust@ircN.org).
+                       Ideas and corrections.
+R. Hoelscher   -       Famicom four-player adapter information.
+Rob Mocca       -       DC PasoFami NES packs, testing.
+Sean Whalen    -       Node99.
+Tatsuyuki Satoh -       OPL2 emulator
+TheRedEye      -       ROM images, testing.
+
+
+Info-ZIP       -       ZLIB
+
+...and everyone else who has helped me.
diff --git a/Documentation/rel/readme-win.txt b/Documentation/rel/readme-win.txt
new file mode 100644 (file)
index 0000000..8c4425d
--- /dev/null
@@ -0,0 +1,641 @@
+                                   FCE Ultra
+                                     0.81
+
+                         http://fceultra.sourceforge.net/
+
+
+What is new:
+
+       *  Screen snapshots can now be taken while playing an NSF.
+       *  Saving screen snapshots will no longer corrupt the frame buffer.
+       *  Added many more games to the list of games that usually are found
+          with bad iNES headers.
+       *  Fixed more network play bugs.  It should now work correctly(how
+          many times have I said or implied that...).
+       *  The NSF player will now disable the FDS sound channel on song
+          initialization(fixes a problem with the Zelda no Densetsu
+          rip).
+       *  Reads from $4090 and $4092 while emulating the FDS will now return
+          the current envelope settings.  Affects "Ai Senshi Nicole" 
+          and "Bio Miracle Bokutte Upa", at least.
+       *  Merged a lot of pirate MMC3 multicart emulation code with the main
+          MMC3 emulation code.
+       *  Added support for the MMC5's split-screen mode.  This fixes the
+          introduction in "Uchuu Keibitai SDF".
+       *  Writes to $8000-$FFFF with D7 set during MMC1 emulation will
+          cause the MMC1 mode register to be OR'd with $C.  This fixes
+          "Robocop 3".
+       *  Replaced an MMC1 hack that I used to get "Bill and Ted's Excellent
+          Video Game Adventure" to work with something more accurate.
+       *  Fixed the MMC5 read handler to return the data last on the data
+          bus instead of $FF when a read occured to an unmapped address.
+          This fixes the lockup problem in "Bandit Kings of Ancient China"
+          and possibly other games.
+       *  Added support for the game "Ishin no Arashi" in the iNES format
+          (I added an entry with its CRC32 value and the number of 8KB
+           WRAM banks it needs into the MMC5 WRAM size table).
+       *  Added support for MMC1 games in the iNES format with 16KB of RAM
+           via CRC32 comparisons(currently only Genghis Khan(USA), Romance
+          of the 3 Kingdoms(USA), and Nobunaga's Ambition(USA and Japan) are 
+           recognized).
+       *  iNES mapper 1 now supports pageable CHR RAM if CHR ROM is not
+          present.  Fixes "Family School".
+       *  Added support for iNES mappers 51 and 52.  Thanks to Kevin Horton
+          for the information.
+       *  Modified MMC3(iNES mapper 4/118/119) IRQ counter emulation.  Fixes
+          problems in "MegaMan 3", "Gun Nac", and the Japanese version of
+          "Klax", but it *might* cause problems with other games.
+       *  Fixed an iNES mapper 32 emulation bug.  "Ai Sensei no Oshiete"
+          works now.
+       *  Fixed iNES mapper 33/48 IRQ emulation.
+       *  Fixed iNES mapper 16 IRQ emulation.
+       *  Added support for "Famicom Jump 2" as iNES mapper 153.
+           If a good(as far as I can tell) dump is loaded, FCE Ultra will
+           automatically fix the mapper number.
+       *  The VS Unisystem bit in iNES headers is no longer recognized.
+          Too many games have this bit set when it shouldn't be set.
+          Now VS Unisystem games are recognized by CRC32 value.
+       *  Reads from $4015 no longer reset DMC IRQ.  This fixes the
+          title screen of "Romancia".
+       *  PPU NMI now occurs a few cycles later.  Fixes the "BattleToads"
+          lockup problem.
+       *  BRK emulation now sets the I flag.
+       *  Changed a few zero-page address mode functions to read directly
+          from emulated RAM.
+
+
+Contents:
+
+  1.  Basic information
+        1.0 What FCE Ultra is.
+        1.1 System requirements.
+  2.  How to use
+        2.0 Starting FCE Ultra
+        2.1 Using FCE Ultra
+  3.  Notes
+        3.0 Platform Specific Notes
+        3.1 Network Play Notes
+        3.2 VS Unisystem Notes
+        3.3 Famicom Disk System Notes
+        3.4 Light Gun Notes
+        3.5 Palette Notes
+        3.6 Compressed File Notes
+       3.7 Game Genie Notes
+  4.  Extra
+        4.0 Contacting the author
+        4.1 Credits
+
+/******************************************************************************/
+/*  1.0)       What FCE Ultra is:                                            */
+/******************************************************************************/
+
+        FCE Ultra is an NTSC and PAL Famicom/NES emulator for various 
+        platforms. It is based upon Bero's original FCE source code.  Current
+       features include good PPU, CPU, pAPU, expansion chip, and joystick
+       emulation.  Also a feature unique to this emulator(at the current
+        time) is authentic Game Genie emulation.  Save states and snapshot
+       features also have been implemented.  The VS Unisystem is emulated
+        as well.  FCE Ultra supports iNES format ROM images, UNIF format ROM
+       images, headerless and FWNES style FDS disk images, and NSF files.
+
+        FCE Ultra currently supports the following iNES mappers(many partially):
+
+Number:         Description:                    Game Examples:
+--------------------------------------------------------------------------------
+  0             No Mapper                       Donkey Kong, Mario Bros
+  1             Nintendo MMC1                   MegaMan 2, Final Fantasy
+  2             Simple 16KB PRG Switch          MegaMan 1, Archon, 1944
+  3             Simple 8KB CHR Switch           Spy Hunter, Gradius
+  4             Nintendo MMC3                   Recca, TMNT 2, Final Fantasy 3
+  5             Nintendo MMC5                   Castlevania 3, Just Breed, Uchuu Keibitai SDF
+  6             FFE F4 Series(hacked)           Saint Seiya, Ganbare Goemon
+  7             AOROM                           Battle Toads, Lion King
+  8             FFE F3 Series(hacked)           Doraemon Kaitakuhen
+  9             Nintendo MMC2                   Punchout!
+ 10             Nintendo MMC4                   Fire Emblem, Fire Emblem Gaiden
+ 11             Color Dreams                    Crystal Mines, Bible Adventures
+ 13             CPROM                           Videomation
+ 15             Multi-cart(pirate)              100-in-1: Contra Function 16
+ 16             Bandai                          Dragon Ball Z, Gundam Knight
+ 17             FFE F8 Series(hacked)           Parodius, Last Armageddon
+ 18             Jaleco SS806                    Pizza Pop, Plazma Ball
+ 19             Namco 106                       Splatter House, Mappy Kids                
+ 21             Konami VRC4 2A                  WaiWai World 2, Ganbare Goemon Gaiden 2
+ 22             Konami VRC4 1B                  Twinbee 3
+ 23             Konami VRC2B                    WaiWai World, Getsufuu Maden
+ 24             Konami VRC6                     Akumajo Densetsu(Dracula 3)
+ 25             Konami VRC4                     Gradius 2, Bio Miracle: Boku tte Upa
+ 26             Konami VRC6 A0-A1 Inverse       Esper Dream 2, Madara
+ 32             Irem G-101                      Image Fight 2, Perman
+ 33             Taito TC0190/TC0350             Don Doko Don 1&2
+ 34             NINA-001 and BNROM             Impossible Mission 2, Deadly Towers, Bug Honey
+ 40             (pirate)                        Super Mario Bros. 2
+ 41             Caltron 6-in-1                  Caltron 6-in-1
+ 42            (pirate)                        "Mario Baby"
+ 43            Multi-cart(pirate)              Golden Game 150 in 1
+ 44            Multi-cart(pirate)              Super HiK 7 in 1        
+ 45            Multi-cart(pirate)              Super 1000000 in 1
+ 46            Game Station                    Rumble Station
+ 47            NES-QJ                          Nintendo World Cup/Super Spike V.B.
+ 48            Taito TC190V                    Flintstones
+ 49             Multi-cart(pirate)              Super HiK 4 in 1
+ 51            Multi-cart(pirate)              11 in 1 Ball Games
+ 52            Multi-cart(pirate)              Mario Party 7 in 1
+ 64             Tengen RAMBO-1                  Shinobi, Klax
+ 65             Irem H-3001                     Daiku no Gensan 2
+ 66             GNROM                           SMB + Duck Hunt
+ 67             Sunsoft Mapper "3"              Fantasy Zone 2
+ 68             Sunsoft Mapper "4"              After Burner 2, Nantetta Baseball 
+ 69             Sunsoft FME-7                   Batman: ROTJ, Gimmick!
+ 70            ??                              Kamen Rider Club
+ 71             Camerica                        Fire Hawk, Linus Spacehead
+ 72            Jaleco ??                       Pinball Quest
+ 73             Konami VRC3                     Salamander
+ 75             Jaleco SS8805/Konami VRC1       Tetsuwan Atom, King Kong 2
+ 76             Namco 109                       Megami Tenshi 1
+ 77             Irem ??                         Napoleon Senki
+ 78             Irem 74HC161/32                 Holy Diver
+ 79             NINA-06                                F15 City War, Krazy Kreatures
+ 80             Taito X-005                     Minelvation Saga
+ 82            Taito ??                        Kyuukyoku Harikiri Stadium - Heisei Gannen Ban                  
+ 83            Multi-cart(pirate)              Dragon Ball Party
+ 85             Konami VRC7                     Lagrange Point
+ 86            Jaleco ??                       More Pro Baseball
+ 87            ??                              Argus
+ 89            Sunsoft ??                      Mito Koumon
+ 90            Pirate                          Super Mario World, Mortal Kombat
+ 92             Jaleco ??                       MOERO Pro Soccer, MOERO Pro Yakyuu '88
+ 93            ??                              Fantasy Zone
+ 94            ??                              Senjou no Ookami
+ 95            Namco ??                        Dragon Buster
+ 97            ??                              Kaiketsu Yanchamaru
+ 99             VS System 8KB CHR Switch        VS SMB, VS Excite Bike
+105             NES-EVENT                       Nintendo World Championships
+112             Asder                          Sango Fighter, Hwang Di
+113            MB-91                           Deathbots
+118            MMC3-TLSROM/TKSROM Board        Ys 3, Goal! 2, NES Play Action Football
+119             MMC3-TQROM Board                High Speed, Pin*Bot
+140            Jaleco ??                       Bio Senshi Dan
+151             Konami VS System Expansion      VS The Goonies, VS Gradius
+152            ??                              Arkanoid 2, Saint Seiya Ougon Densetsu
+153             Bandai ??                       Famicom Jump 2
+180             ??                              Crazy Climber
+182            ??                              Super Donkey Kong
+184            ??                              Wing of Madoola, The
+189             Micro Genius TXC ??             Thunder Warrior
+225             Multi-cart(pirate)              58-in-1/110-in-1/52 Games
+226             Multi-cart(pirate)              76-in-1
+227            Multi-cart(pirate)              1200-in-1
+228             Action 52                       Action 52, Cheetahmen 2
+229             Multi-cart(pirate)              31-in-1
+232            BIC-48                          Quattro Arcade, Quattro Sports
+234            Multi-cart ??                   Maxi-15
+240             ??                              Gen Ke Le Zhuan, Shen Huo Le Zhuan
+242            ??                              Wai Xing Zhan Shi
+246            ??                              Fong Shen Ban
+248            ??                              Bao Qing Tian
+250            ??                              Time Diver Avenger
+
+       FCE Ultra currently supports the following UNIF boards(minus the 
+        prefixes HVC-, NES-, BTL-, and BMC-, as they are currently ignored):
+        
+Group: Name:                   Game Examples:
+--------------------------------------------------------------------------------
+Bootleg:
+        MARIO1-MALEE2          Super Mario Bros. Malee 2
+        NovelDiamond9999999in1 Novel Diamond 999999 in 1
+       Super24in1SC03          Super 24 in 1
+        Supervision16in1       Supervision 16-in-1
+
+Unlicensed:
+        Sachen-8259A           Super Cartridge Version 1
+        Sachen-8259B           Silver Eagle
+        Sachen-74LS374N                Auto Upturn
+        SA-016-1M              Master Chu and the Drunkard Hu
+        SA-72007               Sidewinder
+        SA-72008               Jovial Race
+        SA-0036                        Mahjong 16
+        SA-0037                        Mahjong Trap
+       TC-U01-1.5M             Challenge of the Dragon
+
+MMC1:
+       SAROM                   Dragon Warrior
+       SBROM                   Dance Aerobics
+       SCROM                   Orb 3D
+       SEROM                   Boulderdash
+       SGROM                   Defender of the Crown
+       SKROM                   Dungeon Magic
+       SLROM                   Castlevania 2
+       SL1ROM                  Sky Shark
+       SNROM                   Shingen the Ruler
+       SOROM                   Nobunaga's Ambition
+
+MMC3:
+       TFROM                   Legacy of the Wizard
+       TGROM                   Megaman 4
+       TKROM                   Kirby's Adventure
+       TKSROM                  Ys 3
+       TLROM                   Super Spike V'Ball
+       TLSROM                  Goal! 2
+       TR1ROM                  Gauntlet
+       TQROM                   Pinbot
+       TSROM                   Super Mario Bros. 3
+       TVROM                   Rad Racer 2
+
+MMC5:
+       EKROM                   Gemfire
+       ELROM                   Castlevania 3
+       ETROM                   Nobunaga's Ambition 2
+       EWROM                   Romance of the Three Kingdoms 2
+
+MMC6:
+       HKROM                   Star Tropics
+
+Nintendo
+discrete
+logic:
+        CNROM                  Gotcha
+        CPROM                  Videomation
+        MHROM
+        NROM-128               Mario Bros.
+        NROM-256               Super Mario Bros.
+        RROM-128
+        UNROM                  Megaman
+
+
+/******************************************************************************/
+/*  1.1)       System requirements:                                          */
+/******************************************************************************/
+
+        Minimum system specifications:
+
+        Pentium 60 MHz
+        8 MB RAM
+        400 KB free disk space
+       Windows 95
+       DirectX 7.0
+        Video adapter
+
+        Recommended minimum system specifications:
+
+        Pentium 233 MHz
+        16 MB RAM
+        5 MB free disk space
+       Windows 98SE
+        Video adapter with 2D acceleration abilities
+       DirectX 8.0
+       Joystick
+       Mouse
+        Sound device capable of handling a sample rate of 44100 hz.
+
+
+/******************************************************************************/
+/*  2.0)        Starting FCE Ultra                                            */
+/******************************************************************************/
+
+        FCE Ultra can be started by running the executable "fceu.exe".
+        I do not recommend running it from a DOS "box".
+
+
+/******************************************************************************/
+/*  2.1)        Using FCE Ultra:                                              */
+/******************************************************************************/
+
+        After starting FCE Ultra, you'll probably want to load a game.  Do
+        this by going to File/Open.
+
+        Menu descriptions:
+
+        File
+         Open           - Loads a new game.                
+         Save State     - Saves the current NES state.
+         Load State     - Loads a saved NES state.
+         Log Sound As   - Logs sound to a file.  It will not work if sound
+                          is disabled.                               
+         Exit           - Exit the emulator.
+
+        NES
+         Reset          - Resets the virtual NES.
+         Power          - Power cycles the virtual NES.
+         Cheats         - Activates the cheat interface.  See "cheat.txt" for
+                          more details.
+
+        Config
+         Hide Menu      - Hides the menu.
+         Game Genie     - If checked, enable Game Genie emulation.
+                          Game Genie emulation will only begin or end when a new
+                          game is loaded.
+         PAL Emulation  - If checked, enable PAL emulation.  Changes take effect
+                          immediately, though I recommend resetting the virtual
+                          NES afterward PAL emulation is enabled or disabled.  
+         Directories    - Configure the directories that FCE Ultra will store
+                          its files in.
+         Input          - Enter input configuration dialog.
+                          Note that not all virtual devices are configurable.
+         Miscellaneous  - Enter miscellaneous configuration dialog.
+         Network Play   - Enter network play configuration dialog.
+         Palette        - Enter palette configuration dialog.
+         Sound          - Enter sound configuration dialog.
+          Sound enabled:
+                Sound emulation and output are enabled when this is checked.
+          Force 8-bit sound:
+                Forces 8-bit sound output.  Use only when absolutely
+                necessary(very rare).                        
+          Sample rate:
+                Specifies how many sound samples will be played back per
+                second.  Unless you know what you are doing, you probably
+                don't need to change this setting.
+          Use secondary sound buffer:
+                Uses a secondary sound buffer.  This option may be required
+                for sound to work with certain sound cards/devices.
+                Selecting "with global focus" will cause sound to be played
+                while FCE Ultra has lost window focus, but you will probably
+                also want to select "Active While Focus Lost" in the Config
+                menu as well, otherwise you will just get repeating sound
+                when FCE Ultra loses focus.
+          Length of sound buffer:
+                Specifies what length of sound(in milliseconds) should be
+                buffered by FCE Ultra.  DirectSound and the Windows kernel
+                may or may not cause a little more latency than what you
+                might expect(usually not any more than a few milliseconds),
+                depending on your setup.
+                Use larger values if you have sound problems such as popping
+                or gaps, though.  Larger values will increase the latency of
+                the sound, however.  Finally, larger values are ideal for
+                background music listening.
+          Volume:
+                Specifies the volume of FCE Ultra's sound output.  Setting
+                the volume too high MIGHT cause noticeable clipping on some
+                sounds(loud drums, for example), but don't let that possibility
+                stop you from experimenting.
+
+         Video          - Enter video configuration dialog.
+
+        Default Key Mapping:
+
+         For emulated Family BASIC Keyboard:
+          Enable/Disable Keyboard Input         Scroll Lock
+                (enabling emulated keyboard input will disable
+                 commands keys)
+          All emulated keys are mapped to the closest open key on the PC
+          keyboard, with a few exceptions.  The emulated "@" key is
+          mapped to the "`"(grave) key, and the emulated "kana" key
+          is mapped to the "Insert" key(in the 3x2 key block above the
+          cursor keys).
+
+         For emulated game pads:
+          Left Control             B
+          Left Alt                 A
+          Enter/Return             Start
+          Tab                      Select
+          Cursor Down              Down
+          Cursor Up                Up
+          Cursor Left              Left
+          Cursor Right             Right
+        
+         For emulated power pads(keys correspond to button locations on
+         side "B"):
+          O P [ ]
+          K L ; '
+          M , . /
+
+         For FDS games:
+          I                        Insert disk.
+          E                        Eject disk.
+          S                        Select disk/disk side.
+
+         For VS Unisystem games:
+          C                        Insert coin.
+          V                        Show/Hide dip switches.
+           1-8                      Toggle dip switches(when dip switches
+                                    are shown).
+
+         0-9                      Select save state.
+      
+         F5/F7                    Save/Load state.
+         F9                       Save screen snapshot.
+
+         F3                       Hide/Show menu.
+         F4                       Toggle between windowed/full screen modes.
+         F10                      Reset.
+         F11                      Power off/on.
+         F12                      Exit.
+
+
+/******************************************************************************/
+/*  3.0)       Platform Specific Notes                                       */
+/******************************************************************************/
+
+        Your desktop color depth must be 16bpp, 24bpp, or 32bpp for FCE Ultra
+        to run properly in windowed mode.
+
+       FCE Ultra's base directory is the directory in which the executable
+       is located.
+
+
+/******************************************************************************/
+/*  3.1)        Network Play Notes                                            */
+/******************************************************************************/
+
+        In TCP/IP network play, the server will be player one, and the
+        client will be player 2.
+
+        Zapper emulation and power pad emulation currently do not work with
+        network play.
+
+        Having Game Genie or PAL emulation enabled on only one side
+        will cause problems.
+
+        Both players MUST use the same ROM/disk image and SRAM
+        file(if applicable).
+
+       When using FDS or VS Unisystem games with network play, only player
+       1 will be able to insert disk, eject disk, insert coins, toggle dip
+       switches, etc.
+
+/******************************************************************************/
+/*  3.2)       VS Unisystem Notes                                            */
+/******************************************************************************/
+
+        FCE Ultra currently only supports VS Unisystem ROM images in the
+        iNES format. 
+
+        ROM Images:
+
+         * VS Unisystem games that are about 49,000 bytes in size most likely
+           use mapper 99.
+         * Other VS Unisystem games will use other mappers.  Here is a short
+           list of games and the mappers they use:
+
+               CastleVania - 2
+               Dr. Mario   - 1
+               Goonies     - 151
+               Gradius     - 151
+              Ice Climber - 99
+               Platoon     - 68
+
+        Palette(s):
+
+         * The colors in many VS Unisystem games may be incorrect.  This
+           is due to each game having its own PPU, and thus using a
+           different palette than games that use a different PPU.
+
+
+/******************************************************************************/
+/*  3.3)        Famicom Disk System Notes                                     */
+/******************************************************************************/
+
+       You will need the FDS BIOS ROM image in the base FCE Ultra directory.
+       It must be named "disksys.rom".  I will not give this file to you, so
+       don't ask.
+
+       Two types of FDS disk images are supported:  disk images with the 
+       FWNES-style header, and disk images with no header.
+
+       You should make backups of all of your FDS games you use with FCE 
+       Ultra.  This is because FCE Ultra will write the disk image back to 
+       the storage medium, and the disk image in RAM might have been corrupted
+        because of inaccurate emulation(this case is not likely to occur, but 
+       it could occur).
+
+
+/******************************************************************************/
+/*  3.4)        Light Gun Notes                                               */
+/******************************************************************************/
+
+       Currently, the NES Zapper and the light gun used with the VS
+       Unisystem(I will call both the same name, Zapper) are supported.
+       Most(all?) NES games expect the Zapper to be plugged into port 2.
+       and most(all?) VS Unisystem games expect the Zapper to be plugged 
+       into port(?) 1.
+
+       The LEFT mouse button is the emulated trigger button for the
+       Zapper.  The RIGHT mouse button is also emulated as the trigger,
+       but as long as you have the RIGHT mouse button held down, no color
+       detection will take place, which is effectively like pulling the
+       trigger while the Zapper is pointed away from the television screen.
+       Note that you must hold the RIGHT button down for a short
+       time(greater than just a fast click, shorter than a second).
+       
+       Zapper emulation currently does NOT work with network play, so
+       don't even try it. I may add support in the future if enough
+       people want it or if I want it.
+
+
+/******************************************************************************/
+/*  3.5)        Palette Notes                                                 */
+/******************************************************************************/
+
+       Palettes files are expected to contain 64 8-bit RGB triplets(each in
+       that order; red comes first in the triplet in the file, then green, 
+       then blue).  Each 8-bit value represents brightness for that particular
+       color.  0 is minimum, 255 is maximum.
+
+       Palettes can be set on a per-game basis.  To do this, put a palette
+       file in the "gameinfo" directory with the same base filename
+       as the game you wish to associate with and the extension "pal".  
+       Examples:
+
+               File name:              Palette file name:
+                BigBad.nes              BigBad.pal
+                BigBad.zip              BigBad.pal
+                BigBad.Better.nes       BigBad.Better.pal
+
+
+        With so many ways to choose a palette, figuring out which one will
+        be active may be difficult.  Here's a list of what palettes will
+        be used, in order from highest priority to least priority(if a condition
+        doesn't exist for a higher priority palette, the emulator will
+        continue down its list of palettes).
+
+        NSF Palette(for NSFs only)
+         Palette loaded from the "gameinfo" directory.
+          NTSC Color Emulation(only for NTSC NES games).
+           VS Unisystem palette(if the game is a VS Unisystem game and a palette
+           is available).
+            Custom global palette.
+             Default NES palette.
+
+
+/******************************************************************************/
+/*  3.6)        Compressed File Notes                                         */
+/******************************************************************************/
+
+        FCE Ultra can load data from both PKZIP-format files and
+        gzip-format files.  Only one type of (de)compression algorithm is
+        supported:  "deflate"; this seems to be the most popular compression
+        algorithm, though.
+
+        A compressed FDS disk image will only be saved back to disk if it
+        uses the gzip format.
+
+        All files in a PKZIP format file will be scanned for the
+        followings extensions:  .nes, .fds, .nsf, .unf, .nez, .unif
+        The first compressed file to have one of these extensions will be
+        loaded. If no compressed file has one of these extensions, the
+        first compressed file will be loaded.
+
+
+/******************************************************************************/
+/*  3.7)        Game Genie Notes                                             */
+/******************************************************************************/
+
+       The Game Genie ROM image is loaded from the file "gg.rom" in the
+       base directory the first time Game Genie emulation is enabled and
+       a ROM image is loaded since the time FCE Ultra has run.
+
+       The ROM image may either be the 24592 byte iNES-format image, or
+       the 4352 raw ROM image.
+
+       Remember that enabling/disabling Game Genie emulation will not take
+       effect until a new game is loaded(this statement shouldn't concern
+       any of the "run once" command-line driven ports).
+
+/******************************************************************************/
+/*  4.0)        Contacting the author                                         */
+/******************************************************************************/
+
+        I can be reached via email at xodnizel@users.sourceforge.net.
+        Bero can be reached via email at 9bero9@geocities.co.jp
+         (Note that Bero can not and will not answer any questions
+          regarding the operation of FCE Ultra, so please don't ask him.
+          If you understand this, remove the 9's from the email address
+         provided to get his real email address.)
+
+
+/******************************************************************************/
+/*  4.1)        Credits                                                       */
+/******************************************************************************/
+
+\Firebug\       -       High-level mapper information.
+Bero            -       Original FCE source code.
+Brad Taylor    -       NES sound channel guide.
+Chris Hickman  -       Archaic Ruins.
+Donald Moore    -       DC PasoFami NES packs.
+Fredrik Olson  -       NES four-player adapter information.
+Gilles Vollant -       PKZIP file loading functions.
+goroh           -       Various documents.
+Jeff Tamer      -       Insaniacal fun.
+Jeremy Chadwick -       General NES information.
+Justin Smith    -       Giving me obscure ROM images in the "dark ages of
+                        NES emulation".
+Kevin Horton    -       Low level NES information and sound information.
+Ki             -       Various technical information.
+Mark Knibbs     -       Various NES information.
+Marat Fayzullin -       General NES information.
+Matthew Conte   -       Sound information.
+N. Andou       -       Awesome NES/SNES emulators, at the time...
+nori           -       FDS sound information.
+Quietust        -       VRC7 sound translation code by The Quietust
+                        (quietust@ircN.org).
+                       Ideas and corrections.
+R. Hoelscher   -       Famicom four-player adapter information.
+Rob Mocca       -       DC PasoFami NES packs, testing.
+Sean Whalen    -       Node99.
+Tatsuyuki Satoh -       OPL2 emulator
+TheRedEye      -       ROM images, testing.
+
+
+Info-ZIP       -       ZLIB
+
+...and everyone else who has helped me.
diff --git a/Documentation/rel/toc b/Documentation/rel/toc
new file mode 100644 (file)
index 0000000..5abafb3
--- /dev/null
@@ -0,0 +1,23 @@
+
+
+Contents:
+
+  1.  Basic information
+        1.0 What FCE Ultra is.
+        1.1 System requirements.
+  2.  How to use
+        2.0 Starting FCE Ultra
+        2.1 Using FCE Ultra
+  3.  Notes
+        3.0 Platform Specific Notes
+        3.1 Network Play Notes
+        3.2 VS Unisystem Notes
+        3.3 Famicom Disk System Notes
+        3.4 Light Gun Notes
+        3.5 Palette Notes
+        3.6 Compressed File Notes
+       3.7 Game Genie Notes
+  4.  Extra
+        4.0 Contacting the author
+        4.1 Credits
+
diff --git a/Documentation/rel/top.dos b/Documentation/rel/top.dos
new file mode 100644 (file)
index 0000000..372f204
--- /dev/null
@@ -0,0 +1,8 @@
+                                   FCE Ultra
+                                     0.81
+
+                         http://fceultra.sourceforge.net/
+
+
+What is new:
+
diff --git a/Documentation/rel/top.linux b/Documentation/rel/top.linux
new file mode 100644 (file)
index 0000000..372f204
--- /dev/null
@@ -0,0 +1,8 @@
+                                   FCE Ultra
+                                     0.81
+
+                         http://fceultra.sourceforge.net/
+
+
+What is new:
+
diff --git a/Documentation/rel/top.win b/Documentation/rel/top.win
new file mode 100644 (file)
index 0000000..372f204
--- /dev/null
@@ -0,0 +1,8 @@
+                                   FCE Ultra
+                                     0.81
+
+                         http://fceultra.sourceforge.net/
+
+
+What is new:
+
diff --git a/Documentation/tech/README.now b/Documentation/tech/README.now
new file mode 100644 (file)
index 0000000..4575e0c
--- /dev/null
@@ -0,0 +1,6 @@
+Many(possibly all) of these documents contain flaws or are incomplete, so
+don't pull out your hair if there are inconsistencies between the documents,
+what's in FCE Ultra, and what you observe.  That's not to say that FCE Ultra
+doesn't have its share of (emulation) flaws, though...
+
+For many more NES-related documents, try http://nesdev.parodius.com
diff --git a/Documentation/tech/README.sound b/Documentation/tech/README.sound
new file mode 100644 (file)
index 0000000..cce9504
--- /dev/null
@@ -0,0 +1,2 @@
+Sound information is in the "cpu" subdirectory, due to the intimate
+relationship between the sound circuitry and the cpu.
diff --git a/Documentation/tech/UNIF_current.txt b/Documentation/tech/UNIF_current.txt
new file mode 100644 (file)
index 0000000..31e17c8
--- /dev/null
@@ -0,0 +1,302 @@
+****************************************************************************
+                   UNIF file format specifications
+                 (Universal NES Image) file format
+
+        Created by Tennessee Carmel-Veilleux (veilleux@ameth.org)
+                    REV 7b, November 28th, 2000
+
+***********THIS IS AN OPEN STANDARD. IT IS OPEN TO SUGGESTIONS**************
+
+Overview 
+-------- 
+The UNIF format is a portable, flexible REPLACEMENT of the NES standard
+(Designed by Marat Fayzullin). It is a chunked file format in the lines of
+the Amiga IFF (LBM), Microsoft RIFF (WAV) and Autodesk 3D studio mesh
+files (3DS). The goal of having a chunked definition is to provide
+flexibility and ease of implementation, as data is described in blocks
+with type IDs referring to them and header information to provide a 
+selective data reading. The format uses symetric data conversion for
+numerical compatibility between the different platforms' byte ordering.
+The ordering used is the 6502 Byte order (Intel), so that no more
+bickering arrises from people who do not appreciate Network Byte Ordering 
+(Motorola). 
+
+***
+The extension suggested for use with this format is .UNF (.UNIF under Operating
+systems which support longer extensions). 
+***
+
+Byte ordering
+-------------
+Byte ordering used throughout the file for DWORDs and WORDs is 6502 Byte
+order. The 6502 byte order is LSB, least significant byte first
+(Little-endian):
+
+ 3 2 1 0 <- Byte order for MSB (Network Byte order, m68k, PowerPC)
+ 0 1 2 3 <- Byte order for LSB (80x86, 6502, Z80)
+
+Care must be taken to convert the WORDs and DWORDs if you are using a
+non-LSB platform (Mac, Amiga, some others).
+
+File format
+-----------
+00h-1Fh : Header
+20h-EOF : Chunks
+
+I can not think of an easier format to describe :)
+
+Header
+------
+The 4-byte header contains the string "UNIF" , NON null-terminated, case
+as written. This is for identification purposes, a little like .NES' "NES^Z"
+It is followed by Revision number and reserved bytes.
+
+Format: 00h-03h: "UNIF" tag identifier
+        04h-07h: DWORD -> Revision number, currently 4
+        08h-1Fh: Reserved for future usage
+
+Sample structure:
+
+structure UNIF_header [
+   char identification[4]; /* MUST be "UNIF" */
+   dword revision; /* Revision number */
+   byte expansion[24];
+];
+
+Chunks
+------
+Each chunks is composed of 3 distinct elements:
+        00h-03h: Chunk ID string
+        04h-07h: DWORD -> Block Length of Data
+        08h-?? : Data
+
+All the chunks are written sequentially in the file. If you do not understand
+a chunk by its ID, simply jump over it using the data length information.
+*** ALL THE CHUNKS ARE OPTIONAL ***
+That means that there are NO mandatory chunks, and you support only the
+ONES YOU WISH, passing over the others while you are interpreting the
+file.
+
+Sample structure:
+
+structure UNIF_chunk [
+   char chunk_ID[4]; /* Chunk identification string. Can also be considered a
+                        number. ASCII format */
+   dword length; /* Data length, in little-endian format */
+];
+
+The different chunks:
+---------------------
+*******************************************************************************
+How chunks are described:
+ID field: Contains the 4-characters string identifier for the chunk
+
+Length: Length of the block. If it is "??", then the block may have
+        variable data size depending on the cartridge.
+
+Revision: First revision in which the chunk appeared. If your reader supports
+          a lower revision, you might be unable to read the chunk, simply pass
+          over it. The Revision used by the cart is written in the header. The
+          number represents the Revision Number of the most recent chunk
+          contained in the file. Example : If you have 5 chunks of revision 1
+          and 2 chunks of revision 4 in the file, the Revision number in the
+          header will be 4.
+
+Description: Complete description of the contents and encoding of the chunk
+*******************************************************************************
+
+ID: [MAPR]
+Length: ?? (Suggested max: 32 chars)
+Revision: 1
+Description: This is supplemental information about the mapper. DO NOT USE
+             A MAPPER NUMBER HERE ! Rather use the BOARD NAME. There is
+             already a list in progress describing each NES cart and the
+             board it uses. The string is NULL-TERMINATED.
+
+examples: N,R,O,M,,0 -> This "No mapper"
+          U,N,R,O,M,0 -> This is (LS161+LS32)
+
+NOTA: This mapper organization suggests that emulators must be rewritten
+to emulate the ACTUAL CARTRIDGE HARDWARE, and not solely a case of another
+mapper number. That means you have to make for UNROM:
+1- Mapper handler (74LS161+74LS32)
+2- CHR-RAM Handler
+
+Those components can be reused, since many boards only have a slight
+difference in them compared to similar ones.
+
+**IT SHOULD BE NOTED THAT**: A board name tells you EVERYTHING there is to
+know about a board. You do not need other chunks to tell you how much RAM
+there is, or if it is VRAM. It is all implied by the board name. A list
+will soon be distributed containing board name information.
+
+Address of board table for North American Games and Board Names description:
+http://www.parodius.com/~veilleux/boardtable.txt
+http://www.parodius.com/~veilleux/boardnames
+
+ID: [READ]
+Length: ??
+Revision: 1
+Description: Commentaries for the user of the ROM image. In the case of a
+homebrew game, this can be very useful to store credit and maker
+information. *** This could be "Incitation to littering". Please do not
+put garbage in there. It is meant for either mapper information or
+licensing information for homebrew games.***
+
+
+ID: [NAME]
+Length: ??
+Revision: 1
+Description: NULL-terminated string containing the name of the game. If not
+             present, use the filename as the name.
+
+ID: [TVCI]
+Length: BYTE
+Revision: 6
+Description:  Television Standards Compatability Information set to: 
+0- Originally NTSC cartridge
+1- Originally PAL cartridge
+2- Does not matter
+NOTE: ALL North American carts that are dumps of the North American
+Version are NTSC. All licensed famicom games are NTSC.
+
+ID: [DINF]
+Length: 204
+Revision: 2
+Description: Dumper information block:
+ structure dumper_info [
+
+   char dumper_name[100]; /* NULL-terminated string containing the name
+                              of the person who dumped the cart. */
+   byte day; /* Day of the month when cartridge was dumped */
+   byte month; /* Month of the year when cartridge was dumped */
+   word year; /* Year during which the cartridge was dumped */
+   char dumper_agent[100]; /* NULL-terminated string containing the name of
+                              the ROM-dumping means used */
+ ]
+
+ID: [CTRL]
+Length: BYTE
+Revision: 7
+Description: Bitfield containing information about the controllers used by the
+cartridge. 
+
+Bit 0: Regular Joypad
+Bit 1: Zapper
+Bit 2: R.O.B
+Bit 3: Arkanoid Controller
+Bit 4: Power Pad
+Bit 5: Four-Score adapter
+Bit 6: Expansion (Do not touch)
+Bit 7: Expansion (Do not touch)
+
+ID: [PCK0] through [PCKF]
+Length: DWORD
+Reivision: 5
+Description: This block contains a 32-bit CRC which can be used to make
+sure that the ROM content matches a checksum when burning on EPROM. This
+block provides a checksum for [PRG0] through [PRGF] inclusively
+
+ID: [CCK0] through [CCKF]
+Length: DWORD
+Reivision: 5
+Description: This block contains a 32-bit CRC which can be used to make
+sure that the ROM content matches a checksum when burning on EPROM. This
+block provides a checksum for [CHR0] through [CHRF] inclusively
+
+ID: [PRG0] through [PRGF]
+Length: ??
+Revision: 4
+Description: Chunks containing the Binary data of the PRG ROM. If there
+are more than 1 PRG chips on the PRG bus, use PRG1, PRG2, PRG4, etc. 
+The way PRGs are handled depends on the mapper and emulator. Most generaly
+(99%), only use PRG0. (Some carts have been witnessed with 8 PRG ROMs).
+
+ID: [CHR0] through [CHRF]
+Length: ??
+Revision: 4
+Description: Chunks containing the binary data of the CHR ROM. If there
+are more than 1 CHR chips on the CHR bus, use CHR1, CHR2, CHR4, etc. The 
+way CHRs are handled depends on the mapper and emulator. Most generaly
+(99%), only CHR0 is used.
+
+ID: [BATR]
+Length: BYTE
+Revision: 5
+Description: The presence of this block indicates that the board indeed
+contains a battery. This is necessary because many boards have the
+capability of a battery (the traces and holes are there), but they only
+use RAM and don't add the battery at manufacturing time. Examples:
+ * SAROM: MMC1B, PRG ROM, CHR ROM, optional 8k of RAM (battery)
+ * SKROM: MMC1B, PRG ROM, CHR ROM, 8k optional RAM (battery)
+
+Both these boards (SAROM and SKROM) can have a battery, but usually they
+don't have it.
+
+ID: [VROR]
+Length: BYTE
+Revision: 5
+Description: This is a VRAM Override. If this chunk is present, then the
+CHR-ROM area will be considered as RAM even if ROM is present. This
+overrides board identification. This is present so that homemade carts
+which use NROM or others and replace the CHR-ROM with CHR-RAM can still be
+interpreted (since NROM is always CHR-ROM in commercial games).
+
+ID: [MIRR]
+Length: BYTE
+Revision: 5
+Description: This chunk tells you how the hardwired mirroring is setup on
+the board. The board name CANNOT tell you (in most cases) what the
+mirroring is, since the all have solder pads to select the mirroring at
+manufacturing time. The following values are legal:
+
+ * $00 - Horizontal Mirroring (Hard Wired)          
+ * $01 - Vertical Mirroring (Hard Wired)            
+ * $02 - Mirror All Pages From $2000 (Hard Wired)   
+ * $03 - Mirror All Pages From $2400 (Hard Wired)  
+ * $04 - Four Screens of VRAM (Hard Wired)              
+ * $05 - Mirroring Controlled By Mapper Hardware   
+
+Conclusion
+----------
+This ends the specification for Revision 6 of UNIF. If you have ANY 
+suggestions to make regarding the UNIF file format, such as chunk ideas or
+modifications, or would like to collaborate to the elaboration and design
+process, e-mail me at veilleux@ameth.org.
+
+A multi-platform C Code Library for UNIF support was made by Evan Teran. It
+is available at http://www.pretendo.org/~proxy/.
+
+[References]
+{.NES file format specifications} by Marat Fayzullin (fms@cs.umd.edu)
+{NESDEV mailing list} by Various authors
+{NES technical documentation} by Jeremy Chadwick (yoshi@parodius.com)
+
+[Credits]
+Neal Tew for his neat emulator and great contribution to the NESdev
+community.
+       
+Jeremy Chadwick (yoshi@parodius.com) for his contribution to the NESdev
+community and great advice over the time.
+
+Mark Knibbs (mark_k@iname.com) for his excellent web site as well as his
+more than honorable contribution to the NES world
+
+Matthew Conte (itsbroke@classicgaming.com) for his CajoNES and Nofrendo
+programs
+
+Michael Iwaniec (mrbananmos@yahoo.com) for his interest in UNIF and
+constructive criticism.
+
+Kevin Horton (khorton@iquest.net) for his proposals and support of
+UNIF. He's also been a fantastic help to me in my learning curve of the
+NES's hardware aspects.
+
+/Firebug/ (firebug@cfl.rr.com) for the ideas brought with NIFF
+
+T. Alex Reed {W1k} (rizen@netzero.net) for suggestions of additions
+to UNIF. He also pointed out some mistakes in the original specifications.
+
+Evan Teran {PrOxY} (emt3734@rit.edu) for making suggestions as well as
+writing a .NES->UNIF converter and the LIB_UNIF library.
diff --git a/Documentation/tech/cpu/4017.txt b/Documentation/tech/cpu/4017.txt
new file mode 100644 (file)
index 0000000..25cb839
--- /dev/null
@@ -0,0 +1,97 @@
+This is an email posted to nesdev by Ki a while back.  I have removed one
+line at the end regarding the B flag of the cpu(the information was 
+incorrect, which Ki noted in a later email).
+
+--------------------------------------------------------------------------------
+
+ By reading Brad's NESSOUND document, we know that there is a
+"frame counter" in the NES/FC APU.  I would like to post
+some more on this.
+
+  The frame counter is reset upon any write to $4017.  It is
+reset at system power-on as well, but is NOT reset upon
+system reset.
+
+  Thanks to Samus Aran, we now know the exact period of the
+PPU's single frame.  In another words, we are now sure that
+the NMI occurs on every 29780 2/3 CPU cycles.
+
+  However, the APU's single frame is NOT 29780 2/3 CPU cycles.
+What I mean by "APU's single frame" here is that it is the
+number of CPU cycles taken between the frame IRQs.
+
+  The APU's single frame seems to be:
+
+    1789772.727... / 60 = 29829 6/11  [CPU CYCLE]
+
+  Below is a simple diagram which shows the difference
+in periods of the PPU's single frame and the APU's.
+
+
+    RESET         29780 2/3 CPU CYCLES          NMI
+PPU   |------------------------------------------|
+      |           29829 6/11 CPU CYCLES          IRQ
+APU   |----------|----------|----------|----------|
+
+
+  Note that if you write $00 to $4017 on every NMI, the frame
+IRQ would NEVER go off even if it is enabled.  This is because
+the the period of NMI is slightly shorter than the period of
+the frame IRQ.  This causes the frame counter to be reset
+before the frame IRQ goes off.
+
+When you write zero to bit 7 of $4017, the frame counter will
+be reset, and the first sound update will be done after 7457 CPU
+cycles (i.e. 29829/4).  2nd update will be done 7457 after that,
+same goes for 3rd update and 4th update, but the frame IRQ occurs
+on 4th update, resetting the frame counter as well.
+
+When you write 1 to bit 7 of $4017, the frame counter will be
+reset, but the first sound update will occur at the same time.
+2nd, 3rd, and 4th update will be done after 7457, 14914, 22371
+CPU cycles after the first update respectively, but the 5th
+update will be 14914 cycles after the 4th update.  This causes
+sound output to last 1.25 times longer than that of bit 7 = 0.
+
+
+$4017W:
+
+o when the MSB of $4017 is 0:
+
+bit7=0
+  |---------|---------|---------|---------|---------|---------|----
+            1st       2nd       3rd       4th    5th(1st)  6th(2nd)
+
+
+o when the MSB of $4017 is 1:
+
+bit7=1
+  |---------|---------|---------|-------------------|---------|----
+  1st       2nd       3rd       4th              5th(1st)  6th(2nd)
+
+
+On 1st, 3rd, 5th, ... updates, the envelope decay and the
+linear counter are updated.
+
+On 2nd, 4th, 6th, ... updates, the envelope decay, the
+linear counter, the length counter, and the frequency sweep
+are updated.
+----
+
+  The original info was provided by goroh, and verified by me.
+However, it could still be wrong.  Please tell me if you
+find anything wrong.
+----
+
+(Correction from my last posting)
+
+  I have checked once again and it turned out that the frame IRQ
+was NOT disabled upon system reset.  What actually prevented the
+frame IRQ to occur after system reset was, in fact, the I flag.
+I checked this flag shortly after system reset (right after stack
+pointer was initialized), and the flag was 1, although I never
+executed "sei" after reset.  Therefore the I flag of the PR2A03G
+is 1 on system reset.
+
+  Thanks Matthew Conte and Samus Aran for pointing out the
+inaccuracy.
diff --git a/Documentation/tech/cpu/6502_cpu.txt b/Documentation/tech/cpu/6502_cpu.txt
new file mode 100644 (file)
index 0000000..938556c
--- /dev/null
@@ -0,0 +1,1537 @@
+#
+# $Id: 6502_cpu.txt,v 1.1 2002/05/21 00:42:27 xodnizel Exp $
+#
+# This file is part of Commodore 64 emulator
+#      and Program Development System.
+#
+# See README for copyright notice
+#
+# This file contains documentation for 6502/6510/8500/8502 instruction set.
+#
+#
+# Written by
+#   John West       (john@ucc.gu.uwa.edu.au)
+#   Marko M\8akel\8a    (msmakela@kruuna.helsinki.fi)
+#
+#
+# $Log: 6502_cpu.txt,v $
+# Revision 1.1  2002/05/21 00:42:27  xodnizel
+# updates
+#
+# Revision 1.8  1994/06/03  19:50:04  jopi
+# Patchlevel 2
+#
+# Revision 1.7  1994/04/15  13:07:04  jopi
+# 65xx Register descriptions added
+#
+# Revision 1.6  1994/02/18  16:09:36  jopi
+#
+# Revision 1.5  1994/01/26  16:08:37  jopi
+# X64 version 0.2 PL 1
+#
+# Revision 1.4  1993/11/10  01:55:34  jopi
+#
+# Revision 1.3  93/06/21  13:37:18  jopi
+#  X64 version 0.2 PL 0
+#
+# Revision 1.2  93/06/21  13:07:15  jopi
+# *** empty log message ***
+#
+#
+
+ Note: To extract the uuencoded ML programs in this article most
+       easily you may use e.g. "uud" by Edwin Kremer ,
+       which extracts them all at once.
+
+
+Documentation for the NMOS 65xx/85xx Instruction Set
+
+        6510 Instructions by Addressing Modes
+        6502 Registers
+        6510/8502 Undocumented Commands
+        Register selection for load and store
+        Decimal mode in NMOS 6500 series
+        6510 features
+        Different CPU types
+        6510 Instruction Timing
+        How Real Programmers Acknowledge Interrupts
+        Memory Management
+        Autostart Code
+        Notes
+        References
+
+
+6510 Instructions by Addressing Modes
+
+off- ++++++++++ Positive ++++++++++  ---------- Negative ----------
+set  00      20      40      60      80      a0      c0      e0      mode
+
++00  BRK     JSR     RTI     RTS     NOP*    LDY     CPY     CPX     Impl/immed
++01  ORA     AND     EOR     ADC     STA     LDA     CMP     SBC     (indir,x)
++02   t       t       t       t      NOP*t   LDX     NOP*t   NOP*t     ? /immed
++03  SLO*    RLA*    SRE*    RRA*    SAX*    LAX*    DCP*    ISB*    (indir,x)
++04  NOP*    BIT     NOP*    NOP*    STY     LDY     CPY     CPX     Zeropage
++05  ORA     AND     EOR     ADC     STA     LDA     CMP     SBC     Zeropage
++06  ASL     ROL     LSR     ROR     STX     LDX     DEC     INC     Zeropage
++07  SLO*    RLA*    SRE*    RRA*    SAX*    LAX*    DCP*    ISB*    Zeropage
+
++08  PHP     PLP     PHA     PLA     DEY     TAY     INY     INX     Implied
++09  ORA     AND     EOR     ADC     NOP*    LDA     CMP     SBC     Immediate
++0a  ASL     ROL     LSR     ROR     TXA     TAX     DEX     NOP     Accu/impl
++0b  ANC**   ANC**   ASR**   ARR**   ANE**   LXA**   SBX**   SBC*    Immediate
++0c  NOP*    BIT     JMP     JMP ()  STY     LDY     CPY     CPX     Absolute
++0d  ORA     AND     EOR     ADC     STA     LDA     CMP     SBC     Absolute
++0e  ASL     ROL     LSR     ROR     STX     LDX     DEC     INC     Absolute
++0f  SLO*    RLA*    SRE*    RRA*    SAX*    LAX*    DCP*    ISB*    Absolute
+
++10  BPL     BMI     BVC     BVS     BCC     BCS     BNE     BEQ     Relative
++11  ORA     AND     EOR     ADC     STA     LDA     CMP     SBC     (indir),y
++12   t       t       t       t       t       t       t       t         ?
++13  SLO*    RLA*    SRE*    RRA*    SHA**   LAX*    DCP*    ISB*    (indir),y
++14  NOP*    NOP*    NOP*    NOP*    STY     LDY     NOP*    NOP*    Zeropage,x
++15  ORA     AND     EOR     ADC     STA     LDA     CMP     SBC     Zeropage,x
++16  ASL     ROL     LSR     ROR     STX  y) LDX  y) DEC     INC     Zeropage,x
++17  SLO*    RLA*    SRE*    RRA*    SAX* y) LAX* y) DCP*    ISB*    Zeropage,x
+
++18  CLC     SEC     CLI     SEI     TYA     CLV     CLD     SED     Implied
++19  ORA     AND     EOR     ADC     STA     LDA     CMP     SBC     Absolute,y
++1a  NOP*    NOP*    NOP*    NOP*    TXS     TSX     NOP*    NOP*    Implied
++1b  SLO*    RLA*    SRE*    RRA*    SHS**   LAS**   DCP*    ISB*    Absolute,y
++1c  NOP*    NOP*    NOP*    NOP*    SHY**   LDY     NOP*    NOP*    Absolute,x
++1d  ORA     AND     EOR     ADC     STA     LDA     CMP     SBC     Absolute,x
++1e  ASL     ROL     LSR     ROR     SHX**y) LDX  y) DEC     INC     Absolute,x
++1f  SLO*    RLA*    SRE*    RRA*    SHA**y) LAX* y) DCP*    ISB*    Absolute,x
+
+        ROR intruction is available on MC650x microprocessors after
+        June, 1976.
+
+        Legend:
+
+        t       Jams the machine
+        *t      Jams very rarely
+        *       Undocumented command
+        **      Unusual operation
+        y)      indexed using Y instead of X
+        ()      indirect instead of absolute
+
+Note that the NOP instructions do have other addressing modes than the
+implied addressing. The NOP instruction is just like any other load
+instruction, except it does not store the result anywhere nor affects the
+flags.
+
+6502 Registers
+
+The NMOS 65xx processors are not ruined with too many registers. In addition
+to that, the registers are mostly 8-bit. Here is a brief description of each
+register:
+
+     PC Program Counter
+          This register points the address from which the next instruction
+          byte (opcode or parameter) will be fetched. Unlike other
+          registers, this one is 16 bits in length. The low and high 8-bit
+          halves of the register are called PCL and PCH, respectively. The
+          Program Counter may be read by pushing its value on the stack.
+          This can be done either by jumping to a subroutine or by causing
+          an interrupt.
+     S Stack pointer
+          The NMOS 65xx processors have 256 bytes of stack memory, ranging
+          from $0100 to $01FF. The S register is a 8-bit offset to the stack
+          page. In other words, whenever anything is being pushed on the
+          stack, it will be stored to the address $0100+S.
+
+          The Stack pointer can be read and written by transfering its value
+          to or from the index register X (see below) with the TSX and TXS
+          instructions.
+     P Processor status
+          This 8-bit register stores the state of the processor. The bits in
+          this register are called flags. Most of the flags have something
+          to do with arithmetic operations.
+
+          The P register can be read by pushing it on the stack (with PHP or
+          by causing an interrupt). If you only need to read one flag, you
+          can use the branch instructions. Setting the flags is possible by
+          pulling the P register from stack or by using the flag set or
+          clear instructions.
+
+          Following is a list of the flags, starting from the 8th bit of the
+          P register (bit 7, value $80):
+               N Negative flag
+                    This flag will be set after any arithmetic operations
+                    (when any of the registers A, X or Y is being loaded
+                    with a value). Generally, the N flag will be copied from
+                    the topmost bit of the register being loaded.
+
+                    Note that TXS (Transfer X to S) is not an arithmetic
+                    operation. Also note that the BIT instruction affects
+                    the Negative flag just like arithmetic operations.
+                    Finally, the Negative flag behaves differently in
+                    Decimal operations (see description below).
+               V oVerflow flag
+                    Like the Negative flag, this flag is intended to be used
+                    with 8-bit signed integer numbers. The flag will be
+                    affected by addition and subtraction, the instructions
+                    PLP, CLV and BIT, and the hardware signal -SO. Note that
+                    there is no SEV instruction, even though the MOS
+                    engineers loved to use East European abbreviations, like
+                    DDR (Deutsche Demokratische Republik vs. Data Direction
+                    Register). (The Russian abbreviation for their former
+                    trade association COMECON is SEV.) The -SO (Set
+                    Overflow) signal is available on some processors, at
+                    least the 6502, to set the V flag. This enables response
+                    to an I/O activity in equal or less than three clock
+                    cycles when using a BVC instruction branching to itself
+                    ($50 $FE).
+
+                    The CLV instruction clears the V flag, and the PLP and
+                    BIT instructions copy the flag value from the bit 6 of
+                    the topmost stack entry or from memory.
+
+                    After a binary addition or subtraction, the V flag will
+                    be set on a sign overflow, cleared otherwise. What is a
+                    sign overflow? For instance, if you are trying to add
+                    123 and 45 together, the result (168) does not fit in a
+                    8-bit signed integer (upper limit 127 and lower limit
+                    -128). Similarly, adding -123 to -45 causes the
+                    overflow, just like subtracting -45 from 123 or 123 from
+                    -45 would do.
+
+                    Like the N flag, the V flag will not be set as expected
+                    in the Decimal mode. Later in this document is a precise
+                    operation description.
+
+                    A common misbelief is that the V flag could only be set
+                    by arithmetic operations, not cleared.
+               1 unused flag
+                    To the current knowledge, this flag is always 1.
+               B Break flag
+                    This flag is used to distinguish software (BRK)
+                    interrupts from hardware interrupts (IRQ or NMI). The B
+                    flag is always set except when the P register is being
+                    pushed on stack when jumping to an interrupt routine to
+                    process only a hardware interrupt.
+
+                    The official NMOS 65xx documentation claims that the BRK
+                    instruction could only cause a jump to the IRQ vector
+                    ($FFFE). However, if an NMI interrupt occurs while
+                    executing a BRK instruction, the processor will jump to
+                    the NMI vector ($FFFA), and the P register will be
+                    pushed on the stack with the B flag set.
+               D Decimal mode flag
+                    This flag is used to select the (Binary Coded) Decimal
+                    mode for addition and subtraction. In most applications,
+                    the flag is zero.
+
+                    The Decimal mode has many oddities, and it operates
+                    differently on CMOS processors. See the description of
+                    the ADC, SBC and ARR instructions below.
+               I Interrupt disable flag
+                    This flag can be used to prevent the processor from
+                    jumping to the IRQ handler vector ($FFFE) whenever the
+                    hardware line -IRQ is active. The flag will be
+                    automatically set after taking an interrupt, so that the
+                    processor would not keep jumping to the interrupt
+                    routine if the -IRQ signal remains low for several clock
+                    cycles.
+               Z Zero flag
+                    The Zero flag will be affected in the same cases than
+                    the Negative flag. Generally, it will be set if an
+                    arithmetic register is being loaded with the value zero,
+                    and cleared otherwise. The flag will behave differently
+                    in Decimal operations.
+               C Carry flag
+                    This flag is used in additions, subtractions,
+                    comparisons and bit rotations. In additions and
+                    subtractions, it acts as a 9th bit and lets you to chain
+                    operations to calculate with bigger than 8-bit numbers.
+                    When subtracting, the Carry flag is the negative of
+                    Borrow: if an overflow occurs, the flag will be clear,
+                    otherwise set. Comparisons are a special case of
+                    subtraction: they assume Carry flag set and Decimal flag
+                    clear, and do not store the result of the subtraction
+                    anywhere.
+
+                    There are four kinds of bit rotations. All of them store
+                    the bit that is being rotated off to the Carry flag. The
+                    left shifting instructions are ROL and ASL. ROL copies
+                    the initial Carry flag to the lowmost bit of the byte;
+                    ASL always clears it. Similarly, the ROR and LSR
+                    instructions shift to the right.
+     A Accumulator
+          The accumulator is the main register for arithmetic and logic
+          operations. Unlike the index registers X and Y, it has a direct
+          connection to the Arithmetic and Logic Unit (ALU). This is why
+          many operations are only available for the accumulator, not the
+          index registers.
+     X Index register X
+          This is the main register for addressing data with indices. It has
+          a special addressing mode, indexed indirect, which lets you to
+          have a vector table on the zero page.
+     Y Index register Y
+          The Y register has the least operations available. On the other
+          hand, only it has the indirect indexed addressing mode that
+          enables access to any memory place without having to use
+          self-modifying code.
+
+6510/8502 Undocumented Commands
+
+-- A brief explanation about what may happen while using don't care states.
+
+        ANE $8B         A = (A | #$EE) & X & #byte
+                        same as
+                        A = ((A & #$11 & X) | ( #$EE & X)) & #byte
+
+                        In real 6510/8502 the internal parameter #$11
+                        may occasionally be #$10, #$01 or even #$00.
+                        This occurs when the video chip starts DMA
+                        between the opcode fetch and the parameter fetch
+                        of the instruction.  The value probably depends
+                        on the data that was left on the bus by the VIC-II.
+
+        LXA $AB         C=Lehti:   A = X = ANE
+                        Alternate: A = X = (A & #byte)
+
+                        TXA and TAX have to be responsible for these.
+
+        SHA $93,$9F     Store (A & X & (ADDR_HI + 1))
+        SHX $9E         Store (X & (ADDR_HI + 1))
+        SHY $9C         Store (Y & (ADDR_HI + 1))
+        SHS $9B         SHA and TXS, where X is replaced by (A & X).
+
+                        Note: The value to be stored is copied also
+                        to ADDR_HI if page boundary is crossed.
+
+        SBX $CB         Carry and Decimal flags are ignored but the
+                        Carry flag will be set in substraction. This
+                        is due to the CMP command, which is executed
+                        instead of the real SBC.
+
+        ARR $6B         This instruction first performs an AND
+                        between the accumulator and the immediate
+                        parameter, then it shifts the accumulator to
+                        the right. However, this is not the whole
+                        truth. See the description below.
+
+Many undocumented commands do not use AND between registers, the CPU
+just throws the bytes to a bus simultaneously and lets the
+open-collector drivers perform the AND. I.e. the command called 'SAX',
+which is in the STORE section (opcodes $A0...$BF), stores the result
+of (A & X) by this way.
+
+More fortunate is its opposite, 'LAX' which just loads a byte
+simultaneously into both A and X.
+
+        $6B  ARR
+
+This instruction seems to be a harmless combination of AND and ROR at
+first sight, but it turns out that it affects the V flag and also has
+a special kind of decimal mode. This is because the instruction has
+inherited some properties of the ADC instruction ($69) in addition to
+the ROR ($6A).
+
+In Binary mode (D flag clear), the instruction effectively does an AND
+between the accumulator and the immediate parameter, and then shifts
+the accumulator to the right, copying the C flag to the 8th bit. It
+sets the Negative and Zero flags just like the ROR would. The ADC code
+shows up in the Carry and oVerflow flags. The C flag will be copied
+from the bit 6 of the result (which doesn't seem too logical), and the
+V flag is the result of an Exclusive OR operation between the bit 6
+and the bit 5 of the result.  This makes sense, since the V flag will
+be normally set by an Exclusive OR, too.
+
+In Decimal mode (D flag set), the ARR instruction first performs the
+AND and ROR, just like in Binary mode. The N flag will be copied from
+the initial C flag, and the Z flag will be set according to the ROR
+result, as expected. The V flag will be set if the bit 6 of the
+accumulator changed its state between the AND and the ROR, cleared
+otherwise.
+
+Now comes the funny part. If the low nybble of the AND result,
+incremented by its lowmost bit, is greater than 5, the low nybble in
+the ROR result will be incremented by 6. The low nybble may overflow
+as a consequence of this BCD fixup, but the high nybble won't be
+adjusted. The high nybble will be BCD fixed in a similar way. If the
+high nybble of the AND result, incremented by its lowmost bit, is
+greater than 5, the high nybble in the ROR result will be incremented
+by 6, and the Carry flag will be set. Otherwise the C flag will be
+cleared.
+
+To help you understand this description, here is a C routine that
+illustrates the ARR operation in Decimal mode:
+
+        unsigned
+           A,  /* Accumulator */
+           AL, /* low nybble of accumulator */
+           AH, /* high nybble of accumulator */
+
+           C,  /* Carry flag */
+           Z,  /* Zero flag */
+           V,  /* oVerflow flag */
+           N,  /* Negative flag */
+
+           t,  /* temporary value */
+           s;  /* value to be ARRed with Accumulator */
+
+        t = A & s;                      /* Perform the AND. */
+
+        AH = t >> 4;                    /* Separate the high */
+        AL = t & 15;                    /* and low nybbles. */
+
+        N = C;                          /* Set the N and */
+        Z = !(A = (t >> 1) | (C << 7)); /* Z flags traditionally */
+        V = (t ^ A) & 64;               /* and V flag in a weird way. */
+
+        if (AL + (AL & 1) > 5)          /* BCD "fixup" for low nybble. */
+          A = (A & 0xF0) | ((A + 6) & 0xF);
+
+        if (C = AH + (AH & 1) > 5)      /* Set the Carry flag. */
+          A = (A + 0x60) & 0xFF;        /* BCD "fixup" for high nybble. */
+
+        $CB  SBX   X <- (A & X) - Immediate
+
+The 'SBX' ($CB) may seem to be very complex operation, even though it
+is a combination of the subtraction of accumulator and parameter, as
+in the 'CMP' instruction, and the command 'DEX'. As a result, both A
+and X are connected to ALU but only the subtraction takes place. Since
+the comparison logic was used, the result of subtraction should be
+normally ignored, but the 'DEX' now happily stores to X the value of
+(A & X) - Immediate.  That is why this instruction does not have any
+decimal mode, and it does not affect the V flag. Also Carry flag will
+be ignored in the subtraction but set according to the result.
+
+ Proof:
+
+begin 644 vsbx
+M`0@9$,D'GL(H-#,IJC(U-JS"*#0T*:HR-@```*D`H#V1*Z`_D2N@09$KJ0>%
+M^QBE^VEZJ+$KH#F1*ZD`2"BI`*(`RP`(:-B@.5$K*4#P`E@`H#VQ*SAI`)$K
+JD-Z@/[$K:0"1*Y#4J2X@TO\XH$&Q*VD`D2N0Q,;[$+188/_^]_:_OK>V
+`
+end
+
+ and
+
+begin 644 sbx
+M`0@9$,D'GL(H-#,IJC(U-JS"*#0T*:HR-@```'BI`*!-D2N@3Y$KH%&1*ZD#
+MA?L8I?M*2)`#J1@LJ3B@29$K:$J0`ZGX+*G8R)$K&/BXJ?2B8\L)AOP(:(7]
+MV#B@3;$KH$\Q*Z!1\2L(1?SP`0!H1?TIM]#XH$VQ*SAI`)$KD,N@3[$K:0"1
+9*Y#!J2X@TO\XH%&Q*VD`D2N0L<;[$))88-#X
+`
+end
+
+These test programs show if your machine is compatible with ours
+regarding the opcode $CB. The first test, vsbx, proves that SBX does
+not affect the V flag. The latter one, sbx, proves the rest of our
+theory. The vsbx test tests 33554432 SBX combinations (16777216
+different A, X and Immediate combinations, and two different V flag
+states), and the sbx test doubles that amount (16777216*4 D and C flag
+combinations). Both tests have run successfully on a C64 and a Vic20.
+They ought to run on C16, +4 and the PET series as well. The tests
+stop with BRK, if the opcode $CB does not work as expected. Successful
+operation ends in RTS. As the tests are very slow, they print dots on
+the screen while running so that you know that the machine has not
+jammed. On computers running at 1 MHz, the first test prints
+approximately one dot every four seconds and a total of 2048 dots,
+whereas the second one prints half that amount, one dot every seven
+seconds.
+
+If the tests fail on your machine, please let us know your processor's
+part number and revision. If possible, save the executable (after it
+has stopped with BRK) under another name and send it to us so that we
+know at which stage the program stopped.
+
+The following program is a Commodore 64 executable that Marko M"akel"a
+developed when trying to find out how the V flag is affected by SBX.
+(It was believed that the SBX affects the flag in a weird way, and
+this program shows how SBX sets the flag differently from SBC.)  You
+may find the subroutine at $C150 useful when researching other
+undocumented instructions' flags. Run the program in a machine
+language monitor, as it makes use of the BRK instruction. The result
+tables will be written on pages $C2 and $C3.
+
+begin 644 sbx-c100
+M`,%XH`",#L&,$,&,$L&XJ8*B@LL7AOL(:(7\N#BM#L$M$,'M$L$(Q?OP`B@`
+M:$7\\`,@4,'N#L'0U.X0P=#/SB#0[A+!T,<``````````````)BJ\!>M#L$M
+L$,'=_\'0":T2P=W_PM`!8,K0Z:T.P2T0P9D`PID`!*T2P9D`PYD`!
+
+Other undocumented instructions usually cause two preceding opcodes
+being executed. However 'NOP' seems to completely disappear from 'SBC'
+code $EB.
+
+The most difficult to comprehend are the rest of the instructions
+located on the '$0B' line.
+
+All the instructions located at the positive (left) side of this line
+should rotate either memory or the accumulator, but the addressing
+mode turns out to be immediate! No problem. Just read the operand, let
+it be ANDed with the accumulator and finally use accumulator
+addressing mode for the instructions above them.
+
+RELIGION_MODE_ON
+/* This part of the document is not accurate.  You can
+   read it as a fairy tale, but do not count on it when
+   performing your own measurements. */
+
+The rest two instructions on the same line, called 'ANE' and 'LXA'
+($8B and $AB respectively) often give quite unpredictable results.
+However, the most usual operation is to store ((A | #$ee) & X & #$nn)
+to accumulator. Note that this does not work reliably in a real 64!
+In the Commodore 128 the opcode $8B uses values 8C, CC, EE, and
+occasionally 0C and 8E for the OR instead of EE,EF,FE and FF used in
+the C64. With a C128 running at 2 MHz #$EE is always used.  Opcode $AB
+does not cause this OR taking place on 8502 while 6510 always performs
+it. Note that this behaviour depends on processor and/or video chip
+revision.
+
+Let's take a closer look at $8B (6510).
+
+        A <- X & D & (A | VAL)
+
+        where VAL comes from this table:
+
+       X high   D high  D low   VAL
+        even     even    ---    $EE (1)
+        even     odd     ---    $EE
+        odd      even    ---    $EE
+        odd      odd      0     $EE
+        odd      odd     not 0  $FE (2)
+
+(1) If the bottom 2 bits of A are both 1, then the LSB of the result may
+    be 0. The values of X and D are different every time I run the test.
+    This appears to be very rare.
+(2) VAL is $FE most of the time. Sometimes it is $EE - it seems to be random,
+    not related to any of the data. This is much more common than (1).
+
+  In decimal mode, VAL is usually $FE.
+
+Two different functions have been discovered for LAX, opcode $AB. One
+is A = X = ANE (see above) and the other, encountered with 6510 and
+8502, is less complicated A = X = (A & #byte). However, according to
+what is reported, the version altering only the lowest bits of each
+nybble seems to be more common.
+
+What happens, is that $AB loads a value into both A and X, ANDing the
+low bit of each nybble with the corresponding bit of the old
+A. However, there are exceptions. Sometimes the low bit is cleared
+even when A contains a '1', and sometimes other bits are cleared. The
+exceptions seem random (they change every time I run the test). Oops -
+that was in decimal mode. Much the same with D=0.
+
+What causes the randomness?  Probably it is that it is marginal logic
+levels - when too much wired-anding goes on, some of the signals get
+very close to the threshold. Perhaps we're seeing some of them step
+over it. The low bit of each nybble is special, since it has to cope
+with carry differently (remember decimal mode). We never see a '0'
+turn into a '1'.
+
+Since these instructions are unpredictable, they should not be used.
+
+There is still very strange instruction left, the one named SHA/X/Y,
+which is the only one with only indexed addressing modes. Actually,
+the commands 'SHA', 'SHX' and 'SHY' are generated by the indexing
+algorithm.
+
+While using indexed addressing, effective address for page boundary
+crossing is calculated as soon as possible so it does not slow down
+operation. As a result, in the case of SHA/X/Y, the address and data
+are processed at the same time making AND between them to take place.
+Thus, the value to be stored by SAX, for example, is in fact (A & X &
+(ADDR_HI + 1)).  On page boundary crossing the same value is copied
+also to high byte of the effective address.
+
+RELIGION_MODE_OFF
+
+
+Register selection for load and store
+
+   bit1 bit0     A  X  Y
+    0    0             x
+    0    1          x
+    1    0       x
+    1    1       x  x
+
+So, A and X are selected by bits 1 and 0 respectively, while
+ ~(bit1|bit0) enables Y.
+
+Indexing is determined by bit4, even in relative addressing mode,
+which is one kind of indexing.
+
+Lines containing opcodes xxx000x1 (01 and 03) are treated as absolute
+after the effective address has been loaded into CPU.
+
+Zeropage,y and Absolute,y (codes 10x1 x11x) are distinquished by bit5.
+
+
+Decimal mode in NMOS 6500 series
+
+  Most sources claim that the NMOS 6500 series sets the N, V and Z
+flags unpredictably when performing addition or subtraction in decimal
+mode. Of course, this is not true. While testing how the flags are
+set, I also wanted to see what happens if you use illegal BCD values.
+
+  ADC works in Decimal mode in a quite complicated way. It is amazing
+how it can do that all in a single cycle. Here's a C code version of
+the instruction:
+
+        unsigned
+           A,  /* Accumulator */
+           AL, /* low nybble of accumulator */
+           AH, /* high nybble of accumulator */
+
+           C,  /* Carry flag */
+           Z,  /* Zero flag */
+           V,  /* oVerflow flag */
+           N,  /* Negative flag */
+
+           s;  /* value to be added to Accumulator */
+
+        AL = (A & 15) + (s & 15) + C;         /* Calculate the lower nybble. */
+
+        AH = (A >> 4) + (s >> 4) + (AL > 15); /* Calculate the upper nybble. */
+
+        if (AL > 9) AL += 6;                  /* BCD fixup for lower nybble. */
+
+        Z = ((A + s + C) & 255 != 0);         /* Zero flag is set just
+                                                 like in Binary mode. */
+
+        /* Negative and Overflow flags are set with the same logic than in
+           Binary mode, but after fixing the lower nybble. */
+
+        N = (AH & 8 != 0);
+        V = ((AH << 4) ^ A) & 128 && !((A ^ s) & 128);
+
+        if (AH > 9) AH += 6;                  /* BCD fixup for upper nybble. */
+
+        /* Carry is the only flag set after fixing the result. */
+
+        C = (AH > 15);
+        A = ((AH << 4) | (AL & 15)) & 255;
+
+  The C flag is set as the quiche eaters expect, but the N and V flags
+are set after fixing the lower nybble but before fixing the upper one.
+They use the same logic than binary mode ADC. The Z flag is set before
+any BCD fixup, so the D flag does not have any influence on it.
+
+Proof: The following test program tests all 131072 ADC combinations in
+       Decimal mode, and aborts with BRK if anything breaks this theory.
+       If everything goes well, it ends in RTS.
+
+begin 600 dadc
+M 0@9",D'GL(H-#,IJC(U-JS"*#0T*:HR-@   'BI&*  A/N$_$B@+)$KH(V1
+M*Q@(I?PI#X7]I?LI#V7]R0J0 FD%J"D/A?VE^RGP9?PI\ C $) ":0^JL @H
+ML ?)H) &""@X:5\X!?V%_0AH*3W@ ! ""8"HBD7[$ JE^T7\, 28"4"H**7[
+M9?S0!)@) J@8N/BE^V7\V A%_= G:(3]1?W0(.;[T(?F_-"#:$D8\ )88*D=
+0&&4KA?NI &4LA?RI.&S[  A%
+
+end
+
+  All programs in this chapter have been successfully tested on a Vic20
+and a Commodore 64 and a Commodore 128D in C64 mode. They should run on
+C16, +4 and on the PET series as well. If not, please report the problem
+to Marko M"akel"a. Each test in this chapter should run in less than a
+minute at 1 MHz.
+
+SBC is much easier. Just like CMP, its flags are not affected by
+the D flag.
+
+Proof:
+
+begin 600 dsbc-cmp-flags
+M 0@9",D'GL(H-#,IJC(U-JS"*#0T*:HR-@   'B@ (3[A/RB XH8:66HL2N@
+M09$KH$R1*XII::BQ*Z!%D2N@4)$K^#BXI?OE_-@(:(7].+BE^^7\"&A%_? !
+5 .;[T./F_-#?RA"_8!@X&#CEY<7%
+
+end
+
+  The only difference in SBC's operation in decimal mode from binary mode
+is the result-fixup:
+
+        unsigned
+           A,  /* Accumulator */
+           AL, /* low nybble of accumulator */
+           AH, /* high nybble of accumulator */
+
+           C,  /* Carry flag */
+           Z,  /* Zero flag */
+           V,  /* oVerflow flag */
+           N,  /* Negative flag */
+
+           s;  /* value to be added to Accumulator */
+
+        AL = (A & 15) - (s & 15) - !C;        /* Calculate the lower nybble. */
+
+        if (AL & 16) AL -= 6;                 /* BCD fixup for lower nybble. */
+
+        AH = (A >> 4) - (s >> 4) - (AL & 16); /* Calculate the upper nybble. */
+
+        if (AH & 16) AH -= 6;                 /* BCD fixup for upper nybble. */
+
+        /* The flags are set just like in Binary mode. */
+
+        C = (A - s - !C) & 256 != 0;
+        Z = (A - s - !C) & 255 != 0;
+        V = ((A - s - !C) ^ s) & 128 && (A ^ s) & 128;
+        N = (A - s - !C) & 128 != 0;
+
+        A = ((AH << 4) | (AL & 15)) & 255;
+
+  Again Z flag is set before any BCD fixup. The N and V flags are set
+at any time before fixing the high nybble. The C flag may be set in any
+phase.
+
+  Decimal subtraction is easier than decimal addition, as you have to
+make the BCD fixup only when a nybble overflows. In decimal addition,
+you had to verify if the nybble was greater than 9. The processor has
+an internal "half carry" flag for the lower nybble, used to trigger
+the BCD fixup. When calculating with legal BCD values, the lower nybble
+cannot overflow again when fixing it.
+So, the processor does not handle overflows while performing the fixup.
+Similarly, the BCD fixup occurs in the high nybble only if the value
+overflows, i.e. when the C flag will be cleared.
+
+  Because SBC's flags are not affected by the Decimal mode flag, you
+could guess that CMP uses the SBC logic, only setting the C flag
+first. But the SBX instruction shows that CMP also temporarily clears
+the D flag, although it is totally unnecessary.
+
+  The following program, which tests SBC's result and flags,
+contains the 6502 version of the pseudo code example above.
+
+begin 600 dsbc
+M 0@9",D'GL(H-#,IJC(U-JS"*#0T*:HR-@   'BI&*  A/N$_$B@+)$KH':1
+M*S@(I?PI#X7]I?LI#^7]L /I!1@I#ZBE_"GPA?VE^RGP"#CE_2GPL KI7RBP
+M#ND/.+ )*+ &Z0^P NE?A/T%_87]*+BE^^7\"&BH.+CXI?OE_-@(1?W0FVB$
+8_47]T)3F^]">YOS0FFA)&- $J3C0B%A@
+
+end
+
+  Obviously the undocumented instructions RRA (ROR+ADC) and ISB
+(INC+SBC) have inherited also the decimal operation from the official
+instructions ADC and SBC. The program droradc proves this statement
+for ROR, and the dincsbc test proves this for ISB. Finally,
+dincsbc-deccmp proves that ISB's and DCP's (DEC+CMP) flags are not
+affected by the D flag.
+
+begin 644 droradc
+M`0@9",D'GL(H-#,IJC(U-JS"*#0T*:HR-@```'BI&*``A/N$_$B@+)$KH(V1
+M*S@(I?PI#X7]I?LI#V7]R0J0`FD%J"D/A?VE^RGP9?PI\`C`$)`":0^JL`@H
+ML`?)H)`&""@X:5\X!?V%_0AH*3W@`!`""8"HBD7[$`JE^T7\,`28"4"H**7[
+M9?S0!)@)`J@XN/BE^R;\9_S8"$7]T"=HA/U%_=`@YOO0A>;\T(%H21CP`EA@
+2J1T892N%^ZD`92R%_*DX;/L`
+`
+end
+
+begin 644 dincsbc
+M`0@9",D'GL(H-#,IJC(U-JS"*#0T*:HR-@```'BI&*``A/N$_$B@+)$KH':1
+M*S@(I?PI#X7]I?LI#^7]L`/I!1@I#ZBE_"GPA?VE^RGP"#CE_2GPL`KI7RBP
+M#ND/.+`)*+`&Z0^P`NE?A/T%_87]*+BE^^7\"&BH.+CXI?O&_.?\V`A%_="9
+::(3]1?W0DN;[T)SF_-"8:$D8T`2I.-"&6&#\
+`
+end
+
+begin 644 dincsbc-deccmp
+M`0@9",D'GL(H-#,IJC(U-JS"*#0T*:HR-@```'B@`(3[A/RB`XH8:7>HL2N@
+M3Y$KH%R1*XII>ZBQ*Z!3D2N@8)$KBFE_J+$KH%61*Z!BD2OX.+BE^^;\Q_S8
+L"&B%_3BXI?OF_,?\"&A%_?`!`.;[T-_F_-#;RA"M8!@X&#CFYL;&Q\?GYP#8
+`
+end
+
+
+6510 features
+
+   o  PHP always pushes the Break (B) flag as a `1' to the stack.
+      Jukka Tapanim"aki claimed in C=lehti issue 3/89, on page 27 that the
+      processor makes a logical OR between the status register's bit 4
+      and the bit 8 of the stack pointer register (which is always 1).
+      He did not give any reasons for this argument, and has refused to clarify
+      it afterwards. Well, this was not the only error in his article...
+
+   o  Indirect addressing modes do not handle page boundary crossing at all.
+      When the parameter's low byte is $FF, the effective address wraps
+      around and the CPU fetches high byte from $xx00 instead of $xx00+$0100.
+      E.g. JMP ($01FF) fetches PCL from $01FF and PCH from $0100,
+      and LDA ($FF),Y fetches the base address from $FF and $00.
+
+   o  Indexed zero page addressing modes never fix the page address on
+      crossing the zero page boundary.
+      E.g. LDX #$01 : LDA ($FF,X) loads the effective address from $00 and $01.
+
+   o  The processor always fetches the byte following a relative branch
+      instruction. If the branch is taken, the processor reads then the
+      opcode from the destination address. If page boundary is crossed, it
+      first reads a byte from the old page from a location that is bigger
+      or smaller than the correct address by one page.
+
+   o  If you cross a page boundary in any other indexed mode,
+      the processor reads an incorrect location first, a location that is
+      smaller by one page.
+
+   o  Read-Modify-Write instructions write unmodified data, then modified
+      (so INC effectively does LDX loc;STX loc;INX;STX loc)
+
+   o  -RDY is ignored during writes
+      (This is why you must wait 3 cycles before doing any DMA --
+      the maximum number of consecutive writes is 3, which occurs
+      during interrupts except -RESET.)
+
+   o  Some undefined opcodes may give really unpredictable results.
+
+   o  All registers except the Program Counter remain unmodified after -RESET.
+      (This is why you must preset D and I flags in the RESET handler.)
+
+
+Different CPU types
+
+The Rockwell data booklet 29651N52 (technical information about R65C00
+microprocessors, dated October 1984), lists the following differences between
+NMOS R6502 microprocessor and CMOS R65C00 family:
+
+
+     1. Indexed addressing across page boundary.
+             NMOS: Extra read of invalid address.
+             CMOS: Extra read of last instruction byte.
+
+
+     2. Execution of invalid op codes.
+             NMOS: Some terminate only by reset. Results are undefined.
+             CMOS: All are NOPs (reserved for future use).
+
+
+     3. Jump indirect, operand = XXFF.
+             NMOS: Page address does not increment.
+             CMOS: Page address increments and adds one additional cycle.
+
+
+     4. Read/modify/write instructions at effective address.
+             NMOS: One read and two write cycles.
+             CMOS: Two read and one write cycle.
+
+
+     5. Decimal flag.
+             NMOS: Indeterminate after reset.
+             CMOS: Initialized to binary mode (D=0) after reset and interrupts.
+
+
+     6. Flags after decimal operation.
+             NMOS: Invalid N, V and Z flags.
+             CMOS: Valid flag adds one additional cycle.
+
+
+     7. Interrupt after fetch of BRK instruction.
+             NMOS: Interrupt vector is loaded, BRK vector is ignored.
+             CMOS: BRK is executed, then interrupt is executed.
+
+
+6510 Instruction Timing
+
+  The NMOS 6500 series processors always perform at least two reads
+for each instruction. In addition to the operation code (opcode), they
+fetch the next byte. This is quite efficient, as most instructions are
+two or three bytes long.
+
+  The processors also use a sort of pipelining. If an instruction does
+not store data in memory on its last cycle, the processor can fetch
+the opcode of the next instruction while executing the last cycle. For
+instance, the instruction EOR #$FF truly takes three cycles. On the
+first cycle, the opcode $49 will be fetched. During the second cycle
+the processor decodes the opcode and fetches the parameter #$FF. On
+the third cycle, the processor will perform the operation and store
+the result to accumulator, but simultaneously it fetches the opcode
+for the next instruction. This is why the instruction effectively
+takes only two cycles.
+
+  The following tables show what happens on the bus while executing
+different kinds of instructions.
+
+  Interrupts
+
+     NMI and IRQ both take 7 cycles. Their timing diagram is much like
+     BRK's (see below). IRQ will be executed only when the I flag is
+     clear. IRQ and BRK both set the I flag, whereas the NMI does not
+     affect its state.
+
+     The processor will usually wait for the current instruction to
+     complete before executing the interrupt sequence. To process the
+     interrupt before the next instruction, the interrupt must occur
+     before the last cycle of the current instruction.
+
+     There is one exception to this rule: the BRK instruction. If a
+     hardware interrupt (NMI or IRQ) occurs before the fourth (flags
+     saving) cycle of BRK, the BRK instruction will be skipped, and
+     the processor will jump to the hardware interrupt vector. This
+     sequence will always take 7 cycles.
+
+     You do not completely lose the BRK interrupt, the B flag will be
+     set in the pushed status register if a BRK instruction gets
+     interrupted. When BRK and IRQ occur at the same time, this does
+     not cause any problems, as your program will consider it as a
+     BRK, and the IRQ would occur again after the processor returned
+     from your BRK routine, unless you cleared the interrupt source in
+     your BRK handler. But the simultaneous occurrence of NMI and BRK
+     is far more fatal. If you do not check the B flag in the NMI
+     routine and subtract two from the return address when needed, the
+     BRK instruction will be skipped.
+
+     If the NMI and IRQ interrupts overlap each other (one interrupt
+     occurs before fetching the interrupt vector for the other
+     interrupt), the processor will most probably jump to the NMI
+     vector in every case, and then jump to the IRQ vector after
+     processing the first instruction of the NMI handler. This has not
+     been measured yet, but the IRQ is very similar to BRK, and many
+     sources state that the NMI has higher priority than IRQ. However,
+     it might be that the processor takes the interrupt that comes
+     later, i.e. you could lose an NMI interrupt if an IRQ occurred in
+     four cycles after it.
+
+     After finishing the interrupt sequence, the processor will start
+     to execute the first instruction of the interrupt routine. This
+     proves that the processor uses a sort of pipelining: it finishes
+     the current instruction (or interrupt sequence) while reading the
+     opcode of the next instruction.
+
+     RESET does not push program counter on stack, and it lasts
+     probably 6 cycles after deactivating the signal. Like NMI, RESET
+     preserves all registers except PC.
+
+  Instructions accessing the stack
+
+     BRK
+
+        #  address R/W description
+       --- ------- --- -----------------------------------------------
+        1    PC     R  fetch opcode, increment PC
+        2    PC     R  read next instruction byte (and throw it away),
+                       increment PC
+        3  $0100,S  W  push PCH on stack (with B flag set), decrement S
+        4  $0100,S  W  push PCL on stack, decrement S
+        5  $0100,S  W  push P on stack, decrement S
+        6   $FFFE   R  fetch PCL
+        7   $FFFF   R  fetch PCH
+
+     RTI
+
+        #  address R/W description
+       --- ------- --- -----------------------------------------------
+        1    PC     R  fetch opcode, increment PC
+        2    PC     R  read next instruction byte (and throw it away)
+        3  $0100,S  R  increment S
+        4  $0100,S  R  pull P from stack, increment S
+        5  $0100,S  R  pull PCL from stack, increment S
+        6  $0100,S  R  pull PCH from stack
+
+     RTS
+
+        #  address R/W description
+       --- ------- --- -----------------------------------------------
+        1    PC     R  fetch opcode, increment PC
+        2    PC     R  read next instruction byte (and throw it away)
+        3  $0100,S  R  increment S
+        4  $0100,S  R  pull PCL from stack, increment S
+        5  $0100,S  R  pull PCH from stack
+        6    PC     R  increment PC
+
+     PHA, PHP
+
+        #  address R/W description
+       --- ------- --- -----------------------------------------------
+        1    PC     R  fetch opcode, increment PC
+        2    PC     R  read next instruction byte (and throw it away)
+        3  $0100,S  W  push register on stack, decrement S
+
+     PLA, PLP
+
+        #  address R/W description
+       --- ------- --- -----------------------------------------------
+        1    PC     R  fetch opcode, increment PC
+        2    PC     R  read next instruction byte (and throw it away)
+        3  $0100,S  R  increment S
+        4  $0100,S  R  pull register from stack
+
+     JSR
+
+        #  address R/W description
+       --- ------- --- -------------------------------------------------
+        1    PC     R  fetch opcode, increment PC
+        2    PC     R  fetch low address byte, increment PC
+        3  $0100,S  R  internal operation (predecrement S?)
+        4  $0100,S  W  push PCH on stack, decrement S
+        5  $0100,S  W  push PCL on stack, decrement S
+        6    PC     R  copy low address byte to PCL, fetch high address
+                       byte to PCH
+
+  Accumulator or implied addressing
+
+        #  address R/W description
+       --- ------- --- -----------------------------------------------
+        1    PC     R  fetch opcode, increment PC
+        2    PC     R  read next instruction byte (and throw it away)
+
+  Immediate addressing
+
+        #  address R/W description
+       --- ------- --- ------------------------------------------
+        1    PC     R  fetch opcode, increment PC
+        2    PC     R  fetch value, increment PC
+
+  Absolute addressing
+
+     JMP
+
+        #  address R/W description
+       --- ------- --- -------------------------------------------------
+        1    PC     R  fetch opcode, increment PC
+        2    PC     R  fetch low address byte, increment PC
+        3    PC     R  copy low address byte to PCL, fetch high address
+                       byte to PCH
+
+     Read instructions (LDA, LDX, LDY, EOR, AND, ORA, ADC, SBC, CMP, BIT,
+                        LAX, NOP)
+
+        #  address R/W description
+       --- ------- --- ------------------------------------------
+        1    PC     R  fetch opcode, increment PC
+        2    PC     R  fetch low byte of address, increment PC
+        3    PC     R  fetch high byte of address, increment PC
+        4  address  R  read from effective address
+
+     Read-Modify-Write instructions (ASL, LSR, ROL, ROR, INC, DEC,
+                                     SLO, SRE, RLA, RRA, ISB, DCP)
+
+        #  address R/W description
+       --- ------- --- ------------------------------------------
+        1    PC     R  fetch opcode, increment PC
+        2    PC     R  fetch low byte of address, increment PC
+        3    PC     R  fetch high byte of address, increment PC
+        4  address  R  read from effective address
+        5  address  W  write the value back to effective address,
+                       and do the operation on it
+        6  address  W  write the new value to effective address
+
+     Write instructions (STA, STX, STY, SAX)
+
+        #  address R/W description
+       --- ------- --- ------------------------------------------
+        1    PC     R  fetch opcode, increment PC
+        2    PC     R  fetch low byte of address, increment PC
+        3    PC     R  fetch high byte of address, increment PC
+        4  address  W  write register to effective address
+
+  Zero page addressing
+
+     Read instructions (LDA, LDX, LDY, EOR, AND, ORA, ADC, SBC, CMP, BIT,
+                        LAX, NOP)
+
+        #  address R/W description
+       --- ------- --- ------------------------------------------
+        1    PC     R  fetch opcode, increment PC
+        2    PC     R  fetch address, increment PC
+        3  address  R  read from effective address
+
+     Read-Modify-Write instructions (ASL, LSR, ROL, ROR, INC, DEC,
+                                     SLO, SRE, RLA, RRA, ISB, DCP)
+
+        #  address R/W description
+       --- ------- --- ------------------------------------------
+        1    PC     R  fetch opcode, increment PC
+        2    PC     R  fetch address, increment PC
+        3  address  R  read from effective address
+        4  address  W  write the value back to effective address,
+                       and do the operation on it
+        5  address  W  write the new value to effective address
+
+     Write instructions (STA, STX, STY, SAX)
+
+        #  address R/W description
+       --- ------- --- ------------------------------------------
+        1    PC     R  fetch opcode, increment PC
+        2    PC     R  fetch address, increment PC
+        3  address  W  write register to effective address
+
+  Zero page indexed addressing
+
+     Read instructions (LDA, LDX, LDY, EOR, AND, ORA, ADC, SBC, CMP, BIT,
+                        LAX, NOP)
+
+        #   address  R/W description
+       --- --------- --- ------------------------------------------
+        1     PC      R  fetch opcode, increment PC
+        2     PC      R  fetch address, increment PC
+        3   address   R  read from address, add index register to it
+        4  address+I* R  read from effective address
+
+       Notes: I denotes either index register (X or Y).
+
+              * The high byte of the effective address is always zero,
+                i.e. page boundary crossings are not handled.
+
+     Read-Modify-Write instructions (ASL, LSR, ROL, ROR, INC, DEC,
+                                     SLO, SRE, RLA, RRA, ISB, DCP)
+
+        #   address  R/W description
+       --- --------- --- ---------------------------------------------
+        1     PC      R  fetch opcode, increment PC
+        2     PC      R  fetch address, increment PC
+        3   address   R  read from address, add index register X to it
+        4  address+X* R  read from effective address
+        5  address+X* W  write the value back to effective address,
+                         and do the operation on it
+        6  address+X* W  write the new value to effective address
+
+       Note: * The high byte of the effective address is always zero,
+               i.e. page boundary crossings are not handled.
+
+     Write instructions (STA, STX, STY, SAX)
+
+        #   address  R/W description
+       --- --------- --- -------------------------------------------
+        1     PC      R  fetch opcode, increment PC
+        2     PC      R  fetch address, increment PC
+        3   address   R  read from address, add index register to it
+        4  address+I* W  write to effective address
+
+       Notes: I denotes either index register (X or Y).
+
+              * The high byte of the effective address is always zero,
+                i.e. page boundary crossings are not handled.
+
+  Absolute indexed addressing
+
+     Read instructions (LDA, LDX, LDY, EOR, AND, ORA, ADC, SBC, CMP, BIT,
+                        LAX, LAE, SHS, NOP)
+
+        #   address  R/W description
+       --- --------- --- ------------------------------------------
+        1     PC      R  fetch opcode, increment PC
+        2     PC      R  fetch low byte of address, increment PC
+        3     PC      R  fetch high byte of address,
+                         add index register to low address byte,
+                         increment PC
+        4  address+I* R  read from effective address,
+                         fix the high byte of effective address
+        5+ address+I  R  re-read from effective address
+
+       Notes: I denotes either index register (X or Y).
+
+              * The high byte of the effective address may be invalid
+                at this time, i.e. it may be smaller by $100.
+
+              + This cycle will be executed only if the effective address
+                was invalid during cycle #4, i.e. page boundary was crossed.
+
+     Read-Modify-Write instructions (ASL, LSR, ROL, ROR, INC, DEC,
+                                     SLO, SRE, RLA, RRA, ISB, DCP)
+
+        #   address  R/W description
+       --- --------- --- ------------------------------------------
+        1    PC       R  fetch opcode, increment PC
+        2    PC       R  fetch low byte of address, increment PC
+        3    PC       R  fetch high byte of address,
+                         add index register X to low address byte,
+                         increment PC
+        4  address+X* R  read from effective address,
+                         fix the high byte of effective address
+        5  address+X  R  re-read from effective address
+        6  address+X  W  write the value back to effective address,
+                         and do the operation on it
+        7  address+X  W  write the new value to effective address
+
+       Notes: * The high byte of the effective address may be invalid
+                at this time, i.e. it may be smaller by $100.
+
+     Write instructions (STA, STX, STY, SHA, SHX, SHY)
+
+        #   address  R/W description
+       --- --------- --- ------------------------------------------
+        1     PC      R  fetch opcode, increment PC
+        2     PC      R  fetch low byte of address, increment PC
+        3     PC      R  fetch high byte of address,
+                         add index register to low address byte,
+                         increment PC
+        4  address+I* R  read from effective address,
+                         fix the high byte of effective address
+        5  address+I  W  write to effective address
+
+       Notes: I denotes either index register (X or Y).
+
+              * The high byte of the effective address may be invalid
+                at this time, i.e. it may be smaller by $100. Because
+                the processor cannot undo a write to an invalid
+                address, it always reads from the address first.
+
+  Relative addressing (BCC, BCS, BNE, BEQ, BPL, BMI, BVC, BVS)
+
+        #   address  R/W description
+       --- --------- --- ---------------------------------------------
+        1     PC      R  fetch opcode, increment PC
+        2     PC      R  fetch operand, increment PC
+        3     PC      R  Fetch opcode of next instruction,
+                         If branch is taken, add operand to PCL.
+                         Otherwise increment PC.
+        4+    PC*     R  Fetch opcode of next instruction.
+                         Fix PCH. If it did not change, increment PC.
+        5!    PC      R  Fetch opcode of next instruction,
+                         increment PC.
+
+       Notes: The opcode fetch of the next instruction is included to
+              this diagram for illustration purposes. When determining
+              real execution times, remember to subtract the last
+              cycle.
+
+              * The high byte of Program Counter (PCH) may be invalid
+                at this time, i.e. it may be smaller or bigger by $100.
+
+              + If branch is taken, this cycle will be executed.
+
+              ! If branch occurs to different page, this cycle will be
+                executed.
+
+  Indexed indirect addressing
+
+     Read instructions (LDA, ORA, EOR, AND, ADC, CMP, SBC, LAX)
+
+        #    address   R/W description
+       --- ----------- --- ------------------------------------------
+        1      PC       R  fetch opcode, increment PC
+        2      PC       R  fetch pointer address, increment PC
+        3    pointer    R  read from the address, add X to it
+        4   pointer+X   R  fetch effective address low
+        5  pointer+X+1  R  fetch effective address high
+        6    address    R  read from effective address
+
+       Note: The effective address is always fetched from zero page,
+             i.e. the zero page boundary crossing is not handled.
+
+     Read-Modify-Write instructions (SLO, SRE, RLA, RRA, ISB, DCP)
+
+        #    address   R/W description
+       --- ----------- --- ------------------------------------------
+        1      PC       R  fetch opcode, increment PC
+        2      PC       R  fetch pointer address, increment PC
+        3    pointer    R  read from the address, add X to it
+        4   pointer+X   R  fetch effective address low
+        5  pointer+X+1  R  fetch effective address high
+        6    address    R  read from effective address
+        7    address    W  write the value back to effective address,
+                           and do the operation on it
+        8    address    W  write the new value to effective address
+
+       Note: The effective address is always fetched from zero page,
+             i.e. the zero page boundary crossing is not handled.
+
+     Write instructions (STA, SAX)
+
+        #    address   R/W description
+       --- ----------- --- ------------------------------------------
+        1      PC       R  fetch opcode, increment PC
+        2      PC       R  fetch pointer address, increment PC
+        3    pointer    R  read from the address, add X to it
+        4   pointer+X   R  fetch effective address low
+        5  pointer+X+1  R  fetch effective address high
+        6    address    W  write to effective address
+
+       Note: The effective address is always fetched from zero page,
+             i.e. the zero page boundary crossing is not handled.
+
+  Indirect indexed addressing
+
+     Read instructions (LDA, EOR, AND, ORA, ADC, SBC, CMP)
+
+        #    address   R/W description
+       --- ----------- --- ------------------------------------------
+        1      PC       R  fetch opcode, increment PC
+        2      PC       R  fetch pointer address, increment PC
+        3    pointer    R  fetch effective address low
+        4   pointer+1   R  fetch effective address high,
+                           add Y to low byte of effective address
+        5   address+Y*  R  read from effective address,
+                           fix high byte of effective address
+        6+  address+Y   R  read from effective address
+
+       Notes: The effective address is always fetched from zero page,
+              i.e. the zero page boundary crossing is not handled.
+
+              * The high byte of the effective address may be invalid
+                at this time, i.e. it may be smaller by $100.
+
+              + This cycle will be executed only if the effective address
+                was invalid during cycle #5, i.e. page boundary was crossed.
+
+     Read-Modify-Write instructions (SLO, SRE, RLA, RRA, ISB, DCP)
+
+        #    address   R/W description
+       --- ----------- --- ------------------------------------------
+        1      PC       R  fetch opcode, increment PC
+        2      PC       R  fetch pointer address, increment PC
+        3    pointer    R  fetch effective address low
+        4   pointer+1   R  fetch effective address high,
+                           add Y to low byte of effective address
+        5   address+Y*  R  read from effective address,
+                           fix high byte of effective address
+        6   address+Y   R  read from effective address
+        7   address+Y   W  write the value back to effective address,
+                           and do the operation on it
+        8   address+Y   W  write the new value to effective address
+
+       Notes: The effective address is always fetched from zero page,
+              i.e. the zero page boundary crossing is not handled.
+
+              * The high byte of the effective address may be invalid
+                at this time, i.e. it may be smaller by $100.
+
+     Write instructions (STA, SHA)
+
+        #    address   R/W description
+       --- ----------- --- ------------------------------------------
+        1      PC       R  fetch opcode, increment PC
+        2      PC       R  fetch pointer address, increment PC
+        3    pointer    R  fetch effective address low
+        4   pointer+1   R  fetch effective address high,
+                           add Y to low byte of effective address
+        5   address+Y*  R  read from effective address,
+                           fix high byte of effective address
+        6   address+Y   W  write to effective address
+
+       Notes: The effective address is always fetched from zero page,
+              i.e. the zero page boundary crossing is not handled.
+
+              * The high byte of the effective address may be invalid
+                at this time, i.e. it may be smaller by $100.
+
+  Absolute indirect addressing (JMP)
+
+        #   address  R/W description
+       --- --------- --- ------------------------------------------
+        1     PC      R  fetch opcode, increment PC
+        2     PC      R  fetch pointer address low, increment PC
+        3     PC      R  fetch pointer address high, increment PC
+        4   pointer   R  fetch low address to latch
+        5  pointer+1* R  fetch PCH, copy latch to PCL
+
+       Note: * The PCH will always be fetched from the same page
+               than PCL, i.e. page boundary crossing is not handled.
+
+                How Real Programmers Acknowledge Interrupts
+
+  With RMW instructions:
+
+        ; beginning of combined raster/timer interrupt routine
+        LSR $D019       ; clear VIC interrupts, read raster interrupt flag to C
+        BCS raster      ; jump if VIC caused an interrupt
+        ...             ; timer interrupt routine
+
+        Operational diagram of LSR $D019:
+
+          #  data  address  R/W
+         --- ----  -------  ---  ---------------------------------
+          1   4E     PC      R   fetch opcode
+          2   19    PC+1     R   fetch address low
+          3   D0    PC+2     R   fetch address high
+          4   xx    $D019    R   read memory
+          5   xx    $D019    W   write the value back, rotate right
+          6  xx/2   $D019    W   write the new value back
+
+        The 5th cycle acknowledges the interrupt by writing the same
+        value back. If only raster interrupts are used, the 6th cycle
+        has no effect on the VIC. (It might acknowledge also some
+        other interrupts.)
+
+  With indexed addressing:
+
+        ; acknowledge interrupts to both CIAs
+        LDX #$10
+        LDA $DCFD,X
+
+        Operational diagram of LDA $DCFD,X:
+
+          #  data  address  R/W  description
+         --- ----  -------  ---  ---------------------------------
+          1   BD     PC      R   fetch opcode
+          2   FD    PC+1     R   fetch address low
+          3   DC    PC+2     R   fetch address high, add X to address low
+          4   xx    $DC0D    R   read from address, fix high byte of address
+          5   yy    $DD0D    R   read from right address
+
+        ; acknowledge interrupts to CIA 2
+        LDX #$10
+        STA $DDFD,X
+
+        Operational diagram of STA $DDFD,X:
+
+          #  data  address  R/W  description
+         --- ----  -------  ---  ---------------------------------
+          1   9D     PC      R   fetch opcode
+          2   FD    PC+1     R   fetch address low
+          3   DC    PC+2     R   fetch address high, add X to address low
+          4   xx    $DD0D    R   read from address, fix high byte of address
+          5   ac    $DE0D    W   write to right address
+
+  With branch instructions:
+
+        ; acknowledge interrupts to CIA 2
+                LDA #$00  ; clear N flag
+                JMP $DD0A
+        DD0A    BPL $DC9D ; branch
+        DC9D    BRK       ; return
+
+        You need the following preparations to initialize the CIA registers:
+
+                LDA #$91  ; argument of BPL
+                STA $DD0B
+                LDA #$10  ; BPL
+                STA $DD0A
+                STA $DD08 ; load the ToD values from the latches
+                LDA $DD0B ; freeze the ToD display
+                LDA #$7F
+                STA $DC0D ; assure that $DC0D is $00
+
+        Operational diagram of BPL $DC9D:
+
+          #  data  address  R/W  description
+         --- ----  -------  ---  ---------------------------------
+          1   10    $DD0A    R   fetch opcode
+          2   91    $DD0B    R   fetch argument
+          3   xx    $DD0C    R   fetch opcode, add argument to PCL
+          4   yy    $DD9D    R   fetch opcode, fix PCH
+        ( 5   00    $DC9D    R   fetch opcode )
+
+        ; acknowledge interrupts to CIA 1
+                LSR       ; clear N flag
+                JMP $DCFA
+        DCFA    BPL $DD0D
+        DD0D    BRK
+
+        ; Again you need to set the ToD registers of CIA 1 and the
+        ; Interrupt Control Register of CIA 2 first.
+
+        Operational diagram of BPL $DD0D:
+
+          #  data  address  R/W  description
+         --- ----  -------  ---  ---------------------------------
+          1   10    $DCFA    R   fetch opcode
+          2   11    $DCFB    R   fetch argument
+          3   xx    $DCFC    R   fetch opcode, add argument to PCL
+          4   yy    $DC0D    R   fetch opcode, fix PCH
+        ( 5   00    $DD0D    R   fetch opcode )
+
+        ; acknowledge interrupts to CIA 2 automagically
+                ; preparations
+                LDA #$7F
+                STA $DD0D       ; disable all interrupt sources of CIA2
+                LDA $DD0E
+                AND #$BE        ; ensure that $DD0C remains constant
+                STA $DD0E       ; and stop the timer
+                LDA #$FD
+                STA $DD0C       ; parameter of BPL
+                LDA #$10
+                STA $DD0B       ; BPL
+                LDA #$40
+                STA $DD0A       ; RTI/parameter of LSR
+                LDA #$46
+                STA $DD09       ; LSR
+                STA $DD08       ; load the ToD values from the latches
+                LDA $DD0B       ; freeze the ToD display
+                LDA #$09
+                STA $0318
+                LDA #$DD
+                STA $0319       ; change NMI vector to $DD09
+                LDA #$FF        ; Try changing this instruction's operand
+                STA $DD05       ; (see comment below).
+                LDA #$FF
+                STA $DD04       ; set interrupt frequency to 1/65536 cycles
+                LDA $DD0E
+                AND #$80
+                ORA #$11
+                LDX #$81
+                STX $DD0D       ; enable timer interrupt
+                STA $DD0E       ; start timer
+
+                LDA #$00        ; To see that the interrupts really occur,
+                STA $D011       ; use something like this and see how
+        LOOP    DEC $D020       ; changing the byte loaded to $DD05 from
+                BNE LOOP        ; #$FF to #$0F changes the image.
+
+        When an NMI occurs, the processor jumps to Kernal code, which jumps to
+        ($0318), which points to the following routine:
+
+        DD09    LSR $40         ; clear N flag
+                BPL $DD0A       ; Note: $DD0A contains RTI.
+
+        Operational diagram of BPL $DD0A:
+
+          #  data  address  R/W  description
+         --- ----  -------  ---  ---------------------------------
+          1   10    $DD0B    R   fetch opcode
+          2   11    $DD0C    R   fetch argument
+          3   xx    $DD0D    R   fetch opcode, add argument to PCL
+          4   40    $DD0A    R   fetch opcode, (fix PCH)
+
+  With RTI:
+
+        ; the fastest possible interrupt handler in the 6500 family
+                ; preparations
+                SEI
+                LDA $01         ; disable ROM and enable I/O
+                AND #$FD
+                ORA #$05
+                STA $01
+                LDA #$7F
+                STA $DD0D       ; disable CIA 2's all interrupt sources
+                LDA $DD0E
+                AND #$BE        ; ensure that $DD0C remains constant
+                STA $DD0E       ; and stop the timer
+                LDA #$40
+                STA $DD0C       ; store RTI to $DD0C
+                LDA #$0C
+                STA $FFFA
+                LDA #$DD
+                STA $FFFB       ; change NMI vector to $DD0C
+                LDA #$FF        ; Try changing this instruction's operand
+                STA $DD05       ; (see comment below).
+                LDA #$FF
+                STA $DD04       ; set interrupt frequency to 1/65536 cycles
+                LDA $DD0E
+                AND #$80
+                ORA #$11
+                LDX #$81
+                STX $DD0D       ; enable timer interrupt
+                STA $DD0E       ; start timer
+
+                LDA #$00        ; To see that the interrupts really occur,
+                STA $D011       ; use something like this and see how
+        LOOP    DEC $D020       ; changing the byte loaded to $DD05 from
+                BNE LOOP        ; #$FF to #$0F changes the image.
+
+        When an NMI occurs, the processor jumps to Kernal code, which
+        jumps to ($0318), which points to the following routine:
+
+        DD0C    RTI
+
+        How on earth can this clear the interrupts? Remember, the
+        processor always fetches two successive bytes for each
+        instruction.
+
+        A little more practical version of this is redirecting the NMI
+        (or IRQ) to your own routine, whose last instruction is JMP
+        $DD0C or JMP $DC0C.  If you want to confuse more, change the 0
+        in the address to a hexadecimal digit different from the one
+        you used when writing the RTI.
+
+        Or you can combine the latter two methods:
+
+        DD09    LSR $xx  ; xx is any appropriate BCD value 00-59.
+                BPL $DCFC
+        DCFC    RTI
+
+        This example acknowledges interrupts to both CIAs.
+
+  If you want to confuse the examiners of your code, you can use any
+of these techniques. Although these examples use no undefined opcodes,
+they do not necessarily run correctly on CMOS processors. However, the
+RTI example should run on 65C02 and 65C816, and the latter branch
+instruction example might work as well.
+
+  The RMW instruction method has been used in some demos, others were
+developed by Marko M"akel"a. His favourite is the automagical RTI
+method, although it does not have any practical applications, except
+for some time dependent data decryption routines for very complicated
+copy protections.
+
+
diff --git a/Documentation/tech/cpu/NESSOUND.txt b/Documentation/tech/cpu/NESSOUND.txt
new file mode 100644 (file)
index 0000000..bb6d059
--- /dev/null
@@ -0,0 +1,697 @@
+The NES sound channel guide 1.8
+Written by Brad Taylor.
+btmine@hotmail.com
+
+Last updated: July 27th, 2000.
+
+All results were obtained by studying prior information available (from 
+nestech 1.00, and postings on NESDev from miscellanious people), and through 
+a series of experiments conducted by me. Results acquired by individuals 
+prior to my reverse-engineering have been double checked, and final results 
+have been confirmed. Credit is due to those individual(s) who contributed 
+any information in regards to the the miscellanious sound channels wihtin 
+the NES.
+
+A special thanks goes out to Matthew Conte, for his expertise on 
+pseudo-random number generation (amoung other things), which allowed for the 
+full reverse engineering of the NES's noise channel to take place. Without 
+his help, I would still be trying to find a needle in a haystack, as far as 
+the noise's method of pseudo-random number generation goes. Additionally, 
+his previous findings / reverse engineering work on the NES's sound hardware 
+really got the ball of NES sound emulation rolling. If it weren't for Matt's 
+original work, this document wouldn't exist.
+
+Thanks to Kentaro Ishihara, for his excellent work on finding the difference 
+in upward frequency sweep between the 2 square wave channels.
+
+****************
+* Introduction *
+****************
+
+The 2A03 (NES's integrated CPU) has 4 internal channels to it that have the 
+ability to generate semi-analog sound, for musical playback purposes. These 
+channels are 2 square wave channels, one triangle wave channel, and a noise 
+generation channel. This document will go into full detail on every aspect 
+of the operation and timing of the mentioned sound channels.
+
+
+*******************
+* Channel details *
+*******************
+
+Each channel has different characteristics to it that make up it's 
+operation.
+
+The square channel(s) have the ability to generate a square wave frequency 
+in the range of 54.6 Hz to 12.4 KHz. It's key features are frequency sweep 
+abilities, and output duty cycle adjustment.
+
+The triangle wave channel has the ability to generate an output triangle 
+wave with a resolution of 4-bits (16 steps), in the range of 27.3 Hz to 55.9 
+KHz. The key features this channel has is it's analog triangle wave output, 
+and it's linear counter, which can be set to automatically disable the 
+channel's sound after a certain period of time has gone by.
+
+The noise channel is used for producing random frequencys, which results in 
+a "noisey" sounding output. Output frequencys can range anywhere from 29.3 
+Hz to 447 KHz. It's key feature is it's pseudo- random number generator, 
+which generates the random output frequencys heard by the channel.
+
+
+*****************
+* Frame counter *
+*****************
+
+The 2A03 has an internal frame counter. It has the ability to generate 60 Hz 
+(1/1 framerate), 120 Hz (1/2 framerate), and 240 Hz (1/4 framerate) signals, 
+used by some of the sound hardware. The 1/4 framerate is calculated by 
+taking twice the CPU clock speed (3579545.454545 Hz), and dividing it by 
+14915 (i.e., the divide-by-14915 counter is decremented on the rising AND 
+falling edge of the CPU's clock signal).
+
+
+************************
+* Sound hardware delay *
+************************
+
+After resetting the 2A03, the first time any sound channel(s) length counter 
+contains a non-zero value (channel is enabled), there will be a 2048 CPU 
+clock cycle delay before any of the sound hardware is clocked. After the 2K 
+clock cycles go by, the NES sound hardware will be clocked normally. This 
+phenomenon only occurs prior to a system reset, and only occurs during the 
+first 2048 CPU clocks for any sound channel prior to a sound channel being 
+enabled.
+
+The information in regards to this delay is only provided to keep this 
+entire document persistently accurate on the 2A03's sound hardware, but may 
+not be 100% accurate in itself. I haven't done much tests on the behaviour 
+of this delay (mainly because I don't care, as I view it as a inconvenience 
+anyway), so that's why I believe there could be some inaccuracies.
+
+
+************************
+* Register Assignments *
+************************
+
+The sound hardware internal to the 2A03 has been designated these special 
+memory addresses in the CPU's memory map.
+
+$4000-$4003    Square wave 1
+$4004-$4007    Square wave 2 (identical to the first, except for upward 
+frequency sweeps (see "sweep unit" section))
+$4008-$400B    Triangle
+$400C-$400F    Noise
+$4015          Channel enable / length counter status
+
+Note that $4015 is the only R/W register. All others are write only (attempt 
+to read them will most likely result in a returned 040H, due to heavy 
+capacitance on the NES's data bus). Reading a "write only" register, will 
+have no effect on the specific register, or channel.
+
+Every sound channel has 4 registers affiliated with it. The description of 
+the register sets are as follows:
+
++----------------+
+| Register set 1 |
++----------------+
+
+$4000(sq1)/$4004(sq2)/$400C(noise) bits
+---------------------------------------
+0-3    volume / envelope decay rate
+4      envelope decay disable
+5      length counter clock disable / envelope decay looping enable
+6-7    duty cycle type (unused on noise channel)
+
+$4008(tri) bits
+---------------
+0-6    linear counter load register
+7      length counter clock disable / linear counter start
+
+
++----------------+
+| Register set 2 |
++----------------+
+
+$4001(sq1)/$4005(sq2) bits
+--------------------------
+0-2    right shift amount
+3      decrease / increase (1/0) wavelength
+4-6    sweep update rate
+7      sweep enable
+
+$4009(tri)/$400D(noise) bits
+----------------------------
+0-7    unused
+
+
++----------------+
+| Register set 3 |
++----------------+
+
+$4002(sq1)/$4006(sq2)/$400A(Tri) bits
+-------------------------------------
+0-7    8 LSB of wavelength
+
+$400E(noise) bits
+-----------------
+0-3    playback sample rate
+4-6    unused
+7      random number type generation
+
+
++----------------+
+| Register set 4 |
++----------------+
+
+$4003(sq1)/$4007(sq2)/$400B(tri)/$400F(noise) bits
+--------------------------------------------------
+0-2    3 MS bits of wavelength (unused on noise channel)
+3-7    length counter load register
+
+
++--------------------------------+
+| length counter status register |
++--------------------------------+
+
+$4015(read)
+-----------
+0      square wave channel 1
+1      square wave channel 2
+2      triangle wave channel
+3      noise channel
+4      DMC (see "DMC.TXT" for details)
+5-6    unused
+7      IRQ status of DMC (see "DMC.TXT" for details)
+
+
++-------------------------+
+| channel enable register |
++-------------------------+
+
+$4015(write)
+------------
+0      square wave channel 1
+1      square wave channel 2
+2      triangle wave channel
+3      noise channel
+4      DMC channel (see "DMC.TXT" for details)
+5-7    unused
+
+
+************************
+* Channel architecture *
+************************
+
+This section will describe the internal components making up each individual 
+channel. Each component will then be described in full detail.
+
+Device                        Triangle Noise  Square
+------                        -------- ------ ------
+triangle step generator              X
+linear counter                       X
+programmable timer                   X      X      X
+length counter                       X      X      X
+4-bit DAC                            X      X      X
+volume/envelope decay unit                  X      X
+sweep unit                                         X
+duty cycle generator                               X
+wavelength converter                        X
+random number generator                     X
+
+
++-------------------------+
+| Triangle step generator |
++-------------------------+
+
+This is a 5-bit, single direction counter, and it is only used in the 
+triangle channel. Each of the 4 LSB outputs of the counter lead to one input 
+on a corresponding mutually exclusive XNOR gate. The 4 XNOR gates have been 
+strobed together, which results in the inverted representation of the 4 LSB 
+of the counter appearing on the outputs of the gates when the strobe is 0, 
+and a non-inverting action taking place when the strobe is 1. The strobe is 
+naturally connected to the MSB of the counter, which effectively produces on 
+the output of the XNOR gates a count sequence which reflects the scenario of 
+a near- ideal triangle step generator (D,E,F,F,E,D,...,2,1,0,0,1,2,...). At 
+this point, the outputs of the XNOR gates will be fed into the input of a 
+4-bit DAC.
+
+This 5-bit counter will be halted whenever the Triangle channel's length or 
+linear counter contains a count of 0. This results in a "latching" 
+behaviour; the counter will NOT be reset to any definite state.
+
+On system reset, this counter is loaded with 0.
+
+The counter's clock input is connected directly to the terminal count output 
+pin of the 11-bit programmable timer in the triangle channel. As a result of 
+the 5-bit triangle step generator, the output triangle wave frequency will 
+be 32 times less than the frequency of the triangle channel's programmable 
+timer is set to generate.
+
+
++----------------+
+| Linear counter |
++----------------+
+
+The linear counter is only found in the triangle channel. It is a 7-bit 
+presettable down counter, with a decoded output condition of 0 available 
+(not exactly the same as terminal count). Here's the bit assignments:
+
+$4008 bits
+----------
+0-6    bits 0-6 of the linear counter load register (NOT the linear counter 
+itself)
+7      linear counter start
+
+The counter is clocked at 240 Hz (1/4 framerate), and the calculated length 
+in frames is 0.25*N, where N is the 7-bit loaded value. The counter is 
+always being clocked, except when 0 appears on the output of the counter. At 
+this point, the linear counter & triangle step counter clocks signals are 
+disabled, which results in both counters latching their current state (the 
+linear counter will stay at 0, and the triangle step counter will stop, and 
+the channel will be silenced due to this).
+
+The linear counter has 2 modes: load, and count. When the linear counter is 
+in load mode, it essentially becomes transparent (i.e. whatever value is 
+currently in, or being written to $4008, will appear on the output of the 
+counter). Because of this, no count action can occur in load mode. When the 
+mode changes from load to count, the counter will now latch the value 
+currently in it, and start counting down from there. In the count mode, the 
+current value of $4008 is ignored by the counter (but still retained in 
+$4008). Described below is how the mode of the linear counter is set:
+
+Writes to $400B
+---------------
+cur    mode
+---    ----
+1      load
+0      load (during the write cycle), count
+
+Cur is the current state of the MSB of $4008.
+
+Writes to $4008
+---------------
+old    new     mode
+---    ---     ----
+0      X       count
+1      0       no change (during the write cycle), count
+1      1       no change
+
+Old and new represent the state(s) of the MSB of $4008. Old is the value 
+being replaced in the MSB of $4008 on the write, and new is the value 
+replacing the old one.
+
+"no change" indicates that the mode of the linear counter will not change 
+from the last.
+
+
++--------------------+
+| Programmable timer |
++--------------------+
+
+The programmable timer is a 11-bit presettable down counter, and is found in 
+the square, triangle, and noise channel(s). The bit assignments are as 
+follows:
+
+$4002(sq1)/$4006(sq2)/$400A(Tri) bits
+-------------------------------------
+0-7    represent bits 0-7 of the 11-bit wavelength
+
+$4003(sq1)/$4007(sq2)/$400B(Tri) bits
+-------------------------------------
+0-2    represent bits 8-A of the 11-bit wavelength
+
+Note that on the noise channel, the 11 bits are not available directly. See 
+the wavelength converter section, for more details.
+
+The counter has automatic syncronous reloading upon terminal count 
+(count=0), therefore the counter will count for N+1 (N is the 11-bit loaded 
+value) clock cycles before arriving at terminal count, and reloading. This 
+counter will typically be clocked at the 2A03's internal 6502 speed (1.79 
+MHz), and produces an output frequency of 1.79 MHz/(N+1). The terminal 
+count's output spike length is typically no longer than half a CPU clock. 
+The TC signal will then be fed to the appropriate device for the particular 
+sound channel (for square, this terminal count spike will lead to the duty 
+cycle generator. For the triangle, the spike will be fed to the triangle 
+step generator. For noise, this signal will go to the random number 
+generator unit).
+
+
++----------------+
+| Length counter |
++----------------+
+
+The length counter is found in all sound channels. It is essentially a 7-bit 
+down counter, and is conditionally clocked at a frequency of 60 Hz.
+
+When the length counter arrives at a count of 0, the counter will be stopped 
+(stay on 0), and the appropriate channel will be silenced.
+
+The length counter clock disable bit, found in all the channels, can also be 
+used to halt the count sequence of the length counter for the appropriate 
+channel, by writing a 1 out to it. A 0 condition will permit counting 
+(unless of course, the counter's current count = 0). Location(s) of the 
+length counter clock disable bit:
+
+$4000(sq1)/$4004(sq2)/$400C(noise) bits
+---------------------------------------
+5      length counter clock disable
+
+$4008(tri) bits
+---------------
+7      length counter clock disable
+
+To load the length counter with a specified count, a write must be made out 
+to the length register. Location(s) of the length register:
+
+$4003(sq1)/$4007(sq2)/$400B(tri)/$400F(noise) bits
+--------------------------------------------------
+3-7    length
+
+The 5-bit length value written, determines what 7-bit value the length 
+counter will start counting from. A conversion table here will show how the 
+values are translated.
+
+       +-----------------------+
+       |       bit3=0          |
+       +-------+---------------+
+       |       |frames         |
+       |bits   +-------+-------+
+       |4-6    |bit7=0 |bit7=1 |
+       +-------+-------+-------+
+       |0      |05     |06     |
+       |1      |0A     |0C     |
+       |2      |14     |18     |
+       |3      |28     |30     |
+       |4      |50     |60     |
+       |5      |1E     |24     |
+       |6      |07     |08     |
+       |7      |0E     |10     |
+       +-------+-------+-------+
+
+       +---------------+
+       |       bit3=1  |
+       +-------+-------+
+       |bits   |       |
+       |4-7    |frames |
+       +-------+-------+
+       |0      |7F     |
+       |1      |01     |
+       |2      |02     |
+       |3      |03     |
+       |4      |04     |
+       |5      |05     |
+       |6      |06     |
+       |7      |07     |
+       |8      |08     |
+       |9      |09     |
+       |A      |0A     |
+       |B      |0B     |
+       |C      |0C     |
+       |D      |0D     |
+       |E      |0E     |
+       |F      |0F     |
+       +-------+-------+
+
+The length counter's real-time status for each channel can be attained. A 0 
+is returned for a zero count status in the length counter (channel's sound 
+is disabled), and 1 for a non-zero status. Here's the bit description of the 
+length counter status register:
+
+$4015(read)
+-----------
+0      length counter status of square wave channel 1
+1      length counter status of square wave channel 2
+2      length counter status of triangle wave channel
+3      length counter status of noise channel
+4      length counter status of DMC (see "DMC.TXT" for details)
+5-6    unused
+7      IRQ status of DMC (see "DMC.TXT" for details)
+
+Writing a 0 to the channel enable register will force the length counters to 
+always contain a count equal to 0, which renders that specific channel 
+disabled (as if it doesn't exist). Writing a 1 to the channel enable 
+register disables the forced length counter value of 0, but will not change 
+the count itself (it will still be whatever it was prior to the writing of 
+1).
+
+Bit description of the channel enable register:
+
+$4015(write)
+------------
+0      enable square wave channel 1
+1      enable square wave channel 2
+2      enable triangle wave channel
+3      enable noise channel
+4      enable DMC channel (see "DMC.TXT" for details)
+5-7    unused
+
+Note that all 5 used bits in this register will be set to 0 upon system 
+reset.
+
+
++-----------+
+| 4-bit DAC |
++-----------+
+
+This is just a standard 4-bit DAC with 16 steps of output voltage 
+resolution, and is used by all 4 sound channels.
+
+On the 2A03, square wave 1 & 2 are mixed together, and are available via pin 
+1. Triangle & noise are available on pin 2. These analog outputs require a 
+negative current source, to attain linear symmetry on the various output 
+voltage levels generated by the channel(s) (moreover, to get the sound to be 
+audible). Since the NES just uses external 100 ohm pull-down resistors, this 
+results in the output waveforms being of very small amplitude, but with 
+minimal linearity asymmetry.
+
+
++------------------------------+
+| Volume / envelope decay unit |
++------------------------------+
+
+The volume / envelope decay hardware is found only in the square wave and 
+noise channels.
+
+$4000(sq1)/$4004(sq2)/$400C(noise)
+----------------------------------
+0-3    volume / envelope decay rate
+4      envelope decay disable
+5      envelope decay looping enable
+
+When the envelope decay disable bit (bit 4) is set (1), the current volume 
+value (bits 0-3) is sent directly to the channel's DAC. However, depending 
+on certain conditions, this 4-bit volume value will be ignored, and a value 
+of 0 will be sent to the DAC instead. This means that while the channel is 
+enabled (producing sound), the output of the channel (what you'll hear from 
+the DAC) will either be the 4-bit volume value, or 0. This also means that a 
+4-bit volume value of 0 will result in no audible sound. These conditions 
+are as follows:
+
+- When hardware in the channel wants to disable it's sound output (like the 
+length counter, or sweep unit (square channels only)).
+
+- On the negative portion of the output frequency signal coming from the 
+duty cycle / random number generator hardware (square wave channel / noise 
+channel).
+
+When the envelope decay disable bit is cleared, bits 0-3 now control the 
+envelope decay rate, and an internal 4-bit down counter (hereon the envelope 
+decay counter) now controls the channel's volume level. "Envelope decay" is 
+used to describe the action of the channel's audio output volume starting 
+from a certain value, and decreasing by 1 at a fixed (linear) rate (which 
+produces a "fade-out" sounding effect). This fixed decrement rate is 
+controlled by the envelope decay rate (bits 0-3). The calculated decrement 
+rate is 240Hz/(N+1), where N is any value between $0-$F.
+
+When the channel's envelope decay counter reaches a value of 0, depending on 
+the status of the envelope decay looping enable bit (bit 5, which is shared 
+with the length counter's clock disable bit), 2 different things will 
+happen:
+
+bit 5  action
+-----  ------
+0      The envelope decay count will stay at 0 (channel silenced).
+1      The envelope decay count will wrap-around to $F (upon the next clock 
+cycle). The envelope decay counter will then continue to count down 
+normally.
+
+Only a write out to $4003/$4007/$400F will reset the current envelope decay 
+counter to a known state (to $F, the maximum volume level) for the 
+appropriate channel's envelope decay hardware. Otherwise, the envelope decay 
+counter is always counting down (by 1) at the frequency currently contained 
+in the volume / envelope decay rate bits (even when envelope decays are 
+disabled (setting bit 4)), except when the envelope decay counter contains a 
+value of 0, and envelope decay looping (bit 5) is disabled (0).
+
+
++------------+
+| Sweep unit |
++------------+
+
+The sweep unit is only found in the square wave channels. The controls for 
+the sweep unit have been mapped in at $4001 for square 1, and $4005 for 
+square 2.
+
+The controls
+------------
+Bit 7          when this bit is set (1), sweeping is active. This results in 
+real-time increasing or decreasing of the the current wavelength value (the 
+audible frequency will decrease or increase, respectively). The wavelength 
+value in $4002/3 ($4006/7) is constantly read & updated by the sweep. 
+Modifying the contents of $4002/3 will be immediately audible, and will 
+result in the sweep now starting from this new wavelength value.
+
+Bits 6-4       These 3 bits represent the sweep refresh rate, or the frequency at 
+which $4002/3 is updated with the new calculated wavelength. The refresh 
+rate frequency is 120Hz/(N+1), where N is the value written, between 0 and 
+7.
+
+Bit 3          This bit controls the sweep mode. When this bit is set (1), sweeps 
+will decrease the current wavelength value, as a 0 will increase the current 
+wavelength.
+
+Bits 2-0       These bits control the right shift amount of the new calculated 
+sweep update wavelength. Code that shows how the sweep unit calculates a new 
+sweep wavelength is as follows:
+
+bit 3
+-----
+0      New = Wavelength + (Wavelength >> N)
+1      New = Wavelength - (Wavelength >> N) (minus an additional 1, if using 
+square wave channel 1)
+
+where N is the the shift right value, between 0-7.
+
+Note that in decrease mode, for subtracting the 2 values:
+1's compliment (NOT) is being used for square wave channel 1
+2's compliment (NEG) is being used for square wave channel 2
+
+This information is currently the only known difference between the 2 square 
+wave channels.
+
+On each sweep refresh clock, the Wavelength register will be updated with 
+the New value, but only if all 3 of these conditions are met:
+
+- bit 7 is set (sweeping enabled)
+- the shift value (which is N in the formula) does not equal to 0
+- the channel's length counter contains a non-zero value
+
+Notes
+-----
+There are certain conditions that will cause the sweep unit to silence the 
+channel, and halt the sweep refresh clock (which effectively stops sweep 
+action, if any). Note that these conditions pertain regardless of any sweep 
+refresh rate values, or if sweeping is enabled/disabled (via bit 7).
+
+- an 11-bit wavelength value less than $008 will cause this condition
+- if the sweep unit is currently set to increase mode, the New calculated 
+wavelength value will always be tested to see if a carry (bit $B) was 
+generated or not (if sweeping is enabled, this carry will be examined before 
+the Wavelength register is updated) from the shift addition calculation. If 
+carry equals 1, the channel is silenced, and sweep action is halted.
+
+
++----------------------+
+| Duty cycle generator |
++----------------------+
+
+The duty cycle generator takes the fequency produced from the 11-bit 
+programmable timer, and uses a 4 bit counter to produce 4 types of duty 
+cycles. The output frequency is then 1/16 that of the programmable timer. 
+The duty cycle hardware is only found in the square wave channels. The bit 
+assignments are as follows:
+
+$4000(sq1)/$4004(sq2)
+---------------------
+6-7    Duty cycle type
+
+       duty (positive/negative)
+val    in clock cycles
+---    ---------------
+00      2/14
+01      4/12
+10      8/ 8
+11     12/ 4
+
+Where val represents bits 6-7 of $4000/$4004.
+
+The output frequency at this point will now be fed to the volume/envelope 
+decay hardware.
+
+
++----------------------+
+| Wavelength converter |
++----------------------+
+
+The wavelength converter is only used in the noise channel. It is used to 
+convert a given 4-bit value to an 11-bit wavelength, which then is sent to 
+the noise's own programmable timer. Here is the bit descriptions:
+
+$400E bits
+----------
+0-3    The 4-bit value to be converted
+
+Below is a conversion chart that shows what 4-bit value will represent the 
+11-bit wavelength to be fed to the channel's programmable timer:
+
+value  octave  scale   CPU clock cycles (11-bit wavelength+1)
+-----  ------  -----   --------------------------------------
+0      15      A       002
+1      14      A       004
+2      13      A       008
+3      12      A       010
+4      11      A       020
+5      11      D       030
+6      10      A       040
+7      10      F       050
+8      10      C       065
+9       9      A       07F
+A       9      D       0BE
+B       8      A       0FE
+C       8      D       17D
+D       7      A       1FC
+E       6      A       3F9
+F       5      A       7F2
+
+Octave and scale information is provided for the music enthusiast programmer 
+who is more familiar with notes than clock cycles.
+
+
++-------------------------+
+| Random number generator |
++-------------------------+
+
+The noise channel has a 1-bit pseudo-random number generator. It's based on 
+a 15-bit shift register, and an exclusive or gate. The generator can produce 
+two types of random number sequences: long, and short. The long sequence 
+generates 32,767-bit long number patterns. The short sequence generates 
+93-bit long number patterns. The 93-bit mode will generally produce higher 
+sounding playback frequencys on the channel. Here is the bit that controls 
+the mode:
+
+$400E bits
+----------
+7      mode
+
+If mode=0, then 32,767-bit long number sequences will be produced (32K 
+mode), otherwise 93-bit long number sequences will be produced (93-bit 
+mode).
+
+The following diagram shows where the XOR taps are taken off the shift 
+register to produce the 1-bit pseudo-random number sequences for each mode.
+
+mode       <-----
+----   EDCBA9876543210
+32K    **
+93-bit *     *
+
+The current result of the XOR will be transferred into bit position 0 of the 
+SR, upon the next shift cycle. The 1-bit random number output is taken from 
+pin E, is inverted, then is sent to the volume/envelope decay hardware for 
+the noise channel. The shift register is shifted upon recieving 2 clock 
+pulses from the programmable timer (the shift frequency will be half that of 
+the frequency from the programmable timer (one octave lower)).
+
+On system reset, this shift register is loaded with a value of 1.
+
+
diff --git a/Documentation/tech/cpu/dmc.txt b/Documentation/tech/cpu/dmc.txt
new file mode 100644 (file)
index 0000000..c33f4de
--- /dev/null
@@ -0,0 +1,235 @@
+Delta modulation channel tutorial 1.0
+Written by Brad Taylor
+
+Last updated: August 20th, 2000.
+
+All results were obtained by studying prior information available (from 
+nestech 1.00, and postings on NESDev from miscellanious people), and through 
+a series of experiments conducted by me. Results aquired by individuals 
+prior to my reverse-engineering have been double checked, and final results 
+have been confirmed. Credit is due to those individual(s) who contributed 
+any information in regards to the DMC.
+
+Description
+-----------
+
+The delta modulation channel (DMC) is a complex digital network of counters 
+and registers used to produce analog sound. It's primary function is to play 
+"samples" from memory, and have an internal counter connected to a digital 
+to analog converter (DAC) updated accordingly. The channel is able to be 
+assigned a pointer to a chunk of memory to be played. At timed intervals, 
+the DMC will halt the 2A03 (NES's CPU) for 1 clock cycle to retrieve the 
+sample to pe played. This method of playback will be refered to here on as 
+direct memory access (DMA). Another method of playback known as pulse code 
+modulation (PCM) is available by the channel, which requires the constant 
+updating of one of the DMC's memory-mapped registers.
+
+Registers
+---------
+
+The DMC has 5 registers assigned to it. They are as follows:
+
+$4010: play mode and DMA frequency
+$4011: delta counter
+$4012: play code's starting address
+$4013: length of play code
+$4015: DMC/IRQ status
+
+Note that $4015 is the only R/W register. All others are write only (attempt 
+to read them will most likely result in a returned 040H, due to heavy 
+capacitance on the NES's data bus).
+
+$4010 - Play mode and DMA frequency
+-----------------------------------
+This register is used to control the frequency of the DMA fetches, and to 
+control the playback mode.
+
+Bits
+----
+6-7    this is the playback mode.
+
+       00 - play DMC sample until length counter reaches 0 (see $4013)
+       x1 - loop the DMC sample (x = immaterial)
+       10 - play DMC sample until length counter reaches 0, then generate a CPU 
+IRQ
+
+Looping (playback mode "x1") will have the chunk of memory played over and 
+over, until the channel is disabled (via $4015). In this case, after the 
+length counter reaches 0, it will be reloaded with the calculated length 
+value of $4013.
+
+If playback mode "10" is chosen, an interrupt will be dispached when the 
+length counter reaches 0 (after the sample is done playing). There are 2 
+ways to acknowledge the DMC's interrupt request upon recieving it. The first 
+is a write to this register ($4010), with the MSB (bit 7) cleared (0). The 
+second is any write to $4015 (see the $4015 register description for more 
+details).
+
+If playback mode "00" is chosen, the sample plays until the length counter 
+reaches 0. No interrupt is generated.
+
+5-4    appear to be unused
+
+3-0    this is the DMC frequency control. Valid values are from 0 - F. The 
+value of this register determines how many CPU clocks to wait before the DMA 
+will fetch another byte from memory. The # of clocks to wait -1 is initially 
+loaded into an internal 12-bit down counter. The down counter is then 
+decremented at the frequency of the CPU (1.79MHz). The channel fetches the 
+next DMC sample byte when the count reaches 0, and then reloads the count. 
+This process repeats until the channel is disabled by $4015, or when the 
+length counter has reached 0 (if not in the looping playback mode). The 
+exact number of CPU clock cycles is as follows:
+
+value   CPU
+written        clocks  octave  scale
+-------        ------  ------  -----
+F      1B0     8       C
+E      240     7       G
+D      2A0     7       E
+C      350     7       C
+B      400     6       A
+A      470     6       G
+9      500     6       F
+8      5F0     6       D
+7      6B0     6       C
+6      710     5       B
+5      7F0     5       A
+4      8F0     5       G
+3      A00     5       F
+2      AA0     5       E
+1      BE0     5       D
+0      D60     5       C
+
+The octave and scale values shown represent the DMC DMA clock cycle rate 
+equivelant. These values are merely shown for the music enthusiast 
+programmer, who is more familiar with notes than clock cycles.
+
+Every fetched byte is loaded into a internal 8-bit shift register. The shift 
+register is then clocked at 8x the DMA frequency (which means that the CPU 
+clock count would be 1/8th that of the DMA clock count), or shifted at +3 
+the octave of the DMA (same scale). The data shifted out of the register is 
+in serial form, and the least significant bit (LSB, or bit 0) of the fetched 
+byte is the first one to be shifted out (then bit 1, bit 2, etc.).
+
+The bits shifted out are then fed to the UP/DOWN control pin of the internal 
+delta counter, which will effectively have the counter increment it's 
+retained value by one on "1" bit samples, and decrement it's value by one on 
+"0" bit samples. This counter is clocked at the same frequency of the shift 
+register's.
+
+The counter is only 6 bits in size, and has it's 6 outputs tied to the 6 MSB 
+inputs of a 7 bit DAC. The analog output of the DAC is then what you hear 
+being played by the DMC.
+
+Wrap around counting is not allowed on this counter. Instead, a "clipping" 
+behaviour is exhibited. If the internal value of the counter has reached 0, 
+and the next bit sample is a 0 (instructing a decrement), the counter will 
+take no action. Likewise, if the counter's value is currently at -1 
+(111111B, or 03FH), and the bit sample to be played is a 1, the counter will 
+not increment.
+
+
+$4011 - Delta counter load register
+-----------------------------------
+
+bits
+----
+7      appears to be unused
+1-6    the load inputs of the internal delta counter
+0      LSB of the DAC
+
+A write to this register effectively loads the internal delta counter with a 
+6 bit value, but can be used for 7 bit PCM playback. Bit 0 is connected 
+directly to the LSB (bit 0) of the DAC, and has no effect on the internal 
+delta counter. Bit 7 appears to be unused.
+
+This register can be used to output direct 7-bit digital PCM data to the 
+DMC's audio output. To use this register for PCM playback, the programmer 
+would be responsible for making sure that this register is updated at a 
+constant rate. The rate is completely user-definable. For the regular CD 
+quality 44100 Hz playback sample rate, this register would have to be 
+written to approximately every 40 CPU cycles (assuming the 2A03 is running @ 
+1.79 MHz).
+
+
+$4012 - DMA address load register
+----------------------------
+
+This register contains the initial address where the DMC is to fetch samples 
+from memory for playback. The effective address value is $4012 shl 6 or 
+0C000H. This register is connected to the load pins of the internal DMA 
+address pointer register (counter). The counter is incremented after every 
+DMA byte fetch. The counter is 15 bits in size, and has addresses wrap 
+around from $FFFF to $8000 (not $C000, as you might have guessed). The DMA 
+address pointer register is reloaded with the initial calculated address, 
+when the DMC is activated from an inactive state, or when the length counter 
+has arrived at terminal count (count=0), if in the looping playback mode.
+
+
+$4013 - DMA length register
+---------------------------
+
+This register contains the length of the chunk of memory to be played by the 
+DMC, and it's size is measured in bytes. The value of $4013 shl 4 is loaded 
+into a 12 bit internal down counter, dubbed the length counter. The length 
+counter is decremented after every DMA fetch, and when it arrives at 0, the 
+DMC will take action(s) based on the 2 MSB of $4010. This counter will be 
+loaded with the current calculated address value of $4013 when the DMC is 
+activated from an inactive state. Because the value that is loaded by the 
+length counter is $4013 shl 4, this effectively produces a calculated byte 
+sample length of $4013 shl 4 + 1 (i.e. if $4013=0, sample length is 1 byte 
+long; if $4013=FF, sample length is $FF1 bytes long).
+
+
+$4015 - DMC status
+------------------
+
+This contains the current status of the DMC channel. There are 2 read bits, 
+and 1 write bit.
+
+bits
+----
+7(R)   DMC's IRQ status (1=CPU IRQ being caused by DMC)
+4(R)   DMC is currently enabled (playing a stream of samples)
+4(W)   enable/disable DMC (1=start/continue playing a sample;0=stop playing)
+
+When an IRQ goes off inside the 2A03, Bit 7 of $4015 can tell the interrupt 
+handler if it was caused by the DMC hardware or not. This bit will be set 
+(1) if the DMC is responsible for the IRQ. Of course, if your program has no 
+other IRQ-generating hardware going while it's using the DMC, then reading 
+this register is not neccessary upon IRQ generation. Note that reading this 
+register will NOT clear bit 7 (meaning that the DMC's IRQ will still NOT be 
+acknowledged). Also note that if the 2 MSB of $4010 were set to 10, no IRQ 
+will be generated, and bit 7 will always be 0.
+
+Upon generation of a IRQ, to let the DMC know that the software has 
+acknowledged the /IRQ (and to reset the DMC's internal IRQ flag), any write 
+out to $4015 will reset the flag, or a write out to $4010 with the MSB set 
+to 0 will do. These practices should be performed inside the IRQ handler 
+routine. To replay the same sample that just finished, all you need to do is 
+just write a 1 out to bit 4 of $4015.
+
+Bit 4 of $4015 reports the real-time status of the DMC. A returned value of 
+1 denotes that the channel is currently playing a stream of samples. A 
+returned value of 0 indicates that the channel is inactive. If the 
+programmer needed to know when a stream of samples was finished playing, but 
+didn't want to use the IRQ generation feature of the DMC, then polling this 
+bit would be a valid option.
+
+Writing a value to $4015's 4th bit has the effect of enabling the channel 
+(start, or continue playing a stream of samples), or disabling the channel 
+(stop all DMC activity). Note that writing a 1 to this bit while the channel 
+is currently enabled, will have no effect on counters or registers internal 
+to the DMC.
+
+The conditions that control the time the DMC will stay enabled are 
+determined by the 2 MSB of $4010, and register $4013 (if applicable).
+
+
+System Reset
+------------
+
+On system reset, all 7 used bits of $4011 are reset to 0, the IRQ flag is 
+cleared (disabled), and the channel is disabled. All other registers will 
+remain unmodified.
+
diff --git a/Documentation/tech/exp/mmc5-e.txt b/Documentation/tech/exp/mmc5-e.txt
new file mode 100644 (file)
index 0000000..eab191a
--- /dev/null
@@ -0,0 +1,250 @@
+========= mmc5 infomation ==========
+date 1998/05/31
+by goroh
+translated May 31, 1998 by Sgt. Bowhack
+mail goroh_kun@geocities.co.jp
+
+5000,5004 ch1,ch2 Pulse Control
+ bit CCwevvvv
+    CC Duty Cycle (Positive vs. Negative)
+      #0:87.5%  #1:75.0%  #2:50.0%  #3:25.0%
+    w Waveform Hold (e.g. Looping)
+      0: Off 1: On
+    e Envelope Select
+      0: Varied 1: Fixed
+    < e=0 >
+     vvvv Playback Rate
+         #0<-fast<--->-slow--> #15
+    < e=1 >
+     vvvv Output Volume
+
+5002,5006 ch1,ch2 frequency L
+ bit ffffffff
+5003,5007 ch1,ch2 frequency H
+ bit tttttfff
+  ttttt sound occurence time
+
+Objective is to remove the continuous changing of frequency for
+square wave setup and do the same to the main part of the square wave
+of studying the main part of the famicom. (?- Sgt. Bowhack)
+
+5010 ch3 synthetic voice business channel
+ bit -------O
+  O wave output 0:Off 1:On
+
+5011 ch4 synthetic voice business channel 2
+ bit vvvvvvvv
+  vvvvvvvv wave size
+
+5015 sound output channel
+ bit ------BA
+  A: ch1 output  1:enable 0:disable
+  B: ch2 output  1:enable 0:disable
+
+5100 PRG-page size Setting
+ bit ------SS
+    SS PRG-page size
+       0: 32k 1:16k 2,3:8k
+* Reset is misled the first times for about 8k (?- SB)
+       
+5101 CHR-page size Setting
+ bit ------SS
+    SS CHR-page size
+       0:8k 1:4k 2:2k 3:1k
+
+5102 W BBR-RAM Write Protect 1
+ bit ------AA
+5103 W BBR-RAM Write Protect 2
+ bit ------BB
+  (AA,BB) = (2,1) permitted to write to BBR-RAM only when crowded
+*Reset write around becomes prohibited when crowded
+
+5104 Grafix Mode Setting
+ $5c00-$5fff decides how it should be used
+  bit ------MM
+  #00:Enable only Split Mode
+  #01:Enable Split Mode & ExGrafix Mode
+  #02:ExRAM Mode
+  #03:ExRAM Mode & Write Protect
+
+Consideration
+ MMC5 has 2 graphic mode extensions that allow more than 256 characters
+on one standard game screen.  It uses Split Mode so it can display the
+specified CHR-page and scroll position seperate from ExGrafix Mode to
+be able to choose a palette, and the other divides it vertically.
+
+5105 W NameTable Setting
+  bit ddccbbaa
+  aa: Select VRAM at 0x2000-0x23ff
+  bb: Select VRAM at 0x2400-0x27ff
+  cc: Select VRAM at 0x2800-0x2bff
+  dd: Select VRAM at 0x2c00-0x2fff
+    #0:use VRAM 0x000-0x3ff
+    #1:use VRAM 0x400-0x7ff
+    #2:use ExVRAM 0x000-0x3ff
+    #3:use ExNameTable(Fill Mode)
+
+Consideration
+ The name table can designate 4 kinds of this resister and be a useful
+special quality for this because painting and smashing it with a
+character that there is 1 sheet for the remaining sheets can generally
+be used. (?-SB)
+
+5106 W Fill Mode Setting 1
+  bit vvvvvvvv
+  Fill chr-table
+ For whether it paints or smashes it at any non-designated character
+
+5107 W Fill Mode Setting 2
+  bit ------pp
+ Whether or not it uses any non-designated palettes
+
+5113 RAM-page for $6000-$7FFF
+  bit -----p--
+
+5114-5117 Program Bank switch
+ < page_size=32k >
+ $5117 [8]-[F] bit pppppp--
+
+ < page_size=16k >
+ $5115 [8]-[B] bit ppppppp-
+ $5117 [C]-[F] bit ppppppp-
+
+ < page_size=8k >
+ $5114 [8][9]  bit pppppppp
+ $5115 [A][B]  bit pppppppp
+ $5116 [C][D]  bit pppppppp
+ $5117* [E][F]  bit pppppppp
+
+*Reset is around early, Last Page misled
+
+5120-512b Charactor Bank switch
+ < page_size=8k >
+ $5120-$5127 switch to mode A
+ $5128-$512b switch to mode B
+ $5127 [0]-[7] modeA
+ $512b [0]-[7] modeB
+
+ < page_size=4k >
+ $5120-$5127 switch to mode A
+ $5128-$512b switch to mode B
+ $5123 [0]-[3] modeA
+ $5127 [4]-[7] modeA
+ $512b [0]-[3],[4]-[7] modeB
+
+ < page_size=2k >
+ $5120-$5127 switch to mode A
+ $5128-$512b switch to mode B
+ $5121 [0]-[1] modeA
+ $5123 [2]-[3] modeA
+ $5125 [4]-[5] modeA
+ $5127 [6]-[7] modeA
+ $5129 [0]-[1],[4]-[5] modeB
+ $512b [2]-[3],[6]-[7] modeB
+ < page_size=1k >
+ $5120-$5127 switch to mode A
+ $5128-$512b switch to mode B
+ $5120 [0] modeA
+ $5121 [1] modeA
+ $5122 [2] modeA
+ $5123 [3] modeA
+ $5124 [4] modeA
+ $5125 [5] modeA
+ $5126 [6] modeA
+ $5127 [7] modeA
+ $5128 [0],[4] modeB
+ $5129 [1],[5] modeB
+ $512a [2],[6] modeB
+ $512b [3],[7] modeB
+
+Consideration
+ MMC5 has mode A ,mode B and 2 kinds of CHR-page memory resistors.
+They can be used for refreshing it. (?-SB)
+
+5130 ???
+analyzing it...
+
+5200 W Split Mode Control 1
+ bit Ec-vvvvv
+ For the E function 0:don't use 1:use
+ c boundary's side is for using Split Mode extension of graphics
+   0: left side  1: right side
+ vvvvv left boundary is designated with the char. # to count places
+
+Sample.
+  5200 <- #00
+    (not?) used yet
+  5200 <- #82
+    Used for SplitMode GFX extension from left 1-2 character
+  5200 <- #c2
+    Used for SplitMode GFX extension from the right side 3 chars.
+  5200 <- #c0
+    Used for SplitMode GFX extension on the whole screen
+  5200 <- #d0
+    Used for SplitMode GFX extension on the right side of the screen
+  5200 <- #90
+    Used for SplitMode GFX extension on the left side of the screen
+    
+5201 W SplitMode setup for SplitMode Ext. GFX use 1
+  $2005 determines the vertical movement; it can also delay ext. gfx's
+ vert. movement if necessary.  It's written 2 times in bulk in the same
+ way as it would slip off a grade in $2005 (??-SB)
+  
+5202 W SplitMode setup for SplitMode Ext. GFX use 2
+   bit --pppppp
+  uses vertical division of ext. gfx CHR-page designation
+  index_size=4k(0x1000byte)
+In case it uses a character 0x4000-0x4fff for the ext. gfx in question
+  $5202 <- 4
+
+5203 W scanline break point
+  For scanline # that it splits and wants to make it designate it in bulk
+
+5204 WR IRQ enable/disable
+ W bit I-------
+  I 1:IRQ Enable 0:IRQ Disable
+ R bit I-------
+  I 1:Scanline Hit 0:Scanline not Hit
+   $5203 is designated as scanline when arrived.
+
+5205 WR mult input/output
+5206 WR mult input/output
+($5205in)*($5206in) = $5205,$5206out
+
+5c00-5fbf ext. gfx business VRAM
+ shows an attribute of every position character
+
+  <ExGrafix Mode>
+  bit PPpppppp
+    PP: use character palette number
+    pppppp: use background CHR-PAGE number index=4k
+      #0-#3F are designations, $0000-$3FFF is CHR-data's range
+    Use for extension gfx
+
+  <Split Mode>
+  SplitMode uses a Name Table for extension gfx use.
+  bit pppppppp
+    pppppppp: use for background char. number designation
+
+  <ExRAM Mode>
+ Used for Extension RAM
+
+5fc0-5fff
+  <ExGrafix Mode>
+  (not?) used yet
+
+  <Split Mode>
+  SplitMode uses gfx's Attribute Table extension.
+  PPU uses $23c0-$23ff in the same way as the Attribute Table
+
+  <ExRAM Mode>
+ Used for Extension RAM
+
+Consideration
+ 5c00-5fff has 3 uses.
+ Split Mode and ExGrafix Mode's VBlank is written so as to become
+  crowded, it writes a 0 and becomes crowded.
+ Every mode tries to go around ExRAM mode including reading but it
+  writes it, is effective in bulk and #5c-#5f is the output at times
+  where it is effective.
\ No newline at end of file
diff --git a/Documentation/tech/exp/mmc5_bank_switch.txt b/Documentation/tech/exp/mmc5_bank_switch.txt
new file mode 100644 (file)
index 0000000..b82f38c
--- /dev/null
@@ -0,0 +1,128 @@
+MMC5 Bankswitching
+by Kevin Horton
+--------------------
+
+5100:  Controls paging of RAM and ROM
+
+Bits: ???? ??xx
+
+For xx:
+
+00: 32K bankswitching.  Only 5117 can be used to control banks. 5114 thru
+     5116 have no effect.
+
+
+01: 16K bankswitching. Only 5115 and 5117 can be used to control banks.
+     5114 and 5116 have no effect.
+
+
+10: 8K/16K bankswitching. 5115-5117 are used.  5114 has no effect.
+
+11: 8K bankswitching. 5114-5117 are used.
+
+(See below for detailed description)
+
+--
+
+5113:  RAM page 6000-7FFF bank.  Lower 3 bits are used, for a possible
+        64K of WRAM. (Note more bits *may* be possible for more RAM.
+        This has not been confirmed yet).
+
+Bits: ???? ?xxx
+
+WRAM follows a certain convention, based on the style of MMC5 board used.
+8K and 32K carts are usually implemented with a single chip, while 16K
+carts use two 8K'ers.  This is important since enabling changes, and hence
+valid banks.
+
+for xxx:
+
+      8K         16K        32K        40K        64K
+
+0: bank 0     bank 0     bank 0     bank 0     bank 0
+1: bank 0     bank 0     bank 1     bank 1     bank 1
+2: bank 0     bank 0     bank 2     bank 2     bank 2
+3: bank 0     bank 0     bank 3     bank 3     bank 3
+4: open bus   bank 1     open bus   bank 4     bank 4
+5: open bus   bank 1     open bus   bank 4     bank 5
+6: open bus   bank 1     open bus   bank 4     bank 6
+7: open bus   bank 1     open bus   bank 4     bank 7
+
+Note that the 40K and 64K examples are hypothetical.  The first three,
+however *are* real and is what you find inside a real MMC5 cart.
+
+Also note, that 5114-5116 follow this identical convention, if set up
+to switch in RAM banks.
+
+--
+
+Bankswitching is a bit complicated.  This table should make things clearer.
+The numbers at the top are what you write to 5100 to select mode.
+
+Legend:
+
+-   = this has no effect
+--- = this register is not used, and writes to it are ignored
+R   = PRG ROM/WRAM select.  0=WRAM, 1=PRG ROM
+b   = bank bits
+
+
+
+5100:    00          01          10          11
+
+5114     ---         ---         ---      Rbbb bbbb
+5115     ---      Rbbb bbb-   Rbbb bbb-   Rbbb bbbb
+5116     ---         ---      Rbbb bbbb   Rbbb bbbb
+5117  -bbb bb--   -bbb bbb-   -bbb bbbb   -bbb bbbb
+
+
+Mode 00
+-------
+
+Only one 32K page can be selected.  The lower 2 bits of the desired bank
+are ANDed out.  writing 084h, 085h, 086h, and 087h to 5117 in this mode
+all result in selection of the same 32K.  No RAM is available in this mode.
+
+Mode 01
+-------
+
+There are two selectable 16K pages.  Similar to above, the lowest bit written
+is not used to select banks.  In this mode, writing to 5115 selects 16K
+at 8000-BFFF, and 5117 selects 16K at C000-FFFF. RAM can be enabled in this
+mode for 8000-BFFF.  If RAM is enabled for 8000-BFFF, remember that the
+lowest bank select bit is not used.
+
+Mode 10
+-------
+
+This is the oddest one.  There is one 16K selectable page, and two 8K
+selectable pages.  5115 selects the 16K page at 8000-BFFF, 5116 selects
+an 8K page at C000-DFFF, and 5117 selects an 8K page at E000-FFFF.
+RAM can be enabled for 8000-DFFF. (16K of RAM at 8000-BFFF via bit 7 of
+D115, and 8K of RAM at C000-DFFF via bit 7 of d116).  Note that RAM banking
+works the same as mode 01, above for the 16K bank.
+
+
+Mode 11
+-------
+
+There are 4 8K selectable pages. 5114 controls 8000-9FFF, etc. all the way
+up to 5117 that controls E000-FFFF.  The first 3 pages can use RAM, while
+the last page cannot.
+
+
+--
+
+WRAM write enable.
+
+5102, 5103
+
+To enable writing to RAM, 5102 must have 02h written to it, and 5103
+must have 01h written to it. If this is not the case, you can still
+*read* the RAM, but writes to it have no effect.  Supposidly only the
+lower two bits of 5102 and 5103 are checked, but I didn't verify this.
+I *did* however verify that setting the two registers to the above
+values allows writing.  If voltage goes out of tolerance (Read: you
+turn the power on/off) the RAM writing is disabled.  (To prevent
+corruption of saved-games during power cycling)
+
diff --git a/Documentation/tech/nsfspec.txt b/Documentation/tech/nsfspec.txt
new file mode 100644 (file)
index 0000000..2ef526d
--- /dev/null
@@ -0,0 +1,336 @@
+                            NES Music Format Spec
+                            ---------------------
+
+
+By: Kevin Horton  khorton@iquest.net
+
+
+NOTE:
+-----
+
+
+Remember that I am very willing to add stuff and update this spec.  If
+you find a new sound chip or other change let me know and I will get back
+with you.  E-mail to the above address. 
+
+
+V1.61 - 06/27/2000 Updated spec a bit
+V1.60 - 06/01/2000 Updated Sunsoft, MMC5, and Namco chip information
+V1.50 - 05/28/2000 Updated FDS, added Sunsoft and Namco chips
+V1.32 - 11/27/1999 Added MMC5 register locations
+V1.30 - 11/14/1999 Added MMC5 audio bit, added some register info
+V1.20 - 09/12/1999 VRC and FDS prelim sound info added
+V1.00 - 05/11/1999 First official NSF specification file
+
+
+
+This file encompasses a way to transfer NES music data in a small, easy to
+use format.
+
+The basic idea is one rips the music/sound code from an NES game and prepends
+a small header to the data.
+
+A program of some form (6502/sound emulator) then takes the data and loads
+it into the proper place into the 6502's address space, then inits and plays
+the tune.
+
+Here's an overview of the header:
+
+offset  # of bytes   Function
+----------------------------
+
+0000    5   STRING  "NESM",01Ah  ; denotes an NES sound format file
+0005    1   BYTE    Version number (currently 01h)
+0006    1   BYTE    Total songs   (1=1 song, 2=2 songs, etc)
+0007    1   BYTE    Starting song (1= 1st song, 2=2nd song, etc)
+0008    2   WORD    (lo/hi) load address of data (8000-FFFF)
+000a    2   WORD    (lo/hi) init address of data (8000-FFFF)
+000c    2   WORD    (lo/hi) play address of data (8000-FFFF)
+000e    32  STRING  The name of the song, null terminated
+002e    32  STRING  The artist, if known, null terminated
+004e    32  STRING  The Copyright holder, null terminated
+006e    2   WORD    (lo/hi) speed, in 1/1000000th sec ticks, NTSC (see text)
+0070    8   BYTE    Bankswitch Init Values (see text, and FDS section)
+0078    2   WORD    (lo/hi) speed, in 1/1000000th sec ticks, PAL (see text)
+007a    1   BYTE    PAL/NTSC bits:
+                 bit 0: if clear, this is an NTSC tune
+                 bit 0: if set, this is a PAL tune
+                 bit 1: if set, this is a dual PAL/NTSC tune
+                 bits 2-7: not used. they *must* be 0
+007b    1   BYTE    Extra Sound Chip Support
+                 bit 0: if set, this song uses VRCVI
+                 bit 1: if set, this song uses VRCVII
+                 bit 2: if set, this song uses FDS Sound
+                 bit 3: if set, this song uses MMC5 audio
+                 bit 4: if set, this song uses Namco 106
+                 bit 5: if set, this song uses Sunsoft FME-07
+                 bits 6,7: future expansion: they *must* be 0
+007c    4   ----    4 extra bytes for expansion (must be 00h)
+0080    nnn ----    The music program/data follows
+
+This may look somewhat familiar;  if so that's because this is somewhat
+sorta of based on the PSID file format for C64 music/sound.
+
+
+Loading a tune into RAM
+-----------------------
+
+If offsets 0070h to 0077h have 00h in them, then bankswitching is *not*
+used.  If one or more bytes are something other than 00h then bankswitching
+is used.  If bankswitching is used then the load address is still used,
+but you now use (ADDRESS AND 0FFFh) to determine where on the first bank
+to load the data.
+
+
+Each bank is 4K in size, and that means there are 8 of them for the
+entire 08000h-0ffffh range in the 6502's address space.  You determine where
+in memory the data goes by setting bytes 070h thru 077h in the file.
+These determine the inital bank values that will be used, and hence where
+the data will be loaded into the address space.
+
+Here's an example:
+
+METROID.NSF will be used for the following explaination.
+
+The file is set up like so:  (starting at 070h in the file)
+
+
+0070: 05 05 05 05 05 05 05 05 - 00 00 00 00 00 00 00 00
+0080: ... music data goes here...
+
+Since 0070h-0077h are something other than 00h, then we know that this
+tune uses bankswitching.  The load address for the data is specified as
+08000h.  We take this AND 0fffh and get 0000h, so we will load data in
+at byte 0 of bank 0, since data is loaded into the banks sequentially
+starting from bank 0 up until the music data is fully loaded.
+
+Metroid has 6 4K banks in it, numbered 0 through 5.  The 6502's address
+space has 8 4K bankswitchable blocks on it, starting at 08000h-08fffh,
+09000h-09fffh, 0a000h-0afffh ... 0f000h-0ffffh.  Each one of these is 4K in
+size, and the current bank is controlled by writes to 05ff8h thru 05fffh,
+one byte per bank.  So, 05ff8h controls the 08000h-08fffh range, 05ff9h 
+controls the 09000h-09fffh range, etc. up to 05fffh which controls the 
+0f000h-0ffffh range.  When the song is loaded into RAM, it is loaded into
+the banks and not the 6502's address space.  Once this is done, then the
+bank control registers are written to set up the inital bank values.
+To do this, the value at 0070h in the file is written to 05ff8h, 0071h
+is written to 05ff9h, etc. all the way to 0077h is written to 05fffh.
+This is should be done before every call to the init routine.
+
+If the tune was not bankswitched, then it is simply loaded in at the 
+specified load address, until EOF
+
+
+Initalizing a tune
+------------------
+
+This is pretty simple.  Load the desired song # into the accumulator,
+minus 1 and set the X register to specify PAL (X=1) or NTSC (X=0).
+If this is a single standard tune (i.e. PAL *or* NTSC but not both)
+then the X register contents should not matter.  Once the song # and
+optional PAL/NTSC standard are loaded, simply call the INIT address.
+Once init is done, it should perform an RTS.
+
+
+Playing a tune
+--------------
+
+Once the tune has been initalized, it can now be played.  To do this,
+simply call the play address several times a second.  How many times
+per second is determined by offsets 006eh and 006fh in the file.
+These bytes denote the speed of playback in 1/1000000ths of a second.  
+For the "usual" 60Hz playback rate, set this to 411ah.  
+
+To generate a differing playback rate, use this formula:
+
+
+         1000000
+PBRATE= ---------
+          speed
+
+Where PBRATE is the value you stick into 006e/006fh in the file, and
+speed is the desired speed in hertz. 
+
+
+"Proper" way to load the tune
+-----------------------------
+
+1) If the tune is bankswitched, go to #3.
+
+2) Load the data into the 6502's address space starting at the specified
+   load address. Go to #4.
+
+3) Load the data into a RAM area, starting at (start_address AND 0fffh).
+
+4) Tune load is done.
+
+
+"Proper" way to init a tune
+---------------------------
+
+1) Clear all RAM at 0000h-07ffh.
+
+2) Clear all RAM at 6000h-7fffh.
+
+3) Init the sound registers by writing 00h to 04000-0400Fh, 10h to 4010h,
+   and 00h to 4011h-4013h.
+
+4) Set volume register 04015h to 00fh.
+
+5) If this is a banked tune, load the bank values from the header into
+   5ff8-5fffh.
+
+6) Set the accumulator and X registers for the desired song.
+
+7) Call the music init routine.
+
+
+"Proper" way to play a tune
+---------------------------
+
+1) Call the play address of the music at periodic intervals determined
+   by the speed words.  Which word to use is determined by which mode
+   you are in- PAL or NTSC.
+
+
+Sound Chip Support
+------------------
+
+Byte 007bh of the file stores the sound chip flags.  If a particular flag
+is set, those sound registers should be enabled.  If the flag is clear,
+then those registers should be disabled.
+
+* VRCVI Uses registers 9000-9002, A000-A002, and B000-B002, write only.
+
+Caveats: 1) The above registers are *write only* and must not disrupt music
+            code that happens to be stored there.
+
+         2) Major caveat:  The A0 and A1 lines are flipped on a few games!!
+            If you rip the music and it sounds all funny, flip around 
+            the xxx1 and xxx2 register pairs.  (i.e. 9001 and 9002)  9000
+            and 9003 can be left untouched.  I decided to do this since it 
+            would make things easier all around, and this means you only 
+            will have to change the music code in a very few places (6).
+            Esper2 and Madara will need this change, while Castlevania 3j
+            will not for instance.
+         
+         3) See my VRCVI.TXT doc for a complete register description.
+
+* VRCVII Uses registers 9010 and 9030, write only.
+
+Caveats: 1) Same caveat as #1, above.
+
+         2) See my VRCVII.TXT doc for a complete register description.
+
+* FDS Sound uses registers from 4040 through 4092.
+
+Caveats: 1) 6000-DFFF is assumed to be RAM, since 6000-DFFF is RAM on the
+            FDS.  E000-FFFF is usually not included in FDS games because
+            it is the BIOS ROM.  However, it can be used on FDS rips to help
+            the ripper (for modified play/init addresses).
+
+         2) Bankswitching operates slightly different on FDS tunes.  
+            5FF6 and 5FF7 control the banks 6000-6FFF and 7000-7FFF 
+            respectively.  NSF header offsets 76h and 77h correspond to
+            *both* 6000-7FFF *AND* E000-FFFF.  Keep this in mind!
+
+* MMC5 Sound Uses registers 5000-5015, write only as well as 5205 and 5206,
+            and 5C00-5FF5
+
+Caveats: 1) Generating a proper doc file.  Be patient.  
+
+         2) 5205 and 5206 are a hardware 8*8 multiplier.  The idea being
+            you write your two bytes to be multiplied into 5205 and 5206
+            and after doing so, you read the result back out.  Still working
+            on what exactly triggers it (I think a write to either 5205
+            or 5206 triggers the multiply).
+
+         3) 5C00-5FF5 should be RAM to emulate EXRAM while in MMC5 mode.
+
+Note: Thanks to Mamiya for the EXRAM info.
+
+
+* Namco 106 Sound Uses registers 4800 and F800.  
+
+            This works similar to VRC7.  4800 is the "data" port which is
+            readable and writable, while F800 is the "address" port and is
+            writable only.
+
+            The address is 7 bits plus a "mode" bit.  Bit 7 controls
+            address auto-incrementing.  If bit 7 is set, the address will
+            auto-increment after a byte of data is read or written from/to
+            4800.
+
+            $40 ffffffff f:frequency L
+            $42 ffffffff f:frequency M
+            $44 ---sssff f:frequency H s:tone length (8-s)*4 in 4bit-samples
+            $46 tttttttt t:tone address(4bit-address,$41 means high-4bits of $20)
+            $47 -cccvvvv v:linear volume 1+c:number of channels in use($7F only)
+            $40-47:ch1 $48-4F:ch2 ... $78-7F:ch8
+            ch2-ch8 same to ch1
+
+            $00-3F(8ch)...77(1ch) hhhhllll tone data
+            h:odd address data(signed 4bit)
+            l:even address data(signed 4bit)
+
+            real frequency = (f * NES_BASECYCLES) / (40000h * (c+1) * (8-s)*4 * 45)
+            NES_BASECYCLES 21477270(Hz)
+
+Note:  Very Special thanks to Mamiya for this information!
+
+
+* Sunsoft FME-07 Sound uses registers C000 and E000
+
+            This is similar to the common AY 3-8910 sound chip that is
+            used on tons of arcade machines, and in the Intellivision.
+
+            C000 is the address port
+            E000 is the data port
+
+            Both are write-only, and behave like the AY 3-8910.
+
+Note:  Special thanks to Mamiya for this information as well
+
+
+Caveats
+-------
+
+1) The starting song number and maximum song numbers start counting at
+   1, while the init address of the tune starts counting at 0.  To
+   "fix", simply pass the desired song number minus 1 to the init
+   routine.
+
+2) The NTSC speed word is used *only* for NTSC tunes, or dual PAL/NTSC tunes.
+   The PAL speed word is used *only* for PAL tunes, or dual PAL/NTSC tunes.
+
+3) The length of the text in the name, artist, and copyright fields must 
+   be 31 characters or less!  There has to be at least a single NULL byte
+   (00h) after the text, between fields.
+
+4) If a field is not known (name, artist, copyright) then the field must
+   contain the string "<?>" (without quotes).  
+
+5) There should be 8K of RAM present at 6000-7FFFh. MMC5 tunes need RAM at
+   5C00-5FF7 to emulate its EXRAM. 8000-FFFF Should be read-only (not 
+   writable) after a tune has loaded.  The only time this area should be 
+   writable is if an FDS tune is being played.
+
+6) Do not assume the state of *anything* on entry to the init routine
+   except A and X.  Y can be anything, as can the flags.  
+
+7) Do not assume the state of *anything* on entry to the play routine either.
+   Flags, X, A, and Y could be at any state.  I've fixed about 10 tunes
+   because of this problem and the problem, above.
+
+8) The stack sits at 1FFh and grows down.  Make sure the tune does not
+   attempt to use 1F0h-1FFh for variables. (Armed Dragon Villigust did and
+   I had to relocate its RAM usage to 2xx)
+
+9) Variables should sit in the 0000h-07FFh area *only*.  If the tune writes
+   outside this range, say 1400h this is bad and should be relocated. 
+   (Terminator 3 did this and I relocated it to 04xx).
+
+That's it!
+
+
+
diff --git a/Documentation/tech/ppu/loopy1.txt b/Documentation/tech/ppu/loopy1.txt
new file mode 100644 (file)
index 0000000..bda6d85
--- /dev/null
@@ -0,0 +1,63 @@
+Subject: [nesdev] the skinny on nes scrolling\r
+Date: Tue, 13 Apr 1999 16:42:00 -0600\r
+From: loopy <zxcvzxcv@netzero.net>\r
+Reply-To: nesdev@onelist.com\r
+To: nesdev@onelist.com\r
+\r
+From: loopy <zxcvzxcv@netzero.net>\r
+\r
+---------\r
+the current information on background scrolling is sufficient for most games;\r
+however, there are a few that require a more complete understanding.\r
+\r
+here are the related registers:\r
+        (v) vram address, a.k.a. 2006 which we all know and love.  (16 bits)\r
+        (t) another temp vram address (16 bits)\r
+           (you can really call them 15 bits, the last isn't used)\r
+       (x) tile X offset (3 bits)\r
+\r
+the ppu uses the vram address for both reading/writing to vram thru 2007,\r
+and for fetching nametable data to draw the background.  as it's drawing the\r
+background, it updates the address to point to the nametable data currently\r
+being drawn.  bits 0-11 hold the nametable address (-$2000).  bits 12-14 are\r
+the tile Y offset.\r
+\r
+---------\r
+stuff that affects register contents:\r
+(sorry for the shorthand logic but i think it's easier to see this way)\r
+\r
+2000 write:\r
+        t:0000110000000000=d:00000011\r
+2005 first write:\r
+        t:0000000000011111=d:11111000\r
+        x=d:00000111\r
+2005 second write:\r
+        t:0000001111100000=d:11111000\r
+        t:0111000000000000=d:00000111\r
+2006 first write:\r
+        t:0011111100000000=d:00111111\r
+        t:1100000000000000=0\r
+2006 second write:\r
+        t:0000000011111111=d:11111111\r
+        v=t\r
+scanline start (if background and sprites are enabled):\r
+        v:0000010000011111=t:0000010000011111\r
+frame start (line 0) (if background and sprites are enabled):\r
+        v=t\r
+\r
+note!  2005 and 2006 share the toggle that selects between first/second\r
+writes.  reading 2002 will clear it.\r
+\r
+note!  all of this info agrees with the tests i've run on a real nes.  BUT\r
+if there's something you don't agree with, please let me know so i can verify\r
+it.\r
+\r
+________________________________________________________\r
+NetZero - We believe in a FREE Internet.  Shouldn't you?\r
+Get your FREE Internet Access and Email at\r
+http://www.netzero.net/download.html\r
+\r
+------------------------------------------------------------------------\r
+New hobbies? New curiosities? New enthusiasms?\r
+http://www.ONElist.com\r
+Sign up for a new e-mail list today!\r
diff --git a/Documentation/tech/ppu/loopy2.txt b/Documentation/tech/ppu/loopy2.txt
new file mode 100644 (file)
index 0000000..7a4585e
--- /dev/null
@@ -0,0 +1,33 @@
+Subject: [nesdev] Re: the skinny on nes scrolling\r
+Date: Tue, 13 Apr 1999 17:48:54 -0600\r
+From: loopy <zxcvzxcv@netzero.net>\r
+Reply-To: nesdev@onelist.com\r
+To: nesdev@onelist.com\r
+\r
+From: loopy <zxcvzxcv@netzero.net>\r
+\r
+(more notes on ppu logic)\r
+\r
+you can think of bits 0,1,2,3,4 of the vram address as the "x scroll"(*8)\r
+that the ppu increments as it draws.  as it wraps from 31 to 0, bit 10 is\r
+switched.  you should see how this causes horizontal wrapping between name\r
+tables (0,1) and (2,3).\r
+\r
+you can think of bits 5,6,7,8,9 as the "y scroll"(*8).  this functions\r
+slightly different from the X.  it wraps to 0 and bit 11 is switched when\r
+it's incremented from _29_ instead of 31.  there are some odd side effects\r
+from this.. if you manually set the value above 29 (from either 2005 or\r
+2006), the wrapping from 29 obviously won't happen, and attrib data will be\r
+used as name table data.  the "y scroll" still wraps to 0 from 31, but\r
+without switching bit 11.  this explains why writing 240+ to 'Y' in 2005\r
+appeared as a negative scroll value.\r
+\r
+________________________________________________________\r
+NetZero - We believe in a FREE Internet.  Shouldn't you?\r
+Get your FREE Internet Access and Email at\r
+http://www.netzero.net/download.html\r
+\r
+------------------------------------------------------------------------\r
+Looking for a new hobby?  Want to make a new friend?\r
+http://www.ONElist.com\r
+Come join one of the 115,000 e-mail communities at ONElist!\r
diff --git a/Documentation/tech/ppu/timing.txt b/Documentation/tech/ppu/timing.txt
new file mode 100644 (file)
index 0000000..6a669b4
--- /dev/null
@@ -0,0 +1,266 @@
+NTSC PPU timing
+by Samus Aran (livingmonolith@hotmail.com)
+date: Sept. 25th, Y2K
+
+This weekend, I setup an experiment with my NTSC NES MB & my PC so's I could 
+RE the PPU's timing. What I did was (using a PC interface) analyse the 
+changes that occur on the PPU's address and data pins on every rising & 
+falling edge of the PPU's clock. I was not planning on removing the PPU from 
+the motherboard (yet), so basically I just kept everything intact (minus the 
+stuff I added onto the MB so I could monitor the PPU's signals), and popped 
+in a game, so that it would initialize the PPU for me (I used DK classics, 
+since it was only taking somthing like 4 frames before it was turning on the 
+background/sprites).
+
+The only change I made was taking out the 21 MHz clock generator circuitry. 
+To replace the clock signal, I connected a port controlled latch to the 
+NES's main clock line instead. Now, by writing a 0 or a 1 out to an PC ISA 
+port of my choice (I was using $104), I was able to control the 21 MHz 
+clockline of the NES. After I would create a rise or a fall on the NES's 
+clock line, I would then read in the data that appeared on the PPU's address 
+and data pins, which included monitoring what PPU registers the game 
+read/wrote to (& the data that was read/written).
+
+My findings:
+
+- The PPU makes NO external access to name or character tables, unless the 
+background or sprites are enabled. This means that the PPU's address and 
+data busses are dead while in this state.
+
+- Because the PPU's palette RAM is internal to it, the PPU has multiport 
+access to it, and therefore, instant access to it at all times (this is why 
+reading palette RAM via $2007 does not require a throw-away read). This is 
+why when a scanline is being rendered, never does the PPU put the palette 
+address on it's bus; it's simply unneccessary. Additionally, when the 
+programmer accesses palette RAM via $2006/7, the palette address accessed 
+actually does show up on the PPU's external address bus, but the PPU's /R & 
+/W flags are not activated. This is required; to prevent writing over name 
+table data falling under the approprite mirrored area. I don't know why 
+Nintendo didn't just devote an exclusive area for palette RAM, like it did 
+for sprite RAM.
+
+- Sprite DMA is 6144 clock cycles long (or in CPU clock cycles, 6144/12). 
+256 individual transfers are made from CPU memory to a temp register inside 
+the CPU, then from the CPU's temp reg, to $2004.
+
+- One scanline is EXACTLY 1364 cycles long. In comparison to the CPU's 
+speed, one scanline is 1364/12 CPU cycles long.
+
+- One frame is EXACTLY 357368 cycles long, or EXACTLY 262 scanlines long.
+
+
+Sequence of pixel rendering
+---------------------------
+
+External PPU memory is accessed every 8 clock cycles by the PPU when it's 
+drawing the background. Therefore, the PPU will typically access external 
+memory 170 times per scanline. After the 170th fetch, the PPU does nothing 
+for 4 clock cycles (except in the case of a 1360 clock cycle scanline (more 
+on this later)), and thus making the scanline up of 1364 cycles.
+
+       accesses
+       --------
+
+         1 thru 128:
+
+               1. Fetch 1 name table byte
+               2. Fetch 1 attribute table byte
+               3. Fetch 2 pattern table bitmap bytes
+
+               This process is repeated 32 times (32 tiles in a scanline).
+
+               This is when the PPU retrieves the appropriate data from PPU memory for 
+rendering the background. The first background tile fetched here is actually 
+the 3rd to be drawn on the screen (the background data for the first 2 tiles 
+to be rendered on the next scanline are fetched at the end of the scanline 
+prior to this one).
+
+In one complete cycle of fetches (4 fetches, or 32 cycles), the PPU renders 
+or draws 8 pixels on the screen. However, this does not suggest that the PPU 
+is always drawing on-screen results while background data is being fetched. 
+There is a delay inside the PPU from when the first background tile is 
+fetched, and when the first pixel to be displayed on the screen is rendered. 
+It is important to be aware of this delay, since it specifically relates to 
+the "sprite 0 hit" flag's timing. I currently do not know what the delay 
+time is (as far as clock cycles go).
+
+               Note that the PPU fetches a nametable byte for every 8 horizontal pixels 
+it draws. It should be understood that with some custom cartridge hardware, 
+the PPU's color area could be increased (more about this at the end of this 
+document).
+
+               It is also during this time that the PPU evaluates the "Y coordinate" 
+entries of all 64 sprites (starting with sprite 0) in sprite RAM, to see if 
+the sprites are within range (to be drawn on the screen) FOR THE NEXT 
+SCANLINE. For sprite entries that have been found to be in range, they (that 
+is, the sprite's nametable, and x coordinate bytes, attribute (5 bits) and 
+fine y scroll (3 or 4 bits, depending on bit 5 of $2000 ("sprite size")) 
+bits) accumulate into a part of PPU memory called the "sprite temporary 
+memory", which is big enough to hold the data for up to 8 sprites. If 8 
+sprites have accumulated into the temporary memory and the PPU is still 
+finding more sprites in range for drawing on the next scanline, then the 
+sprite data is ignored (not loaded into the sprite temporary memory), and 
+the PPU raises a flag (bit 5 of $2002) indicating that it is going to be 
+dropping sprites for the next scanline.
+
+       129 thru 160:
+
+               1. Fetch 2 garbage name table bytes
+               2. Fetch 2 pattern table bitmap bytes for applicable sprites ON THE NEXT 
+SCANLINE
+
+               This process is repeated 8 times.
+
+               This is the period of time when the PPU retrieves the appropriate pattern 
+table data for the sprites to be drawn on the next scanline. Where the PPU 
+fetches pattern table data for an individual sprite depends on the nametable 
+byte, and fine y scroll bits of a single sprite entry in the sprite 
+temporary memory, and bits 3 and 5 of $2000 ("sprite pattern table select" 
+and "sprite size" bits, respectively). The fetched pattern table data (which 
+is 2 bytes), plus the associated 5 attribute bytes, and the x coordinate 
+byte in sprite temporary memory are then loaded into a part of the PPU 
+called the "sprite buffer memory". This memory area again, is large enough 
+to hold the contents for 8 sprites. The makeup of one sprite memory cell 
+here is composed of 2 8-bit shift registers (the fetched pattern table data 
+is loaded in here, where it will be serialized at the appropriate time), a 
+5-bit latch (which holds the attribute data for a sprite), and a 8-bit down 
+counter (this is where the x coordinate is loaded). The counter is 
+decremented every time the PPU draws a pixel on screen, and when the counter 
+reaches 0, the pattern table data in the shift registers will start to 
+serialize, and be drawn on the screen.
+
+               Even if no sprites exist on the next scanline, a pattern table fetch takes 
+place.
+
+               Although the fetched name table data is thrown away, I still can't make 
+much sense out of the name table address accesses the PPU makes during this 
+time. However, the address does seem to relate to the first name table tile 
+to be rendered on the screen.
+
+               It should also be noted that because this fetch is required for sprites on 
+the next line, it is neccessary for a garbage scanline to exist prior to the 
+very first scanline to be actually rendered, so that sprite RAM entries can 
+be evaluated, and the appropriate bitmap data retrieved.
+
+                Finally, it would appear to me that the PPU's 8 sprite/scanline 
+bottleneck exists clearly because the PPU could only find the time in one 
+scanline to fetch the pattern bitmaps for 8 sprites. However, why the PPU 
+doesn't attempt to access pattern table data in the time when it fetches 2 
+garbage name table bytes is a good question.
+
+       161 thru 168:
+
+               1. Fetch 1 name table byte
+               2. Fetch 1 attribute table byte
+               3. Fetch 2 pattern table bitmap bytes
+
+               This process is repeated 2 times.
+
+               It is during this time that the PPU fetches the appliciable background 
+data for the first and second tiles to be rendered on the screen for the 
+next scanline. The rest of tiles (3..128) are fetched at the beginning of 
+the following scanline.
+
+       169 thru 170:
+
+               1. Fetch 1 name table byte
+
+               This process is repeated 2 times.
+
+               I'm unclear of the reason why this particular access to memory is made. 
+The nametable address that is accessed 2 times in a row here, is also the 
+same nametable address that points to the 3rd tile to be rendered on the 
+screen (or basically, the first nametable address that will be accessed when 
+the PPU is fetching background data on the next scanline).
+
+
+       After memory access 170, the PPU simply rests for 4 cycles (or the 
+equivelant of half a memory access cycle) before repeating the whole 
+pixel/scanline rendering process. If the scanline being rendered is the very 
+first one on every second frame, then this delay simply doesn't exist.
+
+
+Sequence of line rendering
+--------------------------
+
+       1. Starting at the instant the VINT flag is pulled down (when a NMI is 
+generated), 20 scanlines make up the period of time on the PPU which I like 
+to call the VINT period. During this time, the PPU makes NO access to it's 
+external memory (i.e. name / pattern tables, etc.).
+
+       2. After 20 scanlines worth of time go by (since the VINT flag was set), 
+the PPU starts to render scanlines. Now, the first scanline it renders is a 
+dummy one; although it will access it's external memory in the same sequence 
+it would for drawing a valid scanline, the fetched background data is thrown 
+away, and the places that the PPU accesses name table data is unexplainable 
+(for now).
+
+IMPORTANT! this is the only scanline that has variable length. On every 
+second rendered frame, this scanline is only 1360 cycles. Otherwise it's 
+1364.
+
+       3. after rendering 1 dummy scanline, the PPU starts to render the actual 
+data to be displayed on the screen. This is done for 240 scanlines, of 
+course.
+
+       4. after the very last rendered scanline finishes, the PPU does nothing for 
+1 scanline (i.e. makes no external memory accesses). When this scanline 
+finishes, the VINT flag is set, and the process of drawing lines starts all 
+over again.
+
+This makes a total of 262 scanlines. Although one scanline is slightly 
+shorter on every second rendered frame (4 cycles), I don't know if this 
+feature is neccessary to implement in emulators, since it only makes 1/3 a 
+CPU cycle difference per frame (and there's NO way that a game could take 
+into account 1/3 of a CPU cycle).
+
+
+Food for thought
+----------------
+
+What's important to remember about the NES's 2C02 or picture proecssing unit 
+(hereon PPU) is that all screen data is fetched & drawn on a real-time 
+basis. For example, let's consider how the PPU draws background tiles.
+
+We know that one name table byte is associated with an 8x8 cluster of pixels 
+(and therefore, 16 bytes worth of pattern bitmap data, plus 2 attribute 
+bits). Therefore, it would make sense for the PPU to only have to fetch a 
+name table byte once for each 8x8 pixel array it draws (one tile), and 1 
+attribute byte fetch for every 4x4 tile matrix that it draws. However, since 
+the PPU always draws one complete scanline before drawing the next, The PPU 
+will actually fetch the same name table byte 8 times, once each scanline at 
+the appropriate x coordinate. Since these name table address access reads 
+are redundant, with some custom cartridge hardware, it would be possible to 
+make the PPU appear as if it had background tiles as small as 8x1 pixels!
+
+Additionally, an attribute table byte is fetched from name table RAM once 
+per 2 fetched pattern bitmap bytes (or, every 8 pixels worth of pattern 
+bitmap data). This is useful information to keep in mind, for with some 
+custom cartridge hardware, this would allow the NES's PPU to appear to have 
+an effective color area as small as of 8*1 pixels (!), where only the 8 
+pixels are limited to having 4 exclusive colors, which, is *alot* better 
+than the PPU's default color area of 16x16 pixels.
+
+So basically, what I'm getting at here, is that the PPU has absolutely NO 
+memory whatsoever of what it rendered last scanline, and therefore all data 
+must be processed/evaluated again, whether it's name table accesses, 
+attribute table accesses, or even it's internal sprite RAM accesses.
+
+What's good, and what's bad about the way the PPU draws it's pictures:
+
+What's good about it is that it makes the PPU a hell of alot more versatile, 
+provided you have the appropriate hardware to assist in the improvement of 
+the PPU's background drawing techniques (MMC5 comes to mind). Also, by doing 
+background rendering in the real time, the PPU complexity is less, and less 
+internal temporary registers are required.
+
+What's bad about it is that it eats up memory bandwidth like it's going out 
+of style. When the PPU is rendering scanlines, the PPU is accessing the VRAM 
+every chance it gets, which takes away from the time that the programmer 
+gets to access the VRAM. In contrast, if redundantly loaded data (like 
+attribute bytes) were kept in internal PPU RAM, this would allow some time 
+for the PPU to allow access to it's VRAM.
+
+All in all though, Nintendo engineered quite a cost effective, versatile 
+graphic processor. Now, if only they brought the 4 expansion pins on the PPU 
+out of the deck!
diff --git a/Makefile.base b/Makefile.base
new file mode 100644 (file)
index 0000000..3e3f273
--- /dev/null
@@ -0,0 +1,42 @@
+CFLAGS  = -Wall -Winline ${TFLAGS}
+OBJECTS = fce.o x6502.o video.o general.o endian.o svga.o sound.o nsf.o fds.o netplay.o ines.o state.o unif.o input.o file.o cart.o crc32.o memory.o cheat.o debug.o
+
+fceu:          fceu2
+include        mappers/Makefile
+include boards/Makefile
+include mbshare/Makefile
+include input/Makefile
+
+fceu2:         ${OBJECTS} ${MOBJS} ${MUOBJS} ${MUSOBJS} ${INPOBJS} ${OBJDRIVER}
+               ${CC} -s -o fceu ${OBJECTS} ${MOBJS} ${MUOBJS} ${MUSOBJS} ${INPOBJS} ${OBJDRIVER} ${LDRIVER}
+
+clean:
+               ${RM} fceu fceu.exe ${OBJECTS} ${INPOBJS} ${MOBJS} ${MUOBJS} ${MUSOBJS} ${OBJDRIVER}
+
+nsf.o:         nsf.c nsf.h fce.h x6502.h svga.h video.h sound.h nsfbgnew.h general.h file.h
+x6502.o:       x6502.c x6502.h ops.h fce.h sound.h
+video.o:       video.c types.h video.h svga.h version.h general.h
+sound.o:       sound.c sound.h types.h fce.h svga.h x6502.h
+svga.o:                svga.c svga.h types.h palette.h state.h netplay.h fds.h fce.h nsf.h video.h sound.h palettes/*.h driver.h drawing.h
+netplay.o:     netplay.c netplay.h types.h svga.h
+
+state.o:        state.c state.h
+
+unif.o:                unif.c unif.h file.h cart.h
+
+memory.o:      memory.c memory.h
+
+cart.o:                cart.c cart.h types.h version.h fce.h
+fce.o:          fce.c *.h
+fds.o:         fds.h x6502.h types.h version.h fce.h svga.h sound.h general.h state.h file.h memory.h
+ines.o:         ines.c ines.h x6502.h types.h fce.h ines.h version.h svga.h general.h state.h file.h memory.h cart.h crc32.h banksw.h
+input.o:       input.c input.h x6502.h types.h fce.h sound.h netplay.h driver.h svga.h
+
+crc32.o:       crc32.c crc32.h types.h
+endian.o:      endian.c endian.h types.h
+file.o:                file.c file.h types.h endian.h memory.h driver.h
+general.o:     general.c general.h types.h state.h version.h
+
+cheat.o:       cheat.c driver.h
+
+debug.o:       debug.c debug.h fce.h
diff --git a/Makefile.beos b/Makefile.beos
new file mode 100644 (file)
index 0000000..0537114
--- /dev/null
@@ -0,0 +1,23 @@
+CC     = gcc 
+TFLAGS  = -no-fpic -DC80x86 -DNETWORK -DFPS `sdl-config --cflags` -mcpu=i686 -O2 -Izlib -fomit-frame-pointer -DLSB_FIRST -DSDL -DUNIX -DPSS_STYLE=1 -DZLIB
+RM     = rm -f
+B      = drivers/cli/
+
+all:           fceu
+
+include zlib/Makefile
+
+OBJDRIVER      = ${B}sdl.o ${B}main.o ${B}throttle.o ${B}sdl-netplay.o ${B}sdl-sound.o ${B}sdl-video.o ${B}sdl-joystick.o drivers/common/cheat.o drivers/common/config.o drivers/common/args.o drivers/common/vidblit.o ${UNZIPOBJS}
+LDRIVER                = -static `sdl-config --libs` -lz -lSDL_net
+
+include Makefile.base
+
+${B}sdl-joystick.o:    ${B}sdl-joystick.c
+${B}main.o:            ${B}main.c ${B}main.h ${B}usage.h ${B}input.c ${B}keyscan.h
+${B}sdl.o:             ${B}sdl.c ${B}sdl.h
+${B}sdl-video.o:       ${B}sdl-video.c
+${B}sdl-sound.o:       ${B}sdl-sound.c
+${B}sdl-netplay.o:     ${B}sdl-netplay.c
+${B}throttle.o:         ${B}throttle.c ${B}main.h ${B}throttle.h
+
+include Makefile.common
diff --git a/Makefile.common b/Makefile.common
new file mode 100644 (file)
index 0000000..891b77a
--- /dev/null
@@ -0,0 +1,6 @@
+drivers/common/cheat.o:         drivers/common/cheat.c drivers/common/cheat.h
+drivers/common/config.o:        drivers/common/config.c drivers/common/config.h
+drivers/common/args.o:          drivers/common/args.c drivers/common/args.h
+drivers/common/unixdsp.o:       drivers/common/unixdsp.c drivers/common/unixdsp.h
+drivers/common/videblit.o:      drivers/common/vidblit.c drivers/common/vidblit.h
+
diff --git a/Makefile.dos b/Makefile.dos
new file mode 100644 (file)
index 0000000..bef31aa
--- /dev/null
@@ -0,0 +1,23 @@
+CC     = gcc 
+TFLAGS  = -O2 -mcpu=i686 -Izlib -fomit-frame-pointer -DC80x86 -DLSB_FIRST -DDOS -DPSS_STYLE=2 -DZLIB -D_USE_LIBM_MATH_H
+RM     = del
+B      = drivers/cli/
+
+all:           fceu
+
+include zlib/Makefile
+
+OBJDRIVER      = ${B}main.o ${B}dos.o ${B}throttle.o ${B}dos-joystick.o ${B}dos-keyboard.o ${B}dos-mouse.o ${B}dos-sound.o ${B}dos-video.o drivers/common/cheat.o drivers/common/config.o drivers/common/args.o ${ZLIBOBJS} ${UNZIPOBJS}
+LDRIVER                = -lm
+
+include Makefile.base
+
+${B}main.o:             ${B}main.c ${B}main.h ${B}usage.h ${B}input.c
+${B}dos.o:             ${B}dos.c ${B}dos.h
+${B}throttle.o:         ${B}throttle.c ${B}main.h ${B}throttle.h
+${B}dos-joystick.o:    ${B}dos-joystick.c ${B}dos.h ${B}dos-joystick.h
+${B}dos-keyboard.o:    ${B}dos-keyboard.c ${B}keyscan.h
+${B}dos-mouse.o:       ${B}dos-mouse.c
+${B}dos-sound.o:       ${B}dos-sound.c ${B}dos.h ${B}dos-sound.h ${B}dos-joystick.h
+${B}dos-video.o:       ${B}dos-video.c ${B}dos.h ${B}dos-video.h
+include Makefile.common
diff --git a/Makefile.linuxvga b/Makefile.linuxvga
new file mode 100644 (file)
index 0000000..a123168
--- /dev/null
@@ -0,0 +1,22 @@
+CC     = gcc 
+TFLAGS  = -DFPS -mcpu=i686 -O2 -Izlib -fomit-frame-pointer -DC80x86 -DLSB_FIRST -DSVGALIB -DUNIX -DLINUX -DNETWORK -DPSS_STYLE=1 -DZLIB
+RM     = rm -f
+B      = drivers/cli/
+
+all:           fceu
+
+include zlib/Makefile
+
+OBJDRIVER      = ${B}svgalib.o ${B}main.o ${B}throttle.o ${B}svga-video.o ${B}unix-netplay.o ${B}lnx-joystick.o drivers/common/unixdsp.o drivers/common/cheat.o drivers/common/config.o drivers/common/args.o ${ZLIBOBJS} ${UNZIPOBJS}
+LDRIVER                = -lm -lvga
+
+include Makefile.base
+
+${B}lnx-joystick.o:    ${B}lnx-joystick.c
+${B}main.o:            ${B}main.c ${B}main.h ${B}usage.h ${B}input.c
+${B}throttle.o:                ${B}throttle.c ${B}main.h ${B}throttle.h
+${B}svgalib.o:         ${B}svgalib.c ${B}svgalib.h
+${B}svga-video.o:      ${B}svga-video.c ${B}svga-video.h ${B}vgatweak.c
+${B}unix-netplay.o:    ${B}unix-netplay.c
+
+include Makefile.common
diff --git a/Makefile.unixsdl b/Makefile.unixsdl
new file mode 100644 (file)
index 0000000..d8122d9
--- /dev/null
@@ -0,0 +1,25 @@
+CC     = gcc 
+TFLAGS  = -DNETWORK -DFPS `sdl-config --cflags` -mcpu=i686 -O2 -Izlib -fomit-frame-pointer -DC80x86 -DLSB_FIRST -DSDL -DUNIX -DPSS_STYLE=1 -DZLIB
+
+RM     = rm -f
+B      = drivers/cli/
+
+all:           fceu
+
+include zlib/Makefile
+
+OBJDRIVER      = ${B}sdl.o ${B}main.o ${B}throttle.o ${B}unix-netplay.o ${B}sdl-sound.o ${B}sdl-video.o ${B}sdl-joystick.o drivers/common/cheat.o drivers/common/config.o drivers/common/args.o drivers/common/vidblit.o ${UNZIPOBJS}
+LDRIVER                = -lm `sdl-config --libs` -lz
+
+include Makefile.base
+
+${B}sdl-joystick.o:    ${B}sdl-joystick.c
+${B}main.o:            ${B}main.c ${B}main.h ${B}usage.h ${B}input.c ${B}keyscan.h
+${B}sdl.o:             ${B}sdl.c ${B}sdl.h
+${B}sdl-video.o:       ${B}sdl-video.c
+${B}sdl-sound.o:       ${B}sdl-sound.c
+#${B}sdl-netplay.o:    ${B}sdl-netplay.c
+${B}unix-netplay.o:    ${B}unix-netplay.c
+${B}throttle.o:         ${B}throttle.c ${B}main.h ${B}throttle.h
+
+include Makefile.common
diff --git a/Makefile.win b/Makefile.win
new file mode 100644 (file)
index 0000000..1767c71
--- /dev/null
@@ -0,0 +1,22 @@
+CC     = gcc
+TFLAGS  = -mcpu=i686 -O2 -Izlib -fomit-frame-pointer -DNOSTDOUT -DC80x86 -DLSB_FIRST -DWINDOWS -DNETWORK -DPSS_STYLE=2 -DZLIB
+RM     = del
+B      = drivers/win/
+all:           fceu
+
+include zlib/Makefile
+
+LDRIVER = -mwindows -lddraw -ldinput -ldsound -lgdi32 -ldxguid -lwinmm -lshell32 -lwsock32 -lcomdlg32 -lole32
+OBJDRIVER      = ${B}main.o ${B}input.o ${B}joystick.o ${B}keyboard.o ${B}cheat.o ${B}res.o ${ZLIBOBJS} ${UNZIPOBJS} drivers/common/config.o
+
+include Makefile.base
+
+${B}main.o:            ${B}main.c drivers/win/netplay.c ${B}config.c ${B}throttle.c ${B}video.c drivers/win/window.c drivers/win/sound.c drivers/win/wave.c
+${B}cheat.o:           ${B}common.h ${B}cheat.h
+${B}input.o:           ${B}common.h ${B}input.h ${B}joystick.h ${B}keyboard.h
+${B}joystick.o:                ${B}common.h ${B}joystick.h ${B}input.h
+${B}keyboard.o:                ${B}common.h ${B}keyboard.h ${B}input.h
+drivers/win/res.o:     drivers/win/res.res
+                       windres -o drivers/win/res.o drivers/win/res.res
+
+include Makefile.common
diff --git a/banksw.h b/banksw.h
new file mode 100644 (file)
index 0000000..f45c489
--- /dev/null
+++ b/banksw.h
@@ -0,0 +1,101 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 Bero
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+void FASTAPASS(2) VRAM_BANK1(uint32 A, uint8 V)
+{
+ V&=7;
+ PPUCHRRAM|=(1<<(A>>10));
+ CHRBankList[(A)>>10]=V;
+ VPage[(A)>>10]=&CHRRAM[V<<10]-(A);
+}
+
+void FASTAPASS(2) VRAM_BANK4(uint32 A, uint32 V)
+{
+ V&=1;
+ PPUCHRRAM|=(0xF<<(A>>10));
+ CHRBankList[(A)>>10]=(V<<2);
+ CHRBankList[((A)>>10)+1]=(V<<2)+1;
+ CHRBankList[((A)>>10)+2]=(V<<2)+2;
+ CHRBankList[((A)>>10)+3]=(V<<2)+3;
+ VPage[(A)>>10]=&CHRRAM[V<<10]-(A);
+}
+
+void FASTAPASS(2) VROM_BANK1(uint32 A,uint32 V)
+{
+ setchr1(A,V);
+ CHRBankList[(A)>>10]=V;
+}
+
+void FASTAPASS(2) VROM_BANK2(uint32 A,uint32 V)
+{
+ setchr2(A,V);
+ CHRBankList[(A)>>10]=(V<<1);
+ CHRBankList[((A)>>10)+1]=(V<<1)+1;
+}
+
+void FASTAPASS(2) VROM_BANK4(uint32 A, uint32 V)
+{
+ setchr4(A,V);
+ CHRBankList[(A)>>10]=(V<<2);
+ CHRBankList[((A)>>10)+1]=(V<<2)+1;
+ CHRBankList[((A)>>10)+2]=(V<<2)+2;
+ CHRBankList[((A)>>10)+3]=(V<<2)+3;
+}
+
+void FASTAPASS(1) VROM_BANK8(uint32 V)
+{
+ setchr8(V);
+ CHRBankList[0]=(V<<3);
+ CHRBankList[1]=(V<<3)+1;
+ CHRBankList[2]=(V<<3)+2;
+ CHRBankList[3]=(V<<3)+3;
+ CHRBankList[4]=(V<<3)+4;
+ CHRBankList[5]=(V<<3)+5;
+ CHRBankList[6]=(V<<3)+6;
+ CHRBankList[7]=(V<<3)+7;
+}
+
+void FASTAPASS(2) ROM_BANK8(uint32 A, uint32 V)
+{
+ setprg8(A,V);
+ if(A>=0x8000)
+  PRGBankList[((A-0x8000)>>13)]=V;
+}
+
+void FASTAPASS(2) ROM_BANK16(uint32 A, uint32 V)
+{
+ setprg16(A,V);
+ if(A>=0x8000)
+ {
+  PRGBankList[((A-0x8000)>>13)]=V<<1;
+  PRGBankList[((A-0x8000)>>13)+1]=(V<<1)+1;
+ }
+}
+
+void FASTAPASS(1) ROM_BANK32(uint32 V)
+{
+ setprg32(0x8000,V);
+ PRGBankList[0]=V<<2;
+ PRGBankList[1]=(V<<2)+1;
+ PRGBankList[2]=(V<<2)+2;
+ PRGBankList[3]=(V<<2)+3; 
+}
+
diff --git a/boards/Makefile b/boards/Makefile
new file mode 100644 (file)
index 0000000..58dd4ef
--- /dev/null
@@ -0,0 +1,9 @@
+MUOBJS   =     boards/simple.o boards/malee.o boards/supervision.o boards/novel.o boards/super24.o boards/h2288.o boards/sachen.o
+
+boards/simple.o:       boards/simple.c
+boards/malee.o:                boards/malee.c
+boards/supervision.o:  boards/supervision.c
+boards/novel.o:                boards/novel.c
+boards/super24.o:      boards/super24.c
+boards/h2288.o:                boards/h2288.c
+boards/sachen.o:       boards/sachen.c
diff --git a/boards/h2288.c b/boards/h2288.c
new file mode 100644 (file)
index 0000000..c8ad1e0
--- /dev/null
@@ -0,0 +1,99 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+/* Not finished.  Darn evil game... *Mumble*... */
+
+#include "mapinc.h"
+
+static uint8 cmd;
+static uint8 regs[8];
+
+static void DoPRG(void)
+{
+ if(cmd&0x40)
+ {
+  setprg8(0xC000,regs[4]);
+  setprg8(0xA000,regs[5]);
+  setprg8(0x8000,~1);
+  setprg8(0xE000,~0);
+ }
+ else
+ {
+  setprg8(0x8000,regs[4]);
+  setprg8(0xA000,regs[5]);
+  setprg8(0xC000,~1);
+  setprg8(0xE000,~0);
+ }
+}
+
+static void DoCHR(void)
+{
+ uint32 base=(cmd&0x80)<<5;
+
+ setchr2(0x0000^base,regs[0]);
+ setchr2(0x0800^base,regs[2]);
+
+ setchr1(0x1000^base,regs[6]);
+ setchr1(0x1400^base,regs[1]);
+ setchr1(0x1800^base,regs[7]);
+ setchr1(0x1c00^base,regs[3]);
+}
+
+static DECLFW(H2288Write)
+{
+ //printf("$%04x:$%02x, $%04x\n",A,V,X.PC.W);
+ //RAM[0x7FB]=0x60;
+ switch(A&0xE001)
+ {
+  case 0xa000:setmirror((V&1)^1);break;
+  case 0x8000://  DumpMem("out",0x0000,0xFFFF);
+             cmd=V;DoPRG();DoCHR();break;
+  case 0x8001:regs[cmd&7]=V;
+             if((cmd&7)==4 || (cmd&7)==5)
+              DoPRG();
+             else
+              DoCHR();
+             break;
+ }
+}
+
+static DECLFR(H2288Read)
+{
+ //printf("Rd: $%04x, $%04x\n",A,X.PC.W);
+ return((X.DB&0xFE)|(A&(A>>8)));
+}
+
+static void H2288Reset(void)
+{
+  int x;
+
+  SetReadHandler(0x5800,0x5FFF,H2288Read);
+  SetReadHandler(0x8000,0xFFFF,CartBR);
+  SetWriteHandler(0x8000,0xFFFF,H2288Write);
+  for(x=0;x<8;x++) regs[x]=0;
+  cmd=0;
+  DoPRG();
+  DoCHR();
+}
+
+void H2288_Init(void)
+{
+  BoardPower=H2288Reset;
+}
diff --git a/boards/malee.c b/boards/malee.c
new file mode 100644 (file)
index 0000000..f575159
--- /dev/null
@@ -0,0 +1,45 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+DECLFW(MWrite)
+{
+ (GameMemBlock-0x7000)[A]=V;
+}
+
+static void MALEEReset(void)
+{
+  setprg2r(0x10,0x7000,0);
+  SetReadHandler(0x8000,0xFFFF,CartBR);
+  SetReadHandler(0x6000,0x67ff,CartBR);
+  SetReadHandler(0x7000,0x77FF,CartBR);
+  SetWriteHandler(0x7000,0x77FF,MWrite);
+  setprg2r(1,0x6000,0);
+  setprg32(0x8000,0);
+  setchr8(0);
+}
+
+void MALEE_Init(void)
+{
+  AddExState(GameMemBlock, 2048, 0,"RAM");
+  SetupCartPRGMapping(0x10,GameMemBlock,2048,1);
+  BoardPower=MALEEReset;
+}
diff --git a/boards/mapinc.h b/boards/mapinc.h
new file mode 100644 (file)
index 0000000..e6d4c41
--- /dev/null
@@ -0,0 +1,11 @@
+#include       "../types.h"
+#include        "../x6502.h"
+#include        "../fce.h"
+#include        "../version.h"
+#include        "../memory.h"
+#include       "../sound.h"
+#include        "../svga.h"
+#include       "../state.h"
+#define UNIFPRIV
+#include        "../unif.h"
+#include       "../cart.h"
diff --git a/boards/novel.c b/boards/novel.c
new file mode 100644 (file)
index 0000000..7d620db
--- /dev/null
@@ -0,0 +1,53 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+static void DoNovel(void)
+{
+ setprg32(0x8000,GameMemBlock[0]&3);
+ setchr8(GameMemBlock[0]&7);
+}
+
+static DECLFW(NovelWrite)
+{
+ GameMemBlock[0]=A&0xFF;
+ DoNovel();
+}
+
+static void NovelReset(void)
+{
+  SetWriteHandler(0x8000,0xFFFF,NovelWrite);
+  SetReadHandler(0x8000,0xFFFF,CartBR);  
+  setprg32(0x8000,0);
+  setchr8(0);
+}
+
+static void NovelRestore(int version)
+{
+ DoNovel();
+}
+
+void Novel_Init(void)
+{
+  AddExState(&GameMemBlock[0], 1, 0,"L1");
+  BoardPower=NovelReset;
+  GameStateRestore=NovelRestore;
+}
diff --git a/boards/sachen.c b/boards/sachen.c
new file mode 100644 (file)
index 0000000..d4d20c2
--- /dev/null
@@ -0,0 +1,289 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+static uint8 cmd;
+static uint8 latch[8];
+#define CHRRAM (GameMemBlock)
+
+static void S74LS374NSynco(void)
+{
+ setprg32(0x8000,latch[0]);
+ setchr8(latch[1]);
+ setmirror(latch[2]&1);
+// setchr8(6);
+}
+
+static DECLFW(S74LS374NWrite)
+{
+ //printf("$%04x:$%02x\n",A,V);
+ A&=0x4101;
+ if(A==0x4100)
+  cmd=V&7;
+ else 
+ {
+  switch(cmd)
+  {
+   case 0:latch[0]=0;latch[1]=3;break;
+   case 4:latch[1]&=3;latch[1]|=(V<<2);break;
+   case 5:latch[0]=V&0x7;break;
+   case 6:latch[1]&=0x1C;latch[1]|=V&3;break;
+   case 7:latch[2]=V&1;break;
+  }
+  S74LS374NSynco();
+ }
+}
+
+static void S74LS374NReset(void)
+{
+ latch[0]=latch[2]=0;
+ latch[1]=3;
+ S74LS374NSynco();
+ SetReadHandler(0x8000,0xFFFF,CartBR);
+ SetWriteHandler(0x4100,0x7FFF,S74LS374NWrite);
+}
+
+static void S74LS374NRestore(int version)
+{
+ S74LS374NSynco();
+}
+
+void S74LS374N_Init(void)
+{
+ BoardPower=S74LS374NReset;
+ GameStateRestore=S74LS374NRestore;
+ AddExState(latch, 3, 0, "LATC");
+ AddExState(&cmd, 1, 0, "CMD");
+}
+
+static int type;
+static void S8259Synco(void)
+{
+ int x;
+
+ setprg32(0x8000,latch[5]&7);
+
+ if(!UNIFchrrama)      // No CHR RAM?  Then BS'ing is ok.
+ {
+  if(!type)
+  {
+   for(x=0;x<4;x++)
+    setchr2(0x800*x,(x&1)|((latch[x]&7)<<1)|((latch[4]&7)<<4));
+  }
+  else
+  {
+   for(x=0;x<4;x++)
+    setchr2(0x800*x,(latch[x]&0x7)|((latch[4]&7)<<3));
+  }
+ }
+ switch((latch[7]>>1)&3)
+ {
+  case 0:setmirrorw(0,0,0,1);break;
+  case 1:setmirror(MI_H);break;
+  case 2:setmirror(MI_V);break;
+  case 3:setmirror(MI_0);break;
+ }
+}
+
+static DECLFW(S8259Write)
+{
+ A&=0x4101;
+ if(A==0x4100) cmd=V;
+ else 
+ {
+  latch[cmd&7]=V;
+  S8259Synco();
+ }
+}
+
+static void S8259Reset(void)
+{
+ int x;
+ cmd=0;
+
+ for(x=0;x<8;x++) latch[x]=0;
+ if(UNIFchrrama) setchr8(0);
+
+ S8259Synco();
+ SetReadHandler(0x8000,0xFFFF,CartBR);
+ SetWriteHandler(0x4100,0x7FFF,S8259Write);
+}
+
+static void S8259Restore(int version)
+{
+ S8259Synco();
+}
+
+void S8259A_Init(void)
+{
+ BoardPower=S8259Reset;
+ GameStateRestore=S8259Restore;
+ AddExState(latch, 8, 0, "LATC");
+ AddExState(&cmd, 1, 0, "CMD");
+ type=0;
+
+ //if(!CHRsize[0])
+ //{
+ // SetupCartCHRMapping(0,CHRRAM,8192,1);
+ // AddExState(CHRRAM, 8192, 0, "CHRR");
+ //}
+}
+
+void S8259B_Init(void)
+{
+ BoardPower=S8259Reset;
+ GameStateRestore=S8259Restore;
+ AddExState(latch, 8, 0, "LATC");
+ AddExState(&cmd, 1, 0, "CMD");
+ type=1;
+}
+
+static void(*WSync)(void);
+
+static void SA0161MSynco()
+{
+ setprg32(0x8000,(latch[0]>>3)&1); 
+ setchr8(latch[0]&7);
+}
+
+static DECLFW(SAWrite)
+{
+ if(A&0x100)
+ {
+  latch[0]=V;
+  WSync();
+ }
+}
+
+static void SAReset(void)
+{
+ latch[0]=0;
+ WSync();
+ SetReadHandler(0x8000,0xFFFF,CartBR);
+ SetWriteHandler(0x4100,0x5FFF,SAWrite);
+}
+
+void SA0161M_Init(void)
+{
+ WSync=SA0161MSynco;
+ GameStateRestore=SA0161MSynco;
+ BoardPower=SAReset;
+ AddExState(&latch[0], 1, 0, "LATC");
+}
+
+static void SA72007Synco()
+{
+ setprg32(0x8000,0);
+ setchr8(latch[0]>>7);
+}
+
+void SA72007_Init(void)
+{
+ WSync=SA72007Synco;
+ GameStateRestore=SA72007Synco;
+ BoardPower=SAReset;
+ AddExState(&latch[0], 1, 0, "LATC");
+}
+
+static void SA72008Synco()
+{
+ setprg32(0x8000,(latch[0]>>2)&1);
+ setchr8(latch[0]&3);
+}
+
+void SA72008_Init(void)
+{
+ WSync=SA72008Synco;
+ GameStateRestore=SA72008Synco;
+ BoardPower=SAReset;
+ AddExState(&latch[0], 1, 0, "LATC");
+}
+
+static DECLFW(SADWrite)
+{
+ latch[0]=V;
+ WSync();
+}
+
+static void SADReset(void)
+{
+ latch[0]=0;
+ WSync();
+ SetReadHandler(0x8000,0xFFFF,CartBR);
+ SetWriteHandler(0x8000,0xFFFF,SADWrite);
+}
+
+static void SA0036Synco()
+{
+ setprg32(0x8000,0);
+ setchr8(latch[0]>>7);
+}
+
+static void SA0037Synco()
+{
+ setprg32(0x8000,(latch[0]>>3)&1);
+ setchr8(latch[0]&7);
+}
+
+void SA0036_Init(void)
+{
+ WSync=SA0036Synco;
+ GameStateRestore=SA0036Synco;
+ BoardPower=SADReset;
+ AddExState(&latch[0], 1, 0, "LATC");
+}
+
+void SA0037_Init(void)
+{
+ WSync=SA0037Synco;
+ GameStateRestore=SA0037Synco;
+ BoardPower=SADReset;
+ AddExState(&latch[0], 1, 0, "LATC");
+}
+
+static void TCU01Synco()
+{
+ setprg32(0x8000,(latch[0]>>2)&1);
+ setchr8((latch[0]>>3)&0xF);
+}
+
+static DECLFW(TCWrite)
+{
+ if((A&0x103)==0x102)
+  latch[0]=V;
+ TCU01Synco();
+}
+
+static void TCU01Reset(void)
+{
+ latch[0]=0;
+ SetReadHandler(0x8000,0xFFFF,CartBR);
+ SetWriteHandler(0x4100,0xFFFF,TCWrite);
+ TCU01Synco();
+}
+
+void TCU01_Init(void)
+{
+ GameStateRestore=TCU01Synco;
+ BoardPower=TCU01Reset;
+ AddExState(&latch[0], 1, 0, "LATC");
+}
+
diff --git a/boards/simple.c b/boards/simple.c
new file mode 100644 (file)
index 0000000..ca4d1db
--- /dev/null
@@ -0,0 +1,162 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define CHRRAM (GameMemBlock)
+static uint8 latche;
+
+DECLFW(CPROMWrite)
+{
+ latche=V&3;
+ setvram4(0x1000,CHRRAM+((V&3)<<12));
+}
+
+static void CPROMReset(void)
+{
+ setprg32(0x8000,0);
+ setvram8(0);
+ SetReadHandler(0x8000,0xFFFF,CartBR);
+ SetWriteHandler(0x8000,0xffff,CPROMWrite);
+}
+
+static void CPROMRestore(int version)
+{
+ setvram4(0x1000,CHRRAM+((latche)<<12));
+}
+
+void CPROM_Init(void)
+{
+ BoardPower=CPROMReset;
+ GameStateRestore=CPROMRestore;
+ AddExState(&latche, 1, 0, "LATC");
+}
+
+DECLFW(CNROMWrite)
+{
+ latche=V&3;
+ setchr8(V&3);
+}
+
+static void CNROMReset(void)
+{
+  setprg16(0x8000,0);
+  setprg16(0xC000,1);
+  SetReadHandler(0x8000,0xFFFF,CartBR);
+  SetWriteHandler(0x8000,0xffff,CNROMWrite);
+}
+
+static void CNROMRestore(int version)
+{
+ setchr8(latche);
+}
+
+void CNROM_Init(void)
+{
+ BoardPower=CNROMReset;
+ GameStateRestore=CNROMRestore;
+ AddExState(&latche, 1, 0, "LATC");
+}
+
+static void NROM128Reset(void)
+{
+  setprg16(0x8000,0);
+  setprg16(0xC000,0);
+  setchr8(0);
+  SetReadHandler(0x8000,0xFFFF,CartBR);
+}
+
+static void NROM256Reset(void)
+{
+  setprg16(0x8000,0);
+  setprg16(0xC000,1);
+  setchr8(0);
+  SetReadHandler(0x8000,0xFFFF,CartBR);
+}
+void NROM128_Init(void)
+{
+  BoardPower=NROM128Reset;
+}
+
+void NROM256_Init(void)
+{
+  BoardPower=NROM256Reset;
+}
+
+static DECLFW(MHROMWrite)
+{
+ setprg32(0x8000,V>>4);
+ setchr8(V);
+ latche=V;
+}
+
+static void MHROMReset(void)
+{
+ setprg32(0x8000,0);
+ setchr8(0);
+ latche=0;
+ SetReadHandler(0x8000,0xFFFF,CartBR);
+}
+
+static void MHROMRestore(int version)
+{
+ setprg32(0x8000,latche);
+ setchr8(latche);
+ SetWriteHandler(0x8000,0xffff,MHROMWrite);
+}
+
+void MHROM_Init(void)
+{ 
+ BoardPower=MHROMReset;
+ AddExState(&latche, 1, 0,"LATC");
+ PRGmask32[0]&=1;
+ CHRmask8[0]&=1;
+ GameStateRestore=MHROMRestore;
+}
+
+static void UNROMRestore(int version)
+{
+ setprg16(0x8000,latche);
+}
+
+static DECLFW(UNROMWrite)
+{
+ setprg16(0x8000,V);
+ latche=V;
+}
+
+static void UNROMReset(void)
+{
+ setprg16(0x8000,0);
+ setprg16(0xc000,~0);
+ setvram8(CHRRAM);
+ SetWriteHandler(0x8000,0xffff,UNROMWrite);
+ SetReadHandler(0x8000,0xFFFF,CartBR);
+ latche=0;
+}
+
+void UNROM_Init(void)
+{
+ BoardPower=UNROMReset;
+ PRGmask16[0]&=7;
+ AddExState(&latche, 1, 0, "LATC");
+ AddExState(CHRRAM, 8192, 0, "CHRR");
+ GameStateRestore=UNROMRestore;
+}
diff --git a/boards/super24.c b/boards/super24.c
new file mode 100644 (file)
index 0000000..64af337
--- /dev/null
@@ -0,0 +1,236 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+//undef printf
+
+static int32 IRQCount,IRQLatch;
+static uint8 IRQa,resetmode,mbia;
+static uint8 sizer,bigbank,bigbank2;
+
+static uint8 DRegBuf[8],MMC3_cmd;
+
+static int masko8[8]={63,31,15,1,3,0,0,0};
+//static int masko1[8]={511,255,127,7,7,0,0,0};
+
+static void swsetprg8(uint32 A, uint32 V)
+{
+ V&=masko8[sizer&7];
+ V|=(bigbank*2);
+ setprg8r((V/64)&15,A,V);
+}
+
+static void swsetchr1(uint32 A, uint32 V)
+{
+ if(sizer&0x20)
+  setchr1r(0x10,A,V);
+ else
+ {
+//  V&=masko1[sizer&7];
+  V|=bigbank2*8;
+  setchr1r((V/512)&15,A,V);
+ }
+}
+
+static void swsetchr2(uint32 A, uint32 V)
+{
+ if(sizer&0x20)
+  setchr2r(0x10,A,V);
+ else
+ {
+  //V&=masko1[sizer&7]>>1;
+  V|=bigbank2*4;  
+  setchr2r((V/256)&15,A,V);
+ }
+}
+
+static void Sup24_hb(void)
+{
+     if(ScreenON || SpriteON)
+     {
+      resetmode=0;
+      if(IRQCount>=0)
+      {
+        IRQCount--;
+        if(IRQCount<0)
+        {
+         if(IRQa)
+         {
+            resetmode = 1;
+           X6502_IRQBegin(FCEU_IQEXT);
+         }
+        }
+      }
+     }
+}
+
+static DECLFW(Sup24IRQWrite)
+{
+        switch(A&0xE001)
+        {
+         case 0xc000:IRQLatch=V;
+                     if(resetmode==1)
+                      IRQCount=IRQLatch;
+                     break;
+         case 0xc001:resetmode=1;
+                     IRQCount=IRQLatch;
+                     break;
+         case 0xE000:IRQa=0;X6502_IRQEnd(FCEU_IQEXT);
+                     if(resetmode==1)
+                      {IRQCount=IRQLatch;}
+                     break;
+         case 0xE001:IRQa=1;
+                     if(resetmode==1)
+                       {IRQCount=IRQLatch;}
+                     break;
+        }
+}
+
+static INLINE void FixMMC3PRG(int V)
+{
+         swsetprg8(0xA000,DRegBuf[7]);
+         swsetprg8(0xE000,~0);
+          if(V&0x40)
+           {
+            swsetprg8(0xC000,DRegBuf[6]);
+            swsetprg8(0x8000,~1);
+           }
+          else
+           {
+            swsetprg8(0x8000,DRegBuf[6]);
+            swsetprg8(0xC000,~1);
+           }
+}
+
+static INLINE void FixMMC3CHR(int V)
+{
+           int cbase=(V&0x80)<<5;
+           swsetchr2((cbase^0x000),DRegBuf[0]>>1);
+           swsetchr2((cbase^0x800),DRegBuf[1]>>1);
+           swsetchr1(cbase^0x1000,DRegBuf[2]);
+           swsetchr1(cbase^0x1400,DRegBuf[3]);
+           swsetchr1(cbase^0x1800,DRegBuf[4]);
+           swsetchr1(cbase^0x1c00,DRegBuf[5]);
+}
+
+static DECLFW(Super24hiwrite)
+{
+       //printf("$%04x:$%02x, %d\n",A,V,scanline);
+        switch(A&0xE001)
+        {
+         case 0x8000:
+          if((V&0x40) != (MMC3_cmd&0x40))
+           FixMMC3PRG(V);
+          if((V&0x80) != (MMC3_cmd&0x80))
+           FixMMC3CHR(V);
+          MMC3_cmd = V;
+          break;
+
+        case 0x8001:
+                {
+                 int cbase=(MMC3_cmd&0x80)<<5;
+                 DRegBuf[MMC3_cmd&0x7]=V;
+                 switch(MMC3_cmd&0x07)
+                 {
+                  case 0: V>>=1;swsetchr2((cbase^0x000),V);break;
+                  case 1: V>>=1;swsetchr2((cbase^0x800),V);break;
+                  case 2: swsetchr1(cbase^0x1000,V); break;
+                  case 3: swsetchr1(cbase^0x1400,V); break;
+                  case 4: swsetchr1(cbase^0x1800,V); break;
+                  case 5: swsetchr1(cbase^0x1C00,V); break;
+                  case 6: if (MMC3_cmd&0x40) swsetprg8(0xC000,V);
+                          else swsetprg8(0x8000,V);
+                          break;
+                  case 7: swsetprg8(0xA000,V);
+                          break;
+                 }
+                }
+                break;
+
+        case 0xA000:
+               mbia=V;
+                setmirror((V&1)^1);
+                break;
+ }
+}
+
+
+DECLFW(Super24Write)
+{
+ //printf("$%04x:$%02x\n",A,V);
+ switch(A)
+ {
+  case 0x5ff0:sizer=V;
+             FixMMC3PRG(MMC3_cmd);
+             FixMMC3CHR(MMC3_cmd);
+             break;
+  case 0x5FF1:
+             bigbank=V;
+             FixMMC3PRG(MMC3_cmd);
+             break;
+  case 0x5FF2:
+             bigbank2=V;
+             FixMMC3CHR(MMC3_cmd);
+             break;
+ }
+}
+
+static void Super24Reset(void)
+{
+ SetWriteHandler(0x8000,0xBFFF,Super24hiwrite);
+ SetWriteHandler(0x5000,0x7FFF,Super24Write);
+ SetWriteHandler(0xC000,0xFFFF,Sup24IRQWrite);
+ SetReadHandler(0x8000,0xFFFF,CartBR);
+ GameHBIRQHook=Sup24_hb;
+ IRQCount=IRQLatch=IRQa=resetmode=0;
+ sizer=0x24;
+ bigbank=159;
+ bigbank2=0;
+
+ MMC3_cmd=0;
+ DRegBuf[6]=0;
+ DRegBuf[7]=1;
+
+ FixMMC3PRG(0);
+ FixMMC3CHR(0);
+}
+
+static void MrRestore(int version)
+{
+ FixMMC3PRG(MMC3_cmd);
+ FixMMC3CHR(MMC3_cmd);
+ setmirror((mbia&1)^1);
+}
+
+void Super24_Init(void)
+{
+ BoardPower=Super24Reset;
+ SetupCartCHRMapping(0x10, GameMemBlock, 8192, 1);
+ GameStateRestore=MrRestore;
+
+ AddExState(GameMemBlock, 8192, 0, "CHRR");
+ AddExState(DRegBuf, 8, 0, "DREG");
+ AddExState(&IRQCount, 4, 1, "IRQC");
+ AddExState(&IRQLatch, 4, 1, "IQL1");
+ AddExState(&IRQa, 1, 0, "IRQA");
+ AddExState(&sizer, 1, 0, "SIZA");
+ AddExState(&bigbank, 1, 0, "BIG1");
+ AddExState(&bigbank2, 1, 0, "BIG2");
+}
diff --git a/boards/supervision.c b/boards/supervision.c
new file mode 100644 (file)
index 0000000..fc22599
--- /dev/null
@@ -0,0 +1,76 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define CHRRAM (GameMemBlock+16)
+
+static void DoSuper(void)
+{
+ setprg8r((GameMemBlock[0]&0xC)>>2,0x6000,((GameMemBlock[0]&0x3)<<4)|0xF);
+ if(GameMemBlock[0]&0x10)
+ {
+  setprg16r((GameMemBlock[0]&0xC)>>2,0x8000,((GameMemBlock[0]&0x3)<<3)|(GameMemBlock[1]&7));
+  setprg16r((GameMemBlock[0]&0xC)>>2,0xc000,((GameMemBlock[0]&0x3)<<3)|7);
+ }
+ else
+  setprg32r(4,0x8000,0);
+
+ setmirror(((GameMemBlock[0]&0x20)>>5)^1);
+}
+
+static DECLFW(SuperWrite)
+{
+ if(!(GameMemBlock[0]&0x10))
+ {
+  GameMemBlock[0]=V;
+  DoSuper();
+ }
+}
+
+static DECLFW(SuperHi)
+{
+ GameMemBlock[1]=V; 
+ DoSuper();
+}
+
+static void SuperReset(void)
+{
+  SetWriteHandler(0x6000,0x7FFF,SuperWrite);
+  SetWriteHandler(0x8000,0xFFFF,SuperHi);
+  SetReadHandler(0x6000,0xFFFF,CartBR);  
+  GameMemBlock[0]=GameMemBlock[1]=0;
+  setprg32r(4,0x8000,0);
+  setvram8(CHRRAM);
+}
+
+static void SuperRestore(int version)
+{
+ DoSuper();
+}
+
+void Supervision16_Init(void)
+{
+  AddExState(&GameMemBlock[0], 1, 0,"L1");
+  AddExState(&GameMemBlock[1], 1, 0,"L2");
+  AddExState(CHRRAM, 8192, 0, "CHRR");
+  BoardPower=SuperReset;
+  GameStateRestore=SuperRestore;
+}
diff --git a/cart.c b/cart.c
new file mode 100644 (file)
index 0000000..030e764
--- /dev/null
+++ b/cart.c
@@ -0,0 +1,590 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>     /* For GG loading code. */
+
+#include "types.h"
+#include "version.h"
+#include "fce.h"
+#include "cart.h"
+#include "memory.h"
+
+#include "general.h"
+#include "svga.h"
+
+/* 
+   This file contains all code for coordinating the mapping in of the
+   address space external to the NES.
+   It's also (ab)used by the NSF code.
+*/
+
+uint8 *Page[32],*VPage[8];
+uint8 **VPageR=VPage;
+uint8 *VPageG[8];
+uint8 *MMC5SPRVPage[8];
+uint8 *MMC5BGVPage[8];
+
+/* 16 are (sort of) reserved for UNIF/iNES and 16 to map other stuff. */
+
+static int CHRram[32];
+static int PRGram[32];
+
+uint8 *PRGptr[32];
+uint8 *CHRptr[32];
+
+uint32 PRGsize[32];
+uint32 CHRsize[32];
+
+uint32 PRGmask2[32];
+uint32 PRGmask4[32];
+uint32 PRGmask8[32];
+uint32 PRGmask16[32];
+uint32 PRGmask32[32];
+
+uint32 CHRmask1[32];
+uint32 CHRmask2[32];
+uint32 CHRmask4[32];
+uint32 CHRmask8[32];
+
+int geniestage=0;
+
+int modcon;
+
+uint8 genieval[3];
+uint8 geniech[3];
+
+uint32 genieaddr[3];
+
+static INLINE void setpageptr(int s, uint32 A, uint8 *p)
+{
+ uint32 AB=A>>11;
+ int x;
+
+ for(x=(s>>1)-1;x>=0;x--)
+  Page[AB+x]=p-A;
+}
+
+static char nothing[8192];
+void ResetCartMapping(void)
+{
+ int x;
+
+ for(x=0;x<32;x++)
+ {
+  Page[x]=nothing-x*2048;
+  PRGptr[x]=CHRptr[x]=0;
+  PRGsize[x]=CHRsize[x]=0;
+ }
+ for(x=0;x<8;x++)
+ {
+  MMC5SPRVPage[x]=MMC5BGVPage[x]=VPageR[x]=nothing-0x400*x;
+ }
+
+}
+
+void SetupCartPRGMapping(int chip, uint8 *p, uint32 size, int ram)
+{
+ PRGptr[chip]=p;
+ PRGsize[chip]=size;
+
+ PRGmask2[chip]=(size>>11)-1;
+ PRGmask4[chip]=(size>>12)-1;
+ PRGmask8[chip]=(size>>13)-1;
+ PRGmask16[chip]=(size>>14)-1;
+ PRGmask32[chip]=(size>>15)-1; 
+
+ PRGram[chip]=ram?1:0;
+}
+
+void SetupCartCHRMapping(int chip, uint8 *p, uint32 size, int ram)
+{
+ CHRptr[chip]=p;
+ CHRsize[chip]=size;
+
+ CHRmask1[chip]=(size>>10)-1;
+ CHRmask2[chip]=(size>>11)-1;
+ CHRmask4[chip]=(size>>12)-1;
+ CHRmask8[chip]=(size>>13)-1;
+
+ CHRram[chip]=ram;
+}
+
+DECLFR(CartBR)
+{
+ return Page[A>>11][A];
+}
+
+void FASTAPASS(3) GINLINE setprg2r(int r, unsigned int A, unsigned int V)
+{
+  if(!PRGptr[r]) return;
+  V&=PRGmask2[r];
+
+  setpageptr(2,A,(&PRGptr[r][V<<11]));
+}
+
+void FASTAPASS(2) setprg2(uint32 A, uint32 V)
+{
+ setprg2r(0,A,V);
+}
+
+void FASTAPASS(3) GINLINE setprg4r(int r, unsigned int A, unsigned int V)
+{
+  if(!PRGptr[r]) return;
+  V&=PRGmask4[r];
+  setpageptr(4,A,(&PRGptr[r][V<<12]));
+}
+
+void FASTAPASS(2) setprg4(uint32 A, uint32 V)
+{
+ setprg4r(0,A,V);
+}
+
+void FASTAPASS(3) GINLINE setprg8r(int r, unsigned int A, unsigned int V)
+{
+  if(!PRGptr[r]) return;
+
+  if(PRGsize[r]>=8192)
+  {
+   V&=PRGmask8[r];
+   setpageptr(8,A,(&PRGptr[r][V<<13]));
+  }
+  else
+  {
+   uint32 VA=V<<2;
+   int x;
+   for(x=0;x<4;x++)
+    setpageptr(2,A+(x<<11),(&PRGptr[r][((VA+x)&PRGmask2[r])<<11]));
+  }
+}
+
+void FASTAPASS(2) setprg8(uint32 A, uint32 V)
+{
+ setprg8r(0,A,V);
+}
+
+void FASTAPASS(3) GINLINE setprg16r(int r, unsigned int A, unsigned int V)
+{
+  if(!PRGptr[r]) return;
+
+  if(PRGsize[r]>=16384)
+  {
+   V&=PRGmask16[r];
+   setpageptr(16,A,(&PRGptr[r][V<<14]));
+  }
+  else
+  {
+   uint32 VA=V<<3;
+   int x;
+
+   for(x=0;x<8;x++)
+    setpageptr(2,A+(x<<11),(&PRGptr[r][((VA+x)&PRGmask2[r])<<11]));
+  }
+}
+
+void FASTAPASS(2) setprg16(uint32 A, uint32 V)
+{
+ setprg16r(0,A,V);
+}
+
+void FASTAPASS(3) GINLINE setprg32r(int r,unsigned int A, unsigned int V)
+{
+  if(!PRGptr[r]) return;
+  if(PRGsize[r]>=32768)
+  {
+   V&=PRGmask32[r];
+   setpageptr(32,A,(&PRGptr[r][V<<15]));
+  }
+  else
+  {
+   uint32 VA=V<<4;
+   int x;
+
+   for(x=0;x<16;x++)
+    setpageptr(2,A+(x<<11),(&PRGptr[r][((VA+x)&PRGmask2[r])<<11]));
+  }
+}
+
+void FASTAPASS(2) setprg32(uint32 A, uint32 V)
+{
+ setprg32r(0,A,V);
+}
+
+void GINLINE FASTAPASS(3) setchr1r(int r, unsigned int A, unsigned int V)
+{
+  if(!CHRptr[r]) return;
+  V&=CHRmask1[r];
+  if(CHRram[r])
+   PPUCHRRAM|=(1<<(A>>10));
+  else
+   PPUCHRRAM&=~(1<<(A>>10));
+  VPageR[(A)>>10]=&CHRptr[r][(V)<<10]-(A);
+}
+
+void GINLINE FASTAPASS(3) setchr2r(int r, unsigned int A, unsigned int V)
+{
+  if(!CHRptr[r]) return;
+  V&=CHRmask2[r];
+  VPageR[(A)>>10]=VPageR[((A)>>10)+1]=&CHRptr[r][(V)<<11]-(A);
+  if(CHRram[r])
+   PPUCHRRAM|=(3<<(A>>10));
+  else
+   PPUCHRRAM&=~(3<<(A>>10));
+}
+
+void GINLINE FASTAPASS(3) setchr4r(int r, unsigned int A, unsigned int V)
+{
+  if(!CHRptr[r]) return;
+  V&=CHRmask4[r];
+  VPageR[(A)>>10]=VPageR[((A)>>10)+1]=
+  VPageR[((A)>>10)+2]=VPageR[((A)>>10)+3]=&CHRptr[r][(V)<<12]-(A);
+  if(CHRram[r])
+   PPUCHRRAM|=(15<<(A>>10));
+  else
+   PPUCHRRAM&=~(15<<(A>>10));
+}
+
+void GINLINE FASTAPASS(2) setchr8r(int r, unsigned int V)
+{
+  int x;
+
+  if(!CHRptr[r]) return;
+  V&=CHRmask8[r];
+  for(x=7;x>=0;x--)
+   VPageR[x]=&CHRptr[r][V<<13];
+  if(CHRram[r])
+   PPUCHRRAM|=(255);
+  else
+   PPUCHRRAM&=~(255);
+}
+
+void FASTAPASS(2) setchr1(unsigned int A, unsigned int V)
+{
+ setchr1r(0,A,V);
+}
+
+void FASTAPASS(2) setchr2(unsigned int A, unsigned int V)
+{
+ setchr2r(0,A,V);
+}
+
+void FASTAPASS(2) setchr4(unsigned int A, unsigned int V)
+{
+ setchr4r(0,A,V);
+}
+
+void FASTAPASS(1) setchr8(unsigned int V)
+{
+ setchr8r(0,V);
+}
+
+void FASTAPASS(1) setvram8(uint8 *p)
+{
+  int x;
+  for(x=7;x>=0;x--)
+   VPageR[x]=p;
+  PPUCHRRAM|=255;
+}
+
+void FASTAPASS(2) setvram4(uint32 A, uint8 *p)
+{
+  int x;
+  for(x=3;x>=0;x--)
+   VPageR[(A>>10)+x]=p-A;
+  PPUCHRRAM|=(15<<(A>>10));
+}
+
+void FASTAPASS(3) setvramb1(uint8 *p, uint32 A, uint32 b)
+{
+  VPageR[A>>10]=p-A+(b<<10);
+  PPUCHRRAM|=(1<<(A>>10));
+}
+
+void FASTAPASS(3) setvramb2(uint8 *p, uint32 A, uint32 b)
+{
+  VPageR[(A>>10)]=VPageR[(A>>10)+1]=p-A+(b<<11);
+  PPUCHRRAM|=(3<<(A>>10));
+}
+
+void FASTAPASS(3) setvramb4(uint8 *p, uint32 A, uint32 b)
+{
+  int x;
+
+  for(x=3;x>=0;x--)
+   VPageR[(A>>10)+x]=p-A+(b<<12);
+  PPUCHRRAM|=(15<<(A>>10));
+}
+
+void FASTAPASS(2) setvramb8(uint8 *p, uint32 b)
+{
+  int x;
+
+  for(x=7;x>=0;x--)
+   VPageR[x]=p+(b<<13);
+  PPUCHRRAM|=255;
+}
+
+/* This function can be called without calling SetupCartMirroring(). */
+
+void FASTAPASS(3) setntamem(uint8 *p, int ram, uint32 b)
+{
+ vnapage[b]=p;
+ PPUNTARAM&=~(1<<b);
+ if(ram)
+  PPUNTARAM|=1<<b;
+}
+
+static int mirrorhard=0;
+void setmirrorw(int a, int b, int c, int d)
+{
+ vnapage[0]=NTARAM+a*0x400;
+ vnapage[1]=NTARAM+b*0x400;
+ vnapage[2]=NTARAM+c*0x400;
+ vnapage[3]=NTARAM+d*0x400;
+}
+
+void FASTAPASS(1) setmirror(int t)
+{
+  if(!mirrorhard)
+  {
+   switch(t)
+   {
+    case MI_H:
+     vnapage[0]=vnapage[1]=NTARAM;vnapage[2]=vnapage[3]=NTARAM+0x400;
+     break;
+    case MI_V:
+     vnapage[0]=vnapage[2]=NTARAM;vnapage[1]=vnapage[3]=NTARAM+0x400;
+     break;
+    case MI_0:
+     vnapage[0]=vnapage[1]=vnapage[2]=vnapage[3]=NTARAM;
+     break;
+    case MI_1:
+     vnapage[0]=vnapage[1]=vnapage[2]=vnapage[3]=NTARAM+0x400;
+     break;
+   }
+  PPUNTARAM=0xF;
+ }
+}
+
+void SetupCartMirroring(int m, int hard, uint8 *extra)
+{
+ if(m<4)
+  setmirror(m);
+ else
+ {
+  vnapage[0]=NTARAM;
+  vnapage[1]=NTARAM+0x400;
+  vnapage[2]=extra;
+  vnapage[3]=extra+0x400;
+  PPUNTARAM=0xF;
+ }
+ mirrorhard=hard;
+}
+
+static uint8 *GENIEROM=0;
+
+void FixGenieMap(void);
+
+/* Called when a game(file) is opened successfully. */
+void OpenGenie(void)
+{
+ FILE *fp;
+ int x;
+
+ if(!GENIEROM)
+ {
+  if(!(GENIEROM=FCEU_malloc(4096+1024))) return;
+
+  if(!(fp=fopen(FCEU_MakeFName(FCEUMKF_GGROM,0,0),"rb")))
+  {
+   FCEU_PrintError("Error opening Game Genie ROM image!");
+   free(GENIEROM);
+   GENIEROM=0;
+   return;
+  }
+  if(fread(GENIEROM,1,16,fp)!=16)
+  {
+   grerr:
+   FCEU_PrintError("Error reading from Game Genie ROM image!");
+   free(GENIEROM);
+   GENIEROM=0;
+   fclose(fp);
+   return;
+  }
+  if(GENIEROM[0]==0x4E)        /* iNES ROM image */
+  {
+   if(fread(GENIEROM,1,4096,fp)!=4096)
+    goto grerr;
+   if(fseek(fp,16384-4096,SEEK_CUR))
+    goto grerr;
+   if(fread(GENIEROM+4096,1,256,fp)!=256)
+    goto grerr;
+  }
+  else
+  {
+   if(fread(GENIEROM+16,1,4352-16,fp)!=(4352-16))
+    goto grerr;
+  }
+  fclose(fp);
+  /* Workaround for the FCE Ultra CHR page size only being 1KB */
+  for(x=0;x<4;x++)
+   memcpy(GENIEROM+4096+(x<<8),GENIEROM+4096,256);
+ }
+
+ geniestage=1;
+}
+
+/* Called when a game is closed. */
+void CloseGenie(void)
+{
+ /* No good reason to free() the Game Genie ROM image data. */
+ geniestage=0;
+ FlushGenieRW();
+ VPageR=VPage;
+}
+
+static DECLFR(GenieRead)
+{
+ return GENIEROM[A&4095];
+}
+
+static DECLFW(GenieWrite)
+{
+ switch(A)
+ {
+  case 0x800c:
+  case 0x8008:
+  case 0x8004:genieval[((A-4)&0xF)>>2]=V;break;
+
+  case 0x800b:
+  case 0x8007:
+  case 0x8003:geniech[((A-3)&0xF)>>2]=V;break;
+
+  case 0x800a:
+  case 0x8006:
+  case 0x8002:genieaddr[((A-2)&0xF)>>2]&=0xFF00;genieaddr[((A-2)&0xF)>>2]|=V;break;
+
+  case 0x8009:
+  case 0x8005:
+  case 0x8001:genieaddr[((A-1)&0xF)>>2]&=0xFF;genieaddr[((A-1)&0xF)>>2]|=(V|0x80)<<8;break;
+
+  case 0x8000:if(!V)
+               FixGenieMap();
+              else
+              {
+               modcon=V^0xFF;
+               if(V==0x71) 
+               modcon=0;
+              }
+              break;
+ }
+}
+
+static readfunc GenieBackup[3];
+
+static DECLFR(GenieFix1)
+{
+ uint8 r=GenieBackup[0](A);
+
+ if((modcon>>1)&1)             // No check
+  return genieval[0];
+ else if(r==geniech[0])
+  return genieval[0];
+
+ return r;
+}
+
+static DECLFR(GenieFix2)
+{
+ uint8 r=GenieBackup[1](A);
+
+ if((modcon>>2)&1)              // No check
+  return genieval[1];
+ else if(r==geniech[1])
+  return genieval[1];
+
+ return r;
+}
+
+static DECLFR(GenieFix3)
+{
+ uint8 r=GenieBackup[2](A);
+
+ if((modcon>>3)&1)              // No check
+  return genieval[2];
+ else if(r==geniech[2])
+  return genieval[2];
+
+ return r;
+}
+
+
+void FixGenieMap(void)
+{
+ int x;
+
+ geniestage=2;
+
+ for(x=0;x<8;x++)
+  VPage[x]=VPageG[x];
+
+ VPageR=VPage;
+ FlushGenieRW();
+ for(x=0;x<3;x++)
+  if((modcon>>(4+x))&1)
+  {
+   readfunc tmp[3]={GenieFix1,GenieFix2,GenieFix3};
+   GenieBackup[x]=GetReadHandler(genieaddr[x]);
+   SetReadHandler(genieaddr[x],genieaddr[x],tmp[x]);
+  }
+}
+
+void GeniePower(void)
+{
+ uint32 x;
+
+ if(!geniestage)
+  return;
+
+ geniestage=1;
+ for(x=0;x<3;x++)
+ {
+  genieval[x]=0xFF;
+  geniech[x]=0xFF;
+  genieaddr[x]=0xFFFF;
+ }
+ modcon=0;
+
+ SetWriteHandler(0x8000,0xFFFF,GenieWrite);
+ SetReadHandler(0x8000,0xFFFF,GenieRead);
+
+ for(x=0;x<8;x++)
+  VPage[x]=GENIEROM+4096-0x400*x;
+
+ if(AllocGenieRW())
+  VPageR=VPageG;
+ else
+  geniestage=2;
+}
+
+
diff --git a/cart.h b/cart.h
new file mode 100644 (file)
index 0000000..b066771
--- /dev/null
+++ b/cart.h
@@ -0,0 +1,70 @@
+extern uint8 *Page[32],*VPage[8],*MMC5SPRVPage[8],*MMC5BGVPage[8];
+
+void ResetCartMapping(void);
+void SetupCartPRGMapping(int chip, uint8 *p, uint32 size, int ram);
+void SetupCartCHRMapping(int chip, uint8 *p, uint32 size, int ram);
+void SetupCartMirroring(int m, int hard, uint8 *extra);
+
+DECLFR(CartBR);
+extern uint8 *PRGptr[32];
+extern uint8 *CHRptr[32];
+
+extern uint32 PRGsize[32];
+extern uint32 CHRsize[32];
+
+extern uint32 PRGmask2[32];
+extern uint32 PRGmask4[32];
+extern uint32 PRGmask8[32];
+extern uint32 PRGmask16[32];
+extern uint32 PRGmask32[32];
+
+extern uint32 CHRmask1[32];
+extern uint32 CHRmask2[32];
+extern uint32 CHRmask4[32];
+extern uint32 CHRmask8[32];
+
+void FASTAPASS(2) setprg2(uint32 A, uint32 V);
+void FASTAPASS(2) setprg4(uint32 A, uint32 V);
+void FASTAPASS(2) setprg8(uint32 A, uint32 V);
+void FASTAPASS(2) setprg16(uint32 A, uint32 V);
+void FASTAPASS(2) setprg32(uint32 A, uint32 V);
+
+void FASTAPASS(3) setprg2r(int r, unsigned int A, unsigned int V);
+void FASTAPASS(3) setprg4r(int r, unsigned int A, unsigned int V);
+void FASTAPASS(3) setprg8r(int r, unsigned int A, unsigned int V);
+void FASTAPASS(3) setprg16r(int r, unsigned int A, unsigned int V);
+void FASTAPASS(3) setprg32r(int r, unsigned int A, unsigned int V);
+
+void FASTAPASS(3) setchr1r(int r, unsigned int A, unsigned int V);
+void FASTAPASS(3) setchr2r(int r, unsigned int A, unsigned int V);
+void FASTAPASS(3) setchr4r(int r, unsigned int A, unsigned int V);
+void FASTAPASS(2) setchr8r(int r, unsigned int V);
+
+void FASTAPASS(2) setchr1(unsigned int A, unsigned int V);
+void FASTAPASS(2) setchr2(unsigned int A, unsigned int V);
+void FASTAPASS(2) setchr4(unsigned int A, unsigned int V);
+void FASTAPASS(2) setchr8(unsigned int V);
+
+void FASTAPASS(2) setvram4(uint32 A, uint8 *p);
+void FASTAPASS(1) setvram8(uint8 *p);
+
+void FASTAPASS(3) setvramb1(uint8 *p, uint32 A, uint32 b);
+void FASTAPASS(3) setvramb2(uint8 *p, uint32 A, uint32 b);
+void FASTAPASS(3) setvramb4(uint8 *p, uint32 A, uint32 b);
+void FASTAPASS(2) setvramb8(uint8 *p, uint32 b);
+
+void FASTAPASS(1) setmirror(int t);
+void setmirrorw(int a, int b, int c, int d);
+void FASTAPASS(3) setntamem(uint8 *p, int ram, uint32 b);
+
+#define MI_H 0
+#define MI_V 1
+#define MI_0 2
+#define MI_1 3
+
+extern int geniestage;
+
+void GeniePower(void);
+
+void OpenGenie(void);
+void CloseGenie(void);
diff --git a/cheat.c b/cheat.c
new file mode 100644 (file)
index 0000000..d789d74
--- /dev/null
+++ b/cheat.c
@@ -0,0 +1,565 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "types.h"
+#include "x6502.h"
+#include "cheat.h"
+#include "fce.h"
+#include "svga.h"
+#include "general.h"
+#include "cart.h"
+#include "memory.h"
+
+static uint8 *CheatRPtrs[64];
+
+void FCEU_CheatResetRAM(void)
+{
+ int x;
+
+ for(x=0;x<64;x++) 
+  CheatRPtrs[x]=0;
+}
+
+void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p)
+{
+ uint32 AB=A>>10;
+ int x;
+
+ for(x=s-1;x>=0;x--)
+  CheatRPtrs[AB+x]=p-A;
+}
+
+
+struct CHEATF {
+           struct CHEATF *next;
+           char *name;
+           uint16 addr;
+           uint8 val;
+          int status;
+};
+
+struct CHEATF *cheats=0,*cheatsl=0;
+
+
+#define CHEATC_NONE     0x8000
+#define CHEATC_EXCLUDED 0x4000
+#define CHEATC_NOSHOW   0xC000
+
+static uint16 *CheatComp=0;
+static int savecheats;
+
+static int AddCheatEntry(char *name, uint32 addr, uint8 val, int status);
+
+static void CheatMemErr(void)
+{
+ FCEUD_PrintError("Error allocating memory for cheat data.");
+}
+
+/* This function doesn't allocate any memory for "name" */
+static int AddCheatEntry(char *name, uint32 addr, uint8 val, int status)
+{
+ struct CHEATF *temp;
+ if(!(temp=malloc(sizeof(struct CHEATF))))
+ {
+  CheatMemErr();
+  return(0);
+ }
+ temp->name=name;
+ temp->addr=addr;
+ temp->val=val;
+ temp->status=status;
+
+ temp->next=0;
+
+ if(cheats)
+ {
+  cheatsl->next=temp;
+  cheatsl=temp;
+ }
+ else
+  cheats=cheatsl=temp;
+
+ return(1);
+}
+
+void LoadGameCheats(void)
+{
+ FILE *fp;
+ char *name=0;
+ unsigned int addr;
+ unsigned int val;
+ unsigned int status;
+ int x;
+
+ char linebuf[256+4+2+2+1+1]; /* 256 for name, 4 for address, 2 for value, 2 for semicolons, 1 for status, 1 for null */
+ char namebuf[257];
+ int tc=0;
+
+ savecheats=0;
+ if(!(fp=fopen(FCEU_MakeFName(FCEUMKF_CHEAT,0,0),"rb")))
+  return;
+ while(fgets(linebuf,256+4+2+2+1+1,fp)>0)
+ { 
+  addr=val=status=0;
+  namebuf[0]=0; // If the cheat doesn't have a name...
+  if(linebuf[0]==':')  
+  {
+   strncpy(namebuf,&linebuf[1+4+2+2],257);
+   if(sscanf(&linebuf[1],"%04x%*[:]%02x",&addr,&val)!=2)
+    continue;
+   status=0;
+  }
+  else
+  {
+   strncpy(namebuf,&linebuf[4+2+2],257);
+   if(sscanf(linebuf,"%04x%*[:]%02x",&addr,&val)!=2) continue;
+   status=1;
+  }
+  for(x=0;x<257;x++)
+  {
+   if(namebuf[x]==10 || namebuf[x]==13)
+   {
+    namebuf[x]=0;
+    break;
+   }
+  }
+  namebuf[256]=0;
+  if(!(name=malloc(strlen(namebuf)+1)))
+   CheatMemErr();
+  else
+  {
+   strcpy(name,namebuf);
+   AddCheatEntry(name,addr,val,status);
+   tc++;
+  }
+ }
+ fclose(fp);
+}
+
+
+void FlushGameCheats(void)
+{
+ if(CheatComp)
+ {
+  free(CheatComp);
+  CheatComp=0;
+ }
+
+ if(!savecheats)
+ {
+  if(cheats)
+  {
+   struct CHEATF *next=cheats;
+   for(;;)
+   {  
+    next=next->next;
+    free(cheats->name);
+    free(cheats);
+    if(!next) break;
+   }
+   cheats=cheatsl=0;
+  }
+ }
+ else
+ {
+  if(cheats)
+  {
+   struct CHEATF *next=cheats;
+   FILE *fp;
+   if((fp=fopen(FCEU_MakeFName(FCEUMKF_CHEAT,0,0),"wb")))
+   {
+    for(;;)
+    {
+     struct CHEATF *t;
+     if(next->status)
+      fprintf(fp,"%04x:%02x:%s\n",next->addr,next->val,next->name);
+     else
+      fprintf(fp,":%04x:%02x:%s\n",next->addr,next->val,next->name);
+     free(next->name);
+     t=next;
+     next=next->next;
+     free(t);
+     if(!next) break;
+    }
+    fclose(fp);
+   }
+   else
+    FCEUD_PrintError("Error saving cheats.");
+   cheats=cheatsl=0;
+  }
+  else
+   remove(FCEU_MakeFName(FCEUMKF_CHEAT,0,0));
+ }
+}
+
+
+int FCEUI_AddCheat(char *name, uint32 addr, uint8 val)
+{
+ char *t;
+
+ if(!(t=malloc(strlen(name)+1)))
+ {
+  CheatMemErr();
+  return(0);
+ }
+ strcpy(t,name);
+ if(!AddCheatEntry(t,addr,val,1))
+ {
+  free(t);
+  return(0);
+ }
+ savecheats=1;
+ return(1);
+}
+
+int FCEUI_DelCheat(uint32 which)
+{
+ struct CHEATF *prev;
+ struct CHEATF *cur;
+ uint32 x=0;
+
+ for(prev=0,cur=cheats;;)
+ {
+  if(x==which)          // Remove this cheat.
+  {
+   if(prev)             // Update pointer to this cheat.
+   {
+    if(cur->next)       // More cheats.
+     prev->next=cur->next;
+    else                // No more.
+    {
+     prev->next=0;
+     cheatsl=prev;      // Set the previous cheat as the last cheat.
+    }
+   }
+   else                 // This is the first cheat.
+   {
+    if(cur->next)       // More cheats
+     cheats=cur->next;
+    else
+     cheats=cheatsl=0;  // No (more) cheats.
+   }
+   free(cur->name);     // Now that all references to this cheat are removed,
+   free(cur);           // free the memory.   
+   break;
+  }                     // *END REMOVE THIS CHEAT*
+
+
+  if(!cur->next)        // No more cheats to go through(this shouldn't ever happen...)
+   return(0);
+  prev=cur;
+  cur=prev->next;
+  x++;
+ }
+
+ savecheats=1;
+ return(1);
+}
+
+void ApplyPeriodicCheats(void)
+{
+ struct CHEATF *cur=cheats;
+ if(!cur) return;
+
+ for(;;)
+ {
+  if(cur->status)
+   if(CheatRPtrs[cur->addr>>10])
+    CheatRPtrs[cur->addr>>10][cur->addr]=cur->val;
+  if(cur->next)
+   cur=cur->next;
+  else
+   break;
+ }
+}
+
+
+void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int s))
+{
+  struct CHEATF *next=cheats;
+
+  while(next)
+  {
+   if(!callb(next->name,next->addr,next->val,next->status)) break;
+   next=next->next;
+  }
+}
+
+int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *s)
+{
+ struct CHEATF *next=cheats;
+ uint32 x=0;
+
+ while(next)
+ {
+  if(x==which)
+  {
+   if(name)
+    *name=next->name;
+   if(a)
+    *a=next->addr; 
+   if(v)
+    *v=next->val;
+   if(s)
+    *s=next->status;
+
+   return(1);
+  }
+  next=next->next;
+  x++;
+ }
+ return(0);
+}
+
+/* name can be NULL if the name isn't going to be changed. */
+/* same goes for a, v, and s(except the values of each one must be <0) */
+
+int FCEUI_SetCheat(uint32 which, char *name, int32 a, int32 v, int s)
+{
+ struct CHEATF *next=cheats;
+ uint32 x=0;
+
+ while(next)
+ {
+  if(x==which)
+  {
+   if(name)
+   {
+    char *t;
+
+    if((t=realloc(next->name,strlen(name+1))))
+    {
+     next->name=t;
+     strcpy(next->name,name);
+    }
+    else
+     return(0);
+   }
+   if(a>=0)
+    next->addr=a;
+   if(v>=0)
+    next->val=v;
+   if(s>=0)
+    next->status=s;
+   savecheats=1;
+   return(1);
+  }
+  next=next->next;
+  x++;
+ }
+ return(0);
+}
+
+
+static int InitCheatComp(void)
+{
+ uint32 x;
+
+ CheatComp=malloc(65536*sizeof(uint16));
+ if(!CheatComp)
+ {
+  CheatMemErr();
+  return(0);
+ }
+ for(x=0;x<65536;x++)
+  CheatComp[x]=CHEATC_NONE;
+ return(1);
+}
+
+void FCEUI_CheatSearchSetCurrentAsOriginal(void)
+{
+ uint32 x;
+ for(x=0x000;x<0x10000;x++)
+  if(!(CheatComp[x]&CHEATC_NOSHOW))
+  {
+   if(CheatRPtrs[x>>10])
+    CheatComp[x]=CheatRPtrs[x>>10][x];
+   else
+    CheatComp[x]|=CHEATC_NONE;
+  }
+}
+
+void FCEUI_CheatSearchShowExcluded(void)
+{
+ uint32 x;
+
+ for(x=0x000;x<0x10000;x++)
+  CheatComp[x]&=~CHEATC_EXCLUDED;
+}
+
+
+int32 FCEUI_CheatSearchGetCount(void)
+{
+ uint32 x,c=0;
+
+ if(CheatComp)
+ {
+  for(x=0x0000;x<0x10000;x++)
+   if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10])
+    c++;
+ }
+
+ return c;
+}
+/* This function will give the initial value of the search and the current value at a location. */
+
+void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current))
+{
+  uint32 x;
+
+  if(!CheatComp)
+  {
+   if(!InitCheatComp())
+    CheatMemErr();
+   return;
+  }
+
+  for(x=0;x<0x10000;x++)
+   if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10])
+    if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x]))
+     break;
+}
+
+void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current))
+{
+  uint32 x;
+  uint32 in=0;
+
+  if(!CheatComp)
+  {
+   if(!InitCheatComp())
+    CheatMemErr();
+   return;
+  }
+
+  for(x=0;x<0x10000;x++)
+   if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10])
+   {
+    if(in>=first)
+     if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x]))
+      break;
+    in++;
+    if(in>last) return;
+   }
+}
+
+void FCEUI_CheatSearchBegin(void)
+{
+ uint32 x;
+
+ if(!CheatComp)
+ {
+  if(!InitCheatComp())
+  {
+   CheatMemErr();
+   return;
+  }
+ }
+ for(x=0;x<0x10000;x++)
+ {
+  if(CheatRPtrs[x>>10])
+   CheatComp[x]=CheatRPtrs[x>>10][x];
+  else
+   CheatComp[x]=CHEATC_NONE;
+ }
+}
+
+
+static int INLINE CAbs(int x)
+{
+ if(x<0)
+  return(0-x);
+ return x;
+}
+
+void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2)
+{
+ uint32 x;
+
+ if(!CheatComp)
+ {
+  if(!InitCheatComp())
+  {
+   CheatMemErr();
+   return;
+  }
+ }
+
+
+ if(!type)      // Change to a specific value.
+ {
+  for(x=0;x<0x10000;x++)
+   if(!(CheatComp[x]&CHEATC_NOSHOW))
+   {
+    if(CheatComp[x]==v1 && CheatRPtrs[x>>10][x]==v2)
+    {
+
+    }
+    else
+     CheatComp[x]|=CHEATC_EXCLUDED;
+   }
+ }
+ else if(type==1)           // Search for relative change(between values).
+ {
+  for(x=0;x<0x10000;x++)
+   if(!(CheatComp[x]&CHEATC_NOSHOW))
+   {
+    if(CheatComp[x]==v1 && CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2)
+    {
+
+    }
+    else
+     CheatComp[x]|=CHEATC_EXCLUDED;
+   }
+ }
+ else if(type==2)                          // Purely relative change.
+ {
+  for(x=0x000;x<0x10000;x++)
+   if(!(CheatComp[x]&CHEATC_NOSHOW))
+   {
+    if(CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2)
+    {
+
+    }
+    else
+     CheatComp[x]|=CHEATC_EXCLUDED;
+   }
+ }
+ else if(type==3)                          // Any change.
+ {
+  for(x=0x000;x<0x10000;x++)
+   if(!(CheatComp[x]&CHEATC_NOSHOW))
+   {
+    if(CheatComp[x]!=CheatRPtrs[x>>10][x])
+    {
+
+    }
+    else
+     CheatComp[x]|=CHEATC_EXCLUDED;
+   }
+
+ }
+}
diff --git a/cheat.h b/cheat.h
new file mode 100644 (file)
index 0000000..e930f52
--- /dev/null
+++ b/cheat.h
@@ -0,0 +1,6 @@
+void FCEU_CheatResetRAM(void);
+void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p);
+
+void LoadGameCheats(void);
+void FlushGameCheats(void);
+void ApplyPeriodicCheats(void);
diff --git a/crc32.c b/crc32.c
new file mode 100644 (file)
index 0000000..c4d272b
--- /dev/null
+++ b/crc32.c
@@ -0,0 +1,100 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#ifndef ZLIB
+#include "types.h"
+#include "crc32.h"
+
+static uint32 CRC32Table[256] = {
+       0x00000000,0x77073096,0xee0e612c,0x990951ba,
+       0x076dc419,0x706af48f,0xe963a535,0x9e6495a3,
+       0x0edb8832,0x79dcb8a4,0xe0d5e91e,0x97d2d988,
+       0x09b64c2b,0x7eb17cbd,0xe7b82d07,0x90bf1d91,
+       0x1db71064,0x6ab020f2,0xf3b97148,0x84be41de,
+       0x1adad47d,0x6ddde4eb,0xf4d4b551,0x83d385c7,
+       0x136c9856,0x646ba8c0,0xfd62f97a,0x8a65c9ec,
+       0x14015c4f,0x63066cd9,0xfa0f3d63,0x8d080df5,
+       0x3b6e20c8,0x4c69105e,0xd56041e4,0xa2677172,
+       0x3c03e4d1,0x4b04d447,0xd20d85fd,0xa50ab56b,
+       0x35b5a8fa,0x42b2986c,0xdbbbc9d6,0xacbcf940,
+       0x32d86ce3,0x45df5c75,0xdcd60dcf,0xabd13d59,
+       0x26d930ac,0x51de003a,0xc8d75180,0xbfd06116,
+       0x21b4f4b5,0x56b3c423,0xcfba9599,0xb8bda50f,
+       0x2802b89e,0x5f058808,0xc60cd9b2,0xb10be924,
+       0x2f6f7c87,0x58684c11,0xc1611dab,0xb6662d3d,
+       0x76dc4190,0x01db7106,0x98d220bc,0xefd5102a,
+       0x71b18589,0x06b6b51f,0x9fbfe4a5,0xe8b8d433,
+       0x7807c9a2,0x0f00f934,0x9609a88e,0xe10e9818,
+       0x7f6a0dbb,0x086d3d2d,0x91646c97,0xe6635c01,
+       0x6b6b51f4,0x1c6c6162,0x856530d8,0xf262004e,
+       0x6c0695ed,0x1b01a57b,0x8208f4c1,0xf50fc457,
+       0x65b0d9c6,0x12b7e950,0x8bbeb8ea,0xfcb9887c,
+       0x62dd1ddf,0x15da2d49,0x8cd37cf3,0xfbd44c65,
+       0x4db26158,0x3ab551ce,0xa3bc0074,0xd4bb30e2,
+       0x4adfa541,0x3dd895d7,0xa4d1c46d,0xd3d6f4fb,
+       0x4369e96a,0x346ed9fc,0xad678846,0xda60b8d0,
+       0x44042d73,0x33031de5,0xaa0a4c5f,0xdd0d7cc9,
+       0x5005713c,0x270241aa,0xbe0b1010,0xc90c2086,
+       0x5768b525,0x206f85b3,0xb966d409,0xce61e49f,
+       0x5edef90e,0x29d9c998,0xb0d09822,0xc7d7a8b4,
+       0x59b33d17,0x2eb40d81,0xb7bd5c3b,0xc0ba6cad,
+       0xedb88320,0x9abfb3b6,0x03b6e20c,0x74b1d29a,
+       0xead54739,0x9dd277af,0x04db2615,0x73dc1683,
+       0xe3630b12,0x94643b84,0x0d6d6a3e,0x7a6a5aa8,
+       0xe40ecf0b,0x9309ff9d,0x0a00ae27,0x7d079eb1,
+       0xf00f9344,0x8708a3d2,0x1e01f268,0x6906c2fe,
+       0xf762575d,0x806567cb,0x196c3671,0x6e6b06e7,
+       0xfed41b76,0x89d32be0,0x10da7a5a,0x67dd4acc,
+       0xf9b9df6f,0x8ebeeff9,0x17b7be43,0x60b08ed5,
+       0xd6d6a3e8,0xa1d1937e,0x38d8c2c4,0x4fdff252,
+       0xd1bb67f1,0xa6bc5767,0x3fb506dd,0x48b2364b,
+       0xd80d2bda,0xaf0a1b4c,0x36034af6,0x41047a60,
+       0xdf60efc3,0xa867df55,0x316e8eef,0x4669be79,
+       0xcb61b38c,0xbc66831a,0x256fd2a0,0x5268e236,
+       0xcc0c7795,0xbb0b4703,0x220216b9,0x5505262f,
+       0xc5ba3bbe,0xb2bd0b28,0x2bb45a92,0x5cb36a04,
+       0xc2d7ffa7,0xb5d0cf31,0x2cd99e8b,0x5bdeae1d,
+       0x9b64c2b0,0xec63f226,0x756aa39c,0x026d930a,
+       0x9c0906a9,0xeb0e363f,0x72076785,0x05005713,
+       0x95bf4a82,0xe2b87a14,0x7bb12bae,0x0cb61b38,
+       0x92d28e9b,0xe5d5be0d,0x7cdcefb7,0x0bdbdf21,
+       0x86d3d2d4,0xf1d4e242,0x68ddb3f8,0x1fda836e,
+       0x81be16cd,0xf6b9265b,0x6fb077e1,0x18b74777,
+       0x88085ae6,0xff0f6a70,0x66063bca,0x11010b5c,
+       0x8f659eff,0xf862ae69,0x616bffd3,0x166ccf45,
+       0xa00ae278,0xd70dd2ee,0x4e048354,0x3903b3c2,
+       0xa7672661,0xd06016f7,0x4969474d,0x3e6e77db,
+       0xaed16a4a,0xd9d65adc,0x40df0b66,0x37d83bf0,
+       0xa9bcae53,0xdebb9ec5,0x47b2cf7f,0x30b5ffe9,
+       0xbdbdf21c,0xcabac28a,0x53b39330,0x24b4a3a6,
+       0xbad03605,0xcdd70693,0x54de5729,0x23d967bf,
+       0xb3667a2e,0xc4614ab8,0x5d681b02,0x2a6f2b94,
+       0xb40bbe37,0xc30c8ea1,0x5a05df1b,0x2d02ef8d
+};
+
+uint32 CalcCRC32(uint32 crc, uint8 *buf, uint32 len)
+{
+ crc=~crc;
+ while(len--)
+  crc=(crc>>8)^CRC32Table[(crc&0xFF)^(*buf++)];
+ return(~crc);
+}
+#endif
diff --git a/crc32.h b/crc32.h
new file mode 100644 (file)
index 0000000..fa1291c
--- /dev/null
+++ b/crc32.h
@@ -0,0 +1,6 @@
+#ifdef ZLIB
+#include <zlib.h>
+#define CalcCRC32 crc32
+#else
+uint32 CalcCRC32(uint32 crc, uint8 *buf, uint32 len);
+#endif
diff --git a/debug.c b/debug.c
new file mode 100644 (file)
index 0000000..206a58d
--- /dev/null
+++ b/debug.c
@@ -0,0 +1,35 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdio.h>
+#include "types.h"
+#include "fce.h"
+#include "debug.h"
+
+
+
+void DumpMem(char *fname, uint32 start, uint32 end)
+{
+ FILE *fp=fopen(fname,"wb");
+ for(;start<=end;start++)
+  fputc(ARead[start](start),fp);
+ fclose(fp);
+
+}
diff --git a/debug.h b/debug.h
new file mode 100644 (file)
index 0000000..85afa34
--- /dev/null
+++ b/debug.h
@@ -0,0 +1,2 @@
+void DumpMem(char *fname, uint32 start, uint32 end);
+
diff --git a/drawing.h b/drawing.h
new file mode 100644 (file)
index 0000000..4e7bfec
--- /dev/null
+++ b/drawing.h
@@ -0,0 +1,154 @@
+static void DrawDips(void)
+{
+  uint32 *dest;
+  int y,x;
+
+  dest=(uint32 *)(XBuf+272*12+164);
+  for(y=24;y;y--,dest+=(272-72)>>2)
+  {
+   for(x=72>>2;x;x--,dest++)
+    *dest=0x80808080;
+  }
+
+  dest=(uint32 *)(XBuf+272*(12+4)+164+6 );
+  for(y=16;y;y--,dest+=(272>>2)-16)
+   for(x=8;x;x--)
+   {
+    *dest=0x81818181;
+    dest+=2;
+   }   
+
+  dest=(uint32 *)(XBuf+272*(12+4)+164+6 );
+  for(x=0;x<8;x++,dest+=2)
+  {
+   uint32 *da=dest+(272>>2);
+
+   if(!((vsdip>>x)&1))
+    da+=(272>>2)*10;
+    
+   for(y=4;y;y--,da+=272>>2)
+    *da=0x80808080;
+   
+  }
+}
+
+static void DrawMessage(void)
+{
+ if(howlong)
+  {
+   uint8 *t;
+   howlong--;
+   t=XBuf+(FSettings.LastSLine-29)*272+32;
+   if(t>=XBuf)
+    DrawTextTrans(t,272,errmsg,132);
+  }
+}
+
+uint8 sstat[2541] =
+{
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x81,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
+0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,
+0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,
+0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,
+0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,
+0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
+};
+
+uint8 fontdata2[2048] =
+{
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x81,0xa5,0x81,0xbd,0x99,0x81,0x7e,0x7e,0xff,0xdb,0xff,0xc3,0xe7,0xff,0x7e,0x36,0x7f,0x7f,0x7f,0x3e,0x1c,0x08,0x00,0x08,0x1c,0x3e,0x7f,0x3e,0x1c,0x08,0x00,0x1c,0x3e,0x1c,0x7f,0x7f,0x3e,0x1c,0x3e,0x08,0x08,0x1c,0x3e,0x7f,0x3e,0x1c,0x3e,0x00,0x00,0x18,0x3c,0x3c,0x18,0x00,0x00,0xff,0xff,0xe7,0xc3,0xc3,0xe7,0xff,0xff,0x00,0x3c,0x66,0x42,0x42,0x66,0x3c,0x00,0xff,0xc3,0x99,0xbd,0xbd,0x99,0xc3,0xff,0xf0,0xe0,0xf0,0xbe,0x33,0x33,0x33,0x1e,0x3c,0x66,0x66,0x66,0x3c,0x18,0x7e,0x18,0xfc,0xcc,0xfc,0x0c,0x0c,0x0e,0x0f,0x07,0xfe,0xc6,0xfe,0xc6,0xc6,0xe6,0x67,0x03,0x99,0x5a,0x3c,0xe7,0xe7,0x3c,0x5a,0x99,0x01,0x07,0x1f,0x7f,0x1f,0x07,0x01,0x00,0x40,0x70,0x7c,0x7f,0x7c,0x70,0x40,0x00,0x18,0x3c,0x7e,0x18,0x18,0x7e,0x3c,0x18,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x00,0xfe,0xdb,0xdb,0xde,0xd8,0xd8,0xd8,0x00,0x7c,0xc6,0x1c,0x36,0x36,0x1c,0x33,0x1e,0x00,0x00,0x00,0x00,0x7e,0x7e,0x7e,0x00,0x18,0x3c,0x7e,0x18,0x7e,0x3c,0x18,0xff,0x18,0x3c,0x7e,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00,0x00,0x18,0x30,0x7f,0x30,0x18,0x00,0x00,0x00,0x0c,0x06,0x7f,0x06,0x0c,0x00,0x00,0x00,0x00,0x03,0x03,0x03,0x7f,0x00,0x00,0x00,0x24,0x66,0xff,0x66,0x24,0x00,0x00,0x00,0x18,0x3c,0x7e,0xff,0xff,0x00,0x00,0x00,0xff,0xff,0x7e,0x3c,0x18,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x1e,0x0c,0x0c,0x00,0x0c,0x00,0x36,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x36,0x36,0x7f,0x36,0x7f,0x36,0x36,0x00,0x0c,0x3e,0x03,0x1e,0x30,0x1f,0x0c,0x00,0x00,0x63,0x33,0x18,0x0c,0x66,0x63,0x00,0x1c,0x36,0x1c,0x6e,0x3b,0x33,0x6e,0x00,0x06,0x06,0x03,0x00,0x00,0x00,0x00,0x00,0x18,0x0c,0x06,0x06,0x06,0x0c,0x18,0x00,0x06,0x0c,0x18,0x18,0x18,0x0c,0x06,0x00,0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00,0x00,0x0c,0x0c,0x3f,0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x0c,0x06,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x0c,0x00,0x60,0x30,0x18,0x0c,0x06,0x03,0x01,0x00,0x3e,0x63,0x73,0x7b,0x6f,0x67,0x3e,0x00,0x0c,0x0e,0x0c,0x0c,0x0c,0x0c,0x3f,0x00,0x1e,0x33,0x30,0x1c,0x06,0x33,0x3f,0x00,0x1e,0x33,0x30,0x1c,0x30,0x33,0x1e,0x00,0x38,0x3c,0x36,0x33,0x7f,0x30,0x78,0x00,0x3f,0x03,0x1f,0x30,0x30,0x33,0x1e,0x00,0x1c,0x06,0x03,0x1f,0x33,0x33,0x1e,0x00,0x3f,0x33,0x30,0x18,0x0c,0x0c,0x0c,0x00,0x1e,0x33,0x33,0x1e,0x33,0x33,0x1e,0x00,0x1e,0x33,0x33,0x3e,0x30,0x18,0x0e,0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x06,0x18,0x0c,0x06,0x03,0x06,0x0c,0x18,0x00,0x00,0x00,0x3f,0x00,0x00,0x3f,0x00,0x00,0x06,0x0c,0x18,0x30,0x18,0x0c,0x06,0x00,0x1e,0x33,0x30,0x18,0x0c,0x00,0x0c,0x00,
+0x3e,0x63,0x7b,0x7b,0x7b,0x03,0x1e,0x00,0x0c,0x1e,0x33,0x33,0x3f,0x33,0x33,0x00,0x3f,0x66,0x66,0x3e,0x66,0x66,0x3f,0x00,0x3c,0x66,0x03,0x03,0x03,0x66,0x3c,0x00,0x1f,0x36,0x66,0x66,0x66,0x36,0x1f,0x00,0x7f,0x46,0x16,0x1e,0x16,0x46,0x7f,0x00,0x7f,0x46,0x16,0x1e,0x16,0x06,0x0f,0x00,0x3c,0x66,0x03,0x03,0x73,0x66,0x7c,0x00,0x33,0x33,0x33,0x3f,0x33,0x33,0x33,0x00,0x1e,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x78,0x30,0x30,0x30,0x33,0x33,0x1e,0x00,0x67,0x66,0x36,0x1e,0x36,0x66,0x67,0x00,0x0f,0x06,0x06,0x06,0x46,0x66,0x7f,0x00,0x63,0x77,0x7f,0x7f,0x6b,0x63,0x63,0x00,0x63,0x67,0x6f,0x7b,0x73,0x63,0x63,0x00,0x1c,0x36,0x63,0x63,0x63,0x36,0x1c,0x00,0x3f,0x66,0x66,0x3e,0x06,0x06,0x0f,0x00,0x1e,0x33,0x33,0x33,0x3b,0x1e,0x38,0x00,0x3f,0x66,0x66,0x3e,0x36,0x66,0x67,0x00,0x1e,0x33,0x07,0x0e,0x38,0x33,0x1e,0x00,0x3f,0x2d,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x33,0x33,0x33,0x33,0x33,0x33,0x3f,0x00,0x33,0x33,0x33,0x33,0x33,0x1e,0x0c,0x00,0x63,0x63,0x63,0x6b,0x7f,0x77,0x63,0x00,0x63,0x63,0x36,0x1c,0x1c,0x36,0x63,0x00,0x33,0x33,0x33,0x1e,0x0c,0x0c,0x1e,0x00,0x7f,0x63,0x31,0x18,0x4c,0x66,0x7f,0x00,0x1e,0x06,0x06,0x06,0x06,0x06,0x1e,0x00,0x03,0x06,0x0c,0x18,0x30,0x60,0x40,0x00,0x1e,0x18,0x18,0x18,0x18,0x18,0x1e,0x00,0x08,0x1c,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,
+0x0c,0x0c,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1e,0x30,0x3e,0x33,0x6e,0x00,0x07,0x06,0x06,0x3e,0x66,0x66,0x3b,0x00,0x00,0x00,0x1e,0x33,0x03,0x33,0x1e,0x00,0x38,0x30,0x30,0x3e,0x33,0x33,0x6e,0x00,0x00,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x1c,0x36,0x06,0x0f,0x06,0x06,0x0f,0x00,0x00,0x00,0x6e,0x33,0x33,0x3e,0x30,0x1f,0x07,0x06,0x36,0x6e,0x66,0x66,0x67,0x00,0x0c,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x30,0x00,0x30,0x30,0x30,0x33,0x33,0x1e,0x07,0x06,0x66,0x36,0x1e,0x36,0x67,0x00,0x0e,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x33,0x7f,0x7f,0x6b,0x63,0x00,0x00,0x00,0x1f,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x1e,0x33,0x33,0x33,0x1e,0x00,0x00,0x00,0x3b,0x66,0x66,0x3e,0x06,0x0f,0x00,0x00,0x6e,0x33,0x33,0x3e,0x30,0x78,0x00,0x00,0x3b,0x6e,0x66,0x06,0x0f,0x00,0x00,0x00,0x3e,0x03,0x1e,0x30,0x1f,0x00,0x08,0x0c,0x3e,0x0c,0x0c,0x2c,0x18,0x00,0x00,0x00,0x33,0x33,0x33,0x33,0x6e,0x00,0x00,0x00,0x33,0x33,0x33,0x1e,0x0c,0x00,0x00,0x00,0x63,0x6b,0x7f,0x7f,0x36,0x00,0x00,0x00,0x63,0x36,0x1c,0x36,0x63,0x00,0x00,0x00,0x33,0x33,0x33,0x3e,0x30,0x1f,0x00,0x00,0x3f,0x19,0x0c,0x26,0x3f,0x00,0x38,0x0c,0x0c,0x07,0x0c,0x0c,0x38,0x00,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0x07,0x0c,0x0c,0x38,0x0c,0x0c,0x07,0x00,0x6e,0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1c,0x36,0x63,0x63,0x7f,0x00,
+0x1e,0x33,0x03,0x33,0x1e,0x18,0x30,0x1e,0x00,0x33,0x00,0x33,0x33,0x33,0x7e,0x00,0x38,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x7e,0xc3,0x3c,0x60,0x7c,0x66,0xfc,0x00,0x33,0x00,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x07,0x00,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x0c,0x0c,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x00,0x00,0x1e,0x03,0x03,0x1e,0x30,0x1c,0x7e,0xc3,0x3c,0x66,0x7e,0x06,0x3c,0x00,0x33,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x07,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x33,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x3e,0x63,0x1c,0x18,0x18,0x18,0x3c,0x00,0x07,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x63,0x1c,0x36,0x63,0x7f,0x63,0x63,0x00,0x0c,0x0c,0x00,0x1e,0x33,0x3f,0x33,0x00,0x38,0x00,0x3f,0x06,0x1e,0x06,0x3f,0x00,0x00,0x00,0xfe,0x30,0xfe,0x33,0xfe,0x00,0x7c,0x36,0x33,0x7f,0x33,0x33,0x73,0x00,0x1e,0x33,0x00,0x1e,0x33,0x33,0x1e,0x00,0x00,0x33,0x00,0x1e,0x33,0x33,0x1e,0x00,0x00,0x07,0x00,0x1e,0x33,0x33,0x1e,0x00,0x1e,0x33,0x00,0x33,0x33,0x33,0x7e,0x00,0x00,0x07,0x00,0x33,0x33,0x33,0x7e,0x00,0x00,0x33,0x00,0x33,0x33,0x3e,0x30,0x1f,0xc3,0x18,0x3c,0x66,0x66,0x3c,0x18,0x00,0x33,0x00,0x33,0x33,0x33,0x33,0x1e,0x00,0x18,0x18,0x7e,0x03,0x03,0x7e,0x18,0x18,0x1c,0x36,0x26,0x0f,0x06,0x67,0x3f,0x00,0x33,0x33,0x1e,0x3f,0x0c,0x3f,0x0c,0x0c,0x1f,0x33,0x33,0x5f,0x63,0xf3,0x63,0xe3,0x70,0xd8,0x18,0x3c,0x18,0x18,0x1b,0x0e,
+0x38,0x00,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x1c,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x38,0x00,0x1e,0x33,0x33,0x1e,0x00,0x00,0x38,0x00,0x33,0x33,0x33,0x7e,0x00,0x00,0x1f,0x00,0x1f,0x33,0x33,0x33,0x00,0x3f,0x00,0x33,0x37,0x3f,0x3b,0x33,0x00,0x3c,0x36,0x36,0x7c,0x00,0x7e,0x00,0x00,0x1c,0x36,0x36,0x1c,0x00,0x3e,0x00,0x00,0x0c,0x00,0x0c,0x06,0x03,0x33,0x1e,0x00,0x00,0x00,0x00,0x3f,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x3f,0x30,0x30,0x00,0x00,0xc3,0x63,0x33,0x7b,0xcc,0x66,0x33,0xf0,0xc3,0x63,0x33,0xdb,0xec,0xf6,0xf3,0xc0,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x00,0x00,0xcc,0x66,0x33,0x66,0xcc,0x00,0x00,0x00,0x33,0x66,0xcc,0x66,0x33,0x00,0x00,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xdb,0xee,0xdb,0x77,0xdb,0xee,0xdb,0x77,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x1f,0x18,0x18,0x18,0x6c,0x6c,0x6c,0x6c,0x6f,0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00,0x7f,0x6c,0x6c,0x6c,0x00,0x00,0x1f,0x18,0x1f,0x18,0x18,0x18,0x6c,0x6c,0x6f,0x60,0x6f,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x7f,0x60,0x6f,0x6c,0x6c,0x6c,0x6c,0x6c,0x6f,0x60,0x7f,0x00,0x00,0x00,0x6c,0x6c,0x6c,0x6c,0x7f,0x00,0x00,0x00,0x18,0x18,0x1f,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0xf8,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0xf8,0x18,0x18,0x18,0x6c,0x6c,0x6c,0x6c,0xec,0x6c,0x6c,0x6c,0x6c,0x6c,0xec,0x0c,0xfc,0x00,0x00,0x00,0x00,0x00,0xfc,0x0c,0xec,0x6c,0x6c,0x6c,0x6c,0x6c,0xef,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xef,0x6c,0x6c,0x6c,0x6c,0x6c,0xec,0x0c,0xec,0x6c,0x6c,0x6c,0x00,0x00,0xff,0x00,0xff,0x00,0x00,0x00,0x6c,0x6c,0xef,0x00,0xef,0x6c,0x6c,0x6c,0x18,0x18,0xff,0x00,0xff,0x00,0x00,0x00,0x6c,0x6c,0x6c,0x6c,0xff,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0xff,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0xfc,0x00,0x00,0x00,0x18,0x18,0xf8,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0xf8,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0xfc,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0xff,0x6c,0x6c,0x6c,0x18,0x18,0xff,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0x18,0x18,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
+0x00,0x00,0x6e,0x3b,0x13,0x3b,0x6e,0x00,0x00,0x1e,0x33,0x1f,0x33,0x1f,0x03,0x03,0x00,0x3f,0x33,0x03,0x03,0x03,0x03,0x00,0x00,0x7f,0x36,0x36,0x36,0x36,0x36,0x00,0x3f,0x33,0x06,0x0c,0x06,0x33,0x3f,0x00,0x00,0x00,0x7e,0x1b,0x1b,0x1b,0x0e,0x00,0x00,0x66,0x66,0x66,0x66,0x3e,0x06,0x03,0x00,0x6e,0x3b,0x18,0x18,0x18,0x18,0x00,0x3f,0x0c,0x1e,0x33,0x33,0x1e,0x0c,0x3f,0x1c,0x36,0x63,0x7f,0x63,0x36,0x1c,0x00,0x1c,0x36,0x63,0x63,0x36,0x36,0x77,0x00,0x38,0x0c,0x18,0x3e,0x33,0x33,0x1e,0x00,0x00,0x00,0x7e,0xdb,0xdb,0x7e,0x00,0x00,0x60,0x30,0x7e,0xdb,0xdb,0x7e,0x06,0x03,0x1c,0x06,0x03,0x1f,0x03,0x06,0x1c,0x00,0x1e,0x33,0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x3f,0x00,0x3f,0x00,0x3f,0x00,0x00,0x0c,0x0c,0x3f,0x0c,0x0c,0x00,0x3f,0x00,0x06,0x0c,0x18,0x0c,0x06,0x00,0x3f,0x00,0x18,0x0c,0x06,0x0c,0x18,0x00,0x3f,0x00,0x70,0xd8,0xd8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x0e,0x0c,0x0c,0x00,0x3f,0x00,0x0c,0x0c,0x00,0x00,0x6e,0x3b,0x00,0x6e,0x3b,0x00,0x00,0x1c,0x36,0x36,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xf0,0x30,0x30,0x30,0x37,0x36,0x3c,0x38,0x1e,0x36,0x36,0x36,0x36,0x00,0x00,0x00,0x0e,0x18,0x0c,0x06,0x1e,0x00,0x00,0x00,0x00,0x00,0x3c,0x3c,0x3c,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+
+static void DrawState(void)
+{
+ uint8 *XBaf;
+ int x,y,z;
+
+ XBaf=XBuf+4+(FSettings.LastSLine-44)*272;
+
+ if(XBaf>=XBuf)
+ for(z=1;z<11;z++)
+ {
+  if(SaveStateStatus[z%10]) 
+   {
+          for(y=0;y<13;y++)
+           for(x=0;x<21;x++)
+           XBaf[y*272+x+z*21+z]=sstat[y*21+x+(z-1)*21*12];           
+   } else {
+          for(y=0;y<13;y++)
+           for(x=0;x<21;x++)
+            if(sstat[y*21+x+(z-1)*21*12]!=0x83)
+             XBaf[y*272+x+z*21+z]=sstat[y*21+x+(z-1)*21*12];
+   }
+  if(CurrentState==z%10)
+   {
+    for(x=0;x<21;x++)
+     XBaf[x+z*21+z*1]=132;
+    for(x=1;x<12;x++)
+     {
+     XBaf[272*x+z*21+z*1]=
+     XBaf[272*x+z*21+z*1+20]=132;
+     }
+    for(x=0;x<21;x++)
+     XBaf[3264+x+z*21+z*1]=132;
+   }
+  } 
+ StateShow--;
+}
+
+void DrawTextTrans(uint8 *dest, uint32 width, uint8 *textmsg, uint8 fgcolor)
+{
+       uint8 length=strlen(textmsg);
+       uint8 x;
+       uint8 y;
+       uint8 z;
+
+       for(x=0;x<length;x++)    
+         for(y=0;y<8;y++)       
+          for(z=0;z<8;z++) 
+           if((fontdata2[(textmsg[x]<<3)+y]>>z)&1) dest[y*width+(x<<3)+z]=fgcolor;
+}
+
+void DrawBars(void)
+{
+ uint8 *XBaf;
+ short which=0;
+ int x,x2;
+
+ if(controlselect==1)
+ {
+  DrawTextTrans(XBuf+128-12+180*272, 272, "Hue", 0x85);
+  which=ntschue<<1;
+ }
+ else if(controlselect==2)
+ {
+  DrawTextTrans(XBuf+128-16+180*272, 272, "Tint", 0x85);
+  which=ntsctint<<1;
+ }
+
+ XBaf=XBuf+200*272;
+ for(x=0;x<which;x+=2)
+ {
+  for(x2=6;x2>=-6;x2--)
+  {
+   XBaf[x-272*x2]=0x85;
+  }
+ }
+ for(;x<256;x+=2)
+ {
+  for(x2=2;x2>=-2;x2--)
+   XBaf[x-272*x2]=0x85;
+ }
+
+}
diff --git a/driver.h b/driver.h
new file mode 100644 (file)
index 0000000..9a298c6
--- /dev/null
+++ b/driver.h
@@ -0,0 +1,174 @@
+#include "types.h"
+#include "git.h"
+
+/* Prototypes for platform interface functions follow: */
+
+void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count);
+
+/* Video interface */
+void FCEUD_SetPalette(uint8 index, uint8 r, uint8 g, uint8 b);
+void FCEUD_GetPalette(uint8 i,uint8 *r, unsigned char *g, unsigned char *b);
+
+/* Sound interface */
+void FCEUD_WriteSoundData(int32 *Buffer, int Count);
+
+/* Displays an error.  Can block or not. */
+void FCEUD_PrintError(char *s);
+
+#ifdef NETWORK
+/* Network interface */
+
+int FCEUD_NetworkConnect(void);
+int FCEUD_NetworkRecvData(uint8 *data, uint32 len, int block);
+int FCEUD_NetworkSendData(uint8 *data, uint32 len);
+void FCEUD_NetworkClose(void);
+
+#endif
+
+#define DES_NTSCCOL     2
+
+#define DES_RESET       0x10
+#define DES_POWER       0x11
+
+#define DES_GETNTSCHUE  0x20
+#define DES_GETNTSCTINT  0x21
+#define DES_SETNTSCHUE  0x22
+#define DES_SETNTSCTINT  0x23
+
+#define DES_NSFINC     0x50
+#define DES_NSFDEC     0x51
+#define DES_NSFRES     0x52
+
+#define DES_VSUNIDIPSET 0x70
+#define DES_VSUNITOGGLEDIPVIEW 0x71
+#define        DES_VSUNICOIN   0x72
+#define DES_FDSINSERT  0x80
+#define DES_FDSEJECT   0x81
+#define DES_FDSSELECT  0x82
+
+#define DES_NTSCSELHUE 0x90
+#define DES_NTSCSELTINT        0x91
+#define DES_NTSCDEC    0x92
+#define DES_NTSCINC    0x93
+
+void DriverInterface(int w, void *d);
+
+void FCEUI_SetInput(int port, int type, void *ptr, int attrib);
+void FCEUI_SetInputFC(int type, void *ptr, int attrib);
+void FCEUI_DisableFourScore(int s);
+
+#include "version.h"
+
+#define SI_NONE     0
+#define SI_GAMEPAD  1
+#define SI_ZAPPER   2
+#define SI_POWERPAD 3
+#define SI_ARKANOID 4
+
+#define SIFC_NONE      0
+#define SIFC_ARKANOID  1
+#define SIFC_SHADOW    2
+#define SIFC_4PLAYER    3
+#define SIFC_FKB       4
+#define SIFC_OEKA      5
+
+/* New interface functions */
+
+/* 0 to order screen snapshots numerically(0.png), 1 to order them file base-numerically(smb3-0.png). */
+void FCEUI_SetSnapName(int a);
+
+/* 0 to keep 8-sprites limitation, 1 to remove it */
+void FCEUI_DisableSpriteLimitation(int a);
+
+/* 0 to save extra game data(*.sav) in same dir as game, 1 to save under base dir */
+void FCEUI_SaveExtraDataUnderBase(int a);
+
+/* name=path and file to load.  returns 0 on failure, 1 on success */
+FCEUGI *FCEUI_LoadGame(char *name);
+
+/* allocates memory.  0 on failure, 1 on success. */
+int FCEUI_Initialize(void);
+
+/* begins emulation.  Returns after FCEUI_CloseGame() is called */
+void FCEUI_Emulate(void);
+
+/* Closes currently loaded game, causes FCEUI_Emulate to return */
+void FCEUI_CloseGame(void);
+
+/* Enable/Disable game genie. a=0 disable, a=1 enable */
+void FCEUI_SetGameGenie(int a);
+
+/* Set video system a=0 NTSC, a=1 PAL */
+void FCEUI_SetVidSystem(int a);
+
+/* Convenience function; returns currently emulated video system(0=NTSC, 1=PAL).  */
+int FCEUI_GetCurrentVidSystem(int *slstart, int *slend);
+
+#ifdef FRAMESKIP
+/* Should be called from FCEUD_BlitScreen().  Specifies how many frames
+   to skip until FCEUD_BlitScreen() is called.  FCEUD_BlitScreenDummy()
+   will be called instead of FCEUD_BlitScreen() when when a frame is skipped.
+*/
+void FCEUI_FrameSkip(int x);
+#endif
+
+/* First and last scanlines to render, for ntsc and pal emulation. */
+void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall);
+
+/* Sets the base directory(save states, snapshots, etc. are saved in directories
+   below this directory. */
+void FCEUI_SetBaseDirectory(char *dir);
+
+/* Tells FCE Ultra to copy the palette data pointed to by pal and use it.
+   Data pointed to by pal needs to be 64*3 bytes in length.
+*/
+void FCEUI_SetPaletteArray(uint8 *pal);
+
+/* Sets up sound code to render sound at the specified rate, in samples
+   per second.  The sample rate should be as close to 44100 hz as possible.
+   Sample rates from 8192 through 65535 are ok, though if the sample rate
+   is too low, some sound channels(noise) won't sound right.
+   If "Rate" equals 0, sound is disabled.
+*/
+void FCEUI_Sound(int Rate);
+void FCEUI_SetSoundVolume(uint32 volume);
+
+#ifdef NETWORK
+/* Set network play stuff. type=1 for server, type=2 for client.
+   skip is only used for server */
+void FCEUI_SetNetworkPlay(int type);
+#endif
+
+void FCEUI_SelectState(int w);
+void FCEUI_SaveState(void);
+void FCEUI_LoadState(void);
+int32 FCEUI_GetDesiredFPS(void);
+void FCEUI_SaveSnapshot(void);
+void FCEU_DispMessage(char *format, ...);
+#define FCEUI_DispMessage FCEU_DispMessage
+
+int FCEUI_AddCheat(char *name, uint32 addr, uint8 val);
+int FCEUI_DelCheat(uint32 which);
+
+int32 FCEUI_CheatSearchGetCount(void);
+void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current));
+void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current));
+void FCEUI_CheatSearchBegin(void);
+void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2);
+void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int s));
+
+int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *s);
+int FCEUI_SetCheat(uint32 which, char *name, int32 a, int32 v, int s);
+void FCEUI_CheatSearchShowExcluded(void);
+void FCEUI_CheatSearchSetCurrentAsOriginal(void);
+
+#define FCEUIOD_STATE   0
+#define FCEUIOD_SNAPS   1
+#define FCEUIOD_NV      2
+#define FCEUIOD_CHEATS  3
+#define FCEUIOD_MISC    4
+
+#define FCEUIOD__COUNT  5
+
+void FCEUI_SetDirOverride(int which, char *n);
+
diff --git a/drivers/cli/dface.h b/drivers/cli/dface.h
new file mode 100644 (file)
index 0000000..92df082
--- /dev/null
@@ -0,0 +1,32 @@
+extern CFGSTRUCT DriverConfig[];
+extern ARGPSTRUCT DriverArgs[];
+extern char *DriverUsage;
+
+void DoDriverArgs(void);
+void GetBaseDirectory(char *BaseDirectory);
+
+int InitSound(void);
+void WriteSound(int32 *Buffer, int Count, int NoWaiting);
+void KillSound(void);
+void SilenceSound(int s); /* DOS and SDL */
+
+
+int InitMouse(void);
+void KillMouse(void);
+void GetMouseData(uint32 *MouseData);
+
+int InitJoysticks(void);
+void KillJoysticks(void);
+uint32 *GetJSOr(void);
+
+int InitKeyboard(void);
+int UpdateKeyboard(void);
+char *GetKeyboard(void);
+void KillKeyboard(void);
+
+int InitVideo(void);
+void KillVideo(void);
+void BlitScreen(uint8 *XBuf);
+void LockConsole(void);
+void UnlockConsole(void);
+void ToggleFS();               /* SDL */
diff --git a/drivers/cli/dos-joystick.c b/drivers/cli/dos-joystick.c
new file mode 100644 (file)
index 0000000..3729187
--- /dev/null
@@ -0,0 +1,190 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <dpmi.h>
+#include <sys/farptr.h>
+#include <go32.h>
+#include <pc.h>
+
+#include "dos.h"
+#include "dos-joystick.h"
+
+#define JOY_A   1
+#define JOY_B   2
+#define JOY_SELECT      4
+#define JOY_START       8
+#define JOY_UP  0x10
+#define JOY_DOWN        0x20
+#define JOY_LEFT        0x40
+#define JOY_RIGHT       0x80
+
+int joy=0;
+int joyBMap[4];
+
+static int32 joybuttons=0;
+static uint32 joyx=0;
+static uint32 joyy=0;
+static uint32 joyxcenter;
+static uint32 joyycenter;
+
+static void ConfigJoystick(void);
+volatile int soundjoyer=0;
+volatile int soundjoyeron=0;
+
+/* Crude method to detect joystick. */
+static int DetectJoystick(void)
+{
+ uint8 b;
+
+ outportb(0x201,0);
+ b=inportb(0x201);
+ sleep(1);
+ if((inportb(0x201)&3)==(b&3))
+  return 0;
+ else
+  return 1;
+}
+
+void UpdateJoyData(void)
+{
+ uint32 xc,yc;
+
+
+ joybuttons=((inportb(0x201)&0xF0)^0xF0)>>4;
+
+ xc=yc=0;
+
+ {
+  outportb(0x201,0);
+
+  for(;;)
+  {
+   uint8 b;
+
+   b=inportb(0x201);
+   if(!(b&3))
+    break;
+   if(b&1) xc++;
+   if(b&2) yc++;
+  }
+ }
+
+ joyx=xc;
+ joyy=yc;
+}
+
+uint32 GetJSOr(void)
+{
+        int y;
+        unsigned long ret;
+        ret=0;
+
+        if(!soundo)
+         UpdateJoyData();
+        for(y=0;y<4;y++)
+         if(joybuttons&joyBMap[y]) ret|=(1<<y)<<((joy-1)<<3);
+
+        if(joyx<=joyxcenter*.25) ret|=JOY_LEFT<<((joy-1)<<3);
+        else if(joyx>=joyxcenter*1.75) ret|=JOY_RIGHT<<((joy-1)<<3);
+        if(joyy<=joyycenter*.25) ret|=JOY_UP<<((joy-1)<<3);
+        else if(joyy>=joyycenter*1.75) ret|=JOY_DOWN<<((joy-1)<<3);
+
+        return ret;
+}
+
+int InitJoysticks(void)
+{
+       if(!joy) return(0);
+        if(!DetectJoystick())
+        {
+         printf("Joystick not detected!\n");
+         joy=0;
+         return 0;
+        }
+        if(soundo)
+        {
+         soundjoyeron=1;
+         while(!soundjoyer);
+        }
+        else
+         UpdateJoyData();
+
+        joyxcenter=joyx;
+        joyycenter=joyy;
+
+        if(!(joyBMap[0]|joyBMap[1]|joyBMap[2]|joyBMap[3]))
+         ConfigJoystick();
+        return(1);
+}
+
+static void BConfig(int b)
+{
+  int c=0;
+  uint32 st=time(0);
+
+  while(time(0)< (st+4) )
+  {
+   if(!soundo)
+    UpdateJoyData();
+   if(joybuttons) c=joybuttons;
+   else if(c && !joybuttons)
+   {
+    joyBMap[b]=c;
+    break;
+   }
+
+  }
+}
+
+void KillJoysticks(void)
+{
+
+}
+
+static void ConfigJoystick(void)
+{
+ static char *genb="** Press button for ";
+
+ printf("\n\n Joystick button configuration:\n\n");
+ printf("   Push and release the button to map to the virtual joystick.\n");
+ printf("   If you do not wish to assign a button, wait a few seconds\n");
+ printf("   and the configuration will continue.\n\n");
+ printf("   Press enter to continue...\n");
+ getchar();
+                                                        
+ printf("%s\"Select\".\n",genb);
+ BConfig(2);
+
+ printf("%s\"Start\".\n",genb);
+ BConfig(3);
+
+ printf("%s\"B\".\n",genb);
+ BConfig(1);
+
+ printf("%s\"A\".\n",genb);
+ BConfig(0);
+}
+
diff --git a/drivers/cli/dos-joystick.h b/drivers/cli/dos-joystick.h
new file mode 100644 (file)
index 0000000..6cfaee5
--- /dev/null
@@ -0,0 +1,27 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 2002 Ben Parnell\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+void UpdateJoyData(void);\r
+uint32 GetJSOr(void);\r
+int InitJoysticks(void);\r
+\r
+/* Variables to save in config file. */\r
+extern int joy;\r
+extern int joyBMap[4];\r
diff --git a/drivers/cli/dos-keyboard.c b/drivers/cli/dos-keyboard.c
new file mode 100644 (file)
index 0000000..22ca9e8
--- /dev/null
@@ -0,0 +1,131 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 2002 Ben Parnell\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <signal.h>\r
+#include <string.h>\r
+#include <pc.h>\r
+#include <dpmi.h>\r
+#include <go32.h>\r
+#include "keyscan.h"\r
+\r
+static unsigned char lastsc;\r
+static char keybuf[256];\r
+int newk;\r
+\r
+/* Read scan code from port $60 */\r
+/* Acknowledge interrupt( output $20 to port $20) */\r
+\r
+static void ihandler(_go32_dpmi_registers *r)\r
+{\r
+ unsigned char scode=inp(0x60);        /* Get scan code. */\r
+\r
+\r
+ if(scode!=0xE0)\r
+ {\r
+  int offs=0;\r
+\r
+  /* I'm only interested in preserving the independent status of the\r
+     right ALT and CONTROL keys.\r
+  */\r
+  if(lastsc==0xE0)\r
+   if((scode&0x7F)==SCAN_LEFTALT || (scode&0x7F)==SCAN_LEFTCONTROL)\r
+    offs=0x80;\r
+  \r
+\r
+  keybuf[(scode&0x7f)|offs]=((scode&0x80)^0x80);\r
+  newk++;\r
+ }\r
+ lastsc=scode;\r
+\r
+ outp(0x20,0x20);      /* Acknowledge interrupt. */\r
+}\r
+\r
+static _go32_dpmi_seginfo KBIBack,KBIBackRM;\r
+static _go32_dpmi_seginfo KBI,KBIRM;\r
+static _go32_dpmi_registers KBIRMRegs;\r
+static int initdone=0;\r
+\r
+int InitKeyboard(void)\r
+{\r
+ /* I'll assume that the keyboard is in the correct scancode mode(translated\r
+    mode 2, I think).\r
+ */\r
+  newk=0;\r
+  memset(keybuf,0,sizeof(keybuf));\r
+  KBIRM.pm_offset=KBI.pm_offset=(int)ihandler;\r
+  KBIRM.pm_selector=KBI.pm_selector=_my_cs();\r
+\r
+  _go32_dpmi_get_real_mode_interrupt_vector(9,&KBIBackRM);\r
+  _go32_dpmi_allocate_real_mode_callback_iret(&KBIRM, &KBIRMRegs);\r
+  _go32_dpmi_set_real_mode_interrupt_vector(9,&KBIRM);\r
+\r
+  _go32_dpmi_get_protected_mode_interrupt_vector(9,&KBIBack);\r
+  _go32_dpmi_allocate_iret_wrapper(&KBI);\r
+  _go32_dpmi_set_protected_mode_interrupt_vector(9,&KBI);\r
+  lastsc=0;\r
+  initdone=1;\r
+  return(1);\r
+}\r
+\r
+void KillKeyboard(void)\r
+{\r
+ if(initdone)\r
+ {\r
+  _go32_dpmi_set_protected_mode_interrupt_vector(9,&KBIBack);\r
+  _go32_dpmi_free_iret_wrapper(&KBI);\r
+\r
+  _go32_dpmi_set_real_mode_interrupt_vector(9,&KBIBackRM);\r
+  _go32_dpmi_free_real_mode_callback(&KBIRM);\r
+  initdone=0;\r
+ }\r
+}\r
+\r
+/* In FCE Ultra, it doesn't matter if the key states change\r
+   in the middle of the keyboard handling code.  If you want\r
+   to use this code elsewhere, you may want to memcpy() keybuf\r
+   to another buffer and return that when GetKeyboard() is\r
+   called.\r
+*/\r
+\r
+char *GetKeyboard(void)\r
+{\r
+ return keybuf;\r
+}\r
+\r
+/* Returns 1 on new scan codes generated, 0 on no new scan codes. */\r
+int UpdateKeyboard(void)\r
+{\r
+ int t=newk;\r
+\r
+ if(t)\r
+ {\r
+  asm volatile(\r
+        "subl %%eax,_newk\n\t"\r
+       :\r
+       : "a" (t)\r
+  );\r
+\r
+  if(keybuf[SCAN_LEFTCONTROL] && keybuf[SCAN_C])\r
+   raise(SIGINT);\r
+  return(1);\r
+ }\r
+ return(0);\r
+}\r
diff --git a/drivers/cli/dos-mouse.c b/drivers/cli/dos-mouse.c
new file mode 100644 (file)
index 0000000..ae3e341
--- /dev/null
@@ -0,0 +1,77 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 2002 Ben Parnell\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+#include <dpmi.h>\r
+#include <string.h>\r
+\r
+#include "dos.h"\r
+\r
+int InitMouse(void)\r
+{\r
+ __dpmi_regs regs;\r
+\r
+ memset(&regs,0,sizeof(regs));\r
+ regs.x.ax=0;\r
+ __dpmi_int(0x33,&regs);\r
+ if(regs.x.ax!=0xFFFF)\r
+  return(0);\r
+\r
+ memset(&regs,0,sizeof(regs));\r
+ regs.x.ax=0x7;\r
+ regs.x.cx=0;           // Min X\r
+ regs.x.dx=260;         // Max X\r
+ __dpmi_int(0x33,&regs);\r
+\r
+ memset(&regs,0,sizeof(regs));\r
+ regs.x.ax=0x8;\r
+ regs.x.cx=0;           // Min Y\r
+ regs.x.dx=260;         // Max Y\r
+ __dpmi_int(0x33,&regs);\r
+\r
+ memset(&regs,0,sizeof(regs));\r
+ regs.x.ax=0xF;\r
+ regs.x.cx=8;           // Mickey X\r
+ regs.x.dx=8;           // Mickey Y\r
+ __dpmi_int(0x33,&regs);\r
+\r
+ memset(&regs,0,sizeof(regs));\r
+ regs.x.ax=0x2;\r
+ __dpmi_int(0x33,&regs);\r
+\r
+ return(1);\r
+}\r
+\r
+uint32 GetMouseData(uint32 *x, uint32 *y)\r
+{\r
+ __dpmi_regs regs;\r
+\r
+ memset(&regs,0,sizeof(regs));\r
+ regs.x.ax=0x3;\r
+ __dpmi_int(0x33,&regs);\r
+\r
+ *x=regs.x.cx;\r
+ *y=regs.x.dx;\r
+ return(regs.x.bx&3);\r
+}\r
+\r
+void KillMouse(void)\r
+{\r
+\r
+}\r
diff --git a/drivers/cli/dos-sound.c b/drivers/cli/dos-sound.c
new file mode 100644 (file)
index 0000000..19ef271
--- /dev/null
@@ -0,0 +1,567 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 2002 Ben Parnell\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <sys/farptr.h>\r
+#include <pc.h>\r
+#include <dos.h>\r
+#include <dpmi.h>\r
+#include <go32.h>\r
+#include <ctype.h>\r
+\r
+#include "dos.h"\r
+#include "dos-sound.h"\r
+#include "dos-joystick.h"\r
+\r
+\r
+static void SBIRQHandler(_go32_dpmi_registers *r);\r
+static uint32 LMBuffer;         /* Address of low memory DMA playback buffer. */\r
+static int LMSelector;\r
+\r
+static uint8 *WaveBuffer;\r
+static unsigned int IVector, SBIRQ, SBDMA, SBDMA16, SBPort;\r
+static int DSPV,hsmode;\r
+static int format;\r
+static int frags, fragsize, fragtotal;\r
+static volatile int WritePtr, ReadPtr;\r
+static volatile int hbusy;\r
+static volatile int whichbuf;\r
+\r
+\r
+static uint8 PICMask;\r
+/* Protected mode interrupt vector info. */\r
+static _go32_dpmi_seginfo SBIH,SBIHOld;\r
+\r
+/* Real mode interrupt vector info. */\r
+static _go32_dpmi_seginfo SBIHRM,SBIHRMOld;\r
+static _go32_dpmi_registers SBIHRMRegs;\r
+\r
+static int WriteDSP(uint8 V)\r
+{\r
+ int x;\r
+\r
+ for(x=65536;x;x--)\r
+ {\r
+  if(!(inportb(SBPort+0xC)&0x80))\r
+  {\r
+   outportb(SBPort+0xC,V);\r
+   return(1);\r
+  }\r
+ }\r
+ return(0);\r
+}\r
+\r
+static int ReadDSP(uint8 *V)\r
+{\r
+ int x;\r
+\r
+ for(x=65536;x;x--)             /* Should be more than enough time... */\r
+ {\r
+  if(inportb(SBPort+0xE)&0x80)\r
+  {\r
+   *V=inportb(SBPort+0xA);\r
+   return(1);\r
+  }\r
+ }\r
+ return(0);\r
+}\r
+\r
+\r
+static int SetVectors(void)\r
+{\r
+ SBIH.pm_offset=SBIHRM.pm_offset=(int)SBIRQHandler;\r
+ SBIH.pm_selector=SBIHRM.pm_selector=_my_cs();\r
+\r
+ /* Get and set real mode interrupt vector.  */\r
+ _go32_dpmi_get_real_mode_interrupt_vector(IVector,&SBIHRMOld);\r
+ _go32_dpmi_allocate_real_mode_callback_iret(&SBIHRM, &SBIHRMRegs);\r
+ _go32_dpmi_set_real_mode_interrupt_vector(IVector,&SBIHRM);  \r
+\r
+ /* Get and set protected mode interrupt vector. */\r
+ _go32_dpmi_get_protected_mode_interrupt_vector(IVector,&SBIHOld);\r
+ _go32_dpmi_allocate_iret_wrapper(&SBIH);\r
+ _go32_dpmi_set_protected_mode_interrupt_vector(IVector,&SBIH); \r
+\r
+ return(1);\r
+}\r
+\r
+static void ResetVectors(void)\r
+{\r
+ _go32_dpmi_set_protected_mode_interrupt_vector(IVector,&SBIHOld);\r
+ _go32_dpmi_free_iret_wrapper(&SBIH);\r
+ _go32_dpmi_set_real_mode_interrupt_vector(IVector,&SBIHRMOld);\r
+ _go32_dpmi_free_real_mode_callback(&SBIHRM);\r
+}\r
+\r
+int GetBLASTER(void)\r
+{\r
+ int check=0;\r
+ char *s;\r
+\r
+ if(!(s=getenv("BLASTER")))\r
+ {\r
+  puts(" Error getting BLASTER environment variable.");\r
+  return(0);\r
+ }\r
+\r
+ while(*s)\r
+ {\r
+  switch(toupper(*s))\r
+  {\r
+   case 'A': check|=(sscanf(s+1,"%x",&SBPort)==1)?1:0;break;\r
+   case 'I': check|=(sscanf(s+1,"%d",&SBIRQ)==1)?2:0;break;\r
+   case 'D': check|=(sscanf(s+1,"%d",&SBDMA)==1)?4:0;break;\r
+   case 'H': check|=(sscanf(s+1,"%d",&SBDMA16)==1)?8:0;break;\r
+  }\r
+  s++;\r
+ }\r
\r
+ if((check^7)&7 || SBDMA>=4 || (SBDMA16<=4 && check&8) || SBIRQ>15)\r
+ {\r
+  puts(" Invalid or incomplete BLASTER environment variable.");\r
+  return(0);\r
+ }\r
+ if(!(check&8))\r
+  format=0;\r
+ return(1);\r
+}\r
+\r
+static int ResetDSP(void)\r
+{\r
+ uint8 b;\r
+\r
+ outportb(SBPort+0x6,0x1);\r
+ delay(10);\r
+ outportb(SBPort+0x6,0x0);\r
+ delay(10);\r
+\r
+ if(ReadDSP(&b))\r
+  if(b==0xAA)\r
+   return(1); \r
+ return(0);\r
+}\r
+\r
+static int GetDSPVersion(void)\r
+{\r
+ int ret;\r
+ uint8 t;\r
+\r
+ if(!WriteDSP(0xE1))\r
+  return(0);\r
+ if(!ReadDSP(&t))\r
+  return(0);\r
+ ret=t<<8;\r
+ if(!ReadDSP(&t))\r
+  return(0);\r
+ ret|=t;\r
+\r
+ return(ret);\r
+}\r
+\r
+static void KillDMABuffer(void)\r
+{\r
+ __dpmi_free_dos_memory(LMSelector);\r
+}\r
+\r
+static int MakeDMABuffer(void)\r
+{\r
+ uint32 size;\r
+ int32 tmp;\r
+\r
+ size=fragsize*2;       /* Two buffers in the DMA buffer. */\r
+ size<<=format;         /* Twice the size for 16-bit than for 8-bit. */\r
+\r
+ size<<=1;              /* Double the size in case the first 2 buffers\r
+                           cross a 64KB or 128KB page boundary.\r
+                        */\r
+ size=(size+15)>>4;     /* Convert to paragraphs */\r
+\r
+ if((tmp=__dpmi_allocate_dos_memory(size,&LMSelector))<0)\r
+  return(0);\r
+\r
+ LMBuffer=tmp<<=4;\r
+\r
+ if(format)   /* Check for and fix 128KB page boundary crossing. */\r
+ {\r
+  if((LMBuffer&0x20000) != ((LMBuffer+fragsize*2*2-1)&0x20000))\r
+   LMBuffer+=fragsize*2*2;\r
+ }\r
+ else   /* Check for and fix 64KB page boundary crossing. */\r
+ {\r
+  if((LMBuffer&0x10000) != ((LMBuffer+fragsize*2-1)&0x10000))\r
+   LMBuffer+=fragsize*2;\r
+ }\r
+\r
+ DOSMemSet(LMBuffer, format?0:128, (fragsize*2)<<format);\r
+\r
+ return(1);\r
+}\r
+\r
+static void ProgramDMA(void)\r
+{\r
+ static int PPorts[8]={0x87,0x83,0x81,0x82,0,0x8b,0x89,0x8a};\r
+ uint32 tmp;\r
+\r
+ if(format)\r
+ {\r
+  outportb(0xd4,(SBDMA16&0x3)|0x4);\r
+  outportb(0xd8,0x0);\r
+  outportb(0xd6,(SBDMA16&0x3)|0x58);\r
+  tmp=((SBDMA16&3)<<2)+0xC2;\r
+ }\r
+ else\r
+ {\r
+  outportb(0xA,SBDMA|0x4);\r
+  outportb(0xC,0x0);\r
+  outportb(0xB,SBDMA|0x58);\r
+  tmp=(SBDMA<<1)+1;\r
+ }\r
+\r
+ /* Size of entire buffer. */\r
+ outportb(tmp,(fragsize*2-1));\r
+ outportb(tmp,(fragsize*2-1)>>8);\r
+\r
+ /* Page of buffer. */\r
+ outportb(PPorts[format?SBDMA16:SBDMA],LMBuffer>>16);\r
+\r
+ /* Offset of buffer within page. */\r
+ if(format)\r
+  tmp=((SBDMA16&3)<<2)+0xc0;\r
+ else\r
+  tmp=SBDMA<<1;\r
+\r
+ outportb(tmp,(LMBuffer>>format));\r
+ outportb(tmp,(LMBuffer>>(8+format)));\r
+}\r
+\r
+int InitSB(int Rate, int bittage)\r
+{\r
+ hsmode=hbusy=0;\r
+ whichbuf=1;\r
+ puts("Initializing Sound Blaster...");\r
+\r
+ format=bittage?1:0;\r
+ frags=8;\r
+\r
+ if(Rate<=11025)\r
+  fragsize=1<<5;\r
+ else if(Rate<=22050)\r
+  fragsize=1<<6;\r
+ else\r
+  fragsize=1<<7;\r
+\r
+ fragtotal=frags*fragsize;\r
+ WaveBuffer=malloc(fragtotal<<format);\r
+\r
+ if(format)\r
+  memset(WaveBuffer,0,fragtotal*2);\r
+ else\r
+  memset(WaveBuffer,128,fragtotal);\r
+\r
+ WritePtr=ReadPtr=0;\r
+\r
+ if((Rate<8192) || (Rate>65535))\r
+ {\r
+  printf(" Unsupported playback rate: %d samples per second\n",Rate);\r
+  return(0);\r
+ }\r
+\r
+ if(!GetBLASTER())\r
+  return(0);\r
\r
+ /* Disable IRQ line in PIC0 or PIC1 */\r
+ if(SBIRQ>7)\r
+ {\r
+  PICMask=inportb(0xA1);\r
+  outportb(0xA1,PICMask|(1<<(SBIRQ&7)));\r
+ }\r
+ else\r
+ {\r
+  PICMask=inportb(0x21);\r
+  outportb(0x21,PICMask|(1<<SBIRQ));\r
+ }\r
+ if(!ResetDSP())\r
+ {\r
+  puts(" Error resetting the DSP.");\r
+  return(0);\r
+ }\r
\r
+ if(!(DSPV=GetDSPVersion()))\r
+ {\r
+  puts(" Error getting the DSP version.");\r
+  return(0);\r
+ }\r
+\r
+ printf(" DSP Version: %d.%d\n",DSPV>>8,DSPV&0xFF);\r
+ if(DSPV<0x201)\r
+ {\r
+  printf(" DSP version number is too low.\n");\r
+  return(0);\r
+ }\r
+\r
+ if(DSPV<0x400)\r
+  format=0;\r
+ if(!MakeDMABuffer())\r
+ {\r
+  puts(" Error creating low-memory DMA buffer.");\r
+  return(0);\r
+ }\r
+\r
+ if(SBIRQ>7) IVector=SBIRQ+0x68;\r
+ else IVector=SBIRQ+0x8;\r
+\r
+ if(!SetVectors())\r
+ {\r
+  puts(" Error setting interrupt vectors.");\r
+  KillDMABuffer();\r
+  return(0);\r
+ }\r
+\r
+ /* Reenable IRQ line. */\r
+ if(SBIRQ>7)\r
+  outportb(0xA1,PICMask&(~(1<<(SBIRQ&7))));\r
+ else\r
+  outportb(0x21,PICMask&(~(1<<SBIRQ)));\r
+\r
+ ProgramDMA();\r
+\r
+ /* Note that the speaker must always be turned on before the mode transfer\r
+    byte is sent to the DSP if we're going into high-speed mode, since\r
+    a real Sound Blaster(at least my SBPro) won't accept DSP commands(except\r
+    for the reset "command") after it goes into high-speed mode.\r
+ */\r
+ WriteDSP(0xD1);                 // Turn on DAC speaker\r
+\r
+ if(DSPV>=0x400)\r
+ {\r
+  WriteDSP(0x41);                // Set sampling rate\r
+  WriteDSP(Rate>>8);             // High byte\r
+  WriteDSP(Rate&0xFF);           // Low byte\r
+  if(!format)\r
+  {\r
+   WriteDSP(0xC6);                // 8-bit output\r
+   WriteDSP(0x00);                // 8-bit mono unsigned PCM\r
+  }\r
+  else\r
+  {\r
+   WriteDSP(0xB6);                // 16-bit output\r
+   WriteDSP(0x10);                // 16-bit mono signed PCM\r
+  }\r
+  WriteDSP((fragsize-1)&0xFF);// Low byte of size\r
+  WriteDSP((fragsize-1)>>8);  // High byte of size\r
+ }\r
+ else\r
+ {\r
+  int tc,command;\r
+  if(Rate>22050)\r
+  {\r
+   tc=(65536-(256000000/Rate))>>8;\r
+   Rate=256000000/(65536-(tc<<8));\r
+   command=0x90;                  // High-speed auto-initialize DMA mode transfer\r
+   hsmode=1;\r
+  }\r
+  else\r
+  {\r
+   tc=256-(1000000/Rate);\r
+   Rate=1000000/(256-tc);\r
+   command=0x1c;                  // Auto-initialize DMA mode transfer\r
+  }\r
+  WriteDSP(0x40);       // Set DSP time constant\r
+  WriteDSP(tc);         // time constant\r
+  WriteDSP(0x48);       // Set DSP block transfer size\r
+  WriteDSP((fragsize-1)&0xFF);\r
+  WriteDSP((fragsize-1)>>8);\r
+\r
+  WriteDSP(command);\r
+ }\r
+\r
+ /* Enable DMA */\r
+ if(format)\r
+  outportb(0xd4,SBDMA16&3);\r
+ else\r
+  outportb(0xa,SBDMA);\r
+\r
+ printf(" %d hz, %d-bit\n",Rate,8<<format);\r
+ return(Rate);\r
+}\r
+\r
+extern volatile int soundjoyer;\r
+extern volatile int soundjoyeron;\r
+static int ssilence=0;\r
+\r
+static void SBIRQHandler(_go32_dpmi_registers *r)\r
+{\r
+        uint32 *src;\r
+       uint32 dest;\r
+       int32 x;\r
+\r
+\r
+        if(format)\r
+        {\r
+         uint8 status;\r
+\r
+         outportb(SBPort+4,0x82);\r
+         status=inportb(SBPort+5);\r
+         if(status&2)\r
+          inportb(SBPort+0x0F);\r
+        }\r
+        else\r
+         inportb(SBPort+0x0E);\r
+\r
+        #ifdef OLD\r
+        {\r
+         uint8 status;\r
+\r
+         outportb(SBPort+4,0x82);\r
+         status=inportb(SBPort+5);\r
+         if(status&1)\r
+          inportb(SBPort+0x0E);\r
+         else if(status&2)\r
+          inportb(SBPort+0x0F);\r
+         else\r
+          return;               // Mysterious interrupt source!  *eerie music*\r
+        }         \r
+        #endif\r
+\r
+        if(hbusy)\r
+        {\r
+         outportb(0x20,0x20);\r
+         if(SBIRQ>=8)\r
+          outportb(0xA0,0x20);\r
+         whichbuf^=1;         \r
+         return;\r
+        }\r
+        hbusy=1;\r
+\r
+        {\r
+         /* This code seems to fail on many SB emulators.  Bah.\r
+            SCREW SB EMULATORS. ^_^ */\r
+         uint32 count;\r
+        uint32 block;\r
+        uint32 port;\r
+       \r
+         if(format)\r
+          port=((SBDMA16&3)*4)+0xc2;\r
+         else\r
+          port=(SBDMA*2)+1;\r
+\r
+         count=inportb(port);\r
+         count|=inportb(port)<<8;\r
+\r
+         if(count>=fragsize)\r
+          block=1;\r
+         else\r
+          block=0;\r
+         dest=LMBuffer+((block*fragsize)<<format);\r
+\r
+         #ifdef MOO\r
+         dest=LMBuffer+((whichbuf*fragsize)<<format);\r
+         whichbuf^=1;\r
+         #endif\r
+        }\r
+\r
+        _farsetsel(_dos_ds);\r
+\r
+        src=(uint32 *)(WaveBuffer+(ReadPtr<<format));\r
+\r
+       if(ssilence)\r
+       {\r
+        uint32 sby;\r
+        if(format) sby=0;      /* 16-bit silence.  */\r
+        else sby=0x80808080;   /* 8-bit silence.   */\r
+\r
+         for(x=(fragsize<<format)>>2;x;x--,dest+=4)\r
+         {\r
+          _farnspokel(dest,sby);\r
+         }\r
+       }\r
+       else\r
+       {\r
+         for(x=(fragsize<<format)>>2;x;x--,dest+=4,src++)\r
+         {\r
+          _farnspokel(dest,*src);\r
+         }\r
+         ReadPtr=(ReadPtr+fragsize)&(fragtotal-1);\r
+       }\r
+\r
+        if(soundjoyeron)\r
+        {\r
+         static int coot=0;\r
+         if(!coot)\r
+         {\r
+          UpdateJoyData();\r
+          soundjoyer=1;\r
+         }\r
+         coot=(coot+1)&3;\r
+        }\r
+        hbusy=0;\r
+        outportb(0x20,0x20);\r
+        if(SBIRQ>=8)        \r
+         outportb(0xA0,0x20);\r
+}\r
+\r
+void SilenceSound(int s)\r
+{\r
+ ssilence=s;\r
+}\r
+\r
+void WriteSBSound(int32 *Buffer, int Count, int NoBlocking)\r
+{\r
+ int x;\r
+\r
+ if(!format)\r
+ {\r
+   for(x=0;x<Count;x++)\r
+   {\r
+    while(WritePtr==ReadPtr)\r
+     if(NoBlocking)\r
+      return;\r
+    WaveBuffer[WritePtr]=(uint8)((Buffer[x])>>8)^128;\r
+    WritePtr=(WritePtr+1)&(fragtotal-1);\r
+   }\r
+ }     \r
+ else // 16 bit\r
+ {\r
+   for(x=0;x<Count;x++)\r
+   {\r
+    while(WritePtr==ReadPtr)\r
+     if(NoBlocking)\r
+      return;\r
+    ((int16 *)WaveBuffer)[WritePtr]=Buffer[x];\r
+    WritePtr=(WritePtr+1)&(fragtotal-1);\r
+   }\r
+ }\r
+}\r
+\r
+void KillSB(void)\r
+{\r
+ if(hsmode)\r
+  ResetDSP();                   /* High-speed mode requires a DSP reset. */\r
+ else\r
+  WriteDSP(format?0xD9:0xDA);    /* Exit auto-init DMA transfer mode. */ \r
+ WriteDSP(0xD3);                /* Turn speaker off. */\r
+\r
+ outportb((SBIRQ>7)?0xA1:0x21,PICMask|(1<<(SBIRQ&7)));\r
+ ResetVectors();\r
+ outportb((SBIRQ>7)?0xA1:0x21,PICMask);\r
+ KillDMABuffer();\r
+}\r
diff --git a/drivers/cli/dos-sound.h b/drivers/cli/dos-sound.h
new file mode 100644 (file)
index 0000000..7f5185a
--- /dev/null
@@ -0,0 +1,26 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 2002 Ben Parnell\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+int InitSB(int Rate, int bittage);\r
+void KillSB(void);\r
+\r
+void WriteSBSound(int32 *Buffer, int Count, int NoBlocking);\r
+void SilenceSound(int s);\r
+\r
diff --git a/drivers/cli/dos-video.c b/drivers/cli/dos-video.c
new file mode 100644 (file)
index 0000000..574c824
--- /dev/null
@@ -0,0 +1,246 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 1998 \Firebug\\r
+ *  Copyright (C) 2002 Ben Parnell\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <dpmi.h>\r
+#include <sys/farptr.h>\r
+#include <go32.h>\r
+#include <pc.h>\r
+\r
+#include "dos.h"\r
+#include "dos-video.h"\r
+\r
+#define TEXT            3\r
+#define G320x200x256    0x13\r
+\r
+static void vga_waitretrace(void)\r
+{ \r
+ while(inp(0x3da)&0x8); \r
+ while(!(inp(0x3da)&0x8));\r
+}\r
+\r
+static void vga_setmode(int mode)\r
+{\r
+ __dpmi_regs regs;\r
+\r
+ memset(&regs,0,sizeof(regs));\r
+ regs.x.ax=mode;\r
+\r
+ __dpmi_int(0x10,&regs);\r
+}\r
+\r
+void vga_setpalette(int i, int r, int g, int b)\r
+{ \r
+ outp(0x3c8,i);\r
+ outp(0x3c9,r);\r
+ outp(0x3c9,g);\r
+ outp(0x3c9,b); \r
+}\r
+\r
+int FCEUDvmode=1;\r
+\r
+static int vidready=0;\r
+\r
+/*      Part of the VGA low-level mass register setting code derived from\r
+       code by \Firebug\.\r
+*/\r
+\r
+#include "vgatweak.c"\r
+\r
+void SetBorder(void)\r
+{\r
+ inportb(0x3da);\r
+ outportb(0x3c0,(0x11|0x20));\r
+ outportb(0x3c0,0x80);\r
+}\r
+\r
+void TweakVGA(int VGAMode)\r
+{\r
+  int I;\r
+  \r
+  vga_waitretrace();\r
+\r
+  outportb(0x3C8,0x00);\r
+  for(I=0;I<768;I++) outportb(0x3C9,0x00);\r
+\r
+  outportb(0x3D4,0x11);\r
+  I=inportb(0x3D5)&0x7F;\r
+  outportb(0x3D4,0x11);\r
+  outportb(0x3D5,I);\r
+\r
+  switch(VGAMode)\r
+  {\r
+    case 1:  for(I=0;I<25;I++) VGAPortSet(v256x240[I]);break;\r
+    case 2:  for(I=0;I<25;I++) VGAPortSet(v256x256[I]);break;\r
+    case 3:  for(I=0;I<25;I++) VGAPortSet(v256x256S[I]);break;\r
+    case 6:  for(I=0;I<25;I++) VGAPortSet(v256x224S[I]);break;\r
+    case 8:  for(I=0;I<25;I++) VGAPortSet(v256x224_103[I]);break;\r
+    default: break;\r
+  }\r
+\r
+  outportb(0x3da,0);\r
+}\r
+\r
+\r
+static uint8 palettedbr[256],palettedbg[256],palettedbb[256];\r
+\r
+static void FlushPalette(void)\r
+{\r
+ int x;\r
+ for(x=0;x<256;x++)\r
+ {\r
+  int z=x;\r
+  vga_setpalette(z,palettedbr[x]>>2,palettedbg[x]>>2,palettedbb[x]>>2);\r
+ }\r
+}\r
+\r
+void FCEUD_SetPalette(uint8 index, uint8 r, uint8 g, uint8 b)\r
+{\r
+  palettedbr[index]=r;\r
+  palettedbg[index]=g;\r
+  palettedbb[index]=b;\r
+  if(vidready)\r
+  {\r
+   vga_setpalette(index,r>>2,g>>2,b>>2);\r
+  }\r
+}\r
+\r
+\r
+void FCEUD_GetPalette(uint8 i, uint8 *r, uint8 *g, uint8 *b)\r
+{\r
+ *r=palettedbr[i];\r
+ *g=palettedbg[i];\r
+ *b=palettedbb[i];\r
+}\r
+\r
+static uint32 ScreenLoc;\r
+\r
+int InitVideo(void)\r
+{\r
+ vidready=0;\r
+ switch(FCEUDvmode)\r
+ {\r
+  default:\r
+  case 1:\r
+  case 2:\r
+  case 3:\r
+  case 6:\r
+  case 8:\r
+         vga_setmode(G320x200x256);\r
+        vidready|=1;\r
+         ScreenLoc=0xa0000;\r
+         TweakVGA(FCEUDvmode);\r
+         SetBorder();\r
+         DOSMemSet(ScreenLoc, 128, 256*256);\r
+         break;\r
+ }\r
+ vidready|=2;\r
+ FlushPalette();\r
+ return 1;\r
+}\r
+\r
+void KillVideo(void)\r
+{\r
+ if(vidready)\r
+ {\r
+  vga_setmode(TEXT);\r
+  vidready=0;\r
+ }\r
+}\r
+void LockConsole(void){}\r
+void UnlockConsole(void){}\r
+void BlitScreen(uint8 *XBuf)\r
+{\r
+ uint32 dest;\r
+ int tlines;\r
+\r
+ if(eoptions&4 && !NoWaiting)\r
+  vga_waitretrace();\r
+\r
+ tlines=erendline-srendline+1;\r
+\r
+ dest=ScreenLoc;\r
+\r
+ switch(FCEUDvmode)\r
+ {\r
+  case 1:dest+=(((240-tlines)>>1)<<8);break;\r
+  case 2:\r
+  case 3:dest+=(((256-tlines)>>1)<<8);break;\r
+  case 4:\r
+  case 5:dest+=(((240-tlines)>>1)*640+((640-512)>>1));break;\r
+  case 8:\r
+  case 6:if(tlines>224) tlines=224;dest+=(((224-tlines)>>1)<<8);break;\r
+ }\r
\r
+ XBuf+=(srendline<<8)+(srendline<<4);\r
+           \r
+  _farsetsel(_dos_ds);\r
+ if(eoptions&DO_CLIPSIDES)\r
+ {\r
+  asm volatile(     \r
+     "agoop1:\n\t"\r
+     "movl $30,%%eax\n\t"\r
+     "agoop2:\n\t"\r
+     "movl (%%esi),%%edx\n\t"\r
+     "movl 4(%%esi),%%ecx\n\t"\r
+     ".byte 0x64 \n\t"\r
+     "movl %%edx,(%%edi)\n\t"\r
+     ".byte 0x64 \n\t"\r
+     "movl %%ecx,4(%%edi)\n\t"\r
+     "addl $8,%%esi\n\t"\r
+     "addl $8,%%edi\n\t"\r
+     "decl %%eax\n\t"\r
+     "jne agoop2\n\t"\r
+     "addl $32,%%esi\n\t"\r
+     "addl $16,%%edi\n\t"\r
+     "decb %%bl\n\t"\r
+     "jne agoop1\n\t"\r
+     :\r
+     : "S" (XBuf+8), "D" (dest+8), "b" (tlines)\r
+     : "%eax","%cc","%edx","%ecx" );\r
+ }\r
+ else\r
+ {\r
+  asm volatile(     \r
+     "goop1:\n\t"\r
+     "movl $32,%%eax\n\t"\r
+     "goop2:\n\t"\r
+     "movl (%%esi),%%edx\n\t"\r
+     "movl 4(%%esi),%%ecx\n\t"\r
+     ".byte 0x64 \n\t"\r
+     "movl %%edx,(%%edi)\n\t"\r
+     ".byte 0x64 \n\t"\r
+     "movl %%ecx,4(%%edi)\n\t"\r
+     "addl $8,%%esi\n\t"\r
+     "addl $8,%%edi\n\t"\r
+     "decl %%eax\n\t"\r
+     "jne goop2\n\t"\r
+     "addl $16,%%esi\n\t"\r
+     "decb %%bl\n\t"\r
+     "jne goop1\n\t"\r
+     :\r
+     : "S" (XBuf), "D" (dest), "b" (tlines)\r
+     : "%eax","%cc","%edx","%ecx" );\r
+ }\r
+}\r
+\r
+\r
diff --git a/drivers/cli/dos-video.h b/drivers/cli/dos-video.h
new file mode 100644 (file)
index 0000000..ee09b51
--- /dev/null
@@ -0,0 +1,22 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 2002 Ben Parnell\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+extern int FCEUDvmode;\r
+\r
diff --git a/drivers/cli/dos.c b/drivers/cli/dos.c
new file mode 100644 (file)
index 0000000..8ba1578
--- /dev/null
@@ -0,0 +1,128 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <crt0.h>
+#include <sys/farptr.h>
+#include <go32.h>
+
+#include "dos.h"
+#include "dos-joystick.h"
+#include "dos-video.h"
+#include "dos-sound.h"
+#include "../common/args.h"
+#include "../common/config.h"
+
+/* _CRT0_FLAG_LOCK_MEMORY might not always result in all memory being locked.
+   Bummer.  I'll add code to explicitly lock the data touched by the sound
+   interrupt handler(and the handler itself), if necessary(though that might
+   be tricky...).  I'll also to cover the data the keyboard
+   interrupt handler touches.
+*/
+
+int _crt0_startup_flags = _CRT0_FLAG_FILL_SBRK_MEMORY | _CRT0_FLAG_LOCK_MEMORY | _CRT0_FLAG_USE_DOS_SLASHES;
+
+static int f8bit=0;
+int soundo=44100;
+int doptions=0;
+
+
+CFGSTRUCT DriverConfig[]={
+        NAC("sound",soundo),
+        AC(doptions),
+        AC(f8bit),
+        AC(FCEUDvmode),
+        NACA("joybmap",joyBMap),
+        AC(joy),
+        ENDCFGSTRUCT
+};
+
+char *DriverUsage=
+"-vmode x        Select video mode(all are 8 bpp).\n\
+                 1 = 256x240                 6 = 256x224(with scanlines)\n\
+                 2 = 256x256                 8 = 256x224\n\
+                 3 = 256x256(with scanlines)\n\
+-vsync x        Wait for the screen's vertical retrace before updating the\n\
+                screen.  Refer to the documentation for caveats.\n\
+                 0 = Disabled.\n\
+                 1 = Enabled.\n\
+-sound x        Sound.\n\
+                 0 = Disabled.\n\
+                 Otherwise, x = playback rate.\n\
+-f8bit x        Force 8-bit sound.\n\
+                 0 = Disabled.\n\
+                 1 = Enabled.\n\
+-joy x          Joystick mapped to virtual joystick x(1-4).\n\
+                 0 = Disabled, reset configuration.\n\
+                 1 = Enabled.";
+
+ARGPSTRUCT DriverArgs[]={
+         {"-vmode",0,&FCEUDvmode,0},
+         {"-sound",0,&soundo,0},
+         {"-f8bit",0,&f8bit,0},
+         {"-joy",0,&joy,0},
+         {"-vsync",0,&eoptions,0x8004},
+         {0,0,0,0}
+};
+
+void DoDriverArgs(void)
+{
+        if(!joy) memset(joyBMap,0,4);
+}
+
+int InitSound(void)
+{
+ if(soundo)
+ {
+  if(soundo==1)
+   soundo=44100;
+  soundo=InitSB(soundo,f8bit?0:1);
+  FCEUI_Sound(soundo);
+ }
+ return(soundo?1:0);
+}
+
+void WriteSound(int32 *Buffer, int Count, int NoWaiting)
+{
+ WriteSBSound(Buffer,Count,NoWaiting);
+}
+
+void KillSound(void)
+{
+ if(soundo)
+  KillSB();
+}
+
+void DOSMemSet(uint32 A, uint8 V, uint32 count)
+{
+ uint32 x;
+
+ _farsetsel(_dos_ds);
+ for(x=0;x<count;x++)
+  _farnspokeb(A+x,V);
+}
+
+static char *arg0;
+void GetBaseDirectory(char *BaseDirectory)
+{
+ int x=0;
+
+ if(arg0)
+  for(x=strlen(arg0);x>=0;x--)
+  {
+   if(arg0[x]=='/' || arg0[x]=='\\')
+   {
+    strncpy(BaseDirectory,arg0,x);
+    break;
+   }
+  }
+
+ BaseDirectory[x]=0;
+}
+
+int main(int argc, char *argv[])
+{
+        puts("\nStarting FCE Ultra "VERSION_STRING"...\n");
+       arg0=argv[0];
+        return(CLImain(argc,argv));
+}
+
diff --git a/drivers/cli/dos.h b/drivers/cli/dos.h
new file mode 100644 (file)
index 0000000..05bc8e5
--- /dev/null
@@ -0,0 +1,28 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 2002 Ben Parnell\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+#include "../../driver.h"\r
+#include "main.h"\r
+\r
+extern int eoptions;\r
+extern int soundo;\r
+void DOSMemSet(uint32 A, uint8 V, uint32 count);\r
+#define DO_CLIPSIDES    1\r
+\r
diff --git a/drivers/cli/input.c b/drivers/cli/input.c
new file mode 100644 (file)
index 0000000..b946c5b
--- /dev/null
@@ -0,0 +1,340 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#define JOY_A   1
+#define JOY_B   2
+#define JOY_SELECT      4
+#define JOY_START       8
+#define JOY_UP  0x10
+#define JOY_DOWN        0x20
+#define JOY_LEFT        0x40
+#define JOY_RIGHT       0x80
+
+static void UpdateFKB(void);
+
+/* UsrInputType[] is user-specified.  InputType[] is current
+       (game loading can override user settings) 
+*/
+static int UsrInputType[2]={SI_GAMEPAD,SI_GAMEPAD};
+static int InputType[2];
+
+static int UsrInputTypeFC={SI_NONE};
+static int InputTypeFC;
+
+static uint32 JSreturn;
+int NoWaiting=0;
+
+static void DoCheatSeq(void)
+{
+ #if defined(DOS) || defined(SDL)
+ if(inited&1)
+  SilenceSound(1);
+ #endif
+ KillKeyboard();
+ KillVideo();
+
+ DoConsoleCheatConfig();
+ InitVideo();
+ InitKeyboard();
+ #if defined(DOS) || defined(SDL)
+ if(inited&1)
+  SilenceSound(0);
+ #endif
+}
+
+#include "keyscan.h"
+static char *keys;
+static int DIPS=0;
+static uint8 keyonce[MK_COUNT];
+#define KEY(__a) keys[MK(__a)]
+#define keyonly(__a,__z) {if(KEY(__a)){if(!keyonce[MK(__a)]) {keyonce[MK(__a)]=1;__z}}else{keyonce[MK(__a)]=0;}}
+static int JoySwap=0;
+static int cidisabled=0;
+static int KeyboardUpdate(void)
+{
+
+ if(!UpdateKeyboard())
+   if(keys)
+    return 0;
+
+  keys=GetKeyboard(); 
+
+  if(InputTypeFC==SIFC_FKB)
+  {
+   keyonly(SCROLLLOCK,cidisabled^=1;
+    FCEUI_DispMessage("Family Keyboard %sabled.",cidisabled?"en":"dis");)
+   #ifdef SDL
+   SDL_WM_GrabInput(cidisabled?SDL_GRAB_ON:SDL_GRAB_OFF);
+   #endif
+   if(cidisabled) return(1);
+  }
+  #ifdef SVGALIB
+  keyonly(F3,LockConsole();)  
+  keyonly(F4,UnlockConsole();)
+  #elif SDL
+  keyonly(F4,ToggleFS();)
+  #endif
+  NoWaiting&=~1;
+  if(KEY(GRAVE))
+   NoWaiting|=1;
+
+  if(gametype==GIT_FDS)
+  {
+   keyonly(S,DriverInterface(DES_FDSSELECT,0);)
+   keyonly(I,DriverInterface(DES_FDSINSERT,0);)
+   keyonly(E,DriverInterface(DES_FDSEJECT,0);)
+  }
+
+ keyonly(F9,FCEUI_SaveSnapshot();)
+ if(gametype!=GIT_NSF)
+ {
+  keyonly(F2,DoCheatSeq();)
+  keyonly(F5,FCEUI_SaveState();)
+  keyonly(F7,FCEUI_LoadState();)
+ }
+ else
+ {
+  keyonly(CURSORLEFT,DriverInterface(DES_NSFDEC,0);)
+  keyonly(CURSORRIGHT,DriverInterface(DES_NSFINC,0);)
+  if( KEY(ENTER)) DriverInterface(DES_NSFRES,0);
+  if( KEY(CURSORUP)) DriverInterface(DES_NSFINC,0);
+  if( KEY(CURSORDOWN)) DriverInterface(DES_NSFDEC,0);
+ }
+
+ keyonly(F10,DriverInterface(DES_RESET,0);)
+ keyonly(F11,DriverInterface(DES_POWER,0);)
+ if(KEY(F12) || KEY(ESCAPE)) FCEUI_CloseGame();
+
+ if(gametype==GIT_VSUNI)
+ {
+   keyonly(C,DriverInterface(DES_VSUNICOIN,0);)
+   keyonly(V,DIPS^=1;DriverInterface(DES_VSUNITOGGLEDIPVIEW,0);)
+   if(!(DIPS&1)) goto DIPSless;
+   keyonly(1,DriverInterface(DES_VSUNIDIPSET,(void *)1);)
+   keyonly(2,DriverInterface(DES_VSUNIDIPSET,(void *)2);)
+   keyonly(3,DriverInterface(DES_VSUNIDIPSET,(void *)3);)
+   keyonly(4,DriverInterface(DES_VSUNIDIPSET,(void *)4);)
+   keyonly(5,DriverInterface(DES_VSUNIDIPSET,(void *)5);)
+   keyonly(6,DriverInterface(DES_VSUNIDIPSET,(void *)6);)
+   keyonly(7,DriverInterface(DES_VSUNIDIPSET,(void *)7);)
+   keyonly(8,DriverInterface(DES_VSUNIDIPSET,(void *)8);)
+ }
+ else
+ {
+  keyonly(H,DriverInterface(DES_NTSCSELHUE,0);)
+  keyonly(T,DriverInterface(DES_NTSCSELTINT,0);)
+  if(KEY(KP_MINUS) || KEY(MINUS)) DriverInterface(DES_NTSCDEC,0);
+  if(KEY(KP_PLUS) || KEY(EQUAL)) DriverInterface(DES_NTSCINC,0);
+
+  DIPSless:
+  keyonly(0,FCEUI_SelectState(0);)
+  keyonly(1,FCEUI_SelectState(1);)
+  keyonly(2,FCEUI_SelectState(2);)
+  keyonly(3,FCEUI_SelectState(3);)
+  keyonly(4,FCEUI_SelectState(4);)
+  keyonly(5,FCEUI_SelectState(5);)
+  keyonly(6,FCEUI_SelectState(6);)
+  keyonly(7,FCEUI_SelectState(7);)
+  keyonly(8,FCEUI_SelectState(8);)
+  keyonly(9,FCEUI_SelectState(9);)
+ }
+ return 1;
+}
+
+static uint32 KeyboardDodo(void)
+{
+ uint32 JS=0;
+
+ if(gametype!=GIT_NSF)
+ {
+  int x,y;
+  x=y=0;
+  keyonly(CAPSLOCK,
+                   {
+                    char tmp[64];
+                    JoySwap=(JoySwap+8)%32;
+                    sprintf(tmp,"Joystick %d selected.",(JoySwap>>3)+1);
+                    FCEUI_DispMessage(tmp);
+                   })
+
+  if(KEY(LEFTALT) || KEY(X))        JS|=JOY_A<<JoySwap;
+  if(KEY(LEFTCONTROL) || KEY(SPACE) || KEY(Z) ) JS |=JOY_B<<JoySwap;
+  if(KEY(ENTER))       JS |= JOY_START<<JoySwap;
+  if(KEY(TAB))         JS |= JOY_SELECT<<JoySwap;
+  if(KEY(CURSORDOWN))  y|= JOY_DOWN;
+  if(KEY(CURSORUP))    y|= JOY_UP;
+  if(KEY(CURSORLEFT))  x|= JOY_LEFT;
+  if(KEY(CURSORRIGHT)) x|= JOY_RIGHT;
+  if(y!=(JOY_DOWN|JOY_UP)) JS|=y<<JoySwap;
+  if(x!=(JOY_LEFT|JOY_RIGHT)) JS|=x<<JoySwap;
+ }
+ return JS;
+}
+
+static int powerpadsc[2][12]={
+                              {
+                               MK(O),MK(P),MK(BRACKET_LEFT),
+                               MK(BRACKET_RIGHT),MK(K),MK(L),MK(SEMICOLON),
+                               MK(APOSTROPHE),
+                               MK(M),MK(COMMA),MK(PERIOD),MK(SLASH)
+                              },
+                              {
+                               MK(O),MK(P),MK(BRACKET_LEFT),
+                               MK(BRACKET_RIGHT),MK(K),MK(L),MK(SEMICOLON),
+                                MK(APOSTROPHE),
+                               MK(M),MK(COMMA),MK(PERIOD),MK(SLASH)
+                              }
+                             };
+
+static uint32 powerpadbuf[2];
+static int powerpadside=0;
+
+static uint32 UpdatePPadData(int w)
+{
+ static const char shifttableA[12]={8,9,0,1,11,7,4,2,10,6,5,3};
+ static const char shifttableB[12]={1,0,9,8,2,4,7,11,3,5,6,10};
+ uint32 r=0;
+ int *ppadtsc=powerpadsc[w];
+ int x;
+
+ if(powerpadside&(1<<w))
+ {
+  for(x=0;x<12;x++)
+   if(keys[ppadtsc[x]]) r|=1<<shifttableA[x];
+ }
+ else
+ {
+  for(x=0;x<12;x++)
+   if(keys[ppadtsc[x]]) r|=1<<shifttableB[x];
+ }
+ return r;
+}
+
+static uint32 MouseData[3];
+static uint8 fkbkeys[0x48];
+
+void FCEUD_UpdateInput(void)
+{
+  int x;
+  int t=0;
+  static uint32 KeyBJS=0;
+  uint32 JS;
+  int b;
+
+  b=KeyboardUpdate();
+
+  for(x=0;x<2;x++)
+   switch(InputType[x])
+   {
+    case SI_GAMEPAD:t|=1;break;
+    case SI_ARKANOID:t|=2;break;
+    case SI_ZAPPER:t|=2;break;
+    case SI_POWERPAD:powerpadbuf[x]=UpdatePPadData(x);break;
+   }
+
+  switch(InputTypeFC)
+  {
+   case SIFC_ARKANOID:t|=2;break;
+   case SIFC_SHADOW:t|=2;break;
+   case SIFC_FKB:if(cidisabled) UpdateFKB();break;
+  }
+
+  if(t&1)
+  {
+   if(b)
+    KeyBJS=KeyboardDodo();
+   JS=KeyBJS;
+   JS|=(uint32)GetJSOr();
+   JSreturn=(JS&0xFF000000)|(JS&0xFF)|((JS&0xFF0000)>>8)|((JS&0xFF00)<<8);
+  }
+  if(t&2)
+   GetMouseData(MouseData);
+}
+
+static void InitOtherInput(void)
+{
+   void *InputDPtr;
+
+   int t;
+   int x;
+   int attrib;
+
+   for(t=0,x=0;x<2;x++)
+   {
+    attrib=0;
+    InputDPtr=0;
+    switch(InputType[x])
+    {
+     case SI_POWERPAD:InputDPtr=&powerpadbuf[x];break;
+     case SI_GAMEPAD:InputDPtr=((uint8 *)&JSreturn)+(x<<1);break;     
+     case SI_ARKANOID:InputDPtr=MouseData;t|=1;break;
+     case SI_ZAPPER:InputDPtr=MouseData;
+                                t|=1;
+                                attrib=1;
+                                break;
+    }
+    FCEUI_SetInput(x,InputType[x],InputDPtr,attrib);
+   }
+
+   attrib=0;
+   InputDPtr=0;
+   switch(InputTypeFC)
+   {
+    case SIFC_SHADOW:InputDPtr=MouseData;t|=1;attrib=1;break;
+    case SIFC_ARKANOID:InputDPtr=MouseData;t|=1;break;
+    case SIFC_FKB:InputDPtr=fkbkeys;break;
+   }
+
+   FCEUI_SetInputFC(InputTypeFC,InputDPtr,attrib);
+   FCEUI_DisableFourScore(eoptions&EO_NOFOURSCORE);
+
+   if(t && !(inited&16)) 
+   {
+    InitMouse();
+    inited|=16;
+   }
+}
+
+int fkbmap[0x48]=
+{
+ MK(F1),MK(F2),MK(F3),MK(F4),MK(F5),MK(F6),MK(F7),MK(F8),
+ MK(1),MK(2),MK(3),MK(4),MK(5),MK(6),MK(7),MK(8),MK(9),MK(0),
+        MK(MINUS),MK(EQUAL),MK(BACKSLASH),MK(BACKSPACE),
+ MK(ESCAPE),MK(Q),MK(W),MK(E),MK(R),MK(T),MK(Y),MK(U),MK(I),MK(O),
+        MK(P),MK(GRAVE),MK(BRACKET_LEFT),MK(ENTER),
+ MK(LEFTCONTROL),MK(A),MK(S),MK(D),MK(F),MK(G),MK(H),MK(J),MK(K),
+        MK(L),MK(SEMICOLON),MK(APOSTROPHE),MK(BRACKET_RIGHT),MK(INSERT),
+ MK(LEFTSHIFT),MK(Z),MK(X),MK(C),MK(V),MK(B),MK(N),MK(M),MK(COMMA),
+        MK(PERIOD),MK(SLASH),MK(RIGHTALT),MK(RIGHTSHIFT),MK(LEFTALT),MK(SPACE),
+ MK(DELETE),MK(END),MK(PAGEDOWN),
+ MK(CURSORUP),MK(CURSORLEFT),MK(CURSORRIGHT),MK(CURSORDOWN)
+};
+
+static void UpdateFKB(void)
+{
+ int x;
+
+ for(x=0;x<0x48;x++)
+ {
+  fkbkeys[x]=0;
+  if(keys[fkbmap[x]])
+   fkbkeys[x]=1;
+ }
+}
diff --git a/drivers/cli/keyscan.h b/drivers/cli/keyscan.h
new file mode 100644 (file)
index 0000000..af82127
--- /dev/null
@@ -0,0 +1,166 @@
+#ifdef SVGALIB\r
+\r
+#include <vgakeyboard.h>\r
+#define SCANCODE_DELETE SCANCODE_REMOVE\r
+#define SCANCODE_KP_MINUS      SCANCODE_KEYPADMINUS\r
+#define SCANCODE_KP_PLUS       SCANCODE_KEYPADPLUS\r
+#define MK(k) SCANCODE_##k\r
+#define MK_COUNT 256\r
+#elif SDL\r
+#include <SDL.h>\r
+#define SDLK_A SDLK_a\r
+#define SDLK_B SDLK_b\r
+#define SDLK_C SDLK_c\r
+#define SDLK_D SDLK_d\r
+#define SDLK_E SDLK_e\r
+#define SDLK_F SDLK_f\r
+#define SDLK_G SDLK_g\r
+#define SDLK_H SDLK_h\r
+#define SDLK_I SDLK_i\r
+#define SDLK_J SDLK_j\r
+#define SDLK_K SDLK_k\r
+#define SDLK_L SDLK_l\r
+#define SDLK_M SDLK_m\r
+#define SDLK_N SDLK_n\r
+#define SDLK_O SDLK_o\r
+#define SDLK_P SDLK_p\r
+#define SDLK_Q SDLK_q\r
+#define SDLK_R SDLK_r\r
+#define SDLK_S SDLK_s\r
+#define SDLK_T SDLK_t\r
+#define SDLK_U SDLK_u\r
+#define SDLK_V SDLK_v\r
+#define SDLK_W SDLK_w\r
+#define SDLK_X SDLK_x\r
+#define SDLK_Y SDLK_y\r
+#define SDLK_Z SDLK_z\r
+#define SDLK_LEFTCONTROL SDLK_LCTRL\r
+#define SDLK_RIGHTCONTROL SDLK_RCTRL\r
+#define SDLK_LEFTALT SDLK_LALT\r
+#define SDLK_RIGHTALT SDLK_RALT\r
+#define SDLK_LEFTSHIFT SDLK_LSHIFT\r
+#define SDLK_RIGHTSHIFT SDLK_RSHIFT\r
+#define SDLK_CURSORDOWN SDLK_DOWN\r
+#define SDLK_CURSORUP SDLK_UP\r
+#define SDLK_CURSORLEFT SDLK_LEFT\r
+#define SDLK_CURSORRIGHT SDLK_RIGHT\r
+#define SDLK_ENTER SDLK_RETURN\r
+#define SDLK_EQUAL SDLK_EQUALS\r
+#define SDLK_APOSTROPHE SDLK_QUOTE\r
+#define SDLK_BRACKET_LEFT SDLK_LEFTBRACKET\r
+#define SDLK_BRACKET_RIGHT SDLK_RIGHTBRACKET\r
+#define SDLK_SCROLLLOCK SDLK_SCROLLOCK         /* I guess the SDL people don't like lots of Ls... */\r
+#define SDLK_GRAVE     SDLK_BACKQUOTE\r
+#define MK(k) SDLK_##k\r
+#define MK_COUNT (SDLK_LAST+1)\r
+#elif DOS\r
+\r
+#define SCAN_GRAVE     0x29\r
+#define SCAN_1         0x02\r
+#define SCAN_2         0x03\r
+#define SCAN_3         0x04\r
+#define SCAN_4          0x05\r
+#define SCAN_5          0x06\r
+#define SCAN_6          0x07\r
+#define SCAN_7          0x08\r
+#define SCAN_8          0x09\r
+#define SCAN_9          0x0A\r
+#define SCAN_0          0x0B\r
+#define SCAN_MINUS     0x0C\r
+#define SCAN_EQUAL     0x0D\r
+#define SCAN_BACKSLASH 0x2B\r
+#define SCAN_BACKSPACE 0x0E\r
+#define SCAN_TAB       0x0F\r
+#define SCAN_Q         0x10\r
+#define SCAN_W         0x11\r
+#define SCAN_E         0x12\r
+#define SCAN_R         0x13\r
+#define SCAN_T         0x14\r
+#define SCAN_Y         0x15\r
+#define SCAN_U         0x16\r
+#define SCAN_I         0x17\r
+#define SCAN_O         0x18\r
+#define SCAN_P         0x19\r
+#define SCAN_BRACKET_LEFT      0x1A\r
+#define SCAN_BRACKET_RIGHT     0x1B\r
+#define SCAN_LOWBACKSLASH      0x2B\r
+#define SCAN_CAPSLOCK  0x3A\r
+#define SCAN_A         0x1E\r
+#define SCAN_S         0x1F\r
+#define SCAN_D          0x20\r
+#define SCAN_F          0x21\r
+#define SCAN_G          0x22\r
+#define SCAN_H          0x23\r
+#define SCAN_J          0x24\r
+#define SCAN_K          0x25\r
+#define SCAN_L          0x26\r
+#define SCAN_SEMICOLON 0x27\r
+#define SCAN_APOSTROPHE        0x28\r
+#define SCAN_ENTER     0x1C\r
+#define SCAN_LEFTSHIFT 0x2A\r
+#define SCAN_Z         0x2C\r
+#define SCAN_X         0x2D\r
+#define SCAN_C          0x2E\r
+#define SCAN_V          0x2F\r
+#define SCAN_B          0x30\r
+#define SCAN_N          0x31\r
+#define SCAN_M          0x32\r
+#define SCAN_COMMA      0x33\r
+#define SCAN_PERIOD    0x34\r
+#define SCAN_SLASH     0x35\r
+#define SCAN_RIGHTSHIFT        0x36\r
+#define SCAN_LEFTCONTROL       0x1D\r
+#define SCAN_LEFTALT           0x38\r
+#define SCAN_SPACE             0x39\r
+\r
+/* Extended keys. */\r
+#define SCAN_RIGHTALT          (0x38|0x80)\r
+#define SCAN_RIGHTCONTROL      (0x1D|0x80)\r
+#define SCAN_BL_INSERT         (0x52|0x80)\r
+#define SCAN_BL_DELETE         (0x53|0x80)\r
+#define SCAN_BL_CURSORLEFT     (0x4B|0x80)\r
+#define SCAN_BL_HOME           (0x47|0x80)\r
+#define SCAN_BL_END            (0x4F|0x80)\r
+#define SCAN_BL_CURSORUP       (0x48|0x80)\r
+#define SCAN_BL_CURSORDOWN     (0x50|0x80)\r
+#define SCAN_BL_PAGEUP         (0x49|0x80)\r
+#define SCAN_BL_PAGEDOWN       (0x51|0x80)\r
+#define SCAN_BL_CURSORRIGHT    (0x4D|0x80)\r
+\r
+#define SCAN_SCROLLLOCK         0x46\r
+/* Keys in the key pad area. */\r
+#define SCAN_NUMLOCK           0x45\r
+#define SCAN_HOME              0x47\r
+#define SCAN_CURSORLEFT                0x4B\r
+#define SCAN_END               0x4F\r
+#define SCAN_SLASH             0x35\r
+#define SCAN_CURSORUP          0x48\r
+#define SCAN_CENTER            0x4C\r
+#define SCAN_CURSORDOWN                0x50\r
+#define SCAN_INSERT            0x52\r
+#define SCAN_ASTERISK          0x37\r
+#define SCAN_PAGEUP            0x49\r
+#define SCAN_CURSORRIGHT       0x4D\r
+#define SCAN_PAGEDOWN           0x51\r
+#define SCAN_DELETE          0x53\r
+#define SCAN_KP_MINUS           0x4A\r
+#define SCAN_KP_PLUS            0x4E\r
+#define SCAN_KP_ENTER           0x1C\r
+\r
+#define SCAN_ESCAPE            0x01\r
+#define SCAN_F1                        0x3B\r
+#define SCAN_F2                        0x3C\r
+#define SCAN_F3                 0x3D\r
+#define SCAN_F4                 0x3E\r
+#define SCAN_F5                 0x3F\r
+#define SCAN_F6                 0x40\r
+#define SCAN_F7                 0x41\r
+#define SCAN_F8                 0x42\r
+#define SCAN_F9                 0x43\r
+#define SCAN_F10                0x44\r
+#define SCAN_F11                0x57\r
+#define SCAN_F12                0x58\r
\r
+#define MK_COUNT 256\r
+#define MK(k) SCAN_##k\r
+#endif\r
diff --git a/drivers/cli/lnx-joystick.c b/drivers/cli/lnx-joystick.c
new file mode 100644 (file)
index 0000000..4c2ae6a
--- /dev/null
@@ -0,0 +1,201 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <linux/joystick.h>
+#include "main.h"
+#include "lnx-joystick.h"
+
+int joy[4]={0,0,0,0};
+int joyBMap[4][4];
+
+static int32 joybuttons[4]={0,0,0,0};
+static int32 joyx[4]={0,0,0,0};
+static int32 joyy[4]={0,0,0,0};
+
+static void ConfigJoystick(int z);
+static int fd[4];
+
+#define JOY_A   1
+#define JOY_B   2
+#define JOY_SELECT      4
+#define JOY_START       8
+#define JOY_UP  0x10
+#define JOY_DOWN        0x20
+#define JOY_LEFT        0x40
+#define JOY_RIGHT       0x80
+
+static void UpdateJoyData(int x)
+{
+       struct js_event e;
+
+       while(read(fd[x],&e,sizeof(struct js_event))==sizeof(struct js_event))
+       {
+        e.type&=~JS_EVENT_INIT;
+         if(e.type==JS_EVENT_BUTTON) 
+        {
+          if(e.value)
+           joybuttons[x]|=(1<<e.number);
+          else
+           joybuttons[x]&=~(1<<e.number);
+         }
+        else if(e.type==JS_EVENT_AXIS)
+        {
+         if(e.number==0)
+          joyx[x]=e.value;
+         else if(e.number==1)
+          joyy[x]=e.value;
+        }
+       }
+}
+
+uint32 GetJSOr(void)
+{
+       int x,y;
+       unsigned long ret;
+       ret=0;
+
+       for(x=0;x<4;x++)
+       {
+        int *joym=joyBMap[x];
+
+        if(!joy[x]) continue;
+        UpdateJoyData(x);
+        for(y=0;y<4;y++)
+         if(joybuttons[x]&joym[y]) ret|=(1<<y)<<(x<<3);
+        if(joyx[x]<=-16383) ret|=JOY_LEFT<<(x<<3);
+        else if(joyx[x]>=16383) ret|=JOY_RIGHT<<(x<<3);
+        if(joyy[x]<=-16383) ret|=JOY_UP<<(x<<3);
+        else if(joyy[x]>=16383) ret|=JOY_DOWN<<(x<<3);
+        }
+       return ret;
+}
+
+void KillJoysticks(void)
+{
+       int x;
+       for(x=0;x<4;x++)
+        if(joy[x]) 
+         close(fd[x]);
+}
+
+int InitJoysticks(void)
+{
+       char dbuf[64];
+       int version;
+       int z;
+
+       for(z=0;z<4;z++)
+       {
+        if(!joy[z]) continue;
+        sprintf(dbuf,"/dev/js%d",joy[z]-1);
+        if((fd[z]=open(dbuf,O_RDONLY|O_NONBLOCK))<0) 
+        {
+          printf("Could not open %s.\n",dbuf);
+          joy[z]=0;
+          continue;
+         }
+
+         if(ioctl(fd[z], JSIOCGVERSION, &version)==-1) 
+        {
+         printf("Error using ioctl JSIOCGVERSION on %s.\n",dbuf);
+         joy[z]=0;
+         close(fd[z]);
+         continue;
+        }
+
+         if(!(joyBMap[z][0]|joyBMap[z][1]|joyBMap[z][2]|joyBMap[z][3]))
+          ConfigJoystick(z);
+        }
+
+       return(joy[0]|joy[1]|joy[2]|joy[3]);
+}
+
+#define WNOINPUT(); for(;;){uint8 t; if(read(fileno(stdin),&t,1)==-1) \
+                          {break;}}
+
+static void BConfig(int z,int b)
+{
+  WNOINPUT();
+  for(;;)
+  {
+   uint8 t;
+   if(read(fileno(stdin),&t,1)==-1)
+   {
+    if(errno!=EAGAIN) break;
+   }
+   else
+    break;
+
+   {
+    struct js_event e;
+
+    while(read(fd[z],&e,sizeof(struct js_event))==sizeof(struct js_event))
+    {
+      if(e.type==JS_EVENT_BUTTON)
+      {
+       if(!e.value)
+       {
+       joyBMap[z][b]=1<<e.number;
+       goto endsa;
+       }
+      }
+    }
+   }
+
+  }
+  endsa:
+  WNOINPUT();
+}
+
+void ConfigJoystick(int z)
+{
+ int sa;
+ static char *genb="** Press button for ";
+
+ printf("\n\n Joystick button configuration:\n\n");
+ printf("   Push the button to map to the virtual joystick.\n");
+ printf("   If you do not wish to assign a button, press Enter to skip\n");
+ printf("   that button.\n\n");
+ printf("   Press enter to continue...\n");
+ getchar();
+ printf("****  Configuring joystick %d ****\n\n",z+1);
+
+ sa=fcntl(fileno(stdin),F_GETFL);
+ fcntl(fileno(stdin),F_SETFL,O_NONBLOCK);
+
+  printf("%s\"Select\".\n",genb);
+  BConfig(z,2);
+
+  printf("%s\"Start\".\n",genb);
+  BConfig(z,3);
+
+  printf("%s\"B\".\n",genb);
+  BConfig(z,1);
+
+  printf("%s\"A\".\n",genb);
+  BConfig(z,0);
+
+  fcntl(fileno(stdin),F_SETFL,sa);
+}
+
diff --git a/drivers/cli/lnx-joystick.h b/drivers/cli/lnx-joystick.h
new file mode 100644 (file)
index 0000000..a38ae77
--- /dev/null
@@ -0,0 +1,3 @@
+extern int joy[4];
+extern int joyBMap[4][4];
+
diff --git a/drivers/cli/main.c b/drivers/cli/main.c
new file mode 100644 (file)
index 0000000..b65b36d
--- /dev/null
@@ -0,0 +1,376 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+/*  This file contains or coordinates all of the code necessary to compile
+    on a UNIX system that can use svgalib, such as FreeBSD and Linux.  
+    This code is not guaranteed to compile on FreeBSD, though.
+*/
+
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "main.h"
+#include "throttle.h"
+
+#include "../common/config.h"
+#include "../common/args.h"
+#include "../common/unixdsp.h"
+#include "../common/cheat.h"
+
+#include "dface.h"
+
+static int ntsccol=0,ntschue=-1,ntsctint=-1;
+static int soundvol=100;
+static int inited=0;
+
+int srendlinev[2]={8,0};
+int erendlinev[2]={239,239};
+int srendline,erendline;
+
+
+static char BaseDirectory[2048];
+
+int eoptions=0;
+
+static void DriverKill(void);
+static int DriverInitialize(void);
+
+static int gametype;
+#include "input.c"
+
+static void ParseGI(FCEUGI *gi)
+{
+ gametype=gi->type;
+
+ InputType[0]=UsrInputType[0];
+ InputType[1]=UsrInputType[1];
+ InputTypeFC=UsrInputTypeFC;
+
+ if(gi->input[0]>=0)
+  InputType[0]=gi->input[0];
+ if(gi->input[1]>=0)
+  InputType[1]=gi->input[1];
+ if(gi->inputfc>=0)
+  InputTypeFC=gi->inputfc;
+ FCEUI_GetCurrentVidSystem(&srendline,&erendline);
+}
+
+void FCEUD_PrintError(char *s)
+{
+ puts(s);
+}
+
+static char *cpalette=0;
+static void LoadCPalette(void)
+{
+ char tmpp[192];
+ FILE *fp;
+
+ if(!(fp=fopen(cpalette,"rb")))
+ {
+  printf(" Error loading custom palette from file: %s\n",cpalette);
+  return;
+ }
+ fread(tmpp,1,192,fp);
+ FCEUI_SetPaletteArray(tmpp);
+ fclose(fp);
+}
+
+static CFGSTRUCT fceuconfig[]={
+       AC(soundvol),
+       ACS(cpalette),
+       AC(ntsctint),
+       AC(ntschue),
+       AC(ntsccol),
+       AC(UsrInputTypeFC),
+       ACA(UsrInputType),
+       AC(powerpadside),
+       AC(powerpadsc),
+       AC(eoptions),
+       ACA(srendlinev),
+       ACA(erendlinev),
+       ADDCFGSTRUCT(DriverConfig),
+       ENDCFGSTRUCT
+};
+
+static void SaveConfig(void)
+{      
+       char tdir[2048];
+       sprintf(tdir,"%s"PSS"fceu.cfg",BaseDirectory);
+        DriverInterface(DES_GETNTSCTINT,&ntsctint);
+        DriverInterface(DES_GETNTSCHUE,&ntschue);
+        SaveFCEUConfig(tdir,fceuconfig);
+}
+
+static void LoadConfig(void)
+{
+       char tdir[2048];
+        sprintf(tdir,"%s"PSS"fceu.cfg",BaseDirectory);
+        LoadFCEUConfig(tdir,fceuconfig);
+        if(ntsctint>=0) DriverInterface(DES_SETNTSCTINT,&ntsctint);
+        if(ntschue>=0) DriverInterface(DES_SETNTSCHUE,&ntschue);
+}
+
+static void CreateDirs(void)
+{
+ char *subs[5]={"fcs","snaps","gameinfo","sav","cheats"};
+ char tdir[2048];
+ int x;
+
+ mkdir(BaseDirectory,S_IRWXU);
+ for(x=0;x<5;x++)
+ {
+  sprintf(tdir,"%s"PSS"%s",BaseDirectory,subs[x]);
+  mkdir(tdir,S_IRWXU);
+ }
+}
+
+static void SetSignals(void (*t)(int))
+{
+  int sigs[11]={SIGINT,SIGTERM,SIGHUP,SIGPIPE,SIGSEGV,SIGFPE,SIGKILL,SIGALRM,SIGABRT,SIGUSR1,SIGUSR2};
+  int x;
+  for(x=0;x<11;x++)
+   signal(sigs[x],t);
+}
+
+static void CloseStuff(int signum)
+{
+       DriverKill();
+        printf("\nSignal %d has been caught and dealt with...\n",signum);
+        switch(signum)
+        {
+         case SIGINT:printf("How DARE you interrupt me!\n");break;
+         case SIGTERM:printf("MUST TERMINATE ALL HUMANS\n");break;
+         case SIGHUP:printf("Reach out and hang-up on someone.\n");break;
+         case SIGPIPE:printf("The pipe has broken!  Better watch out for floods...\n");break;
+         case SIGSEGV:printf("Iyeeeeeeeee!!!  A segmentation fault has occurred.  Have a fluffy day.\n");break;
+        /* So much SIGBUS evil. */
+        #ifdef SIGBUS
+        #if(SIGBUS!=SIGSEGV)
+         case SIGBUS:printf("I told you to be nice to the driver.\n");break;
+        #endif
+        #endif
+         case SIGFPE:printf("Those darn floating points.  Ne'er know when they'll bite!\n");break;
+         case SIGALRM:printf("Don't throw your clock at the meowing cats!\n");break;
+         case SIGABRT:printf("Abort, Retry, Ignore, Fail?\n");break;
+         case SIGUSR1:
+         case SIGUSR2:printf("Killing your processes is not nice.\n");break;
+        }
+        exit(1);
+}
+
+static void DoArgs(int argc, char *argv[])
+{
+        static char *cortab[5]={"none","gamepad","zapper","powerpad","arkanoid"};
+        static int cortabi[5]={SI_NONE,SI_GAMEPAD,
+                               SI_ZAPPER,SI_POWERPAD,SI_ARKANOID};
+       static char *fccortab[5]={"none","arkanoid","shadow","4player","fkb"};
+       static int fccortabi[5]={SIFC_NONE,SIFC_ARKANOID,SIFC_SHADOW,
+                                SIFC_4PLAYER,SIFC_FKB};
+
+       int x;
+       static char *inputa[2]={0,0};
+       static char *fcexp=0;
+       static int docheckie[4];
+
+        static ARGPSTRUCT FCEUArgs[]={
+         {"-soundvol",0,&soundvol,0},
+         {"-cpalette",0,&cpalette,0x4001},
+
+         {"-ntsccol",0,&ntsccol,0},
+         {"-pal",&docheckie[0],0,0},
+         {"-input1",0,&inputa[0],0x4001},{"-input2",0,&inputa[1],0x4001},
+         {"-fcexp",0,&fcexp,0x4001},
+
+         {"-gg",&docheckie[1],0,0},
+         {"-no8lim",0,&eoptions,0x8001},
+         {"-subase",0,&eoptions,0x8002},
+         {"-snapname",0,&eoptions,0x8000|EO_SNAPNAME},
+        {"-nofs",0,&eoptions,0x8000|EO_NOFOURSCORE},
+         {"-clipsides",0,&eoptions,0x8000|EO_CLIPSIDES},
+        {"-nothrottle",0,&eoptions,0x8000|EO_NOTHROTTLE},
+         {"-slstart",0,&srendlinev[0],0},{"-slend",0,&erendlinev[0],0},
+         {"-slstartp",0,&srendlinev[1],0},{"-slendp",0,&erendlinev[1],0},
+        {0,(void *)DriverArgs,0,0},
+        {0,0,0,0}
+        };
+
+        memset(docheckie,0,sizeof(docheckie));
+       ParseArguments(argc, argv, FCEUArgs);
+       if(cpalette)
+       {
+        if(cpalette[0]=='0')
+         if(cpalette[1]==0)
+         {
+          free(cpalette);
+          cpalette=0;
+         }
+       }
+       if(docheckie[0])
+        FCEUI_SetVidSystem(1);
+       if(docheckie[1])
+        FCEUI_SetGameGenie(1);
+
+        FCEUI_DisableSpriteLimitation(eoptions&1);
+        FCEUI_SaveExtraDataUnderBase(eoptions&2);
+       FCEUI_SetSnapName(eoptions&EO_SNAPNAME);
+
+       for(x=0;x<2;x++)
+       {
+         if(srendlinev[x]<0 || srendlinev[x]>239) srendlinev[x]=0;
+         if(erendlinev[x]<srendlinev[x] || erendlinev[x]>239) erendlinev[x]=239;
+       }
+
+        FCEUI_SetRenderedLines(srendlinev[0],erendlinev[0],srendlinev[1],erendlinev[1]);
+        FCEUI_SetSoundVolume(soundvol);
+       DriverInterface(DES_NTSCCOL,&ntsccol);
+       DoDriverArgs();
+
+       if(fcexp)
+       {
+        int y;
+         for(y=0;y<5;y++)
+         {
+          if(!strncmp(fccortab[y],fcexp,8))
+          {
+          UsrInputTypeFC=fccortabi[y];
+          break;
+          }
+         }
+        free(fcexp);
+       }
+       for(x=0;x<2;x++)
+       {
+        int y;
+
+         if(!inputa[x])
+         continue;
+
+        for(y=0;y<5;y++)        
+        {
+         if(!strncmp(cortab[y],inputa[x],8))
+         {
+          UsrInputType[x]=cortabi[y];
+          if(y==3)
+          {
+           powerpadside&=~(1<<x);
+           powerpadside|=((((inputa[x][8])-'a')&1)^1)<<x;
+          }
+          free(inputa[x]);
+         }
+        }
+       }       
+}
+
+#include "usage.h"
+
+int CLImain(int argc, char *argv[])
+{
+       FCEUGI *tmp;
+       int ret;
+
+       if(!(ret=FCEUI_Initialize()))
+         return(1);
+        GetBaseDirectory(BaseDirectory);
+       FCEUI_SetBaseDirectory(BaseDirectory);
+
+       CreateDirs();
+        if(argc<=1) 
+        {
+         ShowUsage(argv[0]);
+         return 1;
+        }
+        LoadConfig();
+        DoArgs(argc-2,&argv[1]);
+       if(cpalette)
+        LoadCPalette();
+       if(InitSound())
+        inited|=1;
+
+        if(!(tmp=FCEUI_LoadGame(argv[argc-1])))
+        {
+         ret=0;
+         goto dk;
+        }
+       ParseGI(tmp);
+       RefreshThrottleFPS();
+        if(!DriverInitialize())
+        {
+         ret=0;
+         goto dk;
+        }
+       InitOtherInput();
+       FCEUI_Emulate();
+
+       dk:
+       DriverKill();
+        return(ret?0:1);
+}
+
+static int DriverInitialize(void)
+{
+   SetSignals((void *)CloseStuff);
+
+   if(InitJoysticks())
+    inited|=2;
+   if(!InitVideo()) return 0;
+   inited|=4;
+   if(!InitKeyboard()) return 0;
+   inited|=8;
+   return 1;
+}
+
+static void DriverKill(void)
+{
+ SaveConfig();
+ SetSignals(SIG_IGN);
+
+ if(inited&2)
+  KillJoysticks();
+ if(inited&8)
+  KillKeyboard();
+ if(inited&4)
+  KillVideo();
+ if(inited&1)
+  KillSound();
+ if(inited&16)
+  KillMouse();
+ inited=0;
+}
+
+void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count)
+{
+ if(!Count && !NoWaiting && !(eoptions&EO_NOTHROTTLE))
+  SpeedThrottle();
+ BlitScreen(XBuf);
+ if(Count)
+  WriteSound(Buffer,Count,NoWaiting);
+ FCEUD_UpdateInput();
+}
+
diff --git a/drivers/cli/main.h b/drivers/cli/main.h
new file mode 100644 (file)
index 0000000..99dc5b5
--- /dev/null
@@ -0,0 +1,30 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+#include "../../driver.h"
+
+extern int eoptions;
+#define EO_NO8LIM      1
+#define EO_SUBASE      2
+#define EO_CLIPSIDES   8
+#define EO_SNAPNAME    16
+#define EO_NOFOURSCORE 32
+#define EO_NOTHROTTLE  64
+extern int srendline,erendline,srendlinev[2],erendlinev[2];
+extern int NoWaiting;
diff --git a/drivers/cli/sdl-joystick.c b/drivers/cli/sdl-joystick.c
new file mode 100644 (file)
index 0000000..1a3fecf
--- /dev/null
@@ -0,0 +1,200 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *  Copyright (C) 2002 Paul Kuliniewicz
+ *
+ * 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-1307  USA
+ */
+
+/* PK: SDL joystick input stuff */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "sdl.h"
+static SDL_Joystick *jo[4] = {NULL, NULL, NULL, NULL};
+
+static void ConfigJoystick (int z);
+
+#define JOY_A          0x01
+#define JOY_B          0x02
+#define JOY_SELECT     0x04
+#define JOY_START      0x08
+#define JOY_UP         0x10
+#define JOY_DOWN       0x20
+#define JOY_LEFT       0x40
+#define JOY_RIGHT      0x80
+
+/* Gets the current joystick position information. */
+uint32 GetJSOr (void)
+{
+       int n;                  /* joystick index */
+       int b;                  /* button index */
+       int *joym;              /* pointer to a joystick's button map */
+       Sint16 pos;             /* axis position */
+       uint32 ret = 0;         /* return value */
+
+       for (n = 0; n < 4; n++)
+       {
+               if (joy[n] == 0)
+                       continue;
+               joym = joyBMap[n];
+
+               /* Axis information. */
+               pos = SDL_JoystickGetAxis(jo[n], joyAMap[n][0]);
+               if (pos <= -16383)
+                       ret |= JOY_LEFT << (n << 3);
+               else if (pos >= 16363)
+                       ret |= JOY_RIGHT << (n << 3);
+               pos = SDL_JoystickGetAxis(jo[n], joyAMap[n][1]);
+               if (pos <= -16383)
+                       ret |= JOY_UP << (n << 3);
+               else if (pos >= 16383)
+                       ret |= JOY_DOWN << (n << 3);
+
+               /* Button information. */
+               for (b = 0; b < 4; b++)
+               {
+                       if (SDL_JoystickGetButton(jo[n], joym[b]))
+                               ret |= (1 << b) << (n << 3);
+               }
+       }
+
+       return ret;
+}
+
+/* Cleanup opened joysticks. */
+void KillJoysticks (void)
+{
+       int n;                  /* joystick index */
+
+       for (n = 0; n < 4; n++)
+       {
+               if (joy[n] != 0)
+                       SDL_JoystickClose(jo[n]);
+       }
+       SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
+       return;
+}
+
+/* Initialize joysticks. */
+int InitJoysticks (void)
+{
+       int n;                  /* joystick index */
+       if(!(joy[0]|joy[1]|joy[2]|joy[3]))
+        return(0);
+       SDL_InitSubSystem(SDL_INIT_JOYSTICK);
+       for (n = 0; n < 4; n++)
+       {
+               if (joy[n] == 0)
+                       continue;
+               
+               /* Open the joystick under SDL. */
+               jo[n] = SDL_JoystickOpen(joy[n] - 1);
+               if (jo[n] == NULL)
+               {
+                       printf("Could not open joystick %d: %s.\n",
+                               joy[n] - 1, SDL_GetError());
+                       joy[n] = 0;
+                       continue;
+               }
+
+               /* Check for a button map. */
+               if (!(joyBMap[n][0] | joyBMap[n][1] | joyBMap[n][2] |
+                       joyBMap[n][3]))
+               {
+                       ConfigJoystick(n);
+               }
+       }
+
+       return (1);
+}
+
+#define WNOINPUT(); for(;;){uint8 t; if(read(fileno(stdin),&t,1)==-1) \
+                       {break;}}
+
+/* Configure a joystick button. */
+static void BConfig (int n, int b)
+{
+       SDL_Event event;                /* SDL event structure */
+       WNOINPUT();
+       while (1)
+       {
+               uint8 t;
+               if (read(fileno(stdin), &t, 1) == -1)
+               {
+                       if (errno != EAGAIN)
+                               break;
+               }
+               else
+                       break;
+               
+               if (SDL_PollEvent(&event) && event.type == SDL_JOYBUTTONDOWN)
+               {
+                       joyBMap[n][b] = event.jbutton.button;
+                       goto endsa;
+               }
+       }
+
+       endsa:
+       WNOINPUT();
+
+       return;
+}
+
+/* Joystick button and axis configuration. */
+void ConfigJoystick (int n)
+{
+       int sa;                 /* buffer value */
+       char buf[128];          /* input buffer */
+
+       printf("\n\n Joystick button and axis configuration:\n\n");
+       printf("   Select the joystick axes to use for the virtual d-pad.\n");
+       printf("   If you do not wish to assign an axis, press Enter to skip\n");
+       printf("   that axis.\n");
+       printf("   Push the button to map to the virtual joystick.\n");
+       printf("   If you do not wish to assign a button, press Enter to skip\n");
+       printf("   that button.\n   Press enter to continue...\n");
+       getchar();
+       printf("****  Configuring joystick %d ****\n\n", n + 1);
+
+       printf("** Enter axis to use for the x-axis (default 0).\n");
+       fgets(buf, sizeof(buf), stdin);
+       joyAMap[n][0] = ('0' <= buf[0] && buf[9] <= '9') ? atoi(buf) : 0;
+
+       printf("** Enter axis to use for the y-axis (default 1).\n");
+       fgets(buf, sizeof(buf), stdin);
+       joyAMap[n][1] = ('0' <= buf[0] && buf[9] <= '9') ? atoi(buf) : 1;
+
+       sa = fcntl(fileno(stdin), F_GETFL);
+       fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
+
+       printf("** Press button for \"Select\".\n");
+       BConfig(n, 2);
+
+       printf("** Press button for \"Start\".\n");
+       BConfig(n, 3);
+
+       printf("** Press button for \"B\".\n");
+       BConfig(n, 1);
+
+       printf("** Press button for \"A\".\n");
+       BConfig(n, 0);
+       
+       fcntl(fileno(stdin), F_SETFL, sa);
+}
diff --git a/drivers/cli/sdl-netplay.c b/drivers/cli/sdl-netplay.c
new file mode 100644 (file)
index 0000000..38a4c81
--- /dev/null
@@ -0,0 +1,163 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2001 LULU
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "sdl.h"
+#include <SDL/SDL_net.h>
+#include "sdl-netplay.h"
+
+char *netplayhost=0;
+
+static int tonowait;
+
+int Port=0xFCE;
+int FDnetplay=0;
+
+
+static SDLNet_SocketSet socketset = NULL;
+static TCPsocket tcpsock = NULL, servsock = NULL;
+
+void cleanup(void)
+{
+    if (tcpsock != NULL) {
+        SDLNet_TCP_DelSocket(socketset, tcpsock);
+        SDLNet_TCP_Close(tcpsock);
+        tcpsock = NULL;
+    }
+    if (servsock != NULL) {
+        SDLNet_TCP_DelSocket(socketset, servsock);
+        SDLNet_TCP_Close(servsock);
+        servsock = NULL;
+    }
+    if (socketset != NULL) {
+        SDLNet_FreeSocketSet(socketset);
+        socketset = NULL;
+    }
+}
+
+int FCEUD_NetworkConnect(void)
+{
+    IPaddress serverIP;
+
+    tonowait=0;
+
+    if (netplay == 2) {
+        /* client */
+        printf("connecting to %s\n", netplayhost);
+
+        SDLNet_ResolveHost(&serverIP, netplayhost, Port);
+        if (serverIP.host == INADDR_NONE) {
+            fprintf(stderr, "Couldn't connected to %s\n", netplayhost);
+            return -1;
+        } else {
+            tcpsock = SDLNet_TCP_Open(&serverIP);
+            if (tcpsock == NULL) {
+                fprintf(stderr, "Couldn't connected to %s\n", netplayhost);
+                return -1;
+            }
+        }
+        printf("connected to %s\n", netplayhost);
+
+        socketset = SDLNet_AllocSocketSet(1);
+        if (socketset == NULL) {
+            fprintf(stderr, "Couldn't create socket set: %s\n",
+                    SDLNet_GetError());
+            return -1;
+        }
+        SDLNet_TCP_AddSocket(socketset, tcpsock);
+
+        return 1;
+    } else {
+        /* server */
+
+        SDLNet_ResolveHost(&serverIP, NULL, Port);
+        printf("Server IP: %x, %d\n", serverIP.host, serverIP.port);
+        servsock = SDLNet_TCP_Open(&serverIP);
+        if (servsock == NULL) {
+            cleanup();
+            fprintf(stderr, "Couldn't create server socket: %s\n",
+                    SDLNet_GetError());
+            return -1;
+        }
+
+        socketset = SDLNet_AllocSocketSet(2);
+        if (socketset == NULL) {
+            fprintf(stderr, "Couldn't create socket set: %s\n",
+                    SDLNet_GetError());
+            return -1;
+        }
+        SDLNet_TCP_AddSocket(socketset, servsock);
+
+        if (SDLNet_CheckSockets(socketset, ~0)) {
+            tcpsock = SDLNet_TCP_Accept(servsock);
+            if (tcpsock == NULL) {
+                return -1;
+            }
+            SDLNet_TCP_AddSocket(socketset, tcpsock);
+
+            printf("OK, connected\n");
+            return 1;
+        }
+    }
+
+    return -1;
+}
+
+void FCEUD_NetworkClose(void)
+{
+    cleanup();
+}
+
+int FCEUD_NetworkRecvData(uint8 *data, uint32 len, int block)
+{
+  if(block)
+  {
+   if(SDLNet_TCP_Recv(tcpsock, (void *) data, len)!=len)
+   {
+    cleanup();
+    return(0);
+   }
+   switch(SDLNet_CheckSockets(socketset,0))
+   {
+    case -1:return(0);
+    case 0:NoWaiting&=~2;tonowait=0;break; 
+    default:if(tonowait>=3)
+            NoWaiting|=2;
+           else tonowait++;
+           break;
+   }
+   return(1);
+  }
+  else
+  {
+   int t=SDLNet_CheckSockets(socketset,0);
+   if(t<0) return(0);
+   if(!t) return(-1);
+   return(SDLNet_TCP_Recv(tcpsock, (void *) data, len)==len);
+  }
+}
+
+/* 0 on failure, 1 on success.  This function should always block. */
+int FCEUD_NetworkSendData(uint8 *Value, uint32 len)
+{
+    if (tcpsock)
+        return(SDLNet_TCP_Send(tcpsock, (void *) Value, len)==len);
+    return 0;
+}
diff --git a/drivers/cli/sdl-netplay.h b/drivers/cli/sdl-netplay.h
new file mode 100644 (file)
index 0000000..48769f6
--- /dev/null
@@ -0,0 +1,5 @@
+extern char *netplayhost;
+extern int Port;
+extern int FDnetplay;
+#define netplay FDnetplay
+
diff --git a/drivers/cli/sdl-sound.c b/drivers/cli/sdl-sound.c
new file mode 100644 (file)
index 0000000..bbe716b
--- /dev/null
@@ -0,0 +1,148 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdio.h>
+#include "sdl.h"
+
+#ifndef DSPSOUND
+
+//#define BSIZE (32768-1024)
+
+static int32 BSIZE;
+static volatile int16 AudioBuf[32768];
+static volatile uint32 readoffs,writeoffs;
+void fillaudio(void *udata, uint8 *stream, int len)
+{
+ int16 *dest=(int16 *)stream;
+
+ len>>=1;
+ while(len)
+ {
+  *dest=AudioBuf[readoffs];
+  dest++;
+  readoffs=(readoffs+1)&32767;
+  len--;
+ }
+}
+
+void WriteSound(int32 *Buffer, int Count, int NoWaiting)
+{
+ while(Count)
+ {
+  while(writeoffs==((readoffs-BSIZE)&32767)) 
+   if(NoWaiting)
+    return;
+  AudioBuf[writeoffs]=*Buffer;
+  writeoffs=(writeoffs+1)&32767;
+  Buffer++;
+  Count--;
+ }
+}
+
+int InitSound(void)
+{
+ if(_sound)
+ {
+  SDL_AudioSpec spec;
+
+  if(_lbufsize<_ebufsize) 
+  {
+   puts("Ack, lbufsize must not be smaller than ebufsize!");
+   return(0);
+  }
+  if(_lbufsize<6 || _lbufsize>13)
+  {
+   puts("lbufsize out of range");
+   return(0);
+  }
+  if(_ebufsize<5)
+  {
+   puts("ebufsize out of range");
+   return(0);
+  }
+  memset(&spec,0,sizeof(spec));
+  if(SDL_InitSubSystem(SDL_INIT_AUDIO)<0)
+  {
+   puts(SDL_GetError());
+   return(0);
+  }
+  if(_sound==1) _sound=44100;
+  spec.freq=_sound;
+  spec.format=AUDIO_S16;
+  spec.channels=1;
+  spec.samples=1<<_ebufsize;
+  spec.callback=fillaudio;
+  spec.userdata=0;
+
+  if(SDL_OpenAudio(&spec,0)<0)
+  {
+   puts(SDL_GetError());
+   SDL_QuitSubSystem(SDL_INIT_AUDIO);
+   return(0);
+  }
+  FCEUI_Sound(_sound);
+  BSIZE=32768-(1<<_lbufsize);
+  SDL_PauseAudio(0);
+  return(1);
+ }
+ return(0);
+}
+
+void SilenceSound(int n)
+{
+ SDL_PauseAudio(n);
+
+}
+
+void KillSound(void)
+{
+ SDL_CloseAudio();
+ SDL_QuitSubSystem(SDL_INIT_AUDIO);
+}
+
+#else
+#include "../common/unixdsp.h"
+
+void WriteSound(int32 *Buffer, int Count, int NoWaiting)
+{
+  WriteUNIXDSPSound(Buffer, Count, NoWaiting);
+}
+
+int InitSound(void)
+{
+        if(_sound)
+        {
+         int rate;
+         if(_sound==1)
+          _sound=48000;
+         rate=_sound;
+         if(InitUNIXDSPSound(&rate,_f8bit?0:1,8,8))
+         {
+          FCEUI_Sound(rate);
+          return(1);
+         }
+        }
+        return(0);
+}
+void KillSound(void)
+{
+        KillUNIXDSPSound();
+}
+#endif
diff --git a/drivers/cli/sdl-video.c b/drivers/cli/sdl-video.c
new file mode 100644 (file)
index 0000000..5ca240c
--- /dev/null
@@ -0,0 +1,228 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "sdl.h"
+#include "../common/vidblit.h"
+
+#define _sline srendline
+#define _eline erendline
+
+SDL_Surface *screen;
+
+static int tlines;
+static int inited=0;
+
+static int exs,eys,eefx;
+#define NWIDTH (256-((eoptions&EO_CLIPSIDES)?16:0))
+#define NOFFSET        (eoptions&EO_CLIPSIDES?8:0)
+
+static void CleanSurface(void)
+{
+ uint32 x;
+
+ x=screen->pitch*screen->h;
+
+ if(SDL_MUSTLOCK(screen))
+  SDL_LockSurface(screen);
+
+ memset((uint8*)screen->pixels, 0x80, x);
+
+ if(SDL_MUSTLOCK(screen))
+  SDL_UnlockSurface(screen);
+
+ SDL_UpdateRect(screen, 0, 0, 0, 0);
+}
+
+static int paletterefresh;
+
+void KillVideo(void)
+{
+ if(inited&1)
+ {
+  SDL_QuitSubSystem(SDL_INIT_VIDEO);
+ }
+ inited=0;
+}
+
+int InitVideo(void)
+{
+ const SDL_VideoInfo *vinf;
+ int flags=0;
+
+ #ifdef BROKEN
+ if(_fullscreen && _fshack)
+  setenv("SDL_VIDEODRIVER",_fshack,1);
+ else
+ {
+  if(!_fshacksave)
+   unsetenv("SDL_VIDEODRIVER");
+  else
+   setenv("SDL_VIDEODRIVER",_fshacksave,1);
+ }
+ #endif
+ if(SDL_InitSubSystem(SDL_INIT_VIDEO)==-1)
+ {
+  puts(SDL_GetError());
+  return(0);
+ }
+ inited|=1;
+
+ SDL_ShowCursor(0);
+ tlines=_eline-_sline+1;
+
+ vinf=SDL_GetVideoInfo();
+
+ if(vinf->hw_available)
+  flags|=SDL_HWSURFACE;
+
+ if(_fullscreen)
+  flags|=SDL_FULLSCREEN;
+ flags|=SDL_HWPALETTE;
+
+ if(_fullscreen)
+ {
+  exs=_xscalefs;
+  eys=_yscalefs;
+  eefx=_efxfs;
+  if(_xres<NWIDTH*exs || _yres<tlines*eys)
+  {
+   puts("xscale and/or yscale out of bounds.");
+   KillVideo();
+   return(0);
+  }
+  screen = SDL_SetVideoMode(_xres, _yres, 8, flags);
+ }
+ else
+ {
+  exs=_xscale;
+  eys=_yscale;
+  eefx=_efx;
+  screen = SDL_SetVideoMode(NWIDTH*exs, tlines*eys, 8, flags);
+ }
+ if(!screen)
+ {
+  puts(SDL_GetError());
+  KillVideo();
+  return(0);
+ }
+ inited=1;
+ CleanSurface();
+
+ SDL_WM_SetCaption("FCE Ultra","FCE Ultra");
+ paletterefresh=1;
+ return 1;
+}
+
+void ToggleFS(void)
+{
+ KillVideo();
+ _fullscreen=!_fullscreen;
+
+ if(!InitVideo())
+ {
+  _fullscreen=!_fullscreen;
+  if(!InitVideo())
+  {
+   puts("Gah, bailing out.");
+   exit(1);
+  }
+ }
+}
+static SDL_Color psdl[256];
+
+void FCEUD_SetPalette(uint8 index, uint8 r, uint8 g, uint8 b)
+{
+
+ psdl[index].r=r;
+ psdl[index].g=g;
+ psdl[index].b=b;
+
+ paletterefresh=1;
+}
+
+void FCEUD_GetPalette(uint8 index, uint8 *r, uint8 *g, uint8 *b)
+{
+ *r=psdl[index].r;
+ *g=psdl[index].g;
+ *b=psdl[index].b;
+}
+
+static void RedoPalette(void)
+{
+ SDL_SetPalette(screen,SDL_PHYSPAL,psdl,0,256);
+}
+
+void LockConsole(){}
+void UnlockConsole(){}
+void BlitScreen(uint8 *XBuf)
+{
+ uint8 *dest;
+ int xo=0,yo=0;
+
+ if(paletterefresh)
+ {
+  RedoPalette();
+  paletterefresh=0;
+ }
+
+ XBuf+=_sline*272;
+
+ if(SDL_MUSTLOCK(screen))
+  SDL_LockSurface(screen);
+
+ dest=screen->pixels;
+
+ if(_fullscreen)
+ {
+  xo=(((screen->w-NWIDTH*exs))>>1);
+  dest+=xo;
+  if(screen->h>(tlines*eys))
+  {
+   yo=((screen->h-tlines*eys)>>1);
+   dest+=yo*screen->pitch;
+  }
+ }
+
+ Blit8To8(XBuf+NOFFSET,dest, NWIDTH, tlines, screen->pitch,exs,eys,eefx);
+
+ if(SDL_MUSTLOCK(screen))
+  SDL_UnlockSurface(screen);
+
+ SDL_UpdateRect(screen, xo, yo, NWIDTH*exs, tlines*eys);
+}
+
+uint32 PtoV(uint16 x, uint16 y)
+{
+ if(_fullscreen)
+ {
+
+ }
+ else
+ {
+  if(eoptions&EO_CLIPSIDES)
+   x+=8;
+  y+=srendline;
+ }
+ return(x|(y<<16));
+}
diff --git a/drivers/cli/sdl-video.h b/drivers/cli/sdl-video.h
new file mode 100644 (file)
index 0000000..036c933
--- /dev/null
@@ -0,0 +1 @@
+uint32 PtoV(uint16 x, uint16 y);
diff --git a/drivers/cli/sdl.c b/drivers/cli/sdl.c
new file mode 100644 (file)
index 0000000..dfa5d40
--- /dev/null
@@ -0,0 +1,215 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sdl.h"
+#include "sdl-video.h"
+#ifdef NETWORK
+#include "unix-netplay.h"
+#endif
+
+DSETTINGS Settings;
+CFGSTRUCT DriverConfig[]={
+       AC(_xscale),
+       AC(_yscale),
+       AC(_xscalefs),
+       AC(_yscalefs),
+       AC(_efx),
+       AC(_efxfs),
+        AC(_sound),
+       #ifdef DSPSOUND
+        AC(_f8bit),
+       #else
+       AC(_ebufsize),
+       AC(_lbufsize),
+       #endif
+       AC(_fullscreen),
+        AC(_xres),
+       AC(_yres),
+        ACA(joyBMap),
+       ACA(joyAMap),
+        ACA(joy),
+        //ACS(_fshack),
+        ENDCFGSTRUCT
+};
+
+//-fshack x       Set the environment variable SDL_VIDEODRIVER to \"x\" when
+//                entering full screen mode and x is not \"0\".
+
+char *DriverUsage=
+"-xres   x       Set horizontal resolution to x for full screen mode.\n\
+-yres   x       Set vertical resolution to x for full screen mode.\n\
+-xscale(fs) x  Multiply width by x.\n\
+-yscale(fs) x  Multiply height by x.\n\
+-efx(fs) x     Enable scanlines effect if x is non zero.  yscale must be >=2\n\
+               and preferably a multiple of 2.\n\
+-fs     x      Select full screen mode if x is non zero.\n\
+-joyx   y       Use joystick y as virtual joystick x.\n\
+-sound x        Sound.\n\
+                 0 = Disabled.\n\
+                 Otherwise, x = playback rate.\n\
+"
+#ifdef DSPSOUND
+"-f8bit x        Force 8-bit sound.\n\
+                 0 = Disabled.\n\
+                 1 = Enabled.\n\
+"
+#else
+"-lbufsize x   Internal FCE Ultra sound buffer size. Size = 2^x samples.\n\
+-ebufsize x    External SDL sound buffer size. Size = 2^x samples.\n\
+"
+#endif
+"-connect s      Connect to server 's' for TCP/IP network play.\n\
+-server         Be a host/server for TCP/IP network play.\n\
+-netport x      Use TCP/IP port x for network play.";
+
+static int docheckie[2]={0,0};
+ARGPSTRUCT DriverArgs[]={
+         {"-joy1",0,&joy[0],0},{"-joy2",0,&joy[1],0},
+         {"-joy3",0,&joy[2],0},{"-joy4",0,&joy[3],0},
+        {"-xscale",0,&_xscale,0},
+        {"-yscale",0,&_yscale,0},
+        {"-efx",0,&_efx,0},
+         {"-xscalefs",0,&_xscalefs,0},
+         {"-yscalefs",0,&_yscalefs,0},
+         {"-efxfs",0,&_efxfs,0},
+        {"-xres",0,&_xres,0},
+         {"-yres",0,&_yres,0},
+         {"-fs",0,&_fullscreen,0},
+         //{"-fshack",0,&_fshack,0x4001},
+         {"-sound",0,&_sound,0},
+        #ifdef DSPSOUND
+         {"-f8bit",0,&_f8bit,0},
+        #else
+        {"-lbufsize",0,&_lbufsize,0},
+        {"-ebufsize",0,&_ebufsize,0},
+        #endif
+        #ifdef NETWORK
+         {"-connect",&docheckie[0],&netplayhost,0x4001},
+         {"-server",&docheckie[1],0,0},
+         {"-netport",0,&Port,0},
+        #endif
+         {0,0,0,0}
+};
+
+static void SetDefaults(void)
+{
+ _xres=320;
+ _yres=240;
+ _fullscreen=0;
+ _sound=48000;
+ #ifdef DSPSOUND
+ _f8bit=0;
+ #else
+ _lbufsize=10;
+ _ebufsize=8;
+ #endif
+ _xscale=_yscale=_xscalefs=_yscalefs=1;
+ _efx=_efxfs=0;
+ //_fshack=_fshacksave=0;
+ memset(joy,0,sizeof(joy));
+}
+
+void DoDriverArgs(void)
+{
+        int x;
+
+       #ifdef BROKEN
+        if(_fshack)
+        {
+         if(_fshack[0]=='0')
+          if(_fshack[1]==0)
+          {
+           free(_fshack);
+           _fshack=0;
+          }
+        }
+       #endif
+
+       #ifdef NETWORK
+        if(docheckie[0])
+         netplay=2;
+        else if(docheckie[1])
+         netplay=1;
+
+        if(netplay)
+         FCEUI_SetNetworkPlay(netplay);
+       #endif
+
+        for(x=0;x<4;x++)
+         if(!joy[x]) 
+        {
+         memset(joyBMap[x],0,sizeof(joyBMap[0]));
+         memset(joyAMap[x],0,sizeof(joyAMap[0]));
+        }
+}
+int InitMouse(void)
+{
+ return(0);
+}
+void KillMouse(void){}
+void GetMouseData(uint32 *d)
+{
+ int x,y;
+ uint32 t;
+
+ t=SDL_GetMouseState(&x,&y);
+ d[2]=0;
+ if(t&SDL_BUTTON(1))
+  d[2]|=1;
+ if(t&SDL_BUTTON(3))
+  d[2]|=2;
+ t=PtoV(x,y); 
+ d[0]=t&0xFFFF;
+ d[1]=(t>>16)&0xFFFF;
+}
+
+int InitKeyboard(void)
+{
+ return(1);
+}
+
+int UpdateKeyboard(void)
+{
+ return(1);
+}
+
+void KillKeyboard(void)
+{
+
+}
+
+char *GetKeyboard(void)
+{
+ SDL_PumpEvents();
+ return(SDL_GetKeyState(0));
+}
+#include "unix-basedir.h"
+
+int main(int argc, char *argv[])
+{
+        puts("\nStarting FCE Ultra "VERSION_STRING"...\n");
+       if(SDL_Init(0))
+       {
+        printf("Could not initialize SDL: %s.\n", SDL_GetError());
+        return(-1);
+       }
+       SetDefaults();
+
+       #ifdef BROKEN
+        if(getenv("SDL_VIDEODRIVER"))
+       {
+        if((_fshacksave=malloc(strlen(getenv("SDL_VIDEODRIVER"))+1)))
+         strcpy(_fshacksave,getenv("SDL_VIDEODRIVER"));
+       }
+        else
+         _fshacksave=0;
+       #endif
+
+       {
+        int ret=CLImain(argc,argv);
+        SDL_Quit();
+        return(ret);
+       }
+}
+
diff --git a/drivers/cli/sdl.h b/drivers/cli/sdl.h
new file mode 100644 (file)
index 0000000..a235951
--- /dev/null
@@ -0,0 +1,47 @@
+#include <SDL.h>
+#include "../../driver.h"
+#include "../common/args.h"
+#include "../common/config.h"
+#include "main.h"
+
+typedef struct {
+        int xres;
+        int yres;
+       int xscale,yscale;
+       int xscalefs,yscalefs;
+       int efx,efxfs;
+        int fullscreen;
+       int sound;
+       #ifdef DSPSOUND
+       int f8bit;
+       #else
+       int lbufsize,ebufsize;
+       #endif
+       int joy[4];
+       int joyAMap[4][2];
+       int joyBMap[4][4];
+       char *fshack;
+       char *fshacksave;
+} DSETTINGS;
+
+extern DSETTINGS Settings;
+
+#define _xres Settings.xres
+#define _yres Settings.yres
+#define _fullscreen Settings.fullscreen
+#define _sound Settings.sound
+#define _f8bit Settings.f8bit
+#define _xscale Settings.xscale
+#define _yscale Settings.yscale
+#define _xscalefs Settings.xscalefs
+#define _yscalefs Settings.yscalefs
+#define _efx Settings.efx
+#define _efxfs Settings.efxfs
+#define _ebufsize Settings.ebufsize
+#define _lbufsize Settings.lbufsize
+#define _fshack Settings.fshack
+#define _fshacksave Settings.fshacksave
+
+#define joyAMap Settings.joyAMap
+#define joyBMap Settings.joyBMap
+#define joy    Settings.joy
diff --git a/drivers/cli/svga-video.c b/drivers/cli/svga-video.c
new file mode 100644 (file)
index 0000000..67f4ecb
--- /dev/null
@@ -0,0 +1,497 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 \Firebug\
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <vga.h>
+#include <sys/io.h>
+
+#define inportb inb
+#define outportb(port, value) outb(value, port)
+#define outportw(port, value) outw(value, port)
+
+#include "main.h"
+#include "svgalib.h"
+#include "svga-video.h"
+
+
+int vmode=1;
+
+#ifdef FRAMESKIP
+int FCEUDfskip=0;
+#endif
+
+static int vidready=0;
+static int conlock=0;
+
+void LockConsole(void)
+{
+ if(!conlock)
+ {
+  vga_lockvc();
+  conlock=1;
+  FCEUI_DispMessage("Console locked.");
+ }
+}
+
+void UnlockConsole(void)
+{
+ if(conlock)
+ {
+  vga_unlockvc();
+  conlock=0;
+  FCEUI_DispMessage("Console unlocked.");
+ }
+}
+
+void SetBorder(void)
+{
+ if(!conlock) 
+  vga_lockvc();
+ inportb(0x3da);
+ outportb(0x3c0,(0x11|0x20));
+ outportb(0x3c0,0x80);
+ if(!conlock) 
+  vga_unlockvc();
+}
+
+#include "vgatweak.c"
+
+void TweakVGA(int VGAMode)
+{
+  int I;
+
+  if(!conlock)
+   vga_lockvc();
+
+  outportb(0x3C8,0x00);
+  for(I=0;I<768;I++) outportb(0x3C9,0x00);
+
+  outportb(0x3D4,0x11);
+  I=inportb(0x3D5)&0x7F;
+  outportb(0x3D4,0x11);
+  outportb(0x3D5,I);
+
+  switch(VGAMode)
+  {
+    case 1:  for(I=0;I<25;I++) VGAPortSet(v256x240[I]);break;
+    case 2:  for(I=0;I<25;I++) VGAPortSet(v256x256[I]);break;
+    case 3:  for(I=0;I<25;I++) VGAPortSet(v256x256S[I]);break;
+    case 6:  for(I=0;I<25;I++) VGAPortSet(v256x224S[I]);break;
+    case 8:  for(I=0;I<25;I++) VGAPortSet(v256x224_103[I]);break;
+    default: break;
+  }
+
+  outportb(0x3da,0);
+  if(!conlock) 
+   vga_unlockvc();
+}
+
+
+static uint8 palettedbr[256],palettedbg[256],palettedbb[256];
+
+static void FlushPalette(void)
+{
+ int x;
+ for(x=0;x<256;x++)
+ {
+  int z=x;
+  if(vmode==4 || vmode==5 || vmode==7) z^=0x80;
+  vga_setpalette(z,palettedbr[x]>>2,palettedbg[x]>>2,palettedbb[x]>>2);
+ }
+}
+
+void FCEUD_SetPalette(uint8 index, uint8 r, uint8 g, uint8 b)
+{
+  palettedbr[index]=r;
+  palettedbg[index]=g;
+  palettedbb[index]=b;
+
+  if(vidready)
+  {
+   if(vmode==4 || vmode==5 || vmode==7) index^=0x80;
+   vga_setpalette(index,r>>2,g>>2,b>>2);
+  }
+}
+
+
+void FCEUD_GetPalette(uint8 i, uint8 *r, uint8 *g, uint8 *b)
+{
+ *r=palettedbr[i];
+ *g=palettedbg[i];
+ *b=palettedbb[i];
+}
+
+static void vcfix(void)
+{
+ int z;
+
+ if(!conlock)
+  vga_lockvc();
+ z=inportb(0x3cc);
+ if(!conlock) 
+  vga_unlockvc();
+ if(z!=0xe3 && z!=0xe7)                // Common value in all tweaked video modes(and not in 320x200 mode).
+ {
+  TweakVGA(vmode);
+  SetBorder();
+  FlushPalette();
+ }
+}
+
+static uint8 *ScreenLoc;
+
+int InitVideo(void)
+{
+ #ifdef DUMMY
+ return(1);
+ #endif
+ vidready=0;
+
+ if(vmode<=3 || vmode==6 || vmode==8)
+ {
+  if(vga_getcurrentchipset()==FBDEV)
+  {
+   puts("Tweaked VGA video modes will not work.  Using a 320x240 video mode instead...");
+   vmode=7;
+  }
+ }
+
+ switch(vmode)
+ {
+  default:
+  case 1:
+  case 2:
+  case 3:
+  case 6:
+  case 8:
+        vga_setmode(G320x200x256);
+        vidready|=1;
+         ScreenLoc=vga_getgraphmem();
+         TweakVGA(vmode);
+         SetBorder();
+         memset(ScreenLoc,128,256*256);
+         break;
+  case 4:
+  case 5:
+         if(!(vga_getmodeinfo(G640x480x256)->flags & CAPABLE_LINEAR))
+         {
+          puts("Video:  No linear addressing mode available!");
+          return 0;
+         }
+         if(vga_setmode(G640x480x256)==-1)
+         {
+          puts("Video:  Could not set 640x480x8bpp video mode!");
+          return 0;
+         }
+        vidready|=1;
+
+         vga_setpage(0);
+         if(vga_setlinearaddressing()!=-1)
+          ScreenLoc=vga_getgraphmem();
+         else
+         {
+          puts("Video:  Could not set linear addressing!");
+          return 0;
+         }
+         memset(ScreenLoc,0,640*480);
+         break;
+  case 7:
+         if(!(vga_getmodeinfo(G320x240x256V)->flags & CAPABLE_LINEAR))
+         {
+          puts("Video:  No linear addressing mode available!");
+          return 0;
+         }
+         if(vga_setmode(G320x240x256V)==-1)
+         {
+          puts("Video:  Could not set 320x240x8bpp video mode!");
+          return 0;
+         }
+         vidready|=1;
+
+         vga_setpage(0);
+         if(vga_setlinearaddressing()!=-1)
+          ScreenLoc=vga_getgraphmem();
+         else
+         {
+          puts("Video:  Could not set linear addressing!");
+          return 0;
+         }
+         memset(ScreenLoc,0,320*240);
+         break;
+ }
+ vidready|=2;
+ FlushPalette(); // Needed for cheat console code(and it isn't a bad thing to do anyway...).
+ return 1;
+}
+
+void KillVideo(void)
+{
+ if(vidready)
+ {
+  vga_setmode(TEXT);
+  vidready=0;
+ }
+}
+
+
+void BlitScreen(uint8 *XBuf)
+{
+ static int conto=0;
+ uint8 *dest;
+ int tlines;
+ #ifdef DUMMY
+ return;
+ #endif
+ #ifdef FRAMESKIP
+ FCEUI_FrameSkip(FCEUDfskip);
+ #endif
+
+ if(doptions&DO_VSYNC && !NoWaiting)
+ {
+  vga_waitretrace();
+ }
+
+ tlines=erendline-srendline+1;
+
+ dest=ScreenLoc;
+
+ if(vmode!=4 && vmode!=5 && vmode!=7)
+ {
+  conto=(conto+1)&0x3F;
+  if(!conto) vcfix();
+ }
+ switch(vmode)
+ {
+  case 1:dest+=(((240-tlines)>>1)<<8);break;
+  case 2:
+  case 3:dest+=(((256-tlines)>>1)<<8);break;
+  case 4:
+  case 5:dest+=(((240-tlines)>>1)*640+((640-512)>>1));break;
+  case 8:
+  case 6:if(tlines>224) tlines=224;dest+=(((224-tlines)>>1)<<8);break;
+  case 7:dest+=(((240-tlines)>>1)*320)+32;break;
+ }
+
+ XBuf+=(srendline<<8)+(srendline<<4);
+
+ if(eoptions&EO_CLIPSIDES)
+ {
+  if(vmode==5)
+  {
+   asm volatile(
+     "xorl %%edx, %%edx\n\t"
+     "ckoop1:\n\t"
+     "movb $120,%%al     \n\t"
+     "ckoop2:\n\t"
+     "movb 1(%%esi),%%dl\n\t"
+     "shl  $16,%%edx\n\t"
+     "movb (%%esi),%%dl\n\t"
+     "xorl $0x00800080,%%edx\n\t"
+     "movl %%edx,(%%edi)\n\t"
+     "addl $2,%%esi\n\t"
+     "addl $4,%%edi\n\t"
+     "decb %%al\n\t"
+     "jne ckoop2\n\t"
+
+     "addl $32,%%esi\n\t"
+     "addl $800,%%edi\n\t"
+     "decb %%bl\n\t"
+     "jne ckoop1\n\t"
+     :
+     : "S" (XBuf+8), "D" (dest+8), "b" (tlines)
+     : "%al", "%edx", "%cc" );
+  }
+  else if(vmode==4)
+  {
+   asm volatile(
+     "cyoop1:\n\t"
+     "movb $120,%%al     \n\t"
+     "cyoop2:\n\t"
+     "movb 1(%%esi),%%dh\n\t"
+     "movb %%dh,%%dl\n\t"
+     "shl  $16,%%edx\n\t"
+     "movb (%%esi),%%dl\n\t"
+     "movb %%dl,%%dh\n\t"               // Ugh
+     "xorl $0x80808080,%%edx\n\t"
+     "movl %%edx,(%%edi)\n\t"
+     "addl $2,%%esi\n\t"
+     "addl $4,%%edi\n\t"
+     "decb %%al\n\t"
+     "jne cyoop2\n\t"
+
+     "addl $32,%%esi\n\t"
+     "addl $800,%%edi\n\t"
+     "decb %%bl\n\t"
+     "jne cyoop1\n\t"
+     :
+     : "S" (XBuf+8), "D" (dest+8), "b" (tlines)
+     : "%al", "%edx", "%cc" );
+  }
+  else if(vmode==7)
+  {
+   asm volatile(
+     "cgoop81:\n\t"
+     "movl $30,%%eax\n\t"
+     "cgoop82:\n\t"
+     "movl (%%esi),%%edx\n\t"
+     "movl 4(%%esi),%%ecx\n\t"
+     "xorl $0x80808080,%%edx\n\t"
+     "xorl $0x80808080,%%ecx\n\t"
+     "movl %%edx,(%%edi)\n\t"
+     "movl %%ecx,4(%%edi)\n\t"
+     "addl $8,%%esi\n\t"
+     "addl $8,%%edi\n\t"
+     "decl %%eax\n\t"
+     "jne cgoop82\n\t"
+     "addl $80,%%edi\n\t"
+     "addl $32,%%esi\n\t"
+     "decb %%bl\n\t"
+     "jne cgoop81\n\t"
+     :
+     : "S" (XBuf+8), "D" (dest+8), "b" (tlines)
+     : "%eax","%cc","%edx","%ecx" );
+  }
+  else
+  {
+   asm volatile(
+     "cgoop1:\n\t"
+     "movl $30,%%eax\n\t"
+     "cgoop2:\n\t"
+     "movl (%%esi),%%edx\n\t"
+     "movl 4(%%esi),%%ecx\n\t"
+     "movl %%edx,(%%edi)\n\t"
+     "movl %%ecx,4(%%edi)\n\t"
+     "addl $8,%%esi\n\t"
+     "addl $8,%%edi\n\t"
+     "decl %%eax\n\t"
+     "jne cgoop2\n\t"
+     "addl $32,%%esi\n\t"
+     "addl $16,%%edi\n\t"
+     "decb %%bl\n\t"
+     "jne cgoop1\n\t"
+     :
+     : "S" (XBuf+8), "D" (dest+8), "b" (tlines)
+     : "%eax","%cc","%edx","%ecx" );
+  }
+ }
+ else
+ {
+  if(vmode==5)
+  {
+   asm volatile(
+     "xorl %%edx, %%edx\n\t"
+     "koop1:\n\t"
+     "movb $128,%%al     \n\t"
+     "koop2:\n\t"
+     "movb 1(%%esi),%%dl\n\t"
+     "shl  $16,%%edx\n\t"
+     "movb (%%esi),%%dl\n\t"
+     "xorl $0x00800080,%%edx\n\t"
+     "movl %%edx,(%%edi)\n\t"
+     "addl $2,%%esi\n\t"
+     "addl $4,%%edi\n\t"
+     "decb %%al\n\t"
+     "jne koop2\n\t"
+
+     "addl $16,%%esi\n\t"
+     "addl $768,%%edi\n\t"
+     "decb %%bl\n\t"
+     "jne koop1\n\t"
+     :
+     : "S" (XBuf), "D" (dest), "b" (tlines)
+     : "%al", "%edx", "%cc" );
+  }
+  else if(vmode==4)
+  {
+   asm volatile(
+     "yoop1:\n\t"
+     "movb $128,%%al     \n\t"
+     "yoop2:\n\t"
+     "movb 1(%%esi),%%dh\n\t"
+     "movb %%dh,%%dl\n\t"
+     "shl  $16,%%edx\n\t"
+     "movb (%%esi),%%dl\n\t"
+     "movb %%dl,%%dh\n\t"               // Ugh
+     "xorl $0x80808080,%%edx\n\t"
+     "movl %%edx,(%%edi)\n\t"
+     "addl $2,%%esi\n\t"
+     "addl $4,%%edi\n\t"
+     "decb %%al\n\t"
+     "jne yoop2\n\t"
+
+     "addl $16,%%esi\n\t"
+     "addl $768,%%edi\n\t"
+     "decb %%bl\n\t"
+     "jne yoop1\n\t"
+     :
+     : "S" (XBuf), "D" (dest), "b" (tlines)
+     : "%al", "%edx", "%cc" );
+  }
+  else if(vmode==7)
+  {
+   asm volatile(
+     "goop81:\n\t"
+     "movl $32,%%eax\n\t"
+     "goop82:\n\t"
+     "movl (%%esi),%%edx\n\t"
+     "movl 4(%%esi),%%ecx\n\t"
+     "xorl $0x80808080,%%edx\n\t"
+     "xorl $0x80808080,%%ecx\n\t"
+     "movl %%edx,(%%edi)\n\t"
+     "movl %%ecx,4(%%edi)\n\t"
+     "addl $8,%%esi\n\t"
+     "addl $8,%%edi\n\t"
+     "decl %%eax\n\t"
+     "jne goop82\n\t"
+     "addl $64,%%edi\n\t"
+     "addl $16,%%esi\n\t"
+     "decb %%bl\n\t"
+     "jne goop81\n\t"
+     :
+     : "S" (XBuf), "D" (dest), "b" (tlines)
+     : "%eax","%cc","%edx","%ecx" );
+  }
+  else
+  {
+   asm volatile(
+     "goop1:\n\t"
+     "movl $32,%%eax\n\t"
+     "goop2:\n\t"
+     "movl (%%esi),%%edx\n\t"
+     "movl 4(%%esi),%%ecx\n\t"
+     "movl %%edx,(%%edi)\n\t"
+     "movl %%ecx,4(%%edi)\n\t"
+     "addl $8,%%esi\n\t"
+     "addl $8,%%edi\n\t"
+     "decl %%eax\n\t"
+     "jne goop2\n\t"
+     "addl $16,%%esi\n\t"
+     "decb %%bl\n\t"
+     "jne goop1\n\t"
+     :
+     : "S" (XBuf), "D" (dest), "b" (tlines)
+     : "%eax","%cc","%edx","%ecx" );
+  }
+ }
+}
+
+
diff --git a/drivers/cli/svga-video.h b/drivers/cli/svga-video.h
new file mode 100644 (file)
index 0000000..e0a991b
--- /dev/null
@@ -0,0 +1,32 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+extern int vmode;
+
+#ifdef FRAMESKIP
+extern int FCEUDfskip;
+#endif
+
+void LockConsole(void);
+void UnlockConsole(void);
+int InitVideo(void);
+void KillVideo(void);
+void FCEUD_BlitScreen(uint8 *XBuf);
+
diff --git a/drivers/cli/svgalib.c b/drivers/cli/svgalib.c
new file mode 100644 (file)
index 0000000..7d293e9
--- /dev/null
@@ -0,0 +1,178 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vga.h>
+#include <vgamouse.h>
+#include <vgakeyboard.h>
+
+#include "../../driver.h"
+#include "../common/args.h"
+#include "../common/config.h"
+#include "../common/unixdsp.h"
+
+#include "svgalib.h"
+#include "svga-video.h"
+#include "lnx-joystick.h"
+#include "unix-netplay.h"
+
+static int soundo=48000;
+static int f8bit=0;
+static int sfragsize=7,snfrags=8;
+
+int doptions=0;
+
+CFGSTRUCT DriverConfig[]={
+        NAC("sound",soundo),
+       AC(doptions),
+        AC(f8bit),
+        AC(vmode),
+        NACA("joybmap",joyBMap),
+        ACA(joy),
+        AC(snfrags),
+        AC(sfragsize),
+       ENDCFGSTRUCT
+};
+
+
+char *DriverUsage=
+"-vmode x        Select video mode(all are 8 bpp).\n\
+                 1 = 256x240                 5 = 640x480(\"1 per 4\")\n\
+                 2 = 256x256                 6 = 256x224(with scanlines)\n\
+                 3 = 256x256(with scanlines) 7 = 320x240\n\
+                 4 = 640x480(with scanlines) 8 = 256x224\n\
+-vsync x        Wait for the screen's vertical retrace before updating the\n\
+                screen.  Refer to the documentation for caveats.\n\
+                 0 = Disabled.\n\
+                 1 = Enabled.\n\
+-joyx y         Joystick mapped to virtual joystick x(1-4).\n\
+                 0 = Disabled, reset configuration.\n\
+                 Otherwise, y(1-inf) = joystick number.\n\
+-sound x        Sound.\n\
+                 0 = Disabled.\n\
+                 Otherwise, x = playback rate.\n\
+-sfragsize x    Set sound fragment size to 2^x samples.\n\
+-snfrags x      Set number of sound fragments to x.\n\
+-f8bit x        Force 8-bit sound.\n\
+                 0 = Disabled.\n\
+                 1 = Enabled.\n\
+-connect s      Connect to server 's' for TCP/IP network play.\n\
+-server         Be a host/server for TCP/IP network play.\n\
+-netport x      Use TCP/IP port x for network play.";
+
+
+static int docheckie[2]={0,0};
+ARGPSTRUCT DriverArgs[]={
+         {"-joy1",0,&joy[0],0},{"-joy2",0,&joy[1],0},
+         {"-joy3",0,&joy[2],0},{"-joy4",0,&joy[3],0},
+         {"-snfrags",0,&snfrags,0},{"-sfragsize",0,&sfragsize,0},
+        {"-vmode",0,&vmode,0},
+         {"-vsync",0,&doptions,0x8000|DO_VSYNC},
+        {"-sound",0,&soundo,0},
+         {"-f8bit",0,&f8bit,0},
+         {"-connect",&docheckie[0],&netplayhost,0x4001},
+         {"-server",&docheckie[1],0,0},
+         {"-netport",0,&Port,0},
+        {0,0,0,0}
+};
+
+void DoDriverArgs(void)
+{
+       int x;
+
+        if(docheckie[0])
+         netplay=2;
+        else if(docheckie[1])
+         netplay=1;
+
+        if(netplay)
+         FCEUI_SetNetworkPlay(netplay);
+
+        for(x=0;x<4;x++)
+         if(!joy[x]) memset(joyBMap[x],0,4*sizeof(int));
+}
+
+int InitSound(void)
+{
+        if(soundo)
+        {
+         int rate;
+         if(soundo==1)
+          soundo=48000;
+         rate=soundo;
+         if(InitUNIXDSPSound(&rate,f8bit?0:1,sfragsize,snfrags))
+        {
+         FCEUI_Sound(rate);
+         return(1);
+        }
+        }
+       return(0);
+}
+
+void WriteSound(int32 *Buffer, int Count, int NoWaiting)
+{
+       WriteUNIXDSPSound(Buffer,Count,NoWaiting);
+}
+
+void KillSound(void)
+{
+       KillUNIXDSPSound();
+}
+
+int InitMouse(void)
+{
+    vga_setmousesupport(1);
+    mouse_setxrange(0,260);
+    mouse_setyrange(0,260);
+    mouse_setscale(1);
+    return(1);
+}
+
+void KillMouse(void)
+{
+ mouse_close();
+}
+
+void GetMouseData(uint32 *MouseData)
+{
+ int z;
+ mouse_update();
+ MouseData[0]=mouse_getx();
+ MouseData[1]=mouse_gety();
+ z=mouse_getbutton();
+ MouseData[2]=((z&MOUSE_LEFTBUTTON)?1:0)|((z&MOUSE_RIGHTBUTTON)?2:0);
+}
+
+#include "unix-basedir.h"
+
+int InitKeyboard(void)
+{
+  if(keyboard_init()==-1)
+  {
+   puts("Error initializing keyboard.");
+   return 0;
+  }
+  keyboard_translatekeys(TRANSLATE_CURSORKEYS | TRANSLATE_DIAGONAL);
+  return 1;
+}
+
+int UpdateKeyboard(void)
+{
+ return(keyboard_update());
+}
+
+char *GetKeyboard(void)
+{
+ return(keyboard_getstate());
+}
+
+void KillKeyboard(void)
+{
+ keyboard_close();
+}
+
+int main(int argc, char *argv[])
+{
+        puts("\nStarting FCE Ultra "VERSION_STRING"...\n");
+        vga_init();
+       return(CLImain(argc,argv));
+}
diff --git a/drivers/cli/svgalib.h b/drivers/cli/svgalib.h
new file mode 100644 (file)
index 0000000..8f18b74
--- /dev/null
@@ -0,0 +1,2 @@
+#define DO_VSYNC        1
+extern int doptions;
diff --git a/drivers/cli/throttle.c b/drivers/cli/throttle.c
new file mode 100644 (file)
index 0000000..604cef7
--- /dev/null
@@ -0,0 +1,41 @@
+#include <sys/time.h>
+#include "main.h"
+#include "throttle.h"
+
+static uint64 tfreq;
+static uint64 desiredfps;
+
+void RefreshThrottleFPS(void)
+{
+ desiredfps=FCEUI_GetDesiredFPS()>>8;
+ tfreq=1000000;
+ tfreq<<=16;    /* Adjustment for fps returned from FCEUI_GetDesiredFPS(). */
+}
+
+static uint64 GetCurTime(void)
+{
+ uint64 ret;
+ struct timeval tv;
+
+ gettimeofday(&tv,0);
+ ret=(uint64)tv.tv_sec*1000000;
+ ret+=tv.tv_usec;
+ return(ret);
+}
+
+void SpeedThrottle(void)
+{
+ static uint64 ttime,ltime;
+
+ waiter:
+
+ ttime=GetCurTime();
+
+ if( (ttime-ltime) < (tfreq/desiredfps) )
+  goto waiter;
+ if( (ttime-ltime) >= (tfreq*4/desiredfps))
+  ltime=ttime;
+ else
+  ltime+=tfreq/desiredfps;
+}
+
diff --git a/drivers/cli/throttle.h b/drivers/cli/throttle.h
new file mode 100644 (file)
index 0000000..0b0ad9f
--- /dev/null
@@ -0,0 +1,2 @@
+void RefreshThrottleFPS(void);
+void SpeedThrottle(void);
diff --git a/drivers/cli/unix-basedir.h b/drivers/cli/unix-basedir.h
new file mode 100644 (file)
index 0000000..4f6808c
--- /dev/null
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+void GetBaseDirectory(char *BaseDirectory)
+{
+ char *ol;
+
+ ol=getenv("HOME");
+ BaseDirectory[0]=0;
+ if(ol)
+ {
+  strncpy(BaseDirectory,ol,2047);
+  BaseDirectory[2047]=0;
+  strcat(BaseDirectory,"/.fceultra");
+ }
+}
+
diff --git a/drivers/cli/unix-netplay.c b/drivers/cli/unix-netplay.c
new file mode 100644 (file)
index 0000000..d5d1cc4
--- /dev/null
@@ -0,0 +1,158 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <errno.h>
+
+#ifndef socklen_t
+#define socklen_t int
+#endif
+
+static int Socket=-1;
+#include "main.h"
+#include "unix-netplay.h"
+
+char *netplayhost=0;
+int Port=0xFCE;
+int netplay=0;
+
+int FCEUD_NetworkConnect(void)
+{
+ struct sockaddr_in sockn;
+ int TSocket;
+
+ memset(&sockn,0,sizeof(sockn));
+ sockn.sin_family=AF_INET;
+ sockn.sin_port=htons(Port);
+
+ if((TSocket=socket(AF_INET, SOCK_STREAM, 0))<0)
+ {
+  puts("Error creating socket.");
+  return(0);
+ }
+
+ if(netplay==1)                /* Be a server. */
+ {
+  sockn.sin_addr.s_addr=INADDR_ANY;
+  if(bind(TSocket, (struct sockaddr *)&sockn, sizeof(sockn))<0)
+  {
+   close(TSocket);
+   puts("Error binding to socket."); 
+   return(0);
+  }
+  if(listen(TSocket, 1)<0)
+  {
+   puts("Error listening on socket.");
+   close(TSocket);
+   return(0);
+  }
+  {
+   socklen_t len=sizeof(sockn);
+     
+   printf("Accepting connection on port %d...\n",Port);
+   if((Socket=accept(TSocket,(struct sockaddr *)&sockn,&len))<0 )
+   {
+    puts("Error accepting a connection.");
+    close(TSocket);
+    return(0);
+   }
+   close(TSocket);
+  }
+
+ }
+ else /* Connect as a client if not a server. */
+ {
+  struct hostent *Host;
+
+  if((sockn.sin_addr.s_addr=inet_addr(netplayhost))==INADDR_NONE)
+  {
+   if(!(Host=gethostbyname(netplayhost)))
+   {
+    puts("Error getting network host entry.");
+    return(0);
+   }
+   memcpy(&sockn.sin_addr,Host->h_addr,Host->h_length);
+  }  
+  printf("Attempting to connect to %s...\n",netplayhost);
+  if( connect(TSocket, (struct sockaddr *)&sockn, sizeof(sockn)) <0 )
+  {
+   puts("Error connecting to remote host.");
+   close(TSocket);
+   return(0);
+  }
+  Socket=TSocket;
+ }
+ return(1);  
+}
+
+/* 0 on failure, 1 on success, -1 if it would block and blocking is not
+   specified.
+*/
+
+int FCEUD_NetworkRecvData(uint8 *data, uint32 len, int block)
+{
+  if(block)
+  {
+   int t;
+   uint8 temp[32];
+   t=recv(Socket,temp,32,MSG_PEEK|MSG_DONTWAIT);
+   if(t==-1)
+   {
+    if(errno!=EAGAIN) return(0);
+   }
+   else if(t==32)
+    NoWaiting|=2;
+   else
+    NoWaiting&=~2;
+   return(recv(Socket,data,len,0)==len);
+  }
+  else
+  {
+   int t=recv(Socket,data,len,MSG_DONTWAIT);
+   if(t==-1)
+   {
+    if(errno==EAGAIN)   // Would block
+     return(-1);
+    return(0);
+   }
+   return(1);
+  }
+}
+
+/* 0 on failure, 1 on success.  This function should always block. */
+
+int FCEUD_NetworkSendData(uint8 *Value, uint32 len)
+{
+ return(send(Socket,Value,len,0)==len);
+}
+
+void FCEUD_NetworkClose(void)
+{
+ if(Socket>0)
+  close(Socket);
+ Socket=-1;
+}
+
diff --git a/drivers/cli/unix-netplay.h b/drivers/cli/unix-netplay.h
new file mode 100644 (file)
index 0000000..48769f6
--- /dev/null
@@ -0,0 +1,5 @@
+extern char *netplayhost;
+extern int Port;
+extern int FDnetplay;
+#define netplay FDnetplay
+
diff --git a/drivers/cli/usage.h b/drivers/cli/usage.h
new file mode 100644 (file)
index 0000000..425a907
--- /dev/null
@@ -0,0 +1,56 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+void ShowUsage(char *prog)
+{
+printf("\nUsage is as follows:\n%s <options> filename\n\n",prog);
+puts("Options:");
+puts(DriverUsage);
+puts("-cpalette x     Load a custom global palette from file x.\n\
+-ntsccol x      Emulate an NTSC's TV's colors.\n\
+                 0 = Disabled.\n\
+                 1 = Enabled.\n\
+-pal            Emulate a PAL NES.\n\
+-soundvol x    Sound volume. x is an integral percentage value.\n\
+-inputx str    Select device mapped to virtual input port x(1-2).\n\
+                str may be: none, gamepad, zapper, powerpada, powerpadb,\n\
+                            arkanoid\n\
+-fcexp str     Select Famicom expansion port device.\n\
+                str may be: none, shadow, arkanoid, 4player, fkb\n\
+-nofs x                Disables Four-Score emulation if x is 1.\n\
+-gg             Enable Game Genie emulation.\n\
+-no8lim x       Disables the 8 sprites per scanline limitation.\n\
+                 0 = Limitation enabled.\n\
+                 1 = Limitation disabled.\n\
+-subase x       Save extra game data files under the base directory if enabled.\n\
+                 0 = Disabled.\n\
+                1 = Enabled.\n\
+-snapname x    Selects what type of file name snapshots will have.\n\
+                0 = Numeric(0.png)\n\
+                1 = File base and numeric(mario-0.png)\n\
+-nothrottle x  Disable artificial speed throttling if x is non-zero.\n\
+-clipsides x   Clip leftmost and rightmost 8 columns of pixels of video output.\n\
+                 0 = No clipping.\n\
+                 1 = Clipping.\n\
+-slstart x     Set the first drawn emulated scanline.  Valid values for x are\n\
+               0 through 239.\n\
+-slend x       Set the last drawn emulated scanline.  Valid values for x are\n\
+               0 through 239.");
+}
diff --git a/drivers/cli/vgatweak.c b/drivers/cli/vgatweak.c
new file mode 100644 (file)
index 0000000..a04cf94
--- /dev/null
@@ -0,0 +1,168 @@
+/* This file is "#include"d from dos-video.c and svga-video.c */
+
+typedef struct {
+  uint8 p;
+  uint8 i;
+  uint8 v;
+} vgareg;
+
+vgareg v256x224_103[25] =
+{
+        { 0xc2, 0x0, 0xe7},
+        { 0xd4, 0x0, 0x45},
+        { 0xd4, 0x1, 0x3f},
+        { 0xd4, 0x2, 0x40},
+        { 0xd4, 0x3, 0x86},
+        { 0xd4, 0x4, 0x3f},
+        { 0xd4, 0x5, 0x10},
+        { 0xd4, 0x6, 0xcd},
+        { 0xd4, 0x7, 0x1f},
+        { 0xd4, 0x8, 0x0},
+        { 0xd4, 0x9, 0x41},
+        { 0xd4, 0x10, 0xc0},
+        { 0xd4, 0x11, 0xac},
+        { 0xd4, 0x12, 0xbf},
+        { 0xd4, 0x13, 0x20},
+        { 0xd4, 0x14, 0x40},    //
+        { 0xd4, 0x15, 0xe7},
+        { 0xd4, 0x16, 0x06},    //
+        { 0xd4, 0x17, 0xa3},
+        { 0xc4, 0x1, 0x1},
+        { 0xc4, 0x4, 0xe},      //
+        { 0xce, 0x5, 0x40},
+        { 0xce, 0x6, 0x5},
+        { 0xc0, 0x10, 0x41},
+        { 0xc0, 0x13, 0x0},
+};
+
+vgareg v256x240[25] =
+{
+        { 0xc2, 0x0, 0xe3},
+        { 0xd4, 0x0, 0x4f},
+        { 0xd4, 0x1, 0x3f},
+        { 0xd4, 0x2, 0x40},
+        { 0xd4, 0x3, 0x92},
+        { 0xd4, 0x4, 0x44},
+        { 0xd4, 0x5, 0x10},
+        { 0xd4, 0x6, 0x0a},
+        { 0xd4, 0x7, 0x3e},
+        { 0xd4, 0x8, 0x00},
+        { 0xd4, 0x9, 0x41},
+        { 0xd4, 0x10, 0xea},
+        { 0xd4, 0x11, 0xac},
+        { 0xd4, 0x12, 0xdf},
+        { 0xd4, 0x13, 0x20},
+        { 0xd4, 0x14, 0x40},
+        { 0xd4, 0x15, 0xe7},
+        { 0xd4, 0x16, 0x06},
+        { 0xd4, 0x17, 0xa3},
+        { 0xc4, 0x1, 0x1},
+        { 0xc4, 0x4, 0xe},
+        { 0xce, 0x5, 0x40},
+        { 0xce, 0x6, 0x5},
+        { 0xc0, 0x10, 0x41},
+        { 0xc0, 0x13, 0x0}
+};
+
+vgareg v256x224S[25] =
+{
+        { 0xc2, 0x0, 0xe3},
+        { 0xd4, 0x0, 0x5f},
+        { 0xd4, 0x1, 0x3f},
+        { 0xd4, 0x2, 0x40},
+        { 0xd4, 0x3, 0x82},
+        { 0xd4, 0x4, 0x4e},
+        { 0xd4, 0x5, 0x96},
+        { 0xd4, 0x6, 0x5},
+        { 0xd4, 0x7, 0x1},
+        { 0xd4, 0x8, 0x0},
+        { 0xd4, 0x9, 0x40},
+        { 0xd4, 0x10, 0xea},
+        { 0xd4, 0x11, 0xac},
+        { 0xd4, 0x12, 0xdf},
+        { 0xd4, 0x13, 0x20},
+        { 0xd4, 0x14, 0x40},
+        { 0xd4, 0x15, 0xe7},
+        { 0xd4, 0x16, 0x0},
+        { 0xd4, 0x17, 0xe3},
+        { 0xc4, 0x1, 0x1},
+        { 0xc4, 0x4, 0xe},
+        { 0xce, 0x5, 0x40},
+        { 0xce, 0x6, 0x5},
+        { 0xc0, 0x10, 0x41},
+        { 0xc0, 0x13, 0x0}
+};
+
+vgareg v256x256[25] =
+{
+        { 0xc2, 0x0, 0xe7},
+        { 0xd4, 0x0, 0x5f},
+        { 0xd4, 0x1, 0x3f},
+        { 0xd4, 0x2, 0x40},
+        { 0xd4, 0x3, 0x82},
+        { 0xd4, 0x4, 0x4a},
+        { 0xd4, 0x5, 0x9a},
+        { 0xd4, 0x6, 0x23},
+        { 0xd4, 0x7, 0xb2},
+        { 0xd4, 0x8, 0x0},
+        { 0xd4, 0x9, 0x61},
+        { 0xd4, 0x10, 0xa},
+        { 0xd4, 0x11, 0xac},
+        { 0xd4, 0x12, 0xff},
+        { 0xd4, 0x13, 0x20},
+        { 0xd4, 0x14, 0x40},
+        { 0xd4, 0x15, 0x7},
+        { 0xd4, 0x16, 0x1a},
+        { 0xd4, 0x17, 0xa3},
+        { 0xc4, 0x1, 0x1},
+        { 0xc4, 0x4, 0xe},
+        { 0xce, 0x5, 0x40},
+        { 0xce, 0x6, 0x5},
+        { 0xc0, 0x10, 0x41},
+        { 0xc0, 0x13, 0x0}
+};
+
+vgareg v256x256S[25] =
+{
+  { 0xc2, 0x00, 0xe7},{ 0xd4, 0x00, 0x5F},{ 0xd4, 0x01, 0x3f},
+  { 0xd4, 0x02, 0x40},{ 0xd4, 0x03, 0x82},{ 0xd4, 0x04, 0x4a},
+  { 0xd4, 0x05, 0x9a},{ 0xd4, 0x06, 0x25},{ 0xd4, 0x07, 0x15},
+  { 0xd4, 0x08, 0x00},{ 0xd4, 0x09, 0x60},{ 0xd4, 0x10, 0x0a},
+  { 0xd4, 0x11, 0xac},{ 0xd4, 0x12, 0xff},{ 0xd4, 0x13, 0x20},
+  { 0xd4, 0x14, 0x40},{ 0xd4, 0x15, 0x07},{ 0xd4, 0x16, 0x1a},
+  { 0xd4, 0x17, 0xa3},{ 0xc4, 0x01, 0x01},{ 0xc4, 0x04, 0x0e},
+  { 0xce, 0x05, 0x40},{ 0xce, 0x06, 0x05},{ 0xc0, 0x10, 0x41},
+  { 0xc0, 0x13, 0x00}
+};
+
+static void VGAPortSet(vgareg R)
+{
+  int p,i,v;
+
+  p=0x300|R.p;
+  i=R.i;
+  v=R.v;
+
+  switch(p)
+  {
+    case 0x3C0: inportb(0x3DA);
+                outportb(0x3C0,i);
+                outportb(0x3C0,v);
+                break;
+    case 0x3C2:
+    case 0x3C3:
+    default:    outportb(p, v);
+                break;
+    case 0x3C4: if(i==1)
+                {
+                 outportw(0x3c4,0x100);
+                 outportw(0x3c4,(v<<8)|1);
+                 outportw(0x3c4,0x300);
+                 break;
+                }
+    case 0x3CE:
+    case 0x3D4: outportw(p,i|(v<<8));
+                break;
+  }
+}
+
diff --git a/drivers/common/args.c b/drivers/common/args.c
new file mode 100644 (file)
index 0000000..7c6c8fe
--- /dev/null
@@ -0,0 +1,91 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+/****************************************************************/
+/*                     FCE Ultra                               */
+/*                                                             */
+/*     This file contains code for parsing command-line        */
+/*     options.                                                */
+/*                                                             */
+/****************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../types.h"
+#include "args.h"
+
+void ParseEA(int x, int argc, char *argv[], ARGPSTRUCT *argsps)
+{
+  int y=0;
+
+  do
+  {
+   if(!argsps[y].name)
+   {
+    ParseEA(x,argc,argv,(void *)argsps[y].var);
+    y++;
+    continue;
+   }
+   if(!strcmp(argv[x],argsps[y].name)) // A match.
+   {
+    if(argsps[y].subs)
+    {
+     if((x+1)>=argc)
+      break;
+     if(argsps[y].substype&0x8000)
+     {
+      *(int *)argsps[y].subs&=~(argsps[y].substype&(~0x8000));
+      *(int *)argsps[y].subs|=atoi(argv[x+1])?(argsps[y].substype&(~0x8000)):0;
+     }
+     else
+      switch(argsps[y].substype&(~0x4000))
+      {
+       case 0:         // Integer
+             *(int *)argsps[y].subs=atoi(argv[x+1]);
+             break;
+       case 1:         // String
+             if(argsps[y].substype&0x4000)
+             {
+               if(*(char **)argsps[y].subs)
+               free(*(char **)argsps[y].subs);
+              if(!( *(char **)argsps[y].subs=malloc(strlen(argv[x+1])+1) ))
+               break;
+             } 
+             strcpy(*(char **)argsps[y].subs,argv[x+1]);
+             break;
+      }
+    }
+    if(argsps[y].var)
+     *argsps[y].var=1;
+   }
+   y++;
+  } while(argsps[y].var || argsps[y].subs);
+}
+
+void ParseArguments(int argc, char *argv[], ARGPSTRUCT *argsps)
+{
+ int x;
+
+ for(x=0;x<argc;x++)
+  ParseEA(x,argc,argv,argsps);
+}
+
diff --git a/drivers/common/args.h b/drivers/common/args.h
new file mode 100644 (file)
index 0000000..426aa63
--- /dev/null
@@ -0,0 +1,30 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+typedef struct {
+        char *name;
+       int *var;
+
+       void *subs;
+       int substype;
+} ARGPSTRUCT;
+
+void ParseArguments(int argc, char *argv[], ARGPSTRUCT *argsps);
+
diff --git a/drivers/common/cheat.c b/drivers/common/cheat.c
new file mode 100644 (file)
index 0000000..fe77510
--- /dev/null
@@ -0,0 +1,448 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "../../driver.h"
+
+static void GetString(char *s)
+{
+ int x;
+ fgets(s,256,stdin);
+
+ for(x=0;x<256;x++)
+  if(s[x]=='\n')
+  {
+   s[x]=0;
+   break;
+  }
+}
+
+/* Get unsigned 16-bit integer from stdin in hex. */
+static uint32 GetH16(unsigned int def)
+{
+ char buf[32];
+
+ fgets(buf,32,stdin);
+ if(buf[0]=='\n')
+  return(def);
+ if(buf[0]=='$')
+  sscanf(buf+1,"%04x",&def);
+ else
+  sscanf(buf,"%04x",&def);
+ return def;
+}
+
+/* Get unsigned 8-bit integer from stdin in decimal. */
+static uint8 Get8(unsigned int def)
+{
+ char buf[32];
+
+ fgets(buf,32,stdin);
+ if(buf[0]=='\n')
+  return(def);
+ sscanf(buf,"%d",&def);
+ return def;
+}
+
+static int GetYN(int def)
+{
+ char buf[32];
+ printf("(Y/N)[%s]: ",def?"Y":"N");
+ fgets(buf,32,stdin);
+ if(buf[0]=='y' || buf[0]=='Y')
+  return(1);
+ if(buf[0]=='n' || buf[0]=='N')
+  return(0);
+ return(def);
+}
+
+/*
+**     Begin list code.
+**
+*/
+static int listcount;
+static int listids[16];
+static int listsel;
+static int mordoe;
+
+void BeginListShow(void)
+{
+ listcount=0;
+ listsel=-1;
+ mordoe=0;
+}
+
+/* Hmm =0 for in list choices, hmm=1 for end of list choices. */
+/* Return equals 0 to continue, -1 to stop, otherwise a number. */
+int ListChoice(int hmm)
+{
+  char buf[32];
+
+  if(!hmm)
+  {
+   int num=0;
+
+   tryagain:
+   printf(" <'Enter' to continue, (S)top, or enter a number.> ");
+   fgets(buf,32,stdin);
+   if(buf[0]=='s' || buf[0]=='S') return(-1);
+   if(buf[0]=='\n') return(0);
+   if(!sscanf(buf,"%d",&num))
+    return(0);  
+   if(num<1) goto tryagain;
+   return(num);
+  }
+  else
+  {
+   int num=0;
+
+   tryagain2:
+   printf(" <'Enter' to make no selection or enter a number.> ");
+   fgets(buf,32,stdin);
+   if(buf[0]=='\n') return(0);
+   if(!sscanf(buf,"%d",&num))
+    return(0);
+   if(num<1) goto tryagain2;
+   return(num);
+  }
+}
+
+int EndListShow(void)
+{
+  if(mordoe)
+  {
+   int r=ListChoice(1);
+   if(r>0 && r<=listcount)
+    listsel=listids[r-1];
+  }
+  return(listsel);
+}
+
+/* Returns 0 to stop listing, 1 to continue. */
+int AddToList(char *text, uint32 id)
+{
+ if(listcount==16)
+ {
+  int t=ListChoice(0);
+  mordoe=0;
+  if(t==-1) return(0);  // Stop listing.
+  else if(t>0 && t<17)
+  {
+   listsel=listids[t-1];
+   return(0);
+  }
+  listcount=0;
+ }
+ mordoe=1;
+ listids[listcount]=id;
+ printf("%2d) %s\n",listcount+1,text);
+ listcount++; 
+ return(1);
+}
+
+/*
+**     
+**     End list code.
+**/
+
+typedef struct MENU {
+       char *text;
+       void *action;
+       int type;       // 0 for menu, 1 for function.
+} MENU;
+
+static void SetOC(void)
+{
+ FCEUI_CheatSearchSetCurrentAsOriginal();
+}
+
+static void UnhideEx(void)
+{
+ FCEUI_CheatSearchShowExcluded();
+}
+
+static void ToggleCheat(int num)
+{
+ uint32 A;
+ int s;
+
+ FCEUI_GetCheat(num,0,&A,0,&s);
+ s^=1;
+ FCEUI_SetCheat(num,0,-1,-1,s);
+ printf("Cheat for address $%04x %sabled.\n",(unsigned int)A,s?"en":"dis");
+}
+
+static void ModifyCheat(int num)
+{
+ char *name;
+ char buf[256];
+ uint32 A;
+ uint8 V;
+ int s;
+ int t;
+
+ FCEUI_GetCheat(num, &name, &A, &V, &s);
+
+ printf("Name [%s]: ",name);
+ GetString(buf);
+
+ /* This obviously doesn't allow for cheats with no names.  Bah.  Who wants
+    nameless cheats anyway... 
+ */
+
+ if(buf[0])
+  name=buf;    // Change name when FCEUI_SetCheat() is called.
+ else
+  name=0;      // Don't change name when FCEUI_SetCheat() is called.
+
+ printf("Address [$%04x]: ",(unsigned int)A);
+ A=GetH16(A);
+
+ printf("Value [%03d]: ",(unsigned int)V);
+ V=Get8(V);
+
+ printf("Enable [%s]: ",s?"Y":"N");
+ t=getchar();
+ if(t=='Y' || t=='y') s=1;
+ else if(t=='N' || t=='n') s=0;
+
+ FCEUI_SetCheat(num,name,A,V,s);
+}
+
+static void AddCheatParam(uint32 A, uint8 V)
+{
+ char name[256];
+
+ printf("Name: ");
+ GetString(name);
+ printf("Address [$%04x]: ",(unsigned int)A);
+ A=GetH16(A);
+ printf("Value [%03d]: ",(unsigned int)V);
+ V=Get8(V);
+ printf("Add cheat \"%s\" for address $%04x with value %03d?",name,(unsigned int)A,(unsigned int)V);
+ if(GetYN(0))
+ {
+  if(FCEUI_AddCheat(name,A,V))
+   puts("Cheat added.");
+  else
+   puts("Error adding cheat.");
+ }
+}
+
+static void AddCheat(void)
+{
+ AddCheatParam(0,0);
+}
+
+static int lid;
+static int clistcallb(char *name, uint32 a, uint8 v, int s)
+{
+ char tmp[512];
+ int ret;
+
+ sprintf(tmp,"%s $%04x:%03d - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,name);
+ ret=AddToList(tmp,lid);
+ lid++;
+ return(ret);
+}
+
+static void ListCheats(void)
+{
+ int which;
+ lid=0;
+
+ BeginListShow();
+ FCEUI_ListCheats(clistcallb);
+ which=EndListShow();
+ if(which>=0)
+ {
+  char tmp[32];
+  printf(" <(T)oggle status, (M)odify, or (D)elete this cheat.> ");
+  fgets(tmp,32,stdin);
+  switch(tolower(tmp[0]))
+  {
+   case 't':ToggleCheat(which);
+           break;
+   case 'd':if(!FCEUI_DelCheat(which))
+            puts("Error deleting cheat!");
+           else 
+            puts("Cheat has been deleted.");
+           break;
+   case 'm':ModifyCheat(which);
+           break;
+  }
+ }
+}
+
+static void ResetSearch(void)
+{
+ FCEUI_CheatSearchBegin();
+ puts("Done.");
+}
+
+static int srescallb(uint32 a, uint8 last, uint8 current)
+{
+ char tmp[13];
+ sprintf(tmp, "$%04x:%03d:%03d",(unsigned int)a,(unsigned int)last,(unsigned int)current);
+ return(AddToList(tmp,a));
+}
+
+static void ShowRes(void)
+{
+ int n=FCEUI_CheatSearchGetCount();
+ printf(" %d results:\n",n);
+ if(n)
+ {
+  int which;
+  BeginListShow();
+  FCEUI_CheatSearchGet(srescallb);
+  which=EndListShow();
+  if(which>=0)
+   AddCheatParam(which,0);
+ }
+}
+
+static int ShowShortList(char *moe[], int n, int def)
+{
+ int x,c;
+ unsigned int baa;
+ char tmp[16];
+
+ red:
+ for(x=0;x<n;x++)
+  printf("%d) %s\n",x+1,moe[x]);
+ puts("D) Display List");
+ clo:
+
+ printf("\nSelection [%d]> ",def+1);
+ fgets(tmp,256,stdin);
+ if(tmp[0]=='\n')
+  return def;
+ c=tolower(tmp[0]);
+ baa=c-'1';
+
+ if(baa<n)
+  return baa;
+ else if(c=='d')
+  goto red;
+ else
+ {
+  puts("Invalid selection.");
+  goto clo;
+ }
+}
+
+static void DoSearch(void)
+{
+ static int v1=0,v2=0;
+ static int method=0;
+ char *m[4]={"O==V1 && C==V2","O==V1 && |O-C|==V2","|O-C|==V2","O!=C"};
+ printf("\nSearch Filter:\n");
+
+ method=ShowShortList(m,4,method);
+ if(method<=1)
+ {
+  printf("V1 [%03d]: ",v1);
+  v1=Get8(v1);
+ }
+ if(method<=2)
+ {
+  printf("V2 [%03d]: ",v2);
+  v2=Get8(v2);
+ }
+ FCEUI_CheatSearchEnd(method,v1,v2);
+ puts("Search completed.\n");
+}
+
+
+static MENU NewCheatsMenu[7]={
+ {"Add Cheat",AddCheat,1},
+ {"Reset Search",ResetSearch,1},
+ {"Do Search",DoSearch,1},
+ {"Set Original to Current",SetOC,1},
+ {"Unhide Excluded",UnhideEx,1},
+ {"Show Results",ShowRes,1},
+ {0}
+};
+
+static MENU MainMenu[3]={
+ {"List Cheats",ListCheats,1},
+ {"New Cheats...",NewCheatsMenu,0},
+ {0}
+};
+
+static void DoMenu(MENU *men)
+{
+ int x=0;
+
+ redisplay:
+ x=0;
+ puts("");
+ while(men[x].text)
+ {
+  printf("%d) %s\n",x+1,men[x].text);
+  x++;
+ }
+ puts("D) Display Menu\nX) Return to Previous\n");
+ {
+  char buf[32];
+  int c;
+
+  recommand:
+  printf("Command> ");
+  fgets(buf,32,stdin);
+  c=tolower(buf[0]);
+  if(c=='\n')
+   goto recommand;
+  else if(c=='d')
+   goto redisplay;
+  else if(c=='x')
+  {
+   return;
+  }
+  else if(sscanf(buf,"%d",&c))
+  {
+   if(c>x) goto invalid;
+   if(men[c-1].type)
+   {
+    void (*func)(void)=men[c-1].action;
+    func();
+   }
+   else
+    DoMenu(men[c-1].action);   /* Mmm...recursivey goodness. */
+   goto redisplay;
+  }
+  else
+  {
+   invalid:
+   puts("Invalid command.\n");
+   goto recommand;
+  }
+
+ }
+}
+
+void DoConsoleCheatConfig(void)
+{
+ MENU *curmenu=MainMenu;
+
+ DoMenu(curmenu);
+}
diff --git a/drivers/common/cheat.h b/drivers/common/cheat.h
new file mode 100644 (file)
index 0000000..6422569
--- /dev/null
@@ -0,0 +1,21 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+void DoConsoleCheatConfig(void);
diff --git a/drivers/common/config.c b/drivers/common/config.c
new file mode 100644 (file)
index 0000000..6f87f55
--- /dev/null
@@ -0,0 +1,151 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+/****************************************************************/
+/*                     FCE Ultra                               */
+/*                                                             */
+/*     This file contains routines for reading/writing the     */
+/*     configuration file.                                     */
+/*                                                             */
+/****************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../types.h"
+#include "config.h"
+
+static int FReadString(FILE *fp, char *str, int n)
+{
+ int x=0,z;
+ for(;;)
+ {
+  z=fgetc(fp);
+  str[x]=z;
+  x++;  
+  if(z<=0) break;
+  if(x>=n) return 0;
+ }
+ if(z<0) return 0;
+ return 1;
+}
+
+static void GetValueR(FILE *fp, char *str, void *v, int c)
+{
+ char buf[256];
+ int s;
+
+ while(FReadString(fp,buf,256))
+ {
+  fread(&s,1,4,fp);
+  if(!strcmp(str, buf))
+  {
+   if(!c)      // String, allocate some memory.
+   {
+    if(!(*(char **)v=malloc(s)))
+     goto gogl;
+    fread(*(char **)v,1,s,fp);
+    continue;
+   }
+   else if(s>c || s<c)
+   {
+     gogl:
+     fseek(fp,s,SEEK_CUR);
+     continue;
+   }
+   fread((uint8*)v,1,c,fp);
+  }
+  else
+   fseek(fp,s,SEEK_CUR);
+ }
+ fseek(fp,4,SEEK_SET);
+}
+
+static void SetValueR(FILE *fp, char *str, void *v, int c)
+{
+ fwrite(str,1,strlen(str)+1,fp);
+ fwrite((uint8*)&c,1,4,fp);
+ fwrite((uint8*)v,1,c,fp);
+}
+
+static void SaveParse(CFGSTRUCT *cfgst, FILE *fp)
+{
+        int x=0;
+
+        do
+        {
+         if(!cfgst[x].name)     // Link to new config structure
+        {
+         SaveParse(cfgst[x].ptr,fp);   // Recursion is sexy.  I could
+                                       // save a little stack space if I made
+                                       // the file pointer a non-local
+                                       // variable...
+         x++;
+         continue;
+        }
+
+         if(cfgst[x].len)               // Plain data
+          SetValueR(fp,cfgst[x].name,cfgst[x].ptr,cfgst[x].len);
+         else                           // String
+          if(*(char **)cfgst[x].ptr)    // Only save it if there IS a string.
+           SetValueR(fp,cfgst[x].name,*(char **)cfgst[x].ptr,
+                        strlen(*(char **)cfgst[x].ptr)+1);
+         x++;
+        } while(cfgst[x].ptr);
+}
+
+void SaveFCEUConfig(char *filename, CFGSTRUCT *cfgst)
+{
+       FILE *fp;
+
+        fp=fopen(filename,"wb");
+        if(fp==NULL) return;
+
+       SaveParse(cfgst,fp);
+
+       fclose(fp);
+}
+
+static void LoadParse(CFGSTRUCT *cfgst, FILE *fp)
+{
+       int x=0;
+        do
+        {
+         if(!cfgst[x].name)     // Link to new config structure
+         {
+         LoadParse(cfgst[x].ptr,fp);
+         x++;
+         continue;
+         }
+         GetValueR(fp,cfgst[x].name,cfgst[x].ptr,cfgst[x].len);
+         x++;
+        } while(cfgst[x].ptr);
+}
+
+void LoadFCEUConfig(char *filename, CFGSTRUCT *cfgst)
+{
+        FILE *fp;
+
+        fp=fopen(filename,"rb");
+        if(fp==NULL) return;
+       LoadParse(cfgst,fp);
+        fclose(fp);
+}
diff --git a/drivers/common/config.h b/drivers/common/config.h
new file mode 100644 (file)
index 0000000..0689f21
--- /dev/null
@@ -0,0 +1,57 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+typedef struct {
+        char *name;
+        void *ptr;
+        int len;
+} CFGSTRUCT;
+
+void SaveFCEUConfig(char *filename, CFGSTRUCT *cfgst);
+void LoadFCEUConfig(char *filename, CFGSTRUCT *cfgst);
+
+/* Macros for building CFGSTRUCT structures. */
+
+/* CFGSTRUCT structures must always end with ENDCFGSTRUCT */
+#define ENDCFGSTRUCT   { 0,0,0 }
+
+/* When this macro is used, the config loading/saving code will parse
+   the new config structure until the end of it is detected, then it
+   will continue parsing the original config structure.
+*/
+#define ADDCFGSTRUCT(x) { 0,&x,0 }
+
+/* Oops.  The NAC* macros shouldn't have the # in front of the w, but
+   fixing this would break configuration files of previous versions and it 
+   isn't really hurting much.
+*/
+
+/* Single piece of data(integer). */
+#define AC(x)   { #x,&x,sizeof(x)}
+#define NAC(w,x) { #w,&x,sizeof(x)}
+
+/* Array. */
+#define ACA(x)   {#x,x,sizeof(x)}
+#define NACA(w,x) {#w,x,sizeof(x)}
+
+/* String(pointer) with automatic memory allocation. */
+#define ACS(x)  {#x,&x,0}
+#define NACS(w,x)  {#w,&x,0}
+
diff --git a/drivers/common/unixdsp.c b/drivers/common/unixdsp.c
new file mode 100644 (file)
index 0000000..6b0d947
--- /dev/null
@@ -0,0 +1,123 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sched.h>
+#include <sys/soundcard.h>
+
+#include "../../types.h"
+
+static int format;
+static int dspfd;
+
+// fsize is in samples, not bytes(gets translated before ioctl())
+int InitUNIXDSPSound(int *rate, int bits, int fsize, int nfrags)
+{
+ int x;
+
+ printf("  Opening /dev/dsp...");
+ dspfd=open("/dev/dsp",O_WRONLY);
+ if(dspfd==-1) goto __disperror;
+
+ if(!bits) goto skip16check;
+ x=AFMT_S16_LE;
+ format=0;
+ printf("\n   Setting format to 16-bit, signed, LSB first...");
+ if(ioctl(dspfd,SNDCTL_DSP_SETFMT,&x)==-1)
+ {
+  skip16check:
+  x=AFMT_U8;
+  printf("\n   Setting format to 8-bit, unsigned...");
+  if(ioctl(dspfd,SNDCTL_DSP_SETFMT,&x)==-1) goto __disperror;
+  format=1;
+ }
+
+ printf("\n   Setting fragment size to %d samples and number of fragments to %d...",1<<fsize,nfrags);
+
+ if(!format)
+  fsize++;
+ x=fsize|(nfrags<<16);
+
+ if(ioctl(dspfd,SNDCTL_DSP_SETFRAGMENT,&x)==-1)
+  printf("ERROR (continuing anyway)\n");
+ x=0;
+ printf("\n   Setting mono sound...");  
+ if(ioctl(dspfd,SNDCTL_DSP_STEREO,&x)==-1) goto __disperror;
+ printf("\n   Setting playback rate of %d hz...",*rate);
+ if(ioctl(dspfd,SNDCTL_DSP_SPEED,rate)==-1) goto __disperror;
+ printf("Set to %d hz\n",*rate);
+ if(*rate<8192 || *rate>65535)
+ {
+  printf("    Sample rate is out of the acceptable range(8192-65535).\n");
+  close(dspfd);
+  return(0);
+ }
+ return 1;
+ __disperror:
+ printf("ERROR\n");
+ return 0;
+}
+
+void KillUNIXDSPSound(void)
+{
+  close(dspfd);
+}
+
+static int16 MBuffer[2048];
+void WriteUNIXDSPSound(int32 *Buffer, int Count, int noblocking)
+{
+ int P,c;
+ int32 *src=Buffer;
+
+ if(format)
+ {
+  uint8 *dest=(uint8 *)MBuffer;
+  for(P=Count;P;P--,dest++,src++)
+   *dest=(uint8)((*src)>>8)^128;
+  c=Count;
+ }
+ else
+ {
+  int16 *dest=MBuffer;
+  for(P=Count;P;P--,dest++,src++)
+   *dest=*src;
+  c=Count<<1;
+ }
+
+// noblocking=!noblocking; // speed testing
+ if(noblocking)
+ {
+  struct audio_buf_info ai;
+  if(!ioctl(dspfd,SNDCTL_DSP_GETOSPACE,&ai))
+   if(ai.bytes<c)
+    return;
+ }
+ write(dspfd,(uint8 *)MBuffer,c);
+}
diff --git a/drivers/common/unixdsp.h b/drivers/common/unixdsp.h
new file mode 100644 (file)
index 0000000..7f6310d
--- /dev/null
@@ -0,0 +1,23 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+int InitUNIXDSPSound(int *rate, int bits, int fsize, int nfrags);
+void WriteUNIXDSPSound(int32 *Buffer, int Count, int noblocking);
+void KillUNIXDSPSound(void);
diff --git a/drivers/common/vidblit.c b/drivers/common/vidblit.c
new file mode 100644 (file)
index 0000000..75802e3
--- /dev/null
@@ -0,0 +1,229 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdlib.h>
+
+#include "../../types.h"
+
+static uint32 CBM[3];
+static uint32 *palettetranslate=0;
+static int Bpp;        // BYTES per pixel
+
+
+int InitBlitToHigh(int b, uint32 rmask, uint32 gmask, uint32 bmask)
+{
+ Bpp=b;
+ if(Bpp<=1 || Bpp>4)
+  return(0);
+
+ if(Bpp==2)
+  palettetranslate=malloc(65536*4);
+ else if(Bpp>=3)
+  palettetranslate=malloc(256*4);
+ if(!palettetranslate)
+  return(0);
+
+ CBM[0]=rmask;
+ CBM[1]=gmask;
+ CBM[2]=bmask;
+ return(1);
+}
+
+void KillBlitToHigh(void)
+{
+  free(palettetranslate);
+}
+
+void SetPaletteBlitToHigh(uint8 *src)
+{ 
+             int cshiftr[3];
+             int cshiftl[3];
+             int a,x,z,y;
+
+             cshiftl[0]=cshiftl[1]=cshiftl[2]=-1;
+             for(a=0;a<3;a++)
+             {
+              for(x=0,y=-1,z=0;x<32;x++)
+              {
+               if(CBM[a]&(1<<x))
+               {
+                if(cshiftl[a]==-1) cshiftl[a]=x;
+                z++;
+               }
+              }
+              cshiftr[a]=(8-z);
+             }
+
+ switch(Bpp)
+ {
+    case 2:
+             for(x=0;x<65536;x++)
+             {
+              uint16 lower,upper;
+
+              lower=(src[((x&255)<<2)]>>cshiftr[0])<<cshiftl[0];
+              lower|=(src[((x&255)<<2)+1]>>cshiftr[1])<<cshiftl[1];
+              lower|=(src[((x&255)<<2)+2]>>cshiftr[2])<<cshiftl[2];
+              upper=(src[((x>>8)<<2)]>>cshiftr[0])<<cshiftl[0];
+              upper|=(src[((x>>8)<<2)+1]>>cshiftr[1])<<cshiftl[1];
+              upper|=(src[((x>>8)<<2)+2]>>cshiftr[2])<<cshiftl[2];
+
+              palettetranslate[x]=lower|(upper<<16);
+             }
+           break;
+    case 3:
+    case 4:
+            for(x=0;x<256;x++)
+            {
+             uint32 t;
+
+            t=src[(x<<2)]<<cshiftl[0];
+            t|=src[(x<<2)+1]<<cshiftl[1];
+            t|=src[(x<<2)+2]<<cshiftl[2];
+
+             palettetranslate[x]=t;
+            }
+            break;
+ }
+}
+
+void Blit8To8(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale, int yscale, int efx)
+{
+ int x,y;
+ int pinc;
+
+ pinc=pitch-(xr*xscale);
+ if(xscale!=1 || yscale!=1)
+ {
+  if(efx)
+  {
+   for(y=yr;y;y--,/*dest+=pinc,*/src+=272-xr)
+   {
+    int doo=yscale-(yscale>>1);
+    do
+    {
+     for(x=xr;x;x--,src++)
+     {
+      int too=xscale;
+      do
+      {
+       *(uint8 *)dest=*(uint8 *)src;
+       dest++;
+      } while(--too);
+     }
+     src-=xr;
+     dest+=pinc;
+    } while(--doo);
+    //src-=xr*(yscale-(yscale>>1));
+    dest+=pitch*(yscale>>1);
+
+    src+=xr;
+   }
+
+  }
+  else
+  {
+   for(y=yr;y;y--,/*dest+=pinc,*/src+=272-xr)
+   {
+    int doo=yscale;
+    do
+    {
+     for(x=xr;x;x--,src++)
+     {
+      int too=xscale;
+      do
+      {
+       *(uint8 *)dest=*(uint8 *)src;
+       dest++;
+      } while(--too);
+     }
+     src-=xr;
+     dest+=pinc;
+    } while(--doo);
+    src+=xr;
+   }
+ }
+ }
+ else
+ {
+  for(y=yr;y;y--,dest+=pinc,src+=272-xr)
+   for(x=xr;x;x-=4,dest+=4,src+=4)
+    *(uint32 *)dest=*(uint32 *)src;
+ }
+}
+
+void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch)
+{
+ int x,y;
+ int pinc;
+
+ switch(Bpp)
+ {
+  case 4:
+   pinc=pitch-(xr<<2);
+   for(y=yr;y;y--)
+   {
+    for(x=xr;x;x--)
+    {
+     *(uint32 *)dest=palettetranslate[(uint32)*src];
+     dest+=4;
+     src++;
+    }
+    dest+=pinc;
+    src+=16;
+   }
+  break;
+
+  case 3:
+   pinc=pitch-(xr+xr+xr);
+   for(y=yr;y;y--)
+   {
+    for(x=xr;x;x--)
+    {
+     uint32 tmp;
+     tmp=palettetranslate[(uint32)*src];
+     *(uint16*)dest=(uint16)tmp;
+     *&dest[2]=(uint8)(tmp>>16);
+     dest+=3;
+     src++;
+    }
+    dest+=pinc;
+    src+=16;
+   }
+   break;
+
+  case 2:
+   pinc=pitch-(xr<<1);
+   for(y=yr;y;y--)
+   {
+    for(x=xr>>1;x;x--)
+    {
+     *(uint32 *)dest=palettetranslate[*(uint16 *)src];
+     dest+=4;
+     src+=2;
+    }
+    dest+=pinc;
+    src+=16;
+   }
+   break;
+ }
+}
diff --git a/drivers/common/vidblit.h b/drivers/common/vidblit.h
new file mode 100644 (file)
index 0000000..a84588c
--- /dev/null
@@ -0,0 +1,25 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+int InitBlitToHigh(int b, uint32 rmask, uint32 gmask, uint32 bmask);
+void SetPaletteBlitToHigh(uint8 *src);
+void KillBlitToHigh(void);
+void Blit8ToHigh(uint8 *src, uint8 *dest, int xr, int yr, int pitch);
+void Blit8To8(uint8 *src, uint8 *dest, int xr, int yr, int pitch, int xscale, int yscale, int efx);
diff --git a/drivers/win/cheat.c b/drivers/win/cheat.c
new file mode 100644 (file)
index 0000000..3b53c2f
--- /dev/null
@@ -0,0 +1,471 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 2002 Ben Parnell\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+#include "common.h"\r
+\r
+#include "cheat.h"\r
+\r
+static int selcheat;\r
+static int scheatmethod=0;\r
+static uint8 cheatval1=0;\r
+static uint8 cheatval2=0;\r
+\r
+static void ConfigAddCheat(HWND wnd);\r
+\r
+\r
+static uint16 StrToU16(char *s)\r
+{\r
+ unsigned int ret=0;\r
+ sscanf(s,"%4x",&ret);\r
+ return ret;\r
+}\r
+\r
+static uint8 StrToU8(char *s)\r
+{\r
+ unsigned int ret=0;\r
+ sscanf(s,"%d",&ret);\r
+ return ret;\r
+}\r
+\r
+\r
+/* Need to be careful where these functions are used. */\r
+static char *U16ToStr(uint16 a)\r
+{\r
+ static char TempArray[16];\r
+ sprintf(TempArray,"%04X",a);\r
+ return TempArray;\r
+}\r
+\r
+static char *U8ToStr(uint8 a)\r
+{\r
+ static char TempArray[16];\r
+ sprintf(TempArray,"%03d",a);\r
+ return TempArray;\r
+}\r
+\r
+\r
+static HWND RedoCheatsWND;\r
+static int RedoCheatsCallB(char *name, uint32 a, uint8 v, int s)\r
+{\r
+ SendDlgItemMessage(RedoCheatsWND,101,LB_ADDSTRING,0,(LPARAM)(LPSTR)name);\r
+ return(1);\r
+}\r
+\r
+static void RedoCheatsLB(HWND hwndDlg)\r
+{\r
+ SendDlgItemMessage(hwndDlg,101,LB_RESETCONTENT,0,0);\r
+ RedoCheatsWND=hwndDlg;\r
+ FCEUI_ListCheats(RedoCheatsCallB);\r
+}\r
+\r
+\r
+BOOL CALLBACK CheatsConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+  switch(uMsg)\r
+  {\r
+   case WM_INITDIALOG:                  \r
+                RedoCheatsLB(hwndDlg);\r
+                break;\r
+   case WM_CLOSE:\r
+   case WM_QUIT: goto gornk;\r
+   case WM_COMMAND:\r
+                switch(HIWORD(wParam))\r
+                {\r
+                 case BN_CLICKED:\r
+                        if(selcheat>=0)\r
+                        {\r
+                         if(LOWORD(wParam)==107)\r
+                          FCEUI_SetCheat(selcheat,0,-1,-1,1);\r
+                         else if(LOWORD(wParam)==108)\r
+                          FCEUI_SetCheat(selcheat,0,-1,-1,0);\r
+                        }\r
+                        break;\r
+                 case EN_KILLFOCUS:\r
+                        if(selcheat>=0)\r
+                        {\r
+                         char TempArray[256];\r
+                         int32 t;\r
+\r
+                         GetDlgItemText(hwndDlg,LOWORD(wParam),TempArray,256);\r
+                         switch(LOWORD(wParam))\r
+                         {\r
+                          case 102:FCEUI_SetCheat(selcheat,TempArray,-1,-1,-1);\r
+                                   SendDlgItemMessage(hwndDlg,101,LB_INSERTSTRING,selcheat,(LPARAM)(LPCTSTR)TempArray);\r
+                                   SendDlgItemMessage(hwndDlg,101,LB_DELETESTRING,selcheat+1,0);\r
+                                   SendDlgItemMessage(hwndDlg,101,LB_SETCURSEL,selcheat,0);\r
+                                   break;\r
+                          case 103:t=StrToU16(TempArray);\r
+                                   FCEUI_SetCheat(selcheat,0,t,-1,-1);\r
+                                   break;\r
+                          case 104:t=StrToU8(TempArray);\r
+                                   FCEUI_SetCheat(selcheat,0,-1,t,-1);\r
+                                   break;\r
+                         }\r
+                        }\r
+                        break;\r
+                }\r
+\r
+                switch(LOWORD(wParam))\r
+                {\r
+                 case 101:\r
+                        if(HIWORD(wParam)==LBN_SELCHANGE)\r
+                        {\r
+                         char *s;\r
+                         uint32 a;\r
+                         uint8 b;\r
+                        int status;\r
+\r
+                         selcheat=SendDlgItemMessage(hwndDlg,101,LB_GETCURSEL,0,(LPARAM)(LPSTR)0);\r
+                         if(selcheat<0) break;\r
+\r
+                         FCEUI_GetCheat(selcheat,&s,&a,&b,&status);\r
+                         SetDlgItemText(hwndDlg,102,(LPTSTR)s);\r
+                         SetDlgItemText(hwndDlg,103,(LPTSTR)U16ToStr(a));\r
+                         SetDlgItemText(hwndDlg,104,(LPTSTR)U8ToStr(b));\r
+\r
+                         CheckRadioButton(hwndDlg,107,108,status?107:108);\r
+                        }\r
+                        break;\r
+                }\r
+\r
+                if(!(wParam>>16))\r
+                switch(wParam&0xFFFF)\r
+                {\r
+                 case 106:\r
+                          if(selcheat>=0)\r
+                          {\r
+                           FCEUI_DelCheat(selcheat);\r
+                           SendDlgItemMessage(hwndDlg,101,LB_DELETESTRING,selcheat,0);\r
+                           selcheat=-1;\r
+                           SetDlgItemText(hwndDlg,102,(LPTSTR)"");\r
+                           SetDlgItemText(hwndDlg,103,(LPTSTR)"");\r
+                           SetDlgItemText(hwndDlg,104,(LPTSTR)"");\r
+                           CheckRadioButton(hwndDlg,107,108,0); // Is this correct?\r
+                          }\r
+                          break;\r
+                 case 105:\r
+                          ConfigAddCheat(hwndDlg);\r
+                          RedoCheatsLB(hwndDlg);\r
+                          break;\r
+                 case 1:\r
+                        gornk:\r
+                        EndDialog(hwndDlg,0);\r
+                        break;\r
+                }\r
+              }\r
+  return 0;\r
+}\r
+\r
+\r
+void ConfigCheats(HWND hParent)\r
+{\r
+ if(!GI)\r
+ {\r
+  FCEUD_PrintError("You must have a game loaded before you can manipulate cheats.");\r
+  return;\r
+ }\r
+\r
+ if(GI->type==GIT_NSF)\r
+ {\r
+  FCEUD_PrintError("Sorry, you can't cheat with NSFs.");\r
+  return;\r
+ }\r
+\r
+ selcheat=-1;\r
+ DialogBox(fceu_hInstance,"CHEATS",hParent,CheatsConCallB);\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+HWND cfcallbw;\r
+\r
+int cfcallb(uint32 a, uint8 last, uint8 current)\r
+{\r
+ char temp[16];\r
+\r
+ sprintf(temp,"%04X:%03d:%03d",(unsigned int)a,last,current);\r
+ SendDlgItemMessage(cfcallbw,108,LB_ADDSTRING,0,(LPARAM)(LPSTR)temp);\r
+ return(1);\r
+}\r
+\r
+static int scrollindex;\r
+static int scrollnum;\r
+static int scrollmax;\r
+\r
+int cfcallbinsert(uint32 a, uint8 last, uint8 current)\r
+{\r
+ char temp[16];\r
+\r
+ sprintf(temp,"%04X:%03d:%03d",(unsigned int)a,last,current);\r
+ SendDlgItemMessage(cfcallbw,108,LB_INSERTSTRING,13,(LPARAM)(LPSTR)temp);\r
+ return(1);\r
+}\r
+\r
+int cfcallbinsertt(uint32 a, uint8 last, uint8 current)\r
+{\r
+ char temp[16];\r
+\r
+ sprintf(temp,"%04X:%03d:%03d",(unsigned int)a,last,current);\r
+ SendDlgItemMessage(cfcallbw,108,LB_INSERTSTRING,0,(LPARAM)(LPSTR)temp);\r
+ return(1);\r
+}\r
+\r
+\r
+void AddTheThing(HWND hwndDlg, char *s, int a, int v)\r
+{\r
+ if(FCEUI_AddCheat(s,a,v))\r
+  MessageBox(hwndDlg,"Cheat Added","Cheat Added",MB_OK);\r
+}\r
+\r
+\r
+static void DoGet(void)\r
+{\r
+ int n=FCEUI_CheatSearchGetCount();\r
+ int t;\r
+ scrollnum=n;\r
+ scrollindex=-32768;\r
+\r
+ SendDlgItemMessage(cfcallbw,108,LB_RESETCONTENT,0,0);\r
+ FCEUI_CheatSearchGetRange(0,13,cfcallb);\r
+\r
+ t=-32768+n-1-13;\r
+ if(t<-32768)\r
+  t=-32768;\r
+ scrollmax=t;\r
+ SendDlgItemMessage(cfcallbw,120,SBM_SETRANGE,-32768,t);\r
+ SendDlgItemMessage(cfcallbw,120,SBM_SETPOS,-32768,1);\r
+}\r
+\r
+\r
+BOOL CALLBACK AddCheatCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+  static int lbfocus;\r
+  static HWND hwndLB;\r
+  cfcallbw=hwndDlg;\r
+\r
+\r
+  switch(uMsg)\r
+  {                                                                               \r
+   case WM_VSCROLL:\r
+                if(scrollnum>13)\r
+                {\r
+                 switch((int)LOWORD(wParam))\r
+                 {\r
+                  case SB_TOP:\r
+                        scrollindex=-32768;\r
+                        SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);\r
+                        SendDlgItemMessage(hwndDlg,108,LB_RESETCONTENT,13,0);\r
+                        FCEUI_CheatSearchGetRange(scrollindex+32768,scrollindex+32768+13,cfcallb);\r
+                        break;\r
+                  case SB_BOTTOM:\r
+                        scrollindex=scrollmax;\r
+                        SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);\r
+                        SendDlgItemMessage(hwndDlg,108,LB_RESETCONTENT,13,0);\r
+                        FCEUI_CheatSearchGetRange(scrollindex+32768,scrollindex+32768+13,cfcallb);\r
+                        break;\r
+                  case SB_LINEUP:\r
+                        if(scrollindex>-32768)\r
+                        {\r
+                         scrollindex--;\r
+                         SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);\r
+                         SendDlgItemMessage(hwndDlg,108,LB_DELETESTRING,13,0);\r
+                         FCEUI_CheatSearchGetRange(scrollindex+32768,scrollindex+32768,cfcallbinsertt);\r
+                        }\r
+                        break;\r
+\r
+                  case SB_PAGEUP:\r
+                        scrollindex-=14;\r
+                        if(scrollindex<-32768) scrollindex=-32768;\r
+                        SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);\r
+                        SendDlgItemMessage(hwndDlg,108,LB_RESETCONTENT,13,0);\r
+                        FCEUI_CheatSearchGetRange(scrollindex+32768,scrollindex+32768+13,cfcallb);\r
+                        break;\r
+\r
+                  case SB_LINEDOWN:\r
+                        if(scrollindex<scrollmax)\r
+                        {\r
+                         scrollindex++;\r
+                         SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);\r
+                         SendDlgItemMessage(hwndDlg,108,LB_DELETESTRING,0,0);\r
+                         FCEUI_CheatSearchGetRange(scrollindex+32768+13,scrollindex+32768+13,cfcallbinsert);\r
+                        }\r
+                        break;\r
+\r
+                  case SB_PAGEDOWN:\r
+                        scrollindex+=14;\r
+                        if(scrollindex>scrollmax)\r
+                         scrollindex=scrollmax;\r
+                        SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);\r
+                        SendDlgItemMessage(hwndDlg,108,LB_RESETCONTENT,0,0);\r
+                        FCEUI_CheatSearchGetRange(scrollindex+32768,scrollindex+32768+13,cfcallb);\r
+                        break;\r
+\r
+                  case SB_THUMBPOSITION:\r
+                  case SB_THUMBTRACK:\r
+                        scrollindex=(short int)HIWORD(wParam);\r
+                        SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);\r
+                        SendDlgItemMessage(hwndDlg,108,LB_RESETCONTENT,0,0);\r
+                        FCEUI_CheatSearchGetRange(32768+scrollindex,32768+scrollindex+13,cfcallb);\r
+                        break;\r
+                 }\r
+\r
+                }                \r
+                break;\r
+\r
+   case WM_INITDIALOG:\r
+                SetDlgItemText(hwndDlg,110,(LPTSTR)U8ToStr(cheatval1));\r
+                SetDlgItemText(hwndDlg,111,(LPTSTR)U8ToStr(cheatval2));\r
+                DoGet();\r
+                CheckRadioButton(hwndDlg,115,118,scheatmethod+115);\r
+                lbfocus=0;\r
+                hwndLB=0;\r
+                break;\r
+\r
+   case WM_VKEYTOITEM:\r
+                if(lbfocus)\r
+                {\r
+                 int real;\r
+\r
+                 real=SendDlgItemMessage(hwndDlg,108,LB_GETCURSEL,0,(LPARAM)(LPSTR)0);\r
+                 switch((int)LOWORD(wParam))\r
+                 {\r
+                  case VK_UP: \r
+                              /* mmmm....recursive goodness */\r
+                              if(!real)\r
+                               SendMessage(hwndDlg,WM_VSCROLL,SB_LINEUP,0);\r
+                              return(-1);\r
+                              break;\r
+                  case VK_DOWN:\r
+                              if(real==13)\r
+                               SendMessage(hwndDlg,WM_VSCROLL,SB_LINEDOWN,0);\r
+                              return(-1);\r
+                              break;\r
+                  case VK_PRIOR:\r
+                              SendMessage(hwndDlg,WM_VSCROLL,SB_PAGEUP,0);\r
+                              break;\r
+                  case VK_NEXT:\r
+                              SendMessage(hwndDlg,WM_VSCROLL,SB_PAGEDOWN,0);\r
+                              break;\r
+                  case VK_HOME:\r
+                              SendMessage(hwndDlg,WM_VSCROLL,SB_TOP,0);\r
+                              break;\r
+                  case VK_END:\r
+                              SendMessage(hwndDlg,WM_VSCROLL,SB_BOTTOM,0);\r
+                              break;\r
+                 }\r
+                 return(-2);\r
+                }\r
+                break;\r
+\r
+   case WM_CLOSE:\r
+   case WM_QUIT: goto gornk;\r
+   case WM_COMMAND:\r
+                switch(LOWORD(wParam))\r
+                {\r
+                 case 108:\r
+                        switch(HIWORD(wParam))\r
+                        {\r
+                         case LBN_SELCHANGE:\r
+                                 {\r
+                                  char TempArray[32];\r
+                                  SendDlgItemMessage(hwndDlg,108,LB_GETTEXT,SendDlgItemMessage(hwndDlg,108,LB_GETCURSEL,0,(LPARAM)(LPSTR)0),(LPARAM)(LPCTSTR)TempArray);\r
+                                  TempArray[4]=0;\r
+                                  SetDlgItemText(hwndDlg,201,(LPTSTR)TempArray);                                 \r
+                                 }\r
+                                 break;\r
+                         case LBN_SETFOCUS:\r
+                                 lbfocus=1;\r
+                                 break;\r
+                         case LBN_KILLFOCUS:\r
+                                 lbfocus=0;\r
+                                 break;\r
+                        }\r
+                        break;\r
+                }\r
+\r
+                switch(HIWORD(wParam))\r
+                {\r
+                 case BN_CLICKED:\r
+                        if(LOWORD(wParam)>=115 && LOWORD(wParam)<=118)\r
+                         scheatmethod=LOWORD(wParam)-115;\r
+                        break;\r
+                 case EN_CHANGE:\r
+                        {\r
+                         char TempArray[256];\r
+                         GetDlgItemText(hwndDlg,LOWORD(wParam),TempArray,256);\r
+                         switch(LOWORD(wParam))\r
+                         {\r
+                          case 110:cheatval1=StrToU8(TempArray);break;\r
+                          case 111:cheatval2=StrToU8(TempArray);break;\r
+                         }\r
+                        }\r
+                        break;\r
+                }\r
+\r
+\r
+                if(!(wParam>>16))\r
+                switch(wParam&0xFFFF)\r
+                {\r
+                 case 112:\r
+                          FCEUI_CheatSearchBegin();\r
+                          DoGet();\r
+                          break;\r
+                 case 113:\r
+                          FCEUI_CheatSearchEnd(scheatmethod,cheatval1,cheatval2);\r
+                          DoGet();\r
+                          break;\r
+                 case 114:\r
+                          FCEUI_CheatSearchSetCurrentAsOriginal();\r
+                          DoGet();\r
+                          break;\r
+                 case 107:\r
+                          FCEUI_CheatSearchShowExcluded();\r
+                          DoGet();\r
+                          break;\r
+                 case 105:\r
+                          {\r
+                           int a,v;\r
+                           char temp[256];\r
+\r
+                           GetDlgItemText(hwndDlg,201,temp,4+1);\r
+                           a=StrToU16(temp);\r
+                           GetDlgItemText(hwndDlg,202,temp,3+1);\r
+                           v=StrToU8(temp);\r
+\r
+                           GetDlgItemText(hwndDlg,200,temp,256);\r
+                           AddTheThing(hwndDlg,temp,a,v);\r
+                          }\r
+                          break;\r
+                 case 106:\r
+                        gornk:\r
+                        EndDialog(hwndDlg,0);\r
+                        break;\r
+                }\r
+              }\r
+  return 0;\r
+}\r
+\r
+static void ConfigAddCheat(HWND wnd)\r
+{\r
+ DialogBox(fceu_hInstance,"ADDCHEAT",wnd,AddCheatCallB);\r
+}\r
diff --git a/drivers/win/cheat.h b/drivers/win/cheat.h
new file mode 100644 (file)
index 0000000..b3cd3cc
--- /dev/null
@@ -0,0 +1 @@
+void ConfigCheats(HWND hParent);\r
diff --git a/drivers/win/common.h b/drivers/win/common.h
new file mode 100644 (file)
index 0000000..91b8d3d
--- /dev/null
@@ -0,0 +1,20 @@
+#include <stdio.h>\r
+#include <windows.h>\r
+#include <windowsx.h>\r
+\r
+#ifndef WIN32\r
+#define WIN32\r
+#endif\r
+#undef  WINNT\r
+#define NONAMELESSUNION\r
+\r
+#define DIRECTSOUND_VERSION  0x0700\r
+#define DIRECTDRAW_VERSION 0x0700\r
+#define DIRECTINPUT_VERSION     0x700\r
+#include "../../driver.h"\r
+\r
+extern HWND hAppWnd;\r
+extern HINSTANCE fceu_hInstance;\r
+\r
+extern int NoWaiting;\r
+extern FCEUGI *GI;\r
diff --git a/drivers/win/config.c b/drivers/win/config.c
new file mode 100644 (file)
index 0000000..761a7a9
--- /dev/null
@@ -0,0 +1,132 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+/****************************************************************/
+/*                     FCE Ultra                               */
+/*                                                             */
+/*     This file contains code to interface to the standard    */
+/*     FCE Ultra configuration file saving/loading code.       */
+/*                                                             */
+/****************************************************************/
+#include "../common/config.h"
+
+static CFGSTRUCT fceuconfig[]={
+
+        ACS(rfiles[0]),
+        ACS(rfiles[1]),
+        ACS(rfiles[2]),
+        ACS(rfiles[3]),
+        ACS(rfiles[4]),
+        ACS(rfiles[5]),
+        ACS(rfiles[6]),
+        ACS(rfiles[7]),
+        ACS(rfiles[8]),
+        ACS(rfiles[9]),
+
+        AC(ntsccol),AC(ntsctint),AC(ntschue),
+
+        AC(soundsleep),
+        NAC("palyo",palyo),
+       NAC("genie",genie),
+       NAC("fs",fullscreen),
+       NAC("vgamode",vmod),
+       NAC("sound",soundo),
+
+        ACS(gfsdir),
+
+        NACS("odcheats",DOvers[0]),
+        NACS("odmisc",DOvers[1]),
+        NACS("odnonvol",DOvers[2]),
+        NACS("odstates",DOvers[3]),
+        NACS("odsnaps",DOvers[4]),
+        NACS("odbase",DOvers[5]),
+
+       NAC("winsizemul",winsizemul),
+
+       AC(soundrate),
+        AC(soundbuftime),
+       AC(soundoptions),
+        AC(soundvolume),
+
+       NAC("eoptions",eoptions),
+        NACA("cpalette",cpalette),
+
+        ACA(joy),
+       ACA(joyA),ACA(joyB),ACA(joySelect),ACA(joyStart),
+
+        AC(joyOptions),
+        ACA(joyUp),ACA(joyDown),ACA(joyLeft),ACA(joyRight),
+
+        NACA("InputType",UsrInputType),
+       NAC("keyben",keybEnable),
+
+       NACA("keybm0",keyBMap[0]),
+       NACA("keybm1",keyBMap[1]),
+       NACA("keybm2",keyBMap[2]),
+       NACA("keybm3",keyBMap[3]),
+       NACA("ppasc0",powerpadsc[0]),
+       NACA("ppasc1",powerpadsc[1]),
+
+       NAC("ppaside",powerpadside),
+       NAC("vmcx",vmodes[0].x),
+       NAC("vmcy",vmodes[0].y),
+       NAC("vmcb",vmodes[0].bpp),
+       NAC("vmcf",vmodes[0].flags),
+       NAC("vmcxs",vmodes[0].xscale),
+       NAC("vmcys",vmodes[0].yscale),
+
+        NAC("srendline",srendlinen),
+        NAC("erendline",erendlinen),
+        NAC("srendlinep",srendlinep),
+        NAC("erendlinep",erendlinep),
+
+        AC(UsrInputTypeFC),
+       AC(winsync),
+        AC(fssync),
+        AC(NoFourScore),
+        ACA(fkbmap),
+        ENDCFGSTRUCT
+};
+
+static void SaveConfig(char *filename)
+{
+        DriverInterface(DES_GETNTSCTINT,&ntsctint);
+        DriverInterface(DES_GETNTSCHUE,&ntschue);
+        SaveFCEUConfig(filename,fceuconfig);
+}
+
+static void LoadConfig(char *filename)
+{
+        DriverInterface(DES_GETNTSCTINT,&ntsctint);
+        DriverInterface(DES_GETNTSCHUE,&ntschue);
+        LoadFCEUConfig(filename,fceuconfig);
+       DriverInterface(DES_NTSCCOL,&ntsccol);
+        DriverInterface(DES_SETNTSCTINT,&ntsctint);
+        DriverInterface(DES_SETNTSCHUE,&ntschue);
+
+       palyo&=1;
+       FCEUI_SetVidSystem(palyo);
+       genie&=1;
+       FCEUI_SetGameGenie(genie);
+       fullscreen&=1;
+        soundo&=1;
+        FCEUI_SetSoundVolume(soundvolume);
+}
+
diff --git a/drivers/win/input.c b/drivers/win/input.c
new file mode 100644 (file)
index 0000000..aea3f47
--- /dev/null
@@ -0,0 +1,288 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 2002 Ben Parnell\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+#include "common.h"\r
+#include <dinput.h>\r
+\r
+#include "input.h"\r
+#include "keyboard.h"\r
+#include "joystick.h"\r
+\r
+\r
+int UsrInputType[2]={SI_GAMEPAD,SI_GAMEPAD};\r
+int UsrInputTypeFC=SIFC_NONE;\r
+int InputType[2];\r
+int InputTypeFC;\r
+\r
+int NoFourScore=0;\r
+\r
+static uint32 powerpadbuf[2];\r
+\r
+LPDIRECTINPUT7 lpDI;\r
+\r
+void FixGIGO(void)\r
+{\r
+ InputType[0]=UsrInputType[0];\r
+ InputType[1]=UsrInputType[1];\r
+ InputTypeFC=UsrInputTypeFC;\r
+\r
+ if(GI)\r
+ {\r
+  if(GI->input[0]>=0)\r
+   InputType[0]=GI->input[0];\r
+  if(GI->input[1]>=0)\r
+   InputType[1]=GI->input[1];\r
+  if(GI->inputfc>=0)\r
+   InputTypeFC=GI->inputfc;\r
+  CreateInputStuff();\r
+ }\r
+}\r
+\r
+static uint32 JSreturn;\r
+static uint32 mousedata[3];\r
+\r
+\r
+static void ConfigGamePad(HWND hParent, int port);\r
+\r
+int InitDInput(void)\r
+{\r
+ HRESULT ddrval;\r
+\r
+ ddrval=DirectInputCreateEx(fceu_hInstance,DIRECTINPUT_VERSION,&IID_IDirectInput7,(LPVOID *)&lpDI,0);\r
+ if(ddrval!=DI_OK)\r
+ {\r
+  FCEUD_PrintError("DirectInput: Error creating DirectInput object.");\r
+  return 0;\r
+ }\r
+ return 1;\r
+}\r
+\r
+static int screenmode=0;\r
+void InputScreenChanged(int fs)\r
+{\r
+ int x;\r
+ for(x=0;x<2;x++)\r
+  if(InputType[x]==SI_ZAPPER)\r
+   FCEUI_SetInput(x,SI_ZAPPER,mousedata,fs);\r
+ if(InputTypeFC==SIFC_SHADOW)\r
+  FCEUI_SetInputFC(SIFC_SHADOW,mousedata,fs);\r
+ screenmode=fs;\r
+}\r
+\r
+void InitInputStuff(void)\r
+{\r
+   KeyboardInitialize();\r
+   InitJoysticks(hAppWnd);\r
+}\r
+\r
+void CreateInputStuff(void)\r
+{ \r
+   void *InputDPtr=0;\r
+   int x;\r
+   int TAttrib;\r
+\r
+   for(x=0;x<2;x++)\r
+   {\r
+    TAttrib=0;\r
+    switch(InputType[x])\r
+    {\r
+     case SI_GAMEPAD:InputDPtr=((uint8 *)&JSreturn)+(x<<1);\r
+                                break;\r
+     case SI_POWERPAD:InputDPtr=&powerpadbuf[x];break;\r
+     case SI_ARKANOID:InputDPtr=mousedata;break;\r
+     case SI_ZAPPER:InputDPtr=mousedata;\r
+                                TAttrib=screenmode;\r
+                                break;\r
+    }   \r
+    FCEUI_SetInput(x,InputType[x],InputDPtr,TAttrib);\r
+   }\r
+\r
+   TAttrib=0;\r
+   switch(InputTypeFC)\r
+   {\r
+    case SIFC_SHADOW:InputDPtr=mousedata;TAttrib=screenmode;break;\r
+    case SIFC_ARKANOID:InputDPtr=mousedata;break;    \r
+    case SIFC_FKB:InputDPtr=fkbkeys;memset(fkbkeys,0,sizeof(fkbkeys));break;\r
+   }\r
+   FCEUI_SetInputFC(InputTypeFC,InputDPtr,TAttrib);\r
+   FCEUI_DisableFourScore(NoFourScore);\r
+}\r
+\r
+void DestroyInput(void)\r
+{\r
+   KillJoysticks();\r
+   KeyboardClose();\r
+}\r
+\r
+void FCEUD_UpdateInput(void)\r
+{\r
+  int x;\r
+  uint32 JS;\r
+  int t=0;\r
+\r
+  KeyboardUpdate();\r
+\r
+  for(x=0;x<2;x++)\r
+   switch(InputType[x])\r
+   {\r
+    case SI_GAMEPAD:t|=1;break;\r
+    case SI_ARKANOID:t|=2;break;\r
+    case SI_ZAPPER:t|=2;break;\r
+    case SI_POWERPAD:powerpadbuf[x]=UpdatePPadData(x);break;\r
+   }\r
+  switch(InputTypeFC)\r
+  {\r
+   case SIFC_ARKANOID:t|=2;break;\r
+   case SIFC_SHADOW:t|=2;break;\r
+   case SIFC_FKB: if(cidisabled) UpdateFKB();break;\r
+  }\r
+  if(t&1)\r
+  {\r
+   JS=KeyboardDodo();\r
+   if(joy[0]|joy[1]|joy[2]|joy[3])\r
+    JS|=(uint32)GetJSOr();\r
+   JSreturn=(JS&0xFF000000)|(JS&0xFF)|((JS&0xFF0000)>>8)|((JS&0xFF00)<<8);   \r
+  }\r
+  if(t&2)  \r
+   GetMouseData(&mousedata[0], &mousedata[1], &mousedata[2]);\r
+}\r
+\r
+\r
+BOOL CALLBACK InputConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+  static void (*boopar[5])(HWND hParent, int port)={0,ConfigGamePad,0,ConfigKeyboardiePowerpad,0};\r
+  static void (*boopar2[5])(HWND hParent)={0,0,0,0,ConfigFKB};\r
+  static char *strn[5]={"<none>","Gamepad","Zapper","Power Pad","Arkanoid Paddle"};\r
+  static char *strf[5]={"<none>","Arkanoid Paddle","Hyper Shot gun","4-Player Adapter","Family Keyboard"};\r
+  int x;\r
+  \r
+  switch(uMsg) {\r
+   case WM_INITDIALOG:                \r
+                for(x=0;x<2;x++)        \r
+                {\r
+                 int y;\r
+\r
+                 for(y=0;y<5;y++)\r
+                  SendDlgItemMessage(hwndDlg,104+x,CB_ADDSTRING,0,(LPARAM)(LPSTR)strn[y]);\r
+\r
+                 SendDlgItemMessage(hwndDlg,104+x,CB_SETCURSEL,UsrInputType[x],(LPARAM)(LPSTR)0);\r
+                 EnableWindow(GetDlgItem(hwndDlg,106+x),boopar[InputType[x]]?1:0);\r
+                 SetDlgItemText(hwndDlg,200+x,(LPTSTR)strn[InputType[x]]);\r
+                }\r
+\r
+\r
+                {\r
+                 int y;\r
+                 for(y=0;y<5;y++)\r
+                  SendDlgItemMessage(hwndDlg,110,CB_ADDSTRING,0,(LPARAM)(LPSTR)strf[y]);\r
+                 SendDlgItemMessage(hwndDlg,110,CB_SETCURSEL,UsrInputTypeFC,(LPARAM)(LPSTR)0);                \r
+                 EnableWindow(GetDlgItem(hwndDlg,111),boopar2[InputTypeFC]?1:0);\r
+                 SetDlgItemText(hwndDlg,202,(LPTSTR)strf[InputTypeFC]);\r
+                }\r
+                \r
+                break;\r
+   case WM_CLOSE:\r
+   case WM_QUIT: goto gornk;\r
+   case WM_COMMAND:\r
+                if(HIWORD(wParam)==CBN_SELENDOK)\r
+                {\r
+                 switch(LOWORD(wParam))\r
+                 {\r
+                  case 104:\r
+                  case 105:UsrInputType[LOWORD(wParam)-104]=InputType[LOWORD(wParam)-104]=SendDlgItemMessage(hwndDlg,LOWORD(wParam),CB_GETCURSEL,0,(LPARAM)(LPSTR)0);\r
+                           EnableWindow( GetDlgItem(hwndDlg,LOWORD(wParam)+2),boopar[InputType[LOWORD(wParam)-104]]?1:0);\r
+                           SetDlgItemText(hwndDlg,200+LOWORD(wParam)-104,(LPTSTR)strn[InputType[LOWORD(wParam)-104]]);\r
+                           break;\r
+                  case 110:UsrInputTypeFC=InputTypeFC=SendDlgItemMessage(hwndDlg,110,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);\r
+                           EnableWindow(GetDlgItem(hwndDlg,111),boopar2[InputTypeFC]?1:0);\r
+                           SetDlgItemText(hwndDlg,202,(LPTSTR)strf[InputTypeFC]);\r
+                           break;\r
+                           \r
+                 }\r
+\r
+                }\r
+                if(!(wParam>>16))\r
+                switch(wParam&0xFFFF)\r
+                {\r
+                 case 111:\r
+                  if(boopar2[InputTypeFC])\r
+                   boopar2[InputTypeFC](hwndDlg);\r
+                  break;\r
+\r
+                 case 107:\r
+                 case 106:\r
+                  {\r
+                   int t=(wParam&0xFFFF)-106;\r
+                   if(boopar[InputType[t]])\r
+                    boopar[InputType[t]](hwndDlg,t);\r
+                  }\r
+                  break;\r
+                 case 1:\r
+                        gornk:\r
+                        EndDialog(hwndDlg,0);\r
+                        break;\r
+               }\r
+              }\r
+  return 0;\r
+}\r
+\r
+void ConfigInput(HWND hParent)\r
+{\r
+  DialogBox(fceu_hInstance,"INPUTCONFIG",hParent,InputConCallB);\r
+  CreateInputStuff();\r
+}\r
+\r
+\r
+static int porttemp;\r
+\r
+BOOL CALLBACK GPConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+  switch(uMsg) {\r
+   case WM_INITDIALOG:                \r
+                if(NoFourScore)\r
+                 CheckDlgButton(hwndDlg,200,BST_CHECKED);\r
+                break;\r
+   case WM_CLOSE:\r
+   case WM_QUIT: goto gornk;\r
+   case WM_COMMAND:\r
+                if(!(wParam>>16))\r
+                switch(wParam&0xFFFF)\r
+                {\r
+                 case 107:ConfigJoystickies(hwndDlg, porttemp);break;\r
+                 case 106:ConfigKeyboardie(hwndDlg, porttemp);break;\r
+                 case 1:\r
+                        gornk:\r
+                        NoFourScore=0;\r
+                        if(IsDlgButtonChecked(hwndDlg,200)==BST_CHECKED)\r
+                         NoFourScore=1;\r
+                        EndDialog(hwndDlg,0);\r
+                        break;\r
+               }\r
+              }\r
+  return 0;\r
+}\r
+\r
+static void ConfigGamePad(HWND hParent, int port)\r
+{\r
+  porttemp=port;\r
+  DialogBox(fceu_hInstance,"GAMEPADCONFIG",hParent,GPConCallB);\r
+}\r
+\r
+\r
diff --git a/drivers/win/input.h b/drivers/win/input.h
new file mode 100644 (file)
index 0000000..559f1af
--- /dev/null
@@ -0,0 +1,25 @@
+void ConfigInput(HWND hParent);\r
+int InitDInput(void);\r
+void CreateInputStuff(void);\r
+void InitInputStuff(void);\r
+void DestroyInput(void);\r
+void InputScreenChanged(int fs);\r
+void FixGIGO(void);\r
+\r
+extern LPDIRECTINPUT7 lpDI;\r
+\r
+#define JOY_A   1\r
+#define JOY_B   2\r
+#define JOY_SELECT      4\r
+#define JOY_START       8\r
+#define JOY_UP  0x10\r
+#define JOY_DOWN        0x20\r
+#define JOY_LEFT        0x40\r
+#define JOY_RIGHT       0x80\r
+\r
+\r
+extern int InputType[2];\r
+extern int InputTypeFC;\r
+extern int NoFourScore;\r
+extern int UsrInputType[2];\r
+extern int UsrInputTypeFC;\r
diff --git a/drivers/win/joystick.c b/drivers/win/joystick.c
new file mode 100644 (file)
index 0000000..375b7af
--- /dev/null
@@ -0,0 +1,407 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 2002 Ben Parnell\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+#include "common.h"\r
+#include <dinput.h>\r
+\r
+#include "input.h"\r
+#include "joystick.h"\r
+\r
+\r
+HRESULT  ddrval;\r
+\r
+static GUID joyGUID[64];\r
+\r
+static int joycounter;\r
+\r
+static LPDIRECTINPUTDEVICE7 lpJoy[4]={0,0,0,0};\r
+\r
+int joyOptions[4]={0,0,0,0};\r
+int joyA[4]={1,1,1,1};\r
+int joyB[4]={0,0,0,0};\r
+int joySelect[4]={2,2,2,2};\r
+int joyStart[4]={3,3,3,3};\r
+int joyUp[4]={4,4,4,4};\r
+int joyDown[4]={5,5,5,5};\r
+int joyLeft[4]={6,6,6,6};\r
+int joyRight[4]={7,7,7,7};\r
+\r
+int joy[4]={0,0,0,0};\r
+\r
+static int JoyXMax[4];\r
+static int JoyXMin[4];\r
+\r
+static int JoyYMax[4];\r
+static int JoyYMin[4];\r
+\r
+static DIJOYSTATE2 JoyStatus;\r
+\r
+static void ShowDIJErr(int w, char *s)\r
+{\r
+ char tempo[128];\r
+ sprintf(tempo,"DirectInput: Joystick %d: %s",w+1,s);\r
+ FCEUD_PrintError(tempo);\r
+}\r
+\r
+static void JoyAutoRestore(HRESULT ddrval,LPDIRECTINPUTDEVICE7 lpJJoy)\r
+{\r
+   switch(ddrval)\r
+    {\r
+     case DIERR_INPUTLOST:\r
+     case DIERR_NOTACQUIRED:\r
+                           IDirectInputDevice7_Acquire(lpJJoy);\r
+                           break;\r
+    }\r
+}\r
+\r
+static int GetJoystickButton(int x)\r
+{\r
+ int errc=0;\r
+ int z;\r
+\r
+ if(lpJoy[x])\r
+ {\r
+   doagaino:\r
+   if(errc>8) return(-1);\r
+\r
+   ddrval=IDirectInputDevice7_Poll(lpJoy[x]);\r
+   if(ddrval!=DI_OK && ddrval!=DI_NOEFFECT) {JoyAutoRestore(ddrval,lpJoy[x]);errc++;goto doagaino;}\r
+\r
+   ddrval=IDirectInputDevice7_GetDeviceState(lpJoy[x],sizeof(JoyStatus),&JoyStatus);\r
+   if(ddrval!=DI_OK) {JoyAutoRestore(ddrval,lpJoy[x]);errc++;goto doagaino;}\r
+\r
+   for(z=0;z<128;z++)\r
+    if(JoyStatus.rgbButtons[z]&0x80)\r
+     return z;\r
+ }\r
+ return(-1);\r
+}\r
+\r
+uint32 GetJSOr(void)\r
+{\r
+        unsigned long ret;\r
+        int x;\r
+        ret=0;\r
+\r
+        for(x=0;x<4;x++)\r
+        {\r
+         if(lpJoy[x])\r
+         {\r
+\r
+          ddrval=IDirectInputDevice7_Poll(lpJoy[x]);\r
+          if(ddrval!=DI_OK && ddrval!=DI_NOEFFECT) JoyAutoRestore(ddrval,lpJoy[x]);\r
+\r
+          ddrval=IDirectInputDevice7_GetDeviceState(lpJoy[x],sizeof(JoyStatus),&JoyStatus);\r
+          if(ddrval!=DI_OK) JoyAutoRestore(ddrval,lpJoy[x]);\r
+\r
+          if(joyOptions[x]&1)\r
+          {\r
+           if(JoyStatus.rgbButtons[joyUp[x]&127]&0x80) ret|=JOY_UP<<(x<<3);\r
+           if(JoyStatus.rgbButtons[joyDown[x]&127]&0x80) ret|=JOY_DOWN<<(x<<3);\r
+           if(JoyStatus.rgbButtons[joyLeft[x]&127]&0x80) ret|=JOY_LEFT<<(x<<3);\r
+           if(JoyStatus.rgbButtons[joyRight[x]&127]&0x80) ret|=JOY_RIGHT<<(x<<3);\r
+          }\r
+          else\r
+          {\r
+           if(JoyStatus.lX>=JoyXMax[x])\r
+            ret|=JOY_RIGHT<<(x<<3);\r
+           else if(JoyStatus.lX<=JoyXMin[x])\r
+            ret|=JOY_LEFT<<(x<<3);\r
+\r
+           if(JoyStatus.lY>=JoyYMax[x])\r
+            ret|=JOY_DOWN<<(x<<3);\r
+           else if(JoyStatus.lY<=JoyYMin[x])\r
+            ret|=JOY_UP<<(x<<3);\r
+          }\r
+          if(JoyStatus.rgbButtons[joyA[x]&127]&0x80) ret|=1<<(x<<3);\r
+          if(JoyStatus.rgbButtons[joyB[x]&127]&0x80) ret|=2<<(x<<3);\r
+          if(JoyStatus.rgbButtons[joySelect[x]&127]&0x80) ret|=4<<(x<<3);\r
+          if(JoyStatus.rgbButtons[joyStart[x]&127]&0x80) ret|=8<<(x<<3);\r
+         }\r
+        }\r
+\r
+        return ret;\r
+}\r
+\r
+static void KillJoystick(int w)\r
+{\r
+ if(lpJoy[w])\r
+ {\r
+  IDirectInputDevice7_Unacquire(lpJoy[w]);\r
+  IDirectInputDevice7_Release(lpJoy[w]);\r
+  lpJoy[w]=0;\r
+ }\r
+}\r
+\r
+void KillJoysticks(void)\r
+{\r
+ int x;\r
+ for(x=0;x<4;x++)\r
+  KillJoystick(x);\r
+}\r
+\r
+static BOOL CALLBACK JoystickFound(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)\r
+{\r
+   if(joycounter<64)\r
+   {\r
+    joyGUID[joycounter]=lpddi->guidInstance;\r
+    joycounter++;\r
+    if(pvRef)\r
+    {\r
+     SendDlgItemMessage(pvRef,106,CB_ADDSTRING,0,(LPARAM)(LPSTR)lpddi->tszProductName);\r
+     SendDlgItemMessage(pvRef,112,CB_ADDSTRING,0,(LPARAM)(LPSTR)lpddi->tszProductName);\r
+    }\r
+    return DIENUM_CONTINUE;\r
+   }\r
+   else\r
+    return 0;   \r
+}\r
+\r
+void InitJoystick(int w, HWND wnd)\r
+{\r
+  if(joy[w])\r
+  {\r
+   if(joy[w]>joycounter)\r
+   {\r
+    ShowDIJErr(w,"Not found."); \r
+    joy[w]=0;\r
+    return;\r
+   }\r
+   ddrval=IDirectInput7_CreateDeviceEx(lpDI,&joyGUID[joy[w]-1],&IID_IDirectInputDevice7,(LPVOID *)&lpJoy[w],0);\r
+   if(ddrval != DI_OK)\r
+   {   \r
+    ShowDIJErr(w,"Error creating device.");\r
+    joy[w]=0;\r
+    return;\r
+   }\r
+   ddrval=IDirectInputDevice7_SetCooperativeLevel(lpJoy[w],wnd,DISCL_FOREGROUND|DISCL_NONEXCLUSIVE);\r
+   if (ddrval != DI_OK)\r
+   {\r
+    ShowDIJErr(w,"Error setting cooperative level.");\r
+    KillJoystick(w);\r
+    joy[w]=0;\r
+    return;\r
+   }\r
+   ddrval=IDirectInputDevice7_SetDataFormat(lpJoy[w],&c_dfDIJoystick2);\r
+   if (ddrval != DI_OK)\r
+   {\r
+    ShowDIJErr(w,"Error setting data format.");\r
+    KillJoystick(w);\r
+    joy[w]=0;\r
+    return;\r
+   }\r
+\r
+   {\r
+    DIPROPRANGE diprg;\r
+    int r;\r
+\r
+    memset(&diprg,0,sizeof(DIPROPRANGE));\r
+    diprg.diph.dwSize=sizeof(DIPROPRANGE);\r
+    diprg.diph.dwHeaderSize=sizeof(DIPROPHEADER);\r
+    diprg.diph.dwHow=DIPH_BYOFFSET;\r
+    diprg.diph.dwObj=DIJOFS_X;\r
+    ddrval=IDirectInputDevice7_GetProperty(lpJoy[w],DIPROP_RANGE,&diprg.diph);\r
+    if(ddrval!=DI_OK)\r
+    {\r
+     ShowDIJErr(w,"Error getting X axis range.");\r
+     joy[w]=0;\r
+     KillJoystick(w);\r
+     joy[w]=0;\r
+     return;\r
+    }\r
+    r=diprg.lMax-diprg.lMin;\r
+    JoyXMax[w]=diprg.lMax-(r>>2);\r
+    JoyXMin[w]=diprg.lMin+(r>>2);\r
+\r
+    memset(&diprg,0,sizeof(DIPROPRANGE));\r
+    diprg.diph.dwSize=sizeof(DIPROPRANGE);\r
+    diprg.diph.dwHeaderSize=sizeof(DIPROPHEADER);\r
+    diprg.diph.dwHow=DIPH_BYOFFSET;\r
+    diprg.diph.dwObj=DIJOFS_Y;\r
+    ddrval=IDirectInputDevice7_GetProperty(lpJoy[w],DIPROP_RANGE,&diprg.diph);\r
+    if(ddrval!=DI_OK)\r
+    {\r
+     ShowDIJErr(w,"Error getting X axis range.");\r
+     KillJoystick(w);\r
+     joy[w]=0;\r
+     return;\r
+    }\r
+    r=diprg.lMax-diprg.lMin;\r
+    JoyYMax[w]=diprg.lMax-(r>>2);\r
+    JoyYMin[w]=diprg.lMin+(r>>2);\r
+   }\r
+\r
+  }\r
+}\r
+\r
+void InitJoysticks(HWND wnd)\r
+{\r
+ int x;\r
+\r
+ joycounter=0;\r
+ IDirectInput7_EnumDevices(lpDI, DIDEVTYPE_JOYSTICK,JoystickFound,0,DIEDFL_ATTACHEDONLY);\r
\r
+ for(x=0;x<4;x++)\r
+  InitJoystick(x,wnd);\r
+}\r
+\r
+\r
+static int joyconport;\r
+\r
+static BOOL CALLBACK JoyConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+  char tempo[64];\r
+  int x;\r
+  static int bid;\r
+\r
+  switch(uMsg) {\r
+   case WM_TIMER:\r
+                 if(bid>=200 && bid<=215)\r
+                 {\r
+                  int z;\r
+\r
+                  /* GetJoystickButton() makes sure there is a joystick,\r
+                     so we don't need to here.\r
+                  */                     \r
+                  if(bid<=207)\r
+                  {\r
+                   if( (z=GetJoystickButton(joyconport))!=-1)\r
+                     SetDlgItemInt(hwndDlg,bid,z,0);\r
+                   }\r
+                   else\r
+                   {\r
+                    if( (z=GetJoystickButton(2+joyconport))!=-1)\r
+                     SetDlgItemInt(hwndDlg,bid,z,0);\r
+                   }\r
+                 }\r
+                break;\r
+   case WM_INITDIALOG:\r
+                bid=0;\r
+                SetTimer(hwndDlg,666,20,0);     /* Every 20ms(50x a second).*/\r
+\r
+                InitJoysticks(hwndDlg);\r
+\r
+                SendDlgItemMessage(hwndDlg,106,CB_ADDSTRING,0,(LPARAM)(LPSTR)"<none>");\r
+                SendDlgItemMessage(hwndDlg,112,CB_ADDSTRING,0,(LPARAM)(LPSTR)"<none>");\r
+\r
+                sprintf(tempo,"Virtual Gamepad %d",joyconport+1);\r
+                SetDlgItemText(hwndDlg,102,tempo);\r
+                sprintf(tempo,"Virtual Gamepad %d",joyconport+3);\r
+                SetDlgItemText(hwndDlg,104,tempo);\r
+\r
+                for(x=0;x<=2;x+=2)\r
+                {\r
+                 SetDlgItemInt(hwndDlg,200+(x<<2),joySelect[x+joyconport],0);\r
+                 SetDlgItemInt(hwndDlg,201+(x<<2),joyStart[x+joyconport],0);\r
+                 SetDlgItemInt(hwndDlg,202+(x<<2),joyB[x+joyconport],0);\r
+                 SetDlgItemInt(hwndDlg,203+(x<<2),joyA[x+joyconport],0);\r
+\r
+                 SetDlgItemInt(hwndDlg,204+(x<<2),joyUp[x+joyconport],0);\r
+                 SetDlgItemInt(hwndDlg,205+(x<<2),joyDown[x+joyconport],0);\r
+                 SetDlgItemInt(hwndDlg,206+(x<<2),joyLeft[x+joyconport],0);\r
+                 SetDlgItemInt(hwndDlg,207+(x<<2),joyRight[x+joyconport],0);\r
+\r
+                }\r
+                joycounter=0;\r
+                IDirectInput7_EnumDevices(lpDI, DIDEVTYPE_JOYSTICK,JoystickFound,hwndDlg,DIEDFL_ATTACHEDONLY);\r
+\r
+                SendDlgItemMessage(hwndDlg,106,CB_SETCURSEL,joy[0+joyconport],(LPARAM)(LPSTR)0);\r
+                SendDlgItemMessage(hwndDlg,112,CB_SETCURSEL,joy[2+joyconport],(LPARAM)(LPSTR)0);\r
+                \r
+                if(joyOptions[joyconport]&1)\r
+                 CheckDlgButton(hwndDlg,300,BST_CHECKED);\r
+                if(joyOptions[joyconport+2]&1)\r
+                 CheckDlgButton(hwndDlg,301,BST_CHECKED);               \r
+                break;\r
+   case WM_CLOSE:\r
+   case WM_QUIT: goto gornk;\r
+   case WM_COMMAND:\r
+                if(HIWORD(wParam)==EN_SETFOCUS)\r
+                {\r
+                 bid=LOWORD(wParam);\r
+                }\r
+                else if(HIWORD(wParam)==EN_KILLFOCUS)\r
+                {\r
+                 bid=0;\r
+                }\r
+                else if(HIWORD(wParam)==CBN_SELENDOK)\r
+                {\r
+                 switch(LOWORD(wParam))\r
+                 {\r
+                  case 106:\r
+                   KillJoystick(joyconport);\r
+                   joy[0+(joyconport)]=SendDlgItemMessage(hwndDlg,106,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);\r
+                   InitJoystick(joyconport,hwndDlg);\r
+                   SendDlgItemMessage(hwndDlg,106,CB_SETCURSEL,joy[0+joyconport],(LPARAM)(LPSTR)0);\r
+                   break;\r
+                  case 112:\r
+                   KillJoystick(2+joyconport);\r
+                   joy[2+(joyconport)]=SendDlgItemMessage(hwndDlg,112,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);\r
+                   InitJoystick(2+joyconport,hwndDlg);                                      \r
+                   SendDlgItemMessage(hwndDlg,112,CB_SETCURSEL,joy[2+joyconport],(LPARAM)(LPSTR)0);\r
+                   break;\r
+                 }\r
+                }\r
+\r
+                if(!(wParam>>16))\r
+                switch(wParam&0xFFFF)\r
+                {\r
+                 case 1:\r
+                        gornk:\r
+\r
+                        KillTimer(hwndDlg,666);\r
+                        KillJoysticks();\r
+\r
+                        for(x=0;x<=2;x+=2)\r
+                        {\r
+                         joySelect[x+(joyconport)]=GetDlgItemInt(hwndDlg,200+(x<<2),0,0);\r
+                         joyStart[x+(joyconport)]=GetDlgItemInt(hwndDlg,201+(x<<2),0,0);\r
+                         joyB[x+(joyconport)]=GetDlgItemInt(hwndDlg,202+(x<<2),0,0);\r
+                         joyA[x+(joyconport)]=GetDlgItemInt(hwndDlg,203+(x<<2),0,0);\r
+\r
+                         joyUp[x+(joyconport)]=GetDlgItemInt(hwndDlg,204+(x<<2),0,0);\r
+                         joyDown[x+(joyconport)]=GetDlgItemInt(hwndDlg,205+(x<<2),0,0);\r
+                         joyLeft[x+(joyconport)]=GetDlgItemInt(hwndDlg,206+(x<<2),0,0);\r
+                         joyRight[x+(joyconport)]=GetDlgItemInt(hwndDlg,207+(x<<2),0,0);\r
+                        }\r
+                        if(IsDlgButtonChecked(hwndDlg,300)==BST_CHECKED)\r
+                         joyOptions[joyconport]|=1;\r
+                        else\r
+                         joyOptions[joyconport]&=~1;\r
+                        if(IsDlgButtonChecked(hwndDlg,301)==BST_CHECKED)\r
+                         joyOptions[joyconport+2]|=1;\r
+                        else\r
+                         joyOptions[joyconport+2]&=~1;                        \r
+                        EndDialog(hwndDlg,0);\r
+                        break;\r
+               }\r
+              }\r
+  return 0;\r
+}\r
+\r
+void ConfigJoystickies(HWND hParent, int port)\r
+{\r
+ joyconport=port;\r
+\r
+ KillJoysticks();\r
+ DialogBox(fceu_hInstance,"JOYCONFIG",hParent,JoyConCallB);\r
+ InitJoysticks(hAppWnd);\r
+}\r
+\r
diff --git a/drivers/win/joystick.h b/drivers/win/joystick.h
new file mode 100644 (file)
index 0000000..a5cdb40
--- /dev/null
@@ -0,0 +1,16 @@
+void ConfigJoystickies(HWND hParent, int port);\r
+void InitJoysticks(HWND wnd);\r
+void KillJoysticks(void);\r
+uint32 GetJSOr(void);\r
+\r
+extern int joyOptions[4];\r
+extern int joyA[4];\r
+extern int joyB[4];\r
+extern int joySelect[4];\r
+extern int joyStart[4];\r
+extern int joyUp[4];\r
+extern int joyDown[4];\r
+extern int joyLeft[4];\r
+extern int joyRight[4];\r
+extern int joy[4];\r
+\r
diff --git a/drivers/win/keyboard.c b/drivers/win/keyboard.c
new file mode 100644 (file)
index 0000000..b521081
--- /dev/null
@@ -0,0 +1,458 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "common.h"
+#include <dinput.h>
+
+
+#include "input.h"
+#include "keyboard.h"
+
+#include "keyscan.h"
+
+
+HRESULT  ddrval;
+
+static LPDIRECTINPUTDEVICE7 lpdid=0;
+static int porttemp;
+
+
+int keyBMap[4][8]={
+                   {SCAN_LEFTALT,SCAN_LEFTCONTROL,SCAN_TAB,SCAN_ENTER,SCAN_BL_CURSORUP,SCAN_BL_CURSORDOWN,SCAN_BL_CURSORLEFT,SCAN_BL_CURSORRIGHT},
+                   {SCAN_LEFTALT,SCAN_LEFTCONTROL,SCAN_TAB,SCAN_ENTER,SCAN_BL_CURSORUP,SCAN_BL_CURSORDOWN,SCAN_BL_CURSORLEFT,SCAN_BL_CURSORRIGHT},
+                   {SCAN_LEFTALT,SCAN_LEFTCONTROL,SCAN_TAB,SCAN_ENTER,SCAN_BL_CURSORUP,SCAN_BL_CURSORDOWN,SCAN_BL_CURSORLEFT,SCAN_BL_CURSORRIGHT},
+                   {SCAN_LEFTALT,SCAN_LEFTCONTROL,SCAN_TAB,SCAN_ENTER,SCAN_BL_CURSORUP,SCAN_BL_CURSORDOWN,SCAN_BL_CURSORLEFT,SCAN_BL_CURSORRIGHT}
+                  };
+int keybEnable=1;
+
+int powerpadside=0;
+int powerpadsc[2][12]={
+                              {
+                               SCAN_O,SCAN_P,SCAN_BRACKET_LEFT,
+                               SCAN_BRACKET_RIGHT,SCAN_K,SCAN_L,SCAN_SEMICOLON,SCAN_APOSTROPHE,
+                               SCAN_M,SCAN_COMMA,SCAN_PERIOD,SCAN_SLASH
+                              },
+                              {
+                               SCAN_O,SCAN_P,SCAN_BRACKET_LEFT,
+                               SCAN_BRACKET_RIGHT,SCAN_K,SCAN_L,SCAN_SEMICOLON,SCAN_APOSTROPHE,
+                               SCAN_M,SCAN_COMMA,SCAN_PERIOD,SCAN_SLASH
+                              }
+                             };
+
+
+
+
+void KeyboardClose(void)
+{
+ if(lpdid) IDirectInputDevice7_Unacquire(lpdid);
+ lpdid=0;
+}
+
+static char keys[256];
+static void KeyboardUpdateState(void)
+{
+ ddrval=IDirectInputDevice7_GetDeviceState(lpdid,256,keys);
+ switch(ddrval)
+  {
+   case DIERR_INPUTLOST:
+   case DIERR_NOTACQUIRED:
+                         IDirectInputDevice7_Acquire(lpdid);
+                         break;
+  }
+}
+
+int KeyboardInitialize(void)
+{
+
+ if(lpdid)
+  return(1);
+
+ ddrval=IDirectInput7_CreateDeviceEx(lpDI, &GUID_SysKeyboard,&IID_IDirectInputDevice7, (LPVOID *)&lpdid,0);
+ if(ddrval != DI_OK)
+ {
+  FCEUD_PrintError("DirectInput: Error creating keyboard device.");
+  return 0;
+ }
+
+ ddrval=IDirectInputDevice7_SetCooperativeLevel(lpdid, hAppWnd,DISCL_FOREGROUND|DISCL_NONEXCLUSIVE);
+ if(ddrval != DI_OK)
+ {
+  FCEUD_PrintError("DirectInput: Error setting keyboard cooperative level.");
+  return 0;
+ }
+
+ ddrval=IDirectInputDevice7_SetDataFormat(lpdid,&c_dfDIKeyboard);
+ if(ddrval != DI_OK)
+ {
+  FCEUD_PrintError("DirectInput: Error setting keyboard data format.");
+  return 0;
+ }
+
+ ddrval=IDirectInputDevice7_Acquire(lpdid);
+ if(ddrval != DI_OK)
+ {
+  FCEUD_PrintError("DirectInput: Error acquiring keyboard.");
+  return 0;
+ }
+ return 1;
+}
+
+static int DIPS=0;
+static uint8 keyonce[256];
+#define KEY(__a) keys[SCAN_##__a]
+#define keyonly(__a,__z) {if(KEY(__a)){if(!keyonce[SCAN_##__a]) {keyonce[SCAN_##__a]=1;__z}} else{keyonce[SCAN_##__a]=0;}}
+int cidisabled=0;
+
+void KeyboardUpdate(void)
+{ 
+ KeyboardUpdateState();
+
+ if(InputTypeFC==SIFC_FKB && cidisabled)
+  return;
+
+ NoWaiting&=~1;
+ if(KEY(GRAVE))
+  NoWaiting|=1;
+
+ if(GI)
+ {
+  if(GI->type==GIT_FDS)
+  {
+   keyonly(S,DriverInterface(DES_FDSSELECT,0);)
+   keyonly(I,DriverInterface(DES_FDSINSERT,0);)
+   keyonly(E,DriverInterface(DES_FDSEJECT,0);)
+  }
+
+  if(GI->type!=GIT_NSF)
+  {
+   keyonly(F5,FCEUI_SaveState();)
+   keyonly(F7,FCEUI_LoadState();)
+  }
+  keyonly(F9,FCEUI_SaveSnapshot();)
+
+  if(GI->type==GIT_VSUNI)
+  {
+   keyonly(C,DriverInterface(DES_VSUNICOIN,0);)
+   keyonly(V,DIPS^=1;DriverInterface(DES_VSUNITOGGLEDIPVIEW,0);)
+   if(!(DIPS&1)) goto DIPSless;
+   keyonly(1,DriverInterface(DES_VSUNIDIPSET,(void *)1);)
+   keyonly(2,DriverInterface(DES_VSUNIDIPSET,(void *)2);)
+   keyonly(3,DriverInterface(DES_VSUNIDIPSET,(void *)3);)
+   keyonly(4,DriverInterface(DES_VSUNIDIPSET,(void *)4);)
+   keyonly(5,DriverInterface(DES_VSUNIDIPSET,(void *)5);)
+   keyonly(6,DriverInterface(DES_VSUNIDIPSET,(void *)6);)
+   keyonly(7,DriverInterface(DES_VSUNIDIPSET,(void *)7);)
+   keyonly(8,DriverInterface(DES_VSUNIDIPSET,(void *)8);)
+  }
+  else
+  {
+   keyonly(H,DriverInterface(DES_NTSCSELHUE,0);)
+   keyonly(T,DriverInterface(DES_NTSCSELTINT,0);)
+   if(KEY(KP_MINUS) || KEY(MINUS)) DriverInterface(DES_NTSCDEC,0);
+   if(KEY(KP_PLUS) || KEY(EQUAL)) DriverInterface(DES_NTSCINC,0);
+
+   DIPSless:
+   keyonly(0,FCEUI_SelectState(0);)
+   keyonly(1,FCEUI_SelectState(1);)
+   keyonly(2,FCEUI_SelectState(2);)
+   keyonly(3,FCEUI_SelectState(3);)
+   keyonly(4,FCEUI_SelectState(4);)
+   keyonly(5,FCEUI_SelectState(5);)
+   keyonly(6,FCEUI_SelectState(6);)
+   keyonly(7,FCEUI_SelectState(7);)
+   keyonly(8,FCEUI_SelectState(8);)
+   keyonly(9,FCEUI_SelectState(9);)
+  }
+ }
+}
+
+uint32 KeyboardDodo(void)
+{
+ uint32 JS=0;
+
+
+ if(GI)
+ if(GI->type!=GIT_NSF)
+ {
+  int x,y,u,b;
+
+  for(u=0;u<4;u++)
+  {
+   if(keybEnable&(1<<u))
+   {
+    int *tmpo=keyBMap[u];
+    x=y=0;
+
+    for(b=3;b>=0;b--)
+     if(keys[tmpo[b]]) JS|=(1<<b)<<(u<<3);
+
+    if(keys[tmpo[4]])    y|= JOY_UP;
+    if(keys[tmpo[5]])  y|= JOY_DOWN;
+    if(keys[tmpo[6]])  x|= JOY_LEFT;
+    if(keys[tmpo[7]]) x|= JOY_RIGHT;
+
+    if(y!=(JOY_DOWN|JOY_UP)) JS|=y<<(u<<3);
+    if(x!=(JOY_LEFT|JOY_RIGHT)) JS|=x<<(u<<3);
+   }
+  }
+ }
+ return JS;
+}
+
+uint32 UpdatePPadData(int w)
+{
+ static const char shifttableA[12]={8,9,0,1,11,7,4,2,10,6,5,3};
+ static const char shifttableB[12]={1,0,9,8,2,4,7,11,3,5,6,10};
+ uint32 r=0;
+ int *ppadtsc=powerpadsc[w];
+ int x;
+
+ if(powerpadside&(1<<w))
+ {
+  for(x=0;x<12;x++)
+   if(keys[ppadtsc[x]]) r|=1<<shifttableA[x];
+ }
+ else
+ {
+  for(x=0;x<12;x++)
+   if(keys[ppadtsc[x]]) r|=1<<shifttableB[x];
+ }
+ return r;
+}
+
+int fkbmap[0x48]=
+{
+ SCAN_F1,SCAN_F2,SCAN_F3,SCAN_F4,SCAN_F5,SCAN_F6,SCAN_F7,SCAN_F8,
+ SCAN_1,SCAN_2,SCAN_3,SCAN_4,SCAN_5,SCAN_6,SCAN_7,SCAN_8,SCAN_9,SCAN_0,
+        SCAN_MINUS,SCAN_EQUAL,SCAN_BACKSLASH,SCAN_BACKSPACE,
+ SCAN_ESCAPE,SCAN_Q,SCAN_W,SCAN_E,SCAN_R,SCAN_T,SCAN_Y,SCAN_U,SCAN_I,SCAN_O,
+        SCAN_P,SCAN_GRAVE,SCAN_BRACKET_LEFT,SCAN_ENTER,
+ SCAN_LEFTCONTROL,SCAN_A,SCAN_S,SCAN_D,SCAN_F,SCAN_G,SCAN_H,SCAN_J,SCAN_K,
+        SCAN_L,SCAN_SEMICOLON,SCAN_APOSTROPHE,SCAN_BRACKET_RIGHT,SCAN_BL_INSERT,
+ SCAN_LEFTSHIFT,SCAN_Z,SCAN_X,SCAN_C,SCAN_V,SCAN_B,SCAN_N,SCAN_M,SCAN_COMMA,
+        SCAN_PERIOD,SCAN_SLASH,SCAN_RIGHTALT,SCAN_RIGHTSHIFT,SCAN_LEFTALT,SCAN_SPACE,
+ SCAN_BL_DELETE,SCAN_BL_END,SCAN_BL_PAGEDOWN,
+ SCAN_BL_CURSORUP,SCAN_BL_CURSORLEFT,SCAN_BL_CURSORRIGHT,SCAN_BL_CURSORDOWN
+};
+
+uint8 fkbkeys[0x48];
+void UpdateFKB(void)
+{
+ int x;
+
+ for(x=0;x<0x48;x++)
+ {
+  fkbkeys[x]=0;
+  if(keys[fkbmap[x]])
+   fkbkeys[x]=1;
+ }
+}
+
+
+
+static int inkeyloop=0;
+
+static BOOL CALLBACK KeyConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+  int x,y;
+  char tempo[64];
+
+  switch(uMsg) {
+   case WM_USER+666:
+                   if(inkeyloop)
+                   {
+                    SetDlgItemInt(hwndDlg,inkeyloop,lParam,0);
+                    inkeyloop=0;
+                   }                   
+                   break;
+   case WM_INITDIALOG:
+                sprintf(tempo,"Virtual Gamepad %d",porttemp+1);
+                SetDlgItemText(hwndDlg,302,tempo);
+                sprintf(tempo,"Virtual Gamepad %d",porttemp+3);
+                SetDlgItemText(hwndDlg,311,tempo);
+
+                for(x=0;x<2;x++)
+                {
+                 for(y=0;y<8;y++)
+                  SetDlgItemInt(hwndDlg,600+y+x*10,keyBMap[porttemp+(x<<1)][y],0);
+                 if(keybEnable&(1<<((x<<1)+porttemp)))
+                  CheckDlgButton(hwndDlg,320+x,BST_CHECKED);
+                }
+                break;
+   case WM_CLOSE:
+   case WM_QUIT: goto gornk;
+   case WM_COMMAND:
+                  if(!(wParam>>16))
+                  {
+                   wParam&=0xFFFF;
+                   if((wParam>=600 && wParam<=607) || (wParam>=610 && wParam<=617))
+                    inkeyloop=wParam;
+                   else switch(wParam)
+                   {                    
+                    case 1:
+                           gornk:
+                           for(x=0;x<2;x++)
+                           {
+                            for(y=0;y<8;y++)
+                             keyBMap[porttemp+(x<<1)][y]=GetDlgItemInt(hwndDlg,600+y+x*10,0,0);
+
+                            if(IsDlgButtonChecked(hwndDlg,320+x)==BST_CHECKED)
+                             keybEnable|=(1<<((x<<1)+porttemp));
+                            else
+                             keybEnable&=~(1<<((x<<1)+porttemp));
+                           }
+
+                           EndDialog(hwndDlg,0);
+                           break;
+                   }  
+                  }
+              }
+  return 0;
+}
+
+static BOOL CALLBACK KeyPPConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+  int x;
+  char tempo[64];
+
+  switch(uMsg) {
+   case WM_USER+666:
+                   if(inkeyloop)
+                   {
+                    SetDlgItemInt(hwndDlg,inkeyloop,lParam,0);
+                    inkeyloop=0;
+                   }                   
+                   break;
+   case WM_INITDIALOG:
+                for(x=0;x<12;x++)
+                 SetDlgItemInt(hwndDlg,500+x,powerpadsc[porttemp][x],0);
+                CheckDlgButton(hwndDlg,300+((powerpadside>>porttemp)&1),BST_CHECKED);
+                sprintf(tempo,"Virtual Power Pad %d",porttemp+1);
+                SetDlgItemText(hwndDlg,302,tempo);
+                break;
+   case WM_CLOSE:
+   case WM_QUIT: goto gornk;
+   case WM_COMMAND:
+                  if(!(wParam>>16))
+                  {                   
+                   wParam&=0xFFFF;
+                   if(wParam>=500 && wParam<=511)
+                    inkeyloop=wParam;
+                   else switch(wParam)
+                   {                    
+                    case 1:
+                           gornk:
+                           for(x=0;x<12;x++)
+                            powerpadsc[porttemp][x]=GetDlgItemInt(hwndDlg,500+x,0,0);
+                           powerpadside&=~(1<<porttemp);
+                           if(IsDlgButtonChecked(hwndDlg,301)==BST_CHECKED)
+                            powerpadside|=1<<porttemp;
+                           EndDialog(hwndDlg,0);
+                           break;
+                   }  
+                  }
+              }
+  return 0;
+}
+
+static BOOL CALLBACK FKBConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+  int x;
+
+  switch(uMsg) {
+   case WM_USER+666:
+                   if(inkeyloop)
+                   {
+                    SetDlgItemInt(hwndDlg,inkeyloop,lParam,0);
+                    fkbmap[inkeyloop-300]=lParam;
+                    inkeyloop=0;
+                   }                   
+                   break;
+   case WM_INITDIALOG:
+                for(x=0;x<72;x++)
+                 SetDlgItemInt(hwndDlg,300+x,fkbmap[x],0);
+                break;
+   case WM_CLOSE:
+   case WM_QUIT: goto gornk;
+   case WM_COMMAND:
+                  if(!(wParam>>16))
+                  {                   
+                   wParam&=0xFFFF;
+                   if(wParam>=300 && wParam<=371)
+                    inkeyloop=wParam;
+                   else switch(wParam)
+                   {                    
+                    case 1:
+                           gornk:
+                           EndDialog(hwndDlg,0);
+                           break;
+                   }  
+                  }
+              }
+  return 0;
+}
+
+static HHOOK hHook;
+static LRESULT CALLBACK FilterFunc(int nCode, WORD wParam, DWORD lParam)
+{
+ MSG FAR *ptrMsg;
+ LPARAM tmpo;
+
+ if(nCode>=0)
+ {
+  if(nCode==MSGF_DIALOGBOX)
+  {
+   ptrMsg=(MSG FAR *)lParam;
+   if(ptrMsg->message==WM_KEYDOWN || ptrMsg->message==WM_SYSKEYDOWN)
+   {
+    tmpo=((ptrMsg->lParam>>16)&0x7F)|((ptrMsg->lParam>>17)&0x80);
+    PostMessage(GetParent(ptrMsg->hwnd),WM_USER+666,0,tmpo);
+    if(inkeyloop) return 1;
+   }
+  }
+ }
+ return CallNextHookEx(hHook,nCode,wParam,lParam);
+}
+
+
+void ConfigKeyboardie(HWND hParent, int port)
+{
+ porttemp=port;
+
+ hHook=SetWindowsHookEx(WH_MSGFILTER,(HOOKPROC)FilterFunc,fceu_hInstance,GetCurrentThreadId());
+ DialogBox(fceu_hInstance,"KEYCONFIG",hParent,KeyConCallB);
+ UnhookWindowsHookEx(hHook);
+}
+
+void ConfigKeyboardiePowerpad(HWND hParent, int port)
+{
+ porttemp=port;
+
+ hHook=SetWindowsHookEx(WH_MSGFILTER,(HOOKPROC)FilterFunc,fceu_hInstance,GetCurrentThreadId());
+ DialogBox(fceu_hInstance,"KEYPPCONFIG",hParent,KeyPPConCallB);
+ UnhookWindowsHookEx(hHook);
+}
+
+void ConfigFKB(HWND hParent)
+{
+ hHook=SetWindowsHookEx(WH_MSGFILTER,(HOOKPROC)FilterFunc,fceu_hInstance,GetCurrentThreadId());
+ DialogBox(fceu_hInstance,"FKBCONFIG",hParent,FKBConCallB);
+ UnhookWindowsHookEx(hHook);
+}
diff --git a/drivers/win/keyboard.h b/drivers/win/keyboard.h
new file mode 100644 (file)
index 0000000..f118fc6
--- /dev/null
@@ -0,0 +1,22 @@
+void KeyboardClose(void);\r
+int KeyboardInitialize(void);\r
+void KeyboardUpdate(void);\r
+uint32 KeyboardDodo(void);\r
+uint32 UpdatePPadData(int w);\r
+void UpdateFKB(void);\r
+\r
+\r
+void ConfigFKB(HWND hParent);\r
+void ConfigKeyboardie(HWND hParent, int port);\r
+void ConfigKeyboardiePowerpad(HWND hParent, int port);\r
+\r
+extern int cidisabled;\r
+\r
+/* Config stuff: */\r
+extern int keyBMap[4][8];\r
+extern int keybEnable;\r
+extern int powerpadside;\r
+extern int powerpadsc[2][12];\r
+\r
+extern int fkbmap[0x48];\r
+extern uint8 fkbkeys[0x48];\r
diff --git a/drivers/win/keyscan.h b/drivers/win/keyscan.h
new file mode 100644 (file)
index 0000000..689d780
--- /dev/null
@@ -0,0 +1,125 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#define SCAN_GRAVE     0x29
+#define SCAN_1         0x02
+#define SCAN_2         0x03
+#define SCAN_3         0x04
+#define SCAN_4          0x05
+#define SCAN_5          0x06
+#define SCAN_6          0x07
+#define SCAN_7          0x08
+#define SCAN_8          0x09
+#define SCAN_9          0x0A
+#define SCAN_0          0x0B
+#define SCAN_MINUS     0x0C
+#define SCAN_EQUAL     0x0D
+#define SCAN_BACKSLASH 0x2B
+#define SCAN_BACKSPACE 0x0E
+#define SCAN_TAB       0x0F
+#define SCAN_Q         0x10
+#define SCAN_W         0x11
+#define SCAN_E         0x12
+#define SCAN_R         0x13
+#define SCAN_T         0x14
+#define SCAN_Y         0x15
+#define SCAN_U         0x16
+#define SCAN_I         0x17
+#define SCAN_O         0x18
+#define SCAN_P         0x19
+#define SCAN_BRACKET_LEFT      0x1A
+#define SCAN_BRACKET_RIGHT     0x1B
+#define SCAN_LOWBACKSLASH      0x2B
+#define SCAN_CAPSLOCK  0x3A
+#define SCAN_A         0x1E
+#define SCAN_S         0x1F
+#define SCAN_D          0x20
+#define SCAN_F          0x21
+#define SCAN_G          0x22
+#define SCAN_H          0x23
+#define SCAN_J          0x24
+#define SCAN_K          0x25
+#define SCAN_L          0x26
+#define SCAN_SEMICOLON 0x27
+#define SCAN_APOSTROPHE        0x28
+#define SCAN_ENTER     0x1C
+#define SCAN_LEFTSHIFT 0x2A
+#define SCAN_Z         0x2C
+#define SCAN_X         0x2D
+#define SCAN_C          0x2E
+#define SCAN_V          0x2F
+#define SCAN_B          0x30
+#define SCAN_N          0x31
+#define SCAN_M          0x32
+#define SCAN_COMMA      0x33
+#define SCAN_PERIOD    0x34
+#define SCAN_SLASH     0x35
+#define SCAN_RIGHTSHIFT        0x36
+#define SCAN_LEFTCONTROL       0x1D
+#define SCAN_LEFTALT           0x38
+#define SCAN_SPACE             0x39
+
+#define SCAN_RIGHTALT          (0x38|0x80)
+#define SCAN_RIGHTCONTROL      (0x1D|0x80)
+#define SCAN_BL_INSERT         (0x52|0x80)
+#define SCAN_BL_DELETE         (0x53|0x80)
+#define SCAN_BL_CURSORLEFT     (0x4B|0x80)
+#define SCAN_BL_HOME           (0x47|0x80)
+#define SCAN_BL_END            (0x4F|0x80)
+#define SCAN_BL_CURSORUP       (0x48|0x80)
+#define SCAN_BL_CURSORDOWN     (0x50|0x80)
+#define SCAN_BL_PAGEUP         (0x49|0x80)
+#define SCAN_BL_PAGEDOWN       (0x51|0x80)
+#define SCAN_BL_CURSORRIGHT    (0x4D|0x80)
+
+#define SCAN_SCROLLLOCK         0x46
+/* Keys in the key pad area. */
+#define SCAN_NUMLOCK           0x45
+#define SCAN_HOME              0x47
+#define SCAN_CURSORLEFT                0x4B
+#define SCAN_END               0x4F
+#define SCAN_SLASH             0x35
+#define SCAN_CURSORUP          0x48
+#define SCAN_CENTER            0x4C
+#define SCAN_CURSORDOWN                0x50
+#define SCAN_INSERT            0x52
+#define SCAN_ASTERISK          0x37
+#define SCAN_PAGEUP            0x49
+#define SCAN_CURSORRIGHT       0x4D
+#define SCAN_PAGEDOWN           0x51
+#define SCAN_KP_DELETE          0x53
+#define SCAN_KP_MINUS           0x4A
+#define SCAN_KP_PLUS            0x4E
+#define SCAN_KP_ENTER           0x1C
+
+#define SCAN_ESCAPE            0x01
+#define SCAN_F1                        0x3B
+#define SCAN_F2                        0x3C
+#define SCAN_F3                 0x3D
+#define SCAN_F4                 0x3E
+#define SCAN_F5                 0x3F
+#define SCAN_F6                 0x40
+#define SCAN_F7                 0x41
+#define SCAN_F8                 0x42
+#define SCAN_F9                 0x43
+#define SCAN_F10                0x44
+#define SCAN_F11                0x57
+#define SCAN_F12                0x58
diff --git a/drivers/win/main.c b/drivers/win/main.c
new file mode 100644 (file)
index 0000000..2faf4eb
--- /dev/null
@@ -0,0 +1,338 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+
+#include "common.h"
+
+#include <winsock.h>
+#include <mmsystem.h>
+#include <ddraw.h>
+#include <dsound.h>
+#include <dinput.h>
+#include <dir.h>
+#include <commctrl.h>
+#include <shlobj.h>     // For directories configuration dialog.
+
+#include "input.h"
+#include "joystick.h"
+#include "keyboard.h"
+#include "cheat.h"
+
+
+#define EO_BGRUN          1
+
+#define EO_CPALETTE       4
+#define EO_NOSPRLIM       8
+#define EO_BSAV          16
+#define EO_FSAFTERLOAD   32
+#define EO_FOAFTERSTART  64
+#define EO_NOTHROTTLE   128
+#define EO_CLIPSIDES    256
+#define EO_SNAPNAME    512
+
+/* EO_USERFORCE is something I've been playing with.
+   The code for it isn't finished.
+*/
+#define EO_USERFORCE   1024
+
+
+#define VNSCLIP  ((eoptions&EO_CLIPSIDES)?8:0)
+#define VNSWID   ((eoptions&EO_CLIPSIDES)?240:256)
+
+static int eoptions=EO_BGRUN;
+
+void ResetVideo(void);
+void ShowCursorAbs(int w);
+void HideFWindow(int h);
+int SetMainWindowStuff(void);
+int GetClientAbsRect(LPRECT lpRect);
+void UpdateFCEUWindow(void);
+
+
+HWND hAppWnd=0;
+HINSTANCE fceu_hInstance;
+
+HRESULT  ddrval;
+
+FCEUGI *GI=0;
+
+// cheats, misc, nonvol, states, snaps, base
+static char *DOvers[6]={0,0,0,0,0,0};
+static char *defaultds[5]={"cheats","gameinfo","sav","fcs","snaps"};
+
+static char TempArray[2048];
+static char BaseDirectory[2048];
+
+void SetDirs(void)
+{
+ int x;
+ static int jlist[5]=
+  {FCEUIOD_CHEATS,FCEUIOD_MISC,FCEUIOD_NV,FCEUIOD_STATE,FCEUIOD_SNAPS};
+
+ for(x=0;x<5;x++)
+  FCEUI_SetDirOverride(jlist[x], DOvers[x]);  
+ if(DOvers[5])
+  FCEUI_SetBaseDirectory(DOvers[5]);
+ else
+  FCEUI_SetBaseDirectory(BaseDirectory);
+ FCEUI_SaveExtraDataUnderBase(eoptions&EO_BSAV);
+}
+/* Remove empty, unused directories. */
+void RemoveDirs(void)
+{
+ int x;
+
+ for(x=0;x<5;x++)
+  if(!DOvers[x])
+  {
+   sprintf(TempArray,"%s\\%s",DOvers[5]?DOvers[5]:BaseDirectory,defaultds[x]);
+   RemoveDirectory(TempArray);
+  }
+}
+
+void CreateDirs(void)
+{
+ int x;
+
+ for(x=0;x<5;x++)
+  if(!DOvers[x])
+  {
+   sprintf(TempArray,"%s\\%s",DOvers[5]?DOvers[5]:BaseDirectory,defaultds[x]);
+   CreateDirectory(TempArray,0);
+  }
+}
+
+static char *gfsdir=0;
+void GetBaseDirectory(void)
+{
+ int x;
+ BaseDirectory[0]=0;
+ GetModuleFileName(0,(LPTSTR)BaseDirectory,2047);
+
+ for(x=strlen(BaseDirectory);x>=0;x--)
+ {
+  if(BaseDirectory[x]=='\\' || BaseDirectory[x]=='/')
+   {BaseDirectory[x]=0;break;}
+ }
+}
+
+static int exiting=0;
+int BlockingCheck(void)
+{
+  MSG msg;
+
+  while( PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE ) ) {
+     if( GetMessage( &msg, 0,  0, 0)>0 )
+     {
+     TranslateMessage(&msg);
+     DispatchMessage(&msg);
+     }
+   }
+
+ if(exiting) return(0);
+
+ return(1);
+}
+
+int NoWaiting=0;
+static int fullscreen=0;
+static int soundflush=0;
+static int soundsleep=0;
+static int genie=0;
+static int palyo=0;
+static int windowedfailed;
+static int winsizemul=1;
+static int winwidth,winheight;
+
+static volatile int nofocus=0;
+static volatile int userpause=0;
+
+#define SO_FORCE8BIT  1
+#define SO_SECONDARY  2
+#define SO_GFOCUS     4
+#define SO_D16VOL     8
+
+static int soundrate=44100;
+static int soundbuftime=46;
+static int soundbufsize;
+static int soundoptions=0;
+static int soundvolume=100;
+
+static unsigned int srendline,erendline;
+static unsigned int srendlinen=8;
+static unsigned int erendlinen=239;
+static unsigned int srendlinep=0;
+static unsigned int erendlinep=239;
+
+
+static unsigned int totallines;
+
+static void FixFL(void)
+{
+ FCEUI_GetCurrentVidSystem(&srendline,&erendline);
+ totallines=erendline-srendline+1;
+}
+
+static void UpdateRendBounds(void)
+{ 
+ FCEUI_SetRenderedLines(srendlinen,erendlinen,srendlinep,erendlinep);
+ FixFL(); 
+}
+
+static uint8 cpalette[192];
+static int vmod=1;
+static int soundo=1;
+static int ntsccol=0,ntsctint,ntschue;
+
+void FCEUD_PrintError(char *s)
+{
+ if(fullscreen) ShowCursorAbs(1);
+ MessageBox(0,s,"FCE Ultra Error",MB_ICONERROR|MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
+ if(fullscreen)ShowCursorAbs(0);
+}
+
+void ShowAboutBox(void)
+{
+ sprintf(TempArray,"FCE Ultra "VERSION_STRING"\n\nhttp://fceultra.sourceforge.net\n\n"__TIME__"\n"__DATE__"\n""gcc "__VERSION__);
+ MessageBox(hAppWnd,TempArray,"About FCE Ultra",MB_OK);
+}
+
+void DoFCEUExit(void)
+{
+ exiting=1;
+ if(GI)
+ {
+  FCEUI_CloseGame();
+  GI=0;
+ }
+}
+
+static int changerecursive=0;
+
+#include "throttle.c"
+
+#include "netplay.c"
+#include "sound.c"
+#include "video.c"
+#include "window.c"
+#include "config.c"
+
+
+int DriverInitialize(void)
+{
+  if(!InitializeDDraw())
+   return(0);
+
+  if(soundo)
+   soundo=InitSound();
+
+  SetVideoMode(fullscreen);
+  InitInputStuff();             /* Initialize DInput interfaces. */
+  CreateInputStuff();           /* Create and set virtual NES/FC devices. */
+  return 1;
+}
+
+static void DriverKill(void)
+{ 
+ sprintf(TempArray,"%s/fceu.cfg",BaseDirectory);
+ SaveConfig(TempArray);
+ DestroyInput();
+ ResetVideo();
+ if(soundo) TrashSound();
+ CloseWave();
+ ByebyeWindow();
+}
+
+
+int main(int argc,char *argv[])
+{
+  char *t;
+
+  if(!FCEUI_Initialize())
+   goto doexito;
+
+  fceu_hInstance=GetModuleHandle(0);
+
+  GetBaseDirectory();
+
+  sprintf(TempArray,"%s\\fceu.cfg",BaseDirectory);
+  LoadConfig(TempArray);
+  FixGIGO();      /* Since a game doesn't have to be
+                     loaded before the GUI can be used, make
+                     sure the temporary input type variables
+                     are set.
+                  */
+
+
+  CreateDirs();
+  SetDirs();
+
+  DoVideoConfigFix();
+  DoMiscConfigFix();
+
+  if(eoptions&EO_CPALETTE)
+   FCEUI_SetPaletteArray(cpalette);
+
+  t=0;
+  if(argc>1)
+   t=argv[1];
+  if(!t) fullscreen=0;
+
+  CreateMainWindow();
+
+  if(!InitDInput())
+   goto doexito;
+
+  if(!DriverInitialize())
+   goto doexito;
+  InitSpeedThrottle();
+  UpdateMenu();
+
+  if(t)
+   ALoad(t);
+  else if(eoptions&EO_FOAFTERSTART)
+   LoadNewGamey(hAppWnd);
+
+  doloopy:
+  UpdateFCEUWindow();
+  if(GI)
+  {
+   FCEUI_Emulate();
+   RedrawWindow(hAppWnd,0,0,RDW_ERASE|RDW_INVALIDATE);
+   StopSound();
+  }
+  Sleep(50);
+  if(!exiting)
+   goto doloopy;
+
+  doexito:
+  DriverKill();
+  return(0);
+}
+
+void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count)
+{
+ FCEUD_BlitScreen(XBuf);
+ if(Count)
+  FCEUD_WriteSoundData(Buffer,Count);
+ FCEUD_UpdateInput();
+}
+
diff --git a/drivers/win/netplay.c b/drivers/win/netplay.c
new file mode 100644 (file)
index 0000000..6c7ac45
--- /dev/null
@@ -0,0 +1,415 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 2002 Ben Parnell\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+static char netplayhost[256]={0};\r
+static int netplayport=0xFCE;\r
+\r
+static int netplayon=0;\r
+static int netplaytype=0;\r
+\r
+static HWND hwndns=0;\r
+\r
+static SOCKET Socket=INVALID_SOCKET;\r
+static int wsainit=0;\r
+\r
+static volatile int abortnetplay=0;\r
+static volatile int concommand=0;\r
+\r
+static void WSE(char *ahh)\r
+{\r
+ char tmp[256];\r
+ sprintf(tmp,"Winsock: %s",ahh);\r
+ FCEUD_PrintError(tmp);\r
+}\r
+\r
+int SetBlockingSock(SOCKET Socko)\r
+{\r
+   unsigned long t;\r
+   t=1;\r
+   if(ioctlsocket(Socko,FIONBIO,&t))\r
+   {\r
+    WSE("Error setting socket to non-blocking mode!\n");\r
+    return 0;\r
+   }\r
+  return 1;\r
+}\r
+\r
+BOOL CALLBACK BoogaDooga(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+  switch(uMsg) {\r
+   case WM_USER+1:\r
+                if(WSAGETASYNCERROR(lParam))\r
+                 concommand=1;\r
+                else\r
+                 concommand=2;\r
+                break;\r
+   case WM_USER:\r
+                if(WSAGETSELECTEVENT(lParam)==FD_CONNECT)\r
+                 {\r
+                  if(WSAGETSELECTERROR(lParam))\r
+                   concommand=1;\r
+                  else\r
+                   concommand=2;\r
+                 }                \r
+                break;\r
+   case WM_INITDIALOG:\r
+                if(!netplaytype) SetDlgItemText(hwndDlg,100,(LPTSTR)"Waiting for a connection...");\r
+                else SetDlgItemText(hwndDlg,100,(LPTSTR)"Attempting to establish a connection...");                                 \r
+                break;\r
+   case WM_CLOSE:\r
+   case WM_QUIT: goto gornk;\r
+   case WM_COMMAND:\r
+                if(!(wParam>>16))\r
+                switch(wParam&0xFFFF)\r
+                {\r
+                  case 1:\r
+                        gornk:\r
+                        abortnetplay=1;\r
+                        EndDialog(hwndDlg,0);\r
+                        break;\r
+               }\r
+              }\r
+  return 0;\r
+\r
+}\r
+\r
+static void CloseNSDialog(void)\r
+{\r
+ if(hwndns)\r
+  {\r
+   SendMessage(hwndns,WM_COMMAND,1,0);\r
+   hwndns=0;\r
+  }\r
+}\r
+\r
+void CreateStatusDialog(void)\r
+{\r
+ hwndns=CreateDialog(fceu_hInstance,"NETSTAT",hAppWnd,BoogaDooga);\r
+}\r
+\r
+void FCEUD_NetworkClose(void)\r
+{\r
+ CloseNSDialog();\r
+ if(Socket!=INVALID_SOCKET)\r
+ {\r
+  closesocket(Socket);\r
+  Socket=INVALID_SOCKET;\r
+ }\r
+ if(wsainit)\r
+ {\r
+  WSACleanup();\r
+  wsainit=0;\r
+ }\r
+ /* Make sure blocking is returned to normal once network play is stopped. */\r
+ NoWaiting&=~2;\r
+}\r
+\r
+int FCEUD_NetworkConnect(void)\r
+{\r
+ WSADATA WSAData;\r
+ SOCKADDR_IN sockin;    /* I want to play with fighting robots. */\r
+ SOCKET TSocket;\r
+\r
+ if(WSAStartup(MAKEWORD(1,1),&WSAData))\r
+ {\r
+  FCEUD_PrintError("Error initializing Windows Sockets.");\r
+  return(0);\r
+ }\r
+ wsainit=1;\r
+ concommand=abortnetplay=0;\r
+\r
+ if( (TSocket=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)\r
+ {\r
+  WSE("Error creating socket.");\r
+  FCEUD_NetworkClose();\r
+  return(0);\r
+ }\r
+\r
+ memset(&sockin,0,sizeof(sockin));\r
+ sockin.sin_family=AF_INET;\r
+ sockin.sin_port=htons(netplayport);\r
+\r
+ if(!netplaytype)       /* Act as a server. */\r
+ {\r
+\r
+  int sockin_len;\r
+  sockin.sin_addr.s_addr=INADDR_ANY;\r
+\r
+  sockin_len=sizeof(sockin);\r
+\r
+  if(bind(TSocket,(struct sockaddr *)&sockin,sizeof(sockin))==SOCKET_ERROR)\r
+  {\r
+   WSE("Error binding to socket.");\r
+   closesocket(TSocket);\r
+   FCEUD_NetworkClose();\r
+   return(0);\r
+  }\r
+\r
+  if(listen(TSocket,1)==SOCKET_ERROR)\r
+  {\r
+   WSE("Error listening on socket.");\r
+   closesocket(TSocket);\r
+   FCEUD_NetworkClose();\r
+   return(0);\r
+  }\r
+\r
+  CreateStatusDialog();\r
+  if(!SetBlockingSock(TSocket))\r
+  {\r
+   closesocket(TSocket);\r
+   FCEUD_NetworkClose();\r
+   return(0);\r
+  }\r
+\r
+  while( (Socket=accept(TSocket,(struct sockaddr *) &sockin,(int *)&sockin_len)) ==\r
+                INVALID_SOCKET)\r
+  {\r
+   if(abortnetplay || WSAGetLastError()!=WSAEWOULDBLOCK)\r
+   {\r
+    if(!abortnetplay)\r
+     WSE("Error accepting connection.");\r
+    closesocket(TSocket);\r
+    FCEUD_NetworkClose();\r
+    return(0);\r
+   }\r
+   else\r
+    BlockingCheck();\r
+  }\r
+\r
+  if(!SetBlockingSock(Socket))\r
+  {\r
+   FCEUD_NetworkClose();\r
+   return(0);\r
+  }\r
+\r
+ }    \r
+ else   /* We're a client... */\r
+ {\r
+  char phostentb[MAXGETHOSTSTRUCT];\r
+  unsigned long hadr;\r
+\r
+  hadr=inet_addr(netplayhost);\r
+\r
+  CreateStatusDialog();\r
+\r
+  if(hadr!=INADDR_NONE)\r
+   sockin.sin_addr.s_addr=hadr;\r
+  else\r
+  {\r
+   if(!WSAAsyncGetHostByName(hwndns,WM_USER+1,(const char *)netplayhost,phostentb,MAXGETHOSTSTRUCT))\r
+   {\r
+    ghosterr:\r
+    WSE("Error getting host network information.");\r
+    closesocket(TSocket);\r
+    FCEUD_NetworkClose();\r
+    return(0);\r
+   }\r
+   while(concommand!=2)\r
+   {\r
+    BlockingCheck();\r
+    if(concommand==1 || abortnetplay)\r
+     goto ghosterr;\r
+   }\r
+   memcpy((char *)&sockin.sin_addr,((PHOSTENT)phostentb)->h_addr,((PHOSTENT)phostentb)->h_length);\r
+  }\r
+  concommand=0;\r
+\r
+  if(WSAAsyncSelect(TSocket,hwndns,WM_USER,FD_CONNECT|FD_CLOSE)==SOCKET_ERROR)\r
+  {\r
+   eventnoterr:\r
+   WSE("Error setting event notification on socket.");\r
+   closesocket(TSocket);\r
+   FCEUD_NetworkClose();\r
+   return(0);\r
+  }\r
+\r
+  if(!SetBlockingSock(TSocket))\r
+  {\r
+   closesocket(TSocket);\r
+   FCEUD_NetworkClose();\r
+   return(0);\r
+  }\r
+\r
+  if(connect(TSocket,(PSOCKADDR)&sockin,sizeof(sockin))==SOCKET_ERROR)\r
+  {\r
+   if(WSAGetLastError()!=WSAEWOULDBLOCK)\r
+   {\r
+    cerrav:\r
+    WSE("Error connecting to remote host.");\r
+\r
+    cerra:\r
+    closesocket(TSocket);\r
+    FCEUD_NetworkClose();\r
+    return(0);\r
+   }\r
+\r
+   while(concommand!=2)\r
+   {\r
+    BlockingCheck();        \r
+    if(abortnetplay) goto cerra;\r
+    if(concommand==1) goto cerrav;\r
+   }\r
+  }\r
+  if(WSAAsyncSelect(TSocket,hAppWnd,WM_USER,0)==SOCKET_ERROR)\r
+   goto eventnoterr;\r
+  Socket=TSocket;\r
+\r
+ }\r
+ CloseNSDialog();\r
+ return(1);\r
+}\r
+\r
+\r
+int FCEUD_NetworkSendData(uint8 *data, uint32 len)\r
+{\r
+        int erc;\r
+\r
+        while((erc=send(Socket,data,len,0)))\r
+        {\r
+         if(erc!=SOCKET_ERROR)\r
+         {\r
+          len-=erc;\r
+          data+=erc;\r
+          if(!len)\r
+           return(1);   /* All data sent. */\r
+\r
+          if(!BlockingCheck()) return(0);\r
+         }\r
+         else\r
+         {\r
+          if(WSAGetLastError()==WSAEWOULDBLOCK)\r
+          {\r
+           if(!BlockingCheck()) return(0);\r
+           continue;\r
+          }\r
+          return(0);\r
+         }\r
+        }\r
+        return(0);\r
+}\r
+\r
+int FCEUD_NetworkRecvData(uint8 *data, uint32 len, int block)\r
+{\r
+ int erc;\r
+\r
+ if(block)      // TODO: Add code elsewhere to handle sound buffer underruns.\r
+ {\r
+  while((erc=recv(Socket,data,len,0))!=len)\r
+  {         \r
+         if(!erc)\r
+          return(0);\r
+         if(WSAGetLastError()==WSAEWOULDBLOCK)\r
+         {\r
+          if(!BlockingCheck()) return(0);\r
+          continue;\r
+         }\r
+         return(0);\r
+  }\r
+\r
+  {\r
+   char buf[24];\r
+   if(recv(Socket,buf,24,MSG_PEEK)==SOCKET_ERROR)\r
+   {\r
+    if(WSAGetLastError()==WSAEWOULDBLOCK)\r
+     NoWaiting&=~2;\r
+    else\r
+     return(0);\r
+   }\r
+   else\r
+    NoWaiting|=2;       /* We're the client and we're lagging behind.\r
+                           disable blocking(particularly sound...) to *try*\r
+                           to catch up.\r
+                        */                          \r
+  }\r
+\r
+  return 1;\r
+ }\r
+\r
+ else   /* We're the server.  See if there's any new data\r
+           from player 2.  If not, then return(-1).\r
+        */\r
+ {\r
+  erc=recv(Socket,data,len,0);\r
+  if(!erc)\r
+   return(0);\r
+  if(erc==SOCKET_ERROR)\r
+  {\r
+   if(WSAGetLastError()==WSAEWOULDBLOCK)\r
+    return(-1);\r
+   return(0);  // Some other(bad) error occurred.\r
+  }\r
+  return(1);\r
+ } // end else to if(block)\r
+}\r
+\r
+BOOL CALLBACK NetConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+  switch(uMsg) {\r
+   case WM_INITDIALOG:                \r
+\r
+                CheckDlgButton(hwndDlg,100,netplayon?BST_CHECKED:BST_UNCHECKED);\r
+                CheckRadioButton(hwndDlg,101,102,101+netplaytype);\r
+                SetDlgItemInt(hwndDlg,107,netplayport,0);\r
+\r
+                if(netplayhost[0])\r
+                 SetDlgItemText(hwndDlg,104,netplayhost);\r
+                break;\r
+   case WM_CLOSE:\r
+   case WM_QUIT: goto gornk;\r
+   case WM_COMMAND:\r
+                if(!(wParam>>16))\r
+                switch(wParam&0xFFFF)\r
+                {\r
+                 case 1:\r
+                        gornk:\r
+\r
+                        netplayport=GetDlgItemInt(hwndDlg,107,0,0);\r
+\r
+                        if(IsDlgButtonChecked(hwndDlg,100)==BST_CHECKED)\r
+                         netplayon=1;\r
+                        else\r
+                         netplayon=0;\r
+\r
+                        if(IsDlgButtonChecked(hwndDlg,101)==BST_CHECKED)\r
+                         netplaytype=0;\r
+                        else\r
+                         netplaytype=1;\r
+\r
+                        GetDlgItemText(hwndDlg,104,netplayhost,255);\r
+                        netplayhost[255]=0;\r
+\r
+                        EndDialog(hwndDlg,0);\r
+                        break;\r
+               }\r
+              }\r
+  return 0;\r
+}\r
+\r
+\r
+static void ConfigNetplay(void)\r
+{\r
+ DialogBox(fceu_hInstance,"NETPLAYCONFIG",hAppWnd,NetConCallB);\r
+\r
+ if(netplayon)\r
+  FCEUI_SetNetworkPlay(netplaytype+1);\r
+ else\r
+  FCEUI_SetNetworkPlay(0);\r
+}\r
+\r
diff --git a/drivers/win/res.res b/drivers/win/res.res
new file mode 100644 (file)
index 0000000..e7e533d
Binary files /dev/null and b/drivers/win/res.res differ
diff --git a/drivers/win/sound.c b/drivers/win/sound.c
new file mode 100644 (file)
index 0000000..d9c29c5
--- /dev/null
@@ -0,0 +1,457 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 2002 Ben Parnell\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+FILE *soundlog=0;\r
+void WriteWaveData(int32 *Buffer, int Count);\r
+DWORD WINAPI DSThread(LPVOID lpParam);\r
+LPDIRECTSOUND ppDS=0;\r
+LPDIRECTSOUNDBUFFER ppbuf=0;\r
+LPDIRECTSOUNDBUFFER ppbufsec=0;\r
+LPDIRECTSOUNDBUFFER ppbufw;\r
+\r
+DSBUFFERDESC DSBufferDesc;\r
+WAVEFORMATEX wfa;\r
+WAVEFORMATEX wf;\r
+\r
+static int DSBufferSize=0;\r
+static int bittage;\r
+\r
+void TrashSound(void)\r
+{\r
+ FCEUI_Sound(0);\r
+ if(ppbufsec)\r
+ {\r
+  IDirectSoundBuffer_Stop(ppbufsec);\r
+  IDirectSoundBuffer_Release(ppbufsec);\r
+  ppbufsec=0;\r
+ }\r
+ if(ppbuf)\r
+ {\r
+  IDirectSoundBuffer_Stop(ppbuf);\r
+  IDirectSoundBuffer_Release(ppbuf);\r
+  ppbuf=0;\r
+ }\r
+ if(ppDS)\r
+ {\r
+  IDirectSound_Release(ppDS);\r
+  ppDS=0;\r
+ }\r
+}\r
+\r
+\r
+ static VOID *feegle[2];\r
+ static DWORD dook[2];\r
+ static DWORD writepos=0,playpos=0,lplaypos=0;\r
+void CheckDStatus(void)\r
+{\r
+  DWORD status;\r
+  status=0;\r
+  IDirectSoundBuffer_GetStatus(ppbufw, &status);\r
+\r
+  if(status&DSBSTATUS_BUFFERLOST)\r
+  {\r
+   IDirectSoundBuffer_Restore(ppbufw);\r
+  }\r
+\r
+  if(!(status&DSBSTATUS_PLAYING))\r
+  {\r
+   lplaypos=0;\r
+   writepos=((soundbufsize)<<bittage);\r
+   IDirectSoundBuffer_SetFormat(ppbufw,&wf);\r
+   IDirectSoundBuffer_Play(ppbufw,0,0,DSBPLAY_LOOPING);\r
+  }\r
+}\r
+\r
+static int16 MBuffer[2048];\r
+void FCEUD_WriteSoundData(int32 *Buffer, int Count)\r
+{\r
+ int P;\r
+ int k=0;\r
+\r
+ if(soundlog)\r
+  WriteWaveData(Buffer, Count);\r
+\r
+ if(!bittage)\r
+ {\r
+  for(P=0;P<Count;P++)\r
+   *(((uint8*)MBuffer)+P)=((int8)(Buffer[P]>>8))^128;\r
+ }\r
+ else\r
+ {\r
+  for(P=0;P<Count;P++)\r
+   MBuffer[P]=Buffer[P];\r
+ }\r
+  ilicpo:\r
+  CheckDStatus();\r
+  IDirectSoundBuffer_GetCurrentPosition(ppbufw,&playpos,0);\r
+\r
+  if(writepos>=DSBufferSize) \r
+   if(playpos<lplaypos)\r
+    writepos-=DSBufferSize;\r
+  lplaypos=playpos;\r
+\r
+  /* If the write position is beyond the fill buffer, block. */\r
+  if(writepos>=(playpos+(soundbufsize<<bittage)))\r
+  //if(!(writepos<playpos+((soundbufsize)<<bittage)))\r
+  {\r
+   if(!NoWaiting)\r
+   {\r
+    if(soundsleep==1)\r
+    {\r
+     if(!k)\r
+     {\r
+      int stime;      \r
+\r
+      stime=writepos-(playpos+(soundbufsize<<bittage));\r
+      stime*=1000;\r
+      stime/=soundrate;\r
+      stime>>=1;\r
+      if(stime>=5)\r
+       Sleep(stime);\r
+      k=1;\r
+     }     \r
+    }\r
+    else if(soundsleep==2)\r
+    {\r
+     int stime;      \r
+     stime=writepos-(playpos+(soundbufsize<<bittage));\r
+     stime*=1000;\r
+     stime/=soundrate;\r
+     stime>>=1;\r
+     if(stime>=2)\r
+      Sleep(stime);\r
+    }\r
+   }\r
+   BlockingCheck();\r
+   if(!soundo || NoWaiting) return;\r
+   goto ilicpo;\r
+  }\r
+\r
+  if(netplaytype && netplayon)\r
+  {\r
+   if(writepos<=playpos+128)\r
+   writepos=playpos+(soundbufsize<<bittage);\r
+  }\r
+\r
+  {\r
+   feegle[0]=feegle[1]=0;\r
+   dook[0]=dook[1]=0;\r
+\r
+   \r
+   ddrval=IDirectSoundBuffer_Lock(ppbufw,(writepos%DSBufferSize),Count<<bittage,&feegle[0],&dook[0],&feegle[1],&dook[1],0);\r
+   if(ddrval!=DS_OK)\r
+    goto nolock;\r
+\r
+   if(feegle[1]!=0 && feegle[1]!=feegle[0])\r
+   {\r
+    if(soundflush)\r
+    {\r
+     memset(feegle[0],0x80,dook[0]);\r
+     memset(feegle[1],0x80,dook[1]);\r
+    }\r
+    else\r
+    {\r
+     memcpy(feegle[0],(uint8 *)MBuffer,dook[0]);\r
+     memcpy(feegle[1],((uint8 *)MBuffer)+dook[0],dook[1]);\r
+    }\r
+   }\r
+   else\r
+   {\r
+    if(soundflush)\r
+     memset(feegle[0],0x80,dook[0]);\r
+    else\r
+     memcpy(feegle[0],(uint8 *)MBuffer,dook[0]);\r
+   }\r
+\r
+   IDirectSoundBuffer_Unlock(ppbufw,feegle[0],dook[0],feegle[1],dook[1]);\r
+   writepos+=Count<<bittage;\r
+  }\r
+ nolock:\r
+ ///////// Ending\r
+}\r
+\r
+int InitSound()\r
+{\r
+ DSCAPS dscaps;\r
+ DSBCAPS dsbcaps;\r
+\r
+ memset(&wf,0x00,sizeof(wf));\r
+ wf.wFormatTag = WAVE_FORMAT_PCM;\r
+ wf.nChannels = 1;\r
+ wf.nSamplesPerSec = soundrate;\r
+\r
+ ddrval=DirectSoundCreate(0,&ppDS,0);\r
+ if (ddrval != DS_OK)\r
+ {\r
+  FCEUD_PrintError("DirectSound: Error creating DirectSound object.");\r
+  return 0;\r
+ }\r
+\r
+ if(soundoptions&SO_SECONDARY)\r
+ {\r
+  trysecondary:\r
+  ddrval=IDirectSound_SetCooperativeLevel(ppDS,hAppWnd,DSSCL_PRIORITY);\r
+  if (ddrval != DS_OK)\r
+  {\r
+   FCEUD_PrintError("DirectSound: Error setting cooperative level to DDSCL_PRIORITY.");\r
+   TrashSound();\r
+   return 0;\r
+  }\r
+ }\r
+ else\r
+ {\r
+  ddrval=IDirectSound_SetCooperativeLevel(ppDS,hAppWnd,DSSCL_WRITEPRIMARY);\r
+  if (ddrval != DS_OK)\r
+  {\r
+   FCEUD_PrintError("DirectSound: Error setting cooperative level to DDSCL_WRITEPRIMARY.  Forcing use of secondary sound buffer and trying again...");\r
+   soundoptions|=SO_SECONDARY;\r
+   goto trysecondary;\r
+  }\r
+ }\r
+ memset(&dscaps,0x00,sizeof(dscaps));\r
+ dscaps.dwSize=sizeof(dscaps);\r
+ ddrval=IDirectSound_GetCaps(ppDS,&dscaps);\r
+ if(ddrval!=DS_OK)\r
+ {\r
+  FCEUD_PrintError("DirectSound: Error getting capabilities.");\r
+  return 0;\r
+ }\r
+\r
+ if(dscaps.dwFlags&DSCAPS_EMULDRIVER)\r
+  FCEUD_PrintError("DirectSound: Sound device is being emulated through waveform-audio functions.  Sound quality will most likely be awful.  Try to update your sound device's sound drivers.");\r
+\r
+ IDirectSound_Compact(ppDS);\r
+\r
+ memset(&DSBufferDesc,0x00,sizeof(DSBUFFERDESC));\r
+ DSBufferDesc.dwSize=sizeof(DSBufferDesc);\r
+ if(soundoptions&SO_SECONDARY)\r
+  DSBufferDesc.dwFlags=DSBCAPS_PRIMARYBUFFER;\r
+ else\r
+  DSBufferDesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_GETCURRENTPOSITION2;\r
+\r
+ ddrval=IDirectSound_CreateSoundBuffer(ppDS,&DSBufferDesc,&ppbuf,0);\r
+ if (ddrval != DS_OK)\r
+ {\r
+  FCEUD_PrintError("DirectSound: Error creating primary buffer.");\r
+  TrashSound();\r
+  return 0;\r
+ } \r
+\r
+ memset(&wfa,0x00,sizeof(wfa));\r
+\r
+ if(soundoptions&SO_FORCE8BIT)\r
+  bittage=0;\r
+ else\r
+ {\r
+  bittage=1;\r
+  if( (!(dscaps.dwFlags&DSCAPS_PRIMARY16BIT)) ||\r
+      (!(dscaps.dwFlags&DSCAPS_SECONDARY16BIT) && (soundoptions&SO_SECONDARY)))\r
+  {\r
+   FCEUD_PrintError("DirectSound: 16-bit sound is not supported.  Forcing 8-bit sound.");\r
+   bittage=0;\r
+   soundoptions|=SO_FORCE8BIT;\r
+  }\r
+ }\r
+\r
+ wf.wBitsPerSample=8<<bittage;\r
+ wf.nBlockAlign = bittage+1;\r
+ wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;\r
\r
+ ddrval=IDirectSoundBuffer_SetFormat(ppbuf,&wf);\r
+ if (ddrval != DS_OK)\r
+ {\r
+  FCEUD_PrintError("DirectSound: Error setting primary buffer format.");\r
+  TrashSound();\r
+  return 0;\r
+ }\r
+\r
+ IDirectSoundBuffer_GetFormat(ppbuf,&wfa,sizeof(wfa),0);\r
+\r
+ if(soundoptions&SO_SECONDARY)\r
+ {\r
+  memset(&DSBufferDesc,0x00,sizeof(DSBUFFERDESC));  \r
+  DSBufferDesc.dwSize=sizeof(DSBufferDesc);\r
+  DSBufferDesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;\r
+  if(soundoptions&SO_GFOCUS)\r
+   DSBufferDesc.dwFlags|=DSBCAPS_GLOBALFOCUS;\r
+  DSBufferDesc.dwBufferBytes=32768;\r
+  DSBufferDesc.lpwfxFormat=&wfa;  \r
+  ddrval=IDirectSound_CreateSoundBuffer(ppDS, &DSBufferDesc, &ppbufsec, 0);\r
+  if (ddrval != DS_OK)\r
+  {\r
+   FCEUD_PrintError("DirectSound: Error creating secondary buffer.");\r
+   TrashSound();\r
+   return 0;\r
+  }\r
+ }\r
+\r
+ //sprintf(TempArray,"%d\n",wfa.nSamplesPerSec);\r
+ //FCEUD_PrintError(TempArray);\r
+\r
+ if(soundoptions&SO_SECONDARY)\r
+ {\r
+  DSBufferSize=32768;\r
+  IDirectSoundBuffer_SetCurrentPosition(ppbufsec,0);\r
+  ppbufw=ppbufsec;\r
+ }\r
+ else\r
+ {\r
+  memset(&dsbcaps,0,sizeof(dsbcaps));\r
+  dsbcaps.dwSize=sizeof(dsbcaps);\r
+  ddrval=IDirectSoundBuffer_GetCaps(ppbuf,&dsbcaps);\r
+  if (ddrval != DS_OK)\r
+  {\r
+   FCEUD_PrintError("DirectSound: Error getting buffer capabilities.");\r
+   TrashSound();\r
+   return 0;\r
+  }\r
+\r
+  DSBufferSize=dsbcaps.dwBufferBytes;\r
+\r
+  if(DSBufferSize<8192)\r
+  {\r
+   FCEUD_PrintError("DirectSound: Primary buffer size is too small!");\r
+   TrashSound();\r
+   return 0;\r
+  }\r
+  ppbufw=ppbuf;\r
+ }\r
+\r
+ soundbufsize=(soundbuftime*soundrate/1000);\r
+ FCEUI_Sound(soundrate);\r
+ return 1;\r
+}\r
+\r
+BOOL CALLBACK SoundConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+  int x;\r
+\r
+  switch(uMsg) {\r
+   case WM_INITDIALOG:\r
+                if(soundo)\r
+                 CheckDlgButton(hwndDlg,126,BST_CHECKED);\r
+                if(soundoptions&SO_FORCE8BIT)\r
+                 CheckDlgButton(hwndDlg,122,BST_CHECKED);\r
+                if(soundoptions&SO_SECONDARY)\r
+                 CheckDlgButton(hwndDlg,123,BST_CHECKED);\r
+                if(soundoptions&SO_GFOCUS)\r
+                 CheckDlgButton(hwndDlg,124,BST_CHECKED);\r
+                SetDlgItemInt(hwndDlg,200,soundrate,0);\r
+\r
+                /* Volume Trackbar */\r
+                SendDlgItemMessage(hwndDlg,500,TBM_SETRANGE,1,MAKELONG(0,200));\r
+                SendDlgItemMessage(hwndDlg,500,TBM_SETTICFREQ,25,0);\r
+                SendDlgItemMessage(hwndDlg,500,TBM_SETPOS,1,200-soundvolume);\r
+\r
+                /* buffer size time trackbar */\r
+                SendDlgItemMessage(hwndDlg,128,TBM_SETRANGE,1,MAKELONG(15,200));\r
+                SendDlgItemMessage(hwndDlg,128,TBM_SETTICFREQ,1,0);\r
+                SendDlgItemMessage(hwndDlg,128,TBM_SETPOS,1,soundbuftime);\r
+\r
+                {\r
+                 char tbuf[8];\r
+                 sprintf(tbuf,"%d",soundbuftime);\r
+                 SetDlgItemText(hwndDlg,666,(LPTSTR)tbuf);\r
+                }\r
+                \r
+                SendDlgItemMessage(hwndDlg,129,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Mean");\r
+                SendDlgItemMessage(hwndDlg,129,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Nice");\r
+                SendDlgItemMessage(hwndDlg,129,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Nicest");\r
+                SendDlgItemMessage(hwndDlg,129,CB_SETCURSEL,soundsleep,(LPARAM)(LPSTR)0);\r
+                break;\r
+   case WM_HSCROLL:\r
+                // This doesn't seem to work.  Hmm...\r
+                //if((HWND)lParam==(HWND)128)\r
+                {\r
+                 char tbuf[8];\r
+                 soundbuftime=SendDlgItemMessage(hwndDlg,128,TBM_GETPOS,0,0);\r
+                 sprintf(tbuf,"%d",soundbuftime);\r
+                 SetDlgItemText(hwndDlg,666,(LPTSTR)tbuf);\r
+                }\r
+                break;\r
+   case WM_CLOSE:\r
+   case WM_QUIT: goto gornk;\r
+   case WM_COMMAND:\r
+                if(!(wParam>>16))\r
+                switch(wParam&0xFFFF)\r
+                {\r
+                 case 1:\r
+                        gornk:\r
+                        soundoptions=0;\r
+                        if(IsDlgButtonChecked(hwndDlg,122)==BST_CHECKED)\r
+                         soundoptions|=SO_FORCE8BIT;\r
+                        if(IsDlgButtonChecked(hwndDlg,123)==BST_CHECKED)\r
+                         soundoptions|=SO_SECONDARY;\r
+                        if(IsDlgButtonChecked(hwndDlg,124)==BST_CHECKED)\r
+                         soundoptions|=SO_GFOCUS;\r
+                        if(IsDlgButtonChecked(hwndDlg,126)==BST_CHECKED)\r
+                         soundo=1;\r
+                        else\r
+                         soundo=0;\r
+                        x=GetDlgItemInt(hwndDlg,200,0,0);\r
+                        if(x<8192 || x>65535)\r
+                        {\r
+                         FCEUD_PrintError("Sample rate is out of range(8192-65535).");\r
+                         break;\r
+                        }\r
+                        else\r
+                         soundrate=x;\r
+\r
+                        soundvolume=200-SendDlgItemMessage(hwndDlg,500,TBM_GETPOS,0,0);\r
+                        FCEUI_SetSoundVolume(soundvolume);\r
+                        soundsleep=SendDlgItemMessage(hwndDlg,129,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);\r
+                        EndDialog(hwndDlg,0);\r
+                        break;\r
+               }\r
+              }\r
+  return 0;\r
+}\r
+\r
+\r
+void ConfigSound(void)\r
+{\r
+ int backo=soundo,sr=soundrate;\r
+ int so=soundoptions;\r
+\r
+ DialogBox(fceu_hInstance,"SOUNDCONFIG",hAppWnd,SoundConCallB);\r
+\r
+ if(((backo?1:0)!=(soundo?1:0)))\r
+ {\r
+  if(!soundo)\r
+   TrashSound();\r
+  else\r
+   soundo=InitSound();\r
+ }\r
+ else if(( soundoptions!=so || (sr!=soundrate)) && soundo)\r
+ {\r
+    TrashSound();\r
+    soundo=InitSound();\r
+ }\r
+ soundbufsize=(soundbuftime*soundrate/1000);\r
+}\r
+\r
+\r
+void StopSound(void)\r
+{\r
+ if(soundo)\r
+  IDirectSoundBuffer_Stop(ppbufw);\r
+}\r
+\r
+#include "wave.c"\r
diff --git a/drivers/win/throttle.c b/drivers/win/throttle.c
new file mode 100644 (file)
index 0000000..1ccf271
--- /dev/null
@@ -0,0 +1,73 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+static uint64 tmethod,tfreq;
+static uint64 desiredfps;
+
+static void RefreshThrottleFPS(void)
+{
+ desiredfps=FCEUI_GetDesiredFPS()>>8;
+}
+
+static uint64 GetCurTime(void)
+{
+ if(tmethod)
+ {
+  uint64 tmp;
+
+  /* Practically, LARGE_INTEGER and uint64 differ only by signness and name. */
+  QueryPerformanceCounter((LARGE_INTEGER*)&tmp);
+
+  return(tmp);
+ }
+ else
+  return((uint64)GetTickCount());
+
+}
+
+static void InitSpeedThrottle(void)
+{
+ tmethod=0;
+ if(QueryPerformanceFrequency((LARGE_INTEGER*)&tfreq))
+ {
+  tmethod=1;
+ }
+ else
+  tfreq=1000;
+ tfreq<<=16;    /* Adjustment for fps returned from FCEUI_GetDesiredFPS(). */
+}
+
+
+static void SpeedThrottle(void)
+{
+ static uint64 ttime,ltime;
+
+ waiter:
+
+ ttime=GetCurTime();
+
+                            
+ if( (ttime-ltime) < (tfreq/desiredfps) )
+  goto waiter;
+ if( (ttime-ltime) >= (tfreq*4/desiredfps))
+  ltime=ttime;
+ else
+  ltime+=tfreq/desiredfps;
+}
diff --git a/drivers/win/video.c b/drivers/win/video.c
new file mode 100644 (file)
index 0000000..a0438a0
--- /dev/null
@@ -0,0 +1,1174 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+static int RecalcCustom(void);
+
+#define VF_DDSTRETCHED     1
+
+#define VEF_LOSTSURFACE 1
+#define VEF____INTERNAL 2
+
+#define VMDF_DXBLT 1
+#define VMDF_STRFS 2
+
+typedef struct {
+        int x;
+        int y;
+        int bpp;
+        int flags;
+        int xscale;
+        int yscale;
+        RECT srect;
+        RECT drect;        
+} vmdef;
+
+// left, top, right, bottom
+static vmdef vmodes[11]={
+                         {320,240,8,0,1,1}, //0
+                         {320,240,8,0,1,1}, //1
+                         {512,384,8,0,1,1}, //2
+                         {640,480,8,0,1,1}, //3
+                         {640,480,8,0,1,1}, //4
+                         {640,480,8,0,1,1}, //5
+                         {640,480,8,VMDF_DXBLT,2,2}, //6
+                         {1024,768,8,VMDF_DXBLT,4,3}, //7
+                         {1280,1024,8,VMDF_DXBLT,5,4}, //8
+                         {1600,1200,8,VMDF_DXBLT,6,5}, //9
+                         {800,600,8,VMDF_DXBLT|VMDF_STRFS,0,0}    //10
+                       };
+static DDCAPS caps;
+static int mustrestore=0;
+static DWORD CBM[3];
+
+static int bpp;
+static int vflags;
+static int veflags;
+
+int fssync=0;
+int winsync=0;
+
+static uint32 *palettetranslate=0;
+
+PALETTEENTRY color_palette[256];
+static int PaletteChanged=0;
+
+LPDIRECTDRAWCLIPPER lpClipper=0;
+LPDIRECTDRAW  lpDD=0;
+LPDIRECTDRAW4 lpDD4=0;
+LPDIRECTDRAWPALETTE lpddpal;
+
+DDSURFACEDESC2 ddsd;
+
+DDSURFACEDESC2        ddsdback;
+LPDIRECTDRAWSURFACE4  lpDDSPrimary=0;
+LPDIRECTDRAWSURFACE4  lpDDSDBack=0;
+LPDIRECTDRAWSURFACE4  lpDDSBack=0;
+
+static void ShowDDErr(char *s)
+{
+ char tempo[512];
+ sprintf(tempo,"DirectDraw: %s",s);
+ FCEUD_PrintError(tempo);
+}
+
+int RestoreDD(int w)
+{
+ if(w)
+  {
+   if(!lpDDSBack) return 0;
+   if(IDirectDrawSurface4_Restore(lpDDSBack)!=DD_OK) return 0;
+  }
+ else
+  {
+   if(!lpDDSPrimary) return 0;
+   if(IDirectDrawSurface4_Restore(lpDDSPrimary)!=DD_OK) return 0;
+  }
+ veflags|=1;
+ return 1;
+}
+
+void FCEUD_SetPalette(unsigned char index, unsigned char r, unsigned char g, unsigned char b)
+{
+        color_palette[index].peRed=r;
+        color_palette[index].peGreen=g;
+        color_palette[index].peBlue=b;
+        PaletteChanged=1;
+}
+
+void FCEUD_GetPalette(unsigned char i, unsigned char *r, unsigned char *g, unsigned char *b)
+{
+        *r=color_palette[i].peRed;
+        *g=color_palette[i].peGreen;
+        *b=color_palette[i].peBlue;
+}
+
+int InitializeDDraw(void)
+{
+        ddrval = DirectDrawCreate(NULL, &lpDD, NULL);
+        if (ddrval != DD_OK)
+        {
+         ShowDDErr("Error creating DirectDraw object.");
+         return 0;
+        }
+
+        ddrval = IDirectDraw_QueryInterface(lpDD,&IID_IDirectDraw4,(LPVOID *)&lpDD4);
+        IDirectDraw_Release(lpDD);
+
+        if (ddrval != DD_OK)
+        {
+         ShowDDErr("Error querying interface.");
+         return 0;
+        }
+
+        caps.dwSize=sizeof(caps);
+        if(IDirectDraw4_GetCaps(lpDD4,&caps,0)!=DD_OK)
+        {
+         ShowDDErr("Error getting capabilities.");
+         return 0;
+        }
+        return 1;
+}
+
+static int GetBPP(void)
+{
+        DDPIXELFORMAT ddpix;
+
+        memset(&ddpix,0,sizeof(ddpix));
+        ddpix.dwSize=sizeof(ddpix);
+
+        ddrval=IDirectDrawSurface4_GetPixelFormat(lpDDSPrimary,&ddpix);
+        if (ddrval != DD_OK)
+        {
+         ShowDDErr("Error getting primary surface pixel format.");
+         return 0;
+        }
+
+        if(ddpix.dwFlags&DDPF_RGB)
+        {
+         bpp=ddpix.DUMMYUNIONNAMEN(1).dwRGBBitCount;
+         CBM[0]=ddpix.DUMMYUNIONNAMEN(2).dwRBitMask;
+         CBM[1]=ddpix.DUMMYUNIONNAMEN(3).dwGBitMask;
+         CBM[2]=ddpix.DUMMYUNIONNAMEN(4).dwBBitMask;
+        }
+        else
+        {
+         ShowDDErr("RGB data not valid.");
+         return 0;
+        }
+        if(bpp==15) bpp=16;
+
+        return 1;
+}
+
+static int InitBPPStuff(void)
+{
+   if(bpp==16)
+    palettetranslate=malloc(65536*4);
+   else if(bpp>=24)
+    palettetranslate=malloc(256*4);
+   else if(bpp==8)
+   {
+    ddrval=IDirectDraw4_CreatePalette( lpDD4, DDPCAPS_8BIT|DDPCAPS_ALLOW256|DDPCAPS_INITIALIZE,color_palette,&lpddpal,NULL);
+    if (ddrval != DD_OK)
+    {
+     ShowDDErr("Error creating palette object.");
+     return 0;
+    }
+    ddrval=IDirectDrawSurface4_SetPalette(lpDDSPrimary, lpddpal);
+    if (ddrval != DD_OK)
+    {
+     ShowDDErr("Error setting palette object.");
+     return 0;
+    }
+   }
+   return 1;
+}
+
+int SetVideoMode(int fs)
+{
+        if(!lpDD4)      // DirectDraw not initialized
+         return(1);
+
+        if(fs)
+         if(!vmod)
+          if(!RecalcCustom())
+           return(0);
+
+        vflags=0;
+        veflags=1;
+        PaletteChanged=1;
+
+        ResetVideo();
+
+        if(!fs)
+        { 
+         ShowCursorAbs(1);
+         windowedfailed=1;
+         HideFWindow(0);
+
+         ddrval = IDirectDraw4_SetCooperativeLevel ( lpDD4, hAppWnd, DDSCL_NORMAL);
+         if (ddrval != DD_OK)
+         {
+          ShowDDErr("Error setting cooperative level.");
+          return 1;
+         }
+
+         /* Beginning */
+         memset(&ddsd,0,sizeof(ddsd));
+         ddsd.dwSize = sizeof(ddsd);
+         ddsd.dwFlags = DDSD_CAPS;
+         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+         ddrval = IDirectDraw4_CreateSurface ( lpDD4, &ddsd, &lpDDSPrimary,(IUnknown FAR*)NULL);
+         if (ddrval != DD_OK)
+         {
+          ShowDDErr("Error creating primary surface.");
+          return 1;
+         }
+
+         memset(&ddsdback,0,sizeof(ddsdback));
+         ddsdback.dwSize=sizeof(ddsdback);
+         ddsdback.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+         ddsdback.ddsCaps.dwCaps= DDSCAPS_OFFSCREENPLAIN;
+
+         ddsdback.dwWidth=256;
+         ddsdback.dwHeight=240;
+
+         /* If no blit hardware is present, make sure buffer is created
+            in system memory.
+         */
+         if(!(caps.dwCaps&DDCAPS_BLT))
+          ddsdback.ddsCaps.dwCaps|=DDSCAPS_SYSTEMMEMORY;
+        
+         ddrval = IDirectDraw4_CreateSurface ( lpDD4, &ddsdback, &lpDDSBack, (IUnknown FAR*)NULL);
+         if (ddrval != DD_OK)
+         {
+          ShowDDErr("Error creating secondary surface.");
+          return 0;
+         }
+
+         if(!GetBPP())
+          return 0;
+
+         if(bpp!=16 && bpp!=24 && bpp!=32)
+         {
+          ShowDDErr("Current bit depth not supported!");
+          return 0;
+         }
+
+         if(!InitBPPStuff())
+          return 0;
+
+         ddrval=IDirectDraw4_CreateClipper(lpDD4,0,&lpClipper,0);
+         if (ddrval != DD_OK)
+         {
+          ShowDDErr("Error creating clipper.");
+          return 0;
+         }
+
+         ddrval=IDirectDrawClipper_SetHWnd(lpClipper,0,hAppWnd);
+         if (ddrval != DD_OK)
+         {
+          ShowDDErr("Error setting clipper window.");
+          return 0;
+         }
+         ddrval=IDirectDrawSurface4_SetClipper(lpDDSPrimary,lpClipper);
+         if (ddrval != DD_OK)
+         {
+          ShowDDErr("Error attaching clipper to primary surface.");
+          return 0;
+         }
+
+         windowedfailed=0;
+         SetMainWindowStuff();
+        }
+        else
+        {
+         HideFWindow(1);
+
+         ddrval = IDirectDraw4_SetCooperativeLevel ( lpDD4, hAppWnd,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT);
+         if (ddrval != DD_OK)
+         {
+          ShowDDErr("Error setting cooperative level.");
+          return 0;
+         }
+
+         ddrval = IDirectDraw4_SetDisplayMode(lpDD4, vmodes[vmod].x, vmodes[vmod].y,vmodes[vmod].bpp,0,0);
+         if (ddrval != DD_OK)
+         {
+          ShowDDErr("Error setting display mode.");
+          return 0;
+         }
+         if(vmodes[vmod].flags&VMDF_DXBLT)
+         {
+          memset(&ddsdback,0,sizeof(ddsdback));
+          ddsdback.dwSize=sizeof(ddsdback);
+          ddsdback.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+          ddsdback.ddsCaps.dwCaps= DDSCAPS_OFFSCREENPLAIN;
+
+          ddsdback.dwWidth=256; //vmodes[vmod].srect.right;
+          ddsdback.dwHeight=240; //vmodes[vmod].srect.bottom;
+
+          if(!(caps.dwCaps&DDCAPS_BLT))
+           ddsdback.ddsCaps.dwCaps|=DDSCAPS_SYSTEMMEMORY;
+
+          ddrval = IDirectDraw4_CreateSurface ( lpDD4, &ddsdback, &lpDDSBack, (IUnknown FAR*)NULL);
+          if(ddrval!=DD_OK)
+          {
+           ShowDDErr("Error creating secondary surface.");
+           return 0;
+          }
+         }
+
+         // create foreground surface
+        
+         memset(&ddsd,0,sizeof(ddsd));
+         ddsd.dwSize = sizeof(ddsd);
+         ddsd.dwFlags = DDSD_CAPS;
+         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+         if(fssync==2) // Double buffering.
+         {
+          ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT;
+          ddsd.dwBackBufferCount = 1;
+          ddsd.ddsCaps.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_FLIP;
+         }
+
+         ddrval = IDirectDraw4_CreateSurface ( lpDD4, &ddsd, &lpDDSPrimary,(IUnknown FAR*)NULL);
+         if (ddrval != DD_OK)
+         {
+          ShowDDErr("Error creating primary surface.");
+          return 0;
+         } 
+
+         if(fssync==2)
+         {
+          DDSCAPS2 tmp;
+
+          memset(&tmp,0,sizeof(tmp));
+          tmp.dwCaps=DDSCAPS_BACKBUFFER;
+
+          if(IDirectDrawSurface4_GetAttachedSurface(lpDDSPrimary,&tmp,&lpDDSDBack)!=DD_OK)
+          {
+           ShowDDErr("Error getting attached surface.");
+           return 0;
+          }
+         }
+
+         if(!GetBPP())
+          return 0;
+         if(!InitBPPStuff())
+          return 0;
+
+         mustrestore=1;
+         ShowCursorAbs(0);
+        }
+
+        InputScreenChanged(fs);
+        fullscreen=fs;
+        return 1;
+}
+
+static void BlitScreenWindow(uint8 *XBuf);
+static void BlitScreenFull(uint8 *XBuf);
+
+void FCEUD_BlitScreen(uint8 *XBuf)
+{
+ doagain:
+
+ UpdateFCEUWindow();
+
+ if(!(eoptions&EO_BGRUN))
+  while(nofocus)
+  {
+   Sleep(50);
+   BlockingCheck();
+  }
+
+
+ /* This complex statement deserves some explanation.
+    Make sure this special speed throttling hasn't been disabled by the user
+    first. Second, we don't want to throttle the speed if the fast-forward
+    button is pressed down(or during certain network play conditions).
+       
+    Now, if we're at this point, we'll throttle speed if sound is disabled.
+    Otherwise, it gets a bit more complicated.  We'll throttle speed if focus
+    to FCE Ultra has been lost and we're writing to the primary sound buffer
+    because our sound code won't block.  Blocking does seem to work when
+    writing to a secondary buffer, so we won't throttle when a secondary
+    buffer is used.
+ */
+
+ if(!(eoptions&EO_NOTHROTTLE))
+  if(!NoWaiting)
+   if(!soundo || (soundo && nofocus && !(soundoptions&SO_SECONDARY)) )
+       SpeedThrottle();
+
+ if(fullscreen)
+ {
+  if(fssync==1 && !NoWaiting)
+   IDirectDraw4_WaitForVerticalBlank(lpDD4,DDWAITVB_BLOCKBEGIN,0);
+
+  BlitScreenFull(XBuf);
+ }
+ else
+ {
+  if(winsync && !NoWaiting)
+   IDirectDraw4_WaitForVerticalBlank(lpDD4,DDWAITVB_BLOCKBEGIN,0);
+
+  if(!windowedfailed)
+   BlitScreenWindow(XBuf);
+ }
+ if(userpause)
+ {
+  StopSound();
+  Sleep(50);
+  BlockingCheck();
+  goto doagain;
+ }
+}
+
+static INLINE void BlitVidHi(uint8 *src, uint8 *dest, /*int xr,*/ int yr, int pitch)
+{
+ int x,y;
+ int pinc;
+
+ if(!(eoptions&EO_CLIPSIDES))
+  switch(bpp)
+  {
+   case 32:
+
+   pinc=pitch-(256<<2);
+   for(y=yr;y;y--)
+   {
+    for(x=256;x;x--)
+    {
+     *(uint32 *)dest=palettetranslate[(uint32)*src];     
+     dest+=4;
+     src++;
+    }
+    dest+=pinc;
+    src+=16;
+   }
+   break;
+
+  case 24:
+   pinc=pitch-(256*3);
+   for(y=yr;y;y--)
+   {
+    for(x=256;x;x--)
+    {
+     uint32 tmp;
+     tmp=palettetranslate[(uint32)*src];
+     *(uint16*)dest=(uint16)tmp;
+     *&dest[2]=(uint8)(tmp>>16);
+     dest+=3;
+     src++;
+    }
+    dest+=pinc;
+    src+=16;
+   }
+   break;
+
+  case 16:
+   pinc=pitch-(256<<1);
+   for(y=yr;y;y--)
+   {
+    for(x=256>>1;x;x--)
+    {
+     *(unsigned long *)dest=palettetranslate[*(unsigned short *)src];
+     dest+=4;
+     src+=2;
+    }
+    dest+=pinc;
+    src+=16;
+   }
+   break;
+ }
+ else
+  switch(bpp)
+  {
+   case 32:
+
+   pinc=pitch-(240<<2);
+   for(y=yr;y;y--)
+   {
+    for(x=240;x;x--)
+    {
+     *(uint32 *)dest=palettetranslate[(uint32)*src];
+     dest+=4;
+     src++;
+    }
+    dest+=pinc;
+    src+=32;
+   }
+   break;
+
+  case 24:
+   pinc=pitch-(240*3);
+   for(y=yr;y;y--)
+   {
+    for(x=240;x;x--)
+    {
+     uint32 tmp;
+     tmp=palettetranslate[(uint32)*src];
+     *(uint16*)dest=(uint16)tmp;
+     *&dest[2]=(uint8)(tmp>>16);
+     dest+=3;
+     src++;
+    }
+    dest+=pinc;
+    src+=32;
+   }
+   break;
+  case 16:
+   pinc=pitch-(240<<1);
+   for(y=yr;y;y--)
+   {
+    for(x=240>>1;x;x--)
+    {
+     *(unsigned long *)dest=palettetranslate[*(unsigned short *)src];
+     dest+=4;
+     src+=2;
+    }
+    dest+=pinc;
+    src+=32;
+   }
+   break;
+ }
+}
+
+static INLINE void FixPaletteHi(void)
+{
+   int x;
+
+   switch(bpp)
+   {
+    case 16:{
+             int cshiftr[3];
+             int cshiftl[3];
+             int a,x,z,y;
+        
+             cshiftl[0]=cshiftl[1]=cshiftl[2]=-1;
+             for(a=0;a<3;a++)
+             {
+              for(x=0,y=-1,z=0;x<16;x++)
+              {
+               if(CBM[a]&(1<<x))
+               {
+                if(cshiftl[a]==-1) cshiftl[a]=x;
+                z++;
+               }
+              }
+              cshiftr[a]=(8-z);
+             }
+
+             for(x=0;x<65536;x++)
+             { 
+              uint16 lower,upper;   
+              lower=(color_palette[x&255].peRed>>cshiftr[0])<<cshiftl[0];
+              lower|=(color_palette[x&255].peGreen>>cshiftr[1])<<cshiftl[1];
+              lower|=(color_palette[x&255].peBlue>>cshiftr[2])<<cshiftl[2];
+              upper=(color_palette[x>>8].peRed>>cshiftr[0])<<cshiftl[0];
+              upper|=(color_palette[x>>8].peGreen>>cshiftr[1])<<cshiftl[1];
+              upper|=(color_palette[x>>8].peBlue>>cshiftr[2])<<cshiftl[2];      
+              palettetranslate[x]=lower|(upper<<16);
+             }
+            }
+            break;
+    case 24:
+    case 32:
+            for(x=0;x<256;x++)
+            {
+             uint32 t;
+             t=0;
+             t=color_palette[x].peBlue;
+             t|=color_palette[x].peGreen<<8;
+             t|=color_palette[x].peRed<<16;
+             palettetranslate[x]=t;
+            }
+            break;
+   }
+}
+
+static void BlitScreenWindow(unsigned char *XBuf)
+{
+ int pitch;
+ unsigned char *ScreenLoc;
+ static RECT srect;
+ RECT drect;
+
+ srect.top=srect.left=0;
+ srect.right=VNSWID;
+ srect.bottom=totallines;
+
+ if(PaletteChanged==1)
+ {
+  FixPaletteHi();
+  PaletteChanged=0;
+ }
+ if(!GetClientAbsRect(&drect)) return;
+
+ ddrval=IDirectDrawSurface4_Lock(lpDDSBack,NULL,&ddsdback, 0, NULL);
+ if(ddrval!=DD_OK)
+ {
+  if(ddrval==DDERR_SURFACELOST) RestoreDD(1);
+  return;
+ }
+ pitch=ddsdback.DUMMYUNIONNAMEN(1).lPitch;
+ ScreenLoc=ddsdback.lpSurface;
+
+ if(veflags&1)
+ {
+  memset(ScreenLoc,0,pitch*240);
+  veflags&=~1;
+ }
+
+ BlitVidHi(XBuf+srendline*272+VNSCLIP, ScreenLoc, /*VNSWID,*/ totallines, pitch);
+
+ IDirectDrawSurface4_Unlock(lpDDSBack, NULL);
+
+ if(IDirectDrawSurface4_Blt(lpDDSPrimary, &drect,lpDDSBack,&srect,DDBLT_ASYNC,0)!=DD_OK)
+ {
+  ddrval=IDirectDrawSurface4_Blt(lpDDSPrimary, &drect,lpDDSBack,&srect,DDBLT_WAIT,0);
+  if(ddrval!=DD_OK)
+  {
+   if(ddrval==DDERR_SURFACELOST) {RestoreDD(1);RestoreDD(0);}
+   return;
+  }
+ }
+}
+
+static void BlitScreenFull(uint8 *XBuf)
+{
+  static int pitch;
+  char *ScreenLoc;
+  unsigned long x;
+  uint8 y;
+  RECT srect,drect;
+  LPDIRECTDRAWSURFACE4 lpDDSVPrimary;
+
+
+  if(fssync==2)
+   lpDDSVPrimary=lpDDSDBack;
+  else
+   lpDDSVPrimary=lpDDSPrimary;
+
+  if(PaletteChanged==1)
+  {
+   if(bpp>=16)
+    FixPaletteHi();
+   else
+    for(x=0;x<=0x80;x+=0x80)
+    {
+     ddrval=IDirectDrawPalette_SetEntries(lpddpal,0,0x80^x,128,&color_palette[x]);
+     if(ddrval!=DD_OK)
+     {
+      if(ddrval==DDERR_SURFACELOST) RestoreDD(0);
+      return;
+     }
+    }
+   PaletteChanged=0;
+  }
+
+ if(vmodes[vmod].flags&VMDF_DXBLT)
+ {
+  ddrval=IDirectDrawSurface4_Lock(lpDDSBack,NULL,&ddsdback, 0, NULL);
+  if(ddrval!=DD_OK)
+  {
+   if(ddrval==DDERR_SURFACELOST) RestoreDD(1);
+   return;
+  }
+  ScreenLoc=ddsdback.lpSurface;
+  pitch=ddsdback.DUMMYUNIONNAMEN(1).lPitch;
+
+  srect.top=0;
+  srect.left=0;
+  srect.right=VNSWID;
+  srect.bottom=totallines;
+  if(vmodes[vmod].flags&VMDF_STRFS)
+  {
+   drect.top=0;
+   drect.left=0;
+   drect.right=vmodes[vmod].x;
+   drect.bottom=vmodes[vmod].y;
+  }
+  else
+  {
+   drect.top=(vmodes[vmod].y-(totallines*vmodes[vmod].yscale))>>1;
+   drect.bottom=drect.top+(totallines*vmodes[vmod].yscale);
+   drect.left=(vmodes[vmod].x-VNSWID*vmodes[vmod].xscale)>>1;
+   drect.right=drect.left+VNSWID*vmodes[vmod].xscale;
+  }
+ }
+ else
+ {
+  ddrval=IDirectDrawSurface4_Lock(lpDDSVPrimary,NULL,&ddsd, 0, NULL);
+  if(ddrval!=DD_OK)
+  {
+   if(ddrval==DDERR_SURFACELOST) RestoreDD(0);
+   return;
+  }
+
+  ScreenLoc=ddsd.lpSurface;
+  pitch=ddsd.DUMMYUNIONNAMEN(1).lPitch;
+ }
+
+ if(veflags&1)
+ {
+  if(vmodes[vmod].flags&VMDF_DXBLT)
+  {
+   veflags|=2;
+   memset((char *)ScreenLoc,0,pitch*srect.bottom);
+  }
+  else
+  {
+   memset((char *)ScreenLoc,0,pitch*vmodes[vmod].y);
+  }
+  PaletteChanged=1;
+  veflags&=~1;
+ }
+
+ if(vmod==5)
+ {
+  if(eoptions&EO_CLIPSIDES)
+  {
+   asm volatile(
+      "xorl %%edx, %%edx\n\t"
+      "akoop1:\n\t"
+      "movb $120,%%al     \n\t"
+      "akoop2:\n\t"
+      "movb 1(%%esi),%%dl\n\t"
+      "shl  $16,%%edx\n\t"
+      "movb (%%esi),%%dl\n\t"
+      "xorl $0x00800080,%%edx\n\t"
+      "movl %%edx,(%%edi)\n\t"
+      "addl $2,%%esi\n\t"
+      "addl $4,%%edi\n\t"
+      "decb %%al\n\t"
+      "jne akoop2\n\t"
+      "addl $32,%%esi\n\t"
+      "addl %%ecx,%%edi\n\t"
+      "decb %%bl\n\t"
+      "jne akoop1\n\t"
+      :
+      : "S" (XBuf+srendline*272+VNSCLIP), "D" (ScreenLoc+((240-totallines)/2)*pitch+(640-(VNSWID<<1))/2),"b" (totallines), "c" ((pitch-VNSWID)<<1)
+      : "%al", "%edx", "%cc" );
+  }
+  else
+  {
+   asm volatile(
+     "xorl %%edx, %%edx\n\t"
+     "koop1:\n\t"
+     "movb $128,%%al     \n\t"
+     "koop2:\n\t"
+     "movb 1(%%esi),%%dl\n\t"
+     "shl  $16,%%edx\n\t"
+     "movb (%%esi),%%dl\n\t"
+     "xorl $0x00800080,%%edx\n\t"
+     "movl %%edx,(%%edi)\n\t"
+     "addl $2,%%esi\n\t"
+     "addl $4,%%edi\n\t"
+     "decb %%al\n\t"
+     "jne koop2\n\t"
+     "addl $16,%%esi\n\t"
+     "addl %%ecx,%%edi\n\t"
+     "decb %%bl\n\t"
+     "jne koop1\n\t"
+      :
+      : "S" (XBuf+srendline*272), "D" (ScreenLoc+((240-totallines)/2)*pitch+(640-512)/2),"b" (totallines), "c" (pitch-512+pitch)
+      : "%al", "%edx", "%cc" );
+  }
+ }
+ else if(vmod==4)
+ {
+  if(eoptions&EO_CLIPSIDES)
+  {
+   asm volatile(
+      "ayoop1:\n\t"
+      "movb $120,%%al     \n\t"
+      "ayoop2:\n\t"
+      "movb 1(%%esi),%%dh\n\t"
+      "movb %%dh,%%dl\n\t"
+      "shl  $16,%%edx\n\t"
+      "movb (%%esi),%%dl\n\t"
+      "movb %%dl,%%dh\n\t"               // Ugh
+      "xorl $0x80808080,%%edx\n\t"
+      "movl %%edx,(%%edi)\n\t"
+      "addl $2,%%esi\n\t"
+      "addl $4,%%edi\n\t"
+      "decb %%al\n\t"
+      "jne ayoop2\n\t"
+      "addl $32,%%esi\n\t"
+      "addl %%ecx,%%edi\n\t"
+      "decb %%bl\n\t"
+      "jne ayoop1\n\t"
+      :
+      : "S" (XBuf+srendline*272+VNSCLIP), "D" (ScreenLoc+((240-totallines)/2)*pitch+(640-(VNSWID<<1))/2),"b" (totallines), "c" ((pitch-VNSWID)<<1)
+      : "%al", "%edx", "%cc" );
+  }
+  else
+  {
+   asm volatile(
+      "yoop1:\n\t"
+      "movb $128,%%al     \n\t"
+      "yoop2:\n\t"
+      "movb 1(%%esi),%%dh\n\t"
+      "movb %%dh,%%dl\n\t"
+      "shl  $16,%%edx\n\t"
+      "movb (%%esi),%%dl\n\t"
+      "movb %%dl,%%dh\n\t"               // Ugh
+      "xorl $0x80808080,%%edx\n\t"
+      "movl %%edx,(%%edi)\n\t"
+      "addl $2,%%esi\n\t"
+      "addl $4,%%edi\n\t"
+      "decb %%al\n\t"
+      "jne yoop2\n\t"
+      "addl $16,%%esi\n\t"
+      "addl %%ecx,%%edi\n\t"
+      "decb %%bl\n\t"
+      "jne yoop1\n\t"
+      :
+      : "S" (XBuf+srendline*272), "D" (ScreenLoc+((240-totallines)/2)*pitch+(640-512)/2),"b" (totallines), "c" (pitch-512+pitch)
+      : "%al", "%edx", "%cc" );
+  }
+ }
+ else
+ {
+  if(!(vmodes[vmod].flags&VMDF_DXBLT))
+  {  
+   ScreenLoc+=((vmodes[vmod].x-VNSWID)>>1)*(bpp>>3)+(((vmodes[vmod].y-totallines)>>1))*pitch;
+  }
+  if(bpp>=16)
+  {
+   BlitVidHi(XBuf+srendline*272+VNSCLIP, ScreenLoc, /*VNSWID,*/ totallines, pitch);
+  }
+  else
+  {
+   XBuf+=srendline*272+VNSCLIP;
+   if(eoptions&EO_CLIPSIDES)
+   {
+    for(y=totallines;y;y--)
+    {
+     for(x=60;x;x--)
+     {
+      *(long *)ScreenLoc=(*(long *)XBuf)^0x80808080;
+      ScreenLoc+=4;
+      XBuf+=4;
+     }
+     ScreenLoc+=pitch-240;
+     XBuf+=32;
+    }
+   }
+   else
+   {
+    for(y=totallines;y;y--)
+    {
+     for(x=64;x;x--)
+     {
+      *(long *)ScreenLoc=(*(long *)XBuf)^0x80808080;
+      ScreenLoc+=4;
+      XBuf+=4;
+     }
+     ScreenLoc+=pitch-256;
+     XBuf+=16;
+    }
+   }
+  }
+ }
+
+ if(vmodes[vmod].flags&VMDF_DXBLT)
+ { 
+  IDirectDrawSurface4_Unlock(lpDDSBack, NULL);
+
+  if(veflags&2)
+  {
+   if(IDirectDrawSurface4_Lock(lpDDSVPrimary,NULL,&ddsd, 0, NULL)==DD_OK)
+   {
+    memset(ddsd.lpSurface,0,ddsd.DUMMYUNIONNAMEN(1).lPitch*vmodes[vmod].y);
+    IDirectDrawSurface4_Unlock(lpDDSVPrimary, NULL);
+    veflags&=~2;
+   }
+  }
+
+  if(IDirectDrawSurface4_Blt(lpDDSVPrimary, &drect,lpDDSBack,&srect,DDBLT_ASYNC,0)!=DD_OK)
+  {
+   ddrval=IDirectDrawSurface4_Blt(lpDDSVPrimary, &drect,lpDDSBack,&srect,DDBLT_WAIT,0);
+   if(ddrval!=DD_OK)
+   {
+    if(ddrval==DDERR_SURFACELOST)
+    {
+     RestoreDD(0);
+     RestoreDD(1);
+    }
+    return;
+   }
+
+  }
+ }
+ else
+  IDirectDrawSurface4_Unlock(lpDDSVPrimary, NULL);
+ if(fssync==2)
+ {
+  IDirectDrawSurface4_Flip(lpDDSPrimary,0,0);
+
+ }
+}
+
+void ResetVideo(void)
+{
+ ShowCursorAbs(1);
+ if(palettetranslate) {free(palettetranslate);palettetranslate=0;}
+ if(lpDD4)
+  if(mustrestore)
+   {IDirectDraw4_RestoreDisplayMode(lpDD4);mustrestore=0;}
+ if(lpDDSBack) {IDirectDrawSurface4_Release(lpDDSBack);lpDDSBack=0;}
+ if(lpDDSPrimary) {IDirectDrawSurface4_Release(lpDDSPrimary);lpDDSPrimary=0;} 
+ if(lpClipper) {IDirectDrawClipper_Release(lpClipper);lpClipper=0;}
+}
+
+static int RecalcCustom(void)
+{
+ vmodes[0].flags&=~VMDF_DXBLT;
+
+ if(vmodes[0].flags&VMDF_STRFS)
+ {
+  vmodes[0].flags|=VMDF_DXBLT;
+
+  vmodes[0].srect.top=srendline;
+  vmodes[0].srect.left=VNSCLIP;
+  vmodes[0].srect.right=256-VNSCLIP;
+  vmodes[0].srect.bottom=erendline+1;
+
+  vmodes[0].drect.top=vmodes[0].drect.left=0;
+  vmodes[0].drect.right=vmodes[0].x;
+  vmodes[0].drect.bottom=vmodes[0].y;
+ }
+ else if(vmodes[0].xscale!=1 || vmodes[0].yscale!=1)
+ {
+  vmodes[0].flags|=VMDF_DXBLT;
+  if(VNSWID*vmodes[0].xscale>vmodes[0].x)
+  {
+   FCEUD_PrintError("Scaled width is out of range.  Reverting to no horizontal scaling.");
+   vmodes[0].xscale=1;
+  }
+  if(totallines*vmodes[0].yscale>vmodes[0].y)
+  {
+   FCEUD_PrintError("Scaled height is out of range.  Reverting to no vertical scaling.");
+   vmodes[0].yscale=1;
+  }
+
+  vmodes[0].srect.left=VNSCLIP;
+  vmodes[0].srect.top=srendline;
+  vmodes[0].srect.right=256-VNSCLIP;
+  vmodes[0].srect.bottom=erendline+1;
+
+  vmodes[0].drect.top=(vmodes[0].y-(totallines*vmodes[0].yscale))>>1;
+  vmodes[0].drect.bottom=vmodes[0].drect.top+totallines*vmodes[0].yscale;
+  
+  vmodes[0].drect.left=(vmodes[0].x-(VNSWID*vmodes[0].xscale))>>1;
+  vmodes[0].drect.right=vmodes[0].drect.left+VNSWID*vmodes[0].xscale;
+ }
+
+ if(vmodes[0].x<VNSWID)
+ {
+  FCEUD_PrintError("Horizontal resolution is too low.");
+  return(0);
+ }
+ if(vmodes[0].y<totallines && !(vmodes[0].flags&VMDF_STRFS))
+ {
+  FCEUD_PrintError("Vertical resolution must not be less than the total number of drawn scanlines.");
+  return(0);
+ }
+
+ return(1);
+}
+
+BOOL CALLBACK VideoConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+        static char *vmstr[11]={
+                                "Custom",
+                                "320x240 Full Screen",
+                                "512x384 Centered",
+                                "640x480 Centered",
+                                "640x480 Scanlines",
+                                "640x480 \"4 per 1\"",
+                                "640x480 2x,2y",
+                                "1024x768 4x,3y",
+                                "1280x1024 5x,4y",
+                                "1600x1200 6x,5y",
+                                "800x600 Stretched"
+                               };
+        int x;
+
+        switch(uMsg)
+        {
+         case WM_INITDIALOG:                
+                for(x=0;x<11;x++)
+                 SendDlgItemMessage(hwndDlg,100,CB_ADDSTRING,0,(LPARAM)(LPSTR)vmstr[x]);
+                SendDlgItemMessage(hwndDlg,100,CB_SETCURSEL,vmod,(LPARAM)(LPSTR)0);
+
+                SendDlgItemMessage(hwndDlg,202,CB_ADDSTRING,0,(LPARAM)(LPSTR)"8");
+                SendDlgItemMessage(hwndDlg,202,CB_ADDSTRING,0,(LPARAM)(LPSTR)"16");
+                SendDlgItemMessage(hwndDlg,202,CB_ADDSTRING,0,(LPARAM)(LPSTR)"24");
+                SendDlgItemMessage(hwndDlg,202,CB_ADDSTRING,0,(LPARAM)(LPSTR)"32");
+                SendDlgItemMessage(hwndDlg,202,CB_SETCURSEL,(vmodes[0].bpp>>3)-1,(LPARAM)(LPSTR)0);
+
+                SetDlgItemInt(hwndDlg,200,vmodes[0].x,0);
+                SetDlgItemInt(hwndDlg,201,vmodes[0].y,0);
+
+                SetDlgItemInt(hwndDlg,302,vmodes[0].xscale,0);
+                SetDlgItemInt(hwndDlg,303,vmodes[0].yscale,0);
+                CheckRadioButton(hwndDlg,300,301,(vmodes[0].flags&VMDF_STRFS)?301:300);
+                if(eoptions&EO_FSAFTERLOAD)
+                 CheckDlgButton(hwndDlg,102,BST_CHECKED);
+
+                if(eoptions&EO_CLIPSIDES)
+                 CheckDlgButton(hwndDlg,106,BST_CHECKED);
+
+                SetDlgItemInt(hwndDlg,500,srendlinen,0);
+                SetDlgItemInt(hwndDlg,501,erendlinen,0);
+
+                SetDlgItemInt(hwndDlg,502,srendlinep,0);
+                SetDlgItemInt(hwndDlg,503,erendlinep,0);
+
+
+                SetDlgItemInt(hwndDlg,103,winsizemul,0);
+
+                SendDlgItemMessage(hwndDlg,104,CB_ADDSTRING,0,(LPARAM)(LPSTR)"<none>");
+                SendDlgItemMessage(hwndDlg,105,CB_ADDSTRING,0,(LPARAM)(LPSTR)"<none>");
+
+                SendDlgItemMessage(hwndDlg,104,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Wait for VBlank");
+                SendDlgItemMessage(hwndDlg,105,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Wait for VBlank");
+
+                SendDlgItemMessage(hwndDlg,105,CB_ADDSTRING,0,(LPARAM)(LPSTR)"Double Buffering");
+
+                SendDlgItemMessage(hwndDlg,104,CB_SETCURSEL,winsync,(LPARAM)(LPSTR)0);
+                SendDlgItemMessage(hwndDlg,105,CB_SETCURSEL,fssync,(LPARAM)(LPSTR)0);
+                break;
+         case WM_CLOSE:
+         case WM_QUIT: goto gornk;
+         case WM_COMMAND:
+                        if(!(wParam>>16))
+                        switch(wParam&0xFFFF)
+                        {
+                         case 1:
+                         gornk:
+         
+                         if(IsDlgButtonChecked(hwndDlg,106)==BST_CHECKED)
+                          eoptions|=EO_CLIPSIDES;
+                         else
+                          eoptions&=~EO_CLIPSIDES;
+
+                         srendlinen=GetDlgItemInt(hwndDlg,500,0,0);
+                         erendlinen=GetDlgItemInt(hwndDlg,501,0,0);
+                         srendlinep=GetDlgItemInt(hwndDlg,502,0,0);
+                         erendlinep=GetDlgItemInt(hwndDlg,503,0,0);
+
+
+                         if(erendlinen>239) erendlinen=239;
+                         if(srendlinen>erendlinen) srendlinen=erendlinen;
+
+                         if(erendlinep>239) erendlinep=239;
+                         if(srendlinep>erendlinen) srendlinep=erendlinep;
+
+                         UpdateRendBounds();
+
+                         if(IsDlgButtonChecked(hwndDlg,301)==BST_CHECKED)
+                          vmodes[0].flags|=VMDF_STRFS;
+                         else
+                          vmodes[0].flags&=~VMDF_STRFS;
+
+                         vmod=SendDlgItemMessage(hwndDlg,100,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);
+                         vmodes[0].x=GetDlgItemInt(hwndDlg,200,0,0);
+                         vmodes[0].y=GetDlgItemInt(hwndDlg,201,0,0);
+                         vmodes[0].bpp=(SendDlgItemMessage(hwndDlg,202,CB_GETCURSEL,0,(LPARAM)(LPSTR)0)+1)<<3;
+
+                         vmodes[0].xscale=GetDlgItemInt(hwndDlg,302,0,0);
+                         vmodes[0].yscale=GetDlgItemInt(hwndDlg,303,0,0);
+        
+                         if(IsDlgButtonChecked(hwndDlg,101)==BST_CHECKED)
+                          fullscreen=1;
+                         else
+                          fullscreen=0;
+                         if(IsDlgButtonChecked(hwndDlg,102)==BST_CHECKED)
+                          eoptions|=EO_FSAFTERLOAD;
+                         else
+                          eoptions&=~EO_FSAFTERLOAD;
+
+                         {
+                          int t=GetDlgItemInt(hwndDlg,103,0,0);
+                          if(t>0 && t<60)
+                           winsizemul=t;
+                         }
+                         winsync=SendDlgItemMessage(hwndDlg,104,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);
+                         fssync=SendDlgItemMessage(hwndDlg,105,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);
+                         EndDialog(hwndDlg,0);
+                         break;
+               }
+              }
+  return 0;
+}
+
+static void SetFSVideoMode(void)
+{
+ changerecursive=1;
+ if(!SetVideoMode(1))
+  SetVideoMode(0);
+ changerecursive=0;
+}
+
+
+
+void ConfigVideo(void)
+{
+        DialogBox(fceu_hInstance,"VIDEOCONFIG",hAppWnd,VideoConCallB); 
+        UpdateRendBounds();
+        if(fullscreen)
+         SetFSVideoMode();
+        else
+         SetMainWindowStuff();
+}
+
+void DoVideoConfigFix(void)
+{
+        UpdateRendBounds();
+}
+
+
+#ifdef moo
+                         if(!vmod)
+                         {
+                          if(vmodes[0].x<VNSWID)
+                          {
+                           FCEUD_PrintError("Horizontal resolution is too low.");
+                           return 0;
+                          }
+                          if(vmodes[0].y<totallines && !(vmodes[0].flags&VMDF_STRFS))
+                          {
+                           FCEUD_PrintError("Vertical resolution must not be less than the total number of drawn scanlines.");
+                           return 0;
+                          }
+                         }
+
+
+#endif
diff --git a/drivers/win/wave.c b/drivers/win/wave.c
new file mode 100644 (file)
index 0000000..70ac49c
--- /dev/null
@@ -0,0 +1,125 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+static int16 MoBuffer[2048];
+static int wsize;
+void WriteWaveData(int32 *Buffer, int Count)
+{
+  int P;
+
+  for(P=0;P<Count;P++)
+   MoBuffer[P]=Buffer[P];
+  wsize+=fwrite(MoBuffer,1,Count<<1,soundlog);
+}
+
+static int CloseWave(void)
+{
+ int s;
+
+ if(!soundlog) return 0;
+ s=ftell(soundlog)-8;
+ fseek(soundlog,4,SEEK_SET);
+ fputc(s&0xFF,soundlog);
+ fputc((s>>8)&0xFF,soundlog);
+ fputc((s>>16)&0xFF,soundlog);
+ fputc((s>>24)&0xFF,soundlog);
+
+ fseek(soundlog,0x28,SEEK_SET);
+ s=wsize;
+ fputc(s&0xFF,soundlog);
+ fputc((s>>8)&0xFF,soundlog);
+ fputc((s>>16)&0xFF,soundlog);
+ fputc((s>>24)&0xFF,soundlog);
+
+ fclose(soundlog);
+ soundlog=0;
+ return 1;
+}
+int WriteWaveHeader(FILE *fp)
+{
+ int r;
+ fputs("RIFF",fp);
+ fseek(fp,4,SEEK_CUR);  // Skip size
+ fputs("WAVEfmt ",fp);
+ fputc(0x10,fp);
+ fputc(0,fp);
+ fputc(0,fp);
+ fputc(0,fp);
+
+ fputc(1,fp);           // PCM
+ fputc(0,fp);
+ fputc(1,fp);           // Monophonic
+ fputc(0,fp);
+
+ r=44100;
+ fputc(r&0xFF,fp);
+ fputc((r>>8)&0xFF,fp);
+ fputc((r>>16)&0xFF,fp);
+ fputc((r>>24)&0xFF,fp);
+ r<<=1;
+ fputc(r&0xFF,fp);
+ fputc((r>>8)&0xFF,fp);
+ fputc((r>>16)&0xFF,fp);
+ fputc((r>>24)&0xFF,fp);
+ fputc(2,fp);
+ fputc(0,fp);
+ fputc(16,fp);
+ fputc(0,fp);
+
+ fputs("data",fp);
+ fseek(fp,4,SEEK_CUR);
+
+ return 1;
+}
+
+int StartSoundLog(char *str)
+{
+  wsize=0;
+  soundlog=fopen(str,"wb");
+  if(soundlog)
+   return WriteWaveHeader(soundlog);
+  else
+   return 0;
+}
+int CreateSoundSave(void)
+{
+ const char filter[]="MS WAVE(*.wav)\0*.wav\0";
+ char nameo[2048];
+ OPENFILENAME ofn;
+
+ if(soundlog)
+  {
+   CloseWave();
+   return 0;
+  }
+
+ memset(&ofn,0,sizeof(ofn));
+ ofn.lStructSize=sizeof(ofn);
+ ofn.hInstance=fceu_hInstance;
+ ofn.lpstrTitle="Log Sound As...";
+ ofn.lpstrFilter=filter;
+ nameo[0]=0;
+ ofn.lpstrFile=nameo;
+ ofn.nMaxFile=256;
+ ofn.Flags=OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
+ if(GetSaveFileName(&ofn))
+  return StartSoundLog(nameo);
+ return 0;
+}
diff --git a/drivers/win/window.c b/drivers/win/window.c
new file mode 100644 (file)
index 0000000..6ccd4e0
--- /dev/null
@@ -0,0 +1,855 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 2002 Ben Parnell\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+static void ConfigMisc(void);\r
+static void ConfigPalette(void);\r
+static void ConfigDirectories(void);\r
+\r
+static HMENU fceumenu=0;\r
+static HMENU recentmenu;\r
+\r
+static int tog=0;\r
+\r
+void ShowCursorAbs(int w)\r
+{\r
+ static int stat=0;\r
+ if(w)\r
+ {\r
+  if(stat==-1) {stat++; ShowCursor(1);}\r
+ }\r
+ else\r
+ {\r
+  if(stat==0) {stat--; ShowCursor(0);}\r
+ }\r
+}\r
+\r
+\r
+RECT *CalcWindowSize(void)\r
+{\r
+ static RECT al;\r
+ al.left=0;\r
+ al.right=VNSWID*winsizemul;\r
+ al.top=0;\r
+ al.bottom=totallines*winsizemul;\r
+\r
+ AdjustWindowRectEx(&al,GetWindowLong(hAppWnd,GWL_STYLE),GetMenu(hAppWnd)!=NULL,GetWindowLong(hAppWnd,GWL_EXSTYLE));\r
+\r
+ al.right-=al.left;\r
+ al.left=0;\r
+ al.bottom-=al.top;\r
+ al.top=0;\r
+\r
+ return(&al);\r
+}\r
+\r
+void UpdateMenu(void)\r
+{\r
+ static int *polo[2]={&genie,&palyo};\r
+ static int polo2[2]={310,311};\r
+ int x;\r
+\r
+ for(x=0;x<2;x++)\r
+  CheckMenuItem(fceumenu,polo2[x],*polo[x]?MF_CHECKED:MF_UNCHECKED);\r
+ if(eoptions&EO_BGRUN)\r
+  CheckMenuItem(fceumenu,301,MF_CHECKED);\r
+ else\r
+  CheckMenuItem(fceumenu,301,MF_UNCHECKED);\r
+}\r
+\r
+char *rfiles[10]={0,0,0,0,0,0,0,0,0,0};\r
+\r
+void UpdateRMenu(void)\r
+{\r
+ MENUITEMINFO moo;\r
+ int x;\r
+\r
+ moo.cbSize=sizeof(moo);\r
+ moo.fMask=MIIM_SUBMENU|MIIM_STATE;\r
+\r
+ GetMenuItemInfo(GetSubMenu(fceumenu,0),102,FALSE,&moo);\r
+ moo.hSubMenu=recentmenu;\r
+ moo.fState=rfiles[0]?MFS_ENABLED:MFS_GRAYED;\r
+\r
+ SetMenuItemInfo(GetSubMenu(fceumenu,0),102,FALSE,&moo);\r
+\r
+ for(x=0;x<10;x++)\r
+  RemoveMenu(recentmenu,600+x,MF_BYCOMMAND);\r
+ for(x=9;x>=0;x--)\r
+ {  \r
+  char tmp[128+5];\r
+  if(!rfiles[x]) continue;\r
+\r
+  moo.cbSize=sizeof(moo);\r
+  moo.fMask=MIIM_DATA|MIIM_ID|MIIM_TYPE;\r
+\r
+  if(strlen(rfiles[x])<128)\r
+  {\r
+   sprintf(tmp,"&%d. %s",(x+1)%10,rfiles[x]);\r
+  }\r
+  else\r
+   sprintf(tmp,"&%d. %s",(x+1)%10,rfiles[x]+strlen(rfiles[x])-127);\r
+\r
+  moo.cch=strlen(tmp);\r
+  moo.fType=0;\r
+  moo.wID=600+x;\r
+  moo.dwTypeData=tmp;\r
+  InsertMenuItem(recentmenu,0,1,&moo);\r
+ }\r
+ DrawMenuBar(hAppWnd);\r
+}\r
+\r
+void AddRecent(char *fn)\r
+{\r
+ int x;\r
+\r
+ for(x=0;x<10;x++)\r
+  if(rfiles[x])\r
+   if(!strcmp(rfiles[x],fn))    // Item is already in list.\r
+   {\r
+    int y;\r
+    char *tmp;\r
+\r
+    tmp=rfiles[x];              // Save pointer.\r
+    for(y=x;y;y--)\r
+     rfiles[y]=rfiles[y-1];     // Move items down.\r
+\r
+    rfiles[0]=tmp;              // Put item on top.\r
+    UpdateRMenu();\r
+    return;\r
+   }\r
+\r
+ if(rfiles[9]) free(rfiles[9]);\r
+ for(x=9;x;x--) rfiles[x]=rfiles[x-1];\r
+ rfiles[0]=malloc(strlen(fn)+1);\r
+ strcpy(rfiles[0],fn);\r
+ UpdateRMenu();\r
+}\r
+\r
+void HideMenu(int h)\r
+{\r
+  if(h)\r
+  {\r
+   SetMenu(hAppWnd,0);   \r
+  }\r
+  else\r
+  {\r
+   SetMenu(hAppWnd,fceumenu);\r
+  }\r
+}\r
+\r
+static LONG WindowXC=1<<30,WindowYC;\r
+void HideFWindow(int h)\r
+{\r
+ LONG desa;\r
+\r
+ if(h)\r
+ {\r
+   RECT bo;\r
+   GetWindowRect(hAppWnd,&bo);\r
+   WindowXC=bo.left;\r
+   WindowYC=bo.top;\r
+\r
+   SetMenu(hAppWnd,0);\r
+   desa=WS_POPUP|WS_CLIPSIBLINGS;\r
+ }\r
+ else\r
+ {\r
+   desa=WS_OVERLAPPEDWINDOW|WS_CLIPSIBLINGS;\r
+   HideMenu(tog);\r
+ }\r
\r
+ SetWindowLong(hAppWnd,GWL_STYLE,desa|(GetWindowLong(hAppWnd,GWL_STYLE)&WS_VISIBLE));\r
+ SetWindowPos(hAppWnd,0,0,0,0,0,SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOREPOSITION|SWP_NOSIZE|SWP_NOZORDER);\r
+}\r
+\r
+void ToggleHideMenu(void)\r
+{ \r
+ if(!fullscreen)\r
+ {\r
+  tog^=1;\r
+  HideMenu(tog);\r
+  SetMainWindowStuff();\r
+ }\r
+}\r
+\r
+static void ALoad(char *nameo)\r
+{\r
+  if((GI=FCEUI_LoadGame(nameo)))\r
+  {\r
+   FixFL();\r
+   FixGIGO();\r
+   SetMainWindowStuff();\r
+   AddRecent(nameo);\r
+   RefreshThrottleFPS();\r
+   if(eoptions&EO_FSAFTERLOAD)\r
+    SetFSVideoMode();\r
+  }\r
+  else\r
+   StopSound();\r
+}\r
+\r
+void LoadNewGamey(HWND hParent)\r
+{\r
+ const char filter[]="All usable files(*.nes,*.nsf,*.fds,*.unf,*.zip,*.gz)\0*.nes;*.nsf;*.fds;*.unf;*.zip;*.gz\0All non-compressed usable files(*.nes,*.nsf,*.fds,*.unf)\0*.nes;*.nsf;*.fds;*.unf\0All files (*.*)\0*.*\0";\r
+ char nameo[2048];\r
+ OPENFILENAME ofn;\r
+ memset(&ofn,0,sizeof(ofn));\r
+ ofn.lStructSize=sizeof(ofn);\r
+ ofn.hInstance=fceu_hInstance;\r
+ ofn.lpstrTitle="FCE Ultra Open File...";\r
+ ofn.lpstrFilter=filter;\r
+ nameo[0]=0;\r
+ ofn.hwndOwner=hParent;\r
+ ofn.lpstrFile=nameo;\r
+ ofn.nMaxFile=256;\r
+ ofn.Flags=OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY; //OFN_EXPLORER|OFN_ENABLETEMPLATE|OFN_ENABLEHOOK;\r
+ ofn.lpstrInitialDir=gfsdir;\r
+ if(GetOpenFileName(&ofn))\r
+ {\r
+  if(gfsdir) free(gfsdir);\r
+  if((gfsdir=malloc(ofn.nFileOffset+1)))\r
+  {\r
+   strncpy(gfsdir,ofn.lpstrFile,ofn.nFileOffset);\r
+   gfsdir[ofn.nFileOffset]=0;\r
+  }\r
+  ALoad(nameo);\r
+ }\r
+}\r
+\r
+static uint32 mousex,mousey,mouseb;\r
+void GetMouseData(uint32 *x, uint32 *y, uint32 *b)\r
+{\r
+ *x=mousex;\r
+ *y=mousey;\r
+ if(!fullscreen)\r
+ {\r
+  if(eoptions&EO_USERFORCE)\r
+  {\r
+   RECT t;\r
+   GetClientRect(hAppWnd,&t);\r
+\r
+   *x=*x*VNSWID/(t.right?t.right:1);\r
+   *y=*y*totallines/(t.bottom?t.bottom:1);\r
+  }\r
+  else\r
+  {\r
+   *x/=winsizemul;\r
+   *y/=winsizemul;\r
+  }\r
+  *x+=VNSCLIP;\r
+ }\r
+\r
+ *y+=srendline;\r
+ *b=((mouseb==MK_LBUTTON)?1:0)|((mouseb==MK_RBUTTON)?2:0);\r
+}\r
+\r
+static int sizchange=0;\r
+static int vchanged=0;\r
+\r
+LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)\r
+{\r
+  switch(msg) {   \r
+    case WM_LBUTTONDOWN:\r
+    case WM_LBUTTONUP:\r
+    case WM_RBUTTONDOWN:\r
+    case WM_RBUTTONUP:\r
+                  mouseb=wParam;\r
+                  goto proco;\r
+    case WM_MOUSEMOVE:\r
+                  {\r
+                   mousex=LOWORD(lParam);\r
+                   mousey=HIWORD(lParam);\r
+                  }\r
+                  goto proco;\r
+    case WM_SIZING:\r
+                 sizchange=1;\r
+                 goto proco;\r
+    case WM_DISPLAYCHANGE:\r
+                if(!fullscreen && !changerecursive)\r
+                 vchanged=1;\r
+                goto proco;\r
+    case WM_DROPFILES:\r
+                {\r
+                 UINT len;\r
+                 char *ftmp;\r
+\r
+                 len=DragQueryFile((HANDLE)wParam,0,0,0)+1;\r
+                 if((ftmp=malloc(len)))\r
+                 {\r
+                  DragQueryFile((HANDLE)wParam,0,ftmp,len);\r
+                  ALoad(ftmp);\r
+                  free(ftmp);\r
+                 }                 \r
+                }\r
+                break;\r
+    case WM_COMMAND:\r
+                if(!(wParam>>16))\r
+                {\r
+                 wParam&=0xFFFF;\r
+                 if(wParam>=600 && wParam<=609)\r
+                 {\r
+                  if(rfiles[wParam-600]) ALoad(rfiles[wParam-600]);\r
+                 }\r
+                 switch(wParam)\r
+                 {\r
+                  case 300:ToggleHideMenu();break;\r
+                  case 301:eoptions^=EO_BGRUN;UpdateMenu();break;\r
+\r
+                  case 310:genie^=1;FCEUI_SetGameGenie(genie);UpdateMenu();break;\r
+                  case 311:palyo^=1;\r
+                           FCEUI_SetVidSystem(palyo);\r
+                           RefreshThrottleFPS();\r
+                           UpdateMenu();\r
+                           FixFL();\r
+                           SetMainWindowStuff();\r
+                           break;\r
+\r
+                  case 320:StopSound();ConfigDirectories();break;\r
+                  case 321:StopSound();ConfigInput(hWnd);break;\r
+                  case 322:ConfigMisc();break;\r
+                  case 323:StopSound();ConfigNetplay();break;\r
+                  case 324:StopSound();ConfigPalette();break;\r
+                  case 325:StopSound();ConfigSound();break;\r
+                  case 326:ConfigVideo();break;\r
+\r
+                  case 200:DriverInterface(DES_RESET,0);break;\r
+                  case 201:DriverInterface(DES_POWER,0);break;\r
+                  case 202:ConfigCheats(hWnd);break;\r
+\r
+                  case 100:StopSound();\r
+                           LoadNewGamey(hWnd);\r
+                           break;\r
+                  case 101:if(GI)\r
+                           {\r
+                            FCEUI_CloseGame();                            \r
+                            GI=0;\r
+                           }\r
+                           break;\r
+                  case 110:FCEUI_SaveState();break;\r
+                  case 111:FCEUI_LoadState();break;\r
+\r
+                  case 120:\r
+                           {\r
+                            MENUITEMINFO mi;\r
+                            char *str;\r
+             \r
+                            StopSound();\r
+                            if(CreateSoundSave())\r
+                             str="Stop Sound Logging";\r
+                            else\r
+                             str="Log Sound As...";\r
+                            memset(&mi,0,sizeof(mi));\r
+                            mi.fMask=MIIM_DATA|MIIM_TYPE;\r
+                            mi.cbSize=sizeof(mi);\r
+                            GetMenuItemInfo(fceumenu,120,0,&mi);                           \r
+                            mi.fMask=MIIM_DATA|MIIM_TYPE;\r
+                            mi.cbSize=sizeof(mi);\r
+                            mi.dwTypeData=str;\r
+                            mi.cch=strlen(str);\r
+                            SetMenuItemInfo(fceumenu,120,0,&mi);\r
+                           }\r
+                           break;\r
+                  case 130:DoFCEUExit();break;\r
+\r
+                  case 400:StopSound();ShowAboutBox();break;\r
+                 }              \r
+                }\r
+                break;\r
+\r
+\r
+    case WM_SYSCOMMAND:\r
+               if(wParam==SC_KEYMENU)\r
+                if(GI && InputTypeFC==SIFC_FKB && cidisabled)\r
+                 break;\r
+               goto proco;\r
+    case WM_SYSKEYDOWN:\r
+               if(GI && InputTypeFC==SIFC_FKB && cidisabled)\r
+                break; /* Hopefully this won't break DInput... */\r
+\r
+               if(fullscreen || tog)\r
+               {\r
+                if(wParam==VK_MENU)\r
+                 break;\r
+               }\r
+               if(wParam==VK_F10)\r
+               {\r
+                if(!(lParam&0x40000000))\r
+                 DriverInterface(DES_RESET,0);\r
+                break;\r
+               }\r
+               goto proco;\r
+\r
+    case WM_KEYDOWN:\r
+              if(GI)\r
+             {\r
+              /* Only disable command keys if a game is loaded(and the other\r
+                 conditions are right, of course). */\r
+               if(InputTypeFC==SIFC_FKB)\r
+              {\r
+               if(wParam==VK_SCROLL)\r
+               {\r
+                cidisabled^=1;\r
+                FCEUI_DispMessage("Family Keyboard %sabled.",cidisabled?"en":"dis");\r
+               }\r
+               if(cidisabled)\r
+                 break; /* Hopefully this won't break DInput... */\r
+              }\r
+               if(GI->type==GIT_NSF)\r
+                switch(wParam)\r
+                {\r
+                 case VK_UP:DriverInterface(DES_NSFINC,0);break;\r
+                 case VK_DOWN:DriverInterface(DES_NSFDEC,0);break;\r
+                 case VK_RETURN:DriverInterface(DES_NSFRES,0);break;\r
+\r
+                 case VK_LEFT:if(!(lParam&0x40000000))\r
+                               DriverInterface(DES_NSFDEC,0); break;\r
+                 case VK_RIGHT:if(!(lParam&0x40000000))\r
+                                DriverInterface(DES_NSFINC,0); break;\r
+                }\r
+\r
+              }\r
+               if(!(lParam&0x40000000))\r
+                switch( wParam )\r
+                {\r
+                  case VK_F11:DriverInterface(DES_POWER,0);break;\r
+                  case VK_F12:DoFCEUExit();break;\r
+                  case VK_F2:userpause^=1;break;\r
+                  case VK_F3:ToggleHideMenu();break;\r
+                  case VK_F4:       UpdateMenu();\r
+                                    changerecursive=1;\r
+                                    if(!SetVideoMode(fullscreen^1))\r
+                                     SetVideoMode(fullscreen);\r
+                                    changerecursive=0;\r
+                                    break;\r
+                }\r
+                goto proco;\r
+\r
+\r
+    case WM_NCRBUTTONDOWN:\r
+    case WM_NCMBUTTONDOWN:StopSound();goto proco;\r
+    case WM_NCLBUTTONDOWN:StopSound();goto proco;\r
+\r
+    case WM_ENTERMENULOOP:StopSound();goto proco;\r
+    case WM_CLOSE:\r
+    case WM_DESTROY:\r
+    case WM_QUIT:DoFCEUExit();break;\r
+    case WM_ACTIVATEAPP:       \r
+       if((BOOL)wParam)\r
+       {\r
+        nofocus=0;\r
+       }\r
+       else\r
+       {\r
+        nofocus=1;\r
+       }\r
+    default:\r
+      proco:\r
+      return DefWindowProc(hWnd,msg,wParam,lParam);\r
+   }\r
+  return 0;\r
+}\r
+\r
+void UpdateFCEUWindow(void)\r
+{\r
+  int w,h;\r
+  RECT wrect;\r
+\r
+  if(vchanged && !fullscreen && !changerecursive && !nofocus)\r
+  {\r
+   SetVideoMode(0);\r
+   vchanged=0;\r
+  }\r
+\r
+  if(sizchange && !fullscreen && !(eoptions&EO_USERFORCE))\r
+  {      \r
+   GetWindowRect(hAppWnd,&wrect);\r
+   h=wrect.bottom-wrect.top;\r
+   w=wrect.right-wrect.left;\r
+   if(w!=winwidth)\r
+    winsizemul=(w-(winwidth-VNSWID*winsizemul)+(VNSWID>>1))>>8;\r
+   else\r
+   if(h!=winheight)\r
+    winsizemul=(h-(winheight-totallines*winsizemul)+(totallines>>1))>>8;\r
+\r
+   if(winsizemul<1)\r
+    winsizemul=1;\r
+   SetMainWindowStuff();\r
+  }\r
+  sizchange=0;\r
+\r
+  BlockingCheck();\r
+}\r
+\r
+void ByebyeWindow(void)\r
+{\r
+ SetMenu(hAppWnd,0);\r
+ DestroyMenu(fceumenu);\r
+ DestroyWindow(hAppWnd);\r
+}\r
+\r
+int CreateMainWindow(void)\r
+{\r
+  WNDCLASSEX winclass;\r
+  RECT tmp;\r
+\r
+  memset(&winclass,0,sizeof(winclass));\r
+  winclass.cbSize=sizeof(WNDCLASSEX);\r
+  winclass.style=CS_OWNDC|CS_HREDRAW|CS_VREDRAW|CS_SAVEBITS;\r
+  winclass.lpfnWndProc=AppWndProc;\r
+  winclass.cbClsExtra=0;\r
+  winclass.cbWndExtra=0;\r
+  winclass.hInstance=fceu_hInstance;\r
+  winclass.hIcon=LoadIcon(fceu_hInstance, "ICON_1");\r
+  winclass.hIconSm=LoadIcon(fceu_hInstance, "ICON_1");\r
+  winclass.hCursor=LoadCursor(NULL, IDC_ARROW);\r
+  winclass.hbrBackground=GetStockObject(BLACK_BRUSH);\r
+  //winclass.lpszMenuName="FCEUMENU";\r
+  winclass.lpszClassName="FCEULTRA";\r
+\r
+  if(!RegisterClassEx(&winclass))\r
+    return FALSE;\r
+\r
+  AdjustWindowRectEx(&tmp,WS_OVERLAPPEDWINDOW,1,0);\r
+\r
+  fceumenu=LoadMenu(fceu_hInstance,"FCEUMENU");\r
+  recentmenu=CreateMenu();\r
+  UpdateRMenu();\r
+\r
+  hAppWnd = CreateWindowEx(0,"FCEULTRA","FCE Ultra",\r
+                        WS_OVERLAPPEDWINDOW|WS_CLIPSIBLINGS,  /* Style */\r
+                        CW_USEDEFAULT,CW_USEDEFAULT,256,240,  /* X,Y ; Width, Height */\r
+                        NULL,fceumenu,fceu_hInstance,NULL );  \r
+  DragAcceptFiles(hAppWnd, 1);\r
+  SetMainWindowStuff();\r
+  return 1;\r
+}\r
+\r
+\r
+int SetMainWindowStuff(void)\r
+{\r
+  RECT *srect;\r
+  RECT tmp;\r
+\r
+  GetWindowRect(hAppWnd,&tmp);\r
+\r
+  if(WindowXC!=(1<<30))\r
+  {\r
+   /* Subtracting and adding for if(eoptions&EO_USERFORCE) below. */\r
+   tmp.bottom-=tmp.top;\r
+   tmp.bottom+=WindowYC;\r
+\r
+   tmp.right-=tmp.left;\r
+   tmp.right+=WindowXC;\r
+   \r
+\r
+   tmp.left=WindowXC;\r
+   tmp.top=WindowYC;\r
+   WindowXC=1<<30;\r
+  }\r
+\r
+  if(eoptions&EO_USERFORCE)\r
+  {\r
+   SetWindowPos(hAppWnd,HWND_TOP,tmp.left,tmp.top,0,0,SWP_NOSIZE|SWP_SHOWWINDOW);\r
+   winwidth=tmp.right-tmp.left;\r
+   winheight=tmp.bottom-tmp.top;\r
+  }\r
+  else\r
+  {\r
+   srect=CalcWindowSize();\r
+   SetWindowPos(hAppWnd,HWND_TOP,tmp.left,tmp.top,srect->right,srect->bottom,SWP_SHOWWINDOW);\r
+   winwidth=srect->right;\r
+   winheight=srect->bottom;\r
+  }\r
+\r
+\r
+  ShowWindow(hAppWnd, SW_SHOWNORMAL);\r
+  return 1;\r
+}\r
+\r
+int GetClientAbsRect(LPRECT lpRect)\r
+{\r
+  POINT point;\r
+  point.x=point.y=0;\r
+  if(!ClientToScreen(hAppWnd,&point)) return 0;\r
+\r
+  lpRect->top=point.y;\r
+  lpRect->left=point.x;\r
+\r
+  if(eoptions&EO_USERFORCE)\r
+  {\r
+   RECT al;\r
+\r
+   GetClientRect(hAppWnd,&al);\r
+\r
+   lpRect->right=point.x+al.right;\r
+   lpRect->bottom=point.y+al.bottom;\r
+  }\r
+  else\r
+  {\r
+   lpRect->right=point.x+VNSWID*winsizemul;\r
+   lpRect->bottom=point.y+totallines*winsizemul;\r
+  }\r
+  return 1;\r
+}\r
+\r
+\r
+void LoadPaletteFile(void)\r
+{\r
+ FILE *fp;\r
+ const char filter[]="All usable files(*.pal)\0*.pal\0All files (*.*)\0*.*\0";\r
+ char nameo[2048];\r
+ OPENFILENAME ofn;\r
+ memset(&ofn,0,sizeof(ofn));\r
+ ofn.lStructSize=sizeof(ofn);\r
+ ofn.hInstance=fceu_hInstance;\r
+ ofn.lpstrTitle="FCE Ultra Open Palette File...";\r
+ ofn.lpstrFilter=filter;\r
+ nameo[0]=0;\r
+ ofn.lpstrFile=nameo;\r
+ ofn.nMaxFile=256;\r
+ ofn.Flags=OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;\r
+ ofn.lpstrInitialDir=0;\r
+ if(GetOpenFileName(&ofn))\r
+ {\r
+  if((fp=fopen(nameo,"rb")))\r
+  {\r
+   fread(cpalette,1,192,fp);\r
+   fclose(fp);\r
+   FCEUI_SetPaletteArray(cpalette);\r
+   eoptions|=EO_CPALETTE;\r
+  }\r
+  else\r
+   FCEUD_PrintError("Error opening palette file!");\r
+ }\r
+}\r
+\r
+BOOL CALLBACK PaletteConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+  switch(uMsg) {\r
+   case WM_INITDIALOG:                \r
+                if(ntsccol)\r
+                 CheckDlgButton(hwndDlg,100,BST_CHECKED);\r
+                SendDlgItemMessage(hwndDlg,500,TBM_SETRANGE,1,MAKELONG(0,128));\r
+                SendDlgItemMessage(hwndDlg,501,TBM_SETRANGE,1,MAKELONG(0,128));\r
+                DriverInterface(DES_GETNTSCTINT,&ntsctint);\r
+                DriverInterface(DES_GETNTSCHUE,&ntschue);\r
+                SendDlgItemMessage(hwndDlg,500,TBM_SETPOS,1,ntsctint);\r
+                SendDlgItemMessage(hwndDlg,501,TBM_SETPOS,1,ntschue);\r
+                break;\r
+   case WM_CLOSE:\r
+   case WM_QUIT: goto gornk;\r
+   case WM_COMMAND:\r
+                if(!(wParam>>16))\r
+                switch(wParam&0xFFFF)\r
+                {\r
+                 case 100:ntsccol^=1;DriverInterface(DES_NTSCCOL,&ntsccol);break;\r
+                 case 200:\r
+                          LoadPaletteFile();\r
+                          break;\r
+                 case 201:FCEUI_SetPaletteArray(0);\r
+                          eoptions&=~EO_CPALETTE;\r
+                          break;\r
+                 case 1:\r
+                        gornk:\r
+                        ntsctint=SendDlgItemMessage(hwndDlg,500,TBM_GETPOS,0,(LPARAM)(LPSTR)0);\r
+                        ntschue=SendDlgItemMessage(hwndDlg,501,TBM_GETPOS,0,(LPARAM)(LPSTR)0);\r
+                        EndDialog(hwndDlg,0);\r
+                        break;\r
+               }\r
+              }\r
+  return 0;\r
+}\r
+\r
+static void ConfigPalette(void)\r
+{\r
+  DialogBox(fceu_hInstance,"PALCONFIG",hAppWnd,PaletteConCallB);\r
+  DriverInterface(DES_SETNTSCTINT,&ntsctint);\r
+  DriverInterface(DES_SETNTSCHUE,&ntschue);\r
+}\r
+\r
+\r
+static BOOL CALLBACK MiscConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+  switch(uMsg) {\r
+   case WM_INITDIALOG:                \r
+                if(eoptions&EO_NOSPRLIM)\r
+                 CheckDlgButton(hwndDlg,100,BST_CHECKED);\r
+                if(eoptions&EO_FOAFTERSTART)\r
+                 CheckDlgButton(hwndDlg,102,BST_CHECKED);\r
+                if(eoptions&EO_SNAPNAME)\r
+                 CheckDlgButton(hwndDlg,103,BST_CHECKED);\r
+                if(eoptions&EO_NOTHROTTLE)\r
+                 CheckDlgButton(hwndDlg,101,BST_CHECKED);\r
+                break;\r
+   case WM_CLOSE:\r
+   case WM_QUIT: goto gornk;\r
+   case WM_COMMAND:\r
+                if(!(wParam>>16))\r
+                switch(wParam&0xFFFF)\r
+                {\r
+                 case 1:\r
+                        gornk:\r
+                        if(IsDlgButtonChecked(hwndDlg,100)==BST_CHECKED)\r
+                         eoptions|=EO_NOSPRLIM;\r
+                        else\r
+                         eoptions&=~EO_NOSPRLIM;\r
+                        if(IsDlgButtonChecked(hwndDlg,102)==BST_CHECKED)\r
+                         eoptions|=EO_FOAFTERSTART;\r
+                        else\r
+                         eoptions&=~EO_FOAFTERSTART;\r
+                        if(IsDlgButtonChecked(hwndDlg,103)==BST_CHECKED)\r
+                         eoptions|=EO_SNAPNAME;\r
+                        else\r
+                         eoptions&=~EO_SNAPNAME;\r
+                        if(IsDlgButtonChecked(hwndDlg,101)==BST_CHECKED)\r
+                         eoptions|=EO_NOTHROTTLE;\r
+                        else\r
+                         eoptions&=~EO_NOTHROTTLE;\r
+                        EndDialog(hwndDlg,0);\r
+                        break;\r
+               }\r
+              }\r
+  return 0;\r
+}\r
+\r
+void DoMiscConfigFix(void)\r
+{\r
+  FCEUI_DisableSpriteLimitation(eoptions&EO_NOSPRLIM);\r
+  FCEUI_SetSnapName(eoptions&EO_SNAPNAME);\r
+}\r
+\r
+static void ConfigMisc(void)\r
+{\r
+  DialogBox(fceu_hInstance,"MISCCONFIG",hAppWnd,MiscConCallB);  \r
+  DoMiscConfigFix();\r
+}\r
+\r
+static int BrowseForFolder(HWND hParent, char *htext, char *buf)\r
+{\r
+ BROWSEINFO bi;\r
+ LPCITEMIDLIST pidl;\r
+ int ret=1;\r
+\r
+ buf[0]=0;\r
+\r
+ memset(&bi,0,sizeof(bi));\r
+                \r
+ bi.hwndOwner=hParent;\r
+ bi.lpszTitle=htext;\r
+ bi.ulFlags=BIF_RETURNONLYFSDIRS; \r
+\r
+ if(FAILED(CoInitialize(0)))\r
+  return(0);\r
+\r
+ if(!(pidl=SHBrowseForFolder(&bi)))\r
+ {\r
+  ret=0;\r
+  goto end1;\r
+ }\r
+\r
+ if(!SHGetPathFromIDList(pidl,buf))\r
+ {\r
+  ret=0;\r
+  goto end2;\r
+ }\r
+\r
+ end2:\r
+ /* This probably isn't the best way to free the memory... */\r
+ CoTaskMemFree((PVOID)pidl);\r
+\r
+ end1:\r
+ CoUninitialize();\r
+ return(ret);\r
+}\r
+\r
+static BOOL CALLBACK DirConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+  int x;\r
+\r
+  switch(uMsg){\r
+   case WM_INITDIALOG:                \r
+                for(x=0;x<6;x++)\r
+                 SetDlgItemText(hwndDlg,100+x,DOvers[x]);\r
+\r
+                if(eoptions&EO_BSAV)\r
+                 CheckDlgButton(hwndDlg,300,BST_CHECKED);\r
+                break;\r
+   case WM_CLOSE:\r
+   case WM_QUIT: goto gornk;\r
+   case WM_COMMAND:\r
+                if(!(wParam>>16))\r
+                {\r
+                 if((wParam&0xFFFF)>=200 && (wParam&0xFFFF)<=205)\r
+                 {\r
+                  static char *helpert[6]={"Cheats","Miscellaneous","Nonvolatile Game Data","Save States","Screen Snapshots","Base Directory"};\r
+                  char name[MAX_PATH];\r
+\r
+                  if(BrowseForFolder(hwndDlg,helpert[((wParam&0xFFFF)-200)],name))\r
+                   SetDlgItemText(hwndDlg,100+((wParam&0xFFFF)-200),name);\r
+                 }\r
+                 else switch(wParam&0xFFFF)\r
+                 {\r
+                  case 1:\r
+                        gornk:\r
+\r
+                        RemoveDirs();   // Remove empty directories.\r
+\r
+                        for(x=0;x<6;x++)\r
+                        {\r
+                         LONG len;\r
+                         len=SendDlgItemMessage(hwndDlg,100+x,WM_GETTEXTLENGTH,0,0);\r
+                         if(len<=0)\r
+                         {\r
+                          if(DOvers[x]) free(DOvers[x]);\r
+                          DOvers[x]=0;\r
+                          continue;\r
+                         }\r
+                         len++; // Add 1 for null character.\r
+                         if(!(DOvers[x]=malloc(len)))\r
+                          continue;\r
+                         if(!GetDlgItemText(hwndDlg,100+x,DOvers[x],len))\r
+                         {\r
+                          free(DOvers[x]);\r
+                          DOvers[x]=0;\r
+                          continue;\r
+                         }\r
+\r
+                        }\r
+                        if(IsDlgButtonChecked(hwndDlg,300)==BST_CHECKED)\r
+                         eoptions|=EO_BSAV;\r
+                        else\r
+                         eoptions&=~EO_BSAV;\r
+\r
+                        CreateDirs();   // Create needed directories.\r
+                        SetDirs();      // Set the directories in the core.\r
+                        EndDialog(hwndDlg,0);\r
+                        break;\r
+                 }\r
+                }\r
+              }\r
+  return 0;\r
+}\r
+\r
+\r
+\r
+static void ConfigDirectories(void)\r
+{\r
+  DialogBox(fceu_hInstance,"DIRCONFIG",hAppWnd,DirConCallB);\r
+}\r
diff --git a/endian.c b/endian.c
new file mode 100644 (file)
index 0000000..8cd5b70
--- /dev/null
+++ b/endian.c
@@ -0,0 +1,71 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+/*     Contains file I/O functions that write/read data    */
+/*     LSB first.                                          */
+
+
+#include <stdio.h>
+#include "types.h"
+#include "endian.h"
+
+static uint8 s[4];
+
+int write16(uint16 b, FILE *fp)
+{
+ s[0]=b;
+ s[1]=b>>8;
+ return((fwrite(s,1,2,fp)<2)?0:2);
+}
+
+int write32(uint32 b, FILE *fp)
+{
+ s[0]=b;
+ s[1]=b>>8;
+ s[2]=b>>16;
+ s[3]=b>>24;
+ return((fwrite(s,1,4,fp)<4)?0:4);
+}
+
+int read32(void *Bufo, FILE *fp)
+{
+ uint32 buf;
+ if(fread(&buf,1,4,fp)<4)
+  return 0;
+ #ifdef LSB_FIRST
+ *(uint32*)Bufo=buf;
+ #else
+ *(uint32*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24);
+ #endif
+ return 1;
+}
+
+int read16(char *d, FILE *fp)
+{
+ #ifdef LSB_FIRST
+ return((fread(d,1,2,fp)<2)?0:2);
+ #else
+ int ret;
+ ret=fread(d+1,1,1,fp);
+ ret+=fread(d,1,1,fp);
+ return ret<2?0:2;
+ #endif
+}
+
diff --git a/endian.h b/endian.h
new file mode 100644 (file)
index 0000000..23ee4ed
--- /dev/null
+++ b/endian.h
@@ -0,0 +1,3 @@
+int write16(uint16 b, FILE *fp);
+int write32(uint32 b, FILE *fp);
+int read32(void *Bufo, FILE *fp);
diff --git a/fce.c b/fce.c
new file mode 100644 (file)
index 0000000..653a3f6
--- /dev/null
+++ b/fce.c
@@ -0,0 +1,1565 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 BERO 
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include        <string.h>
+#include       <stdio.h>
+#include       <stdlib.h>
+
+#include       "types.h"
+#include       "x6502.h"
+#include       "fce.h"
+#include       "sound.h"
+#include        "svga.h"
+#include       "netplay.h"
+#include       "general.h"
+#include       "endian.h"
+#include       "version.h"
+#include        "memory.h"
+
+#include       "cart.h"
+#include       "nsf.h"
+#include       "fds.h"
+#include       "ines.h"
+#include       "unif.h"
+#include        "cheat.h"
+
+#include       "state.h"
+#include        "video.h"
+#include       "input.h"
+#include       "file.h"
+#include       "crc32.h"
+
+#define Pal     (PALRAM)
+
+static void FetchSpriteData(void);
+static void FASTAPASS(1) RefreshLine(uint8 *target);
+static void PRefreshLine(void);
+static void FASTAPASS(1) RefreshSprite(uint8 *target);
+static void ResetPPU(void);
+static void PowerPPU(void);
+
+uint64 timestampbase=0;
+
+int MMC5Hack;
+uint32 MMC5HackVROMMask;
+uint8 *MMC5HackExNTARAMPtr;
+uint8 *MMC5HackVROMPTR;
+uint8 MMC5HackCHRMode=0; 
+uint8 MMC5HackSPMode;
+uint8 MMC5HackSPScroll;
+uint8 MMC5HackSPPage;
+
+uint8 *MMC5SPRVPage[8];
+uint8 *MMC5BGVPage[8];
+
+
+uint8 VRAMBuffer,PPUGenLatch;
+
+uint8 *vnapage[4];
+uint8 PPUNTARAM;
+uint8 PPUCHRRAM;
+
+/* Color deemphasis emulation.  Joy... */
+static uint8 deemp=0;
+static int deempcnt[8];
+
+static int tosprite=256;
+
+FCEUGI FCEUGameInfo;
+void (*GameInterface)(int h);
+
+void FP_FASTAPASS(1) (*PPU_hook)(uint32 A);
+
+void (*GameStateRestore)(int version);
+void (*GameHBIRQHook)(void);
+
+readfunc ARead[0x10000];
+writefunc BWrite[0x10000];
+static readfunc *AReadG;
+static writefunc *BWriteG;
+static int RWWrap=0;
+
+DECLFW(BNull)
+{
+
+}
+
+DECLFR(ANull)
+{
+ return(X.DB);
+}
+
+int AllocGenieRW(void)
+{
+ if(!(AReadG=FCEU_malloc(0x8000*sizeof(readfunc))))
+  return 0;
+ if(!(BWriteG=FCEU_malloc(0x8000*sizeof(writefunc))))
+  return 0;
+ RWWrap=1;
+ return 1;
+}
+
+void FlushGenieRW(void)
+{
+ int32 x;
+
+ if(RWWrap)
+ {
+  for(x=0;x<0x8000;x++)
+  {
+   ARead[x+0x8000]=AReadG[x];
+   BWrite[x+0x8000]=BWriteG[x];
+  }
+  free(AReadG);
+  free(BWriteG);
+  AReadG=0;
+  BWriteG=0;
+  RWWrap=0;
+ }
+}
+
+readfunc FASTAPASS(1) GetReadHandler(int32 a)
+{
+  if(a>=0x8000 && RWWrap)
+   return AReadG[a-0x8000];
+  else
+   return ARead[a];
+}
+
+void FASTAPASS(3) SetReadHandler(int32 start, int32 end, readfunc func)
+{
+  int32 x;
+
+  if(!func)
+   func=ANull;
+
+  if(RWWrap)
+   for(x=end;x>=start;x--)
+   {
+    if(x>=0x8000)
+     AReadG[x-0x8000]=func;
+    else
+     ARead[x]=func;
+   }
+  else
+
+   for(x=end;x>=start;x--)
+    ARead[x]=func;
+}
+
+writefunc FASTAPASS(1) GetWriteHandler(int32 a)
+{
+  if(RWWrap && a>=0x8000)
+   return BWriteG[a-0x8000];
+  else
+   return BWrite[a];
+}
+
+void FASTAPASS(3) SetWriteHandler(int32 start, int32 end, writefunc func)
+{
+  int32 x;
+
+  if(!func)
+   func=BNull;
+
+  if(RWWrap)
+   for(x=end;x>=start;x--)
+   {
+    if(x>=0x8000)
+     BWriteG[x-0x8000]=func;
+    else
+     BWrite[x]=func;
+   }
+  else
+   for(x=end;x>=start;x--)
+    BWrite[x]=func;
+}
+
+uint8 vtoggle=0;
+uint8 XOffset=0;
+
+uint32 TempAddr,RefreshAddr;
+
+static int maxsprites=8;
+
+/* scanline is equal to the current visible scanline we're on. */
+
+int scanline;
+static uint32 scanlines_per_frame;
+
+uint8 PPU[4];
+uint8 PPUSPL;
+
+uint8 GameMemBlock[131072];
+uint8 NTARAM[0x800],PALRAM[0x20],SPRAM[0x100],SPRBUF[0x100];
+uint8 RAM[0x800];
+
+uint8 PAL=0;
+
+#define MMC5SPRVRAMADR(V)      &MMC5SPRVPage[(V)>>10][(V)]
+#define MMC5BGVRAMADR(V)      &MMC5BGVPage[(V)>>10][(V)]
+#define        VRAMADR(V)      &VPage[(V)>>10][(V)]
+static DECLFW(BRAML)
+{  
+        RAM[A]=V;
+}
+
+static DECLFW(BRAMH)
+{
+        RAM[A&0x7FF]=V;
+}
+
+static DECLFR(ARAML)
+{
+        return RAM[A];
+}
+
+static DECLFR(ARAMH)
+{
+        return RAM[A&0x7FF];
+}
+
+           
+static DECLFR(A2002)
+{
+                        uint8 ret;
+                        ret = PPU_status;
+                        vtoggle=0;
+                        PPU_status&=0x7F;
+                        return ret|(PPUGenLatch&0x1F);
+}
+
+static DECLFR(A200x)
+{
+                        return PPUGenLatch;
+}
+
+static DECLFR(A2007)
+{
+                        uint8 ret;
+                       uint32 tmp=RefreshAddr&0x3FFF;
+
+                        PPUGenLatch=ret=VRAMBuffer;
+                       if(PPU_hook) PPU_hook(tmp);
+                        if(tmp<0x2000) 
+                       {
+                        VRAMBuffer=VPage[tmp>>10][tmp];
+                       }
+                        else 
+                       {
+                        VRAMBuffer=vnapage[(tmp>>10)&0x3][tmp&0x3FF];
+                       }
+
+                        if (INC32) RefreshAddr+=32;
+                        else RefreshAddr++;
+                       if(PPU_hook) PPU_hook(RefreshAddr&0x3fff);
+                        return ret;
+}
+
+static DECLFW(B2000)
+{
+                PPUGenLatch=V;
+                PPU[0]=V;
+               TempAddr&=0xF3FF;
+               TempAddr|=(V&3)<<10;
+}
+
+static DECLFW(B2001)
+{
+                  PPUGenLatch=V;
+                 PPU[1]=V;
+                 if(V&0xE0)
+                  deemp=V>>5;
+                 //printf("$%04x:$%02x, %d\n",X.PC,V,scanline);
+}
+
+static DECLFW(B2002)
+{
+                 PPUGenLatch=V;
+}
+
+static DECLFW(B2003)
+{
+                PPUGenLatch=V;
+                PPU[3]=V;
+               PPUSPL=V&0x7;
+}
+
+static DECLFW(B2004)
+{
+                PPUGenLatch=V;
+                //SPRAM[PPU[3]++]=V;
+               if(PPUSPL&8)
+               {
+                if(PPU[3]>=8)
+                 SPRAM[PPU[3]]=V;
+               }
+               else
+               {
+                //printf("$%02x:$%02x\n",PPUSPL,V);
+                SPRAM[PPUSPL]=V;
+                PPUSPL++;
+               }
+               PPU[3]++;
+}
+
+static DECLFW(B2005)
+{
+               uint32 tmp=TempAddr;
+
+               PPUGenLatch=V;
+               if (!vtoggle)
+                {
+                tmp&=0xFFE0;
+                tmp|=V>>3;
+                 XOffset=V&7;
+                }
+                else
+                {
+                 tmp&=0x8C1F;
+                 tmp|=((V&~0x7)<<2);
+                tmp|=(V&7)<<12;
+                }
+
+               TempAddr=tmp;
+                vtoggle^=1;
+}
+
+static DECLFW(B2006)
+{
+                       PPUGenLatch=V;
+                       if(!vtoggle)
+                       {
+                       TempAddr&=0x00FF;
+                        TempAddr|=(V&0x3f)<<8;
+                       }
+                       else
+                       {
+                       TempAddr&=0xFF00;
+                       TempAddr|=V;
+                        RefreshAddr=TempAddr;
+
+                       if(PPU_hook)
+                        PPU_hook(RefreshAddr);
+                       }
+                      vtoggle^=1;
+}
+
+static DECLFW(B2007)
+{  
+                       uint32 tmp=RefreshAddr&0x3FFF;
+
+                        PPUGenLatch=V;
+                        if(tmp>=0x3F00)
+                        {
+                        // hmmm....
+                        if(!(tmp&0xf))
+                         PALRAM[0x00]=PALRAM[0x04]=PALRAM[0x08]=PALRAM[0x0C]=
+                         PALRAM[0x10]=PALRAM[0x14]=PALRAM[0x18]=PALRAM[0x1c]=V&0x3f;
+                        else if(tmp&3) PALRAM[(tmp&0x1f)]=V&0x3f;
+                        }
+                        else if(tmp<0x2000)
+                        {
+                          if(PPUCHRRAM&(1<<(tmp>>10)))
+                            VPage[tmp>>10][tmp]=V;
+                        }
+                        else
+                       {                                               
+                         if(PPUNTARAM&(1<<((tmp&0xF00)>>10)))
+                          vnapage[((tmp&0xF00)>>10)][tmp&0x3FF]=V;
+                        }
+                        if (INC32) RefreshAddr+=32;
+                        else RefreshAddr++;
+                        if(PPU_hook) PPU_hook(RefreshAddr&0x3fff);
+}
+
+static DECLFW(B4014)
+{                        
+       uint32 t=V<<8;
+       int x;
+       for(x=0;x<256;x++)
+        B2004(0x2004,X.DB=ARead[t+x](t+x));
+       X6502_AddCycles(512);
+}
+
+static void FASTAPASS(1) BGRender(uint8 *target)
+{
+       uint32 tem;
+        RefreshLine(target);
+        if(!(PPU[1]&2))
+        {
+         tem=Pal[0]|(Pal[0]<<8)|(Pal[0]<<16)|(Pal[0]<<24);
+         tem|=0x40404040;
+         *(uint32 *)target=*(uint32 *)(target+4)=tem;
+        }
+}
+
+#ifdef FRAMESKIP
+static int FSkip=0;
+void FCEUI_FrameSkip(int x)
+{
+ FSkip=x;
+}
+#endif
+
+/*     This is called at the beginning of each visible scanline */
+static void Loop6502(void)
+{
+       uint32 tem;
+       int x;
+        uint8 *target=XBuf+(scanline<<8)+(scanline<<4)+8;
+
+        if(ScreenON || SpriteON)
+        {
+        /* PRefreshLine() will not get called on skipped frames.  This
+           could cause a problem, but the solution would be rather complex,
+           due to the current sprite 0 hit code.
+        */
+        #ifdef FRAMESKIP
+        if(!FSkip)
+        {
+        #endif
+         if(ScreenON)
+         {
+          if(scanline>=FSettings.FirstSLine && scanline<=FSettings.LastSLine)
+           BGRender(target);
+          else
+          {
+           if(PPU_hook)
+            PRefreshLine();
+          }
+         }
+         else
+         {
+          tem=Pal[0]|(Pal[0]<<8)|(Pal[0]<<16)|(Pal[0]<<24);
+          tem|=0x40404040;
+          FCEU_dwmemset(target,tem,264);
+         }
+        #ifdef FRAMESKIP
+        }
+        #endif
+        if (SpriteON && scanline)
+         RefreshSprite(target);
+        #ifdef FRAMESKIP
+        if(!FSkip)
+        {
+        #endif
+         if(PPU[1]&0x01)
+         { 
+          for(x=63;x>=0;x--)
+           *(uint32 *)&target[x<<2]=(*(uint32*)&target[x<<2])&0xF0F0F0F0;
+         }
+          if((PPU[1]>>5)==0x7)
+           for(x=63;x>=0;x--)
+            *(uint32 *)&target[x<<2]=((*(uint32*)&target[x<<2])&0x3f3f3f3f)|0x40404040;
+          else if(PPU[1]&0xE0)
+           for(x=63;x>=0;x--)
+            *(uint32 *)&target[x<<2]=(*(uint32*)&target[x<<2])|0xC0C0C0C0;
+          else
+            for(x=63;x>=0;x--)
+             *(uint32 *)&target[x<<2]=(*(uint32*)&target[x<<2])&0x3f3f3f3f;
+
+        #ifdef FRAMESKIP
+        }
+        #endif
+       }
+       else
+       {
+        tem=Pal[0]|(Pal[0]<<8)|(Pal[0]<<16)|(Pal[0]<<24);
+        FCEU_dwmemset(target,tem,256);
+       }               
+        if(InputScanlineHook)
+         InputScanlineHook(target, scanline);
+}
+
+#define PAL(c)  ((c)+cc)
+
+
+static void PRefreshLine(void)
+{
+        uint32 vofs;
+        uint8 X1;
+
+        vofs = 0;
+        if (BGAdrHI) vofs = 0x1000;
+
+        vofs+=(RefreshAddr>>12)&7;
+
+        for(X1=33;X1;X1--)
+        {
+                register uint8 no;
+                register uint8 zz2;
+                zz2=(uint8)((RefreshAddr>>10)&3);
+               PPU_hook(0x2000|(RefreshAddr&0xFFF));
+                no  = vnapage[zz2][(RefreshAddr&0x3ff)];
+                PPU_hook((no<<4)+vofs);
+                if((RefreshAddr&0x1f)==0x1f)
+                 RefreshAddr^=0x41F;
+                else
+                 RefreshAddr++;
+        }
+}
+
+/*              Total of 33 tiles(32 + 1 extra) */
+static void FASTAPASS(1) RefreshLine(uint8 *target)
+{
+       uint32 vofs;
+        int X1;
+        register uint8 *P=target; 
+
+       vofs=0;
+       
+        Pal[0]|=64;
+        Pal[4]|=64;
+        Pal[8]|=64;
+        Pal[0xC]|=64;
+
+       vofs=((PPU[0]&0x10)<<8) | ((RefreshAddr>>12)&7);
+        P-=XOffset;
+
+       /* This high-level graphics MMC5 emulation code was written
+          for MMC5 carts in "CL" mode.  It's probably not totally
+          correct for carts in "SL" mode.
+       */
+        if(MMC5Hack && geniestage!=1)
+        {
+        if(MMC5HackCHRMode==0 && (MMC5HackSPMode&0x80))
+        {
+         int8 tochange;
+
+          tochange=MMC5HackSPMode&0x1F;
+
+          for(X1=33;X1;X1--,P+=8)
+          {
+                uint8 *C;
+                register uint8 cc,zz,zz2;
+                uint32 vadr;
+
+                if((tochange<=0 && MMC5HackSPMode&0x40) || 
+                  (tochange>0 && !(MMC5HackSPMode&0x40)))
+                {
+                 uint8 xs,ys;
+
+                 xs=33-X1; 
+                 ys=((scanline>>3)+MMC5HackSPScroll)&0x1F;
+                 if(ys>=0x1E) ys-=0x1E;
+                 vadr=(MMC5HackExNTARAMPtr[xs|(ys<<5)]<<4)+(vofs&7);
+
+                 C = MMC5HackVROMPTR+vadr;
+                 C += ((MMC5HackSPPage & 0x3f & MMC5HackVROMMask) << 12);
+
+                 cc=MMC5HackExNTARAMPtr[0x3c0+(xs>>2)+((ys&0x1C)<<1)];
+                 cc=((cc >> ((xs&2) + ((ys&0x2)<<1))) &3) <<2;
+                }
+                else
+                {
+                 zz=RefreshAddr&0x1F;
+                 zz2=(RefreshAddr>>10)&3;
+                 vadr=(vnapage[zz2][RefreshAddr&0x3ff]<<4)+vofs;
+                 C = MMC5BGVRAMADR(vadr);
+                 cc=vnapage[zz2][0x3c0+(zz>>2)+((RefreshAddr&0x380)>>4)];
+                 cc=((cc >> ((zz&2) + ((RefreshAddr&0x40)>>4))) &3) <<2;
+                }
+                #include "fceline.h"
+
+                if((RefreshAddr&0x1f)==0x1f)
+                 RefreshAddr^=0x41F;
+                else
+                 RefreshAddr++;
+                tochange--;
+          }
+        }
+        else if(MMC5HackCHRMode==1 && (MMC5HackSPMode&0x80))
+        {
+          int8 tochange;
+
+          tochange=MMC5HackSPMode&0x1F;
+
+          for(X1=33;X1;X1--,P+=8)
+          {
+                uint8 *C;
+                register uint8 cc;
+                register uint8 zz2;
+                uint32 vadr;
+
+                if((tochange<=0 && MMC5HackSPMode&0x40) ||
+                   (tochange>0 && !(MMC5HackSPMode&0x40)))
+                {
+                 uint8 xs,ys;
+
+                 xs=33-X1; 
+                 ys=((scanline>>3)+MMC5HackSPScroll)&0x1F;
+                 if(ys>=0x1E) ys-=0x1E;
+                 vadr=(MMC5HackExNTARAMPtr[xs|(ys<<5)]<<4)+(vofs&7);
+
+                 C = MMC5HackVROMPTR+vadr;
+                 C += ((MMC5HackSPPage & 0x3f & MMC5HackVROMMask) << 12);
+
+                 cc=MMC5HackExNTARAMPtr[0x3c0+(xs>>2)+((ys&0x1C)<<1)];
+                 cc=((cc >> ((xs&2) + ((ys&0x2)<<1))) &3) <<2;
+                }
+                else
+                {
+                 C=MMC5HackVROMPTR;
+                 zz2=(RefreshAddr>>10)&3;
+                 vadr = (vnapage[zz2][RefreshAddr & 0x3ff] << 4) + vofs;
+                 C += (((MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff]) & 0x3f &
+                         MMC5HackVROMMask) << 12) + (vadr & 0xfff);
+                 vadr = (MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff] & 0xC0)>> 4;
+                 cc = vadr;
+               }
+                #include "fceline.h"
+                if((RefreshAddr&0x1f)==0x1f)
+                 RefreshAddr^=0x41F;
+                else
+                 RefreshAddr++;
+               tochange--;
+          }
+        }
+
+         else if(MMC5HackCHRMode==1)
+         {
+          for(X1=33;X1;X1--,P+=8)
+          {
+                uint8 *C;                                   
+                register uint8 cc;
+                register uint8 zz2;
+                uint32 vadr;  
+
+                C=MMC5HackVROMPTR;
+                zz2=(RefreshAddr>>10)&3;
+                vadr = (vnapage[zz2][RefreshAddr & 0x3ff] << 4) + vofs;
+                C += (((MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff]) & 0x3f & 
+                       MMC5HackVROMMask) << 12) + (vadr & 0xfff);
+                vadr = (MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff] & 0xC0)>> 4;
+                cc = vadr;
+
+                #include "fceline.h"
+                if((RefreshAddr&0x1f)==0x1f)
+                 RefreshAddr^=0x41F;
+                else
+                 RefreshAddr++;
+          }
+         }
+         else
+         {
+          for(X1=33;X1;X1--,P+=8)
+          {
+                uint8 *C;
+                register uint8 cc,zz,zz2;
+                uint32 vadr;
+
+                zz=RefreshAddr&0x1F;
+                zz2=(RefreshAddr>>10)&3;
+                vadr=(vnapage[zz2][RefreshAddr&0x3ff]<<4)+vofs;
+                C = MMC5BGVRAMADR(vadr);
+                cc=vnapage[zz2][0x3c0+(zz>>2)+((RefreshAddr&0x380)>>4)];
+                cc=((cc >> ((zz&2) + ((RefreshAddr&0x40)>>4))) &3) <<2;
+
+               #include "fceline.h"
+                
+               if((RefreshAddr&0x1f)==0x1f)
+                 RefreshAddr^=0x41F;
+                else
+                 RefreshAddr++;
+          }          
+         }
+        }       // End if(MMC5Hack) 
+
+        else if(PPU_hook)
+        {
+         for(X1=33;X1;X1--,P+=8)
+         {
+                uint8 *C;                                   
+                register uint8 cc,zz,zz2;
+                uint32 vadr;  
+
+                zz=RefreshAddr&0x1F;
+                zz2=(RefreshAddr>>10)&3;
+                PPU_hook(0x2000|(RefreshAddr&0xFFF));
+                cc=vnapage[zz2][0x3c0+(zz>>2)+((RefreshAddr&0x380)>>4)];
+                cc=((cc >> ((zz&2) + ((RefreshAddr&0x40)>>4))) &3) <<2;
+                vadr=(vnapage[zz2][RefreshAddr&0x3ff]<<4)+vofs;
+                C = VRAMADR(vadr);
+
+               #include "fceline.h"
+
+               PPU_hook(vadr);
+
+                if((RefreshAddr&0x1f)==0x1f)
+                 RefreshAddr^=0x41F;
+                else
+                 RefreshAddr++;
+         }
+        }
+        else
+        {      
+         for(X1=33;X1;X1--,P+=8)
+         {
+                uint8 *C;
+                register uint8 cc,zz,zz2;
+                uint32 vadr;
+
+                zz=RefreshAddr&0x1F;
+               zz2=(RefreshAddr>>10)&3;
+                vadr=(vnapage[zz2][RefreshAddr&0x3ff]<<4)+vofs;
+                C = VRAMADR(vadr);
+               cc=vnapage[zz2][0x3c0+(zz>>2)+((RefreshAddr&0x380)>>4)];
+               cc=((cc >> ((zz&2) + ((RefreshAddr&0x40)>>4))) &3) <<2;
+               #include "fceline.h"
+                
+                if((RefreshAddr&0x1f)==0x1f)
+                 RefreshAddr^=0x41F;
+                else
+                 RefreshAddr++;
+         }
+        }
+
+        #undef vofs
+
+        Pal[0]&=63;
+        Pal[4]&=63;
+        Pal[8]&=63;
+        Pal[0xC]&=63;
+}
+
+static INLINE void Fixit2(void)
+{
+   if(ScreenON || SpriteON)
+   {
+    uint32 rad=RefreshAddr;
+    rad&=0xFBE0;
+    rad|=TempAddr&0x041f;
+    RefreshAddr=rad;
+    //PPU_hook(RefreshAddr,-1);
+   }
+}
+
+static INLINE void Fixit1(void)
+{
+   if(ScreenON || SpriteON)
+   {
+    uint32 rad=RefreshAddr;
+
+    if((rad&0x7000)==0x7000)
+    {
+     rad^=0x7000;
+     if((rad&0x3E0)==0x3A0)
+     {
+      rad^=0x3A0;
+      rad^=0x800;
+     }
+     else
+     {
+      if((rad&0x3E0)==0x3e0)
+       rad^=0x3e0;
+      else rad+=0x20;
+     }
+    }
+    else
+     rad+=0x1000;
+    RefreshAddr=rad;
+    //PPU_hook(RefreshAddr,-1);
+   }
+}
+
+/*      This is called at the beginning of all h-blanks on visible lines. */
+static void DoHBlank(void)
+{
+ if(ScreenON || SpriteON)
+  FetchSpriteData();
+ if(GameHBIRQHook && (ScreenON || SpriteON))
+ {
+  X6502_Run(12);
+  GameHBIRQHook();
+  X6502_Run(25-12);
+  Fixit2();
+  X6502_Run(85-25);
+ }
+ else
+ {
+  X6502_Run(25);       // Tried 65, caused problems with Slalom(maybe others)
+  Fixit2();
+  X6502_Run(85-25);
+ }
+ //PPU_hook(0,-1);
+ //fprintf(stderr,"%3d: $%04x\n",scanline,RefreshAddr);
+}
+
+#define        V_FLIP  0x80
+#define        H_FLIP  0x40
+#define        SP_BACK 0x20
+
+typedef struct {
+        uint8 y,no,atr,x;
+} SPR;
+
+typedef struct {
+       uint8 ca[2],atr,x;
+} SPRB;
+
+uint8 sprlinebuf[256+8];        
+
+void FCEUI_DisableSpriteLimitation(int a)
+{
+ maxsprites=a?64:8;
+}
+
+static uint8 nosprites,SpriteBlurp;
+
+static void FetchSpriteData(void)
+{
+       SPR *spr;
+       uint8 H;
+       int n,vofs;
+
+       spr=(SPR *)SPRAM;
+       H=8;
+
+       nosprites=SpriteBlurp=0;
+
+        vofs=(unsigned int)(PPU[0]&0x8&(((PPU[0]&0x20)^0x20)>>2))<<9;
+       H+=(PPU[0]&0x20)>>2;
+
+        if(!PPU_hook)
+         for(n=63;n>=0;n--,spr++)
+         {
+                if((unsigned int)(scanline-spr->y)>=H) continue;
+
+                if(nosprites<maxsprites)
+                {
+                 if(n==63) SpriteBlurp=1;
+
+                {
+                 SPRB dst;
+                 uint8 *C;
+                  int t;
+                  unsigned int vadr;
+
+                  t = (int)scanline-(spr->y);
+
+                  if (Sprite16)
+                   vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4);
+                  else
+                   vadr = (spr->no<<4)+vofs;
+
+                  if (spr->atr&V_FLIP)
+                  {
+                        vadr+=7;
+                        vadr-=t;
+                        vadr+=(PPU[0]&0x20)>>1;
+                        vadr-=t&8;
+                  }
+                  else
+                  {
+                        vadr+=t;
+                        vadr+=t&8;
+                  }
+
+                 /* Fix this geniestage hack */
+                 if(MMC5Hack && geniestage!=1) C = MMC5SPRVRAMADR(vadr);
+                  else C = VRAMADR(vadr);
+
+                 
+                 dst.ca[0]=C[0];
+                 dst.ca[1]=C[8];
+                 dst.x=spr->x;
+                 dst.atr=spr->atr;
+
+
+                 *(uint32 *)&SPRBUF[nosprites<<2]=*(uint32 *)&dst;
+                }
+
+                 nosprites++;
+                }
+                else
+                {
+                  PPU_status|=0x20;
+                  break;
+                }
+         }
+       else
+         for(n=63;n>=0;n--,spr++)
+         {
+                if((unsigned int)(scanline-spr->y)>=H) continue;
+
+                if(nosprites<maxsprites)
+                {
+                 if(n==63) SpriteBlurp=1;
+
+                 {
+                  SPRB dst;
+                  uint8 *C;
+                  int t;
+                  unsigned int vadr;
+
+                  t = (int)scanline-(spr->y);
+
+                  if (Sprite16)
+                   vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4);
+                  else
+                   vadr = (spr->no<<4)+vofs;
+
+                  if (spr->atr&V_FLIP)
+                  {
+                        vadr+=7;
+                        vadr-=t;
+                        vadr+=(PPU[0]&0x20)>>1;
+                        vadr-=t&8;
+                  }
+                  else
+                  {
+                        vadr+=t;
+                        vadr+=t&8;
+                  }
+
+                  if(MMC5Hack) C = MMC5SPRVRAMADR(vadr);
+                  else C = VRAMADR(vadr);
+                  dst.ca[0]=C[0];
+                 PPU_hook(vadr);
+                  dst.ca[1]=C[8];
+                 PPU_hook(vadr|8);
+                  dst.x=spr->x;
+                  dst.atr=spr->atr;
+
+
+                  *(uint32 *)&SPRBUF[nosprites<<2]=*(uint32 *)&dst;
+                 }
+
+                 nosprites++;
+                }
+                else
+                {
+                  PPU_status|=0x20;
+                  break;
+                }
+         }
+}
+
+static void FASTAPASS(1) RefreshSprite(uint8 *target)
+{
+       int n;
+        SPRB *spr;
+        uint8 *P=target;
+
+        if(!nosprites) return;
+       #ifdef FRAMESKIP
+       if(FSkip)
+       {
+        if(!SpriteBlurp)
+        {
+         nosprites=0;
+         return;
+        }
+        else
+         nosprites=1;
+       }
+       #endif
+
+        FCEU_dwmemset(sprlinebuf,0x80808080,256);
+        nosprites--;
+        spr = (SPRB*)SPRBUF+nosprites;
+
+       for(n=nosprites;n>=0;n--,spr--)
+       {
+        register uint8 J,atr,c1,c2;
+       int x=spr->x;
+        uint8 *C;
+        uint8 *VB;
+                
+        P+=x;
+
+        c1=((spr->ca[0]>>1)&0x55)|(spr->ca[1]&0xAA);
+       c2=(spr->ca[0]&0x55)|((spr->ca[1]<<1)&0xAA);
+
+        J=spr->ca[0]|spr->ca[1];
+       atr=spr->atr;
+
+                       if(J)
+                       {        
+                        if(n==0 && SpriteBlurp && !(PPU_status&0x40))
+                        {  
+                        int z,ze=x+8;
+                        if(ze>256) {ze=256;}
+                        if(ScreenON && (scanline<FSettings.FirstSLine || scanline>FSettings.LastSLine
+                        #ifdef FRAMESKIP
+                        || FSkip
+                        #endif
+                        ))
+                         BGRender(target);
+
+                        if(!(atr&H_FLIP))
+                        {
+                         for(z=x;z<ze;z++)
+                         {
+                          if(J&(0x80>>(z-x)))
+                          {
+                           if(!(target[z]&64))
+                            tosprite=z;
+                          }
+                         }
+                        }
+                        else
+                        {
+                          for(z=x;z<ze;z++)
+                          {
+                           if(J&(1<<(z-x)))
+                           {
+                            if(!(target[z]&64))
+                             tosprite=z;
+                           }
+                          }
+                        }
+                        //FCEU_DispMessage("%d, %d:%d",scanline,x,tosprite);
+                        }
+
+        C = sprlinebuf+x;
+         VB = (PALRAM+0x10)+((atr&3)<<2);
+
+         if(atr&SP_BACK) 
+         {
+          if (atr&H_FLIP)
+          {
+           if (J&0x02)  C[1]=VB[c1&3]|0x40;
+           if (J&0x01)  *C=VB[c2&3]|0x40;
+           c1>>=2;c2>>=2;
+           if (J&0x08)  C[3]=VB[c1&3]|0x40;;
+           if (J&0x04)  C[2]=VB[c2&3]|0x40;;
+           c1>>=2;c2>>=2;
+           if (J&0x20)  C[5]=VB[c1&3]|0x40;;
+           if (J&0x10)  C[4]=VB[c2&3]|0x40;;
+           c1>>=2;c2>>=2;
+           if (J&0x80)  C[7]=VB[c1]|0x40;;
+           if (J&0x40)  C[6]=VB[c2]|0x40;;
+         } else  {
+           if (J&0x02)  C[6]=VB[c1&3]|0x40;
+           if (J&0x01)  C[7]=VB[c2&3]|0x40;
+          c1>>=2;c2>>=2;
+           if (J&0x08)  C[4]=VB[c1&3]|0x40;
+           if (J&0x04)  C[5]=VB[c2&3]|0x40;
+           c1>>=2;c2>>=2;
+           if (J&0x20)  C[2]=VB[c1&3]|0x40;
+           if (J&0x10)  C[3]=VB[c2&3]|0x40;
+           c1>>=2;c2>>=2;
+           if (J&0x80)  *C=VB[c1]|0x40;
+           if (J&0x40)  C[1]=VB[c2]|0x40;
+         }
+         } else {
+          if (atr&H_FLIP)
+         {
+           if (J&0x02)  C[1]=VB[(c1&3)];
+           if (J&0x01)  *C=VB[(c2&3)];
+           c1>>=2;c2>>=2;
+           if (J&0x08)  C[3]=VB[(c1&3)];
+           if (J&0x04)  C[2]=VB[(c2&3)];
+           c1>>=2;c2>>=2;
+           if (J&0x20)  C[5]=VB[(c1&3)];
+           if (J&0x10)  C[4]=VB[(c2&3)];
+           c1>>=2;c2>>=2;
+           if (J&0x80)  C[7]=VB[c1];
+           if (J&0x40)  C[6]=VB[c2];
+          }else{                 
+           if (J&0x02)  C[6]=VB[(c1&3)];
+           if (J&0x01)  C[7]=VB[(c2&3)];
+           c1>>=2;c2>>=2;
+           if (J&0x08)  C[4]=VB[(c1&3)];
+           if (J&0x04)  C[5]=VB[(c2&3)];
+           c1>>=2;c2>>=2;
+           if (J&0x20)  C[2]=VB[(c1&3)];
+           if (J&0x10)  C[3]=VB[(c2&3)];
+           c1>>=2;c2>>=2;
+           if (J&0x80)  *C=VB[c1];
+           if (J&0x40)  C[1]=VB[c2];
+          }
+         }
+        }
+       P-=x;
+      }
+
+     nosprites=0;
+     #ifdef FRAMESKIP
+     if(FSkip) return;
+     #endif
+
+     {
+      uint8 n=((PPU[1]&4)^4)<<1;
+      loopskie:
+      {
+       uint32 t=*(uint32 *)(sprlinebuf+n);
+       if(t!=0x80808080)
+       {
+       #ifdef LSB_FIRST
+        if(!(t&0x80))
+        {
+         if(!(t&0x40))       // Normal sprite
+          P[n]=sprlinebuf[n];
+         else if(P[n]&64)        // behind bg sprite
+          P[n]=sprlinebuf[n];
+        }
+
+        if(!(t&0x8000))
+        {
+         if(!(t&0x4000))       // Normal sprite
+          P[n+1]=(sprlinebuf+1)[n];
+         else if(P[n+1]&64)        // behind bg sprite
+          P[n+1]=(sprlinebuf+1)[n];
+        }
+
+        if(!(t&0x800000))
+        {
+         if(!(t&0x400000))       // Normal sprite
+          P[n+2]=(sprlinebuf+2)[n];
+         else if(P[n+2]&64)        // behind bg sprite
+          P[n+2]=(sprlinebuf+2)[n];
+        }
+
+        if(!(t&0x80000000))
+        {
+         if(!(t&0x40000000))       // Normal sprite
+          P[n+3]=(sprlinebuf+3)[n];
+         else if(P[n+3]&64)        // behind bg sprite
+          P[n+3]=(sprlinebuf+3)[n];
+        }
+       #else
+        if(!(t&0x80000000))
+        {
+         if(!(t&0x40))       // Normal sprite
+          P[n]=sprlinebuf[n];
+         else if(P[n]&64)        // behind bg sprite
+          P[n]=sprlinebuf[n];
+        }
+
+        if(!(t&0x800000))
+        {
+         if(!(t&0x4000))       // Normal sprite
+          P[n+1]=(sprlinebuf+1)[n];
+         else if(P[n+1]&64)        // behind bg sprite
+          P[n+1]=(sprlinebuf+1)[n];
+        }
+
+        if(!(t&0x8000))
+        {
+         if(!(t&0x400000))       // Normal sprite
+          P[n+2]=(sprlinebuf+2)[n];
+         else if(P[n+2]&64)        // behind bg sprite
+          P[n+2]=(sprlinebuf+2)[n];
+        }
+
+        if(!(t&0x80))
+        {
+         if(!(t&0x40000000))       // Normal sprite
+          P[n+3]=(sprlinebuf+3)[n];
+         else if(P[n+3]&64)        // behind bg sprite
+          P[n+3]=(sprlinebuf+3)[n];
+        }
+       #endif
+       }
+      }
+      n+=4;
+      if(n) goto loopskie;
+     }
+}
+
+void ResetMapping(void)
+{
+       int x;
+
+        SetReadHandler(0x0000,0xFFFF,ANull);
+       SetWriteHandler(0x0000,0xFFFF,BNull);
+
+        SetReadHandler(0,0x7FF,ARAML);
+        SetWriteHandler(0,0x7FF,BRAML);
+
+        SetReadHandler(0x800,0x1FFF,ARAMH);  /* Part of a little */
+        SetWriteHandler(0x800,0x1FFF,BRAMH); /* hack for a small speed boost. */
+
+        for(x=0x2000;x<0x4000;x+=8)
+        {
+         ARead[x]=A200x;
+         BWrite[x]=B2000;
+         ARead[x+1]=A200x;
+         BWrite[x+1]=B2001;
+         ARead[x+2]=A2002;
+         BWrite[x+2]=B2002;
+         ARead[x+3]=A200x;
+         BWrite[x+3]=B2003;
+         ARead[x+4]=A200x;
+         BWrite[x+4]=B2004;
+         ARead[x+5]=A200x;
+         BWrite[x+5]=B2005;
+         ARead[x+6]=A200x;
+         BWrite[x+6]=B2006;
+         ARead[x+7]=A2007;
+         BWrite[x+7]=B2007;
+        }
+
+        BWrite[0x4014]=B4014;
+        SetNESSoundMap();
+       InitializeInput();
+}
+
+int GameLoaded=0;
+void CloseGame(void)
+{
+ if(GameLoaded)
+ {
+  if(FCEUGameInfo.type!=GIT_NSF)
+   FlushGameCheats();
+  #ifdef NETWORK
+  if(FSettings.NetworkPlay) KillNetplay();
+  #endif       
+  GameInterface(GI_CLOSE);
+  CloseGenie();
+  GameLoaded=0;
+ }
+}
+
+void ResetGameLoaded(void)
+{
+        if(GameLoaded) CloseGame();
+        GameStateRestore=0;
+        PPU_hook=0;
+        GameHBIRQHook=0;
+       GameExpSound.Fill=0;
+       GameExpSound.RChange=0;
+        if(GameExpSound.Kill)
+         GameExpSound.Kill();
+        GameExpSound.Kill=0;
+        MapIRQHook=0;
+        MMC5Hack=0;
+        PAL&=1;
+       pale=0;
+
+       FCEUGameInfo.name=0;
+       FCEUGameInfo.type=GIT_CART;
+       FCEUGameInfo.vidsys=GIV_USER;
+       FCEUGameInfo.input[0]=FCEUGameInfo.input[1]=-1;
+       FCEUGameInfo.inputfc=-1;
+}
+
+FCEUGI *FCEUI_LoadGame(char *name)
+{
+        int fp;
+
+        Exit=1;
+        ResetGameLoaded();
+
+       fp=FCEU_fopen(name,"rb");
+       if(!fp)
+        {
+        FCEU_PrintError("Error opening \"%s\"!",name);
+        return 0;
+       }
+
+        GetFileBase(name);
+        if(iNESLoad(name,fp))
+         goto endlseq;
+        if(NSFLoad(fp))
+         goto endlseq;
+        if(FDSLoad(name,fp))
+         goto endlseq;
+        if(UNIFLoad(name,fp))
+         goto endlseq;
+
+        FCEU_PrintError("An error occurred while loading the file.");
+        FCEU_fclose(fp);
+        return 0;
+
+        endlseq:
+        FCEU_fclose(fp);
+        GameLoaded=1;        
+
+        FCEU_ResetVidSys();
+        if(FCEUGameInfo.type!=GIT_NSF)
+         if(FSettings.GameGenie)
+         OpenGenie();
+
+        PowerNES();
+       #ifdef NETWORK
+        if(FSettings.NetworkPlay) InitNetplay();
+       #endif
+        SaveStateRefresh();
+        if(FCEUGameInfo.type!=GIT_NSF)
+        {
+         LoadGamePalette();
+         LoadGameCheats();
+        }
+        
+       FCEU_ResetPalette();
+        Exit=0;
+        return(&FCEUGameInfo);
+}
+
+
+void FCEU_ResetVidSys(void)
+{
+ int w;
+
+ if(FCEUGameInfo.vidsys==GIV_NTSC)
+  w=0;
+ else if(FCEUGameInfo.vidsys==GIV_PAL)
+  w=1;
+ else
+  w=FSettings.PAL;
+
+ if(w)
+ {
+  PAL=1;
+  scanlines_per_frame=312;
+  FSettings.FirstSLine=FSettings.UsrFirstSLine[1];
+  FSettings.LastSLine=FSettings.UsrLastSLine[1];
+ }
+ else
+ {
+  PAL=0;
+  scanlines_per_frame=262;
+  FSettings.FirstSLine=FSettings.UsrFirstSLine[0];
+  FSettings.LastSLine=FSettings.UsrLastSLine[0];
+ }
+ SetSoundVariables();
+}
+
+int FCEUI_Initialize(void)
+{
+        if(!InitVirtualVideo())
+         return 0;
+       memset(&FSettings,0,sizeof(FSettings));
+       FSettings.UsrFirstSLine[0]=8;
+       FSettings.UsrFirstSLine[1]=0;
+        FSettings.UsrLastSLine[0]=FSettings.UsrLastSLine[1]=239;
+       FSettings.SoundVolume=65536;    // 100%
+        return 1;
+}
+
+#define harko 0xe //0x9
+static INLINE void Thingo(void)
+{
+   Loop6502();
+
+   if(tosprite>=256)
+   { 
+    X6502_Run(256-harko);
+    Fixit1();
+    X6502_Run(harko);
+   }
+   else
+   {
+    if(tosprite<=240)
+    {
+     X6502_Run(tosprite);
+     PPU[2]|=0x40;
+     X6502_Run(256-tosprite-harko);
+     Fixit1();
+     X6502_Run(harko);
+    }
+    else
+    {
+     X6502_Run(256-harko);
+     Fixit1();
+     X6502_Run(tosprite-(256-harko));
+     PPU[2]|=0x40;
+     X6502_Run(256-tosprite);
+    }
+    tosprite=256;
+   }
+   DoHBlank();
+}
+#undef harko
+
+void EmLoop(void)
+{
+ for(;;)
+ {
+  ApplyPeriodicCheats();
+  X6502_Run(256+85);
+
+  PPU[2]|=0x80;
+  PPU[3]=PPUSPL=0;            /* Not sure if this is correct.  According
+                                 to Matt Conte and my own tests, it is.  Timing is probably
+                                 off, though.  NOTE:  Not having this here
+                                 breaks a Super Donkey Kong game. */
+
+  X6502_Run(12);               /* I need to figure out the true nature and length
+                                  of this delay. 
+                               */
+  if(FCEUGameInfo.type==GIT_NSF)
+   TriggerNMINSF();
+  else if(VBlankON)
+   TriggerNMI();
+
+  X6502_Run((scanlines_per_frame-242)*(256+85)-12); 
+
+  PPU_status&=0x1f;
+
+  X6502_Run(256);
+  {
+   static int kook=0;
+   if(ScreenON || SpriteON)
+    if(GameHBIRQHook)
+     GameHBIRQHook();
+
+   X6502_Run(85-kook);
+   kook=(kook+1)&1;
+  }
+
+  if(ScreenON || SpriteON)
+  {
+   RefreshAddr=TempAddr;
+   if(PPU_hook) PPU_hook(RefreshAddr&0x3fff);
+  }
+  if(FCEUGameInfo.type==GIT_NSF)
+   X6502_Run((256+85)*240);
+  else
+  {
+   int x,max,maxref;
+
+   deemp=PPU[1]>>5;
+   for(scanline=0;scanline<240;scanline++)
+   {
+    deempcnt[deemp]++;
+    Thingo();
+   }
+   for(x=1,max=0,maxref=0;x<7;x++)
+   {
+    if(deempcnt[x]>max)
+    {
+     max=deempcnt[x];
+     maxref=x;
+    }
+    deempcnt[x]=0;
+   }
+   //FCEU_DispMessage("%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x %d",deempcnt[0],deempcnt[1],deempcnt[2],deempcnt[3],deempcnt[4],deempcnt[5],deempcnt[6],deempcnt[7],maxref);
+   //memset(deempcnt,0,sizeof(deempcnt));
+   SetNESDeemph(maxref,0);
+  }
+
+  {
+   int ssize;
+
+   ssize=FlushEmulateSound();
+
+   #ifdef FRAMESKIP
+   if(FSkip)
+   {
+    FCEU_PutImageDummy();
+    FSkip--;
+    FCEUD_Update(0,WaveFinal,ssize);
+   }
+   else
+   #endif
+   {
+    FCEU_PutImage();
+    FCEUD_Update(XBuf+8,WaveFinal,ssize);
+   }
+   UpdateInput();
+  }
+
+  if(Exit)
+  {
+   CloseGame();
+   break;
+  }
+
+ }
+}
+
+#ifdef FPS
+#include <sys/time.h>
+uint64 frcount;
+#endif
+void FCEUI_Emulate(void)
+{
+       #ifdef FPS
+        uint64 starttime,end;
+        struct timeval tv;
+       frcount=0;
+        gettimeofday(&tv,0);
+        starttime=((uint64)tv.tv_sec*1000000)+tv.tv_usec;
+       #endif
+       EmLoop();
+
+        #ifdef FPS
+        // Probably won't work well on Windows port; for
+       // debugging/speed testing.
+       {
+        uint64 w;
+        int i,frac;
+         gettimeofday(&tv,0);
+         end=((uint64)tv.tv_sec*1000000)+tv.tv_usec;
+        w=frcount*10000000000LL/(end-starttime);
+        i=w/10000;
+        frac=w-i*10000;
+         printf("Average FPS: %d.%04d\n",i,frac);
+       }
+        #endif
+
+}
+
+void FCEUI_CloseGame(void)
+{
+        Exit=1;
+}
+
+static void ResetPPU(void)
+{
+        VRAMBuffer=PPU[0]=PPU[1]=PPU[2]=PPU[3]=0;
+        PPUSPL=0;
+       PPUGenLatch=0;
+        RefreshAddr=TempAddr=0;
+        vtoggle = 0;
+}
+
+static void PowerPPU(void)
+{
+        memset(NTARAM,0x00,0x800);
+        memset(PALRAM,0x00,0x20);
+        memset(SPRAM,0x00,0x100);
+       ResetPPU();
+}
+
+void ResetNES(void)
+{
+        if(!GameLoaded || (FCEUGameInfo.type==GIT_NSF)) return;
+        GameInterface(GI_RESETM2);
+        ResetSound();
+        ResetPPU();
+        X6502_Reset();
+}
+
+void PowerNES(void) 
+{
+        if(!GameLoaded) return;
+
+       FCEU_CheatResetRAM();
+       FCEU_CheatAddRAM(2,0,RAM);
+
+        GeniePower();
+
+        memset(RAM,0x00,0x800);
+        ResetMapping();
+       GameInterface(GI_POWER);
+        PowerSound();
+       PowerPPU();
+       timestampbase=0;
+       X6502_Power();
+}
+
diff --git a/fce.h b/fce.h
new file mode 100644 (file)
index 0000000..ba90d75
--- /dev/null
+++ b/fce.h
@@ -0,0 +1,81 @@
+#ifndef _FCEH
+extern int GameLoaded;
+void ResetGameLoaded(void);
+
+#define DECLFR(x) uint8 FP_FASTAPASS(1) x (uint32 A)
+#define DECLFW(x) void FP_FASTAPASS(2) x (uint32 A, uint8 V)
+
+void FASTAPASS(3) SetReadHandler(int32 start, int32 end, readfunc func);
+void FASTAPASS(3) SetWriteHandler(int32 start, int32 end, writefunc func);
+writefunc FASTAPASS(1) GetWriteHandler(int32 a);
+readfunc FASTAPASS(1) GetReadHandler(int32 a);
+
+int AllocGenieRW(void);
+void FlushGenieRW(void);
+
+void FCEU_ResetVidSys(void);
+
+void ResetMapping(void);
+void ResetNES(void);
+void PowerNES(void);
+
+
+extern uint64 timestampbase;
+extern uint32 MMC5HackVROMMask;
+extern uint8 *MMC5HackExNTARAMPtr;
+extern int MMC5Hack;
+extern uint8 *MMC5HackVROMPTR;
+extern uint8 MMC5HackCHRMode;
+extern uint8 MMC5HackSPMode;
+extern uint8 MMC5HackSPScroll;
+extern uint8 MMC5HackSPPage;
+
+extern uint8 RAM[0x800],SPRAM[0x100],NTARAM[0x800],PALRAM[0x20],SPRAM[0x100],SPRBUF[0x100];
+extern uint8 GameMemBlock[131072];
+
+extern uint32 RefreshAddr,TempAddr;
+extern uint8 vtoggle,XOffset,VRAMBuffer,PPUGenLatch;
+extern uint8 PPU[4];
+
+extern int scanline;
+extern uint8 *vnapage[4];
+
+extern uint8 PPUNTARAM;
+extern uint8 PPUCHRRAM;
+extern uint8 VPAL[8];
+extern uint8 PAL;
+
+extern readfunc ARead[0x10000];
+extern writefunc BWrite[0x10000];
+
+#define        VBlankON        (PPU[0]&0x80)   /* Generate VBlank NMI */
+#define        SpHitON         (PPU[0]&0x40)   
+#define        Sprite16        (PPU[0]&0x20)   /* Sprites 8x16/8x8        */
+#define        BGAdrHI         (PPU[0]&0x10)   /* BG pattern adr $0000/$1000 */
+#define        SpAdrHI         (PPU[0]&0x08)   /* Sprite pattern adr $0000/$1000 */
+#define        INC32           (PPU[0]&0x04)   /* auto increment 1/32  */
+#define        NameTable       (PPU[0]&0x3)    /* name table $2000/$2400/$2800/$2C00 */
+
+#define SpriteON        (PPU[1]&0x10)   /* Show Sprite             */
+#define ScreenON        (PPU[1]&0x08)   /* Show screen             */
+#define PPU_status      (PPU[2])
+
+
+extern void (*GameInterface)(int h);
+extern void FP_FASTAPASS(1) (*PPU_hook)(uint32 A);
+extern void (*GameHBIRQHook)(void);
+extern void (*GameStateRestore)(int version);
+
+#define GI_RESETM2     1
+#define GI_POWER       2
+#define GI_CLOSE       3
+
+#include "git.h"
+extern FCEUGI FCEUGameInfo;
+extern int GameAttributes;
+
+
+#endif
+
+#define _FCEH
+
diff --git a/fceline.h b/fceline.h
new file mode 100644 (file)
index 0000000..5ba0ab7
--- /dev/null
+++ b/fceline.h
@@ -0,0 +1,112 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 BERO
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+#ifdef C80x86
+{
+ int dummy,dummy1,dummy2;
+        __asm__ __volatile__(
+       "xorl %%edx,%%edx\n\t"
+        "movb (%%esi),%%cl\n\t"
+        "movb 8(%%esi),%%dl\n\t"
+        "movl %%ebx,%%esi\n\t"
+        "addl %%eax,%%esi\n\t"
+       "xorl %%ebx,%%ebx\n\t"
+        "movb %%cl,%%bl\n\t"
+        "movb %%dl,%%al\n\t"
+        "shrb $1,%%bl\n\t"
+        "andb $0xaa,%%al\n\t"
+        "andb $0x55,%%bl\n\t"
+
+        "andb $0x55,%%cl\n\t"
+        "shlb $1,%%dl\n\t"
+        "andb $0xaa,%%dl\n\t"
+        "orb  %%al, %%bl\n\t"            // Stick c1 into bl
+        "orb  %%cl, %%dl\n\t"           // Stick c2 into dl
+        "xorl %%eax, %%eax\n\t"
+        "xorl %%ecx, %%ecx\n\t"
+        /*      At this point, bl contains c1, and dl contains c2 */
+        /*      and edi contains P, esi contains VRAM[] */
+        /*      al will be used for zz, cl will be used for zz2  */
+        "movb %%bl,%%al\n\t"
+        "movb %%dl,%%cl\n\t"
+        "andb $3,%%al\n\t"
+        "andb $3,%%cl\n\t"
+        "movb (%%esi,%%eax),%%bh\n\t"
+        "movb (%%esi,%%ecx),%%dh\n\t"
+        "movb %%bh,6(%%edi)\n\t"
+        "movb %%dh,7(%%edi)\n\t"
+
+        "movb %%bl,%%al\n\t"
+        "movb %%dl,%%cl\n\t"
+        "shrb $2,%%al\n\t"
+        "shrb $2,%%cl\n\t"
+        "andb $3,%%al\n\t"
+        "andb $3,%%cl\n\t"
+        "movb (%%esi,%%eax),%%bh\n\t"
+        "movb (%%esi,%%ecx),%%dh\n\t"
+        "movb %%bh,4(%%edi)\n\t"
+        "movb %%dh,5(%%edi)\n\t"
+
+        "movb %%bl,%%al\n\t"
+        "movb %%dl,%%cl\n\t"
+        "shrb $4,%%al\n\t"
+        "shrb $4,%%cl\n\t"
+        "andb $3,%%al\n\t"
+        "andb $3,%%cl\n\t"
+        "movb (%%esi,%%eax),%%bh\n\t"
+        "movb (%%esi,%%ecx),%%dh\n\t"
+        "movb %%bh,2(%%edi)\n\t"
+        "movb %%dh,3(%%edi)\n\t"
+
+//        "movb %%bl,%%al\n\t"
+//        "movb %%dl,%%cl\n\t"
+       "xorb %%bh,%%bh\n\t"
+       "xorb %%dh,%%dh\n\t"
+        "shrb $6,%%bl\n\t"
+        "shrb $6,%%dl\n\t"
+        "movb (%%esi,%%ebx),%%al\n\t"
+        "movb (%%esi,%%edx),%%cl\n\t"
+        "movb %%al,0(%%edi)\n\t"
+        "movb %%cl,1(%%edi)\n\t"
+       : "=S" (dummy), "=a" (dummy1), "=b" (dummy2)
+        : "D" (P), "S" (C), "a" (cc), "b" (PALRAM)
+        : "%ecx", "%edx"
+        );
+
+}
+#else
+        {
+        uint8 *S=PALRAM+cc;
+        register uint8 c1,c2;
+         
+        c1=((C[0]>>1)&0x55)|(C[8]&0xAA);
+         c2=(C[0]&0x55)|((C[8]<<1)&0xAA);
+
+         P[6]=S[c1&3];
+         P[7]=S[c2&3];
+         P[4]=S[(c1>>2)&3];
+         P[5]=S[(c2>>2)&3];
+         P[2]=S[(c1>>4)&3];
+         P[3]=S[(c2>>4)&3];
+
+         P[0]=S[c1>>6];
+         P[1]=S[c2>>6];
+        }
+#endif
diff --git a/fds.c b/fds.c
new file mode 100644 (file)
index 0000000..07445e7
--- /dev/null
+++ b/fds.c
@@ -0,0 +1,709 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "types.h"
+#include "x6502.h"
+#include "version.h"
+#include "fce.h"
+#include "fds.h"
+#include "svga.h"
+#include "sound.h"
+#include "general.h"
+#include "state.h"
+#include "file.h"
+#include "memory.h"
+#include "cart.h"
+
+/*     TODO:  Add code to put a delay in between the time a disk is inserted
+       and the when it can be successfully read/written to.  This should
+       prevent writes to wrong places OR add code to prevent disk ejects
+       when the virtual motor is on(mmm...virtual motor).
+*/
+
+static DECLFR(FDSRead4030);
+static DECLFR(FDSRead4031);
+static DECLFR(FDSRead4032);
+static DECLFR(FDSRead4033);
+static DECLFW(FDSWrite4020);
+static DECLFW(FDSWrite4021);
+static DECLFW(FDSWrite4022);
+static DECLFW(FDSWrite4023);
+static DECLFW(FDSWrite4024);
+static DECLFW(FDSWrite4025);
+static DECLFW(FDSWaveWrite);
+static DECLFR(FDSWaveRead);
+
+static DECLFR(FDSSRead);
+static DECLFW(FDSSWrite);
+static DECLFR(FDSBIOSRead);
+static DECLFR(FDSRAMRead);
+static DECLFW(FDSRAMWrite);
+static void FDSInit(void);
+static void FDSReset(void);
+static void FP_FASTAPASS(1) FDSFix(int a);
+
+#define FDSRAM GameMemBlock
+#define mapbyte1 (GameMemBlock+32768)
+#define mapbyte2 (GameMemBlock+32768+8)
+#define mapbyte3 (GameMemBlock+32768+16)
+#define mapbyte4 (GameMemBlock+32768+24)        // 8 bytes
+#define CHRRAM   (GameMemBlock+32768+32+64)
+
+#define IRQLatch       (*(int32*)(CHRRAM+8192))
+#define IRQCount       (*(int32*)(CHRRAM+8192+4))
+#define IRQa           (*(CHRRAM+8192+8))
+
+static void FDSClose(void);
+static uint8 header[16];
+#define writeskip mapbyte2[0]
+
+static char FDSSaveName[2048];
+
+uint8 FDSBIOS[8192];
+uint8 *diskdata[4]={0,0,0,0};
+
+#define SideWrite mapbyte2[1]
+#define DiskPtr (*(uint32*)(mapbyte2+4))
+#define dsr0 mapbyte2[2]
+#define dsr1 mapbyte2[3]
+
+#define DC_INC         1
+
+#define DiskSeekIRQ (*(int32*)(mapbyte3+4))
+#define SelectDisk mapbyte3[0]
+#define InDisk    mapbyte3[1]
+
+static void FDSReset(void)
+{
+        memset(mapbyte1,0,8);
+        memset(mapbyte2,0,8);
+        memset(mapbyte3+4,0,4);
+        memset(mapbyte4,0,8);
+}
+
+void FDSGI(int h)
+{
+ switch(h)
+ {
+  case GI_CLOSE: FDSClose();break;
+  case GI_POWER: FDSReset();FDSInit();break;
+ }
+}
+
+static void FDSStateRestore(int version)
+{ 
+ setmirror(((mapbyte1[5]&8)>>3)^1);
+}
+
+void FDSSound();
+void FDSSoundReset(void);
+void FDSSoundStateAdd(void);
+static void RenderSound(void);
+
+static void FDSInit(void)
+{
+ dsr0=0;
+ dsr1=0x41;
+ setmirror(1);
+ if(InDisk!=255)
+  dsr1&=0xFE;
+
+ setprg8r(0,0xe000,0);          // BIOS
+ setprg32r(1,0x6000,0);         // 32KB RAM
+ setchr8(0);           // 8KB CHR RAM
+
+ MapIRQHook=FDSFix;
+ GameStateRestore=FDSStateRestore;
+
+ SetReadHandler(0x4030,0x4030,FDSRead4030);
+ SetReadHandler(0x4031,0x4031,FDSRead4031);
+ SetReadHandler(0x4032,0x4032,FDSRead4032);
+ SetReadHandler(0x4033,0x4033,FDSRead4033);
+
+ SetWriteHandler(0x4020,0x4020,FDSWrite4020); 
+ SetWriteHandler(0x4021,0x4021,FDSWrite4021);
+ SetWriteHandler(0x4022,0x4022,FDSWrite4022);
+ SetWriteHandler(0x4023,0x4023,FDSWrite4023);
+ SetWriteHandler(0x4024,0x4024,FDSWrite4024);
+ SetWriteHandler(0x4025,0x4025,FDSWrite4025);
+
+ SetWriteHandler(0x6000,0xdfff,FDSRAMWrite);
+ SetReadHandler(0x6000,0xdfff,FDSRAMRead);
+ SetReadHandler(0xE000,0xFFFF,FDSBIOSRead);
+
+ IRQCount=IRQLatch=IRQa=0;
+
+ FDSSoundReset();
+}
+
+void FDSControl(int what)
+{
+ switch(what)
+ {
+  case FDS_IDISK:dsr1&=0xFE;
+                 if(InDisk==255)
+                {
+                 FCEU_DispMessage("Disk %d Side %s Inserted",
+                 SelectDisk>>1,(SelectDisk&1)?"B":"A");
+                 InDisk=SelectDisk;
+                }
+                else
+                 FCEU_DispMessage("Jamming disks is a BAD IDEA");
+                break;
+  case FDS_EJECT:
+                if(InDisk!=255)
+                 FCEU_DispMessage("Disk Ejected");
+                else
+                 FCEU_DispMessage("Cannot Eject Air");
+                dsr1|=1;
+                InDisk=255;
+                break;
+  case FDS_SELECT:
+                 if(InDisk!=255)
+                 {
+                  FCEU_DispMessage("Eject disk before selecting.");
+                  break;
+                 }
+                 SelectDisk=((SelectDisk+1)%header[4])&3;
+                 FCEU_DispMessage("Disk %d Side %s Selected",
+                       SelectDisk>>1,(SelectDisk&1)?"B":"A");
+                 break;
+ }
+}
+
+static void FP_FASTAPASS(1) FDSFix(int a)
+{
+ if(IRQa)
+ {
+  IRQCount-=a;
+  if(IRQCount<=0)
+  {
+   IRQa=0;
+   dsr0|=1;
+   dsr0&=~2;
+   IRQCount=0xFFFF;
+   X6502_IRQBegin(FCEU_IQEXT);
+  }
+ }
+ if(DiskSeekIRQ>0) 
+ {
+  DiskSeekIRQ-=a;
+  if(DiskSeekIRQ<=0)
+  {
+   if(mapbyte1[5]&0x80)
+   {
+    dsr0&=~1;
+    dsr0|=2;
+    TriggerIRQ();
+   }
+  }
+ }
+}
+
+void DiskControl(int which)
+{
+if(mapbyte1[5]&1)
+ {
+  switch(which)
+  {
+  case DC_INC:
+              if(DiskPtr<64999) DiskPtr++;
+              //DiskSeekIRQ=160+100;
+              //DiskSeekIRQ=140;
+              //DiskSeekIRQ=160;
+               DiskSeekIRQ=150;
+              break;
+  }
+ }
+}
+static DECLFR(FDSRead4030)
+{
+       X6502_IRQEnd(FCEU_IQEXT);
+       return dsr0;
+}
+
+static DECLFR(FDSRead4031)
+{
+       static uint8 z=0;
+       if(InDisk!=255)
+       {
+         z=diskdata[InDisk][DiskPtr];
+         DiskControl(DC_INC);
+       }
+        return z;
+}
+
+static DECLFR(FDSRead4032)
+{
+       return dsr1;
+}
+
+static DECLFR(FDSRead4033)
+{
+       return 0x80; // battery
+}
+
+static DECLFW(FDSRAMWrite)
+{
+ (FDSRAM-0x6000)[A]=V;
+}
+
+static DECLFR(FDSBIOSRead)
+{
+ return (FDSBIOS-0xE000)[A];
+}
+
+static DECLFR(FDSRAMRead)
+{
+ return (FDSRAM-0x6000)[A];
+}
+
+/* Begin FDS sound */
+
+#define FDSClock (1789772.7272727272727272/8)
+
+typedef struct {
+        int64 cycles;           // Cycles per PCM sample
+        int64 count;           // Cycle counter
+       int64 envcount;         // Envelope cycle counter
+       uint32 b19shiftreg60;
+       uint32 b24adder66;
+       uint32 b24latch68;
+       uint32 b17latch76;
+        int32 clockcount;      // Counter to divide frequency by 8.
+       uint8 b8shiftreg88;     // Modulation register.
+       uint8 amplitude[2];     // Current amplitudes.
+        uint8 mwave[0x20];      // Modulation waveform
+        uint8 cwave[0x40];      // Game-defined waveform(carrier)
+        uint8 SPSG[0xB];
+} FDSSOUND;
+
+static FDSSOUND fdso;
+
+#define        SPSG    fdso.SPSG
+#define b19shiftreg60  fdso.b19shiftreg60
+#define b24adder66     fdso.b24adder66
+#define b24latch68     fdso.b24latch68
+#define b17latch76     fdso.b17latch76
+#define b8shiftreg88   fdso.b8shiftreg88
+#define clockcount     fdso.clockcount
+#define amplitude      fdso.amplitude
+
+void FDSSoundStateAdd(void)
+{
+ AddExState(fdso.cwave,64,0,"WAVE");
+ AddExState(fdso.mwave,32,0,"MWAV");
+ AddExState(amplitude,2,0,"AMPL");
+ AddExState(SPSG,0xB,0,"SPSG");
+
+ AddExState(&b8shiftreg88,1,0,"B88");
+
+ AddExState(&clockcount, 4, 1, "CLOC");
+ AddExState(&b19shiftreg60,4,1,"B60");
+ AddExState(&b24adder66,4,1,"B66");
+ AddExState(&b24latch68,4,1,"B68");
+ AddExState(&b17latch76,4,1,"B76");
+
+}
+
+static DECLFR(FDSSRead)
+{
+ switch(A&0xF)
+ {
+  case 0x0:return(amplitude[0]|(X.DB&0xC0));
+  case 0x2:return(amplitude[1]|(X.DB&0xC0));
+ }
+ return(X.DB);
+}
+
+static DECLFW(FDSSWrite)
+{
+ if(FSettings.SndRate)
+  RenderSound();
+ A-=0x4080;
+ switch(A)
+ {
+  case 0x0: 
+  case 0x4:
+           if(!(V&0x80))
+           {
+             // if(V&0x40) amplitude[(A&0xF)>>2]=0;
+             // else amplitude[(A&0xF)>>2]=0x3F;
+           }
+           else 
+            amplitude[(A&0xF)>>2]=V&0x3F;
+           break;
+  case 0x7: b17latch76=0;SPSG[0x5]=0;break;
+  case 0x8:
+          //printf("%d:$%02x\n",SPSG[0x5],V);
+          fdso.mwave[SPSG[0x5]&0x1F]=V&0x7;
+           SPSG[0x5]=(SPSG[0x5]+1)&0x1F;
+          break;
+ }
+ //if(A>=0x7 && A!=0x8 && A<=0xF)
+ //if(A==0xA || A==0x9) printf("$%04x:$%02x\n",A,V);
+ SPSG[A]=V;
+}
+
+// $4080 - Fundamental wave amplitude data register 92
+// $4082 - Fundamental wave frequency data register 58
+// $4083 - Same as $4082($4083 is the upper 4 bits).
+
+// $4084 - Modulation amplitude data register 78
+// $4086 - Modulation frequency data register 72
+// $4087 - Same as $4086($4087 is the upper 4 bits)
+
+
+static void DoEnv()
+{
+ int x;
+
+ for(x=0;x<2;x++)
+  if(!(SPSG[x<<2]&0x80) && !(SPSG[0x9+x]&0x80))
+  {
+   static int counto[2]={0,0};
+
+   if(counto[x]<=0)
+   {
+    if(SPSG[x<<2]&0x40)
+    {
+     if(amplitude[x]<0x3F)
+      amplitude[x]++;
+    }
+    else
+    {
+     if(amplitude[x]>0)
+      amplitude[x]--;
+    }
+    counto[x]=(SPSG[x<<2]&0x3F);
+   }
+   else
+    counto[x]--;
+  }
+}
+
+static DECLFR(FDSWaveRead)
+{
+ return(fdso.cwave[A&0x3f]|(X.DB&0xC0));
+}
+
+static DECLFW(FDSWaveWrite)
+{
+ if(SPSG[0x9]&0x80)
+  fdso.cwave[A&0x3f]=V&0x3F;
+}
+
+static INLINE void ClockRise(void)
+{
+ if(!clockcount)
+ {
+  b19shiftreg60=(SPSG[0x2]|((SPSG[0x3]&0xF)<<8));
+  b17latch76=(SPSG[0x6]|((SPSG[0x07]&0x3)<<8))+b17latch76;
+
+  if(!(SPSG[0x7]&0x80))
+  {
+   b8shiftreg88=(amplitude[1]*((fdso.mwave[(b17latch76>>11)&0x1F]&7)));
+   //b8shiftreg88=((fdso.mwave[(b17latch76>>11)&0x1F]&7))|(amplitude[1]<<3);
+  }
+  else
+  { b8shiftreg88=0;}
+ }
+ else
+ {
+  b19shiftreg60<<=1;  
+  b8shiftreg88>>=1;
+ }
+ b24adder66=(b24latch68+b19shiftreg60)&0xFFFFFF;
+}
+
+static INLINE void ClockFall(void)
+{
+// if(!(SPSG[0x7]&0x80))
+ {
+  if(!(b8shiftreg88&1))
+   b24latch68=b24adder66;
+ }
+ clockcount=(clockcount+1)&7;
+}
+
+static INLINE int32 FDSDoSound(void)
+{
+ fdso.count+=fdso.cycles;
+ if(fdso.count>=((int64)1<<40))
+ {
+  dogk:
+  fdso.count-=(int64)1<<40;
+  ClockRise();
+  ClockFall();
+ }
+ if(fdso.count>=32768) goto dogk;
+
+ fdso.envcount-=fdso.cycles;
+ if(fdso.envcount<=0)
+ {
+  // Fix this?
+  fdso.envcount+=((int64)1<<40)*FDSClock/1024;
+  DoEnv();
+ }
+
+ // Might need to emulate applying the amplitude to the waveform a bit better...
+ return (fdso.cwave[b24latch68>>18]*amplitude[0]);
+}
+
+static int32 FBC=0;
+
+static void RenderSound(void)
+{
+ int32 end, start;
+ int32 x;
+
+ start=FBC;
+ end=(timestamp<<16)/soundtsinc;
+ if(end<=start)
+  return;
+ FBC=end;
+
+ if(!(SPSG[0x9]&0x80))
+  for(x=start;x<end;x++)
+  {
+   uint32 t=FDSDoSound();
+   Wave[x>>4]+=t>>3;
+  }
+}
+
+void FDSSound(int c)
+{
+  RenderSound();
+  FBC=c;
+}
+
+static void FDS_ESI(void)
+{
+ if(FSettings.SndRate)
+ {
+  fdso.cycles=((int64)1<<40)*FDSClock;
+  fdso.cycles/=FSettings.SndRate OVERSAMPLE;
+ }
+//  fdso.cycles=(int64)32768*FDSClock/(FSettings.SndRate OVERSAMPLE);
+ SetReadHandler(0x4040,0x407f,FDSWaveRead);
+ SetWriteHandler(0x4040,0x407f,FDSWaveWrite);
+ SetWriteHandler(0x4080,0x408A,FDSSWrite);
+ SetReadHandler(0x4090,0x4092,FDSSRead);
+}
+
+void FDSSoundReset(void)
+{
+ memset(&fdso,0,sizeof(fdso));
+ FDS_ESI();
+ GameExpSound.Fill=FDSSound;
+ GameExpSound.RChange=FDS_ESI;
+}
+
+
+static DECLFW(FDSWrite4020)
+{
+       X6502_IRQEnd(FCEU_IQEXT);
+       IRQLatch&=0xFF00;
+       IRQLatch|=V;
+       mapbyte1[0]=V;
+}
+static DECLFW(FDSWrite4021)
+{
+       X6502_IRQEnd(FCEU_IQEXT);
+       IRQLatch&=0xFF;
+       IRQLatch|=V<<8;
+       mapbyte1[1]=V;
+}
+static DECLFW(FDSWrite4022)
+{
+       X6502_IRQEnd(FCEU_IQEXT);
+       IRQCount=IRQLatch;
+       IRQa=V&2;
+       mapbyte1[2]=V;
+}
+static DECLFW(FDSWrite4023)
+{
+       mapbyte1[3]=V;
+}
+static DECLFW(FDSWrite4024)
+{
+        if(InDisk!=255 && !(mapbyte1[5]&0x4) && mapbyte1[3]&0x1)
+        {
+         if(DiskPtr>=0 && DiskPtr<65000)
+         {
+          if(writeskip) writeskip--;
+          else if(DiskPtr>=2)
+          {
+           SideWrite|=1<<InDisk;
+           diskdata[InDisk][DiskPtr-2]=V;
+          }
+         }
+        }
+}
+static DECLFW(FDSWrite4025)
+{
+       if(InDisk!=255)
+       {
+         if(!(V&0x40))
+         {
+          if(mapbyte1[5]&0x40 && !(V&0x10))
+          {
+           DiskSeekIRQ=200;
+           DiskPtr-=2;
+          }
+          if(DiskPtr<0) DiskPtr=0;
+         }
+         if(!(V&0x4)) writeskip=2;
+         if(V&2) {DiskPtr=0;DiskSeekIRQ=200;}
+         if(V&0x40) DiskSeekIRQ=200;
+       }
+       mapbyte1[5]=V;
+        setmirror(((V>>3)&1)^1);
+}
+static void FreeFDSMemory(void)
+{
+ int x;
+
+ for(x=0;x<header[4];x++)
+  if(diskdata[x])
+  {
+   free(diskdata[x]);
+   diskdata[x]=0;
+  }
+}
+
+int FDSLoad(char *name, int fp)
+{
+ FILE *zp;
+ int x;
+
+ FCEU_fseek(fp,0,SEEK_SET);
+ FCEU_fread(header,16,1,fp);
+
+ if(memcmp(header,"FDS\x1a",4)) 
+ {
+  if(!(memcmp(header+1,"*NINTENDO-HVC*",14)))
+  {
+   long t;   
+   t=FCEU_fgetsize(fp);
+   if(t<65500)
+    t=65500;
+   header[4]=t/65500;
+   header[0]=0;
+   FCEU_fseek(fp,0,SEEK_SET);
+  }
+  else
+   return 0; 
+ } 
+
+ if(header[4]>4) header[4]=4;
+ if(!header[4]) header[4]|=1;
+ for(x=0;x<header[4];x++)
+ {
+  diskdata[x]=FCEU_malloc(65500);
+  if(!diskdata[x]) 
+  {
+   int zol;
+   for(zol=0;zol<x;zol++)
+    free(diskdata[zol]);
+   return 0;
+  }
+  FCEU_fread(diskdata[x],1,65500,fp);
+ }
+
+ if(!(zp=fopen(FCEU_MakeFName(FCEUMKF_FDSROM,0,0),"rb"))) 
+ {
+  FCEU_PrintError("FDS BIOS ROM image missing!");
+  FreeFDSMemory();
+  return 0;
+ }
+
+ if(fread(FDSBIOS,1,8192,zp)!=8192)
+ {
+  fclose(zp);
+  FreeFDSMemory();
+  FCEU_PrintError("Error reading FDS BIOS ROM image");
+  return 0;
+ }
+
+ fclose(zp);
+
+ FCEUGameInfo.type=GIT_FDS;
+ strcpy(FDSSaveName,name);
+ GameInterface=FDSGI;
+
+ SelectDisk=0;
+ InDisk=255;
+
+ ResetExState();
+ FDSSoundStateAdd();
+
+ for(x=0;x<header[4];x++)
+ {
+  char temp[5];
+  sprintf(temp,"DDT%d",x);
+  AddExState(diskdata[x],65500,0,temp);
+ }
+
+ AddExState(FDSRAM,32768,0,"FDSR");
+ AddExState(mapbyte1,32,0,"MPBY");
+ AddExState(CHRRAM,8192,0,"CHRR");
+ AddExState(&IRQCount, 4, 1, "IRQC");
+ AddExState(&IRQLatch, 4, 1, "IQL1");
+ AddExState(&IRQa, 1, 0, "IRQA");
+
+
+ ResetCartMapping();
+
+ SetupCartCHRMapping(0,CHRRAM,8192,1);
+ SetupCartMirroring(0,0,0);
+
+ return 1;
+}
+
+void FDSClose(void)
+{
+  int fp;
+  int x;
+
+  fp=FCEU_fopen(FDSSaveName,"wb");
+  if(!fp) return;
+
+  if(header[0])                        // Does it have a 16-byte FWNES-style header?
+   if(FCEU_fwrite(header,1,16,fp)!=16) // Write it out.  Should be nicer than fseek()'ing if the file is compressed.  Hopefully...
+    goto fdswerr;
+
+  for(x=0;x<header[4];x++)
+  {
+   if(FCEU_fwrite(diskdata[x],1,65500,fp)!=65500) 
+   {
+    fdswerr:
+    FCEU_PrintError("Error writing FDS image \"%s\"!",FDSSaveName);
+    FCEU_fclose(fp);
+    return;
+   }
+  }
+  FreeFDSMemory();
+  FCEU_fclose(fp);
+}
diff --git a/fds.h b/fds.h
new file mode 100644 (file)
index 0000000..9e526db
--- /dev/null
+++ b/fds.h
@@ -0,0 +1,8 @@
+void FDSControl(int what);
+
+#define FDS_IDISK  1
+#define FDS_EJECT  2
+#define FDS_SELECT 3
+
+int FDSLoad(char *name, int fp);
+void FDSSoundReset(void);
diff --git a/file.c b/file.c
new file mode 100644 (file)
index 0000000..d9d3a52
--- /dev/null
+++ b/file.c
@@ -0,0 +1,407 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef ZLIB
+ #include <zlib.h>
+ #include "zlib/unzip.h"
+#endif
+
+#include "types.h"
+#include "file.h"
+#include "endian.h"
+#include "memory.h"
+#include "driver.h"
+
+static void *desctable[8]={0,0,0,0,0,0,0,0};
+static int x;
+
+#ifdef ZLIB
+
+typedef struct {
+           uint8 *data;
+           uint32 size;
+           uint32 location;
+} ZIPWRAP;
+
+void *MakeZipWrap(void *tz)
+{
+ unz_file_info ufo;
+ ZIPWRAP *tmp;
+
+ if(!(tmp=FCEU_malloc(sizeof(ZIPWRAP))))
+  goto doret;
+ unzGetCurrentFileInfo(tz,&ufo,0,0,0,0,0,0);  
+
+ tmp->location=0;
+ tmp->size=ufo.uncompressed_size;
+ if(!(tmp->data=FCEU_malloc(ufo.uncompressed_size)))
+ {
+  tmp=0;
+  goto doret;
+ }
+
+ unzReadCurrentFile(tz,tmp->data,ufo.uncompressed_size);
+
+ doret:
+
+ unzCloseCurrentFile(tz);
+ unzClose(tz);
+ return tmp;
+}
+#endif
+
+#ifndef __GNUC__
+ #define strcasecmp strcmp
+#endif
+
+int FASTAPASS(2) FCEU_fopen(char *path, char *mode)
+{
+ void *t;
+
+ #ifdef ZLIB
+  unzFile tz;
+  if((tz=unzOpen(path)))  // If it's not a zip file, use regular file handlers.
+                         // Assuming file type by extension usually works,
+                         // but I don't like it. :)
+  {
+   if(unzGoToFirstFile(tz)==UNZ_OK)
+   {
+    for(;;)
+    {
+     char tempu[512];  // Longer filenames might be possible, but I don't
+                       // think people would name files that long in zip files...
+     unzGetCurrentFileInfo(tz,0,tempu,512,0,0,0,0);
+     tempu[511]=0;
+     if(strlen(tempu)>=4)
+     {
+      char *za=tempu+strlen(tempu)-4;
+      if(!strcasecmp(za,".nes") || !strcasecmp(za,".fds") ||
+         !strcasecmp(za,".nsf") || !strcasecmp(za,".unf") ||
+         !strcasecmp(za,".nez"))
+       break;
+     }
+     if(strlen(tempu)>=5)
+     {
+      if(!strcasecmp(tempu+strlen(tempu)-5,".unif"))
+       break;
+     }
+     if(unzGoToNextFile(tz)!=UNZ_OK)
+     { 
+      if(unzGoToFirstFile(tz)!=UNZ_OK) goto zpfail;
+      break;     
+     }
+    }
+    if(unzOpenCurrentFile(tz)!=UNZ_OK)
+     goto zpfail;       
+   }
+   else
+   {
+    zpfail:
+    unzClose(tz);
+    return 0;
+   }
+
+   for(x=0;x<8;x++)
+    if(!desctable[x])
+    {
+     if(!(desctable[x]=MakeZipWrap(tz)))
+      return(0);
+     return((x+1)|0x8000);
+    }
+  }
+#endif
+
+ #ifdef ZLIB
+ if((t=fopen(path,"rb")))
+ {
+  uint32 magic;
+
+  magic=fgetc(t);
+  magic|=fgetc(t)<<8;
+  magic|=fgetc(t)<<16;
+
+  fclose(t);
+
+  if(magic==0x088b1f)
+  {
+   if((t=gzopen(path,mode)))
+    for(x=0;x<8;x++)
+     if(!desctable[x])
+     {
+      desctable[x]=t;
+      return((x+1)|0x4000);
+     }
+  }
+ }
+ #endif
+
+  if((t=fopen(path,mode)))
+  {
+   fseek(t,0,SEEK_SET);
+   for(x=0;x<8;x++)
+    if(!desctable[x])
+    {
+     desctable[x]=t;
+     return(x+1);
+    }
+  }
+ return 0;
+}
+
+int FASTAPASS(1) FCEU_fclose(int stream)
+{
+ #ifdef ZLIB
+ if(stream&0x4000)
+ {
+  gzclose(desctable[(stream&255)-1]);
+  desctable[(stream&255)-1]=0;
+ }
+ else if(stream&0x8000)
+ {
+  free(((ZIPWRAP*)desctable[(stream&255)-1])->data);
+  free(desctable[(stream&255)-1]);
+  desctable[(stream&255)-1]=0;
+ }
+ else // close zip file
+ {
+ #endif
+  fclose(desctable[stream-1]);
+  desctable[stream-1]=0;
+ #ifdef ZLIB
+ }
+ #endif
+ return 1;
+}
+
+size_t FASTAPASS(3) FCEU_fread(void *ptr, size_t size, size_t nmemb, int stream)
+{
+ #ifdef ZLIB
+ if(stream&0x4000)
+ {
+  return gzread(desctable[(stream&255)-1],ptr,size*nmemb);
+ }
+ else if(stream&0x8000)
+ { 
+  ZIPWRAP *wz;
+  uint32 total=size*nmemb;
+
+  wz=(ZIPWRAP*)desctable[(stream&255)-1];
+  if(wz->location>=wz->size) return 0;
+
+  if((wz->location+total)>wz->size)
+  {
+   int ak=wz->size-wz->location;
+   memcpy((uint8*)ptr,wz->data+wz->location,ak);
+   wz->location=wz->size;
+   return(ak/size);
+  }
+  else
+  {
+   memcpy((uint8*)ptr,wz->data+wz->location,total);
+   wz->location+=total;
+   return nmemb;
+  }
+ }
+ else
+ {
+ #endif
+ return fread(ptr,size,nmemb,desctable[stream-1]);
+ #ifdef ZLIB
+ }
+ #endif
+}
+
+size_t FASTAPASS(3) FCEU_fwrite(void *ptr, size_t size, size_t nmemb, int stream)
+{
+ #ifdef ZLIB
+ if(stream&0x4000)
+ {
+  return gzwrite(desctable[(stream&255)-1],ptr,size*nmemb);
+ }
+ else if(stream&0x8000)
+ { 
+  return 0;
+ }
+ else
+ #endif
+  return fwrite(ptr,size,nmemb,desctable[stream-1]);
+}
+
+int FASTAPASS(3) FCEU_fseek(int stream, long offset, int whence)
+{
+ #ifdef ZLIB
+ if(stream&0x4000)
+ {
+  return gzseek(desctable[(stream&255)-1],offset,whence);
+ } 
+ else if(stream&0x8000)
+ {
+  ZIPWRAP *wz;
+  wz=(ZIPWRAP*)desctable[(stream&255)-1];
+
+  switch(whence)
+  {
+   case SEEK_SET:if(offset>=wz->size)
+                  return(-1);
+                 wz->location=offset;break;
+   case SEEK_CUR:if(offset+wz->location>wz->size)
+                  return (-1);
+                 wz->location+=offset;
+                 break;
+  }    
+  return 0;
+ }
+ else
+ #endif
+  return fseek(desctable[stream-1],offset,whence);
+}
+
+long FASTAPASS(1) FCEU_ftell(int stream)
+{
+ #ifdef ZLIB
+ if(stream&0x4000)
+ {
+  return gztell(desctable[(stream&255)-1]);
+ }
+ else if(stream&0x8000)
+ { 
+  return (((ZIPWRAP *)desctable[(stream&255)-1])->location);  
+ }
+ else
+ #endif
+  return ftell(desctable[stream-1]);
+}
+
+void FASTAPASS(1)FCEU_rewind(int stream)
+{
+ #ifdef ZLIB
+ if(stream&0x4000)
+ {
+  gzrewind(desctable[(stream&255)-1]);
+ }
+ else if(stream&0x8000)
+ {
+  ((ZIPWRAP *)desctable[(stream&255)-1])->location=0;
+ }
+ else
+ #endif
+ #ifdef _WIN32_WCE
+  fseek(desctable[stream-1],0,SEEK_SET);
+ #else
+  rewind(desctable[stream-1]);
+ #endif 
+}
+
+int FASTAPASS(2) FCEU_read32(void *Bufo, int stream)
+{
+ #ifdef ZLIB
+ if(stream&0xC000)
+ { 
+  uint8 t[4];
+  #ifndef LSB_FIRST
+  uint8 x[4];
+  #endif
+  if(stream&0x8000)
+  { 
+   ZIPWRAP *wz;
+   wz=(ZIPWRAP*)desctable[(stream&255)-1];
+   if(wz->location+4>wz->size)
+    {return 0;}
+   *(uint32 *)t=*(uint32 *)(wz->data+wz->location);
+   wz->location+=4;
+  }
+  else if(stream&0x4000)
+   gzread(desctable[(stream&255)-1],&t,4);
+  #ifndef LSB_FIRST
+  x[0]=t[3];
+  x[1]=t[2];
+  x[2]=t[1];
+  x[3]=t[0];
+  *(uint32*)Bufo=*(uint32*)x;
+  #else
+  *(uint32*)Bufo=*(uint32*)t;
+  #endif
+  return 1;
+ }
+ else
+ #endif
+ {
+  return read32(Bufo,desctable[stream-1]);
+ }
+}
+
+int FASTAPASS(1) FCEU_fgetc(int stream)
+{
+ #ifdef ZLIB
+ if(stream&0x4000)
+  return gzgetc(desctable[(stream&255)-1]); 
+ else if(stream&0x8000)
+ {
+  ZIPWRAP *wz;
+  wz=(ZIPWRAP*)desctable[(stream&255)-1];
+  if(wz->location<wz->size)
+   return wz->data[wz->location++];
+  return EOF;
+ }
+ else
+#endif
+  return fgetc(desctable[stream-1]);
+}
+
+long FASTAPASS(1) FCEU_fgetsize(int stream)
+{
+ #ifdef ZLIB
+ if(stream&0x4000)
+ {
+  int x,t;
+  t=gztell(desctable[(stream&255)-1]);
+  gzrewind(desctable[(stream&255)-1]);
+  for(x=0;gzgetc(desctable[(stream&255)-1]) != EOF; x++);
+  gzseek(desctable[(stream&255)-1],t,SEEK_SET);
+  return(x);
+ }
+ else if(stream&0x8000)
+  return ((ZIPWRAP*)desctable[(stream&255)-1])->size;
+ else
+ #endif
+ {
+  long t,r;
+  t=ftell(desctable[stream-1]);
+  fseek(desctable[stream-1],0,SEEK_END);
+  r=ftell(desctable[stream-1]);
+  fseek(desctable[stream-1],t,SEEK_SET);
+  return r;
+ }
+}
+
+int FASTAPASS(1) FCEU_fisarchive(int stream)
+{
+ #ifdef ZLIB
+ if(stream&0x8000)
+  return 1;
+ #endif
+ return 0;
+}
diff --git a/file.h b/file.h
new file mode 100644 (file)
index 0000000..3c70f97
--- /dev/null
+++ b/file.h
@@ -0,0 +1,12 @@
+int FASTAPASS(2) FCEU_fopen(char *path, char *mode);
+int FASTAPASS(1) FCEU_fclose(int stream);
+size_t FASTAPASS(3) FCEU_fread(void *ptr, size_t size, size_t nmemb, int stream);
+size_t FASTAPASS(3) FCEU_fwrite(void *ptr, size_t size, size_t nmemb, int stream);
+int FASTAPASS(3) FCEU_fseek(int stream, long offset, int whence);
+long FASTAPASS(1) FCEU_ftell(int stream);
+void FASTAPASS(1) FCEU_rewind(int stream);
+int FASTAPASS(2) FCEU_read32(void *Bufo, int fp);
+int FASTAPASS(1) FCEU_fgetc(int stream);
+long FASTAPASS(1) FCEU_fgetsize(int stream);
+int FASTAPASS(1) FCEU_fisarchive(int stream);
+
diff --git a/general.c b/general.c
new file mode 100644 (file)
index 0000000..b0c1942
--- /dev/null
+++ b/general.c
@@ -0,0 +1,169 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "types.h"
+
+#include "general.h"
+#include "state.h"
+#include "version.h"
+#include "svga.h"
+#include "driver.h"
+
+char *marray[1]={"Error allocating memory!"};
+
+static char BaseDirectory[2048];
+static char FileBase[2048];
+static char FileExt[2048];
+static char FileBaseDirectory[2048];
+
+void FCEUI_SetBaseDirectory(char *dir)
+{
+ strncpy(BaseDirectory,dir,2047);
+ BaseDirectory[2047]=0;
+}
+
+static char *odirs[FCEUIOD__COUNT]={0,0,0,0,0};     // odirs, odors. ^_^
+
+void FCEUI_SetDirOverride(int which, char *n)
+{
+ odirs[which]=n;
+ if(which==FCEUIOD_STATE)
+  SaveStateRefresh();
+}
+
+/* We should probably use snprintf(), but many C libraries don't seem to
+   have this function.
+*/
+char *FCEU_MakeFName(int type, int id1, char *cd1)
+{
+ static uint8 ret[2048];
+
+ ret[0]=0;
+ switch(type)
+ {
+  case FCEUMKF_STATE:if(odirs[FCEUIOD_STATE])
+                      sprintf(ret,"%s"PSS"%s.fc%d",odirs[FCEUIOD_STATE],FileBase,id1);
+                     else
+                      sprintf(ret,"%s"PSS"fcs"PSS"%s.fc%d",BaseDirectory,FileBase,id1);
+                     break;
+  case FCEUMKF_SNAP:
+                   if(FSettings.SnapName)
+                   {
+                     if(odirs[FCEUIOD_SNAPS])
+                      sprintf(ret,"%s"PSS"%s-%d.%s",odirs[FCEUIOD_SNAPS],FileBase,id1,cd1);
+                     else
+                      sprintf(ret,"%s"PSS"snaps"PSS"%s-%d.%s",BaseDirectory,FileBase,id1,cd1);
+                   }
+                   else
+                   {
+                    if(odirs[FCEUIOD_SNAPS])
+                      sprintf(ret,"%s"PSS"%d.%s",odirs[FCEUIOD_SNAPS],id1,cd1);
+                     else
+                      sprintf(ret,"%s"PSS"snaps"PSS"%d.%s",BaseDirectory,id1,cd1);
+                   }
+                    break;
+  case FCEUMKF_SAV:if(odirs[FCEUIOD_NV])
+                   {
+                    sprintf(ret,"%s"PSS"%s.%s",odirs[FCEUIOD_NV],FileBase,cd1);
+                   }
+                  else
+                   {
+                    if(FSettings.SUnderBase)
+                     sprintf(ret,"%s"PSS"sav"PSS"%s.%s",BaseDirectory,FileBase,cd1);
+                    else
+                     sprintf(ret,"%s"PSS"%s.%s",FileBaseDirectory,FileBase,cd1);
+                   }
+                   break;
+  case FCEUMKF_CHEAT:
+                     if(odirs[FCEUIOD_CHEATS])
+                      sprintf(ret,"%s"PSS"%s.cht",odirs[FCEUIOD_CHEATS],FileBase);
+                     else
+                      sprintf(ret,"%s"PSS"cheats"PSS"%s.cht",BaseDirectory,FileBase);
+                     break;
+  case FCEUMKF_GGROM:sprintf(ret,"%s"PSS"gg.rom",BaseDirectory);break;
+  case FCEUMKF_FDSROM:sprintf(ret,"%s"PSS"disksys.rom",BaseDirectory);break;
+  case FCEUMKF_PALETTE:
+                       if(odirs[FCEUIOD_MISC])
+                        sprintf(ret,"%s"PSS"%s.pal",odirs[FCEUIOD_MISC],FileBase);
+                       else
+                        sprintf(ret,"%s"PSS"gameinfo"PSS"%s.pal",BaseDirectory,FileBase);
+                       break;
+ }
+ return(ret);
+}
+
+void GetFileBase(char *f)
+{
+        char *tp1,*tp3;
+
+ #if PSS_STYLE==4
+     tp1=((char *)strrchr(f,':'));
+ #elif PSS_STYLE==1
+     tp1=((char *)strrchr(f,'/'));
+ #else
+     tp1=((char *)strrchr(f,'\\'));
+  #if PSS_STYLE!=3
+     tp3=((char *)strrchr(f,'/'));
+     if(tp1<tp3) tp1=tp3;
+  #endif
+ #endif
+     if(!tp1)
+     {
+      tp1=f;
+      strcpy(FileBaseDirectory,".");
+     }
+     else
+     {
+      memcpy(FileBaseDirectory,f,tp1-f);
+      FileBaseDirectory[tp1-f]=0;
+      tp1++;
+     }
+
+     if((tp3=strrchr(f,'.'))!=NULL)
+     {
+      memcpy(FileBase,tp1,tp3-tp1);
+      FileBase[tp3-tp1]=0;
+      strcpy(FileExt,tp3+1);
+     }
+     else
+     {
+      strcpy(FileBase,tp1);
+      FileExt[0]=0;
+     }
+}
+
+uint32 uppow2(uint32 n)
+{
+ int x;
+
+ for(x=31;x>=0;x--)
+  if(n&(1<<x))
+  {
+   if((1<<x)!=n)
+    return(1<<(x+1));
+   break;
+  }
+ return n;
+}
+
diff --git a/general.h b/general.h
new file mode 100644 (file)
index 0000000..2a874ff
--- /dev/null
+++ b/general.h
@@ -0,0 +1,14 @@
+void GetFileBase(char *f);
+#define MSG_ERRAM       marray[0]
+extern char *marray[];
+extern uint32 uppow2(uint32 n);
+
+char *FCEU_MakeFName(int type, int id1, char *cd1);
+
+#define FCEUMKF_STATE  1
+#define FCEUMKF_SNAP   2
+#define FCEUMKF_SAV    3
+#define FCEUMKF_CHEAT  4
+#define FCEUMKF_FDSROM 5
+#define FCEUMKF_PALETTE        6
+#define FCEUMKF_GGROM  7
diff --git a/git.h b/git.h
new file mode 100644 (file)
index 0000000..5dbc2b7
--- /dev/null
+++ b/git.h
@@ -0,0 +1,22 @@
+#ifndef __FCEU_GIT
+#define __FCEU_GIT
+/* Mmm...git. Almost as funny as "gimp". */
+#define GIT_CART        0      /* Cart. */
+#define GIT_VSUNI       1      /* VS Unisystem. */
+#define GIT_FDS         2      /* Famicom Disk System. */
+#define GIT_NSF         3      /* NES Sound Format. */
+
+#define GIV_NTSC       0       /* NTSC emulation. */
+#define GIV_PAL                1       /* PAL emulation. */
+#define GIV_USER       2       /* What was set by FCEUI_SetVidSys(). */
+       
+typedef struct {
+       char *name;
+        int type;       /* GIT_* */
+        int vidsys;     /* Current emulated video system; GIV_* */
+        int input[2];   /* Desired input for emulated input ports 1 and 2; -1
+                           for unknown desired input. */
+       int inputfc;    /* Desired Famicom expansion port device. -1 for unknown
+                          desired input. */
+} FCEUGI;
+#endif
diff --git a/ines.c b/ines.c
new file mode 100644 (file)
index 0000000..b71460d
--- /dev/null
+++ b/ines.c
@@ -0,0 +1,860 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 BERO 
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "types.h"
+#include "x6502.h"
+#include "fce.h"
+#define INESPRIV
+#include "ines.h"
+#include "version.h"
+#include "svga.h"
+#include "general.h"
+#include "state.h"
+#include "file.h"
+#include "memory.h"
+#include "cart.h"
+#include "crc32.h"
+#include "cheat.h"
+
+static DECLFR(VSRead);
+
+static uint8 *trainerpoo=0;
+static uint8 *ROM=NULL;
+uint8 *VROM=NULL;
+
+
+static uint32 ROM_size;
+uint32 VROM_size;
+
+static void CheckVSUni(void);
+static int MMC_init(int type);
+void (*MapClose)(void);
+void (*MapperReset)(void);
+
+static int MapperNo;
+static int SaveGame=0;
+
+static iNES_HEADER head;
+
+/*  MapperReset() is called when the NES is reset(with the reset button).  
+    Mapperxxx_init is called when the NES has been powered on.
+*/
+
+static void iNESGI(int h)
+{
+ switch(h)
+ {
+  case GI_RESETM2:
+               if(MapperReset)
+                MapperReset();
+               break;
+  case GI_POWER:
+               SetReadHandler(0x8000,0xFFFF,CartBR);
+                MMC_init(MapperNo);
+               break;
+  case GI_CLOSE:
+               {
+                FILE *sp;
+               
+                if(ROM) {free(ROM);ROM=0;}
+                if(VROM) {free(VROM);VROM=0;}
+
+                if(SaveGame)
+                {
+                 char *soot;
+                 SaveGame=0;
+                 soot=FCEU_MakeFName(FCEUMKF_SAV,0,"sav");
+                 sp=fopen(soot,"wb");
+                 if (sp==NULL)
+                  FCEU_PrintError("WRAM file \"%s\" cannot be written to.\n",soot);
+                 else
+                 {
+                  void *ptr;
+                  uint32 amount;
+                  ptr=WRAM;
+                  amount=8192;
+
+                  if(MapperNo==1)
+                  {
+                    extern uint8 MMC1WRAMsize;
+                    if(MMC1WRAMsize==2) ptr=WRAM+8192;
+                  }
+                  else if(MapperNo==5)
+                  {
+                   extern uint8 MMC5WRAMsize;
+                   if(MMC5WRAMsize==4)
+                    amount=32768;
+                  }
+
+                  fwrite(ptr,1,amount,sp);
+                  fclose(sp);
+                 }
+                }
+                if(MapClose) MapClose();
+                if(trainerpoo) {free(trainerpoo);trainerpoo=0;}
+               }
+               break;
+     }
+}
+
+uint32 iNESGameCRC32;
+
+struct CRCMATCH        {
+       uint32 crc;
+       char *name;
+};
+
+static void CheckBad(void)
+{
+ int x;
+ #define CRCNT 7
+ struct CRCMATCH tab[CRCNT]={
+       {0x28d183ac,"Antarctic Adventure"},
+       {0x7095ac65,"Akumajo Densetsu"},
+       {0x1bd7ed5a,"Gradius 2"},
+       {0x81c3aa66,"Crisis Force"},
+       {0xfe3088df,"Fire Emblem Gaiden"},
+       {0xfa8339a5,"Bucky O'Hare"},
+       {0x3c539d78,"Ganbare Goemon 2"},
+       };
+  for(x=0;x<CRCNT;x++)
+   if(tab[x].crc == iNESGameCRC32)
+   {
+    FCEU_PrintError("The copy of the game you have loaded, %s, is a bad dump, has been hacked, or both.  It will not work correctly on FCE Ultra.  Use a good copy of the ROM image instead.",tab[x].name);
+    break;
+   }
+}
+
+struct INPSEL {
+       uint32 crc32;
+       int input1;
+       int input2;
+       int inputfc;
+};
+
+/* This is mostly for my personal use.  So HA. */
+static void SetInput(void)
+{
+ static struct INPSEL moo[]=
+       {
+        {0xad9c63e2,SI_GAMEPAD,-1,SIFC_SHADOW},        /* Space Shadow */
+        {0x24598791,-1,SI_ZAPPER,0},   /* Duck Hunt */
+        {0xff24d794,-1,SI_ZAPPER,0},   /* Hogan's Alley */
+        {0xbeb8ab01,-1,SI_ZAPPER,0},   /* Gumshoe */
+        {0xde8fd935,-1,SI_ZAPPER,0},   /* To the Earth */
+        {0xedc3662b,-1,SI_ZAPPER,0},   /* Operation Wolf */
+        {0x23d17f5e,SI_GAMEPAD,SI_ZAPPER,0},   /* The Lone Ranger */
+        {0xb8b9aca3,-1,SI_ZAPPER,0},  /* Wild Gunman */
+        {0x5112dc21,-1,SI_ZAPPER,0},  /* Wild Gunman */
+        {0x4318a2f8,-1,SI_ZAPPER,0},  /* Barker Bill's Trick Shooting */
+        {0x5ee6008e,-1,SI_ZAPPER,0},  /* Mechanized Attack */
+        {0x3e58a87e,-1,SI_ZAPPER,0},  /* Freedom Force */
+        {0x851eb9be,SI_GAMEPAD,SI_ZAPPER,0},   /* Shooting Range */
+        {0x74bea652,SI_GAMEPAD,SI_ZAPPER,0},   /* Supergun 3-in-1 */
+        {0x32fb0583,-1,SI_ARKANOID,0}, /* Arkanoid(NES) */
+        {0xd89e5a67,-1,-1,SIFC_ARKANOID}, /* Arkanoid (J) */
+        {0x0f141525,-1,-1,SIFC_ARKANOID}, /* Arkanoid 2(J) */
+
+        {0xf7606810,-1,-1,SIFC_FKB},   /* Family BASIC 2.0A */
+        {0x895037bc,-1,-1,SIFC_FKB},   /* Family BASIC 2.1a */
+        {0xb2530afc,-1,-1,SIFC_FKB},   /* Family BASIC 3.0 */
+        {0,-1,-1,-1}
+       };
+ int x=0;
+
+ while(moo[x].input1>=0 || moo[x].input2>=0 || moo[x].inputfc>=0)
+ {
+  if(moo[x].crc32==iNESGameCRC32)
+  {
+   FCEUGameInfo.input[0]=moo[x].input1;
+   FCEUGameInfo.input[1]=moo[x].input2;
+   FCEUGameInfo.inputfc=moo[x].inputfc;
+   break;
+  }
+  x++;
+ }
+}
+
+struct CHINF {
+       uint32 crc32;
+       int32 mapper;
+       int32 mirror;
+};
+
+#define SAVCNT 14
+static void CheckHInfo(void)
+{
+ /* ROM images that have the battery-backed bit set in the header that really
+    don't have battery-backed RAM is not that big of a problem, so I'll
+    treat this differently.
+ */
+
+ static uint32 savie[SAVCNT]=
+       {
+        0x7cab2e9b,0x3ee43cda,0xe1383deb,      /* Mouryou Senki Madara */
+        0x3b3f88f0,0x2545214c,                 /* Dragon Warrior PRG 0 and 1 */
+        0x8c5a784e,    /* DW 2 */
+        0xa86a5318,    /* DW 3 */
+        0x506e259d,    /* DW 4 */
+        0xcebd2a31,0xb8b88130, /* Final Fantasy */
+        0x466efdc2,    /* FF(J) */
+        0xc9556b36,    /* FF1+2*/
+        0xd29db3c7,    /* FF2 */
+        0x57e220d0,    /* FF3 */
+       };
+
+ static struct CHINF moo[]=
+       {
+        {0xc68363f6,180,0},    /* Crazy Climber */
+        {0xbe939fce,9,1},      /* Punchout*/
+        {0x5e66eaea,13,1},     /* Videomation */
+        {0xaf5d7aa2,-1,0},     /* Clu Clu Land */
+
+        {0xc2730c30,34,0},     /* Deadly Towers */
+        {0x932ff06e,34,1},     /* Classic Concentration */
+        {0x4c7c1af3,34,1},     /* Caesar's Palace */
+        {0x9ea1dc76,2,0},      /* Rainbow Islands */
+        
+        {0x9eefb4b4,4,8},      /* Pachi Slot Adventure 2 */
+        {0x5337f73c,4,8},      /* Niji no Silk Road */
+        {0x7474ac92,4,8},      /* Kabuki: Quantum Fighter */
+
+        {0x970bd9c2,1,8},      /* Hanjuku Hero */
+
+        {0xbb7c5f7a,89,8},     /* Mito Koumon or something similar */
+        /* Probably a Namco MMC3-workalike */
+        {0xa5e6baf9,4,1|4},    /* Dragon Slayer 4 */
+        {0xe40b4973,4,1|4},    /* Metro Cross */
+         {0xd97c31b0,4,1|4},    /* Rasaaru Ishii no Childs Quest */
+
+        {0x84382231,9,0},      /* Punch Out (J) */
+
+        {0xfcdaca80,0,0},      /* Elevator Action */
+        {0xe492d45a,0,0},      /* Zippy Race */
+        {0x32fa246f,0,0},      /* Tag Team Pro Wrestling */
+        {0x6d65cac6,2,0},      /* Terra Cresta */
+        {0x28c11d24,2,1},      /* Sukeban Deka */
+         {0x02863604,2,1},      /* Sukeban Deka */
+         {0x2bb6a0f8,2,1},      /* Sherlock Holmes */
+        {0x55773880,2,1},      /* Gilligan's Island */
+        {0x419461d0,2,1},      /* Super Cars */
+        {0x6e0eb43e,2,1},      /* Puss n Boots */
+        {0xfc3e5c86,2,1},      /* Trojan */
+
+        {0x291bcd7d,1,8},      /* Pachio Kun 2 */
+        {0xf74dfc91,1,-1},     /* Win, Lose, or Draw */
+
+        {0x59280bec,4,8},      /* Jackie Chan */
+
+        {0xfe364be5,1,8},      /* Deep Dungeon 4 */
+        {0xd8ee7669,1,8},      /* Adventures of Rad Gravity */
+        {0xa5e8d2cd,1,8},      /* Breakthru */
+        {0xf6fa4453,1,8},      /* Bigfoot */
+        {0x37ba3261,1,8},      /* Back to the Future 2 and 3 */
+        {0x934db14a,1,-1},     /* All-Pro Basketball */
+        {0xe94d5181,1,8},      /* Mirai Senshi - Lios */
+        {0x7156cb4d,1,8},      /* Muppet Adventure Carnival thingy */
+        {0x5b6ca654,1,8},      /* Barbie rev X*/
+        {0x57c12280,1,8},      /* Demon Sword */
+
+        {0xcf322bb3,3,1},      /* John Elway's Quarterback */
+        {0x9bde3267,3,1},      /* Adventures of Dino Riki */
+        {0x02cc3973,3,8},      /* Ninja Kid */
+        {0xb5d28ea2,3,1},      /* Mystery Quest - mapper 3?*/
+        {0xbc065fc3,3,1},      /* Pipe Dream */
+
+        {0x5b837e8d,1,8},      /* Alien Syndrome */
+        {0x283ad224,32,8},     /* Ai Sensei no Oshiete */
+        {0x5555fca3,32,8},     /* "" ""                */
+        {0x243a8735,32,0x10|4}, /* Major League */
+
+        {0x6bc65d7e,66,1},     /* Youkai Club*/
+        {0xc2df0a00,66,1},     /* Bio Senshi Dan(hacked) */
+        {0xbde3ae9b,66,1},     /* Doraemon */
+        {0xd26efd78,66,1},     /* SMB Duck Hunt */
+        {0x811f06d9,66,1},     /* Dragon Power */
+
+        {0x3293afea,66,1},     /* Mississippi Satsujin Jiken */
+        {0xe84274c5,66,1},     /* "" "" */
+
+
+        {0x6e68e31a,16,8},     /* Dragon Ball 3*/
+
+        {0xba51ac6f,78,2},
+        {0x3d1c3137,78,8},
+
+        {0xbda8f8e4,152,8},    /* Gegege no Kitarou 2 */
+        {0x026c5fca,152,8},    /* Saint Seiya Ougon Densetsu */
+        {0x0f141525,152,8},    /* Arkanoid 2 (Japanese) */
+        {0xb1a94b82,152,8},    /* Pocket Zaurus */
+
+        {0x3f15d20d,153,8},    /* Famicom Jump 2 */
+
+        {0xbba58be5,70,-1},    /* Family Trainer - Manhattan Police */
+        {0x370ceb65,70,-1},    /* Family Trainer - Meiro Dai Sakusen */
+        {0xdd8ed0f7,70,1},     /* Kamen Rider Club */
+
+        {0x90c773c1,118,-1},   /* Goal! 2 */
+        {0xb9b4d9e0,118,-1},   /* NES Play Action Football */
+        {0x78b657ac,118,-1},   /* Armadillo */
+        {0x37b62d04,118,-1},   /* Ys 3 */
+        {0x07d92c31,118,-1},   /* RPG Jinsei Game */
+        {0x2705eaeb,234,-1},   /* Maxi 15 */
+        {0x404b2e8b,4,2},      /* Rad Racer 2 */
+
+        {0x1356f6a6,4,8},      /* "Cattou Ninden Teyandee" English tranlation.
+                                   Should I have even bothered to do this? */
+        {0x50fd4fd6,4,8},      /* "" "" */
+
+        {0xa912b064,51|0x800,8},       /* 11-in-1 Ball Games(has CHR ROM when it shouldn't) */
+        {0,-1,-1}
+       };
+ int tofix=0;
+ int x=0;
+
+ do
+ {
+  if(moo[x].crc32==iNESGameCRC32)
+  {
+   if(moo[x].mapper>=0)
+   {
+    if(moo[x].mapper&0x800 && VROM_size)
+    {
+     VROM_size=0;
+     free(VROM);
+     tofix|=8;
+    }
+    if(MapperNo!=(moo[x].mapper&0xFF))
+    {
+     tofix|=1;
+     MapperNo=moo[x].mapper&0xFF;
+    }
+   }
+   if(moo[x].mirror>=0)
+   {
+    if(moo[x].mirror==8)
+    {
+     if(Mirroring==2)  /* Anything but hard-wired(four screen). */
+     {
+      tofix|=2;
+      Mirroring=0;
+     }
+    }
+    else if(Mirroring!=moo[x].mirror)
+    {
+     if(Mirroring!=(moo[x].mirror&~4))
+      if((moo[x].mirror&~4)<=2)        /* Don't complain if one-screen mirroring
+                                  needs to be set(the iNES header can't
+                                  hold this information).
+                               */
+       tofix|=2;
+     Mirroring=moo[x].mirror;
+    }
+   }
+   break;
+  }
+  x++;
+ } while(moo[x].mirror>=0 || moo[x].mapper>=0);
+
+ for(x=0;x<SAVCNT;x++)
+ {
+  if(savie[x]==iNESGameCRC32)
+  {
+   if(!(head.ROM_type&2))
+   {
+    tofix|=4;
+    head.ROM_type|=2;
+   }
+  }
+ }
+
+ /* Games that use these iNES mappers tend to have the four-screen bit set
+    when it should not be.
+ */
+ if((MapperNo==118 || MapperNo==24 || MapperNo==26) && (Mirroring==2))
+ {
+  Mirroring=0;
+  tofix|=2;
+ }
+
+ if(tofix)
+ {
+  char gigastr[768];
+  strcpy(gigastr,"The iNES header contains incorrect information.  For now, the information will be corrected in RAM.  ");
+  if(tofix&1)
+   sprintf(gigastr+strlen(gigastr),"The mapper number should be set to %d.  ",MapperNo);
+  if(tofix&2)
+  {
+   char *mstr[3]={"Horizontal","Vertical","Four-screen"};
+   sprintf(gigastr+strlen(gigastr),"Mirroring should be set to \"%s\".  ",mstr[Mirroring&3]);
+  }
+  if(tofix&4)
+   strcat(gigastr,"The battery-backed bit should be set.  ");  
+  if(tofix&8)
+   strcat(gigastr,"This game should not have any CHR ROM.  ");
+  strcat(gigastr,"\n");
+  FCEUD_PrintError(gigastr);
+ }
+}
+
+int iNESLoad(char *name, int fp)
+{
+        FILE *sp;
+
+       if(FCEU_fread(&head,1,16,fp)!=16)
+        return 0;
+
+        if(memcmp(&head,"NES\x1a",4))
+         return 0;
+
+        if(!memcmp((char *)(&head)+0x7,"DiskDude",8))
+        {
+         memset((char *)(&head)+0x7,0,0x9);
+        }
+
+        if(!memcmp((char *)(&head)+0x7,"demiforce",9))
+        {
+         memset((char *)(&head)+0x7,0,0x9);
+        }
+
+        if(!memcmp((char *)(&head)+0xA,"Ni03",4))
+        {
+         if(!memcmp((char *)(&head)+0x7,"Dis",3))
+          memset((char *)(&head)+0x7,0,0x9);
+         else
+          memset((char *)(&head)+0xA,0,0x6);
+        }
+
+        if(!head.ROM_size)
+         head.ROM_size++;
+
+        ROM_size = head.ROM_size;
+        VROM_size = head.VROM_size;
+       ROM_size=uppow2(ROM_size);
+
+        if(VROM_size)
+        VROM_size=uppow2(VROM_size);
+
+        MapperNo = (head.ROM_type>>4);
+        MapperNo|=(head.ROM_type2&0xF0);
+
+        Mirroring = (head.ROM_type&1);
+       if(head.ROM_type&8) Mirroring=2;
+
+        if(!(ROM=(uint8 *)FCEU_malloc(ROM_size<<14)))
+        return 0;
+               
+        if (VROM_size) 
+         if(!(VROM=(uint8 *)FCEU_malloc(VROM_size<<13)))
+        {
+         free(ROM);
+         return 0;
+        }
+
+        memset(ROM,0xFF,ROM_size<<14);
+        if(VROM_size) memset(VROM,0xFF,VROM_size<<13);
+        if(head.ROM_type&4)    /* Trainer */
+       {
+        if(!(trainerpoo=FCEU_malloc(512)))
+         return(0);
+        FCEU_fread(trainerpoo,512,1,fp);
+       }
+       ResetCartMapping();
+       SetupCartPRGMapping(0,ROM,ROM_size*0x4000,0);
+        SetupCartPRGMapping(1,WRAM,8192,1);
+
+        FCEU_fread(ROM,0x4000,head.ROM_size,fp);
+
+       if(VROM_size)
+        FCEU_fread(VROM,0x2000,head.VROM_size,fp);
+
+        printf("File %s loaded.\n",name);
+
+       iNESGameCRC32=CalcCRC32(0,ROM,ROM_size<<14);
+       if(VROM_size)
+        iNESGameCRC32=CalcCRC32(iNESGameCRC32,VROM,VROM_size<<13);
+        printf("\n PRG ROM:  %3d x 16k\n CHR ROM:  %3d x  8k\n ROM CRC32:  %08lx\n Mapper:  %d\n Mirroring: %s\n",head.ROM_size,head.VROM_size,iNESGameCRC32,MapperNo,Mirroring==2?"None(Four-screen)":Mirroring?"Vertical":"Horizontal");
+        if(head.ROM_type&2) puts(" Battery-backed.");
+        if(head.ROM_type&4) puts(" Trained.");
+       puts("");
+
+       CheckBad();
+       SetInput();
+       CheckHInfo();
+       CheckVSUni();
+        //if(MapperNo!=4 && MapperNo!=118 && MapperNo!=119) exit(1); // Testing
+
+       /* Must remain here because above functions might change value of
+          VROM_size and free(VROM).
+       */
+       if(VROM_size)
+         SetupCartCHRMapping(0,VROM,VROM_size*0x2000,0);
+
+        if(Mirroring==2)
+         SetupCartMirroring(4,1,ExtraNTARAM);
+        else if(Mirroring>=0x10)
+        SetupCartMirroring(2+(Mirroring&1),1,0);
+       else
+         SetupCartMirroring(Mirroring&1,(Mirroring&4)>>2,0);
+
+        if(MapperNo==5) DetectMMC5WRAMSize();
+       else if(MapperNo==1) DetectMMC1WRAMSize();
+
+        if(head.ROM_type&2)
+        {         
+         char *soot;
+
+         SaveGame=1;
+         soot=FCEU_MakeFName(FCEUMKF_SAV,0,"sav");
+         sp=fopen(soot,"rb");
+         if(sp!=NULL)
+         {
+         void *ptr;
+         uint32 amount;
+
+         ptr=WRAM;
+         amount=8192;
+         if(MapperNo==1)
+         {
+          extern uint8 MMC1WRAMsize;
+          if(MMC1WRAMsize==2) ptr=WRAM+8192;
+         }
+         else if(MapperNo==5)
+         {
+          extern uint8 MMC5WRAMsize;
+           if(MMC5WRAMsize==4)
+           amount=32768;
+         }
+          if(fread(ptr,1,amount,sp)==amount)
+           printf("  WRAM Save File \"%s\" loaded...\n",soot);
+          fclose(sp);
+         }
+
+   }
+       GameInterface=iNESGI;
+        return 1;
+}
+
+#include       "banksw.h"
+
+
+void FASTAPASS(1) onemir(uint8 V)
+{
+       if(Mirroring==2) return;
+        if(V>1)
+         V=1;
+       Mirroring=0x10|V;
+       setmirror(MI_0+V);
+}
+
+void FASTAPASS(1) MIRROR_SET2(uint8 V)
+{
+       if(Mirroring==2) return;
+       Mirroring=V;
+       setmirror(V);
+}
+
+void FASTAPASS(1) MIRROR_SET(uint8 V)
+{
+       if(Mirroring==2) return;
+       V^=1;
+       Mirroring=V;
+       setmirror(V);
+}
+
+static void NONE_init(void)
+{
+        ROM_BANK16(0x8000,0);
+        ROM_BANK16(0xC000,~0);
+
+        if(VROM_size) 
+        VROM_BANK8(0);
+        else
+        setvram8(CHRRAM);
+}
+
+static uint8 secdata[2][32]=
+{
+ {
+  0xff, 0xbf, 0xb7, 0x97, 0x97, 0x17, 0x57, 0x4f,
+  0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90, 0x94, 0x14,
+  0x56, 0x4e, 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90,
+  0xd4, 0x5c, 0x3e, 0x26, 0x87, 0x83, 0x13, 0x00
+ },
+ {
+  0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00,
+  0x00, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ }
+};
+
+static uint8 *secptr;
+
+static void CheckVSUni(void)
+{
+        FCEUGameInfo.type=GIT_VSUNI;
+       
+       /* FCE Ultra doesn't complain when headers for these games are bad. */
+       secptr=0;
+       switch(iNESGameCRC32)
+       {
+        default:FCEUGameInfo.type=0;break;
+
+        case 0xffbef374: pale=1;break; /* Castlevania */
+
+        case 0x98e3c75a: 
+        case 0x7cff0f84: pale=2;break; /* SMB */
+       
+        case 0xef7af338: pale=2;break; /* Ice Climber */
+        case 0xabe1a0c2: FCEUGameInfo.input[0]=SI_ZAPPER;break; /*Duck hunt */
+        case 0x16aa4e2d: pale=7;FCEUGameInfo.input[0]=SI_ZAPPER;break; /* hoganal ^_^ */
+        case 0x2b85420e: pale=3;break; /* Dr Mario */
+
+        case 0xfb0ddde7: pale=2;break;
+        case 0xc95321a8: pale=6;break; /* Excitebike */
+        case 0xb1c4c508: pale=1;break; /* Golf */
+
+        case 0x66471efe: break;
+        case 0xca3e9b1a: pale=7;break; /* Pinball*/
+
+        case 0xf735d926: pale=7; break; /* Gradius */
+
+        case 0x2019fe65:
+        case 0x31678411:MapperNo=68;pale=7;break; /* Platoon */
+
+        case 0x74f713b4:pale=4;break; /* Goonies */
+        case 0x9ae2baa0:pale=5;break; /* Slalom */
+        case 0xe45485a5:secptr=secdata[1];vsdip=0x20;MapperNo=4;break; /* RBI Baseball */
+        case 0x21a653c7:vsdip=0x20;MapperNo=4;break; /* Super Sky Kid */
+         case 0xe9a6f17d:vsdip=0x20;break; /* Tetris */
+
+         case 0x159ef3c1:break; /* Star Luster */
+         case 0x9768e5e0:break; /* Stroke and Match Golf */
+       
+        /* FCE Ultra doesn't have correct palettes for the following games. */
+        case 0x0fa322c2:pale=2;break; /* Clu Clu Land */
+
+        case 0x766c2cac:       /* Soccer */
+        case 0x01357944:       /* Battle City */
+        case 0xb2816bf9:break; /* Battle City (Bootleg) */
+
+        case 0x832cf592:FCEUGameInfo.input[0]=SI_ZAPPER;break; /* Freedom Force */
+        case 0x63abf889:break; /* Ladies Golf */
+        case 0x8c0c2df5:pale=2;MapperNo=1;Mirroring=1;break; /* Top Gun */
+        case 0x52c501d0:vsdip=0x80;MapperNo=4;secptr=secdata[0];break; 
+                       /* TKO Boxing */
+       }
+
+       if(MapperNo==99)
+        Mirroring=2;
+}
+
+
+static int VSindex;
+
+static DECLFR(VSRead)
+{
+ //printf("$%04x, $%04x\n",A,X.PC);
+ switch(A)
+ {
+  default:
+  case 0x5e00: VSindex=0;return 0xFF;
+  case 0x5e01: return(secptr[(VSindex++)&0x1F]);
+ }
+}
+
+static void DoVSHooks(void)
+{
+ if(secptr)
+  SetReadHandler(0x5e00,0x5e01,VSRead);
+}
+
+void (*MapInitTab[256])(void)=
+{
+       0,
+       Mapper1_init,Mapper2_init,Mapper3_init,Mapper4_init,
+       Mapper5_init,Mapper6_init,Mapper7_init,Mapper8_init,
+       Mapper9_init,Mapper10_init,Mapper11_init,0,
+       Mapper13_init,0,Mapper15_init,Mapper16_init,
+       Mapper17_init,Mapper18_init,Mapper19_init,0,
+       Mapper21_init,Mapper22_init,Mapper23_init,Mapper24_init,
+       Mapper25_init,Mapper26_init,0,0,
+       0,0,0,Mapper32_init,
+       Mapper33_init,Mapper34_init,0,0,
+       0,0,0,Mapper40_init,
+       Mapper41_init,Mapper42_init,Mapper43_init,Mapper44_init,
+       Mapper45_init,Mapper46_init,Mapper47_init,Mapper33_init,Mapper49_init,0,Mapper51_init,Mapper52_init,
+       0,0,0,0,0,0,0,0,
+       0,0,0,Mapper64_init,
+       Mapper65_init,Mapper66_init,Mapper67_init,Mapper68_init,
+       Mapper69_init,Mapper70_init,Mapper71_init,Mapper72_init,
+       Mapper73_init,0,Mapper75_init,Mapper76_init,
+       Mapper77_init,Mapper78_init,Mapper79_init,Mapper80_init,
+       0,Mapper82_init,Mapper83_init,0,
+       Mapper85_init,Mapper86_init,Mapper87_init,Mapper88_init,
+       Mapper89_init,Mapper90_init,0,Mapper92_init,
+       Mapper93_init,Mapper94_init,Mapper95_init,Mapper96_init,
+       Mapper97_init,0,Mapper99_init,0,
+       0,0,0,0,Mapper105_init,0,0,0,
+       0,0,0,Mapper112_init,Mapper113_init,0,0,0,
+       Mapper117_init,Mapper118_init,Mapper119_init,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,Mapper140_init,
+       0,0,0,0,0,0,0,0,
+       0,0,Mapper151_init,Mapper152_init,Mapper153_init,0,0,0,
+       0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,Mapper180_init,
+       0,Mapper182_init,0,Mapper184_init,Mapper185_init,0,0,0,
+       Mapper189_init,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,
+       0,0,0,0,Mapper225_init,Mapper226_init,Mapper227_init,Mapper228_init,
+       Mapper229_init,0,0,Mapper232_init,0,Mapper234_init,Mapper43_init,0,
+       0,0,0,Mapper240_init,0,Mapper242_init,0,0,
+       Mapper245_init,Mapper246_init,0,Mapper248_init,Mapper249_init,Mapper250_init,0,0,0,0,0
+};
+
+static DECLFW(BWRAM)
+{
+                WRAM[A-0x6000]=V;
+}
+
+static DECLFR(AWRAM)
+{
+                return WRAM[A-0x6000];
+}
+
+void (*MapStateRestore)(int version);
+void iNESStateRestore(int version)
+{
+ int x;
+ if(!MapperNo) return;
+
+ for(x=0;x<4;x++)
+  setprg8(0x8000+x*8192,PRGBankList[x]);
+
+ if(VROM_size)
+  for(x=0;x<8;x++) 
+    setchr1(0x400*x,CHRBankList[x]);
+
+ switch(Mirroring)
+ {
+   case 0:setmirror(MI_H);break;
+   case 1:setmirror(MI_V);break;
+   case 0x12:
+   case 0x10:setmirror(MI_0);break;
+   case 0x13:
+   case 0x11:setmirror(MI_1);break;
+ }
+ if(MapStateRestore) MapStateRestore(version);
+}
+
+static int MMC_init(int type)
+{
+        int x;
+
+        GameStateRestore=iNESStateRestore;
+        MapClose=0;
+       MapperReset=0;
+        MapStateRestore=0;
+
+        setprg8r(1,0x6000,0);
+
+        SetReadHandler(0x6000,0x7FFF,AWRAM);
+        SetWriteHandler(0x6000,0x7FFF,BWRAM);
+        FCEU_CheatAddRAM(8,0x6000,WRAM);
+
+       /* This statement represents atrocious code.  I need to rewrite
+          all of the iNES mapper code... */
+       IRQCount=IRQLatch=IRQa=0;
+        if(head.ROM_type&2)
+       {
+        extern uint8 MMC5WRAMsize,MMC1WRAMsize;
+        if(type==5 && MMC5WRAMsize==4)
+         memset(GameMemBlock+32768,0,sizeof(GameMemBlock)-32768);
+        else if(type==1 && MMC1WRAMsize==2)
+        {
+         memset(GameMemBlock,0,8192);
+         memset(GameMemBlock+16384,0,sizeof(GameMemBlock)-16384);
+        }
+        else
+          memset(GameMemBlock+8192,0,sizeof(GameMemBlock)-8192);
+       }
+       else
+         memset(GameMemBlock,0,sizeof(GameMemBlock));
+        if(head.ROM_type&4)
+        memcpy(WRAM+4096,trainerpoo,512);
+
+        NONE_init();
+
+       if(FCEUGameInfo.type==GIT_VSUNI)
+        DoVSHooks();
+        if(type==5)
+        {
+          MMC5HackVROMMask=CHRmask4[0];
+          MMC5HackExNTARAMPtr=MapperExRAM+0x6000;
+          MMC5Hack=1;
+          MMC5HackVROMPTR=VROM;
+          MMC5HackCHRMode=0;
+        }
+        ResetExState();
+        AddExState(WRAM, 8192, 0, "WRAM");
+        if(type==19 || type==5 || type==6 || type==69 || type==85)
+         AddExState(MapperExRAM, 32768, 0, "MEXR");
+        if((!VROM_size || type==6 || type==19 || type==119) &&
+          (type!=13 && type!=96))
+         AddExState(CHRRAM, 8192, 0, "CHRR");
+        if(head.ROM_type&8)
+         AddExState(ExtraNTARAM, 2048, 0, "EXNR");
+
+       /* Exclude some mappers whose emulation code handle save state stuff 
+          themselves. */
+       if(type && type!=13 && type!=96)
+       {
+         AddExState(mapbyte1, 32, 0, "MPBY");
+         AddExState(&Mirroring, 1, 0, "MIRR");
+         AddExState(&IRQCount, 4, 1, "IRQC");
+         AddExState(&IRQLatch, 4, 1, "IQL1");
+         AddExState(&IRQa, 1, 0, "IRQA");
+         AddExState(PRGBankList, 4, 0, "PBL");
+         for(x=0;x<8;x++)
+         {
+          char tak[8];
+          sprintf(tak,"CBL%d",x);         
+          AddExState(&CHRBankList[x], 2, 1,tak);
+         }
+       }
+
+        if(MapInitTab[type]) MapInitTab[type]();
+        else if(type)
+        {
+         FCEU_PrintError("iNES mapper #%d is not supported at all.",type);
+        }
+        return 1;
+}
diff --git a/ines.h b/ines.h
new file mode 100644 (file)
index 0000000..a27cf74
--- /dev/null
+++ b/ines.h
@@ -0,0 +1,366 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 Bero
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#ifdef INESPRIV
+
+void iNESStateRestore(int version);
+extern uint32 iNESGameCRC32;
+
+extern uint8 *VROM;
+extern uint32 VROM_size;
+
+extern void (*MapStateRestore)(int version);
+extern void (*MapClose)(void);
+extern void (*MapperReset)(void);
+
+/* This order is necessary */
+#define WRAM          (GameMemBlock)
+#define sizeofWRAM    8192
+
+#define MapperExRAM   (GameMemBlock+sizeofWRAM)
+#define sizeofMapperExRAM  32768
+/* for the MMC5 code to work properly.  It might be fixed later... */
+
+
+#define CHRRAM        (GameMemBlock+sizeofWRAM+sizeofMapperExRAM)
+#define sizeofCHRRAM 8192
+
+#define ExtraNTARAM   (GameMemBlock+sizeofWRAM+sizeofMapperExRAM+sizeofCHRRAM)
+#define sizeofExtraNTARAM 2048
+
+#define PRGBankList    (ExtraNTARAM+sizeofExtraNTARAM)
+
+#define mapbyte1       (PRGBankList+4)
+#define mapbyte2       (mapbyte1+8)
+#define mapbyte3       (mapbyte2+8)
+#define mapbyte4       (mapbyte3+8)
+uint16 iNESCHRBankList[8];
+int32 iNESIRQLatch,iNESIRQCount;
+uint8 iNESMirroring;
+uint8 iNESIRQa;
+
+#define IRQa iNESIRQa
+#define Mirroring iNESMirroring
+#define IRQCount iNESIRQCount
+#define IRQLatch iNESIRQLatch
+#define CHRBankList iNESCHRBankList
+#else
+int iNESLoad(char *name, int fp);
+#endif
+
+       typedef struct {
+               char ID[4]; /*NES^Z*/
+                uint8 ROM_size;
+                uint8 VROM_size;
+                uint8 ROM_type;
+                uint8 ROM_type2;
+                uint8 reserve[8];
+       } iNES_HEADER;
+
+void FASTAPASS(2) VRAM_BANK1(uint32 A, uint8 V);
+void FASTAPASS(2) VRAM_BANK4(uint32 A,uint32 V);
+
+void FASTAPASS(2) VROM_BANK1(uint32 A,uint32 V);
+void FASTAPASS(2) VROM_BANK2(uint32 A,uint32 V);
+void FASTAPASS(2) VROM_BANK4(uint32 A, uint32 V);
+void FASTAPASS(1) VROM_BANK8(uint32 V);
+void FASTAPASS(2) ROM_BANK8(uint32 A, uint32 V);
+void FASTAPASS(2) ROM_BANK16(uint32 A, uint32 V);
+void FASTAPASS(2) ROM_BANK32(uint32 V);
+
+extern uint8 vmask;
+extern uint32 vmask1;
+extern uint32 vmask2;
+extern uint32 vmask4;
+extern uint32 pmask8;
+extern uint8 pmask16;
+extern uint8 pmask32;
+
+void FASTAPASS(1) onemir(uint8 V);
+void FASTAPASS(1) MIRROR_SET2(uint8 V);
+void FASTAPASS(1) MIRROR_SET(uint8 V);
+
+
+void DetectMMC1WRAMSize(void);
+void DetectMMC5WRAMSize(void);
+
+void Mapper0_init(void);
+void Mapper1_init(void);
+void Mapper2_init(void);
+void Mapper3_init(void);
+void Mapper4_init(void);
+void Mapper5_init(void);
+void Mapper6_init(void);
+void Mapper7_init(void);
+void Mapper8_init(void);
+void Mapper9_init(void);
+void Mapper10_init(void);
+void Mapper11_init(void);
+void Mapper12_init(void);
+void Mapper13_init(void);
+void Mapper14_init(void);
+void Mapper15_init(void);
+void Mapper16_init(void);
+void Mapper17_init(void);
+void Mapper18_init(void);
+void Mapper19_init(void);
+void Mapper20_init(void);
+void Mapper21_init(void);
+void Mapper22_init(void);
+void Mapper23_init(void);
+void Mapper24_init(void);
+void Mapper25_init(void);
+void Mapper26_init(void);
+void Mapper27_init(void);
+void Mapper28_init(void);
+void Mapper29_init(void);
+void Mapper30_init(void);
+void Mapper31_init(void);
+void Mapper32_init(void);
+void Mapper33_init(void);
+void Mapper34_init(void);
+void Mapper35_init(void);
+void Mapper36_init(void);
+void Mapper37_init(void);
+void Mapper38_init(void);
+void Mapper39_init(void);
+void Mapper40_init(void);
+void Mapper41_init(void);
+void Mapper42_init(void);
+void Mapper43_init(void);
+void Mapper44_init(void);
+void Mapper45_init(void);
+void Mapper46_init(void);
+void Mapper47_init(void);
+void Mapper48_init(void);
+void Mapper49_init(void);
+void Mapper50_init(void);
+void Mapper51_init(void);
+void Mapper52_init(void);
+void Mapper53_init(void);
+void Mapper54_init(void);
+void Mapper55_init(void);
+void Mapper56_init(void);
+void Mapper57_init(void);
+void Mapper58_init(void);
+void Mapper59_init(void);
+void Mapper60_init(void);
+void Mapper61_init(void);
+void Mapper62_init(void);
+void Mapper63_init(void);
+void Mapper64_init(void);
+void Mapper65_init(void);
+void Mapper66_init(void);
+void Mapper67_init(void);
+void Mapper68_init(void);
+void Mapper69_init(void);
+void Mapper70_init(void);
+void Mapper71_init(void);
+void Mapper72_init(void);
+void Mapper73_init(void);
+void Mapper74_init(void);
+void Mapper75_init(void);
+void Mapper76_init(void);
+void Mapper77_init(void);
+void Mapper78_init(void);
+void Mapper79_init(void);
+void Mapper80_init(void);
+void Mapper81_init(void);
+void Mapper82_init(void);
+void Mapper83_init(void);
+void Mapper84_init(void);
+void Mapper85_init(void);
+void Mapper86_init(void);
+void Mapper87_init(void);
+void Mapper88_init(void);
+void Mapper89_init(void);
+void Mapper90_init(void);
+void Mapper91_init(void);
+void Mapper92_init(void);
+void Mapper93_init(void);
+void Mapper94_init(void);
+void Mapper95_init(void);
+void Mapper96_init(void);
+void Mapper97_init(void);
+void Mapper98_init(void);
+void Mapper99_init(void);
+void Mapper100_init(void);
+void Mapper101_init(void);
+void Mapper102_init(void);
+void Mapper103_init(void);
+void Mapper104_init(void);
+void Mapper105_init(void);
+void Mapper106_init(void);
+void Mapper107_init(void);
+void Mapper108_init(void);
+void Mapper109_init(void);
+void Mapper110_init(void);
+void Mapper111_init(void);
+void Mapper112_init(void);
+void Mapper113_init(void);
+void Mapper114_init(void);
+void Mapper115_init(void);
+void Mapper116_init(void);
+void Mapper117_init(void);
+void Mapper118_init(void);
+void Mapper119_init(void);
+void Mapper120_init(void);
+void Mapper121_init(void);
+void Mapper122_init(void);
+void Mapper123_init(void);
+void Mapper124_init(void);
+void Mapper125_init(void);
+void Mapper126_init(void);
+void Mapper127_init(void);
+void Mapper128_init(void);
+void Mapper129_init(void);
+void Mapper130_init(void);
+void Mapper131_init(void);
+void Mapper132_init(void);
+void Mapper133_init(void);
+void Mapper134_init(void);
+void Mapper135_init(void);
+void Mapper136_init(void);
+void Mapper137_init(void);
+void Mapper138_init(void);
+void Mapper139_init(void);
+void Mapper140_init(void);
+void Mapper141_init(void);
+void Mapper142_init(void);
+void Mapper143_init(void);
+void Mapper144_init(void);
+void Mapper145_init(void);
+void Mapper146_init(void);
+void Mapper147_init(void);
+void Mapper148_init(void);
+void Mapper149_init(void);
+void Mapper150_init(void);
+void Mapper151_init(void);
+void Mapper152_init(void);
+void Mapper153_init(void);
+void Mapper154_init(void);
+void Mapper155_init(void);
+void Mapper156_init(void);
+void Mapper157_init(void);
+void Mapper158_init(void);
+void Mapper159_init(void);
+void Mapper160_init(void);
+void Mapper161_init(void);
+void Mapper162_init(void);
+void Mapper163_init(void);
+void Mapper164_init(void);
+void Mapper165_init(void);
+void Mapper166_init(void);
+void Mapper167_init(void);
+void Mapper168_init(void);
+void Mapper169_init(void);
+void Mapper170_init(void);
+void Mapper171_init(void);
+void Mapper172_init(void);
+void Mapper173_init(void);
+void Mapper174_init(void);
+void Mapper175_init(void);
+void Mapper176_init(void);
+void Mapper177_init(void);
+void Mapper178_init(void);
+void Mapper179_init(void);
+void Mapper180_init(void);
+void Mapper181_init(void);
+void Mapper182_init(void);
+void Mapper183_init(void);
+void Mapper184_init(void);
+void Mapper185_init(void);
+void Mapper186_init(void);
+void Mapper187_init(void);
+void Mapper188_init(void);
+void Mapper189_init(void);
+void Mapper190_init(void);
+void Mapper191_init(void);
+void Mapper192_init(void);
+void Mapper193_init(void);
+void Mapper194_init(void);
+void Mapper195_init(void);
+void Mapper196_init(void);
+void Mapper197_init(void);
+void Mapper198_init(void);
+void Mapper199_init(void);
+void Mapper200_init(void);
+void Mapper201_init(void);
+void Mapper202_init(void);
+void Mapper203_init(void);
+void Mapper204_init(void);
+void Mapper205_init(void);
+void Mapper206_init(void);
+void Mapper207_init(void);
+void Mapper208_init(void);
+void Mapper209_init(void);
+void Mapper210_init(void);
+void Mapper211_init(void);
+void Mapper212_init(void);
+void Mapper213_init(void);
+void Mapper214_init(void);
+void Mapper215_init(void);
+void Mapper216_init(void);
+void Mapper217_init(void);
+void Mapper218_init(void);
+void Mapper219_init(void);
+void Mapper220_init(void);
+void Mapper221_init(void);
+void Mapper222_init(void);
+void Mapper223_init(void);
+void Mapper224_init(void);
+void Mapper225_init(void);
+void Mapper226_init(void);
+void Mapper227_init(void);
+void Mapper228_init(void);
+void Mapper229_init(void);
+void Mapper230_init(void);
+void Mapper231_init(void);
+void Mapper232_init(void);
+void Mapper233_init(void);
+void Mapper234_init(void);
+void Mapper235_init(void);
+void Mapper236_init(void);
+void Mapper237_init(void);
+void Mapper238_init(void);
+void Mapper239_init(void);
+void Mapper240_init(void);
+void Mapper241_init(void);
+void Mapper242_init(void);
+void Mapper243_init(void);
+void Mapper244_init(void);
+void Mapper245_init(void);
+void Mapper246_init(void);
+void Mapper247_init(void);
+void Mapper248_init(void);
+void Mapper249_init(void);
+void Mapper250_init(void);
+void Mapper251_init(void);
+void Mapper252_init(void);
+void Mapper253_init(void);
+void Mapper254_init(void);
+void Mapper255_init(void);
+
+void VRC6_ESI(int t);
+void VRC7_ESI(void);
+void Mapper5_ESI(void);
+void Mapper69_ESI(void);
+void Mapper19_ESI(void);
diff --git a/input.c b/input.c
new file mode 100644 (file)
index 0000000..be6b360
--- /dev/null
+++ b/input.c
@@ -0,0 +1,330 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 BERO 
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "types.h"
+#include "x6502.h"
+
+#include "fce.h"
+#include "sound.h"
+#include "netplay.h"
+#include "svga.h"
+
+#include "input.h"
+
+extern INPUTC *FCEU_InitZapper(int w);
+extern INPUTC *FCEU_InitPowerpad(int w);
+extern INPUTC *FCEU_InitArkanoid(int w);
+
+extern INPUTCFC *FCEU_InitArkanoidFC(void);
+extern INPUTCFC *FCEU_InitSpaceShadow(void);
+extern INPUTCFC *FCEU_InitFKB(void);
+static uint8 joy_readbit[2];
+static uint16 joy[2]={0,0};
+
+extern int coinon;
+
+static int FSDisable=0;        /* Set to 1 if NES-style four-player adapter is disabled. */
+static int JPAttrib[2]={0,0};
+static int JPType[2]={0,0};
+static void *InputDataPtr[2];
+
+static int JPAttribFC=0;
+static int JPTypeFC=0;
+static void *InputDataPtrFC;
+
+void (*InputScanlineHook)(uint8 *buf, int line);
+
+static INPUTC DummyJPort={0,0,0,0,0};
+static INPUTC *JPorts[2]={&DummyJPort,&DummyJPort};
+static INPUTCFC *FCExp=0;
+
+static uint8 FP_FASTAPASS(1) ReadGPVS(int w)
+{
+                uint8 ret=0;
+
+               if(joy_readbit[w]>=8)
+                ret=1;
+               else
+               {
+                 ret = ((joy[w]>>(joy_readbit[w]))&1);
+                 joy_readbit[w]++;
+               }
+                return ret;
+}
+
+static uint8 FP_FASTAPASS(1) ReadGP(int w)
+{
+                uint8 ret;
+                //if(JoyMulti) 
+               //{
+                 //ret = ((joy[w]>>(joy_readbit[w]))&1)|
+                 //(((joy[w]>>(joy_readbit[w]+8))&1)<<1);
+                 //if(joy_readbit[w]>8) ret=0;
+               //}
+                ret = ((joy[w]>>(joy_readbit[w]))&1);
+               if(FSDisable)
+               {
+                if(joy_readbit[w]>=8) ret|=1;
+               }
+               else
+               {
+                 if(joy_readbit[w]==19-w) ret|=1;
+               }
+               joy_readbit[w]++;
+                return ret;
+}
+
+static DECLFR(JPRead)
+{
+       uint8 ret=0;
+
+       if(JPorts[A&1]->Read)
+        ret|=JPorts[A&1]->Read(A&1);
+       
+       if(FCExp)
+        if(FCExp->Read)
+         ret=FCExp->Read(A&1,ret);
+
+       ret|=X.DB&0xC0;
+       return(ret);
+}
+
+static DECLFW(B4016)
+{
+       if(FCExp)
+        if(FCExp->Write)
+         FCExp->Write(V&7);
+
+       if(JPorts[0]->Write)
+        JPorts[0]->Write(V&1);
+        if(JPorts[1]->Write)
+         JPorts[1]->Write(V&1);
+
+        if((PSG[0x16]&1) && (!(V&1)))
+        {
+        /* This strobe code is just for convenience.  If it were
+           with the code in input / *.c, it would more accurately represent
+           what's really going on.  But who wants accuracy? ;)
+           Seriously, though, this shouldn't be a problem.
+        */
+        if(JPorts[0]->Strobe)
+         JPorts[0]->Strobe(0);
+         if(JPorts[1]->Strobe)
+          JPorts[1]->Strobe(1);
+        if(FCExp)
+         if(FCExp->Strobe)
+          FCExp->Strobe();
+        }
+         PSG[0x16]=V;
+}
+
+static void FP_FASTAPASS(1) StrobeGP(int w)
+{
+       joy_readbit[w]=0;
+}
+
+static INPUTC GPC={ReadGP,0,StrobeGP,0,0,0};
+static INPUTC GPCVS={ReadGPVS,0,StrobeGP,0,0,0};
+
+void DrawInput(uint8 *buf)
+{
+ int x;
+
+ for(x=0;x<2;x++)
+  if(JPorts[x]->Draw)
+   JPorts[x]->Draw(x,buf,JPAttrib[x]);
+ if(FCExp)
+  if(FCExp->Draw)
+   FCExp->Draw(buf,JPAttribFC);
+}
+
+void UpdateInput(void)
+{
+       int x;
+
+       for(x=0;x<2;x++)
+       {
+        switch(JPType[x])
+        {
+         case SI_GAMEPAD:
+               if(!x) joy[0]=*(uint16 *)InputDataPtr[0];
+               else joy[1]=*(uint16 *)InputDataPtr[1];
+               break;
+         default:
+               if(JPorts[x]->Update)
+                JPorts[x]->Update(x,InputDataPtr[x],JPAttrib[x]);
+               break;
+        }
+       }
+       if(FCExp)
+        if(FCExp->Update)
+         FCExp->Update(InputDataPtrFC,JPAttribFC);
+
+        if(FCEUGameInfo.type==GIT_VSUNI)
+        {
+        uint16 t=joy[0];
+        joy[0]=(joy[0]&0xC)|(joy[1]&0xF3);
+        joy[1]=(joy[1]&0xC)|(t&0xF3);
+        if(coinon) coinon--;
+       }
+       #ifdef NETWORK
+       if(netplay) NetplayUpdate(&joy[0],&joy[1]);
+       #endif
+       FlushCommandQueue();
+}
+
+static DECLFR(VSUNIRead0)
+{
+       uint8 ret=0;
+
+        if(JPorts[0]->Read)
+         ret|=(JPorts[0]->Read(0))&1;
+
+       ret|=(vsdip&3)<<3;
+       if(coinon)
+        ret|=0x4;
+       return ret;
+}
+
+static DECLFR(VSUNIRead1)
+{
+        uint8 ret=0;
+
+        if(JPorts[1]->Read)
+         ret|=(JPorts[1]->Read(1))&1;
+        ret|=vsdip&0xFC;
+        return ret;
+}
+
+static void SLHLHook(uint8 *buf, int line)
+{
+ int x;
+
+ for(x=0;x<2;x++)
+  if(JPorts[x]->SLHook)
+   JPorts[x]->SLHook(x,buf,line);
+ if(FCExp) 
+  if(FCExp->SLHook)
+   FCExp->SLHook(buf,line);
+}
+
+static void CheckSLHook(void)
+{
+        InputScanlineHook=0;
+        if(JPorts[0]->SLHook || JPorts[1]->SLHook)
+         InputScanlineHook=SLHLHook;
+        if(FCExp)
+         if(FCExp->SLHook)
+          InputScanlineHook=SLHLHook;
+}
+
+static void FASTAPASS(1) SetInputStuff(int x)
+{
+        switch(JPType[x])
+        {
+         case SI_GAMEPAD:
+           if(FCEUGameInfo.type==GIT_VSUNI)
+           JPorts[x]=&GPCVS;
+          else
+           JPorts[x]=&GPC;
+         break;
+         case SI_ARKANOID:JPorts[x]=FCEU_InitArkanoid(x);break;
+         case SI_ZAPPER:JPorts[x]=FCEU_InitZapper(x);break;
+          case SI_POWERPAD:JPorts[x]=FCEU_InitPowerpad(x);break;
+         case SI_NONE:JPorts[x]=&DummyJPort;break;
+         }
+
+       CheckSLHook();
+}
+
+static uint8 F4ReadBit[2];
+static void StrobeFami4(void)
+{
+ F4ReadBit[0]=F4ReadBit[1]=0;
+}
+
+static uint8 FP_FASTAPASS(2) ReadFami4(int w, uint8 ret)
+{
+ ret&=1;
+
+ ret |= ((joy[w]>>(F4ReadBit[w]+8))&1)<<1;
+ if(F4ReadBit[w]>=8) ret|=2;
+ else F4ReadBit[w]++;
+
+ return(ret);
+}
+
+static INPUTCFC FAMI4C={ReadFami4,0,StrobeFami4,0,0,0};
+static void SetInputStuffFC(void)
+{
+        switch(JPTypeFC)
+        {
+         case SIFC_NONE:FCExp=0;break;
+         case SIFC_ARKANOID:FCExp=FCEU_InitArkanoidFC();break;
+        case SIFC_SHADOW:FCExp=FCEU_InitSpaceShadow();break;
+         case SIFC_4PLAYER:FCExp=&FAMI4C;memset(&F4ReadBit,0,sizeof(F4ReadBit));break;
+        case SIFC_FKB:FCExp=FCEU_InitFKB();break;
+        }
+       CheckSLHook();
+}
+
+// VS Unisystem code called after SetInputMap() hooks B4016.  Need to
+// rewrite code to make this more sane?
+
+void InitializeInput(void)
+{ 
+       memset(joy_readbit,0,sizeof(joy_readbit));
+       memset(joy,0,sizeof(joy));
+
+        if(FCEUGameInfo.type==GIT_VSUNI)
+        {
+         SetReadHandler(0x4016,0x4016,VSUNIRead0);
+         SetReadHandler(0x4017,0x4017,VSUNIRead1);
+        }
+        else
+         SetReadHandler(0x4016,0x4017,JPRead);
+        SetWriteHandler(0x4016,0x4016,B4016);
+
+        SetInputStuff(0);
+        SetInputStuff(1);
+       SetInputStuffFC();
+}
+
+void FCEUI_SetInput(int port, int type, void *ptr, int attrib)
+{
+ JPAttrib[port]=attrib;
+ JPType[port]=type;
+ InputDataPtr[port]=ptr;
+ SetInputStuff(port);
+}
+
+void FCEUI_DisableFourScore(int s)
+{
+ FSDisable=s;
+}
+
+void FCEUI_SetInputFC(int type, void *ptr, int attrib)
+{
+ JPAttribFC=attrib;
+ JPTypeFC=type;
+ InputDataPtrFC=ptr;
+ SetInputStuffFC();
+}
diff --git a/input.h b/input.h
new file mode 100644 (file)
index 0000000..8cec68a
--- /dev/null
+++ b/input.h
@@ -0,0 +1,23 @@
+typedef struct {
+        uint8 FP_FASTAPASS(1) (*Read)(int w);
+       void FP_FASTAPASS(1) (*Write)(uint8 v);
+        void FP_FASTAPASS(1) (*Strobe)(int w);
+       void FP_FASTAPASS(3) (*Update)(int w, void *data, int arg);
+       void FP_FASTAPASS(3) (*SLHook)(int w, uint8 *buf, int line);
+       void FP_FASTAPASS(3) (*Draw)(int w, uint8 *buf, int arg);
+} INPUTC;
+
+typedef struct {
+       uint8 FP_FASTAPASS(2) (*Read)(int w, uint8 ret);
+       void FP_FASTAPASS(1) (*Write)(uint8 v);
+       void (*Strobe)(void);
+        void FP_FASTAPASS(2) (*Update)(void *data, int arg);
+        void FP_FASTAPASS(2) (*SLHook)(uint8 *buf, int line);
+        void FP_FASTAPASS(2) (*Draw)(uint8 *buf, int arg);
+} INPUTCFC;
+
+void DrawInput(uint8 *buf);
+void UpdateInput(void);
+void InitializeInput(void);
+extern void (*PStrobe[2])(void);
+extern void (*InputScanlineHook)(uint8 *buf, int line);
diff --git a/input/Makefile b/input/Makefile
new file mode 100644 (file)
index 0000000..0327a9f
--- /dev/null
@@ -0,0 +1,8 @@
+INPOBJS   =       input/cursor.o input/powerpad.o input/zapper.o input/arkanoid.o input/shadow.o input/fkb.o
+
+input/cursor.o:                input/cursor.c
+input/zapper.o:                input/zapper.c
+input/powerpad.o:      input/powerpad.c
+input/arkanoid.o:      input/arkanoid.c
+input/shadow.o:                input/shadow.c
+input/fkb.o:           input/fkb.c input/fkb.h
diff --git a/input/arkanoid.c b/input/arkanoid.c
new file mode 100644 (file)
index 0000000..b53fd3a
--- /dev/null
@@ -0,0 +1,117 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include        <string.h>
+#include       <stdlib.h>
+#include       "share.h"
+
+typedef struct {
+       uint32 mzx,mzb;
+       uint32 readbit;
+} ARK;
+
+static ARK NESArk[2];
+static ARK FCArk;
+
+static void StrobeARKFC(void)
+{
+       FCArk.readbit=0;
+}
+
+
+static uint8 FP_FASTAPASS(2) ReadARKFC(int w,uint8 ret)
+{
+ ret&=~2;
+
+ if(w)  
+ {
+  if(FCArk.readbit>=8) 
+   ret|=2;
+  else
+  {
+   ret|=((FCArk.mzx>>(7-FCArk.readbit))&1)<<1;
+   FCArk.readbit++;
+  }
+ }
+ else
+  ret|=FCArk.mzb<<1;
+ return(ret);
+}
+
+static uint32 FixX(uint32 x)
+{
+ x=98+x*144/240;
+ if(x>242) x=242;
+ x=~x;
+ return(x);
+}
+
+static void FP_FASTAPASS(2) UpdateARKFC(void *data, int arg)
+{
+ uint32 *ptr=data;
+ FCArk.mzx=FixX(ptr[0]);
+ FCArk.mzb=ptr[2]?1:0;
+}
+
+static INPUTCFC ARKCFC={ReadARKFC,0,StrobeARKFC,UpdateARKFC,0,0};
+
+INPUTCFC *FCEU_InitArkanoidFC(void)
+{
+ FCArk.mzx=98;
+ FCArk.mzb=0;
+ return(&ARKCFC);
+}
+
+static uint8 FP_FASTAPASS(1) ReadARK(int w)
+{
+ uint8 ret=0;
+
+ if(NESArk[w].readbit>=8)
+  ret|=1<<4;
+ else
+ {
+  ret|=((NESArk[w].mzx>>(7-NESArk[w].readbit))&1)<<4;
+  NESArk[w].readbit++;
+ }
+ ret|=(NESArk[w].mzb&1)<<3;
+ return(ret);
+}
+
+
+static void FP_FASTAPASS(1) StrobeARK(int w)
+{
+       NESArk[w].readbit=0;
+}
+
+static void FP_FASTAPASS(3) UpdateARK(int w, void *data, int arg)
+{
+ uint32 *ptr=data;
+ NESArk[w].mzx=FixX(ptr[0]);
+ NESArk[w].mzb=ptr[2]?1:0;
+}
+
+static INPUTC ARKC={ReadARK, 0, StrobeARK, UpdateARK, 0, 0};
+
+INPUTC *FCEU_InitArkanoid(int w)
+{
+ NESArk[w].mzx=98;
+ NESArk[w].mzb=0;
+ return(&ARKC);
+}
diff --git a/input/cursor.c b/input/cursor.c
new file mode 100644 (file)
index 0000000..cb78d73
--- /dev/null
@@ -0,0 +1,45 @@
+#include "share.h"
+
+static uint8 FCEUcursor[11*19]=
+{
+ 1,0,0,0,0,0,0,0,0,0,0,
+ 1,1,0,0,0,0,0,0,0,0,0,
+ 1,2,1,0,0,0,0,0,0,0,0,
+ 1,2,2,1,0,0,0,0,0,0,0,
+ 1,2,2,2,1,0,0,0,0,0,0,
+ 1,2,2,2,2,1,0,0,0,0,0,
+ 1,2,2,2,2,2,1,0,0,0,0,
+ 1,2,2,2,2,2,2,1,0,0,0,
+ 1,2,2,2,2,2,2,2,1,0,0,
+ 1,2,2,2,2,2,2,2,2,1,0,
+ 1,2,2,2,2,2,1,1,1,1,1,
+ 1,2,2,1,2,2,1,0,0,0,0,
+ 1,2,1,0,1,2,2,1,0,0,0,
+ 1,1,0,0,1,2,2,1,0,0,0,
+ 1,0,0,0,0,1,2,2,1,0,0,
+ 0,0,0,0,0,1,2,2,1,0,0,
+ 0,0,0,0,0,0,1,2,2,1,0,
+ 0,0,0,0,0,0,1,2,2,1,0,
+ 0,0,0,0,0,0,0,1,1,0,0,
+};
+
+void FCEU_DrawCursor(uint8 *buf, int xc, int yc)
+{
+ int x,y;
+ int c,d;
+
+  if(xc<256 && yc<240)
+  for(y=0;y<19;y++)
+   for(x=0;x<11;x++)
+   {
+    uint8 a;
+    a=FCEUcursor[y*11+x];
+    if(a)
+    {
+     c=(yc+y);
+     d=(xc+x);
+     if(d<256 && c<240)
+      buf[c*272+d]=a+127;
+    }
+   }
+}
diff --git a/input/fkb.c b/input/fkb.c
new file mode 100644 (file)
index 0000000..c70e73f
--- /dev/null
@@ -0,0 +1,102 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <string.h>
+#include "share.h"
+#include "fkb.h"
+#define AK2(x,y)       ( (FKB_##x) | (FKB_##y <<8) )
+#define AK(x)          FKB_##x
+
+static uint8 bufit[0x49];
+static uint8 ksmode;
+static uint8 ksindex;
+
+
+static uint16 matrix[9][2][4]=
+{
+{{AK(F8),AK(RETURN),AK(BRACKETLEFT),AK(BRACKETRIGHT)},   
+       {AK(KANA),AK(RIGHTSHIFT),AK(BACKSLASH),AK(STOP)}},
+{{AK(F7),AK(AT),AK(COLON),AK(SEMICOLON)},              
+       {AK(UNDERSCORE),AK(SLASH),AK(MINUS),AK(CARET)}},
+{{AK(F6),AK(O),AK(L),AK(K)},   
+       {AK(PERIOD),AK(COMMA),AK(P),AK(0)}},
+{{AK(F5),AK(I),AK(U),AK(J)},           
+       {AK(M),AK(N),AK(9),AK(8)}},
+{{AK(F4),AK(Y),AK(G),AK(H)},  
+       {AK(B),AK(V),AK(7),AK(6)}},
+{{AK(F3),AK(T),AK(R),AK(D)},  
+       {AK(F),AK(C),AK(5),AK(4)}},
+{{AK(F2),AK(W),AK(S),AK(A)},  
+       {AK(X),AK(Z),AK(E),AK(3)}},
+{{AK(F1),AK(ESCAPE),AK(Q),AK(CONTROL)},    
+       {AK(LEFTSHIFT),AK(GRAPH),AK(1),AK(2)}},
+{{AK(CLEAR),AK(UP),AK(RIGHT),AK(LEFT)},    
+       {AK(DOWN),AK(SPACE),AK(DELETE),AK(INSERT)}},
+};
+
+static void FP_FASTAPASS(1) FKB_Write(uint8 v)
+{
+ v>>=1;
+ if(v&2)
+ {
+  if((ksmode&1) && !(v&1))
+   ksindex=(ksindex+1)%9;
+ }
+ ksmode=v;
+}
+
+static uint8 FP_FASTAPASS(2) FKB_Read(int w, uint8 ret)
+{
+ //printf("$%04x, %d, %d\n",w+0x4016,ksindex,ksmode&1);
+ if(w)
+ {
+  int x;
+
+  ret&=~0x1E;
+  for(x=0;x<4;x++)
+    if(bufit[ matrix[ksindex][ksmode&1][x]&0xFF ] || bufit[ matrix[ksindex][ksmode&1][x]>>8])
+    {
+     ret|=1<<(x+1);
+    }
+  ret^=0x1E;
+ }
+ return(ret);
+}
+
+static void FKB_Strobe(void)
+{
+ ksmode=0;
+ ksindex=0;
+ //printf("strobe\n");
+}
+
+static void FP_FASTAPASS(2) FKB_Update(void *data, int arg)
+{
+ memcpy(bufit+1,data,0x48);
+}
+
+static INPUTCFC FKB={FKB_Read,FKB_Write,FKB_Strobe,FKB_Update,0,0};
+
+INPUTCFC *FCEU_InitFKB(void)
+{
+ memset(bufit,0,sizeof(bufit));
+ ksmode=ksindex=0;
+ return(&FKB);
+}
diff --git a/input/fkb.h b/input/fkb.h
new file mode 100644 (file)
index 0000000..ca27b34
--- /dev/null
@@ -0,0 +1,72 @@
+#define FKB_F1 0x01
+#define FKB_F2 0x02
+#define FKB_F3 0x03
+#define FKB_F4 0x04
+#define FKB_F5 0x05
+#define FKB_F6 0x06
+#define FKB_F7 0x07
+#define FKB_F8 0x08
+#define FKB_1  0x09
+#define FKB_2   0x0A
+#define FKB_3   0x0B
+#define FKB_4   0x0C
+#define FKB_5   0x0D
+#define FKB_6   0x0E
+#define FKB_7   0x0F
+#define FKB_8   0x10
+#define FKB_9   0x11
+#define FKB_0  0x12
+#define FKB_MINUS      0x13
+#define FKB_CARET      0x14
+#define FKB_BACKSLASH  0x15
+#define FKB_STOP       0x16
+#define FKB_ESCAPE     0x17
+#define FKB_Q          0x18
+#define FKB_W           0x19
+#define FKB_E           0x1A
+#define FKB_R           0x1B
+#define FKB_T           0x1C
+#define FKB_Y           0x1D
+#define FKB_U           0x1E
+#define FKB_I           0x1F
+#define FKB_O           0x20
+#define FKB_P           0x21
+#define FKB_AT          0x22
+#define FKB_BRACKETLEFT 0x23
+#define FKB_RETURN      0x24
+#define FKB_CONTROL     0x25
+#define FKB_A           0x26
+#define FKB_S           0x27
+#define FKB_D           0x28
+#define FKB_F           0x29
+#define FKB_G           0x2A
+#define FKB_H           0x2B
+#define FKB_J           0x2C
+#define FKB_K           0x2D
+#define FKB_L           0x2E
+#define FKB_SEMICOLON   0x2F
+#define FKB_COLON       0x30
+#define FKB_BRACKETRIGHT 0x31
+#define FKB_KANA        0x32
+#define FKB_LEFTSHIFT   0x33
+#define FKB_Z           0x34
+#define FKB_X           0x35
+#define FKB_C           0x36
+#define FKB_V           0x37
+#define FKB_B           0x38
+#define FKB_N           0x39
+#define FKB_M           0x3A
+#define FKB_COMMA       0x3B
+#define FKB_PERIOD      0x3C
+#define FKB_SLASH       0x3D
+#define FKB_UNDERSCORE  0x3E
+#define FKB_RIGHTSHIFT  0x3F
+#define FKB_GRAPH       0x40
+#define FKB_SPACE       0x41
+#define FKB_CLEAR       0x42
+#define FKB_INSERT      0x43
+#define FKB_DELETE      0x44
+#define FKB_UP          0x45
+#define FKB_LEFT        0x46
+#define FKB_RIGHT       0x47
+#define FKB_DOWN        0x48
diff --git a/input/powerpad.c b/input/powerpad.c
new file mode 100644 (file)
index 0000000..3c613f9
--- /dev/null
@@ -0,0 +1,60 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include        <string.h>
+#include       <stdlib.h>
+#include       "share.h"
+
+
+static uint32 pprsb[2];
+static uint32 pprdata[2];
+
+static uint8 FP_FASTAPASS(1) ReadPP(int w)
+{
+                uint8 ret=0;
+                ret|=((pprdata[w]>>pprsb[w])&1)<<3;
+                ret|=((pprdata[w]>>(pprsb[w]+8))&1)<<4;
+               if(pprsb[w]>=4) 
+               {
+                ret|=0x10;
+                if(pprsb[w]>=8) 
+                 ret|=0x08;
+               }
+                pprsb[w]++;
+                return ret;
+}
+
+static void FP_FASTAPASS(1) StrobePP(int w)
+{
+               pprsb[w]=0;
+}
+
+void FP_FASTAPASS(3) UpdatePP(int w, void *data, int arg)
+{
+        pprdata[w]=*(uint32 *)data;
+}
+
+static INPUTC PPC={ReadPP,0,StrobePP,UpdatePP,0,0};
+
+INPUTC *FCEU_InitPowerpad(int w)
+{
+ pprsb[w]=pprdata[w]=0;
+ return(&PPC);
+}
diff --git a/input/shadow.c b/input/shadow.c
new file mode 100644 (file)
index 0000000..499e640
--- /dev/null
@@ -0,0 +1,127 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include        <string.h>
+#include       <stdlib.h>
+
+#include        "share.h"
+
+typedef struct {
+        uint32 mzx,mzy,mzb;
+        int zap_readbit;
+        int bogo;
+        uint32 colok;
+        uint32 coloklast;
+} ZAPPER;
+
+static ZAPPER ZD;
+
+static void FP_FASTAPASS(2) ZapperThingy(uint8 *buf, int line)
+{
+       int mzx=ZD.mzx;
+
+       if(line==0) ZD.colok=1<<16;     /* Disable it. */
+       ZD.coloklast=ZD.colok;
+
+       if((line>=ZD.mzy-3 && line<=ZD.mzy+3) && mzx<256)
+       {
+        int a,sum,x;
+
+        for(x=-4;x<4;x++)
+        {
+         if((mzx+x)<0 || (mzx+x)>255) continue;
+         a=buf[mzx+x]&63;
+         sum=palo[a].r+palo[a].g+palo[a].b;
+        
+         if(sum>=100*3)
+         {
+          ZD.colok=timestamp+mzx/3;
+          break;
+         }
+        }
+       }
+}
+
+static INLINE int CheckColor(void)
+{
+  if( (timestamp>=ZD.coloklast && timestamp<=(ZD.coloklast+10)) ||
+   (timestamp>=ZD.colok && timestamp<=(ZD.colok+10)) )
+   return 0;
+  return 1;
+}
+
+static uint8 FP_FASTAPASS(2) ReadZapper(int w, uint8 ret)
+{
+               if(w)
+               {
+                ret&=~0x18;
+                 if(ZD.bogo)
+                  ret|=0x10;
+                 if(CheckColor())
+                  ret|=0x8;
+               }
+               else
+               {
+                //printf("Kayo: %d\n",ZD.zap_readbit);
+                ret&=~2;
+                //if(ZD.zap_readbit==4) ret|=ZD.mzb&2;
+                ret|=(ret&1)<<1;
+                //ZD.zap_readbit++;
+               }
+                return ret;
+}
+
+static void FP_FASTAPASS(2) DrawZapper(uint8 *buf, int arg)
+{
+ if(arg)
+  FCEU_DrawCursor(buf, ZD.mzx, ZD.mzy);
+}
+
+static void FP_FASTAPASS(2) UpdateZapper(void *data, int arg)
+{
+  uint32 *ptr=data;
+
+  if(ZD.bogo)
+   ZD.bogo--;
+  if(ptr[2]&1 && (!(ZD.mzb&1)))
+   ZD.bogo=5;
+
+  ZD.mzx=ptr[0];
+  ZD.mzy=ptr[1];
+  ZD.mzb=ptr[2];
+
+  if(ZD.mzx>=256 || ZD.mzy>=240)
+   ZD.colok=0;
+}
+
+static void StrobeShadow(void)
+{
+ ZD.zap_readbit=0;
+}
+
+static INPUTCFC SHADOWC={ReadZapper,0,StrobeShadow,UpdateZapper,ZapperThingy,DrawZapper};
+
+INPUTCFC *FCEU_InitSpaceShadow(void)
+{
+  memset(&ZD,0,sizeof(ZAPPER));
+  return(&SHADOWC);
+}
+
+
diff --git a/input/share.h b/input/share.h
new file mode 100644 (file)
index 0000000..8e8c333
--- /dev/null
@@ -0,0 +1,7 @@
+#include "../types.h"
+#include "../input.h"
+#include "../fce.h"
+#include "../svga.h"
+#include "../x6502.h"
+
+void FCEU_DrawCursor(uint8 *buf, int xc, int yc);
diff --git a/input/zapper.c b/input/zapper.c
new file mode 100644 (file)
index 0000000..16f9e15
--- /dev/null
@@ -0,0 +1,143 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include        <string.h>
+#include       <stdlib.h>
+
+#include        "share.h"
+
+typedef struct {
+        uint32 mzx,mzy,mzb;
+        int zap_readbit;
+        int bogo;
+        uint32 colok;
+       uint32 coloklast;
+} ZAPPER;
+
+static ZAPPER ZD[2];
+
+static void FP_FASTAPASS(3) ZapperThingy(int w, uint8 *buf, int line)
+{
+       int mzx=ZD[w].mzx;
+
+        if(line==0) ZD[w].colok=1<<16;     /* Disable it. */
+
+       ZD[w].coloklast=ZD[w].colok;
+
+       if(ZD[w].mzb&2) return;
+        if((line>=ZD[w].mzy-3 && line<=ZD[w].mzy+3) && mzx<256)
+        {
+         int a,sum,x;
+
+         for(x=-4;x<4;x++)
+         {
+          if((mzx+x)<0 || (mzx+x)>255) continue;
+          a=buf[mzx+x]&63;
+          sum=palo[a].r+palo[a].g+palo[a].b;
+
+          if(sum>=100*3)
+          {
+           ZD[w].colok=timestamp+mzx/3;
+           break;
+          }
+         }
+        }
+
+}
+
+static INLINE int CheckColor(int w)
+{
+  if( (timestamp>=ZD[w].coloklast && timestamp<=(ZD[w].coloklast+100)) ||
+   (timestamp>=ZD[w].colok && timestamp<=(ZD[w].colok+100)) )
+   return 0;
+  return 1;
+}
+
+static uint8 FP_FASTAPASS(1) ReadZapperVS(int w)
+{
+                uint8 ret=0;
+
+                if(ZD[w].zap_readbit==4) ret=1;
+
+                if(ZD[w].zap_readbit==7)
+                {
+                 if(ZD[w].bogo)
+                  ret|=0x1;
+                }
+                if(ZD[w].zap_readbit==6)
+                {
+                 if(!CheckColor(w))
+                  ret|=0x1;
+                }
+                ZD[w].zap_readbit++; 
+                return ret;
+}
+
+static void FP_FASTAPASS(1) StrobeZapperVS(int w)
+{                        
+                       ZD[w].zap_readbit=0;
+}
+
+static uint8 FP_FASTAPASS(1) ReadZapper(int w)
+{
+                uint8 ret=0;
+                if(ZD[w].bogo)
+                 ret|=0x10;
+                if(CheckColor(w))
+                 ret|=0x8;
+                return ret;
+}
+
+static void FASTAPASS(3) DrawZapper(int w, uint8 *buf, int arg)
+{
+ if(arg)
+  FCEU_DrawCursor(buf, ZD[w].mzx,ZD[w].mzy);
+}
+
+static void FP_FASTAPASS(3) UpdateZapper(int w, void *data, int arg)
+{
+  uint32 *ptr=data;
+
+  if(ZD[w].bogo)
+   ZD[w].bogo--;
+  if(ptr[2]&3 && (!(ZD[w].mzb&3)))
+   ZD[w].bogo=5;
+
+  ZD[w].mzx=ptr[0];
+  ZD[w].mzy=ptr[1];
+  ZD[w].mzb=ptr[2];
+
+  if(ZD[w].mzb&2 || ZD[w].mzx>=256 || ZD[w].mzy>=240)
+   ZD[w].colok=0;
+}
+
+static INPUTC ZAPC={ReadZapper,0,0,UpdateZapper,ZapperThingy,DrawZapper};
+static INPUTC ZAPVSC={ReadZapperVS,0,StrobeZapperVS,UpdateZapper,ZapperThingy,DrawZapper};
+
+INPUTC *FCEU_InitZapper(int w)
+{
+  memset(&ZD[w],0,sizeof(ZAPPER));
+  if(FCEUGameInfo.type==GIT_VSUNI)
+   return(&ZAPVSC);
+  else
+   return(&ZAPC);
+}
+
+
diff --git a/mappers/105.c b/mappers/105.c
new file mode 100644 (file)
index 0000000..977e9f2
--- /dev/null
@@ -0,0 +1,131 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 BERO
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define MMC1_reg mapbyte1
+#define MMC1_buf mapbyte2[0]
+#define MMC1_sft mapbyte3[0]
+#define lastn    mapbyte2[1]
+
+#define NWCDIP 0xE
+
+static void FP_FASTAPASS(1) NWCIRQHook(int a)
+{
+       if(!(MMC1_reg[1]&0x10))
+       {
+        IRQCount+=a;
+        if((IRQCount|(NWCDIP<<25))>=0x3e000000)
+          {
+          IRQCount=0;
+          X6502_IRQBegin(FCEU_IQEXT);
+         }
+       }
+}
+
+
+static void MMC1PRG(void)
+{
+       if(MMC1_reg[1]&8)
+       {       
+        switch(MMC1_reg[0]&0xC)
+         { 
+           case 0xC: ROM_BANK16(0x8000,8+(MMC1_reg[3]&7));
+                     ROM_BANK16(0xC000,15);
+                     break;
+           case 0x8: ROM_BANK16(0xC000,8+((MMC1_reg[3])&7));
+                     ROM_BANK16(0x8000,8);
+                     break;
+           case 0x0:
+           case 0x4:
+                     ROM_BANK16(0x8000,8+(MMC1_reg[3]&6));
+                     ROM_BANK16(0xc000,8+((MMC1_reg[3]&6)+1));
+                     break;
+         }
+       }
+       else
+       {
+        ROM_BANK32((MMC1_reg[1]>>1)&3);
+       }
+}
+
+DECLFW(Mapper105_write)
+{
+        int n=(A>>13)-4;
+
+        if (V&0x80)
+        {
+         MMC1_sft=MMC1_buf=0;
+         return;
+        }
+
+        if(lastn!=n)
+        {
+         MMC1_sft=MMC1_buf=0;
+        }
+        lastn=n;
+
+       //MMC1_reg[n]&=~((1)<<(MMC1_sft));
+        MMC1_buf|=(V&1)<<(MMC1_sft++);
+
+  if (MMC1_sft==5) 
+       {
+        if(n==3) V&=0xF;
+        else     V&=0x1F;
+
+        MMC1_reg[n]=V=MMC1_buf;
+        MMC1_sft = MMC1_buf=0;
+
+        switch(n){
+        case 0:
+                switch(MMC1_reg[0]&3)
+                {
+                 case 2: MIRROR_SET(0);break;
+                 case 3: MIRROR_SET(1);break;
+                 case 0: onemir(0);break;
+                 case 1: onemir(1);break;
+                }
+                MMC1PRG();
+                break;
+        case 1:
+               if(MMC1_reg[1]&0x10)
+                {IRQCount=0;X6502_IRQEnd(FCEU_IQEXT);}
+                MMC1PRG();
+                break;
+        case 3:
+                MMC1PRG();
+                break;
+        }
+  }
+}
+
+
+void Mapper105_init(void)
+{
+        int i;
+        for(i=0;i<4;i++) MMC1_reg[i]=0;
+        MMC1_sft = MMC1_buf =0;
+        MMC1_reg[0]=0xC;
+        ROM_BANK32(0);
+       SetWriteHandler(0x8000,0xFFFF,Mapper105_write);
+       MapIRQHook=NWCIRQHook;
+}
+
diff --git a/mappers/112.c b/mappers/112.c
new file mode 100644 (file)
index 0000000..bfa4595
--- /dev/null
@@ -0,0 +1,52 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper112_write)
+{
+switch(A)
+{
+ case 0xe000:MIRROR_SET(V&1);break;
+ case 0x8000:mapbyte1[0]=V;break;
+ case 0xa000:switch(mapbyte1[0])
+            {
+            case 0:ROM_BANK8(0x8000,V);break;
+            case 1:ROM_BANK8(0xA000,V);break;
+                case 2: V&=0xFE;VROM_BANK1(0,V);
+                        VROM_BANK1(0x400,(V+1));break;
+                case 3: V&=0xFE;VROM_BANK1(0x800,V);
+                        VROM_BANK1(0xC00,(V+1));break;
+            case 4:VROM_BANK1(0x1000,V);break;
+            case 5:VROM_BANK1(0x1400,V);break;
+            case 6:VROM_BANK1(0x1800,V);break;
+            case 7:VROM_BANK1(0x1c00,V);break;
+            }
+            break;
+ }
+}
+
+void Mapper112_init(void)
+{
+  SetWriteHandler(0x8000,0xffff,Mapper112_write);
+}
+
diff --git a/mappers/113.c b/mappers/113.c
new file mode 100644 (file)
index 0000000..66548b5
--- /dev/null
@@ -0,0 +1,47 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+/*      I'm getting the feeling this is another "jam two different bank
+        switching hardwares into one mapper".
+*/        
+
+/* HES 4-in-1 */
+DECLFW(Mapper113_write)
+{
+        ROM_BANK32((V>>3)&7);
+        VROM_BANK8(V&7);
+}
+
+      
+/*      Deathbots */
+DECLFW(Mapper113_writeh)
+{
+        ROM_BANK32(V&0xF);
+}
+
+
+void Mapper113_init(void)
+{
+ ROM_BANK32(0);
+ SetWriteHandler(0x4020,0x7fff,Mapper113_write);
+ SetWriteHandler(0x8000,0xffff,Mapper113_writeh);
+}
diff --git a/mappers/117.c b/mappers/117.c
new file mode 100644 (file)
index 0000000..aa0ea5f
--- /dev/null
@@ -0,0 +1,67 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper117_write)
+{
+ switch(A)
+ {
+  case 0xc003:IRQCount=V;break;
+  case 0xc001:IRQa=V;break;
+  case 0xa000:VROM_BANK1(0x0000,V);break;
+  case 0xa001:VROM_BANK1(0x0400,V);break;
+  case 0xa002:VROM_BANK1(0x0800,V);break;
+  case 0xa003:VROM_BANK1(0x0c00,V);break;
+  case 0xa004:VROM_BANK1(0x1000,V);break;
+  case 0xa005:VROM_BANK1(0x1400,V);break;
+  case 0xa006:VROM_BANK1(0x1800,V);break;
+  case 0xa007:VROM_BANK1(0x1c00,V);break;
+  case 0x8000:ROM_BANK8(0x8000,V);break;
+  case 0x8001:ROM_BANK8(0xa000,V);break;
+  case 0x8002:ROM_BANK8(0xc000,V);break;
+  case 0x8003:ROM_BANK8(0xe000,V);break;
+ }
+}
+
+static void Mapper117_hb(void)
+{
+ if(IRQa)
+ {
+        if(IRQCount<=0)
+        {
+         IRQa=0;
+         TriggerIRQ();
+        }
+        else
+        {
+         IRQCount--;
+        }
+ }
+}
+
+void Mapper117_init(void)
+{
+  GameHBIRQHook=Mapper117_hb;
+  SetWriteHandler(0x8000,0xffff,Mapper117_write);
+}
+
diff --git a/mappers/15.c b/mappers/15.c
new file mode 100644 (file)
index 0000000..05146af
--- /dev/null
@@ -0,0 +1,87 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 BERO
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+
+
+DECLFW(Mapper15_write)
+{
+switch(A)
+ {
+  case 0x8000:
+        if(V&0x80)
+        {
+        ROM_BANK8(0x8000,(V<<1)+1);
+        ROM_BANK8(0xA000,(V<<1));
+        ROM_BANK8(0xC000,(V<<1)+2);
+        ROM_BANK8(0xE000,(V<<1)+1);
+        }
+        else
+        {
+        ROM_BANK16(0x8000,V);
+        ROM_BANK16(0xC000,V+1);
+        }
+        MIRROR_SET((V>>6)&1);
+        break;
+  case 0x8001:
+        MIRROR_SET(0);
+        ROM_BANK16(0x8000,V);
+        ROM_BANK16(0xc000,~0);
+        break;
+  case 0x8002:
+        if(V&0x80)
+        {
+         ROM_BANK8(0x8000,((V<<1)+1));
+         ROM_BANK8(0xA000,((V<<1)+1));
+         ROM_BANK8(0xC000,((V<<1)+1));
+         ROM_BANK8(0xE000,((V<<1)+1));
+        }
+        else
+        {
+         ROM_BANK8(0x8000,(V<<1));
+         ROM_BANK8(0xA000,(V<<1));
+         ROM_BANK8(0xC000,(V<<1));
+         ROM_BANK8(0xE000,(V<<1));
+        }
+        break;
+  case 0x8003:
+        MIRROR_SET((V>>6)&1);
+        if(V&0x80)
+        {
+         ROM_BANK8(0xC000,(V<<1)+1);
+         ROM_BANK8(0xE000,(V<<1));
+        }
+        else
+        {
+         ROM_BANK16(0xC000,V);
+        }
+        break;
+ }
+}
+
+void Mapper15_init(void)
+{
+        ROM_BANK32(0);
+       SetWriteHandler(0x8000,0xFFFF,Mapper15_write);
+}
+
diff --git a/mappers/151.c b/mappers/151.c
new file mode 100644 (file)
index 0000000..cc59c6c
--- /dev/null
@@ -0,0 +1,41 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper151_write)
+{
+ switch(A&0xF000)
+ {
+  case 0x8000:ROM_BANK8(0x8000,V);break;
+  case 0xA000:ROM_BANK8(0xA000,V);break;
+  case 0xC000:ROM_BANK8(0xC000,V);break;
+  case 0xe000:VROM_BANK4(0x0000,V);break;
+  case 0xf000:VROM_BANK4(0x1000,V);break;
+ }
+}
+
+void Mapper151_init(void)
+{
+  SetWriteHandler(0x8000,0xffff,Mapper151_write);
+}
+
diff --git a/mappers/16.c b/mappers/16.c
new file mode 100644 (file)
index 0000000..3742c34
--- /dev/null
@@ -0,0 +1,129 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 BERO
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+static void FP_FASTAPASS(1) BandaiIRQHook(int a)
+{
+  if(IRQa)
+  {
+   IRQCount-=a;
+   if(IRQCount<0)
+   {
+    X6502_IRQBegin(FCEU_IQEXT);
+    //printf("IRQ: %d, %d\n",scanline,timestamp);
+    IRQa=0;
+    IRQCount=0xFFFF;
+   }
+  }
+}
+
+static DECLFW(Mapper16_write)
+{
+        A&=0xF;
+
+        if(A<=0x7)
+         VROM_BANK1(A<<10,V);
+        else if(A==0x8)
+         ROM_BANK16(0x8000,V);
+        else switch(A) {
+         case 0x9: switch(V&3) {
+                    case 0x00:MIRROR_SET2(1);break;
+                    case 0x01:MIRROR_SET2(0);break;
+                    case 0x02:onemir(0);break;
+                    case 0x03:onemir(1);break;
+                   }
+                   break;
+         case 0xA:X6502_IRQEnd(FCEU_IQEXT);
+                  IRQa=V&1;
+                  IRQCount=IRQLatch;
+                  break;
+         case 0xB:IRQLatch&=0xFF00;
+                  IRQLatch|=V;
+                  break;
+         case 0xC:IRQLatch&=0xFF;
+                  IRQLatch|=V<<8;
+                  break;
+         case 0xD: break;/* Serial EEPROM control port */
+ }
+}
+
+// Famicom jump 2:
+// 0-7: Lower bit of data selects which 256KB PRG block is in use.
+// This seems to be a hack on the developers' part, so I'll make emulation
+// of it a hack(I think the current PRG block would depend on whatever the
+// lowest bit of the CHR bank switching register that corresponds to the
+// last CHR address read).
+
+static void PRGO(void)
+{
+ uint32 base=(mapbyte1[0]&1)<<4;
+ ROM_BANK16(0x8000,(mapbyte2[0]&0xF)|base);
+ ROM_BANK16(0xC000,base|0xF);
+}
+
+static DECLFW(Mapper153_write)
+{
+       A&=0xF;
+        if(A<=0x7) 
+       {
+        mapbyte1[A&7]=V;
+        PRGO();
+       }
+        else if(A==0x8) 
+       {
+        mapbyte2[0]=V;
+        PRGO();
+       }
+       else switch(A) {
+        case 0x9: switch(V&3) {
+                           case 0x00:MIRROR_SET2(1);break;
+                    case 0x01:MIRROR_SET2(0);break;
+                    case 0x02:onemir(0);break;
+                    case 0x03:onemir(1);break;
+                   }
+                   break;
+         case 0xA:X6502_IRQEnd(FCEU_IQEXT);
+                 IRQa=V&1;
+                 IRQCount=IRQLatch;
+                 break;
+         case 0xB:IRQLatch&=0xFF00;
+                 IRQLatch|=V;
+                 break;
+         case 0xC:IRQLatch&=0xFF;
+                 IRQLatch|=V<<8;
+                 break;
+        }
+}
+
+void Mapper16_init(void)
+{
+ MapIRQHook=BandaiIRQHook;
+ SetWriteHandler(0x6000,0xFFFF,Mapper16_write);
+}
+
+void Mapper153_init(void)
+{
+ MapIRQHook=BandaiIRQHook;
+ SetWriteHandler(0x8000,0xFFFF,Mapper153_write);
+ /* This mapper/board seems to have WRAM at $6000-$7FFF, so I'll let the
+    main ines code take care of that memory region. */
+}
diff --git a/mappers/17.c b/mappers/17.c
new file mode 100644 (file)
index 0000000..66b85d4
--- /dev/null
@@ -0,0 +1,74 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+
+static void FP_FASTAPASS(1) FFEIRQHook(int a)
+{
+  if(IRQa)
+  {
+   IRQCount+=a;
+
+   if(IRQCount>=0x10000)
+   {
+    TriggerIRQ();
+    IRQa=0;
+    IRQCount=0;
+   }
+  }
+}
+
+
+DECLFW(Mapper17_write)
+{
+        switch(A){
+        default:
+                  break;
+        case 0x42FE:
+                   onemir((V>>4)&1);
+                   break;
+        case 0x42FF:
+                   MIRROR_SET((V>>4)&1);
+                  break;
+        case 0x4501:IRQa=V&1;break;
+        case 0x4502:IRQCount&=0xFF00;IRQCount|=V;break;
+        case 0x4503:IRQCount&=0x00FF;IRQCount|=V<<8;IRQa=1;break;
+        case 0x4504: ROM_BANK8(0x8000,V);break;
+        case 0x4505: ROM_BANK8(0xA000,V);break;
+        case 0x4506: ROM_BANK8(0xC000,V);break;
+        case 0x4507: ROM_BANK8(0xE000,V);break;
+        case 0x4510: VROM_BANK1(0x0000,V);break;
+        case 0x4511: VROM_BANK1(0x0400,V);break;
+        case 0x4512: VROM_BANK1(0x0800,V);break;
+        case 0x4513: VROM_BANK1(0x0C00,V);break;
+        case 0x4514: VROM_BANK1(0x1000,V);break;
+        case 0x4515: VROM_BANK1(0x1400,V);break;
+        case 0x4516: VROM_BANK1(0x1800,V);break;
+        case 0x4517: VROM_BANK1(0x1C00,V);break;
+        }
+}
+
+void Mapper17_init(void)
+{
+MapIRQHook=FFEIRQHook;
+SetWriteHandler(0x4020,0x5fff,Mapper17_write);
+}
diff --git a/mappers/18.c b/mappers/18.c
new file mode 100644 (file)
index 0000000..f77e831
--- /dev/null
@@ -0,0 +1,80 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define K4buf mapbyte2
+#define K4buf2 mapbyte3
+
+void FP_FASTAPASS(1) JalecoIRQHook(int a)
+{
+  if(IRQa && IRQCount)
+  {
+   IRQCount-=a;
+   if(IRQCount<=0)
+   {
+    X6502_IRQBegin(FCEU_IQEXT);
+    IRQCount=0;
+    IRQa=0;
+   }
+  }
+}
+
+DECLFW(Mapper18_write)
+{
+       A&=0xF003;
+       if(A>=0x8000 && A<=0x9001)
+       {
+         int x=((A>>1)&1)|((A-0x8000)>>11);
+
+         K4buf2[x]&=(0xF0)>>((A&1)<<2);
+         K4buf2[x]|=(V&0xF)<<((A&1)<<2);
+         ROM_BANK8(0x8000+(x<<13),K4buf2[x]);
+       }
+       else if(A>=0xa000 && A<=0xd003)
+       {
+        int x=((A>>1)&1)|((A-0xA000)>>11);
+
+         K4buf[x]&=(0xF0)>>((A&1)<<2);
+         K4buf[x]|=(V&0xF)<<((A&1)<<2);
+         VROM_BANK1(x<<10,K4buf[x]);
+       }
+        else switch(A)
+        {
+        case 0xe000:IRQLatch&=0xFFF0;IRQLatch|=(V&0x0f);break;
+        case 0xe001:IRQLatch&=0xFF0F;IRQLatch|=(V&0x0f)<<4;break;
+        case 0xe002:IRQLatch&=0xF0FF;IRQLatch|=(V&0x0f)<<8;break;
+        case 0xe003:IRQLatch&=0x0FFF;IRQLatch|=(V&0x0f)<<12;break;
+        case 0xf000:IRQCount=IRQLatch;
+                    break;
+        case 0xf001:IRQa=V&1;
+                    X6502_IRQEnd(FCEU_IQEXT);
+                    break;
+        case 0xf002:MIRROR_SET2(V&1);
+                    if(V&2) onemir(0);
+                    break;
+        }
+}
+
+void Mapper18_init(void)
+{
+ SetWriteHandler(0x8000,0xffff,Mapper18_write);
+ MapIRQHook=JalecoIRQHook;
+}
diff --git a/mappers/180.c b/mappers/180.c
new file mode 100644 (file)
index 0000000..bd877c8
--- /dev/null
@@ -0,0 +1,14 @@
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper180_write)
+{
+ROM_BANK16(0xC000,V);
+}
+
+void Mapper180_init(void)
+{
+  SetWriteHandler(0x8000,0xffff,Mapper180_write);
+}
+
diff --git a/mappers/182.c b/mappers/182.c
new file mode 100644 (file)
index 0000000..5fe0750
--- /dev/null
@@ -0,0 +1,48 @@
+#include "mapinc.h"
+
+DECLFW(Mapper182_write)
+{
+  switch(A&0xf003)
+  {
+   case 0xe003:IRQCount=V;IRQa=1;break;
+   case 0x8001:MIRROR_SET(V&1);break;
+   case 0xA000:mapbyte1[0]=V;break;
+   case 0xC000:
+               switch(mapbyte1[0]&7)
+               {
+                case 0:VROM_BANK2(0x0000,V>>1);break;
+                case 1:VROM_BANK1(0x1400,V);break;
+                case 2:VROM_BANK2(0x0800,V>>1);break;
+                case 3:VROM_BANK1(0x1c00,V);break;
+                case 4:ROM_BANK8(0x8000,V);break;
+                case 5:ROM_BANK8(0xA000,V);break;
+                case 6:VROM_BANK1(0x1000,V);break;
+                case 7:VROM_BANK1(0x1800,V);break;
+               }
+               break;
+
+
+  }
+}
+
+void blop(void)
+{
+ if(IRQa)
+  {
+   if(IRQCount)
+   {
+    IRQCount--;
+    if(!IRQCount)
+    {
+     IRQa=0;
+     TriggerIRQ();
+    }
+   }
+  }
+}
+void Mapper182_init(void)
+{
+ SetWriteHandler(0x8000,0xFFFF,Mapper182_write);
+ GameHBIRQHook=blop;
+}
+
diff --git a/mappers/184.c b/mappers/184.c
new file mode 100644 (file)
index 0000000..70fd6b1
--- /dev/null
@@ -0,0 +1,15 @@
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper184_write)
+{
+VROM_BANK4(0x0000,V);
+VROM_BANK4(0x1000,(V>>4));
+}
+
+void Mapper184_init(void)
+{
+  SetWriteHandler(0x6000,0xffff,Mapper184_write);
+}
+
diff --git a/mappers/189.c b/mappers/189.c
new file mode 100644 (file)
index 0000000..7d8bcff
--- /dev/null
@@ -0,0 +1,37 @@
+/* Is this an MMC3 workalike piece of hardware, with the addition of
+   a register at $4120 or does it have only partial MMC3 functionality?
+   A good test would be to see if commands 6 and 7 can change PRG banks
+   and of course test the regs >=$c000, on the real cart.
+*/
+#include "mapinc.h"
+
+#define cmd mapbyte1[0]
+static DECLFW(Mapper189_write)
+{
+ if(A==0x4120) ROM_BANK32(V>>4);
+ else switch(A&0xE001)
+ {
+  case 0xa000:MIRROR_SET(V&1);break;
+  case 0x8000:cmd=V;break; 
+  case 0x8001:switch(cmd&7)
+             {
+              case 0:VROM_BANK2(0x0000,V>>1);break;
+              case 1:VROM_BANK2(0x0800,V>>1);break;
+              case 2:VROM_BANK1(0x1000,V);break;
+               case 3:VROM_BANK1(0x1400,V);break;
+               case 4:VROM_BANK1(0x1800,V);break;
+               case 5:VROM_BANK1(0x1C00,V);break;
+             }
+             break;
+
+ }
+}
+
+void Mapper189_init(void)
+{
+  SetWriteHandler(0x4120,0xFFFF,Mapper189_write);
+  SetReadHandler(0x6000,0x7FFF,0);
+  ROM_BANK32(0);
+}
+
+
diff --git a/mappers/19.c b/mappers/19.c
new file mode 100644 (file)
index 0000000..53de232
--- /dev/null
@@ -0,0 +1,286 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define dopol mapbyte1[0]
+#define gorfus mapbyte1[1]
+#define gorko mapbyte1[2]
+
+static void NamcoSound(int Count);
+static void NamcoSoundHack(void);
+
+static int32 inc;
+void FP_FASTAPASS(1) NamcoIRQHook(int a)
+{
+  if(IRQa)
+  {
+   IRQCount+=a;
+   if(IRQCount>=0x7fff)
+   {
+    X6502_IRQBegin(FCEU_IQEXT);
+    IRQa=0;
+    IRQCount=0x7fff;
+   }
+  }
+}
+
+DECLFR(Namco_Read4800)
+{
+       uint8 ret=MapperExRAM[dopol&0x7f];
+       if(dopol&0x80)
+        dopol=(dopol&0x80)|((dopol+1)&0x7f);
+       return ret;
+}
+
+DECLFR(Namco_Read5000)
+{
+ return(IRQCount);
+}
+
+DECLFR(Namco_Read5800)
+{
+ return(IRQCount>>8);
+}
+
+static void FASTAPASS(2) DoNTARAMROM(int w, uint8 V)
+{
+        mapbyte2[w]=V;
+        //if(V>=0xE0)
+       // setntamem(NTARAM+((V&1)<<10), 1, w);
+       if((V>=0xE0)) // || ((gorko>>(6+(w>>1)))&1) )
+        setntamem(NTARAM+((V&1)<<10), 1, w);
+       else 
+       {
+        V&=CHRmask1[0];
+        setntamem(VROM+(V<<10), 0, w);
+       }
+//     else
+//      setntamem(NTARAM+((V&1)<<10), 1, w);
+}
+
+static void FixNTAR(void)
+{
+ int x;
+
+ for(x=0;x<4;x++)
+  DoNTARAMROM(x,mapbyte2[x]);
+}
+
+static void FASTAPASS(2) DoCHRRAMROM(int x, uint8 V)
+{
+         mapbyte3[x]=V;
+         if(!((gorfus>>((x>>2)+6))&1) && (V>=0xE0))
+          VRAM_BANK1(x<<10,V&7);
+         else
+          VROM_BANK1(x<<10,V);
+}
+
+static void FixCRR(void)
+{
+ int x;
+ for(x=0;x<8;x++)
+  DoCHRRAMROM(x,mapbyte3[x]);
+}
+
+static DECLFW(Mapper19_write)
+{
+       A&=0xF800;
+
+       if(A>=0x8000 && A<=0xb800)
+        DoCHRRAMROM((A-0x8000)>>11,V);
+       else if(A>=0xC000 && A<=0xd800)
+        DoNTARAMROM((A-0xC000)>>11,V);
+        else switch(A)
+       {
+        case 0x4800:
+                  if(dopol&0x40)
+                   {
+                    if(FSettings.SndRate)
+                   {
+                    NamcoSoundHack();
+                     GameExpSound.Fill=NamcoSound;
+                   }
+                   }
+                  MapperExRAM[dopol&0x7f]=V;
+                   if(dopol&0x80)
+                    dopol=(dopol&0x80)|((dopol+1)&0x7f);
+                   break;
+
+        case 0xf800: dopol=V;break;
+        case 0x5000: IRQCount&=0xFF00;IRQCount|=V;X6502_IRQEnd(FCEU_IQEXT);break;
+        case 0x5800: IRQCount&=0x00ff;IRQCount|=(V&0x7F)<<8;
+                     IRQa=V&0x80;
+                     X6502_IRQEnd(FCEU_IQEXT);
+                     break;
+
+        case 0xE000:gorko=V&0xC0;
+                   //FixNTAR();
+                    ROM_BANK8(0x8000,V);
+                    break;
+        case 0xE800:gorfus=V&0xC0;
+                   FixCRR();
+                    ROM_BANK8(0xA000,V);
+                    break;
+        case 0xF000:
+                    ROM_BANK8(0xC000,V);
+                    break;
+        }
+}
+
+static int dwave=0;
+static void DoNamcoSound(uint32 *Wave, int Count);
+
+static void NamcoSoundHack(void)
+{
+ int32 z,a;
+
+ z=((timestamp<<16)/soundtsinc)>>4;  
+ a=z-dwave;
+ if(a)
+  DoNamcoSound(&Wave[dwave], a);
+ dwave+=a;
+}
+
+static void NamcoSound(int Count)
+{
+ int32 z,a;
+
+ z=((timestamp<<16)/soundtsinc)>>4;
+ a=z-dwave;
+ if(a)
+   DoNamcoSound(&Wave[dwave], a);
+ dwave=0;
+}
+
+static uint8 PlayIndex[8];
+static int32 vcount[8];
+
+static void DoNamcoSound(uint32 *Wave, int Count)
+{
+       int P,V;
+
+
+      //FCEU_DispMessage("%d",MapperExRAM[0x7F]>>4);
+      for(P=7;P>=7-((MapperExRAM[0x7F]>>4)&7);P--)
+      {
+       if((MapperExRAM[0x44+(P<<3)]&0xE0) && (MapperExRAM[0x47+(P<<3)]&0xF))
+       {
+       uint32 freq;
+       int32 vco;
+       uint32 duff,duff2,lengo,envelope;
+        //uint64 ta;
+
+        vco=vcount[P];
+        freq=MapperExRAM[0x40+(P<<3)];
+        freq|=MapperExRAM[0x42+(P<<3)]<<8;
+        freq|=(MapperExRAM[0x44+(P<<3)]&3)<<16;
+
+        if(!freq) continue;
+
+       {
+        int c=((MapperExRAM[0x7F]>>4)&7)+1;
+
+        inc=(long double)(FSettings.SndRate<<15)/((long double)freq*
+               21477272/((long double)0x400000*c*45));
+       }
+
+        envelope=((MapperExRAM[0x47+(P<<3)]&0xF)<<18)/15;
+        duff=MapperExRAM[(((MapperExRAM[0x46+(P<<3)]+PlayIndex[P])>>1)&0xFF)];
+        if((MapperExRAM[0x46+(P<<3)]+PlayIndex[P])&1)
+         duff>>=4;
+        duff&=0xF;
+        duff2=(duff*envelope)>>14;
+  
+        lengo=((8-((MapperExRAM[0x44+(P<<3)]>>2)&7)))<<2;
+        for(V=0;V<Count OVERSAMPLE;V++)
+        {
+         if(vco>=inc)
+         {
+          PlayIndex[P]++;
+          if(PlayIndex[P]>=lengo)
+           PlayIndex[P]=0;
+          vco-=inc;
+          duff=MapperExRAM[(((MapperExRAM[0x46+(P<<3)]+PlayIndex[P])&0xFF)>>1)];
+          if((MapperExRAM[0x46+(P<<3)]+PlayIndex[P])&1)
+           duff>>=4;
+          duff&=0xF;
+          duff2=(duff*envelope)>>14;
+         }
+          Wave[V>>4]+=duff2;
+          vco+=0x8000;
+        }
+        vcount[P]=vco;
+       }
+      }
+}
+
+static void Mapper19_StateRestore(int version)
+{
+ FixNTAR();
+ if(version>=80)
+  FixCRR();
+}
+
+static void M19SC(void)
+{
+ if(FSettings.SndRate)
+  Mapper19_ESI();
+}
+
+void Mapper19_ESI(void)
+{
+  GameExpSound.RChange=M19SC;
+  SetWriteHandler(0xf800,0xffff,Mapper19_write);
+  SetWriteHandler(0x4800,0x4fff,Mapper19_write);
+  SetReadHandler(0x4800,0x4fff,Namco_Read4800);
+}
+
+void Mapper19_init(void)
+{
+        if(!Mirroring)
+        {
+         DoNTARAMROM(0,0xE0);
+         DoNTARAMROM(1,0xE0);
+         DoNTARAMROM(2,0xE1);
+         DoNTARAMROM(3,0xE1);
+        }
+        else
+        {
+         DoNTARAMROM(0,0xE0);
+         DoNTARAMROM(2,0xE0);
+         DoNTARAMROM(1,0xE1);
+         DoNTARAMROM(3,0xE1);
+        }
+        VROM_BANK8(~0);
+        SetWriteHandler(0x8000,0xffff,Mapper19_write);
+        SetWriteHandler(0x4020,0x5fff,Mapper19_write);
+        SetReadHandler(0x4800,0x4fff,Namco_Read4800);
+       SetReadHandler(0x5000,0x57ff,Namco_Read5000);
+       SetReadHandler(0x5800,0x5fff,Namco_Read5800);
+
+        MapIRQHook=NamcoIRQHook;
+        MapStateRestore=Mapper19_StateRestore;
+        GameExpSound.RChange=M19SC;
+        if(FSettings.SndRate)
+         Mapper19_ESI();
+        gorfus=0xFF;
+}
+
diff --git a/mappers/21.c b/mappers/21.c
new file mode 100644 (file)
index 0000000..bda50a5
--- /dev/null
@@ -0,0 +1,102 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define K4buf mapbyte2
+#define K4IRQ mapbyte1[1]
+#define K4sel mapbyte1[0]
+
+static int acount=0;
+
+DECLFW(Mapper21_write)
+{
+       A|=((A>>5)&0xF);
+
+       if((A&0xF000)==0xA000)
+         ROM_BANK8(0xA000,V);
+       else if((A&0xF000)==0x8000)
+       {
+         if(K4sel&2)
+          ROM_BANK8(0xC000,V);
+         else
+          ROM_BANK8(0x8000,V);
+       }
+       else if(A>=0xb000 && A<=0xefff)
+       {
+         A&=0xF006;
+          {
+           int x=((A>>2)&1)|((A-0xB000)>>11);
+
+           K4buf[x]&=(0xF0)>>((A&2)<<1);
+           K4buf[x]|=(V&0xF)<<((A&2)<<1);
+           VROM_BANK1(x<<10,K4buf[x]);
+          }
+       }
+       else switch(A&0xF006)
+        {
+        case 0x9000:
+                    switch(V&0x3)
+                    {
+                     case 0:MIRROR_SET(0);break;
+                     case 1:MIRROR_SET(1);break;
+                     case 2:onemir(0);break;
+                     case 3:onemir(1);break;
+                    }
+                    break;
+        case 0x9006:
+        case 0x9004:
+        case 0x9002:if((K4sel&2)!=(V&2))
+                    {
+                     uint8 swa;
+                     swa=PRGBankList[0];
+                     ROM_BANK8(0x8000,PRGBankList[2]);
+                     ROM_BANK8(0xc000,swa);
+                    }
+                    K4sel=V;
+                    break;
+        case 0xf000:IRQLatch&=0xF0;IRQLatch|=V&0xF;break;
+         case 0xf002:IRQLatch&=0x0F;IRQLatch|=V<<4;break;
+        case 0xf004:IRQCount=IRQLatch;
+                    IRQa=V&2;K4IRQ=V&1;break;
+        case 0xf006:IRQa=K4IRQ;break;
+ }
+}
+static void FP_FASTAPASS(1) KonamiIRQHook(int a)
+{
+  #define LCYCS 114
+  if(IRQa)
+   {
+    acount+=a;
+    if(acount>=LCYCS)
+    {
+     doagainbub:acount-=LCYCS;IRQCount++;
+     if(IRQCount&0x100) {TriggerIRQ();IRQCount=IRQLatch;}
+     if(acount>=LCYCS) goto doagainbub;
+    }
+ }
+}
+
+void Mapper21_init(void)
+{
+        SetWriteHandler(0x8000,0xffff,Mapper21_write);
+        MapIRQHook=KonamiIRQHook;
+}
diff --git a/mappers/22.c b/mappers/22.c
new file mode 100644 (file)
index 0000000..44ebe25
--- /dev/null
@@ -0,0 +1,63 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define K4buf mapbyte2
+
+
+
+DECLFW(Mapper22_write)
+{
+        if(A<=0xAFFF)
+         {
+          switch(A&0xF000)
+          {
+          case 0x8000:ROM_BANK8(0x8000,V);break;
+          case 0xa000:ROM_BANK8(0xA000,V);break;
+          case 0x9000:switch(V&3)
+                     {
+                       case 0x00:MIRROR_SET2(1);break;
+                       case 0x01:MIRROR_SET2(0);break;
+                       case 0x02:onemir(0);break;
+                       case 0x03:onemir(1);break;
+                      }
+                      break;
+          }
+         }
+        else
+        {
+         A&=0xF003;
+         if(A>=0xb000 && A<=0xe003)
+         {
+          int x=(A&1)|((A-0xB000)>>11);
+
+          K4buf[x]&=(0xF0)>>((A&2)<<1);
+          K4buf[x]|=(V&0xF)<<((A&2)<<1);
+          VROM_BANK1(x<<10,K4buf[x]>>1);
+         }
+        }
+}
+
+
+void Mapper22_init(void)
+{
+       SetWriteHandler(0x8000,0xffff,Mapper22_write);
+}
diff --git a/mappers/225.c b/mappers/225.c
new file mode 100644 (file)
index 0000000..6edb486
--- /dev/null
@@ -0,0 +1,87 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+#define reg1 mapbyte1[0]
+#define reg2 mapbyte1[1]
+#define reg3 mapbyte1[2]
+#define reg4 mapbyte1[3]
+
+DECLFR(A110in1read)
+{
+switch(A&0x3)
+ {
+  case 0:return reg1;break;
+  case 1:return reg2;break;
+  case 2:return reg3;break;
+  case 3:return reg4;break;
+ }
+return 0xF;
+}
+DECLFW(A110in1regwr)
+{
+switch(A&0x3)
+ {
+  case 0:reg1=V&0xF;break;
+  case 1:reg2=V&0xF;break;
+  case 2:reg3=V&0xF;break;
+  case 3:reg4=V&0xF;break;
+ }
+}
+
+DECLFW(Mapper225_write)
+{
+ int banks=0;
+
+ MIRROR_SET((A>>13)&1);
+ if(A&0x4000)
+  banks=1;
+ else
+  banks=0;
+
+  VROM_BANK8(((A&0x003f)+(banks<<6)));
+ if(A&0x1000)
+  {
+   if(A&0x40)
+    {
+     ROM_BANK16(0x8000,((((((A>>7)&0x1F)+(banks<<5)))<<1)+1));
+     ROM_BANK16(0xC000,((((((A>>7)&0x1F)+(banks<<5)))<<1)+1));
+    }
+    else
+    {
+     ROM_BANK16(0x8000,(((((A>>7)&0x1F)+(banks<<5)))<<1));
+     ROM_BANK16(0xC000,(((((A>>7)&0x1F)+(banks<<5)))<<1));
+    }
+  }
+  else
+  {
+    ROM_BANK32(((((A>>7)&0x1F)+(banks<<5))));
+  }
+}
+
+void Mapper225_init(void)
+{
+  SetWriteHandler(0x8000,0xffff,Mapper225_write);
+  SetReadHandler(0x5800,0x5fff,A110in1read);
+  SetWriteHandler(0x5800,0x5fff,A110in1regwr);
+}
+
diff --git a/mappers/226.c b/mappers/226.c
new file mode 100644 (file)
index 0000000..41fd9a4
--- /dev/null
@@ -0,0 +1,105 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define rg mapbyte1
+static void DoPRG(void)
+{
+  int32 b=((rg[0]>>1)&0xF) | ((rg[0]>>3)&0x10) | ((rg[1]&1)<<5);
+  if(rg[0]&0x20)        // 16 KB
+  {
+   ROM_BANK16(0x8000,(b<<1)|(rg[0]&1));
+   ROM_BANK16(0xC000,(b<<1)|(rg[0]&1));
+  }
+  else
+   ROM_BANK32(b);
+}
+
+static DECLFW(Mapper226_write)
+{
+ rg[A&1]=V;
+ DoPRG();
+ if(A&1)
+ {
+  if(rg[1]&2)
+   PPUCHRRAM=0;  // Write protected.
+  else
+   PPUCHRRAM=0xFF; // Not write protected.
+ }
+ else
+  MIRROR_SET2((rg[0]>>6)&1);
+}
+
+static void M26Reset(void)
+{
+ rg[0]=rg[1]=0;
+ DoPRG();
+ PPUCHRRAM=0xFF;
+ MIRROR_SET2(0);
+}
+
+static void M26Restore(int version)
+{
+ DoPRG();
+ if(rg[1]&2)
+  PPUCHRRAM=0;  // Write protected.
+ else
+  PPUCHRRAM=0xFF; // Not write protected.
+ MIRROR_SET2((rg[0]>>6)&1);
+}
+
+void Mapper226_init(void)
+{
+  SetWriteHandler(0x8000,0xffff,Mapper226_write);
+  MapperReset=M26Reset;
+  GameStateRestore=M26Restore;
+  M26Reset();
+}
+
+#ifdef OLD     // What the heck is this??
+DECLFW(Mapper226_write)
+{
+ MIRROR_SET((A>>13)&1);
+ VROM_BANK8(A&0x7F);
+ if(A&0x1000)
+  {
+   if(A&0x40)
+    {
+     ROM_BANK16(0x8000,(((A>>7))<<1)+1);
+     ROM_BANK16(0xC000,(((A>>7))<<1)+1);
+    }
+    else
+    {
+     ROM_BANK16(0x8000,(((A>>7))<<1));
+     ROM_BANK16(0xC000,(((A>>7))<<1));
+    }
+  }
+  else
+  {
+   ROM_BANK32(A>>7);
+  }
+}
+
+void Mapper226_init(void)
+{
+  SetWriteHandler(0x8000,0xffff,Mapper226_write);
+}
+#endif
diff --git a/mappers/227.c b/mappers/227.c
new file mode 100644 (file)
index 0000000..a006ce3
--- /dev/null
@@ -0,0 +1,79 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define rg mapbyte1
+
+static void DoSync(uint32 A)
+{
+ int32 p=((A>>3)&0xF) | ((A>>4)&0x10);
+
+ rg[0]=A;
+ rg[1]=A>>8;
+
+ MIRROR_SET((A>>1)&1);
+ if(A&1)       //32 KB
+ {
+  ROM_BANK32(p);
+ }
+ else          //16 KB
+ {
+  ROM_BANK16(0x8000,(p<<1)|((A&4)>>2));
+  ROM_BANK16(0xc000,(p<<1)|((A&4)>>2));
+ }
+ if(A&0x80)
+ {
+  PPUCHRRAM=0;
+ }
+ else
+ {
+  PPUCHRRAM=0xFF;
+  if(A&0x200)
+   ROM_BANK16(0xC000,(p<<1)|7);
+  else
+   ROM_BANK16(0xC000,(p<<1)&(~7));
+ }
+}
+
+static DECLFW(Mapper227_write)
+{
+ rg[A&1]=V;
+ DoSync(A);
+}
+
+static void M227Reset(void)
+{
+ rg[0]=rg[1]=0;
+ DoSync(0);
+}
+
+static void M227Restore(int version)
+{
+ DoSync(rg[0]|(rg[1]<<8));
+}
+
+void Mapper227_init(void)
+{
+  SetWriteHandler(0x8000,0xffff,Mapper227_write);
+  MapperReset=M227Reset;
+  GameStateRestore=M227Restore;
+  M227Reset();
+}
diff --git a/mappers/228.c b/mappers/228.c
new file mode 100644 (file)
index 0000000..741bab0
--- /dev/null
@@ -0,0 +1,52 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+static DECLFW(Mapper228_write)
+{
+ uint32 page,pagel,pageh;
+
+ MIRROR_SET((A>>13)&1);
+
+ page=(A>>7)&0x3F;
+ if((page&0x30)==0x30)
+  page-=0x10;
+ pagel=pageh=(page<<1) + (((A>>6)&1)&((A>>5)&1));
+ pageh+=((A>>5)&1)^1;
+
+ ROM_BANK16(0x8000,pagel);
+ ROM_BANK16(0xC000,pageh);
+ VROM_BANK8( (V&0x3) | ((A&0xF)<<2) );
+}
+
+static void A52Reset(void)
+{
+ Mapper228_write(0,0);
+}
+
+void Mapper228_init(void)
+{
+  MapperReset=A52Reset;
+  A52Reset();
+  SetWriteHandler(0x8000,0xffff,Mapper228_write);
+}
+
diff --git a/mappers/229.c b/mappers/229.c
new file mode 100644 (file)
index 0000000..8ffe911
--- /dev/null
@@ -0,0 +1,48 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper229_write)
+{
+if(A>=0x8000)
+{
+MIRROR_SET((A>>5)&1);
+if(!(A&0x1e))
+ {
+ ROM_BANK32(0);
+ }
+else
+ {
+ ROM_BANK16(0x8000,A&0x1f);
+ ROM_BANK16(0xC000,A&0x1f);
+ }
+ VROM_BANK8(A);
+}
+
+}
+
+void Mapper229_init(void)
+{
+  SetWriteHandler(0x8000,0xffff,Mapper229_write);
+}
+
diff --git a/mappers/23.c b/mappers/23.c
new file mode 100644 (file)
index 0000000..12f30d8
--- /dev/null
@@ -0,0 +1,102 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define K4buf mapbyte2
+#define K4IRQ mapbyte1[1]
+#define K4sel mapbyte1[0]
+
+DECLFW(Mapper23_write)
+{
+ if((A&0xF000)==0x8000)
+ {
+  if(K4sel&2)
+   ROM_BANK8(0xC000,V);
+  else
+   ROM_BANK8(0x8000,V);
+  } 
+  else if((A&0xF000)==0xA000) 
+   ROM_BANK8(0xA000,V);
+  else
+  {
+   A|=((A>>2)&0x3)|((A>>4)&0x3)|((A>>6)&0x3);
+   A&=0xF003;
+   if(A>=0xb000 && A<=0xe003)
+   {
+    int x=((A>>1)&1)|((A-0xB000)>>11);
+
+    K4buf[x]&=(0xF0)>>((A&1)<<2);
+    K4buf[x]|=(V&0xF)<<((A&1)<<2);
+    VROM_BANK1(x<<10,K4buf[x]);
+   }
+   else 
+    switch(A)
+    {
+     case 0xf000:X6502_IRQEnd(FCEU_IQEXT);IRQLatch&=0xF0;IRQLatch|=V&0xF;break;
+     case 0xf001:X6502_IRQEnd(FCEU_IQEXT);IRQLatch&=0x0F;IRQLatch|=V<<4;break;
+     case 0xf002:X6502_IRQEnd(FCEU_IQEXT);IRQCount=IRQLatch;IRQa=V&2;K4IRQ=V&1;break;
+     case 0xf003:X6502_IRQEnd(FCEU_IQEXT);IRQa=K4IRQ;break;
+     case 0x9001:
+     case 0x9002:
+     case 0x9003:
+                 if((K4sel&2)!=(V&2))
+                 {
+                  uint8 swa;
+                  swa=PRGBankList[0];
+                  ROM_BANK8(0x8000,PRGBankList[2]);
+                  ROM_BANK8(0xc000,swa);
+                 }
+                 K4sel=V;
+                 break;
+     case 0x9000:
+               switch(V&0x3)
+               {
+                 case 0:MIRROR_SET(0);break;
+                case 1:MIRROR_SET(1);break;
+                case 2:onemir(0);break;
+                case 3:onemir(1);break;
+               }
+               break;
+  }
+ }
+}
+
+void FP_FASTAPASS(1) KonamiIRQHook2(int a)
+{
+  static int acount=0;
+  if(IRQa)
+   {
+    acount+=(a<<1)+a;
+    if(acount>=342)
+    {
+     doagainbub:acount-=342;IRQCount++;
+     if(IRQCount&0x100) {X6502_IRQBegin(FCEU_IQEXT);IRQCount=IRQLatch;}
+     if(acount>=342) goto doagainbub;
+    }
+ }
+}
+
+void Mapper23_init(void)
+{
+        SetWriteHandler(0x8000,0xffff,Mapper23_write);
+        MapIRQHook=KonamiIRQHook2;
+}
+
diff --git a/mappers/232.c b/mappers/232.c
new file mode 100644 (file)
index 0000000..9d71b24
--- /dev/null
@@ -0,0 +1,50 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+static void DoIt(void)
+{
+  ROM_BANK16(0x8000,(mapbyte1[1]&3) | ((mapbyte1[0]&0x18)>>1));
+  ROM_BANK16(0xc000,3|(((mapbyte1[0])&0x18)>>1));
+}
+
+DECLFW(Mapper232_write)
+{
+       if(A<=0x9FFF)
+        mapbyte1[0]=V;
+       else
+        mapbyte1[1]=V;
+       DoIt();
+}
+
+static void QuattroReset(void)
+{
+ mapbyte1[0]=0x18;
+ DoIt();
+}
+
+void Mapper232_init(void)
+{
+ SetWriteHandler(0x6000,0xffff,Mapper232_write);
+ MapperReset=QuattroReset;
+ QuattroReset();
+}
+
diff --git a/mappers/234.c b/mappers/234.c
new file mode 100644 (file)
index 0000000..4a8ac45
--- /dev/null
@@ -0,0 +1,107 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define r1 mapbyte1[0]
+#define r2 mapbyte1[1]
+
+static void DoBS(void)
+{
+ if(r1&0x40)
+ {
+  ROM_BANK32((r1&0xE)|(r2&1));
+  VROM_BANK8( ((r1&0xE)<<2) | ((r2>>4)&7) );
+ }
+ else
+ {
+  ROM_BANK32(r1&0xF);
+  VROM_BANK8( ((r1&0xF)<<2) | ((r2>>4)&3) );
+ }
+}
+
+static void R1Set(uint8 V)
+{
+ if(r1) return;
+ r1=V;
+ MIRROR_SET(V>>7);
+ DoBS();
+}
+
+static void R2Set(uint8 V)
+{
+ r2=V;
+ DoBS();
+}
+
+DECLFW(R1W)
+{
+ R1Set(V);
+}
+
+DECLFR(R1R)
+{
+ uint8 r=CartBR(A);
+ R1Set(r);
+ return r;
+}
+
+DECLFW(R2W)
+{
+ R2Set(V);
+}
+
+DECLFR(R2R)
+{
+ uint8 r=CartBR(A);
+ R2Set(r);
+ return r;
+}
+
+static void M15Restore(int version)
+{
+ DoBS();
+ MIRROR_SET(r1>>7);
+}
+
+static void M15Reset(void)
+{
+ r1=r2=0;
+ DoBS();
+ MIRROR_SET(0);
+}
+
+void Mapper234_init(void)
+{
+        SetWriteHandler(0xff80,0xff9f,R1W);
+       SetReadHandler(0xff80,0xff9f,R1R);
+
+       SetWriteHandler(0xffe8,0xfff7,R2W);
+       SetReadHandler(0xffe8,0xfff7,R2R);
+
+       SetReadHandler(0x6000,0x7FFF,0);
+       SetWriteHandler(0x6000,0x7FFF,0);
+
+       M15Reset();
+               
+       GameStateRestore=M15Restore;
+       MapperReset=M15Reset;
+}
+
diff --git a/mappers/240.c b/mappers/240.c
new file mode 100644 (file)
index 0000000..4c1fd27
--- /dev/null
@@ -0,0 +1,39 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper240_write)
+{
+ if(A<0x8000)
+ {
+  ROM_BANK32(V>>4);
+  VROM_BANK8(V&0xF);
+ }
+}
+
+void Mapper240_init(void)
+{
+  SetWriteHandler(0x4020,0x5fff,Mapper240_write);
+  SetWriteHandler(0x8000,0xffff,Mapper240_write);
+}
+
diff --git a/mappers/242.c b/mappers/242.c
new file mode 100644 (file)
index 0000000..93f654c
--- /dev/null
@@ -0,0 +1,41 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+DECLFW(Mapper242_write)
+{
+  ROM_BANK32((A>>3)&0xF);
+  switch(V&3)
+  {
+   case 0:MIRROR_SET(0);break;
+   case 1:MIRROR_SET(1);break;
+   case 2:onemir(0);break;             
+   case 3:onemir(1);break;
+  }
+}
+
+void Mapper242_init(void)
+{
+  ROM_BANK32(0);
+  SetWriteHandler(0x8000,0xffff,Mapper242_write);
+}
+
diff --git a/mappers/245.c b/mappers/245.c
new file mode 100644 (file)
index 0000000..2a25182
--- /dev/null
@@ -0,0 +1,51 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+static void Synco(void)
+{
+ ROM_BANK8(0x8000,mapbyte2[0]);
+ ROM_BANK8(0xA000,mapbyte2[1]);
+ ROM_BANK8(0xc000,0x3e);
+ ROM_BANK8(0xe000,0x3f);
+}
+static DECLFW(Mapper245_write)
+{
+ switch(A&0xe001)
+ {
+  case 0xa000:mapbyte1[1]=V;Synco();break;
+  case 0x8000:mapbyte1[0]=V;break;
+  case 0x8001:switch(mapbyte1[0]&7)
+               {
+//              default:printf("ark\n");break;
+                case 6:mapbyte2[0]=V;Synco();break;
+                case 7:mapbyte2[1]=V;Synco();break;
+               }break;
+  //case 0xa001:MIRROR_SET2(V>>7);break;
+ }
+// printf("$%04x:$%02x\n",A,V);
+}
+
+void Mapper245_init(void)
+{
+  SetWriteHandler(0x8000,0xffff,Mapper245_write);
+}
+
diff --git a/mappers/246.c b/mappers/246.c
new file mode 100644 (file)
index 0000000..42613fc
--- /dev/null
@@ -0,0 +1,44 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+DECLFW(Mapper246_write)
+{
+ switch(A&0xF007)
+ {
+ case 0x6000:ROM_BANK8(0x8000,V);break;
+ case 0x6001:ROM_BANK8(0xA000,V);break;
+ case 0x6002:ROM_BANK8(0xC000,V);break;
+ case 0x6003:ROM_BANK8(0xE000,V);break;
+ case 0x6004:VROM_BANK2(0x0000,V);break;
+ case 0x6005:VROM_BANK2(0x0800,V);break;
+ case 0x6006:VROM_BANK2(0x1000,V);break;
+ case 0x6007:VROM_BANK2(0x1800,V);break;
+ }
+}
+
+void Mapper246_init(void)
+{
+  SetWriteHandler(0x4020,0x67ff,Mapper246_write);
+  SetWriteHandler(0x8000,0xffff,Mapper246_write);
+}
+
diff --git a/mappers/248.c b/mappers/248.c
new file mode 100644 (file)
index 0000000..af40264
--- /dev/null
@@ -0,0 +1,90 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define cmd mapbyte1[0]
+#define lpa mapbyte1[1]
+#define prgl mapbyte2
+
+static void PRGSynco(void)
+{
+ if(lpa&0x80)
+ {
+  ROM_BANK16(0x8000,lpa&0xF);
+ }
+ else
+ {
+  ROM_BANK8(0x8000,prgl[0]&0x1F);
+  ROM_BANK8(0xa000,prgl[1]&0x1F);
+ }
+}
+
+static DECLFW(Mapper248_writelow)
+{
+ lpa=V;
+ PRGSynco();
+}
+
+static DECLFW(Mapper248_write)
+{
+ switch(A&0xF001)
+ {
+  case 0xa000:MIRROR_SET(V&1);break; // Not sure if this is right.  Mirroring may be hard wired...
+  case 0xc000:IRQLatch=V;break;
+  case 0xc001:IRQCount=IRQLatch;break;
+  case 0xe000:IRQa=0;X6502_IRQEnd(FCEU_IQEXT);break;
+  case 0xe001:IRQa=1;break;
+  case 0x8000:cmd=V;break;
+  case 0x8001:switch(cmd&7)
+             {
+              case 0:VROM_BANK2(0x000,V>>1);break;
+              case 1:VROM_BANK2(0x800,V>>1);break;
+              case 2:VROM_BANK1(0x1000,V);break;
+              case 3:VROM_BANK1(0x1400,V);break;
+              case 4:VROM_BANK1(0x1800,V);break;
+              case 5:VROM_BANK1(0x1c00,V);break;
+              case 6:prgl[0]=V;PRGSynco();break;
+              case 7:prgl[1]=V;PRGSynco();break;
+             }
+             break;
+ }
+}
+
+static void Mapper248_hb(void)
+{
+ if(IRQa)
+ {
+         IRQCount--;
+         if(IRQCount<0)
+         {
+         X6502_IRQBegin(FCEU_IQEXT);
+         IRQCount=IRQLatch;
+         }
+ }
+}
+
+void Mapper248_init(void)
+{
+  SetWriteHandler(0x6000,0x6fff,Mapper248_writelow);
+  SetWriteHandler(0x8000,0xffff,Mapper248_write);
+  GameHBIRQHook=Mapper248_hb;
+}
+
diff --git a/mappers/249.c b/mappers/249.c
new file mode 100644 (file)
index 0000000..6225d49
--- /dev/null
@@ -0,0 +1,46 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+uint8 doh;
+
+static DECLFW(Mapper249_write)
+{
+ switch(A&0xe001)
+ {
+  case 0x8000:doh=V;break;
+  case 0x8001:switch(doh&7)
+               {
+                case 0:VROM_BANK2(0x0000,V>>1);break;
+                case 1:VROM_BANK2(0x0800,V>>1);break;
+                case 2:VROM_BANK1(0x1000,V);break;
+//              case 6:ROM_BANK8(0xa000,V);break;
+//              case 2:ROM_BANK8(0x8000,V);break;
+               }
+ }
+// printf("$%04x:$%02x\n",A,V);
+}
+
+void Mapper249_init(void)
+{
+  SetWriteHandler(0x8000,0xffff,Mapper249_write);
+}
+
diff --git a/mappers/24and26.c b/mappers/24and26.c
new file mode 100644 (file)
index 0000000..575e5e6
--- /dev/null
@@ -0,0 +1,351 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define vrctemp mapbyte1[0]
+#define regb000 mapbyte3[0]
+#define regb001 mapbyte3[1]
+#define regb002 mapbyte3[2]
+#define exchstat mapbyte4[0]
+#define VPSG2 mapbyte3
+#define VPSG mapbyte2
+
+static void DoSQV1(void);
+static void DoSQV2(void);
+static void DoSawV(void);
+
+static int swaparoo;
+static int32 inc;
+static DECLFW(VRC6PSGW90)
+{
+ DoSQV1();VPSG[0]=V;
+}
+static DECLFW(VRC6PSGW91)
+{
+ DoSQV1();VPSG[2]=V;
+}
+static DECLFW(VRC6PSGW92)
+{
+ DoSQV1();VPSG[3]=V;
+}
+static DECLFW(VRC6PSGWA0)
+{
+ DoSQV2();VPSG[4]=V;
+}
+static DECLFW(VRC6PSGWA1)
+{
+ DoSQV2();VPSG[6]=V;
+}
+static DECLFW(VRC6PSGWA2)
+{
+ DoSQV2();VPSG[7]=V;
+}
+static DECLFW(VRC6PSGWB0)
+{
+ DoSawV();VPSG2[0]=V;
+}
+static DECLFW(VRC6PSGWB1)
+{
+ DoSawV();VPSG2[1]=V;
+}
+static DECLFW(VRC6PSGWB2)
+{
+ DoSawV();VPSG2[2]=V;
+}
+
+static int acount=0;
+
+static void FP_FASTAPASS(1) KonamiIRQHook(int a)
+{
+  #define LCYCS 114
+  if(IRQa)
+  {
+   acount+=a;
+   if(acount>=LCYCS)
+   {
+    doagainbub:acount-=LCYCS;IRQCount++;
+    if(IRQCount==0x100) {TriggerIRQ();IRQCount=IRQLatch;}
+    if(acount>=LCYCS) goto doagainbub;
+   }
+ }
+}
+
+DECLFW(Mapper24_write)
+{
+       if(swaparoo)
+        A=(A&0xFFFC)|((A>>1)&1)|((A<<1)&2);
+
+        switch(A&0xF003)
+       {
+         case 0x8000:ROM_BANK16(0x8000,V);break;
+         case 0xB003:
+                switch(V&0xF)
+                {
+                 case 0x0:MIRROR_SET2(1);break;
+                 case 0x4:MIRROR_SET2(0);break;
+                 case 0x8:onemir(0);break;
+                 case 0xC:onemir(1);break;
+                }
+                break;
+         case 0xC000:ROM_BANK8(0xC000,V);break;
+         case 0xD000:VROM_BANK1(0x0000,V);break;
+         case 0xD001:VROM_BANK1(0x0400,V);break;
+         case 0xD002:VROM_BANK1(0x0800,V);break;
+         case 0xD003:VROM_BANK1(0x0c00,V);break;
+         case 0xE000:VROM_BANK1(0x1000,V);break;
+         case 0xE001:VROM_BANK1(0x1400,V);break;
+         case 0xE002:VROM_BANK1(0x1800,V);break;
+         case 0xE003:VROM_BANK1(0x1c00,V);break;
+         case 0xF000:IRQLatch=V;break;
+         case 0xF001:IRQa=V&2;
+                     vrctemp=V&1;
+                     if(V&2) {IRQCount=IRQLatch;}
+                    //acount=0;
+                     break;
+         case 0xf002:IRQa=vrctemp;break;
+         case 0xF003:break;
+  }
+}
+
+static int CVBC[3]={0,0,0};
+static int32 vcount[2];
+
+static void DoSQV1(void)
+{
+    uint8 amp;
+    int32 freq;
+    int V;
+    int32 start,end;
+
+    start=CVBC[0];    
+    end=(timestamp<<16)/soundtsinc;
+    if(end<=start) return;
+    CVBC[0]=end;
+
+    if(VPSG[0x3]&0x80)
+    {
+     amp=(VPSG[0]&15)<<4;
+     if(VPSG[0]&0x80)
+     {
+      for(V=start;V<end;V++)
+       Wave[V>>4]+=amp;
+     }
+     else
+     {
+      unsigned long dcycs;      
+      freq=(((VPSG[0x2]|((VPSG[0x3]&15)<<8))+1));
+      inc=(long double)((unsigned long)((FSettings.SndRate OVERSAMPLE)<<12))/((long double)PSG_base/freq);
+      switch(VPSG[0]&0x70)
+      {
+       default:
+       case 0x00:dcycs=inc>>4;break;
+       case 0x10:dcycs=inc>>3;break;
+       case 0x20:dcycs=(inc*3)>>4;break;
+       case 0x30:dcycs=inc>>2;break;
+       case 0x40:dcycs=(inc*5)>>4;break;
+       case 0x50:dcycs=(inc*6)>>4;break;
+       case 0x60:dcycs=(inc*7)>>4;break;
+       case 0x70:dcycs=inc>>1;break;
+      }
+             for(V=start;V<end;V++)
+              {
+               if(vcount[0]<dcycs)
+                 Wave[V>>4]+=amp;
+               vcount[0]+=0x1000;
+               if(vcount[0]>=inc) vcount[0]-=inc;
+               }
+     }
+    }
+}
+static void DoSQV2(void)
+{
+    uint8 amp;
+    int32 freq;
+    int V;
+    int32 start,end;
+
+    start=CVBC[1];
+    end=(timestamp<<16)/soundtsinc;   
+    if(end<=start) return;
+    CVBC[1]=end;
+
+    if(VPSG[0x7]&0x80)
+    {
+     amp=(VPSG[4]&15)<<4;
+     if(VPSG[4]&0x80)
+     {
+      for(V=start;V<end;V++)
+       Wave[V>>4]+=amp;
+     }
+     else
+     {
+      unsigned long dcycs;
+      freq=(((VPSG[0x6]|((VPSG[0x7]&15)<<8))+1));
+      inc=(long double)((unsigned long)((FSettings.SndRate OVERSAMPLE)<<12))/((long double)PSG_base/freq);
+      switch(VPSG[4]&0x70)
+      {
+       default:
+       case 0x00:dcycs=inc>>4;break;
+       case 0x10:dcycs=inc>>3;break;
+       case 0x20:dcycs=(inc*3)>>4;break;
+       case 0x30:dcycs=inc>>2;break;
+       case 0x40:dcycs=(inc*5)>>4;break;
+       case 0x50:dcycs=(inc*6)>>4;break;
+       case 0x60:dcycs=(inc*7)>>4;break;
+       case 0x70:dcycs=inc>>1;break;
+      }
+             for(V=start;V<end;V++)
+              {
+               if(vcount[1]<dcycs)
+                 Wave[V>>4]+=amp;
+               vcount[1]+=0x1000;
+               if(vcount[1]>=inc) vcount[1]-=inc;
+               }
+     }
+    }
+}
+
+static void DoSawV(void)
+{
+    int V;
+    int32 start,end;
+
+    start=CVBC[2];
+    end=(timestamp<<16)/soundtsinc;   
+    if(end<=start) return;
+    CVBC[2]=end;
+
+   if(VPSG2[2]&0x80)
+   {
+    static int64 saw1phaseacc=0;
+    uint32 freq3;
+    static uint8 b3=0;
+    static int32 phaseacc=0;
+    static uint32 duff=0;
+
+    freq3=(VPSG2[1]+((VPSG2[2]&15)<<8)+1);
+
+    for(V=start;V<end;V++)
+    {
+     saw1phaseacc-=nesincsizeLL;
+     if(saw1phaseacc<=0)
+     {
+      int64 t;
+      rea:
+      t=freq3;
+      t<<=50;  // 49 + 1
+      saw1phaseacc+=t;
+      phaseacc+=VPSG2[0]&0x3f;
+      b3++;
+      if(b3==7)
+      {
+       b3=0;
+       phaseacc=0;
+      }
+      if(saw1phaseacc<=0) 
+       goto rea;
+      duff=(((phaseacc>>3)&0x1f)<<4);
+      }
+     Wave[V>>4]+=duff;
+    }
+   }
+}
+
+void VRC6Sound(int Count)
+{
+    int x;
+
+    DoSQV1();
+    DoSQV2();
+    DoSawV();
+    for(x=0;x<3;x++)
+     CVBC[x]=Count;
+}
+
+static int satype=0;
+
+void VRC6SoundC(void)
+{
+  int x;
+
+  if(FSettings.SndRate)
+   VRC6_ESI(satype);
+  else
+  {
+   for(x=000;x<0x1000;x+=4)
+   {
+          SetWriteHandler(0x9000+x,0x9002+x,0); 
+          SetWriteHandler(0xa000+x,0xa002+x,0); 
+          SetWriteHandler(0xb000+x,0xb002+x,0); 
+   }
+  }
+}
+
+void VRC6_ESI(int t)
+{
+        int x;
+
+       satype=t;
+
+        GameExpSound.RChange=VRC6SoundC;
+        GameExpSound.Fill=VRC6Sound;
+        if(FSettings.SndRate)
+         for(x=000;x<0x1000;x+=4)
+         {
+          uint32 a;
+
+          a=0x9000+x;
+          SetWriteHandler(a,a,VRC6PSGW90);
+          SetWriteHandler(a+(1^t),a+(1^t),VRC6PSGW91);
+          SetWriteHandler(a+(2^t),a+(2^t),VRC6PSGW92);
+
+          a=0xa000+x;
+          SetWriteHandler(a,a,VRC6PSGWA0);
+          SetWriteHandler(a+(1^t),a+(1^t),VRC6PSGWA1);
+          SetWriteHandler(a+(2^t),a+(2^t),VRC6PSGWA2);
+
+          a=0xb000+x;
+          SetWriteHandler(a,a,VRC6PSGWB0);
+          SetWriteHandler(a+(1^t),a+(1^t),VRC6PSGWB1);
+          SetWriteHandler(a+(2^t),a+(2^t),VRC6PSGWB2);
+         }
+}
+
+void Mapper24_init(void)
+{
+        SetWriteHandler(0x8000,0xffff,Mapper24_write);
+        if(FSettings.SndRate)
+         VRC6_ESI(0);
+        GameExpSound.RChange=VRC6SoundC;
+        MapIRQHook=KonamiIRQHook;
+       swaparoo=0;
+}
+
+void Mapper26_init(void)
+{
+        SetWriteHandler(0x8000,0xffff,Mapper24_write);
+       if(FSettings.SndRate)
+         VRC6_ESI(3);
+       GameExpSound.RChange=VRC6SoundC;
+        MapIRQHook=KonamiIRQHook;
+       swaparoo=1;
+}
+
diff --git a/mappers/25.c b/mappers/25.c
new file mode 100644 (file)
index 0000000..db5ba33
--- /dev/null
@@ -0,0 +1,95 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define K4buf mapbyte2
+#define K4IRQ mapbyte1[1]
+#define K4sel mapbyte1[0]
+
+DECLFW(Mapper25_write)
+{
+       A=(A&0xF003)|((A&0xC)>>2);
+
+       if((A&0xF000)==0xA000)
+         ROM_BANK8(0xA000,V);
+       else if(A>=0xB000 && A<=0xEFFF)
+       {
+         int x=(A&1)|((A-0xB000)>>11);
+
+         K4buf[x]&=(0xF0)>>((A&2)<<1);
+         K4buf[x]|=(V&0xF)<<((A&2)<<1);
+         VROM_BANK1(x<<10,K4buf[x]);
+       }
+       else if((A&0xF000)==0x8000)
+       {
+         if(K4sel&2)
+          ROM_BANK8(0xC000,V);
+         else
+          ROM_BANK8(0x8000,V);
+       }
+       else switch(A)
+       {
+        case 0x9000:switch(V&0x3)
+                    {
+                     case 0:MIRROR_SET(0);break;
+                     case 1:MIRROR_SET(1);break;
+                     case 2:onemir(0);break;
+                     case 3:onemir(1);break;
+                    }
+                    break;
+        case 0x9001:if((K4sel&2)!=(V&2))
+                    {
+                     uint8 swa;
+                     swa=PRGBankList[0];
+                     ROM_BANK8(0x8000,PRGBankList[2]);
+                     ROM_BANK8(0xc000,swa);
+                    }
+                    K4sel=V;
+                    break;
+       case 0xf000:IRQLatch&=0xF0;IRQLatch|=V&0xF;break;
+       case 0xf002:IRQLatch&=0x0F;IRQLatch|=V<<4;break;
+       case 0xf001:IRQCount=IRQLatch;IRQa=V&2;K4IRQ=V&1;break;
+       case 0xf003:IRQa=K4IRQ;break;
+ }
+}
+
+static void FP_FASTAPASS(1) KonamiIRQHook(int a)
+{
+  static int count=0;
+  #define LCYCS 114
+  if(IRQa)
+  {
+   count+=a;
+   if(count>=LCYCS)
+   {
+    doagainbub:count-=LCYCS;IRQCount++;
+    if(IRQCount&0x100) {count=0;TriggerIRQ();IRQCount=IRQLatch;}
+    if(count>=LCYCS) goto doagainbub;
+   }
+ }
+}
+
+void Mapper25_init(void)
+{
+        SetWriteHandler(0x8000,0xffff,Mapper25_write);
+        MapIRQHook=KonamiIRQHook;
+}
+
diff --git a/mappers/32.c b/mappers/32.c
new file mode 100644 (file)
index 0000000..da856b9
--- /dev/null
@@ -0,0 +1,54 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+#define IREMCon mapbyte1[0]
+
+static DECLFW(Mapper32_write)
+{
+ switch(A>>12)
+ {
+  case 0x8:
+          mapbyte1[1]=V;
+           if(IREMCon) {ROM_BANK8(0xc000,V);ROM_BANK8(0x8000,~1);}
+           else {ROM_BANK8(0x8000,V);ROM_BANK8(0xc000,~1);}
+           break;
+  case 0x9:MIRROR_SET2(V&1);
+           IREMCon=(V>>1)&1;
+           if(IREMCon) {ROM_BANK8(0xc000,mapbyte1[1]);ROM_BANK8(0x8000,~1);}
+           else {ROM_BANK8(0x8000,mapbyte1[1]); ROM_BANK8(0xc000,~1);}
+           MIRROR_SET(V&1);
+           break;
+  case 0xa:ROM_BANK8(0xA000,V);
+           break;
+ }
+
+ if((A&0xF000)==0xb000)
+  VROM_BANK1((A&0x7)<<10,V);
+}
+
+void Mapper32_init(void)
+{
+  ROM_BANK16(0x8000,0);
+  ROM_BANK16(0xc000,~0);
+  SetWriteHandler(0x8000,0xffff,Mapper32_write);
+}
diff --git a/mappers/33.c b/mappers/33.c
new file mode 100644 (file)
index 0000000..baa2bf9
--- /dev/null
@@ -0,0 +1,63 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+static DECLFW(Mapper33_write)
+{
+        A&=0xF003;
+
+       //printf("$%04x:$%02x, %d\n",A,V,scanline);
+        if(A>=0xA000 && A<=0xA003)
+         VROM_BANK1(0x1000+((A&3)<<10),V);
+        else switch(A){
+        case 0x8000:if(!mapbyte1[0])
+                     MIRROR_SET((V>>6)&1);
+                     ROM_BANK8(0x8000,V);
+                    break;
+        case 0x8001:ROM_BANK8(0xA000,V); break;
+        case 0x8002:VROM_BANK2(0x0000,V);break;
+        case 0x8003:VROM_BANK2(0x0800,V);break;
+       case 0xc000:IRQLatch=V;break;
+       case 0xc001:IRQCount=IRQLatch;break;
+        case 0xc003:IRQa=0;break;
+        case 0xc002:IRQa=1;break;
+        case 0xe000:mapbyte1[0]=1;MIRROR_SET((V>>6)&1);break;
+        }
+}
+
+static void heho(void)
+{
+ if(IRQa)
+ {
+   IRQCount++;
+   if(IRQCount==0x100) 
+   {
+    TriggerIRQ();
+    IRQa=0;
+   }
+ }
+}
+
+void Mapper33_init(void)
+{
+       SetWriteHandler(0x8000,0xffff,Mapper33_write);
+       GameHBIRQHook=heho;
+}
diff --git a/mappers/40.c b/mappers/40.c
new file mode 100644 (file)
index 0000000..30f9459
--- /dev/null
@@ -0,0 +1,58 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+static DECLFW(Mapper40_write)
+{
+ switch(A&0xe000)
+ {
+  case 0x8000:IRQa=0;IRQCount=0;break;
+  case 0xa000:IRQa=1;break;
+  case 0xe000:ROM_BANK8(0xc000,V&7);break;
+ }
+}
+
+static void FP_FASTAPASS(1) Mapper40IRQ(int a)
+{
+ if(IRQa)
+ {
+        if(IRQCount<4096) 
+        IRQCount+=a;
+       else
+        {
+         IRQa=0;
+         TriggerIRQ();
+        }
+ }
+}
+
+void Mapper40_init(void)
+{
+  ROM_BANK8(0x6000,(~0)-1);
+  ROM_BANK8(0x8000,(~0)-3);
+  ROM_BANK8(0xa000,(~0)-2);
+  SetWriteHandler(0x8000,0xffff,Mapper40_write);
+  SetReadHandler(0x6000,0x7fff,CartBR);
+  MapIRQHook=Mapper40IRQ;
+}
+
+
diff --git a/mappers/41.c b/mappers/41.c
new file mode 100644 (file)
index 0000000..1139db9
--- /dev/null
@@ -0,0 +1,51 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+#define calreg mapbyte1[0]
+#define calchr mapbyte1[1]
+
+DECLFW(Mapper41_write)
+{
+ if(A<0x8000)
+ {
+ ROM_BANK32(A&7);
+ MIRROR_SET((A>>5)&1);
+ calreg=A;
+ calchr&=0x3;
+ calchr|=(A>>1)&0xC;
+ VROM_BANK8(calchr);
+ }
+ else if(calreg&0x4)
+ {
+ calchr&=0xC;
+ calchr|=A&3;
+ VROM_BANK8(calchr);
+ }
+}
+
+void Mapper41_init(void)
+{
+ ROM_BANK32(0);
+ SetWriteHandler(0x8000,0xffff,Mapper41_write);
+ SetWriteHandler(0x6000,0x67ff,Mapper41_write);
+}
diff --git a/mappers/42.c b/mappers/42.c
new file mode 100644 (file)
index 0000000..2700227
--- /dev/null
@@ -0,0 +1,63 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+static DECLFW(Mapper42_write)
+{
+ switch(A&0xe003)
+ {
+  case 0xe000:mapbyte1[0]=V;ROM_BANK8(0x6000,V&0xF);break;
+  case 0xe001:MIRROR_SET((V>>3)&1);break;
+  case 0xe002:IRQa=V&2;if(!IRQa) IRQCount=0;break;
+ }
+}
+
+static void FP_FASTAPASS(1) Mapper42IRQ(int a)
+{
+ if(IRQa)
+ {
+        if(IRQCount<24576)
+         IRQCount+=a;
+        else
+        {
+         IRQa=0;
+         TriggerIRQ();
+        }
+ }
+}
+
+static void Mapper42_StateRestore(int version)
+{
+    ROM_BANK8(0x6000,mapbyte1[0]&0xF);
+}
+
+
+void Mapper42_init(void)
+{
+  ROM_BANK8(0x6000,0);
+  ROM_BANK32(~0);
+  SetWriteHandler(0xe000,0xffff,Mapper42_write);
+  SetReadHandler(0x6000,0x7fff,CartBR);
+  MapStateRestore=Mapper42_StateRestore;
+  MapIRQHook=Mapper42IRQ;
+}
+
diff --git a/mappers/43.c b/mappers/43.c
new file mode 100644 (file)
index 0000000..2e5f427
--- /dev/null
@@ -0,0 +1,63 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper43_write)
+{
+  uint32 m;
+  int z;
+
+  if(A&0x400)
+   onemir(0);
+  else
+   MIRROR_SET((A>>13)&1);
+  m=A&0x1f;
+
+  z=(A>>8)&3;
+
+  switch(CHRmask8[0])
+  {
+   default:
+   case 0xFF:
+             if(z&2)
+              m|=0x20;
+             break;
+   case 0x1FF:
+             m|=z<<5;
+             break;
+  }
+
+   if(A&0x800)
+   {
+    ROM_BANK16(0x8000,(m<<1)|((A&0x1000)>>12));
+    ROM_BANK16(0xC000,(m<<1)|((A&0x1000)>>12));
+   }
+   else
+    ROM_BANK32(m);
+}
+
+void Mapper43_init(void)
+{
+ ROM_BANK32(0);
+ SetWriteHandler(0x8000,0xffff,Mapper43_write);
+}
diff --git a/mappers/46.c b/mappers/46.c
new file mode 100644 (file)
index 0000000..4157f2b
--- /dev/null
@@ -0,0 +1,48 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+
+#define A64reg  mapbyte1[0]
+#define A64wr   mapbyte1[1]
+
+DECLFW(Mapper46_writel)
+{
+  A64reg=V;
+  ROM_BANK32((A64wr&1)+((A64reg&0xF)<<1));
+  VROM_BANK8(((A64wr>>4)&7)+((A64reg&0xF0)>>1));
+}
+
+DECLFW(Mapper46_write)
+{
+  A64wr=V;
+  ROM_BANK32((V&1)+((A64reg&0xF)<<1));
+  VROM_BANK8(((V>>4)&7)+((A64reg&0xF0)>>1));
+}
+
+void Mapper46_init(void)
+{
+ MIRROR_SET(0);
+ ROM_BANK32(0);
+ SetWriteHandler(0x8000,0xffff,Mapper46_write);
+ SetWriteHandler(0x6000,0x7fff,Mapper46_writel);
+}
diff --git a/mappers/51.c b/mappers/51.c
new file mode 100644 (file)
index 0000000..c6a33f3
--- /dev/null
@@ -0,0 +1,66 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define mode mapbyte1[0]
+#define page mapbyte1[1]
+
+static uint32 Get8K(uint32 A)
+{
+ uint32 bank;
+ bank=(page<<2)|((A>>13)&1);
+
+ if(A&0x4000 && !(mode&1)) bank|=0xC;
+ if(!(A&0x8000)) bank|=0x20;
+ if(mode==2) bank|=2;
+ else bank|=(A>>13)&2;
+ return(bank);
+}
+
+static void Synco(void)
+{
+ uint32 x;
+ if(mapbyte1[0]<=2)
+  MIRROR_SET2(1);
+ else
+  MIRROR_SET2(0);
+ for(x=0x6000;x<0x10000;x+=8192)
+  ROM_BANK8(x,Get8K(x));
+}
+
+static DECLFW(Write)
+{
+ if(A&0x8000) mapbyte1[1]=V&0xF;
+ else mapbyte1[0]=(mapbyte1[0]&2)|((V>>1)&1);
+
+ if(A&0x4000) mapbyte1[0]=(mapbyte1[0]&1)|((V>>3)&2);
+ Synco();
+}
+
+void Mapper51_init(void)
+{
+ SetWriteHandler(0x6000,0xFFFF,Write);
+ SetReadHandler(0x6000,0xFFFF,CartBR);
+ mapbyte1[0]=1;
+ mapbyte1[1]=0;
+ Synco();
+}
diff --git a/mappers/6.c b/mappers/6.c
new file mode 100644 (file)
index 0000000..015aa9c
--- /dev/null
@@ -0,0 +1,76 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+#define FVRAM_BANK8(A,V) {VPage[0]=VPage[1]=VPage[2]=VPage[3]=VPage[4]=VPage[5]=VPage[6]=VPage[7]=V?&MapperExRAM[(V)<<13]-(A):&CHRRAM[(V)<<13]-(A);CHRBankList[0]=((V)<<3);CHRBankList[1]=((V)<<3)+1;CHRBankList[2]=((V)<<3)+2;CHRBankList[3]=((V)<<3)+3;CHRBankList[4]=((V)<<3)+4;CHRBankList[5]=((V)<<3)+5;CHRBankList[6]=((V)<<3)+6;CHRBankList[7]=((V)<<3)+7;PPUCHRRAM=0xFF;}
+
+static void FP_FASTAPASS(1) FFEIRQHook(int a)
+{
+  if(IRQa)
+  {
+   IRQCount+=a;
+   if(IRQCount>=0x10000)
+   {
+    TriggerIRQ();
+    IRQa=0;
+    IRQCount=0;
+   }
+  }
+}
+
+DECLFW(Mapper6_write)
+{
+        if(A<0x8000)
+        {
+                switch(A){
+                case 0x42FF:MIRROR_SET((V>>4)&1);break;
+                case 0x42FE:onemir((V>>3)&2);break;
+                case 0x4501:IRQa=0;break;
+                case 0x4502:IRQCount&=0xFF00;IRQCount|=V;break;
+                case 0x4503:IRQCount&=0xFF;IRQCount|=V<<8;IRQa=1;break;
+                }
+        } else {
+        ROM_BANK16(0x8000,V>>2);
+        FVRAM_BANK8(0x0000,V&3);
+        }
+}
+void Mapper6_StateRestore(int version)
+{
+ int x;
+ for(x=0;x<8;x++)
+  if(PPUCHRRAM&(1<<x))
+  {
+   if(CHRBankList[x]>7)
+    VPage[x]=&MapperExRAM[(CHRBankList[x]&31)*0x400]-(x*0x400);
+   else VPage[x]=&CHRRAM[(CHRBankList[x]&7)*0x400]-(x*0x400);
+  }
+}
+void Mapper6_init(void)
+{
+MapIRQHook=FFEIRQHook;
+ROM_BANK16(0xc000,7);
+
+SetWriteHandler(0x4020,0x5fff,Mapper6_write);
+SetWriteHandler(0x8000,0xffff,Mapper6_write);
+MapStateRestore=Mapper6_StateRestore;
+}
+
diff --git a/mappers/64.c b/mappers/64.c
new file mode 100644 (file)
index 0000000..96dbac2
--- /dev/null
@@ -0,0 +1,150 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define cmd   mapbyte1[0]
+#define mir   mapbyte1[1]
+#define rmode mapbyte1[2]
+#define regsl mapbyte2
+#define regsh mapbyte3
+
+static void RAMBO1_hb(void)
+{
+      rmode=0;
+      if(IRQCount>=0)
+      {
+        IRQCount--;
+        if(IRQCount<0)
+        {
+         if(IRQa)
+         {
+//         printf("IRQ: %d\n",scanline);
+            rmode = 1;
+            X6502_IRQBegin(FCEU_IQEXT);
+         }
+        }
+      }
+}
+
+static void Synco(void)
+{
+ int x;
+
+ if(cmd&0x20)
+ {
+  setchr1(0x0000,regsl[0]);
+  setchr1(0x0800,regsl[1]);
+  setchr1(0x0400,regsh[0]);
+  setchr1(0x0c00,regsh[1]);
+ }
+ else
+ {
+  setchr2(0x0000,regsl[0]>>1);
+  setchr2(0x0800,regsl[1]>>1);
+ }
+
+ for(x=0;x<4;x++)
+  setchr1(0x1000+x*0x400,regsl[2+x]);
+
+ setprg8(0x8000,regsl[6]);
+ setprg8(0xA000,regsl[7]);
+
+ setprg8(0xC000,regsh[7]);
+}
+
+
+static DECLFW(RAMBO1_write)
+{
+ //if(A>=0xC000 && A<=0xFFFF) printf("$%04x:$%02x, %d, %d\n",A,V,scanline,timestamp);
+ switch(A&0xF001)
+ {
+        case 0xa000:mir=V&1;
+                   setmirror(mir^1);
+                   break;
+        case 0x8000:cmd = V;
+                   break;
+        case 0x8001:
+                   if((cmd&15)<8)
+                    regsl[cmd&7]=V;
+                   else
+                    regsh[cmd&7]=V;
+                   Synco();
+                   break;
+        case 0xc000:IRQLatch=V;
+                    if(rmode==1)
+                     {
+                      IRQCount=IRQLatch;
+                     }
+                    break;
+        case 0xc001:rmode=1;
+                    IRQCount=IRQLatch;
+                    break;
+        case 0xE000:IRQa=0;X6502_IRQEnd(FCEU_IQEXT);
+                    if(rmode==1)
+                     {IRQCount=IRQLatch;}
+                    break;
+        case 0xE001:IRQa=1;
+                    if(rmode==1)
+                     {IRQCount=IRQLatch;}
+                    break;
+  }    
+}
+
+static void RAMBO1_Restore(int version)
+{
+ if(version<74)
+ {
+  int x;
+
+  x=mapbyte1[1];        // was MMC3_cmd
+  cmd=x;
+
+  regsl[0]=CHRBankList[0];
+  regsl[1]=CHRBankList[2];
+  regsh[0]=CHRBankList[1];
+  regsh[1]=CHRBankList[3];
+
+  for(x=0;x<4;x++)
+   regsl[2+x]=CHRBankList[4+x];
+
+  regsl[6]=PRGBankList[0];
+  regsl[7]=PRGBankList[1];
+  regsh[7]=PRGBankList[2];
+  mir=Mirroring^1;
+ }
+ Synco();
+ setmirror(mir^1);
+}
+
+void Mapper64_init(void)
+{
+       int x;
+
+       for(x=0;x<8;x++)
+        regsl[x]=regsh[x]=~0;
+       cmd=0;
+       mir=0;
+       setmirror(1);
+       Synco();
+       GameHBIRQHook=RAMBO1_hb;
+       GameStateRestore=RAMBO1_Restore;
+       SetWriteHandler(0x8000,0xffff,RAMBO1_write);
+}
diff --git a/mappers/65.c b/mappers/65.c
new file mode 100644 (file)
index 0000000..b4051e8
--- /dev/null
@@ -0,0 +1,68 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+void FP_FASTAPASS(1) IREMIRQHook(int a)
+{
+  if(IRQa)
+  {
+   IRQCount-=a;
+   if(IRQCount<=0-4)
+   {
+    TriggerIRQ();
+    IRQa=0;
+    IRQCount=0xFFFF;
+   }
+  }
+}
+
+DECLFW(Mapper65_write)
+{
+switch(A)
+{
+case 0x8000:ROM_BANK8(0x8000,V);break;
+case 0x9000:MIRROR_SET2((V>>6)&1);break;
+case 0x9003:IRQa=V&0x80;break;
+case 0x9004:IRQCount=IRQLatch;break;
+case 0x9005:          IRQLatch&=0x00FF;
+                      IRQLatch|=V<<8;
+                      break;
+case 0x9006:          IRQLatch&=0xFF00;IRQLatch|=V;
+                      break;
+case 0xB000:VROM_BANK1(0x0000,V);break;
+case 0xB001:VROM_BANK1(0x0400,V);break;
+case 0xB002:VROM_BANK1(0x0800,V);break;
+case 0xB003:VROM_BANK1(0x0C00,V);break;
+case 0xB004:VROM_BANK1(0x1000,V);break;
+case 0xB005:VROM_BANK1(0x1400,V);break;
+case 0xB006:VROM_BANK1(0x1800,V);break;
+case 0xB007:VROM_BANK1(0x1C00,V);break;
+case 0xa000:ROM_BANK8(0xA000,V);break;
+case 0xC000:ROM_BANK8(0xC000,V);break;
+ }
+}
+
+void Mapper65_init(void)
+{
+ MapIRQHook=IREMIRQHook;
+ SetWriteHandler(0x8000,0xffff,Mapper65_write);
+}
diff --git a/mappers/67.c b/mappers/67.c
new file mode 100644 (file)
index 0000000..96c695b
--- /dev/null
@@ -0,0 +1,67 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+#define suntoggle mapbyte1[0]
+
+DECLFW(Mapper67_write)
+{
+ A&=0xF800;
+ if((A&0x800) && A<=0xb800)
+ {
+  VROM_BANK2((A-0x8800)>>1,V);
+ }
+ else switch(A)
+ {
+  case 0xc800:
+  case 0xc000:if(!suntoggle)
+              {IRQCount&=0xFF;IRQCount|=V<<8;}
+              else{IRQCount&=0xFF00;IRQCount|=V;}
+              suntoggle^=1;
+              break;
+  case 0xd800:suntoggle=0;IRQa=V&0x10;break;
+
+  case 0xe800:switch(V&3)
+              {
+               case 0:MIRROR_SET2(1);break;
+               case 1:MIRROR_SET2(0);break;
+               case 2:onemir(0);break;
+               case 3:onemir(1);break;
+              }
+              break;
+  case 0xf800:ROM_BANK16(0x8000,V);break;
+ }
+}
+static void FP_FASTAPASS(1) SunIRQHook(int a)
+{
+  if(IRQa)
+  {
+   IRQCount-=a;
+   if(IRQCount<=0)
+   {TriggerIRQ();IRQa=0;IRQCount=0xFFFF;}
+  }
+}
+void Mapper67_init(void)
+{
+SetWriteHandler(0x8000,0xffff,Mapper67_write);
+MapIRQHook=SunIRQHook;
+}
diff --git a/mappers/68.c b/mappers/68.c
new file mode 100644 (file)
index 0000000..98cb0d8
--- /dev/null
@@ -0,0 +1,104 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+static void Fixerit(void)
+{
+ switch(mapbyte2[0]&3)
+ {
+  case 0:vnapage[0]=vnapage[2]=VROM+(((mapbyte1[0]|128)&CHRmask1[0])<<10);
+        vnapage[1]=vnapage[3]=VROM+(((mapbyte1[1]|128)&CHRmask1[0])<<10);
+        break;
+  case 1:vnapage[0]=vnapage[1]=VROM+(((mapbyte1[0]|128)&CHRmask1[0])<<10);
+         vnapage[2]=vnapage[3]=VROM+(((mapbyte1[1]|128)&CHRmask1[0])<<10);
+         break;
+  case 2:vnapage[0]=vnapage[1]=vnapage[2]=vnapage[3]=VROM+(((mapbyte1[0]|128)&CHRmask1[0])<<10);
+        break;
+  case 3:vnapage[0]=vnapage[1]=vnapage[2]=vnapage[3]=VROM+(((mapbyte1[1]|128)&CHRmask1[0])<<10);
+        break;
+ }
+}
+
+DECLFW(Mapper68_write)
+{
+ A&=0xF000;
+
+ if(A>=0x8000 && A<=0xB000)
+ {
+  VROM_BANK2((A-0x8000)>>1,V);
+ }
+ else switch(A)
+ {
+  case 0xc000:mapbyte1[0]=V;
+              if(VROM_size && mapbyte2[0]&0x10)
+              Fixerit();
+              break;
+
+  case 0xd000:mapbyte1[1]=V;
+             if(VROM_size && mapbyte2[0]&0x10)
+              Fixerit();
+              break;
+
+  case 0xe000: mapbyte2[0]=V;
+               if(!(V&0x10))
+               {
+                switch(V&3)
+                {
+                 case 0:MIRROR_SET2(1);break;
+                 case 1:MIRROR_SET2(0);break;
+                 case 2:onemir(0);break;
+                 case 3:onemir(1);break;
+                }
+               }
+               else if(VROM_size)
+              {
+               Fixerit();
+               PPUNTARAM=0;
+              }
+               break;
+  case 0xf000: ROM_BANK16(0x8000,V);break;
+ }
+}
+
+static void Mapper68_StateRestore(int version)
+{
+              if(!(mapbyte2[0]&0x10))
+              {
+               switch(mapbyte2[0]&3)
+               {
+                case 0:MIRROR_SET(0);break;
+                case 1:MIRROR_SET(1);break;
+                case 2:onemir(0);break;
+                case 3:onemir(1);break;
+               }
+              }
+              else if(VROM_size)
+              {
+               Fixerit();
+                PPUNTARAM=0;
+              }
+}
+
+void Mapper68_init(void)
+{
+ SetWriteHandler(0x8000,0xffff,Mapper68_write);
+ MapStateRestore=Mapper68_StateRestore;
+}
diff --git a/mappers/69.c b/mappers/69.c
new file mode 100644 (file)
index 0000000..ec6336f
--- /dev/null
@@ -0,0 +1,268 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+static void AYSound(int Count);
+static void DoAYSQ(int x);
+static void DoAYNoise(void);
+
+#define sunselect mapbyte1[0]
+#define sungah    mapbyte1[1]
+#define sunindex  mapbyte1[2]
+
+static uint16 znreg;
+static int32 inc;
+
+DECLFW(SUN5BWRAM)
+{
+ if((sungah&0xC0)==0xC0)
+  (WRAM-0x6000)[A]=V;
+}
+
+DECLFR(SUN5AWRAM)
+{
+ if((sungah&0xC0)==0x40)
+  return X.DB; 
+ return CartBR(A);
+}
+
+DECLFW(Mapper69_SWL)
+{
+  sunindex=V%14;
+}
+DECLFW(Mapper69_SWH)
+{
+             GameExpSound.Fill=AYSound;
+             switch(sunindex)
+             {
+              case 0:
+              case 1:
+              case 8:DoAYSQ(0);break;
+              case 2:
+              case 3:
+              case 9:DoAYSQ(1);break;
+              case 4:
+              case 5:
+              case 10:DoAYSQ(2);break;
+              case 6:DoAYNoise();znreg=0xFFFF;break;
+              case 7:DoAYNoise();
+                     DoAYSQ(0);
+                     DoAYSQ(1);
+                     DoAYSQ(2);break;
+             }
+             MapperExRAM[sunindex]=V; 
+}
+
+DECLFW(Mapper69_write)
+{
+ switch(A&0xE000)
+ {
+  case 0x8000:sunselect=V;break;
+  case 0xa000:
+              sunselect&=0xF;
+              if(sunselect<=7)
+               VROM_BANK1(sunselect<<10,V);
+              else
+               switch(sunselect&0x0f)
+               {
+                case 8:
+                       sungah=V;
+                       if(V&0x40)
+                        {
+                         if(V&0x80) // Select WRAM
+                          setprg8r(0x10,0x6000,0);
+                        }
+                        else
+                         setprg8(0x6000,V);
+                        break;
+                case 9:ROM_BANK8(0x8000,V);break;
+                case 0xa:ROM_BANK8(0xa000,V);break;
+                case 0xb:ROM_BANK8(0xc000,V);break;
+                case 0xc:
+                         switch(V&3)
+                         {
+                          case 0:MIRROR_SET2(1);break;
+                          case 1:MIRROR_SET2(0);break;
+                          case 2:onemir(0);break;
+                          case 3:onemir(1);break;
+                         }
+                         break;
+             case 0xd:IRQa=V;break;
+             case 0xe:IRQCount&=0xFF00;IRQCount|=V;break;
+             case 0xf:IRQCount&=0x00FF;IRQCount|=V<<8;break;
+             }
+             break;
+ }
+}
+
+static int32 vcount[4];
+static int CAYBC[4]={0,0,0,0};
+static void DoAYSQ(int x)
+{
+    int V;
+    uint32 freq;
+    unsigned char amp;
+    int32 start,end;
+
+    start=CAYBC[x];    
+    end=(timestamp<<16)/soundtsinc;
+    if(end<=start) return;
+    CAYBC[x]=end;
+
+    if(!(MapperExRAM[0x7]&(1<<x)))
+    {
+      long vcoo;
+      freq=(MapperExRAM[x<<1]|((MapperExRAM[(x<<1)+1]&15)<<8))+1;
+      inc=(long double)((unsigned long)((FSettings.SndRate OVERSAMPLE)<<12))/
+        ((long double)PSG_base/freq);
+                            amp=MapperExRAM[0x8+x]&15;
+              amp<<=3;
+              vcoo=vcount[x];
+             if(amp)
+              for(V=start;V<end;V++)
+               {
+                if(vcoo<(inc>>1))
+                  Wave[V>>4]+=amp;
+                vcoo+=0x1000;
+                if(vcoo>=inc) vcoo-=inc;
+                }
+              vcount[x]=vcoo;
+     }
+}
+static void DoAYNoise(void)
+{
+    int V;
+    uint32 freq;
+    unsigned char amp;
+    int32 start,end;
+
+    start=CAYBC[3];    
+    end=(timestamp<<16)/soundtsinc;
+    if(end<=start) return;
+    CAYBC[3]=end;
+
+        amp=0;
+        for(V=0;V<3;V++)
+         {
+          if(!(MapperExRAM[0x7]&(8<<V)))
+          {
+          //if(MapperExRAM[0x8+V]&0x10) amp+=MapperExRAM[0x20]&15;
+                                //else
+                                amp+=MapperExRAM[0x8+V]&15;
+          }
+         }
+     amp<<=3;
+
+     if(amp)
+       {
+        freq=PSG_base/(MapperExRAM[0x6]+1);
+        if(freq>44100)
+         inc=((freq<<11)/(FSettings.SndRate OVERSAMPLE))<<4;
+        else
+         inc=(freq<<15)/(FSettings.SndRate OVERSAMPLE);
+
+         for(V=start;V<end;V++)
+          {
+             static uint32 mixer;
+
+             if(vcount[3]>=32768)
+             {
+               unsigned char feedback;
+               mixer=0;
+               if(znreg&1) mixer+=amp;
+               feedback=((znreg>>13)&1)^((znreg>>14)&1);
+               znreg=(znreg<<1)+(feedback);
+               vcount[3]-=32768;
+             }
+             Wave[V>>4]+=mixer;
+             vcount[3]+=inc;
+           }
+       }
+
+
+}
+static void AYSound(int Count)
+{
+    int x;
+    DoAYSQ(0);
+    DoAYSQ(1);
+    DoAYSQ(2);
+    DoAYNoise();
+    for(x=0;x<4;x++)
+     CAYBC[x]=Count;
+}
+
+static void FP_FASTAPASS(1) SunIRQHook(int a)
+{
+  if(IRQa)
+  {
+   IRQCount-=a;
+   if(IRQCount<=0)
+   {TriggerIRQ();IRQa=0;IRQCount=0xFFFF;}
+  }
+}
+
+void Mapper69_StateRestore(int version)
+{
+   if(version>=19)
+   {
+    if(mapbyte1[1]&0x40)
+    {
+     if(mapbyte1[1]&0x80) // Select WRAM
+      setprg8r(0x10,0x6000,0);
+    }
+    else
+     setprg8(0x6000,mapbyte1[1]);
+   }
+   else
+    mapbyte1[1]=0xC0;
+}
+
+static void M69SC(void)
+{
+ if(FSettings.SndRate)
+  Mapper69_ESI();
+ else 
+  SetWriteHandler(0xc000,0xffff,(writefunc)0);
+}
+
+void Mapper69_ESI(void)
+{
+ GameExpSound.RChange=M69SC; 
+ if(FSettings.SndRate)
+ {
+  SetWriteHandler(0xc000,0xdfff,Mapper69_SWL);
+  SetWriteHandler(0xe000,0xffff,Mapper69_SWH);
+ }
+}
+
+void Mapper69_init(void)
+{
+ SetupCartPRGMapping(0x10,WRAM,8192,1);
+
+ SetWriteHandler(0x8000,0xbfff,Mapper69_write);
+ SetWriteHandler(0x6000,0x7fff,SUN5BWRAM);
+ SetReadHandler(0x6000,0x7fff,SUN5AWRAM);
+ Mapper69_ESI();
+ MapIRQHook=SunIRQHook;
+ MapStateRestore=Mapper69_StateRestore;
+ znreg=0;
+}
+
diff --git a/mappers/71.c b/mappers/71.c
new file mode 100644 (file)
index 0000000..7643978
--- /dev/null
@@ -0,0 +1,41 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper71_write)
+{
+switch(A&0xF000)
+ {
+ case 0xF000:
+ case 0xE000:
+ case 0xD000:
+ case 0xC000:ROM_BANK16(0x8000,V);break;
+ case 0x9000:onemir((V>>3)&2);break;
+ }
+}
+
+void Mapper71_init(void)
+{
+SetWriteHandler(0x4020,0xffff,Mapper71_write);
+}
+
diff --git a/mappers/72.c b/mappers/72.c
new file mode 100644 (file)
index 0000000..dcc5828
--- /dev/null
@@ -0,0 +1,37 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+DECLFW(Mapper72_write)
+{
+ mapbyte1[0]=V;
+ if(V&0x80)
+  ROM_BANK16(0x8000,V&0xF);
+ if(V&0x40)
+  VROM_BANK8(V&0xF);
+}
+
+void Mapper72_init(void)
+{
+ SetWriteHandler(0x6000,0xffff,Mapper72_write);
+}
+
diff --git a/mappers/73.c b/mappers/73.c
new file mode 100644 (file)
index 0000000..ca230f8
--- /dev/null
@@ -0,0 +1,57 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper73_write)
+{
+switch(A&0xF000)
+ {
+ case 0x8000:IRQCount&=0xFFF0;IRQCount|=(V&0xF);break;
+ case 0x9000:IRQCount&=0xFF0F;IRQCount|=(V&0xF)<<4;break;
+ case 0xa000:IRQCount&=0xF0FF;IRQCount|=(V&0xF)<<8;break;
+ case 0xb000:IRQCount&=0x0FFF;IRQCount|=(V&0xF)<<12;break;
+ case 0xc000:IRQa=V&2;break;
+ case 0xf000:ROM_BANK16(0x8000,V);break;
+ }
+}
+
+static void FP_FASTAPASS(1) Mapper73IRQHook(int a)
+{
+ if(IRQa)
+ {
+  IRQCount+=a;
+  if(IRQCount>=0xFFFF)
+  {
+   IRQCount&=0xFFFF;
+   IRQa=0;
+   TriggerIRQ();
+  }
+ }
+}
+
+void Mapper73_init(void)
+{
+ SetWriteHandler(0x8000,0xffff,Mapper73_write);
+ MapIRQHook=Mapper73IRQHook;
+}
+
diff --git a/mappers/75.c b/mappers/75.c
new file mode 100644 (file)
index 0000000..0bd2711
--- /dev/null
@@ -0,0 +1,47 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+#define map75sel mapbyte1[0]
+#define map75ar  mapbyte2
+
+DECLFW(Mapper75_write)
+{
+switch(A&0xF000)
+ {
+ case 0x8000:ROM_BANK8(0x8000,V);break;
+ case 0x9000:
+             VROM_BANK4(0x0000,map75ar[0]|((V&2)<<3));
+             VROM_BANK4(0x1000,map75ar[1]|((V&4)<<2));
+             map75sel=V;MIRROR_SET(V&1);break;
+ case 0xa000:ROM_BANK8(0xa000,V);break;
+ case 0xc000:ROM_BANK8(0xc000,V);break;
+ case 0xe000:V&=0xF;map75ar[0]=V;V|=(map75sel&2)<<3;VROM_BANK4(0x0000,V);break;
+ case 0xf000:V&=0xF;map75ar[1]=V;V|=(map75sel&4)<<2;VROM_BANK4(0x1000,V);break;
+ }
+}
+
+void Mapper75_init(void)
+{
+SetWriteHandler(0x8000,0xffff,Mapper75_write);
+}
+
diff --git a/mappers/76.c b/mappers/76.c
new file mode 100644 (file)
index 0000000..d901bb7
--- /dev/null
@@ -0,0 +1,55 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper76_write)
+{
+        switch(A&0xE001){
+        case 0x8000:
+         MMC3_cmd = V;
+         break;
+        case 0x8001:
+                switch(MMC3_cmd&0x07){
+                case 2: VROM_BANK2(0x000,V);break;
+                case 3: VROM_BANK2(0x800,V);break;
+                case 4: VROM_BANK2(0x1000,V);break;
+                case 5: VROM_BANK2(0x1800,V);break;
+                case 6:
+                        if (MMC3_cmd&0x40) ROM_BANK8(0xC000,V);
+                        else ROM_BANK8(0x8000,V);
+                        break;
+                case 7: ROM_BANK8(0xA000,V);
+                        break;
+               }
+               break;
+        case 0xA000:
+        MIRROR_SET(V&1);
+        break;
+ }
+}
+
+void Mapper76_init(void)
+{
+SetWriteHandler(0x8000,0xffff,Mapper76_write);
+}
+
diff --git a/mappers/77.c b/mappers/77.c
new file mode 100644 (file)
index 0000000..e9d0015
--- /dev/null
@@ -0,0 +1,54 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+/* Original code provided by LULU */
+
+static DECLFW(Mapper77_write)
+{
+ mapbyte1[0]=V;
+ ROM_BANK32(V&0x7);
+ VROM_BANK2(0x0000, (V&0xf0)>>4);
+}
+
+static void Mapper77_StateRestore(int version)
+{
+ int x;
+ if(version>=72)
+ {
+  ROM_BANK32(mapbyte1[0]&0x7);
+  VROM_BANK2(0x0000, (mapbyte1[0]&0xf0)>>4);
+ }
+ for(x=2;x<8;x++)
+  VRAM_BANK1(x*0x400,x);
+}
+
+void Mapper77_init(void)
+{
+ int x;
+
+ ROM_BANK32(0);
+ for(x=2;x<8;x++)
+  VRAM_BANK1(x*0x400,x);
+ SetWriteHandler(0x6000,0xffff,Mapper77_write);
+ MapStateRestore=Mapper77_StateRestore;
+}
diff --git a/mappers/79.c b/mappers/79.c
new file mode 100644 (file)
index 0000000..5e79efe
--- /dev/null
@@ -0,0 +1,40 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper79_write)
+{
+ if(A<0x8000 && ((A^0x4100)==0))
+ {
+  ROM_BANK32((V>>3)&1);
+ }
+ VROM_BANK8(V);
+}
+
+void Mapper79_init(void)
+{
+ ROM_BANK32(~0);
+ SetWriteHandler(0x8000,0xffff,Mapper79_write);
+ SetWriteHandler(0x4020,0x5fff,Mapper79_write);
+}
+
diff --git a/mappers/8.c b/mappers/8.c
new file mode 100644 (file)
index 0000000..1a68bf8
--- /dev/null
@@ -0,0 +1,38 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 BERO
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper8_write)
+{
+        ROM_BANK16(0x8000,V>>3);
+        VROM_BANK8(V&7);
+}
+
+void Mapper8_init(void)
+{
+       ROM_BANK32(0);
+        SetWriteHandler(0x8000,0xFFFF,Mapper8_write);
+}
+
diff --git a/mappers/80.c b/mappers/80.c
new file mode 100644 (file)
index 0000000..c824a12
--- /dev/null
@@ -0,0 +1,49 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper80_write)
+{
+switch(A)
+ {
+  case 0x7ef0: VROM_BANK1(0x000,V);VROM_BANK1(0x400,(V+1));break;
+  case 0x7ef1: VROM_BANK1(0x800,V);VROM_BANK1(0xC00,(V+1));break;
+
+  case 0x7ef2: VROM_BANK1(0x1000,V);break;
+  case 0x7ef3: VROM_BANK1(0x1400,V);break;
+  case 0x7ef4: VROM_BANK1(0x1800,V);break;
+  case 0x7ef5: VROM_BANK1(0x1c00,V);break;
+  case 0x7efa:
+  case 0x7efb: ROM_BANK8(0x8000,V);break;
+  case 0x7efd:
+  case 0x7efc: ROM_BANK8(0xA000,V);break;
+  case 0x7efe:
+  case 0x7eff: ROM_BANK8(0xC000,V);break;
+ }
+}
+
+void Mapper80_init(void)
+{
+SetWriteHandler(0x4020,0x7fff,Mapper80_write);
+}
+
diff --git a/mappers/82.c b/mappers/82.c
new file mode 100644 (file)
index 0000000..b6a1cb2
--- /dev/null
@@ -0,0 +1,62 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define ctrl   mapbyte1[6]
+
+static void DoCHR(void)
+{
+ int x;
+
+ for(x=0;x<2;x++)
+  VROM_BANK2((x<<11)|((ctrl&2)<<11),mapbyte1[x]>>1);
+ for(x=0;x<4;x++)
+  VROM_BANK1((x<<10) | (((ctrl&2)^2)<<11),mapbyte1[2+x]);
+}
+
+static DECLFW(Mapper82_write)
+{
+ if(A<=0x7EF5)
+ {
+  mapbyte1[A&7]=V;
+  DoCHR();
+ }
+ else
+  switch(A)
+  {
+   case 0x7ef6:ctrl=V&3;
+              MIRROR_SET2(V&1);
+              DoCHR();
+              break;
+   case 0x7efa:V>>=2;mapbyte2[0]=V;ROM_BANK8(0x8000,V);break;
+   case 0x7efb:V>>=2;mapbyte2[1]=V;ROM_BANK8(0xa000,V);break;
+   case 0x7efc:V>>=2;mapbyte2[2]=V;ROM_BANK8(0xc000,V);break;
+  }
+}
+
+void Mapper82_init(void)
+{
+ ROM_BANK8(0xE000,~0);
+
+ /* external WRAM might end at $73FF */
+ SetWriteHandler(0x7ef0,0x7efc,Mapper82_write);
+}
+
diff --git a/mappers/83.c b/mappers/83.c
new file mode 100644 (file)
index 0000000..6bcca19
--- /dev/null
@@ -0,0 +1,113 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+void FP_FASTAPASS(1) m83IRQHook(int a)
+{
+  if(IRQa)
+  {
+   IRQCount-=a;
+   if(IRQCount<0)
+   {
+    TriggerIRQ();
+    IRQa=0;
+    IRQCount=0xFFFF;
+   }
+  }
+}
+
+static DECLFW(wrlow)
+{
+ mapbyte4[A&3]=V;
+}
+
+static DECLFR(rdlow)
+{
+ return mapbyte4[A&3];
+}
+
+static void m83prg(void)
+{
+  ROM_BANK16(0x8000,mapbyte1[0]&0x3F);
+  ROM_BANK16(0xC000,(mapbyte1[0]&0x30)|0xF);
+}
+
+static void m83chr(void)
+{
+  int x;
+  for(x=0;x<8;x++)
+   VROM_BANK1(x*0x400,mapbyte2[x]|((mapbyte1[0]&0x30)<<4));
+}
+
+static DECLFW(Mapper83_write)
+{
+ //printf("$%04x:$%02x\n",A,V);
+ switch(A)
+ {
+  case 0x8000:
+  case 0xB000:
+  case 0xB0FF:
+  case 0xB1FF:
+       {
+        mapbyte1[0]=V;
+        m83prg();
+        m83chr();
+       }
+       break;
+  case 0x8100:
+              switch(V&0x3)
+              {
+              case 0x00:MIRROR_SET2(1);break;
+              case 0x01:MIRROR_SET2(0);break;
+              case 0x02:onemir(0);break;
+              case 0x03:onemir(1);break;
+              }
+              break;
+  case 0x8200:IRQCount&=0xFF00;IRQCount|=V;break;
+  case 0x8201:IRQa=1;IRQCount&=0xFF;IRQCount|=V<<8;break;
+  //case 0x8300:ROM_BANK8(0x8000,V);break;
+  //case 0x8301:ROM_BANK8(0xA000,V);break;
+  //case 0x8302:ROM_BANK8(0xC000,V);break;
+  case 0x8310:mapbyte2[0]=V;m83chr();break;
+  case 0x8311:mapbyte2[1]=V;m83chr();break;
+  case 0x8312:mapbyte2[2]=V;m83chr();break;
+  case 0x8313:mapbyte2[3]=V;m83chr();break;
+  case 0x8314:mapbyte2[4]=V;m83chr();break;
+  case 0x8315:mapbyte2[5]=V;m83chr();break;
+  case 0x8316:mapbyte2[6]=V;m83chr();break;
+  case 0x8317:mapbyte2[7]=V;m83chr();break;
+ }
+// printf("$%04x:$%02x, $%04x\n",A,V,X.PC.W);
+}
+
+void Mapper83_init(void)
+{
+
+ ROM_BANK8(0xc000,0x1e);
+ ROM_BANK8(0xe000,0x1f);
+
+ MapIRQHook=m83IRQHook;
+
+ SetReadHandler(0x5100,0x5103,rdlow);
+ SetWriteHandler(0x5100,0x5103,wrlow);
+ SetWriteHandler(0x8000,0xffff,Mapper83_write);
+}
diff --git a/mappers/85.c b/mappers/85.c
new file mode 100644 (file)
index 0000000..0d45898
--- /dev/null
@@ -0,0 +1,140 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define vrctemp mapbyte1[0]
+#define indox  mapbyte1[1]
+
+static int acount=0;
+
+void KillOPL(void);
+void UpdateOPL(int Count);
+void vrc7translate(uint8 A, uint8 V);
+void LoadOPL(void);
+extern uint8 VRC7Instrument[16][8];
+extern uint8 VRC7Chan[3][6];
+
+static INLINE void DaMirror(int V)
+{
+ int salpo[4]={MI_V,MI_H,MI_0,MI_1};
+ setmirror(salpo[V&3]);
+}
+
+DECLFW(Mapper85_write)
+{
+       A|=(A&8)<<1;
+
+       if(A>=0xa000 && A<=0xDFFF)
+       {
+        A&=0xF010;
+        {
+         int x=((A>>4)&1)|((A-0xA000)>>11);
+         mapbyte3[x]=V;
+         setchr1(x<<10,V);
+        }
+       }
+       else if(A==0x9030)
+       {
+        if(FSettings.SndRate)
+          vrc7translate(indox,V);
+         GameExpSound.Fill=UpdateOPL;
+       }
+       else switch(A&0xF010)
+        {
+         case 0x8000:mapbyte2[0]=V;setprg8(0x8000,V);break;
+         case 0x8010:mapbyte2[1]=V;setprg8(0xa000,V);break;
+         case 0x9000:mapbyte2[2]=V;setprg8(0xc000,V);break;
+         case 0x9010:indox=V;break;
+         case 0xe000:mapbyte2[3]=V;DaMirror(V);break;
+         case 0xE010:IRQLatch=V;
+                     break;
+         case 0xF000:IRQa=V&2;
+                     vrctemp=V&1;
+                     if(V&2) {IRQCount=IRQLatch;acount=0;}
+                     break;
+         case 0xf010:if(vrctemp) IRQa=1;
+                     else IRQa=0;
+                     break;
+        }
+}
+
+static void FP_FASTAPASS(1) KonamiIRQHook(int a)
+{
+  if(IRQa)
+   {
+    acount+=(a<<1)+a;
+    if(acount>=339)
+    {
+     doagainbub:acount-=339;IRQCount++;
+     if(IRQCount&0x100) {TriggerIRQ();IRQCount=IRQLatch;}
+     if(acount>=339) goto doagainbub;
+    }
+ }
+}
+
+void Mapper85_StateRestore(int version)
+{
+ int x;
+
+ if(version<72)
+ {
+  for(x=0;x<8;x++)
+   mapbyte3[x]=CHRBankList[x];
+  for(x=0;x<3;x++)
+   mapbyte2[x]=PRGBankList[x];
+  mapbyte2[3]=(Mirroring<0x10)?Mirroring:Mirroring-0xE;
+ }
+
+ for(x=0;x<8;x++)
+  setchr1(x*0x400,mapbyte3[x]);
+ for(x=0;x<3;x++)
+  setprg8(0x8000+x*8192,mapbyte2[x]);
+ DaMirror(mapbyte2[3]);
+ LoadOPL();
+}
+
+static void M85SC(void)
+{
+  KillOPL();
+}
+
+void VRC7_ESI(void)
+{
+   if(FSettings.SndRate)
+   {
+    SetWriteHandler(0x9010,0x901F,Mapper85_write);
+    SetWriteHandler(0x9030,0x903F,Mapper85_write);
+   }
+   GameExpSound.RChange=M85SC;
+}
+
+void Mapper85_init(void)
+{
+  MapIRQHook=KonamiIRQHook;
+  SetWriteHandler(0x8000,0xffff,Mapper85_write);
+  GameStateRestore=Mapper85_StateRestore;
+  VRC7_ESI();
+  if(!VROM_size)
+   SetupCartCHRMapping(0, CHRRAM, 8192, 1);
+  AddExState(VRC7Instrument, 16, 0, "VC7I");
+  AddExState(VRC7Chan, sizeof(VRC7Chan), 0, "V7CH");
+
+}
diff --git a/mappers/86.c b/mappers/86.c
new file mode 100644 (file)
index 0000000..5bcefcd
--- /dev/null
@@ -0,0 +1,32 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+DECLFW(Mapper86_write)
+{
+ VROM_BANK8((V&3)|((V>>4)&4));
+ ROM_BANK32((V>>4)&3);
+}
+
+void Mapper86_init(void)
+{
+ SetWriteHandler(0x6000,0x6000,Mapper86_write);
+}
diff --git a/mappers/88.c b/mappers/88.c
new file mode 100644 (file)
index 0000000..d6a7f86
--- /dev/null
@@ -0,0 +1,56 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+static DECLFW(Mapper88_write)
+{
+ //if(A>=0x8002 || A<0x8000)
+ //if(A==0xc000)
+ // printf("$%04x:$%02x\n",A,V);
+ switch(A) //&0xc001)
+ {
+             //case 0xc000:
+             //MIRROR_SET((V&0x40)>>6);
+             //onemir((V&0x40)>>6);
+             //break;
+  case 0x8000:mapbyte1[0]=V;break;
+  case 0x8001:
+             switch(mapbyte1[0]&7)
+             {
+              case 0:VROM_BANK2(0,V>>1);break;
+              case 1:VROM_BANK2(0x800,V>>1);break;
+              case 2:VROM_BANK1(0x1000,V|0x40);break;
+              case 3:VROM_BANK1(0x1400,V|0x40);break;
+              case 4:VROM_BANK1(0x1800,V|0x40);break;
+              case 5:VROM_BANK1(0x1c00,V|0x40);break;
+              case 6:ROM_BANK8(0x8000,V);break;
+              case 7:ROM_BANK8(0xA000,V);break;
+             }
+             break;
+
+ }
+}
+
+void Mapper88_init(void)
+{
+  SetWriteHandler(0x8000,0xffff,Mapper88_write);
+}
+
diff --git a/mappers/89.c b/mappers/89.c
new file mode 100644 (file)
index 0000000..696e698
--- /dev/null
@@ -0,0 +1,34 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+DECLFW(Mapper89_write)
+{
+ VROM_BANK8((V&7)|((V>>4)&8));
+ ROM_BANK16(0x8000,(V>>4)&7);
+ onemir((V>>3)&1);
+}
+
+void Mapper89_init(void)
+{
+ Mirroring=0;
+ SetWriteHandler(0x8000,0xffff,Mapper89_write);
+}
diff --git a/mappers/90.c b/mappers/90.c
new file mode 100644 (file)
index 0000000..97405dc
--- /dev/null
@@ -0,0 +1,154 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define tkcom1 mapbyte1[1]
+#define tkcom2 mapbyte1[2]
+
+#define prgb   mapbyte2
+#define unkl   (mapbyte2+4)
+#define chrlow  mapbyte3
+#define chrhigh mapbyte4
+
+static uint8 tekker=0x80;
+
+static DECLFR(tekread)
+{
+ return tekker;
+}
+
+static void tekprom(void)
+{
+ switch(tkcom1&3)
+  {
+   case 1:              // 16 KB
+          ROM_BANK16(0x8000,prgb[0]);
+          ROM_BANK16(0xC000,prgb[2]);
+          break;
+
+   case 2:              //2 = 8 KB ??
+   case 3:
+          ROM_BANK8(0x8000,prgb[0]);
+          ROM_BANK8(0xa000,prgb[1]);
+          ROM_BANK8(0xc000,prgb[2]);
+          ROM_BANK8(0xe000,prgb[3]);
+          break;
+  }
+}
+
+static void tekvrom(void)
+{
+ int x;
+ switch(tkcom1&0x18)
+  {
+   case 0x00:      // 8KB
+           VROM_BANK8(chrlow[0]|(chrhigh[0]<<8));
+          break;
+   case 0x08:      // 4KB
+          for(x=0;x<8;x+=4)
+           VROM_BANK4(x<<10,chrlow[x]|(chrhigh[x]<<8));
+         break;
+   case 0x10:      // 2KB
+         for(x=0;x<8;x+=2)
+           VROM_BANK2(x<<10,chrlow[x]|(chrhigh[x]<<8));
+         break;
+   case 0x18:      // 1KB
+          for(x=0;x<8;x++)
+           VROM_BANK1(x<<10,chrlow[x]|(chrhigh[x]<<8));
+          break;
+ }
+}
+
+static DECLFW(Mapper90_write)
+{
+ A&=0xF007;
+
+ if(A>=0x8000 && A<=0x8003)
+ {
+  prgb[A&3]=V;
+  tekprom();
+ }
+ else if(A>=0x9000 && A<=0x9007)
+ {
+  chrlow[A&7]=V;
+  tekvrom();
+ }
+ else if(A>=0xa000 && A<=0xa007)
+ {
+  chrhigh[A&7]=V;
+  tekvrom();
+ }
+ else if(A>=0xb000 && A<=0xb003)
+ {
+  unkl[A&3]=V;
+ }
+ else switch(A)
+ {
+   case 0xc004:
+   case 0xc000:IRQLatch=V;break;
+
+   case 0xc005:
+   case 0xc001:X6502_IRQEnd(FCEU_IQEXT);
+               IRQCount=V;break;
+   case 0xc006:
+   case 0xc002:X6502_IRQEnd(FCEU_IQEXT);
+               IRQa=0;
+               IRQCount=IRQLatch;
+               break;
+   case 0xc007:
+   case 0xc003:IRQa=1;break;
+
+   case 0xd000:tkcom1=V;break;
+   case 0xd001:switch(V&3){
+                  case 0x00:MIRROR_SET(0);break;
+                  case 0x01:MIRROR_SET(1);break;
+                  case 0x02:onemir(0);break;
+                  case 0x03:onemir(1);break;
+               }
+              break;
+   break;
+ }
+}
+
+static void Mapper90_hb(void)
+{
+ if(IRQa)
+ {
+  if(IRQCount) 
+  {
+   IRQCount--;
+   if(!IRQCount)
+   {
+    X6502_IRQBegin(FCEU_IQEXT);
+    IRQCount=IRQLatch;
+   }
+  }
+ }
+}
+
+void Mapper90_init(void)
+{
+  tekker^=0x80;
+  SetWriteHandler(0x8000,0xffff,Mapper90_write);
+  SetReadHandler(0x5000,0x5000,tekread);
+  GameHBIRQHook=Mapper90_hb;
+}
+
diff --git a/mappers/92.c b/mappers/92.c
new file mode 100644 (file)
index 0000000..1494e7f
--- /dev/null
@@ -0,0 +1,45 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+/* Original code provided by LULU */
+
+static DECLFW(Mapper92_write)
+{
+ uint8 reg=(A&0xF0)>>4;
+ uint8 bank=A&0xF;
+
+ if(A>=0x9000)
+ {
+  if(reg==0xD) ROM_BANK16(0xc000,bank);
+  else if(reg==0xE) VROM_BANK8(bank);
+ }
+ else
+ {
+  if(reg==0xB) ROM_BANK16(0xc000,bank);
+  else if(reg==0x7) VROM_BANK8(bank);
+ }
+}
+
+void Mapper92_init(void)
+{
+ SetWriteHandler(0x8000,0xFFFF,Mapper92_write);
+}
diff --git a/mappers/95.c b/mappers/95.c
new file mode 100644 (file)
index 0000000..2d6792b
--- /dev/null
@@ -0,0 +1,76 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+#define dbarray mapbyte1
+static void FP_FASTAPASS(1) dragonbust_ppu(uint32 A)
+{
+ static int last=-1;
+ static uint8 z;
+
+ if(A>=0x2000) return;
+
+ A>>=13;
+
+ z=dbarray[A];
+
+ if(z!=last)
+ {
+  onemir(z);
+  last=z;
+ }
+}
+
+
+DECLFW(Mapper95_write)
+{
+        switch(A&0xF001){
+
+        case 0x8000:
+        MMC3_cmd = V;
+        break;
+
+        case 0x8001:
+                switch(MMC3_cmd&7){
+                case 0: dbarray[0]=dbarray[1]=(V&0x20)>>4;onemir((V&0x20)>>4);V>>=1;VROM_BANK2(0x0000,V);break;
+                case 1: dbarray[2]=dbarray[3]=(V&0x20)>>4;onemir((V&0x20)>>4);V>>=1;VROM_BANK2(0x0800,V);break;
+                case 2: dbarray[4]=(V&0x20)>>4;onemir((V&0x20)>>4);VROM_BANK1(0x1000,V); break;
+                case 3: dbarray[5]=(V&0x20)>>4;onemir((V&0x20)>>4);VROM_BANK1(0x1400,V); break;
+                case 4: dbarray[6]=(V&0x20)>>4;onemir((V&0x20)>>4);VROM_BANK1(0x1800,V); break;
+                case 5: dbarray[7]=(V&0x20)>>4;onemir((V&0x20)>>4);VROM_BANK1(0x1C00,V); break;
+                case 6:
+                        ROM_BANK8(0x8000,V);
+                        break;
+                case 7:
+                        ROM_BANK8(0xA000,V);
+                        break;
+                }
+                break;
+}
+}
+
+void Mapper95_init(void)
+{
+  SetWriteHandler(0x8000,0xffff,Mapper95_write);
+  PPU_hook=dragonbust_ppu;
+}
+
diff --git a/mappers/97.c b/mappers/97.c
new file mode 100644 (file)
index 0000000..f019fdc
--- /dev/null
@@ -0,0 +1,42 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper97_write)
+{
+ROM_BANK16(0xC000,V&15);
+switch(V>>6)
+ {
+ case 0:break;
+ case 1:MIRROR_SET2(0);break;
+ case 2:MIRROR_SET2(1);break;
+ case 3:break;
+ }
+}
+
+void Mapper97_init(void)
+{
+  ROM_BANK16(0x8000,~0);
+  SetWriteHandler(0x8000,0xffff,Mapper97_write);
+}
+
diff --git a/mappers/99.c b/mappers/99.c
new file mode 100644 (file)
index 0000000..c71611e
--- /dev/null
@@ -0,0 +1,35 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+static writefunc oldmorko;
+
+static DECLFW(morko)
+{
+ VROM_BANK8((V>>2)&1);
+ oldmorko(A,V);
+}
+
+void Mapper99_init(void)
+{
+ oldmorko=GetWriteHandler(0x4016);
+ SetWriteHandler(0x4016,0x4016,morko);
+}
diff --git a/mappers/Makefile b/mappers/Makefile
new file mode 100644 (file)
index 0000000..c95ca8f
--- /dev/null
@@ -0,0 +1,74 @@
+MOBJS   =      mappers/mmc2and4.o mappers/simple.o mappers/112.o mappers/117.o mappers/15.o mappers/151.o mappers/16.o mappers/17.o mappers/18.o mappers/180.o mappers/184.o mappers/19.o  mappers/21.o mappers/22.o mappers/225.o mappers/226.o mappers/228.o mappers/229.o mappers/23.o mappers/24and26.o mappers/240.o mappers/246.o mappers/25.o mappers/32.o mappers/33.o mappers/40.o mappers/41.o mappers/6.o mappers/64.o mappers/65.o mappers/67.o mappers/68.o mappers/69.o mappers/71.o mappers/73.o mappers/75.o mappers/76.o mappers/79.o mappers/8.o mappers/80.o mappers/85.o mappers/90.o mappers/95.o mappers/97.o mappers/99.o mappers/182.o mappers/vrc7snd.o mappers/46.o mappers/43.o mappers/42.o mappers/113.o mappers/86.o mappers/89.o mappers/83.o mappers/77.o mappers/92.o mappers/105.o mappers/88.o mappers/248.o mappers/fmopl.o mappers/242.o mappers/232.o mappers/72.o mappers/234.o mappers/227.o mappers/82.o mappers/189.o mappers/245.o mappers/249.o mappers/51.o
+
+fmopl.o:       mappers/fmopl.c mappers/fmopl.h
+vrc7snd.o:     mappers/vrc7snd.c
+
+mappers/simple.o:       mappers/simple.c
+mappers/mmc2and4.o:     mappers/mmc2and4.c
+
+mappers/112.o:         mappers/112.c
+mappers/117.o:         mappers/117.c
+mappers/15.o:          mappers/15.c
+mappers/151.o:         mappers/151.c
+mappers/16.o:          mappers/16.c
+mappers/17.o:          mappers/17.c
+mappers/18.o:          mappers/18.c
+mappers/19.o:          mappers/19.c
+mappers/180.o:         mappers/180.c
+mappers/184.o:         mappers/184.c
+mappers/21.o:          mappers/21.c
+mappers/22.o:          mappers/22.c
+mappers/23.o:          mappers/23.c
+mappers/24and26.o:     mappers/24and26.c
+mappers/25.o:          mappers/25.c
+mappers/225.o:         mappers/225.c
+mappers/226.o:         mappers/226.c
+mappers/228.o:         mappers/228.c
+mappers/229.o:         mappers/229.c
+mappers/240.o:         mappers/240.c
+mappers/246.o:         mappers/246.c
+mappers/32.o:          mappers/32.c
+mappers/33.o:          mappers/33.c
+mappers/40.o:          mappers/40.c
+mappers/41.o:          mappers/41.c
+mappers/6.o:           mappers/6.c
+mappers/64.o:          mappers/64.c
+mappers/65.o:          mappers/65.c
+mappers/67.o:          mappers/67.c
+mappers/68.o:          mappers/68.c
+mappers/69.o:          mappers/69.c
+mappers/71.o:          mappers/71.c
+mappers/73.o:          mappers/73.c
+mappers/75.o:          mappers/75.c
+mappers/76.o:          mappers/76.c
+mappers/79.o:          mappers/79.c
+mappers/8.o:           mappers/8.c
+mappers/80.o:          mappers/80.c
+mappers/85.o:          mappers/85.c
+mappers/90.o:          mappers/90.c
+mappers/95.o:          mappers/95.c
+mappers/97.o:          mappers/97.c
+mappers/99.o:          mappers/99.c
+mappers/182.o:         mappers/182.c
+mappers/46.o:           mappers/46.c
+mappers/43.o:           mappers/43.c
+mappers/42.o:           mappers/42.c
+mappers/113.o:          mappers/113.c
+mappers/86.o:          mappers/86.c
+mappers/89.o:          mappers/89.c
+mappers/83.o:          mappers/83.c
+mappers/77.o:          mappers/77.c
+mappers/92.o:          mappers/92.c
+mappers/105.o:         mappers/105.c
+mappers/88.o:          mappers/88.c
+mappers/248.o:         mappers/248.c
+mappers/242.o:         mappers/242.c
+mappers/232.o:         mappers/232.c
+mappers/72.o:          mappers/72.c
+mappers/234.o:         mappers/234.c
+mappers/227.o:         mappers/227.c
+mappers/82.o:          mappers/82.c
+mappers/189.o:         mappers/189.c
+mappers/245.o:         mappers/245.c
+mappers/249.o:         mappers/249.c
+mappers/51.o:          mappers/51.c
diff --git a/mappers/fmopl.c b/mappers/fmopl.c
new file mode 100644 (file)
index 0000000..b2fc12c
--- /dev/null
@@ -0,0 +1,871 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1999,2000 Tatsuyuki Satoh
+ *  Copyright (C) 2001,2002 Ben Parnell
+ *
+ * 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-1307  USA 
+ */
+
+/* This file has been heavily modified from the original(mostly unused
+   code was removed).  If you want to use it for anything other than
+   VRC7 sound emulation, you should get the original from the AdPlug
+   source distribution or the MAME(version 0.37b16) source distribution
+   (but be careful about the different licenses).
+        - Xodnizel
+*/
+   
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+#include "mapinc.h"
+#include "fmopl.h"
+
+#ifndef PI
+#define PI 3.14159265358979323846
+#endif
+
+/* -------------------- preliminary define section --------------------- */
+/* attack/decay rate time rate */
+#define OPL_ARRATE     141280  /* RATE 4 =  2826.24ms @ 3.6MHz */
+#define OPL_DRRATE    1956000  /* RATE 4 = 39280.64ms @ 3.6MHz */
+
+#define DELTAT_MIXING_LEVEL (1) /* DELTA-T ADPCM MIXING LEVEL */
+
+#define FREQ_BITS 24                   /* frequency turn          */
+
+/* counter bits = 20 , octerve 7 */
+#define FREQ_RATE   (1<<(FREQ_BITS-20))
+#define TL_BITS    (FREQ_BITS+2)
+
+/* final output shift , limit minimum and maximum */
+#define OPL_OUTSB   (TL_BITS+3-16)             /* OPL output final shift 16bit */
+#define OPL_MAXOUT (0x7fff<<OPL_OUTSB<<3)
+#define OPL_MINOUT (-0x8000<<OPL_OUTSB<<3)
+
+/* -------------------- quality selection --------------------- */
+
+/* sinwave entries */
+/* used static memory = SIN_ENT * 4 (byte) */
+#define SIN_ENT 2048
+
+/* output level entries (envelope,sinwave) */
+/* envelope counter lower bits */
+#define ENV_BITS 16
+/* envelope output entries */
+#define EG_ENT   4096
+/* used dynamic memory = EG_ENT*4*4(byte)or EG_ENT*6*4(byte) */
+/* used static  memory = EG_ENT*4 (byte)                     */
+
+#define EG_OFF   ((2*EG_ENT)<<ENV_BITS)  /* OFF          */
+#define EG_DED   EG_OFF
+#define EG_DST   (EG_ENT<<ENV_BITS)      /* DECAY  START */
+#define EG_AED   EG_DST
+#define EG_AST   0                       /* ATTACK START */
+
+#define EG_STEP (96.0/EG_ENT) /* OPL is 0.1875 dB step  */
+
+/* LFO table entries */
+#define VIB_ENT 512
+#define VIB_SHIFT (32-9)
+#define AMS_ENT 512
+#define AMS_SHIFT (32-9)
+
+#define VIB_RATE 256
+
+/* -------------------- local defines , macros --------------------- */
+
+/* register number to channel number , slot offset */
+#define SLOT1 0
+#define SLOT2 1
+
+/* envelope phase */
+#define ENV_MOD_RR  0x00
+#define ENV_MOD_DR  0x01
+#define ENV_MOD_AR  0x02
+
+/* -------------------- tables --------------------- */
+static const int slot_array[32]=
+{
+        0, 2, 4, 1, 3, 5,-1,-1,
+        6, 8,10, 7, 9,11,-1,-1,
+       12,14,16,13,15,17,-1,-1,
+       -1,-1,-1,-1,-1,-1,-1,-1
+};
+
+/* key scale level */
+/* table is 3dB/OCT , DV converts this in TL step at 6dB/OCT */
+#define DV (EG_STEP/2)
+static const UINT32 KSL_TABLE[8*16]=
+{
+       /* OCT 0 */
+        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+       /* OCT 1 */
+        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+        0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV,
+        1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV,
+       /* OCT 2 */
+        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+        0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV,
+        3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV,
+        4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV,
+       /* OCT 3 */
+        0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV,
+        3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV,
+        6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV,
+        7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV,
+       /* OCT 4 */
+        0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV,
+        6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV,
+        9.000/DV, 9.750/DV,10.125/DV,10.500/DV,
+       10.875/DV,11.250/DV,11.625/DV,12.000/DV,
+       /* OCT 5 */
+        0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV,
+        9.000/DV,10.125/DV,10.875/DV,11.625/DV,
+       12.000/DV,12.750/DV,13.125/DV,13.500/DV,
+       13.875/DV,14.250/DV,14.625/DV,15.000/DV,
+       /* OCT 6 */
+        0.000/DV, 6.000/DV, 9.000/DV,10.875/DV,
+       12.000/DV,13.125/DV,13.875/DV,14.625/DV,
+       15.000/DV,15.750/DV,16.125/DV,16.500/DV,
+       16.875/DV,17.250/DV,17.625/DV,18.000/DV,
+       /* OCT 7 */
+        0.000/DV, 9.000/DV,12.000/DV,13.875/DV,
+       15.000/DV,16.125/DV,16.875/DV,17.625/DV,
+       18.000/DV,18.750/DV,19.125/DV,19.500/DV,
+       19.875/DV,20.250/DV,20.625/DV,21.000/DV
+};
+#undef DV
+
+/* sustain lebel table (3db per step) */
+/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
+#define SC(db) (db*((3/EG_STEP)*(1<<ENV_BITS)))+EG_DST
+static const INT32 SL_TABLE[16]={
+ SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
+ SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
+};
+#undef SC
+
+#define TL_MAX (EG_ENT*2) /* limit(tl + ksr + envelope) + sinwave */
+/* TotalLevel : 48 24 12  6  3 1.5 0.75 (dB) */
+/* TL_TABLE[ 0      to TL_MAX          ] : plus  section */
+/* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */
+static INT32 *TL_TABLE;
+
+/* pointers to TL_TABLE with sinwave output offset */
+static INT32 **SIN_TABLE;
+
+/* LFO table */
+static INT32 *AMS_TABLE;
+static INT32 *VIB_TABLE;
+
+/* envelope output curve table */
+/* attack + decay + OFF */
+static INT32 ENV_CURVE[2*EG_ENT+1];
+
+/* multiple table */
+#define ML 2
+static const UINT32 MUL_TABLE[16]= {
+/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */
+   0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML,
+   8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML
+};
+#undef ML
+
+/* dummy attack / decay rate ( when rate == 0 ) */
+static INT32 RATE_0[16]=
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+/* -------------------- static state --------------------- */
+
+/* lock level of common table */
+static int num_lock = 0;
+
+/* work table */
+static void *cur_chip = NULL;  /* current chip point */
+/* currenct chip state */
+/* static OPLSAMPLE  *bufL,*bufR; */
+static OPL_CH *S_CH;
+static OPL_CH *E_CH;
+OPL_SLOT *SLOT7_1,*SLOT7_2,*SLOT8_1,*SLOT8_2;
+
+static INT32 outd[1];
+static INT32 ams;
+static INT32 vib;
+INT32  *ams_table;
+INT32  *vib_table;
+static INT32 amsIncr;
+static INT32 vibIncr;
+static INT32 feedback2;                /* connect for SLOT 2 */
+
+/* --------------------- subroutines  --------------------- */
+
+INLINE int Limit( int val, int max, int min ) {
+       if ( val > max )
+               val = max;
+       else if ( val < min )
+               val = min;
+
+       return val;
+}
+
+/* ----- key on  ----- */
+INLINE void OPL_KEYON(OPL_SLOT *SLOT)
+{
+       /* sin wave restart */
+       SLOT->Cnt = 0;
+       /* set attack */
+       SLOT->evm = ENV_MOD_AR;
+       SLOT->evs = SLOT->evsa;
+       SLOT->evc = EG_AST;
+       SLOT->eve = EG_AED;
+}
+/* ----- key off ----- */
+INLINE void OPL_KEYOFF(OPL_SLOT *SLOT)
+{
+       if( SLOT->evm > ENV_MOD_RR)
+       {
+               /* set envelope counter from envleope output */
+               SLOT->evm = ENV_MOD_RR;
+               if( !(SLOT->evc&EG_DST) )
+                       //SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<<ENV_BITS) + EG_DST;
+                       SLOT->evc = EG_DST;
+               SLOT->eve = EG_DED;
+               SLOT->evs = SLOT->evsr;
+       }
+}
+
+/* ---------- calcrate Envelope Generator & Phase Generator ---------- */
+/* return : envelope output */
+INLINE UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
+{
+       /* calcrate envelope generator */
+       if( (SLOT->evc+=SLOT->evs) >= SLOT->eve )
+       {
+               switch( SLOT->evm ){
+               case ENV_MOD_AR: /* ATTACK -> DECAY1 */
+                       /* next DR */
+                       SLOT->evm = ENV_MOD_DR;
+                       SLOT->evc = EG_DST;
+                       SLOT->eve = SLOT->SL;
+                       SLOT->evs = SLOT->evsd;
+                       break;
+               case ENV_MOD_DR: /* DECAY -> SL or RR */
+                       SLOT->evc = SLOT->SL;
+                       SLOT->eve = EG_DED;
+                       if(SLOT->eg_typ)
+                       {
+                               SLOT->evs = 0;
+                       }
+                       else
+                       {
+                               SLOT->evm = ENV_MOD_RR;
+                               SLOT->evs = SLOT->evsr;
+                       }
+                       break;
+               case ENV_MOD_RR: /* RR -> OFF */
+                       SLOT->evc = EG_OFF;
+                       SLOT->eve = EG_OFF+1;
+                       SLOT->evs = 0;
+                       break;
+               }
+       }
+       /* calcrate envelope */
+       return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]+(SLOT->ams ? ams : 0);
+}
+
+/* set algorythm connection */
+static void set_algorythm( OPL_CH *CH)
+{
+       INT32 *carrier = &outd[0];
+       CH->connect1 = CH->CON ? carrier : &feedback2;
+       CH->connect2 = carrier;
+}
+
+/* ---------- frequency counter for operater update ---------- */
+INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
+{
+       int ksr;
+
+       /* frequency step counter */
+       SLOT->Incr = CH->fc * SLOT->mul;
+       ksr = CH->kcode >> SLOT->KSR;
+
+       if( SLOT->ksr != ksr )
+       {
+               SLOT->ksr = ksr;
+               /* attack , decay rate recalcration */
+               SLOT->evsa = SLOT->AR[ksr];
+               SLOT->evsd = SLOT->DR[ksr];
+               SLOT->evsr = SLOT->RR[ksr];
+       }
+       SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+}
+
+/* set multi,am,vib,EG-TYP,KSR,mul */
+INLINE void set_mul(FM_OPL *OPL,int slot,int v)
+{
+       OPL_CH   *CH   = &OPL->P_CH[slot/2];
+       OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+
+       SLOT->mul    = MUL_TABLE[v&0x0f];
+       SLOT->KSR    = (v&0x10) ? 0 : 2;
+       SLOT->eg_typ = (v&0x20)>>5;
+       SLOT->vib    = (v&0x40);
+       SLOT->ams    = (v&0x80);
+       CALC_FCSLOT(CH,SLOT);
+}
+
+/* set ksl & tl */
+INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v)
+{
+       OPL_CH   *CH   = &OPL->P_CH[slot/2];
+       OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+       int ksl = v>>6; /* 0 / 1.5 / 3 / 6 db/OCT */
+
+//     if(slot&1) 
+//         if(ksl) {sprintf(errmsg,"doh");howlong=255;ksl=0;}
+
+       SLOT->ksl = ksl ? ksl : 31;
+//     SLOT->ksl = ksl ? 3-ksl : 31;
+       SLOT->TL  = (v&0x3f)*(0.75/EG_STEP); /* 0.75db step */
+
+       if( !(OPL->mode&0x80) )
+       {       /* not CSM latch total level */
+               SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+       }
+}
+
+/* set attack rate & decay rate  */
+INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v)
+{
+       OPL_CH   *CH   = &OPL->P_CH[slot/2];
+       OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+       int ar = v>>4;
+       int dr = v&0x0f;
+
+       SLOT->AR = ar ? &OPL->AR_TABLE[ar<<2] : RATE_0;
+       SLOT->evsa = SLOT->AR[SLOT->ksr];
+       if( SLOT->evm == ENV_MOD_AR ) SLOT->evs = SLOT->evsa;
+
+       SLOT->DR = dr ? &OPL->DR_TABLE[dr<<2] : RATE_0;
+       SLOT->evsd = SLOT->DR[SLOT->ksr];
+       if( SLOT->evm == ENV_MOD_DR ) SLOT->evs = SLOT->evsd;
+}
+
+/* set sustain level & release rate */
+INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v)
+{
+       OPL_CH   *CH   = &OPL->P_CH[slot/2];
+       OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+       int sl = v>>4;
+       int rr = v & 0x0f;
+
+       SLOT->SL = SL_TABLE[sl];
+       if( SLOT->evm == ENV_MOD_DR ) SLOT->eve = SLOT->SL;
+       SLOT->RR = &OPL->DR_TABLE[rr<<2];
+       SLOT->evsr = SLOT->RR[SLOT->ksr];
+       if( SLOT->evm == ENV_MOD_RR ) SLOT->evs = SLOT->evsr;
+}
+
+/* operator output calcrator */
+#define OP_OUT(slot,env,con)   slot->wavetable[((slot->Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env]
+/* ---------- calcrate one of channel ---------- */
+INLINE void OPL_CALC_CH( OPL_CH *CH )
+{
+       UINT32 env_out;
+       OPL_SLOT *SLOT;
+
+       feedback2 = 0;
+       /* SLOT 1 */
+       SLOT = &CH->SLOT[SLOT1];
+       env_out=OPL_CALC_SLOT(SLOT);
+       if( env_out < EG_ENT-1 )
+       {
+               /* PG */
+               if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
+               else          SLOT->Cnt += SLOT->Incr;
+               /* connectoion */
+               if(CH->FB)
+               {
+                       int feedback1 = (CH->op1_out[0]+CH->op1_out[1])>>CH->FB;
+                       CH->op1_out[1] = CH->op1_out[0];
+                       *CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
+               }
+               else
+               {
+                       *CH->connect1 += OP_OUT(SLOT,env_out,0);
+               }
+       }else
+       {
+               CH->op1_out[1] = CH->op1_out[0];
+               CH->op1_out[0] = 0;
+       }
+       /* SLOT 2 */
+       SLOT = &CH->SLOT[SLOT2];
+       env_out=OPL_CALC_SLOT(SLOT);
+       if( env_out < EG_ENT-1 )
+       {
+               /* PG */
+               if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
+               else          SLOT->Cnt += SLOT->Incr;
+               /* connectoion */
+               outd[0] += OP_OUT(SLOT,env_out, feedback2);
+       }
+}
+
+/* ----------- initialize time tabls ----------- */
+static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE )
+{
+       int i;
+       double rate;
+
+       /* make attack rate & decay rate tables */
+       for (i = 0;i < 4;i++) OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0;
+       for (i = 4;i <= 60;i++){
+               rate  = OPL->freqbase;                                          /* frequency rate */
+               if( i < 60 ) rate *= 1.0+(i&3)*0.25;            /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */
+               rate *= 1<<((i>>2)-1);                                          /* b2-5 : shift bit */
+               rate *= (double)(EG_ENT<<ENV_BITS);
+               OPL->AR_TABLE[i] = rate / ARRATE;
+               OPL->DR_TABLE[i] = rate / DRRATE;
+       }
+       for (i = 60;i < 76;i++)
+       {
+               OPL->AR_TABLE[i] = EG_AED-1;
+               OPL->DR_TABLE[i] = OPL->DR_TABLE[60];
+       }
+}
+
+/* ---------- generic table initialize ---------- */
+static int OPLOpenTable( void )
+{
+       int s,t;
+       double rate;
+       int i,j;
+       double pom;
+
+       /* allocate dynamic tables */
+       if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL)
+               return 0;
+       if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL)
+       {
+               free(TL_TABLE);
+               return 0;
+       }
+       if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL)
+       {
+               free(TL_TABLE);
+               free(SIN_TABLE);
+               return 0;
+       }
+       if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL)
+       {
+               free(TL_TABLE);
+               free(SIN_TABLE);
+               free(AMS_TABLE);
+               return 0;
+       }
+       /* make total level table */
+       for (t = 0;t < EG_ENT-1 ;t++){
+               rate = ((1<<TL_BITS)-1)/pow(10,EG_STEP*t/20);   /* dB -> voltage */
+               TL_TABLE[       t] =  (int)rate;
+               TL_TABLE[TL_MAX+t] = -TL_TABLE[t];
+
+       }
+       /* fill volume off area */
+       for ( t = EG_ENT-1; t < TL_MAX ;t++){
+               TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0;
+       }
+
+       /* make sinwave table (total level offet) */
+       /* degree 0 = degree 180                   = off */
+       SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2]         = &TL_TABLE[EG_ENT-1];
+       for (s = 1;s <= SIN_ENT/4;s++){
+               pom = sin(2*PI*s/SIN_ENT); /* sin     */
+               pom = 20*log10(1/pom);     /* decibel */
+               j = pom / EG_STEP;         /* TL_TABLE steps */
+
+        /* degree 0   -  90    , degree 180 -  90 : plus section */
+               SIN_TABLE[          s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j];
+        /* degree 180 - 270    , degree 360 - 270 : minus section */
+               SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT  -s] = &TL_TABLE[TL_MAX+j];
+
+       }
+       for (s = 0;s < SIN_ENT;s++)
+       {
+               SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT];
+               SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)];
+               SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s];
+       }
+
+       /* envelope counter -> envelope output table */
+       for (i=0; i<EG_ENT; i++)
+       {
+               /* ATTACK curve */
+               pom = pow( ((double)(EG_ENT-1-i)/EG_ENT) , 8 ) * EG_ENT;
+               /* if( pom >= EG_ENT ) pom = EG_ENT-1; */
+               ENV_CURVE[i] = (int)pom;
+               /* DECAY ,RELEASE curve */
+               ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i;
+       }
+       /* off */
+       ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1;
+       /* make LFO ams table */
+       for (i=0; i<AMS_ENT; i++)
+       {
+               pom = (1.0+sin(2*PI*i/AMS_ENT))/2; /* sin */
+               AMS_TABLE[i]         = (1.0/EG_STEP)*pom; /* 1dB   */
+               AMS_TABLE[AMS_ENT+i] = (4.8/EG_STEP)*pom; /* 4.8dB */
+       }
+       /* make LFO vibrate table */
+       for (i=0; i<VIB_ENT; i++)
+       {
+               /* 100cent = 1seminote = 6% ?? */
+               pom = (double)VIB_RATE*0.06*sin(2*PI*i/VIB_ENT); /* +-100sect step */
+               VIB_TABLE[i]         = VIB_RATE + (pom*0.07); /* +- 7cent */
+               VIB_TABLE[VIB_ENT+i] = VIB_RATE + (pom*0.14); /* +-14cent */
+       }
+       return 1;
+}
+
+
+static void OPLCloseTable( void )
+{
+       free(TL_TABLE);
+       free(SIN_TABLE);
+       free(AMS_TABLE);
+       free(VIB_TABLE);
+}
+
+/* CSM Key Controll */
+INLINE void CSMKeyControll(OPL_CH *CH)
+{
+       OPL_SLOT *slot1 = &CH->SLOT[SLOT1];
+       OPL_SLOT *slot2 = &CH->SLOT[SLOT2];
+       /* all key off */
+       OPL_KEYOFF(slot1);
+       OPL_KEYOFF(slot2);
+       /* total level latch */
+       slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
+       slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
+       /* key on */
+       CH->op1_out[0] = CH->op1_out[1] = 0;
+       OPL_KEYON(slot1);
+       OPL_KEYON(slot2);
+}
+
+/* ---------- opl initialize ---------- */
+static void OPL_initalize(FM_OPL *OPL)
+{
+       int fn;
+
+       /* frequency base */
+       OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72  : 0;
+       /* make time tables */
+       init_timetables( OPL , OPL_ARRATE , OPL_DRRATE );
+       /* make fnumber -> increment counter table */
+       for( fn=0 ; fn < 1024 ; fn++ )
+       {
+               OPL->FN_TABLE[fn] = OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2;
+       }
+       /* LFO freq.table */
+       OPL->amsIncr = OPL->rate ? (double)AMS_ENT*(1<<AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0;
+       OPL->vibIncr = OPL->rate ? (double)VIB_ENT*(1<<VIB_SHIFT) / OPL->rate * 6.4 * ((double)OPL->clock/3600000) : 0;
+}
+
+/* ---------- write a OPL registers ---------- */
+static void OPLWriteReg(FM_OPL *OPL, int r, int v)
+{
+       OPL_CH *CH;
+       int slot;
+       int block_fnum;
+
+       switch(r&0xe0)
+       {
+       case 0x00: /* 00-1f:controll */
+               switch(r&0x1f)
+               {
+               case 0x01:
+                       /* wave selector enable */
+                       if(OPL->type&OPL_TYPE_WAVESEL)
+                       {
+                               OPL->wavesel = v&0x20;
+                               if(!OPL->wavesel)
+                               {
+                                       /* preset compatible mode */
+                                       int c;
+                                       for(c=0;c<OPL->max_ch;c++)
+                                       {
+                                               OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
+                                               OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
+                                       }
+                               }
+                       }
+                       return;
+               }
+               break;
+       case 0x20:      /* am,vib,ksr,eg type,mul */
+               slot = slot_array[r&0x1f];
+               if(slot == -1) return;
+               set_mul(OPL,slot,v);
+               return;
+       case 0x40:
+               slot = slot_array[r&0x1f];
+               if(slot == -1) return;
+               set_ksl_tl(OPL,slot,v);
+               return;
+       case 0x60:
+               slot = slot_array[r&0x1f];
+               if(slot == -1) return;
+               set_ar_dr(OPL,slot,v);
+               return;
+       case 0x80:
+               slot = slot_array[r&0x1f];
+               if(slot == -1) return;
+               set_sl_rr(OPL,slot,v);
+               return;
+       case 0xa0:
+               switch(r)
+               {
+               case 0xbd:
+                       /* amsep,vibdep,r,bd,sd,tom,tc,hh */
+                       {
+                       OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0];
+                       OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0];
+                       }
+                       return;
+               }
+               /* keyon,block,fnum */
+               if( (r&0x0f) > 8) return;
+               CH = &OPL->P_CH[r&0x0f];
+               if(!(r&0x10))
+               {       /* a0-a8 */
+                       block_fnum  = (CH->block_fnum&0x1f00) | v;
+               }
+               else
+               {       /* b0-b8 */
+                       int keyon = (v>>5)&1;
+                       block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff);
+                       if(CH->keyon != keyon)
+                       {
+                               if( (CH->keyon=keyon) )
+                               {
+                                       CH->op1_out[0] = CH->op1_out[1] = 0;
+                                       OPL_KEYON(&CH->SLOT[SLOT1]);
+                                       OPL_KEYON(&CH->SLOT[SLOT2]);
+                               }
+                               else
+                               {
+                                       OPL_KEYOFF(&CH->SLOT[SLOT1]);
+                                       OPL_KEYOFF(&CH->SLOT[SLOT2]);
+                               }
+                       }
+               }
+               /* update */
+               if(CH->block_fnum != block_fnum)
+               {
+                       int blockRv = 7-(block_fnum>>10);
+                       int fnum   = block_fnum&0x3ff;
+                       CH->block_fnum = block_fnum;
+
+                       CH->ksl_base = KSL_TABLE[block_fnum>>6];
+                       CH->fc = OPL->FN_TABLE[fnum]>>blockRv;
+                       CH->kcode = CH->block_fnum>>9;
+                       if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1;
+                       CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
+                       CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
+               }
+               return;
+       case 0xc0:
+               /* FB,C */
+               if( (r&0x0f) > 8) return;
+               CH = &OPL->P_CH[r&0x0f];
+               {
+               int feedback = (v>>1)&7;
+               CH->FB   = feedback ? (8+1) - feedback : 0;
+               CH->CON = v&1;
+               set_algorythm(CH);
+               }
+               return;
+       case 0xe0: /* wave type */
+               slot = slot_array[r&0x1f];
+               if(slot == -1) return;
+               CH = &OPL->P_CH[slot/2];
+               if(OPL->wavesel)
+               {
+                       CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT];
+               }
+               return;
+       }
+}
+
+/* lock/unlock for common table */
+static int OPL_LockTable(void)
+{
+       num_lock++;
+       if(num_lock>1) return 0;
+       /* first time */
+       cur_chip = NULL;
+       /* allocate total level table (128kb space) */
+       if( !OPLOpenTable() )
+       {
+               num_lock--;
+               return -1;
+       }
+       return 0;
+}
+
+static void OPL_UnLockTable(void)
+{
+       if(num_lock) num_lock--;
+       if(num_lock) return;
+       /* last time */
+       cur_chip = NULL;
+       OPLCloseTable();
+}
+
+/*******************************************************************************/
+/*             YM3812 local section                                                   */
+/*******************************************************************************/
+
+/* ---------- update one of chip ----------- */
+void YM3812UpdateOne(FM_OPL *OPL, UINT32 *buffer, int length)
+{
+    int i;
+       UINT32 *buf = buffer;
+       UINT32 amsCnt  = OPL->amsCnt;
+       UINT32 vibCnt  = OPL->vibCnt;
+       OPL_CH *CH,*R_CH;
+
+       if( (void *)OPL != cur_chip ){
+               cur_chip = (void *)OPL;
+               /* channel pointers */
+               S_CH = OPL->P_CH;
+               E_CH = &S_CH[6];
+               /* LFO state */
+               amsIncr = OPL->amsIncr;
+               vibIncr = OPL->vibIncr;
+               ams_table = OPL->ams_table;
+               vib_table = OPL->vib_table;
+       }
+       R_CH = E_CH;
+    for( i=0; i < length ; i++ )
+       {
+               /*            channel A         channel B         channel C      */
+               /* LFO */
+               ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
+               vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
+               outd[0] = 0;
+               /* FM part */
+               for(CH=S_CH ; CH < R_CH ; CH++)
+                       OPL_CALC_CH(CH);
+               /* limit check */
+               //data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
+               /* store to sound buffer */
+                {
+                 int32 d=outd[0]>>OPL_OUTSB;
+                 if(d<-32768) d=-32768;
+                 d+=32768;
+                 buf[i] += d;
+                }
+       }
+
+       OPL->amsCnt = amsCnt;
+       OPL->vibCnt = vibCnt;
+}
+
+/* ---------- reset one of chip ---------- */
+void OPLResetChip(FM_OPL *OPL)
+{
+       int c,s;
+       int i;
+
+       /* reset chip */
+       OPL->mode   = 0;        /* normal mode */
+
+       /* reset with register write */
+       OPLWriteReg(OPL,0x01,0); /* wabesel disable */
+       for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0);
+       /* reset OPerator paramater */
+       for( c = 0 ; c < OPL->max_ch ; c++ )
+       {
+               OPL_CH *CH = &OPL->P_CH[c];
+               /* OPL->P_CH[c].PAN = OPN_CENTER; */
+               for(s = 0 ; s < 2 ; s++ )
+               {
+                       /* wave table */
+                       CH->SLOT[s].wavetable = &SIN_TABLE[0];
+                       /* CH->SLOT[s].evm = ENV_MOD_RR; */
+                       CH->SLOT[s].evc = EG_OFF;
+                       CH->SLOT[s].eve = EG_OFF+1;
+                       CH->SLOT[s].evs = 0;
+               }
+       }
+}
+
+/* ----------  Create one of vietual YM3812 ----------       */
+/* 'rate'  is sampling rate and 'bufsiz' is the size of the  */
+FM_OPL *OPLCreate(int type, int clock, int rate)
+{
+       char *ptr;
+       FM_OPL *OPL;
+       int state_size;
+       int max_ch = 9; /* normaly 9 channels */
+
+       if( OPL_LockTable() ==-1) return NULL;
+       /* allocate OPL state space */
+       state_size  = sizeof(FM_OPL);
+       state_size += sizeof(OPL_CH)*max_ch;
+
+       /* allocate memory block */
+       ptr = malloc(state_size);
+       if(ptr==NULL) return NULL;
+       /* clear */
+       memset(ptr,0,state_size);
+       OPL        = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL);
+       OPL->P_CH  = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;
+
+       /* set channel state pointer */
+       OPL->type  = type;
+       OPL->clock = clock;
+       OPL->rate  = rate;
+       OPL->max_ch = max_ch;
+       /* init grobal tables */
+       OPL_initalize(OPL);
+       /* reset chip */
+       OPLResetChip(OPL);
+
+       return OPL;
+}
+
+/* ----------  Destroy one of vietual YM3812 ----------       */
+void OPLDestroy(FM_OPL *OPL)
+{
+       OPL_UnLockTable();
+       free(OPL);
+}
+
+/* ---------- YM3812 I/O interface ---------- */
+void OPLWrite(FM_OPL *OPL,UINT8 a,UINT8 v)
+{
+       OPLWriteReg(OPL,a,v);
+}
diff --git a/mappers/fmopl.h b/mappers/fmopl.h
new file mode 100644 (file)
index 0000000..f11a087
--- /dev/null
@@ -0,0 +1,149 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1999,2000 Tatsuyuki Satoh
+ *  Copyright (C) 2001,2002 Ben Parnell
+ *
+ * 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-1307  USA 
+ */
+/* This file has been heavily modified from the original(mostly unused
+   code was removed).  If you want to use it for anything other than
+   VRC7 sound emulation, you should get the original from the AdPlug
+   source distribution or the MAME(version 0.37b16) source distribution
+   (but be careful about the different licenses).
+        - Xodnizel
+*/
+
+#ifndef __FMOPL_H_
+#define __FMOPL_H_
+
+/* --- system optimize --- */
+/* select bit size of output : 8 or 16 */
+#define OPL_OUTPUT_BIT 16
+
+/* compiler dependence */
+#ifndef OSD_CPU_H
+#define OSD_CPU_H
+
+typedef unsigned char  UINT8;   /* unsigned  8bit */
+typedef unsigned short UINT16;  /* unsigned 16bit */
+typedef unsigned long  UINT32;  /* unsigned 32bit */
+typedef signed char            INT8;    /* signed  8bit   */
+typedef signed short   INT16;   /* signed 16bit   */
+typedef signed long            INT32;   /* signed 32bit   */
+#endif
+
+#if (OPL_OUTPUT_BIT==16)
+typedef INT16 OPLSAMPLE;
+#endif
+#if (OPL_OUTPUT_BIT==8)
+typedef unsigned char  OPLSAMPLE;
+#endif
+
+
+/* !!!!! here is private section , do not access there member direct !!!!! */
+
+#define OPL_TYPE_WAVESEL   0x01  /* waveform select    */
+
+/* Saving is necessary for member of the 'R' mark for suspend/resume */
+/* ---------- OPL one of slot  ---------- */
+typedef struct fm_opl_slot {
+       INT32 TL;               /* total level     :TL << 8            */
+       INT32 TLL;              /* adjusted now TL                     */
+       UINT8  KSR;             /* key scale rate  :(shift down bit)   */
+       INT32 *AR;              /* attack rate     :&AR_TABLE[AR<<2]   */
+       INT32 *DR;              /* decay rate      :&DR_TALBE[DR<<2]   */
+       INT32 SL;               /* sustin level    :SL_TALBE[SL]       */
+       INT32 *RR;              /* release rate    :&DR_TABLE[RR<<2]   */
+       UINT8 ksl;              /* keyscale level  :(shift down bits)  */
+       UINT8 ksr;              /* key scale rate  :kcode>>KSR         */
+       UINT32 mul;             /* multiple        :ML_TABLE[ML]       */
+       UINT32 Cnt;             /* frequency count :                   */
+       UINT32 Incr;    /* frequency step  :                   */
+       /* envelope generator state */
+       UINT8 eg_typ;   /* envelope type flag                  */
+       UINT8 evm;              /* envelope phase                      */
+       INT32 evc;              /* envelope counter                    */
+       INT32 eve;              /* envelope counter end point          */
+       INT32 evs;              /* envelope counter step               */
+       INT32 evsa;     /* envelope step for AR :AR[ksr]           */
+       INT32 evsd;     /* envelope step for DR :DR[ksr]           */
+       INT32 evsr;     /* envelope step for RR :RR[ksr]           */
+       /* LFO */
+       UINT8 ams;              /* ams flag                            */
+       UINT8 vib;              /* vibrate flag                        */
+       /* wave selector */
+       INT32 **wavetable;
+}OPL_SLOT;
+
+/* ---------- OPL one of channel  ---------- */
+typedef struct fm_opl_channel {
+       OPL_SLOT SLOT[2];
+       UINT8 CON;                      /* connection type                     */
+       UINT8 FB;                       /* feed back       :(shift down bit)   */
+       INT32 *connect1;        /* slot1 output pointer                */
+       INT32 *connect2;        /* slot2 output pointer                */
+       INT32 op1_out[2];       /* slot1 output for selfeedback        */
+       /* phase generator state */
+       UINT32  block_fnum;     /* block+fnum      :                   */
+       UINT8 kcode;            /* key code        : KeyScaleCode      */
+       UINT32  fc;                     /* Freq. Increment base                */
+       UINT32  ksl_base;       /* KeyScaleLevel Base step             */
+       UINT8 keyon;            /* key on/off flag                     */
+} OPL_CH;
+
+/* OPL state */
+typedef struct fm_opl_f {
+       UINT8 type;                     /* chip type                         */
+       int clock;                      /* master clock  (Hz)                */
+       int rate;                       /* sampling rate (Hz)                */
+       double freqbase;        /* frequency base                    */
+       double TimerBase;       /* Timer base time (==sampling time) */
+       UINT8 address;          /* address register                  */
+       UINT32 mode;            /* Reg.08 : CSM , notesel,etc.       */
+
+       /* FM channel slots */
+       OPL_CH *P_CH;           /* pointer of CH                     */
+       int     max_ch;                 /* maximum channel                   */
+
+       /* time tables */
+       INT32 AR_TABLE[75];     /* atttack rate tables */
+       INT32 DR_TABLE[75];     /* decay rate tables   */
+       UINT32 FN_TABLE[1024];  /* fnumber -> increment counter */
+       /* LFO */
+       INT32 *ams_table;
+       INT32 *vib_table;
+       INT32 amsCnt;
+       INT32 amsIncr;
+       INT32 vibCnt;
+       INT32 vibIncr;
+       /* wave selector enable flag */
+       UINT8 wavesel;
+
+} FM_OPL;
+
+/* ---------- Generic interface section ---------- */
+#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
+
+FM_OPL *OPLCreate(int type, int clock, int rate);
+void OPLDestroy(FM_OPL *OPL);
+
+void OPLResetChip(FM_OPL *OPL);
+void OPLWrite(FM_OPL *OPL,UINT8 a,UINT8 v);
+
+/* YM3626/YM3812 local section */
+void YM3812UpdateOne(FM_OPL *OPL, UINT32 *buffer, int length);
+
+#endif
diff --git a/mappers/mapinc.h b/mappers/mapinc.h
new file mode 100644 (file)
index 0000000..ebe446c
--- /dev/null
@@ -0,0 +1,12 @@
+#include        "../types.h"
+#include        "../x6502.h"
+#include        "../fce.h"
+#define INESPRIV
+#include        "../ines.h"
+#include        "../version.h"
+#include        "../memory.h"
+#include       "../sound.h"
+#include        "../svga.h"
+#include       "../state.h"
+#include       "../cart.h"
+#include       "mapshare.h"
diff --git a/mappers/mapshare.h b/mappers/mapshare.h
new file mode 100644 (file)
index 0000000..4853050
--- /dev/null
@@ -0,0 +1,5 @@
+void MMC3_hb(void);
+
+#define resetmode mapbyte1[0]
+#define MMC3_cmd mapbyte1[1]
+
diff --git a/mappers/mmc2and4.c b/mappers/mmc2and4.c
new file mode 100644 (file)
index 0000000..1688d57
--- /dev/null
@@ -0,0 +1,121 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define MMC4reg mapbyte1
+#define latcha1 mapbyte2[0]
+#define latcha2 mapbyte2[1]
+
+
+static void FP_FASTAPASS(1) latchcheck(uint32 VAddr)
+{
+     uint8 l,h;
+
+     h=VAddr>>8;
+
+     if(h>=0x20 || ((h&0xF)!=0xF)) 
+      return;
+
+     l=VAddr&0xF0;
+
+     if(h<0x10)
+     {
+      if(l==0xD0)
+      {
+       VROM_BANK4(0x0000,MMC4reg[0]);
+       latcha1=0xFD;
+      }
+      else if(l==0xE0)
+      {
+       VROM_BANK4(0x0000,MMC4reg[1]);
+       latcha1=0xFE;
+      }
+     }
+     else
+     {
+      if(l==0xD0)
+      {
+       VROM_BANK4(0x1000,MMC4reg[2]);
+       latcha2=0xFD;
+      }
+      else if(l==0xE0)
+      {
+       VROM_BANK4(0x1000,MMC4reg[3]);
+       latcha2=0xFE;
+      }
+     }
+}
+
+DECLFW(Mapper9_write)  // $Axxx
+{
+ ROM_BANK8(0x8000,V);
+}
+
+DECLFW(Mapper10_write)
+{
+ ROM_BANK16(0x8000,V);
+}
+
+DECLFW(Mapper9and10_write)
+{
+       switch(A&0xF000)
+       {
+        case 0xB000:
+                if (latcha1==0xFD) { VROM_BANK4(0x0000,V);}
+                MMC4reg[0]=V;
+                break;
+        case 0xC000:
+                if (latcha1==0xFE) {VROM_BANK4(0x0000,V);}
+                MMC4reg[1]=V;
+                break;
+        case 0xD000:
+                if (latcha2==0xFD) {VROM_BANK4(0x1000,V);}
+                MMC4reg[2]=V;
+                break;
+        case 0xE000:
+                if (latcha2==0xFE) {VROM_BANK4(0x1000,V);}
+                MMC4reg[3]=V;
+                break;
+        case 0xF000:
+                MIRROR_SET(V&1);
+                break;
+        }
+}
+
+void Mapper9_init(void)
+{
+        latcha1=0xFE;
+        latcha2=0xFE;
+        ROM_BANK8(0xA000,~2);
+        ROM_BANK8(0x8000,0);
+        SetWriteHandler(0xA000,0xAFFF,Mapper9_write);
+       SetWriteHandler(0xB000,0xFFFF,Mapper9and10_write);
+        PPU_hook=latchcheck;
+}
+
+void Mapper10_init(void)
+{
+        latcha1=latcha2=0xFE;
+        SetWriteHandler(0xA000,0xAFFF,Mapper10_write);
+       SetWriteHandler(0xB000,0xFFFF,Mapper9and10_write);
+        PPU_hook=latchcheck;
+}
+
diff --git a/mappers/simple.c b/mappers/simple.c
new file mode 100644 (file)
index 0000000..8f1ad74
--- /dev/null
@@ -0,0 +1,299 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 BERO
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+static uint8 latche;
+
+static DECLFW(Mapper2_write)
+{
+       latche=V;
+        ROM_BANK16(0x8000,V);
+}
+
+void Mapper2_init(void)
+{
+  SetWriteHandler(0x8000,0xFFFF,Mapper2_write);
+  AddExState(&latche, 1, 0, "LATC");
+}
+
+static DECLFW(Mapper3_write)
+{
+        VROM_BANK8(V);
+       latche=V;
+}
+
+void Mapper3_init(void)
+{
+       SetWriteHandler(0x8000,0xFFFF,Mapper3_write);
+       AddExState(&latche, 1, 0, "LATC");
+}
+
+DECLFW(Mapper7_write)
+{
+      ROM_BANK32(V&0xF);
+      onemir((V>>4)&1);
+      latche=V;
+}
+
+void Mapper7_init(void)
+{
+        onemir(0);
+        SetWriteHandler(0x8000,0xFFFF,Mapper7_write);
+       AddExState(&latche, 1, 0, "LATC");
+}
+
+DECLFW(Mapper11_write)
+{
+        ROM_BANK32(V);
+        VROM_BANK8(V>>4);
+       latche=V;
+}
+
+void Mapper11_init(void)
+{
+        ROM_BANK32(0);
+       SetWriteHandler(0x8000,0xFFFF,Mapper11_write);
+       AddExState(&latche, 1, 0, "LATC");
+}
+
+static DECLFW(Mapper13_write)
+{
+       setchr4r(0x10,0x1000,V&3);
+       setprg32(0x8000,(V>>4)&3);
+       latche=V;
+}
+
+static void Mapper13_StateRestore(int version)
+{
+       setchr4r(0x10,0x0000,0);
+        setchr4r(0x10,0x1000,latche&3);
+        setprg32(0x8000,(latche>>4)&3);
+}
+
+void Mapper13_init(void)
+{
+       SetWriteHandler(0x8000,0xFFFF,Mapper13_write);
+       GameStateRestore=Mapper13_StateRestore;
+       AddExState(&latche, 1, 0, "LATC");
+       AddExState(MapperExRAM, 16384, 0, "CHRR");
+       SetupCartCHRMapping(0x10, MapperExRAM, 16384, 1);
+
+       latche=0;
+        Mapper13_StateRestore(VERSION_NUMERIC);
+}
+
+DECLFW(Mapper34_write)
+{
+switch(A)
+ {
+ case 0x7FFD:ROM_BANK32(V);break;
+ case 0x7FFE:VROM_BANK4(0x0000,V);break;
+ case 0x7fff:VROM_BANK4(0x1000,V);break;
+ }
+if(A>=0x8000)
+ ROM_BANK32(V);
+}
+
+void Mapper34_init(void)
+{
+  SetWriteHandler(0x7ffd,0xffff,Mapper34_write);
+}
+
+DECLFW(Mapper66_write)
+{
+ VROM_BANK8(V&0xF);
+ ROM_BANK32((V>>4));
+ latche=V;
+}
+
+void Mapper66_init(void)
+{
+ ROM_BANK32(0);
+ SetWriteHandler(0x6000,0xffff,Mapper66_write);
+ AddExState(&latche, 1, 0, "LATC");
+}
+
+DECLFW(Mapper152_write)
+{
+ ROM_BANK16(0x8000,(V>>4)&0x7);
+ VROM_BANK8(V&0xF);
+ onemir((V>>7)&1);     /* Saint Seiya...hmm. */
+ latche=V;
+}
+
+void Mapper152_init(void)
+{
+ onemir(0);
+ SetWriteHandler(0x6000,0xffff,Mapper152_write);
+ AddExState(&latche, 1, 0, "LATC");
+}
+
+static DECLFW(Mapper70_write)
+{
+ ROM_BANK16(0x8000,V>>4);
+ VROM_BANK8(V&0xF);
+ latche=V;
+}
+
+void Mapper70_init(void)
+{
+ SetWriteHandler(0x6000,0xffff,Mapper70_write);
+ AddExState(&latche, 1, 0, "LATC");
+}
+/* Should be two separate emulation functions for this "mapper".  Sigh.  URGE TO KILL RISING. */
+static DECLFW(Mapper78_write)
+{
+ //printf("$%04x:$%02x\n",A,V);
+ ROM_BANK16(0x8000,V&0x7);
+ VROM_BANK8(V>>4);
+ onemir((V>>3)&1);
+ latche=V;
+}
+
+void Mapper78_init(void)
+{
+ SetWriteHandler(0x8000,0xffff,Mapper78_write);
+ AddExState(&latche, 1, 0, "LATC");
+}
+
+DECLFW(Mapper87_write)
+{
+ VROM_BANK8(V>>1);
+ latche=V;
+}
+
+void Mapper87_init(void)
+{
+ SetWriteHandler(0x6000,0xffff,Mapper87_write);
+ AddExState(&latche, 1, 0, "LATC");
+}
+
+DECLFW(Mapper93_write)
+{
+  ROM_BANK16(0x8000,V>>4);
+  MIRROR_SET(V&1);
+  latche=V;
+}
+
+void Mapper93_init(void)
+{
+  SetWriteHandler(0x8000,0xffff,Mapper93_write);
+  AddExState(&latche, 1, 0, "LATC");
+}
+
+
+DECLFW(Mapper94_write)
+{
+ ROM_BANK16(0x8000,V>>2);
+ latche=V;
+}
+
+void Mapper94_init(void)
+{
+  SetWriteHandler(0x8000,0xffff,Mapper94_write);
+  AddExState(&latche, 1, 0, "LATC");
+}
+
+/* I might want to add some code to the mapper 96 PPU hook function
+   to not change CHR banks if the attribute table is being accessed,
+   if I make emulation a little more accurate in the future.
+*/
+
+static uint8 M96LA;
+static DECLFW(Mapper96_write)
+{
+ latche=V;
+ setprg32(0x8000,V&3);
+ setchr4r(0x10,0x0000,(latche&4)|M96LA);
+ setchr4r(0x10,0x1000,(latche&4)|3);
+}
+
+static void FP_FASTAPASS(1) M96Hook(uint32 A)
+{
+ if(A<0x2000)
+  return;
+ M96LA=(A>>8)&3;
+ setchr4r(0x10,0x0000,(latche&4)|M96LA);
+}
+
+static void M96Sync()
+{
+ setprg32(0x8000,latche&3);
+ setchr4r(0x10,0x0000,(latche&4)|M96LA);
+ setchr4r(0x10,0x1000,(latche&4)|3);
+}
+
+void Mapper96_init(void)
+{
+ SetWriteHandler(0x8000,0xffff,Mapper96_write);
+ PPU_hook=M96Hook;
+ AddExState(&latche, 1, 0, "LATC");
+ AddExState(&M96LA, 1, 0, "LAVA");
+ SetupCartCHRMapping(0x10, MapperExRAM, 32768, 1);
+ latche=M96LA=0;
+ M96Sync();
+ GameStateRestore=M96Sync;
+}
+
+static DECLFW(Mapper140_write)
+{
+ VROM_BANK8(V&0xF);
+ ROM_BANK32((V>>4)&0xF);
+}
+
+void Mapper140_init(void)
+{
+ ROM_BANK32(0);
+ SetWriteHandler(0x6000,0x7FFF,Mapper140_write);
+}
+
+static void M185Sync()
+{
+ int x;
+
+ if(!(mapbyte1[0]&3))
+// if(!(mapbyte1[0]==0x21))
+ {
+  for(x=0;x<8;x++)
+   setchr1r(0x10,x<<10,0);
+  }
+ else
+  setchr8(0);
+}
+
+static DECLFW(Mapper185_write)
+{
+ mapbyte1[0]=V;
+ M185Sync();
+ // printf("Wr: $%04x:$%02x\n",A,V);
+}
+
+void Mapper185_init(void)
+{
+ memset(MapperExRAM,0xFF,1024);
+ MapStateRestore=M185Sync;
+ mapbyte1[0]=0;
+ M185Sync();
+
+ SetupCartCHRMapping(0x10,MapperExRAM,1024,0);
+ SetWriteHandler(0x8000,0xFFFF,Mapper185_write);
+}
diff --git a/mappers/vrc7snd.c b/mappers/vrc7snd.c
new file mode 100644 (file)
index 0000000..355143f
--- /dev/null
@@ -0,0 +1,190 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "mapinc.h"
+#include "fmopl.h"
+
+static void VRC7_LoadInstrument(uint8 Chan);
+void vrc7translate(uint8 Reg,uint8 V);
+
+FM_OPL *fmob=0;
+uint8 VRC7Chan[3][6];
+static void InitOPL(void);
+
+void OPL2_setreg(uint8 A, uint8 V)
+{
+ if(fmob) 
+  OPLWrite(fmob,A,V);
+}
+
+
+void LoadOPL(void)
+{
+ int x;
+ int y;
+
+ for(x=y=0;x<0x40;x++)
+  y|=MapperExRAM[x];
+ if(y)
+ { 
+  InitOPL(); 
+  for(x=0;x<6;x++)
+  {
+   VRC7_LoadInstrument(x); 
+   vrc7translate(0x10+x,VRC7Chan[0][x]);
+  }
+ }
+}
+
+static int dwave=0;
+
+void VRC7Update(void)
+{
+ int32 z,a;
+
+ z=((timestamp<<16)/soundtsinc)>>4;  
+ a=z-dwave;
+
+ if(a && fmob)
+  YM3812UpdateOne(fmob, &Wave[dwave], a);
+ dwave+=a;
+}
+
+void UpdateOPL(int Count)
+{
+ int32 z,a;
+
+ z=((timestamp<<16)/soundtsinc)>>4;
+ a=z-dwave;
+
+ if(fmob && a)
+  YM3812UpdateOne(fmob, &Wave[dwave], a);
+
+ dwave=0;
+}
+
+void KillOPL(void)
+{
+ if(fmob) OPLDestroy(fmob);
+ fmob=0;
+}
+
+static void InitOPL(void)
+{
+        int x;
+
+       if(!fmob)
+       {       
+         if(!( fmob=OPLCreate(OPL_TYPE_WAVESEL,1789772*2,FSettings.SndRate)))
+         return;
+       }
+       GameExpSound.Kill=KillOPL;
+        OPLResetChip(fmob);
+
+        for(x=0x1;x<0xF6;x++)
+         OPL2_setreg(x,0);
+        OPL2_setreg(0xBD,0xC0);
+        OPL2_setreg(1,0x20);      /* Enable waveform type manipulation */
+}
+
+/*     This following code is in the public domain, but the author, Quietust(see       */
+/*     the "AUTHORS" file, would appreciate credit to go to him if this code */
+/*     is used.                */
+
+uint8 VRC7Instrument[16][8] = {
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},      /* Custom instrument. */
+       {0x03,0x01,0x14,0x80,0xC2,0x90,0x43,0x14},      /* Currently working on this one */
+       {0x13,0x41,0x10,0x0B,0xFF,0xF2,0x32,0xD6},
+       {0x01,0x01,0x10,0x08,0xF0,0xF4,0x00,0x04},      /* 90% perfect */
+       {0x21,0x41,0x1B,0x08,0x66,0x80,0x30,0x85},
+       {0x22,0x21,0x20,0x03,0x75,0x70,0x24,0x14},
+       {0x02,0x01,0x06,0x00,0xF0,0xF2,0x03,0x95},      /* Do not touch! 98% perfect! */
+       {0x21,0x41,0x18,0x10,0x93,0xE0,0x21,0x15},
+       {0x01,0x22,0x13,0x00,0xF0,0x82,0x00,0x15},
+       {0x05,0x01,0x22,0x00,0x60,0xE3,0xA0,0xF5},      /* 90% perfect */
+       {0x85,0x01,0x20,0x00,0xD7,0xA2,0x22,0xF5},      /* 90% perfect */
+       {0x07,0x81,0x2B,0x05,0xF4,0xF2,0x14,0xF4},      /* 95% perfect */
+       {0x21,0x41,0x20,0x18,0xF3,0x80,0x13,0x95},
+       {0x01,0x02,0x20,0x00,0xF9,0x92,0x41,0x75},      /* Do not touch! 98% perfect! */
+       {0x21,0x62,0x0E,0x00,0x84,0x85,0x45,0x15},      /* 90% perfect */
+       {0x21,0x62,0x0E,0x00,0xA1,0xA0,0x34,0x16}       /* Do not touch! 98% perfect! */
+};
+
+static uint8 InstTrans[6] = {0x00,0x01,0x02,0x08,0x09,0x0A};
+
+static void VRC7_LoadInstrument(uint8 Chan)
+{
+       uint8 *i;
+       uint8 x = InstTrans[Chan];
+       uint8 y = (VRC7Chan[2][Chan] >> 4) & 0xF;
+       
+       i=VRC7Instrument[y];
+
+       OPL2_setreg((0x20+x),i[0]);
+       OPL2_setreg((0x23+x),i[1]);
+       OPL2_setreg((0x40+x),i[2]);
+       OPL2_setreg((0x43+x),((i[3] & 0xC0) 
+               | ((VRC7Chan[2][Chan] << 2) & 0x3C)));  // quiet
+       OPL2_setreg(0xe0+x,(i[3] >> 3) & 0x01);
+       OPL2_setreg(0xe3+x,(i[3] >> 4) & 0x01);
+       OPL2_setreg(0xC0+Chan,(i[3] << 1) & 0x0E);
+       OPL2_setreg(0x60+x,i[4]);
+       OPL2_setreg(0x63+x,i[5]);
+       OPL2_setreg(0x80+x,i[6]);
+       OPL2_setreg(0x83+x,i[7]);
+}
+
+void vrc7translate(uint8 Reg,uint8 V)
+{
+       uint8 x = Reg & 0x0F, y;
+        if(!fmob) InitOPL();
+
+       MapperExRAM[Reg]=V;
+
+       VRC7Update();
+       switch ((Reg & 0xF0) >> 4)
+       {
+        case 0:
+               if (x & 0x08) break;
+               VRC7Instrument[0][x] = V;
+               for (y = 0; y < 6; y++)
+                if (!(VRC7Chan[2][y]&0xF0))
+                 VRC7_LoadInstrument(y);
+               break;
+        case 1:
+               if(x>5) break;
+               VRC7Chan[0][x] = V;
+               OPL2_setreg(0xA0 + x,(VRC7Chan[0][x] << 1) & 0xFE);
+               OPL2_setreg(0xB0 + x,((VRC7Chan[0][x] >> 7) & 0x01) | ((VRC7Chan[1][x] << 1) & 0x3E));
+               break;
+        case 2:
+               if(x>5) break;
+               VRC7Chan[1][x] = V;
+               OPL2_setreg(0xB0 + x,(((VRC7Chan[0][x] >> 7) & 0x01) | ((VRC7Chan[1][x] << 1) & 0x3E)));
+               break;
+        case 3:
+               if(x>5) break;
+               VRC7Chan[2][x] = V;
+               VRC7_LoadInstrument(x);
+               break;
+       }
+}
diff --git a/mbshare/Makefile b/mbshare/Makefile
new file mode 100644 (file)
index 0000000..3508da1
--- /dev/null
@@ -0,0 +1,5 @@
+MUSOBJS   =       mbshare/mmc5.o mbshare/mmc3.o mbshare/mmc1.o
+
+mbshare/mmc1.o:                mbshare/mmc1.c
+mbshare/mmc3.o:         mbshare/mmc3.c
+mbshare/mmc5.o:         mbshare/mmc5.c
diff --git a/mbshare/mapinc.h b/mbshare/mapinc.h
new file mode 100644 (file)
index 0000000..9702ec2
--- /dev/null
@@ -0,0 +1,14 @@
+#include        "../types.h"
+#include        "../x6502.h"
+#include        "../fce.h"
+#define INESPRIV
+#include        "../ines.h"
+#include        "../version.h"
+#include        "../memory.h"
+#include       "../sound.h"
+#include       "../svga.h"
+#include       "../state.h"
+#define UNIFPRIV
+#include       "../unif.h"
+#include       "../cart.h"
+#include       "../cheat.h"
diff --git a/mbshare/mmc1.c b/mbshare/mmc1.c
new file mode 100644 (file)
index 0000000..8b238d7
--- /dev/null
@@ -0,0 +1,353 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 BERO
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "mapinc.h"
+
+#define MMC1_reg mapbyte1
+#define MMC1_buf mapbyte2[0]
+#define MMC1_sft mapbyte3[0]
+
+static int mmc1opts;
+
+
+uint8 MMC1WRAMsize;    /* For use in iNES.c */
+
+static DECLFW(MBWRAM)
+{
+ if(!(MMC1_reg[3]&0x10))
+  Page[A>>11][A]=V;     // WRAM is enabled.
+}
+
+static DECLFR(MAWRAM)
+{
+ if(MMC1_reg[3]&0x10)   
+  return X.DB;          // WRAM is disabled
+ return(Page[A>>11][A]);
+}
+
+static void MMC1CHR(void)
+{
+    if(mmc1opts&4)
+    {
+     if(MMC1_reg[0]&0x10)
+      setprg8r(0x10,0x6000,(MMC1_reg[1]>>4)&1);
+     else
+      setprg8r(0x10,0x6000,(MMC1_reg[1]>>3)&1);
+    }
+
+    if(MMC1_reg[0]&0x10)
+    {
+     setchr4(0x0000,MMC1_reg[1]);
+     setchr4(0x1000,MMC1_reg[2]);
+    }
+    else
+     setchr8(MMC1_reg[1]>>1);
+}
+
+static void MMC1PRG(void)
+{
+        uint8 offs;
+
+        offs=MMC1_reg[1]&0x10;
+        switch(MMC1_reg[0]&0xC)
+        {
+          case 0xC: setprg16(0x8000,(MMC1_reg[3]+offs));
+                    setprg16(0xC000,0xF+offs);
+                    break;
+          case 0x8: setprg16(0xC000,(MMC1_reg[3]+offs));
+                    setprg16(0x8000,offs);
+                    break;
+          case 0x0:
+          case 0x4:
+                    setprg16(0x8000,((MMC1_reg[3]&~1)+offs));
+                    setprg16(0xc000,((MMC1_reg[3]&~1)+offs+1));
+                    break;
+        }
+}
+static void MMC1MIRROR(void)
+{
+                switch(MMC1_reg[0]&3)
+                {
+                 case 2: setmirror(MI_V);break;
+                 case 3: setmirror(MI_H);break;
+                 case 0: setmirror(MI_0);break;
+                 case 1: setmirror(MI_1);break;
+                }
+}
+
+static uint64 lreset;
+
+static DECLFW(MMC1_write)
+{
+        int n=(A>>13)-4;
+       //FCEU_DispMessage("%016x",timestampbase+timestamp);
+       //printf("$%04x:$%02x, $%04x\n",A,V,X.PC);
+       //DumpMem("out",0xe000,0xffff);
+
+       /* The MMC1 is busy so ignore the write. */
+       /* As of version FCE Ultra 0.81, the timestamp is only
+          increased before each instruction is executed(in other words
+          precision isn't that great), but this should still work to
+          deal with 2 writes in a row from a single RMW instruction.
+       */
+       if( (timestampbase+timestamp)<(lreset+2))
+        return;
+        if (V&0x80)
+        {
+        MMC1_reg[0]|=0xC;
+         MMC1_sft=MMC1_buf=0;
+        MMC1PRG();
+        lreset=timestampbase+timestamp;
+         return;
+        }
+
+        MMC1_buf|=(V&1)<<(MMC1_sft++);
+
+  if (MMC1_sft==5) {
+        MMC1_reg[n]=MMC1_buf;
+        MMC1_sft = MMC1_buf=0;
+
+        switch(n){
+        case 0:
+               MMC1MIRROR();
+                MMC1CHR();
+                MMC1PRG();
+                break;
+        case 1:
+                MMC1CHR();
+                MMC1PRG();
+                break;
+        case 2:
+                MMC1CHR();
+                break;
+        case 3:
+                MMC1PRG();
+                break;
+        }
+  }
+}
+
+static void MMC1_Restore(int version)
+{
+ MMC1MIRROR();
+ MMC1CHR();
+ MMC1PRG();
+}
+
+static void MMC1CMReset(void)
+{
+        int i;
+
+        for(i=0;i<4;i++)
+         MMC1_reg[i]=0;
+        MMC1_sft = MMC1_buf =0;
+        MMC1_reg[0]=0x1F;
+
+        MMC1_reg[1]=0;
+        MMC1_reg[2]=0;                  // Should this be something other than 0?
+        MMC1_reg[3]=0;
+
+        MMC1MIRROR();
+        MMC1CHR();
+        MMC1PRG();
+}
+
+void DetectMMC1WRAMSize(void)
+{
+        switch(iNESGameCRC32)
+        {
+         default:MMC1WRAMsize=1;break;
+        case 0xc6182024:       /* Romance of the 3 Kingdoms */
+         case 0x2225c20f:       /* Genghis Khan */
+         case 0x4642dda6:       /* Nobunaga's Ambition */
+        case 0x29449ba9:       /* ""   "" (J) */
+        case 0x2b11e0b0:       /* ""   "" (J) */
+                MMC1WRAMsize=2;
+                break;
+        }
+}
+
+void Mapper1_init(void)
+{
+       lreset=0;
+       mmc1opts=0;
+        MMC1CMReset();        
+       SetWriteHandler(0x8000,0xFFFF,MMC1_write);
+       MapStateRestore=MMC1_Restore;
+       AddExState(&lreset, 8, 1, "LRST");
+
+       if(!VROM_size)
+        SetupCartCHRMapping(0, CHRRAM, 8192, 1);
+
+       if(MMC1WRAMsize==2)
+        mmc1opts|=4;
+
+       SetupCartPRGMapping(0x10,WRAM,MMC1WRAMsize*8192,1);
+       SetReadHandler(0x6000,0x7FFF,MAWRAM);
+       SetWriteHandler(0x6000,0x7FFF,MBWRAM);
+       setprg8r(0x10,0x6000,0);
+}
+
+static void GenMMC1Close(void)
+{
+ UNIFOpenWRAM(UOW_WR,0,0);
+ UNIFWriteWRAM(WRAM+((mmc1opts&4)?8192:0),8192);
+ UNIFCloseWRAM();
+}
+
+
+static void GenMMC1Power(void)
+{
+ lreset=0;
+ if(mmc1opts&1)
+ {
+  FCEU_CheatAddRAM(8,0x6000,WRAM);
+  if(mmc1opts&4)
+   FCEU_dwmemset(WRAM,0,8192)
+  else if(!(mmc1opts&2))
+   FCEU_dwmemset(WRAM,0,8192);
+ }
+ SetWriteHandler(0x8000,0xFFFF,MMC1_write);
+ SetReadHandler(0x8000,0xFFFF,CartBR);
+
+ if(mmc1opts&1)
+ {
+  SetReadHandler(0x6000,0x7FFF,MAWRAM);
+  SetWriteHandler(0x6000,0x7FFF,MBWRAM);
+  setprg8r(0x10,0x6000,0);
+ }
+
+ MMC1CMReset();
+}
+
+static void GenMMC1Init(int prg, int chr, int wram, int battery)
+{
+ mmc1opts=0;
+ PRGmask16[0]&=(prg>>14)-1;
+ CHRmask4[0]&=(chr>>12)-1;
+ CHRmask8[0]&=(chr>>13)-1;
+
+ if(wram) 
+ { 
+  mmc1opts|=1;
+  if(wram>8) mmc1opts|=4;
+  SetupCartPRGMapping(0x10,WRAM,wram*1024,1);
+  AddExState(WRAM, wram*1024, 0, "WRAM");
+ }
+
+ if(battery && UNIFbattery)
+ {
+  mmc1opts|=2;
+  BoardClose=GenMMC1Close;
+
+  UNIFOpenWRAM(UOW_RD,0,0);
+  UNIFReadWRAM(WRAM+((mmc1opts&4)?8192:0),8192);
+  UNIFCloseWRAM();
+ }
+
+ if(!chr)
+ {
+  CHRmask4[0]=1;
+  SetupCartCHRMapping(0, CHRRAM, 8192, 1);
+  AddExState(CHRRAM, 8192, 0, "CHRR");
+ }
+ AddExState(mapbyte1, 32, 0, "MPBY");
+ BoardPower=GenMMC1Power;
+
+ GameStateRestore=MMC1_Restore;
+ AddExState(&lreset, 8, 1, "LRST");
+}
+
+//static void GenMMC1Init(int prg, int chr, int wram, int battery)
+void SAROM_Init(void)
+{
+ GenMMC1Init(128, 64, 8, 1); 
+}
+
+void SBROM_Init(void)
+{
+ GenMMC1Init(128, 64, 0, 0);
+}
+
+void SCROM_Init(void)  
+{
+ GenMMC1Init(128, 128, 0, 0);
+}
+
+void SEROM_Init(void)
+{
+ GenMMC1Init(32, 64, 0, 0);
+}
+
+void SGROM_Init(void)
+{
+ GenMMC1Init(256, 0, 0, 0);
+}
+
+void SKROM_Init(void)
+{
+ GenMMC1Init(256, 64, 8, 1);
+}
+
+void SLROM_Init(void)
+{
+ GenMMC1Init(256, 128, 0, 0);
+}
+
+void SL1ROM_Init(void)
+{
+ GenMMC1Init(128, 128, 0, 0);
+}
+
+/* Begin unknown - may be wrong - perhaps they use different MMC1s from the
+   similarly functioning boards?
+*/
+
+void SL2ROM_Init(void)
+{
+ GenMMC1Init(256, 256, 0, 0);
+}
+
+void SFROM_Init(void)
+{
+ GenMMC1Init(256, 256, 0, 0);
+}
+
+void SHROM_Init(void)
+{
+ GenMMC1Init(256, 256, 0, 0);
+}
+
+/* End unknown  */
+/*              */
+/*              */
+
+void SNROM_Init(void)
+{
+ GenMMC1Init(256, 0, 8, 1);
+}
+
+void SOROM_Init(void)
+{
+ GenMMC1Init(256, 0, 16, 1);
+}
+
+
diff --git a/mbshare/mmc3.c b/mbshare/mmc3.c
new file mode 100644 (file)
index 0000000..e1e55c8
--- /dev/null
@@ -0,0 +1,649 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 BERO
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+/*  Code for emulating iNES mappers 4, 118,119 */
+
+#include "mapinc.h"
+
+#define resetmode mapbyte1[0]
+#define MMC3_cmd mapbyte1[1]
+#define A000B mapbyte1[2]
+#define A001B mapbyte1[3]
+#define DRegBuf mapbyte4
+
+#define PPUCHRBus mapbyte2[0]
+#define TKSMIR mapbyte3
+#define PIRREGS        mapbyte2
+
+static void (*pwrap)(uint32 A, uint8 V);
+static void (*cwrap)(uint32 A, uint8 V);
+static void (*mwrap)(uint8 V);
+
+static int mmc3opts=0;
+
+static INLINE void FixMMC3PRG(int V);
+static INLINE void FixMMC3CHR(int V);
+
+static int latched;
+
+static DECLFW(MMC3_IRQWrite)
+{
+       //printf("$%04x:$%02x, %d\n",A,V,scanline);
+        switch(A&0xE001)
+        {
+         case 0xc000:IRQLatch=V;
+                    latched=1;
+                    if(resetmode)
+                    {
+                     IRQCount=V;
+                     latched=0;
+                     //resetmode=0;
+                    }
+                     break;
+         case 0xc001:IRQCount=IRQLatch;
+                     break;
+         case 0xE000:IRQa=0;
+                    X6502_IRQEnd(FCEU_IQEXT);
+                    resetmode=1;
+                     break;
+         case 0xE001:IRQa=1;
+                    if(latched) 
+                     IRQCount=IRQLatch;
+                     break;
+        }
+}
+
+static INLINE void FixMMC3PRG(int V)
+{
+          if(V&0x40)
+          {
+           pwrap(0xC000,DRegBuf[6]);
+           pwrap(0x8000,~1);
+          }
+          else
+          {
+           pwrap(0x8000,DRegBuf[6]);
+           pwrap(0xC000,~1);
+          }
+         pwrap(0xA000,DRegBuf[7]);
+         pwrap(0xE000,~0);
+}
+
+static INLINE void FixMMC3CHR(int V)
+{
+           int cbase=(V&0x80)<<5;
+           cwrap((cbase^0x000),DRegBuf[0]&(~1));
+           cwrap((cbase^0x400),DRegBuf[0]|1);
+           cwrap((cbase^0x800),DRegBuf[1]&(~1));
+           cwrap((cbase^0xC00),DRegBuf[1]|1);
+
+           cwrap(cbase^0x1000,DRegBuf[2]);
+           cwrap(cbase^0x1400,DRegBuf[3]);
+           cwrap(cbase^0x1800,DRegBuf[4]);
+           cwrap(cbase^0x1c00,DRegBuf[5]);
+}
+
+static void MMC3RegReset(void)
+{
+ IRQCount=IRQLatch=IRQa=MMC3_cmd=0;
+
+ DRegBuf[0]=0;
+ DRegBuf[1]=2;
+ DRegBuf[2]=4;
+ DRegBuf[3]=5;
+ DRegBuf[4]=6;
+ DRegBuf[5]=7;
+ DRegBuf[6]=0;
+ DRegBuf[7]=1;
+
+ FixMMC3PRG(0);
+ FixMMC3CHR(0);
+}
+
+static DECLFW(Mapper4_write)
+{
+        switch(A&0xE001)
+       {
+         case 0x8000:
+          if((V&0x40) != (MMC3_cmd&0x40))
+          FixMMC3PRG(V);
+          if((V&0x80) != (MMC3_cmd&0x80))
+           FixMMC3CHR(V);
+          MMC3_cmd = V;
+          break;
+
+        case 0x8001:
+                {
+                 int cbase=(MMC3_cmd&0x80)<<5;
+                 DRegBuf[MMC3_cmd&0x7]=V;
+                 switch(MMC3_cmd&0x07)
+                 {
+                  case 0: cwrap((cbase^0x000),V&(~1));
+                         cwrap((cbase^0x400),V|1);
+                         break;
+                  case 1: cwrap((cbase^0x800),V&(~1));
+                         cwrap((cbase^0xC00),V|1);
+                         break;
+                  case 2: cwrap(cbase^0x1000,V); break;
+                  case 3: cwrap(cbase^0x1400,V); break;
+                  case 4: cwrap(cbase^0x1800,V); break;
+                  case 5: cwrap(cbase^0x1C00,V); break;
+                  case 6: if (MMC3_cmd&0x40) pwrap(0xC000,V);
+                          else pwrap(0x8000,V);
+                          break;
+                  case 7: pwrap(0xA000,V);
+                          break;
+                 }
+                }
+                break;
+
+        case 0xA000:
+               if(mwrap) mwrap(V&1);
+                break;
+       case 0xA001:
+               A001B=V;
+               break;
+ }
+}
+
+static void MMC3_hb(void)
+{
+      resetmode=0;
+      if(IRQCount>=0)
+      {
+        IRQCount--;
+        if(IRQCount<0)
+        {
+        //printf("IRQ: %d\n",scanline);
+         if(IRQa)
+         X6502_IRQBegin(FCEU_IQEXT);
+        }
+      }
+}
+static int isines;
+
+static void genmmc3restore(int version)
+{
+ if(version>=56)
+ {
+  mwrap(A000B&1);
+  FixMMC3PRG(MMC3_cmd);
+  FixMMC3CHR(MMC3_cmd);
+ }
+ else if(isines)
+  iNESStateRestore(version);
+}
+
+static void GENCWRAP(uint32 A, uint8 V)
+{
+ setchr1(A,V);
+}
+
+static void GENPWRAP(uint32 A, uint8 V)
+{
+ setprg8(A,V&0x3F);
+}
+
+static void GENMWRAP(uint8 V)
+{
+ A000B=V;
+ setmirror(V^1);
+}
+
+static void GENNOMWRAP(uint8 V)
+{
+ A000B=V;
+}
+
+static void genmmc3ii(void (*PW)(uint32 A, uint8 V), 
+                     void (*CW)(uint32 A, uint8 V), 
+                     void (*MW)(uint8 V))
+{
+ pwrap=GENPWRAP;
+ cwrap=GENCWRAP;
+ mwrap=GENMWRAP;
+ if(PW) pwrap=PW;
+ if(CW) cwrap=CW;
+ if(MW) mwrap=MW;
+ A000B=(Mirroring&1)^1; // For hard-wired mirroring on some MMC3 games.
+                        // iNES format needs to die or be extended...
+ mmc3opts=0;
+ SetWriteHandler(0x8000,0xBFFF,Mapper4_write);
+ SetWriteHandler(0xC000,0xFFFF,MMC3_IRQWrite);
+
+ GameHBIRQHook=MMC3_hb;
+ GameStateRestore=genmmc3restore;
+ if(!VROM_size)
+  SetupCartCHRMapping(0, CHRRAM, 8192, 1);
+ isines=1;
+ MMC3RegReset();
+ MapperReset=MMC3RegReset;
+}
+
+void Mapper4_init(void)
+{
+ genmmc3ii(0,0,0);
+}
+
+static void M47PW(uint32 A, uint8 V)
+{
+ V&=0xF;
+ V|=PIRREGS[0]<<4;
+ setprg8(A,V);
+}
+
+static void M47CW(uint32 A, uint8 V)
+{
+ uint32 NV=V;
+ NV&=0x7F;
+ NV|=PIRREGS[0]<<7;
+ setchr1(A,NV);
+}
+
+static DECLFW(M47Write)
+{
+ PIRREGS[0]=V&1;
+ FixMMC3PRG(MMC3_cmd);
+ FixMMC3CHR(MMC3_cmd); 
+}
+
+void Mapper47_init(void)
+{
+ genmmc3ii(M47PW,M47CW,0);
+ SetWriteHandler(0x6000,0x7FFF,M47Write);
+ SetReadHandler(0x6000,0x7FFF,0);
+}
+
+static void M44PW(uint32 A, uint8 V)
+{
+ uint32 NV=V;
+ if(PIRREGS[0]>=6) NV&=0x1F;
+ else NV&=0x0F;
+ NV|=PIRREGS[0]<<4;
+ setprg8(A,NV);
+}
+static void M44CW(uint32 A, uint8 V)
+{
+ uint32 NV=V;
+ if(PIRREGS[0]<6) NV&=0x7F;
+ NV|=PIRREGS[0]<<7;
+ setchr1(A,NV);
+}
+
+static DECLFW(Mapper44_write)
+{
+ if(A&1)
+ {
+  PIRREGS[0]=V&7;
+  FixMMC3PRG(MMC3_cmd);
+  FixMMC3CHR(MMC3_cmd);
+ }
+ else
+  Mapper4_write(A,V);
+}
+
+void Mapper44_init(void)
+{
+ genmmc3ii(M44PW,M44CW,0);
+ SetWriteHandler(0xA000,0xBFFF,Mapper44_write);
+}
+
+static void M52PW(uint32 A, uint8 V)
+{
+ uint32 NV=V;
+ NV&=0x1F^((PIRREGS[0]&8)<<1);
+ NV|=((PIRREGS[0]&6)|((PIRREGS[0]>>3)&PIRREGS[0]&1))<<4;
+ setprg8(A,NV);
+}
+
+static void M52CW(uint32 A, uint8 V)
+{
+ uint32 NV=V;
+ NV&=0xFF^((PIRREGS[0]&0x40)<<1);
+ NV|=(((PIRREGS[0]>>3)&4)|((PIRREGS[0]>>1)&2)|((PIRREGS[0]>>6)&(PIRREGS[0]>>4)&1))<<7;
+ setchr1(A,NV);
+}
+
+static DECLFW(Mapper52_write)
+{
+ if(PIRREGS[1]) 
+ {
+  (WRAM-0x6000)[A]=V;
+  return;
+ }
+ PIRREGS[1]=1;
+ PIRREGS[0]=V;
+ FixMMC3PRG(MMC3_cmd);
+ FixMMC3CHR(MMC3_cmd);
+}
+
+static void M52Reset(void)
+{
+ PIRREGS[0]=PIRREGS[1]=0;
+ MMC3RegReset(); 
+}
+
+void Mapper52_init(void)
+{
+ genmmc3ii(M52PW,M52CW,0);
+ SetWriteHandler(0x6000,0x7FFF,Mapper52_write);
+ MapperReset=M52Reset;
+}
+
+static void M45CW(uint32 A, uint8 V)
+{
+ uint32 NV=V;
+ if(PIRREGS[2]&8)
+  NV&=(1<<( (PIRREGS[2]&7)+1 ))-1;
+ else
+  NV&=0;
+ NV|=PIRREGS[0]|((PIRREGS[2]&0x10)<<4);
+ setchr1(A,NV);
+}
+
+static void M45PW(uint32 A, uint8 V)
+{
+ V&=(PIRREGS[3]&0x3F)^0x3F;
+ V|=PIRREGS[1];
+ setprg8(A,V);
+}
+
+static DECLFW(Mapper45_write)
+{
+ if(PIRREGS[3]&0x40) return;
+ PIRREGS[PIRREGS[4]]=V;
+ PIRREGS[4]=(PIRREGS[4]+1)&3;
+ FixMMC3PRG(MMC3_cmd);
+ FixMMC3CHR(MMC3_cmd);
+}
+
+static void M45Reset(void)
+{
+ FCEU_dwmemset(PIRREGS,0,5);
+ MMC3RegReset();
+}
+
+void Mapper45_init(void)
+{
+ genmmc3ii(M45PW,M45CW,0);
+ SetWriteHandler(0x6000,0x7FFF,Mapper45_write);
+ SetReadHandler(0x6000,0x7FFF,0);
+ MapperReset=M45Reset;
+}
+static void M49PW(uint32 A, uint8 V)
+{
+ if(PIRREGS[0]&1)
+ {
+  V&=0xF;
+  V|=(PIRREGS[0]&0xC0)>>2;
+  setprg8(A,V);
+ }
+ else
+  setprg32(0x8000,(PIRREGS[0]>>4)&3);
+}
+
+static void M49CW(uint32 A, uint8 V)
+{
+ uint32 NV=V;
+ NV&=0x7F;
+ NV|=(PIRREGS[0]&0xC0)<<1;
+ setchr1(A,NV);
+}
+
+static DECLFW(M49Write)
+{
+ //printf("$%04x:$%02x\n",A,V);
+ if(A001B&0x80)
+ {
+  PIRREGS[0]=V;
+  FixMMC3PRG(MMC3_cmd);
+  FixMMC3CHR(MMC3_cmd);
+ }
+}
+
+static void M49Reset(void)
+{
+ PIRREGS[0]=0;
+ MMC3RegReset();
+}
+
+void Mapper49_init(void)
+{
+ genmmc3ii(M49PW,M49CW,0);
+ SetWriteHandler(0x6000,0x7FFF,M49Write);
+ SetReadHandler(0x6000,0x7FFF,0);
+ MapperReset=M49Reset;
+}
+
+static DECLFW(Mapper250_write)
+{
+       Mapper4_write((A&0xE000)|((A&0x400)>>10),A&0xFF);
+}
+
+static DECLFW(M250_IRQWrite)
+{
+       MMC3_IRQWrite((A&0xE000)|((A&0x400)>>10),A&0xFF);
+}
+
+void Mapper250_init(void)
+{
+ genmmc3ii(0,0,0);
+ SetWriteHandler(0x8000,0xBFFF,Mapper250_write);
+ SetWriteHandler(0xC000,0xFFFF,M250_IRQWrite);
+}
+
+static void FP_FASTAPASS(1) TKSPPU(uint32 A)
+{
+ //static uint8 z;
+ //if(A>=0x2000 || type<0) return;
+ //if(type<0) return;
+ A&=0x1FFF;
+ //if(scanline>=140 && scanline<=200) {setmirror(MI_1);return;}
+ //if(scanline>=140 && scanline<=200)
+ // if(scanline>=190 && scanline<=200) {setmirror(MI_1);return;}
+ // setmirror(MI_1); 
+ //printf("$%04x\n",A);
+
+ A>>=10;
+ PPUCHRBus=A;
+ setmirror(MI_0+TKSMIR[A]);
+}
+
+static void TKSWRAP(uint32 A, uint8 V)
+{
+ TKSMIR[A>>10]=V>>7;
+ setchr1(A,V&0x7F);
+ if(PPUCHRBus==(A>>10))
+  setmirror(MI_0+(V>>7));
+}
+
+void Mapper118_init(void)
+{
+  genmmc3ii(0,TKSWRAP,GENNOMWRAP);
+  PPU_hook=TKSPPU;
+}
+
+static void TQWRAP(uint32 A, uint8 V)
+{
+ setchr1r((V&0x40)>>2,A,V&0x3F);
+}
+
+void Mapper119_init(void)
+{
+  genmmc3ii(0,TQWRAP,0);
+  SetupCartCHRMapping(0x10, CHRRAM, 8192, 1);
+}
+
+static int wrams;
+
+static void GenMMC3Close(void)
+{
+ UNIFOpenWRAM(UOW_WR,0,1);
+ UNIFWriteWRAM(WRAM,wrams);
+ UNIFCloseWRAM();
+}
+
+static DECLFW(MBWRAM)
+{
+  (WRAM-0x6000)[A]=V;
+}
+
+static DECLFR(MAWRAM)
+{
+ return((WRAM-0x6000)[A]);
+}
+
+static DECLFW(MBWRAMMMC6)
+{
+ WRAM[A&0x3ff]=V;
+}
+
+static DECLFR(MAWRAMMMC6)
+{
+ return(WRAM[A&0x3ff]);
+}
+
+static void GenMMC3Power(void)
+{
+ SetWriteHandler(0x8000,0xBFFF,Mapper4_write);
+ SetReadHandler(0x8000,0xFFFF,CartBR);
+ SetWriteHandler(0xC000,0xFFFF,MMC3_IRQWrite);
+
+ if(mmc3opts&1)
+ {
+  if(wrams==1024)
+  {
+   FCEU_CheatAddRAM(1,0x7000,WRAM);
+   SetReadHandler(0x7000,0x7FFF,MAWRAMMMC6);
+   SetWriteHandler(0x7000,0x7FFF,MBWRAMMMC6);
+  }
+  else
+  {
+   FCEU_CheatAddRAM(wrams/1024,0x6000,WRAM);
+   SetReadHandler(0x6000,0x6000+wrams-1,MAWRAM);
+   SetWriteHandler(0x6000,0x6000+wrams-1,MBWRAM);
+  }
+  if(!(mmc3opts&2))
+   FCEU_dwmemset(WRAM,0,wrams);
+ }
+ MMC3RegReset();
+}
+
+void GenMMC3_Init(int prg, int chr, int wram, int battery)
+{
+ pwrap=GENPWRAP;
+ cwrap=GENCWRAP;
+ mwrap=GENMWRAP;
+
+ wrams=wram*1024;
+
+ PRGmask8[0]&=(prg>>13)-1;
+ CHRmask1[0]&=(chr>>10)-1;
+ CHRmask2[0]&=(chr>>11)-1;
+
+ if(wram)
+ {
+  mmc3opts|=1;
+  AddExState(WRAM, wram*1024, 0, "WRAM");
+ }
+
+ if(battery)
+ {
+  mmc3opts|=2;
+  BoardClose=GenMMC3Close;
+
+  UNIFOpenWRAM(UOW_RD,0,1);
+  UNIFReadWRAM(WRAM,wram*1024);
+  UNIFCloseWRAM();
+ }
+
+ if(!chr)
+ {
+  CHRmask1[0]=7;
+  CHRmask2[0]=3;
+  SetupCartCHRMapping(0, CHRRAM, 8192, 1);
+  AddExState(CHRRAM, 8192, 0, "CHRR");
+ }
+ AddExState(mapbyte1, 32, 0, "MPBY");
+ AddExState(&IRQa, 1, 0, "IRQA");
+ AddExState(&IRQCount, 4, 1, "IRQC");
+ AddExState(&IRQLatch, 4, 1, "IQL1");
+
+ BoardPower=GenMMC3Power;
+ BoardReset=MMC3RegReset;
+
+ GameHBIRQHook=MMC3_hb;
+ GameStateRestore=genmmc3restore;
+ isines=0;
+}
+
+// void GenMMC3_Init(int prg, int chr, int wram, int battery)
+
+void TFROM_Init(void)
+{
+ GenMMC3_Init(512, 64, 0, 0);
+}
+
+void TGROM_Init(void)
+{
+ GenMMC3_Init(512, 0, 0, 0);
+}
+
+void TKROM_Init(void)
+{
+ GenMMC3_Init(512, 256, 8, 1);
+}
+
+void TLROM_Init(void)
+{
+ GenMMC3_Init(512, 256, 0, 0);
+}
+
+void TSROM_Init(void)
+{
+ GenMMC3_Init(512, 256, 8, 0);
+}
+
+void TLSROM_Init(void)
+{
+ GenMMC3_Init(512, 256, 8, 0);
+ cwrap=TKSWRAP;
+ mwrap=GENNOMWRAP;
+}
+
+void TKSROM_Init(void)
+{
+ GenMMC3_Init(512, 256, 8, 1);
+ cwrap=TKSWRAP;
+ mwrap=GENNOMWRAP;
+}
+
+void TQROM_Init(void)
+{
+ GenMMC3_Init(512, 64, 0, 0);
+ cwrap=TQWRAP;
+}
+
+/* MMC6 board */
+void HKROM_Init(void)
+{
+ GenMMC3_Init(512, 512, 1, 1);
+}
diff --git a/mbshare/mmc5.c b/mbshare/mmc5.c
new file mode 100644 (file)
index 0000000..bb3e8f1
--- /dev/null
@@ -0,0 +1,758 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+/* None of this code should use any of the iNES bank switching wrappers. */
+
+#include "mapinc.h"
+
+void MMC5Sound(int Count);
+void Do5SQ(int P);
+
+static INLINE void MMC5SPRVROM_BANK1(uint32 A,uint32 V) 
+{
+ if(CHRptr[0])
+ {
+  V&=CHRmask1[0];
+  MMC5SPRVPage[(A)>>10]=&CHRptr[0][(V)<<10]-(A);
+ }
+}
+
+static INLINE void MMC5BGVROM_BANK1(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask1[0];MMC5BGVPage[(A)>>10]=&CHRptr[0][(V)<<10]-(A);}}
+
+static INLINE void MMC5SPRVROM_BANK2(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask2[0];MMC5SPRVPage[(A)>>10]=MMC5SPRVPage[((A)>>10)+1]=&CHRptr[0][(V)<<11]-(A);}}
+static INLINE void MMC5BGVROM_BANK2(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask2[0];MMC5BGVPage[(A)>>10]=MMC5BGVPage[((A)>>10)+1]=&CHRptr[0][(V)<<11]-(A);}}
+
+static INLINE void MMC5SPRVROM_BANK4(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask4[0];MMC5SPRVPage[(A)>>10]=MMC5SPRVPage[((A)>>10)+1]= MMC5SPRVPage[((A)>>10)+2]=MMC5SPRVPage[((A)>>10)+3]=&CHRptr[0][(V)<<12]-(A);}}
+static INLINE void MMC5BGVROM_BANK4(uint32 A,uint32 V) {if(CHRptr[0]){V&=CHRmask4[0];MMC5BGVPage[(A)>>10]=MMC5BGVPage[((A)>>10)+1]=MMC5BGVPage[((A)>>10)+2]=MMC5BGVPage[((A)>>10)+3]=&CHRptr[0][(V)<<12]-(A);}}
+
+static INLINE void MMC5SPRVROM_BANK8(uint32 V) {if(CHRptr[0]){V&=CHRmask8[0];MMC5SPRVPage[0]=MMC5SPRVPage[1]=MMC5SPRVPage[2]=MMC5SPRVPage[3]=MMC5SPRVPage[4]=MMC5SPRVPage[5]=MMC5SPRVPage[6]=MMC5SPRVPage[7]=&CHRptr[0][(V)<<13];}}
+static INLINE void MMC5BGVROM_BANK8(uint32 V) {if(CHRptr[0]){V&=CHRmask8[0];MMC5BGVPage[0]=MMC5BGVPage[1]=MMC5BGVPage[2]=MMC5BGVPage[3]=MMC5BGVPage[4]=MMC5BGVPage[5]=MMC5BGVPage[6]=MMC5BGVPage[7]=&CHRptr[0][(V)<<13];}}
+
+static int32 inc;
+uint8 MMC5fill[0x400];
+
+#define MMC5IRQR        mapbyte3[4]
+#define MMC5LineCounter mapbyte3[5]
+#define mmc5psize mapbyte1[0]
+#define mmc5vsize mapbyte1[1]
+
+uint8 MMC5WRAMsize;
+uint8 MMC5WRAMIndex[8];
+
+uint8 MMC5ROMWrProtect[4];
+uint8 MMC5MemIn[5];
+
+static void MMC5CHRA(void);
+static void MMC5CHRB(void);
+
+typedef struct __cartdata {
+        unsigned long crc32;
+        unsigned char size;
+} cartdata;
+
+
+// ETROM seems to have 16KB of WRAM, ELROM seems to have 8KB
+// EWROM seems to have 32KB of WRAM
+
+#define MMC5_NOCARTS 14
+cartdata MMC5CartList[MMC5_NOCARTS]=
+{
+ {0x9c18762b,2},         /* L'Empereur */
+ {0x26533405,2},
+ {0x6396b988,2},
+
+ {0xaca15643,2},        /* Uncharted Waters */
+ {0xfe3488d1,2},        /* Dai Koukai Jidai */
+
+ {0x15fe6d0f,2},        /* BKAC             */
+ {0x39f2ce4b,2},        /* Suikoden              */
+
+ {0x8ce478db,2},        /* Nobunaga's Ambition 2 */
+ {0xeee9a682,2},
+
+ {0x1ced086f,2},       /* Ishin no Arashi */
+
+ {0xf540677b,4},        /* Nobunaga...Bushou Fuuun Roku */
+
+ {0x6f4e4312,4},        /* Aoki Ookami..Genchou */
+
+ {0xf011e490,4},        /* Romance of the 3 Kingdoms 2 */
+ {0x184c2124,4},        /* Sangokushi 2 */
+};
+
+
+// Called by iNESLoad()
+void DetectMMC5WRAMSize(void)
+{
+ int x;
+
+ MMC5WRAMsize=1;
+
+ for(x=0;x<MMC5_NOCARTS;x++)
+  if(iNESGameCRC32==MMC5CartList[x].crc32)
+   {
+   MMC5WRAMsize=MMC5CartList[x].size;
+   break;
+   }
+}
+
+static void BuildWRAMSizeTable(void)
+{
+ int x;
+
+ for(x=0;x<8;x++)
+ {
+  switch(MMC5WRAMsize)
+  {
+    default:
+    case 1:MMC5WRAMIndex[x]=(x>3)?255:0;break;
+    case 2:MMC5WRAMIndex[x]=(x&4)>>2;break;
+    case 4:MMC5WRAMIndex[x]=(x>3)?255:(x&3);break;
+  }
+ }
+}
+
+static void MMC5CHRA(void)
+{
+       int x;
+       switch(mapbyte1[1]&3)
+       {
+        case 0:MMC5SPRVROM_BANK8(mapbyte2[7]);
+               setchr8(mapbyte2[7]);
+               break;
+        case 1:MMC5SPRVROM_BANK4(0x0000,mapbyte2[3]);
+               MMC5SPRVROM_BANK4(0x1000,mapbyte2[7]);
+               setchr4(0x0000,mapbyte2[3]);
+               setchr4(0x1000,mapbyte2[7]);
+               break;
+        case 2:MMC5SPRVROM_BANK2(0x0000,mapbyte2[1]);
+               MMC5SPRVROM_BANK2(0x0800,mapbyte2[3]);
+               MMC5SPRVROM_BANK2(0x1000,mapbyte2[5]);
+               MMC5SPRVROM_BANK2(0x1800,mapbyte2[7]);
+               setchr2(0x0000,mapbyte2[1]);
+               setchr2(0x0800,mapbyte2[3]);
+               setchr2(0x1000,mapbyte2[5]);
+               setchr2(0x1800,mapbyte2[7]);
+               break;
+        case 3:
+               for(x=0;x<8;x++)
+               {
+                setchr1(x<<10,mapbyte2[x]);
+                MMC5SPRVROM_BANK1(x<<10,mapbyte2[x]);
+               }
+               break;
+ }
+}
+
+static void MMC5CHRB(void)
+{
+int x;
+switch(mapbyte1[1]&3)
+ {
+ case 0:MMC5BGVROM_BANK8(mapbyte3[3]);
+        setchr8(mapbyte3[3]);
+        break;
+ case 1:
+        MMC5BGVROM_BANK4(0x0000,mapbyte3[3]);
+        MMC5BGVROM_BANK4(0x1000,mapbyte3[3]);
+        setchr4(0x0000,mapbyte3[3]);
+        setchr4(0x1000,mapbyte3[3]);
+        break;
+ case 2:MMC5BGVROM_BANK2(0x0000,mapbyte3[1]);
+        MMC5BGVROM_BANK2(0x0800,mapbyte3[3]);
+        MMC5BGVROM_BANK2(0x1000,mapbyte3[1]);
+        MMC5BGVROM_BANK2(0x1800,mapbyte3[3]);
+        setchr2(0x0000,mapbyte3[1]);
+        setchr2(0x0800,mapbyte3[3]);
+        setchr2(0x1000,mapbyte3[1]);
+        setchr2(0x1800,mapbyte3[3]);
+        break;
+ case 3:
+        for(x=0;x<8;x++)
+       {
+        setchr1(x<<10,mapbyte3[x&3]);
+         MMC5BGVROM_BANK1(x<<10,mapbyte3[x&3]);
+       }
+        break;
+ }
+}
+
+static void FASTAPASS(2) MMC5WRAM(uint32 A, uint32 V)
+{
+   V=MMC5WRAMIndex[V&7];
+   if(V!=255)
+   {
+    setprg8r(0x10,A,V);
+    MMC5MemIn[(A-0x6000)>>13]=1;
+   }
+   else
+    MMC5MemIn[(A-0x6000)>>13]=0;
+}
+
+static void MMC5PRG(void)
+{
+ int x;
+
+ switch(mapbyte1[0]&3)
+  {
+  case 0:
+           MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=
+           MMC5ROMWrProtect[2]=MMC5ROMWrProtect[3]=1;
+           setprg32(0x8000,((mapbyte1[5]&0x7F)>>2));
+          for(x=0;x<4;x++)
+           MMC5MemIn[1+x]=1;
+           break;
+  case 1:
+         if(mapbyte1[5]&0x80)
+          {
+           MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=1;
+           setprg16(0x8000,(mapbyte1[5]>>1));
+          MMC5MemIn[1]=MMC5MemIn[2]=1;
+          }
+         else
+          {
+           MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=0;
+           MMC5WRAM(0x8000,mapbyte1[5]&7&0xFE);
+           MMC5WRAM(0xA000,(mapbyte1[5]&7&0xFE)+1);
+          }
+         MMC5MemIn[3]=MMC5MemIn[4]=1;
+          MMC5ROMWrProtect[2]=MMC5ROMWrProtect[3]=1;
+          setprg16(0xC000,(mapbyte1[7]&0x7F)>>1);
+         break;
+  case 2:
+         if(mapbyte1[5]&0x80)
+          {
+          MMC5MemIn[1]=MMC5MemIn[2]=1;
+           MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=1;
+           setprg16(0x8000,(mapbyte1[5]&0x7F)>>1);
+          }
+         else
+          {
+           MMC5ROMWrProtect[0]=MMC5ROMWrProtect[1]=0;
+           MMC5WRAM(0x8000,mapbyte1[5]&7&0xFE);
+           MMC5WRAM(0xA000,(mapbyte1[5]&7&0xFE)+1);
+          }
+         if(mapbyte1[6]&0x80)
+          {MMC5ROMWrProtect[2]=1;MMC5MemIn[3]=1;setprg8(0xC000,mapbyte1[6]&0x7F);}
+         else
+          {MMC5ROMWrProtect[2]=0;MMC5WRAM(0xC000,mapbyte1[6]&7);}
+        MMC5MemIn[4]=1;
+         MMC5ROMWrProtect[3]=1;
+         setprg8(0xE000,mapbyte1[7]&0x7F);
+         break;
+  case 3:
+        for(x=0;x<3;x++)
+         if(mapbyte1[4+x]&0x80)
+         {
+          MMC5ROMWrProtect[0]=1;
+          setprg8(0x8000+(x<<13),mapbyte1[4+x]&0x7F);
+          MMC5MemIn[1+x]=1;
+         }
+         else
+         {
+          MMC5ROMWrProtect[0]=0;
+          MMC5WRAM(0x8000+(x<<13),mapbyte1[4+x]&7);
+         }
+        MMC5MemIn[4]=1;
+         MMC5ROMWrProtect[3]=1;
+         setprg8(0xE000,mapbyte1[7]&0x7F);
+         break;
+  }
+}
+
+#define mul1 mapbyte3[6]
+#define mul2 mapbyte3[7]
+
+static DECLFW(Mapper5_write)
+{
+ switch(A)
+  {
+   default:break;
+   case 0x5105:
+                {
+                int x;
+                for(x=0;x<4;x++)
+                {
+                 switch((V>>(x<<1))&3)
+                 {
+                  case 0:PPUNTARAM|=1<<x;vnapage[x]=NTARAM;break;
+                  case 1:PPUNTARAM|=1<<x;vnapage[x]=NTARAM+0x400;break;
+                  case 2:PPUNTARAM|=1<<x;vnapage[x]=MapperExRAM+0x6000;break;
+                  case 3:PPUNTARAM&=~(1<<x);vnapage[x]=MMC5fill;break;
+                 }
+                }
+               }
+               mapbyte4[3]=V;
+               break;
+
+   case 0x5113:mapbyte4[6]=V;MMC5WRAM(0x6000,V&7);break;
+   case 0x5100:mapbyte1[0]=V;MMC5PRG();break;
+   case 0x5101:mapbyte1[1]=V;
+               if(!mapbyte4[7])
+                {MMC5CHRB();MMC5CHRA();}
+               else
+                {MMC5CHRA();MMC5CHRB();}
+               break;
+
+   case 0x5114:
+   case 0x5115:
+   case 0x5116:
+   case 0x5117:
+               mapbyte1[A&7]=V;MMC5PRG();break;
+
+   case 0x5120:
+   case 0x5121:
+   case 0x5122:
+   case 0x5123:
+   case 0x5124:
+   case 0x5125:
+   case 0x5126:
+   case 0x5127:mapbyte4[7]=0;
+               mapbyte2[A&7]=V;MMC5CHRA();break;
+   case 0x5128:
+   case 0x5129:
+   case 0x512a:
+   case 0x512b:mapbyte4[7]=1;
+               mapbyte3[A&3]=V;MMC5CHRB();break;
+   case 0x5102:mapbyte4[0]=V;break;
+   case 0x5103:mapbyte4[1]=V;break;
+   case 0x5104:mapbyte4[2]=V;MMC5HackCHRMode=V&3;break;
+   case 0x5106:if(V!=mapbyte4[4])
+               {
+               uint32 t;
+               t=V|(V<<8)|(V<<16)|(V<<24);
+                FCEU_dwmemset(MMC5fill,t,0x3c0);
+               }
+               mapbyte4[4]=V;
+               break;
+   case 0x5107:if(V!=mapbyte4[5])
+               {
+                unsigned char moop;
+                uint32 t;
+                moop=V|(V<<2)|(V<<4)|(V<<6);
+               t=moop|(moop<<8)|(moop<<16)|(moop<<24);
+                FCEU_dwmemset(MMC5fill+0x3c0,t,0x40);
+               }
+               mapbyte4[5]=V;
+               break;
+   case 0x5200:MMC5HackSPMode=V;break;
+   case 0x5201:MMC5HackSPScroll=(V>>3)&0x1F;break;
+   case 0x5202:MMC5HackSPPage=V&0x3F;break;
+   case 0x5203:X6502_IRQEnd(FCEU_IQEXT);IRQCount=V;break;
+   case 0x5204:X6502_IRQEnd(FCEU_IQEXT);IRQa=V&0x80;break;
+   case 0x5205:mul1=V;break;
+   case 0x5206:mul2=V;break;
+  }
+}
+
+DECLFR(MMC5_ReadROMRAM)
+{
+       if(MMC5MemIn[(A-0x6000)>>13])
+         return Page[A>>11][A];
+       else
+        return X.DB;
+}
+
+DECLFW(MMC5_WriteROMRAM)
+{
+       if(A>=0x8000)
+        if(MMC5ROMWrProtect[(A-0x8000)>>13])
+         return;
+       if(MMC5MemIn[(A-0x6000)>>13])
+        if(((mapbyte4[0]&3)|((mapbyte4[1]&3)<<2)) == 6)
+         Page[A>>11][A]=V;
+}
+
+static DECLFW(MMC5_ExRAMWr)
+{
+ if(MMC5HackCHRMode!=3)
+  (MapperExRAM+0x6000)[A&0x3ff]=V;
+}
+
+static DECLFR(MMC5_ExRAMRd)
+{
+ /* Not sure if this is correct, so I'll comment it out for now. */
+ //if(MMC5HackCHRMode>=2)
+  return (MapperExRAM+0x6000)[A&0x3ff];
+ //else
+ // return(X.DB);
+}
+
+static DECLFR(MMC5_read)
+{
+ switch(A)
+ {
+  //default:printf("$%04x\n",A);break;
+  case 0x5204:X6502_IRQEnd(FCEU_IQEXT);
+              {
+               uint8 x;
+               x=MMC5IRQR;
+               MMC5IRQR&=0x40;
+               return x;
+             }
+  case 0x5205:return (mul1*mul2);
+  case 0x5206:return ((mul1*mul2)>>8);
+ }
+ return(X.DB);
+}
+
+uint8 dorko[0x400];
+
+void MMC5Synco(void)
+{
+ int x;
+
+ MMC5PRG();
+ for(x=0;x<4;x++)
+ {
+  switch((mapbyte4[3]>>(x<<1))&3)
+   {
+    case 0:PPUNTARAM|=1<<x;vnapage[x]=NTARAM;break;
+    case 1:PPUNTARAM|=1<<x;vnapage[x]=NTARAM+0x400;break;
+    case 2:PPUNTARAM|=1<<x;vnapage[x]=MapperExRAM+0x6000;break;
+    case 3:PPUNTARAM&=~(1<<x);vnapage[x]=MMC5fill;break;
+   }
+ }
+ MMC5WRAM(0x6000,mapbyte4[6]&7);
+ if(!mapbyte4[7])
+ {
+  MMC5CHRB();
+  MMC5CHRA();
+ }
+ else
+ {
+   MMC5CHRA();
+   MMC5CHRB();
+ }
+  {
+    uint32 t;
+    t=mapbyte4[4]|(mapbyte4[4]<<8)|(mapbyte4[4]<<16)|(mapbyte4[4]<<24);
+    FCEU_dwmemset(MMC5fill,t,0x3c0);
+  }
+  {
+   unsigned char moop;
+   uint32 t;
+   moop=mapbyte4[5]|(mapbyte4[5]<<2)|(mapbyte4[5]<<4)|(mapbyte4[5]<<6);
+   t=moop|(moop<<8)|(moop<<16)|(moop<<24);
+   FCEU_dwmemset(MMC5fill+0x3c0,t,0x40);
+  }
+  X6502_IRQEnd(FCEU_IQEXT);
+  MMC5HackCHRMode=mapbyte4[2]&3;
+}
+
+void MMC5_hbo(void)
+{
+  if(scanline==0)
+   MMC5LineCounter=0;
+
+  if(MMC5LineCounter<245)
+  {
+   MMC5LineCounter++;
+   if(MMC5LineCounter==IRQCount) MMC5IRQR|=0x80;
+   if((MMC5LineCounter==IRQCount && IRQa&0x80))
+    X6502_IRQBegin(FCEU_IQEXT);
+  }
+  if(MMC5LineCounter>=239)
+    MMC5IRQR|=0x40;
+}
+
+void MMC5_hb(void)
+{
+  if(scanline==240)
+  {
+   MMC5LineCounter=0;
+   MMC5IRQR=0x40;
+   return;
+  }
+
+  if(MMC5LineCounter<240)
+  {
+   MMC5LineCounter++;
+   if(MMC5LineCounter==IRQCount) 
+   {
+    MMC5IRQR|=0x80;
+    if(IRQa&0x80)
+     X6502_IRQBegin(FCEU_IQEXT);
+   }
+  }
+//  printf("%d:%d\n",MMC5LineCounter,scanline);
+ if(MMC5LineCounter==240)
+   MMC5IRQR=0;
+}
+
+void Mapper5_StateRestore(int version)
+{
+ if(version<=70)
+ {
+  uint8 tmp[8192];
+
+  FCEU_memmove(tmp,MapperExRAM,8192);
+  FCEU_memmove(MapperExRAM,MapperExRAM+8192,16384+8192);
+  FCEU_memmove(MapperExRAM+16384+8192,tmp,8192);
+ }
+ MMC5Synco();
+}
+
+#define MMC5PSG         (MapperExRAM+0x640B+8)
+
+static int C5BC[3]={0,0,0};
+
+static void Do5PCM(void)
+{
+   int32 V;
+   int32 start,end;
+
+   start=C5BC[2];
+   end=(timestamp<<16)/soundtsinc;
+   if(end<=start) return;
+   C5BC[2]=end;
+   
+   if(!(MMC5PSG[0x10]&0x40) && MMC5PSG[0x11])
+    for(V=start;V<end;V++)
+     Wave[V>>4]+=MMC5PSG[0x11]<<2;
+}
+
+DECLFW(Mapper5_SW)
+{
+ GameExpSound.Fill=MMC5Sound;
+ A&=0x1F;
+
+ switch(A)
+ {
+  case 0x10:
+  case 0x11:Do5PCM();break;
+
+  case 0x0:Do5SQ(0);break;
+  case 0x2:Do5SQ(0);break;
+  case 0x3:Do5SQ(0);break;
+  case 0x4:Do5SQ(1);break;
+  case 0x6:Do5SQ(1);break;
+  case 0x7:Do5SQ(1);break;
+  case 0x15:
+         {
+          int t=V^MMC5PSG[0x15];
+           if(t&1)
+            Do5SQ(0);
+           if(t&2)
+            Do5SQ(1);
+         }
+          break;
+ }
+ MMC5PSG[A]=V;
+}
+
+static int32 vcount[2];
+void Do5SQ(int P)
+{
+    int32 start,end;
+    int V;
+    int32 freq;
+
+    start=C5BC[P];
+    end=(timestamp<<16)/soundtsinc;
+    if(end<=start) return;
+    C5BC[P]=end;
+
+
+
+    if(MMC5PSG[0x15]&(P+1))
+    {
+     unsigned long dcycs;
+     unsigned char amplitude;
+     long vcoo;
+
+     freq=(((MMC5PSG[(P<<2)+0x2]|((MMC5PSG[(P<<2)+0x3]&7)<<8))));
+
+     if(freq<8) goto mmc5enda;
+     freq+=1;
+     inc=(long double)((unsigned long)((FSettings.SndRate OVERSAMPLE)<<12))/((long double)PSG_base/freq);
+
+     switch(MMC5PSG[P<<2]&0xC0)
+     {
+     default:
+     case 0x00:dcycs=inc>>3;break;
+     case 0x40:dcycs=inc>>2;break;
+     case 0x80:dcycs=inc>>1;break;
+     case 0xC0:dcycs=(inc+inc+inc)>>2;break;
+     }
+
+      amplitude=(MMC5PSG[P<<2]&15)<<4;
+
+      vcoo=vcount[P];
+             for(V=start;V<end;V++)
+              {
+               if(vcoo<dcycs)
+                Wave[V>>4]+=amplitude;
+               vcoo+=0x1000;
+               if(vcoo>=inc) vcoo-=inc;
+               }
+      vcount[P]=vcoo;
+    }
+  mmc5enda:; // semi-colon must be here for MSVC
+}
+
+void MMC5Sound(int Count)
+{
+  int x;
+  Do5SQ(0);
+  Do5SQ(1);
+  Do5PCM();
+  for(x=0;x<3;x++)
+   C5BC[x]=Count;
+}
+
+static void MMC5SoundC(void)
+{
+ if(FSettings.SndRate)
+  Mapper5_ESI();
+ else
+  SetWriteHandler(0x5000,0x5015,0); 
+}
+
+void Mapper5_ESI(void)
+{
+ GameExpSound.RChange=MMC5SoundC;
+
+ if(FSettings.SndRate)
+ {
+  SetWriteHandler(0x5000,0x5015,Mapper5_SW);
+  SetWriteHandler(0x5205,0x5206,Mapper5_write);
+  SetReadHandler(0x5205,0x5206,MMC5_read);
+ }
+ if(FCEUGameInfo.type==GIT_NSF)
+ {
+  SetWriteHandler(0x5c00,0x5fef,MMC5_ExRAMWr);
+  SetReadHandler(0x5c00,0x5fef,MMC5_ExRAMRd);
+  MMC5HackCHRMode=2;
+ }
+ else
+  GameHBIRQHook=MMC5_hb;
+}
+
+static void GenMMC5Reset(void)
+{
+ mapbyte1[4]=mapbyte1[5]=mapbyte1[6]=mapbyte1[7]=~0;
+ mapbyte1[0]=mapbyte1[1]=3;
+ mapbyte4[2]=0;
+
+ mapbyte4[3]=mapbyte4[4]=mapbyte4[5]=0xFF;
+
+ MMC5Synco();
+
+ SetWriteHandler(0x4020,0x5bff,Mapper5_write);
+ SetReadHandler(0x4020,0x5bff,MMC5_read);
+
+ SetWriteHandler(0x5c00,0x5fff,MMC5_ExRAMWr);
+ SetReadHandler(0x5c00,0x5fff,MMC5_ExRAMRd);
+
+ SetWriteHandler(0x6000,0xFFFF,MMC5_WriteROMRAM);
+ SetReadHandler(0x6000,0xFFFF,MMC5_ReadROMRAM);
+
+ Mapper5_ESI();
+
+ GameHBIRQHook=MMC5_hb;
+ FCEU_CheatAddRAM(8,0x6000,WRAM);
+ FCEU_CheatAddRAM(1,0x5c00,MapperExRAM+0x6000);
+}
+
+void Mapper5_init(void)
+{
+ AddExState(&MMC5HackSPMode, 1, 0, "SPLM");
+ AddExState(&MMC5HackSPScroll, 1, 0, "SPLS");
+ AddExState(&MMC5HackSPPage, 1, 0, "SPLP");
+ SetupCartPRGMapping(0x10,WRAM,32768,1);
+ GenMMC5Reset();
+ BuildWRAMSizeTable();
+ GameStateRestore=Mapper5_StateRestore;
+}
+
+static int m5boo;
+static void GenMMC5_Close(void)
+{
+ UNIFOpenWRAM(UOW_WR,0,1);
+ if(m5boo<=16)
+  UNIFWriteWRAM(WRAM,8192);
+ else
+  UNIFWriteWRAM(WRAM,32768);
+ UNIFCloseWRAM();
+}
+
+static void GenMMC5_Init(int wsize, int battery)
+{
+ SetupCartPRGMapping(0x10,WRAM,32768,1);
+ AddExState(WRAM, 8192, 0, "WRAM");
+ AddExState(MapperExRAM, 32768, 0, "MEXR");
+ AddExState(&IRQCount, 4, 1, "IRQC");
+ AddExState(&IRQa, 1, 0, "IRQA");
+ AddExState(mapbyte1, 32, 0, "MPBY");
+ AddExState(&MMC5HackSPMode, 1, 0, "SPLM");
+ AddExState(&MMC5HackSPScroll, 1, 0, "SPLS");
+ AddExState(&MMC5HackSPPage, 1, 0, "SPLP");
+
+ MMC5WRAMsize=wsize/8; 
+ BuildWRAMSizeTable();
+ GameStateRestore=Mapper5_StateRestore;
+ BoardPower=GenMMC5Reset;
+
+ if(battery)
+ {
+  UNIFOpenWRAM(UOW_RD,0,1);
+  if(wsize<=16)
+   UNIFReadWRAM(WRAM,8192);
+  else
+   UNIFReadWRAM(WRAM,32768);
+  UNIFCloseWRAM();
+  BoardClose=GenMMC5_Close;
+  m5boo=wsize;
+ }
+
+ MMC5HackVROMMask=CHRmask4[0];
+ MMC5HackExNTARAMPtr=MapperExRAM+0x6000;
+ MMC5Hack=1;
+ MMC5HackVROMPTR=CHRptr[0];
+ MMC5HackCHRMode=0;
+ MMC5HackSPMode=MMC5HackSPScroll=MMC5HackSPPage=0;
+
+}
+
+// ETROM seems to have 16KB of WRAM, ELROM seems to have 8KB
+// EWROM seems to have 32KB of WRAM
+
+// ETROM and EWROM are battery-backed, ELROM isn't.
+
+void ETROM_Init(void)
+{
+ GenMMC5_Init(16,1);
+}
+
+void ELROM_Init(void)
+{
+ GenMMC5_Init(8,0);
+}
+
+void EWROM_Init(void)
+{
+ GenMMC5_Init(32,1);
+}
+
+void EKROM_Init(void)
+{
+ GenMMC5_Init(8,1);
+}
diff --git a/memory.c b/memory.c
new file mode 100644 (file)
index 0000000..bec7270
--- /dev/null
+++ b/memory.c
@@ -0,0 +1,67 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdlib.h>
+
+#include "types.h"
+#include "version.h"
+#include "memory.h"
+#include "general.h"
+#include "svga.h"
+
+void *FCEU_malloc(uint32 size)
+{
+ void *ret;
+ ret=malloc(size);
+ if(!ret)
+  FCEU_PrintError(MSG_ERRAM);
+ return ret;
+}
+
+void FCEU_free(void *ptr)              // Might do something with this and FCEU_malloc later...
+{
+ free(ptr);
+}
+
+void FASTAPASS(3) FCEU_memmove(void *d, void *s, uint32 l)
+{
+ uint32 x;
+ int t;
+
+ /* Type really doesn't matter. */
+ t=(int)d;
+ t|=(int)s;
+ t|=(int)l;
+
+ if(t&3)          // Not 4-byte aligned and/or length is not a multiple of 4.
+  for(x=l;x;x--)        // This could be optimized further, though(more tests could be performed).
+  {
+   *(uint8*)d=*(uint8 *)s;
+   ((uint8 *)d)++;
+   ((uint8 *)s)++;
+  }
+ else
+  for(x=l>>2;x;x--)
+  {
+   *(uint32*)d=*(uint32*)s;
+   ((uint32 *)d)++;
+   ((uint32 *)s)++;
+  }
+}
diff --git a/memory.h b/memory.h
new file mode 100644 (file)
index 0000000..122a858
--- /dev/null
+++ b/memory.h
@@ -0,0 +1,29 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+/*              Various macros for faster memory stuff 
+               (at least that's the idea) 
+*/
+
+#define FCEU_dwmemset(d,c,n) {int _x; for(_x=n-4;_x>=0;_x-=4) *(uint32 *)&(d)[_x]=c;}
+
+void *FCEU_malloc(uint32 size);
+void FCEU_free(void *ptr);
+void FASTAPASS(3) FCEU_memmove(void *d, void *s, uint32 l);
diff --git a/netplay.c b/netplay.c
new file mode 100644 (file)
index 0000000..fc2a42e
--- /dev/null
+++ b/netplay.c
@@ -0,0 +1,98 @@
+/* FCE Ultra - NES/Famicom Emulator\r
+ *\r
+ * Copyright notice for this file:\r
+ *  Copyright (C) 2002 Ben Parnell\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+#ifdef NETWORK\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "types.h"\r
+#include "svga.h"\r
+#include "netplay.h"\r
+\r
+int netplay=0;         /*      1 if we are a server */\r
+                        /*      2 if we need a host  */\r
+static uint8 netjoy[4];        // controller stuff.\r
+\r
+static void NetError(void)\r
+{\r
+ FCEU_DispMessage("Network error/connection lost!");\r
+// FCEUD_PrintError("Network error/connection lost!");\r
+ netplay=0;\r
+ FCEUD_NetworkClose();\r
+}\r
+\r
+void KillNetplay(void)\r
+{\r
+ if(netplay)\r
+ {\r
+  FCEUD_NetworkClose();\r
+  netplay=0;\r
+ }\r
+}\r
+\r
+int InitNetplay(void)\r
+{\r
+         if(!FCEUD_NetworkConnect())\r
+          {NetError();return 0;}\r
+         netplay=FSettings.NetworkPlay;\r
+        memset(netjoy,0,sizeof(netjoy));\r
+         return 1;\r
+}\r
+\r
+void NetplayUpdate(uint16 *joyp1, uint16 *joyp2)\r
+{\r
+ uint8 buf[5];\r
+ if(netplay==1)         // We're the server\r
+ {\r
+  int t;\r
+\r
+  loopo:\r
+\r
+  t=FCEUD_NetworkRecvData(&netjoy[2],1,0);\r
+  if(!t) {NetError();return;}   \r
+  if(t!=-1) goto loopo;\r
+\r
+  netjoy[0]=*joyp1;\r
+  memcpy(buf,netjoy,4);\r
+  buf[4]=CommandQueue;\r
+\r
+  if(!FCEUD_NetworkSendData(buf,5)) {NetError();return;}\r
+  if(CommandQueue)\r
+  {\r
+   DoCommand(CommandQueue);\r
+   CommandQueue=0;\r
+  }\r
+ }\r
+ else if(netplay==2)    // We're connected to a host (we're second player)\r
+ {\r
+  uint8 ja=(*joyp1)|(*joyp1>>8)|(*joyp2)|(*joyp2>>8);\r
+  if(!FCEUD_NetworkSendData(&ja,1)) {NetError();return;}\r
+  if(!FCEUD_NetworkRecvData(buf,5,1)) {NetError();return;}\r
+\r
+  memcpy(netjoy,buf,4);\r
+  if(buf[4]) DoCommand(buf[4]);\r
+ }\r
+ *joyp1=netjoy[0]|(netjoy[1]<<8);\r
+ *joyp2=netjoy[2]|(netjoy[3]<<8);\r
+\r
+}\r
+#endif\r
diff --git a/netplay.h b/netplay.h
new file mode 100644 (file)
index 0000000..d6ddd37
--- /dev/null
+++ b/netplay.h
@@ -0,0 +1,7 @@
+#ifdef NETWORK
+int InitNetplay(void);
+void KillNetplay(void);
+void NetplayUpdate(uint16 *JS1, uint16 *JS2);
+
+extern int netplay;
+#endif
diff --git a/nsf.c b/nsf.c
new file mode 100644 (file)
index 0000000..cadb726
--- /dev/null
+++ b/nsf.c
@@ -0,0 +1,410 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "types.h"
+#include "x6502.h"
+#include "fce.h"
+#include "svga.h"
+#include "video.h"
+#include "sound.h"
+#include "ines.h"
+#include "nsf.h"
+#include "nsfbgnew.h"
+#include "general.h"
+#include "memory.h"
+#include "file.h"
+#include "fds.h"
+#include "cart.h"
+#include "input.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+uint8 SongReload;
+uint8 CurrentSong;
+
+static int sinetable[32];
+
+
+static uint8 NSFROM[0x30+6]=
+{
+/* 0x00 */
+
+0x08,0x48,0x8A,0x48,0x98,0x48,          /* Store regs           */
+0xA9,0xFF,
+0x8D,0xF2,0x5F,                                /* NMI has occured      */
+0x68,0xA8,0x68,0xAA,0x68,0x28,
+0x40,     /* Restore regs         */
+
+/* 0x12 */
+
+0xAD,0xF2,0x5F,                                /* See if an NMI occured */
+0xF0,0xFB,                             /* If it hasn't, loop    */
+
+0xA9,0x00,
+0x8D,0xF2,0x5F,                                /* Clear play pending reg*/
+
+
+0xAD,0xF0,0x5F,                         /* See if we need to init. */
+0xF0,0x09,                              /* If 0, go to JMP         */
+
+0xAD,0xF1,0x5F,                         /* Confirm and load A      */
+0xAE,0xF3,0x5F,                         /* Load X with PAL/NTSC byte */
+
+0x20,0x00,0x00,                         /* JSR to init routine     */
+
+0x20,0x00,0x00,                         /* JSR to play routine  */
+
+0x4C,0x12,0x38,                         /* Loop                 */
+
+0xA2,0xFF,0x9A,                                /* Initialize the stack pointer. */
+0x4C,0x12,0x38
+};
+
+static DECLFR(NSFROMRead)
+{
+ return (NSFROM-0x3800)[A];
+}
+
+
+
+static uint8 *NSFDATA=0;
+static int NSFMaxBank;
+
+static int NSFSize;
+static uint8 BSon;
+static uint16 PlayAddr;
+static uint16 InitAddr;
+static uint16 LoadAddr;
+
+NSF_HEADER NSFHeader;
+
+void NSFGI(int h)
+{
+ switch(h)
+ {
+ case GI_CLOSE:
+  if(NSFDATA) {free(NSFDATA);NSFDATA=0;}
+  break;
+ case GI_POWER: NSF_init();break;
+ }
+}
+
+// First 32KB is reserved for sound chip emulation in the iNES mapper code.
+
+#define WRAM (GameMemBlock+32768)
+#define FDSMEM (GameMemBlock+32768)
+
+static INLINE void BANKSET(uint32 A, uint32 bank)
+{
+ bank&=NSFMaxBank;
+ if(NSFHeader.SoundChip&4)
+  memcpy(FDSMEM+(A-0x6000),NSFDATA+(bank<<12),4096);
+ else 
+  setprg4(A,bank);
+}
+
+int NSFLoad(int fp)
+{
+  int x;
+
+  FCEU_fseek(fp,0,SEEK_SET);
+  FCEU_fread(&NSFHeader,1,0x80,fp);
+  if (memcmp(NSFHeader.ID,"NESM\x1a",5))
+                  return 0;
+  NSFHeader.SongName[31]=NSFHeader.Artist[31]=NSFHeader.Copyright[31]=0;
+
+  LoadAddr=NSFHeader.LoadAddressLow;
+  LoadAddr|=NSFHeader.LoadAddressHigh<<8;
+
+  InitAddr=NSFHeader.InitAddressLow;
+  InitAddr|=NSFHeader.InitAddressHigh<<8;
+
+  PlayAddr=NSFHeader.PlayAddressLow;
+  PlayAddr|=NSFHeader.PlayAddressHigh<<8;
+
+  NSFSize=FCEU_fgetsize(fp)-0x80;
+
+  NSFMaxBank=((NSFSize+(LoadAddr&0xfff)+4095)/4096);
+  NSFMaxBank=uppow2(NSFMaxBank);
+
+  if(!(NSFDATA=(uint8 *)FCEU_malloc(NSFMaxBank*4096)))
+   return 0;
+
+  FCEU_fseek(fp,0x80,SEEK_SET);
+  memset(NSFDATA,0x00,NSFMaxBank*4096);
+  FCEU_fread(NSFDATA+(LoadAddr&0xfff),1,NSFSize,fp);
+  NSFMaxBank--;
+
+  BSon=0;
+  for(x=0;x<8;x++)
+   BSon|=NSFHeader.BankSwitch[x];
+
+ FCEUGameInfo.type=GIT_NSF;
+ FCEUGameInfo.input[0]=FCEUGameInfo.input[1]=SI_NONE;
+
+ for(x=0;;x++)
+ {
+  if(NSFROM[x]==0x20)
+  {
+   NSFROM[x+1]=InitAddr&0xFF;
+   NSFROM[x+2]=InitAddr>>8;
+   NSFROM[x+4]=PlayAddr&0xFF;
+   NSFROM[x+5]=PlayAddr>>8;
+   break;
+  }
+ }
+
+ if(NSFHeader.VideoSystem==0)
+  FCEUGameInfo.vidsys=GIV_NTSC;
+ else if(NSFHeader.VideoSystem==1)
+  FCEUGameInfo.vidsys=GIV_PAL;
+
+ {
+  double fruit=0;
+  for(x=0;x<32;x++)
+  {
+   double ta,no;
+   ta=sin(fruit)*7;
+   ta+=modf(ta,&no);
+   sinetable[x]=ta;
+   fruit+=(double)M_PI*2/32;
+  }
+ }
+ GameInterface=NSFGI;
+
+ puts("NSF Loaded.  File information:\n");
+ printf(" Name:       %s\n Artist:     %s\n Copyright:  %s\n\n",NSFHeader.SongName,NSFHeader.Artist,NSFHeader.Copyright);
+ if(NSFHeader.SoundChip)
+ {
+  static char *tab[6]={"Konami VRCVI","Konami VRCVII","Nintendo FDS","Nintendo MMC5","Namco 106","Sunsoft FME-07"};
+  for(x=0;x<6;x++)
+   if(NSFHeader.SoundChip&(1<<x))
+   {
+    printf(" Expansion hardware:  %s\n",tab[x]);
+    break;
+   }
+ }
+ if(BSon)
+  puts(" Bank-switched.");
+ printf(" Load address:  $%04x\n Init address:  $%04x\n Play address:  $%04x\n",LoadAddr,InitAddr,PlayAddr);
+ printf(" %s\n",(NSFHeader.VideoSystem&1)?"PAL":"NTSC");
+ printf(" Starting song:  %d / %d\n\n",NSFHeader.StartingSong,NSFHeader.TotalSongs);
+ return 1;
+}
+
+static DECLFW(BWRAM)
+{
+                (WRAM-0x6000)[A]=V;
+}
+
+static DECLFW(NSFFDSWrite)
+{
+       (FDSMEM-0x6000)[A]=V;
+}
+
+static DECLFR(NSFFDSRead)
+{
+       return (FDSMEM-0x6000)[A];
+}
+
+static DECLFR(AWRAM)
+{
+       return WRAM[A-0x6000];
+}
+
+void NSF_init(void)
+{
+  if(NSFHeader.SoundChip&4)
+  {
+   memset(FDSMEM,0x00,32768+8192);
+   SetWriteHandler(0x6000,0xDFFF,NSFFDSWrite);
+   SetReadHandler(0x6000,0xFFFF,NSFFDSRead);
+  }
+  else
+  {
+   memset(WRAM,0x00,8192);
+   SetReadHandler(0x6000,0x7FFF,AWRAM);
+   SetWriteHandler(0x6000,0x7FFF,BWRAM);
+   ResetCartMapping();
+   SetupCartPRGMapping(0,NSFDATA,((NSFMaxBank+1)*4096),0);
+   SetReadHandler(0x8000,0xFFFF,CartBR);
+  }
+
+  if(BSon)
+  {
+   int32 x;
+   for(x=0;x<8;x++)
+   {
+    if(NSFHeader.SoundChip&4 && x>=6)
+     BANKSET(0x6000+(x-6)*4096,NSFHeader.BankSwitch[x]);
+    BANKSET(0x8000+x*4096,NSFHeader.BankSwitch[x]);
+   }
+  }
+  else
+  {
+   int32 x;
+    for(x=(LoadAddr&0x7000);x<0x8000;x+=0x1000)
+     BANKSET(0x8000+x,((x-(LoadAddr&0x7000))>>12));
+  }
+
+  SetWriteHandler(0x2000,0x3fff,0);
+  SetReadHandler(0x2000,0x37ff,0);
+  SetReadHandler(0x3836,0x3FFF,0);
+  SetReadHandler(0x3800,0x3835,NSFROMRead);
+
+  SetWriteHandler(0x4020,0x5fff,NSF_write);
+  SetReadHandler(0x4020,0x5fff,NSF_read);
+
+
+  if(NSFHeader.SoundChip&1) { 
+   VRC6_ESI(0);
+  } else if (NSFHeader.SoundChip&2) {
+   VRC7_ESI();
+  } else if (NSFHeader.SoundChip&4) {
+   FDSSoundReset();
+  } else if (NSFHeader.SoundChip&8) {
+   Mapper5_ESI();
+  } else if (NSFHeader.SoundChip&0x10) {
+   Mapper19_ESI();
+  } else if (NSFHeader.SoundChip&0x20) {
+   Mapper69_ESI();
+  }
+  CurrentSong=NSFHeader.StartingSong;
+  SongReload=1;
+}
+
+static uint8 DoUpdateStuff=0;
+DECLFW(NSF_write)
+{
+switch(A)
+{
+ case 0x5FF2:if((X.PC&0xF000)==0x3000) DoUpdateStuff=V;break;
+ case 0x5FF6:
+ case 0x5FF7:if(!(NSFHeader.SoundChip&4)) return;
+ case 0x5FF8:
+ case 0x5FF9:
+ case 0x5FFA:
+ case 0x5FFB:
+ case 0x5FFC:
+ case 0x5FFD:
+ case 0x5FFE:
+ case 0x5FFF:if(!BSon) return;
+             A&=0xF;
+             BANKSET((A*4096),V);
+            break;
+}
+}
+
+DECLFR(NSF_read)
+{
+ int x;
+
+ if((X.PC&0xF000)==0x3000)
+ switch(A)
+ {
+ case 0x5ff0:x=SongReload;SongReload=0;return x;
+ case 0x5ff1:
+            {
+             memset(RAM,0x00,0x800);
+             memset(WRAM,0x00,8192);
+             BWrite[0x4015](0x4015,0xF);
+             for(x=0;x<0x14;x++)
+              {if(x!=0x11) BWrite[0x4015](0x4015,0);}
+             BWrite[0x4015](0x4015,0x0);
+             for(x=0;x<0x14;x++)
+              {if(x!=0x11) BWrite[0x4015](0x4015,0);}
+            BWrite[0x4011](0x4011,0x40);
+             BWrite[0x4015](0x4015,0xF);
+            BWrite[0x4017](0x4017,0x40);
+            if(NSFHeader.SoundChip&4) 
+             BWrite[0x4089](0x4089,0x80);
+             if(BSon)
+             {
+              for(x=0;x<8;x++)
+              BANKSET(0x8000+x*4096,NSFHeader.BankSwitch[x]);
+             }
+             return (CurrentSong-1);
+            }
+ case 0x5FF2:return DoUpdateStuff;
+ case 0x5FF3:return PAL;
+ }
+ return 0;
+}
+static int32 *Bufpl;
+void DrawNSF(uint8 *XBuf)
+{
+ char snbuf[16];
+ static int z=0;
+ int x,y;
+ uint8 *XBuf2,*tmpb;
+
+ XBuf+=8;
+ XBuf2=XBuf;
+
+ tmpb=NSFBG+8;
+ for(y=120;y;y--)
+  {
+   uint8 *offs;
+
+   offs=tmpb+sinetable[((z+y)>>2)&31];
+   memcpy(XBuf2,offs,256);
+   memcpy(XBuf2+(120*272),offs,256);
+
+   XBuf2+=272;
+   tmpb+=272;
+  }
+ tmpb=NSFBG+8;
+ z=(z+1)&127;
+
+ DrawTextTrans(XBuf+10*272+4+(((31-strlen(NSFHeader.SongName))<<2)), 272, NSFHeader.SongName, 38);
+ DrawTextTrans(XBuf+30*272+4+(((31-strlen(NSFHeader.Artist))<<2)), 272, NSFHeader.Artist, 38);
+ DrawTextTrans(XBuf+50*272+4+(((31-strlen(NSFHeader.Copyright))<<2)), 272, NSFHeader.Copyright, 38);
+
+ DrawTextTrans(XBuf+90*272+4+(((31-strlen("Song:"))<<2)), 272, "Song:", 38);
+ sprintf(snbuf,"<%d/%d>",CurrentSong,NSFHeader.TotalSongs);
+ DrawTextTrans(XBuf+102*272+4+(((31-strlen(snbuf))<<2)), 272, snbuf, 38);
+
+ GetSoundBuffer(&Bufpl);
+  for(x=0;x<256;x++)
+   XBuf[x+(224-((((Bufpl[x]>>(7)^128)&255)*3)>>3))*272]=38;
+}
+
+void NSFControl(int z)
+{ 
+ if(z==1)
+ {
+  if(CurrentSong<NSFHeader.TotalSongs) CurrentSong++;
+ }
+ else if(z==2)
+ {
+  if(CurrentSong>1) CurrentSong--;
+ }
+ SongReload=0xFF;
+}
diff --git a/nsf.h b/nsf.h
new file mode 100644 (file)
index 0000000..3333201
--- /dev/null
+++ b/nsf.h
@@ -0,0 +1,53 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+typedef struct {
+                char ID[5]; /*NESM^Z*/
+                uint8 Version;
+                uint8 TotalSongs;
+                uint8 StartingSong;
+                uint8 LoadAddressLow;
+                uint8 LoadAddressHigh;
+                uint8 InitAddressLow;
+                uint8 InitAddressHigh;
+                uint8 PlayAddressLow;
+                uint8 PlayAddressHigh;
+                uint8 SongName[32];
+                uint8 Artist[32];
+                uint8 Copyright[32];
+                uint8 NTSCspeed[2];              // Unused
+                uint8 BankSwitch[8];
+                uint8 PALspeed[2];               // Unused
+                uint8 VideoSystem;
+                uint8 SoundChip;
+                uint8 Expansion[4];
+                uint8 reserve[8];
+        } NSF_HEADER;
+int NSFLoad(int fp);
+DECLFW(NSF_write);
+DECLFR(NSF_read);
+void NSF_init(void);
+extern uint8 CurrentSong;
+extern uint8 SongReload;
+void DrawNSF(uint8 *XBuf);
+void NSFControl(int z);
+extern NSF_HEADER NSFHeader;
+void NSFDealloc(void);
+void NSFDodo(void);
diff --git a/nsfbgnew.h b/nsfbgnew.h
new file mode 100644 (file)
index 0000000..2c55fe1
--- /dev/null
@@ -0,0 +1,2062 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+uint8 NSFBG[32640] = {
+0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,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,3,3,3,
+3,3,3,3,3,3,3,3,3,3,3,3,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,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,5,
+5,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,
+7,7,7,7,7,7,7,7,7,7,7,7,7,7,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,6,6,6,6,6,
+6,6,6,6,6,6,6,6,6,5,4,4,4,4,4,4,
+4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,
+4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,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,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
+4,4,4,4,4,4,4,4,4,4,4,4,5,6,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,
+7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+7,7,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,6,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,5,4,4,4,4,4,4,4,4,4,4,4,4,
+5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,
+4,4,4,4,4,4,4,4,4,4,5,5,6,6,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,6,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,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,6,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,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,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,
+4,4,4,4,4,4,4,4,5,5,6,6,6,6,6,6,
+6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,
+7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+7,7,7,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,6,6,
+7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,6,5,4,4,
+4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,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,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,
+4,4,4,4,4,5,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,
+7,7,7,7,7,7,7,7,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,
+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,6,6,6,6,
+6,6,6,6,6,6,6,6,5,5,4,4,4,4,4,4,
+4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,
+3,3,3,24,24,3,3,3,3,3,3,3,3,3,3,3,
+3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
+0,0,0,4,4,4,4,4,4,4,4,4,4,4,5,6,
+6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,
+7,7,7,7,7,7,7,7,7,7,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,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,
+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,7,7,7,7,7,
+7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,
+6,5,4,4,4,4,4,4,4,4,4,0,0,0,0,0,
+0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,
+1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,
+3,3,3,3,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,24,24,24,24,24,24,24,24,24,24,24,24,
+24,24,24,3,3,3,3,3,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,
+1,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,
+4,4,4,4,4,5,6,6,6,6,6,6,6,6,6,6,
+6,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,
+8,8,8,8,8,8,8,8,8,8,8,8,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,
+10,10,10,10,10,10,10,11,11,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,7,7,7,7,7,7,7,7,7,6,
+6,6,6,6,6,6,6,6,5,4,4,4,4,4,4,4,
+4,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
+1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,
+3,3,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,25,25,25,
+25,25,25,25,25,25,25,24,24,24,24,24,24,24,24,24,
+24,24,3,3,3,2,2,2,2,2,2,2,2,2,2,2,
+1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
+0,0,4,4,4,4,4,4,4,4,5,6,6,6,6,6,
+6,6,6,6,7,7,7,7,7,7,7,7,7,7,8,8,
+8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,
+9,9,9,9,9,9,9,9,9,9,11,11,10,10,10,10,
+10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+12,12,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
+10,10,10,10,10,10,10,10,11,9,9,9,9,9,9,9,
+9,9,9,9,8,8,8,8,8,8,8,8,8,8,7,7,
+7,7,7,7,7,7,6,6,6,6,6,6,6,6,5,4,
+4,4,4,4,4,4,0,0,0,0,0,0,0,1,1,1,
+1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,
+3,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,25,25,25,25,25,25,25,25,25,25,25,25,
+25,25,25,25,24,24,24,24,24,24,24,24,3,3,3,2,
+2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,
+0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,6,
+6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,
+8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,
+9,9,9,9,11,10,10,10,10,10,10,10,10,10,10,10,
+10,10,10,10,10,10,10,10,10,10,10,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,10,10,10,10,10,10,10,10,
+10,10,10,11,9,9,9,9,9,9,9,9,8,8,8,8,
+8,8,8,8,7,7,7,7,7,7,7,7,6,6,6,6,
+6,6,5,4,4,4,4,4,4,0,0,0,0,0,0,0,
+1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,
+3,24,24,24,24,24,24,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,26,26,26,26,26,26,26,26,26,26,26,26,26,26,
+26,26,26,25,25,25,25,25,25,25,25,25,25,25,24,24,
+24,24,24,24,3,3,3,2,2,2,2,2,2,2,1,1,
+1,1,1,1,1,0,0,0,0,0,0,0,4,4,4,4,
+4,4,5,6,6,6,6,6,6,6,7,7,7,7,7,7,
+7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,
+9,9,11,10,10,10,10,10,10,10,10,10,10,10,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,12,12,12,12,12,12,12,12,12,12,
+12,12,12,10,10,10,10,10,10,10,10,9,9,9,9,9,
+9,9,9,8,8,8,8,8,8,8,7,7,7,7,7,7,
+6,6,6,6,6,6,5,4,4,4,4,4,0,0,0,0,
+0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,
+3,3,24,24,24,24,24,25,25,25,25,25,25,25,25,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,27,27,27,27,27,27,
+27,27,26,26,26,26,26,26,26,26,26,26,26,25,25,25,
+25,25,25,25,25,24,24,24,24,24,24,3,3,2,2,2,
+2,2,2,1,1,1,1,1,1,1,0,0,0,0,0,0,
+4,4,4,4,4,5,6,6,6,6,6,6,7,7,7,7,
+7,7,7,8,8,8,8,8,8,9,9,9,9,9,9,9,
+9,10,10,10,10,10,10,10,10,10,12,12,12,12,12,12,
+12,12,12,12,12,12,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,13,13,13,13,13,13,13,13,13,13,13,13,13,
+13,12,12,12,12,12,12,12,12,12,10,10,10,10,10,10,
+10,11,9,9,9,9,9,9,8,8,8,8,8,8,7,7,
+7,7,7,7,6,6,6,6,6,6,4,4,4,4,4,0,
+0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,
+2,3,24,24,24,24,24,25,25,25,25,25,25,25,26,26,
+26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,
+27,27,27,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,
+27,27,27,27,27,27,27,27,27,27,27,27,26,26,26,26,
+26,26,26,26,25,25,25,25,25,25,25,24,24,24,24,24,
+3,3,2,2,2,2,2,2,1,1,1,1,1,1,0,0,
+0,0,0,4,4,4,4,4,5,6,6,6,6,6,7,7,
+7,7,7,7,8,8,8,8,8,8,9,9,9,9,9,9,
+9,10,10,10,10,10,10,10,12,12,12,12,12,12,12,12,
+12,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,
+13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,
+12,10,10,10,10,10,10,9,9,9,9,9,9,8,8,8,
+8,8,7,7,7,7,7,7,6,6,6,6,6,4,4,4,
+4,4,0,0,0,0,0,1,1,1,1,1,2,2,2,2,
+2,2,3,24,24,24,24,25,25,25,25,25,25,26,26,26,
+26,26,26,26,26,27,27,27,27,27,27,27,27,29,29,29,
+29,29,28,28,28,28,28,28,28,28,28,28,30,30,30,30,
+30,30,30,30,30,30,30,30,30,30,30,30,28,28,28,28,
+28,28,28,28,28,29,29,29,29,29,29,27,27,27,27,27,
+27,27,27,26,26,26,26,26,26,26,25,25,25,25,25,25,
+25,24,24,24,24,3,2,2,2,2,2,2,1,1,1,1,
+1,0,0,0,0,0,4,4,4,4,4,6,6,6,6,6,
+7,7,7,7,7,8,8,8,8,8,8,9,9,9,9,9,
+9,10,10,10,10,10,10,12,12,12,12,12,12,12,12,13,
+13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,
+15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16,
+16,16,16,16,16,16,16,16,16,16,15,15,15,15,14,14,
+14,14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,
+12,12,12,12,12,12,10,10,10,10,10,11,9,9,9,9,
+9,8,8,8,8,8,7,7,7,7,7,6,6,6,6,5,
+4,4,4,4,0,0,0,0,0,1,1,1,1,1,2,2,
+2,2,2,3,24,24,24,24,25,25,25,25,25,26,26,26,
+26,26,26,26,27,27,27,27,27,27,27,29,29,29,29,28,
+28,28,28,28,30,30,30,30,30,30,30,30,30,30,30,30,
+30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,
+30,30,30,30,30,30,30,30,30,28,28,28,28,28,29,29,
+29,29,27,27,27,27,27,27,27,26,26,26,26,26,26,25,
+25,25,25,25,25,24,24,24,24,3,2,2,2,2,2,1,
+1,1,1,1,0,0,0,0,0,4,4,4,4,6,6,6,
+6,6,7,7,7,7,7,8,8,8,8,8,9,9,9,9,
+9,11,10,10,10,10,10,12,12,12,12,12,12,13,13,13,
+13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,15,
+16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,
+17,17,17,17,17,17,17,17,17,17,16,16,16,16,16,16,
+16,16,16,16,15,15,14,14,14,14,14,14,14,14,13,13,
+13,13,13,13,13,12,12,12,12,12,10,10,10,10,10,11,
+9,9,9,9,8,8,8,8,8,7,7,7,7,7,6,6,
+6,6,4,4,4,4,0,0,0,0,0,1,1,1,1,2,
+2,2,2,2,3,24,24,24,24,25,25,25,25,25,26,26,
+26,26,26,27,27,27,27,27,27,29,29,29,29,28,28,28,
+28,30,30,30,30,30,30,30,30,30,30,31,31,31,31,31,
+31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,
+31,31,31,31,31,31,30,30,30,30,30,30,30,30,30,30,
+30,28,28,28,28,29,29,29,27,27,27,27,27,27,26,26,
+26,26,26,26,25,25,25,25,25,24,24,24,3,3,2,2,
+2,2,1,1,1,1,1,0,0,0,0,4,4,4,4,5,
+6,6,6,6,7,7,7,7,8,8,8,8,8,9,9,9,
+9,9,10,10,10,10,10,12,12,12,12,12,12,13,13,13,
+13,13,13,14,14,14,14,14,14,14,14,15,15,16,16,16,
+16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+17,17,17,17,16,16,16,16,16,16,16,15,15,14,14,14,
+14,14,14,14,13,13,13,13,13,12,12,12,12,12,10,10,
+10,10,10,9,9,9,9,9,8,8,8,8,7,7,7,7,
+6,6,6,6,5,4,4,4,4,0,0,0,0,1,1,1,
+1,2,2,2,2,3,24,24,24,24,25,25,25,25,26,26,
+26,26,26,27,27,27,27,27,27,29,29,29,28,28,28,30,
+30,30,30,30,30,30,30,31,31,31,31,31,31,31,31,31,
+31,31,31,31,31,32,32,32,32,32,32,32,32,32,32,32,
+32,31,31,31,31,31,31,31,31,31,31,31,31,31,31,30,
+30,30,30,30,30,30,30,28,28,28,29,29,29,27,27,27,
+27,27,27,26,26,26,26,26,25,25,25,25,24,24,24,24,
+3,2,2,2,2,1,1,1,1,0,0,0,0,4,4,4,
+4,5,6,6,6,6,7,7,7,7,8,8,8,8,9,9,
+9,9,9,10,10,10,10,10,12,12,12,12,12,13,13,13,
+13,13,14,14,14,14,14,14,14,15,15,16,16,16,16,16,
+17,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,
+18,17,17,17,17,17,17,17,17,17,17,16,16,16,16,16,
+16,15,14,14,14,14,14,14,13,13,13,13,13,12,12,12,
+12,12,10,10,10,10,9,9,9,9,9,8,8,8,8,7,
+7,7,7,6,6,6,6,4,4,4,4,0,0,0,0,1,
+1,1,2,2,2,2,2,3,24,24,24,25,25,25,25,26,
+26,26,26,26,27,27,27,27,27,29,29,28,28,28,30,30,
+30,30,30,30,30,31,31,31,31,31,31,31,31,31,32,32,
+32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
+32,32,32,32,32,32,32,32,32,32,32,32,31,31,31,31,
+31,31,31,31,31,30,30,30,30,30,30,30,28,28,28,29,
+29,27,27,27,27,27,26,26,26,26,26,25,25,25,25,24,
+24,24,24,3,2,2,2,2,1,1,1,1,0,0,0,0,
+4,4,4,5,6,6,6,6,7,7,7,8,8,8,8,8,
+9,9,9,9,10,10,10,10,12,12,12,12,12,13,13,13,
+13,13,14,14,14,14,14,14,15,16,16,16,16,16,16,17,
+17,17,17,17,17,18,18,18,18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,18,18,17,17,17,17,17,17,17,
+17,16,16,16,16,16,15,14,14,14,14,14,13,13,13,13,
+13,12,12,12,12,10,10,10,10,9,9,9,9,8,8,8,
+8,7,7,7,7,6,6,6,6,4,4,4,4,0,0,0,
+1,1,1,1,2,2,2,2,3,24,24,24,25,25,25,25,
+26,26,26,26,27,27,27,27,27,29,29,28,28,28,30,30,
+30,30,30,30,31,31,31,31,31,31,31,32,32,32,32,32,
+32,32,32,32,32,32,32,33,33,33,33,33,33,33,33,33,
+33,33,33,33,33,33,33,33,32,32,32,32,32,32,32,32,
+32,32,32,31,31,31,31,31,31,31,30,30,30,30,30,30,
+28,28,28,29,29,27,27,27,27,27,26,26,26,26,25,25,
+25,25,24,24,24,3,2,2,2,2,1,1,1,1,0,0,
+0,0,4,4,4,5,6,6,6,7,7,7,7,8,8,8,
+8,9,9,9,9,10,10,10,10,12,12,12,12,13,13,13,
+13,13,14,14,14,14,14,15,15,16,16,16,16,16,17,17,
+17,17,17,18,18,18,18,18,18,18,18,18,18,19,19,19,
+19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+19,19,19,19,19,19,18,18,18,18,18,18,18,18,18,17,
+17,17,17,17,17,16,16,16,16,16,15,14,14,14,14,14,
+13,13,13,13,12,12,12,12,10,10,10,10,9,9,9,9,
+8,8,8,8,7,7,7,6,6,6,6,4,4,4,4,0,
+0,0,1,1,1,1,2,2,2,3,24,24,24,25,25,25,
+25,26,26,26,26,27,27,27,27,27,29,29,28,28,30,30,
+30,30,30,30,31,31,31,31,31,31,32,32,32,32,32,32,
+32,32,33,33,33,33,33,33,33,33,33,35,35,35,35,35,
+35,35,35,35,35,35,35,33,33,33,33,33,33,33,33,33,
+32,32,32,32,32,32,32,32,32,31,31,31,31,31,31,30,
+30,30,30,30,28,28,28,29,29,27,27,27,27,26,26,26,
+26,25,25,25,25,24,24,24,3,2,2,2,2,1,1,1,
+0,0,0,0,4,4,4,6,6,6,6,7,7,7,7,8,
+8,8,9,9,9,9,10,10,10,10,12,12,12,12,13,13,
+13,13,13,14,14,14,14,15,15,16,16,16,16,17,17,17,
+17,17,17,18,18,18,18,18,18,18,19,19,19,19,19,19,
+19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+19,19,19,19,19,19,19,19,19,19,19,19,18,18,18,18,
+18,18,18,18,17,17,17,17,17,17,16,16,16,15,15,14,
+14,14,14,13,13,13,13,12,12,12,12,10,10,10,10,9,
+9,9,9,8,8,8,7,7,7,7,6,6,6,4,4,4,
+0,0,0,0,1,1,1,2,2,2,2,3,24,24,24,25,
+25,25,26,26,26,26,27,27,27,27,29,29,28,28,28,30,
+30,30,30,30,31,31,31,31,31,32,32,32,32,32,32,32,
+33,33,33,33,33,33,35,35,35,35,35,34,34,34,34,34,
+34,34,34,34,34,34,34,34,34,34,34,35,35,35,35,35,
+35,33,33,33,33,33,32,32,32,32,32,32,32,31,31,31,
+31,31,31,30,30,30,30,30,28,28,29,29,27,27,27,27,
+26,26,26,26,25,25,25,25,24,24,3,2,2,2,2,1,
+1,1,0,0,0,0,4,4,4,6,6,6,6,7,7,7,
+8,8,8,8,9,9,9,11,10,10,10,12,12,12,12,13,
+13,13,13,14,14,14,14,14,15,16,16,16,16,17,17,17,
+17,17,18,18,18,18,18,18,18,19,19,19,19,19,19,19,
+19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
+20,20,20,20,20,20,20,20,19,19,19,19,19,19,19,19,
+19,18,18,18,18,18,18,18,17,17,17,17,17,16,16,16,
+16,15,14,14,14,14,13,13,13,13,12,12,12,12,10,10,
+10,9,9,9,9,8,8,8,7,7,7,7,6,6,6,4,
+4,4,0,0,0,0,1,1,1,2,2,2,2,24,24,24,
+25,25,25,25,26,26,26,27,27,27,27,29,29,28,28,30,
+30,30,30,30,31,31,31,31,31,32,32,32,32,32,32,33,
+33,33,33,33,35,35,35,34,34,34,34,34,34,34,34,34,
+34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
+34,34,34,35,35,35,35,33,33,33,33,32,32,32,32,32,
+32,31,31,31,31,31,30,30,30,30,30,28,28,29,29,27,
+27,27,27,26,26,26,26,25,25,25,24,24,24,3,2,2,
+2,1,1,1,1,0,0,0,4,4,4,6,6,6,6,7,
+7,7,8,8,8,9,9,9,9,10,10,10,10,12,12,12,
+13,13,13,13,14,14,14,14,14,15,16,16,16,17,17,17,
+17,17,17,18,18,18,18,18,19,19,19,19,19,19,19,19,
+20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21,
+21,21,21,21,21,21,21,21,21,21,20,20,20,20,19,19,
+19,19,19,19,19,19,18,18,18,18,18,18,17,17,17,17,
+17,16,16,16,15,14,14,14,14,13,13,13,13,12,12,12,
+10,10,10,10,9,9,9,8,8,8,8,7,7,7,6,6,
+6,4,4,4,0,0,0,0,1,1,1,2,2,2,3,24,
+24,24,25,25,25,26,26,26,26,27,27,27,29,29,28,28,
+30,30,30,30,30,31,31,31,31,32,32,32,32,32,32,33,
+33,33,33,35,35,35,34,34,34,34,34,34,34,34,34,34,
+34,34,34,34,36,36,36,36,36,36,36,34,34,34,34,34,
+34,34,34,34,34,34,34,34,35,35,35,33,33,33,33,32,
+32,32,32,32,32,31,31,31,31,31,30,30,30,30,28,28,
+29,29,27,27,27,27,26,26,26,25,25,25,25,24,24,3,
+2,2,2,1,1,1,1,0,0,0,4,4,4,6,6,6,
+7,7,7,7,8,8,8,9,9,9,11,10,10,10,12,12,
+12,13,13,13,13,14,14,14,14,15,16,16,16,16,17,17,
+17,17,17,18,18,18,18,18,18,19,19,19,19,19,19,20,
+20,20,20,21,21,21,21,21,21,21,21,22,22,22,22,22,
+22,22,22,22,22,22,22,21,21,21,21,21,21,21,21,20,
+20,20,20,19,19,19,19,19,19,19,18,18,18,18,18,17,
+17,17,17,17,16,16,16,15,14,14,14,14,13,13,13,12,
+12,12,12,10,10,10,9,9,9,9,8,8,8,7,7,7,
+6,6,6,4,4,4,0,0,0,1,1,1,1,2,2,2,
+3,24,24,25,25,25,26,26,26,26,27,27,27,27,29,28,
+28,30,30,30,30,30,31,31,31,31,32,32,32,32,32,33,
+33,33,33,35,35,34,34,34,34,34,34,34,34,34,34,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,34,34,34,34,34,34,34,34,34,35,35,33,
+33,33,33,32,32,32,32,32,31,31,31,31,31,30,30,30,
+30,28,28,29,29,27,27,27,26,26,26,26,25,25,25,24,
+24,24,2,2,2,2,1,1,1,0,0,0,4,4,4,6,
+6,6,7,7,7,8,8,8,8,9,9,9,10,10,10,12,
+12,12,12,13,13,13,13,14,14,14,15,16,16,16,16,17,
+17,17,17,17,18,18,18,18,18,19,19,19,19,19,19,20,
+20,20,21,21,21,21,21,21,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,21,21,
+21,21,21,21,20,20,20,19,19,19,19,19,19,18,18,18,
+18,18,17,17,17,17,17,16,16,16,15,14,14,14,13,13,
+13,13,12,12,12,10,10,10,11,9,9,9,8,8,8,7,
+7,7,6,6,6,4,4,4,0,0,0,1,1,1,2,2,
+2,2,24,24,24,25,25,25,26,26,26,27,27,27,27,29,
+29,28,28,30,30,30,30,31,31,31,31,32,32,32,32,32,
+33,33,33,35,35,35,34,34,34,34,34,34,34,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,34,34,34,34,34,34,34,
+34,35,35,33,33,33,32,32,32,32,32,31,31,31,31,31,
+30,30,30,30,28,28,29,27,27,27,27,26,26,26,25,25,
+25,24,24,24,3,2,2,2,1,1,1,0,0,0,4,4,
+4,6,6,6,7,7,7,8,8,8,9,9,9,9,10,10,
+10,12,12,12,13,13,13,13,14,14,14,14,15,16,16,16,
+16,17,17,17,17,18,18,18,18,18,19,19,19,19,19,19,
+20,20,21,21,21,21,21,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,21,21,21,21,21,20,20,20,19,19,19,19,19,
+18,18,18,18,18,17,17,17,17,16,16,16,15,14,14,14,
+14,13,13,13,12,12,12,12,10,10,10,9,9,9,8,8,
+8,7,7,7,6,6,6,5,4,4,0,0,0,1,1,1,
+2,2,2,3,24,24,24,25,25,25,26,26,26,27,27,27,
+29,29,28,28,30,30,30,30,31,31,31,31,32,32,32,32,
+32,33,33,33,35,35,34,34,34,34,34,34,34,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,34,34,34,
+34,34,34,34,35,35,33,33,33,32,32,32,32,32,31,31,
+31,31,30,30,30,30,28,28,29,29,27,27,27,26,26,26,
+25,25,25,25,24,24,3,2,2,2,1,1,1,0,0,0,
+4,4,4,6,6,6,7,7,7,8,8,8,9,9,9,11,
+10,10,10,12,12,12,13,13,13,14,14,14,14,15,16,16,
+16,16,17,17,17,17,18,18,18,18,18,19,19,19,19,19,
+20,20,20,21,21,21,21,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,21,21,21,21,20,20,20,19,19,
+19,19,19,18,18,18,18,18,17,17,17,17,16,16,16,15,
+14,14,14,13,13,13,13,12,12,12,10,10,10,9,9,9,
+8,8,8,7,7,7,6,6,6,5,4,4,0,0,0,1,
+1,1,2,2,2,3,24,24,25,25,25,26,26,26,26,27,
+27,27,29,29,28,28,30,30,30,31,31,31,31,32,32,32,
+32,32,33,33,33,35,35,34,34,34,34,34,34,36,36,36,
+36,36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,36,36,36,36,36,36,36,36,36,36,
+36,34,34,34,34,34,34,35,35,33,33,33,32,32,32,32,
+32,31,31,31,31,30,30,30,30,28,28,29,27,27,27,27,
+26,26,26,25,25,25,24,24,3,2,2,2,1,1,1,0,
+0,0,4,4,4,6,6,6,7,7,7,8,8,8,9,9,
+9,10,10,10,12,12,12,12,13,13,13,14,14,14,14,16,
+15,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,
+19,19,20,20,21,21,21,21,22,22,22,22,22,22,22,22,
+22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,22,
+22,22,22,22,22,22,22,22,22,22,21,21,21,21,20,20,
+20,19,19,19,19,19,18,18,18,18,17,17,17,17,16,16,
+16,15,14,14,14,14,13,13,13,12,12,12,10,10,10,9,
+9,9,8,8,8,7,7,7,6,6,6,5,4,4,0,0,
+0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,26,
+27,27,27,27,29,28,28,30,30,30,30,31,31,31,31,32,
+32,32,32,33,33,33,35,35,34,34,34,34,34,34,36,36,
+36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,36,36,36,36,36,
+36,36,36,36,34,34,34,34,34,34,35,35,33,33,33,32,
+32,32,32,31,31,31,31,30,30,30,30,28,28,29,29,27,
+27,27,26,26,26,25,25,25,24,24,3,2,2,2,1,1,
+1,0,0,0,4,4,4,6,6,6,7,7,7,8,8,8,
+9,9,9,10,10,10,12,12,12,13,13,13,13,14,14,14,
+14,14,15,16,16,16,17,17,17,17,18,18,18,18,19,19,
+19,19,19,20,20,21,21,21,21,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,23,22,22,22,22,22,22,22,22,22,21,21,21,
+21,20,20,19,19,19,19,19,18,18,18,18,18,17,17,17,
+17,16,16,16,15,14,14,14,13,13,13,12,12,12,10,10,
+10,11,9,9,9,8,8,8,7,7,6,6,6,5,4,4,
+0,0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,
+26,26,27,27,27,27,29,28,28,30,30,30,30,31,31,31,
+31,32,32,32,32,33,33,33,35,35,34,34,34,34,34,36,
+36,36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,
+33,33,32,32,32,32,31,31,31,31,30,30,30,28,28,29,
+29,27,27,27,26,26,26,25,25,25,24,24,24,2,2,2,
+1,1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,
+8,8,9,9,9,10,10,10,12,12,12,13,13,13,14,14,
+14,14,14,14,15,16,16,17,17,17,17,18,18,18,18,18,
+19,19,19,19,19,20,20,21,21,21,21,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,23,23,23,22,22,22,22,22,22,22,22,22,
+21,21,21,21,20,20,19,19,19,19,19,18,18,18,18,17,
+17,17,17,16,16,16,15,14,14,14,13,13,13,13,12,12,
+12,10,10,10,9,9,9,8,8,8,7,7,7,6,6,6,
+4,4,0,0,0,1,1,1,2,2,2,3,24,24,25,25,
+25,26,26,26,27,27,27,27,29,28,28,30,30,30,30,31,
+31,31,32,32,32,32,32,33,33,35,35,34,34,34,34,34,
+34,36,36,36,36,36,36,36,36,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,36,36,36,36,36,36,36,36,34,34,34,34,34,35,
+35,33,33,33,32,32,32,32,31,31,31,31,30,30,30,30,
+28,28,29,27,27,27,26,26,26,25,25,25,25,24,24,3,
+2,2,1,1,1,0,0,0,4,4,4,6,6,6,7,7,
+7,8,8,8,9,9,9,10,10,10,12,12,12,13,13,13,
+13,13,14,14,14,14,15,16,16,17,17,17,17,18,18,18,
+18,18,19,19,19,19,20,20,20,21,21,21,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,23,23,23,23,23,22,22,22,22,22,22,
+22,22,22,21,21,21,20,20,20,19,19,19,19,18,18,18,
+18,18,17,17,17,17,16,16,15,14,14,14,14,13,13,13,
+12,12,12,10,10,10,9,9,9,8,8,8,7,7,7,6,
+6,6,4,4,4,0,0,1,1,1,2,2,2,3,24,24,
+25,25,25,26,26,26,27,27,27,27,29,28,28,30,30,30,
+30,31,31,31,32,32,32,32,33,33,33,35,35,34,34,34,
+34,34,34,36,36,36,36,36,36,36,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,36,36,36,36,36,36,36,34,34,34,34,
+34,34,35,35,33,33,33,32,32,32,32,31,31,31,30,30,
+30,30,28,28,29,27,27,27,27,26,26,26,25,25,25,24,
+24,3,2,2,2,1,1,1,0,0,4,4,4,6,6,6,
+7,7,7,8,8,8,9,9,9,10,10,10,12,12,12,13,
+12,13,13,13,13,14,14,14,15,16,16,16,17,17,17,18,
+18,18,18,18,19,19,19,19,20,20,20,21,21,21,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,23,23,23,23,23,23,22,22,22,
+22,22,22,22,22,21,21,21,21,20,20,19,19,19,19,19,
+18,18,18,18,17,17,17,17,16,16,16,14,14,14,14,13,
+13,13,12,12,12,10,10,10,9,9,9,8,8,8,7,7,
+7,6,6,6,4,4,4,0,0,0,1,1,1,2,2,3,
+24,24,25,25,25,26,26,26,26,27,27,27,29,28,28,30,
+30,30,30,31,31,31,32,32,32,32,32,33,33,35,35,34,
+34,34,34,34,34,36,36,36,36,36,36,36,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,36,36,36,36,36,36,36,36,34,
+34,34,34,34,35,35,33,33,33,32,32,32,32,31,31,31,
+31,30,30,30,28,28,29,29,27,27,27,26,26,26,25,25,
+25,24,24,3,2,2,2,1,1,1,0,0,0,4,4,6,
+6,6,7,7,7,8,8,8,9,9,9,10,10,10,12,12,
+12,12,12,12,13,13,13,14,14,14,15,16,16,16,17,17,
+17,17,18,18,18,18,19,19,19,19,19,20,20,21,21,21,
+21,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,22,
+22,22,22,22,22,22,22,21,21,21,21,20,20,19,19,19,
+19,19,18,18,18,18,17,17,17,17,16,16,16,15,14,14,
+14,13,13,13,12,12,12,10,10,10,11,9,9,8,8,8,
+7,7,7,6,6,6,4,4,4,0,0,0,1,1,1,2,
+2,2,3,24,24,25,25,25,26,26,26,27,27,27,29,28,
+28,30,30,30,30,31,31,31,31,32,32,32,32,33,33,33,
+35,34,34,34,34,34,34,36,36,36,36,36,36,36,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,36,36,36,36,36,36,
+36,34,34,34,34,34,35,35,33,33,33,32,32,32,32,31,
+31,31,31,30,30,30,30,28,29,29,27,27,27,26,26,26,
+25,25,25,24,24,3,2,2,2,1,1,1,0,0,0,4,
+4,5,6,6,6,7,7,7,8,8,9,9,9,11,10,10,
+10,10,10,12,12,12,13,13,13,14,14,14,14,16,16,16,
+17,17,17,17,18,18,18,18,19,19,19,19,19,20,20,21,
+21,21,21,22,22,22,22,22,22,22,22,23,23,23,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,22,22,22,22,22,22,22,22,22,21,21,21,20,20,19,
+19,19,19,19,18,18,18,18,17,17,17,17,16,16,16,15,
+14,14,14,13,13,13,13,12,12,12,10,10,10,9,9,9,
+8,8,8,7,7,7,6,6,5,4,4,0,0,0,1,1,
+1,2,2,2,3,24,24,25,25,25,26,26,26,27,27,27,
+29,29,28,28,30,30,30,31,31,31,31,32,32,32,32,33,
+33,33,35,35,34,34,34,34,34,36,36,36,36,36,36,36,
+36,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,36,36,36,36,
+36,36,36,34,34,34,34,34,34,35,35,33,33,32,32,32,
+32,31,31,31,31,30,30,30,30,28,28,29,27,27,27,26,
+26,26,26,25,25,25,24,24,3,2,2,1,1,1,0,0,
+0,4,4,4,6,6,6,7,7,7,8,8,8,9,9,9,
+9,9,10,10,10,12,12,12,13,13,13,13,14,14,14,15,
+16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,19,
+20,20,21,21,21,21,22,22,22,22,22,22,22,22,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,22,22,22,22,22,22,22,22,22,21,21,21,20,
+20,20,19,19,19,19,18,18,18,18,18,17,17,17,17,16,
+16,15,14,14,14,14,13,13,13,12,12,12,10,10,10,9,
+9,9,8,8,8,7,7,7,6,6,6,4,4,4,0,0,
+0,1,1,1,2,2,3,24,24,25,25,25,26,26,26,26,
+27,27,27,29,28,28,30,30,30,30,31,31,31,31,32,32,
+32,32,33,33,33,35,34,34,34,34,34,34,36,36,36,36,
+36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,36,
+36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,33,
+32,32,32,32,31,31,31,31,30,30,30,28,28,29,27,27,
+27,27,26,26,26,25,25,25,24,24,3,2,2,2,1,1,
+1,0,0,0,4,4,6,6,6,7,7,7,8,8,8,9,
+8,8,9,9,9,10,10,10,12,12,12,13,13,13,14,14,
+14,14,16,16,16,17,17,17,17,18,18,18,18,18,19,19,
+19,19,20,20,20,21,21,21,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,23,23,23,22,22,22,22,22,22,22,22,22,21,21,
+21,20,20,20,19,19,19,19,19,18,18,18,18,17,17,17,
+17,16,16,16,15,14,14,14,13,13,13,12,12,12,10,10,
+10,9,9,9,8,8,8,7,7,7,6,6,6,5,4,4,
+0,0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,
+26,26,27,27,27,29,29,28,28,30,30,30,31,31,31,31,
+32,32,32,32,33,33,33,35,35,34,34,34,34,34,34,36,
+36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,
+33,33,32,32,32,32,31,31,31,31,30,30,30,28,28,29,
+29,27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,
+1,1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,
+7,8,8,8,9,9,9,10,10,10,12,12,12,12,13,13,
+13,14,14,14,15,16,16,16,17,17,17,17,18,18,18,18,
+19,19,19,19,19,20,20,20,21,21,21,21,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,23,22,22,22,22,22,22,22,22,22,22,
+21,21,21,20,20,20,19,19,19,19,19,18,18,18,18,17,
+17,17,17,16,16,16,15,14,14,14,13,13,13,13,12,12,
+12,10,10,10,9,9,9,8,8,8,7,7,7,6,6,6,
+4,4,4,0,0,0,1,1,1,2,2,3,24,24,25,25,
+25,25,26,26,26,27,27,27,29,29,28,30,30,30,30,31,
+31,31,31,32,32,32,32,33,33,33,35,35,34,34,34,34,
+34,34,36,36,36,36,36,36,36,36,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,36,36,36,36,36,36,36,36,34,34,34,34,34,34,35,
+35,33,33,33,32,32,32,32,31,31,31,31,30,30,30,30,
+28,28,29,27,27,27,26,26,26,26,25,25,25,24,24,3,
+2,2,2,1,1,1,0,0,4,4,4,6,6,6,7,7,
+6,7,7,7,8,8,8,9,9,9,10,10,10,12,12,12,
+13,13,13,13,14,14,14,15,16,16,16,17,17,17,17,18,
+18,18,18,19,19,19,19,19,20,20,20,21,21,21,21,22,
+22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,
+23,23,23,23,23,23,23,22,22,22,22,22,22,22,22,22,
+22,21,21,21,21,20,20,20,19,19,19,19,19,18,18,18,
+18,17,17,17,17,16,16,16,15,14,14,14,14,13,13,13,
+12,12,12,10,10,10,9,9,9,8,8,8,7,7,7,6,
+6,6,5,4,4,0,0,0,1,1,1,2,2,2,3,24,
+24,25,25,25,26,26,26,27,27,27,27,29,28,28,30,30,
+30,30,31,31,31,31,32,32,32,32,33,33,33,35,35,34,
+34,34,34,34,34,36,36,36,36,36,36,36,36,36,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,36,36,36,36,36,36,36,36,34,34,34,34,34,
+34,35,35,33,33,33,32,32,32,32,31,31,31,31,30,30,
+30,30,28,28,29,29,27,27,27,26,26,26,25,25,25,24,
+24,3,2,2,2,1,1,1,0,0,0,4,4,4,6,6,
+5,6,6,6,7,7,7,8,8,8,9,9,9,10,10,10,
+12,12,12,13,13,13,14,14,14,14,15,16,16,16,17,17,
+17,17,18,18,18,18,19,19,19,19,19,19,20,20,21,21,
+21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,23,
+23,23,23,23,23,23,23,22,22,22,22,22,22,22,22,22,
+22,22,22,21,21,21,21,20,20,20,19,19,19,19,19,18,
+18,18,18,18,17,17,17,17,16,16,16,15,14,14,14,13,
+13,13,12,12,12,12,10,10,10,9,9,9,8,8,8,7,
+7,7,6,6,6,4,4,4,0,0,0,1,1,1,2,2,
+2,3,24,24,25,25,25,26,26,26,27,27,27,27,29,28,
+28,30,30,30,30,31,31,31,31,32,32,32,32,33,33,33,
+35,35,34,34,34,34,34,34,36,36,36,36,36,36,36,36,
+36,36,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,36,36,36,36,36,36,36,36,36,34,34,34,
+34,34,34,35,35,33,33,33,32,32,32,32,32,31,31,31,
+31,30,30,30,28,28,29,29,27,27,27,26,26,26,26,25,
+25,25,24,24,3,2,2,2,1,1,1,0,0,0,4,4,
+4,4,4,6,6,6,7,7,7,8,8,8,9,9,9,11,
+10,10,10,12,12,12,13,13,13,14,14,14,14,15,16,16,
+16,17,17,17,17,18,18,18,18,19,19,19,19,19,19,20,
+20,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,21,21,21,21,20,20,20,19,19,19,19,
+19,18,18,18,18,18,17,17,17,17,16,16,16,15,14,14,
+14,14,13,13,13,12,12,12,10,10,10,9,9,9,9,8,
+8,8,7,7,7,6,6,6,4,4,4,0,0,0,1,1,
+1,2,2,2,24,24,24,25,25,25,26,26,26,27,27,27,
+29,29,28,28,30,30,30,30,31,31,31,31,32,32,32,32,
+33,33,33,35,35,34,34,34,34,34,34,34,36,36,36,36,
+36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,36,36,36,36,36,36,36,36,36,36,34,
+34,34,34,34,34,34,35,35,33,33,33,32,32,32,32,31,
+31,31,31,30,30,30,30,28,28,29,27,27,27,27,26,26,
+26,25,25,25,24,24,3,2,2,2,1,1,1,0,0,0,
+0,0,0,4,4,4,6,6,6,7,7,7,8,8,8,9,
+9,9,11,10,10,10,12,12,12,13,13,13,14,14,14,14,
+15,16,16,16,17,17,17,17,18,18,18,18,18,19,19,19,
+19,19,20,20,20,21,21,21,21,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,21,21,21,21,21,20,20,19,19,
+19,19,19,19,18,18,18,18,17,17,17,17,17,16,16,16,
+15,14,14,14,13,13,13,13,12,12,12,10,10,10,9,9,
+9,8,8,8,7,7,7,6,6,6,5,4,4,0,0,0,
+1,1,1,2,2,2,3,24,24,24,25,25,25,26,26,26,
+27,27,27,29,29,28,28,30,30,30,30,31,31,31,31,32,
+32,32,32,33,33,33,33,35,35,34,34,34,34,34,34,36,
+36,36,36,36,36,36,36,36,36,36,36,36,37,37,37,37,
+37,37,37,37,37,36,36,36,36,36,36,36,36,36,36,36,
+36,34,34,34,34,34,34,34,35,35,33,33,33,32,32,32,
+32,32,31,31,31,31,30,30,30,28,28,29,29,27,27,27,
+26,26,26,26,25,25,25,24,24,3,2,2,2,1,1,1,
+1,1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,
+8,8,9,9,9,10,10,10,12,12,12,12,13,13,13,14,
+14,14,14,15,16,16,16,17,17,17,17,18,18,18,18,18,
+19,19,19,19,19,19,20,20,21,21,21,21,21,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,21,21,21,21,21,20,20,
+19,19,19,19,19,19,18,18,18,18,18,17,17,17,17,16,
+16,16,15,14,14,14,14,13,13,13,12,12,12,12,10,10,
+10,9,9,9,8,8,8,7,7,7,6,6,6,4,4,4,
+0,0,0,1,1,1,2,2,2,3,24,24,25,25,25,25,
+26,26,26,27,27,27,29,29,28,28,30,30,30,30,31,31,
+31,31,32,32,32,32,32,33,33,33,35,35,34,34,34,34,
+34,34,34,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,34,34,34,34,34,34,34,35,35,33,33,33,32,
+32,32,32,32,31,31,31,31,30,30,30,30,28,28,29,29,
+27,27,27,26,26,26,25,25,25,25,24,24,3,2,2,2,
+2,2,2,1,1,1,0,0,0,4,4,5,6,6,6,7,
+7,7,8,8,8,9,9,9,10,10,10,12,12,12,12,13,
+13,13,14,14,14,14,15,16,16,16,17,17,17,17,18,18,
+18,18,18,19,19,19,19,19,19,20,20,20,21,21,21,21,
+21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,21,21,21,21,21,21,
+20,20,20,19,19,19,19,19,18,18,18,18,18,17,17,17,
+17,17,16,16,16,15,14,14,14,13,13,13,13,12,12,12,
+10,10,10,11,9,9,9,8,8,8,7,7,7,6,6,6,
+4,4,4,0,0,0,1,1,1,2,2,2,3,24,24,25,
+25,25,25,26,26,26,27,27,27,29,29,28,28,30,30,30,
+30,31,31,31,31,32,32,32,32,32,33,33,33,35,35,35,
+34,34,34,34,34,34,34,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,34,34,34,34,34,34,34,35,35,33,33,
+33,33,32,32,32,32,31,31,31,31,31,30,30,30,30,28,
+28,29,27,27,27,27,26,26,26,25,25,25,24,24,24,3,
+24,3,2,2,2,1,1,1,1,0,0,0,4,4,5,6,
+6,6,7,7,7,8,8,8,9,9,9,10,10,10,10,12,
+12,12,13,13,13,14,14,14,14,15,16,16,16,17,17,17,
+17,17,18,18,18,18,18,19,19,19,19,19,19,20,20,20,
+21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,21,21,21,21,
+21,21,20,20,20,19,19,19,19,19,19,18,18,18,18,18,
+17,17,17,17,16,16,16,15,14,14,14,14,13,13,13,13,
+12,12,12,10,10,10,9,9,9,9,8,8,8,7,7,7,
+6,6,6,4,4,4,0,0,0,1,1,1,2,2,2,3,
+24,24,25,25,25,25,26,26,26,27,27,27,27,29,28,28,
+30,30,30,30,31,31,31,31,32,32,32,32,32,33,33,33,
+33,35,35,34,34,34,34,34,34,34,34,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,34,34,34,34,34,34,34,34,35,
+35,33,33,33,32,32,32,32,32,31,31,31,31,30,30,30,
+30,28,28,29,29,27,27,27,27,26,26,26,25,25,25,24,
+25,25,24,24,3,2,2,2,1,1,1,0,0,0,0,4,
+4,5,6,6,6,7,7,7,8,8,8,9,9,9,10,10,
+10,10,12,12,12,13,13,13,13,14,14,14,15,16,16,16,
+17,17,17,17,17,18,18,18,18,18,19,19,19,19,19,19,
+20,20,20,21,21,21,21,21,21,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,21,21,
+21,21,21,21,20,20,20,19,19,19,19,19,19,18,18,18,
+18,18,18,17,17,17,17,16,16,16,15,14,14,14,14,13,
+13,13,12,12,12,12,10,10,10,9,9,9,8,8,8,8,
+7,7,7,6,6,6,4,4,4,0,0,0,1,1,1,2,
+2,2,3,24,24,25,25,25,25,26,26,26,27,27,27,27,
+29,28,28,30,30,30,30,31,31,31,31,31,32,32,32,32,
+32,33,33,33,35,35,34,34,34,34,34,34,34,34,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,34,34,34,34,34,34,34,
+34,35,35,33,33,33,33,32,32,32,32,32,31,31,31,31,
+30,30,30,30,28,28,29,29,27,27,27,26,26,26,26,25,
+26,26,25,25,25,24,24,3,2,2,2,1,1,1,0,0,
+0,0,4,4,5,6,6,6,7,7,7,8,8,8,9,9,
+9,11,10,10,10,12,12,12,13,13,13,13,14,14,14,14,
+16,16,16,16,17,17,17,17,18,18,18,18,18,19,19,19,
+19,19,19,19,20,20,20,21,21,21,21,21,21,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+21,21,21,21,21,21,20,20,20,20,19,19,19,19,19,19,
+18,18,18,18,18,17,17,17,17,17,16,16,16,15,14,14,
+14,14,13,13,13,12,12,12,12,10,10,10,9,9,9,8,
+8,8,7,7,7,7,6,6,6,4,4,4,0,0,0,1,
+1,1,2,2,2,3,24,24,25,25,25,25,26,26,26,27,
+27,27,27,29,28,28,28,30,30,30,30,31,31,31,31,32,
+32,32,32,32,33,33,33,35,35,35,34,34,34,34,34,34,
+34,34,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,34,34,34,34,34,
+34,34,34,35,35,35,33,33,33,32,32,32,32,32,31,31,
+31,31,31,30,30,30,30,28,28,29,29,27,27,27,26,26,
+27,26,26,26,25,25,25,25,24,24,3,2,2,2,1,1,
+1,0,0,0,4,4,4,5,6,6,6,7,7,7,8,8,
+8,9,9,9,11,10,10,10,12,12,12,13,13,13,13,14,
+14,14,14,15,16,16,16,17,17,17,17,18,18,18,18,18,
+18,19,19,19,19,19,19,20,20,20,21,21,21,21,21,21,
+21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,21,21,21,21,21,21,21,20,20,20,19,19,19,19,
+19,19,19,18,18,18,18,18,17,17,17,17,17,16,16,16,
+15,14,14,14,14,13,13,13,12,12,12,12,10,10,10,9,
+9,9,8,8,8,7,7,7,7,6,6,6,4,4,4,0,
+0,0,1,1,1,2,2,2,3,24,24,24,25,25,25,26,
+26,26,27,27,27,27,29,29,28,28,30,30,30,30,31,31,
+31,31,32,32,32,32,32,33,33,33,33,35,35,34,34,34,
+34,34,34,34,34,34,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,34,34,
+34,34,34,34,34,34,35,35,35,33,33,33,32,32,32,32,
+32,31,31,31,31,31,30,30,30,30,28,28,29,27,27,27,
+27,27,27,27,26,26,26,25,25,25,25,24,24,3,2,2,
+2,1,1,1,0,0,0,4,4,4,5,6,6,6,7,7,
+7,8,8,8,9,9,9,11,10,10,10,12,12,12,13,13,
+13,13,14,14,14,14,15,16,16,16,17,17,17,17,18,18,
+18,18,18,18,19,19,19,19,19,19,20,20,20,20,21,21,
+21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,21,21,21,21,21,21,21,20,20,20,19,
+19,19,19,19,19,19,18,18,18,18,18,17,17,17,17,16,
+16,16,16,15,14,14,14,13,13,13,13,12,12,12,12,10,
+10,10,9,9,9,8,8,8,7,7,7,7,6,6,6,4,
+4,4,0,0,0,1,1,1,2,2,2,3,24,24,24,25,
+25,25,26,26,26,27,27,27,27,29,29,28,28,30,30,30,
+30,31,31,31,31,32,32,32,32,32,33,33,33,33,35,35,
+34,34,34,34,34,34,34,34,34,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+34,34,34,34,34,34,34,34,34,35,35,33,33,33,33,32,
+32,32,32,32,31,31,31,31,30,30,30,30,30,28,28,29,
+28,28,29,27,27,27,27,26,26,26,25,25,25,25,24,24,
+3,2,2,2,1,1,1,0,0,0,4,4,4,5,6,6,
+6,7,7,7,8,8,8,9,9,9,11,10,10,10,12,12,
+12,13,13,13,13,14,14,14,14,15,16,16,16,17,17,17,
+17,17,18,18,18,18,18,19,19,19,19,19,19,20,20,20,
+20,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,21,21,21,21,21,21,21,20,20,
+20,20,19,19,19,19,19,19,18,18,18,18,18,18,17,17,
+17,17,16,16,16,15,14,14,14,14,13,13,13,13,12,12,
+12,10,10,10,10,9,9,9,8,8,8,7,7,7,7,6,
+6,6,4,4,4,0,0,0,1,1,1,2,2,2,3,24,
+24,24,25,25,25,26,26,26,27,27,27,27,29,29,28,28,
+30,30,30,30,31,31,31,31,32,32,32,32,32,33,33,33,
+33,35,35,35,34,34,34,34,34,34,34,34,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,34,34,34,34,34,34,34,34,34,35,35,33,33,
+33,33,32,32,32,32,32,31,31,31,31,30,30,30,30,28,
+30,30,28,28,28,29,27,27,27,27,26,26,26,25,25,25,
+25,24,24,3,2,2,2,1,1,1,0,0,0,4,4,4,
+6,6,6,6,7,7,7,8,8,8,9,9,9,11,10,10,
+10,12,12,12,13,13,13,13,14,14,14,14,15,16,16,16,
+17,17,17,17,18,18,18,18,18,18,19,19,19,19,19,19,
+20,20,20,20,21,21,21,21,21,21,21,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,21,21,21,21,21,21,
+21,20,20,20,20,19,19,19,19,19,19,18,18,18,18,18,
+18,17,17,17,17,16,16,16,15,14,14,14,14,13,13,13,
+13,12,12,12,10,10,10,10,9,9,9,8,8,8,7,7,
+7,6,6,6,6,4,4,4,0,0,0,1,1,1,2,2,
+2,3,24,24,25,25,25,25,26,26,26,27,27,27,27,29,
+29,28,28,30,30,30,30,31,31,31,31,32,32,32,32,32,
+33,33,33,33,35,35,34,34,34,34,34,34,34,34,34,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,34,34,34,34,34,34,34,34,34,35,
+35,33,33,33,33,32,32,32,32,32,31,31,31,31,30,30,
+31,30,30,30,30,28,28,29,29,27,27,27,27,26,26,26,
+25,25,25,24,24,24,3,2,2,2,1,1,1,0,0,0,
+4,4,4,6,6,6,6,7,7,7,8,8,8,9,9,9,
+10,10,10,10,12,12,12,13,13,13,13,14,14,14,14,16,
+16,16,16,17,17,17,17,18,18,18,18,18,18,19,19,19,
+19,19,19,20,20,20,20,21,21,21,21,21,21,21,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,21,21,21,
+21,21,21,21,20,20,20,20,19,19,19,19,19,19,18,18,
+18,18,18,18,17,17,17,17,16,16,16,15,14,14,14,14,
+13,13,13,13,12,12,12,10,10,10,11,9,9,9,8,8,
+8,7,7,7,6,6,6,5,4,4,4,0,0,0,1,1,
+1,2,2,2,3,24,24,25,25,25,25,26,26,26,27,27,
+27,27,29,28,28,28,30,30,30,30,31,31,31,31,32,32,
+32,32,32,33,33,33,33,35,35,34,34,34,34,34,34,34,
+34,34,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,34,34,34,34,34,34,34,
+34,34,35,35,33,33,33,33,32,32,32,32,32,31,31,31,
+31,31,31,31,30,30,30,30,28,28,29,29,27,27,27,27,
+26,26,26,25,25,25,24,24,24,3,2,2,2,1,1,1,
+0,0,0,4,4,4,6,6,6,7,7,7,8,8,8,8,
+9,9,9,10,10,10,12,12,12,12,13,13,13,14,14,14,
+14,15,16,16,16,17,17,17,17,17,18,18,18,18,18,19,
+19,19,19,19,19,19,20,20,20,21,21,21,21,21,21,21,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,21,21,21,21,21,21,20,20,20,20,19,19,19,19,19,
+19,18,18,18,18,18,18,17,17,17,17,16,16,16,15,14,
+14,14,14,13,13,13,13,12,12,12,10,10,10,11,9,9,
+9,8,8,8,7,7,7,6,6,6,5,4,4,0,0,0,
+0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,26,
+26,27,27,27,29,29,28,28,30,30,30,30,31,31,31,31,
+31,32,32,32,32,32,33,33,33,35,35,35,34,34,34,34,
+34,34,34,34,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,34,34,34,34,
+34,34,34,34,34,35,35,33,33,33,33,32,32,32,32,32,
+32,32,32,31,31,31,31,30,30,30,30,28,28,29,29,27,
+27,27,26,26,26,26,25,25,25,24,24,24,2,2,2,2,
+1,1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,
+8,8,9,9,9,9,10,10,10,12,12,12,13,13,13,13,
+14,14,14,14,15,16,16,16,17,17,17,17,17,18,18,18,
+18,18,19,19,19,19,19,19,20,20,20,21,21,21,21,21,
+21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,21,21,21,21,21,21,21,20,20,20,19,19,
+19,19,19,19,18,18,18,18,18,17,17,17,17,17,16,16,
+16,15,14,14,14,14,13,13,13,13,12,12,12,10,10,10,
+9,9,9,9,8,8,8,7,7,7,6,6,6,4,4,4,
+0,0,0,1,1,1,2,2,2,2,24,24,24,25,25,25,
+26,26,26,26,27,27,27,29,29,28,28,30,30,30,30,31,
+31,31,31,32,32,32,32,32,33,33,33,33,35,35,34,34,
+34,34,34,34,34,34,34,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,34,
+34,34,34,34,34,34,34,34,35,35,33,33,33,33,32,32,
+33,32,32,32,32,32,31,31,31,31,30,30,30,30,28,28,
+29,29,27,27,27,26,26,26,26,25,25,25,24,24,3,2,
+2,2,1,1,1,0,0,0,4,4,4,5,6,6,6,7,
+7,7,8,8,8,9,9,9,10,10,10,10,12,12,12,13,
+13,13,13,14,14,14,15,16,16,16,17,17,17,17,17,18,
+18,18,18,18,19,19,19,19,19,19,20,20,20,20,21,21,
+21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,21,21,21,21,21,21,20,20,
+20,19,19,19,19,19,19,18,18,18,18,18,17,17,17,17,
+17,16,16,16,15,14,14,14,14,13,13,13,12,12,12,12,
+10,10,10,9,9,9,8,8,8,7,7,7,7,6,6,6,
+4,4,4,0,0,0,1,1,1,2,2,2,3,24,24,25,
+25,25,25,26,26,26,27,27,27,27,29,28,28,30,30,30,
+30,31,31,31,31,31,32,32,32,32,32,33,33,33,35,35,
+35,34,34,34,34,34,34,34,34,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,34,34,34,34,34,34,34,34,35,35,33,33,33,
+33,33,33,33,32,32,32,32,31,31,31,31,31,30,30,30,
+30,28,28,29,27,27,27,27,26,26,26,25,25,25,25,24,
+24,3,2,2,2,1,1,1,0,0,0,4,4,4,6,6,
+6,7,7,7,8,8,8,8,9,9,9,10,10,10,12,12,
+12,13,13,13,13,14,14,14,14,15,16,16,16,17,17,17,
+17,18,18,18,18,18,19,19,19,19,19,19,20,20,20,21,
+21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,21,21,21,21,21,
+21,20,20,20,19,19,19,19,19,19,18,18,18,18,18,17,
+17,17,17,17,16,16,16,15,14,14,14,13,13,13,13,12,
+12,12,10,10,10,10,9,9,9,8,8,8,7,7,7,6,
+6,6,5,4,4,0,0,0,1,1,1,1,2,2,2,3,
+24,24,25,25,25,26,26,26,26,27,27,27,29,29,28,28,
+30,30,30,30,31,31,31,31,32,32,32,32,32,33,33,33,
+35,35,35,34,34,34,34,34,34,34,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,34,34,34,34,34,34,34,34,35,35,
+34,35,35,33,33,33,32,32,32,32,32,31,31,31,31,30,
+30,30,30,28,28,29,29,27,27,27,26,26,26,26,25,25,
+25,24,24,3,2,2,2,1,1,1,0,0,0,0,4,4,
+5,6,6,6,7,7,7,8,8,8,9,9,9,10,10,10,
+12,12,12,12,13,13,13,14,14,14,14,15,16,16,16,17,
+17,17,17,18,18,18,18,18,19,19,19,19,19,19,20,20,
+20,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,21,
+21,21,21,21,20,20,20,19,19,19,19,19,19,18,18,18,
+18,18,17,17,17,17,16,16,16,15,14,14,14,14,13,13,
+13,13,12,12,12,10,10,10,9,9,9,8,8,8,8,7,
+7,7,6,6,6,4,4,4,0,0,0,1,1,1,2,2,
+2,3,24,24,25,25,25,25,26,26,26,27,27,27,29,29,
+28,28,30,30,30,30,31,31,31,31,32,32,32,32,32,33,
+33,33,35,35,35,34,34,34,34,34,34,34,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,34,34,34,34,34,34,34,
+34,34,34,34,35,35,33,33,33,32,32,32,32,32,31,31,
+31,31,30,30,30,30,28,28,29,29,27,27,27,26,26,26,
+25,25,25,25,24,24,3,2,2,2,1,1,1,0,0,0,
+4,4,4,6,6,6,7,7,7,8,8,8,9,9,9,11,
+10,10,10,12,12,12,13,13,13,14,14,14,14,15,16,16,
+16,17,17,17,17,18,18,18,18,18,19,19,19,19,19,19,
+20,20,20,21,21,21,21,21,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,21,21,21,21,21,20,20,20,19,19,19,19,19,19,
+18,18,18,18,18,17,17,17,17,16,16,16,15,14,14,14,
+14,13,13,13,12,12,12,12,10,10,10,9,9,9,8,8,
+8,7,7,7,6,6,6,4,4,4,0,0,0,1,1,1,
+2,2,2,3,24,24,24,25,25,25,26,26,26,27,27,27,
+27,29,28,28,30,30,30,30,31,31,31,31,32,32,32,32,
+32,33,33,33,35,35,35,34,34,34,34,34,34,34,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,34,34,34,34,
+34,34,34,34,34,34,35,35,33,33,33,33,32,32,32,32,
+31,31,31,31,31,30,30,30,28,28,29,29,27,27,27,26,
+26,26,26,25,25,25,24,24,3,2,2,2,1,1,1,0,
+0,0,4,4,4,6,6,6,7,7,7,8,8,8,9,9,
+9,9,10,10,10,12,12,12,13,13,13,13,14,14,14,15,
+16,16,16,17,17,17,17,18,18,18,18,18,19,19,19,19,
+19,19,20,20,20,21,21,21,21,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,21,21,21,21,21,20,20,20,19,19,19,
+19,19,18,18,18,18,18,17,17,17,17,17,16,16,15,14,
+14,14,14,13,13,13,13,12,12,12,10,10,10,9,9,9,
+8,8,8,7,7,7,6,6,6,5,4,4,0,0,0,1,
+1,1,1,2,2,2,24,24,24,25,25,25,26,26,26,27,
+27,27,27,29,28,28,30,30,30,30,31,31,31,31,32,32,
+32,32,32,33,33,33,35,35,34,34,34,34,34,34,34,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,34,
+36,36,34,34,34,34,34,34,34,35,35,33,33,33,32,32,
+32,32,32,31,31,31,31,30,30,30,30,28,28,29,27,27,
+27,27,26,26,26,25,25,25,24,24,3,2,2,2,1,1,
+1,0,0,0,4,4,4,6,6,6,7,7,7,8,8,8,
+9,9,9,9,10,10,10,12,12,12,13,13,13,14,14,14,
+14,15,16,16,16,17,17,17,17,18,18,18,18,18,19,19,
+19,19,19,20,20,20,21,21,21,21,21,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,21,21,21,21,21,20,20,19,
+19,19,19,19,19,18,18,18,18,18,17,17,17,17,16,16,
+16,15,14,14,14,13,13,13,13,12,12,12,10,10,10,9,
+9,9,8,8,8,8,7,7,7,6,6,6,4,4,4,0,
+0,0,1,1,1,2,2,2,24,24,24,25,25,25,26,26,
+26,27,27,27,27,29,28,28,30,30,30,30,31,31,31,31,
+32,32,32,32,32,33,33,33,35,35,34,34,34,34,34,34,
+34,36,36,36,36,36,36,36,36,36,36,36,36,37,37,37,
+37,37,37,37,37,37,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,34,34,34,34,34,34,35,35,35,33,33,
+33,32,32,32,32,31,31,31,31,30,30,30,30,28,28,29,
+27,27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,
+1,1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,
+8,8,9,9,9,11,10,10,10,12,12,12,13,13,13,14,
+14,14,14,15,16,16,16,17,17,17,17,18,18,18,18,19,
+19,19,19,19,19,20,20,21,21,21,21,21,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,21,21,21,21,20,
+20,20,19,19,19,19,19,18,18,18,18,18,17,17,17,17,
+16,16,16,15,14,14,14,14,13,13,13,12,12,12,10,10,
+10,9,9,9,9,8,8,8,7,7,7,6,6,6,4,4,
+4,0,0,0,1,1,1,2,2,2,24,24,24,25,25,25,
+26,26,26,27,27,27,29,29,28,28,30,30,30,30,31,31,
+31,31,32,32,32,32,33,33,33,35,35,34,34,34,34,34,
+34,34,36,36,36,36,36,36,36,36,36,36,36,37,37,37,
+37,37,37,37,37,37,37,37,37,37,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,34,34,34,34,34,34,35,35,
+33,33,33,32,32,32,32,31,31,31,31,30,30,30,30,28,
+28,29,27,27,27,27,26,26,26,25,25,25,24,24,3,2,
+2,2,1,1,1,0,0,0,4,4,4,6,6,6,7,7,
+7,8,8,8,9,9,9,10,10,10,12,12,12,12,13,13,
+13,14,14,14,14,16,16,16,17,17,17,17,18,18,18,18,
+18,19,19,19,19,19,20,20,20,21,21,21,21,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,21,21,
+21,21,20,20,19,19,19,19,19,19,18,18,18,18,17,17,
+17,17,16,16,16,15,14,14,14,14,13,13,13,12,12,12,
+10,10,10,9,9,9,9,8,8,8,7,7,7,6,6,5,
+4,4,0,0,0,1,1,1,2,2,2,3,24,24,25,25,
+25,25,26,26,26,27,27,27,29,29,28,28,30,30,30,31,
+31,31,31,32,32,32,32,32,33,33,33,35,35,34,34,34,
+34,34,34,36,36,36,36,36,36,36,36,36,36,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,36,
+37,36,36,36,36,36,36,36,36,36,34,34,34,34,34,34,
+35,35,33,33,33,32,32,32,32,31,31,31,31,30,30,30,
+30,28,28,29,27,27,27,27,26,26,26,25,25,25,24,24,
+3,2,2,2,1,1,1,0,0,0,4,4,4,6,6,6,
+7,7,7,8,8,8,9,9,9,10,10,10,12,12,12,13,
+13,13,13,14,14,14,15,16,16,16,17,17,17,17,18,18,
+18,18,19,19,19,19,19,19,20,20,21,21,21,21,22,22,
+22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,
+23,23,23,23,23,22,22,22,22,22,22,22,22,22,22,22,
+21,21,21,21,20,20,20,19,19,19,19,19,18,18,18,18,
+17,17,17,17,16,16,16,15,14,14,14,14,13,13,13,12,
+12,12,10,10,10,9,9,9,8,8,8,7,7,7,6,6,
+6,5,4,4,0,0,0,1,1,1,2,2,2,3,24,24,
+25,25,25,26,26,26,27,27,27,27,29,28,28,30,30,30,
+30,31,31,31,31,32,32,32,32,33,33,33,35,35,34,34,
+34,34,34,34,36,36,36,36,36,36,36,36,36,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,36,36,36,36,36,36,36,36,36,34,34,34,34,
+34,34,35,35,33,33,33,32,32,32,32,31,31,31,31,30,
+30,30,30,28,28,29,27,27,27,26,26,26,26,25,25,25,
+24,24,3,2,2,2,1,1,1,0,0,0,4,4,5,6,
+6,7,7,7,8,8,8,9,9,9,11,10,10,10,12,12,
+12,13,13,13,14,14,14,14,16,16,16,17,17,17,17,18,
+18,18,18,18,19,19,19,19,19,20,20,21,21,21,21,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,22,22,22,22,22,22,22,22,
+22,22,21,21,21,21,20,20,20,19,19,19,19,19,18,18,
+18,18,17,17,17,17,16,16,16,15,14,14,14,13,13,13,
+13,12,12,12,10,10,10,9,9,9,8,8,8,7,7,7,
+6,6,6,4,4,4,0,0,0,1,1,1,2,2,2,24,
+24,24,25,25,25,26,26,26,27,27,27,29,29,28,28,30,
+30,30,31,31,31,31,32,32,32,32,32,33,33,33,35,34,
+34,34,34,34,34,36,36,36,36,36,36,36,36,36,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,36,36,36,36,36,36,36,36,34,34,
+34,34,34,34,35,35,33,33,33,32,32,32,32,31,31,31,
+31,30,30,30,28,28,29,29,27,27,27,26,26,26,25,25,
+25,24,24,24,2,2,2,1,1,1,0,0,0,4,4,4,
+6,6,6,7,7,7,8,8,8,9,9,9,10,10,10,12,
+12,12,13,13,13,14,14,14,14,15,16,16,16,17,17,17,
+17,18,18,18,18,19,19,19,19,19,20,20,21,21,21,21,
+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,23,22,22,22,22,22,
+22,22,22,22,21,21,21,21,20,20,19,19,19,19,19,18,
+18,18,18,18,17,17,17,17,16,16,16,15,14,14,14,13,
+13,13,12,12,12,10,10,10,11,9,9,9,8,8,8,7,
+7,6,6,6,5,4,4,0,0,0,1,1,1,2,2,2,
+3,24,24,25,25,25,26,26,26,27,27,27,27,29,28,28,
+30,30,30,30,31,31,31,31,32,32,32,32,33,33,33,35,
+35,34,34,34,34,34,36,36,36,36,36,36,36,36,36,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,36,36,36,36,36,36,36,36,
+34,34,34,34,34,35,35,33,33,33,32,32,32,32,31,31,
+31,31,30,30,30,30,28,28,29,27,27,27,27,26,26,26,
+25,25,25,24,24,3,2,2,2,1,1,1,0,0,0,4,
+4,6,6,6,7,7,7,8,8,8,9,9,9,10,10,10,
+12,12,12,13,13,13,13,14,14,14,15,16,16,16,17,17,
+17,17,18,18,18,18,19,19,19,19,19,20,20,21,21,21,
+21,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,23,23,23,22,22,22,
+22,22,22,22,22,22,21,21,21,21,20,20,19,19,19,19,
+19,18,18,18,18,17,17,17,17,16,16,16,15,14,14,14,
+13,13,13,13,12,12,12,10,10,10,9,9,9,8,8,8,
+7,7,7,6,6,6,4,4,4,0,0,0,1,1,1,2,
+2,3,24,24,25,25,25,25,26,26,26,27,27,27,29,28,
+28,30,30,30,30,31,31,31,31,32,32,32,32,33,33,33,
+35,35,34,34,34,34,34,36,36,36,36,36,36,36,36,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,36,36,36,36,36,36,
+36,34,34,34,34,34,34,35,35,33,33,33,32,32,32,32,
+31,31,31,31,30,30,30,28,28,29,29,27,27,27,26,26,
+26,25,25,25,24,24,3,2,2,2,1,1,1,0,0,0,
+4,4,5,6,6,6,7,7,8,8,8,9,9,9,11,10,
+10,10,12,12,12,13,13,13,14,14,14,15,16,16,16,17,
+17,17,17,18,18,18,18,19,19,19,19,19,20,20,21,21,
+21,21,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,23,23,23,23,22,
+22,22,22,22,22,22,22,22,21,21,21,20,20,20,19,19,
+19,19,19,18,18,18,18,17,17,17,17,16,16,16,14,14,
+14,14,13,13,13,12,12,12,10,10,10,9,9,9,8,8,
+8,7,7,7,6,6,6,4,4,4,0,0,0,1,1,1,
+2,2,2,3,24,24,25,25,25,26,26,26,27,27,27,29,
+29,28,30,30,30,30,31,31,31,31,32,32,32,32,33,33,
+33,35,35,34,34,34,34,34,36,36,36,36,36,36,36,36,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,36,36,36,36,36,
+36,36,36,34,34,34,34,34,35,35,33,33,33,32,32,32,
+32,31,31,31,31,30,30,30,30,28,29,29,27,27,27,26,
+26,26,25,25,25,24,24,3,2,2,2,1,1,1,0,0,
+0,4,4,4,6,6,6,7,7,7,8,8,8,9,9,9,
+10,10,10,12,12,12,13,13,13,14,14,14,15,16,16,16,
+17,17,17,17,18,18,18,18,19,19,19,19,19,20,20,21,
+21,21,21,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,23,23,23,23,
+22,22,22,22,22,22,22,22,22,21,21,21,21,20,20,19,
+19,19,19,19,18,18,18,18,17,17,17,17,16,16,16,15,
+14,14,14,13,13,13,12,12,12,10,10,10,11,9,9,9,
+8,8,7,7,7,6,6,6,5,4,4,0,0,0,1,1,
+1,2,2,2,3,24,24,25,25,25,26,26,26,27,27,27,
+29,29,28,28,30,30,30,31,31,31,31,32,32,32,32,33,
+33,33,35,35,34,34,34,34,34,36,36,36,36,36,36,36,
+36,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,36,36,36,36,
+36,36,36,36,34,34,34,34,34,35,35,33,33,33,32,32,
+32,32,31,31,31,31,30,30,30,30,28,29,29,27,27,27,
+26,26,26,25,25,25,24,24,3,2,2,2,1,1,1,0,
+0,0,4,4,4,6,6,6,7,7,7,8,8,8,9,9,
+9,10,10,10,12,12,12,13,13,13,14,14,14,15,16,16,
+16,17,17,17,17,18,18,18,18,19,19,19,19,19,20,20,
+21,21,21,21,22,22,22,22,22,22,22,22,23,23,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,22,22,22,22,22,22,22,22,21,21,21,21,20,20,
+19,19,19,19,19,18,18,18,18,17,17,17,17,16,16,16,
+15,14,14,14,13,13,13,12,12,12,12,10,10,11,9,9,
+9,8,8,7,7,7,6,6,6,5,4,4,0,0,0,1,
+1,1,2,2,2,3,24,24,25,25,25,26,26,26,27,27,
+27,29,29,28,28,30,30,30,31,31,31,31,32,32,32,32,
+33,33,33,35,35,34,34,34,34,34,36,36,36,36,36,36,
+36,36,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,36,
+36,36,36,36,36,34,34,34,34,34,35,35,33,33,33,32,
+32,32,32,31,31,31,31,30,30,30,30,28,29,29,27,27,
+27,26,26,26,25,25,25,24,24,3,2,2,2,1,1,1,
+0,0,0,4,4,5,6,6,6,7,7,7,8,8,9,9,
+9,11,10,10,12,12,12,12,13,13,13,14,14,14,15,16,
+16,16,17,17,17,17,18,18,18,18,19,19,19,19,19,20,
+20,21,21,21,21,22,22,22,22,22,22,22,22,23,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,22,22,22,22,22,22,22,22,21,21,21,21,20,
+20,19,19,19,19,19,18,18,18,18,17,17,17,17,16,16,
+16,15,14,14,14,13,13,13,12,12,12,10,10,10,11,9,
+9,8,8,8,7,7,7,6,6,6,4,4,4,0,0,0,
+1,1,1,2,2,2,3,24,24,25,25,25,26,26,26,27,
+27,27,29,29,28,30,30,30,30,31,31,31,31,32,32,32,
+32,33,33,33,35,35,34,34,34,34,34,36,36,36,36,36,
+36,36,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,36,
+36,36,36,36,36,36,34,34,34,34,34,35,35,33,33,33,
+32,32,32,32,31,31,31,31,30,30,30,28,28,29,29,27,
+27,27,26,26,26,25,25,25,24,24,3,2,2,2,1,1,
+1,0,0,0,4,4,5,6,6,7,7,7,8,8,8,9,
+9,9,10,10,10,12,12,12,13,13,13,13,14,14,14,15,
+16,16,16,17,17,17,18,18,18,18,18,19,19,19,19,19,
+20,20,21,21,21,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,23,23,
+23,23,23,23,22,22,22,22,22,22,22,22,21,21,21,21,
+20,20,19,19,19,19,19,18,18,18,18,17,17,17,17,16,
+16,16,14,14,14,14,13,13,13,12,12,12,10,10,10,9,
+9,9,8,8,8,7,7,7,6,6,6,4,4,4,0,0,
+0,1,1,1,2,2,2,24,24,25,25,25,25,26,26,26,
+27,27,27,29,28,28,30,30,30,30,31,31,31,32,32,32,
+32,32,33,33,35,35,34,34,34,34,34,34,36,36,36,36,
+36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,
+33,32,32,32,32,31,31,31,31,30,30,30,28,28,29,27,
+27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,1,
+1,1,0,0,4,4,4,6,6,6,7,7,7,8,8,8,
+9,9,9,10,10,10,12,12,12,13,13,13,14,14,14,14,
+15,16,16,17,17,17,17,18,18,18,18,19,19,19,19,19,
+20,20,21,21,21,21,22,22,22,22,22,22,22,22,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,23,22,22,22,22,22,22,22,22,21,21,21,
+20,20,20,19,19,19,19,19,18,18,18,18,17,17,17,17,
+16,16,15,14,14,14,14,13,13,13,12,12,12,10,10,10,
+9,9,9,8,8,8,7,7,7,6,6,6,4,4,4,0,
+0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,26,
+27,27,27,27,29,28,28,30,30,30,31,31,31,31,32,32,
+32,32,33,33,33,35,35,34,34,34,34,34,36,36,36,36,
+36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+36,36,36,36,36,36,36,34,34,34,34,34,34,35,33,33,
+33,32,32,32,32,31,31,31,31,30,30,30,30,28,29,29,
+27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,1,
+1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,8,
+8,9,9,9,10,10,10,12,12,12,13,13,13,14,14,14,
+15,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,
+19,20,20,21,21,21,21,22,22,22,22,22,22,22,22,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,23,22,22,22,22,22,22,22,22,21,21,21,
+21,20,20,19,19,19,19,19,18,18,18,18,17,17,17,17,
+16,16,16,15,14,14,14,13,13,13,12,12,12,12,10,10,
+11,9,9,9,8,8,7,7,7,6,6,6,5,4,4,0,
+0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,
+26,27,27,27,29,29,28,30,30,30,30,31,31,31,31,32,
+32,32,32,33,33,33,35,35,34,34,34,34,34,36,36,36,
+36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+36,36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,
+33,33,32,32,32,32,31,31,31,31,30,30,30,28,28,29,
+27,27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,
+1,1,1,0,0,4,4,4,6,6,6,7,7,7,8,8,
+8,9,9,9,10,10,10,12,12,12,13,13,13,14,14,14,
+14,15,16,16,17,17,17,17,18,18,18,18,18,19,19,19,
+19,20,20,20,21,21,21,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,
+23,23,23,23,23,22,22,22,22,22,22,22,22,22,21,21,
+21,20,20,20,19,19,19,19,18,18,18,18,18,17,17,17,
+17,16,16,15,14,14,14,14,13,13,13,12,12,12,10,10,
+10,9,9,9,8,8,8,7,7,7,6,6,6,4,4,4,
+0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,
+26,27,27,27,27,29,28,28,30,30,30,30,31,31,31,32,
+32,32,32,33,33,33,35,35,34,34,34,34,34,34,36,36,
+36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+36,36,36,36,36,36,36,36,34,34,34,34,34,35,35,33,
+33,33,32,32,32,32,31,31,31,31,30,30,30,28,28,29,
+29,27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,
+1,1,1,0,0,0,4,4,5,6,6,6,7,7,8,8,
+8,9,9,9,11,10,10,12,12,12,12,13,13,13,14,14,
+14,15,16,16,16,17,17,17,17,18,18,18,18,19,19,19,
+19,19,20,20,21,21,21,21,22,22,22,22,22,22,22,22,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,23,23,22,22,22,22,22,22,22,22,21,21,
+21,21,20,20,19,19,19,19,19,18,18,18,18,17,17,17,
+17,16,16,16,15,14,14,14,13,13,13,12,12,12,10,10,
+10,9,9,9,8,8,8,7,7,7,6,6,6,4,4,4,
+0,0,0,1,1,1,2,2,2,24,24,24,25,25,25,26,
+26,26,27,27,27,29,29,28,30,30,30,30,31,31,31,31,
+32,32,32,32,33,33,33,35,35,34,34,34,34,34,36,36,
+36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+36,36,36,36,36,36,36,36,34,34,34,34,34,35,35,33,
+33,33,32,32,32,32,31,31,31,31,30,30,30,30,28,28,
+29,27,27,27,26,26,26,25,25,25,24,24,24,2,2,2,
+1,1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,
+8,8,9,9,9,10,10,10,12,12,12,13,13,13,14,14,
+14,14,16,16,16,17,17,17,17,18,18,18,18,19,19,19,
+19,19,20,20,21,21,21,21,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,23,23,23,23,23,22,22,22,22,22,22,22,22,21,21,
+21,21,20,20,19,19,19,19,19,18,18,18,18,17,17,17,
+17,16,16,16,15,14,14,14,13,13,13,12,12,12,12,10,
+10,11,9,9,9,8,8,8,7,7,7,6,6,5,4,4,
+0,0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,
+26,26,27,27,27,29,29,28,28,30,30,30,31,31,31,31,
+32,32,32,32,33,33,33,35,35,34,34,34,34,34,34,36,
+36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+36,36,36,36,36,36,36,36,34,34,34,34,34,34,35,33,
+33,33,32,32,32,32,31,31,31,31,30,30,30,30,28,28,
+29,27,27,27,26,26,26,26,25,25,25,24,24,3,2,2,
+2,1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,
+8,8,9,9,9,10,10,10,12,12,12,13,13,13,14,14,
+14,14,15,16,16,17,17,17,17,18,18,18,18,18,19,19,
+19,19,19,20,20,21,21,21,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,23,23,23,23,23,22,22,22,22,22,22,22,22,21,21,
+21,21,20,20,19,19,19,19,19,18,18,18,18,17,17,17,
+17,16,16,16,15,14,14,14,13,13,13,13,12,12,12,10,
+10,10,9,9,9,8,8,8,7,7,7,6,6,6,4,4,
+0,0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,
+26,26,27,27,27,27,29,28,28,30,30,30,30,31,31,31,
+32,32,32,32,32,33,33,35,35,34,34,34,34,34,34,36,
+36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+36,36,36,36,36,36,36,36,34,34,34,34,34,34,35,33,
+33,33,32,32,32,32,31,31,31,31,30,30,30,30,28,28,
+29,27,27,27,27,26,26,26,25,25,25,24,24,3,2,2,
+2,1,1,1,0,0,4,4,4,6,6,6,7,7,7,8,
+8,8,9,9,9,10,10,10,12,12,12,13,13,13,13,14,
+14,14,15,16,16,16,17,17,17,17,18,18,18,18,19,19,
+19,19,19,20,20,21,21,21,21,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,23,23,23,22,22,22,22,22,22,22,22,22,21,21,
+21,21,20,20,19,19,19,19,19,18,18,18,18,17,17,17,
+17,16,16,16,15,14,14,14,13,13,13,13,12,12,12,10,
+10,10,9,9,9,8,8,8,7,7,7,6,6,6,4,4,
+4,0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,
+26,26,27,27,27,27,29,28,28,30,30,30,30,31,31,31,
+31,32,32,32,32,33,33,33,35,34,34,34,34,34,34,36,
+36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+36,36,36,36,36,36,36,36,34,34,34,34,34,35,35,33,
+33,33,32,32,32,32,31,31,31,31,30,30,30,30,28,28,
+29,27,27,27,27,26,26,26,25,25,25,24,24,3,2,2,
+2,1,1,1,0,0,4,4,4,6,6,6,7,7,7,8,
+8,8,9,9,9,10,10,10,12,12,12,13,13,13,13,14,
+14,14,15,16,16,16,17,17,17,17,18,18,18,18,19,19,
+19,19,19,20,20,21,21,21,21,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,23,23,23,22,22,22,22,22,22,22,22,22,21,21,
+21,21,20,20,19,19,19,19,19,18,18,18,18,17,17,17,
+17,16,16,16,15,14,14,14,13,13,13,13,12,12,12,10,
+10,10,9,9,9,8,8,8,7,7,7,6,6,6,4,4,
+4,0,0,0,1,1,2,2,2,3,24,24,25,25,25,26,
+26,26,26,27,27,27,29,28,28,30,30,30,30,31,31,31,
+31,32,32,32,32,33,33,33,35,35,34,34,34,34,34,36,
+36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,
+36,36,36,36,36,36,36,36,34,34,34,34,34,35,35,33,
+33,33,32,32,32,32,31,31,31,31,30,30,30,30,28,28,
+29,27,27,27,26,26,26,26,25,25,25,24,24,3,2,2,
+2,1,1,1,0,0,4,4,4,6,6,6,7,7,7,8,
+8,8,9,9,9,10,10,10,12,12,12,13,13,13,13,14,
+14,14,15,16,16,16,17,17,17,17,18,18,18,18,19,19,
+19,19,19,20,20,21,21,21,21,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,23,23,23,22,22,22,22,22,22,22,22,22,21,21,
+21,21,20,20,19,19,19,19,19,18,18,18,18,17,17,17,
+17,16,16,16,15,14,14,14,13,13,13,13,12,12,12,10,
+10,10,9,9,9,8,8,8,7,7,7,6,6,6,4,4,
+4,0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,
+26,26,26,27,27,27,29,28,28,30,30,30,30,31,31,31,
+31,32,32,32,32,33,33,33,35,35,34,34,34,34,34,36,
+36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,
+33,33,32,32,32,32,31,31,31,31,30,30,30,30,28,28,
+29,27,27,27,26,26,26,25,25,25,25,24,24,3,2,2,
+2,1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,
+8,8,9,9,9,10,10,10,12,12,12,13,13,13,13,14,
+14,14,15,16,16,16,17,17,17,17,18,18,18,18,19,19,
+19,19,19,20,20,21,21,21,21,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,23,23,22,22,22,22,22,22,22,22,22,22,21,21,
+21,21,20,20,19,19,19,19,19,18,18,18,18,17,17,17,
+17,16,16,16,15,14,14,14,13,13,13,13,12,12,12,10,
+10,10,9,9,9,8,8,8,7,7,7,6,6,6,4,4,
+0,0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,
+26,26,27,27,27,27,29,28,28,30,30,30,30,31,31,31,
+31,32,32,32,32,33,33,33,35,35,34,34,34,34,34,36,
+36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,
+33,33,32,32,32,32,31,31,31,31,30,30,30,30,28,29,
+29,27,27,27,26,26,26,25,25,25,24,24,24,2,2,2,
+1,1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,
+8,8,9,9,9,10,10,10,12,12,12,13,13,13,14,14,
+14,14,15,16,16,16,17,17,17,17,18,18,18,18,19,19,
+19,19,19,20,20,21,21,21,21,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,23,23,22,22,22,22,22,22,22,22,22,22,21,21,
+21,20,20,20,19,19,19,19,19,18,18,18,18,17,17,17,
+17,16,16,16,15,14,14,14,13,13,13,12,12,12,12,10,
+10,11,9,9,9,8,8,8,7,7,7,6,6,5,4,4,
+0,0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,
+26,26,27,27,27,27,29,28,28,30,30,30,30,31,31,31,
+32,32,32,32,32,33,33,33,35,35,34,34,34,34,34,36,
+36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,
+33,33,32,32,32,32,31,31,31,31,30,30,30,28,28,29,
+29,27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,
+1,1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,
+8,8,9,9,9,10,10,10,12,12,12,13,13,13,14,14,
+14,14,15,16,16,17,17,17,17,18,18,18,18,18,19,19,
+19,19,19,20,20,21,21,21,21,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,23,23,22,22,22,22,22,22,22,22,22,21,21,21,
+21,20,20,20,19,19,19,19,18,18,18,18,18,17,17,17,
+17,16,16,16,14,14,14,14,13,13,13,12,12,12,10,10,
+10,9,9,9,8,8,8,7,7,7,6,6,6,5,4,4,
+0,0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,
+26,26,27,27,27,29,29,28,28,30,30,30,31,31,31,31,
+32,32,32,32,32,33,33,35,35,34,34,34,34,34,34,36,
+36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,
+33,32,32,32,32,32,31,31,31,31,30,30,30,28,28,29,
+29,27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,
+1,1,1,0,0,0,4,4,5,6,6,6,7,7,7,8,
+8,9,9,9,11,10,10,10,12,12,12,13,13,13,14,14,
+14,14,16,16,16,17,17,17,17,18,18,18,18,19,19,19,
+19,19,20,20,20,21,21,21,21,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,23,23,22,22,22,22,22,22,22,22,22,21,21,21,
+21,20,20,19,19,19,19,19,18,18,18,18,18,17,17,17,
+17,16,16,15,14,14,14,14,13,13,13,12,12,12,10,10,
+10,9,9,9,8,8,8,7,7,7,6,6,6,4,4,4,
+0,0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,
+26,26,27,27,27,29,29,28,28,30,30,30,31,31,31,31,
+32,32,32,32,33,33,33,35,35,34,34,34,34,34,34,36,
+36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,36,34,34,34,34,34,35,35,33,33,
+33,32,32,32,32,31,31,31,31,30,30,30,30,28,28,29,
+27,27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,
+1,1,1,0,0,0,4,4,6,6,6,7,7,7,8,8,
+8,9,9,9,10,10,10,12,12,12,12,13,13,13,14,14,
+14,15,16,16,16,17,17,17,17,18,18,18,18,19,19,19,
+19,19,20,20,20,21,21,21,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,23,23,22,22,22,22,22,22,22,22,22,21,21,21,
+21,20,20,19,19,19,19,19,18,18,18,18,17,17,17,17,
+16,16,16,15,14,14,14,13,13,13,13,12,12,12,10,10,
+10,9,9,9,8,8,8,7,7,7,6,6,6,4,4,4,
+0,0,0,1,1,1,2,2,2,24,24,25,25,25,25,26,
+26,26,27,27,27,29,28,28,30,30,30,30,31,31,31,31,
+32,32,32,32,33,33,33,35,35,34,34,34,34,34,34,36,
+36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,36,34,34,34,34,34,35,35,33,33,
+33,32,32,32,32,31,31,31,31,30,30,30,30,28,28,29,
+27,27,27,26,26,26,26,25,25,25,24,24,3,2,2,2,
+1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,8,
+8,9,9,9,10,10,10,12,12,12,13,13,13,13,14,14,
+14,15,16,16,16,17,17,17,17,18,18,18,18,19,19,19,
+19,19,20,20,21,21,21,21,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,23,23,23,22,22,22,22,22,22,22,22,22,21,21,21,
+21,20,20,19,19,19,19,19,18,18,18,18,17,17,17,17,
+16,16,16,15,14,14,14,13,13,13,13,12,12,12,10,10,
+10,9,9,9,8,8,8,7,7,7,6,6,6,4,4,0,
+0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,
+26,27,27,27,27,29,28,28,30,30,30,30,31,31,31,31,
+32,32,32,32,33,33,33,35,35,34,34,34,34,34,36,36,
+36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,
+33,32,32,32,32,31,31,31,31,30,30,30,28,28,29,29,
+27,27,27,26,26,26,25,25,25,24,24,24,2,2,2,1,
+1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,8,
+8,9,9,9,10,10,10,12,12,12,13,13,13,14,14,14,
+14,15,16,16,17,17,17,17,18,18,18,18,18,19,19,19,
+19,19,20,20,21,21,21,21,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,23,23,23,22,22,22,22,22,22,22,22,22,21,21,21,
+20,20,20,19,19,19,19,19,18,18,18,18,17,17,17,17,
+16,16,16,15,14,14,14,13,13,13,12,12,12,12,10,10,
+11,9,9,9,8,8,8,7,7,6,6,6,5,4,4,0,
+0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,
+26,27,27,27,29,29,28,28,30,30,30,31,31,31,31,32,
+32,32,32,33,33,33,35,35,34,34,34,34,34,34,36,36,
+36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,
+33,32,32,32,32,31,31,31,31,30,30,30,28,28,29,29,
+27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,1,
+1,1,0,0,0,4,4,5,6,6,6,7,7,7,8,8,
+9,9,9,11,10,10,10,12,12,12,13,13,13,14,14,14,
+15,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,
+19,20,20,21,21,21,21,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,
+23,23,23,23,22,22,22,22,22,22,22,22,22,21,21,21,
+20,20,20,19,19,19,19,19,18,18,18,18,17,17,17,17,
+16,16,16,14,14,14,14,13,13,13,12,12,12,10,10,10,
+9,9,9,8,8,8,7,7,7,6,6,6,4,4,4,0,
+0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,
+26,27,27,27,29,29,28,28,30,30,30,31,31,31,31,32,
+32,32,32,33,33,33,35,35,34,34,34,34,34,34,36,36,
+36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,
+33,32,32,32,32,31,31,31,31,30,30,30,28,28,29,29,
+27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,1,
+1,1,0,0,0,4,4,5,6,6,7,7,7,8,8,8,
+9,9,9,10,10,10,12,12,12,13,13,13,13,14,14,14,
+15,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,
+19,20,20,21,21,21,21,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,
+23,23,23,23,22,22,22,22,22,22,22,22,22,21,21,21,
+20,20,20,19,19,19,19,18,18,18,18,18,17,17,17,17,
+16,16,15,14,14,14,14,13,13,13,12,12,12,10,10,10,
+9,9,9,8,8,8,7,7,7,6,6,6,4,4,4,0,
+0,0,1,1,1,2,2,2,24,24,24,25,25,25,26,26,
+26,27,27,27,29,28,28,30,30,30,30,31,31,31,31,32,
+32,32,32,33,33,33,35,35,34,34,34,34,34,36,36,36,
+36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,
+32,32,32,32,32,31,31,31,30,30,30,30,28,28,29,27,
+27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,1,
+1,1,0,0,4,4,4,6,6,6,7,7,7,8,8,8,
+9,9,9,10,10,10,12,12,12,13,13,13,13,14,14,14,
+15,16,16,16,17,17,17,18,18,18,18,18,19,19,19,19,
+19,20,20,21,21,21,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,23,
+23,23,23,23,22,22,22,22,22,22,22,22,22,21,21,21,
+20,20,20,19,19,19,19,18,18,18,18,18,17,17,17,17,
+16,16,15,14,14,14,14,13,13,13,12,12,12,10,10,10,
+9,9,9,8,8,8,7,7,7,6,6,6,4,4,4,0,
+0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,26,
+27,27,27,27,29,28,28,30,30,30,30,31,31,31,32,32,
+32,32,32,33,33,35,35,34,34,34,34,34,34,36,36,36,
+36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,
+32,32,32,32,32,31,31,31,30,30,30,30,28,28,29,27,
+27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,1,
+1,0,0,0,4,4,4,6,6,6,7,7,7,8,8,8,
+9,9,9,10,10,10,12,12,12,13,13,13,14,14,14,14,
+15,16,16,17,17,17,17,18,18,18,18,19,19,19,19,19,
+20,20,20,21,21,21,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,23,
+23,23,23,23,22,22,22,22,22,22,22,22,22,21,21,21,
+20,20,19,19,19,19,19,18,18,18,18,18,17,17,17,16,
+16,16,15,14,14,14,13,13,13,13,12,12,12,10,10,10,
+9,9,9,8,8,8,7,7,7,6,6,6,4,4,0,0,
+0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,26,
+27,27,27,29,29,28,28,30,30,30,31,31,31,31,32,32,
+32,32,33,33,33,35,35,34,34,34,34,34,34,36,36,36,
+36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,
+32,32,32,32,32,31,31,31,30,30,30,30,28,28,29,27,
+27,27,26,26,26,26,25,25,25,24,24,3,2,2,1,1,
+1,0,0,0,4,4,4,6,6,6,7,7,7,8,8,8,
+9,9,9,10,10,10,12,12,12,13,13,13,14,14,14,14,
+16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,19,
+20,20,21,21,21,21,22,22,22,22,22,22,22,22,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,22,22,22,22,22,22,22,22,22,21,21,21,
+20,20,19,19,19,19,19,18,18,18,18,18,17,17,17,16,
+16,16,15,14,14,14,13,13,13,13,12,12,12,10,10,10,
+9,9,9,8,8,8,7,7,7,6,6,5,4,4,0,0,
+0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,26,
+27,27,27,29,29,28,28,30,30,30,31,31,31,31,32,32,
+32,32,33,33,33,35,35,34,34,34,34,34,36,36,36,36,
+36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,
+32,32,32,32,31,31,31,31,30,30,30,30,28,28,29,27,
+27,27,26,26,26,25,25,25,25,24,24,2,2,2,1,1,
+1,0,0,0,4,4,4,6,6,6,7,7,7,8,8,8,
+9,9,9,10,10,10,12,12,12,13,13,13,14,14,14,15,
+16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,19,
+20,20,21,21,21,21,22,22,22,22,22,22,22,22,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,22,22,22,22,22,22,22,22,22,21,21,21,
+20,20,19,19,19,19,19,18,18,18,18,17,17,17,17,16,
+16,16,15,14,14,14,13,13,13,13,12,12,12,10,10,10,
+9,9,9,8,8,8,7,7,7,6,6,5,4,4,0,0,
+0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,26,
+27,27,27,29,29,28,28,30,30,30,31,31,31,31,32,32,
+32,32,33,33,33,35,35,34,34,34,34,34,36,36,36,36,
+36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,
+32,32,32,32,31,31,31,31,30,30,30,30,28,28,29,27,
+27,27,26,26,26,25,25,25,25,24,24,2,2,2,1,1,
+1,0,0,0,4,4,4,6,6,6,7,7,7,8,8,8,
+9,9,9,10,10,10,12,12,12,13,13,13,14,14,14,15,
+16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,19,
+20,20,21,21,21,21,22,22,22,22,22,22,22,22,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,22,22,22,22,22,22,22,22,22,21,21,21,
+20,20,19,19,19,19,19,18,18,18,18,17,17,17,17,16,
+16,16,15,14,14,14,13,13,13,13,12,12,12,10,10,10,
+9,9,9,8,8,8,7,7,7,6,6,5,4,4,0,0,
+0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,26,
+27,27,27,29,29,28,28,30,30,30,31,31,31,31,32,32,
+32,32,33,33,33,35,35,34,34,34,34,34,36,36,36,36,
+36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,
+32,32,32,32,31,31,31,31,30,30,30,30,28,28,29,27,
+27,27,26,26,26,26,25,25,25,24,24,3,2,2,1,1,
+1,0,0,0,4,4,4,6,6,6,7,7,7,8,8,8,
+9,9,9,10,10,10,12,12,12,13,13,13,14,14,14,14,
+16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,19,
+20,20,21,21,21,21,22,22,22,22,22,22,22,22,23,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,22,22,22,22,22,22,22,22,22,21,21,21,
+20,20,19,19,19,19,19,18,18,18,18,18,17,17,17,16,
+16,16,15,14,14,14,13,13,13,13,12,12,12,10,10,10,
+9,9,9,8,8,8,7,7,7,6,6,5,4,4,0,0,
+0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,26,
+27,27,27,29,29,28,28,30,30,30,31,31,31,31,32,32,
+32,32,33,33,33,35,35,34,34,34,34,34,36,36,36,36,
+36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,
+36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,
+32,32,32,32,32,31,31,31,30,30,30,30,28,28,29,27,
+27,27,26,26,26,26,25,25,25,24,24,3,2,2,2,1,
+1,0,0,0,4,4,4,6,6,6,7,7,7,8,8,8,
+9,9,9,10,10,10,12,12,12,13,13,13,14,14,14,14,
+15,16,16,17,17,17,17,18,18,18,18,19,19,19,19,19,
+20,20,20,21,21,21,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,23,
+23,23,23,23,22,22,22,22,22,22,22,22,22,21,21,21,
+20,20,19,19,19,19,19,18,18,18,18,18,17,17,17,16,
+16,16,15,14,14,14,13,13,13,13,12,12,12,10,10,10,
+9,9,9,8,8,8,7,7,7,6,6,6,4,4,0,0,
+0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,26,
+27,27,27,29,29,28,28,30,30,30,31,31,31,31,32,32,
+32,32,33,33,33,35,35,34,34,34,34,34,34,36,36,36,
+36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,36,
+36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,
+32,32,32,32,32,31,31,31,30,30,30,30,28,28,29,27,
+27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,1,
+1,1,0,0,4,4,4,6,6,6,7,7,7,8,8,8,
+9,9,9,10,10,10,12,12,12,13,13,13,13,14,14,14,
+15,16,16,16,17,17,17,18,18,18,18,18,19,19,19,19,
+19,20,20,21,21,21,21,22,22,22,22,22,22,22,22,23,
+23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
+23,23,23,23,22,22,22,22,22,22,22,22,21,21,21,21,
+20,20,19,19,19,19,19,18,18,18,18,18,17,17,17,16,
+16,16,15,14,14,14,14,13,13,13,12,12,12,10,10,10,
+9,9,9,8,8,8,7,7,7,6,6,6,4,4,4,0,
+0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,26,
+27,27,27,27,29,28,28,30,30,30,30,31,31,31,32,32,
+32,32,32,33,33,35,35,34,34,34,34,34,34,36,36,36,
+36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,36,
+36,36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,
+32,32,32,32,32,31,31,31,30,30,30,30,28,28,29,27,
+27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,1,
+1,1,0,0,0,4,4,5,6,6,7,7,7,8,8,8,
+9,9,9,11,10,10,12,12,12,12,13,13,13,14,14,14,
+15,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,
+19,20,20,20,21,21,21,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,
+23,23,23,22,22,22,22,22,22,22,22,22,21,21,21,21,
+20,20,19,19,19,19,19,18,18,18,18,18,17,17,17,17,
+16,16,15,14,14,14,14,13,13,13,12,12,12,10,10,10,
+9,9,9,8,8,8,7,7,7,6,6,6,4,4,4,0,
+0,0,1,1,1,2,2,2,24,24,24,25,25,25,26,26,
+26,27,27,27,29,29,28,30,30,30,30,31,31,31,31,32,
+32,32,32,33,33,33,35,35,34,34,34,34,34,34,36,36,
+36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,37,36,36,36,
+36,36,36,36,36,36,34,34,34,34,34,34,35,33,33,33,
+32,32,32,32,32,31,31,31,31,30,30,30,28,28,29,29,
+27,27,27,26,26,26,25,25,25,24,24,3,2,2,2,1,
+1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,8,
+8,9,9,9,10,10,10,12,12,12,13,13,13,14,14,14,
+14,15,16,16,17,17,17,17,18,18,18,18,18,19,19,19,
+19,19,20,20,21,21,21,21,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,22,22,22,22,22,22,22,22,22,22,21,21,21,21,
+20,20,19,19,19,19,19,18,18,18,18,18,17,17,17,17,
+16,16,15,14,14,14,14,13,13,13,12,12,12,10,10,10,
+9,9,9,8,8,8,7,7,7,6,6,6,5,4,4,0,
+0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,26,
+26,27,27,27,29,29,28,28,30,30,30,30,31,31,31,32,
+32,32,32,32,33,33,33,35,35,34,34,34,34,34,36,36,
+36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,37,36,36,36,36,
+36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,33,
+32,32,32,32,32,31,31,31,31,30,30,30,28,28,29,29,
+27,27,27,26,26,26,25,25,25,24,24,24,2,2,2,1,
+1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,8,
+8,9,9,9,10,10,10,12,12,12,12,13,13,13,14,14,
+14,15,16,16,16,17,17,17,17,18,18,18,18,18,19,19,
+19,19,19,20,20,21,21,21,21,22,22,22,22,22,22,22,
+22,22,22,22,22,23,23,23,23,23,23,23,23,23,23,23,
+22,22,22,22,22,22,22,22,22,22,22,21,21,21,21,20,
+20,20,19,19,19,19,19,18,18,18,18,18,17,17,17,17,
+16,16,15,14,14,14,14,13,13,13,12,12,12,10,10,10,
+11,9,9,9,8,8,8,7,7,7,6,6,6,4,4,0,
+0,0,1,1,1,2,2,2,3,24,24,25,25,25,25,26,
+26,26,27,27,27,29,29,28,28,30,30,30,31,31,31,31,
+32,32,32,32,33,33,33,35,35,34,34,34,34,34,34,34,
+36,36,36,36,36,36,36,36,36,37,37,37,37,37,37,37,
+37,37,37,37,37,37,37,37,37,37,37,36,36,36,36,36,
+36,36,36,36,36,34,34,34,34,34,34,35,35,33,33,33,
+32,32,32,32,32,31,31,31,31,30,30,30,28,28,29,29,
+27,27,27,26,26,26,26,25,25,25,24,24,3,2,2,2,
+1,1,1,0,0,0,4,4,5,6,6,6,7,7,7,8,
+8,8,9,9,9,10,10,10,12,12,12,13,13,13,13,14,
+14,14,15,16,16,16,17,17,17,17,18,18,18,18,18,19,
+19,19,19,19,20,20,20,21,21,21,21,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,21,21,21,21,20,
+20,20,19,19,19,19,19,18,18,18,18,18,17,17,17,17,
+16,16,16,14,14,14,14,13,13,13,12,12,12,12,10,10,
+10,9,9,9,8,8,8,7,7,7,6,6,6,4,4,4,
+0,0,0,1,1,1,2,2,2,3,24,24,25,25,25,26,
+26,26,27,27,27,27,29,28,28,30,30,30,30,31,31,31,
+31,32,32,32,32,33,33,33,33,35,35,34,34,34,34,34,
+34,36,36,36,36,36,36,36,36,36,36,37,37,37,37,37,
+37,37,37,37,37,37,37,36,36,36,36,36,36,36,36,36,
+36,36,36,36,34,34,34,34,34,34,34,35,35,33,33,33,
+32,32,32,32,32,31,31,31,31,30,30,30,28,28,29,29,
+27,27,27,26,26,26,26,25,25,25,24,24,3,2,2,2,
+1,1,1,0,0,0,4,4,4,6,6,6,7,7,7,8,
+8,8,9,9,9,11,10,10,10,12,12,12,13,13,13,14,
+14,14,14,15,16,16,16,17,17,17,17,18,18,18,18,18,
+19,19,19,19,19,20,20,20,21,21,21,21,21,22,22,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,22,22,21,21,21,21,20,20,
+20,19,19,19,19,19,19,18,18,18,18,17,17,17,17,17,
+16,16,16,15,14,14,14,13,13,13,13,12,12,12,10,10,
+10,9,9,9,8,8,8,7,7,7,6,6,6,5,4,4,
+0,0,0,1,1,1,2,2,2,2,24,24,24,25,25,25,
+26,26,26,27,27,27,27,29,28,28,30,30,30,30,31,31,
+31,31,32,32,32,32,32,33,33,33,35,35,34,34,34,34,
+34,34,34,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,34,34,34,34,34,34,34,35,35,33,33,33,33,
+32,32,32,32,31,31,31,31,31,30,30,30,30,28,28,29,
+27,27,27,27,26,26,26,25,25,25,24,24,24,2,2,2,
+2,1,1,1,0,0,0,4,4,5,6,6,6,7,7,7,
+8,8,8,9,9,9,10,10,10,12,12,12,12,13,13,13,
+14,14,14,14,15,16,16,16,17,17,17,17,18,18,18,18,
+18,19,19,19,19,19,19,20,20,20,21,21,21,21,21,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,22,22,21,21,21,21,21,21,20,20,
+20,19,19,19,19,19,18,18,18,18,18,17,17,17,17,17,
+16,16,16,15,14,14,14,13,13,13,13,12,12,12,10,10,
+10,11,9,9,9,8,8,8,7,7,7,6,6,6,4,4,
+4,0,0,0,1,1,1,2,2,2,3,24,24,25,25,25,
+25,26,26,26,27,27,27,27,29,28,28,30,30,30,30,31,
+31,31,31,32,32,32,32,32,33,33,33,35,35,35,34,34,
+34,34,34,34,34,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,34,34,34,34,34,34,34,34,35,35,35,33,33,33,32,
+32,32,32,32,31,31,31,31,31,30,30,30,30,28,28,29,
+27,27,27,27,26,26,26,25,25,25,25,24,24,3,2,2,
+2,1,1,1,0,0,0,4,4,4,6,6,6,6,7,7,
+7,8,8,8,9,9,9,10,10,10,12,12,12,12,13,13,
+13,13,14,14,14,15,16,16,16,17,17,17,17,17,18,18,
+18,18,18,19,19,19,19,19,19,20,20,20,20,21,21,21,
+21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,
+22,22,22,22,22,22,21,21,21,21,21,21,20,20,20,20,
+19,19,19,19,19,19,18,18,18,18,18,17,17,17,17,17,
+16,16,16,15,14,14,14,13,13,13,13,12,12,12,12,10,
+10,10,9,9,9,8,8,8,7,7,7,6,6,6,6,4,
+4,4,0,0,0,1,1,1,2,2,2,3,24,24,25,25,
+25,25,26,26,26,27,27,27,27,29,28,28,30,30,30,30,
+31,31,31,31,31,32,32,32,32,32,33,33,33,35,35,35,
+34,34,34,34,34,34,34,34,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,34,34,
+34,34,34,34,34,34,34,34,35,35,35,33,33,33,33,32,
+32,32,32,32,31,31,31,31,31,30,30,30,30,28,28,29,
+29,27,27,27,26,26,26,26,25,25,25,24,24,24,2,2,
+2,2,1,1,1,0,0,0,4,4,4,6,6,6,7,7,
+7,7,8,8,8,9,9,9,10,10,10,10,12,12,12,13,
+13,13,13,14,14,14,14,15,16,16,16,17,17,17,17,17,
+18,18,18,18,18,19,19,19,19,19,19,19,20,20,20,20,
+21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,22,
+22,21,21,21,21,21,21,21,21,21,20,20,20,20,19,19,
+19,19,19,19,19,18,18,18,18,18,18,17,17,17,17,16,
+16,16,16,15,14,14,14,14,13,13,13,12,12,12,12,10,
+10,10,9,9,9,9,8,8,8,7,7,7,6,6,6,5,
+4,4,0,0,0,0,1,1,1,2,2,2,3,24,24,25,
+25,25,25,26,26,26,27,27,27,27,29,29,28,28,30,30,
+30,30,31,31,31,31,31,32,32,32,32,32,33,33,33,33,
+35,35,34,34,34,34,34,34,34,34,34,34,36,36,36,36,
+34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
+34,34,34,34,34,34,34,35,35,35,33,33,33,33,32,32,
+32,32,32,31,31,31,31,31,30,30,30,30,30,28,28,29,
+29,27,27,27,26,26,26,26,25,25,25,25,24,24,3,2,
+2,2,1,1,1,1,0,0,0,4,4,4,6,6,6,7,
+7,7,7,8,8,8,9,9,9,11,10,10,10,12,12,12,
+13,13,13,13,14,14,14,14,15,16,16,16,16,17,17,17,
+17,17,18,18,18,18,18,18,19,19,19,19,19,19,19,19,
+20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21,
+21,21,21,21,21,21,21,20,20,20,20,20,19,19,19,19,
+19,19,19,19,18,18,18,18,18,18,17,17,17,17,17,16,
+16,16,16,15,14,14,14,14,13,13,13,13,12,12,12,10,
+10,10,11,9,9,9,8,8,8,7,7,7,7,6,6,6,
+4,4,4,0,0,0,1,1,1,1,2,2,2,3,24,24,
+25,25,25,25,26,26,26,26,27,27,27,29,29,28,28,30,
+30,30,30,30,31,31,31,31,31,32,32,32,32,32,33,33,
+33,33,35,35,35,34,34,34,34,34,34,34,34,34,34,34,
+34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
+34,34,34,34,35,35,35,35,33,33,33,33,33,32,32,32,
+32,32,32,31,31,31,31,31,30,30,30,30,30,28,28,29,
+29,27,27,27,27,26,26,26,25,25,25,25,24,24,24,2,
+2,2,2,1,1,1,0,0,0,0,4,4,4,6,6,6,
+7,7,7,7,8,8,8,9,9,9,9,10,10,10,12,12,
+12,12,13,13,13,13,14,14,14,14,15,16,16,16,16,17,
+17,17,17,17,18,18,18,18,18,18,18,19,19,19,19,19,
+19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,20,
+20,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19,
+19,19,19,18,18,18,18,18,18,17,17,17,17,17,17,16,
+16,16,15,14,14,14,14,14,13,13,13,13,12,12,12,10,
+10,10,10,9,9,9,9,8,8,8,7,7,7,6,6,6,
+6,4,4,4,0,0,0,1,1,1,1,2,2,2,3,24,
+24,24,25,25,25,26,26,26,26,27,27,27,27,29,29,28,
+28,30,30,30,30,30,31,31,31,31,31,32,32,32,32,32,
+32,33,33,33,33,33,35,35,35,35,34,34,34,34,34,34,
+34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
+35,35,35,35,35,33,33,33,33,33,33,32,32,32,32,32,
+32,32,31,31,31,31,31,30,30,30,30,30,28,28,28,29,
+29,27,27,27,27,26,26,26,26,25,25,25,24,24,24,3,
+2,2,2,2,1,1,1,0,0,0,0,4,4,4,6,6,
+6,7,7,7,7,8,8,8,9,9,9,9,10,10,10,10,
+12,12,12,12,13,13,13,13,14,14,14,14,15,15,16,16,
+16,16,17,17,17,17,17,18,18,18,18,18,18,18,18,19,
+19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
+19,18,18,18,18,18,18,18,17,17,17,17,17,17,16,16,
+16,16,15,14,14,14,14,14,13,13,13,13,12,12,12,12,
+10,10,10,11,9,9,9,8,8,8,8,7,7,7,6,6,
+6,6,4,4,4,0,0,0,0,1,1,1,2,2,2,2,
+3,24,24,25,25,25,25,26,26,26,26,27,27,27,27,29,
+29,28,28,30,30,30,30,30,31,31,31,31,31,31,32,32,
+32,32,32,32,32,33,33,33,33,33,33,35,35,35,35,35,
+33,33,35,35,35,35,35,35,35,35,35,35,35,35,35,35,
+33,33,33,33,33,33,33,33,32,32,32,32,32,32,32,32,
+32,31,31,31,31,31,31,30,30,30,30,30,28,28,28,29,
+29,27,27,27,27,26,26,26,26,25,25,25,25,24,24,24,
+3,2,2,2,1,1,1,1,0,0,0,4,4,4,4,6,
+6,6,6,7,7,7,8,8,8,8,9,9,9,9,10,10,
+10,10,12,12,12,12,13,13,13,13,14,14,14,14,14,15,
+16,16,16,16,17,17,17,17,17,17,17,18,18,18,18,18,
+18,18,18,18,19,19,19,19,19,19,19,19,19,19,19,19,
+19,19,19,19,19,19,19,19,19,19,19,19,19,19,18,18,
+18,18,18,18,18,18,18,17,17,17,17,17,17,16,16,16,
+16,15,15,14,14,14,14,13,13,13,13,13,12,12,12,12,
+10,10,10,10,9,9,9,9,8,8,8,7,7,7,7,6,
+6,6,6,4,4,4,0,0,0,0,1,1,1,2,2,2,
+2,3,24,24,24,25,25,25,25,26,26,26,26,27,27,27,
+27,29,29,28,28,28,30,30,30,30,30,31,31,31,31,31,
+31,32,32,32,32,32,32,32,32,33,33,33,33,33,33,33,
+33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
+33,33,33,33,32,32,32,32,32,32,32,32,32,32,32,31,
+31,31,31,31,31,31,30,30,30,30,30,28,28,28,29,29,
+27,27,27,27,27,26,26,26,26,25,25,25,25,24,24,24,
+3,2,2,2,2,1,1,1,1,0,0,0,0,4,4,4,
+6,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,
+10,10,10,10,12,12,12,12,13,13,13,13,13,14,14,14,
+14,14,15,16,16,16,16,16,17,17,17,17,17,17,17,17,
+18,18,18,18,18,18,18,18,18,18,18,18,18,18,19,19,
+19,19,19,19,19,19,18,18,18,18,18,18,18,18,18,18,
+18,18,18,18,17,17,17,17,17,17,17,17,16,16,16,16,
+16,15,14,14,14,14,14,13,13,13,13,13,12,12,12,12,
+10,10,10,10,9,9,9,9,8,8,8,8,7,7,7,7,
+6,6,6,6,4,4,4,0,0,0,0,1,1,1,1,2,
+2,2,2,3,24,24,24,25,25,25,25,26,26,26,26,27,
+27,27,27,27,29,29,28,28,28,30,30,30,30,30,31,31,
+31,31,31,31,31,32,32,32,32,32,32,32,32,32,32,32,
+32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
+32,32,32,32,32,32,32,32,32,32,32,32,31,31,31,31,
+31,31,31,31,30,30,30,30,30,30,28,28,28,28,29,29,
+27,27,27,27,27,26,26,26,26,25,25,25,25,25,24,24,
+24,3,2,2,2,2,1,1,1,1,0,0,0,0,4,4,
+4,5,6,6,6,6,7,7,7,8,8,8,8,8,9,9,
+9,9,10,10,10,10,12,12,12,12,12,13,13,13,13,13,
+14,14,14,14,14,15,15,16,16,16,16,16,17,17,17,17,
+17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,
+18,17,17,17,17,17,17,17,17,17,16,16,16,16,16,15,
+15,14,14,14,14,14,14,13,13,13,13,13,12,12,12,12,
+10,10,10,10,11,9,9,9,9,8,8,8,8,7,7,7,
+7,6,6,6,6,4,4,4,4,0,0,0,0,1,1,1,
+2,2,2,2,2,3,24,24,24,25,25,25,25,26,26,26,
+26,26,27,27,27,27,29,29,29,28,28,28,30,30,30,30,
+30,30,31,31,31,31,31,31,31,31,31,32,32,32,32,32,
+31,31,31,32,32,32,32,32,32,32,32,32,32,32,32,32,
+32,32,32,32,32,32,31,31,31,31,31,31,31,31,31,31,
+31,31,30,30,30,30,30,30,30,28,28,28,28,29,29,27,
+27,27,27,27,27,26,26,26,26,26,25,25,25,25,24,24,
+24,3,3,2,2,2,2,1,1,1,1,0,0,0,0,4,
+4,4,4,6,6,6,6,7,7,7,7,8,8,8,8,8,
+9,9,9,9,10,10,10,10,10,12,12,12,12,12,13,13,
+13,13,13,14,14,14,14,14,14,14,15,16,16,16,16,16,
+16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+17,17,17,17,17,17,17,16,16,16,16,16,16,16,15,14,
+14,14,14,14,14,14,13,13,13,13,13,12,12,12,12,12,
+10,10,10,10,10,9,9,9,9,8,8,8,8,8,7,7,
+7,7,6,6,6,6,4,4,4,4,0,0,0,0,1,1,
+1,1,2,2,2,2,2,3,24,24,24,25,25,25,25,25,
+26,26,26,26,27,27,27,27,27,27,29,29,28,28,28,28,
+30,30,30,30,30,30,30,31,31,31,31,31,31,31,31,31,
+31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,
+31,31,31,31,31,31,31,31,31,31,31,31,31,31,30,30,
+30,30,30,30,30,30,30,28,28,28,28,29,29,29,27,27,
+27,27,27,27,26,26,26,26,26,26,25,25,25,25,25,24,
+24,24,3,2,2,2,2,2,1,1,1,1,0,0,0,0,
+4,4,4,4,5,6,6,6,6,7,7,7,7,7,8,8,
+8,8,9,9,9,9,9,10,10,10,10,10,12,12,12,12,
+12,13,13,13,13,13,13,14,14,14,14,14,14,14,14,15,
+15,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,
+17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
+17,17,16,16,16,16,16,16,16,16,16,15,15,14,14,14,
+14,14,14,14,14,13,13,13,13,13,13,12,12,12,12,12,
+10,10,10,10,10,9,9,9,9,9,8,8,8,8,8,7,
+7,7,7,6,6,6,6,5,4,4,4,4,0,0,0,0,
+1,1,1,1,2,2,2,2,2,3,24,24,24,24,25,25,
+25,25,25,26,26,26,26,26,27,27,27,27,27,27,29,29,
+29,28,28,28,28,30,30,30,30,30,30,30,30,30,31,31,
+30,30,30,30,30,30,30,30,30,30,30,30,31,31,31,31,
+31,31,31,31,30,30,30,30,30,30,30,30,30,30,30,30,
+30,30,30,30,28,28,28,28,28,29,29,29,29,27,27,27,
+27,27,27,27,26,26,26,26,26,25,25,25,25,25,25,24,
+24,24,3,3,2,2,2,2,2,1,1,1,1,0,0,0,
+0,0,4,4,4,4,5,6,6,6,6,7,7,7,7,7,
+8,8,8,8,8,9,9,9,9,9,10,10,10,10,10,12,
+12,12,12,12,12,13,13,13,13,13,13,13,13,14,14,14,
+14,14,14,14,14,14,15,15,15,16,16,16,16,16,16,16,
+16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
+16,16,16,16,16,16,16,15,15,15,14,14,14,14,14,14,
+14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12,
+10,10,10,10,10,9,9,9,9,9,9,8,8,8,8,7,
+7,7,7,7,6,6,6,6,6,4,4,4,4,0,0,0,
+0,0,1,1,1,1,1,2,2,2,2,2,3,24,24,24,
+24,25,25,25,25,25,26,26,26,26,26,26,27,27,27,27,
+27,27,27,29,29,29,28,28,28,28,28,30,30,30,30,30,
+28,28,28,28,30,30,30,30,30,30,30,30,30,30,30,30,
+30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,28,
+28,28,28,28,28,28,29,29,29,29,27,27,27,27,27,27,
+27,27,26,26,26,26,26,26,26,25,25,25,25,25,25,24,
+24,24,24,3,2,2,2,2,2,2,1,1,1,1,1,0,
+0,0,0,0,4,4,4,4,5,6,6,6,6,6,7,7,
+7,7,7,8,8,8,8,8,9,9,9,9,9,9,10,10,
+10,10,10,10,12,12,12,12,12,12,12,13,13,13,13,13,
+13,13,13,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,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
+13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,10,
+10,10,10,10,10,11,9,9,9,9,9,8,8,8,8,8,
+7,7,7,7,7,6,6,6,6,6,5,4,4,4,4,0,
+0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,3,
+24,24,24,24,25,25,25,25,25,25,26,26,26,26,26,26,
+26,27,27,27,27,27,27,27,27,29,29,29,29,28,28,28,
+27,29,29,29,29,29,29,29,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,27,27,27,27,27,27,27,27,27,27,
+26,26,26,26,26,26,26,26,25,25,25,25,25,25,25,24,
+24,24,24,3,3,2,2,2,2,2,2,1,1,1,1,1,
+0,0,0,0,0,0,4,4,4,4,5,6,6,6,6,6,
+7,7,7,7,7,7,8,8,8,8,8,8,9,9,9,9,
+9,9,10,10,10,10,10,10,10,12,12,12,12,12,12,12,
+12,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,13,13,13,13,13,
+13,13,13,13,13,13,12,12,12,12,12,12,12,12,10,10,
+10,10,10,10,10,9,9,9,9,9,9,9,8,8,8,8,
+8,7,7,7,7,7,7,6,6,6,6,6,5,4,4,4,
+4,4,0,0,0,0,0,1,1,1,1,1,1,2,2,2,
+2,2,3,3,24,24,24,24,25,25,25,25,25,25,25,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,29,29,29,29,29,29,29,29,29,29,27,27,27,27,27,
+27,27,27,27,27,27,27,27,27,27,27,27,27,26,26,26,
+26,26,26,26,26,26,26,25,25,25,25,25,25,25,25,24,
+24,24,24,24,3,3,2,2,2,2,2,2,1,1,1,1,
+1,1,0,0,0,0,0,0,4,4,4,4,4,5,6,6,
+6,6,6,6,7,7,7,7,7,7,8,8,8,8,8,8,
+9,9,9,9,9,9,9,11,10,10,10,10,10,10,10,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,13,13,13,13,13,13,
+13,13,12,12,12,12,12,12,12,12,12,12,12,10,10,10,
+10,10,10,10,11,9,9,9,9,9,9,9,8,8,8,8,
+8,8,7,7,7,7,7,7,6,6,6,6,6,6,5,4,
+4,4,4,4,0,0,0,0,0,0,1,1,1,1,1,1,
+2,2,2,2,2,2,3,3,24,24,24,24,24,25,25,25,
+25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,27,
+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,26,26,26,26,26,26,26,26,26,
+26,26,26,26,26,25,25,25,25,25,25,25,25,25,24,24,
+24,24,24,24,3,3,2,2,2,2,2,2,2,1,1,1,
+1,1,1,1,0,0,0,0,0,0,4,4,4,4,4,4,
+5,6,6,6,6,6,6,7,7,7,7,7,7,7,8,8,
+8,8,8,8,8,9,9,9,9,9,9,9,9,9,10,10,
+10,10,10,10,10,10,10,10,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,12,12,12,12,12,12,12,12,
+12,12,12,12,12,12,12,12,12,12,10,10,10,10,10,10,
+10,10,10,11,9,9,9,9,9,9,9,9,8,8,8,8,
+8,8,8,7,7,7,7,7,7,7,6,6,6,6,6,6,
+6,4,4,4,4,4,4,0,0,0,0,0,0,0,1,1,
+1,1,1,1,2,2,2,2,2,2,2,2,3,3,24,24,
+24,24,24,24,25,25,25,25,25,25,25,25,25,26,26,26,
+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,26,26,26,26,26,26,26,26,
+25,25,25,25,25,25,25,25,25,25,25,25,25,24,24,24,
+24,24,24,24,3,3,2,2,2,2,2,2,2,2,2,1,
+1,1,1,1,1,1,0,0,0,0,0,0,0,4,4,4,
+4,4,4,4,5,6,6,6,6,6,6,6,7,7,7,7,
+7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,
+9,9,9,9,9,9,11,10,10,10,10,10,10,10,10,10,
+10,10,10,10,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,10,10,10,10,10,10,10,10,10,10,10,10,
+10,11,9,9,9,9,9,9,9,9,9,9,8,8,8,8,
+8,8,8,8,8,7,7,7,7,7,7,7,6,6,6,6,
+6,6,6,6,4,4,4,4,4,4,4,0,0,0,0,0,
+0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,
+2,2,3,3,24,24,24,24,24,24,24,25,25,25,25,25,
+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,25,25,25,25,25,25,25,25,25,25,
+25,25,25,25,25,25,25,25,25,25,24,24,24,24,24,24,
+24,24,24,3,3,3,2,2,2,2,2,2,2,2,2,2,
+1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
+0,4,4,4,4,4,4,4,5,6,6,6,6,6,6,6,
+6,6,7,7,7,7,7,7,7,7,7,8,8,8,8,8,
+8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,
+9,9,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,11,9,9,
+9,9,9,9,9,9,9,9,9,9,9,9,8,8,8,8,
+8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,6,
+6,6,6,6,6,6,6,5,4,4,4,4,4,4,4,0,
+0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,
+2,2,2,2,2,2,2,2,2,2,3,3,3,24,24,24,
+2,2,2,2,2,3,3,3,3,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,24,24,24,24,24,24,24,24,24,24,24,24,
+24,24,3,3,3,3,2,2,2,2,2,2,2,2,2,2,
+2,2,1,1,1,1,1,1,1,1,1,1,0,0,0,0,
+0,0,0,0,0,0,4,4,4,4,4,4,4,4,5,6,
+6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,
+7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,
+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,11,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,7,7,7,7,7,7,7,7,7,
+7,7,6,6,6,6,6,6,6,6,6,5,4,4,4,4,
+4,4,4,4,4,0,0,0,0,0,0,0,0,0,1,1,
+1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,
+1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,3,3,3,3,3,3,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,24,24,24,24,3,3,
+3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,
+1,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,
+4,4,4,4,4,4,5,6,6,6,6,6,6,6,6,6,
+6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,8,
+8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+8,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,7,7,7,7,7,7,7,
+7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,6,
+6,5,4,4,4,4,4,4,4,4,4,4,0,0,0,0,
+0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1
+};
diff --git a/ops.h b/ops.h
new file mode 100644 (file)
index 0000000..7e7075a
--- /dev/null
+++ b/ops.h
@@ -0,0 +1,479 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+case 0x00:  /* BRK */
+            _PC++;
+            PUSH(_PC>>8);
+            PUSH(_PC);
+            PUSH(_P|U_FLAG|B_FLAG);
+           _P|=I_FLAG;
+            _PC=RdMem(0xFFFE);
+            _PC|=RdMem(0xFFFF)<<8;
+            break;
+
+case 0x40:  /* RTI */
+            _P=POP();
+           _PI=_P;
+            _PC=POP();
+            _PC|=POP()<<8;
+            break;
+            
+case 0x60:  /* RTS */
+            _PC=POP();
+            _PC|=POP()<<8;
+            _PC++;
+            break;
+
+case 0x48: /* PHA */
+           PUSH(_A);
+           break;
+case 0x08: /* PHP */
+           PUSH(_P|U_FLAG|B_FLAG);
+           break;
+case 0x68: /* PLA */
+           _A=POP();
+           X_ZN(_A);
+           break;
+case 0x28: /* PLP */
+           _P=POP();
+           break;
+case 0x4C:
+         {
+          uint16 ptmp=_PC;
+          unsigned int npc;
+
+          npc=RdMem(ptmp);
+          ptmp++;
+          npc|=RdMem(ptmp)<<8;
+          _PC=npc;
+         }
+         break; /* JMP ABSOLUTE */
+case 0x6C: 
+          {
+           uint32 tmp;
+           GetAB(tmp);
+           _PC=RdMem(tmp);
+           _PC|=RdMem( ((tmp+1)&0x00FF) | (tmp&0xFF00))<<8;
+          }
+          break;
+case 0x20: /* JSR */
+          {
+           uint8 npc;
+           npc=RdMem(_PC++);
+            PUSH(_PC>>8);
+            PUSH(_PC);
+            _PC=RdMem(_PC)<<8;
+           _PC|=npc;
+          }
+           break;
+
+case 0xAA: /* TAX */
+           _X=_A;
+           X_ZN(_A);
+           break;
+
+case 0x8A: /* TXA */
+           _A=_X;
+           X_ZN(_A);
+           break;
+
+case 0xA8: /* TAY */
+           _Y=_A;
+           X_ZN(_A);
+           break;
+case 0x98: /* TYA */
+           _A=_Y;
+           X_ZN(_A);
+           break;
+
+case 0xBA: /* TSX */
+           _X=_S;
+           X_ZN(_X);
+           break;
+case 0x9A: /* TXS */
+           _S=_X;
+           break;
+
+case 0xCA: /* DEX */
+           _X--;
+           X_ZN(_X);
+           break;
+case 0x88: /* DEY */
+           _Y--;
+           X_ZN(_Y);
+           break;
+
+case 0xE8: /* INX */
+           _X++;
+           X_ZN(_X);
+           break;
+case 0xC8: /* INY */
+           _Y++;
+           X_ZN(_Y);
+           break;
+
+case 0x18: /* CLC */
+           _P&=~C_FLAG;
+           break;
+case 0xD8: /* CLD */
+           _P&=~D_FLAG;
+           break;
+case 0x58: /* CLI */
+           _P&=~I_FLAG;
+           break;
+case 0xB8: /* CLV */
+           _P&=~V_FLAG;
+           break;
+
+case 0x38: /* SEC */
+           _P|=C_FLAG;
+           break;
+case 0xF8: /* SED */
+           _P|=D_FLAG;
+           break;
+case 0x78: /* SEI */
+           _P|=I_FLAG;
+           break;
+
+case 0xEA: /* NOP */
+           break;
+
+case 0x0A: RMW_A(ASL);
+case 0x06: RMW_ZP(ASL);
+case 0x16: RMW_ZPX(ASL);
+case 0x0E: RMW_AB(ASL);
+case 0x1E: RMW_ABX(ASL);
+
+case 0xC6: RMW_ZP(DEC);
+case 0xD6: RMW_ZPX(DEC);
+case 0xCE: RMW_AB(DEC);
+case 0xDE: RMW_ABX(DEC);
+
+case 0xE6: RMW_ZP(INC);
+case 0xF6: RMW_ZPX(INC);
+case 0xEE: RMW_AB(INC);
+case 0xFE: RMW_ABX(INC);
+
+case 0x4A: RMW_A(LSR);
+case 0x46: RMW_ZP(LSR);
+case 0x56: RMW_ZPX(LSR);
+case 0x4E: RMW_AB(LSR);
+case 0x5E: RMW_ABX(LSR);
+
+case 0x2A: RMW_A(ROL);
+case 0x26: RMW_ZP(ROL);
+case 0x36: RMW_ZPX(ROL);
+case 0x2E: RMW_AB(ROL);
+case 0x3E: RMW_ABX(ROL);
+
+case 0x6A: RMW_A(ROR);
+case 0x66: RMW_ZP(ROR);
+case 0x76: RMW_ZPX(ROR);
+case 0x6E: RMW_AB(ROR);
+case 0x7E: RMW_ABX(ROR);
+
+case 0x69: LD_IM(ADC);
+case 0x65: LD_ZP(ADC);
+case 0x75: LD_ZPX(ADC);
+case 0x6D: LD_AB(ADC);
+case 0x7D: LD_ABX(ADC);
+case 0x79: LD_ABY(ADC);
+case 0x61: LD_IX(ADC);
+case 0x71: LD_IY(ADC);
+
+case 0x29: LD_IM(AND);
+case 0x25: LD_ZP(AND);
+case 0x35: LD_ZPX(AND);
+case 0x2D: LD_AB(AND);
+case 0x3D: LD_ABX(AND);
+case 0x39: LD_ABY(AND);
+case 0x21: LD_IX(AND);
+case 0x31: LD_IY(AND);
+
+case 0x24: LD_ZP(BIT);
+case 0x2C: LD_AB(BIT);
+
+case 0xC9: LD_IM(CMP);
+case 0xC5: LD_ZP(CMP);
+case 0xD5: LD_ZPX(CMP);
+case 0xCD: LD_AB(CMP);
+case 0xDD: LD_ABX(CMP);
+case 0xD9: LD_ABY(CMP);
+case 0xC1: LD_IX(CMP);
+case 0xD1: LD_IY(CMP);
+
+case 0xE0: LD_IM(CPX);
+case 0xE4: LD_ZP(CPX);
+case 0xEC: LD_AB(CPX);
+
+case 0xC0: LD_IM(CPY);
+case 0xC4: LD_ZP(CPY);
+case 0xCC: LD_AB(CPY);
+
+case 0x49: LD_IM(EOR);
+case 0x45: LD_ZP(EOR);
+case 0x55: LD_ZPX(EOR);
+case 0x4D: LD_AB(EOR);
+case 0x5D: LD_ABX(EOR);
+case 0x59: LD_ABY(EOR);
+case 0x41: LD_IX(EOR);
+case 0x51: LD_IY(EOR);
+
+case 0xA9: LD_IM(LDA);
+case 0xA5: LD_ZP(LDA);
+case 0xB5: LD_ZPX(LDA);
+case 0xAD: LD_AB(LDA);
+case 0xBD: LD_ABX(LDA);
+case 0xB9: LD_ABY(LDA);
+case 0xA1: LD_IX(LDA);
+case 0xB1: LD_IY(LDA);
+
+case 0xA2: LD_IM(LDX);
+case 0xA6: LD_ZP(LDX);
+case 0xB6: LD_ZPY(LDX);
+case 0xAE: LD_AB(LDX);
+case 0xBE: LD_ABY(LDX);
+
+case 0xA0: LD_IM(LDY);
+case 0xA4: LD_ZP(LDY);
+case 0xB4: LD_ZPX(LDY);
+case 0xAC: LD_AB(LDY);
+case 0xBC: LD_ABX(LDY);
+
+case 0x09: LD_IM(ORA);
+case 0x05: LD_ZP(ORA);
+case 0x15: LD_ZPX(ORA);
+case 0x0D: LD_AB(ORA);
+case 0x1D: LD_ABX(ORA);
+case 0x19: LD_ABY(ORA);
+case 0x01: LD_IX(ORA);
+case 0x11: LD_IY(ORA);
+
+case 0xEB:     /* (undocumented) */
+case 0xE9: LD_IM(SBC);
+case 0xE5: LD_ZP(SBC);
+case 0xF5: LD_ZPX(SBC);
+case 0xED: LD_AB(SBC);
+case 0xFD: LD_ABX(SBC);
+case 0xF9: LD_ABY(SBC);
+case 0xE1: LD_IX(SBC);
+case 0xF1: LD_IY(SBC);
+
+case 0x85: ST_ZP(_A);
+case 0x95: ST_ZPX(_A);
+case 0x8D: ST_AB(_A);
+case 0x9D: ST_ABX(_A);
+case 0x99: ST_ABY(_A);
+case 0x81: ST_IX(_A);
+case 0x91: ST_IY(_A);
+
+case 0x86: ST_ZP(_X);
+case 0x96: ST_ZPY(_X);
+case 0x8E: ST_AB(_X);
+
+case 0x84: ST_ZP(_Y);
+case 0x94: ST_ZPX(_Y);
+case 0x8C: ST_AB(_Y);
+
+/* BCC */
+case 0x90: if(_P&C_FLAG) _PC++; else {JR();} break;
+
+/* BCS */
+case 0xB0: if(_P&C_FLAG) {JR();} else _PC++; break;
+
+/* BEQ */
+case 0xF0: if(_P&Z_FLAG) {JR();} else _PC++; break;
+
+/* BNE */
+case 0xD0: if(_P&Z_FLAG) _PC++; else {JR();} break;
+
+/* BMI */
+case 0x30: if(_P&N_FLAG) {JR();} else _PC++; break;
+
+/* BPL */
+case 0x10: if(_P&N_FLAG) _PC++; else {JR();} break;
+
+/* BVC */
+case 0x50: if(_P&V_FLAG) _PC++; else {JR();} break;
+
+/* BVS */
+case 0x70: if(_P&V_FLAG) {JR();} else _PC++; break;
+
+/* Here comes the undocumented instructions.  Note that this implementation
+   may be "wrong".  If so, please tell me.
+*/
+
+/* AAC */
+case 0x2B:
+case 0x0B: LD_IM(AND;_P&=~C_FLAG;_P|=_A>>7);
+
+/* AAX */
+case 0x87: ST_ZP(_A&_X);
+case 0x97: ST_ZPY(_A&_X);
+case 0x8F: ST_AB(_A&_X);
+case 0x83: ST_IX(_A&_X);
+
+/* ARR - ARGH, MATEY! */
+case 0x6B: { 
+            uint8 arrtmp; 
+            LD_IM(AND;_P&=~V_FLAG;_P|=(_A^(_A>>1))&0x40;arrtmp=_A>>7;_A>>=1;_A|=(_P&C_FLAG)<<7;_P&=~C_FLAG;_P|=arrtmp;X_ZN(_A));
+          }
+/* ASR */
+case 0x4B: LD_IM(AND;LSRA);
+
+/* ATX(OAL) Is this(OR with $EE) correct? */
+case 0xAB: LD_IM(_A|=0xEE;AND;_X=_A);
+
+/* AXS */ 
+case 0xCB: LD_IM(AXS);
+
+/* DCP */
+case 0xC7: LD_ZP(DEC;CMP);
+case 0xD7: LD_ZPX(DEC;CMP);
+case 0xCF: LD_AB(DEC;CMP);
+case 0xDF: LD_ABX(DEC;CMP);
+case 0xDB: LD_ABY(DEC;CMP);
+case 0xC3: LD_IX(DEC;CMP);
+case 0xD3: LD_IY(DEC;CMP);
+
+/* ISC */
+case 0xE7: LD_ZP(INC;SBC);
+case 0xF7: LD_ZPX(INC;SBC);
+case 0xEF: LD_AB(INC;SBC);
+case 0xFF: LD_ABX(INC;SBC);
+case 0xFB: LD_ABY(INC;SBC);
+case 0xE3: LD_IX(INC;SBC);
+case 0xF3: LD_IY(INC;SBC);
+
+/* DOP */
+
+case 0x04: _PC++;break;
+case 0x14: _PC++;break;
+case 0x34: _PC++;break;
+case 0x44: _PC++;break;
+case 0x54: _PC++;break;
+case 0x64: _PC++;break;
+case 0x74: _PC++;break;
+
+case 0x80: _PC++;break;
+case 0x82: _PC++;break;
+case 0x89: _PC++;break;
+case 0xC2: _PC++;break;
+case 0xD4: _PC++;break;
+case 0xE2: _PC++;break;
+case 0xF4: _PC++;break;
+
+/* KIL */
+
+case 0x02:
+case 0x12:
+case 0x22:
+case 0x32:
+case 0x42:
+case 0x52:
+case 0x62:
+case 0x72:
+case 0x92:
+case 0xB2:
+case 0xD2:
+case 0xF2:ADDCYC(0xFF);
+          _jammed=1;
+         _PC--;
+         break;
+
+/* LAR */
+case 0xBB: RMW_ABY(_S&=x;_A=_X=_S;X_ZN(_X));
+
+/* LAX */
+case 0xA7: LD_ZP(LDA;LDX);
+case 0xB7: LD_ZPY(LDA;LDX);
+case 0xAF: LD_AB(LDA;LDX);
+case 0xBF: LD_ABY(LDA;LDX);
+case 0xA3: LD_IX(LDA;LDX);
+case 0xB3: LD_IY(LDA;LDX);
+
+/* NOP */
+case 0x1A:
+case 0x3A:
+case 0x5A:
+case 0x7A:
+case 0xDA:
+case 0xFA: break;
+
+/* RLA */
+case 0x27: RMW_ZP(ROL;AND);
+case 0x37: RMW_ZPX(ROL;AND);
+case 0x2F: RMW_AB(ROL;AND);
+case 0x3F: RMW_ABX(ROL;AND);
+case 0x3B: RMW_ABY(ROL;AND);
+case 0x23: RMW_IX(ROL;AND);
+case 0x33: RMW_IY(ROL;AND);
+
+/* RRA */
+case 0x67: RMW_ZP(ROR;ADC);
+case 0x77: RMW_ZPX(ROR;ADC);
+case 0x6F: RMW_AB(ROR;ADC);
+case 0x7F: RMW_ABX(ROR;ADC);
+case 0x7B: RMW_ABY(ROR;ADC);
+case 0x63: RMW_IX(ROR;ADC);
+case 0x73: RMW_IY(ROR;ADC);
+
+/* SLO */
+case 0x07: RMW_ZP(ASL;ORA);
+case 0x17: RMW_ZPX(ASL;ORA);
+case 0x0F: RMW_AB(ASL;ORA);
+case 0x1F: RMW_ABX(ASL;ORA);
+case 0x1B: RMW_ABY(ASL;ORA);
+case 0x03: RMW_IX(ASL;ORA);
+case 0x13: RMW_IY(ASL;ORA);
+
+/* SRE */
+case 0x47: RMW_ZP(LSR;EOR);
+case 0x57: RMW_ZPX(LSR;EOR);
+case 0x4F: RMW_AB(LSR;EOR);
+case 0x5F: RMW_ABX(LSR;EOR);
+case 0x5B: RMW_ABY(LSR;EOR);
+case 0x43: RMW_IX(LSR;EOR);
+case 0x53: RMW_IY(LSR;EOR);
+
+/* AXA - SHA */
+case 0x93: ST_IY(_A&_X&(((A-_Y)>>8)+1));
+case 0x9F: ST_ABY(_A&_X&(((A-_Y)>>8)+1));
+
+/* SYA */
+case 0x9C: ST_ABX(_Y&(((A-_X)>>8)+1));
+
+/* SXA */
+case 0x9E: ST_ABY(_X&(((A-_Y)>>8)+1));
+
+/* XAS */
+case 0x9B: _S=_A&_X;ST_ABY(_S& (((A-_Y)>>8)+1) );
+
+/* TOP */
+case 0x0C: LD_AB(;);
+case 0x1C: 
+case 0x3C: 
+case 0x5C: 
+case 0x7C: 
+case 0xDC: 
+case 0xFC: LD_ABX(;);
+
+/* XAA - BIG QUESTION MARK HERE */
+case 0x8B: _A|=0xEE; _A&=_X; LD_IM(AND);
diff --git a/palette.h b/palette.h
new file mode 100644 (file)
index 0000000..9a4647c
--- /dev/null
+++ b/palette.h
@@ -0,0 +1,120 @@
+pal rp2c04001[64] = {
+ #include "palettes/rp2c04001.h"
+};
+
+pal NSFPalette[39] = {
+ #include "palettes/nsfnew.h"
+};
+
+pal palettevseb[64] = {
+#include "palettes/vseb.h"
+};
+
+pal palettevsslalom[64] = {
+#include "palettes/vsslalom.h"
+};
+
+pal palettevsgoon[64] = {
+#include "palettes/vsgoonies.h"
+};
+
+pal palettevsgrad[64] = {
+#include "palettes/vsplatoon.h"
+};
+
+pal palettevscv[64] = {
+#include "palettes/vscv.h"
+};
+
+pal palettevssmb[64] = {
+#include "palettes/vssmb.h"
+};
+
+pal palettevsmar[64] = {
+#include "palettes/vsmar.h"
+};
+
+pal unvpalette[6] = {
+{ 0x00<<2,0x00<<2,0x00<<2}, // Black
+{ 0x3F<<2,0x3F<<2,0x34<<2}, // White
+{ 0x00<<2,0x00<<2,0x00<<2}, // Black
+{ 0x1d<<2,0x1d<<2,0x24<<2}, // Greyish
+{ 190,0,0    }, // Redish
+{ 51,255,51}, // Bright green
+};
+
+
+/* These are dynamically filled/generated palettes: */
+pal palettei[64];      // Custom palette for an individual game.
+pal palettec[64];      // Custom "global" palette.
+pal paletten[64];      // Mathematically generated palette.
+
+
+/* Default palette */
+pal palette[64] = {
+
+        { 0x1D<<2, 0x1D<<2, 0x1D<<2 }, /* Value 0 */
+        { 0x09<<2, 0x06<<2, 0x23<<2 }, /* Value 1 */
+        { 0x00<<2, 0x00<<2, 0x2A<<2 }, /* Value 2 */
+        { 0x11<<2, 0x00<<2, 0x27<<2 }, /* Value 3 */
+        { 0x23<<2, 0x00<<2, 0x1D<<2 }, /* Value 4 */
+        { 0x2A<<2, 0x00<<2, 0x04<<2 }, /* Value 5 */
+        { 0x29<<2, 0x00<<2, 0x00<<2 }, /* Value 6 */
+        { 0x1F<<2, 0x02<<2, 0x00<<2 }, /* Value 7 */
+        { 0x10<<2, 0x0B<<2, 0x00<<2 }, /* Value 8 */
+        { 0x00<<2, 0x11<<2, 0x00<<2 }, /* Value 9 */
+        { 0x00<<2, 0x14<<2, 0x00<<2 }, /* Value 10 */
+        { 0x00<<2, 0x0F<<2, 0x05<<2 }, /* Value 11 */
+        { 0x06<<2, 0x0F<<2, 0x17<<2 }, /* Value 12 */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 13 */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 14 */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 15 */
+        { 0x2F<<2, 0x2F<<2, 0x2F<<2 }, /* Value 16 */
+        { 0x00<<2, 0x1C<<2, 0x3B<<2 }, /* Value 17 */
+        { 0x08<<2, 0x0E<<2, 0x3B<<2 }, /* Value 18 */
+        { 0x20<<2, 0x00<<2, 0x3C<<2 }, /* Value 19 */
+        { 0x2F<<2, 0x00<<2, 0x2F<<2 }, /* Value 20 */
+        { 0x39<<2, 0x00<<2, 0x16<<2 }, /* Value 21 */
+        { 0x36<<2, 0x0A<<2, 0x00<<2 }, /* Value 22 */
+        { 0x32<<2, 0x13<<2, 0x03<<2 }, /* Value 23 */
+        { 0x22<<2, 0x1C<<2, 0x00<<2 }, /* Value 24 */
+        { 0x00<<2, 0x25<<2, 0x00<<2 }, /* Value 25 */
+        { 0x00<<2, 0x2A<<2, 0x00<<2 }, /* Value 26 */
+        { 0x00<<2, 0x24<<2, 0x0E<<2 }, /* Value 27 */
+        { 0x00<<2, 0x20<<2, 0x22<<2 }, /* Value 28 */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 29 */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 30 */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 31 */
+        { 0x3F<<2, 0x3F<<2, 0x3F<<2 }, /* Value 32 */
+        { 0x0F<<2, 0x2F<<2, 0x3F<<2 }, /* Value 33 */
+        { 0x17<<2, 0x25<<2, 0x3F<<2 }, /* Value 34 */
+        { 0x10<<2, 0x22<<2, 0x3F<<2 }, /* Value 35 */
+        { 0x3D<<2, 0x1E<<2, 0x3F<<2 }, /* Value 36 */
+        { 0x3F<<2, 0x1D<<2, 0x2D<<2 }, /* Value 37 */
+        { 0x3F<<2, 0x1D<<2, 0x18<<2 }, /* Value 38 */
+        { 0x3F<<2, 0x26<<2, 0x0E<<2 }, /* Value 39 */
+        { 0x3C<<2, 0x2F<<2, 0x0F<<2 }, /* Value 40 */
+        { 0x20<<2, 0x34<<2, 0x04<<2 }, /* Value 41 */
+        { 0x13<<2, 0x37<<2, 0x12<<2 }, /* Value 42 */
+        { 0x16<<2, 0x3E<<2, 0x26<<2 }, /* Value 43 */
+        { 0x00<<2, 0x3A<<2, 0x36<<2 }, /* Value 44 */
+        { 0x1E<<2, 0x1E<<2, 0x1E<<2 }, /* Value 45 */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 46 */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 47 */
+        { 0x3F<<2, 0x3F<<2, 0x3F<<2 }, /* Value 48 */
+        { 0x2A<<2, 0x39<<2, 0x3F<<2 }, /* Value 49 */
+        { 0x31<<2, 0x35<<2, 0x3F<<2 }, /* Value 50 */
+        { 0x35<<2, 0x32<<2, 0x3F<<2 }, /* Value 51 */
+        { 0x3F<<2, 0x31<<2, 0x3F<<2 }, /* Value 52 */
+        { 0x3F<<2, 0x31<<2, 0x36<<2 }, /* Value 53 */
+        { 0x3F<<2, 0x2F<<2, 0x2C<<2 }, /* Value 54 */
+        { 0x3F<<2, 0x36<<2, 0x2A<<2 }, /* Value 55 */
+        { 0x3F<<2, 0x39<<2, 0x28<<2 }, /* Value 56 */
+        { 0x38<<2, 0x3F<<2, 0x28<<2 }, /* Value 57 */
+        { 0x2A<<2, 0x3C<<2, 0x2F<<2 }, /* Value 58 */
+        { 0x2C<<2, 0x3F<<2, 0x33<<2 }, /* Value 59 */
+        { 0x27<<2, 0x3F<<2, 0x3C<<2 }, /* Value 60 */
+        { 0x31<<2, 0x31<<2, 0x31<<2 }, /* Value 61 */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 62 */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 63 */
+};
diff --git a/palettes/nsfnew.h b/palettes/nsfnew.h
new file mode 100644 (file)
index 0000000..7ee0068
--- /dev/null
@@ -0,0 +1,39 @@
+{0<<2,14<<2,3<<2},
+{0<<2,13<<2,3<<2},
+{0<<2,12<<2,3<<2},
+{0<<2,11<<2,3<<2},
+{0<<2,15<<2,3<<2},
+{0<<2,15<<2,4<<2},
+{0<<2,16<<2,4<<2},
+{0<<2,17<<2,4<<2},
+{0<<2,18<<2,4<<2},
+{0<<2,19<<2,4<<2},
+{0<<2,20<<2,5<<2},
+{0<<2,20<<2,4<<2},
+{0<<2,21<<2,5<<2},
+{0<<2,22<<2,5<<2},
+{0<<2,23<<2,5<<2},
+{0<<2,24<<2,5<<2},
+{0<<2,24<<2,6<<2},
+{0<<2,25<<2,6<<2},
+{0<<2,26<<2,6<<2},
+{0<<2,27<<2,6<<2},
+{0<<2,28<<2,6<<2},
+{0<<2,28<<2,7<<2},
+{0<<2,29<<2,7<<2},
+{0<<2,30<<2,7<<2},
+{0<<2,11<<2,2<<2},
+{0<<2,10<<2,2<<2},
+{0<<2,9<<2,2<<2},
+{0<<2,8<<2,2<<2},
+{0<<2,7<<2,1<<2},
+{0<<2,7<<2,2<<2},
+{0<<2,6<<2,1<<2},
+{0<<2,5<<2,1<<2},
+{0<<2,4<<2,1<<2},
+{0<<2,3<<2,1<<2},
+{0<<2,2<<2,0<<2},
+{0<<2,3<<2,0<<2},
+{0<<2,1<<2,0<<2},
+{0<<2,0<<2,0<<2},
+{3<<2,0<<2,43<<2},
diff --git a/palettes/rp2c04001.h b/palettes/rp2c04001.h
new file mode 100644 (file)
index 0000000..f2526b9
--- /dev/null
@@ -0,0 +1,64 @@
+{ 0x3f<<2, 0x31<<2, 0x36<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x36<<2, 0x0a<<2, 0x00<<2, },
+{ 0x17<<2, 0x25<<2, 0x3f<<2, },
+{ 0x00<<2, 0x20<<2, 0x22<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x39<<2, 0x00<<2, 0x16<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x1d<<2, 0x1d<<2, 0x1d<<2, },
+{ 0x3f<<2, 0x26<<2, 0x0e<<2, },
+{ 0x2a<<2, 0x00<<2, 0x04<<2, },
+{ 0x23<<2, 0x00<<2, 0x1d<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x10<<2, 0x0b<<2, 0x00<<2, },
+{ 0x3f<<2, 0x3f<<2, 0x3f<<2, },
+{ 0x0f<<2, 0x2f<<2, 0x3f<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x20<<2, 0x34<<2, 0x04<<2, },
+{ 0x27<<2, 0x3f<<2, 0x3c<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x3f<<2, 0x2f<<2, 0x2c<<2, },
+{ 0x08<<2, 0x0e<<2, 0x3b<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x16<<2, 0x3e<<2, 0x26<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x09<<2, 0x06<<2, 0x23<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x2a<<2, 0x39<<2, 0x3f<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x13<<2, 0x37<<2, 0x12<<2, },
+{ 0x00<<2, 0x3a<<2, 0x36<<2, },
+{ 0x06<<2, 0x0f<<2, 0x17<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x1f<<2, 0x02<<2, 0x00<<2, },
+{ 0x3f<<2, 0x31<<2, 0x3f<<2, },
+{ 0x29<<2, 0x00<<2, 0x00<<2, },
+{ 0x20<<2, 0x00<<2, 0x3c<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x3f<<2, 0x1d<<2, 0x18<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x00<<2, 0x25<<2, 0x00<<2, },
+{ 0x2f<<2, 0x2f<<2, 0x2f<<2, },
+{ 0x00<<2, 0x14<<2, 0x00<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x32<<2, 0x13<<2, 0x03<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x00<<2, 0x1c<<2, 0x3b<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
+{ 0x3f<<2, 0x1d<<2, 0x2d<<2, },
+{ 0x22<<2, 0x1c<<2, 0x00<<2, },
+{ 0x00<<2, 0x00<<2, 0x00<<2, },
diff --git a/palettes/vscv.h b/palettes/vscv.h
new file mode 100644 (file)
index 0000000..8220f30
--- /dev/null
@@ -0,0 +1,64 @@
+{127,127,127},
+{255,163,71},
+{0,0,191},
+{71,43,191},
+{151,0,135},
+{248,88,152},
+{171,19,0},
+{248,184,248},
+{191,0,0},
+{0,120,0},
+{0,107,0},
+{0,91,0},
+{255,255,255},
+{152,120,248},
+{0,0,0},
+{0,0,0},
+{191,191,191},
+{0,120,248},
+{171,19,0},
+{107,71,255},
+{0,174,0},
+{231,0,91},
+{248,56,0},
+{119,119,255},
+{175,127,0},
+{0,184,0},
+{0,171,0},
+{0,171,71},
+{0,139,139},
+{0,0,0},
+{0,0,0},
+{71,43,191},
+{248,248,248},
+{255,227,171},
+{248,120,88},
+{152,120,248},
+{0,120,248},
+{248,88,152},
+{191,191,191},
+{255,163,71},
+{200,0,200},
+{184,248,24},
+{127,127,127},
+{0,120,0},
+{0,235,219},
+{0,0,0},
+{0,0,0},
+{255,255,255},
+{255,255,255},
+{167,231,255},
+{91,219,87},
+{231,95,19},
+{0,67,88},
+{0,0,255},
+{231,0,91},
+{0,184,0},
+{251,219,123},
+{216,248,120},
+{139,23,0},
+{255,227,171},
+{0,255,255},
+{171,0,35},
+{0,0,0},
+{0,0,0},
diff --git a/palettes/vseb.h b/palettes/vseb.h
new file mode 100644 (file)
index 0000000..234d993
--- /dev/null
@@ -0,0 +1,64 @@
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x2a<<2, 0x00<<2},
+{0x3f<<2, 0x3f<<2, 0x3f<<2},
+{0x27<<2, 0x3f<<2, 0x3c<<2},
+{0x00<<2, 0x11<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x2a<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x3f<<2, 0x3f<<2, 0x3f<<2},
+{0x31<<2, 0x35<<2, 0x3f<<2},
+{0x31,0xa6,0xf6}, 
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x08<<2, 0x0e<<2, 0x3b<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x22<<2, 0x1c<<2, 0x00<<2},
+{0x32<<2, 0x13<<2, 0x03<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x06<<2, 0x0f<<2, 0x17<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x2a<<2},
+{0x36<<2, 0x0a<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x3f<<2, 0x36<<2, 0x2a<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0xd8,0xd6,0xb1}, 
+{0x3f<<2, 0x26<<2, 0x0e<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x20<<2, 0x34<<2, 0x04<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x0f<<2, 0x2f<<2, 0x3f<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x1c<<2, 0x3b<<2},  
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x2a<<2, 0x39<<2, 0x3f<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0xc6,0x9D,0x62}, 
+{0x13<<2, 0x37<<2, 0x12<<2},
+{0x3c<<2, 0x2f<<2, 0x0f<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x20<<2, 0x00<<2, 0x3c<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
+{0x00<<2, 0x00<<2, 0x00<<2},
diff --git a/palettes/vsgoonies.h b/palettes/vsgoonies.h
new file mode 100644 (file)
index 0000000..9dd272e
--- /dev/null
@@ -0,0 +1,65 @@
+        { 0x1D<<2, 0x1D<<2, 0x1D <<2}, /* Value 0 */
+        { 0x09<<2, 0x06<<2, 0x23 <<2}, /* Value 1 */
+        { 0x00<<2, 0x00<<2, 0x2A <<2}, /* Value 2 */
+        { 0x2f<<2, 0x2f<<2, 0x2f <<2}, /* Value 3 */
+        { 0x23<<2, 0x00<<2, 0x1D <<2}, /* Value 4 */
+        { 0x3f<<2, 0x3f<<2, 0x3f <<2}, /* Value 5 */
+        { 0x2a<<2, 0x39<<2, 0x3f <<2}, /* Value 6 */
+        { 0x1F<<2, 0x02<<2, 0x00 <<2}, /* Value 7 */
+        { 0x09<<2, 0x06<<2, 0x23 <<2}, /* Value 8 */
+        { 0x00<<2, 0x00<<2, 0x00 <<2}, /* Value 9 */
+        { 0x3f<<2, 0x2f<<2, 0x2c <<2}, /* Value a */
+        { 0x00<<2, 0x0F<<2, 0x05 <<2}, /* Value b */
+        { 0x06<<2, 0x0F<<2, 0x17 <<2}, /* Value c */
+        { 0x00<<2, 0x00<<2, 0x00 <<2}, /* Value d */
+        { 0x00<<2, 0x00<<2, 0x00 <<2}, /* Value e */
+        { 0x00<<2, 0x00<<2, 0x00 <<2}, /* Value f */
+        { 0x2F<<2, 0x2F<<2, 0x2F <<2}, /* Value 10 */
+        { 0x00<<2, 0x1C<<2, 0x3B <<2}, /* Value 11 */
+        { 0x08<<2, 0x0E<<2, 0x3B <<2}, /* Value 12 */
+        { 0x08<<2, 0x0e<<2, 0x3b <<2}, /* Value 13 */
+        { 0x00<<2, 0x25<<2, 0x00 <<2}, /* Value 14 */
+        { 0x39<<2, 0x00<<2, 0x16 <<2}, /* Value 15 */ 
+        { 0x32<<2, 0x13<<2, 0x03 <<2}, /* Value 16 */
+        { 0x32<<2, 0x13<<2, 0x03 <<2}, /* Value 17 */
+        { 0x1d<<2, 0x1d<<2, 0x1d <<2}, /* Value 18 */
+        { 0x00<<2, 0x25<<2, 0x00 <<2}, /* Value 19 */
+        { 0x00<<2, 0x2A<<2, 0x00 <<2}, /* Value 1a */
+        { 0x00<<2, 0x00<<2, 0x2a <<2}, /* Value 1b */
+        { 0x36<<2, 0x0a<<2, 0x00 <<2}, /* Value 1c */
+        { 0x00<<2, 0x00<<2, 0x00 <<2}, /* Value 1d */
+        { 0x00<<2, 0x00<<2, 0x00 <<2}, /* Value 1e */
+        { 0x00<<2, 0x00<<2, 0x00 <<2}, /* Value 1f */
+        { 0x3F<<2, 0x3F<<2, 0x3F <<2}, /* Value 20 */
+        { 0x0F<<2, 0x2F<<2, 0x3F <<2}, /* Value 21 */
+        { 0x17<<2, 0x25<<2, 0x3F <<2}, /* Value 22 */
+        { 0x10<<2, 0x22<<2, 0x3F <<2}, /* Value 23 */
+        { 0x3D<<2, 0x1E<<2, 0x3F <<2}, /* Value 24 */
+        { 0x3F<<2, 0x26<<2, 0x0e <<2}, /* Value 25 */
+        { 0x3F<<2, 0x1D<<2, 0x18 <<2}, /* Value 26 */
+        { 0x3F<<2, 0x3f<<2, 0x3f <<2}, /* Value 27 */
+        { 0x3C<<2, 0x2F<<2, 0x0F <<2}, /* Value 28 */
+        { 0x20<<2, 0x34<<2, 0x04 <<2}, /* Value 29 */
+        { 0x17<<2, 0x25<<2, 0x3f <<2}, /* Value 2a */
+        { 0x16<<2, 0x3E<<2, 0x26 <<2}, /* Value 2b */
+        { 0x00<<2, 0x1c<<2, 0x3b <<2}, /* Value 2c */
+        { 0x00<<2, 0x00<<2, 0x00 <<2}, /* Value 2d */
+        { 0x00<<2, 0x00<<2, 0x00 <<2}, /* Value 2e */
+        { 0x00<<2, 0x00<<2, 0x00 <<2}, /* Value 2f */
+        { 0x3F<<2, 0x3F<<2, 0x3F <<2}, /* Value 30 */
+        { 0x2A<<2, 0x39<<2, 0x3F <<2}, /* Value 31 */
+        { 0x31<<2, 0x35<<2, 0x3F <<2}, /* Value 32 */
+        { 0x35<<2, 0x32<<2, 0x3F <<2}, /* Value 33 */
+        { 0x1F<<2, 0x02<<2, 0x00 <<2}, /* Value 34 */
+        { 0x3F<<2, 0x31<<2, 0x36 <<2}, /* Value 35 */
+        { 0x3F<<2, 0x2F<<2, 0x2C <<2}, /* Value 36 */
+        { 0x3F<<2, 0x36<<2, 0x2A <<2}, /* Value 37 */
+        { 0x3F<<2, 0x39<<2, 0x28 <<2}, /* Value 38 */
+        { 0x38<<2, 0x3F<<2, 0x28 <<2}, /* Value 39 */
+        { 0x2A<<2, 0x3C<<2, 0x2F <<2}, /* Value 3a */
+        { 0x2C<<2, 0x3F<<2, 0x33 <<2}, /* Value 3b */
+        { 0x27<<2, 0x3F<<2, 0x3C <<2}, /* Value 3c */
+        { 0x00<<2, 0x00<<2, 0x00 <<2}, /* Value 3d */
+        { 0x00<<2, 0x00<<2, 0x00 <<2}, /* Value 3e */
+        { 0x06<<2, 0x0f<<2, 0x17 <<2}, /* Value 3f */
+
diff --git a/palettes/vsgrad.h b/palettes/vsgrad.h
new file mode 100644 (file)
index 0000000..3f8c6fe
--- /dev/null
@@ -0,0 +1,65 @@
+        { 0x3f<<2, 0x31<<2, 0x36<<2 }, /* Value 0 */ // Done
+        { 0x09<<2, 0x06<<2, 0x23<<2 }, /* Value 1 */
+        { 0x36<<2, 0x0a<<2, 0x00<<2 }, /* Value 2 */ // Done
+        { 0x11<<2, 0x00<<2, 0x27<<2 }, /* Value 3 */
+        { 0x00<<2, 0x20<<2, 0x22<<2 }, /* Value 4 */ // Done
+        { 0x2A<<2, 0x00<<2, 0x04<<2 }, /* Value 5 */
+        { 0x29<<2, 0x00<<2, 0x00<<2 }, /* Value 6 */
+        { 0x1F<<2, 0x02<<2, 0x00<<2 }, /* Value 7 */
+        { 0x10<<2, 0x0B<<2, 0x00<<2 }, /* Value 8 */
+        { 0x00<<2, 0x11<<2, 0x00<<2 }, /* Value 9 */
+        { 0x3f<<2, 0x26<<2, 0x0e<<2 }, /* Value a */ // Done
+        { 0x00<<2, 0x0F<<2, 0x05<<2 }, /* Value b */
+        { 0x06<<2, 0x0F<<2, 0x17<<2 }, /* Value c */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value d */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value e */
+        { 0x3f<<2, 0x3f<<2, 0x3f<<2 }, /* Value f */ // Done
+        { 0x0F<<2, 0x2F<<2, 0x3F<<2 }, /* Value 10 */ //Done
+        { 0x00<<2, 0x1C<<2, 0x3B<<2 }, /* Value 11 */
+        { 0x08<<2, 0x0E<<2, 0x3B<<2 }, /* Value 12 */
+        { 0x20<<2, 0x00<<2, 0x3C<<2 }, /* Value 13 */
+        { 0x2F<<2, 0x00<<2, 0x2F<<2 }, /* Value 14 */
+        { 0x39<<2, 0x00<<2, 0x16<<2 }, /* Value 15 */ 
+        { 0x36<<2, 0x0A<<2, 0x00<<2 }, /* Value 16 */
+        { 0x08<<2, 0x0e<<2, 0x3b<<2 }, /* Value 17 */ // Done
+        { 0x22<<2, 0x1C<<2, 0x00<<2 }, /* Value 18 */
+        { 0x00<<2, 0x25<<2, 0x00<<2 }, /* Value 19 */
+        { 0x00<<2, 0x2A<<2, 0x00<<2 }, /* Value 1a */
+        { 0x00<<2, 0x24<<2, 0x0E<<2 }, /* Value 1b */
+        { 0x00<<2, 0x20<<2, 0x22<<2 }, /* Value 1c */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 1d */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 1e */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 1f */
+        { 0x3F<<2, 0x3F<<2, 0x3F<<2 }, /* Value 20 */
+        { 0x0F<<2, 0x2F<<2, 0x3F<<2 }, /* Value 21 */
+        { 0x17<<2, 0x25<<2, 0x3F<<2 }, /* Value 22 */
+        { 0x0f<<2, 0x2f<<2, 0x3f<<2 }, /* Value 23 */ // Done
+        { 0x00<<2, 0x3a<<2, 0x36<<2 }, /* Value 24 */ // Done
+        { 0x06<<2, 0x0f<<2, 0x17<<2 }, /* Value 25 */ // Done
+        { 0x3F<<2, 0x1D<<2, 0x18<<2 }, /* Value 26 */
+        { 0x3F<<2, 0x26<<2, 0x0E<<2 }, /* Value 27 */
+        { 0x3C<<2, 0x2F<<2, 0x0F<<2 }, /* Value 28 */
+        { 0x1f<<2, 0x02<<2, 0x00<<2 }, /* Value 29 */ // Done
+        { 0x13<<2, 0x37<<2, 0x12<<2 }, /* Value 2a */
+        { 0x29<<2, 0x00<<2, 0x00<<2 }, /* Value 2b */ // Done
+        { 0x00<<2, 0x3A<<2, 0x36<<2 }, /* Value 2c */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 2d */
+        { 0x3f<<2, 0x1d<<2, 0x18<<2 }, /* Value 2e */ // done
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 2f */ // done
+        { 0x3F<<2, 0x3F<<2, 0x3F<<2 }, /* Value 30 */
+        { 0x00<<2, 0x25<<2, 0x00<<2 }, /* Value 31 */ // Done
+        { 0x2f<<2, 0x2f<<2, 0x2F<<2 }, /* Value 32 */ // Done
+        { 0x35<<2, 0x32<<2, 0x3F<<2 }, /* Value 33 */
+        { 0x3F<<2, 0x31<<2, 0x3F<<2 }, /* Value 34 */
+        { 0x3F<<2, 0x31<<2, 0x36<<2 }, /* Value 35 */
+        { 0x3F<<2, 0x2F<<2, 0x2C<<2 }, /* Value 36 */
+        { 0x32<<2, 0x13<<2, 0x03<<2 }, /* Value 37 */ // Done
+        { 0x3F<<2, 0x39<<2, 0x28<<2 }, /* Value 38 */
+        { 0x38<<2, 0x3F<<2, 0x28<<2 }, /* Value 39 */
+        { 0x2A<<2, 0x3C<<2, 0x2F<<2 }, /* Value 3a */
+        { 0x2C<<2, 0x3F<<2, 0x33<<2 }, /* Value 3b */
+        { 0x27<<2, 0x3F<<2, 0x3C<<2 }, /* Value 3c */
+        { 0x3f<<2, 0x1d<<2, 0x2d<<2 }, /* Value 3d */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 3e */
+        { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 3f */
+
diff --git a/palettes/vsmar.h b/palettes/vsmar.h
new file mode 100644 (file)
index 0000000..5eb7143
--- /dev/null
@@ -0,0 +1,64 @@
+{ 0x1d<<2, 0x1d<<2, 0x1d<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x11<<2, 0x00<<2, 0x27<<2 },
+{ 0x00<<2, 0x2a<<2, 0x00<<2 },
+{ 0x3f<<2, 0x3f<<2, 0x3f<<2 },
+{ 0x2a<<2, 0x39<<2, 0x3f<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x39<<2, 0x00<<2, 0x16<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x17<<2, 0x25<<2, 0x3f<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x22<<2, 0x1c<<2, 0x00<<2 },
+{ 0x32<<2, 0x13<<2, 0x03<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x1d<<2, 0x1d<<2, 0x1d<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x3f<<2, 0x3f<<2, 0x3f<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x3f<<2, 0x26<<2, 0x0e<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x20<<2, 0x34<<2, 0x04<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x0f<<2, 0x2f<<2, 0x3f<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x1c<<2, 0x3b<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x3a<<2, 0x36<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x3a<<2, 0x36<<2 },
+{ 0x3c<<2, 0x2f<<2, 0x0f<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x14<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x31<<2, 0x35<<2, 0x3f<<2 },
+{ 0x3f<<2, 0x36<<2, 0x2a<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
diff --git a/palettes/vsplatoon.h b/palettes/vsplatoon.h
new file mode 100644 (file)
index 0000000..7d7dce4
--- /dev/null
@@ -0,0 +1,64 @@
+{63<<2,49<<2,54<<2},
+{9<<2,6<<2,35<<2},
+{54<<2,10<<2,0<<2},
+{17<<2,0<<2,39<<2},
+{0<<2,32<<2,34<<2},
+{0<<2,17<<2,0<<2},
+{41<<2,0<<2,0<<2},
+{63<<2,29<<2,45<<2},
+{63<<2,63<<2,63<<2},
+{0<<2,17<<2,0<<2},
+{63<<2,38<<2,14<<2},
+{42<<2,0<<2,4<<2},
+{6<<2,15<<2,23<<2},
+{32<<2,52<<2,4<<2},
+{0<<2,0<<2,0<<2},
+{63<<2,63<<2,63<<2},
+{15<<2,47<<2,63<<2},
+{0<<2,28<<2,59<<2},
+{8<<2,14<<2,59<<2},
+{63<<2,63<<2,63<<2},
+{47<<2,0<<2,47<<2},
+{57<<2,0<<2,22<<2},
+{63<<2,47<<2,44<<2},
+{8<<2,14<<2,59<<2},
+{34<<2,28<<2,0<<2},
+{0<<2,37<<2,0<<2},
+{0<<2,42<<2,0<<2},
+{0<<2,36<<2,14<<2},
+{0<<2,32<<2,34<<2},
+{0<<2,0<<2,0<<2},
+{0<<2,0<<2,0<<2},
+{0<<2,0<<2,0<<2},
+{63<<2,63<<2,63<<2},
+{15<<2,47<<2,63<<2},
+{23<<2,37<<2,63<<2},
+{19<<2,55<<2,18<<2},
+{0<<2,58<<2,54<<2},
+{6<<2,15<<2,23<<2},
+{63<<2,29<<2,24<<2},
+{63<<2,38<<2,14<<2},
+{60<<2,47<<2,15<<2},
+{31<<2,2<<2,0<<2},
+{19<<2,55<<2,18<<2},
+{41<<2,0<<2,0<<2},
+{0<<2,58<<2,54<<2},
+{0<<2,0<<2,0<<2},
+{63<<2,29<<2,24<<2},
+{0<<2,0<<2,0<<2},
+{63<<2,63<<2,63<<2},
+{0<<2,37<<2,0<<2},
+{47<<2,47<<2,47<<2},
+{0<<2,20<<2,0<<2},
+{63<<2,49<<2,63<<2},
+{63<<2,49<<2,54<<2},
+{63<<2,38<<2,14<<2},
+{54<<2,10<<2,0<<2},
+{63<<2,57<<2,40<<2},
+{15<<2,47<<2,63<<2},
+{42<<2,60<<2,47<<2},
+{44<<2,63<<2,51<<2},
+{39<<2,63<<2,60<<2},
+{63<<2,29<<2,45<<2},
+{34<<2,28<<2,0<<2},
+{0<<2,0<<2,0<<2}
diff --git a/palettes/vsslalom.h b/palettes/vsslalom.h
new file mode 100644 (file)
index 0000000..4328b1c
--- /dev/null
@@ -0,0 +1,64 @@
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x3f<<2, 0x26<<2, 0x0e<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x3f<<2, 0x1d<<2, 0x18<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x3f<<2, 0x1d<<2, 0x2d<<2 },
+{ 0x3f<<2, 0x3f<<2, 0x3f<<2 },
+{ 0x2f<<2, 0x00<<2, 0x2f<<2 },
+{ 0x27<<2, 0x3f<<2, 0x3c<<2 },
+{ 0x00<<2, 0x25<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x0f<<2, 0x2f<<2, 0x3f<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x16<<2, 0x3e<<2, 0x26<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x3d<<2, 0x1e<<2, 0x3f<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x2c<<2, 0x3f<<2, 0x33<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x09<<2, 0x06<<2, 0x23<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x35<<2, 0x32<<2, 0x3f<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x2f<<2, 0x2f<<2, 0x2f<<2 },
+{ 0x17<<2, 0x25<<2, 0x3f<<2 },
+{ 0x2f<<2, 0x00<<2, 0x2f<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x17<<2, 0x25<<2, 0x3f<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x3f<<2, 0x3f<<2, 0x3f<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x13<<2, 0x37<<2, 0x12<<2 },
+{ 0x3f<<2, 0x26<<2, 0x0e<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x27<<2, 0x3f<<2, 0x3c<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x3f<<2, 0x39<<2, 0x28<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
+{ 0x00<<2, 0x00<<2, 0x00<<2 },
diff --git a/palettes/vssmb.h b/palettes/vssmb.h
new file mode 100644 (file)
index 0000000..f942610
--- /dev/null
@@ -0,0 +1,65 @@
+{98,106,0},   // 0
+{0,0,255},    // 1
+{0,106,119},  // 2
+{71,43,191},  // 3
+{151,0,135},  // 4
+{171,0,35},   // 5
+{0x24,0x18,0x8c},   // 6 
+{0xc8,0x4c,0x0c},  // 7 
+{162,162,162},// 8
+{0,120,0},    // 9
+{0x4c,0xDC,0x48},    // a
+{0,91,0},     // b
+{255,213,153},// c
+{255,255,0},  // d
+{0,153,0},    // e
+{0,0,0},      // f 
+{255,102,255},// 10
+{0,120,248},  // 11
+{0x20,0x38,0xec},   // 12
+{107,71,255}, // 13
+{0,0,0},      // 14
+{231,0,91},   // 15
+{248,56,0},   // 16
+{251,0x74,0x60},  // 17
+{175,127,0},  // 18
+{0,184,0},    // 19
+{81,115,255}, // 1a
+{0,171,71},   // 1b
+{0,139,139},  // 1c
+{0,0,0},      // 1d
+{145,255,136},// 1e
+{0x3F,0xbF,0xFF},    // 1f
+{248,248,248},// 20
+{0,0x50,0}, // 21
+{107,0,0},    // 22
+{72,85,248},  // 23
+{248,120,248},// 24
+{248,88,152}, // 25
+{89,89,88},   // 26
+{249,0,0x58},  // 27
+{0,47,47},    // 28
+{184,248,24}, // 29
+
+{0x3f,0xbf,0xff},  // 2a
+{88,248,152}, // 2b
+{0,235,219},  // 2c
+{120,120,120},// 2d
+{0,0,0},      // 2e
+{0,0,0},      // 2f
+{255,255,255},// 30
+{167,231,255},// 31
+{89,4,0},     // 32
+{187,0,0},    // 33
+{248,184,248},// 34
+{251,167,195},// 35   
+{255,255,255},// 36
+{0,227,225},  // 37
+{251,219,123},// 38
+{255,174,15},  // 39
+{184,248,184},// 3a
+{184,248,216},// 3b
+{0x80,0xd0,0x10},    // 3c
+{248,216,248},// 3d
+{255,170,170},// 3e
+{0,64,0},     // 3f
diff --git a/sound.c b/sound.c
new file mode 100644 (file)
index 0000000..76f85a0
--- /dev/null
+++ b/sound.c
@@ -0,0 +1,1029 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+/********************************************************/
+/*******               sound.c                         */
+/*******                                               */
+/*******  Sound emulation code and waveform synthesis  */
+/*******  routines.  A few ideas were inspired         */
+/*******  by code from Marat Fayzullin's EMUlib                */
+/*******                                               */
+/********************************************************/             
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <string.h>
+
+#include "types.h"
+#include "x6502.h"
+
+#include "fce.h"
+#include "svga.h"
+#include "sound.h"
+
+uint32 soundtsinc;
+uint32 soundtsi;
+
+uint32 Wave[2048];
+int32 WaveFinal[2048];
+
+EXPSOUND GameExpSound={0,0,0};
+
+uint8 trimode=0;
+uint8 tricoop=0;
+uint8 PSG[0x18];
+
+uint8 decvolume[3];
+uint8 realvolume[3];
+
+static int32 count[5];
+static int64 sqacc[2]={0,0};
+uint8 sqnon=0;
+
+#undef printf
+uint16 nreg;
+int32 lengthcount[4]; 
+
+static const uint8 Slengthtable[0x20]=
+{
+ 0x5,0x7f,0xA,0x1,0x14,0x2,0x28,0x3,0x50,0x4,0x1E,0x5,0x7,0x6,0x0E,0x7,
+ 0x6,0x08,0xC,0x9,0x18,0xa,0x30,0xb,0x60,0xc,0x24,0xd,0x8,0xe,0x10,0xf
+};
+
+static uint32 lengthtable[0x20];
+
+static const uint32 SNoiseFreqTable[0x10]=
+{
+ 2,4,8,0x10,0x20,0x30,0x40,0x50,0x65,0x7f,0xbe,0xfe,0x17d,0x1fc,0x3f9,0x7f2
+};
+static uint32 NoiseFreqTable[0x10];
+
+int64 nesincsizeLL;
+
+static const uint8 NTSCPCMTable[0x10]=
+{
+ 0xd6,0xbe,0xaa,0xa0,0x8f,0x7f,0x71,0x6b,
+ 0x5f,0x50,0x47,0x40,0x35,0x2a,0x24,0x1b
+};
+
+static const uint8 PALPCMTable[0x10]=  // These values are just guessed.
+{
+ 0xc6,0xb0,0x9d,0x94,0x84,0x75,0x68,0x63,
+ 0x58,0x4a,0x41,0x3b,0x31,0x27,0x21,0x19
+};
+
+uint32 PSG_base;
+
+// $4010        -        Frequency
+// $4011        -        Actual data outputted
+// $4012        -        Address register: $c000 + V*64
+// $4013        -        Size register:  Size in bytes = (V+1)*64
+
+
+static int64 PCMacc=0;
+static int PCMfreq;
+int32 PCMIRQCount;
+uint8 PCMBitIndex=0;
+uint32 PCMAddressIndex=0;
+int32 PCMSizeIndex=0;
+uint8 PCMBuffer=0; 
+int vdis=0;
+
+static void Dummyfunc(void) {};
+
+static void (*DoNoise)(void)=Dummyfunc;
+static void (*DoTriangle)(void)=Dummyfunc;
+static void (*DoPCM)(void)=Dummyfunc;
+static void (*DoSQ1)(void)=Dummyfunc;
+static void (*DoSQ2)(void)=Dummyfunc;
+
+static void CalcDPCMIRQ(void)
+{
+ uint32 freq;
+ uint32 honk;
+ uint32 cycles;
+
+ if(PAL)
+  freq=(PALPCMTable[PSG[0x10]&0xF]<<4);
+ else
+  freq=(NTSCPCMTable[PSG[0x10]&0xF]<<4);
+
+ cycles=(((PSG[0x13]<<4)+1));
+ cycles*=freq/14; 
+ honk=((PSG[0x13]<<4)+1)*freq;
+ honk-=cycles; 
+ //if(PAL) honk/=107;
+ //else honk/=(double)113.66666666;
+ PCMIRQCount=honk*48;
+ //PCMIRQCount=honk*3; //180;
+ //if(PAL) PCMIRQCount*=.93;
+ vdis=0;
+}
+
+static void PrepDPCM()
+{
+ PCMAddressIndex=0x4000+(PSG[0x12]<<6); 
+ PCMSizeIndex=(PSG[0x13]<<4)+1;
+ PCMBitIndex=0;  
+ //PCMBuffer=ARead[0x8000+PCMAddressIndex](0x8000+PCMAddressIndex);
+ if(PAL)
+  PCMfreq=PALPCMTable[PSG[0x10]&0xF];
+ else
+  PCMfreq=NTSCPCMTable[PSG[0x10]&0xF];
+ PCMacc=(int64)PCMfreq<<50;
+}
+
+uint8 sweepon[2]={0,0};
+int32 curfreq[2]={0,0};
+
+
+uint8 SIRQStat=0;
+
+uint8 SweepCount[2];
+uint8 DecCountTo1[3];
+
+uint8 fcnt=0;
+int32 fhcnt=0;
+int32 fhinc;
+
+static uint8 laster;
+
+/* Instantaneous?  Maybe the new freq value is being calculated all of the time... */
+static int FASTAPASS(2) CheckFreq(uint32 cf, uint8 sr)
+{
+ uint32 mod;
+ if(!(sr&0x8))
+ {
+  mod=cf>>(sr&7);
+  if((mod+cf)&0x800)
+   return(0);
+ }
+ return(1);
+}
+
+static DECLFW(Write0x11)
+{
+ DoPCM();
+ PSG[0x11]=V&0x7F;
+}
+
+static uint8 DutyCount[2]={0,0};
+
+static DECLFW(Write_PSG)
+{
+ //if((A>=0x4004 && A<=0x4007) || A==0x4015)
+  //printf("$%04x:$%02x, %d\n",A,V,timestamp);
+ A&=0x1f;
+ switch(A)
+ {
+  case 0x0:
+           DoSQ1();
+           if(V&0x10)
+            realvolume[0]=V&0xF;
+           break;
+  case 0x1:
+           sweepon[0]=V&0x80;
+           break;
+  case 0x2:
+           DoSQ1();
+           curfreq[0]&=0xFF00;
+           curfreq[0]|=V;
+           break;
+  case 0x3:          
+           if(PSG[0x15]&1)
+           {
+            DoSQ1();
+            lengthcount[0]=lengthtable[(V>>3)&0x1f];
+            sqnon|=1;                
+          }
+           sweepon[0]=PSG[1]&0x80;
+           curfreq[0]=PSG[0x2]|((V&7)<<8);
+          decvolume[0]=0xF;
+          DecCountTo1[0]=(PSG[0]&0xF)+1;
+           SweepCount[0]=((PSG[0x1]>>4)&7)+1;
+          DutyCount[0]=0;
+           sqacc[0]=((int64)curfreq[0]+1)<<50;
+           break;
+
+  case 0x4:           
+          DoSQ2();
+           if(V&0x10)
+            realvolume[1]=V&0xF;
+          break;
+  case 0x5:
+          sweepon[1]=V&0x80;
+          break;
+  case 0x6:
+          DoSQ2();
+          curfreq[1]&=0xFF00;
+          curfreq[1]|=V;
+          break;
+  case 0x7:          
+          if(PSG[0x15]&2)
+          {
+          DoSQ2();
+          lengthcount[1]=lengthtable[(V>>3)&0x1f];
+           sqnon|=2;
+         }
+          sweepon[1]=PSG[0x5]&0x80;
+          curfreq[1]=PSG[0x6]|((V&7)<<8);          
+          decvolume[1]=0xF;
+         DecCountTo1[1]=(PSG[0x4]&0xF)+1;
+          SweepCount[1]=((PSG[0x5]>>4)&7)+1;
+          DutyCount[1]=0;
+          sqacc[1]=((int64)curfreq[1]+1)<<50;
+          break;
+  case 0x8:                                 
+          DoTriangle();
+         if(laster&0x80)
+         {
+            tricoop=V&0x7F;
+            trimode=V&0x80;
+          }
+          if(!(V&0x7F))
+           tricoop=0;
+          laster=V&0x80;
+          break;
+  case 0xa:DoTriangle();
+          break;
+  case 0xb:
+         if(PSG[0x15]&0x4)
+         {
+          DoTriangle();
+           sqnon|=4;
+           lengthcount[2]=lengthtable[(V>>3)&0x1f];
+         }
+          laster=0x80;
+          tricoop=PSG[0x8]&0x7f;
+          trimode=PSG[0x8]&0x80;
+          break;
+  case 0xC:DoNoise();
+           if(V&0x10)
+            realvolume[2]=V&0xF;
+           break;
+  case 0xE:DoNoise();break;
+  case 0xF:
+           if(PSG[0x15]&8)
+           {
+           DoNoise();
+            sqnon|=8;
+           lengthcount[3]=lengthtable[(V>>3)&0x1f];
+          }
+           decvolume[2]=0xF;
+          DecCountTo1[2]=(PSG[0xC]&0xF)+1;          
+           break;
+ case 0x10:DoPCM();
+          if(!(V&0x80))
+           X6502_IRQEnd(FCEU_IQDPCM);
+          break;
+ case 0x15: 
+          {
+           int t=V^PSG[0x15];
+
+            if(t&1)
+             DoSQ1();
+            if(t&2)
+             DoSQ2();
+            if(t&4)
+             DoTriangle();
+            if(t&8)
+             DoNoise();
+            if(t&0x10)
+             DoPCM();
+            sqnon&=V;
+            if(V&0x10)
+            {
+             if(!(PSG[0x15]&0x10))
+             {
+              PrepDPCM();
+              CalcDPCMIRQ();
+             }
+             else if(vdis)
+              CalcDPCMIRQ();
+            }
+            else
+             PCMIRQCount=0;
+            X6502_IRQEnd(FCEU_IQDPCM);
+          }
+           break;
+ case 0x17: 
+          V&=0xC0;
+           fcnt=0;      
+           if(V&0x80)
+            FrameSoundUpdate();
+           fhcnt=fhinc;
+           X6502_IRQEnd(FCEU_IQFCOUNT);
+          SIRQStat&=~0x40;        
+           break;
+ }
+ PSG[A]=V;
+}
+
+DECLFR(Read_PSG)
+{
+   uint8 ret;
+   if(PSG[0x15]&0x10)
+    DoPCM();
+   ret=(PSG[0x15]&(sqnon|0x10))|SIRQStat;
+   SIRQStat&=~0x40;
+   X6502_IRQEnd(/*FCEU_IQDPCM|*/FCEU_IQFCOUNT);
+   return ret;
+}
+
+DECLFR(Read_PSGDummy)
+{
+   uint8 ret;
+
+   ret=(PSG[0x15]&sqnon)|SIRQStat;
+   SIRQStat&=~0x40;
+   X6502_IRQEnd(/*FCEU_IQDPCM|*/FCEU_IQFCOUNT);
+   return ret;
+}
+
+static void FASTAPASS(1) FrameSoundStuff(int V)
+{
+ int P;
+
+ DoSQ1();
+ DoSQ2();
+ DoNoise();
+
+ switch((V&1))
+ {
+  case 1:       /* Envelope decay, linear counter, length counter, freq sweep */
+        if(PSG[0x15]&4 && sqnon&4)
+         if(!(PSG[8]&0x80))
+         {
+          if(lengthcount[2]>0)
+          {
+            lengthcount[2]--;
+            if(lengthcount[2]<=0)
+             {
+              DoTriangle();
+              sqnon&=~4;
+             }
+           }        
+         }
+
+        for(P=0;P<2;P++)
+        {
+         if(PSG[0x15]&(P+1) && sqnon&(P+1))
+        {
+          if(!(PSG[P<<2]&0x20))
+          {
+           if(lengthcount[P]>0)
+           {
+            lengthcount[P]--;            
+            if(lengthcount[P]<=0)
+             {
+              sqnon&=~(P+1);
+             }
+           }
+          }
+        }
+               /* Frequency Sweep Code Here */
+               /* xxxx 0000 */
+               /* xxxx = hz.  120/(x+1)*/
+         if(sweepon[P])
+          {
+           int32 mod=0;
+
+          if(SweepCount[P]>0) SweepCount[P]--; 
+          if(SweepCount[P]<=0)
+          {
+           SweepCount[P]=((PSG[(P<<2)+0x1]>>4)&7)+1; //+1;
+            {
+             if(PSG[(P<<2)+0x1]&0x8)
+             {
+              mod-=(P^1)+((curfreq[P])>>(PSG[(P<<2)+0x1]&7));          
+
+              if(curfreq[P] && (PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/)
+              {
+               curfreq[P]+=mod;
+              }
+             }
+             else
+             {
+              mod=curfreq[P]>>(PSG[(P<<2)+0x1]&7);
+              if((mod+curfreq[P])&0x800)
+              {
+               sweepon[P]=0;
+               curfreq[P]=0;
+              }
+              else
+              {
+               if(curfreq[P] && (PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/)
+               {
+                curfreq[P]+=mod;
+               }
+              }
+             }
+            }
+          }
+          } 
+         }
+
+       if(PSG[0x15]&0x8 && sqnon&8)
+        {
+         if(!(PSG[0xC]&0x20))
+         {
+          if(lengthcount[3]>0)
+          {
+           lengthcount[3]--;
+           if(lengthcount[3]<=0)
+           {
+            sqnon&=~8;
+           }
+          }
+         }
+        }
+
+  case 0:       /* Envelope decay + linear counter */
+         if(!trimode)
+         {           
+           laster=0;
+           if(tricoop)
+           {
+            if(tricoop==1) DoTriangle();
+            tricoop--;
+           }
+         }
+
+        for(P=0;P<2;P++)
+        {
+         if(DecCountTo1[P]>0) DecCountTo1[P]--;
+          if(DecCountTo1[P]<=0)
+          {
+          DecCountTo1[P]=(PSG[P<<2]&0xF)+1;
+           if(decvolume[P] || PSG[P<<2]&0x20)
+           {
+            decvolume[P]--;
+           /* Step from 0 to full volume seems to take twice as long
+              as the other steps.  I don't know if this is the correct
+              way to double its length, though(or if it even matters).
+           */
+            if((PSG[P<<2]&0x20) && (decvolume[P]==0))
+             DecCountTo1[P]<<=1;
+           decvolume[P]&=15;
+           }
+          }
+          if(!(PSG[P<<2]&0x10))
+           realvolume[P]=decvolume[P];
+        }
+
+         if(DecCountTo1[2]>0) DecCountTo1[2]--;
+         if(DecCountTo1[2]<=0)
+         {
+          DecCountTo1[2]=(PSG[0xC]&0xF)+1;
+          if(decvolume[2] || PSG[0xC]&0x20)
+          {
+            decvolume[2]--;
+            /* Step from 0 to full volume seems to take twice as long
+               as the other steps.  I don't know if this is the correct
+               way to double its length, though(or if it even matters).
+            */
+            if((PSG[0xC]&0x20) && (decvolume[2]==0))
+             DecCountTo1[2]<<=1;
+            decvolume[2]&=15;
+          }
+         }
+         if(!(PSG[0xC]&0x10))
+          realvolume[2]=decvolume[2];
+
+        break;
+ }
+
+}
+
+void FrameSoundUpdate(void)
+{
+ // Linear counter:  Bit 0-6 of $4008
+ // Length counter:  Bit 4-7 of $4003, $4007, $400b, $400f
+
+ if(fcnt==3)
+ {
+       if(PSG[0x17]&0x80)
+        fhcnt+=fhinc;
+        if(!(PSG[0x17]&0xC0))
+        {
+         SIRQStat|=0x40;
+        X6502_IRQBegin(FCEU_IQFCOUNT);
+        }
+ }
+ //if(SIRQStat&0x40) X6502_IRQBegin(FCEU_IQFCOUNT);
+ FrameSoundStuff(fcnt);
+ fcnt=(fcnt+1)&3;
+}
+
+static uint32 ChannelBC[5];
+
+static uint32 RectAmp[2][8];
+
+static void FASTAPASS(1) CalcRectAmp(int P)
+{
+  static int tal[4]={1,2,4,6};
+  int V;
+  int x;
+  uint32 *b=RectAmp[P];
+  int m;
+
+  //if(PSG[P<<2]&0x10)
+   V=realvolume[P]<<4;
+  //V=(PSG[P<<2]&15)<<4;
+  //else
+  // V=decvolume[P]<<4;
+  m=tal[(PSG[P<<2]&0xC0)>>6];
+  for(x=0;x<m;x++,b++)
+   *b=0;
+  for(;x<8;x++,b++)
+   *b=V;
+}
+
+static void RDoPCM(void)
+{
+   int32 V;
+   int32 start,end;
+   int64 freq;
+   uint32 out=PSG[0x11]<<3;
+
+   start=ChannelBC[4];
+   end=(timestamp<<16)/soundtsinc;   
+   if(end<=start) return;
+   ChannelBC[4]=end;
+
+   if(PSG[0x15]&0x10)
+   {
+      freq=PCMfreq;
+      freq<<=50;
+
+      for(V=start;V<end;V++)
+      {
+       PCMacc-=nesincsizeLL;
+       if(PCMacc<=0)
+       {
+       if(!PCMBitIndex)
+       {
+         PCMSizeIndex--;
+         if(!PCMSizeIndex)
+         {
+          if(PSG[0x10]&0x40)
+           PrepDPCM();
+          else
+          {
+           PSG[0x15]&=~0x10;
+           for(;V<end;V++)
+            Wave[V>>4]+=PSG[0x11]<<3;
+           goto endopcmo;
+          }
+         }
+         else
+         {
+          PCMBuffer=ARead[0x8000+PCMAddressIndex](0x8000+PCMAddressIndex);
+          PCMAddressIndex=(PCMAddressIndex+1)&0x7fff;
+        }
+       }
+
+       {
+         int t=(((PCMBuffer>>PCMBitIndex)&1)<<2)-2;
+         uint8 bah=PSG[0x11];
+
+        PCMacc+=freq;
+         PSG[0x11]+=t;
+         if(PSG[0x11]&0x80)
+          PSG[0x11]=bah;
+        else
+         out=PSG[0x11]<<3;
+       }
+       PCMBitIndex=(PCMBitIndex+1)&7;
+       }
+       Wave[V>>4]+=out; //(PSG[0x11]-64)<<3;
+      }
+   }
+   else
+   {
+     if((end-start)>64)
+     {
+      for(V=start;V<=(start|15);V++)
+       Wave[V>>4]+=out;
+      out<<=4;
+      for(V=(start>>4)+1;V<(end>>4);V++)
+       Wave[V]+=out;
+      out>>=4;
+      for(V=end&(~15);V<end;V++)
+       Wave[V>>4]+=out;
+     }
+     else
+      for(V=start;V<end;V++)
+       Wave[V>>4]+=out;
+   }
+    endopcmo:;
+}
+
+static void RDoSQ1(void)
+{
+   int32 V;
+   int32 start,end;
+   int64 freq;
+
+   CalcRectAmp(0);
+   start=ChannelBC[0];
+   end=(timestamp<<16)/soundtsinc;
+   if(end<=start) return;
+   ChannelBC[0]=end;
+
+   if(curfreq[0]<8 || curfreq[0]>0x7ff)
+    return;
+   if(!CheckFreq(curfreq[0],PSG[0x1]))
+    return;
+
+   if(PSG[0x15]&1 && sqnon&1)
+   {
+    uint32 out=RectAmp[0][DutyCount[0]];
+    freq=curfreq[0]+1;
+    {
+      freq<<=50;
+      for(V=start;V<end;V++)
+      {
+       Wave[V>>4]+=out;
+       sqacc[0]-=nesincsizeLL;
+       if(sqacc[0]<=0)
+       {
+        rea:
+        sqacc[0]+=freq;
+        DutyCount[0]++;
+        if(sqacc[0]<=0) goto rea;
+
+        DutyCount[0]&=7;
+        out=RectAmp[0][DutyCount[0]];
+       }
+
+      }
+     }
+    }
+}
+
+static void RDoSQ2(void)
+{
+   int32 V;
+   int32 start,end;
+   int64 freq;
+
+   CalcRectAmp(1);
+   start=ChannelBC[1];
+   end=(timestamp<<16)/soundtsinc;
+   if(end<=start) return;
+   ChannelBC[1]=end;
+
+   if(curfreq[1]<8 || curfreq[1]>0x7ff)
+    return;
+   if(!CheckFreq(curfreq[1],PSG[0x5]))
+    return;
+
+   if(PSG[0x15]&2 && sqnon&2)
+   {
+    uint32 out=RectAmp[1][DutyCount[1]];
+    freq=curfreq[1]+1;
+
+    {
+      freq<<=50;
+      for(V=start;V<end;V++)
+      {
+       Wave[V>>4]+=out;
+       sqacc[1]-=nesincsizeLL;
+       if(sqacc[1]<=0)
+       {
+        rea:
+        sqacc[1]+=freq;
+        DutyCount[1]++;
+       if(sqacc[1]<=0) goto rea;
+
+        DutyCount[1]&=7;
+       out=RectAmp[1][DutyCount[1]];
+       }
+
+      }
+     }
+    }
+}
+
+
+static void RDoTriangle(void)
+{
+   static uint32 tcout=0;
+   int32 V;
+   int32 start,end; //,freq;
+   int64 freq=(((PSG[0xa]|((PSG[0xb]&7)<<8))+1));
+
+   start=ChannelBC[2];
+   end=(timestamp<<16)/soundtsinc;   
+   if(end<=start) return;
+   ChannelBC[2]=end;
+
+    if(! (PSG[0x15]&0x4 && sqnon&4 && tricoop) )
+    {  // Counter is halted, but we still need to output.
+     for(V=start;V<end;V++)
+       Wave[V>>4]+=tcout;
+    }
+    else if(freq<=4) // 55.9Khz - Might be barely audible on a real NES, but
+              // it's too costly to generate audio at this high of a frequency
+              // (55.9Khz * 32 for the stepping).
+              // The same could probably be said for ~27.8Khz, so we'll
+              // take care of that too.  We'll just output the average
+              // value(15/2 - scaled properly for our output format, of course).
+              // We'll also take care of ~18Khz and ~14Khz too, since they should be barely audible.
+              // (Some proof or anything to confirm/disprove this would be nice.).
+    {
+     for(V=start;V<end;V++)
+      Wave[V>>4]+=((0xF<<4)+(0xF<<2))>>1;
+    }
+    else
+    {
+     static int64 triacc=0; 
+     static uint8 tc=0; 
+
+      freq<<=49;
+      for(V=start;V<end;V++)
+      {
+       triacc-=nesincsizeLL;
+       if(triacc<=0)
+       {
+        rea:
+        triacc+=freq; //t;
+        tc=(tc+1)&0x1F;
+        if(triacc<=0) goto rea;
+
+        tcout=(tc&0xF);
+        if(tc&0x10) tcout^=0xF;
+        tcout=(tcout<<4)+(tcout<<2);
+       }
+       Wave[V>>4]+=tcout;
+      }
+    }
+}
+
+static void RDoNoise(void)
+{
+   int32 inc,V;
+   int32 start,end;
+
+   start=ChannelBC[3];
+   end=(timestamp<<16)/soundtsinc;   
+   if(end<=start) return;
+   ChannelBC[3]=end;
+
+   if(PSG[0x15]&0x8 && sqnon&8)
+   {
+      uint32 outo;
+      uint32 amptab[2];
+      uint8 amplitude;
+       
+      amplitude=realvolume[2];
+      //if(PSG[0xC]&0x10)
+      // amplitude=(PSG[0xC]&0xF);
+      //else                  
+      // amplitude=decvolume[2]&0xF;
+
+      inc=NoiseFreqTable[PSG[0xE]&0xF]; 
+      amptab[0]=((amplitude<<2)+amplitude+amplitude)<<1;
+      amptab[1]=0;
+      outo=amptab[nreg&1];
+
+      if(amplitude) 
+      {
+       if(PSG[0xE]&0x80)       // "short" noise        
+        for(V=start;V<end;V++)
+        {     
+         Wave[V>>4]+=outo;
+         if(count[3]>=inc)
+         {                          
+          uint8 feedback;      
+
+          feedback=((nreg>>8)&1)^((nreg>>14)&1);
+          nreg=(nreg<<1)+feedback;
+          nreg&=0x7fff;
+          outo=amptab[nreg&1];
+          count[3]-=inc;
+         }
+         count[3]+=0x1000;
+        }
+       else
+        for(V=start;V<end;V++)
+        {
+         Wave[V>>4]+=outo;
+         if(count[3]>=inc)
+         {
+          uint8 feedback;
+
+          feedback=((nreg>>13)&1)^((nreg>>14)&1);
+          nreg=(nreg<<1)+feedback;
+          nreg&=0x7fff;
+          outo=amptab[nreg&1];
+          count[3]-=inc;
+         }
+         count[3]+=0x1000;
+        }
+      }
+
+   }
+}
+
+void SetNESSoundMap(void)
+{ 
+  SetWriteHandler(0x4000,0x4013,Write_PSG);
+  SetWriteHandler(0x4011,0x4011,Write0x11);
+  SetWriteHandler(0x4015,0x4015,Write_PSG);
+  SetWriteHandler(0x4017,0x4017,Write_PSG);        
+  SetReadHandler(0x4015,0x4015,Read_PSG);
+}
+
+static int32 WaveNSF[256];
+
+int64 highp;                   // 0 through 65536, 0 = no high pass, 65536 = max high pass
+
+int64 lowp;                    // 0 through 65536, 65536 = max low pass(total attenuation)
+                               // 65536 = no low pass
+static void FilterSound(uint32 *in, int32 *out, int count)
+{
+ static int64 acc=0, acc2=0;
+
+ for(;count;count--,in++,out++)
+ {
+  int64 diff;
+
+  diff=((int64)*in<<24)-acc;
+
+  acc+=(diff*highp)>>16;
+  acc2+=((diff-acc2)*lowp)>>16;
+  *in=0;
+  *out=(acc2*(int64)FSettings.SoundVolume)>>(24+16);
+  if(*out<-32767) *out=-32767;
+  if(*out>32767) *out=32767;
+  //*out=((int64)(acc2>>24)*(int64)FSettings.SoundVolume)>>16; //acc2>>24;
+ }
+}
+
+int FlushEmulateSound(void)
+{
+  uint32 end;
+  int x;
+
+  if(!timestamp) return(0);
+
+  if(!FSettings.SndRate)
+  {
+   end=0;
+   goto nosoundo;
+  }
+
+  end=(timestamp<<16)/soundtsinc;
+  DoSQ1();
+  DoSQ2();
+  DoTriangle();
+  DoNoise();
+  DoPCM();
+
+  if(GameExpSound.Fill)
+   GameExpSound.Fill(end&0xF);
+
+  FilterSound(Wave,WaveFinal,end>>4);
+
+  if(FCEUGameInfo.type==GIT_NSF)
+  {
+   int x,s=0,si=end/1024;       // Only want 1/4 of the output buffer to be displayed
+   for(x=0;x<256;x++)
+   {
+    WaveNSF[x]=WaveFinal[s>>4];
+    s+=si;
+   }
+  }
+
+  if(end&0xF)
+   Wave[0]=Wave[(end>>4)];
+  Wave[(end>>4)]=0;  
+
+  nosoundo:
+  for(x=0;x<5;x++)
+   ChannelBC[x]=end&0xF;
+  timestampbase+=timestamp;
+  timestamp=(soundtsinc*(end&0xF))>>16;  
+  timestampbase-=timestamp;
+  return(end>>4);
+}
+
+void GetSoundBuffer(int32 **W)
+{
+ *W=WaveNSF;
+}
+
+void PowerSound(void)
+{
+       int x;
+
+        SetNESSoundMap();
+
+        for(x=0;x<0x16;x++)
+         if(x!=0x14)
+          BWrite[0x4000+x](0x4000+x,0);
+        PSG[0x17]=0; //x40;
+        fhcnt=fhinc;
+        fcnt=0;
+        nreg=1;
+}
+
+void ResetSound(void)
+{
+        int x;
+        for(x=0;x<0x16;x++)
+         if(x!=1 && x!=5 && x!=0x14) BWrite[0x4000+x](0x4000+x,0);
+        PSG[0x17]=0;
+        fhcnt=fhinc;
+        fcnt=0;
+        nreg=1;
+}
+
+void SetSoundVariables(void)
+{
+  int x;  
+
+  fhinc=PAL?16626:14915;       // *2 CPU clock rate
+  fhinc*=24;
+  for(x=0;x<0x20;x++)
+   lengthtable[x]=Slengthtable[x]<<1;
+
+  if(FSettings.SndRate)
+  {
+   DoNoise=RDoNoise;
+   DoTriangle=RDoTriangle;
+   DoPCM=RDoPCM;
+   DoSQ1=RDoSQ1;
+   DoSQ2=RDoSQ2;
+  }  
+  else
+  {
+   DoNoise=DoTriangle=DoPCM=DoSQ1=DoSQ2=Dummyfunc;
+  }
+
+  if(!FSettings.SndRate) return;
+  if(GameExpSound.RChange)
+   GameExpSound.RChange();
+
+  nesincsizeLL=(int64)((int64)562949953421312*(long double)(PAL?PAL_CPU:NTSC_CPU)/(FSettings.SndRate OVERSAMPLE));
+  PSG_base=(uint32)(PAL?(long double)PAL_CPU/16:(long double)NTSC_CPU/16);
+
+  for(x=0;x<0x10;x++)
+  {
+   long double z;
+   z=SNoiseFreqTable[x]<<1;
+   z=(PAL?PAL_CPU:NTSC_CPU)/z;
+   z=(long double)((uint32)((FSettings.SndRate OVERSAMPLE)<<12))/z;
+   NoiseFreqTable[x]=z;
+  }
+  soundtsinc=(uint32)((uint64)(PAL?(long double)PAL_CPU*65536:(long double)NTSC_CPU*65536)/(FSettings.SndRate OVERSAMPLE));
+  memset(Wave,0,2048*4);
+  for(x=0;x<5;x++)
+   ChannelBC[x]=0;
+  highp=(250<<16)/FSettings.SndRate;  // Arbitrary
+  lowp=((int64)25000<<16)/FSettings.SndRate; // Arbitrary
+
+  if(highp>(1<<16)) highp=1<<16;
+  if(lowp>(1<<16)) lowp=1<<16;
+}
+
+void FixOldSaveStateSFreq(void)
+{
+        int x;
+        for(x=0;x<2;x++)
+        {
+         curfreq[x]=PSG[0x2+(x<<2)]|((PSG[0x3+(x<<2)]&7)<<8);
+        }
+}
+
+void FCEUI_Sound(int Rate)
+{
+ FSettings.SndRate=Rate;
+ SetSoundVariables();
+}
+
+void FCEUI_SetSoundVolume(uint32 volume)
+{
+ FSettings.SoundVolume=(volume<<16)/100;
+}
diff --git a/sound.h b/sound.h
new file mode 100644 (file)
index 0000000..53c397b
--- /dev/null
+++ b/sound.h
@@ -0,0 +1,73 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#define OVERSAMPLESHIFT 4
+#define OVERSAMPLE *16
+#define SND_BUFSIZE 256
+
+
+typedef struct {
+          void (*Fill)(int Count);
+          void (*RChange)(void);
+          void (*Kill)(void);
+} EXPSOUND;
+
+extern EXPSOUND GameExpSound;
+
+extern int64 nesincsizeLL;
+extern uint8 PSG[];
+extern uint32 PSG_base;
+extern int32 PCMIRQCount;
+
+void SetSoundVariables(void);
+void PowerSound(void);
+void ResetSound(void);
+extern uint8 decvolume[];
+
+extern int vdis;
+extern uint8 sqnon;
+extern uint16 nreg;
+
+extern uint8 trimode;
+extern uint8 tricoop;
+extern uint8 PCMBitIndex;
+extern uint32 PCMAddressIndex;
+extern int32 PCMSizeIndex;
+extern uint8 PCMBuffer;
+
+extern uint8 sweepon[2];
+extern int32 curfreq[2];
+
+extern uint8 SweepCount[2];
+extern uint8 DecCountTo1[3];
+
+extern uint8 fcnt;
+extern int32 fhcnt;
+extern int32 fhinc;
+
+void GetSoundBuffer(int32 **W);
+int FlushEmulateSound(void);
+extern uint32 Wave[2048];
+extern int32 WaveFinal[2048];
+extern uint32 soundtsinc;
+
+void SetNESSoundMap(void);
+void FrameSoundUpdate(void);
+void FixOldSaveStateSFreq(void);
diff --git a/state.c b/state.c
new file mode 100644 (file)
index 0000000..ac48818
--- /dev/null
+++ b/state.c
@@ -0,0 +1,607 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+/*  TODO: Add (better) file io error checking */
+/*  TODO: Change save state file format. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "types.h"
+#include "x6502.h"
+#include "version.h"
+#include "fce.h"
+#include "sound.h"
+#define INESPRIV                // Take this out when old save state support is removed in a future version.
+#include "ines.h"
+#include "svga.h"
+#include "endian.h"
+#include "fds.h"
+#include "general.h"
+#include "state.h"
+#include "memory.h"
+
+static SFORMAT SFMDATA[64];
+static int SFEXINDEX;
+static int stateversion;
+
+#define RLSB           0x80000000
+
+#define SFCPUELEMENTS 7
+
+SFORMAT SFCPU[SFCPUELEMENTS]={
+ { &X.PC, 2|RLSB, "PC\0"},
+ { &X.A, 1, "A\0\0"},
+ { &X.P, 1, "P\0\0"},
+ { &X.X, 1, "X\0\0"},
+ { &X.Y, 1, "Y\0\0"},
+ { &X.S, 1, "S\0\0"},
+ { RAM, 0x800, "RAM"}
+};
+
+#define SFCPUCELEMENTS 6
+SFORMAT SFCPUC[SFCPUCELEMENTS]={
+ { &X.jammed, 1, "JAMM"},
+ { &X.IRQlow, 1, "IRQL"},
+ { &X.tcount, 4|RLSB, "ICoa"},
+ { &X.count,  4|RLSB, "ICou"},
+ { &timestamp, 4|RLSB, "TIME"},
+ { &timestampbase, 8|RLSB, "TMEB"}
+};
+
+static uint16 TempAddrT,RefreshAddrT;
+
+#define SFPPUELEMENTS 10
+SFORMAT SFPPU[SFPPUELEMENTS]={
+ { NTARAM, 0x800, "NTAR"},
+ { PALRAM, 0x20, "PRAM"},
+ { SPRAM, 0x100, "SPRA"},
+ { PPU, 0x4, "PPUR"},
+ { &XOffset, 1, "XOFF"},
+ { &vtoggle, 1, "VTOG"},
+ { &RefreshAddrT, 2|RLSB, "RADD"},
+ { &TempAddrT, 2|RLSB, "TADD"},
+ { &VRAMBuffer, 1, "VBUF"},
+ { &PPUGenLatch, 1, "PGEN"},
+};
+
+// Is this chunk necessary?  I'll fix it later.
+//#define SFCTLRELEMENTS 2
+//SFORMAT SFCTLR[SFCTLRELEMENTS]={
+// { &joy_readbit, 1, "J1RB"},
+// { &joy2_readbit, 1, "J2RB"}
+//};
+
+#define SFSNDELEMENTS 18
+SFORMAT SFSND[SFSNDELEMENTS]={
+ { &fhcnt, 4|RLSB,"FHCN"},
+ { &fcnt, 1, "FCNT"},
+ { PSG, 14, "PSG"},
+ { &PSG[0x15], 1, "P15"},
+ { &PSG[0x17], 1, "P17"},
+ { decvolume, 3, "DECV"},
+ { &sqnon, 1, "SQNO"},
+ { &nreg, 2|RLSB, "NREG"},
+ { &trimode, 1, "TRIM"},
+ { &tricoop, 1, "TRIC"},
+ { sweepon, 2, "SWEE"},
+ { &curfreq[0], 4|RLSB,"CRF1"},
+ { &curfreq[1], 4|RLSB,"CRF2"},
+ { SweepCount, 2,"SWCT"},
+ { DecCountTo1, 3,"DCT1"},
+ { &PCMBitIndex, 1,"PBIN"},
+ { &PCMAddressIndex, 4|RLSB, "PAIN"},
+ { &PCMSizeIndex, 4|RLSB, "PSIN"}
+};
+
+
+int WriteStateChunk(FILE *st, int type, SFORMAT *sf, int count)
+{
+ int bsize;
+ int x;
+
+ fputc(type,st);
+ for(x=bsize=0;x<count;x++)
+  bsize+=sf[x].s&(~RLSB);
+ bsize+=count<<3;
+ write32(bsize,st);
+ for(x=0;x<count;x++)
+ {
+  fwrite(sf[x].desc,1,4,st);
+  write32(sf[x].s&(~RLSB),st);
+  #ifdef LSB_FIRST
+  fwrite((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
+  #else
+  {
+  int z;
+  if(sf[x].s&RLSB)
+  {
+   for(z=(sf[x].s&(~RLSB))-1;z>=0;z--)
+   {
+    fputc(*(uint8*)sf[x].v,st);
+   }
+  }
+  else
+   fwrite((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
+  }
+  #endif
+ }
+ return (bsize+5);
+}
+
+int ReadStateChunk(FILE *st, SFORMAT *sf, int count, int size)
+{
+ uint8 tmpyo[16];
+ int bsize;
+ int x;
+
+ for(x=bsize=0;x<count;x++)
+  bsize+=sf[x].s&(~RLSB);
+ if(stateversion>=53)
+  bsize+=count<<3;
+ else
+ {
+  if(bsize!=size)
+  {
+   fseek(st,size,SEEK_CUR);
+   return 0;
+  }
+ }
+
+ if(stateversion<56)
+  memcpy(tmpyo,mapbyte3,16);
+
+ if(stateversion>=53)
+ {
+  int temp;
+  temp=ftell(st);
+
+  while(ftell(st)<temp+size)
+  {
+   int tsize;
+   char toa[4];
+
+   if(fread(toa,1,4,st)<=0)
+    return 0;
+   read32(&tsize,st);
+
+   for(x=0;x<count;x++)
+   {
+    if(!memcmp(toa,sf[x].desc,4))
+    {
+     if(tsize!=(sf[x].s&(~RLSB)))
+      goto nkayo;
+     #ifndef LSB_FIRST
+     if(sf[x].s&RLSB)
+     {
+      int z;
+       for(z=(sf[x].s&(~RLSB))-1;z>=0;z--)       
+        *(uint8*)sf[x].v=fgetc(st);
+     }
+     else
+     #endif
+     {
+       fread((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
+     }
+     goto bloo;
+    }
+   }
+  nkayo:
+  fseek(st,tsize,SEEK_CUR);
+  bloo:;
+  } // while(...)
+ }  // >=53
+ else
+ {
+  for(x=0;x<count;x++)
+  {
+   #ifdef LSB_FIRST
+   fread((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
+   #else
+   int z;
+   if(sf[x].s&RLSB)
+    for(z=(sf[x].s&(~RLSB))-1;z>=0;z--)
+    {
+     *(uint8*)sf[x].v=fgetc(st);
+    }
+   else
+    fread((uint8 *)sf[x].v,1,sf[x].s&(~RLSB),st);
+   #endif
+  }
+ }
+ if(stateversion<56)
+ {
+  for(x=0;x<16;x++)
+   #ifdef LSB_FIRST
+   mapbyte1[x]=mapbyte1[x<<1];
+   #else
+   mapbyte1[x]=mapbyte1[(x<<1)+1];
+   #endif
+  memcpy(mapbyte3,tmpyo,16);
+ }
+ return 1;
+}
+
+int ReadStateChunks(FILE *st)
+{
+ int t;
+ uint32 size;
+ int ret=1;
+
+for(;;)
+ {
+  t=fgetc(st);
+  if(t==EOF) break;
+  if(!read32(&size,st)) break;
+  switch(t)
+  {
+   case 1:if(!ReadStateChunk(st,SFCPU,SFCPUELEMENTS,size)) ret=0;break;
+   case 2:if(!ReadStateChunk(st,SFCPUC,SFCPUCELEMENTS,size)) ret=0;
+          else
+         {
+          X.mooPI=X.P; // Quick and dirty hack.
+         }
+         break;
+   case 3:if(!ReadStateChunk(st,SFPPU,SFPPUELEMENTS,size)) ret=0;break;
+//   case 4:if(!ReadStateChunk(st,SFCTLR,SFCTLRELEMENTS,size)) ret=0;break;
+   case 5:if(!ReadStateChunk(st,SFSND,SFSNDELEMENTS,size)) ret=0;break;
+   case 0x10:if(!ReadStateChunk(st,SFMDATA,SFEXINDEX,size)) ret=0;break;
+   default: if(fseek(st,size,SEEK_CUR)<0) goto endo;break;
+  }
+ }
+ endo:
+ return ret;
+}
+
+
+int CurrentState=0;
+extern int geniestage;
+void SaveState(void)
+{
+       FILE *st=NULL;
+
+       TempAddrT=TempAddr;
+       RefreshAddrT=RefreshAddr;
+
+       if(geniestage==1)
+       {
+        FCEU_DispMessage("Cannot save FCS in GG screen.");
+        return;
+        }
+
+        st=fopen(FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0),"wb");
+
+        if(st!=NULL)
+        {
+         static uint32 totalsize;
+         static uint8 header[16]="FCS";
+         memset(header+4,0,13);
+         header[3]=VERSION_NUMERIC;
+         fwrite(header,1,16,st);
+
+         totalsize=WriteStateChunk(st,1,SFCPU,SFCPUELEMENTS);
+         totalsize+=WriteStateChunk(st,2,SFCPUC,SFCPUCELEMENTS);
+         totalsize+=WriteStateChunk(st,3,SFPPU,SFPPUELEMENTS);
+       //  totalsize+=WriteStateChunk(st,4,SFCTLR,SFCTLRELEMENTS);
+         totalsize+=WriteStateChunk(st,5,SFSND,SFSNDELEMENTS);
+         totalsize+=WriteStateChunk(st,0x10,SFMDATA,SFEXINDEX);
+       
+         fseek(st,4,SEEK_SET);
+         write32(totalsize,st);
+         SaveStateStatus[CurrentState]=1;
+         fclose(st);
+         FCEU_DispMessage("State %d saved.",CurrentState);
+        }
+        else
+         FCEU_DispMessage("State %d save error.",CurrentState);
+}
+
+static int LoadStateOld(FILE *st);
+void LoadState(void)
+{
+       int x;
+       FILE *st=NULL;
+
+        if(geniestage==1)
+        {
+         FCEU_DispMessage("Cannot load FCS in GG screen.");
+         return;
+        }
+
+       st=fopen(FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0),"rb");
+
+       if(st!=NULL)
+       {
+        uint8 header[16];
+
+         fread(&header,1,16,st);
+         if(memcmp(header,"FCS",3))
+         {
+          fseek(st,0,SEEK_SET);    
+          if(!LoadStateOld(st))
+           goto lerror;
+          goto okload;
+         }
+         stateversion=header[3];
+        if(stateversion<53)
+        FixOldSaveStateSFreq();
+        x=ReadStateChunks(st);
+        if(GameStateRestore) GameStateRestore(header[3]);
+        if(x)
+        {
+         okload:
+          TempAddr=TempAddrT;
+          RefreshAddr=RefreshAddrT;
+
+         SaveStateStatus[CurrentState]=1;
+         FCEU_DispMessage("State %d loaded.",CurrentState);
+         SaveStateStatus[CurrentState]=1;
+        }
+        else
+        {
+         SaveStateStatus[CurrentState]=1;
+         FCEU_DispMessage("Error(s) reading state %d!",CurrentState);
+        }
+       }
+       else
+       {
+        lerror:
+        FCEU_DispMessage("State %d load error.",CurrentState);
+        SaveStateStatus[CurrentState]=0;
+        return;
+       }
+       fclose(st);
+}
+
+char SaveStateStatus[10];
+void CheckStates(void)
+{
+       FILE *st=NULL;
+       int ssel;
+
+       if(SaveStateStatus[0]==-1)
+        for(ssel=0;ssel<10;ssel++)
+        {
+         st=fopen(FCEU_MakeFName(FCEUMKF_STATE,ssel,0),"rb");
+          if(st)
+          {
+           SaveStateStatus[ssel]=1;
+           fclose(st);
+          }
+          else
+           SaveStateStatus[ssel]=0;
+        }
+}
+
+void SaveStateRefresh(void)
+{
+ SaveStateStatus[0]=-1;
+}
+
+void ResetExState(void)
+{
+ int x;
+ for(x=0;x<SFEXINDEX;x++)
+  free(SFMDATA[x].desc);
+ SFEXINDEX=0;
+}
+
+void AddExState(void *v, uint32 s, int type, char *desc)
+{
+ SFMDATA[SFEXINDEX].desc=FCEU_malloc(5);
+ if(SFMDATA[SFEXINDEX].desc)
+ {
+  strcpy(SFMDATA[SFEXINDEX].desc,desc);
+  SFMDATA[SFEXINDEX].v=v;
+  SFMDATA[SFEXINDEX].s=s;
+  if(type) SFMDATA[SFEXINDEX].s|=RLSB;
+  if(SFEXINDEX<63) SFEXINDEX++;
+ }
+}
+
+/* Old state loading code follows */
+
+uint8 *StateBuffer;
+unsigned int intostate;
+
+static void afread(void *ptr, size_t _size, size_t _nelem)
+{
+       memcpy(ptr,StateBuffer+intostate,_size*_nelem);
+       intostate+=_size*_nelem;
+}
+
+
+static void areadlower8of16(int8 *d)
+{
+#ifdef LSB_FIRST
+       *d=StateBuffer[intostate++];
+#else
+       d[1]=StateBuffer[intostate++];
+#endif
+}
+
+
+static void areadupper8of16(int8 *d)
+{
+#ifdef LSB_FIRST
+       d[1]=StateBuffer[intostate++];
+#else
+       *d=StateBuffer[intostate++];
+#endif
+}
+
+
+static void aread16(int8 *d)
+{
+#ifdef LSB_FIRST
+       *d=StateBuffer[intostate++];
+       d[1]=StateBuffer[intostate++];
+#else
+       d[1]=StateBuffer[intostate++];
+       *d=StateBuffer[intostate++];
+#endif
+}
+
+
+static void aread32(int8 *d)
+{
+#ifdef LSB_FIRST
+       *d=StateBuffer[intostate++];
+       d[1]=StateBuffer[intostate++];
+       d[2]=StateBuffer[intostate++];
+       d[3]=StateBuffer[intostate++];
+#else
+       d[3]=StateBuffer[intostate++];
+       d[2]=StateBuffer[intostate++];
+       d[1]=StateBuffer[intostate++];
+       *d=StateBuffer[intostate++];
+#endif
+}
+
+static int LoadStateOld(FILE *st)
+{
+       int x;
+       int32 nada;
+        uint8 version;
+       nada=0;
+       
+       StateBuffer=FCEU_malloc(59999);
+       if(StateBuffer==NULL)
+         return 0;
+        if(!fread(StateBuffer,59999,1,st))
+        {
+            fclose(st);
+            free(StateBuffer);
+            return 0;
+        }
+
+       intostate=0;
+
+       {
+        uint8 a[2];
+        afread(&a[0],1,1);
+        afread(&a[1],1,1);
+        X.PC=a[0]|(a[1]<<8);
+       }
+       afread(&X.A,1,1);
+       afread(&X.P,1,1);
+       afread(&X.X,1,1);
+       afread(&X.Y,1,1);
+       afread(&X.S,1,1);
+       afread(&version,1,1);
+       afread(&nada,1,1);
+       afread(&nada,1,1);
+       afread(&nada,1,1);
+       afread(&nada,1,1);
+       aread32((int8 *)&X.count);
+       afread(&nada,1,1);
+       afread(&nada,1,1);
+       afread(&nada,1,1);
+       afread(&nada,1,1);
+       aread32((int8 *)&nada);
+       afread(&nada,1,1);
+       afread(&nada,1,1);
+       afread(&nada,1,1);
+       afread(&nada,1,1);
+       
+       for(x=0;x<8;x++)
+               areadupper8of16((int8 *)&CHRBankList[x]);
+       afread(PRGBankList,4,1);
+       for(x=0;x<8;x++)
+               areadlower8of16((int8 *)&CHRBankList[x]);
+        afread(CHRRAM,1,0x2000);
+        afread(NTARAM,1,0x400);
+        afread(ExtraNTARAM,1,0x400);
+        afread(NTARAM+0x400,1,0x400);
+        afread(ExtraNTARAM+0x400,1,0x400);
+
+        for(x=0;x<0xF00;x++)
+         afread(&nada,1,1);
+        afread(PALRAM,1,0x20);
+        for(x=0;x<256-32;x++)
+         afread(&nada,1,1);
+        for(x=0x00;x<0x20;x++)
+         PALRAM[x]&=0x3f;
+       afread(PPU,1,4);
+       afread(SPRAM,1,0x100);
+       afread(WRAM,1,8192);
+       afread(RAM,1,0x800);
+       aread16((int8 *)&scanline);
+       aread16((int8 *)&RefreshAddr);
+       afread(&VRAMBuffer,1,1);
+       
+       afread(&IRQa,1,1);
+       aread32((int8 *)&IRQCount);
+       aread32((int8 *)&IRQLatch);
+       afread(&Mirroring,1,1);
+       afread(PSG,1,0x17);
+       PSG[0x11]&=0x7F;
+        afread(MapperExRAM,1,193);
+        if(version>=31)
+         PSG[0x17]=MapperExRAM[115];
+        else
+         PSG[0x17]|=0x40;
+        PSG[0x15]&=0xF;
+        sqnon=PSG[0x15];
+
+        X.IRQlow=0;
+        afread(&nada,1,1);
+        afread(&nada,1,1);
+        afread(&nada,1,1);
+        afread(&nada,1,1);
+        afread(&nada,1,1);
+        afread(&nada,1,1);
+       afread(&XOffset,1,1);
+        PPUCHRRAM=0;
+        for(x=0;x<8;x++)
+        {
+         nada=0;
+         afread(&nada,1,1);
+         PPUCHRRAM|=(nada?1:0)<<x;         
+        }
+                       
+         afread(mapbyte1,1,8);
+         afread(mapbyte2,1,8);
+         afread(mapbyte3,1,8);
+         afread(mapbyte4,1,8);
+         for(x=0;x<4;x++)
+          aread16((int8 *)&nada);
+                
+         PPUNTARAM=0;
+         for(x=0;x<4;x++)
+         {
+          nada=0;
+          aread16((int8 *)&nada);
+          PPUNTARAM|=((nada&0x800)?0:1)<<x;
+         }
+         afread(MapperExRAM,1,32768);
+         afread(&vtoggle,1,1);
+         aread16((int8 *)&TempAddrT);
+         aread16((int8 *)&RefreshAddrT);
+                               
+         if(GameStateRestore) GameStateRestore(version);
+         free(StateBuffer);
+        FixOldSaveStateSFreq();
+        X.mooPI=X.P;
+         return 1;
+}
+
diff --git a/state.h b/state.h
new file mode 100644 (file)
index 0000000..61939fd
--- /dev/null
+++ b/state.h
@@ -0,0 +1,39 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+void SaveState(void);
+void LoadState(void);
+
+extern uint8 StateName[2048];
+extern uint8 StateFile[2048];
+extern int CurrentState;
+extern char SaveStateStatus[10];
+void CheckStates(void);
+void SaveStateRefresh(void);
+
+typedef struct {
+           void *v;
+           uint32 s;
+          char *desc;
+} SFORMAT;
+
+void ResetExState(void);
+void AddExState(void *v, uint32 s, int type, char *desc);
+
diff --git a/svga.c b/svga.c
new file mode 100644 (file)
index 0000000..815af19
--- /dev/null
+++ b/svga.c
@@ -0,0 +1,567 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 BERO 
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+/*                      SVGA High Level Routines
+                          FCE / FCE Ultra
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#include <stdarg.h>
+
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#include "types.h"
+#include "svga.h" 
+#include "fce.h"
+#include "general.h"
+#include "video.h"
+#include "sound.h"
+#include "version.h"
+#include "nsf.h"
+#include "palette.h"
+#include "fds.h"
+#include "netplay.h"
+#include "state.h"
+#include "cart.h"
+#include "input.h"
+
+FCEUS FSettings;
+
+static int howlong;
+static char errmsg[65];
+
+void FCEU_PrintError(char *format, ...)
+{
+ char temp[2048];
+
+ va_list ap;
+
+ va_start(ap,format);
+ vsprintf(temp,format,ap);
+ FCEUD_PrintError(temp);
+
+ va_end(ap);
+}
+
+void FCEU_DispMessage(char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap,format);
+ vsprintf(errmsg,format,ap);
+ va_end(ap);
+
+ howlong=180;
+}
+
+void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall)
+{
+ FSettings.UsrFirstSLine[0]=ntscf;
+ FSettings.UsrLastSLine[0]=ntscl;
+ FSettings.UsrFirstSLine[1]=palf;
+ FSettings.UsrLastSLine[1]=pall;
+ if(PAL)
+ {
+  FSettings.FirstSLine=FSettings.UsrFirstSLine[1];
+  FSettings.LastSLine=FSettings.UsrLastSLine[1];
+ }
+ else
+ {
+  FSettings.FirstSLine=FSettings.UsrFirstSLine[0];
+  FSettings.LastSLine=FSettings.UsrLastSLine[0];
+ }
+
+}
+
+void FCEUI_SetVidSystem(int a)
+{
+ FSettings.PAL=a?1:0;
+ FCEU_ResetVidSys();
+ FCEU_ResetPalette();
+}
+
+int FCEUI_GetCurrentVidSystem(int *slstart, int *slend)
+{
+ if(slstart)
+  *slstart=FSettings.FirstSLine;
+ if(slend)
+  *slend=FSettings.LastSLine;
+ return(PAL);
+}
+
+#ifdef NETWORK
+void FCEUI_SetNetworkPlay(int type)
+{
+ FSettings.NetworkPlay=type;
+}
+#endif
+
+void FCEUI_SetGameGenie(int a)
+{
+ FSettings.GameGenie=a?1:0;
+}
+
+static void CalculatePalette(void);
+static void ChoosePalette(void);
+static void WritePalette(void);
+
+#ifndef NETWORK
+#define netplay 0
+#endif
+
+static uint8 StateShow=0;
+
+uint8 Exit=0;
+
+uint8 DIPS=0;
+uint8 vsdip=0;
+int coinon=0;
+
+uint8 pale=0;
+uint8 CommandQueue=0;
+
+static int controlselect=0;
+static int ntsccol=0;
+static int ntsctint=46+10;
+static int ntschue=72;
+static int controllength=0;
+
+pal *palo;
+static pal *palpoint[8]=
+     {
+     palette,
+     palettevscv,
+     palettevssmb,
+     palettevsmar,
+     palettevsgoon,
+     palettevsslalom,
+     palettevseb,
+     rp2c04001
+     };
+
+void FCEUI_SetSnapName(int a)
+{
+ FSettings.SnapName=a;
+}
+
+void FCEUI_SaveExtraDataUnderBase(int a)
+{
+ FSettings.SUnderBase=a;
+}
+
+void FCEUI_SetPaletteArray(uint8 *pal)
+{
+ if(!pal)
+  palpoint[0]=palette;
+ else
+ {
+  int x;
+  palpoint[0]=palettec;
+  for(x=0;x<64;x++)
+  {
+   palpoint[0][x].r=*((uint8 *)pal+x+x+x);
+   palpoint[0][x].g=*((uint8 *)pal+x+x+x+1);
+   palpoint[0][x].b=*((uint8 *)pal+x+x+x+2);
+  }
+ }
+ FCEU_ResetPalette();
+}
+
+void FCEUI_SelectState(int w)
+{
+ if(netplay!=2 && FCEUGameInfo.type!=GIT_NSF) 
+  CommandQueue=42+w;
+}
+
+void FCEUI_SaveState(void)
+{
+ if(netplay!=2 && FCEUGameInfo.type!=GIT_NSF)
+  CommandQueue=40;
+}
+
+void FCEUI_LoadState(void)
+{
+ if(netplay!=2 && FCEUGameInfo.type!=GIT_NSF) 
+  CommandQueue=41;
+}
+
+int32 FCEUI_GetDesiredFPS(void)
+{
+  if(PAL)
+   return(838977920); // ~50.007
+  else
+   return(1008307711); // ~60.1
+}
+
+static int dosnapsave=0;
+void FCEUI_SaveSnapshot(void)
+{
+ dosnapsave=1;
+}
+
+/* I like the sounds of breaking necks. */
+static void ReallySnap(void)
+{
+ int x=SaveSnapshot();
+ if(!x)
+  FCEU_DispMessage("Error saving screen snapshot.");
+ else
+  FCEU_DispMessage("Screen snapshot %d saved.",x-1);
+}
+
+void DriverInterface(int w, void *d)
+{
+ switch(w)
+ {
+  case DES_NTSCCOL:ntsccol=*(int *)d;FCEU_ResetPalette();break;
+  case DES_RESET:if(netplay!=2) CommandQueue=30;break;
+  case DES_POWER:if(netplay!=2) CommandQueue=31;break;
+  case DES_GETNTSCTINT:*(int*)d=ntsctint;break;
+  case DES_GETNTSCHUE:*(int*)d=ntschue;break;
+  case DES_SETNTSCTINT:ntsctint=*(int*)d;if(ntsccol)FCEU_ResetPalette();break;
+  case DES_SETNTSCHUE:ntschue=*(int*)d;if(ntsccol)FCEU_ResetPalette();break;
+
+  case DES_FDSINSERT:if(netplay!=2) CommandQueue=2;break;
+  case DES_FDSEJECT:if(netplay!=2) CommandQueue=3;break;
+  case DES_FDSSELECT:if(netplay!=2) CommandQueue=1;break;
+
+  case DES_NSFINC:NSFControl(1);break;
+  case DES_NSFDEC:NSFControl(2);break;
+  case DES_NSFRES:NSFControl(0);break;  
+
+  case DES_VSUNIDIPSET:CommandQueue=10+(int)d;break;
+  case DES_VSUNITOGGLEDIPVIEW:CommandQueue=10;break;
+  case DES_VSUNICOIN:CommandQueue=19;break;
+  case DES_NTSCSELHUE:if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF){controlselect=1;controllength=360;}break;
+  case DES_NTSCSELTINT:if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF){controlselect=2;controllength=360;}break;
+
+  case DES_NTSCDEC:
+                 if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF)
+                 {
+                  char which;
+                  if(controlselect)
+                  {
+                   if(controllength)
+                   {
+                    which=controlselect==1?ntschue:ntsctint;
+                    which--;
+                    if(which<0) which=0;
+                        if(controlselect==1) 
+                         ntschue=which;                     
+                        else ntsctint=which;                
+                    CalculatePalette();
+                   }
+                  controllength=360;
+                   }
+                  }
+                 break;
+  case DES_NTSCINC:    
+                  if(ntsccol && FCEUGameInfo.type!=GIT_VSUNI && !PAL && FCEUGameInfo.type!=GIT_NSF)
+                    if(controlselect)
+                    {
+                     if(controllength)
+                     {
+                      switch(controlselect)
+                      {
+                       case 1:ntschue++;
+                              if(ntschue>128) ntschue=128;
+                              CalculatePalette();
+                              break;
+                       case 2:ntsctint++;
+                              if(ntsctint>128) ntsctint=128;
+                              CalculatePalette();
+                              break;
+                      }
+                     }
+                     controllength=360;
+                    }
+                   break;
+  }
+}
+
+static uint8 lastd=0;
+void SetNESDeemph(uint8 d, int force)
+{
+ static uint16 rtmul[7]={32768*1.239,32768*.794,32768*1.019,32768*.905,32768*1.023,32768*.741,32768*.75};
+ static uint16 gtmul[7]={32768*.915,32768*1.086,32768*.98,32768*1.026,32768*.908,32768*.987,32768*.75};
+ static uint16 btmul[7]={32768*.743,32768*.882,32768*.653,32768*1.277,32768*.979,32768*.101,32768*.75};
+ uint32 r,g,b;
+ int x;
+
+ /* If it's not forced(only forced when the palette changes), 
+    don't waste cpu time if the same deemphasis bits are set as the last call. 
+ */
+ if(!force) 
+ {
+  if(d==lastd) 
+   return;
+ }
+ else  /* Only set this when palette has changed. */
+ {
+  r=rtmul[6];
+  g=rtmul[6];
+  b=rtmul[6];
+
+  for(x=0;x<0x40;x++)
+  {
+   uint32 m,n,o;
+   m=palo[x].r;
+   n=palo[x].g;
+   o=palo[x].b;
+   m=(m*r)>>15;
+   n=(n*g)>>15;
+   o=(o*b)>>15;
+   if(m>0xff) m=0xff;
+   if(n>0xff) n=0xff;
+   if(o>0xff) o=0xff;
+   FCEUD_SetPalette(x|0x40,m,n,o);
+  }
+ }
+ if(!d) return;        /* No deemphasis, so return. */
+
+  r=rtmul[d-1];
+  g=gtmul[d-1];
+  b=btmul[d-1];
+
+    for(x=0;x<0x40;x++)
+    {
+     uint32 m,n,o;
+
+     m=palo[x].r;
+     n=palo[x].g;
+     o=palo[x].b;
+     m=(m*r)>>15;
+     n=(n*g)>>15;
+     o=(o*b)>>15;
+     if(m>0xff) m=0xff;
+     if(n>0xff) n=0xff;
+     if(o>0xff) o=0xff;
+
+     FCEUD_SetPalette(x|0xC0,m,n,o);
+    }
+ lastd=d;
+}
+
+#define HUEVAL  ((double)((double)ntschue/(double)2)+(double)300)
+#define TINTVAL ((double)((double)ntsctint/(double)128))
+
+static void CalculatePalette(void)
+{
+ int x,z;
+ int r,g,b;
+ double s,y,theta;
+ static uint8 cols[16]={0,24,21,18,15,12,9,6,3,0,33,30,27,0,0,0};
+ static uint8 br1[4]={6,9,12,12};
+ static double br2[4]={.29,.45,.73,.9};
+ static double br3[4]={0,.24,.47,.77};
+  
+ for(x=0;x<=3;x++)
+  for(z=0;z<16;z++)
+  {
+   s=(double)TINTVAL;
+   y=(double)br2[x];
+   if(z==0)  {s=0;y=((double)br1[x])/12;}
+   
+   if(z>=13)
+   {
+    s=y=0;
+    if(z==13)
+     y=(double)br3[x];     
+   }
+
+   theta=(double)M_PI*(double)(((double)cols[z]*10+HUEVAL)/(double)180);
+   r=(int)(((double)y+(double)s*(double)sin(theta))*(double)256);
+   g=(int)(((double)y-(double)((double)27/(double)53)*s*(double)sin(theta)+(double)((double)10/(double)53)*s*cos(theta))*(double)256);
+   b=(int)(((double)y-(double)s*(double)cos(theta))*(double)256);  
+
+   // TODO:  Fix RGB to compensate for phosphor changes(add to red??).
+
+   if(r>255) r=255;
+   if(g>255) g=255;
+   if(b>255) b=255;
+   if(r<0) r=0;
+   if(g<0) g=0;
+   if(b<0) b=0;
+    
+   paletten[(x<<4)+z].r=r;
+   paletten[(x<<4)+z].g=g;
+   paletten[(x<<4)+z].b=b;
+  }
+ WritePalette();
+}
+
+#include "drawing.h"
+#ifdef FRAMESKIP
+void FCEU_PutImageDummy(void)
+{
+ if(FCEUGameInfo.type!=GIT_NSF)
+ {
+  if(controllength) controllength--;
+ }
+ if(StateShow) StateShow--; /* DrawState() */
+ if(howlong) howlong--;        /* DrawMessage() */
+ #ifdef FPS
+ {
+  extern uint64 frcount;
+  frcount++;
+ }
+ #endif
+
+}
+#endif
+
+void FCEU_PutImage(void)
+{
+        if(FCEUGameInfo.type==GIT_NSF)
+       {
+         DrawNSF(XBuf);
+        /* Save snapshot after NSF screen is drawn.  Why would we want to
+           do it before?
+        */
+         if(dosnapsave)
+         {
+          ReallySnap();
+          dosnapsave=0;
+         }
+       }
+        else
+        {      
+        /* Save snapshot before overlay stuff is written. */
+         if(dosnapsave)
+         {
+          ReallySnap();
+          dosnapsave=0;
+         }
+        if(FCEUGameInfo.type==GIT_VSUNI && DIPS&2)         
+         DrawDips();
+         if(StateShow) DrawState();
+         if(controllength) {controllength--;DrawBars();}
+        }
+       DrawMessage();
+       #ifdef FPS
+       {
+       extern uint64 frcount;
+       frcount++;
+       }
+       #endif
+       DrawInput(XBuf+8);
+}
+
+static int ipalette=0;
+
+void LoadGamePalette(void)
+{
+  uint8 ptmp[192];
+  FILE *fp;
+  ipalette=0;
+  if((fp=fopen(FCEU_MakeFName(FCEUMKF_PALETTE,0,0),"rb")))
+  {
+   int x;
+   fread(ptmp,1,192,fp);
+   fclose(fp);
+   for(x=0;x<64;x++)
+   {
+    palettei[x].r=ptmp[x+x+x];
+    palettei[x].g=ptmp[x+x+x+1];
+    palettei[x].b=ptmp[x+x+x+2];
+   }
+   ipalette=1;
+  }
+}
+
+void FCEU_ResetPalette(void)
+{
+   ChoosePalette();
+   WritePalette();
+}
+
+static void ChoosePalette(void)
+{
+    if(FCEUGameInfo.type==GIT_NSF)
+     palo=NSFPalette;   
+    else if(ipalette)
+     palo=palettei;
+    else if(ntsccol && !PAL && FCEUGameInfo.type!=GIT_VSUNI)
+     {
+      palo=paletten;
+      CalculatePalette();
+     }
+    else
+     palo=palpoint[pale];  
+}
+
+void WritePalette(void)
+{
+    int x;
+
+    for(x=0;x<6;x++)
+     FCEUD_SetPalette(x+128,unvpalette[x].r,unvpalette[x].g,unvpalette[x].b);
+    if(FCEUGameInfo.type==GIT_NSF)
+    {
+     for(x=0;x<39;x++)
+      FCEUD_SetPalette(x,palo[x].r,palo[x].g,palo[x].b); 
+    }
+    else
+    {
+     for(x=0;x<64;x++)
+      FCEUD_SetPalette(x,palo[x].r,palo[x].g,palo[x].b);
+     SetNESDeemph(lastd,1);
+    }
+}
+
+void FlushCommandQueue(void)
+{
+  if(!netplay && CommandQueue) {DoCommand(CommandQueue);CommandQueue=0;}
+}
+
+void DoCommand(uint8 c)
+{
+ switch(c)
+ {
+  case 1:FDSControl(FDS_SELECT);break;
+  case 2:FDSControl(FDS_IDISK);break;
+  case 3:FDSControl(FDS_EJECT);break;
+
+  case 10:DIPS^=2;break;
+  case 11:vsdip^=1;DIPS|=2;break;
+  case 12:vsdip^=2;DIPS|=2;break;
+  case 13:vsdip^=4;DIPS|=2;break;
+  case 14:vsdip^=8;DIPS|=2;break;
+  case 15:vsdip^=0x10;DIPS|=2;break;
+  case 16:vsdip^=0x20;DIPS|=2;break;
+  case 17:vsdip^=0x40;DIPS|=2;break;
+  case 18:vsdip^=0x80;DIPS|=2;break;
+  case 19:coinon=6;break;
+  case 30:ResetNES();break;
+  case 31:PowerNES();break;
+  case 40:CheckStates();StateShow=0;SaveState();break;
+  case 41:CheckStates();StateShow=0;LoadState();break;
+  case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49:
+  case 50: case 51:StateShow=180;CurrentState=c-42;CheckStates();break;
+ }
+}
diff --git a/svga.h b/svga.h
new file mode 100644 (file)
index 0000000..cebd555
--- /dev/null
+++ b/svga.h
@@ -0,0 +1,83 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 1998 Bero
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include "driver.h"
+typedef struct __pal {
+       uint8 r;
+       uint8 g;
+       uint8 b;
+} pal;
+
+typedef struct {
+           int PAL;
+           #ifdef NETWORK
+           int NetworkPlay;
+           #endif
+          int SoundVolume;
+           int GameGenie;
+          int SUnderBase;
+
+          /* Current first and last rendered scanlines. */
+          int FirstSLine;
+          int LastSLine;
+
+          /* Driver code(user)-specified first and last rendered scanlines. 
+             Usr*SLine[0] is for NTSC, Usr*SLine[1] is for PAL.
+           */
+          int UsrFirstSLine[2];
+          int UsrLastSLine[2];
+          int SnapName;
+          unsigned int SndRate;
+} FCEUS;
+
+extern FCEUS FSettings;
+
+void FCEU_PrintError(char *format, ...);
+void FCEU_DispMessage(char *format, ...);
+
+void SetNESDeemph(uint8 d, int force);
+void DrawTextTrans(uint8 *dest, uint32 width, uint8 *textmsg, uint8 fgcolor);
+void FCEU_PutImage(void);
+#ifdef FRAMESKIP
+void FCEU_PutImageDummy(void);
+#endif
+
+extern uint8 Exit;
+extern uint8 pale;
+extern uint8 vsdip;
+void SetNESPalette(void);
+
+#define JOY_A   1
+#define JOY_B   2
+#define JOY_SELECT      4
+#define JOY_START       8
+#define JOY_UP  0x10
+#define JOY_DOWN        0x20
+#define JOY_LEFT        0x40
+#define JOY_RIGHT       0x80
+
+extern pal *palo;
+
+void DoCommand(uint8 c);
+extern uint8 CommandQueue;
+void FCEU_ResetPalette(void);
+void LoadGamePalette(void);
+void FlushCommandQueue(void);
diff --git a/types.h b/types.h
new file mode 100644 (file)
index 0000000..05512f8
--- /dev/null
+++ b/types.h
@@ -0,0 +1,66 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2001 Aaron Oneal
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#ifndef __FCEU_TYPES
+#define __FCEU_TYPES
+
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned long  uint32;
+
+#ifdef __GNUC__
+ typedef unsigned long long uint64;
+ typedef long long int64;
+ #define INLINE inline
+ #define GINLINE inline
+#elif MSVC
+ typedef __int64 int64;
+ typedef unsigned __int64 uint64;
+ #define INLINE __inline
+ #define GINLINE                       /* Can't declare a function INLINE
+                                          and global in MSVC.  Bummer.
+                                       */
+ #define PSS_STYLE 2                   /* Does MSVC compile for anything
+                                          other than Windows/DOS targets?
+                                       */
+#endif
+typedef signed char int8;
+typedef signed short int16;
+typedef signed long int32;
+#define byte uint8
+#define word uint16
+
+#ifdef __GNUC__
+ #ifdef C80x86
+  #define FASTAPASS(x) __attribute__((regparm(x)))
+  #define FP_FASTAPASS FASTAPASS
+ #else
+  #define FASTAPASS(x) 
+  #define FP_FASTAPASS(x)      
+ #endif
+#else
+ #define FP_FASTAPASS(x)
+ #define FASTAPASS(x) __fastcall
+#endif
+
+typedef void FP_FASTAPASS(2) (*writefunc)(uint32 A, uint8 V);
+typedef uint8 FP_FASTAPASS(1) (*readfunc)(uint32 A);
+#endif
diff --git a/unif.c b/unif.c
new file mode 100644 (file)
index 0000000..f54ad39
--- /dev/null
+++ b/unif.c
@@ -0,0 +1,469 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+/* TODO:  Battery backup file saving, mirror force */
+/* **INCOMPLETE**                                 */
+/* Override stuff: CHR RAM instead of CHR ROM,
+                  mirroring.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include       "types.h"
+#include        "fce.h"
+#include        "unif.h"
+#include        "version.h"
+#include       "svga.h"
+#include        "general.h"
+#include       "state.h"
+#include       "endian.h"
+#include       "file.h"
+#include       "cart.h"
+#include       "memory.h"
+#include       "input.h"
+
+typedef struct {
+           char ID[4];
+           uint32 info;
+} UNIF_HEADER;
+
+typedef struct {
+           char *name;
+           void (*init)(void);
+          int flags;
+} BMAPPING;
+
+typedef struct {
+           char *name;
+           int (*init)(int fp);
+} BFMAPPING;
+
+void (*BoardClose)(void);
+void (*BoardPower)(void);
+void (*BoardReset)(void);
+
+static int vramo;
+static int mirrortodo;
+int UNIFbattery;
+static char *boardname;
+static char *sboardname;
+char *UNIFchrrama;
+
+static UNIF_HEADER unhead;
+static UNIF_HEADER uchead;
+
+
+static uint8 *malloced[32];
+
+static int FixRomSize(uint32 size, uint32 minimum)
+{
+  int x=1;
+
+  if(size<minimum)
+   return minimum;
+  while(x<size)
+   x<<=1;
+  return x;
+}
+
+static void FreeUNIF(void)
+{
+ int x;
+ if(UNIFchrrama)
+  {free(UNIFchrrama);UNIFchrrama=0;}
+ if(boardname)
+  {free(boardname);boardname=0;}
+ for(x=0;x<32;x++)
+ {
+  if(malloced[x])
+   {free(malloced[x]);malloced[x]=0;}
+ }
+}
+
+static void ResetUNIF(void)
+{
+ int x;
+ for(x=0;x<32;x++)
+  malloced[x]=0;
+ vramo=0;
+ UNIFbattery=0;
+ boardname=0;
+ mirrortodo=0;
+ BoardReset=BoardPower=BoardClose=0;
+ UNIFchrrama=0;
+}
+
+static uint8 exntar[2048];
+
+static void MooMirroring(void)
+{
+ if(mirrortodo<0x4)
+  SetupCartMirroring(mirrortodo,1,0);
+ else if(mirrortodo==0x4)
+ {
+  SetupCartMirroring(4,1,exntar);
+  AddExState(exntar, 2048, 0,"EXNR");
+ }
+ else
+  SetupCartMirroring(0,0,0);
+}
+
+static int DoMirroring(int fp)
+{
+ uint8 t;
+ t=FCEU_fgetc(fp);
+ mirrortodo=t; 
+
+ {
+  static char *stuffo[6]={"Horizontal","Vertical","$2000","$2400","\"Four-screen\"","Controlled by Mapper Hardware"};
+  if(t<6)
+   printf(" Name/Attribute Table Mirroring: %s\n",stuffo[t]);
+ }
+ return(1);
+}
+
+static int CTRL(int fp)
+{
+ int t;
+
+ if((t=FCEU_fgetc(fp))==EOF)
+  return(0);
+ /* The information stored in this byte isn't very helpful, but it's
+    better than nothing...maybe.
+ */
+
+ if(t&1) FCEUGameInfo.input[0]=FCEUGameInfo.input[1]=SI_GAMEPAD;
+ else FCEUGameInfo.input[0]=FCEUGameInfo.input[1]=SI_NONE;
+
+ if(t&2) FCEUGameInfo.input[1]=SI_ZAPPER;
+ else if(t&0x10) FCEUGameInfo.input[1]=SI_POWERPAD;
+
+ return(1);
+}
+
+static int TVCI(int fp)
+{
+ int t;
+ if( (t=FCEU_fgetc(fp)) ==EOF)
+  return(0);
+ if(t<=2)
+ {
+  char *stuffo[3]={"NTSC","PAL","NTSC and PAL"};
+  if(t==0)
+   FCEUGameInfo.vidsys=GIV_NTSC;
+  else if(t==1)
+   FCEUGameInfo.vidsys=GIV_PAL;
+  printf(" TV Standard Compatibility: %s\n",stuffo[t]);
+ }
+ return(1);
+}
+
+static int EnableBattery(int fp)
+{
+ puts(" Battery-backed.");
+ if(FCEU_fgetc(fp)==EOF)
+  return(0);
+ UNIFbattery=1;
+ return(1);
+}
+
+static int LoadPRG(int fp)
+{
+ int z,t;
+ z=uchead.ID[3]-'0';
+
+ if(z<0 || z>15)
+  return(0);
+ printf(" PRG ROM %d size: %d",z,(int) uchead.info);
+ if(malloced[z])
+  free(malloced[z]);
+ t=FixRomSize(uchead.info,2048);
+ if(!(malloced[z]=FCEU_malloc(t)))
+  return(0);
+ memset(malloced[z]+uchead.info,0xFF,t-uchead.info);
+ if(FCEU_fread(malloced[z],1,uchead.info,fp)!=uchead.info)
+ {
+  puts("Read Error!");
+  return(0);
+ }
+ else
+  puts("");
+
+ SetupCartPRGMapping(z,malloced[z],t,0); 
+ return(1);
+}
+
+static int SetBoardName(int fp)
+{
+ if(!(boardname=FCEU_malloc(uchead.info+1)))
+  return(0);
+ FCEU_fread(boardname,1,uchead.info,fp);
+ boardname[uchead.info]=0;
+ printf(" Board name: %s\n",boardname);
+ sboardname=boardname;
+ if(!memcmp(boardname,"NES-",4) || !memcmp(boardname,"UNL-",4) || !memcmp(boardname,"HVC-",4) || !memcmp(boardname,"BTL-",4) || !memcmp(boardname,"BMC-",4))
+  sboardname+=4;
+ return(1);
+}
+
+static int LoadCHR(int fp)
+{
+ int z,t;
+ z=uchead.ID[3]-'0';
+ if(z<0 || z>15)
+  return(0);
+ printf(" CHR ROM %d size: %d",z,(int) uchead.info);
+ if(malloced[16+z])
+  free(malloced[16+z]);
+ t=FixRomSize(uchead.info,8192);
+ if(!(malloced[16+z]=FCEU_malloc(t)))
+  return(0);
+ memset(malloced[16+z]+uchead.info,0xFF,t-uchead.info);
+ if(FCEU_fread(malloced[16+z],1,uchead.info,fp)!=uchead.info)
+ {
+  puts("Read Error!");
+  return(0);
+ }
+ else
+  puts("");
+
+ SetupCartCHRMapping(z,malloced[16+z],t,0);
+ return(1);
+}
+
+
+#define BMCFLAG_FORCE4 1
+#define BMCFLAG_CHRROK 2       // Ok for generic UNIF code to make available
+                               // 8KB of CHR RAM if no CHR ROM is present.
+#define BMC 48
+
+BMAPPING bmap[BMC] = {
+
+/* Sachen Carts */
+ { "TC-U01-1.5M", TCU01_Init,0},
+ { "Sachen-8259B", S8259B_Init,BMCFLAG_CHRROK},
+ { "Sachen-8259A", S8259A_Init,BMCFLAG_CHRROK},
+ { "Sachen-74LS374N", S74LS374N_Init,0},
+ { "SA-016-1M", SA0161M_Init,0},
+ { "SA-72007", SA72007_Init,0},
+ { "SA-72008", SA72008_Init,0},
+ { "SA-0036", SA0036_Init,0},
+ { "SA-0037", SA0037_Init,0},
+
+ { "H2288", H2288_Init,0},
+// /* AVE carts. */
+// { "MB-91", MB91_Init,0},    // DeathBots
+// { "NINA-06", NINA06_Init,0},        // F-15 City War
+// { "NINA-03", NINA03_Init,0},        // Tiles of Fate
+// { "NINA-001", NINA001_Init,0}, // Impossible Mission 2
+
+ { "HKROM", HKROM_Init,0},
+
+ { "EWROM", EWROM_Init,0},
+ { "EKROM", EKROM_Init,0},
+ { "ELROM", ELROM_Init,0},
+ { "ETROM", ETROM_Init,0},
+
+ { "SAROM", SAROM_Init,0},
+ { "SBROM", SBROM_Init,0},
+ { "SCROM", SCROM_Init,0},
+ { "SEROM", SEROM_Init,0},
+ { "SGROM", SGROM_Init,0},
+ { "SKROM", SKROM_Init,0},
+ { "SLROM", SLROM_Init,0},
+ { "SL1ROM", SL1ROM_Init,0},
+ { "SNROM", SNROM_Init,0},
+ { "SOROM", SOROM_Init,0},
+
+ { "TGROM", TGROM_Init,0},
+ { "TR1ROM", TFROM_Init,BMCFLAG_FORCE4},
+ { "TFROM", TFROM_Init,0},
+ { "TLROM", TLROM_Init,0},
+ { "TKROM", TKROM_Init,0},
+ { "TSROM", TSROM_Init,0},
+
+ { "TLSROM", TLSROM_Init,0},
+ { "TKSROM", TKSROM_Init,0},
+ { "TQROM", TQROM_Init,0},
+ { "TVROM", TLROM_Init,BMCFLAG_FORCE4},
+
+ { "CPROM", CPROM_Init,0},
+ { "CNROM", CNROM_Init,0},
+ { "NROM", NROM256_Init,0 },
+ { "RROM", NROM128_Init,0 },
+ { "RROM-128", NROM128_Init,0 },
+ { "NROM-128", NROM128_Init,0 },
+ { "NROM-256", NROM256_Init,0 },
+ { "MHROM", MHROM_Init,0},
+ { "UNROM", UNROM_Init,0},
+ { "MARIO1-MALEE2", MALEE_Init,0},
+ { "Supervision16in1", Supervision16_Init,0},
+ { "NovelDiamond9999999in1", Novel_Init,0},
+ { "Super24in1SC03", Super24_Init,0}
+};
+
+#define BMF 7
+BFMAPPING bfunc[BMF] = {
+ { "CTRL", CTRL },
+ { "TVCI", TVCI },
+ { "BATR", EnableBattery },
+ { "MIRR", DoMirroring },
+ { "PRG",  LoadPRG },
+ { "CHR",  LoadCHR },
+ { "MAPR", SetBoardName }
+};
+
+int LoadUNIFChunks(int fp)
+{
+   int x;
+   int t;
+   for(;;)
+   {
+    t=FCEU_fread(&uchead,1,4,fp);
+    if(t<4) 
+    {
+     if(t>0)
+      return 0; 
+     return 1;
+    }
+    if(!(FCEU_read32(&uchead.info,fp))) 
+     return 0;
+    t=0;
+    for(x=0;x<BMF;x++)
+    {
+     if(memcmp(&uchead,bfunc[x].name,strlen(bfunc[x].name)))
+      continue;
+     if(!bfunc[x].init(fp))
+      return 0;
+     t=1;
+     break;     
+    }
+    if(!t)
+     if(FCEU_fseek(fp,uchead.info,SEEK_CUR))
+      return(0);
+   }
+}
+
+static int InitializeBoard(void)
+{
+   int x;
+
+   for(x=0;x<BMC;x++)
+   {
+    if(strcmp(sboardname,bmap[x].name)) continue;
+    if(!malloced[16] && (bmap[x].flags&BMCFLAG_CHRROK))
+    {
+     if((malloced[16]=UNIFchrrama=FCEU_malloc(8192)))
+     {
+      SetupCartCHRMapping(0,UNIFchrrama,8192,1);
+      AddExState(UNIFchrrama, 8192, 0,"CHRR");
+     }
+     else
+      return(-1);
+    }
+    if(bmap[x].flags&BMCFLAG_FORCE4)
+     mirrortodo=4;
+    MooMirroring();
+    bmap[x].init();
+    return(1);
+   }
+   FCEU_PrintError("Board type not supported.");
+   return(0);
+}
+
+static void UNIFGI(int h)
+{
+ switch(h)
+ {
+  case GI_RESETM2:
+               if(BoardReset) BoardReset();
+               break;
+  case GI_POWER:
+                if(BoardPower) BoardPower();
+               if(UNIFchrrama) memset(UNIFchrrama,0,8192);
+               break;
+  case GI_CLOSE:
+                if(BoardClose)
+                 BoardClose();
+                FreeUNIF();
+                break;
+ }
+}
+
+int UNIFLoad(char *name, int fp)
+{
+        FCEU_fseek(fp,0,SEEK_SET);
+        FCEU_fread(&unhead,1,4,fp);
+        if(memcmp(&unhead,"UNIF",4))
+         return 0;        
+
+       ResetCartMapping();
+
+        ResetExState();
+        ResetUNIF();
+        if(!FCEU_read32(&unhead.info,fp))
+        goto aborto;
+        if(FCEU_fseek(fp,0x20,SEEK_SET)<0)
+        goto aborto;
+        if(!LoadUNIFChunks(fp))
+        goto aborto;
+        if(!InitializeBoard())
+        goto aborto;
+
+        GameInterface=UNIFGI;
+        return 1;
+       
+       aborto:
+
+       FreeUNIF();
+       ResetUNIF();
+       return 0;
+}
+
+static FILE *fssp=0;
+
+void UNIFOpenWRAM(int t, char *ext, int override)
+{
+ if(UNIFbattery|override)
+ {
+  fssp=fopen(FCEU_MakeFName(FCEUMKF_SAV,0,(ext?ext:"sav")),(t==UOW_RD)?"rb":"wb");
+ }
+}
+
+void UNIFWriteWRAM(uint8 *p, int size)
+{
+ if(fssp)
+  fwrite(p, size, 1, fssp);
+}
+
+void UNIFReadWRAM(uint8 *p, int size)
+{
+ if(fssp)
+  fread(p, size, 1, fssp);
+}
+void UNIFCloseWRAM(void)
+{
+ if(fssp)
+  fclose(fssp);
+ fssp=0;
+}
diff --git a/unif.h b/unif.h
new file mode 100644 (file)
index 0000000..1db41dd
--- /dev/null
+++ b/unif.h
@@ -0,0 +1,94 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#ifndef UNIFPRIV
+int UNIFLoad(char *name, int fp);
+#endif
+
+void TCU01_Init(void);
+void S8259B_Init(void);
+void S8259A_Init(void);
+void S74LS374N_Init(void);
+void SA0161M_Init(void);
+
+void SA72007_Init(void);
+void SA72008_Init(void);
+void SA0036_Init(void);
+void SA0037_Init(void);
+
+void H2288_Init(void);
+
+void HKROM_Init(void);
+
+void ETROM_Init(void);
+void EKROM_Init(void);
+void ELROM_Init(void);
+void EWROM_Init(void);
+
+void SAROM_Init(void);
+void SBROM_Init(void);
+void SCROM_Init(void);
+void SEROM_Init(void);
+void SGROM_Init(void);
+void SKROM_Init(void);
+void SLROM_Init(void);
+void SL1ROM_Init(void);
+void SNROM_Init(void);
+void SOROM_Init(void);
+
+void NROM_Init(void);
+void NROM256_Init(void);
+void NROM128_Init(void);
+void MHROM_Init(void);
+void UNROM_Init(void);
+void MALEE_Init(void);
+void Supervision16_Init(void);
+void Super24_Init(void);
+void Novel_Init(void);
+void CNROM_Init(void);
+void CPROM_Init(void);
+
+void TFROM_Init(void);
+void TGROM_Init(void);
+void TKROM_Init(void);
+void TSROM_Init(void);
+void TLROM_Init(void);
+void TLSROM_Init(void);
+void TKSROM_Init(void);
+void TQROM_Init(void);
+void TQROM_Init(void);
+
+
+void UNIFOpenWRAM(int t, char *ext, int override);
+void UNIFWriteWRAM(uint8 *p, int size);
+void UNIFReadWRAM(uint8 *p, int size);
+void UNIFCloseWRAM(void);
+#define        UOW_RD  0
+#define UOW_WR 1
+
+extern void (*BoardClose)(void);
+extern void (*BoardPower)(void);
+extern void (*BoardReset)(void);
+
+#define UNIFMemBlock (GameMemBlock+32768)
+
+extern int UNIFbattery;
+extern char *UNIFchrrama;      // Meh.  So I can't stop CHR RAM 
+                               // bank switcherooing with certain boards...
diff --git a/version.h b/version.h
new file mode 100644 (file)
index 0000000..02acc81
--- /dev/null
+++ b/version.h
@@ -0,0 +1,29 @@
+#define VERSION_NUMERIC 81
+#define VERSION_STRING ".81"
+
+#if PSS_STYLE==2
+
+#define PSS "\\"
+#define PS '\\'
+
+#elif PSS_STYLE==1
+
+#define PSS "/"
+#define PS '/'
+
+#elif PSS_STYLE==3
+
+#define PSS "\\"
+#define PS '\\'
+
+#elif PSS_STYLE==4
+
+#define PSS ":"
+#define PS ':'
+
+#endif
+
+#ifdef NOSTDOUT
+#define puts(x) 
+#define printf(x,...)
+#endif
diff --git a/video.c b/video.c
new file mode 100644 (file)
index 0000000..5ab1bc9
--- /dev/null
+++ b/video.c
@@ -0,0 +1,261 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+/****************************************/
+/*             FCE Ultra               */
+/*                                     */
+/*             video.c                 */
+/*                                     */
+/*  Some generic high-level video      */
+/*  related functions.                 */
+/****************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "types.h"
+#include "video.h"
+#include "fce.h"
+#include "svga.h"
+#include "version.h"
+#include "general.h"
+#include "memory.h"
+
+uint8 *XBuf=NULL;
+
+int InitVirtualVideo(void)
+{
+ uint32 m;
+
+ if(!XBuf)             /* Some driver code may allocate XBuf externally. */
+  if(!(XBuf = (uint8*) (FCEU_malloc((256+16) * 240 + 8))))
+   return 0;
+
+ if(sizeof(uint8*)==4)
+ {
+  m=(uint32) XBuf;
+  m+=8;m&=0xFFFFFFF8;
+  (uint32)XBuf=m;
+ } 
+
+ memset(XBuf,128,272*240);
+ return 1;
+}
+
+#ifndef ZLIB
+static uint8 pcxheader[128] =
+{
+ 10,5,1,8,1,0,1,0,0,1,240,0,2,1,234,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,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,1,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+
+int SaveSnapshot(void)
+{
+ char *fn=0;
+ uint8 *tmp;
+ int x,u,y;
+ FILE *pp=NULL;
+
+ for(u=0;u<999;u++)
+ {
+  pp=fopen((fn=FCEU_MakeFName(FCEUMKF_SNAP,u,"pcx")),"rb");
+  if(pp==NULL) break;
+  fclose(pp);
+ }
+
+ if(!(pp=fopen(fn,"wb")))
+  return 0;
+
+ {
+  int totallines=FSettings.LastSLine-FSettings.FirstSLine+1;
+
+  tmp=XBuf+8+FSettings.FirstSLine*272;
+
+  pcxheader[10]=totallines;
+  fwrite(pcxheader,1,128,pp);
+  for(y=0;y<totallines;y++)
+  {
+   for(x=0;x<256;x++)
+   {
+    if(*tmp>=0xc0) fputc(0xC1,pp);
+     fputc(*tmp,pp);
+    tmp++;
+   }
+   tmp+=16;
+  }
+ }
+
+ fputc(0xC,pp);
+ for(x=0;x<256;x++)
+ {
+  uint8 r,g,b;
+
+  FCEUD_GetPalette(x,&r,&g,&b);
+  fputc(r,pp);
+  fputc(g,pp);
+  fputc(b,pp);
+ }
+ fclose(pp);
+ return u+1;
+}
+
+#else
+
+#include <zlib.h>
+#include "crc32.h"
+
+static int WritePNGChunk(FILE *fp, uint32 size, char *type, uint8 *data)
+{
+ uint32 crc;
+
+ uint8 tempo[4];
+
+ tempo[0]=size>>24;
+ tempo[1]=size>>16;
+ tempo[2]=size>>8;
+ tempo[3]=size;
+
+ if(fwrite(tempo,4,1,fp)!=1)
+  return 0;
+ if(fwrite(type,4,1,fp)!=1)
+  return 0;
+
+ if(size)
+  if(fwrite(data,1,size,fp)!=size)
+   return 0;
+
+ crc=CalcCRC32(0,type,4);
+ if(size)
+  crc=CalcCRC32(crc,data,size);
+
+ tempo[0]=crc>>24;
+ tempo[1]=crc>>16;
+ tempo[2]=crc>>8;
+ tempo[3]=crc;
+
+ if(fwrite(tempo,4,1,fp)!=1)
+  return 0;
+ return 1;
+}
+
+int SaveSnapshot(void)
+{
+ char *fn=0;
+ int totallines=FSettings.LastSLine-FSettings.FirstSLine+1;
+ int x,u,y;
+ FILE *pp=NULL;
+ uint8 *compmem=NULL;
+ uint32 compmemsize=totallines*263+12;
+
+ if(!(compmem=FCEU_malloc(compmemsize)))
+  return 0;
+
+ for(u=0;u<999;u++)
+ {
+  pp=fopen((fn=FCEU_MakeFName(FCEUMKF_SNAP,u,"png")),"rb");
+  if(pp==NULL) break;
+  fclose(pp);
+ }
+
+ if(!(pp=fopen(fn,"wb")))
+  return 0;
+ {
+  static uint8 header[8]={137,80,78,71,13,10,26,10};
+  if(fwrite(header,8,1,pp)!=1)
+   goto PNGerr;
+ }
+
+ {
+  uint8 chunko[13];
+
+  chunko[0]=chunko[1]=chunko[3]=0;
+  chunko[2]=0x1;                       // Width of 256
+
+  chunko[4]=chunko[5]=chunko[6]=0;
+  chunko[7]=totallines;                        // Height
+
+  chunko[8]=8;                         // bit depth
+  chunko[9]=3;                         // Color type; indexed 8-bit
+  chunko[10]=0;                                // compression: deflate
+  chunko[11]=0;                                // Basic adapative filter set(though none are used).
+  chunko[12]=0;                                // No interlace.
+
+  if(!WritePNGChunk(pp,13,"IHDR",chunko))
+   goto PNGerr;
+ }
+
+ {
+  char pdata[256*3];
+  for(x=0;x<256;x++)
+   FCEUD_GetPalette(x,pdata+x*3,pdata+x*3+1,pdata+x*3+2);
+  if(!WritePNGChunk(pp,256*3,"PLTE",pdata))
+   goto PNGerr;
+ }
+
+ {
+  uint8 *tmp=XBuf+FSettings.FirstSLine*272+8;
+  uint8 *dest,*mal,*mork;
+
+  /* If memory couldn't be allocated, just use XBuf(screen contents
+     will be corrupted for one frame, though.
+  */
+  if(!(mal=mork=dest=malloc((totallines<<8)+totallines)))
+   mork=dest=XBuf;
+
+  for(y=0;y<totallines;y++)
+  {
+   *dest=0;                    // No filter.
+   dest++;
+   for(x=256;x;x--,tmp++,dest++)
+    *dest=*tmp;        
+   tmp+=16;
+  }
+
+  if(compress(compmem,&compmemsize,mork,(totallines<<8)+totallines)!=Z_OK)
+  {
+   if(mal) free(mal);
+   goto PNGerr;
+  }
+  if(mal) free(mal);
+  if(!WritePNGChunk(pp,compmemsize,"IDAT",compmem))
+   goto PNGerr;
+ }
+ if(!WritePNGChunk(pp,0,"IEND",0))
+  goto PNGerr;
+
+ free(compmem);
+ fclose(pp);
+
+ return u+1;
+
+
+ PNGerr:
+ if(compmem)
+  free(compmem);
+ if(pp)
+  fclose(pp);
+ return(0);
+}
+
+#endif
diff --git a/video.h b/video.h
new file mode 100644 (file)
index 0000000..751fb3a
--- /dev/null
+++ b/video.h
@@ -0,0 +1,3 @@
+int InitVirtualVideo(void);
+int SaveSnapshot(void);
+extern uint8 *XBuf;
diff --git a/x6502.c b/x6502.c
new file mode 100644 (file)
index 0000000..daba073
--- /dev/null
+++ b/x6502.c
@@ -0,0 +1,484 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+#include <string.h>
+
+#include "types.h"
+#include "x6502.h"
+#include "fce.h"
+#include "sound.h"
+
+X6502 X;
+uint32 timestamp;
+void FP_FASTAPASS(1) (*MapIRQHook)(int a);
+
+#define _PC              X.PC
+#define _A               X.A
+#define _X               X.X
+#define _Y               X.Y
+#define _S               X.S
+#define _P               X.P
+#define _PI              X.mooPI
+#define _PZ              X.PZ
+#define _DB              X.DB
+#define _count           X.count
+#define _tcount          X.tcount
+#define _IRQlow          X.IRQlow
+#define _jammed          X.jammed
+
+
+static INLINE uint8 RdMem(unsigned int A)
+{
+ return((_DB=ARead[A](A)));
+}
+
+static INLINE void WrMem(unsigned int A, uint8 V)
+{
+ BWrite[A](A,V);
+}
+
+static INLINE uint8 RdRAM(unsigned int A)
+{
+ return((_DB=RAM[A]));
+}
+
+static INLINE void WrRAM(unsigned int A, uint8 V)
+{
+ RAM[A]=V;
+}
+
+static INLINE void ADDCYC(int x)
+{
+ _tcount+=x;
+ _count-=x*48;
+ timestamp+=x;
+}
+
+void FASTAPASS(1) X6502_AddCycles(int x)
+{
+ ADDCYC(x);
+}
+
+static INLINE void PUSH(uint8 V)
+{
+ WrRAM(0x100+_S,V);
+ _S--;
+}
+
+static INLINE uint8 POP(void)
+{
+ _S++;
+ return(RdRAM(0x100+_S));
+}
+
+static uint8 ZNTable[256] = {
+        Z_FLAG,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+       N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
+       N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
+        N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
+        N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
+        N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
+        N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
+        N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,
+        N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG,N_FLAG
+};
+/* Some of these operations will only make sense if you know what the flag
+   constants are. */
+#define X_ZN(zort)         _P&=~(Z_FLAG|N_FLAG);_P|=ZNTable[zort]
+#define X_ZNT(zort)    _P|=ZNTable[zort]
+
+/* Care must be taken if you want to turn this into a macro.  Use { and }. */
+#define JR();  \
+{              \
+ uint32 tmp;   \
+ int8 disp;    \
+ disp=RdMem(_PC++);    \
+ ADDCYC(1);    \
+ tmp=_PC;      \
+ _PC+=disp;    \
+ if((tmp^_PC)&0x100)   \
+  ADDCYC(1);   \
+}
+
+#define LDA       _A=x;X_ZN(_A)
+#define LDX       _X=x;X_ZN(_X)
+#define LDY        _Y=x;X_ZN(_Y)
+
+/*  All of the freaky arithmetic operations. */
+#define AND        _A&=x;X_ZN(_A)
+#define BIT        _P&=~(Z_FLAG|V_FLAG|N_FLAG);_P|=ZNTable[x&_A]&Z_FLAG;_P|=x&(V_FLAG|N_FLAG)
+#define EOR        _A^=x;X_ZN(_A)
+#define ORA        _A|=x;X_ZN(_A)
+
+#define ADC  { \
+             uint32 l=_A+x+(_P&1);     \
+             _P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG);       \
+             _P|=((((_A^x)&0x80)^0x80) & ((_A^l)&0x80))>>1;    \
+             _P|=(l>>8)&C_FLAG;        \
+             _A=l;     \
+             X_ZNT(_A);        \
+            }
+#define SBC  { \
+             uint32 l=_A-x-((_P&1)^1); \
+             _P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG);       \
+             _P|=((_A^l)&(_A^x)&0x80)>>1;      \
+             _P|=((l>>8)&C_FLAG)^C_FLAG;       \
+             _A=l;     \
+             X_ZNT(_A);        \
+            }
+
+#define CMPL(a1,a2) {  \
+                    uint32 t=a1-a2;    \
+                    X_ZN(t&0xFF);      \
+                    _P&=~C_FLAG;       \
+                    _P|=((t>>8)&C_FLAG)^C_FLAG;        \
+                   }
+
+/* Special undocumented operation.  Very similar to CMP. */
+#define AXS        {   \
+                     uint32 t=(_A&_X)-x;    \
+                     X_ZN(t&0xFF);      \
+                     _P&=~C_FLAG;       \
+                     _P|=((t>>8)&C_FLAG)^C_FLAG;        \
+                    _X=t;      \
+                    }
+
+#define CMP            CMPL(_A,x)
+#define CPX            CMPL(_X,x)
+#define CPY            CMPL(_Y,x)
+
+/* The following operations modify the byte being worked on. */
+#define DEC            x--;X_ZN(x)
+#define INC            x++;X_ZN(x)
+
+#define ASL        _P&=~C_FLAG;_P|=x>>7;x<<=1;X_ZN(x)
+#define LSR    _P&=~(C_FLAG|N_FLAG|Z_FLAG);_P|=x&1;x>>=1;X_ZNT(x)
+
+/* For undocumented instructions, maybe for other things later... */
+#define LSRA   _P&=~(C_FLAG|N_FLAG|Z_FLAG);_P|=_A&1;_A>>=1;X_ZNT(_A)
+
+#define ROL    {       \
+                uint8 l=x>>7;  \
+                x<<=1; \
+                x|=_P&C_FLAG;  \
+                _P&=~(Z_FLAG|N_FLAG|C_FLAG);   \
+                _P|=l; \
+                X_ZNT(x);      \
+               }
+#define ROR    {       \
+                uint8 l=x&1;   \
+                x>>=1; \
+                x|=(_P&C_FLAG)<<7;     \
+                _P&=~(Z_FLAG|N_FLAG|C_FLAG);   \
+                _P|=l; \
+                X_ZNT(x);      \
+               }
+                
+/* Icky icky thing for some undocumented instructions.  Can easily be
+   broken if names of local variables are changed.
+*/
+
+/* Absolute */
+#define GetAB(target)  \
+{      \
+ target=RdMem(_PC++);  \
+ target|=RdMem(_PC++)<<8;      \
+}
+
+/* Absolute Indexed(for reads) */
+#define GetABIRD(target, i)    \
+{      \
+ unsigned int tmp;     \
+ GetAB(tmp);   \
+ target=tmp;   \
+ target+=i;    \
+ if((target^tmp)&0x100)        \
+ {     \
+  target&=0xFFFF;      \
+  RdMem(target^0x100); \
+  ADDCYC(1);   \
+ }     \
+}
+
+/* Absolute Indexed(for writes and rmws) */
+#define GetABIWR(target, i)    \
+{      \
+ unsigned int rt;      \
+ GetAB(rt);    \
+ target=rt;    \
+ target+=i;    \
+ target&=0xFFFF;       \
+ RdMem((target&0x00FF)|(rt&0xFF00));   \
+}
+
+/* Zero Page */
+#define GetZP(target)  \
+{      \
+ target=RdMem(_PC++);  \
+}
+
+/* Zero Page Indexed */
+#define GetZPI(target,i)       \
+{      \
+ target=i+RdMem(_PC++);        \
+}
+
+/* Indexed Indirect */
+#define GetIX(target)  \
+{      \
+ uint8 tmp;    \
+ tmp=RdMem(_PC++);     \
+ tmp+=_X;      \
+ target=RdRAM(tmp++);  \
+ target|=RdRAM(tmp)<<8;        \
+}
+
+/* Indirect Indexed(for reads) */
+#define GetIYRD(target)        \
+{      \
+ unsigned int rt;      \
+ uint8 tmp;    \
+ tmp=RdMem(_PC++);     \
+ rt=RdRAM(tmp++);      \
+ rt|=RdRAM(tmp)<<8;    \
+ target=rt;    \
+ target+=_Y;   \
+ if((target^rt)&0x100) \
+ {     \
+  target&=0xFFFF;      \
+  RdMem(target^0x100); \
+  ADDCYC(1);   \
+ }     \
+}
+
+/* Indirect Indexed(for writes and rmws) */
+#define GetIYWR(target)        \
+{      \
+ unsigned int rt;      \
+ uint8 tmp;    \
+ tmp=RdMem(_PC++);     \
+ rt=RdRAM(tmp++);      \
+ rt|=RdRAM(tmp)<<8;    \
+ target=rt;    \
+ target+=_Y;   \
+ RdMem((target&0x00FF)|(rt&0xFF00));   \
+}
+
+/* Now come the macros to wrap up all of the above stuff addressing mode functions
+   and operation macros.  Note that operation macros will always operate(redundant
+   redundant) on the variable "x".
+*/
+
+#define RMW_A(op) {uint8 x=_A; op; _A=x; break; } /* Meh... */
+#define RMW_AB(op) {unsigned int A; uint8 x; GetAB(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
+#define RMW_ABI(reg,op) {unsigned int A; uint8 x; GetABIWR(A,reg); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
+#define RMW_ABX(op)    RMW_ABI(_X,op)
+#define RMW_ABY(op)    RMW_ABI(_Y,op)
+#define RMW_IX(op)  {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
+#define RMW_IY(op)  {unsigned int A; uint8 x; GetIYWR(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; }
+#define RMW_ZP(op)  {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; WrRAM(A,x); break; }
+#define RMW_ZPX(op) {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; WrRAM(A,x); break;}
+
+#define LD_IM(op)      {uint8 x; x=RdMem(_PC++); op; break;}
+#define LD_ZP(op)      {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; break;}
+#define LD_ZPX(op)  {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; break;}
+#define LD_ZPY(op)  {uint8 A; uint8 x; GetZPI(A,_Y); x=RdRAM(A); op; break;}
+#define LD_AB(op)      {unsigned int A; uint8 x; GetAB(A); x=RdMem(A); op; break; }
+#define LD_ABI(reg,op)  {unsigned int A; uint8 x; GetABIRD(A,reg); x=RdMem(A); op; break;}
+#define LD_ABX(op)     LD_ABI(_X,op)
+#define LD_ABY(op)     LD_ABI(_Y,op)
+#define LD_IX(op)      {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); op; break;}
+#define LD_IY(op)      {unsigned int A; uint8 x; GetIYRD(A); x=RdMem(A); op; break;}
+
+#define ST_ZP(r)       {uint8 A; GetZP(A); WrRAM(A,r); break;}
+#define ST_ZPX(r)      {uint8 A; GetZPI(A,_X); WrRAM(A,r); break;}
+#define ST_ZPY(r)      {uint8 A; GetZPI(A,_Y); WrRAM(A,r); break;}
+#define ST_AB(r)       {unsigned int A; GetAB(A); WrMem(A,r); break;}
+#define ST_ABI(reg,r)  {unsigned int A; GetABIWR(A,reg); WrMem(A,r); break; }
+#define ST_ABX(r)      ST_ABI(_X,r)
+#define ST_ABY(r)      ST_ABI(_Y,r)
+#define ST_IX(r)       {unsigned int A; GetIX(A); WrMem(A,r); break; }
+#define ST_IY(r)       {unsigned int A; GetIYWR(A); WrMem(A,r); break; }
+
+static uint8 CycTable[256] =
+{                             
+/*0x00*/ 7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6,
+/*0x10*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
+/*0x20*/ 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6,
+/*0x30*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
+/*0x40*/ 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6,
+/*0x50*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
+/*0x60*/ 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6,
+/*0x70*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
+/*0x80*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
+/*0x90*/ 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5,
+/*0xA0*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
+/*0xB0*/ 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4,
+/*0xC0*/ 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
+/*0xD0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
+/*0xE0*/ 2,6,3,8,3,3,5,5,2,2,2,2,4,4,6,6,
+/*0xF0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
+};
+
+void FASTAPASS(1) X6502_IRQBegin(int w)
+{
+ _IRQlow|=w;
+}
+
+void FASTAPASS(1) X6502_IRQEnd(int w)
+{
+ _IRQlow&=~w;
+}
+
+void TriggerIRQ(void)  /* This function should probably be phased out. */
+{
+ _IRQlow|=FCEU_IQTEMP;
+}
+
+void TriggerNMINSF(void)
+{
+ ADDCYC(7);
+ PUSH(_PC>>8);
+ PUSH(_PC);
+ PUSH((_P&~B_FLAG)|(U_FLAG));
+ _PC=0x3800;
+}
+
+void TriggerNMI(void)
+{
+ _IRQlow|=FCEU_IQNMI;
+}
+
+static void TriggerNMIReal(void)
+{
+ if(!_jammed)
+ {
+  ADDCYC(7);
+  PUSH(_PC>>8);
+  PUSH(_PC);
+  PUSH((_P&~B_FLAG)|(U_FLAG));
+  _PC=RdMem(0xFFFA);
+  _PC|=RdMem(0xFFFB)<<8;
+ }
+}
+
+void TriggerIRQReal(void)
+{
+ if(!(_PI&I_FLAG) && !_jammed)
+ {
+  ADDCYC(7);
+  PUSH(_PC>>8);
+  PUSH(_PC);
+  PUSH((_P&~B_FLAG)|(U_FLAG));
+  _P|=I_FLAG;
+  _PC=RdMem(0xFFFE);
+  _PC|=RdMem(0xFFFF)<<8;
+ }
+}
+
+void X6502_Reset(void)
+{
+  _PC=RdMem(0xFFFC);
+  _PC|=RdMem(0xFFFD)<<8;
+  if(FCEUGameInfo.type==GIT_NSF) _PC=0x3830;
+  _jammed=0;
+  _PI=_P=I_FLAG;
+}
+
+void X6502_Power(void)
+{
+ memset((void *)&X,0,sizeof(X)); 
+ timestamp=0;
+ X6502_Reset();
+}
+
+void X6502_Run(int32 cycles)
+{
+       if(PAL)
+        cycles*=15;          // 15*4=60
+       else
+        cycles*=16;          // 16*4=64
+
+       _count+=cycles;
+
+       while(_count>0)
+       {
+        int32 temp;
+        uint8 b1;
+
+        if(_IRQlow)
+        {
+         if(_IRQlow&FCEU_IQNMI)
+          TriggerNMIReal();
+         else
+          TriggerIRQReal();
+
+         _IRQlow&=~(FCEU_IQTEMP|FCEU_IQNMI);
+         if(_count<=0) {_PI=_P;return;} /* Should increase accuracy without a */
+                                          /* major speed hit. */
+        }
+        _PI=_P;
+        b1=RdMem(_PC);
+        ADDCYC(CycTable[b1]);
+        temp=_tcount;
+        _tcount=0;
+        if(MapIRQHook) MapIRQHook(temp);
+
+        temp*=48;
+
+        fhcnt-=temp;
+        if(fhcnt<=0)
+        {
+         FrameSoundUpdate();
+         fhcnt+=fhinc;
+        }
+
+       
+        if(PCMIRQCount>0)
+        {
+         PCMIRQCount-=temp;
+         if(PCMIRQCount<=0)
+         {
+          vdis=1;
+          if((PSG[0x10]&0x80) && !(PSG[0x10]&0x40))
+          {
+           extern uint8 SIRQStat;
+           SIRQStat|=0x80;
+           X6502_IRQBegin(FCEU_IQDPCM);
+          }
+         }
+        }
+         //printf("$%04x:$%02x\n",_PC,b1);
+        //_PC++;
+        //printf("$%02x\n",b1);
+        _PC++;
+         switch(b1)
+         {
+          #include "ops.h"
+         } 
+       }
+}
diff --git a/x6502.h b/x6502.h
new file mode 100644 (file)
index 0000000..414533b
--- /dev/null
+++ b/x6502.h
@@ -0,0 +1,66 @@
+/* FCE Ultra - NES/Famicom Emulator
+ *
+ * Copyright notice for this file:
+ *  Copyright (C) 2002 Ben Parnell
+ *
+ * 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-1307  USA
+ */
+
+typedef struct {
+        int32 count;            /* Cycle counter           */
+        int32 tcount;           /* Temporary cycle counter */
+        uint16 PC;             /* I'll change this to uint32 later... */
+                               /* I'll need to AND PC after increments to 0xFFFF */
+                               /* when I do, though.  Perhaps an IPC() macro? */
+        uint8 A,X,Y,S,P,mooPI,PZ;
+        uint8 DB;               /* Data bus "cache" for reads from certain areas */
+       uint8 IRQlow;           /* Simulated IRQ pin held low(or is it high?). */
+       uint8 jammed;
+} X6502;
+
+extern X6502 X;
+
+#define N_FLAG  0x80
+#define V_FLAG  0x40
+#define U_FLAG  0x20
+#define B_FLAG  0x10
+#define D_FLAG  0x08
+#define I_FLAG  0x04
+#define Z_FLAG  0x02
+#define C_FLAG  0x01
+
+extern uint32 timestamp;
+extern void FP_FASTAPASS(1) (*MapIRQHook)(int a);
+
+#define NTSC_CPU 1789772.7272727272727272
+#define PAL_CPU  1662607.125
+
+#define FCEU_IQEXT      0x01
+#define FCEU_IQNMI     0x08
+#define FCEU_IQDPCM     0x10
+#define FCEU_IQFCOUNT   0x20
+#define FCEU_IQTEMP     0x80
+
+void X6502_Reset(void);
+void X6502_Power(void);
+void X6502_Run(int32 cycles);
+
+void TriggerIRQ(void);
+void TriggerNMI(void);
+void TriggerNMINSF(void);
+
+void FASTAPASS(1) X6502_AddCycles(int x);
+void FASTAPASS(1) X6502_IRQBegin(int w);
+void FASTAPASS(1) X6502_IRQEnd(int w);
diff --git a/zlib/ChangeLog b/zlib/ChangeLog
new file mode 100644 (file)
index 0000000..58d58af
--- /dev/null
@@ -0,0 +1,481 @@
+
+               ChangeLog file for zlib
+
+Changes in 1.1.4 (11 March 2002)
+- ZFREE was repeated on same allocation on some error conditions.
+  This creates a security problem described in
+  http://www.zlib.org/advisory-2002-03-11.txt
+- Returned incorrect error (Z_MEM_ERROR) on some invalid data
+- Avoid accesses before window for invalid distances with inflate window
+  less than 32K.
+- force windowBits > 8 to avoid a bug in the encoder for a window size
+  of 256 bytes. (A complete fix will be available in 1.1.5).
+       
+Changes in 1.1.3 (9 July 1998)
+- fix "an inflate input buffer bug that shows up on rare but persistent
+  occasions" (Mark)
+- fix gzread and gztell for concatenated .gz files (Didier Le Botlan)
+- fix gzseek(..., SEEK_SET) in write mode
+- fix crc check after a gzeek (Frank Faubert)
+- fix miniunzip when the last entry in a zip file is itself a zip file
+  (J Lillge)
+- add contrib/asm586 and contrib/asm686 (Brian Raiter)
+  See http://www.muppetlabs.com/~breadbox/software/assembly.html
+- add support for Delphi 3 in contrib/delphi (Bob Dellaca)
+- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti)
+- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren)
+- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks)
+- added a FAQ file
+
+- Support gzdopen on Mac with Metrowerks (Jason Linhart)
+- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart)
+- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young)
+- avoid some warnings with Borland C (Tom Tanner)
+- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant)
+- emulate utime() for WIN32 in contrib/untgz  (Gilles Vollant)
+- allow several arguments to configure (Tim Mooney, Frodo Looijaard)
+- use libdir and includedir in Makefile.in (Tim Mooney)
+- support shared libraries on OSF1 V4 (Tim Mooney)
+- remove so_locations in "make clean"  (Tim Mooney)
+- fix maketree.c compilation error (Glenn, Mark)
+- Python interface to zlib now in Python 1.5 (Jeremy Hylton)
+- new Makefile.riscos (Rich Walker)
+- initialize static descriptors in trees.c for embedded targets (Nick Smith)
+- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith)
+- add the OS/2 files in Makefile.in too (Andrew Zabolotny)
+- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane)
+- fix maketree.c to allow clean compilation of inffixed.h (Mark)
+- fix parameter check in deflateCopy (Gunther Nikl)
+- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler)
+- Many portability patches by Christian Spieler:
+  . zutil.c, zutil.h: added "const" for zmem*
+  . Make_vms.com: fixed some typos
+  . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists
+  . msdos/Makefile.msc: remove "default rtl link library" info from obj files
+  . msdos/Makefile.*: use model-dependent name for the built zlib library
+  . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc:
+     new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT)
+- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane)
+- replace __far with _far for better portability (Christian Spieler, Tom Lane)
+- fix test for errno.h in configure (Tim Newsham)
+
+Changes in 1.1.2 (19 March 98)
+- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant)
+  See http://www.winimage.com/zLibDll/unzip.html
+- preinitialize the inflate tables for fixed codes, to make the code
+  completely thread safe (Mark)
+- some simplifications and slight speed-up to the inflate code (Mark)
+- fix gzeof on non-compressed files (Allan Schrum)
+- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs)
+- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn)
+- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny)
+- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori)
+- do not wrap extern "C" around system includes (Tom Lane)
+- mention zlib binding for TCL in README (Andreas Kupries)
+- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert)
+- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson)
+- allow "configure --prefix $HOME" (Tim Mooney)
+- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson)
+- move Makefile.sas to amiga/Makefile.sas
+
+Changes in 1.1.1 (27 Feb 98)
+- fix macros _tr_tally_* in deflate.h for debug mode  (Glenn Randers-Pehrson)
+- remove block truncation heuristic which had very marginal effect for zlib
+  (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the
+  compression ratio on some files. This also allows inlining _tr_tally for
+  matches in deflate_slow.
+- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier)
+
+Changes in 1.1.0 (24 Feb 98)
+- do not return STREAM_END prematurely in inflate (John Bowler)
+- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler)
+- compile with -DFASTEST to get compression code optimized for speed only
+- in minigzip, try mmap'ing the input file first (Miguel Albrecht)
+- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain
+  on Sun but significant on HP)
+
+- add a pointer to experimental unzip library in README (Gilles Vollant)
+- initialize variable gcc in configure (Chris Herborth)
+
+Changes in 1.0.9 (17 Feb 1998)
+- added gzputs and gzgets functions
+- do not clear eof flag in gzseek (Mark Diekhans)
+- fix gzseek for files in transparent mode (Mark Diekhans)
+- do not assume that vsprintf returns the number of bytes written (Jens Krinke)
+- replace EXPORT with ZEXPORT to avoid conflict with other programs
+- added compress2 in zconf.h, zlib.def, zlib.dnt
+- new asm code from Gilles Vollant in contrib/asm386
+- simplify the inflate code (Mark):
+ . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new()
+ . ZALLOC the length list in inflate_trees_fixed() instead of using stack
+ . ZALLOC the value area for huft_build() instead of using stack
+ . Simplify Z_FINISH check in inflate()
+
+- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8
+- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi)
+- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with
+  the declaration of FAR (Gilles VOllant)
+- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann)
+- read_buf buf parameter of type Bytef* instead of charf*
+- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout)
+- do not redeclare unlink in minigzip.c for WIN32 (John Bowler)
+- fix check for presence of directories in "make install" (Ian Willis)
+
+Changes in 1.0.8 (27 Jan 1998)
+- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant)
+- fix gzgetc and gzputc for big endian systems (Markus Oberhumer)
+- added compress2() to allow setting the compression level
+- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong)
+- use constant arrays for the static trees in trees.c instead of computing
+  them at run time (thanks to Ken Raeburn for this suggestion). To create
+  trees.h, compile with GEN_TREES_H and run "make test".
+- check return code of example in "make test" and display result
+- pass minigzip command line options to file_compress
+- simplifying code of inflateSync to avoid gcc 2.8 bug
+
+- support CC="gcc -Wall" in configure -s (QingLong)
+- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn)
+- fix test for shared library support to avoid compiler warnings
+- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant)
+- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit)
+- do not use fdopen for Metrowerks on Mac (Brad Pettit))
+- add checks for gzputc and gzputc in example.c
+- avoid warnings in gzio.c and deflate.c (Andreas Kleinert)
+- use const for the CRC table (Ken Raeburn)
+- fixed "make uninstall" for shared libraries
+- use Tracev instead of Trace in infblock.c
+- in example.c use correct compressed length for test_sync
+- suppress +vnocompatwarnings in configure for HPUX (not always supported)
+
+Changes in 1.0.7 (20 Jan 1998)
+- fix gzseek which was broken in write mode
+- return error for gzseek to negative absolute position
+- fix configure for Linux (Chun-Chung Chen)
+- increase stack space for MSC (Tim Wegner)
+- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant)
+- define EXPORTVA for gzprintf (Gilles Vollant)
+- added man page zlib.3 (Rick Rodgers)
+- for contrib/untgz, fix makedir() and improve Makefile
+
+- check gzseek in write mode in example.c
+- allocate extra buffer for seeks only if gzseek is actually called
+- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant)
+- add inflateSyncPoint in zconf.h
+- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def
+
+Changes in 1.0.6 (19 Jan 1998)
+- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and
+  gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code)
+- Fix a deflate bug occuring only with compression level 0 (thanks to
+  Andy Buckler for finding this one).
+- In minigzip, pass transparently also the first byte for .Z files.
+- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress()
+- check Z_FINISH in inflate (thanks to Marc Schluper)
+- Implement deflateCopy (thanks to Adam Costello)
+- make static libraries by default in configure, add --shared option.
+- move MSDOS or Windows specific files to directory msdos
+- suppress the notion of partial flush to simplify the interface
+  (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4)
+- suppress history buffer provided by application to simplify the interface
+  (this feature was not implemented anyway in 1.0.4)
+- next_in and avail_in must be initialized before calling inflateInit or
+  inflateInit2
+- add EXPORT in all exported functions (for Windows DLL)
+- added Makefile.nt (thanks to Stephen Williams)
+- added the unsupported "contrib" directory:
+   contrib/asm386/ by Gilles Vollant <info@winimage.com>
+       386 asm code replacing longest_match().
+   contrib/iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
+        A C++ I/O streams interface to the zlib gz* functions
+   contrib/iostream2/  by Tyge Løvset <Tyge.Lovset@cmr.no>
+       Another C++ I/O streams interface
+   contrib/untgz/  by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
+       A very simple tar.gz file extractor using zlib
+   contrib/visual-basic.txt by Carlos Rios <c_rios@sonda.cl>
+        How to use compress(), uncompress() and the gz* functions from VB.
+- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression
+  level) in minigzip (thanks to Tom Lane)
+
+- use const for rommable constants in deflate
+- added test for gzseek and gztell in example.c
+- add undocumented function inflateSyncPoint() (hack for Paul Mackerras)
+- add undocumented function zError to convert error code to string
+  (for Tim Smithers)
+- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code.
+- Use default memcpy for Symantec MSDOS compiler.
+- Add EXPORT keyword for check_func (needed for Windows DLL)
+- add current directory to LD_LIBRARY_PATH for "make test"
+- create also a link for libz.so.1
+- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura)
+- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX)
+- added -soname for Linux in configure (Chun-Chung Chen,
+- assign numbers to the exported functions in zlib.def (for Windows DLL)
+- add advice in zlib.h for best usage of deflateSetDictionary
+- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn)
+- allow compilation with ANSI keywords only enabled for TurboC in large model
+- avoid "versionString"[0] (Borland bug)
+- add NEED_DUMMY_RETURN for Borland
+- use variable z_verbose for tracing in debug mode (L. Peter Deutsch).
+- allow compilation with CC
+- defined STDC for OS/2 (David Charlap)        
+- limit external names to 8 chars for MVS (Thomas Lund)
+- in minigzip.c, use static buffers only for 16-bit systems
+- fix suffix check for "minigzip -d foo.gz"
+- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee)
+- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau)
+- added makelcc.bat for lcc-win32 (Tom St Denis)
+- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe)
+- Avoid expanded $Id: ChangeLog,v 1.2 2002/03/13 17:45:55 xodnizel Exp $. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion.
+- check for unistd.h in configure (for off_t)
+- remove useless check parameter in inflate_blocks_free
+- avoid useless assignment of s->check to itself in inflate_blocks_new
+- do not flush twice in gzclose (thanks to Ken Raeburn)
+- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h
+- use NO_ERRNO_H instead of enumeration of operating systems with errno.h
+- work around buggy fclose on pipes for HP/UX
+- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson)
+- fix configure if CC is already equal to gcc
+
+Changes in 1.0.5 (3 Jan 98)
+- Fix inflate to terminate gracefully when fed corrupted or invalid data
+- Use const for rommable constants in inflate
+- Eliminate memory leaks on error conditions in inflate
+- Removed some vestigial code in inflate
+- Update web address in README
+  
+Changes in 1.0.4 (24 Jul 96)
+- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF
+  bit, so the decompressor could decompress all the correct data but went
+  on to attempt decompressing extra garbage data. This affected minigzip too.
+- zlibVersion and gzerror return const char* (needed for DLL)
+- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno)
+- use z_error only for DEBUG (avoid problem with DLLs)
+
+Changes in 1.0.3 (2 Jul 96)
+- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS
+  small and medium models; this makes the library incompatible with previous
+  versions for these models. (No effect in large model or on other systems.)
+- return OK instead of BUF_ERROR if previous deflate call returned with
+  avail_out as zero but there is nothing to do
+- added memcmp for non STDC compilers
+- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly)
+- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO)
+- better check for 16-bit mode MSC (avoids problem with Symantec)
+
+Changes in 1.0.2 (23 May 96)
+- added Windows DLL support
+- added a function zlibVersion (for the DLL support)
+- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model)
+- Bytef is define's instead of typedef'd only for Borland C
+- avoid reading uninitialized memory in example.c
+- mention in README that the zlib format is now RFC1950
+- updated Makefile.dj2
+- added algorithm.doc
+
+Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion]
+- fix array overlay in deflate.c which sometimes caused bad compressed data
+- fix inflate bug with empty stored block
+- fix MSDOS medium model which was broken in 0.99
+- fix deflateParams() which could generated bad compressed data.
+- Bytef is define'd instead of typedef'ed (work around Borland bug)
+- added an INDEX file
+- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32),
+  Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas)
+- speed up adler32 for modern machines without auto-increment
+- added -ansi for IRIX in configure
+- static_init_done in trees.c is an int
+- define unlink as delete for VMS
+- fix configure for QNX
+- add configure branch for SCO and HPUX
+- avoid many warnings (unused variables, dead assignments, etc...)
+- no fdopen for BeOS
+- fix the Watcom fix for 32 bit mode (define FAR as empty)
+- removed redefinition of Byte for MKWERKS
+- work around an MWKERKS bug (incorrect merge of all .h files)
+
+Changes in 0.99 (27 Jan 96)
+- allow preset dictionary shared between compressor and decompressor
+- allow compression level 0 (no compression)
+- add deflateParams in zlib.h: allow dynamic change of compression level
+  and compression strategy.
+- test large buffers and deflateParams in example.c
+- add optional "configure" to build zlib as a shared library
+- suppress Makefile.qnx, use configure instead
+- fixed deflate for 64-bit systems (detected on Cray)
+- fixed inflate_blocks for 64-bit systems (detected on Alpha)
+- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2)
+- always return Z_BUF_ERROR when deflate() has nothing to do
+- deflateInit and inflateInit are now macros to allow version checking
+- prefix all global functions and types with z_ with -DZ_PREFIX
+- make falloc completely reentrant (inftrees.c)
+- fixed very unlikely race condition in ct_static_init
+- free in reverse order of allocation to help memory manager
+- use zlib-1.0/* instead of zlib/* inside the tar.gz
+- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith
+  -Wconversion -Wstrict-prototypes -Wmissing-prototypes"
+- allow gzread on concatenated .gz files
+- deflateEnd now returns Z_DATA_ERROR if it was premature
+- deflate is finally (?) fully deterministic (no matches beyond end of input)
+- Document Z_SYNC_FLUSH
+- add uninstall in Makefile
+- Check for __cpluplus in zlib.h
+- Better test in ct_align for partial flush
+- avoid harmless warnings for Borland C++
+- initialize hash_head in deflate.c
+- avoid warning on fdopen (gzio.c) for HP cc -Aa
+- include stdlib.h for STDC compilers
+- include errno.h for Cray
+- ignore error if ranlib doesn't exist
+- call ranlib twice for NeXTSTEP
+- use exec_prefix instead of prefix for libz.a
+- renamed ct_* as _tr_* to avoid conflict with applications
+- clear z->msg in inflateInit2 before any error return
+- initialize opaque in example.c, gzio.c, deflate.c and inflate.c
+- fixed typo in zconf.h (_GNUC__ => __GNUC__)
+- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode)
+- fix typo in Make_vms.com (f$trnlnm -> f$getsyi)
+- in fcalloc, normalize pointer if size > 65520 bytes
+- don't use special fcalloc for 32 bit Borland C++
+- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc...
+- use Z_BINARY instead of BINARY
+- document that gzclose after gzdopen will close the file
+- allow "a" as mode in gzopen.
+- fix error checking in gzread
+- allow skipping .gz extra-field on pipes
+- added reference to Perl interface in README
+- put the crc table in FAR data (I dislike more and more the medium model :)
+- added get_crc_table
+- added a dimension to all arrays (Borland C can't count).
+- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast
+- guard against multiple inclusion of *.h (for precompiled header on Mac)
+- Watcom C pretends to be Microsoft C small model even in 32 bit mode.
+- don't use unsized arrays to avoid silly warnings by Visual C++:
+     warning C4746: 'inflate_mask' : unsized array treated as  '__far'
+     (what's wrong with far data in far model?).
+- define enum out of inflate_blocks_state to allow compilation with C++
+
+Changes in 0.95 (16 Aug 95)
+- fix MSDOS small and medium model (now easier to adapt to any compiler)
+- inlined send_bits
+- fix the final (:-) bug for deflate with flush (output was correct but
+  not completely flushed in rare occasions).
+- default window size is same for compression and decompression
+  (it's now sufficient to set MAX_WBITS in zconf.h).
+- voidp -> voidpf and voidnp -> voidp (for consistency with other
+  typedefs and because voidnp was not near in large model).
+
+Changes in 0.94 (13 Aug 95)
+- support MSDOS medium model
+- fix deflate with flush (could sometimes generate bad output)
+- fix deflateReset (zlib header was incorrectly suppressed)
+- added support for VMS
+- allow a compression level in gzopen()
+- gzflush now calls fflush
+- For deflate with flush, flush even if no more input is provided.
+- rename libgz.a as libz.a
+- avoid complex expression in infcodes.c triggering Turbo C bug
+- work around a problem with gcc on Alpha (in INSERT_STRING)
+- don't use inline functions (problem with some gcc versions)
+- allow renaming of Byte, uInt, etc... with #define.
+- avoid warning about (unused) pointer before start of array in deflate.c
+- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c
+- avoid reserved word 'new' in trees.c
+
+Changes in 0.93 (25 June 95)
+- temporarily disable inline functions
+- make deflate deterministic
+- give enough lookahead for PARTIAL_FLUSH
+- Set binary mode for stdin/stdout in minigzip.c for OS/2
+- don't even use signed char in inflate (not portable enough)
+- fix inflate memory leak for segmented architectures
+
+Changes in 0.92 (3 May 95)
+- don't assume that char is signed (problem on SGI)
+- Clear bit buffer when starting a stored block
+- no memcpy on Pyramid
+- suppressed inftest.c
+- optimized fill_window, put longest_match inline for gcc
+- optimized inflate on stored blocks.
+- untabify all sources to simplify patches
+
+Changes in 0.91 (2 May 95)
+- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h
+- Document the memory requirements in zconf.h
+- added "make install"
+- fix sync search logic in inflateSync
+- deflate(Z_FULL_FLUSH) now works even if output buffer too short
+- after inflateSync, don't scare people with just "lo world"
+- added support for DJGPP
+
+Changes in 0.9 (1 May 95)
+- don't assume that zalloc clears the allocated memory (the TurboC bug
+  was Mark's bug after all :)
+- let again gzread copy uncompressed data unchanged (was working in 0.71)
+- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented
+- added a test of inflateSync in example.c
+- moved MAX_WBITS to zconf.h because users might want to change that.
+- document explicitly that zalloc(64K) on MSDOS must return a normalized
+  pointer (zero offset)
+- added Makefiles for Microsoft C, Turbo C, Borland C++
+- faster crc32()
+
+Changes in 0.8 (29 April 95)
+- added fast inflate (inffast.c)
+- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this
+  is incompatible with previous versions of zlib which returned Z_OK.
+- work around a TurboC compiler bug (bad code for b << 0, see infutil.h)
+  (actually that was not a compiler bug, see 0.81 above)
+- gzread no longer reads one extra byte in certain cases
+- In gzio destroy(), don't reference a freed structure
+- avoid many warnings for MSDOS
+- avoid the ERROR symbol which is used by MS Windows
+
+Changes in 0.71 (14 April 95)
+- Fixed more MSDOS compilation problems :( There is still a bug with
+  TurboC large model.
+
+Changes in 0.7 (14 April 95)
+- Added full inflate support.
+- Simplified the crc32() interface. The pre- and post-conditioning
+  (one's complement) is now done inside crc32(). WARNING: this is
+  incompatible with previous versions; see zlib.h for the new usage.
+
+Changes in 0.61 (12 April 95)
+- workaround for a bug in TurboC. example and minigzip now work on MSDOS.
+
+Changes in 0.6 (11 April 95)
+- added minigzip.c
+- added gzdopen to reopen a file descriptor as gzFile
+- added transparent reading of non-gziped files in gzread.
+- fixed bug in gzread (don't read crc as data)
+- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose).
+- don't allocate big arrays in the stack (for MSDOS)
+- fix some MSDOS compilation problems
+
+Changes in 0.5:
+- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but
+  not yet Z_FULL_FLUSH.
+- support decompression but only in a single step (forced Z_FINISH)
+- added opaque object for zalloc and zfree.
+- added deflateReset and inflateReset
+- added a variable zlib_version for consistency checking.
+- renamed the 'filter' parameter of deflateInit2 as 'strategy'.
+  Added Z_FILTERED and Z_HUFFMAN_ONLY constants.
+
+Changes in 0.4:
+- avoid "zip" everywhere, use zlib instead of ziplib.
+- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush
+  if compression method == 8.
+- added adler32 and crc32
+- renamed deflateOptions as deflateInit2, call one or the other but not both
+- added the method parameter for deflateInit2.
+- added inflateInit2
+- simplied considerably deflateInit and inflateInit by not supporting
+  user-provided history buffer. This is supported only in deflateInit2
+  and inflateInit2.
+
+Changes in 0.3:
+- prefix all macro names with Z_
+- use Z_FINISH instead of deflateEnd to finish compression.
+- added Z_HUFFMAN_ONLY
+- added gzerror()
diff --git a/zlib/Makefile b/zlib/Makefile
new file mode 100644 (file)
index 0000000..ac87b2f
--- /dev/null
@@ -0,0 +1,25 @@
+UNZIPOBJS = zlib/unzip.o
+ZLIBOBJS = zlib/adler32.o zlib/compress.o zlib/crc32.o zlib/gzio.o zlib/uncompr.o zlib/deflate.o zlib/trees.o \
+               zlib/zutil.o zlib/inflate.o zlib/infblock.o zlib/inftrees.o zlib/infcodes.o zlib/infutil.o zlib/inffast.o
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+zlib/adler32.o: zlib/zlib.h zlib/zconf.h
+zlib/compress.o: zlib/zlib.h zlib/zconf.h
+zlib/crc32.o: zlib/zlib.h zlib/zconf.h
+zlib/deflate.o: zlib/deflate.h zlib/zutil.h zlib/zlib.h zlib/zconf.h
+zlib/example.o: zlib/zlib.h zlib/zconf.h
+zlib/gzio.o: zlib/zutil.h zlib/zlib.h zlib/zconf.h
+zlib/infblock.o: zlib/infblock.h zlib/inftrees.h zlib/infcodes.h zlib/infutil.h zlib/zutil.h zlib/zlib.h zlib/zconf.h
+zlib/infcodes.o: zlib/zutil.h zlib/zlib.h zlib/zconf.h
+zlib/infcodes.o: zlib/inftrees.h zlib/infblock.h zlib/infcodes.h zlib/infutil.h zlib/inffast.h
+zlib/inffast.o: zlib/zutil.h zlib/zlib.h zlib/zconf.h zlib/inftrees.h
+zlib/inffast.o: zlib/infblock.h zlib/infcodes.h zlib/infutil.h zlib/inffast.h
+zlib/inflate.o: zlib/zutil.h zlib/zlib.h zlib/zconf.h zlib/infblock.h
+zlib/inftrees.o: zlib/zutil.h zlib/zlib.h zlib/zconf.h zlib/inftrees.h
+zlib/infutil.o: zlib/zutil.h zlib/zlib.h zlib/zconf.h zlib/infblock.h zlib/inftrees.h zlib/infcodes.h zlib/infutil.h
+zlib/trees.o: zlib/deflate.h zlib/zutil.h zlib/zlib.h zlib/zconf.h zlib/trees.h
+zlib/uncompr.o: zlib/zlib.h zlib/zconf.h
+zlib/zutil.o: zlib/zutil.h zlib/zlib.h zlib/zconf.h  
+
+zlib/unzip.o: zlib/unzip.h
diff --git a/zlib/adler32.c b/zlib/adler32.c
new file mode 100644 (file)
index 0000000..a250f3f
--- /dev/null
@@ -0,0 +1,48 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id: adler32.c,v 1.2 2002/03/13 17:45:56 xodnizel Exp $ */
+
+#include "zlib.h"
+
+#define BASE 65521L /* 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)  {s1 += buf[i]; s2 += s1;}
+#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);
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+    uLong adler;
+    const Bytef *buf;
+    uInt len;
+{
+    unsigned long s1 = adler & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == Z_NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+           buf += 16;
+            k -= 16;
+        }
+        if (k != 0) do {
+            s1 += *buf++;
+           s2 += s1;
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 16) | s1;
+}
diff --git a/zlib/algorithm.txt b/zlib/algorithm.txt
new file mode 100644 (file)
index 0000000..cdc830b
--- /dev/null
@@ -0,0 +1,213 @@
+1. Compression algorithm (deflate)
+
+The deflation algorithm used by gzip (also zip and zlib) is a variation of
+LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in
+the input data.  The second occurrence of a string is replaced by a
+pointer to the previous string, in the form of a pair (distance,
+length).  Distances are limited to 32K bytes, and lengths are limited
+to 258 bytes. When a string does not occur anywhere in the previous
+32K bytes, it is emitted as a sequence of literal bytes.  (In this
+description, `string' must be taken as an arbitrary sequence of bytes,
+and is not restricted to printable characters.)
+
+Literals or match lengths are compressed with one Huffman tree, and
+match distances are compressed with another tree. The trees are stored
+in a compact form at the start of each block. The blocks can have any
+size (except that the compressed data for one block must fit in
+available memory). A block is terminated when deflate() determines that
+it would be useful to start another block with fresh trees. (This is
+somewhat similar to the behavior of LZW-based _compress_.)
+
+Duplicated strings are found using a hash table. All input strings of
+length 3 are inserted in the hash table. A hash index is computed for
+the next 3 bytes. If the hash chain for this index is not empty, all
+strings in the chain are compared with the current input string, and
+the longest match is selected.
+
+The hash chains are searched starting with the most recent strings, to
+favor small distances and thus take advantage of the Huffman encoding.
+The hash chains are singly linked. There are no deletions from the
+hash chains, the algorithm simply discards matches that are too old.
+
+To avoid a worst-case situation, very long hash chains are arbitrarily
+truncated at a certain length, determined by a runtime option (level
+parameter of deflateInit). So deflate() does not always find the longest
+possible match but generally finds a match which is long enough.
+
+deflate() also defers the selection of matches with a lazy evaluation
+mechanism. After a match of length N has been found, deflate() searches for
+a longer match at the next input byte. If a longer match is found, the
+previous match is truncated to a length of one (thus producing a single
+literal byte) and the process of lazy evaluation begins again. Otherwise,
+the original match is kept, and the next match search is attempted only N
+steps later.
+
+The lazy match evaluation is also subject to a runtime parameter. If
+the current match is long enough, deflate() reduces the search for a longer
+match, thus speeding up the whole process. If compression ratio is more
+important than speed, deflate() attempts a complete second search even if
+the first match is already long enough.
+
+The lazy match evaluation is not performed for the fastest compression
+modes (level parameter 1 to 3). For these fast modes, new strings
+are inserted in the hash table only when no match was found, or
+when the match is not too long. This degrades the compression ratio
+but saves time since there are both fewer insertions and fewer searches.
+
+
+2. Decompression algorithm (inflate)
+
+2.1 Introduction
+
+The real question is, given a Huffman tree, how to decode fast.  The most
+important realization is that shorter codes are much more common than
+longer codes, so pay attention to decoding the short codes fast, and let
+the long codes take longer to decode.
+
+inflate() sets up a first level table that covers some number of bits of
+input less than the length of longest code.  It gets that many bits from the
+stream, and looks it up in the table.  The table will tell if the next
+code is that many bits or less and how many, and if it is, it will tell
+the value, else it will point to the next level table for which inflate()
+grabs more bits and tries to decode a longer code.
+
+How many bits to make the first lookup is a tradeoff between the time it
+takes to decode and the time it takes to build the table.  If building the
+table took no time (and if you had infinite memory), then there would only
+be a first level table to cover all the way to the longest code.  However,
+building the table ends up taking a lot longer for more bits since short
+codes are replicated many times in such a table.  What inflate() does is
+simply to make the number of bits in the first table a variable, and set it
+for the maximum speed.
+
+inflate() sends new trees relatively often, so it is possibly set for a
+smaller first level table than an application that has only one tree for
+all the data.  For inflate, which has 286 possible codes for the
+literal/length tree, the size of the first table is nine bits.  Also the
+distance trees have 30 possible values, and the size of the first table is
+six bits.  Note that for each of those cases, the table ended up one bit
+longer than the ``average'' code length, i.e. the code length of an
+approximately flat code which would be a little more than eight bits for
+286 symbols and a little less than five bits for 30 symbols.  It would be
+interesting to see if optimizing the first level table for other
+applications gave values within a bit or two of the flat code size.
+
+
+2.2 More details on the inflate table lookup
+
+Ok, you want to know what this cleverly obfuscated inflate tree actually  
+looks like.  You are correct that it's not a Huffman tree.  It is simply a  
+lookup table for the first, let's say, nine bits of a Huffman symbol.  The  
+symbol could be as short as one bit or as long as 15 bits.  If a particular  
+symbol is shorter than nine bits, then that symbol's translation is duplicated
+in all those entries that start with that symbol's bits.  For example, if the  
+symbol is four bits, then it's duplicated 32 times in a nine-bit table.  If a  
+symbol is nine bits long, it appears in the table once.
+
+If the symbol is longer than nine bits, then that entry in the table points  
+to another similar table for the remaining bits.  Again, there are duplicated  
+entries as needed.  The idea is that most of the time the symbol will be short
+and there will only be one table look up.  (That's whole idea behind data  
+compression in the first place.)  For the less frequent long symbols, there  
+will be two lookups.  If you had a compression method with really long  
+symbols, you could have as many levels of lookups as is efficient.  For  
+inflate, two is enough.
+
+So a table entry either points to another table (in which case nine bits in  
+the above example are gobbled), or it contains the translation for the symbol  
+and the number of bits to gobble.  Then you start again with the next  
+ungobbled bit.
+
+You may wonder: why not just have one lookup table for how ever many bits the  
+longest symbol is?  The reason is that if you do that, you end up spending  
+more time filling in duplicate symbol entries than you do actually decoding.   
+At least for deflate's output that generates new trees every several 10's of  
+kbytes.  You can imagine that filling in a 2^15 entry table for a 15-bit code  
+would take too long if you're only decoding several thousand symbols.  At the  
+other extreme, you could make a new table for every bit in the code.  In fact,
+that's essentially a Huffman tree.  But then you spend two much time  
+traversing the tree while decoding, even for short symbols.
+
+So the number of bits for the first lookup table is a trade of the time to  
+fill out the table vs. the time spent looking at the second level and above of
+the table.
+
+Here is an example, scaled down:
+
+The code being decoded, with 10 symbols, from 1 to 6 bits long:
+
+A: 0
+B: 10
+C: 1100
+D: 11010
+E: 11011
+F: 11100
+G: 11101
+H: 11110
+I: 111110
+J: 111111
+
+Let's make the first table three bits long (eight entries):
+
+000: A,1
+001: A,1
+010: A,1
+011: A,1
+100: B,2
+101: B,2
+110: -> table X (gobble 3 bits)
+111: -> table Y (gobble 3 bits)
+
+Each entry is what the bits decode to and how many bits that is, i.e. how  
+many bits to gobble.  Or the entry points to another table, with the number of
+bits to gobble implicit in the size of the table.
+
+Table X is two bits long since the longest code starting with 110 is five bits
+long:
+
+00: C,1
+01: C,1
+10: D,2
+11: E,2
+
+Table Y is three bits long since the longest code starting with 111 is six  
+bits long:
+
+000: F,2
+001: F,2
+010: G,2
+011: G,2
+100: H,2
+101: H,2
+110: I,3
+111: J,3
+
+So what we have here are three tables with a total of 20 entries that had to  
+be constructed.  That's compared to 64 entries for a single table.  Or  
+compared to 16 entries for a Huffman tree (six two entry tables and one four  
+entry table).  Assuming that the code ideally represents the probability of  
+the symbols, it takes on the average 1.25 lookups per symbol.  That's compared
+to one lookup for the single table, or 1.66 lookups per symbol for the  
+Huffman tree.
+
+There, I think that gives you a picture of what's going on.  For inflate, the  
+meaning of a particular symbol is often more than just a letter.  It can be a  
+byte (a "literal"), or it can be either a length or a distance which  
+indicates a base value and a number of bits to fetch after the code that is  
+added to the base value.  Or it might be the special end-of-block code.  The  
+data structures created in inftrees.c try to encode all that information  
+compactly in the tables.
+
+
+Jean-loup Gailly        Mark Adler
+jloup@gzip.org          madler@alumni.caltech.edu
+
+
+References:
+
+[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data
+Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3,
+pp. 337-343.
+
+``DEFLATE Compressed Data Format Specification'' available in
+ftp://ds.internic.net/rfc/rfc1951.txt
diff --git a/zlib/compress.c b/zlib/compress.c
new file mode 100644 (file)
index 0000000..c0eecda
--- /dev/null
@@ -0,0 +1,68 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id: compress.c,v 1.2 2002/03/13 17:45:56 xodnizel Exp $ */
+
+#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 (dest, destLen, source, sourceLen, level)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+    int level;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (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 (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
diff --git a/zlib/crc32.c b/zlib/crc32.c
new file mode 100644 (file)
index 0000000..558f6f6
--- /dev/null
@@ -0,0 +1,162 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id: crc32.c,v 1.2 2002/03/13 17:45:56 xodnizel Exp $ */
+
+#include "zlib.h"
+
+#define local static
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local int crc_table_empty = 1;
+local uLongf crc_table[256];
+local void make_crc_table OF((void));
+
+/*
+  Generate a table 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 table is simply the CRC of all possible eight bit values.  This is all
+  the information needed to generate CRC's on data a byte at a time for all
+  combinations of CRC register values and incoming bytes.
+*/
+local void make_crc_table()
+{
+  uLong c;
+  int n, k;
+  uLong poly;            /* polynomial exclusive-or pattern */
+  /* terms of polynomial defining this crc (except x^32): */
+  static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+  /* make exclusive-or pattern from polynomial (0xedb88320L) */
+  poly = 0L;
+  for (n = 0; n < sizeof(p)/sizeof(Byte); n++)
+    poly |= 1L << (31 - p[n]);
+  for (n = 0; n < 256; n++)
+  {
+    c = (uLong)n;
+    for (k = 0; k < 8; k++)
+      c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+    crc_table[n] = c;
+  }
+  crc_table_empty = 0;
+}
+#else
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+local const uLongf crc_table[256] = {
+  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+  0x2d02ef8dL
+};
+#endif
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const uLongf * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+  if (crc_table_empty) make_crc_table();
+#endif
+  return (const uLongf *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf)  DO1(buf); DO1(buf);
+#define DO4(buf)  DO2(buf); DO2(buf);
+#define DO8(buf)  DO4(buf); DO4(buf);
+
+/* ========================================================================= */
+uLong ZEXPORT crc32(crc, buf, len)
+    uLong crc;
+    const Bytef *buf;
+    uInt len;
+{
+    if (buf == Z_NULL) return 0L;
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+      make_crc_table();
+#endif
+    crc = crc ^ 0xffffffffL;
+    while (len >= 8)
+    {
+      DO8(buf);
+      len -= 8;
+    }
+    if (len) do {
+      DO1(buf);
+    } while (--len);
+    return crc ^ 0xffffffffL;
+}
diff --git a/zlib/deflate.c b/zlib/deflate.c
new file mode 100644 (file)
index 0000000..0b79a14
--- /dev/null
@@ -0,0 +1,1350 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * 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 ftp://ds.internic.net/rfc/rfc1951.txt
+ *
+ *      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,v 1.2 2002/03/13 17:45:56 xodnizel Exp $ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+   " deflate 1.1.4 Copyright 1995-2002 Jean-loup Gailly ";
+/*
+  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));
+local block_state deflate_slow   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 */
+
+#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.
+ */
+
+/* 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;
+
+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}, /* maximum 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}}; /* maximum compression */
+
+/* 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 */
+
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+
+/* ===========================================================================
+ * 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)<<s->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)]), \
+    s->prev[(str) & s->w_mask] = match_head = 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_(strm, level, version, stream_size)
+    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_(strm, level, method, windowBits, memLevel, strategy,
+                 version, stream_size)
+    z_streamp strm;
+    int  level;
+    int  method;
+    int  windowBits;
+    int  memLevel;
+    int  strategy;
+    const char *version;
+    int stream_size;
+{
+    deflate_state *s;
+    int noheader = 0;
+    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 == Z_NULL) {
+       strm->zalloc = zcalloc;
+       strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == Z_NULL) strm->zfree = zcfree;
+
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#ifdef FASTEST
+    level = 1;
+#endif
+
+    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+        noheader = 1;
+        windowBits = -windowBits;
+    }
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 9 || windowBits > 15 || level < 0 || level > 9 ||
+       strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+        return Z_STREAM_ERROR;
+    }
+    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->noheader = noheader;
+    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->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) {
+        strm->msg = (char*)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 (strm, dictionary, dictLength)
+    z_streamp strm;
+    const Bytef *dictionary;
+    uInt  dictLength;
+{
+    deflate_state *s;
+    uInt length = dictLength;
+    uInt n;
+    IPos hash_head = 0;
+
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+        strm->state->status != INIT_STATE) return Z_STREAM_ERROR;
+
+    s = strm->state;
+    strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+    if (length < MIN_MATCH) return Z_OK;
+    if (length > MAX_DIST(s)) {
+       length = MAX_DIST(s);
+#ifndef USE_DICT_HEAD
+       dictionary += dictLength - length; /* use the tail of the dictionary */
+#endif
+    }
+    zmemcpy(s->window, dictionary, length);
+    s->strstart = length;
+    s->block_start = (long)length;
+
+    /* Insert all strings in the hash table (except for the last two bytes).
+     * s->lookahead stays null, so s->ins_h will be recomputed at the next
+     * call of fill_window.
+     */
+    s->ins_h = s->window[0];
+    UPDATE_HASH(s, s->ins_h, s->window[1]);
+    for (n = 0; n <= length - MIN_MATCH; n++) {
+       INSERT_STRING(s, n, hash_head);
+    }
+    if (hash_head) hash_head = 0;  /* to make compiler happy */
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+    
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        strm->zalloc == Z_NULL || strm->zfree == Z_NULL) 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->noheader < 0) {
+        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+    }
+    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+    strm->adler = 1;
+    s->last_flush = Z_NO_FLUSH;
+
+    _tr_init(s);
+    lm_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+    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;
+
+    if (level == Z_DEFAULT_COMPRESSION) {
+       level = 6;
+    }
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+       return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if (func != configuration_table[level].func && strm->total_in != 0) {
+       /* Flush the last buffer: */
+       err = deflate(strm, Z_PARTIAL_FLUSH);
+    }
+    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;
+}
+
+/* =========================================================================
+ * 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 (s, b)
+    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(strm)
+    z_streamp strm;
+{
+    unsigned len = strm->state->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    zmemcpy(strm->next_out, strm->state->pending_out, len);
+    strm->next_out  += len;
+    strm->state->pending_out  += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    strm->state->pending -= len;
+    if (strm->state->pending == 0) {
+        strm->state->pending_out = strm->state->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+    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_FINISH || 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 zlib header */
+    if (s->status == INIT_STATE) {
+
+        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+        uInt level_flags = (s->level-1) >> 1;
+
+        if (level_flags > 3) 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 = 1L;
+    }
+
+    /* 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_BUFF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && flush <= 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 = (*(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 { /* 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 */
+                }
+            }
+            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->noheader) return Z_STREAM_END;
+
+    /* Write the zlib trailer (adler32) */
+    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.
+     */
+    s->noheader = -1; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+    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 != 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 (dest, source)
+    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;
+
+    *dest = *source;
+
+    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+    if (ds == Z_NULL) return Z_MEM_ERROR;
+    dest->state = (struct internal_state FAR *) ds;
+    *ds = *ss;
+    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(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+    zmemcpy(ds->head, 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
+}
+
+/* ===========================================================================
+ * 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(strm, buf, size)
+    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;
+
+    if (!strm->state->noheader) {
+        strm->adler = adler32(strm->adler, strm->next_in, len);
+    }
+    zmemcpy(buf, strm->next_in, len);
+    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 (s)
+    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->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+#ifdef ASMV
+    match_init(); /* initialize the asm code */
+#endif
+}
+
+/* ===========================================================================
+ * 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.
+ */
+#ifndef FASTEST
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current 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:
+         */
+#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;
+}
+
+#else /* FASTEST */
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 only
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current 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 len <= s->lookahead ? len : s->lookahead;
+}
+#endif /* FASTEST */
+#endif /* ASMV */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+    deflate_state *s;
+    IPos start, 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
+
+/* ===========================================================================
+ * 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(s)
+    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;
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        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
+             * and lookahead == 1 (input done one 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.
+         */
+        } else 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) return;
+
+        /* 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 >= MIN_MATCH) {
+            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 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);
+}
+
+/* ===========================================================================
+ * 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, eof) { \
+   _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), \
+               (eof)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+   FLUSH_BLOCK_ONLY(s, eof); \
+   if (s->strm->avail_out == 0) return (eof) ? 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(s, flush)
+    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);
+       }
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : 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(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL; /* 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:
+         */
+        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).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY) {
+                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 hash 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);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * 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(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL;    /* 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:
+         */
+        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).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
+                 (s->match_length == MIN_MATCH &&
+                  s->strstart - s->match_start > TOO_FAR))) {
+
+                /* 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;
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
diff --git a/zlib/deflate.h b/zlib/deflate.h
new file mode 100644 (file)
index 0000000..9bd8cb0
--- /dev/null
@@ -0,0 +1,318 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2002 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,v 1.2 2002/03/13 17:45:56 xodnizel Exp $ */
+
+#ifndef _DEFLATE_H
+#define _DEFLATE_H
+
+#include "zutil.h"
+
+/* ===========================================================================
+ * 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 INIT_STATE    42
+#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 */
+    int   pending;       /* nb of bytes in the pending buffer */
+    int   noheader;      /* suppress zlib header and adler32 */
+    Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
+    Byte  method;        /* STORED (for zip only) or 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 supress 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 */
+    int last_eob_len;   /* bit length of EOB code for last block */
+
+#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.
+     */
+
+} 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.
+ */
+
+        /* in trees.c */
+void _tr_init         OF((deflate_state *s));
+int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
+                         int eof));
+void _tr_align        OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+                          int eof));
+
+#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 _length_code[];
+  extern uch _dist_code[];
+#else
+  extern const uch _length_code[];
+  extern const uch _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
diff --git a/zlib/descrip.mms b/zlib/descrip.mms
new file mode 100644 (file)
index 0000000..9d36459
--- /dev/null
@@ -0,0 +1,48 @@
+# descrip.mms: MMS description file for building zlib on VMS
+# written by Martin P.J. Zinser <m.zinser@gsi.de>
+
+cc_defs = 
+c_deb = 
+
+.ifdef __DECC__
+pref = /prefix=all
+.endif
+
+OBJS = adler32.obj, compress.obj, crc32.obj, gzio.obj, uncompr.obj,\
+       deflate.obj, trees.obj, zutil.obj, inflate.obj, infblock.obj,\
+       inftrees.obj, infcodes.obj, infutil.obj, inffast.obj
+
+CFLAGS= $(C_DEB) $(CC_DEFS) $(PREF)
+
+all : example.exe minigzip.exe
+        @ write sys$output " Example applications available"
+libz.olb : libz.olb($(OBJS))
+       @ write sys$output " libz available"
+
+example.exe : example.obj libz.olb
+              link example,libz.olb/lib
+
+minigzip.exe : minigzip.obj libz.olb
+              link minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib
+
+clean : 
+       delete *.obj;*,libz.olb;*
+
+
+# Other dependencies.
+adler32.obj : zutil.h zlib.h zconf.h
+compress.obj : zlib.h zconf.h
+crc32.obj : zutil.h zlib.h zconf.h
+deflate.obj : deflate.h zutil.h zlib.h zconf.h
+example.obj : zlib.h zconf.h
+gzio.obj : zutil.h zlib.h zconf.h
+infblock.obj : zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h
+infcodes.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h
+inffast.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h
+inflate.obj : zutil.h zlib.h zconf.h infblock.h
+inftrees.obj : zutil.h zlib.h zconf.h inftrees.h
+infutil.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h
+minigzip.obj : zlib.h zconf.h
+trees.obj : deflate.h zutil.h zlib.h zconf.h
+uncompr.obj : zlib.h zconf.h
+zutil.obj : zutil.h zlib.h zconf.h
diff --git a/zlib/example.c b/zlib/example.c
new file mode 100644 (file)
index 0000000..af7f43e
--- /dev/null
@@ -0,0 +1,556 @@
+/* example.c -- usage example of the zlib compression library
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id: example.c,v 1.2 2002/03/13 17:45:56 xodnizel Exp $ */
+
+#include <stdio.h>
+#include "zlib.h"
+
+#ifdef STDC
+#  include <string.h>
+#  include <stdlib.h>
+#else
+   extern void exit  OF((int));
+#endif
+
+#if defined(VMS) || defined(RISCOS)
+#  define TESTFILE "foo-gz"
+#else
+#  define TESTFILE "foo.gz"
+#endif
+
+#define CHECK_ERR(err, msg) { \
+    if (err != Z_OK) { \
+        fprintf(stderr, "%s error: %d\n", msg, err); \
+        exit(1); \
+    } \
+}
+
+const char hello[] = "hello, hello!";
+/* "hello world" would be more standard, but the repeated "hello"
+ * stresses the compression code better, sorry...
+ */
+
+const char dictionary[] = "hello";
+uLong dictId; /* Adler32 value of the dictionary */
+
+void test_compress      OF((Byte *compr, uLong comprLen,
+                           Byte *uncompr, uLong uncomprLen));
+void test_gzio          OF((const char *out, const char *in, 
+                           Byte *uncompr, int uncomprLen));
+void test_deflate       OF((Byte *compr, uLong comprLen));
+void test_inflate       OF((Byte *compr, uLong comprLen,
+                           Byte *uncompr, uLong uncomprLen));
+void test_large_deflate OF((Byte *compr, uLong comprLen,
+                           Byte *uncompr, uLong uncomprLen));
+void test_large_inflate OF((Byte *compr, uLong comprLen,
+                           Byte *uncompr, uLong uncomprLen));
+void test_flush         OF((Byte *compr, uLong *comprLen));
+void test_sync          OF((Byte *compr, uLong comprLen,
+                           Byte *uncompr, uLong uncomprLen));
+void test_dict_deflate  OF((Byte *compr, uLong comprLen));
+void test_dict_inflate  OF((Byte *compr, uLong comprLen,
+                           Byte *uncompr, uLong uncomprLen));
+int  main               OF((int argc, char *argv[]));
+
+/* ===========================================================================
+ * Test compress() and uncompress()
+ */
+void test_compress(compr, comprLen, uncompr, uncomprLen)
+    Byte *compr, *uncompr;
+    uLong comprLen, uncomprLen;
+{
+    int err;
+    uLong len = strlen(hello)+1;
+
+    err = compress(compr, &comprLen, (const Bytef*)hello, len);
+    CHECK_ERR(err, "compress");
+
+    strcpy((char*)uncompr, "garbage");
+
+    err = uncompress(uncompr, &uncomprLen, compr, comprLen);
+    CHECK_ERR(err, "uncompress");
+
+    if (strcmp((char*)uncompr, hello)) {
+        fprintf(stderr, "bad uncompress\n");
+       exit(1);
+    } else {
+        printf("uncompress(): %s\n", (char *)uncompr);
+    }
+}
+
+/* ===========================================================================
+ * Test read/write of .gz files
+ */
+void test_gzio(out, in, uncompr, uncomprLen)
+    const char *out; /* compressed output file */
+    const char *in;  /* compressed input file */
+    Byte *uncompr;
+    int  uncomprLen;
+{
+    int err;
+    int len = strlen(hello)+1;
+    gzFile file;
+    z_off_t pos;
+
+    file = gzopen(out, "wb");
+    if (file == NULL) {
+        fprintf(stderr, "gzopen error\n");
+        exit(1);
+    }
+    gzputc(file, 'h');
+    if (gzputs(file, "ello") != 4) {
+        fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err));
+       exit(1);
+    }
+    if (gzprintf(file, ", %s!", "hello") != 8) {
+        fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err));
+       exit(1);
+    }
+    gzseek(file, 1L, SEEK_CUR); /* add one zero byte */
+    gzclose(file);
+
+    file = gzopen(in, "rb");
+    if (file == NULL) {
+        fprintf(stderr, "gzopen error\n");
+    }
+    strcpy((char*)uncompr, "garbage");
+
+    uncomprLen = gzread(file, uncompr, (unsigned)uncomprLen);
+    if (uncomprLen != len) {
+        fprintf(stderr, "gzread err: %s\n", gzerror(file, &err));
+       exit(1);
+    }
+    if (strcmp((char*)uncompr, hello)) {
+        fprintf(stderr, "bad gzread: %s\n", (char*)uncompr);
+       exit(1);
+    } else {
+        printf("gzread(): %s\n", (char *)uncompr);
+    }
+
+    pos = gzseek(file, -8L, SEEK_CUR);
+    if (pos != 6 || gztell(file) != pos) {
+       fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n",
+               (long)pos, (long)gztell(file));
+       exit(1);
+    }
+
+    if (gzgetc(file) != ' ') {
+       fprintf(stderr, "gzgetc error\n");
+       exit(1);
+    }
+
+    gzgets(file, (char*)uncompr, uncomprLen);
+    uncomprLen = strlen((char*)uncompr);
+    if (uncomprLen != 6) { /* "hello!" */
+        fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err));
+       exit(1);
+    }
+    if (strcmp((char*)uncompr, hello+7)) {
+        fprintf(stderr, "bad gzgets after gzseek\n");
+       exit(1);
+    } else {
+        printf("gzgets() after gzseek: %s\n", (char *)uncompr);
+    }
+
+    gzclose(file);
+}
+
+/* ===========================================================================
+ * Test deflate() with small buffers
+ */
+void test_deflate(compr, comprLen)
+    Byte *compr;
+    uLong comprLen;
+{
+    z_stream c_stream; /* compression stream */
+    int err;
+    int len = strlen(hello)+1;
+
+    c_stream.zalloc = (alloc_func)0;
+    c_stream.zfree = (free_func)0;
+    c_stream.opaque = (voidpf)0;
+
+    err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+    CHECK_ERR(err, "deflateInit");
+
+    c_stream.next_in  = (Bytef*)hello;
+    c_stream.next_out = compr;
+
+    while (c_stream.total_in != (uLong)len && c_stream.total_out < comprLen) {
+        c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */
+        err = deflate(&c_stream, Z_NO_FLUSH);
+        CHECK_ERR(err, "deflate");
+    }
+    /* Finish the stream, still forcing small buffers: */
+    for (;;) {
+        c_stream.avail_out = 1;
+        err = deflate(&c_stream, Z_FINISH);
+        if (err == Z_STREAM_END) break;
+        CHECK_ERR(err, "deflate");
+    }
+
+    err = deflateEnd(&c_stream);
+    CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with small buffers
+ */
+void test_inflate(compr, comprLen, uncompr, uncomprLen)
+    Byte *compr, *uncompr;
+    uLong comprLen, uncomprLen;
+{
+    int err;
+    z_stream d_stream; /* decompression stream */
+
+    strcpy((char*)uncompr, "garbage");
+
+    d_stream.zalloc = (alloc_func)0;
+    d_stream.zfree = (free_func)0;
+    d_stream.opaque = (voidpf)0;
+
+    d_stream.next_in  = compr;
+    d_stream.avail_in = 0;
+    d_stream.next_out = uncompr;
+
+    err = inflateInit(&d_stream);
+    CHECK_ERR(err, "inflateInit");
+
+    while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) {
+        d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
+        err = inflate(&d_stream, Z_NO_FLUSH);
+        if (err == Z_STREAM_END) break;
+        CHECK_ERR(err, "inflate");
+    }
+
+    err = inflateEnd(&d_stream);
+    CHECK_ERR(err, "inflateEnd");
+
+    if (strcmp((char*)uncompr, hello)) {
+        fprintf(stderr, "bad inflate\n");
+       exit(1);
+    } else {
+        printf("inflate(): %s\n", (char *)uncompr);
+    }
+}
+
+/* ===========================================================================
+ * Test deflate() with large buffers and dynamic change of compression level
+ */
+void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
+    Byte *compr, *uncompr;
+    uLong comprLen, uncomprLen;
+{
+    z_stream c_stream; /* compression stream */
+    int err;
+
+    c_stream.zalloc = (alloc_func)0;
+    c_stream.zfree = (free_func)0;
+    c_stream.opaque = (voidpf)0;
+
+    err = deflateInit(&c_stream, Z_BEST_SPEED);
+    CHECK_ERR(err, "deflateInit");
+
+    c_stream.next_out = compr;
+    c_stream.avail_out = (uInt)comprLen;
+
+    /* At this point, uncompr is still mostly zeroes, so it should compress
+     * very well:
+     */
+    c_stream.next_in = uncompr;
+    c_stream.avail_in = (uInt)uncomprLen;
+    err = deflate(&c_stream, Z_NO_FLUSH);
+    CHECK_ERR(err, "deflate");
+    if (c_stream.avail_in != 0) {
+        fprintf(stderr, "deflate not greedy\n");
+       exit(1);
+    }
+
+    /* Feed in already compressed data and switch to no compression: */
+    deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY);
+    c_stream.next_in = compr;
+    c_stream.avail_in = (uInt)comprLen/2;
+    err = deflate(&c_stream, Z_NO_FLUSH);
+    CHECK_ERR(err, "deflate");
+
+    /* Switch back to compressing mode: */
+    deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED);
+    c_stream.next_in = uncompr;
+    c_stream.avail_in = (uInt)uncomprLen;
+    err = deflate(&c_stream, Z_NO_FLUSH);
+    CHECK_ERR(err, "deflate");
+
+    err = deflate(&c_stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        fprintf(stderr, "deflate should report Z_STREAM_END\n");
+       exit(1);
+    }
+    err = deflateEnd(&c_stream);
+    CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with large buffers
+ */
+void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
+    Byte *compr, *uncompr;
+    uLong comprLen, uncomprLen;
+{
+    int err;
+    z_stream d_stream; /* decompression stream */
+
+    strcpy((char*)uncompr, "garbage");
+
+    d_stream.zalloc = (alloc_func)0;
+    d_stream.zfree = (free_func)0;
+    d_stream.opaque = (voidpf)0;
+
+    d_stream.next_in  = compr;
+    d_stream.avail_in = (uInt)comprLen;
+
+    err = inflateInit(&d_stream);
+    CHECK_ERR(err, "inflateInit");
+
+    for (;;) {
+        d_stream.next_out = uncompr;            /* discard the output */
+       d_stream.avail_out = (uInt)uncomprLen;
+        err = inflate(&d_stream, Z_NO_FLUSH);
+        if (err == Z_STREAM_END) break;
+        CHECK_ERR(err, "large inflate");
+    }
+
+    err = inflateEnd(&d_stream);
+    CHECK_ERR(err, "inflateEnd");
+
+    if (d_stream.total_out != 2*uncomprLen + comprLen/2) {
+        fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out);
+       exit(1);
+    } else {
+        printf("large_inflate(): OK\n");
+    }
+}
+
+/* ===========================================================================
+ * Test deflate() with full flush
+ */
+void test_flush(compr, comprLen)
+    Byte *compr;
+    uLong *comprLen;
+{
+    z_stream c_stream; /* compression stream */
+    int err;
+    int len = strlen(hello)+1;
+
+    c_stream.zalloc = (alloc_func)0;
+    c_stream.zfree = (free_func)0;
+    c_stream.opaque = (voidpf)0;
+
+    err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+    CHECK_ERR(err, "deflateInit");
+
+    c_stream.next_in  = (Bytef*)hello;
+    c_stream.next_out = compr;
+    c_stream.avail_in = 3;
+    c_stream.avail_out = (uInt)*comprLen;
+    err = deflate(&c_stream, Z_FULL_FLUSH);
+    CHECK_ERR(err, "deflate");
+
+    compr[3]++; /* force an error in first compressed block */
+    c_stream.avail_in = len - 3;
+
+    err = deflate(&c_stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        CHECK_ERR(err, "deflate");
+    }
+    err = deflateEnd(&c_stream);
+    CHECK_ERR(err, "deflateEnd");
+
+    *comprLen = c_stream.total_out;
+}
+
+/* ===========================================================================
+ * Test inflateSync()
+ */
+void test_sync(compr, comprLen, uncompr, uncomprLen)
+    Byte *compr, *uncompr;
+    uLong comprLen, uncomprLen;
+{
+    int err;
+    z_stream d_stream; /* decompression stream */
+
+    strcpy((char*)uncompr, "garbage");
+
+    d_stream.zalloc = (alloc_func)0;
+    d_stream.zfree = (free_func)0;
+    d_stream.opaque = (voidpf)0;
+
+    d_stream.next_in  = compr;
+    d_stream.avail_in = 2; /* just read the zlib header */
+
+    err = inflateInit(&d_stream);
+    CHECK_ERR(err, "inflateInit");
+
+    d_stream.next_out = uncompr;
+    d_stream.avail_out = (uInt)uncomprLen;
+
+    inflate(&d_stream, Z_NO_FLUSH);
+    CHECK_ERR(err, "inflate");
+
+    d_stream.avail_in = (uInt)comprLen-2;   /* read all compressed data */
+    err = inflateSync(&d_stream);           /* but skip the damaged part */
+    CHECK_ERR(err, "inflateSync");
+
+    err = inflate(&d_stream, Z_FINISH);
+    if (err != Z_DATA_ERROR) {
+        fprintf(stderr, "inflate should report DATA_ERROR\n");
+        /* Because of incorrect adler32 */
+       exit(1);
+    }
+    err = inflateEnd(&d_stream);
+    CHECK_ERR(err, "inflateEnd");
+
+    printf("after inflateSync(): hel%s\n", (char *)uncompr);
+}
+
+/* ===========================================================================
+ * Test deflate() with preset dictionary
+ */
+void test_dict_deflate(compr, comprLen)
+    Byte *compr;
+    uLong comprLen;
+{
+    z_stream c_stream; /* compression stream */
+    int err;
+
+    c_stream.zalloc = (alloc_func)0;
+    c_stream.zfree = (free_func)0;
+    c_stream.opaque = (voidpf)0;
+
+    err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
+    CHECK_ERR(err, "deflateInit");
+
+    err = deflateSetDictionary(&c_stream,
+                              (const Bytef*)dictionary, sizeof(dictionary));
+    CHECK_ERR(err, "deflateSetDictionary");
+
+    dictId = c_stream.adler;
+    c_stream.next_out = compr;
+    c_stream.avail_out = (uInt)comprLen;
+
+    c_stream.next_in = (Bytef*)hello;
+    c_stream.avail_in = (uInt)strlen(hello)+1;
+
+    err = deflate(&c_stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        fprintf(stderr, "deflate should report Z_STREAM_END\n");
+       exit(1);
+    }
+    err = deflateEnd(&c_stream);
+    CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with a preset dictionary
+ */
+void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
+    Byte *compr, *uncompr;
+    uLong comprLen, uncomprLen;
+{
+    int err;
+    z_stream d_stream; /* decompression stream */
+
+    strcpy((char*)uncompr, "garbage");
+
+    d_stream.zalloc = (alloc_func)0;
+    d_stream.zfree = (free_func)0;
+    d_stream.opaque = (voidpf)0;
+
+    d_stream.next_in  = compr;
+    d_stream.avail_in = (uInt)comprLen;
+
+    err = inflateInit(&d_stream);
+    CHECK_ERR(err, "inflateInit");
+
+    d_stream.next_out = uncompr;
+    d_stream.avail_out = (uInt)uncomprLen;
+
+    for (;;) {
+        err = inflate(&d_stream, Z_NO_FLUSH);
+        if (err == Z_STREAM_END) break;
+       if (err == Z_NEED_DICT) {
+           if (d_stream.adler != dictId) {
+               fprintf(stderr, "unexpected dictionary");
+               exit(1);
+           }
+           err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary,
+                                      sizeof(dictionary));
+       }
+        CHECK_ERR(err, "inflate with dict");
+    }
+
+    err = inflateEnd(&d_stream);
+    CHECK_ERR(err, "inflateEnd");
+
+    if (strcmp((char*)uncompr, hello)) {
+        fprintf(stderr, "bad inflate with dict\n");
+       exit(1);
+    } else {
+        printf("inflate with dictionary: %s\n", (char *)uncompr);
+    }
+}
+
+/* ===========================================================================
+ * Usage:  example [output.gz  [input.gz]]
+ */
+
+int main(argc, argv)
+    int argc;
+    char *argv[];
+{
+    Byte *compr, *uncompr;
+    uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */
+    uLong uncomprLen = comprLen;
+    static const char* myVersion = ZLIB_VERSION;
+
+    if (zlibVersion()[0] != myVersion[0]) {
+        fprintf(stderr, "incompatible zlib version\n");
+        exit(1);
+
+    } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) {
+        fprintf(stderr, "warning: different zlib version\n");
+    }
+
+    compr    = (Byte*)calloc((uInt)comprLen, 1);
+    uncompr  = (Byte*)calloc((uInt)uncomprLen, 1);
+    /* compr and uncompr are cleared to avoid reading uninitialized
+     * data and to ensure that uncompr compresses well.
+     */
+    if (compr == Z_NULL || uncompr == Z_NULL) {
+        printf("out of memory\n");
+       exit(1);
+    }
+    test_compress(compr, comprLen, uncompr, uncomprLen);
+
+    test_gzio((argc > 1 ? argv[1] : TESTFILE),
+              (argc > 2 ? argv[2] : TESTFILE),
+             uncompr, (int)uncomprLen);
+
+    test_deflate(compr, comprLen);
+    test_inflate(compr, comprLen, uncompr, uncomprLen);
+
+    test_large_deflate(compr, comprLen, uncompr, uncomprLen);
+    test_large_inflate(compr, comprLen, uncompr, uncomprLen);
+
+    test_flush(compr, &comprLen);
+    test_sync(compr, comprLen, uncompr, uncomprLen);
+    comprLen = uncomprLen;
+
+    test_dict_deflate(compr, comprLen);
+    test_dict_inflate(compr, comprLen, uncompr, uncomprLen);
+
+    exit(0);
+    return 0; /* to avoid warning */
+}
diff --git a/zlib/faq b/zlib/faq
new file mode 100644 (file)
index 0000000..0feb6d3
--- /dev/null
+++ b/zlib/faq
@@ -0,0 +1,72 @@
+
+               Frequently Asked Questions about zlib
+
+
+If your question is not there, please check the zlib home page 
+http://www.cdrom.com/pub/infozip/zlib/ which may have more recent information.
+
+
+1) I need a Windows DLL
+2) I need a Visual Basic interface to zlib
+3) compress() returns Z_BUF_ERROR
+4) deflate or inflate returns Z_BUF_ERROR
+5) Where is the zlib documentation (man pages, etc...)?
+6) Why don't you use GNU autoconf, libtool, etc...?
+7) There is a bug in zlib.
+8) I get "undefined reference to gzputc"
+
+
+
+1) I need a Windows DLL
+
+  The zlib sources can be compiled without change to produce a DLL.
+  If you want a precompiled DLL, see http://www.winimage.com/zLibDll
+
+
+2) I need a Visual Basic interface to zlib
+
+  See http://www.tcfb.com/dowseware/cmp-z-it.zip
+      http://web2.airmail.net/markn/articles/zlibtool/zlibtool.htm
+  and contrib/visual-basic.txt
+
+3) compress() returns Z_BUF_ERROR
+
+  Make sure that before the call of compress, the length of the
+  compressed buffer is equal to the total size of the compressed buffer
+  and not zero.  For Visual Basic, check that this parameter is passed
+  by reference ("as any"), not by value ("as long").
+
+
+4) deflate or inflate returns Z_BUF_ERROR
+
+  Make sure that before the call avail_in and avail_out are not zero.
+
+
+5) Where is the zlib documentation (man pages, etc...)?
+
+  It's in zlib.h for the moment. Volunteers to transform this
+  to man pages, please contact jloup@gzip.org. Examples of zlib usage
+  are in the files example.c and minigzip.c.
+
+
+6) Why don't you use GNU autoconf, libtool, etc...?
+
+  Because we would like to keep zlib as a very small and simple package.
+  zlib is rather portable and doesn't need much configuration.
+
+
+7) There is a bug in zlib.
+
+  Most of the time, such problems are due to an incorrect usage
+  of zlib. Please try to reproduce the problem with a small
+  program and send us the corresponding source at zlib@quest.jpl.nasa.gov
+  Do not send multi-megabyte data files without prior agreement.
+
+
+8) I get "undefined reference to gzputc"
+
+  If "make test" produces something like
+     example.o(.text+0x174): 
+  check that you don't have old files libz.* in /usr/lib, /usr/local/lib
+  or /usr/X11R6/lib. Remove old versions then do "make install".
+
diff --git a/zlib/gzio.c b/zlib/gzio.c
new file mode 100644 (file)
index 0000000..6142b0a
--- /dev/null
@@ -0,0 +1,875 @@
+/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Compile this file with -DNO_DEFLATE to avoid the compression code.
+ */
+
+/* @(#) $Id: gzio.c,v 1.2 2002/03/13 17:45:56 xodnizel Exp $ */
+
+#include <stdio.h>
+
+#include "zutil.h"
+
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+#ifndef Z_BUFSIZE
+#  ifdef MAXSEG_64K
+#    define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
+#  else
+#    define Z_BUFSIZE 16384
+#  endif
+#endif
+#ifndef Z_PRINTF_BUFSIZE
+#  define Z_PRINTF_BUFSIZE 4096
+#endif
+
+#define ALLOC(size) malloc(size)
+#define TRYFREE(p) {if (p) free(p);}
+
+static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define RESERVED     0xE0 /* bits 5..7: reserved */
+
+typedef struct gz_stream {
+    z_stream stream;
+    int      z_err;   /* error code for last stream operation */
+    int      z_eof;   /* set if end of input file */
+    FILE     *file;   /* .gz file */
+    Byte     *inbuf;  /* input buffer */
+    Byte     *outbuf; /* output buffer */
+    uLong    crc;     /* crc32 of uncompressed data */
+    char     *msg;    /* error message */
+    char     *path;   /* path name for debugging only */
+    int      transparent; /* 1 if input file is not a .gz file */
+    char     mode;    /* 'w' or 'r' */
+    long     startpos; /* start of compressed data in file (header skipped) */
+} gz_stream;
+
+
+local gzFile gz_open      OF((const char *path, const char *mode, int  fd));
+local int do_flush        OF((gzFile file, int flush));
+local int    get_byte     OF((gz_stream *s));
+local void   check_header OF((gz_stream *s));
+local int    destroy      OF((gz_stream *s));
+local void   putLong      OF((FILE *file, uLong x));
+local uLong  getLong      OF((gz_stream *s));
+
+/* ===========================================================================
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb"). The file is given either by file descriptor
+   or path name (if fd == -1).
+     gz_open return NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).
+*/
+local gzFile gz_open (path, mode, fd)
+    const char *path;
+    const char *mode;
+    int  fd;
+{
+    int err;
+    int level = Z_DEFAULT_COMPRESSION; /* compression level */
+    int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
+    char *p = (char*)mode;
+    gz_stream *s;
+    char fmode[80]; /* copy of mode, without the compression level */
+    char *m = fmode;
+
+    if (!path || !mode) return Z_NULL;
+
+    s = (gz_stream *)ALLOC(sizeof(gz_stream));
+    if (!s) return Z_NULL;
+
+    s->stream.zalloc = (alloc_func)0;
+    s->stream.zfree = (free_func)0;
+    s->stream.opaque = (voidpf)0;
+    s->stream.next_in = s->inbuf = Z_NULL;
+    s->stream.next_out = s->outbuf = Z_NULL;
+    s->stream.avail_in = s->stream.avail_out = 0;
+    s->file = NULL;
+    s->z_err = Z_OK;
+    s->z_eof = 0;
+    s->crc = crc32(0L, Z_NULL, 0);
+    s->msg = NULL;
+    s->transparent = 0;
+
+    s->path = (char*)ALLOC(strlen(path)+1);
+    if (s->path == NULL) {
+        return destroy(s), (gzFile)Z_NULL;
+    }
+    strcpy(s->path, path); /* do this early for debugging */
+
+    s->mode = '\0';
+    do {
+        if (*p == 'r') s->mode = 'r';
+        if (*p == 'w' || *p == 'a') s->mode = 'w';
+        if (*p >= '0' && *p <= '9') {
+           level = *p - '0';
+       } else if (*p == 'f') {
+         strategy = Z_FILTERED;
+       } else if (*p == 'h') {
+         strategy = Z_HUFFMAN_ONLY;
+       } else {
+           *m++ = *p; /* copy the mode */
+       }
+    } while (*p++ && m != fmode + sizeof(fmode));
+    if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
+    
+    if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+        err = Z_STREAM_ERROR;
+#else
+        err = deflateInit2(&(s->stream), level,
+                           Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
+        /* windowBits is passed < 0 to suppress zlib header */
+
+        s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+#endif
+        if (err != Z_OK || s->outbuf == Z_NULL) {
+            return destroy(s), (gzFile)Z_NULL;
+        }
+    } else {
+        s->stream.next_in  = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
+
+        err = inflateInit2(&(s->stream), -MAX_WBITS);
+        /* windowBits is passed < 0 to tell that there is no zlib header.
+         * Note that in this case inflate *requires* an extra "dummy" byte
+         * after the compressed stream in order to complete decompression and
+         * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
+         * present after the compressed stream.
+         */
+        if (err != Z_OK || s->inbuf == Z_NULL) {
+            return destroy(s), (gzFile)Z_NULL;
+        }
+    }
+    s->stream.avail_out = Z_BUFSIZE;
+
+    errno = 0;
+    s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
+
+    if (s->file == NULL) {
+        return destroy(s), (gzFile)Z_NULL;
+    }
+    if (s->mode == 'w') {
+        /* Write a very simple .gz header:
+         */
+        fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
+             Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
+       s->startpos = 10L;
+       /* We use 10L instead of ftell(s->file) to because ftell causes an
+         * fflush on some systems. This version of the library doesn't use
+         * startpos anyway in write mode, so this initialization is not
+         * necessary.
+         */
+    } else {
+       check_header(s); /* skip the .gz header */
+       s->startpos = (ftell(s->file) - s->stream.avail_in);
+    }
+    
+    return (gzFile)s;
+}
+
+/* ===========================================================================
+     Opens a gzip (.gz) file for reading or writing.
+*/
+gzFile ZEXPORT gzopen (path, mode)
+    const char *path;
+    const char *mode;
+{
+    return gz_open (path, mode, -1);
+}
+
+/* ===========================================================================
+     Associate a gzFile with the file descriptor fd. fd is not dup'ed here
+   to mimic the behavio(u)r of fdopen.
+*/
+gzFile ZEXPORT gzdopen (fd, mode)
+    int fd;
+    const char *mode;
+{
+    char name[20];
+
+    if (fd < 0) return (gzFile)Z_NULL;
+    sprintf(name, "<fd:%d>", fd); /* for debugging */
+
+    return gz_open (name, mode, fd);
+}
+
+/* ===========================================================================
+ * Update the compression level and strategy
+ */
+int ZEXPORT gzsetparams (file, level, strategy)
+    gzFile file;
+    int level;
+    int strategy;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+    /* Make room to allow flushing */
+    if (s->stream.avail_out == 0) {
+
+       s->stream.next_out = s->outbuf;
+       if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+           s->z_err = Z_ERRNO;
+       }
+       s->stream.avail_out = Z_BUFSIZE;
+    }
+
+    return deflateParams (&(s->stream), level, strategy);
+}
+
+/* ===========================================================================
+     Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+   for end of file.
+   IN assertion: the stream s has been sucessfully opened for reading.
+*/
+local int get_byte(s)
+    gz_stream *s;
+{
+    if (s->z_eof) return EOF;
+    if (s->stream.avail_in == 0) {
+       errno = 0;
+       s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+       if (s->stream.avail_in == 0) {
+           s->z_eof = 1;
+           if (ferror(s->file)) s->z_err = Z_ERRNO;
+           return EOF;
+       }
+       s->stream.next_in = s->inbuf;
+    }
+    s->stream.avail_in--;
+    return *(s->stream.next_in)++;
+}
+
+/* ===========================================================================
+      Check the gzip header of a gz_stream opened for reading. Set the stream
+    mode to transparent if the gzip magic header is not present; set s->err
+    to Z_DATA_ERROR if the magic header is present but the rest of the header
+    is incorrect.
+    IN assertion: the stream s has already been created sucessfully;
+       s->stream.avail_in is zero for the first time, but may be non-zero
+       for concatenated .gz files.
+*/
+local void check_header(s)
+    gz_stream *s;
+{
+    int method; /* method byte */
+    int flags;  /* flags byte */
+    uInt len;
+    int c;
+
+    /* Check the gzip magic header */
+    for (len = 0; len < 2; len++) {
+       c = get_byte(s);
+       if (c != gz_magic[len]) {
+           if (len != 0) s->stream.avail_in++, s->stream.next_in--;
+           if (c != EOF) {
+               s->stream.avail_in++, s->stream.next_in--;
+               s->transparent = 1;
+           }
+           s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
+           return;
+       }
+    }
+    method = get_byte(s);
+    flags = get_byte(s);
+    if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+       s->z_err = Z_DATA_ERROR;
+       return;
+    }
+
+    /* Discard time, xflags and OS code: */
+    for (len = 0; len < 6; len++) (void)get_byte(s);
+
+    if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+       len  =  (uInt)get_byte(s);
+       len += ((uInt)get_byte(s))<<8;
+       /* len is garbage if EOF but the loop below will quit anyway */
+       while (len-- != 0 && get_byte(s) != EOF) ;
+    }
+    if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+       while ((c = get_byte(s)) != 0 && c != EOF) ;
+    }
+    if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
+       while ((c = get_byte(s)) != 0 && c != EOF) ;
+    }
+    if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
+       for (len = 0; len < 2; len++) (void)get_byte(s);
+    }
+    s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
+}
+
+ /* ===========================================================================
+ * Cleanup then free the given gz_stream. Return a zlib error code.
+   Try freeing in the reverse order of allocations.
+ */
+local int destroy (s)
+    gz_stream *s;
+{
+    int err = Z_OK;
+
+    if (!s) return Z_STREAM_ERROR;
+
+    TRYFREE(s->msg);
+
+    if (s->stream.state != NULL) {
+       if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+           err = Z_STREAM_ERROR;
+#else
+           err = deflateEnd(&(s->stream));
+#endif
+       } else if (s->mode == 'r') {
+           err = inflateEnd(&(s->stream));
+       }
+    }
+    if (s->file != NULL && fclose(s->file)) {
+#ifdef ESPIPE
+       if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
+#endif
+           err = Z_ERRNO;
+    }
+    if (s->z_err < 0) err = s->z_err;
+
+    TRYFREE(s->inbuf);
+    TRYFREE(s->outbuf);
+    TRYFREE(s->path);
+    TRYFREE(s);
+    return err;
+}
+
+/* ===========================================================================
+     Reads the given number of uncompressed bytes from the compressed file.
+   gzread returns the number of bytes actually read (0 for end of file).
+*/
+int ZEXPORT gzread (file, buf, len)
+    gzFile file;
+    voidp buf;
+    unsigned len;
+{
+    gz_stream *s = (gz_stream*)file;
+    Bytef *start = (Bytef*)buf; /* starting point for crc computation */
+    Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
+
+    if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
+
+    if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
+    if (s->z_err == Z_STREAM_END) return 0;  /* EOF */
+
+    next_out = (Byte*)buf;
+    s->stream.next_out = (Bytef*)buf;
+    s->stream.avail_out = len;
+
+    while (s->stream.avail_out != 0) {
+
+       if (s->transparent) {
+           /* Copy first the lookahead bytes: */
+           uInt n = s->stream.avail_in;
+           if (n > s->stream.avail_out) n = s->stream.avail_out;
+           if (n > 0) {
+               zmemcpy(s->stream.next_out, s->stream.next_in, n);
+               next_out += n;
+               s->stream.next_out = next_out;
+               s->stream.next_in   += n;
+               s->stream.avail_out -= n;
+               s->stream.avail_in  -= n;
+           }
+           if (s->stream.avail_out > 0) {
+               s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out,
+                                            s->file);
+           }
+           len -= s->stream.avail_out;
+           s->stream.total_in  += (uLong)len;
+           s->stream.total_out += (uLong)len;
+            if (len == 0) s->z_eof = 1;
+           return (int)len;
+       }
+        if (s->stream.avail_in == 0 && !s->z_eof) {
+
+            errno = 0;
+            s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+            if (s->stream.avail_in == 0) {
+                s->z_eof = 1;
+               if (ferror(s->file)) {
+                   s->z_err = Z_ERRNO;
+                   break;
+               }
+            }
+            s->stream.next_in = s->inbuf;
+        }
+        s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
+
+       if (s->z_err == Z_STREAM_END) {
+           /* Check CRC and original size */
+           s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+           start = s->stream.next_out;
+
+           if (getLong(s) != s->crc) {
+               s->z_err = Z_DATA_ERROR;
+           } else {
+               (void)getLong(s);
+                /* The uncompressed length returned by above getlong() may
+                 * be different from s->stream.total_out) in case of
+                * concatenated .gz files. Check for such files:
+                */
+               check_header(s);
+               if (s->z_err == Z_OK) {
+                   uLong total_in = s->stream.total_in;
+                   uLong total_out = s->stream.total_out;
+
+                   inflateReset(&(s->stream));
+                   s->stream.total_in = total_in;
+                   s->stream.total_out = total_out;
+                   s->crc = crc32(0L, Z_NULL, 0);
+               }
+           }
+       }
+       if (s->z_err != Z_OK || s->z_eof) break;
+    }
+    s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+
+    return (int)(len - s->stream.avail_out);
+}
+
+
+/* ===========================================================================
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+int ZEXPORT gzgetc(file)
+    gzFile file;
+{
+    unsigned char c;
+
+    return gzread(file, &c, 1) == 1 ? c : -1;
+}
+
+
+/* ===========================================================================
+      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.  The string is then terminated
+   with a null character.
+      gzgets returns buf, or Z_NULL in case of error.
+
+      The current implementation is not optimized at all.
+*/
+char * ZEXPORT gzgets(file, buf, len)
+    gzFile file;
+    char *buf;
+    int len;
+{
+    char *b = buf;
+    if (buf == Z_NULL || len <= 0) return Z_NULL;
+
+    while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
+    *buf = '\0';
+    return b == buf && len > 0 ? Z_NULL : b;
+}
+
+
+#ifndef NO_DEFLATE
+/* ===========================================================================
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of bytes actually written (0 in case of error).
+*/
+int ZEXPORT gzwrite (file, buf, len)
+    gzFile file;
+    const voidp buf;
+    unsigned len;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+    s->stream.next_in = (Bytef*)buf;
+    s->stream.avail_in = len;
+
+    while (s->stream.avail_in != 0) {
+
+        if (s->stream.avail_out == 0) {
+
+            s->stream.next_out = s->outbuf;
+            if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+                s->z_err = Z_ERRNO;
+                break;
+            }
+            s->stream.avail_out = Z_BUFSIZE;
+        }
+        s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
+        if (s->z_err != Z_OK) break;
+    }
+    s->crc = crc32(s->crc, (const Bytef *)buf, len);
+
+    return (int)(len - s->stream.avail_in);
+}
+
+/* ===========================================================================
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).
+*/
+#ifdef STDC
+#include <stdarg.h>
+
+int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
+{
+    char buf[Z_PRINTF_BUFSIZE];
+    va_list va;
+    int len;
+
+    va_start(va, format);
+#ifdef HAS_vsnprintf
+    (void)vsnprintf(buf, sizeof(buf), format, va);
+#else
+    (void)vsprintf(buf, format, va);
+#endif
+    va_end(va);
+    len = strlen(buf); /* some *sprintf don't return the nb of bytes written */
+    if (len <= 0) return 0;
+
+    return gzwrite(file, buf, (unsigned)len);
+}
+#else /* not ANSI C */
+
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+                      a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+    gzFile file;
+    const char *format;
+    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+       a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+    char buf[Z_PRINTF_BUFSIZE];
+    int len;
+
+#ifdef HAS_snprintf
+    snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+            a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#else
+    sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+           a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#endif
+    len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */
+    if (len <= 0) return 0;
+
+    return gzwrite(file, buf, len);
+}
+#endif
+
+/* ===========================================================================
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+int ZEXPORT gzputc(file, c)
+    gzFile file;
+    int c;
+{
+    unsigned char cc = (unsigned char) c; /* required for big endian systems */
+
+    return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
+}
+
+
+/* ===========================================================================
+      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.
+*/
+int ZEXPORT gzputs(file, s)
+    gzFile file;
+    const char *s;
+{
+    return gzwrite(file, (char*)s, (unsigned)strlen(s));
+}
+
+
+/* ===========================================================================
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function.
+*/
+local int do_flush (file, flush)
+    gzFile file;
+    int flush;
+{
+    uInt len;
+    int done = 0;
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+    s->stream.avail_in = 0; /* should be zero already anyway */
+
+    for (;;) {
+        len = Z_BUFSIZE - s->stream.avail_out;
+
+        if (len != 0) {
+            if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
+                s->z_err = Z_ERRNO;
+                return Z_ERRNO;
+            }
+            s->stream.next_out = s->outbuf;
+            s->stream.avail_out = Z_BUFSIZE;
+        }
+        if (done) break;
+        s->z_err = deflate(&(s->stream), flush);
+
+       /* Ignore the second of two consecutive flushes: */
+       if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
+
+        /* deflate has finished flushing only when it hasn't used up
+         * all the available space in the output buffer: 
+         */
+        done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
+        if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
+    }
+    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+int ZEXPORT gzflush (file, flush)
+     gzFile file;
+     int flush;
+{
+    gz_stream *s = (gz_stream*)file;
+    int err = do_flush (file, flush);
+
+    if (err) return err;
+    fflush(s->file);
+    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+#endif /* NO_DEFLATE */
+
+/* ===========================================================================
+      Sets the starting position for the next gzread or gzwrite on the given
+   compressed file. The offset represents a number of bytes in the
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error.
+      SEEK_END is not implemented, returns error.
+      In this version of the library, gzseek can be extremely slow.
+*/
+z_off_t ZEXPORT gzseek (file, offset, whence)
+    gzFile file;
+    z_off_t offset;
+    int whence;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || whence == SEEK_END ||
+       s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
+       return -1L;
+    }
+    
+    if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+       return -1L;
+#else
+       if (whence == SEEK_SET) {
+           offset -= s->stream.total_in;
+       }
+       if (offset < 0) return -1L;
+
+       /* At this point, offset is the number of zero bytes to write. */
+       if (s->inbuf == Z_NULL) {
+           s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
+           zmemzero(s->inbuf, Z_BUFSIZE);
+       }
+       while (offset > 0)  {
+           uInt size = Z_BUFSIZE;
+           if (offset < Z_BUFSIZE) size = (uInt)offset;
+
+           size = gzwrite(file, s->inbuf, size);
+           if (size == 0) return -1L;
+
+           offset -= size;
+       }
+       return (z_off_t)s->stream.total_in;
+#endif
+    }
+    /* Rest of function is for reading only */
+
+    /* compute absolute position */
+    if (whence == SEEK_CUR) {
+       offset += s->stream.total_out;
+    }
+    if (offset < 0) return -1L;
+
+    if (s->transparent) {
+       /* map to fseek */
+       s->stream.avail_in = 0;
+       s->stream.next_in = s->inbuf;
+        if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
+
+       s->stream.total_in = s->stream.total_out = (uLong)offset;
+       return offset;
+    }
+
+    /* For a negative seek, rewind and use positive seek */
+    if ((uLong)offset >= s->stream.total_out) {
+       offset -= s->stream.total_out;
+    } else if (gzrewind(file) < 0) {
+       return -1L;
+    }
+    /* offset is now the number of bytes to skip. */
+
+    if (offset != 0 && s->outbuf == Z_NULL) {
+       s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+    }
+    while (offset > 0)  {
+       int size = Z_BUFSIZE;
+       if (offset < Z_BUFSIZE) size = (int)offset;
+
+       size = gzread(file, s->outbuf, (uInt)size);
+       if (size <= 0) return -1L;
+       offset -= size;
+    }
+    return (z_off_t)s->stream.total_out;
+}
+
+/* ===========================================================================
+     Rewinds input file. 
+*/
+int ZEXPORT gzrewind (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+    
+    if (s == NULL || s->mode != 'r') return -1;
+
+    s->z_err = Z_OK;
+    s->z_eof = 0;
+    s->stream.avail_in = 0;
+    s->stream.next_in = s->inbuf;
+    s->crc = crc32(0L, Z_NULL, 0);
+       
+    if (s->startpos == 0) { /* not a compressed file */
+       rewind(s->file);
+       return 0;
+    }
+
+    (void) inflateReset(&s->stream);
+    return fseek(s->file, s->startpos, SEEK_SET);
+}
+
+/* ===========================================================================
+     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.
+*/
+z_off_t ZEXPORT gztell (file)
+    gzFile file;
+{
+    return gzseek(file, 0L, SEEK_CUR);
+}
+
+/* ===========================================================================
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+int ZEXPORT gzeof (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+    
+    return (s == NULL || s->mode != 'r') ? 0 : s->z_eof;
+}
+
+/* ===========================================================================
+   Outputs a long in LSB order to the given file
+*/
+local void putLong (file, x)
+    FILE *file;
+    uLong x;
+{
+    int n;
+    for (n = 0; n < 4; n++) {
+        fputc((int)(x & 0xff), file);
+        x >>= 8;
+    }
+}
+
+/* ===========================================================================
+   Reads a long in LSB order from the given gz_stream. Sets z_err in case
+   of error.
+*/
+local uLong getLong (s)
+    gz_stream *s;
+{
+    uLong x = (uLong)get_byte(s);
+    int c;
+
+    x += ((uLong)get_byte(s))<<8;
+    x += ((uLong)get_byte(s))<<16;
+    c = get_byte(s);
+    if (c == EOF) s->z_err = Z_DATA_ERROR;
+    x += ((uLong)c)<<24;
+    return x;
+}
+
+/* ===========================================================================
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state.
+*/
+int ZEXPORT gzclose (file)
+    gzFile file;
+{
+    int err;
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL) return Z_STREAM_ERROR;
+
+    if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+       return Z_STREAM_ERROR;
+#else
+        err = do_flush (file, Z_FINISH);
+        if (err != Z_OK) return destroy((gz_stream*)file);
+
+        putLong (s->file, s->crc);
+        putLong (s->file, s->stream.total_in);
+#endif
+    }
+    return destroy((gz_stream*)file);
+}
+
+/* ===========================================================================
+     Returns the error message for the last error which occured on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occured 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.
+*/
+const char*  ZEXPORT gzerror (file, errnum)
+    gzFile file;
+    int *errnum;
+{
+    char *m;
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL) {
+        *errnum = Z_STREAM_ERROR;
+        return (const char*)ERR_MSG(Z_STREAM_ERROR);
+    }
+    *errnum = s->z_err;
+    if (*errnum == Z_OK) return (const char*)"";
+
+    m =  (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
+
+    if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
+
+    TRYFREE(s->msg);
+    s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
+    strcpy(s->msg, s->path);
+    strcat(s->msg, ": ");
+    strcat(s->msg, m);
+    return (const char*)s->msg;
+}
diff --git a/zlib/infblock.c b/zlib/infblock.c
new file mode 100644 (file)
index 0000000..dd7a6d4
--- /dev/null
@@ -0,0 +1,403 @@
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local const uInt border[] = { /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarily, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+
+
+void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+  if (c != Z_NULL)
+    *c = s->check;
+  if (s->mode == BTREE || s->mode == DTREE)
+    ZFREE(z, s->sub.trees.blens);
+  if (s->mode == CODES)
+    inflate_codes_free(s->sub.decode.codes, z);
+  s->mode = TYPE;
+  s->bitk = 0;
+  s->bitb = 0;
+  s->read = s->write = s->window;
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
+  Tracev((stderr, "inflate:   blocks reset\n"));
+}
+
+
+inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+  inflate_blocks_statef *s;
+
+  if ((s = (inflate_blocks_statef *)ZALLOC
+       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+    return s;
+  if ((s->hufts =
+       (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL)
+  {
+    ZFREE(z, s);
+    return Z_NULL;
+  }
+  if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+  {
+    ZFREE(z, s->hufts);
+    ZFREE(z, s);
+    return Z_NULL;
+  }
+  s->end = s->window + w;
+  s->checkfn = c;
+  s->mode = TYPE;
+  Tracev((stderr, "inflate:   blocks allocated\n"));
+  inflate_blocks_reset(s, z, Z_NULL);
+  return s;
+}
+
+
+int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt t;               /* temporary storage */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input based on current state */
+  while (1) switch (s->mode)
+  {
+    case TYPE:
+      NEEDBITS(3)
+      t = (uInt)b & 7;
+      s->last = t & 1;
+      switch (t >> 1)
+      {
+        case 0:                         /* stored */
+          Tracev((stderr, "inflate:     stored block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          t = k & 7;                    /* go to byte boundary */
+          DUMPBITS(t)
+          s->mode = LENS;               /* get length of stored block */
+          break;
+        case 1:                         /* fixed */
+          Tracev((stderr, "inflate:     fixed codes block%s\n",
+                 s->last ? " (last)" : ""));
+          {
+            uInt bl, bd;
+            inflate_huft *tl, *td;
+
+            inflate_trees_fixed(&bl, &bd, &tl, &td, z);
+            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+            if (s->sub.decode.codes == Z_NULL)
+            {
+              r = Z_MEM_ERROR;
+              LEAVE
+            }
+          }
+          DUMPBITS(3)
+          s->mode = CODES;
+          break;
+        case 2:                         /* dynamic */
+          Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          s->mode = TABLE;
+          break;
+        case 3:                         /* illegal */
+          DUMPBITS(3)
+          s->mode = BAD;
+          z->msg = (char*)"invalid block type";
+          r = Z_DATA_ERROR;
+          LEAVE
+      }
+      break;
+    case LENS:
+      NEEDBITS(32)
+      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+      {
+        s->mode = BAD;
+        z->msg = (char*)"invalid stored block lengths";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+      s->sub.left = (uInt)b & 0xffff;
+      b = k = 0;                      /* dump bits */
+      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
+      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+      break;
+    case STORED:
+      if (n == 0)
+        LEAVE
+      NEEDOUT
+      t = s->sub.left;
+      if (t > n) t = n;
+      if (t > m) t = m;
+      zmemcpy(q, p, t);
+      p += t;  n -= t;
+      q += t;  m -= t;
+      if ((s->sub.left -= t) != 0)
+        break;
+      Tracev((stderr, "inflate:       stored end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      s->mode = s->last ? DRY : TYPE;
+      break;
+    case TABLE:
+      NEEDBITS(14)
+      s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+      {
+        s->mode = BAD;
+        z->msg = (char*)"too many length or distance symbols";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+#endif
+      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+      {
+        r = Z_MEM_ERROR;
+        LEAVE
+      }
+      DUMPBITS(14)
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       table sizes ok\n"));
+      s->mode = BTREE;
+    case BTREE:
+      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+      {
+        NEEDBITS(3)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+        DUMPBITS(3)
+      }
+      while (s->sub.trees.index < 19)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+      s->sub.trees.bb = 7;
+      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+                             &s->sub.trees.tb, s->hufts, z);
+      if (t != Z_OK)
+      {
+        r = t;
+        if (r == Z_DATA_ERROR)
+        {
+          ZFREE(z, s->sub.trees.blens);
+          s->mode = BAD;
+        }
+        LEAVE
+      }
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       bits tree ok\n"));
+      s->mode = DTREE;
+    case DTREE:
+      while (t = s->sub.trees.table,
+             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+      {
+        inflate_huft *h;
+        uInt i, j, c;
+
+        t = s->sub.trees.bb;
+        NEEDBITS(t)
+        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+        t = h->bits;
+        c = h->base;
+        if (c < 16)
+        {
+          DUMPBITS(t)
+          s->sub.trees.blens[s->sub.trees.index++] = c;
+        }
+        else /* c == 16..18 */
+        {
+          i = c == 18 ? 7 : c - 14;
+          j = c == 18 ? 11 : 3;
+          NEEDBITS(t + i)
+          DUMPBITS(t)
+          j += (uInt)b & inflate_mask[i];
+          DUMPBITS(i)
+          i = s->sub.trees.index;
+          t = s->sub.trees.table;
+          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+              (c == 16 && i < 1))
+          {
+            ZFREE(z, s->sub.trees.blens);
+            s->mode = BAD;
+            z->msg = (char*)"invalid bit length repeat";
+            r = Z_DATA_ERROR;
+            LEAVE
+          }
+          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+          do {
+            s->sub.trees.blens[i++] = c;
+          } while (--j);
+          s->sub.trees.index = i;
+        }
+      }
+      s->sub.trees.tb = Z_NULL;
+      {
+        uInt bl, bd;
+        inflate_huft *tl, *td;
+        inflate_codes_statef *c;
+
+        bl = 9;         /* must be <= 9 for lookahead assumptions */
+        bd = 6;         /* must be <= 9 for lookahead assumptions */
+        t = s->sub.trees.table;
+        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+                                  s->sub.trees.blens, &bl, &bd, &tl, &td,
+                                  s->hufts, z);
+        if (t != Z_OK)
+        {
+          if (t == (uInt)Z_DATA_ERROR)
+          {
+            ZFREE(z, s->sub.trees.blens);
+            s->mode = BAD;
+          }
+          r = t;
+          LEAVE
+        }
+        Tracev((stderr, "inflate:       trees ok\n"));
+        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+        {
+          r = Z_MEM_ERROR;
+          LEAVE
+        }
+        s->sub.decode.codes = c;
+      }
+      ZFREE(z, s->sub.trees.blens);
+      s->mode = CODES;
+    case CODES:
+      UPDATE
+      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+        return inflate_flush(s, z, r);
+      r = Z_OK;
+      inflate_codes_free(s->sub.decode.codes, z);
+      LOAD
+      Tracev((stderr, "inflate:       codes end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      if (!s->last)
+      {
+        s->mode = TYPE;
+        break;
+      }
+      s->mode = DRY;
+    case DRY:
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      s->mode = DONE;
+    case DONE:
+      r = Z_STREAM_END;
+      LEAVE
+    case BAD:
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+int inflate_blocks_free(s, z)
+inflate_blocks_statef *s;
+z_streamp z;
+{
+  inflate_blocks_reset(s, z, Z_NULL);
+  ZFREE(z, s->window);
+  ZFREE(z, s->hufts);
+  ZFREE(z, s);
+  Tracev((stderr, "inflate:   blocks freed\n"));
+  return Z_OK;
+}
+
+
+void inflate_set_dictionary(s, d, n)
+inflate_blocks_statef *s;
+const Bytef *d;
+uInt  n;
+{
+  zmemcpy(s->window, d, n);
+  s->read = s->write = s->window + n;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. 
+ * IN assertion: s != Z_NULL
+ */
+int inflate_blocks_sync_point(s)
+inflate_blocks_statef *s;
+{
+  return s->mode == LENS;
+}
diff --git a/zlib/infblock.h b/zlib/infblock.h
new file mode 100644 (file)
index 0000000..173b226
--- /dev/null
@@ -0,0 +1,39 @@
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995-2002 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.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+extern inflate_blocks_statef * inflate_blocks_new OF((
+    z_streamp z,
+    check_func c,               /* check function */
+    uInt w));                   /* window size */
+
+extern int inflate_blocks OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));                      /* initial return code */
+
+extern void inflate_blocks_reset OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    uLongf *));                  /* check value on output */
+
+extern int inflate_blocks_free OF((
+    inflate_blocks_statef *,
+    z_streamp));
+
+extern void inflate_set_dictionary OF((
+    inflate_blocks_statef *s,
+    const Bytef *d,  /* dictionary */
+    uInt  n));       /* dictionary length */
+
+extern int inflate_blocks_sync_point OF((
+    inflate_blocks_statef *s));
diff --git a/zlib/infcodes.c b/zlib/infcodes.c
new file mode 100644 (file)
index 0000000..9abe541
--- /dev/null
@@ -0,0 +1,251 @@
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+typedef enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+      START,    /* x: set up for LEN */
+      LEN,      /* i: get length/literal/eob next */
+      LENEXT,   /* i: getting length extra (have base) */
+      DIST,     /* i: get distance next */
+      DISTEXT,  /* i: getting distance extra */
+      COPY,     /* o: copying bytes in window, waiting for space */
+      LIT,      /* o: got literal, waiting for output space */
+      WASH,     /* o: got eob, possibly still output waiting */
+      END,      /* x: got eob and all data flushed */
+      BADCODE}  /* x: got error */
+inflate_codes_mode;
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+  /* mode */
+  inflate_codes_mode mode;      /* current inflate_codes mode */
+
+  /* mode dependent information */
+  uInt len;
+  union {
+    struct {
+      inflate_huft *tree;       /* pointer into tree */
+      uInt need;                /* bits needed */
+    } code;             /* if LEN or DIST, where in tree */
+    uInt lit;           /* if LIT, literal */
+    struct {
+      uInt get;                 /* bits to get for extra */
+      uInt dist;                /* distance back to copy from */
+    } copy;             /* if EXT or COPY, where and how much */
+  } sub;                /* submode */
+
+  /* mode independent information */
+  Byte lbits;           /* ltree bits decoded per branch */
+  Byte dbits;           /* dtree bits decoder per branch */
+  inflate_huft *ltree;          /* literal/length/eob tree */
+  inflate_huft *dtree;          /* distance tree */
+
+};
+
+
+inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+  inflate_codes_statef *c;
+
+  if ((c = (inflate_codes_statef *)
+       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+  {
+    c->mode = START;
+    c->lbits = (Byte)bl;
+    c->dbits = (Byte)bd;
+    c->ltree = tl;
+    c->dtree = td;
+    Tracev((stderr, "inflate:       codes new\n"));
+  }
+  return c;
+}
+
+
+int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt j;               /* temporary storage */
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  Bytef *f;             /* pointer to copy strings from */
+  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input and output based on current state */
+  while (1) switch (c->mode)
+  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+    case START:         /* x: set up for LEN */
+#ifndef SLOW
+      if (m >= 258 && n >= 10)
+      {
+        UPDATE
+        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+        LOAD
+        if (r != Z_OK)
+        {
+          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+          break;
+        }
+      }
+#endif /* !SLOW */
+      c->sub.code.need = c->lbits;
+      c->sub.code.tree = c->ltree;
+      c->mode = LEN;
+    case LEN:           /* i: get length/literal/eob next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e == 0)               /* literal */
+      {
+        c->sub.lit = t->base;
+        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                 "inflate:         literal '%c'\n" :
+                 "inflate:         literal 0x%02x\n", t->base));
+        c->mode = LIT;
+        break;
+      }
+      if (e & 16)               /* length */
+      {
+        c->sub.copy.get = e & 15;
+        c->len = t->base;
+        c->mode = LENEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t + t->base;
+        break;
+      }
+      if (e & 32)               /* end of block */
+      {
+        Tracevv((stderr, "inflate:         end of block\n"));
+        c->mode = WASH;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid literal/length code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case LENEXT:        /* i: getting length extra (have base) */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->len += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      c->sub.code.need = c->dbits;
+      c->sub.code.tree = c->dtree;
+      Tracevv((stderr, "inflate:         length %u\n", c->len));
+      c->mode = DIST;
+    case DIST:          /* i: get distance next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e & 16)               /* distance */
+      {
+        c->sub.copy.get = e & 15;
+        c->sub.copy.dist = t->base;
+        c->mode = DISTEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t + t->base;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid distance code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case DISTEXT:       /* i: getting distance extra */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->sub.copy.dist += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
+      c->mode = COPY;
+    case COPY:          /* o: copying bytes in window, waiting for space */
+      f = q - c->sub.copy.dist;
+      while (f < s->window)             /* modulo window size-"while" instead */
+        f += s->end - s->window;        /* of "if" handles invalid distances */
+      while (c->len)
+      {
+        NEEDOUT
+        OUTBYTE(*f++)
+        if (f == s->end)
+          f = s->window;
+        c->len--;
+      }
+      c->mode = START;
+      break;
+    case LIT:           /* o: got literal, waiting for output space */
+      NEEDOUT
+      OUTBYTE(c->sub.lit)
+      c->mode = START;
+      break;
+    case WASH:          /* o: got eob, possibly more output */
+      if (k > 7)        /* return unused byte, if any */
+      {
+        Assert(k < 16, "inflate_codes grabbed too many bytes")
+        k -= 8;
+        n++;
+        p--;            /* can always return one */
+      }
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      c->mode = END;
+    case END:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADCODE:       /* x: got error */
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+#ifdef NEED_DUMMY_RETURN
+  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
+#endif
+}
+
+
+void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+  ZFREE(z, c);
+  Tracev((stderr, "inflate:       codes free\n"));
+}
diff --git a/zlib/infcodes.h b/zlib/infcodes.h
new file mode 100644 (file)
index 0000000..46821a0
--- /dev/null
@@ -0,0 +1,27 @@
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995-2002 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.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+extern inflate_codes_statef *inflate_codes_new OF((
+    uInt, uInt,
+    inflate_huft *, inflate_huft *,
+    z_streamp ));
+
+extern int inflate_codes OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+extern void inflate_codes_free OF((
+    inflate_codes_statef *,
+    z_streamp ));
+
diff --git a/zlib/inffast.c b/zlib/inffast.c
new file mode 100644 (file)
index 0000000..aa7f1d4
--- /dev/null
@@ -0,0 +1,183 @@
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
+
+/* Called with number of bytes left to write in window at least 258
+   (the maximum string length) and number of input bytes available
+   at least ten.  The ten bytes are six bytes for the longest length/
+   distance pair plus four bytes for overloading the bit buffer. */
+
+int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+inflate_blocks_statef *s;
+z_streamp z;
+{
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  uInt ml;              /* mask for literal/length tree */
+  uInt md;              /* mask for distance tree */
+  uInt c;               /* bytes to copy */
+  uInt d;               /* distance back to copy from */
+  Bytef *r;             /* copy source pointer */
+
+  /* load input, output, bit values */
+  LOAD
+
+  /* initialize masks */
+  ml = inflate_mask[bl];
+  md = inflate_mask[bd];
+
+  /* do until not enough input or output space for fast loop */
+  do {                          /* assume called with m >= 258 && n >= 10 */
+    /* get literal/length code */
+    GRABBITS(20)                /* max bits for literal/length code */
+    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+    {
+      DUMPBITS(t->bits)
+      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                "inflate:         * literal '%c'\n" :
+                "inflate:         * literal 0x%02x\n", t->base));
+      *q++ = (Byte)t->base;
+      m--;
+      continue;
+    }
+    do {
+      DUMPBITS(t->bits)
+      if (e & 16)
+      {
+        /* get extra bits for length */
+        e &= 15;
+        c = t->base + ((uInt)b & inflate_mask[e]);
+        DUMPBITS(e)
+        Tracevv((stderr, "inflate:         * length %u\n", c));
+
+        /* decode distance base of block to copy */
+        GRABBITS(15);           /* max bits for distance code */
+        e = (t = td + ((uInt)b & md))->exop;
+        do {
+          DUMPBITS(t->bits)
+          if (e & 16)
+          {
+            /* get extra bits to add to distance base */
+            e &= 15;
+            GRABBITS(e)         /* get extra bits (up to 13) */
+            d = t->base + ((uInt)b & inflate_mask[e]);
+            DUMPBITS(e)
+            Tracevv((stderr, "inflate:         * distance %u\n", d));
+
+            /* do the copy */
+            m -= c;
+            r = q - d;
+            if (r < s->window)                  /* wrap if needed */
+            {
+              do {
+                r += s->end - s->window;        /* force pointer in window */
+              } while (r < s->window);          /* covers invalid distances */
+              e = s->end - r;
+              if (c > e)
+              {
+                c -= e;                         /* wrapped copy */
+                do {
+                    *q++ = *r++;
+                } while (--e);
+                r = s->window;
+                do {
+                    *q++ = *r++;
+                } while (--c);
+              }
+              else                              /* normal copy */
+              {
+                *q++ = *r++;  c--;
+                *q++ = *r++;  c--;
+                do {
+                    *q++ = *r++;
+                } while (--c);
+              }
+            }
+            else                                /* normal copy */
+            {
+              *q++ = *r++;  c--;
+              *q++ = *r++;  c--;
+              do {
+                *q++ = *r++;
+              } while (--c);
+            }
+            break;
+          }
+          else if ((e & 64) == 0)
+          {
+            t += t->base;
+            e = (t += ((uInt)b & inflate_mask[e]))->exop;
+          }
+          else
+          {
+            z->msg = (char*)"invalid distance code";
+            UNGRAB
+            UPDATE
+            return Z_DATA_ERROR;
+          }
+        } while (1);
+        break;
+      }
+      if ((e & 64) == 0)
+      {
+        t += t->base;
+        if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)
+        {
+          DUMPBITS(t->bits)
+          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                    "inflate:         * literal '%c'\n" :
+                    "inflate:         * literal 0x%02x\n", t->base));
+          *q++ = (Byte)t->base;
+          m--;
+          break;
+        }
+      }
+      else if (e & 32)
+      {
+        Tracevv((stderr, "inflate:         * end of block\n"));
+        UNGRAB
+        UPDATE
+        return Z_STREAM_END;
+      }
+      else
+      {
+        z->msg = (char*)"invalid literal/length code";
+        UNGRAB
+        UPDATE
+        return Z_DATA_ERROR;
+      }
+    } while (1);
+  } while (m >= 258 && n >= 10);
+
+  /* not enough input or output--restore pointers and return */
+  UNGRAB
+  UPDATE
+  return Z_OK;
+}
diff --git a/zlib/inffast.h b/zlib/inffast.h
new file mode 100644 (file)
index 0000000..a31a4bb
--- /dev/null
@@ -0,0 +1,17 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2002 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.
+ */
+
+extern int inflate_fast OF((
+    uInt,
+    uInt,
+    inflate_huft *,
+    inflate_huft *,
+    inflate_blocks_statef *,
+    z_streamp ));
diff --git a/zlib/inffixed.h b/zlib/inffixed.h
new file mode 100644 (file)
index 0000000..77f7e76
--- /dev/null
@@ -0,0 +1,151 @@
+/* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by the maketree.c program
+ */
+
+/* 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.
+ */
+
+local uInt fixed_bl = 9;
+local uInt fixed_bd = 5;
+local inflate_huft fixed_tl[] = {
+    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
+    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
+    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
+    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
+    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
+    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
+    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
+    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
+    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
+    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
+    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
+    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
+    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
+    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
+    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
+    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
+    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
+    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
+    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
+    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
+    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
+    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
+    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
+    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
+    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
+    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
+    {{{82,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}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
+    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
+    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
+    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
+    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
+    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
+    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
+    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
+    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
+    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
+    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
+    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
+    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
+    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
+    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
+    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
+    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
+    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
+    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
+    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
+    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
+    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
+    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
+    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
+    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
+    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
+    {{{82,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}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
+    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
+    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
+    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
+    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
+    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
+    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
+    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
+    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
+    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
+    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
+    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
+    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
+    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
+    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
+    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
+    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
+    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
+    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
+    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
+    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
+    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
+    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
+    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
+    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
+    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
+    {{{82,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}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
+    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
+    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
+    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
+    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
+    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
+    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
+    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
+    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
+    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
+    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
+    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
+    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
+    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
+    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
+    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
+    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
+    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
+    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
+    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
+    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
+    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
+    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
+    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
+    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
+    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
+    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
+    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
+  };
+local inflate_huft fixed_td[] = {
+    {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
+    {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
+    {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
+    {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
+    {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
+    {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
+    {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
+    {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
+  };
diff --git a/zlib/inflate.c b/zlib/inflate.c
new file mode 100644 (file)
index 0000000..dfb2e86
--- /dev/null
@@ -0,0 +1,366 @@
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+
+struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
+
+typedef enum {
+      METHOD,   /* waiting for method byte */
+      FLAG,     /* waiting for flag byte */
+      DICT4,    /* four dictionary check bytes to go */
+      DICT3,    /* three dictionary check bytes to go */
+      DICT2,    /* two dictionary check bytes to go */
+      DICT1,    /* one dictionary check byte to go */
+      DICT0,    /* waiting for inflateSetDictionary */
+      BLOCKS,   /* decompressing blocks */
+      CHECK4,   /* four check bytes to go */
+      CHECK3,   /* three check bytes to go */
+      CHECK2,   /* two check bytes to go */
+      CHECK1,   /* one check byte to go */
+      DONE,     /* finished check, done */
+      BAD}      /* got an error--stay here */
+inflate_mode;
+
+/* inflate private state */
+struct internal_state {
+
+  /* mode */
+  inflate_mode  mode;   /* current inflate mode */
+
+  /* mode dependent information */
+  union {
+    uInt method;        /* if FLAGS, method byte */
+    struct {
+      uLong was;                /* computed check value */
+      uLong need;               /* stream check value */
+    } check;            /* if CHECK, check values to compare */
+    uInt marker;        /* if BAD, inflateSync's marker bytes count */
+  } sub;        /* submode */
+
+  /* mode independent information */
+  int  nowrap;          /* flag for no wrapper */
+  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
+  inflate_blocks_statef 
+    *blocks;            /* current inflate_blocks state */
+
+};
+
+
+int ZEXPORT inflateReset(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->total_in = z->total_out = 0;
+  z->msg = Z_NULL;
+  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+  inflate_blocks_reset(z->state->blocks, z, Z_NULL);
+  Tracev((stderr, "inflate: reset\n"));
+  return Z_OK;
+}
+
+
+int ZEXPORT inflateEnd(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->blocks != Z_NULL)
+    inflate_blocks_free(z->state->blocks, z);
+  ZFREE(z, z->state);
+  z->state = Z_NULL;
+  Tracev((stderr, "inflate: end\n"));
+  return Z_OK;
+}
+
+
+int ZEXPORT inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+      stream_size != sizeof(z_stream))
+      return Z_VERSION_ERROR;
+
+  /* initialize state */
+  if (z == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->msg = Z_NULL;
+  if (z->zalloc == Z_NULL)
+  {
+    z->zalloc = zcalloc;
+    z->opaque = (voidpf)0;
+  }
+  if (z->zfree == Z_NULL) z->zfree = zcfree;
+  if ((z->state = (struct internal_state FAR *)
+       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+    return Z_MEM_ERROR;
+  z->state->blocks = Z_NULL;
+
+  /* handle undocumented nowrap option (no zlib header or check) */
+  z->state->nowrap = 0;
+  if (w < 0)
+  {
+    w = - w;
+    z->state->nowrap = 1;
+  }
+
+  /* set window size */
+  if (w < 8 || w > 15)
+  {
+    inflateEnd(z);
+    return Z_STREAM_ERROR;
+  }
+  z->state->wbits = (uInt)w;
+
+  /* create inflate_blocks state */
+  if ((z->state->blocks =
+      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
+      == Z_NULL)
+  {
+    inflateEnd(z);
+    return Z_MEM_ERROR;
+  }
+  Tracev((stderr, "inflate: allocated\n"));
+
+  /* reset state */
+  inflateReset(z);
+  return Z_OK;
+}
+
+
+int ZEXPORT inflateInit_(z, version, stream_size)
+z_streamp z;
+const char *version;
+int stream_size;
+{
+  return inflateInit2_(z, DEF_WBITS, version, stream_size);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int ZEXPORT inflate(z, f)
+z_streamp z;
+int f;
+{
+  int r;
+  uInt b;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
+    return Z_STREAM_ERROR;
+  f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+  r = Z_BUF_ERROR;
+  while (1) switch (z->state->mode)
+  {
+    case METHOD:
+      NEEDBYTE
+      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"unknown compression method";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"invalid window size";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = FLAG;
+    case FLAG:
+      NEEDBYTE
+      b = NEXTBYTE;
+      if (((z->state->sub.method << 8) + b) % 31)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"incorrect header check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Tracev((stderr, "inflate: zlib header ok\n"));
+      if (!(b & PRESET_DICT))
+      {
+        z->state->mode = BLOCKS;
+        break;
+      }
+      z->state->mode = DICT4;
+    case DICT4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = DICT3;
+    case DICT3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = DICT2;
+    case DICT2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = DICT1;
+    case DICT1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+      z->adler = z->state->sub.check.need;
+      z->state->mode = DICT0;
+      return Z_NEED_DICT;
+    case DICT0:
+      z->state->mode = BAD;
+      z->msg = (char*)"need dictionary";
+      z->state->sub.marker = 0;       /* can try inflateSync */
+      return Z_STREAM_ERROR;
+    case BLOCKS:
+      r = inflate_blocks(z->state->blocks, z, r);
+      if (r == Z_DATA_ERROR)
+      {
+        z->state->mode = BAD;
+        z->state->sub.marker = 0;       /* can try inflateSync */
+        break;
+      }
+      if (r == Z_OK)
+        r = f;
+      if (r != Z_STREAM_END)
+        return r;
+      r = f;
+      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      if (z->state->nowrap)
+      {
+        z->state->mode = DONE;
+        break;
+      }
+      z->state->mode = CHECK4;
+    case CHECK4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = CHECK3;
+    case CHECK3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = CHECK2;
+    case CHECK2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = CHECK1;
+    case CHECK1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+
+      if (z->state->sub.check.was != z->state->sub.check.need)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"incorrect data check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Tracev((stderr, "inflate: zlib check ok\n"));
+      z->state->mode = DONE;
+    case DONE:
+      return Z_STREAM_END;
+    case BAD:
+      return Z_DATA_ERROR;
+    default:
+      return Z_STREAM_ERROR;
+  }
+#ifdef NEED_DUMMY_RETURN
+  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
+#endif
+}
+
+
+int ZEXPORT inflateSetDictionary(z, dictionary, dictLength)
+z_streamp z;
+const Bytef *dictionary;
+uInt  dictLength;
+{
+  uInt length = dictLength;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
+    return Z_STREAM_ERROR;
+
+  if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
+  z->adler = 1L;
+
+  if (length >= ((uInt)1<<z->state->wbits))
+  {
+    length = (1<<z->state->wbits)-1;
+    dictionary += dictLength - length;
+  }
+  inflate_set_dictionary(z->state->blocks, dictionary, length);
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+
+int ZEXPORT inflateSync(z)
+z_streamp z;
+{
+  uInt n;       /* number of bytes to look at */
+  Bytef *p;     /* pointer to bytes */
+  uInt m;       /* number of marker bytes found in a row */
+  uLong r, w;   /* temporaries to save total_in and total_out */
+
+  /* set up */
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->mode != BAD)
+  {
+    z->state->mode = BAD;
+    z->state->sub.marker = 0;
+  }
+  if ((n = z->avail_in) == 0)
+    return Z_BUF_ERROR;
+  p = z->next_in;
+  m = z->state->sub.marker;
+
+  /* search */
+  while (n && m < 4)
+  {
+    static const Byte mark[4] = {0, 0, 0xff, 0xff};
+    if (*p == mark[m])
+      m++;
+    else if (*p)
+      m = 0;
+    else
+      m = 4 - m;
+    p++, n--;
+  }
+
+  /* restore */
+  z->total_in += p - z->next_in;
+  z->next_in = p;
+  z->avail_in = n;
+  z->state->sub.marker = m;
+
+  /* return no joy or set up to restart on a new block */
+  if (m != 4)
+    return Z_DATA_ERROR;
+  r = z->total_in;  w = z->total_out;
+  inflateReset(z);
+  z->total_in = r;  z->total_out = w;
+  z->state->mode = BLOCKS;
+  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)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
+    return Z_STREAM_ERROR;
+  return inflate_blocks_sync_point(z->state->blocks);
+}
diff --git a/zlib/inftrees.c b/zlib/inftrees.c
new file mode 100644 (file)
index 0000000..4c32ca3
--- /dev/null
@@ -0,0 +1,454 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#if !defined(BUILDFIXED) && !defined(STDC)
+#  define BUILDFIXED   /* non ANSI compilers may not accept inffixed.h */
+#endif
+
+const char inflate_copyright[] =
+   " inflate 1.1.4 Copyright 1995-2002 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.
+ */
+struct internal_state  {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+    uIntf *,            /* code lengths in bits */
+    uInt,               /* number of codes */
+    uInt,               /* number of "simple" codes */
+    const uIntf *,      /* list of base values for non-simple codes */
+    const uIntf *,      /* list of extra bits for non-simple codes */
+    inflate_huft * FAR*,/* result: starting table */
+    uIntf *,            /* maximum lookup bits (returns actual) */
+    inflate_huft *,     /* space for trees */
+    uInt *,             /* hufts used in space */
+    uIntf * ));         /* space for values */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
+        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};
+        /* see note #13 above about 258 */
+local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
+        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, 112, 112}; /* 112==invalid */
+local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
+        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};
+local const uInt cpdext[30] = { /* Extra bits for distance codes */
+        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};
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15         /* maximum bit length of any code */
+
+local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
+uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
+uInt n;                 /* number of codes (assumed <= 288) */
+uInt s;                 /* number of simple-valued codes (0..s-1) */
+const uIntf *d;         /* list of base values for non-simple codes */
+const uIntf *e;         /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t;  /* result: starting table */
+uIntf *m;               /* maximum lookup bits, returns actual */
+inflate_huft *hp;       /* space for trees */
+uInt *hn;               /* hufts used in space */
+uIntf *v;               /* working area: values in order of bit length */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
+   if the given code set is incomplete (the tables are still built in this
+   case), or Z_DATA_ERROR if the input is invalid. */
+{
+
+  uInt a;                       /* counter for codes of length k */
+  uInt c[BMAX+1];               /* bit length count table */
+  uInt f;                       /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register uInt i;              /* counter, current code */
+  register uInt j;              /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  uInt mask;                    /* (1 << w) - 1, to avoid cc -O bug on HP */
+  register uIntf *p;            /* pointer into c[], b[], or v[] */
+  inflate_huft *q;              /* points to current table */
+  struct inflate_huft_s r;      /* table entry for structure assignment */
+  inflate_huft *u[BMAX];        /* table stack */
+  register int w;               /* bits before this table == (l * h) */
+  uInt x[BMAX+1];               /* bit offsets, then code stack */
+  uIntf *xp;                    /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  uInt z;                       /* number of entries in current table */
+
+
+  /* Generate counts for each bit length */
+  p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+  C4                            /* clear c[]--assume BMAX+1 is 16 */
+  p = b;  i = n;
+  do {
+    c[*p++]++;                  /* assume all entries <= BMAX */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (inflate_huft *)Z_NULL;
+    *m = 0;
+    return Z_OK;
+  }
+
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((uInt)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((uInt)l > i)
+    l = i;
+  *m = l;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return Z_DATA_ERROR;
+  if ((y -= c[i]) < 0)
+    return Z_DATA_ERROR;
+  c[i] += y;
+
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+  n = x[g];                     /* set n to length of v */
+
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
+  q = (inflate_huft *)Z_NULL;   /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+    a = c[k];
+    while (a--)
+    {
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = g - w;
+        z = z > (uInt)l ? l : z;        /* table size upper limit */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          if (j < z)
+            while (++j < z)     /* try smaller tables up to z bits */
+            {
+              if ((f <<= 1) <= *++xp)
+                break;          /* enough codes to use up j bits */
+              f -= *xp;         /* else deduct codes from patterns */
+            }
+        }
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate new table */
+        if (*hn + z > MANY)     /* (note: doesn't matter for fixed) */
+          return Z_DATA_ERROR;  /* overflow of MANY */
+        u[h] = q = hp + *hn;
+        *hn += z;
+
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.bits = (Byte)l;     /* bits to dump before this table */
+          r.exop = (Byte)j;     /* bits in this table */
+          j = i >> (w - l);
+          r.base = (uInt)(q - u[h-1] - j);   /* offset to this table */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+        else
+          *t = q;               /* first table is returned result */
+      }
+
+      /* set up table entry in r */
+      r.bits = (Byte)(k - w);
+      if (p >= v + n)
+        r.exop = 128 + 64;      /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
+        r.base = *p++;          /* simple code is just the value */
+      }
+      else
+      {
+        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
+        r.base = d[*p++ - s];
+      }
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      mask = (1 << w) - 1;      /* needed on HP, cc -O bug */
+      while ((i & mask) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+        mask = (1 << w) - 1;
+      }
+    }
+  }
+
+
+  /* Return Z_BUF_ERROR if we were given an incomplete table */
+  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+int inflate_trees_bits(c, bb, tb, hp, z)
+uIntf *c;               /* 19 code lengths */
+uIntf *bb;              /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+inflate_huft *hp;       /* space for trees */
+z_streamp z;            /* for messages */
+{
+  int r;
+  uInt hn = 0;          /* hufts used in space */
+  uIntf *v;             /* work area for huft_build */
+
+  if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL)
+    return Z_MEM_ERROR;
+  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
+                 tb, bb, hp, &hn, v);
+  if (r == Z_DATA_ERROR)
+    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+  else if (r == Z_BUF_ERROR || *bb == 0)
+  {
+    z->msg = (char*)"incomplete dynamic bit lengths tree";
+    r = Z_DATA_ERROR;
+  }
+  ZFREE(z, v);
+  return r;
+}
+
+
+int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
+uInt nl;                /* number of literal/length codes */
+uInt nd;                /* number of distance codes */
+uIntf *c;               /* that many (total) code lengths */
+uIntf *bl;              /* literal desired/actual bit depth */
+uIntf *bd;              /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+inflate_huft *hp;       /* space for trees */
+z_streamp z;            /* for messages */
+{
+  int r;
+  uInt hn = 0;          /* hufts used in space */
+  uIntf *v;             /* work area for huft_build */
+
+  /* allocate work area */
+  if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+    return Z_MEM_ERROR;
+
+  /* build literal/length tree */
+  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
+  if (r != Z_OK || *bl == 0)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed literal/length tree";
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    ZFREE(z, v);
+    return r;
+  }
+
+  /* build distance tree */
+  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
+  if (r != Z_OK || (*bd == 0 && nl > 257))
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed distance tree";
+    else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+      r = Z_OK;
+    }
+#else
+      z->msg = (char*)"incomplete distance tree";
+      r = Z_DATA_ERROR;
+    }
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"empty distance tree with lengths";
+      r = Z_DATA_ERROR;
+    }
+    ZFREE(z, v);
+    return r;
+#endif
+  }
+
+  /* done */
+  ZFREE(z, v);
+  return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+#ifdef BUILDFIXED
+local int fixed_built = 0;
+#define FIXEDH 544      /* number of hufts used by fixed tables */
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+#else
+#include "inffixed.h"
+#endif
+
+
+int inflate_trees_fixed(bl, bd, tl, td, z)
+uIntf *bl;               /* literal desired/actual bit depth */
+uIntf *bd;               /* distance desired/actual bit depth */
+inflate_huft * FAR *tl;  /* literal/length tree result */
+inflate_huft * FAR *td;  /* distance tree result */
+z_streamp z;             /* for memory allocation */
+{
+#ifdef BUILDFIXED
+  /* build fixed tables if not already */
+  if (!fixed_built)
+  {
+    int k;              /* temporary variable */
+    uInt f = 0;         /* number of hufts used in fixed_mem */
+    uIntf *c;           /* length list for huft_build */
+    uIntf *v;           /* work area for huft_build */
+
+    /* allocate memory */
+    if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+      return Z_MEM_ERROR;
+    if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+    {
+      ZFREE(z, c);
+      return Z_MEM_ERROR;
+    }
+
+    /* literal table */
+    for (k = 0; k < 144; k++)
+      c[k] = 8;
+    for (; k < 256; k++)
+      c[k] = 9;
+    for (; k < 280; k++)
+      c[k] = 7;
+    for (; k < 288; k++)
+      c[k] = 8;
+    fixed_bl = 9;
+    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl,
+               fixed_mem, &f, v);
+
+    /* distance table */
+    for (k = 0; k < 30; k++)
+      c[k] = 5;
+    fixed_bd = 5;
+    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd,
+               fixed_mem, &f, v);
+
+    /* done */
+    ZFREE(z, v);
+    ZFREE(z, c);
+    fixed_built = 1;
+  }
+#endif
+  *bl = fixed_bl;
+  *bd = fixed_bd;
+  *tl = fixed_tl;
+  *td = fixed_td;
+  return Z_OK;
+}
diff --git a/zlib/inftrees.h b/zlib/inftrees.h
new file mode 100644 (file)
index 0000000..04b73b7
--- /dev/null
@@ -0,0 +1,58 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2002 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.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+  union {
+    struct {
+      Byte Exop;        /* number of extra bits or operation */
+      Byte Bits;        /* number of bits in this code or subcode */
+    } what;
+    uInt pad;           /* pad structure to a power of 2 (4 bytes for */
+  } word;               /*  16-bit, 8 bytes for 32-bit int's) */
+  uInt base;            /* literal, length base, distance base,
+                           or table offset */
+};
+
+/* Maximum size of dynamic tree.  The maximum found in a long but non-
+   exhaustive search was 1004 huft structures (850 for length/literals
+   and 154 for distances, the latter actually the result of an
+   exhaustive search).  The actual maximum is not known, but the
+   value below is more than safe. */
+#define MANY 1440
+
+extern int inflate_trees_bits OF((
+    uIntf *,                    /* 19 code lengths */
+    uIntf *,                    /* bits tree desired/actual depth */
+    inflate_huft * FAR *,       /* bits tree result */
+    inflate_huft *,             /* space for trees */
+    z_streamp));                /* for messages */
+
+extern int inflate_trees_dynamic OF((
+    uInt,                       /* number of literal/length codes */
+    uInt,                       /* number of distance codes */
+    uIntf *,                    /* that many (total) code lengths */
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    inflate_huft *,             /* space for trees */
+    z_streamp));                /* for messages */
+
+extern int inflate_trees_fixed OF((
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    z_streamp));                /* for memory allocation */
diff --git a/zlib/infutil.c b/zlib/infutil.c
new file mode 100644 (file)
index 0000000..9a07622
--- /dev/null
@@ -0,0 +1,87 @@
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* And'ing with mask[n] masks the lower n bits */
+uInt inflate_mask[17] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+
+/* copy as much as possible from the sliding window to the output area */
+int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt n;
+  Bytef *p;
+  Bytef *q;
+
+  /* local copies of source and destination pointers */
+  p = z->next_out;
+  q = s->read;
+
+  /* compute number of bytes to copy as far as end of window */
+  n = (uInt)((q <= s->write ? s->write : s->end) - q);
+  if (n > z->avail_out) n = z->avail_out;
+  if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+  /* update counters */
+  z->avail_out -= n;
+  z->total_out += n;
+
+  /* update check information */
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+  /* copy as far as end of window */
+  zmemcpy(p, q, n);
+  p += n;
+  q += n;
+
+  /* see if more to copy at beginning of window */
+  if (q == s->end)
+  {
+    /* wrap pointers */
+    q = s->window;
+    if (s->write == s->end)
+      s->write = s->window;
+
+    /* compute bytes to copy */
+    n = (uInt)(s->write - q);
+    if (n > z->avail_out) n = z->avail_out;
+    if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+    /* update counters */
+    z->avail_out -= n;
+    z->total_out += n;
+
+    /* update check information */
+    if (s->checkfn != Z_NULL)
+      z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+    /* copy */
+    zmemcpy(p, q, n);
+    p += n;
+    q += n;
+  }
+
+  /* update pointers */
+  z->next_out = p;
+  s->read = q;
+
+  /* done */
+  return r;
+}
diff --git a/zlib/infutil.h b/zlib/infutil.h
new file mode 100644 (file)
index 0000000..4401df8
--- /dev/null
@@ -0,0 +1,98 @@
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-2002 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.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+typedef enum {
+      TYPE,     /* get type bits (3, including end bit) */
+      LENS,     /* get lengths for stored */
+      STORED,   /* processing stored block */
+      TABLE,    /* get table lengths */
+      BTREE,    /* get bit lengths tree for a dynamic block */
+      DTREE,    /* get length, distance trees for a dynamic block */
+      CODES,    /* processing fixed or dynamic block */
+      DRY,      /* output remaining window bytes */
+      DONE,     /* finished last block, done */
+      BAD}      /* got a data error--stuck here */
+inflate_block_mode;
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+  /* mode */
+  inflate_block_mode  mode;     /* current inflate_block mode */
+
+  /* mode dependent information */
+  union {
+    uInt left;          /* if STORED, bytes left to copy */
+    struct {
+      uInt table;               /* table lengths (14 bits) */
+      uInt index;               /* index into blens (or border) */
+      uIntf *blens;             /* bit lengths of codes */
+      uInt bb;                  /* bit length tree depth */
+      inflate_huft *tb;         /* bit length decoding tree */
+    } trees;            /* if DTREE, decoding info for trees */
+    struct {
+      inflate_codes_statef 
+         *codes;
+    } decode;           /* if CODES, current state */
+  } sub;                /* submode */
+  uInt last;            /* true if this block is the last block */
+
+  /* mode independent information */
+  uInt bitk;            /* bits in bit buffer */
+  uLong bitb;           /* bit buffer */
+  inflate_huft *hufts;  /* single malloc for tree space */
+  Bytef *window;        /* sliding window */
+  Bytef *end;           /* one byte after sliding window */
+  Bytef *read;          /* window read pointer */
+  Bytef *write;         /* window write pointer */
+  check_func checkfn;   /* check function */
+  uLong check;          /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/*   update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/*   get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/*   output bytes */
+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/*   load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
+extern uInt inflate_mask[17];
+
+/* copy as much as possible from the sliding window to the output area */
+extern int inflate_flush OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+struct internal_state      {int dummy;}; /* for buggy compilers */
+
+#endif
diff --git a/zlib/maketree.c b/zlib/maketree.c
new file mode 100644 (file)
index 0000000..a16d4b1
--- /dev/null
@@ -0,0 +1,85 @@
+/* maketree.c -- make inffixed.h table for decoding fixed codes
+ * Copyright (C) 1995-2002 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.
+ */
+
+/* This program is included in the distribution for completeness.
+   You do not need to compile or run this program since inffixed.h
+   is already included in the distribution.  To use this program
+   you need to compile zlib with BUILDFIXED defined and then compile
+   and link this program with the zlib library.  Then the output of
+   this program can be piped to inffixed.h. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "zutil.h"
+#include "inftrees.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* generate initialization table for an inflate_huft structure array */
+void maketree(uInt b, inflate_huft *t)
+{
+  int i, e;
+
+  i = 0;
+  while (1)
+  {
+    e = t[i].exop;
+    if (e && (e & (16+64)) == 0)        /* table pointer */
+    {
+      fprintf(stderr, "maketree: cannot initialize sub-tables!\n");
+      exit(1);
+    }
+    if (i % 4 == 0)
+      printf("\n   ");
+    printf(" {{{%u,%u}},%u}", t[i].exop, t[i].bits, t[i].base);
+    if (++i == (1<<b))
+      break;
+    putchar(',');
+  }
+  puts("");
+}
+
+/* create the fixed tables in C initialization syntax */
+void main(void)
+{
+  int r;
+  uInt bl, bd;
+  inflate_huft *tl, *td;
+  z_stream z;
+
+  z.zalloc = zcalloc;
+  z.opaque = (voidpf)0;
+  z.zfree = zcfree;
+  r = inflate_trees_fixed(&bl, &bd, &tl, &td, &z);
+  if (r)
+  {
+    fprintf(stderr, "inflate_trees_fixed error %d\n", r);
+    return;
+  }
+  puts("/* inffixed.h -- table for decoding fixed codes");
+  puts(" * Generated automatically by the maketree.c program");
+  puts(" */");
+  puts("");
+  puts("/* WARNING: this file should *not* be used by applications. It is");
+  puts("   part of the implementation of the compression library and is");
+  puts("   subject to change. Applications should only use zlib.h.");
+  puts(" */");
+  puts("");
+  printf("local uInt fixed_bl = %d;\n", bl);
+  printf("local uInt fixed_bd = %d;\n", bd);
+  printf("local inflate_huft fixed_tl[] = {");
+  maketree(bl, tl);
+  puts("  };");
+  printf("local inflate_huft fixed_td[] = {");
+  maketree(bd, td);
+  puts("  };");
+}
diff --git a/zlib/readme b/zlib/readme
new file mode 100644 (file)
index 0000000..8ff4587
--- /dev/null
@@ -0,0 +1,148 @@
+zlib 1.1.3 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 
+ftp://ds.internic.net/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate
+format) and rfc1952.txt (gzip format). These documents are also available in
+other formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+
+All functions of the compression library are documented in the file zlib.h
+(volunteer to write man pages welcome, contact jloup@gzip.org). A usage
+example of the library is given in the file example.c which also tests that
+the library is working correctly. Another example is given in the file
+minigzip.c. The compression library itself is composed of all source files
+except example.c and minigzip.c.
+
+To compile all files and run the test program, follow the instructions
+given at the top of Makefile. In short "make test; make install"
+should work for most machines. For Unix: "configure; make test; make install"
+For MSDOS, use one of the special makefiles such as Makefile.msc.
+For VMS, use Make_vms.com or descrip.mms.
+
+Questions about zlib should be sent to <zlib@quest.jpl.nasa.gov>, or to
+Gilles Vollant <info@winimage.com> for the Windows DLL version.
+The zlib home page is http://www.cdrom.com/pub/infozip/zlib/
+The official zlib ftp site is ftp://ftp.cdrom.com/pub/infozip/zlib/
+Before reporting a problem, please check those sites to verify that
+you have the latest version of zlib; otherwise get the latest version and
+check whether the problem still exists or not.
+
+Mark Nelson <markn@tiny.com> wrote an article about zlib for the Jan. 1997
+issue of  Dr. Dobb's Journal; a copy of the article is available in
+http://web2.airmail.net/markn/articles/zlibtool/zlibtool.htm
+
+The changes made in version 1.1.3 are documented in the file ChangeLog.
+The main changes since 1.1.2 are:
+
+- fix "an inflate input buffer bug that shows up on rare but persistent
+  occasions" (Mark)
+- fix gzread and gztell for concatenated .gz files (Didier Le Botlan)
+- fix gzseek(..., SEEK_SET) in write mode
+- fix crc check after a gzeek (Frank Faubert)
+- fix miniunzip when the last entry in a zip file is itself a zip file
+  (J Lillge)
+- add contrib/asm586 and contrib/asm686 (Brian Raiter)
+  See http://www.muppetlabs.com/~breadbox/software/assembly.html
+- add support for Delphi 3 in contrib/delphi (Bob Dellaca)
+- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti)
+- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren)
+- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks)
+- added a FAQ file
+
+plus many changes for portability.
+
+Unsupported third party contributions are provided in directory "contrib".
+
+A Java implementation of zlib is available in the Java Development Kit 1.1
+http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html
+See the zlib home page http://www.cdrom.com/pub/infozip/zlib/ for details.
+
+A Perl interface to zlib written by Paul Marquess <pmarquess@bfsec.bt.co.uk>
+is in the CPAN (Comprehensive Perl Archive Network) sites, such as:
+ftp://ftp.cis.ufl.edu/pub/perl/CPAN/modules/by-module/Compress/Compress-Zlib*
+
+A Python interface to zlib written by A.M. Kuchling <amk@magnet.com>
+is available in Python 1.5 and later versions, see
+http://www.python.org/doc/lib/module-zlib.html
+
+A zlib binding for TCL written by Andreas Kupries <a.kupries@westend.com>
+is availlable at http://www.westend.com/~kupries/doc/trf/man/man.html
+
+An experimental package to read and write files in .zip format,
+written on top of zlib by Gilles Vollant <info@winimage.com>, is
+available at http://www.winimage.com/zLibDll/unzip.html
+and also in the contrib/minizip directory of zlib.
+
+
+Notes for some targets:
+
+- To build a Windows DLL version, include in a DLL project zlib.def, zlib.rc
+  and all .c files except example.c and minigzip.c; compile with -DZLIB_DLL
+  The zlib DLL support was initially done by Alessandro Iacopetti and is
+  now maintained by Gilles Vollant <info@winimage.com>. Check the zlib DLL
+  home page at http://www.winimage.com/zLibDll
+
+  From Visual Basic, you can call the DLL functions which do not take
+  a structure as argument: compress, uncompress and all gz* functions.
+  See contrib/visual-basic.txt for more information, or get
+  http://www.tcfb.com/dowseware/cmp-z-it.zip
+
+- 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, BEOS and by some Mac compilers.
+
+- For Turbo C the small model is supported only with reduced performance to
+  avoid any far allocation; it was tested with -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3
+
+- For PalmOs, see http://www.cs.uit.no/~perm/PASTA/pilot/software.html
+  Per Harald Myrvang <perm@stud.cs.uit.no>
+
+
+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-1998 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.
diff --git a/zlib/trees.c b/zlib/trees.c
new file mode 100644 (file)
index 0000000..c98b000
--- /dev/null
@@ -0,0 +1,1214 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2002 Jean-loup Gailly
+ * 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,v 1.2 2002/03/13 17:45:56 xodnizel Exp $ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+#  include <ctype.h>
+#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.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * 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, ct_data *ltree,
+                              ct_data *dtree));
+local void set_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(s, value, length)
+    deflate_state *s;
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+    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 |= (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 |= 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 |= (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 |= (value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG */
+
+
+#define MAX(a,b) (a >= b ? a : b)
+/* 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: */
+    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;
+
+    /* 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<<extra_lbits[code]); n++) {
+            _length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    _length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            _dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 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 <stdio.h>
+#  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 _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 _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 _tr_init(s)
+    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;
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+#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(s)
+    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(s, tree, k)
+    deflate_state *s;
+    ct_data *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    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(s, desc)
+    deflate_state *s;
+    tree_desc *desc;    /* the tree descriptor */
+{
+    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 (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 (tree, max_code, bl_count)
+    ct_data *tree;             /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+    ushf *bl_count;            /* number of codes at each bit length */
+{
+    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<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+    deflate_state *s;
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree         = desc->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) (MAX(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 (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree;   /* the tree to be scanned */
+    int max_code;    /* and its largest code of non zero frequency */
+{
+    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 (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    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(s)
+    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(s, lcodes, dcodes, blcodes)
+    deflate_state *s;
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    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 _tr_stored_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    send_bits(s, (STORED_BLOCK<<1)+eof, 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 */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+    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);
+    /* Of the 10 bits for the empty block, we have already sent
+     * (10 - bi_valid) bits. The lookahead for the last real code (before
+     * the EOB of the previous block) was thus at least one plus the length
+     * of the EOB plus what we have just sent of the empty static block.
+     */
+    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+        send_bits(s, STATIC_TREES<<1, 3);
+        send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+        s->compressed_len += 10L;
+#endif
+        bi_flush(s);
+    }
+    s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    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 ascii or binary */
+       if (s->data_type == Z_UNKNOWN) set_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 first the block length 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, eof);
+
+#ifdef FORCE_STATIC
+    } else if (static_lenb >= 0) { /* force static trees */
+#else
+    } else if (static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+eof, 3);
+        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->static_len;
+#endif
+    } else {
+        send_bits(s, (DYN_TREES<<1)+eof, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (ct_data *)s->dyn_ltree, (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 (eof) {
+        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*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+    deflate_state *s;
+    unsigned dist;  /* distance of matched string */
+    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    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(s, ltree, dtree)
+    deflate_state *s;
+    ct_data *ltree; /* literal tree */
+    ct_data *dtree; /* distance tree */
+{
+    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(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+    s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_data_type(s)
+    deflate_state *s;
+{
+    int n = 0;
+    unsigned ascii_freq = 0;
+    unsigned bin_freq = 0;
+    while (n < 7)        bin_freq += s->dyn_ltree[n++].Freq;
+    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
+    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+    s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+}
+
+/* ===========================================================================
+ * 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(code, len)
+    unsigned code; /* the value to invert */
+    int len;       /* its bit length */
+{
+    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(s)
+    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(s)
+    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(s, buf, len, header)
+    deflate_state *s;
+    charf    *buf;    /* the input data */
+    unsigned len;     /* its length */
+    int      header;  /* true if block header must be written */
+{
+    bi_windup(s);        /* align on byte boundary */
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+
+    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++);
+    }
+}
diff --git a/zlib/trees.h b/zlib/trees.h
new file mode 100644 (file)
index 0000000..72facf9
--- /dev/null
@@ -0,0 +1,128 @@
+/* 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 _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 _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
+};
+
diff --git a/zlib/uncompr.c b/zlib/uncompr.c
new file mode 100644 (file)
index 0000000..3a71259
--- /dev/null
@@ -0,0 +1,58 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id: uncompr.c,v 1.2 2002/03/13 17:45:56 xodnizel Exp $ */
+
+#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.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     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 (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (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);
+        return err == Z_OK ? Z_BUF_ERROR : err;
+    }
+    *destLen = stream.total_out;
+
+    err = inflateEnd(&stream);
+    return err;
+}
diff --git a/zlib/unzip.c b/zlib/unzip.c
new file mode 100644 (file)
index 0000000..d156fae
--- /dev/null
@@ -0,0 +1,1301 @@
+/* unzip.c -- IO on .zip files using zlib 
+   Version 0.15 beta, Mar 19th, 1998,
+
+   Read unzip.h for more info
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zlib.h"
+#include "unzip.h"
+
+#ifdef STDC
+#  include <stddef.h>
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+    extern int errno;
+#else
+#   include <errno.h>
+#endif
+
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+
+
+#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \
+                      !defined(CASESENSITIVITYDEFAULT_NO)
+#define CASESENSITIVITYDEFAULT_NO
+#endif
+
+
+#ifndef UNZ_BUFSIZE
+#define UNZ_BUFSIZE (16384)
+#endif
+
+#ifndef UNZ_MAXFILENAMEINZIP
+#define UNZ_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+# define TRYFREE(p) {if (p) free(p);}
+#endif
+
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+
+
+/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
+
+#ifndef SEEK_CUR
+#define SEEK_CUR    1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END    2
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET    0
+#endif
+
+const char unz_copyright[] =
+   " unzip 0.15 Copyright 1998 Gilles Vollant ";
+
+/* unz_file_info_interntal contain internal info about a file in zipfile*/
+typedef struct unz_file_info_internal_s
+{
+    uLong offset_curfile;/* relative offset of local header 4 bytes */
+} unz_file_info_internal;
+
+
+/* file_in_zip_read_info_s contain internal information about a file in zipfile,
+    when reading and decompress it */
+typedef struct
+{
+       char  *read_buffer;         /* internal buffer for compressed data */
+       z_stream stream;            /* zLib stream structure for inflate */
+
+       uLong pos_in_zipfile;       /* position in byte on the zipfile, for fseek*/
+       uLong stream_initialised;   /* flag set if stream structure is initialised*/
+
+       uLong offset_local_extrafield;/* offset of the local extra field */
+       uInt  size_local_extrafield;/* size of the local extra field */
+       uLong pos_local_extrafield;   /* position in the local extra field in read*/
+
+       uLong crc32;                /* crc32 of all data uncompressed */
+       uLong crc32_wait;           /* crc32 we must obtain after decompress all */
+       uLong rest_read_compressed; /* number of byte to be decompressed */
+       uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/
+       FILE* file;                 /* io structore of the zipfile */
+       uLong compression_method;   /* compression method (0==store) */
+       uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+} file_in_zip_read_info_s;
+
+
+/* unz_s contain internal information about the zipfile
+*/
+typedef struct
+{
+       FILE* file;                 /* io structore of the zipfile */
+       unz_global_info gi;       /* public global information */
+       uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+       uLong num_file;             /* number of the current file in the zipfile*/
+       uLong pos_in_central_dir;   /* pos of the current file in the central dir*/
+       uLong current_file_ok;      /* flag about the usability of the current file*/
+       uLong central_pos;          /* position of the beginning of the central dir*/
+
+       uLong size_central_dir;     /* size of the central directory  */
+       uLong offset_central_dir;   /* offset of start of central directory with
+                                                                  respect to the starting disk number */
+
+       unz_file_info cur_file_info; /* public info about the current file in zip*/
+       unz_file_info_internal cur_file_info_internal; /* private info about it*/
+    file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current
+                                           file if we are decompressing it */
+} unz_s;
+
+
+/* ===========================================================================
+     Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+   for end of file.
+   IN assertion: the stream s has been sucessfully opened for reading.
+*/
+
+
+local int unzlocal_getByte(fin,pi)
+       FILE *fin;
+       int *pi;
+{
+    unsigned char c;
+       int err = fread(&c, 1, 1, fin);
+    if (err==1)
+    {
+        *pi = (int)c;
+        return UNZ_OK;
+    }
+    else
+    {
+        if (ferror(fin)) 
+            return UNZ_ERRNO;
+        else
+            return UNZ_EOF;
+    }
+}
+
+
+/* ===========================================================================
+   Reads a long in LSB order from the given gz_stream. Sets 
+*/
+local int unzlocal_getShort (fin,pX)
+       FILE* fin;
+    uLong *pX;
+{
+    uLong x ;
+    int i;
+    int err;
+
+    err = unzlocal_getByte(fin,&i);
+    x = (uLong)i;
+    
+    if (err==UNZ_OK)
+        err = unzlocal_getByte(fin,&i);
+    x += ((uLong)i)<<8;
+   
+    if (err==UNZ_OK)
+        *pX = x;
+    else
+        *pX = 0;
+    return err;
+}
+
+local int unzlocal_getLong (fin,pX)
+       FILE* fin;
+    uLong *pX;
+{
+    uLong x ;
+    int i;
+    int err;
+
+    err = unzlocal_getByte(fin,&i);
+    x = (uLong)i;
+    
+    if (err==UNZ_OK)
+        err = unzlocal_getByte(fin,&i);
+    x += ((uLong)i)<<8;
+
+    if (err==UNZ_OK)
+        err = unzlocal_getByte(fin,&i);
+    x += ((uLong)i)<<16;
+
+    if (err==UNZ_OK)
+        err = unzlocal_getByte(fin,&i);
+    x += ((uLong)i)<<24;
+   
+    if (err==UNZ_OK)
+        *pX = x;
+    else
+        *pX = 0;
+    return err;
+}
+
+
+/* My own strcmpi / strcasecmp */
+local int strcmpcasenosensitive_internal (fileName1,fileName2)
+       const char* fileName1;
+       const char* fileName2;
+{
+       for (;;)
+       {
+               char c1=*(fileName1++);
+               char c2=*(fileName2++);
+               if ((c1>='a') && (c1<='z'))
+                       c1 -= 0x20;
+               if ((c2>='a') && (c2<='z'))
+                       c2 -= 0x20;
+               if (c1=='\0')
+                       return ((c2=='\0') ? 0 : -1);
+               if (c2=='\0')
+                       return 1;
+               if (c1<c2)
+                       return -1;
+               if (c1>c2)
+                       return 1;
+       }
+}
+
+
+#ifdef  CASESENSITIVITYDEFAULT_NO
+#define CASESENSITIVITYDEFAULTVALUE 2
+#else
+#define CASESENSITIVITYDEFAULTVALUE 1
+#endif
+
+#ifndef STRCMPCASENOSENTIVEFUNCTION
+#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
+#endif
+
+/* 
+   Compare two filename (fileName1,fileName2).
+   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+                                                                or strcasecmp)
+   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+        (like 1 on Unix, 2 on Windows)
+
+*/
+extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity)
+       const char* fileName1;
+       const char* fileName2;
+       int iCaseSensitivity;
+{
+       if (iCaseSensitivity==0)
+               iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
+
+       if (iCaseSensitivity==1)
+               return strcmp(fileName1,fileName2);
+
+       return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
+} 
+
+#define BUFREADCOMMENT (0x400)
+
+/*
+  Locate the Central directory of a zipfile (at the end, just before
+    the global comment)
+*/
+local uLong unzlocal_SearchCentralDir(fin)
+       FILE *fin;
+{
+       unsigned char* buf;
+       uLong uSizeFile;
+       uLong uBackRead;
+       uLong uMaxBack=0xffff; /* maximum size of global comment */
+       uLong uPosFound=0;
+       
+       if (fseek(fin,0,SEEK_END) != 0)
+               return 0;
+
+
+       uSizeFile = ftell( fin );
+       
+       if (uMaxBack>uSizeFile)
+               uMaxBack = uSizeFile;
+
+       buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+       if (buf==NULL)
+               return 0;
+
+       uBackRead = 4;
+       while (uBackRead<uMaxBack)
+       {
+               uLong uReadSize,uReadPos ;
+               int i;
+               if (uBackRead+BUFREADCOMMENT>uMaxBack) 
+                       uBackRead = uMaxBack;
+               else
+                       uBackRead+=BUFREADCOMMENT;
+               uReadPos = uSizeFile-uBackRead ;
+               
+               uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? 
+                     (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
+               if (fseek(fin,uReadPos,SEEK_SET)!=0)
+                       break;
+
+               if (fread(buf,(uInt)uReadSize,1,fin)!=1)
+                       break;
+
+                for (i=(int)uReadSize-3; (i--)>0;)
+                       if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && 
+                               ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
+                       {
+                               uPosFound = uReadPos+i;
+                               break;
+                       }
+
+               if (uPosFound!=0)
+                       break;
+       }
+       TRYFREE(buf);
+       return uPosFound;
+}
+
+/*
+  Open a Zip file. path contain the full pathname (by example,
+     on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer
+        "zlib/zlib109.zip".
+        If the zipfile cannot be opened (file don't exist or in not valid), the
+          return value is NULL.
+     Else, the return value is a unzFile Handle, usable with other function
+          of this unzip package.
+*/
+extern unzFile ZEXPORT unzOpen (path)
+       const char *path;
+{
+       unz_s us;
+       unz_s *s;
+       uLong central_pos,uL;
+       FILE * fin ;
+
+       uLong number_disk;          /* number of the current dist, used for 
+                                                                  spaning ZIP, unsupported, always 0*/
+       uLong number_disk_with_CD;  /* number the the disk with central dir, used
+                                                                  for spaning ZIP, unsupported, always 0*/
+       uLong number_entry_CD;      /* total number of entries in
+                                      the central dir 
+                                      (same than number_entry on nospan) */
+
+       int err=UNZ_OK;
+
+    if (unz_copyright[0]!=' ')
+        return NULL;
+
+    fin=fopen(path,"rb");
+       if (fin==NULL)
+               return NULL;
+
+       central_pos = unzlocal_SearchCentralDir(fin);
+       if (central_pos==0)
+               err=UNZ_ERRNO;
+
+       if (fseek(fin,central_pos,SEEK_SET)!=0)
+               err=UNZ_ERRNO;
+
+       /* the signature, already checked */
+       if (unzlocal_getLong(fin,&uL)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* number of this disk */
+       if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* number of the disk with the start of the central directory */
+       if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* total number of entries in the central dir on this disk */
+       if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* total number of entries in the central dir */
+       if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if ((number_entry_CD!=us.gi.number_entry) ||
+               (number_disk_with_CD!=0) ||
+               (number_disk!=0))
+               err=UNZ_BADZIPFILE;
+
+       /* size of the central directory */
+       if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* offset of start of central directory with respect to the 
+             starting disk number */
+       if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       /* zipfile comment length */
+       if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if ((central_pos<us.offset_central_dir+us.size_central_dir) && 
+               (err==UNZ_OK))
+               err=UNZ_BADZIPFILE;
+
+       if (err!=UNZ_OK)
+       {
+               fclose(fin);
+               return NULL;
+       }
+
+       us.file=fin;
+       us.byte_before_the_zipfile = central_pos -
+                                   (us.offset_central_dir+us.size_central_dir);
+       us.central_pos = central_pos;
+    us.pfile_in_zip_read = NULL;
+       
+
+       s=(unz_s*)ALLOC(sizeof(unz_s));
+       *s=us;
+       unzGoToFirstFile((unzFile)s);   
+       return (unzFile)s;      
+}
+
+
+/*
+  Close a ZipFile opened with unzipOpen.
+  If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
+    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+  return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzClose (file)
+       unzFile file;
+{
+       unz_s* s;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+
+    if (s->pfile_in_zip_read!=NULL)
+        unzCloseCurrentFile(file);
+
+       fclose(s->file);
+       TRYFREE(s);
+       return UNZ_OK;
+}
+
+
+/*
+  Write info about the ZipFile in the *pglobal_info structure.
+  No preparation of the structure is needed
+  return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info)
+       unzFile file;
+       unz_global_info *pglobal_info;
+{
+       unz_s* s;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+       *pglobal_info=s->gi;
+       return UNZ_OK;
+}
+
+
+/*
+   Translate date/time from Dos format to tm_unz (readable more easilty)
+*/
+local void unzlocal_DosDateToTmuDate (ulDosDate, ptm)
+    uLong ulDosDate;
+    tm_unz* ptm;
+{
+    uLong uDate;
+    uDate = (uLong)(ulDosDate>>16);
+    ptm->tm_mday = (uInt)(uDate&0x1f) ;
+    ptm->tm_mon =  (uInt)((((uDate)&0x1E0)/0x20)-1) ;
+    ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;
+
+    ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
+    ptm->tm_min =  (uInt) ((ulDosDate&0x7E0)/0x20) ;
+    ptm->tm_sec =  (uInt) (2*(ulDosDate&0x1f)) ;
+}
+
+/*
+  Get Info about the current file in the zipfile, with internal only info
+*/
+local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
+                                                  unz_file_info *pfile_info,
+                                                  unz_file_info_internal 
+                                                  *pfile_info_internal,
+                                                  char *szFileName,
+                                                                                                 uLong fileNameBufferSize,
+                                                  void *extraField,
+                                                                                                 uLong extraFieldBufferSize,
+                                                  char *szComment,
+                                                                                                 uLong commentBufferSize));
+
+local int unzlocal_GetCurrentFileInfoInternal (file,
+                                              pfile_info,
+                                              pfile_info_internal,
+                                              szFileName, fileNameBufferSize,
+                                              extraField, extraFieldBufferSize,
+                                              szComment,  commentBufferSize)
+       unzFile file;
+       unz_file_info *pfile_info;
+       unz_file_info_internal *pfile_info_internal;
+       char *szFileName;
+       uLong fileNameBufferSize;
+       void *extraField;
+       uLong extraFieldBufferSize;
+       char *szComment;
+       uLong commentBufferSize;
+{
+       unz_s* s;
+       unz_file_info file_info;
+       unz_file_info_internal file_info_internal;
+       int err=UNZ_OK;
+       uLong uMagic;
+       long lSeek=0;
+
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+       if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0)
+               err=UNZ_ERRNO;
+
+
+       /* we check the magic */
+       if (err==UNZ_OK)
+       {
+               if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
+                       err=UNZ_ERRNO;
+               else if (uMagic!=0x02014b50)
+                       err=UNZ_BADZIPFILE;
+       }
+
+       if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+    unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
+
+       if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       lSeek+=file_info.size_filename;
+       if ((err==UNZ_OK) && (szFileName!=NULL))
+       {
+               uLong uSizeRead ;
+               if (file_info.size_filename<fileNameBufferSize)
+               {
+                       *(szFileName+file_info.size_filename)='\0';
+                       uSizeRead = file_info.size_filename;
+               }
+               else
+                       uSizeRead = fileNameBufferSize;
+
+               if ((file_info.size_filename>0) && (fileNameBufferSize>0))
+                       if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1)
+                               err=UNZ_ERRNO;
+               lSeek -= uSizeRead;
+       }
+
+       
+       if ((err==UNZ_OK) && (extraField!=NULL))
+       {
+               uLong uSizeRead ;
+               if (file_info.size_file_extra<extraFieldBufferSize)
+                       uSizeRead = file_info.size_file_extra;
+               else
+                       uSizeRead = extraFieldBufferSize;
+
+               if (lSeek!=0)
+               {
+                       if (fseek(s->file,lSeek,SEEK_CUR)==0)
+                               lSeek=0;
+                       else
+                               err=UNZ_ERRNO;
+               }
+               if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
+                       if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1)
+                               err=UNZ_ERRNO;
+               lSeek += file_info.size_file_extra - uSizeRead;
+       }
+       else
+               lSeek+=file_info.size_file_extra; 
+
+       
+       if ((err==UNZ_OK) && (szComment!=NULL))
+       {
+               uLong uSizeRead ;
+               if (file_info.size_file_comment<commentBufferSize)
+               {
+                       *(szComment+file_info.size_file_comment)='\0';
+                       uSizeRead = file_info.size_file_comment;
+               }
+               else
+                       uSizeRead = commentBufferSize;
+
+               if (lSeek!=0)
+               {
+                       if (fseek(s->file,lSeek,SEEK_CUR)==0)
+                               lSeek=0;
+                       else
+                               err=UNZ_ERRNO;
+               }
+               if ((file_info.size_file_comment>0) && (commentBufferSize>0))
+                       if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1)
+                               err=UNZ_ERRNO;
+               lSeek+=file_info.size_file_comment - uSizeRead;
+       }
+       else
+               lSeek+=file_info.size_file_comment;
+
+       if ((err==UNZ_OK) && (pfile_info!=NULL))
+               *pfile_info=file_info;
+
+       if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
+               *pfile_info_internal=file_info_internal;
+
+       return err;
+}
+
+
+
+/*
+  Write info about the ZipFile in the *pglobal_info structure.
+  No preparation of the structure is needed
+  return UNZ_OK if there is no problem.
+*/
+extern int ZEXPORT unzGetCurrentFileInfo (file,
+                                                  pfile_info,
+                                                  szFileName, fileNameBufferSize,
+                                                  extraField, extraFieldBufferSize,
+                                                  szComment,  commentBufferSize)
+       unzFile file;
+       unz_file_info *pfile_info;
+       char *szFileName;
+       uLong fileNameBufferSize;
+       void *extraField;
+       uLong extraFieldBufferSize;
+       char *szComment;
+       uLong commentBufferSize;
+{
+       return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,
+                                                                                               szFileName,fileNameBufferSize,
+                                                                                               extraField,extraFieldBufferSize,
+                                                                                               szComment,commentBufferSize);
+}
+
+/*
+  Set the current file of the zipfile to the first file.
+  return UNZ_OK if there is no problem
+*/
+extern int ZEXPORT unzGoToFirstFile (file)
+       unzFile file;
+{
+       int err=UNZ_OK;
+       unz_s* s;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+       s->pos_in_central_dir=s->offset_central_dir;
+       s->num_file=0;
+       err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+                                                                                        &s->cur_file_info_internal,
+                                                                                        NULL,0,NULL,0,NULL,0);
+       s->current_file_ok = (err == UNZ_OK);
+       return err;
+}
+
+
+/*
+  Set the current file of the zipfile to the next file.
+  return UNZ_OK if there is no problem
+  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+extern int ZEXPORT unzGoToNextFile (file)
+       unzFile file;
+{
+       unz_s* s;       
+       int err;
+
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+       if (!s->current_file_ok)
+               return UNZ_END_OF_LIST_OF_FILE;
+       if (s->num_file+1==s->gi.number_entry)
+               return UNZ_END_OF_LIST_OF_FILE;
+
+       s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
+                       s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
+       s->num_file++;
+       err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+                                                                                          &s->cur_file_info_internal,
+                                                                                          NULL,0,NULL,0,NULL,0);
+       s->current_file_ok = (err == UNZ_OK);
+       return err;
+}
+
+
+/*
+  Try locate the file szFileName in the zipfile.
+  For the iCaseSensitivity signification, see unzipStringFileNameCompare
+
+  return value :
+  UNZ_OK if the file is found. It becomes the current file.
+  UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity)
+       unzFile file;
+       const char *szFileName;
+       int iCaseSensitivity;
+{
+       unz_s* s;       
+       int err;
+
+       
+       uLong num_fileSaved;
+       uLong pos_in_central_dirSaved;
+
+
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+
+    if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
+        return UNZ_PARAMERROR;
+
+       s=(unz_s*)file;
+       if (!s->current_file_ok)
+               return UNZ_END_OF_LIST_OF_FILE;
+
+       num_fileSaved = s->num_file;
+       pos_in_central_dirSaved = s->pos_in_central_dir;
+
+       err = unzGoToFirstFile(file);
+
+       while (err == UNZ_OK)
+       {
+               char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
+               unzGetCurrentFileInfo(file,NULL,
+                                                               szCurrentFileName,sizeof(szCurrentFileName)-1,
+                                                               NULL,0,NULL,0);
+               if (unzStringFileNameCompare(szCurrentFileName,
+                                                                               szFileName,iCaseSensitivity)==0)
+                       return UNZ_OK;
+               err = unzGoToNextFile(file);
+       }
+
+       s->num_file = num_fileSaved ;
+       s->pos_in_central_dir = pos_in_central_dirSaved ;
+       return err;
+}
+
+
+/*
+  Read the local header of the current zipfile
+  Check the coherency of the local header and info in the end of central
+        directory about this file
+  store in *piSizeVar the size of extra info in local header
+        (filename and size of extra field data)
+*/
+local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar,
+                                                                                                       poffset_local_extrafield,
+                                                                                                       psize_local_extrafield)
+       unz_s* s;
+       uInt* piSizeVar;
+       uLong *poffset_local_extrafield;
+       uInt  *psize_local_extrafield;
+{
+       uLong uMagic,uData,uFlags;
+       uLong size_filename;
+       uLong size_extra_field;
+       int err=UNZ_OK;
+
+       *piSizeVar = 0;
+       *poffset_local_extrafield = 0;
+       *psize_local_extrafield = 0;
+
+       if (fseek(s->file,s->cur_file_info_internal.offset_curfile +
+                                                               s->byte_before_the_zipfile,SEEK_SET)!=0)
+               return UNZ_ERRNO;
+
+
+       if (err==UNZ_OK)
+       {       
+               if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
+                       err=UNZ_ERRNO;
+               else if (uMagic!=0x04034b50)
+                       err=UNZ_BADZIPFILE;
+       }
+
+       if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
+               err=UNZ_ERRNO;
+/*
+       else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
+               err=UNZ_BADZIPFILE;
+*/
+       if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK)
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
+               err=UNZ_ERRNO;
+       else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
+               err=UNZ_BADZIPFILE;
+
+    if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
+                         (s->cur_file_info.compression_method!=Z_DEFLATED))
+        err=UNZ_BADZIPFILE;
+
+       if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */
+               err=UNZ_ERRNO;
+
+       if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */
+               err=UNZ_ERRNO;
+       else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&
+                                     ((uFlags & 8)==0))
+               err=UNZ_BADZIPFILE;
+
+       if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */
+               err=UNZ_ERRNO;
+       else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&
+                                                         ((uFlags & 8)==0))
+               err=UNZ_BADZIPFILE;
+
+       if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */
+               err=UNZ_ERRNO;
+       else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && 
+                                                         ((uFlags & 8)==0))
+               err=UNZ_BADZIPFILE;
+
+
+       if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK)
+               err=UNZ_ERRNO;
+       else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
+               err=UNZ_BADZIPFILE;
+
+       *piSizeVar += (uInt)size_filename;
+
+       if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK)
+               err=UNZ_ERRNO;
+       *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
+                                                                       SIZEZIPLOCALHEADER + size_filename;
+       *psize_local_extrafield = (uInt)size_extra_field;
+
+       *piSizeVar += (uInt)size_extra_field;
+
+       return err;
+}
+                                                                                               
+/*
+  Open for reading data the current file in the zipfile.
+  If there is no error and the file is opened, the return value is UNZ_OK.
+*/
+extern int ZEXPORT unzOpenCurrentFile (file)
+       unzFile file;
+{
+       int err=UNZ_OK;
+       int Store;
+       uInt iSizeVar;
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       uLong offset_local_extrafield;  /* offset of the local extra field */
+       uInt  size_local_extrafield;    /* size of the local extra field */
+
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+       if (!s->current_file_ok)
+               return UNZ_PARAMERROR;
+
+    if (s->pfile_in_zip_read != NULL)
+        unzCloseCurrentFile(file);
+
+       if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,
+                               &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
+               return UNZ_BADZIPFILE;
+
+       pfile_in_zip_read_info = (file_in_zip_read_info_s*)
+                                                                           ALLOC(sizeof(file_in_zip_read_info_s));
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_INTERNALERROR;
+
+       pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
+       pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
+       pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
+       pfile_in_zip_read_info->pos_local_extrafield=0;
+
+       if (pfile_in_zip_read_info->read_buffer==NULL)
+       {
+               TRYFREE(pfile_in_zip_read_info);
+               return UNZ_INTERNALERROR;
+       }
+
+       pfile_in_zip_read_info->stream_initialised=0;
+       
+       if ((s->cur_file_info.compression_method!=0) &&
+        (s->cur_file_info.compression_method!=Z_DEFLATED))
+               err=UNZ_BADZIPFILE;
+       Store = s->cur_file_info.compression_method==0;
+
+       pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
+       pfile_in_zip_read_info->crc32=0;
+       pfile_in_zip_read_info->compression_method =
+            s->cur_file_info.compression_method;
+       pfile_in_zip_read_info->file=s->file;
+       pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
+
+    pfile_in_zip_read_info->stream.total_out = 0;
+
+       if (!Store)
+       {
+         pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+         pfile_in_zip_read_info->stream.zfree = (free_func)0;
+         pfile_in_zip_read_info->stream.opaque = (voidpf)0; 
+      
+         err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
+         if (err == Z_OK)
+           pfile_in_zip_read_info->stream_initialised=1;
+        /* windowBits is passed < 0 to tell that there is no zlib header.
+         * Note that in this case inflate *requires* an extra "dummy" byte
+         * after the compressed stream in order to complete decompression and
+         * return Z_STREAM_END. 
+         * In unzip, i don't wait absolutely Z_STREAM_END because I known the 
+         * size of both compressed and uncompressed data
+         */
+       }
+       pfile_in_zip_read_info->rest_read_compressed = 
+            s->cur_file_info.compressed_size ;
+       pfile_in_zip_read_info->rest_read_uncompressed = 
+            s->cur_file_info.uncompressed_size ;
+
+       
+       pfile_in_zip_read_info->pos_in_zipfile = 
+            s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + 
+                         iSizeVar;
+       
+       pfile_in_zip_read_info->stream.avail_in = (uInt)0;
+
+
+       s->pfile_in_zip_read = pfile_in_zip_read_info;
+    return UNZ_OK;
+}
+
+
+/*
+  Read bytes from the current file.
+  buf contain buffer where data must be copied
+  len the size of buf.
+
+  return the number of byte copied if somes bytes are copied
+  return 0 if the end of file was reached
+  return <0 with error code if there is an error
+    (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+extern int ZEXPORT unzReadCurrentFile  (file, buf, len)
+       unzFile file;
+       voidp buf;
+       unsigned len;
+{
+       int err=UNZ_OK;
+       uInt iRead = 0;
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_PARAMERROR;
+
+
+       if ((pfile_in_zip_read_info->read_buffer == NULL))
+               return UNZ_END_OF_LIST_OF_FILE;
+       if (len==0)
+               return 0;
+
+       pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
+
+       pfile_in_zip_read_info->stream.avail_out = (uInt)len;
+       
+       if (len>pfile_in_zip_read_info->rest_read_uncompressed)
+               pfile_in_zip_read_info->stream.avail_out = 
+                 (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
+
+       while (pfile_in_zip_read_info->stream.avail_out>0)
+       {
+               if ((pfile_in_zip_read_info->stream.avail_in==0) &&
+            (pfile_in_zip_read_info->rest_read_compressed>0))
+               {
+                       uInt uReadThis = UNZ_BUFSIZE;
+                       if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
+                               uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
+                       if (uReadThis == 0)
+                               return UNZ_EOF;
+                       if (fseek(pfile_in_zip_read_info->file,
+                      pfile_in_zip_read_info->pos_in_zipfile + 
+                         pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0)
+                               return UNZ_ERRNO;
+                       if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1,
+                         pfile_in_zip_read_info->file)!=1)
+                               return UNZ_ERRNO;
+                       pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
+
+                       pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
+                       
+                       pfile_in_zip_read_info->stream.next_in = 
+                (Bytef*)pfile_in_zip_read_info->read_buffer;
+                       pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
+               }
+
+               if (pfile_in_zip_read_info->compression_method==0)
+               {
+                       uInt uDoCopy,i ;
+                       if (pfile_in_zip_read_info->stream.avail_out < 
+                            pfile_in_zip_read_info->stream.avail_in)
+                               uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
+                       else
+                               uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
+                               
+                       for (i=0;i<uDoCopy;i++)
+                               *(pfile_in_zip_read_info->stream.next_out+i) =
+                        *(pfile_in_zip_read_info->stream.next_in+i);
+                                       
+                       pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
+                                                               pfile_in_zip_read_info->stream.next_out,
+                                                               uDoCopy);
+                       pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
+                       pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
+                       pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
+                       pfile_in_zip_read_info->stream.next_out += uDoCopy;
+                       pfile_in_zip_read_info->stream.next_in += uDoCopy;
+            pfile_in_zip_read_info->stream.total_out += uDoCopy;
+                       iRead += uDoCopy;
+               }
+               else
+               {
+                       uLong uTotalOutBefore,uTotalOutAfter;
+                       const Bytef *bufBefore;
+                       uLong uOutThis;
+                        int flush=Z_SYNC_FLUSH;
+
+                       uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
+                       bufBefore = pfile_in_zip_read_info->stream.next_out;
+
+                       /*
+                       if ((pfile_in_zip_read_info->rest_read_uncompressed ==
+                                pfile_in_zip_read_info->stream.avail_out) &&
+                               (pfile_in_zip_read_info->rest_read_compressed == 0))
+                               flush = Z_FINISH;
+                       */
+                       err=inflate(&pfile_in_zip_read_info->stream,flush);
+
+                       uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
+                       uOutThis = uTotalOutAfter-uTotalOutBefore;
+                       
+                       pfile_in_zip_read_info->crc32 = 
+                crc32(pfile_in_zip_read_info->crc32,bufBefore,
+                        (uInt)(uOutThis));
+
+                       pfile_in_zip_read_info->rest_read_uncompressed -=
+                uOutThis;
+
+                       iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
+            
+                       if (err==Z_STREAM_END)
+                               return (iRead==0) ? UNZ_EOF : iRead;
+                       if (err!=Z_OK) 
+                               break;
+               }
+       }
+
+       if (err==Z_OK)
+               return iRead;
+       return err;
+}
+
+
+/*
+  Give the current position in uncompressed data
+*/
+extern z_off_t ZEXPORT unztell (file)
+       unzFile file;
+{
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_PARAMERROR;
+
+       return (z_off_t)pfile_in_zip_read_info->stream.total_out;
+}
+
+
+/*
+  return 1 if the end of file was reached, 0 elsewhere 
+*/
+extern int ZEXPORT unzeof (file)
+       unzFile file;
+{
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_PARAMERROR;
+       
+       if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
+               return 1;
+       else
+               return 0;
+}
+
+
+
+/*
+  Read extra field from the current file (opened by unzOpenCurrentFile)
+  This is the local-header version of the extra field (sometimes, there is
+    more info in the local-header version than in the central-header)
+
+  if buf==NULL, it return the size of the local extra field that can be read
+
+  if buf!=NULL, len is the size of the buffer, the extra header is copied in
+       buf.
+  the return value is the number of bytes copied in buf, or (if <0) 
+       the error code
+*/
+extern int ZEXPORT unzGetLocalExtrafield (file,buf,len)
+       unzFile file;
+       voidp buf;
+       unsigned len;
+{
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       uInt read_now;
+       uLong size_to_read;
+
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_PARAMERROR;
+
+       size_to_read = (pfile_in_zip_read_info->size_local_extrafield - 
+                               pfile_in_zip_read_info->pos_local_extrafield);
+
+       if (buf==NULL)
+               return (int)size_to_read;
+       
+       if (len>size_to_read)
+               read_now = (uInt)size_to_read;
+       else
+               read_now = (uInt)len ;
+
+       if (read_now==0)
+               return 0;
+       
+       if (fseek(pfile_in_zip_read_info->file,
+              pfile_in_zip_read_info->offset_local_extrafield + 
+                         pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0)
+               return UNZ_ERRNO;
+
+       if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1)
+               return UNZ_ERRNO;
+
+       return (int)read_now;
+}
+
+/*
+  Close the file in zip opened with unzipOpenCurrentFile
+  Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+extern int ZEXPORT unzCloseCurrentFile (file)
+       unzFile file;
+{
+       int err=UNZ_OK;
+
+       unz_s* s;
+       file_in_zip_read_info_s* pfile_in_zip_read_info;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+       if (pfile_in_zip_read_info==NULL)
+               return UNZ_PARAMERROR;
+
+
+       if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
+       {
+               if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
+                       err=UNZ_CRCERROR;
+       }
+
+
+       TRYFREE(pfile_in_zip_read_info->read_buffer);
+       pfile_in_zip_read_info->read_buffer = NULL;
+       if (pfile_in_zip_read_info->stream_initialised)
+               inflateEnd(&pfile_in_zip_read_info->stream);
+
+       pfile_in_zip_read_info->stream_initialised = 0;
+       TRYFREE(pfile_in_zip_read_info);
+
+    s->pfile_in_zip_read=NULL;
+
+       return err;
+}
+
+
+/*
+  Get the global comment string of the ZipFile, in the szComment buffer.
+  uSizeBuf is the size of the szComment buffer.
+  return the number of byte copied or an error code <0
+*/
+extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf)
+       unzFile file;
+       char *szComment;
+       uLong uSizeBuf;
+{
+       unz_s* s;
+       uLong uReadThis ;
+       if (file==NULL)
+               return UNZ_PARAMERROR;
+       s=(unz_s*)file;
+
+       uReadThis = uSizeBuf;
+       if (uReadThis>s->gi.size_comment)
+               uReadThis = s->gi.size_comment;
+
+       if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0)
+               return UNZ_ERRNO;
+
+       if (uReadThis>0)
+    {
+      *szComment='\0';
+         if (fread(szComment,(uInt)uReadThis,1,s->file)!=1)
+               return UNZ_ERRNO;
+    }
+
+       if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
+               *(szComment+s->gi.size_comment)='\0';
+       return (int)uReadThis;
+}
diff --git a/zlib/unzip.h b/zlib/unzip.h
new file mode 100644 (file)
index 0000000..76692cb
--- /dev/null
@@ -0,0 +1,275 @@
+/* unzip.h -- IO for uncompress .zip files using zlib 
+   Version 0.15 beta, Mar 19th, 1998,
+
+   Copyright (C) 1998 Gilles Vollant
+
+   This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
+     WinZip, InfoZip tools and compatible.
+   Encryption and multi volume ZipFile (span) are not supported.
+   Old compressions used by old PKZip 1.x are not supported
+
+   THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE
+   CAN CHANGE IN FUTURE VERSION !!
+   I WAIT FEEDBACK at mail info@winimage.com
+   Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
+
+   Condition of use and distribution are the same than zlib :
+
+  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.
+
+
+*/
+/* for more info about .ZIP format, see 
+      ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
+   PkWare has also a specification at :
+      ftp://ftp.pkware.com/probdesc.zip */
+
+#ifndef _unz_H
+#define _unz_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+    from (void*) without cast */
+typedef struct TagunzFile__ { int unused; } unzFile__; 
+typedef unzFile__ *unzFile;
+#else
+typedef voidp unzFile;
+#endif
+
+
+#define UNZ_OK                                  (0)
+#define UNZ_END_OF_LIST_OF_FILE (-100)
+#define UNZ_ERRNO               (Z_ERRNO)
+#define UNZ_EOF                 (0)
+#define UNZ_PARAMERROR                  (-102)
+#define UNZ_BADZIPFILE                  (-103)
+#define UNZ_INTERNALERROR               (-104)
+#define UNZ_CRCERROR                    (-105)
+
+/* tm_unz contain date/time info */
+typedef struct tm_unz_s 
+{
+       uInt tm_sec;            /* seconds after the minute - [0,59] */
+       uInt tm_min;            /* minutes after the hour - [0,59] */
+       uInt tm_hour;           /* hours since midnight - [0,23] */
+       uInt tm_mday;           /* day of the month - [1,31] */
+       uInt tm_mon;            /* months since January - [0,11] */
+       uInt tm_year;           /* years - [1980..2044] */
+} tm_unz;
+
+/* unz_global_info structure contain global data about the ZIPfile
+   These data comes from the end of central dir */
+typedef struct unz_global_info_s
+{
+       uLong number_entry;         /* total number of entries in
+                                      the central dir on this disk */
+       uLong size_comment;         /* size of the global comment of the zipfile */
+} unz_global_info;
+
+
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_info_s
+{
+    uLong version;              /* version made by                 2 bytes */
+    uLong version_needed;       /* version needed to extract       2 bytes */
+    uLong flag;                 /* general purpose bit flag        2 bytes */
+    uLong compression_method;   /* compression method              2 bytes */
+    uLong dosDate;              /* last mod file date in Dos fmt   4 bytes */
+    uLong crc;                  /* crc-32                          4 bytes */
+    uLong compressed_size;      /* compressed size                 4 bytes */ 
+    uLong uncompressed_size;    /* uncompressed size               4 bytes */ 
+    uLong size_filename;        /* filename length                 2 bytes */
+    uLong size_file_extra;      /* extra field length              2 bytes */
+    uLong size_file_comment;    /* file comment length             2 bytes */
+
+    uLong disk_num_start;       /* disk number start               2 bytes */
+    uLong internal_fa;          /* internal file attributes        2 bytes */
+    uLong external_fa;          /* external file attributes        4 bytes */
+
+    tm_unz tmu_date;
+} unz_file_info;
+
+extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
+                                                                                                const char* fileName2,
+                                                                                                int iCaseSensitivity));
+/*
+   Compare two filename (fileName1,fileName2).
+   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+                                                               or strcasecmp)
+   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+       (like 1 on Unix, 2 on Windows)
+*/
+
+
+extern unzFile ZEXPORT unzOpen OF((const char *path));
+/*
+  Open a Zip file. path contain the full pathname (by example,
+     on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
+        "zlib/zlib111.zip".
+        If the zipfile cannot be opened (file don't exist or in not valid), the
+          return value is NULL.
+     Else, the return value is a unzFile Handle, usable with other function
+          of this unzip package.
+*/
+
+extern int ZEXPORT unzClose OF((unzFile file));
+/*
+  Close a ZipFile opened with unzipOpen.
+  If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
+    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+  return UNZ_OK if there is no problem. */
+
+extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
+                                       unz_global_info *pglobal_info));
+/*
+  Write info about the ZipFile in the *pglobal_info structure.
+  No preparation of the structure is needed
+  return UNZ_OK if there is no problem. */
+
+
+extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
+                                                                                  char *szComment,
+                                          uLong uSizeBuf));
+/*
+  Get the global comment string of the ZipFile, in the szComment buffer.
+  uSizeBuf is the size of the szComment buffer.
+  return the number of byte copied or an error code <0
+*/
+
+
+/***************************************************************************/
+/* Unzip package allow you browse the directory of the zipfile */
+
+extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
+/*
+  Set the current file of the zipfile to the first file.
+  return UNZ_OK if there is no problem
+*/
+
+extern int ZEXPORT unzGoToNextFile OF((unzFile file));
+/*
+  Set the current file of the zipfile to the next file.
+  return UNZ_OK if there is no problem
+  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+
+extern int ZEXPORT unzLocateFile OF((unzFile file, 
+                                    const char *szFileName,
+                                    int iCaseSensitivity));
+/*
+  Try locate the file szFileName in the zipfile.
+  For the iCaseSensitivity signification, see unzStringFileNameCompare
+
+  return value :
+  UNZ_OK if the file is found. It becomes the current file.
+  UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+
+
+extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
+                                            unz_file_info *pfile_info,
+                                            char *szFileName,
+                                            uLong fileNameBufferSize,
+                                            void *extraField,
+                                            uLong extraFieldBufferSize,
+                                            char *szComment,
+                                            uLong commentBufferSize));
+/*
+  Get Info about the current file
+  if pfile_info!=NULL, the *pfile_info structure will contain somes info about
+           the current file
+  if szFileName!=NULL, the filemane string will be copied in szFileName
+                       (fileNameBufferSize is the size of the buffer)
+  if extraField!=NULL, the extra field information will be copied in extraField
+                       (extraFieldBufferSize is the size of the buffer).
+                       This is the Central-header version of the extra field
+  if szComment!=NULL, the comment string of the file will be copied in szComment
+                       (commentBufferSize is the size of the buffer)
+*/
+
+/***************************************************************************/
+/* for reading the content of the current zipfile, you can open it, read data
+   from it, and close it (you can close it before reading all the file)
+   */
+
+extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
+/*
+  Open for reading data the current file in the zipfile.
+  If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
+/*
+  Close the file in zip opened with unzOpenCurrentFile
+  Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+
+                                                                                               
+extern int ZEXPORT unzReadCurrentFile OF((unzFile file, 
+                                         voidp buf,
+                                         unsigned len));
+/*
+  Read bytes from the current file (opened by unzOpenCurrentFile)
+  buf contain buffer where data must be copied
+  len the size of buf.
+
+  return the number of byte copied if somes bytes are copied
+  return 0 if the end of file was reached
+  return <0 with error code if there is an error
+    (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+
+extern z_off_t ZEXPORT unztell OF((unzFile file));
+/*
+  Give the current position in uncompressed data
+*/
+
+extern int ZEXPORT unzeof OF((unzFile file));
+/*
+  return 1 if the end of file was reached, 0 elsewhere 
+*/
+
+extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
+                                                                                        voidp buf,
+                                                                                        unsigned len));
+/*
+  Read extra field from the current file (opened by unzOpenCurrentFile)
+  This is the local-header version of the extra field (sometimes, there is
+    more info in the local-header version than in the central-header)
+
+  if buf==NULL, it return the size of the local extra field
+
+  if buf!=NULL, len is the size of the buffer, the extra header is copied in
+       buf.
+  the return value is the number of bytes copied in buf, or (if <0) 
+       the error code
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _unz_H */
diff --git a/zlib/zconf.h b/zlib/zconf.h
new file mode 100644 (file)
index 0000000..68a9f9c
--- /dev/null
@@ -0,0 +1,279 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id: zconf.h,v 1.2 2002/03/13 17:45:56 xodnizel Exp $ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+#  define deflateInit_ z_deflateInit_
+#  define deflate      z_deflate
+#  define deflateEnd   z_deflateEnd
+#  define inflateInit_         z_inflateInit_
+#  define inflate      z_inflate
+#  define inflateEnd   z_inflateEnd
+#  define deflateInit2_        z_deflateInit2_
+#  define deflateSetDictionary z_deflateSetDictionary
+#  define deflateCopy  z_deflateCopy
+#  define deflateReset z_deflateReset
+#  define deflateParams        z_deflateParams
+#  define inflateInit2_        z_inflateInit2_
+#  define inflateSetDictionary z_inflateSetDictionary
+#  define inflateSync  z_inflateSync
+#  define inflateSyncPoint z_inflateSyncPoint
+#  define inflateReset z_inflateReset
+#  define compress     z_compress
+#  define compress2    z_compress2
+#  define uncompress   z_uncompress
+#  define adler32      z_adler32
+#  define crc32                z_crc32
+#  define get_crc_table z_get_crc_table
+
+#  define Byte         z_Byte
+#  define uInt         z_uInt
+#  define uLong                z_uLong
+#  define Bytef                z_Bytef
+#  define charf                z_charf
+#  define intf         z_intf
+#  define uIntf                z_uIntf
+#  define uLongf       z_uLongf
+#  define voidpf       z_voidpf
+#  define voidp                z_voidp
+#endif
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+#  define WIN32
+#endif
+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
+#  ifndef __32BIT__
+#    define __32BIT__
+#  endif
+#endif
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#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).
+ */
+#if defined(MSDOS) && !defined(__32BIT__)
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
+#  define STDC
+#endif
+#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__)
+#  ifndef STDC
+#    define STDC
+#  endif
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const
+#  endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Old Borland C incorrectly complains about missing returns: */
+#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
+#  define NEED_DUMMY_RETURN
+#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
+
+/* 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.
+ */
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
+   /* MSC small or medium model */
+#  define SMALL_MEDIUM
+#  ifdef _MSC_VER
+#    define FAR _far
+#  else
+#    define FAR far
+#  endif
+#endif
+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
+#  ifndef __32BIT__
+#    define SMALL_MEDIUM
+#    define FAR _far
+#  endif
+#endif
+
+/* Compile with -DZLIB_DLL for Windows DLL support */
+#if defined(ZLIB_DLL)
+#  if defined(_WINDOWS) || defined(WINDOWS)
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+#    define ZEXPORT  WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA  WINAPIV
+#    else
+#      define ZEXPORTVA  FAR _cdecl _export
+#    endif
+#  endif
+#  if defined (__BORLANDC__)
+#    if (__BORLANDC__ >= 0x0500) && defined (WIN32)
+#      include <windows.h>
+#      define ZEXPORT __declspec(dllexport) WINAPI
+#      define ZEXPORTRVA __declspec(dllexport) WINAPIV
+#    else
+#      if defined (_Windows) && defined (__DLL__)
+#        define ZEXPORT _export
+#        define ZEXPORTVA _export
+#      endif
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  if defined (ZLIB_DLL)
+#    define ZEXTERN extern __declspec(dllexport)
+#  else
+#    define ZEXTERN extern __declspec(dllimport)
+#  endif
+#endif
+
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+
+#ifndef FAR
+#   define FAR
+#endif
+
+#if !defined(MACOS) && !defined(TARGET_OS_MAC)
+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 FAR *voidpf;
+   typedef void     *voidp;
+#else
+   typedef Byte FAR *voidpf;
+   typedef Byte     *voidp;
+#endif
+
+#ifdef HAVE_UNISTD_H
+#  include <sys/types.h> /* for off_t */
+#  include <unistd.h>    /* for SEEK_* and off_t */
+#  define z_off_t  off_t
+#endif
+#ifndef SEEK_SET
+#  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
+
+/* 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(inflateInit_,"ININ")
+#   pragma map(inflateInit2_,"ININ2")
+#   pragma map(inflateEnd,"INEND")
+#   pragma map(inflateSync,"INSY")
+#   pragma map(inflateSetDictionary,"INSEDI")
+#   pragma map(inflate_blocks,"INBL")
+#   pragma map(inflate_blocks_new,"INBLNE")
+#   pragma map(inflate_blocks_free,"INBLFR")
+#   pragma map(inflate_blocks_reset,"INBLRE")
+#   pragma map(inflate_codes_free,"INCOFR")
+#   pragma map(inflate_codes,"INCO")
+#   pragma map(inflate_fast,"INFA")
+#   pragma map(inflate_flush,"INFLU")
+#   pragma map(inflate_mask,"INMA")
+#   pragma map(inflate_set_dictionary,"INSEDI2")
+#   pragma map(inflate_copyright,"INCOPY")
+#   pragma map(inflate_trees_bits,"INTRBI")
+#   pragma map(inflate_trees_dynamic,"INTRDY")
+#   pragma map(inflate_trees_fixed,"INTRFI")
+#   pragma map(inflate_trees_free,"INTRFR")
+#endif
+
+#endif /* _ZCONF_H */
diff --git a/zlib/zlib.h b/zlib/zlib.h
new file mode 100644 (file)
index 0000000..52cb529
--- /dev/null
@@ -0,0 +1,893 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.1.4, March 11th, 2002
+
+  Copyright (C) 1995-2002 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 ftp://ds.internic.net/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.1.4"
+
+/* 
+     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 (for example if an input file is mmap'ed), 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 library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio.
+
+     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 {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb 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 nb of bytes output so far */
+
+    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: ascii or binary */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+   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 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+/* Allowed flush values; see deflate() 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_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field */
+
+#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,
+   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.
+
+    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.
+
+    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
+  the 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).
+
+    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
+  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
+  Z_STREAM_END, then 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 data_type if it can make a good guess about
+  the input data type (Z_ASCII or Z_BINARY). 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 NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero).
+*/
+
+
+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.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+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 some
+  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.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
+  output as possible to the output buffer. The flushing behavior of inflate is
+  not specified for values of the flush parameter other than Z_SYNC_FLUSH
+  and Z_FINISH, but the current implementation actually flushes as much output
+  as possible anyway.
+
+    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 the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster routine
+  may be used for the single inflate() call.
+
+     If a preset dictionary is needed at this point (see inflateSetDictionary
+  below), inflate sets strm-adler to the adler32 checksum of the
+  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise 
+  it sets strm->adler to the adler32 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() 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
+  adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
+  (for example if next_in or next_out was 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. In the Z_DATA_ERROR
+  case, the application may then call inflateSync to look for a good
+  compression block.
+*/
+
+
+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.
+
+     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), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match).  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 and Z_HUFFMAN_ONLY. The strategy parameter only affects
+   the compression ratio but not the correctness of the compressed output even
+   if it is not set appropriately.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). 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. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. 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 in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front.
+
+     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.)
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). 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 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 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 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. 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.
+
+      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
+   memLevel). msg is set to null if there is no error message.  inflateInit2
+   does not perform any decompression apart from reading the zlib header if
+   present: this will be done by inflate(). (So next_in and avail_in may be
+   modified, but next_out and avail_out are unchanged.)
+*/
+
+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 this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the Adler32 value returned by this call of
+   inflate. The compressor and decompressor must use exactly the same
+   dictionary (see deflateSetDictionary).
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) 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 inflateSync OF((z_streamp strm));
+/* 
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a 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 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 NULL).
+*/
+
+
+                        /* 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 easily 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 0.1% larger than
+   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+   compressed buffer.
+     This function can be used to compress a whole file at once if the
+   input file is mmap'ed.
+     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 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.
+*/
+
+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 compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     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.
+*/
+
+
+typedef voidp gzFile;
+
+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". (See the description
+   of deflateInit2 for more information about the strategy parameter.)
+
+     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.
+
+     gzopen returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).  */
+
+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 (in 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 gzdopen(dup(fd), mode).
+     gzdopen returns NULL if there was insufficient memory to allocate
+   the (de)compression state.
+*/
+
+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 was not in gzip format, gzread copies the given number
+   of bytes into the buffer.
+     gzread returns the number of uncompressed bytes actually read (0 for
+   end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT    gzwrite OF((gzFile file, 
+                                  const voidp buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes actually written
+   (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA   gzprintf OF((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).
+*/
+
+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.  The string is then terminated with a null
+   character.
+      gzgets returns buf, or Z_NULL in case of error.
+*/
+
+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.
+*/
+
+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 returns Z_OK if
+   the flush parameter is Z_FINISH and all output could be flushed.
+     gzflush should be called only when strictly necessary because it can
+   degrade compression.
+*/
+
+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.
+
+   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state. The return value is the zlib
+   error number (see function gzerror below).
+*/
+
+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.
+*/
+
+                        /* 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 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 crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running crc with the bytes buf[0..len-1] and return the updated
+   crc. If buf is 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();
+*/
+
+
+                        /* 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));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char   * ZEXPORT zError           OF((int err));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
diff --git a/zlib/zutil.c b/zlib/zutil.c
new file mode 100644 (file)
index 0000000..08166c0
--- /dev/null
@@ -0,0 +1,225 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* @(#) $Id: zutil.c,v 1.2 2002/03/13 17:45:56 xodnizel Exp $ */
+
+#include "zutil.h"
+
+struct internal_state      {int dummy;}; /* for buggy compilers */
+
+#ifndef STDC
+extern void exit OF((int));
+#endif
+
+const char *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;
+}
+
+#ifdef DEBUG
+
+#  ifndef verbose
+#    define verbose 0
+#  endif
+int z_verbose = verbose;
+
+void z_error (m)
+    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(err)
+    int err;
+{
+    return ERR_MSG(err);
+}
+
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+    Bytef* dest;
+    const Bytef* source;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = *source++; /* ??? to be unrolled */
+    } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+    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 zmemzero(dest, len)
+    Bytef* dest;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = 0;  /* ??? to be unrolled */
+    } while (--len != 0);
+}
+#endif
+
+#ifdef __TURBOC__
+#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
+/* Small and medium model in Turbo C are for now limited to near allocation
+ * with reduced MAX_WBITS and MAX_MEM_LEVEL
+ */
+#  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 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  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
+#endif /* __TURBOC__ */
+
+
+#if defined(M_I86) && !defined(__32BIT__)
+/* Microsoft C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+#  define _halloc  halloc
+#  define _hfree   hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    return _halloc((long)items, size);
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    _hfree(ptr);
+}
+
+#endif /* MSC */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp  calloc OF((uInt items, uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+    voidpf opaque;
+    unsigned items;
+    unsigned size;
+{
+    if (opaque) items += size - size; /* make compiler happy */
+    return (voidpf)calloc(items, size);
+}
+
+void  zcfree (opaque, ptr)
+    voidpf opaque;
+    voidpf ptr;
+{
+    free(ptr);
+    if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/zlib/zutil.h b/zlib/zutil.h
new file mode 100644 (file)
index 0000000..507cab9
--- /dev/null
@@ -0,0 +1,220 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2002 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,v 1.2 2002/03/13 17:45:56 xodnizel Exp $ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#ifdef STDC
+#  include <stddef.h>
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+    extern int errno;
+#else
+#   include <errno.h>
+#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 const char *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 = (char*)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 */
+
+#ifdef MSDOS
+#  define OS_CODE  0x00
+#  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 <alloc.h>
+#    endif
+#  else /* MSC or DJGPP */
+#    include <malloc.h>
+#  endif
+#endif
+
+#ifdef OS2
+#  define OS_CODE  0x06
+#endif
+
+#ifdef WIN32 /* Window 95 & Windows NT */
+#  define OS_CODE  0x0b
+#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
+
+#ifdef AMIGA
+#  define OS_CODE  0x01
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  define OS_CODE  0x05
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+#  define OS_CODE  0x07
+#  if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+#    include <unix.h> /* for fdopen */
+#  else
+#    ifndef fdopen
+#      define fdopen(fd,mode) NULL /* No fdopen() */
+#    endif
+#  endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+#  define OS_CODE  0x0F
+#endif
+
+#ifdef TOPS20
+#  define OS_CODE  0x0a
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+#  define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+#  define fdopen(fd,type)  _fdopen(fd,type)
+#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 */
+
+#ifdef HAVE_STRERROR
+   extern char *strerror OF((int));
+#  define zstrerror(errnum) strerror(errnum)
+#else
+#  define zstrerror(errnum) ""
+#endif
+
+#if defined(pyr)
+#  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
+   extern void zmemcpy  OF((Bytef* dest, const Bytef* source, uInt len));
+   extern int  zmemcmp  OF((const Bytef* s1, const Bytef* s2, uInt len));
+   extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  include <stdio.h>
+   extern int z_verbose;
+   extern void 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
+
+
+typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
+                                      uInt len));
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void   zcfree  OF((voidpf opaque, voidpf ptr));
+
+#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);}
+
+#endif /* _Z_UTIL_H */