/* codef8.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Code Generator Fairchild F8 */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <string.h>
#include <ctype.h>
#include "bpemu.h"
#include "strutil.h"
#include "chunks.h"
#include "headids.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmitree.h"
#include "codepseudo.h"
#include "intpseudo.h"
#include "codevars.h"
#include "errmsg.h"
#include "codef8.h"
#define Flg_IO (1 << 8)
#define Flg_Code (1 << 9)
#define Flg_CMOS (1 << 10)
static IntType CodeIntType;
static Word MomCPUFlags;
/*---------------------------------------------------------------------------*/
static Boolean DecodeReg(const tStrComp *pArg, Byte *pResult)
{
/* KU/KL/QU/QL are addressed via dedicated LR instructions! */
static const char RegNames[][3] = { "J", "HU", "HL", "S", "I", "D", "" };
int z;
Boolean OK;
for (z = 0; *RegNames[z]; z++)
if (!as_strcasecmp(RegNames[z], pArg->str.p_str))
{
*pResult = z + 9;
return True;
}
*pResult = EvalStrIntExpression(pArg, UInt4, &OK);
return OK;
}
static Boolean DecodeAux(const char *pArg, Byte *pResult)
{
return False;
*pResult = 0;
*pResult |= 2;
return False;
*pResult |= 1;
return False;
return True;
}
static Boolean ArgPair(const char *pArg1, const char *pArg2)
{
return !as_strcasecmp(ArgStr[1].str.p_str, pArg1) && !as_strcasecmp(ArgStr[2].str.p_str, pArg2);
}
/*---------------------------------------------------------------------------*/
static void DecodeFixed(Word Code)
{
if (!ChkArgCnt(0, 0));
else if ((Code & Flg_CMOS) && (!(MomCPUFlags & Flg_CMOS))) WrError(ErrNum_InstructionNotSupported);
else
{
BAsmCode[0] = Code;
CodeLen = 1;
}
}
static void DecodeImm8(Word Code)
{
Boolean IsIO = !!(Code & Flg_IO);
if (ChkArgCnt(1, 1))
{
tEvalResult EvalResult;
BAsmCode[1] = EvalStrIntExpressionWithResult(&ArgStr[1], IsIO ? UInt8 : Int8, &EvalResult);
if (EvalResult.OK)
{
if (IsIO)
{
ChkSpace(SegIO, EvalResult.AddrSpaceMask);
if (BAsmCode[1] < 4)
WrStrErrorPos(ErrNum_NeedShortIO, &ArgStr[1]);
}
BAsmCode[0] = Lo(Code);
CodeLen = 2;
}
}
}
static void DecodeImm4(Word Code)
{
Boolean IsIO = !!(Code & Flg_IO);
if (ChkArgCnt(1, 1))
{
tEvalResult EvalResult;
BAsmCode[0] = Lo(Code) | EvalStrIntExpressionWithResult(&ArgStr[1], UInt4, &EvalResult);
if (EvalResult.OK)
{
CodeLen = 1;
if (IsIO)
ChkSpace(SegIO, EvalResult.AddrSpaceMask);
}
}
}
static void DecodeImm3(Word Code)
{
if (ChkArgCnt(1, 1))
{
Boolean OK;
BAsmCode[0] = Code | EvalStrIntExpression(&ArgStr[1], UInt3, &OK);
if (OK)
CodeLen = 1;
}
}
static void DecodeImm16(Word Code)
{
Boolean IsCode = !!(Code & Flg_Code);
if (ChkArgCnt(1, 1))
{
tEvalResult EvalResult;
Word Arg = EvalStrIntExpressionWithResult(&ArgStr[1], IsCode ? CodeIntType : Int16, &EvalResult);
if (EvalResult.OK)
{
BAsmCode[0] = Code;
BAsmCode[1] = Hi(Arg);
BAsmCode[2] = Lo(Arg);
CodeLen = 3;
if (IsCode)
ChkSpace(SegCode, EvalResult.AddrSpaceMask);
}
}
}
static void DecodeOneReg(Word Code)
{
if (ChkArgCnt(1, 1) && DecodeReg(&ArgStr[1], &BAsmCode[0]))
{
BAsmCode[0] |= Code;
CodeLen = 1;
}
}
static void DecodeBranchCore(const tStrComp *pArg, Word Code)
{
Boolean OK;
LongInt Dist;
tSymbolFlags Flags;
Dist = EvalStrIntExpressionWithFlags(pArg, UInt16, &OK, &Flags) - (EProgCounter() + 1);
if (OK)
{
if (!mSymbolQuestionable(Flags) && ((Dist < -128) || (Dist > 127))) WrStrErrorPos(ErrNum_JmpDistTooBig, pArg);
else
{
BAsmCode[0] = Code;
BAsmCode[1] = Dist & 0xff;
CodeLen = 2;
}
}
}
static void DecodeBranch(Word Code)
{
if (ChkArgCnt(1, 1))
DecodeBranchCore(&ArgStr[1], Code);
}
static void DecodeGenBranch(Word Code)
{
if (ChkArgCnt(2, 2))
{
Boolean OK;
/* BT does not include OVF flag in its condition mask, only values 0..7! */
Code |= EvalStrIntExpression(&ArgStr[1], (Code == 0x90) ? UInt4 : UInt3, &OK);
if (OK)
DecodeBranchCore(&ArgStr[2], Code);
}
}
static void DecodeLR(Word Code)
{
UNUSED(Code);
if (!ChkArgCnt(2,2))
return;
if (!as_strcasecmp(ArgStr[1].str.p_str, "A"))
{
if (DecodeAux(ArgStr[2].str.p_str, &BAsmCode[0]))
{
CodeLen = 1;
}
else if (!as_strcasecmp(ArgStr[2].str.p_str, "IS"))
{
BAsmCode[0] = 0x0a;
CodeLen = 1;
}
else if (DecodeReg(&ArgStr[2], &BAsmCode[0]))
{
BAsmCode[0] |= 0x40;
CodeLen = 1;
}
}
else if (!as_strcasecmp(ArgStr[2].str.p_str, "A"))
{
if (DecodeAux(ArgStr[1].str.p_str, &BAsmCode[0]))
{
BAsmCode[0] |= 4;
CodeLen = 1;
}
else if (!as_strcasecmp(ArgStr[1].str.p_str, "IS"))
BAsmCode[CodeLen++] = 0x0b;
else if (DecodeReg(&ArgStr[1], &BAsmCode[0]))
{
BAsmCode[0] |= 0x50;
CodeLen = 1;
}
}
else if (ArgPair("DC", "Q"))
BAsmCode[CodeLen++] = 0x0f;
else if (ArgPair("DC", "H"))
BAsmCode[CodeLen++] = 0x10;
else if (ArgPair("Q", "DC"))
BAsmCode[CodeLen++] = 0x0e;
else if (ArgPair("H", "DC"))
BAsmCode[CodeLen++] = 0x11;
else if (ArgPair("K", "P"))
BAsmCode[CodeLen++] = 0x08;
else if (ArgPair("P", "K"))
BAsmCode[CodeLen++] = 0x09;
else if (ArgPair("P0", "Q"))
BAsmCode[CodeLen++] = 0x0d;
else if (ArgPair("J", "W"))
BAsmCode[CodeLen++] = 0x1e;
else if (ArgPair("W", "J"))
BAsmCode[CodeLen++] = 0x1d;
else
WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[1]);
}
static void DecodeShift(Word Code)
{
if (!ArgCnt)
BAsmCode[CodeLen++] = Code;
else if (ChkArgCnt(1,1))
{
Boolean OK;
Byte Cnt;
tSymbolFlags Flags;
Cnt = EvalStrIntExpressionWithFlags(&ArgStr[1], UInt3, &OK, &Flags);
if (OK)
{
if (Cnt == 4)
BAsmCode[CodeLen++] = Code + 2;
else if (mFirstPassUnknown(Flags) || (Cnt == 1))
BAsmCode[CodeLen++] = Code;
else
WrStrErrorPos(ErrNum_OverRange, &ArgStr[1]);
}
}
}
static void DecodePORT(Word Code)
{
UNUSED(Code);
CodeEquate(SegIO, 0, 0xff);
}
/*---------------------------------------------------------------------------*/
static void AddFixed(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeFixed);
}
static void AddImm8(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeImm8);
}
static void AddImm4(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeImm4);
}
static void AddImm3(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeImm3);
}
static void AddImm16(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeImm16);
}
static void AddOneReg(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeOneReg);
}
static void AddBranch(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeBranch);
}
static void AddGenBranch(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeGenBranch);
}
static void AddShift(const char *NName, Word NCode)
{
AddInstTable(InstTable, NName, NCode, DecodeShift);
}
static void InitFields(void)
{
InstTable = CreateInstTable(101);
AddFixed("ADC", 0x8e);
AddFixed("AM" , 0x88);
AddFixed("AMD", 0x89);
AddFixed("CLR", 0x70);
AddFixed("CM" , 0x8d);
AddFixed("COM", 0x18);
AddFixed("DI" , 0x1a);
AddFixed("EI" , 0x1b);
AddFixed("HET", Flg_CMOS | 0x2e); /* guess */
AddFixed("HAL", Flg_CMOS | 0x2f); /* guess */
AddFixed("INC", 0x1f);
AddFixed("LM" , 0x16);
AddFixed("LNK", 0x19);
AddFixed("NM" , 0x8a);
AddFixed("NOP", NOPCode);
AddFixed("OM" , 0x8b);
AddFixed("PK" , 0x0c);
AddFixed("POP", 0x1c);
AddFixed("ST" , 0x17);
AddFixed("XDC", 0x2c);
AddFixed("XM" , 0x8c);
AddImm8("AI" , 0x24);
AddImm8("CI" , 0x25);
AddImm8("LI" , 0x20);
AddImm8("NI" , 0x21);
AddImm8("IN" , Flg_IO | 0x26);
AddImm8("OI" , 0x22);
AddImm8("OUT", Flg_IO | 0x27);
AddImm8("XI" , 0x23);
AddImm4("LIS" , 0x70);
AddImm4("INS" , Flg_IO | 0xa0);
AddImm4("OUTS", Flg_IO | 0xb0);
AddImm3("LISL", 0x68);
AddImm3("LISU", 0x60);
AddImm16("DCI", 0x2a);
AddImm16("JMP", Flg_Code | 0x29);
AddImm16("PI" , Flg_Code | 0x28);
AddOneReg("AS" , 0xc0);
AddOneReg("ASD" , 0xd0);
AddOneReg("DS" , 0x30);
AddOneReg("NS" , 0xf0);
AddOneReg("XS" , 0xe0);
AddBranch("BC" , 0x82);
AddBranch("BM" , 0x91);
AddBranch("BNC" , 0x92);
AddBranch("BNO" , 0x98);
AddBranch("BNZ" , 0x94);
AddBranch("BP" , 0x81);
AddBranch("BR" , 0x90);
AddBranch("BR7" , 0x8f);
AddBranch("BZ" , 0x84);
AddGenBranch("BF", 0x90);
AddGenBranch("BT", 0x80);
AddShift("SL", 0x13);
AddShift("SR", 0x12);
AddInstTable(InstTable, "LR", 0, DecodeLR);
AddInstTable(InstTable, "PORT", 0, DecodePORT);
}
static void DeinitFields(void)
{
DestroyInstTable(InstTable);
}
/*---------------------------------------------------------------------------*/
static void MakeCode_F8(void)
{
CodeLen = 0; DontPrint = False;
/* zu ignorierendes */
if (Memo("")) return;
/* Pseudoanweisungen - DS is a machine instruction on F8 */
if (!Memo("DS"))
{
if (DecodeIntelPseudo(True)) return;
}
if (!LookupInstTable(InstTable, OpPart.str.p_str))
WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
}
static void SwitchFrom_F8(void)
{
DeinitFields();
}
static Boolean IsDef_F8(void)
{
return Memo("PORT");
}
static void SwitchTo_F8(void)
{
const TFamilyDescr *Descr;
TurnWords = False;
SetIntConstMode(eIntConstModeIntel);
Descr = FindFamilyByName("F8");
PCSymbol = "$";
HeaderID = Descr->Id;
NOPCode = 0x2b;
DivideChars = ",";
HasAttrs = False;
ValidSegs = (1 << SegCode) | (1 << SegData) | (1 << SegIO);
Grans[SegCode] = 1; ListGrans[SegCode] = 1; SegLimits[SegCode] = IntTypeDefs[CodeIntType].Max;
Grans[SegData] = 1; ListGrans[SegData] = 1; SegLimits[SegData] = 0x3f;
Grans[SegIO ] = 1; ListGrans[SegIO ] = 1; SegLimits[SegIO ] = 0xff;
MakeCode = MakeCode_F8;
SwitchFrom = SwitchFrom_F8;
IsDef = IsDef_F8;
InitFields();
}
static void SwitchTo_F8_12(void)
{
CodeIntType = UInt12;
MomCPUFlags = 0;
SwitchTo_F8();
}
static void SwitchTo_F8_16(void)
{
CodeIntType = UInt16;
MomCPUFlags = 0;
SwitchTo_F8();
}
static void SwitchTo_F8_12_CMOS(void)
{
CodeIntType = UInt12;
MomCPUFlags = Flg_CMOS;
SwitchTo_F8();
}
void codef8_init(void)
{
(void)AddCPU("F3850" , SwitchTo_F8_16);
(void)AddCPU("MK3850" , SwitchTo_F8_16);
(void)AddCPU("MK3870" , SwitchTo_F8_12);
(void)AddCPU("MK3870/10", SwitchTo_F8_12);
(void)AddCPU("MK3870/12", SwitchTo_F8_12);
(void)AddCPU("MK3870/20", SwitchTo_F8_12); /* == MK3870 */
(void)AddCPU("MK3870/22", SwitchTo_F8_12); /* == MK3876 */
(void)AddCPU("MK3870/30", SwitchTo_F8_12);
(void)AddCPU("MK3870/32", SwitchTo_F8_12);
(void)AddCPU("MK3870/40", SwitchTo_F8_12);
(void)AddCPU("MK3870/42", SwitchTo_F8_12); /* == MK3872 */
(void)AddCPU("MK3872" , SwitchTo_F8_12);
(void)AddCPU("MK3873" , SwitchTo_F8_12);
(void)AddCPU("MK3873/10", SwitchTo_F8_12);
(void)AddCPU("MK3873/12", SwitchTo_F8_12);
(void)AddCPU("MK3873/20", SwitchTo_F8_12); /* == MK3873 */
(void)AddCPU("MK3873/22", SwitchTo_F8_12);
(void)AddCPU("MK3874" , SwitchTo_F8_12);
(void)AddCPU("MK3875" , SwitchTo_F8_12);
(void)AddCPU("MK3875/22", SwitchTo_F8_12); /* == MK3876 with standby */
(void)AddCPU("MK3875/42", SwitchTo_F8_12); /* == MK3872 with standby */
(void)AddCPU("MK3876" , SwitchTo_F8_12);
(void)AddCPU("MK38P70/02",SwitchTo_F8_12); /* == MK3874, MK974xx */
(void)AddCPU("MK38CP70/02", SwitchTo_F8_12_CMOS);
(void)AddCPU("MK38C70" , SwitchTo_F8_12_CMOS);
(void)AddCPU("MK38C70/10",SwitchTo_F8_12);
(void)AddCPU("MK38C70/20",SwitchTo_F8_12); /* == MK38C70 */
(void)AddCPU("MK97400" , SwitchTo_F8_12);
(void)AddCPU("MK97410" , SwitchTo_F8_12);
(void)AddCPU("MK97500" , SwitchTo_F8_16);
(void)AddCPU("MK97501" , SwitchTo_F8_16);
(void)AddCPU("MK97503" , SwitchTo_F8_16);
}