--- /dev/null
+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
--- /dev/null
+
+ 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.
--- /dev/null
+.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.
--- /dev/null
+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.
--- /dev/null
+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.
--- /dev/null
+----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.
--- /dev/null
+*** 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).
--- /dev/null
+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.
--- /dev/null
+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.
+
--- /dev/null
+*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 ^_^.
+
+
+
+
--- /dev/null
+/******************************************************************************/
+/* 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
+
+
--- /dev/null
+/******************************************************************************/
+/* 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)
+
+
--- /dev/null
+/******************************************************************************/
+/* 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.
+
+
--- /dev/null
+/******************************************************************************/
+/* 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.
+
+
--- /dev/null
+/******************************************************************************/
+/* 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.
+
--- /dev/null
+/******************************************************************************/
+/* 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.
--- /dev/null
+/******************************************************************************/
+/* 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".
+
+
--- /dev/null
+/******************************************************************************/
+/* 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.
+
+
--- /dev/null
+/******************************************************************************/
+/* 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.
+
+
--- /dev/null
+/******************************************************************************/
+/* 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.
+
+
--- /dev/null
+/******************************************************************************/
+/* 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.
+
--- /dev/null
+/******************************************************************************/
+/* 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
+
--- /dev/null
+/******************************************************************************/
+/* 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.
+
+
--- /dev/null
+/******************************************************************************/
+/* 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.
+
--- /dev/null
+/******************************************************************************/
+/* 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.
+
+
--- /dev/null
+/******************************************************************************/
+/* 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).
+
+
--- /dev/null
+/******************************************************************************/
+/* 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.
+
+
--- /dev/null
+/******************************************************************************/
+/* 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.
+
+
--- /dev/null
+/******************************************************************************/
+/* 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.
+
+
--- /dev/null
+/******************************************************************************/
+/* 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).
+
--- /dev/null
+/******************************************************************************/
+/* 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.)
+
+
--- /dev/null
+/******************************************************************************/
+/* 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.
--- /dev/null
+#!/bin/sh
+
+./da.sh linux
+./da.sh win
+./da.sh dos
--- /dev/null
+#!/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
--- /dev/null
+ * 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.
--- /dev/null
+ * 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.
--- /dev/null
+ * 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.
+
--- /dev/null
+ 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.
--- /dev/null
+ 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.
--- /dev/null
+ 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.
--- /dev/null
+
+
+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
+
--- /dev/null
+ FCE Ultra
+ 0.81
+
+ http://fceultra.sourceforge.net/
+
+
+What is new:
+
--- /dev/null
+ FCE Ultra
+ 0.81
+
+ http://fceultra.sourceforge.net/
+
+
+What is new:
+
--- /dev/null
+ FCE Ultra
+ 0.81
+
+ http://fceultra.sourceforge.net/
+
+
+What is new:
+
--- /dev/null
+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
--- /dev/null
+Sound information is in the "cpu" subdirectory, due to the intimate
+relationship between the sound circuitry and the cpu.
--- /dev/null
+****************************************************************************
+ 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.
--- /dev/null
+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.
--- /dev/null
+#
+# $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.
+
+
--- /dev/null
+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.
+
+
--- /dev/null
+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.
+
--- /dev/null
+========= 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
--- /dev/null
+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)
+
--- /dev/null
+ 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!
+
+
+
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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!
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
+
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+#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"
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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");
+}
+
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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");
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
+
+
--- /dev/null
+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);
--- /dev/null
+/* 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;
+ }
+
+ }
+}
--- /dev/null
+void FCEU_CheatResetRAM(void);
+void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p);
+
+void LoadGameCheats(void);
+void FlushGameCheats(void);
+void ApplyPeriodicCheats(void);
--- /dev/null
+/* 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
--- /dev/null
+#ifdef ZLIB
+#include <zlib.h>
+#define CalcCRC32 crc32
+#else
+uint32 CalcCRC32(uint32 crc, uint8 *buf, uint32 len);
+#endif
--- /dev/null
+/* 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);
+
+}
--- /dev/null
+void DumpMem(char *fname, uint32 start, uint32 end);
+
--- /dev/null
+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;
+ }
+
+}
--- /dev/null
+#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);
+
--- /dev/null
+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 */
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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(®s,0,sizeof(regs));\r
+ regs.x.ax=0;\r
+ __dpmi_int(0x33,®s);\r
+ if(regs.x.ax!=0xFFFF)\r
+ return(0);\r
+\r
+ memset(®s,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,®s);\r
+\r
+ memset(®s,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,®s);\r
+\r
+ memset(®s,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,®s);\r
+\r
+ memset(®s,0,sizeof(regs));\r
+ regs.x.ax=0x2;\r
+ __dpmi_int(0x33,®s);\r
+\r
+ return(1);\r
+}\r
+\r
+uint32 GetMouseData(uint32 *x, uint32 *y)\r
+{\r
+ __dpmi_regs regs;\r
+\r
+ memset(®s,0,sizeof(regs));\r
+ regs.x.ax=0x3;\r
+ __dpmi_int(0x33,®s);\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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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(®s,0,sizeof(regs));\r
+ regs.x.ax=mode;\r
+\r
+ __dpmi_int(0x10,®s);\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
--- /dev/null
+/* 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
--- /dev/null
+#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));
+}
+
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+ }
+}
--- /dev/null
+#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
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+extern int joy[4];
+extern int joyBMap[4][4];
+
--- /dev/null
+/* 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();
+}
+
--- /dev/null
+/* 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;
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+extern char *netplayhost;
+extern int Port;
+extern int FDnetplay;
+#define netplay FDnetplay
+
--- /dev/null
+/* 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
--- /dev/null
+/* 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));
+}
--- /dev/null
+uint32 PtoV(uint16 x, uint16 y);
--- /dev/null
+#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);
+ }
+}
+
--- /dev/null
+#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
--- /dev/null
+/* 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" );
+ }
+ }
+}
+
+
--- /dev/null
+/* 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);
+
--- /dev/null
+#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));
+}
--- /dev/null
+#define DO_VSYNC 1
+extern int doptions;
--- /dev/null
+#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;
+}
+
--- /dev/null
+void RefreshThrottleFPS(void);
+void SpeedThrottle(void);
--- /dev/null
+#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");
+ }
+}
+
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+extern char *netplayhost;
+extern int Port;
+extern int FDnetplay;
+#define netplay FDnetplay
+
--- /dev/null
+/* 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.");
+}
--- /dev/null
+/* 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;
+ }
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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}
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
--- /dev/null
+/* 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;
+ }
+}
--- /dev/null
+/* 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);
--- /dev/null
+/* 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
--- /dev/null
+void ConfigCheats(HWND hParent);\r
--- /dev/null
+#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
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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
--- /dev/null
+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
--- /dev/null
+/* 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
--- /dev/null
+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
--- /dev/null
+/* 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);
+}
--- /dev/null
+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
--- /dev/null
+/* 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
+
--- /dev/null
+/* 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();
+}
+
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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
+}
+
--- /dev/null
+int write16(uint16 b, FILE *fp);
+int write32(uint32 b, FILE *fp);
+int read32(void *Bufo, FILE *fp);
--- /dev/null
+/* 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();
+}
+
--- /dev/null
+#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
+
--- /dev/null
+/* 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
--- /dev/null
+/* 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);
+}
--- /dev/null
+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);
--- /dev/null
+/* 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;
+}
--- /dev/null
+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);
+
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+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
--- /dev/null
+#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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
--- /dev/null
+/* 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();
+}
--- /dev/null
+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);
--- /dev/null
+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
--- /dev/null
+/* 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);
+}
--- /dev/null
+#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;
+ }
+ }
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+#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
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
+
+
--- /dev/null
+#include "../types.h"
+#include "../input.h"
+#include "../fce.h"
+#include "../svga.h"
+#include "../x6502.h"
+
+void FCEU_DrawCursor(uint8 *buf, int xc, int yc);
--- /dev/null
+/* 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);
+}
+
+
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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. */
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper180_write)
+{
+ROM_BANK16(0xC000,V);
+}
+
+void Mapper180_init(void)
+{
+ SetWriteHandler(0x8000,0xffff,Mapper180_write);
+}
+
--- /dev/null
+#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;
+}
+
--- /dev/null
+#include "mapinc.h"
+
+
+
+DECLFW(Mapper184_write)
+{
+VROM_BANK4(0x0000,V);
+VROM_BANK4(0x1000,(V>>4));
+}
+
+void Mapper184_init(void)
+{
+ SetWriteHandler(0x6000,0xffff,Mapper184_write);
+}
+
--- /dev/null
+/* 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);
+}
+
+
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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
--- /dev/null
+/* 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();
+}
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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();
+}
+
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
+
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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();
+}
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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");
+
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+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
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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
--- /dev/null
+#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"
--- /dev/null
+void MMC3_hb(void);
+
+#define resetmode mapbyte1[0]
+#define MMC3_cmd mapbyte1[1]
+
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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;
+ }
+}
--- /dev/null
+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
--- /dev/null
+#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"
--- /dev/null
+/* 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);
+}
+
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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)++;
+ }
+}
--- /dev/null
+/* 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);
--- /dev/null
+/* 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
--- /dev/null
+#ifdef NETWORK
+int InitNetplay(void);
+void KillNetplay(void);
+void NetplayUpdate(uint16 *JS1, uint16 *JS2);
+
+extern int netplay;
+#endif
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
--- /dev/null
+/* 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
+};
--- /dev/null
+/* 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);
--- /dev/null
+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 */
+};
--- /dev/null
+{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},
--- /dev/null
+{ 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, },
--- /dev/null
+{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},
--- /dev/null
+{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},
--- /dev/null
+ { 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 */
+
--- /dev/null
+ { 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 */
+
--- /dev/null
+{ 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 },
--- /dev/null
+{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}
--- /dev/null
+{ 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 },
--- /dev/null
+{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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
--- /dev/null
+/* 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"},
+ { ×tamp, 4|RLSB, "TIME"},
+ { ×tampbase, 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;
+}
+
--- /dev/null
+/* 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);
+
--- /dev/null
+/* 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;
+ }
+}
--- /dev/null
+/* 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);
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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...
--- /dev/null
+#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
--- /dev/null
+/* 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
--- /dev/null
+int InitVirtualVideo(void);
+int SaveSnapshot(void);
+extern uint8 *XBuf;
--- /dev/null
+/* 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"
+ }
+ }
+}
--- /dev/null
+/* 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);
--- /dev/null
+
+ 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()
--- /dev/null
+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
--- /dev/null
+/* 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;
+}
--- /dev/null
+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
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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
--- /dev/null
+# 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
--- /dev/null
+/* 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 */
+}
--- /dev/null
+
+ 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".
+
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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));
--- /dev/null
+/* 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"));
+}
--- /dev/null
+/* 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 ));
+
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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 ));
--- /dev/null
+/* 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}
+ };
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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(" };");
+}
--- /dev/null
+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.
--- /dev/null
+/* 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++);
+ }
+}
--- /dev/null
+/* 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
+};
+
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 */