nesemu/debugger/program_view.c

208 lines
6.6 KiB
C
Raw Permalink Normal View History

2024-01-11 16:02:53 -05:00
//
// Created by william on 10/01/24.
//
2024-01-14 21:59:13 -05:00
#include <stdlib.h>
2024-01-16 15:46:22 -05:00
#include <assert.h>
2024-01-11 16:02:53 -05:00
#include "program_view.h"
#include "../cpu/op.h"
2024-01-16 15:46:22 -05:00
#include "memory_view.h"
2024-04-03 23:03:35 -04:00
#include "keys.h"
#include "dialog.h"
2024-01-16 15:46:22 -05:00
void decode_operands(ProgramView *view) {
int pc = PROGRAM_VIEW_BASE_ADDR;
while (pc < 0xfffa) {
DebugOperand *operand = malloc(sizeof(DebugOperand));
if (operand == NULL) {
perror("Failed to allocate memory for debug operand");
exit(EXIT_FAILURE);
}
2024-01-11 16:02:53 -05:00
2024-05-06 20:23:44 -04:00
byte op_code = mem_get_byte(pc);
2024-01-16 15:46:22 -05:00
operand->addr = pc;
operand->op_code = op_code;
operand->addr_mode = get_op_addr_mode(op_code);
2024-01-14 21:59:13 -05:00
pc += 1;
2024-04-08 14:19:59 -04:00
switch (operand->addr_mode) {
case ADDR_MODE_ACCUMULATOR:
case ADDR_MODE_IMPLICIT:
operand->value = 0;
break;
case ADDR_MODE_RELATIVE:
case ADDR_MODE_IMMEDIATE:
case ADDR_MODE_ZERO_PAGE:
case ADDR_MODE_ZERO_PAGE_INDEXED_X:
case ADDR_MODE_ZERO_PAGE_INDEXED_Y:
2024-05-06 20:23:44 -04:00
operand->value = mem_get_byte(pc);
2024-04-08 14:19:59 -04:00
pc += 1;
break;
default:
2024-05-06 20:23:44 -04:00
operand->value = mem_get_byte(pc);
operand->value += mem_get_byte(pc + 1) << 8;
2024-04-08 14:19:59 -04:00
pc += 2;
break;
2024-01-14 21:59:13 -05:00
}
2024-01-16 15:46:22 -05:00
linked_list_add(&view->operands, operand);
2024-01-11 16:02:53 -05:00
}
}
2024-01-14 21:59:13 -05:00
char *get_addr_mode_format_str(AddressingMode addr_mode) {
switch (addr_mode) {
case ADDR_MODE_ABSOLUTE:
2024-04-08 14:19:59 -04:00
return "$%04x ";
2024-01-14 21:59:13 -05:00
case ADDR_MODE_ABSOLUTE_INDEXED_X:
2024-04-08 14:19:59 -04:00
return "$%04x,x ";
2024-01-14 21:59:13 -05:00
case ADDR_MODE_ABSOLUTE_INDEXED_Y:
2024-04-08 14:19:59 -04:00
return "$%04x,y ";
2024-01-14 21:59:13 -05:00
case ADDR_MODE_ACCUMULATOR:
2024-04-08 14:19:59 -04:00
return "A ";
2024-01-14 21:59:13 -05:00
case ADDR_MODE_IMMEDIATE:
2024-04-08 14:19:59 -04:00
return "#$%02x ";
2024-01-14 21:59:13 -05:00
case ADDR_MODE_IMPLICIT:
2024-04-08 14:19:59 -04:00
return " ";
2024-01-14 21:59:13 -05:00
case ADDR_MODE_INDIRECT_X:
2024-04-08 14:19:59 -04:00
return "($%04x,x) ";
2024-01-14 21:59:13 -05:00
case ADDR_MODE_INDIRECT_JUMP:
2024-04-08 14:19:59 -04:00
return "($%04x) ";
2024-01-14 21:59:13 -05:00
case ADDR_MODE_INDIRECT_Y:
2024-04-08 14:19:59 -04:00
return "($%04x),y ";
2024-01-14 21:59:13 -05:00
case ADDR_MODE_RELATIVE:
2024-04-08 14:19:59 -04:00
return "$%04x ";
2024-01-14 21:59:13 -05:00
case ADDR_MODE_ZERO_PAGE:
2024-04-08 14:19:59 -04:00
return "$%02x,y ";
2024-01-14 21:59:13 -05:00
case ADDR_MODE_ZERO_PAGE_INDEXED_X:
2024-04-08 14:19:59 -04:00
return "$%02x,x ";
2024-01-14 21:59:13 -05:00
case ADDR_MODE_ZERO_PAGE_INDEXED_Y:
2024-04-08 14:19:59 -04:00
return "$%02x,y ";
2024-01-14 21:59:13 -05:00
}
2024-01-11 16:02:53 -05:00
}
2024-04-03 23:03:35 -04:00
bool pv_predicate_operand_by_addr(void *data, void *userdata) {
DebugOperand *operand = (DebugOperand *) data;
address *addr = (address *) userdata;
return operand->addr == *addr;
}
int pv_predicate_operand_distance(void *data, void *userdata) {
DebugOperand *operand = (DebugOperand *) data;
address *addr = (address *) userdata;
2024-04-08 14:19:59 -04:00
return abs(operand->addr - *addr);
2024-04-03 23:03:35 -04:00
}
2024-04-08 14:19:59 -04:00
void pv_write_line(ProgramView *view, int line, DebugOperand *operand) {
2024-01-14 21:59:13 -05:00
char *op_name = get_op_code_name(operand->op_code);
window_inter_print(view->window, 0, line, "%04x:", operand->addr);
2024-01-16 15:46:22 -05:00
window_inter_print(view->window, 6, line, "(%02x) %s", operand->op_code, op_name);
2024-01-14 21:59:13 -05:00
char *format = get_addr_mode_format_str(operand->addr_mode);
2024-01-16 15:46:22 -05:00
window_inter_print(view->window, 16, line, format, operand->value);
2024-01-14 21:59:13 -05:00
}
2024-01-11 16:02:53 -05:00
2024-04-08 14:19:59 -04:00
void pv_print(ProgramView *view) {
2024-04-03 23:03:35 -04:00
LinkedListNode *current_node = view->first_operand_node;
2024-01-16 15:46:22 -05:00
int line = 0;
while (line <= 0xf && current_node != NULL) {
2024-04-08 14:19:59 -04:00
pv_write_line(view, line, (DebugOperand *) current_node->data);
2024-01-16 15:46:22 -05:00
current_node = current_node->next;
line++;
2024-01-11 16:02:53 -05:00
}
}
2024-04-08 14:19:59 -04:00
void pv_cursor_init(ProgramView *view) {
2024-01-16 15:46:22 -05:00
window_inter_cursor_init(view->window, 0, 0xf);
2024-01-14 21:59:13 -05:00
view->window->cursor.width = PROGRAM_VIEW_WIDTH - 2;
}
2024-04-03 23:03:35 -04:00
void pv_goto(ProgramView *view, address target) {
assert(target <= RAM_SIZE);
LinkedListNode *match = linked_list_get_near(&view->operands, &pv_predicate_operand_distance, &target);
view->first_operand_node = match;
2024-04-08 14:19:59 -04:00
view->last_operand_node = view->first_operand_node;
for (int i = 0; i < 0xf; i++) {
if (view->last_operand_node->next != NULL) {
view->last_operand_node = view->last_operand_node->next;
} else {
view->first_operand_node = view->first_operand_node->previous;
}
2024-04-03 23:03:35 -04:00
}
2024-04-08 14:19:59 -04:00
pv_print(view);
2024-04-03 23:03:35 -04:00
}
2024-01-16 15:46:22 -05:00
void pv_scroll(ProgramView *view, int direction) {
assert(direction == CURSOR_OFFSET_DOWN || direction == CURSOR_OFFSET_UP);
2024-04-03 23:03:35 -04:00
if (direction == CURSOR_OFFSET_UP && view->first_operand_node->previous != NULL) {
view->first_operand_node = view->first_operand_node->previous;
view->last_operand_node = view->last_operand_node->previous;
2024-04-08 14:19:59 -04:00
} else if (direction == CURSOR_OFFSET_DOWN && view->last_operand_node->next != NULL) {
2024-04-03 23:03:35 -04:00
view->first_operand_node = view->first_operand_node->next;
view->last_operand_node = view->last_operand_node->next;
2024-01-16 15:46:22 -05:00
}
2024-04-08 14:19:59 -04:00
pv_print(view);
2024-01-16 15:46:22 -05:00
}
void pv_handle_cursor_move(InteractWindow *window, int horizontal, int vertical) {
ProgramView *view = (ProgramView *) window->view;
if (vertical == CURSOR_OFFSET_DOWN && view->window->cursor.pos_y == 0xf ||
vertical == CURSOR_OFFSET_UP && view->window->cursor.pos_y == 0) {
// Scroll the view
pv_scroll(view, vertical);
}
2024-01-14 21:59:13 -05:00
cursor_move(&window->cursor, horizontal, vertical);
}
2024-01-11 16:02:53 -05:00
2024-04-08 14:19:59 -04:00
void pv_handle_key_down(InteractWindow *window, int keycode) {
2024-04-03 23:03:35 -04:00
if (keycode == KEY_GOTO) {
Dialog dialog = dialog_create("Goto Address");
bool cancelled = false;
address input = dialog_get_address(&dialog, &cancelled);
dialog_remove(&dialog);
2024-01-11 16:02:53 -05:00
2024-04-03 23:03:35 -04:00
if (!cancelled) {
ProgramView *view = window->view;
pv_goto(view, input);
cursor_set_pos(&view->window->cursor, 0, 0);
}
}
2024-01-14 21:59:13 -05:00
}
2024-01-16 15:46:22 -05:00
void pv_deinit(InteractWindow *window) {
ProgramView *view = (ProgramView *) window->view;
linked_list_uninit(&view->operands);
}
2024-05-06 20:23:44 -04:00
void pv_init(InteractWindow *interact, int x, int y) {
2024-01-14 21:59:13 -05:00
ProgramView *view = malloc(sizeof(ProgramView));
view->window = interact;
2024-05-06 20:23:44 -04:00
view->pc = &cpu_get_state()->program_counter;
view->operands = linked_list_init(false);
2024-01-11 16:02:53 -05:00
2024-01-14 21:59:13 -05:00
interact->view = view;
2024-01-16 15:46:22 -05:00
interact->handle_cursor_move = &pv_handle_cursor_move;
2024-04-08 14:19:59 -04:00
interact->handle_key_down = &pv_handle_key_down;
2024-01-16 15:46:22 -05:00
interact->deinit = &pv_deinit;
2024-01-14 21:59:13 -05:00
window_inter_init(interact, x, y, PROGRAM_VIEW_WIDTH, PROGRAM_VIEW_HEIGHT, "PROGRAM VIEW");
2024-01-16 15:46:22 -05:00
decode_operands(view);
2024-04-03 23:03:35 -04:00
view->first_operand_node = linked_list_get_if(&view->operands, &pv_predicate_operand_by_addr, view->pc);
LinkedListNode *last_node = view->first_operand_node;
for (int i = 0; i < 0xf; i++) {
last_node = last_node->next;
}
view->last_operand_node = last_node;
2024-01-14 21:59:13 -05:00
2024-04-08 14:19:59 -04:00
pv_print(view);
pv_cursor_init(view);
2024-01-11 16:02:53 -05:00
}