aboutsummaryrefslogtreecommitdiff
path: root/source/doc/porting.txt
diff options
context:
space:
mode:
Diffstat (limited to 'source/doc/porting.txt')
-rw-r--r--source/doc/porting.txt725
1 files changed, 725 insertions, 0 deletions
diff --git a/source/doc/porting.txt b/source/doc/porting.txt
new file mode 100644
index 0000000..3d28eec
--- /dev/null
+++ b/source/doc/porting.txt
@@ -0,0 +1,725 @@
+ How to Port Snes9x to a New Platform
+ ====================================
+
+Version: 1.01
+Date: 23-December-1998
+
+(c) Copyright 1998 Gary Henderson (gary@daniver.demon.co.uk)
+
+Introduction
+============
+
+This is brief description of the steps involved in porting Snes9x, the Super
+Nintendo Entertainment System emulator, to new hardware which is at least
+similar to Workstation or PC. It describes what code you have to write and
+what functions exist that you can make use of. It also gives some insights as
+to how Snes9x actually works, although that will be subject of another
+document yet to be written.
+
+Host System Requirements
+========================
+
+A C++ compiler, so you can compile the emulator! Snes9x really isn't written
+in C++, it just uses the C++ compiler as a 'better C' compiler to get inline
+functions and so on. With some modification, it could be converted to be
+compiled with an ordinary C compiler. Snes9x isn't very C type safe and
+will probably not work on a system who's integers are less than 32-bits wide
+without lots of editing.
+
+If the host system uses a CPU that implements the i386 instruction set then
+you will also want to use the three assembler CPU cores, although I recently
+scrapped the SPC700 assembler code (too many bugs) and replaced it with
+compiler generated assembler code that I haven't got around to optimising
+yet. The 65c816 and SPC700 code needs to be assembled using the GNU
+assembler that comes with gcc and the Super FX code assembled with NASM
+v0.97 or higher. gcc is available from lots of sites. NASM is available from
+http://www.cryogen.com/Nasm
+
+A fast CPU. SNES emulation is very compute intensive: two, or sometimes three
+CPUs to emulate, an 8-channel 16-bit stereo sound digital signal processor
+with real-time sample decompression, filter and echo effects, two custom
+graphics processor chips that can produce transparency, scaling, rotation
+and window effects in 32768 colors, and finally hardware DMA all take their
+toll on the host CPU.
+
+Lots of RAM. The SNES itself has 128k work RAM, 64k V-RAM and 64k sound CPU
+RAM. If a Super FX game is being emulated, that usually comes with another
+64k inside the game pack. Snes9x itself needs 4Mb to load SNES ROM images
+into (or 6Mb if I ever figure out the SNES memory map of the 48Mbit ROM
+images out there), 256k to cache decompressed sound samples in, 512k to
+cache converted SNES tiles in, and another 64k for S-RAM emulation. And
+that's not counting a few large lookup tables that the graphics code needs
+for speeding up transparency effects plus few other tables used by the ZSNES
+Super FX code. It all adds up to 7Mb (ish). Add to that RAM needed to
+store the actual emulator code and RAM required by the host operating system
+and any other process that is running; that's lots of RAM. Well, it is if
+your host system only has a few mega-bytes of RAM available.
+
+An 8-bit, 256 color (one byte per pixel) or deeper display, at least 256x239
+pixels in resolution, or 512x478 if you're going to support the SNES'
+hi-res. background screen modes. Ideally, a 16-bit, 65536 color screen mode
+is required if you want to support transparency at speed, as that is what the
+code renders internally. Any other format screen, with transparency enabled,
+will require picture format conversion before you can place the rendered
+SNES image on to the screen.
+
+Sound output requires spooling 8-bit or 16-bit, mono or stereo digital sound
+data to the host computer's sound hardware. The DOS port uses interrupts
+from the sound card to know when more sound data is required, most other
+ports have to periodically poll the host sound hardware to see if more data
+is required; if it is then the SNES sound mixing code provided by Snes9x is
+called to fill an area of system memory with ready mixed SNES sound data,
+which then can be passed on to the host sound hardware. Sound data is
+generated as an array of bytes (uint8) for 8-bit sound or shorts (int16) for
+16-bit data. Stereo sound data generates twice as many samples, with each
+channel's samples interleaved, first left's then right's.
+
+For the user to be able to control and play SNES games, some form of input
+device is required, a joystick or keyboard, for example. The real SNES can
+have 2 eight-button digital joy-pads connected to it or 5 joy-pads when an
+optional multi-player adaptor was purchased, although most games only require
+a single joy-pad. Access to all eight buttons and the direction pad, of
+course, are usually required by most games. Snes9x does emulate the
+multi-player adaptor hardware, if you were wondering, but its still up to
+you to provide the emulation of the individual joy-pads.
+
+The SNES also had a mouse and light gun available as optional extras,
+Snes9x can emulate both of these using some form of pointing device,
+usually the host system's mouse.
+
+If an accurate, constant SNES play rate is required, then a real-time timer
+will be needed that can time intervals of 16.7ms (NTSC frame time) or 20ms
+(PAL frame time).
+
+Some SNES game packs contained a small amount of extra RAM and a battery so
+ROMs could save a player's progress through a game for games that takes many
+hours to play from start to finish. Snes9x simulates this S-RAM by saving
+the contents of the area of memory normally occupied by the S-RAM into file
+then automatically restoring it again the next time the user plays the same
+game. If the hardware you're porting to doesn't have a hard disk available
+then you could be in trouble.
+
+Snes9x also implements freeze-game files which can record the state of the
+SNES hardware and RAM at a particular point in time and can restore it to
+that exact state at a later date - the result is that users can save a game
+at any point, not just at save-game or password points provided by the
+original game coders. Each freeze file is over 400k in size. To help save
+disk space, Snes9x can be compiled with zlib, which is used to compress the
+freeze files, reducing the size to typically below 100k. Download zlib from
+its homepage at http://www.cdrom.com/pub/infozip/zlib/, compile Snes9x with
+ZLIB defined and link with zlib. zlib is also used to load any compressed
+ROM images Snes9x my encounter, compressed with gzip or compress.
+
+Porting
+=======
+
+In theory you will only need to edit port.h, then in a separate file write
+all the initialisation code and interface routines that Snes9x expects the
+you to implement. You, no doubt, will discover otherwise....
+
+There are several compile-time only options available:
+
+DEBUGGER
+--------
+
+Enables extra code to assist me in debugging SNES ROMs. The debugger has only
+ever been a quick-hack by me and user-interface to debugger facilities is
+virtually non-existent. Most of the debugger information is output via
+stdout and enabling the compile-time options slows the whole emulator down
+slightly. However, the debugger options available are very powerful; you
+could use it to help get your port working. You probably still want to ship
+the finished version with the debugger disabled, it will only confuse
+non-technical users.
+
+VAR_CYCLES
+----------
+
+I recommend you define this. The main CPU in the SNES actually varies in
+speed depending on what area of memory its accessing and the ROM access
+speed of the game pack; defining VAR_CYCLES causes Snes9x to emulate this,
+using a good approximation, rather than fixed cycle length as ZSNES does. The
+resultant code is slightly slower. Leaving it undefined results in many more
+emulation timing errors appearing while playing games.
+
+CPU_SHUTDOWN and SPC700_SHUTDOWN
+--------------------------------
+
+Again I recommend defining both of these. They are both speed up hacks.
+When defined, Snes9x starts watching for when either the main or sound CPUs
+are in simply loops waiting for a known event to happen - like the end of
+the current scan-line, and interrupt or a sound timer to reach a particular
+value. If Snes9x spots either CPU in such a loop it uses its insider
+knowledge to simply skip the emulation of that CPU's instructions until the
+event happens. It can be a big win with lots of SNES games.
+
+I'm constantly amazed at the ingenuity of some programmers who are able to
+produce complex code to do simple things: some ROM's wait loops are so
+complex Snes9x fails to spot the CPU is in such a loop and the shutdown
+speed up hacks don't work.
+
+You might be wondering why VAR_CYCLES, and the two SHUTDOWN options have to
+be enabled with defines, well, in the past they sometimes introduced
+problems with some ROMs, so I kept them as options. I think I've fixed all
+the problems now, but you never know...
+
+SPC700_C
+--------
+
+Define this if you are using the C/C++ version of the SPC700 CPU core. It
+enables a ROM compatibility feature that executes SPC700 instructions during
+SNES DMA, it allows several games to start that would otherwise lock up and
+fixes music pauses when ROMs do lots of DMA, usually when switching between
+game screens.
+
+ZLIB
+----
+
+Define this if you have the zlib library available and you want it to
+compress freeze-game files to save disk space. The library is also used to
+support compressed ROM images.
+
+NO_INLINE_SET_GET
+-----------------
+
+Define this to stop several of the memory access routines from being
+defined in-line. Whether the C++ compiler actually in-lines when this symbol
+is not defined is up to the compiler itself. In-lines functions can speed up
+the C++ CPU emulations on some architectures at the cost of increased code
+size. Try fiddling with this option once you've got port working to see if
+it helps the speed of your port.
+
+EXECUTE_SUPERFX_PER_LINE and ZSNES_FX
+-------------------------------------
+
+Define these if you're going to be using the ZSNES Super FX i386 assembler
+code, otherwise leave them both undefined. In theory,
+EXECUTE_SUPERFX_PER_LINE can also be defined when using the C++ Super FX
+emulation code, but the code is still buggy and enabling the option
+introduces more problems than it fixes. Any takers for fixing the C++ code?
+
+JOYSTICK_SUPPORT, SIDEWINDER_SUPPORT and GRIP_SUPPORT
+-----------------------------------------------------
+
+These options enable support for various input devices in the UNIX and MS-DOS
+port code. They're only of interest if you're able to use the existing UNIX
+or MS-DOS port specific code.
+
+port.h
+======
+
+If the byte ordering of the target system is least significant byte first,
+make sure LSB_FIRST is defined in this header, otherwise, make sure its not
+defined.
+
+If you're going to support 16-bit screen rendering (required if you want
+transparency effects) and your system doesn't use RGB 565 - 5 bits for red,
+6 bits for green and 5 bits for blue - then you'll need make sure RGB555,
+BGR565 or BGR555 is defined instead. You might want to take a look at the
+*_LOW_BIT_MASKs, *_HI_BIT_MASKs and BUILD_PIXEL macros to make sure they're
+correct, because I've only every tested the RGB565 version, though the Mac
+port uses the RGB555 option. If your system is 24 or 32-bit only, then
+don't define anything; instead write a conversion routine that will take a
+complete rendered 16-bit SNES screen in RGB565 format and convert to the
+format required to be displayed on your hardware.
+
+port.h also typedefs some types, uint8 for an unsigned, 8-bit quantity,
+uint16 for an unsigned, 16-bit quantity, uint32 for a 32-bit, unsigned
+quantity and bool8 for a true/false type. Signed versions are also
+typedef'ed.
+
+The CHECK_SOUND macro can be defined to invoke some code that polls the
+host system's sound hardware to see if it can accept any more sound data.
+Snes9x makes calls to this macro several times when it is rendering the SNES
+screen, during large SNES DMAs and after every emulated CPU instruction.
+
+Since this CHECK_SOUND macro is invoked often, the code should only take a
+very small amount of time to execute or it will slow down the emulator's
+performance. The Linux and UNIX ports use a system timer and set a variable
+when it has expired; the CHECK_SOUND only has to check to see if the
+variable is set. On the MS-DOS and Mac ports, the sound hardware is not
+polled at all, instead it is driven by interrupts or callbacks and the
+CHECK_SOUND macro is defined to be empty.
+
+Initialisation Code
+-------------------
+
+This is what the Linux, UNIX and MS-DOS ports do, I suspect your code
+might be similar:
+
+- The Settings structure is initialised to some sensible default values -
+ check the main function in unix.cpp for the values it uses.
+
+- The command line is parsed, options specified override default values in
+ the Settings structure and specify a ROM image filename that the user
+ wants loaded. Your port could load user preferences from a file or some
+ other source at this point. Most values, with a little care, can be changed
+ via a GUI once the emulator is running.
+
+- Some Settings structure value validation takes place, for example if
+ transparency effects are requested the code also makes sure 16-bit
+ screen rendering is turned on as well.
+
+- Memory.Init() and S9xInitAPU() are called, checking neither failed. The
+ only reason they would fail is if memory allocation failed.
+
+- Memory.LoadROM (filename) is called to load the specified ROM image into
+ memory. If that worked Memory.LoadSRAM (sram_filename) is called to load
+ the ROM's S-RAM file, if one exists. The all current ports base the
+ sram_filename on the filename of the ROM image, changing the file's
+ extension (the .smc or whatever bit) and changing the directory where its
+ located - you won't be able to save S-RAM files onto a CD if that's where
+ the ROM image is located!
+
+ If your port has a GUI, you can delay this step until the user picks an
+ image to load.
+
+ SNES roms images come in all shapes and sizes, some with headers, some
+ without, some have been mangled by the copier device in one of two ways, and
+ some split into several pieces; plus the SNES itself has several different
+ memory map models. The code tries to auto-detect all these various types,
+ but sometimes the SNES ROM header information has been manually edited by
+ someone at some stage and the code guesses wrong. To help it out it these
+ situations, the Settings structure contains several options to force a
+ particular ROM image format; these values must be initialised prior to each
+ call to Memory.LoadROM(filename).
+
+- The Linux and UNIX ports now do some more operating system initialisation
+ ready for a system timer to be started.
+
+- The host display hardware is now initialised. The actual screen depth and
+ resolution should be picked based on the user preferences if possible.
+ The X Window System port can't control the screen depth or resolution, if
+ the user requests transparency effects but the display hardware is only
+ set to 8-bit, it has to invoke an extra step of converting the 16-bit SNES
+ rendered screen to a fixed palette 8-bit display just before the SNES
+ screen is copied to the display hardware.
+
+ The GFX.Screen pointer needs to be initialised to point to an array of
+ uint8 for 8-bit screen rendering or uint16 for 16-bit rendering, cast to
+ an array of uint8. The array needs to be at least 256x239 bytes or shorts
+ in size for lo-res only support (Settings.SupportHiRes = FALSE) or
+ 512x478 for lo-res and hi-res support. If transparency effects are
+ required, the GFX.SubScreen array also needs to be initialised to another
+ identically sized array of the same type, otherwise it can be just
+ initialised to NULL.
+
+ The GFX.Pitch variable needs to be set to the number of bytes on each line
+ of the arrays, e.g. 256 for lo-res only support, up to 1024 for 16-bit
+ hi-res support. If GFX.Screen is pointing into an existing array, one
+ created by the library function rather than just calling malloc or new,
+ then set GFX.Pitch to the number of bytes per line of that array,
+ including any padding the library function may have added.
+
+ If the target hardware supports fast access to video RAM, the screen is in
+ 16-bit format supported by the SNES rendering code and you can double
+ buffer the display, you might want to point GFX.Screen directly at the
+ video buffer RAM. You will need to recompute the GFX.Delta value every
+ time you change the GFX.Screen value to double-buffer the rendering and
+ display.
+
+- A call to S9xGraphicsInit() is made; make sure all your graphics rendering
+ options are setup correctly by now. If later, you want to change some
+ settings, for example 16-bit to 8-bit rendering, call S9xGraphicsDeinit()
+ first, change your settings, GFX.Screen and GFX.SubScreen arrays, etc.,
+ then call S9xGraphicsInit() again.
+
+- S9xInitSound(int playbackrate, bool8 stereo, int sound_buffer_size)
+ is now called, which in turn will call your S9xOpenSoundDevice function -
+ see below.
+
+- The display is switched to graphics mode using a call to S9xGraphicsMode().
+
+- The system timer is started; its used for keeping the emulator speed
+ relatively constant on the MS-DOS port and noting when the sound hardware
+ sound should be able to accept more sound data on the Linux and UNIX ports.
+
+- A main loop is entered which is just a loop constantly calling
+ S9xMainLoop() then polling the operating system for any pending events
+ such as key presses and releases, joystick updates, mouse position
+ updates, GUI user interaction, etc.
+
+ Pause functionality can be implemented by skipping the call to S9xMainLoop
+ and muting the sound output by calling S9xSetSoundMute (TRUE).
+
+ Don't enter the main loop until a SNES ROM image has been loaded, or at
+ least skip calling S9xMainLoop inside the loop until one is and make sure
+ S9xReset is called instead before entering the main loop. The Mac port
+ implements this technique by starting in pause mode and refusing to unpause
+ until a ROM image is loaded.
+
+ S9xMainLoop processes SNES CPU emulation, SNES screen rendering, DMA and
+ H-DMA emulation, until emulated scan-line 0 is reached, then it returns.
+ Now is your chance to process any system events pending, scan the
+ keyboard, read joystick values, etc.
+
+ If DEBUGGER compile-time support is enabled and the CPU emulation has hit
+ a break point or single-stepping is switched on, or the DEBUG_MODE_FLAG is
+ set in the CPU.Flags variable, then the S9xMainLoop routine returns early,
+ allowing you to act on the event in some way. The Linux, DOS and UNIX ports
+ respond to the DEBUG_MODE_FLAG being set by calling S9xDoDebug(), which in
+ turn outputs the current instruction and loops reading commands from stdin
+ and outputting debug information, currently via stdout. The debugger
+ desperately needs rewriting to support a GUI interface, more descriptive
+ commands and better error handling; maybe one day...
+
+Existing Interface Routines
+---------------------------
+
+These are routines already written that you will either need to call or
+might find useful.
+
+-> bool8 Memory.Init ()
+
+Allocates and initialises several major lumps of memory, for example
+the SNES ROM and RAM arrays, tile cache arrays, etc. Returns FALSE if
+memory allocation fails.
+
+-> void Memory.Deinit ()
+
+Undoes the memory allocations made by Memory.Init.
+
+-> bool8 S9xGraphicsInit ()
+
+Allocated and initialises several lookup tables used to speed up SNES
+graphics rendering. Call after you have initialised the GFX.Screen,
+GFX.SubScreen and GFX.Pitch values. If Settings.Transparency is false it
+does not allocate tables used to speed up transparency effects. If you
+want to provide the user with option to turn the effects on and off during
+game play, make sure Settings.Transparency is true when this function is
+called, it can later be set to FALSE.
+
+Returns FALSE if memory allocation fails.
+
+-> void S9xGraphicsDeinit ()
+
+Undoes the memory allocations made by S9xGraphicsInit.
+
+-> bool8 S9xInitAPU ()
+
+Allocates and initialises several arrays used by the sound CPU and sound
+generation code.
+
+-> void S9xDeinitAPU ()
+
+Undoes the allocations made by S9xInitAPU.
+
+-> bool8 S9xInitSound (int mode, bool8 stereo, int buffer_size)
+
+Does more sound code initialisation and opens the host system's sound hardware
+by calling the S9xOpenSoundDevice function provided by you.
+
+-> void S9xReset ()
+
+Resets the SNES emulated hardware back to the state it was in at 'switch-on'
+except the S-RAM area is presevered. The effect is it resets the current game
+back to the start. This function is automatically called by Memory.LoROM.
+
+-> bool8 Memory.LoadROM (const char *filename)
+
+Attempts to load the specified ROM image filename into the emulated ROM area.
+There are many different SNES ROM image formats and the code attempts to
+auto-detect as many different types as it can and in a vast majority of the
+cases gets it right. However, some ROM images have been edited by someone at
+some stage or have been mangled by the ROM copier that produced them and
+LoadROM needs help. Inparticular, it can't auto-detect the odd way in which
+some Super FX games have been mangled and needs to be told, via
+Settings.Interleaved2, that the ROM image is in that format, or that
+odd-sized ROM images have a 512 byte copier header.
+
+There are several other ROM image options in the Settings structure;
+allow the user to set them before calling LoadROM, or make sure they all
+reset to default values before each call to LoadROM.
+
+-> bool8 Memory.LoadSRAM (const char *filename)
+
+Call this routine to load the associated S-RAM save file (if any). The
+filename should be based on the ROM image name to allow easy linkage.
+The current ports change the directory and the filename extension of the ROM
+filename to derive the S-RAM filename.
+
+-> bool8 Memory.SaveSRAM (const char *filename)
+
+Call this routine to save the emulated S-RAM area into a file so it can
+be restored again the next time the user wants to play the game. Remember
+to call this when just before the emulator exits or when the user has been
+playing a game and is about to load another one.
+
+-> void S9xMainLoop()
+
+The emulator main loop. Call this from your own main loop that calls this
+function (if a ROM image is loaded and the game is not paused), processes
+any pending host system events, then goes back around the loop again until
+the emulator exits.
+
+S9xMainLoop normally returns control to your main loop once every emulated
+frame, when it reaches the start of scan-line zero. However, the routine
+can return more often if the DEBUGGER compile-time flag is defined and the
+CPU has hit a break point, or the DEBUG_MODE_FLAG bit is set in CPU.Flags
+or instruction single-stepping is enabled.
+
+-> void S9xMixSamples (uint8 *buffer, int sample_count)
+
+Call this routine from your host sound hardware handling code to fill the
+specified buffer with ready mixed SNES sound data. If 16-bit sound mode is
+choosen, then the buffer will be filled with an array of sample_count int16,
+otherwise an array of sample_count uint8. If stereo sound generation is
+selected the buffer is filled with the same number of samples, but in pairs,
+first a left channel sample followed by the right channel sample.
+
+There is a limit on how much data S9xMixSamples can deal with in one go and
+hence a limit on the sample_count value; the limit is the value of the
+MAX_BUFFER_SIZE symbol, normally 4096 bytes.
+
+-> bool8 S9xSetSoundMute (bool8 mute)
+
+Call with a TRUE parmeter to prevent S9xMixSamples from processing SNES
+sample data and instead just filling the return buffer with silent sound
+data. Useful if your sound system is interrupt or callback driven and the
+game has been paused either directly or indirectly because the user
+interacting with the emulator's user interface in some way.
+
+-> bool8 S9xFreezeGame (const char *filename)
+
+Call this routine to record the current SNES hardware state into a file,
+the file can be loaded back using S9xUnfreezeGame at a later date effectively
+restoring the current game to exact same spot. Call this routine while
+you're processing any pending system events when S9xMainLoop has returned
+control to you in your main loop.
+
+-> bool8 S9xUnfreezeGame (const char *filename)
+
+Restore the SNES hardware back to the exactly the state it was in when
+S9xFreezeGame was used to generate the file specified. You have to arrange
+the correct ROM is already loaded using Memory.LoadROM, an easy way to
+arrange this is to base freeze-game filenames on the ROM image name. The
+Linux, UNIX and DOS ports load freeze-game files when the user presses a
+function key, with the names romfilename.000 for F1, romfilename.001 for F2,
+etc. Games are frozen in the first place when the user presses Shift-function
+key. You could choose some other scheme.
+
+-> void S9xNextController ()
+
+The real SNES allows several different types of devices to be plugged into
+the game controller ports. The devices Snes9x emulates are a joy-pad,
+multi-player adaptor (allowing a further 4 joy-pads to be plugged in),
+a 2-button mouse and a light gun known as the SuperScope.
+
+Each call to S9xNextController will step the current emulated device on to
+the next device in the sequence multi-player, joy-pad, mouse on port 1,
+mouse on port 2, light gun then back to multi-player again. Defines
+allocating a number of each device type are in snes9x.h. The currently
+selected device is stored in IPPU.Controller if you want to give some
+feedback to the user. The initial value of IPPU.Controller (set when
+S9xReset is called) is obtained from Settings.ControllerOption based on
+currently enabled options.
+
+Some ROMs object to certain non-joy-pad devices being plugged into the real
+SNES while they are running, all Super FX games should only allow joy-pads to
+be plugged in because the Super FX chip and any other device would overload
+the SNES power supply. Tetris and Dr. Mario also objects for reasons best
+known to itself. For this reason there are switches in the Settings
+structure to enable and display the emulation of the various devices.
+
+const char *S9xGameGenieToRaw (const char *code, uint32 &address, uint8 &byte)
+
+const char *S9xProActionReplayToRaw (const char *code, uint32 &address,
+ uint8 &byte)
+
+const char *S9xGoldFingerToRaw (const char *code, uint32 &address, bool8 &sram,
+ uint8 &num_bytes, uint8 bytes[3])
+
+void S9xApplyCheats (bool8 apply)
+
+void S9xRemoveCheats ()
+
+void S9xAddCheat (uint32 address, bool8 cpu_address, bool8 sram, uint8 num_bytes,
+ uint8 byte1, uint8 byte2, uint8 byte3)
+
+void S9xDeleteCheats ()
+
+void S9xDoDebug ()
+
+Interface Routines You Need to Implement
+----------------------------------------
+
+bool8 S9xOpenSnapshotFile (const char *base, bool8 read_only, STREAM *file)
+***************************************************************************
+void S9xCloseSnapshotFile (STREAM file)
+***************************************
+
+Routines to open and close freeze-game files. STREAM is defined as a
+gzFile if ZLIB is defined else its defined as FILE *. The read_only parameter
+is set to TRUE when reading a freeze-game file and FALSE when writing a
+freeze-game file.
+
+void S9xExit ()
+***************
+
+Called when some fatal error situation arises or when the 'q' debugger
+command is used. The Mac port just beeps and drops back to the GUI when
+S9xExit is called, the MS-DOS, Linux and Solaris ports all call exit () to
+terminate the emulator process.
+
+void S9xParseArg (char **argv, int &index, int argc)
+****************************************************
+
+void S9xExtraUsage ()
+*********************
+
+If you're going to be using the simple command line parser, when it
+encounters an unknown option it calls S9xUsage which is supposed to report
+all options the generic parse knows about (I haven't been keeping it up to
+date of late). S9xUsage then, in turn calls S9xExtraUsage which you
+implement to report any port-specific options available.
+
+void S9xGraphicsMode ()
+***********************
+void S9xTextMode ()
+*******************
+
+The SNES debugger calls these routines to switch from a graphics screen
+mode used to display the SNES game to a debugger screen used to display
+debugger output. If the SNES screen can be displayed at the same time as
+a text display, as would be the case when the host system implements a
+graphical window system, or you're not going to support the SNES debugger,
+then these routines should do nothing.
+
+On the X Window System UNIX/Linux port, these routines do nothing where as
+on the MS-DOS port they switch between a graphics screen mode and a text-only
+screen mode.
+
+bool8 S9xInitUpdate ()
+**********************
+
+Called just before Snes9x starts to render a SNES screen. The Windows port
+uses this call to lock Direct X screen area to allow exclusive access; on
+other existing ports its implemented as an empty function.
+
+bool8 S9xDeinitDisplay (int width, int height, bool8 sixteen_bit)
+*****************************************************************
+
+Called once a complete SNES screen has been rendered into the GFX.Screen
+memory buffer, now is your chance to copy the SNES rendered screen to the
+host computer's screen memory. The problem is that you have to cope with
+different sized SNES rendered screens. Width is always 256, unless you're
+supporting SNES hi-res. screen modes (Settings.SupportHiRes is TRUE), in
+which case it can be 256 or 512. The height parameter can be either 224 or
+239 if you're only supporting SNES lo-res. screen modes, or 224, 239, 448 or
+478 if hi-res. SNES screen modes are being supported.
+
+All current ports support scaling the SNES screen to fill the host system's
+screen, the many ports even supports interpolation - blending the colours of
+adjacent pixels to help hide the fact they've been scaled - and scan-line
+simulation - slightly darkening every other horizontal line.
+
+Don't forget that if you're just placing the SNES image centerally in the
+screen then you might need to clear areas of the screen if the SNES image
+changes size between calls to S9xDeinitDisplay. The MS-DOS and UNIX ports
+currently don't do this which results in junk being left on the screen if
+the ROM changes SNES screen modes.
+
+The sixteen_bit is just a copy of the Settings.SixteenBit setting and if
+TRUE indicates a 16-bit SNES screen image has been rendered, 8-bit otherwise.
+
+void S9xMessage (int type, int number, const char *message)
+***********************************************************
+
+I've started work on converting all the old printfs into calls to this
+routine. When Snes9x wants to display an error, information or warning
+message, it calls this routine. Check in messages.h for the types and
+individual message numbers that Snes9x currently passes as parameters.
+
+The idea is display the message string so the user can see it, but you
+choose not to display anything at all, or change the message based on the
+message number or message type.
+
+Eventually all debug output will also go via this function, trace information
+already does.
+
+bool8 S9xOpenSoundDevice(int mode, bool8 stereo, int buffer_size)
+*****************************************************************
+
+S9xInitSound calls this function to actually open the host operating system's
+sound device, or initialise the sound card in MS-DOS port.
+
+The mode parameter is the value passed in on the command line with the -r
+command line flag, assuming you're using the Snes9x parser. Its meant to
+indicate what playback the sound hardware should be set to, value 1 to 7.
+I think the real SNES sound chip playback rate is 30kHz, but such high
+playback rates take a lot of native CPU power to emulate. The default
+playback rate is 22kHz for the MS-DOS and UNIX ports.
+
+The stereo flag indicates if the user wants stereo sound. Again, stereo
+sound takes more CPU to power to emulate compared to mono sound.
+
+The buffer_size value indicates what sample buffer size the user wants,
+usually zero, meaning you should pick the value best suited to the current
+playback rate. Sound data is normally passed to the sound hardware in
+blocks, the smaller the block the less latency between the SNES game playing
+a sound and it being heard by the user. But if you pick a too smaller value,
+and you're having to periodically poll the operating system to see if it can
+accept more sound data, then the sound output will break up because other
+actions such as rendering the SNES screen can prevent you from polling the
+hardware often enough and the operating system runs out of sound data to
+play.
+
+The MS-DOS port uses a buffer size of 128 samples since the sound card
+sends an interrupt when more data is required which is acted upon promptly,
+where as the Linux and Solaris ports use a buffer size of 512 samples or
+more depending on the playback rate. Stereo and 16-bit sound both double the
+actual size of the buffer in bytes.
+
+uint32 S9xReadJoypad (int which1_0_to_4)
+****************************************
+
+This function is called to return a bit-wise mask of the state of one of the
+five emulated SNES controllers. Return 0 if you're not supporting controllers
+past a certain number or return the mask representing the current state of
+the controller number passed as a parameter or'ed with 0x80000000.
+
+Symbolic constants are defined in snes9x.h indicating the bit positions of
+the various SNES buttons and direction indicators; they're all in the form
+SNES_X_MASK where X is the SNES controller button name.
+
+The MS-DOS and X Window System ports record what keys are currently pressed
+and use that to build up a mask, the Windows port polls the operating system
+when S9xReadJoypad is called to find out what keys are pressed. All ports
+also implement host joysticks and joy-pads via this interface.
+
+bool8 S9xReadMousePosition (int which1_0_to_1, int &x, int &y, uint32 &buttons)
+*******************************************************************************
+
+Used by Snes9x to get the current position of the host pointing device,
+usually a mouse, used to emulated the SNES mouse. Snes9x converts the x and
+y values to delta values required by the SNES mouse, so the actual x and y
+values are unimportant, only the change in value since the last call to
+this function is used.
+
+Graphical windowing systems normally restrict the movement of the pointer on
+the screen, if you're porting to such an environment you might want to make
+a note of the change in position in the mouse since the last time you asked
+the operating system the mouse position, add this change in value to some
+saved x and y value, the reposition the pointer back to the centre of the
+SNES display window. The saved x and y values will be the values returned
+by this function.
+
+The buttons return value is a bit-wise mask of the two SNES mouse buttons,
+bit 0 for button 1 (left) and bit 1 for button 2 (right).
+
+bool8 S9xReadSuperScopePosition (int &x, int &y, uint32 &buttons)
+*****************************************************************
+
+void S9xSetPalette ()
+*********************
+
+void S9xSyncSpeed ()
+S9xUnixProcessSound
+void _makepath(char *, char const *, char const *, char const *, char const *)
+void _splitpath(char const *, char *, char *, char *, char *)
+
+
+Sound Generation
+----------------
+
+Settings
+--------