diff --git a/examples/PoolBox/PoolBox.code-workspace b/examples/PoolBox/PoolBox.code-workspace index 2939de43..540f55ec 100644 --- a/examples/PoolBox/PoolBox.code-workspace +++ b/examples/PoolBox/PoolBox.code-workspace @@ -93,7 +93,7 @@ "settings": { "C_Cpp.default.includePath": [ "${env:JABY_ENGINE_PATH}/include", - "${env:JABY_ENGINE_PATH}/Support/include" + "${env:JABY_ENGINE_PATH}/support/include" ], "C_Cpp.default.compilerPath": "", "C_Cpp.default.cStandard": "c17", diff --git a/examples/PoolBox/application/Makefile b/examples/PoolBox/application/Makefile index 4ad6e032..cd3f4824 100644 --- a/examples/PoolBox/application/Makefile +++ b/examples/PoolBox/application/Makefile @@ -3,7 +3,7 @@ OVERLAY_CONFIG = Overlays.json include $(JABY_ENGINE_DIR)/mkfile/common/Wildcard.mk SRCS = $(call rwildcard, src, c cpp) -INCLUDES += -I$(JABY_ENGINE_DIR)/Support/include -I$(JABY_ENGINE_DIR)/include +INCLUDES += -I$(JABY_ENGINE_DIR)/support/include -I$(JABY_ENGINE_DIR)/include CCFLAGS += -save-temps=obj SUPPORT_LIBS += FontWriter diff --git a/examples/PoolBox/application/src/application.cpp b/examples/PoolBox/application/src/application.cpp index e2ff39e6..902ca15e 100644 --- a/examples/PoolBox/application/src/application.cpp +++ b/examples/PoolBox/application/src/application.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include using namespace JabyEngine; @@ -155,6 +156,10 @@ namespace LoadingScene { static void run() { if(old_state_changer != state_changer) { printf("Loading new state...\n"); + + Callback::VSyncCallback::install([]() { + printf("Still loading...\n"); + }); update(); GPU::swap_buffers_vsync(1); @@ -165,6 +170,7 @@ namespace LoadingScene { state_changer.asset_load(); old_state_changer = state_changer; CDDA::pop_play(); + Callback::VSyncCallback::uninstall(); } state_changer.main(); diff --git a/include/PSX/Audio/CDDA.hpp b/include/PSX/Audio/CDDA.hpp index bea2d1d6..acb6fc89 100644 --- a/include/PSX/Audio/CDDA.hpp +++ b/include/PSX/Audio/CDDA.hpp @@ -15,7 +15,7 @@ namespace JabyEngine { TrackList get_tracks(); void play(uint8_t track); - void pause(); + void stop(); void push_play(); void pop_play(); diff --git a/include/PSX/System/IOPorts/cd_io.hpp b/include/PSX/System/IOPorts/cd_io.hpp index 8c1038bf..1ea6ecf0 100644 --- a/include/PSX/System/IOPorts/cd_io.hpp +++ b/include/PSX/System/IOPorts/cd_io.hpp @@ -160,6 +160,7 @@ namespace JabyEngine { static constexpr Desc SetMode{0x0E, Interrupt::Type::Acknowledge}; static constexpr Desc GetLocP{0x11, Interrupt::Type::Acknowledge}; static constexpr Desc GetTN{0x13, Interrupt::Type::Acknowledge}; + static constexpr Desc GetTD{0x14, Interrupt::Type::Acknowledge}; }; static constexpr auto IORegister1Adr = 0x1F801801; diff --git a/include/PSX/System/callbacks.hpp b/include/PSX/System/callbacks.hpp new file mode 100644 index 00000000..ae6e950c --- /dev/null +++ b/include/PSX/System/callbacks.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "syscalls.hpp" + +namespace JabyEngine { + namespace Callback { + struct VSyncCallback { + using Function = void (*)(); + + static Function callback; + + static void install(Function function) { + VSyncCallback::callback = function; + } + + static void uninstall() { + VSyncCallback::install(nullptr); + } + }; + } +} \ No newline at end of file diff --git a/include/PSX/System/syscalls.hpp b/include/PSX/System/syscalls.hpp index df0694a5..92c64a29 100644 --- a/include/PSX/System/syscalls.hpp +++ b/include/PSX/System/syscalls.hpp @@ -45,6 +45,51 @@ namespace JabyEngine { extern const Version version; } + struct TCB { + uint32_t status; + uint32_t unused; + uint32_t reg[32]; + uint32_t epc; + uint32_t hi; + uint32_t lo; + uint32_t sr; + uint32_t cause; + uint32_t unused2[9]; + }; + + struct PCB { + TCB* current_tcb; + }; + + struct ToT { + using ExCB = void; + using EvCB = void; + using FCB = void; + + ExCB* exception_chain; + uint32_t exception_chain_size; + PCB* processes; + uint32_t processes_size; + TCB* threads; + uint32_t threads_size; + uint32_t reserved_0; + uint32_t reserved_1; + EvCB* events; + uint32_t events_size; + uint32_t reserved_2; + uint32_t reserved_3; + uint32_t reserved_4; + uint32_t reserved_5; + uint32_t reserved_6; + uint32_t reserved_7; + FCB* files; + uint32_t files_size; + uint32_t reserved_8; + uint32_t reserved_9; + }; + + extern ToT table_of_tables; + namespace SysCall { static constexpr const uint32_t Table_A = 0xA0; static constexpr const uint32_t Table_B = 0xB0; @@ -73,6 +118,7 @@ namespace JabyEngine { typedef InterruptVerifierResult (*InterruptVerifier)(); typedef uint32_t (*InterruptHandler)(uint32_t); + using ThreadHandle = uint32_t; #pragma pack(push, 1) struct InterrupCallback { @@ -85,6 +131,12 @@ namespace JabyEngine { #define __syscall_function_cast(table, ...) reinterpret_cast<__VA_ARGS__>(table) + static __always_inline uint32_t* get_gp() { + uint32_t* gp; + __asm__("sw $gp, %0" : "=m"(gp)); + return gp; + } + 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)); @@ -92,6 +144,13 @@ namespace JabyEngine { return __syscall_function_cast(Table_A, void*(*)(void*, const void*, size_t))(dst, src, len); } + static __always_inline ThreadHandle OpenThread(void (*thread_func)(), uint32_t* stack_ptr, uint32_t* gp) { + register uint32_t FuncID asm("t1") = 0x0E; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + return __syscall_function_cast(Table_B, ThreadHandle(*)(void(*)(), uint32_t*, uint32_t*))(thread_func, stack_ptr, gp); + } + 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)); diff --git a/include/PSX/System/threads.hpp b/include/PSX/System/threads.hpp new file mode 100644 index 00000000..1ee97422 --- /dev/null +++ b/include/PSX/System/threads.hpp @@ -0,0 +1,43 @@ +#pragma once +#include "syscalls.hpp" + +namespace JabyEngine { + struct Thread { + static constexpr uint32_t idx_from_handle(SysCall::ThreadHandle thread) { + return thread & 0xFFFF; + } + + static void prepare_next(SysCall::ThreadHandle thread) { + table_of_tables.processes->current_tcb = &table_of_tables.threads[idx_from_handle(thread)]; + } + + static void execute_next() { + SysCall::ReturnFromException(); + } + + static void set_kernel_mode_for(SysCall::ThreadHandle handle) { + table_of_tables.threads[idx_from_handle(handle)].sr = 0x0; + } + + static void set_user_mode_for(SysCall::ThreadHandle handle) { + table_of_tables.threads[idx_from_handle(handle)].sr = 0x40000404; + } + }; + + struct MainThread { + static void prepare_if_main(SysCall::ThreadHandle handle) { + if(table_of_tables.processes->current_tcb == &table_of_tables.threads[0]) { + Thread::prepare_next(handle); + } + } + + static void prepare_restore() { + Thread::prepare_next(0); + } + + static void restore() { + MainThread::prepare_restore(); + Thread::execute_next(); + } + }; +} \ No newline at end of file diff --git a/mkfile/PSEXETarget.mk b/mkfile/PSEXETarget.mk index 85632fa6..ac315988 100644 --- a/mkfile/PSEXETarget.mk +++ b/mkfile/PSEXETarget.mk @@ -5,7 +5,7 @@ include $(AUTO_OVERLAY_DIR)/Overlays.mk include $(JABY_ENGINE_DIR)/mkfile/common/CustomConfigHelper.mk JABY_ENGINE_LIB_DIR = $(JABY_ENGINE_DIR)/lib/PSX-$(BUILD_PROFILE)/$(CUSTOM_CONFIG) -JABY_ENGINE_SUPPORT_LIB_DIR = $(JABY_ENGINE_DIR)/Support/lib/PSX-$(BUILD_PROFILE) +JABY_ENGINE_SUPPORT_LIB_DIR = $(JABY_ENGINE_DIR)/support/lib/PSX-$(BUILD_PROFILE) JABY_ENGINE_SUPPORT_LIBS = $(addprefix -l,$(SUPPORT_LIBS)) JABY_ENGINE_SUPPORT_DEPS = $(addsuffix .a,$(addprefix $(JABY_ENGINE_SUPPORT_LIB_DIR)/lib,$(SUPPORT_LIBS))) JABY_ENGINE_LIB_NAME = JabyEngine_$(PSX_TV_FORMAT) diff --git a/mkfile/psexe.ld b/mkfile/psexe.ld index cde05fcb..d1fef6ec 100644 --- a/mkfile/psexe.ld +++ b/mkfile/psexe.ld @@ -31,10 +31,11 @@ ENTRY(_ZN10JabyEngine5startEv) TLOAD_ADDR = DEFINED(TLOAD_ADDR) ? TLOAD_ADDR : 0x80010000; MEMORY { + bios : ORIGIN = 0x100, LENGTH = 0x500 loader : ORIGIN = (TLOAD_ADDR - 0x800), LENGTH = 2048 - ram(rwx) : ORIGIN = 0x80010000, LENGTH = 2M - 0x10000 - ram_alt(rwx) : ORIGIN = 0x80010000, LENGTH = 2M - 0x10000 - dcache : ORIGIN = 0x1f800000, LENGTH = 0x400 + ram(rwx) : ORIGIN = 0x80010000, LENGTH = 2M - 0x10000 + ram_alt(rwx) : ORIGIN = 0x80010000, LENGTH = 2M - 0x10000 + dcache : ORIGIN = 0x1f800000, LENGTH = 0x400 } __ram_top = ORIGIN(ram) + LENGTH(ram); @@ -50,7 +51,12 @@ __persistent_lbas_len = (__persistent_lbas_end - __persistent_lbas_start); __stack_start = ORIGIN(ram) + LENGTH(ram); + SECTIONS { + .bios (NOLOAD) : { + _ZN10JabyEngine15table_of_tablesE = .; + } > bios + /DISCARD/ : { *(.MIPS.abiflags) } /* Everything is statically linked, so discard PLTs. */ diff --git a/src/Library/internal-include/BootLoader/boot_loader.hpp b/src/Library/internal-include/BootLoader/boot_loader.hpp index 38b3ac0f..49b5a6ea 100644 --- a/src/Library/internal-include/BootLoader/boot_loader.hpp +++ b/src/Library/internal-include/BootLoader/boot_loader.hpp @@ -8,6 +8,10 @@ namespace JabyEngine { void identify(); } + namespace Callbacks { + void setup(); + } + namespace CD { void setup(); } diff --git a/src/Library/internal-include/CD/cd_internal.hpp b/src/Library/internal-include/CD/cd_internal.hpp index 79e9efcc..71ce373c 100644 --- a/src/Library/internal-include/CD/cd_internal.hpp +++ b/src/Library/internal-include/CD/cd_internal.hpp @@ -4,9 +4,8 @@ namespace JabyEngine { namespace CD { namespace internal { - extern State current_state; - extern CD_IO::Interrupt::Type last_interrupt; - extern uint8_t cmd_interrupt_bit; + extern State current_state; + extern uint8_t cmd_interrupt_bit; struct Command { static void wait_completed() { diff --git a/src/Library/internal-include/System/callbacks_internal.hpp b/src/Library/internal-include/System/callbacks_internal.hpp new file mode 100644 index 00000000..6664e202 --- /dev/null +++ b/src/Library/internal-include/System/callbacks_internal.hpp @@ -0,0 +1,21 @@ +#pragma once +#include + +namespace JabyEngine { + namespace Callback { + namespace internal { + namespace VSync { + static constexpr size_t StackSize = 64; + + extern SysCall::ThreadHandle thread_handle; + extern uint32_t stack[StackSize]; + void routine(); + + static void execute() { + MainThread::prepare_if_main(VSync::thread_handle); + Thread::execute_next(); + } + } + } + } +} diff --git a/src/Library/src/Audio/CDDA.cpp b/src/Library/src/Audio/CDDA.cpp index 527e5ec4..8888ae88 100644 --- a/src/Library/src/Audio/CDDA.cpp +++ b/src/Library/src/Audio/CDDA.cpp @@ -1,11 +1,11 @@ #include "../../internal-include/CD/cd_internal.hpp" #include -#include namespace JabyEngine { namespace CDDA { namespace CD = JabyEngine::CD::internal; + static CD::CDTimeStamp playing_track; static CD::CDTimeStamp last_track; TrackList get_tracks() { @@ -28,16 +28,22 @@ namespace JabyEngine { void play(uint8_t track) { CD::enable_CDDA(); // < Command waits + + CD::Command::send_wait(CD_IO::Command::GetTD, track); + const auto stats = CD_IO::PortIndex0::ResponseFifo.read().raw; + playing_track.min = CD_IO::PortIndex0::ResponseFifo.read().raw; + playing_track.sec = CD_IO::PortIndex0::ResponseFifo.read().raw; + CD::Command::send(CD_IO::Command::Play, track); } - void pause() { + void stop() { CD::Command::wait_completed(); CD::Command::send(CD_IO::Command::Pause); } void push_play() { - pause(); + stop(); CD::Command::wait_completed(); CD::Command::send_wait(CD_IO::Command::GetLocP); @@ -53,8 +59,8 @@ namespace JabyEngine { void pop_play() { CD::Command::wait_completed(); - CD::Command::send_wait(CD_IO::Command::SetLoc, last_track.min, last_track.sec, last_track.sector); CD::enable_CDDA(); // < Command waits + CD::Command::send_wait(CD_IO::Command::SetLoc, last_track.min, last_track.sec, last_track.sector); CD::Command::send(CD_IO::Command::Play); } } diff --git a/src/Library/src/BootLoader/callbacks_boot.cpp b/src/Library/src/BootLoader/callbacks_boot.cpp new file mode 100644 index 00000000..7c5fb44b --- /dev/null +++ b/src/Library/src/BootLoader/callbacks_boot.cpp @@ -0,0 +1,21 @@ +#include "../../internal-include/BootLoader/boot_loader.hpp" +#include "../../internal-include/System/callbacks_internal.hpp" + +namespace JabyEngine { + namespace boot { + namespace Callbacks { + namespace InternalCallback = JabyEngine::Callback::internal; + + void setup() { + SysCall::EnterCriticalSection(); + InternalCallback::VSync::thread_handle = SysCall::OpenThread( + InternalCallback::VSync::routine, + &InternalCallback::VSync::stack[InternalCallback::VSync::StackSize - 1], + SysCall::get_gp() + ); + Thread::set_user_mode_for(InternalCallback::VSync::thread_handle); + SysCall::ExitCriticalSection(); + } + } + } +} \ No newline at end of file diff --git a/src/Library/src/BootLoader/start_boot.cpp b/src/Library/src/BootLoader/start_boot.cpp index c97c659e..4c85bae2 100644 --- a/src/Library/src/BootLoader/start_boot.cpp +++ b/src/Library/src/BootLoader/start_boot.cpp @@ -47,6 +47,7 @@ namespace JabyEngine { static constexpr auto DebugScale = 1.0; BIOS::identify(); + Callbacks::setup(); __debug_boot_color_at(::JabyEngine::GPU::Color24::Grey(), DebugX, DebugY, DebugScale); DMA::setup(); @@ -69,7 +70,6 @@ namespace JabyEngine { test_bios_font(); test_gte_scale(); - //Pause?? SPU::setup(); } } diff --git a/src/Library/src/CD/cd.cpp b/src/Library/src/CD/cd.cpp index df38ae1f..39d3f992 100644 --- a/src/Library/src/CD/cd.cpp +++ b/src/Library/src/CD/cd.cpp @@ -2,11 +2,12 @@ #include #include #include +#include namespace JabyEngine { namespace CD { namespace internal { - static constexpr auto AudioSectorMode = CD_IO::Mode::from(CD_IO::Mode::SingleSpeed, CD_IO::Mode::CDDA); + static constexpr auto AudioSectorMode = CD_IO::Mode::from(CD_IO::Mode::SingleSpeed, CD_IO::Mode::AutoPauseTrack, CD_IO::Mode::CDDA); static constexpr auto DataSectorMode = CD_IO::Mode::from(CD_IO::Mode::DoubleSpeed, CD_IO::Mode::DataSector); static SysCall::InterruptVerifierResult interrupt_verifier(); @@ -16,7 +17,6 @@ namespace JabyEngine { 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; SysCall::InterrupCallback callback = { @@ -84,32 +84,45 @@ namespace JabyEngine { CD_IO::PortIndex1::change_to(); const auto cur_irq = CD_IO::Interrupt::get_type(CD_IO::PortIndex1::InterruptFlag); - last_interrupt = cur_irq; CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag); cmd_interrupt_bit = bit::clear(cmd_interrupt_bit, cur_irq); - if(cur_irq == CD_IO::Interrupt::DataReady) { - // Obtain sector content here - auto* sector = sector_allocator.allocate_sector(); - if(sector) { - //Now obtain sector - read_sector_to(*sector); + switch(cur_irq) { + case CD_IO::Interrupt::DataReady: { + // Obtain sector content here + auto* sector = sector_allocator.allocate_sector(); + if(sector) { + //Now obtain sector + read_sector_to(*sector); - cur_lba++; - if(cur_lba == dst_lba) { - current_state = State::Done; + cur_lba++; + if(cur_lba == dst_lba) { + current_state = State::Done; + pause_cd(); + } + } + + else { + current_state = State::BufferFull; pause_cd(); } - } + } break; - else { - current_state = State::BufferFull; - pause_cd(); - } - } + case CD_IO::Interrupt::DataEnd: { + CD_IO::PortIndex0::change_to(); + Command::send(CD_IO::Command::SetLoc, static_cast(0x0), static_cast(0x09), static_cast(0x0)); - else if(cur_irq == CD_IO::Interrupt::DiskError) { - current_state = State::Error; + CD_IO::PortIndex1::change_to(); + while(CD_IO::Interrupt::get_type(CD_IO::PortIndex1::InterruptFlag) != CD_IO::Interrupt::Acknowledge); + CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag); + + CD_IO::PortIndex0::change_to(); + Command::send(CD_IO::Command::Play); + } break; + + case CD_IO::Interrupt::DiskError: { + current_state = State::Error; + } break; } // No masking required because we can only write bit 0 - 2 @@ -141,7 +154,7 @@ namespace JabyEngine { void enable_CDDA() { Command::wait_completed(); CD_IO::PortIndex0::change_to(); - Command::send_wait(CD_IO::Command::SetMode, AudioSectorMode); + Command::send_wait(CD_IO::Command::SetMode, AudioSectorMode); } } } diff --git a/src/Library/src/GPU/gpu.cpp b/src/Library/src/GPU/gpu.cpp index bd692544..e84edb7e 100644 --- a/src/Library/src/GPU/gpu.cpp +++ b/src/Library/src/GPU/gpu.cpp @@ -1,4 +1,5 @@ #include "../../internal-include/GPU/gpu_internal.hpp" +#include "../../internal-include/System/callbacks_internal.hpp" #include #include #include @@ -40,8 +41,7 @@ namespace JabyEngine { MasterTime::value++; Interrupt::ack_irq(Interrupt::VBlank); - SysCall::ReturnFromException(); - __builtin_unreachable(); + Callback::internal::VSync::execute(); } uint32_t Display :: exchange_buffer_and_display() { diff --git a/src/Library/src/System/callbacks.cpp b/src/Library/src/System/callbacks.cpp new file mode 100644 index 00000000..d71da9b5 --- /dev/null +++ b/src/Library/src/System/callbacks.cpp @@ -0,0 +1,26 @@ +#include "../../internal-include/System/callbacks_internal.hpp" +#include + +#include + +namespace JabyEngine { + namespace Callback { + VSyncCallback::Function VSyncCallback :: callback = nullptr; + + namespace internal { + namespace VSync { + SysCall::ThreadHandle thread_handle = 0; + uint32_t stack[StackSize] = {0}; + + void routine() { + while(true) { + if(VSyncCallback::callback) { + VSyncCallback::callback(); + } + MainThread::restore(); + } + } + } + } + } +} \ No newline at end of file diff --git a/support/src/Makefile b/support/src/Makefile index c5efff53..923279d5 100644 --- a/support/src/Makefile +++ b/support/src/Makefile @@ -1,5 +1,5 @@ FontWriter: always - $(MAKE) -C $(JABY_ENGINE_DIR)/Support/src/FontWriter $(MAKECMDGOALS) + $(MAKE) -C $(JABY_ENGINE_DIR)/support/src/FontWriter $(MAKECMDGOALS) all: FontWriter diff --git a/template/JabyEngine-PSX_Game/#{ProjectName}.code-workspace b/template/JabyEngine-PSX_Game/#{ProjectName}.code-workspace index 866a6c77..4e1124dc 100644 --- a/template/JabyEngine-PSX_Game/#{ProjectName}.code-workspace +++ b/template/JabyEngine-PSX_Game/#{ProjectName}.code-workspace @@ -93,7 +93,7 @@ "settings": { "C_Cpp.default.includePath": [ "${env:JABY_ENGINE_PATH}/include", - "${env:JABY_ENGINE_PATH}/Support/include" + "${env:JABY_ENGINE_PATH}/support/include" ], "C_Cpp.default.compilerPath": "", "C_Cpp.default.cStandard": "c17", diff --git a/template/JabyEngine-PSX_Game/application/Makefile b/template/JabyEngine-PSX_Game/application/Makefile index 6432cda9..2de33a7b 100644 --- a/template/JabyEngine-PSX_Game/application/Makefile +++ b/template/JabyEngine-PSX_Game/application/Makefile @@ -4,7 +4,7 @@ include $(JABY_ENGINE_DIR)/mkfile/common/Wildcard.mk SRCS = $(call rwildcard, src, c cpp) INCLUDES += -I$(JABY_ENGINE_DIR)/include -#INCLUDES += -I$(JABY_ENGINE_DIR)/Support/include +#INCLUDES += -I$(JABY_ENGINE_DIR)/support/include #Example for using Support libs #SUPPORT_LIBS += FontWriter