Z80 Disassembler.c

/***
 *  Z80 Disassembler
 *
 *  Dieser kleine Disassembler für Z80-Code ist an einem Nachmittag entstanden.
 *  Es gibt keine Benutzeroberfläche! Größe des zu disassemblierenden ROMs und
 *  eventuelle weitere Sprünge sind direkt im Programmcode zu ändern!!!
 *
 *  Er läßt sich unter Think C 5.0 auf dem Macintosh übersetzen. Wer keinen
 *  Macintosh hat, darf zum einen die Umlaute im Sourcecode wandeln, und
 *  — sofern man keinen C++ Compiler hat — die Kommentare von \\ umstellen.
 *
 *  Ferner wird eine ANSI-Library (Dateifunktionen) benötigt. Aber auch das
 *  kann man leicht umstellen (siehe main()). Hier wird stets die Datei “EPROM”
 *  geladen. Kann man natürlich ändern…
 *
 *  Das Programm besteht aus zwei Teilen:
 *  1.  Analyse des Programms. Hierbei wird das Programm ab den verschiedenen
 *      Hardware-Vektoren des Z80 (RST-Befehle, NMI) durchgegangen und alle Spünge
 *      durch ein rekursives Unterprogramm (ParseOpcodes) ausgeführt. Dabei werden
 *      gefundene Opcodes in einem Array (OpcodesFlags) markiert. Auch Adressen, die
 *      als Sprungziele verwendet werden, sind dort markiert. Der Disassembler
 *      kann später also genau erkennen, ob er Daten oder Programmcode vor sich hat!
 *      Dabei gibt es natürlich Ausnahmen, die er nicht erkennen kann:
 *      a)  selbstmodifizierender Code. Sowas sollte in einem ROM normalerweise
 *          nicht auftreten.
 *      b)  berechnete Sprünge mit JP (IY), JP (IX) oder JP (HL). Auch hier kann
 *          der Parser die Sprünge nicht erkennen. Man landet im MacsBug, wenn
 *          so ein Sprung gefunden wurde. Wer das Symbol DEBUGGER auf 0 setzt,
 *          hat Ruhe…
 *      c)  Sprungtabellen. Diese treten leider recht häufig auf. Einzige Lösung:
 *          Programm disassemblieren und ansehen. Wenn man die Sprungtabellen
 *          gefunden hat, kann man — wie bei meinem Futura Aquariencomputer ROMs
 *          geschehen — weitere ParseOpcodes() Aufrufe einfügen. Wie und wo das
 *          geht, steht in main()
 *      d)  Unbenutzer Code. Code der nie angesprungen wird, wird natürlich durch
 *          die Analyse nicht gefunden. I.d.R. ist es um solchen Code auch nicht
 *          schade :-) Häufig wird der "unbenutzte" Code jedoch über eine Sprungtabelle
 *          angesprungen! Also Achtung!
 *  2.  Disassemblieren des Programms. Mit Hilfe der beim Parsen erzeugten
 *      OpcodesFlags-Tabelle wird nun ein Listing erzeugt. Das Disassemble-Unterprogramm
 *      ist leider recht "länglich". Es disassembliert einen Opcode ab einer Adresse
 *      im ROM in einen Buffer. Ich habe es in einem Stück runtergeschrieben (an Hand
 *      einer Opcodeliste). Inbesondere die Verwaltung von IX und IY kann man sicher
 *      stark kürzen…
 *
 *  Das Unterprogramm OpcodeLen() ermittelt die Länge eines Opcodes in Bytes. Es
 *  wird während des Parsens und während des Disassemblierens benötigt.
 *
 *  Der Disassembler kennt übrigens _keine_ versteckten Opcodes des Z80. Ich hatte
 *  keine Tabelle darüber. In meinem Fall waren die auch gar nicht nötig… Wer so
 *  eine Liste hat, kann den Disassembler ja mal ergänzen.
 *
 *  Wenn übrigens ein Unterprogramm eine "Adresse" im Z80-Code erwartet, so ist
 *  damit ein _Offset_ auf das Array mit dem Code gemeint! Pointer sind es NICHT!
 *  Longs sind übrigens unnötig, denn ein Z80 hat ja nur 64K…
 *
 *  In main() kann man anstatt einer Disassemblierung mit Labeln auch eine mit
 *  Adresse und Hexdump vor dem Opcode einstellen. Sehr praktisch um evtl. Fehler
 *  im Disassembler zu finden oder beim Erstellen einer Variablenliste.
 *
 *
 *  Das Programm ist Freeware. Es darf _nicht_ als Basis für ein kommerzielles
 *  Produkt genommen werden! Ich übernehme keine Haftung für Schäden, die direkt
 *  oder indirekt durch die Benutzung dieses Programms entstehen!
 *
 *  Wer mich erreichen will, kann dies am besten in unserer Firmen-Mailbox:
 *
 *  Sigma-Soft-Mailbox
 *  ©1992 ∑-Soft, Markus Fritze
 ***/
 
#include <stdio.h>
#include <portab.h>
 
#define CODESIZE        8192L           // 8K Programmcode
#define FUTURA_189      1               // Sprungtabellen-Sprünge für Futura Aquariencomputer ROM V1.89
#define DEBUGGER        0               // wenn 1, dann landet man bei berechneten
                                        // Sprüngen im Debugger. Siehe auch oben.
 
// Speicher für den Programmcode
UBYTE       Opcodes[CODESIZE];
 
// Flag pro Speicherstelle, ob Opcode, Operand, Daten
// Bit 4 = 1, d.h. hier wird per JR o.ä. hingesprungen.
enum {
    Opcode,
    Operand,
    Data
} DataType;
 
UBYTE       OpcodesFlags[CODESIZE];
 
// Länge eines Opcodes in Bytes ermitteln
UBYTE       OpcodeLen(ULONG p)
{
UBYTE   len = 1;
 
    switch(Opcodes[p]) {// Opcode
    case 0x06:          // LD B,n
    case 0x0E:          // LD C,n
    case 0x10:          // DJNZ e
    case 0x16:          // LD D,n
    case 0x18:          // JR e
    case 0x1E:          // LD E,n
    case 0x20:          // JR NZ,e
    case 0x26:          // LD H,n
    case 0x28:          // JR Z,e
    case 0x2E:          // LD L,n
    case 0x30:          // JR NC,e
    case 0x36:          // LD (HL),n
    case 0x38:          // JR C,e
    case 0x3E:          // LD A,n
    case 0xC6:          // ADD A,n
    case 0xCE:          // ADC A,n
    case 0xD3:          // OUT (n),A
    case 0xD6:          // SUB n
    case 0xDB:          // IN A,(n)
    case 0xDE:          // SBC A,n
    case 0xE6:          // AND n
    case 0xEE:          // XOR n
    case 0xF6:          // OR n
    case 0xFE:          // CP n
 
    case 0xCB:          // Shift-,Rotate-,Bit-Befehle
                len = 2;
                break;
    case 0x01:          // LD BC,nn'
    case 0x11:          // LD DE,nn'
    case 0x21:          // LD HL,nn'
    case 0x22:          // LD (nn'),HL
    case 0x2A:          // LD HL,(nn')
    case 0x31:          // LD SP,(nn')
    case 0x32:          // LD (nn'),A
    case 0x3A:          // LD A,(nn')
    case 0xC2:          // JP NZ,nn'
    case 0xC3:          // JP nn'
    case 0xC4:          // CALL NZ,nn'
    case 0xCA:          // JP Z,nn'
    case 0xCC:          // CALL Z,nn'
    case 0xCD:          // CALL nn'
    case 0xD2:          // JP NC,nn'
    case 0xD4:          // CALL NC,nn'
    case 0xDA:          // JP C,nn'
    case 0xDC:          // CALL C,nn'
    case 0xE2:          // JP PO,nn'
    case 0xE4:          // CALL PO,nn'
    case 0xEA:          // JP PE,nn'
    case 0xEC:          // CALL PE,nn'
    case 0xF2:          // JP P,nn'
    case 0xF4:          // CALL P,nn'
    case 0xFA:          // JP M,nn'
    case 0xFC:          // CALL M,nn'
                len = 3;
                break;
    case 0xDD:  len = 2;
                switch(Opcodes[p+1]) {// 2.Teil des Opcodes
                case 0x34:          // INC (IX+d)
                case 0x35:          // DEC (IX+d)
                case 0x46:          // LD B,(IX+d)
                case 0x4E:          // LD C,(IX+d)
                case 0x56:          // LD D,(IX+d)
                case 0x5E:          // LD E,(IX+d)
                case 0x66:          // LD H,(IX+d)
                case 0x6E:          // LD L,(IX+d)
                case 0x70:          // LD (IX+d),B
                case 0x71:          // LD (IX+d),C
                case 0x72:          // LD (IX+d),D
                case 0x73:          // LD (IX+d),E
                case 0x74:          // LD (IX+d),H
                case 0x75:          // LD (IX+d),L
                case 0x77:          // LD (IX+d),A
                case 0x7E:          // LD A,(IX+d)
                case 0x86:          // ADD A,(IX+d)
                case 0x8E:          // ADC A,(IX+d)
                case 0x96:          // SUB A,(IX+d)
                case 0x9E:          // SBC A,(IX+d)
                case 0xA6:          // AND (IX+d)
                case 0xAE:          // XOR (IX+d)
                case 0xB6:          // OR (IX+d)
                case 0xBE:          // CP (IX+d)
                            len = 3;
                            break;
                case 0x21:          // LD IX,nn'
                case 0x22:          // LD (nn'),IX
                case 0x2A:          // LD IX,(nn')
                case 0x36:          // LD (IX+d),n
                case 0xCB:          // Rotation (IX+d)
                            len = 4;
                            break;
                }
                break;
    case 0xED:  len = 2;
                switch(Opcodes[p+1]) {// 2.Teil des Opcodes
                case 0x43:          // LD (nn'),BC
                case 0x4B:          // LD BC,(nn')
                case 0x53:          // LD (nn'),DE
                case 0x5B:          // LD DE,(nn')
                case 0x73:          // LD (nn'),SP
                case 0x7B:          // LD SP,(nn')
                            len = 4;
                            break;
                }
                break;
    case 0xFD:  len = 2;
                switch(Opcodes[p+1]) {// 2.Teil des Opcodes
                case 0x34:          // INC (IY+d)
                case 0x35:          // DEC (IY+d)
                case 0x46:          // LD B,(IY+d)
                case 0x4E:          // LD C,(IY+d)
                case 0x56:          // LD D,(IY+d)
                case 0x5E:          // LD E,(IY+d)
                case 0x66:          // LD H,(IY+d)
                case 0x6E:          // LD L,(IY+d)
                case 0x70:          // LD (IY+d),B
                case 0x71:          // LD (IY+d),C
                case 0x72:          // LD (IY+d),D
                case 0x73:          // LD (IY+d),E
                case 0x74:          // LD (IY+d),H
                case 0x75:          // LD (IY+d),L
                case 0x77:          // LD (IY+d),A
                case 0x7E:          // LD A,(IY+d)
                case 0x86:          // ADD A,(IY+d)
                case 0x8E:          // ADC A,(IY+d)
                case 0x96:          // SUB A,(IY+d)
                case 0x9E:          // SBC A,(IY+d)
                case 0xA6:          // AND (IY+d)
                case 0xAE:          // XOR (IY+d)
                case 0xB6:          // OR (IY+d)
                case 0xBE:          // CP (IY+d)
                            len = 3;
                            break;
                case 0x21:          // LD IY,nn'
                case 0x22:          // LD (nn'),IY
                case 0x2A:          // LD IY,(nn')
                case 0x36:          // LD (IY+d),n
                case 0xCB:          // Rotation,Bitop (IY+d)
                            len = 4;
                            break;
                }
                break;
    }
    return(len);
}
 
void        ParseOpcodes(ULONG adr)
{
WORD    i,len;
ULONG   next;
Boolean label = true;
 
    do {
        if(label)                       // ein Label setzen?
            OpcodesFlags[adr] |= 0x10;  // Label setzen
        if((OpcodesFlags[adr] & 0x0F) == Opcode) break; // Schleife erkannt!
        if((OpcodesFlags[adr] & 0x0F) == Operand) {
            DebugStr("\pIllegaler Sprung?!?");
            return;
        }
        len = OpcodeLen(adr);           // Länge vom Opcode ermitteln
        for(i=0;i<len;i++)
            OpcodesFlags[adr+i] = Operand;  // Opcode eintragen
        OpcodesFlags[adr] = Opcode;     // Start des Opcodes markieren
        if(label) {                     // ein Label setzen?
            OpcodesFlags[adr] |= 0x10;  // Label setzen
            label = false;              // Label-Flag zurücksetzen
        }
 
        next = adr + len;               // Ptr auf den Folgeopcode
        switch(Opcodes[adr]) {          // Opcode holen
        case 0xCA:      // JP c,????
        case 0xC2:
        case 0xDA:
        case 0xD2:
        case 0xEA:
        case 0xE2:
        case 0xFA:
        case 0xF2:
                ParseOpcodes((Opcodes[adr+2]<<8) + Opcodes[adr+1]);
                break;
        case 0x28:      // JR c,??
        case 0x20:
        case 0x38:
        case 0x30:
                ParseOpcodes(adr + 2 + (BYTE)Opcodes[adr+1]);
                break;
        case 0xCC:      // CALL c,????
        case 0xC4:
        case 0xDC:
        case 0xD4:
        case 0xEC:
        case 0xE4:
        case 0xFC:
        case 0xF4:
                ParseOpcodes((Opcodes[adr+2]<<8) + Opcodes[adr+1]);
                break;
        case 0xC8:      // RET c
        case 0xC0:
        case 0xD8:
        case 0xD0:
        case 0xE8:
        case 0xE0:
        case 0xF8:
        case 0xF0:
                break;
        case 0xC7:      // RST 0
        case 0xCF:      // RST 8
        case 0xD7:      // RST 10
        case 0xDF:      // RST 18
        case 0xE7:      // RST 20
        case 0xEF:      // RST 28
        case 0xF7:      // RST 30
        case 0xFF:      // RST 38
                ParseOpcodes(Opcodes[adr] & 0x38);
                break;
        case 0x10:      // DJNZ ??
                ParseOpcodes(adr + 2 + (BYTE)Opcodes[adr+1]);
                break;
        case 0xC3:      // JP ????
                next = (Opcodes[adr+2]<<8) + Opcodes[adr+1];
                label = true;
                break;
        case 0x18:      // JR ??
                next = adr + 2 + (BYTE)Opcodes[adr+1];
                label = true;
                break;
        case 0xCD:      // CALL ????
                ParseOpcodes((Opcodes[adr+2]<<8) + Opcodes[adr+1]);
                break;
        case 0xC9:      // RET
                return;
        case 0xE9:
#if DEBUGGER
                DebugStr("\pJP (HL) gefunden"); // JP (HL)
#endif
                break;
        case 0xDD:
#if DEBUGGER
                if(Opcodes[adr+1] == 0xE9) {    // JP (IX)
                    DebugStr("\pJP (IX) gefunden");
                }
#endif
                break;
        case 0xFD:
#if DEBUGGER
                if(Opcodes[adr+1] == 0xE9) {    // JP (IY)
                    DebugStr("\pJP (IY) gefunden");
                }
#endif
                break;
        case 0xED:
                if(Opcodes[adr+1] == 0x4D) {    // RTI
                    return;
                } else if(Opcodes[adr+1] == 0x45) { // RETN
                    return;
                }
                break;
        }
        adr = next;
    } while(1);
}
 
// Disassemblieren
VOID        Disassemble(UWORD adr,STR s)
{
UBYTE           a = Opcodes[adr];
UBYTE           d = (a >> 3) & 7;
UBYTE           e = a & 7;
static STR      reg[8] = {"B","C","D","E","H","L","(HL)","A"};
static STR      dreg[4] = {"BC","DE","HL","SP"};
static STR      cond[8] = {"NZ","Z","NC","C","PO","PE","P","M"};
static STR      arith[8] = {"ADD\t\tA,","ADC\t\tA,","SUB\t\t","SBC\t\tA,","AND\t\t","XOR\t\t","OR\t\t","CP\t\t"};
CHAR            stemp[80];      // temp.String für sprintf()
CHAR            ireg[3];        // temp.Indexregister
 
    switch(a & 0xC0) {
    case 0x00:
        switch(e) {
        case 0x00:
            switch(d) {
            case 0x00:
                strcpy(s,"NOP");
                break;
            case 0x01:
                strcpy(s,"EX\t\tAF,AF'");
                break;
            case 0x02:
                strcpy(s,"DJNZ\t");
                sprintf(stemp,"%4.4Xh",adr+2+(BYTE)Opcodes[adr+1]);strcat(s,stemp);
                break;
            case 0x03:
                strcpy(s,"JR\t\t");
                sprintf(stemp,"%4.4Xh",adr+2+(BYTE)Opcodes[adr+1]);strcat(s,stemp);
                break;
            default:
                strcpy(s,"JR\t\t");
                strcat(s,cond[d & 3]);
                strcat(s,",");
                sprintf(stemp,"%4.4Xh",adr+2+(BYTE)Opcodes[adr+1]);strcat(s,stemp);
                break;
            }
            break;
        case 0x01:
            if(a & 0x08) {
                strcpy(s,"ADD\t\tHL,");
                strcat(s,dreg[d >> 1]);
            } else {
                strcpy(s,"LD\t\t");
                strcat(s,dreg[d >> 1]);
                strcat(s,",");
                sprintf(stemp,"%4.4Xh",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
            }
            break;
        case 0x02:
            switch(d) {
            case 0x00:
                strcpy(s,"LD\t\t(BC),A");
                break;
            case 0x01:
                strcpy(s,"LD\tA,(BC)");
                break;
            case 0x02:
                strcpy(s,"LD\t\t(DE),A");
                break;
            case 0x03:
                strcpy(s,"LD\t\tA,(DE)");
                break;
            case 0x04:
                strcpy(s,"LD\t\t(");
                sprintf(stemp,"%4.4Xh",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
                strcat(s,"),HL");
                break;
            case 0x05:
                strcpy(s,"LD\t\tHL,(");
                sprintf(stemp,"%4.4Xh",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
                strcat(s,")");
                break;
            case 0x06:
                strcpy(s,"LD\t\t(");
                sprintf(stemp,"%4.4Xh",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
                strcat(s,"),A");
                break;
            case 0x07:
                strcpy(s,"LD\t\tA,(");
                sprintf(stemp,"%4.4Xh",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
                strcat(s,")");
                break;
            }
            break;
        case 0x03:
            if(a & 0x08)
                strcpy(s,"DEC\t\t");
            else
                strcpy(s,"INC\t\t");
            strcat(s,dreg[d >> 1]);
            break;
        case 0x04:
            strcpy(s,"INC\t\t");
            strcat(s,reg[d]);
            break;
        case 0x05:
            strcpy(s,"DEC\t\t");
            strcat(s,reg[d]);
            break;
        case 0x06:              // LD   d,n
            strcpy(s,"LD\t\t");
            strcat(s,reg[d]);
            strcat(s,",");
            sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
            break;
        case 0x07:
            {
            static STR str[8] = {"RLCA","RRCA","RLA","RRA","DAA","CPL","SCF","CCF"};
            strcpy(s,str[d]);
            }
            break;
        }
        break;
    case 0x40:                          // LD   d,s
        if(d == e) {
            strcpy(s,"HALT");
        } else {
            strcpy(s,"LD\t\t");
            strcat(s,reg[d]);
            strcat(s,",");
            strcat(s,reg[e]);
        }
        break;
    case 0x80:
        strcpy(s,arith[d]);
        strcat(s,reg[e]);
        break;
    case 0xC0:
        switch(e) {
        case 0x00:
            strcpy(s,"RET\t\t");
            strcat(s,cond[d]);
            break;
        case 0x01:
            if(d & 1) {
                switch(d >> 1) {
                case 0x00:
                    strcpy(s,"RET");
                    break;
                case 0x01:
                    strcpy(s,"EXX");
                    break;
                case 0x02:
                    strcpy(s,"JP\t\t(HL)");
                    break;
                case 0x03:
                    strcpy(s,"LD\t\tSP,HL");
                    break;
                }
            } else {
                strcpy(s,"POP\t\t");
                if((d >> 1)==3)
                    strcat(s,"AF");
                else
                    strcat(s,dreg[d >> 1]);
            }
            break;
        case 0x02:
            strcpy(s,"JP\t\t");
            strcat(s,cond[d]);
            strcat(s,",");
            sprintf(stemp,"%4.4Xh",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
            break;
        case 0x03:
            switch(d) {
            case 0x00:
                strcpy(s,"JP\t\t");
                sprintf(stemp,"%4.4Xh",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
                break;
            case 0x01:                  // 0xCB
                a = Opcodes[++adr];     // Erweiterungsopcode holen
                d = (a >> 3) & 7;
                e = a & 7;
                stemp[1] = 0;           // temp.String = 1 Zeichen
                switch(a & 0xC0) {
                case 0x00:
                    {
                    static STR str[8] = {"RLC","RRC","RL","RR","SLA","SRA","???","SRL"};
                    strcpy(s,str[d]);
                    }
                    strcat(s,"\t\t");
                    strcat(s,reg[e]);
                    break;
                case 0x40:
                    strcpy(s,"BIT\t\t");
                    stemp[0] = d+'0';strcat(s,stemp);
                    strcat(s,",");
                    strcat(s,reg[e]);
                    break;
                case 0x80:
                    strcpy(s,"RES\t\t");
                    stemp[0] = d+'0';strcat(s,stemp);
                    strcat(s,",");
                    strcat(s,reg[e]);
                    break;
                case 0xC0:
                    strcpy(s,"SET\t\t");
                    stemp[0] = d+'0';strcat(s,stemp);
                    strcat(s,",");
                    strcat(s,reg[e]);
                    break;
                }
                break;
            case 0x02:
                strcpy(s,"OUT\t\t(");
                sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                strcat(s,"),A");
                break;
            case 0x03:
                strcpy(s,"IN\t\tA,(");
                sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                strcat(s,")");
                break;
            case 0x04:
                strcpy(s,"EX\t\t(SP),HL");
                break;
            case 0x05:
                strcpy(s,"EX\t\tDE,HL");
                break;
            case 0x06:
                strcpy(s,"DI");
                break;
            case 0x07:
                strcpy(s,"EI");
                break;
            }
            break;
        case 0x04:
            strcpy(s,"CALL\t");
            strcat(s,cond[d]);
            strcat(s,",");
            sprintf(stemp,"%4.4Xh",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
            break;
        case 0x05:
            if(d & 1) {
                switch(d >> 1) {
                case 0x00:
                    strcpy(s,"CALL\t");
                    sprintf(stemp,"%4.4Xh",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
                    break;
                case 0x02:              // 0xED
                    a = Opcodes[++adr]; // Erweiterungsopcode holen
                    d = (a >> 3) & 7;
                    e = a & 7;
                    switch(a & 0xC0) {
                    case 0x40:
                        switch(e) {
                        case 0x00:
                            strcpy(s,"IN\t\t");
                            strcat(s,reg[d]);
                            strcat(s,",(C)");
                            break;
                        case 0x01:
                            strcpy(s,"OUT\t\t(C),");
                            strcat(s,reg[d]);
                            break;
                        case 0x02:
                            if(d & 1)
                                strcpy(s,"ADC");
                            else
                                strcpy(s,"SBC");
                            strcat(s,"\t\tHL,");
                            strcat(s,dreg[d >> 1]);
                            break;
                        case 0x03:
                            if(d & 1) {
                                strcpy(s,"LD\t\t");
                                strcat(s,dreg[d >> 1]);
                                strcat(s,",(");
                                sprintf(stemp,"%4.4Xh",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
                                strcat(s,")");
                            } else {
                                strcpy(s,"LD\t\t(");
                                sprintf(stemp,"%4.4Xh",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
                                strcat(s,"),");
                                strcat(s,dreg[d >> 1]);
                            }
                            break;
                        case 0x04:
                            {
                            static STR str[8] = {"NEG","???","???","???","???","???","???","???"};
                            strcpy(s,str[d]);
                            }
                            break;
                        case 0x05:
                            {
                            static STR str[8] = {"RETN","RETI","???","???","???","???","???","???"};
                            strcpy(s,str[d]);
                            }
                            break;
                        case 0x06:
                            strcpy(s,"IM\t\t");
                            stemp[0] = d + '0' - 1; stemp[1] = 0;
                            strcat(s,stemp);
                            break;
                        case 0x07:
                            {
                            static STR str[8] = {"LD\t\tI,A","???","LD\t\tA,I","???","RRD","RLD","???","???"};
                            strcpy(s,str[d]);
                            }
                            break;
                        }
                        break;
                    case 0x80:
                        {
                        static STR str[32] = {"LDI","CPI","INI","OUTI","???","???","???","???",
                                              "LDD","CPD","IND","OUTD","???","???","???","???",
                                              "LDIR","CPIR","INIR","OTIR","???","???","???","???",
                                              "LDDR","CPDR","INDR","OTDR","???","???","???","???"};
                        strcpy(s,str[a & 0x1F]);
                        }
                        break;
                    }
                    break;
                default:                // 0x01 (0xDD) = IX, 0x03 (0xFD) = IY
                    strcpy(ireg,(a & 0x20)?"IY":"IX");
                    a = Opcodes[++adr]; // Erweiterungsopcode holen
                    switch(a) {
                    case 0x09:
                        strcpy(s,"ADD\t\t");
                        strcat(s,ireg);
                        strcat(s,",BC");
                        break;
                    case 0x19:
                        strcpy(s,"ADD\t\t");
                        strcat(s,ireg);
                        strcat(s,",DE");
                        break;
                    case 0x21:
                        strcpy(s,"LD\t\t");
                        strcat(s,ireg);
                        strcat(s,",");
                        sprintf(stemp,"%4.4Xh",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
                        break;
                    case 0x22:
                        strcpy(s,"LD\t\t(");
                        sprintf(stemp,"%4.4Xh",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
                        strcat(s,"),");
                        strcat(s,ireg);
                        break;
                    case 0x23:
                        strcpy(s,"INC\t\t");
                        strcat(s,ireg);
                        break;
                    case 0x29:
                        strcpy(s,"ADD\t\t");
                        strcat(s,ireg);
                        strcat(s,",");
                        strcat(s,ireg);
                        break;
                    case 0x2A:
                        strcpy(s,"LD\t\t");
                        strcat(s,ireg);
                        strcat(s,",(");
                        sprintf(stemp,"%4.4Xh",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
                        strcat(s,")");
                        break;
                    case 0x2B:
                        strcpy(s,"DEC\t\t");
                        strcat(s,ireg);
                        break;
                    case 0x34:
                        strcpy(s,"INC\t\t(");
                        strcat(s,ireg);
                        strcat(s,"+");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                        strcat(s,")");
                        break;
                    case 0x35:
                        strcpy(s,"DEC\t\t(");
                        strcat(s,ireg);
                        strcat(s,"+");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                        strcat(s,")");
                        break;
                    case 0x36:
                        strcpy(s,"LD\t\t(");
                        strcat(s,ireg);
                        strcat(s,"+");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                        strcat(s,"),");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+2]);strcat(s,stemp);
                        break;
                    case 0x39:
                        strcpy(s,"ADD\t\t");
                        strcat(s,ireg);
                        strcat(s,",SP");
                        break;
                    case 0x46:
                    case 0x4E:
                    case 0x56:
                    case 0x5E:
                    case 0x66:
                    case 0x6E:
                        strcpy(s,"LD\t\t");
                        strcat(s,reg[(a>>3)&7]);
                        strcat(s,",(");
                        strcat(s,ireg);
                        strcat(s,"+");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                        strcat(s,")");
                        break;
                    case 0x70:
                    case 0x71:
                    case 0x72:
                    case 0x73:
                    case 0x74:
                    case 0x75:
                    case 0x77:
                        strcpy(s,"LD\t\t(");
                        strcat(s,ireg);
                        strcat(s,"+");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                        strcat(s,"),");
                        strcat(s,reg[a & 7]);
                        break;
                    case 0x7E:
                        strcpy(s,"LD\t\tA,(");
                        strcat(s,ireg);
                        strcat(s,"+");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                        strcat(s,")");
                        break;
                    case 0x86:
                        strcpy(s,"ADD\t\tA,(");
                        strcat(s,ireg);
                        strcat(s,"+");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                        strcat(s,")");
                        break;
                    case 0x8E:
                        strcpy(s,"ADC\t\tA,(");
                        strcat(s,ireg);
                        strcat(s,"+");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                        strcat(s,")");
                        break;
                    case 0x96:
                        strcpy(s,"SUB\t\t(");
                        strcat(s,ireg);
                        strcat(s,"+");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                        strcat(s,")");
                        break;
                    case 0x9E:
                        strcpy(s,"SBC\t\tA,(");
                        strcat(s,ireg);
                        strcat(s,"+");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                        strcat(s,")");
                        break;
                    case 0xA6:
                        strcpy(s,"AND\t\tA,(");
                        strcat(s,ireg);
                        strcat(s,"+");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                        strcat(s,")");
                        break;
                    case 0xAE:
                        strcpy(s,"XOR\t\tA,(");
                        strcat(s,ireg);
                        strcat(s,"+");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                        strcat(s,")");
                        break;
                    case 0xB6:
                        strcpy(s,"OR\t\tA,(");
                        strcat(s,ireg);
                        strcat(s,"+");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                        strcat(s,")");
                        break;
                    case 0xBE:
                        strcpy(s,"CP\t\tA,(");
                        strcat(s,ireg);
                        strcat(s,"+");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                        strcat(s,")");
                        break;
                    case 0xE1:
                        strcpy(s,"POP\t\t");
                        strcat(s,ireg);
                        break;
                    case 0xE3:
                        strcpy(s,"EX\t\t(SP),");
                        strcat(s,ireg);
                        break;
                    case 0xE5:
                        strcpy(s,"PUSH\t");
                        strcat(s,ireg);
                        break;
                    case 0xE9:
                        strcpy(s,"JP\t\t(");
                        strcat(s,ireg);
                        strcat(s,")");
                        break;
                    case 0xF9:
                        strcpy(s,"LD\t\tSP,");
                        strcat(s,ireg);
                        break;
                    case 0xCB:
                        a = Opcodes[adr+2]; // weiteren Unteropcode
                        d = (a >> 3) & 7;
                        stemp[1] = 0;
                        switch(a & 0xC0) {
                        case 0x00:
                            {
                            static STR str[8] = {"RLC","RRC","RL","RR","SLA","SRA","???","SRL"};
                            strcpy(s,str[d]);
                            }
                            strcat(s,"\t\t");
                            break;
                        case 0x40:
                            strcpy(s,"BIT\t\t");
                            stemp[0] = d + '0';
                            strcat(s,stemp);
                            strcat(s,",");
                            break;
                        case 0x80:
                            strcpy(s,"RES\t\t");
                            stemp[0] = d + '0';
                            strcat(s,stemp);
                            strcat(s,",");
                            break;
                        case 0xC0:
                            strcpy(s,"SET\t\t");
                            stemp[0] = d + '0';
                            strcat(s,stemp);
                            strcat(s,",");
                            break;
                        }
                        strcat(s,"(");
                        strcat(s,ireg);
                        strcat(s,"+");
                        sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
                        strcat(s,")");
                        break;
                    }
                    break;
                }
            } else {
                strcpy(s,"PUSH\t");
                if((d >> 1)==3)
                    strcat(s,"AF");
                else
                    strcat(s,dreg[d >> 1]);
            }
            break;
        case 0x06:
            strcpy(s,arith[d]);
            sprintf(stemp,"%2.2Xh",Opcodes[adr+1]);strcat(s,stemp);
            break;
        case 0x07:
            strcpy(s,"RST\t\t");
            sprintf(stemp,"%2.2Xh",a & 0x38);strcat(s,stemp);
            break;
        }
        break;
    }
}
 
// Einlesen, Parsen, Disassemblieren und Ausgeben
void        main(void)
{
WORD    i;
FILE    *f;
UWORD   adr = 0;
CHAR    s[80];          // Ausgabestring
 
    f = fopen("EPROM","rb");
    if(!f) return;
    fread(Opcodes,CODESIZE,1,f);    // EPROM einlesen
    fclose(f);
 
    for(i=0;i<CODESIZE;i++)         // alles Daten…
        OpcodesFlags[i] = Data;
    for(i=0;i<0x40;i+=0x08)
        if((OpcodesFlags[i] & 0x0F) == Data)
            ParseOpcodes(i);        // RST-Vektoren parsen (wenn nötig)
    if((OpcodesFlags[i] & 0x0F) == Data)
        ParseOpcodes(0x66);         // NMI-Vektor auch parsen (wenn nötig)
 
#if FUTURA_189
    ParseOpcodes(0xA41);
    ParseOpcodes(0xDB6);        // Meßwerte darstellen
    ParseOpcodes(0xF5D);
    ParseOpcodes(0xE83);
 
    ParseOpcodes(0x0978);
    ParseOpcodes(0x0933);
    ParseOpcodes(0x11D3);
    ParseOpcodes(0x1292);
    ParseOpcodes(0x0AF8);
    ParseOpcodes(0x098F);
    ParseOpcodes(0x0B99);
    ParseOpcodes(0x0BB3);
    ParseOpcodes(0x0B4A);       // Tastenfeld
    ParseOpcodes(0x0B12);
    ParseOpcodes(0x08FF);
    ParseOpcodes(0x08F0);
    ParseOpcodes(0x0BDA);
    ParseOpcodes(0x0BCD);
    ParseOpcodes(0x0A7E);
    ParseOpcodes(0x0C2D);
    ParseOpcodes(0x0AA6);
    ParseOpcodes(0x0848);
 
    ParseOpcodes(0x1660);
    ParseOpcodes(0x166E);
    ParseOpcodes(0x167C);       // Spezielle Tastenkombinationen
    ParseOpcodes(0x168A);
    ParseOpcodes(0x1698);
    ParseOpcodes(0x16A6);
    ParseOpcodes(0x16CF);
#endif
 
    f = stdout;
    f = fopen("OUTPUT","w");
    if(!f) return;
    while(adr < CODESIZE) {
        WORD    len,i;
 
        if((OpcodesFlags[adr] & 0x0F) == Data) {
            fprintf(f,"L%4.4X:\tDEFB",(UWORD)adr);
            for(i=0;i<16;i++) {
                if((OpcodesFlags[adr+i] & 0x0F) != Data) break;
                fprintf(f,"%c%2.2Xh",(i)?',':' ',Opcodes[adr+i]);
            }
            fprintf(f,"\n");
            adr += i;
        } else {
            len = OpcodeLen(adr);           // Länge vom Opcode ermitteln
#if 1
            if(OpcodesFlags[adr] & 0x10)
                fprintf(f,"L%4.4X:\t",adr);
            else
                fprintf(f,"\t\t");
#else
            fprintf(f,"%4.4X: ",(UWORD)adr);
            for(i=0;i<len;i++)
                fprintf(f,"%2.2X ",Opcodes[adr+i]);
            for(i=4;i>len;i--)
                fprintf(f,"   ");
            fprintf(f," ");
#endif
            Disassemble(adr,s);
            fprintf(f,"%s\n",s);
            adr += len;
        }
    }
    fclose(f);
}
 
software/z80_disassembler.c.txt · Last modified: 2006/03/16 02:57 (external edit)
 
Recent changes RSS feed