/* code78k2.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Codegenerator 78K2-Familie */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <string.h>
#include <ctype.h>
#include "bpemu.h"
#include "strutil.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmitree.h"
#include "codepseudo.h"
#include "intpseudo.h"
#include "codevars.h"
#include "headids.h"
#include "errmsg.h"
#include "code78k2.h"
/*-------------------------------------------------------------------------*/
enum
{
ModNone = -1,
ModImm = 0,
ModReg8 = 1,
ModReg16 = 2,
ModMem = 3,
ModAbs = 4,
ModShort = 5,
ModSFR = 6,
ModPSW = 7,
ModSP = 8,
ModSTBC = 9
};
#define MModImm (1 << ModImm)
#define MModReg8 (1 << ModReg8)
#define MModReg16 (1 << ModReg16)
#define MModMem (1 << ModMem)
#define MModAbs (1 << ModAbs)
#define MModShort (1 << ModShort)
#define MModSFR (1 << ModSFR)
#define MModPSW (1 << ModPSW)
#define MModSP (1 << ModSP)
#define MModSTBC (1 << ModSTBC)
#define AccReg8 1
#define AccReg16 0
#define SFR_SP 0xfc
#define SFR_PSW 0xfe
/*-------------------------------------------------------------------------*/
static CPUVar CPU78214;
typedef struct
{
ShortInt Mode, Val;
Byte Vals[3];
tSymbolFlags ValSymFlags;
Boolean AltBank;
int Cnt;
} tAdrResult;
static ShortInt OpSize;
static Byte *pCode;
static LongInt Reg_P6, Reg_PM6;
/*-------------------------------------------------------------------------*/
/* address decoders */
static Boolean SetOpSize(ShortInt NewSize)
{
if (OpSize < 0)
{
OpSize = NewSize;
return True;
}
else if (OpSize != NewSize)
{
WrError(ErrNum_ConfOpSizes);
return False;
}
else
return True;
}
static ShortInt DecodeReg8(char *pAsc)
{
ShortInt Result = -1;
if (l == 1)
{
static const char Reg8Names[9] = "XACBEDLH";
const char *pPos
= strchr(Reg8Names
, as_toupper
(*pAsc
));
if (pPos)
Result = pPos - Reg8Names;
}
else if ((l
== 2) && (toupper(pAsc
[0]) == 'R'))
{
if ((pAsc[1] >= '0') && (pAsc[1] <= '7'))
Result = pAsc[1] - '0';
}
return Result;
}
static ShortInt DecodeReg16(char *pAsc)
{
ShortInt Result = -1;
if (l == 2)
{
static const char Reg16Names[4][3] = {"AX", "BC", "DE", "HL"};
int z;
for (z = 0; z < 4; z++)
if (!as_strcasecmp(Reg16Names[z], pAsc))
{
Result = z;
break;
}
}
else if ((l
== 3) && (toupper(pAsc
[0]) == 'R') && (toupper(pAsc
[1]) == 'P'))
{
if ((pAsc[2] >= '0') && (pAsc[2] <= '3'))
Result = pAsc[2] - '0';
}
return Result;
}
static ShortInt DecodeAdr(const tStrComp *pArg, Word Mask, tAdrResult *pResult)
{
Word WordOp;
LongWord LongOp;
Boolean OK;
tStrComp Arg;
unsigned ForceLong;
int ArgLen;
pResult->Mode = ModNone;
pResult->AltBank = False;
pResult->Cnt = 0;
/* immediate ? */
if (*pArg->str.p_str == '#')
{
switch (OpSize)
{
case 0:
pResult->Vals[0] = EvalStrIntExpressionOffs(pArg, 1, Int8, &OK);
if (OK)
{
pResult->Cnt = 1;
pResult->Mode = ModImm;
}
break;
case 1:
WordOp = EvalStrIntExpressionOffs(pArg, 1, Int16, &OK);
if (OK)
{
pResult->Vals[0] = Lo(WordOp);
pResult->Vals[1] = Hi(WordOp);
pResult->Cnt = 2;
pResult->Mode = ModImm;
}
break;
default:
WrError(ErrNum_UndefOpSizes);
}
goto AdrFound;
}
/* 8 bit registers? */
if ((pResult->Val = DecodeReg8(pArg->str.p_str)) >= 0)
{
pResult->Mode = ModReg8;
SetOpSize(0);
goto AdrFound;
}
if (!as_strcasecmp(pArg->str.p_str, "PSW"))
{
pResult->Mode = ModPSW;
SetOpSize(0);
goto AdrFound;
}
if (!as_strcasecmp(pArg->str.p_str, "STBC"))
{
pResult->Mode = ModSTBC;
SetOpSize(0);
goto AdrFound;
}
/* 16 bit registers? */
if ((pResult->Val = DecodeReg16(pArg->str.p_str)) >= 0)
{
pResult->Mode = ModReg16;
SetOpSize(1);
goto AdrFound;
}
if (!as_strcasecmp(pArg->str.p_str, "SP"))
{
pResult->Mode = ModSP;
SetOpSize(1);
goto AdrFound;
}
/* OK, everything that follows is memory: alternate bank ? */
StrCompRefRight(&Arg, pArg, 0);
if (*Arg.str.p_str == '&')
{
pResult->AltBank = True;
StrCompIncRefLeft(&Arg, 1);
}
/* memory-indirect addressing? */
ArgLen
= strlen(Arg.
str.
p_str);
if ((ArgLen >= 2) && (Arg.str.p_str[ArgLen - 1] == ']'))
{
tStrComp Base, Remainder;
char *pStart;
/* remove ']' */
StrCompShorten(&Arg, 1);
pStart = RQuotPos(Arg.str.p_str, '[');
if (!pStart)
{
WrError(ErrNum_BrackErr);
goto AdrFound;
}
/* purely indirect? */
if (pStart == Arg.str.p_str)
{
static const char Modes[][5] = { "DE+", "HL+", "DE-", "HL-", "DE", "HL",
"RP2+", "RP3+", "RP2-", "RP3-", "RP2", "RP3" };
unsigned z;
char *pSep, Save;
/* skip '[' */
StrCompIncRefLeft(&Arg, 1);
/* simple expression without displacement? */
for (z = 0; z < sizeof(Modes) / sizeof(*Modes); z++)
if (!as_strcasecmp(Arg.str.p_str, Modes[z]))
{
pResult->Mode = ModMem; pResult->Val = 0x16;
pResult->Vals[0] = z % (sizeof(Modes) / sizeof(*Modes) / 2);
pResult->Cnt = 1;
goto AdrFound;
}
/* no -> extract base register. Its name ends with the first non-letter,
which either means +/- or a blank */
for (pSep = Arg.str.p_str; *pSep; pSep++)
if (!as_isalpha(*pSep))
break;
/* decode base register. SP is not otherwise handled. */
Save = StrCompSplitRef(&Base, &Remainder, &Arg, pSep);
if (!as_strcasecmp(Base.str.p_str, "SP"))
pResult->Vals[0] = 1;
else
{
int tmp;
tmp = DecodeReg16(Base.str.p_str);
if (tmp == 2) /* DE */
pResult->Vals[0] = 0;
else if (tmp == 3) /* HL */
pResult->Vals[0] = 2;
else
{
WrStrErrorPos(ErrNum_InvReg, &Base);
goto AdrFound;
}
}
/* now that we have the base, prepare displacement. */
*pSep = Save;
if (pSep > Arg.str.p_str)
pSep--;
*pSep = '0';
pResult->Vals[1] = EvalStrIntExpressionOffs(&Arg, pSep - Arg.str.p_str, Int8, &OK);
if (OK)
{
pResult->Mode = ModMem; pResult->Val = 0x06;
pResult->Cnt = 2;
goto AdrFound;
}
}
/* no -> with outer displacement */
else
{
tStrComp Disp, Reg;
int tmp;
/* split displacement + register */
StrCompSplitRef(&Disp, &Reg, &Arg, pStart);
/* handle base register */
tmp = DecodeReg8(Reg.str.p_str);
switch (tmp)
{
case 1: /* A/B */
case 3:
pResult->Vals[0] = tmp;
break;
case -1:
tmp = DecodeReg16(Reg.str.p_str);
if (tmp >= 2) /* DE/HL */
{
pResult->Vals[0] = (tmp - 2) << 1;
break;
}
/* else fall-through */
default:
WrStrErrorPos(ErrNum_InvReg, &Reg);
goto AdrFound;
}
/* compute displacement */
WordOp = EvalStrIntExpression(&Disp, Int16, &OK);
if (OK)
{
pResult->Mode = ModMem; pResult->Val = 0x0a;
pResult->Vals[1] = Lo(WordOp); pResult->Vals[2] = Hi(WordOp);
pResult->Cnt = 3;
goto AdrFound;
}
}
}
/* OK, nothing but absolute left...exclamation mark enforces 16-bit addressing */
ForceLong = !!(*Arg.str.p_str == '!');
LongOp = EvalStrIntExpressionOffsWithFlags(&Arg, ForceLong, UInt20, &OK, &pResult->ValSymFlags);
if (OK)
{
if (!mFirstPassUnknown(pResult->ValSymFlags))
{
LongWord CompBank = pResult->AltBank ? Reg_P6 : Reg_PM6;
if (CompBank != (LongOp >> 16)) WrError(ErrNum_InAccPage);
}
WordOp = LongOp & 0xffff;
if ((Mask & MModShort) && (!ForceLong) && ((WordOp >= 0xfe20) && (WordOp <= 0xff1f)))
{
pResult->Mode = ModShort; pResult->Cnt = 1;
pResult->Vals[0] = Lo(WordOp);
}
else if ((Mask & MModSFR) && (!ForceLong) && (Hi(WordOp) == 0xff))
{
pResult->Mode = ModSFR; pResult->Cnt = 1;
pResult->Vals[0] = Lo(WordOp);
}
else
{
pResult->Mode = ModAbs; pResult->Cnt = 2;
pResult->Vals[0] = Lo(WordOp); pResult->Vals[1] = Hi(WordOp);
}
}
AdrFound:
if ((pResult->Mode != ModNone) && (!(Mask & (1 << pResult->Mode))))
{
WrError(ErrNum_InvAddrMode);
pResult->Mode = ModNone; pResult->Cnt = 0; pResult->AltBank = False;
}
return pResult->Mode;
}
static Boolean ChkAcc(const tStrComp *pArg)
{
tAdrResult Result;
if (DecodeAdr(pArg, OpSize ? MModReg16 : MModReg8, &Result) == ModNone)
return False;
if (((OpSize) && (Result.Val != AccReg16))
|| ((!OpSize) && (Result.Val != AccReg8)))
{
WrError(ErrNum_InvAddrMode);
return False;
}
return True;
}
static Boolean ChkMem1(const tAdrResult *pResult)
{
return (pResult->Val == 0x16) && (*pResult->Vals >= 4);
}
static Boolean DecodeBitAdr(const tStrComp *pArg, LongWord *pResult)
{
char *pSplit;
Boolean OK;
pSplit = RQuotPos(pArg->str.p_str, '.');
if (pSplit)
{
tStrComp Reg, Bit;
StrCompSplitRef(&Reg, &Bit, pArg, pSplit);
*pResult = EvalStrIntExpression(&Bit, UInt3, &OK) << 8;
if (OK)
{
tAdrResult Result;
switch (DecodeAdr(&Reg, MModReg8 | MModPSW | MModSFR | MModShort, &Result))
{
case ModReg8:
if (Result.Val >= 2)
{
WrStrErrorPos(ErrNum_InvReg, &Reg);
OK = FALSE;
}
else
*pResult |= (((LongWord)Result.Val) << 11) | 0x00030000;
break;
case ModPSW:
*pResult |= 0x00020000;
break;
case ModSFR:
*pResult |= 0x01080800 | *Result.Vals;
break;
case ModShort:
*pResult |= 0x01080000 | *Result.Vals;
break;
default:
OK = FALSE;
}
}
}
else
*pResult = EvalStrIntExpression(pArg, UInt32, &OK);
return OK;
}
/*-------------------------------------------------------------------------*/
/* instruction decoders */
static void DecodeFixed(Word Index)
{
if (ChkArgCnt(0, 0))
*pCode++ = Index;
}
static void DecodeMOV(Word Index)
{
UNUSED(Index);
SetOpSize(0);
if (ChkArgCnt(2, 2))
{
tAdrResult DestResult;
switch (DecodeAdr(&ArgStr[1], MModReg8 | MModShort | MModSFR | MModMem | MModAbs | MModPSW | MModSTBC, &DestResult))
{
case ModReg8:
{
tAdrResult SrcResult;
switch (DecodeAdr(&ArgStr[2], MModImm | MModReg8 | (DestResult.Val == AccReg8 ? (MModShort | MModSFR | MModAbs | MModMem | MModPSW) : 0), &SrcResult))
{
case ModImm:
*pCode++ = 0xb8 | DestResult.Val;
*pCode++ = *SrcResult.Vals;
break;
case ModReg8:
if (DestResult.Val == AccReg8)
*pCode++ = 0xd0 | SrcResult.Val;
else
{
*pCode++ = 0x24;
*pCode++ = (DestResult.Val << 4) | SrcResult.Val;
}
break;
case ModSFR:
*pCode++ = 0x10;
*pCode++ = *SrcResult.Vals;
break;
case ModShort:
*pCode++ = 0x20;
*pCode++ = *SrcResult.Vals;
break;
case ModAbs:
if (SrcResult.AltBank)
*pCode++ = 0x01;
*pCode++ = 0x09;
*pCode++ = 0xf0;
*pCode++ = *SrcResult.Vals;
*pCode++ = 1[SrcResult.Vals];
break;
case ModMem:
if (SrcResult.AltBank)
*pCode++ = 0x01;
if (SrcResult.Val == 0x16)
*pCode++ = 0x58 | *SrcResult.Vals;
else
{
*pCode++ = 0x00 | SrcResult.Val;
*pCode++ = *SrcResult.Vals << 4;
memcpy(pCode
, SrcResult.
Vals + 1, SrcResult.
Cnt - 1);
pCode += SrcResult.Cnt - 1;
}
break;
case ModPSW:
*pCode++ = 0x10;
*pCode++ = SFR_PSW;
break;
}
break;
}
case ModShort:
{
tAdrResult SrcResult;
switch (DecodeAdr(&ArgStr[2], MModImm | MModReg8 | MModShort, &SrcResult))
{
case ModImm:
*pCode++ = 0x3a;
*pCode++ = *DestResult.Vals;
*pCode++ = *SrcResult.Vals;
break;
case ModReg8:
if (SrcResult.Val != AccReg8) WrError(ErrNum_InvAddrMode);
else
{
*pCode++ = 0x22;
*pCode++ = *DestResult.Vals;
}
break;
case ModShort:
*pCode++ = 0x38;
*pCode++ = *DestResult.Vals;
*pCode++ = *SrcResult.Vals;
break;
}
break;
}
case ModSFR:
{
tAdrResult SrcResult;
switch (DecodeAdr(&ArgStr[2], MModImm | MModReg8, &SrcResult))
{
case ModImm:
*pCode++ = 0x2b;
*pCode++ = *DestResult.Vals;
*pCode++ = *SrcResult.Vals;
break;
case ModReg8:
if (SrcResult.Val != AccReg8) WrError(ErrNum_InvAddrMode);
else
{
*pCode++ = 0x12;
*pCode++ = *DestResult.Vals;
}
break;
}
break;
}
case ModPSW:
{
tAdrResult SrcResult;
switch (DecodeAdr(&ArgStr[2], MModImm | MModReg8, &SrcResult))
{
case ModImm:
*pCode++ = 0x2b;
*pCode++ = SFR_PSW;
*pCode++ = *SrcResult.Vals;
break;
case ModReg8:
if (SrcResult.Val != AccReg8) WrError(ErrNum_InvAddrMode);
else
{
*pCode++ = 0x12;
*pCode++ = SFR_PSW;
}
break;
}
break;
}
case ModSTBC:
{
tAdrResult SrcResult;
switch (DecodeAdr(&ArgStr[2], MModImm, &SrcResult))
{
case ModImm:
*pCode++ = 0x09;
*pCode++ = 0xc0;
*pCode++ = *SrcResult.Vals;
*pCode++ = ~(*SrcResult.Vals);
break;
}
break;
}
/* only works against ACC - dump result first, since DecodeAdr
destroys values */
case ModMem:
if (DestResult.AltBank)
*pCode++ = 0x01;
if (DestResult.Val == 0x16)
*pCode++ = 0x50 | *DestResult.Vals;
else
{
*pCode++ = 0x00 | DestResult.Val;
*pCode++ = 0x80 | (*DestResult.Vals << 4);
memcpy(pCode
, DestResult.
Vals + 1, DestResult.
Cnt - 1);
pCode += DestResult.Cnt - 1;
}
if (!ChkAcc(&ArgStr[2]))
pCode = BAsmCode;
break;
case ModAbs:
if (DestResult.AltBank)
*pCode++ = 0x01;
*pCode++ = 0x09;
*pCode++ = 0xf1;
*pCode++ = *DestResult.Vals;
*pCode++ = 1[DestResult.Vals];
if (!ChkAcc(&ArgStr[2]))
pCode = BAsmCode;
break;
}
}
}
static void DecodeXCH(Word Index)
{
UNUSED(Index);
SetOpSize(0);
if (ChkArgCnt(2, 2))
{
tAdrResult DestResult;
switch (DecodeAdr(&ArgStr[1], MModReg8 | MModShort | MModSFR | MModMem, &DestResult))
{
case ModReg8:
{
tAdrResult SrcResult;
switch (DecodeAdr(&ArgStr[2], MModReg8 | ((DestResult.Val == AccReg8) ? (MModShort | MModSFR | MModMem) : 0), &SrcResult))
{
case ModReg8:
if (DestResult.Val == AccReg8)
*pCode++ = 0xd8 | SrcResult.Val;
else if (SrcResult.Val == AccReg8)
*pCode++ = 0xd8 | DestResult.Val;
else
{
*pCode++ = 0x25;
*pCode++ = (DestResult.Val << 4) | SrcResult.Val;
}
break;
case ModShort:
*pCode++ = 0x21;
*pCode++ = *SrcResult.Vals;
break;
case ModSFR:
*pCode++ = 0x01;
*pCode++ = 0x21;
*pCode++ = *SrcResult.Vals;
break;
case ModMem:
if (SrcResult.AltBank)
*pCode++ = 0x01;
*pCode++ = SrcResult.Val;
*pCode++ = (*SrcResult.Vals << 4) | 0x04;
memcpy(pCode
, SrcResult.
Vals + 1, SrcResult.
Cnt - 1);
pCode += SrcResult.Cnt - 1;
break;
}
break;
}
case ModShort:
{
tAdrResult SrcResult;
switch (DecodeAdr(&ArgStr[2], MModReg8 | MModShort, &SrcResult))
{
case ModReg8:
if (SrcResult.Val != AccReg8) WrError(ErrNum_InvAddrMode);
else
{
*pCode++ = 0x21;
*pCode++ = *DestResult.Vals;
}
break;
case ModShort:
*pCode++ = 0x39;
*pCode++ = *DestResult.Vals;
*pCode++ = *SrcResult.Vals;
break;
}
break;
}
case ModSFR:
if (ChkAcc(&ArgStr[2]))
{
*pCode++ = 0x01;
*pCode++ = 0x21;
*pCode++ = *DestResult.Vals;
}
break;
case ModMem:
if (DestResult.AltBank)
*pCode++ = 0x01;
*pCode++ = DestResult.Val;
*pCode++ = (*DestResult.Vals << 4) | 0x04;
memcpy(pCode
, DestResult.
Vals + 1, DestResult.
Cnt - 1);
pCode += DestResult.Cnt - 1;
if (!ChkAcc(&ArgStr[2]))
pCode = BAsmCode;
break;
}
}
}
static void DecodeMOVW(Word Index)
{
UNUSED(Index);
SetOpSize(1);
if (ChkArgCnt(2, 2))
{
tAdrResult DestResult;
switch (DecodeAdr(&ArgStr[1], MModReg16 | MModSP | MModShort | MModSFR | MModMem, &DestResult))
{
case ModReg16:
{
tAdrResult SrcResult;
switch (DecodeAdr(&ArgStr[2], MModReg16 | MModImm | ((DestResult.Val == AccReg16) ? (MModSP | MModShort | MModSFR | MModMem) : 0), &SrcResult))
{
case ModReg16:
*pCode++ = 0x24;
*pCode++ = 0x08 | (DestResult.Val << 5) | (SrcResult.Val << 1);
break;
case ModImm:
*pCode++ = 0x60 | (DestResult.Val << 1);
*pCode++ = *SrcResult.Vals;
*pCode++ = 1[SrcResult.Vals];
break;
case ModShort:
*pCode++ = 0x1c;
*pCode++ = *SrcResult.Vals;
break;
case ModSFR:
*pCode++ = 0x11;
*pCode++ = *SrcResult.Vals;
break;
case ModSP:
*pCode++ = 0x11;
*pCode++ = SFR_SP;
break;
case ModMem:
if (ChkMem1(&SrcResult))
{
if (SrcResult.AltBank)
*pCode++ = 0x01;
*pCode++ = 0x05;
*pCode++ = 0xe2 | (*SrcResult.Vals & 0x01);
}
break;
}
break;
}
case ModSP:
{
tAdrResult SrcResult;
switch (DecodeAdr(&ArgStr[2], MModReg16 | MModImm, &SrcResult))
{
case ModReg16:
if (SrcResult.Val != AccReg16) WrError(ErrNum_InvAddrMode);
else
{
*pCode++ = 0x13;
*pCode++ = SFR_SP;
}
break;
case ModImm:
*pCode++ = 0x0b;
*pCode++ = SFR_SP;
*pCode++ = *SrcResult.Vals;
*pCode++ = 1[SrcResult.Vals];
break;
}
break;
}
case ModShort:
{
tAdrResult SrcResult;
switch (DecodeAdr(&ArgStr[2], MModReg16 | MModImm, &SrcResult))
{
case ModReg16:
if (SrcResult.Val != AccReg16) WrError(ErrNum_InvAddrMode);
else
{
*pCode++ = 0x1a;
*pCode++ = *DestResult.Vals;
}
break;
case ModImm:
*pCode++ = 0x0c;
*pCode++ = *DestResult.Vals;
*pCode++ = *SrcResult.Vals;
*pCode++ = 1[SrcResult.Vals];
break;
}
break;
}
case ModSFR:
{
tAdrResult SrcResult;
switch (DecodeAdr(&ArgStr[2], MModReg16 | MModImm, &SrcResult))
{
case ModReg16:
if (SrcResult.Val != AccReg16) WrError(ErrNum_InvAddrMode);
else
{
*pCode++ = 0x13;
*pCode++ = *DestResult.Vals;
}
break;
case ModImm:
*pCode++ = 0x0b;
*pCode++ = *DestResult.Vals;
*pCode++ = *SrcResult.Vals;
*pCode++ = 1[SrcResult.Vals];
break;
}
break;
}
case ModMem:
if (ChkMem1(&DestResult))
{
if (DestResult.AltBank)
*pCode++ = 0x01;
*pCode++ = 0x05;
*pCode++ = 0xe6 | (*DestResult.Vals & 0x01);
if (!ChkAcc(&ArgStr[2]))
pCode = BAsmCode;
}
break;
}
}
}
static void DecodeALU(Word Index)
{
SetOpSize(0);
if (ChkArgCnt(2, 2))
{
tAdrResult DestResult;
switch (DecodeAdr(&ArgStr[1], MModReg8 | MModShort | MModSFR, &DestResult))
{
case ModReg8:
{
tAdrResult SrcResult;
switch (DecodeAdr(&ArgStr[2], MModReg8 | ((DestResult.Val == AccReg8) ? (MModImm | MModShort | MModSFR | MModMem): 0), &SrcResult))
{
case ModReg8:
*pCode++ = 0x88 | Index;
*pCode++ = (DestResult.Val << 4) | SrcResult.Val;
break;
case ModImm:
*pCode++ = 0xa8 | Index;
*pCode++ = *SrcResult.Vals;
break;
case ModShort:
*pCode++ = 0x98 | Index;
*pCode++ = *SrcResult.Vals;
break;
case ModSFR:
*pCode++ = 0x01;
*pCode++ = 0x98 | Index;
*pCode++ = *SrcResult.Vals;
break;
case ModMem:
if (SrcResult.AltBank)
*pCode++ = 0x01;
*pCode++ = 0x00 | SrcResult.Val;
*pCode++ = 0x08 | (*SrcResult.Vals << 4) | Index;
memcpy(pCode
, SrcResult.
Vals + 1, SrcResult.
Cnt - 1);
pCode += SrcResult.Cnt - 1;
break;
}
break;
}
case ModShort:
{
tAdrResult SrcResult;
switch (DecodeAdr(&ArgStr[2], MModImm | MModShort, &SrcResult))
{
case ModImm:
*pCode++ = 0x68 | Index;
*pCode++ = *DestResult.Vals;
*pCode++ = *SrcResult.Vals;
break;
case ModShort:
*pCode++ = 0x78 | Index;
*pCode++ = *SrcResult.Vals;
*pCode++ = *DestResult.Vals;
break;
}
break;
}
case ModSFR:
{
tAdrResult SrcResult;
switch (DecodeAdr(&ArgStr[2], MModImm, &SrcResult))
{
case ModImm:
*pCode++ = 0x01;
*pCode++ = 0x68 | Index;
*pCode++ = *DestResult.Vals;
*pCode++ = *SrcResult.Vals;
break;
}
break;
}
}
}
}
static void DecodeALU16(Word Index)
{
static Byte Vals[3] = { 0, 2, 7 };
if (ChkArgCnt(2, 2))
{
SetOpSize(1);
if (ChkAcc(&ArgStr[1]))
{
tAdrResult Result;
switch (DecodeAdr(&ArgStr[2], MModImm | MModReg16 | MModShort | MModSFR, &Result))
{
case ModImm:
*pCode++ = 0x2c | Index;
*pCode++ = *Result.Vals;
*pCode++ = 1[Result.Vals];
break;
case ModReg16:
*pCode++ = 0x88 | Vals[Index - 1];
*pCode++ = 0x08 | (Result.Val << 1);
break;
case ModShort:
*pCode++ = 0x1c | Index;
*pCode++ = *Result.Vals;
break;
case ModSFR:
*pCode++ = 0x01;
*pCode++ = 0x1c | Index;
*pCode++ = *Result.Vals;
break;
}
}
}
}
static void DecodeMULDIV(Word Index)
{
if (ChkArgCnt(1, 1))
{
tAdrResult Result;
switch (DecodeAdr(&ArgStr[1], MModReg8, &Result))
{
case ModReg8:
*pCode++ = 0x05;
*pCode++ = Index | Result.Val;
break;
}
}
}
static void DecodeINCDEC(Word Index)
{
if (ChkArgCnt(1, 1))
{
tAdrResult Result;
switch (DecodeAdr(&ArgStr[1], MModReg8 | MModShort, &Result))
{
case ModReg8:
*pCode++ = 0xc0 | (Index << 3) | Result.Val;
break;
case ModShort:
*pCode++ = 0x26 | Index;
*pCode++ = *Result.Vals;
break;
}
}
}
static void DecodeINCDECW(Word Index)
{
if (ChkArgCnt(1, 1))
{
tAdrResult Result;
switch (DecodeAdr(&ArgStr[1], MModReg16 | MModSP, &Result))
{
case ModReg16:
*pCode++ = 0x44 | (Index << 3) | Result.Val;
break;
case ModSP:
*pCode++ = 0x05;
*pCode++ = 0xc0 | Index;
break;
}
}
}
static void DecodeShift8(Word Index)
{
Boolean OK;
Byte Shift;
if (ChkArgCnt(2, 2))
{
tAdrResult Result;
switch (DecodeAdr(&ArgStr[1], MModReg8, &Result))
{
case ModReg8:
Shift = EvalStrIntExpression(&ArgStr[2], UInt3, &OK);
if (OK)
{
*pCode++ = 0x30 | Hi(Index);
*pCode++ = Lo(Index) | (Shift << 3) | Result.Val;
}
break;
}
}
}
static void DecodeShift16(Word Index)
{
Boolean OK;
Byte Shift;
if (ChkArgCnt(2, 2))
{
tAdrResult Result;
switch (DecodeAdr(&ArgStr[1], MModReg16, &Result))
{
case ModReg16:
Shift = EvalStrIntExpression(&ArgStr[2], UInt3, &OK);
if (OK)
{
*pCode++ = 0x30 | Hi(Index);
*pCode++ = Lo(Index) | (Shift << 3) | (Result.Val << 1);
}
break;
}
}
}
static void DecodeShift4(Word Index)
{
if (ChkArgCnt(1, 1))
{
tAdrResult Result;
switch (DecodeAdr(&ArgStr[1], MModMem, &Result))
{
case ModMem:
if (ChkMem1(&Result))
{
if (Index)
*pCode++ = 0x01;
*pCode++ = 0x05;
*pCode++ = 0x8c | ((*Result.Vals & 1) << 1);
}
break;
}
}
}
static void DecodePUSHPOP(Word Index)
{
if (ChkArgCnt(1, 1))
{
tAdrResult Result;
switch (DecodeAdr(&ArgStr[1], MModReg16 | MModPSW | MModSFR, &Result))
{
case ModReg16:
*pCode++ = 0x34 | (Index << 3) | Result.Val;
break;
case ModPSW:
*pCode++ = 0x48 | Index;
break;
case ModSFR:
*pCode++ = Index ? 0x29 : 0x43;
*pCode++ = *Result.Vals;
break;
}
}
}
static void DecodeCALL(Word Index)
{
UNUSED(Index);
if (ChkArgCnt(1, 1))
{
tAdrResult Result;
switch (DecodeAdr(&ArgStr[1], MModAbs | MModReg16, &Result))
{
case ModAbs:
*pCode++ = 0x28;
*pCode++ = *Result.Vals;
*pCode++ = 1[Result.Vals];
break;
case ModReg16:
*pCode++ = 0x05;
*pCode++ = 0x58 | (Result.Val << 1);
break;
}
}
}
static void DecodeCALLF(Word Index)
{
Word AdrWord;
Boolean OK;
UNUSED(Index);
if (ChkArgCnt(1, 1))
{
tSymbolFlags Flags;
AdrWord = EvalStrIntExpressionOffsWithFlags(&ArgStr[1], !!(*ArgStr[1].str.p_str == '!'), UInt12, &OK, &Flags);
if (OK)
{
if (mFirstPassUnknown(Flags))
AdrWord |= 0x800;
if (AdrWord < 0x800) WrError(ErrNum_UnderRange);
else
{
*pCode++ = 0x90 | (Hi(AdrWord) & 7);
*pCode++ = Lo(AdrWord);
}
}
}
}
static void DecodeCALLT(Word Index)
{
Word AdrWord;
Boolean OK;
int ArgLen;
tStrComp Arg;
UNUSED(Index);
if (ChkArgCnt(1, 1))
{
StrCompRefRight
(&Arg
, &ArgStr
[1], 0); ArgLen
= strlen(Arg.
str.
p_str);
if ((*Arg.str.p_str != '[') || (Arg.str.p_str[ArgLen - 1] != ']')) WrError(ErrNum_InvAddrMode);
else
{
tSymbolFlags Flags;
StrCompIncRefLeft(&Arg, 1);
StrCompShorten(&Arg, 1);
AdrWord = EvalStrIntExpressionWithFlags(&Arg, UInt7, &OK, &Flags);
if (OK)
{
if (mFirstPassUnknown(Flags))
AdrWord = 0x40;
if (ChkRange(AdrWord, 0x40, 0x7e))
{
if (AdrWord & 1) WrError(ErrNum_AddrMustBeEven);
else
{
*pCode++ = 0xe0 | ((AdrWord - 0x40) >> 1);
}
}
}
}
}
}
static void DecodeBR(Word Index)
{
Boolean Rel;
UNUSED(Index);
if (ChkArgCnt(1, 1))
{
tAdrResult Result;
tStrComp Arg;
StrCompRefRight(&Arg, &ArgStr[1], 0);
Rel = (*Arg.str.p_str == '$');
if (Rel)
StrCompIncRefLeft(&Arg, 1);
switch (DecodeAdr(&Arg, MModAbs | MModReg16, &Result))
{
case ModAbs:
if (Rel)
{
LongInt Addr = (((Word)1[Result.Vals]) << 8) | (*Result.Vals);
Addr -= EProgCounter() + 2;
if (!mSymbolQuestionable(Result.ValSymFlags) && ((Addr < -128) || (Addr > 127))) WrError(ErrNum_JmpDistTooBig);
else
{
*pCode++ = 0x14;
*pCode++ = Addr & 0xff;
}
}
else
{
*pCode++ = 0x2c;
*pCode++ = *Result.Vals;
*pCode++ = 1[Result.Vals];
}
break;
case ModReg16:
*pCode++ = 0x05;
*pCode++ = 0x48 | (Result.Val << 1);
break;
}
}
}
static void DecodeBranch(Word Index)
{
LongInt Addr;
Boolean OK;
if (ChkArgCnt(1, 1))
{
tSymbolFlags Flags;
Addr = EvalStrIntExpressionOffsWithFlags(&ArgStr[1], !!(*ArgStr[1].str.p_str == '$'), UInt16, &OK, &Flags) - (EProgCounter() + 2);
if (OK)
{
if (!mSymbolQuestionable(Flags) && ((Addr < -128) || (Addr > 127))) WrError(ErrNum_JmpDistTooBig);
else
{
*pCode++ = Index;
*pCode++ = Addr & 0xff;
}
}
}
}
static void DecodeDBNZ(Word Index)
{
LongInt Addr;
Boolean OK;
UNUSED(Index);
if (ChkArgCnt(2, 2))
{
tAdrResult Result;
switch (DecodeAdr(&ArgStr[1], MModShort | MModReg8, &Result))
{
case ModShort:
*pCode++ = 0x3b;
*pCode++ = *Result.Vals;
break;
case ModReg8:
if ((Result.Val < 2) || (Result.Val > 3))
{
WrError(ErrNum_InvAddrMode);
Result.Mode = ModNone;
}
else
*pCode++ = 0x30 | Result.Val;
break;
}
if (Result.Mode != ModNone)
{
tSymbolFlags Flags;
Addr = EvalStrIntExpressionOffsWithFlags(&ArgStr[2], !!(*ArgStr[2].str.p_str == '$'), UInt16, &OK, &Flags) - (EProgCounter() + (pCode - BAsmCode) + 1);
if (!mSymbolQuestionable(Flags) && ((Addr < -128) || (Addr > 127)))
{
WrError(ErrNum_JmpDistTooBig);
pCode = BAsmCode;
}
else
*pCode++ = Addr & 0xff;
}
}
}
static void DecodeSEL(Word Index)
{
Boolean OK;
Byte Bank;
UNUSED(Index);
if (!ChkArgCnt(1, 1));
else if (as_strncasecmp(ArgStr[1].str.p_str, "RB", 2)) WrError(ErrNum_InvAddrMode);
else
{
Bank = EvalStrIntExpressionOffs(&ArgStr[1], 2, UInt2, &OK);
if (OK)
{
*pCode++ = 0x05;
*pCode++ = 0xa8 | Bank;
}
}
}
static void DecodeBIT(Word Index)
{
LongWord Result;
UNUSED(Index);
if (!ChkArgCnt(1, 1));
else if (DecodeBitAdr(&ArgStr[1], &Result))
EnterIntSymbol(&LabPart, Result, SegNone, False);
}
static void DecodeMOV1(Word Index)
{
LongWord Bit;
int ArgPos;
UNUSED(Index);
if (ChkArgCnt(2, 2))
{
if (!as_strcasecmp(ArgStr[1].str.p_str, "CY"))
ArgPos = 2;
else if (!as_strcasecmp(ArgStr[2].str.p_str, "CY"))
ArgPos = 1;
else
{
WrError(ErrNum_InvAddrMode);
return;
}
if (DecodeBitAdr(&ArgStr[ArgPos], &Bit))
{
*pCode++ = 0x00 | ((Bit >> 16) & 0xff);
*pCode++ = ((2 - ArgPos) << 4) | ((Bit >> 8) & 0xff);
if (Bit & 0x1000000)
*pCode++ = Bit & 0xff;
}
}
}
static void DecodeANDOR1(Word Index)
{
LongWord Bit;
if (!ChkArgCnt(2, 2));
else if (as_strcasecmp(ArgStr[1].str.p_str, "CY")) WrError(ErrNum_InvAddrMode);
else
{
tStrComp *pArg = &ArgStr[2], BitArg;
if (*pArg->str.p_str == '/')
{
StrCompRefRight(&BitArg, &ArgStr[2], 1);
pArg = &BitArg;
Index |= 0x10;
}
if (DecodeBitAdr(pArg, &Bit))
{
*pCode++ = 0x00 | ((Bit >> 16) & 0xff);
*pCode++ = Index | ((Bit >> 8) & 0xff);
if (Bit & 0x1000000)
*pCode++ = Bit & 0xff;
}
}
}
static void DecodeXOR1(Word Index)
{
LongWord Bit;
UNUSED(Index);
if (!ChkArgCnt(2, 2));
else if (as_strcasecmp(ArgStr[1].str.p_str, "CY")) WrError(ErrNum_InvAddrMode);
else
{
if (DecodeBitAdr(&ArgStr[2], &Bit))
{
*pCode++ = 0x00 | ((Bit >> 16) & 0xff);
*pCode++ = 0x60 | ((Bit >> 8) & 0xff);
if (Bit & 0x1000000)
*pCode++ = Bit & 0xff;
}
}
}
static void DecodeBit1(Word Index)
{
LongWord Bit;
UNUSED(Index);
if (!ChkArgCnt(1, 1));
else if (!as_strcasecmp(ArgStr[1].str.p_str, "CY"))
{
*pCode++ = 0x40 | (9 - (Index >> 4));
}
else if (DecodeBitAdr(&ArgStr[1], &Bit))
{
if ((Index >= 0x80) && ((Bit & 0xfffff800) == 0x01080000))
{
*pCode++ = (0x130 - Index) | ((Bit >> 8) & 7);
*pCode++ = Bit & 0xff;
}
else
{
*pCode++ = 0x00 | ((Bit >> 16) & 0xff);
*pCode++ = Index | ((Bit >> 8) & 0xff);
if (Bit & 0x1000000)
*pCode++ = Bit & 0xff;
}
}
}
static void DecodeBrBit(Word Index)
{
LongWord Bit;
LongInt Addr;
Boolean OK;
UNUSED(Index);
if (ChkArgCnt(2, 2)
&& DecodeBitAdr(&ArgStr[1], &Bit))
{
tSymbolFlags Flags;
if ((Bit & 0xfffff800) == 0x01080000)
{
if (Index == 0x80)
{
*pCode++ = 0x70 | ((Bit >> 8) & 7);
*pCode++ = Bit & 0xff;
}
else
{
*pCode++ = 0x00 | ((Bit >> 16) & 0xff);
*pCode++ = (0x130 - Index) | ((Bit >> 8) & 0xff);
if (Bit & 0x1000000)
*pCode++ = Bit & 0xff;
}
}
else
{
*pCode++ = 0x00 | ((Bit >> 16) & 0xff);
*pCode++ = (0x130 - Index) | ((Bit >> 8) & 0xff);
if (Bit & 0x1000000)
*pCode++ = Bit & 0xff;
}
Addr = EvalStrIntExpressionOffsWithFlags(&ArgStr[2], !!(*ArgStr[2].str.p_str == '$'), UInt16, &OK, &Flags) - (EProgCounter() + (pCode - BAsmCode) + 1);
if (!mSymbolQuestionable(Flags) && ((Addr < -128) || (Addr > 127)))
{
WrError(ErrNum_JmpDistTooBig);
pCode = BAsmCode;
}
else
*pCode++ = Addr & 0xff;
}
}
/*-------------------------------------------------------------------------*/
/* dynamic code table handling */
static void AddFixed(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeFixed);
}
static void InitFields(void)
{
InstTable = CreateInstTable(201);
AddInstTable(InstTable, "MOV", 0, DecodeMOV);
AddInstTable(InstTable, "XCH", 0, DecodeXCH);
AddInstTable(InstTable, "MOVW", 0, DecodeMOVW);
AddInstTable(InstTable, "ADD" , 0, DecodeALU);
AddInstTable(InstTable, "ADDC" , 1, DecodeALU);
AddInstTable(InstTable, "SUB" , 2, DecodeALU);
AddInstTable(InstTable, "SUBC" , 3, DecodeALU);
AddInstTable(InstTable, "AND" , 4, DecodeALU);
AddInstTable(InstTable, "OR" , 6, DecodeALU);
AddInstTable(InstTable, "XOR" , 5, DecodeALU);
AddInstTable(InstTable, "CMP" , 7, DecodeALU);
AddInstTable(InstTable, "ADDW", 1, DecodeALU16);
AddInstTable(InstTable, "SUBW", 2, DecodeALU16);
AddInstTable(InstTable, "CMPW", 3, DecodeALU16);
AddInstTable(InstTable, "MULU" , 0x08, DecodeMULDIV);
AddInstTable(InstTable, "DIVUW", 0x18, DecodeMULDIV);
AddInstTable(InstTable, "INC", 0, DecodeINCDEC);
AddInstTable(InstTable, "DEC", 1, DecodeINCDEC);
AddInstTable(InstTable, "INCW", 0, DecodeINCDECW);
AddInstTable(InstTable, "DECW", 1, DecodeINCDECW);
AddInstTable(InstTable, "ROR" , 0x040, DecodeShift8);
AddInstTable(InstTable, "ROL" , 0x140, DecodeShift8);
AddInstTable(InstTable, "RORC" , 0x000, DecodeShift8);
AddInstTable(InstTable, "ROLC" , 0x100, DecodeShift8);
AddInstTable(InstTable, "SHR" , 0x080, DecodeShift8);
AddInstTable(InstTable, "SHL" , 0x180, DecodeShift8);
AddInstTable(InstTable, "SHRW" , 0x0c0, DecodeShift16);
AddInstTable(InstTable, "SHLW" , 0x1c0, DecodeShift16);
AddInstTable(InstTable, "ROR4" , 0, DecodeShift4);
AddInstTable(InstTable, "ROL4" , 1, DecodeShift4);
AddInstTable(InstTable, "POP" , 0, DecodePUSHPOP);
AddInstTable(InstTable, "PUSH" , 1, DecodePUSHPOP);
AddInstTable(InstTable, "CALL" , 0, DecodeCALL);
AddInstTable(InstTable, "CALLF", 0, DecodeCALLF);
AddInstTable(InstTable, "CALLT", 0, DecodeCALLT);
AddInstTable(InstTable, "BR" , 0, DecodeBR);
AddInstTable(InstTable, "BC" , 0x83, DecodeBranch);
AddInstTable(InstTable, "BL" , 0x83, DecodeBranch);
AddInstTable(InstTable, "BNC" , 0x82, DecodeBranch);
AddInstTable(InstTable, "BNL" , 0x82, DecodeBranch);
AddInstTable(InstTable, "BZ" , 0x81, DecodeBranch);
AddInstTable(InstTable, "BE" , 0x81, DecodeBranch);
AddInstTable(InstTable, "BNZ" , 0x80, DecodeBranch);
AddInstTable(InstTable, "BNE" , 0x80, DecodeBranch);
AddInstTable(InstTable, "DBNZ" , 0, DecodeDBNZ);
AddInstTable(InstTable, "SEL", 0, DecodeSEL);
AddInstTable(InstTable, "MOV1", 0, DecodeMOV1);
AddInstTable(InstTable, "AND1", 0x20, DecodeANDOR1);
AddInstTable(InstTable, "OR1" , 0x40, DecodeANDOR1);
AddInstTable(InstTable, "XOR1" , 0, DecodeXOR1);
AddInstTable(InstTable, "SET1", 0x80, DecodeBit1);
AddInstTable(InstTable, "CLR1", 0x90, DecodeBit1);
AddInstTable(InstTable, "NOT1", 0x70, DecodeBit1);
AddInstTable(InstTable, "BT" , 0x80, DecodeBrBit);
AddInstTable(InstTable, "BF" , 0x90, DecodeBrBit);
AddInstTable(InstTable, "BTCLR" , 0x60, DecodeBrBit);
AddFixed("NOP", 0x00);
AddFixed("DI", 0x4a);
AddFixed("EI", 0x4b);
AddFixed("BRK", 0x5e);
AddFixed("RET", 0x56);
AddFixed("RETI", 0x57);
AddFixed("RETB", 0x5f);
AddFixed("ADJBA", 0x0e);
AddFixed("ADJBS", 0x0f);
AddInstTable(InstTable, "BIT", 0, DecodeBIT);
}
static void DeinitFields(void)
{
DestroyInstTable(InstTable);
}
/*-------------------------------------------------------------------------*/
/* interface to common layer */
static void MakeCode_78K2(void)
{
CodeLen = 0; DontPrint = False; OpSize = -1;
/* zu ignorierendes */
if (Memo("")) return;
/* Pseudoanweisungen */
if (DecodeIntelPseudo(False)) return;
pCode = BAsmCode;
if (!LookupInstTable(InstTable, OpPart.str.p_str))
WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
else
CodeLen = pCode - BAsmCode;
}
static void InitCode_78K2(void)
{
Reg_PM6 = 0;
Reg_P6 = 0;
}
static Boolean IsDef_78K2(void)
{
return Memo("BIT");
}
static void SwitchFrom_78K2(void)
{
DeinitFields();
}
static void SwitchTo_78K2(void)
{
static const ASSUMERec ASSUME78K2s[] =
{
{"P6" , &Reg_P6 , 0, 0xf, 0x10, NULL},
{"PM6" , &Reg_PM6 , 0, 0xf, 0x10, NULL}
};
const TFamilyDescr *pDescr;
pDescr = FindFamilyByName("78K2");
TurnWords = False;
SetIntConstMode(eIntConstModeIntel);
PCSymbol = "PC";
HeaderID = pDescr->Id;
NOPCode = 0x00;
DivideChars = ",";
HasAttrs = False;
ValidSegs = 1 << SegCode;
Grans[SegCode] = 1; ListGrans[SegCode] = 1; SegInits[SegCode] = 0;
SegLimits[SegCode] = 0xfffff;
pASSUMERecs = ASSUME78K2s;
ASSUMERecCnt = sizeof(ASSUME78K2s) / sizeof(ASSUME78K2s[0]);
MakeCode = MakeCode_78K2; IsDef = IsDef_78K2;
SwitchFrom = SwitchFrom_78K2; InitFields();
}
void code78k2_init(void)
{
CPU78214 = AddCPU("78214", SwitchTo_78K2);
AddInitPassProc(InitCode_78K2);
}