/* code90c141.c */
/*****************************************************************************/
/* AS-Portierung                                                             */
/*                                                                           */
/* Codegenerator Toshiba TLCS-90                                             */
/*                                                                           */
/* Historie: 30.10.1996 Grundsteinlegung                                     */
/*            2. 1.1999 ChkPC umgebaut                                       */
/*                                                                           */
/*****************************************************************************/

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

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


typedef struct
         { 
          Byte Code;
         } FixedOrder;

typedef struct
         { 
          Byte Code;
          Boolean MayReg;
         } ShiftOrder;

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


#define AccReg 6
#define HLReg 2

#define FixedOrderCnt 18
#define MoveOrderCnt 8
#define ShiftOrderCnt 10
#define BitOrderCnt 4
#define AccOrderCnt 3
#define ALU2OrderCnt 8
#define ConditionCnt 24

#define ModNone (-1)
#define ModReg8    0
#define MModReg8   (1 << ModReg8)
#define ModReg16   1
#define MModReg16  (1 << ModReg16)
#define ModIReg16  2
#define MModIReg16 (1 << ModIReg16)
#define ModIndReg  3
#define MModIndReg (1 << ModIndReg)
#define ModIdxReg  4
#define MModIdxReg (1 << ModIdxReg)
#define ModDir     5
#define MModDir    (1 << ModDir)
#define ModMem     6
#define MModMem    (1 << ModMem)
#define ModImm     7
#define MModImm    (1 << ModImm)

static int DefaultCondition;

static ShortInt AdrType;
static Byte AdrMode;
static ShortInt OpSize;
static Byte AdrVals[10];
static Boolean MinOneIs0;

static FixedOrder *FixedOrders;
static FixedOrder *MoveOrders;
static ShiftOrder *ShiftOrders;
static FixedOrder *BitOrders;
static FixedOrder *AccOrders;
static char **ALU2Orders;
static Condition *Conditions;
static PInstTreeNode ITree;

static CPUVar CPU90C141;

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

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

	static void SetOpSize(ShortInt New)
BEGIN
   if (OpSize==-1) OpSize=New;
   else if (OpSize!=New)
    BEGIN
     WrError(1131); AdrType=ModNone; AdrCnt=0;
    END
END

	static void DecodeAdr(char *Asc, Byte Erl)
BEGIN
#define Reg8Cnt 7
   static char *Reg8Names[Reg8Cnt]={"B","C","D","E","H","L","A"};
#define Reg16Cnt 7
   static char *Reg16Names[Reg16Cnt]={"BC","DE","HL","\0","IX","IY","SP"};
#define IReg16Cnt 3
   static char *IReg16Names[IReg16Cnt]={"IX","IY","SP"};

   int z;
   char *p,*ppos,*mpos;
   LongInt DispAcc,DispVal;
   Byte OccFlag,BaseReg;
   Boolean ok,fnd,NegFlag,NNegFlag,Unknown;
   String Part;

   AdrType=ModNone; AdrCnt=0;

   /* 1. 8-Bit-Register */

   for (z=0; z<Reg8Cnt; z++)
    if (strcasecmp(Asc,Reg8Names[z])==0)
     BEGIN
      AdrType=ModReg8; AdrMode=z; SetOpSize(0);
      ChkAdr(Erl); return;
     END

   /* 2. 16-Bit-Register, indiziert */

   if ((Erl & MModIReg16)!=0)
    for (z=0; z<IReg16Cnt; z++)
     if (strcasecmp(Asc,IReg16Names[z])==0)
      BEGIN
       AdrType=ModIReg16; AdrMode=z; SetOpSize(1);
       ChkAdr(Erl); return;
      END

   /* 3. 16-Bit-Register, normal */

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

   /* Speicheradresse */

   if (IsIndirect(Asc))
    BEGIN
     OccFlag=0; BaseReg=0; DispAcc=0; ok=True; NegFlag=False; Unknown=False;
     strcpy(Asc,Asc+1); Asc[strlen(Asc)-1]='\0';
     do
      BEGIN
       ppos=QuotPos(Asc,'+');
       mpos=QuotPos(Asc,'-');
       if (ppos==Nil) p=mpos; 
       else if (mpos==Nil) p=ppos;
       else p=min(mpos,ppos);
       NNegFlag=((p!=Nil) AND (*p=='-')); 
       if (p==Nil)
        BEGIN
         strmaxcpy(Part,Asc,255); *Asc='\0';
        END
       else
        BEGIN
         *p='\0'; strmaxcpy(Part,Asc,255); strcpy(Asc,p+1);
        END
       fnd=False;
       if (strcasecmp(Part,"A")==0)
        BEGIN
 	 fnd=True;
	 ok=((NOT NegFlag) AND ((OccFlag & 1)==0));
	 if (ok) OccFlag+=1; else WrError(1350);
        END
       if (NOT fnd)
        for (z=0; z<Reg16Cnt; z++)
	 if (strcasecmp(Part,Reg16Names[z])==0)
	  BEGIN
	   fnd=True; BaseReg=z;
	   ok=((NOT NegFlag) AND ((OccFlag & 2)==0));
	   if (ok) OccFlag+=2; else WrError(1350);
	  END
       if (NOT fnd)
        BEGIN
	 FirstPassUnknown=False;
	 DispVal=EvalIntExpression(Part,Int32,&ok);
	 if (ok)
	  BEGIN
	   if (NegFlag) DispAcc-=DispVal; else DispAcc+=DispVal;
	   if (FirstPassUnknown) Unknown=True;
	  END
        END
       NegFlag=NNegFlag;
      END
     while ((*Asc!='\0') AND (ok));
     if (NOT ok) return;
     if (Unknown) DispAcc&=0x7f;
     switch (OccFlag)
      BEGIN
       case 1:
        WrError(1350); break;
       case 3:
        if ((BaseReg!=2) OR (DispAcc!=0)) WrError(1350);
        else
 	 BEGIN
	  AdrType=ModIdxReg; AdrMode=3;
	 END
        break;
       case 2:
        if ((DispAcc>127) OR (DispAcc<-128)) WrError(1320);
        else if (DispAcc==0)
	 BEGIN
	  AdrType=ModIndReg; AdrMode=BaseReg;
 	 END
        else if (BaseReg<4) WrError(1350);
        else
 	 BEGIN
	  AdrType=ModIdxReg; AdrMode=BaseReg-4;
	  AdrCnt=1; AdrVals[0]=DispAcc & 0xff;
	 END
        break;
       case 0:
        if (DispAcc>0xffff) WrError(1925);
        else if ((Hi(DispAcc)==0xff) AND ((Erl & MModDir)!=0))
	 BEGIN
	  AdrType=ModDir; AdrCnt=1; AdrVals[0]=Lo(DispAcc);
	 END
        else
	 BEGIN
	  AdrType=ModMem; AdrCnt=2;
          AdrVals[0]=Lo(DispAcc); AdrVals[1]=Hi(DispAcc);
	 END
        break;
      END
    END

   /* immediate */

   else
    BEGIN
     if ((OpSize==-1) AND (MinOneIs0)) OpSize=0;
     switch (OpSize)
      BEGIN
       case -1:
        WrError(1130); break;
       case 0:
	AdrVals[0]=EvalIntExpression(Asc,Int8,&ok);
	if (ok)
	 BEGIN
	  AdrType=ModImm; AdrCnt=1;
	 END
        break;
       case 1:
	DispVal=EvalIntExpression(Asc,Int16,&ok);
	if (ok)
	 BEGIN
	  AdrType=ModImm; AdrCnt=2;
	  AdrVals[0]=Lo(DispVal); AdrVals[1]=Hi(DispVal);
	 END
        break;
      END
    END

   /* gefunden */

   ChkAdr(Erl);
END

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

	static Boolean DecodePseudo(void)
BEGIN
   return False;
END

	static Boolean WMemo(char *Name)
BEGIN
   String tmp;

   if (Memo(Name)) return True;

   sprintf(tmp,"%sW",Name);
   if (Memo(tmp))
    BEGIN
     OpSize=1; return True;
    END
   else return False;
END

	static Boolean ArgPair(char *Arg1, char *Arg2)
BEGIN
   return  (((strcasecmp(ArgStr[1],Arg1)==0) AND (strcasecmp(ArgStr[2],Arg2)==0))
	 OR ((strcasecmp(ArgStr[1],Arg2)==0) AND (strcasecmp(ArgStr[2],Arg1)==0)));
END

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

/* ohne Argument */

	static void CodeFixed(Word Index)
BEGIN
   if (ArgCnt!=0) WrError(1110);
   else
    BEGIN
     CodeLen=1; BAsmCode[0]=FixedOrders[Index].Code;
    END
END

        static void CodeMove(Word Index)
BEGIN
   if (ArgCnt!=0) WrError(1110);
   else
    BEGIN
     CodeLen=2; BAsmCode[0]=0xfe; BAsmCode[1]=MoveOrders[Index].Code;
    END
END

        static void CodeShift(Word Index)
BEGIN
   if (ArgCnt!=1) WrError(1110);
   else
    BEGIN
     DecodeAdr(ArgStr[1],((ShiftOrders[Index].MayReg)?MModReg8:0)+MModIndReg+MModIdxReg+MModMem+MModDir);
     switch (AdrType)
      BEGIN
       case ModReg8:
        CodeLen=2; BAsmCode[0]=0xf8+AdrMode; BAsmCode[1]=ShiftOrders[Index].Code;
        if (AdrMode==AccReg) WrError(10);
        break;
       case ModIndReg:
        CodeLen=2; BAsmCode[0]=0xe0+AdrMode; BAsmCode[1]=ShiftOrders[Index].Code;
        break;
       case ModIdxReg:
        CodeLen=2+AdrCnt; BAsmCode[0]=0xf0+AdrMode;
        memcpy(BAsmCode+1,AdrVals,AdrCnt); BAsmCode[1+AdrCnt]=ShiftOrders[Index].Code;
        break;
       case ModDir:
        CodeLen=3; BAsmCode[0]=0xe7; BAsmCode[1]=AdrVals[0];
        BAsmCode[2]=ShiftOrders[Index].Code;
        break;
       case ModMem:
        CodeLen=4; BAsmCode[0]=0xe3;
        memcpy(BAsmCode+1,AdrVals,AdrCnt);
        BAsmCode[3]=ShiftOrders[Index].Code;
        break;
      END
    END
END

/* Logik */

        static void CodeBit(Word Index)
BEGIN
   Byte HReg;
   Boolean OK;

   if (ArgCnt!=2) WrError(1110);
   else
    BEGIN
     HReg=EvalIntExpression(ArgStr[1],UInt3,&OK);
     if (OK)
      BEGIN
       DecodeAdr(ArgStr[2],MModReg8+MModIndReg+MModIdxReg+MModMem+MModDir);
       switch (AdrType)
        BEGIN
         case ModReg8:
          CodeLen=2;
          BAsmCode[0]=0xf8+AdrMode; BAsmCode[1]=BitOrders[Index].Code+HReg;
          break;
         case ModIndReg:
          CodeLen=2;
          BAsmCode[0]=0xe0+AdrMode; BAsmCode[1]=BitOrders[Index].Code+HReg;
          break;
         case ModIdxReg:
          CodeLen=2+AdrCnt; memcpy(BAsmCode+1,AdrVals,AdrCnt);
          BAsmCode[0]=0xf0+AdrMode; BAsmCode[1+AdrCnt]=BitOrders[Index].Code+HReg;
          break;
         case ModMem:
          CodeLen=4; memcpy(BAsmCode+1,AdrVals,AdrCnt);
          BAsmCode[0]=0xe3; BAsmCode[1+AdrCnt]=BitOrders[Index].Code+HReg;
          break;
         case ModDir:
          BAsmCode[1]=AdrVals[0];
          if (Index==4)
           BEGIN
            BAsmCode[0]=0xe7; BAsmCode[2]=BitOrders[Index].Code+HReg; CodeLen=3;
           END
          else
           BEGIN
            BAsmCode[0]=BitOrders[Index].Code+HReg; CodeLen=2;
           END
          break;
        END
      END
    END
END

        static void CodeAcc(Word Index)
BEGIN
   if (ArgCnt!=1) WrError(1110);
   else if (strcasecmp(ArgStr[1],"A")!=0) WrError(1350);
   else
    BEGIN
     CodeLen=1; BAsmCode[0]=AccOrders[Index].Code;
    END
END

        static void MakeCode_90C141(void)
BEGIN
   int z;
   Integer AdrInt;
   Boolean OK;
   Byte HReg;

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

   /* zu ignorierendes */

   if (Memo("")) return;

   /* Pseudoanweisungen */

   if (DecodePseudo()) return;

   if (DecodeIntelPseudo(False)) return;

   if (SearchInstTree(ITree,OpPart)) return;

   /* Datentransfer */

   if (WMemo("LD"))
    BEGIN
     if (ArgCnt!=2) WrError(1110);
     else
      BEGIN
       DecodeAdr(ArgStr[1],MModReg8+MModReg16+MModIndReg+MModIdxReg+MModDir+MModMem);
       switch (AdrType)
        BEGIN
         case ModReg8:
	  HReg=AdrMode;
	  DecodeAdr(ArgStr[2],MModReg8+MModIndReg+MModIdxReg+MModDir+MModMem+MModImm);
	  switch (AdrType)
           BEGIN
	    case ModReg8:
	     if (HReg==AccReg)
	      BEGIN
	       CodeLen=1; BAsmCode[0]=0x20+AdrMode;
	      END
	     else if (AdrMode==AccReg)
	      BEGIN
	       CodeLen=1; BAsmCode[0]=0x28+HReg;
	      END
	     else
	      BEGIN
	       CodeLen=2; BAsmCode[0]=0xf8+AdrMode; BAsmCode[1]=0x30+HReg;
	      END
             break;
	    case ModIndReg:
	     CodeLen=2; BAsmCode[0]=0xe0+AdrMode; BAsmCode[1]=0x28+HReg;
	     break;
	    case ModIdxReg:
	     CodeLen=2+AdrCnt; BAsmCode[0]=0xf0+AdrMode;
	     memcpy(BAsmCode+1,AdrVals,AdrCnt); BAsmCode[1+AdrCnt]=0x28+HReg;
	     break;
	    case ModDir:
	     if (HReg==AccReg)
	      BEGIN
	       CodeLen=2; BAsmCode[0]=0x27; BAsmCode[1]=AdrVals[0];
	      END
	     else
	      BEGIN
	       CodeLen=3; BAsmCode[0]=0xe7; BAsmCode[1]=AdrVals[0];
	       BAsmCode[2]=0x28+HReg;
	      END
             break;
	    case ModMem:
	     CodeLen=4; BAsmCode[0]=0xe3;
	     memcpy(BAsmCode+1,AdrVals,AdrCnt); BAsmCode[3]=0x28+HReg;
	     break;
	    case ModImm:
	     CodeLen=2; BAsmCode[0]=0x30+HReg; BAsmCode[1]=AdrVals[0];
	     break;
	   END
	  break;
         case ModReg16:
	  HReg=AdrMode;
	  DecodeAdr(ArgStr[2],MModReg16+MModIndReg+MModIdxReg+MModDir+MModMem+MModImm);
	  switch (AdrType)
           BEGIN
	    case ModReg16:
	     if (HReg==HLReg)
	      BEGIN
	       CodeLen=1; BAsmCode[0]=0x40+AdrMode;
	      END
	     else if (AdrMode==HLReg)
	      BEGIN
	       CodeLen=1; BAsmCode[0]=0x48+HReg;
	      END
	     else
	      BEGIN
	       CodeLen=2; BAsmCode[0]=0xf8+AdrMode; BAsmCode[1]=0x38+HReg;
	      END
             break;
	    case ModIndReg:
	     CodeLen=2;
	     BAsmCode[0]=0xe0+AdrMode; BAsmCode[1]=0x48+HReg;
	     break;
	    case ModIdxReg:
	     CodeLen=2+AdrCnt; BAsmCode[0]=0xf0+AdrMode;
	     memcpy(BAsmCode+1,AdrVals,AdrCnt); BAsmCode[1+AdrCnt]=0x48+HReg;
	     break;
	    case ModDir:
	     if (HReg==HLReg)
	      BEGIN
	       CodeLen=2; BAsmCode[0]=0x47; BAsmCode[1]=AdrVals[0];
	      END
	     else
	      BEGIN
	       CodeLen=3; BAsmCode[0]=0xe7; BAsmCode[1]=AdrVals[0];
	       BAsmCode[2]=0x48+HReg;
	      END
             break;
	    case ModMem:
	     CodeLen=4; BAsmCode[0]=0xe3; BAsmCode[3]=0x48+HReg;
	     memcpy(BAsmCode+1,AdrVals,AdrCnt);
	     break;
            case ModImm:
             CodeLen=3; BAsmCode[0]=0x38+HReg;
             memcpy(BAsmCode+1,AdrVals,AdrCnt);
             break;
	   END
	  break;
         case ModIndReg:
         case ModIdxReg:
         case ModDir:
         case ModMem:
	  MinOneIs0=True; HReg=AdrCnt; memcpy(BAsmCode+1,AdrVals,AdrCnt);
	  switch (AdrType)
           BEGIN
	    case ModIndReg: BAsmCode[0]=0xe8+AdrMode; break;
	    case ModIdxReg: BAsmCode[0]=0xf4+AdrMode; break;
	    case ModMem:    BAsmCode[0]=0xeb; break;
	    case ModDir:    BAsmCode[0]=0x0f; break;
	   END
	  DecodeAdr(ArgStr[2],MModReg16+MModReg8+MModImm);
	  if (BAsmCode[0]==0x0f)
	   switch (AdrType)
            BEGIN
	     case ModReg8:
	      if (AdrMode==AccReg)
	       BEGIN
	        CodeLen=2; BAsmCode[0]=0x2f;
	       END
	      else
	       BEGIN
	        CodeLen=3; BAsmCode[0]=0xef; BAsmCode[2]=0x20+AdrMode;
	       END
              break;
	     case ModReg16:
	      if (AdrMode==HLReg)
	       BEGIN
	        CodeLen=2; BAsmCode[0]=0x4f;
	       END
	      else
	       BEGIN
	        CodeLen=3; BAsmCode[0]=0xef; BAsmCode[2]=0x40+AdrMode;
	       END
              break;
	     case ModImm:
	      CodeLen=3+OpSize; BAsmCode[0]=0x37+(OpSize << 3);
	      memcpy(BAsmCode+2,AdrVals,AdrCnt);
	      break;
	    END
	   else
	    BEGIN
	     switch (AdrType)
              BEGIN
	       case ModReg8:  BAsmCode[1+HReg]=0x20+AdrMode; break;
	       case ModReg16: BAsmCode[1+HReg]=0x40+AdrMode; break;
	       case ModImm:   BAsmCode[1+HReg]=0x37+(OpSize << 3); break;
	      END
	     memcpy(BAsmCode+2+HReg,AdrVals,AdrCnt);
	     CodeLen=1+HReg+1+AdrCnt;
	    END
	  break;
        END
      END
     return;
    END

   if ((Memo("PUSH")) OR (Memo("POP")))
    BEGIN
     if (ArgCnt!=1) WrError(1110);
     else
      BEGIN
       HReg=Ord(Memo("POP")) << 3;
       if (strcasecmp(ArgStr[1],"AF")==0)
	BEGIN
	 CodeLen=1; BAsmCode[0]=0x56+HReg;
	END
       else
	BEGIN
	 DecodeAdr(ArgStr[1],MModReg16);
	 if (AdrType==ModReg16)
	  if (AdrMode==6) WrError(1350);
	  else
	   BEGIN
	    CodeLen=1; BAsmCode[0]=0x50+HReg+AdrMode;
	   END
	END
      END
     return;
    END

   if (Memo("LDA"))
    BEGIN
     if (ArgCnt!=2) WrError(1110);
     else
      BEGIN
       DecodeAdr(ArgStr[1],MModReg16);
       if (AdrType==ModReg16)
	BEGIN
	 HReg=0x38+AdrMode;
	 DecodeAdr(ArgStr[2],MModIndReg+MModIdxReg);
	 switch (AdrType)
          BEGIN
	   case ModIndReg:
	    if (AdrMode<4) WrError(1350);
	    else
	     BEGIN
	      CodeLen=3; BAsmCode[0]=0xf0+AdrMode;
	      BAsmCode[1]=0; BAsmCode[2]=HReg;
	     END
            break;
	   case ModIdxReg:
	    CodeLen=2+AdrCnt; BAsmCode[0]=0xf4+AdrMode;
	    memcpy(BAsmCode+1,AdrVals,AdrCnt); BAsmCode[1+AdrCnt]=HReg;
	    break;
	  END
	END
      END
     return;
    END

   if (Memo("LDAR"))
    BEGIN
     if (ArgCnt!=2) WrError(1110);
     else if (strcasecmp(ArgStr[1],"HL")!=0) WrError(1350);
     else
      BEGIN
       AdrInt=EvalIntExpression(ArgStr[2],Int16,&OK)-(EProgCounter()+2);
       if (OK)
	BEGIN
	 CodeLen=3; BAsmCode[0]=0x17;
	 BAsmCode[1]=Lo(AdrInt); BAsmCode[2]=Hi(AdrInt);
	END
      END
     return;
    END

   if (Memo("EX"))
    BEGIN
     if (ArgCnt!=2) WrError(1110);
     else if (ArgPair("DE","HL"))
      BEGIN
       CodeLen=1; BAsmCode[0]=0x08;
      END
     else if ((ArgPair("AF","AF\'") OR ArgPair("AF","AF`")))
      BEGIN
       CodeLen=1; BAsmCode[0]=0x09;
      END
     else
      BEGIN
       DecodeAdr(ArgStr[1],MModReg16+MModIndReg+MModIdxReg+MModMem+MModDir);
       switch (AdrType)
        BEGIN
         case ModReg16:
	  HReg=0x50+AdrMode;
	  DecodeAdr(ArgStr[2],MModIndReg+MModIdxReg+MModMem+MModDir);
	  switch (AdrType)
           BEGIN
	    case ModIndReg:
	     CodeLen=2; BAsmCode[0]=0xe0+AdrMode; BAsmCode[1]=HReg;
	     break;
	    case ModIdxReg:
	     CodeLen=2+AdrCnt; BAsmCode[0]=0xf0+AdrMode;
	     memcpy(BAsmCode+1,AdrVals,AdrCnt);
	     BAsmCode[1+AdrCnt]=HReg;
	     break;
	    case ModDir:
	     CodeLen=3; BAsmCode[0]=0xe7; BAsmCode[1]=AdrVals[0];
	     BAsmCode[2]=HReg;
	     break;
	    case ModMem:
	     CodeLen=4; BAsmCode[0]=0xe3; memcpy(BAsmCode+1,AdrVals,AdrCnt);
	     BAsmCode[3]=HReg;
	     break;
 	   END
	  break;
         case ModIndReg:
         case ModIdxReg:
         case ModDir:
         case ModMem:
 	  switch (AdrType)
           BEGIN
 	    case ModIndReg:  BAsmCode[0]=0xe0+AdrMode; break;
	    case ModIdxReg:  BAsmCode[0]=0xf0+AdrMode; break;
	    case ModDir:     BAsmCode[0]=0xe7; break;
	    case ModMem:     BAsmCode[0]=0xe3; break;
	   END
	  memcpy(BAsmCode+1,AdrVals,AdrCnt); HReg=2+AdrCnt;
	  DecodeAdr(ArgStr[2],MModReg16);
	  if (AdrType==ModReg16)
	   BEGIN
	    BAsmCode[HReg-1]=0x50+AdrMode; CodeLen=HReg;
	   END
	  break;
        END
      END
     return;
    END

   /* Arithmetik */

   for (z=0; z<ALU2OrderCnt; z++)
    if (Memo(ALU2Orders[z]))
     BEGIN
      if (ArgCnt!=2) WrError(1110);
      else
       BEGIN
	DecodeAdr(ArgStr[1],MModReg8+MModReg16+MModIdxReg+MModIndReg+MModDir+MModMem);
	switch (AdrType)
         BEGIN
	  case ModReg8:
           DecodeAdr(ArgStr[2],MModImm+(((HReg=AdrMode)==AccReg)?MModReg8+MModIndReg+MModIdxReg+MModDir+MModMem:0));
	   switch(AdrType)
            BEGIN
	     case ModReg8:
	      CodeLen=2;
	      BAsmCode[0]=0xf8+AdrMode; BAsmCode[1]=0x60+z;
	      break;
	     case ModIndReg:
	      CodeLen=2;
	      BAsmCode[0]=0xe0+AdrMode; BAsmCode[1]=0x60+z;
	      break;
	     case ModIdxReg:
	      CodeLen=2+AdrCnt;
	      BAsmCode[0]=0xf0+AdrMode;
	      memcpy(BAsmCode+1,AdrVals,AdrCnt);
	      BAsmCode[1+AdrCnt]=0x60+z;
	      break;
	     case ModDir:
	      CodeLen=2;
	      BAsmCode[0]=0x60+z;
	      BAsmCode[1]=AdrVals[0];
	      break;
	     case ModMem:
	      CodeLen=4;
	      BAsmCode[0]=0xe3; BAsmCode[3]=0x60+z;
	      memcpy(BAsmCode+1,AdrVals,AdrCnt);
	      break;
	     case ModImm:
	      if (HReg==AccReg)
	       BEGIN
	        CodeLen=2;
	        BAsmCode[0]=0x68+z; BAsmCode[1]=AdrVals[0];
	       END
	      else
	       BEGIN
	        CodeLen=3;
	        BAsmCode[0]=0xf8+HReg; BAsmCode[1]=0x68+z;
	        BAsmCode[2]=AdrVals[0];
	       END
	      break;
	    END
           break;
	  case ModReg16:
	   if ((AdrMode==2) OR ((z==0) AND (AdrMode>=4)))
	    BEGIN
	     HReg=AdrMode;
	     DecodeAdr(ArgStr[2],MModReg16+MModIndReg+MModIdxReg+MModDir+MModMem+MModImm);
	     switch (AdrType)
              BEGIN
	       case ModReg16:
	        CodeLen=2;
	        BAsmCode[0]=0xf8+AdrMode;
	        BAsmCode[1]=(HReg>=4) ? 0x14+HReg-4 : 0x70+z;
	        break;
	       case ModIndReg:
	        CodeLen=2;
	        BAsmCode[0]=0xe0+AdrMode;
	        BAsmCode[1]=(HReg>=4) ? 0x14+HReg-4 : 0x70+z;
	        break;
	       case ModIdxReg:
	        CodeLen=2+AdrCnt;
	        BAsmCode[0]=0xf0+AdrMode;
	        memcpy(BAsmCode+1,AdrVals,AdrCnt);
                BAsmCode[1+AdrCnt]=(HReg>=4) ? 0x14+HReg-4 : 0x70+z;
	        break;
	       case ModDir:
	        if (HReg>=4)
	         BEGIN
	          CodeLen=3;
	          BAsmCode[0]=0xe7;
	          BAsmCode[1]=AdrVals[0];
	          BAsmCode[2]=0x10+HReg;
	         END
	        else
	         BEGIN
	          CodeLen=2;
	          BAsmCode[0]=0x70+z; BAsmCode[1]=AdrVals[0];
	         END
                break;
	       case ModMem:
	        CodeLen=4;
	        BAsmCode[0]=0xe3;
	        memcpy(BAsmCode+1,AdrVals,2);
                BAsmCode[3]=(HReg>=4) ? 0x14+HReg-4 : 0x70+z;
	        break;
	       case ModImm:
	        CodeLen=3;
                BAsmCode[0]=(HReg>=4) ? 0x14+HReg-4 : 0x78+z;
	        memcpy(BAsmCode+1,AdrVals,AdrCnt);
	        break;
	      END
	    END
	   else WrError(1350);
           break;
	  case ModIndReg:
          case ModIdxReg:
          case ModDir:
          case ModMem:
	   OpSize=0;
	   switch (AdrType)
            BEGIN
	     case ModIndReg:
	      HReg=3;
	      BAsmCode[0]=0xe8+AdrMode; BAsmCode[1]=0x68+z;
	      break;
	     case ModIdxReg:
	      HReg=3+AdrCnt;
	      BAsmCode[0]=0xf4+AdrMode; BAsmCode[1+AdrCnt]=0x68+z;
	      memcpy(BAsmCode+1,AdrVals,AdrCnt);
	      break;
	     case ModDir:
	      HReg=4;
	      BAsmCode[0]=0xef; BAsmCode[1]=AdrVals[0]; BAsmCode[2]=0x68+z;
	      break;
	     case ModMem:
	      HReg=5;
	      BAsmCode[0]=0xeb; memcpy(BAsmCode+1,AdrVals,2); BAsmCode[3]=0x68+z;
	      break;
             default:
              HReg=0;
	    END
	   DecodeAdr(ArgStr[2],MModImm);
	   if (AdrType==ModImm)
	    BEGIN
	     BAsmCode[HReg-1]=AdrVals[0]; CodeLen=HReg;
	    END
	   break;
	 END
       END
      return;
     END

   if ((WMemo("INC")) OR (WMemo("DEC")))
    BEGIN
     if (ArgCnt!=1) WrError(1110);
     else
      BEGIN
       HReg=Ord(WMemo("DEC")) << 3;
       DecodeAdr(ArgStr[1],MModReg8+MModReg16+MModIndReg+MModIdxReg+MModDir+MModMem);
       if (OpSize==-1) OpSize=0;
       switch (AdrType)
        BEGIN
         case ModReg8:
	  CodeLen=1; BAsmCode[0]=0x80+HReg+AdrMode;
	  break;
         case ModReg16:
	  CodeLen=1; BAsmCode[0]=0x90+HReg+AdrMode;
	  break;
         case ModIndReg:
	  CodeLen=2; BAsmCode[0]=0xe0+AdrMode;
	  BAsmCode[1]=0x87+(OpSize << 4)+HReg;
	  break;
         case ModIdxReg:
	  CodeLen=2+AdrCnt; BAsmCode[0]=0xf0+AdrMode;
	  memcpy(BAsmCode+1,AdrVals,AdrCnt);
	  BAsmCode[1+AdrCnt]=0x87+(OpSize << 4)+HReg;
	  break;
         case ModDir:
	  CodeLen=2; BAsmCode[0]=0x87+(OpSize << 4)+HReg;
	  BAsmCode[1]=AdrVals[0];
	  break;
         case ModMem:
	  CodeLen=4; BAsmCode[0]=0xe3;
	  memcpy(BAsmCode+1,AdrVals,AdrCnt);
	  BAsmCode[3]=0x87+(OpSize << 4)+HReg;
	  BAsmCode[1]=AdrVals[0];
	  break;
        END
      END
     return;
    END

   if ((Memo("INCX")) OR (Memo("DECX")))
    BEGIN
     if (ArgCnt!=1) WrError(1110);
     else
      BEGIN
       DecodeAdr(ArgStr[1],MModDir);
       if (AdrType==ModDir)
	BEGIN
	 CodeLen=2;
	 BAsmCode[0]=0x07+(Ord(Memo("DECX")) << 3);
	 BAsmCode[1]=AdrVals[0];
	END
      END
     return;
    END

   if ((Memo("MUL")) OR (Memo("DIV")))
    BEGIN
     if (ArgCnt!=2) WrError(1110);
     else if (strcasecmp(ArgStr[1],"HL")!=0) WrError(1350);
     else
      BEGIN
       HReg=0x12+Ord(Memo("DIV")); OpSize=0;
       DecodeAdr(ArgStr[2],MModReg8+MModIndReg+MModIdxReg+MModDir+MModMem+MModImm);
       switch (AdrType)
        BEGIN
         case ModReg8:
	  CodeLen=2;
	  BAsmCode[0]=0xf8+AdrMode; BAsmCode[1]=HReg;
	  break;
         case ModIndReg:
	  CodeLen=2;
	  BAsmCode[0]=0xe0+AdrMode; BAsmCode[1]=HReg;
	  break;
         case ModIdxReg:
	  CodeLen=2+AdrCnt;
	  BAsmCode[0]=0xf0+AdrMode; BAsmCode[1+AdrCnt]=HReg;
	  memcpy(BAsmCode+1,AdrVals,AdrCnt);
	  break;
         case ModDir:
	  CodeLen=3; BAsmCode[0]=0xe7;
	  BAsmCode[1]=AdrVals[0]; BAsmCode[2]=HReg;
	  break;
         case ModMem:
	  CodeLen=4; BAsmCode[0]=0xe3; BAsmCode[3]=HReg;
	  memcpy(BAsmCode+1,AdrVals,AdrCnt);
	  break;
         case ModImm:
          CodeLen=3; BAsmCode[0]=0xe7; BAsmCode[1]=AdrVals[0]; BAsmCode[2]=HReg;
          break;
        END
      END
     return;
    END

   /* Spruenge */

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

   if ((Memo("CALL")) OR (Memo("JP")))
    BEGIN
     if ((ArgCnt!=1) AND (ArgCnt!=2)) WrError(1110);
     else
      BEGIN
       if (ArgCnt==1) z=DefaultCondition;
       else
        BEGIN
         NLS_UpString(ArgStr[1]);
         for (z=0; z<ConditionCnt; z++)
          if (strcmp(Conditions[z].Name,ArgStr[1])==0) break;
        END
       if (z>=ConditionCnt) WrError(1360);
       else
	BEGIN
	 OpSize=1; HReg=Ord(Memo("CALL"));
	 DecodeAdr(ArgStr[ArgCnt],MModIndReg+MModIdxReg+MModMem+MModImm);
	 if (AdrType==ModImm) AdrType=ModMem;
	 switch (AdrType)
          BEGIN
	   case ModIndReg:
	    CodeLen=2;
	    BAsmCode[0]=0xe8+AdrMode;
	    BAsmCode[1]=0xc0+(HReg << 4)+Conditions[z].Code;
	    break;
	   case ModIdxReg:
	    CodeLen=2+AdrCnt;
	    BAsmCode[0]=0xf4+AdrMode;
	    memcpy(BAsmCode+1,AdrVals,AdrCnt);
	    BAsmCode[1+AdrCnt]=0xc0+(HReg << 4)+Conditions[z].Code;
	    break;
	   case ModMem:
	    if (z==DefaultCondition)
	     BEGIN
	      CodeLen=3;
	      BAsmCode[0]=0x1a+(HReg << 1);
	      memcpy(BAsmCode+1,AdrVals,AdrCnt);
	     END
	    else
	     BEGIN
	      CodeLen=4;
	      BAsmCode[0]=0xeb;
	      memcpy(BAsmCode+1,AdrVals,AdrCnt);
	      BAsmCode[3]=0xc0+(HReg << 4)+Conditions[z].Code;
	     END
	    break;
	  END
        END
      END
     return;
    END

   if (Memo("RET"))
    BEGIN
     if ((ArgCnt!=0) AND (ArgCnt!=1)) WrError(1110);
     else
      BEGIN
       if (ArgCnt==0) z=DefaultCondition;
       else
        BEGIN
         NLS_UpString(ArgStr[1]);
         for (z=0; z<ConditionCnt; z++)
          if (strcmp(ArgStr[1],Conditions[z].Name)==0) break;
        END
       if (z>=ConditionCnt) WrError(1360);
       if (z==DefaultCondition)
	BEGIN
	 CodeLen=1; BAsmCode[0]=0x1e;
	END
       else if (z<ConditionCnt)
	BEGIN
	 CodeLen=2; BAsmCode[0]=0xfe;
	 BAsmCode[1]=0xd0+Conditions[z].Code;
	END
      END
     return;
    END

   if (Memo("DJNZ"))
    BEGIN
     if ((ArgCnt!=1) AND (ArgCnt!=2)) WrError(1110);
     else
      BEGIN
       if (ArgCnt==1)
	BEGIN
	 AdrType=ModReg8; AdrMode=0; OpSize=0;
	END
       else DecodeAdr(ArgStr[1],MModReg8+MModReg16);
       if (AdrType!=ModNone)
	if (AdrMode!=0) WrError(1350);
	else
	 BEGIN
	  AdrInt=EvalIntExpression(ArgStr[ArgCnt],Int16,&OK)-(EProgCounter()+2);
	  if (OK)
	   if ((NOT SymbolQuestionable) AND ((AdrInt>127) OR (AdrInt<-128))) WrError(1370);
	   else
	    BEGIN
	     CodeLen=2;
	     BAsmCode[0]=0x18+OpSize;
	     BAsmCode[1]=AdrInt & 0xff;
	    END
	 END
      END
     return;
    END

   if ((Memo("JRL")) OR (Memo("CALR")))
    BEGIN
     if (ArgCnt!=1) WrError(1110);
     else
      BEGIN
       AdrInt=EvalIntExpression(ArgStr[1],Int16,&OK)-(EProgCounter()+2);
       if (OK)
	BEGIN
	 CodeLen=3;
	 if (Memo("JRL"))
	  BEGIN
	   BAsmCode[0]=0x1b;
	   if ((AdrInt>=-128) AND (AdrInt<=127)) WrError(20);
	  END
	 else BAsmCode[0]=0x1d;
	 BAsmCode[1]=Lo(AdrInt); BAsmCode[2]=Hi(AdrInt);
	END
      END
     return;
    END

   WrXError(1200,OpPart);
END

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

	static void AddFixed(char *NName, Byte NCode)
BEGIN
   if (InstrZ>=FixedOrderCnt) exit(255);
   FixedOrders[InstrZ].Code=NCode;
   AddInstTree(&ITree,NName,CodeFixed,InstrZ++);
END

        static void AddMove(char *NName, Byte NCode)
BEGIN
   if (InstrZ>=MoveOrderCnt) exit(255);
   MoveOrders[InstrZ].Code=NCode;
   AddInstTree(&ITree,NName,CodeMove,InstrZ++);
END

        static void AddShift(char *NName, Byte NCode, Boolean NMay)
BEGIN
   if (InstrZ>=ShiftOrderCnt) exit(255);
   ShiftOrders[InstrZ].Code=NCode;
   ShiftOrders[InstrZ].MayReg=NMay;
   AddInstTree(&ITree,NName,CodeShift,InstrZ++);
END

        static void AddBit(char *NName, Byte NCode)
BEGIN
   if (InstrZ>=BitOrderCnt) exit(255);
   BitOrders[InstrZ].Code=NCode;
   AddInstTree(&ITree,NName,CodeBit,InstrZ++);
END

        static void AddAcc(char *NName, Byte NCode)
BEGIN
   if (InstrZ>=AccOrderCnt) exit(255);
   AccOrders[InstrZ].Code=NCode;
   AddInstTree(&ITree,NName,CodeAcc,InstrZ++);
END

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

	static void InitFields(void)
BEGIN
   ITree=Nil;

   FixedOrders=(FixedOrder *) malloc(sizeof(FixedOrder)*FixedOrderCnt); InstrZ=0;
   AddFixed("EXX" ,0x0a); AddFixed("CCF" ,0x0e);
   AddFixed("SCF" ,0x0d); AddFixed("RCF" ,0x0c);
   AddFixed("NOP" ,0x00); AddFixed("HALT",0x01);
   AddFixed("DI"  ,0x02); AddFixed("EI"  ,0x03);
   AddFixed("SWI" ,0xff); AddFixed("RLCA",0xa0);
   AddFixed("RRCA",0xa1); AddFixed("RLA" ,0xa2);
   AddFixed("RRA" ,0xa3); AddFixed("SLAA",0xa4);
   AddFixed("SRAA",0xa5); AddFixed("SLLA",0xa6);
   AddFixed("SRLA",0xa7); AddFixed("RETI",0x1f);

   MoveOrders=(FixedOrder *) malloc(sizeof(FixedOrder)*MoveOrderCnt); InstrZ=0;
   AddMove("LDI" ,0x58);
   AddMove("LDIR",0x59);
   AddMove("LDD" ,0x5a);
   AddMove("LDDR",0x5b);
   AddMove("CPI" ,0x5c);
   AddMove("CPIR",0x5d);
   AddMove("CPD" ,0x5e);
   AddMove("CPDR",0x5f);

   ShiftOrders=(ShiftOrder *) malloc(sizeof(ShiftOrder)*ShiftOrderCnt); InstrZ=0;
   AddShift("RLC",0xa0,True );
   AddShift("RRC",0xa1,True );
   AddShift("RL" ,0xa2,True );
   AddShift("RR" ,0xa3,True );
   AddShift("SLA",0xa4,True );
   AddShift("SRA",0xa5,True );
   AddShift("SLL",0xa6,True );
   AddShift("SRL",0xa7,True );
   AddShift("RLD",0x10,False);
   AddShift("RRD",0x11,False);

   BitOrders=(FixedOrder *) malloc(sizeof(FixedOrder)*BitOrderCnt); InstrZ=0;
   AddBit("BIT" ,0xa8);
   AddBit("SET" ,0xb8);
   AddBit("RES" ,0xb0);
   AddBit("TSET",0x18);

   AccOrders=(FixedOrder *) malloc(sizeof(FixedOrder)*AccOrderCnt); InstrZ=0;
   AddAcc("DAA",0x0b);
   AddAcc("CPL",0x10);
   AddAcc("NEG",0x11);

   ALU2Orders=(char **) malloc(sizeof(char *)*ALU2OrderCnt); InstrZ=0;
   ALU2Orders[InstrZ++]="ADD"; ALU2Orders[InstrZ++]="ADC";
   ALU2Orders[InstrZ++]="SUB"; ALU2Orders[InstrZ++]="SBC";
   ALU2Orders[InstrZ++]="AND"; ALU2Orders[InstrZ++]="XOR";
   ALU2Orders[InstrZ++]="OR";  ALU2Orders[InstrZ++]="CP";

   Conditions=(Condition *) malloc(sizeof(Condition)*ConditionCnt); InstrZ=0;
   AddCondition("F"  ,  0); DefaultCondition=InstrZ; AddCondition("T"  ,  8);
   AddCondition("Z"  ,  6); AddCondition("NZ" , 14);
   AddCondition("C"  ,  7); AddCondition("NC" , 15);
   AddCondition("PL" , 13); AddCondition("MI" ,  5);
   AddCondition("P"  , 13); AddCondition("M"  ,  5);
   AddCondition("NE" , 14); AddCondition("EQ" ,  6);
   AddCondition("OV" ,  4); AddCondition("NOV", 12);
   AddCondition("PE" ,  4); AddCondition("PO" , 12);
   AddCondition("GE" ,  9); AddCondition("LT" ,  1);
   AddCondition("GT" , 10); AddCondition("LE" ,  2);
   AddCondition("UGE", 15); AddCondition("ULT",  7);
   AddCondition("UGT", 11); AddCondition("ULE",  3);
END

	static void DeinitFields(void)
BEGIN
   ClearInstTree(&ITree);

   free(FixedOrders);
   free(MoveOrders);
   free(ShiftOrders);
   free(BitOrders);
   free(AccOrders);
   free(ALU2Orders);
   free(Conditions);
END

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

	static Boolean IsDef_90C141(void)
BEGIN
   return False;
END

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

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

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

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

   MakeCode=MakeCode_90C141; IsDef=IsDef_90C141;
   SwitchFrom=SwitchFrom_90C141; InitFields();
END

	void code90c141_init(void)
BEGIN
   CPU90C141=AddCPU("90C141",SwitchTo_90C141);
END
