/****************************************************************************
**
**  Name:  asmppc.c
**
**  Description:
**     This is a disassembler
**
**  Status:  REVIEWED
**
**  $Log:   S:/tbird/arcppc/dasm/asmppc.c_v  $
** 
**    Rev 1.5   19 Aug 1997 16:01:26   cjchen
** 
**    Rev 1.4   15 Jul 1997 10:01:46   cjchen
** 
**    Rev 1.3   31 Mar 1997 13:41:02   cjchen
**
**  $Header:   S:/tbird/arcppc/dasm/asmppc.c_v   1.5   19 Aug 1997 16:01:26   cjchen  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/
#include <stdio.h>
#include <io.h>
#include <string.h>
#include <alloc.h>
#include <stdlib.h>

#ifndef _BASEWIND_
#include "basewind.h"
#endif

#ifndef _BASETYPE_
#include "basetype.h"
#endif

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

#ifndef _HEAP_
#include "heap.h"
#endif

#ifndef _ADDR_
#include "addr.h"
#endif

#include "asmdef.h"
#include "dadasm.h"
#include "603asm.tbl"
#define MAX_LINE_PER_INST 3

//RETCODE SetOperand(U8 index,LPSTR operandString,OPERATOR *opSet);
RETCODE GetToken(OPERATOR *opSet,LPSTR inInst);
RETCODE DeleteBlank(LPSTR inString,LPSTR outString);
RETCODE IdentifyInst(OPERATOR *opSet,U16 *instNo);
RETCODE CheckOperandSyntax(U16 index,OPERATOR *opSet,DESCRIPTOR startAddr,
    U16 instNo);
RETCODE PutBits(U32 *outInst,S32 value,U8 startBit, U8 endBit);
RETCODE SplitBits(U32 *shInst,S32 SHInst,U8 frontBits,U8 endBits);
RETCODE CheckVA(LPSTR vaPtr,S32 *vaValue);
RETCODE AsmInst(OPERATOR FAR *opSet, LPSTR inInst, LPSTR *outInst,
                LPWORD numBytes, DESCRIPTOR startAddr);
//RETCODE AsmInst(OPERATOR *opSet, LPSTR inInst, LPSTR *outInst,
//                LPWORD numBytes);
S8 FindString(U8 Count, U8 **Source, U8 *Search);

/****************************************************************************
*
*  FindString
*
*****************************************************************************/
S8 FindString(U8 Count, U8 **Source, U8 *Search) {
   U8   idx;
   idx = 0;

   while ((idx < Count) && (_fstricmp(Search,Source[idx]) != 0)) idx++;
   if( idx == Count ) return(-1);
   return(idx);
}
/****************************************************************************
*
*  AsmInst
*
*****************************************************************************/
 
RETCODE AsmInst(OPERATOR *opSet, LPSTR inInst, LPSTR *outInst,
		LPWORD numBytes, DESCRIPTOR startAddr) {

   U16       instNo;
   U8        WordBuf[10],i,j,tempU8;
   RETCODE   err;
   char      tempString[10];
   U32       tempOutInst,SHInst,tempObjCode,startOffset;
   U8        startBit,length,endBit,wordBuf[10];
   BOOLEAN   reverseFlag;
   char      *tempPtr;

   if ((err = GetToken(opSet,inInst)) != GOOD)
      return err;
   if ((err = IdentifyInst(opSet,&instNo)) != GOOD)
      return err;

   if ((err = CheckOperandSyntax(instructionSet[instNo].OperandType,opSet,
      startAddr,instNo)) != GOOD)
      return err;

   if ((err = AdrGetAddrOffset(startAddr,&startOffset)) != GOOD)
      return err;

   tempOutInst=0;
   /* put opcode bits */
   PutBits(&tempOutInst,instructionSet[instNo].OpCode,0,5);
   /* put XO bits     */
   PutBits(&tempOutInst,instructionSet[instNo].Xo,21,30);
   startBit=endBit=length=6;
   reverseFlag=FALSE;
   j=0;
   for (i=0;i<5;i++) { 
      switch (opPos[(instructionSet[instNo].OperandPos)].OperandPos[i]) {
         case 0:
            i=4;
            break;
         case B5:
            PutBits(&tempOutInst,opSet->OperandValue[j],startBit,
               startBit+4);
            startBit=startBit+5;
            if (reverseFlag) {
               PutBits(&tempOutInst,opSet->OperandValue[j-1],startBit,
                  startBit+4);
               startBit=startBit+5;
               reverseFlag=FALSE;
            }
            
            break;
         case ZR:
            PutBits(&tempOutInst,0,startBit,startBit+4);
            startBit=startBit+5;
            j--;
            break;
         case RB5:
            reverseFlag=TRUE; 
            break;
         case crfDZZ:
            PutBits(&tempOutInst,opSet->OperandValue[j]<<2,startBit,
               startBit+4);
            startBit=startBit+5;
            break;
         case crfDZL:
            PutBits(&tempOutInst,(opSet->OperandValue[j]<<2) ||
               (opSet->OperandValue[j+1]),startBit,startBit+4);
            j++;
            startBit=startBit+5;
            break;
         case ZSR:
            PutBits(&tempOutInst,opSet->OperandValue[j],startBit,
               startBit+4);
            startBit=startBit+5;
            if (reverseFlag) {
               PutBits(&tempOutInst,opSet->OperandValue[j-1],startBit,
                  startBit+4);
               startBit=startBit+5;
               reverseFlag=FALSE; 
            } 
            break;
         case ZUB8Z:
            PutBits(&tempOutInst,opSet->OperandValue[j]<<1,startBit,
               startBit+9);
            startBit=startBit+10;
            if (reverseFlag) {
               PutBits(&tempOutInst,opSet->OperandValue[j-1],startBit,
                  startBit+4);
               startBit=startBit+5;
               reverseFlag=FALSE;
            } 
            break;
         case RZUB8Z: /* for CRM */
            PutBits(&tempOutInst,opSet->OperandValue[j]<<1,11,
               20);
            startBit=6;
            break;
         case RUB10:   /* for spr */
            PutBits(&tempOutInst,opSet->OperandValue[j],11,20);
            startBit=6;
            break;
         case UB10:
            SplitBits(&SHInst,opSet->OperandValue[j],5,5);
            PutBits(&tempOutInst,SHInst,startBit,
               startBit+9);
            startBit=startBit+10;
            if (reverseFlag) {
               PutBits(&tempOutInst,opSet->OperandValue[j-1],startBit,
                  startBit+4);
               startBit=startBit+5;
               reverseFlag=FALSE;
            } 
            break;
         case UB4Z:
            PutBits(&tempOutInst,opSet->OperandValue[j]<<1,startBit,
               startBit+4);
            startBit=startBit+5;
            break;
         case SB24:
            PutBits(&tempOutInst,opSet->OperandValue[j],startBit,
               startBit+23);
            startBit=startBit+24;
            break;
         case SB16:
         case UB16:
            PutBits(&tempOutInst,opSet->OperandValue[j],startBit,
               startBit+15);
            startBit=startBit+16;
            break;
         case SB14:
            PutBits(&tempOutInst,opSet->OperandValue[j],startBit,
               startBit+13);
            startBit=startBit+14;
            break;
         case UB6sh:
            SplitBits(&SHInst,opSet->OperandValue[j],5,1);
            PutBits(&tempOutInst,SHInst>>1,startBit,startBit+4);
            PutBits(&tempOutInst,SHInst & 0x1,30,30);
            startBit=startBit+5;
            break;
         case UB6:
            SplitBits(&SHInst,opSet->OperandValue[j],5,1);
            PutBits(&tempOutInst,SHInst,startBit,startBit+5);
            startBit=startBit+6;
         }
         j++; /* optype, opvalue */
   }
   if (instructionSet[instNo].OE!=0xF)
      PutBits(&tempOutInst,instructionSet[instNo].OE,OE_BIT,OE_BIT);
   if (instructionSet[instNo].RC!=0xF)
      PutBits(&tempOutInst,instructionSet[instNo].RC,RC_BIT,RC_BIT);
   if (instructionSet[instNo].AA!=0xF)
      PutBits(&tempOutInst,instructionSet[instNo].AA,AA_BIT,AA_BIT);
   if (instructionSet[instNo].LK!=0xF)
      PutBits(&tempOutInst,instructionSet[instNo].LK,LK_BIT,LK_BIT);
   tempPtr = &tempOutInst;
   if ((*outInst = (LPU8)TMalloc(MAX_LINE_PER_INST*MAX_LINE_LENGTH)) == NULL)
      return ER_OUT_OF_MEMORY;
   //*outInst = tempOutInst;
   opSet->ObjCode=0;
   for (i=0;i<4;i++) {
       tempObjCode=*(tempPtr+i);
       tempObjCode=tempObjCode & 0x000000ff;
       opSet->ObjCode=(opSet->ObjCode<<8)|(tempObjCode);
   }

   if (err == GOOD) {
      **outInst = wordBuf[0] = 0x00;
      wsprintf(*outInst," %6.6lX  ",startOffset);
      wsprintf(wordBuf,"%8.8lX",tempOutInst);
      lstrcat(*outInst,wordBuf);
      lstrcat(*outInst,"  ");
      lstrcat(*outInst,inInst);
      *numBytes = 4;
      //lstrcat(*outInst,"\r");
   } else {
      lstrcat(*outInst,"   *** Error ***     ");
      lstrcat(*outInst,inInst);
      *numBytes = 0;
   }
   /*fputc(*(tempPtr+3),output);
   fputc(*(tempPtr+2),output);
   fputc(*(tempPtr+1),output);
   fputc(*(tempPtr),output);*/
   //fprintf(output,"%c%c%c%c",*(tempPtr+3),*(tempPtr+2),*(tempPtr+1),
   //   *tempPtr);
   return(err);
}

/****************************************************************************
*
*  GetToken
*
*****************************************************************************/
RETCODE GetToken(OPERATOR *opSet,LPSTR inInst) {
char outString[MAX_LINE_LENGTH];
char tempString[MAX_LINE_LENGTH];
char errString[MAX_ERR_LENGTH];
LPSTR tempPtr,commaPtr;
U8 i;
   for (i=0;i<strlen(inInst);i++)
      inInst[i]=tolower(inInst[i]);
   DeleteBlank(inInst,outString);
   sscanf(outString,"%s",opSet->Mnemonic);
   tempPtr=outString+strlen(opSet->Mnemonic);
   DeleteBlank(tempPtr,outString);
   commaPtr=tempPtr=outString;
   for (i=0;i<5;i++)
      opSet->Operand[i][0]='\0';
   i=0;
   if (*commaPtr!='\0') {
      while (commaPtr!=NULL) {
         commaPtr=_fstrchr(tempPtr,','); 
         if (commaPtr!=NULL) { 
            *commaPtr=' ';
            sscanf(tempPtr,"%s",opSet->Operand[i]);  
            *commaPtr=',';
            tempPtr=commaPtr+1;
            i++;
         }
         if (i==5)
            break;
      }
      if (i>=0 && i<5)
         sscanf(tempPtr,"%s",opSet->Operand[i]);
   }
   if (i==5)
      //return ER_PARAMETER_TOO_MUCH;
      return ER_DAD_ASM_ERROR;
   //printf(opSet->Mnemonic); 
   //printf(tempString);
   return GOOD;
}

/****************************************************************************
*
*  IdentifyInst
*
*****************************************************************************/
RETCODE IdentifyInst(OPERATOR *opSet,U16 *instNo) {
U16 i;
   *instNo=0xffff;
   for (i=0;i<INSTRUCTION_NO;i++) {
     if (strcmpi(opSet->Mnemonic,instructionSet[i].Mnemonic)==0) {
        *instNo=i;
        break;
     }
   }
   //printf("instNo %u",*instNo);
   if (*instNo==0xffff)
      //return ER_INST_NOT_FOUND;
      return ER_DAD_ASM_ERROR;

   return GOOD;
}
/****************************************************************************
*
*  DeleteBlank
*
*****************************************************************************/
RETCODE DeleteBlank(LPSTR inString,LPSTR outString) {
U8 i;
LPSTR tempString;
   i=0;   
   while (*(inString+i)==' ')
      i++;
   tempString=inString+i;
   strcpy(outString,tempString);
   return GOOD;
}
 
/****************************************************************************
*
*  CheckOperandSyntax
*
*****************************************************************************/
RETCODE CheckOperandSyntax(U16 index,OPERATOR *opSet,DESCRIPTOR startAddr,
    U16 instNo) {
LPSTR tempPtr,temp1Ptr;
U8 i;
S32 tempi;
RETCODE err;
U32 addrOffset;

   if ((err = AdrGetAddrOffset(startAddr,&addrOffset)) != GOOD)
      return err;
   for (i=0;i<5;i++) {
      switch(opType[index].OperandType[i]) {
         case rA:
           tempPtr=opSet->Operand[i];
           if (opSet->Operand[i][0]=='r')
              tempPtr=opSet->Operand[i]+1;
           tempi=atol(tempPtr);
           if (tempi>=0 && tempi<=31) {
               opSet->OperandValue[i]=tempi;
               break;
           }
           else
              //return ER_REGISTER_OVER_LIMIT;
              return ER_DAD_ASM_ERROR;
         case frA: 
            if (opSet->Operand[i][0]=='f' && opSet->Operand[i][1]=='r') {
               tempPtr=opSet->Operand[i]+2;
               tempi=atol(tempPtr);
               if (tempi>=0 && tempi<=31) {
                  opSet->OperandValue[i]=tempi;
                  break;
               }
               else
                  //return ER_REGISTER_OVER_LIMIT;
                  return ER_DAD_ASM_ERROR;
            }
            else
               //return ER_INST_SYNTAX_ERROR;
               return ER_DAD_ASM_ERROR;
         case crfD: 
            if ((err=CheckVA(opSet->Operand[i],&tempi))!=GOOD)
               return err;
            if (tempi>=0 && tempi<=7) {
                opSet->OperandValue[i]=tempi;
                break;
            }
            else
               //return ER_CRFD_OVER_LIMIT;
               return ER_DAD_ASM_ERROR;
         case crbA:
            if ((err=CheckVA(opSet->Operand[i],&tempi))!=GOOD)
                return err;
            if (tempi>=0 && tempi<=31) {
               opSet->OperandValue[i]=tempi;
               break;
            }
            else
               //return ER_CRBA_OVER_LIMIT;
               return ER_DAD_ASM_ERROR;
         case SVA16:
         case SVA14:
            tempPtr=_fstrchr(opSet->Operand[i],')');
            if (tempPtr!=NULL && *(tempPtr+1)=='\0') {
               opSet->OperandValue[i]=opSet->OperandValue[i+1]=0xffffffff;
               sscanf(opSet->Operand[i],"%I(r%lu)",&(opSet->OperandValue[i+1]),
               &(opSet->OperandValue[i]));
               if ((opSet->OperandValue[i]==0xffffffff) ||
                  (opSet->OperandValue[i+1]==0xffffffff))
                  return err;
               break;
            }
            CheckVA(opSet->Operand[i],&tempi);
            if (opType[index].OperandType[i]==SVA14) {
               //&& tempi<=0xffffffff && tempi>=0 ) {
                //tempi>=(S32)-0x1fff && tempi<=(S32)0x1ffff) {
                if (instructionSet[instNo].AA)
                   tempi=(tempi>>2);
                else
                   tempi=(tempi-addrOffset)>>2;
                opSet->OperandValue[i]=tempi;
                break;
            }
            else {
               if (opType[index].OperandType[i]==SVA16) {
                  //&& tempi<=0xffffffff && tempi >=0) {
                   //tempi>=(S32)-0x7fff && tempi<=(S32)0x7fff) {
                   /*
                   if (instructionSet[instNo].AA)
                      tempi=(tempi>>2);
                   else
                      tempi=(tempi-addrOffset)>>2;
                   */
                   opSet->OperandValue[i]=tempi;
                   break;
               }
               else
                  //return ER_CONST_OVER_LIMIT;
                  return ER_DAD_ASM_ERROR;
            }
         case UVA1:
            if ((err=CheckVA(opSet->Operand[i],&tempi))!=GOOD)
               return err;
            if (tempi>=0 && tempi<=1) {
               opSet->OperandValue[i]=tempi;
               break;
            }
            else
               //return ER_CONST_OVER_LIMIT;
               return ER_DAD_ASM_ERROR;
         case UVA4:
            if ((err=CheckVA(opSet->Operand[i],&tempi))!=GOOD)
               return err;
            if (tempi>=0 && tempi<=(S32)0xf) {
               opSet->OperandValue[i]=tempi;
               break;
            }
            else
               //return ER_CONST_OVER_LIMIT;
               return ER_DAD_ASM_ERROR;
         case UVA5:
            if ((err=CheckVA(opSet->Operand[i],&tempi))!=GOOD)
               return err;
            if (tempi>=0 && tempi<=(S32)0x1f) {
               opSet->OperandValue[i]=tempi;
               break;
            }
            else
               //return ER_CONST_OVER_LIMIT;
               return ER_DAD_ASM_ERROR;
         case UVA6:
            if ((err=CheckVA(opSet->Operand[i],&tempi))!=GOOD)
               return err;
            if (tempi>=0 && tempi<=(S32)0x3f) {
               opSet->OperandValue[i]=tempi;
               break;
            }
            else
               //return ER_CONST_OVER_LIMIT;
               return ER_DAD_ASM_ERROR;
         case UVA8:
            if ((err=CheckVA(opSet->Operand[i],&tempi))!=GOOD)
               return err;
            if (tempi>=0 && tempi<=(S32)0xff) {
               opSet->OperandValue[i]=tempi;
               break;
            }
            else
               //return ER_CONST_OVER_LIMIT;
               return ER_DAD_ASM_ERROR;
         case UVA10:
            if ((err=CheckVA(opSet->Operand[i],&tempi))!=GOOD)
               return err;
            if (tempi>=0 && tempi<=(S32)0x3ff) {
               opSet->OperandValue[i]=tempi;
               break;
            }
            else
               //return ER_CONST_OVER_LIMIT;
               return ER_DAD_ASM_ERROR;
         case UVA16:
            if ((err=CheckVA(opSet->Operand[i],&tempi))!=GOOD)
               return err;
            if (tempi>=0 && tempi<=(S32)0xFFFF) {
               opSet->OperandValue[i]=tempi;
               break;
            }
            else
               //return ER_CONST_OVER_LIMIT;
               return ER_DAD_ASM_ERROR;
         case SVA24:
            if ((err=CheckVA(opSet->Operand[i],&tempi))!=GOOD)
               return err;
            if (tempi<=0xffffffff && tempi>=0) {
            //if (tempi>=(S32)-0x7fffff && tempi<=(S32)0x7fffff) {
               if (instructionSet[instNo].AA)
                  tempi=(tempi>>2);
               else
                  tempi=(tempi-addrOffset)>>2;
               opSet->OperandValue[i]=tempi;
               break;
            }
            else
               //return ER_CONST_OVER_LIMIT;
               return ER_DAD_ASM_ERROR;
         case 0:
            if (opSet->Operand[i][0]!='\0')
               //return ER_TOO_MUCH_PARAMETER;
               return ER_DAD_ASM_ERROR;
            else {
               i=4;
               break;
            }

      }
      //printf("%u %lu \n",opType[index].OperandType[i],opSet->OperandValue[i]);

   }
   return GOOD;
}
/****************************************************************************
*
*  PutBits
*
*****************************************************************************/
RETCODE PutBits(U32 *outInst,S32 value,U8 startBit,U8 endBit) {
U8 length;
U32 mask;
U32 buffer;
   length=endBit-startBit+1;
   mask=0xffffffff;
   mask=mask >> (32-length);
   buffer = value & mask;
   mask=mask << (32-length-startBit);
   mask=mask ^ 0xffffffff;
   *outInst=*outInst & mask;
   *outInst=*outInst | (buffer << (32-length-startBit));
   return GOOD;
}
/****************************************************************************
*
*  SplitBits
*
*****************************************************************************/
RETCODE SplitBits(U32 *shInst,S32 SHInst,U8 frontBits,U8 endBits) {
U8 length;
U32 mask;
U32 buffer,temp1,temp2;
   length=frontBits+endBits;
   mask=0xffffffff;
   mask=mask >> (32-length);
   buffer = SHInst & mask;
   temp1=buffer >> frontBits;
   temp2=buffer << endBits;
   /*
   temp1=buffer >> endBits;
   temp2=buffer << frontBits;
   */
   *shInst=(temp2 & mask) | temp1;
   return GOOD;
}
/****************************************************************************
*
*  CheckVA
*
*****************************************************************************/
RETCODE CheckVA(LPSTR vaPtr,S32 *vaValue) {
char outValue[MAX_LINE_LENGTH];
LPSTR tempPtr;
U8 i;
   DeleteBlank(vaPtr,outValue);
   i=0;
   if (outValue[0]=='+' || outValue[0]=='-')
      i++;
   if (outValue[i]=='0' && (outValue[i+1]=='x' || outValue[i+1]=='X')) {
      for (i=i+2;i<strlen(outValue);i++)
         if (!((outValue[i]>='0' && outValue[i]<='9') ||
            (outValue[i]>='a' && outValue[i]<='f') ||
            (outValue[i]>='A' && outValue[i]<='F')))
            //return ER_VALUE_ERROR;
            return ER_DAD_ASM_ERROR;
      *vaValue=strtol(outValue,&tempPtr,16);
   }
   else {
      for (i=0;i<strlen(outValue);i++) 
         if (!(i==0 && (outValue[0]=='-' || outValue[0]=='+')))
            if (!(outValue[i]>='0' && outValue[i]<='9'))  
               //return ER_VALUE_ERROR;
               return ER_DAD_ASM_ERROR;
      *vaValue=strtol(outValue,&tempPtr,10);
   }
   return GOOD;
}
