summaryrefslogtreecommitdiff
path: root/disasm.c
diff options
context:
space:
mode:
Diffstat (limited to 'disasm.c')
-rw-r--r--disasm.c429
1 files changed, 357 insertions, 72 deletions
diff --git a/disasm.c b/disasm.c
index 8c16db6..74dac5f 100644
--- a/disasm.c
+++ b/disasm.c
@@ -2,6 +2,16 @@
#include "disasm.h"
#include <string.h>
+#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_regs(struct sux *cpu, uint8_t lines, uint8_t thread) {
for (uint8_t i = (24*thread)+2; i <= 24*(thread+1); i++) {
wmove(scr, i, 0);
@@ -24,9 +34,271 @@ void print_regs(struct sux *cpu, uint8_t lines, uint8_t thread) {
wprintw(scr, ", inst: ");
}
-void disasm(struct sux *cpu, uint8_t lines, uint8_t opcode, uint8_t prefix, uint8_t ext_prefix, uint8_t prefix2, uint8_t thread) {
+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 &= mask;
+ value = -(value+1);
+ }
+ 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_1cc(uint8_t opcode) {
+ switch (opcode) {
+ case ORTHO_1CC(SET, NG):
+ case ORTHO_1CC(SET, PO):
+ case ORTHO_1CC(SET, CS):
+ case ORTHO_1CC(SET, CC):
+ case ORTHO_1CC(SET, EQ):
+ case ORTHO_1CC(SET, NE):
+ case ORTHO_1CC(SET, VS):
+ case ORTHO_1CC(SET, VC): return 1;
+ }
+ return 0;
+}
+
+static int is_1op(uint8_t opcode) {
+ switch (opcode) {
+ case ORTHO_1OP(PSH):
+ case ORTHO_1OP(PEA):
+ case ORTHO_1OP(PUL):
+ case ORTHO_1OP(SWP):
+ case ORTHO_1OP(NOT):
+ case ORTHO_1OP(NEG):
+ case ORTHO_1OP(DEC):
+ case ORTHO_1OP(INC):
+ case ORTHO_1OP(CLZ):
+ case ORTHO_1OP(CLO): return 1;
+ }
+ 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, 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][17];
+ 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;
+ if (op[i].type) {
+ uint8_t addr_size = get_ortho_addrsize(prefix, op[i].id);
+ if (addr_size != 0xFF) {
+ uint64_t value = get_offset(op[i].value, addr_size+1, &sign[i]);
+ sprintf(address[i], "$%0*"PRIX64, (addr_size+1)*2, value);
+ }
+ if (op[i].id == MEM_SIB) {
+ sprintf(scale[i], "%u*", op[i].scale+1);
+ }
+ 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 (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;
+ }
+ }
+ }
+ sprintf(idx[i], "%s%s%s%s", scale[i], rind[0], (op[i].rind[1] != 0xFF) ? "+" : "", 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], "#$%*"PRIX64, rs*2, op[i].value); break;
+ case 4: sprintf(opr[i], "%s", reg[i]); break;
+ }
+ }
+ 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)) {
+ 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 = cc;
+ } else if (is_2op(opcode)) {
+ op2 = opr[1];
+ }
+ wprintw(scr, "%s%s%s %s%s %s", inst_name, postfix, os, opr[0], (op_count == 2) ? "," : "", op2);
+ wmove(scr, 29, 0);
+ wclrtoeol(scr);
+ for (int i = 0; i < 2; i++) {
+ if (op[i].type) {
+ sprintf(address[i], "$%04"PRIX64, value[i]);
+ } else {
+ sprintf(address[i], "none");
+ }
+ }
+ wprintw(scr, "destination address: %s, source address: %s", address[0], address[1]);
+}
+
+
+void disasm(struct sux *cpu, 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 = get_addr(cpu, opcode, prefix, ext_prefix, 0, 0, thread);
+ 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, prefix, cpu->pc, ortho_op, ortho_addr, op_type, op_id, 0, 0, thread);
+ }
uint8_t rs = (prefix >> 4) & 3;
char *postfix;
char *of;
@@ -38,15 +310,6 @@ void disasm(struct sux *cpu, uint8_t lines, uint8_t opcode, uint8_t prefix, uint
mask.u64 = 0;
const char *inst_name;
uint8_t inst_type;
- if ((ext_prefix & 0xD) == 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);
op[3] = 0;
switch (rs) {
case 0: postfix = ""; break;
@@ -62,74 +325,92 @@ void disasm(struct sux *cpu, uint8_t lines, uint8_t opcode, uint8_t prefix, uint
case 1 : of = "SP"; break;
case 2 : of = "PC"; break;
}
- uint8_t addrsize = 0;
- char *idx;
- 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;
+ 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;
}
- value = (sign[0] == '-') ? (~value + 1) & mask.u64 : value;
- }
- switch (inst_type) {
- case EIND :
- case BREG :
- case IMPL : wprintw(scr, "%s%s" , inst_name, postfix); break;
- case IMM : wprintw(scr, "%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 ZMX :
- case ZMY :
- case ABSX :
- case ABSY :
- case ZM :
- case ABS : wprintw(scr, "%s%s %s%s%s$%0*" PRIX64"%s" , op, postfix, ind, of, sign, (addrsize+1) << 1, value, idx); break;
- case REL : wprintw(scr, "%s%s %s$%0*"PRIX64 , op, postfix, sign, (addrsize+1) << 1, value); break;
+ switch (inst_type) {
+ case BREG :
+ case IMPL : wprintw(scr, "%s%s" , inst_name, postfix); break;
+ case EIND : wprintw(scr, "%s%s (E)" , op, postfix); break;
+ case IMM : wprintw(scr, "%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 ZMX :
+ case ZMY :
+ case ABSX :
+ case ABSY :
+ case ZM :
+ case ABS : wprintw(scr, "%s%s %s%s%s$%0*" PRIX64"%s" , op, postfix, ind, of, sign, (addrsize+1) << 1, value, idx); break;
+ case REL : wprintw(scr, "%s%s %s$%0*"PRIX64 , op, postfix, sign, (addrsize+1) << 1, value); break;
+ }
+ } else {
+ inst_name = ortho_opname[opcode];
+ memcpy(op, inst_name, 3);
+ disasm_ortho(cpu, opcode, prefix, prefix2, ortho_addr, op, postfix, ortho_op, rs, thread);
}
if (address == TX_ADDR || address == RX_ADDR) {
wmove(scr, 27, 0);
wprintw(scr, "TX_ADDR: $%02X, RX_ADDR: $%02X", addr[TX_ADDR], addr[RX_ADDR]);
}
- wmove(scr, 29, 0);
- wclrtoeol(scr);
- wprintw(scr, "address: $%04"PRIX64, address);
+ if (ext_prefix != 0x1D) {
+ wmove(scr, 29, 0);
+ wclrtoeol(scr);
+ wprintw(scr, "address: $%04"PRIX64, address);
+ }
if (subdbg) {
uint8_t ln = 33;
uint16_t line_idx = 0;
@@ -253,3 +534,7 @@ void disasm(struct sux *cpu, uint8_t lines, uint8_t opcode, uint8_t prefix, uint
}
}
+
+#undef ORTHO_1CC
+#undef ORTHO_1OP
+#undef ORTHO_2OP