Turn SysCalls into a C++ file

This commit is contained in:
Björn Gaier 2023-10-06 10:27:03 +02:00
parent 37e63d66f4
commit 074e2d073f
12 changed files with 228 additions and 227 deletions

View File

@ -1,175 +0,0 @@
#ifndef __JABYENGINE_SYSCALLS__H
#define __JABYENGINE_SYSCALLS__H
#include "../jabyengine_defines.h"
/*
R0 zr Constant Zero
R1 at Reserved for the assembler
R2-R3 v0-v1 Values for results and expression evaluation
R4-R7 a0-a3 Arguments
R8-R15 t0-t7 Temporaries (not preserved across call)
R16-R23 s0-s7 Saved (preserved across call)
R24-R25 t8-t9 More temporaries (not preserved across call)
R26-R27 k0-k1 Reserved for OS Kernel
R28 gp Global Pointer
R29 sp Stack Pointer
R30 fp Frame Pointer
R31 ra Return address (set by function call)
*/
static __constexpr const uint32_t __syscall_Table_A = 0xA0;
static __constexpr const uint32_t __syscall_Table_B = 0xB0;
static __constexpr const uint32_t __syscall_Table_C = 0xC0;
enum __syscall_PriorityChain {
CdromDmaIrq = 0,
CdromIoIrq = 0,
SyscallException = 0,
CardSpecificIrq = 1,
VblankIrq = 1,
Timer2Irq = 1,
Timer1Irq = 1,
Timer0Irq = 1,
PadCardIrq = 2,
DefInt = 3
};
enum InterruptVerifierResult {
SkipHandler = 0,
ExecuteHandler = 1
};
typedef InterruptVerifierResult (*InterruptVerifier)();
typedef uint32_t (*InterruptHandler)(uint32_t);
#pragma pack(push, 1)
struct InterrupCallback {
struct InterrupCallback* next;
InterruptHandler handler_function;
InterruptVerifier verifier_function;
uint32_t notUsed;
};
#pragma pack(pop)
#ifdef __cplusplus
#define __syscall_function_cast(table, ...) reinterpret_cast<__VA_ARGS__>(table)
extern "C" {
#else
#define __syscall_function_cast(table, ...) ((__VA_ARGS__)(void*)table)
#endif
static __always_inline void* __syscall_memcpy(void *dst, const void *src, size_t len) {
register uint32_t FuncID asm("t1") = 0x2A;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
return __syscall_function_cast(__syscall_Table_A, void*(*)(void*, const void*, size_t))(dst, src, len);
}
static __always_inline void __syscall_InitPad(uint8_t *portA, uint32_t portASize, uint8_t *portB, uint32_t portBSize) {
register uint32_t FuncID asm("t1") = 0x12;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
__syscall_function_cast(__syscall_Table_B, void(*)(uint8_t*, uint32_t, uint8_t*, uint32_t))(portA, portASize, portB, portBSize);
}
static __always_inline void __syscall_StartPad() {
register uint32_t FuncID asm("t1") = 0x13;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
__syscall_function_cast(__syscall_Table_B, void(*)())();
}
static __always_inline void __syscall_StopPad() {
register uint32_t FuncID asm("t1") = 0x14;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
__syscall_function_cast(__syscall_Table_B, void(*)())();
}
static __always_inline void __syscall_ChangeClearPad(int32_t _reserved) {
register uint32_t FuncID asm("t1") = 0x5B;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
__syscall_function_cast(__syscall_Table_B, void(*)(int32_t))(_reserved);
}
static __always_inline void [[noreturn]] __syscall_ReturnFromException() {
register uint32_t FuncID asm("t1") = 0x17;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
__syscall_function_cast(__syscall_Table_B, void(*)())();
}
static __always_inline int __syscall_SysEnqIntRP(enum __syscall_PriorityChain prio, struct InterrupCallback* interElm) {
register uint32_t FuncID asm("t1") = 0x02;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
return __syscall_function_cast(__syscall_Table_C, int(*)(enum __syscall_PriorityChain prio, struct InterrupCallback *interElm))(prio, interElm);
}
static __always_inline int __syscall_SysDeqIntRP(enum __syscall_PriorityChain prio, struct InterrupCallback *interElm) {
register uint32_t FuncID asm("t1") = 0x03;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
return __syscall_function_cast(__syscall_Table_C, int(*)(enum __syscall_PriorityChain prio, struct InterrupCallback *interElm))(prio, interElm);
}
static __always_inline uint32_t __syscall_EnterCriticalSection() {
register uint32_t FuncID asm("a0") = 0x01;
register uint32_t returnValue asm("v0");
__asm__ volatile("syscall" : "=r"(FuncID), "=r"(returnValue) : "r"(FuncID) : "at", "v1", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "memory");
return returnValue;
}
static __always_inline void __syscall_ExitCriticalSection() {
register uint32_t FuncID asm("a0") = 0x02;
__asm__ volatile("syscall" : "=r"(FuncID) : "r"(FuncID) : "at", "v0", "v1", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "memory");
}
static __always_inline void __syscall__DeliverEvent(uint32_t classId, uint32_t spec) {
register uint32_t FuncID asm("t1") = 0x07;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
__syscall_function_cast(__syscall_Table_B, void (*)(uint32_t, uint32_t))(classId, spec);
}
static __always_inline uint32_t __syscall_OpenEvent(uint32_t classId, uint32_t spec, uint32_t mode, void (*handler)()) {
register uint32_t FuncID asm("t1") = 0x08;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
return __syscall_function_cast(__syscall_Table_B, uint32_t(*)(uint32_t, uint32_t, uint32_t, void(*)()))(classId, spec, mode, handler);
}
static __always_inline int __syscall_CloseEvent(uint32_t event) {
register uint32_t FuncID asm("t1") = 0x09;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
return __syscall_function_cast(__syscall_Table_B, uint32_t(*)(uint32_t))(event);
}
static __always_inline int __syscall_TestEvent(uint32_t event) {
register uint32_t FuncID asm("t1") = 0x0B;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
return __syscall_function_cast(__syscall_Table_B, int (*)(uint32_t))(event);
}
static __always_inline int __syscall_EnableEvent(uint32_t event) {
register uint32_t FuncID asm("t1") = 0x0C;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
return __syscall_function_cast(__syscall_Table_B, int (*)(uint32_t))(event);
}
void __syscall_printf(const char* txt, ...);
#ifdef __cplusplus
}
#endif
#endif //!__JABYENGINE_SYSCALLS__H

View File

@ -0,0 +1,167 @@
#pragma once
#include "../jabyengine_defines.h"
/*
R0 zr Constant Zero
R1 at Reserved for the assembler
R2-R3 v0-v1 Values for results and expression evaluation
R4-R7 a0-a3 Arguments
R8-R15 t0-t7 Temporaries (not preserved across call)
R16-R23 s0-s7 Saved (preserved across call)
R24-R25 t8-t9 More temporaries (not preserved across call)
R26-R27 k0-k1 Reserved for OS Kernel
R28 gp Global Pointer
R29 sp Stack Pointer
R30 fp Frame Pointer
R31 ra Return address (set by function call)
*/
namespace JabyEngine {
namespace SysCall {
static constexpr const uint32_t Table_A = 0xA0;
static constexpr const uint32_t Table_B = 0xB0;
static constexpr const uint32_t Table_C = 0xC0;
enum struct Priority {
CdromDmaIrq = 0,
CdromIoIrq = 0,
SyscallException = 0,
CardSpecificIrq = 1,
VblankIrq = 1,
Timer2Irq = 1,
Timer1Irq = 1,
Timer0Irq = 1,
PadCardIrq = 2,
DefInt = 3
};
enum InterruptVerifierResult {
SkipHandler = 0,
ExecuteHandler = 1
};
typedef InterruptVerifierResult (*InterruptVerifier)();
typedef uint32_t (*InterruptHandler)(uint32_t);
#pragma pack(push, 1)
struct InterrupCallback {
struct InterrupCallback* next;
InterruptHandler handler_function;
InterruptVerifier verifier_function;
uint32_t notUsed;
};
#pragma pack(pop)
#define __syscall_function_cast(table, ...) reinterpret_cast<__VA_ARGS__>(table)
static __always_inline void* memcpy(void *dst, const void *src, size_t len) {
register uint32_t FuncID asm("t1") = 0x2A;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
return __syscall_function_cast(Table_A, void*(*)(void*, const void*, size_t))(dst, src, len);
}
static __always_inline void InitPad(uint8_t *portA, uint32_t portASize, uint8_t *portB, uint32_t portBSize) {
register uint32_t FuncID asm("t1") = 0x12;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
__syscall_function_cast(Table_B, void(*)(uint8_t*, uint32_t, uint8_t*, uint32_t))(portA, portASize, portB, portBSize);
}
static __always_inline void StartPad() {
register uint32_t FuncID asm("t1") = 0x13;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
__syscall_function_cast(Table_B, void(*)())();
}
static __always_inline void StopPad() {
register uint32_t FuncID asm("t1") = 0x14;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
__syscall_function_cast(Table_B, void(*)())();
}
static __always_inline void ChangeClearPad(int32_t _reserved) {
register uint32_t FuncID asm("t1") = 0x5B;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
__syscall_function_cast(Table_B, void(*)(int32_t))(_reserved);
}
static __always_inline void [[noreturn]] ReturnFromException() {
register uint32_t FuncID asm("t1") = 0x17;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
__syscall_function_cast(Table_B, void(*)())();
}
static __always_inline int SysEnqIntRP(Priority prio, InterrupCallback* interElm) {
register uint32_t FuncID asm("t1") = 0x02;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
return __syscall_function_cast(Table_C, int(*)(Priority prio, InterrupCallback *interElm))(prio, interElm);
}
static __always_inline int SysDeqIntRP(Priority prio, InterrupCallback *interElm) {
register uint32_t FuncID asm("t1") = 0x03;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
return __syscall_function_cast(Table_C, int(*)(Priority prio, InterrupCallback *interElm))(prio, interElm);
}
static __always_inline uint32_t EnterCriticalSection() {
register uint32_t FuncID asm("a0") = 0x01;
register uint32_t returnValue asm("v0");
__asm__ volatile("syscall" : "=r"(FuncID), "=r"(returnValue) : "r"(FuncID) : "at", "v1", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "memory");
return returnValue;
}
static __always_inline void ExitCriticalSection() {
register uint32_t FuncID asm("a0") = 0x02;
__asm__ volatile("syscall" : "=r"(FuncID) : "r"(FuncID) : "at", "v0", "v1", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "memory");
}
static __always_inline void DeliverEvent(uint32_t classId, uint32_t spec) {
register uint32_t FuncID asm("t1") = 0x07;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
__syscall_function_cast(Table_B, void (*)(uint32_t, uint32_t))(classId, spec);
}
static __always_inline uint32_t OpenEvent(uint32_t classId, uint32_t spec, uint32_t mode, void (*handler)()) {
register uint32_t FuncID asm("t1") = 0x08;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
return __syscall_function_cast(Table_B, uint32_t(*)(uint32_t, uint32_t, uint32_t, void(*)()))(classId, spec, mode, handler);
}
static __always_inline int CloseEvent(uint32_t event) {
register uint32_t FuncID asm("t1") = 0x09;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
return __syscall_function_cast(Table_B, uint32_t(*)(uint32_t))(event);
}
static __always_inline int TestEvent(uint32_t event) {
register uint32_t FuncID asm("t1") = 0x0B;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
return __syscall_function_cast(Table_B, int (*)(uint32_t))(event);
}
static __always_inline int EnableEvent(uint32_t event) {
register uint32_t FuncID asm("t1") = 0x0C;
__asm__ volatile("" : "=r"(FuncID) : "r"(FuncID));
return __syscall_function_cast(Table_B, int (*)(uint32_t))(event);
}
void printf(const char* txt, ...);
}
}

View File

@ -12,7 +12,11 @@
#ifdef __cplusplus
#define __constexpr constexpr
#define START_C_FUNCTIONS extern "C" {
#define END_C_FUNCTIONS }
#else
#define __constexpr
#define START_C_FUNCTIONS
#define END_C_FUNCTIONS
#endif
#endif //!__JABYENGINE_DEFINES__H__

View File

@ -1,7 +1,8 @@
#ifndef __STDIO__H
#define __STDIO__H
#include "PSX/System/syscalls.h"
#define printf __syscall_printf
#include "PSX/jabyengine_defines.h"
START_C_FUNCTIONS
int printf(const char* txt, ...) asm("_ZN10JabyEngine7SysCall6printfEPKcz");
END_C_FUNCTIONS
#endif //!__STDIO__H

View File

@ -1 +1 @@
rebuild: |clean all
rebuild: | clean all

View File

@ -2,12 +2,12 @@
#include "../../internal-include/CD/cd_internal.hpp"
#include <PSX/System/IOPorts/interrupt_io.hpp>
#include <PSX/System/IOPorts/memory_io.hpp>
#include <PSX/System/syscalls.h>
#include <PSX/System/syscalls.hpp>
namespace JabyEngine {
namespace CD {
namespace internal {
extern InterrupCallback callback;
extern SysCall::InterrupCallback callback;
}
}
@ -21,11 +21,11 @@ namespace JabyEngine {
static constexpr auto DebugScale = 1.0;
__debug_boot_color_at(::JabyEngine::GPU::Color24::White(), DebugX, DebugY, DebugScale);
__syscall_EnterCriticalSection();
SysCall::EnterCriticalSection();
Memory_IO::COM_DELAY.write(Memory_IO::COM_DELAY::create());
Memory_IO::CD_DELAY.write(Memory_IO::CD_DELAY::create());
__syscall_SysEnqIntRP(CdromIoIrq, &::JabyEngine::CD::internal::callback);
SysCall::SysEnqIntRP(SysCall::Priority::CdromIoIrq, &::JabyEngine::CD::internal::callback);
CD_IO::PortIndex1::change_to();
CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag);
@ -34,7 +34,7 @@ namespace JabyEngine {
Interrupt::enable_irq(Interrupt::CDROM);
Interrupt::ack_irq(Interrupt::CDROM);
__syscall_ExitCriticalSection();
SysCall::ExitCriticalSection();
__debug_boot_color_at(::JabyEngine::GPU::Color24::Red(), DebugX, DebugY, DebugScale);
CD_IO::PortIndex0::change_to();

View File

@ -3,6 +3,7 @@
#include <PSX/Auxiliary/lz4_decompressor.hpp>
#include <PSX/File/Processor/file_processor.hpp>
#include <PSX/GPU/gpu.hpp>
#include <PSX/System/syscalls.hpp>
#include <stdio.h>
#ifdef JABYENGINE_PAL
@ -16,7 +17,7 @@ extern "C" uint32_t __boot_loader_end;
namespace JabyEngine {
namespace GPU {
namespace internal {
extern InterrupCallback callback;
extern SysCall::InterrupCallback callback;
}
}
@ -72,10 +73,10 @@ namespace JabyEngine {
GPU::internal::wait_ready_for_CMD();
GPU::internal::quick_fill_fast(Color24::Black(), {PositionU16::create(0, 0), SizeU16::create(Display::Width, Display::Height)});
__syscall_EnterCriticalSection();
__syscall_SysEnqIntRP(VblankIrq, &::JabyEngine::GPU::internal::callback);
SysCall::EnterCriticalSection();
SysCall::SysEnqIntRP(SysCall::Priority::VblankIrq, &::JabyEngine::GPU::internal::callback);
Interrupt::enable_irq(Interrupt::VBlank);
__syscall_ExitCriticalSection();
SysCall::ExitCriticalSection();
}
}
}

View File

@ -1,12 +1,12 @@
#include <PSX/System/IOPorts/interrupt_io.hpp>
#include <PSX/System/syscalls.h>
#include <PSX/System/syscalls.hpp>
#define private public
#include <PSX/Timer/high_res_timer.hpp>
#undef private
namespace JabyEngine {
namespace Timer {
extern InterrupCallback IRQCallback;
extern SysCall::InterrupCallback IRQCallback;
}
namespace boot {
@ -22,9 +22,9 @@ namespace JabyEngine {
// Having the interrupt fire every 10ms will slow us down slightly so we only do it on demand
Interrupt::disable_irq(Interrupt::Timer2);
__syscall_EnterCriticalSection();
__syscall_SysEnqIntRP(Timer2Irq, &IRQCallback);
__syscall_ExitCriticalSection();
SysCall::EnterCriticalSection();
SysCall::SysEnqIntRP(SysCall::Priority::Timer2Irq, &IRQCallback);
SysCall::ExitCriticalSection();
Counter2.set_target_value(HighResTime::TicksFor10ms);
Counter2.set_mode(Mode);

View File

@ -1,26 +1,26 @@
#include "../../internal-include/CD/cd_internal.hpp"
#include <PSX/System/IOPorts/dma_io.hpp>
#include <PSX/System/IOPorts/interrupt_io.hpp>
#include <PSX/System/syscalls.h>
#include <PSX/System/syscalls.hpp>
namespace JabyEngine {
namespace CD {
namespace internal {
static constexpr auto DataSectorMode = CD_IO::Mode::from(CD_IO::Mode::DoubleSpeed, CD_IO::Mode::DataSector);
static InterruptVerifierResult interrupt_verifier();
static void interrupt_handler(uint32_t);
static SysCall::InterruptVerifierResult interrupt_verifier();
static uint32_t interrupt_handler(uint32_t);
static SectorBufferAllocator sector_allocator;
static uint32_t cur_lba;
static uint32_t dst_lba;
CD_IO::Interrupt::Type last_interrupt = CD_IO::Interrupt::Type::None;
uint8_t cmd_interrupt_bit = 0;
State current_state = State::Free;
InterrupCallback callback = {
CD_IO::Interrupt::Type last_interrupt = CD_IO::Interrupt::Type::None;
uint8_t cmd_interrupt_bit = 0;
State current_state = State::Free;
SysCall::InterrupCallback callback = {
.next = nullptr,
.handler_function = reinterpret_cast<InterruptHandler>(interrupt_handler),
.handler_function = interrupt_handler,
.verifier_function = interrupt_verifier
};
@ -68,17 +68,17 @@ namespace JabyEngine {
// Doesn't seem to important when we can use DMA
}
static InterruptVerifierResult interrupt_verifier() {
static SysCall::InterruptVerifierResult interrupt_verifier() {
if(Interrupt::is_irq(Interrupt::CDROM)) {
return InterruptVerifierResult::ExecuteHandler;
return SysCall::InterruptVerifierResult::ExecuteHandler;
}
else {
return InterruptVerifierResult::SkipHandler;
return SysCall::InterruptVerifierResult::SkipHandler;
}
}
static void interrupt_handler(uint32_t) {
static uint32_t interrupt_handler(uint32_t) {
const auto old_status = CD_IO::IndexStatus.read();
CD_IO::PortIndex1::change_to();
@ -114,7 +114,8 @@ namespace JabyEngine {
// No masking required because we can only write bit 0 - 2
CD_IO::IndexStatus.write(old_status);
Interrupt::ack_irq(Interrupt::CDROM);
__syscall_ReturnFromException();
SysCall::ReturnFromException();
__builtin_unreachable();
}
void read_file(AutoLBAEntry file_info, const SectorBufferAllocator& buffer_allocator) {

View File

@ -4,40 +4,41 @@
#include <PSX/Timer/frame_timer.hpp>
#undef private
#include <PSX/System/IOPorts/interrupt_io.hpp>
#include <PSX/System/syscalls.h>
#include <PSX/System/syscalls.hpp>
namespace JabyEngine {
namespace GPU {
uint8_t Display :: current_id = 1; //< Setup will call exchange and set it to 0
namespace internal {
static InterruptVerifierResult interrupt_verifier();
static void interrupt_handler(uint32_t);
static SysCall::InterruptVerifierResult interrupt_verifier();
static uint32_t interrupt_handler(uint32_t);
static uint8_t vsync_counter = 0;
InterrupCallback callback = {
SysCall::InterrupCallback callback = {
.next = nullptr,
.handler_function = reinterpret_cast<InterruptHandler>(interrupt_handler),
.handler_function = interrupt_handler,
.verifier_function = interrupt_verifier
};
static InterruptVerifierResult interrupt_verifier() {
static SysCall::InterruptVerifierResult interrupt_verifier() {
if(Interrupt::is_irq(Interrupt::VBlank)) {
return InterruptVerifierResult::ExecuteHandler;
return SysCall::InterruptVerifierResult::ExecuteHandler;
}
else {
return InterruptVerifierResult::SkipHandler;
return SysCall::InterruptVerifierResult::SkipHandler;
}
}
static void interrupt_handler(uint32_t) {
static uint32_t interrupt_handler(uint32_t) {
vsync_counter++;
MasterTime::value++;
Interrupt::ack_irq(Interrupt::VBlank);
__syscall_ReturnFromException();
SysCall::ReturnFromException();
__builtin_unreachable();
}
uint32_t Display :: exchange_buffer_and_display() {

View File

@ -1,6 +1,6 @@
#define private public
#include <PSX/System/IOPorts/timer_io.hpp>
#include <PSX/System/syscalls.h>
#include <PSX/System/syscalls.hpp>
#include <PSX/Timer/high_res_timer.hpp>
#undef private
@ -8,26 +8,27 @@ namespace JabyEngine {
volatile uint16_t HighResTime :: global_counter_10ms = 0;
namespace Timer {
static InterruptVerifierResult interrupt_verifier() {
static SysCall::InterruptVerifierResult interrupt_verifier() {
if(Interrupt::is_irq(Interrupt::Timer2)) {
return InterruptVerifierResult::ExecuteHandler;
return SysCall::InterruptVerifierResult::ExecuteHandler;
}
else {
return InterruptVerifierResult::SkipHandler;
return SysCall::InterruptVerifierResult::SkipHandler;
}
}
static void interrupt_handler(uint32_t) {
static uint32_t interrupt_handler(uint32_t) {
HighResTime::global_counter_10ms = HighResTime::global_counter_10ms + 1;
Interrupt::ack_irq(Interrupt::Timer2);
__syscall_ReturnFromException();
SysCall::ReturnFromException();
__builtin_unreachable();
}
InterrupCallback IRQCallback = {
SysCall::InterrupCallback IRQCallback = {
.next = nullptr,
.handler_function = reinterpret_cast<InterruptHandler>(interrupt_handler),
.handler_function = interrupt_handler,
.verifier_function = interrupt_verifier
};
}

View File

@ -2,10 +2,10 @@
.set noreorder
.section .text, "ax", @progbits
.align 2
.global __syscall_printf
.type __syscall_printf, @function
.global _ZN10JabyEngine7SysCall6printfEPKcz
.type _ZN10JabyEngine7SysCall6printfEPKcz, @function
__syscall_printf:
_ZN10JabyEngine7SysCall6printfEPKcz:
li $t2, 0xa0
jr $t2
li $t1, 0x3f