/*---------------------------------------------------------------------------- If compiled as an executable "Dis8051", then the command line used to generate the file r.s above would have been: Dis8051 r.s or, for binary mode: Dis8051 r.bin >r,s There is no copyright on this software. You may use it as you wish, wherever you wish. It is being distributed with the philosophy that the more of my software pervades this world, and the more that my style influences others, the better off software engineering (and the world) will be. Send comments and feedback to markh@csd4.csd.uwm.edu. Direct correspondence can be sent to: Mark Hopkins Consulting 2619 North Oakland Avenue, Suite 204 Milwaukee, Wisconsin 53211-3523 (414)332-8857 ------------------------ modified by john maushammer: http://www.maushammer.com -- "prettier" output for readability, not compilability. -- binary file read -- handles program memory size of up to 64K instead of 16K. -- changed hex output from 1234h to 1234 (argh, 0abcdh is ugly!) -- added address and hex bytes out for each line of assembled code -- comments are now mandatory in "entries" file ( line format: 4 hex bytes, comments (>= 1 character!), then return. -- limited call-counter to 26 instead of 31 (so it ends at Z) It also starts at A. */ #include typedef unsigned char byte; typedef unsigned int word; byte Arg[3]; word PC; byte Generating; byte Ref[0x10000], Hex[0x10000]; #define ENTRY 0x80 #define OP 0x40 #define ARG 0x20 #define LINKS 0x1f word Paged(byte P) { return PC&0xf800 | (Arg[0]&0xe0) << 3 | P; }; word Relative(byte R) { return PC + (signed char)R; }; word Entries[0x100], *EP = Entries; void PUSH(word Address) { byte B = Ref[Address]&LINKS; if (Ref[Address]&ARG) { fprintf(stderr, "Entry into ARG at %04x.\n", PC); return; } // if (++B <= LINKS) Ref[Address] = Ref[Address]&~LINKS | B; if (++B <= 26) Ref[Address] = Ref[Address]&~LINKS | B; if (Ref[Address]&ENTRY) return; Ref[Address] |= ENTRY; if (Ref[Address]&OP) return; if (EP - Entries == 0x100) { fprintf(stderr, "Too many entries, PC = %04x.\n", PC); exit(1); } *EP++ = Address; }; byte Xs[0x100] = { 1, 14, 15, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 6, 7, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 14, 9, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 6, 9, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 14, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 14, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 2, 25, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 14, 14, 2, 1, 1, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 6, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 14, 2, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 2, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 14, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 6, 2, 1, 1, 7, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 1, 14, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; char *Ns[0x100] = { "nop", "ajmp %P", "ljmp %L", "rr A", "inc A", "inc %D", "inc %i", "inc %i", "inc %n", "inc %n", "inc %n", "inc %n", "inc %n", "inc %n", "inc %n", "inc %n", "jbc %B, %R", "acall %P", "lcall %L", "rrc A", "dec A", "dec %D", "dec %i", "dec %i", "dec %n", "dec %n", "dec %n", "dec %n", "dec %n", "dec %n", "dec %n", "dec %n", "jb %B, %R", "ajmp %P", "ret", "rl A", "add A, %I", "add A, %D", "add A, %i", "add A, %i", "add A, %n", "add A, %n", "add A, %n", "add A, %n", "add A, %n", "add A, %n", "add A, %n", "add A, %n", "jnb %B, %R", "acall %P", "reti", "rlc A", "addc A, %I", "addc A, %D", "addc A, %i", "addc A, %i", "addc A, %n", "addc A, %n", "addc A, %n", "addc A, %n", "addc A, %n", "addc A, %n", "addc A, %n", "addc A, %n", "jc %R", "ajmp %P", "orl %D, A", "orl %D, %I", "orl A, %I", "orl A, %D", "orl A, %i", "orl A, %i", "orl A, %n", "orl A, %n", "orl A, %n", "orl A, %n", "orl A, %n", "orl A, %n", "orl A, %n", "orl A, %n", "jnc %R", "acall %P", "anl %D, A", "anl %D, %I", "anl A, %I", "anl A, %D", "anl A, %i", "anl A, %i", "anl A, %n", "anl A, %n", "anl A, %n", "anl A, %n", "anl A, %n", "anl A, %n", "anl A, %n", "anl A, %n", "jz %R", "ajmp %P", "xrl %D, A", "xrl %D, %I", "xrl A, %I", "xrl A, %D", "xrl A, %i", "xrl A, %i", "xrl A, %n", "xrl A, %n", "xrl A, %n", "xrl A, %n", "xrl A, %n", "xrl A, %n", "xrl A, %n", "xrl A, %n", "jnz %R", "acall %P", "orl C, %B", "jmp @A+DPTR", "mov A, %I", "mov %D, %I", "mov %i, %I", "mov %i, %I", "mov %n, %I", "mov %n, %I", "mov %n, %I", "mov %n, %I", "mov %n, %I", "mov %n, %I", "mov %n, %I", "mov %n, %I", "sjmp %R", "ajmp %P", "anl C, %B", "movc A, @A+PC", "div AB", "mov %2D, %1D", "mov %D, %i", "mov %D, %i", "mov %D, %n", "mov %D, %n", "mov %D, %n", "mov %D, %n", "mov %D, %n", "mov %D, %n", "mov %D, %n", "mov %D, %n", "mov DPTR, %W", "acall %P", "mov %B, C", "movc A, @A+DPTR", "subb A, %I", "subb A, %D", "subb A, %i", "subb A, %i", "subb A, %n", "subb A, %n", "subb A, %n", "subb A, %n", "subb A, %n", "subb A, %n", "subb A, %n", "subb A, %n", "orl C, /%B", "ajmp %P", "mov C, %B", "inc DPTR", "mul AB", "ERROR", "mov %i, %D", "mov %i, %D", "mov %n, %D", "mov %n, %D", "mov %n, %D", "mov %n, %D", "mov %n, %D", "mov %n, %D", "mov %n, %D", "mov %n, %D", "anl C, /%B", "acall %P", "cpl %B", "cpl C", "cjne A, %I, %R", "cjne A, %D, %R", "cjne %i, %I, %R", "cjne %i, %I, %R", "cjne %n, %I, %R", "cjne %n, %I, %R", "cjne %n, %I, %R", "cjne %n, %I, %R", "cjne %n, %I, %R", "cjne %n, %I, %R", "cjne %n, %I, %R", "cjne %n, %I, %R", "push %D", "ajmp %P", "clr %B", "clr C", "swap A", "xch A, %D", "xch A, %i", "xch A, %i", "xch A, %n", "xch A, %n", "xch A, %n", "xch A, %n", "xch A, %n", "xch A, %n", "xch A, %n", "xch A, %n", "pop %D", "acall %P", "setb %B", "setb C", "da A", "djnz %D, %R", "xchd A, %i", "xchd A, %i", "djnz %n, %R", "djnz %n, %R", "djnz %n, %R", "djnz %n, %R", "djnz %n, %R", "djnz %n, %R", "djnz %n, %R", "djnz %n, %R", "movx A, @DPTR", "ajmp %P", "movx A, @R0", "movx A, @R1", "clr A", "mov A, %D", "mov A, %i", "mov A, %i", "mov A, %n", "mov A, %n", "mov A, %n", "mov A, %n", "mov A, %n", "mov A, %n", "mov A, %n", "mov A, %n", "movx @DPTR, A", "acall %P", "movx @R0, A", "movx @R1, A", "cpl A", "mov %D, A", "mov %i, A", "mov %i, A", "mov %n, A", "mov %n, A", "mov %n, A", "mov %n, A", "mov %n, A", "mov %n, A", "mov %n, A", "mov %n, A" }; void PrintByte(byte B) { // if (B >= 0xa0) putchar('0'); // printf("%02xh", B); printf("0x%02x", B); } void PrintWord(word W) { // if (W >= 0xa000) putchar('0'); // printf("%04xh", W); printf("0x%04x", W); } // This is slightly tainted with 251 regs: DPXL and SPH char *SFRs[0x80] = { "P0", "SP", "DPL", "DPH", "DPXL", 0, 0, "PCON", "TCON", "TMOD", "TL0", "TL1", "TH0", "TH1", 0, 0, "P1", 0, 0, 0, 0, 0, 0, 0, "SCON", "SBUF", 0, 0, 0, 0, 0, 0, "P2", 0, 0, 0, 0, 0, 0, 0, "IE", 0, 0, 0, 0, 0, 0, 0, "P3", 0, 0, 0, 0, 0, 0, 0, "IP", 0, 0, 0, 0, "SPH", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "T2CON", 0, "RCAP2L", "RCAP2H", "TL2", "TH2", 0, 0, "PSW", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "ACC", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "B", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; void PrintData(byte D) { /* THIS ASSUMES THE 8052 */ if (!Generating) return; if (D < 0x80 || SFRs[D - 0x80] == 0) { PrintByte(D); return; } printf(SFRs[D - 0x80]); } char *Bits[0x80] = { 0, 0, 0, 0, 0, 0, 0, 0, "IT0", "IE0", "IT1", "IE1", "TR0", "TF0", "TR1", "TF1", "T2", "T2EX", 0, 0, 0, 0, 0, 0, "RI", "TI", "RB8", "TB8", "REN", "SM2", "SM1", "SM0", 0, 0, 0, 0, 0, 0, 0, 0, "EX0", "ET0", "EX1", "ET1", "ES", "ET2", 0, "EA", "RXD", "TXD", "INT0", "INT1", "T0", "T1", "WR", "RD", "PX0", "PT0", "PX1", "PT1", "PS", "PT2", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "CP_RL2", "C_T2", "TR2", "EXEN2", "TCLK", "RCLK", "EXF2", "TF2", "P", 0, "OV", "RS0", "RS1", "F0", "AC", "CY", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; void PrintBit(byte B) { byte Byte, Bit; if (!Generating) return; if (B < 0x80) { PrintByte(B); return; } B -= 0x80; if (Bits[B] != 0) { printf(Bits[B]); return; } Byte = B&0x78; Bit = B&0x07; if (SFRs[Byte] != 0) { printf("%s.%1x", SFRs[Byte], Bit); return; } PrintByte((byte)(B + 0x80)); } void PrintImmByte(byte B) { if (!Generating) return; putchar('#'); PrintByte(B); } void PrintImmWord(word W) { if (!Generating) return; putchar('#'); PrintWord(W); } byte CheckSum; word HighAddr; byte Nib(int X) { if (X >= '0' && X <= '9') return X - '0'; if (X >= 'a' && X <= 'f') return X - 'a' + 10; if (X >= 'A' && X <= 'F') return X - 'A' + 10; fprintf(stderr, "Bad hexadecimal digit in input.\n"); exit(1); } byte GetHex(void) { int A, B; byte Bt; A = getchar(); B = getchar(); if (A == EOF || B == EOF) { fprintf(stderr, "Unexpected EOF.\n"); exit(1); } Bt = Nib(A) << 4 | Nib(B); CheckSum = (CheckSum + Bt)&0xff; return Bt; } word GetWord(void) { word A, B; A = GetHex(); B = GetHex(); return (A << 8) | B; } void HexLoad(void) { int Ch, I; byte Size, Mark, CheckSum; word Addr; byte Buffer[0x10]; HighAddr = 0; while (1) { do { Ch = getchar(); if (Ch == EOF) { fprintf(stderr, "Unexpected EOF.\n"); exit(1); } } while (Ch != ':'); CheckSum = 0; Size = GetHex(); Addr = GetWord(); Mark = GetHex(); for (I = 0; I < Size; I++) Buffer[I] = GetHex(); (void)GetHex(); if (CheckSum != 0) { fprintf(stderr, "Bad checksum.\n"); exit(1); } if (Mark) break; if (Addr >= 0x4000 - Size) { printf("Address out of range 0 - 4000h in input.\n"); exit(0); } for (I = 0; I < Size; I++, Addr++) Hex[Addr] = Buffer[I], Ref[Addr] = 0; if (Addr > HighAddr) HighAddr = Addr; (void)getchar(); } } void BinLoad(char * filename) { FILE *f1 = fopen(filename, "rb"); int ch; int Addr = 0; if (f1 == NULL) { fprintf(stderr, "Could not open binary file.\n"); exit(1); } HighAddr = 0; do { ch = fgetc(f1); if (Addr > 0xFFFF) { printf("Address out of range 0 - FFFFh in input; truncating\n"); fclose(f1); return; } Hex[Addr] = ch; Ref[Addr] = 0; if (Addr > HighAddr) HighAddr = Addr; Addr++; } while (!feof(f1)); fclose(f1); } #define IN_RANGE(A) ((A) >= 0x0000 && (A) < HighAddr) word Address; void PutLabel(word PC) { byte B; if (!Generating) Address = PC; else { if (PC >= 0x10000) { PrintWord(PC); return; } B = (Ref[PC]&LINKS) + 'A' - 1; printf("%c%04x", B, PC); } } void MakeOp(char *S) { int A; byte B; for (A = 1; *S != '\0'; S++) { if (*S != '%') { if (Generating) putchar(*S); continue; } S++; if (*S >= '0' && *S <= '2') A = *S++ - '0'; switch (*S) { case 'L': B = Arg[A++]; PutLabel(B << 8 | Arg[A++]); break; case 'P': PutLabel(Paged(Arg[A++])); break; case 'R': PutLabel(Relative(Arg[A++])); break; case 'D': PrintData(Arg[A++]); break; case 'B': PrintBit(Arg[A++]); break; case 'I': PrintImmByte(Arg[A++]); break; case 'W': B = Arg[A++]; PrintImmWord(B << 8 | Arg[A++]); break; case 'i': if (Generating) printf("@R%1x", Arg[0]&1); break; case 'n': if (Generating) printf("R%1x", Arg[0]&7); break; // original was wrong!! Used &3, for only 4 regs! default: fprintf(stderr, "Bad format string, PC = %04x.\n", PC); exit(1); } } if (Generating) putchar('\n'); else if (!IN_RANGE(Address)) printf("REF: %04x\n", Address); else PUSH(Address); } int Disassemble(void) { byte B; byte Mode; char *Name; int I; if (Ref[PC]&ARG) { fprintf(stderr, "OP into ARG at %04x.\n", PC); return 1; } if (Generating) { if (Ref[PC]&ENTRY) { printf("\n "); PutLabel(PC); printf(":\n"); } printf("%04x: ", PC); } else { if (Ref[PC]&OP) return 1; Ref[PC] |= OP; } Arg[0] = B = Hex[PC++]; if (Generating) printf("%02x ", Arg[0]); Mode = Xs[B]; Name = Ns[B]; for (I = 1; I < (Mode&3); I++) { if (Ref[PC]&OP) { fprintf(stderr, "ARG into OP at %04x.\n", PC); return 1; } if (!Generating) { if (Ref[PC]&ARG) { fprintf(stderr, "ARG into ARG at %04x.\n", PC); return 1; } Ref[PC] |= ARG; } Arg[I] = Hex[PC++]; if (Generating) printf("%02x ", Arg[I]); } while(I++<4 && Generating) { printf(" "); } if (Generating) { if (!(Mode&8)) printf(" "); MakeOp(Name); } else { if (Mode&4) MakeOp(Name); if (Mode&0x10) { printf("Indirect jump at %04x\n", PC - (Mode&3)); } } return (!Generating && (Mode&8) || Generating && !Ref[PC]); } void PCHAR(byte B) { putchar((B < 0x20 || B >= 0x7f)? ' ': B); } int Ended; FILE *EntryF; byte fGetHex(void) { int A, B; if (Ended) return 0; A = fgetc(EntryF); B = fgetc(EntryF); if (A == EOF || B == EOF) { Ended = 1; return 0; } return Nib(A) << 4 | Nib(B); } word fGetWord(void) { word A, B; A = fGetHex(); B = fGetHex(); (void)fgetc(EntryF); if (Ended) return 0; return (A << 8) | B; } fGetToEndOfLine(void) { word A; do { A = fgetc(EntryF); if (A == EOF) { Ended = 1; return 0; } } while (A != '\n'); } int main(int argc, char * argv[]) { word *E, W; if(argc == 1) { HexLoad(); } else { BinLoad(argv[1]); } fprintf(stderr, "First pass\n"); Generating = 0; EntryF = fopen("entries", "r"); if (EntryF == NULL) { fprintf(stderr, "No entry points listed.\n"); exit(1); } for (Ended = 0, EP = Entries; !Ended; ) { W = fGetWord(); if (!Ended) PUSH(W); fGetToEndOfLine(); } while (EP > Entries) { PC = *--EP; while (!Disassemble()); } fprintf(stderr, "Second pass\n"); Generating = 1; if (Ref[0]) printf("\norg 0\n"); for (PC = 0x00; IN_RANGE(PC); ) { byte F, Buf[16]; printf("\n"); if (!Ref[PC]) { printf("%04x: ", PC); for (F = 0; !Ref[PC] && IN_RANGE(PC); PC++) { Buf[F++] = Hex[PC]; if (F == 16) { for (F = 0; F < 16; F++) { printf("%02x", Buf[F]); if (F < 15) putchar(' '); else printf(" |"); } for (F = 0; F < 16; F++) PCHAR(Buf[F]); putchar('|'); putchar('\n'); F = 0; printf("%04x: ", PC + 1); } } if (F > 0) { byte F1; for (F1 = 0; F1 < F; F1++) printf("%02x ", Buf[F1]); for (; F1 < 16; F1++) { Buf[F1] = 0; printf(" "); if (F1 < 15) putchar(' '); else printf(" |"); } for (F = 0; F < 16; F++) PCHAR(Buf[F]); putchar('|'); putchar('\n'); } if (!IN_RANGE(PC)) break; /* printf("\norg "); PrintWord(PC); */ putchar('\n'); } while (!Disassemble()); } return 0; }