gsplus/src/debug_sweet16.re2c

403 lines
8.5 KiB
Plaintext

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "defc.h"
enum modes {
none = 0,
reg = 1 << 1,
indir_reg = 1 << 2,
reg_imm = 1 << 3,
relative = 1 << 4
};
static word32 to_hex(const char *iter, const char *end) {
word32 rv = 0;
while(iter != end) {
char c = *iter++;
rv <<= 4;
if (isdigit(c)) rv |= c - '0';
else rv |= (c | 0x20) - 'a' + 10;
}
return rv;
}
const char *ltrim(const char *cp) {
while (isspace(*cp)) ++cp;
return cp;
}
/*!re2c
re2c:define:YYCTYPE = char;
re2c:yyfill:enable = 0;
eol = "\x00";
ws = [ \t];
x = [A-Fa-f0-9];
*/
const char *parse_pc(const char *cp, uint32_t *pc) {
const char *YYCURSOR = cp;
const char *YYMARKER = NULL;
const char *YYCTXMARKER = NULL;
if (isspace(*cp)) return ltrim(cp);
/*!re2c
* { return NULL; }
x{4} ':' {
*pc &= 0xff0000;
*pc |= to_hex(cp, YYCURSOR - 1);
goto next;
}
x{6} ':' {
*pc = to_hex(cp, YYCURSOR - 1);
goto next;
}
x{2} '/' x{4} ':' {
uint32_t tmp = to_hex(cp, cp + 2) << 16;
tmp |= to_hex(cp + 3, YYCURSOR - 1);
*pc = tmp;
goto next;
}
*/
next:
return ltrim(YYCURSOR);
}
const char *parse_opcode(const char *cp, int *opcode, int *mode) {
int op = -1;
int m = 0;
unsigned c;
const char *YYCURSOR = cp;
const char *YYMARKER = NULL;
const char *YYCTXMARKER = NULL;
/* TODO - db, dw ? */
/*!re2c
* { return NULL; }
'set' { op = 0x10; m = reg_imm; goto next; }
'ld' { op = 0x20; m = reg | indir_reg; goto next; }
'st' { op = 0x30; m = reg | indir_reg; goto next; }
'ldd' { op = 0x60; m = indir_reg; goto next; }
'std' { op = 0x70; m = indir_reg; goto next; }
'pop' { op = 0x80; m = indir_reg; goto next; }
'stp' { op = 0x90; m = indir_reg; goto next; }
'add' { op = 0xa0; m = reg; goto next; }
'sub' { op = 0xb0; m = reg; goto next; }
'popd' { op = 0xc0; m = indir_reg; goto next; }
'cpr' { op = 0xd0; m = reg; goto next; }
'inr' { op = 0xe0; m = reg; goto next; }
'dcr' { op = 0xf0; m = reg; goto next; }
'rtn' { op = 0x00; goto next; }
'br' { op = 0x01; m = relative; goto next; }
'bnc' { op = 0x02; m = relative; goto next; }
'bc' { op = 0x03; m = relative; goto next; }
'bp' { op = 0x04; m = relative; goto next; }
'bm' { op = 0x05; m = relative; goto next; }
'bz' { op = 0x06; m = relative; goto next; }
'bnz' { op = 0x07; m = relative; goto next; }
'bm1' { op = 0x08; m = relative; goto next; }
'bnm1' { op = 0x09; m = relative; goto next; }
'bk' { op = 0x0a; goto next; }
'rs' { op = 0x0b; goto next; }
'bs' { op = 0x0c; m = relative; goto next; }
*/
next:
c = *YYCURSOR;
if (c && !isspace(c)) return NULL;
*opcode = op;
*mode = m;
return ltrim(YYCURSOR);
}
const char *parse_register(const char *cp, int *opcode) {
const char *YYCURSOR = cp;
const char *YYMARKER = NULL;
const char *YYCTXMARKER = NULL;
/*!re2c
* { return NULL; }
'R' ([0-9]{1,2}) {
int r = 0;
for(cp = cp + 1; cp < YYCURSOR; ++cp) {
r = r * 10 + *cp - '0';
}
if (r > 15) return NULL;
*opcode |= r;
goto next;
}
/*
'R' x {
int r = to_hex(cp + 1, YYCURSOR);
*opcode |= r;
goto next;
}
*/
'ACC' { *opcode |= 0x00; goto next; }
'PC' { *opcode |= 0x0f; goto next; }
'SR' { *opcode |= 0x0e; goto next; }
*/
next:
return ltrim(YYCURSOR);
}
const char *parse_address(const char *cp, int *address, int pc) {
const char *YYCURSOR = cp;
const char *YYMARKER = NULL;
const char *YYCTXMARKER = NULL;
int ea = 0;
/*!re2c
* { return NULL; }
'*' { ea = pc; goto next; }
'*' [+-] x{1,4} {
ea = to_hex(cp + 2, YYCURSOR);
if (cp[1] == '+') ea += pc;
else ea -= pc;
goto next;
}
x{1,4} {
ea = to_hex(cp, YYCURSOR);
goto next;
}
*/
next:
*address = ea & 0xffff;
return ltrim(YYCURSOR);
}
uint32_t sweet16_disasm(uint32_t addr, int lines) {
unsigned op;
const char *opcode;
unsigned mode = none;
unsigned operand;
unsigned x;
int i;
uint8_t bytes[4];
while (lines--) {
unsigned size = 0;
uint32_t pc = addr;
op = get_memory_c(addr++, 0);
bytes[size++] = op;
switch (op >> 4) {
case 0x00:
switch(op) {
case 0x00: opcode = "RTN"; break;
case 0x01: opcode = "BR"; mode = relative; break;
case 0x02: opcode = "BNC"; mode = relative; break;
case 0x03: opcode = "BC"; mode = relative; break;
case 0x04: opcode = "BP"; mode = relative; break;
case 0x05: opcode = "BM"; mode = relative; break;
case 0x06: opcode = "BZ"; mode = relative; break;
case 0x07: opcode = "BNZ"; mode = relative; break;
case 0x08: opcode = "BM1"; mode = relative; break;
case 0x09: opcode = "BNM1"; mode = relative; break;
case 0x0a: opcode = "BK"; break;
case 0x0b: opcode = "RS"; break;
case 0x0c: opcode = "BS"; mode = relative; break;
case 0x0d: opcode = "???"; break;
case 0x0e: opcode = "???"; break;
case 0x0f: opcode = "???"; break;
}
break;
case 0x01: opcode = "SET"; mode = reg_imm; break;
case 0x02: opcode = "LD"; mode = reg; break;
case 0x03: opcode = "ST"; mode = reg; break;
case 0x04: opcode = "LD"; mode = indir_reg; break;
case 0x05: opcode = "ST"; mode = indir_reg; break;
case 0x06: opcode = "LDD"; mode = indir_reg; break;
case 0x07: opcode = "STD"; mode = indir_reg; break;
case 0x08: opcode = "POP"; mode = indir_reg; break;
case 0x09: opcode = "STP"; mode = indir_reg; break;
case 0x0a: opcode = "ADD"; mode = reg; break;
case 0x0b: opcode = "SUB"; mode = reg; break;
case 0x0c: opcode = "POPD"; mode = indir_reg; break;
case 0x0d: opcode = "CPR"; mode = reg; break;
case 0x0e: opcode = "INR"; mode = reg; break;
case 0x0f: opcode = "DCR"; mode = reg; break;
}
switch(mode) {
case none:
case reg:
case indir_reg:
break;
case relative:
operand = (int8_t)get_memory_c(addr++, 0);
bytes[size++] = operand;
operand += addr;
operand &= 0xffff;
break;
case reg_imm:
operand = get_memory16_c(addr, 0);
addr += 2;
bytes[size++] = operand & 0xff;
bytes[size++] = operand >> 8;
break;
}
x = printf("%02x/%04x:", pc >> 16, pc & 0xffff);
for (i = 0; i < size; ++i) {
x += printf(" %02x", bytes[i]);
}
for( ; x < 20; ++x) fputc(' ', stdout);
printf("%-5s", opcode);
switch(mode) {
case none: break;
case reg: x += printf("R%d", op & 0x0f); break;
case indir_reg: x += printf("@R%d", op & 0x0f); break;
case relative:
x += printf("%04x", operand);
break;
case reg_imm:
x += printf("R%d, %04x", op & 0x0f, operand);
break;
}
fputc('\n', stdout);
}
return addr;
}
static int error(int offset, const char *msg) {
while (offset > 0) { fputc(' ', stderr); --offset; }
fputs(" ^", stderr);
fputs(msg, stderr);
fputc('\n', stderr);
return -1;
}
int parse_line(const char *cp, uint32_t *pc) {
uint32_t addr = *pc;
int opcode;
int operand;
int indir = 0;
int mode = 0;
int i;
unsigned offset = 0;
const char *start = cp;
uint8_t bytes[3];
int size = 0;
cp = parse_pc(cp, &addr);
if (!cp) return error(0, "error");
offset = cp - start;
/* label only? */
if (!*cp) {
*pc = addr;
return 0;
}
cp = parse_opcode(cp, &opcode, &mode);
if (!cp) return error(offset, "bad opcode");
offset = cp - start;
if (mode & (reg | indir_reg | reg_imm)) {
if (*cp == '@') {
indir = 1;
++cp;
}
cp = parse_register(cp, &opcode);
if (!cp) return error(offset, "bad register");
offset = cp - start;
/* cleanup indir */
/* LD / ST */
if (indir && mode == (reg|indir_reg)) {
opcode += 0x20;
mode = indir_reg;
}
if ((mode == indir_reg) != indir)
return error(offset, "bad operand");
}
bytes[size++] = opcode;
if (mode == reg_imm) {
if (*cp++ != ',')
return error(offset, "expected ,");
cp = ltrim(cp);
offset = cp - start;
}
if (mode & (relative | reg_imm)) {
cp = parse_address(cp, &operand, addr);
if (!cp) return error(offset, "bad operand");
offset = cp - start;
if (mode == relative) {
int tmp = (addr + 2) & 0xffff;
operand -= tmp;
if (operand > 127 || operand < -128)
return error(offset, "out of range");
bytes[size++] = operand;
} else {
bytes[size++] = operand & 0xff;
bytes[size++] = operand >> 8;
}
}
if (!cp) return error(offset, "bad operand");
for (i = 0; i < size; ++i) {
set_memory_c(addr + i, bytes[i], 0);
}
*pc = addr + size;
fputs("\r\x1b[A\x1b[K", stdout);
sweet16_disasm(addr, 1);
return 1;
}
extern char *x_readline(const char *prompt);
uint32_t sweet16_asm_shell(uint32_t addr) {
printf("%02x/%04x:\n", addr >> 16, addr & 0xffff);
for(;;) {
const char *cp = x_readline("!!");
if (!cp || !*cp) return addr;
parse_line(cp, &addr);
}
}