/* codemsp.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Codegenerator MSP430 */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <ctype.h>
#include <string.h>
#include "nls.h"
#include "be_le.h"
#include "strutil.h"
#include "bpemu.h"
#include "chunks.h"
#include "errmsg.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmcode.h"
#include "asmpars.h"
#include "asmallg.h"
#include "onoff_common.h"
#include "chartrans.h"
#include "asmitree.h"
#include "codepseudo.h"
#include "codevars.h"
typedef struct
{
Boolean MayByte
;
Word Code
;
} OneOpOrder
;
typedef enum
{
eModeReg
= 0,
eModeRegDisp
= 1,
eModeIReg
= 2,
eModeIRegAutoInc
= 3,
eModeNone
= 0xff
} tMode
;
#define MModeReg (1 << eModeReg)
#define MModeRegDisp (1 << eModeRegDisp)
#define MModeIReg (1 << eModeIReg)
#define MModeIRegAutoInc (1 << eModeIRegAutoInc)
#define MModeAs 15
#define MModeAd 3
typedef enum
{
eExtModeNo
= 0,
eExtModeYes
= 1
} tExtMode
;
typedef enum
{
eOpSizeB
= 0,
eOpSizeW
= 1,
eOpSizeA
= 2,
eOpSizeCnt
,
eOpSizeDefault
= eOpSizeW
} tOpSize
;
#define RegPC 0
#define RegSP 1
#define RegSR 2
#define RegCG1 2
#define RegCG2 3
#define REG_PC 0
#define REG_SP 1
#define REG_SR 2
typedef struct
{
Word Mode
, Part
, Cnt
;
LongWord Val
;
Boolean WasImm
, WasAbs
;
} tAdrParts
;
/* float exp (8bit bias 128) sign mant (impl. norm.)
double exp (8bit bias 128) sign mant (impl. norm.) */
static CPUVar CPUMSP430
, CPUMSP430X
;
static OneOpOrder
*OneOpOrders
;
static tOpSize OpSize
;
static Word PCDist
, MultPrefix
;
static IntType AdrIntType
, DispIntType
;
static const IntType OpSizeIntTypes
[eOpSizeCnt
] = { Int8
, Int16
, Int20
};
/*-------------------------------------------------------------------------*/
static void ResetAdr
(tAdrParts
*pAdrParts
)
{
pAdrParts
->Mode
= eModeNone
;
pAdrParts
->Part
= 0;
pAdrParts
->Cnt
= 0;
pAdrParts
->WasImm
=
pAdrParts
->WasAbs
= False
;
}
static Boolean ChkAdr
(Byte Mask
, tAdrParts
*pAdrParts
)
{
if ((pAdrParts
->Mode
!= 0xff) && ((Mask
& (1 << pAdrParts
->Mode
)) == 0))
{
ResetAdr
(pAdrParts
);
WrError
(ErrNum_InvAddrMode
);
return False
;
}
return True
;
}
/*!------------------------------------------------------------------------
* \fn DecodeRegCore(const char *pArg, Word *pResult)
* \brief check whether argument is a CPU register
* \param pArg argument to check
* \param pResult numeric register value if yes
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean DecodeRegCore
(const char *pArg
, Word
*pResult
)
{
if (!as_strcasecmp
(pArg
, "PC"))
{
*pResult
= REGSYM_FLAG_ALIAS
| REG_PC
; return True
;
}
else if (!as_strcasecmp
(pArg
,"SP"))
{
*pResult
= REGSYM_FLAG_ALIAS
| REG_SP
; return True
;
}
else if (!as_strcasecmp
(pArg
, "SR"))
{
*pResult
= REGSYM_FLAG_ALIAS
| REG_SR
; return True
;
}
if ((as_toupper
(*pArg
) == 'R') && (strlen(pArg
) >= 2) && (strlen(pArg
) <= 3))
{
Boolean OK
;
*pResult
= ConstLongInt
(pArg
+ 1, &OK
, 10);
return OK
&& (*pResult
< 16);
}
return False
;
}
/*!------------------------------------------------------------------------
* \fn DissectReg_MSP(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
* \brief dissect register symbols - MSP variant
* \param pDest destination buffer
* \param DestSize destination buffer size
* \param Value numeric register value
* \param InpSize register size
* ------------------------------------------------------------------------ */
static void DissectReg_MSP
(char *pDest
, size_t DestSize
, tRegInt Value
, tSymbolSize InpSize
)
{
switch (InpSize
)
{
case eSymbolSize8Bit
:
switch (Value
)
{
case REGSYM_FLAG_ALIAS
| REG_PC
:
as_snprintf
(pDest
, DestSize
, "PC");
break;
case REGSYM_FLAG_ALIAS
| REG_SP
:
as_snprintf
(pDest
, DestSize
, "SP");
break;
case REGSYM_FLAG_ALIAS
| REG_SR
:
as_snprintf
(pDest
, DestSize
, "SR");
break;
default:
as_snprintf
(pDest
, DestSize
, "R%u", (unsigned)Value
);
}
break;
default:
as_snprintf
(pDest
, DestSize
, "%d-%u", (int)InpSize
, (unsigned)Value
);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeReg(const tStrComp *pArg, Word *pResult, Boolean MustBeReg)
* \brief check whether argument is a CPU register or register alias
* \param pArg argument to check
* \param pResult numeric register value if yes
* \param MustBeReg excpecting register as arg
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean DecodeReg
(const tStrComp
*pArg
, Word
*pResult
, Boolean MustBeReg
)
{
tRegDescr RegDescr
;
tEvalResult EvalResult
;
tRegEvalResult RegEvalResult
;
if (DecodeRegCore
(pArg
->str.
p_str, pResult
))
{
*pResult
&= ~REGSYM_FLAG_ALIAS
;
return True
;
}
RegEvalResult
= EvalStrRegExpressionAsOperand
(pArg
, &RegDescr
, &EvalResult
, eSymbolSize8Bit
, MustBeReg
);
*pResult
= RegDescr.
Reg & ~REGSYM_FLAG_ALIAS
;
return (RegEvalResult
== eIsReg
);
}
static void FillAdrPartsImm
(tAdrParts
*pAdrParts
, LongWord Value
, Boolean ForceLong
)
{
ResetAdr
(pAdrParts
);
pAdrParts
->WasImm
= True
;
pAdrParts
->Val
= Value
;
/* assume no usage of constant generators */
pAdrParts
->Part
= RegPC
;
/* constant generators allowed at all? */
if (!ForceLong
)
{
/* special treatment for -1 since it depends on the operand size: */
if ((Value
== 0xffffffff)
|| ((OpSize
== eOpSizeB
) && (Value
== 0xff))
|| ((OpSize
== eOpSizeW
) && (Value
== 0xffff))
|| ((OpSize
== eOpSizeA
) && (Value
== 0xfffff)))
{
pAdrParts
->Cnt
= 0;
pAdrParts
->Part
= RegCG2
;
pAdrParts
->Mode
= eModeIRegAutoInc
;
}
else switch (Value
)
{
case 0:
pAdrParts
->Part
= RegCG2
;
pAdrParts
->Mode
= eModeReg
;
break;
case 1:
pAdrParts
->Part
= RegCG2
;
pAdrParts
->Mode
= eModeRegDisp
;
break;
case 2:
pAdrParts
->Part
= RegCG2
;
pAdrParts
->Mode
= eModeIReg
;
break;
case 4:
pAdrParts
->Part
= RegCG1
;
pAdrParts
->Mode
= eModeIReg
;
break;
case 8:
pAdrParts
->Part
= RegCG1
;
pAdrParts
->Mode
= eModeIRegAutoInc
;
break;
default:
break;
}
}
/* constant generators not used, in one or the other way -> use
@PC++ to dispose constant */
if (pAdrParts
->Part
== RegPC
)
{
pAdrParts
->Cnt
= 1;
pAdrParts
->Mode
= eModeIRegAutoInc
;
}
}
static Boolean DecodeAdr
(const tStrComp
*pArg
, tExtMode ExtMode
, Byte Mask
, Boolean MayImm
, tAdrParts
*pAdrParts
)
{
LongWord AdrWord
, CurrPC
;
Word Reg
;
Boolean OK
;
char *p
;
IntType ThisAdrIntType
= (ExtMode
== eExtModeYes
) ? AdrIntType
: UInt16
;
IntType ThisDispIntType
= (ExtMode
== eExtModeYes
) ? DispIntType
: Int16
;
int ArgLen
;
ResetAdr
(pAdrParts
);
/* immediate */
if (*pArg
->str.
p_str == '#')
{
if (!MayImm
) WrError
(ErrNum_InvAddrMode
);
else
{
int ForceLong
= (pArg
->str.
p_str[1] == '>') ? 1 : 0;
AdrWord
= EvalStrIntExpressionOffs
(pArg
, 1 + ForceLong
, OpSizeIntTypes
[OpSize
], &OK
);
if (OK
)
{
FillAdrPartsImm
(pAdrParts
, AdrWord
, ForceLong
);
}
}
return ChkAdr
(Mask
, pAdrParts
);
}
/* absolut */
if (*pArg
->str.
p_str == '&')
{
pAdrParts
->Val
= EvalStrIntExpressionOffs
(pArg
, 1, ThisAdrIntType
, &OK
);
if (OK
)
{
pAdrParts
->WasAbs
= True
;
pAdrParts
->Mode
= eModeRegDisp
;
pAdrParts
->Part
= RegCG1
; /* == 0 with As/Ad=1 */
pAdrParts
->Cnt
= 1;
}
return ChkAdr
(Mask
, pAdrParts
);
}
/* Register */
switch (DecodeReg
(pArg
, &Reg
, False
))
{
case eIsReg
:
if (Reg
== RegCG2
) WrStrErrorPos
(ErrNum_InvReg
, pArg
);
else
{
pAdrParts
->Mode
= eModeReg
;
pAdrParts
->Part
= Reg
;
}
return ChkAdr
(Mask
, pAdrParts
);
case eIsNoReg
:
break;
case eRegAbort
:
return False
;
}
/* Displacement */
ArgLen
= strlen(pArg
->str.
p_str);
if ((*pArg
->str.
p_str) && (pArg
->str.
p_str[ArgLen
- 1] == ')'))
{
tStrComp Arg
= *pArg
;
StrCompShorten
(&Arg
, 1);
p
= RQuotPos
(Arg.
str.
p_str, '(');
if (p
)
{
tStrComp RegComp
, OffsComp
;
char Save
;
Save
= StrCompSplitRef
(&OffsComp
, &RegComp
, &Arg
, p
);
if (DecodeReg
(&RegComp
, &Reg
, True
) == eIsReg
)
{
pAdrParts
->Val
= EvalStrIntExpression
(&OffsComp
, ThisDispIntType
, &OK
);
if (OK
)
{
if ((Reg
== 2) || (Reg
== 3)) WrStrErrorPos
(ErrNum_InvReg
, &RegComp
);
else if ((pAdrParts
->Val
== 0) && ((Mask
& 4) != 0))
{
pAdrParts
->Part
= Reg
;
pAdrParts
->Mode
= eModeIReg
;
}
else
{
pAdrParts
->Part
= Reg
;
pAdrParts
->Cnt
= 1;
pAdrParts
->Mode
= eModeRegDisp
;
}
}
}
*p
= Save
;
}
pArg
->str.
p_str[ArgLen
- 1] = ')';
if (pAdrParts
->Mode
!= eModeNone
)
return ChkAdr
(Mask
, pAdrParts
);
}
/* indirekt mit/ohne Autoinkrement */
if ((*pArg
->str.
p_str == '@') || (*pArg
->str.
p_str == '*'))
{
Boolean AutoInc
= False
;
tStrComp Arg
;
StrCompRefRight
(&Arg
, pArg
, 1);
ArgLen
= strlen(Arg.
str.
p_str);
if (Arg.
str.
p_str[ArgLen
- 1] == '+')
{
AutoInc
= True
;
StrCompShorten
(&Arg
, 1);
}
if (DecodeReg
(&Arg
, &Reg
, True
) != eIsReg
);
else if ((Reg
== 2) || (Reg
== 3)) WrStrErrorPos
(ErrNum_InvReg
, &Arg
);
else if (!AutoInc
&& ((Mask
& MModeIReg
) == 0))
{
pAdrParts
->Part
= Reg
;
pAdrParts
->Val
= 0;
pAdrParts
->Cnt
= 1;
pAdrParts
->Mode
= eModeRegDisp
;
}
else
{
pAdrParts
->Part
= Reg
;
pAdrParts
->Mode
= AutoInc
? eModeIRegAutoInc
: eModeIReg
;
}
return ChkAdr
(Mask
, pAdrParts
);
}
/* bleibt PC-relativ aka 'symbolic mode': */
if (!PCDist
)
{
fprintf(stderr
, "internal error: PCDist not set for '%s'\n", OpPart.
str.
p_str);
exit(10);
}
CurrPC
= EProgCounter
() + PCDist
;
/* extended instruction (on 430X): use the full 20 bit displacement: */
if (ExtMode
== eExtModeYes
)
{
AdrWord
= (EvalStrIntExpression
(pArg
, UInt20
, &OK
) - CurrPC
) & 0xfffff;
}
/* non-extended instruction on 430X: if the current PC is within the
first 64K, bits 16..19 will be cleared after addition, i.e. the
target address must also be within the first 64K: */
else if (MomCPU
>= CPUMSP430X
)
{
if (CurrPC
<= 0xffff)
{
AdrWord
= (EvalStrIntExpression
(pArg
, UInt16
, &OK
) - CurrPC
) & 0xffff;
}
else
{
AdrWord
= (EvalStrIntExpression
(pArg
, UInt20
, &OK
) - CurrPC
) & 0xfffff;
if ((AdrWord
> 0x7fff) && (AdrWord
< 0xf8000))
{
WrError
(ErrNum_OverRange
);
OK
= False
;
}
}
}
/* non-extended instruction on 430: all within 64K with wraparound */
else
{
AdrWord
= (EvalStrIntExpression
(pArg
, UInt16
, &OK
) - CurrPC
) & 0xffff;
}
if (OK
)
{
pAdrParts
->Part
= RegPC
;
pAdrParts
->Mode
= eModeRegDisp
;
pAdrParts
->Cnt
= 1;
pAdrParts
->Val
= AdrWord
;
}
return ChkAdr
(Mask
, pAdrParts
);
}
static Word GetBW
(void)
{
return (OpSize
== eOpSizeB
) || (OpSize
== eOpSizeA
) ? 0x0040 : 0x0000;
}
static Word GetAL
(void)
{
return (OpSize
== eOpSizeW
) || (OpSize
== eOpSizeB
) ? 0x0040 : 0x0000;
}
static Word GetMult
(const tStrComp
*pArg
, Boolean
*pOK
)
{
Word Result
= 0x0000;
switch (DecodeReg
(pArg
, &Result
, False
))
{
case eIsReg
:
*pOK
= True
;
return Result
| 0x0080;
case eIsNoReg
:
break;
case eRegAbort
:
*pOK
= False
;
return 0;
}
if (*pArg
->str.
p_str == '#')
{
tSymbolFlags Flags
;
Result
= EvalStrIntExpressionOffsWithFlags
(pArg
, 1, UInt5
, pOK
, &Flags
);
if (*pOK
)
{
if (mFirstPassUnknown
(Flags
))
Result
= 1;
if (!ChkRange
(Result
, 1, 16))
*pOK
= False
;
else
Result
--;
}
}
else
*pOK
= False
;
return Result
;
}
/*-------------------------------------------------------------------------*/
static void PutByte
(Word Value
)
{
if (CodeLen
& 1)
WAsmCode
[CodeLen
>> 1] = (Value
<< 8) | BAsmCode
[CodeLen
- 1];
else
BAsmCode
[CodeLen
] = Value
;
CodeLen
++;
}
static void AppendAdrVals
(const tAdrParts
*pParts
)
{
Word i
;
for (i
= 0; i
< pParts
->Cnt
; i
++)
{
WAsmCode
[CodeLen
>> 1] = pParts
->Val
;
CodeLen
+= 2;
}
}
static void ConstructTwoOp
(Word Code
, const tAdrParts
*pSrcParts
, const tAdrParts
*pDestParts
)
{
WAsmCode
[CodeLen
>> 1] = Code
| (pSrcParts
->Part
<< 8) | (pDestParts
->Mode
<< 7)
| GetBW
() | (pSrcParts
->Mode
<< 4) | pDestParts
->Part
;
CodeLen
+= 2;
AppendAdrVals
(pSrcParts
);
AppendAdrVals
(pDestParts
);
}
static void ConstructTwoOpX
(Word Code
, const tAdrParts
*pSrcParts
, const tAdrParts
*pDestParts
)
{
Word Prefix
= 0x1800 | GetAL
();
if ((eModeReg
!= pSrcParts
->Mode
) || (eModeReg
!= pDestParts
->Mode
))
{
if (pSrcParts
->Cnt
)
Prefix
|= ((pSrcParts
->Val
>> 16) & 15) << 7;
if (pDestParts
->Cnt
)
Prefix
|= ((pDestParts
->Val
>> 16) & 15);
}
/* take over multiply prefix for register<->register ops only */
else
{
Prefix
|= MultPrefix
;
MultPrefix
= 0;
}
WAsmCode
[CodeLen
>> 1] = Prefix
; CodeLen
+= 2;
ConstructTwoOp
(Code
, pSrcParts
, pDestParts
);
}
static void DecodeFixed
(Word Code
)
{
if (!ChkArgCnt
(0, 0));
else if (*AttrPart.
str.
p_str) WrError
(ErrNum_UseLessAttr
);
else if (OpSize
!= eOpSizeDefault
) WrError
(ErrNum_InvOpSize
);
else
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
WAsmCode
[0] = Code
; CodeLen
= 2;
}
}
static void DecodeTwoOp
(Word Code
)
{
tAdrParts SrcParts
, DestParts
;
if (!ChkArgCnt
(2, 2));
else if (OpSize
> eOpSizeW
) WrError
(ErrNum_InvOpSize
);
else
{
PCDist
= 2;
if (DecodeAdr
(&ArgStr
[1], eExtModeNo
, 15, True
, &SrcParts
))
{
PCDist
+= SrcParts.
Cnt << 1;
if (DecodeAdr
(&ArgStr
[2], eExtModeNo
, 3, False
, &DestParts
))
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
ConstructTwoOp
(Code
, &SrcParts
, &DestParts
);
}
}
}
}
static void DecodeTwoOpX
(Word Code
)
{
tAdrParts SrcParts
, DestParts
;
Code
&= ~
1;
if (!ChkArgCnt
(2, 2))
return;
PCDist
= 4;
if (DecodeAdr
(&ArgStr
[1], eExtModeYes
, MModeAs
, True
, &SrcParts
))
{
PCDist
+= SrcParts.
Cnt << 1;
if (DecodeAdr
(&ArgStr
[2], eExtModeYes
, MModeAd
, False
, &DestParts
))
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
ConstructTwoOpX
(Code
, &SrcParts
, &DestParts
);
}
}
}
static void DecodeEmulOneToTwo
(Word Code
)
{
Byte SrcSpec
;
tAdrParts SrcParts
, DestParts
;
/* separate src spec & opcode */
SrcSpec
= Lo
(Code
);
Code
&= 0xff00;
if (!ChkArgCnt
(1, 1))
return;
if (OpSize
> eOpSizeW
)
{
WrError
(ErrNum_InvOpSize
);
return;
}
/* Decode operand:
- Ad modes always allowed
- for Src == Dest, also allow @Rn+: */
PCDist
= 2;
if (!DecodeAdr
(&ArgStr
[1], eExtModeNo
, MModeAd
| ((SrcSpec
== 0xaa) ? MModeIRegAutoInc
: 0), False
, &DestParts
))
return;
/* filter immediate out separately (we get it as d(PC): */
if (DestParts.
WasImm)
{
WrError
(ErrNum_InvAddrMode
);
return;
}
/* deduce src operand: 0xaa = special value for Src == Dest: */
if (SrcSpec
== 0xaa)
{
/* default assumption: */
SrcParts
= DestParts
;
/* @Rn+: is transformed to @Rn+,-opsize(Rn): */
if (SrcParts.
Mode == eModeIRegAutoInc
)
{
static const Byte MemLen
[3] = { 1, 2, 4 };
DestParts.
Mode = eModeRegDisp
;
DestParts.
Val = (0 - MemLen
[OpSize
]) & 0xffff;
DestParts.
Cnt = 1;
}
/* for PC-relative addressing, fix up destination displacement and
complain on displacement overflow: */
else if ((DestParts.
Mode == eModeRegDisp
) && (DestParts.
Part == RegPC
))
{
LongWord NewDist
= DestParts.
Val - 2;
if ((NewDist
& 0x8000) != (DestParts.
Val & 0x8000))
{
WrError
(ErrNum_DistTooBig
);
return;
}
DestParts.
Val = NewDist
;
}
/* transform 0(Rn) as Dest back to @Rn as Src: */
else if ((SrcParts.
Mode == eModeRegDisp
) && (DestParts.
Val == 0))
{
SrcParts.
Mode = eModeIReg
;
SrcParts.
Cnt = 0;
}
}
/* Src == other (constant) value: 0xff means -1: */
else
FillAdrPartsImm
(&SrcParts
, SrcSpec
== 0xff ? 0xffffffff : SrcSpec
, False
);
/* assemble like 2-op instruction: */
ConstructTwoOp
(Code
, &SrcParts
, &DestParts
);
}
static void DecodeBR
(Word Code
)
{
tAdrParts DstParts
, SrcParts
;
PCDist
= 2;
if (!ChkArgCnt
(1, 1));
else if (*AttrPart.
str.
p_str) WrError
(ErrNum_UseLessAttr
);
else if (DecodeAdr
(&ArgStr
[1], eExtModeNo
, MModeAs
, True
, &SrcParts
))
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
ResetAdr
(&DstParts
);
DstParts.
Mode = eModeReg
;
DstParts.
Part = RegPC
;
ConstructTwoOp
(Code
, &SrcParts
, &DstParts
);
}
}
static void DecodeEmulOneToTwoX
(Word Code
)
{
Byte SrcSpec
;
tAdrParts SrcParts
, DestParts
;
/* separate src spec & opcode */
SrcSpec
= Lo
(Code
);
Code
&= 0xff00;
if (!ChkArgCnt
(1, 1))
return;
/* Decode operand:
- Ad modes always allowed
- for Src == Dest, also allow @Rn+: */
PCDist
= 4;
if (!DecodeAdr
(&ArgStr
[1], eExtModeYes
, MModeAd
| ((SrcSpec
== 0xaa) ? MModeIRegAutoInc
: 0), False
, &DestParts
))
return;
/* filter immediate out separately (we get it as d(PC): */
if (DestParts.
WasImm)
{
WrError
(ErrNum_InvAddrMode
);
return;
}
/* deduce src operand: 0xaa = special value for Src == Dest: */
if (SrcSpec
== 0xaa)
{
/* default assumption: */
SrcParts
= DestParts
;
/* @Rn+: is transformed to @Rn+,-opsize(Rn): */
if (SrcParts.
Mode == eModeIRegAutoInc
)
{
static const Byte MemLen
[3] = { 1, 2, 4 };
DestParts.
Mode = eModeRegDisp
;
DestParts.
Val = (0 - MemLen
[OpSize
]) & 0xfffff;
DestParts.
Cnt = 1;
}
/* for PC-relative addressing, fix up destination displacement and
complain on displacement overflow: */
else if ((DestParts.
Mode == eModeRegDisp
) && (DestParts.
Part == RegPC
))
{
LongWord NewDist
= DestParts.
Val - 2;
if ((NewDist
& 0x8000) != (DestParts.
Val & 0x8000))
{
WrError
(ErrNum_DistTooBig
);
return;
}
DestParts.
Val = NewDist
;
}
/* transform 0(Rn) as Dest back to @Rn as Src: */
else if ((SrcParts.
Mode == eModeRegDisp
) && (DestParts.
Val == 0))
{
SrcParts.
Mode = eModeIReg
;
SrcParts.
Cnt = 0;
}
}
/* Src == other (constant) value: 0xff means -1: */
else
FillAdrPartsImm
(&SrcParts
, SrcSpec
== 0xff ? 0xffffffff : SrcSpec
, False
);
/* assemble like 2-op instruction: */
ConstructTwoOpX
(Code
, &SrcParts
, &DestParts
);
}
static void DecodePOP
(Word Code
)
{
tAdrParts DstParts
, SrcParts
;
PCDist
= 2;
if (ChkArgCnt
(1, 1)
&& DecodeAdr
(&ArgStr
[1], eExtModeNo
, MModeAd
, True
, &DstParts
))
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
ResetAdr
(&SrcParts
);
SrcParts.
Mode = eModeIRegAutoInc
;
SrcParts.
Part = RegSP
;
ConstructTwoOp
(Code
, &SrcParts
, &DstParts
);
}
}
static void DecodePOPX
(Word Code
)
{
tAdrParts DstParts
, SrcParts
;
PCDist
= 4;
if (ChkArgCnt
(1, 1)
&& DecodeAdr
(&ArgStr
[1], eExtModeYes
, MModeAd
, True
, &DstParts
))
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
ResetAdr
(&SrcParts
);
SrcParts.
Mode = eModeIRegAutoInc
;
SrcParts.
Part = RegSP
;
ConstructTwoOpX
(Code
, &SrcParts
, &DstParts
);
}
}
static void DecodeOneOp
(Word Index
)
{
const OneOpOrder
*pOrder
= OneOpOrders
+ Index
;
if (!ChkArgCnt
(1, 1));
else if (OpSize
> eOpSizeW
) WrError
(ErrNum_InvOpSize
);
else if ((OpSize
== eOpSizeB
) && (!pOrder
->MayByte
)) WrError
(ErrNum_InvOpSize
);
else
{
tAdrParts AdrParts
;
PCDist
= 2;
if (DecodeAdr
(&ArgStr
[1], eExtModeNo
, 15, True
, &AdrParts
))
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
WAsmCode
[0] = pOrder
->Code
| GetBW
() | (AdrParts.
Mode << 4) | AdrParts.
Part; CodeLen
+= 2;
AppendAdrVals
(&AdrParts
);
}
}
}
static void DecodeOneOpX
(Word Index
)
{
const OneOpOrder
*pOrder
= OneOpOrders
+ Index
;
if (!ChkArgCnt
(1, 1));
else if ((OpSize
== eOpSizeB
) && (!pOrder
->MayByte
)) WrError
(ErrNum_InvOpSize
);
else
{
tAdrParts AdrParts
;
PCDist
= 4;
if (DecodeAdr
(&ArgStr
[1], eExtModeYes
, 15, True
, &AdrParts
))
{
/* B/W for 20 bit size is 0 instead of 1 for SXT/SWPB */
Word ActBW
= pOrder
->MayByte
? GetBW
() : 0;
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
WAsmCode
[CodeLen
>> 1] = 0x1800 | GetAL
();
/* put bits 16:19 of operand into bits 0:3 or 7:10 of extension word? */
if (AdrParts.
Cnt)
WAsmCode
[CodeLen
>> 1] |= (((AdrParts.
Val >> 16) & 15) << 7);
/* repeat only supported for register op */
if (AdrParts.
Mode == eModeReg
)
{
WAsmCode
[CodeLen
>> 1] |= MultPrefix
;
MultPrefix
= 0;
}
CodeLen
+= 2;
WAsmCode
[CodeLen
>> 1] = pOrder
->Code
| ActBW
| (AdrParts.
Mode << 4) | AdrParts.
Part; CodeLen
+= 2;
AppendAdrVals
(&AdrParts
);
}
}
}
static void DecodeMOVA
(Word Code
)
{
tAdrParts AdrParts
;
UNUSED
(Code
);
OpSize
= eOpSizeA
;
if (!ChkArgCnt
(2, 2));
else if (*AttrPart.
str.
p_str) WrError
(ErrNum_UseLessAttr
);
else
{
PCDist
= 2;
DecodeAdr
(&ArgStr
[2], eExtModeYes
, 15, False
, &AdrParts
);
if (AdrParts.
WasAbs)
{
if (DecodeReg
(&ArgStr
[1], &WAsmCode
[0], True
) == eIsReg
)
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
WAsmCode
[0] = 0x0060 | (WAsmCode
[0] << 8) | ((AdrParts.
Val >> 16) & 0x0f);
WAsmCode
[1] = AdrParts.
Val & 0xffff;
CodeLen
= 4;
}
}
else switch (AdrParts.
Mode)
{
case eModeReg
:
WAsmCode
[0] = AdrParts.
Part;
DecodeAdr
(&ArgStr
[1], eExtModeYes
, 15, True
, &AdrParts
);
if (AdrParts.
WasImm)
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
WAsmCode
[0] |= ((AdrParts.
Val >> 8) & 0x0f00) | 0x0080;
WAsmCode
[1] = AdrParts.
Val & 0xffff;
CodeLen
= 4;
}
else if (AdrParts.
WasAbs)
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
WAsmCode
[0] |= ((AdrParts.
Val >> 8) & 0x0f00) | 0x0020;
WAsmCode
[1] = AdrParts.
Val & 0xffff;
CodeLen
= 4;
}
else switch (AdrParts.
Mode)
{
case eModeReg
:
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
WAsmCode
[0] |= (AdrParts.
Part << 8) | 0x00c0;
CodeLen
= 2;
break;
case eModeIReg
:
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
WAsmCode
[0] |= (AdrParts.
Part << 8) | 0x0000;
CodeLen
= 2;
break;
case eModeIRegAutoInc
:
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
WAsmCode
[0] |= (AdrParts.
Part << 8) | 0x0010;
CodeLen
= 2;
break;
case eModeRegDisp
:
if (ChkRange
(AdrParts.
Val, 0, 0xffff))
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
WAsmCode
[0] |= (AdrParts.
Part << 8) | 0x0030;
WAsmCode
[1] = AdrParts.
Val & 0xffff;
CodeLen
= 4;
}
break;
}
break;
/* 'MOVA ...,@Rn' is not defined, treat like 'MOVA ...,0(Rn)' */
case eModeIReg
:
AdrParts.
Mode = eModeRegDisp
;
AdrParts.
Val = 0;
/* fall-thru */
case eModeRegDisp
:
if (ChkRange
(AdrParts.
Val, 0, 0xffff)
&& (DecodeReg
(&ArgStr
[1], &WAsmCode
[0], True
) == eIsReg
))
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
WAsmCode
[0] = 0x0070 | (WAsmCode
[0] << 8) | AdrParts.
Part;
WAsmCode
[1] = AdrParts.
Val & 0xffff;
CodeLen
= 4;
}
break;
}
}
}
static void DecodeBRA
(Word Code
)
{
if (ChkArgCnt
(1, 1))
{
const char PCArg
[] = "PC";
AppendArg
(strlen(PCArg
));
strcpy(ArgStr
[ArgCnt
].
str.
p_str, PCArg
);
DecodeMOVA
(Code
);
}
}
static void DecodeCLRA
(Word Code
)
{
if (ChkArgCnt
(1, 1)
&& (DecodeReg
(&ArgStr
[1], &WAsmCode
[0], True
) == eIsReg
))
{
WAsmCode
[0] |= Code
;
CodeLen
= 2;
}
}
static void DecodeTSTA
(Word Code
)
{
if (ChkArgCnt
(1, 1)
&& (DecodeReg
(&ArgStr
[1], &WAsmCode
[0], True
) == eIsReg
))
{
WAsmCode
[0] |= Code
;
WAsmCode
[1] = 0x0000;
CodeLen
= 4;
}
}
static void DecodeDECDA_INCDA
(Word Code
)
{
if (ChkArgCnt
(1, 1)
&& (DecodeReg
(&ArgStr
[1], &WAsmCode
[0], True
) == eIsReg
))
{
WAsmCode
[0] |= Code
;
WAsmCode
[1] = 2;
CodeLen
= 4;
}
}
static void DecodeADDA_SUBA_CMPA
(Word Code
)
{
OpSize
= eOpSizeA
;
if (!ChkArgCnt
(2, 2));
else if (*AttrPart.
str.
p_str) WrError
(ErrNum_UseLessAttr
);
else if (DecodeReg
(&ArgStr
[2], &WAsmCode
[0], False
) == eIsReg
)
{
tAdrParts AdrParts
;
DecodeAdr
(&ArgStr
[1], eExtModeYes
, 15, True
, &AdrParts
);
if (AdrParts.
WasImm)
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
WAsmCode
[0] |= Code
| ((AdrParts.
Val >> 8) & 0xf00);
WAsmCode
[1] = AdrParts.
Val & 0xffff;
CodeLen
= 4;
}
else if (eModeReg
== AdrParts.
Mode)
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
WAsmCode
[0] |= Code
| 0x0040 | (AdrParts.
Part << 8);
CodeLen
= 2;
}
else
WrError
(ErrNum_InvOpSize
);
}
}
static void DecodeRxM
(Word Code
)
{
if (!ChkArgCnt
(2, 2));
else if (OpSize
== eOpSizeB
) WrError
(ErrNum_InvOpSize
);
else if (DecodeReg
(&ArgStr
[2], &WAsmCode
[0], True
) != eIsReg
);
else if (ArgStr
[1].
str.
p_str[0] != '#') WrError
(ErrNum_OnlyImmAddr
);
else
{
Word Mult
;
tSymbolFlags Flags
;
Boolean OK
;
Mult
= EvalStrIntExpressionOffsWithFlags
(&ArgStr
[1], 1, UInt3
, &OK
, &Flags
);
if (OK
)
{
if (mFirstPassUnknown
(Flags
))
Mult
= 1;
if (ChkRange
(Mult
, 1, 4))
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
WAsmCode
[0] |= Code
| ((Mult
- 1) << 10) | (GetAL
() >> 2);
CodeLen
= 2;
}
}
}
}
static void DecodeCALLA
(Word Code
)
{
tAdrParts AdrParts
;
UNUSED
(Code
);
OpSize
= eOpSizeA
;
PCDist
= 2;
if (!ChkArgCnt
(1, 1));
else if (*AttrPart.
str.
p_str) WrError
(ErrNum_UseLessAttr
);
else if (DecodeAdr
(&ArgStr
[1], eExtModeYes
, 15, True
, &AdrParts
))
{
if (AdrParts.
WasImm)
{
WAsmCode
[0] = 0x13b0 | ((AdrParts.
Val >> 16) & 15);
WAsmCode
[1] = AdrParts.
Val & 0xffff;
CodeLen
= 4;
}
else if (AdrParts.
WasAbs)
{
WAsmCode
[0] = 0x1380 | ((AdrParts.
Val >> 16) & 15);
WAsmCode
[1] = AdrParts.
Val & 0xffff;
CodeLen
= 4;
}
else if ((AdrParts.
Mode == eModeRegDisp
) && (AdrParts.
Part == RegPC
))
{
WAsmCode
[0] = 0x1390 | ((AdrParts.
Val >> 16) & 15);
WAsmCode
[1] = AdrParts.
Val & 0xffff;
CodeLen
= 4;
}
else if ((AdrParts.
Mode == eModeRegDisp
) && (((AdrParts.
Val & 0xfffff) > 0x7fff) && ((AdrParts.
Val & 0xfffff) < 0xf8000))) WrError
(ErrNum_OverRange
);
else
{
WAsmCode
[CodeLen
>> 1] = 0x1340 | (AdrParts.
Mode << 4) | (AdrParts.
Part); CodeLen
+= 2;
AppendAdrVals
(&AdrParts
);
}
}
}
static void DecodePUSHM_POPM
(Word Code
)
{
if (!ChkArgCnt
(2, 2));
else if (OpSize
== 0) WrError
(ErrNum_InvOpSize
);
else if (DecodeReg
(&ArgStr
[2], &WAsmCode
[0], True
) != eIsReg
);
else if (ArgStr
[1].
str.
p_str[0] != '#') WrError
(ErrNum_OnlyImmAddr
);
else
{
Boolean OK
;
Word Cnt
;
tSymbolFlags Flags
;
Cnt
= EvalStrIntExpressionOffsWithFlags
(&ArgStr
[1], 1, UInt5
, &OK
, &Flags
);
if (mFirstPassUnknown
(Flags
))
Cnt
= 1;
if (OK
&& ChkRange
(Cnt
, 1, 16))
{
Cnt
--;
if (Code
& 0x0200)
WAsmCode
[0] = (WAsmCode
[0] - Cnt
) & 15;
WAsmCode
[0] |= Code
| (Cnt
<< 4) | (GetAL
() << 2);
CodeLen
= 2;
}
}
}
static void DecodeJmp
(Word Code
)
{
Integer AdrInt
;
tSymbolFlags Flags
;
Boolean OK
;
if (!ChkArgCnt
(1, 1));
else if (OpSize
!= eOpSizeDefault
) WrError
(ErrNum_InvOpSize
);
{
AdrInt
= EvalStrIntExpressionWithFlags
(&ArgStr
[1], UInt16
, &OK
, &Flags
) - (EProgCounter
() + 2);
if (OK
)
{
if (Odd
(AdrInt
)) WrError
(ErrNum_DistIsOdd
);
else if (!mSymbolQuestionable
(Flags
) && ((AdrInt
< -1024) || (AdrInt
> 1022))) WrError
(ErrNum_JmpDistTooBig
);
else
{
if (Odd
(EProgCounter
())) WrError
(ErrNum_AddrNotAligned
);
WAsmCode
[0] = Code
| ((AdrInt
>> 1) & 0x3ff);
CodeLen
= 2;
}
}
}
}
static void DecodeBYTE
(Word Index
)
{
TempResult t
;
UNUSED
(Index
);
as_tempres_ini
(&t
);
if (ChkArgCnt
(1, ArgCntMax
))
{
Boolean OK
= True
;
tStrComp
*pArg
;
forallargs
(pArg
, OK
)
{
KillBlanks
(pArg
->str.
p_str);
EvalStrExpression
(pArg
, &t
);
switch (t.
Typ)
{
case TempInt
:
if (mFirstPassUnknown
(t.
Flags)) t.
Contents.
Int &= 0xff;
if (!RangeCheck
(t.
Contents.
Int, Int8
)) WrStrErrorPos
(ErrNum_OverRange
, pArg
);
else if (SetMaxCodeLen
(CodeLen
+ 1))
{
WrStrErrorPos
(ErrNum_CodeOverflow
, pArg
);
OK
= False
;
}
else
PutByte
(t.
Contents.
Int);
break;
case TempString
:
{
if (as_chartrans_xlate_nonz_dynstr
(CurrTransTable
->p_table
, &t.
Contents.
str, pArg
))
OK
= False
;
else
{
unsigned l
= t.
Contents.
str.
len;
if (SetMaxCodeLen
(l
+ CodeLen
))
{
WrStrErrorPos
(ErrNum_CodeOverflow
, pArg
);
OK
= False
;
}
else
{
char *pEnd
= t.
Contents.
str.
p_str + l
, *p
;
for (p
= t.
Contents.
str.
p_str; p
< pEnd
; PutByte
(*(p
++)));
}
}
break;
}
case TempFloat
:
WrStrErrorPos
(ErrNum_StringOrIntButFloat
, pArg
);
/* fall-through */
default:
OK
= False
;
break;
}
}
if (!OK
)
CodeLen
= 0;
}
as_tempres_free
(&t
);
}
static void DecodeWORD
(Word Index
)
{
int z
;
Word HVal16
;
Boolean OK
;
UNUSED
(Index
);
if (ChkArgCnt
(1, ArgCntMax
))
{
z
= 1; OK
= True
;
do
{
HVal16
= EvalStrIntExpression
(&ArgStr
[z
], Int16
, &OK
);
if (OK
)
{
WAsmCode
[CodeLen
>> 1] = HVal16
;
CodeLen
+= 2;
}
z
++;
}
while ((z
<= ArgCnt
) && (OK
));
if (!OK
) CodeLen
= 0;
}
}
static void DecodeBSS
(Word Index
)
{
Word HVal16
;
Boolean OK
;
UNUSED
(Index
);
if (ChkArgCnt
(1, 1))
{
tSymbolFlags Flags
;
HVal16
= EvalStrIntExpressionWithFlags
(&ArgStr
[1], Int16
, &OK
, &Flags
);
if (mFirstPassUnknown
(Flags
)) WrError
(ErrNum_FirstPassCalc
);
else if (OK
)
{
if (!HVal16
) WrError
(ErrNum_NullResMem
);
DontPrint
= True
; CodeLen
= HVal16
;
BookKeeping
();
}
}
}
static void DecodeRPT
(Word Code
)
{
char *pOpPart
, *pArgPart1
, *pAttrPart
;
Boolean OK
;
/* fundamentals */
if (!ChkArgCnt
(1, ArgCntMax
))
return;
if (*AttrPart.
str.
p_str != '\0')
{
WrError
(ErrNum_UseLessAttr
);
return;
}
/* multiplier argument */
pOpPart
= FirstBlank
(ArgStr
[1].
str.
p_str);
if (!pOpPart
)
{
WrError
(ErrNum_CannotSplitArg
);
return;
}
*pOpPart
++ = '\0';
MultPrefix
= Code
| GetMult
(&ArgStr
[1], &OK
);
if (!OK
)
return;
/* new OpPart: */
KillPrefBlanks
(pOpPart
);
pArgPart1
= FirstBlank
(pOpPart
);
if (!pArgPart1
)
{
WrError
(ErrNum_CannotSplitArg
);
return;
}
*pArgPart1
++ = '\0';
strcpy(OpPart.
str.
p_str, pOpPart
);
UpString
(OpPart.
str.
p_str);
KillPrefBlanks
(pArgPart1
);
strmov
(ArgStr
[1].
str.
p_str, pArgPart1
);
/* split off new attribute part: */
pAttrPart
= strrchr(OpPart.
str.
p_str, '.');
if (pAttrPart
)
{
AttrPart.
Pos.
Len = strmemcpy
(AttrPart.
str.
p_str, STRINGSIZE
, pAttrPart
+ 1, strlen(pAttrPart
+ 1));
*pAttrPart
= '\0';
}
else
StrCompReset
(&AttrPart
);
/* prefix 0x0000 is rptc #1 and effectively a NOP prefix: */
MakeCode
();
if (MultPrefix
)
{
WrError
(ErrNum_NotRepeatable
);
CodeLen
= 0;
}
}
/*-------------------------------------------------------------------------*/
#define AddFixed(NName, NCode) \
AddInstTable(InstTable, NName, NCode, DecodeFixed)
static void AddTwoOp
(const char *NName
, Word NCode
)
{
AddInstTable
(InstTable
, NName
, NCode
, DecodeTwoOp
);
if (MomCPU
>= CPUMSP430X
)
{
char XName
[20];
as_snprintf
(XName
, sizeof(XName
), "%sX", NName
);
AddInstTable
(InstTable
, XName
, NCode
, DecodeTwoOpX
);
}
}
static void AddEmulOneToTwo
(const char *NName
, Word NCode
)
{
AddInstTable
(InstTable
, NName
, NCode
, DecodeEmulOneToTwo
);
}
static void AddEmulOneToTwoX
(const char *NName
, Word NCode
)
{
AddInstTable
(InstTable
, NName
, NCode
, DecodeEmulOneToTwoX
);
}
static void AddOneOp
(const char *NName
, Boolean NMay
, Boolean AllowX
, Word NCode
)
{
order_array_rsv_end
(OneOpOrders
, OneOpOrder
);
OneOpOrders
[InstrZ
].
MayByte = NMay
;
OneOpOrders
[InstrZ
].
Code = NCode
;
AddInstTable
(InstTable
, NName
, InstrZ
, DecodeOneOp
);
if ((MomCPU
>= CPUMSP430X
) && AllowX
)
{
char XName
[20];
as_snprintf
(XName
, sizeof(XName
), "%sX", NName
);
AddInstTable
(InstTable
, XName
, InstrZ
, DecodeOneOpX
);
}
InstrZ
++;
}
#define AddJmp(NName, NCode) \
AddInstTable(InstTable, NName, NCode, DecodeJmp)
static void InitFields
(void)
{
InstTable
= CreateInstTable
(207);
SetDynamicInstTable
(InstTable
);
AddFixed
("RETI", 0x1300);
AddFixed
("CLRC", 0xc312);
AddFixed
("CLRN", 0xc222);
AddFixed
("CLRZ", 0xc322);
AddFixed
("DINT", 0xc232);
AddFixed
("EINT", 0xd232);
AddFixed
("NOP" , NOPCode
);
AddFixed
("RET" , 0x4130);
AddFixed
("SETC", 0xd312);
AddFixed
("SETN", 0xd222);
AddFixed
("SETZ", 0xd322);
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);
AddEmulOneToTwo
("ADC" , 0x6000); /* ADDC #0, dst */
AddInstTable
(InstTable
, "BR", 0x4000, DecodeBR
); /* MOV dst, PC */
AddEmulOneToTwo
("CLR" , 0x4000); /* MOV #0, dst */
AddEmulOneToTwo
("DADC", 0xa000); /* DADD #0, dst */
AddEmulOneToTwo
("DEC" , 0x8001); /* SUB #1, dst */
AddEmulOneToTwo
("DECD", 0x8002); /* SUB #2, dst */
AddEmulOneToTwo
("INC" , 0x5001); /* ADD #1, dst */
AddEmulOneToTwo
("INCD", 0x5002); /* ADD #2, dst */
AddEmulOneToTwo
("INV" , 0xe0ff); /* XOR #-1, dst */
AddInstTable
(InstTable
, "POP", 0x4000, DecodePOP
); /* MOV @SP+,dst */
AddEmulOneToTwo
("RLA" , 0x50aa); /* ADD dst, dst */
AddEmulOneToTwo
("RLC" , 0x60aa); /* ADDC dst, dst */
AddEmulOneToTwo
("SBC" , 0x7000); /* SUBC #0, dst */
AddEmulOneToTwo
("TST" , 0x9000); /* CMP #0, dst */
InstrZ
= 0;
AddOneOp
("RRC" , True
, True
, 0x1000); AddOneOp
("RRA" , True
, True
, 0x1100);
AddOneOp
("PUSH", True
, True
, 0x1200); AddOneOp
("SWPB", False
, True
, 0x1080);
AddOneOp
("CALL", False
, False
, 0x1280); AddOneOp
("SXT" , False
, True
, 0x1180);
if (MomCPU
>= CPUMSP430X
)
{
/* what about RRUX? */
AddInstTable
(InstTable
, "MOVA", 0x0000, DecodeMOVA
);
AddInstTable
(InstTable
, "ADDA", 0x00a0, DecodeADDA_SUBA_CMPA
);
AddInstTable
(InstTable
, "CMPA", 0x0090, DecodeADDA_SUBA_CMPA
);
AddInstTable
(InstTable
, "SUBA", 0x00b0, DecodeADDA_SUBA_CMPA
);
AddInstTable
(InstTable
, "RRCM", 0x0040, DecodeRxM
);
AddInstTable
(InstTable
, "RRAM", 0x0140, DecodeRxM
);
AddInstTable
(InstTable
, "RLAM", 0x0240, DecodeRxM
);
AddInstTable
(InstTable
, "RRUM", 0x0340, DecodeRxM
);
AddInstTable
(InstTable
, "CALLA", 0x0000, DecodeCALLA
);
AddInstTable
(InstTable
, "PUSHM", 0x1400, DecodePUSHM_POPM
);
AddInstTable
(InstTable
, "POPM", 0x1600, DecodePUSHM_POPM
);
AddEmulOneToTwoX
("ADCX", 0x6000); /* ADDCX #0, dst */
AddInstTable
(InstTable
, "BRA", 0x4000, DecodeBRA
); /* MOVA dst, PC */
AddFixed
("RETA", 0x0110); /* MOVA @SP+,PC */
AddInstTable
(InstTable
, "CLRA", 0x4300, DecodeCLRA
); /* MOV #0,Rdst */
AddEmulOneToTwoX
("CLRX", 0x4000); /* MOVX #0, dest */
AddEmulOneToTwoX
("DADCX", 0xa000); /* DADDX #0, dst */
AddEmulOneToTwoX
("DECX" , 0x8001); /* SUBX #1, dst */
AddInstTable
(InstTable
, "DECDA", 0x00b0, DecodeDECDA_INCDA
); /* SUBA #2,Rdst */
AddEmulOneToTwoX
("DECDX", 0x8002); /* SUBX #2, dst */
AddEmulOneToTwoX
("INCX" , 0x5001); /* SUBX #1, dst */
AddInstTable
(InstTable
, "INCDA", 0x00a0, DecodeDECDA_INCDA
); /* SUBA #2,Rdst */
AddEmulOneToTwoX
("INCDX", 0x5002); /* SUBX #2, dst */
AddEmulOneToTwoX
("INVX" , 0xe0ff); /* XORX #-1, dst */
AddEmulOneToTwoX
("RLAX" , 0x50aa); /* ADDX dst, dst */
AddEmulOneToTwoX
("RLCX" , 0x60aa); /* ADDCX dst, dst */
AddEmulOneToTwoX
("SBCX" , 0x7000); /* SUBCX #0, dst */
AddInstTable
(InstTable
, "TSTA" , 0x0090, DecodeTSTA
); /* CMPA #0,Rdst */
AddEmulOneToTwoX
("TSTX" , 0x9000); /* CMPX #0, dst */
AddInstTable
(InstTable
, "POPX", 0x4000, DecodePOPX
); /* MOVX @SP+,dst */
AddInstTable
(InstTable
, "RPTC", 0x0000, DecodeRPT
);
AddInstTable
(InstTable
, "RPTZ", 0x0100, DecodeRPT
);
}
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);
AddJmp
("JEQ" , 0x2400); AddJmp
("JLO" , 0x2800);
AddJmp
("JHS" , 0x2c00);
AddInstTable
(InstTable
, "WORD", 0, DecodeWORD
);
AddInstTable
(InstTable
, "REG", 0, CodeREG
);
}
static void DeinitFields
(void)
{
order_array_free
(OneOpOrders
);
DestroyInstTable
(InstTable
);
}
/*-------------------------------------------------------------------------*/
/*!------------------------------------------------------------------------
* \fn InternSymbol_MSP(char *pArg, TempResult *pResult)
* \brief handle built-in (register) symbols for MSP
* \param pArg source argument
* \param pResult result buffer
* ------------------------------------------------------------------------ */
static void InternSymbol_MSP
(char *pArg
, TempResult
*pResult
)
{
Word RegNum
;
if (DecodeRegCore
(pArg
, &RegNum
))
{
pResult
->Typ
= TempReg
;
pResult
->DataSize
= eSymbolSize8Bit
;
pResult
->Contents.
RegDescr.
Reg = RegNum
;
pResult
->Contents.
RegDescr.
Dissect = DissectReg_MSP
;
pResult
->Contents.
RegDescr.
compare = NULL
;
}
}
static Boolean DecodeAttrPart_MSP
(void)
{
if (strlen(AttrPart.
str.
p_str) > 1)
{
WrStrErrorPos
(ErrNum_UndefAttr
, &AttrPart
);
return False
;
}
switch (as_toupper
(*AttrPart.
str.
p_str))
{
case '\0':
break;
case 'B':
AttrPartOpSize
[0] = eSymbolSize8Bit
;
break;
case 'W':
AttrPartOpSize
[0] = eSymbolSize16Bit
;
break;
case 'A':
if (MomCPU
>= CPUMSP430X
)
{
AttrPartOpSize
[0] = eSymbolSize24Bit
; /* TODO: should be 20 bits */
break;
}
/* else fall-through */
default:
WrStrErrorPos
(ErrNum_UndefAttr
, &AttrPart
);
return False
;
}
return True
;
}
static void MakeCode_MSP
(void)
{
CodeLen
= 0; DontPrint
= False
; PCDist
= 0;
/* to be ignored: */
if (Memo
("")) return;
/* process attribute */
switch (AttrPartOpSize
[0])
{
case eSymbolSize24Bit
:
OpSize
= eOpSizeA
;
break;
case eSymbolSize16Bit
:
OpSize
= eOpSizeW
;
break;
case eSymbolSize8Bit
:
OpSize
= eOpSizeB
;
break;
default:
OpSize
= eOpSizeDefault
;
break;
}
/* insns not requiring word alignment */
if (Memo
("BYTE"))
{
DecodeBYTE
(0);
return;
}
if (Memo
("BSS"))
{
DecodeBSS
(0);
return;
}
/* For all other (pseudo) instructions, optionally pad to even */
if (Odd
(EProgCounter
()))
{
if (DoPadding
)
InsertPadding
(1, False
);
else
WrError
(ErrNum_AddrNotAligned
);
}
/* all the rest from table */
if (!LookupInstTable
(InstTable
, OpPart.
str.
p_str))
WrStrErrorPos
(ErrNum_UnknownInstruction
, &OpPart
);
}
static Boolean IsDef_MSP
(void)
{
return Memo
("REG");
}
static void SwitchTo_MSP
(void)
{
TurnWords
= False
; SetIntConstMode
(eIntConstModeIntel
);
PCSymbol
= "$"; HeaderID
= 0x4a; NOPCode
= 0x4303; /* = MOV #0,#0 */
DivideChars
= ","; HasAttrs
= True
; AttrChars
= ".";
ValidSegs
= 1 << SegCode
;
Grans
[SegCode
] = 1; ListGrans
[SegCode
] = 2; SegInits
[SegCode
] = 0;
AdrIntType
= (MomCPU
== CPUMSP430X
) ? UInt20
: UInt16
;
DispIntType
= (MomCPU
== CPUMSP430X
) ? Int20
: Int16
;
SegLimits
[SegCode
] = IntTypeDefs
[AdrIntType
].
Max;
AddONOFF
(DoPaddingName
, &DoPadding
, DoPaddingName
, False
);
DecodeAttrPart
= DecodeAttrPart_MSP
;
MakeCode
= MakeCode_MSP
;
IsDef
= IsDef_MSP
;
InternSymbol
= InternSymbol_MSP
;
DissectReg
= DissectReg_MSP
;
SwitchFrom
= DeinitFields
; InitFields
();
MultPrefix
= 0x0000;
}
void codemsp_init
(void)
{
CPUMSP430
= AddCPU
("MSP430", SwitchTo_MSP
);
CPUMSP430X
= AddCPU
("MSP430X", SwitchTo_MSP
);
}