Z80 Compile.c

/***
 *  eine tokenisierte Zeile übersetzen
 ***/
 
#include <stdio.h>
#include <stdlib.h>
#include "Z80 Assembler.h"
 
VOID            DoPseudo(CommandP *cp);
VOID            DoOpcode(CommandP *cp);
WORD            GetOperand(CommandP *cp,LONG *value);
 
/***
 *  Operanden holen
 ***/
WORD            GetOperand(CommandP *c,LONG *value)
{
WORD        typ;
WORD        val,sval;
 
    LastRecalc = nil;   // (sicher ist sicher: Recalc-Eintrag löschen)
    *value = 0;
    typ = (*c)->typ;val = (*c)++->val;                      // Wert und Typ holen
    if(typ == OPCODE) {
        if((val >= 0x300)&&(val <= 0x4FF)) {
            if((val == 0x323)&&((*c)->typ == OPCODE)&&((*c)->val == '\'')) {    // AF'?
                (*c)++;                                     // ' überspringen
                val = 0x324;                                // AF' zurückgeben
            }
            return(val);                                    // Register bzw. Conditions
        }
        if((val >= 0x100)&&(val <= 0x2FF))                  // ein Opcode!
            Error("Illegaler Operand!");
        if((val == '('))    {                               // Indirekte Adreßierung?
            typ = (*c)->typ;sval = (*c)++->val;             // Wert und Typ holen
            if(typ == OPCODE) {
                if(((sval & 0xFF0) == 0x310)||(sval == 0x301)) {// Register
                    typ = (*c)->typ;val = (*c)++->val;      // Wert und Typ holen
                    if((typ == OPCODE)&&(val == ')')) {
                        if(sval == 0x312)                   // (HL)?
                            return(0x306);                  // zum besseren Zusammensetzen!!!
                        return(sval + 0x200);               // (C),(BC),(DE),(SP)
                    }
                    Error("Klammer zu nach (BC,(DE,(HL oder (SP fehlt!");
                }
                if((sval & 0xFF0) == 0x330) {               // IX,IY
                    if((*c)->typ == OPCODE) {               // folgt ein Rechenzeichen?
                        val = (*c)->val;
                        if((val == '+')||(val == '-')) {
                            *value = CalcTerm(c);
                            typ = (*c)->typ;val = (*c)++->val;  // Klammer zu holen
                            if((typ == OPCODE)&&(val == ')'))
                                return(sval + 0x300);       // (IX+d) oder (IY+d)
                            Error("Klammer zu nach (IX oder (IY fehlt!");
                        } else {
                            if((typ == OPCODE)&&(val == ')')) {
                                (*c)++;                     // Klammer zu überlesen
                                return(sval + 0x200);       // (IX) oder (IY)
                            }
                            Error("Klammer zu nach (IX oder (IY fehlt!");
                        }
                    } else
                        Error("Illegales Zeichen nach (IX oder (IY");
                }
            }
            (*c)--;     // Ptr auf das vorherige Zeichen zurück
            *value = CalcTerm(c);
            typ = (*c)->typ;val = (*c)++->val;      // Klammer zu holen
            if((typ == OPCODE)&&(val == ')'))
                return(0x280);                      // (Adr)
            Error("Klammer zu nach (Adr) fehlt!");
        }
    }                                       // Absolute Adreßierung
    (*c)--;                                 // Ptr auf das vorherige Zeichen zurück
    *value = CalcTerm(c);
    return(0x281);                          // Adr
}
 
/***
 *  Opcode abtesten
 ***/
VOID            DoOpcode(CommandP *cp)
{
CommandP    c = *cp;
UCHAR       *iRAM = RAM + PC;
ULONG       op0;
UBYTE       Op0_24,Op0_16;
WORD        op1,op2;
LONG        value1,value2;
RecalcListP op1Recalc,op2Recalc;
 
    op0 = c++->val;                             // Opcode
    op1 = op2 = 0;
    if(c->typ) {
        op1 = GetOperand(&c,&value1);           // 1. Operand holen
        op1Recalc = LastRecalc;                 // evtl. Recalc-Eintrag
        if((c->typ == OPCODE)&&(c->val == ',')) {   // ein 2. Operand?
            c++;
            op2 = GetOperand(&c,&value2);       // diesen auch holen
            op2Recalc = LastRecalc;             // evtl. Recalc-Eintrag
        }
    }
    Op0_24 = op0 >> 24;
    Op0_16 = op0 >> 16;
    switch(op0 & 0xFF) {        // Opcode
    case 0x00:                              // IN/OUT
                if(Op0_24 & 0x01) {         // OUT?
                    LONG    t;
                    t = op1; op1 = op2; op2 = t;                // Operanden drehen
                    t = value1; value1 = value2; value2 = t;
                    t = (LONG)op1Recalc; op1Recalc = op2Recalc; op2Recalc = (RecalcListP)t;
                }
                if(((op1 & 0xFF0)== 0x300)&&(op2 == 0x501)) {   // IN ?,(C) bzw. OUT (C),?
                    if(op1 == 0x306)
                        Error("IN (HL),(C) bzw. OUT (C),(HL) geht nicht!");
                    else {
                        *iRAM++ = 0xED;
                        *iRAM++ = Op0_24|((op1 & 0x7) << 3);
                    }
                } else if((op1 == 0x307)&&(op2 == 0x280)) {     // IN A,(n) bzw. OUT (n),A
                    *iRAM++ = Op0_16;
                    if(op2Recalc) {         // Ausdruck undefiniert?
                        op2Recalc->typ = 0; // ein Byte einsetzen
                        op2Recalc->adr = iRAM - RAM;
                        op2Recalc = nil;    // Term eingesetzt
                    }
                    *iRAM++ = value2;
                } else
                    Error("Operanden bei IN/OUT nicht erlaubt!");
                break;
    case 0x01:                              // 1.Byte Befehl ohne Parameter
                if(op1|op2)                             // Operanden angegeben?
                    Error("Keine Operanden erlaubt");   // das ist falsch!
                else
                    *iRAM++ = Op0_24;
                break;
    case 0x02:                              // 2.Byte Befehl ohne Parameter
                if(op1|op2)                             // Operanden angegeben?
                    Error("Keine Operanden erlaubt");   // das ist falsch!
                else {
                    *iRAM++ = Op0_24;
                    *iRAM++ = Op0_16;
                }
                break;
    case 0x03:  if(((op1 != 0x306)&&(op1))||(op2))      // RRD (HL) oder RLD (HL)
                    Error("Falscher Operand!");
                else {
                    *iRAM++ = Op0_24;
                    *iRAM++ = Op0_16;
                }
                break;
    case 0x04:  // 1.Parameter = Bitno., 2.Parameter = <ea> (BIT,RES,SET)
                if((op1 != 0x281)||(value1 < 0)||(value1 > 7))
                    Error("1.Operand muß 0…7 sein!");
                else {
                    if((op2 & 0xFF0) == 0x300) {    // A,B,C,D,E,H,L,(HL)
                        *iRAM++ = Op0_24;
                        *iRAM++ = Op0_16|(value1 << 3)|(op2 & 0x07);
                    } else if((op2 & 0xFF0) == 0x630) { // (IX+d) oder (IY+d)
                        *iRAM++ = (op2 & 0x01)?0xFD:0xDD;
                        *iRAM++ = Op0_24;
                        if(op2Recalc) {         // Ausdruck undefiniert?
                            op2Recalc->typ = 0; // ein Byte einsetzen
                            op2Recalc->adr = iRAM - RAM;
                            op2Recalc = nil;    // Term eingesetzt
                        }
                        *iRAM++ = value2;
                        *iRAM++ = Op0_16|(value1 << 3)|6;
                    } else
                        Error("2.Operand falsch");
                }
                break;
    case 0x05:  // IM (ein Parameter: 0,1,2)
                if((op1 != 0x281)||(op2))
                    Error("Operandenangabe falsch");
                else {
                    if((value1 < 0)||(value1 > 2))
                        Error("Nur 0, 1 oder 2 erlaubt!");
                    else {
                        if(value1 > 0) value1++;
                        *iRAM++ = Op0_24;
                        *iRAM++ = Op0_16|((value1 & 0x07)<<3);
                    }
                }
                break;
 
    case 0x06:  // ADD,ADC,SUB,SBC,AND,XOR,OR,CP
                switch(op1) {
                case 0x312: // HL
                    if((op2 >= 0x310)&&(op2 <= 0x313)) {    // BC,DE,HL,SP
                        switch(Op0_24) {
                        case 0x80:  // ADD
                            *iRAM++ = 0x09|((op2 & 0x03)<<4);
                            break;
                        case 0x88:  // ADC
                            *iRAM++ = 0xED;
                            *iRAM++ = 0x4A|((op2 & 0x03)<<4);
                            break;
                        case 0x98:  // SBC
                            *iRAM++ = 0xED;
                            *iRAM++ = 0x42|((op2 & 0x03)<<4);
                            break;
                        default:
                            Error("Befehl mit dieser <ea> nicht möglich");
                        }
                    } else
                        Error("Doppelregister erwartet");
                    break;
                case 0x330: // IX
                case 0x331: // IY
                    switch(op2) {
                    case 0x310: // BC
                        *iRAM++ = (op1 & 0x01)?0xFD:0xDD;
                        *iRAM++ = 0x09;
                        break;
                    case 0x311: // DE
                        *iRAM++ = (op1 & 0x01)?0xFD:0xDD;
                        *iRAM++ = 0x19;
                        break;
                    case 0x330: // IX
                    case 0x331: // IY
                        if(op1 == op2) {
                            *iRAM++ = (op1 & 0x01)?0xFD:0xDD;
                            *iRAM++ = 0x29;
                        } else
                            Error("Nur ADD IX,IY oder ADD IY,IY möglich!");
                        break;
                    case 0x313: // SP
                        *iRAM++ = (op1 & 0x01)?0xFD:0xDD;
                        *iRAM++ = 0x39;
                        break;
                    default:
                        Error("Befehl mit dieser <ea> nicht möglich");
                    }
                    break;
                default:
                    if((op1 == 0x307)&&(op2)) { // Akku?
                        op1 = op2;
                        value1 = value2;        // 2. Operanden nach vorne schieben
                        op1Recalc = op2Recalc;
                        op2Recalc = nil;
                    }
                    switch(op1 & 0xFF0) {
                    case 0x350: // X,HX
                                *iRAM++ = 0xDD;
                                *iRAM++ = Op0_24|(op1 & 7);
                                break;
                    case 0x360: // Y,HY
                                *iRAM++ = 0xFD;
                                *iRAM++ = Op0_24|(op1 & 7);
                                break;
                    case 0x300: // A,B,C,D,E,H,L,(HL)
                                *iRAM++ = Op0_24|(op1 & 7);
                                break;
                    case 0x630: // (IX+d) oder (IY+d)
                                *iRAM++ = (op1 & 0x01)?0xFD:0xDD;
                                *iRAM++ = Op0_24|6;
                                if(op1Recalc) {         // Ausdruck undefiniert?
                                    op1Recalc->typ = 0; // ein Byte einsetzen
                                    op1Recalc->adr = iRAM - RAM;
                                    op1Recalc = nil;    // Term eingesetzt
                                }
                                *iRAM++ = value1;
                                break;
                    case 0x280: // n
                                if(op1 == 0x281) {
                                    *iRAM++ = Op0_16;
                                    if(op1Recalc) {         // Ausdruck undefiniert?
                                        op1Recalc->typ = 0; // ein Byte einsetzen
                                        op1Recalc->adr = iRAM - RAM;
                                        op1Recalc = nil;    // Term eingesetzt
                                    }
                                    *iRAM++ = value1;
                                    break;
                                }
                    default:
                                Error("2.Operand falsch");
                    }
                }
                break;
    case 0x07:  // INC, DEC, wie 0x06 nur ohne absolute Adr.
                if(op2)
                    Error("2.Operand nicht erlaubt!");
                if((op1 & 0xFF0) == 0x300) {        // A,B,C,D,E,H,L,(HL)
                    *iRAM++ = Op0_24|((op1 & 7)<<3);
                } else if((op1 & 0xFF0) == 0x630) { // (IX+d) oder (IY+d)
                    *iRAM++ = (op1 & 1)?0xFD:0xDD;
                    *iRAM++ = Op0_24|(6<<3);
                    if(op1Recalc) {         // Ausdruck undefiniert?
                        op1Recalc->typ = 0; // ein Byte einsetzen
                        op1Recalc->adr = iRAM - RAM;
                        op1Recalc = nil;    // Term eingesetzt
                    }
                    *iRAM++ = value1;
                } else {
                    Boolean     decFlag = Op0_24 & 1;   // True: DEC, False: INC
                    switch(op1) {
                    case 0x354: // HX
                            *iRAM++ = 0xDD;
                            *iRAM++ = decFlag?0x25:0x24;
                            break;
                    case 0x355: // X
                            *iRAM++ = 0xDD;
                            *iRAM++ = decFlag?0x2D:0x2C;
                            break;
                    case 0x364: // HY
                            *iRAM++ = 0xFD;
                            *iRAM++ = decFlag?0x25:0x24;
                            break;
                    case 0x365: // Y
                            *iRAM++ = 0xFD;
                            *iRAM++ = decFlag?0x2D:0x2C;
                            break;
                    case 0x310: // BC
                            *iRAM++ = decFlag?0x0B:0x03;
                            break;
                    case 0x311: // DE
                            *iRAM++ = decFlag?0x1B:0x13;
                            break;
                    case 0x312: // HL
                            *iRAM++ = decFlag?0x2B:0x23;
                            break;
                    case 0x313: // HL
                            *iRAM++ = decFlag?0x3B:0x33;
                            break;
                    case 0x330: // IX
                            *iRAM++ = 0xDD;
                            *iRAM++ = decFlag?0x2B:0x23;
                            break;
                    case 0x331: // IY
                            *iRAM++ = 0xFD;
                            *iRAM++ = decFlag?0x2B:0x23;
                            break;
                    default:
                            Error("Adressierungsart nicht erlaubt!");
                    }
                }
                break;
    case 0x08:  // JP, CALL, JR (Achtung! Unterschiedliche <ea>!)
                if(op1 == 0x301) op1 = 0x403;   // Register C in Condition C wandeln
                switch(Op0_24) {
                case 0xC2:  // JP
                        if((op1 >= 0x400)&&(op1 <= 0x4FF)&&(op2 == 0x281)) {    // Cond,Adr
                            *iRAM++ = Op0_24|((op1 & 0x07)<<3);
                            if(op2Recalc) {         // Ausdruck undefiniert?
                                op2Recalc->typ = 1; // zwei Byte einsetzen
                                op2Recalc->adr = iRAM - RAM;
                                op2Recalc = nil;    // Term eingesetzt
                            }
                            *iRAM++ = value2;
                            *iRAM++ = value2 >> 8;
                        } else if((op1 == 0x306)&&!op2) {   // JP (HL)
                            *iRAM++ = 0xE9;
                        } else if((op1 == 0x530)&&!op2) {   // JP (IX)
                            *iRAM++ = 0xDD;
                            *iRAM++ = 0xE9;
                        } else if((op1 == 0x531)&&!op2) {   // JP (IY)
                            *iRAM++ = 0xFD;
                            *iRAM++ = 0xE9;
                        } else if((op1 == 0x281)|!op2) {    //  JP Adr
                            *iRAM++ = Op0_16;
                            if(op1Recalc) {         // Ausdruck undefiniert?
                                op1Recalc->typ = 1; // zwei Byte einsetzen
                                op1Recalc->adr = iRAM - RAM;
                                op1Recalc = nil;    // Term eingesetzt
                            }
                            *iRAM++ = value1;
                            *iRAM++ = value1 >> 8;
                        } else
                            Error("1.Operand falsch");
                        break;
                case 0x20:  // JR
                        if((op1 >= 0x400)&&(op1 <= 0x403)&&(op2 == 0x281)) {    // Cond,Adr
                            *iRAM++ = Op0_24|((op1 & 0x07)<<3);
                            if(op2Recalc) {         // Ausdruck undefiniert?
                                op2Recalc->typ = 2; // ein PC-rel-Byte einsetzen
                                op2Recalc->adr = iRAM - RAM;
                                op2Recalc = nil;    // Term eingesetzt
                            }
                            *iRAM++ = value2 - (iRAM - RAM) - 1;
                        } else if((op1 == 0x281)&&!op2) {   //  JR Adr
                            *iRAM++ = Op0_16;
                            if(op1Recalc) {         // Ausdruck undefiniert?
                                op1Recalc->typ = 2; // ein PC-rel-Byte einsetzen
                                op1Recalc->adr = iRAM - RAM;
                                op1Recalc = nil;    // Term eingesetzt
                            }
                            *iRAM++ = value1 - (iRAM - RAM) - 1;
                        } else
                            Error("Bedingung nicht erlaubt!");
                        break;
                case 0xC4:  // CALL
                        if((op1 >= 0x400)&&(op1 <= 0x4FF)&&(op2 == 0x281)) {    // Cond,Adr
                            *iRAM++ = Op0_24|((op1 & 0x07)<<3);
                            if(op2Recalc) {         // Ausdruck undefiniert?
                                op2Recalc->typ = 1; // zwei Byte einsetzen
                                op2Recalc->adr = iRAM - RAM;
                                op2Recalc = nil;    // Term eingesetzt
                            }
                            *iRAM++ = value2;
                            *iRAM++ = value2 >> 8;
                        } else if((op1 == 0x281)&&!op2) {   //  CALL Adr
                            *iRAM++ = Op0_16;
                            if(op1Recalc) {         // Ausdruck undefiniert?
                                op1Recalc->typ = 1; // zwei Byte einsetzen
                                op1Recalc->adr = iRAM - RAM;
                                op1Recalc = nil;    // Term eingesetzt
                            }
                            *iRAM++ = value1;
                            *iRAM++ = value1 >> 8;
                        } else
                            Error("1.Operand falsch");
                        break;
                default:
                        Error("Opcode-Tabelle defekt!");
                }
                break;
    case 0x09:  if(op2)                         // RET-Befehl
                    Error("zu viele Operanden");
                else if(!op1)                   // keine Condition angegeben?
                    *iRAM++ = Op0_16;           // normalen Opcode nehmen
                else {
                    if(op1 == 0x301) op1 = 0x403;   // Register C in Condition C wandeln
                    if((op1 & 0xF00) != 0x400)
                        Error("falscher Operand angegeben!");
                    else
                        *iRAM++ = Op0_24|((op1 & 0x07)<<3);
                }
                break;
    case 0x0A:  // RST (00,08,10,18,20,28,30,38)
                if(op2)
                    Error("zu viele Operanden");
                else if(op1 == 0x281) {     // n
                    WORD    i = -1;
                    switch(value1) {
                    case 0: i = 0x00;
                            break;
                    case 1:
                    case 8: i = 0x08;
                            break;
                    case 2:
                    case 10:i = 0x10;
                            break;
                    case 3:
                    case 18:i = 0x18;
                            break;
                    case 4:
                    case 20:i = 0x20;
                            break;
                    case 5:
                    case 28:i = 0x28;
                            break;
                    case 6:
                    case 30:i = 0x30;
                            break;
                    case 7:
                    case 38:i = 0x38;
                            break;
                    default:
                            Error("Nur 00,08,10,18,20,28,30,38 ist erlaubt!");
                    }
                    if(i>=0)
                        *iRAM++ = Op0_24|i;
                } else
                    Error("Adressierungsart nicht erlaubt!");
                break;
    case 0x0B:  // DJNZ
                *iRAM++ = Op0_24;
                if(op1Recalc) {         // Ausdruck undefiniert?
                    op1Recalc->typ = 2; // ein PC-rel-Byte einsetzen
                    op1Recalc->adr = iRAM - RAM;
                    op1Recalc = nil;    // Term eingesetzt
                }
                *iRAM++ = value1 - (iRAM - RAM) - 1;        // relozieren
                break;
    case 0x0C:  // EX: (SP),dreg oder DE,HL oder AF,AF'
                if((op1 == 0x311)&&(op2 == 0x312))      // EX DE,HL
                    *iRAM++ = 0xEB;
                else if((op1 == 0x323)&&(op2 == 0x324)) {   // EX AF,AF'
                    *iRAM++ = 0x08;
                }
                else if((op1 == 0x513)&&(op2 == 0x312))     // EX (SP),HL
                    *iRAM++ = 0xE3;
                else if((op1 == 0x513)&&(op2 == 0x330)) {   // EX (SP),IX
                    *iRAM++ = 0xDD;
                    *iRAM++ = 0xE3;
                }
                else if((op1 == 0x513)&&(op2 == 0x331)) {   // EX (SP),IY
                    *iRAM++ = 0xFD;
                    *iRAM++ = 0xE3;
                }
                else
                    Error("Operanden bei Exchange nicht möglich!");
                break;
    case 0x0D:  // LD
                if(!(op1 & op2))
                    Error("Operand fehlt!");
                else {
                    UBYTE   FirstByte = 0;
                    switch(op1) {
                    case 0x530: // LD (IX),
                    case 0x531: // LD (IY),
                            op1 = (op1 == 0x530)?0x356:0x366;
                    case 0x354: //  HX
                    case 0x355: //  X
                    case 0x364: //  HY
                    case 0x365: //  Y
                            FirstByte = ((op1 & 0xFF0)==0x350)?0xDD:0xFD;
                            *iRAM++ = FirstByte;
                            op1 &= 0xF0F;   // auf H und L ummappen
                    case 0x300: // B
                    case 0x301: // C
                    case 0x302: // D
                    case 0x303: // E
                    case 0x304: // H
                    case 0x305: // L
                    case 0x306: // (HL)
                    case 0x307: // A
                            switch(op2 & 0xFF0) {
                            case 0x530: // LD <ea>,(IX), bzw. LD <ea>,(IY)
                                    op2 = (op2 == 0x530)?0x356:0x366;
                            case 0x350:     // X,HX
                            case 0x360:     // Y,HY
                                    {
                                    Boolean flag = ((op2 & 0xFF0)==0x350);
                                    switch(FirstByte) {
                                    case 0xDD:  // IX
                                            if(!flag)
                                                Error("IX,IY geht nicht!");
                                            break;
                                    case 0xFD:  // IY
                                            if(flag)
                                                Error("IY,IX geht nicht!");
                                            break;
                                    default:    // noch nix
                                            *iRAM++ = (flag)?0xDD:0xFD;
                                            break;
                                    }
                                    }
                                    op2 &= 0xF0F;   // auf H und L ummappen
                            case 0x300:     // B,C,D,E,H,L,(HL),A
                                    *iRAM++ = 0x40|((op1 & 0x07)<<3)|(op2 & 0x07);
                                    break;
                            case 0x510:     // (BC),(DE),(SP)
                                    if(op1 == 0x307) {
                                        if(op2 == 0x510)
                                            *iRAM++ = 0x0A;
                                        else if(op2 == 0x511)
                                            *iRAM++ = 0x1A;
                                        else
                                            Error("(SP) nicht erlaubt");
                                    } else
                                        Error("nur LD A,(BC) oder LD A,(DE) möglich!");
                                    break;
                            case 0x630: // (IX+d), (IY+d)
                                    if(op1 != 0x306) {  // (HL)
                                        *iRAM++ = (op2 & 0x01)?0xFD:0xDD;
                                        *iRAM++ = 0x46|((op1 & 0x07)<<3);
                                        if(op2Recalc) {         // Ausdruck undefiniert?
                                            op2Recalc->typ = 0; // ein Byte einsetzen
                                            op2Recalc->adr = iRAM - RAM;
                                            op2Recalc = nil;    // Term eingesetzt
                                        }
                                        *iRAM++ = value2;
                                    } else
                                        Error("LD (HL),(IX/IY+d) nicht erlaubt!");
                                    break;
                            case 0x280: // (n), n
                                    if(op2 == 0x281) {
                                        *iRAM++ = 0x06|((op1 & 0x07)<<3);
                                        if(op2Recalc) {         // Ausdruck undefiniert?
                                            op2Recalc->typ = 0; // ein Byte einsetzen
                                            op2Recalc->adr = iRAM - RAM;
                                            op2Recalc = nil;    // Term eingesetzt
                                        }
                                        *iRAM++ = value2;
                                    } else {
                                        if(op1 == 0x307) {
                                            *iRAM++ = 0x3A;
                                            if(op2Recalc) {         // Ausdruck undefiniert?
                                                op2Recalc->typ = 1; // zwei Byte einsetzen
                                                op2Recalc->adr = iRAM - RAM;
                                                op2Recalc = nil;    // Term eingesetzt
                                            }
                                            *iRAM++ = value2;
                                            *iRAM++ = value2 >> 8;
                                        } else
                                            Error("Nur LD A,(n) ist erlaubt!");
                                    }
                                    break;
                            case 0x340: // I,R
                                    if(op1 == 0x307) {
                                        *iRAM++ = 0xED;
                                        *iRAM++ = (op2 != 0x340)?0x57:0x5F;
                                    } else
                                        Error("Nur LD A,I oder LD A,R ist erlaubt!");
                                    break;
                            default:
                                    Error("2.Operand fehlerhaft");
                            }
                            break;
                    case 0x340: // I,R
                    case 0x341: // I,R
                            if(op2 == 0x307) {  // A
                                *iRAM++ = 0xED;
                                *iRAM++ = (op1 != 0x340)?0x47:0x4F;
                            } else
                                Error("nur LD I,A oder LD R,A erlaubt!");
                            break;
                    case 0x510: // (BC)
                    case 0x511: // (DE)
                            if(op2 == 0x307) {  // A
                                *iRAM++ = (op1 == 0x510)?0x02:0x12;
                            } else
                                Error("nur LD (BC),A oder LD (DE),A erlaubt!");
                            break;
                    case 0x630: // (IX+d)
                    case 0x631: // (IY+d)
                            switch(op2) {
                            case 0x300: // B
                            case 0x301: // C
                            case 0x302: // D
                            case 0x303: // E
                            case 0x304: // H
                            case 0x305: // L
                            case 0x307: // A
                                *iRAM++ = (op1 & 0x01)?0xFD:0xDD;
                                *iRAM++ = 0x70|(op2 & 0x07);
                                if(op1Recalc) {         // Ausdruck undefiniert?
                                    op1Recalc->typ = 0; // ein Byte einsetzen
                                    op1Recalc->adr = iRAM - RAM;
                                    op1Recalc = nil;    // Term eingesetzt
                                }
                                *iRAM++ = value1;
                                break;
                            case 0x281: // n
                                *iRAM++ = (op1 & 0x01)?0xFD:0xDD;
                                *iRAM++ = 0x36;
                                if(op1Recalc) {         // Ausdruck undefiniert?
                                    op1Recalc->typ = 0; // ein Byte einsetzen
                                    op1Recalc->adr = iRAM - RAM;
                                    op1Recalc = nil;    // Term eingesetzt
                                }
                                *iRAM++ = value1;
                                if(op2Recalc) {         // Ausdruck undefiniert?
                                    op2Recalc->typ = 0; // ein Byte einsetzen
                                    op2Recalc->adr = iRAM - RAM;
                                    op2Recalc = nil;    // Term eingesetzt
                                }
                                *iRAM++ = value2;
                                break;
                            default:
                                Error("2.Operand fehlerhaft");
                            }
                            break;
                    case 0x280: // (n)
                            switch(op2) {
                            case 0x307: // A
                                *iRAM++ = 0x32;
                                if(op1Recalc) {         // Ausdruck undefiniert?
                                    op1Recalc->typ = 1; // zwei Byte einsetzen
                                    op1Recalc->adr = iRAM - RAM;
                                    op1Recalc = nil;    // Term eingesetzt
                                }
                                *iRAM++ = value1;
                                *iRAM++ = value1 >> 8;
                                break;
                            case 0x312: // HL
                                *iRAM++ = 0x22;
                                if(op1Recalc) {         // Ausdruck undefiniert?
                                    op1Recalc->typ = 1; // zwei Byte einsetzen
                                    op1Recalc->adr = iRAM - RAM;
                                    op1Recalc = nil;    // Term eingesetzt
                                }
                                *iRAM++ = value1;
                                *iRAM++ = value1 >> 8;
                                break;
                            case 0x310: // BC
                            case 0x311: // DE
                            case 0x313: // SP
                                *iRAM++ = 0xED;
                                *iRAM++ = 0x43|((op2 & 0x03)<<4);
                                if(op1Recalc) {         // Ausdruck undefiniert?
                                    op1Recalc->typ = 1; // zwei Byte einsetzen
                                    op1Recalc->adr = iRAM - RAM;
                                    op1Recalc = nil;    // Term eingesetzt
                                }
                                *iRAM++ = value1;
                                *iRAM++ = value1 >> 8;
                                break;
                            case 0x330: // IX
                            case 0x331: // IY
                                *iRAM++ = (op2 & 0x01)?0xFD:0xDD;
                                *iRAM++ = 0x22;
                                if(op1Recalc) {         // Ausdruck undefiniert?
                                    op1Recalc->typ = 1; // zwei Byte einsetzen
                                    op1Recalc->adr = iRAM - RAM;
                                    op1Recalc = nil;    // Term eingesetzt
                                }
                                *iRAM++ = value1;
                                *iRAM++ = value1 >> 8;
                                break;
                            default:
                                Error("2.Operand fehlerhaft");
                            }
                            break;
                    case 0x313: // SP
                            switch(op2) {
                            case 0x312:     // HL
                                *iRAM++ = 0xF9;
                                break;
                            case 0x330:     // IX
                                *iRAM++ = 0xDD;
                                *iRAM++ = 0xF9;
                                break;
                            case 0x331:     // IY
                                *iRAM++ = 0xFD;
                                *iRAM++ = 0xF9;
                                break;
                            }
                    case 0x310: // BC
                    case 0x311: // DE
                    case 0x312: // HL
                            if((op2 == 0x280)||(op2 == 0x281))  {   // (n), n
                                if(op2 == 0x281) {      // n
                                    *iRAM++ = 0x01|((op1 & 0x03)<<4);
                                } else {                // (n)
                                    if(op1 == 0x312)    // HL
                                        *iRAM++ = 0x2A;
                                    else {
                                        *iRAM++ = 0xED;
                                        *iRAM++ = 0x4B|((op1 & 0x03)<<4);
                                    }
                                }
                                if(op2Recalc) {         // Ausdruck undefiniert?
                                    op2Recalc->typ = 1; // zwei Byte einsetzen
                                    op2Recalc->adr = iRAM - RAM;
                                    op2Recalc = nil;    // Term eingesetzt
                                }
                                *iRAM++ = value2;
                                *iRAM++ = value2 >> 8;
                            } else
                                Error("2.Operand fehlerhaft");
                            break;
                    case 0x330: // IX
                    case 0x331: // IY
                            if((op2 == 0x280)||(op2 == 0x281))  {   // (n), n
                                *iRAM++ = (op1 & 0x01)?0xFD:0xDD;
                                *iRAM++ = (op2 == 0x281)?0x21:0x2A;
                                if(op2Recalc) {         // Ausdruck undefiniert?
                                    op2Recalc->typ = 1; // zwei Byte einsetzen
                                    op2Recalc->adr = iRAM - RAM;
                                    op2Recalc = nil;    // Term eingesetzt
                                }
                                *iRAM++ = value2;
                                *iRAM++ = value2 >> 8;
                            } else
                                Error("2.Operand fehlerhaft");
                            break;
                    default:
                            Error("Adreßierungsart nicht erlaubt!");
                    }
                }
                break;
    case 0x0E:  // PUSH, POP: dreg
                if(op2)
                    Error("zu viele Operanden");
                else if(((op1 & 0xFF0) >= 0x310)&&((op1 & 0xFF0) <= 0x33F)) {   // Doppel-Register?
                    if((op1 >= 0x310)&&(op1 <= 0x312))
                        *iRAM++ = Op0_24|((op1-0x310)<<4);  // PUSH BC,DE,HL
                    else if(op1 == 0x323)
                        *iRAM++ = Op0_24|((op1-0x320)<<4);  // PUSH AF
                    else if((op1 == 0x330)|(op1 == 0x331)) {    // PUSH IX,IY
                        *iRAM++ = (op1 & 0x01)?0xFD:0xDD;
                        *iRAM++ = Op0_16;
                    }
                } else
                    Error("nur Doppelregister sind möglich!");
                break;
    case 0x0F:  // RR,RL,RRC,RLC,SRA,SLA,SRL
                if(op2)
                    Error("nur ein Operand erlaubt!");
                else if((op1 & 0xFF0) == 0x300) {           // B,C,D,E,H,L,(HL),A
                    *iRAM++ = 0xCB;
                    *iRAM++ = Op0_24|(op1 & 0x07);
                } else if((op1 == 0x630)||(op1 = 0x631)) {  // (IX+d), (IY+d)
                    *iRAM++ = (op1 & 0x01)?0xFD:0xDD;
                    *iRAM++ = 0xCB;
                    if(op1Recalc) {         // Ausdruck undefiniert?
                        op1Recalc->typ = 0; // ein Byte einsetzen
                        op1Recalc->adr = iRAM - RAM;
                        op1Recalc = nil;    // Term eingesetzt
                    }
                    *iRAM++ = value1;
                    *iRAM++ = Op0_24|6;
                } else
                    Error("Operand hier nicht erlaubt");
                break;
    default:
                Error("Unbekannte Opcode-Typ!");
                while(c->typ) c++;
    }
    *cp = c;
    PC = iRAM - RAM;
}
 
/***
 *  Pseudo-Opcode abtesten
 ***/
Boolean     IgnoreUntilIF = false;  // Zeilen bis zum "ENDIF" ignorieren
 
 
VOID            DoPseudo(CommandP *cp)
{
CommandP    c = *cp;
CommandP    cptr;
UWORD       iPC = PC;
 
    switch(c++->val) {      // Opcode durchgehen
    case 0x100:             // DEFB
                c--;
                do {
                    c++;
                    cptr = c;
                    RAM[iPC++] = CalcTerm(&cptr);
                    c = cptr;
                    if(LastRecalc) {            // Ausdruck undefiniert?
                        LastRecalc->typ = 0;    // ein Byte einsetzen
                        LastRecalc->adr = iPC - 1;
                    }
                } while((c->typ == OPCODE)&&(c->val == ','));
                break;
    case 0x101:             // DEFM
                if(c->typ != STRING) {
                    Error("Kein String bei DEFM!");
                } else {
                    STR     sp;
                    c--;
                    do {
                        c++;                        // Opcode bzw. Komma skippen
                        sp = (STR)c++->val;         // Wert = Ptr auf den String
                        while(*sp)
                            RAM[iPC++] = *sp++;     // String übertragen
                    } while((c->typ == OPCODE)&&(c->val == ','));
                }
                break;
    case 0x102:             // DEFS
                cptr = c;
                iPC +=  CalcTerm(&cptr);        // PC weitersetzen
                c = cptr;
                if(LastRecalc)
                    Error("Symbol nicht definiert!");
                break;
    case 0x103:             // DEFW
                c--;
                do {
                    ULONG   val;
                    c++;
                    cptr = c;
                    val = CalcTerm(&cptr);      // Ausdruck auswerten
                    c = cptr;
                    if(LastRecalc) {            // Ausdruck undefiniert?
                        LastRecalc->typ = 1;    // zwei Byte einsetzen
                        LastRecalc->adr = iPC;
                    }
                    RAM[iPC++] = val >> 8;
                    RAM[iPC++] = val;
                } while((c->typ == OPCODE)&&(c->val == ','));
                break;
    case 0x104:             // END
                if(IgnoreUntilIF)                   // dann nicht mehr übersetzen
                    Error("IF ohne ENDIF!");
                Error("Ende vom Sourcetext erreicht");
                exit(0);
    case 0x106:             // ORG
                cptr = c;
                iPC = CalcTerm(&cptr);              // PC setzen
                c = cptr;
                if(LastRecalc)
                    Error("Symbol nicht definiert!");
                break;
    case 0x107:             // IF
                cptr = c;
                if(!CalcTerm(&cptr))                // IF-Bedinung false?
                    IgnoreUntilIF = true;           // dann nicht mehr übersetzen
                c = cptr;
                break;
    case 0x108:             // ENDIF
                IgnoreUntilIF = false;              // ab hier stets übersetzen
                break;
    case 0x109:             // ELSE
                IgnoreUntilIF = !IgnoreUntilIF;     // Zeilen-Übersetzen-Flag toggeln
                break;
    case 0x10A:             // PRINT
                if(c->typ != STRING)
                    Error("Kein String bei PRINT!");
                else
                    puts((STR)c++->val);            // Message ausgeben
                break;
    }
    *cp = c;
    PC = iPC;
}
 
/***
 *  Zeile übersetzen
 ***/
VOID        CompileLine(VOID)
{
CommandP        c = Cmd;
CommandP        cptr;
SymbolP         s;
UWORD           val;
 
    if(!c->typ) return;                 // Leerzeile => raus
    if((c->typ == SYMBOL)&& !IgnoreUntilIF) {           // ein Symbol am Zeilenanfang und _kein_ IF?
        s = (SymbolP)c->val;            // Wert = Symbol-Ptr
        if(s->defined) {
            Error("Symbol bereits definiert");
            return;
        }
        c++;                            // ein Command weiter
        if((c->typ == OPCODE)&&(c->val == ':'))
            c++;                        // eventuellen ':' überspringen
        if((c->typ == OPCODE)&&(c->val == 0x105)) { // EQU?
            c++;                        // EQU überspringen
            cptr = c;
            s->val = CalcTerm(&cptr);   // Ausduck ausrechnen
            c = cptr;
            if(LastRecalc)
                Error("Symbol in Formel nicht definiert");
            s->defined = true;          // Symbol definiert
            if(c->typ != ILLEGAL) {
                Error("Daten nach EQU!");
                return;
            }
        } else {
            s->val = PC;                // Adresse = aktueller PC
            s->defined = true;          // Symbol definiert
        }
        while(s->recalc) {              // vom Symbol abhängige Ausdrücke?
            RecalcListP r = s->recalc;
            CommandP    saveC;
            LONG        value;
 
            s->recalc = r->next;        // zum nächsten Symbol vorrücken
            saveC = r->c;
            value = CalcTerm(&(r->c));  // Formel (mit jetzt def. Symbol) erneut ausrechnen
            if(!LastRecalc) {           // Ausdruck nun gültig (oder gar noch ein Symbol?)
                UWORD   adr = r->adr;
                switch(r->typ) {
                case 0x00:              // ein Byte einsetzen
                            RAM[adr] = value;
                            break;
                case 0x01:              // zwei Byte einsetzen
                            RAM[adr++] = value;
                            RAM[adr] = value>>8;
                            break;
                case 0x02:              // PC-rel-Byte einsetzen
                            RAM[adr] = value - (adr + 1);
                            break;
                default:    Error("unbekannter Recalc-Typ!");
                }
            } else {                    // Ausdruck immer noch nicht zu berechnen
                LastRecalc->typ = r->typ;   // Typ übertragen
                LastRecalc->adr = r->adr;   // Adresse übertragen
            }
            free(saveC);                // Formel freigeben
            free(r);                    // Recalc-Term freigeben
        }
    }
    if(IgnoreUntilIF) {                 // innerhalb eines IFs?
        if(c->typ == OPCODE) {
            switch(c->val) {
            case 0x108:     // ENDIF erreicht?
                    IgnoreUntilIF = false;          // Zeilen wieder übersetzen
                    break;
            case 0x109:     // ELSE erreicht?
                    IgnoreUntilIF = !IgnoreUntilIF; // Zeilen-Übersetzen-Flag toggeln
                    break;
            }
        }
    } else
        while(c->typ) {                 // bis zum Zeilenende scannen
            val = c->val;
            if((val < 0x100)||(val > 0x2FF))    // kein Opcode bzw. Pseudo-Opcode?
                Error("Illegales Zeichen");     // => Fehler!
            cptr = c;
            if((val >= 0x100)&&(val <= 0x1FF))  // Pseudo-Opcode
                DoPseudo(&cptr);
            else
                DoOpcode(&cptr);                // Opcode scannen
            c = cptr;
        }
}
 
software/z80_compile.c.txt · Last modified: 2006/03/16 02:57 (external edit)
 
Recent changes RSS feed