psxsdk/libpsx/src/psxsdk.c

621 lines
12 KiB
C

/*
* PSXSDK Library
*
* Free and open source library to develop for the Sony PlayStation
*/
#include <psx.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "exception.h"
static const char *sysromver_unavail = "System ROM Version Unavailable";
void (*vblank_handler_callback)();
extern int *vblank_handler();
void (*rcnt_handler_callback)();
extern int *rcnt_handler();
/*static unsigned int vblank_queue_buf[4] = {0x0, // Will contain next interrupt handler in queue
0x0, // func1
(unsigned int)vblank_handler, // func2
0x0, // pad
};*/
static int vblank_handler_set = 0;
static unsigned int vblank_handler_event_id = 0;
static int rcnt_handler_set = 0;
static unsigned int rcnt_handler_event_id = 0;
unsigned int rcnt_handler_evfield;
void _internal_cdromlib_init(void);
static unsigned int psxSdkFlags = 0;
static unsigned char *psxBiosState;
extern void _96_remove(void);
extern void _96_init(void);
extern void InitCARD(void);
extern void StartCARD(void);
extern void StopCARD(void);
extern void _bu_init(void);
extern void BIOSWarmReboot(void);
void PSX_InitEx(unsigned int flags)
{
if(flags & PSX_INIT_NOBIOS)
{
printf("Entering No BIOS mode...\n");
__PSX_Init_NoBios();
goto _initex_end;
}
if(flags & PSX_INIT_SAVESTATE)
{
// Save BIOS state
// This simply copies the entire section of RAM used by the BIOS
// in a buffer.
EnterCriticalSection();
psxBiosState = malloc(0x10000);
memcpy(psxBiosState, (void*)0x80000000, 0x10000);
ExitCriticalSection();
}
/* Reinitialize ISO 9660 filesystem driver */
if(flags & PSX_INIT_CD)
{
EnterCriticalSection();
_96_remove();
ExitCriticalSection();
_96_init();
}
/*This is needed, otherwise PSX will crash when VBlank handler is set*/
/*InitCARD(1);
StartCARD();
StopCARD();*/
if(flags & PSX_INIT_CD)
_internal_cdromlib_init();
printf("PSXSDK testing version !!!\n");
vblank_handler_set = 0;
_initex_end:
psxSdkFlags = flags;
}
void PSX_Init(void)
{
PSX_InitEx(PSX_INIT_CD);
}
void PSX_DeInit(void)
{
if(psxSdkFlags & PSX_INIT_CD)
{
EnterCriticalSection();
_96_remove();
ExitCriticalSection();
}
RemoveVBlankHandler();
if(psxSdkFlags & PSX_INIT_SAVESTATE)// This must always be the last to be called!
PSX_RestoreBiosState();
}
void PSX_ReadPad(unsigned short *padbuf, unsigned short *padbuf2)
{
int x;
unsigned char arr[PAD_READ_RAW_SIZE];
unsigned short *padbuf_a[2];
// Now uses low level pad routines...
padbuf_a[0] = padbuf;
padbuf_a[1] = padbuf2;
for(x = 0; x < 2; x++)
{
pad_read_raw(x, arr);
if(arr[2] == 0x5a)
{
*padbuf_a[x] = (arr[3]<<8)|arr[4];
*padbuf_a[x] = ~*padbuf_a[x];
}
else
*padbuf_a[x] = 0;
}
}
unsigned char psxsdkPadArr[PAD_READ_RAW_SIZE][2];
void PSX_ReadMouse(unsigned short* dig_pad1, unsigned short* adc_pad1)
{
unsigned char* arr = psxsdkPadArr[0];
const unsigned char pad_cmd[PAD_READ_RAW_SIZE] = {1,0x42,0,0,0,0,0}; // 2 extra bytes than digital pad
QueryPAD(0, pad_cmd, arr, sizeof(pad_cmd));
if(arr[2] == 0x5A)
{
*dig_pad1 = (arr[3]<<8)|arr[4];
*dig_pad1 = ~*dig_pad1;
*adc_pad1 = (arr[5]<<8)|arr[6];
}
else
{
*dig_pad1 = 0;
*adc_pad1 = 0;
}
}
void PSX_PollPad_Fast_Ex(const unsigned char* const arr, psx_pad_state* const pad_state)
{
//Rely on pad_read_raw being called AFTER PSX_ReadPad(),
//so that pad_read_raw is only called once.
pad_state->status = arr[0];
pad_state->id = arr[1];
pad_state->buttons = (arr[3]<<8)|arr[4];
pad_state->buttons = ~pad_state->buttons;
//dprintf("Pad Status: 0x%.2X\n",pad_state->status);
switch(pad_state->id)
{
case 0xFF:
pad_state->type = PADTYPE_NONE;
break;
case 0x41:
pad_state->type = PADTYPE_NORMALPAD;
break;
case 0x53:
pad_state->type = PADTYPE_ANALOGJOY;
pad_state->extra.analogJoy.x[0] = arr[5]-128;
pad_state->extra.analogJoy.y[0] = arr[6]-128;
pad_state->extra.analogJoy.x[1] = arr[7]-128;
pad_state->extra.analogJoy.y[1] = arr[8]-128;
break;
case 0x73:
pad_state->type = PADTYPE_ANALOGPAD;
pad_state->extra.analogPad.x[0] = arr[5]-128;
pad_state->extra.analogPad.y[0] = arr[6]-128;
pad_state->extra.analogPad.x[1] = arr[7]-128;
pad_state->extra.analogPad.y[1] = arr[8]-128;
break;
case 0x23:
pad_state->type = PADTYPE_NEGCON;
pad_state->extra.negCon.steering = arr[5]-128;
pad_state->extra.negCon.one = arr[6];
pad_state->extra.negCon.two = arr[7];
pad_state->extra.negCon.shoulder = arr[8];
break;
case 0x31:
pad_state->type = PADTYPE_KONAMIGUN;
break;
case 0x12:
pad_state->type = PADTYPE_MOUSE;
break;
default:
pad_state->type = PADTYPE_UNKNOWN;
}
}
void PSX_PollPad_Fast(int pad_num, psx_pad_state *pad_state)
{
PSX_PollPad_Fast_Ex(psxsdkPadArr[pad_num], pad_state);
}
void PSX_PollPad(int pad_num, psx_pad_state *pad_state)
{
// int x;
/*unsigned short *padbuf_a[2];
// Now uses low level pad routines...
padbuf_a[0] = padbuf;
padbuf_a[1] = padbuf2;
for(x = 0; x < 2; x++)
{
pad_read_raw(x, arr);
if(arr[2] == 0x5a)
{
*padbuf_a[x] = (arr[3]<<8)|arr[4];
*padbuf_a[x] = ~*padbuf_a[x];
}
else
*padbuf_a[x] = 0;
}*/
unsigned char *arr = psxsdkPadArr[pad_num];
pad_read_raw(pad_num, arr);
pad_state->status = arr[0];
pad_state->id = arr[1];
pad_state->buttons = (arr[3]<<8)|arr[4];
pad_state->buttons = ~pad_state->buttons;
switch(pad_state->id)
{
case 0xFF:
pad_state->type = PADTYPE_NONE;
break;
case 0x41:
pad_state->type = PADTYPE_NORMALPAD;
break;
case 0x53:
pad_state->type = PADTYPE_ANALOGJOY;
pad_state->extra.analogJoy.x[0] = arr[5]-128;
pad_state->extra.analogJoy.y[0] = arr[6]-128;
pad_state->extra.analogJoy.x[1] = arr[7]-128;
pad_state->extra.analogJoy.y[1] = arr[8]-128;
break;
case 0x73:
pad_state->type = PADTYPE_ANALOGPAD;
pad_state->extra.analogPad.x[0] = arr[5]-128;
pad_state->extra.analogPad.y[0] = arr[6]-128;
pad_state->extra.analogPad.x[1] = arr[7]-128;
pad_state->extra.analogPad.y[1] = arr[8]-128;
break;
case 0x23:
pad_state->type = PADTYPE_NEGCON;
pad_state->extra.negCon.steering = arr[5]-128;
pad_state->extra.negCon.one = arr[6];
pad_state->extra.negCon.two = arr[7];
pad_state->extra.negCon.shoulder = arr[8];
break;
case 0x31:
pad_state->type = PADTYPE_KONAMIGUN;
break;
default:
pad_state->type = PADTYPE_UNKNOWN;
}
}
/*int PSX_GetPadType(unsigned int pad_num)
//{
//#warning "Function does not currently work!"
// unsigned char arr[16];
pad_read_raw(pad_num, arr);
switch(arr[1])
{
case 0xFF:
return PADTYPE_NONE;
break;
case 0x41:
return PADTYPE_NORMALPAD;
break;
case 0x53:
return PADTYPE_ANALOGJOY;
break;
case 0x73:
return PADTYPE_ANALOGPAD;
break;
}
return PADTYPE_UNKNOWN;
}*/
void PSX_GetSysInfo(struct psx_info *info)
{
unsigned long i,i2;
info->kernel.version = GetKernelRomVersion();
i = GetKernelDate();
/*
* Convert year from BCD to decimal
*/
i2 = i >> 16;
info->kernel.year = i2 & 0xf;
info->kernel.year+= ((i2>>4)&0xf)*10;
info->kernel.year+= ((i2>>8)&0xf)*100;
info->kernel.year+= ((i2>>12)&0xf)*1000;
/*
* Convert month from BCD to decimal
*/
i2 = (i >> 8) & 0xff;
info->kernel.month = i2 & 0xf;
info->kernel.month+= (i2>>4) * 10;
/*
* Convert day from BCD to decimal
*/
i2 = i & 0xff;
info->kernel.day = i2 & 0xf;
info->kernel.day+= (i2>>4) * 10;
/*
* Unless we receive something in the range >= 1 && <= 16,
* RAM size will be reported as 2 Megabytes
*/
i = GetRamSize();
if(i == 0 || i > 16)
info->system.memory = 2<<20; /* 2 Megabytes */
else
info->system.memory <<= 20;
}
int get_real_file_size(const char *name)
{
struct DIRENTRY dirent_buf;
if(firstfile(name, &dirent_buf) == &dirent_buf)
return dirent_buf.size;
else
return 0;
}
int get_file_size(const char *name)
{
int i = get_real_file_size(name);
if(strncmp(name, "cdrom:", 6) == 0)
{
if(i & 0x7ff)
{
i += 0x800;
i &= ~0x7ff;
}
}else if(strncmp(name, "bu", 2) == 0)
{
if(i & 0x7f)
{
i += 0x80;
i &= ~0x7f;
}
}
return i;
}
int SetRCnt(int spec, unsigned short target, unsigned int mode)
{
spec &= 0xf;
if(spec >= 3)
return 0;
RCNT_MODE(spec)=0;
RCNT_TARGET(spec)=target;
RCNT_MODE(spec)=mode;
return 1;
}
int GetRCnt(int spec)
{
spec &= 0xf;
if(spec >= 4)
return -1;
return (RCNT_COUNT(spec) & 0xffff);
}
int StartRCnt(int spec)
{
spec &= 0xf;
if(spec >= 3)
return 0;
IMASK |= 1 << (spec + 4);
return 1;
}
int StopRCnt(int spec)
{
spec &= 0xf;
if(spec >= 3)
return 0;
IMASK ^= 1 << (spec + 4);
return 1;
}
void SetVBlankHandler(void (*callback)())
{
if(psxSdkFlags & PSX_INIT_NOBIOS)
{
_EXC_vblank_handler_set = 0;
_EXC_vblank_handler = callback;
_EXC_vblank_handler_set = 1;
return;
}
if(vblank_handler_set == 1)
{
EnterCriticalSection();
vblank_handler_callback = callback;
ExitCriticalSection();
return;
}
// Enter critical section
EnterCriticalSection();
IMASK|=1;
vblank_handler_event_id = OpenEvent(RCntCNT3, 2, 0x1000, vblank_handler);
EnableEvent(vblank_handler_event_id);
vblank_handler_callback = callback;
vblank_handler_set = 1;
// Exit critical section
ExitCriticalSection();
}
void RemoveVBlankHandler(void)
{
if(psxSdkFlags & PSX_INIT_NOBIOS)
{
_EXC_vblank_handler_set = 0;
_EXC_vblank_handler = NULL;
return;
}
if(vblank_handler_set)
{
EnterCriticalSection();
DisableEvent(vblank_handler_event_id);
CloseEvent(vblank_handler_event_id);
//IMASK^=1;
// ^ commented because masking out vblank could give problems to other bios functions
vblank_handler_set = 0;
ExitCriticalSection();
}
}
void SetRCntHandler(void (*callback)(), int spec, unsigned short target)
{
if(psxSdkFlags & PSX_INIT_NOBIOS)
return; // Not yet supported in No-Bios Mode
if(rcnt_handler_set)
{
EnterCriticalSection();
rcnt_handler_callback = callback;
ExitCriticalSection();
return;
}
// Enter critical section
SetRCnt(spec, target, RCntIntr | 0x08 | 0x10 | 0x40);
StartRCnt(spec);
EnterCriticalSection();
rcnt_handler_event_id = OpenEvent(spec, 2, 0x1000, rcnt_handler);
EnableEvent(rcnt_handler_event_id);
rcnt_handler_callback = callback;
rcnt_handler_set = spec;
switch(spec)
{
case RCntCNT0: rcnt_handler_evfield = 1 << 4; break;
case RCntCNT1: rcnt_handler_evfield = 1 << 5; break;
case RCntCNT2: rcnt_handler_evfield = 1 << 6; break;
case RCntCNT3: rcnt_handler_evfield = 1; break;
}
// Exit critical section
ExitCriticalSection();
}
void RemoveRCntHandler(int spec)
{
if(psxSdkFlags & PSX_INIT_NOBIOS)
return; // Not yet supported in No-Bios Mode
if(rcnt_handler_set)
{
EnterCriticalSection();
DisableEvent(rcnt_handler_event_id);
CloseEvent(rcnt_handler_event_id);
rcnt_handler_set = 0;
ExitCriticalSection();
}
}
const char *GetSystemRomVersion(void)
{
// Get pointer to zero-terminated string containing System ROM Version which is embedded in
// most PlayStation BIOSes.
// If getting the pointer is not possible, a pointer to a string saying "System ROM Unavailable" is returned.
int x;
for(x = 0x7ffee; x >= 0; x--)
if(memcmp("System ROM Version", (void*)(0xbfc00000 + x), 18) == 0)
return (char*)(0xbfc00000 + x);
return sysromver_unavail;
}
int PSX_RestoreBiosState(void)
{
if(!(psxSdkFlags & PSX_INIT_SAVESTATE))
return 0; // can't restore BIOS state if it was not saved previously
EnterCriticalSection();
memcpy((void*)0x80000000, psxBiosState, 0x10000);
ExitCriticalSection();
return 1;
}
unsigned int PSX_GetInitFlags(void)
{
return psxSdkFlags;
}
void PSX_WarmReboot(void)
{
if(psxSdkFlags & PSX_INIT_NOBIOS)
{
psx_warmreboot_nobios:
PSX_DeInit();
__asm__("j _start");
__asm__("nop");
}
else
{
if(!(psxSdkFlags & PSX_INIT_CD))
goto psx_warmreboot_nobios;
BIOSWarmReboot();
}
}