/**
 * TrueReality - debug.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 <stdio.h>
#include <stdlib.h>

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

#include "N64/memory.h"
#include "N64/mnemonic.h"
#include "N64/registers.h"
#include "N64/rsp_registers.h"
#include "N64/rsp.h"
#include "N64/cpu.h"

#include "file_loader.h"

#include <debug.h>

#ifdef READLINE
        #include <readline/readline.h>
        #include <readline/history.h>
#endif




static  WORD    breakp[256];





static  char *  get_line(char *prompt);
static  void    n64_rsp_debugger_switch(char line[]);
static  void    n64_rsp_debugger_files();








/*
   get_line:

   This routine supports readline if defined.
   You need the readline and ncurses library!

   After using this routine the last time you've to free the mem!
*/

static char *get_line(char *prompt)
{
        static char     *line = NULL;



        if(line)
        {
                free(line);
                line = NULL;
        }

#ifndef READLINE
        printf("%s", prompt);

        line = (char *)malloc(82);

        fgets(line, 80, stdin);
#else
        line = readline(prompt);

        if(line && *line)
                add_history(line);
#endif

        return(line);

} /* static char *get_line(char *prompt, char *line) */





void n64_cpu_debugger()
{
        char    *line;
        int     i, j, n;
        WORD    addr;
        HWORD   hword;
        WORD    word;
        DWORD   dword;



        breakp[0] = 0;
   
        do
        {
                line = get_line("TR-debug> ");
      
                switch(line[0])
                {
                    case 'j':
                        if(sscanf(line+1, "%lx", &word) == 1)
                        {
                                reg.pc = word;
                        }
                        else
                        {
                                fputs("n64_rsp_debugger: Use 'j addr' sets pc to addr\n", stderr);
                        }
                        break;



                    case 'C':
                        n64_rsp_debugger();
                        break;



                    case 'R':
                        dispatch(EMU_RESET, 0);
                        break;



                    case 'h':
                    case 'H':
                        fputs("n64_cpu_debugger: For help have a look at TrueReality/Documentation/Debugger\n"
                             "(Exit debugger with '!')\n\n", stderr);
                        break;

                    
                    
                    case 'd':
                        if(sscanf(line+1, "%llx", &dword) == 1)
                                prefs.debug = dword;
                        else
                                print_debugging_options();
                        break;
                        
            
            
                    case '.':
                        if(sscanf(line+1, "%x", &n) == 1)
                        {
                                switch(n)
                                {
                                    case 0:
                                        reg.halt = 0;
                                        break;

                                    case 1:
                                        reg.halt = 1;
                                        break;
                                
                                } /* switch(n) */
                                break;
                                
                        } /* if(sscanf(line+1, "%x", &n) == 1) */
                        
                        fputs("n64_cpu_debugger: Use '. n' set/reset halt state\n"
                              "          n = 0: cpu run\n"
                              "          n = 1: cpu halt\n\n", stderr);
                        
                        break;
                        
            
            
                    case 'G':
                        for(;;)
                        {
#ifdef HALT
                                if(reg.halt)
                                {
                                        reg.halt = 0;
                                        break;
                                }
#endif
                                cpu_step();
                        }
                        break;


            
#if DISPLAY_SUPPORT
                    case 'r':
                        dispatch(DISPLAY_REFRESH, 0);
                        break;
#endif
            

            
                    case 'b':
                        if(sscanf(line+1, "%lx", &addr) == 1)
                        {
                                breakp[0] += 1;
                                breakp[ breakp[0] ] = addr;
               
                                printf("Breakpoint #%d set @ %08lx\n", (int)breakp[0], breakp[ breakp[0] ]);
                        }
                        else if(line[1] == '-')
                        {
                                if(breakp[0] > 0)
                                {
                                        breakp[0] -= 1;

                                        printf("Breakpoint #%d removed\n", (int)breakp[0] + 1);
                                }
                                else
                                        printf("There is no breakpoint to remove (set one!)\n");
                  
                        }
                        else if(line[1] == 'l')
                        {
                                for(i=1; i<=breakp[0]; i++)
                                        printf("Breakpoint #%d: %08lx\n", i, breakp[i]);
                                putchar('\n');
                        }
                        else
                        {
                                fputs("n64_cpu_debugger: 'b pos' ... sets breakpoint @ pos\n"
                                      "          'b-'    ... remove last breakpoint\n"
                                      "          'bl'    ... lists all breakpoints\n\n'", stderr);
                        }
                        break;
      
      
                    
                    case 't':
                        cpu_step();
                        break;
            
            
            
                    case 'g':
                        if(line[1] == '-')
                        {
                                if(sscanf(line + 2, "%llx", &dword) == 1)
                                {
                                        while(reg.cpr[0][9] < dword)
                                        {
#ifdef HALT
                                                if(reg.halt)
                                                {
                                                        reg.halt = 0;
                                                        break;
                                                }
#endif
                                                cpu_step();
                                                for(j=1; j<=breakp[0]; j++)
                                                        if(reg.pc == breakp[j])
                                                        {
                                                                printf("\nBreakpoint #%d @ %08lx ([count]=%016llx) reached\n\n", j, breakp[j], reg.cpr[0][COUNT]);
                                                                dword = 0;
                                                                break;
                           
                                                        } /* if(reg.pc == breakp[j]) */
                        
                                        } /* while(reg.cpr[0][9] < dword) */
                  
                                } /* if(sscanf(line + 2, "%llx", &dword) == 1) */
               
                                else
                                        fputs("n64_cpu_debugger: g  x ... executes x instructions\n"  
                                              "          g- x ... executes instructions until count == x\n\n", stderr);
                        }
            
                        else
                        {
                                if(sscanf(line + 1, "%llx", &dword) == 1)
                                {
                                        for(i=0; i<dword; i++)
                                        {
#ifdef HALT
                                                if(reg.halt)
                                                {
                                                        reg.halt = 0;
                                                        break;
                                                }
#endif
                                                cpu_step();
                                                for(j=1; j<=breakp[0]; j++)
                                                        if(reg.pc == breakp[j])
                                                        {
                                                                printf("\nBreakpoint #%d @ %08lx ([count]=%016llx) reached\n\n", j, breakp[j], reg.cpr[0][COUNT]);
                                                                dword = 0;
                                                                break;
                           
                                                        } /* if(reg.pc == breakp[j]) */
                                
                                        } /* for(i=0; i<dword; i++) */

                                } /* if(sscanf(line + 1, "%llx", &dword) == 1) */
                                else
                                        fputs("n64_cpu_debugger: g  x ... executes x instructions\n"  
                                              "          g- x ... executes instructions until count == x\n\n", stderr);

                        } /* if(line[1] != '-') */
            
                        break;
            
                    
                    
                    case 'l':
                        switch(line[1])
                        {
                            case 'w':
                                if(sscanf(line + 2, "%lx", &addr) == 1)
                                {
                                        printf("%lx: %08lx\n", addr, doReadMemWord(addr));
                                }
                                break;
                            case 'd':
                                if(sscanf(line + 2, "%lx", &addr) == 1)
                                {
                                        printf("%lx: %016llx\n", addr, doReadMemDoubleWord(addr));
                                }
                                break;
                            case 'h':
                                if(sscanf(line + 2, "%lx", &addr) == 1)
                                {
                                        printf("%lx: %04hx\n", addr, doReadMemHalfWord(addr));
                                }
                                break;
                            case 'b':
                                if(sscanf(line + 2, "%lx", &addr) == 1)
                                {
                                        printf("%lx: %02x\n", addr, doReadMemByte(addr));
                                }
                                break;
                        }
                        break;
                    

                    
                    case 's':
                        switch(line[1])
                        {
                            case 'w':
                                if(sscanf(line+2, "%lx %lx", &addr, &word) == 2)
                                {
                                        printf("%08lx <- %08lx\n", addr, word);
                                        doWriteMemWord(word, addr);
                                }
                                break;
                    
                            case 'd':
                                if(sscanf(line+2, "%lx %llx", &addr, &dword) == 2)
                                {
                                        printf("%08lx <- %016llx\n", addr, dword);
                                        doWriteMemDoubleWord(dword, addr);
                                }
                                break;
                    
                            case 'h':
                                if(sscanf(line+2, "%lx %hx", &addr, &hword) == 2)
                                {
                                        printf("%08lx <- %04hx\n", addr, hword);
                                        doWriteMemHalfWord(hword, addr);
                                }
                                break;
                    
                            case 'b':
                                if(sscanf(line+2, "%lx %hx", &addr, &hword) == 2)
                                {
                                        printf("%08lx <- %02x\n", addr, (BYTE)hword);
                                        doWriteMemByte((BYTE)hword, addr);
                                }
                                break;
                        }

                        break;
            

            
         
                    case 'm':
                        if(sscanf(line + 1, "%lx %d", &addr, &n) == 2)
                        {
                                for(i=0; i<n; i++)
                                {
                                        printf("%02x%s", doReadMemByte(addr + i), ((i%16) == 15)?"\n":((i%4) == 3)?" ":"");
                                }
                                
                                if((n%16) != 0)
                                        putchar('\n');
                                
                        }
                        else
                                puts("n64_cpu_debugger: 'm addr length'\n"
                                     "                  prints length bytes of n64 mem starting @ addr\n");
                        break;


         

         
         case 'x':
            switch(line[1])
            {
               case 'v':
                  rsp_print_v();
                  break;
               case 'r':
                  rsp_print_r();
                  break;
               case 't':
                  puts("TLB:\n");
                  for(i=0; i<32; i++)
                  {
                     printf("reg.tlb[%02d].hh = %08lx\n", i, reg.tlb[i].hh);
                     printf("reg.tlb[%02d].hl = %08lx\n", i, reg.tlb[i].hl);
                     printf("reg.tlb[%02d].lh = %08lx\n", i, reg.tlb[i].lh);
                     printf("reg.tlb[%02d].ll = %08lx\n", i, reg.tlb[i].ll);
                     printf("reg.tlb[%02d].g  = %1x\n\n",   i, reg.tlb[i].g);
                  }
                  break;
               case 'p':
                  printf("[pc] = %08lx\n", reg.pc);
                  break;
               case 'c':
                  cpu_print_gpr();
                  break;
               case '0':
                  cpu_print_cp0();
                  break;
               case '1':
                  cpu_print_cp1();
                  break;
               case '2':
                  cpu_print_cp2();
                  break;
               case 'm':   /* all 'doReadMemXXXX()' have to be changed to access the mem direct! */
                  puts("RDRAM Registers (0x03f0_0000 .. 0x03ff_ffff)");
                  for(i=0; i<=0x24; i+=4)
                  {
                     printf("%08lx ", doReadMemWord(0x03f00000+i));
                     if(!((i+4)%32))
                        putchar('\n');
                  }
                  puts("\n");
                  puts("SP CP0 Registers (0x04040000)");
                  for(i=0; i<=0x1c; i+=4)
                  {
                     printf("%08lx ", doReadMemWord(0x4040000+i));
                     if(!((i+4)%32))
                        putchar('\n');
                  }
                  putchar('\n');
                  puts("SP_PC_REG (0x04080000) & SP_IBIST_REG (0x04080004)");
                  printf("%08lx %08lx\n\n", mem.sp_reg_pc, mem.sp_reg_ibist);
                  puts("DP Command Registers (0x04100000)");
                  for(i=0; i<=0x1c; i+=4)
                  {
                     printf("%08lx ", doReadMemWord(0xffffffff04100000ULL+i));
                     if(!((i+4)%32))
                        putchar('\n');
                  }
                  putchar('\n');
                  puts("DP Span Registers (0x04200000)");
                  for(i=0; i<=0x0c; i+=4)
                  {
                     printf("%08lx ", doReadMemWord(0xffffffff04100000ULL+i));
                     if(!((i+4)%32))
                        putchar('\n');
                  }
                  puts("\n");
                  puts("MIPS Interface (MI) Registers (0x04300000)");
                  for(i=0; i<=0x0c; i+=4)
                  {
                     printf("%08lx ", doReadMemWord(0xffffffff04300000ULL+i));
                     if(!((i+4)%32))
                        putchar('\n');
                  }
                  puts("\n");
                  puts("Video Interface (VI) Registers (0x04400000)");
                  for(i=0; i<=0x34; i+=4)
                  {
                     printf("%08lx ", doReadMemWord(0xffffffff04400000ULL+i));
                     if(!((i+4)%32))
                        putchar('\n');
                  }
                  puts("\n");
                  puts("Audio Interface (AI) Registers (0x04500000)");
                  for(i=0; i<=0x14; i+=4)
                  {
                     printf("%08lx ", doReadMemWord(0xffffffff04500000ULL+i));
                     if(!((i+4)%32))
                        putchar('\n');
                  }
                  puts("\n");
                  puts("Peripheral Interface (PI) Registers (0x04600000)");
                  for(i=0; i<=0x30; i+=4)
                  {
                     printf("%08lx ", doReadMemWord(0xffffffff04600000ULL+i));
                     if(!((i+4)%32))
                        putchar('\n');
                  }
                  puts("\n");
                  puts("RDRAM Interface (RI) Registers (0x04700000)");
                  for(i=0; i<=0x1c; i+=4)
                  {
                     printf("%08lx ", doReadMemWord(0xffffffff04700000ULL+i));
                     if(!((i+4)%32))
                        putchar('\n');
                  }
                  putchar('\n');
                  puts("Serial Interface (SI) Registers (0x04800000)");
                  for(i=0; i<=0x18; i+=4)
                  {
                     printf("%08lx ", doReadMemWord(0xffffffff04800000ULL+i));
                     if(!((i+4)%32))
                        putchar('\n');
                  }
                  puts("\n");
                  break;
               default:
                  printf("use: xr, x0, x1, x2, xm or xp!\n");
                  break;
                        }
                        break;
         
                }
        }
        while(line[0] != '!');



        if(line)
        {
                free(line);
                line = NULL;
        }



        dispatch(SHUTDOWN, 0);

} /* void n64_cpu_debugger() */





void n64_rsp_debugger()
{
        char    *line;



        do
        {
                line = get_line("TR-RSP-debug> ");

                n64_rsp_debugger_switch(line);

        }
        while(line[0] != 'C' && line[0] != '!');

} /* void n64_rsp_debugger() */





static void n64_rsp_debugger_switch(char line[])
{
        static int      do_not_branch = 0;
        
        int     i, j, n;
        WORD    addr;
        HWORD   hword;
        WORD    word;
        DWORD   dword;



        switch(line[0])
        {
            case 'T':
                do
                {
                        rsp_step();
                }
                while(!rsp_reg.halt);
                rsp_print_r();
                line[0] = 'C';
                break;



            case 'N':
                if(do_not_branch)
                {
                        do_not_branch = 0;
                        puts("Message: Branch and jump enabled"); fflush(stdout);
                }
                else
                {
                        do_not_branch = 1;
                        puts("Message: Branch and jump disabled"); fflush(stdout);
                }
                break;



            case 'n':
                rsp_reg.delay = NO_RSP_DELAY;
                break;



            case 'j':
                if(sscanf(line+1, "%lx", &word) == 1)
                {
                        mem.sp_reg_pc = word;
                }
                else
                {
                        fputs("n64_rsp_debugger: Use 'j addr' sets rsp pc to addr\n", stderr);
                }
                break;



            case 'F':
                n64_rsp_debugger_files();
                return;



            case 'C':
                return;



            case 'R':
                dispatch(EMU_RESET, 0);
                break;



            case 'h':
            case 'H':
                fputs("n64_rsp_debugger: No help right now. Look at source code!\n"
                     "(Exit rsp debugger with 'C')\n\n", stderr);
                break;

            
            
            case 'd':
                if(sscanf(line+1, "%llx", &dword) == 1)
                        prefs.debug = dword;
                else
                        print_debugging_options();
                break;
                
    
    
            case '.':
                if(sscanf(line+1, "%x", &n) == 1)
                {
                        switch(n)
                        {
                            case 0:
                                rsp_reg.halt = 0;
                                break;

                            case 1:
                                rsp_reg.halt = 1;
                                break;
                        
                        } /* switch(n) */
                        break;
                        
                } /* if(sscanf(line+1, "%x", &n) == 1) */
                
                fputs("n64_rsp_debugger: Use '. n' set/reset halt state\n"
                      "          n = 0: rsp run\n"
                      "          n = 1: rsp halt\n\n", stderr);
                
                break;
                
    
    
            case 'J':
                for(;;)
                {
#ifdef HALT
                        if(rsp_reg.halt)
                        {
                                rsp_reg.halt = 0;
                                break;
                        }
#endif
                        rsp_step();
                }
                break;


    
#if DISPLAY_SUPPORT
            case 'r':
                dispatch(DISPLAY_REFRESH, 0);
                break;
#endif
    

    
            case 'b':
                if(sscanf(line+1, "%lx", &addr) == 1)
                {
                        breakp[0] += 1;
                        breakp[ breakp[0] ] = addr;
       
                        printf("Breakpoint #%d set @ %08lx\n", (int)breakp[0], breakp[ breakp[0] ]);
                }
                else if(line[1] == '-')
                {
                        if(breakp[0] > 0)
                        {
                                breakp[0] -= 1;

                                printf("Breakpoint #%d removed\n", (int)breakp[0] + 1);
                        }
                        else
                                printf("There is no breakpoint to remove (set one!)\n");
          
                }
                else if(line[1] == 'l')
                {
                        for(i=1; i<=breakp[0]; i++)
                                printf("Breakpoint #%d: %08lx\n", i, breakp[i]);
                        putchar('\n');
                }
                else
                {
                        fputs("n64_rsp_debugger: 'b pos' ... sets breakpoint @ pos\n"
                              "          'b-'    ... remove last breakpoint\n"
                              "          'bl'    ... lists all breakpoints\n\n'", stderr);
                }
                break;


            
            case 't':
                if(sscanf(line + 1, "%llu", &dword) == 1)
                {
                        for(i=0; i<dword; i++)
                        {
#ifdef HALT
                                if(rsp_reg.halt)
                                        break;
#endif
                                rsp_step();

                                if(do_not_branch && (rsp_reg.delay == EXEC_RSP_DELAY))
                                {
                                        puts("Message: You disabled branch and jump - so I will not"); fflush(stdout);
                                        rsp_reg.delay = NO_RSP_DELAY;
                                }

                                for(j=1; j<=breakp[0]; j++)
                                        if(mem.sp_reg_pc == breakp[j])
                                        {
                                                printf("\nBreakpoint #%d @ %08lx ([count]=%016llx) reached\n\n", j, breakp[j], reg.cpr[0][COUNT]);
                                                dword = 0;
                                                break;
                                        }

                        } /* for(i=0; i<dword; i++) */
                }
                else
                {
                        rsp_step();
                        if(do_not_branch && (rsp_reg.delay == EXEC_RSP_DELAY))
                        {
                                puts("Message: You disabled branch and jump - so I will not"); fflush(stdout);
                                rsp_reg.delay = NO_RSP_DELAY;
                        }
                }

                break;
    
            
            
            case 'l':
                switch(line[1])
                {
                    case 'w':
                        if(sscanf(line + 2, "%lx", &addr) == 1)
                        {
                                printf("%lx: %08lx\n", addr, doReadMemWord(addr));
                        }
                        break;
                    case 'd':
                        if(sscanf(line + 2, "%lx", &addr) == 1)
                        {
                                printf("%lx: %016llx\n", addr, doReadMemDoubleWord(addr));
                        }
                        break;
                    case 'h':
                        if(sscanf(line + 2, "%lx", &addr) == 1)
                        {
                                printf("%lx: %04hx\n", addr, doReadMemHalfWord(addr));
                        }
                        break;
                    case 'b':
                        if(sscanf(line + 2, "%lx", &addr) == 1)
                        {
                                printf("%lx: %02x\n", addr, doReadMemByte(addr));
                        }
                        break;
                }
                break;
            

            
            case 's':
                switch(line[1])
                {
                    case 'w':
                        if(sscanf(line+2, "%lx %lx", &addr, &word) == 2)
                        {
                                printf("%08lx <- %08lx\n", addr, word);
                                doWriteMemWord(word, addr);
                        }
                        break;
            
                    case 'd':
                        if(sscanf(line+2, "%lx %llx", &addr, &dword) == 2)
                        {
                                printf("%08lx <- %016llx\n", addr, dword);
                                doWriteMemDoubleWord(dword, addr);
                        }
                        break;
            
                    case 'h':
                        if(sscanf(line+2, "%lx %hx", &addr, &hword) == 2)
                        {
                                printf("%08lx <- %04hx\n", addr, hword);
                                doWriteMemHalfWord(hword, addr);
                        }
                        break;
            
                    case 'b':
                        if(sscanf(line+2, "%lx %hx", &addr, &hword) == 2)
                        {
                                printf("%08lx <- %02x\n", addr, (BYTE)hword);
                                doWriteMemByte((BYTE)hword, addr);
                        }
                        break;
                }

                break;
    

    
 
            case 'm':
                if(sscanf(line + 1, "%lx %d", &addr, &n) == 2)
                {
                        for(i=0; i<n; i++)
                        {
                                printf("%02x%s", doReadMemByte(addr + i), ((i%16) == 15)?"\n":((i%4) == 3)?" ":"");
                        }
                        
                        if((n%16) != 0)
                                putchar('\n');
                        
                }
                else
                        puts("n64_rsp_debugger: 'm addr length'\n"
                             "                  prints length bytes of n64 mem starting @ addr\n");
                break;


 

            case 'x':
                switch(line[1])
                {
                    case 'v':
                        rsp_print_v();
                        break;
                    case 'r':
                        rsp_print_r();
                        break;
                    case 't':
                        puts("TLB:\n");
                        for(i=0; i<32; i++)
                        {
                                printf("reg.tlb[%02d].hh = %08lx\n", i, reg.tlb[i].hh);
                                printf("reg.tlb[%02d].hl = %08lx\n", i, reg.tlb[i].hl);
                                printf("reg.tlb[%02d].lh = %08lx\n", i, reg.tlb[i].lh);
                                printf("reg.tlb[%02d].ll = %08lx\n", i, reg.tlb[i].ll);
                                printf("reg.tlb[%02d].g  = %1x\n\n", i, reg.tlb[i].g);
                        }
                        break;
                    case 'p':
                        printf("[pc] = %08lx\n", reg.pc);
                        break;
                    case 'c':
                        cpu_print_gpr();
                        break;
                    case '0':
                        cpu_print_cp0();
                        break;
                    case '1':
                        cpu_print_cp1();
                        break;
                    case '2':
                        cpu_print_cp2();
                        break;
                    case 'm':   /* all 'doReadMemXXXX()' have to be changed to access the mem direct! */
                        puts("RDRAM Registers (0x03f0_0000 .. 0x03ff_ffff)");
                        for(i=0; i<=0x24; i+=4)
                        {
                                printf("%08lx ", doReadMemWord(0x03f00000+i));
                                if(!((i+4)%32))
                                        putchar('\n');
                        }
                        puts("\n");
                        puts("SP CP0 Registers (0x04040000)");
                        for(i=0; i<=0x1c; i+=4)
                        {
                                printf("%08lx ", doReadMemWord(0x4040000+i));
                                if(!((i+4)%32))
                                putchar('\n');
                        }
                        putchar('\n');
                        puts("SP_PC_REG (0x04080000) & SP_IBIST_REG (0x04080004)");
                        printf("%08lx %08lx\n\n", mem.sp_reg_pc, mem.sp_reg_ibist);
                        puts("DP Command Registers (0x04100000)");
                        for(i=0; i<=0x1c; i+=4)
                        {
                                printf("%08lx ", doReadMemWord(0xffffffff04100000ULL+i));
                                if(!((i+4)%32))
                                        putchar('\n');
                        }
                        putchar('\n');
                        puts("DP Span Registers (0x04200000)");
                        for(i=0; i<=0x0c; i+=4)
                        {
                                printf("%08lx ", doReadMemWord(0xffffffff04100000ULL+i));
                                if(!((i+4)%32))
                                        putchar('\n');
                        }
                        puts("\n");
                        puts("MIPS Interface (MI) Registers (0x04300000)");
                        for(i=0; i<=0x0c; i+=4)
                        {
                                printf("%08lx ", doReadMemWord(0xffffffff04300000ULL+i));
                                if(!((i+4)%32))
                                        putchar('\n');
                        }
                        puts("\n");
                        puts("Video Interface (VI) Registers (0x04400000)");
                        for(i=0; i<=0x34; i+=4)
                        {
                                printf("%08lx ", doReadMemWord(0xffffffff04400000ULL+i));
                                if(!((i+4)%32))
                                        putchar('\n');
                        }
                        puts("\n");
                        puts("Audio Interface (AI) Registers (0x04500000)");
                        for(i=0; i<=0x14; i+=4)
                        {
                                printf("%08lx ", doReadMemWord(0xffffffff04500000ULL+i));
                                if(!((i+4)%32))
                                        putchar('\n');
                        }
                        puts("\n");
                        puts("Peripheral Interface (PI) Registers (0x04600000)");
                        for(i=0; i<=0x30; i+=4)
                        {
                                printf("%08lx ", doReadMemWord(0xffffffff04600000ULL+i));
                                if(!((i+4)%32))
                                        putchar('\n');
                        }
                        puts("\n");
                        puts("RDRAM Interface (RI) Registers (0x04700000)");
                        for(i=0; i<=0x1c; i+=4)
                        {
                                printf("%08lx ", doReadMemWord(0xffffffff04700000ULL+i));
                                if(!((i+4)%32))
                                        putchar('\n');
                        }
                        putchar('\n');
                        puts("Serial Interface (SI) Registers (0x04800000)");
                        for(i=0; i<=0x18; i+=4)
                        {
                                printf("%08lx ", doReadMemWord(0xffffffff04800000ULL+i));
                                if(!((i+4)%32))
                                        putchar('\n');
                        }
                        puts("\n");
                        break;
                    default:
                        printf("use: xr, x0, x1, x2, xm or xp!\n");
                        break;
                }
                break;
         
        }
} /* static void n64_rsp_debugger_switch(char line[]) */





static void n64_rsp_debugger_files()
{
        char    name[81];
        FILE    *fd_dmem, *fd_imem;



        fputs("DMEM binary: ", stdout);
        scanf("%80s", name);
        
        fd_dmem = fopen(name, "rb");
        if(fd_dmem == NULL)
        {
                fprintf(stderr, "n64_rsp_debugger: ERROR while opening file '%s'\n", name);
                perror("n64_rsp_debugger");
                return;
        }

        fputs("IMEM binary: ", stdout);
        scanf("%80s", name);
        
        fd_imem = fopen(name, "rb");
        if(fd_imem == NULL)
        {
                fclose(fd_dmem);
                fprintf(stderr, "n64_rsp_debugger: ERROR while opening file '%s'\n", name);
                perror("n64_rsp_debugger");
                return;
        }



        if(fread(mem.sp_dmem, 0x1000, 1, fd_dmem) != 1)
        {
                fclose(fd_dmem);
                fclose(fd_imem);
                fputs("n64_rsp_debugger: ERROR while reading DMEM file\n", stderr);
                perror("n64_rsp_debugger");
                return;
        }

        if(fread(mem.sp_imem, 0x1000, 1, fd_imem) != 1)
        {
                fclose(fd_dmem);
                fclose(fd_imem);
                fputs("n64_rsp_debugger: ERROR while reading IMEM file\n", stderr);
                perror("n64_rsp_debugger");
                return;
        }



        fclose(fd_dmem);
        fclose(fd_imem);

} /* static void n64_rsp_debugger_files() */





void print_debugging_options()
{
        fputs("n64_cpu_debugger: Use 'd n' set debugging to level n\n"
              "          Currently supported n values (don't type '0x' and '_'!)\n"
              "\n"
              "          DBG_CPU_INSTR         0x0000_0000_0000_0001\n"
              "          DBG_CPU_COUNT         0x0000_0000_0000_0002\n"
              "          DBG_CPU_REG           0x0000_0000_0000_0004\n"
#ifdef NATIVE
              "          DBG_NATIVE            0x0000_0000_0000_0008\n"
#endif
              "          DBG_RSP_INSTR         0x0000_0000_0000_0010\n"
              "          DBG_RSP_COUNT         0x0000_0000_0000_0020\n"
              "          DBG_RSP_REG           0x0000_0000_0000_0040\n"
              "          DBG_RDP               0x0000_0000_0000_0080\n"
              "\n"
              "          DBG_INTR_COMP         0x0000_0000_0000_0100\n"
              "          DBG_INTR_VI           0x0000_0000_0000_0200\n"
              "          DBG_INTR_SI           0x0000_0000_0000_0400\n"
              "          DBG_INTR_SP           0x0000_0000_0000_0800\n"
              "          DBG_INTR_PI           0x0000_0000_0000_1000\n"
              "          DBG_INTR_AI           0x0000_0000_0000_2000\n"
              "          DBG_INTR_DP           0x0000_0000_0000_4000\n"
              "\n"
              "          DBG_MEMORY            0x0000_0000_0001_0000\n"
              "          DBG_RD_RAM            0x0000_0000_0002_0000\n"
              "          DBG_RD_REG            0x0000_0000_0004_0000\n"
              "          DBG_SP_DMEM           0x0000_0000_0008_0000\n"
              "          DBG_SP_IMEM           0x0000_0000_0010_0000\n"
              "          DBG_SP_REG            0x0000_0000_0020_0000\n"
              "          DBG_SP_PC_REG         0x0000_0000_0040_0000\n"
              "          DBG_SP_IBIST_REG      0x0000_0000_0080_0000\n"
              "          DBG_DPC_REG           0x0000_0000_0100_0000\n"
              "          DBG_DPS_REG           0x0000_0000_0200_0000\n"
              "          DBG_MI_REG            0x0000_0000_0400_0000\n"
              "          DBG_VI_REG            0x0000_0000_0800_0000\n"
              "          DBG_AI_REG            0x0000_0000_1000_0000\n"
              "          DBG_PI_REG            0x0000_0000_2000_0000\n"
              "          DBG_RI_REG            0x0000_0000_4000_0000\n"
              "          DBG_SI_REG            0x0000_0000_8000_0000\n"
              "          DBG_PI_DOM2_ADDR1     0x0000_0001_0000_0000\n"
              "          DBG_PI_DOM1_ADDR1     0x0000_0002_0000_0000\n"
              "          DBG_PI_DOM2_ADDR2     0x0000_0004_0000_0000\n"
              "          DBG_PI_DOM1_ADDR2     0x0000_0008_0000_0000\n"
              "          DBG_PI_ROM            0x0000_0010_0000_0000\n"
              "          DBG_PI_RAM            0x0000_0020_0000_0000\n"
              "          DBG_PI_DOM1_ADDR3     0x0000_0040_0000_0000\n"
              "\n"
              "          DBG_DISP_REFRESH      0x0000_1000_0000_0000\n"
              "          DBG_DISP_MODE         0x0000_2000_0000_0000\n"
              "\n"
              "          DBG_CONTR_PIF         0x0001_0000_0000_0000\n"
              "          DBG_CONTR_BUTTONS     0x0002_0000_0000_0000\n"
              "\n"
              "          DBG_AUDIO             0x0008_0000_0000_0000\n"
              "\n"
              "          DBG_EXC_OV            0x0010_0000_0000_0000\n"
              "          DBG_EXC_FPE           0x0020_0000_0000_0000\n"
              "          DBG_EXC_TR            0x0040_0000_0000_0000\n"
              "          DBG_EXC_BP            0x0080_0000_0000_0000\n"
              "          DBG_EXC_SYS           0x0100_0000_0000_0000\n"
              "          DBG_EXC_RI            0x0200_0000_0000_0000\n"
              "\n", stderr);

} /* void print_debugging_options() */

