174 lines
4.7 KiB
C
174 lines
4.7 KiB
C
|
#include <kernel/util/disasm.h>
|
||
|
#include <kernel/devices/earlyterm.h>
|
||
|
#include <kernel/drivers/screen.h>
|
||
|
#include <lib/display.h>
|
||
|
#include <lib/stdio.h>
|
||
|
#include <lib/string.h>
|
||
|
|
||
|
static void check_special_addr(ubc_session_t *session, uint32_t address, int mode)
|
||
|
{
|
||
|
extern struct earlyterm earlyterm;
|
||
|
const char *addrname;
|
||
|
char line[128];
|
||
|
|
||
|
// Check address validity
|
||
|
addrname = NULL;
|
||
|
if ((mode & 1) != 0)
|
||
|
addrname = disasm_check_peripheral(address);
|
||
|
if (addrname == NULL && (mode & 2) != 0)
|
||
|
addrname = disasm_check_syscalls(address);
|
||
|
if (addrname == NULL)
|
||
|
return;
|
||
|
|
||
|
// Update vertical counter if needed
|
||
|
if (session->menu.disassembly.print_offset.vertical != 0)
|
||
|
session->menu.disassembly.print_offset.vertical += 1;
|
||
|
|
||
|
// Generate and print line
|
||
|
sprintf(line, "@note: 0x%.8x -> %s\n", address, addrname);
|
||
|
dprint(&earlyterm.display,
|
||
|
session->menu.disassembly.print_offset.horizontal,
|
||
|
session->menu.disassembly.print_offset.vertical, line);
|
||
|
|
||
|
// Update vertical counter
|
||
|
session->menu.disassembly.print_offset.vertical += 1;
|
||
|
}
|
||
|
|
||
|
static uint32_t get_arg(ubc_session_t *session, uint16_t code,
|
||
|
const struct opcode_s *opcode, int id)
|
||
|
{
|
||
|
extern struct earlyterm earlyterm;
|
||
|
uint32_t argument;
|
||
|
int shift;
|
||
|
|
||
|
// Get arg shift.
|
||
|
shift = -1;
|
||
|
while (++shift < 16 && !(opcode->arg[id].mask & (0x01 << shift)));
|
||
|
|
||
|
// Get arguments
|
||
|
argument = (code & opcode->arg[id].mask) >> shift;
|
||
|
|
||
|
// Call specific argument function
|
||
|
if (opcode->arg[id].special != NULL)
|
||
|
argument = (*opcode->arg[id].special)(session->context, argument);
|
||
|
|
||
|
// Check special address and return
|
||
|
check_special_addr(session, argument, 3);
|
||
|
return (argument);
|
||
|
}
|
||
|
|
||
|
static void display_mnemonic(ubc_session_t *session)
|
||
|
{
|
||
|
extern struct earlyterm earlyterm;
|
||
|
char line[128];
|
||
|
uint16_t *area;
|
||
|
uint32_t sspc;
|
||
|
uint32_t spc;
|
||
|
int i;
|
||
|
int j;
|
||
|
|
||
|
// Get starting area.
|
||
|
area = session->menu.disassembly.memory;
|
||
|
|
||
|
// Main Loop.
|
||
|
i = -1;
|
||
|
spc = (uint32_t)area;
|
||
|
sspc = session->context->spc;
|
||
|
session->context->spc = (uint32_t)area;
|
||
|
session->menu.disassembly.print_offset.vertical= 0;
|
||
|
while ((int)session->menu.disassembly.print_offset.vertical < earlyterm.display.ws_row)
|
||
|
{
|
||
|
// Generate first part.
|
||
|
i = i + 1;
|
||
|
memset(line, 0x00, 128);
|
||
|
check_special_addr(session, (uint32_t)&area[i], 2);
|
||
|
sprintf(line, "%.8x %.4x ", (uint32_t)&area[i], area[i]);
|
||
|
|
||
|
// Try to find opcode.
|
||
|
j = -1;
|
||
|
while (opcode_list[++j].name != NULL)
|
||
|
{
|
||
|
// Check opcode.
|
||
|
if ((area[i] & opcode_list[j].mask) != opcode_list[j].code)
|
||
|
continue;
|
||
|
|
||
|
// Generate common line.
|
||
|
sprintf(&line[14],
|
||
|
opcode_list[j].name,
|
||
|
get_arg(session, area[i], &opcode_list[j], 0),
|
||
|
get_arg(session, area[i], &opcode_list[j], 1),
|
||
|
get_arg(session, area[i], &opcode_list[j], 2)
|
||
|
);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// If no opcode are found, generate "empty" line.
|
||
|
if (opcode_list[j].name == NULL)
|
||
|
sprintf(&line[14], ".word 0x%.4x", area[i]);
|
||
|
|
||
|
// Update internal context
|
||
|
// TODO: update all registers (complet emulation ?)
|
||
|
session->context->spc = session->context->spc + 2;
|
||
|
|
||
|
// Display line
|
||
|
dprint(&earlyterm.display,
|
||
|
session->menu.disassembly.print_offset.horizontal,
|
||
|
session->menu.disassembly.print_offset.vertical, line);
|
||
|
|
||
|
// Highlight break line if needed.
|
||
|
if ((uint32_t)&area[i] == sspc)
|
||
|
{
|
||
|
dreverse(&earlyterm.display,
|
||
|
0, session->menu.disassembly.print_offset.vertical * (earlyterm.display.font->font.height + 1),
|
||
|
128, earlyterm.display.font->font.height + 1);
|
||
|
}
|
||
|
if (session->menu.disassembly.next_break != sspc && (uint32_t)&area[i] == session->menu.disassembly.next_break) {
|
||
|
drect(&earlyterm.display,
|
||
|
0, session->menu.disassembly.print_offset.vertical * (earlyterm.display.font->font.height + 1) - 1,
|
||
|
128, earlyterm.display.font->font.height + 1
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// Update vertical counter
|
||
|
session->menu.disassembly.print_offset.vertical += 1;
|
||
|
|
||
|
}
|
||
|
|
||
|
// Restore saved SPC
|
||
|
session->context->spc = sspc;
|
||
|
}
|
||
|
|
||
|
static void cursor_update(ubc_session_t *session)
|
||
|
{
|
||
|
// Horizontal update.
|
||
|
if (session->key.left == 1)
|
||
|
session->menu.disassembly.print_offset.horizontal += 1;
|
||
|
if (session->key.right == 1)
|
||
|
session->menu.disassembly.print_offset.horizontal -= 1;
|
||
|
|
||
|
// Vertical update.
|
||
|
if (session->key.up == 1)
|
||
|
session->menu.disassembly.memory = &session->menu.disassembly.memory[-1];
|
||
|
if (session->key.down == 1)
|
||
|
session->menu.disassembly.memory = &session->menu.disassembly.memory[1];
|
||
|
|
||
|
// Move break point
|
||
|
if (session->key.plus == 1)
|
||
|
session->menu.disassembly.next_break += 2;
|
||
|
if (session->key.minus == 1)
|
||
|
session->menu.disassembly.next_break -= 2;
|
||
|
}
|
||
|
|
||
|
void disasm_menu_disassembly(ubc_session_t *session)
|
||
|
{
|
||
|
extern struct earlyterm earlyterm;
|
||
|
|
||
|
// Update cursor position.
|
||
|
cursor_update(session);
|
||
|
|
||
|
// display ASM.
|
||
|
dclear(&earlyterm.display);
|
||
|
display_mnemonic(session);
|
||
|
screen_update(earlyterm.display.vram);
|
||
|
}
|