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_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_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 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_CFLAGS = @AM_CFLAGS@ @X_CFLAGS@
apple2ix_CCASFLAGS = $(apple2ix_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_LDADD = @ASM_O@ @VIDEO_O@ @AUDIO_O@ @META_O@ @X_LIBS@
apple2ix_DEPENDENCIES = @ASM_O@ @VIDEO_O@ @AUDIO_O@ @META_O@ apple2ix_DEPENDENCIES = @ASM_O@ @VIDEO_O@ @AUDIO_O@ @META_O@

View File

@ -36,8 +36,8 @@
#define RestoreAltZP \ #define RestoreAltZP \
/* Apple //e set stack point to ALTZP (or not) */ \ /* Apple //e set stack point to ALTZP (or not) */ \
movLQ SYM(base_stackzp), _XAX; \ MEM2REG(movLQ, base_stackzp, _XAX); \
subLQ SYM(base_vmem), _XAX; \ MEM2REG(subLQ, base_vmem, _XAX); \
orLQ $0x0100, SP_Reg_X; \ orLQ $0x0100, SP_Reg_X; \
orLQ _XAX, SP_Reg_X; orLQ _XAX, SP_Reg_X;
@ -84,6 +84,7 @@
# define ROR_BIT 31 # define ROR_BIT 31
// x86 registers // x86 registers
# define _XBP %ebp /* x86 base pointer */ # define _XBP %ebp /* x86 base pointer */
# define _PICREG %ebp /* used for accessing GOT */
# define _XSP %esp /* x86 stack pointer */ # define _XSP %esp /* x86 stack pointer */
# define _XDI %edi # define _XDI %edi
# define _XSI %esi # define _XSI %esi
@ -128,31 +129,83 @@
#define ENTRY(x) .globl _UNDER(x); .balign 16; _UNDER(x)##: #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__ #if !__PIC__
# define CALL(x) _UNDER(x)
# define SYM(x) _UNDER(x) // For non-Position Independent Code, the assembly is relatively simple...
# define SYMX_PROLOGUE(x)
# define SYMX(x, IDX, SCALE) _UNDER(x)(,IDX,SCALE) # 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 #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__ # if __LP64__
# define CALL(x) _UNDER(x)_AT_PLT() # define CALL_FN(op,fn,stk) op _UNDER(fn)_AT_PLT
# define SYM(x) _UNDER(x)_AT_GOTPCREL(%rip) # define JUMP_FN(op,fn) op _UNDER(fn)_AT_PLT
# define SYMX_PROLOGUE(x) leaLQ _UNDER(x)_AT_GOTPCREL(%rip), _X8; # define CALL_IND(sym,off,sz) _LEA(sym); callq *(_X8,off,sz)
# define SYMX(x, IDX, SCALE) (_X8,IDX,SCALE) # 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 # else
# warning FIXME ... this is not PIC!
# define CALL(x) _UNDER(x) # if !__i386__
# define SYM(x) _UNDER(x) # error what architecture is this?!
# define SYMX_PROLOGUE(x) # endif
# define SYMX(x, IDX, SCALE) _UNDER(x)(,IDX,SCALE)
// 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
#endif #endif

View File

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

View File

@ -16,36 +16,46 @@
#include "vm.h" #include "vm.h"
#include "cpu-regs.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_EXTERN_C_READ(func)
#define GLUE_BANK_MAYBEREAD(func,pointer) \ #define GLUE_BANK_MAYBEREAD(func,pointer) \
ENTRY(func) testLQ $SS_CXROM, SYM(softswitches); \ ENTRY(func) REG2MEM(testLQ, $SS_CXROM, softswitches); \
jnz 1f; \ jnz 1f; \
callLQ *SYM(pointer); \ CALL_IND0(pointer); \
ret; \ ret; \
1: addLQ SYM(pointer),EffectiveAddr_X; \ 1: MEM2REG(addLQ, pointer, EffectiveAddr_X); \
movb (EffectiveAddr_X),%al; \ movb (EffectiveAddr_X),%al; \
subLQ SYM(pointer),EffectiveAddr_X; \ MEM2REG(subLQ, pointer, EffectiveAddr_X); \
ret; ret;
#define GLUE_BANK_READ(func,pointer) \ #define GLUE_BANK_READ(func,pointer) \
ENTRY(func) addLQ SYM(pointer),EffectiveAddr_X; \ ENTRY(func) MEM2REG(addLQ, pointer, EffectiveAddr_X); \
movb (EffectiveAddr_X),%al; \ movb (EffectiveAddr_X),%al; \
subLQ SYM(pointer),EffectiveAddr_X; \ MEM2REG(subLQ, pointer, EffectiveAddr_X); \
ret; ret;
#define GLUE_BANK_WRITE(func,pointer) \ #define GLUE_BANK_WRITE(func,pointer) \
ENTRY(func) addLQ SYM(pointer),EffectiveAddr_X; \ ENTRY(func) MEM2REG(addLQ, pointer, EffectiveAddr_X); \
movb %al,(EffectiveAddr_X); \ movb %al,(EffectiveAddr_X); \
subLQ SYM(pointer),EffectiveAddr_X; \ MEM2REG(subLQ, pointer, EffectiveAddr_X); \
ret; ret;
#define GLUE_BANK_MAYBEWRITE(func,pointer) \ #define GLUE_BANK_MAYBEWRITE(func,pointer) \
ENTRY(func) addLQ SYM(pointer),EffectiveAddr_X; \ ENTRY(func) MEM2REG(addLQ, pointer, EffectiveAddr_X); \
cmpl $0,SYM(pointer); \ REG2MEM(cmpl, $0, pointer); \
jz 1f; \ jz 1f; \
movb %al,(EffectiveAddr_X); \ movb %al,(EffectiveAddr_X); \
1: subLQ SYM(pointer),EffectiveAddr_X; \ 1: MEM2REG(subLQ, pointer, EffectiveAddr_X); \
ret; ret;
@ -68,7 +78,7 @@ ENTRY(func) pushLQ _XAX; \
pushLQ PC_Reg_X; \ pushLQ PC_Reg_X; \
andLQ $0xff,_XAX; \ andLQ $0xff,_XAX; \
_PUSH_ARGS \ _PUSH_ARGS \
callLQ CALL(c_##func); \ CALL_FN(callLQ, c_##func, _PUSH_COUNT); \
_POP_ARGS \ _POP_ARGS \
popLQ PC_Reg_X; \ popLQ PC_Reg_X; \
popLQ SP_Reg_X; \ popLQ SP_Reg_X; \
@ -77,6 +87,15 @@ ENTRY(func) pushLQ _XAX; \
popLQ _XAX; \ popLQ _XAX; \
ret; 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... // TODO FIXME : implement CDECL prologue/epilogues...
#define _GLUE_C_READ(func, ...) \ #define _GLUE_C_READ(func, ...) \
ENTRY(func) pushLQ XY_Reg_X; \ ENTRY(func) pushLQ XY_Reg_X; \
@ -85,7 +104,7 @@ ENTRY(func) pushLQ XY_Reg_X; \
pushLQ PC_Reg_X; \ pushLQ PC_Reg_X; \
pushLQ _XAX; /* HACK: works around mysterious issue with generated mov(_XAX), _XAX ... */ \ pushLQ _XAX; /* HACK: works around mysterious issue with generated mov(_XAX), _XAX ... */ \
pushLQ EffectiveAddr_X; /* ea is arg0 (and preserved) */ \ pushLQ EffectiveAddr_X; /* ea is arg0 (and preserved) */ \
callLQ CALL(c_##func); \ CALL_FN(callLQ, c_##func, _PUSH_COUNT); \
popLQ EffectiveAddr_X; /* restore ea */ \ popLQ EffectiveAddr_X; /* restore ea */ \
movb %al, %dl; \ movb %al, %dl; \
popLQ _XAX; /* ... ugh */ \ popLQ _XAX; /* ... ugh */ \
@ -94,7 +113,9 @@ ENTRY(func) pushLQ XY_Reg_X; \
popLQ SP_Reg_X; \ popLQ SP_Reg_X; \
popLQ AF_Reg_X; \ popLQ AF_Reg_X; \
popLQ XY_Reg_X; \ popLQ XY_Reg_X; \
_PUSH_GOT(); \
__VA_ARGS__ \ __VA_ARGS__ \
_POP_GOT(); \
ret; ret;
// TODO FIXME : implement CDECL prologue/epilogues... // TODO FIXME : implement CDECL prologue/epilogues...