540 lines
13 KiB
C
540 lines
13 KiB
C
/* codemsp.c */
|
|
/*****************************************************************************/
|
|
/* AS-Portierung */
|
|
/* */
|
|
/* Codegenerator MSP430 */
|
|
/* */
|
|
/* Historie: */
|
|
/* 18. 8.1998 BookKeeping-Aufruf bei BSS */
|
|
/* 2. 1.1998 ChkPC umgestellt */
|
|
/* */
|
|
/*****************************************************************************/
|
|
|
|
#include "stdinc.h"
|
|
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
#include "nls.h"
|
|
#include "endian.h"
|
|
#include "strutil.h"
|
|
#include "bpemu.h"
|
|
#include "chunks.h"
|
|
#include "asmdef.h"
|
|
#include "asmsub.h"
|
|
#include "asmpars.h"
|
|
#include "asmallg.h"
|
|
#include "codepseudo.h"
|
|
#include "codevars.h"
|
|
|
|
#define TwoOpCount 12
|
|
#define OneOpCount 6
|
|
#define JmpCount 10
|
|
|
|
typedef struct
|
|
{
|
|
char *Name;
|
|
Word Code;
|
|
} FixedOrder;
|
|
|
|
typedef struct
|
|
{
|
|
char *Name;
|
|
Boolean MayByte;
|
|
Word Code;
|
|
} OneOpOrder;
|
|
|
|
|
|
static CPUVar CPUMSP430;
|
|
|
|
static FixedOrder *TwoOpOrders;
|
|
static OneOpOrder *OneOpOrders;
|
|
static FixedOrder *JmpOrders;
|
|
|
|
static Word AdrMode,AdrMode2,AdrPart,AdrPart2;
|
|
static Byte AdrCnt2;
|
|
static Word AdrVal,AdrVal2;
|
|
static Byte OpSize;
|
|
static Word PCDist;
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
static void AddTwoOp(char *NName, Word NCode)
|
|
BEGIN
|
|
if (InstrZ>=TwoOpCount) exit(255);
|
|
TwoOpOrders[InstrZ].Name=NName;
|
|
TwoOpOrders[InstrZ++].Code=NCode;
|
|
END
|
|
|
|
static void AddOneOp(char *NName, Boolean NMay, Word NCode)
|
|
BEGIN
|
|
if (InstrZ>=OneOpCount) exit(255);
|
|
OneOpOrders[InstrZ].Name=NName;
|
|
OneOpOrders[InstrZ].MayByte=NMay;
|
|
OneOpOrders[InstrZ++].Code=NCode;
|
|
END
|
|
|
|
static void AddJmp(char *NName, Word NCode)
|
|
BEGIN
|
|
if (InstrZ>=JmpCount) exit(255);
|
|
JmpOrders[InstrZ].Name=NName;
|
|
JmpOrders[InstrZ++].Code=NCode;
|
|
END
|
|
|
|
static void InitFields(void)
|
|
BEGIN
|
|
TwoOpOrders=(FixedOrder *) malloc(sizeof(FixedOrder)*TwoOpCount); InstrZ=0;
|
|
AddTwoOp("MOV" ,0x4000); AddTwoOp("ADD" ,0x5000);
|
|
AddTwoOp("ADDC",0x6000); AddTwoOp("SUBC",0x7000);
|
|
AddTwoOp("SUB" ,0x8000); AddTwoOp("CMP" ,0x9000);
|
|
AddTwoOp("DADD",0xa000); AddTwoOp("BIT" ,0xb000);
|
|
AddTwoOp("BIC" ,0xc000); AddTwoOp("BIS" ,0xd000);
|
|
AddTwoOp("XOR" ,0xe000); AddTwoOp("AND" ,0xf000);
|
|
|
|
OneOpOrders=(OneOpOrder *) malloc(sizeof(OneOpOrder)*OneOpCount); InstrZ=0;
|
|
AddOneOp("RRC" ,True ,0x1000); AddOneOp("RRA" ,True ,0x1100);
|
|
AddOneOp("PUSH",True ,0x1200); AddOneOp("SWPB",False,0x1080);
|
|
AddOneOp("CALL",False,0x1280); AddOneOp("SXT" ,False,0x1180);
|
|
|
|
JmpOrders=(FixedOrder *) malloc(sizeof(FixedOrder)*JmpCount); InstrZ=0;
|
|
AddJmp("JNE" ,0x2000); AddJmp("JNZ" ,0x2000);
|
|
AddJmp("JE" ,0x2400); AddJmp("JZ" ,0x2400);
|
|
AddJmp("JNC" ,0x2800); AddJmp("JC" ,0x2c00);
|
|
AddJmp("JN" ,0x3000); AddJmp("JGE" ,0x3400);
|
|
AddJmp("JL" ,0x3800); AddJmp("JMP" ,0x3C00);
|
|
END
|
|
|
|
static void DeinitFields(void)
|
|
BEGIN
|
|
free(TwoOpOrders);
|
|
free(OneOpOrders);
|
|
free(JmpOrders);
|
|
END
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
static void ResetAdr(void)
|
|
BEGIN
|
|
AdrMode=0xff; AdrCnt=0;
|
|
END
|
|
|
|
static void ChkAdr(Byte Mask)
|
|
BEGIN
|
|
if ((AdrMode!=0xff) AND ((Mask & (1 << AdrMode))==0))
|
|
BEGIN
|
|
ResetAdr(); WrError(1350);
|
|
END
|
|
END
|
|
|
|
static Boolean DecodeReg(char *Asc, Word *Erg)
|
|
BEGIN
|
|
Boolean OK;
|
|
|
|
if (strcasecmp(Asc,"PC")==0)
|
|
BEGIN
|
|
*Erg=0; return True;
|
|
END
|
|
else if (strcasecmp(Asc,"SP")==0)
|
|
BEGIN
|
|
*Erg=1; return True;
|
|
END
|
|
else if (strcasecmp(Asc,"SR")==0)
|
|
BEGIN
|
|
*Erg=2; return True;
|
|
END
|
|
if ((toupper(*Asc)=='R') AND (strlen(Asc)>=2) AND (strlen(Asc)<=3))
|
|
BEGIN
|
|
*Erg=ConstLongInt(Asc+1,&OK);
|
|
return ((OK) AND (*Erg<16));
|
|
END
|
|
return False;
|
|
END
|
|
|
|
static void DecodeAdr(char *Asc, Byte Mask, Boolean MayImm)
|
|
BEGIN
|
|
Word AdrWord;
|
|
Boolean OK;
|
|
char *p;
|
|
|
|
ResetAdr();
|
|
|
|
/* immediate */
|
|
|
|
if (*Asc=='#')
|
|
BEGIN
|
|
if (NOT MayImm) WrError(1350);
|
|
else
|
|
BEGIN
|
|
AdrWord=EvalIntExpression(Asc+1,(OpSize==1)?Int8:Int16,&OK);
|
|
if (OK)
|
|
BEGIN
|
|
switch (AdrWord)
|
|
BEGIN
|
|
case 0:
|
|
AdrPart=3; AdrMode=0;
|
|
break;
|
|
case 1:
|
|
AdrPart=3; AdrMode=1;
|
|
break;
|
|
case 2:
|
|
AdrPart=3; AdrMode=2;
|
|
break;
|
|
case 4:
|
|
AdrPart=2; AdrMode=2;
|
|
break;
|
|
case 8:
|
|
AdrPart=2; AdrMode=3;
|
|
break;
|
|
case 0xffff:
|
|
AdrPart=3; AdrMode=3;
|
|
break;
|
|
default:
|
|
AdrVal=AdrWord; AdrCnt=1;
|
|
AdrPart=0; AdrMode=3;
|
|
break;
|
|
END
|
|
END
|
|
END
|
|
ChkAdr(Mask); return;
|
|
END
|
|
|
|
/* absolut */
|
|
|
|
if (*Asc=='&')
|
|
BEGIN
|
|
AdrVal=EvalIntExpression(Asc+1,UInt16,&OK);
|
|
if (OK)
|
|
BEGIN
|
|
AdrMode=1; AdrPart=2; AdrCnt=1;
|
|
END
|
|
ChkAdr(Mask); return;
|
|
END
|
|
|
|
/* Register */
|
|
|
|
if (DecodeReg(Asc,&AdrPart))
|
|
BEGIN
|
|
if (AdrPart==3) WrXError(1445,Asc);
|
|
else AdrMode=0;
|
|
ChkAdr(Mask); return;
|
|
END
|
|
|
|
/* Displacement */
|
|
|
|
if (Asc[strlen(Asc)-1]==')')
|
|
BEGIN
|
|
Asc[strlen(Asc)-1]='\0';
|
|
p=RQuotPos(Asc,'(');
|
|
if (p!=Nil)
|
|
BEGIN
|
|
if (DecodeReg(p+1,&AdrPart))
|
|
BEGIN
|
|
*p='\0';
|
|
AdrVal=EvalIntExpression(Asc,Int16,&OK);
|
|
if (OK)
|
|
if ((AdrPart==2) OR (AdrPart==3)) WrXError(1445,Asc);
|
|
else if ((AdrVal==0) AND ((Mask & 4)!=0)) AdrMode=2;
|
|
else
|
|
BEGIN
|
|
AdrCnt=1; AdrMode=1;
|
|
END
|
|
*p='(';
|
|
ChkAdr(Mask); return;
|
|
END
|
|
END
|
|
Asc[strlen(Asc)]=')';
|
|
END
|
|
|
|
/* indirekt mit/ohne Autoinkrement */
|
|
|
|
if ((*Asc=='@') OR (*Asc=='*'))
|
|
BEGIN
|
|
if (Asc[strlen(Asc)-1]=='+')
|
|
BEGIN
|
|
AdrWord=1; Asc[strlen(Asc)-1]='\0';
|
|
END
|
|
else AdrWord=0;
|
|
if (NOT DecodeReg(Asc+1,&AdrPart)) WrXError(1445,Asc);
|
|
else if ((AdrPart==2) OR (AdrPart==3)) WrXError(1445,Asc);
|
|
else if ((AdrWord==0) AND ((Mask & 4)==0))
|
|
BEGIN
|
|
AdrVal=0; AdrCnt=1; AdrMode=1;
|
|
END
|
|
else AdrMode=2+AdrWord;
|
|
ChkAdr(Mask); return;
|
|
END
|
|
|
|
/* bleibt PC-relativ */
|
|
|
|
AdrWord=EvalIntExpression(Asc,UInt16,&OK)-EProgCounter()-PCDist;
|
|
if (OK)
|
|
BEGIN
|
|
AdrPart=0; AdrMode=1; AdrCnt=1; AdrVal=AdrWord;
|
|
END
|
|
|
|
ChkAdr(Mask);
|
|
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
|
|
TempResult t;
|
|
Word HVal16;
|
|
int z;
|
|
char *p;
|
|
Boolean OK;
|
|
|
|
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 ((Odd(HVal16)) AND (DoPadding)) HVal16++;
|
|
DontPrint=True; CodeLen=HVal16;
|
|
BookKeeping();
|
|
END
|
|
END
|
|
return True;
|
|
END
|
|
|
|
/* float exp (8bit bias 128) sign mant (impl. norm.)
|
|
double exp (8bit bias 128) sign mant (impl. norm.) */
|
|
|
|
return False;
|
|
END
|
|
|
|
static void MakeCode_MSP(void)
|
|
BEGIN
|
|
int z;
|
|
Integer AdrInt;
|
|
Boolean OK;
|
|
|
|
CodeLen=0; DontPrint=False;
|
|
|
|
/* zu ignorierendes */
|
|
|
|
if (Memo("")) return;
|
|
|
|
/* Attribut bearbeiten */
|
|
|
|
if (*AttrPart=='\0') OpSize=0;
|
|
else if (strlen(AttrPart)>1) WrError(1107);
|
|
else
|
|
switch (toupper(*AttrPart))
|
|
BEGIN
|
|
case 'B': OpSize=1; break;
|
|
case 'W': OpSize=0; break;
|
|
default: WrError(1107); return;
|
|
END
|
|
|
|
/* Pseudoanweisungen */
|
|
|
|
if (DecodePseudo()) return;
|
|
|
|
/* zwei Operanden */
|
|
|
|
for (z=0; z<TwoOpCount; z++)
|
|
if (Memo(TwoOpOrders[z].Name))
|
|
BEGIN
|
|
if (ArgCnt!=2) WrError(1110);
|
|
else
|
|
BEGIN
|
|
PCDist=2; DecodeAdr(ArgStr[1],15,True);
|
|
if (AdrMode!=0xff)
|
|
BEGIN
|
|
AdrMode2=AdrMode; AdrPart2=AdrPart; AdrCnt2=AdrCnt; AdrVal2=AdrVal;
|
|
PCDist+=AdrCnt2 << 1; DecodeAdr(ArgStr[2],3,False);
|
|
if (AdrMode!=0xff)
|
|
BEGIN
|
|
WAsmCode[0]=TwoOpOrders[z].Code+(AdrPart2 << 8)+(AdrMode << 7)
|
|
+(OpSize << 6)+(AdrMode2 << 4)+AdrPart;
|
|
memcpy(WAsmCode+1,&AdrVal2,AdrCnt2 << 1);
|
|
memcpy(WAsmCode+1+AdrCnt2,&AdrVal,AdrCnt << 1);
|
|
CodeLen=(1+AdrCnt+AdrCnt2) << 1;
|
|
END
|
|
END
|
|
END
|
|
return;
|
|
END
|
|
|
|
/* ein Operand */
|
|
|
|
for (z=0; z<OneOpCount; z++)
|
|
if (Memo(OneOpOrders[z].Name))
|
|
BEGIN
|
|
if (ArgCnt!=1) WrError(1110);
|
|
else if ((OpSize==1) AND (NOT OneOpOrders[z].MayByte)) WrError(1130);
|
|
else
|
|
BEGIN
|
|
PCDist=2; DecodeAdr(ArgStr[1],15,False);
|
|
if (AdrMode!=0xff)
|
|
BEGIN
|
|
WAsmCode[0]=OneOpOrders[z].Code+(OpSize << 6)+(AdrMode << 4)+AdrPart;
|
|
memcpy(WAsmCode+1,&AdrVal,AdrCnt << 1);
|
|
CodeLen=(1+AdrCnt) << 1;
|
|
END
|
|
END
|
|
return;
|
|
END
|
|
|
|
/* kein Operand */
|
|
|
|
if (Memo("RETI"))
|
|
BEGIN
|
|
if (ArgCnt!=0) WrError(1110);
|
|
else if (*AttrPart!='\0') WrError(1100);
|
|
else if (OpSize!=0) WrError(1130);
|
|
else
|
|
BEGIN
|
|
WAsmCode[0]=0x1300; CodeLen=2;
|
|
END
|
|
return;
|
|
END
|
|
|
|
/* Spruenge */
|
|
|
|
for (z=0; z<JmpCount; z++)
|
|
if (Memo(JmpOrders[z].Name))
|
|
BEGIN
|
|
if (ArgCnt!=1) WrError(1110);
|
|
else if (OpSize!=0) WrError(1130);
|
|
else
|
|
BEGIN
|
|
AdrInt=EvalIntExpression(ArgStr[1],UInt16,&OK)-(EProgCounter()+2);
|
|
if (OK)
|
|
if (Odd(AdrInt)) WrError(1375);
|
|
else if ((NOT SymbolQuestionable) AND ((AdrInt<-1024) OR (AdrInt>1022))) WrError(1370);
|
|
else
|
|
BEGIN
|
|
WAsmCode[0]=JmpOrders[z].Code+((AdrInt >> 1) & 0x3ff);
|
|
CodeLen=2;
|
|
END
|
|
END
|
|
return;
|
|
END
|
|
|
|
WrXError(1200,OpPart);
|
|
END
|
|
|
|
static Boolean IsDef_MSP(void)
|
|
BEGIN
|
|
return False;
|
|
END
|
|
|
|
static void SwitchFrom_MSP(void)
|
|
BEGIN
|
|
DeinitFields(); ClearONOFF();
|
|
END
|
|
|
|
static void SwitchTo_MSP(void)
|
|
BEGIN
|
|
TurnWords=True; ConstMode=ConstModeIntel; SetIsOccupied=False;
|
|
|
|
PCSymbol="$"; HeaderID=0x4a; NOPCode=0x4303; /* = MOV #0,#0 */
|
|
DivideChars=","; HasAttrs=True; AttrChars=".";
|
|
|
|
ValidSegs=1<<SegCode;
|
|
Grans[SegCode]=1; ListGrans[SegCode]=2; SegInits[SegCode]=0;
|
|
SegLimits[SegCode] = 0xffff;
|
|
|
|
AddONOFF("PADDING", &DoPadding, DoPaddingName,False);
|
|
|
|
MakeCode=MakeCode_MSP; IsDef=IsDef_MSP;
|
|
SwitchFrom=SwitchFrom_MSP; InitFields();
|
|
END
|
|
|
|
void codemsp_init(void)
|
|
BEGIN
|
|
CPUMSP430=AddCPU("MSP430",SwitchTo_MSP);
|
|
END
|