//
// Project UnReality: The First Nintendo 64 Emulator
// Copyright (C) 1997-1998, Cold Fusion Entertainment
// All rights reserved
//
// This source code is unpublished propietary information of Cold Fusion Entertainment.  No portion of this software
// may be disclosed to any third party or copied or duplicated in any form, in whole or in part, without the prior
// written consent of Cold Fusion Entertainment.
// 

//
// $Log: emu.h $
// Revision 1.18  1998/05/25 04:39:27  BREAKPOINT
// Added 'Call Stack' to debugger which shows the history of JAL[R]/JR RA instructions.
// Revision 1.17  1998/05/24 20:48:58  BREAKPOINT
// Beginning of TLB implementation... fixed c0reg.Context to be 32 bit, changed exception handler to support TLB and modified
// assembly core to be re-entrant.
// Revision 1.16  1998/05/23 15:41:27  BREAKPOINT
// Implemented new (and correct) interrupt system..
// Revision 1.15  1998/05/16 02:50:24  BREAKPOINT
// Added extra debugging code to exception handlers to see if access violation was due to DMA or not.
// Revision 1.14  1998/04/23 23:36:19  BREAKPOINT
// Fixed RDP CMD 'current' comment (used to say 'end').
// Revision 1.13  1998/04/19 16:32:58  BREAKPOINT
// Added Trap Exceptions and included TEQ opcode.
// Revision 1.12  1998/04/13 00:56:03  BREAKPOINT
// *MANY* RSP instructions implemented, nearly complete RSP dissasembler functional.
// Revision 1.11  1998/04/08 23:49:30  BREAKPOINT
// Added RDP interrupts (to be used at a later time).
// Revision 1.10  1998/04/06 22:49:51  BREAKPOINT
// Fixed up LWC2 RSP opcode's IMMED decoding.
// Revision 1.9  1998/04/06 22:14:16  BREAKPOINT
// Added more RSP opcodes and RSP debugger opcodes.  LWC2 is kinda broke right now...
// Revision 1.8  1998/04/02 21:18:44  BREAKPOINT
// Implemented new memory mapping routines and changed ROM loading code.
// Revision 1.7  1998/03/29 20:25:10  BREAKPOINT
// Added Arithmetic Overflow Exception to exception handler...
// Revision 1.6  1998/03/22 17:53:53  BREAKPOINT
// Added COD/MAP file support to internal debugger
// Revision 1.5  1998/03/08 19:12:27  BREAKPOINT
// Version 0.3b.3 checkin... I need to really check this stuff in more often..
// Revision 1.4  1998/01/31 19:56:17  BREAKPOINT
// *LOTS* of changes... removed all C prototypes for emulation, changed tables, and removed 'u64' references.
// Revision 1.3  1998/01/20 00:32:35  BREAKPOINT
// New MemoryCopy() function definition...
// Revision 1.2  1998/01/10 21:57:30  BREAKPOINT
// Initial changes to move to assembly version of R4300i assembly core
// Revision 1.1  1998/01/10 01:26:42  BREAKPOINT
// Initial revision
//

//---------------------------------------------------------------------------------------------------------------------

#ifndef EMU_H
#define EMU_H

#include <windows.h>

#pragma pack(1)

void _cdecl MemCopy(void);
void _cdecl MemReadFail(void);
void _cdecl MemWriteFail(void);

void _cdecl UnknownOpcode(void);
void _cdecl COP_Unusable(void);
void _cdecl COP0_Unknown(void);
void _cdecl COP1_Unknown(void);
void _cdecl COP2_Unknown(void);
void _cdecl Unhandled_Opcode(void);

void _cdecl CountCompareInterrupt(void);
void _cdecl VerticalRetraceInterrupt(void);
void _cdecl SerialInterfaceInterrupt(void);
void _cdecl PeripherialInterfaceInterrupt(void);
void _cdecl AudioInterfaceInterrupt(void);
void _cdecl SignalProcessorInterrupt(void);
void _cdecl DisplayProcessorInterrupt(void);

void _cdecl GenerateArithmeticOverflow(void);
void _cdecl GenerateTrapException(void);

void _cdecl RegenInterrupts(void);		// Regenerates any pending interrupts that might have been buffered due to the IM flag off.
void _cdecl EventAdd_Compare(void);		// Adds compare event to the heap.
void _cdecl EventAdd_PI(void);			// Adds PI interrupt event to the heap.
void _cdecl EventAdd_SP(void);          // Adds signal processor interrupt event to the heap.
void _cdecl EventAdd_DP(void);          // Adds display processor interrupt event to the heap.

// Some *EXTREMELY* useful #defines for manipulation of opcodes...  These are *ONLY* used in the debugger for printing opcodes!

#define DECODE_JUMP         (((raw_opcode_ulong & 0x03FFFFFF) << 2) | (raw_opcode_addr & 0xF0000000))
#define DECODE_IMMED        ((uint)((raw_opcode[2] << 8) | raw_opcode[3]))

#define DECODE_RS           ((raw_opcode[0] & 0x03) << 3 | (raw_opcode[1] >> 5))
#define DECODE_RT           (raw_opcode[1] & 0x1F)
#define DECODE_RD           (raw_opcode[2] >> 3)
#define DECODE_SA           ((raw_opcode[2] & 0x07) << 2 | (raw_opcode[3] >> 6))
#define DECODE_FS           (DECODE_RD)
#define DECODE_FT           (DECODE_RT)
#define DECODE_FD           (DECODE_SA)

#define DECODE_BASE         (DECODE_RS)
#define DECODE_OFFSET       ((ulong)(((ulong)(SignExtend16(DECODE_IMMED)) << 2) + raw_opcode_addr + 4))

#define DECODE_SYSCALL      ((raw_opcode_ulong & 0x03FFFFFF) >> 6)
#define DECODE_BREAK        (DECODE_SYSCALL)

#define DECODE_OPCODE       (raw_opcode[0] >> 2)
#define DECODE_FUNCTION     (raw_opcode[3] & 0x3F)
#define DECODE_C0FMT        (DECODE_RS)
#define DECODE_C0FUNC       (DECODE_FUNCTION)
#define DECODE_C1FMT        (DECODE_RS)
#define DECODE_C2TYPE		(DECODE_RD)

#define DECODE_C1BC         (raw_opcode[1] & 0x03)
#define DECODE_C1S          (DECODE_FUNCTION)
#define DECODE_C1D          (DECODE_FUNCTION)
#define DECODE_C1W          (DECODE_FUNCTION)
#define DECODE_C1L          (DECODE_FUNCTION)

#define DECODE_C2IMM		(DECODE_IMMED & 0x07FF)
#define DECODE_C2VEC		(DECODE_SA)

//=========================================================================================================================

/*
 *  ----------------------------------------[ R4300i register structure ]---------------------------------------------------
 */

typedef struct
{
    ulong  GPR[32];						// Integer registers
    ulong  GPR64[64];					// Integer registers used when 64-bit mode is enabled
    float  FGR[32];						// Floating point registers

    ulong  PC;							// Program counter
    ulong  MultHI, MultLO;				// Multiply / divide registers
    ulong  MultHI64[2], MultLO64[2];	// Multiply / divide registers used when 64-bit mode is enabled
    bool   LLBit;						// Load / link bit
} R4RegSet;

/*
 *  -------------------------------------------[ Format of TLB Entry ]-----------------------------------------------------
 */

#define TLBENTRIES			48

typedef struct
{
    ulong PageMask;
    ulong EntryHi;
    ulong EntryLo1;
    ulong EntryLo0;
} TLB_EntryDef;

/*
 *  -----------------------------------------[ COP0 register structure ]---------------------------------------------------
 */

#define C0STATUS_IE			0x00000001
#define C0STATUS_EXL        0x00000002
#define C0STATUS_ERL        0x00000004
#define C0STATUS_KSU		0x00000018
#define C0STATUS_UX			0x00000020
#define C0STATUS_SX			0x00000040
#define C0STATUS_KX			0x00000080
#define C0STATUS_IM0		0x00000100
#define C0STATUS_IM1		0x00000200
#define C0STATUS_IM2		0x00000400
#define C0STATUS_IM3		0x00000800
#define C0STATUS_IM4		0x00001000
#define C0STATUS_IM5		0x00002000
#define C0STATUS_IM6		0x00004000
#define C0STATUS_IM7		0x00008000
#define C0STATUS_DE			0x00010000
#define C0STATUS_CE			0x00020000
#define C0STATUS_CH			0x00040000
#define C0STATUS_SR         0x00100000
#define C0STATUS_TS         0x00200000
#define C0STATUS_BEV        0x00400000
#define C0STATUS_RE			0x02000000
#define C0STATUS_FR			0x04000000
#define C0STATUS_RP			0x08000000
#define C0STATUS_COP0		0x10000000
#define C0STATUS_COP1		0x20000000
#define C0STATUS_COP2		0x40000000
#define C0STATUS_COP3		0x80000000
#define C0STATUS_IMASK		(C0STATUS_IM0 | C0STATUS_IM1 | C0STATUS_IM2 | C0STATUS_IM3 | \
							 C0STATUS_IM4 | C0STATUS_IM5 | C0STATUS_IM6 | C0STATUS_IM7)

#define C0CAUSE_EXC_MASK	0x0000007C
#define C0CAUSE_IP0			0x00000100
#define C0CAUSE_IP1			0x00000200
#define C0CAUSE_IP2			0x00000400
#define C0CAUSE_IP3			0x00000800
#define C0CAUSE_IP4			0x00001000
#define C0CAUSE_IP5			0x00002000
#define C0CAUSE_IP6			0x00004000
#define C0CAUSE_IP7			0x00008000
#define C0CAUSE_CE			0x18000000
#define C0CAUSE_BD			0x80000000
#define C0CAUSE_IPMASK		(C0CAUSE_IP0 | C0CAUSE_IP1 | C0CAUSE_IP2 | C0CAUSE_IP3 | \
							 C0CAUSE_IP4 | C0CAUSE_IP5 | C0CAUSE_IP6 | C0CAUSE_IP7)

typedef struct
{
    ulong Index;                  // Programmable pointer into TLB array
    ulong Random;                 // Random pointer into TLB array
    ulong EntryLo0;               // Low half of the TLB entry for even VPN
    ulong EntryLo1;               // Low half of the TLB entry for odd VPN
    ulong Context;                // Pointer to kernel PTE table
    ulong PageMask;               // TLB page mask
    ulong Wired;                  // Number of wired TLB entries
	ulong Unused7;				  //- UNUSED -
    ulong BadVAddr[2];            // Bad virtual address
    __int64 Count;                // Timer count
    ulong EntryHi;                // High half of TLB entry
    ulong Compare;                // Timer compare
    ulong Status;                 // Status register
    ulong Cause;                  // Cause register
    ulong ExceptionPC;            // Exception program counter
    ulong PRevID;                 // Processor revision identifier
    ulong Config;                 // Configuration register
    ulong LLAddr;                 // Load linked address
    ulong WatchLo;                // Memory reference trap address lower bits
    ulong WatchHi;                // Memory reference trap address upper bits
    ulong XContext[2];            // Context register for MIPS III addressing
	ulong Unused21;				  //- UNUSED -
	ulong Unused22;				  //- UNUSED -
	ulong Unused23;				  //- UNUSED -
	ulong Unused24;				  //- UNUSED -
	ulong Unused25;				  //- UNUSED -
    ulong PErr;                   //- UNUSED -
    ulong CacheErr;               //- UNUSED -
    ulong TagLo;                  // Cache tag register
    ulong TagHi;                  // Cache tag register (Reserved)
    ulong ErrorEPC;               // Error exception program counter
} C0RegSet;

#define C0REG_INDEX             0
#define C0REG_RANDOM            1
#define C0REG_ENTRYLO0          2
#define C0REG_ENTRYLO1          3
#define C0REG_CONTEXT           4
#define C0REG_PAGEMASK          5
#define C0REG_WIRED             6
#define C0REG_BADVADDR          8
#define C0REG_COUNT             9
#define C0REG_ENTRYHI           10
#define C0REG_COMPARE           11
#define C0REG_STATUS            12
#define C0REG_CAUSE             13
#define C0REG_EXCEPTIONPC       14
#define C0REG_PREVID            15
#define C0REG_CONFIG            16
#define C0REG_LLADDR            17
#define C0REG_WATCHLO           18
#define C0REG_WATCHHI           19
#define C0REG_XCONTEXT          20
#define C0REG_PERR              26
#define C0REG_CACHEERR          27
#define C0REG_TAGLO             28
#define C0REG_TAGHI             29
#define C0REG_ERROREPC          30

/*
 *  -----------------------------------------[ COP1 register structure ]---------------------------------------------------
 */

typedef struct
{
    ulong Impl_Rev;             // Implementation / revision
    ulong Unused_1;             //- UNUSED -
    ulong Unused_2;             //- UNUSED -
    ulong Unused_3;             //- UNUSED -
    ulong Unused_4;             //- UNUSED -
    ulong Unused_5;             //- UNUSED -
    ulong Unused_6;             //- UNUSED -
    ulong Unused_7;             //- UNUSED -
    ulong Unused_8;             //- UNUSED -
    ulong Unused_9;             //- UNUSED -
    ulong Unused_10;            //- UNUSED -
    ulong Unused_11;            //- UNUSED -
    ulong Unused_12;            //- UNUSED -
    ulong Unused_13;            //- UNUSED -
    ulong Unused_14;            //- UNUSED -
    ulong Unused_15;            //- UNUSED -
    ulong Unused_16;            //- UNUSED -
    ulong Unused_17;            //- UNUSED -
    ulong Unused_18;            //- UNUSED -
    ulong Unused_19;            //- UNUSED -
    ulong Unused_20;            //- UNUSED -
    ulong Unused_21;            //- UNUSED -
    ulong Unused_22;            //- UNUSED -
    ulong Unused_23;            //- UNUSED -
    ulong Unused_24;            //- UNUSED -
    ulong Unused_25;            //- UNUSED -
    ulong Unused_26;            //- UNUSED -
    ulong Unused_27;            //- UNUSED -
    ulong Unused_28;            //- UNUSED -
    ulong Unused_29;            //- UNUSED -
    ulong Unused_30;            //- UNUSED -
    ulong FCSR;                 // Control / status
} C1RegSet;

#define C1REG_IMPL_REV          0
#define C1REG_FCSR              31

/*
 *  ---------------------------------------[ RDRAM register structure ]---------------------------------------------------
 */

#define RDRAM_BASE_REG              0x03F00000
#define RDRAM_BASE_SIZE             (sizeof(RDRAM_RegSet))
#define RDRAM_BASE_END              (RDRAM_BASE_REG + (RDRAM_BASE_SIZE - 1))

#define RDRAM_CONFIG_REG            0x00
#define RDRAM_DEVICE_TYPE_REG       0x00
#define RDRAM_DEVICE_ID_REG         0x04
#define RDRAM_DELAY_REG             0x08
#define RDRAM_MODE_REG              0x0C
#define RDRAM_REF_INTERVAL_REG      0x10
#define RDRAM_REF_ROW_REG           0x14
#define RDRAM_RAS_INTERVAL_REG      0x18
#define RDRAM_MIN_INTERVAL_REG      0x1C
#define RDRAM_ADDR_SELECT_REG       0x20
#define RDRAM_DEVICE_MANUF_REG      0x24

#define RDRAM_0_DEVICE_ID           0
#define RDRAM_1_DEVICE_ID           1

#define RDRAM_RESET_MODE            0
#define RDRAM_ACTIVE_MODE           1
#define RDRAM_STANDBY_MODE          2

#define RDRAM_BASE_ADDR             0x00000000
#define RDRAM_COUNT                 2                               // 2 chips in N64
#define RDRAM_LENGTH                (2 * 512 * 2048)
#define RDRAM_TOTAL_LENGTH          (RDRAM_COUNT * RDRAM_LENGTH)

#define RDRAM_0_BASE_ADDRESS        (RDRAM_0_DEVICE_ID * RDRAM_LENGTH)
#define RDRAM_1_BASE_ADDRESS        (RDRAM_1_DEVICE_ID * RDRAM_LENGTH)

#define RDRAM_0_CONFIG              0x00000
#define RDRAM_1_CONFIG              0x00400
#define RDRAM_GLOBAL_CONFIG         0x80000

typedef struct
{
    ulong config_devty;
    ulong device_id;
    ulong delay;
    ulong mode;
    ulong ref_interval;
    ulong ref_row;
    ulong ras_interval;
    ulong min_interval;
    ulong addr_select;
    ulong device_manuf;
} RDRAM_RegSet;                     // 03F0_0000 -> 03F0_0027

/*
 *  ------------------------------------------[ RDRAM temp regs ?! ]-------------------------------------------------------
 */

#define RDRAM_TEMP_BASE_REG         (RDRAM_BASE_REG + RDRAM_BASE_SIZE)				// 03F0_0028 -> 03FF_FFFF
#define RDRAM_TEMP_BASE_SIZE        (0x100000 - RDRAM_BASE_SIZE)
#define RDRAM_TEMP_BASE_END         (RDRAM_TEMP_BASE_REG + (RDRAM_TEMP_BASE_SIZE - 1))

/*
 *  ------------------------------------[ Sound Processor Register structure ]---------------------------------------------
 */

#define SP_DMEM_SIZE                0x1000          // 4096 bytes
#define SP_IMEM_SIZE                0x1000          // 4096 bytes

#define SP_DMEM_BASE                0x04000000
#define SP_IMEM_BASE                0x04001000

#define SP_BASE_REG                 0x04040000
#define SP_BASE_SIZE                (sizeof(SP_RegSet))
#define SP_BASE_END                 (SP_BASE_REG + (SP_BASE_SIZE - 1))

#define SP_MEM_ADDR_REG             0x00            // Master
#define SP_DRAM_ADDR_REG            0x04            // Slave
#define SP_RD_LEN_REG               0x08            // R/W: read len
#define SP_WR_LEN_REG               0x0C            // R/W: write len
#define SP_STATUS_REG               0x10
#define SP_DMA_FULL_REG             0x14
#define SP_DMA_BUSY_REG             0x18
#define SP_SEMAPHORE_REG            0x1C

// SP MEM address: bit 12 specifies if address is IMEM or DMEM
#define SP_DMA_DMEM                 0x0000      // Bit 12: 0=DMEM, 1=IMEM
#define SP_DMA_IMEM                 0x1000      // Bit 12: 0=DMEM, 1=IMEM

// Values to clear/set bit in status reg (SP_STATUS_REG - write)
#define SP_CLR_HALT                 0x00001     // Bit  0: clear halt
#define SP_SET_HALT                 0x00002     // Bit  1: set halt
#define SP_CLR_BROKE                0x00004     // Bit  2: clear broke
#define SP_CLR_INTR                 0x00008     // Bit  3: clear intr
#define SP_SET_INTR                 0x00010     // Bit  4: set intr
#define SP_CLR_SSTEP                0x00020     // Bit  5: clear sstep
#define SP_SET_SSTEP                0x00040     // Bit  6: set sstep
#define SP_CLR_INTR_BREAK           0x00080     // Bit  7: clear intr on break
#define SP_SET_INTR_BREAK           0x00100     // Bit  8: set intr on break
#define SP_CLR_SIG0                 0x00200     // Bit  9: clear signal 0
#define SP_SET_SIG0                 0x00400     // Bit 10: set signal 0
#define SP_CLR_SIG1                 0x00800     // Bit 11: clear signal 1
#define SP_SET_SIG1                 0x01000     // Bit 12: set signal 1
#define SP_CLR_SIG2                 0x02000     // Bit 13: clear signal 2
#define SP_SET_SIG2                 0x04000     // Bit 14: set signal 2
#define SP_CLR_SIG3                 0x08000     // Bit 15: clear signal 3
#define SP_SET_SIG3                 0x10000     // Bit 16: set signal 3
#define SP_CLR_SIG4                 0x20000     // Bit 17: clear signal 4
#define SP_SET_SIG4                 0x40000     // Bit 18: set signal 4
#define SP_CLR_SIG5                 0x80000     // Bit 19: clear signal 5
#define SP_SET_SIG5                 0x100000    // Bit 20: set signal 5
#define SP_CLR_SIG6                 0x200000    // Bit 21: clear signal 6
#define SP_SET_SIG6                 0x400000    // Bit 22: set signal 6
#define SP_CLR_SIG7                 0x800000    // Bit 23: clear signal 7
#define SP_SET_SIG7                 0x1000000   // Bit 24: set signal 7

// Patterns to interpret status reg (SP_STATUS_REG - read)
#define SP_STATUS_HALT              0x001       // Bit  0: halt
#define SP_STATUS_BROKE             0x002       // Bit  1: broke
#define SP_STATUS_DMA_BUSY          0x004       // Bit  2: dma busy
#define SP_STATUS_DMA_FULL          0x008       // Bit  3: dma full
#define SP_STATUS_IO_FULL           0x010       // Bit  4: io full
#define SP_STATUS_SSTEP             0x020       // Bit  5: single step
#define SP_STATUS_INTR_BREAK        0x040       // Bit  6: interrupt on break
#define SP_STATUS_SIG0              0x080       // Bit  7: signal 0 set
#define SP_STATUS_SIG1              0x100       // Bit  8: signal 1 set
#define SP_STATUS_SIG2              0x200       // Bit  9: signal 2 set
#define SP_STATUS_SIG3              0x400       // Bit 10: signal 3 set
#define SP_STATUS_SIG4              0x800       // Bit 11: signal 4 set
#define SP_STATUS_SIG5              0x1000      // Bit 12: signal 5 set
#define SP_STATUS_SIG6              0x2000      // Bit 13: signal 6 set
#define SP_STATUS_SIG7              0x4000      // Bit 14: signal 7 set

// Use of SIG bits
#define SP_CLR_YIELD                SP_CLR_SIG0
#define SP_SET_YIELD                SP_SET_SIG0
#define SP_STATUS_YIELD             SP_STATUS_SIG0
#define SP_CLR_YIELDED              SP_CLR_SIG1
#define SP_SET_YIELDED              SP_SET_SIG1
#define SP_STATUS_YIELDED           SP_STATUS_SIG1
#define SP_CLR_TASKDONE             SP_CLR_SIG2
#define SP_SET_TASKDONE             SP_SET_SIG2
#define SP_STATUS_TASKDONE          SP_STATUS_SIG2

typedef struct
{
    ulong mem_addr;             // SP memory address   (R/W): [11:0] DMEM/IMEM address; [12] 0=DMEM,1=IMEM
    ulong dram_addr;            // SP DRAM DMA address (R/W): [23:0] RDRAM address
    ulong read_len;             // SP read DMA length  (R/W): [11:0] length, [19:12] count, [31:20] skip | direction: I/DMEM <- RDRAM
    ulong write_len;            // SP write DMA length (R/W): [11:0] length, [19:12] count, [31:20] skip | direction: I/DMEM -> RDRAM
    ulong status;               // SP status           (R/W): [14:0] valid bits
    ulong dma_full;             // SP DMA full           (R): [0] valid bit; dma full
    ulong dma_busy;             // SP DMA busy           (R): [0] valid bit; dma busy
    ulong semaphore;            // SP semaphore        (R/W): Read:  [0] semaphore flag (set on read)  Write: [] clear semaphore flag
} SP_RegSet;                        // 0404_0000 -> 0404_001F

#define SP_PC_REG                   0x04080000
#define SP_PC_SIZE                  (sizeof(SP_PC_RegSet))
#define SP_PC_END                   (SP_PC_REG + (SP_PC_SIZE - 1))

typedef struct
{
    ulong PC;                   // SP PC               (R/W): [11:0] program counter
} SP_PC_RegSet;                     // 0408_0000 -> 0408_0003

#define SP_IBIST_REG                0x04080004
#define SP_IBIST_SIZE               (sizeof(SP_IMEM_BIST_RegSet))
#define SP_IBIST_END                (SP_IBIST_REG + (SP_IBIST_SIZE - 1))

// Patterns to interpret status reg (SP_BIST_REG - write)
#define SP_IBIST_CHECK              0x01        // Bit 0: BIST check
#define SP_IBIST_GO                 0x02        // Bit 1: BIST go
#define SP_IBIST_CLEAR              0x04        // Bit 2: BIST clear

// Patterns to interpret status reg (SP_BIST_REG - read).
// First 2 bits are same as in write mode: Bit 0: BIST check; Bit 1: BIST go
#define SP_IBIST_DONE               0x04        // Bit 2: BIST done
#define SP_IBIST_FAILED             0x78        // Bit [6:3]: BIST fail

typedef struct
{
    ulong ibist;                // SP IMEM BIST REG (R/W): [6:0] BIST status bits
} SP_IMEM_BIST_RegSet;              // 0408_0004 -> 0408_0007

/*
 *  -----------------------------[ Display Processor Command Register structure ]-------------------------------------------
 */

#define DPC_BASE_REG                0x04100000
#define DPC_BASE_SIZE               (sizeof(DPC_RegSet))
#define DPC_BASE_END                (DPC_BASE_REG + (DPC_BASE_SIZE - 1))

#define DPC_START_REG               0x00
#define DPC_END_REG                 0x04
#define DPC_CURRENT_REG             0x08
#define DPC_STATUS_REG              0x0C
#define DPC_CLOCK_REG               0x10
#define DPC_BUFBUSY_REG             0x14
#define DPC_PIPEBUSY_REG            0x18
#define DPC_TMEM_REG                0x1C

// Values to clear/set bit in status reg (DPC_STATUS_REG - write)
#define DPC_CLR_XBUS_DMEM_DMA       0x0001      // Bit 0: clear xbus_dmem_dma
#define DPC_SET_XBUS_DMEM_DMA       0x0002      // Bit 1: set xbus_dmem_dma
#define DPC_CLR_FREEZE              0x0004      // Bit 2: clear freeze
#define DPC_SET_FREEZE              0x0008      // Bit 3: set freeze
#define DPC_CLR_FLUSH               0x0010      // Bit 4: clear flush
#define DPC_SET_FLUSH               0x0020      // Bit 5: set flush
#define DPC_CLR_TMEM_CTR            0x0040      // Bit 6: clear tmem ctr
#define DPC_CLR_PIPE_CTR            0x0080      // Bit 7: clear pipe ctr
#define DPC_CLR_CMD_CTR             0x0100      // Bit 8: clear cmd ctr
#define DPC_CLR_CLOCK_CTR           0x0200      // Bit 9: clear clock ctr

// Patterns to interpret status reg (DPC_STATUS_REG - read)
#define DPC_STATUS_XBUS_DMEM_DMA    0x001       // Bit  0: xbus_dmem_dma
#define DPC_STATUS_FREEZE           0x002       // Bit  1: freeze
#define DPC_STATUS_FLUSH            0x004       // Bit  2: flush
//#define DPC_STATUS_FROZEN           0x008       // Bit  3: frozen
#define DPC_STATUS_START_GCLK       0x008       // Bit  3: start gclk
#define DPC_STATUS_TMEM_BUSY        0x010       // Bit  4: tmem busy
#define DPC_STATUS_PIPE_BUSY        0x020       // Bit  5: pipe busy
#define DPC_STATUS_CMD_BUSY         0x040       // Bit  6: cmd busy
#define DPC_STATUS_CBUF_READY       0x080       // Bit  7: cbuf ready
#define DPC_STATUS_DMA_BUSY         0x100       // Bit  8: dma busy
#define DPC_STATUS_END_VALID        0x200       // Bit  9: end valid
#define DPC_STATUS_START_VALID      0x400       // Bit 10: start valid

typedef struct
{
    ulong start;                // DP CMD DMA start     (R/W): [23:0] DMEM/RDRAM start address
    ulong end;                  // DP CMD DMA end       (R/W): [23:0] DMEM/RDRAM end address
    ulong current;              // DP CMD DMA current     (R): [23:0] DMEM/RDRAM current address
    ulong status;               // DP CMD status        (R/W):  [9:0] valid bits
    ulong clock;                // DP clock counter       (R): [23:0] clock counter 
    ulong bufbusy;              // DP buffer busy counter (R): [23:0] clock counter
    ulong pipebusy;             // DP pipe busy counter   (R): [23:0] clock counter
    ulong tmem;                 // DP TMEM load counter   (R): [23:0] clock counter
} DPC_RegSet;                       // 0410_0000 -> 0410_001F

/*
 *  -------------------------------[ Display Processor Span Register structure ]--------------------------------------------
 */

#define DPS_BASE_REG                0x04200000
#define DPS_BASE_SIZE               (sizeof(DPS_RegSet))
#define DPS_BASE_END                (DPS_BASE_REG + (DPS_BASE_SIZE - 1))

#define DPS_TBIST_REG               0x00
#define DPS_TEST_MODE_REG           0x04
#define DPS_BUFTEST_ADDR_REG        0x08
#define DPS_BUFTEST_DATA_REG        0x0C

// Patterns to interpret status reg (DPS_TMEM_BIST_REG - write)
#define DPS_TBIST_CHECK             0x01        // Bit 0: BIST check
#define DPS_TBIST_GO                0x02        // Bit 1: BIST go
#define DPS_TBIST_CLEAR             0x04        // Bit 2: BIST clear

// Patterns to interpret status reg (DPS_TMEM_BIST_REG - read)
// First 2 bits are same as in write mode: Bit 0: BIST check; Bit 1: BIST go
#define DPS_TBIST_DONE              0x004       // Bit 2: BIST done
#define DPS_TBIST_FAILED            0x7F8       // Bit [10:3]: BIST fail

typedef struct
{
    ulong tbist;                // DP tmem bist                (R/W): [10:0] BIST status bits
    ulong test_mode;            // DP span test mode           (R/W): [0] Span buffer test access enable
    ulong buftest_addr;         // DP span buffer test address (R/W): [6:0] bits
    ulong buftest_data;         // DP span buffer test data    (R/W): [31:0] span buffer data
} DPS_RegSet;                       // 0420_0000 -> 0420_000F

/*
 *  ------------------------------------[ MIPS Interface Register structure ]--------------------------------------------
 */

#define MI_BASE_REG                 0x04300000
#define MI_BASE_SIZE                (sizeof(MIPS_Intf_RegSet))
#define MI_BASE_END                 (MI_BASE_REG + (MI_BASE_SIZE - 1))

#define MI_INIT_MODE_REG            0x00
#define MI_MODE_REG                 MI_INIT_MODE_REG
#define MI_VERSION_REG              0x04
#define MI_NOOP_REG                 MI_VERSION_REG
#define MI_INTR_REG                 0x08
#define MI_INTR_MASK_REG            0x0C

// Values to clear/set bit in mode reg (MI_MODE_REG - write)
#define MI_CLR_INIT                 0x0080      // Bit  7: clear init mode
#define MI_SET_INIT                 0x0100      // Bit  8: set init mode
#define MI_CLR_EBUS                 0x0200      // Bit  9: clear ebus test
#define MI_SET_EBUS                 0x0400      // Bit 10: set ebus test mode
#define MI_CLR_DP_INTR              0x0800      // Bit 11: clear dp interrupt
#define MI_CLR_RDRAM                0x1000      // Bit 12: clear RDRAM reg
#define MI_SET_RDRAM                0x2000      // Bit 13: set RDRAM reg mode

// Patterns to interpret mode reg (MI_MODE_REG - read)
#define MI_MODE_INIT                0x0080      // Bit  7: init mode
#define MI_MODE_EBUS                0x0100      // Bit  8: ebus test mode
#define MI_MODE_RDRAM               0x0200      // Bit  9: RDRAM reg mode

// The following are values to check for interrupt setting (MI_INTR_REG)
#define MI_INTR_SP                  0x01        // Bit 0: SP intr
#define MI_INTR_SI                  0x02        // Bit 1: SI intr
#define MI_INTR_AI                  0x04        // Bit 2: AI intr
#define MI_INTR_VI                  0x08        // Bit 3: VI intr
#define MI_INTR_PI                  0x10        // Bit 4: PI intr
#define MI_INTR_DP                  0x20        // Bit 5: DP intr
#define MI_INTR_MASK				(MI_INTR_SP | MI_INTR_SI | MI_INTR_AI | MI_INTR_VI | MI_INTR_PI | MI_INTR_DP)

// The following are values to clear/set various interrupt bit mask (MI_INTR_MASK_REG - write)
#define MI_INTR_MASK_CLR_SP         0x0001      // Bit  0: clear SP mask
#define MI_INTR_MASK_SET_SP         0x0002      // Bit  1: set SP mask
#define MI_INTR_MASK_CLR_SI         0x0004      // Bit  2: clear SI mask
#define MI_INTR_MASK_SET_SI         0x0008      // Bit  3: set SI mask
#define MI_INTR_MASK_CLR_AI         0x0010      // Bit  4: clear AI mask
#define MI_INTR_MASK_SET_AI         0x0020      // Bit  5: set AI mask
#define MI_INTR_MASK_CLR_VI         0x0040      // Bit  6: clear VI mask
#define MI_INTR_MASK_SET_VI         0x0080      // Bit  7: set VI mask
#define MI_INTR_MASK_CLR_PI         0x0100      // Bit  8: clear PI mask
#define MI_INTR_MASK_SET_PI         0x0200      // Bit  9: set PI mask
#define MI_INTR_MASK_CLR_DP         0x0400      // Bit 10: clear DP mask
#define MI_INTR_MASK_SET_DP         0x0800      // Bit 11: set DP mask

// The following are values to check for interrupt mask setting (MI_INTR_MASK_REG - read)
#define MI_INTR_MASK_SP             0x01        // Bit 0: SP intr mask
#define MI_INTR_MASK_SI             0x02        // Bit 1: SI intr mask
#define MI_INTR_MASK_AI             0x04        // Bit 2: AI intr mask
#define MI_INTR_MASK_VI             0x08        // Bit 3: VI intr mask
#define MI_INTR_MASK_PI             0x10        // Bit 4: PI intr mask
#define MI_INTR_MASK_DP             0x20        // Bit 5: DP intr mask

typedef struct
{
    ulong mode;                 // MI init mode      (W): [6:0] init length, [7] clear init mode, [8] set init mode
                                //                        [9:10] clear/set ebus test mode, [11] clear DP interrupt
                                //                   (R): [6:0] init length, [7] init mode, [8] ebus test mode

    ulong version;              // MI version        (R): [7:0] io, [15:8] rac, [23:16] rdp, [31:24] rsp
    ulong intr;                 // MI interrupt      (R): [5:0] valid bits
    ulong intr_mask;            // MI interrupt mask (W): [11:0] valid bits | (R): [5:0] valid bits
} MIPS_Intf_RegSet;                 // 0430_0000 -> 0430_000F

/*
 *  ------------------------------------[ Video Interface Register structure ]--------------------------------------------
 */

#define VERTICAL_RETRACE_TIME       625000

extern __int64 Last_Vert_Retrace_Count;

#define VI_BASE_REG                 0x04400000
#define VI_BASE_SIZE                (sizeof(VI_RegSet))
#define VI_BASE_END                 (VI_BASE_REG + (VI_BASE_SIZE - 1))

#define VI_STATUS_REG               0x00
#define VI_CONTROL_REG              VI_STATUS_REG
#define VI_ORIGIN_REG               0x04
#define VI_DRAM_ADDR_REG            VI_ORIGIN_REG
#define VI_WIDTH_REG                0x08
#define VI_H_WIDTH_REG              VI_WIDTH_REG
#define VI_INTR_REG                 0x0C
#define VI_V_INTR_REG               VI_INTR_REG
#define VI_CURRENT_REG              0x10
#define VI_V_CURRENT_LINE_REG       VI_CURRENT_REG
#define VI_BURST_REG                0x14
#define VI_TIMING_REG               VI_BURST_REG
#define VI_V_SYNC_REG               0x18
#define VI_H_SYNC_REG               0x1C
#define VI_LEAP_REG                 0x20
#define VI_H_SYNC_LEAP_REG          VI_LEAP_REG
#define VI_H_START_REG              0x24
#define VI_H_VIDEO_REG              VI_H_START_REG
#define VI_V_START_REG              0x28
#define VI_V_VIDEO_REG              VI_V_START_REG
#define VI_V_BURST_REG              0x2C
#define VI_X_SCALE_REG              0x30
#define VI_Y_SCALE_REG              0x34

// Patterns to interpret VI_CONTROL_REG
#define VI_CTRL_TYPE_16             0x00002    // Bit [1:0] pixel size: 16 bit
#define VI_CTRL_TYPE_32             0x00003    // Bit [1:0] pixel size: 32 bit
#define VI_CTRL_GAMMA_DITHER_ON     0x00004    // Bit 2: default = on
#define VI_CTRL_GAMMA_ON            0x00008    // Bit 3: default = on
#define VI_CTRL_DIVOT_ON            0x00010    // Bit 4: default = on
#define VI_CTRL_SERRATE_ON          0x00040    // Bit 6: on if interlaced
#define VI_CTRL_ANTIALIAS_MASK      0x00300    // Bit [9:8] anti-alias mode
#define VI_CTRL_DITHER_FILTER_ON    0x10000    // Bit 16: dither-filter mode

// Possible video clocks (NTSC or PAL)
#define VI_NTSC_CLOCK               48681812   // Hz = 48.681812 MHz
#define VI_PAL_CLOCK                49656530   // Hz = 49.656530 MHz
#define VI_MPAL_CLOCK               48628316   // Hz = 48.628316 MHz

// VI status/control (R/W): [15-0] valid bits:
//  [1:0]   = type[1:0] (pixel size)
//          0: blank (no data, no sync)
//                      1: reserved
//                      2: 5/5/5/3 ("16" bit)
//                      3: 8/8/8/8 (32 bit)
//  [2]     = gamma_dither_enable (normally on, unless "special effect")
//  [3]     = gamma_enable (normally on, unless MPEG/JPEG)
//  [4]     = divot_enable (normally on if antialiased, unless decal lines)
//  [5]     = reserved - always off
//  [6]     = serrate (always on if interlaced, off if not)
//  [7]     = reserved - diagnostics only
//  [9:8]   = anti-alias (aa) mode[1:0]
//          0: aa & resamp (always fetch extra lines)
//                      1: aa & resamp (fetch extra lines if needed)
//                      2: resamp only (treat as all fully covered)
//                      3: neither (replicate pixels, no interpolate)
//  [11]    = reserved - diagnostics only
//  [15:12] = reserved
typedef struct
{
    ulong stat_ctrl;
    ulong origin;               // VI origin        (R/W): [23:0] frame buffer origin in bytes
    ulong width;                // VI width         (R/W): [11:0] frame buffer line width in pixels
    ulong intr;                 // VI vertical intr (R/W):  [9:0] interrupt when current half-line = V_INTR

    ulong curr_vline;           // VI current vertical line (R/W): [9:0] current half line, sampled once per line (the lsb of 
                                // V_CURRENT is constant within a field, and in interlaced modes gives the field number - which
                                // is constant for non-interlaced modes) - Any write to this register will clear interrupt line

    ulong vid_timing;           // VI video timing  (R/W): [ 7: 0] horizontal sync width in pixels,
                                //                         [15: 8] color burst width in pixels,
                                //                         [19:16] vertical sync width in half lines,
                                //                         [29:20] start of color burst in pixels from h-sync

    ulong vsync;                // VI vertical sync   (R/W): [ 9: 0] number of half-lines per field
    ulong hsync;                // VI horizontal sync (R/W): [11: 0] total duration of a line in 1/4 pixel
                                //                           [20:16] a 5-bit leap pattern used for PAL only (h_sync_period)

    ulong hsync_leap;           // VI horizontal sync leap (R/W): [11: 0] identical to h_sync_period
                                //                                [27:16] identical to h_sync_period

    ulong horiz_vid;            // VI horizontal video (R/W): [ 9: 0] end of active video in screen pixels
                                //                          : [25:16] start of active video in screen pixels

    ulong vert_vid;             // VI vertical video (R/W): [ 9: 0] end of active video in screen half-lines
                                //                        : [25:16] start of active video in screen half-lines

    ulong vert_burst;           // VI vertical burst (R/W): [ 9: 0] end of color burst enable in half-lines
                                //                        : [25:16] start of color burst enable in half-lines

    ulong x_scale;              // VI x-scale (R/W): [11: 0] 1/horizontal scale up factor (2.10 format)
                                //                   [27:16] horizontal subpixel offset (2.10 format)
    ulong y_scale;              // VI y-scale (R/W): [11: 0] 1/vertical scale up factor (2.10 format)
                                //                   [27:16] vertical subpixel offset (2.10 format)
} VI_RegSet;                        // 0440_0000 -> 0440_0037

/*
 *  ------------------------------------[ Audio Interface Register structure ]--------------------------------------------
 */

// The address and length registers are double buffered; that is, they can be written twice before becoming full.
// The address must be written before the length.

#define AI_BASE_REG                 0x04500000
#define AI_BASE_SIZE                (sizeof(AI_RegSet))
#define AI_BASE_END                 (AI_BASE_REG + (AI_BASE_SIZE - 1))

#define AI_DRAM_ADDR_REG            0x00        // R0: DRAM address
#define AI_LEN_REG                  0x04        // R1: Length
#define AI_CONTROL_REG              0x08        // R2: DMA Control
#define AI_STATUS_REG               0x0C        // R3: Status
#define AI_DACRATE_REG              0x10        // R4: DAC rate 14-lsb
#define AI_BITRATE_REG              0x14        // R5: Bit rate 4-lsb

// Value for control register
#define AI_CONTROL_DMA_ON           0x01        // LSB = 1: DMA enable
#define AI_CONTROL_DMA_OFF          0x00        // LSB = 1: DMA enable

// Value for status register
#define AI_STATUS_FIFO_FULL         0x80000000  // Bit 31: full
#define AI_STATUS_DMA_BUSY          0x40000000  // Bit 30: busy

// DAC rate = video clock / audio frequency - DAC rate >= (66 * Bit rate) must be true
#define AI_MAX_DAC_RATE             16384       // 14-bit+1
#define AI_MIN_DAC_RATE             132

// Bit rate <= (DAC rate / 66)
#define AI_MAX_BIT_RATE             16          // 4-bit+1
#define AI_MIN_BIT_RATE             2

// Maximum and minimum values for audio frequency based on video clocks
//   max frequency = (video clock / min dac rate)
//   min frequency = (video clock / max dac rate)
#define AI_NTSC_MAX_FREQ            368000          // 368 KHz
#define AI_NTSC_MIN_FREQ            3000            //   3 KHz ~ 2971 Hz

#define AI_PAL_MAX_FREQ             376000          // 376 KHz
#define AI_PAL_MIN_FREQ             3050            //   3 KHz ~ 3031 Hz

#define AI_MPAL_MAX_FREQ            368000          // 368 KHz
#define AI_MPAL_MIN_FREQ            3000            //   3 KHz ~ 2968 Hz

typedef struct
{
    ulong dram_addr;            // AI DRAM address (W): [23:0] starting RDRAM address (8B-aligned)    

    ulong len;                  // AI length     (R/W): [14:0] transfer length (v1.0) - Bottom 3 bits are ignored
                                //                      [17:0] transfer length (v2.0) - Bottom 3 bits are ignored

    ulong control;              // AI control      (W): [0] DMA enable - if LSB == 1, DMA is enabled

    ulong status;               // AI status       (R): [31]/[0] ai_full (addr & len buffer full), [30] ai_busy
                                //                      Note that a 1->0 transition in ai_full will set interrupt
                                //                 (W): clear audio interrupt

    ulong dacrate;              // AI DAC sample period register (W): [13:0] dac rate
                                //   - vid_clock/(dperiod + 1) is the DAC sample rate
                                //   - (dperiod + 1) >= 66 * (aclockhp + 1) must be true

    ulong bitrate;              // AI bit rate (W): [3:0] bit rate (abus clock half period register - aclockhp)
                                //   - vid_clock/(2 * (aclockhp + 1)) is the DAC clock rate
                                //   - The abus clock stops if aclockhp is zero
} AI_RegSet;                        // 0450_0000 -> 0450_0017

extern ulong aireg_dram_hold, aireg_len_hold;
extern int aireg_dram_state, aireg_len_state;

/*
 *  ----------------------------------[ Peripheral Interface Register structure ]---------------------------------------------
 */

#define PI_BASE_REG                 0x04600000
#define PI_BASE_SIZE                (sizeof(PI_RegSet))
#define PI_BASE_END                 (PI_BASE_REG + (PI_BASE_SIZE - 1))

#define PI_DRAM_ADDR_REG            0x00    // DRAM address
#define PI_CART_ADDR_REG            0x04
#define PI_RD_LEN_REG               0x08
#define PI_WR_LEN_REG               0x0C
#define PI_STATUS_REG               0x10
#define PI_BSD_DOM1_LAT_REG         0x14
#define PI_BSD_DOM1_PWD_REG         0x18
#define PI_BSD_DOM1_PGS_REG         0x1C    //   page size
#define PI_BSD_DOM1_RLS_REG         0x20
#define PI_BSD_DOM2_LAT_REG         0x24    // Domain 2 latency
#define PI_BSD_DOM2_PWD_REG         0x28    //   pulse width
#define PI_BSD_DOM2_PGS_REG         0x2C    //   page size
#define PI_BSD_DOM2_RLS_REG         0x30    //   release duration

#define PI_DOMAIN1_REG              PI_BSD_DOM1_LAT_REG
#define PI_DOMAIN2_REG              PI_BSD_DOM2_LAT_REG

#define PI_DOM_LAT_OFS              0x00
#define PI_DOM_PWD_OFS              0x04
#define PI_DOM_PGS_OFS              0x08
#define PI_DOM_RLS_OFS              0x0C

// PI status register has 3 bits active when read from (PI_STATUS_REG - read)
//  Bit 0: DMA busy - set when DMA is in progress
//  Bit 1: IO busy  - set when IO is in progress
//  Bit 2: Error    - set when CPU issues IO request while DMA is busy
#define PI_STATUS_ERROR             0x04
#define PI_STATUS_IO_BUSY           0x02
#define PI_STATUS_DMA_BUSY          0x01

// PI status register has 2 bits active when written to:
//  Bit 0: When set, reset PIC
//  Bit 1: When set, clear interrupt flag
// The values of the two bits can be ORed together to both reset PIC and
// clear interrupt at the same time.
//
// Note:
//  - The PIC does generate an interrupt at the end of each DMA. CPU
//  needs to clear the interrupt flag explicitly (from an interrupt
//  handler) by writing into the STATUS register with bit 1 set.
//
//  - When a DMA completes, the interrupt flag is set.  CPU can issue
//  another request even while the interrupt flag is set (as long as
//  PIC is idle).  However, it is the CPU's responsibility for
//  maintaining accurate correspondence between DMA completions and
//  interrupts.
//
//  - When PIC is reset, if PIC happens to be busy, an interrupt will
//  be generated as PIC returns to idle.  Otherwise, no interrupt will
//  be generated and PIC remains idle.

// Values to clear interrupt/reset PIC (PI_STATUS_REG - write)
#define PI_STATUS_RESET             0x01
#define PI_SET_RESET                PI_STATUS_RESET
#define PI_STATUS_CLR_INTR          0x02
#define PI_CLR_INTR                 PI_STATUS_CLR_INTR

#define PI_DMA_BUFFER_SIZE          128

#define PI_DOM1_ADDR1               0x06000000  // to 0x07FFFFFF
#define PI_DOM1_ADDR2               0x10000000  // to 0x1FBFFFFF
#define PI_DOM1_ADDR3               0x1FD00000  // to 0x7FFFFFFF
#define PI_DOM2_ADDR1               0x05000000  // to 0x05FFFFFF
#define PI_DOM2_ADDR2               0x08000000  // to 0x0FFFFFFF

typedef struct
{
    ulong dram_addr;            // PI DRAM address        (R/W): [23:0] starting RDRAM address
    ulong cart_addr;            // PI pbus (cart) address (R/W): [31:0] starting AD16 address
    ulong rd_len;               // PI read length         (R/W): [23:0] read data length
    ulong wr_len;               // PI write length        (R/W): [23:0] write data length

    ulong status;               // PI status             (R): [0] DMA busy, [1] IO busy, [2], error
                                //                       (W): [0] reset controller (and abort current op), [1] clear intr

    ulong dom1_lat;             // PI dom1 latency     (R/W): [7:0] domain 1 device latency
    ulong dom1_pulse_width;     // PI dom1 pulse width (R/W): [7:0] domain 1 device R/W strobe pulse width
    ulong dom1_page_size;       // PI dom1 page size   (R/W): [3:0] domain 1 device page size
    ulong dom1_release;         // PI dom1 release     (R/W): [1:0] domain 1 device R/W release duration

    ulong dom2_lat;             // PI dom2 latency     (R/W): [7:0] domain 2 device latency
    ulong dom2_pulse_width;     // PI dom2 pulse width (R/W): [7:0] domain 2 device R/W strobe pulse width
    ulong dom2_page_size;       // PI dom2 page size   (R/W): [3:0] domain 2 device page size
    ulong dom2_release;         // PI dom2 release     (R/W): [1:0] domain 2 device R/W release duration
} PI_RegSet;                        // 0460_0000 -> 0460_0033

/*
 *  ------------------------------------[ RDRAM Interface Register structure ]-----------------------------------------------
 */

#define RI_BASE_REG                 0x04700000
#define RI_BASE_SIZE                (sizeof(RI_RegSet))
#define RI_BASE_END                 (RI_BASE_REG + (RI_BASE_SIZE - 1))

#define RI_MODE_REG                 0x00
#define RI_CONFIG_REG               0x04
#define RI_CURRENT_LOAD_REG         0x08
#define RI_SELECT_REG               0x0C
#define RI_REFRESH_REG              0x10
#define RI_COUNT_REG                RI_REFRESH_REG
#define RI_LATENCY_REG              0x14
#define RI_RERROR_REG               0x18
#define RI_WERROR_REG               0x1C

typedef struct
{
    ulong mode;                 // RI mode       (R/W): [1:0] operating mode, [2] stop T active, [3] stop R active
    ulong config;               // RI config     (R/W): [5:0] current control input, [6] current control enable
    ulong current_load;         // RI current load (W): [] any write updates current control register
    ulong select;               // RI select     (R/W): [2:0] receive select, [2:0] transmit select

    ulong refresh;              // RI refresh    (R/W): [7:0] clean refresh delay, [15:8] dirty refresh delay,
                                //                      [16] refresh bank, [17] refresh enable [18] refresh optimize

    ulong latency;              // RI latency    (R/W): [3:0] DMA latency/overlap
    ulong rerror;               // RI error        (R): [0] nack error, [1] ack error
    ulong werror;               // RI error        (W): [] any write clears all error bits
} RI_RegSet;                        // 0470_0000 -> 0470_001F

/*
 *  ------------------------------------[ Serial Interface Register structure ]-----------------------------------------------
 */

#define SI_BASE_REG                 0x04800000
#define SI_BASE_SIZE                (sizeof(SI_RegSet))
#define SI_BASE_END                 (SI_BASE_REG + (SI_BASE_SIZE - 1))

#define SI_DRAM_ADDR_REG            0x00        // R0: DRAM address
#define SI_PIF_ADDR_RD64B_REG       0x04        // R1: 64B PIF->DRAM
#define SI_PIF_ADDR_WR64B_REG       0x10        // R4: 64B DRAM->PIF
#define SI_STATUS_REG               0x18        // R6: Status

// SI status register has the following bits active:
//  0:   DMA busy       - set when DMA is in progress
//  1:   IO busy        - set when IO access is in progress
//  3:   DMA error      - set when there are overlapping DMA requests
// 12:   Interrupt      - Interrupt set
#define SI_STATUS_DMA_BUSY          0x0001
#define SI_STATUS_RD_BUSY           0x0002
#define SI_STATUS_DMA_ERROR         0x0008
#define SI_STATUS_INTERRUPT         0x1000

typedef struct
{
    ulong dram_addr;            // SI DRAM address    (R/W): [23:0] starting RDRAM address   
    ulong pif_addr_rd64b;       // SI address read 64B  (W): [] any write causes a 64B DMA write
    ulong reserved1;
    ulong reserved2;
    ulong pif_addr_wr64b;       // SI address write 64B (W): [] any write causes a 64B DMA read
    ulong reserved3;
    ulong status;               // SI status (W): [] any write clears interrupt
                                //           (R): [0] DMA busy, [1] IO read busy, [2] reserved, [3] DMA error, [12] interrupt
} SI_RegSet;                        // 0480_0000 -> 0480_001B

/*
 *  -----------------------------------------------[ PIF ROM structure ]---------------------------------------------------
 */

#define PIF_ROM_BASE_REG            0x1FC00000
#define PIF_ROM_BASE_END            0x1FC007BF
#define PIF_ROM_BASE_SIZE           ((PIF_ROM_BASE_END - PIF_ROM_BASE_REG) + 1)

/*
 *  -----------------------------------------------[ PIF RAM structure ]---------------------------------------------------
 */

#define PIF_RAM_BASE_REG            0x1FC007C0
#define PIF_RAM_BASE_END            0x1FC007FF
#define PIF_RAM_BASE_SIZE           ((PIF_RAM_BASE_END - PIF_RAM_BASE_REG) + 1)

/*
 *  ---------------------------------------------[ LEO (DD64) structure ]--------------------------------------------------
 */

#define LEO_BASE_REG                0x05000508
#define LEO_BASE_END                0x0500050B
#define LEO_BASE_SIZE               ((LEO_BASE_END - LEO_BASE_REG) + 1)

#define LEO_NOTEXIST_REG            0x00

typedef struct
{
    ulong not_exist;            // Leo exists == 0, Leo doesn't exist != 0
} LEO_RegSet;                       // 0500_0508 -> 0500_050B

/*
 *  ---------------------------------------[ Cartridge DOMAIN 1 structure ]------------------------------------------------
 */

#define CART1DOM_BASE				0x10000000
#define CART1DOM_SIZE				0x01000000		// 16Mbyte/128Mbit

//=========================================================================================================================

// Lowest and highest addresses that are considered MMIO related.
#define MMIO_LOWEST_ADDR			RDRAM_BASE_REG
#define MMIO_HIGHEST_ADDR			SI_BASE_END

#define NUM_MEMMAPS         24

typedef struct
{
    LPVOID ptr;                         // Pointer in Windows memory where this block is stored.
    ulong start_addr;                   // Starting address in N64 where this block exists.
    ulong end_addr;                     // Ending address in N64 where this block exists.

    // Read function to call with offset when memory is read at an address in this block.
    void  (*read_func)(void);

    // Write function to call with offset when memory is written to at an address in this block.
    void  (*write_func)(void);
} MemMapDef;

extern bool in_MemCopy, in_MemSet;
extern ulong MemCopy_dest, MemSet_dest;

void InitEmulation(void);
void MemoryCopy(ulong dest_addr, ulong src_addr, ulong len);
void MemorySet(ulong dest_addr, uchar val, ulong len);
void AddMemoryPtr(LPVOID ptr, ulong start, ulong end, void (*rd)(void), void (*wr)(void), bool zero);
void AddMemoryPtrToTop(LPVOID ptr, ulong start, ulong end, void (*rd)(void), void (*wr)(void), bool zero);
void OptimizeMemoryMap(void);
LPVOID FindMemoryPtr(ulong addr);

typedef struct
{
	ulong PC;
	ulong call;
} CallStackDef;

// ---------------------------------------------------------------------------------
//
//                                Exception Prototypes
//
// ---------------------------------------------------------------------------------

#define EXCEPTION_INTERRUPT					0
#define EXCEPTION_TLB_MODIFICATION			1
#define EXCEPTION_TLB_LOAD					2
#define EXCEPTION_TLB_STORE					3
#define EXCEPTION_ADDRESS_LOAD				4
#define EXCEPTION_ADDRESS_STORE				5
#define EXCEPTION_BUS_ERROR_FETCH			6
#define EXCEPTION_BUS_ERROR_REF				7
#define EXCEPTION_SYSCALL					8
#define EXCEPTION_BREAK_POINT				9
#define EXCEPTION_RESERVED_INSTRUCTION		10
#define EXCEPTION_COPROCESSOR_UNUSABLE		11
#define EXCEPTION_ARITHMETIC_OVERFLOW		12
#define EXCEPTION_TRAP						13
#define EXCEPTION_VIRTUAL_COHERENCY_INST	14
#define EXCEPTION_FLOATING_POINT			15
#define EXCEPTION_WATCH						23
#define EXCEPTION_VIRTUAL_COHERENCY_DATA	31

void GenerateException(int ex_ty);

// ---------------------------------------------------------------------------------
//
//                                  Opcode Prototypes
//
// ---------------------------------------------------------------------------------

void P_SpecialOpcode(char *buf);
void P_REGIMMOpcode(char *buf);
void P_UnknownOpcode(char *buf);
void P_Reserved(char *buf);
void P_COP0_Unknown(char *buf);
void P_COP1_Unknown(char *buf);
void P_COP2_Unknown(char *buf);

// Standard Opcodes...
void P_J(char *buf);
void P_JAL(char *buf);
void P_BEQ(char *buf);
void P_BNE(char *buf);
void P_BLEZ(char *buf);
void P_BGTZ(char *buf);
void P_ADDI(char *buf);
void P_ADDIU(char *buf);
void P_SLTI(char *buf);
void P_SLTIU(char *buf);
void P_ANDI(char *buf);
void P_ORI(char *buf);
void P_XORI(char *buf);
void P_LUI(char *buf);
void P_COP0(char *buf);
void P_COP1(char *buf);
void P_COP2(char *buf);
void P_BEQL(char *buf);
void P_BNEL(char *buf);
void P_BLEZL(char *buf);
void P_BGTZL(char *buf);
void P_DADDI(char *buf);
void P_DADDIU(char *buf);
void P_LDL(char *buf);
void P_LDR(char *buf);
void P_LB(char *buf);
void P_LH(char *buf);
void P_LWL(char *buf);
void P_LW(char *buf);
void P_LBU(char *buf);
void P_LHU(char *buf);
void P_LWR(char *buf);
void P_LWU(char *buf);
void P_SB(char *buf);
void P_SH(char *buf);
void P_SWL(char *buf);
void P_SW(char *buf);
void P_SDL(char *buf);
void P_SDR(char *buf);
void P_SWR(char *buf);
void P_CACHE(char *buf);
void P_LL(char *buf);
void P_LWC1(char *buf);
void P_LWC2(char *buf);
void P_PREF(char *buf);
void P_LLD(char *buf);
void P_LDC1(char *buf);
void P_LDC2(char *buf);
void P_LD(char *buf);
void P_SC(char *buf);
void P_SWC1(char *buf);
void P_SWC2(char *buf);
void P_SCD(char *buf);
void P_SDC1(char *buf);
void P_SDC2(char *buf);
void P_SD(char *buf);

// Special Opcodes...
void P_SLL(char *buf);
void P_SRL(char *buf);
void P_SRA(char *buf);
void P_SLLV(char *buf);
void P_SRLV(char *buf);
void P_SRAV(char *buf);
void P_JR(char *buf);
void P_JALR(char *buf);
void P_SYSCALL(char *buf);
void P_BREAK(char *buf);
void P_SYNC(char *buf);
void P_MFHI(char *buf);
void P_MTHI(char *buf);
void P_MFLO(char *buf);
void P_MTLO(char *buf);
void P_DSLLV(char *buf);
void P_DSRLV(char *buf);
void P_DSRAV(char *buf);
void P_MULT(char *buf);
void P_MULTU(char *buf);
void P_DIV(char *buf);
void P_DIVU(char *buf);
void P_DMULT(char *buf);
void P_DMULTU(char *buf);
void P_DDIV(char *buf);
void P_DDIVU(char *buf);
void P_ADD(char *buf);
void P_ADDU(char *buf);
void P_SUB(char *buf);
void P_SUBU(char *buf);
void P_AND(char *buf);
void P_OR(char *buf);
void P_XOR(char *buf);
void P_NOR(char *buf);
void P_SLT(char *buf);
void P_SLTU(char *buf);
void P_DADD(char *buf);
void P_DADDU(char *buf);
void P_DSUB(char *buf);
void P_DSUBU(char *buf);
void P_TGE(char *buf);
void P_TGEU(char *buf);
void P_TLT(char *buf);
void P_TLTU(char *buf);
void P_TEQ(char *buf);
void P_TNE(char *buf);
void P_DSLL(char *buf);
void P_DSRL(char *buf);
void P_DSRA(char *buf);
void P_DSLL32(char *buf);
void P_DSRL32(char *buf);
void P_DSRA32(char *buf);

// REGIMM Opcodes...
void P_BLTZ(char *buf);
void P_BGEZ(char *buf);
void P_BLTZL(char *buf);
void P_BGEZL(char *buf);
void P_TGEI(char *buf);
void P_TGEIU(char *buf);
void P_TLTI(char *buf);
void P_TLTIU(char *buf);
void P_TEQI(char *buf);
void P_TNEI(char *buf);
void P_BLTZAL(char *buf);
void P_BGEZAL(char *buf);
void P_BLTZALL(char *buf);
void P_BGEZALL(char *buf);

// COP0 Opcodes...
void P_COP0_Func(char *buf);
void P_MFC0(char *buf);
void P_DMFC0(char *buf);
void P_CFC0(char *buf);
void P_MTC0(char *buf);
void P_DMTC0(char *buf);
void P_CTC0(char *buf);
void P_TLBR(char *buf);
void P_TLBWI(char *buf);
void P_TLBWR(char *buf);
void P_TLBP(char *buf);
void P_ERET(char *buf);

// COP1 Opcodes...
void P_MFC1(char *buf);
void P_CFC1(char *buf);
void P_MTC1(char *buf);
void P_CTC1(char *buf);
void P_COP1_BC(char *buf);
void P_COP1_S(char *buf);
void P_COP1_D(char *buf);
void P_COP1_W(char *buf);
void P_COP1_L(char *buf);
void P_BC1F(char *buf);
void P_BC1T(char *buf);
void P_BC1FL(char *buf);
void P_BC1TL(char *buf);
void P_C1S_ADD(char *buf);
void P_C1S_SUB(char *buf);
void P_C1S_MUL(char *buf);
void P_C1S_DIV(char *buf);
void P_C1S_SQRT(char *buf);
void P_C1S_ABS(char *buf);
void P_C1S_MOV(char *buf);
void P_C1S_NEG(char *buf);
void P_C1S_ROUND_L(char *buf);
void P_C1S_TRUNC_L(char *buf);
void P_C1S_CEIL_L(char *buf);
void P_C1S_FLOOR_L(char *buf);
void P_C1S_ROUND_W(char *buf);
void P_C1S_TRUNC_W(char *buf);
void P_C1S_CEIL_W(char *buf);
void P_C1S_FLOOR_W(char *buf);
void P_C1S_CVT_D(char *buf);
void P_C1S_CVT_W(char *buf);
void P_C1S_CVT_L(char *buf);
void P_C1S_C_F(char *buf);
void P_C1S_C_UN(char *buf);
void P_C1S_C_EQ(char *buf);
void P_C1S_C_UEQ(char *buf);
void P_C1S_C_OLT(char *buf);
void P_C1S_C_ULT(char *buf);
void P_C1S_C_OLE(char *buf);
void P_C1S_C_ULE(char *buf);
void P_C1S_C_SF(char *buf);
void P_C1S_C_NGLE(char *buf);
void P_C1S_C_SEQ(char *buf);
void P_C1S_C_NGL(char *buf);
void P_C1S_C_LT(char *buf);
void P_C1S_C_NGE(char *buf);
void P_C1S_C_LE(char *buf);
void P_C1S_C_NGT(char *buf);
void P_C1D_ADD(char *buf);
void P_C1D_SUB(char *buf);
void P_C1D_MUL(char *buf);
void P_C1D_DIV(char *buf);
void P_C1D_SQRT(char *buf);
void P_C1D_ABS(char *buf);
void P_C1D_MOV(char *buf);
void P_C1D_NEG(char *buf);
void P_C1D_ROUND_L(char *buf);
void P_C1D_TRUNC_L(char *buf);
void P_C1D_CEIL_L(char *buf);
void P_C1D_FLOOR_L(char *buf);
void P_C1D_ROUND_W(char *buf);
void P_C1D_TRUNC_W(char *buf);
void P_C1D_CEIL_W(char *buf);
void P_C1D_FLOOR_W(char *buf);
void P_C1D_CVT_S(char *buf);
void P_C1D_CVT_W(char *buf);
void P_C1D_CVT_L(char *buf);
void P_C1D_C_F(char *buf);
void P_C1D_C_UN(char *buf);
void P_C1D_C_EQ(char *buf);
void P_C1D_C_UEQ(char *buf);
void P_C1D_C_OLT(char *buf);
void P_C1D_C_ULT(char *buf);
void P_C1D_C_OLE(char *buf);
void P_C1D_C_ULE(char *buf);
void P_C1D_C_SF(char *buf);
void P_C1D_C_NGLE(char *buf);
void P_C1D_C_SEQ(char *buf);
void P_C1D_C_NGL(char *buf);
void P_C1D_C_LT(char *buf);
void P_C1D_C_NGE(char *buf);
void P_C1D_C_LE(char *buf);
void P_C1D_C_NGT(char *buf);
void P_C1W_CVT_S(char *buf);
void P_C1W_CVT_D(char *buf);
void P_C1L_CVT_S(char *buf);
void P_C1L_CVT_D(char *buf);


// ---------------------------------------------------------------------------------
//
//                         Opcode Look-up Tables/Structures
//
// ---------------------------------------------------------------------------------

#ifdef NO_EXTERN

char *GPR_LUT[32] = {
    "R0", "AT", "V0", "V1", "A0", "A1", "A2", "A3",
    "T0", "T1", "T2", "T3", "T4", "T5", "T6", "T7",
    "S0", "S1", "S2", "S3", "S4", "S5", "S6", "S7",
    "T8", "T9", "K0", "K1", "GP", "SP", "S8", "RA"
};

char *FGR_LUT[32] = {
    "F0",  "F1",  "F2",  "F3",  "F4",  "F5",  "F6",  "F7",
    "F8",  "F9",  "F10", "F11", "F12", "F13", "F14", "F15",
    "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23",
    "F24", "F25", "F26", "F27", "F28", "F29", "F30", "F31"
};

char *COP0_LUT[32] = {
    "Index",    "Random", "EntryLo0", "EntryLo1", "Context",  "PageMask", "Wired",    "r7",
    "BadVAddr", "Count",  "EntryHi",  "Compare",  "Status",   "Cause",    "ExceptPC", "PRevID",
    "Config",   "LLAddr", "WatchLo",  "WatchHi",  "XContext", "r21",      "r22",      "r23",
    "r24",      "r25",    "PErr",     "CacheErr", "TagLo",    "TagHi",    "ErrorEPC", "r31"
};

char *COP1_LUT[32] = {
    "Impl_Rev", "fp1",  "fp2",  "fp3",  "fp4",  "fp5",  "fp6",  "fp7",
    "fp8",      "fp9",  "fp10", "fp11", "fp12", "fp13", "fp14", "fp15",
    "fp16",     "fp17", "fp18", "fp19", "fp20", "fp21", "fp22", "fp23",
    "fp24",     "fp25", "fp26", "fp27", "fp28", "fp29", "fp30", "FCSR"
};

char *RSP_LUT[32] = {
	"sp_mem_addr", "sp_dram_addr", "sp_rd_len",   "sp_wr_len",  "sp_status", "sp_dma_full", "sp_dma_busy",  "sp_semaphore",
	"dpc_start",   "dpc_end",      "dpc_current", "dpc_status", "dpc_clock", "dpc_bufbusy", "dpc_pipebusy", "dpc_tmem",
	"rsp16",       "rsp17",        "rsp18",       "rsp19",      "rsp20",     "rsp21",       "rsp22",        "rsp23",
	"rsp24",       "rsp25",        "rsp26",       "rsp27",      "rsp28",     "rsp29",       "rsp30",        "rsp31"
};

char *COP2_LUT[32] = {
	"$v0",  "$v1",  "$v2",  "$v3",  "$v4",  "$v5",  "$v6",  "$v7",
	"$v8",  "$v9",  "$v10", "$v11", "$v12", "$v13", "$v14", "$v15",
	"$v16", "$v17", "$v18", "$v19", "$v20", "$v21", "$v22", "$v23",
	"$v24", "$v25", "$v26", "$v27", "$v28", "$v29", "$v30", "$v31"
};

void (*OpcodePrintTable[64])(char *buf) = {
    P_SpecialOpcode, P_REGIMMOpcode, P_J,    P_JAL,      P_BEQ,  P_BNE,  P_BLEZ,  P_BGTZ,
    P_ADDI,          P_ADDIU,        P_SLTI, P_SLTIU,    P_ANDI, P_ORI,  P_XORI,  P_LUI,
    P_COP0,          P_COP1,         P_COP2, P_Reserved, P_BEQL, P_BNEL, P_BLEZL, P_BGTZL,
    P_DADDI,         P_DADDIU,       P_LDL,  P_LDR,      P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode,
    P_LB,            P_LH,           P_LWL,  P_LW,       P_LBU,  P_LHU,  P_LWR,   P_LWU,
    P_SB,            P_SH,           P_SWL,  P_SW,       P_SDL,  P_SDR,  P_SWR,   P_CACHE,
    P_LL,            P_LWC1,         P_LWC2, P_PREF,     P_LLD,  P_LDC1, P_LDC2,  P_LD,
    P_SC,            P_SWC1,         P_SWC2, P_Reserved, P_SCD,  P_SDC1, P_SDC2,  P_SD
};

void (*SpecialPrintTable[64])(char *buf) = {
    P_SLL,           P_UnknownOpcode, P_SRL,           P_SRA,           P_SLLV,    P_UnknownOpcode, P_SRLV,          P_SRAV,
    P_JR,            P_JALR,          P_UnknownOpcode, P_UnknownOpcode, P_SYSCALL, P_BREAK,         P_UnknownOpcode, P_SYNC,
    P_MFHI,          P_MTHI,          P_MFLO,          P_MTLO,          P_DSLLV,   P_UnknownOpcode, P_DSRLV,         P_DSRAV,
    P_MULT,          P_MULTU,         P_DIV,           P_DIVU,          P_DMULT,   P_DMULTU,        P_DDIV,          P_DDIVU,
    P_ADD,           P_ADDU,          P_SUB,           P_SUBU,          P_AND,     P_OR,            P_XOR,           P_NOR,
    P_UnknownOpcode, P_UnknownOpcode, P_SLT,           P_SLTU,          P_DADD,    P_DADDU,         P_DSUB,          P_DSUBU,
    P_TGE,           P_TGEU,          P_TLT,           P_TLTU,          P_TEQ,     P_UnknownOpcode, P_TNE,           P_UnknownOpcode,
    P_DSLL,          P_UnknownOpcode, P_DSRL,          P_DSRA,          P_DSLL32,  P_UnknownOpcode, P_DSRL32,        P_DSRA32
};

void (*REGIMMPrintTable[32])(char *buf) = {
    P_BLTZ,   P_BGEZ,   P_BLTZL,   P_BGEZL,   P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode,
    P_TGEI,   P_TGEIU,  P_TLTI,    P_TLTIU,   P_TEQI,          P_UnknownOpcode, P_TNEI,          P_UnknownOpcode,
    P_BLTZAL, P_BGEZAL, P_BLTZALL, P_BGEZALL, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode,
    P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode, P_UnknownOpcode
};

void (*COP0PrintTable[32])(char *buf) = {
    P_MFC0,         P_DMFC0, P_CFC0, P_COP0_Unknown, P_MTC0, P_DMTC0, P_CTC0, P_COP0_Unknown,
    P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown,
    P_COP0_Func,    P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown,
    P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown
};

void (*COP0PrintFunc[64])(char *buf) = {
    P_COP0_Unknown, P_TLBR, P_TLBWI, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_TLBWR, P_COP0_Unknown,
    P_TLBP,         P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown,
    P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown,
    P_ERET,         P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown,
    P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown,
    P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown,
    P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown,
    P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown, P_COP0_Unknown
};

void (*COP1PrintTable[32])(char *buf) = {
    P_MFC1,         P_COP1_Unknown, P_CFC1,         P_COP1_Unknown, P_MTC1,         P_COP1_Unknown, P_CTC1,         P_COP1_Unknown,
    P_COP1_BC,      P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_S,       P_COP1_D,       P_COP1_Unknown, P_COP1_Unknown, P_COP1_W,       P_COP1_L,       P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown
};

void (*COP1BCPrintTable[4])(char *buf) = {
    P_BC1F,  P_BC1T,
    P_BC1FL, P_BC1TL
};

void (*COP1SPrintTable[64])(char *buf) = {
    P_C1S_ADD,      P_C1S_SUB,      P_C1S_MUL,      P_C1S_DIV,      P_C1S_SQRT,     P_C1S_ABS,      P_C1S_MOV,      P_C1S_NEG,
    P_C1S_ROUND_L,  P_C1S_TRUNC_L,  P_C1S_CEIL_L,   P_C1S_FLOOR_L,  P_C1S_ROUND_W,  P_C1S_TRUNC_W,  P_C1S_CEIL_W,   P_C1S_FLOOR_W,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_C1S_CVT_D,    P_COP1_Unknown, P_COP1_Unknown, P_C1S_CVT_W,    P_C1S_CVT_L,    P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_C1S_C_F,      P_C1S_C_UN,     P_C1S_C_EQ,     P_C1S_C_UEQ,    P_C1S_C_OLT,    P_C1S_C_ULT,    P_C1S_C_OLE,    P_C1S_C_ULE,
    P_C1S_C_SF,     P_C1S_C_NGLE,   P_C1S_C_SEQ,    P_C1S_C_NGL,    P_C1S_C_LT,     P_C1S_C_NGE,    P_C1S_C_LE,     P_C1S_C_NGT
};

void (*COP1DPrintTable[64])(char *buf) = {
    P_C1D_ADD,      P_C1D_SUB,      P_C1D_MUL,      P_C1D_DIV,      P_C1D_SQRT,     P_C1D_ABS,      P_C1D_MOV,      P_C1D_NEG,
    P_C1D_ROUND_L,  P_C1D_TRUNC_L,  P_C1D_CEIL_L,   P_C1D_FLOOR_L,  P_C1D_ROUND_W,  P_C1D_TRUNC_W,  P_C1D_CEIL_W,   P_C1D_FLOOR_W,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_C1D_CVT_S,    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_C1D_CVT_W,    P_C1D_CVT_L,    P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_C1D_C_F,      P_C1D_C_UN,     P_C1D_C_EQ,     P_C1D_C_UEQ,    P_C1D_C_OLT,    P_C1D_C_ULT,    P_C1D_C_OLE,    P_C1D_C_ULE,
    P_C1D_C_SF,     P_C1D_C_NGLE,   P_C1D_C_SEQ,    P_C1D_C_NGL,    P_C1D_C_LT,     P_C1D_C_NGE,    P_C1D_C_LE,     P_C1D_C_NGT
};

void (*COP1WPrintTable[64])(char *buf) = {
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_C1W_CVT_S,    P_C1W_CVT_D,    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown
};

void (*COP1LPrintTable[64])(char *buf) = {
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_C1L_CVT_S,    P_C1L_CVT_D,    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown,
    P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown, P_COP1_Unknown
};

#else

extern char *GPR_LUT[32];
extern char *FGR_LUT[32];
extern char *COP0_LUT[32];
extern char *COP1_LUT[32];
extern char *RSP_LUT[32];
extern char *COP2_LUT[32];

extern void (*OpcodePrintTable[64])(char *buf);
extern void (*SpecialPrintTable[64])(char *buf);
extern void (*REGIMMPrintTable[32])(char *buf);
extern void (*COP0PrintTable[32])(char *buf);
extern void (*COP0PrintFunc[64])(char *buf);
extern void (*COP1PrintTable[32])(char *buf);
extern void (*COP1BCPrintTable[4])(char *buf);
extern void (*COP1SPrintTable[64])(char *buf);
extern void (*COP1DPrintTable[64])(char *buf);
extern void (*COP1WPrintTable[64])(char *buf);
extern void (*COP1LPrintTable[64])(char *buf);

#endif

#pragma pack()

#endif
