504 lines
13 KiB
C
504 lines
13 KiB
C
/* code4004.c */
|
|
/*****************************************************************************/
|
|
/* AS-Portierung */
|
|
/* */
|
|
/* Codegenerator Intel 4004 */
|
|
/* */
|
|
/* Historie: 1. 2.1998 Grundsteinlegung */
|
|
/* 3. 3.1998 weitere Fixed-Befehle hinzugefuegt */
|
|
/* 28.11.1998 LookupInstTable ;-) */
|
|
/* JCN FIM... */
|
|
/* 29.11.1998 HeaderId symbolisch holen */
|
|
/* 3.12.1998 DATA schrieb 16-Bit-Ints statt 8 Bit */
|
|
/* 3. 1.1999 ChkPC-Anpassung */
|
|
/* 23. 1.1999 / / entfernt */
|
|
/* 2. 7.1999 Zus. Befehlsvarianten, andere Registersyntax */
|
|
/* 8. 9.1999 REG fehlte */
|
|
/* */
|
|
/*****************************************************************************/
|
|
|
|
#include "stdinc.h"
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
#include "bpemu.h"
|
|
#include "strutil.h"
|
|
#include "asmdef.h"
|
|
#include "asmsub.h"
|
|
#include "asmpars.h"
|
|
#include "asmitree.h"
|
|
#include "headids.h"
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Variablen */
|
|
|
|
#define FixedOrderCnt 35
|
|
#define OneRegOrderCnt 1
|
|
#define OneRRegOrderCnt 3
|
|
#define AccRegOrderCnt 4
|
|
#define Imm4OrderCnt 2
|
|
|
|
typedef struct
|
|
{
|
|
Byte Code;
|
|
} FixedOrder;
|
|
|
|
static CPUVar CPU4004/*,CPU4040*/;
|
|
|
|
static FixedOrder *FixedOrders;
|
|
static FixedOrder *OneRegOrders;
|
|
static FixedOrder *OneRRegOrders;
|
|
static FixedOrder *AccRegOrders;
|
|
static FixedOrder *Imm4Orders;
|
|
static PInstTable InstTable;
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Parser */
|
|
|
|
static Byte RegVal(char Inp)
|
|
BEGIN
|
|
if ((Inp >='0') AND (Inp <= '9')) return Inp - '0';
|
|
else if ((Inp >='A') AND (Inp <= 'F')) return Inp - 'A' + 10;
|
|
else return 0xff;
|
|
END
|
|
|
|
static Boolean DecodeReg(char *Asc, Byte *Erg)
|
|
BEGIN
|
|
char *s;
|
|
|
|
if (FindRegDef(Asc,&s)) Asc=s;
|
|
|
|
if ((strlen(Asc) != 2) OR (toupper(*Asc)!='R')) return False;
|
|
else
|
|
BEGIN
|
|
*Erg = RegVal(toupper(Asc[1]));
|
|
return (*Erg != 0xff);
|
|
END
|
|
END
|
|
|
|
static Boolean DecodeRReg(char *Asc, Byte *Erg)
|
|
BEGIN
|
|
Byte h;
|
|
char *s;
|
|
|
|
if (FindRegDef(Asc,&s)) Asc = s;
|
|
|
|
if ((strlen(Asc) != 4) OR (toupper(*Asc) != 'R') OR (toupper(Asc[2]) != 'R')) return False;
|
|
else
|
|
BEGIN
|
|
*Erg = RegVal(toupper(Asc[1]));
|
|
h = RegVal(toupper(Asc[3]));
|
|
return ((*Erg != 0xff) AND (h != 0xff) AND (h == (*Erg) + 1) AND (Odd(h)));
|
|
END
|
|
END
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Hilfsdekoder */
|
|
|
|
static void DecodeFixed(Word Index)
|
|
BEGIN
|
|
FixedOrder *Instr=FixedOrders+Index;
|
|
|
|
if (ArgCnt!=0) WrError(1110);
|
|
else
|
|
BEGIN
|
|
BAsmCode[0]=Instr->Code; CodeLen=1;
|
|
END
|
|
END
|
|
|
|
static void DecodeOneReg(Word Index)
|
|
BEGIN
|
|
FixedOrder *Instr=OneRegOrders+Index;
|
|
Byte Erg;
|
|
|
|
if (ArgCnt!=1) WrError(1110);
|
|
else if (NOT DecodeReg(ArgStr[1],&Erg)) WrXError(1445,ArgStr[1]);
|
|
else
|
|
BEGIN
|
|
BAsmCode[0]=Instr->Code+Erg; CodeLen=1;
|
|
END
|
|
END
|
|
|
|
static void DecodeOneRReg(Word Index)
|
|
BEGIN
|
|
FixedOrder *Instr=OneRRegOrders+Index;
|
|
Byte Erg;
|
|
|
|
if (ArgCnt!=1) WrError(1110);
|
|
else if (NOT DecodeRReg(ArgStr[1],&Erg)) WrXError(1445,ArgStr[1]);
|
|
else
|
|
BEGIN
|
|
BAsmCode[0]=Instr->Code+Erg; CodeLen=1;
|
|
END
|
|
END
|
|
|
|
static void DecodeAccReg(Word Index)
|
|
BEGIN
|
|
FixedOrder *Instr=AccRegOrders+Index;
|
|
Byte Erg;
|
|
|
|
if ((ArgCnt != 2) AND (ArgCnt != 1)) WrError(1110);
|
|
else if ((ArgCnt == 2) AND (strcasecmp(ArgStr[1], "A") != 0)) WrError(1350);
|
|
else if (NOT DecodeReg(ArgStr[ArgCnt], &Erg)) WrXError(1445, ArgStr[ArgCnt]);
|
|
else
|
|
BEGIN
|
|
BAsmCode[0] = Instr->Code + Erg; CodeLen = 1;
|
|
END
|
|
END
|
|
|
|
static void DecodeImm4(Word Index)
|
|
BEGIN
|
|
FixedOrder *Instr=Imm4Orders+Index;
|
|
Boolean OK;
|
|
|
|
if (ArgCnt!=1) WrError(1110);
|
|
else
|
|
BEGIN
|
|
BAsmCode[0]=EvalIntExpression(ArgStr[1],UInt4,&OK);
|
|
if (OK)
|
|
BEGIN
|
|
BAsmCode[0]+=Instr->Code; CodeLen=1;
|
|
END
|
|
END
|
|
END
|
|
|
|
static void DecodeFullJmp(Word Index)
|
|
BEGIN
|
|
Word Adr;
|
|
Boolean OK;
|
|
|
|
if (ArgCnt!=1) WrError(1110);
|
|
else
|
|
BEGIN
|
|
Adr=EvalIntExpression(ArgStr[1],UInt12,&OK);
|
|
if (OK)
|
|
BEGIN
|
|
BAsmCode[0]=0x40+(Index << 4)+Hi(Adr);
|
|
BAsmCode[1]=Lo(Adr);
|
|
CodeLen=2;
|
|
END
|
|
END
|
|
END
|
|
|
|
static void DecodeISZ(Word Index)
|
|
BEGIN
|
|
Word Adr;
|
|
Boolean OK;
|
|
Byte Erg;
|
|
|
|
if (ArgCnt!=2) WrError(1110);
|
|
else if (NOT DecodeReg(ArgStr[1],&Erg)) WrXError(1445,ArgStr[1]);
|
|
else
|
|
BEGIN
|
|
Adr=EvalIntExpression(ArgStr[2],UInt12,&OK);
|
|
if (OK)
|
|
if ((NOT SymbolQuestionable) AND (Hi(EProgCounter()+1)!=Hi(Adr))) WrError(1910);
|
|
else
|
|
BEGIN
|
|
BAsmCode[0]=0x70+Erg; BAsmCode[1]=Lo(Adr); CodeLen=2;
|
|
END
|
|
END
|
|
END
|
|
|
|
static void DecodeJCN(Word Index)
|
|
BEGIN
|
|
Word AdrInt;
|
|
Boolean OK;
|
|
|
|
if (ArgCnt != 2) WrError(1110);
|
|
else
|
|
BEGIN
|
|
BAsmCode[0] = 0x10;
|
|
if (strcasecmp(ArgStr[1], "Z") == 0) BAsmCode[0] += 4;
|
|
else if (strcasecmp(ArgStr[1], "NZ") == 0) BAsmCode[0] += 12;
|
|
else if (strcasecmp(ArgStr[1], "C") == 0) BAsmCode[0] += 2;
|
|
else if (strcasecmp(ArgStr[1], "NC") == 0) BAsmCode[0] += 10;
|
|
else if (strcasecmp(ArgStr[1], "T") == 0) BAsmCode[0] += 1;
|
|
else if (strcasecmp(ArgStr[1], "NT") == 0) BAsmCode[0] += 9;
|
|
if (BAsmCode[0] == 0x10) WrXError(1360, ArgStr[1]);
|
|
else
|
|
BEGIN
|
|
AdrInt = EvalIntExpression(ArgStr[2], UInt12, &OK);
|
|
if (OK)
|
|
if ((NOT SymbolQuestionable) AND (Hi(EProgCounter() + 2) != Hi(AdrInt))) WrError(1370);
|
|
else
|
|
BEGIN
|
|
BAsmCode[1] = Lo(AdrInt);
|
|
CodeLen = 2;
|
|
END
|
|
END
|
|
END
|
|
END
|
|
|
|
static void DecodeFIM(Word Index)
|
|
BEGIN
|
|
Boolean OK;
|
|
|
|
if (ArgCnt != 2) WrError(1110);
|
|
else if (NOT DecodeRReg(ArgStr[1], BAsmCode)) WrXError(1445, ArgStr[1]);
|
|
else
|
|
BEGIN
|
|
BAsmCode[1] = EvalIntExpression(ArgStr[2], Int8, &OK);
|
|
if (OK)
|
|
BEGIN
|
|
BAsmCode[0] |= 0x20;
|
|
CodeLen = 2;
|
|
END
|
|
END
|
|
END
|
|
|
|
static Boolean DecodePseudo(void)
|
|
BEGIN
|
|
Boolean ValOK;
|
|
Word Size;
|
|
int z, z2;
|
|
TempResult t;
|
|
char Ch;
|
|
|
|
if (Memo("DS"))
|
|
BEGIN
|
|
if (ArgCnt!=1) WrError(1110);
|
|
else
|
|
BEGIN
|
|
FirstPassUnknown=False;
|
|
Size=EvalIntExpression(ArgStr[1],Int16,&ValOK);
|
|
if (FirstPassUnknown) WrError(1820);
|
|
if ((ValOK) AND (NOT FirstPassUnknown))
|
|
BEGIN
|
|
DontPrint=True;
|
|
CodeLen=Size;
|
|
BookKeeping();
|
|
END
|
|
END
|
|
return True;
|
|
END
|
|
|
|
if (Memo("DATA"))
|
|
BEGIN
|
|
if (ArgCnt==0) WrError(1110);
|
|
else
|
|
BEGIN
|
|
ValOK=True;
|
|
for (z=1; z<=ArgCnt; z++)
|
|
if (ValOK)
|
|
BEGIN
|
|
FirstPassUnknown=False;
|
|
EvalExpression(ArgStr[z],&t);
|
|
if ((t.Typ==TempInt) AND (FirstPassUnknown))
|
|
if (ActPC==SegData) t.Contents.Int&=7; else t.Contents.Int&=127;
|
|
switch (t.Typ)
|
|
BEGIN
|
|
case TempInt:
|
|
if (ActPC==SegCode)
|
|
BEGIN
|
|
if (NOT RangeCheck(t.Contents.Int,Int8))
|
|
BEGIN
|
|
WrError(1320); ValOK=False;
|
|
END
|
|
else BAsmCode[CodeLen++]=t.Contents.Int & 0xff;
|
|
END
|
|
else
|
|
BEGIN
|
|
if (NOT RangeCheck(t.Contents.Int,Int4))
|
|
BEGIN
|
|
WrError(1320); ValOK=False;
|
|
END
|
|
else BAsmCode[CodeLen++]=t.Contents.Int & 0x0f;
|
|
END
|
|
break;
|
|
case TempFloat:
|
|
WrError(1135); ValOK=False;
|
|
break;
|
|
case TempString:
|
|
for (z2=0; z2<strlen(t.Contents.Ascii); z2++)
|
|
BEGIN
|
|
Ch=CharTransTable[((usint) t.Contents.Ascii[z2])&0xff];
|
|
if (ActPC==SegCode)
|
|
BAsmCode[CodeLen++]=Ch;
|
|
else
|
|
BEGIN
|
|
BAsmCode[CodeLen++]=Ch >> 4;
|
|
BAsmCode[CodeLen++]=Ch & 15;
|
|
END
|
|
END
|
|
break;
|
|
default:
|
|
ValOK=False;
|
|
END
|
|
END
|
|
if (NOT ValOK) CodeLen=0;
|
|
END
|
|
return True;
|
|
END
|
|
|
|
if (Memo("REG"))
|
|
BEGIN
|
|
if (ArgCnt!=1) WrError(1110);
|
|
else AddRegDef(LabPart,ArgStr[1]);
|
|
return True;
|
|
END
|
|
|
|
return False;
|
|
END
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Codetabellenverwaltung */
|
|
|
|
static int InstrZ;
|
|
|
|
static void AddFixed(char *NName, Byte NCode)
|
|
BEGIN
|
|
if (InstrZ>=FixedOrderCnt) exit(255);
|
|
FixedOrders[InstrZ].Code=NCode;
|
|
AddInstTable(InstTable,NName,InstrZ++,DecodeFixed);
|
|
END
|
|
|
|
static void AddOneReg(char *NName, Byte NCode)
|
|
BEGIN
|
|
if (InstrZ>=OneRegOrderCnt) exit(255);
|
|
OneRegOrders[InstrZ].Code=NCode;
|
|
AddInstTable(InstTable,NName,InstrZ++,DecodeOneReg);
|
|
END
|
|
|
|
static void AddOneRReg(char *NName, Byte NCode)
|
|
BEGIN
|
|
if (InstrZ>=OneRRegOrderCnt) exit(255);
|
|
OneRRegOrders[InstrZ].Code=NCode;
|
|
AddInstTable(InstTable,NName,InstrZ++,DecodeOneRReg);
|
|
END
|
|
|
|
static void AddAccReg(char *NName, Byte NCode)
|
|
BEGIN
|
|
if (InstrZ>=AccRegOrderCnt) exit(255);
|
|
AccRegOrders[InstrZ].Code=NCode;
|
|
AddInstTable(InstTable,NName,InstrZ++,DecodeAccReg);
|
|
END
|
|
|
|
static void AddImm4(char *NName, Byte NCode)
|
|
BEGIN
|
|
if (InstrZ>=Imm4OrderCnt) exit(255);
|
|
Imm4Orders[InstrZ].Code=NCode;
|
|
AddInstTable(InstTable,NName,InstrZ++,DecodeImm4);
|
|
END
|
|
|
|
static void InitFields(void)
|
|
BEGIN
|
|
InstTable=CreateInstTable(101);
|
|
|
|
InstrZ=0; FixedOrders=(FixedOrder *) malloc(sizeof(FixedOrder)*FixedOrderCnt);
|
|
AddFixed("NOP" ,0x00); AddFixed("WRM" ,0xe0);
|
|
AddFixed("WMP" ,0xe1); AddFixed("WRR" ,0xe2);
|
|
AddFixed("WPM" ,0xe3); AddFixed("WR0" ,0xe4);
|
|
AddFixed("WR1" ,0xe5); AddFixed("WR2" ,0xe6);
|
|
AddFixed("WR3" ,0xe7); AddFixed("SBM" ,0xe8);
|
|
AddFixed("RDM" ,0xe9); AddFixed("RDR" ,0xea);
|
|
AddFixed("ADM" ,0xeb); AddFixed("RD0" ,0xec);
|
|
AddFixed("RD1" ,0xed); AddFixed("RD2" ,0xee);
|
|
AddFixed("RD3" ,0xef); AddFixed("CLB" ,0xf0);
|
|
AddFixed("CLC" ,0xf1); AddFixed("IAC" ,0xf2);
|
|
AddFixed("CMC" ,0xf3); AddFixed("CMA" ,0xf4);
|
|
AddFixed("RAL" ,0xf5); AddFixed("RAR" ,0xf6);
|
|
AddFixed("TCC" ,0xf7); AddFixed("DAC" ,0xf8);
|
|
AddFixed("TCS" ,0xf9); AddFixed("STC" ,0xfa);
|
|
AddFixed("DAA" ,0xfb); AddFixed("KBP" ,0xfc);
|
|
AddFixed("DCL" ,0xfd); AddFixed("AD0" ,0xec);
|
|
AddFixed("AD1" ,0xed); AddFixed("AD2" ,0xee);
|
|
AddFixed("AD3" ,0xef);
|
|
|
|
InstrZ=0; OneRegOrders=(FixedOrder *) malloc(sizeof(FixedOrder)*OneRegOrderCnt);
|
|
AddOneReg("INC" ,0x60);
|
|
|
|
InstrZ=0; OneRRegOrders=(FixedOrder *) malloc(sizeof(FixedOrder)*OneRRegOrderCnt);
|
|
AddOneRReg("SRC" ,0x21);
|
|
AddOneRReg("FIN" ,0x30);
|
|
AddOneRReg("JIN" ,0x31);
|
|
|
|
InstrZ=0; AccRegOrders=(FixedOrder *) malloc(sizeof(FixedOrder)*AccRegOrderCnt);
|
|
AddAccReg("ADD" ,0x80); AddAccReg("SUB" ,0x90);
|
|
AddAccReg("LD" ,0xa0); AddAccReg("XCH" ,0xb0);
|
|
|
|
InstrZ=0; Imm4Orders=(FixedOrder *) malloc(sizeof(FixedOrder)*Imm4OrderCnt);
|
|
AddImm4("BBL" ,0xc0); AddImm4("LDM" ,0xd0);
|
|
|
|
AddInstTable(InstTable,"JCN", 0, DecodeJCN);
|
|
AddInstTable(InstTable,"JCM", 0, DecodeJCN);
|
|
AddInstTable(InstTable,"JUN", 0, DecodeFullJmp);
|
|
AddInstTable(InstTable,"JMS", 1, DecodeFullJmp);
|
|
AddInstTable(InstTable,"ISZ", 0, DecodeISZ);
|
|
AddInstTable(InstTable,"FIM", 0, DecodeFIM);
|
|
END
|
|
|
|
static void DeinitFields(void)
|
|
BEGIN
|
|
DestroyInstTable(InstTable);
|
|
free(FixedOrders);
|
|
free(OneRegOrders);
|
|
free(OneRRegOrders);
|
|
free(AccRegOrders);
|
|
free(Imm4Orders);
|
|
END
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Callbacks */
|
|
|
|
static void MakeCode_4004(void)
|
|
BEGIN
|
|
CodeLen=0; DontPrint=False;
|
|
|
|
/* zu ignorierendes */
|
|
|
|
if (Memo("")) return;
|
|
|
|
/* Pseudoanweisungen */
|
|
|
|
if (DecodePseudo()) return;
|
|
|
|
/* der Rest */
|
|
|
|
if (NOT LookupInstTable(InstTable, OpPart)) WrXError(1200, OpPart);
|
|
END
|
|
|
|
static Boolean IsDef_4004(void)
|
|
BEGIN
|
|
return Memo("REG");
|
|
END
|
|
|
|
static void SwitchFrom_4004(void)
|
|
BEGIN
|
|
DeinitFields();
|
|
END
|
|
|
|
static void SwitchTo_4004(void)
|
|
BEGIN
|
|
PFamilyDescr FoundDescr;
|
|
|
|
FoundDescr=FindFamilyByName("4004/4040");
|
|
|
|
TurnWords=False; ConstMode=ConstModeIntel; SetIsOccupied=False;
|
|
|
|
PCSymbol="$"; HeaderID=FoundDescr->Id; NOPCode=0x00;
|
|
DivideChars=","; HasAttrs=False;
|
|
|
|
ValidSegs=(1<<SegCode)|(1<<SegData);
|
|
Grans[SegCode ]=1; ListGrans[SegCode ]=1; SegInits[SegCode ]=0;
|
|
SegLimits[SegCode] = 0xfff;
|
|
Grans[SegData ]=1; ListGrans[SegData ]=1; SegInits[SegData ]=0;
|
|
SegLimits[SegData] = 0xff;
|
|
|
|
MakeCode=MakeCode_4004; IsDef=IsDef_4004;
|
|
SwitchFrom=SwitchFrom_4004;
|
|
|
|
InitFields();
|
|
END
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Initialisierung */
|
|
|
|
void code4004_init(void)
|
|
BEGIN
|
|
CPU4004=AddCPU("4004",SwitchTo_4004);
|
|
#if 0
|
|
CPU4040=AddCPU("4040",SwitchTo_4004);
|
|
#endif
|
|
END
|