mame/src/emu/debug/dvbpoints.c

423 lines
13 KiB
C

// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/*********************************************************************
dvbpoints.c
Breakpoint debugger view.
***************************************************************************/
#include "emu.h"
#include "dvbpoints.h"
//**************************************************************************
// DEBUG VIEW BREAK POINTS
//**************************************************************************
static const int tableBreaks[] = { 5, 9, 31, 45, 63, 80 };
//-------------------------------------------------
// debug_view_breakpoints - constructor
//-------------------------------------------------
debug_view_breakpoints::debug_view_breakpoints(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate)
: debug_view(machine, DVT_BREAK_POINTS, osdupdate, osdprivate),
m_sortType(SORT_INDEX_ASCENDING)
{
// fail if no available sources
enumerate_sources();
if (m_source_list.count() == 0)
throw std::bad_alloc();
}
//-------------------------------------------------
// ~debug_view_breakpoints - destructor
//-------------------------------------------------
debug_view_breakpoints::~debug_view_breakpoints()
{
}
//-------------------------------------------------
// enumerate_sources - enumerate all possible
// sources for a disassembly view
//-------------------------------------------------
void debug_view_breakpoints::enumerate_sources()
{
// start with an empty list
m_source_list.reset();
// iterate over devices with disassembly interfaces
disasm_interface_iterator iter(machine().root_device());
for (device_disasm_interface *dasm = iter.first(); dasm != NULL; dasm = iter.next())
{
astring name;
name.printf("%s '%s'", dasm->device().name(), dasm->device().tag());
m_source_list.append(*global_alloc(debug_view_source(name.cstr(), &dasm->device())));
}
// reset the source to a known good entry
set_source(*m_source_list.first());
}
//-------------------------------------------------
// view_click - handle a mouse click within the
// current view
//-------------------------------------------------
void debug_view_breakpoints::view_click(const int button, const debug_view_xy& pos)
{
bool clickedTopRow = (m_topleft.y == pos.y);
if (clickedTopRow)
{
if (pos.x < tableBreaks[0] && m_sortType == SORT_INDEX_ASCENDING)
m_sortType = SORT_INDEX_DESCENDING;
else if (pos.x < tableBreaks[0])
m_sortType = SORT_INDEX_ASCENDING;
else if (pos.x < tableBreaks[1] && m_sortType == SORT_ENABLED_ASCENDING)
m_sortType = SORT_ENABLED_DESCENDING;
else if (pos.x < tableBreaks[1])
m_sortType = SORT_ENABLED_ASCENDING;
else if (pos.x < tableBreaks[2] && m_sortType == SORT_CPU_ASCENDING)
m_sortType = SORT_CPU_DESCENDING;
else if (pos.x < tableBreaks[2])
m_sortType = SORT_CPU_ASCENDING;
else if (pos.x < tableBreaks[3] && m_sortType == SORT_ADDRESS_ASCENDING)
m_sortType = SORT_ADDRESS_DESCENDING;
else if (pos.x < tableBreaks[3])
m_sortType = SORT_ADDRESS_ASCENDING;
else if (pos.x < tableBreaks[4] && m_sortType == SORT_CONDITION_ASCENDING)
m_sortType = SORT_CONDITION_DESCENDING;
else if (pos.x < tableBreaks[4])
m_sortType = SORT_CONDITION_ASCENDING;
else if (pos.x < tableBreaks[5] && m_sortType == SORT_ACTION_ASCENDING)
m_sortType = SORT_ACTION_DESCENDING;
else if (pos.x < tableBreaks[5])
m_sortType = SORT_ACTION_ASCENDING;
}
else
{
// Gather a sorted list of all the breakpoints for all the CPUs
device_debug::breakpoint** bpList = NULL;
const int numBPs = breakpoints(SORT_NONE, bpList);
const int bpIndex = pos.y - 1;
if (bpIndex > numBPs || bpIndex < 0)
return;
// Enable / disable
if (bpList[bpIndex]->enabled())
bpList[bpIndex]->setEnabled(false);
else
bpList[bpIndex]->setEnabled(true);
delete[] bpList;
machine().debug_view().update_all(DVT_DISASSEMBLY);
}
begin_update();
m_update_pending = true;
end_update();
}
void debug_view_breakpoints::pad_astring_to_length(astring& str, int len)
{
int diff = len - str.len();
if (diff > 0)
{
astring buffer;
buffer.expand(diff);
for (int i = 0; i < diff; i++)
buffer.catprintf(" ");
str.catprintf("%s", buffer.cstr());
}
}
// Sorting functors for the qsort function
static int cIndexAscending(const void* a, const void* b)
{
const device_debug::breakpoint* left = *(device_debug::breakpoint**)a;
const device_debug::breakpoint* right = *(device_debug::breakpoint**)b;
return left->index() > right->index();
}
static int cIndexDescending(const void* a, const void* b)
{
const device_debug::breakpoint* left = *(device_debug::breakpoint**)a;
const device_debug::breakpoint* right = *(device_debug::breakpoint**)b;
return left->index() < right->index();
}
static int cEnabledAscending(const void* a, const void* b)
{
const device_debug::breakpoint* left = *(device_debug::breakpoint**)a;
const device_debug::breakpoint* right = *(device_debug::breakpoint**)b;
return left->enabled() < right->enabled();
}
static int cEnabledDescending(const void* a, const void* b)
{
const device_debug::breakpoint* left = *(device_debug::breakpoint**)a;
const device_debug::breakpoint* right = *(device_debug::breakpoint**)b;
return left->enabled() > right->enabled();
}
static int cCpuAscending(const void* a, const void* b)
{
const device_debug::breakpoint* left = *(device_debug::breakpoint**)a;
const device_debug::breakpoint* right = *(device_debug::breakpoint**)b;
const int result = strcmp(left->debugInterface()->device().tag(), right->debugInterface()->device().tag());
return result >= 0;
}
static int cCpuDescending(const void* a, const void* b)
{
const device_debug::breakpoint* left = *(device_debug::breakpoint**)a;
const device_debug::breakpoint* right = *(device_debug::breakpoint**)b;
const int result = strcmp(left->debugInterface()->device().tag(), right->debugInterface()->device().tag());
return result < 0;
}
static int cAddressAscending(const void* a, const void* b)
{
const device_debug::breakpoint* left = *(device_debug::breakpoint**)a;
const device_debug::breakpoint* right = *(device_debug::breakpoint**)b;
return left->address() > right->address();
}
static int cAddressDescending(const void* a, const void* b)
{
const device_debug::breakpoint* left = *(device_debug::breakpoint**)a;
const device_debug::breakpoint* right = *(device_debug::breakpoint**)b;
return left->address() < right->address();
}
static int cConditionAscending(const void* a, const void* b)
{
const device_debug::breakpoint* left = *(device_debug::breakpoint**)a;
const device_debug::breakpoint* right = *(device_debug::breakpoint**)b;
const int result = strcmp(left->condition(), right->condition());
return result >= 0;
}
static int cConditionDescending(const void* a, const void* b)
{
const device_debug::breakpoint* left = *(device_debug::breakpoint**)a;
const device_debug::breakpoint* right = *(device_debug::breakpoint**)b;
const int result = strcmp(left->condition(), right->condition());
return result < 0;
}
static int cActionAscending(const void* a, const void* b)
{
const device_debug::breakpoint* left = *(device_debug::breakpoint**)a;
const device_debug::breakpoint* right = *(device_debug::breakpoint**)b;
const int result = strcmp(left->action(), right->action());
return result >= 0;
}
static int cActionDescending(const void* a, const void* b)
{
const device_debug::breakpoint* left = *(device_debug::breakpoint**)a;
const device_debug::breakpoint* right = *(device_debug::breakpoint**)b;
const int result = strcmp(left->action(), right->action());
return result < 0;
}
int debug_view_breakpoints::breakpoints(SortMode sort, device_debug::breakpoint**& bpList)
{
// Alloc
int numBPs = 0;
bpList = NULL;
for (const debug_view_source *source = m_source_list.first(); source != NULL; source = source->next())
{
const device_debug& debugInterface = *source->device()->debug();
for (device_debug::breakpoint *bp = debugInterface.breakpoint_first(); bp != NULL; bp = bp->next())
numBPs++;
}
bpList = new device_debug::breakpoint*[numBPs];
int bpAddIndex = 0;
for (const debug_view_source *source = m_source_list.first(); source != NULL; source = source->next())
{
// Collect
device_debug& debugInterface = *source->device()->debug();
for (device_debug::breakpoint *bp = debugInterface.breakpoint_first(); bp != NULL; bp = bp->next())
{
bpList[bpAddIndex] = bp;
bpAddIndex++;
}
}
// And now for the sort
switch (m_sortType)
{
case SORT_NONE:
break;
case SORT_INDEX_ASCENDING:
qsort(bpList, numBPs, sizeof(device_debug::breakpoint*), cIndexAscending);
break;
case SORT_INDEX_DESCENDING:
qsort(bpList, numBPs, sizeof(device_debug::breakpoint*), cIndexDescending);
break;
case SORT_ENABLED_ASCENDING:
qsort(bpList, numBPs, sizeof(device_debug::breakpoint*), cEnabledAscending);
break;
case SORT_ENABLED_DESCENDING:
qsort(bpList, numBPs, sizeof(device_debug::breakpoint*), cEnabledDescending);
break;
case SORT_CPU_ASCENDING:
qsort(bpList, numBPs, sizeof(device_debug::breakpoint*), cCpuAscending);
break;
case SORT_CPU_DESCENDING:
qsort(bpList, numBPs, sizeof(device_debug::breakpoint*), cCpuDescending);
break;
case SORT_ADDRESS_ASCENDING:
qsort(bpList, numBPs, sizeof(device_debug::breakpoint*), cAddressAscending);
break;
case SORT_ADDRESS_DESCENDING:
qsort(bpList, numBPs, sizeof(device_debug::breakpoint*), cAddressDescending);
break;
case SORT_CONDITION_ASCENDING:
qsort(bpList, numBPs, sizeof(device_debug::breakpoint*), cConditionAscending);
break;
case SORT_CONDITION_DESCENDING:
qsort(bpList, numBPs, sizeof(device_debug::breakpoint*), cConditionDescending);
break;
case SORT_ACTION_ASCENDING:
qsort(bpList, numBPs, sizeof(device_debug::breakpoint*), cActionAscending);
break;
case SORT_ACTION_DESCENDING:
qsort(bpList, numBPs, sizeof(device_debug::breakpoint*), cActionDescending);
break;
}
return numBPs;
}
//-------------------------------------------------
// view_update - update the contents of the
// breakpoints view
//-------------------------------------------------
void debug_view_breakpoints::view_update()
{
// Gather a list of all the breakpoints for all the CPUs
device_debug::breakpoint** bpList = NULL;
const int numBPs = breakpoints(SORT_NONE, bpList);
// Set the view region so the scroll bars update
m_total.y = numBPs + 1;
if (m_total.y < 10)
m_total.y = 10;
// Draw
debug_view_char *dest = m_viewdata;
for (int row = 0; row < m_visible.y; row++)
{
UINT32 effrow = m_topleft.y + row;
// Header
if (row == 0)
{
astring header;
header.printf("ID");
if (m_sortType == SORT_INDEX_ASCENDING) header.catprintf("\\");
else if (m_sortType == SORT_INDEX_DESCENDING) header.catprintf("/");
pad_astring_to_length(header, tableBreaks[0]);
header.catprintf("En");
if (m_sortType == SORT_ENABLED_ASCENDING) header.catprintf("\\");
else if (m_sortType == SORT_ENABLED_DESCENDING) header.catprintf("/");
pad_astring_to_length(header, tableBreaks[1]);
header.catprintf("CPU");
if (m_sortType == SORT_CPU_ASCENDING) header.catprintf("\\");
else if (m_sortType == SORT_CPU_DESCENDING) header.catprintf("/");
pad_astring_to_length(header, tableBreaks[2]);
header.catprintf("Address");
if (m_sortType == SORT_ADDRESS_ASCENDING) header.catprintf("\\");
else if (m_sortType == SORT_ADDRESS_DESCENDING) header.catprintf("/");
pad_astring_to_length(header, tableBreaks[3]);
header.catprintf("Condition");
if (m_sortType == SORT_CONDITION_ASCENDING) header.catprintf("\\");
else if (m_sortType == SORT_CONDITION_DESCENDING) header.catprintf("/");
pad_astring_to_length(header, tableBreaks[4]);
header.catprintf("Action");
if (m_sortType == SORT_ACTION_ASCENDING) header.catprintf("\\");
else if (m_sortType == SORT_ACTION_DESCENDING) header.catprintf("/");
pad_astring_to_length(header, tableBreaks[5]);
for (int i = 0; i < m_visible.x; i++)
{
dest->byte = (i < header.len()) ? header[i] : ' ';
dest->attrib = DCA_ANCILLARY;
dest++;
}
continue;
}
// Breakpoints
int bpi = effrow-1;
if (bpi < numBPs && bpi >= 0)
{
device_debug::breakpoint* bp = bpList[bpi];
astring buffer;
buffer.printf("%X", bp->index());
pad_astring_to_length(buffer, tableBreaks[0]);
buffer.catprintf("%c", bp->enabled() ? 'X' : 'O');
pad_astring_to_length(buffer, tableBreaks[1]);
buffer.catprintf("%s", bp->debugInterface()->device().tag());
pad_astring_to_length(buffer, tableBreaks[2]);
buffer.catprintf("%s", core_i64_hex_format(bp->address(), bp->debugInterface()->logaddrchars()));
pad_astring_to_length(buffer, tableBreaks[3]);
if (astring(bp->condition()) != astring("1"))
{
buffer.catprintf("%s", bp->condition());
pad_astring_to_length(buffer, tableBreaks[4]);
}
if (astring(bp->action()) != astring(""))
{
buffer.catprintf("%s", bp->action());
pad_astring_to_length(buffer, tableBreaks[5]);
}
for (int i = 0; i < m_visible.x; i++)
{
dest->byte = (i < buffer.len()) ? buffer[i] : ' ';
dest->attrib = DCA_NORMAL;
// Color disabled breakpoints red
if (i == 5 && dest->byte == 'O')
dest->attrib = DCA_CHANGED;
dest++;
}
continue;
}
// Fill the remaining vertical space
for (int i = 0; i < m_visible.x; i++)
{
dest->byte = ' ';
dest->attrib = DCA_NORMAL;
dest++;
}
}
delete[] bpList;
}