diff --git a/.gitattributes b/.gitattributes index e150652a..b7be3103 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,4 @@ *.xa filter=lfs diff=lfs merge=lfs -text +*.wav filter=lfs diff=lfs merge=lfs -text *.png filter=lfs diff=lfs merge=lfs -text +*.mp3 filter=lfs diff=lfs merge=lfs -text \ No newline at end of file diff --git a/.gitignore b/.gitignore index ba6fd771..e180f8b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,20 @@ -# For now we ignore what is in root -**/build -**/bin -**/iso/Info -/iso - -.lfsconfig - -*.d -*.a -*.o -*.ii -*.xa \ No newline at end of file +# For now we ignore what is in root +**/build +**/bin +**/gcm.cache +**/iso/Info +/iso + +# Custom configs should not be part of JabyEngine +**/config + +.lfsconfig + +*.d +*.a +*.o +*.ii +*.xa + +# TODO: Remove later +examples/PoolBox/assets/tmp.VAG \ No newline at end of file diff --git a/bin/convert2cdda.sh b/bin/convert2cdda.sh new file mode 100644 index 00000000..60d16550 --- /dev/null +++ b/bin/convert2cdda.sh @@ -0,0 +1,6 @@ +#!/bin/bash +#Made possible by Cody the white tiger + +# $1 => Input file +# $2 => Output file +ffmpeg -i $1 -sample_fmt s16 -ar 44100 $2 \ No newline at end of file diff --git a/bin/run_pop_fe.sh b/bin/run_pop_fe.sh new file mode 100644 index 00000000..630d0868 --- /dev/null +++ b/bin/run_pop_fe.sh @@ -0,0 +1,9 @@ +#!/bin/bash +#Made possible by Cody the white tiger + +BASEDIR=$(dirname "$0") +cd $BASEDIR +source extern/py3venv/bin/activate + +cd extern/pop-fe/ +./pop-fe.py --title=$1 --ps1-newemu --cover=$2/Icon.png --pic0=$2/Title.png --pic1=$2/Background.png --ps3-pkg="${3%.*}.pkg" $3 \ No newline at end of file diff --git a/build_all.bat b/build_all.bat deleted file mode 100644 index 87792541..00000000 --- a/build_all.bat +++ /dev/null @@ -1,19 +0,0 @@ -@echo off -rem build_all [clean] - -set build_type=build - -IF NOT "%~1" == "" ( - set build_type=%~1 -) - -mkdir bin\ -cd src\Tools\ -call build_all.bat update -call build_all.bat %build_type% - -cd ..\Library\ -call run_make.bat %build_type% release - -cd ..\..\ -PAUSE \ No newline at end of file diff --git a/config/DebugColor/jabyengine_custom_config.hpp b/config/DebugColor/jabyengine_custom_config.hpp new file mode 100644 index 00000000..ab418d99 --- /dev/null +++ b/config/DebugColor/jabyengine_custom_config.hpp @@ -0,0 +1,6 @@ +#include "../dummy_default_config.hpp" + +struct CustomConfiguration : public DefaultConfiguration { +}; + +#define __USE_DEBUG_COLOR__ \ No newline at end of file diff --git a/config/Readme.md b/config/Readme.md new file mode 100644 index 00000000..1957ab90 --- /dev/null +++ b/config/Readme.md @@ -0,0 +1,48 @@ +# How to create custom configurations +1. Create folder with name of custom configuration +1. Add `jabyengine_custom_config.hpp` to folder + 1. Follow [guidelines](#jabyengine_custom_confighpp) +1. Build JabyEngine and select your configuration +1. Build your application and select your configuration + +## jabyengine_custom_config.hpp +### Default configuration file +```c++ +// Fix IntelliSense +#include "../dummy_default_config.hpp" + +// Overwrite various configurations +struct CustomConfiguration : public DefaultConfiguration { +}; + +// Define macros here +``` +### `CustomConfiguration` options +When overriding an option make sure to mark the function as `override` +```c++ +struct DefaultConfiguration { + struct BIOSFont { + // VRAM position and CLUT position to load the BIOS font too + static constexpr GPU::PositionU16 texture_load_pos(); + static constexpr GPU::PositionU16 CLUT_load_pos(); + }; + + // Offsets the default origin of the screen by the specified value + static constexpr auto DisplayDefaultOffset; + + struct Periphery { + // Turns on the second controller port and enables multi tap support + static constexpr bool include_portB(); + static constexpr bool use_multi_tap(); + }; +}; +``` +### `CustomConfiguration` macros +```c++ +// Turns on debug information of the SPU MMU (on by default [for now]) +#define __DEBUG_SPU_MMU__ +// Turns on colored rectangles during boot (off by default) +#define __USE_DEBUG_COLOR__ +// Turns on PS3 support (on by default) +#define __SUPPORT_PS3__ +``` \ No newline at end of file diff --git a/config/dummy_default_config.hpp b/config/dummy_default_config.hpp new file mode 100644 index 00000000..5f23015f --- /dev/null +++ b/config/dummy_default_config.hpp @@ -0,0 +1,7 @@ +#pragma once +#ifdef __INTELLISENSE__ +// This provides a dummy struct so IntelliSense is happy + +struct DefaultConfiguration { +}; +#endif //! __INTELLISENSE__ \ No newline at end of file diff --git a/docs/Bugs/observed_bugs.md b/docs/Bugs/observed_bugs.md new file mode 100644 index 00000000..360f0e17 --- /dev/null +++ b/docs/Bugs/observed_bugs.md @@ -0,0 +1,6 @@ +# Observed bugs +- [Observed bugs](#observed-bugs) + - [Deadlock](#deadlock) + +## Deadlock +It was observed in `PoolBox` when loading the `FontCycler` overlay that a deadlock occurred. This error has not been observed since. The current theory is that accidentally an old save state in the emulator was loaded. \ No newline at end of file diff --git a/docs/Features/auto_lba.md b/docs/Features/auto_lba.md index a4f32643..b3d7a376 100644 --- a/docs/Features/auto_lba.md +++ b/docs/Features/auto_lba.md @@ -1,68 +1,40 @@ # Auto LBA +- [Auto LBA](#auto-lba) + - [In Code](#in-code) + - [For CD generation](#for-cd-generation) -## Table of Contents -- [In Code](#in-code) - - [Overlay](#overlay) - - [Main file](#main-file) -- [For CD generation](#for-cd-generation) - -To support the `Auto LBA` feature changes need to be applied to the source files and the CD configuration file. The changes for the source files depend on if they are an Overlay or part of the main executable. - ---- +To support the `Auto LBA` feature changes need to be applied to the source files and the CD configuration file. ## In Code -To use the `Auto LBA` feature the LBAs first need to be defined in either an `enum` or `enum struct`. These need to fit a special pattern. +To use the `Auto LBA` feature the LBAs first need to be defined in either an `enum` or `enum struct`. These need to fit a special pattern. The usage of a `namespace` is recommended. `__jabyengine_start_lba_request` needs to be the first entry while `__jabyengine_end_lba_request` needs to be the last. Each LBA entry needs to be declared with `__jabyengine_request_lba_for` followed by the name for the enum entry and the file path on the disk. ```c++ -#include +namespace Assets { + enum LBA { + __jabyengine_start_lba_request + __jabyengine_request_lba_for(SYSTEM_CNF, "SYSTEM.CNF"), + __jabyengine_end_lba_request + }; + __declare_lba_header(LBA); -enum LBA { - __jabyengine_start_lba_request - __jabyengine_request_lba_for(SYSTEM_CNF, "SYSTEM.CNF"), - __jabyengine_end_lba_request -}; -``` - -### __Overlay__ -For use with Overlays you need to include the related header file. You must place this include into the Namespace of your overlay to avoid name clash. Now the `lba` array is accessible. - -```c++ -namespace Overlay { - #include - - // ... - printf("LBA: %i, Words: %i\n", lba[LBA::SYSTEM_CNF].lba, lba[LBA::SYSTEM_CNF].size_words); - // ... - - __declare_overlay_header(execute, LBA); + namespace { + void load() { + printf("LBA: %i, Words: %i\n", lba[LBA::SYSTEM_CNF].lba, lba[LBA::SYSTEM_CNF].size_words); + } + } } ``` -### __Main file__ -For use with the main file you need to include the header file and use the `__declare_lba_header` macro with the name of your enum to create the LBA area in any file. The header allows to access the `lba` array with your enum as the index. - -```c++ -#include - -// ... -printf("LBA: %i, Words: %i\n", lba[LBA::SYSTEM_CNF].lba, lba[LBA::SYSTEM_CNF].size_words); -// ... - -__declare_lba_header(LBA); -``` - ## For CD generation To automatically fill the LBA values `psxcdgen_ex` needs to be used. - -For the main file the special XML type `Main` needs to be used while specifing the LBA file being used. - -For Overlays the instruction will follow... +The attribute `lba_source` automatically fills in the values. It can be used with the XML `Main` and `Overlay` tag. ```xml - System.cnf -
Application.psexe
+ System.cnf +
Application.psexe
+ Overlay.state ``` \ No newline at end of file diff --git a/docs/docs.md b/docs/docs.md index 477c614a..30637036 100644 --- a/docs/docs.md +++ b/docs/docs.md @@ -1,7 +1,14 @@ # JabyEngine Documentation +- [JabyEngine Documentation](#jabyengine-documentation) + - [Features](#features) + - [Known limitations](#known-limitations) + - [Observed bugs](#observed-bugs) -## Table of Contents -- [Features](#features) ---- ## Features -- [Auto LBAs](./Features/auto_lba.md) \ No newline at end of file +- [Auto LBAs](./Features/auto_lba.md) + +## Known limitations +- Insufficient documentation + +## Observed bugs +- [Observed bugs](./Bugs/observed_bugs.md) \ No newline at end of file diff --git a/examples/PoolBox/.gitignore b/examples/PoolBox/.gitignore new file mode 100644 index 00000000..32e75896 --- /dev/null +++ b/examples/PoolBox/.gitignore @@ -0,0 +1,7 @@ +*.bin +*.cue +*.pkg +*.d +*.o +*.lba +**/bin \ No newline at end of file diff --git a/examples/PoolBox/Makefile b/examples/PoolBox/Makefile new file mode 100644 index 00000000..a231ab4f --- /dev/null +++ b/examples/PoolBox/Makefile @@ -0,0 +1,52 @@ +ARTIFACT = PoolBox +make_assets = $(MAKE) $(1) ARTIFACT=$(ARTIFACT) -C assets +make_application = $(MAKE) $(1) ARTIFACT=$(ARTIFACT) -C application +make_cd = $(MAKE) $(1) ARTIFACT=$(ARTIFACT) -C iso + +ifndef REGION +$(error REGION has to be set!) +endif + +# Add regions on your own +# Extend them with what you need +ifeq ($(REGION),SCEE) + export PSX_TV_FORMAT=PAL + export PSX_LICENSE=LICENSEE + export PSX_BOOT_FILE=SLES_AAA.AA +endif +ifeq ($(REGION),SCEA) + export PSX_TV_FORMAT=NTSC + export PSX_LICENSE=LICENSEA + export PSX_BOOT_FILE=SLUS_AAA.AA +endif +ifeq ($(REGION),SCEI) + export PSX_TV_FORMAT=NTSC + export PSX_LICENSE=LICENSEJ + export PSX_BOOT_FILE=SLJS_AAA.AA +endif + +ifndef PSX_TV_FORMAT +$(error PSX_TV_FORMAT has not be set! REGION not specified?) +endif + +ifndef PSX_LICENSE +$(error PSX_LICENSE has not be set! REGION not specified?) +endif + +all clean rebuild: |assets_$(MAKECMDGOALS) application_$(MAKECMDGOALS) cd_$(MAKECMDGOALS) + +all_%: always + $(call make_assets,$*) + $(call make_application,$*) + $(call make_cd,$*) + +assets_%: always + $(call make_assets,$*) +application_%: always + $(call make_application,$*) +cd_%: always + $(call make_cd,$*) +pkg_%: always + $(call make_cd,pkg_$*) + +always: ; \ No newline at end of file diff --git a/examples/PoolBox/PoolBox.code-workspace b/examples/PoolBox/PoolBox.code-workspace new file mode 100644 index 00000000..540f55ec --- /dev/null +++ b/examples/PoolBox/PoolBox.code-workspace @@ -0,0 +1,108 @@ +{ + "folders": [ + { + "path": ".", + "name": "PoolBox" + } + ], + "tasks": { + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "windows": { // v re-export for WSL v re-export for WSL + "command": "wsl make ${input:project}_${input:target} BUILD_PROFILE=${input:build profile} REGION=${input:region} CUSTOM_CONFIG=${input:custom config} PSX_LICENSE_PATH=$(wslpath ${env:PSX_LICENSE_PATH}) JABY_ENGINE_DIR=$(wslpath ${env:JABY_ENGINE_PATH})", + }, + "linux": { + "command": "make ${input:project}_${input:target} BUILD_PROFILE=${input:build profile} REGION=${input:region} CUSTOM_CONFIG=${input:custom config}", + }, + "group": { + "kind": "build", + "isDefault": true + }, + "options": { + "env": { + "PATH": "${env:JABY_ENGINE_PATH}/bin;${env:PATH}" + } + } + }, + { + "label": "read memory map", + "type": "shell", + "command": "psxreadmap.exe ${input:output memory map} application/bin/${input:tv format}/PSX-${input:build profile}/PoolBox.elf", + "problemMatcher": [], + "options": { + "env": { + "PATH": "${env:JABY_ENGINE_PATH}/bin;${env:PATH}" + } + } + } + ], + "inputs": [ + { + "id": "build profile", + "type": "pickString", + "options": ["debug", "release"], + "default": "release", + "description": "The build profile for PoolBox" + }, + { + "id": "project", + "type": "pickString", + "options": ["all", "assets", "application", "cd", "pkg"], + "default": "all", + "description": "Project to build" + }, + { + "id": "target", + "type": "pickString", + "options": ["all", "clean", "rebuild"], + "default": "all", + "description": "the build target" + }, + { + "id": "region", + "type": "pickString", + "options": ["SCEE", "SCEA", "SCEI"], + "default": "SCEE", + "description": "Region profile to use" + }, + { + "id": "custom config", + "type": "command", + "command": "shellCommand.execute", + "args": { + "command": "echo ^|^ && dir /b /a:d", + "cwd": "${env:JABY_ENGINE_PATH}/config", + "fieldSeparator": "|" + } + }, + { + "id": "output memory map", + "type": "pickString", + "options": ["", "-o application/bin/PoolBox.map"], + "default": "", + "description": "Output a memory map" + } + ] + }, + "extensions": { + "recommendations": ["augustocdias.tasks-shell-input"] + }, + "settings": { + "C_Cpp.default.includePath": [ + "${env:JABY_ENGINE_PATH}/include", + "${env:JABY_ENGINE_PATH}/support/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" + ], + } +} \ No newline at end of file diff --git a/examples/PoolBox/application/Makefile b/examples/PoolBox/application/Makefile new file mode 100644 index 00000000..cd3f4824 --- /dev/null +++ b/examples/PoolBox/application/Makefile @@ -0,0 +1,12 @@ +OVERLAY_CONFIG = Overlays.json + +include $(JABY_ENGINE_DIR)/mkfile/common/Wildcard.mk +SRCS = $(call rwildcard, src, c cpp) + +INCLUDES += -I$(JABY_ENGINE_DIR)/support/include -I$(JABY_ENGINE_DIR)/include +CCFLAGS += -save-temps=obj + +SUPPORT_LIBS += FontWriter + +include $(JABY_ENGINE_DIR)/mkfile/Makefile +include $(JABY_ENGINE_DIR)/mkfile/PSEXETarget.mk \ No newline at end of file diff --git a/examples/PoolBox/application/Overlays.json b/examples/PoolBox/application/Overlays.json new file mode 100644 index 00000000..ee993961 --- /dev/null +++ b/examples/PoolBox/application/Overlays.json @@ -0,0 +1,22 @@ +{ + "slot_0": { + "bios_info": { + "pattern": "bin/*/src/Overlay/BIOSInfo/*.o" + }, + "controller_tests": { + "pattern": "bin/*/src/Overlay/ControllerTest/*.o" + }, + "gpu_tests": { + "pattern": "bin/*/src/Overlay/GPUTest/*.o" + }, + "gte_tests": { + "pattern": "bin/*/src/Overlay/GTETest/*.o" + }, + "font_cycler": { + "pattern": "bin/*/src/Overlay/FontCycler/*.o" + }, + "screen_center": { + "pattern": "bin/*/src/Overlay/ScreenCenter/*.o" + } + } +} \ No newline at end of file diff --git a/examples/PoolBox/application/include/asset_mgr.hpp b/examples/PoolBox/application/include/asset_mgr.hpp new file mode 100644 index 00000000..4dd3165d --- /dev/null +++ b/examples/PoolBox/application/include/asset_mgr.hpp @@ -0,0 +1,41 @@ +#pragma once +#include + +namespace Assets { + using namespace JabyEngine; + + namespace Main { + struct ImageInfo { + SimpleTIM tim; + GPU::SizeI16 size; + }; + + static constexpr auto PacoTIM = SimpleTIM::create(896, 0, 960, 510); + static constexpr auto DoenerFishInfo = ImageInfo{ + .tim = SimpleTIM::create(896 + 30, 0, 960 + 16, 510), + .size = GPU::SizeI16::create(128, 64) + }; + + namespace JabyLoader { + static constexpr auto TIMLoaction = SimpleTIM::create(PacoTIM.get_texture_x(), PacoTIM.get_texture_y() + 128, 960 + 48, 510); + static constexpr auto JabyFrame = GPU::AreaI16::create(0, 0, 32, 44); + static constexpr auto FontFrame = GPU::AreaI16::create(0, 45, 186, 32); + }; + + void load(); + } + + namespace Overlay { + void load_bios_info(); + void load_controller_test(); + void load_gpu_test(); + void load_large_gpu_test(); + void load_gte_test(); + void load_font_cycler(); + void load_screen_center(); + } + + namespace XAAudio { + void play_mix(); + } +} \ No newline at end of file diff --git a/examples/PoolBox/application/include/shared.hpp b/examples/PoolBox/application/include/shared.hpp new file mode 100644 index 00000000..f22ac265 --- /dev/null +++ b/examples/PoolBox/application/include/shared.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "../src/include/menu.hpp" +#include "../src/include/font_writer.hpp" +#include + +namespace Shared { + extern Menu::BackMenu back_menu; + extern JabyEngine::GPU::POLY_G4 background; + extern bool load_test; +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Custom/custom_files.hpp b/examples/PoolBox/application/src/Custom/custom_files.hpp new file mode 100644 index 00000000..39e17ce4 --- /dev/null +++ b/examples/PoolBox/application/src/Custom/custom_files.hpp @@ -0,0 +1,13 @@ +#pragma once +#include + +enum struct FileType : JabyEngine::CDFileType_t { + Jingle, +}; + +struct CustomCDFileBuilder { + static constexpr JabyEngine::CDFile jingle(uint32_t sfx_id) { + // v we reload Paco + return JabyEngine::CDFile::custom(0, FileType::Jingle, sfx_id); + } +}; \ No newline at end of file diff --git a/examples/PoolBox/application/src/Custom/file_parser.cpp b/examples/PoolBox/application/src/Custom/file_parser.cpp new file mode 100644 index 00000000..ac63977b --- /dev/null +++ b/examples/PoolBox/application/src/Custom/file_parser.cpp @@ -0,0 +1,26 @@ +#include "custom_files.hpp" +#include +#include + +namespace JabyEngine { + namespace FileProcessor { + struct JingleState { + uint32_t sfx_id; + }; + + static Progress parse_jingle(State::CDDataProcessor& data_proc, JingleState& jingle) { + SPU::voice[jingle.sfx_id].play(); + return Progress::Done; + } + + State create_custom(const uint32_t* data_adr, const CDFileType_t& file_type, const CDFile::Payload& payload) { + switch(static_cast(file_type)) { + case FileType::Jingle: + return State::from(JingleState{.sfx_id = payload.raw}, data_adr, parse_jingle); + + default: + return FileProcessor::create(data_adr, Nothing()); + } + } + } +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/BIOSInfo/bios_info.cpp b/examples/PoolBox/application/src/Overlay/BIOSInfo/bios_info.cpp new file mode 100644 index 00000000..55454f43 --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/BIOSInfo/bios_info.cpp @@ -0,0 +1,148 @@ +#include "../../../include/asset_mgr.hpp" +#include "../../../include/shared.hpp" +#include +#include +#include +#include +#include +#include + +namespace BIOSInfo { + using namespace JabyEngine; + static constexpr auto TextOffset = Make::PositionI16(16, 16); + + using NameColorPair = pair; + + struct FontSlider { + static constexpr auto MoveTimeout = static_cast(300_ms); + static constexpr auto WaitTimeout = static_cast(1000_ms); + + int16_t count; + int16_t max; + int8_t delta; + IntervalTimer wait_timer; + + static FontSlider create_for(const FontWriter::FontInfo& font_info, const char* str) { + const auto max = static_cast((strlen(str)*font_info.get_kern_size().width) - GPU::Display::Width + (TextOffset.x << 1)); + return FontSlider{ + .count = 0, + .max = max, + .delta = static_cast(max < 0 ? 0 : font_info.get_kern_size().width/2), + .wait_timer = IntervalTimer::create(FontSlider::MoveTimeout) + }; + } + + void advance() { + if(this->wait_timer.is_expired()) { + this->wait_timer.reset(); + this->count += delta; + + if(this->count <= 0 || this->count >= this->max) { + this->delta *= -1; + this->wait_timer.set_interval(FontSlider::WaitTimeout); + } + + else { + this->wait_timer.set_interval(FontSlider::MoveTimeout); + } + } + } + }; + + static struct { + using BIOSStringOffset = const char*const (BIOS::Version::*); + + const BIOSStringOffset bios_str_offset; + const char*const display_str; + FontSlider font_slider; + } BIOSStringInfo[] = { + {.bios_str_offset = &BIOS::Version::kernel_maker, .display_str = "Kernel-Maker"}, + {.bios_str_offset = &BIOS::Version::version_str, .display_str = "Version"}, + {.bios_str_offset = &BIOS::Version::gui_version, .display_str = "GUI-Version"}, + {.bios_str_offset = &BIOS::Version::copyright, .display_str = "Copyright"}, + }; + + static GPU::TILE::Linked border_tiles[2] = { + Make::TILE(Make::AreaI16(0, 0, TextOffset.x, GPU::Display::Height - 32), GPU::Color24::Black()).linked(), + Make::TILE(Make::AreaI16(GPU::Display::Width - TextOffset.x, 0, TextOffset.x, GPU::Display::Height - 32), GPU::Color24::Black()).linked() + }; + + static NameColorPair bios_name; + static FontSlider bios_name_slider; + + static NameColorPair get_bios_name() { + switch(BIOS::version.type) { + case BIOS::Version::Devboard: + return {"DevBoard", GPU::Color24::Green()}; + case BIOS::Version::PS1: + return {"PS1", GPU::Color24::Red()}; + case BIOS::Version::PS2: + return {"PS2", GPU::Color24::Blue()}; + case BIOS::Version::PS3: + return {"PS3", GPU::Color24::Yellow()}; + case BIOS::Version::PSCompatible: + return {"Unkown PS compatible BIOS", GPU::Color24::Grey()}; + case BIOS::Version::No$psx: + return {"NO$PSX", GPU::Color24::Purple()}; + case BIOS::Version::XEBRA: + return {"XEBRA", GPU::Color24::Turquoise()}; + default: + return {"Unkown", GPU::Color24::White()}; + } + } + + static void setup() { + bios_name = get_bios_name(); + Shared::back_menu.reset(); + for(auto& bios_str_info : BIOSStringInfo) { + bios_str_info.font_slider = FontSlider::create_for(FontWriter::BIOSFont::Info, BIOS::version.*(bios_str_info.bios_str_offset)); + } + bios_name_slider = FontSlider::create_for(FontWriter::BIOSFont::Info, bios_name.first); + border_tiles[0].concat(border_tiles[1]); + } + + static bool update_or_exit() { + static const auto move_cursor = [](JabyEngine::Cursor& cursor, int16_t dx, int16_t old_x) -> JabyEngine::Cursor& { + cursor.pos.x = (old_x - dx); + return cursor; + }; + + Periphery::query_controller(); + if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { + return true; + } + + auto cursor = FontWriter::update(TextOffset); + FontWriter::bios_font_writer.write(cursor, "BIOS INFORMATION\n----------------\nDate (day/month/year):\n%i/%i/%i\n", BIOS::version.date.day, BIOS::version.date.month, BIOS::version.date.year); + + const auto old_pos_x = cursor.pos.x; + for(auto& bios_str_info : BIOSStringInfo) { + bios_str_info.font_slider.advance(); + + FontWriter::bios_font_writer.write(move_cursor(cursor, 0, old_pos_x), "%s:\n", bios_str_info.display_str); + FontWriter::bios_font_writer.write(move_cursor(cursor, bios_str_info.font_slider.count, old_pos_x), "%s\n", BIOS::version.*(bios_str_info.bios_str_offset)); + } + FontWriter::bios_font_writer.write(move_cursor(cursor, 0, old_pos_x), "BIOS Type:\n"); + FontWriter::bios_font_writer.write(move_cursor(cursor, bios_name_slider.count, old_pos_x), "%s\n", bios_name.second, bios_name.first); + FontWriter::bios_font_writer.write(move_cursor(cursor, 0, old_pos_x), "----------------\n"); + + return false; + } + + static void render() { + Shared::back_menu.render(); + FontWriter::bios_font_writer.render(); + GPU::render(border_tiles[0]); + } + + void main() { + setup(); + while(true) { + if(update_or_exit()) { + break; + } + GPU::swap_buffers_vsync(1); + render(); + } + } +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ControllerTest/controller_state.cpp b/examples/PoolBox/application/src/Overlay/ControllerTest/controller_state.cpp new file mode 100644 index 00000000..5d2919b8 --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/ControllerTest/controller_state.cpp @@ -0,0 +1,110 @@ +#include "include/controller_state.hpp" +#include +#include + +namespace ControllerTest { + using DigitalButton = Periphery::AnalogeController::Button; + using namespace JabyEngine; + + static void set_active(GPU::SPRT_16::Linked& sprt, bool is_active) { + sprt->tex_offset.y = is_active ? 16 : 0; + if(is_active) { + SPU::voice[1].play_if_end(); + } + } + + static void set_active(GPU::POLY_FT4::Linked& poly, bool is_active) { + poly->tex_offset0.y = is_active ? 16 : 0; + poly->tex_offset1.y = is_active ? 16 : 0; + poly->tex_offset2.y = is_active ? 32 : 16; + poly->tex_offset3.y = is_active ? 32 : 16; + + if(is_active) { + SPU::voice[1].play_if_end(); + } + } + + static const char* get_type_name(Periphery::ControllerType type) { + switch(type) { + case Periphery::ControllerType::Unkown: + return "Unkown"; + + case Periphery::ControllerType::Mouse: + return "Mouse"; + + case Periphery::ControllerType::NegCon: + return "NegCon"; + + case Periphery::ControllerType::HyperBlaster: + return "HyperBlaster"; + + case Periphery::ControllerType::Controller: + return "Digital Controller"; + + case Periphery::ControllerType::ArcadeFlightStick: + return "Flight Stick"; + + case Periphery::ControllerType::GCon: + return "GCon"; + + case Periphery::ControllerType::DualShock: + return "DualShock"; + + case Periphery::ControllerType::MultiTap: + return "MultiTap"; + + default: + return "???"; + } + } + + void ControllerState :: setup() { + for(size_t n = 0; n < 2; n++) { + GPU::LinkHelper::link_array(GPU::LinkHelper::link_array(&this->tex_page[n], this->buttons[n]), this->arrows[n]); + } + } + + void ControllerState :: update(const Periphery::AnalogeController* controller, JabyEngine::FontWriter& font_writer) { + static const DigitalButton ButtonSprtMap[] = { + DigitalButton::Triangle, DigitalButton::Circle, DigitalButton::Cross, DigitalButton::Square, + DigitalButton::ST, DigitalButton::SEL, DigitalButton::L1, DigitalButton::L2, DigitalButton::R1, DigitalButton::R2, + DigitalButton::L3, DigitalButton::R3 + }; + static const DigitalButton ArrowPolyMap[] = { + DigitalButton::Up, DigitalButton::Right, DigitalButton::Down, DigitalButton::Left + }; + + auto& cur_button_sprts = this->buttons[GPU::update_id()]; + auto& cur_arrow_poly = this->arrows[GPU::update_id()]; + + if(controller) { + for(size_t n = 0; n < sizeof(ButtonSprtMap)/sizeof(ButtonSprtMap[0]); n++) { + set_active(cur_button_sprts[n], controller->button.is_down(ButtonSprtMap[n])); + } + for(size_t n = 0; n < sizeof(ArrowPolyMap)/sizeof(ArrowPolyMap[0]); n++) { + set_active(cur_arrow_poly[n], controller->button.is_down(ArrowPolyMap[n])); + } + + set_active(cur_button_sprts[12], controller->header.state == Periphery::RawController::State::Disconnected); + + // Text stuff down here + const auto offset_point = cur_button_sprts[1]->position; + const auto left_stick = controller->get_left_stick_pos(); + const auto right_stick = controller->get_right_stick_pos(); + + auto cursor = Cursor::create(offset_point.move(16, 0), 0); + font_writer.write(cursor, "Right: %i, %i\nLeft : %i, %i\n", right_stick.x, right_stick.y, left_stick.x, left_stick.y); + font_writer.write(cursor, "[%s]", get_type_name(static_cast(controller->get_type()))); + } + + else { + auto cursor = Cursor::create(Make::PositionI16(cur_arrow_poly[3]->vertex0.x, cur_button_sprts[0]->position.y), 0); + font_writer.write(cursor, "!!This Port is not\nenabled in JabyEngine!!", GPU::Color24::Red()); + this->tex_page[GPU::update_id()].terminate(); + } + } + + void ControllerState :: render() { + GPU::render(this->tex_page[GPU::render_id()]); + } +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ControllerTest/controller_test.cpp b/examples/PoolBox/application/src/Overlay/ControllerTest/controller_test.cpp new file mode 100644 index 00000000..2457c201 --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/ControllerTest/controller_test.cpp @@ -0,0 +1,47 @@ +#include "../../../include/shared.hpp" +#include "include/controller_state.hpp" +#include + +namespace ControllerTest { + using namespace JabyEngine; + + static auto controller_state0 = ControllerState::create(Make::PositionI16(0, 0)); + static auto controller_state1 = ControllerState::create(Make::PositionI16(0, 76)); + + static void setup() { + Shared::back_menu.reset(); + controller_state0.setup(); + controller_state1.setup(); + } + + static bool update_or_exit() { + Periphery::query_controller(); + if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { + return true; + } + + controller_state0.update(&Periphery::get_primary_controller_as(), FontWriter::bios_font_writer); + controller_state1.update(Periphery::PortCount > 1 ? &Periphery::get_controller_as(1, 0) : nullptr, FontWriter::bios_font_writer); + return false; + } + + static void render() { + GPU::render(Shared::background); + controller_state0.render(); + controller_state1.render(); + FontWriter::bios_font_writer.render(); + Shared::back_menu.render(); + } + + void main() { + setup(); + + while(true) { + if(update_or_exit()) { + break; + } + GPU::swap_buffers_vsync(1); + render(); + } + } +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ControllerTest/controller_test_assets.cpp b/examples/PoolBox/application/src/Overlay/ControllerTest/controller_test_assets.cpp new file mode 100644 index 00000000..fef8e5ee --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/ControllerTest/controller_test_assets.cpp @@ -0,0 +1,18 @@ +#include "include/controller_test_assets.hpp" +#include +#include + +namespace ControllerTest { + using namespace JabyEngine; + + enum LBA { + __jabyengine_start_lba_request + __jabyengine_request_lba_for(CONT, "ASSETS/CONT/CONT.IMG"), + __jabyengine_end_lba_request + }; + __declare_lba_header(LBA); + + CDFile Assets[1] = { + CDFileBuilder::simple_tim(LBA::CONT, ControllerButtonTIM), + }; +} diff --git a/examples/PoolBox/application/src/Overlay/ControllerTest/include/controller_state.hpp b/examples/PoolBox/application/src/Overlay/ControllerTest/include/controller_state.hpp new file mode 100644 index 00000000..5378d575 --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/ControllerTest/include/controller_state.hpp @@ -0,0 +1,67 @@ +#pragma once +#include "controller_test_assets.hpp" +#include +#include +#include + +namespace ControllerTest { + using namespace JabyEngine; + + class ControllerState { + private: + GPU::TexPage::Linked tex_page[2]; + GPU::SPRT_16::Linked buttons[2][13]; + GPU::POLY_FT4::Linked arrows[2][4]; + + public: + static constexpr ControllerState create(GPU::PositionI16 offset = Make::PositionI16(0, 0)) { + ControllerState state; + + for(auto& tex_page : state.tex_page) { + tex_page = Make::TexPage(ControllerButtonTIM.get_texture_position(), GPU::TextureColorMode::clut4).linked(); + } + + for(auto& buttons : state.buttons) { + // Triangle + buttons[0] = Make::SPRT_16(Make::Vertex(71, 0).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(0, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // Circle + buttons[1] = Make::SPRT_16(Make::Vertex(82, 12).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(1, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // Cross + buttons[2] = Make::SPRT_16(Make::Vertex(71, 23).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(2, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // Square + buttons[3] = Make::SPRT_16(Make::Vertex(60, 11).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(3, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // Play + buttons[4] = Make::SPRT_16(Make::Vertex(51, 21).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(4, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // Block + buttons[5] = Make::SPRT_16(Make::Vertex(24, 21).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(5, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // L1 + buttons[6] = Make::SPRT_16(Make::Vertex(7, 39).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(7, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // L2 + buttons[7] = Make::SPRT_16(Make::Vertex(7, 49).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(8, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // R1 + buttons[8] = Make::SPRT_16(Make::Vertex(71, 39).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(7, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // R2 + buttons[9] = Make::SPRT_16(Make::Vertex(71, 49).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(8, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // L3 + buttons[10] = Make::SPRT_16(Make::Vertex(24, 34).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(9, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // R3 + buttons[11] = Make::SPRT_16(Make::Vertex(52, 34).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(9, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // Connection Symbol + buttons[12] = Make::SPRT_16(Make::Vertex(37, 9).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(10, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + } + + for(auto& arrows : state.arrows) { + arrows[0] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect( Make::AreaI16(Make::PositionI16( 7, 5).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked(); + arrows[1] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect270(Make::AreaI16(Make::PositionI16(14, 11).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked(); + arrows[2] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect180(Make::AreaI16(Make::PositionI16( 7, 17).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked(); + arrows[3] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect90( Make::AreaI16(Make::PositionI16( 0, 11).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked(); + } + + return state; + } + + void setup(); + void update(const Periphery::AnalogeController* controller, JabyEngine::FontWriter& font_writer); + void render(); + }; +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ControllerTest/include/controller_test_assets.hpp b/examples/PoolBox/application/src/Overlay/ControllerTest/include/controller_test_assets.hpp new file mode 100644 index 00000000..55764ac1 --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/ControllerTest/include/controller_test_assets.hpp @@ -0,0 +1,8 @@ +#pragma once +#include + +namespace ControllerTest { + using namespace JabyEngine; + + static constexpr auto ControllerButtonTIM = SimpleTIM::create(384, 0, 384, 511); +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/FontCycler/font_cycler.cpp b/examples/PoolBox/application/src/Overlay/FontCycler/font_cycler.cpp new file mode 100644 index 00000000..c5cc71e1 --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/FontCycler/font_cycler.cpp @@ -0,0 +1,78 @@ +#include "../../../include/shared.hpp" +#include +#include + +namespace FontCycler { + using namespace JabyEngine; + + static const char*const ASCII = "!\"#$%&'()*+,-./0\n123456789:;<=>?@\nABCDEFGHIJKLMNOP\nQRSTUVWXYZ[\\]^_`\nabcdefghijklmnop\nqrstuvwxyz{|}~\n"; + + static JabyEngine::FontWriter*const FontWriters[] = { + &FontWriter::bios_font_writer, + &FontWriter::new_font_writer, + }; + static constexpr auto MaxFontSelector = (sizeof(FontWriters)/sizeof(FontWriters[0])) - 1; + static uint8_t font_selector = 0; + + static void increment_font_selector() { + if(font_selector == MaxFontSelector) { + font_selector = 0; + } + + else { + font_selector++; + } + } + + static void decrement_font_selector() { + if(font_selector == 0) { + font_selector = MaxFontSelector; + } + + else { + font_selector--; + } + } + + static void setup() { + Shared::back_menu.reset(); + font_selector = 0; + } + + static bool update_or_exit() { + Periphery::query_controller(); + if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { + return true; + } + + const auto& controller = Periphery::get_primary_controller_as(); + if(controller.button.went_up(Periphery::GenericController::Button::L1)) { + decrement_font_selector(); + } + if(controller.button.went_up(Periphery::GenericController::Button::R1)) { + increment_font_selector(); + } + + auto cursor = FontWriter::update(Make::PositionI16(8, 8)); + FontWriters[font_selector]->write(cursor, ASCII); + FontWriters[font_selector]->write(cursor, "\nPress L1 or R1 to cycle\nthrough fonts"); + return false; + } + + static void render() { + FontWriters[font_selector]->render(); + Shared::back_menu.render(); + } + + void main() { + setup(); + + while(true) { + if(update_or_exit()) { + break; + } + GPU::swap_buffers_vsync(1); + render(); + } + } +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/GPUTest/gpu_test.cpp b/examples/PoolBox/application/src/Overlay/GPUTest/gpu_test.cpp new file mode 100644 index 00000000..e4c85c8e --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/GPUTest/gpu_test.cpp @@ -0,0 +1,174 @@ +#include "../../../include/shared.hpp" +#include "include/gpu_test_assets.hpp" +#include +#include +#include +#include + +namespace GPUTest { + using namespace JabyEngine; + + // Some default values for the objects + static constexpr auto TriangleColor = GPU::Color24::from_rgb(0x0, 0xFF, 0xFF); + static constexpr auto TriangleArea = Make::AreaI16(Make::PositionI16(0, 0), Make::SizeI16(64, 64)); + static constexpr auto TriangleTPage = Make::TPage(TexPageTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4); + static constexpr auto TriangleClut = Make::PageClut(TexPageTIM.get_clut_position()); + + static constexpr auto RectangleColor = GPU::Color24::from_rgb(0x80, 0x80, 0xFF); + static constexpr auto RectangleArea = Make::AreaI16(Make::PositionI16(0, TriangleArea.size.height), Make::SizeI16(80, 80)); + static constexpr auto RectangleTPage = Make::TPage(IconTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4); + static constexpr auto RectangleClut = Make::PageClut(IconTIM.get_clut_position()); + + static constexpr auto LineColor = GPU::Color24::from_rgb(0xFF, 0x0, 0x0); + + static constexpr const auto triangle1 = Make::POLY_F3({ + Make::Vertex(TriangleArea.position.x, TriangleArea.position.y), + Make::Vertex(TriangleArea.size.width, TriangleArea.size.height), + Make::Vertex(TriangleArea.position.x, TriangleArea.size.height) + }, TriangleColor + ); + static constexpr const auto triangle2 = Make::POLY_FT3({ + Make::Vertex(TriangleArea.position.x, TriangleArea.position.y), + Make::Vertex(TriangleArea.size.width, TriangleArea.position.y), + Make::Vertex(TriangleArea.size.width, TriangleArea.size.height) + },{ + // Texture + Make::PageOffset(TriangleArea.position.x, TriangleArea.position.y), + Make::PageOffset(TriangleArea.size.width, TriangleArea.position.y), + Make::PageOffset(TriangleArea.size.width, TriangleArea.size.height) + }, TriangleTPage, TriangleClut, GPU::Color24::Grey() + ); + static constexpr const auto triangle3 = Make::POLY_G3({ + {triangle1.vertex0.move(TriangleArea.size.width, 0), GPU::Color24::Red()}, + {triangle1.vertex1.move(TriangleArea.size.width, 0), GPU::Color24::Green()}, + {triangle1.vertex2.move(TriangleArea.size.width, 0), GPU::Color24::Blue()}} + ); + static constexpr const auto triangle4 = Make::POLY_GT3({ + {triangle2.vertex0.move(TriangleArea.size.width, 0), triangle2.tex_offset0, GPU::Color24::Red()}, + {triangle2.vertex1.move(TriangleArea.size.width, 0), triangle2.tex_offset1, GPU::Color24::Blue()}, + {triangle2.vertex2.move(TriangleArea.size.width, 0), triangle2.tex_offset2, GPU::Color24::Green()}}, + TriangleTPage, + TriangleClut + ); + + static constexpr const auto rectangle1 = Make::POLY_F4(RectangleArea, RectangleColor); + static constexpr const auto rectangle2 = Make::POLY_FT4(Make::AreaI16( + RectangleArea.position.move(RectangleArea.size.width, 0), RectangleArea.size), Make::PageOffset(0, 0), + RectangleTPage, + RectangleClut, + GPU::Color24::Grey() + ); + static constexpr const auto rectangle3 = Make::POLY_G4( + {RectangleArea.position.move(RectangleArea.size.width*2, 0), RectangleArea.size}, { + GPU::Color24::Red(), + GPU::Color24::Blue(), + GPU::Color24::Green(), + GPU::Color24::White()}); + static constexpr const auto rectangle4 = Make::POLY_GT4(Make::AreaI16( + RectangleArea.position.move(RectangleArea.size.width*3, 0), RectangleArea.size), Make::PageOffset(0, 0), + RectangleTPage, + RectangleClut, { + GPU::Color24::Red(), + GPU::Color24::Blue(), + GPU::Color24::Green(), + GPU::Color24::White()} + ); + static constexpr const auto rectangle5 = Make::POLY_GT4(Make::AreaI16( + RectangleArea.position.move(0, RectangleArea.size.height), RectangleArea.size), Make::PageOffset(0, 0), + RectangleTPage, + RectangleClut, { + GPU::Color24::Red(), + GPU::Color24::Blue(), + GPU::Color24::Green(), + GPU::Color24::White()} + ).set_semi_transparent(true); + + static constexpr const auto line1 = Make::LINE_F(LineColor, + Make::Vertex(0, 0), + Make::Vertex(GPU::Display::Width, GPU::Display::Height) + ); + static constexpr const auto line2 = Make::LINE_F(LineColor.invert(), + Make::Vertex(0, 0), + Make::Vertex(16, 0), + Make::Vertex(16, 16), + Make::Vertex(0, 0) + ); + static constexpr const auto line3 = Make::LINE_G( + GPU::ColorVertex{LineColor, Make::Vertex(GPU::Display::Width, 0)}, + GPU::ColorVertex{LineColor.invert(), Make::Vertex(0, GPU::Display::Height)} + ); + static constexpr const auto line4 = Make::LINE_G( + GPU::ColorVertex{GPU::Color24::Red(), Make::Vertex(0, 0)}, + GPU::ColorVertex{GPU::Color24::Green(), Make::Vertex(0, 16)}, + GPU::ColorVertex{GPU::Color24::Blue(), Make::Vertex(16, 16)}, + GPU::ColorVertex{GPU::Color24::White(), Make::Vertex(0, 0)} + ); + + static constexpr const auto rect1 = Make::TILE(Make::AreaI16(Make::PositionI16(GPU::Display::Width - 32, GPU::Display::Height - 32), Make::SizeI16(32, 32)), GPU::Color24::Green()); + static constexpr const auto rect2 = Make::TILE_16(Make::PositionI16(GPU::Display::Width - 16, GPU::Display::Height - 16), GPU::Color24::Blue()); + static constexpr const auto rect3 = Make::TILE_8(Make::PositionI16(GPU::Display::Width - 8, GPU::Display::Height - 8), GPU::Color24::Yellow()); + static constexpr const auto rect4 = Make::TILE_1(Make::PositionI16(GPU::Display::Width - 1, GPU::Display::Height - 1), GPU::Color24::Red()); + + static constexpr const auto texpage = Make::TexPage(TexPageTIM.get_texture_position(), GPU::TextureColorMode::clut4); + static constexpr const auto rect5 = Make::SPRT(Make::AreaI16(Make::PositionI16(0, GPU::Display::Height - 32), Make::SizeI16(32, 32)), {Make::PageOffset(0, 0), TriangleClut}, GPU::Color24::Green()); + static constexpr const auto rect6 = Make::SPRT_16(Make::Vertex(0, GPU::Display::Height - 16), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Blue()); + static constexpr const auto rect7 = Make::SPRT_8(Make::Vertex(0, GPU::Display::Height - 8), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Yellow()); + static constexpr const auto rect8 = Make::SPRT_1(Make::Vertex(0, GPU::Display::Height - 1), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Red()); + + static auto rect9 = Make::SPRT(Make::AreaI16(Make::PositionI16(GPU::Display::Width/2, GPU::Display::Height/2), Make::SizeI16(32, 32)).centered(), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Grey()).linked(); + static auto rect10 = Make::SPRT(Make::AreaI16(Make::PositionI16(GPU::Display::Width/2, GPU::Display::Height/2 - 32), Make::SizeI16(32, 32)).centered(), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Grey()).linked(); + + void main() { + rect9.concat(rect10); + Shared::back_menu.reset(); + HighResTime::enable(); + + auto start_time = HighResTime::get_time_stamp(); + auto time_passed = 0; + while(true) { + // Update Phase + Periphery::query_controller(); + if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { + break; + } + + auto cursor = FontWriter::update(Make::PositionI16((GPU::Display::Width - 160)/2, GPU::Display::Height - 32)); + FontWriter::bios_font_writer.write(cursor, "Time: %ims", GPU::Color24::Blue(), time_passed); + + GPU::swap_buffers_vsync(1); + const auto end_time = HighResTime::get_time_stamp(); + time_passed = start_time.milliseconds_to(end_time); + start_time = end_time; + + GPU::render(triangle1); + GPU::render(triangle2); + GPU::render(triangle3); + GPU::render(triangle4); + + GPU::render(rectangle1); + GPU::render(rectangle2); + GPU::render(rectangle3); + GPU::render(rectangle4); + GPU::render(rectangle5); + + GPU::render(rect1); + GPU::render(rect2); + GPU::render(rect3); + GPU::render(rect4); + GPU::render(texpage); + GPU::render(rect5); + GPU::render(rect6); + GPU::render(rect7); + GPU::render(rect8); + + GPU::render(line1); + GPU::render(line2); + GPU::render(line3); + GPU::render(line4); + + GPU::render(rect9); + Shared::back_menu.render(); + } + HighResTime::disable(); + } +} diff --git a/examples/PoolBox/application/src/Overlay/GPUTest/gpu_test_assets.cpp b/examples/PoolBox/application/src/Overlay/GPUTest/gpu_test_assets.cpp new file mode 100644 index 00000000..6e74d656 --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/GPUTest/gpu_test_assets.cpp @@ -0,0 +1,60 @@ +#include "include/gpu_test_assets.hpp" +#include +#include + +namespace GPUTest { + using namespace JabyEngine; + + enum LBA { + __jabyengine_start_lba_request + __jabyengine_request_lba_for(TEX, "ASSETS/TEX.IMG"), + __jabyengine_request_lba_for(ICON, "ASSETS/ICON.IMG"), + __jabyengine_request_lba_for(ALL_THE_JABY, "ASSETS/ATJ.TIM"), + __jabyengine_end_lba_request + }; + __declare_lba_header(LBA); + + CDFile Assets[2] = { + CDFileBuilder::simple_tim(LBA::TEX, TexPageTIM), + CDFileBuilder::simple_tim(LBA::ICON, IconTIM), + }; + + CDFile LargeAssets[36] = { + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + }; +} diff --git a/examples/PoolBox/application/src/Overlay/GPUTest/include/gpu_test_assets.hpp b/examples/PoolBox/application/src/Overlay/GPUTest/include/gpu_test_assets.hpp new file mode 100644 index 00000000..aab812d4 --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/GPUTest/include/gpu_test_assets.hpp @@ -0,0 +1,9 @@ +#pragma once +#include + +namespace GPUTest { + using namespace JabyEngine; + + static constexpr auto TexPageTIM = SimpleTIM::create(384, 0, 384, 511); + static constexpr auto IconTIM = SimpleTIM::create(384, 256, 384, 510); +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/GTETest/gte_test.cpp b/examples/PoolBox/application/src/Overlay/GTETest/gte_test.cpp new file mode 100644 index 00000000..1c683d11 --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/GTETest/gte_test.cpp @@ -0,0 +1,166 @@ +#include "../../../include/asset_mgr.hpp" +#include "../../../include/shared.hpp" +#include "include/GTE_Sprite.hpp" +#include "include/gte_test_assets.hpp" +#include + +namespace GTETest { + using namespace JabyEngine; + using namespace GTETest; + + namespace Jaby { + static constexpr auto AnimationTime = 250_ms; + static const struct { + gte_float scale_left; + gte_float scale_right; + } animation[] = { + {.scale_left = 1.0_gf, .scale_right = 1.0_gf}, + {.scale_left = 1.0_gf, .scale_right = 1.0_gf}, + + {.scale_left = 1.2_gf, .scale_right = 1.5_gf}, + {.scale_left = 1.5_gf, .scale_right = 1.2_gf}, + {.scale_left = 1.2_gf, .scale_right = 1.5_gf}, + {.scale_left = 1.5_gf, .scale_right = 1.2_gf}, + + {.scale_left = 1.8_gf, .scale_right = 2.3_gf}, + {.scale_left = 2.3_gf, .scale_right = 1.8_gf}, + {.scale_left = 1.8_gf, .scale_right = 2.3_gf}, + {.scale_left = 2.3_gf, .scale_right = 1.8_gf}, + + {.scale_left = 3.2_gf, .scale_right = 4.5_gf}, + {.scale_left = 4.5_gf, .scale_right = 3.2_gf}, + {.scale_left = 3.2_gf, .scale_right = 4.5_gf}, + {.scale_left = 4.5_gf, .scale_right = 3.2_gf}, + + {.scale_left = 1.8_gf, .scale_right = 2.3_gf}, + {.scale_left = 2.3_gf, .scale_right = 1.8_gf}, + {.scale_left = 1.8_gf, .scale_right = 2.3_gf}, + {.scale_left = 2.3_gf, .scale_right = 1.8_gf}, + + {.scale_left = 1.2_gf, .scale_right = 1.5_gf}, + {.scale_left = 1.5_gf, .scale_right = 1.2_gf}, + {.scale_left = 1.2_gf, .scale_right = 1.5_gf}, + {.scale_left = 1.5_gf, .scale_right = 1.2_gf}, + }; + static IntervalTimer animation_timer; + static auto animation_id = 0; + static constexpr auto Position = Make::PositionI16(GPU::Display::Width - 64, GPU::Display::Height - 64); + + static constexpr GTE_Sprite make_star_eye(GPU::PositionI16 pos) { + return GTE_Sprite::create(Make::POLY_FT4( + Make::AreaI16(pos, GPU::SizeI16(8, 8)), + JabySTARTim.get_page_offset_clut4().add(0, 64), + Make::TPage(JabySTARTim.get_texture_position(), GPU::SemiTransparency::B_add_F, GPU::TextureColorMode::clut4), + Make::PageClut(JabySTARTim.get_clut_position()), + GPU::Color24::Grey() + ).linked()); + } + + static auto star_base = Make::SPRT( + Make::AreaI16(Position, Make::SizeI16(64, 64)), + Make::OffsetPageWithClut(JabySTARTim.get_page_offset_clut4(), Make::PageClut(JabySTARTim.get_clut_position())) + ).linked(); + + static GTE_Sprite star_eyes[2] = { + make_star_eye(Position.add(11, 30)), + make_star_eye(Position.add(33, 31)) + }; + } + + namespace Background { + static constexpr auto ColorBase = 0xC0; + + static constexpr GPU::AreaI16 Area[2] = { + Make::AreaI16(-30, -30, 350, 350), + Make::AreaI16(0, 0, GPU::Display::Width, GPU::Display::Width), + }; + static constexpr GPU::PositionI16 AreaPivot[2] = { + Make::PositionI16(Area[0].size.width/2, Area[0].size.height/2), + Make::PositionI16(Area[1].size.width/2, Area[1].size.height/2), + }; + + static GPU::POLY_G4 poly[2] = { + Make::POLY_G4(Area[0], {GPU::Color24::Blue(ColorBase), GPU::Color24::Red(ColorBase), GPU::Color24::Green(ColorBase), GPU::Color24::Purple(ColorBase)}), + Make::POLY_G4(Area[1], {GPU::Color24::Blue(ColorBase), GPU::Color24::Red(ColorBase), GPU::Color24::Green(ColorBase), GPU::Color24::Purple(ColorBase)}), + }; + } + + static auto doener_fish = GTE_Sprite::create(Make::POLY_FT4( + Make::AreaI16(Make::PositionI16(0, 0), Assets::Main::DoenerFishInfo.size), + Assets::Main::DoenerFishInfo.tim.get_page_offset_clut4(), + Make::TPage(Assets::Main::DoenerFishInfo.tim.get_texture_position(), GPU::SemiTransparency::B_add_F, GPU::TextureColorMode::clut4), + Make::PageClut(Assets::Main::DoenerFishInfo.tim.get_clut_position()), + GPU::Color24::Grey() + ).linked()); + + static auto gbl_rotation = 0.0_deg; + + static void setup() { + Jaby::star_base.concat(Jaby::star_eyes[0].display.concat(Jaby::star_eyes[1].display)); + Jaby::star_eyes[0].scale = Jaby::animation[0].scale_right; + Jaby::star_eyes[1].scale = Jaby::animation[0].scale_left; + Jaby::animation_id = 1; + Jaby::animation_timer = IntervalTimer::create(Jaby::AnimationTime); + + doener_fish.area.position = GPU::PositionI16::create(100, 100); + Shared::back_menu.reset(); + + GTE::set_geom_offset(0, 0); + GTE::set_geom_screen(256); + } + + static bool update_or_exit() { + Periphery::query_controller(); + if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { + return true; + } + + if(Jaby::animation_timer.is_expired()) { + Jaby::star_eyes[0].scale = Jaby::animation[Jaby::animation_id].scale_right; + Jaby::star_eyes[1].scale = Jaby::animation[Jaby::animation_id].scale_left; + + Jaby::animation_id = (Jaby::animation_id + 1)%(sizeof(Jaby::animation)/sizeof(Jaby::animation[0])); + Jaby::animation_timer.reset(); + } + + for(size_t n = 0; n < sizeof(Background::poly)/sizeof(Background::poly[0]); n++) { + auto matrix = [](size_t n) -> GTE::MATRIX { + auto matrix = GTE::MATRIX::translated(-Background::AreaPivot[n].x, -Background::AreaPivot[n].y); + matrix.rotate(0.0_deg, 0.0_deg, (n == 0) ? gbl_rotation : -gbl_rotation); + return matrix.translate(Background::Area[n].position.x + Background::AreaPivot[n].x, Background::Area[n].position.y + Background::AreaPivot[n].y); + }(n); + matrix.apply_to_area(Background::poly[n], Make::AreaI16(Make::PositionI16(), Background::Area[n].size)); + } + + const auto matrix = GTE::MATRIX::rotated(-gbl_rotation, gbl_rotation, -gbl_rotation); + doener_fish.apply(matrix); + Jaby::star_eyes[0].apply(); + Jaby::star_eyes[1].apply(); + + doener_fish.angle += 25.0_deg; + gbl_rotation += 2.5_deg; + return false; + } + + static void render() { + for(const auto& poly : Background::poly) { + GPU::render(poly); + } + doener_fish.render(); + GPU::render(Jaby::star_base); + Shared::back_menu.render(); + GPU::wait_for_render(); //< Because we are single buffer + } + + void main() { + setup(); + + while(true) { + if(update_or_exit()) { + break; + } + GPU::swap_buffers_vsync(1, false); + render(); + } + } +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/GTETest/gte_test_assets.cpp b/examples/PoolBox/application/src/Overlay/GTETest/gte_test_assets.cpp new file mode 100644 index 00000000..10f6cb96 --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/GTETest/gte_test_assets.cpp @@ -0,0 +1,15 @@ +#include "include/gte_test_assets.hpp" +#include + +namespace GTETest { + enum LBA { + __jabyengine_start_lba_request + __jabyengine_request_lba_for(JABY_STAR, "ASSETS/GTE/JABY.IMG"), + __jabyengine_end_lba_request + }; + __declare_lba_header(LBA); + + CDFile Assets[1] = { + CDFileBuilder::simple_tim(LBA::JABY_STAR, JabySTARTim), + }; +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/GTETest/include/GTE_Sprite.hpp b/examples/PoolBox/application/src/Overlay/GTETest/include/GTE_Sprite.hpp new file mode 100644 index 00000000..e6bf841f --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/GTETest/include/GTE_Sprite.hpp @@ -0,0 +1,47 @@ +#pragma once +#include +#include +#include + +#include + +namespace GTETest { + using namespace JabyEngine; + + struct GTE_Sprite { + GPU::AreaI16 area; + GPU::PositionI16 pivot; + deg_t angle; + gte_float scale; + GPU::POLY_FT4::Linked display; + + static constexpr GTE_Sprite create(const GPU::POLY_FT4::Linked& base) { + const auto rect_size = base->get_rect_size(); + return GTE_Sprite{ + .area = GPU::AreaI16::create(base->get_rect_pos(), rect_size), + .pivot = GPU::PositionI16::create(rect_size.width/2, rect_size.height/2), + .angle = 0.0_deg, + .scale = 1.0_gf, + .display = base + }; + } + + void apply(const GTE::MATRIX& gbl_matrix = GTE::MATRIX::identity()) { + const auto matrix = + GTE::MATRIX::translated(-this->pivot.x, -this->pivot.y, 0) + .rotate(0.0_deg, 0.0_deg, this->angle) + .scale(this->scale, this->scale) + .translate(this->area.position.x + this->pivot.x, this->area.position.y + this->pivot.y, 0) + .comp(gbl_matrix); + + this->display->vertex0 = matrix.apply_to(GPU::Vertex::create(0, 0)); + this->display->vertex1 = matrix.apply_to(GPU::Vertex::create(this->area.size.width, 0)); + this->display->vertex2 = matrix.apply_to(GPU::Vertex::create(0, this->area.size.height)); + this->display->vertex3 = matrix.apply_to(GPU::Vertex::create(this->area.size.width, this->area.size.height)); + } + + void render() { + GPU::render(this->display); + } + }; +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/GTETest/include/gte_test_assets.hpp b/examples/PoolBox/application/src/Overlay/GTETest/include/gte_test_assets.hpp new file mode 100644 index 00000000..cf3ef791 --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/GTETest/include/gte_test_assets.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "../../../../include/asset_mgr.hpp" +#include + +namespace GTETest { + using namespace JabyEngine; + + static constexpr auto JabySTARTim = SimpleTIM::create( + // v Doenerfisch rotates so we need some space + Assets::Main::DoenerFishInfo.tim.get_texture_x(), Assets::Main::DoenerFishInfo.tim.get_texture_y() + Assets::Main::DoenerFishInfo.size.height + 2, + Assets::Main::DoenerFishInfo.tim.get_clut_x() + 16, Assets::Main::DoenerFishInfo.tim.get_clut_y() + ); +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/Overlays.hpp b/examples/PoolBox/application/src/Overlay/Overlays.hpp new file mode 100644 index 00000000..0a7f1641 --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/Overlays.hpp @@ -0,0 +1,38 @@ +#pragma once +#include + +namespace BIOSInfo { + void main(); +} + +namespace ControllerTest { + extern const volatile JabyEngine::AutoLBAEntry lba[]; + extern JabyEngine::CDFile Assets[1]; + + void main(); +} + +namespace GPUTest { + extern const volatile JabyEngine::AutoLBAEntry lba[]; + extern JabyEngine::CDFile Assets[2]; + extern JabyEngine::CDFile LargeAssets[36]; + + void main(); +} + +namespace GTETest { + extern const volatile JabyEngine::AutoLBAEntry lba[]; + extern JabyEngine::CDFile Assets[1]; + + void main(); +} + +namespace FontCycler { + void main(); +} + +namespace ScreenCenter { + extern const volatile JabyEngine::AutoLBAEntry lba[]; + extern JabyEngine::CDFile Assets[1]; + void main(); +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ScreenCenter/frame.cpp b/examples/PoolBox/application/src/Overlay/ScreenCenter/frame.cpp new file mode 100644 index 00000000..22900b93 --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/ScreenCenter/frame.cpp @@ -0,0 +1,5 @@ +#include "include/frame.hpp" +#include + +namespace ScreenCenter { +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ScreenCenter/include/frame.hpp b/examples/PoolBox/application/src/Overlay/ScreenCenter/include/frame.hpp new file mode 100644 index 00000000..5a319d6e --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/ScreenCenter/include/frame.hpp @@ -0,0 +1,107 @@ +#pragma once +#include +#include +#include + +namespace ScreenCenter { + using namespace JabyEngine; + + class Frame { + private: + struct TopBorder : public GPU::internal::LinkedElementCreator { + GPU::TILE top_left[2]; + GPU::TILE top_right[2]; + + static constexpr TopBorder::Linked create(GPU::Color24 BaseColor, GPU::SizeI16 Size) { + TopBorder frame; + + frame.top_left[0] = Make::TILE(Make::AreaI16(0, 0, Size.width, Size.height), BaseColor); + frame.top_left[1] = Make::TILE(Make::AreaI16(0, 0, Size.height, Size.width), BaseColor); + + frame.top_right[0] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.width, 0, Size.width, Size.height), BaseColor); + frame.top_right[1] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.height, 0, Size.height, Size.width), BaseColor); + return frame.linked(); + } + }; + + struct BottomBorder : GPU::internal::LinkedElementCreator { + GPU::TILE bottom_left[2]; + GPU::TILE bottom_right[2]; + + static constexpr BottomBorder::Linked create(GPU::Color24 BaseColor, GPU::SizeI16 Size) { + BottomBorder frame; + + frame.bottom_left[0] = Make::TILE(Make::AreaI16(0, GPU::Display::Height - Size.width, Size.height, Size.width), BaseColor); + frame.bottom_left[1] = Make::TILE(Make::AreaI16(0, GPU::Display::Height - Size.height, Size.width, Size.height), BaseColor); + + frame.bottom_right[0] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.height, GPU::Display::Height - Size.width, Size.height, Size.width), BaseColor); + frame.bottom_right[1] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.width, GPU::Display::Height - Size.height, Size.width, Size.height), BaseColor); + return frame.linked(); + } + }; + + struct LineBorder : GPU::internal::LinkedElementCreator { + GPU::LINE_G_MULTI<5> border; + + static constexpr LineBorder::Linked create(int16_t offset = 0) { + const auto get_color = [](size_t idx, int16_t offset) -> GPU::Color24 { + const GPU::Color24 Colors[4] = {GPU::Color24::Red(), GPU::Color24::Green(), GPU::Color24::Blue(), GPU::Color24::Yellow()}; + + return Colors[(idx + offset)%4]; + }; + const int16_t origin = 0 + offset; + const int16_t width = GPU::Display::Width - 1 - offset; + const int16_t height = GPU::Display::Height - 1 - offset; + LineBorder frame; + + frame.border = Make::LINE_G( + GPU::ColorVertex{get_color(0, offset), Make::Vertex(origin, origin)}, + GPU::ColorVertex{get_color(1, offset), Make::Vertex(origin, height)}, + GPU::ColorVertex{get_color(2, offset), Make::Vertex(width, height)}, + GPU::ColorVertex{get_color(3, offset), Make::Vertex(width, origin)}, + GPU::ColorVertex{get_color(4, offset), Make::Vertex(origin, origin)} + ); + return frame.linked(); + } + }; + + struct LineCross : GPU::internal::LinkedElementCreator { + GPU::LINE_G_SINGLE cross[2]; + + static constexpr LineCross::Linked create(const decltype(LineBorder::border)& border) { + LineCross frame; + + frame.cross[0] = Make::LINE_G(border[0], border[2]); + frame.cross[1] = Make::LINE_G(border[3], border[1]); + return frame.linked(); + } + }; + + TopBorder::Linked top_border; + BottomBorder::Linked bottom_border; + LineBorder::Linked line_border[2]; + LineCross::Linked line_cross; + public: + static constexpr Frame create() { + constexpr auto BaseColor = GPU::Color24::from_rgb(0x1D, 0xA0, 0xA3); + constexpr auto Size = Make::SizeI16(64, 16); + + Frame frame; + + frame.top_border = TopBorder::create(BaseColor, Size); + frame.bottom_border = BottomBorder::create(BaseColor, Size); + frame.line_border[0] = LineBorder::create(); + frame.line_border[1] = LineBorder::create(1); + frame.line_cross = LineCross::create(frame.line_border[0]->border); + return frame; + } + + void setup() { + this->top_border.concat(this->bottom_border.concat(this->line_border[0].concat(this->line_border[1].concat(this->line_cross)))); + } + + void render() const { + GPU::render(this->top_border); + } + }; +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ScreenCenter/screen_center.cpp b/examples/PoolBox/application/src/Overlay/ScreenCenter/screen_center.cpp new file mode 100644 index 00000000..50aa18b4 --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/ScreenCenter/screen_center.cpp @@ -0,0 +1,209 @@ +#include "../../../include/shared.hpp" +#include "include/frame.hpp" +#include +#include +#include +#include +#include + +namespace ScreenCenter { + using namespace JabyEngine; + using GenericButton = Periphery::GenericController::Button; + + struct ButtonPulser { + static constexpr auto StartTime = 2500_ms; + static constexpr auto PulseTime = 100_ms; + + enum struct State { + WentDown, + Pulse, + Unkown + }; + + SimpleTimer timer; + uint8_t pulse_time; + + void setup() { + this->timer.reset(); + this->pulse_time = StartTime; + } + + void reset() { + ButtonPulser::setup(); + } + + State check(GenericButton button) { + const auto controller = Periphery::get_primary_controller_as(); + + if(!controller.button.was_down(button)) { + ButtonPulser::reset(); + if(controller.button.went_down(button)) { + return State::WentDown; + } + } + + if(this->timer.is_expired_for(this->pulse_time)) { + this->pulse_time = PulseTime; + this->timer.reset(); + + return State::Pulse; + } + return State::Unkown; + } + }; + + #ifdef JABYENGINE_PAL + static const char TVModeStr[] = "PAL"; + static constexpr uint16_t ScanlinesV = 288; + #else + static const char TVModeStr[] = "NTSC"; + static constexpr uint16_t ScanlinesV = 240; + #endif //JABYENGINE_PAL + + namespace PSYQ { + static const char*const Name = "PSYQ"; + + static void set_offset(uint16_t x, uint16_t y) { + GPU::Display::set_offset(x, y); + } + } + + struct Formular { + const char* name; + void (*function)(uint16_t, uint16_t); + }; + + static const Formular ScreenFormulars[] = { + Formular{.name = PSYQ::Name, .function = PSYQ::set_offset} + }; + + static constexpr const GPU::VRAM2VRAM background_img[] = { + // current_id of 0 will be rendering on (0, 256) + GPU::VRAM2VRAM::create(Make::AreaU16(384, 240, 256, 240), Make::PositionU16(32, GPU::Display::Height)), + GPU::VRAM2VRAM::create(Make::AreaU16(384, 240, 256, 240), Make::PositionU16(32, 0)), + }; + + static auto frame = Frame::create(); + + static ButtonPulser button_pulse[4]; + static void (*update)() = nullptr; + static int16_t offset_x = 0; + static int16_t offset_y = 0; + static uint8_t formular_sel = 0; + + static void update_interactive(); + static void reset_screen(); + + static void update_enter_state() { + static const char IntroductionTest[] = "Press START to begin with\n"; + static constexpr auto IntroductionTestLength = BIOSFont::Info.estimate_str_render_length(IntroductionTest); + static constexpr auto CenterPoint = Make::PositionI16((GPU::Display::Width - IntroductionTestLength)/2, (GPU::Display::Height - (2*16))/2); + + const auto controller = Periphery::get_primary_controller_as(); + + if(controller.button.went_up(GenericButton::R1) || controller.button.went_up(GenericButton::L1)) { + // Only one mode supported + //formular_sel ^= 1; + } + + if(controller.button.went_down(GenericButton::ST)) { + update = update_interactive; + } + + auto cursor = FontWriter::update(CenterPoint); + FontWriter::bios_font_writer.write(cursor, IntroductionTest, GPU::Color24::White()); + FontWriter::bios_font_writer.write(cursor, ScreenFormulars[formular_sel].name, GPU::Color24::White()); + } + + static void update_interactive() { + static const auto handle_button = [](ButtonPulser& button_pulse, GenericButton button, int16_t &dst, const int16_t mlp) { + switch(button_pulse.check(button)) { + case ButtonPulser::State::WentDown: + dst += (1*mlp); + break; + + case ButtonPulser::State::Pulse: + dst += (2*mlp); + break; + } + }; + + static const char*const ModeStr = "TV-Mode: %s\n"; + static const char*const FormularStr = "<<%s>>\n"; + static const char OffsetStr[] = "Offset: %i, %i"; + + static constexpr auto CenterLength = FontWriter::BIOSFont::Info.estimate_str_render_length(OffsetStr); + static constexpr auto CenterPoint = Make::PositionI16((GPU::Display::Width - CenterLength)/2, (GPU::Display::Height - 3*16)/2); + + const auto& screen_formular = ScreenFormulars[formular_sel]; + const auto controller = Periphery::get_primary_controller_as(); + + handle_button(button_pulse[0], GenericButton::Left, offset_x, -1); + handle_button(button_pulse[1], GenericButton::Right, offset_x, 1); + handle_button(button_pulse[2], GenericButton::Up, offset_y, -1); + handle_button(button_pulse[3], GenericButton::Down, offset_y, 1); + + if(controller.button.is_down(GenericButton::R1) && controller.button.is_down(GenericButton::L1)) { + for(auto& pulse : button_pulse) { + pulse.setup(); + } + reset_screen(); + } + + auto cursor = FontWriter::update(CenterPoint.move(-offset_x, -offset_y)); + FontWriter::bios_font_writer.write(cursor, ModeStr, GPU::Color24::White(), TVModeStr); + FontWriter::bios_font_writer.write(cursor, FormularStr, GPU::Color24::White(), screen_formular.name); + FontWriter::bios_font_writer.write(cursor, OffsetStr, GPU::Color24::White(), offset_x, offset_y); + + screen_formular.function(offset_x, offset_y); + } + + static void reset_screen() { + PSYQ::set_offset(0, 0); + offset_x = 0; + offset_y = 0; + } + + static void setup() { + Shared::back_menu.reset(); + frame.setup(); + + for(auto& pulse : button_pulse) { + pulse.setup(); + } + + update = update_enter_state; + formular_sel = 0; + offset_x = 0; + offset_y = 0; + } + + static bool update_or_exit() { + Periphery::query_controller(); + if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { + return true; + } + + update(); + return false; + } + + static void render() { + GPU::render(background_img[GPU::Display::current_id]); + frame.render(); + Shared::back_menu.render(); + } + + void main() { + setup(); + + while(true) { + if(update_or_exit()) { + reset_screen(); + break; + } + GPU::swap_buffers_vsync(1); + render(); + } + } +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ScreenCenter/screen_center_assets.cpp b/examples/PoolBox/application/src/Overlay/ScreenCenter/screen_center_assets.cpp new file mode 100644 index 00000000..6d1670bb --- /dev/null +++ b/examples/PoolBox/application/src/Overlay/ScreenCenter/screen_center_assets.cpp @@ -0,0 +1,17 @@ +#include +#include + +namespace ScreenCenter { + using namespace JabyEngine; + + enum LBA { + __jabyengine_start_lba_request + __jabyengine_request_lba_for(BG_IMAGE, "ASSETS/SAND.TIM"), + __jabyengine_end_lba_request + }; + __declare_lba_header(LBA); + + CDFile Assets[1] = { + CDFileBuilder::sony_tim(LBA::BG_IMAGE, TIM::create()) + }; +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/application.cpp b/examples/PoolBox/application/src/application.cpp new file mode 100644 index 00000000..11b9c4b8 --- /dev/null +++ b/examples/PoolBox/application/src/application.cpp @@ -0,0 +1,299 @@ +#include "../include/asset_mgr.hpp" +#include "include/font_writer.hpp" +#include "include/menu.hpp" +#include "include/paco.hpp" +#include "Overlay/Overlays.hpp" +#include +#include +#include +#include +#include +#include + +using namespace JabyEngine; +using DigitalButton = Periphery::GenericController::Button; + +struct CDPlayer { + static constexpr auto MaxChannels = 2; + + uint8_t channel; + bool is_xa; + + static constexpr CDPlayer create() { + return CDPlayer{.channel = 0, .is_xa = true}; + } + + void play() { + if(this->is_xa) { + Assets::XAAudio::play_mix(); + } + + else { + const auto [first_track, last_track] = CDDA::get_tracks(); + CDDA::play(first_track); + } + } + + void stop() { + if(this->is_xa) { + CDXA::stop(); + } + + else { + CDDA::stop(); + } + } + + void change_channel(int8_t step) { + if(this->is_xa) { + this->channel = static_cast((this->channel + step))%MaxChannels; + CDXA::set_channel(this->channel); + } + } + + void change_audio() { + CDPlayer::stop(); + this->is_xa = !this->is_xa; + CDPlayer::play(); + } + + void push() { + if(this->is_xa) { + CDXA::push_play(); + } + + else { + CDDA::push_play(); + } + } + + void pop() { + if(this->is_xa) { + CDXA::pop_play(); + } + + else { + CDDA::pop_play(); + } + } +}; + +struct StateChange { + void (*asset_load)(); + void (*main)(); + + static constexpr StateChange empty() { + return StateChange{.asset_load = nullptr, .main = nullptr}; + } + + void clear() { + this->asset_load = nullptr; + this->main = nullptr; + } + + bool contains_state() const { + return this->main; + } + + auto operator<=>(const StateChange&) const = default; +}; + +static const Menu::SimpleMenu::Entry MenuEntries[] = { + {"Controller Test"}, + {"GPU Test"}, + {"GTE Test"}, + {"Font Cycler"}, + {"Screen Center"}, + {"BIOS Information"} +}; + +static const auto doener_fish = Make::SPRT( + Make::AreaI16(Make::PositionI16(8, GPU::Display::Height - Assets::Main::DoenerFishInfo.size.height), Assets::Main::DoenerFishInfo.size), // v this needs to be nicer! Has to be + Make::OffsetPageWithClut(Assets::Main::DoenerFishInfo.tim.get_page_offset_clut4(), Make::PageClut(Assets::Main::DoenerFishInfo.tim.get_clut_position())), + GPU::Color24::Grey() +); + +static CDPlayer cd_player = CDPlayer::create(); +static object::Paco paco; +static Menu::SimpleMenu menu; +static StateChange state_changer; +static StateChange old_state_changer; + +namespace Shared { + Menu::BackMenu back_menu; + JabyEngine::GPU::POLY_G4 background = Make::POLY_G4( + Make::AreaI16(0, 0, GPU::Display::Width, GPU::Display::Height), + {GPU::Color24::Red(0xA0), GPU::Color24::Green(0xA0), GPU::Color24::Blue(0xA0), GPU::Color24::Black()} + ); + bool load_test = false; +} + +static void setup() { + Assets::Main::load(); + FontWriter::setup(); + paco.setup(); + Shared::back_menu.setup(&FontWriter::bios_font_writer); + + menu.setup([](uint32_t selection) { + switch(selection) { + case 0: + state_changer.asset_load = Assets::Overlay::load_controller_test; + state_changer.main = ControllerTest::main; + break; + + case 1: + state_changer.asset_load = Assets::Overlay::load_gpu_test; + state_changer.main = GPUTest::main; + break; + + case 2: + state_changer.asset_load = Assets::Overlay::load_gte_test; + state_changer.main = GTETest::main; + break; + + case 3: + state_changer.asset_load = Assets::Overlay::load_font_cycler; + state_changer.main = FontCycler::main; + break; + + case 4: + state_changer.asset_load = Assets::Overlay::load_screen_center; + state_changer.main = ScreenCenter::main; + break; + + case 5: + state_changer.asset_load = Assets::Overlay::load_bios_info; + state_changer.main = BIOSInfo::main; + break; + } + },MenuEntries); + cd_player.play(); +} + +namespace NormalScene { + static void update() { + static const char Title[] = ">> Pool Box <<"; + static const char Version[] = "Ver. 0.9.0"; + static constexpr auto TitleLength = DefaultFont::Info.estimate_str_render_length(Title); + static constexpr auto VersionLength = DefaultFont::Info.estimate_str_render_length(Version); + + Periphery::query_controller(); + const auto& controller = Periphery::get_primary_controller_as(); + + if(controller.is_connected()) { + if(controller.button.went_down(DigitalButton::SEL)) { + cd_player.change_audio(); + } + + if(controller.button.went_down(DigitalButton::R1)) { + cd_player.change_channel(1); + } + + if(controller.button.went_down(DigitalButton::L1)) { + cd_player.change_channel(-1); + } + + // Trigger load test + if(controller.button.is_down(DigitalButton::R2) && controller.button.is_down(DigitalButton::L2) && controller.button.is_down(DigitalButton::ST)) { + Shared::load_test = true; + } + } + + auto cursor = FontWriter::update(Make::PositionI16((GPU::Display::Width-TitleLength)/2, 16)); + paco.update(); + + FontWriter::new_font_writer.write(cursor, Title, GPU::Color24::Yellow(0xD0), &FontWriter::wiggle); + FontWriter::new_font_writer.write(cursor.change_position(Make::PositionI16((GPU::Display::Width-VersionLength)/2, 16 + DefaultFont::Info.get_kern_size().height)), Version, GPU::Color24::Green(0xD0), &FontWriter::wiggle); + menu.update(FontWriter::bios_font_writer, cursor, Make::PositionI16(8, 64)); + + cursor.change_position(Make::PositionI16(doener_fish.position.x + doener_fish.size.width, GPU::Display::Height - 48)); + FontWriter::bios_font_writer.write(cursor, "Audio:\n%s\n(SEL/R1/R2)", cd_player.is_xa ? "CD-XA" : "CD-DA"); + + if(Shared::load_test) { + // Force state change if we are in the load_test state + state_changer.asset_load = Assets::Overlay::load_large_gpu_test; + state_changer.main = GPUTest::main; + } + } + + static void render() { + GPU::render(Shared::background); + FontWriter::new_font_writer.render(); + FontWriter::bios_font_writer.render(); + paco.render(); + GPU::render(doener_fish); + } + + static void run() { + update(); + GPU::swap_buffers_vsync(1); + render(); + } +} + +namespace LoadingScene { + static SimpleTimer jaby_timer; + static uint8_t jaby_frame_offset; + + static void update() { + jaby_timer.reset(); + jaby_frame_offset = 0; + } + + static void vsync_render() { + static constexpr auto StartPosition = Make::PositionI16(24, 64); + const auto load_font = Make::SPRT( + Make::AreaI16(StartPosition.move(Assets::Main::JabyLoader::JabyFrame.size.width + 8, 0), Assets::Main::JabyLoader::FontFrame.size), + Make::OffsetPageWithClut(Assets::Main::JabyLoader::TIMLoaction.get_page_offset_clut4().move(Assets::Main::JabyLoader::FontFrame.position.x, Assets::Main::JabyLoader::FontFrame.position.y), Make::PageClut(Assets::Main::JabyLoader::TIMLoaction.get_clut_position())), + GPU::Color24::Grey() + ); + auto jaby_sprt = Make::SPRT( + Make::AreaI16(StartPosition, Assets::Main::JabyLoader::JabyFrame.size), + Make::OffsetPageWithClut(Assets::Main::JabyLoader::TIMLoaction.get_page_offset_clut4(), Make::PageClut(Assets::Main::JabyLoader::TIMLoaction.get_clut_position())), + GPU::Color24::Grey() + ); + + if(jaby_timer.is_expired_for(500_ms)) { + jaby_frame_offset = jaby_frame_offset ? 0 : 32; + jaby_timer.reset(); + } + jaby_sprt.tex_offset.add(jaby_frame_offset, 0); + + GPU::swap_buffers(!Shared::load_test); + GPU::render(jaby_sprt); + GPU::render(load_font); + jaby_sprt.position.move(Assets::Main::JabyLoader::FontFrame.size.width + Assets::Main::JabyLoader::JabyFrame.size.width + 8, 0); + GPU::render(jaby_sprt); + } + + static void run() { + if(Shared::load_test || old_state_changer != state_changer) { + GPU::set_vsync_callback(vsync_render); + + cd_player.push(); + state_changer.asset_load(); + old_state_changer = state_changer; + cd_player.pop(); + + GPU::set_vsync_callback(nullptr); + } + + state_changer.main(); + state_changer.clear(); + } +} + +void main() { + const auto& controller = Periphery::get_primary_controller_as(); + + setup(); + while(true) { + if(state_changer.contains_state()) { + LoadingScene::run(); + } + + else { + NormalScene::run(); + } + } +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/asset_mgr.cpp b/examples/PoolBox/application/src/asset_mgr.cpp new file mode 100644 index 00000000..8f19c5bc --- /dev/null +++ b/examples/PoolBox/application/src/asset_mgr.cpp @@ -0,0 +1,135 @@ +#include "../include/asset_mgr.hpp" +#include "Custom/custom_files.hpp" +#include "Overlay/Overlays.hpp" +#include +#include +#include +#include +#include + +extern "C" uint32_t __bios_info_start; +extern "C" uint32_t __controller_tests_start; +extern "C" uint32_t __gpu_tests_start; +extern "C" uint32_t __gte_tests_start; +extern "C" uint32_t __font_cycler_start; +extern "C" uint32_t __screen_center_start; + +namespace Assets { + enum LBA { + __jabyengine_start_lba_request + __jabyengine_request_lba_for(PACO, "ASSETS/MAIN/PACO.IMG"), + __jabyengine_request_lba_for(DFISH, "ASSETS/MAIN/DFISH.IMG"), + __jabyengine_request_lba_for(JABY_LOAD, "ASSETS/MAIN/LOAD.IMG"), + __jabyengine_request_lba_for(APPLE_SFX, "SFX/APPLE.VAG"), + __jabyengine_request_lba_for(BLUBB_SFX, "SFX/BLUBB.VAG"), + __jabyengine_request_lba_for(FRIEND_SFX, "SFX/FRIEND.VAG"), + __jabyengine_request_lba_for(MIX_XA, "XAAUDIO/MIX.XA"), + __jabyengine_request_lba_for(BIOS_INFO_OVL, "BIO.BIN"), + __jabyengine_request_lba_for(GPU_TEST_OVL, "GTO.BIN"), + __jabyengine_request_lba_for(GTE_TEST_OVL, "GTE.BIN"), + __jabyengine_request_lba_for(CONT_TEST_OVL, "CTO.BIN"), + __jabyengine_request_lba_for(FONT_CYC_OVL, "FCO.BIN"), + __jabyengine_request_lba_for(SCREEN_CENT_OVL, "SCO.BIN"), + __jabyengine_end_lba_request + }; + __declare_lba_header(LBA); + + static void load(const volatile AutoLBAEntry* lba, const CDFile* assets, size_t size) { + const auto buffer_cfg = CDFileProcessor::BufferConfiguration::new_default(); + CDFileProcessor file_processor; + + file_processor.setup(lba, CDFileProcessor::JobArray{assets, size}, buffer_cfg); + while(true) { + switch(file_processor.process()) { + case Progress::InProgress: + break; + + case Progress::Done: + if(!file_processor.next(lba, buffer_cfg)) { + return; + } + break; + + case Progress::Error: + printf("Error detected! Aborting load\n"); + return; + } + } + file_processor.shutdown(); + } + + template + static void load(const volatile AutoLBAEntry* lba, const CDFile (&files)[N]) { + return load(lba, files, N); + } + + namespace Main { + using SPU::operator""_vol; + + static const CDFile Files[] = { + CDFileBuilder::simple_tim(LBA::PACO, PacoTIM), + CDFileBuilder::simple_tim(LBA::DFISH, DoenerFishInfo.tim), + CDFileBuilder::simple_tim(LBA::JABY_LOAD, JabyLoader::TIMLoaction), + CDFileBuilder::sony_vag(LBA::APPLE_SFX, VAG::create(0, 1.0_vol)), + CDFileBuilder::sony_vag(LBA::BLUBB_SFX, VAG::create(1, 1.0_vol)), + CDFileBuilder::sony_vag(LBA::FRIEND_SFX, VAG::create(2, 1.0_vol)), + CustomCDFileBuilder::jingle(2), + }; + + void load() { + ::Assets::load(lba, Files); + } + } + + namespace Overlay { + static void load(const CDFile& overlay_file, const volatile AutoLBAEntry* overlay_lba, const CDFile* overlay_assets, size_t size) { + ::Assets::load(lba, &overlay_file, 1); + if(overlay_lba) { + ::Assets::load(overlay_lba, overlay_assets, size); + } + } + + static void load(const CDFile& overlay_file) { + load(overlay_file, nullptr, nullptr, 0ull); + } + + template + static void load(const CDFile& overlay_file, const volatile AutoLBAEntry* overlay_lba, const CDFile (&overlay_assets)[N]) { + load(overlay_file, overlay_lba, overlay_assets, N); + } + + void load_bios_info() { + load(CDFileBuilder::overlay(LBA::BIOS_INFO_OVL, &__bios_info_start)); + } + + void load_controller_test() { + load(CDFileBuilder::overlay(LBA::CONT_TEST_OVL, &__controller_tests_start), ControllerTest::lba, ControllerTest::Assets); + } + + void load_gpu_test() { + load(CDFileBuilder::overlay(LBA::GPU_TEST_OVL, &__gpu_tests_start), GPUTest::lba, GPUTest::Assets); + } + + void load_large_gpu_test() { + load(CDFileBuilder::overlay(LBA::GPU_TEST_OVL, &__gpu_tests_start), GPUTest::lba, GPUTest::LargeAssets); + } + + void load_gte_test() { + load(CDFileBuilder::overlay(LBA::GTE_TEST_OVL, &__gte_tests_start), GTETest::lba, GTETest::Assets); + } + + void load_font_cycler() { + load(CDFileBuilder::overlay(LBA::FONT_CYC_OVL, &__font_cycler_start)); + } + + void load_screen_center() { + load(CDFileBuilder::overlay(LBA::SCREEN_CENT_OVL, &__screen_center_start), ScreenCenter::lba, ScreenCenter::Assets); + } + } + + namespace XAAudio { + void play_mix() { + CDXA::play(lba, MIX_XA, 0, false); + } + } +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/font_writer.cpp b/examples/PoolBox/application/src/font_writer.cpp new file mode 100644 index 00000000..3ee50adc --- /dev/null +++ b/examples/PoolBox/application/src/font_writer.cpp @@ -0,0 +1,35 @@ +#include "include/font_writer.hpp" +#include +#include //< only for __heap_start D: +#include + +namespace FontWriter { + using namespace JabyEngine; + + static constexpr auto LibraryFontTIM = SimpleTIM::create(320, 0, 320, DefaultFont::Info.texture_size.height); + + static FontPrimitive font_buffer[2*256]; + Wiggle wiggle = {Make::PositionI8(0, 0), Make::PositionI8(1, -2), Make::PositionI8(0, -4), Make::PositionI8(-1, -2), Make::PositionI8(0, 0), Make::PositionI8(1, 2), Make::PositionI8(0, 4), Make::PositionI8(-1, 2)}; + JabyEngine::FontWriter new_font_writer = JabyEngine::FontWriter::empty(); + JabyEngine::FontWriter bios_font_writer = JabyEngine::FontWriter::empty(); + static SimpleTimer timer; + uint8_t wiggle_count = 0; + + void setup() { + JabyEngine::DefaultFont::load(&__heap_start, LibraryFontTIM); + JabyEngine::GlobalFontPrimitivePool::setup(font_buffer); + + new_font_writer.setup(LibraryFontTIM, JabyEngine::DefaultFont::Info); + bios_font_writer.setup(JabyEngine::BIOSFont::TIM, JabyEngine::BIOSFont::Info); + timer.reset(); + } + + Cursor update(const GPU::PositionI16& start) { + if(timer.is_expired_for(50_ms)) { + timer.reset(); + wiggle_count++; + } + + return Cursor::create(start, wiggle_count); + } +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/include/font_writer.hpp b/examples/PoolBox/application/src/include/font_writer.hpp new file mode 100644 index 00000000..8397a0ec --- /dev/null +++ b/examples/PoolBox/application/src/include/font_writer.hpp @@ -0,0 +1,14 @@ +#pragma once +#include +#include + +namespace FontWriter { + using namespace JabyEngine; + + extern Wiggle wiggle; + extern JabyEngine::FontWriter new_font_writer; + extern JabyEngine::FontWriter bios_font_writer; + + void setup(); + Cursor update(const GPU::PositionI16& start); +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/include/menu.hpp b/examples/PoolBox/application/src/include/menu.hpp new file mode 100644 index 00000000..37c29760 --- /dev/null +++ b/examples/PoolBox/application/src/include/menu.hpp @@ -0,0 +1,50 @@ +#pragma once +#include "font_writer.hpp" +#include +#include + +namespace Menu { + using namespace JabyEngine; + + class SimpleMenu { + public: + struct Entry { + const char* name; + }; + + typedef void (*Callback)(uint32_t selection); + + private: + Callback selection_callback; + const Entry* entries; + size_t size; + uint8_t cur_selection; + + public: + void setup(Callback callback, const Entry* entries, size_t size); + + template + void setup(Callback callback, const Entry (&entries)[N]) { + SimpleMenu::setup(callback, entries, N); + } + + void update(JabyEngine::FontWriter& font_writer, Cursor& cursor, const GPU::PositionI16& start); + }; + + class BackMenu { + private: + JabyEngine::FontWriter* font_writer; + SimpleTimer timeout; + bool waiting; + + public: + void setup(JabyEngine::FontWriter* font_writer); + void reset() { + this->timeout.reset(); + this->waiting = false; + } + + bool update(const GPU::PositionI16& position, bool auto_clear = true); + void render(); + }; +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/include/paco.hpp b/examples/PoolBox/application/src/include/paco.hpp new file mode 100644 index 00000000..ab64ccc8 --- /dev/null +++ b/examples/PoolBox/application/src/include/paco.hpp @@ -0,0 +1,35 @@ +#pragma once +#include "../../include/asset_mgr.hpp" +#include +#include + +namespace object { + using namespace JabyEngine; + + class Paco { + private: + static constexpr auto Size = Make::SizeI16(120, 128); + static const GPU::Color24 Colors[]; + + GPU::TexPage::Linked tex_page; + GPU::SPRT::Linked sprite; + SimpleTimer timer; + uint8_t color_idx; + + public: + constexpr Paco() : + tex_page(Make::TexPage(Make::PositionU16( + Assets::Main::PacoTIM.get_texture_x(), Assets::Main::PacoTIM.get_texture_y()), + GPU::TextureColorMode::clut4).linked()), + sprite(Make::SPRT( + Make::AreaI16(Make::PositionI16(GPU::Display::Width - Size.width, GPU::Display::Height - Size.height), Size), + Make::OffsetPageWithClut(Make::PageOffset(0, 0), Make::PageClut(Assets::Main::PacoTIM.get_clut_x(), Assets::Main::PacoTIM.get_clut_y())), + GPU::Color24::Blue()).linked()), + timer(), + color_idx(0) {} + + void setup(); + void update(); + void render(); + }; +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/menu.cpp b/examples/PoolBox/application/src/menu.cpp new file mode 100644 index 00000000..1dcbfd09 --- /dev/null +++ b/examples/PoolBox/application/src/menu.cpp @@ -0,0 +1,81 @@ +#include "../include/shared.hpp" +#include "include/menu.hpp" +#include +#include + +namespace Menu { + using DigitalButton = Periphery::GenericController::Button; + + void SimpleMenu :: setup(Callback callback, const Entry* entries, size_t size) { + this->selection_callback = callback; + this->entries = entries; + this->size = size; + this->cur_selection = 0; + } + + void SimpleMenu :: update(JabyEngine::FontWriter& font_writer, Cursor& cursor, const GPU::PositionI16& start) { + const auto& controller = Periphery::get_primary_controller_as(); + + if(controller.button.went_down(DigitalButton::Up) && this->cur_selection > 0) { + this->cur_selection -= 1; + } + + if(controller.button.went_down(DigitalButton::Down) && this->cur_selection < (this->size - 1)) { + this->cur_selection += 1; + } + + if(controller.button.went_down(DigitalButton::Cross)) { + SPU::voice[0].play(); + this->selection_callback(this->cur_selection); + } + + cursor.pos = Make::PositionI16(8, 64); + for(size_t n = 0; n < this->size; n++) { + const auto& cur_entry = this->entries[n]; + + if(this->cur_selection == n) { + FontWriter::bios_font_writer.write(cursor, ">%s<\n", cur_entry.name); + } + + else { + FontWriter::bios_font_writer.write(cursor, "%s\n", cur_entry.name); + } + } + } + + void BackMenu :: setup(JabyEngine::FontWriter* font_writer) { + this->font_writer = font_writer; + this->timeout.reset(); + this->waiting = false; + } + + bool BackMenu :: update(const GPU::PositionI16& position, bool auto_clear) { + const auto& controller = Periphery::get_primary_controller_as(); + + if(Shared::load_test || controller.button.is_down(DigitalButton::Circle)) { + this->waiting = true; + if(this->timeout.is_expired_for(2500_ms)) { + return true; + } + } + + else { + this->waiting = false; + this->timeout.reset(); + } + + if(this->waiting) { + auto cursor = JabyEngine::Cursor::create(position); + this->font_writer->write(cursor, "Press and hold O\nto get back", GPU::Color24::Red(0xD0)); + } + + else if(auto_clear) { + this->font_writer->clear(); + } + return false; + } + + void BackMenu :: render() { + this->font_writer->render(); + } +} \ No newline at end of file diff --git a/examples/PoolBox/application/src/paco.cpp b/examples/PoolBox/application/src/paco.cpp new file mode 100644 index 00000000..24862d24 --- /dev/null +++ b/examples/PoolBox/application/src/paco.cpp @@ -0,0 +1,24 @@ +#include "include/paco.hpp" + +namespace object { + const GPU::Color24 Paco :: Colors[] = {GPU::Color24::Red(), GPU::Color24::Green(), GPU::Color24::Blue(), GPU::Color24::Yellow()}; + + void Paco :: setup() { + this->timer.reset(); + this->tex_page.concat(this->sprite); + } + + void Paco :: update() { + if(this->timer.is_expired_for(325_ms)) { + static constexpr uint8_t LastIDX = (sizeof(Paco::Colors)/sizeof(Paco::Colors[0])) - 1; + + this->color_idx = (this->color_idx == LastIDX) ? 0 : this->color_idx + 1; + this->timer.reset(); + } + } + + void Paco :: render() { + this->sprite->color = Paco::Colors[this->color_idx]; + GPU::render(this->tex_page); + } +} \ No newline at end of file diff --git a/examples/PoolBox/assets/AllTheJaby.png b/examples/PoolBox/assets/AllTheJaby.png new file mode 100644 index 00000000..c7a95939 --- /dev/null +++ b/examples/PoolBox/assets/AllTheJaby.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fcb7f29d021b384b1afff8d654a4abee39c855408332c0c63a6938e055852322 +size 539396 diff --git a/examples/PoolBox/assets/Controller.png b/examples/PoolBox/assets/Controller.png new file mode 100644 index 00000000..bda9d4e6 --- /dev/null +++ b/examples/PoolBox/assets/Controller.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5e2ffa4a4ced3d6dbb833a988088f4e3426914df301a03ed1447f4f71367ce44 +size 5070 diff --git a/examples/PoolBox/assets/IMG_6921.png b/examples/PoolBox/assets/IMG_6921.png new file mode 100644 index 00000000..03c8139e --- /dev/null +++ b/examples/PoolBox/assets/IMG_6921.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f99dd1cd3bb0169428c4b9a3376b0cc09b23bac62c1fca91ef452057251e853b +size 21666 diff --git a/examples/PoolBox/assets/IconTexture.png b/examples/PoolBox/assets/IconTexture.png new file mode 100644 index 00000000..d1af743b --- /dev/null +++ b/examples/PoolBox/assets/IconTexture.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4ab27c037b82e661ec89c8275635bd585b1199848744894a200158b05e76783f +size 26787 diff --git a/examples/PoolBox/assets/JabyStar.png b/examples/PoolBox/assets/JabyStar.png new file mode 100644 index 00000000..ba9ced3f --- /dev/null +++ b/examples/PoolBox/assets/JabyStar.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f7653325bc3da6876f2125710e973ff9dbf6eb563a1959255692d29c642757b7 +size 5334 diff --git a/examples/PoolBox/assets/JabyTails.png b/examples/PoolBox/assets/JabyTails.png new file mode 100644 index 00000000..a07750e4 --- /dev/null +++ b/examples/PoolBox/assets/JabyTails.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:49577dbd3b72299e84a2e252e457fd40ce496a51e2179533239d9d2959d3f995 +size 9345 diff --git a/examples/PoolBox/assets/Makefile b/examples/PoolBox/assets/Makefile new file mode 100644 index 00000000..dc7fc71f --- /dev/null +++ b/examples/PoolBox/assets/Makefile @@ -0,0 +1,66 @@ +include $(JABY_ENGINE_DIR)/mkfile/common/ExportPath.mk +include $(JABY_ENGINE_DIR)/mkfile/common/RebuildTarget.mk + +OUTPUT_DIR = bin +CLUT_4_COLOR_TRANS_FLAGS = simple-tim clut4 --color-trans + +# Ressources to convert +## Music tracks +INPUT += $(OUTPUT_DIR)/Evacuation_cdda.xa +INPUT += $(OUTPUT_DIR)/OnMyOwn_BailBonds.xa +INPUT += $(OUTPUT_DIR)/apple.vag +INPUT += $(OUTPUT_DIR)/blubb-mono.vag +INPUT += $(OUTPUT_DIR)/Friendship_samp.vag + +## Images +INPUT += $(OUTPUT_DIR)/TexturePage.img +TexturePage_FLAGS = simple-tim clut4 + +INPUT += $(OUTPUT_DIR)/IconTexture.img +IconTexture_FLAGS = simple-tim clut4 --semi-trans --color-trans + +INPUT += $(OUTPUT_DIR)/Paco.img +Paco_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS) + +INPUT += $(OUTPUT_DIR)/Controller.img +Controller_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS) + +INPUT += $(OUTPUT_DIR)/doener_fish.img +doener_fish_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS) + +INPUT += $(OUTPUT_DIR)/JabyStar.img +JabyStar_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS) + +INPUT += $(OUTPUT_DIR)/JabyTails.img +JabyTails_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS) + +INPUT += $(OUTPUT_DIR)/IMG_6921.tim +IMG_6921_TIM_FLAGS = tim full16 --clut-pos {384,255} --tex-pos {384,256} + +INPUT += $(OUTPUT_DIR)/AllTheJaby.tim +AllTheJaby_TIM_FLAGS = tim full16 --tex-pos {0,0} + +$(OUTPUT_DIR)/%.vag: audio/%.wav + @mkdir -p $(OUTPUT_DIR) + psxfileconv --lz4 $< -o $@ vag + +$(OUTPUT_DIR)/OnMyOwn_BailBonds.xa: audio/OnMyOwn_BailBonds.mp3 + @mkdir -p $(OUTPUT_DIR) + psxfileconv $< -o $@ xa + +$(OUTPUT_DIR)/%.xa: audio/%.wav + @mkdir -p $(OUTPUT_DIR) + psxfileconv $< -o $@ xa + +$(OUTPUT_DIR)/%.img: %.png + @mkdir -p $(OUTPUT_DIR) + psxfileconv --lz4 $< -o $@ $($*_FLAGS) + +$(OUTPUT_DIR)/%.tim: %.png + @mkdir -p $(OUTPUT_DIR) + psxfileconv --lz4 $< -o $@ $($*_TIM_FLAGS) + +all: $(INPUT) + +clean: + rm -fr $(OUTPUT_DIR) \ No newline at end of file diff --git a/examples/PoolBox/assets/Paco.png b/examples/PoolBox/assets/Paco.png new file mode 100644 index 00000000..b508457a --- /dev/null +++ b/examples/PoolBox/assets/Paco.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12cfc332393318a2e22b53493297574de6a2fd58146d901fdbbe102d79ac8d04 +size 5510 diff --git a/examples/PoolBox/assets/TexturePage.png b/examples/PoolBox/assets/TexturePage.png new file mode 100644 index 00000000..e6d6439f --- /dev/null +++ b/examples/PoolBox/assets/TexturePage.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:14e167b003e1335945cf53ea2a1dc38e75e52b429900e745546cef0a91e5036e +size 350 diff --git a/examples/PoolBox/assets/audio/Evacuation_cdda.wav b/examples/PoolBox/assets/audio/Evacuation_cdda.wav new file mode 100644 index 00000000..b32b0e4d --- /dev/null +++ b/examples/PoolBox/assets/audio/Evacuation_cdda.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:01f1dc9922d783b621ace7db1179c9915c066712664a0cff2ec04d8e13bb7550 +size 20412078 diff --git a/examples/PoolBox/assets/audio/Friendship_samp.wav b/examples/PoolBox/assets/audio/Friendship_samp.wav new file mode 100644 index 00000000..ed141ca8 --- /dev/null +++ b/examples/PoolBox/assets/audio/Friendship_samp.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cf9912a199e7b09f064ce96a0f84d60b2521aa3bf5f27b0f03157a100ed79d6e +size 184364 diff --git a/examples/PoolBox/assets/audio/OnMyOwn_BailBonds.mp3 b/examples/PoolBox/assets/audio/OnMyOwn_BailBonds.mp3 new file mode 100644 index 00000000..ed219df9 --- /dev/null +++ b/examples/PoolBox/assets/audio/OnMyOwn_BailBonds.mp3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bcfdb99621b65241e027ffac7a31f499356b732124045698386bf35cc1aa99d9 +size 8193082 diff --git a/examples/PoolBox/assets/audio/apple.wav b/examples/PoolBox/assets/audio/apple.wav new file mode 100644 index 00000000..8562b61f --- /dev/null +++ b/examples/PoolBox/assets/audio/apple.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:822e8486397f99d2cc060c02a2364cb9e3805bc2326d1fc44d88153f53a31787 +size 57204 diff --git a/examples/PoolBox/assets/audio/blubb-mono.wav b/examples/PoolBox/assets/audio/blubb-mono.wav new file mode 100644 index 00000000..c70774b0 --- /dev/null +++ b/examples/PoolBox/assets/audio/blubb-mono.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:164d2f75349bcce06413d8e8de0ce346ccfc6303e3fc014e4cc8cb97b3c57feb +size 23320 diff --git a/examples/PoolBox/assets/audio/jlbrock44_Three_Kings_Funk_cdda_ready.wav b/examples/PoolBox/assets/audio/jlbrock44_Three_Kings_Funk_cdda_ready.wav new file mode 100644 index 00000000..22901976 --- /dev/null +++ b/examples/PoolBox/assets/audio/jlbrock44_Three_Kings_Funk_cdda_ready.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:db843da5092202b9c63331c69fd80d1639e6d2055211795ede327bf3460fcc44 +size 39023054 diff --git a/examples/PoolBox/assets/doener_fish.png b/examples/PoolBox/assets/doener_fish.png new file mode 100644 index 00000000..d524591c --- /dev/null +++ b/examples/PoolBox/assets/doener_fish.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3d7a9e1c2888e552bb0e36123c371a0d9f2ca88f395dc13c3498f62991f7dad7 +size 599 diff --git a/examples/PoolBox/assets/pkg/Background.png b/examples/PoolBox/assets/pkg/Background.png new file mode 100644 index 00000000..c0b14427 --- /dev/null +++ b/examples/PoolBox/assets/pkg/Background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:db524314dc0a0599628e2cbdfa8d028b83408472aaee7d034fd2614c87993d59 +size 18231 diff --git a/examples/PoolBox/assets/pkg/Icon.png b/examples/PoolBox/assets/pkg/Icon.png new file mode 100644 index 00000000..244c13cc --- /dev/null +++ b/examples/PoolBox/assets/pkg/Icon.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c9989d18bff0900db51d1443907f331edef8994215344ccd1e784eff75807c7c +size 23561 diff --git a/examples/PoolBox/assets/pkg/Title.png b/examples/PoolBox/assets/pkg/Title.png new file mode 100644 index 00000000..b3d48dde --- /dev/null +++ b/examples/PoolBox/assets/pkg/Title.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6046e90aa7a2a4e3ed837b95859192d416ca26f64e51404f09d01fee7a027567 +size 71708 diff --git a/examples/PoolBox/iso/Config.xml b/examples/PoolBox/iso/Config.xml new file mode 100644 index 00000000..1a144b2b --- /dev/null +++ b/examples/PoolBox/iso/Config.xml @@ -0,0 +1,60 @@ + + + + Jaby + + %PSX_LICENSE_PATH%/%PSX_LICENSE%.DAT + + + + + System.cnf.subst +
../application/bin/%PSX_TV_FORMAT%/PSX-release/PoolBox.psexe
+ ../application/bin/%PSX_TV_FORMAT%/PSX-release/Overlay.bios_info + ../application/bin/%PSX_TV_FORMAT%/PSX-release/Overlay.controller_tests + ../application/bin/%PSX_TV_FORMAT%/PSX-release/Overlay.gpu_tests + ../application/bin/%PSX_TV_FORMAT%/PSX-release/Overlay.gte_tests + ../application/bin/%PSX_TV_FORMAT%/PSX-release/Overlay.font_cycler + ../application/bin/%PSX_TV_FORMAT%/PSX-release/Overlay.screen_center + + + + +
+ ../assets/audio/jlbrock44_Three_Kings_Funk_cdda_ready.wav +
\ No newline at end of file diff --git a/examples/PoolBox/iso/Makefile b/examples/PoolBox/iso/Makefile new file mode 100644 index 00000000..925d0bd1 --- /dev/null +++ b/examples/PoolBox/iso/Makefile @@ -0,0 +1,2 @@ +include $(JABY_ENGINE_DIR)/mkfile/ISOMakefile.mk +include $(JABY_ENGINE_DIR)/mkfile/common/RebuildTarget.mk \ No newline at end of file diff --git a/examples/PoolBox/iso/System.cnf.subst b/examples/PoolBox/iso/System.cnf.subst new file mode 100644 index 00000000..35c95beb --- /dev/null +++ b/examples/PoolBox/iso/System.cnf.subst @@ -0,0 +1,4 @@ +BOOT=cdrom:\%PSX_BOOT_FILE%;1 +TCB=4 +EVENT=10 +STACK=801FFFF0 \ No newline at end of file diff --git a/include/PSX/Audio/CDDA.hpp b/include/PSX/Audio/CDDA.hpp new file mode 100644 index 00000000..acb6fc89 --- /dev/null +++ b/include/PSX/Audio/CDDA.hpp @@ -0,0 +1,23 @@ +#pragma once +#include "../jabyengine_defines.hpp" + +namespace JabyEngine { + namespace CDDA { + struct TrackList { + uint8_t first_track; + uint8_t last_track; + + static constexpr TrackList empty() { + return TrackList{.first_track = 0, .last_track = 0}; + } + }; + + TrackList get_tracks(); + + void play(uint8_t track); + void stop(); + + void push_play(); + void pop_play(); + } +} \ No newline at end of file diff --git a/include/PSX/Audio/CDXA.hpp b/include/PSX/Audio/CDXA.hpp new file mode 100644 index 00000000..d4506b5d --- /dev/null +++ b/include/PSX/Audio/CDXA.hpp @@ -0,0 +1,14 @@ +#pragma once +#include "../AutoLBA/auto_lba.hpp" + +namespace JabyEngine { + namespace CDXA { + void play(const volatile AutoLBAEntry* lba, uint8_t rel_lba_idx, uint8_t channel, bool double_speed); + void stop(); + + void set_channel(uint8_t channel); + + void push_play(); + void pop_play(); + } +} \ No newline at end of file diff --git a/include/PSX/AutoLBA/auto_lba.hpp b/include/PSX/AutoLBA/auto_lba.hpp index 51291181..8b53a18e 100644 --- a/include/PSX/AutoLBA/auto_lba.hpp +++ b/include/PSX/AutoLBA/auto_lba.hpp @@ -1,5 +1,4 @@ -#ifndef __JABYENGINE_AUTO_LBA_HPP__ -#define __JABYENGINE_AUTO_LBA_HPP__ +#pragma once #include "../Auxiliary/bits.hpp" namespace JabyEngine { @@ -39,6 +38,4 @@ namespace JabyEngine { return const_cast(this)->is_lz4(); } }; -} - -#endif //!__JABYENGINE_AUTO_LBA_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/AutoLBA/auto_lba_declaration.hpp b/include/PSX/AutoLBA/auto_lba_declaration.hpp index ae8fea74..82a54238 100644 --- a/include/PSX/AutoLBA/auto_lba_declaration.hpp +++ b/include/PSX/AutoLBA/auto_lba_declaration.hpp @@ -1,9 +1,6 @@ -#ifndef __JABYENGINE_AUTO_LBA_DECLARATION_HPP__ -#define __JABYENGINE_AUTO_LBA_DECLARATION_HPP__ - +#pragma once extern const volatile JabyEngine::AutoLBAEntry lba[]; #define __declare_lba_header(enum_struct) \ [[gnu::used]] \ const volatile JabyEngine::AutoLBAEntry __section(".header.lbas") lba[static_cast(enum_struct::EndOfRequest)] = {0} -#endif //!__JABYENGINE_AUTO_LBA_DECLARATION_HPP__ \ No newline at end of file diff --git a/include/PSX/Auxiliary/array_range.hpp b/include/PSX/Auxiliary/array_range.hpp index c1378cc4..b473bd2e 100644 --- a/include/PSX/Auxiliary/array_range.hpp +++ b/include/PSX/Auxiliary/array_range.hpp @@ -1,6 +1,5 @@ -#ifndef __JABYENGINE_ARRAY_RANGE_HPP__ -#define __JABYENGINE_ARRAY_RANGE_HPP__ -#include "../../stddef.h" +#pragma once +#include "../../stddef.hpp" namespace JabyEngine { template @@ -39,6 +38,4 @@ namespace JabyEngine { return this->start[idx]; } }; -} - -#endif //!__JABYENGINE_ARRAY_RANGE_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/Auxiliary/big_endian.hpp b/include/PSX/Auxiliary/big_endian.hpp new file mode 100644 index 00000000..4e24c32b --- /dev/null +++ b/include/PSX/Auxiliary/big_endian.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "../jabyengine_defines.hpp" + +namespace JabyEngine { + // Taken from boost endian + + static constexpr uint8_t read_be(uint8_t x) { + return x; + } + + static constexpr uint16_t read_be(uint16_t x) { + return (x << 8) | (x >> 8); + } + + static constexpr uint32_t read_be(uint32_t x) { + const uint32_t step16 = x << 16 | x >> 16; + return ((step16 << 8) & 0xff00ff00) | ((step16 >> 8) & 0x00ff00ff); + } +} \ No newline at end of file diff --git a/include/PSX/Auxiliary/bits.hpp b/include/PSX/Auxiliary/bits.hpp index 2e2cce79..9f8bce3f 100644 --- a/include/PSX/Auxiliary/bits.hpp +++ b/include/PSX/Auxiliary/bits.hpp @@ -1,6 +1,5 @@ -#ifndef __JABYENGINE_BITS_HPP__ -#define __JABYENGINE_BITS_HPP__ -#include "../jabyengine_defines.h" +#pragma once +#include "../jabyengine_defines.hpp" #include "types.hpp" namespace JabyEngine { @@ -151,7 +150,10 @@ namespace JabyEngine { return *reinterpret_cast(&value); } } + + static constexpr uint32_t operator<<(uint32_t value, const Bit& bit) { + return value << bit.pos; + } } -#define __start_end_bit2_start_length(start_bit, end_bit) start_bit, (end_bit - start_bit + 1) -#endif //!__JABYENGINE_BITS_HPP__ \ No newline at end of file +#define __start_end_bit2_start_length(start_bit, end_bit) start_bit, (end_bit - start_bit + 1) \ No newline at end of file diff --git a/include/PSX/Auxiliary/circular_buffer.hpp b/include/PSX/Auxiliary/circular_buffer.hpp index c68f3631..88ada439 100644 --- a/include/PSX/Auxiliary/circular_buffer.hpp +++ b/include/PSX/Auxiliary/circular_buffer.hpp @@ -1,5 +1,4 @@ -#ifndef __JABYENGINE_CIRCULAR_BUFFER_HPP__ -#define __JABYENGINE_CIRCULAR_BUFFER_HPP__ +#pragma once #include "array_range.hpp" namespace JabyEngine { @@ -59,6 +58,4 @@ namespace JabyEngine { return (this->read_adr != this->write_adr); } }; -} - -#endif //!__JABYENGINE_CIRCULAR_BUFFER_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/Auxiliary/literals.hpp b/include/PSX/Auxiliary/literals.hpp new file mode 100644 index 00000000..e328aff7 --- /dev/null +++ b/include/PSX/Auxiliary/literals.hpp @@ -0,0 +1,30 @@ +#pragma once +#include "../../stdint.hpp" + +static constexpr int8_t operator""_i8(unsigned long long int value) { + return static_cast(value); +} + +static constexpr uint8_t operator""_u8(unsigned long long int value) { + return static_cast(value); +} + +// ################################################################### + +static constexpr int16_t operator""_i16(unsigned long long int value) { + return static_cast(value); +} + +static constexpr uint16_t operator""_u16(unsigned long long int value) { + return static_cast(value); +} + +// ################################################################### + +static constexpr int32_t operator""_i32(unsigned long long int value) { + return static_cast(value); +} + +static constexpr uint32_t operator""_u32(unsigned long long int value) { + return static_cast(value); +} \ No newline at end of file diff --git a/include/PSX/Auxiliary/lz4_decompressor.hpp b/include/PSX/Auxiliary/lz4_decompressor.hpp index 0ebd7b90..cf235949 100644 --- a/include/PSX/Auxiliary/lz4_decompressor.hpp +++ b/include/PSX/Auxiliary/lz4_decompressor.hpp @@ -1,6 +1,5 @@ -#ifndef __JABYENGINE_LZ4_DECOMPRESSOR_HPP__ -#define __JABYENGINE_LZ4_DECOMPRESSOR_HPP__ -#include "../../stddef.h" +#pragma once +#include "../../stddef.hpp" #include "array_range.hpp" #include "types.hpp" @@ -76,6 +75,4 @@ namespace JabyEngine { Result process(ArrayRange data, bool is_last); }; -} - -#endif //!__JABYENGINE_LZ4_DECOMPRESSOR_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/Auxiliary/math_helper.hpp b/include/PSX/Auxiliary/math_helper.hpp index 9a8d4c9e..1f022241 100644 --- a/include/PSX/Auxiliary/math_helper.hpp +++ b/include/PSX/Auxiliary/math_helper.hpp @@ -1,8 +1,18 @@ -#ifndef __JABYENGINE_MATH_HELPER_HPP__ -#define __JABYENGINE_MATH_HELPER_HPP__ +#pragma once #include "types.hpp" +#include namespace JabyEngine { + template + static constexpr T pow(T base, T power) { + T result = base; + while(power > 1) { + result = result*base; + power--; + } + return result; + } + template static constexpr pair div_and_mod(T value, T div) { const auto result = value/div; @@ -13,6 +23,25 @@ namespace JabyEngine { const auto [tenth, rest] = div_and_mod(value, static_cast(10)); return (tenth << 4 | rest); } -} -#endif //!__JABYENGINE_MATH_HELPER_HPP__ \ No newline at end of file + template + static constexpr T from_bcd(T value) { + T result = 0; + + for(size_t n = 1; n < pow(10u, sizeof(T)*2); n *= 10) { + result += (value & 0b1111)*n; + value = value >> 4; + } + return result; + } + + template + static constexpr T min_of(T a, T b) { + return (a < b) ? a : b; + } + + template + static constexpr T max_of(T a, T b) { + return (a > b) ? a : b; + } +} \ No newline at end of file diff --git a/include/PSX/Auxiliary/mem_dump.hpp b/include/PSX/Auxiliary/mem_dump.hpp new file mode 100644 index 00000000..41839db5 --- /dev/null +++ b/include/PSX/Auxiliary/mem_dump.hpp @@ -0,0 +1,14 @@ +#pragma once +#include + +namespace JabyEngine { + template + static inline void dump_to_stdoutln(const T& object) { + const uint8_t* raw_ptr = reinterpret_cast(&object); + + for(size_t raw_pos = 0; raw_pos < sizeof(T); raw_pos++) { + printf("[%02X]", raw_ptr[raw_pos]); + } + printf("\n"); + } +} diff --git a/include/PSX/Auxiliary/type_traits.hpp b/include/PSX/Auxiliary/type_traits.hpp new file mode 100644 index 00000000..8ca970c5 --- /dev/null +++ b/include/PSX/Auxiliary/type_traits.hpp @@ -0,0 +1,95 @@ +#pragma once + +namespace JabyEngine { + template + struct integral_constant { + static constexpr T value = v; + + typedef T value_type; + typedef integral_constant type; + + constexpr operator T() const { + return v; + } + + constexpr T operator()() const { + return v; + } + }; + + typedef integral_constant true_type; + typedef integral_constant false_type; + + // ############################################# + + template + struct enable_if {}; + + template + struct enable_if { + typedef T type; + }; + + // ############################################# + + template + struct is_same { + static constexpr bool value = false; + }; + + template + struct is_same { + static constexpr bool value = true; + }; + + // ############################################# + + template + struct conditional { + using type = T; + }; + + template + struct conditional { + using type = F; + }; + + // ############################################# + + template + struct conjunction { + static constexpr bool value = true; + }; + + template + struct conjunction : B1 { + }; + + template + struct conjunction : conditional, B1>::type { + }; + + // ############################################# + + template + struct is_pointer : false_type {}; + + template + struct is_pointer : true_type {}; + + template + struct is_pointer : true_type {}; + + template + struct is_pointer : true_type {}; + + template + struct is_pointer : true_type {}; + + // ############################################# + + template + using variadic_force_same = enable_if...>::value>::type; + + // ############################################# +} \ No newline at end of file diff --git a/include/PSX/Auxiliary/types.hpp b/include/PSX/Auxiliary/types.hpp index 0bcd6a34..ec6ef8d7 100644 --- a/include/PSX/Auxiliary/types.hpp +++ b/include/PSX/Auxiliary/types.hpp @@ -1,5 +1,4 @@ -#ifndef __JABYENGINE_TYPES_HPP__ -#define __JABYENGINE_TYPES_HPP__ +#pragma once namespace JabyEngine { template @@ -8,11 +7,27 @@ namespace JabyEngine { S second; }; + template + struct cplx_pair { + T first; + S second; + + template + constexpr cplx_pair& operator=(const pair& obj) { + this->first = obj.first; + this->second = obj.second; + return *this; + } + }; + + template + constexpr cplx_pair tie(Args&... args) { + return {args...}; + } + enum struct Progress { InProgress = 0, Done, Error }; -} - -#endif //!__JABYENGINE_TYPES_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/Auxiliary/unaligned_read.hpp b/include/PSX/Auxiliary/unaligned_read.hpp index 274b4c64..4e40f354 100644 --- a/include/PSX/Auxiliary/unaligned_read.hpp +++ b/include/PSX/Auxiliary/unaligned_read.hpp @@ -1,11 +1,8 @@ -#ifndef __JABYENGINE_UNALIGNED_READ_HPP__ -#define __JABYENGINE_UNALIGNED_READ_HPP__ -#include "../../stdint.h" +#pragma once +#include "../../stdint.hpp" namespace JabyEngine { uint16_t unaligned_lhu(const uint8_t* adr) { return (static_cast(adr[0]) | static_cast(adr[1]) << 8); } -} - -#endif //!__JABYENGINE_UNALIGNED_READ_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/Auxiliary/word_helper.hpp b/include/PSX/Auxiliary/word_helper.hpp new file mode 100644 index 00000000..6675c8af --- /dev/null +++ b/include/PSX/Auxiliary/word_helper.hpp @@ -0,0 +1,15 @@ +#pragma once +#include + +namespace JabyEngine { + using word_t = uint32_t; + + static constexpr size_t bytes_to_words(size_t bytes) { + return bytes/sizeof(word_t); + } + + static constexpr size_t words_to_bytes(size_t words) { + return words*sizeof(word_t); + } +} + diff --git a/include/PSX/File/Processor/cd_file_processor.hpp b/include/PSX/File/Processor/cd_file_processor.hpp index 42b408c5..fa628c22 100644 --- a/include/PSX/File/Processor/cd_file_processor.hpp +++ b/include/PSX/File/Processor/cd_file_processor.hpp @@ -1,5 +1,4 @@ -#ifndef __JABYENGINE_CD_FILE_PROCESSOR_HPP__ -#define __JABYENGINE_CD_FILE_PROCESSOR_HPP__ +#pragma once #include "../../AutoLBA/auto_lba.hpp" #include "../../Auxiliary/circular_buffer.hpp" #include "../../Auxiliary/lz4_decompressor.hpp" @@ -7,7 +6,7 @@ #include "../cd_file_types.hpp" #include "file_processor.hpp" -extern "C" uint32_t __heap_base; +extern "C" uint32_t __heap_start; namespace JabyEngine { class CDFileProcessor { @@ -20,7 +19,7 @@ namespace JabyEngine { size_t sector_count = 0; static constexpr BufferConfiguration new_default() { - return {&__heap_base, BufferConfiguration::MediumSectorCount}; + return {&__heap_start, BufferConfiguration::MediumSectorCount}; } }; @@ -49,6 +48,7 @@ namespace JabyEngine { CDFileProcessor() = default; void setup(const volatile AutoLBAEntry* lba, JobArray jobs, const BufferConfiguration& buf_cfg); + void shutdown(); template void setup(const volatile AutoLBAEntry* lba, const CDFile (&file_array)[N], const BufferConfiguration& buf_cfg) { @@ -66,6 +66,4 @@ namespace JabyEngine { return false; } }; -} - -#endif //!__JABYENGINE_CD_FILE_PROCESSOR_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/File/Processor/file_processor.hpp b/include/PSX/File/Processor/file_processor.hpp index 5930071a..a31abdeb 100644 --- a/include/PSX/File/Processor/file_processor.hpp +++ b/include/PSX/File/Processor/file_processor.hpp @@ -1,59 +1,73 @@ -#ifndef __JABYENGINE_FILE_PROCESSOR_HPP__ -#define __JABYENGINE_FILE_PROCESSOR_HPP__ -#include "../../Auxiliary/types.hpp" -#include "../file_types.hpp" - -namespace JabyEngine { - namespace FileProcessor { - class State { - private: - struct Reserved { - uint32_t reserved[4]; - }; - - struct Configuration; - - template - using GenericProcessRoutine = Progress (*)(Configuration&, T&); - - typedef GenericProcessRoutine ProcessRoutine; - - struct Configuration { - ProcessRoutine process_routine = nullptr; - const uint8_t* data_adr = nullptr; - size_t data_bytes = 0ull; - - template - static __always_inline Configuration from(GenericProcessRoutine process_routine, const uint8_t* data_adr) { - return {reinterpret_cast(process_routine), data_adr}; - } - - constexpr void processed(size_t bytes) { - this->data_adr += bytes; - this->data_bytes -= bytes; - } - }; - - private: - Configuration config; - Reserved reserved; - - template - static __always_inline State from(const T& reserved, const uint8_t* data_adr, GenericProcessRoutine process_routine) { - return {Configuration::from(process_routine, data_adr), *reinterpret_cast(&reserved)}; - static_assert(sizeof(T) <= sizeof(Reserved)); - } - - public: - Progress process(size_t bytes_ready) { - this->config.data_bytes += bytes_ready; - return (*this->config.process_routine)(this->config, this->reserved); - } - }; - - // The nothing state - State create(const uint32_t* data_adr, const Nothing& nothing); - State create(const uint32_t* data_adr, const SimpleTIM& file); - } -} -#endif // !__JABYENGINE_FILE_PROCESSOR_HPP__ \ No newline at end of file +#pragma once +#include "../../Auxiliary/types.hpp" +#include "../cd_file_types.hpp" + +namespace JabyEngine { + namespace FileProcessor { + class State { + public: + struct Reserved { + uint32_t reserved[8]; + }; + + struct CDDataProcessor; + + template + using GenericProcessRoutine = Progress (*)(CDDataProcessor&, T&); + + typedef GenericProcessRoutine ProcessRoutine; + + struct CDDataProcessor { + ProcessRoutine process_routine = nullptr; + const uint8_t* data_adr = nullptr; + size_t data_bytes = 0ull; + + template + static __always_inline CDDataProcessor from(GenericProcessRoutine process_routine, const uint8_t* data_adr) { + return {reinterpret_cast(process_routine), data_adr}; + } + + template + T simple_read_r() { + static constexpr size_t T_SIZE = sizeof(T); + + T value = *reinterpret_cast(this->data_adr); + CDDataProcessor::processed(T_SIZE); + return value; + } + + constexpr void processed(size_t bytes) { + this->data_adr += bytes; + this->data_bytes -= bytes; + } + + constexpr void skip(size_t bytes) { + CDDataProcessor::processed(bytes); + } + }; + + CDDataProcessor data_proc; + Reserved reserved; + + template + static __always_inline State from(const T& state, const uint32_t* data_adr, GenericProcessRoutine process_routine) { + return {CDDataProcessor::from(process_routine, reinterpret_cast(data_adr)), *reinterpret_cast(&state)}; + static_assert(sizeof(T) <= sizeof(Reserved)); + } + + public: + Progress process(size_t bytes_ready) { + this->data_proc.data_bytes += bytes_ready; + return (*this->data_proc.process_routine)(this->data_proc, this->reserved); + } + }; + + // The nothing state + State create(const uint32_t* data_adr, const Nothing& nothing); + State create(const uint32_t* data_adr, const SimpleTIM& file); + State create(const uint32_t* data_adr, const TIM& file); + State create(const uint32_t* data_adr, const VAG& file); + + State create_custom(const uint32_t* data_adr, const CDFileType_t& file_type, const CDFile::Payload& payload); + } +} \ No newline at end of file diff --git a/include/PSX/File/cd_file_types.hpp b/include/PSX/File/cd_file_types.hpp index 67634209..3e4fa12d 100644 --- a/include/PSX/File/cd_file_types.hpp +++ b/include/PSX/File/cd_file_types.hpp @@ -1,41 +1,66 @@ -#ifndef __JABYENGINE_CD_FILE_TYPES_HPP__ -#define __JABYENGINE_CD_FILE_TYPES_HPP__ +#pragma once +#include #include "../Overlay/overlay.hpp" #include "file_types.hpp" namespace JabyEngine { - enum struct CDFileType : uint8_t { - SimpleTIM = 0, - CopyTo, + using CDFileType_t = uint8_t; + using RawPayload_t = uint32_t; + + enum struct CDFileType : CDFileType_t { + CopyTo = 0, + SimpleTIM, + SonyTIM, + SonyVAG, + Custom, }; - struct __no_align CDFile { - union __no_align Payload { - uint32_t raw; - SimpleTIM simple_tim; - CopyTo copy_to; - Overlay overlay; + #pragma pack(push, 1) + struct CDFile { + union Payload { + RawPayload_t raw; + CopyTo copy_to; + SimpleTIM simple_tim; + TIM tim; + VAG vag; + Overlay overlay; }; uint8_t rel_lba_idx; CDFileType type; Payload payload; + template + static constexpr CDFile custom(uint8_t lba_idx, S cd_file_type, RawPayload_t raw) { + return CDFile{ + .rel_lba_idx = lba_idx, + .type = static_cast(static_cast(CDFileType::Custom) + static_cast(cd_file_type)), + .payload = {.raw = raw} + }; + } static_assert(sizeof(Payload) == sizeof(uint32_t)); }; + #pragma pack(pop) struct CDFileBuilder { + static constexpr CDFile copy_to(uint8_t rel_lba_idx, uint32_t* dst) { + return CDFile{.rel_lba_idx = rel_lba_idx, .type = CDFileType::CopyTo, .payload = {.copy_to = CopyTo{dst}}}; + } + static constexpr CDFile simple_tim(uint8_t rel_lba_idx, SimpleTIM simple_tim) { return CDFile{.rel_lba_idx = rel_lba_idx, .type = CDFileType::SimpleTIM, .payload = {.simple_tim = simple_tim}}; } - static constexpr CDFile copy_to(uint8_t rel_lba_idx, uint32_t* dst) { - return CDFile{.rel_lba_idx = rel_lba_idx, .type = CDFileType::CopyTo, .payload = {.copy_to = CopyTo{dst}}}; + static constexpr CDFile sony_tim(uint8_t rel_lba_idx, TIM tim) { + return CDFile{.rel_lba_idx = rel_lba_idx, .type = CDFileType::SonyTIM, .payload = {.tim = tim}}; + } + + static constexpr CDFile sony_vag(uint8_t lba_idx, VAG vag) { + return CDFile{.rel_lba_idx = lba_idx, .type = CDFileType::SonyVAG, .payload = {.vag = vag}}; } static constexpr CDFile overlay(uint8_t rel_lba_idx, uint32_t* overlay_dst) { return CDFile{.rel_lba_idx = rel_lba_idx, .type = CDFileType::CopyTo, .payload = {.overlay = Overlay{overlay_dst}}}; } }; -} -#endif //!__JABYENGINE_CD_FILE_TYPES_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/File/file_processor_helper.hpp b/include/PSX/File/file_processor_helper.hpp new file mode 100644 index 00000000..04b1552a --- /dev/null +++ b/include/PSX/File/file_processor_helper.hpp @@ -0,0 +1,62 @@ +#pragma once +#include "Processor/file_processor.hpp" +#include "cd_file_types.hpp" +#include + +namespace JabyEngine { + namespace FileProcessor { + namespace Helper { + template + static Progress exchange_and_execute_process_function(State::GenericProcessRoutine process_routine, State::CDDataProcessor& data_proc, T& state) { + data_proc.process_routine = reinterpret_cast(process_routine); + return process_routine(data_proc, state); + } + + namespace DMA { + struct WordsReady { + uint32_t words_to_use; + bool is_last; + + static constexpr WordsReady calculate(const State::CDDataProcessor& data_proc, size_t words_left) { + const auto config_data_words = (data_proc.data_bytes/sizeof(uint32_t)); + const auto words_to_use = (config_data_words > words_left) ? words_left : config_data_words; + + return { + .words_to_use = words_to_use, + .is_last = words_to_use == words_left + }; + } + }; + + template + static size_t send_words(size_t words_to_send, bool send_all) { + auto blocks_to_send = words_to_send/16; + while(blocks_to_send > 0) { + const auto block_send = (blocks_to_send > UI16_MAX) ? UI16_MAX : blocks_to_send; + + // Send data! + T::wait(); + T::Receive::start(blocks_to_send); + blocks_to_send -= block_send; + } + + if(send_all) { + const auto last_words_to_send = (words_to_send & 0b1111); + if(last_words_to_send > 0) { + T::wait(); + T::Receive::start(1, last_words_to_send); + } + + T::wait(); + T::end(); + return words_to_send; + } + + else { + return (words_to_send & ~0b1111); + } + } + } + } + } +} \ No newline at end of file diff --git a/include/PSX/File/file_types.hpp b/include/PSX/File/file_types.hpp index bba6c5f5..38fa7bf5 100644 --- a/include/PSX/File/file_types.hpp +++ b/include/PSX/File/file_types.hpp @@ -1,13 +1,19 @@ -#ifndef __JABYENGINE_FILE_TYPES_HPP__ -#define __JABYENGINE_FILE_TYPES_HPP__ +#pragma once #include "../Auxiliary/bits.hpp" -#include "../jabyengine_defines.h" +#include "../GPU/gpu_types.hpp" +#include "../jabyengine_defines.hpp" +#include "../SPU/spu.hpp" namespace JabyEngine { - struct __no_align Nothing { + #pragma pack(push, 1) + struct Nothing { }; - struct __no_align SimpleTIM { + struct CopyTo { + uint32_t* dst; + }; + + struct SimpleTIM { static constexpr auto TextureX = BitRange::from_to(0, 8); static constexpr auto TextureY = BitRange::from_to(9, 16); static constexpr auto ClutX = BitRange::from_to(17, 22); @@ -15,34 +21,68 @@ namespace JabyEngine { uint32_t raw; - constexpr SimpleTIM() { - this->raw = 0; + static constexpr SimpleTIM create(uint16_t texX, uint16_t texY, uint16_t clutX, uint16_t clutY) { + return SimpleTIM{.raw = TextureX.as_value(texX >> 1) | TextureY.as_value(texY >> 1) | ClutX.as_value(clutX >> 4) | ClutY.as_value(static_cast(clutY))}; } - constexpr SimpleTIM(uint16_t texX, uint16_t texY, uint16_t clutX, uint16_t clutY) : raw(TextureX.as_value(texX >> 1) | TextureY.as_value(texY >> 1) | ClutX.as_value(clutX >> 4) | ClutY.as_value(clutY)) { - } - - constexpr uint16_t getTextureX() const { + constexpr uint16_t get_texture_x() const { return bit::value::get_normalized(this->raw, TextureX) << 1; } - constexpr uint16_t getTextureY() const { + constexpr uint16_t get_texture_y() const { return bit::value::get_normalized(this->raw, TextureY) << 1; } - constexpr uint16_t getClutX() const { + constexpr GPU::PositionU16 get_texture_position() const { + return GPU::PositionU16::create(SimpleTIM::get_texture_x(), SimpleTIM::get_texture_y()); + } + + constexpr uint16_t get_clut_x() const { return bit::value::get_normalized(this->raw, SimpleTIM::ClutX) << 4; } - constexpr uint16_t getClutY() const { + constexpr uint16_t get_clut_y() const { return bit::value::get_normalized(this->raw, ClutY); } + + constexpr GPU::PositionU16 get_clut_position() const { + return GPU::PositionU16::create(SimpleTIM::get_clut_x(), SimpleTIM::get_clut_y()); + } + + constexpr GPU::PageOffset get_page_offset() const { + const auto tex_page = SimpleTIM::get_texture_position(); + return GPU::PageOffset::create(tex_page.x&0x3F, tex_page.y); + } + + constexpr GPU::PageOffset get_page_offset_clut8() const { + const auto page_offset = SimpleTIM::get_page_offset(); + return GPU::PageOffset::create(page_offset.x*2, page_offset.y); + } + + constexpr GPU::PageOffset get_page_offset_clut4() const { + const auto page_offset = SimpleTIM::get_page_offset(); + return GPU::PageOffset::create(page_offset.x*4, page_offset.y); + } }; - struct __no_align CopyTo { - uint32_t* dst; + struct TIM { + uint32_t zero; + + static constexpr TIM create() { + return TIM{.zero = 0}; + } }; - typedef CopyTo Overlay; -} -#endif // !__JABYENGINE_FILE_TYPES_HPP__ \ No newline at end of file + struct VAG { + uint8_t voice_number; + SPU::SimpleVolume inital_stereo_vol; + + static constexpr VAG create(uint8_t voice_num, SPU::SimpleVolume volume) { + return VAG{.voice_number = voice_num, .inital_stereo_vol = volume}; + } + }; + + #pragma pack(pop) + + using Overlay = CopyTo; +} \ No newline at end of file diff --git a/include/PSX/GPU/Primitives/linked_elements.hpp b/include/PSX/GPU/Primitives/linked_elements.hpp new file mode 100644 index 00000000..61e76ddf --- /dev/null +++ b/include/PSX/GPU/Primitives/linked_elements.hpp @@ -0,0 +1,113 @@ +#pragma once +#include "../../Auxiliary/bits.hpp" +#include "../../Auxiliary/type_traits.hpp" +#include "../../System/IOPorts/gpu_io.hpp" + +namespace JabyEngine { + namespace GPU { + struct Link { + static constexpr auto AdrRange = BitRange::from_to(0, 23); + static constexpr auto SizeRange = BitRange::from_to(24, 31); + + static constexpr uint32_t TerminationValue = 0x00FFFFFF; + + static constexpr uint32_t default_link_value(size_t size) { + return SizeRange.as_value(size >> 2) | TerminationValue; + } + + uint32_t link_value; + + constexpr void set_link_identitiy(size_t size) { + this->link_value = default_link_value(size); + } + + void set_adr(const void* adr) { + this->link_value = bit::value::set_normalized(this->link_value, AdrRange.with(reinterpret_cast(adr))); + } + + void* get_adr() const { + return reinterpret_cast(bit::value::get_normalized(this->link_value, AdrRange)); + } + + template + T& insert_after(T& obj) { + const auto adr = Link::get_adr(); + + Link::set_adr(&obj); + obj.set_adr(adr); + return obj; + } + + template + enable_if::value, Link&>::type concat(T& obj) { + Link::set_adr(&obj); + return *this; + } + + template + enable_if::value, const Link&>::type concat(const T& obj) { + return concat(const_cast(obj)); + } + + constexpr void terminate() { + this->link_value |= TerminationValue; + } + }; + + template + struct LinkedElement : public Link { + T element; + + static constexpr LinkedElement create(const T& element) { + LinkedElement new_element; + + new_element.element = element; + new_element.set_link_identitiy(); + return new_element; + } + + constexpr void set_link_identitiy() { + Link::set_link_identitiy(sizeof(T)); + } + + constexpr const T* operator->() const { + return &this->element; + } + + constexpr T* operator->() { + return &this->element; + } + + static_assert((sizeof(T) >> 2) <= GPU_IO::FIFOWordSize); + }; + + namespace internal { + template + struct LinkedElementCreator { + typedef LinkedElement Linked; + + constexpr LinkedElement linked() { + return LinkedElement::create(*static_cast(this)); + } + }; + } + + namespace LinkHelper { + template + static Link* link_array(Link* last_prim, T* elements, size_t length) { + for(size_t n = 0; n < length; n++) { + last_prim->concat(elements[n]); + last_prim = &elements[n]; + } + + last_prim->terminate(); + return last_prim; + } + + template + static Link* link_array(Link* last_prim, T(&elements)[N]) { + return link_array(last_prim, elements, N); + } + } + } +} \ No newline at end of file diff --git a/include/PSX/GPU/Primitives/primitive_gpu_commands.hpp b/include/PSX/GPU/Primitives/primitive_gpu_commands.hpp new file mode 100644 index 00000000..80e385bd --- /dev/null +++ b/include/PSX/GPU/Primitives/primitive_gpu_commands.hpp @@ -0,0 +1,52 @@ +#pragma once +#include "../../System/IOPorts/gpu_io.hpp" +#include "linked_elements.hpp" +#include "primitive_support_types.hpp" + +namespace JabyEngine { + namespace GPU { + struct TexPage : public internal::LinkedElementCreator { + static constexpr bool is_render_primitive = true; + + GPU_IO_Values::GP0 value; + + static constexpr TexPage create(const PositionU16& tex_pos, TextureColorMode tex_color, SemiTransparency transparency = SemiTransparency::B_Half_add_F_Half, bool dither = false) { + return TexPage{.value = GPU_IO_Values::GP0::TexPage(tex_pos, transparency, tex_color, dither, false)}; + } + }; + + struct CPU2VRAM { + static constexpr bool is_render_primitive = true; + + GPU_IO_Values::GP0 cmd; + GPU_IO_Values::GP0 pos; + GPU_IO_Values::GP0 size; + + static constexpr CPU2VRAM create(const AreaU16& dst) { + return CPU2VRAM{ + .cmd = GPU_IO_Values::GP0::CPU2VRAMBlitting(), + .pos = GPU_IO_Values::GP0::PostionTopLeft(dst.position), + .size = GPU_IO_Values::GP0::WidthHeight(dst.size) + }; + } + }; + + struct VRAM2VRAM { + static constexpr bool is_render_primitive = true; + + GPU_IO_Values::GP0 cmd; + GPU_IO_Values::GP0 src_pos; + GPU_IO_Values::GP0 dst_pos; + GPU_IO_Values::GP0 size; + + static constexpr VRAM2VRAM create(const AreaU16& src, const PositionU16& dst) { + return VRAM2VRAM{ + .cmd = GPU_IO_Values::GP0::VRAM2VRAMBlitting(), + .src_pos = GPU_IO_Values::GP0::PostionTopLeft(src.position), + .dst_pos = GPU_IO_Values::GP0::PostionTopLeft(dst), + .size = GPU_IO_Values::GP0::WidthHeight(src.size) + }; + } + }; + } +} \ No newline at end of file diff --git a/include/PSX/GPU/Primitives/primitive_line_types.hpp b/include/PSX/GPU/Primitives/primitive_line_types.hpp new file mode 100644 index 00000000..3996c8ab --- /dev/null +++ b/include/PSX/GPU/Primitives/primitive_line_types.hpp @@ -0,0 +1,135 @@ +#pragma once +#include "linked_elements.hpp" +#include "primitive_support_types.hpp" + +namespace JabyEngine { + namespace GPU { + namespace internal { + struct LineCode : public CodeBase { + static constexpr uint8_t CmdValue = 0b010; + + static constexpr auto GouraudShading = Bit(28 - BitCorrection); + static constexpr auto FlatShading = !GouraudShading; + static constexpr auto PolyLine = Bit(27 - BitCorrection); + static constexpr auto SingleLine = !PolyLine; + + static constexpr LineCode create() { + return CodeBase::create(CmdValue); + } + }; + + template + struct LineCodeInterface { + typedef ::JabyEngine::GPU::internal::LineCode Code; + + constexpr T& set_semi_transparent(bool set = true) { + static_cast(this)->head.code.set_tenary(set, Code::SemiTransparent, Code::NonTransparent); + return *static_cast(this); + } + }; + + struct LineHead { + Color24 color; + LineCode code; + + static constexpr LineHead create(const Color24& color, const LineCode& code, bool is_poly) { + return LineHead{.color = color, .code = code}.set_poly_line(is_poly); + } + + constexpr LineHead& set_poly_line(bool set = true) { + if(set) { + this->code.set(LineCode::PolyLine); + } + + else { + this->code.set(LineCode::SingleLine); + } + return *this; + } + }; + + struct Termination { + Vertex value; + + static constexpr Termination create() { + // 0x55555555 is more common then 0x50005000 + return {.value = Vertex::create(static_cast(0x5555), static_cast(0x5555))}; + } + }; + + template + struct SingleLine : public internal::RenderPrimitive>, public LineCodeInterface>, public internal::LinkedElementCreator> { + LineHead head; + Vertex start_point; + Body end_point; + }; + + template + struct MultiLine : public internal::RenderPrimitive>, public LineCodeInterface>, public internal::LinkedElementCreator> { + LineHead head; + Vertex start_point; + Body points[N]; + Termination end; + + // Could also be none const in the future + template + constexpr typename enable_if::value, Vertex>::type operator[](size_t idx) const { + if(idx == 0) { + return this->start_point; + } + return this->points[idx - 1]; + } + + template + constexpr typename enable_if::value, ColorVertex>::type operator[](size_t idx) const { + if(idx == 0) { + return ColorVertex::create(this->head.color, this->start_point); + } + return this->points[idx - 1]; + } + }; + } + + struct LINE_F { + typedef internal::LineCode Code; + + static constexpr auto IdentityCode = Code::create().set(Code::FlatShading).set(Code::SingleLine).set(Code::NonTransparent); + + static constexpr internal::SingleLine create(const Color24& color, const Vertex& start_point, const Vertex& end_point) { + using namespace internal; + return {.head = LineHead::create(color, IdentityCode, false), .start_point = start_point, .end_point = end_point}; + } + + template + static constexpr internal::MultiLine create(const Color24& color, const Vertex& start_point, const ARGS&...rest) { + using namespace internal; + return {.head = LineHead::create(color, IdentityCode, true), .start_point = start_point, .points = {rest...}, .end = Termination::create()}; + } + }; + + struct LINE_G { + typedef LINE_F::Code Code; + + static constexpr auto IdentityCode = Code(LINE_F::IdentityCode).set(Code::GouraudShading); + + static constexpr internal::SingleLine create(const ColorVertex& start_point, const ColorVertex& end_point) { + using namespace internal; + return {.head = LineHead::create(start_point.color, IdentityCode, false), .start_point = start_point.position, .end_point = end_point}; + } + + template + static constexpr internal::MultiLine create(const ColorVertex& start_point, const ARGS&...rest) { + using namespace internal; + return {.head = LineHead::create(start_point.color, IdentityCode, true), .start_point = start_point.position, .points = {rest...}, .end = Termination::create()}; + } + }; + + using LINE_F_SINGLE = internal::SingleLine; + template + using LINE_F_MULTI = internal::MultiLine; + + using LINE_G_SINGLE = internal::SingleLine; + template + using LINE_G_MULTI = internal::MultiLine; + } +} \ No newline at end of file diff --git a/include/PSX/GPU/Primitives/primitive_poly_types.hpp b/include/PSX/GPU/Primitives/primitive_poly_types.hpp new file mode 100644 index 00000000..27f05f27 --- /dev/null +++ b/include/PSX/GPU/Primitives/primitive_poly_types.hpp @@ -0,0 +1,453 @@ +#pragma once +#include "linked_elements.hpp" +#include "primitive_support_types.hpp" + +namespace JabyEngine { + namespace GPU { + namespace internal { + struct PolyCode : public CodeBase { + static constexpr uint8_t CmdValue = 0b001; + + static constexpr auto GouraudShading = Bit(28 - BitCorrection); + static constexpr auto FlatShading = !GouraudShading; + static constexpr auto QuadVertics = Bit(27 - BitCorrection); + static constexpr auto TriVertics = !QuadVertics; + + static constexpr PolyCode create() { + return CodeBase::create(CmdValue); + } + }; + + template + struct PolyCodeInterface { + typedef ::JabyEngine::GPU::internal::PolyCode Code; + + constexpr T& set_semi_transparent(bool set = true) { + static_cast(this)->code.set_tenary(set, Code::SemiTransparent, Code::NonTransparent); + return *static_cast(this); + } + + constexpr T& set_texture_blending(bool set = true) { + static_cast(this)->code.set_tenary(set, Code::BlendTexture, Code::NoBlendTexture); + return *static_cast(this); + } + }; + + template + struct Poly3Interface {}; + + template + struct Poly4Interface { + static constexpr Vertex vertex0_from(const AreaI16& area) { + return area.get_top_left(); + } + + static constexpr Vertex vertex1_from(const AreaI16& area) { + return area.get_top_right(); + } + + static constexpr Vertex vertex2_from(const AreaI16& area) { + return area.get_bottom_left(); + } + + static constexpr Vertex vertex3_from(const AreaI16& area) { + return area.get_bottom_right(); + } + + constexpr T& set_rect_size(const SizeI16& size) { + static_cast(this)->vertex1 = static_cast(this)->vertex0.add(size.width, 0); + static_cast(this)->vertex2 = static_cast(this)->vertex0.add(0, size.height); + static_cast(this)->vertex3 = static_cast(this)->vertex0.add(size.width, size.height); + + return *static_cast(this); + } + + constexpr T& set_rect_size_fast(const SizeI16& size) { + static_cast(this)->vertex1.x = static_cast(this)->vertex0.x + size.width; + static_cast(this)->vertex2.y = static_cast(this)->vertex0.y + size.height; + static_cast(this)->vertex3 = static_cast(this)->vertex0.add(size.width, size.height); + + return *static_cast(this); + } + + constexpr PositionI16 get_rect_pos() const { + return PositionI16::create( + static_cast(this)->vertex0.x, + static_cast(this)->vertex0.y + ); + } + + constexpr SizeI16 get_rect_size() const { + return SizeI16::create( + static_cast(this)->vertex1.x - static_cast(this)->vertex0.x, + static_cast(this)->vertex2.y - static_cast(this)->vertex0.y + ); + } + }; + } + + /* + 1 + / \ + 3 - 2 + */ + struct POLY_F3 : public internal::RenderPrimitive, public internal::PolyCodeInterface, public internal::Poly3Interface, public internal::LinkedElementCreator { + static constexpr auto IdentityCode = Code::create().set(Code::FlatShading).set(Code::TriVertics).set(Code::Untextured).set(Code::NonTransparent); + + Color24 color; // a + Code code; // a + Vertex vertex0; // b + Vertex vertex1; // c + Vertex vertex2; // d + + static constexpr POLY_F3 create(const Vertex (&verticies)[3], Color24 color) { + return POLY_F3 { + .color = color, .code = IdentityCode, + .vertex0 = verticies[0], + .vertex1 = verticies[1], + .vertex2 = verticies[2] + }; + } + }; + + struct POLY_FT3 : public internal::RenderPrimitive, public internal::PolyCodeInterface, public internal::Poly3Interface, public internal::LinkedElementCreator { + struct VertexEx { + Vertex position; + PageOffset tex_offset; + }; + static constexpr auto IdentityCode = Code(POLY_F3::IdentityCode).set(Code::Textured); + + Color24 color; // a + Code code; // a + Vertex vertex0; // b + PageOffset tex_offset0; // c + PageClut page_clut; // c + Vertex vertex1; // d + PageOffset tex_offset1; // e + TPage tpage; // e + Vertex vertex2; // f + PageOffset tex_offset2; // g + uint16_t padded2; // g + + static constexpr POLY_FT3 create(const Vertex (&verticies)[3], const PageOffset (&tex_offsets)[3], TPage tpage, PageClut clut, Color24 color = Color24::Grey()) { + return POLY_FT3::create({ + {verticies[0], tex_offsets[0]}, + {verticies[1], tex_offsets[1]}, + {verticies[2], tex_offsets[2]} + }, tpage, clut, color); + } + + static constexpr POLY_FT3 create(const VertexEx (&vertices_ex)[3], TPage tpage, PageClut clut, Color24 color) { + return POLY_FT3 { + .color = color, .code = IdentityCode, + .vertex0 = vertices_ex[0].position, .tex_offset0 = vertices_ex[0].tex_offset, .page_clut = clut, + .vertex1 = vertices_ex[1].position, .tex_offset1 = vertices_ex[1].tex_offset, .tpage = tpage, + .vertex2 = vertices_ex[2].position, .tex_offset2 = vertices_ex[2].tex_offset}; + } + }; + + struct POLY_G3 : public internal::RenderPrimitive, public internal::PolyCodeInterface, public internal::Poly3Interface, public internal::LinkedElementCreator { + static constexpr auto IdentityCode = Code(POLY_F3::IdentityCode).set(Code::GouraudShading); + + Color24 color0; // a + Code code; // a + Vertex vertex0; // b + Color24 color1; // c + uint8_t pad1; // c + Vertex vertex1; // d + Color24 color2; // e + uint8_t pad2; // e + Vertex vertex2; // f + + static constexpr POLY_G3 create(const Vertex (&verticies)[3], const Color24 (&color)[3]) { + return POLY_G3::create({ + {verticies[0], color[0]}, + {verticies[1], color[1]}, + {verticies[2], color[2]} + }); + } + + static constexpr POLY_G3 create(const VertexColor (&verticies_ex)[3]) { + return POLY_G3 { + .color0 = verticies_ex[0].color, .code = IdentityCode, .vertex0 = verticies_ex[0].position, + .color1 = verticies_ex[1].color, .pad1 = 0, .vertex1 = verticies_ex[1].position, + .color2 = verticies_ex[2].color, .pad2 = 0, .vertex2 = verticies_ex[2].position + }; + } + }; + + struct POLY_GT3 : public internal::RenderPrimitive, public internal::PolyCodeInterface, public internal::Poly3Interface, public internal::LinkedElementCreator { + struct VertexEx { + Vertex position; + PageOffset tex_offset; + Color24 color; + }; + static constexpr auto IdentityCode = Code(POLY_G3::IdentityCode).set(Code::Textured); + + Color24 color0; // a + Code code; // a + Vertex vertex0; // b + PageOffset tex_offset0; // c + PageClut page_clut; // c + Color24 color1; // d + uint8_t pad1; // d + Vertex vertex1; // e + PageOffset tex_offset1; // f + TPage tpage; // f + Color24 color2; // g + uint8_t pad2; // g + Vertex vertex2; // h + PageOffset tex_offset2; // i + uint16_t pad3; // i + + static constexpr POLY_GT3 create(const Vertex (&verticies)[3], const PageOffset (&tex_offsets)[3], const Color24 (&color)[3], TPage tpage, PageClut clut) { + return POLY_GT3::create({ + {verticies[0], tex_offsets[0], color[0]}, + {verticies[1], tex_offsets[1], color[1]}, + {verticies[2], tex_offsets[2], color[2]} + }, tpage, clut); + } + + static constexpr POLY_GT3 create(const VertexEx (&verticies_ex)[3], TPage tpage, PageClut clut) { + return POLY_GT3 { + .color0 = verticies_ex[0].color, .code = IdentityCode, .vertex0 = verticies_ex[0].position, .tex_offset0 = verticies_ex[0].tex_offset, .page_clut = clut, + .color1 = verticies_ex[1].color, .pad1 = 0, .vertex1 = verticies_ex[1].position, .tex_offset1 = verticies_ex[1].tex_offset, .tpage = tpage, + .color2 = verticies_ex[2].color, .pad2 = 0, .vertex2 = verticies_ex[2].position, .tex_offset2 = verticies_ex[2].tex_offset, .pad3 = 0 + }; + } + }; + + /* + 1 - 2 + | | + 3 - 4 + */ + struct POLY_F4 : public internal::RenderPrimitive, public internal::PolyCodeInterface, public internal::Poly4Interface, public internal::LinkedElementCreator { + static constexpr auto IdentityCode = Code(POLY_F3::IdentityCode).set(Code::QuadVertics); + + Color24 color; // a + Code code; // a + Vertex vertex0; // b + Vertex vertex1; // c + Vertex vertex2; // d + Vertex vertex3; // e + + static constexpr POLY_F4 create(const Vertex (&verticies)[4], Color24 color) { + return POLY_F4 { + .color = color, .code = IdentityCode, + .vertex0 = verticies[0], + .vertex1 = verticies[1], + .vertex2 = verticies[2], + .vertex3 = verticies[3] + }; + } + + static constexpr POLY_F4 create(const AreaI16& area, Color24 color) { + return POLY_F4::create({ + POLY_F4::vertex0_from(area), + POLY_F4::vertex1_from(area), + POLY_F4::vertex2_from(area), + POLY_F4::vertex3_from(area) + }, color); + } + }; + + struct POLY_FT4 : public internal::RenderPrimitive, public internal::PolyCodeInterface, public internal::Poly4Interface, public internal::LinkedElementCreator { + typedef POLY_FT3::VertexEx VertexEx; + static constexpr auto IdentityCode = Code(POLY_FT3::IdentityCode).set(Code::QuadVertics); + + Color24 color; // a + Code code; // a + Vertex vertex0; // b + PageOffset tex_offset0; // c + PageClut page_clut; // c + Vertex vertex1; // d + PageOffset tex_offset1; // e + TPage tpage; // e + Vertex vertex2; // f + PageOffset tex_offset2; // g + uint16_t pad2; // g + Vertex vertex3; // h + PageOffset tex_offset3; // i + uint16_t pad3; // i + + static constexpr POLY_FT4 create(const Vertex (&verticies)[4], const PageOffset (&tex_offsets)[4], TPage tpage, PageClut clut, Color24 color = Color24::Grey()) { + return POLY_FT4::create({ + {verticies[0], tex_offsets[0]}, + {verticies[1], tex_offsets[1]}, + {verticies[2], tex_offsets[2]}, + {verticies[3], tex_offsets[3]} + }, tpage, clut, color); + } + + static constexpr POLY_FT4 create(const VertexEx (&vertices_ex)[4], TPage tpage, PageClut clut, Color24 color = Color24::Grey()) { + return POLY_FT4 { + .color = color, .code = IdentityCode, + .vertex0 = vertices_ex[0].position, .tex_offset0 = vertices_ex[0].tex_offset, .page_clut = clut, + .vertex1 = vertices_ex[1].position, .tex_offset1 = vertices_ex[1].tex_offset, .tpage = tpage, + .vertex2 = vertices_ex[2].position, .tex_offset2 = vertices_ex[2].tex_offset, .pad2 = 0, + .vertex3 = vertices_ex[3].position, .tex_offset3 = vertices_ex[3].tex_offset, .pad3 = 0 + }; + } + + static constexpr POLY_FT4 create(const AreaI16& area, const PageOffset& tex_offset, TPage tpage, PageClut clut, Color24 color = Color24::Grey()) { + return POLY_FT4::create({ + {POLY_FT4::vertex0_from(area), tex_offset}, + {POLY_FT4::vertex1_from(area), tex_offset.move(area.size.width - 1, 0)}, + {POLY_FT4::vertex2_from(area), tex_offset.move(0, area.size.height - 1)}, + {POLY_FT4::vertex3_from(area), tex_offset.move(area.size.width - 1, area.size.height - 1)} + }, tpage, clut, color); + } + }; + + struct POLY_G4 : public internal::RenderPrimitive, public internal::PolyCodeInterface, public internal::Poly4Interface, public internal::LinkedElementCreator { + static constexpr auto IdentityCode = Code(POLY_G3::IdentityCode).set(Code::QuadVertics); + + Color24 color0; // a + Code code; // a + Vertex vertex0; // b + Color24 color1; // c + uint8_t pad1; // c + Vertex vertex1; // d + Color24 color2; // e + uint8_t pad2; // e + Vertex vertex2; // f + Color24 color3; // g + uint8_t pad3; // g + Vertex vertex3; // h + + static constexpr POLY_G4 create(const Vertex (&verticies)[4], const Color24 (&color)[4]) { + return POLY_G4::create({ + {verticies[0], color[0]}, + {verticies[1], color[1]}, + {verticies[2], color[2]}, + {verticies[3], color[3]} + }); + } + + static constexpr POLY_G4 create(const VertexColor (&verticies_ex)[4]) { + return POLY_G4 { + .color0 = verticies_ex[0].color, .code = IdentityCode, .vertex0 = verticies_ex[0].position, + .color1 = verticies_ex[1].color, .pad1 = 0, .vertex1 = verticies_ex[1].position, + .color2 = verticies_ex[2].color, .pad2 = 0, .vertex2 = verticies_ex[2].position, + .color3 = verticies_ex[3].color, .pad3 = 0, .vertex3 = verticies_ex[3].position + }; + } + + static constexpr POLY_G4 create(const AreaI16& area, const Color24 (&color)[4]) { + return POLY_G4::create({ + {POLY_FT4::vertex0_from(area), color[0]}, + {POLY_FT4::vertex1_from(area), color[1]}, + {POLY_FT4::vertex2_from(area), color[2]}, + {POLY_FT4::vertex3_from(area), color[3]} + }); + } + }; + + struct POLY_GT4 : public internal::RenderPrimitive, public internal::PolyCodeInterface, public internal::Poly4Interface, public internal::LinkedElementCreator { + typedef POLY_GT3::VertexEx VertexEx; + static constexpr auto IdentityCode = Code(POLY_GT3::IdentityCode).set(Code::QuadVertics); + + Color24 color0; // a + Code code; // a + Vertex vertex0; // b + PageOffset tex_offset0; // c + PageClut page_clut; // c + Color24 color1; // d + uint8_t pad1; // d + Vertex vertex1; // e + PageOffset tex_offset1; // f + TPage tpage; // f + Color24 color2; // g + uint8_t pad2; // g + Vertex vertex2; // h + PageOffset tex_offset2; // i + uint16_t pad3; // i + Color24 color3; // j + uint8_t pad4; // j + Vertex vertex3; // k + PageOffset tex_offset3; // l + uint16_t pad5; // l + + static constexpr POLY_GT4 create(const Vertex (&verticies)[4], const PageOffset (&tex_offsets)[4], const Color24 (&color)[4], TPage tpage, PageClut clut) { + return POLY_GT4::create({ + {verticies[0], tex_offsets[0], color[0]}, + {verticies[1], tex_offsets[1], color[1]}, + {verticies[2], tex_offsets[2], color[2]}, + {verticies[3], tex_offsets[3], color[3]}, + }, tpage, clut); + } + + static constexpr POLY_GT4 create(const VertexEx (&verticies_ex)[4], TPage tpage, PageClut clut) { + return POLY_GT4 { + .color0 = verticies_ex[0].color, .code = IdentityCode, .vertex0 = verticies_ex[0].position, .tex_offset0 = verticies_ex[0].tex_offset, .page_clut = clut, + .color1 = verticies_ex[1].color, .pad1 = 0, .vertex1 = verticies_ex[1].position, .tex_offset1 = verticies_ex[1].tex_offset, .tpage = tpage, + .color2 = verticies_ex[2].color, .pad2 = 0, .vertex2 = verticies_ex[2].position, .tex_offset2 = verticies_ex[2].tex_offset, .pad3 = 0, + .color3 = verticies_ex[3].color, .pad4 = 0, .vertex3 = verticies_ex[3].position, .tex_offset3 = verticies_ex[3].tex_offset, .pad5 = 0 + }; + } + + static constexpr POLY_GT4 create(const AreaI16& area, const PageOffset& tex_offset, TPage tpage, PageClut clut, const Color24 (&color)[4]) { + return POLY_GT4::create({ + {POLY_FT4::vertex0_from(area), tex_offset, color[0]}, + {POLY_FT4::vertex1_from(area), tex_offset.move(area.size.width, 0), color[1]}, + {POLY_FT4::vertex2_from(area), tex_offset.move(0, area.size.height), color[2]}, + {POLY_FT4::vertex3_from(area), tex_offset.move(area.size.width, area.size.height), color[3]} + }, tpage, clut); + } + }; + + #define __jabyengine_poly_top_left(x, y, w, h) x, y + #define __jabyengine_poly_top_right(x, y, w, h) (x + w), y + #define __jabyengine_poly_bottom_left(x, y, w, h) x, (y + h) + #define __jabyengine_poly_bottom_right(x, y, w, h) (x + w), (y + h) + + #define __jabyengine_polyFT4_vertex_rect(area, tex_off) { \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + } + + #define __jabyengine_polyFT4_vertex_rect90(area, tex_off) { \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + } + + #define __jabyengine_polyFT4_vertex_rect180(area, tex_off) { \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + } + + #define __jabyengine_polyFT4_vertex_rect270(area, tex_off) { \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \ + } + + typedef POLY_F3 FlatTriangle; + typedef POLY_FT3 FlatTexturedTriangle; + typedef POLY_G3 GouraudTriangle; + typedef POLY_GT3 GouraudTexturedTriangle; + + typedef POLY_F4 FlatRectangle; + typedef POLY_FT4 FlatTexturedRectangle; + typedef POLY_G4 GouraudRectangle; + typedef POLY_GT4 GouraudTexturedRectangle; + + static_assert(sizeof(POLY_F3) == 16); + static_assert(sizeof(POLY_FT3) == 28); + static_assert(sizeof(POLY_G3) == 24); + static_assert(sizeof(POLY_GT3) == 36); + + static_assert(sizeof(POLY_F4) == 20); + static_assert(sizeof(POLY_FT4) == 36); + static_assert(sizeof(POLY_G4) == 32); + static_assert(sizeof(POLY_GT4) == 48); + } +} \ No newline at end of file diff --git a/include/PSX/GPU/Primitives/primitive_rectangle_types.hpp b/include/PSX/GPU/Primitives/primitive_rectangle_types.hpp new file mode 100644 index 00000000..2603d268 --- /dev/null +++ b/include/PSX/GPU/Primitives/primitive_rectangle_types.hpp @@ -0,0 +1,128 @@ +#pragma once +#include "linked_elements.hpp" +#include "primitive_support_types.hpp" + +namespace JabyEngine { + namespace GPU { + struct OffsetPageWithClut { + PageOffset tex_offset; + PageClut clut; + + static constexpr OffsetPageWithClut create(PageOffset tex_offset, PageClut clut) { + return OffsetPageWithClut{tex_offset, clut}; + } + }; + + namespace internal { + struct RectCode : public CodeBase { + enum struct SizeType : uint8_t { + Variable = 0, + Pixel1x1 = 1, + Sprite8x8 = 2, + Sprite16x16 = 3 + }; + static constexpr uint8_t CmdValue = 0b011; + + static constexpr auto Size = BitRange::from_to(27 - BitCorrection, 28 - BitCorrection); + + static constexpr RectCode create() { + return CodeBase::create(CmdValue); + } + }; + + template + struct RectCodeInterface { + typedef typename ::JabyEngine::GPU::internal::RectCode Code; + + constexpr T& set_semi_transparent(bool set = true) { + static_cast(this)->code.set_tenary(set, Code::SemiTransparent, Code::NonTransparent); + return *static_cast(this); + } + }; + + template + struct RECT_BASE_F : public RectCodeInterface> { + typedef RectCodeInterface>::Code Code; + static constexpr auto IdentityCode = Code::create().set(Code::Size.with(static_cast(Size))).set(Code::Untextured).set(Code::NonTransparent); + + Color24 color; + Code code; + Vertex position; + + static constexpr RECT_BASE_F create(const Vertex& position, const Color24& color) { + return RECT_BASE_F { + .color = color, .code = IdentityCode, .position = position + }; + } + }; + + template + struct RECT_BASE_T : public RectCodeInterface> { + typedef RectCodeInterface>::Code Code; + static constexpr auto IdentityCode = Code(RECT_BASE_F::IdentityCode).set(Code::Textured); + + Color24 color; + Code code; + Vertex position; + PageOffset tex_offset; + PageClut clut; + + static constexpr RECT_BASE_T create(const Vertex& position, const OffsetPageWithClut& tex_offset_w_clut, const Color24& color = Color24::Grey()) { + return RECT_BASE_T { + .color = color, .code = IdentityCode, .position = position, .tex_offset = tex_offset_w_clut.tex_offset, .clut = tex_offset_w_clut.clut + }; + } + }; + + template + struct RECT_F : public RECT_BASE_F, public internal::RenderPrimitive>, public internal::LinkedElementCreator> { + static constexpr RECT_F create(const Vertex& position, const Color24& color) { + RECT_F rect; + + static_cast&>(rect) = RECT_BASE_F::create(position, color); + return rect; + } + }; + + template + struct RECT_T : public RECT_BASE_T, public internal::RenderPrimitive>, public internal::LinkedElementCreator> { + static constexpr RECT_T create(const Vertex& position, const OffsetPageWithClut& tex_offset_w_clut, const Color24& color = Color24::Grey()) { + RECT_T rect; + + static_cast&>(rect) = RECT_BASE_T::create(position, tex_offset_w_clut, color); + return rect; + } + }; + } + + typedef internal::RECT_F TILE_1; + typedef internal::RECT_F TILE_8; + typedef internal::RECT_F TILE_16; + struct TILE : public internal::RECT_BASE_F, public internal::RenderPrimitive, public internal::LinkedElementCreator { + SizeI16 size; + + static constexpr TILE create(const AreaI16& area, const Color24& color) { + TILE tile; + + static_cast(tile) = RECT_BASE_F::create(area.position, color); + tile.size = area.size; + return tile; + } + }; + + typedef internal::RECT_T SPRT_1; + typedef internal::RECT_T SPRT_8; + typedef internal::RECT_T SPRT_16; + struct SPRT : public internal::RECT_BASE_T, public internal::RenderPrimitive, public internal::LinkedElementCreator { + SizeI16 size; + + static constexpr SPRT create(const AreaI16& area, const OffsetPageWithClut& page, const Color24& color = Color24::Grey()) { + SPRT sprt; + + static_cast(sprt) = RECT_BASE_T::create(area.position, page, color); + sprt.size = area.size; + return sprt; + } + }; + } +} \ No newline at end of file diff --git a/include/PSX/GPU/Primitives/primitive_support_types.hpp b/include/PSX/GPU/Primitives/primitive_support_types.hpp new file mode 100644 index 00000000..1ed04230 --- /dev/null +++ b/include/PSX/GPU/Primitives/primitive_support_types.hpp @@ -0,0 +1,98 @@ +#pragma once +#include "../../Auxiliary/type_traits.hpp" +#include "../../System/IOPorts/gpu_io.hpp" +#include "../gpu_types.hpp" + +namespace JabyEngine { + namespace GPU { + namespace internal { + template + struct CodeBase { + static constexpr auto BitCorrection = 24; + static constexpr auto CmdID = BitRange::from_to(29 - BitCorrection, 31 - BitCorrection); + + uint8_t value; + + // Common values for all the primitves + static constexpr auto Textured = Bit(26 - BitCorrection); + static constexpr auto Untextured = !Textured; + static constexpr auto SemiTransparent = Bit(25 - BitCorrection); + static constexpr auto NonTransparent = !SemiTransparent; + static constexpr auto NoBlendTexture = Bit(24 - BitCorrection); + static constexpr auto BlendTexture = !NoBlendTexture; + + static constexpr T create(uint8_t value) { + return T{bit::value::set_normalized(0u, CmdID.with(value))}; + } + + static constexpr T create(const T& code) { + return CodeBase::create(code.value); + } + + constexpr T& set(Bit bit) { + this->value = bit::set(this->value, bit); + return static_cast(*this); + } + + constexpr T& set(ClearBit bit) { + this->value = bit::set(this->value, bit); + return static_cast(*this); + } + + constexpr T& set(BitRange::RangeValuePair value_pair) { + this->value = bit::value::set_normalized(this->value, value_pair); + return static_cast(*this); + } + + template + constexpr T& set_tenary(bool use_first, const S& first, const R& second) { + if(use_first) { + return this->set(first); + } + + else { + return this->set(second); + } + } + }; + + template + struct RenderPrimitive { + static constexpr bool is_render_primitive = true; + + void set_identitiy() { + static_cast(*this).code = T::IdentityCode; + } + }; + } + + struct PageClut { + uint16_t value; + + static constexpr PageClut create(uint16_t x, uint16_t y) { + return PageClut{static_cast((y << 6) | ((x >> 4) & 0x3f))}; + } + + static constexpr PageClut create(const PositionU16& clut_pos) { + return PageClut::create(clut_pos.x, clut_pos.y); + } + }; + + struct TPage { + static constexpr auto TexturePageX = BitRange::from_to(0, 3); + static constexpr auto TexturePageY = BitRange::from_to(4, 4); + static constexpr auto SemiTransparency = BitRange::from_to(5, 6); + static constexpr auto TextureClut = BitRange::from_to(7, 8); + + uint16_t value; + + static constexpr TPage create(uint16_t x, uint16_t y, ::JabyEngine::GPU::SemiTransparency transparency, TextureColorMode clut_color) { + return TPage{static_cast(TexturePageX.as_value(x >> 6) | TexturePageY.as_value(y >> 8) | SemiTransparency.as_value(static_cast(transparency)) | TextureClut.as_value(static_cast(clut_color)))}; + } + + static constexpr TPage create(const PositionU16& pos, ::JabyEngine::GPU::SemiTransparency transparency, TextureColorMode clut_color) { + return TPage::create(pos.x, pos.y, transparency, clut_color); + } + }; + } +} \ No newline at end of file diff --git a/include/PSX/GPU/gpu.hpp b/include/PSX/GPU/gpu.hpp index 6f026a8f..d364829f 100644 --- a/include/PSX/GPU/gpu.hpp +++ b/include/PSX/GPU/gpu.hpp @@ -1,6 +1,8 @@ -#ifndef __JABYENGINE_GPU_HPP__ -#define __JABYENGINE_GPU_HPP__ +#pragma once +#include "../Auxiliary/type_traits.hpp" #include "../System/IOPorts/gpu_io.hpp" +#include "../jabyengine_config.hpp" +#include "gpu_primitives.hpp" #if !defined(JABYENGINE_NTSC) && !defined(JABYENGINE_PAL) #error "JABYENGINE_NTSC or JABYENGINE_PAL must be defined" @@ -12,29 +14,71 @@ namespace JabyEngine { namespace GPU { + namespace internal { + void render(const uint32_t* data, size_t words); + void render_dma(const uint32_t* data); + } + struct Display { #ifdef JABYENGINE_PAL - static constexpr size_t Width = 320; - static constexpr size_t Height = 256; + static constexpr size_t Width = 320; + static constexpr size_t Height = 256; + static constexpr uint32_t frames_per_sec = 50; #else - static constexpr size_t Width = 320; - static constexpr size_t Height = 240; + static constexpr size_t Width = 320; + static constexpr size_t Height = 240; + static constexpr uint32_t frames_per_sec = 60; #endif + static uint8_t current_id; + + template + static constexpr Area center(const Area& area) { + return Area::create(Position::create((Display::Width - area.size.width)/2, (Display::Height - area.size.height)/2), area.size); + } + static void enable() { - GPU_IO::GP1 = GPU_IO::Command::SetDisplayState(GPU_IO::DisplayState::On); + GPU_IO::GP1.set_display_state(GPU_IO_Values::DisplayMode::State::On); } static void disable() { - GPU_IO::GP1 = GPU_IO::Command::SetDisplayState(GPU_IO::DisplayState::Off); + GPU_IO::GP1.set_display_state(GPU_IO_Values::DisplayMode::State::Off); } - }; - struct Screen { - static uint8_t CurrentDisplayAreaID; - - static void set_offset(uint16_t x, uint16_t y); + static void set_offset(int16_t x, int16_t y); }; + using VSyncCallback = void (*)(); + + static uint32_t update_id() { + return Display::current_id; + } + + static uint32_t render_id() { + return Display::current_id ^ 1; + } + + void set_vsync_callback(VSyncCallback callback); + + template + static void render(const LinkedElement& linked_primitives) { + internal::render_dma(&linked_primitives.link_value); + } + + template + static enable_if::type render(const T& primitive) { + internal::render(reinterpret_cast(&primitive), sizeof(T)/sizeof(uint32_t)); + } + + template + static enable_if::type render(const LINE_F (&primitives)[N]) { + internal::render(reinterpret_cast(&primitives), (sizeof(T)/sizeof(uint32_t))*N); + } + + static void wait_for_render() { + while(!GPU_IO::GPUSTAT.read().is_set(GPU_IO_Values::GPUSTAT::GP0ReadyForCMD)); + } + + void swap_buffers(bool clear_screen = true); + uint8_t swap_buffers_vsync(uint8_t syncs, bool clear_screen = true); } -} -#endif //!__JABYENGINE_GPU_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/GPU/gpu_auto_load_font.hpp b/include/PSX/GPU/gpu_auto_load_font.hpp new file mode 100644 index 00000000..ab979624 --- /dev/null +++ b/include/PSX/GPU/gpu_auto_load_font.hpp @@ -0,0 +1,35 @@ +#pragma once +#include "../jabyengine_config.hpp" +#include "gpu_primitives.hpp" + +namespace JabyEngine { + namespace GPU { + struct BIOS_Font { + // This size is by Hardware limitation + static constexpr auto Size = SizeU16::create(16, 16); + + static constexpr auto TextureLoadPos = Configuration::BIOSFont::texture_load_pos(); + static constexpr auto CLUTLoadPos = Configuration::BIOSFont::CLUT_load_pos(); + + static constexpr TexPage get_tex_page() { + return TexPage::create(BIOS_Font::TextureLoadPos, GPU::TextureColorMode::clut4); + } + + static constexpr TPage get_tpage() { + return TPage::create(TextureLoadPos.x, TextureLoadPos.y, SemiTransparency::B_add_F, TextureColorMode::clut4); + } + + static constexpr PageOffset get_offset_page() { + return PageOffset::create(BIOS_Font::CLUTLoadPos.x & 0x3F, BIOS_Font::CLUTLoadPos.y & 0xFF); + } + + static constexpr PageClut get_page_clut() { + return PageClut::create(BIOS_Font::CLUTLoadPos); + } + + static constexpr OffsetPageWithClut get_offset_page_with_clut() { + return OffsetPageWithClut::create(BIOS_Font::get_offset_page(), BIOS_Font::get_page_clut()); + } + }; + } +} \ No newline at end of file diff --git a/include/PSX/GPU/gpu_primitives.hpp b/include/PSX/GPU/gpu_primitives.hpp new file mode 100644 index 00000000..54a32079 --- /dev/null +++ b/include/PSX/GPU/gpu_primitives.hpp @@ -0,0 +1,6 @@ +#pragma once +#include "../Auxiliary/literals.hpp" +#include "Primitives/primitive_gpu_commands.hpp" +#include "Primitives/primitive_line_types.hpp" +#include "Primitives/primitive_rectangle_types.hpp" +#include "Primitives/primitive_poly_types.hpp" \ No newline at end of file diff --git a/include/PSX/GPU/gpu_types.hpp b/include/PSX/GPU/gpu_types.hpp index 48bfc0ca..48c89700 100644 --- a/include/PSX/GPU/gpu_types.hpp +++ b/include/PSX/GPU/gpu_types.hpp @@ -1,102 +1,329 @@ -#ifndef __JABYENGINE_GPU_TYPES_HPP__ -#define __JABYENGINE_GPU_TYPES_HPP__ -#include "../jabyengine_defines.h" +#pragma once +#include "../Auxiliary/bits.hpp" +#include "../jabyengine_defines.hpp" namespace JabyEngine { namespace GPU { - struct Color24 { - uint8_t red = 0; - uint8_t green = 0; - uint8_t blue = 0; + namespace internal { + template + struct XYMovement { + constexpr T& add(S dx, S dy) { + static_cast(this)->x += dx; + static_cast(this)->y += dy; + + return *static_cast(this); + } - constexpr Color24() = default; - constexpr Color24(uint8_t r, uint8_t g, uint8_t b) : blue(b), green(g), red(r) { + constexpr T add(S dx, S dy) const { + return T::create(static_cast(this)->x, static_cast(this)->y).add(dx, dy); + } + + constexpr T& add(const T& offset) { + return add(offset.x, offset.y); + } + + constexpr T add(const T& offset) const { + return add(offset.x, offset.y); + } + + constexpr T& sub(S dx, S dy) { + static_cast(this)->x -= dx; + static_cast(this)->y -= dy; + + return *static_cast(this); + } + + constexpr T sub(S dx, S dy) const { + return T::create(static_cast(this)->x, static_cast(this)->y).sub(dx, dy); + } + + constexpr T& sub(const T& offset) { + return sub(offset.x, offset.y); + } + + constexpr T sub(const T& offset) const { + return sub(offset.x, offset.y); + } + + constexpr T& move(S dx, S dy) { + return this->add(dx, dy); + } + + constexpr T move(S dx, S dy) const { + return T::create(static_cast(this)->x, static_cast(this)->y).move(dx, dy); + } + }; + + template + struct PredefinedColors { + static constexpr T Black() { + return T::from_rgb(0, 0, 0); + } + + static constexpr T Grey() { + return T::from_rgb(0x80, 0x80, 0x80); + } + + static constexpr T White(uint8_t base = 0xFF) { + return T::from_rgb(base, base, base); + } + + static constexpr T Red(uint8_t base = 0xFF) { + return T::from_rgb(base, 0x0, 0x0); + } + + static constexpr T Green(uint8_t base = 0xFF) { + return T::from_rgb(0x0, base, 0x0); + } + + static constexpr T Blue(uint8_t base = 0xFF) { + return T::from_rgb(0x0, 0x0, base); + } + + static constexpr T Yellow(uint8_t base = 0xFF) { + return T::from_rgb(base, base, 0x0); + } + + static constexpr T Purple(uint8_t base = 0xFF) { + return T::from_rgb(base, 0x0, base); + } + + static constexpr T Turquoise(uint8_t base = 0xFF) { + return T::from_rgb(0x0, base, base); + } + }; + } + + enum struct SemiTransparency { + B_Half_add_F_Half = 0, + B_add_F = 1, + B_sub_F = 2, + B_add_F_Quarter = 3, + }; + + enum struct TextureColorMode { + clut4 = 0, + clut8 = 1, + direct16 = 2, + }; + + struct Color24 : public internal::PredefinedColors { + uint8_t red; + uint8_t green; + uint8_t blue; + + static constexpr Color24 from_rgb(uint8_t r, uint8_t g, uint8_t b) { + return Color24{.red = r, .green = g, .blue = b}; } constexpr uint32_t raw() const { return ((this->blue << 16) | (this->green << 8) | this->red); } - static constexpr Color24 Black() { - return Color24(0, 0, 0); - } - - static constexpr Color24 White() { - return Color24(0xFF, 0xFF, 0xFF); - } - - static constexpr Color24 Red() { - return Color24(0xFF, 0x0, 0x0); - } - - static constexpr Color24 Green() { - return Color24(0x0, 0xFF, 0x0); - } - - static constexpr Color24 Blue() { - return Color24(0x0, 0x0, 0xFF); + constexpr Color24 invert() const { + return Color24::from_rgb(this->red^0xFF, this->green^0xFF, this->blue^0xFF); } }; - class Color { - private: + struct Color : public internal::PredefinedColors { static constexpr auto RedRange = BitRange::from_to(0, 4); static constexpr auto GreenRange = BitRange::from_to(5, 9); static constexpr auto BlueRange = BitRange::from_to(10, 14); static constexpr auto SemiTransperancyBit = Bit(15); - uint16_t value = 0; + uint16_t raw; - public: static constexpr Color from_rgb(uint8_t r, uint8_t g, uint8_t b) { - return Color().set_red(r).set_green(g).set_blue(b); + return Color().set_red(r >> 3).set_green(g >> 3).set_blue(b >> 3); } static constexpr Color from(const Color24& color) { return Color::from_rgb(color.red, color.green, color.blue); } + constexpr Color invert() const { + return Color{.raw = static_cast(this->raw^0xFFFF)}; + } + constexpr Color& set_red(uint8_t red) { - this->value = bit::value::set_normalized(this->value, RedRange.with(red)); + this->raw = bit::value::set_normalized(this->raw, RedRange.with(red)); return *this; } constexpr Color& set_green(uint8_t green) { - this->value = bit::value::set_normalized(this->value, GreenRange.with(green)); + this->raw = bit::value::set_normalized(this->raw, GreenRange.with(green)); return *this; } constexpr Color& set_blue(uint8_t blue) { - this->value = bit::value::set_normalized(this->value, BlueRange.with(blue)); + this->raw = bit::value::set_normalized(this->raw, BlueRange.with(blue)); return *this; } }; - template - struct Position { - T x = 0; - T y = 0; + struct LookUpColor8 { + uint8_t lu_id[2]; - constexpr Position() = default; - constexpr Position(T x, T y) : x(x), y(y) { + static constexpr LookUpColor8 create(const uint8_t (&data)[2]) { + return LookUpColor8::create(data[0], data[1]); + } + + static constexpr LookUpColor8 create(uint8_t px0, uint8_t px1) { + return LookUpColor8{{px0, px1}}; + } + + constexpr uint8_t get_lu_id(size_t at) const { + return this->lu_id[at]; + } + + constexpr void set_lu_id(uint8_t new_lu_id, size_t at) { + this->lu_id[at] = new_lu_id; } }; + struct LookUpColor4 { + uint8_t lu_id[2]; + + static constexpr LookUpColor4 create(const uint8_t (&data)[4]) { + return LookUpColor4::create(data[0], data[1], data[2], data[3]); + } + + static constexpr LookUpColor4 create(uint8_t px0, uint8_t px1, uint8_t px2, uint8_t px3) { + return LookUpColor4{{static_cast((px1 << 4) | px0), static_cast((px3 << 4) | px2)}}; + } + }; + + template + struct Position : public internal::XYMovement, T> { + using PrimitiveType = T; + + T x; + T y; + + static constexpr Position create(T x, T y) { + return Position{.x = x, .y = y}; + } + }; + using PositionI8 = Position; + using PositionU8 = Position; + using PositionI16 = Position; + using PositionU16 = Position; + using Vertex = PositionI16; + template struct Size { - T width = 0; - T height = 0; + T width; + T height; - constexpr Size() = default; - constexpr Size(T w, T h) : width(w), height(h) { + static constexpr Size create(T w, T h) { + return Size{w, h}; + } + + template + static constexpr Size from(const Size& size) { + return Size::create(static_cast(size.width), static_cast(size.height)); + } + + auto operator<=>(const Size&) const = default; + }; + using SizeI8 = Size; + using SizeU8 = Size; + using SizeI16 = Size; + using SizeU16 = Size; + + template + static constexpr T tile_id_for(S id, S row_count, Size size) { + const auto x = id%row_count; + const auto y = id/row_count; + + return T::create(static_cast(size.width*x), static_cast(size.height*y)); + } + + template + static constexpr T tile_id_for16(S id, Size size) { + const auto x = id&0xF; + const auto y = id >> 4; + + return T::create(static_cast(x*size.width), static_cast(y*size.height)); + } + + template + struct Area { + Position position; + Size size; + + static constexpr Area create(Position position, Size size) { + return Area{position, size}; + } + + static constexpr Area create(T position_x, T position_y, T size_width, T size_height) { + return Area{Position::create(position_x, position_y), Size::create(size_width, size_height)}; + } + + constexpr Area centered() const { + return Area(this->position.sub(this->size.width/2, this->size.height/2), this->size); + } + + constexpr Position get_top_left() const { + return this->position; + } + + constexpr Position get_top_right() const { + return this->position.add(this->size.width, 0); + } + + constexpr Position get_bottom_left() const { + return this->position.add(0, this->size.height); + } + + constexpr Position get_bottom_right() const { + return this->position.move(this->size.width, this->size.height); + } + }; + typedef Area AreaI16; + typedef Area AreaU16; + + // Type used for primitives + struct PageOffset : public internal::XYMovement { + union { + uint8_t x; + uint8_t u; + }; + + union { + uint8_t y; + uint8_t v; + }; + + static constexpr PageOffset create(uint8_t u, uint8_t v) { + return PageOffset{.x = u, .y = v}; //< Activate x and y to use XYMovement during constexpr + } + + static constexpr PageOffset from_tile_id(int16_t id, int16_t row_count, SizeI16 size) { + return tile_id_for(id, row_count, size); + } + + static constexpr PageOffset from_tile_id16(int16_t id, SizeI16 size) { + return tile_id_for16(id, size); } }; - typedef Position PositionI16; - typedef Position PositionU16; + struct VertexColor { + Vertex position; + Color24 color; - typedef Size SizeI16; - typedef Size SizeU16; + static constexpr VertexColor create(Vertex vertex, Color24 color) { + return VertexColor{vertex, color}; + } + }; + + struct ColorVertex { + Color24 color; + alignas(2) Vertex position; + + static constexpr ColorVertex create(Color24 color, Vertex vertex) { + return ColorVertex{color, vertex}; + } + }; } -} -#endif //!__JABYENGINE_GPU_TYPES_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/GPU/make_gpu_primitives.hpp b/include/PSX/GPU/make_gpu_primitives.hpp new file mode 100644 index 00000000..146b8a28 --- /dev/null +++ b/include/PSX/GPU/make_gpu_primitives.hpp @@ -0,0 +1,349 @@ +#pragma once +#include "gpu_primitives.hpp" + +namespace JabyEngine { + namespace Make { + template + static constexpr T creator_template(const ARGS&...args) { + return T::create(args...); + } + + // ################################################################### + + static constexpr GPU::SizeI8 SizeI8() { + return creator_template(0_i8, 0_i8); + } + static constexpr GPU::SizeI8 SizeI8(int8_t x, int8_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::SizeU8 SizeU8() { + return creator_template(0_u8, 0_u8); + } + static constexpr GPU::SizeU8 SizeU8(uint8_t x, uint8_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::SizeI16 SizeI16() { + return creator_template(0_i16, 0_i16); + } + static constexpr GPU::SizeI16 SizeI16(int16_t x, int16_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::SizeU16 SizeU16() { + return creator_template(0_u16, 0_u16); + } + static constexpr GPU::SizeU16 SizeU16(uint16_t x, uint16_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::PositionI8 PositionI8() { + return creator_template(0_i8, 0_i8); + } + static constexpr GPU::PositionI8 PositionI8(int8_t x, int8_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::PositionU8 PositionU8() { + return creator_template(0_u8, 0_u8); + } + static constexpr GPU::PositionU8 PositionU8(int8_t x, int8_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::PositionI16 PositionI16() { + return creator_template(0_i16, 0_i16); + } + static constexpr GPU::PositionI16 PositionI16(int16_t x, int16_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::PositionU16 PositionU16() { + return creator_template(0_u16, 0_u16); + } + static constexpr GPU::PositionU16 PositionU16(uint16_t x, uint16_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::Vertex Vertex() { + return creator_template(0_i16, 0_i16); + } + static constexpr GPU::Vertex Vertex(int16_t x, int16_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::AreaI16 AreaI16() { + return creator_template(0, 0, 0, 0); + } + static constexpr GPU::AreaI16 AreaI16(int16_t x, int16_t y, int16_t w, int16_t h) { + return creator_template(x, y, w, h); + } + static constexpr GPU::AreaI16 AreaI16(GPU::PositionI16 pos, GPU::SizeI16 size) { + return creator_template(pos, size); + } + + // ################################################################### + + static constexpr GPU::AreaU16 AreaU16() { + return creator_template(0, 0, 0, 0); + } + static constexpr GPU::AreaU16 AreaU16(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { + return creator_template(x, y, w, h); + } + static constexpr GPU::AreaU16 AreaU16(GPU::PositionU16 pos, GPU::SizeU16 size) { + return creator_template(pos, size); + } + + // ################################################################### + + static constexpr GPU::PageOffset PageOffset() { + return creator_template(0_u8, 0_u8); + } + static constexpr GPU::PageOffset PageOffset(uint8_t u, uint8_t v) { + return creator_template(u, v); + } + + // ################################################################### + + static constexpr GPU::PageClut PageClut() { + return creator_template(0_u16, 0_u16); + } + static constexpr GPU::PageClut PageClut(uint16_t x, uint16_t y) { + return creator_template(x, y); + } + static constexpr GPU::PageClut PageClut(const GPU::PositionU16& clut_pos) { + return creator_template(clut_pos); + } + + // ################################################################### + + static constexpr GPU::TPage TPage() { + return creator_template(0_u16, 0_u16, GPU::SemiTransparency::B_add_F, GPU::TextureColorMode::clut4); + } + static constexpr GPU::TPage TPage(uint16_t x, uint16_t y, GPU::SemiTransparency transparency, GPU::TextureColorMode clut_color) { + return creator_template(x, y, transparency, clut_color); + } + static constexpr GPU::TPage TPage(const GPU::PositionU16& tex_pos, GPU::SemiTransparency transparency, GPU::TextureColorMode clut_color) { + return creator_template(tex_pos, transparency, clut_color); + } + + // ################################################################### + + static constexpr GPU::TexPage TexPage() { + return creator_template(PositionU16(), GPU::TextureColorMode::clut4, GPU::SemiTransparency::B_Half_add_F_Half, false); + } + static constexpr GPU::TexPage TexPage(const GPU::PositionU16& tex_pos, GPU::TextureColorMode tex_color, GPU::SemiTransparency transparency = GPU::SemiTransparency::B_Half_add_F_Half, bool dither = false) { + return creator_template(tex_pos, tex_color, transparency, dither); + } + + // ################################################################### + + static constexpr GPU::OffsetPageWithClut OffsetPageWithClut() { + return creator_template(PageOffset(), PageClut()); + } + static constexpr GPU::OffsetPageWithClut OffsetPageWithClut(GPU::PageOffset tex_offset, GPU::PageClut clut) { + return creator_template(tex_offset, clut); + } + + // ################################################################### + + static constexpr GPU::VertexColor VertexColor() { + return creator_template(Vertex(), GPU::Color24::Black()); + } + static constexpr GPU::VertexColor VertexColor(GPU::Vertex pos, GPU::Color24 color) { + return creator_template(pos, color); + } + + // ################################################################### + + static constexpr GPU::ColorVertex ColorVertex() { + return creator_template(GPU::Color24::Black(), Vertex()); + } + static constexpr GPU::ColorVertex ColorVertex(GPU::Color24 color, GPU::Vertex pos) { + return creator_template(color, pos); + } + + // ################################################################### + + static constexpr GPU::LINE_F_SINGLE LINE_F(const GPU::Color24& color, const GPU::Vertex& start_point, const GPU::Vertex& end_point) { + return GPU::LINE_F::create(color, start_point, end_point); + } + + template + static constexpr GPU::LINE_F_MULTI LINE_F(const GPU::Color24& color, const GPU::Vertex& start_point, const ARGS&...rest) { + return GPU::LINE_F::create(color, start_point, rest...); + } + + static constexpr GPU::LINE_G_SINGLE LINE_G(const GPU::ColorVertex& start_point, const GPU::ColorVertex& end_point) { + return GPU::LINE_G::create(start_point, end_point); + } + + template + static constexpr GPU::LINE_G_MULTI LINE_G(const GPU::ColorVertex& start_point, const ARGS&...rest) { + return GPU::LINE_G::create(start_point, rest...); + } + + // ################################################################### + // ################################################################### + // ################################################################### + + static constexpr GPU::POLY_F3 POLY_F3(const GPU::Vertex (&verticies)[3], GPU::Color24 color) { + return creator_template(verticies, color); + } + + static constexpr GPU::POLY_FT3 POLY_FT3(const GPU::Vertex (&verticies)[3], const GPU::PageOffset (&tex_offset)[3], GPU::TPage tpage, GPU::PageClut clut, GPU::Color24 color = GPU::Color24::Grey()) { + return creator_template(verticies, tex_offset, tpage, clut, color); + } + + static constexpr GPU::POLY_FT3 POLY_FT3(const GPU::POLY_FT3::VertexEx (&vertices_ex)[3], GPU::TPage tpage, GPU::PageClut clut, GPU::Color24 color) { + return creator_template(vertices_ex, tpage, clut, color); + } + + static constexpr GPU::POLY_G3 POLY_G3(const GPU::Vertex (&verticies)[3], const GPU::Color24 (&color)[3]) { + return creator_template(verticies, color); + } + + static constexpr GPU::POLY_G3 POLY_G3(const GPU::VertexColor (&verticies_ex)[3]) { + return creator_template(verticies_ex); + } + + static constexpr GPU::POLY_GT3 POLY_GT3(const GPU::Vertex (&verticies)[3], const GPU::PageOffset (&tex_offset)[3], const GPU::Color24 (&color)[3], GPU::TPage tpage, GPU::PageClut clut) { + return creator_template(verticies, tex_offset, color, tpage, clut); + } + + static constexpr GPU::POLY_GT3 POLY_GT3(const GPU::POLY_GT3::VertexEx (&verticies_ex)[3], GPU::TPage tpage, GPU::PageClut clut) { + return creator_template(verticies_ex, tpage, clut); + } + + static constexpr GPU::POLY_F4 POLY_F4(const GPU::Vertex (&verticies)[4], GPU::Color24 color) { + return creator_template(verticies, color); + } + + static constexpr GPU::POLY_F4 POLY_F4(const GPU::AreaI16& area, GPU::Color24 color) { + return creator_template(area, color); + } + + static constexpr GPU::POLY_FT4 POLY_FT4(const GPU::Vertex (&verticies)[4], const GPU::PageOffset (&tex_offset)[4], GPU::TPage tpage, GPU::PageClut clut, GPU::Color24 color) { + return creator_template(verticies, tex_offset, tpage, clut, color); + } + + static constexpr GPU::POLY_FT4 POLY_FT4(const GPU::POLY_FT4::VertexEx (&vertices_ex)[4], GPU::TPage tpage, GPU::PageClut clut, GPU::Color24 color = GPU::Color24::Grey()) { + return creator_template(vertices_ex, tpage, clut, color); + } + + static constexpr GPU::POLY_FT4 POLY_FT4(const GPU::AreaI16& area, const GPU::PageOffset& tex_offset, GPU::TPage tpage, GPU::PageClut clut, GPU::Color24 color = GPU::Color24::Grey()) { + return creator_template(area, tex_offset, tpage, clut, color); + } + + static constexpr GPU::POLY_G4 POLY_G4(const GPU::Vertex (&verticies)[4], const GPU::Color24 (&color)[4]) { + return creator_template(verticies, color); + } + + static constexpr GPU::POLY_G4 POLY_G4(const GPU::VertexColor (&verticies_ex)[4]) { + return creator_template(verticies_ex); + } + + static constexpr GPU::POLY_G4 POLY_G4(const GPU::AreaI16& area, const GPU::Color24 (&color)[4]) { + return creator_template(area, color); + } + + static constexpr GPU::POLY_GT4 POLY_GT4(const GPU::Vertex (&verticies)[4], const GPU::PageOffset (&tex_offset)[4], const GPU::Color24 (&color)[4], GPU::TPage tpage, GPU::PageClut clut) { + return creator_template(verticies, tex_offset, color, tpage, clut); + } + + static constexpr GPU::POLY_GT4 POLY_GT4(const GPU::POLY_GT4::VertexEx (&verticies_ex)[4], GPU::TPage tpage, GPU::PageClut clut) { + return creator_template(verticies_ex, tpage, clut); + } + + static constexpr GPU::POLY_GT4 POLY_GT4(const GPU::AreaI16& area, const GPU::PageOffset& tex_offset, GPU::TPage tpage, GPU::PageClut clut, const GPU::Color24 (&color)[4]) { + return creator_template(area, tex_offset, tpage, clut, color); + } + + // ################################################################### + + static constexpr GPU::TILE_1 TILE_1() { + return creator_template(Vertex(), GPU::Color24::Black()); + } + + static constexpr GPU::TILE_1 TILE_1(const GPU::Vertex& position, const GPU::Color24& color) { + return creator_template(position, color); + } + + static constexpr GPU::TILE_8 TILE_8() { + return creator_template(Vertex(), GPU::Color24::Black()); + } + + static constexpr GPU::TILE_8 TILE_8(const GPU::Vertex& position, const GPU::Color24& color) { + return creator_template(position, color); + } + + static constexpr GPU::TILE_16 TILE_16() { + return creator_template(Vertex(), GPU::Color24::Black()); + } + + static constexpr GPU::TILE_16 TILE_16(const GPU::Vertex& position, const GPU::Color24& color) { + return creator_template(position, color); + } + + static constexpr GPU::TILE TILE() { + return creator_template(AreaI16(), GPU::Color24::Black()); + } + + static constexpr GPU::TILE TILE(const GPU::AreaI16& area, const GPU::Color24& color) { + return creator_template(area, color); + } + + // ################################################################### + + static constexpr GPU::SPRT_1 SPRT_1() { + return creator_template(Vertex(), OffsetPageWithClut(), GPU::Color24::Black()); + } + + static constexpr GPU::SPRT_1 SPRT_1(const GPU::Vertex& position, const GPU::OffsetPageWithClut& tex_offset_w_clut, const GPU::Color24& color = GPU::Color24::Grey()) { + return creator_template(position, tex_offset_w_clut, color); + } + + static constexpr GPU::SPRT_8 SPRT_8() { + return creator_template(Vertex(), OffsetPageWithClut(), GPU::Color24::Black()); + } + + static constexpr GPU::SPRT_8 SPRT_8(const GPU::Vertex& position, const GPU::OffsetPageWithClut& tex_offset_w_clut, const GPU::Color24& color = GPU::Color24::Grey()) { + return creator_template(position, tex_offset_w_clut, color); + } + + static constexpr GPU::SPRT_16 SPRT_16() { + return creator_template(Vertex(), OffsetPageWithClut(), GPU::Color24::Black()); + } + + static constexpr GPU::SPRT_16 SPRT_16(const GPU::Vertex& position, const GPU::OffsetPageWithClut& tex_offset_w_clut, const GPU::Color24& color = GPU::Color24::Grey()) { + return creator_template(position, tex_offset_w_clut, color); + } + + static constexpr GPU::SPRT SPRT() { + return creator_template(AreaI16(), OffsetPageWithClut(), GPU::Color24::Black()); + } + + static constexpr GPU::SPRT SPRT(const GPU::AreaI16& area, const GPU::OffsetPageWithClut& tex_offset_w_clut, const GPU::Color24& color = GPU::Color24::Grey()) { + return creator_template(area, tex_offset_w_clut, color); + } + } +} \ No newline at end of file diff --git a/include/PSX/GTE/gte.hpp b/include/PSX/GTE/gte.hpp new file mode 100644 index 00000000..f7124d01 --- /dev/null +++ b/include/PSX/GTE/gte.hpp @@ -0,0 +1,241 @@ +#pragma once +#include "gte_instruction.hpp" + +namespace JabyEngine { + namespace GTE { + static constexpr auto StackSize = 16; + + /* + matrix: first input + + Sets the 3x3 constant rotation matrix and the parallel transfer vector from input + */ + void set_matrix(const MATRIX& matrix); + + /* + returns: current matrix + + Gets the current 3x3 constant rotation matrix and the parallel transfer vector + */ + MATRIX get_matrix(); + + /* + RotTrans + + Perform coordinate transformation using a rotation matrix + input: Input vector + output: Output vector + flag: flag output + */ + static void rot_trans(const SVECTOR& input, VECTOR& output, int32_t& flag) { + ldv0(input); + rt(); + stlvnl(output); + stflg(flag); + } + + /* + ScaleMatrix + + m: Pointer to matrix (input/output) + v: Pointer to scale vector (input) + + result: m + Scales m by v. The components of v are fixed point decimals in which 1.0 represents 4096 + */ + static ROTMATRIX& scale_matrix(ROTMATRIX& m, const VECTOR& v) { + static const auto multiply_matrix_row = [](int32_t value, ROTMATRIX& matrix, size_t row) { + ldir0(value); // lwc2 r8, v.x + ldclmv(matrix, row); // load matrix row to r9 - r11 (mtc2) + gpf12(); // gte_gpf12 + stclmv(matrix, row); // store matrix row + }; + + multiply_matrix_row(v.x, m, 0); + multiply_matrix_row(v.y, m, 1); + multiply_matrix_row(v.z, m, 2); + return m; + } + + /* + SetRotMatrix + + Sets a 3x3 matrix m as a constant rotation matrix. + matrix: The rotation matrix to set + */ + static void set_rot_matrix(const ROTMATRIX& matrix) { + __asm__ volatile("lw $12, 0(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("lw $13, 4(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $12, $0" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $13, $1" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("lw $12, 8(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("lw $13, 12(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("lw $14, 16(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $12, $2" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $13, $3" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $14, $4" :: "r"(&matrix) : "$12", "$13", "$14"); + } + + /* + GetRotMatrix + + Writes the current 3x3 constant rotation matrix to matrix + (This doesn't require us to use memory clobber) + */ + static void get_rot_matrix(ROTMATRIX &matrix) { + __asm__ volatile("cfc2 $12, $0" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("cfc2 $13, $1" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("sw $12, 0(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("sw $13, 4(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("cfc2 $12, $2" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("cfc2 $13, $3" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("cfc2 $14, $4" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("sw $12, 8(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("sw $13, 12(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("sw $14, 16(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + } + + /* + SetTransMatrix + + Sets a constant parallel transfer vector specified by m + */ + static void set_trans_vector(const TRANSFERVECTOR& vector) { + __asm__ volatile("lw $12, 0(%0)" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("lw $13, 4(%0)" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $12, $5" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("lw $14, 8(%0)" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $13, $6" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $14, $7" :: "r"(&vector) : "$12", "$13", "$14"); + } + + /* + GetTransMatrix + + Writes the current constant parallel transfer vector to matrix + (This doesn't require us to use memory clobber) + */ + static void get_trans_vector(TRANSFERVECTOR& vector) { + __asm__ volatile("cfc2 $14, $7" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("cfc2 $13, $6" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("sw $14, 8(%0)" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("cfc2 $12, $5" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("sw $13, 4(%0)" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("sw $12, 0(%0)" :: "r"(&vector) : "$12", "$13", "$14"); + } + + /* + ApplyMatrix + m0: Matrix to apply + v0: Vector to apply to + v1: Result + returns: result + + Applies the matrix to the vector + The function destroys the constant rotation matrix and transfer vector + */ + static SVECTOR& apply_matrix(const MATRIX& m0, const SVECTOR& v0, SVECTOR& v1) { + set_matrix(m0); + + JabyEngine::GTE::ldv0(v0); + JabyEngine::GTE::rt(); + JabyEngine::GTE::stsv(v1); + return v1; + } + + /* + Same as apply_matrix but works on Vertex + */ + static GPU::Vertex& apply_matrix(const MATRIX& m0, const GPU::Vertex& v0, GPU::Vertex& v1) { + set_matrix(m0); + + JabyEngine::GTE::ldgv0(v0); + JabyEngine::GTE::rt(); + JabyEngine::GTE::stgv(v1); + return v1; + } + + /* + MulMatrix0 + + m0: first input + m1: second input + result: result of multiplication + returns: result + + Multiplies two matrices m0 and m1. + The function destroys the constant rotation matrix + */ + ROTMATRIX& multiply_matrix(const ROTMATRIX& m0, const ROTMATRIX& m1, ROTMATRIX& result); + + /* + CompMatrix + + m0: first input + m1: second input + result: result of computing m0 and m1 + return: returns result + */ + static MATRIX& comp_matrix(const MATRIX& m0, const MATRIX& m1, MATRIX& result) { + multiply_matrix(m0.rotation, m1.rotation, result.rotation); + set_trans_vector(m0.transfer); + GTE::ldlv0(reinterpret_cast(m1.transfer)); + GTE::rt(); + GTE::stlvnl(reinterpret_cast(result.transfer)); + + return result; + } + + /* + matrix: optional input + + Pushes the current matrix (rotation and parallel) to an internal stack + Optional: replaces current matrix (rotation and parallel) with input + */ + void push_matrix(); + void push_matrix_and_set(const MATRIX& matrix); + + /* + Restores the previous stored matrix (rotation and parallel) + */ + MATRIX get_and_pop_matrix(); + void pop_matrix(); + + /* + SetGeomOffset(ofx,ofy) + + Load GTE-offset. + */ + static void set_geom_offset(int32_t off_x, int32_t off_y) { + __asm__ volatile("sll $12, %0, 16" :: "r"(off_x), "r"(off_y) : "$12", "$13"); + __asm__ volatile("sll $13, %1, 16" :: "r"(off_x), "r"(off_y) : "$12", "$13"); + __asm__ volatile("ctc2 $12, $24" :: "r"(off_x), "r"(off_y) : "$12", "$13"); + __asm__ volatile("ctc2 $13, $25" :: "r"(off_x), "r"(off_y) : "$12", "$13"); + } + + /* + SetGeomScreen(h) + + Load distance from viewpoint to screen. + */ + static void set_geom_screen(int32_t h) { + __asm__ volatile("ctc2 %0, $26" :: "r"(h)); + } + + // Implementations for the MATRIX struct + inline MATRIX& MATRIX :: comp(const MATRIX& matrix) { + return comp_matrix(matrix, *this, *this); + } + + inline GPU::Vertex& MATRIX :: apply_to(GPU::Vertex& vertex) const { + return apply_matrix(*this, vertex, vertex); + } + + inline GPU::Vertex MATRIX :: apply_to(const GPU::Vertex& vertex) const { + GPU::Vertex result; + + apply_matrix(*this, vertex, result); + return result; + } + } +} \ No newline at end of file diff --git a/include/PSX/GTE/gte_instruction.hpp b/include/PSX/GTE/gte_instruction.hpp new file mode 100644 index 00000000..9f5b9ca3 --- /dev/null +++ b/include/PSX/GTE/gte_instruction.hpp @@ -0,0 +1,137 @@ +#pragma once +#include "gte_types.hpp" + +namespace JabyEngine { + namespace GTE { + // Load vertex or normal to vertex register 0 + static __always_inline void ldv0(const SVECTOR& vector) { + __asm__ volatile("lwc2 $0, 0(%0)" :: "r"(&vector)); + __asm__ volatile("lwc2 $1, 4(%0)" :: "r"(&vector)); + } + + // Load vertex or normal to vertex register 1 + static __always_inline void ldv1(const SVECTOR& vector) { + __asm__ volatile("lwc2 $2, 0(%0)" :: "r"(&vector)); + __asm__ volatile("lwc2 $3, 4(%0)" :: "r"(&vector)); + } + + // Load vertex or normal to vertex register 2 + static __always_inline void ldv2(const SVECTOR& vector) { + __asm__ volatile("lwc2 $4, 0(%0)" :: "r"(&vector)); + __asm__ volatile("lwc2 $5, 4(%0)" :: "r"(&vector)); + } + + // Load int32_t to ir0 register (for multiplying usually) + static __always_inline void ldir0(const int32_t& value) { + __asm__ volatile("lwc2 $8, 0(%0)" :: "r"(&value)); + } + + // Load LS 16 bits of VECTOR to 16 bit universal vector. + static __always_inline void ldlv0(const VECTOR& vector) { + __asm__ volatile("lhu $13, 4(%0)" :: "r"(&vector) : "$12", "$13"); + __asm__ volatile("lhu $12, 0(%0)" :: "r"(&vector) : "$12", "$13"); + __asm__ volatile("sll $13, $13, 16" :: "r"(&vector) : "$12", "$13"); + __asm__ volatile("or $12, $12, $13" :: "r"(&vector) : "$12", "$13"); + __asm__ volatile("mtc2 $12, $0" :: "r"(&vector) : "$12", "$13"); + __asm__ volatile("lwc2 $1, 8(%0)" :: "r"(&vector) : "$12", "$13"); + } + + // Loads a GPU VERTEX type + static __always_inline void ldgv0(const GPU::Vertex& vertex) { + __asm__ volatile("lwc2 $0, 0(%0)" :: "r"(&vertex)); + __asm__ volatile("lwc2 $1, 0" :: "r"(&vertex)); + } + + // Load column vector of MATRIX to universal register + static __always_inline void ldclmv(const ROTMATRIX& matrix, size_t col) { + __asm__ volatile("lhu $12, 0(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); + __asm__ volatile("lhu $13, 6(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); + __asm__ volatile("lhu $14, 12(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); + __asm__ volatile("mtc2 $12, $9" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); + __asm__ volatile("mtc2 $13, $10" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); + __asm__ volatile("mtc2 $14, $11" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); + } + + // Store flag + static __always_inline void stflg(int32_t& flag) { + __asm__ volatile("cfc2 $12, $31" :: "r"(&flag) : "$12", "memory"); + __asm__ volatile("nop" :: "r"(&flag) : "$12", "memory"); + __asm__ volatile("sw $12, 0(%0)" :: "r"(&flag) : "$12", "memory"); + } + + // Store MATRIX column from 16 bit universal register + static __always_inline void stclmv(ROTMATRIX& matrix, size_t col) { + __asm__ volatile("mfc2 $12, $9" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); + __asm__ volatile("mfc2 $13, $10" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); + __asm__ volatile("mfc2 $14, $11" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $12, 0(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $13, 6(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $14, 12(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); + } + + // Store VECTOR from 32 bit universal register + static __always_inline void stlvnl(VECTOR& out_vector) { + __asm__ volatile("swc2 $25, 0(%0)" :: "r"(&out_vector) : "memory"); + __asm__ volatile("swc2 $26, 4(%0)" :: "r"(&out_vector) : "memory"); + __asm__ volatile("swc2 $27, 8(%0)" :: "r"(&out_vector) : "memory"); + } + + // Modify to store in VERTEX? + // Store SVECTOR from 16 bit universal register + static __always_inline void stsv(SVECTOR& out_vector) { + __asm__ volatile("mfc2 $12, $9" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); + __asm__ volatile("mfc2 $13, $10" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); + __asm__ volatile("mfc2 $14, $11" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $12, 0(%0)" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $13, 2(%0)" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $14, 4(%0)" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); + } + + // Stores result into a GPU Vertex type + static __always_inline void stgv(GPU::Vertex& out_vertex) { + __asm__ volatile("mfc2 $12, $9" :: "r"(&out_vertex) : "$12", "$13", "$14", "memory"); + __asm__ volatile("mfc2 $13, $10" :: "r"(&out_vertex) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $12, 0(%0)" :: "r"(&out_vertex) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $13, 2(%0)" :: "r"(&out_vertex) : "$12", "$13", "$14", "memory"); + } + + /* + Kernel of RotTrans + (Transfer vector)+(Rotation Matrix)*(vertex register 0) + */ + static __always_inline void rt() { + __asm__ volatile("nop"); + __asm__ volatile("nop"); + __asm__ volatile("cop2 0x0480012"); + } + + /* + Variation of gte_rt + (Rotation Matrix)*(vertex register 0). + */ + static __always_inline void rtv0() { + __asm__ volatile("nop;"); + __asm__ volatile("nop;"); + __asm__ volatile("cop2 0x0486012;"); + } + + /* + Variation of gte_rt + (Rotation Matrix)*(16 bit universal vector) + */ + static __always_inline void rtir() { + __asm__ volatile("nop"); + __asm__ volatile("nop"); + __asm__ volatile("cop2 0x049E012"); + } + + /* + Last half of LoadAverage12. + */ + static __always_inline void gpf12(){ + __asm__ volatile("nop"); + __asm__ volatile("nop"); + __asm__ volatile("cop2 0x0198003D"); + } + } +} \ No newline at end of file diff --git a/include/PSX/GTE/gte_types.hpp b/include/PSX/GTE/gte_types.hpp new file mode 100644 index 00000000..300c6920 --- /dev/null +++ b/include/PSX/GTE/gte_types.hpp @@ -0,0 +1,138 @@ +#pragma once +#include "../GPU/Primitives/primitive_poly_types.hpp" +#include "../GPU/gpu_types.hpp" +#include "../../math.hpp" +#include "../../stdio.hpp" + +namespace JabyEngine { + namespace GTE { + namespace internal { + template + struct VECTOR { + T x; + T y; + T z; + T pad; + + static constexpr VECTOR create() { + return VECTOR::create(0, 0, 0); + } + + static constexpr VECTOR create(T x, T y, T z) { + return VECTOR{.x = x, .y = y, .z = z, .pad = 0}; + } + + static constexpr VECTOR create(gte_float x, gte_float y, gte_float z) { + return VECTOR{.x = static_cast(x), .y = static_cast(y), .z = static_cast(z)}; + } + + template + static constexpr VECTOR from(const GPU::Position& pos) { + return VECTOR::create(static_cast(pos.x), static_cast(pos.y), 0); + } + + template + constexpr S to() const { + return S::create(static_cast(this->x), static_cast(this->y)); + } + }; + } + using VECTOR = internal::VECTOR; + using SVECTOR = internal::VECTOR; + + struct ROTMATRIX { + int16_t matrix[3][3]; + + static constexpr ROTMATRIX identity() { + return ROTMATRIX{.matrix = { + {static_cast(gte_float::one()), 0, 0}, + {0, static_cast(gte_float::one()), 0}, + {0, 0, static_cast(gte_float::one())} + } + }; + } + + static constexpr ROTMATRIX scaled(gte_float sx = 1.0_gf, gte_float sy = 1.0_gf, gte_float sz = 1.0_gf) { + return ROTMATRIX{.matrix = { + {static_cast(sx), 0, 0}, + {0, static_cast(sy), 0}, + {0, 0, static_cast(sz)} + } + }; + } + + static ROTMATRIX rotated(deg_t x = 0.0_deg, deg_t y = 0.0_deg, deg_t z = 0.0_deg); + }; + + struct TRANSFERVECTOR : public VECTOR { + static constexpr TRANSFERVECTOR identity() { + return TRANSFERVECTOR::translated(); + } + + static constexpr TRANSFERVECTOR translated(int32_t x = 0, int32_t y = 0, int32_t z = 0) { + return TRANSFERVECTOR{{.x = x, .y = y, .z = z}}; + } + }; + + struct MATRIX { + ROTMATRIX rotation; + TRANSFERVECTOR transfer; + + static constexpr MATRIX identity() { + return MATRIX{.rotation = ROTMATRIX::identity(), .transfer = TRANSFERVECTOR::identity()}; + } + + static constexpr MATRIX translated(int32_t x = 0, int32_t y = 0, int32_t z = 0) { + return MATRIX{.rotation = ROTMATRIX::identity(), .transfer = TRANSFERVECTOR::translated(x, y, z)}; + } + + static constexpr MATRIX scaled(gte_float sx = 1.0_gf, gte_float sy = 1.0_gf, gte_float sz = 1.0_gf) { + return MATRIX{.rotation = ROTMATRIX::scaled(sx, sy, sz), .transfer = TRANSFERVECTOR::identity()}; + } + + static MATRIX rotated(deg_t x = 0.0_deg, deg_t y = 0.0_deg, deg_t z = 0.0_deg) { + return MATRIX{.rotation = ROTMATRIX::rotated(x, y, z), .transfer = TRANSFERVECTOR::identity()}; + } + + static MATRIX comp(MATRIX new_matrix, const MATRIX& matrix) { + new_matrix.comp(matrix); + return new_matrix; + } + + void dump() const { + printf("---\n"); + printf("|%i|%i|%i|\n", this->rotation.matrix[0][0], this->rotation.matrix[0][1], this->rotation.matrix[0][2]); + printf("|%i|%i|%i|\n", this->rotation.matrix[1][0], this->rotation.matrix[1][1], this->rotation.matrix[1][2]); + printf("|%i|%i|%i|\n", this->rotation.matrix[2][0], this->rotation.matrix[2][1], this->rotation.matrix[2][2]); + printf("~~~\n"); + printf("|%i|%i|%i|\n", this->transfer.x, this->transfer.y, this->transfer.z); + printf("---\n"); + } + + MATRIX& comp(const MATRIX& matrix); + MATRIX& translate(int32_t x = 0, int32_t y = 0, int32_t z = 0) { + return MATRIX::comp(MATRIX::translated(x, y, z)); + } + + MATRIX& scale(gte_float sx = 1.0_gf, gte_float sy = 1.0_gf, gte_float sz = 1.0_gf) { + return MATRIX::comp(MATRIX::scaled(sx, sy, sz)); + } + + MATRIX& rotate(deg_t x = 0.0_deg, deg_t y = 0.0_deg, deg_t z = 0.0_deg) { + return MATRIX::comp(MATRIX::rotated(x, y, z)); + } + + GPU::Vertex& apply_to(GPU::Vertex& vertex) const; + GPU::Vertex apply_to(const GPU::Vertex& vertex) const; + + template + T& apply_to_area(T& poly, const GPU::AreaI16& area) const { + poly.vertex0 = MATRIX::apply_to(GPU::POLY_G4::vertex0_from(area)); + poly.vertex1 = MATRIX::apply_to(GPU::POLY_G4::vertex1_from(area)); + poly.vertex2 = MATRIX::apply_to(GPU::POLY_G4::vertex2_from(area)); + poly.vertex3 = MATRIX::apply_to(GPU::POLY_G4::vertex3_from(area)); + return poly; + } + }; + } +} \ No newline at end of file diff --git a/include/PSX/Overlay/overlay.hpp b/include/PSX/Overlay/overlay.hpp index 1040eed4..bc2121d0 100644 --- a/include/PSX/Overlay/overlay.hpp +++ b/include/PSX/Overlay/overlay.hpp @@ -1,5 +1,4 @@ -#ifndef __JABYENGINE_OVERLAY__HPP__ -#define __JABYENGINE_OVERLAY__HPP__ +#pragma once #include "../AutoLBA/auto_lba.hpp" namespace JabyEngine { @@ -7,5 +6,4 @@ namespace JabyEngine { // Can be used to create dummy values to trick LZ4 into compressing an uncompressed overlay #define __create_dummy_fill(length) static const uint8_t __section(".keep.dummy") __used DummyFilling[length] = {0x0} -} -#endif //!__JABYENGINE_OVERLAY__HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/Overlay/overlay_declaration.hpp b/include/PSX/Overlay/overlay_declaration.hpp deleted file mode 100644 index 85cf0449..00000000 --- a/include/PSX/Overlay/overlay_declaration.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __JABYENGINE_OVERLAY_DECLARATION__HPP__ -#define __JABYENGINE_OVERLAY_DECLARATION__HPP__ - -// No include here because this header should be included in a namespace and we don't want multiple namespace definitions of OverlayHeader and OverlayLBA - -#include "../AutoLBA/auto_lba_declaration.hpp" - -#define __declare_overlay_header(function, enum_struct) \ -__declare_lba_header(enum_struct) -#endif //!__JABYENGINE_OVERLAY_DECLARATION__HPP__ \ No newline at end of file diff --git a/include/PSX/Periphery/controller.hpp b/include/PSX/Periphery/controller.hpp new file mode 100644 index 00000000..80e25207 --- /dev/null +++ b/include/PSX/Periphery/controller.hpp @@ -0,0 +1,107 @@ +#pragma once +#include "../GPU/gpu_types.hpp" +#include "raw_controller.hpp" + +namespace JabyEngine { + namespace Periphery { + class GenericController : public RawController { + public: + struct Rumble { + static constexpr uint8_t LargeMotorThreshold = 0x60; + }; + + enum struct Button : uint16_t { + L2 = static_cast(GenericButton::D0), + R2 = static_cast(GenericButton::D1), + L1 = static_cast(GenericButton::D2), + R1 = static_cast(GenericButton::D3), + Triangle = static_cast(GenericButton::D4), + Circle = static_cast(GenericButton::D5), + Cross = static_cast(GenericButton::D6), + Square = static_cast(GenericButton::D7), + SEL = static_cast(GenericButton::D8), + ST = static_cast(GenericButton::D11), + Up = static_cast(GenericButton::D12), + Right = static_cast(GenericButton::D13), + Down = static_cast(GenericButton::D14), + Left = static_cast(GenericButton::D15) + }; + + void set_digital_rumble() { + RawController::header.rumble0 = 0x1; + RawController::header.rumble1 = 0x7F; + } + + void set_analog_rumble(uint8_t largeMotor, bool smallMotor) { + RawController::header.rumble0 = smallMotor ? 0x1 : 0x0; + RawController::header.rumble1 = largeMotor; + } + + void stopRumble() { + RawController::header.rumble0 = 0x0; + RawController::header.rumble1 = 0x0; + } + + bool is_small_rumble() const { + return static_cast(RawController::header.rumble0); + } + + uint8_t get_large_rumble() const { + return RawController::header.rumble1; + } + + bool is_connected() const { + return RawController::header.state != RawController::State::Disconnected; + } + + bool is_useable() const { + const auto type = RawController::get_type(); + return ((RawController::header.state == RawController::State::Stable) && (type == ControllerType::Controller || type == ControllerType::DualShock)); + } + }; + + class AnalogeController : public GenericController { + public: + enum struct Button : uint16_t { + L2 = static_cast(GenericButton::D0), + R2 = static_cast(GenericButton::D1), + L1 = static_cast(GenericButton::D2), + R1 = static_cast(GenericButton::D3), + Triangle = static_cast(GenericButton::D4), + Circle = static_cast(GenericButton::D5), + Cross = static_cast(GenericButton::D6), + Square = static_cast(GenericButton::D7), + SEL = static_cast(GenericButton::D8), + L3 = static_cast(GenericButton::D9), + R3 = static_cast(GenericButton::D10), + ST = static_cast(GenericButton::D11), + Up = static_cast(GenericButton::D12), + Right = static_cast(GenericButton::D13), + Down = static_cast(GenericButton::D14), + Left = static_cast(GenericButton::D15) + }; + + private: + uint8_t read_special_byte(size_t idx) const { + return reinterpret_cast(this->special)[idx]; + } + + public: + GPU::PositionI16 get_right_stick_pos() const { + const uint8_t joy_x = AnalogeController::read_special_byte(0); + const uint8_t joy_y = AnalogeController::read_special_byte(1); + + return GPU::PositionI16::create(joy_x - 0x80, joy_y - 0x80); + } + + GPU::PositionI16 get_left_stick_pos() const { + const uint8_t joy_x = AnalogeController::read_special_byte(2); + const uint8_t joy_y = AnalogeController::read_special_byte(3); + + return GPU::PositionI16::create(joy_x - 0x80, joy_y - 0x80); + } + }; + + using GenericButtonState = GenericController::ButtonState; + } +} \ No newline at end of file diff --git a/include/PSX/Periphery/periphery.hpp b/include/PSX/Periphery/periphery.hpp new file mode 100644 index 00000000..8cdc7a57 --- /dev/null +++ b/include/PSX/Periphery/periphery.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "../jabyengine_config.hpp" +#include "controller.hpp" + +namespace JabyEngine { + namespace Periphery { + static constexpr uint32_t PortCount = Configuration::Periphery::include_portB() ? 2 : 1; + static constexpr uint32_t DeviceCount = Configuration::Periphery::use_multi_tap() ? 4 : 1; + + extern RawController controller[PortCount][DeviceCount]; + + void query_controller(); + + template + inline T& get_controller_as(size_t port, size_t device) { + return *reinterpret_cast(&controller[port][device]); + } + + template + inline T& get_primary_controller_as() { + return get_controller_as(0, 0); + } + } +} \ No newline at end of file diff --git a/include/PSX/Periphery/raw_controller.hpp b/include/PSX/Periphery/raw_controller.hpp new file mode 100644 index 00000000..3d675aee --- /dev/null +++ b/include/PSX/Periphery/raw_controller.hpp @@ -0,0 +1,137 @@ +#pragma once +#include "../jabyengine_defines.hpp" + +namespace JabyEngine { + namespace Periphery { + enum struct ControllerType : uint8_t { + Unkown = 0x0, + Mouse = 0x1, + NegCon = 0x2, + HyperBlaster = 0x3, // Konami Lightgun + Controller = 0x4, + ArcadeFlightStick = 0x5, + GCon = 0x6, + DualShock = 0x7, + MultiTap = 0x8 + }; + + enum struct GenericButton : uint16_t { + D8 = (1 << 0), + D9 = (1 << 1), + D10 = (1 << 2), + D11 = (1 << 3), + D12 = (1 << 4), + D13 = (1 << 5), + D14 = (1 << 6), + D15 = (1 << 7), + D0 = (1 << 8), + D1 = (1 << 9), + D2 = (1 << 10), + D3 = (1 << 11), + D4 = (1 << 12), + D5 = (1 << 13), + D6 = (1 << 14), + D7 = (1 << 15) + }; + + struct LED { + enum struct State : uint8_t { + Off = 0x0, + On = 0x1 + }; + + enum struct Lock { + Off = 0x2, + On = 0x3 + }; + }; + + class RawController { + public: + enum struct State : uint8_t + { + Disconnected = 0, + EnterConfigMode = (1 << 0), + LockAnalog = (1 << 1), + UnlockRumble = (1 << 2), + ExitConfigMode = (1 << 3), + Stable = (1 << 4) + }; + + protected: + struct Header { + uint8_t type; + State state; + uint8_t rumble0; + uint8_t rumble1; + + void clear() { + this->type = 0; + this->state = State::Disconnected; + } + }; + + public: + class ButtonState { + private: + uint16_t oldState; + uint16_t currentState; + + static bool is_down(uint16_t data, uint16_t button) { + return ((data & button) == 0); + } + + void exchange_state() { + this->oldState = this->currentState; + } + + public: + template + bool is_down(T button) const { + return ButtonState::is_down(this->currentState, static_cast(button)); + } + + template + bool was_down(T button) const { + return ButtonState::is_down(this->oldState, static_cast(button)); + } + + template + bool went_down(T button) const { + return (!ButtonState::was_down(button) && ButtonState::is_down(button)); + } + + template + bool went_up(T button) const { + return (ButtonState::was_down(button) && !ButtonState::is_down(button)); + } + + friend class RawController; + friend struct ControllerHelper; + friend void query_controller(); + }; + + Header header; + ButtonState button; + uint32_t special; + + public: + ControllerType get_type() const { + return static_cast((this->header.type >> 4)); + } + + ButtonState get_button_state() const { + return this->button; + } + + //For debugging only + uint8_t get_raw_type() const { + return this->header.type; + } + + uint16_t get_raw_button_state() const { + return this->button.currentState; + } + }; + } +} \ No newline at end of file diff --git a/include/PSX/SPU/spu.hpp b/include/PSX/SPU/spu.hpp new file mode 100644 index 00000000..89329e00 --- /dev/null +++ b/include/PSX/SPU/spu.hpp @@ -0,0 +1,51 @@ +#pragma once +#include "../System/IOPorts/spu_io.hpp" + +namespace JabyEngine { + namespace SPU { + using SPU_IO_Values::operator""_vol; + + using SRAMAdr = SPU_IO_Values::SRAMAdr; + using SimpleVolume = SPU_IO_Values::SimpleVolume; + using SweepVolume = SPU_IO_Values::SweepVolume; + + struct Voice { + size_t get_id() const { + return reinterpret_cast(this); + } + + SRAMAdr allocate(size_t size); + SRAMAdr allocate(SPU_IO_Values::SampleRate frequency, size_t size); + void deallocate(); + + void set_sample_rate(SPU_IO_Values::SampleRate frequency) { + SPU_IO::Voice[Voice::get_id()].sampleRate.write(frequency); + } + + void set_volume(SimpleVolume left, SimpleVolume right) { + SPU_IO::Voice[Voice::get_id()].volumeLeft.write(SweepVolume::create(left)); + SPU_IO::Voice[Voice::get_id()].volumeRight.write(SweepVolume::create(right)); + } + + void play() { + SPU_IO::Key::On.write(SPU_IO_Values::KeyOn::for_specific(Voice::get_id())); + } + + void play_if_end() { + if(Voice::is_end()) { + Voice::play(); + } + } + + void stop() { + SPU_IO::Key::Off.write(SPU_IO_Values::KeyOff::for_specific(Voice::get_id())); + } + + bool is_end() const { + return SPU_IO::Voice[Voice::get_id()].adsr_volume.read() == SimpleVolume::mute(); + } + }; + + static auto& voice = __declare_io_port_array(Voice, SPU_IO::VoiceCount, 0x0); + } +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/cd_io_values.hpp b/include/PSX/System/IOPorts/IOValues/cd_io_values.hpp new file mode 100644 index 00000000..f99c160c --- /dev/null +++ b/include/PSX/System/IOPorts/IOValues/cd_io_values.hpp @@ -0,0 +1,106 @@ +#pragma once +#include "ioport.hpp" + +namespace JabyEngine { + namespace CD_IO_Values { + __declare_io_struct(AudioVolumeApply, uint8_t) { + static constexpr auto Mute = Bit(0); + static constexpr auto ApplyChanges = Bit(5); + }; + + struct CDDAVolume { + using Type = uint8_t; + + static constexpr uint8_t Off = 0x0; + static constexpr uint8_t Default = 0x80; + static constexpr uint8_t Max = 0xFF; + }; + + __declare_io_struct(CommandFifo, uint8_t) { + }; + + __declare_io_struct(DataFifo, uint8_t) { + }; + + __declare_io_struct(DataFifo16, uint16_t) { + }; + + __declare_io_struct(InterruptEnable, uint8_t) { + static constexpr auto InterruptTypValue = BitRange::from_to(0, 2); + static constexpr auto InterruptExtended = BitRange::from_to(0, 4); + static constexpr auto UnknownIRQ = Bit(3); + static constexpr auto CommandStartIRQ = Bit(4); + }; + using InterruptFlag = InterruptEnable; + + __declare_io_struct(IndexStatus, uint8_t) { + static constexpr auto PortIndex = BitRange::from_to(0, 1); + static constexpr auto HasXAFifoData = Bit(2); + static constexpr auto IsParameterFifoEmpty = Bit(3); + static constexpr auto HasParameterFifoSpace = Bit(4); + static constexpr auto HasResponseFifoData = Bit(5); + static constexpr auto HasDataFifoData = Bit(6); + static constexpr auto IsTransmissionBusy = Bit(7); + }; + + __declare_io_struct(LeftCD2LeftSPU, CDDAVolume::Type) { + }; + + __declare_io_struct(LeftCD2RightSPU, CDDAVolume::Type) { + }; + + __declare_io_struct(Mode, uint8_t) { + static constexpr auto DoubleSpeed = Bit(7); + static constexpr auto SingleSpeed = !DoubleSpeed; + static constexpr auto XADPCM = Bit(6); + static constexpr auto WholeSector = Bit(5); + static constexpr auto DataSector = !WholeSector; + static constexpr auto UseXAFilter = Bit(3); + static constexpr auto AudioPlayIRQ = Bit(2); + static constexpr auto AutoPauseTrack = Bit(1); + static constexpr auto CDDA = Bit(0); + + operator uint8_t() const { + return this->raw; + } + }; + + __declare_io_struct(ParameterFifo, uint8_t) { + }; + + __declare_io_struct(Request, uint8_t) { + static constexpr auto WantCommandStartIRQ = Bit(5); + static constexpr auto WantData = Bit(7); + + static Request want_data() { + return Request{static_cast(Request::WantData)}; + } + + static Request reset() { + return Request{0}; + } + }; + + __declare_io_struct(ResponseFifo, uint8_t) { + }; + + __declare_io_struct(RightCD2LeftSPU, CDDAVolume::Type) { + }; + + __declare_io_struct(RightCD2RightSPU, CDDAVolume::Type) { + }; + + __declare_io_struct(SoundMapCoding, uint8_t) { + static constexpr auto Stereo = Bit(0); + static constexpr auto Mono = !Stereo; + static constexpr auto SampleRate_18900hz = Bit(2); + static constexpr auto SampleRate_37800hz = !SampleRate_18900hz; + static constexpr auto BitsPerSample8 = Bit(4); + static constexpr auto BitsPerSample4 = !BitsPerSample8; + static constexpr auto Emphasis = Bit(6); + }; + + __declare_io_struct(SoundMapDataOut, uint8_t) { + }; + } +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/dma_io_values.hpp b/include/PSX/System/IOPorts/IOValues/dma_io_values.hpp new file mode 100644 index 00000000..78b5cfb5 --- /dev/null +++ b/include/PSX/System/IOPorts/IOValues/dma_io_values.hpp @@ -0,0 +1,152 @@ +#pragma once +#include "ioport.hpp" + +namespace JabyEngine { + namespace DMA_IO_Values { + using Priority = uint32_t; + static constexpr Priority HighestPriority = 0; + static constexpr Priority LowestPriority = 7; + + __declare_io_struct(BCR, uint32_t) { + struct SyncMode0 { + static constexpr auto NumberOfWords = BitRange::from_to(0, 15); + static constexpr auto CD_OneBlock = Bit(16); + + static constexpr BCR for_cd(size_t words) { + return BCR::from(SyncMode0::CD_OneBlock, SyncMode0::NumberOfWords.with(words)); + } + }; + + struct SyncMode1 { + static constexpr auto BlockSize = BitRange::from_to(0, 15); + static constexpr auto BlockAmount = BitRange::from_to(16, 31); + }; + + struct SyncMode2 { + static constexpr BCR for_gpu_cmd() { + return {0}; + } + }; + }; + + __declare_io_struct(CHCHR, uint32_t) { + enum SyncMode_t { + Sync0 = 0, //Start immediately, + Sync1 = 1, //Sync blocks to DMA requests + Sync2 = 2, //Linked List + }; + + static constexpr auto ManualStart = Bit(28); + + static constexpr auto Start = Bit(24); + static constexpr auto Busy = Start; + + static constexpr auto ChoppingCPUWindowSize = BitRange::from_to(20, 22); + static constexpr auto ChoppingDMAWindowSize = BitRange::from_to(16, 18); + + static constexpr auto SyncMode = BitRange::from_to(9, 10); + static constexpr auto UseSyncMode0 = SyncMode.with(Sync0); + static constexpr auto UseSyncMode1 = SyncMode.with(Sync1); + static constexpr auto UseSyncMode2 = SyncMode.with(Sync2); + + static constexpr auto UseChopping = Bit(8); + + static constexpr auto MemoryAdrDecreaseBy4 = Bit(1); + static constexpr auto MemoryAdrIncreaseBy4 = !MemoryAdrDecreaseBy4; + + static constexpr auto FromMainRAM = Bit(0); + static constexpr auto ToMainRAM = !FromMainRAM; + + static constexpr CHCHR StartMDECin() { + return CHCHR{0x01000201}; + } + + static constexpr CHCHR StartMDECout() { + return CHCHR{0x01000200}; + } + + static constexpr CHCHR StartGPUReceive() { + return CHCHR{0x01000201}; + } + + static constexpr CHCHR StartGPULinked() { + return CHCHR{0x01000401}; + } + + static constexpr CHCHR StartCDROM() { + return CHCHR{0x11000000}; + } + + static constexpr CHCHR StartSPUReceive() { + return CHCHR{0x01000201}; + } + + static constexpr CHCHR StartOTC() { + return CHCHR{0x11000002}; + } + }; + + __declare_io_struct(DICR, uint32_t) { + static constexpr auto MasterEnable = Bit(31); + static constexpr auto Flags = BitRange::from_to(24, 30); + static constexpr auto MasterEnableDPCR = Bit(23); + static constexpr auto EnableDPCR = BitRange::from_to(16, 22); + static constexpr auto ForceIRQ = Bit(15); + + static constexpr DICR empty() { + return DICR{0}; + } + }; + + __declare_io_struct(DPCR, uint32_t) { + struct DMASetting { + uint16_t master_bit; + + static constexpr DMASetting create(uint16_t master_bit) { + return DMASetting{master_bit}; + } + + constexpr BitRange::RangeValuePair turn_on(uint8_t priority) const { + return BitRange::from_to(this->master_bit - 3, this->master_bit).with(static_cast(0b1000 + (priority & 0b111))); + } + + constexpr ClearBit turn_off() const { + return ClearBit(this->master_bit); + } + }; + + static constexpr const auto OTC = DMASetting(27); + static constexpr const auto PIO = DMASetting(23); + static constexpr const auto SPU = DMASetting(19); + static constexpr const auto CDROM = DMASetting(15); + static constexpr const auto GPU = DMASetting(11); + static constexpr const auto MDEC_Out = DMASetting(7); + static constexpr const auto MDEC_In = DMASetting(3); + + static constexpr auto OTCEnabled = Bit(27); + static constexpr auto OTCPriority = BitRange::from_to(24, 26); + + static constexpr auto PIOEnabled = Bit(23); + static constexpr auto PIOPriority = BitRange::from_to(20, 22); + + static constexpr auto SPUEnabled = Bit(19); + static constexpr auto SPUPriority = BitRange::from_to(16, 18); + + static constexpr auto CDROMEnabled = Bit(15); + static constexpr auto CDROMPriority = BitRange::from_to(12, 14); + + static constexpr auto GPUEnabled = Bit(11); + static constexpr auto GPUPriority = BitRange::from_to(8, 10); + + static constexpr auto MDECoutEnabled = Bit(7); + static constexpr auto MDECoutPriority = BitRange::from_to(4, 6); + + static constexpr auto MDECinEnabled = Bit(3); + static constexpr auto MDECinPriority = BitRange::from_to(0, 2); + }; + + __declare_io_struct(MADR, uint32_t) { + static constexpr auto MemoryAdr = BitRange::from_to(0, 23); + }; + } +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/gpu_io_values.hpp b/include/PSX/System/IOPorts/IOValues/gpu_io_values.hpp new file mode 100644 index 00000000..c015b2b5 --- /dev/null +++ b/include/PSX/System/IOPorts/IOValues/gpu_io_values.hpp @@ -0,0 +1,220 @@ +#pragma once +#include "../../../GPU/gpu_types.hpp" +#include "ioport.hpp" + +namespace JabyEngine { + namespace GPU_IO_Values { + namespace internal { + template + static constexpr T construct_cmd(uint32_t cmd, uint32_t value) { + return T::from(T::ID.with(cmd), T::Value.with(value)); + } + } + + __declare_io_struct(DisplayMode, uint32_t) { + enum AreaColorDepth { + $15bit = 0, + $24bit = 1, + }; + + enum State { + On = 0, + Off = 1 + }; + + enum HorizontalResolution { + $256 = 0, + $320 = 1, + $512 = 2, + $640 = 3, + }; + + enum struct TVEncoding { + NTSC = 0, + PAL = 1, + }; + + enum VerticalResolution { + $240 = 0, + $480 = 1 + }; + + static constexpr auto HorizontalResolution368 = Bit(6); + static constexpr auto VerticalInterlace = Bit(5); + static constexpr auto DisplayAreaColorDepth = BitRange::from_to(4, 4); + static constexpr auto VideoMode = BitRange::from_to(3, 3); + static constexpr auto VerticalResolution = BitRange::from_to(2, 2); + static constexpr auto HorizontalResolution = BitRange::from_to(0, 1); + + static constexpr DisplayMode PAL() { + return DisplayMode::from( + HorizontalResolution.with(HorizontalResolution::$320), + VerticalResolution.with(VerticalResolution::$240), + VideoMode.with(TVEncoding::PAL), + DisplayAreaColorDepth.with(AreaColorDepth::$15bit) + ); + } + + static constexpr DisplayMode NTSC() { + return DisplayMode::from( + HorizontalResolution.with(HorizontalResolution::$320), + VerticalResolution.with(VerticalResolution::$240), + VideoMode.with(TVEncoding::NTSC), + DisplayAreaColorDepth.with(AreaColorDepth::$15bit) + ); + } + }; + + __declare_io_struct(GPUREAD, uint32_t) { + }; + + __declare_io_struct(GPUSTAT, uint32_t) { + enum DMADirection { + Off = 0, + Fifo = 1, + CPU2GPU = 2, + GPU2CPU = 3, + }; + + static constexpr auto DrawingOddLinesInterlaced = Bit(31); + static constexpr auto DMADirectionValue = BitRange::from_to(29, 30); + static constexpr auto DMAReady = Bit(28); + static constexpr auto VRAMtoCPUtransferReay = Bit(27); + static constexpr auto GP0ReadyForCMD = Bit(26); + static constexpr auto FifoNotFull = Bit(25); // Only for Fifo + static constexpr auto InterruptRequest = Bit(24); + static constexpr auto DisplayDisabled = Bit(23); + static constexpr auto VerticalInterlaceOn = Bit(22); + static constexpr auto DisplayAreaColorDepth = BitRange::from_to(21, 21); + static constexpr auto VideoModePal = Bit(20); + static constexpr auto VerticalResolutionValue = BitRange::from_to(19, 19); + static constexpr auto HorizontalResolutionValue = BitRange::from_to(17, 18); + static constexpr auto HorizontalResolution368 = Bit(16); + static constexpr auto TexturesDisabled = Bit(15); + static constexpr auto NotDrawingMaskedPixels = Bit(12); + static constexpr auto MaskBitSetDuringDrawEnabled = Bit(11); + static constexpr auto DrawingToDisplayAreadAllowed = Bit(10); + static constexpr auto DitherEnabled = Bit(9); + static constexpr auto TexturePageColorValue = BitRange::from_to(7, 8); + static constexpr auto SemiTransparencyValue = BitRange::from_to(5, 6); + static constexpr auto TexturePageY = BitRange::from_to(4, 4); // N*256 + static constexpr auto TexturePageX = BitRange::from_to(0, 3); // N*64 + + static constexpr auto VerticalResolution480 = Bit(19); + static constexpr auto TexturePageY256 = Bit(4); + }; + + __declare_io_struct(GP0, uint32_t) { + static constexpr auto ID = BitRange::from_to(24, 31); + static constexpr auto Value = BitRange::from_to(0, 23); + + static constexpr GP0 DrawAreaTemplate(uint8_t code, uint16_t x, uint16_t y) { + constexpr auto Command = BitRange::from_to(24, 31); + constexpr auto Y = BitRange::from_to(10, 18); + constexpr auto X = BitRange::from_to(0, 9); + + return internal::construct_cmd(code, Y.as_value(static_cast(y)) | X.as_value(static_cast(x))); + } + + static constexpr GP0 ClearCache() { + return internal::construct_cmd(0x01, 0x0); + } + + static constexpr GP0 QuickFill(GPU::Color24 color) { + return internal::construct_cmd(0x02, color.raw()); + } + + static constexpr GP0 VRAM2VRAMBlitting() { + return internal::construct_cmd(0x80, 0); + } + + static constexpr GP0 CPU2VRAMBlitting() { + return internal::construct_cmd(0xA0, 0); + } + + static constexpr GP0 TexPage(const GPU::PositionU16& page_pos, GPU::SemiTransparency transparency, GPU::TextureColorMode tex_color, bool dither, bool draw_on_display_area) { + constexpr auto TexXRange = BitRange::from_to(0, 3); + constexpr auto TexYRange = BitRange::from_to(4, 4); + constexpr auto TransparencyRange = BitRange::from_to(5, 6); + constexpr auto TextureColorRange = BitRange::from_to(7, 8); + constexpr auto DitherBit = BitRange::from_to(9, 9); + constexpr auto DrawOnDisplayAreaBit = BitRange::from_to(10, 10); + + return internal::construct_cmd(0xE1, + TexXRange.as_value(page_pos.x >> 6) | TexYRange.as_value(page_pos.y >> 8) | + TransparencyRange.as_value(static_cast(transparency)) | TextureColorRange.as_value(static_cast(tex_color)) | + DitherBit.as_value(static_cast(dither)) | DrawOnDisplayAreaBit.as_value(static_cast(draw_on_display_area)) + ); + } + + static constexpr GP0 DrawAreaTopLeft(const GPU::PositionU16& position) { + return GP0::DrawAreaTemplate(0xE3, position.x, position.y); + } + + static constexpr GP0 DrawAreaBottomRight(const GPU::PositionU16& position) { + return GP0::DrawAreaTemplate(0xE4, position.x, position.y); + } + + static constexpr GP0 DrawOffset(const GPU::PositionI16& offset) { + constexpr auto X = BitRange::from_to(0, 10); + constexpr auto Y = BitRange::from_to(11, 21); + + return internal::construct_cmd(0xE5, X.as_value(static_cast(offset.x)) | Y.as_value(static_cast(offset.y))); + } + + static constexpr GP0 PostionTopLeft(const GPU::PositionU16& position) { + return GP0{(static_cast(position.y) << 16u) | position.x}; + } + + static constexpr GP0 WidthHeight(const GPU::SizeU16& size) { + return GP0{(static_cast(size.height) << 16u) | size.width}; + } + }; + + __declare_io_struct(GP1, uint32_t) { + static constexpr auto ID = BitRange::from_to(24, 31); + static constexpr auto Value = BitRange::from_to(0, 23); + + static constexpr GP1 Reset() { + return GP1{0}; + } + + static constexpr GP1 ResetCMDBuffer() { + return internal::construct_cmd(0x01, 0); + } + + static constexpr GP1 DisplayState(DisplayMode::State state) { + return internal::construct_cmd(0x03, static_cast(state)); + } + + static constexpr GP1 DMADirection(GPUSTAT::DMADirection dir) { + return internal::construct_cmd(0x04, dir); + } + + static constexpr GP1 DisplayArea(const GPU::PositionU16& position) { + constexpr auto X = BitRange::from_to(0, 9); + constexpr auto Y = BitRange::from_to(10, 18); + + return internal::construct_cmd(0x05, X.as_value(static_cast(position.x)) | Y.as_value(static_cast(position.y))); + } + + static constexpr GP1 HorizontalDisplayRange(uint16_t x1, uint16_t x2) { + constexpr auto X1 = BitRange::from_to(0, 11); + constexpr auto X2 = BitRange::from_to(12, 23); + + return internal::construct_cmd(0x06, X1.as_value(static_cast(x1)) | X2.as_value(static_cast(x2))); + } + + static constexpr GP1 VerticalDisplayRange(uint16_t y1, uint16_t y2) { + constexpr auto Y1 = BitRange::from_to(0, 9); + constexpr auto Y2 = BitRange::from_to(10, 19); + + return internal::construct_cmd(0x07, Y1.as_value(static_cast(y1)) | Y2.as_value(static_cast(y2))); + } + + static constexpr GP1 DisplayMode(GPU_IO_Values::DisplayMode mode) { + return internal::construct_cmd(0x08, mode.raw); + } + }; + } +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/interrupt_io_values.hpp b/include/PSX/System/IOPorts/IOValues/interrupt_io_values.hpp new file mode 100644 index 00000000..549d1b9d --- /dev/null +++ b/include/PSX/System/IOPorts/IOValues/interrupt_io_values.hpp @@ -0,0 +1,12 @@ +#pragma once +#include "ioport.hpp" + +namespace JabyEngine { + namespace Interrupt_IO_Values { + __declare_io_struct(Mask, uint32_t) { + }; + + __declare_io_struct(Status, uint32_t) { + }; + } +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/ioport.hpp b/include/PSX/System/IOPorts/IOValues/ioport.hpp new file mode 100644 index 00000000..aa72cc49 --- /dev/null +++ b/include/PSX/System/IOPorts/IOValues/ioport.hpp @@ -0,0 +1,118 @@ +#pragma once +#include "../../../Auxiliary/types.hpp" +#include "../../../Auxiliary/bits.hpp" + +namespace JabyEngine { + namespace IOAdress { + constexpr uintptr_t patch_adr(uintptr_t adr) { + constexpr uintptr_t Mask = 0xF0000000; + constexpr uintptr_t Base = 0x10000000; // We might want to change this later to 0xB0000000 for caching and stuff (More research needed) + + return (Base + (adr & ~Mask)); + } + } + + namespace internal { + template + struct IOValue { + typedef S UnderlyingType; + + UnderlyingType raw; + + template + static constexpr T from(const ARGS&...args) { + return T{0}.set(args...); + } + + constexpr T& set(Bit bit) { + this->raw = bit::set(this->raw, bit); + return static_cast(*this); + } + + constexpr T& set(ClearBit bit) { + this->raw = bit::set(this->raw, bit); + return static_cast(*this); + } + + constexpr T& set_range(const BitRange& bits, UnderlyingType value) { + this->raw = bit::value::set_normalized(this->raw, bits, value); + return static_cast(*this); + } + + template + constexpr T& set(const BitRange::RangeValuePair& value) { + this->raw = bit::value::set_normalized(this->raw, value); + return static_cast(*this); + } + + template + constexpr T& set(const U& head, const ARGS&...tail) { + return this->set(head).set(tail...); + } + + constexpr IOValue::UnderlyingType get(BitRange bits) const { + return bit::value::get_normalized(this->raw, bits.pos, bits.length); + } + + constexpr T& clear(Bit bit) { + this->raw = bit::clear(this->raw, bit); + return static_cast(*this); + } + + constexpr bool is_set(Bit bit) const { + return bit::is_set(this->raw, bit); + } + }; + } + + template + struct IOPort { + using Value = T; + T value; + + T read() const { + return {const_cast*>(this)->value.raw}; + } + + void write(T value) { + const_cast*>(this)->value.raw = value.raw; + } + }; + + template<> + struct IOPort; + + template + struct IOPort32 { + union ValueHelper { + struct { + uint16_t low; + uint16_t high; + }; + T value; + }; + using Value = T; + T value; + + T read() const { + const auto* cast_this = reinterpret_cast*>(this); + const volatile auto* cv_this = const_cast(cast_this); + + return ValueHelper{.low = cv_this->value.low, .high = cv_this->value.high}.value; + } + + void write(T value) { + const auto new_value = ValueHelper{.value = value}; + auto* cast_this = reinterpret_cast*>(this); + volatile auto* v_this = const_cast(cast_this); + + v_this->value.low = new_value.low; + v_this->value.high = new_value.high; + } + }; + + #define __declare_io_struct(name, type) struct name : public ::JabyEngine::internal::IOValue + #define __declare_io_port(type, adr) *reinterpret_cast(adr) + #define __declare_io_value(type, adr) __declare_io_port(type, adr) + #define __declare_io_port_array(type, size, adr) reinterpret_cast(*reinterpret_cast(adr)) +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/memory_io_values.hpp b/include/PSX/System/IOPorts/IOValues/memory_io_values.hpp new file mode 100644 index 00000000..70050b3b --- /dev/null +++ b/include/PSX/System/IOPorts/IOValues/memory_io_values.hpp @@ -0,0 +1,18 @@ +#pragma once +#include "ioport.hpp" + +namespace JabyEngine { + namespace Memory_IO_Values { + __declare_io_struct(CD_DELAY, uint32_t) { + static constexpr CD_DELAY create() { + return CD_DELAY{0x20943}; + } + }; + + __declare_io_struct(COM_DELAY, uint32_t) { + static constexpr COM_DELAY create() { + return COM_DELAY{0x1325}; + } + }; + } +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/periphery_io_values.hpp b/include/PSX/System/IOPorts/IOValues/periphery_io_values.hpp new file mode 100644 index 00000000..dc49c7ca --- /dev/null +++ b/include/PSX/System/IOPorts/IOValues/periphery_io_values.hpp @@ -0,0 +1,52 @@ +#pragma once +#include "ioport.hpp" + +namespace JabyEngine { + namespace Periphery_IO_Values { + __declare_io_struct(JOY_BAUD, uint16_t) { + static constexpr JOY_BAUD create() { + return JOY_BAUD{0x0088}; + } + }; + + __declare_io_struct(JOY_CTRL, uint16_t) { + static constexpr auto TXEnable = Bit(0); + static constexpr auto SelectJoy = Bit(1); + static constexpr auto ACK = Bit(4); + static constexpr auto ACKIrqEnable = Bit(12); + static constexpr auto PortBSelected = Bit(13); + static constexpr auto PortASelected = !PortBSelected; + + static constexpr JOY_CTRL create_for(uint16_t port) { + return JOY_CTRL{static_cast(port << PortBSelected)}.set(TXEnable, SelectJoy, ACKIrqEnable); + } + + static constexpr JOY_CTRL close() { + return JOY_CTRL{0}; + } + }; + + __declare_io_struct(JOY_MODE, uint16_t) { + static constexpr JOY_MODE create() { + return JOY_MODE{0x000D}; + } + }; + + __declare_io_struct(JOY_RX_DATA, uint8_t) { + }; + + __declare_io_struct(JOY_STAT, uint32_t) { + static constexpr auto TXReadyStart = Bit(0); + static constexpr auto RXFifoNonEmpty = Bit(1); + static constexpr auto TXReadyFinished = Bit(2); + static constexpr auto RXParityError = Bit(3); + static constexpr auto ACKIrqLow = Bit(7); + }; + + __declare_io_struct(JOY_TX_DATA, uint32_t) { + static constexpr JOY_TX_DATA create(uint8_t byte) { + return JOY_TX_DATA{byte}; + } + }; + } +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/spu_io_values.hpp b/include/PSX/System/IOPorts/IOValues/spu_io_values.hpp new file mode 100644 index 00000000..220a66fc --- /dev/null +++ b/include/PSX/System/IOPorts/IOValues/spu_io_values.hpp @@ -0,0 +1,215 @@ +#pragma once +#include "ioport.hpp" +#include + +namespace JabyEngine { + namespace SPU_IO_Values { + namespace MemoryMap { + static constexpr uintptr_t ADPCM = 0x01000; + static constexpr uintptr_t End = 0x7FFFF; + } + + __declare_io_struct(AD, uint16_t) { + static constexpr auto AttackMode = Bit(15); + static constexpr auto AttackShift = BitRange::from_to(10, 14); + static constexpr auto AttackStep = BitRange::from_to(8, 9); + static constexpr auto DecayShift = BitRange::from_to(4, 7); + static constexpr auto SustainLevel = BitRange::from_to(0, 3); + + static constexpr AD none() { + return AD{0}; + } + }; + + __declare_io_struct(ControlRegister, uint16_t) { + enum RAMTransferMode { + Stop = 0, + ManualWrite = 1, + DMAWrite = 2, + DMARead = 3 + }; + + static constexpr auto Enable = Bit(15); + static constexpr auto Unmute = Bit(14); + static constexpr auto NoiseFrequcenyShift = BitRange::from_to(10, 13); + static constexpr auto NoiseFrequcenyStep = BitRange::from_to(8, 9); + static constexpr auto ReverbMasterEnable = Bit(7); + static constexpr auto IRQ9Enable = Bit(6); + static constexpr auto TransferMode = BitRange::from_to(4, 5); + static constexpr auto ExternalAudioReverb = Bit(3); + static constexpr auto CDAudioReverb = Bit(2); + static constexpr auto ExternalAudioEnable = Bit(1); + static constexpr auto CDAudioEnable = Bit(0); + }; + + __declare_io_struct(DataTransferControl, uint16_t) { + static constexpr DataTransferControl NormalTransferMode() { + return DataTransferControl{0x0004}; + } + }; + + __declare_io_struct(Echo, uint32_t) { + static constexpr auto EchoBits = BitRange::from_to(0, 23); + + static constexpr Echo AllOff() { + return Echo{0}; + } + }; + + __declare_io_struct(KeyOff, uint32_t) { + static constexpr KeyOff for_specific(uint32_t id) { + return KeyOff{1u << id}; + } + + static constexpr KeyOff all() { + return KeyOff{UI32_MAX}; + } + }; + + __declare_io_struct(KeyOn, uint32_t) { + static constexpr KeyOn for_specific(uint32_t id) { + return KeyOn{1u << id}; + } + + static constexpr KeyOn all() { + return KeyOn{UI32_MAX}; + } + }; + + __declare_io_struct(KeyStatus, uint32_t) { + }; + + __declare_io_struct(Noise, uint16_t) { + static constexpr auto NoiseBits = BitRange::from_to(0, 23); + + static constexpr Noise AllOff() { + return Noise{0}; + } + }; + + __declare_io_struct(PitchModulation, uint32_t) { + static constexpr auto EnableBits = BitRange::from_to(1, 23); + + static constexpr PitchModulation AllOff() { + return PitchModulation{0}; + } + }; + + __declare_io_struct(SampleRate, uint16_t) { + static constexpr SampleRate stop() { + return SampleRate{0}; + } + + static constexpr SampleRate from_HZ(uint32_t freq) { + constexpr uint32_t Base1024Hz = static_cast((4096.0/44100.0)*1024.0); + return SampleRate{static_cast((freq >> 10)*Base1024Hz)}; + } + + static constexpr SampleRate from_HZ(double freq) { + //4096 == 44100Hz + constexpr double Base = (4096.0 / 44100.0); + return SampleRate{static_cast((freq*Base))}; + } + }; + + __declare_io_struct(SimpleVolume, int16_t) { + static constexpr auto MaxVolume = I16_MAX; + + static constexpr SimpleVolume mute() { + return SimpleVolume{0}; + } + + constexpr operator int16_t() const { + return this->raw; + } + }; + + static constexpr SimpleVolume operator""_vol(long double fraction) { + return {static_cast(static_cast(SimpleVolume::MaxVolume)*fraction)}; + } + + __declare_io_struct(SR, uint16_t) { + static constexpr auto SustainMode = Bit(31 - 16); + static constexpr auto SustainDirection = Bit(30 - 16); + static constexpr auto SustainShift = BitRange::from_to((24 - 16), (28 - 16)); + static constexpr auto SustainStep = BitRange::from_to((22 - 16), (23 - 16)); + static constexpr auto ReleaseMode = Bit(21 - 16); + static constexpr auto ReleaseShift = BitRange::from_to((16 - 16), (20 - 16)); + + static constexpr SR none() { + return SR{0}; + } + }; + + __declare_io_struct(SRAMAdr, uint16_t) { + static constexpr SRAMAdr null() { + return SRAMAdr{0x0}; + } + + static constexpr SRAMAdr adpcm_start() { + return SRAMAdr{MemoryMap::ADPCM}; + } + }; + + __declare_io_struct(StatusRegister, uint16_t) { + enum CapureBufferHalf { + First = 0, + Second = 1 + }; + + static constexpr auto Unused = BitRange::from_to(12, 15); + static constexpr auto CaputreBufferHalf = Bit(11); + static constexpr auto TransferBusy = Bit(10); + static constexpr auto IsDMARead = Bit(9); + static constexpr auto isDMAWrite = Bit(8); + static constexpr auto isDMA = Bit(7); + static constexpr auto isIRQ = Bit(6); + // Copies of ControlRegister + static constexpr auto TransferMode = BitRange::from_to(4, 5); + static constexpr auto ExternalAudioReverb = Bit(3); + static constexpr auto CDAudioReverb = Bit(2); + static constexpr auto ExternalAudioEnable = Bit(1); + static constexpr auto CDAudioEnable = Bit(0); + }; + + __declare_io_struct(SweepVolume, int16_t) { + struct VolumeMode { + static constexpr auto MaxVolume = (I16_MAX >> 1); + static constexpr auto EnableSweep = Bit(15); + static constexpr auto Enable = !EnableSweep; + static constexpr auto Volume = BitRange::from_to(0, 14); + }; + + struct SweepMode { + enum Mode { + Linear = 0, + Exponential = 1, + }; + + enum Direction { + Increase = 0, + Decrease = 1, + }; + + enum Phase { + Posititve = 0, + Negative = 1, + }; + + static constexpr auto Mode = Bit(14); + static constexpr auto Direction = Bit(13); + static constexpr auto Phase = Bit(12); + static constexpr auto Shift = BitRange::from_to(2, 6); + static constexpr auto Step = BitRange::from_to(0, 1); + }; + + static constexpr SweepVolume create(SimpleVolume volume) { + return from(VolumeMode::Enable, VolumeMode::Volume.with(volume.raw >> 1)); + } + + static constexpr SweepVolume mute() { + return SweepVolume{0}; + } + }; + } +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/timer_io_values.hpp b/include/PSX/System/IOPorts/IOValues/timer_io_values.hpp new file mode 100644 index 00000000..66945fbc --- /dev/null +++ b/include/PSX/System/IOPorts/IOValues/timer_io_values.hpp @@ -0,0 +1,31 @@ +#pragma once +#include "ioport.hpp" + +namespace JabyEngine { + namespace Timer_IO_Values { + __declare_io_struct(CounterMode, uint32_t) { + static constexpr auto SyncEnable = Bit(0); + static constexpr auto FreeRun = !SyncEnable; + static constexpr auto SyncMode = BitRange::from_to(1, 2); + static constexpr auto ResetAfterTarget = Bit(3); + static constexpr auto IRQAtTarget = Bit(4); + static constexpr auto IRQAtMax = Bit(5); + static constexpr auto IRQEveryTime = Bit(6); + static constexpr auto IRQOneShot = !IRQEveryTime; + static constexpr auto IRQToggle = Bit(7); + static constexpr auto IRQPulse = !IRQToggle; + static constexpr auto ClockSource = BitRange::from_to(8, 9); + static constexpr auto HasIRQRequest = Bit(10); + static constexpr auto IsTargetReached = Bit(11); + static constexpr auto IsMaxReached = Bit(12); + }; + + __declare_io_struct(CounterTarget, uint32_t) { + static constexpr auto CounterTargetValue = BitRange::from_to(0, 15); + }; + + __declare_io_struct(CounterValue, uint32_t) { + static constexpr auto Value = BitRange::from_to(0, 15); + }; + } +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/cd_io.hpp b/include/PSX/System/IOPorts/cd_io.hpp index f981aaac..9d256525 100644 --- a/include/PSX/System/IOPorts/cd_io.hpp +++ b/include/PSX/System/IOPorts/cd_io.hpp @@ -1,9 +1,25 @@ -#ifndef __JABYENGINE_CD_IO_HPP__ -#define __JABYENGINE_CD_IO_HPP__ -#include "ioport.hpp" +#pragma once +#include "IOValues/cd_io_values.hpp" namespace JabyEngine { namespace CD_IO { + using AudioVolumeApply_IO = IOPort; + using CommandFifo_IO = IOPort; + using DataFifo_IO = IOPort; + using DataFifo16_IO = IOPort; + using IndexStatus_IO = IOPort; + using InterruptEnable_IO = IOPort; + using InterruptFlag_IO = IOPort; + using LeftCD2LeftSPU_IO = IOPort; + using LeftCD2RightSPU_IO = IOPort; + using ParameterFifo_IO = IOPort; + using Request_IO = IOPort; + using ResponseFifo_IO = IOPort; + using RightCD2LeftSPU_IO = IOPort; + using RightCD2RightSPU_IO = IOPort; + using SoundMapDataOut_IO = IOPort; + using SoundMapCoding_IO = IOPort; + struct DataSector { static constexpr size_t SizeBytes = 2048; static constexpr size_t SizeWords = (SizeBytes/sizeof(uint32_t)); @@ -14,6 +30,15 @@ namespace JabyEngine { static constexpr T words_to_sectors(T size) { return (size + static_cast(DataSector::SizeWords - 1))/static_cast(DataSector::SizeWords); } + + constexpr size_t hash() const { + uint32_t value = 0; + + for(const auto word : this->data) { + value += word; + } + return value; + } }; enum Index { @@ -23,84 +48,13 @@ namespace JabyEngine { Index3 = 3, }; - struct CDDAVolume { - typedef uint8_t Type; - - static constexpr uint8_t Off = 0x0; - static constexpr uint8_t Default = 0x80; - static constexpr uint8_t Max = 0xFF; - }; - - __declare_io_type(Mode, uint8_t, - static constexpr auto DoubleSpeed = Bit(7); - static constexpr auto SingleSpeed = !DoubleSpeed; - static constexpr auto XADPCM = Bit(6); - static constexpr auto WholeSector = Bit(5); - static constexpr auto DataSector = !WholeSector; - static constexpr auto UseXAFilter = Bit(3); - static constexpr auto AudioPlayIRQ = Bit(2); - static constexpr auto AutoPauseTrack = Bit(1); - static constexpr auto CDDA = Bit(0); - ); - - __declare_io_type(IndexStatus, uint8_t, - static constexpr auto PortIndex = BitRange::from_to(0, 1); - static constexpr auto HasXAFifoData = Bit(2); - static constexpr auto IsParameterFifoEmpty = Bit(3); - static constexpr auto HasParameterFifoSpace = Bit(4); - static constexpr auto HasResponseFifoData = Bit(5); - static constexpr auto HasDataFifoData = Bit(6); - static constexpr auto IsTransmissionBusy = Bit(7); - ); - - __declare_io_type(InterruptEnable, uint8_t, - static constexpr auto InterruptTypValue = BitRange::from_to(0, 2); - static constexpr auto InterruptExtended = BitRange::from_to(0, 4); - static constexpr auto UnknownIRQ = Bit(3); - static constexpr auto CommandStartIRQ = Bit(4); - ); - typedef InterruptEnable_v InterruptFlag_v; - - __declare_io_type(Request, uint8_t, - static constexpr auto WantCommandStartIRQ = Bit(5); - static constexpr auto WantData = Bit(7); - - void want_data() { - this->raw_value = static_cast(Self::WantData); - } - - void reset() { - this->raw_value = 0; - } - ); - - __declare_io_type(SoundMapCoding, uint8_t, - static constexpr auto Stereo = Bit(0); - static constexpr auto Mono = !Stereo; - static constexpr auto SampleRate_18900hz = Bit(2); - static constexpr auto SampleRate_37800hz = !SampleRate_18900hz; - static constexpr auto BitsPerSample8 = Bit(4); - static constexpr auto BitsPerSample4 = !BitsPerSample8; - static constexpr auto Emphasis = Bit(6); - ); - - __declare_io_type(AudioVolumeApply, uint8_t, - static constexpr auto Mute = Bit(0); - static constexpr auto ApplyChanges = Bit(5); - ); - - __declare_io_type(ResponseFifo, uint8_t,); - __declare_io_type(CommandFifo, uint8_t,); - __declare_io_type(DataFifo, uint8_t,); - __declare_io_type(DataFifo16, uint16_t,); - __declare_io_type(ParameterFifo, uint8_t,); - __declare_io_type(SoundMapDataOut, uint8_t,); - __declare_io_type(LeftCD2LeftSPU, CDDAVolume::Type,); - __declare_io_type(LeftCD2RightSPU, CDDAVolume::Type,); - __declare_io_type(RightCD2RightSPU,CDDAVolume::Type,); - __declare_io_type(RightCD2LeftSPU, CDDAVolume::Type,); - struct Interrupt { + static constexpr auto ExtendedFlags = CD_IO_Values::InterruptEnable::from( + CD_IO_Values::InterruptEnable::InterruptTypValue.range_max(), + CD_IO_Values::InterruptEnable::UnknownIRQ, + CD_IO_Values::InterruptEnable::CommandStartIRQ + ); + enum Type : uint8_t { None = 0, DataReady = 1, @@ -110,24 +64,28 @@ namespace JabyEngine { DiskError = 5 }; - static void enable(InterruptEnable_v& port) { - port.set(InterruptEnable_t::InterruptTypValue.range_max()); + static void enable(InterruptEnable_IO& port) { + port.write(port.read().set(CD_IO_Values::InterruptEnable::InterruptTypValue.range_max())); } - static void enable_extended(InterruptEnable_v& port) { - port = InterruptEnable_t::from(InterruptEnable_t::InterruptTypValue.range_max(), InterruptEnable_t::UnknownIRQ, InterruptEnable_t::CommandStartIRQ); + static void enable_extended(InterruptEnable_IO& port) { + port.write(Interrupt::ExtendedFlags); } - static Type get_type(const InterruptFlag_v& port) { - return static_cast(port.get(InterruptFlag_v::InterruptTypValue)); + static Type get_type(const InterruptFlag_IO& port) { + return static_cast(port.read().get(CD_IO_Values::InterruptFlag::InterruptTypValue)); } - static void ack(InterruptFlag_v& port) { - port.set(InterruptFlag_v::InterruptTypValue.range_max()); + static void ack(InterruptFlag_IO& port) { + port.write(port.read().set(CD_IO_Values::InterruptFlag::InterruptTypValue.range_max())); } - static void ack_extended(InterruptFlag_v& port) { - port = InterruptFlag_v::from(InterruptFlag_v::InterruptTypValue.range_max(), InterruptEnable_v::UnknownIRQ, InterruptEnable_v::CommandStartIRQ); + static void ack_extended(InterruptFlag_IO& port) { + port.write(Interrupt::ExtendedFlags); + } + + static void reset_parameter_fifo(InterruptFlag_IO& port) { + port.write(CD_IO_Values::InterruptFlag{0x40}); } }; @@ -139,87 +97,88 @@ namespace JabyEngine { static constexpr Desc GetStat{0x01, Interrupt::Type::Acknowledge}; static constexpr Desc SetLoc{0x02, Interrupt::Type::Acknowledge}; + static constexpr Desc Play{0x03, Interrupt::Type::Acknowledge}; static constexpr Desc ReadN{0x06, Interrupt::Type::DataReady}; static constexpr Desc Pause{0x09, Interrupt::Type::Complete}; static constexpr Desc Init{0x0A, Interrupt::Type::Complete}; + static constexpr Desc Demute{0x0C, Interrupt::Type::Acknowledge}; + static constexpr Desc Filter{0x0D, Interrupt::Type::Acknowledge}; static constexpr Desc SetMode{0x0E, Interrupt::Type::Acknowledge}; + static constexpr Desc GetLocL{0x10, Interrupt::Type::Acknowledge}; + static constexpr Desc GetLocP{0x11, Interrupt::Type::Acknowledge}; + static constexpr Desc GetTN{0x13, Interrupt::Type::Acknowledge}; + static constexpr Desc GetTD{0x14, Interrupt::Type::Acknowledge}; + static constexpr Desc SeekL{0x15, Interrupt::Type::Complete}; + static constexpr Desc ReadS{0x1B, Interrupt::Type::DataReady}; }; static constexpr auto IORegister1Adr = 0x1F801801; static constexpr auto IORegister2Adr = 0x1F801802; static constexpr auto IORegister3Adr = 0x1F801803; - __declare_new_io_port(IndexStatus, 0x1F801800); - - #define __declare_index_io_port(type, name, adr) __cast_io_adr_with_type(inline, type, name, adr) - #define __declare_index_io_port_const(type, name, adr) __cast_io_adr_with_type(const inline, type, name, adr) + static auto& IndexStatus = __declare_io_port(IndexStatus_IO, 0x1F801800); struct PortIndex0 { - __declare_new_const_io_port(ResponseFifo, IORegister1Adr); - __declare_new_io_port(CommandFifo, IORegister1Adr); + static inline const auto& ResponseFifo = __declare_io_port(ResponseFifo_IO, IORegister1Adr); + static inline auto& CommandFifo = __declare_io_port(CommandFifo_IO, IORegister1Adr); - __declare_new_const_io_port(DataFifo, IORegister2Adr); - __declare_new_const_io_port(DataFifo16, IORegister2Adr); - __declare_new_io_port(ParameterFifo, IORegister2Adr); + static inline const auto& DataFifo = __declare_io_port(DataFifo_IO, IORegister2Adr); + static inline const auto& DataFifo16 = __declare_io_port(DataFifo16_IO, IORegister2Adr); + static inline auto& ParameterFifo = __declare_io_port(ParameterFifo_IO, IORegister2Adr); - __declare_new_const_io_port(InterruptEnable, IORegister3Adr); - __declare_new_io_port(Request, IORegister3Adr); + static inline const auto& InterruptEnable = __declare_io_port(InterruptEnable_IO, IORegister3Adr); + static inline auto& Request = __declare_io_port(Request_IO, IORegister3Adr); static void change_to() { - IndexStatus = Index::Index0; + IndexStatus.write({Index::Index0}); } }; struct PortIndex1 { - __declare_new_const_io_port(ResponseFifo, IORegister1Adr); - __declare_new_io_port(SoundMapDataOut, IORegister1Adr); + static inline const auto& ResponseFifo = __declare_io_port(ResponseFifo_IO, IORegister1Adr); + static inline auto& SoundMapDataOut = __declare_io_port(SoundMapDataOut_IO, IORegister1Adr); - __declare_new_const_io_port(DataFifo, IORegister2Adr); - __declare_new_const_io_port(DataFifo16, IORegister2Adr); - __declare_new_io_port(InterruptEnable, IORegister2Adr); + static inline const auto& DataFifo = __declare_io_port(DataFifo_IO, IORegister2Adr); + static inline const auto& DataFifo16 = __declare_io_port(DataFifo16_IO, IORegister2Adr); + static inline auto& InterruptEnable = __declare_io_port(InterruptEnable_IO, IORegister2Adr); - __declare_new_io_port(InterruptFlag, IORegister3Adr); + static inline auto& InterruptFlag = __declare_io_port(InterruptFlag_IO, IORegister3Adr); static void change_to() { - IndexStatus = Index::Index1; - } + IndexStatus.write({Index::Index1}); + } }; struct PortIndex2 { - __declare_new_const_io_port(ResponseFifo, IORegister1Adr); - __declare_new_io_port(SoundMapCoding, IORegister1Adr); + static inline const auto& ResponseFifo = __declare_io_port(ResponseFifo_IO, IORegister1Adr); + static inline auto& SoundMapCoding = __declare_io_port(SoundMapCoding_IO, IORegister1Adr); - __declare_new_const_io_port(DataFifo, IORegister2Adr); - __declare_new_const_io_port(DataFifo16, IORegister2Adr); - __declare_new_io_port(LeftCD2LeftSPU, IORegister2Adr); + static inline const auto& DataFifo = __declare_io_port(DataFifo_IO, IORegister2Adr); + static inline const auto& DataFifo16 = __declare_io_port(DataFifo16_IO, IORegister2Adr); + static inline auto& LeftCD2LeftSPU = __declare_io_port(LeftCD2LeftSPU_IO, IORegister2Adr); - __declare_new_const_io_port(InterruptEnable, IORegister3Adr); - __declare_new_io_port(LeftCD2RightSPU, IORegister3Adr); + static inline const auto& InterruptEnable = __declare_io_port(InterruptEnable_IO, IORegister3Adr); + static inline auto& LeftCD2RightSPU = __declare_io_port(LeftCD2RightSPU_IO, IORegister3Adr); static void change_to() { - IndexStatus = Index::Index2; + IndexStatus.write({Index::Index2}); } }; struct PortIndex3 { - __declare_new_const_io_port(ResponseFifo, IORegister1Adr); - __declare_new_io_port(RightCD2RightSPU, IORegister1Adr); + static inline const auto& ResponseFifo = __declare_io_port(ResponseFifo_IO, IORegister1Adr); + static inline auto& RightCD2RightSPU = __declare_io_port(RightCD2RightSPU_IO, IORegister1Adr); - __declare_new_const_io_port(DataFifo, IORegister2Adr); - __declare_new_const_io_port(DataFifo16, IORegister2Adr); - __declare_new_io_port(RightCD2LeftSPU, IORegister1Adr); + static inline const auto& DataFifo = __declare_io_port(DataFifo_IO, IORegister2Adr); + static inline const auto& DataFifo16 = __declare_io_port(DataFifo16_IO, IORegister2Adr); + static inline auto& RightCD2LeftSPU = __declare_io_port(RightCD2LeftSPU_IO, IORegister1Adr); - __declare_new_const_io_port(InterruptFlag, IORegister3Adr); - __declare_new_io_port(AudioVolumeApply, IORegister3Adr); + static inline const auto& InterruptFlag = __declare_io_port(InterruptFlag_IO, IORegister3Adr); + static inline auto& AudioVolumeApply = __declare_io_port(AudioVolumeApply_IO, IORegister3Adr); static void change_to() { - IndexStatus = Index::Index3; + IndexStatus.write({Index::Index3}); } }; - - #undef __declare_index_io_port - #undef __declare_index_io_port_const } -} - -#endif //!__JABYENGINE_CD_IO_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/dma_io.hpp b/include/PSX/System/IOPorts/dma_io.hpp index 7f7a1e69..00b4368b 100644 --- a/include/PSX/System/IOPorts/dma_io.hpp +++ b/include/PSX/System/IOPorts/dma_io.hpp @@ -1,155 +1,39 @@ -#ifndef __JABYENGINE_DMA_IO_HPP__ -#define __JABYENGINE_DMA_IO_HPP__ -#include "ioport.hpp" +#pragma once +#include "IOValues/dma_io_values.hpp" namespace JabyEngine { namespace DMA_IO { - __declare_io_type(MADR, uint32_t, - static constexpr auto MemoryAdr = BitRange::from_to(0, 23); - ); + using BCR_IO = IOPort; + using CHCHR_IO = IOPort; + using DICR_IO = IOPort; + using DPCR_IO = IOPort; + using MADR_IO = IOPort; - __declare_io_type(BCR, uint32_t, - struct SyncMode0 { - static constexpr auto NumberOfWords = BitRange::from_to(0, 15); - static constexpr auto CD_OneBlock = Bit(16); + #pragma pack(push, 1) + struct Registers { + MADR_IO adr; + BCR_IO block_ctrl; + CHCHR_IO channel_ctrl; - static constexpr Self for_cd() { - // v Should be replaced with a named constant - return Self::from(SyncMode0::CD_OneBlock, SyncMode0::NumberOfWords.with(512)); - } - }; - - struct SyncMode1 { - static constexpr auto BlockSize = BitRange::from_to(0, 15); - static constexpr auto BlockAmount = BitRange::from_to(16, 31); - }; - - struct SyncMode2 { - }; - ); - - __declare_io_type(CHCHR, uint32_t, - enum SyncMode_t { - Sync0 = 0, //Start immediately, - Sync1 = 1, //Sync blocks to DMA requests - Sync2 = 2, //Linked List - }; - - static constexpr auto ManualStart = Bit(28); - - static constexpr auto Start = Bit(24); - static constexpr auto Busy = Start; - - static constexpr auto ChoppingCPUWindowSize = BitRange::from_to(20, 22); - static constexpr auto ChoppingDMAWindowSize = BitRange::from_to(16, 18); - - static constexpr auto SyncMode = BitRange::from_to(9, 10); - static constexpr auto UseSyncMode0 = SyncMode.with(Sync0); - static constexpr auto UseSyncMode1 = SyncMode.with(Sync1); - static constexpr auto UseSyncMode2 = SyncMode.with(Sync2); - - static constexpr auto UseChopping = Bit(8); - - static constexpr auto MemoryAdrDecreaseBy4 = Bit(1); - static constexpr auto MemoryAdrIncreaseBy4 = !MemoryAdrDecreaseBy4; - - static constexpr auto FromMainRAM = Bit(0); - static constexpr auto ToMainRAM = !FromMainRAM; - - static constexpr Self StartMDECin() { - return Self{0x01000201}; + inline void set_adr(uintptr_t adr) { + this->adr.write({bit::value::set_normalized(0u, DMA_IO_Values::MADR::MemoryAdr.with(adr))}); } - static constexpr Self StartMDECout() { - return Self{0x01000200}; - } - - static constexpr Self StartGPUReceive() { - return Self{0x01000201}; - } - - static constexpr Self StartCDROM() { - return Self{0x11000000}; - } - - static constexpr Self StartSPUReceive() { - return Self{0x01000201}; - } - - static constexpr Self StartOTC() { - return Self{0x11000002}; - } - ); - - struct __no_align Registers { - MADR_v adr; - BCR_v block_ctrl; - CHCHR_v channel_ctrl; - - void set_adr(uintptr_t adr) { - this->adr.set(MADR_t::MemoryAdr.with(adr)); - } - - void wait() { - while(this->channel_ctrl.is_set(CHCHR_t::Busy)); + inline void wait() { + while(this->channel_ctrl.read().is_set(DMA_IO_Values::CHCHR::Busy)); } }; + #pragma pack(pop) - // Those types do not need to be volatile because there members are - typedef Registers MDECin_v; - typedef Registers MDECout_v; - typedef Registers GPU_v; - typedef Registers CDROM_v; - typedef Registers SPU_v; - typedef Registers PIO_v; - typedef Registers OTC_v; + static auto& MDECin = __declare_io_value(Registers, 0x1F801080); + static auto& MDECout = __declare_io_value(Registers, 0x1F801090); + static auto& GPU = __declare_io_value(Registers, 0x1F8010A0); + static auto& CDROM = __declare_io_value(Registers, 0x1F8010B0); + static auto& SPU = __declare_io_value(Registers, 0x1F8010C0); + static auto& PIO = __declare_io_value(Registers, 0x1F8010D0); + static auto& OTC = __declare_io_value(Registers, 0x1F8010E0); - //0: Highest, 7: Lowest - typedef uint32_t Priority; - static constexpr Priority HighestPriority = 0; - static constexpr Priority LowestPriority = 7; - - __declare_io_type(DPCR, uint32_t, - static constexpr auto OTCEnable = Bit(27); - static constexpr auto OTCPriority = BitRange::from_to(24, 26); - - static constexpr auto PIOEnable = Bit(23); - static constexpr auto PIOPriority = BitRange::from_to(20, 22); - - static constexpr auto SPUEnable = Bit(19); - static constexpr auto SPUPriority = BitRange::from_to(16, 18); - - static constexpr auto CDROMEnable = Bit(15); - static constexpr auto CDROMPriority = BitRange::from_to(12, 14); - - static constexpr auto GPUEnable = Bit(11); - static constexpr auto GPUPriority = BitRange::from_to(8, 10); - - static constexpr auto MDECoutEnable = Bit(7); - static constexpr auto MDECoutPriority = BitRange::from_to(4, 6); - - static constexpr auto MDECinEnable = Bit(3); - static constexpr auto MDECinPriority = BitRange::from_to(0, 2); - ); - - __declare_io_type(DICR, uint32_t, - static constexpr auto MasterEnable = Bit(31); - static constexpr auto Flags = BitRange::from_to(24, 30); - static constexpr auto MasterEnableDPCR = Bit(23); - static constexpr auto EnableDPCR = BitRange::from_to(16, 22); - static constexpr auto ForceIRQ = Bit(15); - ); - - __declare_new_io_port(MDECin, 0x1F801080); - __declare_new_io_port(MDECout, 0x1F801090); - __declare_new_io_port(GPU, 0x1F8010A0); - __declare_new_io_port(CDROM, 0x1F8010B0); - __declare_new_io_port(SPU, 0x1F8010C0); - __declare_new_io_port(PIO, 0x1F8010D0); - __declare_new_io_port(OTC, 0x1F8010E0); - - __declare_new_io_port(DPCR, 0x1F8010F0); - __declare_new_io_port(DICR, 0x1F8010F4); + static auto& DPCR = __declare_io_port(DPCR_IO, 0x1F8010F0); + static auto& DICR = __declare_io_port(DICR_IO, 0x1F8010F4); } -} -#endif //!__JABYENGINE_DMA_IO_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/gpu_io.hpp b/include/PSX/System/IOPorts/gpu_io.hpp index 43d93dfb..9c82a045 100644 --- a/include/PSX/System/IOPorts/gpu_io.hpp +++ b/include/PSX/System/IOPorts/gpu_io.hpp @@ -1,208 +1,91 @@ -#ifndef __JABYENGINE_GPU_IO_HPP__ -#define __JABYENGINE_GPU_IO_HPP__ -#include "ioport.hpp" -#include "../../GPU/gpu_types.hpp" +#pragma once +#include "IOValues/gpu_io_values.hpp" namespace JabyEngine { namespace GPU_IO { - enum struct SemiTransparency { - B_Half_add_F_Half = 0, - B_add_F = 1, - B_sub_F = 2, - B_add_F_Quarter = 3, - }; - - enum struct DisplayAreaColorDepth { - $15bit = 0, - $24bit = 1, - }; - - enum struct TexturePageColor { - $4bit = 0, - $8bit = 1, - $15bit = 2, - }; - - enum struct HorizontalResolution { - $256 = 0, - $320 = 1, - $512 = 2, - $640 = 3, - }; - - enum struct VerticalResolution { - $240 = 0, - $480 = 1 - }; - - enum struct DMADirection { - Off = 0, - Fifo = 1, - CPU2GPU = 2, - GPU2CPU = 3, - }; - - enum struct DisplayState { - On = 0, - Off = 1 - }; - - __declare_io_type(DisplayMode, uint32_t, - enum struct TVEncoding { - NTSC = 0, - PAL = 1, - }; - - static constexpr auto HorizontalResolution368 = Bit(6); - static constexpr auto VerticalInterlace = Bit(5); - static constexpr auto DisplayAreaColorDepth = BitRange::from_to(4, 4); - static constexpr auto VideoMode = BitRange::from_to(3, 3); - static constexpr auto VerticalResolution = BitRange::from_to(2, 2); - static constexpr auto HorizontalResolution = BitRange::from_to(0, 1); - - static constexpr Self PAL() { - return Self::from( - HorizontalResolution.with(GPU_IO::HorizontalResolution::$320), - VerticalResolution.with(GPU_IO::VerticalResolution::$240), - VideoMode.with(TVEncoding::PAL), - DisplayAreaColorDepth.with(GPU_IO::DisplayAreaColorDepth::$15bit) - ); + struct GP0_IO : public IOPort { + void clear_cache() { + this->write(GPU_IO_Values::GP0::ClearCache()); } - static constexpr Self NTSC() { - return Self::from( - HorizontalResolution.with(GPU_IO::HorizontalResolution::$320), - VerticalResolution.with(GPU_IO::VerticalResolution::$240), - VideoMode.with(TVEncoding::NTSC), - DisplayAreaColorDepth.with(GPU_IO::DisplayAreaColorDepth::$15bit) - ); - } - ); - - __declare_io_type(GP0, uint32_t, - ); - - __declare_io_type(GP1, uint32_t, - ); - - - struct Command { - struct Helper { - static constexpr GP0_t DrawAreaTemplate(uint8_t code, uint16_t x, uint16_t y) { - constexpr auto Command = BitRange::from_to(24, 31); - constexpr auto Y = BitRange::from_to(10, 18); - constexpr auto X = BitRange::from_to(0, 9); - - return GP0_t::from(Command.with(code), Y.with(y), X.with(x)); - } - - static constexpr uint32_t construct_cmd(uint8_t cmd, uint32_t value) { - return ((cmd << 24) | value); - } - }; - - static constexpr GP0_t QuickFill(GPU::Color24 color) { - return {(0x02 << 24) | color.raw()}; + void quick_fill(GPU::Color24 color) { + this->write(GPU_IO_Values::GP0::QuickFill(color)); } - static constexpr GP0_t CPU2VRAM_Blitting() { - return {(0b101u << 29)}; + void set_vram2vram_blitting() { + this->write(GPU_IO_Values::GP0::VRAM2VRAMBlitting()); } - static constexpr GP0_t DrawAreaTopLeft(uint16_t x, uint16_t y) { - return Helper::DrawAreaTemplate(0xE3, x, y); + void set_cpu2vram_blitting() { + this->write(GPU_IO_Values::GP0::CPU2VRAMBlitting()); } - static constexpr GP0_t DrawAreaBottomRight(uint16_t x, uint16_t y) { - return Helper::DrawAreaTemplate(0xE4, x, y); + void set_tex_page(const GPU::PositionU16& page_pos, GPU::SemiTransparency transparency, GPU::TextureColorMode tex_color, bool dither, bool draw_on_display_area) { + this->write(GPU_IO_Values::GP0::TexPage(page_pos, transparency, tex_color, dither, draw_on_display_area)); } - static constexpr GP0_t TopLeftPosition(uint16_t x, uint16_t y) { - return {static_cast((y << 16u) | x)}; + void set_draw_area_top_left(const GPU::PositionU16& position) { + this->write(GPU_IO_Values::GP0::DrawAreaTopLeft(position)); } - static constexpr GP0_t WidthHeight(uint16_t w, uint16_t h) { - return {static_cast((h << 16u) | w)}; + void set_draw_area_bottom_right(const GPU::PositionU16& position) { + this->write(GPU_IO_Values::GP0::DrawAreaBottomRight(position)); } - static constexpr GP1_t Reset() { - return {0}; + void set_draw_offset(const GPU::PositionI16& offset) { + this->write(GPU_IO_Values::GP0::DrawOffset(offset)); } - static constexpr GP1_t ResetCMDBufer() { - return {Helper::construct_cmd(0x01, 0)}; + void pass_top_left_position(const GPU::PositionU16& position) { + this->write(GPU_IO_Values::GP0::PostionTopLeft(position)); } - static constexpr GP1_t SetDisplayState(DisplayState state) { - return {Helper::construct_cmd(0x03, static_cast(state))}; - } - - static constexpr GP1_t DMADirection(DMADirection dir) { - return {Helper::construct_cmd(0x04, static_cast(dir))}; - } - - static constexpr GP1_t DisplayArea(uint16_t x, uint16_t y) { - constexpr auto X = BitRange::from_to(0, 9); - constexpr auto Y = BitRange::from_to(10, 18); - - return {Helper::construct_cmd(0x05, X.as_value(x) | Y.as_value(y))}; - } - - static constexpr GP1_t HorizontalDisplayRange(uint32_t x1, uint32_t x2) { - constexpr auto X1 = BitRange::from_to(0, 11); - constexpr auto X2 = BitRange::from_to(12, 23); - - return {Helper::construct_cmd(0x06, X1.as_value(x1) | X2.as_value(x2))}; - } - - static constexpr GP1_t VerticalDisplayRange(uint32_t y1, uint32_t y2) { - constexpr auto Y1 = BitRange::from_to(0, 9); - constexpr auto Y2 = BitRange::from_to(10, 19); - - return {Helper::construct_cmd(0x07, Y1.as_value(y1) | Y2.as_value(y2))}; - } - - static constexpr GP1_t DisplayMode(DisplayMode_t mode) { - return {Helper::construct_cmd(0x08, mode)}; + void pass_width_height(const GPU::SizeU16& size) { + this->write(GPU_IO_Values::GP0::WidthHeight(size)); } }; + + struct GP1_IO : public IOPort { + void reset() { + this->write(GPU_IO_Values::GP1::Reset()); + } - __declare_io_type(GPUSTAT, uint32_t, - static constexpr auto DrawingOddLinesInterlaced = Bit(31); - static constexpr auto DMADirectionValue = BitRange::from_to(29, 30); - static constexpr auto DMAReady = Bit(28); - static constexpr auto VRAMtoCPUtransferReay = Bit(27); - static constexpr auto GP0ReadyForCMD = Bit(26); - static constexpr auto FifoNotFull = Bit(25); // Only for Fifo - static constexpr auto InterruptRequest = Bit(24); - static constexpr auto DisplayDisabled = Bit(23); - static constexpr auto VerticalInterlaceOn = Bit(22); - static constexpr auto DisplayAreaColorDepth = BitRange::from_to(21, 21); - static constexpr auto VideoModePal = Bit(20); - static constexpr auto VerticalResolutionValue = BitRange::from_to(19, 19); - static constexpr auto HorizontalResolutionValue = BitRange::from_to(17, 18); - static constexpr auto HorizontalResolution368 = Bit(16); - static constexpr auto TexturesDisabled = Bit(15); - static constexpr auto NotDrawingMaskedPixels = Bit(12); - static constexpr auto MaskBitSetDuringDrawEnabled = Bit(11); - static constexpr auto DrawingToDisplayAreadAllowed = Bit(10); - static constexpr auto DitherEnabled = Bit(9); - static constexpr auto TexturePageColorValue = BitRange::from_to(7, 8); - static constexpr auto SemiTransparencyValue = BitRange::from_to(5, 6); - static constexpr auto TexturePageY = BitRange::from_to(4, 4); // N*256 - static constexpr auto TexturePageX = BitRange::from_to(0, 3); // N*64 + void reset_cmd_buffer() { + this->write(GPU_IO_Values::GP1::ResetCMDBuffer()); + } - static constexpr auto VerticalResolution480 = Bit(19); - static constexpr auto TexturePageY256 = Bit(4); - ); + void set_display_state(GPU_IO_Values::DisplayMode::State state) { + this->write(GPU_IO_Values::GP1::DisplayState(state)); + } - typedef volatile uint32_t GPUREAD_v; + void set_dma_direction(GPU_IO_Values::GPUSTAT::DMADirection dir) { + this->write(GPU_IO_Values::GP1::DMADirection(dir)); + } - __declare_new_io_port(GP0, 0x1F801810); - __declare_new_io_port(GP1, 0x1F801814); + void set_display_area(const GPU::PositionU16& position) { + this->write(GPU_IO_Values::GP1::DisplayArea(position)); + } - __declare_new_const_io_port(GPUREAD, 0x1F801810); - __declare_new_const_io_port(GPUSTAT, 0x1F801814); + void set_horizontal_display_range(uint16_t x1, uint16_t x2) { + this->write(GPU_IO_Values::GP1::HorizontalDisplayRange(x1, x2)); + } + + void set_vertical_display_range(uint16_t y1, uint16_t y2) { + this->write(GPU_IO_Values::GP1::VerticalDisplayRange(y1, y2)); + } + + void set_display_mode(GPU_IO_Values::DisplayMode mode) { + this->write(GPU_IO_Values::GP1::DisplayMode(mode)); + } + }; + using GPUREAD_IO = IOPort; + using GPUSTAT_IO = IOPort; + + static constexpr size_t FIFOWordSize = 16; + + static auto& GP0 = __declare_io_port(GP0_IO, 0x1F801810); + static const auto& GPUREAD = __declare_io_port(GPUREAD_IO, 0x1F801810); + static auto& GP1 = __declare_io_port(GP1_IO, 0x1F801814); + static const auto& GPUSTAT = __declare_io_port(GPUSTAT_IO, 0x1F801814); } -} -#endif //!__JABYENGINE_GPU_IO_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/interrupt_io.hpp b/include/PSX/System/IOPorts/interrupt_io.hpp index cb2aeb3f..00687402 100644 --- a/include/PSX/System/IOPorts/interrupt_io.hpp +++ b/include/PSX/System/IOPorts/interrupt_io.hpp @@ -1,8 +1,10 @@ -#ifndef __JABYENGINE_INTERRUPT_IO_HPP__ -#define __JABYENGINE_INTERRUPT_IO_HPP__ -#include "ioport.hpp" +#pragma once +#include "IOValues/interrupt_io_values.hpp" namespace JabyEngine { + using Status_IO = IOPort; + using Mask_IO = IOPort; + struct Interrupt { static constexpr auto VBlank = Bit(0); static constexpr auto GPU = Bit(1); @@ -17,31 +19,23 @@ namespace JabyEngine { static constexpr auto Controller = Bit(10); static constexpr auto LightPen = Controller; - __declare_io_type(Status, uint32_t, - ); - - __declare_io_type(Mask, uint32_t, - ); - - __declare_new_io_port(Status, 0x1F801070); - __declare_new_io_port(Mask, 0x1F801074); + static inline auto& Status = __declare_io_port(Status_IO, 0x1F801070); + static inline auto& Mask = __declare_io_port(Mask_IO, 0x1F801074); static bool is_irq(Bit irq) { - return Status.is_set(irq); + return Status.read().is_set(irq); } static void ack_irq(Bit irq) { - Status.clear(irq); + Status.write({bit::clear(0b11111111111, irq)}); } static void disable_irq(Bit irq) { - Mask.clear(irq); + Mask.write(Mask.read().clear(irq)); } static void enable_irq(Bit irq) { - Mask.set(irq); + Mask.write(Mask.read().set(irq)); } }; -} - -#endif //!__JABYENGINE_INTERRUPT_IO_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/ioport.hpp b/include/PSX/System/IOPorts/ioport.hpp deleted file mode 100644 index 7120225f..00000000 --- a/include/PSX/System/IOPorts/ioport.hpp +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef __JABYENGINE_IOPORT_HPP__ -#define __JABYENGINE_IOPORT_HPP__ -#include "../../Auxiliary/types.hpp" -#include "../../Auxiliary/bits.hpp" - -namespace JabyEngine { - namespace IOPort { - struct IOValueType { - template - struct Normal { - typedef T Value; - typedef T UnderlyingValue; - }; - - template - struct Volatile { - typedef volatile T Value; - typedef T UnderlyingValue; - }; - }; - } - - namespace IOAdress { - constexpr uintptr_t patch_adr(uintptr_t adr) { - constexpr uintptr_t Mask = 0xF0000000; - constexpr uintptr_t Base = 0x10000000; // We might want to change this later to 0xB0000000 for caching and stuff (More research needed) - - return (Base + (adr & ~Mask)); - } - } - - #define __declare_new_named_io_port(type, name, adr) \ - static inline auto& name = *reinterpret_cast(IOAdress::patch_adr(adr)) - - #define __declare_new_io_port(name, adr) \ - __declare_new_named_io_port(name, name, adr) - - #define __declare_new_const_io_port(name, adr) \ - __declare_new_named_io_port(const name, name, adr) - - #define __declare_new_io_port_array(name, adr, size) \ - static inline auto& name = reinterpret_cast(*reinterpret_cast(adr)) - - // We need this construct to ensure the types end up being a POD - Inheritance doesn't qualify for a POD - #define __declare_io_type(name, type, ...) \ - template typename T> \ - struct name##_io_base { \ - typedef T::UnderlyingValue UnderlyingValue; \ - typedef name##_io_base Self; \ - \ - T::Value raw_value = 0; \ - \ - __VA_ARGS__ \ - \ - template \ - static constexpr Self from(const ARGS&...args) { \ - return Self().set_va(args...); \ - } \ - \ - constexpr Self& set(Bit bit) { \ - this->raw_value = bit::set(this->raw_value, bit); \ - return *this; \ - } \ - \ - constexpr Self& set(ClearBit bit) { \ - this->raw_value = bit::set(this->raw_value, bit); \ - return *this; \ - } \ - \ - constexpr Self& set(BitRange bits, UnderlyingValue value) { \ - this->raw_value = bit::value::set_normalized(this->raw_value, bits, value); \ - return *this; \ - } \ - \ - template \ - constexpr Self& set(const BitRange::RangeValuePair& value) { \ - this->raw_value = bit::value::set_normalized(this->raw_value, value); \ - return *this; \ - } \ - \ - template \ - constexpr Self& set_va(const S& head) { \ - return this->set(head); \ - } \ - \ - template \ - constexpr Self& set_va(const S& head, const ARGS&...tail) { \ - return this->set(head).set_va(tail...); \ - } \ - \ - constexpr UnderlyingValue get(BitRange bits) const { \ - return bit::value::get_normalized(this->raw_value, bits.pos, bits.length); \ - } \ - \ - constexpr Self& clear(Bit bit) { \ - this->raw_value = bit::clear(this->raw_value, bit); \ - return *this; \ - } \ - \ - constexpr bool is_set(Bit bit) const { \ - return bit::is_set(this->raw_value, bit); \ - } \ - \ - constexpr void operator=(UnderlyingValue value) { \ - this->raw_value = value; \ - } \ - \ - constexpr operator UnderlyingValue() const { \ - return this->raw_value; \ - } \ - }; \ - \ - typedef name##_io_base name##_v; \ - typedef name##_io_base name##_t - - struct __no_align ubus32_t { - __declare_io_type(uint16_t, uint16_t,); - uint16_t_v low; - uint16_t_v high; - - constexpr ubus32_t(uint32_t value) : low{0}, high{0} { - *this = value; - } - - constexpr void write(uint32_t value) { - *this = value; - } - - constexpr operator uint32_t() const { - const uint32_t high = this->high; - const uint32_t low = this->low; - - return ((high << 16) | low); - } - - constexpr ubus32_t& operator=(uint32_t value) { - this->low = (value & 0xFFFF); - this->high = (value >> 16); - - return *this; - } - }; -} -#endif //!__JABYENGINE_IOPORT_HPP__ \ No newline at end of file diff --git a/include/PSX/System/IOPorts/memory_io.hpp b/include/PSX/System/IOPorts/memory_io.hpp index dd884d23..1e9c7acd 100644 --- a/include/PSX/System/IOPorts/memory_io.hpp +++ b/include/PSX/System/IOPorts/memory_io.hpp @@ -1,24 +1,12 @@ -#ifndef __JABYENGINE_MEMORY_IO_HPP__ -#define __JABYENGINE_MEMORY_IO_HPP__ -#include "ioport.hpp" +#pragma once +#include "IOValues/memory_io_values.hpp" namespace JabyEngine { namespace Memory_IO { - __declare_io_type(COM_DELAY, uint32_t, - void setup() { - this->raw_value = 0x1325; - } - ); + using CD_DELAY_IO = IOPort; + using COM_DELAY_IO = IOPort; - __declare_io_type(CD_DELAY, uint32_t, - void setup() { - this->raw_value = 0x20943; - } - ); - - __declare_new_io_port(COM_DELAY, 0x1F801020); - __declare_new_io_port(CD_DELAY, 0x1F801018); + static auto& CD_DELAY = __declare_io_port(CD_DELAY_IO, 0x1F801018); + static auto& COM_DELAY = __declare_io_port(COM_DELAY_IO, 0x1F801020); } -} - -#endif //!__JABYENGINE_MEMORY_IO_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/periphery_io.hpp b/include/PSX/System/IOPorts/periphery_io.hpp new file mode 100644 index 00000000..c986c578 --- /dev/null +++ b/include/PSX/System/IOPorts/periphery_io.hpp @@ -0,0 +1,29 @@ +#pragma once +#include "IOValues/periphery_io_values.hpp" + +namespace JabyEngine { + namespace Periphery_IO { + struct JOY_STAT_IO : public IOPort { + inline bool has_response() const { + return this->read().is_set(Periphery_IO_Values::JOY_STAT::RXFifoNonEmpty); + } + + inline bool is_ready_transfer() const { + return this->read().is_set(Periphery_IO_Values::JOY_STAT::TXReadyFinished); + } + }; + + using JOY_BAUD_IO = IOPort; + using JOY_CTRL_IO = IOPort; + using JOY_MODE_IO = IOPort; + using JOY_RX_DATA_IO = IOPort; + using JOY_TX_DATA_IO = IOPort; + + static auto& JOY_TX_DATA = __declare_io_port(JOY_TX_DATA_IO, 0x1F801040); + static const auto& JOY_RX_DATA = __declare_io_port(JOY_RX_DATA_IO, 0x1F801040); + static const auto& JOY_STAT = __declare_io_port(JOY_STAT_IO, 0x1F801044); + static auto& JOY_MODE = __declare_io_port(JOY_MODE_IO, 0x1F801048); + static auto& JOY_CTRL = __declare_io_port(JOY_CTRL_IO, 0x1F80104A); + static auto& JOY_BAUD = __declare_io_port(JOY_BAUD_IO, 0x1F80104E); + } +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/spu_io.hpp b/include/PSX/System/IOPorts/spu_io.hpp index a5edfea0..da44b69e 100644 --- a/include/PSX/System/IOPorts/spu_io.hpp +++ b/include/PSX/System/IOPorts/spu_io.hpp @@ -1,160 +1,89 @@ -#ifndef __JABYENGINE_SPU_IO_HPP__ -#define __JABYENGINE_SPU_IO_HPP__ -#include "ioport.hpp" +#pragma once +#include "IOValues/spu_io_values.hpp" +#include namespace JabyEngine { namespace SPU_IO { - enum struct Mode { - Linear = 0, - Exponential = 1, - }; + static constexpr size_t VoiceCount = 24; + static constexpr size_t ReverbCount = 1; - enum struct Direction { - Increase = 0, - Decrease = 1, - }; + struct ControlRegister_IO : public IOPort { + using TransferMode = Value::RAMTransferMode; - enum struct Phase { - Posititve = 0, - Negative = 1, - }; - - //0..0x1F = Fast..Slow - typedef uint8_t Shift; - - //0..3 = +7, +6, +5, +4 or -6, -7, -6, -5 - typedef uint8_t Step; - - typedef int16_t SimpleVolume; - typedef volatile int16_t SimpleVolume_v; - - typedef volatile uint16_t Adr_v; - typedef volatile uint16_t DataTransferControl_v; - - __declare_io_type(SampleRate, uint16_t, - static constexpr Self from_HZ(double freq) { - //4096 == 44100Hz - constexpr double Base = (4096.0 / 44100.0); - - return {static_cast((freq*Base))}; + void set_transfer_mode(TransferMode mode) { + this->write(this->read().set(Value::ControlRegister::TransferMode.with(mode))); + while(this->read().get(Value::ControlRegister::TransferMode) != mode); } - ); - - __declare_io_type(SweepVolume, int16_t, - // For Volume Mode - static constexpr auto SweepEnable = Bit(15); - static constexpr auto VolumeEnable = !SweepEnable; - static constexpr auto Volume = BitRange::from_to(0, 14); - - // For Sweep Mode - static constexpr auto SweepMode = Bit(14); - static constexpr auto SweepDirection = Bit(13); - static constexpr auto SweepPhase = Bit(12); - static constexpr auto SweepShift = BitRange::from_to(2, 6); - static constexpr auto SweepStep = BitRange::from_to(0, 1); - ); - - __declare_io_type(SR, uint16_t, - static constexpr auto SustainMode = Bit(31 - 16); - static constexpr auto SustainDirection = Bit(30 - 16); - static constexpr auto SustainShift = BitRange::from_to((24 - 16), (28 - 16)); - static constexpr auto SustainStep = BitRange::from_to((22 - 16), (23 - 16)); - static constexpr auto ReleaseMode = Bit(21 - 16); - static constexpr auto ReleaseShift = BitRange::from_to((16 - 16), (20 - 16)); - ); - - __declare_io_type(AD, uint16_t, - static constexpr auto AttackMode = Bit(15); - static constexpr auto AttackShift = BitRange::from_to(10, 14); - static constexpr auto AttackStep = BitRange::from_to(8, 9); - static constexpr auto DecayShift = BitRange::from_to(4, 7); - static constexpr auto SustainLevel = BitRange::from_to(0, 3); - ); - - struct __no_align Voice_v { - SweepVolume_v volumeLeft; //Offset: 0x0 - SweepVolume_v volumeRight; //Offset: 0x2 - SampleRate_v sampleRate; //Offset: 0x4; - Adr_v adr; //Offset: 0x6 - AD_v ad; //Offset: 0x8 - SR_v sr; //Offset: 0xA - SimpleVolume_v currentVolume; //Offset: 0xC - Adr_v repeatAdr; //Offset: 0xE }; - __declare_io_type(ControlRegister, uint16_t, - enum RAMTransferMode { - Stop = 0, - ManualWrite = 1, - DMAWrite = 2, - DMARead = 3 - }; + using AD_IO = IOPort; + using DataTransferControl_IO = IOPort; + using Echo_IO = IOPort32; + using KeyOff_IO = IOPort32; + using KeyOn_IO = IOPort32; + using KeyStatus_IO = IOPort32; + using Noise_IO = IOPort; + using PitchModulation_IO = IOPort32; + using SampleRate_IO = IOPort; + using SimpleVolume_IO = IOPort; + using StatusRegister_IO = IOPort; + using SR_IO = IOPort; + using SRAMAdr_IO = IOPort; + using SweepVolume_IO = IOPort; - static constexpr auto Enable = Bit(15); - static constexpr auto Unmute = Bit(14); - static constexpr auto NoiseFrequcenyShift = BitRange::from_to(10, 13); - static constexpr auto NoiseFrequcenyStep = BitRange::from_to(8, 9); - static constexpr auto ReverbMasterEnable = Bit(7); - static constexpr auto IRQ9Enable = Bit(6); - static constexpr auto TransferMode = BitRange::from_to(4, 5); - static constexpr auto ExternalAudioReverb = Bit(3); - static constexpr auto CDAudioReverb = Bit(2); - static constexpr auto ExternalAudioEnable = Bit(1); - static constexpr auto CDAudioEnable = Bit(0); - ); - - __declare_io_type(PMON, uint16_t, - static constexpr auto EnableBits = BitRange::from_to(1, 23); - ); - - __declare_io_type(NON, uint16_t, - static constexpr auto NoiseBits = BitRange::from_to(0, 23); - ); - - __declare_io_type(EON, uint16_t, - static constexpr auto EchoBits = BitRange::from_to(0, 23); - ); - - static constexpr size_t VoiceCount = 24; - - struct Key { - typedef ubus32_t ubus32_v; - - __declare_new_named_io_port(ubus32, On, 0x1F801D88); - __declare_new_named_io_port(ubus32, Off, 0x1F801D8C); - __declare_new_named_io_port(ubus32, Status, 0x1F801D9C); + #pragma pack(push, 1) + struct Voice { + SweepVolume_IO volumeLeft; //Offset: 0x0 + SweepVolume_IO volumeRight; //Offset: 0x2 + SampleRate_IO sampleRate; //Offset: 0x4; + SRAMAdr_IO adr; //Offset: 0x6 + AD_IO ad; //Offset: 0x8 + SR_IO sr; //Offset: 0xA + SimpleVolume_IO adsr_volume; //Offset: 0xC + SRAMAdr_IO repeatAdr; //Offset: 0xE }; + #pragma pack(pop) - struct MainVolume { - __declare_new_named_io_port(SweepVolume, Left, 0x1F801D80); - __declare_new_named_io_port(SweepVolume, Right, 0x1F801D82); - }; + // Required so GCC does not create guards for the ReverbON reference + #define __eon_declaration __declare_io_port(Echo_IO, 0x1F801D98) + + static auto& Voice = __declare_io_port_array(struct Voice, VoiceCount, 0x1F801C00); + static auto& PMON = __declare_io_port(PitchModulation_IO, 0x1F801D90); + static auto& NON = __declare_io_port(Noise_IO, 0x1F801D94); + static auto& EON = __eon_declaration; + static auto& SRAMTransferAdr = __declare_io_port(SRAMAdr_IO, 0x1F801DA6); + static auto& ControlRegister = __declare_io_port(ControlRegister_IO, 0x1F801DAA); + static auto& DataTransferControl = __declare_io_port(DataTransferControl_IO, 0x1F801DAC); + static auto& StatusRegister = __declare_io_port(StatusRegister_IO, 0x1F801DAE); struct CDVolume { - __declare_new_named_io_port(SimpleVolume, Left, 0x1F801DB0); - __declare_new_named_io_port(SimpleVolume, Right, 0x1F801DB2); + static inline auto& Left = __declare_io_port(SimpleVolume_IO, 0x1F801DB0); + static inline auto& Right = __declare_io_port(SimpleVolume_IO, 0x1F801DB2); }; struct ExternalAudioInputVolume { - __declare_new_named_io_port(SimpleVolume, Left, 0x1F801DB4); - __declare_new_named_io_port(SimpleVolume, Right, 0x1F801DB6); + static inline auto& Left = __declare_io_port(SimpleVolume_IO, 0x1F801DB4); + static inline auto& Right = __declare_io_port(SimpleVolume_IO, 0x1F801DB6); + }; + + struct Key { + static inline auto& On = __declare_io_port(KeyOn_IO, 0x1F801D88); + static inline auto& Off = __declare_io_port(KeyOff_IO, 0x1F801D8C); + static inline auto& Status = __declare_io_port(KeyStatus_IO, 0x1F801D9C); + }; + + struct MainVolume { + static inline auto& Left = __declare_io_port(SweepVolume_IO, 0x1F801D80); + static inline auto& Right = __declare_io_port(SweepVolume_IO, 0x1F801D82); }; struct Reverb { struct Volume { - __declare_new_named_io_port(SimpleVolume, Left, 0x1F801D84); - __declare_new_named_io_port(SimpleVolume, Right, 0x1F801D86); + static inline auto& Left = __declare_io_port(SimpleVolume_IO, 0x1F801D84); + static inline auto& Right = __declare_io_port(SimpleVolume_IO, 0x1F801D86); }; - __declare_new_named_io_port(Adr, WorkAreaAdr, 0x1F801DA2); + static inline auto& On = __eon_declaration; + static inline auto& WorkAreaAdr = __declare_io_port(SRAMAdr_IO, 0x1F801DA2); }; - - __declare_new_io_port(ControlRegister, 0x1F801DAA); - __declare_new_io_port(DataTransferControl, 0x1F801DAC); - __declare_new_io_port(PMON, 0x1F801D90); - __declare_new_io_port(NON, 0x1F801D94); - __declare_new_io_port(EON, 0x1F801D98); - - __declare_new_io_port_array(Voice, 0x1F801C00, VoiceCount); } -} -#endif //!__JABYENGINE_SPU_IO_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/System/IOPorts/timer_io.hpp b/include/PSX/System/IOPorts/timer_io.hpp index eadd5d44..5cda8a83 100644 --- a/include/PSX/System/IOPorts/timer_io.hpp +++ b/include/PSX/System/IOPorts/timer_io.hpp @@ -1,112 +1,89 @@ -#ifndef __JABYENGINE_TIMER_IO_HPP__ -#define __JABYENGINE_TIMER_IO_HPP__ -#include "ioport.hpp" +#pragma once +#include "IOValues/timer_io_values.hpp" namespace JabyEngine { namespace Timer_IO { - __declare_io_type(CounterMode, uint32_t, - static constexpr auto SyncEnable = Bit(0); - static constexpr auto FreeRun = !SyncEnable; - static constexpr auto SyncMode = BitRange::from_to(1, 2); - static constexpr auto ResetAfterTarget = Bit(3); - static constexpr auto IRQAtTarget = Bit(4); - static constexpr auto IRQAtMax = Bit(5); - static constexpr auto IRQEveryTime = Bit(6); - static constexpr auto IRQOneShot = !IRQEveryTime; - static constexpr auto IRQToggle = Bit(7); - static constexpr auto IRQPulse = !IRQToggle; - static constexpr auto ClockSource = BitRange::from_to(8, 9); - static constexpr auto HasIRQRequest = Bit(10); - static constexpr auto IsTargetReached = Bit(11); - static constexpr auto IsMaxReached = Bit(12); - ); + using CounterMode_IO = IOPort; + using CounterTarget_IO = IOPort; + using CounterValue_IO = IOPort; - __declare_io_type(CounterTarget, uint32_t, - static constexpr auto CounterTargetValue = BitRange::from_to(0, 15); - ); + #pragma pack(push, 1) + struct Counter { + CounterValue_IO value; + CounterMode_IO mode; + CounterTarget_IO target; + uint32_t unused; - __declare_io_type(CounterValue, uint32_t, - static constexpr auto Value = BitRange::from_to(0, 15); - ); - - struct __no_align Counter { - CounterValue_v value; - CounterMode_v mode; - CounterTarget_v target; - - private: - uint32_t _unused; - - public: - constexpr uint16_t get_current_value() const { - return this->value.get(CounterValue_v::Value); + inline uint16_t get_current_value() const { + return this->value.read().get(Timer_IO_Values::CounterValue::Value); } - constexpr void set_target_value(uint16_t value) { - this->target.set(CounterTarget_v::CounterTargetValue, value); + inline void set_target_value(uint16_t value) { + this->target.write(Timer_IO_Values::CounterTarget{0}.set_range(Timer_IO_Values::CounterTarget::CounterTargetValue, value)); } - constexpr void set_mode(CounterMode_t mode) { - this->mode = mode; + inline void set_mode(Timer_IO_Values::CounterMode mode) { + this->mode.write(mode); } }; + #pragma pack(pop) + + #pragma pack(push, 1) + struct Counter0 : public Counter { + struct SyncMode { + static constexpr auto Zero_At_Hblank = Timer_IO_Values::CounterMode::SyncMode.with(1u); + static constexpr auto Pause_During_Hblank = Timer_IO_Values::CounterMode::SyncMode.with(0u); + static constexpr auto Zero_At_Hblank_Pause_Outside_Hblank = Timer_IO_Values::CounterMode::SyncMode.with(2u); + static constexpr auto Pause_Until_Hblank_Then_Freerun = Timer_IO_Values::CounterMode::SyncMode.with(3u); + }; + + struct Source { + static constexpr auto System_Clock = Timer_IO_Values::CounterMode::ClockSource.with(0u); + static constexpr auto Dot_Clock = Timer_IO_Values::CounterMode::ClockSource.with(1u); + static constexpr auto System_Clock_Too = Timer_IO_Values::CounterMode::ClockSource.with(2u); + static constexpr auto Dot_Clock_Too = Timer_IO_Values::CounterMode::ClockSource.with(3u); + }; + }; + + struct Counter1 : public Counter { + struct SyncMode { + static constexpr auto Pause_During_Vblank = Timer_IO_Values::CounterMode::SyncMode.with(0u); + static constexpr auto Zero_At_Vblank = Timer_IO_Values::CounterMode::SyncMode.with(1u); + static constexpr auto Zero_At_Vblank_Pause_Outside_Vblank = Timer_IO_Values::CounterMode::SyncMode.with(2u); + static constexpr auto Pause_Until_Vblank_Then_FreeRun = Timer_IO_Values::CounterMode::SyncMode.with(3u); + }; + + struct Source { + static constexpr auto System_Clock = Timer_IO_Values::CounterMode::ClockSource.with(0u); + static constexpr auto Hblank = Timer_IO_Values::CounterMode::ClockSource.with(1u); + static constexpr auto System_Clock_Too = Timer_IO_Values::CounterMode::ClockSource.with(2u); + static constexpr auto Hblank_Too = Timer_IO_Values::CounterMode::ClockSource.with(3u); + }; + }; + + struct Counter2 : public Counter { + struct SyncMode { + static constexpr auto Stop_Counter = Timer_IO_Values::CounterMode::SyncMode.with(0u); + static constexpr auto FreeRun = Timer_IO_Values::CounterMode::SyncMode.with(1u); + static constexpr auto FreeRun_Too = Timer_IO_Values::CounterMode::SyncMode.with(2u); + static constexpr auto Stop_Counter_Too = Timer_IO_Values::CounterMode::SyncMode.with(3u); + }; + + struct Source { + static constexpr auto System_Clock = Timer_IO_Values::CounterMode::ClockSource.with(0u); + static constexpr auto System_Clock_Too = Timer_IO_Values::CounterMode::ClockSource.with(1u); + static constexpr auto System_Clock_Div_8 = Timer_IO_Values::CounterMode::ClockSource.with(2u); + static constexpr auto System_Clock_Div_8_Too = Timer_IO_Values::CounterMode::ClockSource.with(3u); + }; + }; + #pragma pack(pop) static constexpr uintptr_t counter_base_adr(size_t ID) { return (0x1F801100 + (ID*0x10)); } - struct __no_align Counter0_v : public Counter { - struct SyncMode { - static constexpr auto Pause_During_Hblank = CounterMode_v::SyncMode.with(0u); - static constexpr auto Zero_At_Hblank = CounterMode_v::SyncMode.with(1u); - static constexpr auto Zero_At_Hblank_Pause_Outside_Hblank = CounterMode_v::SyncMode.with(2u); - static constexpr auto Pause_Until_Hblank_Then_Freerun = CounterMode_v::SyncMode.with(3u); - }; - - struct Source { - static constexpr auto System_Clock = CounterMode_v::ClockSource.with(0u); - static constexpr auto Dot_Clock = CounterMode_v::ClockSource.with(1u); - static constexpr auto System_Clock_Too = CounterMode_v::ClockSource.with(2u); - static constexpr auto Dot_Clock_Too = CounterMode_v::ClockSource.with(3u); - }; - }; - - struct __no_align Counter1_v : public Counter { - struct SyncMode { - static constexpr auto Pause_During_Vblank = CounterMode_v::SyncMode.with(0u); - static constexpr auto Zero_At_Vblank = CounterMode_v::SyncMode.with(1u); - static constexpr auto Zero_At_Vblank_Pause_Outside_Vblank = CounterMode_v::SyncMode.with(2u); - static constexpr auto Pause_Until_Vblank_Then_FreeRun = CounterMode_v::SyncMode.with(3u); - }; - - struct Source { - static constexpr auto System_Clock = CounterMode_v::ClockSource.with(0u); - static constexpr auto Hblank = CounterMode_v::ClockSource.with(1u); - static constexpr auto System_Clock_Too = CounterMode_v::ClockSource.with(2u); - static constexpr auto Hblank_Too = CounterMode_v::ClockSource.with(3u); - }; - }; - - struct __no_align Counter2_v : public Counter { - struct SyncMode { - static constexpr auto Stop_Counter = CounterMode_v::SyncMode.with(0u); - static constexpr auto FreeRun = CounterMode_v::SyncMode.with(1u); - static constexpr auto FreeRun_Too = CounterMode_v::SyncMode.with(2u); - static constexpr auto Stop_Counter_Too = CounterMode_v::SyncMode.with(3u); - }; - - struct Source { - static constexpr auto System_Clock = CounterMode_v::ClockSource.with(0u); - static constexpr auto System_Clock_Too = CounterMode_v::ClockSource.with(1u); - static constexpr auto System_Clock_Div_8 = CounterMode_v::ClockSource.with(2u); - static constexpr auto System_Clock_Div_8_Too = CounterMode_v::ClockSource.with(3u); - }; - }; - - __declare_new_io_port(Counter0, counter_base_adr(0)); - __declare_new_io_port(Counter1, counter_base_adr(1)); - __declare_new_io_port(Counter2, counter_base_adr(2)); + static auto& Counter0 = __declare_io_value(struct Counter0, counter_base_adr(0)); + static auto& Counter1 = __declare_io_value(struct Counter1, counter_base_adr(1)); + static auto& Counter2 = __declare_io_value(struct Counter2, counter_base_adr(2)); } -} - -#endif //!__JABYENGINE_TIMER_IO_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/System/callbacks.hpp b/include/PSX/System/callbacks.hpp new file mode 100644 index 00000000..efbd9f46 --- /dev/null +++ b/include/PSX/System/callbacks.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "syscalls.hpp" + +namespace JabyEngine { + namespace Callback { + struct [[deprecated("Currently not supported")]] VSyncCallback { + using Function = void (*)(); + + static Function callback; + + static void install(Function function) { + VSyncCallback::callback = function; + } + + static void uninstall() { + VSyncCallback::install(nullptr); + } + }; + } +} \ No newline at end of file diff --git a/include/PSX/System/scratchpad.hpp b/include/PSX/System/scratchpad.hpp index 4d1886aa..bdb1b117 100644 --- a/include/PSX/System/scratchpad.hpp +++ b/include/PSX/System/scratchpad.hpp @@ -1,8 +1,6 @@ -#ifndef __JABYENGINE_SCRATCHPAD_HPP__ -#define __JABYENGINE_SCRATCHPAD_HPP__ +#pragma once #include "../jabyengine_defines.h" namespace JabyEngine { static __always_inline auto& ScratchPad = reinterpret_cast(*reinterpret_cast(0x1F800000)); -} -#endif //!__JABYENGINE_SCRATCHPAD_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/System/syscalls.h b/include/PSX/System/syscalls.h deleted file mode 100644 index ad327d65..00000000 --- a/include/PSX/System/syscalls.h +++ /dev/null @@ -1,173 +0,0 @@ -#ifndef __JABYENGINE_SYSCALLS__H -#define __JABYENGINE_SYSCALLS__H -#include "../jabyengine_defines.h" - -/* -R0 zr Constant Zero -R1 at Reserved for the assembler -R2-R3 v0-v1 Values for results and expression evaluation -R4-R7 a0-a3 Arguments -R8-R15 t0-t7 Temporaries (not preserved across call) -R16-R23 s0-s7 Saved (preserved across call) -R24-R25 t8-t9 More temporaries (not preserved across call) -R26-R27 k0-k1 Reserved for OS Kernel -R28 gp Global Pointer -R29 sp Stack Pointer -R30 fp Frame Pointer -R31 ra Return address (set by function call) -*/ - -static __constexpr const uint32_t __syscall_Table_A = 0xA0; -static __constexpr const uint32_t __syscall_Table_B = 0xB0; -static __constexpr const uint32_t __syscall_Table_C = 0xC0; - -enum __syscall_PriorityChain { - CdromDmaIrq = 0, - CdromIoIrq = 0, - SyscallException = 0, - - CardSpecificIrq = 1, - VblankIrq = 1, - Timer2Irq = 1, - Timer1Irq = 1, - Timer0Irq = 1, - - PadCardIrq = 2, - - DefInt = 3 -}; - -enum InterruptVerifierResult { - SkipHandler = 0, - ExecuteHandler = 1 -}; - -typedef InterruptVerifierResult (*InterruptVerifier)(); -typedef uint32_t (*InterruptHandler)(uint32_t); - -struct __no_align InterrupCallback { - struct InterrupCallback* next; - InterruptHandler handler_function; - InterruptVerifier verifier_function; - uint32_t notUsed; -}; - -#ifdef __cplusplus - #define __syscall_function_cast(table, ...) reinterpret_cast<__VA_ARGS__>(table) - extern "C" { -#else - #define __syscall_function_cast(table, ...) ((__VA_ARGS__)(void*)table) -#endif - -static __always_inline void* __syscall_memcpy(void *dst, const void *src, size_t len) { - register uint32_t FuncID asm("t1") = 0x2A; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - return __syscall_function_cast(__syscall_Table_A, void*(*)(void*, const void*, size_t))(dst, src, len); -} - -static __always_inline void __syscall_InitPad(uint8_t *portA, uint32_t portASize, uint8_t *portB, uint32_t portBSize) { - register uint32_t FuncID asm("t1") = 0x12; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - __syscall_function_cast(__syscall_Table_B, void(*)(uint8_t*, uint32_t, uint8_t*, uint32_t))(portA, portASize, portB, portBSize); -} - -static __always_inline void __syscall_StartPad() { - register uint32_t FuncID asm("t1") = 0x13; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - __syscall_function_cast(__syscall_Table_B, void(*)())(); -} - -static __always_inline void __syscall_StopPad() { - register uint32_t FuncID asm("t1") = 0x14; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - __syscall_function_cast(__syscall_Table_B, void(*)())(); -} - -static __always_inline void __syscall_ChangeClearPad(int32_t _reserved) { - register uint32_t FuncID asm("t1") = 0x5B; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - __syscall_function_cast(__syscall_Table_B, void(*)(int32_t))(_reserved); -} - -static __always_inline void [[noreturn]] __syscall_ReturnFromException() { - register uint32_t FuncID asm("t1") = 0x17; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - __syscall_function_cast(__syscall_Table_B, void(*)())(); -} - -static __always_inline int __syscall_SysEnqIntRP(enum __syscall_PriorityChain prio, struct InterrupCallback* interElm) { - register uint32_t FuncID asm("t1") = 0x02; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - return __syscall_function_cast(__syscall_Table_C, int(*)(enum __syscall_PriorityChain prio, struct InterrupCallback *interElm))(prio, interElm); -} - -static __always_inline int __syscall_SysDeqIntRP(enum __syscall_PriorityChain prio, struct InterrupCallback *interElm) { - register uint32_t FuncID asm("t1") = 0x03; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - return __syscall_function_cast(__syscall_Table_C, int(*)(enum __syscall_PriorityChain prio, struct InterrupCallback *interElm))(prio, interElm); -} - -static __always_inline uint32_t __syscall_EnterCriticalSection() { - register uint32_t FuncID asm("a0") = 0x01; - register uint32_t returnValue asm("v0"); - - __asm__ volatile("syscall" : "=r"(FuncID), "=r"(returnValue) : "r"(FuncID) : "at", "v1", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "memory"); - return returnValue; -} - -static __always_inline void __syscall_ExitCriticalSection() { - register uint32_t FuncID asm("a0") = 0x02; - - __asm__ volatile("syscall" : "=r"(FuncID) : "r"(FuncID) : "at", "v0", "v1", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "memory"); -} - -static __always_inline void __syscall__DeliverEvent(uint32_t classId, uint32_t spec) { - register uint32_t FuncID asm("t1") = 0x07; - - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - __syscall_function_cast(__syscall_Table_B, void (*)(uint32_t, uint32_t))(classId, spec); -} - -static __always_inline uint32_t __syscall_OpenEvent(uint32_t classId, uint32_t spec, uint32_t mode, void (*handler)()) { - register uint32_t FuncID asm("t1") = 0x08; - - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - return __syscall_function_cast(__syscall_Table_B, uint32_t(*)(uint32_t, uint32_t, uint32_t, void(*)()))(classId, spec, mode, handler); -} - -static __always_inline int __syscall_CloseEvent(uint32_t event) { - register uint32_t FuncID asm("t1") = 0x09; - - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - return __syscall_function_cast(__syscall_Table_B, uint32_t(*)(uint32_t))(event); -} - -static __always_inline int __syscall_TestEvent(uint32_t event) { - register uint32_t FuncID asm("t1") = 0x0B; - - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - return __syscall_function_cast(__syscall_Table_B, int (*)(uint32_t))(event); -} - -static __always_inline int __syscall_EnableEvent(uint32_t event) { - register uint32_t FuncID asm("t1") = 0x0C; - - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - return __syscall_function_cast(__syscall_Table_B, int (*)(uint32_t))(event); -} - -void __syscall_printf(const char* txt, ...); - -#ifdef __cplusplus -} -#endif - -#endif //!__JABYENGINE_SYSCALLS__H \ No newline at end of file diff --git a/include/PSX/System/syscalls.hpp b/include/PSX/System/syscalls.hpp new file mode 100644 index 00000000..08a699f5 --- /dev/null +++ b/include/PSX/System/syscalls.hpp @@ -0,0 +1,293 @@ +#pragma once +#include "../jabyengine_defines.hpp" + +/* +R0 zr Constant Zero +R1 at Reserved for the assembler +R2-R3 v0-v1 Values for results and expression evaluation +R4-R7 a0-a3 Arguments +R8-R15 t0-t7 Temporaries (not preserved across call) +R16-R23 s0-s7 Saved (preserved across call) +R24-R25 t8-t9 More temporaries (not preserved across call) +R26-R27 k0-k1 Reserved for OS Kernel +R28 gp Global Pointer +R29 sp Stack Pointer +R30 fp Frame Pointer +R31 ra Return address (set by function call) +*/ + +namespace JabyEngine { + namespace BIOS { + struct Version { + enum Type { + Unkown, + Devboard, + PS1, + PS2, + PS3, + PSCompatible, // internal usage only + No$psx, + XEBRA + }; + + struct { + uint8_t day; + uint8_t month; + uint16_t year; + } date; + Type type; + const char* kernel_maker; + const char* version_str; + const char* gui_version; + const char* copyright; + }; + + extern const Version version; + } + + struct TCB { + uint32_t status; + uint32_t unused; + uint32_t reg[32]; + uint32_t epc; + uint32_t hi; + uint32_t lo; + uint32_t sr; + uint32_t cause; + uint32_t unused2[9]; + }; + + struct PCB { + TCB* current_tcb; + }; + + struct ToT { + using ExCB = void; + using EvCB = void; + using FCB = void; + + ExCB* exception_chain; + uint32_t exception_chain_size; + PCB* processes; + uint32_t processes_size; + TCB* threads; + uint32_t threads_size; + uint32_t reserved_0; + uint32_t reserved_1; + EvCB* events; + uint32_t events_size; + uint32_t reserved_2; + uint32_t reserved_3; + uint32_t reserved_4; + uint32_t reserved_5; + uint32_t reserved_6; + uint32_t reserved_7; + FCB* files; + uint32_t files_size; + uint32_t reserved_8; + uint32_t reserved_9; + }; + + extern ToT table_of_tables; + + namespace SysCall { + static constexpr const uint32_t Table_A = 0xA0; + static constexpr const uint32_t Table_B = 0xB0; + static constexpr const uint32_t Table_C = 0xC0; + + enum struct Priority { + CdromDmaIrq = 0, + CdromIoIrq = 0, + SyscallException = 0, + + CardSpecificIrq = 1, + VblankIrq = 1, + Timer2Irq = 1, + Timer1Irq = 1, + Timer0Irq = 1, + + PadCardIrq = 2, + + DefInt = 3 + }; + + enum InterruptVerifierResult { + SkipHandler = 0, + ExecuteHandler = 1 + }; + + typedef InterruptVerifierResult (*InterruptVerifier)(); + typedef void (*InterruptHandler)(uint32_t); + using ThreadHandle = uint32_t; + + #pragma pack(push, 1) + struct InterruptCallback { + struct InterruptCallback* next; + InterruptHandler handler_function; + InterruptVerifier verifier_function; + uint32_t notUsed; + + static constexpr InterruptCallback from(InterruptVerifier verifier, InterruptHandler handler) { + return InterruptCallback{nullptr, handler, verifier, 0}; + } + }; + #pragma pack(pop) + + #define __syscall_function_cast(table, ...) reinterpret_cast<__VA_ARGS__>(table) + + static __always_inline uint32_t* get_gp() { + uint32_t* gp; + __asm__("sw $gp, %0" : "=m"(gp)); + return gp; + } + + static __always_inline void DequeueCdIntr() { + register uint32_t FuncID asm("t1") = 0xa3; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_A, void(*)())(); + } + + static __always_inline void FlushCache() { + register uint32_t FuncID asm("t1") = 0x44; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_A, void(*)())(); + } + + static __always_inline void* memcpy(void *dst, const void *src, size_t len) { + register uint32_t FuncID asm("t1") = 0x2A; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + return __syscall_function_cast(Table_A, void*(*)(void*, const void*, size_t))(dst, src, len); + } + + static __always_inline ThreadHandle OpenThread(void (*thread_func)(), uint32_t* stack_ptr, uint32_t* gp) { + register uint32_t FuncID asm("t1") = 0x0E; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + return __syscall_function_cast(Table_B, ThreadHandle(*)(void(*)(), uint32_t*, uint32_t*))(thread_func, stack_ptr, gp); + } + + static __always_inline void [[noreturn]] ChangeThread(ThreadHandle handle) { + register uint32_t FuncID asm("t1") = 0x10; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_B, void(*)(ThreadHandle))(handle); + } + + static __always_inline void InitPad(uint8_t *portA, uint32_t portASize, uint8_t *portB, uint32_t portBSize) { + register uint32_t FuncID asm("t1") = 0x12; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_B, void(*)(uint8_t*, uint32_t, uint8_t*, uint32_t))(portA, portASize, portB, portBSize); + } + + static __always_inline void StartPad() { + register uint32_t FuncID asm("t1") = 0x13; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_B, void(*)())(); + } + + static __always_inline void StopPad() { + register uint32_t FuncID asm("t1") = 0x14; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_B, void(*)())(); + } + + static __always_inline void ChangeClearPad(int32_t _reserved) { + register uint32_t FuncID asm("t1") = 0x5B; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_B, void(*)(int32_t))(_reserved); + } + + static __always_inline void [[noreturn]] ReturnFromException() { + register uint32_t FuncID asm("t1") = 0x17; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_B, void(*)())(); + } + + static __always_inline void SetDefaultExitFromException() { + register uint32_t FuncID asm("t1") = 0x18; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_B, void(*)())(); + } + + static __always_inline int SysEnqIntRP(Priority prio, InterruptCallback* interElm) { + register uint32_t FuncID asm("t1") = 0x02; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + return __syscall_function_cast(Table_C, int(*)(Priority prio, InterruptCallback *interElm))(prio, interElm); + } + + static __always_inline int SysDeqIntRP(Priority prio, InterruptCallback *interElm) { + register uint32_t FuncID asm("t1") = 0x03; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + return __syscall_function_cast(Table_C, int(*)(Priority prio, InterruptCallback *interElm))(prio, interElm); + } + + static __always_inline uint32_t EnterCriticalSection() { + register uint32_t FuncID asm("a0") = 0x01; + register uint32_t returnValue asm("v0"); + + __asm__ volatile("syscall" : "=r"(returnValue) : "r"(FuncID) : "memory"); + return returnValue; + } + + static __always_inline void ExitCriticalSection() { + register uint32_t FuncID asm("a0") = 0x02; + + __asm__ volatile("syscall" :: "r"(FuncID) : "memory"); + } + + static __always_inline void DeliverEvent(uint32_t classId, uint32_t spec) { + register uint32_t FuncID asm("t1") = 0x07; + + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + __syscall_function_cast(Table_B, void (*)(uint32_t, uint32_t))(classId, spec); + } + + static __always_inline uint32_t OpenEvent(uint32_t classId, uint32_t spec, uint32_t mode, void (*handler)()) { + register uint32_t FuncID asm("t1") = 0x08; + + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + return __syscall_function_cast(Table_B, uint32_t(*)(uint32_t, uint32_t, uint32_t, void(*)()))(classId, spec, mode, handler); + } + + static __always_inline int CloseEvent(uint32_t event) { + register uint32_t FuncID asm("t1") = 0x09; + + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + return __syscall_function_cast(Table_B, uint32_t(*)(uint32_t))(event); + } + + static __always_inline int32_t TestEvent(uint32_t event) { + register uint32_t FuncID asm("t1") = 0x0B; + + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + return __syscall_function_cast(Table_B, int32_t (*)(uint32_t))(event); + } + + static __always_inline int32_t EnableEvent(uint32_t event) { + register uint32_t FuncID asm("t1") = 0x0C; + + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + return __syscall_function_cast(Table_B, int32_t (*)(uint32_t))(event); + } + + static __always_inline const uint16_t* Krom2RawAdd(uint16_t sjis_code) { + register uint32_t FuncID asm("t1") = 0x51; + + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + return __syscall_function_cast(Table_B, const uint16_t* (*)(uint16_t))(sjis_code); + } + + void printf(const char* txt, ...); + } +} \ No newline at end of file diff --git a/include/PSX/Timer/frame_time_helper.hpp b/include/PSX/Timer/frame_time_helper.hpp new file mode 100644 index 00000000..e1de8ada --- /dev/null +++ b/include/PSX/Timer/frame_time_helper.hpp @@ -0,0 +1,25 @@ +#ifndef __JABYENGINE_FRAME_TIME_HELPER_HPP__ +#define __JABYENGINE_FRAME_TIME_HELPER_HPP__ +#include +#include + +namespace JabyEngine { + static constexpr double ms_per_frame = 1000.0/static_cast(GPU::Display::frames_per_sec); + + template + static constexpr T ms_to_vsync_ticks(T time_ms) { + return static_cast(static_cast(time_ms)/ms_per_frame); + } + + static constexpr uint32_t operator ""_ms(unsigned long long time) { + return static_cast(ms_to_vsync_ticks(time)); + } + + static constexpr size_t max_ms_time_u8 = UI8_MAX*ms_per_frame; + static constexpr size_t max_ms_time_u16 = UI16_MAX*ms_per_frame; + static constexpr size_t max_ms_time_u32 = UI32_MAX; + + #undef literal_operator_template +} +using JabyEngine::operator""_ms; +#endif //!__JABYENGINE_FRAME_TIME_HELPER_HPP__ \ No newline at end of file diff --git a/include/PSX/Timer/frame_timer.hpp b/include/PSX/Timer/frame_timer.hpp new file mode 100644 index 00000000..47888d9a --- /dev/null +++ b/include/PSX/Timer/frame_timer.hpp @@ -0,0 +1,74 @@ +#ifndef __JABYENGINE_FRAME_TIMER_HPP__ +#define __JABYENGINE_FRAME_TIMER_HPP__ +#include "frame_time_helper.hpp" +#include + +namespace JabyEngine { + class MasterTime { + __friends: + static uint32_t value; + + public: + static uint32_t read() { + return reinterpret_cast(MasterTime::value); + } + + template + static T read_as() { + return static_cast(MasterTime::read()); + } + }; + + template + class SimpleTimer { + protected: + T value = 0; + + public: + constexpr SimpleTimer() = default; + + static SimpleTimer create() { + SimpleTimer timer; + + timer.reset(); + return timer; + } + + bool is_expired_for(T time) const { + return static_cast((MasterTime::read_as() - this->value)) >= time; + } + + void reset() { + this->value = MasterTime::read_as(); + } + }; + + template + class IntervalTimer : public SimpleTimer { + private: + T interval = 0; + + public: + constexpr IntervalTimer() = default; + constexpr IntervalTimer(T interval) : SimpleTimer(), interval(interval) { + } + + static constexpr IntervalTimer create(T interval) { + IntervalTimer timer; + + static_cast&>(timer) = SimpleTimer::create(); + timer.interval = interval; + return timer; + } + + void set_interval(T interval) { + this->interval = interval; + } + + bool is_expired() const { + return SimpleTimer::is_expired_for(this->interval); + } + }; +} + +#endif //!__JABYENGINE_FRAME_TIMER_HPP__ \ No newline at end of file diff --git a/include/PSX/Timer/high_res_timer.hpp b/include/PSX/Timer/high_res_timer.hpp index 9ae8141d..c3e1626e 100644 --- a/include/PSX/Timer/high_res_timer.hpp +++ b/include/PSX/Timer/high_res_timer.hpp @@ -1,6 +1,7 @@ #ifndef __JABYENGINE_HIGH_RES_TIMER_HPP__ #define __JABYENGINE_HIGH_RES_TIMER_HPP__ -#include "../jabyengine_defines.h" +#include "../jabyengine_defines.hpp" +#include #include namespace JabyEngine { @@ -24,51 +25,57 @@ namespace JabyEngine { } }; - #ifdef JABYENGINE_USE_HIGH_PERCISION_TIMER - class HighResTime { - public: - class TimeStamp { - private: - uint16_t counter_10ms_value; - uint16_t fraction; - - constexpr TimeStamp(uint16_t counter_10ms_value, uint16_t fraction) : counter_10ms_value(counter_10ms_value), fraction(fraction) { - } - - constexpr static size_t to_us(uint16_t counter_10ms_value, uint16_t fraction) { - return counter_10ms_value*(10*1000) + ((fraction/HighResTime::TicksFor100us)*100); - } - - constexpr static size_t to_ms(uint16_t counter_10ms_value, uint16_t fraction) { - return counter_10ms_value*10 + (fraction/HighResTime::TicksFor1ms); - } - - public: - constexpr size_t microseconds_to(const TimeStamp& end) const { - return TimeStamp::to_us((end.counter_10ms_value - this->counter_10ms_value), (end.fraction - this->fraction)); - } - - constexpr size_t milliseconds_to(const TimeStamp& end) const { - return TimeStamp::to_ms((end.counter_10ms_value - this->counter_10ms_value), (end.fraction - this->fraction)); - } - friend class HighResTime; - }; - + class HighResTime { + public: + class TimeStamp { private: - static constexpr uint16_t TicksFor100us = CPUTicks::ticks_per_us(CPUTicks::Frequency_Hz_Div8, 100.0); - static constexpr uint16_t TicksFor1ms = CPUTicks::ticks_per_ms(CPUTicks::Frequency_Hz_Div8, 1.0); - static constexpr uint16_t TicksFor10ms = CPUTicks::ticks_per_ms(CPUTicks::Frequency_Hz_Div8, 10.0); + uint16_t counter_10ms_value; + uint16_t fraction; - static volatile uint16_t global_counter_10ms; + constexpr TimeStamp(uint16_t counter_10ms_value, uint16_t fraction) : counter_10ms_value(counter_10ms_value), fraction(fraction) { + } + + constexpr static size_t to_us(uint16_t counter_10ms_value, uint16_t fraction) { + return counter_10ms_value*(10*1000) + ((fraction/HighResTime::TicksFor100us)*100); + } + + constexpr static size_t to_ms(uint16_t counter_10ms_value, uint16_t fraction) { + return counter_10ms_value*10 + (fraction/HighResTime::TicksFor1ms); + } public: - HighResTime() = delete; - ~HighResTime() = delete; - - static TimeStamp get_time_stamp() { - return TimeStamp(HighResTime::global_counter_10ms, Timer_IO::Counter2.get_current_value()); + constexpr size_t microseconds_to(const TimeStamp& end) const { + return TimeStamp::to_us((end.counter_10ms_value - this->counter_10ms_value), (end.fraction - this->fraction)); } + + constexpr size_t milliseconds_to(const TimeStamp& end) const { + return TimeStamp::to_ms((end.counter_10ms_value - this->counter_10ms_value), (end.fraction - this->fraction)); + } + friend class HighResTime; }; - #endif //JABYENGINE_USE_HIGH_PERCISION_TIMER + + __friends: + static constexpr uint16_t TicksFor100us = CPUTicks::ticks_per_us(CPUTicks::Frequency_Hz_Div8, 100.0); + static constexpr uint16_t TicksFor1ms = CPUTicks::ticks_per_ms(CPUTicks::Frequency_Hz_Div8, 1.0); + static constexpr uint16_t TicksFor10ms = CPUTicks::ticks_per_ms(CPUTicks::Frequency_Hz_Div8, 10.0); + + static volatile uint16_t global_counter_10ms; + + public: + HighResTime() = delete; + ~HighResTime() = delete; + + static void enable() { + Interrupt::enable_irq(Interrupt::Timer2); + } + + static void disable() { + Interrupt::disable_irq(Interrupt::Timer2); + } + + static TimeStamp get_time_stamp() { + return TimeStamp(HighResTime::global_counter_10ms, Timer_IO::Counter2.get_current_value()); + } + }; } #endif //!__JABYENGINE_HIGH_RES_TIMER_HPP__ \ No newline at end of file diff --git a/include/PSX/jabyengine.hpp b/include/PSX/jabyengine.hpp index 65a33360..e3fc483f 100644 --- a/include/PSX/jabyengine.hpp +++ b/include/PSX/jabyengine.hpp @@ -1,9 +1,6 @@ -#ifndef __JABYENGINE__HPP__ -#define __JABYENGINE__HPP__ -#include "jabyengine_defines.h" +#pragma once +#include "jabyengine_defines.hpp" namespace JabyEngine { typedef void (*MainRoutine)(); -} - -#endif //!__JABYENGINE__HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/include/PSX/jabyengine_config.hpp b/include/PSX/jabyengine_config.hpp index 5d2ed50d..64b5cd2a 100644 --- a/include/PSX/jabyengine_config.hpp +++ b/include/PSX/jabyengine_config.hpp @@ -1,8 +1,37 @@ -#ifndef __JABYENGINE_CONFIG_HPP__ -#define __JABYENGINE_CONFIG_HPP__ - #ifdef USE_CUSTOM_CONFIG - #include - #else - #define JABYENGINE_USE_HIGH_PERCISION_TIMER - #endif //USE_CUSTOM_CONFIG -#endif //!__JABYENGINE_CONFIG_HPP__ \ No newline at end of file +#pragma once +#include + +namespace JabyEngine { + struct DefaultConfiguration { + struct BIOSFont { + static constexpr GPU::PositionU16 texture_load_pos() { + return GPU::PositionU16::create(320, 256); + } + + static constexpr GPU::PositionU16 CLUT_load_pos() { + return GPU::PositionU16::create(320, 511); + } + }; + + static constexpr auto DisplayDefaultOffset = GPU::PositionI16::create(0, 0); + + struct Periphery { + static constexpr bool include_portB() { + return false; + } + + static constexpr bool use_multi_tap(){ + return false; + } + }; + }; + + #if __has_include() + #include + using Configuration = CustomConfiguration; + #else + using Configuration = DefaultConfiguration; + #define __SUPPORT_PS3__ + #define __DEBUG_SPU_MMU__ + #endif // has jabyengine_custom_config +} \ No newline at end of file diff --git a/include/PSX/jabyengine_defines.h b/include/PSX/jabyengine_defines.hpp similarity index 57% rename from include/PSX/jabyengine_defines.h rename to include/PSX/jabyengine_defines.hpp index 8c838cb7..b9b19fb9 100644 --- a/include/PSX/jabyengine_defines.h +++ b/include/PSX/jabyengine_defines.hpp @@ -1,19 +1,16 @@ -#ifndef __JABYENGINE_DEFINES__H__ -#define __JABYENGINE_DEFINES__H__ -#include "jabyengine_config.hpp" -#include "../stddef.h" - -#define __used __attribute__((used)) -#define __no_align __attribute__((packed)) -#define __no_inline __attribute__((noinline)) -#define __no_return __attribute__((noreturn)) -#define __always_inline __attribute__((always_inline)) -#define __section(name) __attribute__((section(name))) -#define __collect(...) __VA_ARGS__ - -#ifdef __cplusplus - #define __constexpr constexpr -#else - #define __constexpr -#endif -#endif //!__JABYENGINE_DEFINES__H__ \ No newline at end of file +#pragma once +#include "Auxiliary/literals.hpp" +#include + +#define __used __attribute__((used)) +#define __no_align __attribute__((packed)) +#define __no_inline __attribute__((noinline)) +#define __no_return __attribute__((noreturn)) +#define __always_inline __attribute__((always_inline)) +#define __weak __attribute__((weak)) +#define __section(name) __attribute__((section(name))) +#define __collect(...) __VA_ARGS__ + +#ifndef __friends + #define __friends private +#endif //!__friends \ No newline at end of file diff --git a/include/limits.h b/include/limits.h deleted file mode 100644 index 49077b0f..00000000 --- a/include/limits.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __LIMITS__H -#define __LIMITS__H - -#define CHAR_BIT 8 -#define SCHAR_MIN (-128) -#define SCHAR_MAX 127 -#define UCHAR_MAX 0xff - -#define CHAR_MIN SCHAR_MIN -#define CHAR_MAX SCHAR_MAX - -#define SHRT_MIN (-32768) -#define SHRT_MAX 32767 -#define USHRT_MAX 0xffff - -#define INT_MIN (-2147483647 - 1) -#define INT_MAX 2147483647 -#define UINT_MAX 0xffffffff - -#define LONG_MIN INT_MIN -#define LONG_MAX INT_MAX -#define ULONG_MAX UINT_MAX - -#define I8_MIN SCHAR_MIN -#define I8_MAX SCHAR_MAX -#define UI8_MAX UCHAR_MAX - -#define I16_MIN SHRT_MIN -#define I16_MAX SHRT_MAX -#define UI16_MAX USHRT_MAX - -#define I32_MIN INT_MIN -#define I32_MAX INT_MAX -#define UI32_MAX UINT_MAX - -#endif //!__LIMITS__H \ No newline at end of file diff --git a/include/limits.hpp b/include/limits.hpp new file mode 100644 index 00000000..c64ed7a0 --- /dev/null +++ b/include/limits.hpp @@ -0,0 +1,33 @@ +#pragma once + +static constexpr auto CHAR_BIT = 8; +static constexpr auto SCHAR_MIN = -128; +static constexpr auto SCHAR_MAX = 127; +static constexpr auto UCHAR_MAX = 0xff; + +static constexpr auto CHAR_MIN = SCHAR_MIN; +static constexpr auto CHAR_MAX = SCHAR_MAX; + +static constexpr auto SHRT_MIN = -32768; +static constexpr auto SHRT_MAX = 32767; +static constexpr auto USHRT_MAX = 0xffff; + +static constexpr auto INT_MIN = -2147483647 - 1; +static constexpr auto INT_MAX = 2147483647; +static constexpr auto UINT_MAX = 0xffffffff; + +static constexpr auto LONG_MIN = INT_MIN; +static constexpr auto LONG_MAX = INT_MAX; +static constexpr auto ULONG_MAX = UINT_MAX; + +static constexpr auto I8_MIN = SCHAR_MIN; +static constexpr auto I8_MAX = SCHAR_MAX; +static constexpr auto UI8_MAX = UCHAR_MAX; + +static constexpr auto I16_MIN = SHRT_MIN; +static constexpr auto I16_MAX = SHRT_MAX; +static constexpr auto UI16_MAX = USHRT_MAX; + +static constexpr auto I32_MIN = INT_MIN; +static constexpr auto I32_MAX = INT_MAX; +static constexpr auto UI32_MAX = UINT_MAX; \ No newline at end of file diff --git a/include/math.hpp b/include/math.hpp new file mode 100644 index 00000000..a48aa03e --- /dev/null +++ b/include/math.hpp @@ -0,0 +1,78 @@ +#pragma once +#include "stdint.hpp" + +namespace math { + template + struct raw_math { + constexpr T operator-() const { + return T{.raw = static_cast(-(static_cast(*this).raw))}; + } + + constexpr T operator+(const T& obj) const { + return T{.raw = static_cast(*this).raw + obj.raw}; + } + + constexpr T operator-(const T& b) const {} + + constexpr T& operator+=(const T& obj) { + static_cast(*this).raw += obj.raw; + return static_cast(*this); + } + + constexpr T& operator-=(const T& obj) { + static_cast(*this).raw -= obj.raw; + return static_cast(*this); + } + }; +} + +struct deg_t : public math::raw_math { + static constexpr auto full_circle = 32768; + static constexpr auto one_degree = full_circle/360; + static constexpr auto one_tenth_degree = full_circle/3600; + + int16_t raw; + + static constexpr deg_t zero() { + return deg_t{.raw = 0}; + } + + static constexpr deg_t from_degree(int32_t deg) { + return deg_t{.raw = static_cast(deg*one_degree)}; + } + + static constexpr deg_t from_tenth_degree(int32_t deg10) { + return deg_t{.raw = static_cast(deg10*one_tenth_degree)}; + } +}; + +static constexpr deg_t operator""_deg(long double degree) { + return deg_t::from_tenth_degree((degree*10.0)); +} + +struct gte_float : public math::raw_math { + int32_t raw; + + static constexpr gte_float from_double(double value) { + return gte_float{.raw = static_cast(4096.0*value)}; + } + + static constexpr gte_float one() { + return gte_float::from_double(1.0); + } + + constexpr explicit operator int32_t() const { + return this->raw; + } + + constexpr explicit operator int16_t() const { + return static_cast(this->raw); + } +}; + +static constexpr gte_float operator""_gf(long double value) { + return gte_float::from_double(value); +} + +gte_float sin(deg_t value); +gte_float cos(deg_t value); \ No newline at end of file diff --git a/include/stdarg.hpp b/include/stdarg.hpp new file mode 100644 index 00000000..d4c85692 --- /dev/null +++ b/include/stdarg.hpp @@ -0,0 +1,7 @@ +#pragma once + +using va_list = __builtin_va_list; +#define va_start __builtin_va_start +#define va_end __builtin_va_end +#define next_arg __builtin_next_arg +#define va_arg __builtin_va_arg \ No newline at end of file diff --git a/include/stddef.h b/include/stddef.h deleted file mode 100644 index ffb37baf..00000000 --- a/include/stddef.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __STDDEF__H -#define __STDDEF__H -#include "stdint.h" - -typedef uintmax_t size_t; - -#endif //!__STDDEF__H \ No newline at end of file diff --git a/include/stddef.hpp b/include/stddef.hpp new file mode 100644 index 00000000..921680bd --- /dev/null +++ b/include/stddef.hpp @@ -0,0 +1,4 @@ +#pragma once +#include "stdint.hpp" + +using size_t = uintmax_t; \ No newline at end of file diff --git a/include/stdint.h b/include/stdint.h deleted file mode 100644 index f27f36cc..00000000 --- a/include/stdint.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __STDINT__H -#define __STDINT__H - -typedef signed char int8_t; -typedef unsigned char uint8_t; - -typedef short int16_t; -typedef unsigned short uint16_t; - -typedef int int32_t; -typedef unsigned int uint32_t; - -typedef signed char int_least8_t; -typedef unsigned char uint_least8_t; - -typedef short int_least16_t; -typedef unsigned short uint_least16_t; - -typedef int int_least32_t; -typedef unsigned int uint_least32_t; - -typedef signed char int_fast8_t; -typedef unsigned char uint_fast8_t; - -typedef int int_fast16_t; -typedef unsigned int uint_fast16_t; - -typedef int int_fast32_t; -typedef unsigned int uint_fast32_t; - -typedef signed int intmax_t; -typedef unsigned int uintmax_t; - -typedef signed long intptr_t; -typedef unsigned long uintptr_t; - -#endif //!__STDINT__H \ No newline at end of file diff --git a/include/stdint.hpp b/include/stdint.hpp new file mode 100644 index 00000000..07a7e574 --- /dev/null +++ b/include/stdint.hpp @@ -0,0 +1,34 @@ +#pragma once + +using int8_t = signed char; +using uint8_t = unsigned char; + +using int16_t = short; +using uint16_t = unsigned short; + +using int32_t = int; +using uint32_t = unsigned int; + +using int_least8_t = signed char; +using uint_least8_t = unsigned char; + +using int_least16_t = short; +using uint_least16_t = unsigned short; + +using int_least32_t = int; +using uint_least32_t = unsigned int; + +using int_fast8_t = signed char; +using uint_fast8_t = unsigned char; + +using int_fast16_t = int; +using uint_fast16_t = unsigned int; + +using int_fast32_t = int; +using uint_fast32_t = unsigned int; + +using intmax_t = signed int; +using uintmax_t = unsigned int; + +using intptr_t = signed long; +using uintptr_t = unsigned long; \ No newline at end of file diff --git a/include/stdio.h b/include/stdio.h deleted file mode 100644 index cb03ac80..00000000 --- a/include/stdio.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __STDIO__H -#define __STDIO__H -#include "PSX/System/syscalls.h" - -#define printf __syscall_printf - -#endif //!__STDIO__H \ No newline at end of file diff --git a/include/stdio.hpp b/include/stdio.hpp new file mode 100644 index 00000000..79fcaf81 --- /dev/null +++ b/include/stdio.hpp @@ -0,0 +1,4 @@ +#pragma once +#include "PSX/jabyengine_defines.hpp" + +int printf(const char* txt, ...) asm("_ZN10JabyEngine7SysCall6printfEPKcz"); \ No newline at end of file diff --git a/include/string.hpp b/include/string.hpp new file mode 100644 index 00000000..072c20b8 --- /dev/null +++ b/include/string.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "PSX/jabyengine_defines.hpp" + +int strncmp(const char* s1, const char* s2, size_t n); +size_t strlen(const char* str); + +extern "C" { + // Needs to be provided for GCC optimizations + void* memset(void* dest, int val, size_t len); +} \ No newline at end of file diff --git a/lib/ExportPath.mk b/lib/ExportPath.mk deleted file mode 100644 index fcc3b8d3..00000000 --- a/lib/ExportPath.mk +++ /dev/null @@ -1,2 +0,0 @@ -#Add the JabyEngine tools to path -export PATH := $(JABY_ENGINE_DIR)/bin/:$(PATH) \ No newline at end of file diff --git a/lib/Makefile b/lib/Makefile deleted file mode 100644 index 5b262c51..00000000 --- a/lib/Makefile +++ /dev/null @@ -1,100 +0,0 @@ -SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST))) -include $(SELF_DIR)ExportPath.mk - -#Build architecture/variant string, possible values: x86, armv7le, etc... -PLATFORM ?= PSX - -#Build profile, possible values: release, debug, profile, coverage -BUILD_DIR ?= bin -BUILD_PROFILE ?= debug -TV_FORMAT ?= PAL - -CONFIG_NAME ?= $(PLATFORM)-$(BUILD_PROFILE) -OUTPUT_DIR = $(BUILD_DIR)/$(CONFIG_NAME) -TARGET = $(OUTPUT_DIR)/$(ARTIFACT) - -#Compiler definitions -HAS_LINUX_MIPS_GCC = $(shell which mipsel-linux-gnu-gcc-10 > /dev/null 2> /dev/null && echo true || echo false) -ifeq ($(HAS_LINUX_MIPS_GCC),true) -PREFIX ?= mipsel-linux-gnu -FORMAT ?= elf32-tradlittlemips -else -PREFIX ?= mipsel-none-elf -FORMAT ?= elf32-littlemips -endif - -#Take this to PSEXETarget.mk?? -#LDSCRIPT ?= $(PSCX_REDUX_DIR)/ps-exe.ld -#ifneq ($(strip $(OVERLAYSCRIPT)),) -#LDSCRIPT := $(addprefix $(OVERLAYSCRIPT) , -T$(LDSCRIPT)) -#else -#LDSCRIPT := $(addprefix $(PSCX_REDUX_DIR)/default.ld , -T$(LDSCRIPT)) -#endif - -CC = $(PREFIX)-gcc-10 -CXX = $(PREFIX)-g++-10 -LD = $(CXX) -AR = ar - -#architecture flags -ARCHFLAGS = -march=mips1 -mabi=32 -EL -fno-pic -mno-shared -nostdinc -nostdinc++ -mno-abicalls -mfp32 -ARCHFLAGS += -fno-stack-protector -nostdlib -ffreestanding - -#Compiler flags for build profiles -CCFLAGS_release += -O3 -CCFLAGS_debug += -O0 - -CXXFLAGS += -fno-exceptions -fno-rtti - -USE_FUNCTION_SECTIONS ?= true -ifeq ($(USE_FUNCTION_SECTIONS),true) -CCFLAGS += -ffunction-sections -endif -CCFLAGS += -mno-gpopt -fomit-frame-pointer -CCFLAGS += -fno-builtin -fno-strict-aliasing -Wno-attributes -CCFLAGS += -std=c++20 -CCFLAGS += $(ARCHFLAGS) - -CCFLAGS += $(CCFLAGS_$(BUILD_PROFILE)) -CCFLAGS += $(INCLUDES) -CCFLAGS += -DJABYENGINE_$(TV_FORMAT) - -#Linker flags -LDFLAGS_release += -Os - -LDFLAGS_all += -Wl,-Map=$(TARGET).map -nostdlib -T$(AUTO_OVERLAY_DIR)/Overlays.ld -T$(JABY_ENGINE_DIR)/lib/psexe.ld -static -Wl,--gc-sections -Wl,--build-id=none -Wl,--no-check-sections -LDFLAGS_all += $(ARCHFLAGS) -Wl,--oformat=$(FORMAT) -LDFLAGS_all += $(LDFLAGS_$(BUILD_PROFILE)) - -LIBS_all += $(LIBS_$(BUILD_PROFILE)) - -DEPS = -Wp,-MMD,$(@:%.o=%.d),-MT,$@ - -#Object files list -OBJS = $(addprefix $(OUTPUT_DIR)/,$(addsuffix .o, $(subst ..,!super,$(basename $(SRCS))))) - -#Compiling rule -$(OUTPUT_DIR)/%.o: %.s - @mkdir -p $(dir $@) - $(CC) -c $(DEPS) -o $@ $(CCFLAGS) $(CCFLAGS) $< - -$(OUTPUT_DIR)/%.o: %.c - @mkdir -p $(dir $@) - $(CC) -c $(DEPS) -o $@ $(CCFLAGS) $(CCFLAGS) $< - -$(OUTPUT_DIR)/%.o: %.cpp - @mkdir -p $(dir $@) - $(CXX) -c $(DEPS) -o $@ $(CCFLAGS) $(CXXFLAGS) $< - -.SECONDEXPANSION: -$(OUTPUT_DIR)/%.o: $$(subst !super,..,%.s) - @mkdir -p $(dir $@) - $(CC) $(ARCHFLAGS) -I$(PCSX_REDUX) -g -c -o $@ $< - -#Rules section for default compilation and linking -rebuild: - $(MAKE) clean - $(MAKE) all - -#Inclusion of dependencies (object files to source and includes) --include $(OBJS:%.o=%.d) \ No newline at end of file diff --git a/lib/PSEXETarget.mk b/lib/PSEXETarget.mk deleted file mode 100644 index 7445dd7d..00000000 --- a/lib/PSEXETarget.mk +++ /dev/null @@ -1,28 +0,0 @@ -#Not intended to be overriden -AUTO_OVERLAY_DIR = $(OUTPUT_DIR)/auto_overlay - -include $(AUTO_OVERLAY_DIR)/Overlays.mk - -#We use the JabyEngine so we will include ourselves -JABY_ENGINE_LIB_DIR = $(JABY_ENGINE_DIR)/lib/PSX-$(BUILD_PROFILE) -JABY_ENGINE_LIB_NAME = JabyEngine_$(TV_FORMAT) - -#Linking rule -$(TARGET).elf: $(OBJS) $(JABY_ENGINE_LIB_DIR)/lib$(JABY_ENGINE_LIB_NAME).a $(AUTO_OVERLAY_DIR)/Overlays.ld - $(LD) -o $(TARGET).elf $(LDFLAGS_all) $(LDFLAGS) $(OBJS) -L$(JABY_ENGINE_LIB_DIR) -l$(JABY_ENGINE_LIB_NAME) $(LIBS) - -#Strips the psexe -$(TARGET).psexe: $(TARGET).elf - $(PREFIX)-objcopy $(addprefix -R , $(OVERLAYSECTION)) -O binary $< $@ - -#Create overlays -$(foreach ovl, $(OVERLAYSECTION), $(OUTPUT_DIR)/Overlay$(ovl)): $(TARGET).elf - $(PREFIX)-objcopy -j $(suffix $@) -O binary $< $@ - -#Create overlay makefile -$(AUTO_OVERLAY_DIR)/Overlays.mk: $(OVERLAY_CONFIG) - @mkdir -p $(AUTO_OVERLAY_DIR) - mkoverlay --mk-file $(AUTO_OVERLAY_DIR)/Overlays.mk --ld-script $(AUTO_OVERLAY_DIR)/Overlays.ld $< - -#Rules section for default compilation and linking -all: $(TARGET).psexe $(foreach ovl, $(OVERLAYSECTION), $(OUTPUT_DIR)/Overlay$(ovl)) \ No newline at end of file diff --git a/mkfile/ISOMakefile.mk b/mkfile/ISOMakefile.mk new file mode 100644 index 00000000..c0c85139 --- /dev/null +++ b/mkfile/ISOMakefile.mk @@ -0,0 +1,23 @@ +CD_OUTPUT ?= $(REGION)/$(ARTIFACT).bin +PKG_OUTPUT ?= $(REGION)/$(ARTIFACT).pkg + +$(CD_OUTPUT): always + @mkdir -p $(REGION) + psxcdgen_ex --list $(REGION)/$(ARTIFACT).lba -o $(REGION)/$(ARTIFACT) bin-cue Config.xml + +$(PKG_OUTPUT): always + @mkdir -p $(REGION) + @echo "!!PKG generation is experimentel!!" + run_pop_fe.sh $(ARTIFACT) $(PWD)/assets/pkg $(PWD)/iso/$(REGION)/$(ARTIFACT).cue + +all: $(CD_OUTPUT) +clean: pkg_clean + rm -fr $(REGION)/*.bin + rm -fr $(REGION)/*.cue + rm -fr $(REGION)/*.lba + +pkg_all: $(PKG_OUTPUT) +pkg_clean: + rm -fr $(REGION)/*.pkg + +always: ; \ No newline at end of file diff --git a/mkfile/Makefile b/mkfile/Makefile new file mode 100644 index 00000000..cd1685f3 --- /dev/null +++ b/mkfile/Makefile @@ -0,0 +1,98 @@ +SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +include $(SELF_DIR)common/ExportPath.mk + +substitute = $(subst $(JABY_ENGINE_DIR)/include/modules,!JABYENGINEMODULES,$(subst ..,!super,$1)) +desubstitute = $(subst !JABYENGINEMODULES,$(JABY_ENGINE_DIR)/include/modules,$(subst !super,..,$1)) + +#Build architecture/variant string, possible values: x86, armv7le, etc... +PLATFORM ?= PSX + +#Build profile, possible values: release, debug, profile, coverage +BUILD_DIR ?= bin/$(PSX_TV_FORMAT) +BUILD_PROFILE ?= debug +PSX_TV_FORMAT ?= PAL + +CONFIG_NAME ?= $(PLATFORM)-$(BUILD_PROFILE) +OUTPUT_DIR = $(BUILD_DIR)/$(CONFIG_NAME) +TARGET = $(OUTPUT_DIR)/$(ARTIFACT) + +#Compiler definitions +HAS_LINUX_MIPS_GCC = $(shell which mipsel-linux-gnu-gcc > /dev/null 2> /dev/null && echo true || echo false) +ifeq ($(HAS_LINUX_MIPS_GCC),true) +PREFIX ?= mipsel-linux-gnu +FORMAT ?= elf32-tradlittlemips +else +PREFIX ?= mipsel-none-elf +FORMAT ?= elf32-littlemips +endif + +#Take this to PSEXETarget.mk?? +#LDSCRIPT ?= $(PSCX_REDUX_DIR)/ps-exe.ld +#ifneq ($(strip $(OVERLAYSCRIPT)),) +#LDSCRIPT := $(addprefix $(OVERLAYSCRIPT) , -T$(LDSCRIPT)) +#else +#LDSCRIPT := $(addprefix $(PSCX_REDUX_DIR)/default.ld , -T$(LDSCRIPT)) +#endif + +CC = $(PREFIX)-gcc +CXX = $(PREFIX)-g++ +LD = $(CXX) +AR = ar + +#architecture flags +ARCHFLAGS = -march=r2000 -mtune=r2000 -mabi=32 -EL -fno-pic -mno-shared -nostdinc -nostdinc++ -mno-abicalls -mfp32 -mno-llsc +ARCHFLAGS += -fno-stack-protector -nostdlib -ffreestanding + +#Compiler flags for build profiles +CCFLAGS_release += -O3 +CCFLAGS_debug += -O0 + +CXXFLAGS += -fno-exceptions -fno-rtti -fno-threadsafe-statics + +CCFLAGS += -mno-gpopt -fomit-frame-pointer -ffunction-sections -fdata-sections +CCFLAGS += -fno-builtin -fno-strict-aliasing -Wno-attributes +CCFLAGS += -std=c++20 -fmodules-ts +CCFLAGS += $(CCFLAGS_$(BUILD_PROFILE)) +CCFLAGS += $(ARCHFLAGS) +CCFLAGS += $(INCLUDES) +CCFLAGS += -DJABYENGINE_$(PSX_TV_FORMAT) + +#Linker flags +LDFLAGS_release += -Os + +LDFLAGS_all += -Wl,-Map=$(TARGET).map -nostdlib -T$(JABY_ENGINE_DIR)/mkfile/psexe.ld -static -Wl,--gc-sections -Wl,--build-id=none -Wl,--no-check-sections +LDFLAGS_all += $(ARCHFLAGS) -Wl,--oformat=$(FORMAT) +LDFLAGS_all += $(LDFLAGS_$(BUILD_PROFILE)) + +LIBS_all += $(LIBS_$(BUILD_PROFILE)) + +DEPS = -Wp,-MMD,$(@:%.o=%.d),-MT,$@ + +#Object files list +MODS += $(call rwildcard,$(JABY_ENGINE_DIR)/include/modules, cxx) +SRCS := $(MODS) $(SRCS) +OBJS = $(addprefix $(OUTPUT_DIR)/,$(addsuffix .o, $(call substitute,$(basename $(SRCS))))) + +#Compiling rule +.SECONDEXPANSION: +$(OUTPUT_DIR)/%.o: $$(call desubstitute,%.s) + @mkdir -p $(dir $@) + $(CC) -c $(DEPS) -o $@ $(CCFLAGS) $< + +.SECONDEXPANSION: +$(OUTPUT_DIR)/%.o: $$(call desubstitute,%.c) + @mkdir -p $(dir $@) + $(CC) -c $(DEPS) -o $@ $(CCFLAGS) $< + +.SECONDEXPANSION: +$(OUTPUT_DIR)/%.o: $$(call desubstitute,%.cpp) + @mkdir -p $(dir $@) + $(CXX) -c $(DEPS) -o $@ $(CCFLAGS) $(CXXFLAGS) $< + +.SECONDEXPANSION: +$(OUTPUT_DIR)/%.o: $$(call desubstitute,%.cxx) + @mkdir -p $(dir $@) + $(CXX) -c $(DEPS) -o $@ $(CCFLAGS) $(CXXFLAGS) $< + +#Inclusion of dependencies (object files to source and includes) +-include $(OBJS:%.o=%.d) \ No newline at end of file diff --git a/mkfile/PSEXETarget.mk b/mkfile/PSEXETarget.mk new file mode 100644 index 00000000..ac315988 --- /dev/null +++ b/mkfile/PSEXETarget.mk @@ -0,0 +1,40 @@ +#Not intended to be overriden +AUTO_OVERLAY_DIR = $(OUTPUT_DIR)/auto_overlay + +include $(AUTO_OVERLAY_DIR)/Overlays.mk +include $(JABY_ENGINE_DIR)/mkfile/common/CustomConfigHelper.mk + +JABY_ENGINE_LIB_DIR = $(JABY_ENGINE_DIR)/lib/PSX-$(BUILD_PROFILE)/$(CUSTOM_CONFIG) +JABY_ENGINE_SUPPORT_LIB_DIR = $(JABY_ENGINE_DIR)/support/lib/PSX-$(BUILD_PROFILE) +JABY_ENGINE_SUPPORT_LIBS = $(addprefix -l,$(SUPPORT_LIBS)) +JABY_ENGINE_SUPPORT_DEPS = $(addsuffix .a,$(addprefix $(JABY_ENGINE_SUPPORT_LIB_DIR)/lib,$(SUPPORT_LIBS))) +JABY_ENGINE_LIB_NAME = JabyEngine_$(PSX_TV_FORMAT) + +OVERLAY_TARGET = $(foreach ovl, $(OVERLAYSECTION), $(OUTPUT_DIR)/Overlay$(ovl)) + +#Linking rule +$(TARGET).elf: $(OBJS) $(JABY_ENGINE_LIB_DIR)/lib$(JABY_ENGINE_LIB_NAME).a $(JABY_ENGINE_SUPPORT_DEPS) $(AUTO_OVERLAY_DIR)/Overlays.ld + $(LD) -o $(TARGET).elf $(LDFLAGS_all) $(LDFLAGS) $(OBJS) -L$(JABY_ENGINE_LIB_DIR) -L$(JABY_ENGINE_SUPPORT_LIB_DIR) -L$(AUTO_OVERLAY_DIR) -l$(JABY_ENGINE_LIB_NAME) $(LIBS) $(JABY_ENGINE_SUPPORT_LIBS) + +#Strips the psexe +$(TARGET).psexe: $(TARGET).elf + $(PREFIX)-objcopy $(addprefix -R , $(OVERLAYSECTION)) -O binary $< $@ + +#Create overlays +$(OVERLAY_TARGET): $(TARGET).elf + $(PREFIX)-objcopy -j $(suffix $@) -O binary $< $@ + +#Create overlay makefile +$(AUTO_OVERLAY_DIR)/Overlays.mk: $(OVERLAY_CONFIG) + @mkdir -p $(AUTO_OVERLAY_DIR) + mkoverlay --mk-file $(AUTO_OVERLAY_DIR)/Overlays.mk --ld-script $(AUTO_OVERLAY_DIR)/Overlays.ld $< + +#Rules section for default compilation and linking +all: $(TARGET).psexe $(OVERLAY_TARGET) + +clean: + rm -fr $(OUTPUT_DIR) + +# For mkoverlay to function correctly this is required (otherwise Overlays.mk is not re-generated) +rebuild: clean + $(MAKE) all diff --git a/mkfile/common/CustomConfigHelper.mk b/mkfile/common/CustomConfigHelper.mk new file mode 100644 index 00000000..35bdb867 --- /dev/null +++ b/mkfile/common/CustomConfigHelper.mk @@ -0,0 +1,4 @@ +JABY_ENGINE_CONFIG_DIR = $(JABY_ENGINE_DIR)config +ifdef CUSTOM_CONFIG + CCFLAGS += -I$(JABY_ENGINE_CONFIG_DIR)/$(CUSTOM_CONFIG) -imacros $(JABY_ENGINE_CONFIG_DIR)/$(CUSTOM_CONFIG)/jabyengine_custom_config.hpp +endif \ No newline at end of file diff --git a/mkfile/common/ExportPath.mk b/mkfile/common/ExportPath.mk new file mode 100644 index 00000000..2cbdb7a7 --- /dev/null +++ b/mkfile/common/ExportPath.mk @@ -0,0 +1,2 @@ +#Add the JabyEngine tools to path +export PATH := $(JABY_ENGINE_DIR)/bin/:$(PATH) \ No newline at end of file diff --git a/mkfile/common/RebuildTarget.mk b/mkfile/common/RebuildTarget.mk new file mode 100644 index 00000000..c26595ee --- /dev/null +++ b/mkfile/common/RebuildTarget.mk @@ -0,0 +1,3 @@ +rebuild: + $(MAKE) clean + $(MAKE) all \ No newline at end of file diff --git a/lib/Wildcard.mk b/mkfile/common/Wildcard.mk similarity index 80% rename from lib/Wildcard.mk rename to mkfile/common/Wildcard.mk index d86f7509..b16caa2e 100644 --- a/lib/Wildcard.mk +++ b/mkfile/common/Wildcard.mk @@ -1,2 +1,2 @@ -#Macro to expand files recursively: parameters $1 - directory, $2 - extension, i.e. cpp +#Macro to expand files recursively: parameters $1 - directory, $2 - extension, i.e. cpp rwildcard = $(wildcard $(addprefix $1/*.,$2)) $(foreach d,$(wildcard $1/*),$(call rwildcard,$d,$2)) \ No newline at end of file diff --git a/lib/psexe.ld b/mkfile/psexe.ld similarity index 66% rename from lib/psexe.ld rename to mkfile/psexe.ld index 2c1638e6..8b672b79 100644 --- a/lib/psexe.ld +++ b/mkfile/psexe.ld @@ -1,242 +1,262 @@ -/* - -MIT License - -Copyright (c) 2019 PCSX-Redux authors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ - -OUTPUT_FORMAT("binary") - -EXTERN(_ZN10JabyEngine5startEv) -ENTRY(_ZN10JabyEngine5startEv) - -TLOAD_ADDR = DEFINED(TLOAD_ADDR) ? TLOAD_ADDR : 0x80010000; - -MEMORY { - loader : ORIGIN = (TLOAD_ADDR - 0x800), LENGTH = 2048 - ram (rwx) : ORIGIN = 0x80010000, LENGTH = 2M - 0x10000 - ram2 (rwx) : ORIGIN = 0x80010000, LENGTH = 2M - 0x10000 - dcache : ORIGIN = 0x1f800000, LENGTH = 0x400 -} - -__ram_top = ORIGIN(ram) + LENGTH(ram); -__sp = __ram_top - 0x100; - -__dcache = ORIGIN(dcache); -__dcache_top = ORIGIN(dcache) + LENGTH(dcache); - -__bss_len = (__bss_end - __bss_start); -__ftext_len = (__ftext_end - __ftext_start); -__fdata_len = (__planschi_end - __fdata_start); -__persistent_lbas_len = (__persistent_lbas_end - __persistent_lbas_start); - -__stack_start = ORIGIN(ram) + LENGTH(ram); - -SECTIONS { - /DISCARD/ : { *(.MIPS.abiflags) } - - /* Everything is statically linked, so discard PLTs. */ - /DISCARD/ : { *(.rel.iplt) *(.rela.iplt) *(.rel.plt) *(.rela.plt) *(.plt) *(.iplt) } - - /* Discard things that the standard link script drops, too. */ - /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.gnu.*) *(.comment) } -} - -/*Overlay sections created by mkoverlay*/ -SECTIONS { - .planschi __bss_end : SUBALIGN(4) - { - __planschi_start = .; - __boot_loader_start = .; - - *libJabyEngine.a:*_boot.o(.text.startup._GLOBAL__*) - *_boot.o(.text.startup._GLOBAL__*) - *libJabyEngine.a:*_boot.o(.ctors) - *_boot.o(.ctors) - - *libJabyEngine.a:*_boot.o(.text.*) - *_boot.o(.text.*) - *libJabyEngine.a:*_boot.o(.rodata*) - *_boot.o(.rodata*) - *libJabyEngine.a:*_boot.o(.sdata*) - *_boot.o(.sdata*) - *libJabyEngine.a:*_boot.o(.data*) - *_boot.o(.data*) - *libJabyEngine.a:*_boot.o(.sbss*) - *_boot.o(.sbss*) - *libJabyEngine.a:*_boot.o(.bss*) - *_boot.o(.bss*) - *libJabyEngine.a:*_boot.o(*) - *_boot.o(*) - - . = ALIGN(4); - __boot_loader_end = .; - /*Only needed for the PSX BIOS to load the entire game*/ - . = ALIGN(2048); - __planschi_end = .; - } -} - -SECTIONS { - .PSX_EXE_Header : { - /* - 0x0000 - 0x0007 : "PS-X EXE" - */ - BYTE(80); BYTE(83); BYTE(45); BYTE(88); BYTE(32); BYTE(69); BYTE(88); BYTE(69); - - /* 0x0008 - 0x000F : skip text_off and data_off since they're not supported by the PS1 BIOS */ - LONG(0); LONG(0); - - /* 0x0010 - 0x0013 : entry point */ - LONG(ABSOLUTE(_ZN10JabyEngine5startEv)); - - /* 0x0014 - 0x0017 : initial value of $gp */ - LONG(0); - - /* 0x0018 - 0x001B : Memory address to load "text" section to. */ - /* - NOTE: The "text" section is actually all of the "load" - sections of the file including .text, .rodata, .data. - etc. - */ - LONG(TLOAD_ADDR); - - /* 0x001C - 0x001F : size, in bytes, of the "text" section. */ - LONG(__persistent_lbas_len + __ftext_len + __fdata_len); - - /* 0x0020 - 0x002F : - Skip "data_addr", "data_size", "bss_addr" and "bss_size". - None of these are supported by retail PS1 BIOS. - */ - LONG(0); LONG(0); - LONG(0); LONG(0); - - /* 0x0030 - 0x0033 : Initial stack address. */ - LONG(DEFINED(_sp) ? ABSOLUTE(_sp) : 0x801FFF00); - - /* 0x0034 - 0x0037 : Initial stack size, set it to 0. */ - LONG(0); - - /* Skip the remaining fields as they're not supported by the BIOS */ - /* e.g. 2048 header bytes minus whatever we've actually used */ - . = . + 1992; - } > loader - - __persistent_lbas_start = ABSOLUTE(.); - .persistent_lbas TLOAD_ADDR : { - __persistent_lbas = .; - KEEP(*(.header.lbas)) - } > ram - . = ALIGN(4); - __persistent_lbas_end = ABSOLUTE(.); - - __ftext_start = ABSOLUTE(.); - .text : { - *(.start) - *(.init) - KEEP (*(SORT_NONE(.fini))) - *(.text.unlikely .text.*_unlikely .text.unlikely.*) - *(.text.exit .text.exit.*) - *(.text.startup .text.startup.*) - *(.text.hot .text.hot.*) - *(.text .stub .text.* .gnu.linkonce.t.*) - - . = ALIGN(16); - KEEP(*(.init)) - . = ALIGN(16); - KEEP(*(.fini)) - } > ram - - . = ALIGN(16); - __text_end = .; - __ftext_end = ABSOLUTE(.); - - __fdata_start = ABSOLUTE(.); - - .rodata : { - *(.rodata .rodata.* .rdata .rdata.* .gnu.linkonce.r.*) - . = ALIGN(16); - __preinit_array_start = .; - KEEP (*(.preinit_array)) - __preinit_array_end = .; - - . = ALIGN(16); - __init_array_start = .; - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - - . = ALIGN(16); - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*crtend.o(.ctors)) - __init_array_end = .; - - . = ALIGN(16); - __fini_array_start = .; - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*crtend.o(.dtors)) - __fini_array_end = .; - __build_id = .; - *(.note.gnu.build-id) - __build_id_end = .; - } > ram - - .rodata1 : { - *(.rodata1) - } > ram - - __data_start = .; - .data : { - *(.a0table) - *(.data .data.* .gnu.linkonce.d.*) - *(.data1) - *(.sdata .sdata.* .gnu.linkonce.s.*) - *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) - *(.got.plt) - *(.got) - } > ram - - __data_end = .; - __fdata_end = .; - __bss_start = .; - .bss : { - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - } > ram - - . = ALIGN(4); - __bss_end = .; - __heap_start = __heap_base; - - . = ADDR(.text) - 0x800; - __end = .; -} +/* + +MIT License + +Copyright (c) 2019 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +OUTPUT_FORMAT("binary") +EXTERN(_ZN10JabyEngine5startEv) +ENTRY(_ZN10JabyEngine5startEv) + +TLOAD_ADDR = DEFINED(TLOAD_ADDR) ? TLOAD_ADDR : 0x80010000; + +MEMORY { + zero : ORIGIN = 0x0 LENGTH = 0x100 + bios : ORIGIN = 0x100, LENGTH = 0x500 + loader : ORIGIN = (TLOAD_ADDR - 0x800), LENGTH = 2048 + ram(rwx) : ORIGIN = 0x80010000, LENGTH = 2M - 0x10000 + ram_alt(rwx) : ORIGIN = 0x80010000, LENGTH = 2M - 0x10000 + dcache : ORIGIN = 0x1f800000, LENGTH = 0x400 +} + +__ram_top = ORIGIN(ram) + LENGTH(ram); +__sp = __ram_top - 0x100; + +__dcache = ORIGIN(dcache); +__dcache_top = ORIGIN(dcache) + LENGTH(dcache); + +__bss_len = (__bss_end - __bss_start); +__ftext_len = (__ftext_end - __ftext_start); +__fdata_len = (__planschi_end - __fdata_start); +__persistent_lbas_len = (__persistent_lbas_end - __persistent_lbas_start); + +__stack_start = ORIGIN(ram) + LENGTH(ram); + + +SECTIONS { + .zero (NOLOAD) : { + _ZN10JabyEngine3SPU5voiceE = .; + } > zero + + .bios (NOLOAD) : { + _ZN10JabyEngine15table_of_tablesE = .; + } > bios + + /DISCARD/ : { *(.MIPS.abiflags) } + + /* Everything is statically linked, so discard PLTs. */ + /DISCARD/ : { *(.rel.iplt) *(.rela.iplt) *(.rel.plt) *(.rela.plt) *(.plt) *(.iplt) } + + /* Discard things that the standard link script drops, too. */ + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.gnu.*) *(.comment) } +} + +/*Overlay sections created by mkoverlay*/ +INCLUDE Overlays.ld +SECTIONS { + .planschi __engine_bss_end : SUBALIGN(4) + { + __planschi_start = .; + __boot_loader_start = .; + + *libJabyEngine_*.a:*_boot.o(.text.startup._GLOBAL__*) + *_boot.o(.text.startup._GLOBAL__*) + *libJabyEngine_*.a:*_boot.o(.ctors) + *_boot.o(.ctors) + + *libJabyEngine_*.a:*_boot.o(.text.*) + *_boot.o(.text.*) + *libJabyEngine_*.a:*_boot.o(.rodata*) + *_boot.o(.rodata*) + *libJabyEngine_*.a:*_boot.o(.sdata*) + *_boot.o(.sdata*) + *libJabyEngine_*.a:*_boot.o(.data*) + *_boot.o(.data*) + *libJabyEngine_*.a:*_boot.o(.sbss*) + *_boot.o(.sbss*) + *libJabyEngine_*.a:*_boot.o(.bss*) + *_boot.o(.bss*) + *libJabyEngine_*.a:*_boot.o(*) + *_boot.o(*) + + . = ALIGN(4); + __boot_loader_end = .; + /*Only needed for the PSX BIOS to load the entire game*/ + . = ALIGN(2048); + __planschi_end = .; + } > ram +} + +SECTIONS { + .PSX_EXE_Header : { + /* + 0x0000 - 0x0007 : "PS-X EXE" + */ + BYTE(80); BYTE(83); BYTE(45); BYTE(88); BYTE(32); BYTE(69); BYTE(88); BYTE(69); + + /* 0x0008 - 0x000F : skip text_off and data_off since they're not supported by the PS1 BIOS */ + LONG(0); LONG(0); + + /* 0x0010 - 0x0013 : entry point */ + LONG(ABSOLUTE(_ZN10JabyEngine5startEv)); + + /* 0x0014 - 0x0017 : initial value of $gp */ + LONG(0); + + /* 0x0018 - 0x001B : Memory address to load "text" section to. */ + /* + NOTE: The "text" section is actually all of the "load" + sections of the file including .text, .rodata, .data. + etc. + */ + LONG(TLOAD_ADDR); + + /* 0x001C - 0x001F : size, in bytes, of the "text" section. */ + LONG(__persistent_lbas_len + __ftext_len + __fdata_len); + + /* 0x0020 - 0x002F : + Skip "data_addr", "data_size", "bss_addr" and "bss_size". + None of these are supported by retail PS1 BIOS. + */ + LONG(0); LONG(0); + LONG(0); LONG(0); + + /* 0x0030 - 0x0033 : Initial stack address. */ + LONG(DEFINED(_sp) ? ABSOLUTE(_sp) : 0x801FFF00); + + /* 0x0034 - 0x0037 : Initial stack size, set it to 0. */ + LONG(0); + + /* Skip the remaining fields as they're not supported by the BIOS */ + /* e.g. 2048 header bytes minus whatever we've actually used */ + . = . + 1992; + } > loader + + .persistent_lbas TLOAD_ADDR : { + __persistent_lbas_start = .; + __persistent_lbas = .; + KEEP(*(.header.lbas)) + . = ALIGN(4); + __persistent_lbas_end = .; + } > ram + + __ftext_start = ABSOLUTE(.); + .text : { + __text_start = .; + *(.start) + *(.init) + KEEP (*(SORT_NONE(.fini))) + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(.text .stub .text.* .gnu.linkonce.t.*) + + . = ALIGN(16); + KEEP(*(.init)) + . = ALIGN(16); + KEEP(*(.fini)) + . = ALIGN(16); + __text_end = .; + } > ram + __ftext_end = ABSOLUTE(.); + + __fdata_start = ABSOLUTE(.); + .rodata : { + *(.rodata .rodata.* .rdata .rdata.* .gnu.linkonce.r.*) + . = ALIGN(16); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + + . = ALIGN(16); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + + . = ALIGN(16); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + __init_array_end = .; + + . = ALIGN(16); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + __fini_array_end = .; + __build_id = .; + *(.note.gnu.build-id) + __build_id_end = .; + } > ram + + .rodata1 : { + *(.rodata1) + } > ram + + .data : { + __data_start = .; + *(.a0table) + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + *(.got.plt) + *(.got) + __data_end = .; + } > ram + + .engine_bss : { + __engine_bss_start = .; + *libJabyEngine_*.a:*(.dynsbss) + *libJabyEngine_*.a:*(.sbss .sbss.* .gnu.linkonce.sb.*) + *libJabyEngine_*.a:*(.scommon) + *libJabyEngine_*.a:*(.dynbss) + *libJabyEngine_*.a:*(.bss .bss.* .gnu.linkonce.b.*) + *libJabyEngine_*.a:*(COMMON) + . = ALIGN(4); + __engine_bss_end = .; + } > ram + __fdata_end = .; + + .bss __persistent_overlay_end (NOLOAD) : { + __bss_start = .; + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + __bss_end = .; + } > ram + + __heap_start = __bss_end; + __end = .; +} \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 00000000..70c32237 --- /dev/null +++ b/readme.md @@ -0,0 +1,71 @@ +- [JabyEngine](#jabyengine) + - [About](#about) + - [How to build](#how-to-build) + - [Building `JabyEngine` (without VSCode)](#building-jabyengine-without-vscode) + - [Building support library (without VSCode)](#building-support-library-without-vscode) + - [`FontWriter` (without VSCode)](#fontwriter-without-vscode) + - [Building `PoolBox` (without VSCode)](#building-poolbox-without-vscode) +- [Media creators](#media-creators) + - [JabyEngine](#jabyengine-1) + - [PoolBox](#poolbox) +- [Special thanks](#special-thanks) + +# JabyEngine +## About +JabyEngine is my personal attempt to eventually make my own PS1 game from "ground up". Originally I didn't indented to release this code publicly but recently I decided to give it a try. If you read this, thank you! + +## How to build +JabyEngine relies on linux to be build. For Windows users it uses `wsl` instead but support for it might get dropped during further development. + +The following environment variables should be set: +* `JABY_ENGINE_PATH`: The path to the root folder of this repo +* `PSX_LICENSE_PATH`: The path to a folder containing the PS1 licenses for generating a CD. + +### Building `JabyEngine` (without VSCode) +`make` requires the following values to be passed: +* `BUILD_PROFILE`: `debug`/`release` +* `PSX_TV_FORMAT`: `PAL`/`NTSC` +* `CUSTOM_CONFIG`: Empty or folder name under `./config` + +### Building support library (without VSCode) +These projects shall eventually turn into useful extensions for the engine. So far they are more tests then proper code. However `PoolBox` is depended on `FontWriter`. + +#### `FontWriter` (without VSCode) +`make` requires the following values to be passed: +* `BUILD_PROFILE`: `debug`/`release` + +### Building `PoolBox` (without VSCode) +`PoolBox` is the one and only example project so far. +`make` requires the following values to be passed: +* `BUILD_PROFILE`: `debug`/`release` +* `REGION`: `SCEE`/`SCEA`/`SCEI` +* `CUSTOM_CONFIG`: Empty or folder name under `$(JABY_ENGINE_PATH)/config` + + +# Media creators +## JabyEngine +| Art | Author | +|-----------------------------------------------------------------|--------| +| `ressources\Splash_ntsc.png`
`ressources\Splash_ntsc.png` | Niuka | + +## PoolBox +| Art | Author | +|-----------------------------------------------------------------|-------------| +| `examples\PoolBox\assets\AllTheJaby.png` | Niuka | +| `examples\PoolBox\assets\IconTexture.png` | Charlie Nax | +| `examples\PoolBox\assets\Paco.png` | Paco | + +| Music | Author | +|---------------------------------------------------------------------------|---------------------------------------| +| `examples\PoolBox\assets\audio\apple.wav` | ??? | +| `examples\PoolBox\assets\audio\blubb-mono.wav` | ??? | +| `examples\PoolBox\assets\audio\Evacuation_cdda.wav` | Cody the white tiger | +| `examples\PoolBox\assets\audio\Friendship_samp.wav` | From Dragon Quest VII | +| `examples\PoolBox\assets\audio\jlbrock44_Three_Kings_Funk_cdda_ready.wav` | `Three Kings Funk` by spinningmerkaba | +| `examples\PoolBox\assets\audio\OnMyOwn_BailBonds.mp3` | `On My Own` by Bail Bonds | + +# Special thanks +* Cody the white tiger +* Nicolas Noble +* Pyravia +* Sickle \ No newline at end of file diff --git a/src/Library/Library.code-workspace b/src/Library/Library.code-workspace index 31e78c26..afb872fc 100644 --- a/src/Library/Library.code-workspace +++ b/src/Library/Library.code-workspace @@ -1,74 +1,113 @@ -{ - "folders": [ - { - "name": "JabyEngine", - "path": ".", - }, - { - "name": "Include", - "path": "..\\..\\include" - }, - { - "name": "Root", - "path": "..\\.." - } - ], - "tasks": { - "version": "2.0.0", - "tasks": [ - { - "label": "make", - "type": "shell", - "command": "./run_make.bat ${input:target} ${input:build cfg}", - "group": "build" - }, - { - "label": "Build Libary and Tools", - "type": "shell", - "command": "./build_all.bat ${input:target}", - "group": "build", - "options": { - "cwd": "../.." - } - }, - ], - "inputs": [ - { - "id": "build cfg", - "type": "pickString", - "options": ["debug", "release"], - "default": "release", - "description": "build configuration" - }, - { - "id": "target", - "type": "pickString", - "options": ["build", "clean", "rebuild"], - "default": "build", - "description": "build target", - } - ] - }, - "settings": { - "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" - ], - "files.exclude": { - "**/*.o": true, - "**/*.dep": true - }, - "files.associations": { - "stdio.h": "c" - } - } +{ + "folders": [ + { + "name": "JabyEngine", + "path": ".", + }, + { + "name": "Include", + "path": "..\\..\\include" + }, + { + "name": "Root", + "path": "..\\.." + } + ], + "tasks": { + "version": "2.0.0", + "tasks": [ + { + "label": "make", + "type": "shell", + "windows": { + "command": "wsl make ${input:target} BUILD_PROFILE=${input:build cfg} PSX_TV_FORMAT=${input:tv format} CUSTOM_CONFIG=${input:config options}", + }, + "linux": { + "command": "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", + "windows": { + "command": "wsl make -f MakeAll.mk ${input:target prefix}_${input:target} BUILD_PROFILE=${input:build cfg} CUSTOM_CONFIG=${input:config options}", + }, + "linux": { + "command": "make -f MakeAll.mk ${input:target} BUILD_PROFILE=${input:build cfg}", + }, + "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 ^|^ && dir /b /a: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"] + }, + "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" + } + } } \ No newline at end of file diff --git a/src/Library/MakeAll.mk b/src/Library/MakeAll.mk new file mode 100644 index 00000000..962c404e --- /dev/null +++ b/src/Library/MakeAll.mk @@ -0,0 +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: + $(call make_all,rebuild,$(config_files)) \ No newline at end of file diff --git a/src/Library/Makefile b/src/Library/Makefile index 4183fabe..1f9114db 100644 --- a/src/Library/Makefile +++ b/src/Library/Makefile @@ -1,49 +1,51 @@ -JABY_ENGINE_DIR = ../../ - -ARTIFACT = libJabyEngine_$(TV_FORMAT) -BUILD_DIR = bin - -SPLASH_IMAGE = src/BootLoader/splash_image_pal_boot.hpp -SPLASH_IMAGE_NTSC = src/BootLoader/splash_image_ntsc_boot.hpp - -CCFLAGS += -Iinclude -I../../include -CCFLAGS += -save-temps=obj - -include ../../lib/Wildcard.mk -SRCS = $(call rwildcard, src, c cpp) -SRCS += src/syscall_printf.asm - -include ../../lib/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 - -# Improve later -# rule to make the boot image -$(SPLASH_IMAGE): ressources/Splash.png - jaby_engine_fconv --lz4 $< simple-tim full16 | cpp_out --name SplashScreen -o $@ - -$(SPLASH_IMAGE_NTSC): ressources/Splash_ntsc.png - jaby_engine_fconv --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) +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 \ No newline at end of file diff --git a/src/Library/internal-include/BootLoader/boot_loader.hpp b/src/Library/internal-include/BootLoader/boot_loader.hpp index 888c1b54..49b5a6ea 100644 --- a/src/Library/internal-include/BootLoader/boot_loader.hpp +++ b/src/Library/internal-include/BootLoader/boot_loader.hpp @@ -1,18 +1,34 @@ -#ifndef BOOT_LOADER_HPP -#define BOOT_LOADER_HPP +#pragma once +#include "color_debug.hpp" #include namespace JabyEngine { namespace boot { + namespace BIOS { + void identify(); + } + + namespace Callbacks { + void setup(); + } + namespace CD { void setup(); } + namespace DMA { + void setup(); + } + namespace GPU { void display_logo(); void setup(); } + namespace GTE { + void setup(); + } + namespace SPU { void stop_voices(); void setup(); @@ -21,8 +37,11 @@ namespace JabyEngine { namespace Timer { void setup(); } + + namespace Periphery { + void setup(); + } } - void __no_return run(); -} -#endif //!BOOT_LOADER_HPP \ No newline at end of file + void __no_return run(); +} \ No newline at end of file diff --git a/src/Library/internal-include/BootLoader/color_debug.hpp b/src/Library/internal-include/BootLoader/color_debug.hpp new file mode 100644 index 00000000..56b35b49 --- /dev/null +++ b/src/Library/internal-include/BootLoader/color_debug.hpp @@ -0,0 +1,30 @@ +#pragma once +#include "../GPU/gpu_internal.hpp" +#include + +namespace JabyEngine { + static void render_num(uint8_t value, uint16_t x, uint16_t y) { + static constexpr auto BitCount = 8; + + for(size_t n = 0; n < BitCount; n++) { + const uint16_t sub_x = (16*((BitCount - 1) - n)); + const uint16_t sub_y = (n&1)*16; + + GPU::internal::quick_fill_fast((value & (1 << n)) ? GPU::Color24::Blue() : GPU::Color24::Red(), GPU::AreaU16::create(GPU::PositionU16::create((x + sub_x), (y + sub_y)), GPU::SizeU16::create(16, 16))); + } + } + +#ifdef __USE_DEBUG_COLOR__ + #define __debug_boot_color_at(color, x, y, scale) { \ + ::JabyEngine::GPU::internal::quick_fill_fast(color, ::JabyEngine::GPU::AreaU16::create(64*x, 64*y, static_cast(64*scale), static_cast(64*scale))); \ + } + + #define __debug_boot_print_at(color, x, y, scale, ...) { \ + __debug_boot_color_at(color, x, y, scale); \ + printf(__VA_ARGS__); \ + } +#else + #define __debug_boot_color_at(...) + #define __debug_boot_print_at(color, x, y, scale, ...) printf(__VA_ARGS__) +#endif // __USE_DEBUG_COLOR__ +} \ No newline at end of file diff --git a/src/Library/internal-include/CD/cd_internal.hpp b/src/Library/internal-include/CD/cd_internal.hpp index aad04e32..3d451007 100644 --- a/src/Library/internal-include/CD/cd_internal.hpp +++ b/src/Library/internal-include/CD/cd_internal.hpp @@ -1,42 +1,67 @@ -#ifndef __JABYENGINE_CD_INTERNAL_HPP__ -#define __JABYENGINE_CD_INTERNAL_HPP__ +#pragma once #include "cd_types.hpp" +#include + +#include +#include namespace JabyEngine { namespace CD { namespace internal { - extern State current_state; - extern CD_IO::Interrupt::Type last_interrupt; - extern uint8_t cmd_interrupt_bit; + struct File { + uint32_t cur_lba; + uint32_t dst_lba; + + void set_from(const AutoLBAEntry& file_info) { + this->cur_lba = file_info.get_lba(); + this->dst_lba = this->cur_lba + file_info.get_size_in_sectors(); + } + + bool done_processing() { + this->cur_lba++; + return this->cur_lba == this->dst_lba; + } + }; + + enum struct State { + Ready = 0, + Done = 0, + + XAMode, + + Reading, + BufferFull, + Error, + }; + + extern State current_state; + extern uint8_t irq_bit_pending; struct Command { static void wait_completed() { - while(const_cast(cmd_interrupt_bit) > 0); + while(const_cast(irq_bit_pending)); } template - static void send(CD_IO::CommandFifo_v& cmd_fifo, CD_IO::ParameterFifo_v& parameter_fifo, CD_IO::Command::Desc cmd, ARGS...args) { - while(CD_IO::IndexStatus.is_set(CD_IO::IndexStatus_t::IsTransmissionBusy)); + static void send_no_wait(CD_IO::Command::Desc cmd, ARGS...args) { + while(CD_IO::IndexStatus.read().is_set(CD_IO_Values::IndexStatus::IsTransmissionBusy)); - ((parameter_fifo = args),...); - cmd_fifo = cmd.id; - cmd_interrupt_bit = bit::set(0, cmd.complete_irq); + irq_bit_pending = bit::set(irq_bit_pending, cmd.complete_irq); + CD_IO::PortIndex0::change_to(); + ((CD_IO::PortIndex0::ParameterFifo.write(CD_IO_Values::ParameterFifo{args})),...); + CD_IO::PortIndex0::CommandFifo.write(CD_IO_Values::CommandFifo{cmd.id}); } - template + template static void send(CD_IO::Command::Desc cmd, ARGS...args) { - send(T::CommandFifo, T::ParameterFifo, cmd, args...); + Command::wait_completed(); + Command::send_no_wait(cmd, args...); } template - static void send_wait(CD_IO::CommandFifo_v& cmd_fifo, CD_IO::ParameterFifo_v& parameter_fifo, CD_IO::Command::Desc cmd, ARGS...args) { - send(cmd_fifo, parameter_fifo, cmd, args...); - wait_completed(); - } - - template - static void send_wait(CD_IO::Command::Desc cmd, ARGS...args) { - send_wait(T::CommandFifo, T::ParameterFifo, cmd, args...); + static void send_wait_response(CD_IO::Command::Desc cmd, ARGS...args) { + Command::send(cmd, args...); + Command::wait_completed(); } }; @@ -45,8 +70,32 @@ namespace JabyEngine { } void read_file(AutoLBAEntry file_info, const SectorBufferAllocator& buffer_allocator); + void end_read_file(); void continue_reading(); + + void copy_from_sector(uint32_t* dst, size_t bytes); + template + T copy_from_sector() { + T data; + + copy_from_sector(reinterpret_cast(&data), sizeof(T)); + return data; + } + + BCDTimeStamp get_loc(); + BCDTimeStamp get_locL(); + + void enable_CD(); + void enable_CDDA(); + void enable_CDXA(bool double_speed); + + static void set_loc(const BCDTimeStamp& cd_time) { + Command::send_no_wait(CD_IO::Command::SetLoc, cd_time.min, cd_time.sec, cd_time.sector); + } + + static void pause() { + Command::send(CD_IO::Command::Pause); + } } } -} -#endif //!__JABYENGINE_CD_INTERNAL_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/src/Library/internal-include/CD/cd_types.hpp b/src/Library/internal-include/CD/cd_types.hpp index 5e1f07d6..58d8aa11 100644 --- a/src/Library/internal-include/CD/cd_types.hpp +++ b/src/Library/internal-include/CD/cd_types.hpp @@ -1,20 +1,38 @@ -#ifndef __JABYENGINE_INTERNAL_CD_TYPES_HPP__ -#define __JABYENGINE_INTERNAL_CD_TYPES_HPP__ +#pragma once #include #include #include -#include +#include namespace JabyEngine { namespace CD { - namespace internal { - enum struct State { - Free = 0, - Done = 0, + using BCD = uint8_t; + using CodingInfo = uint8_t; + using Mode = uint8_t; + using SubMode = uint8_t; - Reading, - BufferFull, - Error, + struct Header { + BCD minute; + BCD second; + BCD sector; + Mode mode; + }; + + struct SubHeader { + uint8_t file_number; + uint8_t channel_number; + SubMode sub_mode; + CodingInfo coding_info; + }; + + namespace internal { + struct RawXADataSector { + Header header; + SubHeader sub_header; + /*SubHeader copy_sub_header; + uint8_t data[0x800]; + uint32_t edc; + uint8_t ecc[0x114];*/ }; class SectorBufferAllocator { @@ -40,11 +58,14 @@ namespace JabyEngine { } inline CD_IO::DataSector* allocate_sector() const { - return this->allocate(this->ctx); + if(this->allocate) { + return this->allocate(this->ctx); + } + return nullptr; } }; - struct CDTimeStamp { + struct BCDTimeStamp { static constexpr size_t MaxSector = 75; static constexpr size_t MaxSeconds = 60; @@ -52,26 +73,21 @@ namespace JabyEngine { uint8_t sec; uint8_t sector; - static constexpr CDTimeStamp from(uint32_t lba) { + static constexpr BCDTimeStamp from_time(uint8_t min, uint8_t sec, uint8_t sectors) { + return BCDTimeStamp{.min = to_bcd(min), .sec = to_bcd(sec), .sector = to_bcd(sectors)}; + } + + static constexpr BCDTimeStamp from(uint32_t lba) { const auto [min, new_lba] = div_and_mod(lba, MaxSector*MaxSeconds); const auto [sec, sectors] = div_and_mod(new_lba, MaxSector); - return CDTimeStamp{static_cast(min), static_cast(sec), static_cast(sectors)}; + return BCDTimeStamp::from_time(min, sec, sectors); } - constexpr uint8_t get_min_cd() const { - return to_bcd(this->min); - } - - constexpr uint8_t get_sec_cd() const { - return to_bcd(this->sec); - } - - constexpr uint8_t get_sector_cd() const { - return to_bcd(this->sector); + constexpr bool is_zero() const { + return this->min == 0 && this->sec == 0 && this->sector == 0; } }; } } -} -#endif //!__JABYENGINE_INTERNAL_CD_TYPES_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/src/Library/internal-include/GPU/gpu_internal.hpp b/src/Library/internal-include/GPU/gpu_internal.hpp index 9903400b..2eb72ee5 100644 --- a/src/Library/internal-include/GPU/gpu_internal.hpp +++ b/src/Library/internal-include/GPU/gpu_internal.hpp @@ -1,5 +1,4 @@ -#ifndef __JABYENGINE_GPU_INTERNAL_HPP__ -#define __JABYENGINE_GPU_INTERNAL_HPP__ +#pragma once #include #include #include @@ -7,81 +6,113 @@ namespace JabyEngine { namespace GPU { namespace internal { - struct Screen { - static void configurate() { - static constexpr uint16_t FirstVisiblePixelH = 0x260; + struct Display { + typedef ::JabyEngine::GPU::Display PublicDisplay; - #ifdef JABYENGINE_PAL - static constexpr uint16_t FirstVisiblePixelV = 0xA3; + static constexpr auto Width = PublicDisplay::Width; + static constexpr auto Height = PublicDisplay::Height; + + #ifdef JABYENGINE_PAL + static constexpr auto DisplayMode = GPU_IO_Values::DisplayMode::PAL(); + static constexpr uint16_t ScanlinesV = 288; + static constexpr auto DisplayRange = PositionI16::create(78, 35); + #else + static constexpr auto DisplayMode = GPU_IO_Values::DisplayMode::NTSC(); + static constexpr uint16_t ScanlinesV = 240; + static constexpr auto DisplayRange = PositionI16::create(76, 16); + #endif //JABYENGINE_PAL - GPU_IO::GP1 = GPU_IO::Command::DisplayMode(GPU_IO::DisplayMode_t::PAL()); - GPU::Screen::set_offset(0, 0); - #else - static constexpr uint16_t FirstVisiblePixelV = 0x88; - - GPU_IO::GP1 = GPU_IO::Command::DisplayMode(GPU_IO::DisplayMode_t::NTSC()); - GPU::Screen::set_offset(0, 5); //< Random values - #endif - } - - static void exchange_buffer_and_display(); + static uint32_t exchange_buffer_and_display(); }; + extern bool vsync_lock_callback; - static void set_draw_area(uint16_t x, uint16_t y) { - GPU_IO::GP0 = GPU_IO::Command::DrawAreaTopLeft(x, y); - GPU_IO::GP0 = GPU_IO::Command::DrawAreaBottomRight((x + Display::Width), (y + Display::Height)); + void wait_vsync(uint8_t syncs); + + static void wait_ready_for_CMD() { + GPU::wait_for_render(); } - static void quick_fill_fast(const Color24& color, const PositionU16& pos, const SizeU16& size) { - GPU_IO::GP0 = GPU_IO::Command::QuickFill(color); - GPU_IO::GP0 = GPU_IO::Command::TopLeftPosition(pos.x, pos.y); - GPU_IO::GP0 = GPU_IO::Command::WidthHeight(size.width, size.height); + static void set_draw_area(const PositionU16& pos) { + wait_ready_for_CMD(); + GPU_IO::GP0.set_draw_area_top_left(pos); + wait_ready_for_CMD(); + GPU_IO::GP0.set_draw_area_bottom_right(pos.move((Display::Width - 1), (Display::Height - 1))); + } + + static void copy_vram_to_vram(const AreaU16& dst, const PositionU16& src) { + wait_ready_for_CMD(); + GPU_IO::GP0.set_vram2vram_blitting(); + GPU_IO::GP0.pass_top_left_position(src); + GPU_IO::GP0.pass_top_left_position(dst.position); + GPU_IO::GP0.pass_width_height(dst.size); + } + + static void quick_fill_fast(const Color24& color, const AreaU16& area) { + wait_ready_for_CMD(); + GPU_IO::GP0.quick_fill(color); + GPU_IO::GP0.pass_top_left_position(area.position); + GPU_IO::GP0.pass_width_height(area.size); + } + + static void set_draw_offset(const PositionI16& offset) { + wait_ready_for_CMD(); + GPU_IO::GP0.set_draw_offset(offset); } static void reset_cmd_buffer() { - GPU_IO::GP1 = GPU_IO::Command::ResetCMDBufer(); + GPU_IO::GP1.reset_cmd_buffer(); } - static void wait_ready_for_CMD() { - while(!GPU_IO::GPUSTAT.is_set(GPU_IO::GPUSTAT_t::GP0ReadyForCMD)); - } + struct DMA { + #ifdef __SUPPORT_PS3__ + // The PS3 doesn't autoincrement the GPU MADR register so we have to do it + static uintptr_t MADR; + #endif // __SUPPORT_PS3__ - namespace DMA { static void wait() { - ::JabyEngine::DMA_IO::GPU.wait(); + DMA_IO::GPU.wait(); + vsync_lock_callback = false; } static void end() { reset_cmd_buffer(); + vsync_lock_callback = false; } - namespace Receive { + struct Receive { static void prepare() { - GPU_IO::GP1 = GPU_IO::Command::DMADirection(GPU_IO::DMADirection::CPU2GPU); + GPU_IO::GP1.set_dma_direction(GPU_IO_Values::GPUSTAT::DMADirection::CPU2GPU); reset_cmd_buffer(); } static void set_src(uintptr_t adr) { - DMA_IO::GPU.set_adr(adr); + #ifdef __SUPPORT_PS3__ + DMA::MADR = adr; + #else + DMA_IO::GPU.set_adr(adr); + #endif // __SUPPORT_PS3__ } static void set_dst(const PositionU16& position, const SizeU16& size) { wait_ready_for_CMD(); - GPU_IO::GP0 = GPU_IO::Command::CPU2VRAM_Blitting(); - GPU_IO::GP0 = GPU_IO::Command::TopLeftPosition(position.x, position.y); - GPU_IO::GP0 = GPU_IO::Command::WidthHeight(size.width, size.height); + GPU_IO::GP0.set_cpu2vram_blitting(); + GPU_IO::GP0.pass_top_left_position(position); + GPU_IO::GP0.pass_width_height(size); } static void start(uint16_t blockCount, uint16_t wordsPerBlock = 0x10) { - typedef DMA_IO::BCR_t::SyncMode1 SyncMode1; + using SyncMode1 = DMA_IO_Values::BCR::SyncMode1; - DMA_IO::GPU.block_ctrl = DMA_IO::BCR_t::from(SyncMode1::BlockSize.with(wordsPerBlock), SyncMode1::BlockAmount.with(blockCount)); - DMA_IO::GPU.channel_ctrl = DMA_IO::CHCHR_t::StartGPUReceive(); + vsync_lock_callback = true; + #ifdef __SUPPORT_PS3__ + DMA_IO::GPU.set_adr(MADR); + DMA::MADR += (blockCount * wordsPerBlock) << 2; + #endif // __SUPPORT_PS3__ + DMA_IO::GPU.block_ctrl.write(DMA_IO_Values::BCR::from(SyncMode1::BlockSize.with(wordsPerBlock), SyncMode1::BlockAmount.with(blockCount))); + DMA_IO::GPU.channel_ctrl.write(DMA_IO_Values::CHCHR::StartGPUReceive()); } - } - } + }; + }; } } -} - -#endif //!__JABYENGINE_GPU_INTERNAL_HPP__ \ No newline at end of file +} \ No newline at end of file diff --git a/src/Library/internal-include/SPU/spu_internal.hpp b/src/Library/internal-include/SPU/spu_internal.hpp new file mode 100644 index 00000000..dc2c7120 --- /dev/null +++ b/src/Library/internal-include/SPU/spu_internal.hpp @@ -0,0 +1,44 @@ +#pragma once +#include +#include + +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()); + } + }; + }; + } + } +} diff --git a/src/Library/internal-include/SPU/spu_mmu.hpp b/src/Library/internal-include/SPU/spu_mmu.hpp new file mode 100644 index 00000000..58103f4e --- /dev/null +++ b/src/Library/internal-include/SPU/spu_mmu.hpp @@ -0,0 +1,9 @@ +#pragma once +#include + +namespace JabyEngine { + namespace SPU_MMU { + const uint8_t* allocate(uint8_t voice, size_t size); + void deallocate(uint8_t voice); + } +} \ No newline at end of file diff --git a/src/Library/internal-include/System/callbacks_internal.hpp b/src/Library/internal-include/System/callbacks_internal.hpp new file mode 100644 index 00000000..590fe80e --- /dev/null +++ b/src/Library/internal-include/System/callbacks_internal.hpp @@ -0,0 +1,51 @@ +#pragma once +#include "threads.hpp" +#include + +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); + } + } + } + } +} diff --git a/src/Library/internal-include/System/threads.hpp b/src/Library/internal-include/System/threads.hpp new file mode 100644 index 00000000..22f7450b --- /dev/null +++ b/src/Library/internal-include/System/threads.hpp @@ -0,0 +1,55 @@ +#pragma once +#include + +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 + static Handle create(void(*function)(uint32_t), uint32_t(&stack)[N]) { + return SysCall::OpenThread(reinterpret_cast(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; + } + }; +} \ No newline at end of file diff --git a/src/Library/internal-include/mipscalls.hpp b/src/Library/internal-include/mipscalls.hpp new file mode 100644 index 00000000..2a74af18 --- /dev/null +++ b/src/Library/internal-include/mipscalls.hpp @@ -0,0 +1,38 @@ +#pragma once +#include + +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)); + } + }; + } +} \ No newline at end of file diff --git a/src/Library/internal-include/periphery_internal.hpp b/src/Library/internal-include/periphery_internal.hpp new file mode 100644 index 00000000..e2bfa408 --- /dev/null +++ b/src/Library/internal-include/periphery_internal.hpp @@ -0,0 +1,39 @@ +#pragma once +#include +#include +#include +#include + +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); + } + } +} \ No newline at end of file diff --git a/src/Library/reference/about_inline_n.md b/src/Library/reference/about_inline_n.md new file mode 100644 index 00000000..0b858063 --- /dev/null +++ b/src/Library/reference/about_inline_n.md @@ -0,0 +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 +Not so helpful but can be found under `psyq\include\LIBGTE.H` \ No newline at end of file diff --git a/src/Library/reference/inline_n.h b/src/Library/reference/inline_n.h new file mode 100644 index 00000000..ba40b2e5 --- /dev/null +++ b/src/Library/reference/inline_n.h @@ -0,0 +1,1517 @@ +/* + * GTE Macro definitions - special version for Nugget (NO DMPSX) + */ + +/* + * Type 1 functions + */ + +#define gte_ldv0(r0) \ + __asm__ volatile( \ + "lwc2 $0, 0( %0 );" \ + "lwc2 $1, 4( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldv1(r0) \ + __asm__ volatile( \ + "lwc2 $2, 0( %0 );" \ + "lwc2 $3, 4( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldv2(r0) \ + __asm__ volatile( \ + "lwc2 $4, 0( %0 );" \ + "lwc2 $5, 4( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldv3(r0, r1, r2) \ + __asm__ volatile( \ + "lwc2 $0, 0( %0 );" \ + "lwc2 $1, 4( %0 );" \ + "lwc2 $2, 0( %1 );" \ + "lwc2 $3, 4( %1 );" \ + "lwc2 $4, 0( %2 );" \ + "lwc2 $5, 4( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2)) + +#define gte_ldv3c(r0) \ + __asm__ volatile( \ + "lwc2 $0, 0( %0 );" \ + "lwc2 $1, 4( %0 );" \ + "lwc2 $2, 8( %0 );" \ + "lwc2 $3, 12( %0 );" \ + "lwc2 $4, 16( %0 );" \ + "lwc2 $5, 20( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldv3c_vertc(r0) \ + __asm__ volatile( \ + "lwc2 $0, 0( %0 );" \ + "lwc2 $1, 4( %0 );" \ + "lwc2 $2, 12( %0 );" \ + "lwc2 $3, 16( %0 );" \ + "lwc2 $4, 24( %0 );" \ + "lwc2 $5, 28( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldv01(r0, r1) \ + __asm__ volatile( \ + "lwc2 $0, 0( %0 );" \ + "lwc2 $1, 4( %0 );" \ + "lwc2 $2, 0( %1 );" \ + "lwc2 $3, 4( %1 )" \ + : \ + : "r"(r0), "r"(r1)) + +#define gte_ldv01c(r0) \ + __asm__ volatile( \ + "lwc2 $0, 0( %0 );" \ + "lwc2 $1, 4( %0 );" \ + "lwc2 $2, 8( %0 );" \ + "lwc2 $3, 12( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldrgb(r0) __asm__ volatile("lwc2 $6, 0( %0 )" : : "r"(r0)) + +#define gte_ldrgb3(r0, r1, r2) \ + __asm__ volatile( \ + "lwc2 $20, 0( %0 );" \ + "lwc2 $21, 0( %1 );" \ + "lwc2 $22, 0( %2 );" \ + "lwc2 $6, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2)) + +#define gte_ldrgb3c(r0) \ + __asm__ volatile( \ + "lwc2 $20, 0( %0 );" \ + "lwc2 $21, 4( %0 );" \ + "lwc2 $22, 8( %0 );" \ + "lwc2 $6, 8( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldlv0(r0) \ + __asm__ volatile( \ + "lhu $13, 4( %0 );" \ + "lhu $12, 0( %0 );" \ + "sll $13, $13, 16;" \ + "or $12, $12, $13;" \ + "mtc2 $12, $0;" \ + "lwc2 $1, 8( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_ldlvl(r0) \ + __asm__ volatile( \ + "lwc2 $9, 0( %0 );" \ + "lwc2 $10, 4( %0 );" \ + "lwc2 $11, 8( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldsv(r0) \ + __asm__ volatile( \ + "lhu $12, 0( %0 );" \ + "lhu $13, 2( %0 );" \ + "lhu $14, 4( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "mtc2 $14, $11" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldbv(r0) \ + __asm__ volatile( \ + "lbu $12, 0( %0 );" \ + "lbu $13, 1( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_ldcv(r0) \ + __asm__ volatile( \ + "lbu $12, 0( %0 );" \ + "lbu $13, 1( %0 );" \ + "lbu $14, 2( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "mtc2 $14, $11" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldclmv(r0) \ + __asm__ volatile( \ + "lhu $12, 0( %0 );" \ + "lhu $13, 6( %0 );" \ + "lhu $14, 12( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "mtc2 $14, $11" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_lddp(r0) __asm__ volatile("mtc2 %0, $8" : : "r"(r0)) + +#define gte_ldsxy0(r0) __asm__ volatile("mtc2 %0, $12" : : "r"(r0)) + +#define gte_ldsxy1(r0) __asm__ volatile("mtc2 %0, $13" : : "r"(r0)) + +#define gte_ldsxy2(r0) __asm__ volatile("mtc2 %0, $14" : : "r"(r0)) + +#define gte_ldsxy3(r0, r1, r2) \ + __asm__ volatile( \ + "mtc2 %0, $12;" \ + "mtc2 %2, $14;" \ + "mtc2 %1, $13" \ + : \ + : "r"(r0), "r"(r1), "r"(r2)) + +#define gte_ldsxy3c(r0) \ + __asm__ volatile( \ + "lwc2 $12, 0( %0 );" \ + "lwc2 $13, 4( %0 );" \ + "lwc2 $14, 8( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldsz3(r0, r1, r2) \ + __asm__ volatile( \ + "mtc2 %0, $17;" \ + "mtc2 %1, $18;" \ + "mtc2 %2, $19" \ + : \ + : "r"(r0), "r"(r1), "r"(r2)) + +#define gte_ldsz4(r0, r1, r2, r3) \ + __asm__ volatile( \ + "mtc2 %0, $16;" \ + "mtc2 %1, $17;" \ + "mtc2 %2, $18;" \ + "mtc2 %3, $19" \ + : \ + : "r"(r0), "r"(r1), "r"(r2), "r"(r3)) + +#define gte_ldopv1(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "ctc2 $12, $0;" \ + "lw $14, 8( %0 );" \ + "ctc2 $13, $2;" \ + "ctc2 $14, $4" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldopv2(r0) \ + __asm__ volatile( \ + "lwc2 $11, 8( %0 );" \ + "lwc2 $9, 0( %0 );" \ + "lwc2 $10, 4( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldlzc(r0) __asm__ volatile("mtc2 %0, $30" : : "r"(r0)) + +#define gte_SetRGBcd(r0) __asm__ volatile("lwc2 $6, 0( %0 )" : : "r"(r0)) + +#define gte_ldbkdir(r0, r1, r2) \ + __asm__ volatile( \ + "ctc2 %0, $13;" \ + "ctc2 %1, $14;" \ + "ctc2 %2, $15" \ + : \ + : "r"(r0), "r"(r1), "r"(r2)) + +#define gte_SetBackColor(r0, r1, r2) \ + __asm__ volatile( \ + "sll $12, %0, 4;" \ + "sll $13, %1, 4;" \ + "sll $14, %2, 4;" \ + "ctc2 $12, $13;" \ + "ctc2 $13, $14;" \ + "ctc2 $14, $15" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "$12", "$13", "$14") + +#define gte_ldfcdir(r0, r1, r2) \ + __asm__ volatile( \ + "ctc2 %0, $21;" \ + "ctc2 %1, $22;" \ + "ctc2 %2, $23" \ + : \ + : "r"(r0), "r"(r1), "r"(r2)) + +#define gte_SetFarColor(r0, r1, r2) \ + __asm__ volatile( \ + "sll $12, %0, 4;" \ + "sll $13, %1, 4;" \ + "sll $14, %2, 4;" \ + "ctc2 $12, $21;" \ + "ctc2 $13, $22;" \ + "ctc2 $14, $23" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "$12", "$13", "$14") + +#define gte_SetGeomOffset(r0, r1) \ + __asm__ volatile( \ + "sll $12, %0, 16;" \ + "sll $13, %1, 16;" \ + "ctc2 $12, $24;" \ + "ctc2 $13, $25" \ + : \ + : "r"(r0), "r"(r1) \ + : "$12", "$13") + +#define gte_SetGeomScreen(r0) __asm__ volatile("ctc2 %0, $26" : : "r"(r0)) + +#define gte_ldsvrtrow0(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "ctc2 $12, $0;" \ + "ctc2 $13, $1" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_SetRotMatrix(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "ctc2 $12, $0;" \ + "ctc2 $13, $1;" \ + "lw $12, 8( %0 );" \ + "lw $13, 12( %0 );" \ + "lw $14, 16( %0 );" \ + "ctc2 $12, $2;" \ + "ctc2 $13, $3;" \ + "ctc2 $14, $4" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldsvllrow0(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "ctc2 $12, $8;" \ + "ctc2 $13, $9" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_SetLightMatrix(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "ctc2 $12, $8;" \ + "ctc2 $13, $9;" \ + "lw $12, 8( %0 );" \ + "lw $13, 12( %0 );" \ + "lw $14, 16( %0 );" \ + "ctc2 $12, $10;" \ + "ctc2 $13, $11;" \ + "ctc2 $14, $12" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldsvlcrow0(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "ctc2 $12, $16;" \ + "ctc2 $13, $17" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_SetColorMatrix(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "ctc2 $12, $16;" \ + "ctc2 $13, $17;" \ + "lw $12, 8( %0 );" \ + "lw $13, 12( %0 );" \ + "lw $14, 16( %0 );" \ + "ctc2 $12, $18;" \ + "ctc2 $13, $19;" \ + "ctc2 $14, $20" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_SetTransMatrix(r0) \ + __asm__ volatile( \ + "lw $12, 20( %0 );" \ + "lw $13, 24( %0 );" \ + "ctc2 $12, $5;" \ + "lw $14, 28( %0 );" \ + "ctc2 $13, $6;" \ + "ctc2 $14, $7" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldtr(r0, r1, r2) \ + __asm__ volatile( \ + "ctc2 %0, $5;" \ + "ctc2 %1, $6;" \ + "ctc2 %2, $7" \ + : \ + : "r"(r0), "r"(r1), "r"(r2)) + +#define gte_SetTransVector(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "lw $14, 8( %0 );" \ + "ctc2 $12, $5;" \ + "ctc2 $13, $6;" \ + "ctc2 $14, $7" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ld_intpol_uv0(r0) \ + __asm__ volatile( \ + "lbu $12, 0( %0 );" \ + "lbu $13, 1( %0 );" \ + "ctc2 $12, $21;" \ + "ctc2 $13, $22" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_ld_intpol_uv1(r0) \ + __asm__ volatile( \ + "lbu $12, 0( %0 );" \ + "lbu $13, 1( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_ld_intpol_bv0(r0) \ + __asm__ volatile( \ + "lbu $12, 0( %0 );" \ + "lbu $13, 1( %0 );" \ + "ctc2 $12, $21;" \ + "ctc2 $13, $22" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_ld_intpol_bv1(r0) \ + __asm__ volatile( \ + "lbu $12, 0( %0 );" \ + "lbu $13, 1( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_ld_intpol_sv0(r0) \ + __asm__ volatile( \ + "lh $12, 0( %0 );" \ + "lh $13, 2( %0 );" \ + "lh $14, 4( %0 );" \ + "ctc2 $12, $21;" \ + "ctc2 $13, $22;" \ + "ctc2 $14, $23" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ld_intpol_sv1(r0) \ + __asm__ volatile( \ + "lh $12, 0( %0 );" \ + "lh $13, 2( %0 );" \ + "lh $14, 4( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "mtc2 $14, $11" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldfc(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "lw $14, 8( %0 );" \ + "ctc2 $12, $21;" \ + "ctc2 $13, $22;" \ + "ctc2 $14, $23" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldopv2SV(r0) \ + __asm__ volatile( \ + "lh $12, 0( %0 );" \ + "lh $13, 2( %0 );" \ + "lh $14, 4( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "mtc2 $14, $11" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldopv1SV(r0) \ + __asm__ volatile( \ + "lh $12, 0( %0 );" \ + "lh $13, 2( %0 );" \ + "ctc2 $12, $0;" \ + "lh $14, 4( %0 );" \ + "ctc2 $13, $2;" \ + "ctc2 $14, $4" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +/* + * Type 2 functions + */ + +#define gte_rtps() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0180001;") + +#define gte_rtpt() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0280030;") + +#define gte_rt() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0480012;") + +#define gte_rtv0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0486012;") + +#define gte_rtv1() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x048E012;") + +#define gte_rtv2() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0496012;") + +#define gte_rtir() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x049E012;") + +#define gte_rtir_sf0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x041E012;") + +#define gte_rtv0tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0480012;") + +#define gte_rtv1tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0488012;") + +#define gte_rtv2tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0490012;") + +#define gte_rtirtr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0498012;") + +#define gte_rtv0bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0482012;") + +#define gte_rtv1bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x048A012;") + +#define gte_rtv2bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0492012;") + +#define gte_rtirbk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x049A012;") + +#define gte_ll() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04A6412;") + +#define gte_llv0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04A6012;") + +#define gte_llv1() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04AE012;") + +#define gte_llv2() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04B6012;") + +#define gte_llir() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04BE012;") + +#define gte_llv0tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04A0012;") + +#define gte_llv1tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04A8012;") + +#define gte_llv2tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04B0012;") + +#define gte_llirtr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04B8012;") + +#define gte_llv0bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04A2012;") + +#define gte_llv1bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04AA012;") + +#define gte_llv2bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04B2012;") + +#define gte_llirbk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04BA012;") + +#define gte_lc() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04DA412;") + +#define gte_lcv0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04C6012;") + +#define gte_lcv1() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04CE012;") + +#define gte_lcv2() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04D6012;") + +#define gte_lcir() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04DE012;") + +#define gte_lcv0tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04C0012;") + +#define gte_lcv1tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04C8012;") + +#define gte_lcv2tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04D0012;") + +#define gte_lcirtr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04D8012;") + +#define gte_lcv0bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04C2012;") + +#define gte_lcv1bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04CA012;") + +#define gte_lcv2bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04D2012;") + +#define gte_lcirbk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04DA012;") + +#define gte_dpcl() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0680029;") + +#define gte_dpcs() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0780010;") + +#define gte_dpct() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0F8002A;") + +#define gte_intpl() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0980011;") + +#define gte_sqr12() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0A80428;") + +#define gte_sqr0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0A00428;") + +#define gte_ncs() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0C8041E;") + +#define gte_nct() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0D80420;") + +#define gte_ncds() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0E80413;") + +#define gte_ncdt() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0F80416;") + +#define gte_nccs() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0108041B;") + +#define gte_ncct() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0118043F;") + +#define gte_cdp() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x01280414;") + +#define gte_cc() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0138041C;") + +#define gte_nclip() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x01400006;") + +#define gte_avsz3() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0158002D;") + +#define gte_avsz4() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0168002E;") + +#define gte_op12() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0178000C;") + +#define gte_op0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0170000C;") + +#define gte_gpf12() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0198003D;") + +#define gte_gpf0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0190003D;") + +#define gte_gpl12() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x01A8003E;") + +#define gte_gpl0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x01A0003E0") + +#define gte_mvmva_core(r0) \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 %0" \ + : \ + : "g"(r0)) + +#define gte_mvmva(sf, mx, v, cv, lm) \ + gte_mvmva_core(0x0400012 | ((sf) << 19) | ((mx) << 17) | ((v) << 15) | ((cv) << 13) | ((lm) << 10)) + +/* + * Type 2 functions without nop + */ + +#define gte_rtps_b() __asm__ volatile("cop2 0x0180001;") +#define gte_rtpt_b() __asm__ volatile("cop2 0x0280030;") +#define gte_rt_b() __asm__ volatile("cop2 0x0480012;") +#define gte_rtv0_b() __asm__ volatile("cop2 0x0486012;") +#define gte_rtv1_b() __asm__ volatile("cop2 0x048E012;") +#define gte_rtv2_b() __asm__ volatile("cop2 0x0496012;") +#define gte_rtir_b() __asm__ volatile("cop2 0x049E012;") +#define gte_rtir_sf0_b() __asm__ volatile("cop2 0x041E012;") +#define gte_rtv0tr_b() __asm__ volatile("cop2 0x0480012;") +#define gte_rtv1tr_b() __asm__ volatile("cop2 0x0488012;") +#define gte_rtv2tr_b() __asm__ volatile("cop2 0x0490012;") +#define gte_rtirtr_b() __asm__ volatile("cop2 0x0498012;") +#define gte_rtv0bk_b() __asm__ volatile("cop2 0x0482012;") +#define gte_rtv1bk_b() __asm__ volatile("cop2 0x048A012;") +#define gte_rtv2bk_b() __asm__ volatile("cop2 0x0492012;") +#define gte_rtirbk_b() __asm__ volatile("cop2 0x049A012;") +#define gte_ll_b() __asm__ volatile("cop2 0x04A6412;") +#define gte_llv0_b() __asm__ volatile("cop2 0x04A6012;") +#define gte_llv1_b() __asm__ volatile("cop2 0x04AE012;") +#define gte_llv2_b() __asm__ volatile("cop2 0x04B6012;") +#define gte_llir_b() __asm__ volatile("cop2 0x04BE012;") +#define gte_llv0tr_b() __asm__ volatile("cop2 0x04A0012;") +#define gte_llv1tr_b() __asm__ volatile("cop2 0x04A8012;") +#define gte_llv2tr_b() __asm__ volatile("cop2 0x04B0012;") +#define gte_llirtr_b() __asm__ volatile("cop2 0x04B8012;") +#define gte_llv0bk_b() __asm__ volatile("cop2 0x04A2012;") +#define gte_llv1bk_b() __asm__ volatile("cop2 0x04AA012;") +#define gte_llv2bk_b() __asm__ volatile("cop2 0x04B2012;") +#define gte_llirbk_b() __asm__ volatile("cop2 0x04BA012;") +#define gte_lc_b() __asm__ volatile("cop2 0x04DA412;") +#define gte_lcv0_b() __asm__ volatile("cop2 0x04C6012;") +#define gte_lcv1_b() __asm__ volatile("cop2 0x04CE012;") +#define gte_lcv2_b() __asm__ volatile("cop2 0x04D6012;") +#define gte_lcir_b() __asm__ volatile("cop2 0x04DE012;") +#define gte_lcv0tr_b() __asm__ volatile("cop2 0x04C0012;") +#define gte_lcv1tr_b() __asm__ volatile("cop2 0x04C8012;") +#define gte_lcv2tr_b() __asm__ volatile("cop2 0x04D0012;") +#define gte_lcirtr_b() __asm__ volatile("cop2 0x04D8012;") +#define gte_lcv0bk_b() __asm__ volatile("cop2 0x04C2012;") +#define gte_lcv1bk_b() __asm__ volatile("cop2 0x04CA012;") +#define gte_lcv2bk_b() __asm__ volatile("cop2 0x04D2012;") +#define gte_lcirbk_b() __asm__ volatile("cop2 0x04DA012;") +#define gte_dpcl_b() __asm__ volatile("cop2 0x0680029;") +#define gte_dpcs_b() __asm__ volatile("cop2 0x0780010;") +#define gte_dpct_b() __asm__ volatile("cop2 0x0F8002A;") +#define gte_intpl_b() __asm__ volatile("cop2 0x0980011;") +#define gte_sqr12_b() __asm__ volatile("cop2 0x0A80428;") +#define gte_sqr0_b() __asm__ volatile("cop2 0x0A00428;") +#define gte_ncs_b() __asm__ volatile("cop2 0x0C8041E;") +#define gte_nct_b() __asm__ volatile("cop2 0x0D80420;") +#define gte_ncds_b() __asm__ volatile("cop2 0x0E80413;") +#define gte_ncdt_b() __asm__ volatile("cop2 0x0F80416;") +#define gte_nccs_b() __asm__ volatile("cop2 0x0108041B;") +#define gte_ncct_b() __asm__ volatile("cop2 0x0118043F;") +#define gte_cdp_b() __asm__ volatile("cop2 0x01280414;") +#define gte_cc_b() __asm__ volatile("cop2 0x0138041C;") +#define gte_nclip_b() __asm__ volatile("cop2 0x01400006;") +#define gte_avsz3_b() __asm__ volatile("cop2 0x0158002D;") +#define gte_avsz4_b() __asm__ volatile("cop2 0x0168002E;") +#define gte_op12_b() __asm__ volatile("cop2 0x0178000C;") +#define gte_op0_b() __asm__ volatile("cop2 0x0170000C;") +#define gte_gpf12_b() __asm__ volatile("cop2 0x0198003D;") +#define gte_gpf0_b() __asm__ volatile("cop2 0x0190003D;") +#define gte_gpl12_b() __asm__ volatile("cop2 0x01A8003E;") +#define gte_gpl0_b() __asm__ volatile("cop2 0x01A0003E0;") +#define gte_mvmva_core_b(r0) __asm__ volatile("cop2 %0" : : "g"(r0)) +#define gte_mvmva_b(sf, mx, v, cv, lm) \ + gte_mvmva_core_b(0x0400012 | ((sf) << 19) | ((mx) << 17) | ((v) << 15) | ((cv) << 13) | ((lm) << 10)) + +/* + * Type 3 functions + */ + +#define gte_stsxy(r0) __asm__ volatile("swc2 $14, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stsxy3(r0, r1, r2) \ + __asm__ volatile( \ + "swc2 $12, 0( %0 );" \ + "swc2 $13, 0( %1 );" \ + "swc2 $14, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "memory") + +#define gte_stsxy3c(r0) \ + __asm__ volatile( \ + "swc2 $12, 0( %0 );" \ + "swc2 $13, 4( %0 );" \ + "swc2 $14, 8( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy2(r0) __asm__ volatile("swc2 $14, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stsxy1(r0) __asm__ volatile("swc2 $13, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stsxy0(r0) __asm__ volatile("swc2 $12, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stsxy01(r0, r1) \ + __asm__ volatile( \ + "swc2 $12, 0( %0 );" \ + "swc2 $13, 0( %1 )" \ + : \ + : "r"(r0), "r"(r1) \ + : "memory") + +#define gte_stsxy01c(r0) \ + __asm__ volatile( \ + "swc2 $12, 0( %0 );" \ + "swc2 $13, 4( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_f3(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 12( %0 );" \ + "swc2 $14, 16( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_g3(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 16( %0 );" \ + "swc2 $14, 24( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_ft3(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 16( %0 );" \ + "swc2 $14, 24( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_gt3(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 20( %0 );" \ + "swc2 $14, 32( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_f4(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 12( %0 );" \ + "swc2 $14, 16( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_g4(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 16( %0 );" \ + "swc2 $14, 24( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_ft4(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 16( %0 );" \ + "swc2 $14, 24( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_gt4(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 20( %0 );" \ + "swc2 $14, 32( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stdp(r0) __asm__ volatile("swc2 $8, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stflg(r0) \ + __asm__ volatile( \ + "cfc2 $12, $31;" \ + "nop;" \ + "sw $12, 0( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "memory") + +#define gte_stflg_4(r0) \ + __asm__ volatile( \ + "cfc2 $12, $31;" \ + "addi $13, $0, 4;" \ + "sll $13, $13, 16;" \ + "and $12, $12, $13;" \ + "sw $12, 0( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "memory") + +#define gte_stsz(r0) __asm__ volatile("swc2 $19, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stsz3(r0, r1, r2) \ + __asm__ volatile( \ + "swc2 $17, 0( %0 );" \ + "swc2 $18, 0( %1 );" \ + "swc2 $19, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "memory") + +#define gte_stsz4(r0, r1, r2, r3) \ + __asm__ volatile( \ + "swc2 $16, 0( %0 );" \ + "swc2 $17, 0( %1 );" \ + "swc2 $18, 0( %2 );" \ + "swc2 $19, 0( %3 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2), "r"(r3) \ + : "memory") + +#define gte_stsz3c(r0) \ + __asm__ volatile( \ + "swc2 $17, 0( %0 );" \ + "swc2 $18, 4( %0 );" \ + "swc2 $19, 8( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsz4c(r0) \ + __asm__ volatile( \ + "swc2 $16, 0( %0 );" \ + "swc2 $17, 4( %0 );" \ + "swc2 $18, 8( %0 );" \ + "swc2 $19, 12( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stszotz(r0) \ + __asm__ volatile( \ + "mfc2 $12, $19;" \ + "nop;" \ + "sra $12, $12, 2;" \ + "sw $12, 0( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "memory") + +#define gte_stotz(r0) __asm__ volatile("swc2 $7, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stopz(r0) __asm__ volatile("swc2 $24, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stlvl(r0) \ + __asm__ volatile( \ + "swc2 $9, 0( %0 );" \ + "swc2 $10, 4( %0 );" \ + "swc2 $11, 8( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stlvnl(r0) \ + __asm__ volatile( \ + "swc2 $25, 0( %0 );" \ + "swc2 $26, 4( %0 );" \ + "swc2 $27, 8( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stlvnl0(r0) __asm__ volatile("swc2 $25, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stlvnl1(r0) __asm__ volatile("swc2 $26, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stlvnl2(r0) __asm__ volatile("swc2 $27, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stsv(r0) \ + __asm__ volatile( \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "mfc2 $14, $11;" \ + "sh $12, 0( %0 );" \ + "sh $13, 2( %0 );" \ + "sh $14, 4( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_stclmv(r0) \ + __asm__ volatile( \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "mfc2 $14, $11;" \ + "sh $12, 0( %0 );" \ + "sh $13, 6( %0 );" \ + "sh $14, 12( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_stbv(r0) \ + __asm__ volatile( \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "sb $12, 0( %0 );" \ + "sb $13, 1( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "memory") + +#define gte_stcv(r0) \ + __asm__ volatile( \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "mfc2 $14, $11;" \ + "sb $12, 0( %0 );" \ + "sb $13, 1( %0 );" \ + "sb $14, 2( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_strgb(r0) __asm__ volatile("swc2 $22, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_strgb3(r0, r1, r2) \ + __asm__ volatile( \ + "swc2 $20, 0( %0 );" \ + "swc2 $21, 0( %1 );" \ + "swc2 $22, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "memory") + +#define gte_strgb3_g3(r0) \ + __asm__ volatile( \ + "swc2 $20, 4( %0 );" \ + "swc2 $21, 12( %0 );" \ + "swc2 $22, 20( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_strgb3_gt3(r0) \ + __asm__ volatile( \ + "swc2 $20, 4( %0 );" \ + "swc2 $21, 16( %0 );" \ + "swc2 $22, 28( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_strgb3_g4(r0) \ + __asm__ volatile( \ + "swc2 $20, 4( %0 );" \ + "swc2 $21, 12( %0 );" \ + "swc2 $22, 20( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_strgb3_gt4(r0) \ + __asm__ volatile( \ + "swc2 $20, 4( %0 );" \ + "swc2 $21, 16( %0 );" \ + "swc2 $22, 28( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_ReadGeomOffset(r0, r1) \ + __asm__ volatile( \ + "cfc2 $12, $24;" \ + "cfc2 $13, $25;" \ + "sra $12, $12, 16;" \ + "sra $13, $13, 16;" \ + "sw $12, 0( %0 );" \ + "sw $13, 0( %1 )" \ + : \ + : "r"(r0), "r"(r1) \ + : "$12", "$13", "memory") + +#define gte_ReadGeomScreen(r0) \ + __asm__ volatile( \ + "cfc2 $12, $26;" \ + "nop;" \ + "sw $12, 0( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "memory") + +#define gte_ReadRotMatrix(r0) \ + __asm__ volatile( \ + "cfc2 $12, $0;" \ + "cfc2 $13, $1;" \ + "sw $12, 0( %0 );" \ + "sw $13, 4( %0 );" \ + "cfc2 $12, $2;" \ + "cfc2 $13, $3;" \ + "cfc2 $14, $4;" \ + "sw $12, 8( %0 );" \ + "sw $13, 12( %0 );" \ + "sw $14, 16( %0 );" \ + "cfc2 $12, $5;" \ + "cfc2 $13, $6;" \ + "cfc2 $14, $7;" \ + "sw $12, 20( %0 );" \ + "sw $13, 24( %0 );" \ + "sw $14, 28( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_sttr(r0) \ + __asm__ volatile( \ + "cfc2 $12, $5;" \ + "cfc2 $13, $6;" \ + "cfc2 $14, $7;" \ + "sw $12, 0( %0 );" \ + "sw $13, 4( %0 );" \ + "sw $14, 8( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_ReadLightMatrix(r0) \ + __asm__ volatile( \ + "cfc2 $12, $8;" \ + "cfc2 $13, $9;" \ + "sw $12, 0( %0 );" \ + "sw $13, 4( %0 );" \ + "cfc2 $12, $10;" \ + "cfc2 $13, $11;" \ + "cfc2 $14, $12;" \ + "sw $12, 8( %0 );" \ + "sw $13, 12( %0 );" \ + "sw $14, 16( %0 );" \ + "cfc2 $12, $13;" \ + "cfc2 $13, $14;" \ + "cfc2 $14, $15;" \ + "sw $12, 20( %0 );" \ + "sw $13, 24( %0 );" \ + "sw $14, 28( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_ReadColorMatrix(r0) \ + __asm__ volatile( \ + "cfc2 $12, $16;" \ + "cfc2 $13, $17;" \ + "sw $12, 0( %0 );" \ + "sw $13, 4( %0 );" \ + "cfc2 $12, $18;" \ + "cfc2 $13, $19;" \ + "cfc2 $14, $20;" \ + "sw $12, 8( %0 );" \ + "sw $13, 12( %0 );" \ + "sw $14, 16( %0 );" \ + "cfc2 $12, $21;" \ + "cfc2 $13, $22;" \ + "cfc2 $14, $23;" \ + "sw $12, 20( %0 );" \ + "sw $13, 24( %0 );" \ + "sw $14, 28( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_stlzc(r0) __asm__ volatile("swc2 $31, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stfc(r0) \ + __asm__ volatile( \ + "cfc2 $12, $21;" \ + "cfc2 $13, $22;" \ + "cfc2 $14, $23;" \ + "sw $12, 0( %0 );" \ + "sw $13, 4( %0 );" \ + "sw $14, 8( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_mvlvtr() \ + __asm__ volatile( \ + "mfc2 $12, $25;" \ + "mfc2 $13, $26;" \ + "mfc2 $14, $27;" \ + "ctc2 $12, $5;" \ + "ctc2 $13, $6;" \ + "ctc2 $14, $7" \ + : \ + : \ + : "$12", "$13", "$14") + +#define gte_nop() __asm__ volatile("nop") + +#define gte_subdvl(r0, r1, r2) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 0( %1 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "sra $12, $12, 16;" \ + "sra $13, $13, 16;" \ + "subu $15, $12, $13;" \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "sw $15, 4( %2 );" \ + "subu $12, $12, $13;" \ + "sw $12, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "$12", "$13", "$14", "$15", "memory") + +#define gte_subdvd(r0, r1, r2) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 0( %1 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "sra $12, $12, 16;" \ + "sra $13, $13, 16;" \ + "subu $15, $12, $13;" \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "sh $15, 2( %2 );" \ + "subu $12, $12, $13;" \ + "sh $12, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "$12", "$13", "$14", "$15", "memory") + +#define gte_adddvl(r0, r1, r2) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 0( %1 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "sra $12, $12, 16;" \ + "sra $13, $13, 16;" \ + "addu $15, $12, $13;" \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "sw $15, 4( %2 );" \ + "addu $12, $12, $13;" \ + "sw $12, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "$12", "$13", "$14", "$15", "memory") + +#define gte_adddvd(r0, r1, r2) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 0( %1 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "sra $12, $12, 16;" \ + "sra $13, $13, 16;" \ + "addu $15, $12, $13;" \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "sh $15, 2( %2 );" \ + "addu $12, $12, $13;" \ + "sh $12, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "$12", "$13", "$14", "$15", "memory") + +#define gte_FlipRotMatrixX() \ + __asm__ volatile( \ + "cfc2 $12, $0;" \ + "cfc2 $13, $1;" \ + "sll $14, $12, 16;" \ + "sra $14, $14, 16;" \ + "subu $14, $0, $14;" \ + "sra $15, $12, 16;" \ + "subu $15, $0, $15;" \ + "sll $15, $15, 16;" \ + "sll $14, $14, 16;" \ + "srl $14, $14, 16;" \ + "or $14, $14, $15;" \ + "ctc2 $14, $0;" \ + "sll $14, $13, 16;" \ + "sra $14, $14, 16;" \ + "subu $14, $0, $14;" \ + "sra $15, $13, 16;" \ + "sll $15, $15, 16;" \ + "sll $14, $14, 16;" \ + "srl $14, $14, 16;" \ + "or $14, $14, $15;" \ + "ctc2 $14, $1" \ + : \ + : \ + : "$12", "$13", "$14", "$15") + +#define gte_FlipTRX() \ + __asm__ volatile( \ + "cfc2 $12, $5;" \ + "nop;" \ + "subu $12, $0, $12;" \ + "ctc2 $12, $5" \ + : \ + : \ + : "$12") diff --git a/src/Library/ressources/Splash.png b/src/Library/ressources/Splash.png index 0504b2f5..1db072bb 100644 --- a/src/Library/ressources/Splash.png +++ b/src/Library/ressources/Splash.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4ca5aebfc2380c4b5e36fc491eec7e1aad65f3336881ad3cbb593eac0faa7ecd -size 101029 +oid sha256:cc2e42d6c8833839446b102035505a571082528dbcf951ec8b010b7854030882 +size 77339 diff --git a/src/Library/ressources/Splash_ntsc.png b/src/Library/ressources/Splash_ntsc.png index e7f7dcd9..beca3031 100644 --- a/src/Library/ressources/Splash_ntsc.png +++ b/src/Library/ressources/Splash_ntsc.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:de46efe930c3e143be231c2acc3b0ae075236536b7ef6cc5f3240ffdec98c5d0 -size 91320 +oid sha256:6ba3314603b5e51ec4ac98f764a2d00ed6dbe877bfd584143c26038322b4f041 +size 69778 diff --git a/src/Library/run_make.bat b/src/Library/run_make.bat deleted file mode 100644 index 4453913e..00000000 --- a/src/Library/run_make.bat +++ /dev/null @@ -1,11 +0,0 @@ -@echo off -rem run_make.bat build|clean|rebuild debug|release - -IF %1 == build ( - set make_target=all -) else ( - set make_target=%1 -) - -@echo make %make_target% BUILD_PROFILE=%2 -wsl make %make_target% BUILD_PROFILE=%2 diff --git a/src/Library/src/Audio/CDDA.cpp b/src/Library/src/Audio/CDDA.cpp new file mode 100644 index 00000000..a40f4788 --- /dev/null +++ b/src/Library/src/Audio/CDDA.cpp @@ -0,0 +1,54 @@ +#include "../../internal-include/CD/cd_internal.hpp" +#include + +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(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); + } + } +} \ No newline at end of file diff --git a/src/Library/src/Audio/CDXA.cpp b/src/Library/src/Audio/CDXA.cpp new file mode 100644 index 00000000..5d81818b --- /dev/null +++ b/src/Library/src/Audio/CDXA.cpp @@ -0,0 +1,68 @@ +#include "../../internal-include/CD/cd_internal.hpp" +#include "../../internal-include/CD/cd_types.hpp" +#include + +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(); + 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); + } + } +} \ No newline at end of file diff --git a/src/Library/src/BootLoader/BIOSFont/ascii_bios_font.hpp b/src/Library/src/BootLoader/BIOSFont/ascii_bios_font.hpp new file mode 100644 index 00000000..977797b9 --- /dev/null +++ b/src/Library/src/BootLoader/BIOSFont/ascii_bios_font.hpp @@ -0,0 +1,73 @@ +#pragma once +#include "../../../internal-include/GPU/gpu_internal.hpp" +#include "bios_font_types.hpp" +#include + +// | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | 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](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](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(); + } + } + } +} \ No newline at end of file diff --git a/src/Library/src/BootLoader/BIOSFont/bios_font_types.hpp b/src/Library/src/BootLoader/BIOSFont/bios_font_types.hpp new file mode 100644 index 00000000..dc88aeee --- /dev/null +++ b/src/Library/src/BootLoader/BIOSFont/bios_font_types.hpp @@ -0,0 +1,98 @@ +#pragma once +#include "../../../internal-include/GPU/gpu_internal.hpp" +#include + +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(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(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)); + } + } +} \ No newline at end of file diff --git a/src/Library/src/BootLoader/callbacks_boot.cxx b/src/Library/src/BootLoader/callbacks_boot.cxx new file mode 100644 index 00000000..90fa716c --- /dev/null +++ b/src/Library/src/BootLoader/callbacks_boot.cxx @@ -0,0 +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();*/ + } + } + } +} \ No newline at end of file diff --git a/src/Library/src/BootLoader/cd_boot.cpp b/src/Library/src/BootLoader/cd_boot.cpp index 24da5b48..2d91da03 100644 --- a/src/Library/src/BootLoader/cd_boot.cpp +++ b/src/Library/src/BootLoader/cd_boot.cpp @@ -1,42 +1,42 @@ -#include "../../internal-include/BootLoader/boot_loader.hpp" -#include "../../internal-include/CD/cd_internal.hpp" -#include -#include -#include - -namespace JabyEngine { - namespace CD { - namespace internal { - extern InterrupCallback callback; - } - } - namespace boot { - namespace CD { - using JabyEngine::CD::internal::Command; - - void setup() { - __syscall_EnterCriticalSection(); - Memory_IO::COM_DELAY.setup(); - Memory_IO::CD_DELAY.setup(); - - __syscall_SysEnqIntRP(CdromIoIrq, &::JabyEngine::CD::internal::callback); - - CD_IO::PortIndex1::change_to(); - CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag); - CD_IO::Interrupt::enable(CD_IO::PortIndex1::InterruptEnable); - - Interrupt::enable_irq(Interrupt::CDROM); - Interrupt::ack_irq(Interrupt::CDROM); - __syscall_ExitCriticalSection(); - - CD_IO::PortIndex0::change_to(); - - Command::send_wait(CD_IO::PortIndex0::CommandFifo, CD_IO::PortIndex0::ParameterFifo, CD_IO::Command::GetStat); - Command::send_wait(CD_IO::PortIndex0::CommandFifo, CD_IO::PortIndex0::ParameterFifo, CD_IO::Command::GetStat); - Command::send_wait(CD_IO::PortIndex0::CommandFifo, CD_IO::PortIndex0::ParameterFifo, CD_IO::Command::Init); - - // Demute? - } - } - } +#include "../../internal-include/BootLoader/boot_loader.hpp" +#include "../../internal-include/CD/cd_internal.hpp" +#include +#include +#include + +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(); + } + } + } } \ No newline at end of file diff --git a/src/Library/src/BootLoader/dma_boot.cpp b/src/Library/src/BootLoader/dma_boot.cpp new file mode 100644 index 00000000..b844393a --- /dev/null +++ b/src/Library/src/BootLoader/dma_boot.cpp @@ -0,0 +1,25 @@ +#include +#include +#include + +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(); + } + } + } +} \ No newline at end of file diff --git a/src/Library/src/BootLoader/gpu_boot.cpp b/src/Library/src/BootLoader/gpu_boot.cpp index 5f38475e..e5a43f2c 100644 --- a/src/Library/src/BootLoader/gpu_boot.cpp +++ b/src/Library/src/BootLoader/gpu_boot.cpp @@ -1,61 +1,109 @@ -#include "../../internal-include/GPU/gpu_internal.hpp" -#include -#include -#include -#include - -#ifdef JABYENGINE_PAL - #include "splash_image_pal_boot.hpp" -#else - #include "splash_image_ntsc_boot.hpp" -#endif //JABYENGINE_PAL - -extern "C" uint32_t __boot_loader_end; - -namespace JabyEngine { - namespace boot { - namespace GPU { - using namespace JabyEngine::GPU; - - static size_t decompress_logo() { - LZ4Decompressor lz4_decomp(reinterpret_cast(&__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() { - const auto bytes_ready = decompress_logo(); - - // Upload SplashScreen picture - auto state = FileProcessor::create(&__boot_loader_end, SimpleTIM(32, 0, 0, 0)); - state.process(bytes_ready); - - Display::enable(); - } - - void setup() { - GPU_IO::GP1 = GPU_IO::Command::Reset(); - internal::Screen::configurate(); - internal::Screen::exchange_buffer_and_display(); - - GPU::internal::wait_ready_for_CMD(); - GPU::internal::quick_fill_fast(Color24::Black(), PositionU16(32, 0), SizeU16(Display::Width, Display::Height)); - } - } - } +#include "../../internal-include/GPU/gpu_internal.hpp" +#include +#include +#include +#include +#include +#include + +#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(&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(&__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(); + } + } + } } \ No newline at end of file diff --git a/src/Library/src/BootLoader/gte_boot.cpp b/src/Library/src/BootLoader/gte_boot.cpp new file mode 100644 index 00000000..caa93717 --- /dev/null +++ b/src/Library/src/BootLoader/gte_boot.cpp @@ -0,0 +1,20 @@ +#include "../../internal-include/mipscalls.hpp" +#include +#include + + +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); + } + } + } +} \ No newline at end of file diff --git a/src/Library/src/BootLoader/periphery_boot.cpp b/src/Library/src/BootLoader/periphery_boot.cpp new file mode 100644 index 00000000..02379fcc --- /dev/null +++ b/src/Library/src/BootLoader/periphery_boot.cpp @@ -0,0 +1,17 @@ +#include "../../internal-include/periphery_internal.hpp" +#include + +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(); + } + } + } +} \ No newline at end of file diff --git a/src/Library/src/BootLoader/spu_boot.cpp b/src/Library/src/BootLoader/spu_boot.cpp index bff3a1d8..334e5ee5 100644 --- a/src/Library/src/BootLoader/spu_boot.cpp +++ b/src/Library/src/BootLoader/spu_boot.cpp @@ -1,86 +1,76 @@ #include -#include -#include +#include namespace JabyEngine { namespace boot { namespace SPU { using namespace JabyEngine; using namespace SPU_IO; + using namespace SPU_IO_Values; static void clear_main_volume() { - static constexpr auto StartVol = SweepVolume_t::from(SweepVolume_t::VolumeEnable, SweepVolume_t::Volume.with(static_cast(I16_MAX >> 2))); + static constexpr auto StartVol = SweepVolume::from(SweepVolume::VolumeMode::Enable, SweepVolume::VolumeMode::Volume.with(SweepVolume::VolumeMode::MaxVolume >> 1)); - MainVolume::Left = StartVol; - MainVolume::Right = StartVol; + MainVolume::Left.write(StartVol); + MainVolume::Right.write(StartVol); } static void clear_cd_and_ext_audio_volume() { - CDVolume::Left = 0; - CDVolume::Right = 0; + CDVolume::Left.write(0.75_vol); + CDVolume::Right.write(0.75_vol); - ExternalAudioInputVolume::Left = 0; - ExternalAudioInputVolume::Right = 0; - } - - static void clear_control_register() { - ControlRegister = 0; + ExternalAudioInputVolume::Left.write(SimpleVolume::mute()); + ExternalAudioInputVolume::Right.write(SimpleVolume::mute()); } static void clear_voice() { for(auto& voice : SPU_IO::Voice) { - voice.volumeLeft = SweepVolume_t(); - voice.volumeRight = SweepVolume_t(); - voice.sampleRate = SampleRate_t(); - voice.ad = AD_t(); - voice.sr = SR_t(); - voice.currentVolume = 0; + voice.volumeLeft.write(SweepVolume::mute()); + voice.volumeRight.write(SweepVolume::mute()); + voice.sampleRate.write(SampleRate::stop()); + voice.ad.write(AD::none()); + voice.sr.write(SR::none()); + voice.adsr_volume.write(SimpleVolume::mute()); - voice.adr = 0x200; - voice.repeatAdr = 0x200; + voice.adr.write(SRAMAdr::adpcm_start()); + voice.repeatAdr.write(SRAMAdr::adpcm_start()); } } static void clear_pmon() { - SPU_IO::PMON = PMON_t(); + SPU_IO::PMON.write(PitchModulation::AllOff()); } static void clear_noise_and_echo() { - SPU_IO::NON = NON_t(); - SPU_IO::EON = EON_t(); + SPU_IO::NON.write(Noise::AllOff()); + SPU_IO::EON.write(Echo::AllOff()); } static void clear_reverb() { - Reverb::Volume::Left = 0; - Reverb::Volume::Right = 0; - Reverb::WorkAreaAdr = 0; + Reverb::Volume::Left.write(SimpleVolume::mute()); + Reverb::Volume::Right.write(SimpleVolume::mute()); + Reverb::WorkAreaAdr.write(SRAMAdr::null()); } static void setup_control_register() { - static constexpr auto SetupValue = ControlRegister_t::from(ControlRegister_t::Enable, ControlRegister_t::Unmute, ControlRegister_t::CDAudioEnable); + static constexpr auto SetupValue = ControlRegister::from(ControlRegister::Enable, ControlRegister::Unmute, ControlRegister::CDAudioEnable); - SPU_IO::ControlRegister = SetupValue; - } - - static void setup_data_transfer_control() { - static constexpr uint16_t RequiredValue = (2 << 1); - - DataTransferControl = RequiredValue; + SPU_IO::ControlRegister.write(SetupValue); } static void wait_voices() { - static constexpr int16_t Treshhold = (I16_MAX*0.03); + static constexpr auto Treshhold = SimpleVolume::mute(); try_again: for(const auto& voice : SPU_IO::Voice) { - if(voice.currentVolume > Treshhold) { + if(voice.adsr_volume.read() > Treshhold) { goto try_again; } } } void stop_voices() { - SPU_IO::Key::Off.write({UI32_MAX}); + SPU_IO::Key::Off.write(KeyOff::all()); } void setup() { @@ -88,13 +78,11 @@ namespace JabyEngine { clear_main_volume(); clear_cd_and_ext_audio_volume(); - clear_control_register(); clear_voice(); clear_pmon(); clear_noise_and_echo(); clear_reverb(); - setup_data_transfer_control(); setup_control_register(); } } diff --git a/src/Library/src/BootLoader/start_boot.cpp b/src/Library/src/BootLoader/start_boot.cpp index 111c5fbf..0616f596 100644 --- a/src/Library/src/BootLoader/start_boot.cpp +++ b/src/Library/src/BootLoader/start_boot.cpp @@ -1,34 +1,86 @@ #include "../../internal-include/BootLoader/boot_loader.hpp" -#include +#include "../../internal-include/GPU/gpu_internal.hpp" +#include -// 2x For setup timing -#include -#include +#include "../../internal-include/SPU/spu_mmu.hpp" +#include +#include +#include +#include + +extern "C" uint32_t __heap_start; +extern "C" uint32_t __bss_start; +extern "C" uint32_t __bss_end; +extern "C" uint32_t __bss_len; +extern "C" uint32_t __planschi_start; +extern "C" uint32_t __planschi_end; namespace JabyEngine { + static void test_gte_scale() { + auto matrix = GTE::ROTMATRIX::identity(); + + GTE::scale_matrix(matrix, GTE::VECTOR::create(1.5_gf, 2.0_gf, 1.0_gf)); + printf("|%i|%i|%i|\n", matrix.matrix[0][0], matrix.matrix[0][1], matrix.matrix[0][2]); + printf("|%i|%i|%i|\n", matrix.matrix[1][0], matrix.matrix[1][1], matrix.matrix[1][2]); + printf("|%i|%i|%i|\n", matrix.matrix[2][0], matrix.matrix[2][1], matrix.matrix[2][2]); + } + + static void test_bios_font() { + static constexpr uint16_t SJIS = 0x83B5; + + const auto* font = SysCall::Krom2RawAdd(SJIS); + const auto*const font_end = font + 16; + printf("Loading SJIS from @0x%p\n", font); + + for(; font < font_end; font++) { + const auto cur_char = __builtin_bswap16(*font); + for(uint16_t shift = 1 << 15; shift; shift = shift >> 1) { + printf(cur_char & shift ? "#" : " "); + } + + printf("\n"); + } + } + namespace boot { namespace Start { - //This should become part of the bootloader later - static void enable_DMA() { - DMA_IO::DPCR = DMA_IO::DPCR_t(DMA_IO::DPCR).set(DMA_IO::DPCR_t::SPUEnable).set(DMA_IO::DPCR_t::GPUEnable).set(DMA_IO::DPCR_t::CDROMEnable); + // Thanks to Nicolas Noble! + static void enable_vanilla_bios() { + SysCall::FlushCache(); + SysCall::DequeueCdIntr(); + SysCall::SetDefaultExitFromException(); } static void setup() { - enable_DMA(); + static constexpr auto DebugX = 1; + static constexpr auto DebugY = 0; + static constexpr auto DebugScale = 1.0; + BIOS::identify(); + enable_vanilla_bios(); + // Not used anymore + //Callbacks::setup(); + + __debug_boot_color_at(::JabyEngine::GPU::Color24::Grey(), DebugX, DebugY, DebugScale); + DMA::setup(); + + __debug_boot_color_at(::JabyEngine::GPU::Color24::White(), DebugX, DebugY, DebugScale); + Periphery::setup(); + + __debug_boot_color_at(::JabyEngine::GPU::Color24::Red(), DebugX, DebugY, DebugScale); SPU::stop_voices(); + __debug_boot_color_at(::JabyEngine::GPU::Color24::Green(), DebugX, DebugY, DebugScale); CD::setup(); + __debug_boot_color_at(::JabyEngine::GPU::Color24::Blue(), DebugX, DebugY, DebugScale); Timer::setup(); - const auto start = HighResTime::get_time_stamp(); - printf("Start...\n"); + __debug_boot_color_at(::JabyEngine::GPU::Color24::Yellow(), DebugX, DebugY, DebugScale); GPU::setup(); GPU::display_logo(); - const auto end = HighResTime::get_time_stamp(); - printf("GPU setup took %ims %ius\n", start.milliseconds_to(end), start.microseconds_to(end)); - - //Pause?? + GTE::setup(); + test_bios_font(); + test_gte_scale(); SPU::setup(); } @@ -36,10 +88,18 @@ namespace JabyEngine { } void start() { - printf("Starting Planschbecken\n"); + static constexpr auto DebugX = 0; + static constexpr auto DebugY = 0; + static constexpr auto DebugScale = 1.0; + + __debug_boot_print_at(GPU::Color24::White(), DebugX, DebugY, DebugScale, "Starting Planschbecken\n"); + printf("Heap starts @0x%p\n", &__heap_start); + printf("BSS from 0x%p to 0x%p (%u)\n", &__bss_start, &__bss_end, __bss_len); + __debug_boot_print_at(GPU::Color24::Green(), DebugX, DebugY, DebugScale, "PLANSCHI from 0x%p to 0x%p\n", &__planschi_start, &__planschi_end); boot::Start::setup(); - printf("Running main...\n"); + __debug_boot_print_at(GPU::Color24::Red(), DebugX, DebugY, DebugScale, "Running main...\n"); + GPU::internal::wait_vsync(0); run(); } } \ No newline at end of file diff --git a/src/Library/src/BootLoader/syscall_boot.cpp b/src/Library/src/BootLoader/syscall_boot.cpp new file mode 100644 index 00000000..009a2f3c --- /dev/null +++ b/src/Library/src/BootLoader/syscall_boot.cpp @@ -0,0 +1,88 @@ +#include +#include +#include + +namespace JabyEngine { + namespace boot { + namespace BIOS { + using Version = JabyEngine::BIOS::Version; + + static uint32_t get_bcd_version() { + return *reinterpret_cast(0xBFC00100); + } + + static const char* get_kernel_maker_str() { + return reinterpret_cast(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 = [](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(date_bcd & 0xFF)); + version.date.month = from_bcd(static_cast((date_bcd >> 8) & 0xFF)); + version.date.year = from_bcd(static_cast(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(0xBFC7FF32); + version.copyright = version.gui_version + (strlen(version.gui_version) + 1); + return version; + } + + void identify() { + const_cast(JabyEngine::BIOS::version) = get_bios_version(); + } + } + } +} \ No newline at end of file diff --git a/src/Library/src/BootLoader/timer_boot.cpp b/src/Library/src/BootLoader/timer_boot.cpp index 201e41ba..76c75e15 100644 --- a/src/Library/src/BootLoader/timer_boot.cpp +++ b/src/Library/src/BootLoader/timer_boot.cpp @@ -1,46 +1,33 @@ -#include -#ifdef JABYENGINE_USE_HIGH_PERCISION_TIMER - #include - #include - #define private public - #include - #undef private +#include +#include +#include - namespace JabyEngine { +namespace JabyEngine { + namespace Timer { + extern SysCall::InterruptCallback irq_callback; + } + + namespace boot { namespace Timer { - extern InterrupCallback IRQCallback; - } + using namespace JabyEngine::Timer; + + void setup() { + using namespace Timer_IO; + using namespace Timer_IO_Values; - namespace boot { - namespace Timer { - using namespace JabyEngine::Timer; - - void setup() { - using namespace Timer_IO; + 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); - static constexpr auto Mode = CounterMode_t::from(CounterMode_t::FreeRun, Counter2_v::SyncMode::FreeRun, CounterMode_t::ResetAfterTarget, CounterMode_t::IRQAtTarget, CounterMode_t::IRQEveryTime, CounterMode_t::IRQPulse, Counter2_v::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); - Interrupt::disable_irq(Interrupt::Timer2); + SysCall::EnterCriticalSection(); + SysCall::SysEnqIntRP(SysCall::Priority::Timer2Irq, &irq_callback); + SysCall::ExitCriticalSection(); - __syscall_EnterCriticalSection(); - __syscall_SysEnqIntRP(Timer2Irq, &IRQCallback); - __syscall_ExitCriticalSection(); - - Counter2.set_target_value(HighResTime::TicksFor10ms); - Counter2.set_mode(Mode); - - Interrupt::enable_irq(Interrupt::Timer2); - } + Counter2.set_target_value(HighResTime::TicksFor10ms); + Counter2.set_mode(Mode); } } } -#else - namespace JabyEngine { - namespace boot { - namespace Timer { - void setup() { - } - } - } - } -#endif //JABYENGINE_USE_HIGH_PERCISION_TIMER \ No newline at end of file +} \ No newline at end of file diff --git a/src/Library/src/CD/cd.cpp b/src/Library/src/CD/cd.cpp index 9ef12677..250ba58d 100644 --- a/src/Library/src/CD/cd.cpp +++ b/src/Library/src/CD/cd.cpp @@ -1,140 +1,130 @@ -#include "../../internal-include/CD/cd_internal.hpp" -#include -#include -#include - -namespace JabyEngine { - namespace CD { - namespace internal { - static constexpr auto DataSectorMode = CD_IO::Mode_t::from(CD_IO::Mode_t::DoubleSpeed, CD_IO::Mode_t::DataSector); - - static InterruptVerifierResult interrupt_verifier(); - static void interrupt_handler(uint32_t); - - static SectorBufferAllocator sector_allocator; - static uint32_t cur_lba; - static uint32_t dst_lba; - - CD_IO::Interrupt::Type last_interrupt = CD_IO::Interrupt::Type::None; - uint8_t cmd_interrupt_bit = 0; - State current_state = State::Free; - InterrupCallback callback = { - .next = nullptr, - .handler_function = reinterpret_cast(interrupt_handler), - .verifier_function = interrupt_verifier - }; - - static void pause_cd() { - CD_IO::PortIndex0::change_to(); - Command::send(CD_IO::Command::Pause); - } - - // Requires Index0 - static void read_cd(uint32_t lba) { - const auto loc = CDTimeStamp::from(lba); - - Command::send_wait(CD_IO::Command::SetLoc, loc.get_min_cd(), loc.get_sec_cd(), loc.get_sector_cd()); - Command::send(CD_IO::Command::ReadN); - current_state = State::Reading; - } - - static void read_sector_dma(CD_IO::DataSector& sector) { - static const auto WaitSectorReady = []() { - while(!CD_IO::IndexStatus.is_set(CD_IO::IndexStatus_t::HasDataFifoData)); - }; - - static const auto ReadSector = [](uint32_t* dst) { - DMA_IO::CDROM.set_adr(reinterpret_cast(dst)); - DMA_IO::CDROM.block_ctrl = DMA_IO::BCR_t::SyncMode0::for_cd(); - DMA_IO::CDROM.channel_ctrl = DMA_IO::CHCHR_t::StartCDROM(); - - DMA_IO::CDROM.wait(); - - CD_IO::PortIndex0::Request.reset(); - }; - - WaitSectorReady(); - ReadSector(sector.data); - } - - static void read_sector_to(CD_IO::DataSector& sector) { - CD_IO::PortIndex0::change_to(); - CD_IO::PortIndex0::Request.want_data(); - - // We only support DMA rn - read_sector_dma(sector); - - // Do we ever want to support reading via IO Port? - // Doesn't seem to important when we can use DMA - } - - static InterruptVerifierResult interrupt_verifier() { - if(Interrupt::is_irq(Interrupt::CDROM)) { - const uint8_t old_status = CD_IO::IndexStatus; - - CD_IO::PortIndex1::change_to(); - const auto cur_irq = CD_IO::Interrupt::get_type(CD_IO::PortIndex1::InterruptFlag); - last_interrupt = cur_irq; - CD_IO::Interrupt::ack(CD_IO::PortIndex1::InterruptFlag); - - cmd_interrupt_bit = bit::clear(cmd_interrupt_bit, cur_irq); - if(cur_irq == CD_IO::Interrupt::DataReady) { - // Obtain sector content here - auto* sector = sector_allocator.allocate_sector(); - if(sector) { - //Now obtain sector - read_sector_to(*sector); - - cur_lba++; - if(cur_lba == dst_lba) { - current_state = State::Done; - pause_cd(); - } - } - - else { - current_state = State::BufferFull; - pause_cd(); - } - } - - else if(cur_irq == CD_IO::Interrupt::DiskError) { - current_state = State::Error; - } - - // No masking required because we can only write bit 0 - 2 - CD_IO::IndexStatus = old_status; - return InterruptVerifierResult::ExecuteHandler; - } - - else { - return InterruptVerifierResult::SkipHandler; - } - } - - static void interrupt_handler(uint32_t) { - Interrupt::ack_irq(Interrupt::CDROM); - __syscall_ReturnFromException(); - } - - void read_file(AutoLBAEntry file_info, const SectorBufferAllocator& buffer_allocator) { - cur_lba = file_info.get_lba(); - dst_lba = cur_lba + file_info.get_size_in_sectors(); - sector_allocator = buffer_allocator; - - Command::wait_completed(); - CD_IO::PortIndex0::change_to(); - Command::send_wait(CD_IO::Command::SetMode, DataSectorMode); - - read_cd(cur_lba); - } - - void continue_reading() { - if(current_state == State::BufferFull) { - Command::wait_completed(); - read_cd(cur_lba); - } - } - } - } +#include "../../internal-include/CD/cd_internal.hpp" +#include "../../internal-include/System/callbacks_internal.hpp" +#include +#include +#include +#include + +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(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(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; + } + } + } } \ No newline at end of file diff --git a/src/Library/src/CD/cd_interrupt_handler.cpp b/src/Library/src/CD/cd_interrupt_handler.cpp new file mode 100644 index 00000000..1aa6b607 --- /dev/null +++ b/src/Library/src/CD/cd_interrupt_handler.cpp @@ -0,0 +1,93 @@ +#include "../../internal-include/CD/cd_internal.hpp" +#include + +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(); + } + } + } + } +} \ No newline at end of file diff --git a/src/Library/src/File/Processor/TIM/simpletim_processor.cpp b/src/Library/src/File/Processor/TIM/simpletim_processor.cpp new file mode 100644 index 00000000..7d6b2751 --- /dev/null +++ b/src/Library/src/File/Processor/TIM/simpletim_processor.cpp @@ -0,0 +1,73 @@ +#include "tim_helper.hpp" +#include + +namespace JabyEngine { + namespace FileProcessor { + using GPU::AreaU16; + using GPU::PositionU16; + using GPU::SizeU16; + + namespace { + struct SimpleTIMSize : private SimpleTIM { + constexpr SimpleTIMSize() { + } + + constexpr uint16_t get_texture_width() const { + return SimpleTIM::get_texture_x(); + } + + constexpr uint16_t get_texture_height() const { + return SimpleTIM::get_texture_y(); + } + + constexpr SizeU16 get_texture_size() const { + return {SimpleTIMSize::get_texture_width(), SimpleTIMSize::get_texture_height()}; + } + + constexpr uint16_t get_clut_width() const { + return SimpleTIM::get_clut_x(); + } + + constexpr uint16_t get_clut_height() const { + return SimpleTIM::get_clut_y(); + } + + constexpr SizeU16 get_clut_size() const { + return {SimpleTIMSize::get_clut_width(), SimpleTIMSize::get_clut_height()}; + } + }; + + struct SimpleTIMState : public TIMFileProcessor::GenericTIM { + static SimpleTIMState create(const SimpleTIM& dst_info) { + SimpleTIMState state; + + state.tex_area = AreaU16::create(dst_info.get_texture_position(), SizeU16::create(0, 0)); + state.clut_area = AreaU16::create(dst_info.get_clut_position(), SizeU16::create(0, 0)); + state.words_left = 0; + return state; + } + + virtual Progress parse_header(State::CDDataProcessor& data_proc) override { + if(data_proc.data_bytes >= sizeof(SimpleTIMSize)) { + const auto size_info = data_proc.simple_read_r(); + + this->clut_area.size = size_info.get_clut_size(); + this->tex_area.size = size_info.get_texture_size(); + return Progress::Done; + } + + return Progress::InProgress; + } + + virtual Progress pre_data_parsing(State::CDDataProcessor& data_proc) { + return Progress::Done; + } + }; + } + + State create(const uint32_t* data_adr, const SimpleTIM& file) { + using Callback = Progress(*)(State::CDDataProcessor& data_proc, SimpleTIMState& simple_tim); + return State::from(SimpleTIMState::create(file), data_adr, reinterpret_cast(TIMFileProcessor::parse_header)); + } + } +} \ No newline at end of file diff --git a/src/Library/src/File/Processor/TIM/tim_helper.cpp b/src/Library/src/File/Processor/TIM/tim_helper.cpp new file mode 100644 index 00000000..6a86ed29 --- /dev/null +++ b/src/Library/src/File/Processor/TIM/tim_helper.cpp @@ -0,0 +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(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(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(data_proc.data_adr), generic_tim.tex_area); + return Helper::exchange_and_execute_process_function(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(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; + } + } +} \ No newline at end of file diff --git a/src/Library/src/File/Processor/TIM/tim_helper.hpp b/src/Library/src/File/Processor/TIM/tim_helper.hpp new file mode 100644 index 00000000..dc012e92 --- /dev/null +++ b/src/Library/src/File/Processor/TIM/tim_helper.hpp @@ -0,0 +1,26 @@ +#pragma once +#include "../../../../internal-include/GPU/gpu_internal.hpp" +#include +#include + +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); + } +} \ No newline at end of file diff --git a/src/Library/src/File/Processor/TIM/tim_processor.cpp b/src/Library/src/File/Processor/TIM/tim_processor.cpp new file mode 100644 index 00000000..57d11ca8 --- /dev/null +++ b/src/Library/src/File/Processor/TIM/tim_processor.cpp @@ -0,0 +1,61 @@ +#include "tim_helper.hpp" +#include + +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(); + + if(flag & HAS_CLUT_BIT) { + const auto block_info = data_proc.simple_read_r(); + 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(); + 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(TIMFileProcessor::parse_header)); + } + } +} \ No newline at end of file diff --git a/src/Library/src/File/Processor/cd_file_processor.cpp b/src/Library/src/File/Processor/cd_file_processor.cpp index 04bf7f8a..aaaccedf 100644 --- a/src/Library/src/File/Processor/cd_file_processor.cpp +++ b/src/Library/src/File/Processor/cd_file_processor.cpp @@ -1,6 +1,6 @@ #include "../../../internal-include/CD/cd_internal.hpp" #include -#include +#include namespace JabyEngine { static constexpr auto DisabledCircularBufferSize = 512; @@ -37,12 +37,20 @@ namespace JabyEngine { }(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::CopyTo: + + 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(data_adr, Nothing()); + return FileProcessor::create_custom(data_adr, static_cast(file.type) - static_cast(CDFileType::Custom), file.payload); } }; @@ -56,7 +64,7 @@ namespace JabyEngine { return self.circular_buffer.allocate(); })); - printf(">>> CD needs to load LBA: %i -> %i (is LZ4: [%s])\n", cur_lba.get_lba(), cur_lba.get_size_in_sectors(), cur_lba.is_lz4() ? "Yes" : "No"); + //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() { @@ -86,9 +94,12 @@ namespace JabyEngine { CDFileProcessor::start_cur_job(const_cast(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: @@ -100,7 +111,7 @@ namespace JabyEngine { return Progress::Done; case CD::internal::State::BufferFull: - /* We processd data and unpause the CD drive */ + /* We processed data and unpause the CD drive */ CD::internal::continue_reading(); return Progress::InProgress; diff --git a/src/Library/src/File/Processor/custom_processor.cpp b/src/Library/src/File/Processor/custom_processor.cpp new file mode 100644 index 00000000..4f1cb308 --- /dev/null +++ b/src/Library/src/File/Processor/custom_processor.cpp @@ -0,0 +1,10 @@ +#include +#include + +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()); + } + } +} \ No newline at end of file diff --git a/src/Library/src/File/Processor/nothing_processor.cpp b/src/Library/src/File/Processor/nothing_processor.cpp index 3bedba7b..b2ee5e6a 100644 --- a/src/Library/src/File/Processor/nothing_processor.cpp +++ b/src/Library/src/File/Processor/nothing_processor.cpp @@ -1,16 +1,16 @@ -#include "simplehelper.hpp" +#include namespace JabyEngine { namespace FileProcessor { struct NothingState { }; - static Progress parse_nothing(State::Configuration& config, NothingState& state) { + static Progress parse_nothing(State::CDDataProcessor& data_proc, NothingState& state) { return Progress::Done; } State create(const uint32_t* data_adr, const Nothing& nothing) { - return State::from(NothingState(), reinterpret_cast(data_adr), parse_nothing); + return State::from(NothingState(), data_adr, parse_nothing); } } } \ No newline at end of file diff --git a/src/Library/src/File/Processor/simplehelper.hpp b/src/Library/src/File/Processor/simplehelper.hpp deleted file mode 100644 index bdcfcae5..00000000 --- a/src/Library/src/File/Processor/simplehelper.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __JABYENGINE_INTERNAL_SIMPLE_HELPER_HPP__ -#define __JABYENGINE_INTERNAL_SIMPLE_HELPER_HPP__ - -// Instead of using friend we use this to access the private members -#define private public -#include - -namespace JabyEngine { - namespace FileProcessor { - namespace Helper { - template - static void simple_read(T& dst, State::Configuration& config) { - static constexpr size_t T_SIZE = sizeof(T); - - dst = *reinterpret_cast(config.data_adr); - config.processed(T_SIZE); - } - - template - static Progress exchange_and_execute_process_function(State::GenericProcessRoutine process_routine, State::Configuration& config, T& state) { - config.process_routine = reinterpret_cast(process_routine); - return process_routine(config, state); - } - } - } -} -#endif // !__JABYENGINE_INTERNAL_SIMPLE_HELPER_HPP__ \ No newline at end of file diff --git a/src/Library/src/File/Processor/tim_processor.cpp b/src/Library/src/File/Processor/tim_processor.cpp deleted file mode 100644 index f0528270..00000000 --- a/src/Library/src/File/Processor/tim_processor.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include "../../../internal-include/GPU/gpu_internal.hpp" -#include "simplehelper.hpp" -#include -#include - -namespace JabyEngine { - namespace FileProcessor { - using GPU::PositionU16; - using GPU::SizeU16; - - struct SimpleTIMSize : private SimpleTIM { - constexpr SimpleTIMSize() { - } - - constexpr uint16_t getTextureWidth() const { - return SimpleTIM::getTextureX(); - } - - constexpr uint16_t getTextureHeight() const { - return SimpleTIM::getTextureY(); - } - - constexpr uint16_t getClutWidth() const { - return SimpleTIM::getClutX(); - } - - constexpr uint16_t getClutHeight() const { - return SimpleTIM::getClutY(); - } - }; - - struct SimpleTIMState { - SimpleTIM dst_info; - SimpleTIMSize size_info; - size_t words_left; //32bit values - - constexpr SimpleTIMState(const SimpleTIM& dst_info) : dst_info(dst_info) { - } - }; - - static 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(x, y), SizeU16(w, h)); - GPU::internal::DMA::Receive::set_src(reinterpret_cast(src)); - } - - static void set_gpu_receive_data(const uint32_t* src, SimpleTIMState& state, uint16_t width, uint16_t height) { - state.words_left = (width*height)/2; - set_gpu_receive(src, state.dst_info.getTextureX(), state.dst_info.getTextureY(), width, height); - } - - static Progress parse_data(State::Configuration& config, SimpleTIMState& state) { - const auto config_data_words = (config.data_bytes/sizeof(uint32_t)); - const auto words_to_use = (config_data_words > state.words_left) ? state.words_left : config_data_words; - bool is_last = (words_to_use == state.words_left); - auto block_count = (words_to_use >> 4); - - while(block_count > 0) { - const auto block_send = (block_count > UI16_MAX) ? UI16_MAX : block_count; - - // Send data! - GPU::internal::DMA::wait(); - GPU::internal::DMA::Receive::start(block_send); - block_count -= block_send; - } - - if(is_last) { - // Send words - const auto last_words = (words_to_use & 0b1111); - if(last_words > 0) { - GPU::internal::DMA::wait(); - GPU::internal::DMA::Receive::start(1, last_words); - } - - GPU::internal::DMA::wait(); - GPU::internal::DMA::end(); - - state.words_left = 0; - config.processed(words_to_use*sizeof(uint32_t)); - - return Progress::Done; - } - - else { - const auto words_used = (words_to_use & ~0b1111); - - state.words_left -= words_used; - config.processed(words_used*sizeof(uint32_t)); - return Progress::InProgress; - } - } - - static Progress switch_state_parse_data(State::Configuration& config, SimpleTIMState& state) { - set_gpu_receive_data(reinterpret_cast(config.data_adr), state, state.size_info.getTextureWidth(), state.size_info.getTextureHeight()); - return Helper::exchange_and_execute_process_function(parse_data, config, state); - } - - static Progress parse_clut(State::Configuration& config, SimpleTIMState& state) { - if(const auto result = parse_data(config, state); result != Progress::Done) { - return result; - } - - else { - return switch_state_parse_data(config, state); - } - } - - static Progress parse_header(State::Configuration& config, SimpleTIMState& state) { - if(config.data_bytes >= sizeof(SimpleTIMSize)) { - Helper::simple_read(state.size_info, config); - - //Check if we have a clut to care about - if(state.size_info.getClutWidth() > 0) { - //CLUTs are 16bit full color anyway - set_gpu_receive_data(reinterpret_cast(config.data_adr), state, state.size_info.getClutWidth(), state.size_info.getClutHeight()); - return Helper::exchange_and_execute_process_function(parse_clut, config, state); - } - - //We have direct data - else { - return switch_state_parse_data(config, state); - } - } - - return Progress::InProgress; - } - - State create(const uint32_t* data_adr, const SimpleTIM& file) { - return State::from(SimpleTIMState(file), reinterpret_cast(data_adr), parse_header); - } - } -} -#undef private \ No newline at end of file diff --git a/src/Library/src/File/Processor/vag_processor.cpp b/src/Library/src/File/Processor/vag_processor.cpp new file mode 100644 index 00000000..66098ed7 --- /dev/null +++ b/src/Library/src/File/Processor/vag_processor.cpp @@ -0,0 +1,79 @@ +#include "../../../internal-include/SPU/spu_internal.hpp" +#include +#include +#include +#include +#include + +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(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(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(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); + } + } +} \ No newline at end of file diff --git a/src/Library/src/GPU/gpu.cpp b/src/Library/src/GPU/gpu.cpp index b4004e80..d7a86db6 100644 --- a/src/Library/src/GPU/gpu.cpp +++ b/src/Library/src/GPU/gpu.cpp @@ -1,39 +1,119 @@ -#include "../../internal-include/GPU/gpu_internal.hpp" - -namespace JabyEngine { - namespace GPU { - uint8_t Screen :: CurrentDisplayAreaID = 1; //< Setup will call exchange and set it to 0 - - namespace internal { - typedef ::JabyEngine::GPU::Screen PublicScreenClass; - - #ifdef JABYENGINE_PAL - static constexpr uint16_t ScanlinesV = 288; - #else - static constexpr uint16_t ScanlinesV = 240; - #endif //JABYENGINE_PAL - - void Screen :: exchange_buffer_and_display() { - GPU::internal::set_draw_area(0, (Display::Height*PublicScreenClass::CurrentDisplayAreaID)); - PublicScreenClass::CurrentDisplayAreaID ^= 1; - GPU_IO::GP1 = GPU_IO::Command::DisplayArea(0, (Display::Height*PublicScreenClass::CurrentDisplayAreaID)); - } - } - - #ifndef USE_NO$PSX - void Screen :: set_offset(uint16_t x, uint16_t y) { - x += 78; - y += 43; - - GPU_IO::GP1 = GPU_IO::Command::HorizontalDisplayRange((x << 3), (x + Display::Width) << 3); - GPU_IO::GP1 = GPU_IO::Command::VerticalDisplayRange(y, y + Display::Height); - } - #else - void Screen :: set_offset(uint16_t x, uint16_t y) { - GPU_IO::GP1 = GPU_IO::Command::HorizontalDisplayRange(x, (x + Display::Width*8)); - GPU_IO::GP1 = GPU_IO::Command::VerticalDisplayRange(y - (ScanlinesV/2), y + (ScanlinesV/2)); - } - #endif //USE_NO$PSX - } - +#include "../../internal-include/GPU/gpu_internal.hpp" +#include +#include +#include + +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((TexturePageHeight*PublicDisplay::current_id)))); + return draw_area_y; + } + + void wait_vsync(uint8_t syncs) { + volatile auto& vsync_count = reinterpret_cast(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(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(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; + } + } } \ No newline at end of file diff --git a/src/Library/src/GTE/gte.cpp b/src/Library/src/GTE/gte.cpp new file mode 100644 index 00000000..5ec27167 --- /dev/null +++ b/src/Library/src/GTE/gte.cpp @@ -0,0 +1,129 @@ +#include + +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< 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(::sin(value)), + .cos = static_cast(::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; + } + } +} \ No newline at end of file diff --git a/src/Library/src/Periphery/periphery.cpp b/src/Library/src/Periphery/periphery.cpp new file mode 100644 index 00000000..82d4bf28 --- /dev/null +++ b/src/Library/src/Periphery/periphery.cpp @@ -0,0 +1,136 @@ +#include "../../internal-include/periphery_internal.hpp" +#include +#include + +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(cont.header.state) & 0xF); + } + + static void advance_config(RawController &cont) { + cont.header.state = static_cast((static_cast(cont.header.state) << 1)); + } + + static uint8_t* raw_device_data(RawController &cont) { + return reinterpret_cast(&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(LED::State::On); + data[selID] = static_cast(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((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(); + } + } +} \ No newline at end of file diff --git a/src/Library/src/SPU/spu.cpp b/src/Library/src/SPU/spu.cpp new file mode 100644 index 00000000..a8ddc2ac --- /dev/null +++ b/src/Library/src/SPU/spu.cpp @@ -0,0 +1,31 @@ +#include "../../internal-include/SPU/spu_internal.hpp" +#include "../../internal-include/SPU/spu_mmu.hpp" +#include +#include +#include + +#include + +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(reinterpret_cast(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()); + } + } +} \ No newline at end of file diff --git a/src/Library/src/SPU/spu_mmu.cpp b/src/Library/src/SPU/spu_mmu.cpp new file mode 100644 index 00000000..7692ee75 --- /dev/null +++ b/src/Library/src/SPU/spu_mmu.cpp @@ -0,0 +1,136 @@ +#include "../../internal-include/SPU/spu_mmu.hpp" +#include +#include +#include +#include +#include +#ifdef __DEBUG_SPU_MMU__ + #include +#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(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(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(); + } + } + } +} \ No newline at end of file diff --git a/src/Library/src/System/callbacks.cxx b/src/Library/src/System/callbacks.cxx new file mode 100644 index 00000000..5a8f7f4a --- /dev/null +++ b/src/Library/src/System/callbacks.cxx @@ -0,0 +1,44 @@ +#include "../../internal-include/System/callbacks_internal.hpp" +#include "../../internal-include/CD/cd_internal.hpp" +#include + +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(); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Library/src/System/string.cpp b/src/Library/src/System/string.cpp new file mode 100644 index 00000000..fa264af1 --- /dev/null +++ b/src/Library/src/System/string.cpp @@ -0,0 +1,63 @@ +#include + +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 +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(dest), val, len); + return dest; +} + +static void* cplx_memset(void* dst, int val, size_t len) { + void*const org_dst = dst; + + if(reinterpret_cast(dst) & 0x2 == 0) { + dst = core_memset(static_cast(dst), val, len); + } + + if(reinterpret_cast(dst) & 0x1 == 0) { + dst = core_memset(static_cast(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); + } +} \ No newline at end of file diff --git a/src/Library/src/System/syscall.cpp b/src/Library/src/System/syscall.cpp new file mode 100644 index 00000000..e28d2fad --- /dev/null +++ b/src/Library/src/System/syscall.cpp @@ -0,0 +1,8 @@ +#include +#include + +namespace JabyEngine { + namespace BIOS { + const Version version = {0}; + } +} \ No newline at end of file diff --git a/src/Library/src/Timer/frame_timer.cpp b/src/Library/src/Timer/frame_timer.cpp new file mode 100644 index 00000000..1c085633 --- /dev/null +++ b/src/Library/src/Timer/frame_timer.cpp @@ -0,0 +1,5 @@ +#include + +namespace JabyEngine { + uint32_t MasterTime :: value = 0; +} \ No newline at end of file diff --git a/src/Library/src/Timer/high_res_timer.cpp b/src/Library/src/Timer/high_res_timer.cpp index 7a7fd3d9..2d9436cd 100644 --- a/src/Library/src/Timer/high_res_timer.cpp +++ b/src/Library/src/Timer/high_res_timer.cpp @@ -1,38 +1,27 @@ -#include -#ifdef JABYENGINE_USE_HIGH_PERCISION_TIMER - #define private public - #include - #include - #include - #include - #undef private +#include +#include +#include - namespace JabyEngine { - volatile uint16_t HighResTime :: global_counter_10ms = 0; - - namespace Timer { - static InterruptVerifierResult interrupt_verifier() { - if(Interrupt::is_irq(Interrupt::Timer2)) { - return InterruptVerifierResult::ExecuteHandler; - } - - else { - return InterruptVerifierResult::SkipHandler; - } - } - - static void interrupt_handler(uint32_t) { - HighResTime::global_counter_10ms = HighResTime::global_counter_10ms + 1; +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); - __syscall_ReturnFromException(); + return SysCall::InterruptVerifierResult::ExecuteHandler; + } + + else { + return SysCall::InterruptVerifierResult::SkipHandler; } - - InterrupCallback IRQCallback = { - .next = nullptr, - .handler_function = reinterpret_cast(interrupt_handler), - .verifier_function = interrupt_verifier - }; } + + 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); } -#endif //JABYENGINE_USE_HIGH_PERCISION_TIMER \ No newline at end of file +} \ No newline at end of file diff --git a/src/Library/src/busyloop.s b/src/Library/src/busyloop.s new file mode 100644 index 00000000..91e5daad --- /dev/null +++ b/src/Library/src/busyloop.s @@ -0,0 +1,26 @@ + .set noreorder + .section .text, "ax", @progbits + .align 2 + .global busy_loop + .type busy_loop, @function + +busy_loop: + sw $a0, 0($sp) + lw $v0, 0($sp) + lw $v1, 0($sp) + nop + addiu $v1, -1 + beqz $v0, early_exit + sw $v1, 0($sp) + +busy_loop_loop: + lw $v0, 0($sp) + lw $v1, 0($sp) + nop + addiu $v1, -1 + bnez $v0, busy_loop_loop + sw $v1, 0($sp) + +early_exit: + jr $ra + nop diff --git a/src/Library/src/run.cpp b/src/Library/src/run.cpp index 37038004..4751f2f4 100644 --- a/src/Library/src/run.cpp +++ b/src/Library/src/run.cpp @@ -1,10 +1,23 @@ -#include +#include +#include +extern "C" uint32_t __bss_start; +extern "C" uint32_t __bss_end; extern void main(); namespace JabyEngine { + static void clear_bss() { + uint32_t* bss_adr = &__bss_start; + while(bss_adr < &__bss_end) { + *bss_adr = 0; + bss_adr++; + } + } + // Executes the game void __no_return run() { + clear_bss(); + main(); printf("Stop!!\n"); while(true); diff --git a/src/Library/src/syscall_printf.s b/src/Library/src/syscall_printf.s index 08d7c540..57322d6e 100644 --- a/src/Library/src/syscall_printf.s +++ b/src/Library/src/syscall_printf.s @@ -1,12 +1,11 @@ - .set push - .set noreorder -#.section .ramtext, "ax", @progbits - .align 2 - .global __syscall_printf - .type __syscall_printf, @function - -__syscall_printf: - li $t2, 0xa0 - jr $t2 - li $t1, 0x3f - \ No newline at end of file + .set push + .set noreorder + .section .text, "ax", @progbits + .align 2 + .global _ZN10JabyEngine7SysCall6printfEPKcz + .type _ZN10JabyEngine7SysCall6printfEPKcz, @function + +_ZN10JabyEngine7SysCall6printfEPKcz: + li $t2, 0xa0 + jr $t2 + li $t1, 0x3f diff --git a/src/Tools/.config_build_all/linux.bat b/src/Tools/.config_build_all/linux.bat deleted file mode 100644 index 901cc3fc..00000000 --- a/src/Tools/.config_build_all/linux.bat +++ /dev/null @@ -1,4 +0,0 @@ -set bin_linux_projects=%bin_projects% %bin_linux_projects% -set clean_projects_linux=%clean_projects% %clean_projects_linux% -set bin_projects= -set clean_projects= \ No newline at end of file diff --git a/src/Tools/.config_build_all/recommended.bat b/src/Tools/.config_build_all/recommended.bat deleted file mode 100644 index 4779c8f0..00000000 --- a/src/Tools/.config_build_all/recommended.bat +++ /dev/null @@ -1,4 +0,0 @@ -set bin_projects=psxcdgen psxcdread psxcdgen_ex wslpath -set bin_linux_projects=cpp_out jaby_engine_fconv mkoverlay -set clean_projects=cdtypes -set clean_projects_linux=tool_helper \ No newline at end of file diff --git a/src/Tools/.config_build_all/windows.bat b/src/Tools/.config_build_all/windows.bat deleted file mode 100644 index c940a9cc..00000000 --- a/src/Tools/.config_build_all/windows.bat +++ /dev/null @@ -1,4 +0,0 @@ -set bin_projects=%bin_projects% %bin_linux_projects% -set clean_projects=%clean_projects% %clean_projects_linux% -set bin_linux_projects= -set clean_projects_linux= \ No newline at end of file diff --git a/src/Tools/.gitignore b/src/Tools/.gitignore index cc8e0b0d..79637d92 100644 --- a/src/Tools/.gitignore +++ b/src/Tools/.gitignore @@ -3,4 +3,5 @@ Input/** Output/** *.lock -**/Tests/Test_*.* \ No newline at end of file +**/Tests/Test_*.* +**/Planschbecken.bin \ No newline at end of file diff --git a/src/Tools/Common.mk b/src/Tools/Common.mk new file mode 100644 index 00000000..772d68d5 --- /dev/null +++ b/src/Tools/Common.mk @@ -0,0 +1,35 @@ +BUILD_PROFILE ?= debug +CARGO_CMD ?= build +WINDOWS_TARGET ?= x86_64-pc-windows-gnu +UNIX_TARGET ?= x86_64-unknown-linux-gnu + +WINDOWS_ARTIFACT = ./target/$(WINDOWS_TARGET)/$(BUILD_PROFILE)/$(ARTIFACT).exe +UNIX_ARTIFACT = ./target/$(UNIX_TARGET)/$(BUILD_PROFILE)/$(ARTIFACT) + +define cp_artifact + $(if $(findstring build,$(CARGO_CMD)), + @mkdir -p $(dir $(1)) + @cp $(1) $(2) + ) +endef + +define cargo_windows_default + $(if $(findstring upgrade,$(CARGO_CMD)), + cargo $(CARGO_CMD) --$(BUILD_PROFILE), + + cargo $(CARGO_CMD) --$(BUILD_PROFILE) --target=$(WINDOWS_TARGET) + $(call cp_artifact,$(WINDOWS_ARTIFACT), ../../../bin/$(ARTIFACT).exe) + ) +endef + +define cargo_unix_default + $(if $(findstring upgrade,$(CARGO_CMD)), + cargo $(CARGO_CMD) --$(BUILD_PROFILE), + + cargo $(CARGO_CMD) --$(BUILD_PROFILE) --target=$(UNIX_TARGET) + $(call cp_artifact,$(UNIX_ARTIFACT), ../../../bin/$(ARTIFACT)) + ) +endef + +# Run `cargo install cargo-edit --locked`to support upgrade +# Windows build requires "rustup target add x86_64-pc-windows-gnu" and "sudo apt-get install mingw-w64" \ No newline at end of file diff --git a/src/Tools/Makefile b/src/Tools/Makefile new file mode 100644 index 00000000..e78b7f49 --- /dev/null +++ b/src/Tools/Makefile @@ -0,0 +1,9 @@ +SUPPORT_PROJECTS = cdtypes tool_helper +PROJECTS = cpp_out psxfileconv mkoverlay psxcdgen_ex psxreadmap wslpath +.PHONY: $(PROJECTS) + +$(foreach var,$(PROJECTS),$(var)): + $(MAKE) -C ./$@ $(MAKECMDGOALS) + +all-windows: $(PROJECTS) +all: $(PROJECTS) \ No newline at end of file diff --git a/src/Tools/Tests/Test.mk b/src/Tools/Tests/Test.mk index cfde7ba9..bdcd7e36 100644 --- a/src/Tools/Tests/Test.mk +++ b/src/Tools/Tests/Test.mk @@ -4,7 +4,7 @@ test_cpp_out: always @echo "Planschbecken" | ./../cpp_out/target/x86_64-unknown-linux-gnu/release/cpp_out --name Dino -o "Test_Planschbecken.cpp" @echo "Planschbecken" | ./../cpp_out/target/x86_64-unknown-linux-gnu/release/cpp_out --name Dino -o "Test_Planschbecken.hpp" -test_jaby_engine_fconv: always -# @./../jaby_engine_fconv/target/x86_64-unknown-linux-musl/release/jaby_engine_fconv -o Test_Planschi.bin Test_PNG.PNG simple-tim full16 - @./../jaby_engine_fconv/target/x86_64-unknown-linux-gnu/release/jaby_engine_fconv --lz4 -o Test_Planschi.bin ../../Library/ressources/Splash.PNG simple-tim full16 +test_psxfileconv: always +# @./../psxfileconv/target/x86_64-unknown-linux-musl/release/psxfileconv -o Test_Planschi.bin Test_PNG.PNG simple-tim full16 + @./../psxfileconv/target/x86_64-unknown-linux-gnu/release/psxfileconv --lz4 -o Test_Planschi.bin ../../Library/ressources/Splash.PNG simple-tim full16 always: ; \ No newline at end of file diff --git a/src/Tools/Tools.code-workspace b/src/Tools/Tools.code-workspace index a1732433..7b35fa07 100644 --- a/src/Tools/Tools.code-workspace +++ b/src/Tools/Tools.code-workspace @@ -1,87 +1,82 @@ -{ - "folders": [ - { - "path": "." - } - ], - "settings": {}, - "tasks": { - "version": "2.0.0", - "tasks": [ - { - "label": "all", - "type": "shell", - "command": "./build_all.bat ${input:cargo cmd}", - "group": { - "kind": "build" - } - }, - { - "label": "cargo", - "type": "shell", - "command": "./run_cargo ${input:project} ${input:cargo cmd} ${input:build cfg} ${input:cargo target}", - "group": { - "kind": "build", - }, - "options": { - "env": { - "CARGO_RUN_ARGS": "${input:cargo run args}" - } - } - }, - { - "label": "cargo test", - "type": "shell", - "command": "./run_cargo ${input:project} test release ${input:cargo target}" - }, - { - "label": "run test make", - "type": "shell", - "command": "wsl make -f Test.mk test_${input:project}", - "group": { - "kind": "build", - }, - "options": { - "cwd": "${workspaceFolder}/Tests" - }, - "dependsOn": ["cargo test"], - "dependsOrder": "sequence" - } - ], - "inputs": [ - { - "id": "build cfg", - "type": "pickString", - "options": ["debug", "release"], - "default": "release", - "description": "build configuration" - }, - { - "id": "project", - "type": "pickString", - "options": ["cdtypes", "cpp_out", "jaby_engine_fconv", "mkoverlay", "psxcdgen", "psxcdgen_ex", "psxcdread", "tool_helper", "wslpath"], - "description": "project to build" - }, - { - "id": "cargo cmd", - "type":"pickString", - "options": ["build", "check", "update", "clean", "run"], - "default": "build", - "description": "cargo command to run" - }, - { - "id": "cargo target", - "type": "pickString", - "options": ["windows", "linux"], - "description": "The target for the tool to build" - }, - { - "id": "cargo run args", - "type": "pickString", - "options": ["", "--help", "--list -o ../Tests/Test_Planschbecken psx bin-cue ../Tests/ISO_Planschbecken.xml"], - "default": "", - "description": "Argument options to pass to cargo run" - } - ] - } +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "cargo_task": [ + "./ all!Unix: All", + "cpp_out all!Unix: cpp_out", + "mkoverlay all!Unix: mkoverlay", + "psxcdgen_ex all!Unix: psxcdgen_ex", + "psxcdread all!Unix: psxcdread", + "psxfileconv all!Unix: psxfileconv", + "psxreadmap all!Unix: psxreadmap", + "wslpath all!Unix: wslpath", + + "./ all-windows!Windows: All", + "cpp_out all-windows!Windows: cpp_out", + "mkoverlay all-windows!Windows: mkoverlay", + "psxcdgen_ex all-windows!Windows: psxcdgen_ex", + "psxcdread all-windows!Windows: psxcdread", + "psxfileconv all-windows!Windows: psxfileconv", + "psxreadmap all-windows!Windows: psxreadmap", + "wslpath all-windows!Windows: wslpath" + ] + }, + "tasks": { + "version": "2.0.0", + "tasks": [ + { + "label": "cargo", + "type": "shell", + "group": { + "kind": "build" + }, + "windows": { + "command": "wsl --shell-type login make -C ${input:windows_cargo_task} CARGO_CMD=${input:cargo cmd} BUILD_PROFILE=${input:build cfg}" + }, + "linux": { + "command": "make -C ${input:linux_cargo_task} BUILD_PROFILE=${input:build cfg}" + }, + "problemMatcher": [] + } + ], + "inputs": [ + { + "id": "windows_cargo_task", + "type": "command", + "command": "shellCommand.execute", + "args": { + "command": "powershell", + "commandArgs": ["-command", "'${config:cargo_task}'.Replace(',',\"`n\")"], + "fieldSeparator": "!" + } + }, + { + "id": "linux_cargo_task", + "type": "command", + "command": "shellCommand.execute", + "args": { + "command": "echo ${config:cargo_task} | tr , \\\\n", + "fieldSeparator": "!" + } + }, + { + "id": "build cfg", + "type": "pickString", + "options": ["debug", "release", "compatible", "incompatible"], + "default": "release", + "description": "build configuration" + }, + { + "id": "cargo cmd", + "type":"pickString", + "options": ["build", "check", "update", "upgrade", "clean", "run", "tree"], + "default": "build", + "description": "cargo command to run" + } + ] + } } \ No newline at end of file diff --git a/src/Tools/build_all.bat b/src/Tools/build_all.bat deleted file mode 100644 index 819747ff..00000000 --- a/src/Tools/build_all.bat +++ /dev/null @@ -1,39 +0,0 @@ -@echo off -setlocal EnableDelayedExpansion -rem build_all [clean] [recommended|windows|linux] - -call .config_build_all/recommended.bat -IF NOT "%~2" == "" ( - set config_path=.config_build_all/%~2.bat - IF exist "!config_path!" ( - call !config_path! - ) ELSE ( - @echo "Configuration !config_path! not found" - exit -1 - ) -) - -set projects=%bin_projects% -set linux_projects=%bin_linux_projects% -set build_type=build -set cur_dir=%cd% - -IF NOT "%~1" == "" ( - IF "%~1" == "clean" ( - set build_type=clean - set projects=%projects% %clean_projects% - set linux_projects=%linux_projects% %clean_projects_linux% - ) ELSE ( - set build_type=%~1 - ) -) - -for %%a in (%projects%) do ( - call .\run_cargo %%a %build_type% release windows - cd %cur_dir% -) - -for %%a in (%linux_projects%) do ( - call .\run_cargo %%a %build_type% release linux - cd %cur_dir% -) \ No newline at end of file diff --git a/src/Tools/cdtypes/Cargo.toml b/src/Tools/cdtypes/Cargo.toml index b6ef204c..639c003f 100644 --- a/src/Tools/cdtypes/Cargo.toml +++ b/src/Tools/cdtypes/Cargo.toml @@ -1,11 +1,12 @@ [package] name = "cdtypes" -version = "0.5.5" +version = "1.0.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[profile.release] +panic = "abort" [dependencies] -byteorder = "*" -paste = "*" -chrono = "*" \ No newline at end of file +byteorder = "1.5.0" +chrono = "0.4.39" +paste = "1.0.15" diff --git a/src/Tools/cdtypes/Makefile b/src/Tools/cdtypes/Makefile new file mode 100644 index 00000000..d2909708 --- /dev/null +++ b/src/Tools/cdtypes/Makefile @@ -0,0 +1,13 @@ +include ../Common.mk + +ARTIFACT = cdtypes + +.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) +$(WINDOWS_ARTIFACT): + $(call cargo_windows_default) + +$(UNIX_ARTIFACT): + $(call cargo_unix_default) + +all-windows: $(WINDOWS_ARTIFACT) +all: $(UNIX_ARTIFACT) \ No newline at end of file diff --git a/src/Tools/cdtypes/src/cd/mod.rs b/src/Tools/cdtypes/src/cd/mod.rs index 3c64cfc9..6b5193f7 100644 --- a/src/Tools/cdtypes/src/cd/mod.rs +++ b/src/Tools/cdtypes/src/cd/mod.rs @@ -2,7 +2,7 @@ pub mod reader; pub mod sector; use sector::*; -use reader::Reader as CDReader; +use reader::{UnknownSectorBehavior, Reader as CDReader}; use super::{Error, types as types}; use types::{cue::{Specifier, DataType, DataTypeEnd}, lsb_msb::ReadWriteEndian, pvd::PrimaryVolumeDescriptor, sector::{Mode2Form1, SubHeaderForm}}; use std::fs::File; @@ -191,7 +191,7 @@ pub struct CD { } impl CD { - pub fn from_file(file: File, specifier: Option>) -> Result { + pub fn from_file(file: File, specifier: Option>, unk_sector_behav: UnknownSectorBehavior) -> Result { let data_type_ends = { if let Some(specifier) = specifier { DataTypeEnd::parse_cue_specifier(specifier)? @@ -201,7 +201,7 @@ impl CD { Vec::new() } }; - let reader = CDReader::new(file, &data_type_ends)?; + let reader = CDReader::new(file, &data_type_ends, unk_sector_behav)?; let mut sectors = Vec::new(); for sector in reader { diff --git a/src/Tools/cdtypes/src/cd/reader.rs b/src/Tools/cdtypes/src/cd/reader.rs index f6aa8150..ed25726c 100644 --- a/src/Tools/cdtypes/src/cd/reader.rs +++ b/src/Tools/cdtypes/src/cd/reader.rs @@ -1,18 +1,28 @@ -use super::sector::Sector; +use super::{sector::Sector, types::time::Time}; use super::super::{Error, types::{cue::{DataType, DataTypeEnd}, sector::*}}; use std::io::Read; +#[derive(Copy, Clone)] +pub enum UnknownSectorBehavior { + CauseError, + CauseWarningAddEmpty, + TreatAsAudio, +} + pub struct Reader<'a> { file: std::fs::File, data_type_guide: &'a Vec, lba: usize, + unk_sector_behav: UnknownSectorBehavior, active: bool } impl<'a> Reader<'a> { - pub fn new(file: std::fs::File, data_type_guide: &'a Vec) -> Result { + const CD_PREGAP_SECTORS:usize = Time::cd_pregap().as_sectors(); + + pub fn new(file: std::fs::File, data_type_guide: &'a Vec, unk_sector_behav: UnknownSectorBehavior) -> Result { Ok(Reader{ - file, data_type_guide, lba: 0, active: true + file, data_type_guide, unk_sector_behav, lba: Self::CD_PREGAP_SECTORS, active: true }) } @@ -23,11 +33,10 @@ impl<'a> Reader<'a> { return Some(data_type.r#type.clone()); } } - None } - fn process_audio_sector(&mut self) -> Result, Error> { + fn process_audio_sector(&mut self, _unk_sector_behav: UnknownSectorBehavior) -> Result, Error> { let mut buffer = [0;std::mem::size_of::