sheu@gitpyr.gatech.EDU (Der-Ru Sheu) (01/20/87)
Attached is a disassembler for Intel MCS-48 family single component micro- processors. I wrote this a while ago, and hereby put it into the public domain. This program would accept an Intel Hex format file, and produce a listing type file (with address and opcode) or assembly type file (with -a option). To compile it, just use "cc main.c decode.c utility.c" (UCB CC) or "cl main.c decode.c utility.c" (MicroSoft C). - - - - - - - - - - - - - - - - CUT HERE - - - - - - - - - - - - - - - - echo X - main.c cat << "#### END OF MAIN.C ####" > main.c #include <stdio.h> /* Intel (TM) 8038 family single component u-p machine code disassembler * By: Sheu, Der-Ru; March 12, 1985 * * Command line options: * -s hex# sets the starting address (default 0) * -e hex# sets the ending address (default 2K) * -a sets output in assembly format (default 0) * * Stdin and Stdout are always used as in/output, use redirection for * file i/o. Input should be in the Intel HEX format. * */ int pc_start = 0; /* Command options */ int pc_end = 0x800; int asm = 0; main(argc, argv) int argc; char *argv[]; { int count, New, c, i, pc; char addr[6]; int new_pc, byte1, byte2, two_byte; /* -1- parse command line parameters */ for (i=1; i<argc;) switch (argv[i++][1]) { case 'a': case 'A': asm = 1; break; case 's': case 'S': if (i >= argc) usage(); pc_start = readhex(argv[i++]); break; case 'e': case 'E': if (i >= argc) usage(); pc_end = readhex(argv[i++]); break; default: usage(); } /* -2- now begin disassemblying */ for (pc = 0; pc < pc_start;) if (!(get_op(pc, &pc, &byte1))) exit(0); if (!(get_op(pc, &pc, &byte1))) exit(0); for (; pc <= pc_end;) if (!(get_op(pc, &new_pc, &byte2))) exit(0); else { if (new_pc == (pc+1)) two_byte = decode(pc, byte1, byte2, asm); else { decode(pc, byte1, 0, asm); two_byte = 0; printf("\n"); } printf("\n"); if (two_byte) { if (!(get_op(new_pc, &pc, &byte1))) exit(0); } else { pc = new_pc; byte1 = byte2; } } printf("\n"); } readhex(string) char string[]; { int c, i, j; for (i=j=0; ; i++) { c = string[i]; if ((c >= '0') && (c <= '9')) c -= '0'; else if ((c >= 'A') && (c < 'G')) c -= 'A' + 10; else if ((c >= 'a') && (c < 'g')) c -= 'a' + 10; else break; j <<= 4; j += c; } return(j); } usage() { fprintf(stderr, "Usage: dee [-a] [-s starting] [-e ending]\n"); exit(-1); } #### END OF MAIN.C #### echo X - decode.c cat << "#### END OF DECODE.C ####" > decode.c #include <stdio.h> #include "tables.h" /* Mnemonis and opcode tables */ int byte1, byte2, Hnibble, Lnibble, i, c; /* * Routine to decode an instruction "byte1 byte2" with address "pc". * calls Dumpbyte to dump a byte * calls lookup to look up in the opcode table */ decode(pc, byte1, byte2, asm) int pc, byte1, byte2, asm; { if (!asm) { printf(" "); Dumpbyte( pc >> 8 ); /* Dump address */ Dumpbyte( pc & 0X0FF ); printf(" "); Dumpbyte(byte1); /* Dump code */ printf(" "); if (_Byte[byte1]) Dumpbyte(byte2); else printf(" "); } Hnibble = byte1 >> 4; /* Extract the higher */ Lnibble = byte1 & 0X0F; /* and lower nibbles */ printf(" "); lookup(); /* and look it up */ if (_Byte[byte1]) if (_Byte[byte1] == 1) Dumpbyte(byte2); else { byte2 += ((pc--) & 0XF00); Dump(byte2>>8); Dumpbyte(byte2 & 0X0FF); } return(_Byte[byte1]); } lookup() /* Lookup: look up the opcode table * input - Lnibble and Hnibble * output - mnemonics are printed */ { if ( (!(Lnibble & 0X08) && (Lnibble & 0X02)) || (Lnibble == 5) ) printf("%s",Row[trans1[Lnibble]][Hnibble]); /* REGULAR opcodes */ else if (Lnibble == 4) { /* CALL or JUMP */ if (Hnibble & 0X01) printf("CALL "); else printf("JMP "); Dump( (Hnibble & 0X0F) >> 1 ); } else if ( (byte1 & 0XFE) == 0X0C0 || (byte1 & 0XFE) == 0X0E0 ) printf("???"); /* unknown opcodes */ else if ( ((Hnibble != 0) && (Hnibble != 3) && (Hnibble != 8) && (Hnibble != 9) ) || (Lnibble > 11 ) ) { i = 0; while ( (c = Col[Hnibble][i++]) != '\0') { switch (c) { case 'r': Dump (Lnibble & 0X07); break; case '@': if (Lnibble < 8) printf("@"); break; case 'p': Dump(Lnibble & 0X03); break; default: putc( c, stdout ); break; } } } else printf("%s", ir[ trans2[Hnibble]][trans3[Lnibble]]); } Dumpbyte( i ) /* Dumpbyte: dump a byte stored in i */ int i; { Dump( i >> 4 ); Dump( i & 0X0F ); } Dump(nibble) /* Dump: dump a nibble (4 bits, a hex digit) */ int nibble; { if( (nibble >= 0) && (nibble <= 9)) putchar( nibble + '0'); else putchar(nibble + 'A' -10); } #### END OF DECODE.C #### echo X - utility.c cat << "#### END OF UTILITY.C ####" > utility.c /* utility module: * * GET_OP: get the next opcode in the Intel Hex format. * KEEP: keep addresses. * SAVE: save the addresses. */ #include <stdio.h> static int check_sum = 0; static int power_up = 1; static int byte_max = 0; /* Force read new line */ static int byte_count = 1; get_nibble() { int i; i = getchar(); if ((i >= '0') && (i <= '9')) return (i - '0'); if ((i >= 'A') && (i <= 'F')) return (i - 'A' + 10); if ((i >= 'a') && (i <= 'f')) return (i - 'a' + 10); printf("\nUnexpected character found in the input file!!!\n"); return(0); } get_byte() { int i; i = get_nibble() << 4; i += get_nibble(); check_sum += i; return(i); } get_pc(pc_) int *pc_; { int i; if (!power_up) { i = get_byte(); if (!check_sum) fprintf(stderr, "Check sum error at PC = $%4x", *pc_); check_sum = 0; } power_up = 0; while (1) { while ( (i = getchar()) != ':') if (i == EOF) return(0); byte_count = 1; byte_max = get_byte(); *pc_ = get_byte() << 8; *pc_ += get_byte(); if ( !(i = get_byte()) ) return(1); if ( i == 1 ) return(0); fprintf(stderr, "Unknown record type found at PC = $%4x", *pc_); } } get_op(pc, pc_, op_) int *pc_, *op_; { if (byte_count >= byte_max) { if (!get_pc(pc_)) return(0); } else { *pc_ = ++pc; byte_count++; } *op_ = get_byte(); return(1); } static char buff[400][6]; static int ptr = 0; keep(addr) char addr[6]; { int i; for (i=0; i<6; i++) buff[ptr][i] = addr[i]; ptr++; } save(fp) FILE *fp; { int i; for(i = 0; i <= ptr; i++) fprintf( fp, "%s", buff[i] ); } #### END OF UTILITY.C #### echo X - tables.h cat << "#### END OF TABLES.H ####" > tables.h int _Byte[256] = { /* byte table */ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0, 1, 0, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static int trans1[8] = { -1, -1, 0, 1, -1, 2, 3, 4 }; /* translation table for *Row */ static char *Row[5][16] = { { "???", "JB0 ", "???", "JB1 ", "MOV A,T", "JB2 ", "MOV T,A", "JB3 ", "???", "JB4 ", "???", "JB5 ", "???", "JB6 ", "???", "JB7 " }, { "ADD A,#", "ADDC A,#", "MOV A,#", "???", "ORL A,#", "ANL A,#", "???", "???", "RET", "RETR", "MOVP A,@A","** JMPP @A **", "???","XRL A,#", "MOVP3 A,@A", "???" }, { "EN I", "DIS I", "EN T", "DIS T", "START E", "START T", "STOP T", "ENT0 CLK", "CLR F0", "CPL F0", "CLR F1", "CPL F1", "SEL RB0", "SEL RB1", "** SEL MB0 **", "** SEL MB1 **" }, { "???", "JTF ", "JNT0 ", "JT0 ", "JNT1 ", "JT1 ", "???", "JF1 ", "JNI ", "JNZ ", "???", "JF0 ", "JZ ", "???", "JNC ", "JC " }, { "DEC A", "INC A", "CLR A", "CPL A", "SWAP A", "DA A", "RRC A", "RR A", "???", "CLR C", "CPL C", "???", "MOV A,PSW","MOV PSW,A","RL A", "RLC A" } }; static char *Col[16] = { "MOVD A,Pp","INC @Rr", "XCH A,@Rr", "MOVD Pp,A","ORL A,@Rr", "ANL A, @Rr", "ADD A,@Rr", "ADDC A,@Rr", "ORLD Pp,A","ANLD Pp,A","MOV @Rr, A", "MOV @Rr,#", "DEC Rr", "XRL A,@Rr", "DJNZ Rr,", "MOV A,@Rr" }; static int trans2[10] = { 0, -1, -1, 1, -1, -1, -1, -1, 2, 3 }; static int trans3[12] = { 0, 1, -1, -1, -1, -1, -1, -1, 2, 3, 4, 5 }; static char *ir[4][6] = { { "NOP", "OUTL BUS,A", "INS A,BUS", "IN A,P1", "IN A,P2", "???" }, { "XCHD A,@R0", "XCHD A,@R1", "???", "OUTL P1,A", "OUTL P2,A", "???" }, { "MOVX A,@R0", "MOVX A,@R1", "ORL BUS,#", "ORL P1,#", "ORL P2,#", "???" }, { "MOVX @R0,A", "MOVX @R1,A", "ANL BUS,#", "ANL P1,#", "ANL P2,#", "???" } }; #### END OF TABLES.H #### echo All done.