all repos — mgba @ 4f04c30f708f30f51f5b90aff2e320cd607955ea

mGBA Game Boy Advance Emulator

Wii: Initial port
Jeffrey Pfau jeffrey@endrift.com
Mon, 15 Jun 2015 23:02:58 -0700
commit

4f04c30f708f30f51f5b90aff2e320cd607955ea

parent

dc33a4f173dbe3d18666deb7c928a45c4c26d66d

M CMakeLists.txtCMakeLists.txt

@@ -202,6 +202,14 @@ add_definitions(-DCOLOR_16_BIT -DCOLOR_5_6_5)

endif() endif() +if(WII) + list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-file.c) + add_definitions(-DCOLOR_16_BIT -DCOLOR_5_6_5) + file(GLOB WII_SRC ${CMAKE_SOURCE_DIR}/src/platform/wii/*.c) + add_executable(${BINARY_NAME}.elf ${WII_SRC}) + target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} fat ogc) +endif() + if(BUILD_PANDORA) add_definitions(-DBUILD_PANDORA) endif()
A src/platform/wii/CMakeToolchain.txt

@@ -0,0 +1,39 @@

+if(DEFINED ENV{DEVKITPRO}) + set(DEVKITPRO $ENV{DEVKITPRO}) +else() + message(FATAL_ERROR "Could not find DEVKITPRO in environment") +endif() + +if(DEFINED ENV{DEVKITPPC}) + set(DEVKITPPC $ENV{DEVKITPPC}) +else() + set(DEVKITPPC ${DEVKITPRO}/devkitPPC) +endif() + +set(toolchain_bin_dir ${DEVKITPPC}/bin) +set(cross_prefix ${toolchain_bin_dir}/powerpc-eabi-) +set(inc_flags -I${DEVKITPRO}/libogc/include) +set(arch_flags "-mrvl -mcpu=750 -meabi -mhard-float -g") +set(link_flags "-L${DEVKITPRO}/libogc/lib/wii ${arch_flags}") + +set(CMAKE_SYSTEM_NAME Generic CACHE INTERNAL "system name") +set(CMAKE_SYSTEM_PROCESSOR arm CACHE INTERNAL "processor") +set(CMAKE_LIBRARY_ARCHITECTURE powerpc-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} ${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(ELF2DOL ${toolchain_bin_dir}/elf2dol) + +set(WII ON) +add_definitions(-DGEKKO)
A src/platform/wii/main.c

@@ -0,0 +1,283 @@

+/* 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/. */ +#define asm __asm__ + +#include <fat.h> +#include <gccore.h> +#include <malloc.h> + +#include "util/common.h" + +#include "gba/gba.h" +#include "gba/renderers/video-software.h" +#include "gba/serialize.h" +#include "gba/supervisor/overrides.h" +#include "gba/video.h" +#include "util/vfs.h" + +#define SAMPLES 1024 + +static void GBAWiiLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args); +static void GBAWiiFrame(void); +static bool GBAWiiLoadGame(const char* path); + +static void _postVideoFrame(struct GBAAVStream*, struct GBAVideoRenderer* renderer); + +static struct GBA gba; +static struct ARMCore cpu; +static struct GBAVideoSoftwareRenderer renderer; +static struct VFile* rom; +static struct VFile* save; +static struct GBAAVStream stream; +static FILE* logfile; +static GXRModeObj* mode; +static Mtx model, view, modelview; +static uint16_t* texmem; +static GXTexObj tex; + +static void* framebuffer[2]; +static int whichFb = 0; + +int main() { + VIDEO_Init(); + PAD_Init(); + + int fmt; +#ifdef COLOR_16_BIT +#ifdef COLOR_5_6_5 + fmt = GX_PF_RGB565_Z16; +#else +#error This pixel format is unsupported. Please use -DCOLOR_16-BIT -DCOLOR_5_6_5 +#endif +#else +#error This pixel format is unsupported. Please use -DCOLOR_16-BIT -DCOLOR_5_6_5 +#endif + + mode = VIDEO_GetPreferredMode(0); + framebuffer[0] = SYS_AllocateFramebuffer(mode); + framebuffer[1] = SYS_AllocateFramebuffer(mode); + + VIDEO_Configure(mode); + VIDEO_SetNextFramebuffer(framebuffer[whichFb]); + VIDEO_SetBlack(FALSE); + VIDEO_Flush(); + VIDEO_WaitVSync(); + if (mode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync(); + + GXColor bg = { 0, 0, 0, 0xFF }; + void* fifo = memalign(32, 0x40000); + memset(fifo, 0, 0x40000); + GX_Init(fifo, 0x40000); + GX_SetPixelFmt(fmt, GX_ZC_LINEAR); + GX_SetCopyClear(bg, 0x00FFFFFF); + GX_SetViewport(0, 0, mode->fbWidth, mode->efbHeight, 0, 1); + + GX_SetCullMode(GX_CULL_NONE); + GX_CopyDisp(framebuffer[whichFb], GX_TRUE); + GX_SetDispCopyGamma(GX_GM_1_0); + + GX_ClearVtxDesc(); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S16, 0); + + GX_SetNumChans(1); + GX_SetNumTexGens(1); + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + GX_SetTevOp(GX_TEVSTAGE0, GX_REPLACE); + + GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); + GX_InvVtxCache(); + GX_InvalidateTexAll(); + + Mtx44 proj; + guOrtho(proj, 0, VIDEO_VERTICAL_PIXELS, 0, VIDEO_HORIZONTAL_PIXELS, 0, 300); + GX_LoadProjectionMtx(proj, GX_ORTHOGRAPHIC); + + guVector cam = { 0.0f, 0.0f, 0.0f }; + guVector up = { 0.0f, 1.0f, 0.0f }; + guVector look = { 0.0f, 0.0f, -1.0f }; + guLookAt(view, &cam, &up, &look); + GX_LoadPosMtxImm(view, GX_PNMTX0); + + guMtxIdentity(model); + guMtxTransApply(model, model, 0.0f, 0.0f, -6.0f); + guMtxConcat(view, model, modelview); + GX_LoadPosMtxImm(modelview, GX_PNMTX0); + + texmem = memalign(32, 256 * 256 * BYTES_PER_PIXEL); + GX_InitTexObj(&tex, texmem, 256, 256, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE); + + fatInitDefault(); + + logfile = fopen("/mgba.log", "w"); + + stream.postAudioFrame = 0; + stream.postAudioBuffer = 0; + stream.postVideoFrame = _postVideoFrame; + + GBACreate(&gba); + ARMSetComponents(&cpu, &gba.d, 0, 0); + ARMInit(&cpu); + gba.logLevel = 0; // TODO: Settings + gba.logHandler = GBAWiiLog; + gba.stream = &stream; + gba.idleOptimization = IDLE_LOOP_REMOVE; // TODO: Settings + rom = 0; + + GBAVideoSoftwareRendererCreate(&renderer); + renderer.outputBuffer = memalign(32, 256 * 256 * BYTES_PER_PIXEL); + renderer.outputBufferStride = 256; + GBAVideoAssociateRenderer(&gba.video, &renderer.d); + + GBAAudioResizeBuffer(&gba.audio, SAMPLES); + +#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF + blip_set_rates(gba.audio.left, GBA_ARM7TDMI_FREQUENCY, 44100); + blip_set_rates(gba.audio.right, GBA_ARM7TDMI_FREQUENCY, 44100); +#endif + + if (!GBAWiiLoadGame("/rom.gba")) { + return 1; + } + + while (true) { + PAD_ScanPads(); + u16 padkeys = PAD_ButtonsDown(0); + int keys = 0; + gba.keySource = &keys; + if (padkeys & PAD_BUTTON_A) { + keys |= 1 << GBA_KEY_A; + } + if (padkeys & PAD_BUTTON_B) { + keys |= 1 << GBA_KEY_B; + } + if (padkeys & PAD_TRIGGER_L) { + keys |= 1 << GBA_KEY_L; + } + if (padkeys & PAD_TRIGGER_R) { + keys |= 1 << GBA_KEY_R; + } + if (padkeys & PAD_BUTTON_START) { + keys |= 1 << GBA_KEY_START; + } + if (padkeys & (PAD_BUTTON_X | PAD_BUTTON_Y)) { + keys |= 1 << GBA_KEY_SELECT; + } + if (padkeys & PAD_BUTTON_LEFT) { + keys |= 1 << GBA_KEY_LEFT; + } + if (padkeys & PAD_BUTTON_RIGHT) { + keys |= 1 << GBA_KEY_RIGHT; + } + if (padkeys & PAD_BUTTON_UP) { + keys |= 1 << GBA_KEY_UP; + } + if (padkeys & PAD_BUTTON_DOWN) { + keys |= 1 << GBA_KEY_DOWN; + } + if (padkeys & PAD_TRIGGER_Z) { + break; + } + int frameCount = gba.video.frameCounter; + while (gba.video.frameCounter == frameCount) { + ARMRunLoop(&cpu); + } + } + + fclose(logfile); + free(fifo); + + rom->close(rom); + save->close(save); + + return 0; +} + +static void GBAWiiFrame(void) { + size_t x, y; + uint64_t* texdest = (uint64_t*) texmem; + uint64_t* texsrc = (uint64_t*) renderer.outputBuffer; + for (y = 0; y < VIDEO_VERTICAL_PIXELS; y += 4) { + for (x = 0; x < VIDEO_HORIZONTAL_PIXELS >> 2; ++x) { + texdest[0 + x * 4 + y * 64] = texsrc[0 + x + y * 64]; + texdest[1 + x * 4 + y * 64] = texsrc[64 + x + y * 64]; + texdest[2 + x * 4 + y * 64] = texsrc[128 + x + y * 64]; + texdest[3 + x * 4 + y * 64] = texsrc[192 + x + y * 64]; + } + } + DCFlushRange(texdest, 256 * 256 * BYTES_PER_PIXEL); + + GX_SetViewport(0, 0, mode->fbWidth, mode->efbHeight, 0, 1); + GX_InvalidateTexAll(); + GX_LoadTexObj(&tex, GX_TEXMAP0); + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position2s16(0, 256); + GX_TexCoord2s16(0, 1); + + GX_Position2s16(256, 256); + GX_TexCoord2s16(1, 1); + + GX_Position2s16(256, 0); + GX_TexCoord2s16(1, 0); + + GX_Position2s16(0, 0); + GX_TexCoord2s16(0, 0); + GX_End(); + + GX_DrawDone(); + + whichFb = !whichFb; + + GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); + GX_SetColorUpdate(GX_TRUE); + GX_CopyDisp(framebuffer[whichFb], GX_TRUE); + VIDEO_SetNextFramebuffer(framebuffer[whichFb]); + VIDEO_Flush(); + VIDEO_WaitVSync(); +} + +bool GBAWiiLoadGame(const char* path) { + rom = VFileFOpen(path, "rb"); + + if (!rom) { + return false; + } + if (!GBAIsROM(rom)) { + return false; + } + + save = VFileFOpen("test.sav", "w+b"); + + GBALoadROM(&gba, rom, save, path); + + struct GBACartridgeOverride override; + const struct GBACartridge* cart = (const struct GBACartridge*) gba.memory.rom; + memcpy(override.id, &cart->id, sizeof(override.id)); + if (GBAOverrideFind(0, &override)) { + GBAOverrideApply(&gba, &override); + } + + ARMReset(&cpu); + return true; +} + +void GBAWiiLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args) { + UNUSED(thread); + UNUSED(level); + vfprintf(logfile, format, args); + fprintf(logfile, "\n"); + fflush(logfile); +} + +static void _postVideoFrame(struct GBAAVStream* stream, struct GBAVideoRenderer* renderer) { + UNUSED(stream); + UNUSED(renderer); + GBAWiiFrame(); +}
A src/platform/wii/memory.c

@@ -0,0 +1,15 @@

+/* 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" + +void* anonymousMemoryMap(size_t size) { + return malloc(size); +} + +void mappedMemoryFree(void* memory, size_t size) { + UNUSED(size); + free(memory); +}
M src/util/common.hsrc/util/common.h

@@ -32,6 +32,9 @@ #define SSIZE_MAX ((ssize_t) SIZE_MAX)

#define strcasecmp _stricmp #define strncasecmp _strnicmp #define ftruncate _chsize +#elif defined(__wii__) +typedef int32_t ssize_t; +#define SSIZE_MAX ((ssize_t) SIZE_MAX) #else #include <strings.h> #include <unistd.h>