ti83-sdk/tool/tilem-src/db/listing.c

380 lines
8.1 KiB
C

/*
* libtilemdb - Utilities for debugging Z80 assembly programs
*
* Copyright (C) 2010 Benjamin Moody
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tilemdb.h"
struct _TilemListingLineCache {
dword minaddr;
dword maxaddr;
int* order;
};
static void sort_lines(TilemListing* lst,
int start, int end)
{
int pivot, ncstart, ncend, n;
dword addr, pivotaddr;
int* order = lst->linecache->order;
pivot = order[start];
pivotaddr = lst->lines[pivot].address;
ncstart = start + 1;
ncend = end;
while (ncstart < ncend) {
n = order[ncstart];
addr = lst->lines[n].address;
if (addr < pivotaddr) {
ncstart++;
}
else {
order[ncstart] = order[ncend - 1];
order[ncend - 1] = n;
ncend--;
}
}
ncstart--;
order[start] = order[ncstart];
order[ncstart] = pivot;
if (ncstart > start + 1)
sort_lines(lst, start, ncstart);
if (end > ncend + 1)
sort_lines(lst, ncend, end);
}
static void ensure_order(TilemListing* lst)
{
int i;
if (lst->nlines == 0) {
lst->linecache->minaddr = 0xffff;
lst->linecache->maxaddr = 0;
}
else if (!lst->linecache->order) {
lst->linecache->order = tilem_new_atomic(int, lst->nlines);
for (i = 0; i < lst->nlines; i++)
lst->linecache->order[i] = i;
sort_lines(lst, 0, lst->nlines);
i = lst->linecache->order[0];
lst->linecache->minaddr = lst->lines[i].address;
i = lst->linecache->order[lst->nlines - 1];
lst->linecache->maxaddr = lst->lines[i].address;
}
}
static void order_destroyed(TilemListing* lst)
{
tilem_free(lst->linecache->order);
lst->linecache->order = NULL;
}
static int first_at_addr(TilemListing* lst, dword addr)
{
int start, end, i;
start = 0;
end = lst->nlines;
while (start < end) {
i = (start + end) / 2;
if (lst->lines[lst->linecache->order[i]].address < addr)
start = i + 1;
else
end = i;
}
return start;
}
TilemListing* tilem_listing_new()
{
TilemListing* lst = tilem_new0(TilemListing, 1);
lst->lines = NULL;
lst->linecache = tilem_new0(TilemListingLineCache, 1);
lst->linecache->order = NULL;
return lst;
}
void tilem_listing_free(TilemListing* lst)
{
int i;
if (!lst)
return;
for (i = 0; i < lst->nlines; i++)
tilem_free(lst->lines[i].text);
tilem_free(lst->lines);
tilem_free(lst->linecache->order);
tilem_free(lst->linecache);
tilem_free(lst);
}
void tilem_listing_file_clear(TilemListing* lst)
{
order_destroyed(lst);
lst->nlines = 0;
lst->nlines_a = 0;
tilem_free(lst->lines);
lst->lines = NULL;
}
void tilem_listing_append_line(TilemListing* lst, int srclinenum, dword address,
int depth, int datasize, const byte* data,
const char* text, int is_expansion)
{
TilemListingLine* line;
int i;
order_destroyed(lst);
lst->nlines++;
if (lst->nlines >= lst->nlines_a) {
lst->nlines_a = lst->nlines * 2;
lst->lines = tilem_renew(TilemListingLine,
lst->lines, lst->nlines_a);
}
line = &lst->lines[lst->nlines - 1];
line->listing = lst;
line->srclinenum = srclinenum;
line->address = address & 0xffff;
line->depth = depth;
if (datasize > TILEM_MAX_LINE_BYTES)
datasize = TILEM_MAX_LINE_BYTES;
line->datasize = datasize;
for (i = 0; i < datasize; i++)
line->data[i] = data[i];
if (text) {
line->text = tilem_new_atomic(char, strlen(text) + 1);
strcpy(line->text, text);
if ((text[0] >= 'A' && text[0] <= 'Z')
|| (text[0] >= 'a' && text[0] <= 'z')
|| (text[0] & 0x80))
line->is_label = 1;
else
line->is_label = 0;
}
else {
line->text = NULL;
line->is_label = 0;
}
line->is_expansion = is_expansion;
}
void tilem_listing_get_address_range(TilemListing* lst, dword* min, dword* max)
{
ensure_order(lst);
if (min)
*min = lst->linecache->minaddr;
if (max)
*max = lst->linecache->maxaddr;
}
TilemListingLine* tilem_listing_line_get_next(TilemListingLine* line)
{
if (!line)
return NULL;
if (line != line->listing->lines + line->listing->nlines)
return line + 1;
else
return NULL;
}
TilemListingLine* tilem_listing_line_get_prev(TilemListingLine* line)
{
if (!line)
return NULL;
if (line != line->listing->lines)
return line - 1;
else
return NULL;
}
TilemListingLine* tilem_listing_get_loaded_line_at_addr(TilemListing* lst,
dword address,
TilemCalc* calc,
int match_internal)
{
int i;
TilemListingLine *line;
ensure_order(lst);
i = first_at_addr(lst, address + 1);
while (--i >= 0) {
line = &lst->lines[lst->linecache->order[i]];
if (match_internal) {
if (line->address + TILEM_MAX_LINE_BYTES <= address)
return NULL;
else if (line->address + line->datasize <= address)
continue;
}
else {
if (line->address != address)
return NULL;
}
if (tilem_listing_line_is_loaded(line, calc))
return line;
}
return NULL;
}
static inline unsigned int getbyte(TilemCalc* calc, dword addr)
{
dword pa = (*calc->hw.mem_ltop)(calc, addr & 0xffff);
return calc->mem[pa];
}
static inline int line_load_count(const TilemListingLine* line, TilemCalc* calc)
{
int i, n;
for (i = n = 0; i < line->datasize; i++)
if (getbyte(calc, line->address + i) == line->data[i])
n++;
return n;
}
static inline TilemListingLine* get_next_local(TilemListingLine* line)
{
TilemListingLine* nline = tilem_listing_line_get_next(line);
if (nline && nline->address != line->address + line->datasize)
return NULL;
else
return nline;
}
static inline TilemListingLine* get_prev_local(TilemListingLine* line)
{
TilemListingLine* nline = tilem_listing_line_get_prev(line);
if (nline && nline->address != line->address + line->datasize)
return NULL;
else
return nline;
}
int tilem_listing_line_is_loaded(TilemListingLine* line, TilemCalc* calc)
{
int nbytes, ngood;
TilemListingLine *nline;
while (line->datasize == 0 && (nline = get_next_local(line)))
line = nline;
if (line_load_count(line, calc) != line->datasize)
return 0;
else {
nbytes = ngood = line->datasize;
nline = line;
while ((nline = get_next_local(nline))
&& nline->address < line->address + 32) {
nbytes += nline->datasize;
ngood += line_load_count(nline, calc);
}
nline = line;
while ((nline = get_prev_local(nline))
&& line->address < nline->address + 32) {
nbytes += nline->datasize;
ngood += line_load_count(nline, calc);
}
return (ngood > nbytes / 2);
}
}
static int bptest_listing_line(TilemCalc* calc, dword addr TILEM_ATTR_UNUSED,
void* data)
{
return tilem_listing_line_is_loaded(data, calc);
}
int tilem_listing_line_add_breakpoint(TilemListingLine* line,
TilemCalc* calc, int bptype,
int match_internal)
{
dword max;
if (match_internal && line->datasize > 0)
max = line->address + line->datasize - 1;
else
max = line->address;
return tilem_z80_add_breakpoint(calc, bptype, line->address, max,
0xffff, &bptest_listing_line,
(void*) line);
}
static int bptest_listing_int(TilemCalc* calc, dword addr, void* data)
{
TilemListing* lst = data;
if (tilem_listing_get_loaded_line_at_addr(lst, addr, calc, 1))
return 1;
else
return 0;
}
static int bptest_listing_top(TilemCalc* calc, dword addr, void* data)
{
TilemListing* lst = data;
if (tilem_listing_get_loaded_line_at_addr(lst, addr, calc, 0))
return 1;
else
return 0;
}
int tilem_listing_add_breakpoint(TilemListing* lst, TilemCalc* calc,
int bptype, int match_internal)
{
dword min, max;
tilem_listing_get_address_range(lst, &min, &max);
return tilem_z80_add_breakpoint(calc, bptype, min, max, 0xffff,
(match_internal
? &bptest_listing_int
: &bptest_listing_top), lst);
}