/* dasm CP/M emulator - instruction disassembler Written by D'Arcy J.M. Cain darcy@druid */ #include #include #include "cpm.h" #define get_prog_word(buf) (buf[1] + (buf[2] << 8)) #define get_prog_byte(buf) (*buf) static char *get_b_reg(int reg) { switch(reg & 0x07) { case 7: return("A"); case 6: return("(HL)"); case 0: return("B"); case 1: return("C"); case 2: return("D"); case 3: return("E"); case 4: return("H"); case 5: return("L"); } return(NULL); } static char *get_w_reg(int reg) { switch (reg & 0x03) { case 2: return("HL"); case 1: return("DE"); case 0: return("BC"); case 3: return("SP"); } return(NULL); } static char *get_s_reg(int reg) { switch (reg & 0x03) { case 2: return("HL"); case 1: return("DE"); case 0: return("BC"); case 3: return("AF"); } return(NULL); } static int relative(int r) { if (r & 0x80) r |= -256; return(PC + r + 2); } static char *condition(int word) { switch (word & 0x07) { case 0: return("NZ"); case 1: return("Z"); case 2: return("NC"); case 3: return("C"); case 4: return("PO"); case 5: return("PE"); case 6: return("P"); case 7: return("M"); } return("\a* * * Internal error (condition()) * * *"); } const char *dasm(const byte *buf) { static char str[32]; char s[32]; switch (*buf & 0xc0) /* get class of opcode */ { case 0x40: /* data transfer */ if (*buf == 0x76) /* HALT - special case */ return("HALT"); sprintf(str, "LD\t%s, %s", get_b_reg(*buf >> 3), get_b_reg(*buf)); return(str); case 0x80: /* 8 bit math & logic */ strcpy(s, get_b_reg(*buf)); strcpy(str, "* * * Internal error * * *"); math_immediate: /* comes from misc instructions */ switch ((*buf >> 3) & 7) /* logic op */ { case 1: /* ADC */ sprintf(str, "ADC\tA, %s", s); break; case 0: /* ADD */ sprintf(str, "ADD\tA, %s", s); break; case 3: /* SBC */ sprintf(str, "SBC\tA, %s", s); break; case 2: /* SUB */ sprintf(str, "SUB\tA, %s", s); break; case 4: /* AND */ sprintf(str, "AND\tA, %s", s); break; case 5: /* XOR */ sprintf(str, "XOR\tA, %s", s); break; case 6: /* OR */ sprintf(str, "OR\tA, %s", s); break; case 7: /* CP */ sprintf(str, "CP\tA, %s", s); break; } /* end - logic op */ return(str); case 0xc0: /* Misc */ if ((*buf & 0x07) == 0x06) { sprintf(s, "0%02.2xH", buf[1]); goto math_immediate; /* sometimes they're necessary */ } if ((*buf & 0x0f) == 1) /* POP */ { sprintf(str, "POP\t%s", get_s_reg(*buf >> 4)); return(str); } if ((*buf & 0x0f) == 5) /* PUSH */ { sprintf(str, "PUSH\t%s", get_s_reg(*buf >> 4)); return(str); } switch (*buf & 0x07) /* BRANCH */ { case 0: /* RET cc */ sprintf(str, "RET\t%s", condition(*buf >> 3)); return(str); case 2: /* JP cc */ sprintf(str, "JP\t%s, 0%02.2x%02.2xH", condition(*buf >> 3), buf[2], buf[1]); return(str); case 4: /* CALL cc */ sprintf(str, "CALL\t%s, 0%02.2x%02.2xH", condition(*buf >> 3), buf[2], buf[1]); return(str); case 7: /* RST n */ sprintf(str, "RST\t%d", (*buf >> 3) & 0x07); return(str); } /* end - BRANCH */ switch (*buf) /* misc */ { case 0xcd: /* CALL */ sprintf(str, "CALL\t0%02.2x%02.2xH", buf[2], buf[1]); return(str); case 0xc3: /* JP */ sprintf(str, "JP\t0%02.2x%02.2xH", buf[2], buf[1]); return(str); case 0xc9: /* RET */ sprintf(str, "RET"); return(str); case 0xeb: /* EX DE, HL */ return("EX\tDE, HL"); case 0xe9: /* JP (HL) */ return("JP\t(HL)"); case 0xe3: /* EX (SP), HL */ return("EX\t(SP), HL"); case 0xf9: /* LD SP, HL */ return("LD\tSP, HL"); case 0xf3: /* DI */ return("DI"); case 0xfb: /* EI */ return("EI"); } /* misc */ sprintf(str, "Unrecognized command (0x%02.2x)", *buf); return(str); case 0: switch (*buf & 0x07) /* misc data (3) */ { case 4: /* INC byte */ sprintf(str, "INC\t%s", get_b_reg(*buf >> 3)); return(str); case 5: /* DEC byte */ sprintf(str, "DEC\t%s", get_b_reg(*buf >> 3)); return(str); case 6: /* LD byte immediate */ sprintf(str, "LD\t%s, 0%02.2xH", get_b_reg(*buf >> 3), buf[1]); return(str); } /* end - misc data (3) */ switch (*buf & 0x0f) /* misc data (4) */ { case 1: /* LD word immediate */ sprintf(str, "LD\t%s, 0%02.2x%02.2xH", get_w_reg(*buf >> 4), buf[2], buf[1]); return(str); case 0x03: /* INC word */ sprintf(str, "INC\t%s", get_w_reg(*buf >> 4)); return(str); case 0x0b: /* DEC word */ sprintf(str, "DEC\t%s", get_w_reg(*buf >> 4)); return(str); case 0x09: /* ADD HL, ss */ sprintf(str, "ADD\tHL, %s", get_w_reg(*buf >> 4)); return(str); } /* end - misc date (4) */ switch (*buf) /* misc data */ { case 0: /* NOP */ return("NOP"); case 0x02: /* LD (BC), A */ return("LD\t(BC), A"); case 0x10: sprintf(str, "DJNZ\t0%04.4xH", relative(buf[1])); return(str); case 0x20: sprintf(str, "JR\tNZ, 0%04.4xH", relative(buf[1])); return(str); case 0x30: sprintf(str, "JR\tNC, 0%04.4xH", relative(buf[1])); return(str); case 0x18: sprintf(str, "JR\t, 0%04.4xH", relative(buf[1])); return(str); case 0x28: sprintf(str, "JR\tZ, 0%04.4xH", relative(buf[1])); return(str); case 0x38: sprintf(str, "JR\tC, 0%04.4xH", relative(buf[1])); return(str); case 0x12: /* LD (DE), A */ return("LD\t(DE), A"); case 0x22: /* LD (nn), HL */ sprintf(str, "LD\t(0%02.2x%02.2xH), HL", buf[2], buf[1]); return(str); case 0x32: /* LD (nn), A */ sprintf(str, "LD\t(0%02.2x%02.2xH), A", buf[2], buf[1]); return(str); case 0x0a: /* LD A, (BC) */ return("LD\tA, (BC)"); case 0x1a: /* LD A, (DE) */ return("LD\tA, (DE)"); case 0x2a: /* LD HL, (nn) */ sprintf(str, "LD\tHL, (0%02.2x%02.2xH)", buf[2], buf[1]); return(str); case 0x3a: /* LD A, (nn) */ sprintf(str, "LD\tA, (0%02.2x%02.2xH)", buf[2], buf[1]); return(str); case 7: /* RLCA */ return("RLCA"); case 0x0f: /* RRCA */ return("RRCA"); case 0x17: /* RLA */ return("RLA"); case 0x1f: /* RRA */ return("RRA"); case 0x27: /* DAA */ return("DAA"); case 0x2f: /* CPL */ return("CPL"); case 0x37: /* SCF */ return("SCF"); case 0x3f: /* CCF */ return("CCF"); } /* end - misc date */ return("* * * Internal error * * *"); } /* end class */ return("* * * Internal error * * *"); }