/*************************************************************************** dsp32dis.c Disassembler for the portable AT&T/Lucent DSP32C emulator. Written by Aaron Giles ***************************************************************************/ #include "dsp32.h" /*************************************************************************** MEMORY ACCESSORS ***************************************************************************/ #define ABS(x) (((x) >= 0) ? (x) : -(x)) /*************************************************************************** CODE CODE ***************************************************************************/ static const char *const sizesuffix[] = { "", "e" }; static const char *const unarysign[] = { "", "-" }; static const char *const sign[] = { "+", "-" }; static const char *const aMvals[] = { "a0", "a1", "a2", "a3", "0.0", "1.0", "Format 4", "Reserved" }; static const char *const memsuffix[] = { "h", "l", "", "e" }; static const char *const functable[] = { "ic", "oc", "float", "int", "round", "ifalt", "ifaeq", "ifagt", "reserved8", "reserved9", "float24", "int24", "ieee", "dsp", "seed", "reservedf" }; static const char *const condtable[] = { "false", "true", "pl", "mi", "ne", "eq", "vc", "vs", "cc", "cs", "ge", "lt", "gt", "le", "hi", "ls", "auc", "aus", "age", "alt", "ane", "aeq", "avc", "avs", "agt", "ale", "!resd", "resd", "!rese", "rese", "!resf", "resf", "ibe", "ibf", "obf", "obe", "pde", "pdf", "pie", "pif", "syc", "sys", "fbc", "fbs", "ireq1_lo", "ireq1_hi", "ireq2_lo", "ireq2_hi", "!?18", "?18", "!?19", "?19", "!?1a", "?1a", "!?1b", "?1b", "!?1c", "?1c", "!?1d", "?1d", "!?1e", "?1e", "!?1f", "?1f" }; static const char *const regname[] = { "0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc", "0", "r15", "r16", "r17", "r18", "r19", "-1", "1", "r20", "r21", "dauc", "ioc", "res1c", "r22", "pcsh", "res1f" }; static const char *const regnamee[] = { "0", "r1e", "r2e", "r3e", "r4e", "r5e", "r6e", "r7e", "r8e", "r9e", "r10e", "r11e", "r12e", "r13e", "r14e", "pce", "0", "r15e", "r16e", "r17e", "r18e", "r19e", "--", "++", "r20e", "r21e", "dauce", "ioce", "res1ce", "r22e", "pcshe", "res1fe" }; static char tempbuf[10][40]; INLINE char *signed_16bit_unary(INT16 val) { static char temp[10]; if (val < 0) sprintf(temp, "-$%x", -val); else sprintf(temp, "$%x", val); return temp; } INLINE char *signed_16bit_sep(INT16 val) { static char temp[10]; if (val < 0) sprintf(temp, " - $%x", -val); else sprintf(temp, " + $%x", val); return temp; } INLINE char *signed_16bit_sep_nospace(INT16 val) { static char temp[10]; if (val < 0) sprintf(temp, "-$%x", -val); else sprintf(temp, "+$%x", val); return temp; } INLINE char *unsigned_16bit_size(INT16 val, UINT8 size) { static char temp[10]; if (size) sprintf(temp, "$%06x", (INT32)val & 0xffffff); else sprintf(temp, "$%04x", val & 0xffff); return temp; } static UINT8 lastp; static const char *dasm_XYZ(UINT8 bits, char *buffer) { UINT8 p = bits >> 3; UINT8 i = bits & 7; if (p) { if (p == 15) p = lastp; /* P=15 means Z inherits from Y, Y inherits from X */ lastp = p; switch (i) { case 0: sprintf(buffer, "*r%d", p); break; case 1: case 2: case 3: case 4: case 5: sprintf(buffer, "*r%d++r%d", p, i + 14); break; case 6: sprintf(buffer, "*r%d--", p); break; case 7: sprintf(buffer, "*r%d++", p); break; } } else { switch (i) { case 0: case 1: case 2: case 3: sprintf(buffer, "a%d", i); break; case 4: sprintf(buffer, "ibuf"); break; case 5: sprintf(buffer, "obuf"); break; case 6: sprintf(buffer, "pdr"); break; case 7: buffer[0] = 0; break; } } return buffer; } static const char *dasm_PI(UINT16 bits, char *buffer) { UINT8 p = bits >> 5; UINT8 i = bits & 0x1f; if (p) { switch (i) { case 0: case 16: sprintf(buffer, "*%s", regname[p]); break; case 22: sprintf(buffer, "*%s--", regname[p]); break; case 23: sprintf(buffer, "*%s++", regname[p]); break; default: sprintf(buffer, "*%s++%s", regname[p], regname[i]); break; } } else { switch (i) { case 4: sprintf(buffer, "ibuf"); break; case 5: sprintf(buffer, "obuf"); break; case 6: sprintf(buffer, "pdr"); break; case 14: sprintf(buffer, "piop"); break; case 20: sprintf(buffer, "pdr2"); break; case 22: sprintf(buffer, "pir"); break; case 30: sprintf(buffer, "pcw"); break; default: sprintf(buffer, "????"); break; } } return buffer; } unsigned dasm_dsp32(char *buffer, unsigned pc, UINT32 op) { UINT32 flags = 0; switch (op >> 25) { /* DA format 1 */ case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: case 0x1b: { const char *X = dasm_XYZ((op >> 14) & 0x7f, tempbuf[0]); const char *Y = dasm_XYZ((op >> 7) & 0x7f, tempbuf[1]); const char *Z = dasm_XYZ((op >> 0) & 0x7f, tempbuf[2]); const char *aM = aMvals[(op >> 26) & 7]; UINT8 aN = (op >> 21) & 3; if ((op & 0x7f) == 7) { if (aM[0] == '0') sprintf(buffer, "a%d = %s%s", aN, unarysign[(op >> 24) & 1], Y); else if (aM[0] == '1') sprintf(buffer, "a%d = %s%s %s %s", aN, unarysign[(op >> 24) & 1], Y, sign[(op >> 23) & 1], X); else sprintf(buffer, "a%d = %s%s %s %s * %s", aN, unarysign[(op >> 24) & 1], Y, sign[(op >> 23) & 1], aM, X); } else { if (aM[0] == '0') sprintf(buffer, "%s = a%d = %s%s", Z, aN, unarysign[(op >> 24) & 1], Y); else if (aM[0] == '1') sprintf(buffer, "%s = a%d = %s%s %s %s", Z, aN, unarysign[(op >> 24) & 1], Y, sign[(op >> 23) & 1], X); else sprintf(buffer, "%s = a%d = %s%s %s %s * %s", Z, aN, unarysign[(op >> 24) & 1], Y, sign[(op >> 23) & 1], aM, X); } break; } /* DA format 2 */ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2a: case 0x2b: { const char *X = dasm_XYZ((op >> 14) & 0x7f, tempbuf[0]); const char *Y = dasm_XYZ((op >> 7) & 0x7f, tempbuf[1]); const char *Z = dasm_XYZ((op >> 0) & 0x7f, tempbuf[2]); const char *aM = aMvals[(op >> 26) & 7]; UINT8 aN = (op >> 21) & 3; if ((op & 0x7f) == 7) { if (aM[0] == '0') sprintf(buffer, "a%d = %s%s * %s", aN, unarysign[(op >> 23) & 1], Y, X); else sprintf(buffer, "a%d = %s%s %s %s * %s", aN, unarysign[(op >> 24) & 1], aM, sign[(op >> 23) & 1], Y, X); } else { if (aM[0] == '0') sprintf(buffer, "a%d = %s(%s=%s) * %s", aN, unarysign[(op >> 23) & 1], Z, Y, X); else sprintf(buffer, "a%d = %s%s %s (%s=%s) * %s", aN, unarysign[(op >> 24) & 1], aM, sign[(op >> 23) & 1], Z, Y, X); } break; } /* DA format 3 */ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x3a: case 0x3b: { const char *X = dasm_XYZ((op >> 14) & 0x7f, tempbuf[0]); const char *Y = dasm_XYZ((op >> 7) & 0x7f, tempbuf[1]); const char *Z = dasm_XYZ((op >> 0) & 0x7f, tempbuf[2]); const char *aM = aMvals[(op >> 26) & 7]; UINT8 aN = (op >> 21) & 3; if ((op & 0x7f) == 7) { if (aM[0] == '0') sprintf(buffer, "a%d = %s%s * %s", aN, unarysign[(op >> 23) & 1], Y, X); else sprintf(buffer, "a%d = %s%s %s %s * %s", aN, unarysign[(op >> 24) & 1], aM, sign[(op >> 23) & 1], Y, X); } else { if (aM[0] == '0') sprintf(buffer, "%s = a%d = %s%s * %s", Z, aN, unarysign[(op >> 23) & 1], Y, X); else sprintf(buffer, "%s = a%d = %s%s %s %s * %s", Z, aN, unarysign[(op >> 24) & 1], aM, sign[(op >> 23) & 1], Y, X); } break; } /* DA format 4 */ case 0x1c: case 0x1d: { const char *X = dasm_XYZ((op >> 14) & 0x7f, tempbuf[0]); const char *Y = dasm_XYZ((op >> 7) & 0x7f, tempbuf[1]); const char *Z = dasm_XYZ((op >> 0) & 0x7f, tempbuf[2]); UINT8 aN = (op >> 21) & 3; if ((op & 0x7f) == 7) sprintf(buffer, "a%d = %s%s %s %s", aN, unarysign[(op >> 24) & 1], Y, sign[(op >> 23) & 1], X); else sprintf(buffer, "a%d = %s(%s=%s) %s %s", aN, unarysign[(op >> 24) & 1], Z, Y, sign[(op >> 23) & 1], X); break; } /* DA format 5 */ case 0x3c: case 0x3d: case 0x3e: case 0x3f: if ((op & 0x7f) == 7) sprintf(buffer, "a%d = %s(%s)", (op >> 21) & 3, // aN functable[(op >> 23) & 15], // G dasm_XYZ((op >> 7) & 0x7f, tempbuf[0])); // Y else sprintf(buffer, "%s = a%d = %s(%s)", dasm_XYZ((op >> 0) & 0x7f, tempbuf[2]), // Z (op >> 21) & 3, // aN functable[(op >> 23) & 15], // G dasm_XYZ((op >> 7) & 0x7f, tempbuf[0])); // Y break; /* CA formats 0/1 */ case 0x00: case 0x01: case 0x02: case 0x03: { const char *rH = regname[(op >> 16) & 0x1f]; UINT8 C = (op >> 21) & 0x3f; INT16 N = (INT16)op; if (op == 0) sprintf(buffer, "nop"); else if (C == 1 && N == 0 && ((op >> 16) & 0x1f) == 0x1e) sprintf(buffer, "ireturn"); else if (C == 1) { if (((op >> 16) & 0x1f) == 15) sprintf(buffer, "goto %s%s [%x]", rH, signed_16bit_sep_nospace(N), (pc + 8 + N) & 0xffffff); else if (N && rH[0] != '0') sprintf(buffer, "goto %s%s", rH, signed_16bit_sep_nospace(N)); else if (N) sprintf(buffer, "goto $%x", ((INT32)N & 0xffffff)); else { if (((op >> 16) & 0x1f) == 20) flags = DASMFLAG_STEP_OUT; sprintf(buffer, "goto %s", rH); } } else { if (((op >> 16) & 0x1f) == 15) sprintf(buffer, "if (%s) goto %s%s [%x]", condtable[C], rH, signed_16bit_sep_nospace(N), (pc + 8 + N) & 0xffffff); else if (N && rH[0] != '0') sprintf(buffer, "if (%s) goto %s%s", condtable[C], rH, signed_16bit_sep_nospace(N)); else if (N) sprintf(buffer, "if (%s) goto $%x", condtable[C], ((INT32)N & 0xffffff)); else { if (((op >> 16) & 0x1f) == 20) flags = DASMFLAG_STEP_OUT; sprintf(buffer, "if (%s) goto %s", condtable[C], rH); } } break; } /* CA format 3a */ case 0x06: case 0x07: { const char *rH = regname[(op >> 16) & 0x1f]; const char *rM = regname[(op >> 21) & 0x1f]; INT16 N = (INT16)op; if (((op >> 16) & 0x1f) == 15) { sprintf(buffer, "if (%s-- >= 0) goto %s%s [%x]", rM, rH, signed_16bit_sep_nospace(N), (pc + 8 + N) & 0xffffff); if (((pc + 8 + N) & 0xffffff) < pc) flags = DASMFLAG_STEP_OVER; } else if (N && rH[0] != '0') sprintf(buffer, "if (%s-- >= 0) goto %s%s", rM, rH, signed_16bit_sep_nospace(N)); else if (N) { sprintf(buffer, "if (%s-- >= 0) goto $%x", rM, ((INT32)N & 0xffffff)); if (((INT32)N & 0xffffff) < pc) flags = DASMFLAG_STEP_OVER; } else { sprintf(buffer, "if (%s-- >= 0) goto %s", rM, rH); if (((op >> 16) & 0x1f) == 20) flags = DASMFLAG_STEP_OUT; } break; } /* CA format 3b/3c */ case 0x46: if (((op >> 21) & 0x1f) == 0) sprintf(buffer, "do %d,%d", (op >> 16) & 0x1f, op & 0x7ff); else if (((op >> 21) & 0x1f) == 1) sprintf(buffer, "do %d,%s", (op >> 16) & 0x1f, regname[op & 0x1f]); break; /* CA format 4 */ case 0x08: case 0x09: { const char *rH = regname[(op >> 16) & 0x1f]; const char *rM = regname[(op >> 21) & 0x1f]; INT16 N = (INT16)op; if (((op >> 16) & 0x1f) == 15) sprintf(buffer, "call %s%s (%s) [%x]", rH, signed_16bit_sep_nospace(N), rM, (pc + 8 + N) & 0xffffff); else if (N && rH[0] != '0') sprintf(buffer, "call %s%s (%s)", rH, signed_16bit_sep_nospace(N), rM); else if (N) sprintf(buffer, "call $%x (%s)", ((INT32)N & 0xffffff), rM); else sprintf(buffer, "call %s (%s)", rH, rM); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; } /* CA format 5a/5b */ case 0x0a: case 0x0b: case 0x4a: case 0x4b: { const char *rD = regname[(op >> 21) & 0x1f]; const char *rH = regname[(op >> 16) & 0x1f]; const char *s = sizesuffix[(op >> 31) & 1]; INT16 N = (INT16)op; if (N == 0) sprintf(buffer, "%s%s = %s%s", rD, s, rH, s); else if (rH[0] == '0') sprintf(buffer, "%s%s = %s", rD, s, signed_16bit_unary(N)); else sprintf(buffer, "%s%s = %s%s%s", rD, s, rH, s, signed_16bit_sep((INT16)op)); break; } /* CA format 6a/6b */ case 0x0c: case 0x4c: { const char *rD = regname[(op >> 16) & 0x1f]; const char *rS1 = regname[(op >> 5) & 0x1f]; const char *rS2 = regname[(op >> 0) & 0x1f]; const char *s = sizesuffix[(op >> 31) & 1]; UINT8 threeop = (op >> 11) & 1; char condbuf[40] = { 0 }; if ((op >> 10) & 1) sprintf(condbuf, "if (%s) ", condtable[(op >> 12) & 15]); switch ((op >> 21) & 15) { /* add */ case 0: if (threeop) { if (rS1[0] == '0' && rS2[0] == '0') sprintf(buffer, "%s%s%s = 0", condbuf, rD, s); else if (rS1[0] == '0') sprintf(buffer, "%s%s%s = %s%s", condbuf, rD, s, rS2, s); else if (rS2[0] == '0') sprintf(buffer, "%s%s%s = %s%s", condbuf, rD, s, rS1, s); else sprintf(buffer, "%s%s%s = %s%s + %s%s", condbuf, rD, s, rS2, s, rS1, s); } else { if (rS1[0] == '0') sprintf(buffer, "%s%s%s = %s%s", condbuf, rD, s, rD, s); else sprintf(buffer, "%s%s%s = %s%s + %s%s", condbuf, rD, s, rD, s, rS1, s); } break; case 1: sprintf(buffer, "%s%s%s = %s%s * 2", condbuf, rD, s, rS1, s); break; case 2: if (threeop) sprintf(buffer, "%s%s%s = %s%s - %s%s", condbuf, rD, s, rS1, s, rS2, s); else sprintf(buffer, "%s%s%s = %s%s - %s%s", condbuf, rD, s, rS1, s, rD, s); break; case 3: if (threeop) sprintf(buffer, "%s%s%s = %s%s # %s%s", condbuf, rD, s, rS2, s, rS1, s); else sprintf(buffer, "%s%s%s = %s%s # %s%s", condbuf, rD, s, rD, s, rS1, s); break; case 4: if (threeop) sprintf(buffer, "%s%s%s = %s%s - %s%s", condbuf, rD, s, rS2, s, rS1, s); else sprintf(buffer, "%s%s%s = %s%s - %s%s", condbuf, rD, s, rD, s, rS1, s); break; case 5: sprintf(buffer, "%s%s%s = -%s%s", condbuf, rD, s, rS1, s); break; case 6: if (threeop) sprintf(buffer, "%s%s%s = %s%s &~ %s%s", condbuf, rD, s, rS2, s, rS1, s); else sprintf(buffer, "%s%s%s = %s%s &~ %s%s", condbuf, rD, s, rD, s, rS1, s); break; case 7: // if (threeop) // sprintf(buffer, "%s%s%s - %s%s", condbuf, rS2, s, rS1, s); // else sprintf(buffer, "%s%s%s - %s%s", condbuf, rD, s, rS1, s); break; case 8: if (threeop) sprintf(buffer, "%s%s%s = %s%s ^ %s%s", condbuf, rD, s, rS2, s, rS1, s); else sprintf(buffer, "%s%s%s = %s%s ^ %s%s", condbuf, rD, s, rD, s, rS1, s); break; case 9: sprintf(buffer, "%s%s%s = %s%s >>> 1", condbuf, rD, s, rS1, s); break; case 10: if (threeop) sprintf(buffer, "%s%s%s = %s%s | %s%s", condbuf, rD, s, rS2, s, rS1, s); else sprintf(buffer, "%s%s%s = %s%s | %s%s", condbuf, rD, s, rD, s, rS1, s); break; case 11: sprintf(buffer, "%s%s%s = %s%s <<< 1", condbuf, rD, s, rS1, s); break; case 12: sprintf(buffer, "%s%s%s = %s%s >> 1", condbuf, rD, s, rS1, s); break; case 13: sprintf(buffer, "%s%s%s = %s%s / 2", condbuf, rD, s, rS1, s); break; case 14: if (threeop) sprintf(buffer, "%s%s%s = %s%s & %s%s", condbuf, rD, s, rS2, s, rS1, s); else sprintf(buffer, "%s%s%s = %s%s & %s%s", condbuf, rD, s, rD, s, rS1, s); break; case 15: // if (threeop) // sprintf(buffer, "%s%s%s & %s%s", condbuf, rS1, s, rS2, s); // else sprintf(buffer, "%s%s%s & %s%s", condbuf, rD, s, rS1, s); break; } break; } /* CA format 6c/6d */ case 0x0d: case 0x4d: { const char *rD = regname[(op >> 16) & 0x1f]; const char *s = sizesuffix[(op >> 31) & 1]; INT16 N = (INT16)op; switch ((op >> 21) & 15) { case 0: case 1: case 5: case 9: case 11: case 12: case 13: sprintf(buffer, "Unexpected: %08X", op); break; case 2: sprintf(buffer, "%s%s = %s - %s%s", rD, s, signed_16bit_unary(N), rD, s); break; case 3: sprintf(buffer, "%s%s = %s%s # %s", rD, s, rD, s, signed_16bit_unary(N)); break; case 4: sprintf(buffer, "%s%s = %s%s - %s", rD, s, rD, s, signed_16bit_unary(N)); break; case 6: sprintf(buffer, "%s%s = %s%s &~ %s", rD, s, rD, s, unsigned_16bit_size(N, (op >> 31) & 1)); break; case 7: sprintf(buffer, "%s%s - %s", rD, s, signed_16bit_unary(N)); break; case 8: sprintf(buffer, "%s%s = %s%s ^ %s", rD, s, rD, s, unsigned_16bit_size(N, (op >> 31) & 1)); break; case 10: sprintf(buffer, "%s%s = %s%s | %s", rD, s, rD, s, unsigned_16bit_size(N, (op >> 31) & 1)); break; case 14: sprintf(buffer, "%s%s = %s%s & %s", rD, s, rD, s, unsigned_16bit_size(N, (op >> 31) & 1)); break; case 15: sprintf(buffer, "%s%s & %s", rD, s, unsigned_16bit_size(N, (op >> 31) & 1)); break; } break; } /* CA format 7a */ case 0x0e: if ((op >> 24) & 1) sprintf(buffer, "*%08X = %s%s", (INT16)op, regname[(op >> 16) & 0x1f], memsuffix[(op >> 22) & 3]); else sprintf(buffer, "%s%s = *%08X", regname[(op >> 16) & 0x1f], memsuffix[(op >> 22) & 3], (INT16)op); break; /* CA format 7b */ case 0x0f: if ((op >> 24) & 1) sprintf(buffer, "%s = %s%s", dasm_PI(op & 0x3ff, tempbuf[0]), regname[(op >> 16) & 0x1f], memsuffix[(op >> 22) & 3]); else sprintf(buffer, "%s%s = %s", regname[(op >> 16) & 0x1f], memsuffix[(op >> 22) & 3], dasm_PI(op & 0x3ff, tempbuf[0])); break; /* CA format 8a */ case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: { INT32 N = (op & 0xffff) | ((INT32)((op & 0x1fe00000) << 3) >> 8); const char *rH = regname[(op >> 16) & 0x1f]; if (((op >> 16) & 0x1f) == 15) sprintf(buffer, "goto %s%s [%x]", rH, signed_16bit_sep_nospace(N), (pc + 8 + N) & 0xffffff); else if (N && rH[0] != '0') sprintf(buffer, "goto %s%s", rH, signed_16bit_sep_nospace(N)); else if (N) sprintf(buffer, "goto $%x", ((INT32)N & 0xffffff)); else { if (((op >> 16) & 0x1f) == 20) flags = DASMFLAG_STEP_OUT; sprintf(buffer, "goto %s", rH); } break; } /* CA format 8b */ case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: { INT32 immed = (op & 0xffff) | ((INT32)((op & 0x1fe00000) << 3) >> 8); sprintf(buffer, "%s = $%x", regnamee[(op >> 16) & 0x1f], immed & 0xffffff); break; } /* CA format 8c */ case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: { INT32 N = (op & 0xffff) | ((INT32)((op & 0x1fe00000) << 3) >> 8); const char *rM = regname[(op >> 16) & 0x1f]; sprintf(buffer, "call $%x (%s)", N & 0xffffff, rM); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; } } return 4 | flags | DASMFLAG_SUPPORTED; }