Vhex-kernel/src/kernel/util/disasm/disassembly.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);
}