ClassiCube/src/gba/Platform_GBA.c

320 lines
10 KiB
C

#define CC_NO_UPDATER
#define CC_NO_DYNLIB
#define CC_NO_SOCKETS
#define CC_NO_THREADING
#define OVERRIDE_MEM_FUNCTIONS
#include "../Stream.h"
#include "../ExtMath.h"
#include "../Funcs.h"
#include "../Window.h"
#include "../Utils.h"
#include "../Errors.h"
#include "../Options.h"
#include "../Animations.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "gbadefs.h"
#include "../../third_party/tinyalloc/tinyalloc.c"
typedef volatile uint8_t vu8;
typedef volatile uint16_t vu16;
typedef volatile uint32_t vu32;
const cc_result ReturnCode_FileShareViolation = 1000000000; // not used
const cc_result ReturnCode_FileNotFound = -1;
const cc_result ReturnCode_DirectoryExists = -1;
const cc_result ReturnCode_SocketInProgess = -1;
const cc_result ReturnCode_SocketWouldBlock = -1;
const cc_result ReturnCode_SocketDropped = -1;
const char* Platform_AppNameSuffix = " GBA";
cc_bool Platform_ReadonlyFilesystem;
cc_uint8 Platform_Flags = PLAT_FLAG_SINGLE_PROCESS | PLAT_FLAG_APP_EXIT;
#include "../_PlatformBase.h"
/*########################################################################################################################*
*-----------------------------------------------------Main entrypoint-----------------------------------------------------*
*#########################################################################################################################*/
#include "../main_impl.h"
int main(int argc, char** argv) {
SetupProgram(argc, argv);
while (Window_Main.Exists) {
RunGame();
}
Window_Free();
return 0;
}
/*########################################################################################################################*
*---------------------------------------------------------Memory----------------------------------------------------------*
*#########################################################################################################################*/
void* Mem_TryAlloc(cc_uint32 numElems, cc_uint32 elemsSize) {
cc_uint32 size = CalcMemSize(numElems, elemsSize);
void* ptr = size ? ta_alloc(size) : NULL;
Platform_Log2("MALLOCED: %x (%i bytes)", &ptr, &size);
return ptr;
}
void* Mem_TryAllocCleared(cc_uint32 numElems, cc_uint32 elemsSize) {
cc_uint32 size = CalcMemSize(numElems, elemsSize);
void* ptr = size ? ta_alloc(size) : NULL;
Platform_Log2("CALLOCED: %x (%i bytes)", &ptr, &size);
if (ptr) Mem_Set(ptr, 0, size);
return ptr;
}
void* Mem_TryRealloc(void* mem, cc_uint32 numElems, cc_uint32 elemsSize) {
return NULL; // TODO
}
void Mem_Free(void* mem) {
if (mem) ta_free(mem);
}
/*########################################################################################################################*
*------------------------------------------------------Logging/Time-------------------------------------------------------*
*#########################################################################################################################*/
static uint32_t GetTimerValues(void) {
uint16_t lo = REG_TMR2_DATA;
uint16_t hi = REG_TMR3_DATA;
// Lo timer can possibly overflow between reading lo and hi
uint16_t lo_again = REG_TMR2_DATA;
uint16_t hi_again = REG_TMR3_DATA;
// Check if lo timer has overflowed
if (lo_again < lo) {
// If so, use known stable timer read values instead
lo = lo_again;
hi = hi_again;
}
return lo | (hi << 16);
}
static void Stopwatch_Init(void) {
// Turn off both timers
REG_TMR2_CTRL = 0;
REG_TMR3_CTRL = 0;
// Reset timer values to 0
REG_TMR2_DATA = 0;
REG_TMR3_DATA = 0;
// Turn on timer 3, with timer 3 incrementing timer 2 on overflow
REG_TMR3_CTRL = TMR_CASCADE | TMR_ENABLE;
REG_TMR2_CTRL = TMR_ENABLE;
}
static uint32_t last_raw;
static uint64_t base_time;
#define US_PER_SEC 1000000
cc_uint64 Stopwatch_ElapsedMicroseconds(cc_uint64 beg, cc_uint64 end) {
if (end < beg) return 0;
cc_uint64 delta = end - beg;
return (delta * US_PER_SEC) / SYS_CLOCK;
}
cc_uint64 Stopwatch_Measure(void) {
uint32_t raw = GetTimerValues();
// Since counter is only a 32 bit integer, it overflows after a minute or two
// TODO use IRQ instead
// TODO lower frequency ?
if (last_raw > 0xF0000000 && raw < 0x10000000) {
base_time += 0x100000000ULL;
}
last_raw = raw;
return base_time + raw;
}
extern int nocash_puts(const char *str);
static void Log_Nocash(char* buffer) {
nocash_puts(buffer);
}
#define MGBA_LOG_DEBUG 4
#define REG_DEBUG_ENABLE (vu16*)0x4FFF780
#define REG_DEBUG_FLAGS (vu16*)0x4FFF700
#define REG_DEBUG_STRING (char*)0x4FFF600
static void Log_mgba(char* buffer, int len) {
*REG_DEBUG_ENABLE = 0xC0DE;
// Check if actually emulated or not
if (*REG_DEBUG_ENABLE != 0x1DEA) return;
Mem_Copy(REG_DEBUG_STRING, buffer, len);
*REG_DEBUG_FLAGS = MGBA_LOG_DEBUG | 0x100;
}
void Platform_Log(const char* msg, int len) {
// Can only be up to 120 bytes total
char buffer[120];
len = min(len, 118);
Mem_Copy(buffer, msg, len);
buffer[len + 0] = '\n';
buffer[len + 1] = '\0';
Log_Nocash(buffer);
Log_mgba(buffer, len);
}
TimeMS DateTime_CurrentUTC(void) {
return 0;
}
void DateTime_CurrentLocal(struct cc_datetime* t) {
Mem_Set(t, 0, sizeof(*t));
}
/*########################################################################################################################*
*-------------------------------------------------------Crash handling----------------------------------------------------*
*#########################################################################################################################*/
void CrashHandler_Install(void) {
}
void Process_Abort2(cc_result result, const char* raw_msg) {
Platform_LogConst(raw_msg);
_exit(0);
}
/*########################################################################################################################*
*-----------------------------------------------------Directory/File------------------------------------------------------*
*#########################################################################################################################*/
void Platform_EncodePath(cc_filepath* dst, const cc_string* path) {
int len = String_CopyToRaw(dst->buffer, sizeof(dst->buffer) - 1, path);
dst->buffer[len] = '\0'; // Always null terminate just in case
}
void Platform_DecodePath(cc_string* dst, const cc_filepath* path) {
String_AppendConst(dst, path->buffer);
}
void Directory_GetCachePath(cc_string* path) { }
cc_result Directory_Create(const cc_filepath* path) {
return ERR_NOT_SUPPORTED;
}
int File_Exists(const cc_filepath* path) {
return false;
}
cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCallback callback) {
return ERR_NOT_SUPPORTED;
}
cc_result File_Open(cc_file* file, const cc_filepath* path) {
return ERR_NOT_SUPPORTED;
}
cc_result File_Create(cc_file* file, const cc_filepath* path) {
return ERR_NOT_SUPPORTED;
}
cc_result File_OpenOrCreate(cc_file* file, const cc_filepath* path) {
return ERR_NOT_SUPPORTED;
}
cc_result File_Read(cc_file file, void* data, cc_uint32 count, cc_uint32* bytesRead) {
return ERR_NOT_SUPPORTED;
}
cc_result File_Write(cc_file file, const void* data, cc_uint32 count, cc_uint32* bytesWrote) {
return ERR_NOT_SUPPORTED;
}
cc_result File_Close(cc_file file) {
return ERR_NOT_SUPPORTED;
}
cc_result File_Seek(cc_file file, int offset, int seekType) {
return ERR_NOT_SUPPORTED;
}
cc_result File_Position(cc_file file, cc_uint32* pos) {
return ERR_NOT_SUPPORTED;
}
cc_result File_Length(cc_file file, cc_uint32* len) {
return ERR_NOT_SUPPORTED;
}
/*########################################################################################################################*
*--------------------------------------------------------Threading--------------------------------------------------------*
*#########################################################################################################################*/
// !!! NOTE: PSP uses cooperative multithreading (not preemptive multithreading) !!!
void Thread_Sleep(cc_uint32 milliseconds) {
Stopwatch_Measure();
//swiDelay(8378 * milliseconds); // TODO probably wrong
}
/*########################################################################################################################*
*--------------------------------------------------------Platform---------------------------------------------------------*
*#########################################################################################################################*/
extern void __ewram_end; // end of USED ewram
#define EWRAM_END 0x0203FFFF
void Platform_Init(void) {
void* heap_beg = &__ewram_end;
void* heap_end = (void*)EWRAM_END;
ta_init(heap_beg, heap_end, 256, 16, 4);
int size = (int)(heap_end - heap_beg);
Platform_Log3("HEAP SIZE: %i bytes (%x -> %x)", &size, &heap_beg, &heap_end);
Stopwatch_Init();
}
void Platform_Free(void) { }
cc_bool Platform_DescribeError(cc_result res, cc_string* dst) {
return false;
}
cc_bool Process_OpenSupported = false;
cc_result Process_StartOpen(const cc_string* args) {
return ERR_NOT_SUPPORTED;
}
cc_result Platform_Encrypt(const void* data, int len, cc_string* dst) {
return ERR_NOT_SUPPORTED;
}
cc_result Platform_Decrypt(const void* data, int len, cc_string* dst) {
return ERR_NOT_SUPPORTED;
}
/*########################################################################################################################*
*-----------------------------------------------------Process/Module------------------------------------------------------*
*#########################################################################################################################*/
cc_result Process_StartGame2(const cc_string* args, int numArgs) {
return 0;
}
int Platform_GetCommandLineArgs(int argc, STRING_REF char** argv, cc_string* args) {
return 0;
}
cc_result Platform_SetDefaultCurrentDirectory(int argc, char **argv) {
return 0;
}
void Process_Exit(cc_result code) { _exit(code); }