Compare commits
12 Commits
40a20ab973
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| a5a3e40ffe | |||
| 8eed63fa52 | |||
|
|
d20d99b32b | ||
|
|
8fcee1b552 | ||
|
|
c31565cd5b | ||
|
|
a545b4fc3e | ||
|
|
69c17a502b | ||
|
|
de78048319 | ||
|
|
321e47f0f3 | ||
|
|
6027487c30 | ||
|
|
00a1f1d447 | ||
|
|
c9b885b144 |
@@ -216,7 +216,7 @@ SMC AdaptUnderlineWidth, { NOP }
|
||||
|
||||
<sect1>Accessing arguments<p>
|
||||
|
||||
These marcos are determined to get, set and change arguments of instructions:
|
||||
These macros are determined to get, set and change arguments of instructions:
|
||||
|
||||
<descrip>
|
||||
|
||||
@@ -458,7 +458,7 @@ SMC GetData, { LDA SMC_AbsAdr }
|
||||
|
||||
<sect1>Operational macros<p>
|
||||
|
||||
These marcos are determined to let read/modify/write opcodes work on parts of
|
||||
These macros are determined to let read/modify/write opcodes work on parts of
|
||||
SMC instructions.
|
||||
|
||||
<descrip>
|
||||
@@ -504,7 +504,7 @@ SMC GetPageData, { LDA SourceData, X }
|
||||
|
||||
<sect1>Scope macros<p>
|
||||
|
||||
These marcos are determined to export and import SMC labels out of the current
|
||||
These macros are determined to export and import SMC labels out of the current
|
||||
file scope. Please handle with care! If you cannot abstain from leaving the
|
||||
file scope, you should at least document the exported SMC lines very well. On
|
||||
import side no checking is available if the SMC line is correct accessed (e.g.
|
||||
|
||||
@@ -109,16 +109,14 @@ newline:
|
||||
: jmp VTABZ
|
||||
|
||||
putchar:
|
||||
.ifdef __APPLE2ENH__
|
||||
ldy INVFLG
|
||||
cpy #$FF ; Normal character display mode?
|
||||
beq putchardirect
|
||||
cmp #$E0 ; Lowercase?
|
||||
bcc mask
|
||||
and #$7F ; Inverse lowercase
|
||||
bra putchardirect
|
||||
and INVFLG ; Apply normal, inverse, flash
|
||||
bcc putchardirect ; Not lowercase, no special handling
|
||||
.ifndef __APPLE2ENH__
|
||||
bit machinetype
|
||||
bpl putchardirect ; Mask normally for ][/+ ; done
|
||||
.endif
|
||||
mask: and INVFLG ; Apply normal, inverse, flash
|
||||
ora #$40 ; Restore lowercase bit for //e and up
|
||||
|
||||
putchardirect:
|
||||
tax
|
||||
|
||||
@@ -291,6 +291,23 @@ static ExprNode* BankByte (ExprNode* Operand)
|
||||
return Expr;
|
||||
}
|
||||
|
||||
static ExprNode* TopByte (ExprNode* Operand)
|
||||
/* Return the top byte of the given expression */
|
||||
{
|
||||
ExprNode* Expr;
|
||||
long Val;
|
||||
|
||||
/* Special handling for const expressions */
|
||||
if (IsEasyConst (Operand, &Val)) {
|
||||
FreeExpr (Operand);
|
||||
Expr = GenLiteralExpr ((Val >> 24) & 0xFF);
|
||||
} else {
|
||||
/* Extract byte #2 */
|
||||
Expr = NewExprNode (EXPR_BYTE3);
|
||||
Expr->Left = Operand;
|
||||
}
|
||||
return Expr;
|
||||
}
|
||||
|
||||
|
||||
static ExprNode* LoWord (ExprNode* Operand)
|
||||
@@ -579,6 +596,11 @@ static ExprNode* FuncLoWord (void)
|
||||
}
|
||||
|
||||
|
||||
ExprNode* FuncTopByte (void)
|
||||
/* Handle the .TOPBYTE builtin function */
|
||||
{
|
||||
return TopByte (Expression ());
|
||||
}
|
||||
|
||||
static ExprNode* DoMatch (enum TC EqualityLevel)
|
||||
/* Handle the .MATCH and .XMATCH builtin functions */
|
||||
@@ -1287,6 +1309,10 @@ static ExprNode* Factor (void)
|
||||
NextTok ();
|
||||
break;
|
||||
|
||||
case TOK_TOPBYTE:
|
||||
N = Function (FuncTopByte);
|
||||
break;
|
||||
|
||||
case TOK_VERSION:
|
||||
N = GenLiteralExpr (GetVersionAsNumber ());
|
||||
NextTok ();
|
||||
|
||||
217
src/ca65/instr.c
217
src/ca65/instr.c
@@ -151,6 +151,9 @@ static void PutRTS (const InsDesc* Ins attribute ((unused)));
|
||||
static void PutAll (const InsDesc* Ins);
|
||||
/* Handle all other instructions */
|
||||
|
||||
static void PutAll32 (const InsDesc* Ins);
|
||||
/* Handle all other instructions for the 65C032 */
|
||||
|
||||
static void Put4510 (const InsDesc* Ins);
|
||||
/* Handle instructions of 4510 not matching any EATab */
|
||||
|
||||
@@ -729,6 +732,119 @@ static const struct {
|
||||
}
|
||||
};
|
||||
|
||||
/* Instruction table for the 65C032 (WDC CMOS with 32 bit addressing) */
|
||||
static const struct {
|
||||
unsigned Count;
|
||||
InsDesc Ins[100];
|
||||
} InsTab65C032 = {
|
||||
/* CAUTION: table must be sorted for bsearch */
|
||||
sizeof (InsTab65C032.Ins) / sizeof (InsTab65C032.Ins[0]),
|
||||
{
|
||||
/* BEGIN SORTED.SH */
|
||||
{ "ADC", 0x080A66C, 0x60, 0, PutAll32 },
|
||||
{ "AND", 0x080A66C, 0x20, 0, PutAll32 },
|
||||
{ "ASL", 0x000006e, 0x02, 1, PutAll32 },
|
||||
{ "BBR0", 0x0000000, 0x0F, 0, PutBitBranch },
|
||||
{ "BBR1", 0x0000000, 0x1F, 0, PutBitBranch },
|
||||
{ "BBR2", 0x0000000, 0x2F, 0, PutBitBranch },
|
||||
{ "BBR3", 0x0000000, 0x3F, 0, PutBitBranch },
|
||||
{ "BBR4", 0x0000000, 0x4F, 0, PutBitBranch },
|
||||
{ "BBR5", 0x0000000, 0x5F, 0, PutBitBranch },
|
||||
{ "BBR6", 0x0000000, 0x6F, 0, PutBitBranch },
|
||||
{ "BBR7", 0x0000000, 0x7F, 0, PutBitBranch },
|
||||
{ "BBS0", 0x0000000, 0x8F, 0, PutBitBranch },
|
||||
{ "BBS1", 0x0000000, 0x9F, 0, PutBitBranch },
|
||||
{ "BBS2", 0x0000000, 0xAF, 0, PutBitBranch },
|
||||
{ "BBS3", 0x0000000, 0xBF, 0, PutBitBranch },
|
||||
{ "BBS4", 0x0000000, 0xCF, 0, PutBitBranch },
|
||||
{ "BBS5", 0x0000000, 0xDF, 0, PutBitBranch },
|
||||
{ "BBS6", 0x0000000, 0xEF, 0, PutBitBranch },
|
||||
{ "BBS7", 0x0000000, 0xFF, 0, PutBitBranch },
|
||||
{ "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
|
||||
{ "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
|
||||
{ "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
|
||||
{ "BIT", 0x0A0006C, 0x00, 2, PutAll32 },
|
||||
{ "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
|
||||
{ "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
|
||||
{ "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
|
||||
{ "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
|
||||
{ "BRK", 0x0800005, 0x00, 6, PutAll32 },
|
||||
{ "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
|
||||
{ "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
|
||||
{ "CLC", 0x0000001, 0x18, 0, PutAll32 },
|
||||
{ "CLD", 0x0000001, 0xd8, 0, PutAll32 },
|
||||
{ "CLI", 0x0000001, 0x58, 0, PutAll32 },
|
||||
{ "CLV", 0x0000001, 0xb8, 0, PutAll32 },
|
||||
{ "CMP", 0x080A66C, 0xc0, 0, PutAll32 },
|
||||
{ "CPX", 0x080000C, 0xe0, 1, PutAll32 },
|
||||
{ "CPY", 0x080000C, 0xc0, 1, PutAll32 },
|
||||
{ "DEA", 0x0000001, 0x00, 3, PutAll32 }, /* == DEC */
|
||||
{ "DEC", 0x000006F, 0x00, 3, PutAll32 },
|
||||
{ "DEX", 0x0000001, 0xca, 0, PutAll32 },
|
||||
{ "DEY", 0x0000001, 0x88, 0, PutAll32 },
|
||||
{ "EOR", 0x080A66C, 0x40, 0, PutAll32 },
|
||||
{ "INA", 0x0000001, 0x00, 4, PutAll32 }, /* == INC */
|
||||
{ "INC", 0x000006f, 0x00, 4, PutAll32 },
|
||||
{ "INX", 0x0000001, 0xe8, 0, PutAll32 },
|
||||
{ "INY", 0x0000001, 0xc8, 0, PutAll32 },
|
||||
{ "JMP", 0x0010808, 0x4c, 6, PutAll32 },
|
||||
{ "JSR", 0x0000008, 0x20, 7, PutAll32 },
|
||||
{ "LDA", 0x080A66C, 0xa0, 0, PutAll32 },
|
||||
{ "LDX", 0x080030C, 0xa2, 1, PutAll32 },
|
||||
{ "LDY", 0x080006C, 0xa0, 1, PutAll32 },
|
||||
{ "LSR", 0x000006F, 0x42, 1, PutAll32 },
|
||||
{ "NOP", 0x0000001, 0xea, 0, PutAll32 },
|
||||
{ "ORA", 0x080A66C, 0x00, 0, PutAll32 },
|
||||
{ "PHA", 0x0000001, 0x48, 0, PutAll32 },
|
||||
{ "PHP", 0x0000001, 0x08, 0, PutAll32 },
|
||||
{ "PHX", 0x0000001, 0xda, 0, PutAll32 },
|
||||
{ "PHY", 0x0000001, 0x5a, 0, PutAll32 },
|
||||
{ "PLA", 0x0000001, 0x68, 0, PutAll32 },
|
||||
{ "PLP", 0x0000001, 0x28, 0, PutAll32 },
|
||||
{ "PLX", 0x0000001, 0xfa, 0, PutAll32 },
|
||||
{ "PLY", 0x0000001, 0x7a, 0, PutAll32 },
|
||||
{ "RMB0", 0x0000004, 0x07, 1, PutAll32 },
|
||||
{ "RMB1", 0x0000004, 0x17, 1, PutAll32 },
|
||||
{ "RMB2", 0x0000004, 0x27, 1, PutAll32 },
|
||||
{ "RMB3", 0x0000004, 0x37, 1, PutAll32 },
|
||||
{ "RMB4", 0x0000004, 0x47, 1, PutAll32 },
|
||||
{ "RMB5", 0x0000004, 0x57, 1, PutAll32 },
|
||||
{ "RMB6", 0x0000004, 0x67, 1, PutAll32 },
|
||||
{ "RMB7", 0x0000004, 0x77, 1, PutAll32 },
|
||||
{ "ROL", 0x000006F, 0x22, 1, PutAll32 },
|
||||
{ "ROR", 0x000006F, 0x62, 1, PutAll32 },
|
||||
{ "RTI", 0x0000001, 0x40, 0, PutAll32 },
|
||||
{ "RTS", 0x0000001, 0x60, 0, PutAll32 },
|
||||
{ "SBC", 0x080A66C, 0xe0, 0, PutAll32 },
|
||||
{ "SEC", 0x0000001, 0x38, 0, PutAll32 },
|
||||
{ "SED", 0x0000001, 0xf8, 0, PutAll32 },
|
||||
{ "SEI", 0x0000001, 0x78, 0, PutAll32 },
|
||||
{ "SMB0", 0x0000004, 0x87, 1, PutAll32 },
|
||||
{ "SMB1", 0x0000004, 0x97, 1, PutAll32 },
|
||||
{ "SMB2", 0x0000004, 0xA7, 1, PutAll32 },
|
||||
{ "SMB3", 0x0000004, 0xB7, 1, PutAll32 },
|
||||
{ "SMB4", 0x0000004, 0xC7, 1, PutAll32 },
|
||||
{ "SMB5", 0x0000004, 0xD7, 1, PutAll32 },
|
||||
{ "SMB6", 0x0000004, 0xE7, 1, PutAll32 },
|
||||
{ "SMB7", 0x0000004, 0xF7, 1, PutAll32 },
|
||||
{ "STA", 0x000A66C, 0x80, 0, PutAll32 },
|
||||
{ "STP", 0x0000001, 0xdb, 0, PutAll32 },
|
||||
{ "STX", 0x000010c, 0x82, 1, PutAll32 },
|
||||
{ "STY", 0x000002c, 0x80, 1, PutAll32 },
|
||||
{ "STZ", 0x000006c, 0x04, 5, PutAll32 },
|
||||
{ "TAX", 0x0000001, 0xaa, 0, PutAll32 },
|
||||
{ "TAY", 0x0000001, 0xa8, 0, PutAll32 },
|
||||
{ "TRB", 0x000000c, 0x10, 1, PutAll32 },
|
||||
{ "TSB", 0x000000c, 0x00, 1, PutAll32 },
|
||||
{ "TSX", 0x0000001, 0xba, 0, PutAll32 },
|
||||
{ "TXA", 0x0000001, 0x8a, 0, PutAll32 },
|
||||
{ "TXS", 0x0000001, 0x9a, 0, PutAll32 },
|
||||
{ "TYA", 0x0000001, 0x98, 0, PutAll32 },
|
||||
{ "WAI", 0x0000001, 0xcb, 0, PutAll32 }
|
||||
/* END SORTED.SH */
|
||||
}
|
||||
};
|
||||
|
||||
/* Instruction table for the 65CE02 */
|
||||
static const struct {
|
||||
unsigned Count;
|
||||
@@ -1622,6 +1738,7 @@ static const InsTable* InsTabs[CPU_COUNT] = {
|
||||
(const InsTable*) &InsTab45GS02,
|
||||
(const InsTable*) &InsTabW65C02, /* CMOS with WDC extensions */
|
||||
(const InsTable*) &InsTab65CE02, /* CMOS with CSG extensions */
|
||||
(const InsTable*) &InsTab65C032,
|
||||
};
|
||||
const InsTable* InsTab = (const InsTable*) &InsTab6502;
|
||||
|
||||
@@ -1786,6 +1903,40 @@ static unsigned char Sweet16ExtBytes[AMSW16I_COUNT] = {
|
||||
0, /* AMSW16_REG */
|
||||
};
|
||||
|
||||
unsigned char ExtBytes32[AM65I_COUNT] = {
|
||||
0, /* Implicit */
|
||||
0, /* Accu */
|
||||
1, /* Direct */
|
||||
4, /* Absolute */
|
||||
3, /* Absolute long */
|
||||
1, /* Direct,X */
|
||||
4, /* Absolute,X */
|
||||
3, /* Absolute long,X */
|
||||
1, /* Direct,Y */
|
||||
4, /* Absolute,Y */
|
||||
1, /* (Direct) */
|
||||
4, /* (Absolute) */
|
||||
1, /* [Direct] */
|
||||
1, /* (Direct),Y */
|
||||
1, /* [Direct],Y */
|
||||
1, /* (Direct,X) */
|
||||
4, /* (Absolute,X) */
|
||||
1, /* Relative short */
|
||||
2, /* Relative long */
|
||||
1, /* r,s */
|
||||
1, /* (r,s),y */
|
||||
1, /* Immidiate accu */
|
||||
1, /* Immidiate index */
|
||||
1, /* Immidiate byte */
|
||||
2, /* Blockmove (65816) */
|
||||
7, /* Block transfer (HuC6280) */
|
||||
4, /* Absolute Indirect long */
|
||||
2, /* Immidiate word */
|
||||
2, /* Direct, Relative short */
|
||||
1, /* Special Page */
|
||||
1, /* [Direct],z */
|
||||
0, /* Q */
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -1849,15 +2000,23 @@ static int EvalEA (const InsDesc* Ins, EffAddr* A)
|
||||
}
|
||||
|
||||
/* Check the size */
|
||||
switch (ED.AddrSize) {
|
||||
if (CPU == CPU_65C032) {
|
||||
switch (ED.AddrSize) {
|
||||
case ADDR_SIZE_LONG:
|
||||
A->AddrModeSet &= ~AM65_SET_ZP;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (ED.AddrSize) {
|
||||
|
||||
case ADDR_SIZE_ABS:
|
||||
A->AddrModeSet &= ~AM65_SET_ZP;
|
||||
break;
|
||||
case ADDR_SIZE_ABS:
|
||||
A->AddrModeSet &= ~AM65_SET_ZP;
|
||||
break;
|
||||
|
||||
case ADDR_SIZE_FAR:
|
||||
A->AddrModeSet &= ~(AM65_SET_ZP | AM65_SET_ABS);
|
||||
break;
|
||||
case ADDR_SIZE_FAR:
|
||||
A->AddrModeSet &= ~(AM65_SET_ZP | AM65_SET_ABS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free any resource associated with the expression desc */
|
||||
@@ -1950,6 +2109,39 @@ static void EmitCode (EffAddr* A)
|
||||
}
|
||||
}
|
||||
|
||||
static void EmitCode32 (EffAddr* A)
|
||||
/* Output code for the data in A */
|
||||
{
|
||||
/* Check how many extension bytes are needed and output the instruction */
|
||||
switch (ExtBytes32[A->AddrMode]) {
|
||||
|
||||
|
||||
case 0:
|
||||
Emit0 (A->Opcode);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
Emit1 (A->Opcode, A->Expr);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
Internal ("65C032 has no 3 byte instructions!");
|
||||
break;
|
||||
|
||||
case 3:
|
||||
Internal ("65C032 has no 4 byte instructions!");
|
||||
break;
|
||||
|
||||
case 4:
|
||||
Emit4 (A->Opcode, A->Expr);
|
||||
break;
|
||||
|
||||
default:
|
||||
Internal ("Invalid operand byte count: %u", ExtBytes[A->AddrMode]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void PutLDM_m740 (const InsDesc* Ins)
|
||||
{
|
||||
@@ -2416,6 +2608,17 @@ static void PutAll (const InsDesc* Ins)
|
||||
}
|
||||
}
|
||||
|
||||
static void PutAll32 (const InsDesc* Ins)
|
||||
/* Handle all other instructions for the 65C032 */
|
||||
{
|
||||
EffAddr A;
|
||||
|
||||
/* Evaluate the Addressing Mode Used */
|
||||
if (EvalEA (Ins, &A)) {
|
||||
/* No error, output code */
|
||||
EmitCode32 (&A);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void Emit4510 (EffAddr* A) {
|
||||
|
||||
@@ -219,6 +219,7 @@ static void DefineCpuSymbols (void)
|
||||
NewSymbol ("CPU_ISET_45GS02", CPU_ISET_45GS02);
|
||||
NewSymbol ("CPU_ISET_W65C02", CPU_ISET_W65C02);
|
||||
NewSymbol ("CPU_ISET_65CE02", CPU_ISET_65CE02);
|
||||
NewSymbol ("CPU_ISET_65C032", CPU_ISET_65C032);
|
||||
|
||||
/* Additional ones from cpu.mac. Not sure how useful they are after the
|
||||
** changes from #2751.
|
||||
@@ -1274,6 +1275,8 @@ int main (int argc, char* argv [])
|
||||
/* Define the default options */
|
||||
SetOptions ();
|
||||
|
||||
CreateDefaultSegments ();
|
||||
|
||||
/* Assemble the input */
|
||||
Assemble ();
|
||||
|
||||
|
||||
@@ -131,6 +131,12 @@ void Emit3 (unsigned char OPC, ExprNode* Expr)
|
||||
EmitFarAddr (Expr);
|
||||
}
|
||||
|
||||
void Emit4 (unsigned char OPC, ExprNode* Expr)
|
||||
/* Emit an instruction with a four byte argument */
|
||||
{
|
||||
Emit0 (OPC);
|
||||
EmitDWord (Expr);
|
||||
}
|
||||
|
||||
|
||||
void EmitSigned (ExprNode* Expr, unsigned Size)
|
||||
|
||||
@@ -62,6 +62,9 @@ void Emit2 (unsigned char OPC, ExprNode* Value);
|
||||
void Emit3 (unsigned char OPC, ExprNode* Expr);
|
||||
/* Emit an instruction with a three byte argument */
|
||||
|
||||
void Emit4 (unsigned char OPC, ExprNode* Expr);
|
||||
/* Emit an instruction with a four byte argument */
|
||||
|
||||
void EmitSigned (ExprNode* Expr, unsigned Size);
|
||||
/* Emit a signed expression with the given size */
|
||||
|
||||
|
||||
@@ -377,7 +377,11 @@ static void DoAddr (void)
|
||||
/* Do a range check */
|
||||
Expr = GenWordExpr (Expr);
|
||||
}
|
||||
EmitWord (Expr);
|
||||
if (GetCPU () == CPU_65C032) {
|
||||
EmitDWord( Expr );
|
||||
} else {
|
||||
EmitWord (Expr);
|
||||
}
|
||||
if (CurTok.Tok != TOK_COMMA) {
|
||||
break;
|
||||
} else {
|
||||
@@ -2254,6 +2258,7 @@ static CtrlDesc CtrlCmdTab [] = {
|
||||
{ ccNone, DoTag }, /* .TAG */
|
||||
{ ccNone, DoUnexpected }, /* .TCOUNT */
|
||||
{ ccNone, DoUnexpected }, /* .TIME */
|
||||
{ ccNone, DoUnexpected }, /* .TOPBYTE */
|
||||
{ ccKeepToken, DoUnDef }, /* .UNDEF, .UNDEFINE */
|
||||
{ ccNone, DoUnion }, /* .UNION */
|
||||
{ ccNone, DoUnexpected }, /* .VERSION */
|
||||
|
||||
@@ -316,6 +316,7 @@ struct DotKeyword {
|
||||
{ ".TAG", TOK_TAG },
|
||||
{ ".TCOUNT", TOK_TCOUNT },
|
||||
{ ".TIME", TOK_TIME },
|
||||
{ ".TOPBYTE", TOK_TOPBYTE },
|
||||
{ ".UNDEF", TOK_UNDEF },
|
||||
{ ".UNDEFINE", TOK_UNDEF },
|
||||
{ ".UNION", TOK_UNION },
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
#include "spool.h"
|
||||
#include "studyexpr.h"
|
||||
#include "symtab.h"
|
||||
#include "cpu.h"
|
||||
|
||||
|
||||
|
||||
@@ -93,7 +94,22 @@ Segment* ActiveSeg;
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
void CreateDefaultSegments(void) {
|
||||
int AddrSizeAbs;
|
||||
|
||||
if (CPU == CPU_65C032) {
|
||||
AddrSizeAbs = 4;
|
||||
} else {
|
||||
AddrSizeAbs = 2;
|
||||
}
|
||||
|
||||
NullSegDef.AddrSize = AddrSizeAbs;
|
||||
ZeropageSegDef.AddrSize = ADDR_SIZE_ZP;
|
||||
DataSegDef.AddrSize = AddrSizeAbs;
|
||||
BssSegDef.AddrSize = AddrSizeAbs;
|
||||
RODataSegDef.AddrSize = AddrSizeAbs;
|
||||
CodeSegDef.AddrSize = AddrSizeAbs;
|
||||
}
|
||||
|
||||
static Segment* NewSegFromDef (SegDef* Def)
|
||||
/* Create a new segment from a segment definition. Used only internally, no
|
||||
|
||||
@@ -90,6 +90,8 @@ extern Segment* ActiveSeg;
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
void CreateDefaultSegments (void);
|
||||
/* Create the default segments, based on the current CPU */
|
||||
|
||||
|
||||
Fragment* GenFragment (unsigned char Type, unsigned short Len);
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "symbol.h"
|
||||
#include "symtab.h"
|
||||
#include "struct.h"
|
||||
#include "cpu.h"
|
||||
|
||||
|
||||
|
||||
@@ -175,7 +176,14 @@ static long DoStructInternal (long Offs, unsigned Type)
|
||||
case TOK_WORD:
|
||||
case TOK_ADDR:
|
||||
NextTok ();
|
||||
MemberSize = Member (2);
|
||||
switch (CPU) {
|
||||
case CPU_65C032:
|
||||
MemberSize = Member (4);
|
||||
break;
|
||||
default:
|
||||
MemberSize = Member (2);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case TOK_FARADDR:
|
||||
|
||||
@@ -274,6 +274,7 @@ static const TokDescEntry TokDesc[] = {
|
||||
{ ".TAG" },
|
||||
{ ".TCOUNT" },
|
||||
{ ".TIME" },
|
||||
{ ".TOPBYTE" },
|
||||
{ ".UNDEF" },
|
||||
{ ".UNION" },
|
||||
{ ".VERSION" },
|
||||
|
||||
@@ -280,6 +280,7 @@ typedef enum token_t {
|
||||
TOK_TAG,
|
||||
TOK_TCOUNT,
|
||||
TOK_TIME,
|
||||
TOK_TOPBYTE,
|
||||
TOK_UNDEF,
|
||||
TOK_UNION,
|
||||
TOK_VERSION,
|
||||
|
||||
@@ -1123,6 +1123,8 @@ void AddOpLow (StackOpData* D, opc_t OPC, LoadInfo* LI)
|
||||
InsertEntry (D, X, D->IP++);
|
||||
|
||||
if (LI->A.LoadEntry->OPC == OP65_JSR) {
|
||||
/* This should only happen in one known ldaxysp case. */
|
||||
CHECK (CE_IsCallTo (LI->A.LoadEntry, "ldaxysp"));
|
||||
/* opc (c_sp),y */
|
||||
X = NewCodeEntry (OPC, AM65_ZP_INDY, "c_sp", 0, D->OpEntry->LI);
|
||||
} else {
|
||||
@@ -1133,7 +1135,7 @@ void AddOpLow (StackOpData* D, opc_t OPC, LoadInfo* LI)
|
||||
|
||||
}
|
||||
|
||||
/* In both cases, we can remove the load */
|
||||
/* In both cases, we may try removing the load */
|
||||
LI->A.Flags |= LI_REMOVE;
|
||||
|
||||
} else {
|
||||
@@ -1188,6 +1190,8 @@ void AddOpHigh (StackOpData* D, opc_t OPC, LoadInfo* LI, int KeepResult)
|
||||
InsertEntry (D, X, D->IP++);
|
||||
|
||||
if (LI->X.LoadEntry->OPC == OP65_JSR) {
|
||||
/* This should only happen in one known ldaxysp case. */
|
||||
CHECK (CE_IsCallTo (LI->X.LoadEntry, "ldaxysp"));
|
||||
/* opc (c_sp),y */
|
||||
X = NewCodeEntry (OPC, AM65_ZP_INDY, "c_sp", 0, D->OpEntry->LI);
|
||||
} else {
|
||||
@@ -1197,7 +1201,7 @@ void AddOpHigh (StackOpData* D, opc_t OPC, LoadInfo* LI, int KeepResult)
|
||||
InsertEntry (D, X, D->IP++);
|
||||
}
|
||||
|
||||
/* In both cases, we can remove the load */
|
||||
/* In both cases, we may try removing the load */
|
||||
LI->X.Flags |= LI_REMOVE;
|
||||
|
||||
} else {
|
||||
@@ -1225,12 +1229,71 @@ void AddOpHigh (StackOpData* D, opc_t OPC, LoadInfo* LI, int KeepResult)
|
||||
void RemoveRegLoads (StackOpData* D, LoadInfo* LI)
|
||||
/* Remove register load insns */
|
||||
{
|
||||
if ((LI->A.Flags & LI_REMOVE) == LI_REMOVE) {
|
||||
if (LI->A.LoadIndex >= 0 &&
|
||||
(LI->A.LoadEntry->Flags & CEF_DONT_REMOVE) == 0) {
|
||||
DelEntry (D, LI->A.LoadIndex);
|
||||
}
|
||||
int CanRemoveA;
|
||||
int CanRemoveX;
|
||||
|
||||
/* When either A or X load insn is a call to ldaxysp runtime, the load
|
||||
** affects both and must be treated as a single A/X unit. A request to
|
||||
** remove the runtime call for just one (A or X) load is not valid in that
|
||||
** case. Either both must be removable+removed, or the other load is
|
||||
** independent, or ldaxysp runtime call must remain.
|
||||
*/
|
||||
CanRemoveA = (LI->A.Flags & LI_REMOVE) == LI_REMOVE &&
|
||||
LI->A.LoadEntry != 0 &&
|
||||
(LI->A.LoadEntry->Flags & CEF_DONT_REMOVE) == 0;
|
||||
|
||||
CanRemoveX = (LI->X.Flags & LI_REMOVE) == LI_REMOVE &&
|
||||
LI->X.LoadEntry != 0 &&
|
||||
(LI->X.LoadEntry->Flags & CEF_DONT_REMOVE) == 0;
|
||||
|
||||
/* The only runtime calls removable as load insns are calls to ldaxysp. */
|
||||
CHECK (!CanRemoveA || LI->A.LoadEntry->OPC != OP65_JSR ||
|
||||
CE_IsCallTo (LI->A.LoadEntry, "ldaxysp"));
|
||||
CHECK (!CanRemoveX || LI->X.LoadEntry->OPC != OP65_JSR ||
|
||||
CE_IsCallTo (LI->X.LoadEntry, "ldaxysp"));
|
||||
|
||||
/* When the A load insn affects X reg (e.g. ldaxysp runtime), and the X
|
||||
** load cannot be removed, we cannot remove the A load either.
|
||||
*/
|
||||
if (CanRemoveA && (LI->A.LoadEntry->Chg & REG_X) != 0 && !CanRemoveX) {
|
||||
/* A load is not removable */
|
||||
LI->A.LoadEntry->Flags |= CEF_DONT_REMOVE;
|
||||
CanRemoveA = 0;
|
||||
}
|
||||
|
||||
/* When the X load insn affects A reg (e.g. ldaxysp runtime), and the A
|
||||
** load cannot be removed, we cannot remove the X load either.
|
||||
*/
|
||||
if (CanRemoveX && (LI->X.LoadEntry->Chg & REG_A) != 0 && !CanRemoveA) {
|
||||
/* X load is not removable */
|
||||
LI->X.LoadEntry->Flags |= CEF_DONT_REMOVE;
|
||||
CanRemoveX = 0;
|
||||
}
|
||||
|
||||
/* A load removal demand which cannot be satisifed is a fatal condition */
|
||||
if (((LI->A.Flags & LI_MUST_REMOVE) != 0 && !CanRemoveA) ||
|
||||
((LI->X.Flags & LI_MUST_REMOVE) != 0 && !CanRemoveX)) {
|
||||
Internal ("Cannot remove a load instruction which must be removed");
|
||||
}
|
||||
|
||||
/* A request to remove a "change" insn (ChgIndex) when there is no
|
||||
** corresponing load insn (LoadIndex) is never valid.
|
||||
*/
|
||||
CHECK ((LI->A.Flags & LI_REMOVE) == 0 || LI->A.ChgIndex < 0 ||
|
||||
LI->A.LoadIndex >= 0);
|
||||
CHECK ((LI->X.Flags & LI_REMOVE) == 0 || LI->X.ChgIndex < 0 ||
|
||||
LI->X.LoadIndex >= 0);
|
||||
|
||||
if (CanRemoveA) {
|
||||
|
||||
CHECK (LI->A.LoadIndex >= 0);
|
||||
DelEntry (D, LI->A.LoadIndex);
|
||||
|
||||
/* Only remove the Y load if it is not shared with a non-removable
|
||||
** X load. A shared load will be removed here otherwise.
|
||||
*/
|
||||
if (LI->A.LoadYIndex >= 0 &&
|
||||
(LI->A.LoadYIndex != LI->X.LoadYIndex || CanRemoveX) &&
|
||||
(LI->A.LoadYEntry->Flags & CEF_DONT_REMOVE) == 0) {
|
||||
DelEntry (D, LI->A.LoadYIndex);
|
||||
}
|
||||
@@ -1247,11 +1310,16 @@ void RemoveRegLoads (StackOpData* D, LoadInfo* LI)
|
||||
LI->A.LoadYEntry->Flags |= CEF_DONT_REMOVE;
|
||||
}
|
||||
|
||||
if ((LI->X.Flags & LI_REMOVE) == LI_REMOVE) {
|
||||
if (LI->X.LoadIndex >= 0 &&
|
||||
(LI->X.LoadEntry->Flags & CEF_DONT_REMOVE) == 0) {
|
||||
DelEntry (D, LI->X.LoadIndex);
|
||||
}
|
||||
/* The X load may have already been removed above if it were a runtime
|
||||
** call (i.e. "jsr ldaxysp"), so need to check again.
|
||||
*/
|
||||
if (CanRemoveX && LI->X.LoadIndex >= 0) {
|
||||
|
||||
DelEntry (D, LI->X.LoadIndex);
|
||||
|
||||
/* Only remove the Y load if it is not shared with non-removable A load.
|
||||
** If it is shared and still needed, it was flaged non-removable above.
|
||||
*/
|
||||
if (LI->X.LoadYIndex >= 0 &&
|
||||
(LI->X.LoadYEntry->Flags & CEF_DONT_REMOVE) == 0) {
|
||||
DelEntry (D, LI->X.LoadYIndex);
|
||||
|
||||
@@ -70,6 +70,7 @@ typedef enum {
|
||||
LI_USED_BY_Y = 0x4000, /* Content used by RegY */
|
||||
LI_SP = 0x8000, /* Content on stack */
|
||||
LI_LOAD_INSN = 0x010000, /* Is a load insn */
|
||||
LI_MUST_REMOVE = 0x020000, /* Load must be removed */
|
||||
} LI_FLAGS;
|
||||
|
||||
/* Structure that tells us how to load the lhs values */
|
||||
|
||||
@@ -436,9 +436,9 @@ static unsigned Opt_toseqax_tosneax (StackOpData* D, const char* BoolTransformer
|
||||
X = NewCodeEntry (OP65_CMP, LoadA->AM, LoadA->Arg, 0, D->OpEntry->LI);
|
||||
InsertEntry (D, X, D->IP++);
|
||||
|
||||
/* Rhs load entries must be removed */
|
||||
D->Rhs.X.Flags |= LI_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_REMOVE;
|
||||
/* Rhs load entries must be removed because Lhs must be in effect */
|
||||
D->Rhs.X.Flags |= (LI_REMOVE | LI_MUST_REMOVE);
|
||||
D->Rhs.A.Flags |= (LI_REMOVE | LI_MUST_REMOVE);
|
||||
|
||||
} else if (RhsIsRemovable (D)) {
|
||||
|
||||
@@ -454,6 +454,10 @@ static unsigned Opt_toseqax_tosneax (StackOpData* D, const char* BoolTransformer
|
||||
/* Add operand for high byte */
|
||||
AddOpHigh (D, OP65_CMP, &D->Rhs, 0);
|
||||
|
||||
/* Rhs load entries must be removed because Lhs must be in effect */
|
||||
D->Rhs.X.Flags |= LI_MUST_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_MUST_REMOVE;
|
||||
|
||||
} else {
|
||||
|
||||
/* Implement the op via a temp ZP location */
|
||||
@@ -1018,9 +1022,9 @@ static unsigned Opt_tosgeax (StackOpData* D)
|
||||
X = NewCodeEntry (OP65_ROL, AM65_ACC, "a", 0, D->OpEntry->LI);
|
||||
InsertEntry (D, X, D->IP++);
|
||||
|
||||
/* Rhs load entries must be removed */
|
||||
D->Rhs.X.Flags |= LI_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_REMOVE;
|
||||
/* Rhs load entries must be removed because Lhs must be in effect */
|
||||
D->Rhs.X.Flags |= LI_MUST_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_MUST_REMOVE;
|
||||
|
||||
/* Remove the push and the call to the tosgeax function */
|
||||
RemoveRemainders (D);
|
||||
@@ -1075,9 +1079,9 @@ static unsigned Opt_tosltax (StackOpData* D)
|
||||
X = NewCodeEntry (OP65_ROL, AM65_ACC, "a", 0, D->OpEntry->LI);
|
||||
InsertEntry (D, X, D->IP++);
|
||||
|
||||
/* Rhs load entries must be removed */
|
||||
D->Rhs.X.Flags |= LI_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_REMOVE;
|
||||
/* Rhs load entries must be removed because Lhs must be in effect */
|
||||
D->Rhs.X.Flags |= LI_MUST_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_MUST_REMOVE;
|
||||
|
||||
/* Remove the push and the call to the tosltax function */
|
||||
RemoveRemainders (D);
|
||||
@@ -1158,9 +1162,9 @@ static unsigned Opt_tossubax (StackOpData* D)
|
||||
/* Add code for high operand */
|
||||
AddOpHigh (D, OP65_SBC, &D->Rhs, 1);
|
||||
|
||||
/* Rhs load entries must be removed */
|
||||
D->Rhs.X.Flags |= LI_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_REMOVE;
|
||||
/* Rhs load entries must be removed because Lhs must be in effect */
|
||||
D->Rhs.X.Flags |= LI_MUST_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_MUST_REMOVE;
|
||||
|
||||
/* Remove the push and the call to the tossubax function */
|
||||
RemoveRemainders (D);
|
||||
@@ -1200,9 +1204,9 @@ static unsigned Opt_tosugeax (StackOpData* D)
|
||||
X = NewCodeEntry (OP65_ROL, AM65_ACC, "a", 0, D->OpEntry->LI);
|
||||
InsertEntry (D, X, D->IP++);
|
||||
|
||||
/* Rhs load entries must be removed */
|
||||
D->Rhs.X.Flags |= LI_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_REMOVE;
|
||||
/* Rhs load entries must be removed because Lhs must be in effect */
|
||||
D->Rhs.X.Flags |= LI_MUST_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_MUST_REMOVE;
|
||||
|
||||
/* Remove the push and the call to the tosugeax function */
|
||||
RemoveRemainders (D);
|
||||
@@ -1246,9 +1250,9 @@ static unsigned Opt_tosugtax (StackOpData* D)
|
||||
X = NewCodeEntry (OP65_JSR, AM65_ABS, "boolugt", 0, D->OpEntry->LI);
|
||||
InsertEntry (D, X, D->IP++);
|
||||
|
||||
/* Rhs load entries must be removed */
|
||||
D->Rhs.X.Flags |= LI_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_REMOVE;
|
||||
/* Rhs load entries must be removed because Lhs must be in effect */
|
||||
D->Rhs.X.Flags |= LI_MUST_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_MUST_REMOVE;
|
||||
|
||||
/* Remove the push and the call to the operator function */
|
||||
RemoveRemainders (D);
|
||||
@@ -1292,9 +1296,9 @@ static unsigned Opt_tosuleax (StackOpData* D)
|
||||
X = NewCodeEntry (OP65_JSR, AM65_ABS, "boolule", 0, D->OpEntry->LI);
|
||||
InsertEntry (D, X, D->IP++);
|
||||
|
||||
/* Rhs load entries must be removed */
|
||||
D->Rhs.X.Flags |= LI_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_REMOVE;
|
||||
/* Rhs load entries must be removed because Lhs must be in effect */
|
||||
D->Rhs.X.Flags |= LI_MUST_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_MUST_REMOVE;
|
||||
|
||||
/* Remove the push and the call to the operator function */
|
||||
RemoveRemainders (D);
|
||||
@@ -1326,9 +1330,9 @@ static unsigned Opt_tosultax (StackOpData* D)
|
||||
X = NewCodeEntry (OP65_JSR, AM65_ABS, "boolult", 0, D->OpEntry->LI);
|
||||
InsertEntry (D, X, D->IP++);
|
||||
|
||||
/* Rhs load entries must be removed */
|
||||
D->Rhs.X.Flags |= LI_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_REMOVE;
|
||||
/* Rhs load entries must be removed because Lhs must be in effect */
|
||||
D->Rhs.X.Flags |= LI_MUST_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_MUST_REMOVE;
|
||||
|
||||
/* Remove the push and the call to the operator function */
|
||||
RemoveRemainders (D);
|
||||
@@ -1396,8 +1400,8 @@ static unsigned Opt_a_tosbitwise (StackOpData* D, opc_t OPC)
|
||||
X = NewCodeEntry (OPC, D->Rhs.A.LoadEntry->AM, D->Rhs.A.LoadEntry->Arg, 0, D->OpEntry->LI);
|
||||
InsertEntry (D, X, D->IP++);
|
||||
|
||||
/* Rhs load entries must be removed */
|
||||
D->Rhs.A.Flags |= LI_REMOVE;
|
||||
/* Rhs A load must be removed because Lhs must be in effect */
|
||||
D->Rhs.A.Flags |= (LI_REMOVE | LI_MUST_REMOVE);
|
||||
|
||||
} else if (RegIsDirectNonStackLoaded (&D->Lhs.A)) {
|
||||
|
||||
@@ -1419,12 +1423,10 @@ static unsigned Opt_a_tosbitwise (StackOpData* D, opc_t OPC)
|
||||
InsertEntry (D, X, D->IP++);
|
||||
}
|
||||
|
||||
/* ### Bug to come: there are dangerous Rhs X removal attempts here.
|
||||
** Runtime function calls can be "loads", and must be treated as a
|
||||
** single A/X unit, so removal of X load alone is not valid.
|
||||
** This can be solved with an additional "removable Rhs" test, or
|
||||
** by simply not forcing the LI_REMOVE flag and letting other optimizers
|
||||
** remove any unnecessary loads.
|
||||
/* Note: Eager Rhs X removals here can sometimes produce slightly worse
|
||||
** code after all other optimizers have run. This may need a general
|
||||
** study of which is better: eager removal, or letting other optimizers
|
||||
** take care of unneeded loads.
|
||||
*/
|
||||
/* Do high-byte operation only when its result is used */
|
||||
if ((GetRegInfo (D->Code, D->IP, REG_X) & REG_X) != 0) {
|
||||
@@ -1433,10 +1435,12 @@ static unsigned Opt_a_tosbitwise (StackOpData* D, opc_t OPC)
|
||||
/* Since this is a "same X" EOR, the result is always 0. */
|
||||
X = NewCodeEntry (OP65_LDX, AM65_IMM, MakeHexArg (0), 0, D->Rhs.X.ChgEntry->LI);
|
||||
InsertEntry (D, X, D->IP++);
|
||||
|
||||
/* Rhs X load may be removed (but this is not a demand) */
|
||||
D->Rhs.X.Flags |= LI_REMOVE;
|
||||
}
|
||||
} else {
|
||||
/* Rhs load entries may be removed */
|
||||
/* Rhs X load may be removed (but this is not a demand) */
|
||||
D->Rhs.X.Flags |= LI_REMOVE;
|
||||
}
|
||||
|
||||
@@ -1464,7 +1468,7 @@ static unsigned Opt_a_toscmpbool (StackOpData* D, const char* BoolTransformer)
|
||||
|
||||
/* Rhs low-byte load must be removed and hi-byte load may be removed */
|
||||
D->Rhs.X.Flags |= LI_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_MUST_REMOVE;
|
||||
|
||||
} else if (RegIsDirectLoaded (&D->Lhs.A)) {
|
||||
/* If the lhs is direct (but not stack relative), encode compares with lhs,
|
||||
@@ -1604,7 +1608,9 @@ static unsigned Opt_a_tosicmp (StackOpData* D)
|
||||
InsertEntry (D, X, D->IP++);
|
||||
}
|
||||
|
||||
/* RHS may be removed */
|
||||
/* RHS may be removed, but it is not a demand because Lhs was
|
||||
** reloaded at Op and is in effect.
|
||||
*/
|
||||
D->Rhs.A.Flags |= LI_REMOVE;
|
||||
D->Rhs.X.Flags |= LI_REMOVE;
|
||||
}
|
||||
@@ -1703,9 +1709,11 @@ static unsigned Opt_a_tossub (StackOpData* D)
|
||||
InsertEntry (D, X, D->IP++);
|
||||
}
|
||||
|
||||
/* Rhs load entries must be removed */
|
||||
/* Rhs low-byte load must be removed (because Lhs must be in effect)
|
||||
** and hi-byte load may be removed.
|
||||
*/
|
||||
D->Rhs.X.Flags |= LI_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_REMOVE;
|
||||
D->Rhs.A.Flags |= LI_MUST_REMOVE;
|
||||
|
||||
/* Remove the push and the call to the tossubax function */
|
||||
RemoveRemainders (D);
|
||||
|
||||
@@ -413,6 +413,7 @@ static void DefineCpuMacros (void)
|
||||
DefineNumericMacro ("__CPU_ISET_65C02__", CPU_ISET_65C02);
|
||||
DefineNumericMacro ("__CPU_ISET_W65C02__", CPU_ISET_W65C02);
|
||||
DefineNumericMacro ("__CPU_ISET_65CE02__", CPU_ISET_65CE02);
|
||||
DefineNumericMacro ("__CPU_ISET_65C032__", CPU_ISET_65C032);
|
||||
DefineNumericMacro ("__CPU_ISET_65816__", CPU_ISET_65816);
|
||||
DefineNumericMacro ("__CPU_ISET_HUC6280__", CPU_ISET_HUC6280);
|
||||
DefineNumericMacro ("__CPU_ISET_4510__", CPU_ISET_4510);
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
/* Maximum possible alignment. Beware: To increase the possible alignment it
|
||||
** is not enough to bump this value. Check the code inside.
|
||||
*/
|
||||
#define MAX_ALIGNMENT 0x10000UL
|
||||
#define MAX_ALIGNMENT 0x100000000UL
|
||||
|
||||
/* The following value marks what is considered a "large alignment" and worth
|
||||
** a warning if not suppressed.
|
||||
|
||||
@@ -68,6 +68,7 @@ const char* CPUNames[CPU_COUNT] = {
|
||||
"45GS02",
|
||||
"W65C02", /* CMOS with WDC extensions */
|
||||
"65CE02", /* CMOS with CSG extensions */
|
||||
"65C032", /* CMOS with 32 bit addressing */
|
||||
};
|
||||
|
||||
/* Tables with CPU instruction sets
|
||||
@@ -102,6 +103,8 @@ const unsigned CPUIsets[CPU_COUNT] = {
|
||||
CPU_ISET_W65C02 | CPU_ISET_6502 | CPU_ISET_65SC02 | CPU_ISET_65C02,
|
||||
/* CPU_65CE02 */
|
||||
CPU_ISET_65CE02 | CPU_ISET_6502 | CPU_ISET_65C02,
|
||||
/* CPU_65C032 */
|
||||
CPU_ISET_65C032,
|
||||
};
|
||||
|
||||
/* Defines for capabilities. Currently the entries are uint32_ts but the table
|
||||
@@ -214,7 +217,7 @@ int ValidAddrSizeForCPU (unsigned char AddrSize)
|
||||
|
||||
case ADDR_SIZE_LONG:
|
||||
/* "none" supports all sizes */
|
||||
return (CPU == CPU_NONE);
|
||||
return (CPU == CPU_65C032);
|
||||
|
||||
default:
|
||||
FAIL ("Invalid address size");
|
||||
|
||||
@@ -66,7 +66,8 @@ typedef enum {
|
||||
CPU_45GS02, /* CPU of MEGA65 */
|
||||
CPU_W65C02, /* CMOS with WDC extensions */
|
||||
CPU_65CE02, /* CMOS with CSG extensions */
|
||||
CPU_COUNT /* Number of different CPUs */
|
||||
CPU_65C032, /* CMOS with 32 bit addressing */
|
||||
CPU_COUNT, /* Number of different CPUs */
|
||||
} cpu_t;
|
||||
|
||||
/* CPU instruction sets */
|
||||
@@ -84,7 +85,8 @@ enum {
|
||||
CPU_ISET_4510 = 1 << CPU_4510,
|
||||
CPU_ISET_45GS02 = 1 << CPU_45GS02,
|
||||
CPU_ISET_W65C02 = 1 << CPU_W65C02,
|
||||
CPU_ISET_65CE02 = 1 << CPU_65CE02
|
||||
CPU_ISET_65CE02 = 1 << CPU_65CE02,
|
||||
CPU_ISET_65C032 = 1 << CPU_65C032,
|
||||
};
|
||||
|
||||
/* CPU used */
|
||||
|
||||
@@ -731,7 +731,7 @@ static void ParseSegments (void)
|
||||
|
||||
case CFGTOK_OFFSET:
|
||||
FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
|
||||
S->Addr = CfgCheckedConstExpr (0, 0x1000000);
|
||||
S->Addr = CfgCheckedConstExpr (0, 0x100000000);
|
||||
S->Flags |= SF_OFFSET;
|
||||
break;
|
||||
|
||||
@@ -752,7 +752,7 @@ static void ParseSegments (void)
|
||||
|
||||
case CFGTOK_START:
|
||||
FlagAttr (&S->Attr, SA_START, "START");
|
||||
S->Addr = CfgCheckedConstExpr (0, 0x1000000);
|
||||
S->Addr = CfgCheckedConstExpr (0, 0x100000000);
|
||||
S->Flags |= SF_START;
|
||||
break;
|
||||
|
||||
@@ -1959,11 +1959,11 @@ unsigned CfgProcess (void)
|
||||
GetString (M->Name));
|
||||
}
|
||||
M->Size = GetExprVal (M->SizeExpr);
|
||||
if (M->Size >= 0x80000000) {
|
||||
PError (GetSourcePos (M->LI),
|
||||
"Size of memory area `%s' is negative: %ld",
|
||||
GetString (M->Name), (long)M->Size);
|
||||
}
|
||||
// if (M->Size >= 0x80000000) {
|
||||
// PError (GetSourcePos (M->LI),
|
||||
// "Size of memory area `%s' is negative: %ld",
|
||||
// GetString (M->Name), (long)M->Size);
|
||||
// }
|
||||
|
||||
/* Walk through the segments in this memory area */
|
||||
for (J = 0; J < CollCount (&M->SegList); ++J) {
|
||||
|
||||
BIN
test/asm/opcodes/65c032-opcodes.ref
Normal file
BIN
test/asm/opcodes/65c032-opcodes.ref
Normal file
Binary file not shown.
258
test/asm/opcodes/65c032-opcodes.s
Normal file
258
test/asm/opcodes/65c032-opcodes.s
Normal file
@@ -0,0 +1,258 @@
|
||||
.setcpu "65C032"
|
||||
|
||||
brk
|
||||
ora ($12,x)
|
||||
.byte $02
|
||||
.byte $03
|
||||
tsb $12
|
||||
ora $12
|
||||
asl $12
|
||||
rmb0 $12
|
||||
php
|
||||
ora #$12
|
||||
asl a
|
||||
.byte $0B
|
||||
tsb $3456789a
|
||||
ora $3456789a
|
||||
asl $3456789a
|
||||
bbr0 $12,*+122
|
||||
bpl *+122
|
||||
ora ($12),y
|
||||
ora ($12)
|
||||
.byte $13
|
||||
trb $12
|
||||
ora $12,x
|
||||
asl $12,x
|
||||
rmb1 $12
|
||||
clc
|
||||
ora $3456789a,y
|
||||
inc a
|
||||
.byte $1B
|
||||
trb $3456789a
|
||||
ora $3456789a,x
|
||||
asl $3456789a,x
|
||||
bbr1 $12,*+122
|
||||
jsr $3456789a
|
||||
and ($12,x)
|
||||
.byte $22
|
||||
.byte $23
|
||||
bit $12
|
||||
and $12
|
||||
rol $12
|
||||
rmb2 $12
|
||||
plp
|
||||
and #$12
|
||||
rol a
|
||||
.byte $2B
|
||||
bit $3456789a
|
||||
and $3456789a
|
||||
rol $3456789a
|
||||
bbr2 $12,*+122
|
||||
bmi *+122
|
||||
and ($12),y
|
||||
and ($12)
|
||||
.byte $33
|
||||
bit $12,x
|
||||
and $12,x
|
||||
rol $12,x
|
||||
rmb3 $12
|
||||
sec
|
||||
and $3456789a,y
|
||||
dec a
|
||||
.byte $3B
|
||||
bit $3456789a,x
|
||||
and $3456789a,x
|
||||
rol $3456789a,x
|
||||
bbr3 $12,*+122
|
||||
rti
|
||||
eor ($12,x)
|
||||
.byte $42
|
||||
.byte $43
|
||||
.byte $44
|
||||
eor $12
|
||||
lsr $12
|
||||
rmb4 $12
|
||||
pha
|
||||
eor #$12
|
||||
lsr a
|
||||
.byte $4B
|
||||
jmp $3456789a
|
||||
eor $3456789a
|
||||
lsr $3456789a
|
||||
bbr4 $12,*+122
|
||||
bvc *+122
|
||||
eor ($12),y
|
||||
eor ($12)
|
||||
.byte $53
|
||||
.byte $54
|
||||
eor $12,x
|
||||
lsr $12,x
|
||||
rmb5 $12
|
||||
cli
|
||||
eor $3456789a,y
|
||||
phy
|
||||
.byte $5B
|
||||
.byte $5C
|
||||
eor $3456789a,x
|
||||
lsr $3456789a,x
|
||||
bbr5 $12,*+122
|
||||
rts
|
||||
adc ($12,x)
|
||||
.byte $62
|
||||
.byte $63
|
||||
stz $12
|
||||
adc $12
|
||||
ror $12
|
||||
rmb6 $12
|
||||
pla
|
||||
adc #$12
|
||||
ror a
|
||||
.byte $6B
|
||||
jmp ($3456789a)
|
||||
adc $3456789a
|
||||
ror $3456789a
|
||||
bbr6 $12,*+122
|
||||
bvs *+122
|
||||
adc ($12),y
|
||||
adc ($12)
|
||||
.byte $73
|
||||
stz $12,x
|
||||
adc $12,x
|
||||
ror $12,x
|
||||
rmb7 $12
|
||||
sei
|
||||
adc $3456789a,y
|
||||
ply
|
||||
.byte $7B
|
||||
jmp ($3456789a,x)
|
||||
adc $3456789a,x
|
||||
ror $3456789a,x
|
||||
bbr7 $12,*+122
|
||||
bra *+122
|
||||
sta ($12,x)
|
||||
.byte $82
|
||||
.byte $83
|
||||
sty $12
|
||||
sta $12
|
||||
stx $12
|
||||
smb0 $12
|
||||
dey
|
||||
bit #$12
|
||||
txa
|
||||
.byte $8B
|
||||
sty $3456789a
|
||||
sta $3456789a
|
||||
stx $3456789a
|
||||
bbs0 $12,*+122
|
||||
bcc *+122
|
||||
sta ($12),y
|
||||
sta ($12)
|
||||
.byte $93
|
||||
sty $12,x
|
||||
sta $12,x
|
||||
stx $12,y
|
||||
smb1 $12
|
||||
tya
|
||||
sta $3456789a,y
|
||||
txs
|
||||
.byte $9B
|
||||
stz $3456789a
|
||||
sta $3456789a,x
|
||||
stz $3456789a,x
|
||||
bbs1 $12,*+122
|
||||
ldy #$12
|
||||
lda ($12,x)
|
||||
ldx #$12
|
||||
.byte $A3
|
||||
ldy $12
|
||||
lda $12
|
||||
ldx $12
|
||||
smb2 $12
|
||||
tay
|
||||
lda #$12
|
||||
tax
|
||||
.byte $AB
|
||||
ldy $3456789a
|
||||
lda $3456789a
|
||||
ldx $3456789a
|
||||
bbs2 $12,*+122
|
||||
bcs *+122
|
||||
lda ($12),y
|
||||
lda ($12)
|
||||
.byte $B3
|
||||
ldy $12,x
|
||||
lda $12,x
|
||||
ldx $12,y
|
||||
smb3 $12
|
||||
clv
|
||||
lda $3456789a,y
|
||||
tsx
|
||||
.byte $BB
|
||||
ldy $3456789a,x
|
||||
lda $3456789a,x
|
||||
ldx $3456789a,y
|
||||
bbs3 $12,*+122
|
||||
cpy #$12
|
||||
cmp ($12,x)
|
||||
.byte $C2
|
||||
.byte $C3
|
||||
cpy $12
|
||||
cmp $12
|
||||
dec $12
|
||||
smb4 $12
|
||||
iny
|
||||
cmp #$12
|
||||
dex
|
||||
.byte $CB
|
||||
cpy $3456789a
|
||||
cmp $3456789a
|
||||
dec $3456789a
|
||||
bbs4 $12,*+122
|
||||
bne *+122
|
||||
cmp ($12),y
|
||||
cmp ($12)
|
||||
.byte $D3
|
||||
.byte $D4
|
||||
cmp $12,x
|
||||
dec $12,x
|
||||
smb5 $12
|
||||
cld
|
||||
cmp $3456789a,y
|
||||
phx
|
||||
.byte $DB
|
||||
.byte $DC
|
||||
cmp $3456789a,x
|
||||
dec $3456789a,x
|
||||
bbs5 $12,*+122
|
||||
cpx #$12
|
||||
sbc ($12,x)
|
||||
.byte $E2
|
||||
.byte $E3
|
||||
cpx $12
|
||||
sbc $12
|
||||
inc $12
|
||||
smb6 $12
|
||||
inx
|
||||
sbc #$12
|
||||
nop
|
||||
.byte $EB
|
||||
cpx $3456789a
|
||||
sbc $3456789a
|
||||
inc $3456789a
|
||||
bbs6 $12,*+122
|
||||
beq *+122
|
||||
sbc ($12),y
|
||||
sbc ($12)
|
||||
.byte $F3
|
||||
.byte $F4
|
||||
sbc $12,x
|
||||
inc $12,x
|
||||
smb7 $12
|
||||
sed
|
||||
sbc $3456789a,y
|
||||
plx
|
||||
.byte $FB
|
||||
.byte $FC
|
||||
sbc $3456789a,x
|
||||
inc $3456789a,x
|
||||
bbs7 $12,*+122
|
||||
@@ -2,13 +2,22 @@
|
||||
|
||||
/* Note: The values for MASK1, MASK2, the return values of GarbleAX and the
|
||||
* arguments for CALC() are carefully chosen to elicit the bug.
|
||||
* CALCLX() errors appear with cc65 -Osi optimizations.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define MASK1 0x000FU
|
||||
#define MASK2 0x00FFU
|
||||
#define CALC(num, op) (((num) & (~MASK1)) op ((num) & MASK2))
|
||||
#define CALCLA(num, op) (((num) & (~MASK1)) op ((num) & MASK2))
|
||||
/* + 0x100 here invokes g_inc(), case CF_INT: if (val <= 0x300), when
|
||||
** CodeSizeFactor >= 200; then g_inc() produces a single "inx"
|
||||
*/
|
||||
#define CALCLX(num, op) (((num) + 0x100) op ((num) & MASK2))
|
||||
#define CALCRX(num, op) (((num) & MASK2) op ((num) << 8))
|
||||
|
||||
#define CALCX(num, op) (((num) + 0x100) op ((num) & (~MASK1)))
|
||||
|
||||
|
||||
static unsigned Failures = 0;
|
||||
static unsigned TestCount = 0;
|
||||
@@ -16,33 +25,157 @@ static unsigned TestCount = 0;
|
||||
unsigned GarbleAX(void)
|
||||
{
|
||||
static const unsigned Garbage[] = {
|
||||
0x1234, 0x0000, 0x1234, 0x1234
|
||||
0x1234, 0x1234, 0x0000, 0x1234, 0x1234, /* Lhs A: Add, Sub, And, Or, Xor */
|
||||
0x0057, 0x0057, 0x0037, 0x0057, /* Lhs A: Eq, Neq, Gte, Lte */
|
||||
|
||||
0x1234, 0x1234, 0x2003, 0x1002, 0x5678, /* Lhs X: Add, Sub, And, Or, Xor */
|
||||
0x0101, 0xFF00, 0xFF00, 0xFF00, /* Lhs X: Eq, Neq, Gte, Lte */
|
||||
|
||||
0x1234, 0x1234, 0xFFFF, 0xFFFF, 0xFFFF, /* Rhs X: Add, Sub, And, Or, Xor */
|
||||
};
|
||||
return Garbage[TestCount - 1];
|
||||
}
|
||||
|
||||
unsigned WrongAdd(unsigned num)
|
||||
unsigned LhsAAdd(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALC(num, +);
|
||||
return CALCLA(num, +);
|
||||
}
|
||||
|
||||
unsigned WrongAnd(unsigned num)
|
||||
unsigned LhsASub(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALC(num, &);
|
||||
return CALCLA(num, -);
|
||||
}
|
||||
|
||||
unsigned WrongOr(unsigned num)
|
||||
unsigned LhsAAnd(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALC(num, |);
|
||||
return CALCLA(num, &);
|
||||
}
|
||||
|
||||
unsigned WrongXor(unsigned num)
|
||||
unsigned LhsAOr(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALC(num, ^);
|
||||
return CALCLA(num, |);
|
||||
}
|
||||
|
||||
unsigned LhsAXor(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCLA(num, ^);
|
||||
}
|
||||
|
||||
|
||||
unsigned LhsAEq(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCLA(num, ==);
|
||||
}
|
||||
|
||||
unsigned LhsANeq(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCLA(num, !=);
|
||||
}
|
||||
|
||||
unsigned LhsAGte(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCLA(num, >=);
|
||||
}
|
||||
|
||||
unsigned LhsALte(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCLA(num, <=);
|
||||
}
|
||||
|
||||
|
||||
unsigned LhsXAdd(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCX(num, +);
|
||||
}
|
||||
|
||||
unsigned LhsXSub(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCX(num, -);
|
||||
}
|
||||
|
||||
unsigned LhsXAnd(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCX(num, &);
|
||||
}
|
||||
|
||||
unsigned LhsXOr(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCLX(num, |);
|
||||
}
|
||||
|
||||
unsigned LhsXXor(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCLX(num, ^);
|
||||
}
|
||||
|
||||
|
||||
unsigned LhsXEq(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCLX(num, ==);
|
||||
}
|
||||
|
||||
unsigned LhsXNeq(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCX(num, !=);
|
||||
}
|
||||
|
||||
unsigned LhsXGte(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCLX(num, >=);
|
||||
}
|
||||
|
||||
unsigned LhsXLte(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCLX(num, <=);
|
||||
}
|
||||
|
||||
|
||||
unsigned RhsXAdd(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCRX(num, +);
|
||||
}
|
||||
|
||||
unsigned RhsXSub(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCRX(num, -);
|
||||
}
|
||||
|
||||
unsigned RhsXAnd(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCRX(num, &);
|
||||
}
|
||||
|
||||
unsigned RhsXOr(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCRX(num, |);
|
||||
}
|
||||
|
||||
unsigned RhsXXor(unsigned num)
|
||||
{
|
||||
unsigned ret=GarbleAX();
|
||||
return CALCRX(num, ^);
|
||||
}
|
||||
|
||||
void Test(unsigned (*F)(unsigned), unsigned Num, unsigned Ref)
|
||||
@@ -58,10 +191,39 @@ void Test(unsigned (*F)(unsigned), unsigned Num, unsigned Ref)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Test(WrongAdd, 0x4715, CALC(0x4715, +));
|
||||
Test(WrongAnd, 0x4715, CALC(0x4715, &));
|
||||
Test(WrongOr, 0x4715, CALC(0x4715, |));
|
||||
Test(WrongXor, 0x4715, CALC(0x4715, ^));
|
||||
/* Test 1+ */
|
||||
Test(LhsAAdd, 0x4715, CALCLA(0x4715, +));
|
||||
Test(LhsASub, 0x4715, CALCLA(0x4715, -));
|
||||
Test(LhsAAnd, 0x4715, CALCLA(0x4715, &));
|
||||
Test(LhsAOr, 0x4715, CALCLA(0x4715, |));
|
||||
Test(LhsAXor, 0x4715, CALCLA(0x4715, ^));
|
||||
|
||||
/* Test 6+ */
|
||||
Test(LhsAEq, 0x4750, CALCLA(0x4750, ==));
|
||||
Test(LhsANeq, 0x4750, CALCLA(0x4750, !=));
|
||||
Test(LhsAGte, 0x4750, CALCLA(0x4750, >=));
|
||||
Test(LhsALte, 0x4750, CALCLA(0x4750, <=));
|
||||
|
||||
/* Test 10+ */
|
||||
Test(LhsXAdd, 0x3F15, CALCX(0x3F15, +));
|
||||
Test(LhsXSub, 0x3F15, CALCX(0x3F15, -));
|
||||
Test(LhsXAnd, 0x3F15, CALCX(0x3F15, &));
|
||||
Test(LhsXOr, 0x3F15, CALCLX(0x3F15, |));
|
||||
Test(LhsXXor, 0x3F15, CALCLX(0x3F15, ^));
|
||||
|
||||
/* Test 15+ */
|
||||
Test(LhsXEq, 0xFF50, CALCLX(0xFF50, ==));
|
||||
Test(LhsXNeq, 0xFF50, CALCX(0xFF50, !=));
|
||||
Test(LhsXGte, 0xFF50, CALCLX(0xFF50, >=));
|
||||
Test(LhsXLte, 0xFF50, CALCLX(0xFF50, <=));
|
||||
|
||||
/* Test 19+ */
|
||||
Test(RhsXAdd, 0x3F15, CALCRX(0x3F15, +));
|
||||
Test(RhsXSub, 0x3F15, CALCRX(0x3F15, -));
|
||||
Test(RhsXAnd, 0x3F15, CALCRX(0x3F15, &));
|
||||
Test(RhsXOr, 0x3F15, CALCRX(0x3F15, |));
|
||||
Test(RhsXXor, 0x3F15, CALCRX(0x3F15, ^));
|
||||
|
||||
printf("Failures: %u\n", Failures);
|
||||
return Failures;
|
||||
}
|
||||
|
||||
244
test/val/pr2951.c
Normal file
244
test/val/pr2951.c
Normal file
@@ -0,0 +1,244 @@
|
||||
|
||||
/* bug #2942/#2947: OptStackOps() sometimes removes Lhs loads shared with Rhs.
|
||||
**
|
||||
** These are synthetic, extreme reuse test cases: AX unchanged by pushax.
|
||||
** These do not occur with the current codegen, runtime and optimizers, but
|
||||
** may occur in the future. If the runtime or codegen change sufficiently to
|
||||
** break these tests, they can be deleted.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int fail = 0;
|
||||
|
||||
#define TRASH_AX 0x55AA
|
||||
|
||||
int stat_val;
|
||||
|
||||
int stat_add_full(int trash)
|
||||
{
|
||||
(void)trash;
|
||||
|
||||
__AX__ = stat_val;
|
||||
/* AX = AX + AX */
|
||||
asm("jsr pushax");
|
||||
asm("jsr tosaddax");
|
||||
|
||||
return __AX__;
|
||||
}
|
||||
|
||||
int stat_xor_full(int trash)
|
||||
{
|
||||
(void)trash;
|
||||
|
||||
__AX__ = stat_val;
|
||||
/* AX = AX ^ AX */
|
||||
asm("jsr pushax");
|
||||
asm("jsr tosxorax");
|
||||
|
||||
return __AX__;
|
||||
}
|
||||
|
||||
int stat_xor_and(int trash)
|
||||
{
|
||||
(void)trash;
|
||||
|
||||
__AX__ = stat_val;
|
||||
/* AX = AX ^ (AX & 0xFFF0) */
|
||||
asm("jsr pushax");
|
||||
asm("and #$F0");
|
||||
asm("jsr tosxorax");
|
||||
|
||||
return __AX__;
|
||||
}
|
||||
|
||||
int stat_or_inx(int trash)
|
||||
{
|
||||
(void)trash;
|
||||
|
||||
__AX__ = stat_val;
|
||||
/* AX = AX | (AX + 0x100) */
|
||||
asm("jsr pushax");
|
||||
asm("inx");
|
||||
asm("jsr tosorax");
|
||||
|
||||
return __AX__;
|
||||
}
|
||||
|
||||
int stat_and_add(int trash)
|
||||
{
|
||||
(void)trash;
|
||||
|
||||
__AX__ = stat_val;
|
||||
/* AX = (AX & 0xFFF0) + (AX & 0xFFF0) */
|
||||
asm("and #$F0");
|
||||
asm("jsr pushax");
|
||||
asm("jsr tosaddax");
|
||||
|
||||
return __AX__;
|
||||
}
|
||||
|
||||
int stat_inx_add(int trash)
|
||||
{
|
||||
(void)trash;
|
||||
|
||||
__AX__ = stat_val;
|
||||
/* AX = (AX + 0x100) + (AX + 0x100) */
|
||||
asm("inx");
|
||||
asm("jsr pushax");
|
||||
asm("jsr tosaddax");
|
||||
|
||||
return __AX__;
|
||||
}
|
||||
|
||||
int stat_inx_or(int trash)
|
||||
{
|
||||
(void)trash;
|
||||
|
||||
__AX__ = stat_val;
|
||||
/* AX = (AX + 0x100) | (AX + 0x100) */
|
||||
asm("inx");
|
||||
asm("jsr pushax");
|
||||
asm("jsr tosorax");
|
||||
|
||||
return __AX__;
|
||||
}
|
||||
|
||||
|
||||
int loc_add_full(int val, int trash)
|
||||
{
|
||||
(void)trash;
|
||||
|
||||
__AX__ = val;
|
||||
/* AX = AX + AX */
|
||||
asm("jsr pushax");
|
||||
asm("jsr tosaddax");
|
||||
|
||||
return __AX__;
|
||||
}
|
||||
|
||||
int loc_xor_full(int val, int trash)
|
||||
{
|
||||
(void)trash;
|
||||
|
||||
__AX__ = val;
|
||||
/* AX = AX ^ AX */
|
||||
asm("jsr pushax");
|
||||
asm("jsr tosxorax");
|
||||
|
||||
return __AX__;
|
||||
}
|
||||
|
||||
int loc_xor_and(int val, int trash)
|
||||
{
|
||||
(void)trash;
|
||||
|
||||
__AX__ = val;
|
||||
/* AX = AX ^ (AX & 0xFFF0) */
|
||||
asm("jsr pushax");
|
||||
asm("and #$F0");
|
||||
asm("jsr tosxorax");
|
||||
|
||||
return __AX__;
|
||||
}
|
||||
|
||||
int loc_or_inx(int val, int trash)
|
||||
{
|
||||
(void)trash;
|
||||
|
||||
__AX__ = val;
|
||||
/* AX = AX | (AX + 0x100) */
|
||||
asm("jsr pushax");
|
||||
asm("inx");
|
||||
asm("jsr tosorax");
|
||||
|
||||
return __AX__;
|
||||
}
|
||||
|
||||
int loc_and_add(int val, int trash)
|
||||
{
|
||||
(void)trash;
|
||||
|
||||
__AX__ = val;
|
||||
/* AX = (AX & 0xFFF0) + (AX & 0xFFF0) */
|
||||
asm("and #$F0");
|
||||
asm("jsr pushax");
|
||||
asm("jsr tosaddax");
|
||||
|
||||
return __AX__;
|
||||
}
|
||||
|
||||
int loc_inx_add(int val, int trash)
|
||||
{
|
||||
(void)trash;
|
||||
|
||||
__AX__ = val;
|
||||
/* AX = (AX + 0x100) + (AX + 0x100) */
|
||||
asm("inx");
|
||||
asm("jsr pushax");
|
||||
asm("jsr tosaddax");
|
||||
|
||||
return __AX__;
|
||||
}
|
||||
|
||||
int loc_inx_or(int val, int trash)
|
||||
{
|
||||
(void)trash;
|
||||
|
||||
__AX__ = val;
|
||||
/* AX = (AX + 0x100) | (AX + 0x100) */
|
||||
asm("inx");
|
||||
asm("jsr pushax");
|
||||
asm("jsr tosorax");
|
||||
|
||||
return __AX__;
|
||||
}
|
||||
|
||||
|
||||
void test_stat(int (*func)(int /*trash*/), int num, int ref, const char* expr)
|
||||
{
|
||||
int res;
|
||||
|
||||
stat_val = num;
|
||||
res = func(TRASH_AX);
|
||||
if (res != ref) {
|
||||
printf("Fail (stat): %s -> 0x%x\n", expr, res);
|
||||
++fail;
|
||||
}
|
||||
}
|
||||
|
||||
void test_loc(int (*func)(int, int /*trash*/), int num, int ref, const char* expr)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = func(num, TRASH_AX);
|
||||
if (res != ref) {
|
||||
printf("Fail (loc): %s -> 0x%x\n", expr, res);
|
||||
++fail;
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_STATIC(func, num, ref) test_stat(func, num, (ref), #ref)
|
||||
#define TEST_LOCAL(func, num, ref) test_loc(func, num, (ref), #ref)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
TEST_STATIC(stat_add_full, 0x321, 0x321 + 0x321);
|
||||
TEST_STATIC(stat_xor_full, 0x321, 0x321 ^ 0x321);
|
||||
TEST_STATIC(stat_xor_and, 0x321, 0x321 ^ (0x321 & 0xFFF0));
|
||||
TEST_STATIC(stat_or_inx, 0x321, 0x321 | (0x321 + 0x100));
|
||||
TEST_STATIC(stat_and_add, 0x321, (0x321 & 0xFFF0) + (0x321 & 0xFFF0));
|
||||
TEST_STATIC(stat_inx_add, 0x321, (0x321 + 0x100) + (0x321 + 0x100));
|
||||
TEST_STATIC(stat_inx_or, 0x321, (0x321 + 0x100) | (0x321 + 0x100));
|
||||
|
||||
TEST_LOCAL(loc_add_full, 0x321, 0x321 + 0x321);
|
||||
TEST_LOCAL(loc_xor_full, 0x321, 0x321 ^ 0x321);
|
||||
TEST_LOCAL(loc_xor_and, 0x321, 0x321 ^ (0x321 & 0xFFF0));
|
||||
TEST_LOCAL(loc_or_inx, 0x321, 0x321 | (0x321 + 0x100));
|
||||
TEST_LOCAL(loc_and_add, 0x321, (0x321 & 0xFFF0) + (0x321 & 0xFFF0));
|
||||
TEST_LOCAL(loc_inx_add, 0x321, (0x321 + 0x100) + (0x321 + 0x100));
|
||||
TEST_LOCAL(loc_inx_or, 0x321, (0x321 + 0x100) | (0x321 + 0x100));
|
||||
|
||||
return fail == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
Reference in New Issue
Block a user