

   ##### ####### ##   ## #### ######   ###   ####      ####   #####  ###  ##
  ##   #  ##   # ###  ##  ##  # ## #  ## ##   ##      ##     ##   ##  ##  ##
 ##       ##     #### ##  ##    ##   ##   ##  ##     ##      ##   ##  ## ## 
 ##       ####   #######  ##    ##   ##   ##  ##     ######   #####   ####  
 ##  ###  ##     ## ####  ##    ##   #######  ##     ##   ## ##   ##  ####  
  ##  ##  ##   # ##  ###  ##    ##   ##   ##  ##  ## ##   ## ##   ##  ## ## 
   ##### ####### ##   ## ####  ####  ##   ## #######  #####   #####  ###  ##

                            [ Genital68K Readme ]
                   Copyright 2000, 2001 Bart Trzynadlowski


This is the documentation for Genital68K Version 0.22, please read it. Terms
of use are explained a little further below, it is required that you read and
abide by them in order to use this software.
    Genital68K emulates the Motorola 68000 microprocessor. It was written for
Intel X86-based (Pentium or better) systems. Originally designed for Genital,
it is now available for public use.

Contact Bart Trzynadlowski:
        Email: trzy@mailandnews.com
        WWW: http://trzy.overclocked.org
             http://trzy.overclocked.org/gen68k


< 0. Terms of Use >

Genital68K is Copyright 2000, 2001 Bart Trzynadlowski.

"Genital68K" refers to: MAKE68K.C, GEN68K.H, README.TXT, any binaries compiled
from those files, any source code emitted from MAKE68K.C, and any object file
created from such code.

To use Genital68K, you must agree to the following:

    - Genital68K shall be distributed freely, unmodified, and intact.
    - Charging money, goods, or services for Genital68K is forbidden.
    - Claiming ownership or authorship of Genital68K is forbidden.
    - Genital68K may not be distributed in any medium for which money, goods,
      or services are solicited.
    - The author, Bart Trzynadlowski, will not be held liable for damages.
    - Credit must be given to the author either in the program itself (where
      the user can see it) or in its documentation.
    
You are encouraged to contact Bart Trzynadlowski if you wish to use Genital68K
in a commercial product (to negotiate licensing.)
    Bart Trzynadlowski reserves the right to use Genital68K in any way he sees
fit. If you do not agree with all of these terms, please remove Genital68K
from your possession.


< 1. Table of Contents >

    0. Terms of Use
    1. Table of Contents
    2. Making Genital68K
    3. Configuration
    4. Genital68K 101
        4.1 Data Types
        4.2 Macros
        4.3 Context
        4.4 Memory Maps
        4.5 Memory Format
        4.6 Function Reference
    5. Running Genital68K
        5.1 Executing Code
        5.2 Managing Interrupts
        5.3 Branches
    6. Tricks of the Trade
        6.1 Alternative Identifiers
        6.2 Multiple Processors
        6.3 Speed
        6.4 PC-Relative Reading
    7. Additional Notes
        7.1 Change History
        7.2 Unemulated Features
        7.3 Errata
        7.4 Bibliography
    8. Special Thanks


< 2. Making Genital68K >

The Genital68K 68000 emulator is usually distributed in a compressed archive,
simply extract it and you should have MAKE68K.C, GEN68K.H, and this README.TXT
file.

The first step is to get the source code emitter, Make68K, up and running. It
should compile with any 32-bit C compiler (compilers other than gcc will often
produce warnings, these can be ignored.) The following have been confirmed:

    - DJGPP (gcc v2.8.1)                            [ MS-DOS ]
    - gcc v2.7.2.1                                  [ FreeBSD ]
    - Microsoft VisualC++ 6.0 Professional Edition  [ Windows 95 ]
    - WATCOM C/C++32 Version 10.6                   [ MS-DOS ]

If you get link errors concerning pow(), make sure to include the appropriate
math library. Try "-lm" if you are using GNU or similar tools.

Once Make68K has been built, run it with the name of the file you wish to emit
on the command line. For example:

    make68k gen68k.asm

Make68K can take a number of options. Try "make68k -h" to see a list of them.
The "Configuration" section of this text describes them in more detail.

Assemble the emitted file with NASM. Version 0.97 or better should work, 0.98
is known to work.
    Genital68K contains identifiers with leading and trailing underscores as
well as without any, so all the object formats supported by NASM should work.
Stack calling conventions are used, if you need register calling conventions,
contact me and I can add support for them.

Remember to include GEN68K.H to use Genital68K.


< 3. Configuration >

Genital68K can be tailored in a variety of ways to suit your needs best. The
options you can specify are:

    -addr #         Address bus width. This simulates the specified number of
                    address lines by cutting off any unsupported address bits
                    when accessing memory or updating the PC. The 68000 has a
                    24-bit address bus. [Default=24]
    -illegal        Emulates illegal instruction traps. Line 1010 and Line
                    1111 emulator exceptions are processed as is the normal
                    illegal instruction exception. [Default]
    -noillegal      Does not emulate illegal instruction traps but instead
                    returns an error from Genital68KRun(). The ILLEGAL opcode
                    does generate an illegal instruction trap regardless of
                    wether -illegal or -noillegal has been specified.
    -skip           Skips over idle DBRA loops by setting the counter register
                    to 0xFFFF, adjusting the timer appropriately, and moving
                    to the next instruction.
    -noskip         Does not skip over idle loops. This eliminates problems
                    with compatibility and is recommended. [Default]
    -brafetch       Uses the fetch memory map array to update the PC on Bcc,
                    BRA, BSR, and DBcc instructions.
    -nobrafetch     Bcc, BRA, BSR, and DBcc branches are handled by adding the
                    displacement to the internal normalized PC. This is less
                    safe because code can jump out of bounds and crash the
                    program. Branches cannot jump too far, so this is usually
                    safe to use -- it is also a bit quicker than -brafetch and
                    produces less code. [Default]
    -pcfetch        PC-relative reads are handled through a special fetch map.
                    Please read section 6.4 for more information.
    -nopcfetch      PC-relative reads are treated as normal data reads.
                    [Default]
    -multiaddr      Separate address spaces for supervisor and user. This has
                    not been extensively tested, so let me know how it works.
                    [Default]
    -singleaddr     Single address space for supervisor and user.
    -defmap         Definable memory map arrays are used to handle reading and
                    writing to the address space. [Default]
    -handler        Uses handlers for reading/writing bytes, words, and long-
                    words. The fetch memory map array must still be set up.
    -stackcall      Use stack-based calling conventions. [Default]
    -regcall        Use register-based calling conventions. EAX contains the
                    first argument, the second is in EDX. Someone let me know
                    if this works or not.
    -id $           Adds the specified string to the beginning of all
                    identifiers. Up to 16 characters are allowed. See section
                    6.1 for more information on this.

Please read the documentation to learn more about the details of some of these
options.


< 4. Genital68K 101 >

A general overview of Genital68K is provided here. More information is given
throughout the rest of the document.

[ 4.1 Data Types ]

A few data types are provided by Genital68K. All structures are build off of
these basic types:

    GENITAL68K_UINT32           Unsigned 32-bit
    GENITAL68K_INT32            Signed 32-bit
    GENITAL68K_UINT16           Unsigned 16-bit
    GENITAL68K_INT16            Signed 16-bit
    GENITAL68K_UINT8            Unsigned 8-bit
    GENITAL68K_INT8             Signed 8-bit

[ 4.2 Macros ]

Genital68K functions return macros to specify wether or not the operation was
successful and, if it was not, what the problem was. There are also a few
macros that can be passed as arguments to certain functions.

    Return Codes:
    -------------
    GENITAL68K_OKAY             Success
    GENITAL68K_NULL             0
    GENITAL68K_SUPERVISOR       Supervisor address space
    GENITAL68K_USER             User address space
    GENITAL68K_ERROR_FETCH      Fetch error (PC out of bounds)
    GENITAL68K_ERROR_INVINST    Invalid instruction
    GENITAL68K_ERROR_INTLEVEL   Invalid interrupt level was specified
    GENITAL68K_ERROR_INTVECTOR  Invalid interrupt vector was specified
    GENITAL68K_ERROR_INTPENDING Specified interrupt level already pending

    Argument Macros:
    ----------------
    GENITAL68K_UNINITIALIZED    Uninitialized interrupt vector
    GENITAL68K_SPURIOUS         Spurious interrupt vector
    GENITAL68K_AUTOVECTOR       Autovectored interrupt

Not all functions return something, and the macros are often specific to
certain functions.

[ 4.3 Context ]

Contexts are special structures which contain information on the processor's
state. The procedure for emulating a 68000 processor with Genital68K involves
setting up a context, mapping it in, emulating some code, and possible mapping
the context back out of Genital68K's internal context space.

    Context Definition:
    -------------------
    struct GENITAL68K_CONTEXT
    {
        void                *fetch;
        void                *read_byte, *read_word, *read_long;
        void                *write_byte, *write_word, *write_long;
        void                *super_fetch;
        void                *super_read_byte, *super_read_word,
                            *super_read_long;
        void                *super_write_byte, *super_write_word,
                            *super_write_long;
        void                *user_fetch;
        void                *user_read_byte, *user_read_word,
                            *user_read_long;
        void                *user_write_byte, *user_write_word,
                            *user_write_long;
        GENITAL68K_UINT32   intr[8], cycles, remaining;
        GENITAL68K_UINT32   d[8], a[8], sp, sr, pc, status;
        void                *Reset;
    };


The "fetch" pointer points to the fetch memory map (memory maps are described
in the next section) which tells Genital68K where it can fetch instructions
from. You can only set this up if separate address spaces for supervisor and
user are disabled. Otherwise, "super_fetch" and "user_fetch" must be set up
and "fetch" will be used internally by Genital68K.
    The "read_byte", "read_word", "read_long", "write_byte", "write_word", and
"write_long" pointers point to the mechanism Genital68K uses to carry out the
corresponding operations. They point either to definable memory map arrays or
to functions, depending on wether you specified -defmap or -handler. As with
the fetch pointer, if separate address spaces are enabled, you must set up
the super_ and user_ pointers and leave the rest for Genital68K's internal
usage.
    The "intr" array holds information on pending interrupts. Entries 0 to 6
hold the vectors for interrupt levels 1-7 (if pending, otherwise they are set
to 0) and "intr[7]" holds the number of pending interrupts.
    The "cycles" and "remaining" members are used to control execution time.
The total amount of request cycles is held in "cycles" and the number left is
held in "remaining."
    Data and address registers are kept in the "d" and "a" array, the PC is
kept in "pc", and the SR is kept in "sr." Whichever stack pointer is not in
A7 is stored in "sp." Thus, if the processor is in Supervisor mode, A7 is the
SSP and "sp" contains the USP. Additional information on the processor status
is reflected in the "status" member. Its format is:
    
    Bit 0:  R (Running) flag -- 0 = not running, 1 = running
    Bit 1:  S (Stopped) flag -- 0 = not stopped, 1 = stopped via the STOP
            instruction
    Bit 2:  I (Interrupt) flag -- 0 = not processing interrupts, 1 = process-
            ing interrupts (Genital68KProcessInterrupts())

Finally, the "Reset" pointer points to a Reset handler. If the RESET instruct-
ion is executed, this handler will be called. If the pointer is set to 0, it
will not be called.

Contexts can be mapped in and out of Genital68K's internal data space by using
Genital68KSetContext() and Genital68KGetContext(). Once they are mapped in, no
changes will be reflected in your context structures until you map them out.

NOTE: You CANNOT access context members while the context is mapped in unless
there are functions provided for that purpose (such as Genital68KSetFetch(),
Genital68KFreeTimeSlice(), Genital68KReadPC(), etc.)
    If there is no function for the operation you want to perform on the
context, you simply cannot do it until the context is mapped out. You may NOT
map contexts in and out from memory handlers while Genital68K is running.
Please consult the function reference for more information.

Genital68K provides an internal context called "genital68kcontext" which is
where you copy your context when you use Genital68KSetContext().
    You can use this internal context if you are emulating a single 68000 but
you must be careful with setting up the memory map. Unlike with contexts that
you define, you may not simply attach (or read) memory map arrays and function
pointers, you must use:

    Genital68KSetFetch(), Genital68KGetFetch()
    Genital68KSetReadByte(), Genital68KSetReadWord(),
    Genital68KSetReadLong(), Genital68KGetReadByte(),
    Genital68KGetReadWord(), Genital68KGetReadLong()
    Genital68KSetWriteByte(), Genital68KSetWriteWord(),
    Genital68KSetWriteLong(), Genital68KGetWriteByte(),
    Genital68KGetWriteWord(), Genital68KGetWriteLong()

The reason for these functions is that Genital68K expects these items in its
internal context to be slightly mangled for performance reasons. You can set
the "Reset" pointer without using any special functions.
    Genital68KSetContext() and Genital68KGetContext adjust the pointers auto-
matically for you. Please see the "Memory Maps" section for more information
on setting up memory maps.

Here is an example of defining a context and mapping it in and out:

    struct GENITAL68K_CONTEXT   mycontext;

    /* ... Set up everything ... */

    Genital68KSetContext(&mycontext);
    /* ... Run some code ... */
    Genital68KGetContext(&mycontext);
    
[ 4.4 Memory Maps ]

The 68000 address space is completely definable by the user. An array of fetch
regions must be set up so that Genital68K can fetch instructions, and then
the byte read, word read, byte write, etc. must be handled through structures
or handlers (depending on wether or not the -defmap or -handler option was
used when emitting Genital68K.)

    Fetch Region Definition:
    ------------------------
    struct GENITAL68K_FETCHREGION
    {
        GENITAL68K_UINT32   base;
        GENITAL68K_UINT32   limit;
        GENITAL68K_UINT32   ptr;
    };

The "base" member of a fetch region structure contains the address of the
start of the region being defined (as the 68000 would see it.) For example, if
a given system has ROM starting at address 0x000000, this would be: 0x000000.
    The "limit" member is the limit of the region. If a given system's ROM
space ended at 0x3FFFFF you would set this to 0x3FFFFF.
    The "ptr" member is a pointer to the host system address where the actual
data will be fetched from -- minus the base 68000 address (this simplifies the
fetching code a bit.) If you have a pointer called "rom", you would set ptr to
"(GENITAL68K_UINT32) rom - 0x000000"; remember to subtract the base!

Genital68K expects an array of fetch regions. The last element of the array
should have the base and limit set to -1 (0xFFFFFFFF) and the pointer set to
0 (GENITAL68K_NULL can be used.) Here is an example of a fetch array for a
hypothetical system:

    struct GENITAL68K_FETCHREGION fetch[] =
    {
        { 0x000000, 0x3fffff, (GENITAL68K_UINT32) rom - 0x000000 },
        { 0xe00000, 0xffffff, (GENITAL68K_UINT32) ram - 0xe00000 },
        { -1,       -1,       GENITAL68K_NULL }
    };

Obviously, if the pointers to the ROM and RAM regions are dynamically allocat-
ed, you will have to set up the pointer for each region using code:

    rom = calloc(0x400000, sizeof(GENITAL68K_UINT8));
    ram = calloc(0x200000, sizeof(GENITAL68K_UINT8));
    fetch[0].ptr = (GENITAL68K_UINT32) rom - 0x000000;
    fetch[1].ptr = (GENITAL68K_UINT32) ram - 0xe00000;

NOTE: It is important that you read section 4.5, "Memory Format", in order to
understand what format Genital68K expects memory regions it accesses to be in.

For data fetching, Genital68K allows more flexibility than for code fetching.
The default method is to set up an array of regions for all the different
access sizes.

    Data Region Definition:
    -----------------------
    struct GENITAL68K_DATAREGION
    {
        GENITAL68K_UINT32   base;
        GENITAL68K_UINT32   limit;
        GENITAL68K_UINT32   ptr;
        void                *handler;
    };

The first 3 members are the same as in the GENITAL68K_FETCHREGION structure.
The "handler" pointer should point to a function if you wish to emulate the
given region that way. Make sure to set "ptr" to 0.
    If you can supply a pointer, it is recommended over using handlers because
it is quicker. Make sure to set the handler pointer to 0.
    Read handlers must take the address as their argument and return the data.
Write handlers return nothing (void) and must take an address and data argum-
ent. For example:

    GENITAL68K_UINT8 ReadByte(GENITAL68K_UINT32 addr)
    {
        return mem[addr ^ 1];
    }

    void WriteWord(GENITAL68K_UINT32 addr, GENITAL68K_UINT16 data)
    {
        *((GENITAL68K_UINT16) (mem + addr)) = data;
    }

Addresses passed to handlers are clipped to the size of the address bus you
are emulating.

You must set up memory maps for all different size memory accesses, even long-
word. The real 68000 has a 16-bit data bus and breaks down long-word accesses
into 2 consecutive word accesses. Genital68K includes a long-word memory map
because it allows for optimization (2 word accesses are very slow.)
    If code tries to access an address which was not defined by you, it will
have no effect in the case of writes, and reads will return all 1's.

Here is an example of a hypothetical system's byte read memory map:

    struct GENITAL68K_DATAREGION read_byte[] =
    {
        { 0x000000, 0x3fffff, (GENITAL68K_UINT32) rom - 0x000000, NULL },
        { 0xa00000, 0xafffff, 0, VRAMReadByte },
        { 0xe00000, 0xffffff, (GENITAL68K_UINT32) ram - 0xe00000, NULL },
        { -1,       -1,       GENITAL68K_NULL,  GENITAL68K_NULL }
    };

There is a special read mode available for the PC-relative addressing mode. It
is by default disabled and is useful only in some very special circumstances.
Please read section 6.4 for more information.

The final step is to hook up your memory maps to Genital68K. The following
example assumes you have defined a context called "mycontext" and that the
supervisor and user address spaces are the same:

    mycontext.super_fetch = fetch;
    mycontext.super_read_byte = read_byte;
    mycontext.super_read_word = read_word;
    mycontext.super_read_long = read_long;
    mycontext.super_write_byte = write_byte;
    mycontext.super_write_word = write_word;
    mycontext.super_write_long = write_long;
    mycontext.user_fetch = fetch;
    mycontext.user_read_byte = read_byte;
    mycontext.user_read_word = read_word;
    mycontext.user_read_long = read_long;
    mycontext.user_write_byte = write_byte;
    mycontext.user_write_word = write_word;
    mycontext.user_write_long = write_long;

If you disabled separate address spaces when generating Genital68K, you only
have to set up the pointers without the super_ or user_ prefixes:

    mycontext.fetch = fetch;
    mycontext.read_byte = read_byte;
    mycontext.read_word = read_word;
    mycontext.read_long = read_long;
    mycontext.write_byte = write_byte;
    mycontext.write_word = write_word;
    mycontext.write_long = write_long;
    
If you are only emulating one 68000, and if you are using genital68kcontext,
you will have to use special functions to hook up the memory map:

    Genital68KSetFetch(fetch, GENITAL68K_SUPERVISOR);
    Genital68KSetReadByte(read_byte, GENITAL68K_SUPERVISOR);
    /* ... etc., etc. ... */
    Genital68KSetFetch(fetch, GENITAL68K_USER);
    Genital68KSetReadByte(read_byte, GENITAL68K_USER);

You may switch memory maps from within a handler to simulate a system that can
change its memory map while running by using the above functions. If you need
to check which memory map is hooked up, use Genital68KGetFetch(), etc.
    If you are not emulating multiple address spaces, you do not have to call
each function twice, just do it once. The second argument, which is a macro
that tells Genital68K wether to modify the supervisor or user space, will be
ignored since it is not applicable:

    Genital68KSetFetch(fetch, GENITAL68K_NULL);
    Genital68KSetReadByte(read_byte, GENITAL68K_NULL);

NOTE: You can choose your own names for the memory map arrays and do not have
to use those shown here.

There is another way to handle memory accesses. You can choose to supply hand-
lers for each of the different sized accesses. This is what the -handler opt-
ion is for. All you have to do is hook up the handler to the context:

    mycontext.super_read_byte = &ReadByte;
    mycontext.super_read_word = &ReadWord;
    /* ... etc., etc. ... */

If you are using genital68kcontext, you will have to use the aforementioned
functions again:

    Genital68KSetReadByte(&ReadByte, GENITAL68K_SUPERVISOR);
    Genital68KSetReadWord(&ReadWord, GENITAL68K_SUPERVISOR);
    /* ... etc., etc. ... */

The fetch memory map MUST be in the array format. You cannot create handlers
for fetching code.

[ 4.5 Memory Format ]

Any memory area which Genital68K will directly access (such as the fetch areas
and memory pointers in the GENITAL68K_DATAREGION arrays) MUST be byte-swapped.
This speeds up memory accesses significantly, and Genital68K relies on it.

    Example of Byte-Swapping Code:
    ------------------------------

    void SwapMemory(GENITAL68K_UINT8 *mem, GENITAL68K_UINT32 length)
    {
        int i, j;

        /* swap bytes in each word */
        for (i = 0; i < length; i += 2)
        {
            j = mem[i];
            mem[i] = mem[i + 1];
            mem[i + 1] = j;
        }
    }
        
[ 4.6 Function Reference ]

All of Genital68K's functions are listed here; some are described later in the
document in a more thorough fashion. If a function is said to work anywhere,
you can use it without worry.
    Functions which are said not to work under a given circumstance will have
undefined results if used under those conditions. Usually this means the
context will be trashed. Be very careful!
    When Genital68K is operating, any handlers you have set up are considered
part of Genital68K. When it is said that a function cannot be called while
Genital68K is running, this means you cannot call it from a handler.

    GENITAL68K_INT32 Genital68KInit();
        Initializes the emulator. This must be called before anything else.
        Input:
            Nothing
        Returns:
            GENITAL68K_OKAY

    GENITAL68K_INT32 Genital68KReset();
        Resets the 68000. It uses read_long to fetch the start-up vectors.
        Make sure everything is set up. This may not be called while
        Genital68K is running.
        Input:
            Nothing
        Returns:
            GENITAL68K_OKAY
            GENITAL68K_ERROR_FETCH (PC is out of bounds)

    GENITAL68K_INT32 Genital68KRun(GENITAL68K_INT32 cycles);
        Executes at least the specified number of cycles. To get the actual
        number of cycles that were emulated, use Genital68KGetElapsedCycles().
        This may not be called while Genital68K is running.
        Input:
            Number of cycles
        Returns:
            GENITAL68K_OKAY
            GENITAL68K_ERROR_FETCH (PC is out of bounds)
            GENITAL68K_ERROR_INVINST (invalid instruction, if -noillegal was
            specified)

    GENITAL68K_INT32 Genital68KProcessInterrupts();
        Processes any pending interrupts (unless the priority level does not
        agree with the SR priority bits.) This has no effect if called while
        Genital68K is running.
        Input:
            Nothing
        Returns:
            GENITAL68K_OKAY
            GENITAL68K_ERROR_FETCH

    GENITAL68K_INT32 Genital68KInterrupt(GENITAL68K_INT32 level,
                                         GENITAL68K_UINT32 vector);
        Generates an interrupt with the specified level and vector. The level
        must be 1-7 and the vector cannot be less than 2. For the vector, you
        may specify the vector itself, GENITAL68K_AUTOVECTOR for an
        autovectored interrupt, GENITAL68K_SPURIOUS for a spurious interrupt,
        or GENITAL68K_UNINITIALIZED for an uninitialized interrupt. This can
        be called anywhere.
        Input:
            Level
            Vector
        Returns:
            GENITAL68K_OKAY
            GENITAL68K_INTLEVEL (invalid level)
            GENITAL68K_INTVECTOR (invalid vector)
            GENITAL68K_INTPENDING (interrupt already pending at this level)

    GENITAL68K_INT32 Genital68KCancelInterrupt(GENITAL68K_INT32 level);
        Cancels the pending interrupt at the specified level. This can be
        called anywhere.
        Input:
            Level
        Returns:
            GENITAL68K_OKAY
            GENITAL68K_INTLEVEL (invalid level)

    GENITAL68K_UINT32 Genital68KReadPC();
        Returns the current PC. If this is called from within a handler, the
        PC may point at the next instruction or to one of the operand words.
        This works anywhere.
        Input:
            Nothing
        Returns:
            PC

    void Genital68KSetFetch(void *fetch, GENITAL68K_INT32 type);
    void Genital68KSetPCFetch(void *pcfetch, GENITAL68K_INT32 type);
    void Genital68KSetReadByte(void *read_byte, GENITAL68K_INT32 type);
    void Genital68KSetReadWord(void *read_word, GENITAL68K_INT32 type);
    void Genital68KSetReadLong(void *read_long, GENITAL68K_INT32 type);
    void Genital68KSetWriteByte(void *write_byte, GENITAL68K_INT32 type);
    void Genital68KSetWriteWord(void *write_word, GENITAL68K_INT32 type);
    void Genital68KSetWriteLong(void *write_long, GENITAL68K_INT32 type);
        These functions will attach memory maps to the mapped-in context,
        genital68kcontext. If you want to attach them to a context you have
        created which is not mapped in, you can just assign them manually.
        These work anywhere.
        Input:
            Memory map array or function pointer (depending on wether
            Genital68K was configured for memory map arrays or handlers)
            Type: GENITAL68K_SUPERVISOR or GENITAL68K_USER. If you are not
            emulating the distinction, this argument can be set to anything
            and will be ignored. If the type is not recognized, the behavior
            is undefined
        Returns:
            Nothing

    void *Genital68KGetFetch(GENITAL68K_INT32 type);
    void *Genital68KGetPCFetch(GENITAL68K_INT32 type);
    void *Genital68KGetReadByte(GENITAL68K_INT32 type);
    void *Genital68KGetReadWord(GENITAL68K_INT32 type);
    void *Genital68KGetReadLong(GENITAL68K_INT32 type);
    void *Genital68KGetWriteByte(GENITAL68K_INT32 type);
    void *Genital68KGetWriteWord(GENITAL68K_INT32 type);
    void *Genital68KGetWriteLong(GENITAL68K_INT32 type);
        Will return the memory map or function pointers that are associated
        with each type of access. These work anywhere.
        Input:
            Type: GENITAL68K_SUPERVISOR or GENITAL68K_USER. If you are not
            emulating the distinction, this argument can be set to anything
            and will be ignored. If the type is not recognized, the behavior
            is undefined
        Returns:
            Memory map array or function pointer

    GENITAL68K_UINT8 *Genital68KFetchPtr(GENITAL68K_UINT32 addr);
        Return a host pointer to the specified address in the current address
        space. Genital68K scans the fetch region and if the address is not
        found, it will return 0. This is useful for disassemblers. It should
        work anywhere.
        Input:
            Address
        Returns:
            Host address

    GENITAL68K_UINT8 Genital68KReadByte(GENITAL68K_UINT32 addr);
    GENITAL68K_UINT16 Genital68KReadWord(GENITAL68K_UINT32 addr);
    GENITAL68K_UINT32 Genital68KReadLong(GENITAL68K_UINT32 addr);
    void Genital68KWriteByte(GENITAL68K_UINT32 addr, GENITAL68K_UINT8 data);
    void Genital68KWriteWord(GENITAL68K_UINT32 addr, GENITAL68K_UINT16 data);
    void Genital68KWriteLong(GENITAL68K_UINT32 addr, GENITAL68K_UINT32 data);
        These functions read/write data from the current Genital68K address
        space. Thus, they can call handlers you have set up. These are
        particularly useful for debuggers. These functions may not be called
        while Genital68K is running. Be careful, the PC returned (and possibly
        other context data) will be invalid. 
        Input:
            Address (and data if writing)
        Returns:
            Data (or nothing if writing)

    void Genital68KSetContext(struct GENITAL68K_CONTEXT *context);
    void Genital68KGetContext(struct GENITAL68K_CONTEXT *context);
        Map in and map out contexts using this pair of functions. Genital68K
        operates only on its internal genital68kcontext, so it is necessary
        to copy externally defined contexts into genital68kcontext when you
        want to emulate the processor they define. These functions also make
        adjustments to the addresses contained in fetch, read_byte, etc. in
        order to speed things up -- therefore you cannot access these members,
        or any other context member, while it is mapped in. These functions
        may not be called while Genital68K is running.
        Input:
            Address of context to map in/out
        Returns:
            Nothing

    GENITAL68K_UINT32 Genital68KGetContextSize();
        Returns the size, in bytes, of a Genital68K context. This is useful
        for asserting that your compiler is packing the contexts correctly.
        This works anywhere.
        Input:
            Nothing
        Returns:
            Size of context in bytes
        
    void Genital68KClearCycles();
        Clears both "cycles" and "remaining" causing Genital68K to exit early.
        Be careful: a call to Genital68KGetElapsedCycles() after this will
        return 0 or a small number which does not reflect the total amount of
        cycles used since Genital68K was last called to run. This works any-
        where.
        Input:
            Nothing
        Returns:
            Nothing

    void Genital68KFreeTimeSlice();
        Causes Genital68K to stop running early by working some magic on both
        "cycles" and "remaining". Unlike Genital68KClearCycles(), you can get
        the number of cycles executed with Genital68KGetElapsedCycles().
        If called from a handler, Genital68K does not actually stop running
        until the current instruction finishes. This works anywhere.
        Input:
            Nothing
        Returns:
            Nothing

    GENITAL68K_INT32 Genital68KGetElapsedCycles();
        Returns the amount of cycles run. Works anywhere.
        Input:
            Nothing
        Returns:
            Cycles run
      

< 5. Running Genital68K >

This section aims to guide you through operating Genital68K once you have set
it up. Please read "Genital68K 101" before you continue.

[ 5.1 Executing Code ]

The bulk of time spent emulating a 68000 processor with Genital68K will be in
Genital68KRun(). This function, as described in the function reference, takes
a single argument which is the amount of cycles to execute.
    Genital68KRun() guarantees it will execute AT LEAST the amount of cycles
you specified unless you explicitly cut it short. It may execute more cycles.
For example, if you ask to execute only 1 cycle, but the next instruction is
RTS, 16 cycles will actually be executed. Use Genital68KGetElapsedCycles() to
obtain the actual amount of cycles used.

It is best to call Genital68KRun() with large cycle counts in order to compen-
sate for the significant overhead at the beginning and end of the function.

Genital68KRun() will probably call any handlers you may have defined (unless
their address range is never accessed) so it is a good idea NOT to do anything
prohibited by the function reference in "Genital68K 101" from within handlers.

It is usually a good idea to test for errors from Genital68KRun(). Error codes
and their explanations are listed below:

    GENITAL68K_ERROR_FETCH      Could not fetch PC (out of bounds.) Genital68K
                                fetches the PC from the fetch array when
                                Genital68KRun() or
                                Genital68KProcessInterrupts() is called. It
                                also fetches when it encounters a JMP, JSR,
                                RTE, RTS, RTR, or has to process an exception.
                                By default, branch instructions do not check
                                the fetch array. See the "Branches" section.
                                Use Genital68KReadPC() to see where the PC
                                is at.
    GENITAL68K_ERROR_INVINST    By default, Genital68K will emulate illegal
                                instruction, Line 1010 emulator, and Line 1111
                                emulator exceptions. However, the -noillegal
                                instruction will cause Genital68K to return
                                this error code if an invalid instruction is
                                encountered. The "ILLEGAL" opcode, 0x4AFC,
                                will always generate an illegal instruction
                                trap, even if -noillegal was used. The PC will
                                point to the instruction which caused the
                                error.
    
[ 5.2 Managing Interrupts ]

Genital68K manages interrupts by storing a queue of up to 1 of each level of
interrupt. To generate an interrupt, call Genital68KInterrupt() with the level
as the first argument (1-7) and the vector as the second.
    The vector may not be 0 or 1, use Genital68KReset() instead. For the un-
initialized interrupt vector, you can use the macro GENITAL68K_UNINITIALIZED.
For the spurious interrupt vector, there is GENITAL68K_SPURIOUS.

Most likely, you will be using autovectored interrupts. In that case, use
GENITAL68K_AUTOVECTOR. This macro does not equal a vector, but a special value
that signals Genital68KInterrupt() to find the appropriate vector.

Genital68KInterrupt() returns GENITAL68K_OKAY or 3 possible errors:

    GENITAL68K_ERROR_INTLEVEL   The interrupt level was invalid. Use 1-7 only.
    GENITAL68K_ERROR_INTVECTOR  The interrupt vector was invalid, use 2-255
                                only.
    GENITAL68K_ERROR_INTPENDING An interrupt was already pending at the level
                                requested.

You can generate interrupts anywhere. Interrupts are processed at the beginn-
ing of Genital68KRun() and through Genital68KProcessInterrupts(). The latter
takes no arguments and can return GENITAL68K_ERROR_FETCH if one of the int-
errupt vectors points out of bounds. It is ignored if Genital68K is running.

If you want to cancel an interrupt (some systems require this to simulate
certain types of behavior) you can use Genital68KCancelInterrupt(). Pass the
level as the only argument, and the interrupt will be removed from the pending
queue. GENITAL68K_ERROR_INTLEVEL will be returned if the level is invalid.
    This function can be called anywhere. It will have no effect if it happens
to be called while interrupts are being processed. Use the "status" member of
the context to determine if Genital68K is busy processing interrupts. If it
is, you will have to exit the handler for Genital68K to finish processing and
test again in another handler or after Genital68K finishes running.

[ 5.3 Branches ]

Branch instructions are: Bcc, BRA, BSR, and DBcc (which includes DBRA.) By
default, Genital68K does not scan the fetch array to determine wether the
branch is within bounds. Most code tends to branch only short distances and
simply setting up your fetch array properly almost always eliminates any prob-
lems.
    Although I have not seen any Sega Genesis code do it, it is possible that
a branch can cross the boundaries of a fetch region. If this happens, the
program will crash. For situations like this, there is the -brafetch option.
This will force Genital68K to check against the fetch array on each branch.
The result of this is a performance hit and increased code size.

Genital68K also provides a very crude mechanism to detect and skip over idle
loops created with DBRA. When a DBRA instruction that branches to itself is
found, Genital68K calculates the amount of cycles the instruction will use
before it expires, and then sets the decrement register to 0xFFFF and goes on
to the next instruction.
    This behavior is turned off by default since it has caused compatibility
problems. To enable it, use the -skip option. Sega Genesis games which lock up
because of this include "Sonic the Hedgehog 3" and "Puggsy."


< 6. Tricks of the Trade >

For those of you who want to get the most out of Genital68K, this section aims
to provide some neat little tricks to try.

[ 6.1 Alternative Identifiers ]

The default identifier names have nothing preceding them (Genital68KInit(),
genital68kcontext, Genital68KReset(), etc.) However, if the need arises, you
can change the identifier names by adding a string to the beginning of them of
up to 16 characters in length.    
    Use the -id option to emit Genital68K with different identifier names. The
data types and macros will not be changed, GENITAL68K_CONTEXT will remain as
it is, so will GENITAL68K_OKAY, etc.
    You must also use the GENITAL68K_ID() macro defined in GEN68K.H to set the
new identifier names immediately after the header file has been included. For
example, if you want identifiers that start with "foo" you would write:

    #include "gen68k.h"
    GENITAL68K_ID(foo);

You can do this multiple times. If you have linked in 2 copies of Genital68K,
one with identifiers that start with "foo", and another with identifiers
starting with "bar", you would write:

    #include "gen68k.h"
    GENITAL68K_ID(foo);
    GENITAL68K_ID(bar);

With the above example, you would have functions like: fooGenital68KInit(),
barGenital68KInit(), and (if you linked in another copy of Genital68K without
modified identifiers) Genital68KInit().

[ 6.2 Multiple Processors ]

Emulating multiple processors is fairly simple (unless extremely accurate
timing is required.) You have to set up a context for each processor. You may
not use genital68kcontext as one of them, since it will be overwritten if you
map in the other processor.

    Simplistic Example of Running 2 68000s:
    ---------------------------------------

    struct GENITAL68K_CONTEXT   context[2];

    /* ... */

    for (int i = 0; i < 2; i++)
    {
        Genital68KSetContext(&context[i]);
        Genital68KRun(500);
        Genital68KGetContext(&context[i]);
    }

Since Genital68K is non-reentrant, you cannot multi-thread 2 processors unless
you link in 2 separate builds of Genital68K (with different identifier names,
you can use the -id option for this.)

[ 6.3 Speed ]

What better reason to write a CPU emulator in assembly language than speed? To
get the most speed out of Genital68K, here are a few things you can try:

    1. If you are using memory map arrays, set them up wisely. If you have
       memory regions bordering each other, try turning them into a single
       large region. This not only cuts down the time it takes to scan through
       the map, but lets code flow between the regions. Put the most commonly
       accessed regions at the beginning of the array, and the least commonly
       accessed at the end.
    2. Consider using handlers and not memory map arrays (-handler option.) If
       you can write a fast and clean set of handlers, you can speed things up
       by taking a load of work off of Genital68K's back. Optimize your long-
       word handlers as well. It is perfectly okay to have a long-word handler
       call your word handlers twice and return the combined data, but it is
       faster to write the handlers specifically for long-word accesses. 
    3. Execute code in large time slices. The overhead of Genital68KRun() is
       significant but it can be compensated by spending more time emulating.
       Throw Genital68KSetContext()/Genital68KGetContext() in the mix and the
       gains are even greater.
    4. If possible, use -nobrafetch (the default) instead of -brafetch. The
       branch instructions are used a lot. If -skip does not impact compatib-
       ility, consider using it, too.
    5. If you can get away with sneaking in a 32-bit address bus, do it. The
       68000 actually uses a 24-bit address bus, which means that Genital68K
       has to mask off the unused bits when fetching data. The overhead of
       doing this is negligible, but if you can get away with using the full
       32-bits, go for it.
    6. Don't allow separate address spaces for supervisor and user if you can
       get away with it (with most systems, it isn't needed.) This reduces
       some overhead in some of the instruction handlers and functions.
    7. Link the Genital68K object file close to the object files which call it
       most frequently. The theory behind this is that the processor will be
       able to easily cache in code areas that use each other often. It might
       not always yield any speed increase, but I have observed slightly
       quicker performance when optimizing the link order in Genital.
    8. Strip the program you compile, this will reduce the executable tremend-
       ously. Genital68K leaves behind a lot of symbols and junk.

There is a lot to do on my part. Genital68K features some really poor code,
but usually in uncommon instructions. When/if I have time, I will optimize
what I can, but not all at once.

[ 6.4 PC-Relative Reading ]

In some rare situations, PC-relative address reading cannot function properly
through the normal data access regions/handlers. An example of when this can
occur is when the emulated system uses partially encrypted ROMs (CPS-2.)
    Genital68K must be emitted with the -pcfetch option and a special fetch
region for PC-relative reads must be set up. Writes are still handled using
the data regions/handlers. The region is a GENITAL68K_FETCHREGION and thus no
handlers can be used. Memory pointers must be provided in the exact same way
as you would for a normal fetch region.
    The array of fetch regions must be attached to the "pcfetch" pointers of
the context:

    mycontext.pcfetch = pcfetch;
    mycontext.super_pcfetch = pcfetch;
    mycontext.user_pcfetch = pcfetch;

When using genital68kcontext, use Genital68KSetPCFetch() and
Genital68KGetPCFetch().


< 7. Additional Notes >

This is a collection of miscellaneous notes, points of interest, and errata.

[ 7.1 Change History ]

February 11, 2001: Version 0.22
    - Added a PC-relative read mode (useful in very special circumstances)
    - Removed some unused data
    - Removed sign-extended byte read functions (they were not being used)

January 13, 2001: Version 0.21
    - Fixed Genital68KReadXXX() and Genital68KWriteXXX() functions, they no
      longer trash the PC

January 7, 2001: Version 0.2
    - Slightly modified Genital68KReadXXX() and Genital68KWriteXXX() functions
    - Registers are now saved when Genital68K functions are called
    - Minor optimizations here and there

December 8, 2000: Version 0.12
    - Fixed a bug with register calling conventions and read/write handlers

December 4, 2000: Version 0.11
    - Fixed a bug in Genital68KGetContext() and Genital68KSetContext() which
      corrupted user and supervisor address spaces
    - Corrected a misleading comment in MAKE68K.C and updated the macro refer-
      ence in this document

December 3, 2000: Version 0.1
    - Added user/supervisor address space distinction (optional)
    - Changed address space functions
    - Added a GENITAL68K_NULL macro
    - Fixed some mistakes in this document

November 23, 2000: Version 0.0
    - Initial release

[ 7.2 Unemulated Features ]

The following are not emulated:

    Tracing         Genital68K does not emulate trace exceptions.
    Address Errors  Genital68K does not emulate address error exceptions. This
                    usually is unimportant for video game systems and arcades.
    Bus Errors      Bus errors are not emulated.
    Undefined Bits  Undefined bits in the SR are usually kept 0, undefined
                    condition flags in the CCR are actually undefined.
    FC Output Lines The real 68000 classifies address space accesses as either
                    "User Data", "User Program", "Supervisor Data", "Supervis-
                    or Program", or "CPU Space." Genital68K simplifies this by
                    supporting a user address space and a supervisor address
                    space. There is also an option to disable this distinction
                    and use one address space.

[ 7.3 Errata ]

Although I have attempted to fix every bug I came across, there is bound to be
something obscure, or possibly major, left undiscovered. There are a few
unimportant inaccuracies I do know about, but have not bothered to fix yet:

    DIVS, DIVU      Timing is off by up to 10% in worst-case scenarios.
    MULS, MULU      Timing is off by an unknown amount. The multiplication
                    algorithm used by the 68000 affects timing in pretty odd
                    ways.
    Timing          Some of the instructions have slightly inacurrate timing,
                    usually because of human error.
    Exceptions      Priority between interrupts and other exceptions (such as
                    privilege violation, division by 0, TRAP, TRAPV, etc.) is
                    not fully emulated. Priority among interrupts themselves
                    seems to be properly handled, and that is most important.
                    I have not seen any situations where interrupts and other
                    exceptions affect each other.
    
More information on the priority of spurious and uninitialized interrupts as
well as level 7 would be appreciated. I am going off what little the Motorola
manuals say.

[ 7.4 Bibliography ]

Most of what I know about the 68000 comes from the 2 free manuals I ordered
from Motorola. The rest comes from individuals who kindly helped me and are
mentioned in section 8.

    Documents Used:
    ---------------
    - "Programmer's Reference Manual" by Motorola (M68000PM/AD REV 1)
    - "M68000 8-/16-/32-Bit Microprocessor User's Manual Ninth Edition" by
      Motorola (M68000UM/AD REV 8)
       

< 8. Special Thanks >

Many thanks go out to those who helped me out with Genital68K and contributed
to the project in any form.

    - Neil Bradley
    - Victor Moya
    - Dynarec Mailing List: M.I.K.e, Neil Griffiths, Gwenole, etc.
    - Quintesson
    - Steve Snake
    - Tim Meekins
    - Kuwanger
    - Charles MacDonald
    - Stephane Dallongeville
    - Eli Dayan
    - Neill Corlett

And, of course, thank YOU! Remember, comments, suggestions, and contributions
are more than welcome, so get in touch with me. See you next time!
