Replay+ - Development Guide
===========================
Version: 1.00
Date:    June 23, 1998
Author:  Kevin Brisley
E-Mail:  replay@icomm.ca
WWW:     http://www.icomm.ca/replay



Replay+ Developer License:
-=-=-=-=-=-=-=-=-=-=-=-=-=

Replay+ Arcade Emulator
Copyright 1997, 1998, Kevin Brisley, All rights reserved.

The following license refers to the developer distributions of Replay+.  A
separate license describing the binary distributions of Replay+ can be 
found in the replay.txt file included with the binary distributions.

- The purpose of the Replay+ developer distribution is to provide information
  about how the classic arcade games of the late 70's and beyond work.  The
  end goal is to preserve these games long after the original hardware is
  gone.  All of the source code found in the Replay+ developer distribution
  has been created by the author or is freely available to the public.  No
  portion of the original arcade game source/binary code is contained in 
  Replay+

- The source code contained in the Replay+ developer distribution may not
  be used in any commercial or non-commercial original or derivative works
  without the express written consent of the author.  The ideas and information
  contained in the code can be used but please show some consideration; give
  credit where credit is due and if possible make further information freely
  available so we can all benefit.

- The Replay+ developer distribution also furthers the goal of preserving
  arcade classics by allowing aspiring or established emulator authors to
  contribute to the development of Replay+.  However to avoid chaos, the
  remainder of the license agreement deals with guidelines for contributing
  to the Replay+ development.

- You are free to make any modifications and additions to the source code. 
  However, you are not permitted to distribute the modified Replay+ source  
  code.  Please submit any modifications or additions to the author for
  acceptance and inclusion in future Replay+ developer distributions.

- You are not permitted to distribute Replay+ executables that have been
  created with the source code from the Replay+ developer distributions.  
  Again, any modifications or additions accepted by the author will
  appear in the next official Replay+ binary distribution.

- You are allowed to distribute Game objects in the form of shared libraries
  (e.g. .DLLs in Win32).  These objects must be derived from the Replay+
  "Game" object and must not be packaged with any other components of Replay+.
  Submission of the source code for the Game object(s) is encouraged so that
  they can be included in the official Replay+ binary and developer 
  distributions (see section 8.0).

- ROM images must not be included in an archive of, on the same physical 
  medium as, or in the same package as a Replay+ developer distribution.

- Replay+ developer versions are provided "as-is" and the author is not
  responsible for damage of any kind caused by their use.
      

Happy Hacking.

-------------------------------------------------------------------------------
Contents:

1.0  Introduction

2.0  Installation
 2.1  Compile Requirements
 2.1.1  Unix/X
 2.1.2  DOS
 2.2  Makefile
 2.2.1  Customization
 2.2.2  Architecture
 2.2.3  Common
 2.2.4  Games
 2.2.5  Combine
 2.2.6  Targets
 2.2.7  Macros
 2.3  Compiling
 2.4  Dependencies

3.0  Replay+ Debugger
 3.1  Description
 3.2  Accessing
 3.3  Layout
 3.4  Information Window
 3.5  Break Points Window
 3.6  Source Window
 3.7  Registers Window
 3.8  Memory Window
 3.9  Command Entry Window
  3.9.1  Continue (C)
  3.9.2  Next (N)
  3.9.3  Memory (M)
  3.9.4  Source (S)
  3.9.5  PC Breakpoint (B)
  3.9.6  Read Breakpoint (R)
  3.9.7  Write Breakpoint (W)
  3.9.8  Disable Breakpoint (D)
  3.9.9  Enable Breakpoint (E)
  3.9.10 Delete Breakpoint (X)
  3.9.11 Assign Memory (A)
  3.9.12 Search Memory (F)
  3.9.13 Change CPU (P)
  3.9.14 Trace (T)
 3.10 Status Window

4.0  Source Files/Directories

5.0  Driver Development
 5.1  Structure
 5.2  File Names
 5.3  Creating
  5.3.1  Starting
  5.3.2  Information
  5.3.3  Ctor/Dtor
  5.3.4  StartUp
  5.3.5  ShutDown
  5.3.6  Display
  5.3.7  Lead by Example

6.0  Types

7.0  Game Class
 7.1  Ctor/Dtor
 7.2  Interface
 7.3  Utility Functions
 7.4  Default Read Handlers
 7.5  Default Write Handlers
 7.6  Default Interrupt Handlers

8.0  Code Submission

9.0  Troubleshooting

-------------------------------------------------------------------------------

1.0 Introduction:
-=-=-=-=-=-=-=-=-

This is a guide to developing new games and new features in Replay+.  Hacking,
modifying and adding to Replay+ is not only permitted, it's encouraged.  To
that end, the Replay+ development distribution was created.  The development
distribution contains the following:

    - Complete source code.
    - An integrated debugger.
    - This development guide.
    - Man pages describing the various Replay+ objects (TBD).

Note that the information described in this file changes rapidly with the
development of Replay+ and as such, this file may not accurately reflect
the code as it exists today.  The best source of information is the source
itself.


2.0 Installation:
-=-=-=-=-=-=-=-=-


2.1 Compile Requirements
------------------------

This section lists what is required to compile the developer's version
of Replay+ for each of the supported platforms.

2.1.1 Unix/X
------------

- GNU C++ compiler.
- NASM assembler (Linux only).
- X11R5.

2.1.2 DOS
---------

- DJGPP GNU C++ compiler (http://www.delorie.com).
- NASM assembler (http://www.web-sites.co.uk/nasm/).
- Allegro graphics library (http://www.talula.demon.co.uk/allegro/index.html).
- Seal audio library (http://www.egerter.com/seal/).
- The GNU 'sed' utility (ftp://ftp.cdrom.com/pub/simtelnet/gnu/djgpp/v2gnu).

An easy way to get the DJGPP & Allegro stuff (for the DOS version) is to go to
http://www.delorie.com and choose their "Zip Picker" option.  Check off "C",
"C++", "Assembler" and "Allegro" and it will provide you with a list of the
required files.  Download them and install as instructed.


When you first compile, you'll see a lot of "error" messages indicating that
dependency files don't exist.  They look like this:

  makefile:1099: depend.dos/m6502.d: No such file or directory (ENOENT)
  makefile:1099: depend.dos/6809kbc.d: No such file or directory (ENOENT)

This is expected!  The build will report that all of these are missing and
then go on and build them so this isn't really a problem.


If you get the following error when compiling the DOS version then you haven't
put the 'sed' utility in a directory in your path (I'd suggest your djgpp/bin
directory):

  Command line too long.
  make.exe: ***[depend.dos/_turtles.d] Error -1


If you get an error like the following:

  Compiling src/cpu/6502/6502mfc/6502mfc.cpp
  make.exe: ***[obj.dos/6502mfc.o] Error -1

It probably means that it can't find your g++.exe.  This should be in your
djgpp/bin directory but for some reason it might have been installed as
g__.exe or gxx.exe or something.  There are two steps to try and fix this:

1)  edit your djgpp/djgpp.env file, look for the +LFN line and set +LFN=y to
enable Win95 long file name support.
2)  if that didn't work, edit the makefile and change the 'CXX.dos=' line
from g++ to g__ or gxx or whatever.


Finally, make sure that after unzipping the SEAL archive, you place audio.h
in the djgpp/include directory and audiodjf.a in the djgpp/lib directory.


2.2 Makefile
------------

Once the Replay+ developer distribution archive has been unpacked you must
modify the "makefile" to fit the system you are compiling on.

The makefile consists of the multiple sections that will be defined below.


2.2.1 Customization
-------------------
This section contains some variable definitions that apply in general to the
compilation.  This section exists to be modified by the developer to suit 
his/her needs.

The settings are described below:

REPPLAT:  
    The line corresponding to the architecture you are building on
    should be uncommented.  If you are porting Replay+ to a new
    platform, you would need to add a choice here and a corresponding
    architecture section (described later).  It can also be convenient
    to set REPPLAT as an environment variable instead of setting it
    in the Makefile.

DISTRIBUTION:
    This should always be set to 'developer' when compiling the developer's
    version.  The only time it is set to 'release' is to compile the 
    binary distribution, which is only possible from the complete 
    Replay+ source distribution.
    If set to 'release' when compiling the developer's version, the build
    will fail because there are files (i.e. ASM CPU cores) that are not
    permitted to be distributed in source form and are therefore unavailable.
     
IDEBUGGER:   
    Set this to 'on' if you would like to make use of the integrated
    debugger.  Set to 'off' if you do not need the integrated debugger.
    The integrated debugger is invaluable while developing emulations for 
    new games.

COMPILEFOR:
    This indicates what compile options you would like to use when compiling.
    The possible options are 'optimize' for optimal performance, 'debug' for
    a compilation with debugging symbols and 'profile' to compile with
    profiling information.

ASSERTS:
    Setting this to 'on' will compile Replay+ with C++ assert() statements
    enabled.
    This is very helpful during development but can slow down a 
    production distribution.  Setting this to 'off' will compile out
    the assert() statements and the extra checking that goes with them.
    If you're using the development package you probably want this
    turned on.

DRIVER_TYPE:
    This can be set to either 'static' or 'shared'.  If set to 'static'
    the object code for the game drivers is compiled directly into
    the Replay+ executable and Replay+ will look no further for games.
    If set to 'shared', the games will be compiled as shared libraries
    (or .DLLs) and Replay+ will have the ability to have new games
    added to it without recompiling the main application (assuming your
    target platform supports shared libraries).

    Note that DOS has no support for shared libraries and should therefore
    be set to 'static'.

    
2.2.2 Architecture
------------------

Following the customization section are many architecture sections.  Each
one refers to settings specific to a particular platform.  The definitions
used are based on the setting of the REPPLAT variable.  The following
variables should be set for each architecture:

OBJ_EXT.<arch>:    Indicates the extension (including '.') for object files.
EXE_EXT.<arch>:    Indicates the extension (including '.') for executables.
SHL_EXT.<arch>:    Indicates the extension (including '.') for shared libraries.

VPATH.<arch>:      A colon(:) separated list of path names that source files
                   can be found in.

RM.<arch>:         This is the command to remove files.
RMDIR.<arch>:      This is the command to remove directories and files.
MKDIR.<arch>:      This is the command to make a directory.
ECHO.<arch>:       This is the command that echos output to the screen.
DIRCHAR.<arch>:    This is the directory separator character.

ARHIVE.<arch>:     This is the command to create an archive.
AREXT.<arch>:      Indicates the extension (including '.') for archive files.

PURIFY.<arch>:     This is the command to purify Replay+.
PFLAGS.<arch>:     These are the flags to pass to the purify program.

QUANTIFY.<arch>:   This is the command to quantify Replay+.
QFLAGS.<arch>:     These are the flags to pass to the quantify program.

CXX.<arch>:        This is the executable for your C++ compiler of choice.
CDIRS.<arch>:      The list of include directories.
CDEFS.<arch>:      Macro definitions to pass to the compiler.
CFLAGS.<p>.<arch>: Flags to pass to the compiler for each build type <p>
                   (release, debug, profile).
CSRC.<arch>:       This is a list of platform specific source files that must 
                   be compiled for this architecture.
COBJ.<arch>:       The list of object files formed from the source file list.

AS.<arch>:         This is the executable for your assembler of choice.
ADEFS.<arch>:      Macro definitions to pass to the assembler.
AFLAGS.<arch>:     Flags to pass to the assembler.
ASRC.<arch>:       This is a platform specific list of source files that must 
                   be assembled for this architecture.
AOBJ.<arch>:       The list of object files formed from the source file list.

LD.<arch>:         This is the executable for your linker of choice.
LDIRS.<arch>:      The list of library directories.
LIBS.<arch>:       A list of libraries that must be linked into the executable.

SLEFLAGS.<arch>:   Flags passed to the compiler when linking the executable
                   when DRIVER_TYPE=shared.
SLLFLAGS.<arch>:   Flags passed to the compiler when linking shared libraries
                   when DRIVER_TYPE=shared.


2.2.3 Common
------------

Following the architecture sections is a common section which lists items
that do not change between various platforms.  This includes common
directories, source files, flags, etc.

VPATH.common:      The directories to search for common source files.

CDIRS.common:      The directories to search for common header files.

CDEFS.common:      Common macro definitions for the compiler.
CFLAGS.common:     Common compiler flags.

CSRC.common:       Source files that are compiled for all platforms.
COBJ.common:       The list of common object files based on the list of
                   common source files.


2.2.4 Games
-----------

Since Replay+ allows game drivers to be built and stored separately from the
executable through the use of shared libraries, it is necessary to provide
definitions concerning how Replay+ should be built based on whether the
drivers are built as shared libraries or linked staticly to the executable.

There are three subsections in the games section.  The first lists general
items as follows:

STATIC.static:       No need to modify - used for makefile logic.
SHARED.shared:       No need to modify - used for makefile logic.

VPATH.games:         The directory where the game source files are stored.

CDIRS.games:         The directory where the game include files are stored.
CDEFS.games:         Macro definitions for compiling game drivers.
CFLAGS.games:        Flags passed to the compiler when compiling game drivers.
CSRC.concrete.games: A list of game driver source files.
CSRC.abstract.games: A list of base class game driver source files.
CSRC.games:          A full list of concrete and abstract source files that
                     make up the game drivers.
COBJ.games:          The list of object files formed from the source file list.

The second subsection lists items that are used when DRIVER_TYPE=static.  
They are as follows:

CDIRS.static:         The directory where the game source files are stored.
CDEFS.static:         Macro definitions for compiling static game drivers.
CFLAGS.static:        Flags passed to the compiler for static drivers.
CSRC.concrete.static: A list of game driver source files.
CSRC.abstract.static: A list of base class game driver source files.
CSRC.static:          A full list of concrete and abstract source files that
                      make up the game drivers. 
COBJ.static:          The list of object files formed from the source file list.
CDLL.static:          The list of shared libraries (typically blank when game
                      drivers are static).
SLEFLAGS.static:      The flags to pass to the linker when linking the 
                      executable (typically blank when game drivers are static).
SLLFLAGS.static:      The flags to pass to the linker when linking shared
                      libraries (typically blank when game drivers are static).
SLDIR.static:         The directory to store the shared libraries (typically
                      blank when game drivers are static).

The third subsection lists items that are used when DRIVER_TYPE=shared.
They are as follows:

CDIRS.shared:         The directory where the game source files are stored.
CDEFS.shared:         Macro definitions for compiling static game drivers.
CFLAGS.shared:        Flags passed to the compiler for static drivers.
CSRC.concrete.shared: A list of game driver source files.
CSRC.abstract.shared: A list of base class game driver source files.
CSRC.static:          A full list of concrete and abstract source files that
COBJ.shared:          The list of object files formed from the source file list.
CDLL.shared:          The list of shared libraries formed from the object files.
SLEFLAGS.shared:      The flags to pass to the linker when linking the 
                      executable.
SLLFLAGS.shared:      The flags to pass to the linker when linking shared
                      libraries.
SLDIR.shared:         The directory to store the shared libraries.


2.2.5 Combine
-------------

After the Games section is a Combine section.  This section combines the
options for the previous sections (Customization, Architecture, Common, Games)
into the final options that will be passed to the various compilers, 
assemblers, linkers, etc.


2.2.6 Targets/Rules
-------------------

The final section of the make file contains the various targets and the
rules to build them.  These are listed below:

all:
This is the default target and will build the Replay+ application.  
If DRIVER_TYPE=shared, it will also build the shared libraries.

purify:
This will build a purified Replay+ executable.  Like 'all', it will also
build shared libraries as necessary.  However, only the main application 
will be purified, not the shared libraries.  If you would like to purify 
the game drivers build Replay+ with DRIVER_TYPE=static.

quantify:
This will build a quantified Replay+ executable.  Like 'all', it will also
build shared libraries as necessary.  However, only the main application 
will be quantified, not the shared libraries.  If you would like to quantify
the game drivers build Replay+ with DRIVER_TYPE=static.

obj.$(REPPLAT)/__dir__:
This is the target that will build the directory to hold the object files.

lib.$(REPPLAT)/__dir__:
This is the target that will build the directory to hold the shared libraries.

replay$(EXE_EXT):
This target is responsible for linking the Replay+ application executable.  It
of course depends on any object files built from source (COBJ) or assembly
(AOBJ) being built first.

preplay$(EXE_EXT):
This target serves the same purpose as replay$(EXE_EXT) except that it 
purifies the application.

qreplay$(EXE_EXT):
This target serves the same purpose as replay$(EXE_EXT) except that it 
quantifies the application.

$(COBJ):
This target provides rules for building staticly linked object files from
C++ source files.

$(AOBJ):
This target provides rules for building statically linked object files from
assembly source files.

$(COBJ.shared):
This target provides rules for building the dynamically linked object files
from C++ game driver source files.  This will only be invoked if 
DRIVER_TYPE=shared.

llib.$(REPPLAT)/<shlib>$(SHL_EXT):
These targets provide rules for building the shared libraries from the game
driver object files.  These will only be invoked if DRIVER_TYPE=shared.

clean:
This will remove all object files, shared libraries, executables and cores.

pristine:
This will perform a clean and then remove the contents of the config
directories along with the dependencies and any saved high scores.

archive:
This will create an archive file containing the Replay+ source code tree.

depend:
This will update the source code dependencies.  This is generally not 
needed if using an up-to-date version of gnu make since the dependencies
will be generated automatically with the newer make.

depend/$(REPPLAT)/__dir__:
This is the target that will build the directory to hold the dependency files.

depend/$(REPPLAT)/%.d:
This target is used for auto-generating and auto-updating of dependency files
whenever anything changes.


2.2.7 Macros
------------

The following macros are recognized throughout the Replay+ source code:

-D<arch>:          Indicates which architecture is being compiled.
-DUNIX:            Indicates a Unix platform.
-DDOS:             Indicates a DOS platform.
-DWIN32:           Indicates a Win32 platform.
-DMAC:             Indicates a Macintosh platform.
-DDEBUG:           Compiles with assert()'s enabled. 
-DNDEBUG:          Compiles with assert()'s disabled.
-DDEBUGGER:        Compiles the integrated debugger into Replay+.
-DNODEBUGGER:      Does not compile the integrated debugger into Replay+.
-DXSHM:            Uses X MIT Shared Memory extensions.
-DBYTE_LS_FIRST:   Indicates that byte order is least significant first.
-DBIT_LS_FIRST:    Indicates that bit order is least significant first.
-DBYTE_MS_FIRST:   Indicates that byte order is most significant first.
-DBIT_MS_FIRST:    Indicates that bit order is most significant first.
-DX86_ASM:         Use i386 inline assembly.
-DARCH=<arch>:     Indicates the architecture being built on.


2.3 Compiling
-------------

Once the makefile has been set up to your liking, Replay+ can be build by
simply running "make".  Once compilation is complete, a "replay" or
"replay.exe" will have been created.


2.4 Dependencies
----------------

With the most recent versions of gnu make, the provided makefile will 
automatically generate the list of dependencies for each source file
being compiled.  The lines that are responsible for this are at the
very bottom of the makefile and appear like:

    include \
        $(CSRC:%.cpp=depend.$(REPPLAT)/%.d) \
        $(CSRC.shared:%.cpp=depend.$(REPPLAT)/%.d)

Auto-dependency generation is a nice feature, however it does slow 
compilation down (especially with a project with a large number of 
files like Replay+).  If you are sure you won't be modifying headers
that will affect a lot of files (like any of the Replay+ framework)
then these lines could be commented out to speed up the compile.

However, if these lines are compiled out you run the risk of not
recompiling files that need recompiling due to a header file change.


3.0 Replay+ Debugger
-=-=-=-=-=-=-=-=-=-=


3.1 Description
---------------

One of the advantages of developing game drivers in Replay+ is the integrated
debugger.  The Replay+ debugger provides the developer with many features 
found in a standard debugger.  The only difference is that you're debugging 
the emulated program instead of the emulator itself.  This is of tremendous
help when attempting to emulate a new game.


3.2 Accessing
-------------

The Replay+ debugger is only available in the Replay+ developer distribution
and only available when Replay+ is compiled with the -DDEBUGGER macro.

When running Replay+ with the debugger compiled in, a debugger window will
appear as soon as an emulated game begins execution.  Once in the debugger,
The developer can perform whatever debugging tasks they would like and 
continue execution of the emulated game when finished.  

To debugger can be re-entered by pressing the F8 key during execution of
the emulated game.


3.3  Layout
-----------

When the debugger is entered, the screen appears like this:

    +----------------------------------------------------------+
    |+--------Information--------------++------Registers------+|
    ||                                 ||                     ||
    ||                                 ||                     ||
    ||                                 ||                     ||
    |+---------------------------------+|                     ||
    |+----------Break Points-----------+|                     ||
    ||                                 ||                     ||
    ||                                 ||                     ||
    ||                                 ||                     ||
    ||                                 ||                     ||
    ||                                 ||                     ||
    ||                                 ||                     ||
    |+---------------------------------++---------------------+|
    |+----------Source----------------------------------------+|
    ||                                                        ||
    ||                                                        ||
    ||                                                        ||
    ||                                                        ||
    ||                                                        ||
    ||                                                        ||
    |+--------------------------------------------------------+|
    |+-------------------------Memory-------------------------+|
    ||                                                        ||
    ||                                                        ||
    ||                                                        ||
    |+--------------------------------------------------------+|
    |+----------------------Command Entry---------------------+|
    || -><                                                    ||
    |+--------------------------------------------------------+|
    |+--------------------------Status------------------------+|
    ||                                                        ||
    |+--------------------------------------------------------+|
    +----------------------------------------------------------+
    
As you can see, there are 7 different windows available in the debugger.  
The currently active window will be highlighted in red, all other windows
will appear in white.  

The current window can be changed by using the <TAB> key.

And of course, any input to the debugger will be sent to the currently
active window.


3.4 Information Window
----------------------

The information window contains certain facts about the CPU currently being
debugged.  The following is displayed:

  CPU Type:     This is the type of the CPU being debugged.  For example, 6502,
                Z80, etc.
  CPU Class:    This is the name of the C++ class for the CPU.  Since there can
                be more than one CPU core for each CPU Type, this indicates 
                which one is currently being used.
  CPU Instance: This is the name of the instance of the C++ CPU object.  For
                example, a game may have two CPU's, the first one named "Game"
                and the second named "Sound".

There are no controls available for this window when it is current since the
information can be completely displayed in the window without any scrolling.


3.5 Break Points Window
-----------------------

This window lists the break points that have been defined for the current
CPU.  Each entry in the list is of the following form:

    <id>-<type> $<start>-$<end> (<status>)

Where:
    <id>     is the identifier of the breakpoint.  This is an integer between
             0 and 999.
    <type>   is 'P' for program counter (i.e. breaks when the program counter
             is in the range), 'R' for read (i.e. breaks when a memory
             location within the range is read from, or 'W' for write (i.e.
             breaks when a memory location within the range is written to).
    <start>  is the start of the range that the breakpoint is valid for.
    <end>    is the end of the range that the breakpoint is valid for.
    <status> is either 'E' if the breakpoint is enabled or 'D' if the 
             breakpoint is disabled.

While in the breakpoint window, the cursor up/down and page up/down keys can
be used to scroll.
 

3.6 Source Window
-----------------

This window lists the disassembled source code for the CPU.  When the debugger
is first entered, this window displays the source code surrounding the
current value of the PC (program counter).

Each line in the source window will appear in the following form:

    <bp><pc>$<addr> <bytes> <src>

where:
    <bp>     is either 'E' indicating that an enabled breakpoint is set on this
             instruction, 'D' indicating that a disabled breakpoint is set on 
             this instruction, or ' ' indicating that no breakpoint is set on 
             this instruction.
    <pc>     is either "->" indicating that the program counter of the CPU is
             currently set to this instruction (i.e. This is the next 
             instruction to be executed), or "  " indicating that the program 
             counter is not set to this instruction.
    <addr>   is the address of the instruction.
    <bytes>  contains the bytes in hex of the instruction opcode and
             arguments.
    <src>    is the disassembled source instruction.

So for a example, a few lines may look like:

     D  $00FF14  4C 03 C0  JMP $C003
      ->$00FF17  78        SEI
     E  $00FF18  D8        CLD

which indicates that there is a disabled breakpoint at $00FF14 (a 6502 jump 
instruction), the CPU is currently at $00FF17, and there is a disabled
breakpoint at $00FF18.

While in the source window, the cursor up/down and page up/down keys can be
used to scroll.  Note that the up/down, pgup/pgdn may not move in equal 
increments since display is based on an estimate of the number of bytes
per machine instruction.  However, the desired line should always appear
on the screen and paging should not page more than a screenful of information.

            
3.7 Registers Window
--------------------

This window lists the values of the current CPU's internal registers. 

The registers of all currently emulated CPUs fit within the window so there
is currently no input needed to this window.


3.8 Memory Window
-----------------

This window lists a section of memory from the currently emulated CPU.  Each
line will appear in the following form:

    <addr>: <bytes> <chars>

where:
    <addr>   is the starting address of the bytes displayed on this line.
    <bytes>  contains 16 hexidecimal values indicating the values found
             in the 16 memory locations starting at <addr>.
    <chars>  is the 16 bytes displayed as characters.

Each line will always contain an address that starts on a 16 byte boundary.

Also note that the bytes are displayed as they would be seen by the CPU.  What
this means is that they do not come directly from the memory space, but rather
they are read through the CPU's read handler list.  This is done so that 
items like memory mapped I/O will be seen correctly.  So if the joystick is
mapped to location 0x4000, then the byte seen at 0x4000 will be the value 
from the joystick input, not a byte in the memory space array.

The lines appearing in the Memory window can be scrolled using cursor up/down
and page up/down.


3.9 Command Entry Window
------------------------

This window is the heart of the debugger.  Commands to the debugger can be
entered in this window.  Commands consist of a one(1) letter instruction
with optional arguments.  The various commands are listed in the following
subsections.

3.9.1 Continue (C)
------------------

Usage:       C
Description: This command is used to continue execution of the emulated game
             until the user interrupts to the debugger or until a breakpoint
             is hit.


3.9.2 Next (N)
---------------

Usage:       N
Description: This command is used to step to the next machine instruction in
             this CPU while remaining in the debugger.  The command will 
             follow all jumps and branches.


3.9.3 Memory (M)
-----------------

Usage:       M [<addr>]
Description: This command will display memory in the memory window starting
             at the first address less than or equal to <addr> that is a
             multiple of 16.  If <addr> is not specified, memory at the
             current PC is shown.  <addr> is taken as a hex value.


3.9.4 Source (S)
-----------------

Usage:       S [<addr>]
Description: This command will display disassembled source code in the 
             source window surrounding the address <addr>.  If <addr> is not
             specified, source at the current PC is shown.  <addr> is taken
             as a hex value.


3.9.5 PC Breakpoint (B)
-----------------------

Usage:       B <addr1> [<addr2>]
Description: This command will set a breakpoint for the specified range of
             <addr1> to <addr2>.  If <addr2> is not specified then the range
             will be a single memory location (<addr1>).  A breakpoint will
             interrupt execution of the game and drop to the debugger when
             the PC falls in the specified range.  <addr1> and <addr2> are
             taken as hex values.


3.9.6 Read Breakpoint (R)
-------------------------

Usage:       R <addr1> [<addr2>]
Description: This command will set a read breakpoint for the specified range
             of <addr1> to <addr2>.  If <addr2> is not specified then the
             range will be a single memory location (<addr1>).  A read 
             breakpoint will interrupt execution of the game and drop to the
             debugger when a CPU instruction reads from a memory location that
             falls into the specified range.   <addr1> and <addr2> are
             taken as hex values.


3.9.7 Write Breakpoint (W)
--------------------------

Usage:       W <addr1> [<addr2>]
Description: This command will set a write breakpoint for the specified range
             of <addr1> to <addr2>.  If <addr2> is not specified then the
             range will be a single memory location (<addr1>).  A write 
             breakpoint will interrupt execution of the game and drop to the
             debugger when a CPU instruction writes to a memory location that
             falls into the specified range.   <addr1> and <addr2> are
             taken as hex values.


3.9.8 Disable Breakpoint (D)
----------------------------

Usage:       D [<bpid>]
Description: This command will disable the breakpoint associated with the
             breakpoint id specified in <bpid>.  If <bpid> is not specified
             then all breakpoints will be disabled.  A disabled breakpoint
             will not cause game execution to be interrupted when hit.  
             <bpid> is a taken as a decimal value.

            
3.9.9  Enable Breakpoint (E)
----------------------------

Usage:       E [<bpid>]
Description: This command will enable the breakpoint associated with the
             breakpoint id specified in <bpid>.  If <bpid> is not specified
             then all breakpoints will be enabled.  An enabled breakpoint
             will cause game execution to be interrupted when hit.
             <bpid> is a taken as a decimal value.


3.9.10 Delete Breakpoint (X)
----------------------------

Usage:       X [<bpid>]
Description: This command will delete the breakpoint associated with the
             breakpoint id specified in <bpid>.  If <bpid> is not specified
             then all breakpoints will be deleted.  Deleted breakpoints are
             gone and cannot be subsequently enabled/disabled.
             <bpid> is a taken as a decimal value.


3.9.11 Assign Memory (A)
------------------------

Usage:       A <addr> <value>
Description: This command will set the byte in the address specified by
             <addr> to the value in <value>.  The CPU's write handlers are
             used to set the value so assigning memory may not have the
             desired effect.  For example, if location 0x4000 invokes a 
             handler that does nothing, then assigning a value to 0x4000 will
             not show a visible change in the memory window for 0x4000.
             <addr> and <value> are taken as hex values.


3.9.12 Search Memory (F)
------------------------

Usage:       F [<value1> [<value2> [<value3> [...]]]]
Description: This command will search memory for the sequence of bytes 
             specified in <value1>, <value2>, etc.  If the sequence is
             found, the address where the sequence begins is reported to
             the developer.  If no values are specified, then the previous
             sequence will be search for again, starting from the location
             where the sequence was last found.  <value1>, <value2>, etc.
             are taken as hex values.


3.9.13 Change CPU (P)
---------------------

Usage:       P [<cpuid>]
Description: This command will change the CPU being examined by the debugger
             to that specified in <cpuid>.  If no <cpuid> is specified, the
             debugger will change to the CPU that is currently executing.
             <cpuid> is taken as a decimal value.  Not that it really matters
             since it doesn't become a problem until you hit CPU 10 and if
             you're emulating 10 CPUs you've got bigger problems.


3.9.14 Trace (T)
----------------

Usage:       T [<type> <addr1> [<addr2>]]
Description: This command will turn tracing on for the current CPU.  Tracing
             dumps information to a "trace.cpu" file in the Replay+ directory.
             One of three types of tracing can be specified.  If <type> is 
             'P' then instruction tracing will be invoked and each instruction 
             as it is executed will be dumped.  If <type> is 'R' then read
             tracing will be invoked and each memory location that is read
             from will be dumped.  If <type> is 'W' then write tracing will
             be invoked and each memory location that is written to will
             be dumped.  If no <type> is specified then tracing will be turned
             off.

             <addr1> and <addr2> define a memory range for which tracing should
             be active.  Only instructions, read, writes that fall in this
             range will be dumped.  If <addr2> is not specified, it will 
             default to <addr1>.

             Note that only one type of tracing is allowed at a time and
             tracing is only allowed on one CPU at a time.

             <addr1> and <addr2> are taken as hex values.


3.10 Status Window
------------------

The status window is a small one line window that displays information on
the success/failure of the command just executed in the debugger.

No controls are applicable in this window.


4.0 Source Files/Directories
-=-=-=-=-=-=-=-=-=-=-=-=-=-=

Replay+ is developed in C++ and as such, there are numerous C++ classes 
derived for the application.  I like to follow the one-file equals one-class
rule, and therefore, you will find that there will be one and only one class
per C++ source file.  The file will be named appropriately but I wanted to
keep 8.3 style file names so the file will not necessarily be given the
exact name of the class it contains.

Each class will have a header file (.h) and a source file (.cpp).

Below is a listing of some of the directories and what they contain:

control:  Various classes for controllers such as keyboard, joystick, mouse,
          etc.
cpu:      All of the classes that contain CPU emulation cores can be found
          under this directory.
debugger: The classes involved in creating the Replay+ integrated debugger
          are found here.
file:     Various file I/O classes can be found here.  They deal with regular
          files, zip files, ROMLIB, etc.
game:     The main Game class and supporting classes are found here.
games:    Game drivers (derived from the Game class) are located here.
meddler:  Classes that are used to modify inputs (i.e. for recording/playback
          of movies, network play, etc.) are found here.
replay:   The classes involved in the core of the Replay+ emulator are 
          contained in this directory.
select:   The main menu and game selection screen classes can be found here.
sound:    The sound code can be found here.
support:  Miscellaneous classes that perform support functionality are 
          stored in this directory.

There are also a variety of architecture directories that contain classes
that are needed in a port of Replay+ to a particular platform.  For example,
there is a linux directory, a dos directory, etc.


5.0 Driver Development
-=-=-=-=-=-=-=-=-=-=-=

5.1 Structure
-------------

The focus of the remainder of this document will be on game driver 
development.  A game driver is the piece of code that makes use of the
components of the Replay+ emulation framework in such a way as to create
a working, playable emulation of the game.

Due to the Object Oriented nature of Replay+, a game driver is essentially
a C++ object derived from the Replay+ Game class.  The Game class provides
an interface between a Game and the rest of the Replay+ framework.  It also,
provides protected utility functions for use by derived classes.  The Game
class will be described fully in a later section.

The developer may also want to take advantage of the Object Oriented nature
of Replay+ when making new Game classes.  For example, since PacMan, 
Ms. PacMan and Crush Roller all run on almost identical hardware, a developer
may create the following hierarchy:

                        +----------------+
                        |     Game       |
                        +----------------+
                                |
                                |
                        +----------------+
                        |    GamePacs    |
                       /+----------------+\
                      /         |          \
    +----------------+  +----------------+  +----------------+
    |   GamePacMan   |  |  GameMsPacMan  |  | GameCrushRoller|
    +----------------+  +----------------+  +----------------+
                
Therefore common functionality can be written into the GamePacs class and
shared by the various derived PacMan games.

Developer's looking to add a game to Replay+ will usually only need to derive
a new class(es) from the Game class.  In rare cases, it may be necessary to 
modify or expand on the Replay+ framework if needed functionality for the
new game is not provided.  A new game class can be packaged into a .DLL or
shared library and distributed as a stand-alone driver that can be shared
with other Replay+ users.


5.2 File Names
--------------

For ease of identification, all abstract game driver classes should have file
names beginning with an underscore.  Therefore, in the above example, the
GamePacs class may be contained in a pair of files called _pac.h, _pac.cpp
and the derived, concrete classes may be contained in files called pacman.h,
pacman.cpp, mspacman.h, mspacman.cpp, crush.h, crush.cpp.


5.3 Creating
------------

5.3.1 Starting
--------------

When attempting to create a driver for a new game, it's generally best to
copy an existing driver file and work from there.  

Unless you know that the new game is a very close derivative of an existing
game, it's probably best to derive your new game class directly from 
the Replay+ game class.


5.3.2 Information
-----------------

Each concrete game driver class must contain an informational section that
is placed just before the constructor.  Macros defined in game.h are used
to specify various information about the game driver.  This information is
essential for the operation of the emulated game.

The information section starts with the 'GAME_INFO' macro and ends with
the 'FOR( <gameid>, <gameclass> )' macro.  Between these two macros 
the following information is specified:

    ASSIGN_GAME_ID:  
        The game identifier.  Each game has a unique identifier that is used 
        in many places including starting a game directly from the command 
        line.  The identifier must be no more than 8 characters.
    ASSIGN_GAME_NAME: 
        The name of the game.  This is used for display purposes when 
        the game is selected.
    ASSIGN_GAME_VERSION:
        The version of the game driver in major, minor form.  This also 
        includes the major and minor version number of the Replay+ application
        itself.  Currently this information is not used but is intended for
        the future to determine when save games, high scores, the driver 
        itself, etc. are incompatible with the version of Replay+ being run.
    ASSIGN_GAME_CONTRIBUTORS:
        This is a list of people that have contributed to bringing the
        game to life.
    ASSIGN_GAME_REQD_FILES:
        This is a list of the external files (i.e. ROMS, samples, etc.) that
        are required for the game to run.

So if I had a game called Super Snack Man I may add the following information
to the ssman.cpp file:

    GAME_INFO
        ASSIGN_GAME_ID,
            "ssman",
        ASSIGN_GAME_NAME,
            "Super Snack Man",
        ASSIGN_GAME_VERSION,
            REPLAY_MAJOR_REVISION, REPLAY_MINOR_REVISION, 1, 0,
        ASSIGN_GAME_CONTRIBUTORS,
            "Harry Carry",
            "Mary Perry",
        ASSIGN_GAME_REQD_FILES,
            "ROM0.bin",
            "ROM1.bin",
    FOR( ssman, GameSuperSnackMan )


5.3.3 Ctor/Dtor
---------------

Each game driver is a C++ class and as such should have a constructor(ctor)
and a destructor(dtor).  

Generally, nothing is done in the constructor aside from initializing member 
data.  Likewise, nothing is really done in the destructor.  Most of the setup 
and teardown work is done in startUpXXX( ) and shutDown( ) functions.  The
reason for this is that it is desirable to be able to create an instance
of the object while controlling when the bulk of the object's data is created.

Thus, we can create a "lightweight" object by simply instantiating it and
then instruct the object (through the startUpXXX( ) functions) to create 
itself as needed.


5.3.4 StartUp
-------------

The meat of the game driver is contained in the startUpXXX( ) member functions
of the game objects.  There are numerous startup member functions that can
be overridden in derived game driver classes to perform the creation of
the CPUs, the decoding of the graphics, the setup of the memory map etc.

They will be called in the following order:

    startUpStart( );
    startUpSpace( );
    startUpROMs( );
    startUpCPU( );
    startUpInput( );
    startUpGraphics( );
    startUpColour( );
    startUpSound( );
    startUpMemMap( );
    startUpOther( );
    startUpEnd( );

When creating a new driver it is generally a good idea to override each
applicable startup function.  Each startup function has a default behaviour
which is generally to do nothing.

The ones that usually need to be overridden immediately when creating
a new driver are: startUpSpace( ), startUpROMs( ), startUpCPU( ), 
and startUpMemMap( ).  This should be enough to get the code executing
in the integrated debugger.  After you have this going and start figuring
out where the dip switches are mapped, how the colour is controlled, etc.,
you can begin filling in the remainder of the startup functions.

For details on the purpose of the startup functions, see the sections on the
game class below.


5.3.5 ShutDown
--------------

There is a single shutdown function that can be overridden by a derived
game class.  Fortunately, this usually does not need to be overridden. 

By default, the shutDown member function will clear all of the lists
contained in the game class and delete the objects contained in them.

Thus, you only need to override this function if you are allocating objects
in the startUpXXX( ) functions that can't or aren't being added to the
Game class lists.

If you do override this function, be sure to call the base class member
function and also be sure to free any stand-alone objects created in the
startUpXXX( ) functions.


5.3.6 Display
-------------

The next important item in creating a game driver is to override the
updateDisplay( ) member function of the game class.  This member is
called once per frame and is responsible for rendering the current
game scene.  

The default behaviour for this function is to do nothing since the method
for rendering a scene varies drastically from game to game.

Therefore, you will find that this member function is redefined for every
game driver available in Replay+.


5.3.7 Lead by Example
---------------------

OK, I always find reading definitions of functions and members kind of mind
numbing.  An example always seems to make things a bit clearer.  The best
examples you will find will be existing drivers already distributed with
Replay+.  

I would suggest taking an existing driver and going over it line-by-line
until you understand exactly how it works.  You can refer to this document
to determine how the various objects work and interact.  You can also
check the source code for the various objects to understand what their
purpose is.


6.0 Types
-=-=-=-=-

The following types are defined in reptypes.h and are used extensively 
throughout Replay+:

typedef signed char    int8;
typedef signed short   int16;
typedef signed long    int32;
typedef unsigned char  uint8;
typedef unsigned short uint16;
typedef unsigned long  uint32;

typedef uint8          Byte;
typedef uint16         Word;
typedef uint32         DWord;

The Byte, Word and DWord types are used whenever possible since they are
the most common types found in CPU primitives and since we're emulating
this stuff we may as well use them. 

Only when an signed value is required are the intXX types used.


7.0 Game Class
-=-=-=-=-=-=-=

The Game class can be found in the "game.h" and "game.cpp" files under the
"game" directory.

The Game class is an abstract base class for all games that are emulated by
Replay+.  It provides a standard interface for Replay+ to communicate with
an emulated game and it also provides a group of utility functions that can
be used by derived classes.

Various other classes will be mentioned while discussing the Game class,
however they will not be explained fully in this section.  See following
sections for details.


7.1 Ctor/Dtor
-------------

The Game constructor and destructor are defined as:

             Game ( const KString& iName );
    virtual ~Game ( );

The only parameter to the constructor is an instance name.  

See section 5.3.3. for information about the constructor and destructors.


7.2 Interface
-------------

This section describes the virtual interface that the Game object exports.
These members may need to be overridden in derived classes to provide the
behaviour appropriate to the specific emulated game.


virtual Byte startUp( );
------------------------
startUp( ) is called by Replay+ when the game is about to be run.  The 
purpose of the startUp( ) member is to perform all initialization, object
creation, space allocation, etc. that will be required by the game emulation.

The function returns TRUE if there is more startUp( ) required and FALSE if
it has completed the startUp( ).  If TRUE is returned, it is requesting the
caller to call the startUp( ) function again.  The reason for this is that
startUp( ) can be time consuming and to allow various processing to continue
in the Replay+ application, the function can perform smaller chunks of 
initialization, returning between each one with an indication that there is
still more work to do.

This allows the startUp( ) function to be friendly and not hog the CPU for
a lengthy time while it's initializing.

The startUp( ) function actually is responsible for calling a variety of
specific startUpXXX( ) functions to perform certain tasks during the 
initialization of the virtual machine.  

Generally, it is these startUpXXX( ) functions that are overridden in 
derived classes, it is rare that the startUp( ) function itself is overridden.

The specific startup functions are listed here:

    startUpStart( ):  
        Pre-startup startup :-)  This is generally not overridden, but can
        be if there is something that just must be done up front.  If it is
        overridden it must call the base class before completing its actions.
    startUpSpace( ):
        Creation of address space objects.  Each CPU operates within a memory
        or address space.  This function should be overridden to create 
        address spaces for the CPUs found in the game.
    startUpROMs( ):
        Load ROMs into address spaces.  The program code for the emulated game
        is executed from a CPU's address space.  This member function should
        be overridden to read the game ROMs into the appropriate address 
        spaces.
    startUpCPU( ):
        Create the required CPUs.  The game isn't going to do a heckuvalot
        if it doesn't have any CPUs.  This member can be overridden to 
        create the required CPUs for the game being emulated.
    startUpInput( ):
        Create the required inputs.  Games usually have a few inputs that
        allow the game to be controlled from externally.  This includes 
        joysticks, buttons, dip switches and etc.  All of these should
        be set up in an overridden startUpInput( ) member function.
    startUpGraphics( ):
        Decode the game graphics.  This member function should be overridden
        to perform the decoding of the graphics from the game ROMs into 
        something usable by Replay+.
    startUpColour( ):
        Setup the colour for the game.  The source and use of colour varies
        from game to game and this function can be overridden to ensure that
        we initialize any colour the game may use during game startup.
    startUpSound( ):
        Initialize the game sound.  This member function should be overridden
        to start the sound processing of the game.  There are various objects
        in the Replay+ representing various forms of sound chips and controls
        and these should be created here.
    startUpMemMap( ):
        Identify the important memory locations.  This function will almost
        certainly be overridden.  Its responsibility is to identify the
        important locations in memory (i.e. those that have some effect on
        the game) and indicate what functions should be called to handle
        read/writes to these locations.
    startUpOther( ):
        Anything missed?  This member function can be overriden to provide
        final initialization of anything that doesn't fall into the previous
        categories.
    startUpEnd( ):
        Post-startup startup :-)  This is generally not overridden, but can
        be if there is something that just must be done after everyting else.  
        If it is overridden it must call the base class before completing its 
        actions.


virtual void shutDown( );
-------------------------
The opposite of startUp( ), shutDown( ) is called when Replay+ is finished
with the game and would like the game to free any resources that it allocated
during the startUp( ).

The shutDown( ) function in the Game class will perform a lot of cleanup 
on behalf of derived classes and therefore should always be called as the
last step of a derived classes shutDown( )function.


virtual void reset( );
----------------------
The reset( ) member is responsible for resetting the game.  

Replay+ calls this member whenever the game needs to be reset either because
of user input or some internal event.

The reset( ) function in the Game class saves high scores, resets the CPUs,
clears the screen bitmap, etc.  It would only need to be overridden in a
derived class if there are game specific items that must be reset when the
game is reset.  A derived class that overrides this member should always call
the base version.


virtual void run( );
--------------------
The run( ) member is used to execute the next frame of the emulated game.
It is called repeatedly by Replay+ when the user is actually playing a game.

The run( ) function in the Game class is relatively simple and just calls
helper functions to update the CPUs, the Display and the Sound of the game
for the current frame.  This function will rarely ever be overridden in
a derived class.


virtual void updateCPUs( );
---------------------------
The updateCPUs( ) member is used to update the CPUs in the game for the
next frame of execution.  It is called by the run( ) method.

The updateCPUs( ) function in the Game class takes care of calling each
CPU in the list of CPUs for the game and instructing them to update themselves.
This function will rarely ever be overridden in a derived class.


virtual void updateDisplay( );
------------------------------
The updateDisplay( ) member is used to update the screen bitmap of the game
for the next frame of execution.  It is called by the run( ) method.

The updateDisplay( ) function in the Game class does absolutely nothing.
This should always be overridden in a derived class to provide a method to
draw what is to be displayed on the screen.


virtual void updateSound( );
----------------------------
The updateSound( ) member is used to update the sound for the next frame of
execution.  It is called by the run( ) method.

The updateSound( ) function in the Game class does not implement any default
behaviour.  This should always be overridden in a derived class to provide
the functionality for keeping sound flowing in the game.


virtual void hiScorePostLoad( );
--------------------------------
The hiScorePostLoad( ) function is available for performing any actions
required after the high scores have been loaded.  This function is called
from the HiScore object immediately following the load of high scores.

The hiScorePostLoad( ) function in the Game class does not implement any
default behaviour.  This should be overridden in a derived class only if
special processing needs to be done once the high scores have been loaded.
For example, a game may store the high scores in location 0x1000-0x1010 but
always starts by displaying 00000 on the screen for the high score until
the player actual obtains a high score.  Therefore, this function could
be overridden to write the score from 0x1000-0x1010 to the screen directly.


virtual void hiScorePreSave( );
-------------------------------
The hiScorePreSave( ) function is available for performing any actions
required before the high scores are saved.  This function is called
from the HiScore object immediately before the saving of high scores.

The hiScorePostSave( ) function in the Game class does not implement any
default behaviour.  This should be overridden in a derived class only if
special processing needs to be done before the high scores are saved.
For example, perhaps, a game only stores the high score in video RAM and
needs to be transferred to regular RAM before saving or some such.


7.3 Utility Functions
---------------------

The Game class provides a variety of utility functions that can be called
by derived classes for various common actions.  These functions are to
be used only by derived classes and are therefore protected.  The remainder
of this section describes the various utility functions.


void setMaxPlayers( const DWord dwMaxPlayers );
-----------------------------------------------
The function should be called to set the maximum number of players in the
game.  The number of players means either alternating players (like in PacMan) 
or simultaneous players (like in Joust).

If not called, the two(2) players are assumed.

This value is used during network play to determine which clients are players
and which clients are simply observers.


void setScreenSize    ( const DWord dwWidth, const DWord dwHeight );
void suggestScreenSize( const DWord dwWidth, const DWord dwHeight );
--------------------------------------------------------------------
These two functions are used to set the screen size of the game in pixels.
The only difference is that setScreenSize( ) indicates a size that is not
allowed to be overridden and suggestScreenSize( ) indicates a size that is
to be used if no user supplied size is given.

For example, Burgertime is a raster game that must be run with a 256x256
screen size, whereas Battlezone is a vector game that allows various screen
sizes and just scales the vectors to fit.


CPU* createCPU(
    const KString&        iName,
    const CPU::CPUType    eCPUType,
    AddrSpace*            pSpace,
    const CPU::CPUPurpose ePurpose = CPU::GAME
);
-----------------------------------------------
CPUs used by the game must be created through this convenience function rather
than instantiated directly.  The reason is that various architectures use
different CPU cores for the same processor (e.g. ASM cores in DOS, 'C' cores 
on Sun).  As well, this function will also perform some initialization on
the CPU.

eCPUType specifies the type of CPU (e.g. 6502, Z80, etc.), pSpace is a pointer
to the address space object associated with the CPU and ePurpose is used to 
indicate whether the CPU is used for Game processing or Sound processing.  This
final parameter allows the sound CPUs to be disabled when sound is turned
off in the emulator, thus speeding up the emulation.


Bitmap* createBitmap     (
    const KString& iName,
    const DWord    dwWidth,
    const DWord    dwHeight,
    const Byte     bForScreen = FALSE
);
-------------------------------------
Bitmaps used by the game must be created through this convenience function
rather than instantiated directly.  The reason is that the Bitmap class
is implemented differently on different architectures and this function will
instantiate the correct class.


const DWord settingsGetValue( xxx );
void        settingsSetValue( xxx );
------------------------------------
This group of functions are convenient functions that can be used to set and
get settings from the Replay+ configuration registry.  Any items that the
game driver would like to persist between runnings of the emulator can be
stored in and later retrieved from the configuration registry.

The functions are overloaded to allow setting/getting of Byte streams, 
integers and strings.


7.4 Default Read Handlers
-------------------------

The Game class also provides some commonly used handler functions for CPU
reads.  CPU Read Handlers are static member functions since the CPU cores
used all use 'C' style callbacks and we do not want to hinder performance
by implementing a 'C' callback to C++ command layer.  

All read handlers take two parameters:

    DWord        dwAddress - The address being read from.
    ReadHandler* pHandler  - A pointer to the handler object.

All read handlers return the value from the specified address (as a DWord).
   

static DWord s_readNo( xxx );
-----------------------------
This handler simply returns 0x00.


static DWord s_readRAM( xxx );
------------------------------
This handler is used to simply return the byte from the appropriate
memory location in the address space.


static DWord s_readSharedRAM( xxx );
------------------------------------
This handler is used to return the byte from the appropriate
memory location in shared address space.


static DWord s_readBuffer( xxx );
---------------------------------
This handler is used to return a value from the specified buffer corresponding
to the address passed in.


static DWord s_readROM( xxx );
------------------------------
Essentially, this is the same as the s_readRAM( ) handler.  It simply
returns the byte from the appropriate memory location in the addres space.


static DWord s_readInput( xxx );
--------------------------------
This handler is used to return the value of an input (e.g. joystick, buttons,
etc.).


static DWord s_readInputs( xxx );
---------------------------------
This handler is an alternate to s_readInput( ) when you have a series of
inputs that are all mapped to consecutive memory locations.  Instead of,
say 5 handlers, a single handler will do.


static DWord s_readCommand( xxx );
----------------------------------
This handler is used to read the next value from a command queue.  These
command queues are generally used as a communication buffer between CPUs.


static DWord s_read8910( xxx );
-------------------------------
This handler is used to read a value from an AY8910 PSG.


static DWord s_readWatchDog( xxx );
-----------------------------------
This handler is used as a "check" read.  If the game does not read from
this location for a certain elapsed time, then the machine resets itself.


7.5 Default Write Handlers
--------------------------

The Game class also provides some commonly used handler functions for CPU
writes.  CPU Write Handlers are static member functions since the CPU cores
used all use 'C' style callbacks and we do not want to hinder performance
by implementing a 'C' callback to C++ command layer.  

All write handlers take three parameters:

    DWord        dwAddress - The address being written to.
    Byte         bValue    - The value to write.
    ReadHandler* pHandler  - A pointer to the handler object.

All write handlers do not return a value.
   

static void s_writeNo( xxx );
-----------------------------
This handler suppresses the write.  That is, no change to memory will occur.


static void s_writeRAM( xxx );
------------------------------
This handler places the specified value into the address space at the 
memory location specified.


static void s_writeSharedRAM( xxx );
------------------------------------
This handler is used to set the byte of the appropriate
memory location in shared address space.


static void s_writeBuffer( xxx );
---------------------------------
This handler is used to set a value in the specified buffer corresponding
to the address passed in.


static void s_writeROM( xxx );
------------------------------
This handler will suppress the write to ROM unless Replay+ is compiled with
-DROM_WRITE_ERROR, in which case a fatal error will be generated when 
a write to ROM occurs.


static void s_writeDirtyByte( xxx );
------------------------------------
Many games use "dirty" buffers to indicate when areas on the display have
and have not changed.  Typically, when a value is written to video memory,
a flag is set in the "dirty" buffer to indicate that the corresponding
character on screen needs to be redrawn.

This handler will handle setting both the value in memory and the flag in
the dirty buffer when a single byte is used to represent the character.


static void s_writeDirtyWord( xxx );
------------------------------------
Same as s_writeDirtyByte( ), however every two bytes identify a single
character (e.g. character number followed immediately by colour index
of that character).


static void s_writeHiScore( xxx );
----------------------------------
This handler can be used for memory locations that trigger the loading of
high scores.  Each time the handler is called, it checks to see if the
high score loading criteria is met and if so, the high scores will be loaded.


static void s_writeScreenRotate( xxx );
-------------------------------------
This handler is used for handling writes to a location that causes the 
screen to rotate 180 degrees.  This is usually needed in those games that 
were optionally produced in a cocktail style cabinet where the screen 
would flip for a second player.


static void s_writeScreenFlipX( xxx );
-------------------------------------
This handler is used for handling writes to a location that causes the 
screen to flip in the X direction.


static void s_writeScreenFlipY( xxx );
-------------------------------------
This handler is used for handling writes to a location that causes the 
screen to flip in the Y direction.


static void s_writeCommand( xxx );
----------------------------------
This handler is called when the game writes to a command queue.  These 
command queues are generall used for communication between two or more
CPUs.


static void s_writeCPUEnable( xxx );
------------------------------------
This handler is called when a CPU is enabled/disabled based on writing
to a specific memory location.


static void s_writeIntEnable( xxx );
------------------------------------
This handler is called when CPU interrupts are enabled/disabled based on 
writing to a specific memory location.


static void s_write8910Write( xxx );
static void s_write8910Control( xxx );
--------------------------------------
These handlers are called by a game that uses an 8910 for producing sound.


static void s_writeWatchDog( xxx );
-----------------------------------
This handler is used as a "check" write.  If the game does not write from
this location for a certain elapsed time, then the machine resets itself.



7.6 Default Interrupt Handlers
------------------------------

The Game class also provides some commonly used handler functions for CPU
interrupts.  CPU Interrupt Handlers are static member functions since the CPU 
cores used all use 'C' style callbacks and we do not want to hinder performance
by implementing a 'C' callback to C++ command layer.  

All interrupt handlers take two parameters:

    CPU*         pCPu      - The CPU being interrupted.
    Game*        pGame     - A pointer to the Game object.

All interrupt handlers return a long integer indicating the interrupt value
for the current frame.
   

static int32 s_irqInterrupt( xxx );
-----------------------------------
This handler simply checks whether interrupts are enabled and returns INT_IRQ
if enabled and INT_NONE otherwise.


static int32 s_nmiInterrupt( xxx );
-----------------------------------
This handler simply checks whether interrupts are enabled and returns INT_NMI
if enabled and INT_NONE otherwise.


static int32 s_noInterrupt( xxx );
----------------------------------
This handler always returns INT_NONE.


static int32 s_vblankInterrupt( xxx );
--------------------------------------
This handler updates the vblank object and then is processed just like
s_irqInterrupt( ) for the remainder.


static int32 s_vectorInterrupt( xxx );
--------------------------------------
This handler is used for games that need to return variable interrupt
vectors to the CPU.


8.0 Code Submission
-=-=-=-=-=-=-=-=-=-

Please submit any modified or new source files that you would like to see
included in the official Replay+ distributions to me (Kevin Brisley).  You
can e-mail the submissions to replay@icomm.ca or kevin@isgtec.com. 

I intend to keep the Replay+ framework consistent and clean in coding style 
and therefore reserve the right to accept, reject or modify submissions
to fit into the spirit and style of the Replay+ code base.  However, you
will be fully credited for any and all code that is accepted into the
Replay+ distributions.


9.0 Troubleshooting
-=-=-=-=-=-=-=-=-=-

This section attempts to answer some of the common problems associated with
developing game drivers.  It is provided in FAQ format.


Q:  My 68000 based game driver works in the development distribution of Replay+
    but doesn't when I run it with the DOS, Win32 or Linux binary distribution.

A:  The binary distribution on intel (x86) based platforms use CPU cores 
    written in ASM for speed.  The development distribution uses CPU cores
    written in 'C'.  

    Assuming that both cores are bug-free you would expect your game driver
    to work on both.  However, there are a couple of small differences in
    the way the ASM 68000 CPU core accesses memory.  Therefore, to ensure
    proper operation make sure your game driver does the following for 
    all 68000 CPUs:

        * If there is any chance that a read handler will be accessed as part
          of a word, make sure the handler starts on an even address.
          For example, if you have two dip switches that are accessed at
          memory addresses 0x080000 and 0x080001 you may be tempted to
          add two handlers, one at 0x080000 and one at 0x080001.  However,
          the CPU core may have problems if it attempts to read both 
          dip switches at once by reading a word value from 0x080000.
          Therefore, combine the two handlers into one and in the handler,
          return the correct value based on the address passed in.
        * Make sure all RAM segments that you allocated with 
          AddrSpace::setSegments() also appear in the read & write handlers
          for the CPU with the Game::s_readRAM() and Game::s_writeRAM()
          handlers respectively.
          The 'C' CPU core will find the sections without having a handler
          specified, however, the ASM core must have them explicitly stated.

Q:  My 68000 based game driver doesn't work in the development distribution
    of Replay+ but works when I run it in the binary distribution in Linux.

A:  There is currently a problem with the way Replay+ interfaces with the
    'C' based assembly core found in the development version.  Certain 
    instructions expect 2 byte addresses to be read/written to page $ff
    instead of page $00.  

    This is a bug in Replay+ that will be fixed shortly!  Fortunately, 
    the instructions in question aren't that common.  Wait for the fix
    or if you can't wait, fix it and send me the changes :-)
