/**
 * TrueReality - N64/memory.c
 * Copyright (C) 1998, 1999 Niki W. Waibel
 *
 * This program is free software; you can redistribute it and/
 * or modify it under the terms of the GNU General Public Li-
 * cence as published by the Free Software Foundation; either
 * version 2 of the Licence, or any later version.
 *
 * This program is distributed in the hope that it will be use-
 * ful, but WITHOUT ANY WARRANTY; without even the implied war-
 * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public Licence for more details.
 *
 * You should have received a copy of the GNU General Public
 * Licence along with this program; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 * USA.
 *
 * Information about me (the author):
 *   Niki W. Waibel, Reichenau 20, 6890 Lustenau, Austria - EUROPE
 *   niki.waibel@gmx.net
**/





/*****************************************************************************/
/* include section                                                           */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <config.h>
#include <parser_extern.h>
#include <file_loader_extern.h>
#include <dispatch.h>
#include <type_sizes.h>
#include <memory_extern.h>
#include <ansi_esc_codes.h>

#include "registers.h"
#include "rsp_registers.h"
#include "rdp.h"
#include "exceptions.h"
#include "interrupts.h"
#include "dma.h"
#include "memory.h"

#ifdef DEBUG
        #include <debug.h>
#endif

#ifdef SHM
#       include <sys/types.h>
#       include <sys/ipc.h>
#       include <sys/shm.h>
#       include <X11/Xlib.h>
#       include <X11/extensions/XShm.h>
#endif



/*****************************************************************************/
/* define section                                                            */

        /* for mem_todo */
#define DO_NOTHING              0x0000
#define DO_DISPLAY_REFRESH      0x0001
#define DO_RUN_RDP              0x0002
#define UPDATE_MI_REG           0x0004
#define UPDATE_VI_REG           0x0008
#define UPDATE_PI_REG           0x0010
#define UPDATE_SP_REG           0x0020
#define UPDATE_DP_REG           0x0040
#define CHECK_VI_REG            0x0080
#define CHECK_AI_REG            0x0100
#define PI_DMA                  0x0200
#define PIF2DRAM_DMA            0x0400
#define DRAM2PIF_DMA            0x0800
#define IDMEM2DRAM_DMA          0x1000
#define DRAM2IDMEM_DMA          0x2000

        /* for making code nicer */
#ifdef DEBUG
        #define print_debug_msg(dbg_func, r_w)                                                  \
                if( (dbg_func) )                                                                \
                {                                                                               \
                        printf("DEBUG MEM: [pc]=%08lx [count]=%016llx vaddr=%08lx (%s)\n",      \
                               reg.pc,                                                          \
                               reg.cpr[0][9],                                                   \
                               virtualaddr,                                                     \
                               r_w);                                                            \
                }
#else
        #define print_debug_msg(dbg_func, r_w)
#endif

        /* for speed reasons ( inline :) ) */
#define final_check()                           \
        if(mem_todo)                            \
        {                                       \
                if(mem_todo & DO_DISPLAY_REFRESH) \
                        do_display_refresh();   \
                if(mem_todo & DO_RUN_RDP)       \
                        rdp_go();               \
                if(mem_todo & UPDATE_VI_REG)    \
                        update_vi_reg();        \
                if(mem_todo & CHECK_VI_REG)     \
                        check_vi_reg();         \
                if(mem_todo & CHECK_AI_REG)     \
                        check_ai_reg();         \
                if(mem_todo & UPDATE_MI_REG)    \
                        update_mi_reg();        \
                if(mem_todo & UPDATE_PI_REG)    \
                        update_pi_reg();        \
                if(mem_todo & UPDATE_SP_REG)    \
                        update_sp_reg();        \
                if(mem_todo & UPDATE_DP_REG)    \
                        update_dp_reg();        \
                if(mem_todo & PI_DMA)           \
                        dma_pi_copy();          \
                if(mem_todo & PIF2DRAM_DMA)     \
                        dma_pif2dram();         \
                if(mem_todo & DRAM2PIF_DMA)     \
                        dma_dram2pif();         \
                if(mem_todo & IDMEM2DRAM_DMA)   \
                        dma_idmem2dram();       \
                if(mem_todo & DRAM2IDMEM_DMA)   \
                        dma_dram2idmem();       \
        }                                       \
        mem_todo = DO_NOTHING;



/*****************************************************************************/
/* extern section                                                            */

struct  tr_rom  rom;
struct  tr_mem  mem;
#ifdef SHM
        struct tr_shminfo shminfo;
#endif





/*****************************************************************************/
/* static section                                                            */

        /* routines */
static  char    *phys_read_addr(WORD virtualaddr);
static  char    *phys_write_addr(WORD virtualaddr);
static  void    write_mem_addr();

static  void    do_display_refresh();
static  void    update_mi_reg();
static  void    update_vi_reg();
static  void    update_pi_reg();
static  void    update_sp_reg();
static  void    update_dp_reg();
static  void    check_vi_reg();
static  void    check_ai_reg();

        /* vars */
static  int     mem_todo;
                /* for check_vi_reg */
static  WORD    old_vi_status_reg;
static  WORD    old_vi_width_reg;
                /* for audio interface */
static  sWORD   ai_addr_len_buffer_full = 0;

/* the followinng define is not in the define section because it is
   VERY important for the next 3 static arrays */

#define N_SEGMENTS 19

static size_t mem_size[N_SEGMENTS] =
{
        4 * 1024 * 1024,        /* rd_ram   */  /*  0 */
        0x1000,                 /* sp_dmem  */  /*  1 */
        0x1000,                 /* sp_imem  */  /*  2 */
        0x7c0,                  /* pi_rom   */  /*  3 */
        0x40,                   /* pi_ram   */  /*  4 */
        0x40,                   /* pi_ram_w */  /*  5 */
        
        1 * 1024 * 1024,        /* rd_reg   */  /*  6 */
        0x20,                   /* sp_reg   */  /*  7 */
        0x20,                   /* dpc_reg  */  /*  8 */
        0x10,                   /* dps_reg  */  /*  9 */
        0x10,                   /* mi_reg   */  /* 10 */
        0x10,                   /* mi_reg_w */  /* 11 */
        0x38,                   /* vi_reg   */  /* 12 */
        0x18,                   /* ai_reg   */  /* 13 */
        0x34,                   /* pi_reg   */  /* 14 */
        0x34,                   /* pi_reg_w */  /* 15 */
        0x20,                   /* ri_reg   */  /* 16 */
        0x1c,                   /* si_reg   */  /* 17 */
        1024                    /* null_mem */  /* 18 */
};

static char *mem_addr[N_SEGMENTS];

#ifdef SHM
        static XShmSegmentInfo mem_shminfo[N_SEGMENTS];
#endif /* SHM */










/*****************************************************************************\
* This is the current implementation of the memory map.                       *
* It is huge but quite fast.                                                  *
* There are 2 routines now. One for READ and one for WRITE.                   *
\*****************************************************************************/

static char *phys_read_addr(WORD virtualaddr)
{
        WORD            vaddr = virtualaddr & 0x1fffffff;
        static sWORD    current_verical_line = -1;





        print_debug_msg(prefs.debug & DBG_MEMORY, "read");

        switch(vaddr & 0x10000000)
        {
            case 0x00000000:
                switch(vaddr & 0x0f000000)
                {
                    case 0x00000000:
                    case 0x01000000:
                    case 0x02000000:
                    case 0x03000000:
                        if(vaddr < 0x00400000)   /* 4MB */
                        {
                                print_debug_msg(prefs.debug & DBG_RD_RAM, "read  - rd ram");
                                return(mem.rd_ram + vaddr);
                        }
                        if(vaddr >= 0x03f00000)
                        {
                                print_debug_msg(prefs.debug & DBG_RD_REG, "read  - rd reg");
                                return(mem.rd_reg + (vaddr & 0x000fffff));
                        }
                        break;

                    case 0x04000000:
                        switch(vaddr & 0x00f00000)
                        {
                            case 0x00000000:                   
                                switch(vaddr & 0x000f0000)
                                {
                                    case 0x00000000:
                                        if(vaddr < 0x04001000)
                                        {
                                                print_debug_msg(prefs.debug & DBG_SP_DMEM, "read  - sp dmem");
                                                return(mem.sp_dmem + (vaddr & 0xfff));
                                        }
                                        if(vaddr < 0x04002000)
                                        {
                                                print_debug_msg(prefs.debug & DBG_SP_IMEM, "read  - sp imem");
                                                return(mem.sp_imem + (vaddr & 0xfff));
                                        }
                                        break;
                                    
                                    case 0x00010000:
                                    case 0x00020000:
                                    case 0x00030000:
                                        break;
                                            
                                    case 0x00040000:
                                        if(vaddr < 0x04040020)
                                        {
                                                print_debug_msg(prefs.debug & DBG_SP_REG, "read  - sp reg");
                                                return(mem.sp_reg + (vaddr & 0xff));
                                        }
                                        break;
                                                    
                                    case 0x00050000:
                                    case 0x00060000:
                                    case 0x00070000:
                                        break;
                                            
                                    case 0x00080000:
                                        if(vaddr < 0x04080004)
                                        {
                                                print_debug_msg(prefs.debug & DBG_SP_PC_REG, "read  - sp pc");
                                                return(((char *)&(mem.sp_reg_pc)) + (vaddr & 0x03));
                                        }
                                        if(vaddr < 0x04080008)
                                        {
                                                print_debug_msg(prefs.debug & DBG_SP_IBIST_REG, "read  - sp ibist");
                                                return(((char *)&(mem.sp_reg_ibist)) + vaddr - 0x04080004);
                                        }
                                        break;
                                    
                                    case 0x00090000:
                                    case 0x000a0000:
                                    case 0x000b0000:
                                    case 0x000c0000:
                                    case 0x000d0000:
                                    case 0x000e0000:
                                    case 0x000f0000:
                                        break;

                                } /* switch(vaddr & 0x000f0000) */
                                break;
                                
                            case 0x00100000:
                                if(vaddr < 0x04100020)
                                {
                                        print_debug_msg(prefs.debug & DBG_DPC_REG, "read  - dpc reg");
                                        return(mem.dpc_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00200000:
                                if(vaddr < 0x04200010)
                                {
                                        print_debug_msg(prefs.debug & DBG_DPS_REG, "read  - dps reg");
                                        return(mem.dps_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00300000:
                                if(vaddr < 0x04300010)
                                {
                                        print_debug_msg(prefs.debug & DBG_MI_REG, "read  - mi reg");
                                        return(mem.mi_reg + (vaddr & 0xf));
                                }
                                break;
                            
                            case 0x00400000:
                                if(vaddr < 0x04400038)
                                {
                                        print_debug_msg(prefs.debug & DBG_VI_REG, "read  - vi reg");

                                        switch(vaddr & 0xff)
                                        {
                                            case 0x10:
                                            case 0x11:
                                            case 0x12:
                                            case 0x13:
                                                if(current_verical_line < 512)
                                                        current_verical_line += 2;
                                                else
                                                        current_verical_line = 0;
                                                        
                                                return(((char *)&current_verical_line) + (vaddr & 0x03));
                                                
                                        } /* switch(vaddr & 0xff) */
                                        
                                        return(mem.vi_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00500000:
                                if(vaddr < 0x04500018)
                                {
                                        print_debug_msg(prefs.debug & DBG_AI_REG, "read  - ai reg");

                                        switch(vaddr & 0xff)
                                        {
                                            case 0x00:   /* AI_DRAM_ADDR_REG */
                                            case 0x01:
                                            case 0x02:
                                            case 0x03:
                                                break;
                                            
                                            case 0x04:   /* AI_LEN_REG */
                                            case 0x05:
                                            case 0x06:
                                            case 0x07:
                                                break;
                                            
                                            case 0x08:   /* AI_CONTROL_REG */
                                            case 0x09:
                                            case 0x0a:
                                            case 0x0b:
                                                break;

                                            case 0x0c:   /* AI_STATUS_REG */
                                            case 0x0d:
                                            case 0x0e:
                                            case 0x0f:
/*
                                                if(dispatch(AUDIO_READY, 0))
                                                {
                                                        puts("AUDIO READY"); fflush(stdout);
                                                        ((WORD *)mem.ai_reg)[3] = 0x00000000;
                                                }
                                                else
                                                {
                                                        puts("AUDIO NOT READY"); fflush(stdout);
                                                        ((WORD *)mem.ai_reg)[3] = 0xc0000001;
                                                }
*/
                                                if(ai_addr_len_buffer_full == 2)
                                                        ((WORD *)mem.ai_reg)[3] = 0x80000000;
                                                else
                                                        ((WORD *)mem.ai_reg)[3] = 0x00000000;

                                                if(ai_addr_len_buffer_full == 3)
                                                        ai_addr_len_buffer_full = 0;

                                                /* ??? bit 0 ??? */
        
                                                break;

                                            case 0x10:   /* AI_DACRATE_REG */
                                            case 0x11:
                                            case 0x12:
                                            case 0x13:
                                                break;

                                            case 0x14:   /* AI_BITRATE_REG */
                                            case 0x15:
                                            case 0x16:
                                            case 0x17:
                                                break;
                                                
                                        } /* switch(vaddr & 0xff) */
                                            
                                        return(mem.ai_reg + (vaddr & 0xff));

                                }
                                break;
                            
                            case 0x00600000:
                                if(vaddr < 0x04600034)
                                {
                                        print_debug_msg(prefs.debug & DBG_PI_REG, "read  - pi reg");
                                        return(mem.pi_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00700000:
                                if(vaddr < 0x04700020)
                                {
                                        print_debug_msg(prefs.debug & DBG_RI_REG, "read  - ri reg");
                                        return(mem.ri_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00800000:
                                if(vaddr < 0x0480001c)
                                {
                                        print_debug_msg(prefs.debug & DBG_SI_REG, "read  - si reg");
                                        return(mem.si_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00900000:
                            case 0x00a00000:
                            case 0x00b00000:
                            case 0x00c00000:
                            case 0x00d00000:
                            case 0x00e00000:
                            case 0x00f00000:
                                break;
                                    
                        } /* switch(vaddr & 0x00f00000) */
                        break;
                            
                    case 0x05000000:                                /* PI_DOM2_ADDR1 */
/*
                        if(vaddr < (0x05000000 + rom.length))
                        {
                                print_debug_msg(prefs.debug & DBG_PI_DOM2_ADDR1, "read");
                                return(rom.image + (vaddr & 0xffffff));
                        }
                        break;
*/

/*
        BUG: ????

        PONG reads a word from 0xa5000508.
        ANDI with 0xffff.
        Then PONG checks if that value is 0.
        If yes, everything is like in PUR03A.
        If not ... BUG?

        So I'll return zeros.
        It seems that PUR03A does not support PI_DOM2_ADDR1.
        In its memory debugger it marks all addresses with an *.
        EXCEPT addr 0xa5000508!!!!!!!!!!!.
        There are 4 bytes containing '0'.

        In this implementation of the memory map all bytes in DEBUG_PI_DOM2_ADDR1 contain '0'.
        Writing to this portion of mem does nothing - mem is always '0'!
*/

                        ((DWORD *)(mem.null_mem))[0] = 0;
                        return(mem.null_mem);
                    
                    case 0x06000000:                                /* PI_DOM1_ADDR1 */
                    case 0x07000000:
                        if(vaddr < (0x06000000 + rom.length))
                        {
                                print_debug_msg(prefs.debug & DBG_PI_DOM1_ADDR1, "read");
                                return(rom.image + vaddr - 0x06000000);
                        }
                        break;
                    
                    case 0x08000000:                                /* PI_DOM2_ADDR2 */
                    case 0x09000000:
                    case 0x0a000000:
                    case 0x0b000000:
                    case 0x0c000000:
                    case 0x0d000000:
                    case 0x0e000000:
                    case 0x0f000000:
                        if(vaddr < (0x08000000 + rom.length))
                        {
                                print_debug_msg(prefs.debug & DBG_PI_DOM2_ADDR2, "read");
                                return(rom.image + vaddr - 0x08000000);
                        }
                        break;
                            
                } /* switch(vaddr & 0x0f000000) */
                break;
                
            case 0x10000000:
                if(vaddr < 0x1fc00000)                                  /* PI_DOM1_ADDR2 */
                {
                        if(vaddr < (0x10000000 + rom.length))
                        {
                                print_debug_msg(prefs.debug & DBG_PI_DOM1_ADDR2, "read");
                                return(rom.image + (vaddr & 0xfffffff));
                        }
                        break;
                }
                
                if(vaddr < 0x1fc007c0)                                         /* PI ROM */
                {
                        print_debug_msg(prefs.debug & DBG_PI_ROM, "read");
                        return(mem.pi_rom + (vaddr & 0xfff));
                }
                    
                if(vaddr < 0x1fc00800)                                         /* PI RAM */
                {
                        print_debug_msg(prefs.debug & DBG_PI_RAM, "read");
                        return(mem.pi_ram + vaddr - 0x1fc007c0);
                }
                
                if(vaddr < 0x1fd00000)                                            /* ??? */
                        break;
                
                if(vaddr < (0x1fd00000 + rom.length))                   /* PI_DOM1_ADDR3 */
                {
                        print_debug_msg(prefs.debug & DBG_PI_DOM1_ADDR3, "read");
                        return(rom.image + vaddr - 0x1fd00000);
                }
                break;
                
        } /* switch(vaddr & 0x10000000) */



        fprintf(stderr, "phys_read_addr: No memory at position: %08lx\n"
                        "    cpr[0][COUNT] = %016llx\n"
                        "               PC = %08lx\n\n", virtualaddr, reg.cpr[0][COUNT], reg.pc);

#ifdef HALT
        reg.halt = 1;
#endif

        return(mem.null_mem);

} /* ststic char *phys_read_addr(WORD vaddr) */





static char *phys_write_addr(WORD virtualaddr)
{
        WORD vaddr = virtualaddr & 0x1fffffff;
        




        print_debug_msg(prefs.debug & DBG_MEMORY, "write");
   

   
        vaddr = vaddr & 0x1fffffff;

        switch(vaddr & 0x10000000)
        {
            case 0x00000000:
                switch(vaddr & 0x0f000000)
                {
                    case 0x00000000:
                    case 0x01000000:
                    case 0x02000000:
                    case 0x03000000:
                        if(vaddr < 0x00400000)   /* 4MB */
                        {
                                print_debug_msg(prefs.debug & DBG_RD_RAM, "write - rd ram");
                                return(mem.rd_ram + vaddr);
                        }
                        if(vaddr >= 0x03f00000)
                        {
                                print_debug_msg(prefs.debug & DBG_RD_REG, "write - rd reg");
                                return(mem.rd_reg + (vaddr & 0x000fffff));
                        }
                        break;

                    case 0x04000000:
                        switch(vaddr & 0x00f00000)
                        {
                            case 0x00000000:
                                switch(vaddr & 0x000f0000)
                                {
                                    case 0x00000000:
                                        if(vaddr < 0x04001000)
                                        {
                                                print_debug_msg(prefs.debug & DBG_SP_DMEM, "write - sp dmem");
                                                return(mem.sp_dmem + (vaddr & 0xfff));
                                        }
                                        if(vaddr < 0x04002000)
                                        {
                                                print_debug_msg(prefs.debug & DBG_SP_IMEM, "write - sp imem");
                                                return(mem.sp_imem + (vaddr & 0xfff));
                                        }
                                        break;
                                    
                                    case 0x00010000:
                                    case 0x00020000:
                                    case 0x00030000:
                                        break;
                                            
                                    case 0x00040000:
                                        if(vaddr < 0x04040020)
                                        {
                                                print_debug_msg(prefs.debug & DBG_SP_REG, "write - sp reg");
                                                switch(vaddr & 0xff)
                                                {
                                                    case 0x00:   /* SP_MEM_ADDR_REG */
                                                    case 0x01:
                                                    case 0x02:
                                                    case 0x03:
                                                        break;
                                                    
                                                    case 0x04:   /* SP_DRAM_ADDR_REG */
                                                    case 0x05:
                                                    case 0x06:
                                                    case 0x07:
                                                        break;
                                                    
                                                    case 0x08:   /* SP_RD_LEN_REG */
                                                    case 0x09:
                                                    case 0x0a:
                                                    case 0x0b:
                                                        mem_todo |= DRAM2IDMEM_DMA;
                                                        break;
                                                        
                                                    
                                                    case 0x0c:   /* SP_WR_LEN_REG */
                                                    case 0x0d:
                                                    case 0x0e:
                                                    case 0x0f:
                                                        mem_todo |= IDMEM2DRAM_DMA;
                                                        break;
                                                    
                                                    case 0x10:   /* SP_STATUS_REG */
                                                    case 0x11:
                                                    case 0x12:
                                                    case 0x13:
                                                        mem_todo |= UPDATE_SP_REG;
                                                        return((char *)&(mem.sp_reg_status_w) + (vaddr & 0x3));
                                                    
                                                    case 0x14:   /* SP_DMA_FULL_REG (ro) */
                                                    case 0x15:
                                                    case 0x16:
                                                    case 0x17:
                                                        return(mem.null_mem);
                                                    
                                                    case 0x18:   /* SP_DMA_BUSY_REG (ro) */
                                                    case 0x19:
                                                    case 0x1a:
                                                    case 0x1b:
                                                        return(mem.null_mem);
                                                    
                                                    case 0x1c:   /* SP_SEMAPHORE_REG */
                                                    case 0x1d:
                                                    case 0x1e:
                                                    case 0x1f:
                                                        break;
                                                    
                                                } /* switch(vaddr & 0xff) */

                                                return(mem.sp_reg + (vaddr & 0xff));
                                        }
                                        break;

                                    case 0x00050000:
                                    case 0x00060000:
                                    case 0x00070000:
                                        break;
                                            
                                    case 0x00080000:
                                        if(vaddr < 0x04080004)
                                        {
                                                print_debug_msg(prefs.debug & DBG_SP_PC_REG, "write - sp pc");
                                                return(((char *)&(mem.sp_reg_pc)) + (vaddr & 0x03));
                                        }
                                        if(vaddr < 0x04080008)
                                        {
                                                print_debug_msg(prefs.debug & DBG_SP_IBIST_REG, "write - sp ibist");
                                                return(((char *)&(mem.sp_reg_ibist)) + vaddr - 0x04080004);
                                        }
                                        break;
                                    
                                    case 0x00090000:
                                    case 0x000a0000:
                                    case 0x000b0000:
                                    case 0x000c0000:
                                    case 0x000d0000:
                                    case 0x000e0000:
                                    case 0x000f0000:
                                        break;

                                } /* switch(vaddr & 0x000f0000) */
                                break;
                                
                            case 0x00100000:
                                if(vaddr < 0x04100020)
                                {
                                        print_debug_msg(prefs.debug & DBG_DPC_REG, "write - dpc reg");
                                        switch(vaddr & 0xff)
                                        {
                                            case 0x00:   /* DPC_START_REG */
                                            case 0x01:
                                            case 0x02:
                                            case 0x03:
                                                break;

                                            case 0x04:   /* DPC_END_REG */
                                            case 0x05:
                                            case 0x06:
                                            case 0x07:
                                                mem_todo |= DO_RUN_RDP;
                                                break;

                                            case 0x08:   /* DPC_CURRENT_REG (ro) */
                                            case 0x09:
                                            case 0x0a:
                                            case 0x0b:
                                                return(mem.null_mem);

                                            case 0x0c:   /* DPC_STATUS_REG */
                                            case 0x0d:
                                            case 0x0e:
                                            case 0x0f:
                                                mem_todo |= UPDATE_DP_REG;
                                                return((char *)&(mem.dpc_reg_status_w) + (vaddr & 0x3));

                                            case 0x10:   /* DPC_CLOCK_REG (ro) */
                                            case 0x11:
                                            case 0x12:
                                            case 0x13:
                                                return(mem.null_mem);

                                            case 0x14:   /* DPC_BUFBUSY_REG (ro) */
                                            case 0x15:
                                            case 0x16:
                                            case 0x17:
                                                return(mem.null_mem);

                                            case 0x18:   /* DPC_PIPEBUSY_REG (ro) */
                                            case 0x19:
                                            case 0x1a:
                                            case 0x1b:
                                                return(mem.null_mem);

                                            case 0x1c:   /* DPC_TMEM_REG (ro) */
                                            case 0x1d:
                                            case 0x1e:
                                            case 0x1f:
                                                return(mem.null_mem);

                                        } /* switch(vaddr & 0xff) */

                                        return(mem.dpc_reg + (vaddr & 0xff));
                                }
                                break;

                            case 0x00200000:
                                if(vaddr < 0x04200010)
                                {
                                        print_debug_msg(prefs.debug & DBG_DPS_REG, "write - dps reg");
                                        return(mem.dps_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00300000:
                                if(vaddr < 0x04300010)
                                {
                                        print_debug_msg(prefs.debug & DBG_MI_REG, "write - mi reg");

                                        switch(vaddr & 0xf)
                                        {
                                            case 0x00:   /* MI_MODE_REG */
                                            case 0x01:
                                            case 0x02:
                                            case 0x03:
                                                mem_todo |= UPDATE_MI_REG;
                                                return((char *)&(mem.mi_reg_mode_w) + (vaddr & 0x3));
                                            
                                            case 0x04:   /* MI_VERSION_REG */
                                            case 0x05:
                                            case 0x06:
                                            case 0x07:
                                                return(mem.null_mem);
                                            
                                            case 0x08:   /* MI_INTR_REG */
                                            case 0x09:
                                            case 0x0a:
                                            case 0x0b:
                                                return(mem.null_mem);
                                                
                                            
                                            case 0x0c:   /* MI_INTR_MASK_REG */
                                            case 0x0d:
                                            case 0x0e:
                                            case 0x0f:
                                                mem_todo |= UPDATE_MI_REG;
                                                reg.do_or_check_sthg |= RS4300I_CHECK_MI_INTERRUPTS;
                                                return((char *)&(mem.mi_reg_intr_mask_w) + (vaddr & 0x3));
                                            
                                        } /* switch(vaddr & 0xf) */

                                }
                                break;
                            
                            case 0x00400000:
                                if(vaddr < 0x04400038)
                                {
                                        print_debug_msg(prefs.debug & DBG_VI_REG, "write - vi reg");

                                        switch(vaddr & 0xff)
                                        {
                                            case 0x00:   /* VI_CONTROL_REG */
                                            case 0x01:
                                            case 0x02:
                                            case 0x03:
                                                mem_todo |= CHECK_VI_REG;
                                                break;
                                            
                                            case 0x04:   /* VI_ORIGIN_REG */
                                            case 0x05:
                                            case 0x06:
                                            case 0x07:
                                                mem_todo |= UPDATE_VI_REG;
#if DISPLAY_SUPPORT
                                                mem_todo |= DO_DISPLAY_REFRESH;
#endif
                                                break;
                                            
                                            case 0x08:   /* VI_WIDTH_REG */
                                            case 0x09:
                                            case 0x0a:
                                            case 0x0b:
                                                mem_todo |= UPDATE_VI_REG;
                                                mem_todo |= CHECK_VI_REG;
                                                break;

                                            case 0x0c:   /* VI_INTR_REG */
                                            case 0x0d:
                                            case 0x0e:
                                            case 0x0f:
                                                break;

                                            case 0x10:   /* VI_CURRENT_REG */
                                            case 0x11:
                                            case 0x12:
                                            case 0x13:
#ifndef PUR03A_COMPATIBLE
                                                ((WORD *)mem.mi_reg)[2] &= ~MI_INTR_VI;   /* clr VI int line */
#endif
                                                return(mem.null_mem);

                                            case 0x14:   /* VI_BURST_REG */
                                            case 0x15:
                                            case 0x16:
                                            case 0x17:
                                                break;
                                            
                                            case 0x18:   /* VI_V_SYNC_REG */
                                            case 0x19:
                                            case 0x1a:
                                            case 0x1b:
                                                break;
                                            
                                            case 0x1c:   /* VI_H_SYNC_REG */
                                            case 0x1d:
                                            case 0x1e:
                                            case 0x1f:
                                                break;
                                            
                                            case 0x20:   /* VI_H_SYNC_LEAP_REG */
                                            case 0x21:
                                            case 0x22:
                                            case 0x23:
                                                break;
                                            
                                            case 0x24:   /* VI_H_START_REG */
                                            case 0x25:
                                            case 0x26:
                                            case 0x27:
                                                break;
                                            
                                            case 0x28:   /* VI_V_START_REG */
                                            case 0x29:
                                            case 0x2a:
                                            case 0x2b:
                                                break;
                                            
                                            case 0x2c:   /* VI_V_BURST_REG */
                                            case 0x2d:
                                            case 0x2e:
                                            case 0x2f:
                                                break;
                                            
                                            case 0x30:   /* VI_X_SCALE_REG */
                                            case 0x31:
                                            case 0x32:
                                            case 0x33:
                                                break;
                                            
                                            case 0x34:   /* VI_Y_SCALE_REG */
                                            case 0x35:
                                            case 0x36:
                                            case 0x37:
                                                break;
                                            
                                        } /* switch(vaddr & 0xff) */

                                        return(mem.vi_reg + (vaddr & 0xff));

                                }
                                break;
                            
                            case 0x00500000:
                                if(vaddr < 0x04500018)
                                {
                                        print_debug_msg(prefs.debug & DBG_AI_REG, "write - ai reg");

                                        switch(vaddr & 0xff)
                                        {
                                            case 0x00:   /* AI_DRAM_ADDR_REG */
                                            case 0x01:
                                            case 0x02:
                                            case 0x03:
                                                if(ai_addr_len_buffer_full == 0)
                                                        ai_addr_len_buffer_full = 1;
                                                else if(ai_addr_len_buffer_full == 1)
                                                        ai_addr_len_buffer_full = 1;
                                                break;
                                            
                                            case 0x04:   /* AI_LEN_REG */
                                            case 0x05:
                                            case 0x06:
                                            case 0x07:
                                                if(ai_addr_len_buffer_full == 0)
                                                        ai_addr_len_buffer_full = 0;
                                                else if(ai_addr_len_buffer_full == 1)
                                                        ai_addr_len_buffer_full = 2;
                                                break;
                                            
                                            case 0x08:   /* AI_CONTROL_REG */
                                            case 0x09:
                                            case 0x0a:
                                            case 0x0b:
                                                if(ai_addr_len_buffer_full == 2)
                                                        ai_addr_len_buffer_full = 3;
                                                mem_todo |= CHECK_AI_REG;
                                                break;

                                            case 0x0c:   /* AI_STATUS_REG */
                                            case 0x0d:
                                            case 0x0e:
                                            case 0x0f:
#ifndef PUR03A_COMPATIBLE
                                                ((WORD *)mem.mi_reg)[2] &= ~MI_INTR_AI;   /* clr AI int line */
#endif
                                                return(mem.null_mem);

                                            case 0x10:   /* AI_DACRATE_REG */
                                            case 0x11:
                                            case 0x12:
                                            case 0x13:
                                                break;

                                            case 0x14:   /* AI_BITRATE_REG */
                                            case 0x15:
                                            case 0x16:
                                            case 0x17:
                                                break;
                                                
                                        } /* switch(vaddr & 0xff) */
                                            
                                        return(mem.ai_reg + (vaddr & 0xff));
                                }
                                break;

                            case 0x00600000:
                                if(vaddr < 0x04600034)
                                {
                                        print_debug_msg(prefs.debug & DBG_PI_REG, "write - pi reg");
                                        switch(vaddr & 0xff)
                                        {
                                            case 0x0c:   /* PI_WR_LEN_REG */
                                            case 0x0d:
                                            case 0x0e:
                                            case 0x0f:
                                                mem_todo |= PI_DMA;
                                                break;
                                                
                                            case 0x10:   /* PI_STATUS_REG */
                                            case 0x11:
                                            case 0x12:
                                            case 0x13:
                                                mem_todo |= UPDATE_PI_REG;
                                                return((char *)&(mem.pi_reg_status_w) + (vaddr & 0x3));
                                                
                                        } /* switch(vaddr & 0xff) */

                                        return(mem.pi_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00700000:
                                if(vaddr < 0x04700020)
                                {
                                        print_debug_msg(prefs.debug & DBG_RI_REG, "write - ri reg");
                                        return(mem.ri_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00800000:
                                if(vaddr < 0x0480001c)
                                {
                                        print_debug_msg(prefs.debug & DBG_SI_REG, "write - si reg");
                                        switch(vaddr & 0xff)
                                        {
                                            case 0x00:   /* SI_DRAM_ADDR_REG */
                                            case 0x01:
                                            case 0x02:
                                            case 0x03:
                                                break;
                                 
                                            case 0x04:   /* SI_PIF_ADDR_RD64B_REG */
                                            case 0x05:
                                            case 0x06:
                                            case 0x07:
                                                mem_todo |= PIF2DRAM_DMA;
                                                break;
                                 
                                            case 0x08:   /* reserved */
                                            case 0x09:
                                            case 0x0a:
                                            case 0x0b:
                                                return(mem.null_mem);
                                 
                                            case 0x0c:   /* reserved */
                                            case 0x0d:
                                            case 0x0e:
                                            case 0x0f:
                                                return(mem.null_mem);
                                 
                                            case 0x10:   /* SI_PIF_ADDR_WR64B_REG */
                                            case 0x11:
                                            case 0x12:
                                            case 0x13:
                                                mem_todo |= DRAM2PIF_DMA;
                                                break;
                                 
                                            case 0x14:   /* reserved */
                                            case 0x15:
                                            case 0x16:
                                            case 0x17:
                                                return(mem.null_mem);
                                 
                                            case 0x18:   /* SI_STATUS_REG */
                                            case 0x19:
                                            case 0x1a:
                                            case 0x1b:
                                                ((WORD *)mem.mi_reg)[2] &= ~MI_INTR_SI;   /* clr SI intr in MI reg */
                                                ((WORD *)mem.si_reg)[6] &= ~0x00000001;   /* BUG:? */
                                                return(mem.null_mem);
                                        
                                        } /* switch(vaddr & 0xff) */
                                        
                                        return(mem.si_reg + (vaddr & 0xff));
                                
                                }
                                break;
                            
                            case 0x00900000:
                            case 0x00a00000:
                            case 0x00b00000:
                            case 0x00c00000:
                            case 0x00d00000:
                            case 0x00e00000:
                            case 0x00f00000:
                                break;
                                    
                        } /* switch(vaddr & 0x00f00000) */
                        break;
                            
                    case 0x05000000:                                /* PI_DOM2_ADDR1 */
/*
                        if(vaddr < (0x05000000 + rom.length))
                        {
                                print_debug_msg(prefs.debug & DBG_PI_DOM2_ADDR1, "write");
                                return(rom.image + (vaddr & 0xffffff));
                        }
                        break;
*/

/*
        BUG: ????

        PONG reads a word from 0xa5000508.
        ANDI with 0xffff.
        Then PONG checks if that value is 0.
        If yes, everything is like in PUR03A.
        If not ... BUG?

        So I'll return zeros.
        It seems that PUR03A does not support PI_DOM2_ADDR1.
        In its memory debugger it marks all addresses with an *.
        EXCEPT addr 0xa5000508!!!!!!!!!!!.
        There are 4 bytes containing '0'.

        In this implementation of the memory map all bytes in DEBUG_PI_DOM2_ADDR1 contain '0'.
        Writing to this portion of mem does nothing - mem is always '0'!
*/
                        
                        return(mem.null_mem);
                            
                    case 0x06000000:                                /* PI_DOM1_ADDR1 */
                    case 0x07000000:
                        if(vaddr < (0x06000000 + rom.length))
                        {
                                print_debug_msg(prefs.debug & DBG_PI_DOM1_ADDR1, "write");
                                return(rom.image + vaddr - 0x06000000);
                        }
                        break;
                    
                    case 0x08000000:                                /* PI_DOM2_ADDR2 */
                    case 0x09000000:
                    case 0x0a000000:
                    case 0x0b000000:
                    case 0x0c000000:
                    case 0x0d000000:
                    case 0x0e000000:
                    case 0x0f000000:
                        if(vaddr < (0x08000000 + rom.length))
                        {
                                print_debug_msg(prefs.debug & DBG_PI_DOM2_ADDR2, "write");
                                return(rom.image + vaddr - 0x08000000);
                        }
                        break;
                            
                } /* switch(vaddr & 0x0f000000) */
                break;
                
            case 0x10000000:
                if(vaddr < 0x1fc00000)                                  /* PI_DOM1_ADDR2 */
                {
                        if(vaddr < (0x10000000 + rom.length))
                        {
                                print_debug_msg(prefs.debug & DBG_PI_DOM1_ADDR2, "write");
                                return(rom.image + (vaddr & 0xfffffff));
                        }
                        break;
                }
                
                if(vaddr < 0x1fc007c0)                                         /* PI ROM */
                {
                        print_debug_msg(prefs.debug & DBG_PI_ROM, "write");
                        return(mem.pi_rom + (vaddr & 0xfff));
                }
                    
                if(vaddr < 0x1fc00800)                                         /* PI RAM */
                {
                        print_debug_msg(prefs.debug & DBG_PI_RAM, "write");
                        // BUG: this might be a bug
                        //return(mem.pi_ram_w + vaddr - 0x1fc007c0);
                        return(mem.pi_ram + vaddr - 0x1fc007c0);
                }
                
                if(vaddr < 0x1fd00000)                                            /* ??? */
                        break;
                
                if(vaddr < (0x1fd00000 + rom.length))                   /* PI_DOM1_ADDR3 */
                {
                        print_debug_msg(prefs.debug & DBG_PI_DOM1_ADDR3, "write");
                        return(rom.image + vaddr - 0x1fd00000);
                }
                break;
                
        } /* switch(vaddr & 0x10000000) */



        fprintf(stderr, "phys_write_addr: No memory at position: %08lx\n"
                        "    cpr[0][COUNT] = %016llx\n"
                        "               PC = %08lx\n\n", virtualaddr, reg.cpr[0][COUNT], reg.pc);

#ifdef HALT
        reg.halt = 1;
#endif

        return(mem.null_mem);

} /* static char *phys_write_addr(WORD vaddr) */











/*                                
               else if(addr >= 0x03f80000 && addr < 0x04000000)
               {
                  return(rdram_512K + (vaddr & 0x000fffff));
               }
*/














/*
** The "memory access" routines follow.
** The should be used to read/write the memory.
*/





BYTE doReadMemByte(WORD where)
{
#ifdef ENDIAN_IS_LITTLE
        where ^= 0x03;
#endif

        return(*((BYTE *)phys_read_addr(where)));

} /* BYTE doReadMemByte(WORD where) */





HWORD doReadMemHalfWord(WORD where)
{
#ifdef ENDIAN_IS_LITTLE
        where ^= 0x02;
#endif

        return(*((HWORD *)phys_read_addr(where)));

} /* HWORD doReadMemHalfWord(WORD where) */





WORD doReadMemWord(WORD where)
{
        return(*((WORD *)phys_read_addr(where)));

} /* WORD doReadMemWord(WORD where) */





DWORD doReadMemDoubleWord(WORD where)
{
#ifdef ENDIAN_IS_LITTLE
        DWORD value;
#endif



#ifdef ENDIAN_IS_BIG
        return(*((DWORD *)phys_read_addr(where)));
#endif
#ifdef ENDIAN_IS_LITTLE
        value = *((DWORD *)phys_read_addr(where));
        return( (value >> 32) + (value << 32) );
#endif

} /* DWORD doReadMemDoubleWord(WORD where) */





void doWriteMemByte(BYTE what, WORD where)
{
#ifdef ENDIAN_IS_LITTLE
        where ^= 0x03;
#endif

        *((BYTE *)phys_write_addr(where)) = what;

        final_check();

} /* void doWriteMemByte(BYTE what, WORD where) */





void doWriteMemHalfWord(HWORD what, WORD where)
{
#ifdef ENDIAN_IS_LITTLE
        where ^= 0x02;
#endif

        *((HWORD *)phys_write_addr(where)) = what;

        final_check();

} /* void doWriteMemHalfWord(HWORD what, WORD where) */





void doWriteMemWord(WORD what, WORD where)
{
        *((WORD *)phys_write_addr(where)) = what;

        final_check();

} /* void doWriteMemWord(WORD what, WORD where) */





void doWriteMemDoubleWord(DWORD what, WORD where)
{
#ifdef ENDIAN_IS_BIG
        *((DWORD *)phys_write_addr(where)) = what;
#endif
#ifdef ENDIAN_IS_LITTLE
        *((DWORD *)phys_write_addr(where)) = (what << 32) + (what >> 32);
#endif
   
        final_check();

} /* void doWriteMemDoubleWord(DWORD what, WORD where) */










/*
** The "main" memory routines follow.
*/



static void write_mem_addr()
{

        mem.rd_ram      = mem_addr[0];
        mem.sp_dmem     = mem_addr[1];
        mem.sp_imem     = mem_addr[2];
        mem.pi_rom      = mem_addr[3];
        mem.pi_ram      = mem_addr[4];
        mem.pi_ram_w    = mem_addr[5];
                     
        mem.rd_reg      = mem_addr[6];
        mem.sp_reg      = mem_addr[7];
        mem.dpc_reg     = mem_addr[8];
        mem.dps_reg     = mem_addr[9];
        mem.mi_reg      = mem_addr[10];
        mem.mi_reg_w    = mem_addr[11];
        mem.vi_reg      = mem_addr[12];
        mem.ai_reg      = mem_addr[13];
        mem.pi_reg      = mem_addr[14];
        mem.pi_reg_w    = mem_addr[15];
        mem.ri_reg      = mem_addr[16];
        mem.si_reg      = mem_addr[17];
        mem.null_mem    = mem_addr[18];

#ifdef SHM
        shminfo.rd_ram  =  mem_shminfo[0];
        shminfo.sp_dmem =  mem_shminfo[1];
        shminfo.sp_imem =  mem_shminfo[2];
        shminfo.pi_rom  =  mem_shminfo[3];
        shminfo.pi_ram  =  mem_shminfo[4];
        shminfo.pi_ram_w=  mem_shminfo[5];
                         
        shminfo.rd_reg  =  mem_shminfo[6];
        shminfo.sp_reg  =  mem_shminfo[7];
        shminfo.dpc_reg =  mem_shminfo[8];
        shminfo.dps_reg =  mem_shminfo[9];
        shminfo.mi_reg  =  mem_shminfo[10];
        shminfo.mi_reg_w = mem_shminfo[11];
        shminfo.vi_reg  =  mem_shminfo[12];
        shminfo.ai_reg  =  mem_shminfo[13];
        shminfo.pi_reg  =  mem_shminfo[14];
        shminfo.pi_reg_w = mem_shminfo[15];
        shminfo.ri_reg  =  mem_shminfo[16];
        shminfo.si_reg  =  mem_shminfo[17];
        shminfo.null_mem = mem_shminfo[18];
#endif /* SHM */

} /* static void write_mem_addr() */





int alloc_n64_mem()
{
        int i;
#ifdef SHM
        struct shmid_ds s;
#endif
        
        
        
        fputs("Allocating memory ...", stdout); fflush(stdout);

        for(i=0; i<N_SEGMENTS; i++)
        {
#ifdef SHM
                if(prefs.UseSHM)
                {
                        mem_shminfo[i].shmid = shmget(IPC_PRIVATE, mem_size[i], IPC_CREAT | 0777);
                        if(mem_shminfo[i].shmid < 0) 
                        { 
                                printf("alloc_n64_mem: Couldn't get SHM ID [%d]\n\n", i);
                                return(-1); 
                        }

                        mem_addr[i] = mem_shminfo[i].shmaddr = shmat(mem_shminfo[i].shmid, 0, 0);
                        if( ! mem_addr[i] ) 
                        { 
                                printf("alloc_n64_mem: Couldn't attach shared memory [%d]\n\n", i);
                                return(-1);
                        }

                        mem_shminfo[i].readOnly = False;

                        shmctl(mem_shminfo[i].shmid, IPC_RMID, &s);   /* if someone kills me, shm should be freed */

                        memset(mem_addr[i], 0, mem_size[i]);

                } /* if(prefs.UseSHM) */
                else
#endif
                {
                        mem_addr[i] = (BYTE *) malloc(mem_size[i]);
                        if( ! mem_addr[i] )
                        {
                                printf("alloc_n64_mem: Not enough memory [%d]\n\n", i);
                                return(-1);
                        }
                        memset(mem_addr[i], 0, mem_size[i]);
                }

        } /* for(i=0; i<N_SEGMENTS; i++) */



        write_mem_addr();



        /* this need to be initialized */

        ((WORD *)mem.mi_reg)[1] = 0x01010101;
        mem.sp_reg_pc = 0x04001000;



        puts(" OK\n"
             "-------------------------------------------------------------------------------"); fflush(stdout);

        return(0);

} /* int alloc_n64_mem() */





void clear_n64_mem()
{
        int i;



        fputs("Clearing memory ...", stdout); fflush(stdout);

        for(i=0; i<N_SEGMENTS; i++)
        {
                memset(mem_addr[i], 0, mem_size[i]);
        
        } /* for(i=0; mem_size[i] > 0; i++) */



        /* this need to be initialized */
        
        ((WORD *)mem.mi_reg)[1] = 0x01010101;
        mem.sp_reg_pc = 0x04001000;



        /* we don't have to do anything in this stage */
        
        mem_todo = DO_NOTHING;


        
        /* clr static vi (video interface) dependend vars */
        
        old_vi_status_reg = 0;  
        old_vi_width_reg  = 0;



        puts(" OK\n"
             "-------------------------------------------------------------------------------"); fflush(stdout);

} /* void clear_n64_mem() */





void free_n64_mem()
{
        int i;
        

        
        fputs("Freeing memory ...", stdout); fflush(stdout);

        for(i=0; i<N_SEGMENTS; i++)
        {
#ifdef SHM
                if(prefs.UseSHM)
                {
                        if(mem_shminfo[i].shmaddr)
                                shmdt(mem_shminfo[i].shmaddr);
                } /* if(prefs.UseSHM) */
                else
#endif
                {
                        if(mem_addr[i])
                                free(mem_addr[i]);
                }

        } /* for(i=0; i<N_SEGMENTS; i++) */

        puts(" OK\n"
             "-------------------------------------------------------------------------------"); fflush(stdout);

} /* void free_n64_mem() */










static void do_display_refresh()
{
        dispatch(DISPLAY_REFRESH, 0);
        
} /* static void do_display_refresh(); */





static void check_vi_reg()
{
        /* BUG: the order might be changed. most changing reg first. (speed) */
        if( old_vi_status_reg != ((WORD *)mem.vi_reg)[0] )
        {
                old_vi_status_reg = ((WORD *)mem.vi_reg)[0];
#if DISPLAY_SUPPORT
                dispatch(DISPLAY_REFRESH, 0);
#endif
                return;
        }
        
        if( old_vi_width_reg  != ((WORD *)mem.vi_reg)[2] )
        {
                old_vi_width_reg  = ((WORD *)mem.vi_reg)[2];
#if DISPLAY_SUPPORT
                dispatch(DISPLAY_REFRESH, 0);
#endif
                return;
        }

} /* static void check_vi_reg() */





static void check_ai_reg()
{
        dispatch(AUDIO_UPDATE, 0);

} /* static void update_ai_reg() */





static void update_vi_reg()
{
        /* there are some unused bits in this regs.
           hope that this works */

        ((WORD *)mem.vi_reg)[1] &= 0x003fffff;
        ((WORD *)mem.vi_reg)[2] &= 0x00000fff;

} /* static void update_vi_reg() */





static void update_pi_reg()
{
        if(mem.pi_reg_status_w & 0x02)
                ((WORD *)mem.mi_reg)[2] &= ~MI_INTR_PI;

} /* static void update_pi_reg() */





static void update_mi_reg()
{
        if(mem.mi_reg_mode_w & 0x0080)        /* MI_CLR_INIT */
                ((WORD *)mem.mi_reg)[0] &= ~0x00000080;

        if(mem.mi_reg_mode_w & 0x0100)        /* MI_SET_INIT */
                ((WORD *)mem.mi_reg)[0] |= 0x00000080;

        if(mem.mi_reg_mode_w & 0x0200)        /* MI_CLR_EBUS */
                ((WORD *)mem.mi_reg)[0] &= ~0x00000100;

        if(mem.mi_reg_mode_w & 0x0400)        /* MI_SET_EBUS */
                ((WORD *)mem.mi_reg)[0] |= 0x00000100;

        if(mem.mi_reg_mode_w & 0x0800)        /* MI_CLR_DP_INTR */
                ((WORD *)mem.mi_reg)[2] &= ~MI_INTR_DP;

        if(mem.mi_reg_mode_w & 0x1000)        /* MI_CLR_RDRAM */
                ((WORD *)mem.mi_reg)[0] &= ~0x00000200;

        if(mem.mi_reg_mode_w & 0x2000)        /* MI_SET_RDRAM */
                ((WORD *)mem.mi_reg)[0] |= 0x00000200;



        if(mem.mi_reg_intr_mask_w & 0x0001)        /* MI_INTR_MASK_CLR_SP */
                ((WORD *)mem.mi_reg)[3] &= ~0x0000001;

        if(mem.mi_reg_intr_mask_w & 0x0002)        /* MI_INTR_MASK_SET_SP */
                ((WORD *)mem.mi_reg)[3] |= 0x00000001;

        if(mem.mi_reg_intr_mask_w & 0x0004)        /* MI_INTR_MASK_CLR_SI */
                ((WORD *)mem.mi_reg)[3] &= ~0x0000002;

        if(mem.mi_reg_intr_mask_w & 0x0008)        /* MI_INTR_MASK_SET_SI */
                ((WORD *)mem.mi_reg)[3] |= 0x00000002;

        if(mem.mi_reg_intr_mask_w & 0x0010)        /* MI_INTR_MASK_CLR_AI */
                ((WORD *)mem.mi_reg)[3] &= ~0x00000004;

        if(mem.mi_reg_intr_mask_w & 0x0020)        /* MI_INTR_MASK_SET_AI */
                ((WORD *)mem.mi_reg)[3] |= 0x00000004;

        if(mem.mi_reg_intr_mask_w & 0x0040)        /* MI_INTR_MASK_CLR_VI */
                ((WORD *)mem.mi_reg)[3] &= ~0x00000008;

        if(mem.mi_reg_intr_mask_w & 0x0080)        /* MI_INTR_MASK_SET_VI */
                ((WORD *)mem.mi_reg)[3] |= 0x00000008;

        if(mem.mi_reg_intr_mask_w & 0x0100)        /* MI_INTR_MASK_CLR_PI */
                ((WORD *)mem.mi_reg)[3] &= ~0x00000010;

        if(mem.mi_reg_intr_mask_w & 0x0200)        /* MI_INTR_MASK_SET_PI */
                ((WORD *)mem.mi_reg)[3] |= 0x00000010;

        if(mem.mi_reg_intr_mask_w & 0x0400)        /* MI_INTR_MASK_CLR_DP */
                ((WORD *)mem.mi_reg)[3] &= ~0x00000020;

        if(mem.mi_reg_intr_mask_w & 0x0800)        /* MI_INTR_MASK_SET_DP */
                ((WORD *)mem.mi_reg)[3] |= 0x00000020;

} /* static void update_mi_reg() */






static void update_sp_reg()
{
        if(mem.sp_reg_status_w & 0x00000001)   /* SP_CLR_HALT       */
        {
                ((WORD *)mem.sp_reg)[4] &= ~0x00000001;
                rsp_reg.halt = 0;
        }

        if(mem.sp_reg_status_w & 0x00000002)   /* SP_SET_HALT       */
        {
                ((WORD *)mem.sp_reg)[4] |= 0x00000001;
                rsp_reg.halt = 1;
        }

        if(mem.sp_reg_status_w & 0x00000004)   /* SP_CLR_BROKE      */
                ((WORD *)mem.sp_reg)[4] &= ~0x00000002;

        if(mem.sp_reg_status_w & 0x00000008)   /* SP_CLR_INTR       */
                ((WORD *)mem.mi_reg)[2] &= ~MI_INTR_SP;

        if(mem.sp_reg_status_w & 0x00000010)   /* SP_SET_INTR       */
        {
                ((WORD *)mem.mi_reg)[2] |= MI_INTR_SP;
                reg.do_or_check_sthg = RS4300I_CHECK_MI_INTERRUPTS;
        }

        if(mem.sp_reg_status_w & 0x00000020)   /* SP_CLR_SSTEP      */
        {
                ((WORD *)mem.sp_reg)[4] &= ~0x00000020;
        }

        if(mem.sp_reg_status_w & 0x00000040)   /* SP_SET_SSTEP      */
        {
                ((WORD *)mem.sp_reg)[4] |= 0x00000020;
        }

        if(mem.sp_reg_status_w & 0x00000080)   /* SP_CLR_INTR_BREAK */
                ((WORD *)mem.sp_reg)[4] &= ~0x00000040;

        if(mem.sp_reg_status_w & 0x00000100)   /* SP_SET_INTR_BREAK */
                ((WORD *)mem.sp_reg)[4] |= 0x00000040;

        if(mem.sp_reg_status_w & 0x00000200)   /* SP_CLR_SIG0       */
                ((WORD *)mem.sp_reg)[4] &= ~0x00000080;

        if(mem.sp_reg_status_w & 0x00000400)   /* SP_SET_SIG0       */
                ((WORD *)mem.sp_reg)[4] |= 0x00000080;

        if(mem.sp_reg_status_w & 0x00000800)   /* SP_CLR_SIG1       */
                ((WORD *)mem.sp_reg)[4] &= ~0x00000100;

        if(mem.sp_reg_status_w & 0x00001000)   /* SP_SET_SIG1       */
                ((WORD *)mem.sp_reg)[4] |= 0x00000100;

        if(mem.sp_reg_status_w & 0x00002000)   /* SP_CLR_SIG2       */
                ((WORD *)mem.sp_reg)[4] &= ~0x00000200;

        if(mem.sp_reg_status_w & 0x00004000)   /* SP_SET_SIG2       */
                ((WORD *)mem.sp_reg)[4] |= 0x00000200;

        if(mem.sp_reg_status_w & 0x00008000)   /* SP_CLR_SIG3       */
                ((WORD *)mem.sp_reg)[4] &= ~0x00000400;

        if(mem.sp_reg_status_w & 0x00010000)   /* SP_SET_SIG3       */
                ((WORD *)mem.sp_reg)[4] |= 0x00000400;

        if(mem.sp_reg_status_w & 0x00020000)   /* SP_CLR_SIG4       */
                ((WORD *)mem.sp_reg)[4] &= ~0x00000800;

        if(mem.sp_reg_status_w & 0x00040000)   /* SP_SET_SIG4       */
                ((WORD *)mem.sp_reg)[4] |= 0x00000800;

        if(mem.sp_reg_status_w & 0x00080000)   /* SP_CLR_SIG5       */
                ((WORD *)mem.sp_reg)[4] &= ~0x00001000;

        if(mem.sp_reg_status_w & 0x00100000)   /* SP_SET_SIG5       */
                ((WORD *)mem.sp_reg)[4] |= 0x00001000;

        if(mem.sp_reg_status_w & 0x00200000)   /* SP_CLR_SIG6       */
                ((WORD *)mem.sp_reg)[4] &= ~0x00002000;

        if(mem.sp_reg_status_w & 0x00400000)   /* SP_SET_SIG6       */
                ((WORD *)mem.sp_reg)[4] |= 0x00002000;

        if(mem.sp_reg_status_w & 0x00800000)   /* SP_CLR_SIG7       */
                ((WORD *)mem.sp_reg)[4] &= ~0x00004000;

        if(mem.sp_reg_status_w & 0x01000000)   /* SP_SET_SIG7       */
                ((WORD *)mem.sp_reg)[4] |= 0x00004000;

} /* static void update_sp_reg() */





static void update_dp_reg()
{
        if(mem.dpc_reg_status_w & 0x0001)       /* DPC_CLR_XBUS_DMEM_DMA */
                ((WORD *)mem.dpc_reg)[3] &= ~0x0000001;

        if(mem.dpc_reg_status_w & 0x0002)       /* DPC_SET_XBUS_DMEM_DMA */
                ((WORD *)mem.dpc_reg)[3] |= 0x00000001;

        if(mem.dpc_reg_status_w & 0x0004)       /* DPC_CLR_FREEZE */
                ((WORD *)mem.dpc_reg)[3] &= ~0x0000002;

        if(mem.dpc_reg_status_w & 0x0008)       /* DPC_SET_FREEZE */
                ((WORD *)mem.dpc_reg)[3] |= 0x00000002;

        if(mem.dpc_reg_status_w & 0x0010)       /* DPC_CLR_FLUSH */
                ((WORD *)mem.dpc_reg)[3] &= ~0x0000004;

        if(mem.dpc_reg_status_w & 0x0020)       /* DPC_SET_FLUSH */
                ((WORD *)mem.dpc_reg)[3] |= 0x00000004;

        if(mem.dpc_reg_status_w & 0x0040)       /* DPC_CLR_TMEM_CTR */
                ((WORD *)mem.dpc_reg)[7] = 0;

        if(mem.dpc_reg_status_w & 0x0080)       /* DPC_CLR_PIPE_CTR */
                ((WORD *)mem.dpc_reg)[6] = 0;

        if(mem.dpc_reg_status_w & 0x0100)       /* DPC_CLR_CMD_CTR */
                ((WORD *)mem.dpc_reg)[5] = 0;

        if(mem.dpc_reg_status_w & 0x0200)       /* DPC_CLR_CLOCK_CTR */
                ((WORD *)mem.dpc_reg)[4] = 0;

} /* static void update_dp_reg() */






