rizin/libr/asm/arch/z80/disasm.c
2015-09-14 10:30:18 +02:00

1024 lines
28 KiB
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 <string.h>
#include <stdbool.h>
//#include <portab.h>
#ifndef R_API_I
#define R_API_I
#endif
#define CHAR char
#define WORD short
#define UWORD unsigned short
#define ut8 unsigned char
#define ut8 unsigned char
#define STR char*
#define BYTE char
#define ULONG unsigned int
#define CODESIZE 8192L // 8K Programmcode
#define FUTURA_189 1 // Sprungtabellen-Sprünge für Futura Aquariencomputer ROM V1.89
// Sprüngen im Debugger. Siehe auch oben.
// Speicher für den Programmcode
//static ut8 *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;
// Länge eines Opcodes in Bytes ermitteln
static ut8 OpcodeLen(ULONG p, const ut8 *Opcodes) {
ut8 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);
}
#if MAIN_DIS
R_API_I ULONG ParseOpcodes(ULONG adr, ut8 *Opcodes, int len) {
int i;
ULONG next;
i = OpcodeLen (adr, Opcodes); // Länge vom Opcode ermitteln
if (len<i)
return 0; // not enought bytes
len = i;
next = adr + len; // Ptr auf den Folgeopcode
switch (Opcodes[adr]) {
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], Opcodes, len);
break;
case 0x28: // JR c,??
case 0x20:
case 0x38:
case 0x30:
ParseOpcodes(adr + 2 + (BYTE)Opcodes[adr+1], Opcodes, len);
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], Opcodes, len);
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, Opcodes, len);
break;
case 0x10: // DJNZ ??
ParseOpcodes(adr + 2 + (BYTE)Opcodes[adr+1], Opcodes, len);
break;
case 0xC3: // JP ????
next = (Opcodes[adr+2]<<8) + Opcodes[adr+1];
break;
case 0x18: // JR ??
next = adr + 2 + (BYTE)Opcodes[adr+1];
break;
case 0xCD: // CALL ????
ParseOpcodes ((Opcodes[adr+2]<<8) + Opcodes[adr+1], Opcodes, len);
break;
case 0xC9: // RET
return 1;
case 0xE9:
break;
case 0xDD:
if(Opcodes[adr+1] == 0xE9) { // JP (IX)
printf ("\tJP (IX) gefunden");
}
break;
case 0xFD:
if (Opcodes[adr+1] == 0xE9) { // JP (IY)
printf ("\tJP (IY) gefunden");
}
break;
case 0xED:
if (Opcodes[adr+1] == 0x4D) { // RTI
return 2;
} else if (Opcodes[adr+1] == 0x45) { // RETN
return 2;
}
break;
}
return next;
}
#endif
// Disassemblieren
static int Disassemble(UWORD adr, const unsigned char *Opcodes, STR s, int olen) {
ut8 a = Opcodes[0];
ut8 d = (a >> 3) & 7;
ut8 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 a, ","adc a, ","sub ","sbc a, ","and ","xor ","or ","cp "};
char stemp[80]; // temp.String für sprintf()
char ireg[3]; // temp.Indexregister
int len = OpcodeLen (0, Opcodes);
switch(a & 0xC0) {
case 0x00:
switch(e) {
case 0x00:
switch(d) {
case 0x00:
strcpy (s,"nop");
break;
case 0x01:
strcpy (s,"ex af, af'");
break;
case 0x02:
strcpy (s,"djnz ");
sprintf (stemp,"0x%2.2X",(adr+2+(BYTE)Opcodes[adr+1])&0xff);strcat(s,stemp);
break;
case 0x03:
strcpy(s,"jr ");
sprintf(stemp,"0x%2.2X",(adr+2+(BYTE)Opcodes[adr+1])&0xff);strcat(s,stemp);
break;
default:
strcpy(s,"jr ");
strcat(s,cond[d & 3]);
strcat(s,", ");
sprintf(stemp,"0x%2.2X",(adr+2+(BYTE)Opcodes[adr+1])&0xff);strcat(s,stemp);
break;
}
break;
case 0x01:
if (a & 0x08) {
strcpy(s,"add hl, ");
strcat(s,dreg[d >> 1]);
} else {
strcpy (s,"ld ");
strcat (s,dreg[d >> 1]);
strcat (s,", ");
sprintf (stemp,"0x%4.4X",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
}
break;
case 0x02:
switch (d) {
case 0x00:
strcpy(s,"ld (bc), a");
break;
case 0x01:
strcpy(s,"ld a, (bc)");
break;
case 0x02:
strcpy(s,"ld (de), a");
break;
case 0x03:
strcpy(s,"ld a, (de)");
break;
case 0x04:
strcpy(s,"ld (");
sprintf(stemp,"0x%4.4X",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
strcat(s,"), hl");
break;
case 0x05:
strcpy(s,"ld hl, (");
sprintf(stemp,"0x%4.4X",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
strcat(s,")");
break;
case 0x06:
strcpy(s,"ld (");
sprintf(stemp,"0x%4.4X",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
strcat(s,"), a");
break;
case 0x07:
strcpy(s,"ld a, (");
sprintf(stemp,"0x%4.4X",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
strcat(s,")");
break;
}
break;
case 0x03:
strcpy (s, (a & 8)? "dec ": "inc ");
strcat (s, dreg[d >> 1]);
break;
case 0x04:
strcpy (s, "inc ");
strcat (s, reg[d]);
break;
case 0x05:
strcpy (s, "dec ");
strcat (s, reg[d]);
break;
case 0x06: // LD d,n
strcpy(s,"ld ");
strcat(s,reg[d]);
strcat(s,", ");
sprintf(stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
break;
case 0x07:
{
static const STR str[8] = {"rlca", "rrca", "rla", "rra", "daa", "cpl", "scf", "ccf"};
strcpy (s,str[d]);
}
break;
}
break;
case 0x40: // LD d,s
if (a == 0x76) {
strcpy(s, "halt");
break;
}
strcpy(s,"ld ");
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 ");
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 (hl)");
break;
case 0x03:
strcpy(s,"ld sp, hl");
break;
}
} else {
strcpy(s,"pop ");
if((d >> 1)==3)
strcat(s,"af");
else
strcat(s,dreg[d >> 1]);
}
break;
case 0x02:
strcpy(s,"jp ");
strcat(s,cond[d]);
strcat(s,", ");
sprintf(stemp, "0x%4.4X",Opcodes[adr+1]+(Opcodes[adr+2]<<8));
strcat(s,stemp);
break;
case 0x03:
switch (d) {
case 0x00:
strcpy (s, "jp ");
sprintf (stemp,"0x%4.4X",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","sll","srl"};
strcpy(s,str[d]);
}
strcat(s," ");
strcat(s,reg[e]);
break;
case 0x40:
strcpy(s,"bit ");
stemp[0] = d+'0';strcat(s,stemp);
strcat(s,", ");
strcat(s,reg[e]);
break;
case 0x80:
strcpy(s,"res ");
stemp[0] = d+'0';strcat(s,stemp);
strcat(s,", ");
strcat(s,reg[e]);
break;
case 0xC0:
strcpy(s, "set ");
stemp[0] = d+'0';strcat(s,stemp);
strcat(s,", ");
strcat(s,reg[e]);
break;
}
break;
case 0x02:
strcpy (s,"out (");
sprintf (stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
strcat (s,"), a");
break;
case 0x03:
strcpy(s,"in a, (");
sprintf(stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
strcat(s,")");
break;
case 0x04:
strcpy(s,"ex (sp), hl");
break;
case 0x05:
strcpy(s,"ex de, hl");
break;
case 0x06:
strcpy(s,"di");
break;
case 0x07:
strcpy(s,"ei");
break;
}
break;
case 0x04:
strcpy(s,"call ");
strcat(s,cond[d]);
strcat(s,", ");
sprintf(stemp,"0x%4.4X",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
break;
case 0x05:
if (d & 1) {
switch (d >> 1) {
case 0x00:
strcpy(s,"call ");
sprintf(stemp,"0x%4.4X",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 ");
if (d != 6)
strcat(s,reg[d]);
else
strcat(s, "f");
strcat(s,", (c)");
break;
case 0x01:
strcpy(s,"out (c), ");
if (d != 6)
strcat(s,reg[d]);
else
strcat(s, "0");
break;
case 0x02:
if(d & 1)
strcpy(s,"adc");
else
strcpy(s,"sbc");
strcat(s," hl, ");
strcat(s,dreg[d >> 1]);
break;
case 0x03:
if(d & 1) {
strcpy(s,"ld ");
strcat(s,dreg[d >> 1]);
strcat(s,", (");
sprintf(stemp,"0x%4.4X",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
strcat(s,")");
} else {
strcpy(s,"ld (");
sprintf(stemp,"0x%4.4X",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 ");
switch (a) {
case 0x46: strcat(s, "0"); break;
case 0x56: strcat(s, "1"); break;
case 0x5E: strcat(s, "2"); break;
}
break;
case 0x07:
{
static STR str[8] = {"ld i, a","ld r, a","ld a, i","ld a, r","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 ");
strcat(s,ireg);
strcat(s,", bc");
break;
case 0x19:
strcpy(s,"add ");
strcat(s,ireg);
strcat(s,", de");
break;
case 0x21:
strcpy(s,"ld ");
strcat(s,ireg);
strcat(s,", ");
sprintf(stemp,"0x%4.4X",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
break;
case 0x22:
strcpy(s,"ld (");
sprintf(stemp,"0x%4.4X",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
strcat(s,"), ");
strcat(s,ireg);
break;
case 0x23:
strcpy (s,"inc ");
strcat (s, ireg);
break;
case 0x29:
strcpy(s,"add ");
strcat(s,ireg);
strcat(s,", ");
strcat(s,ireg);
break;
case 0x2A:
strcpy(s,"ld ");
strcat(s,ireg);
strcat(s,", (");
sprintf(stemp,"0x%4.4X",Opcodes[adr+1]+(Opcodes[adr+2]<<8));strcat(s,stemp);
strcat(s,")");
break;
case 0x2B:
strcpy(s,"dec ");
strcat(s,ireg);
break;
case 0x34:
strcpy(s,"inc (");
strcat(s,ireg);
strcat(s,"+");
sprintf(stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
strcat(s,")");
break;
case 0x35:
strcpy(s,"dec (");
strcat(s,ireg);
strcat(s,"+");
sprintf(stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
strcat(s,")");
break;
case 0x36:
strcpy(s,"ld (");
strcat(s,ireg);
strcat(s,"+");
sprintf(stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
strcat(s,"), ");
sprintf(stemp,"0x%2.2X",Opcodes[adr+2]);strcat(s,stemp);
break;
case 0x39:
strcpy(s,"add ");
strcat(s,ireg);
strcat(s,", sp");
break;
case 0x46:
case 0x4E:
case 0x56:
case 0x5E:
case 0x66:
case 0x6E:
strcpy(s,"ld ");
strcat(s,reg[(a>>3)&7]);
strcat(s,", (");
strcat(s,ireg);
strcat(s,"+");
sprintf(stemp,"0x%2.2X",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 (");
strcat(s,ireg);
strcat(s,"+");
sprintf(stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
strcat(s,"), ");
strcat(s,reg[a & 7]);
break;
case 0x7E:
strcpy(s,"ld a, (");
strcat(s,ireg);
strcat(s,"+");
sprintf(stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
strcat(s,")");
break;
case 0x86:
strcpy(s,"add a, (");
strcat(s,ireg);
strcat(s,"+");
sprintf(stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
strcat(s,")");
break;
case 0x8E:
strcpy(s,"adc a, (");
strcat(s,ireg);
strcat(s,"+");
sprintf(stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
strcat(s,")");
break;
case 0x96:
strcpy(s,"sub a, (");
strcat(s,ireg);
strcat(s,"+");
sprintf(stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
strcat(s,")");
break;
case 0x9E:
strcpy(s,"sbc a, (");
strcat(s,ireg);
strcat(s,"+");
sprintf(stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
strcat(s,")");
break;
case 0xA6:
strcpy(s,"and a, (");
strcat(s,ireg);
strcat(s,"+");
sprintf(stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
strcat(s,")");
break;
case 0xAE:
strcpy(s,"xor a, (");
strcat(s,ireg);
strcat(s,"+");
sprintf(stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
strcat(s,")");
break;
case 0xB6:
strcpy(s,"or a, (");
strcat(s,ireg);
strcat(s,"+");
sprintf(stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
strcat(s,")");
break;
case 0xBE:
strcpy(s,"cp a, (");
strcat(s,ireg);
strcat(s,"+");
sprintf(stemp,"0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
strcat(s,")");
break;
case 0xE1:
strcpy(s,"pop ");
strcat(s,ireg);
break;
case 0xE3:
strcpy(s,"ex (sp), ");
strcat(s,ireg);
break;
case 0xE5:
strcpy(s,"push ");
strcat(s,ireg);
break;
case 0xE9:
strcpy(s,"jp (");
strcat(s,ireg);
strcat(s,")");
break;
case 0xF9:
strcpy(s,"ld sp, ");
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 ", "sll ", "srl " };
strcpy(s,str[d]);
}
break;
case 0x40:
strcpy(s,"bit ");
stemp[0] = d + '0';
strcat(s,stemp);
strcat(s,", ");
break;
case 0x80:
strcpy(s,"res ");
stemp[0] = d + '0';
strcat(s,stemp);
strcat(s,", ");
break;
case 0xC0:
strcpy(s,"set ");
stemp[0] = d + '0';
strcat(s,stemp);
strcat(s,", ");
break;
}
if ((a&7) != 6) {
strcat(s,reg[a&7]);
strcat(s,", ");
}
strcat(s,"(");
strcat(s,ireg);
strcat(s,"+");
sprintf(stemp, "0x%2.2X",Opcodes[adr+1]);
strcat(s,stemp);
strcat(s,")");
break;
}
break;
}
} else {
strcpy (s,"push ");
strcat (s, ((d >> 1)==3)? "af": dreg[d>>1]);
}
break;
case 0x06:
strcpy (s, arith[d]);
sprintf (stemp, "0x%2.2X",Opcodes[adr+1]);strcat(s,stemp);
break;
case 0x07:
strcpy (s, "rst ");
sprintf (stemp, "0x%2.2X",a & 0x38);strcat(s,stemp);
break;
}
break;
}
return len;
}
static int z80dis (int addr, const unsigned char *buf, char *out, int len) {
return Disassemble (addr, buf, out, len);
}
#if MAIN_DIS
// Einlesen, Parsen, Disassemblieren und Ausgeben
int main(void)
{
WORD i;
FILE *f;
UWORD adr = 0;
CHAR s[80]; // Ausgabestring
f = fopen("EPROM","rb");
if(!f) return 1;
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: DEFB",(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, Opcodes); // Länge vom Opcode ermitteln
#if 1
if(OpcodesFlags[adr] & 0x10)
fprintf(f,"L%4.4X: ",adr);
else
fprintf(f," ");
#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);
return 0;
}
#endif