/**
 * TrueReality - n64/memory.c
 * Copyright (C) 1998 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 "../romimage_extern.h"
#include "../dispatch.h"
#include "type_sizes.h"
#include "registers.h"
#include "exceptions.h"
#include "interrupts.h"
#include "dma.h"
#include "memory_extern.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 UPDATE_MI_REG           0x0001
#define UPDATE_PI_REG           0x0002
#define UPDATE_SP_REG           0x0004
#define CHECK_VI_REG            0x0008
#define PIF2DRAM_DMA            0x0010
#define DRAM2PIF_DMA            0x0020
#define PI_DMA                  0x0044
#define IDMEM2DRAM_DMA          0x0080
#define DRAM2IDMEM_DMA          0x0100

        /* for making code nicer */
#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);                                                            \
        }

        /* for speed reasons ( inline :) ) */
#define final_check()                           \
        if(mem_todo)                            \
        {                                       \
                if(mem_todo & CHECK_VI_REG)     \
                        check_vi_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 & 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    update_mi_reg();
static  void    update_pi_reg();
static  void    update_sp_reg();
static  void    check_vi_reg();

        /* vars */
static  int     mem_todo;
                /* for check_vi_reg */
static  WORD    old_vi_status_reg;
static  WORD    old_vi_width_reg;

/* 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;





#ifdef DEBUG_MEMORY
        print_debug_msg(prefs.debug & DBG_MEMORY, "read");
#endif

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

                    case 0x04000000:
                        switch(vaddr & 0x00f00000)
                        {
                            case 0x00000000:                   
                                switch(vaddr & 0x000f0000)
                                {
                                    case 0x00000000:
                                        if(vaddr < 0x04001000)
                                        {
#ifdef DEBUG_SP_DMEM
                                                print_debug_msg(prefs.debug & DBG_SP_DMEM, "read  - sp dmem");
#endif
                                                return(mem.sp_dmem + (vaddr & 0xfff));
                                        }
                                        if(vaddr < 0x04002000)
                                        {
#ifdef DEBUG_SP_IMEM
                                                print_debug_msg(prefs.debug & DBG_SP_IMEM, "read  - sp imem");
#endif
                                                return(mem.sp_imem + (vaddr & 0xfff));
                                        }
                                        break;
                                    
                                    case 0x00010000:
                                    case 0x00020000:
                                    case 0x00030000:
                                        break;
                                            
                                    case 0x00040000:
                                        if(vaddr < 0x04040020)
                                        {
#ifdef DEBUG_SP_REG
                                                print_debug_msg(prefs.debug & DBG_SP_REG, "read  - sp reg");
#endif
                                                return(mem.sp_reg + (vaddr & 0xff));
                                        }
                                        break;
                                                    
                                    case 0x00050000:
                                    case 0x00060000:
                                    case 0x00070000:
                                        break;
                                            
                                    case 0x00080000:
                                        if(vaddr < 0x04080004)
                                        {
#ifdef DEBUG_SP_PC_REG
                                                print_debug_msg(prefs.debug & DBG_SP_PC_REG, "read  - sp pc");
#endif
                                                return(((char *)&(mem.sp_pc_reg)) + (vaddr & 0x03));
                                        }
                                        if(vaddr < 0x04080008)
                                        {
#ifdef DEBUG_SP_IBIST_REG
                                                print_debug_msg(prefs.debug & DBG_SP_IBIST_REG, "read  - sp ibist");
#endif
                                                return(((char *)&(mem.sp_ibist_reg)) + 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)
                                {
#ifdef DEBUG_DPC_REG
                                        print_debug_msg(prefs.debug & DBG_DPC_REG, "read  - dpc reg");
#endif
                                        return(mem.dpc_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00200000:
                                if(vaddr < 0x04200010)
                                {
#ifdef DEBUG_DPS_REG
                                        print_debug_msg(prefs.debug & DBG_DPS_REG, "read  - dps reg");
#endif
                                        return(mem.dps_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00300000:
                                if(vaddr < 0x04300010)
                                {
#ifdef DEBUG_MI_REG
                                        print_debug_msg(prefs.debug & DBG_MI_REG, "read  - mi reg");
#endif
                                        return(mem.mi_reg + (vaddr & 0xf));
                                }
                                break;
                            
                            case 0x00400000:
                                if(vaddr < 0x04400038)
                                {
#ifdef DEBUG_VI_REG
                                        print_debug_msg(prefs.debug & DBG_VI_REG, "read  - vi reg");
#endif

                                        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));
                                                
                                            default:
                                                return(mem.vi_reg + (vaddr & 0xff));
                                        }
                                }
                                break;
                            
                            case 0x00500000:
                                if(vaddr < 0x04500018)
                                {
#ifdef DEBUG_AI_REG
                                        print_debug_msg(prefs.debug & DBG_AI_REG, "read  - ai reg");
#endif
                                        return(mem.ai_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00600000:
                                if(vaddr < 0x04600034)
                                {
#ifdef DEBUG_PI_REG
                                        print_debug_msg(prefs.debug & DBG_PI_REG, "read  - pi reg");
#endif
                                        return(mem.pi_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00700000:
                                if(vaddr < 0x04700020)
                                {
#ifdef DEBUG_RI_REG
                                        print_debug_msg(prefs.debug & DBG_RI_REG, "read  - ri reg");
#endif
                                        return(mem.ri_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00800000:
                                if(vaddr < 0x0480001c)
                                {
#ifdef DEBUG_SI_REG
                                        print_debug_msg(prefs.debug & DBG_SI_REG, "read  - si reg");
#endif
                                        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))
                        {
#ifdef DEBUG_PI_DOM2_ADDR1
                                print_debug_msg(prefs.debug & DBG_PI_DOM2_ADDR1, "read");
#endif
                                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))
                        {
#ifdef DEBUG_PI_DOM1_ADDR1
                                print_debug_msg(prefs.debug & DBG_PI_DOM1_ADDR1, "read");
#endif
                                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))
                        {
#ifdef DEBUG_PI_DOM2_ADDR2
                                print_debug_msg(prefs.debug & DBG_PI_DOM2_ADDR2, "read");
#endif
                                return(rom.image + vaddr - 0x08000000);
                        }
                        break;
                            
                } /* switch(vaddr & 0x0f000000) */
                break;
                
            case 0x10000000:
                if(vaddr < 0x1fc00000)                                  /* PI_DOM1_ADDR2 */
                {
                        if(vaddr < (0x10000000 + rom.length))
                        {
#ifdef DEBUG_PI_DOM1_ADDR2
                                print_debug_msg(prefs.debug & DBG_PI_DOM1_ADDR2, "read");
#endif
                                return(rom.image + (vaddr & 0xfffffff));
                        }
                        break;
                }
                
                if(vaddr < 0x1fc007c0)                                         /* PI ROM */
                {
#ifdef DEBUG_PI_ROM
                        print_debug_msg(prefs.debug & DBG_PI_ROM, "read");
#endif
                        return(mem.pi_rom + (vaddr & 0xfff));
                }
                    
                if(vaddr < 0x1fc00800)                                         /* PI RAM */
                {
#ifdef DEBUG_PI_RAM
                        print_debug_msg(prefs.debug & DBG_PI_RAM, "read");
#endif
                        return(mem.pi_ram + vaddr - 0x1fc007c0);
                }
                
                if(vaddr < 0x1fd00000)                                            /* ??? */
                        break;
                
                if(vaddr < (0x1fd00000 + rom.length))                   /* PI_DOM1_ADDR3 */
                {
#ifdef DEBUG_PI_DOM1_ADDR3
                        print_debug_msg(prefs.debug & DBG_PI_DOM1_ADDR3, "read");
#endif
                        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;
        




#ifdef DEBUG_MEMORY
        print_debug_msg(prefs.debug & DBG_MEMORY, "write");
#endif
   

   
        vaddr = vaddr & 0x1fffffff;

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

                    case 0x04000000:
                        switch(vaddr & 0x00f00000)
                        {
                            case 0x00000000:
                                switch(vaddr & 0x000f0000)
                                {
                                    case 0x00000000:
                                        if(vaddr < 0x04001000)
                                        {
#ifdef DEBUG_SP_DMEM
                                                print_debug_msg(prefs.debug & DBG_SP_DMEM, "write - sp dmem");
#endif
                                                return(mem.sp_dmem + (vaddr & 0xfff));
                                        }
                                        if(vaddr < 0x04002000)
                                        {
#ifdef DEBUG_SP_IMEM
                                                print_debug_msg(prefs.debug & DBG_SP_IMEM, "write - sp imem");
#endif
                                                return(mem.sp_imem + (vaddr & 0xfff));
                                        }
                                        break;
                                    
                                    case 0x00010000:
                                    case 0x00020000:
                                    case 0x00030000:
                                        break;
                                            
                                    case 0x00040000:
                                        if(vaddr < 0x04040020)
                                        {
#ifdef DEBUG_SP_REG
                                                print_debug_msg(prefs.debug & DBG_SP_REG, "write - sp reg");
#endif
                                                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:   /* ?? */
                                                    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)
                                        {
#ifdef DEBUG_SP_PC_REG
                                                print_debug_msg(prefs.debug & DBG_SP_PC_REG, "write - sp pc");
#endif
                                                return(((char *)&(mem.sp_pc_reg)) + (vaddr & 0x03));
                                        }
                                        if(vaddr < 0x04080008)
                                        {
#ifdef DEBUG_SP_IBIST_REG
                                                print_debug_msg(prefs.debug & DBG_SP_IBIST_REG, "write - sp ibist");
#endif
                                                return(((char *)&(mem.sp_ibist_reg)) + 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)
                                {
#ifdef DEBUG_DPC_REG
                                        print_debug_msg(prefs.debug & DBG_DPC_REG, "write - dpc reg");
#endif
                                        return(mem.dpc_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00200000:
                                if(vaddr < 0x04200010)
                                {
#ifdef DEBUG_DPS_REG
                                        print_debug_msg(prefs.debug & DBG_DPS_REG, "write - dps reg");
#endif
                                        return(mem.dps_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00300000:
                                if(vaddr < 0x04300010)
                                {
#ifdef DEBUG_MI_REG
                                        print_debug_msg(prefs.debug & DBG_MI_REG, "write - mi reg");
#endif

                                        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)
                                {
#ifdef DEBUG_VI_REG
                                        print_debug_msg(prefs.debug & DBG_VI_REG, "write - vi reg");
#endif

                                        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:
#if DISPLAY_SUPPORT
                                                dispatch(DISPLAY_REFRESH, 0);
#endif
                                                break;
                                            
                                            case 0x08:   /* VI_WIDTH_REG */
                                            case 0x09:
                                            case 0x0a:
                                            case 0x0b:
                                                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)
                                {
#ifdef DEBUG_AI_REG
                                        print_debug_msg(prefs.debug & DBG_AI_REG, "write - ai reg");
#endif

                                        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:
#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)
                                {
#ifdef DEBUG_PI_REG
                                        print_debug_msg(prefs.debug & DBG_PI_REG, "write - pi reg");
#endif
                                        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)
                                {
#ifdef DEBUG_RI_REG
                                        print_debug_msg(prefs.debug & DBG_RI_REG, "write - ri reg");
#endif
                                        return(mem.ri_reg + (vaddr & 0xff));
                                }
                                break;
                            
                            case 0x00800000:
                                if(vaddr < 0x0480001c)
                                {
#ifdef DEBUG_SI_REG
                                        print_debug_msg(prefs.debug & DBG_SI_REG, "write - si reg");
#endif
                                        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))
                        {
#ifdef DEBUG_PI_DOM2_ADDR1
                                print_debug_msg(prefs.debug & DBG_PI_DOM2_ADDR1, "write");
#endif
                                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))
                        {
#ifdef DEBUG_PI_DOM1_ADDR1
                                print_debug_msg(prefs.debug & DBG_PI_DOM1_ADDR1, "write");
#endif
                                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))
                        {
#ifdef DEBUG_PI_DOM2_ADDR2
                                print_debug_msg(prefs.debug & DBG_PI_DOM2_ADDR2, "write");
#endif
                                return(rom.image + vaddr - 0x08000000);
                        }
                        break;
                            
                } /* switch(vaddr & 0x0f000000) */
                break;
                
            case 0x10000000:
                if(vaddr < 0x1fc00000)                                  /* PI_DOM1_ADDR2 */
                {
                        if(vaddr < (0x10000000 + rom.length))
                        {
#ifdef DEBUG_PI_DOM1_ADDR2
                                print_debug_msg(prefs.debug & DBG_PI_DOM1_ADDR2, "write");
#endif
                                return(rom.image + (vaddr & 0xfffffff));
                        }
                        break;
                }
                
                if(vaddr < 0x1fc007c0)                                         /* PI ROM */
                {
#ifdef DEBUG_PI_ROM
                        print_debug_msg(prefs.debug & DBG_PI_ROM, "write");
#endif
                        return(mem.pi_rom + (vaddr & 0xfff));
                }
                    
                if(vaddr < 0x1fc00800)                                         /* PI RAM */
                {
#ifdef DEBUG_PI_RAM
                        print_debug_msg(prefs.debug & DBG_PI_RAM, "write");
#endif
                        // 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 */
                {
#ifdef DEBUG_PI_DOM1_ADDR3
                        print_debug_msg(prefs.debug & DBG_PI_DOM1_ADDR3, "write");
#endif
                        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() */





/* 'read_n64_image()' from 'romimage.c' has to be executed before!!! */

int alloc_n64_mem()
{
        int i;
#ifdef SHM
        struct shmid_ds s;
#endif
        
        
        
        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] = (char *) 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;



        return(0);
        
} /* int alloc_n64_mem() */





void clear_n64_mem()
{
        int i;



        /* clr the mem */
        
        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;



        /* 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;
        

        
} /* void clear_n64_mem() */





void free_n64_mem()
{
        int i;
        

        
        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++) */

} /* void free_n64_mem() */










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 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;

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

        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() */










