/* code87c800.c */
/*****************************************************************************/
/* AS-Portierung                                                             */
/*                                                                           */
/* Codegenerator TLCS-870                                                    */
/*                                                                           */
/* Historie: 29.12.1996 Grundsteinlegung                                     */
/*            2. 1.1999 ChkPC umgebaut                                       */
/*                                                                           */
/*****************************************************************************/

#include "stdinc.h" 

#include <ctype.h>
#include <string.h>

#include "nls.h"
#include "bpemu.h"
#include "strutil.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "codepseudo.h"
#include "codevars.h"


typedef struct
         {
          char *Name;
          Word Code;
         } FixedOrder;

typedef struct
         {
          char *Name;
          Byte Code;
         } CondRec;

#define FixedOrderCnt 7
#define ConditionCnt 12
#define RegOrderCnt 7
#define ALUOrderCnt 8


#define ModNone (-1)
#define ModReg8 0
#define MModReg8 (1 << ModReg8)
#define ModReg16 1
#define MModReg16 (1 << ModReg16)
#define ModImm 2
#define MModImm (1 << ModImm)
#define ModAbs 3
#define MModAbs (1 << ModAbs)
#define ModMem 4
#define MModMem (1 << ModMem)

#define AccReg 0
#define WAReg 0

#define Reg8Cnt 8
static char *Reg8Names="AWCBEDLH";

static CPUVar CPU87C00,CPU87C20,CPU87C40,CPU87C70;
static ShortInt OpSize;
static Byte AdrVals[4];
static ShortInt AdrType;
static Byte AdrMode;

static FixedOrder *FixedOrders;
static CondRec *Conditions;
static FixedOrder *RegOrders;
static char **ALUOrders;

/*--------------------------------------------------------------------------*/

	static void AddFixed(char *NName, Word NCode)
BEGIN
   if (InstrZ>=FixedOrderCnt) exit(255);
   FixedOrders[InstrZ].Name=NName;
   FixedOrders[InstrZ++].Code=NCode;
END

	static void AddCond(char *NName, Byte NCode)
BEGIN
   if (InstrZ>=ConditionCnt) exit(255);
   Conditions[InstrZ].Name=NName;
   Conditions[InstrZ++].Code=NCode;
END

	static void AddReg(char *NName, Word NCode)
BEGIN
   if (InstrZ>=RegOrderCnt) exit(255);
   RegOrders[InstrZ].Name=NName;
   RegOrders[InstrZ++].Code=NCode;
END

	static void InitFields(void)
BEGIN
   FixedOrders=(FixedOrder *) malloc(sizeof(FixedOrder)*FixedOrderCnt); InstrZ=0;
   AddFixed("DI"  , 0x483a);
   AddFixed("EI"  , 0x403a);
   AddFixed("RET" , 0x0005);
   AddFixed("RETI", 0x0004);
   AddFixed("RETN", 0xe804);
   AddFixed("SWI" , 0x00ff);
   AddFixed("NOP" , 0x0000);

   Conditions=(CondRec *) malloc(sizeof(CondRec)*ConditionCnt); InstrZ=0;
   AddCond("EQ", 0); AddCond("Z" , 0);
   AddCond("NE", 1); AddCond("NZ", 1);
   AddCond("CS", 2); AddCond("LT", 2);
   AddCond("CC", 3); AddCond("GE", 3);
   AddCond("LE", 4); AddCond("GT", 5);
   AddCond("T" , 6); AddCond("F" , 7);

   RegOrders=(FixedOrder *) malloc(sizeof(FixedOrder)*RegOrderCnt); InstrZ=0;
   AddReg("DAA" , 0x0a);  AddReg("DAS" , 0x0b);
   AddReg("SHLC", 0x1c);  AddReg("SHRC", 0x1d);
   AddReg("ROLC", 0x1e);  AddReg("RORC", 0x1f);
   AddReg("SWAP", 0x01);

   ALUOrders=(char **) malloc(sizeof(char *)*ALUOrderCnt); InstrZ=0; 
   ALUOrders[InstrZ++]="ADDC";
   ALUOrders[InstrZ++]="ADD";
   ALUOrders[InstrZ++]="SUBB";
   ALUOrders[InstrZ++]="SUB";
   ALUOrders[InstrZ++]="AND";
   ALUOrders[InstrZ++]="XOR";
   ALUOrders[InstrZ++]="OR";
   ALUOrders[InstrZ++]="CMP";
END

	static void DeinitFields(void)
BEGIN
   free(FixedOrders);
   free(Conditions);
   free(RegOrders);
   free(ALUOrders);
END

/*--------------------------------------------------------------------------*/

	static void ChkAdr(Byte Erl)
BEGIN
   if ((AdrType!=ModNone) AND (((1<<AdrType)&Erl)==0))
    BEGIN
     AdrType=ModNone; AdrCnt=0; WrError(1350);
    END
END

	static void DecodeAdr(char *Asc, Byte Erl)
BEGIN
#define Reg16Cnt 4
   static char *Reg16Names[Reg16Cnt]={"WA","BC","DE","HL"};
#define AdrRegCnt 5
   static char *AdrRegs[AdrRegCnt]={"HL","DE","C","PC","A"};

   int z;
   Byte RegFlag;
   LongInt DispAcc,DispPart;
   String AdrPart;
   Boolean OK,NegFlag,NNegFlag,FirstFlag;
   char *PPos,*NPos,*EPos;

   AdrType=ModNone; AdrCnt=0;

   if (strlen(Asc)==1)
    for (z=0; z<Reg8Cnt; z++)
     if (toupper(*Asc)==Reg8Names[z])
      BEGIN
       AdrType=ModReg8; OpSize=0; AdrMode=z;
       ChkAdr(Erl); return;
      END

   for (z=0; z<Reg16Cnt; z++)
    if (strcasecmp(Asc,Reg16Names[z])==0)
     BEGIN
      AdrType=ModReg16; OpSize=1; AdrMode=z;
      ChkAdr(Erl); return;
     END

   if (IsIndirect(Asc))
    BEGIN
     strcpy(Asc,Asc+1); Asc[strlen(Asc)-1]='\0';
     if (strcasecmp(Asc,"-HL")==0)
      BEGIN
       AdrType=ModMem; AdrMode=7; ChkAdr(Erl); return;
      END
     if (strcasecmp(Asc,"HL+")==0)
      BEGIN
       AdrType=ModMem; AdrMode=6; ChkAdr(Erl); return;
      END
     RegFlag=0; DispAcc=0; NegFlag=False; OK=True; FirstFlag=False;
     while ((OK) AND (*Asc!='\0'))
      BEGIN
       PPos=QuotPos(Asc,'+'); NPos=QuotPos(Asc,'-');
       if (PPos==Nil) EPos=NPos;
       else if (NPos==Nil) EPos=PPos;
       else EPos=min(NPos,PPos);
       NNegFlag=((EPos!=Nil) AND (*EPos=='-'));
       if (EPos==Nil)
        BEGIN
         strmaxcpy(AdrPart,Asc,255); *Asc='\0';
        END
       else
        BEGIN
         *EPos='\0'; strmaxcpy(AdrPart,Asc,255); strcpy(Asc,EPos+1);
        END
       for (z=0; z<AdrRegCnt; z++)
        if (strcasecmp(AdrPart,AdrRegs[z])==0) break;
       if (z>=AdrRegCnt)
	BEGIN
         FirstPassUnknown=False;
	 DispPart=EvalIntExpression(AdrPart,Int32,&OK);
         FirstFlag|=FirstPassUnknown;
	 if (NegFlag) DispAcc-=DispPart; else DispAcc+=DispPart;
	END
       else if ((NegFlag) OR ((RegFlag & (1 << z))!=0))
	BEGIN
	 WrError(1350); OK=False;
	END
       else RegFlag+=1 << z;
       NegFlag=NNegFlag;
      END
     if (DispAcc!=0) RegFlag+=1 << AdrRegCnt;
     if (OK)
      switch (RegFlag)
       BEGIN
        case 0x20:
         if (FirstFlag) DispAcc&=0xff;
         if (DispAcc>0xff) WrError(1320);
	 else
	  BEGIN
	   AdrType=ModAbs; AdrMode=0;
	   AdrCnt=1; AdrVals[0]=DispAcc & 0xff;
	  END
         break;
        case 0x02:
	 AdrType=ModMem; AdrMode=2;
	 break;
        case 0x01:
	 AdrType=ModMem; AdrMode=3;
	 break;
        case 0x21:
         if (FirstFlag) DispAcc&=0x7f;
         if (DispAcc>127) WrError(1320);
	 else if (DispAcc<-128) WrError(1315);
	 else
	  BEGIN
	   AdrType=ModMem; AdrMode=4;
	   AdrCnt=1; AdrVals[0]=DispAcc & 0xff;
	  END
         break;
        case 0x05:
	 AdrType=ModMem; AdrMode=5;
	 break;
        case 0x18:
	 AdrType=ModMem; AdrMode=1;
	 break;
        default:
         WrError(1350);
       END
     ChkAdr(Erl); return;
    END
   else
    switch (OpSize)
     BEGIN
      case -1:
       WrError(1132);
       break;
      case 0:
       AdrVals[0]=EvalIntExpression(Asc,Int8,&OK);
       if (OK)
        BEGIN
 	 AdrType=ModImm; AdrCnt=1;
        END
       break;
      case 1:
       DispAcc=EvalIntExpression(Asc,Int16,&OK);
       if (OK)
        BEGIN
	 AdrType=ModImm; AdrCnt=2;
	 AdrVals[0]=DispAcc & 0xff;
	 AdrVals[1]=(DispAcc >> 8) & 0xff;
        END
       break;
     END

   ChkAdr(Erl);
END

	static Boolean SplitBit(char *Asc, Byte *Erg)
BEGIN
   char *p;
   String Part;

   p=RQuotPos(Asc,'.');
   if (p==Nil) return False;
   *p='\0'; strmaxcpy(Part,p+1,255);

   if (strlen(Part)!=1) return False;
   else
    if ((*Part>='0') AND (*Part<='7'))
     BEGIN
      *Erg=(*Part)-'0'; return True;
     END
    else
     BEGIN
      for (*Erg=0; *Erg<Reg8Cnt; (*Erg)++)
       if (toupper(*Part)==Reg8Names[*Erg]) break;
      if (*Erg<Reg8Cnt)
       BEGIN
	*Erg+=8; return True;
       END
      else return False;
     END
END

	static Boolean DecodePseudo(void)
BEGIN
   return False;
END

	static void CodeMem(Byte Entry, Byte Opcode)
BEGIN
   BAsmCode[0]=Entry+AdrMode;
   memcpy(BAsmCode+1,AdrVals,AdrCnt);
   BAsmCode[1+AdrCnt]=Opcode;
END

	static void MakeCode_87C800(void)
BEGIN
   int z;
   Integer AdrInt,Condition;
   Byte HReg,HCnt,HMode,HVal;
   Boolean OK;

   CodeLen=0; DontPrint=False; OpSize=(-1);

   /* zu ignorierendes */

   if (Memo("")) return;

   /* Pseudoanweisungen */

   if (DecodePseudo()) return;

   if (DecodeIntelPseudo(False)) return;

   /* ohne Argument */

   for (z=0; z<FixedOrderCnt; z++)
    if (Memo(FixedOrders[z].Name))
     BEGIN
      if (ArgCnt!=0) WrError(1110);
      else
       BEGIN
        CodeLen=0;
        if (Hi(FixedOrders[z].Code)!=0) BAsmCode[CodeLen++]=Hi(FixedOrders[z].Code);
        BAsmCode[CodeLen++]=Lo(FixedOrders[z].Code);
       END
      return;
     END

   /* Datentransfer */

   if (Memo("LD"))
    BEGIN
     if (ArgCnt!=2) WrError(1110);
     else if (strcasecmp(ArgStr[1],"SP")==0)
      BEGIN
       OpSize=1;
       DecodeAdr(ArgStr[2],MModImm+MModReg16);
       switch (AdrType)
        BEGIN
         case ModReg16:
	  CodeLen=2; BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=0xfa;
	  break;
         case ModImm:
	  CodeLen=3; BAsmCode[0]=0xfa; memcpy(BAsmCode+1,AdrVals,AdrCnt);
	  break;
        END
      END
     else if (strcasecmp(ArgStr[2],"SP")==0)
      BEGIN
       DecodeAdr(ArgStr[1],MModReg16);
       switch (AdrType)
        BEGIN
         case ModReg16:
	  CodeLen=2; BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=0xfb;
	  break;
        END
      END
     else if (strcasecmp(ArgStr[1],"RBS")==0)
      BEGIN
       BAsmCode[1]=EvalIntExpression(ArgStr[2],Int4,&OK);
       if (OK)
	BEGIN
	 CodeLen=2; BAsmCode[0]=0x0f;
	END
      END
     else if (strcasecmp(ArgStr[1],"CF")==0)
      BEGIN
       if (NOT SplitBit(ArgStr[2],&HReg)) WrError(1510);
       else
	BEGIN
	 DecodeAdr(ArgStr[2],MModReg8+MModAbs+MModMem);
	 switch (AdrType)
          BEGIN
	   case ModReg8:
	    if (HReg>=8) WrError(1350);
	    else
	     BEGIN
	      CodeLen=2; BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=0xd8+HReg;
	     END
            break;
	   case ModAbs:
	    if (HReg>=8) WrError(1350);
	    else
	     BEGIN
	      CodeLen=2; BAsmCode[0]=0xd8+HReg; BAsmCode[1]=AdrVals[0];
	     END
            break;
	   case ModMem:
	    if (HReg<8)
	     BEGIN
	      CodeLen=2+AdrCnt;
	      CodeMem(0xe0,0xd8+HReg);
	     END
	    else if ((AdrMode!=2) AND (AdrMode!=3)) WrError(1350);
	    else
	     BEGIN
	      CodeLen=2; BAsmCode[0]=0xe0+HReg; BAsmCode[1]=0x9c+AdrMode;
	     END
            break;
	  END
	END
      END
     else if (strcasecmp(ArgStr[2],"CF")==0)
      BEGIN
       if (NOT SplitBit(ArgStr[1],&HReg)) WrError(1510);
       else
	BEGIN
	 DecodeAdr(ArgStr[1],MModReg8+MModAbs+MModMem);
	 switch (AdrType)
          BEGIN
	   case ModReg8:
	    if (HReg>=8) WrError(1350);
	    else
	     BEGIN
	      CodeLen=2; BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=0xc8+HReg;
	     END
            break;
	   case ModAbs:
           case ModMem:
	    if (HReg<8)
	     BEGIN
	      CodeLen=2+AdrCnt; CodeMem(0xe0,0xc8+HReg);
	     END
	    else if ((AdrMode!=2) AND (AdrMode!=3)) WrError(1350);
	    else
	     BEGIN
	      CodeLen=2; BAsmCode[0]=0xe0+HReg; BAsmCode[1]=0x98+AdrMode;
	     END
            break;
	  END
	END
      END
     else
      BEGIN
       DecodeAdr(ArgStr[1],MModReg8+MModReg16+MModAbs+MModMem);
       switch (AdrType)
        BEGIN
         case ModReg8:
	  HReg=AdrMode;
	  DecodeAdr(ArgStr[2],MModReg8+MModAbs+MModMem+MModImm);
	  switch (AdrType)
           BEGIN
	    case ModReg8:
	     if (HReg==AccReg)
	      BEGIN
	       CodeLen=1; BAsmCode[0]=0x50+AdrMode;
	      END
	     else if (AdrMode==AccReg)
	      BEGIN
	       CodeLen=1; BAsmCode[0]=0x58+HReg;
	      END
	     else
	      BEGIN
	       CodeLen=2; BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=0x58+HReg;
	      END
             break;
	    case ModAbs:
	     if (HReg==AccReg)
	      BEGIN
	       CodeLen=2; BAsmCode[0]=0x22; BAsmCode[1]=AdrVals[0];
	      END
	     else
	      BEGIN
	       CodeLen=3; BAsmCode[0]=0xe0; BAsmCode[1]=AdrVals[0];
	       BAsmCode[2]=0x58+HReg;
	      END
             break;
	    case ModMem:
	     if ((HReg==AccReg) AND (AdrMode==3))   /* A,(HL) */
	      BEGIN
	       CodeLen=1; BAsmCode[0]=0x23;
	      END
	     else
	      BEGIN
	       CodeLen=2+AdrCnt; CodeMem(0xe0,0x58+HReg);
	       if ((HReg>=6) AND (AdrMode==6)) WrError(140);
	      END
             break;
	    case ModImm:
	     CodeLen=2; BAsmCode[0]=0x30+HReg; BAsmCode[1]=AdrVals[0];
             break;
	   END
	  break;
         case ModReg16:
	  HReg=AdrMode;
	  DecodeAdr(ArgStr[2],MModReg16+MModAbs+MModMem+MModImm);
	  switch (AdrType)
           BEGIN
	    case ModReg16:
	     CodeLen=2; BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=0x14+HReg;
	     break;
	    case ModAbs:
	     CodeLen=3; BAsmCode[0]=0xe0; BAsmCode[1]=AdrVals[0];
	     BAsmCode[2]=0x14+HReg;
	     break;
	    case ModMem:
	     if (AdrMode>5) WrError(1350);   /* (-HL),(HL+) */
	     else
	      BEGIN
	       CodeLen=2+AdrCnt; BAsmCode[0]=0xe0+AdrMode;
	       memcpy(BAsmCode+1,AdrVals,AdrCnt);
               BAsmCode[1+AdrCnt]=0x14+HReg;
	      END
             break;
	    case ModImm:
	     CodeLen=3; BAsmCode[0]=0x14+HReg; memcpy(BAsmCode+1,AdrVals,2);
	     break;
	   END
	  break;
         case ModAbs:
	  HReg=AdrVals[0]; OpSize=0;
	  DecodeAdr(ArgStr[2],MModReg8+MModReg16+MModAbs+MModMem+MModImm);
	  switch (AdrType)
           BEGIN
	    case ModReg8:
	     if (AdrMode==AccReg)
	      BEGIN
	       CodeLen=2; BAsmCode[0]=0x2a; BAsmCode[1]=HReg;
	      END
	     else
	      BEGIN
	       CodeLen=3; BAsmCode[0]=0xf0; BAsmCode[1]=HReg;
	       BAsmCode[2]=0x50+AdrMode;
	      END
             break;
	    case ModReg16:
	     CodeLen=3; BAsmCode[0]=0xf0; BAsmCode[1]=HReg;
	     BAsmCode[2]=0x10+AdrMode;
	     break;
	    case ModAbs:
	     CodeLen=3; BAsmCode[0]=0x26; BAsmCode[1]=AdrVals[0];
	     BAsmCode[2]=HReg;
	     break;
	    case ModMem:
	     if (AdrMode>5) WrError(1350);      /* (-HL),(HL+) */
	     else
	      BEGIN
	       CodeLen=3+AdrCnt; BAsmCode[0]=0xe0+AdrMode;
	       memcpy(BAsmCode+1,AdrVals,AdrCnt); BAsmCode[1+AdrCnt]=0x26;
	       BAsmCode[2+AdrCnt]=HReg;
	      END
             break;
	    case ModImm:
	     CodeLen=3; BAsmCode[0]=0x2c; BAsmCode[1]=HReg;
	     BAsmCode[2]=AdrVals[0];
	     break;
	   END
	  break;
         case ModMem:
	  HVal=AdrVals[0]; HCnt=AdrCnt; HMode=AdrMode; OpSize=0;
	  DecodeAdr(ArgStr[2],MModReg8+MModReg16+MModAbs+MModMem+MModImm);
	  switch (AdrType)
           BEGIN
	    case ModReg8:
	     if ((HMode==3) AND (AdrMode==AccReg))   /* (HL),A */
	      BEGIN
	       CodeLen=1; BAsmCode[0]=0x2b;
	      END
	     else if ((HMode==1) OR (HMode==5)) WrError(1350);
	     else
	      BEGIN
	       CodeLen=2+HCnt; BAsmCode[0]=0xf0+HMode;
	       memcpy(BAsmCode+1,&HVal,HCnt);
               BAsmCode[1+HCnt]=0x50+AdrMode;
	       if ((HMode==6) AND (AdrMode>=6)) WrError(140);
	      END
             break;
	    case ModReg16:
	     if ((HMode<2) OR (HMode>4)) WrError(1350);  /* (HL),(DE),(HL+d) */
	     else
	      BEGIN
	       CodeLen=2+HCnt; BAsmCode[0]=0xf0+HMode;
	       memcpy(BAsmCode+1,&HVal,HCnt); BAsmCode[1+HCnt]=0x10+AdrMode;
	      END
             break;
	    case ModAbs:
	     if (HMode!=3) WrError(1350);  /* (HL) */
	     else
	      BEGIN
	       CodeLen=3; BAsmCode[0]=0xe0; BAsmCode[1]=AdrVals[0];
	       BAsmCode[2]=0x27;
	      END
             break;
	    case ModMem:
	     if (HMode!=3) WrError(1350);         /* (HL) */
	     else if (AdrMode>5) WrError(1350);   /* (-HL),(HL+) */
	     else
	      BEGIN
	       CodeLen=2+AdrCnt; BAsmCode[0]=0xe0+AdrMode;
	       memcpy(BAsmCode+1,AdrVals,AdrCnt); BAsmCode[1+AdrCnt]=0x27;
	      END
             break;
	    case ModImm:
	     if ((HMode==1) OR (HMode==5)) WrError(1350);  /* (HL+C),(PC+A) */
	     else if (HMode==3)               /* (HL) */
	      BEGIN
	       CodeLen=2; BAsmCode[0]=0x2d; BAsmCode[1]=AdrVals[0];
	      END
	     else
	      BEGIN
	       CodeLen=3+HCnt; BAsmCode[0]=0xf0+HMode;
	       memcpy(BAsmCode+1,&HVal,HCnt); BAsmCode[1+HCnt]=0x2c;
	       BAsmCode[2+HCnt]=AdrVals[0];
	      END
             break;
	   END
	  break;
        END
      END
     return;
    END

   if (Memo("XCH"))
    BEGIN
     if (ArgCnt!=2) WrError(1110);
     else
      BEGIN
       DecodeAdr(ArgStr[1],MModReg8+MModReg16+MModAbs+MModMem);
       switch (AdrType)
        BEGIN
         case ModReg8:
	  HReg=AdrMode;
	  DecodeAdr(ArgStr[2],MModReg8+MModAbs+MModMem);
	  switch (AdrType)
           BEGIN
	    case ModReg8:
	     CodeLen=2; BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=0xa8+HReg;
	     break;
	    case ModAbs:
            case ModMem:
	     CodeLen=2+AdrCnt; CodeMem(0xe0,0xa8+HReg);
	     if ((HReg>=6) AND (AdrMode==6)) WrError(140);
	     break;
	   END
	  break;
         case ModReg16:
	  HReg=AdrMode;
	  DecodeAdr(ArgStr[2],MModReg16);
	  if (AdrType!=ModNone)
	   BEGIN
	    CodeLen=2; BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=0x10+HReg;
	   END
	  break;
         case ModAbs:
	  BAsmCode[1]=AdrVals[0];
	  DecodeAdr(ArgStr[2],MModReg8);
	  if (AdrType!=ModNone)
	   BEGIN
	    CodeLen=3; BAsmCode[0]=0xe0; BAsmCode[2]=0xa8+AdrMode;
	   END
	  break;
         case ModMem:
	  BAsmCode[0]=0xe0+AdrMode; memcpy(BAsmCode+1,AdrVals,AdrCnt);
	  HReg=AdrCnt;
	  DecodeAdr(ArgStr[2],MModReg8);
	  if (AdrType!=ModNone)
	   BEGIN
	    CodeLen=2+HReg; BAsmCode[1+HReg]=0xa8+AdrMode;
	    if ((AdrMode>=6) AND ((BAsmCode[0] & 0x0f)==6)) WrError(140);
	   END
	  break;
        END
      END
     return;
    END

   if (Memo("CLR"))
    BEGIN
     if (ArgCnt!=1) WrError(1110);
     else if (strcasecmp(ArgStr[1],"CF")==0)
      BEGIN
       CodeLen=1; BAsmCode[0]=0x0c;
      END
     else if (SplitBit(ArgStr[1],&HReg))
      BEGIN
       DecodeAdr(ArgStr[1],MModReg8+MModAbs+MModMem);
       switch (AdrType)
        BEGIN
         case ModReg8:
	  if (HReg>=8) WrError(1350);
	  else
	   BEGIN
	    CodeLen=2; BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=0x48+HReg;
	   END
          break;
         case ModAbs:
	  if (HReg>=8) WrError(1350);
	  else
	   BEGIN
	    CodeLen=2; BAsmCode[0]=0x48+HReg; BAsmCode[1]=AdrVals[0];
	   END
          break;
         case ModMem:
	  if (HReg<=8)
	   BEGIN
	    CodeLen=2+AdrCnt; CodeMem(0xe0,0x48+HReg);
	   END
	  else if ((AdrMode!=2) AND (AdrMode!=3)) WrError(1350);
	  else
	   BEGIN
	    CodeLen=2; BAsmCode[0]=0xe0+HReg; BAsmCode[1]=0x88+AdrMode;
	   END
          break;
        END
      END
     else
      BEGIN
       DecodeAdr(ArgStr[1],MModReg8+MModReg16+MModAbs+MModMem);
       switch (AdrType)
        BEGIN
         case ModReg8:
	  CodeLen=2; BAsmCode[0]=0x30+AdrMode; BAsmCode[1]=0;
	  break;
         case ModReg16:
	  CodeLen=3; BAsmCode[0]=0x14+AdrMode; BAsmCode[1]=0; BAsmCode[2]=0;
	  break;
         case ModAbs:
	  CodeLen=2; BAsmCode[0]=0x2e; BAsmCode[1]=AdrVals[0];
	  break;
         case ModMem:
	  if ((AdrMode==5) OR (AdrMode==1)) WrError(1350);  /* (PC+A, HL+C) */
	  else if (AdrMode==3)     /* (HL) */
	   BEGIN
	    CodeLen=1; BAsmCode[0]=0x2f;
	   END
	  else
	   BEGIN
	    CodeLen=3+AdrCnt; BAsmCode[0]=0xf0+AdrMode;
	    memcpy(BAsmCode+1,AdrVals,AdrCnt);
	    BAsmCode[1+AdrCnt]=0x2c; BAsmCode[2+AdrCnt]=0;
	   END
          break;
        END
      END
     return;
    END

   if (Memo("LDW"))
    BEGIN
     if (ArgCnt!=2) WrError(1110);
     else
      BEGIN
       AdrInt=EvalIntExpression(ArgStr[2],Int16,&OK);
       if (OK)
	BEGIN
	 DecodeAdr(ArgStr[1],MModReg16+MModAbs+MModMem);
	 switch (AdrType)
          BEGIN
	   case ModReg16:
	    CodeLen=3; BAsmCode[0]=0x14+AdrMode;
	    BAsmCode[1]=AdrInt & 0xff; BAsmCode[2]=AdrInt >> 8;
	    break;
	   case ModAbs:
	    CodeLen=4; BAsmCode[0]=0x24; BAsmCode[1]=AdrVals[0];
	    BAsmCode[2]=AdrInt & 0xff; BAsmCode[3]=AdrInt >> 8;
	    break;
	   case ModMem:
	    if (AdrMode!=3) WrError(1350);  /* (HL) */
	    else
	     BEGIN
	      CodeLen=3; BAsmCode[0]=0x25;
	      BAsmCode[1]=AdrInt & 0xff; BAsmCode[2]=AdrInt >> 8;
	     END
	    break;
	  END
        END
      END
     return;
    END

   if ((Memo("PUSH")) OR (Memo("POP")))
    BEGIN
     HReg=Ord(Memo("PUSH"))+6;
     if (ArgCnt!=1) WrError(1110);
     else if (strcasecmp(ArgStr[1],"PSW")==0)
      BEGIN
       CodeLen=1; BAsmCode[0]=HReg;
      END
     else
      BEGIN
       DecodeAdr(ArgStr[1],MModReg16);
       if (AdrType!=ModNone)
	BEGIN
	 CodeLen=2; BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=HReg;
	END
      END
     return;
    END

   if ((Memo("TEST")) OR (Memo("CPL")) OR (Memo("SET")))
    BEGIN
     if (ArgCnt!=1) WrError(1110);
     else if (strcasecmp(ArgStr[1],"CF")==0)
      BEGIN
       if (Memo("TEST")) WrError(1350);
       else
	BEGIN
	 CodeLen=1; BAsmCode[0]=0x0d+Ord(Memo("CPL"));
	END
      END
     else if (NOT SplitBit(ArgStr[1],&HReg)) WrError(1510);
     else
      BEGIN
       if (Memo("TEST")) HVal=0xd8;
       else if (Memo("SET")) HVal=0x40;
       else HVal=0xc0;
       DecodeAdr(ArgStr[1],MModReg8+MModAbs+MModMem);
       switch (AdrType)
        BEGIN
         case ModReg8:
	  if (HReg>=8) WrError(1350);
	  else
	   BEGIN
	    CodeLen=2; BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=HVal+HReg;
	   END
          break;
         case ModAbs:
	  if (HReg>=8) WrError(1350);
	  else if (Memo("CPL"))
	   BEGIN
	    CodeLen=3; CodeMem(0xe0,HVal+HReg);
	   END
	  else
	   BEGIN
	    CodeLen=2; BAsmCode[0]=HVal+HReg; BAsmCode[1]=AdrVals[0];
	   END
          break;
         case ModMem:
	  if (HReg<8)
	   BEGIN
	    CodeLen=2+AdrCnt; CodeMem(0xe0,HVal+HReg);
	   END
	  else if ((AdrMode!=2) AND (AdrMode!=3)) WrError(1350);
	  else
	   BEGIN
	    CodeLen=2; BAsmCode[0]=0xe0+HReg;
	    BAsmCode[1]=((HVal & 0x18) >> 1)+((HVal & 0x80) >> 3)+0x80+AdrMode;
	   END
          break;
        END
      END
     return;
    END

   /* Arithmetik */

   for (z=0; z<RegOrderCnt; z++)
    if (Memo(RegOrders[z].Name))
     BEGIN
      if (ArgCnt!=1) WrError(1110);
      else
       BEGIN
        DecodeAdr(ArgStr[1],MModReg8);
        if (AdrType!=ModNone)
         if (AdrMode==AccReg)
          BEGIN
           CodeLen=1; BAsmCode[0]=RegOrders[z].Code;
          END
         else
          BEGIN
           CodeLen=2; BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=RegOrders[z].Code;
          END
       END
      return;
     END

   for (z=0; z<ALUOrderCnt; z++)
    if (Memo(ALUOrders[z]))
     BEGIN
      if (ArgCnt!=2) WrError(1110);
      else if (strcasecmp(ArgStr[1],"CF")==0)
       BEGIN
	if (NOT Memo("XOR")) WrError(1350);
	else if (NOT SplitBit(ArgStr[2],&HReg)) WrError(1510);
	else if (HReg>=8) WrError(1350);
	else
	 BEGIN
	  DecodeAdr(ArgStr[2],MModReg8+MModAbs+MModMem);
	  switch (AdrType)
           BEGIN
	    case ModReg8:
	     CodeLen=2; BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=0xd0+HReg;
	     break;
	    case ModAbs:
            case ModMem:
	     CodeLen=2+AdrCnt; CodeMem(0xe0,0xd0+HReg);
	     break;
	   END
	 END
       END
      else
       BEGIN
	DecodeAdr(ArgStr[1],MModReg8+MModReg16+MModMem+MModAbs);
	switch (AdrType)
         BEGIN
	  case ModReg8:
	   HReg=AdrMode;
	   DecodeAdr(ArgStr[2],MModReg8+MModMem+MModAbs+MModImm);
	   switch (AdrType)
            BEGIN
	     case ModReg8:
	      if (HReg==AccReg)
	       BEGIN
	        CodeLen=2;
	        BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=0x60+z;
	       END
	      else if (AdrMode==AccReg)
	       BEGIN
	        CodeLen=2;
	        BAsmCode[0]=0xe8+HReg; BAsmCode[1]=0x68+z;
	       END
	      else WrError(1350);
              break;
	     case ModMem:
	      if (HReg!=AccReg) WrError(1350);
	      else
	       BEGIN
	        CodeLen=2+AdrCnt; BAsmCode[0]=0xe0+AdrMode;
	        memcpy(BAsmCode+1,AdrVals,AdrCnt);
	        BAsmCode[1+AdrCnt]=0x78+z;
	       END
              break;
	     case ModAbs:
	      if (HReg!=AccReg) WrError(1350);
	      else
	       BEGIN
	        CodeLen=2; BAsmCode[0]=0x78+z; BAsmCode[1]=AdrVals[0];
	       END
              break;
	     case ModImm:
	      if (HReg==AccReg)
	       BEGIN
	        CodeLen=2; BAsmCode[0]=0x70+z; BAsmCode[1]=AdrVals[0];
	       END
	      else
	       BEGIN
	        CodeLen=3; BAsmCode[0]=0xe8+HReg;
	        BAsmCode[1]=0x70+z; BAsmCode[2]=AdrVals[0];
	       END
              break;
	    END
	   break;
	  case ModReg16:
	   HReg=AdrMode; DecodeAdr(ArgStr[2],MModImm+MModReg16);
	   switch (AdrType)
            BEGIN
	     case ModImm:
	      CodeLen=4; BAsmCode[0]=0xe8+HReg; BAsmCode[1]=0x38+z;
	      memcpy(BAsmCode+2,AdrVals,AdrCnt);
	      break;
	     case ModReg16:
	      if (HReg!=WAReg) WrError(1350);
	      else
	       BEGIN
	        CodeLen=2; BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=0x30+z;
	       END
	      break;
	    END
           break;
	  case ModAbs:
	   if (strcasecmp(ArgStr[2],"(HL)")==0)
	    BEGIN
	     CodeLen=3; BAsmCode[0]=0xe0;
	     BAsmCode[1]=AdrVals[0]; BAsmCode[2]=0x60+z;
	    END
	   else
	    BEGIN
	     BAsmCode[3]=EvalIntExpression(ArgStr[2],Int8,&OK);
	     if (OK)
	      BEGIN
	       CodeLen=4; BAsmCode[0]=0xe0;
	       BAsmCode[1]=AdrVals[0]; BAsmCode[2]=0x70+z;
	      END
	    END
	   break;
	  case ModMem:
	   if (strcasecmp(ArgStr[2],"(HL)")==0)
	    BEGIN
	     CodeLen=2+AdrCnt; BAsmCode[0]=0xe0+AdrMode;
	     memcpy(BAsmCode+1,AdrVals,AdrCnt); BAsmCode[1+AdrCnt]=0x60+z;
	    END
	   else
	    BEGIN
	     BAsmCode[2+AdrCnt]=EvalIntExpression(ArgStr[2],Int8,&OK);
	     if (OK)
	      BEGIN
	       CodeLen=3+AdrCnt; BAsmCode[0]=0xe0+AdrMode;
	       memcpy(BAsmCode+1,AdrVals,AdrCnt); BAsmCode[1+AdrCnt]=0x70+z;
	      END
	    END
	   break;
	 END
       END
      return;
     END

   if (Memo("MCMP"))
    BEGIN
     if (ArgCnt!=2) WrError(1110);
     else
      BEGIN
       HReg=EvalIntExpression(ArgStr[2],Int8,&OK);
       if (OK)
	BEGIN
	 DecodeAdr(ArgStr[1],MModMem+MModAbs);
	 if (AdrType!=ModNone)
	  BEGIN
	   CodeLen=3+AdrCnt; CodeMem(0xe0,0x2f); BAsmCode[2+AdrCnt]=HReg;
	  END
	END
      END
     return;
    END

   if ((Memo("DEC")) OR (Memo("INC")))
    BEGIN
     HReg=Ord(Memo("DEC")) << 3;
     if (ArgCnt!=1) WrError(1110);
     else
      BEGIN
       DecodeAdr(ArgStr[1],MModReg8+MModReg16+MModAbs+MModMem);
       switch (AdrType)
        BEGIN
         case ModReg8:
	  CodeLen=1; BAsmCode[0]=0x60+HReg+AdrMode;
	  break;
         case ModReg16:
	  CodeLen=1; BAsmCode[0]=0x10+HReg+AdrMode;
	  break;
         case ModAbs:
	  CodeLen=2; BAsmCode[0]=0x20+HReg; BAsmCode[1]=AdrVals[0];
	  break;
         case ModMem:
	  if (AdrMode==3)     /* (HL) */
	   BEGIN
	    CodeLen=1; BAsmCode[0]=0x21+HReg;
	   END
	  else
	   BEGIN
	    CodeLen=2+AdrCnt; BAsmCode[0]=0xe0+AdrMode;
	    memcpy(BAsmCode+1,AdrVals,AdrCnt); BAsmCode[1+AdrCnt]=0x20+HReg;
	   END
          break;
        END
      END
     return;
    END

   if (Memo("MUL"))
    BEGIN
     if (ArgCnt!=2) WrError(1110);
     else
      BEGIN
       DecodeAdr(ArgStr[1],MModReg8);
       if (AdrType==ModReg8)
	BEGIN
	 HReg=AdrMode;
	 DecodeAdr(ArgStr[2],MModReg8);
	 if (AdrType==ModReg8)
	  if ((HReg ^ AdrMode)!=1) WrError(1760);
	  else
	   BEGIN
	    HReg=HReg >> 1;
	    if (HReg==0)
	     BEGIN
	      CodeLen=1; BAsmCode[0]=0x02;
	     END
	    else
	     BEGIN
	      CodeLen=2; BAsmCode[0]=0xe8+HReg; BAsmCode[1]=0x02;
	     END
	   END
	END
      END
     return;
    END

   if (Memo("DIV"))
    BEGIN
     if (ArgCnt!=2) WrError(1110);
     else
      BEGIN
       DecodeAdr(ArgStr[1],MModReg16);
       if (AdrType==ModReg16)
	BEGIN
	 HReg=AdrMode;
	 DecodeAdr(ArgStr[2],MModReg8);
	 if (AdrType==ModReg8)
	  if (AdrMode!=2) WrError(1350);  /* C */
	  else if (HReg==0)
	   BEGIN
	    CodeLen=1; BAsmCode[0]=0x03;
	   END
	  else
	   BEGIN
	    CodeLen=2; BAsmCode[0]=0xe8+HReg; BAsmCode[1]=0x03;
	    if (HReg==1) WrError(140);
	   END
	END
      END
     return;
    END

   if ((Memo("ROLD")) OR (Memo("RORD")))
    BEGIN
     if (ArgCnt!=2) WrError(1110);
     else if (strcasecmp(ArgStr[1],"A")!=0) WrError(1350);
     else
      BEGIN
       HReg=Ord(Memo("RORD"))+8;
       DecodeAdr(ArgStr[2],MModAbs+MModMem);
       if (AdrType!=ModNone)
	BEGIN
	 CodeLen=2+AdrCnt; CodeMem(0xe0,HReg);
	 if (AdrMode==1) WrError(140);
	END
      END
     return;
    END

   /* Spruenge */

   if (Memo("JRS"))
    BEGIN
     if (ArgCnt!=2) WrError(1110);
     else
      BEGIN
       NLS_UpString(ArgStr[1]);
       for (Condition=ConditionCnt-2; Condition<ConditionCnt; Condition++)
        if (strcmp(ArgStr[1],Conditions[Condition].Name)==0) break;
       if (Condition>=ConditionCnt) WrXError(1360,ArgStr[1]);
       else
	BEGIN
	 AdrInt=EvalIntExpression(ArgStr[2],Int16,&OK)-(EProgCounter()+2);
	 if (OK)
	  if (((AdrInt<-16) OR (AdrInt>15)) AND (NOT SymbolQuestionable)) WrError(1370);
	  else
	   BEGIN
	    CodeLen=1;
	    BAsmCode[0]=((Conditions[Condition].Code-2) << 5)+(AdrInt & 0x1f);
	   END
	END
      END
     return;
    END

   if (Memo("JR"))
    BEGIN
     if ((ArgCnt!=2) AND (ArgCnt!=1)) WrError(1110);
     else
      BEGIN
       if (ArgCnt==1) Condition=(-1);
       else
	BEGIN
         NLS_UpString(ArgStr[1]);
	 for (Condition=0; Condition<ConditionCnt; Condition++)
          if (strcmp(ArgStr[1],Conditions[Condition].Name)==0) break;
        END
       if (Condition>=ConditionCnt) WrXError(1360,ArgStr[1]);
       else
	BEGIN
	 AdrInt=EvalIntExpression(ArgStr[2],Int16,&OK)-(EProgCounter()+2);
	 if (OK)
	  if (((AdrInt<-128) OR (AdrInt>127)) AND (NOT SymbolQuestionable)) WrError(1370);
	  else
	   BEGIN
	    CodeLen=2;
	    if (Condition==-1) BAsmCode[0]=0xfb;
	    else BAsmCode[0]=0xd0+Conditions[Condition].Code;
	    BAsmCode[1]=AdrInt & 0xff;
	   END
	END
      END
     return;
    END

   if ((Memo("JP")) OR (Memo("CALL")))
    BEGIN
     if (ArgCnt!=1) WrError(1110);
     else
      BEGIN
       OpSize=1; HReg=0xfc+2*Ord(Memo("JP"));
       DecodeAdr(ArgStr[1],MModReg16+MModAbs+MModMem+MModImm);
       switch (AdrType)
        BEGIN
         case ModReg16:
	  CodeLen=2; BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=HReg;
	  break;
         case ModAbs:
	  CodeLen=3; BAsmCode[0]=0xe0; BAsmCode[1]=AdrVals[0];
	  BAsmCode[2]=HReg;
	  break;
         case ModMem:
	  if (AdrMode>5) WrError(1350);
	  else
	   BEGIN
	    CodeLen=2+AdrCnt; BAsmCode[0]=0xe0+AdrMode;
	    memcpy(BAsmCode+1,AdrVals,AdrCnt); BAsmCode[1+AdrCnt]=HReg;
	   END
          break;
         case ModImm:
	  if ((AdrVals[1]==0xff) AND (Memo("CALL")))
	   BEGIN
	    CodeLen=2; BAsmCode[0]=0xfd; BAsmCode[1]=AdrVals[0];
	   END
	  else
	   BEGIN
	    CodeLen=3; BAsmCode[0]=HReg; memcpy(BAsmCode+1,AdrVals,AdrCnt);
	   END
          break;
        END
      END
     return;
    END

   if (Memo("CALLV"))
    BEGIN
     if (ArgCnt!=1) WrError(1110);
     else
      BEGIN
       HVal=EvalIntExpression(ArgStr[1],Int4,&OK);
       if (OK)
	BEGIN
	 CodeLen=1; BAsmCode[0]=0xc0+(HVal & 15);
	END
      END
     return;
    END

   if (Memo("CALLP"))
    BEGIN
     if (ArgCnt!=1) WrError(1110);
     else
      BEGIN
       AdrInt=EvalIntExpression(ArgStr[1],Int16,&OK);
       if (OK)
	if ((Hi(AdrInt)!=0xff) AND (Hi(AdrInt)!=0)) WrError(1320);
	else
	 BEGIN
	  CodeLen=2; BAsmCode[0]=0xfd; BAsmCode[1]=Lo(AdrInt);
	 END
      END
     return;
    END

   WrXError(1200,OpPart);
END

	static Boolean IsDef_87C800(void)
BEGIN
   return False;
END

        static void SwitchFrom_87C800(void)
BEGIN
   DeinitFields();
END

	static void SwitchTo_87C800(void)
BEGIN
   TurnWords=False; ConstMode=ConstModeIntel; SetIsOccupied=True;

   PCSymbol="$"; HeaderID=0x54; NOPCode=0x00;
   DivideChars=","; HasAttrs=False;

   ValidSegs=1<<SegCode;
   Grans[SegCode]=1; ListGrans[SegCode]=1; SegInits[SegCode]=0;
   SegLimits[SegCode] = 0xffff;

   MakeCode=MakeCode_87C800; IsDef=IsDef_87C800;
   SwitchFrom=SwitchFrom_87C800; InitFields();
END

	void code87c800_init(void)
BEGIN
   CPU87C00=AddCPU("87C00",SwitchTo_87C800);
   CPU87C20=AddCPU("87C20",SwitchTo_87C800);
   CPU87C40=AddCPU("87C40",SwitchTo_87C800);
   CPU87C70=AddCPU("87C70",SwitchTo_87C800);
END
