Fix inconsistent EOL

This commit is contained in:
2025-01-08 22:27:37 +01:00
parent 57671ac79d
commit 1f7141c517
184 changed files with 13686 additions and 13685 deletions

View File

@@ -1,103 +1,103 @@
{
"folders": [
{
"name": "JabyEngine",
"path": ".",
},
{
"name": "Include",
"path": "..\\..\\include"
},
{
"name": "Root",
"path": "..\\.."
}
],
"tasks": {
"version": "2.0.0",
"tasks": [
{
"label": "make",
"type": "shell",
"command": "../../scripts/podman_jaby_engine.sh ../../:src/Library make ${input:target} BUILD_PROFILE=${input:build cfg} PSX_TV_FORMAT=${input:tv format} CUSTOM_CONFIG=${input:config options}",
"group": "build"
},
{
"label": "make_all",
"type": "shell",
"command": "../../scripts/podman_jaby_engine.sh ../../:src/Library make -f MakeAll.mk ${input:target prefix}_${input:target} BUILD_PROFILE=${input:build cfg} CUSTOM_CONFIG=${input:config options}",
"group": "build"
}
],
"inputs": [
{
"id": "build cfg",
"type": "pickString",
"options": ["debug", "release"],
"default": "release",
"description": "build configuration"
},
{
"id": "tv format",
"type": "pickString",
"options": ["PAL", "NTSC"],
"default": "PAL",
"description": "TV format to use"
},
{
"id": "config options",
"type": "command",
"command": "shellCommand.execute",
"args": {
"command": "echo \"|<Default>\" && ls -d */",
"cwd": "${workspaceFolder}/../../config",
"fieldSeparator": "|"
}
},
{
"id": "target prefix",
"type": "pickString",
"options": ["jabyengine", "all_jabyengine"],
"default": "jabyengine",
"description": "To build JabyEngine or JabyEngine with all configs"
},
{
"id": "target",
"type": "pickString",
"options": ["all", "clean", "rebuild"],
"default": "all",
"description": "build target",
}
]
},
"extensions": {
"recommendations": ["augustocdias.tasks-shell-input", "cantonios.project-templates"]
},
"settings": {
"cmake.configureOnOpen": false,
"C_Cpp.default.includePath": [
"include",
"../../include"
],
"C_Cpp.default.compilerPath": "",
"C_Cpp.default.cStandard": "c17",
"C_Cpp.default.cppStandard": "c++20",
"C_Cpp.default.intelliSenseMode": "linux-gcc-x86",
"C_Cpp.default.compilerArgs": [
],
"C_Cpp.default.defines": [
"JABYENGINE_PAL",
"__DEBUG_SPU_MMU__",
"__friends=public"
],
"files.exclude": {
"**/*.o": true,
"**/*.dep": true
},
"files.associations": {
"stdio.h": "c",
"TUTO0.C": "cpp",
"MAIN.C": "cpp"
}
}
{
"folders": [
{
"name": "JabyEngine",
"path": ".",
},
{
"name": "Include",
"path": "..\\..\\include"
},
{
"name": "Root",
"path": "..\\.."
}
],
"tasks": {
"version": "2.0.0",
"tasks": [
{
"label": "make",
"type": "shell",
"command": "../../scripts/podman_jaby_engine.sh ../../:src/Library make ${input:target} BUILD_PROFILE=${input:build cfg} PSX_TV_FORMAT=${input:tv format} CUSTOM_CONFIG=${input:config options}",
"group": "build"
},
{
"label": "make_all",
"type": "shell",
"command": "../../scripts/podman_jaby_engine.sh ../../:src/Library make -f MakeAll.mk ${input:target prefix}_${input:target} BUILD_PROFILE=${input:build cfg} CUSTOM_CONFIG=${input:config options}",
"group": "build"
}
],
"inputs": [
{
"id": "build cfg",
"type": "pickString",
"options": ["debug", "release"],
"default": "release",
"description": "build configuration"
},
{
"id": "tv format",
"type": "pickString",
"options": ["PAL", "NTSC"],
"default": "PAL",
"description": "TV format to use"
},
{
"id": "config options",
"type": "command",
"command": "shellCommand.execute",
"args": {
"command": "echo \"|<Default>\" && ls -d */",
"cwd": "${workspaceFolder}/../../config",
"fieldSeparator": "|"
}
},
{
"id": "target prefix",
"type": "pickString",
"options": ["jabyengine", "all_jabyengine"],
"default": "jabyengine",
"description": "To build JabyEngine or JabyEngine with all configs"
},
{
"id": "target",
"type": "pickString",
"options": ["all", "clean", "rebuild"],
"default": "all",
"description": "build target",
}
]
},
"extensions": {
"recommendations": ["augustocdias.tasks-shell-input", "cantonios.project-templates"]
},
"settings": {
"cmake.configureOnOpen": false,
"C_Cpp.default.includePath": [
"include",
"../../include"
],
"C_Cpp.default.compilerPath": "",
"C_Cpp.default.cStandard": "c17",
"C_Cpp.default.cppStandard": "c++20",
"C_Cpp.default.intelliSenseMode": "linux-gcc-x86",
"C_Cpp.default.compilerArgs": [
],
"C_Cpp.default.defines": [
"JABYENGINE_PAL",
"__DEBUG_SPU_MMU__",
"__friends=public"
],
"files.exclude": {
"**/*.o": true,
"**/*.dep": true
},
"files.associations": {
"stdio.h": "c",
"TUTO0.C": "cpp",
"MAIN.C": "cpp"
}
}
}

View File

@@ -1,26 +1,26 @@
define make_one
$(MAKE) $1 PSX_TV_FORMAT=PAL CUSTOM_CONFIG=$2
$(MAKE) $1 PSX_TV_FORMAT=NTSC CUSTOM_CONFIG=$2
endef
define make_all
$(call make_one,$1,)
$(foreach config,$2,$(call make_one,$1,$(config)))
endef
config_files = $(shell cd ../../config && ls -d */)
jabyengine_%:
$(call make_one,$*,$(CUSTOM_CONFIG))
all_jabyengine_%:
$(call make_all,$*,$(config_files))
all:
$(call make_all,all,$(config_files))
clean:
$(call make_all,clean,$(config_files))
rebuild:
define make_one
$(MAKE) $1 PSX_TV_FORMAT=PAL CUSTOM_CONFIG=$2
$(MAKE) $1 PSX_TV_FORMAT=NTSC CUSTOM_CONFIG=$2
endef
define make_all
$(call make_one,$1,)
$(foreach config,$2,$(call make_one,$1,$(config)))
endef
config_files = $(shell cd ../../config && ls -d */)
jabyengine_%:
$(call make_one,$*,$(CUSTOM_CONFIG))
all_jabyengine_%:
$(call make_all,$*,$(config_files))
all:
$(call make_all,all,$(config_files))
clean:
$(call make_all,clean,$(config_files))
rebuild:
$(call make_all,rebuild,$(config_files))

View File

@@ -1,51 +1,51 @@
include ../../mkfile/common/RebuildTarget.mk
JABY_ENGINE_DIR = ../../
ARTIFACT = libJabyEngine_$(PSX_TV_FORMAT)
SPLASH_IMAGE = src/BootLoader/splash_image_pal_boot.hpp
SPLASH_IMAGE_NTSC = src/BootLoader/splash_image_ntsc_boot.hpp
CCFLAGS += -I../../include -D__friends=public
CCFLAGS += -save-temps=obj
include ../../mkfile/common/CustomConfigHelper.mk
CONFIG_NAME = $(PLATFORM)-$(BUILD_PROFILE)/$(CUSTOM_CONFIG)
include ../../mkfile/common/Wildcard.mk
SRCS = $(call rwildcard, src, c cpp s)
include ../../mkfile/Makefile
LIB_DIR = ../../lib/$(CONFIG_NAME)
MAIN_LIB_OBJS = $(filter-out $(MAIN_BOOT_OBJ) $(OVERLAY_BOOT_OBJ),$(OBJS))
#$(info $$var is [${MAIN_BOOT_OBJ}])
#$(info $$var2 is [${MAIN_LIB_OBJS}])
#Linking rule
$(TARGET).a: $(MAIN_LIB_OBJS) $(SPLASH_IMAGE)
@mkdir -p $(dir $@)
$(AR) rcs $(TARGET).a $(MAIN_LIB_OBJS)
#Copy rules
$(LIB_DIR)/$(ARTIFACT).a: $(TARGET).a
@mkdir -p $(LIB_DIR)
cp $(TARGET).a $(LIB_DIR)/$(ARTIFACT).a
# rule to make the boot image
$(SPLASH_IMAGE): ressources/Splash.png
psxfileconv --lz4 $< simple-tim full16 | cpp_out --name SplashScreen -o $@
$(SPLASH_IMAGE_NTSC): ressources/Splash_ntsc.png
psxfileconv --lz4 $< simple-tim full16 | cpp_out --name SplashScreen -o $@
#Rules section for default compilation and linking
all: $(SPLASH_IMAGE) $(SPLASH_IMAGE_NTSC) $(LIB_DIR)/$(ARTIFACT).a
clean:
rm -fr $(SPLASH_IMAGE)
rm -fr $(SPLASH_IMAGE_NTSC)
rm -fr $(OUTPUT_DIR)
rm -fr gcm.cache
include ../../mkfile/common/RebuildTarget.mk
JABY_ENGINE_DIR = ../../
ARTIFACT = libJabyEngine_$(PSX_TV_FORMAT)
SPLASH_IMAGE = src/BootLoader/splash_image_pal_boot.hpp
SPLASH_IMAGE_NTSC = src/BootLoader/splash_image_ntsc_boot.hpp
CCFLAGS += -I../../include -D__friends=public
CCFLAGS += -save-temps=obj
include ../../mkfile/common/CustomConfigHelper.mk
CONFIG_NAME = $(PLATFORM)-$(BUILD_PROFILE)/$(CUSTOM_CONFIG)
include ../../mkfile/common/Wildcard.mk
SRCS = $(call rwildcard, src, c cpp s)
include ../../mkfile/Makefile
LIB_DIR = ../../lib/$(CONFIG_NAME)
MAIN_LIB_OBJS = $(filter-out $(MAIN_BOOT_OBJ) $(OVERLAY_BOOT_OBJ),$(OBJS))
#$(info $$var is [${MAIN_BOOT_OBJ}])
#$(info $$var2 is [${MAIN_LIB_OBJS}])
#Linking rule
$(TARGET).a: $(MAIN_LIB_OBJS) $(SPLASH_IMAGE)
@mkdir -p $(dir $@)
$(AR) rcs $(TARGET).a $(MAIN_LIB_OBJS)
#Copy rules
$(LIB_DIR)/$(ARTIFACT).a: $(TARGET).a
@mkdir -p $(LIB_DIR)
cp $(TARGET).a $(LIB_DIR)/$(ARTIFACT).a
# rule to make the boot image
$(SPLASH_IMAGE): ressources/Splash.png
psxfileconv --lz4 $< simple-tim full16 | cpp_out --name SplashScreen -o $@
$(SPLASH_IMAGE_NTSC): ressources/Splash_ntsc.png
psxfileconv --lz4 $< simple-tim full16 | cpp_out --name SplashScreen -o $@
#Rules section for default compilation and linking
all: $(SPLASH_IMAGE) $(SPLASH_IMAGE_NTSC) $(LIB_DIR)/$(ARTIFACT).a
clean:
rm -fr $(SPLASH_IMAGE)
rm -fr $(SPLASH_IMAGE_NTSC)
rm -fr $(OUTPUT_DIR)
rm -fr gcm.cache
rm -fr $(LIB_DIR)/$(ARTIFACT).a

View File

@@ -1,44 +1,44 @@
#pragma once
#include <PSX/System/IOPorts/dma_io.hpp>
#include <PSX/SPU/spu.hpp>
namespace JabyEngine {
namespace SPU {
namespace internal {
struct DMA {
static void wait() {
DMA_IO::SPU.wait();
while(SPU_IO::StatusRegister.read().is_set(SPU_IO_Values::StatusRegister::TransferBusy));
}
static void end() {
SPU_IO::ControlRegister.set_transfer_mode(SPU_IO_Values::ControlRegister::Stop);
}
struct Receive {
static void prepare() {
end();
SPU_IO::DataTransferControl.write(SPU_IO_Values::DataTransferControl::NormalTransferMode());
SPU_IO::ControlRegister.set_transfer_mode(SPU_IO_Values::ControlRegister::Stop);
}
static void set_src(uintptr_t adr) {
DMA_IO::SPU.set_adr(adr);
}
static void set_dst(SPU::SRAMAdr adr) {
SPU_IO::SRAMTransferAdr.write(adr);
SPU_IO::ControlRegister.set_transfer_mode(SPU_IO_Values::ControlRegister::DMAWrite);
}
static void start(uint16_t blockCount, uint16_t wordsPerBlock = 0x10) {
using SyncMode1 = DMA_IO_Values::BCR::SyncMode1;
DMA_IO::SPU.block_ctrl.write(DMA_IO_Values::BCR::from(SyncMode1::BlockSize.with(wordsPerBlock), SyncMode1::BlockAmount.with(blockCount)));
DMA_IO::SPU.channel_ctrl.write(DMA_IO_Values::CHCHR::StartSPUReceive());
}
};
};
}
}
}
#pragma once
#include <PSX/System/IOPorts/dma_io.hpp>
#include <PSX/SPU/spu.hpp>
namespace JabyEngine {
namespace SPU {
namespace internal {
struct DMA {
static void wait() {
DMA_IO::SPU.wait();
while(SPU_IO::StatusRegister.read().is_set(SPU_IO_Values::StatusRegister::TransferBusy));
}
static void end() {
SPU_IO::ControlRegister.set_transfer_mode(SPU_IO_Values::ControlRegister::Stop);
}
struct Receive {
static void prepare() {
end();
SPU_IO::DataTransferControl.write(SPU_IO_Values::DataTransferControl::NormalTransferMode());
SPU_IO::ControlRegister.set_transfer_mode(SPU_IO_Values::ControlRegister::Stop);
}
static void set_src(uintptr_t adr) {
DMA_IO::SPU.set_adr(adr);
}
static void set_dst(SPU::SRAMAdr adr) {
SPU_IO::SRAMTransferAdr.write(adr);
SPU_IO::ControlRegister.set_transfer_mode(SPU_IO_Values::ControlRegister::DMAWrite);
}
static void start(uint16_t blockCount, uint16_t wordsPerBlock = 0x10) {
using SyncMode1 = DMA_IO_Values::BCR::SyncMode1;
DMA_IO::SPU.block_ctrl.write(DMA_IO_Values::BCR::from(SyncMode1::BlockSize.with(wordsPerBlock), SyncMode1::BlockAmount.with(blockCount)));
DMA_IO::SPU.channel_ctrl.write(DMA_IO_Values::CHCHR::StartSPUReceive());
}
};
};
}
}
}

View File

@@ -1,9 +1,9 @@
#pragma once
#include <PSX/jabyengine.hpp>
namespace JabyEngine {
namespace SPU_MMU {
const uint8_t* allocate(uint8_t voice, size_t size);
void deallocate(uint8_t voice);
}
#pragma once
#include <PSX/jabyengine.hpp>
namespace JabyEngine {
namespace SPU_MMU {
const uint8_t* allocate(uint8_t voice, size_t size);
void deallocate(uint8_t voice);
}
}

View File

@@ -1,51 +1,51 @@
#pragma once
#include "threads.hpp"
#include <stdio.hpp>
namespace JabyEngine {
namespace Callback {
namespace internal {
static void execute_callback(Thread::Handle thread_handle, uint32_t parm) {
if(CurrentThread::is_me(MainThread::Handle)) {
CurrentThread::replace_with(thread_handle);
CurrentThread::force_a0(parm);
}
SysCall::ReturnFromException();
}
static uint32_t resume_callback(Thread::Handle handle) {
SysCall::ChangeThread(handle);
asm("sw $a0, %0" : "=m"(handle));
return handle;
}
namespace VSync {
static constexpr size_t StackSize = 64;
extern SysCall::ThreadHandle thread_handle;
extern uint32_t stack[StackSize];
void routine();
static void [[deprecated("Currently not in use")]] execute() {
execute_callback(VSync::thread_handle, 0);
}
}
namespace CD {
static constexpr size_t StackSize = 256;
extern Thread::Handle thread_handle;
extern uint32_t stack[StackSize];
void routine(uint32_t irq);
static void execute(uint32_t irq) {
execute_callback(CD::thread_handle, irq);
}
static uint32_t resume() {
return resume_callback(MainThread::Handle);
}
}
}
}
}
#pragma once
#include "threads.hpp"
#include <stdio.hpp>
namespace JabyEngine {
namespace Callback {
namespace internal {
static void execute_callback(Thread::Handle thread_handle, uint32_t parm) {
if(CurrentThread::is_me(MainThread::Handle)) {
CurrentThread::replace_with(thread_handle);
CurrentThread::force_a0(parm);
}
SysCall::ReturnFromException();
}
static uint32_t resume_callback(Thread::Handle handle) {
SysCall::ChangeThread(handle);
asm("sw $a0, %0" : "=m"(handle));
return handle;
}
namespace VSync {
static constexpr size_t StackSize = 64;
extern SysCall::ThreadHandle thread_handle;
extern uint32_t stack[StackSize];
void routine();
static void [[deprecated("Currently not in use")]] execute() {
execute_callback(VSync::thread_handle, 0);
}
}
namespace CD {
static constexpr size_t StackSize = 256;
extern Thread::Handle thread_handle;
extern uint32_t stack[StackSize];
void routine(uint32_t irq);
static void execute(uint32_t irq) {
execute_callback(CD::thread_handle, irq);
}
static uint32_t resume() {
return resume_callback(MainThread::Handle);
}
}
}
}
}

View File

@@ -1,55 +1,55 @@
#pragma once
#include <PSX/System/syscalls.hpp>
namespace JabyEngine {
struct Thread {
using Handle = SysCall::ThreadHandle;
static constexpr uint32_t idx_from_handle(SysCall::ThreadHandle thread) {
return thread & 0xFFFF;
}
static uintptr_t get_pic_of(Handle handle) {
return table_of_tables.threads[idx_from_handle(handle)].epc;
}
template<size_t N>
static Handle create(void(*function)(uint32_t), uint32_t(&stack)[N]) {
return SysCall::OpenThread(reinterpret_cast<void(*)()>(function), &stack[N - 1], SysCall::get_gp());
}
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 CurrentThread {
static uintptr_t get_pic() {
return table_of_tables.processes->current_tcb->epc;
}
static void force_a0(uint32_t a0) {
table_of_tables.processes->current_tcb->reg[4] = a0;
}
static bool is_me(Thread::Handle handle) {
return table_of_tables.processes->current_tcb == &table_of_tables.threads[Thread::idx_from_handle(handle)];
}
static void replace_with(Thread::Handle handle) {
table_of_tables.processes->current_tcb = &table_of_tables.threads[Thread::idx_from_handle(handle)];
}
};
struct MainThread {
static constexpr const Thread::Handle Handle = 0xFF000000;
static uintptr_t get_pic() {
return table_of_tables.threads[0].epc;
}
};
#pragma once
#include <PSX/System/syscalls.hpp>
namespace JabyEngine {
struct Thread {
using Handle = SysCall::ThreadHandle;
static constexpr uint32_t idx_from_handle(SysCall::ThreadHandle thread) {
return thread & 0xFFFF;
}
static uintptr_t get_pic_of(Handle handle) {
return table_of_tables.threads[idx_from_handle(handle)].epc;
}
template<size_t N>
static Handle create(void(*function)(uint32_t), uint32_t(&stack)[N]) {
return SysCall::OpenThread(reinterpret_cast<void(*)()>(function), &stack[N - 1], SysCall::get_gp());
}
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 CurrentThread {
static uintptr_t get_pic() {
return table_of_tables.processes->current_tcb->epc;
}
static void force_a0(uint32_t a0) {
table_of_tables.processes->current_tcb->reg[4] = a0;
}
static bool is_me(Thread::Handle handle) {
return table_of_tables.processes->current_tcb == &table_of_tables.threads[Thread::idx_from_handle(handle)];
}
static void replace_with(Thread::Handle handle) {
table_of_tables.processes->current_tcb = &table_of_tables.threads[Thread::idx_from_handle(handle)];
}
};
struct MainThread {
static constexpr const Thread::Handle Handle = 0xFF000000;
static uintptr_t get_pic() {
return table_of_tables.threads[0].epc;
}
};
}

View File

@@ -1,38 +1,38 @@
#pragma once
#include <PSX/Auxiliary/bits.hpp>
namespace JabyEngine {
namespace MIPS {
struct SR {
static constexpr auto IEc = Bit(0); // Current Interrupt Enable (0=Disable, 1=Enable)
static constexpr auto KUc = Bit(1); // Current Kernel/User Mode (0=Kernel, 1=User)
static constexpr auto IEp = Bit(2); // Previous Interrupt Disable
static constexpr auto KUp = Bit(3); // Previous Kernal/User Mode
static constexpr auto IEo = Bit(4); // Old Interrupt Disable
static constexpr auto KUo = Bit(5); // Old Kernal/User Mode
static constexpr auto Im = BitRange::from_to(8, 15); // 8 bit interrupt mask fields. When set the corresponding interrupts are allowed to cause an exception.
static constexpr auto Isc = Bit(16); // Isolate Cache (0=No, 1=Isolate) When isolated, all load and store operations are targetted to the Data cache, and never the main memory. (Used by PSX Kernel, in combination with Port FFFE0130h)
static constexpr auto Swc = Bit(17); // Swc Swapped cache mode (0=Normal, 1=Swapped) Instruction cache will act as Data cache and vice versa. Use only with Isc to access & invalidate Instr. cache entries. (Not used by PSX Kernel)
static constexpr auto PZ = Bit(18); // PZ When set cache parity bits are written as 0.
static constexpr auto CM = Bit(19); // CM Shows the result of the last load operation with the D-cache isolated. It gets set if the cache really contained data for the addressed memory location.
static constexpr auto PE = Bit(20); // Cache parity error (Does not cause exception)
static constexpr auto TS = Bit(21); // TLB shutdown. Gets set if a programm address simultaneously matches 2 TLB entries. (initial value on reset allows to detect extended CPU version?)
static constexpr auto BEV = Bit(22); // Boot exception vectors in RAM/ROM (0=RAM/KSEG0, 1=ROM/KSEG1)
static constexpr auto RE = Bit(25); // Reverse endianness (0=Normal endianness, 1=Reverse endianness) Reverses the byte order in which data is stored in memory. (lo-hi -> hi-lo) (Has affect only to User mode, not to Kernal mode) (?) (The bit doesn't exist in PSX ?)
static constexpr auto CU0 = Bit(28); // COP0 Enable (0=Enable only in Kernal Mode, 1=Kernal and User Mode)
static constexpr auto CU1 = Bit(29); // COP1 Enable (0=Disable, 1=Enable) (none such in PSX)
static constexpr auto CU2 = Bit(30); // COP2 Enable (0=Disable, 1=Enable) (GTE in PSX)
static constexpr auto CU3 = Bit(31); // COP3 Enable (0=Disable, 1=Enable) (none such in PSX)
static uint32_t read() {
uint32_t sr;
__asm__("mfc0 %0, $12" : "=rm"(sr));
return sr;
}
static void write(uint32_t sr) {
__asm__("mtc0 %0, $12" :: "rm"(sr));
}
};
}
#pragma once
#include <PSX/Auxiliary/bits.hpp>
namespace JabyEngine {
namespace MIPS {
struct SR {
static constexpr auto IEc = Bit(0); // Current Interrupt Enable (0=Disable, 1=Enable)
static constexpr auto KUc = Bit(1); // Current Kernel/User Mode (0=Kernel, 1=User)
static constexpr auto IEp = Bit(2); // Previous Interrupt Disable
static constexpr auto KUp = Bit(3); // Previous Kernal/User Mode
static constexpr auto IEo = Bit(4); // Old Interrupt Disable
static constexpr auto KUo = Bit(5); // Old Kernal/User Mode
static constexpr auto Im = BitRange::from_to(8, 15); // 8 bit interrupt mask fields. When set the corresponding interrupts are allowed to cause an exception.
static constexpr auto Isc = Bit(16); // Isolate Cache (0=No, 1=Isolate) When isolated, all load and store operations are targetted to the Data cache, and never the main memory. (Used by PSX Kernel, in combination with Port FFFE0130h)
static constexpr auto Swc = Bit(17); // Swc Swapped cache mode (0=Normal, 1=Swapped) Instruction cache will act as Data cache and vice versa. Use only with Isc to access & invalidate Instr. cache entries. (Not used by PSX Kernel)
static constexpr auto PZ = Bit(18); // PZ When set cache parity bits are written as 0.
static constexpr auto CM = Bit(19); // CM Shows the result of the last load operation with the D-cache isolated. It gets set if the cache really contained data for the addressed memory location.
static constexpr auto PE = Bit(20); // Cache parity error (Does not cause exception)
static constexpr auto TS = Bit(21); // TLB shutdown. Gets set if a programm address simultaneously matches 2 TLB entries. (initial value on reset allows to detect extended CPU version?)
static constexpr auto BEV = Bit(22); // Boot exception vectors in RAM/ROM (0=RAM/KSEG0, 1=ROM/KSEG1)
static constexpr auto RE = Bit(25); // Reverse endianness (0=Normal endianness, 1=Reverse endianness) Reverses the byte order in which data is stored in memory. (lo-hi -> hi-lo) (Has affect only to User mode, not to Kernal mode) (?) (The bit doesn't exist in PSX ?)
static constexpr auto CU0 = Bit(28); // COP0 Enable (0=Enable only in Kernal Mode, 1=Kernal and User Mode)
static constexpr auto CU1 = Bit(29); // COP1 Enable (0=Disable, 1=Enable) (none such in PSX)
static constexpr auto CU2 = Bit(30); // COP2 Enable (0=Disable, 1=Enable) (GTE in PSX)
static constexpr auto CU3 = Bit(31); // COP3 Enable (0=Disable, 1=Enable) (none such in PSX)
static uint32_t read() {
uint32_t sr;
__asm__("mfc0 %0, $12" : "=rm"(sr));
return sr;
}
static void write(uint32_t sr) {
__asm__("mtc0 %0, $12" :: "rm"(sr));
}
};
}
}

View File

@@ -1,39 +1,39 @@
#pragma once
#include <PSX/System/IOPorts/interrupt_io.hpp>
#include <PSX/System/IOPorts/periphery_io.hpp>
#include <PSX/Periphery/periphery.hpp>
#include <stdio.hpp>
extern "C" void busy_loop(int count);
namespace JabyEngine {
namespace Periphery {
using namespace Periphery_IO;
static void connect_to(uint16_t port) {
JOY_CTRL.write(Periphery_IO_Values::JOY_CTRL::create_for(port));
busy_loop(500);
}
static void close_connection() {
JOY_CTRL.write(Periphery_IO_Values::JOY_CTRL::close());
}
static void send_byte(uint8_t byte) {
while(!JOY_STAT.is_ready_transfer());
JOY_TX_DATA.write(Periphery_IO_Values::JOY_TX_DATA::create(byte));
}
static uint8_t read_byte() {
while(!JOY_STAT.has_response());
return JOY_RX_DATA.read().raw;
}
static void acknowledge() {
while(JOY_STAT.read().is_set(Periphery_IO_Values::JOY_STAT::ACKIrqLow));
JOY_CTRL.write(JOY_CTRL.read().set(Periphery_IO_Values::JOY_CTRL::ACK));
Interrupt::ack_irq(Interrupt::Periphery);
}
}
#pragma once
#include <PSX/System/IOPorts/interrupt_io.hpp>
#include <PSX/System/IOPorts/periphery_io.hpp>
#include <PSX/Periphery/periphery.hpp>
#include <stdio.hpp>
extern "C" void busy_loop(int count);
namespace JabyEngine {
namespace Periphery {
using namespace Periphery_IO;
static void connect_to(uint16_t port) {
JOY_CTRL.write(Periphery_IO_Values::JOY_CTRL::create_for(port));
busy_loop(500);
}
static void close_connection() {
JOY_CTRL.write(Periphery_IO_Values::JOY_CTRL::close());
}
static void send_byte(uint8_t byte) {
while(!JOY_STAT.is_ready_transfer());
JOY_TX_DATA.write(Periphery_IO_Values::JOY_TX_DATA::create(byte));
}
static uint8_t read_byte() {
while(!JOY_STAT.has_response());
return JOY_RX_DATA.read().raw;
}
static void acknowledge() {
while(JOY_STAT.read().is_set(Periphery_IO_Values::JOY_STAT::ACKIrqLow));
JOY_CTRL.write(JOY_CTRL.read().set(Periphery_IO_Values::JOY_CTRL::ACK));
Interrupt::ack_irq(Interrupt::Periphery);
}
}
}

View File

@@ -1,8 +1,8 @@
# inline_n.h
This header is directly lifted from psx-redux and not my creation. I will try to give it my personal touch but the original implementation will be always from [pcsx-redux](https://github.com/grumpycoders/pcsx-redux) and the **grumpycoders**.
# GTEMAC.H
Great for reference! It is under `psyq\include\GTEMAC.H`
# LIBGTE.H
# inline_n.h
This header is directly lifted from psx-redux and not my creation. I will try to give it my personal touch but the original implementation will be always from [pcsx-redux](https://github.com/grumpycoders/pcsx-redux) and the **grumpycoders**.
# GTEMAC.H
Great for reference! It is under `psyq\include\GTEMAC.H`
# LIBGTE.H
Not so helpful but can be found under `psyq\include\LIBGTE.H`

File diff suppressed because it is too large Load Diff

View File

@@ -1,54 +1,54 @@
#include "../../internal-include/CD/cd_internal.hpp"
#include <PSX/Audio/CDDA.hpp>
namespace JabyEngine {
namespace CDDA {
namespace CD = JabyEngine::CD::internal;
static CD::BCDTimeStamp last_track;
CD::BCDTimeStamp playing_track;
TrackList get_tracks() {
CD::Command::send_wait_response(CD_IO::Command::GetTN);
const auto stat = CD_IO::PortIndex0::ResponseFifo.read();
const auto first = CD_IO::PortIndex0::ResponseFifo.read().raw;
const auto end = CD_IO::PortIndex0::ResponseFifo.read().raw;
const auto last_track = (end - first) + 1;
if(last_track == 1) {
return TrackList::empty();
}
return TrackList{.first_track = 2, .last_track = static_cast<uint8_t>(last_track)};
}
void play(uint8_t track) {
CD::enable_CDDA();
CD::Command::send_wait_response(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::SetLoc, playing_track.min, playing_track.sec, 0x0_u8);
CD::Command::send(CD_IO::Command::Play);
// The PS3 does not support playing a track by track id
//CD::Command::send(CD_IO::Command::Play, track);
}
void stop() {
CD::pause();
}
void push_play() {
stop();
last_track = CD::get_loc();
}
void pop_play() {
CD::enable_CDDA();
CD::Command::send(CD_IO::Command::SetLoc, last_track.min, last_track.sec, last_track.sector);
CD::Command::send(CD_IO::Command::Play);
}
}
#include "../../internal-include/CD/cd_internal.hpp"
#include <PSX/Audio/CDDA.hpp>
namespace JabyEngine {
namespace CDDA {
namespace CD = JabyEngine::CD::internal;
static CD::BCDTimeStamp last_track;
CD::BCDTimeStamp playing_track;
TrackList get_tracks() {
CD::Command::send_wait_response(CD_IO::Command::GetTN);
const auto stat = CD_IO::PortIndex0::ResponseFifo.read();
const auto first = CD_IO::PortIndex0::ResponseFifo.read().raw;
const auto end = CD_IO::PortIndex0::ResponseFifo.read().raw;
const auto last_track = (end - first) + 1;
if(last_track == 1) {
return TrackList::empty();
}
return TrackList{.first_track = 2, .last_track = static_cast<uint8_t>(last_track)};
}
void play(uint8_t track) {
CD::enable_CDDA();
CD::Command::send_wait_response(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::SetLoc, playing_track.min, playing_track.sec, 0x0_u8);
CD::Command::send(CD_IO::Command::Play);
// The PS3 does not support playing a track by track id
//CD::Command::send(CD_IO::Command::Play, track);
}
void stop() {
CD::pause();
}
void push_play() {
stop();
last_track = CD::get_loc();
}
void pop_play() {
CD::enable_CDDA();
CD::Command::send(CD_IO::Command::SetLoc, last_track.min, last_track.sec, last_track.sector);
CD::Command::send(CD_IO::Command::Play);
}
}
}

View File

@@ -1,68 +1,68 @@
#include "../../internal-include/CD/cd_internal.hpp"
#include "../../internal-include/CD/cd_types.hpp"
#include <PSX/Audio/CDXA.hpp>
namespace JabyEngine {
namespace CDXA {
namespace CD = JabyEngine::CD::internal;
static struct {
CD::BCDTimeStamp start_loc;
CD::BCDTimeStamp last_loc;
bool double_speed;
uint8_t channel;
} setting;
CD::State interrupt_handler(uint8_t irq) {
switch(irq) {
case CD_IO::Interrupt::DataReady: {
// The IRQ stack is 0x1000 bytes large so this should fit
const auto xa_file = CD::copy_from_sector<CD::RawXADataSector>();
if(setting.channel == xa_file.sub_header.channel_number) {
CD::set_loc(setting.start_loc);
CD::Command::send_no_wait(CD_IO::Command::ReadS);
}
} break;
case CD_IO::Interrupt::DiskError:
return CD::State::Error;
};
return CD::State::XAMode;
}
void play(const volatile AutoLBAEntry* lba, uint8_t rel_lba_idx, uint8_t channel, bool double_speed) {
setting.start_loc = CD::BCDTimeStamp::from(lba[rel_lba_idx].get_lba());
setting.double_speed = double_speed;
CD::enable_CDXA(double_speed); //< Activates PortIndex0
set_channel(channel);
CD::Command::send(CD_IO::Command::SetLoc, setting.start_loc.min, setting.start_loc.sec, setting.start_loc.sector);
CD::Command::send(CD_IO::Command::ReadS);
}
void stop() {
CD::pause();
}
void set_channel(uint8_t channel) {
static constexpr uint8_t File = 1;
CD::Command::send(CD_IO::Command::Filter, File, channel);
setting.channel = channel;
}
void push_play() {
stop();
setting.last_loc = CD::get_loc();
CD::current_state = CD::State::Ready;
}
void pop_play() {
CD::enable_CDXA(setting.double_speed); //< Activates PortIndex0
set_channel(setting.channel);
CD::Command::send(CD_IO::Command::SetLoc, setting.last_loc.min, setting.last_loc.sec, setting.last_loc.sector);
CD::Command::send(CD_IO::Command::ReadS);
}
}
#include "../../internal-include/CD/cd_internal.hpp"
#include "../../internal-include/CD/cd_types.hpp"
#include <PSX/Audio/CDXA.hpp>
namespace JabyEngine {
namespace CDXA {
namespace CD = JabyEngine::CD::internal;
static struct {
CD::BCDTimeStamp start_loc;
CD::BCDTimeStamp last_loc;
bool double_speed;
uint8_t channel;
} setting;
CD::State interrupt_handler(uint8_t irq) {
switch(irq) {
case CD_IO::Interrupt::DataReady: {
// The IRQ stack is 0x1000 bytes large so this should fit
const auto xa_file = CD::copy_from_sector<CD::RawXADataSector>();
if(setting.channel == xa_file.sub_header.channel_number) {
CD::set_loc(setting.start_loc);
CD::Command::send_no_wait(CD_IO::Command::ReadS);
}
} break;
case CD_IO::Interrupt::DiskError:
return CD::State::Error;
};
return CD::State::XAMode;
}
void play(const volatile AutoLBAEntry* lba, uint8_t rel_lba_idx, uint8_t channel, bool double_speed) {
setting.start_loc = CD::BCDTimeStamp::from(lba[rel_lba_idx].get_lba());
setting.double_speed = double_speed;
CD::enable_CDXA(double_speed); //< Activates PortIndex0
set_channel(channel);
CD::Command::send(CD_IO::Command::SetLoc, setting.start_loc.min, setting.start_loc.sec, setting.start_loc.sector);
CD::Command::send(CD_IO::Command::ReadS);
}
void stop() {
CD::pause();
}
void set_channel(uint8_t channel) {
static constexpr uint8_t File = 1;
CD::Command::send(CD_IO::Command::Filter, File, channel);
setting.channel = channel;
}
void push_play() {
stop();
setting.last_loc = CD::get_loc();
CD::current_state = CD::State::Ready;
}
void pop_play() {
CD::enable_CDXA(setting.double_speed); //< Activates PortIndex0
set_channel(setting.channel);
CD::Command::send(CD_IO::Command::SetLoc, setting.last_loc.min, setting.last_loc.sec, setting.last_loc.sector);
CD::Command::send(CD_IO::Command::ReadS);
}
}
}

View File

@@ -1,73 +1,73 @@
#pragma once
#include "../../../internal-include/GPU/gpu_internal.hpp"
#include "bios_font_types.hpp"
#include <PSX/System/syscalls.hpp>
// | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | 0 |
// | 8149 | 8168 | 8194 | 8190 | 8193 | 8195 | 8166 | 8169 | 816A | 8196 | 817B | 8143 | 817C | 8144 | 815E | 8240 |
// | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? | @ |
// | 8251 | 8252 | 8253 | 8254 | 8255 | 8256 | 8257 | 8258 | 8259 | 8146 | 8147 | 8183 | 8181 | 8184 | 8148 | 8197 |
// | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P |
// | 8260 | 8261 | 8262 | 8263 | 8264 | 8265 | 8266 | 8267 | 8268 | 8269 | 826A | 826B | 826C | 826D | 826E | 826F |
// | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ | ` |
// | 8270 | 8271 | 8272 | 8273 | 8274 | 8275 | 8276 | 8277 | 8278 | 8279 | 816D | 815F | 816E | 814F | 8151 | 814D |
// | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p |
// | 8281 | 8282 | 8283 | 8284 | 8285 | 8286 | 8287 | 8288 | 8289 | 828A | 828B | 828C | 828D | 828E | 828F | 8290 |
// | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | | |
// | 8291 | 8292 | 8293 | 8294 | 8295 | 8296 | 8297 | 8298 | 8299 | 829A | 816F | 8162 | 8170 | 8160 | | |
namespace JabyEngine {
namespace GPU {
namespace SJIS {
// base: 0x8100
static const SpecialChar Specials[] = { // ToDo: Can we split this into 4 arrays? Would that help somehow?
// { ! } { " } { # } { $ } { % } { & } { ' } { ( } { ) } { * } { + } { , } { - } { . } { / }
{0x49, 0}, {0x68, 1}, {0x94, 2}, {0x90, 3}, {0x93, 4}, {0x95, 5}, {0x66, 6}, {0x69, 7}, {0x6A, 8}, {0x96, 9}, {0x7B, 10}, {0x43, 11}, {0x7C, 12}, {0x44, 13}, {0x5E, 14},
// { : } { ; } { < } { = } { > } { ? } { @ }
{0x46, 25}, {0x47, 26}, {0x83, 27}, {0x81, 28}, {0x84, 29}, {0x48, 30}, {0x97, 31},
// { [ } { \ } { ] } { ^ } { _ } { ` }
{0x6D, 58}, {0x5F, 59}, {0x6E, 60}, {0x4F, 61}, {0x51, 62}, {0x4D, 63},
// { { } { | } { } } { ~ }
{0x6F, 90}, {0x62, 91}, {0x70, 92}, {0x60, 93}
};
// base: 0x8200
static const RangeChar AlphaNumeric[] = {
// { 0 }
{{0x4F, 15}, 1},
// { 1 - 9 }
{{0x50, 16}, 9},
// { A - Z }
{{0x60, 32}, 26},
// { a - z }
{{0x81, 64}, 26}
};
static void load(const PositionU16& start_pos) {
FontBuffer font_buffer;
const auto load_special_chars = [&font_buffer]<size_t Size>(const PositionU16& pos, const SpecialChar(&special_chars)[Size]) {
for(const auto& special_char : special_chars) {
font_buffer.load_to(pos.add(FontBuffer::vram_offset(special_char.tile_id)), SysCall::Krom2RawAdd(0x8100 | special_char.base_offset));
}
};
const auto load_alpha_num = [&font_buffer]<size_t Size>(const PositionU16& pos, const RangeChar(&range_char)[Size]) {
for(const auto& range : range_char) {
const auto end_tile = range.start_char.tile_id + range.length;
auto sjis_code = 0x8200 | range.start_char.base_offset;
for(uint16_t tile_id = range.start_char.tile_id; tile_id < end_tile; tile_id++,sjis_code++) {
font_buffer.load_to(pos.add(FontBuffer::vram_offset(tile_id)), SysCall::Krom2RawAdd(sjis_code));
}
}
};
font_buffer.setup();
GPU::internal::DMA::Receive::prepare();
load_special_chars(start_pos, Specials);
load_alpha_num(start_pos, AlphaNumeric);
font_buffer.shutdown();
}
}
}
#pragma once
#include "../../../internal-include/GPU/gpu_internal.hpp"
#include "bios_font_types.hpp"
#include <PSX/System/syscalls.hpp>
// | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | 0 |
// | 8149 | 8168 | 8194 | 8190 | 8193 | 8195 | 8166 | 8169 | 816A | 8196 | 817B | 8143 | 817C | 8144 | 815E | 8240 |
// | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? | @ |
// | 8251 | 8252 | 8253 | 8254 | 8255 | 8256 | 8257 | 8258 | 8259 | 8146 | 8147 | 8183 | 8181 | 8184 | 8148 | 8197 |
// | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P |
// | 8260 | 8261 | 8262 | 8263 | 8264 | 8265 | 8266 | 8267 | 8268 | 8269 | 826A | 826B | 826C | 826D | 826E | 826F |
// | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ | ` |
// | 8270 | 8271 | 8272 | 8273 | 8274 | 8275 | 8276 | 8277 | 8278 | 8279 | 816D | 815F | 816E | 814F | 8151 | 814D |
// | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p |
// | 8281 | 8282 | 8283 | 8284 | 8285 | 8286 | 8287 | 8288 | 8289 | 828A | 828B | 828C | 828D | 828E | 828F | 8290 |
// | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | | |
// | 8291 | 8292 | 8293 | 8294 | 8295 | 8296 | 8297 | 8298 | 8299 | 829A | 816F | 8162 | 8170 | 8160 | | |
namespace JabyEngine {
namespace GPU {
namespace SJIS {
// base: 0x8100
static const SpecialChar Specials[] = { // ToDo: Can we split this into 4 arrays? Would that help somehow?
// { ! } { " } { # } { $ } { % } { & } { ' } { ( } { ) } { * } { + } { , } { - } { . } { / }
{0x49, 0}, {0x68, 1}, {0x94, 2}, {0x90, 3}, {0x93, 4}, {0x95, 5}, {0x66, 6}, {0x69, 7}, {0x6A, 8}, {0x96, 9}, {0x7B, 10}, {0x43, 11}, {0x7C, 12}, {0x44, 13}, {0x5E, 14},
// { : } { ; } { < } { = } { > } { ? } { @ }
{0x46, 25}, {0x47, 26}, {0x83, 27}, {0x81, 28}, {0x84, 29}, {0x48, 30}, {0x97, 31},
// { [ } { \ } { ] } { ^ } { _ } { ` }
{0x6D, 58}, {0x5F, 59}, {0x6E, 60}, {0x4F, 61}, {0x51, 62}, {0x4D, 63},
// { { } { | } { } } { ~ }
{0x6F, 90}, {0x62, 91}, {0x70, 92}, {0x60, 93}
};
// base: 0x8200
static const RangeChar AlphaNumeric[] = {
// { 0 }
{{0x4F, 15}, 1},
// { 1 - 9 }
{{0x50, 16}, 9},
// { A - Z }
{{0x60, 32}, 26},
// { a - z }
{{0x81, 64}, 26}
};
static void load(const PositionU16& start_pos) {
FontBuffer font_buffer;
const auto load_special_chars = [&font_buffer]<size_t Size>(const PositionU16& pos, const SpecialChar(&special_chars)[Size]) {
for(const auto& special_char : special_chars) {
font_buffer.load_to(pos.add(FontBuffer::vram_offset(special_char.tile_id)), SysCall::Krom2RawAdd(0x8100 | special_char.base_offset));
}
};
const auto load_alpha_num = [&font_buffer]<size_t Size>(const PositionU16& pos, const RangeChar(&range_char)[Size]) {
for(const auto& range : range_char) {
const auto end_tile = range.start_char.tile_id + range.length;
auto sjis_code = 0x8200 | range.start_char.base_offset;
for(uint16_t tile_id = range.start_char.tile_id; tile_id < end_tile; tile_id++,sjis_code++) {
font_buffer.load_to(pos.add(FontBuffer::vram_offset(tile_id)), SysCall::Krom2RawAdd(sjis_code));
}
}
};
font_buffer.setup();
GPU::internal::DMA::Receive::prepare();
load_special_chars(start_pos, Specials);
load_alpha_num(start_pos, AlphaNumeric);
font_buffer.shutdown();
}
}
}
}

View File

@@ -1,98 +1,98 @@
#pragma once
#include "../../../internal-include/GPU/gpu_internal.hpp"
#include <PSX/GPU/gpu_auto_load_font.hpp>
namespace JabyEngine {
namespace GPU {
namespace SJIS {
struct FontBuffer {
// A line of 16 Pixel
struct Line {
LookUpColor4 pixel[BIOS_Font::Size.width/4];
void load(uint16_t bit_pattern) {
static constexpr auto BitsPerRound = 4;
size_t px_idx = 0;
for(uint16_t shift = 1 << 15; shift; shift = shift >> BitsPerRound) {
uint8_t lu_ids[BitsPerRound];
for(size_t n = 0; n < BitsPerRound; n++) {
lu_ids[n] = (bit_pattern & (shift >> n)) ? 1 : 0;
}
this->pixel[px_idx++] = LookUpColor4::create(lu_ids);
}
}
static PositionU16 vram_offset(uint16_t tile_id) {
return tile_id_for16<PositionU16>(tile_id, SizeU16::create(4, 16));
}
};
// Letters are actually only 16x15 but should be treated 16x16
struct Letter {
PositionU16 position;
Line lines[BIOS_Font::Size.height - 1];
Line empty_line;
void setup() {
this->empty_line.load(0);
}
void load_to(const PositionU16& pos, const uint16_t* bit_map) {
this->position = pos;
for(auto& cur_line : this->lines) {
cur_line.load(__builtin_bswap16(*bit_map++));
}
}
};
// v double buffer do not change size without adjusting
Letter letter_buffer[2];
uint8_t free_idx;
void setup() {
for(auto& letter : this->letter_buffer) {
letter.setup();
}
this->free_idx = 0;
GPU::internal::DMA::Receive::prepare();
}
void shutdown() {
GPU::internal::DMA::wait();
GPU::internal::DMA::end();
}
void load_to(const PositionU16& pos, const uint16_t* bit_map) {
auto& cur_letter = this->letter_buffer[this->free_idx];
this->free_idx ^= 1;
cur_letter.load_to(pos, bit_map);
GPU::internal::DMA::wait();
GPU::internal::DMA::Receive::set_src(reinterpret_cast<uintptr_t>(cur_letter.lines));
// v 4 Pixel per byte
GPU::internal::DMA::Receive::set_dst(cur_letter.position, SizeU16::create(16/4, 16));
GPU::internal::DMA::Receive::start(sizeof(Line) >> 2);
}
static PositionU16 vram_offset(uint16_t tile_id) {
return Line::vram_offset(tile_id);
}
};
struct SpecialChar {
uint8_t base_offset;
uint8_t tile_id;
};
struct RangeChar {
SpecialChar start_char;
uint8_t length;
};
static_assert(BIOS_Font::Size == SizeU16::create(16, 16));
}
}
#pragma once
#include "../../../internal-include/GPU/gpu_internal.hpp"
#include <PSX/GPU/gpu_auto_load_font.hpp>
namespace JabyEngine {
namespace GPU {
namespace SJIS {
struct FontBuffer {
// A line of 16 Pixel
struct Line {
LookUpColor4 pixel[BIOS_Font::Size.width/4];
void load(uint16_t bit_pattern) {
static constexpr auto BitsPerRound = 4;
size_t px_idx = 0;
for(uint16_t shift = 1 << 15; shift; shift = shift >> BitsPerRound) {
uint8_t lu_ids[BitsPerRound];
for(size_t n = 0; n < BitsPerRound; n++) {
lu_ids[n] = (bit_pattern & (shift >> n)) ? 1 : 0;
}
this->pixel[px_idx++] = LookUpColor4::create(lu_ids);
}
}
static PositionU16 vram_offset(uint16_t tile_id) {
return tile_id_for16<PositionU16>(tile_id, SizeU16::create(4, 16));
}
};
// Letters are actually only 16x15 but should be treated 16x16
struct Letter {
PositionU16 position;
Line lines[BIOS_Font::Size.height - 1];
Line empty_line;
void setup() {
this->empty_line.load(0);
}
void load_to(const PositionU16& pos, const uint16_t* bit_map) {
this->position = pos;
for(auto& cur_line : this->lines) {
cur_line.load(__builtin_bswap16(*bit_map++));
}
}
};
// v double buffer do not change size without adjusting
Letter letter_buffer[2];
uint8_t free_idx;
void setup() {
for(auto& letter : this->letter_buffer) {
letter.setup();
}
this->free_idx = 0;
GPU::internal::DMA::Receive::prepare();
}
void shutdown() {
GPU::internal::DMA::wait();
GPU::internal::DMA::end();
}
void load_to(const PositionU16& pos, const uint16_t* bit_map) {
auto& cur_letter = this->letter_buffer[this->free_idx];
this->free_idx ^= 1;
cur_letter.load_to(pos, bit_map);
GPU::internal::DMA::wait();
GPU::internal::DMA::Receive::set_src(reinterpret_cast<uintptr_t>(cur_letter.lines));
// v 4 Pixel per byte
GPU::internal::DMA::Receive::set_dst(cur_letter.position, SizeU16::create(16/4, 16));
GPU::internal::DMA::Receive::start(sizeof(Line) >> 2);
}
static PositionU16 vram_offset(uint16_t tile_id) {
return Line::vram_offset(tile_id);
}
};
struct SpecialChar {
uint8_t base_offset;
uint8_t tile_id;
};
struct RangeChar {
SpecialChar start_char;
uint8_t length;
};
static_assert(BIOS_Font::Size == SizeU16::create(16, 16));
}
}
}

View File

@@ -1,25 +1,25 @@
#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() {
// We do not use threads anymore but keep the code for it
/*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);
InternalCallback::CD::thread_handle = Thread::create(InternalCallback::CD::routine, InternalCallback::CD::stack);
Thread::set_user_mode_for(InternalCallback::CD::thread_handle);
SysCall::ExitCriticalSection();*/
}
}
}
#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() {
// We do not use threads anymore but keep the code for it
/*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);
InternalCallback::CD::thread_handle = Thread::create(InternalCallback::CD::routine, InternalCallback::CD::stack);
Thread::set_user_mode_for(InternalCallback::CD::thread_handle);
SysCall::ExitCriticalSection();*/
}
}
}
}

View File

@@ -1,42 +1,42 @@
#include "../../internal-include/BootLoader/boot_loader.hpp"
#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.hpp>
namespace JabyEngine {
namespace CD {
namespace internal {
extern SysCall::InterruptCallback irq_callback;
}
}
namespace boot {
namespace CD {
using JabyEngine::CD::internal::Command;
void setup() {
static constexpr auto DebugX = 1;
static constexpr auto DebugY = 1;
static constexpr auto DebugScale = 1.0;
__debug_boot_color_at(::JabyEngine::GPU::Color24::White(), DebugX, DebugY, DebugScale);
SysCall::EnterCriticalSection();
Memory_IO::COM_DELAY.write(Memory_IO_Values::COM_DELAY::create());
Memory_IO::CD_DELAY.write(Memory_IO_Values::CD_DELAY::create());
SysCall::SysEnqIntRP(SysCall::Priority::CdromIoIrq, &::JabyEngine::CD::internal::irq_callback);
CD_IO::PortIndex1::change_to();
CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag);
// TODO: Verify this on real HW
CD_IO::Interrupt::enable_extended(CD_IO::PortIndex1::InterruptEnable);
Interrupt::enable_irq(Interrupt::CDROM);
Interrupt::ack_irq(Interrupt::CDROM);
SysCall::ExitCriticalSection();
}
}
}
#include "../../internal-include/BootLoader/boot_loader.hpp"
#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.hpp>
namespace JabyEngine {
namespace CD {
namespace internal {
extern SysCall::InterruptCallback irq_callback;
}
}
namespace boot {
namespace CD {
using JabyEngine::CD::internal::Command;
void setup() {
static constexpr auto DebugX = 1;
static constexpr auto DebugY = 1;
static constexpr auto DebugScale = 1.0;
__debug_boot_color_at(::JabyEngine::GPU::Color24::White(), DebugX, DebugY, DebugScale);
SysCall::EnterCriticalSection();
Memory_IO::COM_DELAY.write(Memory_IO_Values::COM_DELAY::create());
Memory_IO::CD_DELAY.write(Memory_IO_Values::CD_DELAY::create());
SysCall::SysEnqIntRP(SysCall::Priority::CdromIoIrq, &::JabyEngine::CD::internal::irq_callback);
CD_IO::PortIndex1::change_to();
CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag);
// TODO: Verify this on real HW
CD_IO::Interrupt::enable_extended(CD_IO::PortIndex1::InterruptEnable);
Interrupt::enable_irq(Interrupt::CDROM);
Interrupt::ack_irq(Interrupt::CDROM);
SysCall::ExitCriticalSection();
}
}
}
}

View File

@@ -1,25 +1,25 @@
#include <PSX/System/IOPorts/dma_io.hpp>
#include <PSX/System/syscalls.hpp>
#include <PSX/System/IOPorts/interrupt_io.hpp>
namespace JabyEngine {
namespace boot {
namespace DMA {
void setup() {
static constexpr auto EnableDMA = DMA_IO_Values::DPCR::from(
DMA_IO_Values::DPCR::SPU.turn_on(3), DMA_IO_Values::DPCR::GPU.turn_on(3), DMA_IO_Values::DPCR::CDROM.turn_on(3)
);
DMA_IO::DPCR.write(EnableDMA);
DMA_IO::DICR.write(DMA_IO_Values::DICR::empty());
// ACK IRQ
DMA_IO::DICR.write(DMA_IO::DICR.read());
SysCall::EnterCriticalSection();
Interrupt::disable_irq(Interrupt::DMA);
Interrupt::ack_irq(Interrupt::DMA);
SysCall::ExitCriticalSection();
}
}
}
#include <PSX/System/IOPorts/dma_io.hpp>
#include <PSX/System/syscalls.hpp>
#include <PSX/System/IOPorts/interrupt_io.hpp>
namespace JabyEngine {
namespace boot {
namespace DMA {
void setup() {
static constexpr auto EnableDMA = DMA_IO_Values::DPCR::from(
DMA_IO_Values::DPCR::SPU.turn_on(3), DMA_IO_Values::DPCR::GPU.turn_on(3), DMA_IO_Values::DPCR::CDROM.turn_on(3)
);
DMA_IO::DPCR.write(EnableDMA);
DMA_IO::DICR.write(DMA_IO_Values::DICR::empty());
// ACK IRQ
DMA_IO::DICR.write(DMA_IO::DICR.read());
SysCall::EnterCriticalSection();
Interrupt::disable_irq(Interrupt::DMA);
Interrupt::ack_irq(Interrupt::DMA);
SysCall::ExitCriticalSection();
}
}
}
}

View File

@@ -1,109 +1,109 @@
#include "../../internal-include/GPU/gpu_internal.hpp"
#include <PSX/System/IOPorts/interrupt_io.hpp>
#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.hpp>
#ifdef JABYENGINE_PAL
#include "splash_image_pal_boot.hpp"
#else
#include "splash_image_ntsc_boot.hpp"
#endif //JABYENGINE_PAL
// Concept for switchting BIOS Fonts...?
#include "BIOSFont/ascii_bios_font.hpp"
extern "C" uint32_t __boot_loader_end;
namespace JabyEngine {
namespace GPU {
namespace internal {
extern SysCall::InterruptCallback irq_callback;
}
namespace SJIS {
void load_clut(const PositionU16& dst_cord) {
struct CLUT {
CPU2VRAM cmd;
Color data[16];
};
const CLUT clut {
.cmd = CPU2VRAM::create(AreaU16::create(dst_cord, GPU::SizeU16::create(16, 1))),
.data = {
Color::Black(), Color::Grey(),
Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(),
Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(),
}
};
GPU::internal::render(reinterpret_cast<const uint32_t*>(&clut), sizeof(CLUT)/sizeof(uint32_t));
}
}
}
namespace boot {
namespace GPU {
using namespace JabyEngine::GPU;
static void configure_display() {
GPU_IO::GP1.set_display_mode(::JabyEngine::GPU::internal::Display::DisplayMode);
GPU::Display::set_offset(0, 0);
}
static size_t decompress_logo() {
LZ4Decompressor lz4_decomp(reinterpret_cast<uint8_t*>(&__boot_loader_end));
const auto [progress, bytes_ready] = lz4_decomp.process(ArrayRange(SplashScreen, sizeof(SplashScreen)), true);
switch(progress) {
case Progress::InProgress:
printf("Decompressing still in progress... %llu\n", bytes_ready);
break;
case Progress::Error:
printf("Error decompressing!!!\n");
break;
case Progress::Done:
printf("Done decompressing: %llu Bytes ready\n", bytes_ready);
break;
}
return bytes_ready;
}
void display_logo() {
static constexpr uint16_t TexturePageHeight = 256;
const auto bytes_ready = decompress_logo();
// Upload SplashScreen picture
auto state = FileProcessor::create(&__boot_loader_end, SimpleTIM::create(32, 0, 0, 0));
state.process(bytes_ready);
// Now load the BIOS font to the specified location
SJIS::load(BIOS_Font::TextureLoadPos);
SJIS::load_clut(BIOS_Font::CLUTLoadPos);
// Duplicate DisplayBuffer content
::JabyEngine::GPU::internal::copy_vram_to_vram({PositionU16::create(0, TexturePageHeight), SizeU16::create(Display::Width, TexturePageHeight)}, PositionU16::create(0, 0));
Display::enable();
}
void setup() {
GPU_IO::GP1.reset();
configure_display();
::JabyEngine::GPU::internal::Display::exchange_buffer_and_display();
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(SysCall::Priority::VblankIrq, &::JabyEngine::GPU::internal::irq_callback);
Interrupt::enable_irq(Interrupt::VBlank);
SysCall::ExitCriticalSection();
}
}
}
#include "../../internal-include/GPU/gpu_internal.hpp"
#include <PSX/System/IOPorts/interrupt_io.hpp>
#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.hpp>
#ifdef JABYENGINE_PAL
#include "splash_image_pal_boot.hpp"
#else
#include "splash_image_ntsc_boot.hpp"
#endif //JABYENGINE_PAL
// Concept for switchting BIOS Fonts...?
#include "BIOSFont/ascii_bios_font.hpp"
extern "C" uint32_t __boot_loader_end;
namespace JabyEngine {
namespace GPU {
namespace internal {
extern SysCall::InterruptCallback irq_callback;
}
namespace SJIS {
void load_clut(const PositionU16& dst_cord) {
struct CLUT {
CPU2VRAM cmd;
Color data[16];
};
const CLUT clut {
.cmd = CPU2VRAM::create(AreaU16::create(dst_cord, GPU::SizeU16::create(16, 1))),
.data = {
Color::Black(), Color::Grey(),
Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(),
Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(),
}
};
GPU::internal::render(reinterpret_cast<const uint32_t*>(&clut), sizeof(CLUT)/sizeof(uint32_t));
}
}
}
namespace boot {
namespace GPU {
using namespace JabyEngine::GPU;
static void configure_display() {
GPU_IO::GP1.set_display_mode(::JabyEngine::GPU::internal::Display::DisplayMode);
GPU::Display::set_offset(0, 0);
}
static size_t decompress_logo() {
LZ4Decompressor lz4_decomp(reinterpret_cast<uint8_t*>(&__boot_loader_end));
const auto [progress, bytes_ready] = lz4_decomp.process(ArrayRange(SplashScreen, sizeof(SplashScreen)), true);
switch(progress) {
case Progress::InProgress:
printf("Decompressing still in progress... %llu\n", bytes_ready);
break;
case Progress::Error:
printf("Error decompressing!!!\n");
break;
case Progress::Done:
printf("Done decompressing: %llu Bytes ready\n", bytes_ready);
break;
}
return bytes_ready;
}
void display_logo() {
static constexpr uint16_t TexturePageHeight = 256;
const auto bytes_ready = decompress_logo();
// Upload SplashScreen picture
auto state = FileProcessor::create(&__boot_loader_end, SimpleTIM::create(32, 0, 0, 0));
state.process(bytes_ready);
// Now load the BIOS font to the specified location
SJIS::load(BIOS_Font::TextureLoadPos);
SJIS::load_clut(BIOS_Font::CLUTLoadPos);
// Duplicate DisplayBuffer content
::JabyEngine::GPU::internal::copy_vram_to_vram({PositionU16::create(0, TexturePageHeight), SizeU16::create(Display::Width, TexturePageHeight)}, PositionU16::create(0, 0));
Display::enable();
}
void setup() {
GPU_IO::GP1.reset();
configure_display();
::JabyEngine::GPU::internal::Display::exchange_buffer_and_display();
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(SysCall::Priority::VblankIrq, &::JabyEngine::GPU::internal::irq_callback);
Interrupt::enable_irq(Interrupt::VBlank);
SysCall::ExitCriticalSection();
}
}
}
}

View File

@@ -1,20 +1,20 @@
#include "../../internal-include/mipscalls.hpp"
#include <PSX/GTE/gte.hpp>
#include <PSX/System/syscalls.hpp>
namespace JabyEngine {
namespace boot {
namespace GTE {
void setup() {
SysCall::EnterCriticalSection();
const auto sr = bit::set(MIPS::SR::read(), MIPS::SR::CU2);
MIPS::SR::write(sr);
SysCall::ExitCriticalSection();
JabyEngine::GTE::set_geom_offset(0, 0);
JabyEngine::GTE::set_geom_screen(512);
}
}
}
#include "../../internal-include/mipscalls.hpp"
#include <PSX/GTE/gte.hpp>
#include <PSX/System/syscalls.hpp>
namespace JabyEngine {
namespace boot {
namespace GTE {
void setup() {
SysCall::EnterCriticalSection();
const auto sr = bit::set(MIPS::SR::read(), MIPS::SR::CU2);
MIPS::SR::write(sr);
SysCall::ExitCriticalSection();
JabyEngine::GTE::set_geom_offset(0, 0);
JabyEngine::GTE::set_geom_screen(512);
}
}
}
}

View File

@@ -1,17 +1,17 @@
#include "../../internal-include/periphery_internal.hpp"
#include <PSX/System/syscalls.hpp>
namespace JabyEngine {
namespace boot {
namespace Periphery {
void setup() {
Periphery_IO::JOY_MODE.write(Periphery_IO_Values::JOY_MODE::create());
Periphery_IO::JOY_BAUD.write(Periphery_IO_Values::JOY_BAUD::create());
SysCall::EnterCriticalSection();
Interrupt::disable_irq(Interrupt::Periphery);
SysCall::ExitCriticalSection();
}
}
}
#include "../../internal-include/periphery_internal.hpp"
#include <PSX/System/syscalls.hpp>
namespace JabyEngine {
namespace boot {
namespace Periphery {
void setup() {
Periphery_IO::JOY_MODE.write(Periphery_IO_Values::JOY_MODE::create());
Periphery_IO::JOY_BAUD.write(Periphery_IO_Values::JOY_BAUD::create());
SysCall::EnterCriticalSection();
Interrupt::disable_irq(Interrupt::Periphery);
SysCall::ExitCriticalSection();
}
}
}
}

View File

@@ -1,88 +1,88 @@
#include <PSX/Auxiliary/math_helper.hpp>
#include <PSX/System/syscalls.hpp>
#include <string.hpp>
namespace JabyEngine {
namespace boot {
namespace BIOS {
using Version = JabyEngine::BIOS::Version;
static uint32_t get_bcd_version() {
return *reinterpret_cast<uint32_t*>(0xBFC00100);
}
static const char* get_kernel_maker_str() {
return reinterpret_cast<const char*>(0xBFC00108);
}
static const char* get_version_str() {
const char* kernel_maker = get_kernel_maker_str();
const char* ver_start = kernel_maker + (strlen(kernel_maker) + 1);
while(*ver_start == 0) {
ver_start++;
}
return ver_start;
}
static Version::Type get_raw_bios_type(const char* version_str) {
static const auto str_length = []<size_t N>(const char (&name)[N]) -> size_t {
return N - 1;
};
const char dev_str[] = "DTL-";
const char ps1_str[] = "CEX-";
const char ps_compatible_str[] = "PS compatible mode";
const char no$psx_str[] = "no$psx";
const char xebra_str[] = "XEBRA";
const struct {
const char* name;
size_t name_length;
Version::Type type;
} bioses[] = {
// Sorted by likeliness
{.name = ps1_str, .name_length = str_length(ps1_str), .type = Version::Type::PS1},
{.name = ps_compatible_str, .name_length = str_length(ps_compatible_str), .type = Version::Type::PSCompatible},
{.name = no$psx_str, .name_length = str_length(no$psx_str), .type = Version::Type::No$psx},
{.name = xebra_str, .name_length = str_length(xebra_str), .type = Version::Type::XEBRA},
{.name = dev_str, .name_length = str_length(dev_str), .type = Version::Type::Devboard}
};
for(const auto& bios : bioses) {
if(strncmp(version_str, bios.name, bios.name_length) == 0) {
return bios.type;
}
}
return Version::Type::Unkown;
}
static Version::Type refine_bios_type(Version::Type type) {
if(type == Version::Type::PSCompatible) {
const auto bios_year_bcd = get_bcd_version() >> 16;
return bios_year_bcd == 0x2011 ? Version::Type::PS3 : Version::Type::PS2;
}
return type;
}
static Version get_bios_version() {
Version version;
const auto date_bcd = get_bcd_version();
const char*const version_str = get_version_str();
version.date.day = from_bcd(static_cast<uint8_t>(date_bcd & 0xFF));
version.date.month = from_bcd(static_cast<uint8_t>((date_bcd >> 8) & 0xFF));
version.date.year = from_bcd(static_cast<uint16_t>(date_bcd >> 16));
version.type = refine_bios_type(get_raw_bios_type(version_str));
version.kernel_maker = get_kernel_maker_str();
version.version_str = version_str;
version.gui_version = reinterpret_cast<const char*>(0xBFC7FF32);
version.copyright = version.gui_version + (strlen(version.gui_version) + 1);
return version;
}
void identify() {
const_cast<JabyEngine::BIOS::Version&>(JabyEngine::BIOS::version) = get_bios_version();
}
}
}
#include <PSX/Auxiliary/math_helper.hpp>
#include <PSX/System/syscalls.hpp>
#include <string.hpp>
namespace JabyEngine {
namespace boot {
namespace BIOS {
using Version = JabyEngine::BIOS::Version;
static uint32_t get_bcd_version() {
return *reinterpret_cast<uint32_t*>(0xBFC00100);
}
static const char* get_kernel_maker_str() {
return reinterpret_cast<const char*>(0xBFC00108);
}
static const char* get_version_str() {
const char* kernel_maker = get_kernel_maker_str();
const char* ver_start = kernel_maker + (strlen(kernel_maker) + 1);
while(*ver_start == 0) {
ver_start++;
}
return ver_start;
}
static Version::Type get_raw_bios_type(const char* version_str) {
static const auto str_length = []<size_t N>(const char (&name)[N]) -> size_t {
return N - 1;
};
const char dev_str[] = "DTL-";
const char ps1_str[] = "CEX-";
const char ps_compatible_str[] = "PS compatible mode";
const char no$psx_str[] = "no$psx";
const char xebra_str[] = "XEBRA";
const struct {
const char* name;
size_t name_length;
Version::Type type;
} bioses[] = {
// Sorted by likeliness
{.name = ps1_str, .name_length = str_length(ps1_str), .type = Version::Type::PS1},
{.name = ps_compatible_str, .name_length = str_length(ps_compatible_str), .type = Version::Type::PSCompatible},
{.name = no$psx_str, .name_length = str_length(no$psx_str), .type = Version::Type::No$psx},
{.name = xebra_str, .name_length = str_length(xebra_str), .type = Version::Type::XEBRA},
{.name = dev_str, .name_length = str_length(dev_str), .type = Version::Type::Devboard}
};
for(const auto& bios : bioses) {
if(strncmp(version_str, bios.name, bios.name_length) == 0) {
return bios.type;
}
}
return Version::Type::Unkown;
}
static Version::Type refine_bios_type(Version::Type type) {
if(type == Version::Type::PSCompatible) {
const auto bios_year_bcd = get_bcd_version() >> 16;
return bios_year_bcd == 0x2011 ? Version::Type::PS3 : Version::Type::PS2;
}
return type;
}
static Version get_bios_version() {
Version version;
const auto date_bcd = get_bcd_version();
const char*const version_str = get_version_str();
version.date.day = from_bcd(static_cast<uint8_t>(date_bcd & 0xFF));
version.date.month = from_bcd(static_cast<uint8_t>((date_bcd >> 8) & 0xFF));
version.date.year = from_bcd(static_cast<uint16_t>(date_bcd >> 16));
version.type = refine_bios_type(get_raw_bios_type(version_str));
version.kernel_maker = get_kernel_maker_str();
version.version_str = version_str;
version.gui_version = reinterpret_cast<const char*>(0xBFC7FF32);
version.copyright = version.gui_version + (strlen(version.gui_version) + 1);
return version;
}
void identify() {
const_cast<JabyEngine::BIOS::Version&>(JabyEngine::BIOS::version) = get_bios_version();
}
}
}
}

View File

@@ -1,33 +1,33 @@
#include <PSX/System/IOPorts/interrupt_io.hpp>
#include <PSX/System/syscalls.hpp>
#include <PSX/Timer/high_res_timer.hpp>
namespace JabyEngine {
namespace Timer {
extern SysCall::InterruptCallback irq_callback;
}
namespace boot {
namespace Timer {
using namespace JabyEngine::Timer;
void setup() {
using namespace Timer_IO;
using namespace Timer_IO_Values;
static constexpr auto Mode = CounterMode::from(CounterMode::FreeRun, Counter2::SyncMode::FreeRun, CounterMode::ResetAfterTarget, CounterMode::IRQAtTarget, CounterMode::IRQEveryTime, CounterMode::IRQPulse, Counter2::Source::System_Clock_Div_8);
// We disable the IRQ here so it can be enabled by user demand later
// 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(SysCall::Priority::Timer2Irq, &irq_callback);
SysCall::ExitCriticalSection();
Counter2.set_target_value(HighResTime::TicksFor10ms);
Counter2.set_mode(Mode);
}
}
}
#include <PSX/System/IOPorts/interrupt_io.hpp>
#include <PSX/System/syscalls.hpp>
#include <PSX/Timer/high_res_timer.hpp>
namespace JabyEngine {
namespace Timer {
extern SysCall::InterruptCallback irq_callback;
}
namespace boot {
namespace Timer {
using namespace JabyEngine::Timer;
void setup() {
using namespace Timer_IO;
using namespace Timer_IO_Values;
static constexpr auto Mode = CounterMode::from(CounterMode::FreeRun, Counter2::SyncMode::FreeRun, CounterMode::ResetAfterTarget, CounterMode::IRQAtTarget, CounterMode::IRQEveryTime, CounterMode::IRQPulse, Counter2::Source::System_Clock_Div_8);
// We disable the IRQ here so it can be enabled by user demand later
// 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(SysCall::Priority::Timer2Irq, &irq_callback);
SysCall::ExitCriticalSection();
Counter2.set_target_value(HighResTime::TicksFor10ms);
Counter2.set_mode(Mode);
}
}
}
}

View File

@@ -1,130 +1,130 @@
#include "../../internal-include/CD/cd_internal.hpp"
#include "../../internal-include/System/callbacks_internal.hpp"
#include <PSX/System/IOPorts/dma_io.hpp>
#include <PSX/System/IOPorts/interrupt_io.hpp>
#include <PSX/System/syscalls.hpp>
#include <stdio.hpp>
namespace JabyEngine {
namespace CD {
namespace internal {
extern SectorBufferAllocator sector_allocator;
extern File cur_file;
static constexpr auto AudioSectorMode = CD_IO_Values::Mode::from(CD_IO_Values::Mode::SingleSpeed, CD_IO_Values::Mode::AutoPauseTrack, CD_IO_Values::Mode::CDDA);
static constexpr auto DataSectorMode = CD_IO_Values::Mode::from(CD_IO_Values::Mode::DoubleSpeed, CD_IO_Values::Mode::DataSector);
static constexpr auto XAAudioSectorMode = CD_IO_Values::Mode::from(CD_IO_Values::Mode::SingleSpeed, CD_IO_Values::Mode::XADPCM, CD_IO_Values::Mode::WholeSector, CD_IO_Values::Mode::UseXAFilter);
namespace IRQ {
SysCall::InterruptVerifierResult verifier();
void handler(uint32_t);
}
auto irq_callback = SysCall::InterruptCallback::from(IRQ::verifier, IRQ::handler);
State current_state = State::Ready;
uint8_t irq_bit_pending = CD_IO::Interrupt::None;
static void read_sector_dma(uint32_t* dst, size_t bytes) {
static const auto WaitSectorReady = []() {
while(!CD_IO::IndexStatus.read().is_set(CD_IO_Values::IndexStatus::HasDataFifoData));
};
static const auto ReadSector = [](uint32_t* dst, size_t bytes) {
DMA_IO::CDROM.set_adr(reinterpret_cast<uintptr_t>(dst));
DMA_IO::CDROM.block_ctrl.write(DMA_IO_Values::BCR::SyncMode0::for_cd(bytes >> 2));
DMA_IO::CDROM.channel_ctrl.write(DMA_IO_Values::CHCHR::StartCDROM());
DMA_IO::CDROM.wait();
CD_IO::PortIndex0::change_to();
CD_IO::PortIndex0::Request.write(CD_IO_Values::Request::reset());
};
WaitSectorReady();
ReadSector(dst, bytes);
}
static BCDTimeStamp send_read_cmd(uint32_t lba, CD_IO::Command::Desc cmd) {
const auto loc = BCDTimeStamp::from(lba);
Command::send(CD_IO::Command::SetLoc, loc.min, loc.sec, loc.sector);
Command::send(cmd);
return loc;
}
static void send_read_n(uint32_t lba) {
send_read_cmd(lba, CD_IO::Command::ReadN);
current_state = State::Reading;
}
void read_file(AutoLBAEntry file_info, const SectorBufferAllocator& buffer_allocator) {
cur_file.set_from(file_info);
sector_allocator = buffer_allocator;
enable_CD();
send_read_n(cur_file.cur_lba);
}
void end_read_file() {
sector_allocator = SectorBufferAllocator::invalid();
}
void continue_reading() {
if(current_state == State::BufferFull) {
CD_IO::PortIndex0::change_to();
send_read_n(cur_file.cur_lba);
}
}
void copy_from_sector(uint32_t* dst, size_t bytes) {
read_sector_dma(dst, bytes);
}
BCDTimeStamp get_loc() {
Command::send_wait_response(CD_IO::Command::GetLocP);
// XEBRA does not support the mirror register so we go for the original...
CD_IO::PortIndex1::change_to();
const auto track = CD_IO::PortIndex1::ResponseFifo.read().raw; // track number (AAh=Lead-out area) (FFh=unknown, toc, none?)
const auto index = CD_IO::PortIndex1::ResponseFifo.read().raw; // index number (Usually 01h)
const auto mm = CD_IO::PortIndex1::ResponseFifo.read().raw; // minute number within track (00h and up)
const auto ss = CD_IO::PortIndex1::ResponseFifo.read().raw; // second number within track (00h to 59h)
const auto sect = CD_IO::PortIndex1::ResponseFifo.read().raw; // sector number within track (00h to 74h)
const auto min = CD_IO::PortIndex1::ResponseFifo.read().raw; // minute number on entire disk (00h and up)
const auto sec = CD_IO::PortIndex1::ResponseFifo.read().raw; // second number on entire disk (00h to 59h)
const auto sectors = CD_IO::PortIndex1::ResponseFifo.read().raw; // sector number on entire disk (00h to 74h)
return BCDTimeStamp{min, sec, sectors};
}
BCDTimeStamp get_locL() {
Command::send_wait_response(CD_IO::Command::GetLocL);
const auto min = CD_IO::PortIndex0::ResponseFifo.read().raw;
const auto sec = CD_IO::PortIndex0::ResponseFifo.read().raw;
const auto sector = CD_IO::PortIndex0::ResponseFifo.read().raw;
return BCDTimeStamp{min, sec, sector};
}
void enable_CD() {
Command::send(CD_IO::Command::SetMode, DataSectorMode);
}
void enable_CDDA() {
Command::send(CD_IO::Command::SetMode, AudioSectorMode);
}
void enable_CDXA(bool double_speed) {
static constexpr uint8_t SingleSpeedBit = 0x0;
static constexpr uint8_t DoubleSpeedBit = static_cast<uint8_t>(CD_IO_Values::Mode::DoubleSpeed);
const uint8_t mode = XAAudioSectorMode.raw | (double_speed ? DoubleSpeedBit : SingleSpeedBit);
Command::send(CD_IO::Command::SetMode, mode);
current_state = State::XAMode;
}
}
}
#include "../../internal-include/CD/cd_internal.hpp"
#include "../../internal-include/System/callbacks_internal.hpp"
#include <PSX/System/IOPorts/dma_io.hpp>
#include <PSX/System/IOPorts/interrupt_io.hpp>
#include <PSX/System/syscalls.hpp>
#include <stdio.hpp>
namespace JabyEngine {
namespace CD {
namespace internal {
extern SectorBufferAllocator sector_allocator;
extern File cur_file;
static constexpr auto AudioSectorMode = CD_IO_Values::Mode::from(CD_IO_Values::Mode::SingleSpeed, CD_IO_Values::Mode::AutoPauseTrack, CD_IO_Values::Mode::CDDA);
static constexpr auto DataSectorMode = CD_IO_Values::Mode::from(CD_IO_Values::Mode::DoubleSpeed, CD_IO_Values::Mode::DataSector);
static constexpr auto XAAudioSectorMode = CD_IO_Values::Mode::from(CD_IO_Values::Mode::SingleSpeed, CD_IO_Values::Mode::XADPCM, CD_IO_Values::Mode::WholeSector, CD_IO_Values::Mode::UseXAFilter);
namespace IRQ {
SysCall::InterruptVerifierResult verifier();
void handler(uint32_t);
}
auto irq_callback = SysCall::InterruptCallback::from(IRQ::verifier, IRQ::handler);
State current_state = State::Ready;
uint8_t irq_bit_pending = CD_IO::Interrupt::None;
static void read_sector_dma(uint32_t* dst, size_t bytes) {
static const auto WaitSectorReady = []() {
while(!CD_IO::IndexStatus.read().is_set(CD_IO_Values::IndexStatus::HasDataFifoData));
};
static const auto ReadSector = [](uint32_t* dst, size_t bytes) {
DMA_IO::CDROM.set_adr(reinterpret_cast<uintptr_t>(dst));
DMA_IO::CDROM.block_ctrl.write(DMA_IO_Values::BCR::SyncMode0::for_cd(bytes >> 2));
DMA_IO::CDROM.channel_ctrl.write(DMA_IO_Values::CHCHR::StartCDROM());
DMA_IO::CDROM.wait();
CD_IO::PortIndex0::change_to();
CD_IO::PortIndex0::Request.write(CD_IO_Values::Request::reset());
};
WaitSectorReady();
ReadSector(dst, bytes);
}
static BCDTimeStamp send_read_cmd(uint32_t lba, CD_IO::Command::Desc cmd) {
const auto loc = BCDTimeStamp::from(lba);
Command::send(CD_IO::Command::SetLoc, loc.min, loc.sec, loc.sector);
Command::send(cmd);
return loc;
}
static void send_read_n(uint32_t lba) {
send_read_cmd(lba, CD_IO::Command::ReadN);
current_state = State::Reading;
}
void read_file(AutoLBAEntry file_info, const SectorBufferAllocator& buffer_allocator) {
cur_file.set_from(file_info);
sector_allocator = buffer_allocator;
enable_CD();
send_read_n(cur_file.cur_lba);
}
void end_read_file() {
sector_allocator = SectorBufferAllocator::invalid();
}
void continue_reading() {
if(current_state == State::BufferFull) {
CD_IO::PortIndex0::change_to();
send_read_n(cur_file.cur_lba);
}
}
void copy_from_sector(uint32_t* dst, size_t bytes) {
read_sector_dma(dst, bytes);
}
BCDTimeStamp get_loc() {
Command::send_wait_response(CD_IO::Command::GetLocP);
// XEBRA does not support the mirror register so we go for the original...
CD_IO::PortIndex1::change_to();
const auto track = CD_IO::PortIndex1::ResponseFifo.read().raw; // track number (AAh=Lead-out area) (FFh=unknown, toc, none?)
const auto index = CD_IO::PortIndex1::ResponseFifo.read().raw; // index number (Usually 01h)
const auto mm = CD_IO::PortIndex1::ResponseFifo.read().raw; // minute number within track (00h and up)
const auto ss = CD_IO::PortIndex1::ResponseFifo.read().raw; // second number within track (00h to 59h)
const auto sect = CD_IO::PortIndex1::ResponseFifo.read().raw; // sector number within track (00h to 74h)
const auto min = CD_IO::PortIndex1::ResponseFifo.read().raw; // minute number on entire disk (00h and up)
const auto sec = CD_IO::PortIndex1::ResponseFifo.read().raw; // second number on entire disk (00h to 59h)
const auto sectors = CD_IO::PortIndex1::ResponseFifo.read().raw; // sector number on entire disk (00h to 74h)
return BCDTimeStamp{min, sec, sectors};
}
BCDTimeStamp get_locL() {
Command::send_wait_response(CD_IO::Command::GetLocL);
const auto min = CD_IO::PortIndex0::ResponseFifo.read().raw;
const auto sec = CD_IO::PortIndex0::ResponseFifo.read().raw;
const auto sector = CD_IO::PortIndex0::ResponseFifo.read().raw;
return BCDTimeStamp{min, sec, sector};
}
void enable_CD() {
Command::send(CD_IO::Command::SetMode, DataSectorMode);
}
void enable_CDDA() {
Command::send(CD_IO::Command::SetMode, AudioSectorMode);
}
void enable_CDXA(bool double_speed) {
static constexpr uint8_t SingleSpeedBit = 0x0;
static constexpr uint8_t DoubleSpeedBit = static_cast<uint8_t>(CD_IO_Values::Mode::DoubleSpeed);
const uint8_t mode = XAAudioSectorMode.raw | (double_speed ? DoubleSpeedBit : SingleSpeedBit);
Command::send(CD_IO::Command::SetMode, mode);
current_state = State::XAMode;
}
}
}
}

View File

@@ -1,93 +1,93 @@
#include "../../internal-include/CD/cd_internal.hpp"
#include <PSX/System/IOPorts/dma_io.hpp>
namespace JabyEngine {
namespace CDDA {
extern CD::internal::BCDTimeStamp playing_track;
}
namespace CDXA {
CD::internal::State interrupt_handler(uint8_t irq);
}
namespace CD {
namespace internal {
SectorBufferAllocator sector_allocator;
File cur_file;
namespace IRQ {
static void process(uint32_t irq) {
if(current_state != State::XAMode) {
switch(irq) {
case CD_IO::Interrupt::DataReady: {
// Obtain sector content here
auto* sector = sector_allocator.allocate_sector();
if(sector) {
//Now obtain sector
copy_from_sector(sector->data, CD_IO::DataSector::SizeBytes);
if(cur_file.done_processing()) {
current_state = State::Done;
Command::send_no_wait(CD_IO::Command::Pause);
}
}
else {
current_state = State::BufferFull;
Command::send_no_wait(CD_IO::Command::Pause);
}
} break;
case CD_IO::Interrupt::DataEnd: {
set_loc(CDDA::playing_track);
Command::send_no_wait(CD_IO::Command::Play);
} break;
case CD_IO::Interrupt::DiskError: {
current_state = State::Error;
} break;
}
}
else {
current_state = CDXA::interrupt_handler(irq);
}
}
//######################################################################################################################
SysCall::InterruptVerifierResult verifier() {
if(Interrupt::is_irq(Interrupt::CDROM)) {
Interrupt::ack_irq(Interrupt::CDROM);
return SysCall::InterruptVerifierResult::ExecuteHandler;
}
else {
return SysCall::InterruptVerifierResult::SkipHandler;
}
}
void handler(uint32_t x) {
const auto old_status = CD_IO::IndexStatus.read();
CD_IO::PortIndex1::change_to();
const auto cur_irq = CD_IO::Interrupt::get_type(CD_IO::PortIndex1::InterruptFlag);
CD_IO::PortIndex1::change_to();
CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag);
irq_bit_pending = bit::clear(irq_bit_pending, cur_irq);
CD_IO::PortIndex0::change_to();
if(cur_irq == CD_IO::Interrupt::DataReady) {
CD_IO::PortIndex0::Request.write(CD_IO_Values::Request::want_data());
}
process(cur_irq);
// No masking required because we can only write bit 0 - 2
CD_IO::IndexStatus.write(old_status);
return SysCall::ReturnFromException();
}
}
}
}
#include "../../internal-include/CD/cd_internal.hpp"
#include <PSX/System/IOPorts/dma_io.hpp>
namespace JabyEngine {
namespace CDDA {
extern CD::internal::BCDTimeStamp playing_track;
}
namespace CDXA {
CD::internal::State interrupt_handler(uint8_t irq);
}
namespace CD {
namespace internal {
SectorBufferAllocator sector_allocator;
File cur_file;
namespace IRQ {
static void process(uint32_t irq) {
if(current_state != State::XAMode) {
switch(irq) {
case CD_IO::Interrupt::DataReady: {
// Obtain sector content here
auto* sector = sector_allocator.allocate_sector();
if(sector) {
//Now obtain sector
copy_from_sector(sector->data, CD_IO::DataSector::SizeBytes);
if(cur_file.done_processing()) {
current_state = State::Done;
Command::send_no_wait(CD_IO::Command::Pause);
}
}
else {
current_state = State::BufferFull;
Command::send_no_wait(CD_IO::Command::Pause);
}
} break;
case CD_IO::Interrupt::DataEnd: {
set_loc(CDDA::playing_track);
Command::send_no_wait(CD_IO::Command::Play);
} break;
case CD_IO::Interrupt::DiskError: {
current_state = State::Error;
} break;
}
}
else {
current_state = CDXA::interrupt_handler(irq);
}
}
//######################################################################################################################
SysCall::InterruptVerifierResult verifier() {
if(Interrupt::is_irq(Interrupt::CDROM)) {
Interrupt::ack_irq(Interrupt::CDROM);
return SysCall::InterruptVerifierResult::ExecuteHandler;
}
else {
return SysCall::InterruptVerifierResult::SkipHandler;
}
}
void handler(uint32_t x) {
const auto old_status = CD_IO::IndexStatus.read();
CD_IO::PortIndex1::change_to();
const auto cur_irq = CD_IO::Interrupt::get_type(CD_IO::PortIndex1::InterruptFlag);
CD_IO::PortIndex1::change_to();
CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag);
irq_bit_pending = bit::clear(irq_bit_pending, cur_irq);
CD_IO::PortIndex0::change_to();
if(cur_irq == CD_IO::Interrupt::DataReady) {
CD_IO::PortIndex0::Request.write(CD_IO_Values::Request::want_data());
}
process(cur_irq);
// No masking required because we can only write bit 0 - 2
CD_IO::IndexStatus.write(old_status);
return SysCall::ReturnFromException();
}
}
}
}
}

View File

@@ -1,67 +1,67 @@
#include "tim_helper.hpp"
namespace JabyEngine {
namespace TIMFileProcessor {
namespace {
void set_gpu_receive(const uint32_t* src, uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
GPU::internal::DMA::Receive::prepare();
GPU::internal::DMA::Receive::set_dst(PositionU16::create(x, y), SizeU16::create(w, h));
GPU::internal::DMA::Receive::set_src(reinterpret_cast<const uintptr_t>(src));
}
size_t set_gpu_receive_data(const uint32_t* src, const AreaU16& dst) {
const auto width = dst.size.width;
const auto height = dst.size.height;
set_gpu_receive(src, dst.position.x, dst.position.y, width, height);
return (width*height)/2;
}
Progress parse_data(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) {
const auto [words_to_use, is_last] = Helper::DMA::WordsReady::calculate(data_proc, generic_tim.words_left);
const auto words_used = Helper::DMA::send_words<GPU::internal::DMA>(words_to_use, is_last);
generic_tim.words_left -= words_used;
data_proc.processed(words_used*sizeof(uint32_t));
return is_last ? Progress::Done : Progress::InProgress;
}
Progress switch_state_parse_data(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) {
const auto result = generic_tim.pre_data_parsing(data_proc);
if(result == Progress::Done) {
generic_tim.words_left = TIMFileProcessor::set_gpu_receive_data(reinterpret_cast<const uint32_t*>(data_proc.data_adr), generic_tim.tex_area);
return Helper::exchange_and_execute_process_function<TIMFileProcessor::GenericTIM>(TIMFileProcessor::parse_data, data_proc, generic_tim);
}
return result;
}
Progress parse_clut(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) {
if(const auto result = TIMFileProcessor::parse_data(data_proc, generic_tim); result != Progress::Done) {
return result;
}
else {
return switch_state_parse_data(data_proc, generic_tim);
}
}
}
Progress parse_header(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) {
const auto result = generic_tim.parse_header(data_proc);
if(result == Progress::Done) {
//Check if we have a clut to care about
if(generic_tim.has_clut()) {
//CLUTs are 16bit full color anyway
generic_tim.words_left = TIMFileProcessor::set_gpu_receive_data(reinterpret_cast<const uint32_t*>(data_proc.data_adr), generic_tim.clut_area);
return Helper::exchange_and_execute_process_function(parse_clut, data_proc, generic_tim);
}
else {
return switch_state_parse_data(data_proc, generic_tim);
}
}
return result;
}
}
#include "tim_helper.hpp"
namespace JabyEngine {
namespace TIMFileProcessor {
namespace {
void set_gpu_receive(const uint32_t* src, uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
GPU::internal::DMA::Receive::prepare();
GPU::internal::DMA::Receive::set_dst(PositionU16::create(x, y), SizeU16::create(w, h));
GPU::internal::DMA::Receive::set_src(reinterpret_cast<const uintptr_t>(src));
}
size_t set_gpu_receive_data(const uint32_t* src, const AreaU16& dst) {
const auto width = dst.size.width;
const auto height = dst.size.height;
set_gpu_receive(src, dst.position.x, dst.position.y, width, height);
return (width*height)/2;
}
Progress parse_data(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) {
const auto [words_to_use, is_last] = Helper::DMA::WordsReady::calculate(data_proc, generic_tim.words_left);
const auto words_used = Helper::DMA::send_words<GPU::internal::DMA>(words_to_use, is_last);
generic_tim.words_left -= words_used;
data_proc.processed(words_used*sizeof(uint32_t));
return is_last ? Progress::Done : Progress::InProgress;
}
Progress switch_state_parse_data(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) {
const auto result = generic_tim.pre_data_parsing(data_proc);
if(result == Progress::Done) {
generic_tim.words_left = TIMFileProcessor::set_gpu_receive_data(reinterpret_cast<const uint32_t*>(data_proc.data_adr), generic_tim.tex_area);
return Helper::exchange_and_execute_process_function<TIMFileProcessor::GenericTIM>(TIMFileProcessor::parse_data, data_proc, generic_tim);
}
return result;
}
Progress parse_clut(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) {
if(const auto result = TIMFileProcessor::parse_data(data_proc, generic_tim); result != Progress::Done) {
return result;
}
else {
return switch_state_parse_data(data_proc, generic_tim);
}
}
}
Progress parse_header(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) {
const auto result = generic_tim.parse_header(data_proc);
if(result == Progress::Done) {
//Check if we have a clut to care about
if(generic_tim.has_clut()) {
//CLUTs are 16bit full color anyway
generic_tim.words_left = TIMFileProcessor::set_gpu_receive_data(reinterpret_cast<const uint32_t*>(data_proc.data_adr), generic_tim.clut_area);
return Helper::exchange_and_execute_process_function(parse_clut, data_proc, generic_tim);
}
else {
return switch_state_parse_data(data_proc, generic_tim);
}
}
return result;
}
}
}

View File

@@ -1,26 +1,26 @@
#pragma once
#include "../../../../internal-include/GPU/gpu_internal.hpp"
#include <PSX/File/file_processor_helper.hpp>
#include <PSX/GPU/gpu_types.hpp>
namespace JabyEngine {
namespace TIMFileProcessor {
using namespace FileProcessor;
using namespace GPU;
struct GenericTIM {
AreaU16 clut_area;
AreaU16 tex_area;
size_t words_left; //32bit values
bool has_clut() const {
return this->clut_area.size.width > 0;
}
virtual Progress parse_header(State::CDDataProcessor& data_proc) = 0;
virtual Progress pre_data_parsing(State::CDDataProcessor& data_proc) = 0;
};
Progress parse_header(State::CDDataProcessor& data_proc, GenericTIM& generic_tim);
}
#pragma once
#include "../../../../internal-include/GPU/gpu_internal.hpp"
#include <PSX/File/file_processor_helper.hpp>
#include <PSX/GPU/gpu_types.hpp>
namespace JabyEngine {
namespace TIMFileProcessor {
using namespace FileProcessor;
using namespace GPU;
struct GenericTIM {
AreaU16 clut_area;
AreaU16 tex_area;
size_t words_left; //32bit values
bool has_clut() const {
return this->clut_area.size.width > 0;
}
virtual Progress parse_header(State::CDDataProcessor& data_proc) = 0;
virtual Progress pre_data_parsing(State::CDDataProcessor& data_proc) = 0;
};
Progress parse_header(State::CDDataProcessor& data_proc, GenericTIM& generic_tim);
}
}

View File

@@ -1,61 +1,61 @@
#include "tim_helper.hpp"
#include <stdio.hpp>
namespace JabyEngine {
namespace FileProcessor {
namespace {
using GPU::AreaU16;
struct BlockInfo {
uint32_t size;
uint16_t x;
uint16_t y;
uint16_t w;
uint16_t h;
};
struct TIMState : public TIMFileProcessor::GenericTIM {
static TIMState create() {
TIMState state;
return state;
}
virtual Progress parse_header(State::CDDataProcessor& data_proc) override {
static constexpr auto HEADER_SIZE = 2*sizeof(uint32_t);
if(data_proc.data_bytes >= (HEADER_SIZE + sizeof(BlockInfo))) {
static constexpr auto HAS_CLUT_BIT = (0x1 << 3);
data_proc.processed(sizeof(uint32_t));
const auto flag = data_proc.simple_read_r<uint32_t>();
if(flag & HAS_CLUT_BIT) {
const auto block_info = data_proc.simple_read_r<BlockInfo>();
this->clut_area = AreaU16::create(block_info.x, block_info.y, block_info.w, block_info.h);
}
else {
this->clut_area = AreaU16::create(0, 0, 0, 0);
}
return Progress::Done;
}
return Progress::Error;
}
virtual Progress pre_data_parsing(State::CDDataProcessor& data_proc) {
if(data_proc.data_bytes >= sizeof(BlockInfo)) {
const auto block_info = data_proc.simple_read_r<BlockInfo>();
this->tex_area = AreaU16::create(block_info.x, block_info.y, block_info.w, block_info.h);
return Progress::Done;
}
return Progress::InProgress;
}
};
}
State create(const uint32_t* data_adr, const TIM& file) {
using Callback = Progress(*)(State::CDDataProcessor& data_proc, TIMState& simple_tim);
return State::from(TIMState::create(), data_adr, reinterpret_cast<Callback>(TIMFileProcessor::parse_header));
}
}
#include "tim_helper.hpp"
#include <stdio.hpp>
namespace JabyEngine {
namespace FileProcessor {
namespace {
using GPU::AreaU16;
struct BlockInfo {
uint32_t size;
uint16_t x;
uint16_t y;
uint16_t w;
uint16_t h;
};
struct TIMState : public TIMFileProcessor::GenericTIM {
static TIMState create() {
TIMState state;
return state;
}
virtual Progress parse_header(State::CDDataProcessor& data_proc) override {
static constexpr auto HEADER_SIZE = 2*sizeof(uint32_t);
if(data_proc.data_bytes >= (HEADER_SIZE + sizeof(BlockInfo))) {
static constexpr auto HAS_CLUT_BIT = (0x1 << 3);
data_proc.processed(sizeof(uint32_t));
const auto flag = data_proc.simple_read_r<uint32_t>();
if(flag & HAS_CLUT_BIT) {
const auto block_info = data_proc.simple_read_r<BlockInfo>();
this->clut_area = AreaU16::create(block_info.x, block_info.y, block_info.w, block_info.h);
}
else {
this->clut_area = AreaU16::create(0, 0, 0, 0);
}
return Progress::Done;
}
return Progress::Error;
}
virtual Progress pre_data_parsing(State::CDDataProcessor& data_proc) {
if(data_proc.data_bytes >= sizeof(BlockInfo)) {
const auto block_info = data_proc.simple_read_r<BlockInfo>();
this->tex_area = AreaU16::create(block_info.x, block_info.y, block_info.w, block_info.h);
return Progress::Done;
}
return Progress::InProgress;
}
};
}
State create(const uint32_t* data_adr, const TIM& file) {
using Callback = Progress(*)(State::CDDataProcessor& data_proc, TIMState& simple_tim);
return State::from(TIMState::create(), data_adr, reinterpret_cast<Callback>(TIMFileProcessor::parse_header));
}
}
}

View File

@@ -1,127 +1,127 @@
#include "../../../internal-include/CD/cd_internal.hpp"
#include <PSX/File/Processor/cd_file_processor.hpp>
#include <stdio.hpp>
namespace JabyEngine {
static constexpr auto DisabledCircularBufferSize = 512;
void CDFileProcessor :: start_cur_job(const AutoLBAEntry* lba, const BufferConfiguration& buf_cfg) {
using CD::internal::SectorBufferAllocator;
const auto configurate_for = [this](const CDFile& file, const BufferConfiguration& buf_cfg, bool is_lz4) -> FileProcessor::State {
const uint32_t* data_adr = [this](const CDFile& file, const BufferConfiguration& buf_cfg, bool is_lz4) -> const uint32_t* {
const auto disable_lz4 = [this](uint32_t* work_area, size_t size, uint32_t* overwrite_dst = nullptr) -> uint32_t* {
reinterpret_cast<uint8_t*>(this->circular_buffer.setup(reinterpret_cast<CD_IO::DataSector*>(work_area), size));
this->lz4_decomp.disable();
return overwrite_dst ? overwrite_dst : reinterpret_cast<uint32_t*>(work_area);
};
const auto enable_lz4 = [this](uint32_t* work_area, size_t size, uint32_t* override_dst = nullptr) -> uint32_t* {
uint8_t* dst_adr = reinterpret_cast<uint8_t*>(this->circular_buffer.setup(reinterpret_cast<CD_IO::DataSector*>(work_area), size));
if(override_dst) {
dst_adr = reinterpret_cast<uint8_t*>(override_dst);
}
this->lz4_decomp.setup(dst_adr);
return reinterpret_cast<uint32_t*>(dst_adr);
};
if(file.type == CDFileType::CopyTo) {
return is_lz4 ? enable_lz4(buf_cfg.adr, buf_cfg.sector_count, file.payload.overlay.dst) : disable_lz4(file.payload.copy_to.dst, DisabledCircularBufferSize);
}
else {
return is_lz4 ? enable_lz4(buf_cfg.adr, buf_cfg.sector_count) : disable_lz4(buf_cfg.adr, DisabledCircularBufferSize);
}
}(file, buf_cfg, is_lz4);
switch(file.type) {
case CDFileType::CopyTo:
return FileProcessor::create(data_adr, Nothing());
case CDFileType::SimpleTIM:
return FileProcessor::create(data_adr, file.payload.simple_tim);
case CDFileType::SonyTIM:
return FileProcessor::create(data_adr, file.payload.tim);
case CDFileType::SonyVAG:
return FileProcessor::create(data_adr, file.payload.vag);
default:
return FileProcessor::create_custom(data_adr, static_cast<CDFileType_t>(file.type) - static_cast<CDFileType_t>(CDFileType::Custom), file.payload);
}
};
const auto& cur_job = *this->jobs.files;
const auto& cur_lba = lba[cur_job.rel_lba_idx];
this->file_state = configurate_for(cur_job, buf_cfg, cur_lba.is_lz4());
CD::internal::read_file(cur_lba, SectorBufferAllocator::create(this,
[](void* ctx) -> CD_IO::DataSector* {
CDFileProcessor &self = *reinterpret_cast<CDFileProcessor*>(ctx);
return self.circular_buffer.allocate();
}));
//printf(">>> %i.) CD needs to load LBA: %i -> %i (is LZ4: [%s])\n", cur_job.rel_lba_idx, cur_lba.get_lba(), cur_lba.get_size_in_sectors(), cur_lba.is_lz4() ? "Yes" : "No");
}
bool CDFileProcessor :: process_data() {
while(this->circular_buffer.has_data()) {
ArrayRange<const uint8_t> cur_sector(reinterpret_cast<uint8_t*>(this->circular_buffer.get_next()->data), CD_IO::DataSector::SizeBytes);
// v We can not know if there will be more data or not - but it also doesn't matter much for us
const auto result = this->lz4_decomp.process(cur_sector, false);
this->circular_buffer.pop();
if(result) {
// Process the data in the tmp_area
if(this->file_state.process(result.bytes_ready) == Progress::Error) {
return false;
}
}
else {
return false;
}
}
return true;
}
void CDFileProcessor :: setup(const volatile AutoLBAEntry* lba, JobArray jobs, const BufferConfiguration& buf_cfg) {
this->jobs = jobs;
CDFileProcessor::start_cur_job(const_cast<const AutoLBAEntry*>(lba), buf_cfg);
}
void CDFileProcessor :: shutdown() {
CD::internal::end_read_file();
}
Progress CDFileProcessor :: process() {
const auto cur_state = CD::internal::read_current_state();
CDFileProcessor::process_data();
switch(cur_state) {
case CD::internal::State::Done:
/*
We are done now!
The user decides if he wants the next value
*/
//while(this->file_state.process(0) != Progress::Done);
return Progress::Done;
case CD::internal::State::BufferFull:
/* We processed data and unpause the CD drive */
CD::internal::continue_reading();
return Progress::InProgress;
case CD::internal::State::Reading:
return Progress::InProgress;
case CD::internal::State::Error:
default:
/* Error for real */
return Progress::Error;
}
}
#include "../../../internal-include/CD/cd_internal.hpp"
#include <PSX/File/Processor/cd_file_processor.hpp>
#include <stdio.hpp>
namespace JabyEngine {
static constexpr auto DisabledCircularBufferSize = 512;
void CDFileProcessor :: start_cur_job(const AutoLBAEntry* lba, const BufferConfiguration& buf_cfg) {
using CD::internal::SectorBufferAllocator;
const auto configurate_for = [this](const CDFile& file, const BufferConfiguration& buf_cfg, bool is_lz4) -> FileProcessor::State {
const uint32_t* data_adr = [this](const CDFile& file, const BufferConfiguration& buf_cfg, bool is_lz4) -> const uint32_t* {
const auto disable_lz4 = [this](uint32_t* work_area, size_t size, uint32_t* overwrite_dst = nullptr) -> uint32_t* {
reinterpret_cast<uint8_t*>(this->circular_buffer.setup(reinterpret_cast<CD_IO::DataSector*>(work_area), size));
this->lz4_decomp.disable();
return overwrite_dst ? overwrite_dst : reinterpret_cast<uint32_t*>(work_area);
};
const auto enable_lz4 = [this](uint32_t* work_area, size_t size, uint32_t* override_dst = nullptr) -> uint32_t* {
uint8_t* dst_adr = reinterpret_cast<uint8_t*>(this->circular_buffer.setup(reinterpret_cast<CD_IO::DataSector*>(work_area), size));
if(override_dst) {
dst_adr = reinterpret_cast<uint8_t*>(override_dst);
}
this->lz4_decomp.setup(dst_adr);
return reinterpret_cast<uint32_t*>(dst_adr);
};
if(file.type == CDFileType::CopyTo) {
return is_lz4 ? enable_lz4(buf_cfg.adr, buf_cfg.sector_count, file.payload.overlay.dst) : disable_lz4(file.payload.copy_to.dst, DisabledCircularBufferSize);
}
else {
return is_lz4 ? enable_lz4(buf_cfg.adr, buf_cfg.sector_count) : disable_lz4(buf_cfg.adr, DisabledCircularBufferSize);
}
}(file, buf_cfg, is_lz4);
switch(file.type) {
case CDFileType::CopyTo:
return FileProcessor::create(data_adr, Nothing());
case CDFileType::SimpleTIM:
return FileProcessor::create(data_adr, file.payload.simple_tim);
case CDFileType::SonyTIM:
return FileProcessor::create(data_adr, file.payload.tim);
case CDFileType::SonyVAG:
return FileProcessor::create(data_adr, file.payload.vag);
default:
return FileProcessor::create_custom(data_adr, static_cast<CDFileType_t>(file.type) - static_cast<CDFileType_t>(CDFileType::Custom), file.payload);
}
};
const auto& cur_job = *this->jobs.files;
const auto& cur_lba = lba[cur_job.rel_lba_idx];
this->file_state = configurate_for(cur_job, buf_cfg, cur_lba.is_lz4());
CD::internal::read_file(cur_lba, SectorBufferAllocator::create(this,
[](void* ctx) -> CD_IO::DataSector* {
CDFileProcessor &self = *reinterpret_cast<CDFileProcessor*>(ctx);
return self.circular_buffer.allocate();
}));
//printf(">>> %i.) CD needs to load LBA: %i -> %i (is LZ4: [%s])\n", cur_job.rel_lba_idx, cur_lba.get_lba(), cur_lba.get_size_in_sectors(), cur_lba.is_lz4() ? "Yes" : "No");
}
bool CDFileProcessor :: process_data() {
while(this->circular_buffer.has_data()) {
ArrayRange<const uint8_t> cur_sector(reinterpret_cast<uint8_t*>(this->circular_buffer.get_next()->data), CD_IO::DataSector::SizeBytes);
// v We can not know if there will be more data or not - but it also doesn't matter much for us
const auto result = this->lz4_decomp.process(cur_sector, false);
this->circular_buffer.pop();
if(result) {
// Process the data in the tmp_area
if(this->file_state.process(result.bytes_ready) == Progress::Error) {
return false;
}
}
else {
return false;
}
}
return true;
}
void CDFileProcessor :: setup(const volatile AutoLBAEntry* lba, JobArray jobs, const BufferConfiguration& buf_cfg) {
this->jobs = jobs;
CDFileProcessor::start_cur_job(const_cast<const AutoLBAEntry*>(lba), buf_cfg);
}
void CDFileProcessor :: shutdown() {
CD::internal::end_read_file();
}
Progress CDFileProcessor :: process() {
const auto cur_state = CD::internal::read_current_state();
CDFileProcessor::process_data();
switch(cur_state) {
case CD::internal::State::Done:
/*
We are done now!
The user decides if he wants the next value
*/
//while(this->file_state.process(0) != Progress::Done);
return Progress::Done;
case CD::internal::State::BufferFull:
/* We processed data and unpause the CD drive */
CD::internal::continue_reading();
return Progress::InProgress;
case CD::internal::State::Reading:
return Progress::InProgress;
case CD::internal::State::Error:
default:
/* Error for real */
return Progress::Error;
}
}
}

View File

@@ -1,10 +1,10 @@
#include <PSX/File/file_processor_helper.hpp>
#include <stdio.hpp>
namespace JabyEngine {
namespace FileProcessor {
State __weak create_custom(const uint32_t* data_adr, const CDFileType_t& file_type, const CDFile::Payload& payload) {
return FileProcessor::create(data_adr, Nothing());
}
}
#include <PSX/File/file_processor_helper.hpp>
#include <stdio.hpp>
namespace JabyEngine {
namespace FileProcessor {
State __weak create_custom(const uint32_t* data_adr, const CDFileType_t& file_type, const CDFile::Payload& payload) {
return FileProcessor::create(data_adr, Nothing());
}
}
}

View File

@@ -1,79 +1,79 @@
#include "../../../internal-include/SPU/spu_internal.hpp"
#include <PSX/Auxiliary/big_endian.hpp>
#include <PSX/Auxiliary/word_helper.hpp>
#include <PSX/File/file_processor_helper.hpp>
#include <PSX/SPU/spu.hpp>
#include <stdio.hpp>
namespace JabyEngine {
namespace FileProcessor {
struct VAGHeader {
char id[4];
uint32_t version;
uint32_t reserved;
uint32_t sample_size;
uint32_t sample_frequency;
uint8_t reserved_2[12];
char name[16];
constexpr uint32_t get_version() const {
return read_be(this->version);
}
constexpr uint32_t get_sample_size() const {
return read_be(this->sample_size);
}
constexpr uint32_t get_sample_frequency() const {
return read_be(this->sample_frequency);
}
};
struct VAGState {
uint32_t voice_id;
size_t words_left;
SPU::SimpleVolume inital_vol;
static constexpr VAGState create(uint32_t voice_id, SPU::SimpleVolume inital_vol) {
return VAGState{.voice_id = voice_id, .words_left = 0, .inital_vol = inital_vol};
}
};
static Progress parse_sample(State::CDDataProcessor& data_proc, VAGState& state) {
const auto [words_to_use, is_last] = Helper::DMA::WordsReady::calculate(data_proc, state.words_left);
const auto words_used = Helper::DMA::send_words<SPU::internal::DMA>(words_to_use, is_last);
state.words_left -= words_used;
data_proc.processed(words_used*sizeof(uint32_t));
return is_last ? Progress::Done : Progress::InProgress;
}
static Progress parse_header(State::CDDataProcessor& data_proc, VAGState& state) {
if(data_proc.data_bytes >= sizeof(VAGHeader)) {
const auto& header = *reinterpret_cast<const VAGHeader*>(data_proc.data_adr);
const auto words = bytes_to_words(header.get_sample_size());
const auto bytes = words_to_bytes(words);
state.words_left = words;
auto sram_adr = SPU::voice[state.voice_id].allocate(SPU_IO_Values::SampleRate::from_HZ(header.get_sample_frequency()), bytes);
SPU::voice[state.voice_id].set_volume(state.inital_vol, state.inital_vol);
data_proc.processed(sizeof(VAGHeader));
SPU::internal::DMA::Receive::prepare();
SPU::internal::DMA::Receive::set_dst(sram_adr);
SPU::internal::DMA::Receive::set_src(reinterpret_cast<uintptr_t>(data_proc.data_adr));
return Helper::exchange_and_execute_process_function(parse_sample, data_proc, state);
}
return Progress::InProgress;
}
State create(const uint32_t* data_adr, const VAG& file) {
return State::from(VAGState::create(file.voice_number, file.inital_stereo_vol), data_adr, parse_header);
}
}
#include "../../../internal-include/SPU/spu_internal.hpp"
#include <PSX/Auxiliary/big_endian.hpp>
#include <PSX/Auxiliary/word_helper.hpp>
#include <PSX/File/file_processor_helper.hpp>
#include <PSX/SPU/spu.hpp>
#include <stdio.hpp>
namespace JabyEngine {
namespace FileProcessor {
struct VAGHeader {
char id[4];
uint32_t version;
uint32_t reserved;
uint32_t sample_size;
uint32_t sample_frequency;
uint8_t reserved_2[12];
char name[16];
constexpr uint32_t get_version() const {
return read_be(this->version);
}
constexpr uint32_t get_sample_size() const {
return read_be(this->sample_size);
}
constexpr uint32_t get_sample_frequency() const {
return read_be(this->sample_frequency);
}
};
struct VAGState {
uint32_t voice_id;
size_t words_left;
SPU::SimpleVolume inital_vol;
static constexpr VAGState create(uint32_t voice_id, SPU::SimpleVolume inital_vol) {
return VAGState{.voice_id = voice_id, .words_left = 0, .inital_vol = inital_vol};
}
};
static Progress parse_sample(State::CDDataProcessor& data_proc, VAGState& state) {
const auto [words_to_use, is_last] = Helper::DMA::WordsReady::calculate(data_proc, state.words_left);
const auto words_used = Helper::DMA::send_words<SPU::internal::DMA>(words_to_use, is_last);
state.words_left -= words_used;
data_proc.processed(words_used*sizeof(uint32_t));
return is_last ? Progress::Done : Progress::InProgress;
}
static Progress parse_header(State::CDDataProcessor& data_proc, VAGState& state) {
if(data_proc.data_bytes >= sizeof(VAGHeader)) {
const auto& header = *reinterpret_cast<const VAGHeader*>(data_proc.data_adr);
const auto words = bytes_to_words(header.get_sample_size());
const auto bytes = words_to_bytes(words);
state.words_left = words;
auto sram_adr = SPU::voice[state.voice_id].allocate(SPU_IO_Values::SampleRate::from_HZ(header.get_sample_frequency()), bytes);
SPU::voice[state.voice_id].set_volume(state.inital_vol, state.inital_vol);
data_proc.processed(sizeof(VAGHeader));
SPU::internal::DMA::Receive::prepare();
SPU::internal::DMA::Receive::set_dst(sram_adr);
SPU::internal::DMA::Receive::set_src(reinterpret_cast<uintptr_t>(data_proc.data_adr));
return Helper::exchange_and_execute_process_function(parse_sample, data_proc, state);
}
return Progress::InProgress;
}
State create(const uint32_t* data_adr, const VAG& file) {
return State::from(VAGState::create(file.voice_number, file.inital_stereo_vol), data_adr, parse_header);
}
}
}

View File

@@ -1,119 +1,119 @@
#include "../../internal-include/GPU/gpu_internal.hpp"
#include <PSX/Timer/frame_timer.hpp>
#include <PSX/System/IOPorts/interrupt_io.hpp>
#include <PSX/System/syscalls.hpp>
namespace JabyEngine {
namespace GPU {
uint8_t Display :: current_id = 0;
namespace internal {
#ifdef __SUPPORT_PS3__
uintptr_t DMA :: MADR = 0;
#endif // __SUPPORT_PS3__
static SysCall::InterruptVerifierResult interrupt_verifier();
static void interrupt_handler(uint32_t);
auto irq_callback = SysCall::InterruptCallback::from(interrupt_verifier, interrupt_handler);
VSyncCallback vsync_callback = nullptr;
static uint8_t vsync_counter = 0;
bool vsync_lock_callback = false;
static SysCall::InterruptVerifierResult interrupt_verifier() {
if(Interrupt::is_irq(Interrupt::VBlank)) {
Interrupt::ack_irq(Interrupt::VBlank);
return SysCall::InterruptVerifierResult::ExecuteHandler;
}
else {
return SysCall::InterruptVerifierResult::SkipHandler;
}
}
static void interrupt_handler(uint32_t) {
vsync_counter++;
MasterTime::value++;
if(vsync_callback && !vsync_lock_callback) {
vsync_callback();
}
//Callback::internal::VSync::execute();
SysCall::ReturnFromException();
}
uint32_t Display :: exchange_buffer_and_display() {
static constexpr uint16_t TexturePageHeight = 256;
const uint16_t draw_area_y = (TexturePageHeight*PublicDisplay::current_id);
GPU::internal::set_draw_area(GPU::PositionU16::create(0, draw_area_y));
PublicDisplay::current_id ^= 1;
GPU_IO::GP1.set_display_area(GPU::PositionU16::create(0, static_cast<uint16_t>((TexturePageHeight*PublicDisplay::current_id))));
return draw_area_y;
}
void wait_vsync(uint8_t syncs) {
volatile auto& vsync_count = reinterpret_cast<volatile uint8_t&>(vsync_counter);
const uint8_t vsync_dst_value = vsync_count + syncs;
while(vsync_count != vsync_dst_value);
}
void render(const uint32_t* data, size_t words) {
wait_ready_for_CMD();
for(size_t n = 0; n < words; n++) {
GPU_IO::GP0.write({data[n]});
}
}
void render_dma(const uint32_t* data) {
// DPCR already enabled
DMA_IO::GPU.wait();
GPU_IO::GP1.set_dma_direction(GPU_IO_Values::GPUSTAT::DMADirection::CPU2GPU);
DMA_IO::GPU.set_adr(reinterpret_cast<uintptr_t>(data));
DMA_IO::GPU.block_ctrl.write(DMA_IO_Values::BCR::SyncMode2::for_gpu_cmd());
wait_ready_for_CMD();
DMA_IO::GPU.channel_ctrl.write(DMA_IO_Values::CHCHR::StartGPULinked());
}
}
void Display :: set_offset(int16_t x, int16_t y) {
// Does not matter really - The original offset is good enough
#ifdef __ADJUST_PS3_SCREEN_OFFSET__
static constexpr auto PS3_CorrectionX = 2;
static constexpr auto PS3_CorrectionY = 1;
#else
static constexpr auto PS3_CorrectionX = 0;
static constexpr auto PS3_CorrectionY = 0;
#endif // __ADJUST_PS3_SCREEN_OFFSET__
x += (internal::Display::DisplayRange.x + Configuration::DisplayDefaultOffset.x);
y += (internal::Display::DisplayRange.y + Configuration::DisplayDefaultOffset.y);
GPU_IO::GP1.set_horizontal_display_range((x << 3), (x + Display::Width + PS3_CorrectionX) << 3);
GPU_IO::GP1.set_vertical_display_range( y, y + Display::Height + PS3_CorrectionY);
}
void set_vsync_callback(VSyncCallback callback) {
internal::vsync_callback = callback;
}
void swap_buffers(bool clear_screen) {
const int16_t draw_offset_y = internal::Display::exchange_buffer_and_display();
internal::set_draw_offset(GPU::PositionI16::create(0, draw_offset_y));
if(clear_screen) {
internal::quick_fill_fast(Color24::Black(), AreaU16::create(0, static_cast<uint16_t>(draw_offset_y), Display::Width, Display::Height));
}
}
uint8_t swap_buffers_vsync(uint8_t syncs, bool clear_screen) {
// Waits for finish FIFO
internal::wait_ready_for_CMD();
internal::wait_vsync(syncs);
swap_buffers(clear_screen);
return Display::current_id;
}
}
#include "../../internal-include/GPU/gpu_internal.hpp"
#include <PSX/Timer/frame_timer.hpp>
#include <PSX/System/IOPorts/interrupt_io.hpp>
#include <PSX/System/syscalls.hpp>
namespace JabyEngine {
namespace GPU {
uint8_t Display :: current_id = 0;
namespace internal {
#ifdef __SUPPORT_PS3__
uintptr_t DMA :: MADR = 0;
#endif // __SUPPORT_PS3__
static SysCall::InterruptVerifierResult interrupt_verifier();
static void interrupt_handler(uint32_t);
auto irq_callback = SysCall::InterruptCallback::from(interrupt_verifier, interrupt_handler);
VSyncCallback vsync_callback = nullptr;
static uint8_t vsync_counter = 0;
bool vsync_lock_callback = false;
static SysCall::InterruptVerifierResult interrupt_verifier() {
if(Interrupt::is_irq(Interrupt::VBlank)) {
Interrupt::ack_irq(Interrupt::VBlank);
return SysCall::InterruptVerifierResult::ExecuteHandler;
}
else {
return SysCall::InterruptVerifierResult::SkipHandler;
}
}
static void interrupt_handler(uint32_t) {
vsync_counter++;
MasterTime::value++;
if(vsync_callback && !vsync_lock_callback) {
vsync_callback();
}
//Callback::internal::VSync::execute();
SysCall::ReturnFromException();
}
uint32_t Display :: exchange_buffer_and_display() {
static constexpr uint16_t TexturePageHeight = 256;
const uint16_t draw_area_y = (TexturePageHeight*PublicDisplay::current_id);
GPU::internal::set_draw_area(GPU::PositionU16::create(0, draw_area_y));
PublicDisplay::current_id ^= 1;
GPU_IO::GP1.set_display_area(GPU::PositionU16::create(0, static_cast<uint16_t>((TexturePageHeight*PublicDisplay::current_id))));
return draw_area_y;
}
void wait_vsync(uint8_t syncs) {
volatile auto& vsync_count = reinterpret_cast<volatile uint8_t&>(vsync_counter);
const uint8_t vsync_dst_value = vsync_count + syncs;
while(vsync_count != vsync_dst_value);
}
void render(const uint32_t* data, size_t words) {
wait_ready_for_CMD();
for(size_t n = 0; n < words; n++) {
GPU_IO::GP0.write({data[n]});
}
}
void render_dma(const uint32_t* data) {
// DPCR already enabled
DMA_IO::GPU.wait();
GPU_IO::GP1.set_dma_direction(GPU_IO_Values::GPUSTAT::DMADirection::CPU2GPU);
DMA_IO::GPU.set_adr(reinterpret_cast<uintptr_t>(data));
DMA_IO::GPU.block_ctrl.write(DMA_IO_Values::BCR::SyncMode2::for_gpu_cmd());
wait_ready_for_CMD();
DMA_IO::GPU.channel_ctrl.write(DMA_IO_Values::CHCHR::StartGPULinked());
}
}
void Display :: set_offset(int16_t x, int16_t y) {
// Does not matter really - The original offset is good enough
#ifdef __ADJUST_PS3_SCREEN_OFFSET__
static constexpr auto PS3_CorrectionX = 2;
static constexpr auto PS3_CorrectionY = 1;
#else
static constexpr auto PS3_CorrectionX = 0;
static constexpr auto PS3_CorrectionY = 0;
#endif // __ADJUST_PS3_SCREEN_OFFSET__
x += (internal::Display::DisplayRange.x + Configuration::DisplayDefaultOffset.x);
y += (internal::Display::DisplayRange.y + Configuration::DisplayDefaultOffset.y);
GPU_IO::GP1.set_horizontal_display_range((x << 3), (x + Display::Width + PS3_CorrectionX) << 3);
GPU_IO::GP1.set_vertical_display_range( y, y + Display::Height + PS3_CorrectionY);
}
void set_vsync_callback(VSyncCallback callback) {
internal::vsync_callback = callback;
}
void swap_buffers(bool clear_screen) {
const int16_t draw_offset_y = internal::Display::exchange_buffer_and_display();
internal::set_draw_offset(GPU::PositionI16::create(0, draw_offset_y));
if(clear_screen) {
internal::quick_fill_fast(Color24::Black(), AreaU16::create(0, static_cast<uint16_t>(draw_offset_y), Display::Width, Display::Height));
}
}
uint8_t swap_buffers_vsync(uint8_t syncs, bool clear_screen) {
// Waits for finish FIFO
internal::wait_ready_for_CMD();
internal::wait_vsync(syncs);
swap_buffers(clear_screen);
return Display::current_id;
}
}
}

View File

@@ -1,129 +1,129 @@
#include <PSX/GTE/gte.hpp>
static int32_t hisin(int32_t value) {
static constexpr int32_t qN = 13;
static constexpr int32_t qA = 12;
static constexpr int32_t B = 19900;
static constexpr int32_t C = 3516;
const auto c = value << (30 - qN); // Semi-circle info into carry.
value -= 1<<qN; // sine -> cosine calc
value = value << (31 - qN); // Mask with PI
value = value >> (31 - qN); // Note: SIGNED shift! (to qN)
value = value*value >> (2*qN - 14); // x=x^2 To Q14
auto result = B - (value*C >> 14); // B - x^2*C
result = (1 << qA) - (value*result >> 16); // A - x^2*(B-x^2*C)
return c >= 0 ? result : -result;
}
gte_float sin(deg_t value) {
return gte_float{.raw = hisin(value.raw)};
}
gte_float cos(deg_t value) {
return gte_float{.raw = hisin(value.raw + (deg_t::full_circle/4))};
}
namespace JabyEngine {
namespace GTE {
namespace MatrixHelper {
struct SinCosPair {
int16_t sin;
int16_t cos;
static SinCosPair create_for(deg_t value) {
return SinCosPair{
.sin = static_cast<int16_t>(::sin(value)),
.cos = static_cast<int16_t>(::cos(value)),
};
}
};
}
static MATRIX Stack[StackSize];
static MATRIX* FreeStackEntry = Stack;
ROTMATRIX& multiply_matrix(const ROTMATRIX& m0, const ROTMATRIX& m1, ROTMATRIX& result) {
set_rot_matrix(m0);
JabyEngine::GTE::ldclmv(m1, 0);
JabyEngine::GTE::rtir();
JabyEngine::GTE::stclmv(result, 0);
JabyEngine::GTE::ldclmv(m1, 1);
JabyEngine::GTE::rtir();
JabyEngine::GTE::stclmv(result, 1);
JabyEngine::GTE::ldclmv(m1, 2);
JabyEngine::GTE::rtir();
JabyEngine::GTE::stclmv(result, 2);
return result;
}
void set_matrix(const MATRIX& matrix) {
set_rot_matrix(matrix.rotation);
set_trans_vector(matrix.transfer);
}
MATRIX get_matrix() {
MATRIX matrix;
get_rot_matrix(matrix.rotation);
get_trans_vector(matrix.transfer);
return matrix;
}
void push_matrix() {
*FreeStackEntry = get_matrix();
FreeStackEntry++;
}
void push_matrix_and_set(const MATRIX& matrix) {
push_matrix();
set_matrix(matrix);
}
void pop_matrix() {
FreeStackEntry--;
set_matrix(*FreeStackEntry);
}
MATRIX get_and_pop_matrix() {
const auto matrix = get_matrix();
pop_matrix();
return matrix;
}
ROTMATRIX ROTMATRIX :: rotated(deg_t x, deg_t y, deg_t z) {
using namespace MatrixHelper;
const auto sincos_x = SinCosPair::create_for(x);
const auto sincos_y = SinCosPair::create_for(y);
const auto sincos_z = SinCosPair::create_for(z);
auto rotX = ROTMATRIX::identity();
rotX.matrix[1][1] = sincos_x.cos; rotX.matrix[1][2] = -sincos_x.sin;
rotX.matrix[2][1] = sincos_x.sin; rotX.matrix[2][2] = sincos_x.cos;
auto rotY = ROTMATRIX::identity();
rotY.matrix[0][0] = sincos_y.cos; rotY.matrix[0][2] = sincos_y.sin;
rotY.matrix[2][0] = -sincos_y.sin; rotY.matrix[2][2] = sincos_y.cos;
auto rotZ = ROTMATRIX::identity();
rotZ.matrix[0][0] = sincos_z.cos; rotZ.matrix[0][1] = -sincos_z.sin;
rotZ.matrix[1][0] = sincos_z.sin; rotZ.matrix[1][1] = sincos_z.cos;
push_matrix();
multiply_matrix(rotX, rotY, rotX);
multiply_matrix(rotX, rotZ, rotX);
pop_matrix();
return rotX;
}
}
#include <PSX/GTE/gte.hpp>
static int32_t hisin(int32_t value) {
static constexpr int32_t qN = 13;
static constexpr int32_t qA = 12;
static constexpr int32_t B = 19900;
static constexpr int32_t C = 3516;
const auto c = value << (30 - qN); // Semi-circle info into carry.
value -= 1<<qN; // sine -> cosine calc
value = value << (31 - qN); // Mask with PI
value = value >> (31 - qN); // Note: SIGNED shift! (to qN)
value = value*value >> (2*qN - 14); // x=x^2 To Q14
auto result = B - (value*C >> 14); // B - x^2*C
result = (1 << qA) - (value*result >> 16); // A - x^2*(B-x^2*C)
return c >= 0 ? result : -result;
}
gte_float sin(deg_t value) {
return gte_float{.raw = hisin(value.raw)};
}
gte_float cos(deg_t value) {
return gte_float{.raw = hisin(value.raw + (deg_t::full_circle/4))};
}
namespace JabyEngine {
namespace GTE {
namespace MatrixHelper {
struct SinCosPair {
int16_t sin;
int16_t cos;
static SinCosPair create_for(deg_t value) {
return SinCosPair{
.sin = static_cast<int16_t>(::sin(value)),
.cos = static_cast<int16_t>(::cos(value)),
};
}
};
}
static MATRIX Stack[StackSize];
static MATRIX* FreeStackEntry = Stack;
ROTMATRIX& multiply_matrix(const ROTMATRIX& m0, const ROTMATRIX& m1, ROTMATRIX& result) {
set_rot_matrix(m0);
JabyEngine::GTE::ldclmv(m1, 0);
JabyEngine::GTE::rtir();
JabyEngine::GTE::stclmv(result, 0);
JabyEngine::GTE::ldclmv(m1, 1);
JabyEngine::GTE::rtir();
JabyEngine::GTE::stclmv(result, 1);
JabyEngine::GTE::ldclmv(m1, 2);
JabyEngine::GTE::rtir();
JabyEngine::GTE::stclmv(result, 2);
return result;
}
void set_matrix(const MATRIX& matrix) {
set_rot_matrix(matrix.rotation);
set_trans_vector(matrix.transfer);
}
MATRIX get_matrix() {
MATRIX matrix;
get_rot_matrix(matrix.rotation);
get_trans_vector(matrix.transfer);
return matrix;
}
void push_matrix() {
*FreeStackEntry = get_matrix();
FreeStackEntry++;
}
void push_matrix_and_set(const MATRIX& matrix) {
push_matrix();
set_matrix(matrix);
}
void pop_matrix() {
FreeStackEntry--;
set_matrix(*FreeStackEntry);
}
MATRIX get_and_pop_matrix() {
const auto matrix = get_matrix();
pop_matrix();
return matrix;
}
ROTMATRIX ROTMATRIX :: rotated(deg_t x, deg_t y, deg_t z) {
using namespace MatrixHelper;
const auto sincos_x = SinCosPair::create_for(x);
const auto sincos_y = SinCosPair::create_for(y);
const auto sincos_z = SinCosPair::create_for(z);
auto rotX = ROTMATRIX::identity();
rotX.matrix[1][1] = sincos_x.cos; rotX.matrix[1][2] = -sincos_x.sin;
rotX.matrix[2][1] = sincos_x.sin; rotX.matrix[2][2] = sincos_x.cos;
auto rotY = ROTMATRIX::identity();
rotY.matrix[0][0] = sincos_y.cos; rotY.matrix[0][2] = sincos_y.sin;
rotY.matrix[2][0] = -sincos_y.sin; rotY.matrix[2][2] = sincos_y.cos;
auto rotZ = ROTMATRIX::identity();
rotZ.matrix[0][0] = sincos_z.cos; rotZ.matrix[0][1] = -sincos_z.sin;
rotZ.matrix[1][0] = sincos_z.sin; rotZ.matrix[1][1] = sincos_z.cos;
push_matrix();
multiply_matrix(rotX, rotY, rotX);
multiply_matrix(rotX, rotZ, rotX);
pop_matrix();
return rotX;
}
}
}

View File

@@ -1,136 +1,136 @@
#include "../../internal-include/periphery_internal.hpp"
#include <PSX/Periphery/periphery.hpp>
#include <PSX/System/syscalls.hpp>
namespace JabyEngine {
namespace Periphery {
// Controllers are checked every alternating frame
static uint8_t cur_controller_port = 0;
RawController controller[PortCount][DeviceCount];
struct ControllerHelper {
static bool is_config(const RawController &cont) {
return (static_cast<uint8_t>(cont.header.state) & 0xF);
}
static void advance_config(RawController &cont) {
cont.header.state = static_cast<RawController::State>((static_cast<uint32_t>(cont.header.state) << 1));
}
static uint8_t* raw_device_data(RawController &cont) {
return reinterpret_cast<uint8_t*>(&cont.button.currentState);
}
};
static void set_config_command(RawController::State state, uint8_t (&header)[3], uint8_t (&data)[6]) {
static constexpr uint32_t CMDIDX = 1;
switch(state) {
case RawController::State::EnterConfigMode:
static constexpr uint8_t EnterCFGModeCMD = 0x1;
header[CMDIDX] = 0x43;
data[0] = EnterCFGModeCMD;
break;
case RawController::State::LockAnalog:
static constexpr uint8_t valID = 0;
static constexpr uint8_t selID = 1;
header[CMDIDX] = 0x44;
data[valID] = static_cast<uint8_t>(LED::State::On);
data[selID] = static_cast<uint8_t>(LED::Lock::On);
break;
case RawController::State::UnlockRumble:
header[CMDIDX] = 0x4D;
data[1] = 0x1;
for(int32_t n = 2; n < 6; n++) {
data[n] = 0xFF;
}
break;
case RawController::State::ExitConfigMode:
header[CMDIDX] = 0x43;
break;
}
}
static size_t send_data(const uint8_t* header, uint8_t* headerResponse, const uint8_t* data, uint8_t* response) {
const uint8_t *src = header;
uint8_t *dst = headerResponse;
size_t size = 3;
for(size_t n = 0; n < size; n++) {
Periphery::send_byte(*src);
Periphery::acknowledge();
*dst = Periphery::read_byte();
if(n == 2) {
const uint8_t id = headerResponse[1];
size += (id == 0xFF) ? 0 : ((id & 0xF) << 1);
src = data;
dst = response;
}
else {
src++;
dst++;
}
busy_loop(15);
}
return size;
}
void query_controller() {
static constexpr auto TypeIDX = 1;
SysCall::EnterCriticalSection();
Periphery::connect_to(cur_controller_port);
for(uint32_t id = 0; id < Periphery::DeviceCount; id++) {
auto &cur_controller = controller[cur_controller_port][id];
uint8_t header[] = {static_cast<uint8_t>((id + 1)), 0x42, 0x0};
uint8_t data[] = {cur_controller.header.rumble0, cur_controller.header.rumble1, 0x0, 0x0, 0x0, 0x0};
// Can this move to the if??
set_config_command(cur_controller.header.state, header, data);
if(ControllerHelper::is_config(cur_controller)) {
send_data(header, header, data, data);
ControllerHelper::advance_config(cur_controller);
}
else {
cur_controller.button.exchange_state();
send_data(header, header, data, ControllerHelper::raw_device_data(cur_controller));
const bool isValidController = (header[TypeIDX] != 0xFF);
if(header[TypeIDX] != cur_controller.header.type) {
cur_controller.header.type = header[TypeIDX];
cur_controller.header.state = isValidController ? RawController::State::EnterConfigMode : RawController::State::Disconnected;
/*if(!isValidController)
{
printf("Disconnected!\n");
}
else
{
printf("ID: 0x%02X 0x%04X\n", header[TypeIDX], contData.button);
}*/
}
}
}
Periphery::close_connection();
if(Configuration::Periphery::include_portB()) {
cur_controller_port ^= 0x1;
}
SysCall::ExitCriticalSection();
}
}
#include "../../internal-include/periphery_internal.hpp"
#include <PSX/Periphery/periphery.hpp>
#include <PSX/System/syscalls.hpp>
namespace JabyEngine {
namespace Periphery {
// Controllers are checked every alternating frame
static uint8_t cur_controller_port = 0;
RawController controller[PortCount][DeviceCount];
struct ControllerHelper {
static bool is_config(const RawController &cont) {
return (static_cast<uint8_t>(cont.header.state) & 0xF);
}
static void advance_config(RawController &cont) {
cont.header.state = static_cast<RawController::State>((static_cast<uint32_t>(cont.header.state) << 1));
}
static uint8_t* raw_device_data(RawController &cont) {
return reinterpret_cast<uint8_t*>(&cont.button.currentState);
}
};
static void set_config_command(RawController::State state, uint8_t (&header)[3], uint8_t (&data)[6]) {
static constexpr uint32_t CMDIDX = 1;
switch(state) {
case RawController::State::EnterConfigMode:
static constexpr uint8_t EnterCFGModeCMD = 0x1;
header[CMDIDX] = 0x43;
data[0] = EnterCFGModeCMD;
break;
case RawController::State::LockAnalog:
static constexpr uint8_t valID = 0;
static constexpr uint8_t selID = 1;
header[CMDIDX] = 0x44;
data[valID] = static_cast<uint8_t>(LED::State::On);
data[selID] = static_cast<uint8_t>(LED::Lock::On);
break;
case RawController::State::UnlockRumble:
header[CMDIDX] = 0x4D;
data[1] = 0x1;
for(int32_t n = 2; n < 6; n++) {
data[n] = 0xFF;
}
break;
case RawController::State::ExitConfigMode:
header[CMDIDX] = 0x43;
break;
}
}
static size_t send_data(const uint8_t* header, uint8_t* headerResponse, const uint8_t* data, uint8_t* response) {
const uint8_t *src = header;
uint8_t *dst = headerResponse;
size_t size = 3;
for(size_t n = 0; n < size; n++) {
Periphery::send_byte(*src);
Periphery::acknowledge();
*dst = Periphery::read_byte();
if(n == 2) {
const uint8_t id = headerResponse[1];
size += (id == 0xFF) ? 0 : ((id & 0xF) << 1);
src = data;
dst = response;
}
else {
src++;
dst++;
}
busy_loop(15);
}
return size;
}
void query_controller() {
static constexpr auto TypeIDX = 1;
SysCall::EnterCriticalSection();
Periphery::connect_to(cur_controller_port);
for(uint32_t id = 0; id < Periphery::DeviceCount; id++) {
auto &cur_controller = controller[cur_controller_port][id];
uint8_t header[] = {static_cast<uint8_t>((id + 1)), 0x42, 0x0};
uint8_t data[] = {cur_controller.header.rumble0, cur_controller.header.rumble1, 0x0, 0x0, 0x0, 0x0};
// Can this move to the if??
set_config_command(cur_controller.header.state, header, data);
if(ControllerHelper::is_config(cur_controller)) {
send_data(header, header, data, data);
ControllerHelper::advance_config(cur_controller);
}
else {
cur_controller.button.exchange_state();
send_data(header, header, data, ControllerHelper::raw_device_data(cur_controller));
const bool isValidController = (header[TypeIDX] != 0xFF);
if(header[TypeIDX] != cur_controller.header.type) {
cur_controller.header.type = header[TypeIDX];
cur_controller.header.state = isValidController ? RawController::State::EnterConfigMode : RawController::State::Disconnected;
/*if(!isValidController)
{
printf("Disconnected!\n");
}
else
{
printf("ID: 0x%02X 0x%04X\n", header[TypeIDX], contData.button);
}*/
}
}
}
Periphery::close_connection();
if(Configuration::Periphery::include_portB()) {
cur_controller_port ^= 0x1;
}
SysCall::ExitCriticalSection();
}
}
}

View File

@@ -1,31 +1,31 @@
#include "../../internal-include/SPU/spu_internal.hpp"
#include "../../internal-include/SPU/spu_mmu.hpp"
#include <PSX/System/IOPorts/spu_io.hpp>
#include <PSX/SPU/spu.hpp>
#include <stddef.hpp>
#include <stdio.hpp>
namespace JabyEngine {
namespace SPU {
SRAMAdr Voice :: allocate(size_t size) {
Voice::stop();
const auto voice_id = Voice::get_id();
const auto adr = SRAMAdr{static_cast<SRAMAdr::UnderlyingType>(reinterpret_cast<uintptr_t>(SPU_MMU::allocate(voice_id, size)))};
SPU_IO::Voice[voice_id].adr.write(adr);
return adr;
}
SRAMAdr Voice :: allocate(SPU_IO_Values::SampleRate frequency, size_t size) {
const auto result = Voice::allocate(size);
Voice::set_sample_rate(frequency);
return result;
}
void Voice :: deallocate() {
Voice::stop();
SPU_MMU::deallocate(Voice::get_id());
}
}
#include "../../internal-include/SPU/spu_internal.hpp"
#include "../../internal-include/SPU/spu_mmu.hpp"
#include <PSX/System/IOPorts/spu_io.hpp>
#include <PSX/SPU/spu.hpp>
#include <stddef.hpp>
#include <stdio.hpp>
namespace JabyEngine {
namespace SPU {
SRAMAdr Voice :: allocate(size_t size) {
Voice::stop();
const auto voice_id = Voice::get_id();
const auto adr = SRAMAdr{static_cast<SRAMAdr::UnderlyingType>(reinterpret_cast<uintptr_t>(SPU_MMU::allocate(voice_id, size)))};
SPU_IO::Voice[voice_id].adr.write(adr);
return adr;
}
SRAMAdr Voice :: allocate(SPU_IO_Values::SampleRate frequency, size_t size) {
const auto result = Voice::allocate(size);
Voice::set_sample_rate(frequency);
return result;
}
void Voice :: deallocate() {
Voice::stop();
SPU_MMU::deallocate(Voice::get_id());
}
}
}

View File

@@ -1,136 +1,136 @@
#include "../../internal-include/SPU/spu_mmu.hpp"
#include <PSX/System/IOPorts/spu_io.hpp>
#include <PSX/Auxiliary/math_helper.hpp>
#include <PSX/SPU/spu.hpp>
#include <PSX/jabyengine_config.hpp>
#include <stddef.hpp>
#ifdef __DEBUG_SPU_MMU__
#include <stdio.hpp>
#endif // __DEBUG_SPU_MMU__
namespace JabyEngine {
namespace SPU_MMU {
namespace SPU_MemoryMap = SPU_IO_Values::MemoryMap;
struct SPUMemory {
const uint8_t* adr;
size_t size;
static SPUMemory create(size_t size) {
return SPUMemory{.adr = reinterpret_cast<const uint8_t*>(SPU_MemoryMap::ADPCM), .size = size};
}
constexpr void clear() {
this->adr = nullptr;
this->size = 0;
}
constexpr const uint8_t* get_end_adr() const {
return (this->adr + this->size);
}
constexpr bool is_free() const {
return this->adr == nullptr;
}
constexpr bool intersects(const SPUMemory& other) const {
const auto* min = max_of(this->adr, other.adr);
const auto* max = min_of(this->get_end_adr(), other.get_end_adr());
return min < max;
}
};
struct AllocatedVoice {
SPUMemory memory;
AllocatedVoice* next_entry;
};
struct VoiceManager {
struct Iterator {
AllocatedVoice* *prev_voice;
AllocatedVoice* current_voice;
void next() {
this->prev_voice = &this->current_voice->next_entry;
this->current_voice = this->current_voice->next_entry;
}
bool has_next() const {
return this->current_voice;
}
operator bool() const {
return Iterator::has_next();
}
};
AllocatedVoice allocated_voice_buffer[SPU_IO::VoiceCount + SPU_IO::ReverbCount] = {0};
AllocatedVoice* first_allocated_voice = nullptr;
Iterator iterator() {
return Iterator{.prev_voice = &this->first_allocated_voice, .current_voice = this->first_allocated_voice};
}
AllocatedVoice& get_voice(uint8_t id) {
return this->allocated_voice_buffer[id];
}
};
static VoiceManager voice_mgr;
static const uint8_t* reverb_adr = reinterpret_cast<const uint8_t*>(SPU_MemoryMap::End);
// ^ change this to allocate reverb
using MemoryFoundCallback = const uint8_t* (AllocatedVoice& new_entry, AllocatedVoice* &prev_entry, AllocatedVoice* next_entry);
static const uint8_t* verify_and_add(AllocatedVoice& new_entry, AllocatedVoice* &prev_entry, AllocatedVoice* next_entry) {
if(new_entry.memory.adr >= reverb_adr) {
return nullptr;
}
prev_entry = &new_entry;
new_entry.next_entry = next_entry;
return new_entry.memory.adr;
}
static const uint8_t* find_first_fit(AllocatedVoice &new_entry, MemoryFoundCallback memory_found) {
auto iterator = voice_mgr.iterator();
while(iterator) {
if(!iterator.current_voice->memory.intersects(new_entry.memory)) {
break;
}
new_entry.memory.adr = iterator.current_voice->memory.get_end_adr();
iterator.next();
}
return memory_found(new_entry, *iterator.prev_voice, iterator.current_voice);
}
const uint8_t* allocate(uint8_t voice, size_t size) {
auto& voice_entry = voice_mgr.get_voice(voice);
if(!voice_entry.memory.is_free()) {
deallocate(voice);
}
voice_entry.memory = SPUMemory::create(size);
const auto* mem_adr = find_first_fit(voice_entry, verify_and_add);
#ifdef __DEBUG_SPU_MMU__
printf("SPU: Allocated %i @0x%p to 0x%p (%i bytes)\n", voice, mem_adr, (mem_adr + size), size);
#endif // __DEBUG_SPU_MMU__
return mem_adr;
}
void deallocate(uint8_t voice) {
auto* voice_adr = &voice_mgr.get_voice(voice);
auto iterator = voice_mgr.iterator();
voice_adr->memory.clear();
while(iterator) {
if(iterator.current_voice == voice_adr) {
*iterator.prev_voice = voice_adr->next_entry;
break;
}
iterator.next();
}
}
}
#include "../../internal-include/SPU/spu_mmu.hpp"
#include <PSX/System/IOPorts/spu_io.hpp>
#include <PSX/Auxiliary/math_helper.hpp>
#include <PSX/SPU/spu.hpp>
#include <PSX/jabyengine_config.hpp>
#include <stddef.hpp>
#ifdef __DEBUG_SPU_MMU__
#include <stdio.hpp>
#endif // __DEBUG_SPU_MMU__
namespace JabyEngine {
namespace SPU_MMU {
namespace SPU_MemoryMap = SPU_IO_Values::MemoryMap;
struct SPUMemory {
const uint8_t* adr;
size_t size;
static SPUMemory create(size_t size) {
return SPUMemory{.adr = reinterpret_cast<const uint8_t*>(SPU_MemoryMap::ADPCM), .size = size};
}
constexpr void clear() {
this->adr = nullptr;
this->size = 0;
}
constexpr const uint8_t* get_end_adr() const {
return (this->adr + this->size);
}
constexpr bool is_free() const {
return this->adr == nullptr;
}
constexpr bool intersects(const SPUMemory& other) const {
const auto* min = max_of(this->adr, other.adr);
const auto* max = min_of(this->get_end_adr(), other.get_end_adr());
return min < max;
}
};
struct AllocatedVoice {
SPUMemory memory;
AllocatedVoice* next_entry;
};
struct VoiceManager {
struct Iterator {
AllocatedVoice* *prev_voice;
AllocatedVoice* current_voice;
void next() {
this->prev_voice = &this->current_voice->next_entry;
this->current_voice = this->current_voice->next_entry;
}
bool has_next() const {
return this->current_voice;
}
operator bool() const {
return Iterator::has_next();
}
};
AllocatedVoice allocated_voice_buffer[SPU_IO::VoiceCount + SPU_IO::ReverbCount] = {0};
AllocatedVoice* first_allocated_voice = nullptr;
Iterator iterator() {
return Iterator{.prev_voice = &this->first_allocated_voice, .current_voice = this->first_allocated_voice};
}
AllocatedVoice& get_voice(uint8_t id) {
return this->allocated_voice_buffer[id];
}
};
static VoiceManager voice_mgr;
static const uint8_t* reverb_adr = reinterpret_cast<const uint8_t*>(SPU_MemoryMap::End);
// ^ change this to allocate reverb
using MemoryFoundCallback = const uint8_t* (AllocatedVoice& new_entry, AllocatedVoice* &prev_entry, AllocatedVoice* next_entry);
static const uint8_t* verify_and_add(AllocatedVoice& new_entry, AllocatedVoice* &prev_entry, AllocatedVoice* next_entry) {
if(new_entry.memory.adr >= reverb_adr) {
return nullptr;
}
prev_entry = &new_entry;
new_entry.next_entry = next_entry;
return new_entry.memory.adr;
}
static const uint8_t* find_first_fit(AllocatedVoice &new_entry, MemoryFoundCallback memory_found) {
auto iterator = voice_mgr.iterator();
while(iterator) {
if(!iterator.current_voice->memory.intersects(new_entry.memory)) {
break;
}
new_entry.memory.adr = iterator.current_voice->memory.get_end_adr();
iterator.next();
}
return memory_found(new_entry, *iterator.prev_voice, iterator.current_voice);
}
const uint8_t* allocate(uint8_t voice, size_t size) {
auto& voice_entry = voice_mgr.get_voice(voice);
if(!voice_entry.memory.is_free()) {
deallocate(voice);
}
voice_entry.memory = SPUMemory::create(size);
const auto* mem_adr = find_first_fit(voice_entry, verify_and_add);
#ifdef __DEBUG_SPU_MMU__
printf("SPU: Allocated %i @0x%p to 0x%p (%i bytes)\n", voice, mem_adr, (mem_adr + size), size);
#endif // __DEBUG_SPU_MMU__
return mem_adr;
}
void deallocate(uint8_t voice) {
auto* voice_adr = &voice_mgr.get_voice(voice);
auto iterator = voice_mgr.iterator();
voice_adr->memory.clear();
while(iterator) {
if(iterator.current_voice == voice_adr) {
*iterator.prev_voice = voice_adr->next_entry;
break;
}
iterator.next();
}
}
}
}

View File

@@ -1,44 +1,44 @@
#include "../../internal-include/System/callbacks_internal.hpp"
#include "../../internal-include/CD/cd_internal.hpp"
#include <PSX/System/callbacks.hpp>
namespace JabyEngine {
namespace Callback {
// Marked deprecated currently
/*using Function = VSyncCallback::Function;
Function VSyncCallback :: callback = nullptr;*/
namespace internal {
namespace VSync {
SysCall::ThreadHandle thread_handle = 0;
uint32_t stack[StackSize] = {0};
void routine() {
while(true) {
// Marked deprecated currently
/*if(VSyncCallback::callback) {
VSyncCallback::callback();
}*/
SysCall::ChangeThread(MainThread::Handle);
}
}
}
namespace CD {
namespace CD_IRQ = JabyEngine::CD::internal::IRQ;
SysCall::ThreadHandle thread_handle = 0;
uint32_t stack[StackSize];
void routine(uint32_t irq) {
while(true) {
const auto old_status = CD_IO::IndexStatus.read();
CD_IRQ::process(irq);
CD_IO::IndexStatus.write(old_status);
irq = Callback::internal::CD::resume();
}
}
}
}
}
#include "../../internal-include/System/callbacks_internal.hpp"
#include "../../internal-include/CD/cd_internal.hpp"
#include <PSX/System/callbacks.hpp>
namespace JabyEngine {
namespace Callback {
// Marked deprecated currently
/*using Function = VSyncCallback::Function;
Function VSyncCallback :: callback = nullptr;*/
namespace internal {
namespace VSync {
SysCall::ThreadHandle thread_handle = 0;
uint32_t stack[StackSize] = {0};
void routine() {
while(true) {
// Marked deprecated currently
/*if(VSyncCallback::callback) {
VSyncCallback::callback();
}*/
SysCall::ChangeThread(MainThread::Handle);
}
}
}
namespace CD {
namespace CD_IRQ = JabyEngine::CD::internal::IRQ;
SysCall::ThreadHandle thread_handle = 0;
uint32_t stack[StackSize];
void routine(uint32_t irq) {
while(true) {
const auto old_status = CD_IO::IndexStatus.read();
CD_IRQ::process(irq);
CD_IO::IndexStatus.write(old_status);
irq = Callback::internal::CD::resume();
}
}
}
}
}
}

View File

@@ -1,63 +1,63 @@
#include <string.hpp>
int strncmp(const char* s1, const char* s2, size_t n) {
if(n == 0) {
return 0;
}
do {
if(*s1 != *s2++) {
return (*(unsigned char *)s1 - *(unsigned char *)--s2);
}
if(*s1++ == 0) {
break;
}
} while(--n != 0);
return 0;
}
size_t strlen(const char *str) {
const char* end = str;
for(; *end; ++end);
return(end - str);
}
template<typename T>
static void* core_memset(T* dst, int val, size_t &len) {
while(len >= sizeof(T)) {
*dst++ = val;
len -= sizeof(T);
}
return dst;
}
static void* simple_memset(void* dest, int val, size_t len) {
core_memset(static_cast<uint8_t*>(dest), val, len);
return dest;
}
static void* cplx_memset(void* dst, int val, size_t len) {
void*const org_dst = dst;
if(reinterpret_cast<uintptr_t>(dst) & 0x2 == 0) {
dst = core_memset(static_cast<uint32_t*>(dst), val, len);
}
if(reinterpret_cast<uintptr_t>(dst) & 0x1 == 0) {
dst = core_memset(static_cast<uint16_t*>(dst), val, len);
}
if(len > 0) {
simple_memset(dst, val, len);
}
return org_dst;
}
extern "C" {
void* memset(void* dest, int val, size_t len) {
return simple_memset(dest, val, len);
}
#include <string.hpp>
int strncmp(const char* s1, const char* s2, size_t n) {
if(n == 0) {
return 0;
}
do {
if(*s1 != *s2++) {
return (*(unsigned char *)s1 - *(unsigned char *)--s2);
}
if(*s1++ == 0) {
break;
}
} while(--n != 0);
return 0;
}
size_t strlen(const char *str) {
const char* end = str;
for(; *end; ++end);
return(end - str);
}
template<typename T>
static void* core_memset(T* dst, int val, size_t &len) {
while(len >= sizeof(T)) {
*dst++ = val;
len -= sizeof(T);
}
return dst;
}
static void* simple_memset(void* dest, int val, size_t len) {
core_memset(static_cast<uint8_t*>(dest), val, len);
return dest;
}
static void* cplx_memset(void* dst, int val, size_t len) {
void*const org_dst = dst;
if(reinterpret_cast<uintptr_t>(dst) & 0x2 == 0) {
dst = core_memset(static_cast<uint32_t*>(dst), val, len);
}
if(reinterpret_cast<uintptr_t>(dst) & 0x1 == 0) {
dst = core_memset(static_cast<uint16_t*>(dst), val, len);
}
if(len > 0) {
simple_memset(dst, val, len);
}
return org_dst;
}
extern "C" {
void* memset(void* dest, int val, size_t len) {
return simple_memset(dest, val, len);
}
}

View File

@@ -1,8 +1,8 @@
#include <PSX/Auxiliary/math_helper.hpp>
#include <PSX/System/syscalls.hpp>
namespace JabyEngine {
namespace BIOS {
const Version version = {0};
}
#include <PSX/Auxiliary/math_helper.hpp>
#include <PSX/System/syscalls.hpp>
namespace JabyEngine {
namespace BIOS {
const Version version = {0};
}
}

View File

@@ -1,27 +1,27 @@
#include <PSX/System/IOPorts/timer_io.hpp>
#include <PSX/System/syscalls.hpp>
#include <PSX/Timer/high_res_timer.hpp>
namespace JabyEngine {
volatile uint16_t HighResTime :: global_counter_10ms = 0;
namespace Timer {
static SysCall::InterruptVerifierResult interrupt_verifier() {
if(Interrupt::is_irq(Interrupt::Timer2)) {
Interrupt::ack_irq(Interrupt::Timer2);
return SysCall::InterruptVerifierResult::ExecuteHandler;
}
else {
return SysCall::InterruptVerifierResult::SkipHandler;
}
}
static void interrupt_handler(uint32_t) {
HighResTime::global_counter_10ms = HighResTime::global_counter_10ms + 1;
SysCall::ReturnFromException();
}
auto irq_callback = SysCall::InterruptCallback::from(interrupt_verifier, interrupt_handler);
}
#include <PSX/System/IOPorts/timer_io.hpp>
#include <PSX/System/syscalls.hpp>
#include <PSX/Timer/high_res_timer.hpp>
namespace JabyEngine {
volatile uint16_t HighResTime :: global_counter_10ms = 0;
namespace Timer {
static SysCall::InterruptVerifierResult interrupt_verifier() {
if(Interrupt::is_irq(Interrupt::Timer2)) {
Interrupt::ack_irq(Interrupt::Timer2);
return SysCall::InterruptVerifierResult::ExecuteHandler;
}
else {
return SysCall::InterruptVerifierResult::SkipHandler;
}
}
static void interrupt_handler(uint32_t) {
HighResTime::global_counter_10ms = HighResTime::global_counter_10ms + 1;
SysCall::ReturnFromException();
}
auto irq_callback = SysCall::InterruptCallback::from(interrupt_verifier, interrupt_handler);
}
}

View File

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