/* codenv60.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Code Generator NEC V60 */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <string.h>
#include "bpemu.h"
#include "strutil.h"
#include "headids.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmallg.h"
#include "asmitree.h"
#include "codevars.h"
#include "codepseudo.h"
#include "motpseudo.h"
#include "onoff_common.h"
#include "codev60.h"
#define REG_SP 31
#define REG_FP 30
#define REG_AP 29
#define REG_PC 64
/* NOTE: only 3 code flags are available, since machine sub code
is 5 bits long: */
#define CODE_FLAG_SUPMODE (1 << 15)
#define CODE_FLAG_OP2_IMM (1 << 14)
#define CODE_FLAG_LIM32 (1 << 13)
typedef enum
{
ModReg
= 0,
ModImm
= 1,
ModMem
= 2,
ModIO
= 3
} tAdrMode
;
#define MModReg (1 << ModReg)
#define MModImm (1 << ModImm)
#define MModMem (1 << ModMem)
#define MModIO (1 << ModIO)
#define MModImm7Bit (1 << 7)
#define MModImmCondition (1 << 6)
/* Count = 0 implies error/invalid, since at least mod byte must be present */
typedef struct
{
unsigned count
;
Byte m
, vals
[10];
tSymbolSize forced_disp_size
, data_op_size
;
tSymbolFlags immediate_flags
;
Boolean bit_offset_immediate
;
LongInt bit_offset
;
} tAdrVals
;
typedef struct
{
Byte val
;
tSymbolFlags immediate_flags
;
} tLenVals
;
typedef struct
{
char name
[3];
Byte code
;
} tCondition
;
static tSymbolSize OpSize
;
static tCondition
*Conditions
;
/*-------------------------------------------------------------------------*/
/* Register Symbols */
/*!------------------------------------------------------------------------
* \fn DecodeRegCore(const char *pArg, Byte *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
, Byte
*pResult
)
{
size_t l
;
if (!as_strcasecmp
(pArg
, "SP"))
{
*pResult
= REG_SP
| REGSYM_FLAG_ALIAS
;
return True
;
}
else if (!as_strcasecmp
(pArg
, "FP"))
{
*pResult
= REG_FP
| REGSYM_FLAG_ALIAS
;
return True
;
}
else if (!as_strcasecmp
(pArg
, "AP"))
{
*pResult
= REG_AP
| REGSYM_FLAG_ALIAS
;
return True
;
}
l
= strlen(pArg
);
if ((l
< 2) || (l
> 3) || (as_toupper
(*pArg
) != 'R'))
return False
;
*pResult
= 0;
for (pArg
++; *pArg
; pArg
++)
{
if (!isdigit(*pArg
))
return False
;
*pResult
= (*pResult
* 10) + (*pArg
- '0');
}
return (*pResult
< 32);
}
/*!------------------------------------------------------------------------
* \fn DissectReg_V60(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
* \brief dissect register symbols - V60 variant
* \param pDest destination buffer
* \param DestSize destination buffer size
* \param Value numeric register value
* \param InpSize register size
* ------------------------------------------------------------------------ */
static void DissectReg_V60
(char *pDest
, size_t DestSize
, tRegInt Value
, tSymbolSize InpSize
)
{
if (InpSize
== eSymbolSize32Bit
)
{
switch (Value
)
{
case REGSYM_FLAG_ALIAS
| REG_SP
:
as_snprintf
(pDest
, DestSize
, "SP");
break;
case REGSYM_FLAG_ALIAS
| REG_FP
:
as_snprintf
(pDest
, DestSize
, "FP");
break;
case REGSYM_FLAG_ALIAS
| REG_AP
:
as_snprintf
(pDest
, DestSize
, "AP");
break;
default:
as_snprintf
(pDest
, DestSize
, "R%u", (unsigned)(Value
& 31));
}
}
else
as_snprintf
(pDest
, DestSize
, "%d-%u", (int)InpSize
, (unsigned)Value
);
}
/*--------------------------------------------------------------------------*/
/* Address Expression Parser */
/*!------------------------------------------------------------------------
* \fn ResetAdrVals(tAdrVals *p_vals)
* \brief reset to invalid/empty state
* \param p_vals arg to clear
* ------------------------------------------------------------------------ */
static void ResetAdrVals
(tAdrVals
*p_vals
)
{
p_vals
->count
= 0;
p_vals
->m
= 0;
p_vals
->forced_disp_size
=
p_vals
->data_op_size
= eSymbolSizeUnknown
;
p_vals
->immediate_flags
= eSymbolFlag_None
;
p_vals
->bit_offset_immediate
= False
;
p_vals
->bit_offset
= 0;
}
/*!------------------------------------------------------------------------
* \fn DecodeReg(const tStrComp *pArg, Byte *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 argument is expected to be a register
* \return RegEvalResult
* ------------------------------------------------------------------------ */
static tRegEvalResult DecodeReg
(const tStrComp
*pArg
, Byte
*pResult
, Boolean MustBeReg
)
{
tRegDescr RegDescr
;
tEvalResult EvalResult
;
tRegEvalResult RegEvalResult
;
if (DecodeRegCore
(pArg
->str.
p_str, pResult
))
{
*pResult
&= ~REGSYM_FLAG_ALIAS
;
return eIsReg
;
}
RegEvalResult
= EvalStrRegExpressionAsOperand
(pArg
, &RegDescr
, &EvalResult
, eSymbolSize32Bit
, MustBeReg
);
*pResult
= RegDescr.
Reg & ~REGSYM_FLAG_ALIAS
;
return RegEvalResult
;
}
/*!------------------------------------------------------------------------
* \fn DecodeCondition(const char *p_arg, LongWord *p_result)
* \brief check whether argument is a condition identifier
* \param p_arg source argument
* \param p_result result buffer if yes
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean DecodeCondition
(const char *p_arg
, LongWord
*p_result
)
{
int z
;
for (z
= 0; Conditions
[z
].
name[0]; z
++)
if (!as_strcasecmp
(p_arg
, Conditions
[z
].
name))
{
*p_result
= Conditions
[z
].
code;
return True
;
}
return False
;
}
/*!------------------------------------------------------------------------
* \fn DecodeAdr(const tStrComp *pArg, tAdrVals *pResult, unsigned ModeMask)
* \brief decode address expression
* \param pArg source argument
* \param pResult result buffer
* \param MayImm allow immediate?
* \return True if successfully decoded
* ------------------------------------------------------------------------ */
static Boolean check_mode_mask
(const tStrComp
*p_arg
, tAdrMode address_mode
, unsigned mode_mask
)
{
if ((mode_mask
>> address_mode
) & 1)
return True
;
{
WrStrErrorPos
(ErrNum_InvAddrMode
, p_arg
);
return False
;
}
}
static int BaseQualifier
(const char *pArg
, int NextNonBlankPos
, int SplitPos
)
{
return (pArg
[NextNonBlankPos
] == ']') ? SplitPos
: -1;
}
static void CutSize
(tStrComp
*pArg
, tSymbolSize
*pSize
)
{
static const char Suffixes
[6][3] = { "B", "8", "H", "16", "W", "32" };
static const tSymbolSize Sizes
[3] = { eSymbolSize8Bit
, eSymbolSize16Bit
, eSymbolSize32Bit
};
size_t ArgLen
= strlen(pArg
->str.
p_str), ThisLen
;
unsigned z
;
for (z
= 0; z
< 6; z
++)
{
ThisLen
= strlen(Suffixes
[z
]);
if ((ArgLen
> ThisLen
+ 1)
&& (pArg
->str.
p_str[ArgLen
- ThisLen
- 1] == '.')
&& !as_strcasecmp
(pArg
->str.
p_str + ArgLen
- ThisLen
, Suffixes
[z
]))
{
*pSize
= Sizes
[z
/ 2];
StrCompShorten
(pArg
, ThisLen
+ 1);
break;
}
}
}
static void AppendToVals
(tAdrVals
*p_vals
, LongWord Value
, tSymbolSize Size
)
{
p_vals
->vals
[p_vals
->count
++] = Value
& 0xff;
if (Size
>= eSymbolSize16Bit
)
{
p_vals
->vals
[p_vals
->count
++] = (Value
>> 8) & 0xff;
if (Size
>= eSymbolSize32Bit
)
{
p_vals
->vals
[p_vals
->count
++] = (Value
>> 16) & 0xff;
p_vals
->vals
[p_vals
->count
++] = (Value
>> 24) & 0xff;
}
}
}
static Boolean IsPredecrement
(const tStrComp
*pArg
, Byte
*pResult
, tRegEvalResult
*pRegEvalResult
)
{
tStrComp RegComp
;
if (*pArg
->str.
p_str != '-')
return False
;
StrCompRefRight
(&RegComp
, pArg
, 1);
KillPrefBlanksStrComp
(&RegComp
);
*pRegEvalResult
= DecodeReg
(&RegComp
, pResult
, False
);
return (*pRegEvalResult
!= eIsNoReg
);
}
static Boolean IsPostincrement
(const tStrComp
*pArg
, Byte
*pResult
, tRegEvalResult
*pRegEvalResult
)
{
String Reg
;
tStrComp RegComp
;
size_t ArgLen
= strlen(pArg
->str.
p_str);
if (!ArgLen
|| (pArg
->str.
p_str[ArgLen
- 1] != '+'))
return False
;
StrCompMkTemp
(&RegComp
, Reg
, sizeof(Reg
));
StrCompCopySub
(&RegComp
, pArg
, 0, ArgLen
- 1);
KillPostBlanksStrComp
(&RegComp
);
*pRegEvalResult
= DecodeReg
(&RegComp
, pResult
, False
);
return (*pRegEvalResult
!= eIsNoReg
);
}
static Boolean DecodeRegOrPC
(const tStrComp
*pArg
, Byte
*pResult
)
{
if (!as_strcasecmp
(pArg
->str.
p_str, "PC"))
{
*pResult
= REG_PC
;
return True
;
}
else
return (DecodeReg
(pArg
, pResult
, True
) == eIsReg
);
}
static LongInt EvalDispOpt
(const tStrComp
*pArg
, tEvalResult
*pEvalResult
, Boolean PCRelative
)
{
if (*pArg
->str.
p_str)
return EvalStrIntExpressionWithResult
(pArg
, Int32
, pEvalResult
) - (PCRelative
? EProgCounter
() : 0);
else
{
memset(pEvalResult
, 0, sizeof(*pEvalResult
));
pEvalResult
->OK
= True
;
return 0;
}
}
static Boolean ProcessAbsolute
(const tStrComp
*pArg
, tAdrVals
*pResult
, Byte IndexReg
, Byte ModByte
, unsigned mode_mask
)
{
tEvalResult eval_result
;
LongWord Address
;
Address
= EvalStrIntExpressionOffsWithResult
(pArg
, 1, UInt32
, &eval_result
);
pResult
->count
= 0;
if (!eval_result.
OK)
return False
;
if (mode_mask
& MModIO
)
ChkSpace
(SegIO
, eval_result.
AddrSpaceMask);
if (!check_mode_mask
(pArg
, ModMem
, mode_mask
))
return False
;
if (IndexReg
!= REGSYM_FLAG_ALIAS
)
{
pResult
->vals
[pResult
->count
++] = 0xc0 | IndexReg
;
pResult
->m
= 1;
}
else
pResult
->m
= 0;
pResult
->vals
[pResult
->count
++] = ModByte
;
AppendToVals
(pResult
, Address
, eSymbolSize32Bit
);
return True
;
}
static Boolean DeduceAndCheckDispSize
(const tStrComp
*pArg
, LongInt Value
, tSymbolSize
*pSize
, const tEvalResult
*pEvalResult
)
{
if (*pSize
== eSymbolSizeUnknown
)
{
if (RangeCheck
(Value
, SInt8
))
*pSize
= eSymbolSize8Bit
;
else if (RangeCheck
(Value
, SInt16
))
*pSize
= eSymbolSize16Bit
;
else
*pSize
= eSymbolSize32Bit
;
}
if (mFirstPassUnknownOrQuestionable
(pEvalResult
->Flags
))
return True
;
switch (*pSize
)
{
case eSymbolSize8Bit
:
return ChkRangePos
(Value
, -128, 127, pArg
);
case eSymbolSize16Bit
:
return ChkRangePos
(Value
, -32768, 32767, pArg
);
case eSymbolSize32Bit
:
return True
;
default:
WrStrErrorPos
(ErrNum_OverRange
, pArg
);
}
return False
;
}
static Boolean DecodeAdr
(tStrComp
*pArg
, tAdrVals
*pResult
, unsigned ModeMask
)
{
int IndexSplitPos
, OuterDispSplitPos
, ArgLen
;
Byte IndexReg
= REGSYM_FLAG_ALIAS
, BaseReg
= REGSYM_FLAG_ALIAS
;
tEvalResult EvalResult
;
ResetAdrVals
(pResult
);
pResult
->data_op_size
= OpSize
;
/* immediate */
if (*pArg
->str.
p_str == '#')
{
LongWord Value
;
if (!check_mode_mask
(pArg
, ModImm
, ModeMask
))
return False
;
if ((ModeMask
& MModImmCondition
) && DecodeCondition
(pArg
->str.
p_str + 1, &Value
))
EvalResult.
OK = True
;
else switch (OpSize
)
{
case eSymbolSize8Bit
:
Value
= EvalStrIntExpressionOffsWithResult
(pArg
, 1, (ModeMask
& MModImm7Bit
) ? UInt7
: Int8
, &EvalResult
);
break;
case eSymbolSize16Bit
:
Value
= EvalStrIntExpressionOffsWithResult
(pArg
, 1, Int16
, &EvalResult
);
break;
case eSymbolSize32Bit
:
Value
= EvalStrIntExpressionOffsWithResult
(pArg
, 1, Int32
, &EvalResult
);
break;
default:
WrStrErrorPos
(ErrNum_InvOpSize
, pArg
);
EvalResult.
OK = False
;
break;
}
if (!EvalResult.
OK)
return EvalResult.
OK;
pResult
->m
= 0;
if (Value
<= 15)
{
pResult
->vals
[0] = 0xe0 | (Value
& 0x0f);
pResult
->count
= 1;
}
else
{
pResult
->vals
[0] = 0xf4;
pResult
->count
= 1;
AppendToVals
(pResult
, Value
, OpSize
);
}
pResult
->immediate_flags
= EvalResult.
Flags;
return EvalResult.
OK;
}
/* split off index register '(Rx)': */
IndexSplitPos
= FindDispBaseSplitWithQualifier
(pArg
->str.
p_str, &ArgLen
, BaseQualifier
, "()");
if (IndexSplitPos
> 0)
{
String RegStr
;
tStrComp RegComp
;
StrCompMkTemp
(&RegComp
, RegStr
, sizeof(RegStr
));
StrCompCopySub
(&RegComp
, pArg
, IndexSplitPos
+ 1, ArgLen
- IndexSplitPos
- 2);
KillPostBlanksStrComp
(&RegComp
);
KillPrefBlanksStrComp
(&RegComp
);
switch (DecodeReg
(&RegComp
, &IndexReg
, False
))
{
case eRegAbort
:
return False
;
case eIsReg
:
StrCompShorten
(pArg
, ArgLen
- IndexSplitPos
);
break;
default:
break;
}
}
/* absolute */
if (*pArg
->str.
p_str == '/')
return ProcessAbsolute
(pArg
, pResult
, IndexReg
, 0xf3, ModeMask
);
/* indirect modes remain (must end on ]) */
KillPostBlanksStrComp
(pArg
);
OuterDispSplitPos
= FindDispBaseSplitWithQualifier
(pArg
->str.
p_str, &ArgLen
, NULL
, "[]");
if (OuterDispSplitPos
>= 0)
{
tStrComp OuterDisp
, InnerComp
, InnerDisp
;
LongInt OuterDispValue
= 0, InnerDispValue
= 0;
tSymbolSize OuterDispSize
= eSymbolSizeUnknown
,
InnerDispSize
= eSymbolSizeUnknown
;
tEvalResult OuterEvalResult
, InnerEvalResult
;
tRegEvalResult RegEvalResult
;
int InnerDispSplitPos
;
/* split off outer displacement */
StrCompSplitRef
(&OuterDisp
, &InnerComp
, pArg
, &pArg
->str.
p_str[OuterDispSplitPos
]);
StrCompShorten
(&InnerComp
, 1);
KillPostBlanksStrComp
(&InnerComp
);
KillPrefBlanksStrCompRef
(&InnerComp
);
KillPostBlanksStrComp
(&OuterDisp
);
#if 0
DumpStrComp
("OuterDisp", &OuterDisp
);
DumpStrComp
("InnerComp", &InnerComp
);
#endif
/* nested indirect? */
InnerDispSplitPos
= FindDispBaseSplitWithQualifier
(InnerComp.
str.
p_str, &ArgLen
, NULL
, "[]");
if (InnerDispSplitPos
>= 0)
{
StrCompSplitRef
(&InnerDisp
, &InnerComp
, &InnerComp
, &InnerComp.
str.
p_str[InnerDispSplitPos
]);
StrCompShorten
(&InnerComp
, 1);
KillPostBlanksStrComp
(&InnerComp
);
KillPrefBlanksStrCompRef
(&InnerComp
);
KillPostBlanksStrComp
(&InnerDisp
);
#if 0
DumpStrComp
("InnerDisp", &InnerDisp
);
DumpStrComp
("InnerComp(2)", &InnerComp
);
#endif
/* inner comp must be register */
if (!DecodeRegOrPC
(&InnerComp
, &BaseReg
))
return False
;
if (*InnerDisp.
str.
p_str)
CutSize
(&InnerDisp
, &InnerDispSize
);
InnerDispValue
= EvalDispOpt
(&InnerDisp
, &InnerEvalResult
, BaseReg
== REG_PC
);
if (!InnerEvalResult.
OK)
return False
;
(void)InnerDispValue
;
}
/* postincr/predecr? */
else if (IsPredecrement
(&InnerComp
, &pResult
->vals
[0], &RegEvalResult
))
{
if ((eRegAbort
== RegEvalResult
) || !check_mode_mask
(pArg
, ModMem
, ModeMask
))
return False
;
if (*OuterDisp.
str.
p_str)
{
WrStrErrorPos
(ErrNum_InvAddrMode
, pArg
);
return False
;
}
pResult
->vals
[0] |= 0xa0;
pResult
->count
= 1;
pResult
->m
= 1;
return True
;
}
else if (IsPostincrement
(&InnerComp
, &pResult
->vals
[0], &RegEvalResult
))
{
if ((eRegAbort
== RegEvalResult
) || !check_mode_mask
(pArg
, ModMem
, ModeMask
))
return False
;
if (*OuterDisp.
str.
p_str)
{
WrStrErrorPos
(ErrNum_InvAddrMode
, pArg
);
return False
;
}
pResult
->vals
[0] |= 0x80;
pResult
->count
= 1;
pResult
->m
= 1;
return True
;
}
/* direct deferred: */
else if (*InnerComp.
str.
p_str == '/')
return ProcessAbsolute
(&InnerComp
, pResult
, IndexReg
, 0xfb, ModeMask
);
/* no pre/post, double indir, direct -> must be plain register */
else
{
if (!DecodeRegOrPC
(&InnerComp
, &BaseReg
))
return False
;
}
/* for both single & double indirect, outer displacement */
if (*OuterDisp.
str.
p_str)
CutSize
(&OuterDisp
, &OuterDispSize
);
OuterDispValue
= EvalDispOpt
(&OuterDisp
, &OuterEvalResult
, (BaseReg
== REG_PC
) && (InnerDispSplitPos
< 0));
if (!OuterEvalResult.
OK)
return False
;
/* now, decide about the whole mess: no double []: */
if (InnerDispSplitPos
< 0)
{
/* [Rn] */
if (!*OuterDisp.
str.
p_str && (BaseReg
!= REG_PC
))
{
if (!check_mode_mask
(pArg
, ModMem
, ModeMask
))
return False
;
if (IndexReg
!= REGSYM_FLAG_ALIAS
)
{
pResult
->vals
[pResult
->count
++] = 0xc0 | IndexReg
;
pResult
->vals
[pResult
->count
++] = 0x60 | BaseReg
;
pResult
->m
= 1;
}
else
{
pResult
->vals
[pResult
->count
++] = 0x60 | BaseReg
;
pResult
->m
= 0;
}
return True
;
}
pResult
->forced_disp_size
= InnerDispSize
;
if (!DeduceAndCheckDispSize
(&OuterDisp
, OuterDispValue
, &OuterDispSize
, &OuterEvalResult
))
return False
;
if (IndexReg
!= REGSYM_FLAG_ALIAS
)
{
pResult
->vals
[pResult
->count
++] = 0xc0 | IndexReg
;
pResult
->m
= 1;
}
else
pResult
->m
= 0;
if (REG_PC
== BaseReg
)
pResult
->vals
[pResult
->count
++] = 0xf0 + OuterDispSize
;
else
pResult
->vals
[pResult
->count
++] = (OuterDispSize
<< 5) | BaseReg
;
AppendToVals
(pResult
, OuterDispValue
, OuterDispSize
);
}
/* double [[]] and no outer displacement: */
else if (!*OuterDisp.
str.
p_str)
{
pResult
->forced_disp_size
= InnerDispSize
;
if (!DeduceAndCheckDispSize
(&InnerDisp
, InnerDispValue
, &InnerDispSize
, &InnerEvalResult
))
return False
;
if (IndexReg
!= REGSYM_FLAG_ALIAS
)
{
pResult
->vals
[pResult
->count
++] = 0xc0 | IndexReg
;
pResult
->m
= 1;
}
else
pResult
->m
= 0;
if (REG_PC
== BaseReg
)
pResult
->vals
[pResult
->count
++] = 0xf8 + InnerDispSize
;
else
pResult
->vals
[pResult
->count
++] = 0x80 | (InnerDispSize
<< 5) | BaseReg
;
AppendToVals
(pResult
, InnerDispValue
, InnerDispSize
);
}
/* double [[]] and both displacements - no index register allowed! */
else if (IndexReg
!= REGSYM_FLAG_ALIAS
)
{
WrStrErrorPos
(ErrNum_InvAddrMode
, pArg
);
return False
;
}
else
{
/* Both displacements must have same size. If both are left undefined, use the maximum needed: */
if ((InnerDispSize
== eSymbolSizeUnknown
) && (OuterDispSize
== eSymbolSizeUnknown
))
{
DeduceAndCheckDispSize
(&InnerDisp
, InnerDispValue
, &InnerDispSize
, &InnerEvalResult
);
DeduceAndCheckDispSize
(&OuterDisp
, OuterDispValue
, &OuterDispSize
, &OuterEvalResult
);
if (InnerDispSize
> OuterDispSize
)
OuterDispSize
= InnerDispSize
;
else if (OuterDispSize
> InnerDispSize
)
InnerDispSize
= OuterDispSize
;
}
/* Otherwise, accept one size hint also for the other displacement: */
else
{
if (InnerDispSize
== eSymbolSizeUnknown
)
pResult
->forced_disp_size
= InnerDispSize
= OuterDispSize
;
else if (OuterDispSize
== eSymbolSizeUnknown
)
pResult
->forced_disp_size
= OuterDispSize
= InnerDispSize
;
if (InnerDispSize
!= OuterDispSize
)
{
WrStrErrorPos
(ErrNum_ConfOpSizes
, pArg
);
return False
;
}
else
pResult
->forced_disp_size
= OuterDispSize
;
if (!DeduceAndCheckDispSize
(&InnerDisp
, InnerDispValue
, &InnerDispSize
, &InnerEvalResult
)
|| !DeduceAndCheckDispSize
(&OuterDisp
, OuterDispValue
, &OuterDispSize
, &OuterEvalResult
))
return False
;
}
if (REG_PC
== BaseReg
)
{
pResult
->vals
[pResult
->count
++] = 0xfc + InnerDispSize
;
pResult
->m
= 0;
}
else
{
pResult
->vals
[pResult
->count
++] = (InnerDispSize
<< 5) | BaseReg
;
pResult
->m
= 1;
}
AppendToVals
(pResult
, InnerDispValue
, InnerDispSize
);
AppendToVals
(pResult
, OuterDispValue
, OuterDispSize
);
}
}
else
{
tSymbolSize DispSize
= eSymbolSizeUnknown
;
LongInt DispValue
;
/* bare address: register? */
switch (DecodeReg
(pArg
, pResult
->vals
, False
))
{
case eIsReg
:
if (!check_mode_mask
(pArg
, ModReg
, ModeMask
))
return False
;
if (((OpSize
== eSymbolSize64Bit
) || (OpSize
== eSymbolSizeFloat64Bit
))
&& (pResult
->vals
[0] == 31))
WrStrErrorPos
(ErrNum_Unpredictable
, pArg
);
pResult
->vals
[0] |= 0x60;
pResult
->m
= 1;
pResult
->count
= 1;
return True
;
case eRegAbort
:
return False
;
default:
break;
}
/* treat bare address as PC-relative */
CutSize
(pArg
, &DispSize
);
DispValue
= EvalDispOpt
(pArg
, &EvalResult
, True
);
if (!EvalResult.
OK)
return False
;
pResult
->forced_disp_size
= DispSize
;
if (!DeduceAndCheckDispSize
(pArg
, DispValue
, &DispSize
, &EvalResult
))
return False
;
if (IndexReg
!= REGSYM_FLAG_ALIAS
)
{
pResult
->vals
[pResult
->count
++] = 0xc0 | IndexReg
;
pResult
->m
= 1;
}
else
pResult
->m
= 0;
pResult
->vals
[pResult
->count
++] = 0xf0 + DispSize
;
AppendToVals
(pResult
, DispValue
, DispSize
);
}
return (pResult
->count
> 0) && check_mode_mask
(pArg
, ModMem
, ModeMask
);
}
/*!------------------------------------------------------------------------
* \fn IsReg(const tAdrVals *p_vals)
* \brief check whether encoded address expression is register-direct ( Rn )
* \param p_vals encoded address expression
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean IsReg
(const tAdrVals
*p_vals
)
{
return ((p_vals
->count
== 1)
&& (p_vals
->m
== 1)
&& ((p_vals
->vals
[0] & 0xe0) == 0x60));
}
/*!------------------------------------------------------------------------
* \fn IsRegIndirect(const tAdrVals *p_vals)
* \brief check whether encoded address expression is register indirect ( [Rn] )
* \param p_vals encoded address expression
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean IsRegIndirect
(const tAdrVals
*p_vals
)
{
return ((p_vals
->count
== 1)
&& (p_vals
->m
== 0)
&& ((p_vals
->vals
[0] & 0xe0) == 0x60));
}
/*!------------------------------------------------------------------------
* \fn IsPreDecrement(const tAdrVals *p_vals, Byte *p_reg)
* \brief check whether encoded address expression is pre-decrement ( [-Rn] )
* \param p_vals encoded address expression
* \param p_reg return buffer for used register
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean IsPreDecrement
(const tAdrVals
*p_vals
, Byte
*p_reg
)
{
if ((p_vals
->count
== 1)
&& (p_vals
->m
== 1)
&& ((p_vals
->vals
[0] & 0xe0) == 0xa0))
{
if (p_reg
) *p_reg
= p_vals
->vals
[0] & 0x1f;
return True
;
}
else
return False
;
}
/*!------------------------------------------------------------------------
* \fn IsPostIncrement(const tAdrVals *p_vals, Byte *p_reg)
* \brief check whether encoded address expression is post-increment ( [Rn+] )
* \param p_vals encoded address expression
* \param p_reg return buffer for used register
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean IsPostIncrement
(const tAdrVals
*p_vals
, Byte
*p_reg
)
{
if ((p_vals
->count
== 1)
&& (p_vals
->m
== 1)
&& ((p_vals
->vals
[0] & 0xe0) == 0x80))
{
if (p_reg
) *p_reg
= p_vals
->vals
[0] & 0x1f;
return True
;
}
else
return False
;
}
/*!------------------------------------------------------------------------
* \fn IsAbsolute(const tAdrVals *p_vals)
* \brief check whether encoded address expression is absolute ( /abs )
* \param p_vals encoded address expression
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean IsAbsolute
(const tAdrVals
*p_vals
)
{
return ((p_vals
->count
== 5)
&& (p_vals
->m
== 0)
&& (p_vals
->vals
[0] == 0xf3));
}
/*!------------------------------------------------------------------------
* \fn IsAbsoluteIndirect(const tAdrVals *p_vals)
* \brief check whether encoded address expression is absolute indirect ( [/abs] )
* \param p_vals encoded address expression
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean IsAbsoluteIndirect
(const tAdrVals
*p_vals
)
{
return ((p_vals
->count
== 5)
&& (p_vals
->m
== 0)
&& (p_vals
->vals
[0] == 0xfb));
}
/*!------------------------------------------------------------------------
* \fn IsDisplacement(const tAdrVals *p_vals)
* \brief check whether encoded address expression is displacement
* \param p_vals encoded address expression
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean IsDisplacement
(const tAdrVals
*p_vals
)
{
Byte base_mode
= p_vals
->vals
[0],
base_mode_mode
= base_mode
& 0xe0;
return (p_vals
->m
== 0)
&& (p_vals
->count
> 1)
&& ((base_mode_mode
== 0x000) /* disp8[Rn] */
|| (base_mode
== 0x0f0) /* disp8[PC] */
|| (base_mode_mode
== 0x020) /* disp16[Rn] */
|| (base_mode
== 0x0f1) /* disp16[PC] */
|| (base_mode_mode
== 0x040) /* disp32[Rn] */
|| (base_mode
== 0x0f2)); /* disp32[PC] */
}
/*!------------------------------------------------------------------------
* \fn IsIndirectDisplacement(const tAdrVals *p_vals)
* \brief check whether encoded address expression is indirect displacement
* \param p_vals encoded address expression
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean IsIndirectDisplacement
(const tAdrVals
*p_vals
)
{
Byte base_mode
= p_vals
->vals
[0],
base_mode_mode
= base_mode
& 0xe0;
return (p_vals
->m
== 0)
&& (p_vals
->count
> 1)
&& ((base_mode_mode
== 0x080) /* [disp8[Rn]] */
|| (base_mode
== 0x0f8) /* [disp8[PC]] */
|| (base_mode_mode
== 0x0a0) /* [disp16[Rn]] */
|| (base_mode
== 0x0f9) /* [disp16[PC]] */
|| (base_mode_mode
== 0x0c0) /* [disp32[Rn]] */
|| (base_mode
== 0x0fa)); /* [disp32[PC]] */
}
/*!------------------------------------------------------------------------
* \fn IsImmediate(const tAdrVals *p_adr_vals, LongWord *p_imm_value)
* \brief check whether encoded address expression is immediate
* \param p_vals encoded address expression
* \param p_imm_value return buffer for immediate value
* \return True if immediate
* ------------------------------------------------------------------------ */
static Boolean IsImmediate
(const tAdrVals
*p_adr_vals
, LongWord
*p_imm_value
)
{
if ((p_adr_vals
->vals
[0] & 0xf0) == 0xe0)
{
*p_imm_value
= p_adr_vals
->vals
[0] & 0x0f;
return True
;
}
else if ((p_adr_vals
->vals
[0] == 0xf4) && (p_adr_vals
->count
> 1))
{
unsigned z
;
*p_imm_value
= 0;
for (z
= p_adr_vals
->count
- 1; z
> 0; z
--)
*p_imm_value
= (*p_imm_value
<< 8) | p_adr_vals
->vals
[z
];
return True
;
}
else
return False
;
}
/*!------------------------------------------------------------------------
* \fn IsSPAutoIncDec(const tAdrVals *p_adr_vals)
* \brief check whether encoded address expression is auto-increment/decrement with SP
* \param p_adr_vals encoded address expression
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean IsSPAutoIncDec
(const tAdrVals
*p_adr_vals
)
{
return ((p_adr_vals
->count
== 1)
&& p_adr_vals
->m
&& ((p_adr_vals
->vals
[0] == (0x80 | REG_SP
))
|| (p_adr_vals
->vals
[0] == (0xa0 | REG_SP
))));
}
/*!------------------------------------------------------------------------
* \fn IsIndexed(const tAdrVals *p_adr_vals, Byte *p_reg)
* \brief check whether encoded address expression uses an index register
* \param p_adr_vals encoded address expression
* \param p_reg return buffer for index register if yes
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean IsIndexed
(const tAdrVals
*p_adr_vals
, Byte
*p_reg
)
{
if ((p_adr_vals
->count
>= 1)
&& p_adr_vals
->m
&& ((p_adr_vals
->vals
[0] & 0xe0) == 0xc0))
{
if (p_reg
) *p_reg
= p_adr_vals
->vals
[0] & 0x1f;
return True
;
}
else
return False
;
}
/*!------------------------------------------------------------------------
* \fn DecodeBitAdr(tStrComp *p_arg, tAdrVals *p_result, unsigned ModeMask)
* \brief parse bit address expression
* \param p_arg source argument
* \param p_result result buffer
* \return True if success
* ------------------------------------------------------------------------ */
static void insert_index
(tAdrVals
*p_result
, Byte index_reg
)
{
memmove(p_result
->vals
+ 1, p_result
->vals
, p_result
->count
);
p_result
->vals
[0] = 0xc0 | index_reg
;
p_result
->count
++;
p_result
->m
= 1;
}
static void extend_adrvals_size
(tAdrVals
*p_result
, tSymbolSize
*p_curr_size
, tSymbolSize target_size
, Byte mod_incr
)
{
while (*p_curr_size
< target_size
)
{
Byte ext
= (p_result
->vals
[p_result
->count
- 1] & 0x80) ? 0xff : 0x00;
p_result
->vals
[0] += mod_incr
;
*p_curr_size
= (tSymbolSize
)(*p_curr_size
+ 1);
switch (*p_curr_size
)
{
case eSymbolSize32Bit
:
p_result
->vals
[p_result
->count
++] = ext
;
/* FALL-THRU */
case eSymbolSize16Bit
:
p_result
->vals
[p_result
->count
++] = ext
;
break;
default:
break;
}
}
}
static Boolean DecodeBitAdr
(tStrComp
*p_arg
, tAdrVals
*p_result
, unsigned ModeMask
)
{
char *p_sep
;
tStrComp offset_arg
, base_arg
;
Byte offs_reg
;
tEvalResult eval_result
;
/* find '@' that separates bit offset & byte base address, which MUST be present: */
p_sep
= QuotPos
(p_arg
->str.
p_str, '@');
if (!p_sep
)
{
WrStrErrorPos
(ErrNum_InvAddrMode
, p_arg
);
return False
;
}
StrCompSplitRef
(&offset_arg
, &base_arg
, p_arg
, p_sep
);
KillPostBlanksStrComp
(&offset_arg
);
KillPrefBlanksStrCompRef
(&base_arg
);
/* parse the base address */
(void)ModeMask
;
if (!DecodeAdr
(&base_arg
, p_result
, MModMem
))
return False
;
/* no offset: the encoding remains the same, just check for valid addressing modes: */
if (!offset_arg.
str.
p_str[0])
{
eval_result.
OK =
IsRegIndirect
(p_result
)
|| IsPostIncrement
(p_result
, NULL
)
|| IsPreDecrement
(p_result
, NULL
)
|| IsIndirectDisplacement
(p_result
)
|| IsAbsolute
(p_result
)
|| IsAbsoluteIndirect
(p_result
);
if (!eval_result.
OK)
WrStrErrorPos
(ErrNum_InvAddrMode
, &base_arg
);
}
else switch (DecodeReg
(&offset_arg
, &offs_reg
, False
))
{
/* offset is register: if this is a valid addressing mode, insert register
as index register: */
case eIsReg
:
eval_result.
OK = True
;
if (IsRegIndirect
(p_result
)
|| IsDisplacement
(p_result
)
|| IsIndirectDisplacement
(p_result
)
|| IsAbsolute
(p_result
)
|| IsAbsoluteIndirect
(p_result
))
insert_index
(p_result
, offs_reg
);
else
eval_result.
OK = False
;
if (!eval_result.
OK)
WrStrErrorPos
(ErrNum_InvAddrMode
, &base_arg
);
break;
/* offset is immediate value: */
case eIsNoReg
:
{
tSymbolSize forced_offset_size
= eSymbolSizeUnknown
, offset_size
;
CutSize
(&offset_arg
, &forced_offset_size
);
p_result
->bit_offset
= EvalStrIntExpressionWithResult
(&offset_arg
, SInt32
, &eval_result
);
if (!eval_result.
OK)
break;
p_result
->immediate_flags
= eval_result.
Flags;
offset_size
= forced_offset_size
;
if (!(eval_result.
OK = DeduceAndCheckDispSize
(&offset_arg
, p_result
->bit_offset
, &offset_size
, &eval_result
)))
break;
/* base addressing mode has no displacement so far: append as first displacement */
if (IsRegIndirect
(p_result
))
{
p_result
->vals
[0] = (p_result
->vals
[0] & 0x1f) | (offset_size
<< 5);
AppendToVals
(p_result
, p_result
->bit_offset
, offset_size
);
}
/* single (indirect) displacement becomes double displacement */
else if (IsIndirectDisplacement
(p_result
))
{
Boolean base_pc
= !!(p_result
->vals
[0] & 0x10);
/* extract operand size of base displacement */
tSymbolSize base_disp_size
= (tSymbolSize
)((p_result
->vals
[0] >> (base_pc
? 0 : 5)) & 3);
/* Similar to disp1 & disp2, base & offset must have same length, so if
lengths are unequal, extend one of them, or complain if we cannot make
things fit: */
/* (1) No explicit length given for either: extend the other one as needed
if actual sizes differ: */
if ((p_result
->forced_disp_size
== eSymbolSizeUnknown
)
&& (forced_offset_size
== eSymbolSizeUnknown
))
{
if (offset_size
< base_disp_size
)
offset_size
= base_disp_size
;
else if (base_disp_size
< offset_size
)
extend_adrvals_size
(p_result
, &base_disp_size
, offset_size
, p_result
->vals
[0] += base_pc
? 0x01 : 0x20);
}
/* (2a) Only base displacement size is fixed: see if offset size can be extended */
else if (forced_offset_size
== eSymbolSizeUnknown
)
{
if (offset_size
< base_disp_size
)
offset_size
= base_disp_size
;
else
{
WrStrErrorPos
(ErrNum_OverRange
, &offset_arg
);
return False
;
}
}
/* (2b) Vice versa, if only offset size is fixed: */
else if (p_result
->forced_disp_size
== eSymbolSizeUnknown
)
{
if (base_disp_size
< offset_size
)
extend_adrvals_size
(p_result
, &base_disp_size
, offset_size
, p_result
->vals
[0] += base_pc
? 0x01 : 0x20);
else
{
WrStrErrorPos
(ErrNum_OverRange
, &base_arg
);
return False
;
}
}
/* (3) if both sizes are fixed, they must be equal: */
else if (p_result
->forced_disp_size
!= forced_offset_size
)
{
WrStrErrorPos
(ErrNum_ConfOpSizes
, p_arg
);
return False
;
}
/* All fine: Change addressing mode to double displacement,
and add bit offset as second displacement */
if (base_pc
)
p_result
->vals
[0] |= 0x04;
else
{
p_result
->m
= 1;
p_result
->vals
[0] &= ~
0x80;
}
AppendToVals
(p_result
, p_result
->bit_offset
, offset_size
);
}
/* everything else not allowed */
else
{
WrStrErrorPos
(ErrNum_InvAddrMode
, &base_arg
);
eval_result.
OK = False
;
}
p_result
->bit_offset_immediate
= True
;
break;
}
default: /* eRegAbort */
eval_result.
OK = False
;
}
return eval_result.
OK;
}
/*--------------------------------------------------------------------------*/
/* Utility Functions */
/*!------------------------------------------------------------------------
* \fn ChkNoAttrPart(void)
* \brief check for no attribute part
* \return True if no attribute
* ------------------------------------------------------------------------ */
static Boolean ChkNoAttrPart
(void)
{
if (*AttrPart.
str.
p_str)
{
WrError
(ErrNum_UseLessAttr
);
return False
;
}
return True
;
}
/*!------------------------------------------------------------------------
* \fn ChkOpSize(int Op8, int Op16, int Op32, int Op64)
* \brief check for valid (single) (integer) operand size
* \param Op8 machine code if size is 8 bits
* \param Op16 machine code if size is 16 bits
* \param Op32 machine code if size is 32 bits
* \param Op64 machine code if size is 64 bits
* \return True if size is OK
* ------------------------------------------------------------------------ */
static Boolean ChkOpSize
(int Op8
, int Op16
, int Op32
, int Op64
)
{
if (AttrPartOpSize
[1] != eSymbolSizeUnknown
)
{
WrStrErrorPos
(ErrNum_InvOpSize
, &AttrPart
);
return False
;
}
if (OpSize
== eSymbolSizeUnknown
)
{
if (AttrPartOpSize
[0] != eSymbolSizeUnknown
)
OpSize
= AttrPartOpSize
[0];
else if ((Op8
>= 0) && Hi
(Op8
))
OpSize
= eSymbolSize8Bit
;
else if ((Op16
>= 0) && Hi
(Op16
))
OpSize
= eSymbolSize16Bit
;
else if ((Op32
>= 0) && Hi
(Op32
))
OpSize
= eSymbolSize32Bit
;
else if ((Op64
>= 0) && Hi
(Op64
))
OpSize
= eSymbolSize64Bit
;
}
switch (OpSize
)
{
case eSymbolSize8Bit
:
if (Op8
< 0)
goto Bad
;
BAsmCode
[CodeLen
] = Op8
;
return True
;
case eSymbolSize16Bit
:
if (Op16
< 0)
goto Bad
;
BAsmCode
[CodeLen
] = Op16
;
return True
;
case eSymbolSize32Bit
:
if (Op32
< 0)
goto Bad
;
BAsmCode
[CodeLen
] = Op32
;
return True
;
case eSymbolSize64Bit
:
if (Op64
< 0)
goto Bad
;
BAsmCode
[CodeLen
] = Op64
;
return True
;
default:
Bad
:
WrStrErrorPos
(ErrNum_InvOpSize
, &OpPart
);
return False
;
}
}
/*!------------------------------------------------------------------------
* \fn ChkFOpSize(int op_short, int op_long)
* \brief check for valid (real) operand size
* \param op_short machine code if size short real
* \param op_long machine code if size is long real
* \return True if size is OK
* ------------------------------------------------------------------------ */
static Boolean ChkFOpSize
(int op_short
, int op_long
)
{
if (AttrPartOpSize
[1] != eSymbolSizeUnknown
)
{
WrStrErrorPos
(ErrNum_InvOpSize
, &AttrPart
);
return False
;
}
if (OpSize
== eSymbolSizeUnknown
)
{
if (AttrPartOpSize
[0] != eSymbolSizeUnknown
)
OpSize
= AttrPartOpSize
[0];
else if ((op_short
>= 0) && Hi
(op_short
))
OpSize
= eSymbolSizeFloat32Bit
;
else if ((op_long
>= 0) && Hi
(op_long
))
OpSize
= eSymbolSizeFloat64Bit
;
}
switch (OpSize
)
{
case eSymbolSizeFloat32Bit
:
if (op_short
< 0)
goto Bad
;
BAsmCode
[CodeLen
] = op_short
;
return True
;
case eSymbolSizeFloat64Bit
:
if (op_long
< 0)
goto Bad
;
BAsmCode
[CodeLen
] = op_long
;
return True
;
default:
Bad
:
WrStrErrorPos
(ErrNum_InvOpSize
, &OpPart
);
return False
;
}
}
/*!------------------------------------------------------------------------
* \fn ChkPtrOpSize(int op_ptr)
* \brief check for valid (pointer) operand size
* \param op_ptr machine code if size is pointer
* \return True if size is OK
* ------------------------------------------------------------------------ */
static Boolean ChkPtrOpSize
(int op_ptr
)
{
if (AttrPartOpSize
[1] != eSymbolSizeUnknown
)
{
WrStrErrorPos
(ErrNum_InvOpSize
, &AttrPart
);
return False
;
}
if (OpSize
== eSymbolSizeUnknown
)
{
if (AttrPartOpSize
[0] != eSymbolSizeUnknown
)
OpSize
= AttrPartOpSize
[0];
else if ((op_ptr
>= 0) && Hi
(op_ptr
))
OpSize
= eSymbolSize24Bit
;
}
switch (OpSize
)
{
case eSymbolSize24Bit
:
if (op_ptr
< 0)
goto Bad
;
OpSize
= eSymbolSize32Bit
;
BAsmCode
[CodeLen
] = Lo
(op_ptr
);
return True
;
default:
Bad
:
WrStrErrorPos
(ErrNum_InvOpSize
, &OpPart
);
return False
;
}
}
/*!------------------------------------------------------------------------
* \fn chk_sup_mode(Word code)
* \brief check whether privileged instructions are enabled
* \param code machine code with sup mode flag
* \return True if enabled or not required
* ------------------------------------------------------------------------ */
static Boolean chk_sup_mode
(Word code
)
{
if ((code
& CODE_FLAG_SUPMODE
) && !SupAllowed
)
{
WrStrErrorPos
(ErrNum_PrivOrder
, &OpPart
);
return False
;
}
else
return True
;
}
/*!------------------------------------------------------------------------
* \fn AppendAdrVals(const tAdrVals *p_vals)
* \brief append addressing mode extension values to instruction
* \param p_vals holds encoded addressing expression
* ------------------------------------------------------------------------ */
static void AppendAdrVals
(const tAdrVals
*p_vals
)
{
memcpy(&BAsmCode
[CodeLen
], p_vals
->vals
, p_vals
->count
);
CodeLen
+= p_vals
->count
;
}
/*!------------------------------------------------------------------------
* \fn DecodeLength(tStrComp *p_arg, tLenVals *p_len_vals)
* \brief decode length argument of bit string insns
* \param p_arg source argument
* \param p_len_vals encoded length argument
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean DecodeLength
(tStrComp
*p_arg
, tLenVals
*p_len_vals
)
{
tAdrVals adr_vals
;
LongWord length
;
if (!DecodeAdr
(p_arg
, &adr_vals
, MModReg
| MModImm
| MModImm7Bit
))
return False
;
p_len_vals
->immediate_flags
= adr_vals.
immediate_flags;
if (IsReg
(&adr_vals
))
p_len_vals
->val
= 0x80 | (adr_vals.
vals[0] & 0x1f);
else if (IsImmediate
(&adr_vals
, &length
))
p_len_vals
->val
= length
& 127;
else
{
WrStrErrorPos
(ErrNum_InvAddrMode
, p_arg
);
return False
;
}
return True
;
}
/*!------------------------------------------------------------------------
* \fn IsImmediateLength(const tLenVals *p_len_vals, LongWord *p_imm_val)
* \brief check whether encoded bit field length is immediate value
* \param p_len_vals encoded length field from instruction
* \param p_imm_val return buffer if immediate
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean IsImmediateLength
(const tLenVals
*p_len_vals
, LongWord
*p_imm_val
)
{
if (p_len_vals
->val
& 0x80)
return False
;
else
{
*p_imm_val
= p_len_vals
->val
& 0x7f;
return True
;
}
}
/*!------------------------------------------------------------------------
* \fn imm_mask_cond(Word code)
* \brief check whether immediate mode is allowed and return accordingly
* \param code machine code holding CODE_FLAG_OP2_IMM in MSB or not
* \return immediate mask if allowed or 0
* ------------------------------------------------------------------------ */
static unsigned imm_mask_cond
(Word code
)
{
return (code
& CODE_FLAG_OP2_IMM
) ? MModImm
: 0;
}
/*!------------------------------------------------------------------------
* \fn check_addrmodes_unpredictable(const tAdrVals *p_first_vals, const tAdrVals *p_second_vals)
* \brief check whether the combination of two addressing modes may yield unpredictable results
* \param p_first_vals encoded first operand
* \param p_second_vals encoded second operand
* \return True if unpredictable result may occur
* ------------------------------------------------------------------------ */
static Boolean check_addrmodes_unpredictable
(const tAdrVals
*p_first_vals
, const tAdrVals
*p_second_vals
)
{
Byte first_reg
= 0, second_reg
= 0;
/* For all unpredictable combinations, first operand must be auto-increment: */
if (!IsPreDecrement
(p_first_vals
, &first_reg
)
&& !IsPostIncrement
(p_first_vals
, &first_reg
))
return False
;
/* If second operand is auto-increment with same register,
result is unpredictable if both operand sizes differ: */
if ((IsPreDecrement
(p_second_vals
, &second_reg
) || IsPostIncrement
(p_second_vals
, &second_reg
))
&& (second_reg
== first_reg
)
&& (p_first_vals
->data_op_size
!= p_second_vals
->data_op_size
))
{
WrError
(ErrNum_Unpredictable
);
return True
;
}
/* If second operand uses same register as index register,
result is unpredictable: */
else if (IsIndexed
(p_second_vals
, &second_reg
) && (second_reg
== first_reg
))
{
WrError
(ErrNum_Unpredictable
);
return True
;
}
else
return False
;
}
/*!------------------------------------------------------------------------
* \fn EncodeFormat1(Byte Reg, const tAdrVals *pSecond)
* \brief encode instruction in format I
* \param Reg Register# + direction bit
* \param pSecond second operand
* ------------------------------------------------------------------------ */
static void EncodeFormat1
(Byte Reg
, const tAdrVals
*pSecond
)
{
CodeLen
++;
BAsmCode
[CodeLen
++] = Reg
| (pSecond
->m
<< 6);
AppendAdrVals
(pSecond
);
}
/*!------------------------------------------------------------------------
* \fn EncodeFormat2(Byte SubOp, const tAdrVals *pFirst, const tAdrVals *pSecond)
* \brief encode instruction in format II
* \param SubOp extension byte
* \param pFirst first operand
* \param pSecond second operand
* ------------------------------------------------------------------------ */
static void EncodeFormat2
(Byte SubOp
, const tAdrVals
*pFirst
, const tAdrVals
*pSecond
)
{
CodeLen
++;
BAsmCode
[CodeLen
++] = SubOp
| 0x80 | (pSecond
->m
<< 5) | (pFirst
->m
<< 6);
AppendAdrVals
(pFirst
);
AppendAdrVals
(pSecond
);
check_addrmodes_unpredictable
(pFirst
, pSecond
);
}
/*!------------------------------------------------------------------------
* \fn EncodeFormat1Or2(Byte SubOp, const tAdrVals *pFirst, const tAdrVals *pSecond)
* \brief encode instruction in format I if possible or format II
* \param SubOp extension byte for format II
* \param pFirst first operand
* \param pSecond second operand
* ------------------------------------------------------------------------ */
static void EncodeFormat1Or2
(Byte SubOp
, const tAdrVals
*pFirst
, const tAdrVals
*pSecond
)
{
if (IsReg
(pFirst
))
EncodeFormat1
(pFirst
->vals
[0] & 0x1f, pSecond
);
else if (IsReg
(pSecond
))
EncodeFormat1
((pSecond
->vals
[0] & 0x1f) | 0x20, pFirst
);
else
EncodeFormat2
(SubOp
, pFirst
, pSecond
);
}
/*!------------------------------------------------------------------------
* \fn EncodeFormat3(const tAdrVals *p_adr_vals)
* \brief encode instruction in format III
* \param p_adr_vals operand
* ------------------------------------------------------------------------ */
static void EncodeFormat3
(const tAdrVals
*p_adr_vals
)
{
BAsmCode
[CodeLen
] |= p_adr_vals
->m
;
CodeLen
++;
AppendAdrVals
(p_adr_vals
);
}
/*!------------------------------------------------------------------------
* \fn chk_imm_bitfield_range(const tStrComp *p_bitfield_src_arg, const tAdrVals *p_bitfield_adr_vals, const tLenVals *p_len_vals)
* \brief check whether bit field's length plus offset do not exceed allowed range
* \param p_bitfield_src_arg source argument of bit field start+offset
* \param p_bitfield_adr_vals encoded value of bit field start+offset
* \param p_len_vals encoded value of bit field length
* ------------------------------------------------------------------------ */
static void chk_imm_bitfield_range
(const tStrComp
*p_bitfield_src_arg
, const tAdrVals
*p_bitfield_adr_vals
, const tLenVals
*p_len_vals
)
{
LongWord imm_length
;
/* optional check for offset+length <= 32, if possible: */
if (p_bitfield_adr_vals
->bit_offset_immediate
&& !mFirstPassUnknownOrQuestionable
(p_bitfield_adr_vals
->immediate_flags
)
&& IsImmediateLength
(p_len_vals
, &imm_length
)
&& !mFirstPassUnknownOrQuestionable
(p_len_vals
->immediate_flags
)
&& (p_bitfield_adr_vals
->bit_offset
+ imm_length
> 32))
{
char Msg
[64];
as_snprintf
(Msg
, sizeof(Msg
), "%u + %u > 32",
(unsigned)p_bitfield_adr_vals
->bit_offset
,
(unsigned)imm_length
);
WrXErrorPos
(ErrNum_ArgOutOfRange
, Msg
, &p_bitfield_src_arg
->Pos
);
}
}
/*!------------------------------------------------------------------------
* \fn chk_imm_value_range(const tStrComp *p_src_arg, const tAdrVals *p_adr_vals, const char *p_name, unsigned max_value)
* \brief check whether immediate value is in range
* \param p_arg source argument of value
* \param p_adr_vals encoded value of value
* ------------------------------------------------------------------------ */
static void chk_imm_value_range
(const tStrComp
*p_src_arg
, const tAdrVals
*p_adr_vals
, const char *p_name
, unsigned max_value
)
{
LongWord imm_value
;
if (IsImmediate
(p_adr_vals
, &imm_value
)
&& !mFirstPassUnknownOrQuestionable
(p_adr_vals
->immediate_flags
)
&& (imm_value
> max_value
))
{
char Msg
[64];
as_snprintf
(Msg
, sizeof(Msg
), "%s %u > %u",
p_name
, (unsigned)imm_value
, max_value
);
WrXErrorPos
(ErrNum_ArgOutOfRange
, Msg
, &p_src_arg
->Pos
);
}
}
/*!------------------------------------------------------------------------
* \fn chk_imm_level_range(const tStrComp *p_level_src_arg, const tAdrVals *p_level_adr_vals)
* \brief check whether (privilege) level is in range (0..3)
* \param p_level_src_arg source argument of level
* \param p_level_adr_vals encoded value of level
* ------------------------------------------------------------------------ */
static void chk_imm_level_range
(const tStrComp
*p_level_src_arg
, const tAdrVals
*p_level_adr_vals
)
{
chk_imm_value_range
(p_level_src_arg
, p_level_adr_vals
, "lvl", 3);
}
/*--------------------------------------------------------------------------*/
/* Instruction Handlers */
/*!------------------------------------------------------------------------
* \fn DecodeFixed(Word Code)
* \brief handle instructions with no argument
* \param Code machine code
* ------------------------------------------------------------------------ */
static void DecodeFixed
(Word Code
)
{
if (ChkArgCnt
(0, 0)
&& chk_sup_mode
(Code
)
&& ChkNoAttrPart
())
BAsmCode
[CodeLen
++] = Lo
(Code
);
}
/*!------------------------------------------------------------------------
* \fn DecodeArithF(Word code)
* \brief handle FPU arithmetic instructions
* \param code machine opcode for short op size
* ------------------------------------------------------------------------ */
static void DecodeArithF
(Word code
)
{
tAdrVals src_adr_vals
, dest_adr_vals
;
if (ChkArgCnt
(2, 2)
&& ChkFOpSize
(0x100 | Lo
(code
), Lo
(code
) | 0x02)
&& DecodeAdr
(&ArgStr
[1], &src_adr_vals
, MModMem
| MModReg
)
&& DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, MModMem
| MModReg
))
{
EncodeFormat2
(Hi
(code
), &src_adr_vals
, &dest_adr_vals
);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeSCLF(Word code)
* \brief handle SCLF Instruction
* \param code machine opcode for short op size
* ------------------------------------------------------------------------ */
static void DecodeSCLF
(Word code
)
{
if (ChkArgCnt
(2, 2)
&& ChkFOpSize
(0x100 | Lo
(code
), Lo
(code
) | 0x02))
{
tAdrVals count_adr_vals
;
tSymbolSize save_op_size
;
save_op_size
= OpSize
;
OpSize
= eSymbolSize16Bit
;
if (DecodeAdr
(&ArgStr
[1], &count_adr_vals
, MModMem
| MModReg
| MModImm
))
{
tAdrVals dest_adr_vals
;
OpSize
= save_op_size
;
if (DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, MModMem
| MModReg
))
EncodeFormat2
(Hi
(code
), &count_adr_vals
, &dest_adr_vals
);
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeArith(Word code)
* \brief handle arithmetic instructions
* \param code machine code for 8 bit in LSB, bit 8 -> dest may be immediate
* ------------------------------------------------------------------------ */
static void DecodeArith
(Word code
)
{
tAdrVals src_adr_vals
, dest_adr_vals
;
if (ChkArgCnt
(2, 2)
&& ChkOpSize
(Lo
(code
), Lo
(code
) + 2, 0x100 | (Lo
(code
) + 4), -1)
&& DecodeAdr
(&ArgStr
[1], &src_adr_vals
, MModMem
| MModReg
| MModImm
)
&& DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, MModMem
| MModReg
| imm_mask_cond
(code
)))
EncodeFormat1Or2
(0x00, &src_adr_vals
, &dest_adr_vals
);
}
/*!------------------------------------------------------------------------
* \fn DecodeArithX(Word code)
* \brief handle arithmetic instructions with double dest width
* \param code machine code for 8 bit in LSB
* ------------------------------------------------------------------------ */
static void DecodeArithX
(Word code
)
{
tAdrVals src_adr_vals
, dest_adr_vals
;
if (ChkArgCnt
(2, 2)
&& ChkOpSize
(-1, -1, 0x100 | Lo
(code
), -1)
&& DecodeAdr
(&ArgStr
[1], &src_adr_vals
, MModMem
| MModReg
| MModImm
)
&& DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, MModMem
| MModReg
))
EncodeFormat1Or2
(0x00, &src_adr_vals
, &dest_adr_vals
);
}
/*!------------------------------------------------------------------------
* \fn DecodeXCH(Word code)
* \brief handle XCH instruction
* \param code machine code for 8 bit operand size
* ------------------------------------------------------------------------ */
static void DecodeXCH
(Word code
)
{
tAdrVals dest1_adr_vals
, dest2_adr_vals
;
if (ChkArgCnt
(2, 2)
&& ChkOpSize
(Lo
(code
), Lo
(code
) + 2, 0x100 | (Lo
(code
) + 4), -1)
&& DecodeAdr
(&ArgStr
[1], &dest1_adr_vals
, MModMem
| MModReg
)
&& DecodeAdr
(&ArgStr
[2], &dest2_adr_vals
, MModMem
| MModReg
))
{
if (IsReg
(&dest1_adr_vals
))
EncodeFormat1
(dest1_adr_vals.
vals[0] & 0x1f, &dest2_adr_vals
);
else if (IsReg
(&dest2_adr_vals
))
EncodeFormat1
(dest2_adr_vals.
vals[0] & 0x1f, &dest1_adr_vals
);
else
WrError
(ErrNum_InvArgPair
);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeSETF(Word code)
* \brief handle SETF instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeSETF
(Word code
)
{
tAdrVals cond_adr_vals
, dest_adr_vals
;
if (ChkArgCnt
(2, 2)
&& ChkOpSize
(0x100 | Lo
(code
), -1, -1, -1)
&& DecodeAdr
(&ArgStr
[1], &cond_adr_vals
, MModMem
| MModReg
| MModImm
| MModImmCondition
)
&& DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, MModMem
| MModReg
))
{
EncodeFormat1Or2
(0, &cond_adr_vals
, &dest_adr_vals
);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeShift(Word code)
* \brief handle shift instructions
* \param code machine code for 8 bit in LSB
* ------------------------------------------------------------------------ */
static Boolean DecodeShiftCnt
(tStrComp
*p_arg
, tAdrVals
*p_adr_vals
)
{
tSymbolSize save_size
;
Boolean ret
;
save_size
= OpSize
;
OpSize
= eSymbolSize8Bit
;
ret
= DecodeAdr
(p_arg
, p_adr_vals
, MModMem
| MModReg
| MModImm
);
OpSize
= save_size
;
return ret
;
}
static void DecodeShift
(Word code
)
{
tAdrVals shift_adr_vals
, dest_adr_vals
;
if (ChkArgCnt
(2, 2)
&& ChkOpSize
(Lo
(code
), Lo
(code
) + 2, 0x100 | (Lo
(code
) + 4), -1)
&& DecodeShiftCnt
(&ArgStr
[1], &shift_adr_vals
)
&& DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, MModMem
| MModReg
))
EncodeFormat1Or2
(0x00, &shift_adr_vals
, &dest_adr_vals
);
}
/*!------------------------------------------------------------------------
* \fn DecodeArith_7c(Word code)
* \brief handle arithmetic instructions
* \param code machine code in LSB, sub-code in MSB
* ------------------------------------------------------------------------ */
static void DecodeArith_7c
(Word code
)
{
tAdrVals src_adr_vals
, dest_adr_vals
;
if (ChkArgCnt
(3, 3)
&& ChkOpSize
(0x100 | Lo
(code
), -1, -1, -1)
&& DecodeAdr
(&ArgStr
[1], &src_adr_vals
, MModMem
| MModReg
| MModImm
)
&& DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, MModMem
| MModReg
))
{
Boolean ok
;
Byte mask
= EvalStrIntExpressionOffs
(&ArgStr
[3], ArgStr
[3].
str.
p_str[0] == '#', Int8
, &ok
);
if (ok
)
{
EncodeFormat2
(Hi
(code
), &src_adr_vals
, &dest_adr_vals
);
BAsmCode
[CodeLen
++] = mask
;
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeBitString_7b(Word code)
* \brief handle bit string instructions
* \param code machine code in LSB, sub-code in MSB
* ------------------------------------------------------------------------ */
static void DecodeBitString_7b
(Word code
)
{
tAdrVals src_adr_vals
, dest_adr_vals
;
tLenVals length
;
if (ChkArgCnt
(3, 3)
&& ChkNoAttrPart
())
{
OpSize
= eSymbolSize8Bit
;
if (DecodeBitAdr
(&ArgStr
[1], &src_adr_vals
, MModMem
)
&& DecodeLength
(&ArgStr
[2], &length
)
&& DecodeBitAdr
(&ArgStr
[3], &dest_adr_vals
, MModMem
))
{
BAsmCode
[CodeLen
++] = Lo
(code
);
BAsmCode
[CodeLen
++] = Hi
(code
) | 0x80 | (dest_adr_vals.
m << 5) | (src_adr_vals.
m << 6);
AppendAdrVals
(&src_adr_vals
);
BAsmCode
[CodeLen
++] = length.
val;
AppendAdrVals
(&dest_adr_vals
);
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeBitField_7b(Word code)
* \brief handle bit field instructions
* \param code machine code in LSB, sub-code in MSB
* ------------------------------------------------------------------------ */
static void DecodeBitField_7b
(Word code
)
{
tAdrVals bsrc_adr_vals
, src_adr_vals
;
tLenVals length
;
if (ChkArgCnt
(3, 3)
&& ChkNoAttrPart
())
{
OpSize
= eSymbolSize32Bit
;
if (DecodeBitAdr
(&ArgStr
[1], &bsrc_adr_vals
, MModMem
)
&& DecodeLength
(&ArgStr
[2], &length
)
&& DecodeAdr
(&ArgStr
[3], &src_adr_vals
, MModReg
| MModMem
| imm_mask_cond
(code
)))
{
/* optional check for offset+length <= 32, if possible: */
if (code
& CODE_FLAG_LIM32
)
chk_imm_bitfield_range
(&ArgStr
[1], &bsrc_adr_vals
, &length
);
BAsmCode
[CodeLen
++] = Lo
(code
);
BAsmCode
[CodeLen
++] = (Hi
(code
) & 0x1f) | 0x80 | (src_adr_vals.
m << 5) | (bsrc_adr_vals.
m << 6);
AppendAdrVals
(&bsrc_adr_vals
);
BAsmCode
[CodeLen
++] = length.
val;
AppendAdrVals
(&src_adr_vals
);
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeBitField_7c(Word code)
* \brief handle bit field instructions
* \param code machine code in LSB, sub-code in MSB
* ------------------------------------------------------------------------ */
static void DecodeBitField_7c
(Word code
)
{
tAdrVals src_adr_vals
, bdst_adr_vals
;
tLenVals length
;
if (ChkArgCnt
(3, 3)
&& ChkNoAttrPart
())
{
OpSize
= eSymbolSize32Bit
;
if (DecodeAdr
(&ArgStr
[1], &src_adr_vals
, MModReg
| MModMem
| MModImm
)
&& DecodeBitAdr
(&ArgStr
[2], &bdst_adr_vals
, MModMem
)
&& DecodeLength
(&ArgStr
[3], &length
))
{
/* optional check for offset+length <= 32, if possible: */
if (code
& CODE_FLAG_LIM32
)
chk_imm_bitfield_range
(&ArgStr
[2], &bdst_adr_vals
, &length
);
BAsmCode
[CodeLen
++] = Lo
(code
);
BAsmCode
[CodeLen
++] = (Hi
(code
) & 0x1f) | 0x80 | (bdst_adr_vals.
m << 5) | (src_adr_vals.
m << 6);
AppendAdrVals
(&src_adr_vals
);
AppendAdrVals
(&bdst_adr_vals
);
BAsmCode
[CodeLen
++] = length.
val;
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeString_7a(Word code)
* \brief Handle Format VIIa String Instructons
* \param code machine code (LSB) and subcode (MSB)
* ------------------------------------------------------------------------ */
static void DecodeString_7a
(Word code
)
{
tAdrVals src_adr_vals
, dest_adr_vals
;
tLenVals src_length
, dest_length
;
if (ChkArgCnt
(4, 4)
&& ChkOpSize
(0x100 | (Lo
(code
)), Lo
(code
) + 2, -1, -1)
&& DecodeAdr
(&ArgStr
[1], &src_adr_vals
, MModMem
)
&& DecodeLength
(&ArgStr
[2], &src_length
)
&& DecodeAdr
(&ArgStr
[3], &dest_adr_vals
, MModMem
)
&& DecodeLength
(&ArgStr
[4], &dest_length
))
{
CodeLen
++;
BAsmCode
[CodeLen
++] = (Hi
(code
) & 0x1f) | 0x80 | (dest_adr_vals.
m << 5) | (src_adr_vals.
m << 6);
AppendAdrVals
(&src_adr_vals
);
BAsmCode
[CodeLen
++] = src_length.
val;
AppendAdrVals
(&dest_adr_vals
);
BAsmCode
[CodeLen
++] = dest_length.
val;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeString_7b(Word code)
* \brief Handle Format VIIb String Instructons
* \param code machine code (LSB) and subcode (MSB)
* ------------------------------------------------------------------------ */
static void DecodeString_7b
(Word code
)
{
tAdrVals src_adr_vals
, char_adr_vals
;
tLenVals src_length
;
if (ChkArgCnt
(3, 3)
&& ChkOpSize
(0x100 | (Lo
(code
)), Lo
(code
) + 2, -1, -1)
&& DecodeAdr
(&ArgStr
[1], &src_adr_vals
, MModMem
)
&& DecodeLength
(&ArgStr
[2], &src_length
)
&& DecodeAdr
(&ArgStr
[3], &char_adr_vals
, MModReg
| MModMem
| MModImm
))
{
CodeLen
++;
BAsmCode
[CodeLen
++] = (Hi
(code
) & 0x1f) | 0x80 | (char_adr_vals.
m << 5) | (src_adr_vals.
m << 6);
AppendAdrVals
(&src_adr_vals
);
BAsmCode
[CodeLen
++] = src_length.
val;
AppendAdrVals
(&char_adr_vals
);
}
}
/*!------------------------------------------------------------------------
* \fn Decode_4(Word code)
* \brief handle relative branches
* \param code machine code for 16 bit displacement
* ------------------------------------------------------------------------ */
static void Decode_4
(Word code
)
{
if (ChkArgCnt
(1, 1))
{
Boolean ok
;
const Boolean allow_8
= (code
& 0xf0) == 0x70;
tSymbolFlags flags
;
LongWord addr
= EvalStrIntExpressionWithFlags
(&ArgStr
[1], UInt32
, &ok
, &flags
);
if (ok
)
{
LongInt delta
= addr
- EProgCounter
();
switch (AttrPartOpSize
[0])
{
case eSymbolSizeUnknown
:
if ((delta
> -128) && (delta
< 127) && allow_8
)
goto br_short
;
else
goto br_long
;
case eSymbolSizeFloat32Bit
: /* .s */
case eSymbolSize8Bit
: /* .b */
br_short
:
if (!allow_8
)
{
WrStrErrorPos
(ErrNum_InvOpSize
, &AttrPart
);
return;
}
code
-= 0x10;
if (!mFirstPassUnknownOrQuestionable
(flags
) && ((delta
< -128) || (delta
> 127))) WrError
(ErrNum_JmpDistTooBig
);
else
{
BAsmCode
[CodeLen
++] = code
;
BAsmCode
[CodeLen
++] = delta
& 0xff;
}
break;
case eSymbolSizeFloat64Bit
: /* .l */
case eSymbolSize16Bit
: /* .h */
br_long
:
if (!mFirstPassUnknownOrQuestionable
(flags
) && ((delta
< -32768) || (delta
> 32767))) WrError
(ErrNum_JmpDistTooBig
);
else
{
BAsmCode
[CodeLen
++] = code
;
BAsmCode
[CodeLen
++] = delta
& 0xff;
BAsmCode
[CodeLen
++] = (delta
>> 8) & 0xff;
}
break;
default:
WrStrErrorPos
(ErrNum_InvOpSize
, &AttrPart
);
return;
}
}
}
}
/*!------------------------------------------------------------------------
* \fn Decode_6(Word code)
* \brief handle loop instructions
* \param code machine code for 16 bit displacement
* ------------------------------------------------------------------------ */
static void Decode_6
(Word code
)
{
tAdrVals reg_adr_vals
;
/* allow no attribute at all since it would be unclear whether to check
for register operand's size (32 bits) or displacement operand's size
(16 bits): */
if (ChkArgCnt
(2, 2)
&& ChkNoAttrPart
()
&& DecodeAdr
(&ArgStr
[1], ®_adr_vals
, MModReg
))
{
Boolean ok
;
tSymbolFlags flags
;
LongWord addr
= EvalStrIntExpressionWithFlags
(&ArgStr
[2], UInt32
, &ok
, &flags
);
if (ok
)
{
LongInt delta
= addr
- EProgCounter
();
if (!mFirstPassUnknownOrQuestionable
(flags
) && ((delta
< -32768) || (delta
> 32767))) WrError
(ErrNum_JmpDistTooBig
);
else
{
BAsmCode
[CodeLen
++] = Lo
(code
);
BAsmCode
[CodeLen
++] = (reg_adr_vals.
vals[0] & 0x1f) | (Hi
(code
) << 5);
BAsmCode
[CodeLen
++] = delta
& 0xff;
BAsmCode
[CodeLen
++] = (delta
>> 8) & 0xff;
}
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeCLRTLB(Word code)
* \brief handle CLRTLB instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeCLRTLB
(Word code
)
{
tAdrVals adr_vals
;
if (ChkArgCnt
(1, 1)
&& ChkPtrOpSize
(Lo
(code
) | 0x100)
&& chk_sup_mode
(code
)
&& DecodeAdr
(&ArgStr
[1], &adr_vals
, MModMem
| MModImm
| MModReg
))
{
EncodeFormat3
(&adr_vals
);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeGETPSW(Word code)
* \brief handle GETPSW instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeGETPSW
(Word code
)
{
tAdrVals adr_vals
;
if (ChkArgCnt
(1, 1)
&& ChkOpSize
(-1, -1, 0x100 | Lo
(code
), -1)
&& DecodeAdr
(&ArgStr
[1], &adr_vals
, MModMem
| MModReg
))
{
EncodeFormat3
(&adr_vals
);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeUPDPSW(Word code)
* \brief handle UPDPSW instruction
* ------------------------------------------------------------------------ */
static void DecodeUPDPSW
(Word code
)
{
UNUSED
(code
);
if (ChkArgCnt
(2, 2)
&& ChkOpSize
(-1, 0x14a, 0x13, -1)
&& chk_sup_mode
((OpSize
== eSymbolSize32Bit
) ? CODE_FLAG_SUPMODE
: 0))
{
tAdrVals new_psw_adr_vals
, mask_adr_vals
;
OpSize
= eSymbolSize32Bit
;
if (DecodeAdr
(&ArgStr
[1], &new_psw_adr_vals
, MModImm
| MModMem
| MModReg
)
&& DecodeAdr
(&ArgStr
[2], &mask_adr_vals
, MModImm
| MModMem
| MModReg
))
EncodeFormat1Or2
(0, &new_psw_adr_vals
, &mask_adr_vals
);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeFormat3_bhw(Word code)
* \brief handle Format 3 instructions with 8/16/32 bit operand size
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeFormat3_bhw
(Word code
)
{
tAdrVals adr_vals
;
if (ChkArgCnt
(1, 1)
&& ChkOpSize
(Lo
(code
), Lo
(code
) + 2, 0x100 | (Lo
(code
) + 4), -1)
&& DecodeAdr
(&ArgStr
[1], &adr_vals
, MModMem
| MModReg
| imm_mask_cond
(code
)))
{
EncodeFormat3
(&adr_vals
);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeJMP_JSR(Word code)
* \brief handle JMP/JSR instructions
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeJMP_JSR
(Word code
)
{
tAdrVals adr_vals
;
if (ChkArgCnt
(1, 1)
&& ChkNoAttrPart
()
&& DecodeAdr
(&ArgStr
[1], &adr_vals
, MModMem
))
{
if (IsSPAutoIncDec
(&adr_vals
))
WrStrErrorPos
(ErrNum_Unpredictable
, &ArgStr
[1]);
BAsmCode
[CodeLen
] = code
;
EncodeFormat3
(&adr_vals
);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeFormat3_W(Word code)
* \brief handle instructions with single argument and 32 bit operand size
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeFormat3_W
(Word code
)
{
tAdrVals adr_vals
;
/* TODO: allow PUSHM/POPM immediate arg as register list similar to 68K? */
if (ChkArgCnt
(1, 1)
&& chk_sup_mode
(code
)
&& ChkOpSize
(-1, -1, 0x100 | Lo
(code
), -1)
&& DecodeAdr
(&ArgStr
[1], &adr_vals
, MModMem
| MModReg
| imm_mask_cond
(code
)))
{
EncodeFormat3
(&adr_vals
);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeFormat3_H(Word code)
* \brief handle instructions with single argument and 16 bit operand size
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeFormat3_H
(Word code
)
{
tAdrVals adr_vals
;
if (ChkArgCnt
(1, 1)
&& chk_sup_mode
(code
)
&& ChkOpSize
(-1, 0x100 | Lo
(code
), -1, -1)
&& DecodeAdr
(&ArgStr
[1], &adr_vals
, MModMem
| MModReg
| imm_mask_cond
(code
)))
{
EncodeFormat3
(&adr_vals
);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeFormat3_B(Word code)
* \brief handle instructions with single argument and 8 bit operand size
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeFormat3_B
(Word code
)
{
tAdrVals adr_vals
;
if (ChkArgCnt
(1, 1)
&& chk_sup_mode
(code
)
&& ChkOpSize
(0x100 | Lo
(code
), -1, -1, -1)
&& DecodeAdr
(&ArgStr
[1], &adr_vals
, MModMem
| MModReg
| imm_mask_cond
(code
)))
{
EncodeFormat3
(&adr_vals
);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeCALL(Word code)
* \brief handle CALL instructions
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeCALL
(Word code
)
{
tAdrVals target_adr_vals
, arg_adr_vals
;
/* TODO: If register direct mode is disallowed for both arguments,
checking for instruction format I does not make sense? */
if (ChkArgCnt
(2, 2)
&& ChkNoAttrPart
()
&& DecodeAdr
(&ArgStr
[1], &target_adr_vals
, MModMem
)
&& DecodeAdr
(&ArgStr
[2], &arg_adr_vals
, MModMem
))
{
if (IsSPAutoIncDec
(&target_adr_vals
))
WrStrErrorPos
(ErrNum_Unpredictable
, &ArgStr
[1]);
if (IsSPAutoIncDec
(&arg_adr_vals
))
WrStrErrorPos
(ErrNum_Unpredictable
, &ArgStr
[2]);
BAsmCode
[CodeLen
] = Lo
(code
);
EncodeFormat1Or2
(0x00, &target_adr_vals
, &arg_adr_vals
);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeCHKA(Word Code)
* \brief Decode CHKA instruction(s)
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeCHKA
(Word code
)
{
tAdrVals va_adr_vals
;
/* TODO: va is an address operand, so Rn and #imm do not make sense for va? */
if (ChkArgCnt
(2, 2)
&& ChkNoAttrPart
()
&& DecodeAdr
(&ArgStr
[1], &va_adr_vals
, MModMem
| MModReg
| MModImm
))
{
tAdrVals level_adr_vals
;
OpSize
= eSymbolSize8Bit
;
if (DecodeAdr
(&ArgStr
[2], &level_adr_vals
, MModMem
| MModReg
| MModImm
))
{
chk_imm_level_range
(&ArgStr
[1], &level_adr_vals
);
BAsmCode
[CodeLen
] = Lo
(code
);
EncodeFormat1Or2
(0x00, &va_adr_vals
, &level_adr_vals
);
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeCAXI(Word Code)
* \brief Decode CAXI instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeCAXI
(Word code
)
{
tAdrVals reg_adr_vals
, mem_adr_vals
;
if (ChkArgCnt
(2, 2)
&& ChkOpSize
(-1, -1, 0x100 | Lo
(code
), -1)
&& DecodeAdr
(&ArgStr
[1], ®_adr_vals
, MModReg
)
&& DecodeAdr
(&ArgStr
[2], &mem_adr_vals
, MModMem
| MModReg
))
EncodeFormat1
(reg_adr_vals.
vals[0] & 0x1f, &mem_adr_vals
);
}
/*!------------------------------------------------------------------------
* \fn DecodeCHLVL(Word Code)
* \brief Decode CHLVL instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeCHLVL
(Word code
)
{
tAdrVals level_adr_vals
, arg_adr_vals
;
if (ChkArgCnt
(2, 2)
&& ChkNoAttrPart
())
{
OpSize
= eSymbolSize8Bit
;
if (DecodeAdr
(&ArgStr
[1], &level_adr_vals
, MModMem
| MModReg
| MModImm
)
&& DecodeAdr
(&ArgStr
[2], &arg_adr_vals
, MModMem
| MModReg
| MModImm
))
{
chk_imm_level_range
(&ArgStr
[1], &level_adr_vals
);
BAsmCode
[CodeLen
] = Lo
(code
);
EncodeFormat1Or2
(0, &level_adr_vals
, &arg_adr_vals
);
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeGETXTE(Word Code)
* \brief Decode GETATE/GETPTE instructions
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeGETXTE
(Word code
)
{
tAdrVals va_adr_vals
, dst_adr_vals
;
if (ChkArgCnt
(2, 2)
&& chk_sup_mode
(code
)
&& ChkNoAttrPart
())
{
OpSize
= eSymbolSize32Bit
;
if (DecodeAdr
(&ArgStr
[1], &va_adr_vals
, MModMem
| MModReg
| MModImm
)
&& DecodeAdr
(&ArgStr
[2], &dst_adr_vals
, MModMem
| MModReg
| imm_mask_cond
(code
)))
{
BAsmCode
[CodeLen
] = Lo
(code
);
EncodeFormat1Or2
(0, &va_adr_vals
, &dst_adr_vals
);
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeCVT(Word code)
* \brief Handle CVT Instruction
* \param code machine code (abused as scratch)
* ------------------------------------------------------------------------ */
static void DecodeCVT
(Word code
)
{
tAdrVals src_adr_vals
, dest_adr_vals
;
if (!ChkArgCnt
(2, 2))
return;
if ((AttrPartOpSize
[0] == eSymbolSizeFloat32Bit
) && (AttrPartOpSize
[1] == eSymbolSizeFloat64Bit
))
code
= 0x105f;
else if ((AttrPartOpSize
[0] == eSymbolSizeFloat64Bit
) && (AttrPartOpSize
[1] == eSymbolSizeFloat32Bit
))
code
= 0x085f;
else if ((AttrPartOpSize
[0] == eSymbolSize32Bit
) && (AttrPartOpSize
[1] == eSymbolSizeFloat32Bit
))
code
= 0x005f;
else if ((AttrPartOpSize
[0] == eSymbolSize32Bit
) && (AttrPartOpSize
[1] == eSymbolSizeFloat64Bit
))
code
= 0x115f;
else if ((AttrPartOpSize
[0] == eSymbolSizeFloat32Bit
) && (AttrPartOpSize
[1] == eSymbolSize32Bit
))
code
= 0x015f;
else if ((AttrPartOpSize
[0] == eSymbolSizeFloat64Bit
) && (AttrPartOpSize
[1] == eSymbolSize32Bit
))
code
= 0x095f;
else
{
WrStrErrorPos
(ErrNum_UndefAttr
, &AttrPart
);
return;
}
OpSize
= AttrPartOpSize
[0];
if (!DecodeAdr
(&ArgStr
[1], &src_adr_vals
, MModReg
| MModMem
))
return;
OpSize
= AttrPartOpSize
[1];
if (!DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, MModReg
| MModMem
))
return;
BAsmCode
[CodeLen
] = Lo
(code
);
EncodeFormat2
(Hi
(code
), &src_adr_vals
, &dest_adr_vals
);
}
/*!------------------------------------------------------------------------
* \fn DecodeCVT(Word code)
* \brief Handle CVT Instruction
* \param code machine code (abused as scratch)
* ------------------------------------------------------------------------ */
static void DecodeCVTD
(Word code
)
{
tAdrVals src_adr_vals
, dest_adr_vals
;
Byte mask
;
Boolean ok
;
if (!ChkArgCnt
(3, 3))
return;
if ((AttrPartOpSize
[0] == eSymbolSize24Bit
) && (AttrPartOpSize
[1] == eSymbolSizeFloatDec96Bit
));
else if ((AttrPartOpSize
[0] == eSymbolSizeFloatDec96Bit
) && (AttrPartOpSize
[1] == eSymbolSize24Bit
))
code
|= 0x0800;
else
{
WrStrErrorPos
(ErrNum_UndefAttr
, &AttrPart
);
return;
}
OpSize
= (AttrPartOpSize
[0] == eSymbolSize24Bit
) ? eSymbolSize8Bit
: eSymbolSize16Bit
;
if (!DecodeAdr
(&ArgStr
[1], &src_adr_vals
, MModReg
| MModMem
| MModImm
))
return;
OpSize
= (AttrPartOpSize
[1] == eSymbolSize24Bit
) ? eSymbolSize8Bit
: eSymbolSize16Bit
;
if (!DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, MModReg
| MModMem
))
return;
mask
= EvalStrIntExpressionOffs
(&ArgStr
[3], ArgStr
[3].
str.
p_str[0] == '#', Int8
, &ok
);
BAsmCode
[CodeLen
] = Lo
(code
);
EncodeFormat2
(Hi
(code
), &src_adr_vals
, &dest_adr_vals
);
BAsmCode
[CodeLen
++] = mask
;
}
/*!------------------------------------------------------------------------
* \fn DecodeMOVS_MOVZ(Word code)
* \brief Handle MOVS/MOVZ Instructions
* \param code machine code for .bh
* ------------------------------------------------------------------------ */
static void DecodeMOVS_MOVZ
(Word code
)
{
tAdrVals src_adr_vals
, dest_adr_vals
;
if (!ChkArgCnt
(2, 2))
return;
if ((AttrPartOpSize
[0] == eSymbolSize8Bit
) && (AttrPartOpSize
[1] == eSymbolSize16Bit
))
;
else if ((AttrPartOpSize
[0] == eSymbolSize8Bit
) && (AttrPartOpSize
[1] == eSymbolSize32Bit
))
code
+= 0x02;
else if ((AttrPartOpSize
[0] == eSymbolSize16Bit
) && (AttrPartOpSize
[1] == eSymbolSize32Bit
))
code
+= 0x12;
else
{
WrStrErrorPos
(ErrNum_UndefAttr
, &AttrPart
);
return;
}
OpSize
= AttrPartOpSize
[0];
if (!DecodeAdr
(&ArgStr
[1], &src_adr_vals
, MModReg
| MModMem
| MModImm
))
return;
OpSize
= AttrPartOpSize
[1];
if (!DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, MModReg
| MModMem
))
return;
BAsmCode
[CodeLen
] = Lo
(code
);
EncodeFormat1Or2
(Lo
(code
), &src_adr_vals
, &dest_adr_vals
);
}
/*!------------------------------------------------------------------------
* \fn DecodeMOVT(Word code)
* \brief Handle MOVT Instructions
* \param code machine code for .hb
* ------------------------------------------------------------------------ */
static void DecodeMOVT
(Word code
)
{
tAdrVals src_adr_vals
, dest_adr_vals
;
if (!ChkArgCnt
(2, 2))
return;
if ((AttrPartOpSize
[0] == eSymbolSize16Bit
) && (AttrPartOpSize
[1] == eSymbolSize8Bit
))
;
else if ((AttrPartOpSize
[0] == eSymbolSize32Bit
) && (AttrPartOpSize
[1] == eSymbolSize8Bit
))
code
+= 0x10;
else if ((AttrPartOpSize
[0] == eSymbolSize32Bit
) && (AttrPartOpSize
[1] == eSymbolSize16Bit
))
code
+= 0x12;
else
{
WrStrErrorPos
(ErrNum_UndefAttr
, &AttrPart
);
return;
}
OpSize
= AttrPartOpSize
[0];
if (!DecodeAdr
(&ArgStr
[1], &src_adr_vals
, MModReg
| MModMem
| MModImm
))
return;
OpSize
= AttrPartOpSize
[1];
if (!DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, MModReg
| MModMem
))
return;
BAsmCode
[CodeLen
] = Lo
(code
);
EncodeFormat1Or2
(Lo
(code
), &src_adr_vals
, &dest_adr_vals
);
}
/*!------------------------------------------------------------------------
* \fn DecodeBit(Word code)
* \brief decode bit operations
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeBit
(Word code
)
{
tAdrVals offset_adr_vals
, base_adr_vals
;
if (ChkArgCnt
(2, 2)
&& ChkNoAttrPart
())
{
OpSize
= eSymbolSize32Bit
;
if (DecodeAdr
(&ArgStr
[1], &offset_adr_vals
, MModMem
| MModReg
| MModImm
)
&& DecodeAdr
(&ArgStr
[2], &base_adr_vals
, MModMem
| MModReg
))
{
chk_imm_value_range
(&ArgStr
[1], &offset_adr_vals
, "offset", 31);
BAsmCode
[CodeLen
] = Lo
(code
);
EncodeFormat1Or2
(0, &offset_adr_vals
, &base_adr_vals
);
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeIN_OUT(Word code)
* \brief handle IN & OUT instructions
* \param code machine code for 8 bit opsize; MSB -> is OUT
* ------------------------------------------------------------------------ */
static void DecodeIN_OUT
(Word code
)
{
tAdrVals src_adr_vals
, dest_adr_vals
;
Boolean is_out
= !!(Hi
(code
) & 1);
if (ChkArgCnt
(2, 2)
&& chk_sup_mode
(code
)
&& ChkOpSize
(Lo
(code
), Lo
(code
) + 2, 0x100 | Lo
(code
+ 4), -1)
&& DecodeAdr
(&ArgStr
[1], &src_adr_vals
, is_out
? (MModImm
| MModReg
| MModMem
) : (MModMem
| MModIO
))
&& DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, is_out
? (MModMem
| MModIO
) : (MModReg
| MModMem
)))
EncodeFormat1Or2
(0, &src_adr_vals
, &dest_adr_vals
);
}
/*!------------------------------------------------------------------------
* \fn DecodeArith_B(Word code)
* \brief handle format 1/2 instructions with fixed 8 bit size
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeArith_B
(Word code
)
{
tAdrVals src_adr_vals
, dest_adr_vals
;
if (ChkArgCnt
(2, 2)
&& chk_sup_mode
(code
)
&& ChkOpSize
(0x100 | Lo
(code
), -1, -1, -1)
&& DecodeAdr
(&ArgStr
[1], &src_adr_vals
, MModImm
| MModReg
| MModMem
)
&& DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, imm_mask_cond
(code
) | MModReg
| MModMem
))
EncodeFormat1Or2
(0, &src_adr_vals
, &dest_adr_vals
);
}
/*!------------------------------------------------------------------------
* \fn DecodeArith_W(Word code)
* \brief handle format 1/2 instructions with fixed 32 bit size
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeArith_W
(Word code
)
{
tAdrVals src_adr_vals
, dest_adr_vals
;
if (ChkArgCnt
(2, 2)
&& chk_sup_mode
(code
)
&& ChkOpSize
(-1, -1, 0x100 | Lo
(code
), -1)
&& DecodeAdr
(&ArgStr
[1], &src_adr_vals
, MModImm
| MModReg
| MModMem
)
&& DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, imm_mask_cond
(code
) | MModReg
| MModMem
))
EncodeFormat1Or2
(0, &src_adr_vals
, &dest_adr_vals
);
}
/*!------------------------------------------------------------------------
* \fn DecodeLDTASK(Word code)
* \brief Handle LDTASK Instruction
* \param code machine code
* ------------------------------------------------------------------------ */
static void DecodeLDTASK
(Word code
)
{
if (ChkArgCnt
(2, 2)
&& chk_sup_mode
(code
)
&& ChkNoAttrPart
())
{
tAdrVals list_adr_vals
, tcb_ptr_adr_vals
;
OpSize
= eSymbolSize32Bit
;
if (DecodeAdr
(&ArgStr
[1], &list_adr_vals
, MModImm
| MModReg
| MModMem
)
&& DecodeAdr
(&ArgStr
[2], &tcb_ptr_adr_vals
, MModImm
| MModReg
| MModMem
))
{
BAsmCode
[CodeLen
] = Lo
(code
);
EncodeFormat1Or2
(0, &list_adr_vals
, &tcb_ptr_adr_vals
);
}
}
}
/*!------------------------------------------------------------------------
* \fn DecodeMOVEA(Word code)
* \brief Handle MOVEA Instruction
* \param code machine code for 8 bit operand size
* ------------------------------------------------------------------------ */
static void DecodeMOVEA
(Word code
)
{
tAdrVals src_adr_vals
, dest_adr_vals
;
if (ChkArgCnt
(2, 2)
&& ChkOpSize
(Lo
(code
), Lo
(code
) + 2, 0x100 | (Lo
(code
) + 4), -1)
&& DecodeAdr
(&ArgStr
[1], &src_adr_vals
, MModMem
))
{
OpSize
= eSymbolSize32Bit
;
if (DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, MModReg
| MModMem
))
EncodeFormat1Or2
(0, &src_adr_vals
, &dest_adr_vals
);
}
}
/*!------------------------------------------------------------------------
* \fn DecodeMOV(Word Code)
* \brief handle MOV instruction
* ------------------------------------------------------------------------ */
static void DecodeMOV
(Word Code
)
{
tAdrVals src_adr_vals
, dest_adr_vals
;
UNUSED
(Code
);
if (ChkArgCnt
(2, 2)
&& ChkOpSize
(0x09, 0x1b, 0x12d, 0x3f)
&& DecodeAdr
(&ArgStr
[1], &src_adr_vals
, MModMem
| MModImm
| MModReg
)
&& DecodeAdr
(&ArgStr
[2], &dest_adr_vals
, MModMem
| MModReg
))
EncodeFormat1Or2
(0x00, &src_adr_vals
, &dest_adr_vals
);
}
/*!------------------------------------------------------------------------
* \fn CodePORT(Word code)
* \brief handle PORT statement
* ------------------------------------------------------------------------ */
static void CodePORT
(Word code
)
{
UNUSED
(code
);
CodeEquate
(SegIO
, 0, SegLimits
[SegIO
]);
}
/*--------------------------------------------------------------------------*/
/* Instruction Lookup Table */
/*!------------------------------------------------------------------------
* \fn InitFields(void)
* \brief create lookup table
* ------------------------------------------------------------------------ */
static void AddCondition
(const char *p_name
, Word code
)
{
char name
[10];
order_array_rsv_end
(Conditions
, tCondition
);
strmaxcpy
(Conditions
[InstrZ
].
name, p_name
, sizeof(Conditions
[InstrZ
].
name));
Conditions
[InstrZ
].
code = code
;
InstrZ
++;
if (*p_name
)
{
as_snprintf
(name
, sizeof(name
), "B%s", p_name
);
AddInstTable
(InstTable
, name
, 0x70 | code
, Decode_4
);
as_snprintf
(name
, sizeof(name
), "DB%s", p_name
);
AddInstTable
(InstTable
, name
, 0xc6 | (code
& 1) | ((code
<< 7) & 0x0700), Decode_6
);
}
}
static void InitFields
(void)
{
InstTable
= CreateInstTable
(201);
SetDynamicInstTable
(InstTable
);
AddInstTable
(InstTable
, "ABSF" , 0x0a5c, DecodeArithF
);
AddInstTable
(InstTable
, "ADDF" , 0x185c, DecodeArithF
);
AddInstTable
(InstTable
, "CMPF" , 0x005c, DecodeArithF
);
AddInstTable
(InstTable
, "DIVF" , 0x1b5c, DecodeArithF
);
AddInstTable
(InstTable
, "MOVF" , 0x085c, DecodeArithF
);
AddInstTable
(InstTable
, "MULF" , 0x1a5c, DecodeArithF
);
AddInstTable
(InstTable
, "NEGF" , 0x095c, DecodeArithF
);
AddInstTable
(InstTable
, "SUBF" , 0x195c, DecodeArithF
);
AddInstTable
(InstTable
, "SCLF" , 0x105c, DecodeSCLF
);
AddInstTable
(InstTable
, "ADD" , 0x80, DecodeArith
);
AddInstTable
(InstTable
, "ADDC" , 0x90, DecodeArith
);
AddInstTable
(InstTable
, "AND" , 0xa0, DecodeArith
);
AddInstTable
(InstTable
, "CMP" , CODE_FLAG_OP2_IMM
| 0xb8, DecodeArith
);
AddInstTable
(InstTable
, "DIV" , 0xa1, DecodeArith
);
AddInstTable
(InstTable
, "DIVU" , 0xb1, DecodeArith
);
AddInstTable
(InstTable
, "MUL" , 0x81, DecodeArith
);
AddInstTable
(InstTable
, "MULU" , 0x91, DecodeArith
);
AddInstTable
(InstTable
, "NEG" , 0x39, DecodeArith
);
AddInstTable
(InstTable
, "NOT" , 0x38, DecodeArith
);
AddInstTable
(InstTable
, "OR" , 0x88, DecodeArith
);
AddInstTable
(InstTable
, "REM" , 0x50, DecodeArith
);
AddInstTable
(InstTable
, "REMU" , 0x51, DecodeArith
);
AddInstTable
(InstTable
, "SUB" , 0xa8, DecodeArith
);
AddInstTable
(InstTable
, "SUBC" , 0x98, DecodeArith
);
AddInstTable
(InstTable
, "XOR" , 0xb0, DecodeArith
);
AddInstTable
(InstTable
, "DIVX" , 0x00a6, DecodeArithX
);
AddInstTable
(InstTable
, "DIVUX" , 0x00b6, DecodeArithX
);
AddInstTable
(InstTable
, "MULX" , 0x0086, DecodeArithX
);
AddInstTable
(InstTable
, "MULUX" , 0x0096, DecodeArithX
);
AddInstTable
(InstTable
, "ADDDC" , 0x0059, DecodeArith_7c
);
AddInstTable
(InstTable
, "SUBDC" , 0x0159, DecodeArith_7c
);
AddInstTable
(InstTable
, "SUBRDC" , 0x0259, DecodeArith_7c
);
AddInstTable
(InstTable
, "ANDBSU" , 0x105b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "ANDBSD" , 0x115b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "ANDNBSU", 0x125b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "ANDNBSD", 0x135b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "NOTBSU" , 0x0a5b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "NOTBSD" , 0x0b5b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "MOVBSU" , 0x085b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "MOVBSD" , 0x095b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "ORBSU" , 0x145b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "ORBSD" , 0x155b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "ORNBSU" , 0x165b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "ORNBSD" , 0x175b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "XORBSU" , 0x185b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "XORBSD" , 0x195b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "XORNBSU", 0x1a5b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "XORNBSD", 0x1b5b, DecodeBitString_7b
);
AddInstTable
(InstTable
, "CMPC", 0x0058, DecodeString_7a
);
AddInstTable
(InstTable
, "CMPCF", 0x0158, DecodeString_7a
);
AddInstTable
(InstTable
, "CMPCS", 0x0258, DecodeString_7a
);
AddInstTable
(InstTable
, "MOVCU", 0x0858, DecodeString_7a
);
AddInstTable
(InstTable
, "MOVCD", 0x0958, DecodeString_7a
);
AddInstTable
(InstTable
, "MOVCFU", 0x0a58, DecodeString_7a
);
AddInstTable
(InstTable
, "MOVCFD", 0x0b58, DecodeString_7a
);
AddInstTable
(InstTable
, "MOVCS", 0x0c58, DecodeString_7a
);
AddInstTable
(InstTable
, "SCHCU", 0x1858, DecodeString_7b
);
AddInstTable
(InstTable
, "SCHCD", 0x1958, DecodeString_7b
);
AddInstTable
(InstTable
, "SKPCU", 0x1a58, DecodeString_7b
);
AddInstTable
(InstTable
, "SKPCD", 0x1b58, DecodeString_7b
);
AddInstTable
(InstTable
, "CMPBFS", CODE_FLAG_OP2_IMM
| 0x005d, DecodeBitField_7b
);
AddInstTable
(InstTable
, "CMPBFZ", CODE_FLAG_OP2_IMM
| 0x015d, DecodeBitField_7b
);
AddInstTable
(InstTable
, "CMPBFL", CODE_FLAG_OP2_IMM
| 0x025d, DecodeBitField_7b
);
AddInstTable
(InstTable
, "SCH0BSU", 0x005b, DecodeBitField_7b
);
AddInstTable
(InstTable
, "SCH0BSD", 0x015b, DecodeBitField_7b
);
AddInstTable
(InstTable
, "SCH1BSU", 0x025b, DecodeBitField_7b
);
AddInstTable
(InstTable
, "SCH1BSD", 0x035b, DecodeBitField_7b
);
AddInstTable
(InstTable
, "EXTBFS", CODE_FLAG_LIM32
| 0x085d, DecodeBitField_7b
);
AddInstTable
(InstTable
, "EXTBFZ", CODE_FLAG_LIM32
| 0x095d, DecodeBitField_7b
);
AddInstTable
(InstTable
, "EXTBFL", CODE_FLAG_LIM32
| 0x0a5d, DecodeBitField_7b
);
AddInstTable
(InstTable
, "INSBFR", CODE_FLAG_LIM32
| 0x185d, DecodeBitField_7c
);
AddInstTable
(InstTable
, "INSBFL", CODE_FLAG_LIM32
| 0x195d, DecodeBitField_7c
);
AddInstTable
(InstTable
, "BRK" , 0xc8, DecodeFixed
);
AddInstTable
(InstTable
, "BRKV" , 0xc9, DecodeFixed
);
AddInstTable
(InstTable
, "CLRTLBA", CODE_FLAG_SUPMODE
| 0x10, DecodeFixed
);
AddInstTable
(InstTable
, "DISPOSE", 0xcc, DecodeFixed
);
AddInstTable
(InstTable
, "HALT" , 0x00, DecodeFixed
);
AddInstTable
(InstTable
, "NOP" , 0xcd, DecodeFixed
);
AddInstTable
(InstTable
, "RSR" , 0xca, DecodeFixed
);
AddInstTable
(InstTable
, "TRAPFL" , 0xcb, DecodeFixed
);
AddInstTable
(InstTable
, "MOV" , 0x00, DecodeMOV
);
InstrZ
= 0;
AddCondition
("GT", 0xf);
AddCondition
("GE", 0xd);
AddCondition
("LT", 0xc);
AddCondition
("LE", 0xe);
AddCondition
("H" , 0x7);
AddCondition
("NL", 0x3);
AddCondition
("L" , 0x2);
AddCondition
("NH", 0x6);
AddCondition
("E" , 0x4);
AddCondition
("NE", 0x5);
AddCondition
("V" , 0x0);
AddCondition
("NV", 0x1);
AddCondition
("N" , 0x8);
AddCondition
("P" , 0x9);
AddCondition
("C" , 0x2);
AddCondition
("NC", 0x3);
AddCondition
("Z" , 0x4);
AddCondition
("NZ", 0x5);
AddCondition
("" , 0);
AddInstTable
(InstTable
, "BR", 0x7a, Decode_4
);
AddInstTable
(InstTable
, "DBR", 0x05c6, Decode_6
);
AddInstTable
(InstTable
, "TB", 0x05c7, Decode_6
);
AddInstTable
(InstTable
, "BSR", 0x48, Decode_4
);
AddInstTable
(InstTable
, "CLRTLB", CODE_FLAG_SUPMODE
| 0xfe, DecodeCLRTLB
);
AddInstTable
(InstTable
, "GETPSW", 0xf6, DecodeGETPSW
);
AddInstTable
(InstTable
, "UPDPSW", 0x134a, DecodeUPDPSW
);
AddInstTable
(InstTable
, "DEC", 0xd0, DecodeFormat3_bhw
);
AddInstTable
(InstTable
, "INC", 0xd8, DecodeFormat3_bhw
);
AddInstTable
(InstTable
, "TEST", 0xf0 | CODE_FLAG_OP2_IMM
, DecodeFormat3_bhw
);
AddInstTable
(InstTable
, "JMP", 0xd6, DecodeJMP_JSR
);
AddInstTable
(InstTable
, "JSR", 0xe8, DecodeJMP_JSR
);
AddInstTable
(InstTable
, "POP", 0xe6, DecodeFormat3_W
);
AddInstTable
(InstTable
, "PUSH", CODE_FLAG_OP2_IMM
| 0xee, DecodeFormat3_W
);
AddInstTable
(InstTable
, "POPM", CODE_FLAG_OP2_IMM
| 0xe4, DecodeFormat3_W
);
AddInstTable
(InstTable
, "PUSHM", CODE_FLAG_OP2_IMM
| 0xec, DecodeFormat3_W
);
AddInstTable
(InstTable
, "PREPARE", CODE_FLAG_OP2_IMM
| 0xde, DecodeFormat3_W
);
AddInstTable
(InstTable
, "STTASK", CODE_FLAG_OP2_IMM
| CODE_FLAG_SUPMODE
| 0xfc, DecodeFormat3_W
);
AddInstTable
(InstTable
, "RET", CODE_FLAG_OP2_IMM
| 0xe2, DecodeFormat3_H
);
AddInstTable
(InstTable
, "RETIS", CODE_FLAG_OP2_IMM
| CODE_FLAG_SUPMODE
| 0xfa, DecodeFormat3_H
);
AddInstTable
(InstTable
, "RETIU", CODE_FLAG_OP2_IMM
| CODE_FLAG_SUPMODE
| 0xea, DecodeFormat3_H
);
AddInstTable
(InstTable
, "TASI", 0xe0, DecodeFormat3_B
);
AddInstTable
(InstTable
, "TRAP", CODE_FLAG_OP2_IMM
| 0xf8, DecodeFormat3_B
);
AddInstTable
(InstTable
, "CALL", 0x49, DecodeCALL
);
AddInstTable
(InstTable
, "ROT", 0x89, DecodeShift
);
AddInstTable
(InstTable
, "ROTC", 0x99, DecodeShift
);
AddInstTable
(InstTable
, "SHA", 0xb9, DecodeShift
);
AddInstTable
(InstTable
, "SHL", 0xa9, DecodeShift
);
AddInstTable
(InstTable
, "CHKAR", 0x4d, DecodeCHKA
);
AddInstTable
(InstTable
, "CHKAW", 0x4e, DecodeCHKA
);
AddInstTable
(InstTable
, "CHKAE", 0x4f, DecodeCHKA
);
AddInstTable
(InstTable
, "CAXI", 0x4c, DecodeCAXI
);
AddInstTable
(InstTable
, "CHLVL", 0x4b, DecodeCHLVL
);
AddInstTable
(InstTable
, "GETATE", CODE_FLAG_SUPMODE
| 0x05, DecodeGETXTE
);
AddInstTable
(InstTable
, "UPDATE", CODE_FLAG_SUPMODE
| 0x15, DecodeGETXTE
);
AddInstTable
(InstTable
, "GETPTE", CODE_FLAG_SUPMODE
| 0x04, DecodeGETXTE
);
AddInstTable
(InstTable
, "UPDPTE", CODE_FLAG_OP2_IMM
| CODE_FLAG_SUPMODE
| 0x14, DecodeGETXTE
);
AddInstTable
(InstTable
, "GETRA", CODE_FLAG_SUPMODE
| 0x03, DecodeGETXTE
);
AddInstTable
(InstTable
, "CLR1", 0xa7, DecodeBit
);
AddInstTable
(InstTable
, "NOT1", 0xb7, DecodeBit
);
AddInstTable
(InstTable
, "SET1", 0x97, DecodeBit
);
AddInstTable
(InstTable
, "TEST1", 0x87, DecodeBit
);
AddInstTable
(InstTable
, "CVT", 0, DecodeCVT
);
AddInstTable
(InstTable
, "CVTD", 0x1059, DecodeCVTD
);
AddInstTable
(InstTable
, "MOVS", 0x0a, DecodeMOVS_MOVZ
);
AddInstTable
(InstTable
, "MOVT", 0x19, DecodeMOVT
);
AddInstTable
(InstTable
, "MOVZ", 0x0b, DecodeMOVS_MOVZ
);
/* TODO: 0x31 for IN is guessed, same opcode for IN & OUT in manual? */
AddInstTable
(InstTable
, "IN" , CODE_FLAG_SUPMODE
| 0x0031, DecodeIN_OUT
);
AddInstTable
(InstTable
, "OUT", CODE_FLAG_SUPMODE
| 0x0121, DecodeIN_OUT
);
AddInstTable
(InstTable
, "RVBIT", 0x08, DecodeArith_B
);
AddInstTable
(InstTable
, "RVBYTE", 0x2c, DecodeArith_W
);
AddInstTable
(InstTable
, "LDPR", CODE_FLAG_SUPMODE
| CODE_FLAG_OP2_IMM
| 0x12, DecodeArith_W
);
AddInstTable
(InstTable
, "STPR", CODE_FLAG_SUPMODE
| 0x02, DecodeArith_W
);
AddInstTable
(InstTable
, "LDTASK", CODE_FLAG_SUPMODE
| 0x01, DecodeLDTASK
);
AddInstTable
(InstTable
, "MOVEA", 0x40, DecodeMOVEA
);
AddInstTable
(InstTable
, "XCH", 0x41, DecodeXCH
);
AddInstTable
(InstTable
, "SETF", 0x47, DecodeSETF
);
AddInstTable
(InstTable
, "REG", 0, CodeREG
);
AddInstTable
(InstTable
, "PORT", 0, CodePORT
);
}
/*!------------------------------------------------------------------------
* \fn DeinitFields(void)
* \brief destroy/cleanup lookup table
* ------------------------------------------------------------------------ */
static void DeinitFields
(void)
{
order_array_free
(Conditions
);
DestroyInstTable
(InstTable
);
}
/*--------------------------------------------------------------------------*/
/* Interface Functions */
/*!------------------------------------------------------------------------
* \fn InternSymbol_V60(char *pArg, TempResult *pResult)
* \brief handle built-in (register) symbols for V60
* \param pArg source argument
* \param pResult result buffer
* ------------------------------------------------------------------------ */
static void InternSymbol_V60
(char *pArg
, TempResult
*pResult
)
{
Byte RegNum
;
if (DecodeRegCore
(pArg
, &RegNum
))
{
pResult
->Typ
= TempReg
;
pResult
->DataSize
= eSymbolSize32Bit
;
pResult
->Contents.
RegDescr.
Reg = RegNum
;
pResult
->Contents.
RegDescr.
Dissect = DissectReg_V60
;
pResult
->Contents.
RegDescr.
compare = NULL
;
}
}
/*!------------------------------------------------------------------------
* \fn DecodeAttrPart_V60(void)
* \brief handle/decode attribute
* \return True if success
* ------------------------------------------------------------------------ */
static Boolean DecodeAttrPart_V60
(void)
{
int l
= strlen(AttrPart.
str.
p_str), z
;
if (l
> 2)
{
badattr
:
WrStrErrorPos
(ErrNum_UndefAttr
, &AttrPart
);
return False
;
}
for (z
= 0; z
< l
; z
++)
switch (as_toupper
(AttrPart.
str.
p_str[z
]))
{
case 'B': AttrPartOpSize
[z
] = eSymbolSize8Bit
; break;
case 'H': AttrPartOpSize
[z
] = eSymbolSize16Bit
; break;
case 'W': AttrPartOpSize
[z
] = eSymbolSize32Bit
; break;
case 'D': AttrPartOpSize
[z
] = eSymbolSize64Bit
; break;
case 'P': AttrPartOpSize
[z
] = eSymbolSize24Bit
; break;
case 'S': AttrPartOpSize
[z
] = eSymbolSizeFloat32Bit
; break;
case 'L': AttrPartOpSize
[z
] = eSymbolSizeFloat64Bit
; break;
case 'Z': AttrPartOpSize
[z
] = eSymbolSizeFloatDec96Bit
; break; /* just for cvtd.pz/zp */
case '\0': break;
default:
goto badattr
;
}
return True
;
}
/*!------------------------------------------------------------------------
* \fn MakeCode_V60(void)
* \brief encode machine instruction
* ------------------------------------------------------------------------ */
static void MakeCode_V60
(void)
{
CodeLen
= 0; DontPrint
= False
;
OpSize
= eSymbolSizeUnknown
;
/* to be ignored */
if (Memo
("")) return;
/* Pseudo Instructions */
if (DecodeMoto16Pseudo
(AttrPartOpSize
[0], False
))
return;
if (!LookupInstTable
(InstTable
, OpPart.
str.
p_str))
WrStrErrorPos
(ErrNum_UnknownInstruction
, &OpPart
);
}
/*!------------------------------------------------------------------------
* \fn IsDef_V60(void)
* \brief check whether insn makes own use of label
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean IsDef_V60
(void)
{
return Memo
("REG")
|| Memo
("PORT");
}
/*!------------------------------------------------------------------------
* \fn SwitchFrom_V60(void)
* \brief deinitialize as target
* ------------------------------------------------------------------------ */
static void SwitchFrom_V60
(void)
{
DeinitFields
();
}
/*!------------------------------------------------------------------------
* \fn SwitchTo_V60(void *pUser)
* \brief prepare to assemble code for this target
* \param pUser CPU properties
* ------------------------------------------------------------------------ */
static void SwitchTo_V60
(void)
{
const TFamilyDescr
*pDescr
= FindFamilyByName
("V60");
TurnWords
= True
;
SetIntConstMode
(eIntConstModeIntel
);
PCSymbol
= "$"; HeaderID
= pDescr
->Id
;
NOPCode
= 0x00;
DivideChars
= ",";
HasAttrs
= True
;
AttrChars
= ".";
ValidSegs
= (1 << SegCode
) | (1 << SegIO
);
Grans
[SegCode
] = Grans
[SegIO
] = 1;
ListGrans
[SegCode
] = ListGrans
[SegIO
] = 1;
SegInits
[SegCode
] = SegInits
[SegIO
] = 0;
SegLimits
[SegCode
] = 0xfffffffful
;
SegLimits
[SegIO
] = 0xfffffful
;
DecodeAttrPart
= DecodeAttrPart_V60
;
MakeCode
= MakeCode_V60
;
IsDef
= IsDef_V60
;
SwitchFrom
= SwitchFrom_V60
;
InternSymbol
= InternSymbol_V60
;
DissectReg
= DissectReg_V60
;
AddMoto16PseudoONOFF
(False
);
onoff_supmode_add
();
InitFields
();
}
/*!------------------------------------------------------------------------
* \fn codev60_init(void)
* \brief register target to AS
* ------------------------------------------------------------------------ */
void codev60_init
(void)
{
(void)AddCPU
("70616", SwitchTo_V60
);
}