#include "sux.h" #include "disasm.h" #include #define ORTHO_1CC(mne, cc) \ mne##_R##cc: case mne##_M##cc #define ORTHO_1OP(mne) \ mne##_R: case mne##_M #define ORTHO_2OP(mne) \ mne##_RR: case mne##_RM: case mne##_MR: case mne##_MM void print_info(struct sux *cpu, WINDOW *w, uint8_t lines, uint8_t thread) { for (uint8_t i = (24*thread)+2; i <= 24*(thread+1); i++) { wmove(w, i, 0); waddch(w, (i == lines) ? '>' : ' '); } wmove(w, lines, 1); wclrtoeol(w); wprintw(w, "pc: $%04"PRIX64 , cpu->pc); wprintw(w, ", ps: %c%c---%c%c%c", cpu->ps.u8[thread] & N ? 'N' : '-' , cpu->ps.u8[thread] & V ? 'V' : '-' , cpu->ps.u8[thread] & I ? 'I' : '-' , cpu->ps.u8[thread] & Z ? 'Z' : '-' , cpu->ps.u8[thread] & C ? 'C' : '-'); wprintw(w, ", inst: "); } void print_regs(struct sux *cpu, WINDOW *w) { for (int i = 0; i < 9; i++) { wmove(w, i, 0); wclrtoeol(w); } wmove(w, 0, 0); wprintw(w, "Registers:\n"); wprintw(w, " a: $%016"PRIX64", b: $%016"PRIX64"\n", cpu->a, cpu->b); wprintw(w, " x: $%016"PRIX64", y: $%016"PRIX64"\n", cpu->x, cpu->y); wprintw(w, " e: $%016"PRIX64", c: $%016"PRIX64"\n", cpu->e, cpu->c); wprintw(w, " d: $%016"PRIX64", s: $%016"PRIX64"\n", cpu->d, cpu->s); wprintw(w, " f: $%016"PRIX64", sp: $%016"PRIX64"\n", cpu->f, cpu->sp); wprintw(w, " bp: $%016"PRIX64", r11: $%016"PRIX64"\n", cpu->bp, cpu->r11); wprintw(w, "r12: $%016"PRIX64", r13: $%016"PRIX64"\n", cpu->r12, cpu->r13); wprintw(w, "r14: $%016"PRIX64", r15: $%016"PRIX64"\n", cpu->r14, cpu->r15); } static void sub_dbg(struct sux *cpu, WINDOW *w, uint64_t address, uint64_t *ortho_addr, uint8_t thread) { uint8_t ln = 5; uint16_t line_idx = 0; uint32_t tmpad = 0x20247; int row, col; uint8_t iscursor = 0; union reg ptr; ptr.u64 = 0; uint32_t adr; if (address == CTRL_ADDR || ortho_addr[1] == CTRL_ADDR || addr[STEP_ADDR]) { adr = read_value(cpu, 0, tmpad, 7, 0, 0); tmpad += 8; wmove(w, 1, 0); wclrtoeol(w); ptr.u64 = 0; ptr.u64 = read_value(cpu, 0, 4, 1, 0, 0); wprintw(w, "scr_row: %02u, scr_col: %02u, scr_str: %02u, scr_end: %02u, scr_ptr: $%04X", addr[0], addr[1], addr[2], addr[3], ptr.u16[0]); wmove(w, 2, 0); wprintw(w, "bitabl: "); for (uint8_t i = 0; i < 16; i++) { wprintw(w, "%s", showbits(addr[adr+i], 7, 0)); } mvwprintw(w, ln++, 0, "buffer: "); wmove(w, ln++, 0); uint8_t maxrow = 10; int line_offset = (addr[0]-(maxrow-1) >= 0) ? addr[0]-(maxrow-1) : 0; adr = read_value(cpu, 0, tmpad, 7, 0, 0); for (uint8_t i = 0; i < maxrow; i++) { line_idx = (i+addr[2]+line_offset << 6) + (i+addr[2]+line_offset << 4); for (uint8_t j = 0; j < 0x50; j++) { wprintw(w, "%02X", addr[adr+j+line_idx]); if ((addr[0] == i+line_offset) && addr[1] == j) { iscursor=1; getyx(w,row, col); wmove(w, ln++, 0); wclrtoeol(w); wmove(w, row+1, col-2); wprintw(w, "/\\"); wmove(w, row, col); } } wprintw(w, ", i: %02X", i); if (!iscursor) { wmove(w, ln, 0); wclrtoeol(w); } iscursor = 0; wmove(w, ln++, 0); } } /*wclrtoeol(w); wprintw(w, "rega: $%02X, ", addr[0x0A]); wprintw(w, "regb: $%02X, ", addr[0x0B]); wprintw(w, "regc: $%02X, ", addr[0x0C]); wprintw(w, "regd: $%02X, ", addr[0x0D]); wprintw(w, "rege: $%02X, ", addr[0x0E]); wprintw(w, "regf: $%02X, ", addr[0x0F]); wprintw(w, "regg: $%02X", addr[0x10]);*/ wmove(w, 3, 0); wclrtoeol(w); adr = 0x25; ptr.u64 = read_value(cpu, 0, adr, 7, 0, 0); wprintw(w, "ptr1: $%04"PRIX64, ptr.u64); adr = 0x2D; ptr.u64 = read_value(cpu, 0, adr, 7, 0, 0); wprintw(w, ", ptr2: $%04"PRIX64, ptr.u64); adr = 0x35; ptr.u64 = read_value(cpu, 0, adr, 7, 0, 0); wprintw(w, ", ptr3: $%04"PRIX64, ptr.u64); adr = 0x02049A; ptr.u64 = read_value(cpu, 0, adr, 7, 0, 0); wprintw(w, ", idx0: $%04"PRIX64, ptr.u64); adr = 0x334BA; ptr.u64 = read_value(cpu, 0, adr, 7, 0, 0); wprintw(w, ", valbuf: $%016"PRIX64, ptr.u64); wmove(w, 4, 0); wclrtoeol(w); adr = 0x200CA; ptr.u64 = read_value(cpu, 0, adr, 3, 0, 0); wprintw(w, "t_id: $%02X", ptr.u8[0]); wprintw(w, ", t_type: $%02X", ptr.u8[1]); wprintw(w, ", t_space: $%02X", ptr.u8[2]); wprintw(w, ", t_tab: $%02X", ptr.u8[3]); adr += 4; ptr.u64 = read_value(cpu, 0, adr, 7, 0, 0); wprintw(w, ", t_val: $%"PRIX64, ptr.u64); adr += 8; ptr.u64 = read_value(cpu, 0, adr, 7, 0, 0); wprintw(w, ", t_str: $%"PRIX64, ptr.u64); adr += 8; ptr.u64 = read_value(cpu, 0, adr, 7, 0, 0); wprintw(w, ", t_sym: $%"PRIX64, ptr.u64); /* wmove(w, 47, 0); wclrtoeol(w); wprintw(w, "a: $%02X,", addr[0x0A]); wprintw(w, " b: $%02X,", addr[0x0B]); wprintw(w, " c: $%02X,", addr[0x0C]); wprintw(w, " d: $%02X,", addr[0x0D]); wprintw(w, " e: $%02X,", addr[0x0E]); wprintw(w, " f: $%02X", addr[0x0F]); tmpad += 8; adr = read_value(cpu, 0, tmpad, 7, 0, 0); line_idx = 0; wprintw(w, "cmd_buf:"); for (uint8_t i = 0; i < 1; i++) { wmove(w, ln++, 0); wclrtoeol(w); line_idx = (i << 4)+(i << 6); for (uint8_t j = 0; j < 0x50; j++) { wprintw(w, "%02X", addr[adr+j+line_idx]); } wprintw(w, ", i: %02X", i); }*/ } static uint64_t get_offset(uint64_t value, uint8_t size, char **sign) { size = (size > 8) ? 8 : size; uint8_t msb = size*8; uint64_t mask = (-(uint64_t)1 >> ((8 - size) * 8)); mask &= ~(1 << (msb-1)); *sign = ((value >> (msb-1)) & 1) ? "-" : "+"; if (*sign[0] == '-' && value != (1 << (msb-1))) { value = (-value) & mask; } return value; } /* Checks if the opcode, and operands required an ortho suffix. */ static int is_os(uint8_t opcode, operand *op) { uint8_t is_mem = (op[0].type == 1 && op[0].id != MEM_IMM); uint8_t is_idx = (is_mem && !op[1].type && (op[1].id == REG_X || op[1].id == REG_Y)); int is_valid = 1; int is_sp = 0; if (is_mem || is_idx) { switch (op[0].id) { case MEM_AINDR: case MEM_ZINDR: case MEM_ARIND: case MEM_ZRIND: case MEM_SIB : is_valid = 0; break; case MEM_ZMR : case MEM_ABSR : case MEM_RIND : default : if (is_mem && !op[1].type && op[1].id != REG_X && op[1].id != REG_Y) { is_valid = 0; } else if (op[0].id == MEM_ZMR || op[0].id == MEM_ABSR || op[0].id == MEM_RIND) { is_valid = (op[0].rind[0] == REG_SP); is_sp = (op[0].rind[0] == REG_SP); } else if (is_mem && op[1].type == 1) { is_valid = 0; } break; } } switch (opcode) { case ORTHO_2OP(CMP): return (is_idx && is_valid && ((is_sp && op[0].id == MEM_RIND) || (!is_sp && op[0].id == MEM_IND))); case ORTHO_2OP(LEA): return (is_idx && is_valid); } return 0; } static int is_2op(uint8_t opcode) { switch (opcode) { case ORTHO_2OP(MNG): case ORTHO_2OP(ADC): case ORTHO_2OP(ROR): case ORTHO_2OP(ADD): case ORTHO_2OP(MPO): case ORTHO_2OP(SBC): case ORTHO_2OP(MUL): case ORTHO_2OP(SUB): case ORTHO_2OP(MCS): case ORTHO_2OP(AND): case ORTHO_2OP(DIV): case ORTHO_2OP(PCN): case ORTHO_2OP(MCC): case ORTHO_2OP(OR ): case ORTHO_2OP(ASR): case ORTHO_2OP(LEA): case ORTHO_2OP(MEQ): case ORTHO_2OP(XOR): case ORTHO_2OP(CMP): case ORTHO_2OP(MNE): case ORTHO_2OP(LSL): case ORTHO_2OP(MOV): case ORTHO_2OP(MVS): case ORTHO_2OP(LSR): case ORTHO_2OP(IML): case ORTHO_2OP(MVC): case ORTHO_2OP(ROL): case ORTHO_2OP(IDV): return 1; } return 0; } static void disasm_ortho(struct sux *cpu, WINDOW *w, uint8_t opcode, uint8_t prefix, uint8_t prefix2, uint64_t *value, char *inst_name, char *postfix, operand *op, uint8_t rs, uint8_t thread) { char opr[2][256]; char address[2][18]; char *rind[2] = {"", ""}; char *sign[2] = {"", ""}; char *ind[2] = {"", ""}; char idx[2][33]; char scale[2][5]; char *reg[2] = {"", ""}; memset(opr, 0, sizeof(opr)); memset(address, 0, sizeof(address)); memset(idx, 0, sizeof(idx)); memset(scale, 0, sizeof(scale)); for (int i = 0; i < 2; i++) { int is_ind = 0; int is_rind = 0; uint64_t val = 0; if (op[i].type) { uint8_t addr_size = get_ortho_addrsize(prefix, op[i].id); if (op[i].id == MEM_SIB) { sprintf(scale[i], "%u*", op[i].scale+1); } else if (op[i].id == MEM_IMM) { val = read_value(cpu, 0, value[i], rs-1, 0, 0); } switch (op[i].id) { case MEM_ABSR : case MEM_ZMR : case MEM_AINDR: case MEM_AIND : case MEM_ZINDR: case MEM_ARIND: case MEM_ZRIND: case MEM_SIB : case MEM_RIND : is_rind = 1; break; } if (addr_size != 0xFF) { uint64_t value = (is_rind) ? get_offset(op[i].value, addr_size+1, &sign[i]) : op[i].value; sprintf(address[i], "$%0*"PRIX64, (addr_size+1)*2, value); } if (is_rind) { for (int j = 0; j < 2 && op[i].rind[j] != 0xFF; j++) { switch (op[i].rind[j]) { case REG_A : rind[j] = "A"; break; case REG_B : rind[j] = "B"; break; case REG_X : rind[j] = "X"; break; case REG_Y : rind[j] = "Y"; break; case REG_E : rind[j] = "E"; break; case REG_C : rind[j] = "C"; break; case REG_D : rind[j] = "D"; break; case REG_S : rind[j] = "S"; break; case REG_F : rind[j] = "F"; break; case REG_SP : rind[j] = "SP"; break; case REG_BP : rind[j] = "BP"; break; case REG_R11: rind[j] = "R11"; break; case REG_R12: rind[j] = "R12"; break; case REG_R13: rind[j] = "R13"; break; case REG_R14: rind[j] = "R14"; break; case REG_R15: rind[j] = "R15"; break; } } } if (op[i].rind[1] == 0xFF) { rind[1] = (op[i].id == MEM_SIB) ? rind[0] : rind[1]; rind[0] = (op[i].id == MEM_SIB) ? "" : rind[0]; } sprintf(idx[i], "%s%s%s%s", rind[0], (op[i].rind[1] != 0xFF) ? "+" : "", scale[i], rind[1]); switch (op[i].id) { case MEM_AINDR: case MEM_AIND : case MEM_ZINDR: case MEM_IND : is_ind = 1; break; case MEM_ARIND: case MEM_ZRIND: case MEM_SIB : case MEM_RIND : is_ind = 2; break; case MEM_IMM : is_ind = 3; break; } if (!is_rind) { sign[i] = ""; } } else { is_ind = 4; switch (op[i].id) { case REG_A : reg[i] = "A"; break; case REG_B : reg[i] = "B"; break; case REG_X : reg[i] = "X"; break; case REG_Y : reg[i] = "Y"; break; case REG_E : reg[i] = "E"; break; case REG_C : reg[i] = "C"; break; case REG_D : reg[i] = "D"; break; case REG_S : reg[i] = "S"; break; case REG_F : reg[i] = "F"; break; case REG_SP : reg[i] = "SP"; break; case REG_BP : reg[i] = "BP"; break; case REG_R11: reg[i] = "R11"; break; case REG_R12: reg[i] = "R12"; break; case REG_R13: reg[i] = "R13"; break; case REG_R14: reg[i] = "R14"; break; case REG_R15: reg[i] = "R15"; break; } } switch (is_ind) { case 0: sprintf(opr[i], "%s%s%s", idx[i], sign[i], address[i]); break; case 1: sprintf(opr[i], "%s%s(%s)", idx[i], sign[i], address[i]); break; case 2: sprintf(opr[i], "(%s%s%s)", idx[i], sign[i], address[i]); break; case 3: sprintf(opr[i], "#$%0*"PRIX64, rs*2, val); break; case 4: sprintf(opr[i], "%s", reg[i]); break; } } const char *cc = ""; char *op2 = ""; int op_count; char *os = ""; /* Ortho Suffix. */ if (is_os(opcode, op)) { os = (postfix && postfix[0] == '.') ? "O" : ".O"; } if (is_1cc(opcode) || is_2op(opcode)) { op_count = 2; } else if (is_1op(opcode)) { op_count = 1; } if (is_1cc(opcode)) { cc = set_cc[opcode >> 5]; /*switch (opcode) { case ORTHO_1CC(SET, NG): cc = "NG"; break; case ORTHO_1CC(SET, PO): cc = "PO"; break; case ORTHO_1CC(SET, CS): cc = "CS"; break; case ORTHO_1CC(SET, CC): cc = "CC"; break; case ORTHO_1CC(SET, EQ): cc = "EQ"; break; case ORTHO_1CC(SET, NE): cc = "NE"; break; case ORTHO_1CC(SET, VS): cc = "VS"; break; case ORTHO_1CC(SET, VC): cc = "VC"; break; }*/ op2 = (char *)cc; } else if (is_2op(opcode)) { op2 = opr[1]; } wprintw(w, "%s%s%s %s%s %s", inst_name, postfix, os, opr[0], (op_count == 2) ? "," : "", op2); wmove(w, getmaxy(w)-2, 0); wclrtoeol(w); for (int i = 0; i < 2; i++) { if (op[i].type) { sprintf(address[i], "$%04"PRIX64, value[i]); } else { sprintf(address[i], "none"); } } wprintw(w, "destination address: %s, source address: %s", address[0], address[1]); } void disasm(struct sux *cpu, WINDOW *w, uint8_t lines, uint8_t opcode, uint8_t prefix, uint8_t ext_prefix, uint8_t prefix2, uint8_t *op_type, uint8_t *op_id, uint8_t thread) { uint64_t value; uint64_t address = 0; operand ortho_op[2]; uint64_t ortho_addr[2] = {0, 0}; if (ext_prefix != 0x1D) { address = get_addr(cpu, opcode, prefix, ext_prefix, 0, 0, thread); } else { get_ortho_addr(cpu, opcode, prefix, cpu->pc, ortho_op, ortho_addr, op_type, op_id, 0, 0, thread); } uint8_t rs = (prefix >> 4) & 3; char *postfix; char *of; char op[4]; char *sign = ""; char *ind = ""; uint8_t tmp = 0; union reg mask; mask.u64 = 0; const char *inst_name; uint8_t inst_type; op[3] = 0; switch (rs) { case 0: postfix = ""; break; case 1: postfix = ".W"; break; case 2: postfix = ".D"; break; case 3: postfix = ".Q"; break; } if (prefix >> 6) { tmp = 0; } switch (prefix >> 6) { default: of = ""; break; case 1 : of = "SP"; break; case 2 : of = "PC"; break; } if (ext_prefix != 0x1D) { if ((ext_prefix & 0xF) == 0xD) { switch (ext_prefix >> 4) { case 0x0: inst_name = ext_opname[opcode]; inst_type = ext_optype[opcode]; break; } } else { inst_name = opname[opcode]; inst_type = optype[opcode]; } memcpy(op, inst_name, 3); char *idx; uint8_t addrsize = 0; switch (inst_type) { case AIND : case IND : idx = ")"; break; case AINDX: case INDX: idx = ", x)"; break; case AINDY: case INDY: idx = "), y"; break; case ABSX : case ZMX : idx = ", x"; break; case ABSY : case ZMY : idx = ", y"; break; default: idx = ""; break; } switch (inst_type) { case ZM : case ZMX : case ZMY : case IND : case INDX : case INDY : addrsize = get_addrsize(prefix, ZM); break; case ABS : case AIND : case AINDX: case AINDY: case ABSX : case ABSY : addrsize = get_addrsize(prefix, ABS); break; case IMM : case REL : addrsize = (1 << rs)-1; break; } mask.u64 = (-(uint64_t)1 >> ((7 - addrsize) * 8)); value = read_value(cpu, 0, cpu->pc, addrsize, 0, 0); if ((prefix >> 6) == 1 || (prefix >> 6) == 2 || inst_type == REL) { switch (addrsize) { case 0 : sign = ((int8_t )value < 0) ? "-" : "+"; break; case 1 : sign = ((int16_t)value < 0) ? "-" : "+"; break; case 2 : case 3 : sign = ((int32_t)value < 0) ? "-" : "+"; break; case 4 : case 5 : case 6 : case 7 : sign = ((int64_t)value < 0) ? "-" : "+"; break; } value = (sign[0] == '-') ? (~value + 1) & mask.u64 : value; if (inst_type == REL) { value = (sign[0] == '-') ? -value : value; value += (cpu->pc + 1); sign = ""; } addrsize = 0; uint64_t max_val = 0; for (int i = 0; i <= 64; i += 8, addrsize++) { max_val |= (0xFF << i); if (value <= max_val) { break; } } } switch (inst_type) { case BREG : case IMPL : wprintw(w, "%s%s" , inst_name, postfix); break; case EIND : wprintw(w, "%s%s (E)" , op, postfix); break; case IMM : wprintw(w, "%s%s #$%0*"PRIX64 , op, postfix, (addrsize+1) << 1, value); break; case AIND : case AINDX: case AINDY: case IND : case INDX : case INDY : ind = "("; /* Falls through. */ case REL : case ZMX : case ZMY : case ABSX : case ABSY : case ZM : case ABS : wprintw(w, "%s%s %s%s%s$%0*" PRIX64"%s" , op, postfix, ind, of, sign, (addrsize+1) << 1, value, idx); break; } } else { inst_name = ortho_opname[opcode]; memcpy(op, inst_name, 3); disasm_ortho(cpu, w, opcode, prefix, prefix2, ortho_addr, op, postfix, ortho_op, (1 << rs), thread); } int y = getmaxy(w); if (ext_prefix != 0x1D) { wmove(w, y-2, 0); wclrtoeol(w); wprintw(w, "address: $%04"PRIX64, address); } if (address == TX_ADDR || ortho_addr[0] == TX_ADDR || address == RX_ADDR || ortho_addr[1] == RX_ADDR) { wmove(w, y-1, 0); wprintw(w, "TX_ADDR: $%02X, RX_ADDR: $%02X", addr[TX_ADDR], addr[RX_ADDR]); } if (subdbg) { sub_dbg(cpu, dbg_win, address, ortho_addr, thread); } } #undef ORTHO_1CC #undef ORTHO_1OP #undef ORTHO_2OP