aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile16
-rw-r--r--Makefile.libretro176
-rwxr-xr-xconfigure2
-rw-r--r--frontend/cspace_arm.S3
-rw-r--r--frontend/cspace_neon.S (renamed from frontend/cspace_neon.s)14
-rw-r--r--include/arm_features.h16
-rw-r--r--libpcsxcore/gte_arm.S47
-rw-r--r--libpcsxcore/gte_neon.S23
-rw-r--r--libpcsxcore/new_dynarec/linkage_arm.S219
-rw-r--r--plugins/dfsound/arm_utils.S18
-rw-r--r--tools/gas-preprocessor.pl527
11 files changed, 674 insertions, 387 deletions
diff --git a/Makefile b/Makefile
index 5b2bef7..a472492 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/configure b/configure
index 50378ca..bf704ed 100755
--- a/configure
+++ b/configure
@@ -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