diff options
-rw-r--r-- | Makefile | 16 | ||||
-rw-r--r-- | Makefile.libretro | 176 | ||||
-rwxr-xr-x | configure | 2 | ||||
-rw-r--r-- | frontend/cspace_arm.S | 3 | ||||
-rw-r--r-- | frontend/cspace_neon.S (renamed from frontend/cspace_neon.s) | 14 | ||||
-rw-r--r-- | include/arm_features.h | 16 | ||||
-rw-r--r-- | libpcsxcore/gte_arm.S | 47 | ||||
-rw-r--r-- | libpcsxcore/gte_neon.S | 23 | ||||
-rw-r--r-- | libpcsxcore/new_dynarec/linkage_arm.S | 219 | ||||
-rw-r--r-- | plugins/dfsound/arm_utils.S | 18 | ||||
-rw-r--r-- | tools/gas-preprocessor.pl | 527 |
11 files changed, 674 insertions, 387 deletions
@@ -1,9 +1,8 @@ # Makefile for PCSX ReARMed # default stuff goes here, so that config can override -TARGET = pcsx +TARGET ?= pcsx CFLAGS += -Wall -ggdb -Iinclude -ffast-math -LDLIBS += -lpthread ifndef DEBUG CFLAGS += -O2 -DNDEBUG endif @@ -13,6 +12,7 @@ CXXFLAGS += $(CFLAGS) all: config.mak target_ plugins_ +ifndef NO_CONFIG_MAK ifneq ($(wildcard config.mak),) config.mak: ./configure @echo $@ is out-of-date, running configure @@ -23,10 +23,16 @@ config.mak: @echo "Please run ./configure before running make!" @exit 1 endif +else # NO_CONFIG_MAK +config.mak: +endif + -include Makefile.local -CC_LINK = $(CC) +CC_LINK ?= $(CC) +CC_AS ?= $(CC) LDFLAGS += $(MAIN_LDFLAGS) +EXTRA_LDFLAGS ?= -Wl,-Map=$@.map LDLIBS += $(MAIN_LDLIBS) ifdef PCNT CFLAGS += -DPCNT @@ -228,13 +234,13 @@ frontend/revision.h: FORCE @rm $@_ %.o: %.S - $(CC) $(CFLAGS) -c $^ -o $@ + $(CC_AS) $(CFLAGS) -c $^ -o $@ target_: $(TARGET) $(TARGET): $(OBJS) - $(CC_LINK) -o $@ $^ $(LDFLAGS) $(LDLIBS) -Wl,-Map=$@.map + $(CC_LINK) -o $@ $^ $(LDFLAGS) $(LDLIBS) $(EXTRA_LDFLAGS) clean: $(PLAT_CLEAN) clean_plugins $(RM) $(TARGET) $(OBJS) $(TARGET).map frontend/revision.h diff --git a/Makefile.libretro b/Makefile.libretro index d8288f5..bb07fc3 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -1,16 +1,5 @@ # Makefile for PCSX ReARMed (libretro) -# default stuff goes here, so that config can override -CFLAGS += -Wall -ggdb -Iinclude -ffast-math -ifndef DEBUG -CFLAGS += -O2 -DNDEBUG -endif -CXXFLAGS += $(CFLAGS) -#DRC_DBG = 1 -#PCNT = 1 - -all: target_ plugins_ - ifeq ($(platform),) platform = unix ifeq ($(shell uname -a),) @@ -27,6 +16,7 @@ endif CC ?= gcc CXX ?= g++ AS ?= as +CC_AS ?= $(CC) ifeq ($(platform), unix) TARGET := snes9x_next_libretro.so @@ -42,11 +32,15 @@ ARCH := arm fpic := -fPIC SHARED := -dynamiclib -CC = clang -arch armv7 -isysroot $(IOSSDK) -CXX = clang++ -arch armv7 -isysroot $(IOSSDK) -CFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon -ASFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon + CC = clang -arch armv7 -isysroot $(IOSSDK) + CXX = clang++ -arch armv7 -isysroot $(IOSSDK) + CC_AS = perl ./tools/gas-preprocessor.pl $(CC) + CFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon + ASFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon HAVE_NEON = 1 +#TODO +# BUILTIN_GPU = neon +# USE_DYNAREC = 1 CFLAGS += -DIOS else ifeq ($(platform), ps3) TARGET := snes9x_next_libretro_ps3.a @@ -101,160 +95,20 @@ else CFLAGS += -D__WIN32__ -D__WIN32_LIBRETRO__ endif -CFLAGS += -fPIC -ASFLAGS += -LDFLAGS += - +CFLAGS += -fPIC ifneq ($(platform),qnx) LDLIBS += -lpthread MAIN_LDLIBS += -ldl endif -MAIN_LDFLAGS += -shared +MAIN_LDFLAGS += -shared MAIN_LDLIBS += -lm -lz -PLUGIN_CFLAGS += -fPIC +EXTRA_LDFLAGS = TARGET ?= libretro.so PLATFORM = libretro BUILTIN_GPU ?= peops SOUND_DRIVERS = libretro -#PLUGINS = plugins/dfxvideo/gpu_peops.so plugins/gpu_unai/gpu_unai.so - -CC_LINK = $(CC) -LDFLAGS += $(MAIN_LDFLAGS) -LDLIBS += $(MAIN_LDLIBS) -ifdef PCNT -CFLAGS += -DPCNT -endif - -# core -OBJS += libpcsxcore/cdriso.o libpcsxcore/cdrom.o libpcsxcore/cheat.o libpcsxcore/debug.o \ - libpcsxcore/decode_xa.o libpcsxcore/disr3000a.o libpcsxcore/mdec.o \ - libpcsxcore/misc.o libpcsxcore/plugins.o libpcsxcore/ppf.o libpcsxcore/psxbios.o \ - libpcsxcore/psxcommon.o libpcsxcore/psxcounters.o libpcsxcore/psxdma.o libpcsxcore/psxhle.o \ - libpcsxcore/psxhw.o libpcsxcore/psxinterpreter.o libpcsxcore/psxmem.o libpcsxcore/r3000a.o \ - libpcsxcore/sio.o libpcsxcore/socket.o libpcsxcore/spu.o -OBJS += libpcsxcore/gte.o libpcsxcore/gte_nf.o libpcsxcore/gte_divider.o -ifeq "$(ARCH)" "arm" -OBJS += libpcsxcore/gte_arm.o -endif -ifeq "$(HAVE_NEON)" "1" -OBJS += libpcsxcore/gte_neon.o -endif -libpcsxcore/psxbios.o: CFLAGS += -Wno-nonnull - -# dynarec -ifeq "$(USE_DYNAREC)" "1" -OBJS += libpcsxcore/new_dynarec/new_dynarec.o libpcsxcore/new_dynarec/linkage_arm.o -OBJS += libpcsxcore/new_dynarec/pcsxmem.o -else -libpcsxcore/new_dynarec/emu_if.o: CFLAGS += -DDRC_DISABLE -endif -OBJS += libpcsxcore/new_dynarec/emu_if.o -libpcsxcore/new_dynarec/new_dynarec.o: libpcsxcore/new_dynarec/assem_arm.c \ - libpcsxcore/new_dynarec/pcsxmem_inline.c -libpcsxcore/new_dynarec/new_dynarec.o: CFLAGS += -Wno-all -Wno-pointer-sign -ifdef DRC_DBG -libpcsxcore/new_dynarec/emu_if.o: CFLAGS += -D_FILE_OFFSET_BITS=64 -CFLAGS += -DDRC_DBG -endif -ifeq "$(DRC_CACHE_BASE)" "1" -libpcsxcore/new_dynarec/%.o: CFLAGS += -DBASE_ADDR_FIXED=1 -endif - -# spu -OBJS += plugins/dfsound/dma.o plugins/dfsound/freeze.o \ - plugins/dfsound/registers.o plugins/dfsound/spu.o \ - plugins/dfsound/out.o -plugins/dfsound/spu.o: plugins/dfsound/adsr.c plugins/dfsound/reverb.c \ - plugins/dfsound/xa.c -ifeq "$(ARCH)" "arm" -OBJS += plugins/dfsound/arm_utils.o -endif -plugins/dfsound/out.o: CFLAGS += -DHAVE_LIBRETRO - -# builtin gpu -OBJS += plugins/gpulib/gpu.o plugins/gpulib/vout_pl.o -ifeq "$(BUILTIN_GPU)" "neon" -OBJS += plugins/gpu_neon/psx_gpu_if.o plugins/gpu_neon/psx_gpu/psx_gpu_arm_neon.o -plugins/gpu_neon/psx_gpu_if.o: CFLAGS += -DNEON_BUILD -DTEXTURE_CACHE_4BPP -DTEXTURE_CACHE_8BPP -plugins/gpu_neon/psx_gpu_if.o: plugins/gpu_neon/psx_gpu/*.c -endif -ifeq "$(BUILTIN_GPU)" "peops" -# note: code is not safe for strict-aliasing? (Castlevania problems) -plugins/dfxvideo/gpulib_if.o: CFLAGS += -fno-strict-aliasing -plugins/dfxvideo/gpulib_if.o: plugins/dfxvideo/prim.c plugins/dfxvideo/soft.c -OBJS += plugins/dfxvideo/gpulib_if.o -endif -ifeq "$(BUILTIN_GPU)" "unai" -OBJS += plugins/gpu_unai/gpulib_if.o -ifeq "$(ARCH)" "arm" -OBJS += plugins/gpu_unai/gpu_arm.o -endif -plugins/gpu_unai/gpulib_if.o: CFLAGS += -DREARMED -O3 -CC_LINK = $(CXX) -endif - -# cdrcimg -OBJS += plugins/cdrcimg/cdrcimg.o - -# dfinput -OBJS += plugins/dfinput/main.o plugins/dfinput/pad.o plugins/dfinput/guncon.o - -# frontend/gui -OBJS += frontend/cspace.o -ifeq "$(HAVE_NEON)" "1" -OBJS += frontend/cspace_neon.o -else -ifeq "$(ARCH)" "arm" -OBJS += frontend/cspace_arm.o -endif -endif - -CFLAGS += -DFRONTEND_SUPPORTS_RGB565 -DNO_FRONTEND - -# misc -OBJS += frontend/libretro.o frontend/main.o frontend/plugin.o - - -frontend/menu.o frontend/main.o: frontend/revision.h -frontend/libretro.o: frontend/revision.h - -libpcsxcore/gte_nf.o: libpcsxcore/gte.c - $(CC) -c -o $@ $^ $(CFLAGS) -DFLAGLESS - -frontend/revision.h: FORCE - @(git describe || echo) | sed -e 's/.*/#define REV "\0"/' > $@_ - @diff -q $@_ $@ > /dev/null 2>&1 || cp $@_ $@ - @rm $@_ - -%.o: %.S - $(CC) $(CFLAGS) -c $^ -o $@ - -%.o: %.s - $(CC) $(ASFLAGS) -c $^ -o $@ - - -target_: $(TARGET) - -$(TARGET): $(OBJS) - $(CC_LINK) -o $@ $^ $(LDFLAGS) $(LDLIBS) -Wl,-Map=$@.map - -clean: $(PLAT_CLEAN) clean_plugins - $(RM) $(TARGET) $(OBJS) $(TARGET).map frontend/revision.h - -ifneq ($(PLUGINS),) -plugins_: $(PLUGINS) - -$(PLUGINS): - make -C $(dir $@) - -clean_plugins: - make -C plugins/gpulib/ clean - for dir in $(PLUGINS) ; do \ - $(MAKE) -C $$(dirname $$dir) clean; done -else -plugins_: -clean_plugins: -endif +PLUGINS = +NO_CONFIG_MAK = yes -.PHONY: all clean target_ plugins_ clean_plugins FORCE +include Makefile @@ -63,7 +63,7 @@ CC="${CC-${CROSS_COMPILE}gcc}" CXX="${CXX-${CROSS_COMPILE}g++}" AS="${AS-${CROSS_COMPILE}as}" AR="${AS-${CROSS_COMPILE}ar}" -MAIN_LDLIBS="$LDLIBS -ldl -lm" +MAIN_LDLIBS="$LDLIBS -ldl -lm -lpthread" config_mak="config.mak" fail() diff --git a/frontend/cspace_arm.S b/frontend/cspace_arm.S index e9d15a5..67778da 100644 --- a/frontend/cspace_arm.S +++ b/frontend/cspace_arm.S @@ -26,8 +26,7 @@ #endif .endm -.global bgr555_to_rgb565 @ void *dst, const void *src, int bytes -bgr555_to_rgb565: +FUNCTION(bgr555_to_rgb565): @ void *dst, const void *src, int bytes pld_ r1 push {r4-r11,lr} mov lr, #0x001f diff --git a/frontend/cspace_neon.s b/frontend/cspace_neon.S index b458f06..e7b48a9 100644 --- a/frontend/cspace_neon.s +++ b/frontend/cspace_neon.S @@ -8,11 +8,12 @@ * See the COPYING file in the top-level directory. */ +#include "arm_features.h" + .text .align 2 -.global bgr555_to_rgb565 -bgr555_to_rgb565: +FUNCTION(bgr555_to_rgb565): pld [r1] mov r3, #0x07c0 vdup.16 q15, r3 @@ -74,8 +75,7 @@ btr16_end16: bx lr -.global bgr888_to_rgb888 -bgr888_to_rgb888: +FUNCTION(bgr888_to_rgb888): pld [r1] @ r2 /= 48 mov r2, r2, lsr #4 @@ -96,8 +96,7 @@ bgr888_to_rgb888: bx lr -.global bgr888_to_rgb565 -bgr888_to_rgb565: +FUNCTION(bgr888_to_rgb565): pld [r1] @ r2 /= 48 mov r2, r2, lsr #4 @@ -129,8 +128,7 @@ bgr888_to_rgb565: bx lr -.global rgb888_to_rgb565 -rgb888_to_rgb565: +FUNCTION(rgb888_to_rgb565): pld [r1] @ r2 /= 48 mov r2, r2, lsr #4 diff --git a/include/arm_features.h b/include/arm_features.h index dcdda91..a1adfef 100644 --- a/include/arm_features.h +++ b/include/arm_features.h @@ -25,4 +25,20 @@ /* no need for HAVE_NEON - GCC defines __ARM_NEON__ consistently */ +/* global function/external variable */ +#ifndef __MACH__ +#define FUNCTION(name) \ + .global name; \ + .type name, %function; \ + name + +#define EVAR(name) name +#else +#define FUNCTION(name) \ + .globl _##name; \ + _##name + +#define EVAR(name) _##name +#endif + #endif /* __ARM_FEATURES_H__ */ diff --git a/libpcsxcore/gte_arm.S b/libpcsxcore/gte_arm.S index e711e82..3ef876d 100644 --- a/libpcsxcore/gte_arm.S +++ b/libpcsxcore/gte_arm.S @@ -148,8 +148,7 @@ .endm -.global gteRTPS_nf_arm @ r0=CP2 (d,c), -gteRTPS_nf_arm: +FUNCTION(gteRTPS_nf_arm): @ r0=CP2 (d,c), push {r4-r11,lr} ldmia r0, {r8,r9} @ VXYZ(0) @@ -182,7 +181,7 @@ gteRTPS_nf_arm: pop {r0, r12} .endif 1: - ldrd r6, [r0,#4*(32+24)] @ gteOFXY + ldrd r6, r7, [r0, #4*(32+24)] @ gteOFXY cmp r9, #0x20000 add r1, r0, #4*12 @ gteSXY0 movhs r9, #0x20000 @@ -194,7 +193,7 @@ gteRTPS_nf_arm: mov r3, r7, asr #31 smlal r7, r3, r11, r9 lsr r6, #16 - /* gteDQA, gteDQB */ ldrd r10,[r0, #4*(32+27)] + /* gteDQA, gteDQB */ ldrd r10,r11, [r0, #4*(32+27)] orr r6, r2, lsl #16 @ (gteOFX + gteIR1 * q) >> 16 ssatx_prep r2, 11 lsr r7, #16 @@ -215,8 +214,7 @@ gteRTPS_nf_arm: .size gteRTPS_nf_arm, .-gteRTPS_nf_arm -.global gteRTPT_nf_arm @ r0=CP2 (d,c), -gteRTPT_nf_arm: +FUNCTION(gteRTPT_nf_arm): @ r0=CP2 (d,c), ldr r1, [r0, #4*19] @ gteSZ3 push {r4-r11,lr} str r1, [r0, #4*16] @ gteSZ0 @@ -224,7 +222,7 @@ gteRTPT_nf_arm: rtpt_arm_loop: add r1, r0, lr, lsl #1 - ldrd r8, [r1] @ VXYZ(v) + ldrd r8, r9, [r1] @ VXYZ(v) do_rtpx_mac ssatx_prep r6, 16 @@ -253,7 +251,7 @@ rtpt_arm_loop: 1: cmp r9, #0x20000 add r1, r0, #4*12 movhs r9, #0x20000 - ldrd r6, [r0,#4*(32+24)] @ gteOFXY + ldrd r6, r7, [r0,#4*(32+24)] @ gteOFXY /* quotient */ subhs r9, #1 mov r2, r6, asr #31 smlal r6, r2, r10, r9 @@ -272,7 +270,7 @@ rtpt_arm_loop: cmp lr, #12 blt rtpt_arm_loop - ldrd r4, [r0, #4*(32+27)] @ gteDQA, gteDQB + ldrd r4, r5, [r0, #4*(32+27)] @ gteDQA, gteDQB add r1, r0, #4*9 @ gteIR1 mla r3, r4, r9, r5 @ gteDQB + gteDQA * q stmia r1, {r10,r11,r12} @ gteIR123 save @@ -360,13 +358,11 @@ rtpt_arm_loop: bx lr .endm -.global gteMVMVA_part_arm -gteMVMVA_part_arm: +FUNCTION(gteMVMVA_part_arm): mvma_op 1 .size gteMVMVA_part_arm, .-gteMVMVA_part_arm -.global gteMVMVA_part_nf_arm -gteMVMVA_part_nf_arm: +FUNCTION(gteMVMVA_part_nf_arm): mvma_op 0 .size gteMVMVA_part_nf_arm, .-gteMVMVA_part_nf_arm @@ -376,8 +372,7 @@ gteMVMVA_part_nf_arm: @ r0 = CP2 (d,c) (must preserve) @ r4,r5 = VXYZ(v) packed @ r6 = &MX11(mx) -.global gteMVMVA_part_cv3sh12_arm -gteMVMVA_part_cv3sh12_arm: +FUNCTION(gteMVMVA_part_cv3sh12_arm): push {r8-r9} ldmia r6!,{r7-r9} @ MX1*,MX2* smulbb r1, r7, r4 @ MX11 * vx @@ -412,8 +407,7 @@ gteMVMVA_part_cv3sh12_arm: #endif /* HAVE_ARMV5 */ -.global gteNCLIP_arm @ r0=CP2 (d,c), -gteNCLIP_arm: +FUNCTION(gteNCLIP_arm): @ r0=CP2 (d,c), push {r4-r6,lr} ldrsh r4, [r0, #4*12+2] ldrsh r5, [r0, #4*13+2] @@ -464,7 +458,7 @@ gteNCLIP_arm: .endif str r2, [r0, #4*9] #ifdef HAVE_ARMV5 - ldrd r2, [r0, #4*26] @ gteMAC23 + ldrd r2, r3, [r0, #4*26] @ gteMAC23 #else ldr r2, [r0, #4*26] ldr r3, [r0, #4*27] @@ -495,7 +489,7 @@ gteNCLIP_arm: .endif orrlt r12, #1<<22 #ifdef HAVE_ARMV5 - strd r2, [r0, #4*10] @ gteIR23 + strd r2, r3, [r0, #4*10] @ gteIR23 #else str r2, [r0, #4*10] str r3, [r0, #4*11] @@ -504,19 +498,16 @@ gteNCLIP_arm: bx lr .endm -.global gteMACtoIR_lm0 @ r0=CP2 (d,c) -gteMACtoIR_lm0: +FUNCTION(gteMACtoIR_lm0): @ r0=CP2 (d,c) gteMACtoIR 0 .size gteMACtoIR_lm0, .-gteMACtoIR_lm0 -.global gteMACtoIR_lm1 @ r0=CP2 (d,c) -gteMACtoIR_lm1: +FUNCTION(gteMACtoIR_lm1): @ r0=CP2 (d,c) gteMACtoIR 1 .size gteMACtoIR_lm1, .-gteMACtoIR_lm1 -.global gteMACtoIR_lm0_nf @ r0=CP2 (d,c) -gteMACtoIR_lm0_nf: +FUNCTION(gteMACtoIR_lm0_nf): @ r0=CP2 (d,c) add r12, r0, #4*25 ldmia r12, {r1-r3} ssatx_prep r12, 16 @@ -529,8 +520,7 @@ gteMACtoIR_lm0_nf: .size gteMACtoIR_lm0_nf, .-gteMACtoIR_lm0_nf -.global gteMACtoIR_lm1_nf @ r0=CP2 (d,c) -gteMACtoIR_lm1_nf: +FUNCTION(gteMACtoIR_lm1_nf): @ r0=CP2 (d,c) add r12, r0, #4*25 ldmia r12, {r1-r3} ssatx0_prep r12, 16 @@ -544,8 +534,7 @@ gteMACtoIR_lm1_nf: .if 0 -.global gteMVMVA_test -gteMVMVA_test: +FUNCTION(gteMVMVA_test): push {r4-r7,lr} push {r1} and r2, r1, #0x18000 @ v diff --git a/libpcsxcore/gte_neon.S b/libpcsxcore/gte_neon.S index 9fafb27..3c71f55 100644 --- a/libpcsxcore/gte_neon.S +++ b/libpcsxcore/gte_neon.S @@ -5,6 +5,9 @@ * See the COPYING file in the top-level directory. */ +#include "arm_features.h" + +.syntax unified .bss .align 6 @ cacheline @@ -143,8 +146,7 @@ scratch: vqmovn.s32 d10, q4 @ gteIR|123; losing 2 cycles? .endm -.global gteRTPS_neon @ r0=CP2 (d,c), -gteRTPS_neon: +FUNCTION(gteRTPS_neon): @ r0=CP2 (d,c), push {r4-r6,lr} @ fmrx r4, fpscr @ vmrs? at least 40 cycle hit @@ -271,11 +273,11 @@ gteRTPS_neon: orrne lr, #(1<<13) @ limG2 orrne lr, #(1<<31) adds r2, r4, #1 - addvcs r3, r5, #1 + addsvc r3, r5, #1 orrvs lr, #(1<<16) @ F orrvs lr, #(1<<31) subs r2, r4, #1 - subvcs r3, r5, #1 + subsvc r3, r5, #1 orrvs lr, #(1<<31) ldr r4, [r0, #4*24] @ gteMAC0 @@ -297,8 +299,7 @@ gteRTPS_neon: -.global gteRTPT_neon @ r0=CP2 (d,c), -gteRTPT_neon: +FUNCTION(gteRTPT_neon): @ r0=CP2 (d,c), push {r4-r11,lr} ldr_scratch r1 @@ -506,13 +507,13 @@ gteRTPT_neon: add r2, r4, #0x400<<16 @ min fSX add r3, r6, #0x400<<16 @ max fSX lsrs r2, #16+11 - lsreqs r3, #16+11 + lsrseq r3, #16+11 orrne lr, #(1<<31) @ limG1 orrne lr, #(1<<14) add r2, r5, #0x400<<16 @ min fSY add r3, r7, #0x400<<16 @ max fSY lsrs r2, #16+11 - lsreqs r3, #16+11 + lsrseq r3, #16+11 orrne lr, #(1<<31) @ limG2 orrne lr, #(1<<13) adds r2, r9, #1 @@ -544,8 +545,7 @@ gteRTPT_neon: @ r4,r5 = VXYZ(v) packed @ r6 = &MX11(mx) @ r7 = &CV1(cv) -.global gteMVMVA_part_neon -gteMVMVA_part_neon: +FUNCTION(gteMVMVA_part_neon): uxth r5, r5 vmov.32 d8[0], r4 vmov.32 d8[1], r5 @ VXYZ(v) @@ -592,8 +592,7 @@ gteMVMVA_part_neon: @ get flags after gteMVMVA_part_neon operation -.global gteMACtoIR_flags_neon @ r0=CP2 (d,c), r1=lm -gteMACtoIR_flags_neon: +FUNCTION(gteMACtoIR_flags_neon): @ r0=CP2 (d,c), r1=lm push {r4,r5,lr} tst r1, r1 @ lm mov lr, #0 @ gteFLAG diff --git a/libpcsxcore/new_dynarec/linkage_arm.S b/libpcsxcore/new_dynarec/linkage_arm.S index 5b70745..5a76f8e 100644 --- a/libpcsxcore/new_dynarec/linkage_arm.S +++ b/libpcsxcore/new_dynarec/linkage_arm.S @@ -292,9 +292,8 @@ FCR31 = align0 .text .align 2 - .global dyna_linker - .type dyna_linker, %function -dyna_linker: + +FUNCTION(dyna_linker): /* r0 = virtual target address */ /* r1 = instruction to patch */ dyna_linker_main @@ -310,9 +309,8 @@ dyna_linker: mov r1, r0 mov r2, #8 .size dyna_linker, .-dyna_linker - .global exec_pagefault - .type exec_pagefault, %function -exec_pagefault: + +FUNCTION(exec_pagefault): /* r0 = instruction pointer */ /* r1 = fault address */ /* r2 = cause */ @@ -338,9 +336,7 @@ exec_pagefault: /* Special dynamic linker for the case where a page fault may occur in a branch delay slot */ - .global dyna_linker_ds - .type dyna_linker_ds, %function -dyna_linker_ds: +FUNCTION(dyna_linker_ds): /* r0 = virtual target address */ /* r1 = instruction to patch */ dyna_linker_main @@ -368,91 +364,66 @@ dyna_linker_ds: .word hash_table .align 2 - .global jump_vaddr_r0 - .type jump_vaddr_r0, %function -jump_vaddr_r0: + +FUNCTION(jump_vaddr_r0): eor r2, r0, r0, lsl #16 b jump_vaddr .size jump_vaddr_r0, .-jump_vaddr_r0 - .global jump_vaddr_r1 - .type jump_vaddr_r1, %function -jump_vaddr_r1: +FUNCTION(jump_vaddr_r1): eor r2, r1, r1, lsl #16 mov r0, r1 b jump_vaddr .size jump_vaddr_r1, .-jump_vaddr_r1 - .global jump_vaddr_r2 - .type jump_vaddr_r2, %function -jump_vaddr_r2: +FUNCTION(jump_vaddr_r2): mov r0, r2 eor r2, r2, r2, lsl #16 b jump_vaddr .size jump_vaddr_r2, .-jump_vaddr_r2 - .global jump_vaddr_r3 - .type jump_vaddr_r3, %function -jump_vaddr_r3: +FUNCTION(jump_vaddr_r3): eor r2, r3, r3, lsl #16 mov r0, r3 b jump_vaddr .size jump_vaddr_r3, .-jump_vaddr_r3 - .global jump_vaddr_r4 - .type jump_vaddr_r4, %function -jump_vaddr_r4: +FUNCTION(jump_vaddr_r4): eor r2, r4, r4, lsl #16 mov r0, r4 b jump_vaddr .size jump_vaddr_r4, .-jump_vaddr_r4 - .global jump_vaddr_r5 - .type jump_vaddr_r5, %function -jump_vaddr_r5: +FUNCTION(jump_vaddr_r5): eor r2, r5, r5, lsl #16 mov r0, r5 b jump_vaddr .size jump_vaddr_r5, .-jump_vaddr_r5 - .global jump_vaddr_r6 - .type jump_vaddr_r6, %function -jump_vaddr_r6: +FUNCTION(jump_vaddr_r6): eor r2, r6, r6, lsl #16 mov r0, r6 b jump_vaddr .size jump_vaddr_r6, .-jump_vaddr_r6 - .global jump_vaddr_r8 - .type jump_vaddr_r8, %function -jump_vaddr_r8: +FUNCTION(jump_vaddr_r8): eor r2, r8, r8, lsl #16 mov r0, r8 b jump_vaddr .size jump_vaddr_r8, .-jump_vaddr_r8 - .global jump_vaddr_r9 - .type jump_vaddr_r9, %function -jump_vaddr_r9: +FUNCTION(jump_vaddr_r9): eor r2, r9, r9, lsl #16 mov r0, r9 b jump_vaddr .size jump_vaddr_r9, .-jump_vaddr_r9 - .global jump_vaddr_r10 - .type jump_vaddr_r10, %function -jump_vaddr_r10: +FUNCTION(jump_vaddr_r10): eor r2, r10, r10, lsl #16 mov r0, r10 b jump_vaddr .size jump_vaddr_r10, .-jump_vaddr_r10 - .global jump_vaddr_r12 - .type jump_vaddr_r12, %function -jump_vaddr_r12: +FUNCTION(jump_vaddr_r12): eor r2, r12, r12, lsl #16 mov r0, r12 b jump_vaddr .size jump_vaddr_r12, .-jump_vaddr_r12 - .global jump_vaddr_r7 - .type jump_vaddr_r7, %function -jump_vaddr_r7: +FUNCTION(jump_vaddr_r7): eor r2, r7, r7, lsl #16 add r0, r7, #0 .size jump_vaddr_r7, .-jump_vaddr_r7 - .global jump_vaddr - .type jump_vaddr, %function -jump_vaddr: +FUNCTION(jump_vaddr): ldr r1, .htptr mvn r3, #15 and r2, r3, r2, lsr #12 @@ -469,17 +440,11 @@ jump_vaddr: .size jump_vaddr, .-jump_vaddr .align 2 - .global verify_code_ds - .type verify_code_ds, %function -verify_code_ds: + +FUNCTION(verify_code_ds): str r8, [fp, #branch_target-dynarec_local] - .size verify_code_ds, .-verify_code_ds - .global verify_code_vm - .type verify_code_vm, %function -verify_code_vm: - .global verify_code - .type verify_code, %function -verify_code: +FUNCTION(verify_code_vm): +FUNCTION(verify_code): /* r1 = source */ /* r2 = target */ /* r3 = length */ @@ -516,9 +481,7 @@ verify_code: .size verify_code_vm, .-verify_code_vm .align 2 - .global cc_interrupt - .type cc_interrupt, %function -cc_interrupt: +FUNCTION(cc_interrupt): ldr r0, [fp, #last_count-dynarec_local] mov r1, #0 mov r2, #0x1fc @@ -564,9 +527,7 @@ cc_interrupt: .size cc_interrupt, .-cc_interrupt .align 2 - .global do_interrupt - .type do_interrupt, %function -do_interrupt: +FUNCTION(do_interrupt): ldr r0, [fp, #pcaddr-dynarec_local] bl get_addr_ht add r10, r10, #2 @@ -574,9 +535,7 @@ do_interrupt: .size do_interrupt, .-do_interrupt .align 2 - .global fp_exception - .type fp_exception, %function -fp_exception: +FUNCTION(fp_exception): mov r2, #0x10000000 .E7: ldr r1, [fp, #reg_cop0+48-dynarec_local] /* Status */ @@ -591,17 +550,13 @@ fp_exception: mov pc, r0 .size fp_exception, .-fp_exception .align 2 - .global fp_exception_ds - .type fp_exception_ds, %function -fp_exception_ds: +FUNCTION(fp_exception_ds): mov r2, #0x90000000 /* Set high bit if delay slot */ b .E7 .size fp_exception_ds, .-fp_exception_ds .align 2 - .global jump_syscall - .type jump_syscall, %function -jump_syscall: +FUNCTION(jump_syscall): ldr r1, [fp, #reg_cop0+48-dynarec_local] /* Status */ mov r3, #0x80000000 str r0, [fp, #reg_cop0+56-dynarec_local] /* EPC */ @@ -616,9 +571,7 @@ jump_syscall: .align 2 .align 2 - .global jump_syscall_hle - .type jump_syscall_hle, %function -jump_syscall_hle: +FUNCTION(jump_syscall_hle): str r0, [fp, #pcaddr-dynarec_local] /* PC must be set to EPC for psxException */ ldr r2, [fp, #last_count-dynarec_local] mov r1, #0 /* in delay slot */ @@ -640,9 +593,7 @@ pcsx_return: .size jump_syscall_hle, .-jump_syscall_hle .align 2 - .global jump_hlecall - .type jump_hlecall, %function -jump_hlecall: +FUNCTION(jump_hlecall): ldr r2, [fp, #last_count-dynarec_local] str r0, [fp, #pcaddr-dynarec_local] add r2, r2, r10 @@ -652,9 +603,7 @@ jump_hlecall: .size jump_hlecall, .-jump_hlecall .align 2 - .global jump_intcall - .type jump_intcall, %function -jump_intcall: +FUNCTION(jump_intcall): ldr r2, [fp, #last_count-dynarec_local] str r0, [fp, #pcaddr-dynarec_local] add r2, r2, r10 @@ -663,10 +612,8 @@ jump_intcall: b execI .size jump_hlecall, .-jump_hlecall -new_dyna_leave: .align 2 - .global new_dyna_leave - .type new_dyna_leave, %function +FUNCTION(new_dyna_leave): ldr r0, [fp, #last_count-dynarec_local] add r12, fp, #28 add r10, r0, r10 @@ -675,103 +622,77 @@ new_dyna_leave: .size new_dyna_leave, .-new_dyna_leave .align 2 - .global invalidate_addr_r0 - .type invalidate_addr_r0, %function -invalidate_addr_r0: +FUNCTION(invalidate_addr_r0): stmia fp, {r0, r1, r2, r3, r12, lr} b invalidate_addr_call .size invalidate_addr_r0, .-invalidate_addr_r0 .align 2 - .global invalidate_addr_r1 - .type invalidate_addr_r1, %function -invalidate_addr_r1: +FUNCTION(invalidate_addr_r1): stmia fp, {r0, r1, r2, r3, r12, lr} mov r0, r1 b invalidate_addr_call .size invalidate_addr_r1, .-invalidate_addr_r1 .align 2 - .global invalidate_addr_r2 - .type invalidate_addr_r2, %function -invalidate_addr_r2: +FUNCTION(invalidate_addr_r2): stmia fp, {r0, r1, r2, r3, r12, lr} mov r0, r2 b invalidate_addr_call .size invalidate_addr_r2, .-invalidate_addr_r2 .align 2 - .global invalidate_addr_r3 - .type invalidate_addr_r3, %function -invalidate_addr_r3: +FUNCTION(invalidate_addr_r3): stmia fp, {r0, r1, r2, r3, r12, lr} mov r0, r3 b invalidate_addr_call .size invalidate_addr_r3, .-invalidate_addr_r3 .align 2 - .global invalidate_addr_r4 - .type invalidate_addr_r4, %function -invalidate_addr_r4: +FUNCTION(invalidate_addr_r4): stmia fp, {r0, r1, r2, r3, r12, lr} mov r0, r4 b invalidate_addr_call .size invalidate_addr_r4, .-invalidate_addr_r4 .align 2 - .global invalidate_addr_r5 - .type invalidate_addr_r5, %function -invalidate_addr_r5: +FUNCTION(invalidate_addr_r5): stmia fp, {r0, r1, r2, r3, r12, lr} mov r0, r5 b invalidate_addr_call .size invalidate_addr_r5, .-invalidate_addr_r5 .align 2 - .global invalidate_addr_r6 - .type invalidate_addr_r6, %function -invalidate_addr_r6: +FUNCTION(invalidate_addr_r6): stmia fp, {r0, r1, r2, r3, r12, lr} mov r0, r6 b invalidate_addr_call .size invalidate_addr_r6, .-invalidate_addr_r6 .align 2 - .global invalidate_addr_r7 - .type invalidate_addr_r7, %function -invalidate_addr_r7: +FUNCTION(invalidate_addr_r7): stmia fp, {r0, r1, r2, r3, r12, lr} mov r0, r7 b invalidate_addr_call .size invalidate_addr_r7, .-invalidate_addr_r7 .align 2 - .global invalidate_addr_r8 - .type invalidate_addr_r8, %function -invalidate_addr_r8: +FUNCTION(invalidate_addr_r8): stmia fp, {r0, r1, r2, r3, r12, lr} mov r0, r8 b invalidate_addr_call .size invalidate_addr_r8, .-invalidate_addr_r8 .align 2 - .global invalidate_addr_r9 - .type invalidate_addr_r9, %function -invalidate_addr_r9: +FUNCTION(invalidate_addr_r9): stmia fp, {r0, r1, r2, r3, r12, lr} mov r0, r9 b invalidate_addr_call .size invalidate_addr_r9, .-invalidate_addr_r9 .align 2 - .global invalidate_addr_r10 - .type invalidate_addr_r10, %function -invalidate_addr_r10: +FUNCTION(invalidate_addr_r10): stmia fp, {r0, r1, r2, r3, r12, lr} mov r0, r10 b invalidate_addr_call .size invalidate_addr_r10, .-invalidate_addr_r10 .align 2 - .global invalidate_addr_r12 - .type invalidate_addr_r12, %function -invalidate_addr_r12: +FUNCTION(invalidate_addr_r12): stmia fp, {r0, r1, r2, r3, r12, lr} mov r0, r12 .size invalidate_addr_r12, .-invalidate_addr_r12 .align 2 - .global invalidate_addr_call - .type invalidate_addr_call, %function -invalidate_addr_call: +FUNCTION(invalidate_addr_call): ldr r12, [fp, #inv_code_start-dynarec_local] ldr lr, [fp, #inv_code_end-dynarec_local] cmp r0, r12 @@ -781,9 +702,7 @@ invalidate_addr_call: .size invalidate_addr_call, .-invalidate_addr_call .align 2 - .global new_dyna_start - .type new_dyna_start, %function -new_dyna_start: +FUNCTION(new_dyna_start): /* ip is stored to conform EABI alignment */ stmfd sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr} load_varadr fp, dynarec_local @@ -799,22 +718,6 @@ new_dyna_start: /* --------------------------------------- */ .align 2 -.global jump_handler_read8 -.global jump_handler_read16 -.global jump_handler_read32 -.global jump_handler_write8 -.global jump_handler_write16 -.global jump_handler_write32 -.global jump_handler_write_h -.global jump_handle_swl -.global jump_handle_swr -.global rcnt0_read_count_m0 -.global rcnt0_read_count_m1 -.global rcnt1_read_count_m0 -.global rcnt1_read_count_m1 -.global rcnt2_read_count_m0 -.global rcnt2_read_count_m1 - .macro pcsx_read_mem readop tab_shift /* r0 = address, r1 = handler_tab, r2 = cycles */ @@ -835,15 +738,15 @@ new_dyna_start: bx r1 .endm -jump_handler_read8: +FUNCTION(jump_handler_read8): add r1, #0x1000/4*4 + 0x1000/2*4 @ shift to r8 part pcsx_read_mem ldrccb, 0 -jump_handler_read16: +FUNCTION(jump_handler_read16): add r1, #0x1000/4*4 @ shift to r16 part pcsx_read_mem ldrcch, 1 -jump_handler_read32: +FUNCTION(jump_handler_read32): pcsx_read_mem ldrcc, 2 @@ -876,18 +779,18 @@ jump_handler_read32: bx r3 .endm -jump_handler_write8: +FUNCTION(jump_handler_write8): add r3, #0x1000/4*4 + 0x1000/2*4 @ shift to r8 part pcsx_write_mem strccb, 0 -jump_handler_write16: +FUNCTION(jump_handler_write16): add r3, #0x1000/4*4 @ shift to r16 part pcsx_write_mem strcch, 1 -jump_handler_write32: +FUNCTION(jump_handler_write32): pcsx_write_mem strcc, 2 -jump_handler_write_h: +FUNCTION(jump_handler_write_h): /* r0 = address, r1 = data, r2 = cycles, r3 = handler */ ldr r12, [fp, #last_count-dynarec_local] str r0, [fp, #address-dynarec_local] @ some handlers still need it.. @@ -903,7 +806,7 @@ jump_handler_write_h: sub r0, r2, r0 bx r3 -jump_handle_swl: +FUNCTION(jump_handle_swl): /* r0 = address, r1 = data, r2 = cycles */ ldr r3, [fp, #mem_wtab-dynarec_local] mov r12,r0,lsr #12 @@ -938,7 +841,7 @@ jump_handle_swl: bx lr @ TODO? -jump_handle_swr: +FUNCTION(jump_handle_swr): /* r0 = address, r1 = data, r2 = cycles */ ldr r3, [fp, #mem_wtab-dynarec_local] mov r12,r0,lsr #12 @@ -973,16 +876,16 @@ jump_handle_swr: bx lr .endm -rcnt0_read_count_m0: +FUNCTION(rcnt0_read_count_m0): rcntx_read_mode0 0 -rcnt1_read_count_m0: +FUNCTION(rcnt1_read_count_m0): rcntx_read_mode0 1 -rcnt2_read_count_m0: +FUNCTION(rcnt2_read_count_m0): rcntx_read_mode0 2 -rcnt0_read_count_m1: +FUNCTION(rcnt0_read_count_m1): /* r0 = address, r2 = cycles */ ldr r3, [fp, #rcnts-dynarec_local+6*4+7*4*0] @ cycleStart mov_16 r1, 0x3334 @@ -991,7 +894,7 @@ rcnt0_read_count_m1: lsr r0, #16 bx lr -rcnt1_read_count_m1: +FUNCTION(rcnt1_read_count_m1): /* r0 = address, r2 = cycles */ ldr r3, [fp, #rcnts-dynarec_local+6*4+7*4*1] mov_24 r1, 0x1e6cde @@ -999,7 +902,7 @@ rcnt1_read_count_m1: umull r3, r0, r1, r2 @ ~ /= hsync_cycles, max ~0x1e6cdd bx lr -rcnt2_read_count_m1: +FUNCTION(rcnt2_read_count_m1): /* r0 = address, r2 = cycles */ ldr r3, [fp, #rcnts-dynarec_local+6*4+7*4*2] mov r0, r2, lsl #16-3 diff --git a/plugins/dfsound/arm_utils.S b/plugins/dfsound/arm_utils.S index f4ef243..ddc3714 100644 --- a/plugins/dfsound/arm_utils.S +++ b/plugins/dfsound/arm_utils.S @@ -15,17 +15,16 @@ .macro load_varadr reg var #if defined(__ARM_ARCH_7A__) && !defined(__PIC__) - movw \reg, #:lower16:\var - movt \reg, #:upper16:\var + movw \reg, #:lower16:EVAR(\var) + movt \reg, #:upper16:EVAR(\var) #else - ldr \reg, =\var + ldr \reg, =EVAR(\var) #endif .endm #ifdef __ARM_NEON__ -.global mix_chan @ (int start, int count, int lv, int rv) -mix_chan: +FUNCTION(mix_chan): @ (int start, int count, int lv, int rv) vmov.32 d14[0], r2 vmov.32 d14[1], r3 @ multipliers mov r12, r0 @@ -58,8 +57,7 @@ mc_finish: bx lr -.global mix_chan_rvb @ (int start, int count, int lv, int rv) -mix_chan_rvb: +FUNCTION(mix_chan_rvb): @ (int start, int count, int lv, int rv) vmov.32 d14[0], r2 vmov.32 d14[1], r3 @ multipliers mov r12, r0 @@ -103,8 +101,7 @@ mcr_finish: #elif defined(HAVE_ARMV5) -.global mix_chan @ (int start, int count, int lv, int rv) -mix_chan: +FUNCTION(mix_chan): @ (int start, int count, int lv, int rv) stmfd sp!, {r4-r8,lr} orr r3, r2, r3, lsl #16 lsl r3, #1 @ packed multipliers << 1 @@ -133,8 +130,7 @@ mc_finish: ldmfd sp!, {r4-r8,pc} -.global mix_chan_rvb @ (int start, int count, int lv, int rv) -mix_chan_rvb: +FUNCTION(mix_chan_rvb): @ (int start, int count, int lv, int rv) stmfd sp!, {r4-r8,lr} orr lr, r2, r3, lsl #16 lsl lr, #1 diff --git a/tools/gas-preprocessor.pl b/tools/gas-preprocessor.pl new file mode 100644 index 0000000..9787491 --- /dev/null +++ b/tools/gas-preprocessor.pl @@ -0,0 +1,527 @@ +#!/usr/bin/env perl +# by David Conrad +# This code is licensed under GPLv2 or later; go to gnu.org to read it +# (not that it much matters for an asm preprocessor) +# usage: set your assembler to be something like "perl gas-preprocessor.pl gcc" +use strict; + +# Apple's gas is ancient and doesn't support modern preprocessing features like +# .rept and has ugly macro syntax, among other things. Thus, this script +# implements the subset of the gas preprocessor used by x264 and ffmpeg +# that isn't supported by Apple's gas. + +my @gcc_cmd = @ARGV; +my @preprocess_c_cmd; + +my $fix_unreq = $^O eq "darwin"; + +if ($gcc_cmd[0] eq "-fix-unreq") { + $fix_unreq = 1; + shift @gcc_cmd; +} elsif ($gcc_cmd[0] eq "-no-fix-unreq") { + $fix_unreq = 0; + shift @gcc_cmd; +} + +if (grep /\.c$/, @gcc_cmd) { + # C file (inline asm?) - compile + @preprocess_c_cmd = (@gcc_cmd, "-S"); +} elsif (grep /\.[sS]$/, @gcc_cmd) { + # asm file, just do C preprocessor + @preprocess_c_cmd = (@gcc_cmd, "-E"); +} else { + die "Unrecognized input filetype"; +} + +# if compiling, avoid creating an output file named '-.o' +if ((grep /^-c$/, @gcc_cmd) && !(grep /^-o/, @gcc_cmd)) { + foreach my $i (@gcc_cmd) { + if ($i =~ /\.[csS]$/) { + my $outputfile = $i; + $outputfile =~ s/\.[csS]$/.o/; + push(@gcc_cmd, "-o"); + push(@gcc_cmd, $outputfile); + last; + } + } +} +@gcc_cmd = map { /\.[csS]$/ ? qw(-x assembler -) : $_ } @gcc_cmd; +@preprocess_c_cmd = map { /\.o$/ ? "-" : $_ } @preprocess_c_cmd; + +my $comm; + +# detect architecture from gcc binary name +if ($gcc_cmd[0] =~ /arm/) { + $comm = '@'; +} elsif ($gcc_cmd[0] =~ /powerpc|ppc/) { + $comm = '#'; +} + +# look for -arch flag +foreach my $i (1 .. $#gcc_cmd-1) { + if ($gcc_cmd[$i] eq "-arch") { + if ($gcc_cmd[$i+1] =~ /arm/) { + $comm = '@'; + } elsif ($gcc_cmd[$i+1] =~ /powerpc|ppc/) { + $comm = '#'; + } + } +} + +# assume we're not cross-compiling if no -arch or the binary doesn't have the arch name +if (!$comm) { + my $native_arch = qx/arch/; + if ($native_arch =~ /arm/) { + $comm = '@'; + } elsif ($native_arch =~ /powerpc|ppc/) { + $comm = '#'; + } +} + +if (!$comm) { + die "Unable to identify target architecture"; +} + +my %ppc_spr = (ctr => 9, + vrsave => 256); + +open(ASMFILE, "-|", @preprocess_c_cmd) || die "Error running preprocessor"; + +my $current_macro = ''; +my $macro_level = 0; +my %macro_lines; +my %macro_args; +my %macro_args_default; +my $macro_count = 0; +my $altmacro = 0; + +my @pass1_lines; +my @ifstack; + +my %symbols; + +# pass 1: parse .macro +# note that the handling of arguments is probably overly permissive vs. gas +# but it should be the same for valid cases +while (<ASMFILE>) { + # remove all comments (to avoid interfering with evaluating directives) + s/(?<!\\)$comm.*//x; + + # comment out unsupported directives + s/\.type/$comm.type/x; + s/\.func/$comm.func/x; + s/\.endfunc/$comm.endfunc/x; + s/\.ltorg/$comm.ltorg/x; + s/\.size/$comm.size/x; + s/\.fpu/$comm.fpu/x; + s/\.arch/$comm.arch/x; + s/\.object_arch/$comm.object_arch/x; + + # the syntax for these is a little different + s/\.global/.globl/x; + # also catch .section .rodata since the equivalent to .const_data is .section __DATA,__const + s/(.*)\.rodata/.const_data/x; + s/\.bss/.data/x; + s/\.int/.long/x; + s/\.float/.single/x; + + # catch unknown section names that aren't mach-o style (with a comma) + if (/.section ([^,]*)$/) { + die ".section $1 unsupported; figure out the mach-o section name and add it"; + } + + parse_line($_); +} + +sub eval_expr { + my $expr = $_[0]; + $expr =~ s/([A-Za-z._][A-Za-z0-9._]*)/$symbols{$1}/g; + eval $expr; +} + +sub handle_if { + my $line = $_[0]; + # handle .if directives; apple's assembler doesn't support important non-basic ones + # evaluating them is also needed to handle recursive macros + if ($line =~ /\.if(n?)([a-z]*)\s+(.*)/) { + my $result = $1 eq "n"; + my $type = $2; + my $expr = $3; + + if ($type eq "b") { + $expr =~ s/\s//g; + $result ^= $expr eq ""; + } elsif ($type eq "c") { + if ($expr =~ /(.*)\s*,\s*(.*)/) { + $result ^= $1 eq $2; + } else { + die "argument to .ifc not recognized"; + } + } elsif ($type eq "") { + $result ^= eval_expr($expr) != 0; + } elsif ($type eq "eq") { + $result = eval_expr($expr) == 0; + } elsif ($type eq "lt") { + $result = eval_expr($expr) < 0; + } else { + chomp($line); + die "unhandled .if varient. \"$line\""; + } + push (@ifstack, $result); + return 1; + } else { + return 0; + } +} + +sub parse_line { + my $line = @_[0]; + + # evaluate .if blocks + if (scalar(@ifstack)) { + if (/\.endif/) { + pop(@ifstack); + return; + } elsif ($line =~ /\.elseif\s+(.*)/) { + if ($ifstack[-1] == 0) { + $ifstack[-1] = !!eval_expr($1); + } elsif ($ifstack[-1] > 0) { + $ifstack[-1] = -$ifstack[-1]; + } + return; + } elsif (/\.else/) { + $ifstack[-1] = !$ifstack[-1]; + return; + } elsif (handle_if($line)) { + return; + } + + # discard lines in false .if blocks + foreach my $i (0 .. $#ifstack) { + if ($ifstack[$i] <= 0) { + return; + } + } + } + + if (/\.macro/) { + $macro_level++; + if ($macro_level > 1 && !$current_macro) { + die "nested macros but we don't have master macro"; + } + } elsif (/\.endm/) { + $macro_level--; + if ($macro_level < 0) { + die "unmatched .endm"; + } elsif ($macro_level == 0) { + $current_macro = ''; + return; + } + } + + if ($macro_level > 1) { + push(@{$macro_lines{$current_macro}}, $line); + } elsif ($macro_level == 0) { + expand_macros($line); + } else { + if ($line =~ /\.macro\s+([\d\w\.]+)\s*(.*)/) { + $current_macro = $1; + + # commas in the argument list are optional, so only use whitespace as the separator + my $arglist = $2; + $arglist =~ s/,/ /g; + + my @args = split(/\s+/, $arglist); + foreach my $i (0 .. $#args) { + my @argpair = split(/=/, $args[$i]); + $macro_args{$current_macro}[$i] = $argpair[0]; + $argpair[0] =~ s/:vararg$//; + $macro_args_default{$current_macro}{$argpair[0]} = $argpair[1]; + } + # ensure %macro_lines has the macro name added as a key + $macro_lines{$current_macro} = []; + + } elsif ($current_macro) { + push(@{$macro_lines{$current_macro}}, $line); + } else { + die "macro level without a macro name"; + } + } +} + +sub expand_macros { + my $line = @_[0]; + + # handle .if directives; apple's assembler doesn't support important non-basic ones + # evaluating them is also needed to handle recursive macros + if (handle_if($line)) { + return; + } + + if (/\.purgem\s+([\d\w\.]+)/) { + delete $macro_lines{$1}; + delete $macro_args{$1}; + delete $macro_args_default{$1}; + return; + } + + if ($line =~ /\.altmacro/) { + $altmacro = 1; + return; + } + + if ($line =~ /\.noaltmacro/) { + $altmacro = 0; + return; + } + + $line =~ s/\%([^,]*)/eval_expr($1)/eg if $altmacro; + + if ($line =~ /\.set\s+(.*),\s*(.*)/) { + $symbols{$1} = eval_expr($2); + } + + if ($line =~ /(\S+:|)\s*([\w\d\.]+)\s*(.*)/ && exists $macro_lines{$2}) { + push(@pass1_lines, $1); + my $macro = $2; + + # commas are optional here too, but are syntactically important because + # parameters can be blank + my @arglist = split(/,/, $3); + my @args; + my @args_seperator; + + my $comma_sep_required = 0; + foreach (@arglist) { + # allow arithmetic/shift operators in macro arguments + $_ =~ s/\s*(\+|-|\*|\/|<<|>>)\s*/$1/g; + + my @whitespace_split = split(/\s+/, $_); + if (!@whitespace_split) { + push(@args, ''); + push(@args_seperator, ''); + } else { + foreach (@whitespace_split) { + #print ("arglist = \"$_\"\n"); + if (length($_)) { + push(@args, $_); + my $sep = $comma_sep_required ? "," : " "; + push(@args_seperator, $sep); + #print ("sep = \"$sep\", arg = \"$_\"\n"); + $comma_sep_required = 0; + } + } + } + + $comma_sep_required = 1; + } + + my %replacements; + if ($macro_args_default{$macro}){ + %replacements = %{$macro_args_default{$macro}}; + } + + # construct hashtable of text to replace + foreach my $i (0 .. $#args) { + my $argname = $macro_args{$macro}[$i]; + my @macro_args = @{ $macro_args{$macro} }; + if ($args[$i] =~ m/=/) { + # arg=val references the argument name + # XXX: I'm not sure what the expected behaviour if a lot of + # these are mixed with unnamed args + my @named_arg = split(/=/, $args[$i]); + $replacements{$named_arg[0]} = $named_arg[1]; + } elsif ($i > $#{$macro_args{$macro}}) { + # more args given than the macro has named args + # XXX: is vararg allowed on arguments before the last? + $argname = $macro_args{$macro}[-1]; + if ($argname =~ s/:vararg$//) { + #print "macro = $macro, args[$i] = $args[$i], args_seperator=@args_seperator, argname = $argname, arglist[$i] = $arglist[$i], arglist = @arglist, args=@args, macro_args=@macro_args\n"; + #$replacements{$argname} .= ", $args[$i]"; + $replacements{$argname} .= "$args_seperator[$i] $args[$i]"; + } else { + die "Too many arguments to macro $macro"; + } + } else { + $argname =~ s/:vararg$//; + $replacements{$argname} = $args[$i]; + } + } + + my $count = $macro_count++; + + # apply replacements as regex + foreach (@{$macro_lines{$macro}}) { + my $macro_line = $_; + # do replacements by longest first, this avoids wrong replacement + # when argument names are subsets of each other + foreach (reverse sort {length $a <=> length $b} keys %replacements) { + $macro_line =~ s/\\$_/$replacements{$_}/g; + } + $macro_line =~ s/\\\@/$count/g; + $macro_line =~ s/\\\(\)//g; # remove \() + parse_line($macro_line); + } + } else { + push(@pass1_lines, $line); + } +} + +close(ASMFILE) or exit 1; +open(ASMFILE, "|-", @gcc_cmd) or die "Error running assembler"; +#open(ASMFILE, ">/tmp/a.S") or die "Error running assembler"; + +my @sections; +my $num_repts; +my $rept_lines; + +my %literal_labels; # for ldr <reg>, =<expr> +my $literal_num = 0; + +my $thumb = 0; + +my %thumb_labels; +my %call_targets; + +my $in_irp = 0; +my @irp_args; +my $irp_param; + +# pass 2: parse .rept and .if variants +# NOTE: since we don't implement a proper parser, using .rept with a +# variable assigned from .set is not supported +foreach my $line (@pass1_lines) { + # handle .previous (only with regard to .section not .subsection) + if ($line =~ /\.(section|text|const_data)/) { + push(@sections, $line); + } elsif ($line =~ /\.previous/) { + if (!$sections[-2]) { + die ".previous without a previous section"; + } + $line = $sections[-2]; + push(@sections, $line); + } + + $thumb = 1 if $line =~ /\.code\s+16|\.thumb/; + $thumb = 0 if $line =~ /\.code\s+32|\.arm/; + + # handle ldr <reg>, =<expr> + if ($line =~ /(.*)\s*ldr([\w\s\d]+)\s*,\s*=(.*)/) { + my $label = $literal_labels{$3}; + if (!$label) { + $label = "Literal_$literal_num"; + $literal_num++; + $literal_labels{$3} = $label; + } + $line = "$1 ldr$2, $label\n"; + } elsif ($line =~ /\.ltorg/) { + $line .= ".align 2\n"; + foreach my $literal (keys %literal_labels) { + $line .= "$literal_labels{$literal}:\n .word $literal\n"; + } + %literal_labels = (); + } + + # thumb add with large immediate needs explicit add.w + if ($thumb and $line =~ /add\s+.*#([^@]+)/) { + $line =~ s/add/add.w/ if eval_expr($1) > 255; + } + + # mach-o local symbol names start with L (no dot) + $line =~ s/(?<!\w)\.(L\w+)/$1/g; + + if ($thumb and $line =~ /^\s*(\w+)\s*:/) { + $thumb_labels{$1}++; + } + + if ($line =~ /^\s*((\w+:)?blx?|\.globl)\s+(\w+)/) { + $call_targets{$3}++; + } + + # @l -> lo16() @ha -> ha16() + $line =~ s/,\s+([^,]+)\@l\b/, lo16($1)/g; + $line =~ s/,\s+([^,]+)\@ha\b/, ha16($1)/g; + + # move to/from SPR + if ($line =~ /(\s+)(m[ft])([a-z]+)\s+(\w+)/ and exists $ppc_spr{$3}) { + if ($2 eq 'mt') { + $line = "$1${2}spr $ppc_spr{$3}, $4\n"; + } else { + $line = "$1${2}spr $4, $ppc_spr{$3}\n"; + } + } + + # old gas versions store upper and lower case names on .req, + # but they remove only one on .unreq + if ($fix_unreq) { + if ($line =~ /\.unreq\s+(.*)/) { + $line = ".unreq " . lc($1) . "\n"; + print ASMFILE ".unreq " . uc($1) . "\n"; + } + } + + if ($line =~ /\.rept\s+(.*)/) { + $num_repts = $1; + $rept_lines = "\n"; + + # handle the possibility of repeating another directive on the same line + # .endr on the same line is not valid, I don't know if a non-directive is + if ($num_repts =~ s/(\.\w+.*)//) { + $rept_lines .= "$1\n"; + } + $num_repts = eval($num_repts); + } elsif ($line =~ /\.irp\s+([\d\w\.]+)\s*(.*)/) { + $in_irp = 1; + $num_repts = 1; + $rept_lines = "\n"; + $irp_param = $1; + + # only use whitespace as the separator + my $irp_arglist = $2; + $irp_arglist =~ s/,/ /g; + $irp_arglist =~ s/^\s+//; + @irp_args = split(/\s+/, $irp_arglist); + } elsif ($line =~ /\.irpc\s+([\d\w\.]+)\s*(.*)/) { + $in_irp = 1; + $num_repts = 1; + $rept_lines = "\n"; + $irp_param = $1; + + my $irp_arglist = $2; + $irp_arglist =~ s/,/ /g; + $irp_arglist =~ s/^\s+//; + @irp_args = split(//, $irp_arglist); + } elsif ($line =~ /\.endr/) { + if ($in_irp != 0) { + foreach my $i (@irp_args) { + my $line = $rept_lines; + $line =~ s/\\$irp_param/$i/g; + $line =~ s/\\\(\)//g; # remove \() + print ASMFILE $line; + } + } else { + for (1 .. $num_repts) { + print ASMFILE $rept_lines; + } + } + $rept_lines = ''; + $in_irp = 0; + @irp_args = ''; + } elsif ($rept_lines) { + $rept_lines .= $line; + } else { + print ASMFILE $line; + } +} + +print ASMFILE ".text\n"; +print ASMFILE ".align 2\n"; +foreach my $literal (keys %literal_labels) { + print ASMFILE "$literal_labels{$literal}:\n .word $literal\n"; +} + +map print(ASMFILE ".thumb_func $_\n"), + grep exists $thumb_labels{$_}, keys %call_targets; + +close(ASMFILE) or exit 1; +#exit 1 |