#include "sux.h"
#if delay_clk && getclk && !bench
#include <time.h>
#endif
#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
char *key = NULL;
uint8_t key_idx = 0;
uint8_t esc = 0;
uint8_t iscsi = 0;
#if delay_clk && getclk && !bench
uint64_t old_clk = 0;
#endif
typedef struct escape escape;
struct escape {
char buf[128];
size_t len;
int arg[16];
int narg;
char mode[2];
};
escape escseq;
static inline char *get_keyseq(int keycode) {
switch (keycode) {
case KEY_BACKSPACE: return "\b";
case KEY_UP : return "\x1B[A";
case KEY_DOWN : return "\x1B[B";
case KEY_RIGHT : return "\x1B[C";
case KEY_LEFT : return "\x1B[D";
case KEY_F( 1) : return "\x1BOP";
case KEY_F( 2) : return "\x1BOQ";
case KEY_F( 3) : return "\x1BOR";
case KEY_F( 4) : return "\x1BOS";
case KEY_F( 5) : return "\x1B[15~";
case KEY_F( 6) : return "\x1B[17~";
case KEY_F( 7) : return "\x1B[18~";
case KEY_F( 8) : return "\x1B[19~";
case KEY_F( 9) : return "\x1B[20~";
case KEY_F(10) : return "\x1B[21~";
case KEY_F(11) : return "\x1B[23~";
case KEY_F(12) : return "\x1B[24~";
default : return NULL;
}
}
int get_key(WINDOW *scr, int delay, uint64_t cycles) {
int x, y;
int c;
int keycode = 0;
int tmp_flag = dbg_print_per_inst;
#if delay_clk && getclk && !bench
if (!step && delay < 0) {
#define MICRO_PER_SEC (1000 * 1000)
#define NANO_PER_SEC (MICRO_PER_SEC * 1000)
#define CYCLE_PER_SEC (2*MICRO_PER_SEC)
struct timespec ts;
const uint64_t clk_diff = cycles - old_clk;
const uint64_t nanos = (uint64_t)((double)clk_diff * ((double)NANO_PER_SEC / CYCLE_PER_SEC));
if (nanos < NANO_PER_SEC) {
ts.tv_sec = 0;
ts.tv_nsec = nanos;
} else {
ts.tv_sec = nanos / NANO_PER_SEC;
ts.tv_nsec = nanos % NANO_PER_SEC;
}
#if debug
wmove(scr, getmaxy(scr)-2, 0);
wprintw(scr, "ts.tv_sec: %"PRIu64", tv.nsec: %"PRIu64"\n", ts.tv_sec, ts.tv_nsec);
#endif
nanosleep(&ts, NULL);
old_clk = cycles;
}
#endif
wtimeout(scr, delay);
curs_set((delay < 0));
if ((key == NULL) || (key && key[key_idx] == '\0') || !kbd_rdy || delay >= 0) {
c = wgetch(scr);
if (c == 19) {
if (kbd_rdy) {
c = wgetch(scr);
}
step = 1;
} else if (c == 0x11) {
end = 1;
}
if (kbd_rdy && delay < 0) {
key_idx = 0;
key = get_keyseq(c);
}
keycode = c;
}
if (kbd_rdy && delay < 0) {
c = (key != NULL) ? key[key_idx++] : c;
}
if (step) {
if (keycode != 19 && keycode != 18 && keycode != 0x11 && !isalnum(keycode)) {
switch (keycode) {
case KEY_F(1):
endwin();
puts("Starting asmmon()");
asmmon("stdin");
puts("Reinitializing screen.");
init_scr();
wrefresh(scr);
#if debug
wrefresh(regs);
#endif
break;
case KEY_F(3):
dbg_print_per_inst = !dbg_print_per_inst;
}
#if debug && !bench
getyx(scr, y, x);
wmove(scr, getmaxy(scr)-1, 0);
wclrtoeol(scr);
wprintw(scr, "keycode: %i", keycode);
if (tmp_flag != dbg_print_per_inst) {
wprintw(scr, ", Disassemble per instruction %s", (dbg_print_per_inst) ? "enabled" : "disabled");
}
wmove(scr, y, x);
#endif
}
}
if (kbd_rdy && delay < 0) {
switch (c) {
case ERR:
addr[CTRL_ADDR] = 0;
break;
case '\0': break;
default:
if (kbd_rdy && c < 0x100) {
addr[CTRL_ADDR] = 1;
#if debug && !bench
wmove(scr, getmaxy(scr)-1, 0);
wclrtoeol(scr);
wprintw(scr, "c: %i ", c);
wprintw(scr, "key: ");
for (int i = 0; key && key[i] != '\0'; i++) {
wprintw(scr, "$%02X%s", key[i], (key[i+1] != '\0') ? ", " : "");
}
wmove(scr, y, x);
#endif
}
break;
}
} else {
if (step) {
step = !(c == 18);
}
}
addr[STEP_ADDR] = step;
curs_set(0);
return c;
}
void parse_esc() {
char *str = escseq.buf, *nstr;
long int value;
escseq.narg = 0;
escseq.buf[escseq.len] = '\0';
for (;str < escseq.buf + escseq.len; str++) {
nstr = NULL;
value = strtol(str, &nstr, 10);
if (nstr == str) {
value = 0;
}
if (value == LONG_MAX || value == LONG_MIN) {
value = -1;
}
escseq.arg[escseq.narg++] = value;
str = nstr;
if (*str != ';' || escseq.narg == 16) {
break;
}
}
escseq.mode[0] = *str++;
escseq.mode[1] = (str < (escseq.buf + escseq.len)) ? *str : '\0';
}
void handle_esc() {
int x, y;
getyx(scr, y, x);
switch (escseq.mode[0]) {
case 'A':
DEFAULT(escseq.arg[0], 1);
if (y-escseq.arg[0] >= 0) {
y -= escseq.arg[0];
#if !debug
wmove(scr, y, x);
#endif
}
break;
case 'B':
case 'e':
DEFAULT(escseq.arg[0], 1);
if (y+escseq.arg[0] <= getmaxy(scr)) {
y += escseq.arg[0];
#if !debug
wmove(scr, y, x);
#endif
}
break;
case 'C':
case 'a':
DEFAULT(escseq.arg[0], 1);
if (x+escseq.arg[0] <= getmaxx(scr)) {
x += escseq.arg[0];
#if !debug
wmove(scr, y, x);
#endif
}
break;
case 'D':
DEFAULT(escseq.arg[0], 1);
if (x-escseq.arg[0] >= 0) {
x -= escseq.arg[0];
#if !debug
wmove(scr, y, x);
#endif
}
break;
case 'H':
case 'f':
DEFAULT(escseq.arg[0], 1);
DEFAULT(escseq.arg[1], 1);
#if !debug
wmove(scr, escseq.arg[0]-1, escseq.arg[1]-1);
#else
wmove(scr, 31, 0);
wclrtoeol(scr);
wprintw(scr, "escseq.arg[0]: %i, escseq.arg[1]: %i", escseq.arg[0], escseq.arg[1]);
#endif
break;
case 'S':
DEFAULT(escseq.arg[0], 1);
#if !debug
wscrl(scr, -escseq.arg[0]);
#else
#endif
break;
case 'T':
DEFAULT(escseq.arg[0], 1);
#if !debug
wscrl(scr, escseq.arg[0]);
#else
#endif
break;
}
}
void reset_esc() {
memset(&escseq, 0, sizeof(escseq));
}
void handle_ctrlcode(int c) {
int x, y;
uint16_t scr_col = 0;
int tmp_flag = 0;
#if debug
if (subdbg) {
tmp_flag = (addr[TX_ADDR] != 0x0C && addr[TX_ADDR] != '\n' && scr_col < 160);
if (!tmp_flag) {
wmove(scr, 30, 0);
wclrtoeol(scr);
}
scr_col = (tmp_flag) ? (addr[1] << 1)-2 : 0;
wmove(scr, 30, scr_col);
}
#endif
getyx(scr, y, x);
switch (c) {
case 0xC:
x=0,y=0;
#if !debug
wclear(scr);
wmove(scr, y, x);
#endif
break;
case CURSES_BACKSPACE:
case '\b':
if (x > 0) {
x--;
#if !debug
wmove(scr, y, x);
#endif
}
#if !debug
wdelch(scr);
#else
if (subdbg) {
scr_col++;
wmove(scr, 30, scr_col--);
wdelch(scr);
wmove(scr, 30, scr_col);
wdelch(scr);
}
#endif
break;
case '\033': reset_esc(); esc = 1; break;
case '\n':
x = 0;
y+=1;
#if !debug
wmove(scr, y, x);
#endif
break;
default:
#if !debug
waddch(scr, c);
#else
if (subdbg && scr_col < 160) {
if (c != ' ') {
wprintw(scr, "%02X", c);
} else {
wprintw(scr, " ");
}
}
#endif
x+=1;
break;
}
}
void io(uint64_t address, uint8_t rw, uint64_t cycles) {
switch (address) {
case STEP_ADDR: step = (!rw) ? addr[STEP_ADDR] : step; break;
case CTRL_ADDR:
if (!rw) {
break;
}
kbd_rdy = 1;
wrefresh(scr);
#if debug
wrefresh(regs);
wrefresh(inst_win);
wrefresh(dbg_win);
#endif
addr[RX_ADDR] = get_key(scr, -1, cycles);
kbd_rdy = 0;
break;
case TX_ADDR:
if (rw) {
break;
}
if (esc) {
#if debug
if (!subdbg && addr[RX_ADDR] == '\n') {
wclrtoeol(scr);
}
#endif
int c = addr[TX_ADDR];
if (iscsi) {
escseq.buf[escseq.len++] = c;
if (BETWEEN(c, 0x40, 0x7E) || escseq.len >= sizeof(escseq.buf)-1) {
esc = 0;
iscsi = 0;
parse_esc();
handle_esc();
}
}
if (c == '[') {
iscsi = 1;
}
} else {
handle_ctrlcode(addr[TX_ADDR]);
}
break;
}
}