diff --git a/src/ldo.c b/src/ldo.c index e1fb753..09d1ec0 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -47,21 +47,14 @@ */ #ifdef LUA_TARGET_PSX +#include "lpsxbios.h" struct JmpBuf { void * regs[12]; }; -static inline int syscall_setjmp(struct JmpBuf *buf) { - register int n asm("t1") = 0x13; - __asm__ volatile("" : "=r"(n) : "r"(n)); - return ((int (*)(struct JmpBuf * buf))0xa0)(buf); -} - -static inline __attribute__((noreturn)) void syscall_longjmp(struct JmpBuf *buf, int ret) { - register int n asm("t1") = 0x14; - __asm__ volatile("" : "=r"(n) : "r"(n)); - ((void (*)(struct JmpBuf *, int))0xa0)(buf, ret); - __builtin_unreachable(); -} -#define LUAI_THROW(L,c) syscall_longjmp(&(c)->b, 1) -#define LUAI_TRY(L,c,a) if (syscall_setjmp(&(c)->b) == 0) { a } +LUAI_PSX_BIOS_THUNK(setjmp, 0xa0, 0x13) +LUAI_PSX_BIOS_EXTERN int __psxlua_bios_setjmp(struct JmpBuf *buf) __attribute__((returns_twice)); +LUAI_PSX_BIOS_THUNK(longjmp, 0xa0, 0x14) +LUAI_PSX_BIOS_EXTERN void __psxlua_bios_longjmp(struct JmpBuf *buf, int ret) __attribute__((noreturn)); +#define LUAI_THROW(L,c) __psxlua_bios_longjmp(&(c)->b, 1) +#define LUAI_TRY(L,c,a) if (__psxlua_bios_setjmp(&(c)->b) == 0) { a } #define luai_jmpbuf struct JmpBuf #else #include @@ -99,12 +92,9 @@ static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { #ifdef LUA_TARGET_PSX -static inline void abort() { - register int n asm("t1") = 0x40; - __asm__ volatile("" : "=r"(n) : "r"(n)); - ((void (*)())0xa0)(); - __builtin_unreachable(); -} +LUAI_PSX_BIOS_THUNK(abort, 0xa0, 0x40) +LUAI_PSX_BIOS_EXTERN void __psxlua_bios_abort(void) __attribute__((noreturn)); +#define abort() __psxlua_bios_abort() #else #include #endif diff --git a/src/lpsxbios.h b/src/lpsxbios.h new file mode 100644 index 0000000..597a672 --- /dev/null +++ b/src/lpsxbios.h @@ -0,0 +1,33 @@ +/* +** BIOS calls for the PlayStation target. +** Each call goes through a two-instruction thunk, `j 0xa0` with t1 set in its +** delay slot, emitted in every file that includes this header as a weak symbol +** in its own COMDAT section, so the linker keeps one copy of each. To the +** compiler the thunk is a plain function: t1 cannot be reused before the jump, +** and the BIOS returns straight to the caller. +*/ + +#ifndef lpsxbios_h +#define lpsxbios_h + +#include + +#define LUAI_PSX_BIOS_THUNK(name, table, number) \ + __asm__(".pushsection .text.__psxlua_bios_" #name ",\"axG\",@progbits,__psxlua_bios_" #name ",comdat\n" \ + ".weak __psxlua_bios_" #name "\n" \ + ".type __psxlua_bios_" #name ", @function\n" \ + ".set push\n.set noreorder\n" \ + "__psxlua_bios_" #name ":\n" \ + " j " #table "\n" \ + " li $t1, " #number "\n" \ + ".set pop\n" \ + ".size __psxlua_bios_" #name ", . - __psxlua_bios_" #name "\n" \ + ".popsection\n"); + +#ifdef __cplusplus +#define LUAI_PSX_BIOS_EXTERN extern "C" +#else +#define LUAI_PSX_BIOS_EXTERN extern +#endif + +#endif diff --git a/src/luaconf.h b/src/luaconf.h index 3998fae..7be3106 100644 --- a/src/luaconf.h +++ b/src/luaconf.h @@ -211,18 +211,13 @@ */ #if defined(LUA_LIB) || defined(lua_c) #ifdef LUA_TARGET_PSX -static inline void syscall_write(int fd, const void * buf, size_t count) { - register int n asm("t1") = 0x03; - __asm__ volatile("" : "=r"(n) : "r"(n)); - ((void (*)(int, const void *, size_t))0xa0)(fd, buf, count); -} -static inline void syscall_putchar(int c) { - register int n asm("t1") = 0x3c; - __asm__ volatile("" : "=r"(n) : "r"(n)); - ((void (*)(int))0xa0)(c); -} -#define luai_writestring(s,l) syscall_write(1, (s), (l)) -#define luai_writeline() syscall_putchar('\n') +#include "lpsxbios.h" +LUAI_PSX_BIOS_THUNK(write, 0xa0, 0x03) +LUAI_PSX_BIOS_EXTERN size_t __psxlua_bios_write(int fd, const void * buf, size_t count); +LUAI_PSX_BIOS_THUNK(putchar, 0xa0, 0x3c) +LUAI_PSX_BIOS_EXTERN void __psxlua_bios_putchar(int c); +#define luai_writestring(s,l) __psxlua_bios_write(1, (s), (l)) +#define luai_writeline() __psxlua_bios_putchar('\n') #else #include #define luai_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)