Fix x86 and x86_64 __PIC__ code for Linux and Mac

This commit is contained in:
Aaron Culliney 2016-04-28 21:43:01 -07:00
parent da4e5eb75a
commit 7b3eabb12f
5 changed files with 227 additions and 146 deletions

View File

@ -41,7 +41,7 @@ APPLE2_MAIN_SRC = \
APPLE2_OPTIM_CFLAGS := -O2
APPLE2_BASE_CFLAGS := -DAPPLE2IX=1 -DINTERFACE_TOUCH=1 -DMOBILE_DEVICE=1 -DVIDEO_OPENGL=1 -DDEBUGGER=1 -DAUDIO_ENABLED=1 -std=gnu11 -fPIC $(APPLE2_OPTIM_CFLAGS) -I$(APPLE2_SRC_PATH)
APPLE2_BASE_LDLIBS := -llog -landroid -lGLESv2 -lz -lOpenSLES -latomic
APPLE2_BASE_LDLIBS := -Wl,-z,text -Wl,-z,noexecstack -llog -landroid -lGLESv2 -lz -lOpenSLES -latomic
LOCAL_WHOLE_STATIC_LIBRARIES += cpufeatures

View File

@ -68,7 +68,7 @@ apple2ix_SOURCES = src/font.c src/rom.c src/misc.c src/display.c src/vm.c \
apple2ix_CFLAGS = @AM_CFLAGS@ @X_CFLAGS@
apple2ix_CCASFLAGS = $(apple2ix_CFLAGS)
apple2ix_LDFLAGS =
apple2ix_LDFLAGS = -Wl,-z,noexecstack
apple2ix_LDADD = @ASM_O@ @VIDEO_O@ @AUDIO_O@ @META_O@ @X_LIBS@
apple2ix_DEPENDENCIES = @ASM_O@ @VIDEO_O@ @AUDIO_O@ @META_O@

View File

@ -36,8 +36,8 @@
#define RestoreAltZP \
/* Apple //e set stack point to ALTZP (or not) */ \
movLQ SYM(base_stackzp), _XAX; \
subLQ SYM(base_vmem), _XAX; \
MEM2REG(movLQ, base_stackzp, _XAX); \
MEM2REG(subLQ, base_vmem, _XAX); \
orLQ $0x0100, SP_Reg_X; \
orLQ _XAX, SP_Reg_X;
@ -84,6 +84,7 @@
# define ROR_BIT 31
// x86 registers
# define _XBP %ebp /* x86 base pointer */
# define _PICREG %ebp /* used for accessing GOT */
# define _XSP %esp /* x86 stack pointer */
# define _XDI %edi
# define _XSI %esi
@ -128,31 +129,83 @@
#define ENTRY(x) .globl _UNDER(x); .balign 16; _UNDER(x)##:
#if __APPLE__
# define _AT_PLT()
# define _AT_GOTPCREL(x) (x)
#else
# define _AT_PLT() @PLT
# define _AT_GOTPCREL(x) @GOTPCREL(x)
#endif
#if !__PIC__
# define CALL(x) _UNDER(x)
# define SYM(x) _UNDER(x)
# define SYMX_PROLOGUE(x)
# define SYMX(x, IDX, SCALE) _UNDER(x)(,IDX,SCALE)
// For non-Position Independent Code, the assembly is relatively simple...
# define CALL_FN(op,fn,stk) op _UNDER(fn)
# define JUMP_FN(op,fn) op _UNDER(fn)
# define CALL_IND0(sym) callLQ *_UNDER(sym)
# define CALL_IND(sym,off,sz) callLQ *_UNDER(sym)(,off,sz)
# define JUMP_IND(sym,off,sz) jmp *_UNDER(sym)(,off,sz)
# define MEM2REG_IND(op,sym,off,sz,x) op _UNDER(sym)(,off,sz), x
# define REG2MEM_IND(op,x,sym,off,sz) op x, _UNDER(sym)(,off,sz)
# define _2MEM(op,sym) op _UNDER(sym) // op to-memory
# define REG2MEM(op,x,sym) op x, _UNDER(sym) // op register-to-memory
# define MEM2REG(op,sym,x) op _UNDER(sym), x // op memory-to-register
#else
// For PIC code, the assembly is more convoluted, because we have to access symbols only indirectly through the Global
// Offset Table and the Procedure Linkage Table. There is some redundancy in the codegen from these macros (e.g.,
// access to the same symbol back-to-back results in duplicate register loads, when we could keep using the previously
// calculated value).
# if __APPLE__
# if !__LP64__
# error unsure of __PIC__ code on i386 Mac
# endif
# define _AT_PLT
# define _LEA(sym) leaq _UNDER(sym)(%rip), _X8
# define CALL_IND0(fn) callq *_UNDER(fn)(%rip)
# define _2MEM(op,sym) op _UNDER(sym)(%rip) // op to-memory
# define REG2MEM(op,x,sym) op x, _UNDER(sym)(%rip) // op register-to-memory
# define MEM2REG(op,sym,x) op _UNDER(sym)(%rip), x // op memory-to-register
# elif __LP64__
# define _AT_PLT @PLT
# define _LEA(sym) movq _UNDER(sym)@GOTPCREL(%rip), _X8
# define CALL_IND0(fn) callq *_UNDER(fn)_AT_PLT
# define _2MEM(op,sym) _LEA(sym); op (_X8) // op to-memory
# define REG2MEM(op,x,sym) _LEA(sym); op x, (_X8) // op register-to-memory
# define MEM2REG(op,sym,x) _LEA(sym); op (_X8), x // op memory-to-register
# endif
# if __LP64__
# define CALL(x) _UNDER(x)_AT_PLT()
# define SYM(x) _UNDER(x)_AT_GOTPCREL(%rip)
# define SYMX_PROLOGUE(x) leaLQ _UNDER(x)_AT_GOTPCREL(%rip), _X8;
# define SYMX(x, IDX, SCALE) (_X8,IDX,SCALE)
# define CALL_FN(op,fn,stk) op _UNDER(fn)_AT_PLT
# define JUMP_FN(op,fn) op _UNDER(fn)_AT_PLT
# define CALL_IND(sym,off,sz) _LEA(sym); callq *(_X8,off,sz)
# define JUMP_IND(sym,off,sz) _LEA(sym); jmp *(_X8,off,sz)
# define MEM2REG_IND(op,sym,off,sz,x) _LEA(sym); op (_X8,off,sz), x
# define REG2MEM_IND(op,x,sym,off,sz) _LEA(sym); op x, (_X8,off,sz)
# else
# warning FIXME ... this is not PIC!
# define CALL(x) _UNDER(x)
# define SYM(x) _UNDER(x)
# define SYMX_PROLOGUE(x)
# define SYMX(x, IDX, SCALE) _UNDER(x)(,IDX,SCALE)
# if !__i386__
# error what architecture is this?!
# endif
// http://ewontfix.com/18/ -- "32-bit x86 Position Independent Code - It's that bad"
// 2016/05/01 : Strategy here is to (ab)use _PICREG in cpu65_run() to contain the offset to the GOT for symbol access.
// %ebx is used only for actual calls to the fn@PLT (per ABI convention). Similar to x64 PIC, use of these macros does
// result in some code duplication...
# define CALL_FN(op,fn,stk) movl stk(%esp), %ebx; \
op _UNDER(fn)@PLT;
# define _GOT_PRE(sym,reg) movl _A2_PIC_GOT(%esp), reg; \
movl _UNDER(sym)@GOT(reg), reg;
# define CALL_IND0(fn) _GOT_PRE(fn, _PICREG); calll *_PICREG;
# define CALL_IND(sym,off,sz) _GOT_PRE(sym,_PICREG); calll *(_PICREG,off,sz);
# define JUMP_FN(op,fn) op _UNDER(fn)
# define JUMP_IND(sym,off,sz) _GOT_PRE(sym,_PICREG); jmp *(_PICREG,off,sz);
# define MEM2REG_IND(op,sym,off,sz,x) _GOT_PRE(sym,_PICREG); op (_PICREG,off,sz), x;
# define REG2MEM_IND(op,x,sym,off,sz) _GOT_PRE(sym,_PICREG); op x, (_PICREG,off,sz);
# define _2MEM(op,sym) _GOT_PRE(sym,_PICREG); op (_PICREG); // op to-memory
# define REG2MEM(op,x,sym) _GOT_PRE(sym,_PICREG); op x, (_PICREG); // op register-to-memory
# define MEM2REG(op,sym,x) _GOT_PRE(sym,_PICREG); op (_PICREG), x; // op memory-to-register
# endif
#endif

View File

@ -16,33 +16,48 @@
#include "cpu-regs.h"
#include "vm.h"
#if !__PIC__
# define SAVE_Y_REG() \
REG2MEM(movb, Y_Reg, cpu65_y)
# define _POP_PICREG()
#else
# define SAVE_Y_REG() \
movb Y_Reg, %al; \
REG2MEM(movb, %al, cpu65_y)
# if __i386__
# define _A2_PIC_GOT(reg) 0x0(reg) // Assumes GOT pointer is at head of stack
# define _POP_PICREG() popl _PICREG
# else
# define _POP_PICREG()
# endif
#endif
#define CommonSaveCPUState \
movw EffectiveAddr, SYM(cpu65_ea); \
movb A_Reg, SYM(cpu65_a); \
REG2MEM(movw, EffectiveAddr, cpu65_ea); \
REG2MEM(movb, A_Reg, cpu65_a); \
xorw %ax, %ax; \
movb F_Reg, %al; \
SYMX_PROLOGUE(cpu65_flags_encode); \
movb SYMX(cpu65_flags_encode,_XAX,1), %al; \
movb %al, SYM(cpu65_f); \
movb X_Reg, SYM(cpu65_x); \
movb Y_Reg, SYM(cpu65_y); \
movb SP_Reg_L, SYM(cpu65_sp)
MEM2REG_IND(movb,cpu65_flags_encode,_XAX,1,%al); \
REG2MEM(movb, %al, cpu65_f); \
REG2MEM(movb, X_Reg, cpu65_x); \
SAVE_Y_REG(); \
REG2MEM(movb, SP_Reg_L, cpu65_sp)
#if CPU_TRACING
# define TRACE_PROLOGUE \
movw PC_Reg, SYM(cpu65_pc); \
callLQ CALL(cpu65_trace_prologue);
REG2MEM(movw, PC_Reg, cpu65_pc); \
CALL_FN(callLQ, cpu65_trace_prologue, 0x4);
# define TRACE_ARG \
callLQ CALL(cpu65_trace_arg);
CALL_FN(callLQ, cpu65_trace_arg, 0x4);
# define TRACE_ARG1 \
callLQ CALL(cpu65_trace_arg1);
CALL_FN(callLQ, cpu65_trace_arg1, 0x4);
# define TRACE_ARG2 \
callLQ CALL(cpu65_trace_arg2);
CALL_FN(callLQ, cpu65_trace_arg2, 0x4);
# define TRACE_EPILOGUE \
pushLQ _XAX; \
CommonSaveCPUState; \
popLQ _XAX; \
callLQ CALL(cpu65_trace_epilogue);
CALL_FN(callLQ, cpu65_trace_epilogue, 0x4);
#else
# define TRACE_PROLOGUE
# define TRACE_ARG
@ -58,56 +73,47 @@
#define GetFromPC_B \
movLQ PC_Reg_X, EffectiveAddr_X; \
incw PC_Reg; \
SYMX_PROLOGUE(cpu65_vmem_r); \
callLQ *SYMX(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR); \
CALL_IND(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR); \
TRACE_ARG;
#define GetFromPC_W \
movLQ PC_Reg_X, EffectiveAddr_X; \
incw EffectiveAddr; \
addw $2, PC_Reg; \
SYMX_PROLOGUE(cpu65_vmem_r); \
callLQ *SYMX(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR); \
CALL_IND(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR); \
decw EffectiveAddr; \
TRACE_ARG2; \
movb %al, %ah; \
SYMX_PROLOGUE(cpu65_vmem_r); \
callLQ *SYMX(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR); \
CALL_IND(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR); \
TRACE_ARG1;
#define JumpNextInstruction \
TRACE_PROLOGUE; \
GetFromPC_B \
movb %al, SYM(cpu65_opcode); \
movb $0, SYM(cpu65_opcycles); \
movb $0, SYM(cpu65_rw); \
SYMX_PROLOGUE(cpu65__opcodes); \
jmp *SYMX(cpu65__opcodes,_XAX,SZ_PTR);
REG2MEM(movb, %al, cpu65_opcode); \
REG2MEM(movb, $0, cpu65_opcycles); \
REG2MEM(movb, $0, cpu65_rw); \
JUMP_IND(cpu65__opcodes,_XAX,SZ_PTR);
#define GetFromEA_B \
orb $1, SYM(cpu65_rw); \
SYMX_PROLOGUE(cpu65_vmem_r); \
callLQ *SYMX(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR);
REG2MEM(orb, $1, cpu65_rw); \
CALL_IND(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR);
#define GetFromEA_W \
incw EffectiveAddr; \
SYMX_PROLOGUE(cpu65_vmem_r); \
callLQ *SYMX(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR); \
CALL_IND(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR); \
decw EffectiveAddr; \
movb %al, %ah; \
SYMX_PROLOGUE(cpu65_vmem_r); \
callLQ *SYMX(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR);
CALL_IND(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR);
#define PutToEA_B \
orb $2, SYM(cpu65_rw); \
movb %al, SYM(cpu65_d); \
SYMX_PROLOGUE(cpu65_vmem_w); \
callLQ *SYMX(cpu65_vmem_w,EffectiveAddr_X,SZ_PTR);
REG2MEM(orb, $2, cpu65_rw); \
REG2MEM(movb, %al, cpu65_d); \
CALL_IND(cpu65_vmem_w,EffectiveAddr_X,SZ_PTR);
#define GetFromMem_B(x) \
movLQ x, EffectiveAddr_X; \
SYMX_PROLOGUE(cpu65_vmem_r); \
callLQ *SYMX(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR);
CALL_IND(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR);
#define GetFromMem_W(x) \
movLQ x, EffectiveAddr_X; \
@ -117,7 +123,7 @@
jmp continue;
#define BranchXCycles \
incb SYM(cpu65_opcycles); /* +1 branch taken */ \
_2MEM(incb, cpu65_opcycles); /* +1 branch taken */ \
shlLQ $16, _XBX; \
movw PC_Reg, %bx; \
cbw; \
@ -125,7 +131,7 @@
movw %ax, PC_Reg; \
cmpb %ah, %bh; \
je 9f; \
incb SYM(cpu65_opcycles); /* +1 branch new page */ \
_2MEM(incb, cpu65_opcycles); /* +1 branch new page */ \
9: shrLQ $16, _XBX;
#define FlagC \
@ -174,14 +180,12 @@
orb %al, F_Reg;
#define Push(x) \
SYMX_PROLOGUE(apple_ii_64k); \
movb x, SYMX(apple_ii_64k,SP_Reg_X,1); \
REG2MEM_IND(movb,x,apple_ii_64k,SP_Reg_X,1); \
decb SP_Reg_L;
#define Pop(x) \
incb SP_Reg_L; \
SYMX_PROLOGUE(apple_ii_64k); \
movb SYMX(apple_ii_64k,SP_Reg_X,1), x;
MEM2REG_IND(movb,apple_ii_64k,SP_Reg_X,1,x);
/* Immediate Addressing - the operand is contained in the second byte of the
instruction. */
@ -191,8 +195,7 @@
#if CPU_TRACING
#define GetImm \
_GetImm \
SYMX_PROLOGUE(cpu65_vmem_r); \
callLQ *SYMX(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR); \
CALL_IND(cpu65_vmem_r,EffectiveAddr_X,SZ_PTR); \
TRACE_ARG;
#else
#define GetImm \
@ -237,7 +240,7 @@
#define GetAbs_X \
_GetAbs_X \
incb SYM(cpu65_opcycles); /* +1 cycle on page boundary */ \
_2MEM(incb, cpu65_opcycles); /* +1 cycle on page boundary */ \
9: movLQ _XAX, EffectiveAddr_X;
#define GetAbs_X_STx \
@ -252,7 +255,7 @@
#define GetAbs_Y \
_GetAbs_Y \
incb SYM(cpu65_opcycles); /* +1 cycle on page boundary */ \
_2MEM(incb, cpu65_opcycles); /* +1 cycle on page boundary */ \
9: movLQ _XAX, EffectiveAddr_X;
#define GetAbs_Y_STA \
@ -315,7 +318,7 @@
#define GetIndZPage_Y \
_GetIndZPage_Y \
adcb $0, %ah; \
incb SYM(cpu65_opcycles); /* +1 cycle on page boundary */ \
_2MEM(incb, cpu65_opcycles); /* +1 cycle on page boundary */ \
9: movLQ _XAX, EffectiveAddr_X;
#define GetIndZPage_Y_STA \
@ -334,22 +337,22 @@
jz 6f; \
testb $0x60, A_Reg; \
jz 6f; \
callLQ CALL(debug_illegal_bcd); \
CALL_FN(callLQ, debug_illegal_bcd, 0x4); \
6: testb $0x08, A_Reg; \
jz 7f; \
testb $0x06, A_Reg; \
jz 7f; \
callLQ CALL(debug_illegal_bcd); \
CALL_FN(callLQ, debug_illegal_bcd, 0x4); \
7: testb $0x80, %al; \
jz 8f; \
testb $0x60, %al; \
jz 8f; \
callLQ CALL(debug_illegal_bcd); \
CALL_FN(callLQ, debug_illegal_bcd, 0x4); \
8: testb $0x08, %al; \
jz 9f; \
testb $0x06, %al; \
jz 9f; \
callLQ CALL(debug_illegal_bcd); \
CALL_FN(callLQ, debug_illegal_bcd, 0x4); \
9:
#else
#define DebugBCDCheck
@ -526,7 +529,7 @@
// Decimal mode
ENTRY(op_ADC_dec)
incb SYM(cpu65_opcycles) // +1 cycle
_2MEM(incb, cpu65_opcycles) // +1 cycle
GetFromEA_B
DebugBCDCheck
bt $C_Flag_Bit, AF_Reg_X
@ -579,7 +582,7 @@ _daa_finish: popq _XBX
#define maybe_DoADC_d \
testb $D_Flag, F_Reg; /* Decimal mode? */ \
jnz CALL(op_ADC_dec) /* Yes, jump to decimal version */
JUMP_FN(jnz, op_ADC_dec) /* Yes, jump to decimal version */
ENTRY(op_ADC_imm) // 0x69
GetImm
@ -601,7 +604,7 @@ ENTRY(op_ADC_zpage_x) // 0x75
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_ADC_zpage_y)
jmp CALL(op_NOP)
JUMP_FN(jmp, op_NOP)
ENTRY(op_ADC_abs) // 0x6d
GetAbs
@ -662,7 +665,7 @@ ENTRY(op_AND_zpage_x) // 0x35
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_AND_zpage_y)
jmp CALL(op_NOP)
JUMP_FN(jmp, op_NOP)
ENTRY(op_AND_abs) // 0x2d
GetAbs
@ -931,8 +934,7 @@ ENTRY(op_BRK)
orb $(B_Flag|X_Flag), F_Reg
xorw %ax, %ax
movb F_Reg, %al
SYMX_PROLOGUE(cpu65_flags_encode)
movb SYMX(cpu65_flags_encode,_XAX,1), %al
MEM2REG_IND(movb,cpu65_flags_encode,_XAX,1,%al)
Push(%al)
orb $I_Flag, F_Reg
movw $0xFFFE, EffectiveAddr // ROM interrupt vector
@ -1020,7 +1022,7 @@ ENTRY(op_CMP_zpage_x) // 0xd5
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_CMP_zpage_y)
jmp CALL(op_NOP)
JUMP_FN(jmp, op_NOP)
ENTRY(op_CMP_abs) // 0xcd
GetAbs
@ -1165,7 +1167,7 @@ ENTRY(op_EOR_zpage_x) // 0x55
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_EOR_zpage_y)
jmp CALL(op_NOP)
JUMP_FN(jmp, op_NOP)
ENTRY(op_EOR_abs) // 0x4d
GetAbs
@ -1328,7 +1330,7 @@ ENTRY(op_LDA_zpage_x) // 0xb5
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_LDA_zpage_y)
jmp CALL(op_NOP)
JUMP_FN(jmp, op_NOP)
ENTRY(op_LDA_abs) // 0xad
GetAbs
@ -1475,7 +1477,7 @@ ENTRY(op_ORA_zpage_x) // 0x15
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_ORA_zpage_y)
jmp CALL(op_NOP)
JUMP_FN(jmp, op_NOP)
ENTRY(op_ORA_abs) // 0x0d
GetAbs
@ -1522,8 +1524,7 @@ ENTRY(op_PHA) // 0x48
ENTRY(op_PHP) // 0x08
movb F_Reg, %al
SYMX_PROLOGUE(cpu65_flags_encode)
movb SYMX(cpu65_flags_encode,_XAX,1), %al
MEM2REG_IND(movb,cpu65_flags_encode,_XAX,1,%al)
Push(%al)
Continue
@ -1566,12 +1567,11 @@ ENTRY(op_PLA) // 0x68
ENTRY(op_PLP) // 0x28
Pop(%al)
SYMX_PROLOGUE(cpu65_flags_decode)
#if __PIC__
movb SYMX(cpu65_flags_decode,_XAX,1), %al
MEM2REG_IND(movb,cpu65_flags_decode,_XAX,1,%al)
movb %al, F_Reg
#else
movb SYMX(cpu65_flags_decode,_XAX,1), F_Reg
MEM2REG_IND(movb,cpu65_flags_decode,_XAX,1,F_Reg)
#endif
orb $(B_Flag|X_Flag), F_Reg
Continue
@ -1668,12 +1668,11 @@ ENTRY(op_ROR_abs_x) // 0x7e
ENTRY(op_RTI) // 0x40
Pop(%al)
SYMX_PROLOGUE(cpu65_flags_decode)
#if __PIC__
movb SYMX(cpu65_flags_decode,_XAX,1), %al
MEM2REG_IND(movb,cpu65_flags_decode,_XAX,1,%al)
movb %al, F_Reg
#else
movb SYMX(cpu65_flags_decode,_XAX,1), F_Reg
MEM2REG_IND(movb,cpu65_flags_decode,_XAX,1,F_Reg)
#endif
orb $(B_Flag|X_Flag), F_Reg
Pop(%al)
@ -1710,7 +1709,7 @@ ENTRY(op_RTS) // 0x60
---------------------------------- */
ENTRY(op_SBC_dec)
incb SYM(cpu65_opcycles) // +1 cycle
_2MEM(incb, cpu65_opcycles) // +1 cycle
GetFromEA_B
DebugBCDCheck
bt $C_Flag_Bit, AF_Reg_X
@ -1768,7 +1767,7 @@ _das_finish: popq _XBX
#define maybe_DoSBC_d \
testb $D_Flag, F_Reg; /* Decimal mode? */ \
jnz CALL(op_SBC_dec) /* Yes, jump to decimal version */
JUMP_FN(jnz, op_SBC_dec) /* Yes, jump to decimal version */
ENTRY(op_SBC_imm) // 0xe9
GetImm
@ -1790,7 +1789,7 @@ ENTRY(op_SBC_zpage_x) // 0xf5
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_SBC_zpage_y)
jmp CALL(op_NOP)
JUMP_FN(jmp, op_NOP)
ENTRY(op_SBC_abs) // 0xed
GetAbs
@ -1898,7 +1897,7 @@ ENTRY(op_STA_zpage_x) // 0x95
// UNIMPLEMENTED : W65C02S datasheet
ENTRY(op_STA_zpage_y)
jmp CALL(op_NOP)
JUMP_FN(jmp, op_NOP)
ENTRY(op_STA_abs) // 0x8d
GetAbs
@ -2150,20 +2149,19 @@ ENTRY(op_WAI_65c02)
------------------------------------------------------------------------- */
continue:
movzbLQ SYM(cpu65_opcode), _XAX
SYMX_PROLOGUE(cpu65__opcycles)
movb SYMX(cpu65__opcycles,_XAX,1), %al
addb SYM(cpu65_opcycles), %al
movb %al, SYM(cpu65_opcycles)
MEM2REG(movzbLQ, cpu65_opcode, _XAX)
MEM2REG_IND(movb,cpu65__opcycles,_XAX,1,%al)
MEM2REG(addb, cpu65_opcycles, %al)
REG2MEM(movb, %al, cpu65_opcycles)
TRACE_EPILOGUE
addl %eax, SYM(cpu65_cycle_count)
subl %eax, SYM(gc_cycles_timer_0)
subl %eax, SYM(gc_cycles_timer_1)
subl %eax, SYM(cpu65_cycles_to_execute)
REG2MEM(addl, %eax, cpu65_cycle_count)
REG2MEM(subl, %eax, gc_cycles_timer_0)
REG2MEM(subl, %eax, gc_cycles_timer_1)
REG2MEM(subl, %eax, cpu65_cycles_to_execute)
jle exit_cpu65_run
continue1: xorLQ _XAX, _XAX
orb SYM(cpu65__signal), %al
MEM2REG(orb, cpu65__signal, %al)
jnz exception
JumpNextInstruction
@ -2173,12 +2171,12 @@ continue1: xorLQ _XAX, _XAX
exception: testb $ResetSig, %al
jz ex_irq
testb $0xff, SYM(joy_button0) // OpenApple
REG2MEM(testb, $0xff, joy_button0) // OpenApple
jnz exit_reinit
testb $0xff, SYM(joy_button1) // ClosedApple
REG2MEM(testb, $0xff, joy_button1) // ClosedApple
jnz exit_reinit
ex_reset: movb $0, SYM(cpu65__signal)
ex_reset: REG2MEM(movb, $0, cpu65__signal)
movw $0xFFFC, EffectiveAddr // ROM reset vector
GetFromEA_W
movw %ax, PC_Reg
@ -2200,8 +2198,7 @@ ex_irq: testb $I_Flag, F_Reg // Already interrupt
orb $X_Flag, F_Reg
xorw %ax, %ax
movb F_Reg, %al
SYMX_PROLOGUE(cpu65_flags_encode)
movb SYMX(cpu65_flags_encode,_XAX,1), %al
MEM2REG_IND(movb,cpu65_flags_encode,_XAX,1,%al)
Push(%al)
orb $(B_Flag | I_Flag), F_Reg
//andb $~D_Flag, F_Reg // AppleWin clears Decimal bit?
@ -2221,34 +2218,43 @@ ENTRY(cpu65_run)
pushLQ _XDI
pushLQ _XSI
pushLQ _XBX
#ifdef __LP64__
#if __LP64__
// NOTE: should we be also preserving r12-r15?
#endif
#if __PIC__ && __i386__
calll .Lget_pc_thunk0
.Lget_pc_thunk0:
_POP_PICREG()
.Lget_pc_thunk1:
addl $_GLOBAL_OFFSET_TABLE_+(.Lget_pc_thunk1 - .Lget_pc_thunk0), _PICREG
pushl _PICREG
#endif
// Restore CPU state when being called from C.
movzwLQ SYM(cpu65_ea), EffectiveAddr_X
movzwLQ SYM(cpu65_pc), PC_Reg_X
movzbLQ SYM(cpu65_a), AF_Reg_X
movzbLQ SYM(cpu65_f), _XAX
SYMX_PROLOGUE(cpu65_flags_decode)
MEM2REG(movzwLQ, cpu65_ea, EffectiveAddr_X)
MEM2REG(movzwLQ, cpu65_pc, PC_Reg_X)
MEM2REG(movzbLQ, cpu65_a, AF_Reg_X)
MEM2REG(movzbLQ, cpu65_x, XY_Reg_X)
MEM2REG(movzbLQ, cpu65_f, _XAX)
#if __PIC__
movb SYMX(cpu65_flags_decode,_XAX,1), %al
MEM2REG_IND(movb,cpu65_flags_decode,_XAX,1,%al)
movb %al, F_Reg
MEM2REG(movb, cpu65_y, %al)
movb %al, Y_Reg
#else
movb SYMX(cpu65_flags_decode,_XAX,1), F_Reg
MEM2REG_IND(movb,cpu65_flags_decode,_XAX,1,F_Reg)
MEM2REG(movb, cpu65_y, Y_Reg)
#endif
movzbLQ SYM(cpu65_x), XY_Reg_X
movb SYM(cpu65_y), Y_Reg
movzbLQ SYM(cpu65_sp), SP_Reg_X
MEM2REG(movzbLQ, cpu65_sp, SP_Reg_X)
#ifdef APPLE2_VM
RestoreAltZP
#endif
cmpb $0, SYM(emul_reinitialize)
REG2MEM(cmpb, $0, emul_reinitialize)
jnz enter_reinit
jmp continue1
enter_reinit: movb $0, SYM(emul_reinitialize)
enter_reinit: REG2MEM(movb, $0, emul_reinitialize)
jmp ex_reset
/* -------------------------------------------------------------------------
@ -2257,16 +2263,18 @@ enter_reinit: movb $0, SYM(emul_reinitialize)
exit_cpu65_run:
// Save CPU state when returning from being called from C
movw PC_Reg, SYM(cpu65_pc)
REG2MEM(movw, PC_Reg, cpu65_pc)
CommonSaveCPUState
_POP_PICREG()
popLQ _XBX
popLQ _XSI
popLQ _XDI
popLQ _XBP
ret
exit_reinit: movb $0, SYM(cpu65__signal)
movb $1, SYM(emul_reinitialize)
exit_reinit: REG2MEM(movb, $0, cpu65__signal)
REG2MEM(movb, $1, emul_reinitialize)
_POP_PICREG()
popLQ _XBX
popLQ _XSI
popLQ _XDI
@ -2281,8 +2289,7 @@ ENTRY(cpu65_direct_write)
pushLQ EffectiveAddr_X
movLQ 8(_XSP),EffectiveAddr_X
movLQ 12(_XSP),_XAX
SYMX_PROLOGUE(cpu65_vmem_w)
callLQ *SYMX(cpu65_vmem_w,EffectiveAddr_X,SZ_PTR)
CALL_IND(cpu65_vmem_w,EffectiveAddr_X,SZ_PTR)
popLQ EffectiveAddr_X
ret

View File

@ -16,36 +16,46 @@
#include "vm.h"
#include "cpu-regs.h"
/*
* These "glue" macros code become auto-generated trampoline functions for the exclusive use of cpu65_run() CPU module
* to make calls back into C that conform with the x86 and x86_64 calling ABIs.
*/
#if __PIC__ && __i386__
# define _A2_PIC_GOT(reg) 0x4(reg) // Stack offset assumes a CALL has been made that pushed %eip
#endif
#define _PUSH_COUNT ((/*args:*/7+/*ret:*/1) * SZ_PTR)
#define GLUE_EXTERN_C_READ(func)
#define GLUE_BANK_MAYBEREAD(func,pointer) \
ENTRY(func) testLQ $SS_CXROM, SYM(softswitches); \
ENTRY(func) REG2MEM(testLQ, $SS_CXROM, softswitches); \
jnz 1f; \
callLQ *SYM(pointer); \
CALL_IND0(pointer); \
ret; \
1: addLQ SYM(pointer),EffectiveAddr_X; \
1: MEM2REG(addLQ, pointer, EffectiveAddr_X); \
movb (EffectiveAddr_X),%al; \
subLQ SYM(pointer),EffectiveAddr_X; \
MEM2REG(subLQ, pointer, EffectiveAddr_X); \
ret;
#define GLUE_BANK_READ(func,pointer) \
ENTRY(func) addLQ SYM(pointer),EffectiveAddr_X; \
ENTRY(func) MEM2REG(addLQ, pointer, EffectiveAddr_X); \
movb (EffectiveAddr_X),%al; \
subLQ SYM(pointer),EffectiveAddr_X; \
MEM2REG(subLQ, pointer, EffectiveAddr_X); \
ret;
#define GLUE_BANK_WRITE(func,pointer) \
ENTRY(func) addLQ SYM(pointer),EffectiveAddr_X; \
ENTRY(func) MEM2REG(addLQ, pointer, EffectiveAddr_X); \
movb %al,(EffectiveAddr_X); \
subLQ SYM(pointer),EffectiveAddr_X; \
MEM2REG(subLQ, pointer, EffectiveAddr_X); \
ret;
#define GLUE_BANK_MAYBEWRITE(func,pointer) \
ENTRY(func) addLQ SYM(pointer),EffectiveAddr_X; \
cmpl $0,SYM(pointer); \
ENTRY(func) MEM2REG(addLQ, pointer, EffectiveAddr_X); \
REG2MEM(cmpl, $0, pointer); \
jz 1f; \
movb %al,(EffectiveAddr_X); \
1: subLQ SYM(pointer),EffectiveAddr_X; \
1: MEM2REG(subLQ, pointer, EffectiveAddr_X); \
ret;
@ -68,7 +78,7 @@ ENTRY(func) pushLQ _XAX; \
pushLQ PC_Reg_X; \
andLQ $0xff,_XAX; \
_PUSH_ARGS \
callLQ CALL(c_##func); \
CALL_FN(callLQ, c_##func, _PUSH_COUNT); \
_POP_ARGS \
popLQ PC_Reg_X; \
popLQ SP_Reg_X; \
@ -77,6 +87,15 @@ ENTRY(func) pushLQ _XAX; \
popLQ _XAX; \
ret;
#if __PIC__ && __i386__
# define _PUSH_GOT() movl _A2_PIC_GOT(%esp), _PICREG; \
pushl _PICREG;
# define _POP_GOT() addl $4, %esp
#else
# define _PUSH_GOT()
# define _POP_GOT()
#endif
// TODO FIXME : implement CDECL prologue/epilogues...
#define _GLUE_C_READ(func, ...) \
ENTRY(func) pushLQ XY_Reg_X; \
@ -85,7 +104,7 @@ ENTRY(func) pushLQ XY_Reg_X; \
pushLQ PC_Reg_X; \
pushLQ _XAX; /* HACK: works around mysterious issue with generated mov(_XAX), _XAX ... */ \
pushLQ EffectiveAddr_X; /* ea is arg0 (and preserved) */ \
callLQ CALL(c_##func); \
CALL_FN(callLQ, c_##func, _PUSH_COUNT); \
popLQ EffectiveAddr_X; /* restore ea */ \
movb %al, %dl; \
popLQ _XAX; /* ... ugh */ \
@ -94,7 +113,9 @@ ENTRY(func) pushLQ XY_Reg_X; \
popLQ SP_Reg_X; \
popLQ AF_Reg_X; \
popLQ XY_Reg_X; \
_PUSH_GOT(); \
__VA_ARGS__ \
_POP_GOT(); \
ret;
// TODO FIXME : implement CDECL prologue/epilogues...