mirror of https://github.com/mgba-emu/mgba.git
PSP2: Initial support
This commit is contained in:
parent
3f2426ef4c
commit
2e43210eac
|
@ -192,7 +192,7 @@ if(APPLE)
|
|||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=10.6")
|
||||
endif()
|
||||
|
||||
if(NOT HAIKU AND NOT MSVC)
|
||||
if(NOT HAIKU AND NOT MSVC AND NOT PSP2)
|
||||
list(APPEND OS_LIB m)
|
||||
endif()
|
||||
|
||||
|
@ -452,6 +452,10 @@ if(BUILD_PERF)
|
|||
install(FILES ${CMAKE_SOURCE_DIR}/tools/perf.py DESTINATION "${CMAKE_INSTALL_LIBDIR}/${BINARY_NAME}" COMPONENT ${BINARY_NAME}-perf)
|
||||
endif()
|
||||
|
||||
if(PSP2)
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/psp2 ${CMAKE_BINARY_DIR}/psp2)
|
||||
endif()
|
||||
|
||||
# Packaging
|
||||
set(CPACK_PACKAGE_VERSION ${VERSION_STRING})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${LIB_VERSION_MAJOR})
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
#include "gba/serialize.h"
|
||||
#include "util/hash.h"
|
||||
|
||||
#ifdef PSP2
|
||||
#include <psp2/rtc.h>
|
||||
#endif
|
||||
|
||||
static void _readPins(struct GBACartridgeHardware* hw);
|
||||
static void _outputPins(struct GBACartridgeHardware* hw, unsigned pins);
|
||||
|
||||
|
@ -258,6 +262,10 @@ void _rtcUpdateClock(struct GBACartridgeHardware* hw) {
|
|||
struct tm date;
|
||||
#ifdef _WIN32
|
||||
date = *localtime(&t);
|
||||
#elif defined(PSP2)
|
||||
SceRtcTime scertc;
|
||||
sceRtcGetCurrentClockLocalTime(&scertc);
|
||||
sceRtcGetTime_t(&scertc, &t);
|
||||
#else
|
||||
localtime_r(&t, &date);
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
file(GLOB PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/psp2/*.c)
|
||||
|
||||
set(PLATFORM_LIBRARY -lSceCtrl_stub -lSceRtc_stub -lSceGxm_stub -lSceDisplay_stub -lm_stub)
|
||||
|
||||
add_executable(${BINARY_NAME}.elf ${PLATFORM_SRC})
|
||||
target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${PLATFORM_LIBRARY})
|
||||
set_target_properties(${BINARY_NAME}.elf PROPERTIES OUTPUT_NAME ${BINARY_NAME}.elf)
|
||||
add_custom_command(TARGET ${BINARY_NAME}.elf POST_BUILD COMMAND ${FIXUP} -q -S ${BINARY_NAME}.elf ${BINARY_NAME}.velf MAIN_DEPENDENCY ${BINARY_NAME}.elf)
|
|
@ -0,0 +1,44 @@
|
|||
if(DEFINED ENV{DEVKITPRO})
|
||||
set(DEVKITPRO $ENV{DEVKITPRO})
|
||||
else()
|
||||
message(FATAL_ERROR "Could not find DEVKITPRO in environment")
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{DEVKITARM})
|
||||
set(DEVKITARM $ENV{DEVKITARM})
|
||||
else()
|
||||
set(DEVKITARM ${DEVKITPRO}/devkitARM)
|
||||
endif()
|
||||
|
||||
set(toolchain_dir ${DEVKITARM}/psp2)
|
||||
set(toolchain_bin_dir ${toolchain_dir}/bin)
|
||||
set(cross_prefix ${DEVKITARM}/bin/arm-none-eabi-)
|
||||
set(inc_flags -I${toolchain_dir}/include)
|
||||
set(arch_flags "-march=armv7-a -mtune=cortex-a9")
|
||||
set(link_flags "-L${toolchain_dir}/lib -specs=psp2.specs ${arch_flags}")
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Generic CACHE INTERNAL "system name")
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm CACHE INTERNAL "processor")
|
||||
set(CMAKE_LIBRARY_ARCHITECTURE arm-none-eabi CACHE INTERNAL "abi")
|
||||
set(CMAKE_AR ${cross_prefix}ar CACHE INTERNAL "archiver")
|
||||
set(CMAKE_C_COMPILER ${cross_prefix}gcc CACHE INTERNAL "c compiler")
|
||||
set(CMAKE_CXX_COMPILER ${cross_prefix}g++ CACHE INTERNAL "cxx compiler")
|
||||
set(CMAKE_ASM_COMPILER ${cross_prefix}gcc CACHE INTERNAL "assembler")
|
||||
set(common_flags "${arch_flags} -fno-reorder-functions -fno-optimize-sibling-calls ${inc_flags}")
|
||||
set(CMAKE_C_FLAGS ${common_flags} CACHE INTERNAL "c compiler flags")
|
||||
set(CMAKE_ASM_FLAGS ${common_flags} CACHE INTERNAL "c compiler flags")
|
||||
set(CMAKE_CXX_FLAGS ${common_flags} CACHE INTERNAL "cxx compiler flags")
|
||||
set(CMAKE_LINKER ${cross_prefix}ld CACHE INTERNAL "linker")
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "exe link flags")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "module link flags")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS ${link_flags} CACHE INTERNAL "shared link flags")
|
||||
|
||||
set(PKG_CONFIG_EXECUTABLE "/dev/null" CACHE INTERNAL "" FORCE)
|
||||
|
||||
set(FIXUP ${toolchain_bin_dir}/psp2-fixup)
|
||||
|
||||
set(PSP2 ON)
|
||||
add_definitions(-DPSP2)
|
||||
|
||||
set(CMAKE_C_COMPILER_WORKS 1) # Skip test
|
|
@ -0,0 +1,158 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "gba/gba.h"
|
||||
#include "gba/video.h"
|
||||
|
||||
#include "gba/renderers/video-software.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/vfs.h"
|
||||
#include "platform/psp2/sce-vfs.h"
|
||||
|
||||
#include <psp2/ctrl.h>
|
||||
#include <psp2/display.h>
|
||||
#include <psp2/gxm.h>
|
||||
#include <psp2/moduleinfo.h>
|
||||
#include <psp2/kernel/memorymgr.h>
|
||||
#include <psp2/kernel/processmgr.h>
|
||||
|
||||
PSP2_MODULE_INFO(0, 0, "mGBA");
|
||||
|
||||
#define PSP2_HORIZONTAL_PIXELS 960
|
||||
#define PSP2_VERTICAL_PIXELS 544
|
||||
|
||||
static void allocFramebuffer(SceDisplayFrameBuf* fb, int nfbs, SceUID* memblock) {
|
||||
size_t baseSize = 0x200000;
|
||||
size_t size = baseSize * nfbs;
|
||||
*memblock = sceKernelAllocMemBlock("fb", SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, size, 0);
|
||||
sceKernelGetMemBlockBase(*memblock, &fb[0].base);
|
||||
sceGxmMapMemory(fb[0].base, size, SCE_GXM_MEMORY_ATTRIB_RW);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < nfbs; ++i) {
|
||||
fb[i].size = sizeof(fb[i]);
|
||||
fb[i].pitch = PSP2_HORIZONTAL_PIXELS;
|
||||
fb[i].width = PSP2_HORIZONTAL_PIXELS;
|
||||
fb[i].height = PSP2_VERTICAL_PIXELS;
|
||||
fb[i].pixelformat = PSP2_DISPLAY_PIXELFORMAT_A8B8G8R8;
|
||||
fb[i].base = (char*) fb[0].base + i * baseSize;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("%s initializing", projectName);
|
||||
bool running = true;
|
||||
|
||||
struct GBAVideoSoftwareRenderer renderer;
|
||||
GBAVideoSoftwareRendererCreate(&renderer);
|
||||
|
||||
struct GBA* gba = anonymousMemoryMap(sizeof(struct GBA));
|
||||
struct ARMCore* cpu = anonymousMemoryMap(sizeof(struct ARMCore));
|
||||
|
||||
printf("GBA: %08X", gba);
|
||||
printf("CPU: %08X", cpu);
|
||||
int activeKeys = 0;
|
||||
|
||||
SceGxmInitializeParams gxmParams;
|
||||
gxmParams.flags = 0;
|
||||
gxmParams.displayQueueMaxPendingCount = 2;
|
||||
gxmParams.displayQueueCallback = 0;
|
||||
gxmParams.displayQueueCallbackDataSize = 0;
|
||||
gxmParams.parameterBufferSize = 0x1000000;
|
||||
int ret = sceGxmInitialize(&gxmParams);
|
||||
printf("sceGxmInitialize: %08X", ret);
|
||||
|
||||
SceDisplayFrameBuf fb[2];
|
||||
int currentFb = 0;
|
||||
SceUID memblock;
|
||||
allocFramebuffer(fb, 2, &memblock);
|
||||
printf("fb[0]: %08X", fb[0].base);
|
||||
printf("fb[1]: %08X", fb[1].base);
|
||||
|
||||
renderer.outputBuffer = fb[0].base;
|
||||
renderer.outputBufferStride = PSP2_HORIZONTAL_PIXELS;
|
||||
|
||||
struct VFile* rom = VFileOpenSce("cache0:/VitaDefilerClient/Documents/GBA/rom.gba", PSP2_O_RDONLY, 0666);
|
||||
struct VFile* save = VFileOpenSce("cache0:/VitaDefilerClient/Documents/GBA/rom.sav", PSP2_O_RDWR | PSP2_O_CREAT, 0666);
|
||||
|
||||
printf("ROM: %08X", rom);
|
||||
printf("Save: %08X", save);
|
||||
|
||||
GBACreate(gba);
|
||||
ARMSetComponents(cpu, &gba->d, 0, 0);
|
||||
ARMInit(cpu);
|
||||
printf("%s initialized.", "CPU");
|
||||
|
||||
gba->keySource = &activeKeys;
|
||||
gba->sync = 0;
|
||||
|
||||
GBAVideoAssociateRenderer(&gba->video, &renderer.d);
|
||||
|
||||
GBALoadROM(gba, rom, save, 0);
|
||||
printf("%s loaded.", "ROM");
|
||||
|
||||
ARMReset(cpu);
|
||||
|
||||
printf("%s all set and ready to roll.", projectName);
|
||||
|
||||
int frameCounter = 0;
|
||||
while (running) {
|
||||
ARMRunLoop(cpu);
|
||||
|
||||
if (frameCounter != gba->video.frameCounter) {
|
||||
SceCtrlData pad;
|
||||
sceCtrlPeekBufferPositive(0, &pad, 1);
|
||||
activeKeys = 0;
|
||||
if (pad.buttons & PSP2_CTRL_CROSS) {
|
||||
activeKeys |= 1 << GBA_KEY_A;
|
||||
}
|
||||
if (pad.buttons & PSP2_CTRL_CIRCLE) {
|
||||
activeKeys |= 1 << GBA_KEY_B;
|
||||
}
|
||||
if (pad.buttons & PSP2_CTRL_START) {
|
||||
activeKeys |= 1 << GBA_KEY_START;
|
||||
}
|
||||
if (pad.buttons & PSP2_CTRL_SELECT) {
|
||||
activeKeys |= 1 << GBA_KEY_SELECT;
|
||||
}
|
||||
if (pad.buttons & PSP2_CTRL_UP) {
|
||||
activeKeys |= 1 << GBA_KEY_UP;
|
||||
}
|
||||
if (pad.buttons & PSP2_CTRL_DOWN) {
|
||||
activeKeys |= 1 << GBA_KEY_DOWN;
|
||||
}
|
||||
if (pad.buttons & PSP2_CTRL_LEFT) {
|
||||
activeKeys |= 1 << GBA_KEY_LEFT;
|
||||
}
|
||||
if (pad.buttons & PSP2_CTRL_RIGHT) {
|
||||
activeKeys |= 1 << GBA_KEY_RIGHT;
|
||||
}
|
||||
if (pad.buttons & PSP2_CTRL_LTRIGGER) {
|
||||
activeKeys |= 1 << GBA_KEY_L;
|
||||
}
|
||||
if (pad.buttons & PSP2_CTRL_RTRIGGER) {
|
||||
activeKeys |= 1 << GBA_KEY_R;
|
||||
}
|
||||
|
||||
sceDisplaySetFrameBuf(&fb[currentFb], PSP2_DISPLAY_SETBUF_NEXTFRAME);
|
||||
sceDisplayWaitVblankStart();
|
||||
currentFb = !currentFb;
|
||||
renderer.outputBuffer = fb[currentFb].base;
|
||||
|
||||
frameCounter = gba->video.frameCounter;
|
||||
}
|
||||
}
|
||||
printf("%s shutting down...", projectName);
|
||||
|
||||
ARMDeinit(cpu);
|
||||
GBADestroy(gba);
|
||||
|
||||
rom->close(rom);
|
||||
save->close(save);
|
||||
|
||||
mappedMemoryFree(gba, 0);
|
||||
mappedMemoryFree(cpu, 0);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "util/memory.h"
|
||||
#include "util/vector.h"
|
||||
|
||||
#include <psp2/kernel/memorymgr.h>
|
||||
#include <psp2/types.h>
|
||||
|
||||
DECLARE_VECTOR(SceUIDList, SceUID);
|
||||
DEFINE_VECTOR(SceUIDList, SceUID);
|
||||
|
||||
static struct SceUIDList uids;
|
||||
static bool listInit = false;
|
||||
|
||||
void* anonymousMemoryMap(size_t size) {
|
||||
if (!listInit) {
|
||||
SceUIDListInit(&uids, 8);
|
||||
}
|
||||
if (size & 0xFFF) {
|
||||
// Align to 4kB pages
|
||||
size += ((~size) & 0xFFF) + 1;
|
||||
}
|
||||
SceUID memblock = sceKernelAllocMemBlock("anon", SCE_KERNEL_MEMBLOCK_TYPE_USER_RW, size, 0);
|
||||
if (memblock < 0) {
|
||||
return 0;
|
||||
}
|
||||
*SceUIDListAppend(&uids) = memblock;
|
||||
void* ptr;
|
||||
if (sceKernelGetMemBlockBase(memblock, &ptr) < 0) {
|
||||
return 0;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void mappedMemoryFree(void* memory, size_t size) {
|
||||
UNUSED(size);
|
||||
size_t i;
|
||||
for (i = 0; i < SceUIDListSize(&uids); ++i) {
|
||||
SceUID uid = *SceUIDListGetPointer(&uids, i);
|
||||
void* ptr;
|
||||
if (sceKernelGetMemBlockBase(uid, &ptr) < 0) {
|
||||
continue;
|
||||
}
|
||||
if (ptr == memory) {
|
||||
sceKernelFreeMemBlock(uid);
|
||||
SceUIDListUnshift(&uids, i, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "sce-vfs.h"
|
||||
|
||||
#include "util/vfs.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
|
||||
struct VFileSce {
|
||||
struct VFile d;
|
||||
|
||||
SceUID fd;
|
||||
};
|
||||
|
||||
static bool _vfsceClose(struct VFile* vf);
|
||||
static off_t _vfsceSeek(struct VFile* vf, off_t offset, int whence);
|
||||
static ssize_t _vfsceRead(struct VFile* vf, void* buffer, size_t size);
|
||||
static ssize_t _vfsceWrite(struct VFile* vf, const void* buffer, size_t size);
|
||||
static void* _vfsceMap(struct VFile* vf, size_t size, int flags);
|
||||
static void _vfsceUnmap(struct VFile* vf, void* memory, size_t size);
|
||||
static void _vfsceTruncate(struct VFile* vf, size_t size);
|
||||
static ssize_t _vfsceSize(struct VFile* vf);
|
||||
|
||||
struct VFile* VFileOpenSce(const char* path, int flags, SceMode mode) {
|
||||
struct VFileSce* vfsce = malloc(sizeof(struct VFileSce));
|
||||
if (!vfsce) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
vfsce->fd = sceIoOpen(path, flags, mode);
|
||||
if (vfsce->fd < 0) {
|
||||
free(vfsce);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vfsce->d.close = _vfsceClose;
|
||||
vfsce->d.seek = _vfsceSeek;
|
||||
vfsce->d.read = _vfsceRead;
|
||||
vfsce->d.readline = 0;
|
||||
vfsce->d.write = _vfsceWrite;
|
||||
vfsce->d.map = _vfsceMap;
|
||||
vfsce->d.unmap = _vfsceUnmap;
|
||||
vfsce->d.truncate = _vfsceTruncate;
|
||||
vfsce->d.size = _vfsceSize;
|
||||
|
||||
return &vfsce->d;
|
||||
}
|
||||
|
||||
bool _vfsceClose(struct VFile* vf) {
|
||||
struct VFileSce* vfsce = (struct VFileSce*) vf;
|
||||
|
||||
return sceIoClose(vfsce->fd) >= 0;
|
||||
}
|
||||
|
||||
off_t _vfsceSeek(struct VFile* vf, off_t offset, int whence) {
|
||||
struct VFileSce* vfsce = (struct VFileSce*) vf;
|
||||
return sceIoLseek(vfsce->fd, offset, whence);
|
||||
}
|
||||
|
||||
ssize_t _vfsceRead(struct VFile* vf, void* buffer, size_t size) {
|
||||
struct VFileSce* vfsce = (struct VFileSce*) vf;
|
||||
return sceIoRead(vfsce->fd, buffer, size);
|
||||
}
|
||||
|
||||
ssize_t _vfsceWrite(struct VFile* vf, const void* buffer, size_t size) {
|
||||
struct VFileSce* vfsce = (struct VFileSce*) vf;
|
||||
return sceIoWrite(vfsce->fd, buffer, size);
|
||||
}
|
||||
|
||||
static void* _vfsceMap(struct VFile* vf, size_t size, int flags) {
|
||||
struct VFileSce* vfsce = (struct VFileSce*) vf;
|
||||
UNUSED(flags);
|
||||
void* buffer = anonymousMemoryMap(size);
|
||||
if (buffer) {
|
||||
sceIoRead(vfsce->fd, buffer, size);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void _vfsceUnmap(struct VFile* vf, void* memory, size_t size) {
|
||||
UNUSED(vf);
|
||||
mappedMemoryFree(memory, size);
|
||||
}
|
||||
|
||||
static void _vfsceTruncate(struct VFile* vf, size_t size) {
|
||||
struct VFileSce* vfsce = (struct VFileSce*) vf;
|
||||
// TODO
|
||||
}
|
||||
|
||||
ssize_t _vfsceSize(struct VFile* vf) {
|
||||
struct VFileSce* vfsce = (struct VFileSce*) vf;
|
||||
SceOff cur = sceIoLseek(vfsce->fd, 0, SEEK_CUR);
|
||||
SceOff end = sceIoLseek(vfsce->fd, 0, SEEK_END);
|
||||
sceIoLseek(vfsce->fd, cur, SEEK_SET);
|
||||
return end;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef SCE_VFS_H
|
||||
#define SCE_VFS_H
|
||||
|
||||
#ifdef PSP2
|
||||
#include <psp2/types.h>
|
||||
#include <psp2/io/fcntl.h>
|
||||
#else
|
||||
#include <pspiofilemgr.h>
|
||||
#endif
|
||||
|
||||
struct VFile* VFileOpenSce(const char* path, int flags, SceMode mode);
|
||||
|
||||
#endif
|
|
@ -6,7 +6,9 @@
|
|||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#ifndef PSP2
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "vfs.h"
|
||||
|
||||
#ifdef PSP2
|
||||
#include "platform/psp2/sce-vfs.h"
|
||||
#endif
|
||||
|
||||
struct VFile* VFileOpen(const char* path, int flags) {
|
||||
#ifdef USE_VFS_FILE
|
||||
const char* chflags;
|
||||
|
@ -30,6 +34,8 @@ struct VFile* VFileOpen(const char* path, int flags) {
|
|||
break;
|
||||
}
|
||||
return VFileFOpen(path, chflags);
|
||||
#elif defined(PSP2)
|
||||
return VFileOpenSce(path, flags, 0666);
|
||||
#else
|
||||
return VFileOpenFD(path, flags);
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue