// // Created by william on 10/01/24. // #include #include #include "program_view.h" #include "../cpu/op.h" #include "memory_view.h" #include "keys.h" #include "dialog.h" 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); } byte op_code = mem_get_byte(pc); operand->addr = pc; operand->op_code = op_code; operand->addr_mode = get_op_addr_mode(op_code); pc += 1; 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: operand->value = mem_get_byte(pc); pc += 1; break; default: operand->value = mem_get_byte(pc); operand->value += mem_get_byte(pc + 1) << 8; pc += 2; break; } linked_list_add(&view->operands, operand); } } char *get_addr_mode_format_str(AddressingMode addr_mode) { switch (addr_mode) { case ADDR_MODE_ABSOLUTE: return "$%04x "; case ADDR_MODE_ABSOLUTE_INDEXED_X: return "$%04x,x "; case ADDR_MODE_ABSOLUTE_INDEXED_Y: return "$%04x,y "; case ADDR_MODE_ACCUMULATOR: return "A "; case ADDR_MODE_IMMEDIATE: return "#$%02x "; case ADDR_MODE_IMPLICIT: return " "; case ADDR_MODE_INDIRECT_X: return "($%04x,x) "; case ADDR_MODE_INDIRECT_JUMP: return "($%04x) "; case ADDR_MODE_INDIRECT_Y: return "($%04x),y "; case ADDR_MODE_RELATIVE: return "$%04x "; case ADDR_MODE_ZERO_PAGE: return "$%02x,y "; case ADDR_MODE_ZERO_PAGE_INDEXED_X: return "$%02x,x "; case ADDR_MODE_ZERO_PAGE_INDEXED_Y: return "$%02x,y "; } } 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; return abs(operand->addr - *addr); } void pv_write_line(ProgramView *view, int line, DebugOperand *operand) { char *op_name = get_op_code_name(operand->op_code); window_inter_print(view->window, 0, line, "%04x:", operand->addr); window_inter_print(view->window, 6, line, "(%02x) %s", operand->op_code, op_name); char *format = get_addr_mode_format_str(operand->addr_mode); window_inter_print(view->window, 16, line, format, operand->value); } void pv_print(ProgramView *view) { LinkedListNode *current_node = view->first_operand_node; int line = 0; while (line <= 0xf && current_node != NULL) { pv_write_line(view, line, (DebugOperand *) current_node->data); current_node = current_node->next; line++; } } void pv_cursor_init(ProgramView *view) { window_inter_cursor_init(view->window, 0, 0xf); view->window->cursor.width = PROGRAM_VIEW_WIDTH - 2; } 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; 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; } } pv_print(view); } void pv_scroll(ProgramView *view, int direction) { assert(direction == CURSOR_OFFSET_DOWN || direction == CURSOR_OFFSET_UP); 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; } else if (direction == CURSOR_OFFSET_DOWN && view->last_operand_node->next != NULL) { view->first_operand_node = view->first_operand_node->next; view->last_operand_node = view->last_operand_node->next; } pv_print(view); } 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); } cursor_move(&window->cursor, horizontal, vertical); } void pv_handle_key_down(InteractWindow *window, int keycode) { if (keycode == KEY_GOTO) { Dialog dialog = dialog_create("Goto Address"); bool cancelled = false; address input = dialog_get_address(&dialog, &cancelled); dialog_remove(&dialog); if (!cancelled) { ProgramView *view = window->view; pv_goto(view, input); cursor_set_pos(&view->window->cursor, 0, 0); } } } void pv_deinit(InteractWindow *window) { ProgramView *view = (ProgramView *) window->view; linked_list_uninit(&view->operands); } void pv_init(InteractWindow *interact, int x, int y) { ProgramView *view = malloc(sizeof(ProgramView)); view->window = interact; view->pc = &cpu_get_state()->program_counter; view->operands = linked_list_init(false); interact->view = view; interact->handle_cursor_move = &pv_handle_cursor_move; interact->handle_key_down = &pv_handle_key_down; interact->deinit = &pv_deinit; window_inter_init(interact, x, y, PROGRAM_VIEW_WIDTH, PROGRAM_VIEW_HEIGHT, "PROGRAM VIEW"); decode_operands(view); 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; pv_print(view); pv_cursor_init(view); }