/* code9900.h */
/*****************************************************************************/
/* AS-Portierung                                                             */
/*                                                                           */
/* Codegenerator TMS99xx                                                     */     
/*                                                                           */
/* Historie:  9. 3.1997 Grundsteinlegung                                     */     
/*           18. 8.1998 BookKeeping-Aufruf bei BSS                           */
/*            2. 1.1999 ChkPC angepasst                                      */
/*                                                                           */
/*****************************************************************************/

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

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


#define TwoOrderCount 6
#define OneOrderCount 6
#define SingOrderCount 16
#define SBitOrderCount 3
#define JmpOrderCount 13
#define ShiftOrderCount 4
#define ImmOrderCount 5
#define RegOrderCount 4
#define FixedOrderCount 6


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

typedef struct
         {
          char *Name;
          int NameLen;
          Word Code;
          Boolean MustSup;
         } SupOrder;


static CPUVar CPU9900;

static Boolean IsWord;
static Word AdrVal,AdrPart;

static FixedOrder *TwoOrders;
static FixedOrder *OneOrders;
static SupOrder *SingOrders;
static FixedOrder *SBitOrders;
static FixedOrder *JmpOrders;
static FixedOrder *ShiftOrders;
static FixedOrder *ImmOrders;
static FixedOrder *RegOrders;
static SupOrder *FixedOrders;

/*-------------------------------------------------------------------------*/
/* dynamische Belegung/Freigabe Codetabellen */

        static void AddTwo(char *NName, Word NCode)
BEGIN
   if (InstrZ>=TwoOrderCount) exit(255);
   TwoOrders[InstrZ].Name=NName;
   TwoOrders[InstrZ].Code=NCode;
   TwoOrders[InstrZ++].NameLen=strlen(NName);
END

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

        static void AddSing(char *NName, Word NCode,Boolean NSup)
BEGIN
   if (InstrZ>=SingOrderCount) exit(255);
   SingOrders[InstrZ].Name=NName;
   SingOrders[InstrZ].MustSup=NSup;
   SingOrders[InstrZ++].Code=NCode;
END

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

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

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

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

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

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

	static void InitFields(void)
BEGIN
   TwoOrders=(FixedOrder *) malloc(TwoOrderCount*sizeof(FixedOrder)); InstrZ=0;
   AddTwo("A"   ,5); AddTwo("C"   ,4); AddTwo("S"   ,3);
   AddTwo("SOC" ,7); AddTwo("SZC" ,2); AddTwo("MOV" ,6);

   OneOrders=(FixedOrder *) malloc(OneOrderCount*sizeof(FixedOrder)); InstrZ=0;
   AddOne("COC" ,0x08); AddOne("CZC" ,0x09); AddOne("XOR" ,0x0a);
   AddOne("MPY" ,0x0e); AddOne("DIV" ,0x0f); AddOne("XOP" ,0x0b);

   SingOrders=(SupOrder *) malloc(SingOrderCount*sizeof(SupOrder)); InstrZ=0;
   AddSing("B"   ,0x0440,False); AddSing("BL"  ,0x0680,False); AddSing("BLWP",0x0400,False);
   AddSing("CLR" ,0x04c0,False); AddSing("SETO",0x0700,False); AddSing("INV" ,0x0540,False);
   AddSing("NEG" ,0x0500,False); AddSing("ABS" ,0x0740,False); AddSing("SWPB",0x06c0,False);
   AddSing("INC" ,0x0580,False); AddSing("INCT",0x05c0,False); AddSing("DEC" ,0x0600,False);
   AddSing("DECT",0x0640,True ); AddSing("X"   ,0x0480,False); AddSing("LDS" ,0x0780,True );
   AddSing("LDD" ,0x07c0,True );

   SBitOrders=(FixedOrder *) malloc(SBitOrderCount*sizeof(FixedOrder)); InstrZ=0;
   AddSBit("SBO" ,0x1d); AddSBit("SBZ",0x1e); AddSBit("TB" ,0x1f);

   JmpOrders=(FixedOrder *) malloc(JmpOrderCount*sizeof(FixedOrder)); InstrZ=0;
   AddJmp("JEQ",0x13); AddJmp("JGT",0x15); AddJmp("JH" ,0x1b);
   AddJmp("JHE",0x14); AddJmp("JL" ,0x1a); AddJmp("JLE",0x12);
   AddJmp("JLT",0x11); AddJmp("JMP",0x10); AddJmp("JNC",0x17);
   AddJmp("JNE",0x16); AddJmp("JNO",0x19); AddJmp("JOC",0x18);
   AddJmp("JOP",0x1c);

   ShiftOrders=(FixedOrder *) malloc(ShiftOrderCount*sizeof(FixedOrder)); InstrZ=0;
   AddShift("SLA",0x0a); AddShift("SRA",0x08);
   AddShift("SRC",0x0b); AddShift("SRL",0x09);

   ImmOrders=(FixedOrder *) malloc(ImmOrderCount*sizeof(FixedOrder)); InstrZ=0;
   AddImm("AI"  ,0x011); AddImm("ANDI",0x012); AddImm("CI"  ,0x014);
   AddImm("LI"  ,0x010); AddImm("ORI" ,0x013);

   RegOrders=(FixedOrder *) malloc(RegOrderCount*sizeof(FixedOrder)); InstrZ=0;
   AddReg("STST",0x02c); AddReg("LST",0x008);
   AddReg("STWP",0x02a); AddReg("LWP",0x009);

   FixedOrders=(SupOrder *) malloc(FixedOrderCount*sizeof(SupOrder)); InstrZ=0;
   AddFixed("RTWP",0x0380,False); AddFixed("IDLE",0x0340,True );
   AddFixed("RSET",0x0360,True ); AddFixed("CKOF",0x03c0,True );
   AddFixed("CKON",0x03a0,True ); AddFixed("LREX",0x03e0,True );
END

	static void DeinitFields(void)
BEGIN
   free(TwoOrders);
   free(OneOrders);
   free(SingOrders);
   free(SBitOrders);
   free(JmpOrders);
   free(ShiftOrders);
   free(ImmOrders);
   free(RegOrders);
   free(FixedOrders);
END

/*-------------------------------------------------------------------------*/
/* Adressparser */

        static Boolean DecodeReg(char *Asc, Word *Erg)
BEGIN
   Boolean OK;
   *Erg=EvalIntExpression(Asc,UInt4,&OK); return OK;
END

        static char *HasDisp(char *Asc)
BEGIN
   char *p;
   int Lev;

   if (Asc[strlen(Asc)-1]==')')
    BEGIN
     p=Asc+strlen(Asc)-2; Lev=0;
     while ((p>=Asc) AND (Lev!=-1))
      BEGIN
       switch (*p)
        BEGIN
         case '(': Lev--; break;
         case ')': Lev++; break;
        END
       if (Lev!=-1) p--;
      END
     if (Lev!=-1)
      BEGIN
       WrError(1300); p=Nil;
      END
    END
   else p=Nil;

   return p;
END

        static Boolean DecodeAdr(char *Asc)
BEGIN
   Boolean IncFlag;
   String Reg;
   Boolean OK;
   char *p;

   AdrCnt=0;

   if (*Asc=='*')
    BEGIN
     Asc++;
     if (Asc[strlen(Asc)-1]=='+')
      BEGIN
       IncFlag=True; Asc[strlen(Asc)-1]='\0';
      END
     else IncFlag=False;
     if (DecodeReg(Asc,&AdrPart))
      BEGIN
       AdrPart+=0x10+(Ord(IncFlag) << 5);
       return True;
      END
     return False;
    END

   if (*Asc=='@')
    BEGIN
     Asc++; p=HasDisp(Asc);
     if (p==Nil)
      BEGIN
       FirstPassUnknown=False;
       AdrVal=EvalIntExpression(Asc,UInt16,&OK);
       if (OK)
        BEGIN
         AdrPart=0x20; AdrCnt=1;
         if ((NOT FirstPassUnknown) AND (IsWord) AND (Odd(AdrVal))) WrError(180);
         return True;
        END
      END
     else
      BEGIN
       strmaxcpy(Reg,p+1,255); Reg[strlen(Reg)-1]='\0';
       if (DecodeReg(Reg,&AdrPart))
        if (AdrPart==0) WrXError(1445,Reg);
        else
         BEGIN
          *p='\0';
          AdrVal=EvalIntExpression(Asc,Int16,&OK);
          if (OK)
           BEGIN
            AdrPart+=0x20; AdrCnt=1; return True;
           END
         END
      END
     return False;
    END  

   if (DecodeReg(Asc,&AdrPart)) return True;
   else
    BEGIN
     WrError(1350); return False;
    END
END

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

        static void PutByte(Byte Value)
BEGIN
   if (((CodeLen&1)==1) AND (NOT BigEndian))
    BEGIN
     BAsmCode[CodeLen]=BAsmCode[CodeLen-1];
     BAsmCode[CodeLen-1]=Value;
    END
   else
    BEGIN
     BAsmCode[CodeLen]=Value;
    END
   CodeLen++;
END

	static Boolean DecodePseudo(void)
BEGIN
   int z;
   char *p;
   Boolean OK;
   TempResult t;
   Word HVal16;

   if (Memo("BYTE"))
    BEGIN
     if (ArgCnt==0) WrError(1110);
     else
      BEGIN
       z=1; OK=True;
       do
        BEGIN
         KillBlanks(ArgStr[z]);
         FirstPassUnknown=False;
         EvalExpression(ArgStr[z],&t);
         switch (t.Typ)
          BEGIN
           case TempInt:
            if (FirstPassUnknown) t.Contents.Int&=0xff;
            if (NOT RangeCheck(t.Contents.Int,Int8)) WrError(1320);
            else if (CodeLen==MaxCodeLen)
             BEGIN
              WrError(1920); OK=False;
             END
            else PutByte(t.Contents.Int);
            break;
           case TempFloat:
            WrError(1135); OK=False;
            break;
           case TempString:
            if (strlen(t.Contents.Ascii)+CodeLen>=MaxCodeLen)
             BEGIN
              WrError(1920); OK=False;
             END
            else
             BEGIN
              TranslateString(t.Contents.Ascii);
              for (p=t.Contents.Ascii; *p!='\0'; PutByte(*(p++)));
             END
            break;
           case TempNone:
            OK=False;
            break;
          END
         z++;
        END
       while ((z<=ArgCnt) AND (OK));
       if (NOT OK) CodeLen=0;
       else if ((Odd(CodeLen)) AND (DoPadding)) PutByte(0);
      END
     return True;
    END

   if (Memo("WORD"))
    BEGIN
     if (ArgCnt==0) WrError(1110);
     else
      BEGIN
       z=1; OK=True;
       do
        BEGIN
         HVal16=EvalIntExpression(ArgStr[z],Int16,&OK);
         if (OK)
	  BEGIN
	   WAsmCode[CodeLen >> 1]=HVal16;
	   CodeLen+=2;
          END
         z++;
        END
       while ((z<=ArgCnt) AND (OK));
       if (NOT OK) CodeLen=0;
      END
     return True;
    END

   if (Memo("BSS"))
    BEGIN
     if (ArgCnt!=1) WrError(1110);
     else
      BEGIN
       FirstPassUnknown=False;
       HVal16=EvalIntExpression(ArgStr[1],Int16,&OK);
       if (FirstPassUnknown) WrError(1820);
       else if (OK)
        BEGIN
         if ((DoPadding) AND (Odd(HVal16))) HVal16++;
         DontPrint=True; CodeLen=HVal16;
         BookKeeping();
        END
      END
     return True;
    END

   return False;
END

        static void MakeCode_9900(void)
BEGIN
   Word HPart;
   Integer AdrInt;
   int z;
   Boolean OK;

   CodeLen=0; DontPrint=False; IsWord=False;

   /* zu ignorierendes */

   if (Memo("")) return;

   /* Pseudoanweisungen */

   if (DecodePseudo()) return;

   /* zwei Operanden */

   for (z=0; z<TwoOrderCount; z++)
    if ((strncmp(OpPart,TwoOrders[z].Name,TwoOrders[z].NameLen)==0) AND (((OpPart[TwoOrders[z].NameLen]=='B') AND (OpPart[TwoOrders[z].NameLen+1]=='\0')) OR (OpPart[TwoOrders[z].NameLen]=='\0')))
     BEGIN
      if (ArgCnt!=2) WrError(1110);
      else if (DecodeAdr(ArgStr[1]))
       BEGIN
        WAsmCode[0]=AdrPart; WAsmCode[1]=AdrVal;
        HPart=AdrCnt;
        if (DecodeAdr(ArgStr[2]))
         BEGIN
          WAsmCode[0]+=AdrPart << 6; WAsmCode[1+HPart]=AdrVal;
          CodeLen=(1+HPart+AdrCnt) << 1;
          if (OpPart[strlen(OpPart)-1]=='B') WAsmCode[0]+=0x1000;
          WAsmCode[0]+=TwoOrders[z].Code << 13;
         END
       END
      return;
     END

   for (z=0; z<OneOrderCount; z++)
    if (Memo(OneOrders[z].Name))
     BEGIN
      if (ArgCnt!=2) WrError(1110);
      else if (DecodeAdr(ArgStr[1]))
       BEGIN
        WAsmCode[0]=AdrPart; WAsmCode[1]=AdrVal;
        if (DecodeReg(ArgStr[2],&HPart))
         BEGIN
          WAsmCode[0]+=(HPart << 6)+(OneOrders[z].Code << 10);
          CodeLen=(1+AdrCnt) << 1;
         END
       END
      return;
     END

   if ((Memo("LDCR")) OR (Memo("STCR")))
    BEGIN
     if (ArgCnt!=2) WrError(1110);
     else if (DecodeAdr(ArgStr[1]))
      BEGIN
       WAsmCode[0]=0x3000+(Ord(Memo("STCR")) << 10)+AdrPart;
       WAsmCode[1]=AdrVal;
       FirstPassUnknown=False;
       HPart=EvalIntExpression(ArgStr[2],UInt5,&OK);
       if (FirstPassUnknown) HPart=1;
       if (OK)
        if (ChkRange(HPart,1,16))
         BEGIN
          WAsmCode[0]+=(HPart & 15) << 6;
          CodeLen=(1+AdrCnt) << 1;
	 END
      END
     return;
    END

   for (z=0; z<ShiftOrderCount; z++)
    if (Memo(ShiftOrders[z].Name))
     BEGIN
      if (ArgCnt!=2) WrError(1110);
      else if (DecodeReg(ArgStr[1],WAsmCode+0))
       BEGIN
        if (DecodeReg(ArgStr[2],&HPart))
         BEGIN
          WAsmCode[0]+=(HPart << 4)+(ShiftOrders[z].Code << 8);
          CodeLen=2;
         END
       END
      return;
     END

   for (z=0; z<ImmOrderCount; z++)
    if (Memo(ImmOrders[z].Name))
     BEGIN
      if (ArgCnt!=2) WrError(1110);
      else if (DecodeReg(ArgStr[1],WAsmCode+0))
       BEGIN
        WAsmCode[1]=EvalIntExpression(ArgStr[2],Int16,&OK);
        if (OK)
         BEGIN
          WAsmCode[0]+=(ImmOrders[z].Code << 5); CodeLen=4;
         END
       END
      return;
     END

   for (z=0; z<RegOrderCount; z++)
    if (Memo(RegOrders[z].Name))
     BEGIN
      if (ArgCnt!=1) WrError(1110);
      else if (DecodeReg(ArgStr[1],WAsmCode+0))
       BEGIN
        WAsmCode[0]+=RegOrders[z].Code << 4; CodeLen=2;
       END
      return;
     END;

   if (Memo("LMF"))
    BEGIN
     if (ArgCnt!=2) WrError(1110);
     else if (DecodeReg(ArgStr[1],WAsmCode+0))
      BEGIN
       WAsmCode[0]+=0x320+(EvalIntExpression(ArgStr[2],UInt1,&OK) << 4);
       if (OK) CodeLen=2;
       if (NOT SupAllowed) WrError(50);
      END
     return;
    END

   /* ein Operand */

   if ((Memo("MPYS")) OR (Memo("DIVS")))
    BEGIN
     if (ArgCnt!=1) WrError(1110);
     else if (DecodeAdr(ArgStr[1]))
      BEGIN
       WAsmCode[0]=0x0180+(Ord(Memo("MPYS")) << 6)+AdrPart;
       WAsmCode[1]=AdrVal;
       CodeLen=(1+AdrCnt) << 1;
      END
     return;
    END

   for (z=0; z<SingOrderCount; z++)
    if (Memo(SingOrders[z].Name))
     BEGIN
      if (ArgCnt!=1) WrError(1110);
      else if (DecodeAdr(ArgStr[1]))
       BEGIN
        WAsmCode[0]=SingOrders[z].Code+AdrPart;
        WAsmCode[1]=AdrVal;
        CodeLen=(1+AdrCnt) << 1;
        if ((SingOrders[z].MustSup) AND (NOT SupAllowed)) WrError(50);
       END
      return;
     END

   for (z=0; z<SBitOrderCount; z++)
    if (Memo(SBitOrders[z].Name))
     BEGIN
      if (ArgCnt!=1) WrError(1110);
      else
       BEGIN
        WAsmCode[0]=EvalIntExpression(ArgStr[1],SInt8,&OK);
        if (OK)
         BEGIN
          WAsmCode[0]=(WAsmCode[0] & 0xff) | (SBitOrders[z].Code << 8);
          CodeLen=2;
         END
       END
      return;
     END

   for (z=0; z<JmpOrderCount; z++)
    if (Memo(JmpOrders[z].Name))
     BEGIN
      if (ArgCnt!=1) WrError(1110);
      else
       BEGIN
        AdrInt=EvalIntExpression(ArgStr[1],UInt16,&OK)-(EProgCounter()+2);
        if (OK)
         if (Odd(AdrInt)) WrError(1375);
         else if ((NOT SymbolQuestionable) AND ((AdrInt<-256) OR (AdrInt>254))) WrError(1370);
         else
          BEGIN
           WAsmCode[0]=((AdrInt>>1) & 0xff) | (JmpOrders[z].Code << 8);
           CodeLen=2;
          END
       END;
      return;
     END

   if ((Memo("LWPI")) OR (Memo("LIMI")))
    BEGIN
     if (ArgCnt!=1) WrError(1110);
     else
      BEGIN
       WAsmCode[1]=EvalIntExpression(ArgStr[1],UInt16,&OK);
       if (OK)
        BEGIN
         WAsmCode[0]=(0x017+Ord(Memo("LIMI"))) << 5;
         CodeLen=4;
        END
      END
     return;
    END

   /* kein Operand */

   for (z=0; z<FixedOrderCount; z++)
    if (Memo(FixedOrders[z].Name))
     BEGIN
      if (ArgCnt!=0) WrError(1110);
      else
       BEGIN
        WAsmCode[0]=FixedOrders[z].Code; CodeLen=2;
        if ((FixedOrders[z].MustSup) AND (NOT SupAllowed)) WrError(50);
       END
      return;
     END

   WrXError(1200,OpPart);
END

        static Boolean IsDef_9900(void)
BEGIN
   return False;
END

        static void SwitchFrom_9900(void)
BEGIN
   DeinitFields(); ClearONOFF();
END

	static void InternSymbol_9900(char *Asc, TempResult*Erg)
BEGIN
   Boolean err;
   char *h=Asc;

   Erg->Typ=TempNone;
   if ((strlen(Asc)>=2) AND (toupper(*Asc)=='R')) h=Asc+1;
   else if ((strlen(Asc)>=3) AND (toupper(*Asc)=='W') AND (toupper(Asc[1])=='R')) h=Asc+2;

   Erg->Contents.Int=ConstLongInt(h,&err);
   if ((NOT err) OR (Erg->Contents.Int<0) OR (Erg->Contents.Int>15)) return;

   Erg->Typ=TempInt;
END

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

   PCSymbol="$"; HeaderID=0x48; NOPCode=0x0000;
   DivideChars=","; HasAttrs=False;

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

   MakeCode=MakeCode_9900; IsDef=IsDef_9900;
   SwitchFrom=SwitchFrom_9900; InternSymbol=InternSymbol_9900;
   AddONOFF("PADDING", &DoPadding , DoPaddingName ,False);
   AddONOFF("SUPMODE", &SupAllowed, SupAllowedName,False);

   InitFields();
END

	void code9900_init(void)
BEGIN
   CPU9900=AddCPU("TMS9900",SwitchTo_9900);
END
