Files
perfect_dark/port/src/libultra.c
T
2024-01-27 18:25:55 +08:00

489 lines
8.4 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <PR/os_internal.h>
#include <PR/rcp.h>
#include "system.h"
#include "input.h"
#include "video.h"
#include "audio.h"
#include "fs.h"
#define EEPROM_SIZE (EEP16K_MAXBLOCKS * 8)
#define EEPROM_FNAME "eeprom.bin"
#define EEPROM_PATH "$S/" EEPROM_FNAME
#define OS_COUNTER_RATE 46875000ULL
#define OS_COUNTER_NUM (OS_COUNTER_RATE / 1000ULL)
#define OS_COUNTER_DEN (1000000ULL / 1000ULL)
u64 osClockRate = OS_CLOCK_RATE;
u32 osMemSize = 16 * 1024 * 1024; /* expansion pak installed plus some extra */
s32 osTvType = OS_TV_NTSC; /* 0 = PAL, 1 = NTSC, 2 = MPAL */
s32 osResetType = 0; /* 0 = cold reset */
s32 osViClock = VI_NTSC_CLOCK;
static u8 eeprom[EEPROM_SIZE];
static char eepromPath[FS_MAXPATH + 1];
static s32 eepromLoaded = 0;
/* Time */
OSTime osGetTime(void)
{
// u64 should be enough to last a while
return (sysGetMicroseconds() * OS_COUNTER_NUM) / OS_COUNTER_DEN;
}
u32 osGetCount(void)
{
return (u32)osGetTime();
}
/* Thread */
void osCreateThread(OSThread *thrd, OSId id, void (*entry)(void *), void *arg, void *sp, OSPri p)
{
thrd->id = id;
thrd->state = OS_STATE_STOPPED;
}
void osDestroyThread(OSThread *thrd)
{
thrd->id = 0;
thrd->state = 0;
}
void osYieldThread(void)
{
}
void osStartThread(OSThread *thrd)
{
thrd->state = OS_STATE_RUNNING;
}
void osStopThread(OSThread *thrd)
{
thrd->state = OS_STATE_STOPPED;
}
OSPri osGetThreadPri(OSThread *thrd)
{
return 0;
}
void osSetThreadPri(OSThread *thrd, OSPri pri)
{
}
/* Mesg */
void osCreateMesgQueue(OSMesgQueue *mq, OSMesg *msgBuf, s32 count)
{
mq->validCount = 0;
mq->first = 0;
mq->msgCount = count;
mq->msg = msgBuf;
}
void osSetEventMesg(OSEvent e, OSMesgQueue *mq, OSMesg msg)
{
}
s32 osSendMesg(OSMesgQueue *mq, OSMesg msg, s32 flag)
{
return 0;
}
s32 osRecvMesg(OSMesgQueue *mq, OSMesg *msg, s32 flag)
{
return 0;
}
/* Vi */
void osCreateViManager(OSPri pri)
{
}
void osViSetMode(OSViMode *mode)
{
}
void osViSetEvent(OSMesgQueue *mq, OSMesg msg, u32 retraceCount)
{
}
void osViBlack(u8 active)
{
if (active) {
videoClearScreen();
}
}
void osViSetSpecialFeatures(u32 func)
{
}
void osViSwapBuffer(void *vaddr)
{
}
void osViSetXScale(f32 value)
{
}
void osViSetYScale(f32 value)
{
}
/* Ai */
s32 osAiSetFrequency(u32 frequency)
{
// we can allow for any freq
return (s32)frequency;
}
u32 osAiGetLength(void)
{
return audioGetBytesBuffered();
}
s32 osAiSetNextBuffer(void *bufPtr, u32 size)
{
audioSetNextBuffer(bufPtr, size);
return 0;
}
/* Cont */
s32 osContInit(OSMesgQueue *mesgq, u8 *bitpattern, OSContStatus *data)
{
if (bitpattern) {
*bitpattern = inputControllerMask();
}
if (data) {
osContGetQuery(data);
}
return 0;
}
s32 osContStartReadData(OSMesgQueue *mesgq)
{
osSendMesg(mesgq, (OSMesg)0, OS_MESG_NOBLOCK);
return 0;
}
void osContGetReadData(OSContPad *pad)
{
// game always passes in an array of 4 OSContPads
for (s32 i = 0; i < MAXCONTROLLERS; ++i, ++pad) {
pad->button = 0;
pad->stick_x = 0;
pad->stick_y = 0;
pad->rstick_x = 0;
pad->rstick_y = 0;
if (inputReadController(i, pad) < 0) {
pad->errnum = CONT_NO_RESPONSE_ERROR;
} else {
pad->errnum = 0;
}
}
}
s32 osContStartQuery(OSMesgQueue *mq)
{
return 0;
}
void osContGetQuery(OSContStatus *status)
{
// also always 4 status structs here
for (s32 i = 0; i < MAXCONTROLLERS; ++i, ++status) {
if (inputControllerConnected(i)) {
status->errnum = 0;
status->type = CONT_ABSOLUTE;
status->status = CONT_CARD_ON;
} else {
status->errnum = CONT_NO_RESPONSE_ERROR;
status->type = 0;
status->status = 0;
}
}
}
/* Motor */
s32 osMotorProbe(OSMesgQueue *ctrlrqueue, OSPfs* pfs, s32 channel)
{
if (pfs && inputRumbleSupported(channel)) {
pfs->queue = ctrlrqueue;
pfs->channel = channel;
pfs->activebank = 0xff;
pfs->status = PFS_MOTOR_INITIALIZED;
return 0;
}
return PFS_ERR_NOPACK;
}
s32 __osMotorAccess(OSPfs *pfs, s32 cmd)
{
if (!pfs || pfs->channel < 0 || pfs->channel >= INPUT_MAX_CONTROLLERS) {
return PFS_ERR_NOPACK;
}
const f32 strength = (f32)(cmd == MOTOR_START);
inputRumble(pfs->channel, strength, 5.f); // hope someone turns it off in those 5 seconds
return 0;
}
/* Eeprom */
static inline void osEepromSetPath(void)
{
const char *extPath = sysArgGetString("--eeprom-file");
if (extPath && extPath[0]) {
if (extPath[0] == '$' || fsPathIsAbsolute(extPath) || fsPathIsCwdRelative(extPath)) {
strncpy(eepromPath, extPath, FS_MAXPATH);
} else {
// just a filename, look for it in the save dir
snprintf(eepromPath, FS_MAXPATH, "$S/%s", extPath);
}
} else {
strncpy(eepromPath, EEPROM_PATH, FS_MAXPATH);
}
}
static inline void osEeepromLoad(const char *fname)
{
if (!eepromLoaded) {
eepromLoaded = 1;
FILE *fp = fsFileOpenRead(fname);
if (fp) {
fread(eeprom, 1, EEPROM_SIZE, fp);
fsFileClose(fp);
} else {
sysLogPrintf(LOG_NOTE, "could not read EEPROM from `%s`: %s", fsFullPath(fname), strerror(errno));
}
}
}
static inline void osEeepromSave(const char *fname)
{
FILE* fp = fsFileOpenWrite(fname);
if (fp) {
fwrite(eeprom, 1, EEPROM_SIZE, fp);
fsFileClose(fp);
} else {
sysLogPrintf(LOG_ERROR, "could not save EEPROM to `%s`: %s", fsFullPath(fname), strerror(errno));
}
}
s32 osEepromProbe(OSMesgQueue *mq)
{
return EEPROM_TYPE_16K;
}
s32 osEepromLongRead(OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes)
{
if (!eepromPath[0]) {
osEepromSetPath();
}
osEeepromLoad(eepromPath);
memcpy(buffer, eeprom + address * 8, nbytes);
return 0;
}
s32 osEepromLongWrite(OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes)
{
if (!eepromPath[0]) {
osEepromSetPath();
}
osEeepromLoad(eepromPath);
memcpy(eeprom + address * 8, buffer, nbytes);
osEeepromSave(eepromPath);
return 0;
}
/* Pfs */
s32 osPfsIsPlug(OSMesgQueue *queue, u8 *pattern)
{
if (pattern) {
*pattern = 0;
for (s32 i = 0; i < MAXCONTROLLERS; ++i) {
if (inputRumbleSupported(i)) {
*pattern |= 1 << i;
}
}
}
return 0;
}
s32 osPfsInitPak(OSMesgQueue *queue, OSPfs *pfs, s32 channel, s32 *arg3)
{
// if rumble is supported, indicate that we have a rumble pak instead
return inputRumbleSupported(channel) ? PFS_ERR_DEVICE : PFS_ERR_NOPACK;
}
s32 osPfsChecker(OSPfs *pfs)
{
return PFS_ERR_NOPACK;
}
s32 osPfsFreeBlocks(OSPfs *pfs, s32 *remaining)
{
return PFS_ERR_NOPACK;
}
s32 osPfsNumFiles(OSPfs *pfs, s32 *max_files, s32 *files_used)
{
return PFS_ERR_NOPACK;
}
s32 osPfsAllocateFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, int num_bytes, s32 *file_no)
{
return PFS_ERR_NOPACK;
}
s32 osPfsFindFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, s32 *file_no)
{
return PFS_ERR_NOPACK;
}
s32 osPfsDeleteFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name)
{
return PFS_ERR_NOPACK;
}
s32 osPfsReSizeFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, int length)
{
return PFS_ERR_NOPACK;
}
s32 osPfsFileState(OSPfs *pfs, s32 fileNo, OSPfsState *state)
{
return PFS_ERR_NOPACK;
}
s32 osPfsReadWriteFile(OSPfs* pfs, s32 fileNo, u8 flag, int offset, int size, u8* data)
{
return PFS_ERR_NOPACK;
}
/* Gbpak */
s32 osGbpakInit(OSMesgQueue *queue, OSPfs *pfs, s32 ch)
{
return PFS_ERR_NOPACK;
}
s32 osGbpakPower(OSPfs *pfs, s32 flag)
{
return PFS_ERR_NOPACK;
}
s32 osGbpakReadWrite(OSPfs *pfs, u16 flag, u16 addr, u8 *buf, u16 size)
{
return PFS_ERR_NOPACK;
}
s32 osGbpakReadId(OSPfs *pfs, OSGbpakId *id, u8 *status)
{
return PFS_ERR_NOPACK;
}
/* Misc */
void osWritebackDCacheAll(void)
{
}
void osWritebackDCache(void *a, s32 b)
{
}
void osInvalDCache(void *a, s32 b)
{
}
s32 osPiStartDma(OSIoMesg *mb, s32 priority, s32 direction, uintptr_t devAddr, void *vAddr, u32 nbytes, OSMesgQueue *mq)
{
memcpy(vAddr, (const void *)devAddr, nbytes);
return 0;
}
s32 osPiReadIo(u32 devaddr, u32 *data)
{
return 0;
}
uintptr_t osVirtualToPhysical(void *addr)
{
return (uintptr_t)addr;
}
u32 osGetMemSize(void)
{
return osMemSize;
}
OSIntMask osGetIntMask(void)
{
return 0;
}
OSIntMask osSetIntMask(OSIntMask mask)
{
return 0;
}
/* libc compatibility wrappers */
#ifndef HAVE_BZERO
void bzero(void *ptr, size_t size)
{
memset(ptr, 0, size);
}
#endif
#ifndef HAVE_BCOPY
void bcopy(const void *src, void *dst, size_t n)
{
memcpy(dst, src, n);
}
#endif
#ifndef HAVE_BCMP
s32 bcmp(const void *s1, const void *s2, size_t n)
{
return memcmp(s1, s2, n);
}
#endif