summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/debug/debugcmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/debug/debugcmt.c')
-rw-r--r--src/emu/debug/debugcmt.c570
1 files changed, 570 insertions, 0 deletions
diff --git a/src/emu/debug/debugcmt.c b/src/emu/debug/debugcmt.c
new file mode 100644
index 00000000000..fd532f1d904
--- /dev/null
+++ b/src/emu/debug/debugcmt.c
@@ -0,0 +1,570 @@
+/***************************************************************************
+
+ debugcmt.c
+
+ Debugger code-comment management functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Debugger comment file format:
+
+ (from comment struct - assuming (MAX_COMMENT_LINE_LENGTH == 128))
+ 0 - valid byte
+ 1:4 - address
+ 5:133 - comment
+ 134:138 - color
+ 139:142 - instruction crc
+
+***************************************************************************/
+
+#include "driver.h"
+#include "xmlfile.h"
+#include "debugcmt.h"
+#include "debugcpu.h"
+#include "debugvw.h"
+#include "info.h"
+#include <zlib.h>
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+//#define VERBOSE
+
+#ifdef VERBOSE
+#define TRACE(x) do {x;} while (0)
+#else
+#define TRACE(x)
+#endif
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define COMMENT_VERSION (1)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _debug_comment debug_comment;
+struct _debug_comment
+{
+ UINT8 is_valid;
+ UINT32 address;
+ char text[DEBUG_COMMENT_MAX_LINE_LENGTH];
+ rgb_t color;
+ UINT32 crc;
+};
+
+typedef struct _comment_group comment_group;
+struct _comment_group
+{
+ int comment_count;
+ UINT32 change_count;
+ debug_comment *comment_info[DEBUG_COMMENT_MAX_NUM];
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static comment_group *debug_comments;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static int debug_comment_load_xml(mame_file *file);
+static void debug_comment_exit(running_machine *machine);
+static void debug_comment_free(void);
+
+
+
+/***************************************************************************
+
+ Initialization
+
+***************************************************************************/
+
+/*-------------------------------------------------------------------------
+ debug_comment_init - initializes the comment memory and
+ loads any existing comment file
+-------------------------------------------------------------------------*/
+
+int debug_comment_init(running_machine *machine)
+{
+ /* allocate enough comment groups for the total # of cpu's */
+ debug_comments = (comment_group*) auto_malloc(cpu_gettotalcpu() * sizeof(comment_group));
+ memset(debug_comments, 0, cpu_gettotalcpu() * sizeof(comment_group));
+
+ /* automatically load em up */
+ debug_comment_load();
+
+ add_exit_callback(machine, debug_comment_exit);
+
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_add - adds a comment to the list at the given address.
+ use debug_comment_get_opcode_crc32(addr) to get
+ the proper crc32
+-------------------------------------------------------------------------*/
+
+int debug_comment_add(int cpu_num, offs_t addr, const char *comment, rgb_t color, UINT32 c_crc)
+{
+ int i = 0;
+ int insert_point = debug_comments[cpu_num].comment_count;
+ int match = 0;
+
+ /* Create a new item to insert into the list */
+ debug_comment *insert_me = (debug_comment*) malloc_or_die(sizeof(debug_comment));
+ insert_me->color = color;
+ insert_me->is_valid = 1;
+ insert_me->address = addr;
+ insert_me->crc = c_crc;
+ strcpy(insert_me->text, comment);
+
+ /* Find the insert point */
+ for (i = 0; i < debug_comments[cpu_num].comment_count; i++)
+ {
+ if (insert_me->address < debug_comments[cpu_num].comment_info[i]->address)
+ {
+ insert_point = i;
+ break;
+ }
+ else if (insert_me->address == debug_comments[cpu_num].comment_info[i]->address &&
+ insert_me->crc == debug_comments[cpu_num].comment_info[i]->crc)
+ {
+ insert_point = i;
+ match = 1;
+ break;
+ }
+ }
+
+ /* Got an exact match? Just replace */
+ if (match == 1)
+ {
+ free(debug_comments[cpu_num].comment_info[insert_point]);
+ debug_comments[cpu_num].comment_info[insert_point] = insert_me;
+ debug_comments[cpu_num].change_count++;
+
+ /* force an update of disassembly views */
+ debug_view_update_type(DVT_DISASSEMBLY);
+ return 1;
+ }
+
+ /* Otherwise insert */
+ /* First, shift the list down */
+ for (i = debug_comments[cpu_num].comment_count; i >= insert_point; i--)
+ debug_comments[cpu_num].comment_info[i] = debug_comments[cpu_num].comment_info[i-1];
+
+ /* do the insertion */
+ debug_comments[cpu_num].comment_info[insert_point] = insert_me;
+ debug_comments[cpu_num].comment_count++;
+ debug_comments[cpu_num].change_count++;
+
+ /* force an update of disassembly views */
+ debug_view_update_type(DVT_DISASSEMBLY);
+
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_remove - removes a comment at a given address
+ use debug_comment_get_opcode_crc32(addr) to get
+ the proper crc32
+-------------------------------------------------------------------------*/
+
+int debug_comment_remove(int cpu_num, offs_t addr, UINT32 c_crc)
+{
+ int i;
+ int remove_index = -1;
+
+ for (i = 0; i < debug_comments[cpu_num].comment_count; i++)
+ {
+ if (debug_comments[cpu_num].comment_info[i]->address == addr) /* got an address match */
+ {
+ if (debug_comments[cpu_num].comment_info[i]->crc == c_crc)
+ {
+ remove_index = i;
+ }
+ }
+ }
+
+ /* The comment doesn't exist? */
+ if (remove_index == -1)
+ return 0;
+
+ /* Okay, it's there, now remove it */
+ free(debug_comments[cpu_num].comment_info[remove_index]);
+
+ for (i = remove_index; i < debug_comments[cpu_num].comment_count-1; i++)
+ {
+ debug_comments[cpu_num].comment_info[i] = debug_comments[cpu_num].comment_info[i+1];
+ }
+
+ debug_comments[cpu_num].comment_count--;
+ debug_comments[cpu_num].change_count++;
+
+ /* force an update of disassembly views */
+ debug_view_update_type(DVT_DISASSEMBLY);
+
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_get_text - returns the comment for a given addresses
+ use debug_comment_get_opcode_crc32(addr) to get
+ the proper crc32
+-------------------------------------------------------------------------*/
+
+const char *debug_comment_get_text(int cpu_num, offs_t addr, UINT32 c_crc)
+{
+ int i;
+
+ /* inefficient - should use bsearch - but will be a little tricky with multiple comments per addr */
+ for (i = 0; i < debug_comments[cpu_num].comment_count; i++)
+ {
+ if (debug_comments[cpu_num].comment_info[i]->address == addr) /* got an address match */
+ {
+ /* now check the bank information to be sure */
+ if (debug_comments[cpu_num].comment_info[i]->crc == c_crc)
+ {
+ return debug_comments[cpu_num].comment_info[i]->text;
+ }
+ }
+ }
+
+ return 0x00;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_get_count - returns the number of comments
+ for a given cpu number
+-------------------------------------------------------------------------*/
+
+int debug_comment_get_count(int cpu_num)
+{
+ return debug_comments[cpu_num].comment_count;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_get_change_count - returns the change counter
+ for a given cpu number
+-------------------------------------------------------------------------*/
+
+UINT32 debug_comment_get_change_count(int cpu_num)
+{
+ return debug_comments[cpu_num].change_count;
+}
+
+/*-------------------------------------------------------------------------
+ debug_comment_all_change_count - returns the change counter
+ for all cpu's
+-------------------------------------------------------------------------*/
+
+UINT32 debug_comment_all_change_count(void)
+{
+ int i ;
+ UINT32 retVal = 0;
+
+ for (i = 0; i < cpu_gettotalcpu(); i++)
+ retVal += debug_comments[i].change_count ;
+
+ return retVal;
+}
+
+/*-------------------------------------------------------------------------
+ debug_comment_get_opcode_crc32 - magic function that takes all the
+ current state of the debugger and returns a crc32
+ for the opcode at the requested address.
+-------------------------------------------------------------------------*/
+
+UINT32 debug_comment_get_opcode_crc32(offs_t address)
+{
+ const debug_cpu_info *info = debug_get_cpu_info(cpu_getactivecpu());
+ int i;
+ UINT32 crc;
+ UINT8 opbuf[64], argbuf[64];
+ char buff[256];
+ offs_t numbytes;
+ int maxbytes = activecpu_max_instruction_bytes();
+ UINT32 addrmask = (debug_get_cpu_info(cpu_getactivecpu()))->space[ADDRESS_SPACE_PROGRAM].logaddrmask;
+
+ memset(opbuf, 0x00, sizeof(opbuf));
+ memset(argbuf, 0x00, sizeof(argbuf));
+
+ // fetch the bytes up to the maximum
+ for (i = 0; i < maxbytes; i++)
+ {
+ opbuf[i] = debug_read_opcode(address + i, 1, FALSE);
+ argbuf[i] = debug_read_opcode(address + i, 1, TRUE);
+ }
+
+ numbytes = activecpu_dasm(buff, address & addrmask, opbuf, argbuf) & DASMFLAG_LENGTHMASK;
+ numbytes = ADDR2BYTE(numbytes, info, ADDRESS_SPACE_PROGRAM);
+
+ crc = crc32(0, argbuf, numbytes);
+
+ return crc;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_dump - debugging function to dump junk to the command line
+-------------------------------------------------------------------------*/
+
+void debug_comment_dump(int cpu_num, offs_t addr)
+{
+ int i;
+ int ff = 0;
+
+ if (addr == -1)
+ {
+ for (i = 0; i < debug_comments[cpu_num].comment_count; i++)
+ {
+ if (debug_comments[cpu_num].comment_info[i]->is_valid)
+ {
+ logerror("%d : %s (%d %d)\n", i, debug_comments[cpu_num].comment_info[i]->text,
+ debug_comments[cpu_num].comment_info[i]->address,
+ debug_comments[cpu_num].comment_info[i]->crc);
+ }
+ }
+ }
+ else
+ {
+ UINT32 c_crc = debug_comment_get_opcode_crc32(addr);
+
+ for (i = 0; i < debug_comments[cpu_num].comment_count; i++)
+ {
+ if (debug_comments[cpu_num].comment_info[i]->address == addr) /* got an address match */
+ {
+ /* now check the bank information to be sure */
+ if (debug_comments[cpu_num].comment_info[i]->crc == c_crc)
+ {
+ logerror("%d : %s (%d %d)\n", addr,
+ debug_comments[cpu_num].comment_info[addr]->text,
+ debug_comments[cpu_num].comment_info[addr]->address,
+ debug_comments[cpu_num].comment_info[addr]->crc);
+ ff = 1;
+ }
+ }
+ }
+
+ if (!ff) logerror("No comment exists for address : 0x%x\n", addr);
+ }
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_save - comment file saving
+-------------------------------------------------------------------------*/
+
+int debug_comment_save(void)
+{
+ int i, j;
+ char crc_buf[20];
+ xml_data_node *root = xml_file_create();
+ xml_data_node *commentnode, *systemnode;
+ int total_comments = 0;
+
+ /* if we don't have a root, bail */
+ if (!root)
+ return 0;
+
+ /* create a comment node */
+ commentnode = xml_add_child(root, "mamecommentfile", NULL);
+ if (!commentnode)
+ goto error;
+ xml_set_attribute_int(commentnode, "version", COMMENT_VERSION);
+
+ /* create a system node */
+ systemnode = xml_add_child(commentnode, "system", NULL);
+ if (!systemnode)
+ goto error;
+ xml_set_attribute(systemnode, "name", Machine->gamedrv->name);
+
+ /* for each cpu */
+ for (i = 0; i < cpu_gettotalcpu(); i++)
+ {
+ xml_data_node *curnode = xml_add_child(systemnode, "cpu", NULL);
+ if (!curnode)
+ goto error;
+ xml_set_attribute_int(curnode, "num", i);
+
+ for (j = 0; j < debug_comments[i].comment_count; j++)
+ {
+ xml_data_node *datanode = xml_add_child(curnode, "comment", xml_normalize_string(debug_comments[i].comment_info[j]->text));
+ if (!datanode)
+ goto error;
+ xml_set_attribute_int(datanode, "address", debug_comments[i].comment_info[j]->address);
+ xml_set_attribute_int(datanode, "color", debug_comments[i].comment_info[j]->color);
+ sprintf(crc_buf, "%08X", debug_comments[i].comment_info[j]->crc);
+ xml_set_attribute(datanode, "crc", crc_buf);
+ total_comments++;
+ }
+ }
+
+ /* flush the file */
+ if (total_comments > 0)
+ {
+ file_error filerr;
+ astring *fname;
+ mame_file *fp;
+
+ fname = astring_assemble_2(astring_alloc(), Machine->basename, ".cmt");
+ filerr = mame_fopen(SEARCHPATH_COMMENT, astring_c(fname), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &fp);
+ astring_free(fname);
+
+ if (filerr == FILERR_NONE)
+ {
+ xml_file_write(root, mame_core_file(fp));
+ mame_fclose(fp);
+ }
+ }
+
+ /* free and get out of here */
+ xml_file_free(root);
+ return 1;
+
+error:
+ xml_file_free(root);
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_load(_xml) - comment file loading
+-------------------------------------------------------------------------*/
+
+int debug_comment_load(void)
+{
+ file_error filerr;
+ mame_file *fp;
+ astring *fname;
+
+ fname = astring_assemble_2(astring_alloc(), Machine->basename, ".cmt");
+ filerr = mame_fopen(SEARCHPATH_COMMENT, astring_c(fname), OPEN_FLAG_READ, &fp);
+ astring_free(fname);
+
+ if (filerr != FILERR_NONE) return 0;
+ debug_comment_load_xml(fp);
+ mame_fclose(fp);
+
+ return 1;
+}
+
+static int debug_comment_load_xml(mame_file *fp)
+{
+ int i, j;
+ xml_data_node *root, *commentnode, *systemnode, *cpunode, *datanode;
+ const char *name;
+ int version;
+
+ /* read the file */
+ root = xml_file_read(mame_core_file(fp), NULL);
+ if (!root)
+ goto error;
+
+ /* find the config node */
+ commentnode = xml_get_sibling(root->child, "mamecommentfile");
+ if (!commentnode)
+ goto error;
+
+ /* validate the config data version */
+ version = xml_get_attribute_int(commentnode, "version", 0);
+ if (version != COMMENT_VERSION)
+ goto error;
+
+ /* check to make sure the file is applicable */
+ systemnode = xml_get_sibling(commentnode->child, "system");
+ name = xml_get_attribute_string(systemnode, "name", "");
+ if (strcmp(name, Machine->gamedrv->name) != 0)
+ goto error;
+
+ i = 0;
+
+ for (cpunode = xml_get_sibling(systemnode->child, "cpu"); cpunode; cpunode = xml_get_sibling(cpunode->next, "cpu"))
+ {
+ j = 0;
+
+ for (datanode = xml_get_sibling(cpunode->child, "comment"); datanode; datanode = xml_get_sibling(datanode->next, "comment"))
+ {
+ /* Malloc the comment */
+ debug_comments[i].comment_info[j] = (debug_comment*) malloc(sizeof(debug_comment));
+
+ debug_comments[i].comment_info[j]->address = xml_get_attribute_int(datanode, "address", 0);
+ debug_comments[i].comment_info[j]->color = xml_get_attribute_int(datanode, "color", 0);
+ sscanf(xml_get_attribute_string(datanode, "crc", 0), "%08X", &debug_comments[i].comment_info[j]->crc);
+ strcpy(debug_comments[i].comment_info[j]->text, datanode->value);
+ debug_comments[i].comment_info[j]->is_valid = 1;
+
+ j++;
+ }
+
+ debug_comments[i].comment_count = j;
+
+ i++;
+ }
+
+ /* free the parser */
+ xml_file_free(root);
+
+ return 1;
+
+error:
+ if (root)
+ xml_file_free(root);
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_exit - saves the comments and frees memory
+-------------------------------------------------------------------------*/
+
+static void debug_comment_exit(running_machine *machine)
+{
+ debug_comment_save();
+ debug_comment_free();
+}
+
+
+/*-------------------------------------------------------------------------
+ debug_comment_free - cleans up memory
+-------------------------------------------------------------------------*/
+
+static void debug_comment_free(void)
+{
+ int i, j;
+
+ for (i = 0; i < cpu_gettotalcpu(); i++)
+ {
+ for (j = 0; j < debug_comments[i].comment_count; j++)
+ {
+ free(debug_comments[i].comment_info[j]);
+ }
+
+ debug_comments[i].comment_count = 0;
+ }
+}