home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 13 / MA_Cover_13.bin / source / c / gbe / debug.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-11-12  |  10.3 KB  |  358 lines

  1. /*
  2.  *  gbe - gameboy emulator
  3.  *  Copyright (C) 1999  Chuck Mason, Steven Fuller
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  18.  *
  19.  *
  20.  *  Chuck Mason <chuckjr@sinclair.net>
  21.  *  Steven Fuller <relnev@atdot.org>
  22.  */
  23. #ifdef CPU_DEBUG
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <readline/readline.h>
  29. #include <readline/history.h>
  30.  
  31. #include "mem.h"
  32. #include "cpu.h"
  33. #include "rom.h"
  34. #include "vram.h"
  35. #include "regs.h"
  36. #include "debug.h"
  37.  
  38. static int gbz80_debug_status = 0;
  39. static char *inputline;
  40.  
  41. static void gbz80_debug_exit(gameboy_proc_t *);
  42. static void gbz80_debug_step(gameboy_proc_t *);
  43. static void gbz80_debug_skip(gameboy_proc_t *);
  44. static void gbz80_debug_help(gameboy_proc_t *);
  45. static void gbz80_debug_continue(gameboy_proc_t *);
  46. static void gbz80_debug_run_until(gameboy_proc_t *);
  47. static void gbz80_debug_dumpmem(gameboy_proc_t *);
  48. static void gbz80_stats(gameboy_proc_t *);
  49. static void gbz80_debug_writemem(gameboy_proc_t *);
  50. static void gbz80_debug_setreg(gameboy_proc_t *);
  51. static void gbz80_debug_force_screen(gameboy_proc_t *);
  52. static void gbz80_debug_force_dma(gameboy_proc_t *);
  53.  
  54. static void dump_ptrs(gameboy_proc_t *gbz80)
  55. {
  56.      int i;
  57.      
  58.      for(i =0 ; i < 16; i++) 
  59.           printf("bank %d = %p\n", i, gameboy_memory[i]);
  60. }
  61.  
  62. typedef struct _cmds {
  63.      char cmd;
  64.      char *cmdinfo;
  65.      void (*func)(gameboy_proc_t *);
  66. } command;
  67.  
  68. static command commands[] = {
  69.      { 'h', "Show this help", gbz80_debug_help },
  70.      { '?', "Show this help", gbz80_debug_help },
  71.      { 's', "Step one instruction", gbz80_debug_step },
  72.      { 'k', "Skip next instruction", gbz80_debug_skip },
  73.      { 'c', "Continue execution until invalid opcode", gbz80_debug_continue },
  74.      { 'q', "Exits the debugger (also e)", gbz80_debug_exit },
  75.      { 'e', "Exits the debugger (also q)", gbz80_debug_exit },
  76.      { 'u', "Execute until address", gbz80_debug_run_until },
  77.      { 'd', "Dump memory", gbz80_debug_dumpmem },
  78.      { 'r', "Show processor information", gbz80_stats },
  79.      { 'w', "\"w a b\" writes \'b\' address \'a\' in memory", gbz80_debug_writemem },
  80.      { 'm', "\"m <register or flag> <value>\" sets the register/flag to \'value\'", gbz80_debug_setreg },
  81.      { 'v', "Force video refresh", gbz80_debug_force_screen },
  82.      { 'o', "Force DMA copy", gbz80_debug_force_dma },
  83.      { 'p', "Display all bank pointers\n", dump_ptrs },
  84.      { 0x00, (char *)NULL, gbz80_debug_exit },
  85. };
  86.  
  87. void gbz80_stats(gameboy_proc_t *gbz80)
  88. {
  89.      char instruction[512];
  90.  
  91.      gameboy_cpu_create_instruction(instruction, gbz80);
  92.  
  93.      printf("[AF: $%04X]\t[HL: $%04X]\t[BC: $%04X]\t%s\n"
  94.             "[DE: $%04X]\t[SP: $%04X]\t[PC: $%04X]\t[%c%c%c%c....]\n"
  95.             "[(SP): $%04X]\t[(PC): $%02X - %s]\n",
  96.             gbz80->AF.uw, 
  97.             gbz80->HL.uw,
  98.             gbz80->BC.uw,
  99.             (gbz80->IFF == 1) ? "EI" : "DI",
  100.             gbz80->DE.uw,
  101.             gbz80->SP.uw,
  102.             gbz80->PC.uw,
  103.             (FLAGS_ISZERO(gbz80)) ? 'Z' : 'z',
  104.             (FLAGS_ISNEGATIVE(gbz80)) ? 'N' : 'n',
  105.             (FLAGS_ISHALFCARRY(gbz80)) ? 'H' : 'h',
  106.             (FLAGS_ISCARRY(gbz80)) ? 'C' : 'c',
  107.             memory_read_word(gbz80->SP.uw),
  108.             memory_read_byte(gbz80->PC.uw),
  109.             instruction
  110.             );
  111. }
  112.  
  113.      
  114. void gbz80_debugger(gameboy_proc_t *gbz80)
  115. {
  116.      char *in;
  117.      char cmd;
  118.      int oldcmd = 0;
  119.      char oldcmdc;
  120.      int i;
  121.  
  122.      /* A just-in-case-er */
  123.      gbe_close_gfx();
  124.      
  125.      gameboy_proc = gbz80;
  126.                
  127.      while(gbz80_debug_status == 0) {
  128.           in = readline("gbz80> ");
  129.           cmd = *in;
  130.           add_history(in);
  131.  
  132.           inputline = in + 1;
  133.                               
  134.           if(strlen(in) == 0 && oldcmd != 0) 
  135.                cmd = oldcmdc;
  136.           else {
  137.                oldcmd = 1;
  138.                oldcmdc = cmd;
  139.           }
  140.           
  141.           for(i = 0; commands[i].cmd != 0x00; i++) {
  142.                if(cmd == commands[i].cmd) {
  143.                     commands[i].func(gbz80);
  144.                     break;
  145.                }
  146.           }
  147.      }
  148. }
  149.  
  150. void gbz80_debug_exit(gameboy_proc_t *gbz80)
  151. {
  152.      gbz80_debug_status = 1;
  153. }
  154.  
  155. void gbz80_debug_step(gameboy_proc_t *gbz80)
  156. {
  157.      gameboy_cpu_execute_opcode();
  158.      gbz80_stats(gbz80);
  159. }
  160.  
  161. void gbz80_debug_skip(gameboy_proc_t *gbz80)
  162. {
  163.      gbz80->PC.uw ++;
  164.      gbz80_stats(gbz80);
  165. }
  166.  
  167. void gbz80_debug_help(gameboy_proc_t *gbz80)
  168. {
  169.      int i;
  170.      for(i = 0; commands[i].cmd != 0x00; i++) 
  171.           printf("%c - %s\n", commands[i].cmd, commands[i].cmdinfo);
  172. }
  173.  
  174. void gbz80_debug_continue(gameboy_proc_t *gbz80)
  175. {
  176.      for(gbz80->running = 1; gbz80->running; )
  177.           gameboy_cpu_execute_opcode();
  178.      gbz80_stats(gbz80);
  179. }
  180.  
  181. void gbz80_debug_run_until(gameboy_proc_t *gbz80)
  182. {
  183.      unsigned short int address = 0;
  184.  
  185.      if(*inputline == ' ')
  186.           inputline++;
  187.      address = strtoul(inputline, NULL, 16) & 0xFFFF;
  188.           
  189.      for(gbz80->running = 1; gbz80->running && gbz80->PC.uw != address; )
  190.           gameboy_cpu_execute_opcode();
  191.      gbz80_stats(gbz80);
  192. }
  193.  
  194. void gbz80_debug_dumpmem(gameboy_proc_t *gbz80)
  195. {
  196.      unsigned short int address = 0;
  197.      int i, j, k;
  198.      
  199.      if(*inputline == ' ')
  200.           inputline++;
  201.      address = strtoul(inputline, NULL, 16) & 0xFFFF;
  202.      
  203.      for(j = 0; j < 16; j++) {
  204.           printf("%04X: ", address + (j * 16));
  205.           for(k = 0; k < 2; k++) {
  206.                for(i = 0; i < 16; i++) {
  207.                     int offs = address + (j * 16) + i;
  208.                     unsigned char b;
  209.                     
  210.                     b = memory_read_byte(offs);
  211.                     
  212.                     if(k == 0) {
  213.                          printf("%02X ", b);
  214.                          if(i == 7)
  215.                               printf("- ");
  216.                     } else {
  217.                          printf("%c", isprint(b) ? b : '.');
  218.                     }
  219.                }
  220.           }
  221.           printf("\n");
  222.      }
  223. }
  224.  
  225. void gbz80_debug_writemem(gameboy_proc_t *gbz80)
  226. {
  227.      unsigned short int address = 0;
  228.      unsigned char value = 0;
  229.      char *ptr;
  230.      
  231.      if(*inputline == ' ')
  232.           inputline++;
  233.      
  234.      if((ptr = strchr(inputline, ' ')) == NULL) {
  235.           printf("gbz80_debugger: expected arguments\n");
  236.           return;
  237.      }
  238.      *ptr++ = '\0';
  239.      address = strtoul(inputline, NULL, 16) & 0xFFFF;
  240.      value = strtoul(ptr, NULL, 16) & 0xFF;
  241.  
  242.      memory_write_byte(address, value);
  243.      
  244.      printf("gbz80_debugger: wrote 0x%02X to 0x%04X\n", value, address);
  245. }
  246.  
  247. void gbz80_debug_setreg(gameboy_proc_t *gbz80)
  248. {
  249.      char *regname;
  250.      unsigned short int value;
  251.      
  252.      if(*inputline == ' ')
  253.           inputline++;
  254.      
  255.      if(strlen(inputline) == 0) {  /* help */
  256.           printf("gbz80_debugger: possible Registers are:\n");
  257.           printf("\t16bit: PC AF BC DE HL SP\n");
  258.           printf("\t 8bit: A B C D E F H L\n");
  259.           printf("\tflags: zero halfcarry carry negative IFF\n");
  260.           return;
  261.      }
  262.      
  263.      regname = inputline;
  264.      
  265.      if((inputline = strchr(inputline, ' ')) == NULL) {
  266.           printf("gbz80_debugger: expected arguments\n");
  267.           return;
  268.      }
  269.      *inputline++ = '\0';
  270.      
  271.      value = strtoul(inputline, NULL, 16) & 0xFFFF;
  272.      
  273.      if(strcasecmp(regname, "AF") == 0) 
  274.           gbz80->AF.uw = value;
  275.      else if(strcasecmp(regname, "PC") == 0)
  276.           gbz80->PC.uw = value;
  277.      else if(strcasecmp(regname, "BC") == 0)
  278.           gbz80->BC.uw = value;
  279.      else if(strcasecmp(regname, "DE") == 0)
  280.           gbz80->DE.uw = value;
  281.      else if(strcasecmp(regname, "HL") == 0)
  282.           gbz80->HL.uw = value;
  283.      else if(strcasecmp(regname, "SP") == 0)
  284.           gbz80->SP.uw = value;
  285.      else if(strcasecmp(regname, "A") == 0)
  286.           gbz80->AF.b.h = value & 0xFF;
  287.      else if(strcasecmp(regname, "B") == 0)
  288.           gbz80->BC.b.h = value & 0xFF;
  289.      else if(strcasecmp(regname, "C") == 0)
  290.           gbz80->BC.b.l = value & 0xFF;
  291.      else if(strcasecmp(regname, "D") == 0)
  292.           gbz80->DE.b.h = value & 0xFF;
  293.      else if(strcasecmp(regname, "E") == 0)
  294.           gbz80->DE.b.l = value & 0xFF;
  295.      else if(strcasecmp(regname, "F") == 0)
  296.           gbz80->AF.b.l = value & 0xFF;
  297.      else if(strcasecmp(regname, "H") == 0)
  298.           gbz80->HL.b.h = value & 0xFF;
  299.      else if(strcasecmp(regname, "L") == 0)
  300.           gbz80->HL.b.l = value & 0xFF;
  301.      else if(strcasecmp(regname, "ZERO") == 0) {
  302.           if(value) 
  303.                FLAGS_SET(gbz80, FLAGS_ZERO);
  304.           else
  305.                FLAGS_CLEAR(gbz80, FLAGS_ZERO);
  306.      } else if(strcasecmp(regname, "CARRY") == 0) {
  307.           if(value)
  308.                FLAGS_SET(gbz80, FLAGS_CARRY);
  309.           else
  310.                FLAGS_CLEAR(gbz80, FLAGS_CARRY);
  311.      } else if(strcasecmp(regname, "HALFCARRY") == 0) {
  312.           if(value) 
  313.                FLAGS_SET(gbz80, FLAGS_HALFCARRY);
  314.           else
  315.                FLAGS_CLEAR(gbz80, FLAGS_HALFCARRY);
  316.      } else if(strcasecmp(regname, "NEGATIVE") == 0) {
  317.           if(value)
  318.                FLAGS_SET(gbz80, FLAGS_NEGATIVE);
  319.           else
  320.                FLAGS_CLEAR(gbz80, FLAGS_NEGATIVE);
  321.      } else if(strcasecmp(regname, "IFF") == 0) {
  322.           gbz80->IFF = (value) ? 1 : 0;
  323.      } else {
  324.           printf("gbz80_debugger: unknown register \'%s\'\n", regname);
  325.           return;
  326.      }
  327.      
  328.      printf("gbz80_debugger: \'%s\' set to %X\n", regname, value);
  329.      return;
  330. }
  331.  
  332. void gbz80_debug_force_screen(gameboy_proc_t *gbz80)
  333. {
  334.      unsigned char temp;
  335.      temp = CURLINE;
  336.      
  337.      for(CURLINE = 0; CURLINE < 144; CURLINE++)
  338.           vram_plot_screen();
  339.      CURLINE = temp;
  340.      vram_blit();
  341. }
  342.  
  343. void gbz80_debug_force_dma(gameboy_proc_t *gbz80)
  344. {
  345.      gameboy_do_dma();
  346. }
  347.           
  348. #else
  349.  
  350. #include <stdio.h>
  351.  
  352. void gbz80_debugger(void *garbage)
  353. {
  354.      printf("Debugger not available!\n");
  355. }
  356.  
  357. #endif
  358.