Blame |
Last modification |
View Log
| Download
| RSS feed
| ?url?
/* code870c.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Codegenerator TLCS-870/C */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <ctype.h>
#include <string.h>
#include "nls.h"
#include "bpemu.h"
#include "strutil.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmitree.h"
#include "asmcode.h"
#include "codepseudo.h"
#include "intpseudo.h"
#include "codevars.h"
#include "headids.h"
#include "errmsg.h"
#include "code870c.h"
typedef struct
{
const char *Name
;
Word Code
;
} CondRec
;
enum
{
ModNone
= -1,
ModReg8
= 0,
ModReg16
= 1,
ModImm
= 2,
ModMem
= 3
};
#define MModReg8 (1 << ModReg8)
#define MModReg16 (1 << ModReg16)
#define MModImm (1 << ModImm)
#define MModAbs (1 << ModAbs)
#define MModMem (1 << ModMem)
#define AccReg 0
#define WAReg 0
#define COND_CODE_TRUE 0xde
#define Reg8Cnt 8
static const char Reg8Names
[] = "AWCBEDLH";
static CPUVar CPU870C
;
static ShortInt OpSize
;
static Byte AdrVals
[4];
static ShortInt AdrType
;
static Byte AdrMode
;
static CondRec
*Conditions
;
/*--------------------------------------------------------------------------*/
static Boolean DecodeRegDisp
(tStrComp
*pArg
, Byte
*pRegFlag
, LongInt
*pDispAcc
, Boolean
*pFirstFlag
)
{
static const char AdrRegs
[][3] =
{
"DE", "HL", "IX", "IY", "SP", "C"
};
static const int AdrRegCnt
= sizeof(AdrRegs
) / sizeof(*AdrRegs
);
Boolean OK
, NegFlag
, NNegFlag
;
char *EPos
;
LongInt DispPart
;
int z
;
tStrComp Remainder
;
*pRegFlag
= 0;
*pDispAcc
= 0;
NegFlag
= False
;
OK
= True
;
*pFirstFlag
= False
;
do
{
KillPrefBlanksStrCompRef
(pArg
);
EPos
= indir_split_pos
(pArg
->str.
p_str);
NNegFlag
= EPos
&& (*EPos
== '-');
if (EPos
)
StrCompSplitRef
(pArg
, &Remainder
, pArg
, EPos
);
KillPostBlanksStrComp
(pArg
);
for (z
= 0; z
< AdrRegCnt
; z
++)
if (!as_strcasecmp
(pArg
->str.
p_str, AdrRegs
[z
]))
break;
if (z
>= AdrRegCnt
)
{
tSymbolFlags Flags
;
DispPart
= EvalStrIntExpressionWithFlags
(pArg
, Int32
, &OK
, &Flags
);
*pFirstFlag
= *pFirstFlag
|| mFirstPassUnknown
(Flags
);
*pDispAcc
= NegFlag
? *pDispAcc
- DispPart
: *pDispAcc
+ DispPart
;
}
else if ((NegFlag
) || (*pRegFlag
& (1 << z
)))
{
WrError
(ErrNum_InvAddrMode
);
OK
= False
;
}
else
*pRegFlag
|= 1 << z
;
NegFlag
= NNegFlag
;
if (EPos
)
*pArg
= Remainder
;
}
while (OK
&& EPos
);
if (*pDispAcc
!= 0)
*pRegFlag
|= 1 << AdrRegCnt
;
return OK
;
}
static void DecodeAdr
(const tStrComp
*pArg
, Byte Erl
, Boolean IsDest
)
{
static const char Reg16Names
[][3] =
{
"WA", "BC", "DE", "HL", "IX", "IY", "SP"
};
static const int Reg16Cnt
= sizeof(Reg16Names
) / sizeof(*Reg16Names
);
int z
;
Byte RegFlag
;
LongInt DispAcc
;
Boolean OK
, FirstFlag
;
AdrType
= ModNone
;
AdrCnt
= 0;
if (strlen(pArg
->str.
p_str) == 1)
{
for (z
= 0; z
< Reg8Cnt
; z
++)
if (as_toupper
(*pArg
->str.
p_str) == Reg8Names
[z
])
{
AdrType
= ModReg8
;
OpSize
= 0;
AdrMode
= z
;
goto chk
;
}
}
for (z
= 0; z
< Reg16Cnt
; z
++)
if (!as_strcasecmp
(pArg
->str.
p_str, Reg16Names
[z
]))
{
AdrType
= ModReg16
;
OpSize
= 1;
AdrMode
= z
;
goto chk
;
}
if (IsIndirect
(pArg
->str.
p_str))
{
tStrComp Arg
;
StrCompRefRight
(&Arg
, pArg
, 1);
StrCompShorten
(&Arg
, 1);
if ((!as_strcasecmp
(Arg.
str.
p_str, "+SP")) && (!IsDest
))
{
AdrType
= ModMem
;
AdrMode
= 0xe6;
goto chk
;
}
if ((!as_strcasecmp
(Arg.
str.
p_str, "SP-")) && (IsDest
))
{
AdrType
= ModMem
;
AdrMode
= 0xe6;
goto chk
;
}
if ((!as_strcasecmp
(Arg.
str.
p_str, "PC+A")) && (!IsDest
))
{
AdrType
= ModMem
;
AdrMode
= 0x4f;
goto chk
;
}
if (DecodeRegDisp
(&Arg
, &RegFlag
, &DispAcc
, &FirstFlag
))
switch (RegFlag
)
{
case 0x40: /* (nnnn) (nn) */
AdrType
= ModMem
;
AdrVals
[0] = DispAcc
& 0xff;
if (DispAcc
> 0xff)
{
AdrMode
= 0xe1;
AdrCnt
= 2;
AdrVals
[1] = (DispAcc
>> 8) & 0xff;
}
else
{
AdrMode
= 0xe0;
AdrCnt
= 1;
}
break;
case 0x08: /* (IY) */
AdrType
= ModMem
;
AdrMode
= 0xe5;
break;
case 0x04: /* (IX) */
AdrType
= ModMem
;
AdrMode
= 0xe4;
break;
case 0x02: /* (HL) */
AdrType
= ModMem
;
AdrMode
= 0xe3;
break;
case 0x01: /* (DE) */
AdrType
= ModMem
;
AdrMode
= 0xe2;
break;
case 0x50: /* (SP+dd) */
if (FirstFlag
)
DispAcc
&= 0x7f;
if (ChkRange
(DispAcc
, -128, 127))
{
AdrType
= ModMem
;
AdrMode
= 0xd6;
AdrCnt
= 1;
AdrVals
[0] = DispAcc
& 0xff;
}
break;
case 0x48: /* (IY+dd) */
if (FirstFlag
)
DispAcc
&= 0x7f;
if (ChkRange
(DispAcc
, -128, 127))
{
AdrType
= ModMem
;
AdrMode
= 0xd5;
AdrCnt
= 1;
AdrVals
[0] = DispAcc
& 0xff;
}
break;
case 0x44: /* (IX+dd) */
if (FirstFlag
)
DispAcc
&= 0x7f;
if (ChkRange
(DispAcc
, -128, 127))
{
AdrType
= ModMem
;
AdrMode
= 0xd4;
AdrCnt
= 1;
AdrVals
[0] = DispAcc
& 0xff;
}
break;
case 0x42: /* (HL+dd) */
if (FirstFlag
)
DispAcc
&= 0x7f;
if (ChkRange
(DispAcc
, -128, 127))
{
AdrType
= ModMem
;
AdrMode
= 0xd7;
AdrCnt
= 1;
AdrVals
[0] = DispAcc
& 0xff;
}
break;
case 0x22: /* (HL+c) */
AdrType
= ModMem
;
AdrMode
= 0xe7;
break;
default:
WrError
(ErrNum_InvAddrMode
);
}
goto chk
;
}
else
{
switch (OpSize
)
{
case -1:
WrError
(ErrNum_UndefOpSizes
);
break;
case 0:
AdrVals
[0] = EvalStrIntExpression
(pArg
, Int8
, &OK
);
if (OK
)
{
AdrType
= ModImm
;
AdrCnt
= 1;
}
break;
case 1:
DispAcc
= EvalStrIntExpression
(pArg
, Int16
, &OK
);
if (OK
)
{
AdrType
= ModImm
;
AdrCnt
= 2;
AdrVals
[0] = DispAcc
& 0xff;
AdrVals
[1] = (DispAcc
>> 8) & 0xff;
}
break;
}
}
chk
:
if ((AdrType
!= ModNone
) && (!((1<<AdrType
) & Erl
)))
{
AdrType
= ModNone
;
AdrCnt
= 0;
WrError
(ErrNum_InvAddrMode
);
}
}
static Byte MakeDestMode
(Byte AdrMode
)
{
if ((AdrMode
& 0xf0) == 0xe0)
return AdrMode
+ 0x10;
else
return AdrMode
- 0x80;
}
static Boolean DecodeSPDisp
(const tStrComp
*pArg
, Byte
*pDisp
, Boolean
*pDispNeg
)
{
Boolean OK
;
LongInt DispAcc
;
tSymbolFlags Flags
;
*pDisp
= 0;
*pDispNeg
= False
;
/* avoid ambiguities - LD SP,SP should be coded as LD rr,rr */
if (IsIndirect
(pArg
->str.
p_str))
return False
;
if (as_strncasecmp
(pArg
->str.
p_str, "SP", 2))
return False
;
if (strlen(pArg
->str.
p_str) < 3)
return False
;
DispAcc
= EvalStrIntExpressionOffsWithFlags
(pArg
, 2, Int16
, &OK
, &Flags
);
if (!OK
)
return False
;
if (mFirstPassUnknown
(Flags
))
DispAcc
&= 0xff;
if (ChkRange
(DispAcc
, -255, 255))
{
*pDispNeg
= DispAcc
< 0;
*pDisp
= *pDispNeg
? -DispAcc
: DispAcc
;
}
return True
; /* return True even if disp is out of range, addressing mode was properly detected */
}
static Boolean SplitBit
(tStrComp
*pArg
, Byte
*Erg
)
{
tStrComp BitArg
;
char *p
;
p
= RQuotPos
(pArg
->str.
p_str, '.');
if (!p
)
return False
;
StrCompSplitRef
(pArg
, &BitArg
, pArg
, p
);
if (strlen(BitArg.
str.
p_str) != 1) return False
;
else if ((*BitArg.
str.
p_str >= '0') && (*BitArg.
str.
p_str <= '7'))
{
*Erg
= *BitArg.
str.
p_str - '0';
return True
;
}
else if (toupper(*BitArg.
str.
p_str) == 'A')
{
*Erg
= 8;
return True
;
}
else
return False
;
}
static void CodeMem
(Byte Entry
, Byte Opcode
)
{
BAsmCode
[0] = Entry
+ AdrMode
;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
BAsmCode
[1 + AdrCnt
] = Opcode
;
}
/*!------------------------------------------------------------------------
* \fn decode_condition(const char *p_cond_str, Word *p_cond_code)
* \brief parse condition code
* \param p_cond_str source argument
* \param p_cond_code machine code if found
* \return True if found
* ------------------------------------------------------------------------ */
static Boolean decode_condition
(const char *p_cond_str
, Word
*p_cond_code
)
{
int z
;
for (z
= 0; Conditions
[z
].
Name; z
++)
if (!as_strcasecmp
(p_cond_str
, Conditions
[z
].
Name))
{
*p_cond_code
= Conditions
[z
].
Code;
return True
;
}
return False
;
}
/*!------------------------------------------------------------------------
* \fn cond_code_tf(Word cond_code)
* \brief check if condition is true or false
* \param cond_code condition code to check
* \return True if yes
* ------------------------------------------------------------------------ */
static Boolean cond_code_tf
(Word cond_code
)
{
return (cond_code
== COND_CODE_TRUE
)
|| (cond_code
== 0xdf);
}
/*--------------------------------------------------------------------------*/
static void DecodeFixed
(Word Code
)
{
if (ChkArgCnt
(0, 0))
{
CodeLen
= 0;
if (Hi
(Code
) != 0)
BAsmCode
[CodeLen
++] = Hi
(Code
);
BAsmCode
[CodeLen
++] = Lo
(Code
);
}
}
static void DecodeLD
(Word Code
)
{
Byte HReg
, Bit
, HCnt
, HMode
, HVals
[2];
Boolean OK
, NegFlag
;
UNUSED
(Code
);
if (!ChkArgCnt
(2, 2));
else if (!as_strcasecmp
(ArgStr
[1].
str.
p_str, "PSW"))
{
BAsmCode
[2] = EvalStrIntExpression
(&ArgStr
[2], Int8
, &OK
);
if (OK
)
{
BAsmCode
[0] = 0xe8;
BAsmCode
[1] = 0xde;
CodeLen
= 3;
}
}
else if (!as_strcasecmp
(ArgStr
[1].
str.
p_str, "RBS"))
{
BAsmCode
[1] = EvalStrIntExpression
(&ArgStr
[2], UInt1
, &OK
) << 1;
if (OK
)
{
BAsmCode
[0] = 0xf9;
CodeLen
= 2;
}
}
else if ((!as_strcasecmp
(ArgStr
[1].
str.
p_str, "SP")) && (DecodeSPDisp
(&ArgStr
[2], BAsmCode
+ 1, &NegFlag
)))
{
BAsmCode
[0] = NegFlag
? 0x3f : 0x37;
CodeLen
= 2;
}
else if (!as_strcasecmp
(ArgStr
[1].
str.
p_str, "CF"))
{
if (!SplitBit
(&ArgStr
[2], &Bit
)) WrError
(ErrNum_InvBitPos
);
else
{
DecodeAdr
(&ArgStr
[2], (Bit
< 8 ? MModReg8
: 0) | MModMem
, False
);
switch (AdrType
)
{
case ModReg8
:
CodeLen
= 2;
BAsmCode
[0] = 0xe8 | AdrMode
;
BAsmCode
[1] = 0x58 | Bit
;
break;
case ModMem
:
if ((Bit
< 8) && (AdrMode
== 0xe0))
{
CodeLen
= 2;
BAsmCode
[0] = 0x58 | Bit
;
BAsmCode
[1] = AdrVals
[0];
}
else if (Bit
< 8)
{
CodeLen
= 2 + AdrCnt
;
CodeMem
(0x00, 0x58 | Bit
);
}
else
{
CodeLen
= 2 + AdrCnt
;
CodeMem
(0x00, 0xfc);
}
break;
}
}
}
else if (!as_strcasecmp
(ArgStr
[2].
str.
p_str, "CF"))
{
if (!SplitBit
(&ArgStr
[1], &Bit
)) WrError
(ErrNum_InvBitPos
);
else
{
DecodeAdr
(&ArgStr
[1], (Bit
< 8 ? MModReg8
: 0) | MModMem
, False
);
switch (AdrType
)
{
case ModReg8
:
CodeLen
= 2;
BAsmCode
[0] = 0xe8 | AdrMode
;
BAsmCode
[1] = 0xe8 | Bit
;
break;
case ModMem
:
if (Bit
< 8)
{
CodeLen
= 2 + AdrCnt
;
CodeMem
(0x00, 0xe8 | Bit
);
}
else
{
CodeLen
= 2 + AdrCnt
;
CodeMem
(0x00, 0xf3);
}
break;
}
}
}
else
{
DecodeAdr
(&ArgStr
[1], MModReg8
| MModReg16
| MModMem
, TRUE
);
switch (AdrType
)
{
case ModReg8
:
HReg
= AdrMode
;
DecodeAdr
(&ArgStr
[2], MModReg8
| MModMem
| MModImm
, FALSE
);
switch (AdrType
)
{
case ModReg8
:
if (HReg
== AccReg
)
{
CodeLen
= 1; /* OK */
BAsmCode
[0] = 0x10 | AdrMode
;
}
else if (AdrMode
== AccReg
)
{
CodeLen
= 1; /* OK */
BAsmCode
[0] = 0x40 | HReg
;
}
else
{
CodeLen
= 2; /* OK */
BAsmCode
[0] = 0xe8 | AdrMode
;
BAsmCode
[1] = 0x40 | HReg
;
}
break;
case ModMem
:
if ((HReg
== AccReg
) && (AdrMode
== 0xe3)) /* A,(HL) */
{
CodeLen
= 1; /* OK */
BAsmCode
[0] = 0x0d;
}
else if ((HReg
== AccReg
) && (AdrMode
== 0xe0)) /* A,(nn) */
{
CodeLen
= 2; /* OK */
BAsmCode
[0] = 0x0c;
BAsmCode
[1] = AdrVals
[0];
}
else
{
CodeLen
= 2 + AdrCnt
; /* OK */
CodeMem
(0x00, 0x40 | HReg
);
}
break;
case ModImm
:
CodeLen
= 2; /* OK */
BAsmCode
[0] = 0x18 | HReg
;
BAsmCode
[1] = AdrVals
[0];
break;
}
break;
case ModReg16
:
HReg
= AdrMode
;
DecodeAdr
(&ArgStr
[2], MModReg16
| MModMem
| MModImm
, FALSE
);
switch (AdrType
)
{
case ModReg16
:
CodeLen
= 2; /* OK */
BAsmCode
[0] = 0xe8 | AdrMode
;
BAsmCode
[1] = 0x18 | HReg
;
break;
case ModMem
:
CodeLen
= 2 + AdrCnt
; /* OK */
BAsmCode
[0] = AdrMode
;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
BAsmCode
[1 + AdrCnt
] = 0x48 + HReg
;
break;
case ModImm
:
CodeLen
= 3; /* OK */
BAsmCode
[0] = 0x48 | HReg
;
memcpy(BAsmCode
+ 1, AdrVals
, 2);
break;
}
break;
case ModMem
:
memcpy(HVals
, AdrVals
, AdrCnt
);
HCnt
= AdrCnt
;
HMode
= AdrMode
;
OpSize
= 0;
DecodeAdr
(&ArgStr
[2], MModReg8
| MModReg16
| MModImm
, FALSE
);
switch (AdrType
)
{
case ModReg8
:
if ((HMode
== 0xe3) && (AdrMode
== AccReg
)) /* (HL),A */
{
CodeLen
= 1; /* OK */
BAsmCode
[0] = 0x0f;
}
else if ((HMode
== 0xe0) && (AdrMode
== AccReg
))
{
CodeLen
= 2; /* OK */
BAsmCode
[0] = 0x0e;
BAsmCode
[1] = AdrVals
[0];
}
else
{
CodeLen
= 2 + HCnt
; /* OK */
BAsmCode
[0] = MakeDestMode
(HMode
);
memcpy(BAsmCode
+ 1, HVals
, HCnt
);
BAsmCode
[1 + HCnt
] = 0x78 | AdrMode
;
}
break;
case ModReg16
:
CodeLen
= 2 + HCnt
; /* OK */
BAsmCode
[0] = MakeDestMode
(HMode
);
memcpy(BAsmCode
+ 1, HVals
, HCnt
);
BAsmCode
[1 + HCnt
] = 0x68 | AdrMode
;
break;
case ModImm
:
if (HMode
== 0xe0) /* (nn),nn */
{
CodeLen
= 3;
BAsmCode
[0] = 0x0a;
BAsmCode
[1] = HVals
[0];
BAsmCode
[2] = AdrVals
[0];
}
else
{
CodeLen
= 1 + HCnt
+ 1 + AdrCnt
;
BAsmCode
[0] = MakeDestMode
(HMode
);
memcpy(BAsmCode
+ 1, HVals
, HCnt
);
BAsmCode
[1 + HCnt
] = 0xf9;
BAsmCode
[2 + HCnt
] = AdrVals
[0];
}
break;
}
break;
}
}
}
static void DecodeLDW
(Word Code
)
{
UNUSED
(Code
);
if (ChkArgCnt
(2, 2))
{
Boolean OK
;
Integer AdrInt
= EvalStrIntExpression
(&ArgStr
[2], Int16
, &OK
);
if (OK
)
{
DecodeAdr
(&ArgStr
[1], MModReg16
| MModMem
, TRUE
);
switch (AdrType
)
{
case ModReg16
:
CodeLen
= 3;
BAsmCode
[0] = 0x48 | AdrMode
;
BAsmCode
[1] = AdrInt
& 0xff;
BAsmCode
[2] = AdrInt
>> 8;
break;
case ModMem
:
if (AdrMode
== 0xe3) /* HL */
{
CodeLen
= 3;
BAsmCode
[0] = 0x09;
BAsmCode
[1] = AdrInt
& 0xff;
BAsmCode
[2] = AdrInt
>> 8;
}
else if (AdrMode
!= 0xe0) WrError
(ErrNum_InvAddrMode
); /* (nn) */
else
{
CodeLen
= 3;
BAsmCode
[0] = 0x08;
BAsmCode
[1] = AdrInt
& 0xff;
BAsmCode
[2] = AdrInt
>> 8;
}
break;
}
}
}
}
static void DecodePUSH_POP
(Word Code
)
{
if (!ChkArgCnt
(1, 1));
else if (!as_strcasecmp
(ArgStr
[1].
str.
p_str, "PSW"))
{
CodeLen
= 2;
BAsmCode
[0] = 0xe8;
BAsmCode
[1] = 0xdc | Code
;
}
else
{
DecodeAdr
(&ArgStr
[1], MModReg16
, False
);
if (AdrType
!= ModNone
)
{
if (AdrMode
< 4)
{
CodeLen
= 1;
BAsmCode
[0] = (Code
<< 7) | 0x50 | AdrMode
;
}
else
{
CodeLen
= 2;
BAsmCode
[0] = 0xe8 | AdrMode
;
BAsmCode
[1] = 0xd8 | Code
;
}
}
}
}
static void DecodeXCH
(Word Code
)
{
Byte HReg
, HCnt
;
UNUSED
(Code
);
if (ChkArgCnt
(2, 2))
{
DecodeAdr
(&ArgStr
[1], MModReg8
| MModReg16
| MModMem
, FALSE
); /* set IsDest FALSE for mirrored MemOp */
switch (AdrType
)
{
case ModReg8
:
HReg
= AdrMode
;
DecodeAdr
(&ArgStr
[2], MModReg8
| MModMem
, FALSE
);
switch (AdrType
)
{
case ModReg8
:
CodeLen
= 2;
BAsmCode
[0] = 0xe8 | AdrMode
;
BAsmCode
[1] = 0x70 | HReg
;
break;
case ModMem
:
CodeLen
= 2 + AdrCnt
;
CodeMem
(0x00, 0x70 | HReg
);
break;
}
break;
case ModReg16
:
HReg
= AdrMode
;
DecodeAdr
(&ArgStr
[2], MModReg16
| MModMem
, FALSE
);
switch (AdrType
)
{
case ModReg16
:
CodeLen
= 2;
BAsmCode
[0] = 0xe8 | AdrMode
;
BAsmCode
[1] = 0x78 | HReg
;
break;
case ModMem
:
CodeLen
= 2 + AdrCnt
;
CodeMem
(0x00, 0xd8 | HReg
);
break;
}
break;
case ModMem
:
BAsmCode
[0] = AdrMode
;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
HCnt
= AdrCnt
;
DecodeAdr
(&ArgStr
[2], MModReg8
| MModReg16
, FALSE
);
switch (AdrType
)
{
case ModReg8
:
CodeLen
= 2 + HCnt
;
BAsmCode
[1 + HCnt
] = 0x70 | AdrMode
;
break;
case ModReg16
:
CodeLen
= 2 + HCnt
;
BAsmCode
[1 + HCnt
] = 0xd8 | AdrMode
;
break;
}
break;
}
}
}
static void DecodeALU
(Word Code
)
{
Byte HReg
, HLen
;
if (!ChkArgCnt
(2, 2));
else if (!as_strcasecmp
(ArgStr
[1].
str.
p_str, "CF"))
{
Byte Bit
;
if (Code
!= 5) WrError
(ErrNum_InvAddrMode
); /* XOR only */
else if (!SplitBit
(&ArgStr
[2], &Bit
)) WrError
(ErrNum_InvBitPos
);
else if (Bit
>= 8) WrError
(ErrNum_InvAddrMode
); /* only fixed bit # */
else
{
DecodeAdr
(&ArgStr
[2], MModReg8
| MModMem
, False
);
switch (AdrType
)
{
case ModReg8
:
CodeLen
= 2;
BAsmCode
[0] = 0xe8 | AdrMode
;
BAsmCode
[1] = 0x50 | Bit
;
break;
case ModMem
:
CodeLen
= 2 + AdrCnt
;
CodeMem
(0x00, 0x50 | Bit
);
break;
}
}
}
else
{
DecodeAdr
(&ArgStr
[1], MModReg8
| MModReg16
| MModMem
, FALSE
); /* (+SP) allowed as dest mem op instead of (SP-) */
switch (AdrType
)
{
case ModReg8
:
HReg
= AdrMode
;
DecodeAdr
(&ArgStr
[2], MModReg8
| MModMem
| MModImm
, FALSE
);
switch (AdrType
)
{
case ModReg8
:
CodeLen
= 2;
BAsmCode
[0] = 0xe8 | AdrMode
;
BAsmCode
[1] = (HReg
<< 3) | Code
;
break;
case ModMem
:
CodeLen
= 2 + AdrCnt
;
CodeMem
(0x00, (HReg
<< 3) | Code
);
break;
case ModImm
:
if (HReg
== AccReg
)
{
CodeLen
= 2;
BAsmCode
[0] = 0x60 | Code
;
BAsmCode
[1] = AdrVals
[0];
}
else
{
CodeLen
= 3;
BAsmCode
[0] = 0xe8 | HReg
;
BAsmCode
[1] = 0x60 | Code
;
BAsmCode
[2] = AdrVals
[0];
}
break;
}
break;
case ModReg16
:
HReg
= AdrMode
;
DecodeAdr
(&ArgStr
[2], MModImm
| MModMem
| MModReg16
, FALSE
);
switch (AdrType
)
{
case ModImm
:
CodeLen
= 4;
BAsmCode
[0] = 0xe8 | HReg
;
BAsmCode
[1] = 0x68 | Code
;
memcpy(BAsmCode
+ 2, AdrVals
, AdrCnt
);
break;
case ModMem
:
CodeLen
= 2 + AdrCnt
;
CodeMem
(0x00, 0x80 | (HReg
<< 3) | Code
);
break;
case ModReg16
:
CodeLen
= 2;
BAsmCode
[0] = 0xe8 | AdrMode
;
BAsmCode
[1] = 0x80 | (HReg
<< 3) | Code
;
break;
}
break;
case ModMem
:
if ((0xe0 == AdrMode
) && (Code
== 7))
{
BAsmCode
[0] = Code
;
BAsmCode
[1] = AdrVals
[0];
HLen
= 2;
}
else
{
CodeMem
(0x00, 0x60 | Code
);
HLen
= 2 + AdrCnt
;
}
OpSize
= 0;
DecodeAdr
(&ArgStr
[2], MModImm
, FALSE
);
if (AdrType
== ModImm
)
{
BAsmCode
[HLen
] = AdrVals
[0];
CodeLen
= HLen
+ 1;
}
break;
}
}
}
static void DecodeINC_DEC
(Word Code
)
{
if (ChkArgCnt
(1, 1))
{
DecodeAdr
(&ArgStr
[1], MModReg8
| MModReg16
| MModMem
, False
);
switch (AdrType
)
{
case ModReg8
:
CodeLen
= 1;
BAsmCode
[0] = 0x20 | Code
| AdrMode
;
break;
case ModReg16
:
CodeLen
= 1;
BAsmCode
[0] = 0x30 | Code
| AdrMode
;
break;
case ModMem
:
CodeLen
= 2 + AdrCnt
;
CodeMem
(0x00, 0xf0 | Code
);
break;
}
}
}
static void DecodeReg
(Word Code
)
{
if (ChkArgCnt
(1, 1))
{
DecodeAdr
(&ArgStr
[1], MModReg8
, False
);
if (AdrType
!= ModNone
)
{
CodeLen
= 1;
BAsmCode
[0] = Lo
(Code
) | AdrMode
;
if (Hi
(Code
))
BAsmCode
[CodeLen
++] = Hi
(Code
);
}
}
}
static void DecodeReg16
(Word Code
)
{
if (ChkArgCnt
(1, 1))
{
DecodeAdr
(&ArgStr
[1], MModReg16
, False
);
if (AdrType
!= ModNone
)
{
CodeLen
= 1;
BAsmCode
[0] = Lo
(Code
) | AdrMode
;
if (Hi
(Code
))
BAsmCode
[CodeLen
++] = Hi
(Code
);
}
}
}
static void DecodeMUL
(Word Code
)
{
UNUSED
(Code
);
if (ChkArgCnt
(2, 2))
{
DecodeAdr
(&ArgStr
[1], MModReg8
, False
);
if (AdrType
== ModReg8
)
{
Byte HReg
= AdrMode
;
DecodeAdr
(&ArgStr
[2], MModReg8
, False
);
if (AdrType
== ModReg8
)
{
if ((HReg
^ AdrMode
) != 1) WrError
(ErrNum_InvRegPair
);
else
{
CodeLen
= 2;
BAsmCode
[0] = 0xe8 | (HReg
>> 1);
BAsmCode
[1] = 0xf2;
}
}
}
}
}
static void DecodeDIV
(Word Code
)
{
UNUSED
(Code
);
if (ChkArgCnt
(2, 2))
{
DecodeAdr
(&ArgStr
[1], MModReg16
, False
);
if (AdrType
== ModReg16
)
{
if ((AdrMode
== 1) || (AdrMode
> 3)) WrError
(ErrNum_InvAddrMode
); /* WA DE HL */
else
{
Byte HReg
= AdrMode
;
DecodeAdr
(&ArgStr
[2], MModReg8
, False
);
if (AdrType
== ModReg8
)
{
if (AdrMode
!= 2) WrError
(ErrNum_InvAddrMode
); /* C */
else
{
CodeLen
= 2;
BAsmCode
[0] = 0xe8 | HReg
;
BAsmCode
[1] = 0xf3;
}
}
}
}
}
}
static void DecodeNEG
(Word Code
)
{
UNUSED
(Code
);
if (!ChkArgCnt
(2, 2));
else if (as_strcasecmp
(ArgStr
[1].
str.
p_str, "CS")) WrError
(ErrNum_InvAddrMode
);
else
{
DecodeAdr
(&ArgStr
[2], MModReg16
, False
);
if (AdrType
== ModReg16
)
{
CodeLen
= 2;
BAsmCode
[0] = 0xe8 | AdrMode
;
BAsmCode
[1] = 0xfa;
}
}
}
static void DecodeROLD_RORD
(Word Code
)
{
if (!ChkArgCnt
(2, 2));
else if (as_strcasecmp
(ArgStr
[1].
str.
p_str, "A")) WrError
(ErrNum_InvAddrMode
);
else
{
DecodeAdr
(&ArgStr
[2], MModMem
, False
);
if (AdrType
!= ModNone
)
{
CodeLen
= 2 + AdrCnt
;
CodeMem
(0x00, Code
);
}
}
}
static void DecodeTEST_CPL_SET_CLR
(Word Code
)
{
Byte Bit
;
if (!ChkArgCnt
(1, 1));
else if (!as_strcasecmp
(ArgStr
[1].
str.
p_str, "CF"))
{
switch (Lo
(Code
))
{
case 0xc0:
BAsmCode
[0] = 0xc5;
CodeLen
= 1;
break;
case 0xc8:
BAsmCode
[0] = 0xc4;
CodeLen
= 1;
break;
case 0xe0:
BAsmCode
[0] = 0xc6;
CodeLen
= 1;
break;
default:
WrError
(ErrNum_InvAddrMode
);
}
}
else if (!SplitBit
(&ArgStr
[1], &Bit
)) WrError
(ErrNum_InvBitPos
);
else
{
DecodeAdr
(&ArgStr
[1], (Bit
< 8 ? MModReg8
: 0) | MModMem
, False
);
switch (AdrType
)
{
case ModReg8
:
CodeLen
= 2;
BAsmCode
[0] = 0xe8 | AdrMode
;
BAsmCode
[1] = Lo
(Code
) | Bit
;
break;
case ModMem
:
if ((Bit
< 8) && (AdrMode
== 0xe0) && (Lo
(Code
) != 0xe0)) /* no short addr. for CPL */
{
CodeLen
= 2;
BAsmCode
[0] = Lo
(Code
) | Bit
;
BAsmCode
[1] = AdrVals
[0];
}
else if (Bit
< 8)
{
CodeLen
= 2 + AdrCnt
;
CodeMem
(0x00, Lo
(Code
) | Bit
);
}
else
{
CodeLen
= 2 + AdrCnt
;
CodeMem
(0x00, Hi
(Code
));
}
break;
}
}
}
static void DecodeJRS
(Word Code
)
{
UNUSED
(Code
);
if (ChkArgCnt
(2, 2))
{
Integer AdrInt
;
Word cond_code
;
Boolean OK
;
tSymbolFlags Flags
;
/* only T/F allowed */
if (!decode_condition
(ArgStr
[1].
str.
p_str, &cond_code
) || !cond_code_tf
(cond_code
)) WrStrErrorPos
(ErrNum_UndefCond
, &ArgStr
[1]);
else
{
AdrInt
= EvalStrIntExpressionWithFlags
(&ArgStr
[2], Int16
, &OK
, &Flags
) - (EProgCounter
() + 2);
if (OK
)
{
if (((AdrInt
< -16) || (AdrInt
> 15)) && !mSymbolQuestionable
(Flags
)) WrError
(ErrNum_JmpDistTooBig
);
else
{
CodeLen
= 1;
BAsmCode
[0] = 0x80 | ((cond_code
- 0xde) << 5) | (AdrInt
& 0x1f);
}
}
}
}
}
static void DecodeJR
(Word Code
)
{
UNUSED
(Code
);
if (ChkArgCnt
(1, 2))
{
Word cond_code
;
Integer AdrInt
;
int Delta
;
Boolean OK
;
tSymbolFlags Flags
;
if (ArgCnt
== 1)
cond_code
= COND_CODE_TRUE
;
else if (!decode_condition
(ArgStr
[1].
str.
p_str, &cond_code
))
{
WrStrErrorPos
(ErrNum_UndefCond
, &ArgStr
[1]);
return;
}
Delta
= ((ArgCnt
== 1) || (!Hi
(cond_code
))) ? 2 : 3;
AdrInt
= EvalStrIntExpressionWithFlags
(&ArgStr
[ArgCnt
], Int16
, &OK
, &Flags
) - (EProgCounter
() + Delta
);
if (OK
)
{
if (((AdrInt
< -128) || (AdrInt
> 127)) && !mSymbolQuestionable
(Flags
)) WrError
(ErrNum_JmpDistTooBig
);
else
{
if (3 == Delta
)
BAsmCode
[CodeLen
++] = Hi
(cond_code
);
BAsmCode
[CodeLen
++] = (ArgCnt
== 1) ? 0xfc : Lo
(cond_code
);
BAsmCode
[CodeLen
++] = AdrInt
& 0xff;
}
}
}
}
static void DecodeJ
(Word Code
)
{
UNUSED
(Code
);
if (ChkArgCnt
(1, 2))
{
Word cond_code
;
if (ArgCnt
== 1)
cond_code
= COND_CODE_TRUE
;
else if (!decode_condition
(ArgStr
[1].
str.
p_str, &cond_code
))
{
WrStrErrorPos
(ErrNum_UndefCond
, &ArgStr
[1]);
return;
}
OpSize
= 1;
DecodeAdr
(&ArgStr
[ArgCnt
], MModReg16
| MModMem
| MModImm
, False
);
switch (AdrType
)
{
case ModReg16
: /* -> JP */
if (cond_code
!= COND_CODE_TRUE
) WrStrErrorPos
(ErrNum_UndefCond
, &ArgStr
[1]);
else
{
CodeLen
= 2;
BAsmCode
[0] = 0xe8 | AdrMode
;
BAsmCode
[1] = Code
;
}
break;
case ModMem
: /* -> JP */
if (cond_code
!= COND_CODE_TRUE
) WrStrErrorPos
(ErrNum_UndefCond
, &ArgStr
[1]);
else
{
CodeLen
= 2 + AdrCnt
;
CodeMem
(0x00, Code
);
}
break;
case ModImm
:
{
Word Adr
= ((Word
)(AdrVals
[1] << 8)) | AdrVals
[0];
Integer Dist
= Adr
- (EProgCounter
() + 2);
int Delta
= ((ArgCnt
== 1) || !Hi
(cond_code
)) ? 2 : 3;
/* TODO: the ArgCnt != 1 check is only necessary to get same
encoding as previous versions. Encoding 'J xxx' as 'JRS T,XXX'
if possible would actually be smarter: */
if ((Dist
>= -16) && (Dist
< 15) && (ArgCnt
!= 1) && cond_code_tf
(cond_code
)) /* JRS T/F */
{
CodeLen
= 1;
BAsmCode
[0] = 0x80 | ((cond_code
- 0xde) << 5) | (Dist
& 0x1f);
}
else if ((Dist
>= -128) && (Dist
< 127))
{
if (ArgCnt
== 1) /* JR dist */
{
BAsmCode
[CodeLen
++] = 0xfc;
BAsmCode
[CodeLen
++] = Dist
& 0xff;
}
else /* JR cc, dist */
{
if (3 == Delta
)
BAsmCode
[CodeLen
++] = Hi
(cond_code
);
BAsmCode
[CodeLen
++] = Lo
(cond_code
);
BAsmCode
[CodeLen
++] = Dist
& 0xff;
}
}
else
{
if (ArgCnt
== 1) /* JP dest */
{
BAsmCode
[CodeLen
++] = 0xfe;
BAsmCode
[CodeLen
++] = Lo
(Adr
);
BAsmCode
[CodeLen
++] = Hi
(Adr
);
}
else /* JR !cc, JP dest */
{
cond_code
^= 1;
if (3 == Delta
)
BAsmCode
[CodeLen
++] = Hi
(cond_code
);
BAsmCode
[CodeLen
++] = Lo
(cond_code
);
BAsmCode
[CodeLen
++] = 3;
BAsmCode
[CodeLen
++] = 0xfe;
BAsmCode
[CodeLen
++] = Lo
(Adr
);
BAsmCode
[CodeLen
++] = Hi
(Adr
);
}
}
break;
}
}
}
}
static void DecodeJP_CALL
(Word Code
)
{
UNUSED
(Code
);
if (ChkArgCnt
(1, 1))
{
OpSize
= 1;
DecodeAdr
(&ArgStr
[1], MModReg16
| MModMem
| MModImm
, False
);
switch (AdrType
)
{
case ModReg16
:
CodeLen
= 2;
BAsmCode
[0] = 0xe8 | AdrMode
;
BAsmCode
[1] = Code
;
break;
case ModMem
:
CodeLen
= 2 + AdrCnt
;
CodeMem
(0x00, Code
);
break;
case ModImm
:
CodeLen
= 3;
BAsmCode
[0] = Code
;
memcpy(BAsmCode
+ 1, AdrVals
, AdrCnt
);
break;
}
}
}
static void DecodeCALLV
(Word Code
)
{
UNUSED
(Code
);
if (ChkArgCnt
(1, 1))
{
Boolean OK
;
Byte HVal
= EvalStrIntExpression
(&ArgStr
[1], Int4
, &OK
);
if (OK
)
{
CodeLen
= 1;
BAsmCode
[0] = 0x70 | (HVal
& 15);
}
}
}
/*--------------------------------------------------------------------------*/
static void AddFixed
(const char *NName
, Word NCode
)
{
AddInstTable
(InstTable
, NName
, NCode
, DecodeFixed
);
}
static void AddCond
(const char *NName
, Word NCode
)
{
order_array_rsv_end
(Conditions
, CondRec
);
Conditions
[InstrZ
].
Name = NName
;
Conditions
[InstrZ
++].
Code = NCode
;
}
static void AddReg
(const char *NName
, Word NCode
)
{
AddInstTable
(InstTable
, NName
, NCode
, DecodeReg
);
}
static void AddReg16
(const char *NName
, Word NCode
)
{
AddInstTable
(InstTable
, NName
, NCode
, DecodeReg16
);
}
static void InitFields
(void)
{
InstTable
= CreateInstTable
(203);
AddInstTable
(InstTable
, "LD", 0, DecodeLD
);
AddInstTable
(InstTable
, "LDW", 0, DecodeLDW
);
AddInstTable
(InstTable
, "PUSH", 0, DecodePUSH_POP
);
AddInstTable
(InstTable
, "POP", 1, DecodePUSH_POP
);
AddInstTable
(InstTable
, "XCH", 0, DecodeXCH
);
AddInstTable
(InstTable
, "INC", 0, DecodeINC_DEC
);
AddInstTable
(InstTable
, "DEC", 8, DecodeINC_DEC
);
AddInstTable
(InstTable
, "MUL", 0, DecodeMUL
);
AddInstTable
(InstTable
, "DIV", 0, DecodeDIV
);
AddInstTable
(InstTable
, "NEG", 0, DecodeNEG
);
AddInstTable
(InstTable
, "ROLD", 0xf6, DecodeROLD_RORD
);
AddInstTable
(InstTable
, "RORD", 0xf7, DecodeROLD_RORD
);
AddInstTable
(InstTable
, "CLR", 0xfac8, DecodeTEST_CPL_SET_CLR
);
AddInstTable
(InstTable
, "TEST", 0xfc58, DecodeTEST_CPL_SET_CLR
);
AddInstTable
(InstTable
, "CPL", 0xfbe0, DecodeTEST_CPL_SET_CLR
);
AddInstTable
(InstTable
, "SET", 0xf2c0, DecodeTEST_CPL_SET_CLR
);
AddInstTable
(InstTable
, "JR", 0, DecodeJR
);
AddInstTable
(InstTable
, "JRS", 0, DecodeJRS
);
AddInstTable
(InstTable
, "JP", 0xfe, DecodeJP_CALL
);
AddInstTable
(InstTable
, "J", 0, DecodeJ
);
AddInstTable
(InstTable
, "CALL", 0xfd, DecodeJP_CALL
);
AddInstTable
(InstTable
, "CALLV", 0, DecodeCALLV
);
AddFixed
("DI" , 0xc83a);
AddFixed
("EI" , 0xc03a);
AddFixed
("RET" , 0x00fa);
AddFixed
("RETI", 0x00fb);
AddFixed
("RETN", 0xe8fb);
AddFixed
("SWI" , 0x00ff);
AddFixed
("NOP" , 0x0000);
InstrZ
= 0;
AddCond
("EQ" , 0x00d8); AddCond
("Z" , 0x00d8);
AddCond
("NE" , 0x00d9); AddCond
("NZ" , 0x00d9);
AddCond
("CS" , 0x00da); AddCond
("LT" , 0x00da);
AddCond
("CC" , 0x00db); AddCond
("GE" , 0x00db);
AddCond
("LE" , 0x00dc); AddCond
("GT" , 0x00dd);
AddCond
("M" , 0xe8d0); AddCond
("P" , 0xe8d1);
AddCond
("SLT", 0xe8d2); AddCond
("SGE", 0xe8d3);
AddCond
("SLE", 0xe8d4); AddCond
("SGT", 0xe8d5);
AddCond
("VS" , 0xe8d6); AddCond
("VC" , 0xe8d7);
AddCond
("T" , COND_CODE_TRUE
); AddCond
("F" , 0x00df);
AddCond
(NULL
, 0);
AddReg
("DAA" , 0xdae8); AddReg
("DAS" , 0xdbe8);
AddReg
("SHLC", 0xf4e8); AddReg
("SHRC", 0xf5e8);
AddReg
("ROLC", 0xf6e8); AddReg
("RORC", 0xf7e8);
AddReg
("SWAP", 0xffe8);
AddReg16
("SHLCA", 0xf0e8); AddReg16
("SHRCA", 0xf1e8);
InstrZ
= 0;
AddInstTable
(InstTable
, "ADDC", InstrZ
++, DecodeALU
);
AddInstTable
(InstTable
, "ADD" , InstrZ
++, DecodeALU
);
AddInstTable
(InstTable
, "SUBB", InstrZ
++, DecodeALU
);
AddInstTable
(InstTable
, "SUB" , InstrZ
++, DecodeALU
);
AddInstTable
(InstTable
, "AND" , InstrZ
++, DecodeALU
);
AddInstTable
(InstTable
, "XOR" , InstrZ
++, DecodeALU
);
AddInstTable
(InstTable
, "OR" , InstrZ
++, DecodeALU
);
AddInstTable
(InstTable
, "CMP" , InstrZ
++, DecodeALU
);
}
static void DeinitFields
(void)
{
DestroyInstTable
(InstTable
);
order_array_free
(Conditions
);
}
/*--------------------------------------------------------------------------*/
static void MakeCode_870C
(void)
{
CodeLen
= 0;
DontPrint
= False
;
OpSize
= -1;
/* zu ignorierendes */
if (Memo
(""))
return;
/* Pseudoanweisungen */
if (DecodeIntelPseudo
(False
))
return;
if (!LookupInstTable
(InstTable
, OpPart.
str.
p_str))
WrStrErrorPos
(ErrNum_UnknownInstruction
, &OpPart
);
}
static Boolean IsDef_870C
(void)
{
return False
;
}
static void SwitchFrom_870C
(void)
{
DeinitFields
();
}
static Boolean TrueFnc
(void)
{
return True
;
}
static void SwitchTo_870C
(void)
{
const TFamilyDescr
*FoundDescr
;
FoundDescr
= FindFamilyByName
("TLCS-870/C");
TurnWords
= False
;
SetIntConstMode
(eIntConstModeIntel
);
SetIsOccupiedFnc
= TrueFnc
;
PCSymbol
= "$";
HeaderID
= FoundDescr
->Id
;
NOPCode
= 0x00;
DivideChars
= ",";
HasAttrs
= False
;
ValidSegs
= 1 << SegCode
;
Grans
[SegCode
] = 1;
ListGrans
[SegCode
] = 1;
SegInits
[SegCode
] = 0;
SegLimits
[SegCode
] = 0xffff;
MakeCode
= MakeCode_870C
;
IsDef
= IsDef_870C
;
SwitchFrom
= SwitchFrom_870C
;
InitFields
();
}
void code870c_init
(void)
{
CPU870C
= AddCPU
("TLCS-870/C", SwitchTo_870C
);
}