/* tipseudo.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS */
/* */
/* Commonly Used TI-Style Pseudo Instructions-Befehle */
/* */
/*****************************************************************************/
/*****************************************************************************
* Includes
*****************************************************************************/
#include "stdinc.h"
#include <ctype.h>
#include <string.h>
#include <math.h>
#include "strutil.h"
#include "be_le.h"
#include "ieeefloat.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmitree.h"
#include "onoff_common.h"
#include "errmsg.h"
#include "chartrans.h"
#include "codepseudo.h"
#include "fourpseudo.h"
#include "tipseudo.h"
#define LEAVE goto func_exit
/*****************************************************************************
* Local Functions
*****************************************************************************/
static void define_untyped_label(void)
{
if (LabPart.str.p_str[0])
{
PushLocHandle(-1);
EnterIntSymbol(&LabPart, EProgCounter(), SegNone, False);
PopLocHandle();
}
}
static void pseudo_qxx(Integer num)
{
tStrComp *pArg;
Boolean ok = True;
double res;
if (!ChkArgCnt(1, ArgCntMax))
return;
forallargs (pArg, True)
{
if (!*pArg->str.p_str)
{
ok = False;
break;
}
res
= ldexp(EvalStrFloatExpression
(pArg
, Float64
, &ok
), num
);
if (!ok)
break;
if ((res > 32767.49) || (res < -32768.49))
{
ok = False;
WrError(ErrNum_OverRange);
break;
}
WAsmCode[CodeLen++] = res;
}
if (!ok)
CodeLen = 0;
}
static void pseudo_lqxx(Integer num)
{
tStrComp *pArg;
Boolean ok = True;
double res;
LongInt resli;
if (!ChkArgCnt(1, ArgCntMax))
return;
forallargs (pArg, True)
{
if (!*pArg->str.p_str)
{
ok = False;
break;
}
res
= ldexp(EvalStrFloatExpression
(pArg
, Float64
, &ok
), num
);
if (!ok)
break;
if ((res > 2147483647.49) || (res < -2147483647.49))
{
ok = False;
WrError(ErrNum_OverRange);
break;
}
resli = res;
WAsmCode[CodeLen++] = resli & 0xffff;
WAsmCode[CodeLen++] = resli >> 16;
}
if (!ok)
CodeLen = 0;
}
typedef void (*tcallback)(
#ifdef __PROTOS__
Boolean *, int *, LongInt, tSymbolFlags
#endif
);
static void pseudo_store(tcallback callback, Word MaxMultCharLen)
{
Boolean ok = True;
int adr = 0;
tStrComp *pArg;
TempResult t;
as_tempres_ini(&t);
if (!ChkArgCnt(1, ArgCntMax))
LEAVE;
define_untyped_label();
forallargs (pArg, ok)
{
if (!*pArg->str.p_str)
{
ok = False;
break;
}
EvalStrExpression(pArg, &t);
switch (t.Typ)
{
case TempFloat:
WrStrErrorPos(ErrNum_StringOrIntButFloat, pArg);
LEAVE;
case TempString:
{
unsigned char *cp, *cend;
if (MultiCharToInt(&t, MaxMultCharLen))
goto ToInt;
if (as_chartrans_xlate_nonz_dynstr(CurrTransTable->p_table, &t.Contents.str, pArg))
ok = False;
else
{
cp = (unsigned char *)t.Contents.str.p_str;
cend = cp + t.Contents.str.len;
while (cp < cend)
callback(&ok, &adr, *cp++ & 0xff, t.Flags);
}
break;
}
case TempInt:
ToInt:
callback(&ok, &adr, t.Contents.Int, t.Flags);
break;
default:
ok = False;
break;
}
if (!ok)
break;
}
if (!ok)
CodeLen = 0;
func_exit:
as_tempres_free(&t);
}
static void wr_code_byte(Boolean *ok, int *adr, LongInt val, tSymbolFlags Flags)
{
if (!mFirstPassUnknownOrQuestionable(Flags) && !RangeCheck(val, Int8))
{
WrError(ErrNum_OverRange);
*ok = False;
return;
}
WAsmCode[(*adr)++] = val & 0xff;
CodeLen = *adr;
}
static void wr_code_word(Boolean *ok, int *adr, LongInt val, tSymbolFlags Flags)
{
if (!mFirstPassUnknownOrQuestionable(Flags) && !RangeCheck(val, Int16))
{
WrError(ErrNum_OverRange);
*ok = False;
return;
}
WAsmCode[(*adr)++] = val;
CodeLen = *adr;
}
static void wr_code_long(Boolean *ok, int *adr, LongInt val, tSymbolFlags Flags)
{
UNUSED(ok);
UNUSED(Flags);
WAsmCode[(*adr)++] = val & 0xffff;
WAsmCode[(*adr)++] = val >> 16;
CodeLen = *adr;
}
static void wr_code_byte_hilo(Boolean *ok, int *adr, LongInt val, tSymbolFlags Flags)
{
if (!mFirstPassUnknownOrQuestionable(Flags) && !RangeCheck(val, Int8))
{
WrError(ErrNum_OverRange);
*ok = False;
return;
}
if ((*adr) & 1)
WAsmCode[((*adr)++) / 2] |= val & 0xff;
else
WAsmCode[((*adr)++) / 2] = val << 8;
CodeLen = ((*adr) + 1) / 2;
}
static void wr_code_byte_lohi(Boolean *ok, int *adr, LongInt val, tSymbolFlags Flags)
{
if (!mFirstPassUnknownOrQuestionable(Flags) && !RangeCheck(val, Int8))
{
WrError(ErrNum_OverRange);
*ok = False;
return;
}
if ((*adr) & 1)
WAsmCode[((*adr)++) / 2] |= val << 8;
else
WAsmCode[((*adr)++) / 2] = val & 0xff;
CodeLen = ((*adr) + 1) / 2;
}
/*!------------------------------------------------------------------------
* \fn DecodeFLOAT(Word Code)
* \brief decode FLOAT instruction
* ------------------------------------------------------------------------ */
static void DecodeFLOAT(Word Code)
{
Boolean ok;
tStrComp *pArg;
Byte Dest[4];
UNUSED(Code);
if (!ChkArgCnt(1, ArgCntMax))
return;
define_untyped_label();
ok = True;
if (SetMaxCodeLen(ArgCnt * 4))
return;
forallargs (pArg, ok)
{
if (!*pArg->str.p_str)
{
ok = False;
break;
}
Double_2_ieee4(EvalStrFloatExpression(pArg, Float32, &ok), Dest, False);
WAsmCode[CodeLen++] = (Word)Dest[0] | ((Word)Dest[1]) << 8;
WAsmCode[CodeLen++] = (Word)Dest[2] | ((Word)Dest[3]) << 8;
}
if (!ok)
CodeLen = 0;
}
/*!------------------------------------------------------------------------
* \fn DecodeDOUBLE(Word Code)
* \brief decode DOUBLE instruction
* ------------------------------------------------------------------------ */
static void DecodeDOUBLE(Word Code)
{
Boolean ok;
tStrComp *pArg;
Byte Dest[8];
UNUSED(Code);
if (!ChkArgCnt(1, ArgCntMax))
return;
define_untyped_label();
ok = True;
if (SetMaxCodeLen(ArgCnt * 8))
return;
forallargs (pArg, ok)
{
if (!*pArg->str.p_str)
{
ok = False;
break;
}
Double_2_ieee8(EvalStrFloatExpression(pArg, Float64, &ok), Dest, False);
WAsmCode[CodeLen++] = (Word)Dest[0] | ((Word)Dest[1]) << 8;
WAsmCode[CodeLen++] = (Word)Dest[2] | ((Word)Dest[3]) << 8;
WAsmCode[CodeLen++] = (Word)Dest[4] | ((Word)Dest[5]) << 8;
WAsmCode[CodeLen++] = (Word)Dest[6] | ((Word)Dest[7]) << 8;
}
if (!ok)
CodeLen = 0;
}
/*!------------------------------------------------------------------------
* \fn DecodeEFLOAT(Word Code)
* \brief decode EFLOAT instruction
* ------------------------------------------------------------------------ */
static void DecodeEFLOAT(Word Code)
{
Boolean ok;
tStrComp *pArg;
double dbl, mant;
UNUSED(Code);
if (!ChkArgCnt(1, ArgCntMax))
return;
define_untyped_label();
ok = True;
if (SetMaxCodeLen(ArgCnt * 4))
return;
forallargs (pArg, ok)
{
if (!*pArg->str.p_str)
{
ok = False;
break;
}
dbl = EvalStrFloatExpression(pArg, Float64, &ok);
WAsmCode
[CodeLen
++] = ldexp(mant
, 15);
WAsmCode
[CodeLen
++] = exp - 1;
}
if (!ok)
CodeLen = 0;
}
/*!------------------------------------------------------------------------
* \fn DecodeBFLOAT(Word Code)
* \brief decode BFLOAT instruction
* ------------------------------------------------------------------------ */
static void DecodeBFLOAT(Word Code)
{
Boolean ok;
tStrComp *pArg;
double dbl, mant;
long lmant;
UNUSED(Code);
if (!ChkArgCnt(1, ArgCntMax))
return;
define_untyped_label();
ok = True;
if (SetMaxCodeLen(ArgCnt * 6))
return;
forallargs (pArg, ok)
{
if (!*pArg->str.p_str)
{
ok = False;
break;
}
dbl = EvalStrFloatExpression(pArg, Float64, &ok);
WAsmCode[CodeLen++] = (lmant & 0xffff);
WAsmCode[CodeLen++] = (lmant >> 16);
WAsmCode
[CodeLen
++] = exp - 1;
}
if (!ok)
CodeLen = 0;
}
/*!------------------------------------------------------------------------
* \fn DecodeTFLOAT(Word Code)
* \brief decode TFLOAT instruction
* ------------------------------------------------------------------------ */
static void DecodeTFLOAT(Word Code)
{
Boolean ok;
tStrComp *pArg;
double dbl, mant;
UNUSED(Code);
if (!ChkArgCnt(1, ArgCntMax))
return;
define_untyped_label();
ok = True;
if (SetMaxCodeLen(ArgCnt * 12))
return;
forallargs (pArg, ok)
{
if (!*pArg->str.p_str)
{
ok = False;
break;
}
dbl = EvalStrFloatExpression(pArg, Float64, &ok);
WAsmCode[CodeLen + 3] = dbl;
WAsmCode[CodeLen + 2] = dbl;
WAsmCode[CodeLen + 1] = dbl;
WAsmCode[CodeLen] = dbl;
CodeLen += 4;
WAsmCode
[CodeLen
++] = ((exp - 1) & 0xffff);
WAsmCode
[CodeLen
++] = ((exp - 1) >> 16);
}
if (!ok)
CodeLen = 0;
}
/*!------------------------------------------------------------------------
* \fn DecodeSTRING(Word Code)
* \brief decode STRING instruction
* ------------------------------------------------------------------------ */
static void DecodeSTRING(Word Code)
{
UNUSED(Code);
pseudo_store(wr_code_byte_hilo, 1);
}
/*!------------------------------------------------------------------------
* \fn DecodeRSTRING(Word Code)
* \brief decode RSTRING instruction
* ------------------------------------------------------------------------ */
static void DecodeRSTRING(Word Code)
{
UNUSED(Code);
pseudo_store(wr_code_byte_lohi, 1);
}
/*!------------------------------------------------------------------------
* \fn DecodeBYTE(Word Code)
* \brief decode BYTE instruction
* ------------------------------------------------------------------------ */
static void DecodeBYTE(Word Code)
{
UNUSED(Code);
pseudo_store(wr_code_byte, 1);
}
/*!------------------------------------------------------------------------
* \fn DecodeWORD(Word Code)
* \brief decode WORD instruction
* ------------------------------------------------------------------------ */
static void DecodeWORD(Word Code)
{
UNUSED(Code);
pseudo_store(wr_code_word, 2);
}
/*!------------------------------------------------------------------------
* \fn DecodeLONG(Word Code)
* \brief decode LONG instruction
* ------------------------------------------------------------------------ */
static void DecodeLONG(Word Code)
{
UNUSED(Code);
pseudo_store(wr_code_long, 4);
}
/*!------------------------------------------------------------------------
* \fn DecodeBSS(Word Code)
* \brief decode BSS instruction
* ------------------------------------------------------------------------ */
static void DecodeBSS_TI(Word Code)
{
UNUSED(Code);
define_untyped_label();
DecodeRES(Code);
}
/*!------------------------------------------------------------------------
* \fn DecodeDATA_TI(Word Code)
* \brief decode TI-specific DATA instruction
* ------------------------------------------------------------------------ */
static void DecodeDATA_TI(Word Code)
{
UNUSED(Code);
DecodeDATA(Int16, Int16);
}
/*!------------------------------------------------------------------------
* \fn Boolean Is99(const char *pStr, Integer *pNum)
* \brief does string end with number 00...99?
* \param pStr string to check
* \param pNum appended number if yes
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean Is99(const char *pStr, Integer *pNum)
{
if ((l >= 3)
&& as_isdigit(pStr[l - 2])
&& as_isdigit(pStr[l - 1]))
{
*pNum = 10 * (pStr[l - 2] - '0') + (pStr[l - 1] - '0');
return True;
}
return False;
}
/*****************************************************************************
* Global Functions
*****************************************************************************/
Boolean DecodeTIPseudo(void)
{
static PInstTable InstTable;
Integer Num;
/* Qxx */
if (!as_strncasecmp(OpPart.str.p_str, "Q", 1)
&& Is99(OpPart.str.p_str, &Num))
{
pseudo_qxx(Num);
return True;
}
/* LQxx */
if (!as_strncasecmp(OpPart.str.p_str, "LQ", 2)
&& Is99(OpPart.str.p_str, &Num))
{
pseudo_lqxx(Num);
return True;
}
if (!InstTable)
{
InstTable = CreateInstTable(23);
AddInstTable(InstTable, "RES" , 0, DecodeRES);
AddInstTable(InstTable, "BSS" , 0, DecodeBSS_TI);
AddInstTable(InstTable, "DATA" , 0, DecodeDATA_TI);
AddInstTable(InstTable, "STRING" , 0, DecodeSTRING);
AddInstTable(InstTable, "RSTRING", 0, DecodeRSTRING);
AddInstTable(InstTable, "BYTE" , 0, DecodeBYTE);
AddInstTable(InstTable, "WORD" , 0, DecodeWORD);
AddInstTable(InstTable, "LONG" , 0, DecodeLONG);
AddInstTable(InstTable, "FLOAT" , 0, DecodeFLOAT);
AddInstTable(InstTable, "DOUBLE" , 0, DecodeDOUBLE);
AddInstTable(InstTable, "EFLOAT" , 0, DecodeEFLOAT);
AddInstTable(InstTable, "BFLOAT" , 0, DecodeBFLOAT);
AddInstTable(InstTable, "TFLOAT" , 0, DecodeTFLOAT);
}
return LookupInstTable(InstTable, OpPart.str.p_str);
}
Boolean IsTIDef(void)
{
static const char *defs[] =
{
"BSS", "STRING", "RSTRING",
"BYTE", "WORD", "LONG", "FLOAT",
"DOUBLE", "EFLOAT", "BFLOAT",
"TFLOAT", NULL
};
const char **cp = defs;
while (*cp)
{
if (Memo(*cp))
return True;
cp++;
}
return False;
}
/*-------------------------------------------------------------------------*/
/* Convert IEEE to C3x/C4x floating point format */
static void SplitExt(Double Inp, LongInt *Expo, LongWord *Mant)
{
Byte Field[8];
Boolean Sign;
int z;
Double_2_ieee8(Inp, Field, False);
Sign = (Field[7] > 0x7f);
*Expo = (((LongWord) Field[7] & 0x7f) << 4) + (Field[6] >> 4);
*Mant = Field[6] & 0x0f;
if (*Expo != 0)
*Mant |= 0x10;
for (z = 5; z > 2; z--)
*Mant = ((*Mant) << 8) | Field[z];
*Mant = ((*Mant) << 3) + (Field[2] >> 5);
*Expo -= 0x3ff;
if (Sign)
*Mant = (0xffffffff - *Mant) + 1;
*Mant = (*Mant) ^ 0x80000000;
}
Boolean ExtToTIC34xShort(Double Inp, Word *Erg)
{
LongInt Expo;
LongWord Mant;
if (Inp == 0)
*Erg = 0x8000;
else
{
SplitExt(Inp, &Expo, &Mant);
if (!ChkRange(Expo, -7, 7))
return False;
*Erg = ((Expo << 12) & 0xf000) | ((Mant >> 20) & 0xfff);
}
return True;
}
Boolean ExtToTIC34xSingle(Double Inp, LongWord *Erg)
{
LongInt Expo;
LongWord Mant;
if (Inp == 0)
*Erg = 0x80000000;
else
{
SplitExt(Inp, &Expo, &Mant);
if (!ChkRange(Expo, -127, 127))
return False;
*Erg = ((Expo << 24) & 0xff000000) + (Mant >> 8);
}
return True;
}
Boolean ExtToTIC34xExt(Double Inp, LongWord *ErgL, LongWord *ErgH)
{
LongInt Exp;
if (Inp == 0)
{
*ErgH = 0x80;
*ErgL = 0x00000000;
}
else
{
SplitExt(Inp, &Exp, ErgL);
if (!ChkRange(Exp, -127, 127))
return False;
*ErgH = Exp & 0xff;
}
return True;
}
/*-------------------------------------------------------------------------*/
/* Pseudo Instructions common to C3x/C4x */
static void DecodeSINGLE(Word Code)
{
Double f;
tStrComp *pArg;
Boolean OK;
UNUSED(Code);
if (ChkArgCnt(1, ArgCntMax))
{
OK = True;
forallargs (pArg, True)
if (OK)
{
f = EvalStrFloatExpression(pArg, Float64, &OK);
if (OK)
OK = OK && ExtToTIC34xSingle(f, DAsmCode + (CodeLen++));
}
if (!OK)
CodeLen = 0;
}
}
static void DecodeEXTENDED(Word Code)
{
Double f;
tStrComp *pArg;
Boolean OK;
UNUSED(Code);
if (ChkArgCnt(1, ArgCntMax))
{
OK = True;
forallargs (pArg, True)
if (OK)
{
f = EvalStrFloatExpression(pArg, Float64, &OK);
if (OK)
OK = OK && ExtToTIC34xExt(f, DAsmCode + CodeLen + 1, DAsmCode + CodeLen);
CodeLen += 2;
}
if (!OK)
CodeLen = 0;
}
}
static void DecodeWORD_TI34x(Word Code)
{
Boolean OK;
tStrComp *pArg;
UNUSED(Code);
if (ChkArgCnt(1, ArgCntMax))
{
OK = True;
forallargs (pArg, True)
if (OK) DAsmCode[CodeLen++] = EvalStrIntExpression(pArg, Int32, &OK);
if (!OK)
CodeLen = 0;
}
}
static void DecodeDATA_TI34x(Word Code)
{
Boolean OK;
TempResult t;
tStrComp *pArg;
UNUSED(Code);
as_tempres_ini(&t);
if (ChkArgCnt(1, ArgCntMax))
{
OK = True;
forallargs (pArg, OK)
if (OK)
{
EvalStrExpression(pArg, &t);
switch (t.Typ)
{
case TempInt:
ToInt:
#ifdef HAS64
if (!RangeCheck(t.Contents.Int, Int32))
{
OK = False;
WrError(ErrNum_OverRange);
}
else
#endif
DAsmCode[CodeLen++] = t.Contents.Int;
break;
case TempFloat:
if (!ExtToTIC34xSingle(t.Contents.Float, DAsmCode + (CodeLen++)))
OK = False;
break;
case TempString:
{
if (MultiCharToInt(&t, 4))
goto ToInt;
if (as_chartrans_xlate_nonz_dynstr(CurrTransTable->p_table, &t.Contents.str, pArg))
OK = False;
else
string_2_dasm_code(&t.Contents.str, Packing ? 4 : 1, True);
break;
}
default:
OK = False;
}
}
if (!OK)
CodeLen = 0;
}
as_tempres_free(&t);
}
static void DecodeBSS_TI34x(Word Code)
{
Boolean OK;
tSymbolFlags Flags;
LongInt Size;
UNUSED(Code);
if (ChkArgCnt(1, 1))
{
Size = EvalStrIntExpressionWithFlags(&ArgStr[1], UInt24, &OK, &Flags);
if (mFirstPassUnknown(Flags)) WrError(ErrNum_FirstPassCalc);
if (OK && !mFirstPassUnknown(Flags))
{
DontPrint = True;
if (!Size)
WrError(ErrNum_NullResMem);
CodeLen = Size;
BookKeeping();
}
}
}
void AddTI34xPseudo(TInstTable *pInstTable)
{
AddInstTable(pInstTable, "SINGLE", 0, DecodeSINGLE);
AddInstTable(pInstTable, "EXTENDED", 0, DecodeEXTENDED);
AddInstTable(pInstTable, "WORD", 0, DecodeWORD_TI34x);
AddInstTable(pInstTable, "DATA", 0, DecodeDATA_TI34x);
AddInstTable(pInstTable, "BSS", 0, DecodeBSS_TI34x);
}