#include <stdio.h>
#include "ao.h"
#include "cpuintrf.h"
#include "psx.h"
#define DEBUG_HLE_BIOS (0)
#define DEBUG_HLE_IOP (0)
#define DEBUG_UNK_RW (0)
#define DEBUG_THREADING (0)
extern void mips_get_info(UINT32 state, union cpuinfo *info);
extern void mips_set_info(UINT32 state, union cpuinfo *info);
extern int psxcpu_verbose;
extern uint16 SPUreadRegister(uint32 reg);
extern void SPUwriteRegister(uint32 reg, uint16 val);
extern void SPUwriteDMAMem(uint32 usPSXMem,int iSize);
extern void SPUreadDMAMem(uint32 usPSXMem,int iSize);
extern void mips_shorten_frame(void);
extern int mips_execute( int cycles );
extern uint32 psf2_load_file(char *file, uint8 *buf, uint32 buflen);
extern uint32 psf2_load_elf(uint8 *start, uint32 len);
void psx_hw_runcounters(void);
int mips_get_icount(void);
void mips_set_icount(int count);
extern int psf_refresh;
static int skipyet = 0;
extern void SPU2write(unsigned long reg, unsigned short val);
extern unsigned short SPU2read(unsigned long reg);
extern void SPU2readDMA4Mem(uint32 usPSXMem,int iSize);
extern void SPU2writeDMA4Mem(uint32 usPSXMem,int iSize);
extern void SPU2readDMA7Mem(uint32 usPSXMem,int iSize);
extern void SPU2writeDMA7Mem(uint32 usPSXMem,int iSize);
extern void SPU2interruptDMA4(void);
extern void SPU2interruptDMA7(void);
#define MAX_FILE_SLOTS (32)
static volatile int softcall_target = 0;
static int filestat[MAX_FILE_SLOTS];
static uint8 *filedata[MAX_FILE_SLOTS];
static uint32 filesize[MAX_FILE_SLOTS], filepos[MAX_FILE_SLOTS];
uint32 psf2_get_loadaddr(void);
void psf2_set_loadaddr(uint32 new);
static void call_irq_routine(uint32 routine, uint32 parameter);
static int intr_susp = 0;
static uint64 sys_time;
static int timerexp = 0;
typedef struct
{
char name[10];
uint32 dispatch;
} ExternLibEntries;
static int32 iNumLibs;
static ExternLibEntries reglibs[32];
typedef struct
{
uint32 type;
uint32 value;
uint32 param;
int inUse;
} EventFlag;
static int32 iNumFlags;
static EventFlag evflags[32];
typedef struct
{
uint32 attr;
uint32 option;
int32 init;
int32 current;
int32 max;
int32 threadsWaiting;
int32 inuse;
} Semaphore;
#define SEMA_MAX (64)
static int32 iNumSema;
static Semaphore semaphores[SEMA_MAX];
enum
{
TS_RUNNING = 0, TS_READY, TS_WAITEVFLAG, TS_WAITSEMA, TS_WAITDELAY, TS_SLEEPING, TS_CREATED,
TS_MAXSTATE
};
typedef struct
{
int32 iState;
uint32 flags; uint32 routine; uint32 stackloc; uint32 stacksize; uint32 refCon;
uint32 waitparm;
uint32 save_regs[37]; } Thread;
static int32 iNumThreads, iCurThread;
static Thread threads[32];
#if DEBUG_THREADING
static char *_ThreadStateNames[TS_MAXSTATE] = { "RUNNING", "READY", "WAITEVFLAG", "WAITSEMA", "WAITDELAY", "SLEEPING", "CREATED" };
#endif
#if DEBUG_HLE_IOP
static char *seek_types[3] = { "SEEK_SET", "SEEK_CUR", "SEEK_END" };
#endif
typedef struct
{
int32 iActive;
uint32 count;
uint32 target;
uint32 source;
uint32 prescale;
uint32 handler;
uint32 hparam;
uint32 mode;
} IOPTimer;
static IOPTimer iop_timers[8];
static int32 iNumTimers;
typedef struct
{
uint32 count;
uint32 mode;
uint32 target;
uint32 sysclock;
} Counter;
static Counter root_cnts[3];
#define CLOCK_DIV (8)
#define RC_EN (0x0001)
#define RC_RESET (0x0008)
#define RC_IQ1 (0x0010)
#define RC_IQ2 (0x0040)
#define RC_CLC (0x0100)
#define RC_DIV8 (0x0200)
typedef struct
{
uint32 desc;
int32 status;
int32 mode;
uint32 fhandler;
} EvtCtrlBlk[32];
static EvtCtrlBlk *Event;
static EvtCtrlBlk *CounterEvent;
#define EvStUNUSED 0x0000
#define EvStWAIT 0x1000
#define EvStACTIVE 0x2000
#define EvStALREADY 0x4000
#define EvMdINTR 0x1000
#define EvMdNOINTR 0x2000
uint32 psx_ram[(2*1024*1024)/4];
uint32 psx_scratch[0x400];
uint32 initial_ram[(2*1024*1024)/4];
uint32 initial_scratch[0x400];
static uint32 spu_delay, dma_icr, irq_data, irq_mask, dma_timer, WAI;
static uint32 dma4_madr, dma4_bcr, dma4_chcr, dma4_delay;
static uint32 dma7_madr, dma7_bcr, dma7_chcr, dma7_delay;
static uint32 dma4_cb, dma7_cb, dma4_fval, dma4_flag, dma7_fval, dma7_flag;
static uint32 irq9_cb, irq9_fval, irq9_flag;
static void FreezeThread(int32 iThread, int flag)
{
int i;
union cpuinfo mipsinfo;
#if DEBUG_THREADING
#endif
for (i = 0; i < 32; i++)
{
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R0 + i, &mipsinfo);
threads[iThread].save_regs[i] = mipsinfo.i;
}
mips_get_info(CPUINFO_INT_REGISTER + MIPS_HI, &mipsinfo);
threads[iThread].save_regs[32] = mipsinfo.i;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_LO, &mipsinfo);
threads[iThread].save_regs[33] = mipsinfo.i;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_DELAYV, &mipsinfo);
threads[iThread].save_regs[35] = mipsinfo.i;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_DELAYR, &mipsinfo);
threads[iThread].save_regs[36] = mipsinfo.i;
if (flag)
{
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
}
else
{
mips_get_info(CPUINFO_INT_PC, &mipsinfo);
}
threads[iThread].save_regs[34] = mipsinfo.i;
#if DEBUG_THREADING
{
char buffer[256];
DasmMIPS(buffer, mipsinfo.i, &psx_ram[(mipsinfo.i & 0x7fffffff)/4]);
printf("IOP: FreezeThread(%d) => %08x [%s]\n", iThread, threads[iThread].save_regs[34], buffer);
}
#endif
if (threads[iThread].iState == TS_RUNNING)
{
threads[iThread].iState = TS_READY;
}
}
static void ThawThread(int32 iThread)
{
int i;
union cpuinfo mipsinfo;
if (threads[iThread].iState == TS_CREATED)
{
threads[iThread].save_regs[34] = threads[iThread].routine-4; threads[iThread].save_regs[29] = (threads[iThread].stackloc + threads[iThread].stacksize) - 16;
threads[iThread].save_regs[29] |= 0x80000000;
threads[iThread].save_regs[35] = threads[iThread].save_regs[36] = 0;
#if DEBUG_THREADING
#endif
}
#if DEBUG_THREADING
{
char buffer[256];
mips_get_info(CPUINFO_INT_PC, &mipsinfo);
DasmMIPS(buffer, mipsinfo.i, &psx_ram[(mipsinfo.i & 0x7fffffff)/4]);
printf("IOP: ThawThread(%d) => %08x [%s] (wake %d)\n", iThread, threads[iThread].save_regs[34], buffer, wakecount);
}
#endif
for (i = 0; i < 32; i++)
{
mipsinfo.i = threads[iThread].save_regs[i];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R0 + i, &mipsinfo);
}
mipsinfo.i = threads[iThread].save_regs[32];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_HI, &mipsinfo);
mipsinfo.i = threads[iThread].save_regs[33];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_LO, &mipsinfo);
mipsinfo.i = threads[iThread].save_regs[34];
mips_set_info(CPUINFO_INT_PC, &mipsinfo);
mipsinfo.i = threads[iThread].save_regs[35];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_DELAYV, &mipsinfo);
mipsinfo.i = threads[iThread].save_regs[36];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_DELAYR, &mipsinfo);
threads[iThread].iState = TS_RUNNING;
}
static void ps2_reschedule(void)
{
int i, starti, iNextThread;
iNextThread = -1;
i = iCurThread+1;
if (i >= iNumThreads)
{
i = 0;
}
starti = i;
while (i < iNumThreads)
{
if (i != iCurThread)
{
if (threads[i].iState == TS_READY)
{
iNextThread = i;
break;
}
}
i++;
}
if ((starti > 0) && (iNextThread == -1))
{
for (i = 0; i < iNumThreads; i++)
{
if (i != iCurThread)
{
if (threads[i].iState == TS_READY)
{
iNextThread = i;
break;
}
}
}
}
if (iNextThread != -1)
{
#if DEBUG_THREADING
for (i = 0; i < iNumThreads; i++)
{
printf("Thread %02d: %s\n", i, _ThreadStateNames[threads[i].iState]);
}
#endif
if (iCurThread != -1)
{
FreezeThread(iCurThread, 0);
}
ThawThread(iNextThread);
iCurThread = iNextThread;
threads[iCurThread].iState = TS_RUNNING;
}
else
{
if (iCurThread != -1)
{
if (threads[iCurThread].iState != TS_RUNNING)
{
#if DEBUG_THREADING
printf("IOP: no threads to run\n");
for (i = 0; i < iNumThreads; i++)
{
printf("Thread %02d: %s\n", i, _ThreadStateNames[threads[i].iState]);
}
#endif
mips_shorten_frame(); iCurThread = -1; }
}
else
{
mips_shorten_frame(); iCurThread = -1; }
}
}
static void psx_irq_update(void)
{
union cpuinfo mipsinfo;
if ((irq_data & irq_mask) != 0)
{ WAI = 0;
mipsinfo.i = ASSERT_LINE;
mips_set_info( CPUINFO_INT_INPUT_STATE + MIPS_IRQ0, &mipsinfo );
}
else
{
mipsinfo.i = CLEAR_LINE;
mips_set_info( CPUINFO_INT_INPUT_STATE + MIPS_IRQ0, &mipsinfo );
}
}
void psx_irq_set(uint32 irq)
{
irq_data |= irq;
psx_irq_update();
}
static uint32 gpu_stat = 0;
uint32 psx_hw_read(offs_t offset, uint32 mem_mask)
{
if (offset >= 0x00000000 && offset <= 0x007fffff)
{
offset &= 0x1fffff;
return LE32(psx_ram[offset>>2]);
}
if (offset >= 0x80000000 && offset <= 0x807fffff)
{
offset &= 0x1fffff;
return LE32(psx_ram[offset>>2]);
}
if (offset == 0xbfc00180 || offset == 0xbfc00184) {
return FUNCT_HLECALL;
}
if (offset == 0x1f801014)
{
return spu_delay;
}
if (offset == 0xbf801014)
{
return spu_delay;
}
if (offset == 0x1f801814)
{
gpu_stat ^= 0xffffffff;
return gpu_stat;
}
if (offset >= 0x1f801c00 && offset <= 0x1f801dff)
{
if ((mem_mask == 0xffff0000) || (mem_mask == 0xffffff00))
{
return SPUreadRegister(offset) & ~mem_mask;
}
else if (mem_mask == 0x0000ffff)
{
return SPUreadRegister(offset)<<16;
}
else printf("SPU: read unknown mask %08x\n", mem_mask);
}
if (offset >= 0xbf900000 && offset <= 0xbf9007ff)
{
if ((mem_mask == 0xffff0000) || (mem_mask == 0xffffff00))
{
return SPU2read(offset) & ~mem_mask;
}
else if (mem_mask == 0x0000ffff)
{
return SPU2read(offset)<<16;
}
else if (mem_mask == 0)
{
return SPU2read(offset) | SPU2read(offset+2)<<16;
}
else printf("SPU2: read unknown mask %08x\n", mem_mask);
}
if (offset >= 0x1f801100 && offset <= 0x1f801128)
{
int cnt = (offset>>4) & 0xf;
switch (offset & 0xf)
{
case 0:
return root_cnts[cnt].count;
break;
case 4:
return root_cnts[cnt].mode;
break;
case 8:
return root_cnts[cnt].target;
break;
}
return 0;
}
if (offset == 0x1f8010f4)
{
return dma_icr;
}
else if (offset == 0x1f801070)
{
return irq_data;
}
else if (offset == 0x1f801074)
{
return irq_mask;
}
if (offset == 0xbf920344)
{
return 0x80808080;
}
#if DEBUG_UNK_RW
{
union cpuinfo mipsinfo;
mips_get_info(CPUINFO_INT_PC, &mipsinfo);
printf("Unknown read: %08x, mask %08x (PC=%x)\n", offset&~3, mem_mask, mipsinfo.i);
}
#endif
return 0;
}
static void psx_dma4(uint32 madr, uint32 bcr, uint32 chcr)
{
if (chcr == 0x01000201) {
bcr = (bcr>>16) * (bcr & 0xffff) * 2;
SPUwriteDMAMem(madr&0x1fffff, bcr);
}
else
{
bcr = (bcr>>16) * (bcr & 0xffff) * 2;
SPUreadDMAMem(madr&0x1fffff, bcr);
}
}
static void ps2_dma4(uint32 madr, uint32 bcr, uint32 chcr)
{
if (chcr == 0x01000201) {
#if DEBUG_HLE_IOP
printf("DMA4: RAM %08x to SPU2\n", madr);
#endif
bcr = (bcr>>16) * (bcr & 0xffff) * 4;
SPU2writeDMA4Mem(madr&0x1fffff, bcr);
}
else
{
#if DEBUG_HLE_IOP
printf("DMA4: SPU2 to RAM %08x\n", madr);
#endif
bcr = (bcr>>16) * (bcr & 0xffff) * 4;
SPU2readDMA4Mem(madr&0x1fffff, bcr);
}
dma4_delay = 80;
}
static void ps2_dma7(uint32 madr, uint32 bcr, uint32 chcr)
{
if ((chcr == 0x01000201) || (chcr == 0x00100010) || (chcr == 0x000f0010) || (chcr == 0x00010010)) {
#if DEBUG_HLE_IOP
printf("DMA7: RAM %08x to SPU2\n", madr);
#endif
bcr = (bcr>>16) * (bcr & 0xffff) * 4;
SPU2writeDMA7Mem(madr&0x1fffff, bcr);
}
else
{
#if DEBUG_HLE_IOP
printf("DMA7: SPU2 to RAM %08x\n", madr);
#endif
bcr = (bcr>>16) * (bcr & 0xffff) * 4;
}
dma7_delay = 80;
}
void psx_hw_write(offs_t offset, uint32 data, uint32 mem_mask)
{
union cpuinfo mipsinfo;
if (offset >= 0x00000000 && offset <= 0x007fffff)
{
offset &= 0x1fffff;
mips_get_info(CPUINFO_INT_PC, &mipsinfo);
psx_ram[offset>>2] &= LE32(mem_mask);
psx_ram[offset>>2] |= LE32(data);
return;
}
if (offset >= 0x80000000 && offset <= 0x807fffff)
{
offset &= 0x1fffff;
mips_get_info(CPUINFO_INT_PC, &mipsinfo);
psx_ram[offset>>2] &= LE32(mem_mask);
psx_ram[offset>>2] |= LE32(data);
return;
}
if (offset == 0x1f801014 || offset == 0xbf801014)
{
spu_delay &= mem_mask;
spu_delay |= data;
return;
}
if (offset >= 0x1f801c00 && offset <= 0x1f801dff)
{
if (mem_mask == 0xffff0000)
{
SPUwriteRegister(offset, data);
return;
}
else if (mem_mask == 0x0000ffff)
{
SPUwriteRegister(offset, data>>16);
return;
}
else printf("SPU: write unknown mask %08x\n", mem_mask);
}
if (offset >= 0xbf900000 && offset <= 0xbf9007ff)
{
if (mem_mask == 0xffff0000)
{
SPU2write(offset, data);
return;
}
else if (mem_mask == 0x0000ffff)
{
SPU2write(offset, data>>16);
return;
}
else if (mem_mask == 0)
{
SPU2write(offset, data & 0xffff);
SPU2write(offset+2, data>>16);
return;
}
else printf("SPU2: write unknown mask %08x\n", mem_mask);
}
if (offset >= 0x1f801100 && offset <= 0x1f801128)
{
int cnt = (offset>>4) & 0xf;
switch (offset & 0xf)
{
case 0:
root_cnts[cnt].count = data;
break;
case 4:
root_cnts[cnt].mode = data;
break;
case 8:
root_cnts[cnt].target = data;
break;
}
return;
}
if (offset == 0x1f8010c0)
{
dma4_madr = data;
return;
}
else if (offset == 0x1f8010c4)
{
dma4_bcr = data;
return;
}
else if (offset == 0x1f8010c8)
{
dma4_chcr = data;
psx_dma4(dma4_madr, dma4_bcr, dma4_chcr);
if (dma_icr & (1 << (16+4)))
{
dma_timer = 3;
}
return;
}
else if (offset == 0x1f8010f4)
{
dma_icr = ( dma_icr & mem_mask ) |
( ~mem_mask & 0x80000000 & dma_icr) |
( ~data & ~mem_mask & 0x7f000000 & dma_icr) |
( data & ~mem_mask & 0x00ffffff);
if ((dma_icr & 0x7f000000) != 0)
{
dma_icr &= ~0x80000000;
}
return;
}
else if (offset == 0x1f801070)
{
irq_data = (irq_data & mem_mask) | (irq_data & irq_mask & data);
psx_irq_update();
return;
}
else if (offset == 0x1f801074)
{
irq_mask &= mem_mask;
irq_mask |= data;
psx_irq_update();
return;
}
if (offset == 0xbf8010c0)
{
dma4_madr = data;
return;
}
else if (offset == 0xbf8010c8)
{
dma4_chcr = data;
ps2_dma4(dma4_madr, dma4_bcr, dma4_chcr);
if (dma_icr & (1 << (16+4)))
{
dma_timer = 3;
}
return;
}
if (offset == 0xbf8010c4 || offset == 0xbf8010c6)
{
dma4_bcr &= mem_mask;
dma4_bcr |= data;
return;
}
if (offset == 0xbf801500)
{
dma7_madr = data;
return;
}
else if (offset == 0xbf801504)
{
dma7_chcr = data;
ps2_dma7(dma7_madr, dma7_bcr, dma7_chcr);
return;
}
if (offset == 0xbf801508 || offset == 0xbf80150a)
{
dma7_bcr &= mem_mask;
dma7_bcr |= data;
return;
}
#if DEBUG_UNK_RW
{
union cpuinfo mipsinfo;
mips_get_info(CPUINFO_INT_PC, &mipsinfo);
printf("Unknown write: %08x to %08x, mask %08x (PC=%x)\n", data, offset&~3, mem_mask, mipsinfo.i);
}
#endif
}
void psx_hw_slice(void)
{
psx_hw_runcounters();
if (!WAI)
mips_execute(768/CLOCK_DIV);
if (dma_timer)
{
dma_timer--;
if (dma_timer == 0)
{
dma_icr |= (1 << (24+4));
psx_irq_set(0x0008);
}
}
}
void ps2_hw_slice(void)
{
int i = 0;
timerexp = 0;
psx_hw_runcounters();
if (iCurThread != -1)
{
mips_execute(836/CLOCK_DIV);
}
else {
if (timerexp)
{
ps2_reschedule();
if (iCurThread != -1)
{
mips_execute((836/CLOCK_DIV)-i);
i = (836/CLOCK_DIV);
}
}
}
}
static int fcnt = 0;
void psx_hw_frame(void)
{
if (psf_refresh == 50)
{
fcnt++;;
if (fcnt < 6)
{
psx_irq_set(1);
}
else
{
fcnt = 0;
}
}
else {
psx_irq_set(1);
}
}
void ps2_hw_frame(void)
{
ps2_reschedule();
}
enum
{
BLK_STAT = 0,
BLK_SIZE = 4,
BLK_FD = 8,
BLK_BK = 12
};
static uint32 heap_addr, entry_int = 0;
extern uint32 mips_get_cause(void);
extern uint32 mips_get_status(void);
extern void mips_set_status(uint32 status);
extern uint32 mips_get_ePC(void);
static uint32 irq_regs[37];
static int irq_mutex = 0;
static void call_irq_routine(uint32 routine, uint32 parameter)
{
int j, oldICount;
union cpuinfo mipsinfo;
if (!irq_mutex)
{
irq_mutex = 1;
}
else
{
printf("IOP: ERROR! IRQ reentry!\n");
return;
}
for (j = 0; j < 32; j++)
{
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R0 + j, &mipsinfo);
irq_regs[j] = mipsinfo.i;
}
mips_get_info(CPUINFO_INT_REGISTER + MIPS_HI, &mipsinfo);
irq_regs[32] = mipsinfo.i;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_LO, &mipsinfo);
irq_regs[33] = mipsinfo.i;
mips_get_info(CPUINFO_INT_PC, &mipsinfo);
irq_regs[34] = mipsinfo.i;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_DELAYV, &mipsinfo);
irq_regs[35] = mipsinfo.i;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_DELAYR, &mipsinfo);
irq_regs[36] = mipsinfo.i;
mipsinfo.i = routine;
mips_set_info(CPUINFO_INT_PC, &mipsinfo);
mipsinfo.i = parameter;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R4, &mipsinfo);
mipsinfo.i = 0x80001000;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
psx_ram[0x1000/4] = LE32(FUNCT_HLECALL);
softcall_target = 0;
oldICount = mips_get_icount();
while (!softcall_target)
{
mips_execute(10);
}
mips_set_icount(oldICount);
for (j = 0; j < 32; j++)
{
mipsinfo.i = irq_regs[j];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R0 + j, &mipsinfo);
}
mipsinfo.i = irq_regs[32];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_HI, &mipsinfo);
mipsinfo.i = irq_regs[33];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_LO, &mipsinfo);
mipsinfo.i = irq_regs[34];
mips_set_info(CPUINFO_INT_PC, &mipsinfo);
mipsinfo.i = irq_regs[35];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_DELAYV, &mipsinfo);
mipsinfo.i = irq_regs[36];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_DELAYR, &mipsinfo);
irq_mutex = 0;
}
void psx_bios_exception(uint32 pc)
{
uint32 a0, status;
union cpuinfo mipsinfo;
int i, oldICount;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R4, &mipsinfo);
a0 = mipsinfo.i;
switch (mips_get_cause() & 0x3c)
{
case 0: for (i = 0; i < 32; i++)
{
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R0 + i, &mipsinfo);
irq_regs[i] = mipsinfo.i;
}
mips_get_info(CPUINFO_INT_REGISTER + MIPS_HI, &mipsinfo);
irq_regs[32] = mipsinfo.i;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_LO, &mipsinfo);
irq_regs[33] = mipsinfo.i;
if (irq_data & 1) {
if (CounterEvent[3][1].status == LE32(EvStACTIVE))
{
mipsinfo.i = LE32(CounterEvent[3][1].fhandler);
mips_set_info(CPUINFO_INT_PC, &mipsinfo);
mipsinfo.i = 0x80001000;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
psx_ram[0x1000/4] = LE32(FUNCT_HLECALL);
softcall_target = 0;
oldICount = mips_get_icount();
while (!softcall_target)
{
mips_execute(10);
}
mips_set_icount(oldICount);
irq_data &= ~1; }
}
else if (irq_data & 0x70) {
for (i = 0; i < 3; i++)
{
if (irq_data & (1 << (i+4)))
{
if (CounterEvent[i][1].status == LE32(EvStACTIVE))
{
mipsinfo.i = LE32(CounterEvent[i][1].fhandler);
mips_set_info(CPUINFO_INT_PC, &mipsinfo);
mipsinfo.i = 0x80001000;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
psx_ram[0x1000/4] = LE32(FUNCT_HLECALL);
softcall_target = 0;
oldICount = mips_get_icount();
while (!softcall_target)
{
mips_execute(10);
}
mips_set_icount(oldICount);
irq_data &= ~(1 << (i+4));
}
else
{
}
}
}
}
if (entry_int)
{
psx_hw_write(0x1f801070, 0xffffffff, 0);
a0 = entry_int;
mipsinfo.i = LE32(psx_ram[((a0&0x1fffff)+0)/4]);
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
mips_set_info(CPUINFO_INT_PC, &mipsinfo);
mipsinfo.i = LE32(psx_ram[((a0&0x1fffff)+4)/4]);
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R29, &mipsinfo);
mipsinfo.i = LE32(psx_ram[((a0&0x1fffff)+8)/4]);
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R30, &mipsinfo);
for (i = 0; i < 8; i++)
{
mipsinfo.i = LE32(psx_ram[((a0&0x1fffff)+12+(i*4))/4]);
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R16 + i, &mipsinfo);
}
mipsinfo.i = LE32(psx_ram[((a0&0x1fffff)+44)/4]);
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R28, &mipsinfo);
mipsinfo.i = 1;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
else
{
psx_hw_write(0x1f801070, 0, 0xffff0000);
for (i = 0; i < 32; i++)
{
mipsinfo.i = irq_regs[i];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R0 + i, &mipsinfo);
}
mipsinfo.i = irq_regs[32];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_HI, &mipsinfo);
mipsinfo.i = irq_regs[33];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_LO, &mipsinfo);
mipsinfo.i = mips_get_ePC();
mips_set_info(CPUINFO_INT_PC, &mipsinfo);
status = mips_get_status();
status = (status & 0xfffffff0) | ((status & 0x3c)>>2);
mips_set_status(status);
}
break;
case 0x20: status = mips_get_status();
switch (a0)
{
case 1: #if DEBUG_HLE_BIOS
printf("HLEBIOS: EnterCritical\n");
#endif
status &= ~0x0404;
break;
case 2: #if DEBUG_HLE_BIOS
printf("HLEBIOS: ExitCritical\n");
#endif
status |= 0x0404;
break;
default:
#if DEBUG_HLE_BIOS
printf("HLEBIOS: Unknown syscall %x\n", a0);
#endif
break;
}
mipsinfo.i = mips_get_ePC() + 4;
mips_set_info(CPUINFO_INT_PC, &mipsinfo);
status = (status & 0xfffffff0) | ((status & 0x3c)>>2);
mips_set_status(status);
break;
default:
#if DEBUG_HLE_BIOS
printf("HLEBIOS: Unknown exception %x\n", mips_get_cause());
#endif
break;
}
}
static uint32 calc_ev(uint32 a0)
{
uint32 ev;
ev = (a0 >> 24) & 0xf;
if (ev == 0xf)
{
ev = 0x5;
}
ev *= 32;
ev += (a0 & 0x1f);
return ev;
}
static uint32 calc_spec(uint32 a1)
{
uint32 spec = 0;
int i;
if (a1 == 0x301)
{
spec = 16;
}
else if (a1 == 0x302)
{
spec = 17;
}
else
{
for (i = 0; i < 16; i++)
{
if (a1 & (1<<i))
{
spec = i;
break;
}
}
}
return spec;
}
void psx_hw_init(void)
{
timerexp = 0;
memset(filestat, 0, sizeof(filestat));
memset(filedata, 0, sizeof(filedata));
dma4_cb = dma7_cb = 0;
sys_time = 0;
memset(reglibs, 0, sizeof(reglibs));
iNumLibs = 0;
memset(evflags, 0, sizeof(evflags));
iNumFlags = 0;
memset(threads, 0, sizeof(threads));
iNumThreads = 1;
memset(semaphores, 0, sizeof(semaphores));
iNumSema = 0;
threads[0].iState = TS_RUNNING;
iCurThread = 0;
memset(iop_timers, 0, sizeof(iop_timers));
iNumTimers = 0;
psx_ram[0xa0/4] = LE32(FUNCT_HLECALL);
psx_ram[0xb0/4] = LE32(FUNCT_HLECALL);
psx_ram[0xc0/4] = LE32(FUNCT_HLECALL);
Event = (EvtCtrlBlk *)&psx_ram[0x1000/4];
CounterEvent = (Event + (32*2));
dma_icr = 0;
spu_delay = 0;
irq_data = 0;
irq_mask = 0;
softcall_target = 0;
gpu_stat = 0;
dma4_madr = dma4_bcr = dma4_chcr = 0;
heap_addr = 0;
entry_int = 0;
WAI = 0;
root_cnts[0].mode = RC_EN;
root_cnts[1].mode = RC_EN;
root_cnts[2].mode = RC_EN;
root_cnts[0].sysclock = 0;
root_cnts[1].sysclock = 0;
root_cnts[2].sysclock = 0;
}
void psx_bios_hle(uint32 pc)
{
uint32 subcall, status;
union cpuinfo mipsinfo;
uint32 a0, a1, a2, a3;
int i;
if ((pc == 0) || (pc == 0x80000000)) {
#if DEBUG_HLE_IOP
printf("IOP 'null' state\n");
#endif
return;
}
if (pc == 0xbfc00180 || pc == 0xbfc00184) {
psx_bios_exception(pc);
return;
}
if (pc == 0x80001000)
{
softcall_target = 1;
return;
}
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R9, &mipsinfo);
subcall = mipsinfo.i & 0xff;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R4, &mipsinfo);
a0 = mipsinfo.i;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R5, &mipsinfo);
a1 = mipsinfo.i;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R6, &mipsinfo);
a2 = mipsinfo.i;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R7, &mipsinfo);
a3 = mipsinfo.i;
switch (pc)
{
case 0xa0: switch (subcall)
{
case 0x13: mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
psx_ram[((a0&0x1fffff)+0)/4] = LE32(mipsinfo.i);
#if DEBUG_HLE_BIOS
printf("HLEBIOS: setjmp(%08x) => PC %08x\n", a0, mipsinfo.i);
#endif
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R29, &mipsinfo);
psx_ram[((a0&0x1fffff)+4)/4] = LE32(mipsinfo.i);
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R30, &mipsinfo);
psx_ram[((a0&0x1fffff)+8)/4] = LE32(mipsinfo.i);
for (i = 0; i < 8; i++)
{
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R16 + i, &mipsinfo);
psx_ram[((a0&0x1fffff)+12+(i*4))/4] = LE32(mipsinfo.i);
}
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R28, &mipsinfo);
psx_ram[((a0&0x1fffff)+44)/4] = LE32(mipsinfo.i);
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 0x18: {
uint8 *dst, *src;
#if DEBUG_HLE_BIOS
printf("HLEBIOS: strncmp(%08x, %08x, %d)\n", a0, a1, a2);
#endif
dst = (uint8 *)psx_ram;
src = (uint8 *)psx_ram;
dst += (a0 & 0x1fffff);
src += (a1 & 0x1fffff);
mipsinfo.i = strncmp((char *)dst, (char *)src, a2);
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
break;
case 0x19: {
uint8 *dst, *src;
#if DEBUG_HLE_BIOS
printf("HLEBIOS: strcpy(%08x, %08x)\n", a0, a1);
#endif
dst = (uint8 *)psx_ram;
src = (uint8 *)psx_ram;
dst += (a0 & 0x1fffff);
src += (a1 & 0x1fffff);
while (*src)
{
*dst = *src;
dst++;
src++;
}
mipsinfo.i = a0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
break;
case 0x28: {
uint8 *dst;
#if DEBUG_HLE_BIOS
printf("HLEBIOS: bzero(%08x, %08x)\n", a0, a1);
#endif
dst = (uint8 *)psx_ram;
dst += (a0 & 0x1fffff);
memset(dst, 0, a1);
}
break;
case 0x2a: {
uint8 *dst, *src;
#if DEBUG_HLE_BIOS
printf("HLEBIOS: memcpy(%08x, %08x, %08x)\n", a0, a1, a2);
#endif
dst = (uint8 *)psx_ram;
src = (uint8 *)psx_ram;
dst += (a0 & 0x1fffff);
src += (a1 & 0x1fffff);
while (a2)
{
*dst = *src;
dst++;
src++;
a2--;
}
mipsinfo.i = a0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
break;
case 0x2b: {
uint8 *dst;
#if DEBUG_HLE_BIOS
printf("HLEBIOS: memset(%08x, %08x, %08x)\n", a0, a1, a2);
#endif
dst = (uint8 *)psx_ram;
dst += (a0 & 0x1fffff);
while (a2)
{
*dst = a1;
dst++;
a2--;
}
mipsinfo.i = a0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
break;
case 0x2f: #if DEBUG_HLE_BIOS
printf("HLEBIOS: rand\n");
#endif
mipsinfo.i = 1 + (int)(32767.0*rand()/(RAND_MAX+1.0));
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 0x30: #if DEBUG_HLE_BIOS
printf("HLEBIOS: srand(%x)\n", a0);
#endif
srand(a0);
break;
case 0x33: {
uint32 chunk, fd;
#if DEBUG_HLE_BIOS
printf("HLEBIOS: malloc(%x)\n", a0);
#endif
chunk = heap_addr;
while ((a0 > LE32(psx_ram[(chunk+BLK_SIZE)/4])) ||
(LE32(psx_ram[(chunk+BLK_STAT)/4]) == 1))
{
chunk = LE32(psx_ram[(chunk+BLK_FD)]);
}
fd = chunk + 16 + a0; psx_ram[(fd+BLK_STAT)/4] = psx_ram[(chunk+BLK_STAT)/4];
psx_ram[(fd+BLK_SIZE)/4] = LE32(LE32(psx_ram[(chunk+BLK_SIZE)/4]) - a0);
psx_ram[(fd+BLK_FD)/4] = psx_ram[(chunk+BLK_FD)/4];
psx_ram[(fd+BLK_BK)/4] = chunk;
psx_ram[(chunk+BLK_STAT)/4] = LE32(1);
psx_ram[(chunk+BLK_SIZE)/4] = LE32(a0);
psx_ram[(chunk+BLK_FD)/4] = LE32(fd);
mipsinfo.i = chunk + 16;
mipsinfo.i |= 0x80000000;
#if DEBUG_HLE_BIOS
printf("== %08x\n", mipsinfo.i);
#endif
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
break;
case 0x39: #if DEBUG_HLE_BIOS
printf("HLEBIOS: InitHeap(%08x, %08x)\n", a0, a1);
#endif
heap_addr = a0 & 0x3fffffff;
psx_ram[(heap_addr+BLK_STAT)/4] = LE32(0);
psx_ram[(heap_addr+BLK_FD)/4] = LE32(0);
psx_ram[(heap_addr+BLK_BK)/4] = LE32(0);
if (((a0 & 0x1fffff) + a1) >= 2*1024*1024)
{
psx_ram[(heap_addr+BLK_SIZE)/4] = LE32(0x1ffffc - (a0 & 0x1fffff));
}
else
{
psx_ram[(heap_addr+BLK_SIZE)/4] = LE32(a1);
}
break;
case 0x3f: #if DEBUG_HLE_BIOS
printf("HLEBIOS: printf(%08x) = %s\n", a0, &psx_ram[(a0&0x1fffff)/4]);
#endif
break;
case 0x72: #if DEBUG_HLE_BIOS
printf("HLEBIOS: __96_remove\n");
#endif
break;
default:
#if DEBUG_HLE_BIOS
printf("Unknown BIOS A0 call = %x\n", subcall);
#endif
break;
}
break;
case 0xb0: switch (subcall)
{
case 0x07: {
int ev, spec;
ev = calc_ev(a0);
spec = calc_spec(a1);
#if DEBUG_HLE_BIOS
printf("HLEBIOS: DeliverEvent(ev %d, spec %d)\n", ev, spec);
#endif
if (Event[ev][spec].status != LE32(EvStACTIVE))
{
#if DEBUG_HLE_BIOS
printf("event not active\n");
#endif
return;
}
if (Event[ev][spec].mode == LE32(EvMdINTR))
{
#if DEBUG_HLE_BIOS
printf("INTR type, need to call handler %x\n", LE32(Event[ev][spec].fhandler));
#endif
}
else
{
Event[ev][spec].status = LE32(EvStALREADY);
}
}
break;
case 0x08: {
int ev, spec;
ev = calc_ev(a0);
spec = calc_spec(a1);
#if DEBUG_HLE_BIOS
printf("HLEBIOS: OpenEvent(%08x, %08x, %08x, %08x) = ev %d spec %d\n", a0, a1, a2, a3, ev, spec);
if (ev >= 64 && ev <= 67)
{
printf("HLEBIOS: event %d maps to root counter %d\n", ev, ev-64);
}
#endif
Event[ev][spec].status = LE32(EvStWAIT);
Event[ev][spec].mode = LE32(a2);
Event[ev][spec].fhandler = LE32(a3);
mipsinfo.i = ev | (spec<<8);
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
break;
case 0x0a: {
int ev, spec;
ev = a0 & 0xff;
spec = (a0 >> 8) & 0xff;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
#if DEBUG_HLE_BIOS
printf("HLEBIOS: WaitEvent(ev %d spec %d) PC=%x\n", ev, spec, mipsinfo.i);
#endif
Event[ev][spec].status = LE32(EvStACTIVE);
mipsinfo.i = 1;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
WAI = 1;
mips_shorten_frame();
}
break;
case 0x0b: {
int ev, spec;
ev = a0 & 0xff;
spec = (a0 >> 8) & 0xff;
#if DEBUG_HLE_BIOS
printf("HLEBIOS: TestEvent(ev %d spec %d)\n", ev, spec);
#endif
if (Event[ev][spec].status == LE32(EvStALREADY))
{
Event[ev][spec].status = LE32(EvStACTIVE);
mipsinfo.i = 1;
}
else
{
mipsinfo.i = 0;
}
WAI = 1;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R3, &mipsinfo);
}
break;
case 0x0c: {
int ev, spec;
ev = a0 & 0xff;
spec = (a0 >> 8) & 0xff;
#if DEBUG_HLE_BIOS
printf("HLEBIOS: EnableEvent(ev %d spec %d)\n", ev, spec);
#endif
Event[ev][spec].status = LE32(EvStACTIVE);
mipsinfo.i = 1;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
break;
case 0x0d: {
int ev, spec;
ev = a0 & 0xff;
spec = (a0 >> 8) & 0xff;
#if DEBUG_HLE_BIOS
printf("HLEBIOS: DisableEvent(ev %d spec %d)\n", ev, spec);
#endif
Event[ev][spec].status = LE32(EvStWAIT);
mipsinfo.i = 1;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
break;
case 0x17: for (i = 0; i < 32; i++)
{
mipsinfo.i = irq_regs[i];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R0 + i, &mipsinfo);
}
mipsinfo.i = irq_regs[32];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_HI, &mipsinfo);
mipsinfo.i = irq_regs[33];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_LO, &mipsinfo);
mipsinfo.i = mips_get_ePC();
mips_set_info(CPUINFO_INT_PC, &mipsinfo);
status = mips_get_status();
status = (status & 0xfffffff0) | ((status & 0x3c)>>2);
mips_set_status(status);
return; break;
case 0x19: #if DEBUG_HLE_BIOS
printf("HLEBIOS: HookEntryInt(%08x)\n", a0);
#endif
entry_int = a0;
break;
case 0x3f: break;
case 0x5b: #if DEBUG_HLE_BIOS
printf("HLEBIOS: ChangeClearPAD\n");
#endif
break;
default:
#if DEBUG_HLE_BIOS
printf("Unknown BIOS B0 call = %x\n", subcall);
#endif
break;
}
break;
case 0xc0: switch (subcall)
{
case 0xa: #if DEBUG_HLE_BIOS
printf("HLEBIOS: ChangeClearRCnt(%08x, %08x)\n", a0, a1);
#endif
mipsinfo.i = LE32(psx_ram[((a0<<2) + 0x8600)/4]);
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
psx_ram[((a0<<2) + 0x8600)/4] = LE32(a1);
break;
default:
#if DEBUG_HLE_BIOS
printf("Unknown BIOS C0 call = %x\n", subcall);
#endif
break;
}
break;
}
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
mips_set_info(CPUINFO_INT_PC, &mipsinfo);
}
void psx_hw_runcounters(void)
{
int i, j;
union cpuinfo mipsinfo;
if (!intr_susp)
{
if (dma4_delay)
{
dma4_delay--;
if (dma4_delay == 0)
{
SPU2interruptDMA4();
if (dma4_cb)
{
call_irq_routine(dma4_cb, dma4_flag);
}
}
}
if (dma7_delay)
{
dma7_delay--;
if (dma7_delay == 0)
{
SPU2interruptDMA7();
if (dma7_cb)
{
call_irq_routine(dma7_cb, dma7_flag);
}
}
}
for (i = 0; i < iNumThreads; i++)
{
if (threads[i].iState == TS_WAITDELAY)
{
if (threads[i].waitparm > CLOCK_DIV)
{
threads[i].waitparm -= CLOCK_DIV;
}
else {
threads[i].waitparm = 0;
threads[i].iState = TS_READY;
timerexp = 1;
ps2_reschedule();
}
}
}
sys_time += 836;
if (iNumTimers > 0)
{
for (i = 0; i < iNumTimers; i++)
{
if (iop_timers[i].iActive > 0)
{
iop_timers[i].count += 836;
if (iop_timers[i].count >= iop_timers[i].target)
{
iop_timers[i].count -= iop_timers[i].target;
call_irq_routine(iop_timers[i].handler, iop_timers[i].hparam);
timerexp = 1;
}
}
}
}
}
for (i = 0; i < 3; i++)
{
if ((!(root_cnts[i].mode & RC_EN)) && (root_cnts[i].mode != 0))
{
if (root_cnts[i].mode & RC_DIV8)
{
root_cnts[i].count += 768/8;
}
else
{
root_cnts[i].count += 768;
}
if (root_cnts[i].count >= root_cnts[i].target)
{
if (!(root_cnts[i].mode & RC_RESET))
{
root_cnts[i].mode |= RC_EN;
}
else
{
root_cnts[i].count %= root_cnts[i].target;
}
psx_irq_set(1<<(4+i));
}
}
}
}
void SPUirq(void)
{
}
uint8 program_read_byte_32le(offs_t address)
{
switch (address & 0x3)
{
case 0:
return psx_hw_read(address, 0xffffff00);
case 1:
return psx_hw_read(address, 0xffff00ff)>>8;
case 2:
return psx_hw_read(address, 0xff00ffff)>>16;
default: return psx_hw_read(address, 0x00ffffff)>>24;
}
}
uint16 program_read_word_32le(offs_t address)
{
if (address & 2)
return psx_hw_read(address, 0x0000ffff)>>16;
return psx_hw_read(address, 0xffff0000);
}
uint32 program_read_dword_32le(offs_t address)
{
return psx_hw_read(address, 0);
}
void program_write_byte_32le(offs_t address, uint8 data)
{
switch (address & 0x3)
{
case 0:
psx_hw_write(address, data, 0xffffff00);
break;
case 1:
psx_hw_write(address, data<<8, 0xffff00ff);
break;
case 2:
psx_hw_write(address, data<<16, 0xff00ffff);
break;
case 3:
psx_hw_write(address, data<<24, 0x00ffffff);
break;
}
}
void program_write_word_32le(offs_t address, uint16 data)
{
if (address & 2)
{
psx_hw_write(address, data<<16, 0x0000ffff);
return;
}
psx_hw_write(address, data, 0xffff0000);
}
void program_write_dword_32le(offs_t address, uint32 data)
{
psx_hw_write(address, data, 0);
}
static void iop_sprintf(char *out, char *fmt, uint32 pstart)
{
char temp[64], tfmt[64];
char *cf, *pstr;
union cpuinfo mipsinfo;
int curparm, fp, isnum;
curparm = pstart;
cf = fmt;
while (*cf != '\0')
{
if (*cf != '%')
{
if (*cf == 27)
{
*out++ = '[';
*out++ = 'E';
*out++ = 'S';
*out++ = 'C';
*out = ']';
}
else
{
*out = *cf;
}
out++;
cf++;
}
else {
cf++;
tfmt[0] = '%';
fp = 1;
while (((*cf >= '0') && (*cf <= '9')) || (*cf == '.'))
{
tfmt[fp] = *cf;
fp++;
cf++;
}
tfmt[fp] = *cf;
tfmt[fp+1] = '\0';
isnum = 0;
switch (*cf)
{
case 'x':
case 'X':
case 'd':
case 'D':
case 'c':
case 'C':
case 'u':
case 'U':
isnum = 1;
break;
}
if (isnum)
{
mips_get_info(curparm, &mipsinfo);
curparm++;
sprintf(temp, tfmt, (int32)mipsinfo.i);
}
else
{
mips_get_info(curparm, &mipsinfo);
curparm++;
pstr = (char *)psx_ram;
pstr += (mipsinfo.i & 0x1fffff);
sprintf(temp, tfmt, pstr);
}
pstr = &temp[0];
while (*pstr != '\0')
{
*out = *pstr;
out++;
pstr++;
}
cf++;
}
}
*out = '\0';
}
void psx_iop_call(uint32 pc, uint32 callnum)
{
uint32 scan;
char *mname, *str1, *str2, *str3, name[9], out[512];
uint32 a0, a1, a2, a3;
union cpuinfo mipsinfo;
int i;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R4, &mipsinfo);
a0 = mipsinfo.i;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R5, &mipsinfo);
a1 = mipsinfo.i;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R6, &mipsinfo);
a2 = mipsinfo.i;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R7, &mipsinfo);
a3 = mipsinfo.i;
scan = (pc&0x0fffffff)/4;
while ((psx_ram[scan] != LE32(0x41e00000)) && (scan >= (0x10000/4)))
{
scan--;
}
if (psx_ram[scan] != LE32(0x41e00000))
{
printf("FATAL ERROR: couldn't find IOP link signature\n");
return;
}
scan += 3; memcpy(name, &psx_ram[scan], 8);
name[8] = '\0';
if (!strcmp(name, "stdio"))
{
switch (callnum)
{
case 4: mname = (char *)psx_ram;
mname += a0 & 0x1fffff;
mname += (a0 & 3);
iop_sprintf(out, mname, CPUINFO_INT_REGISTER + MIPS_R5);
#if DEBUG_HLE_IOP
printf("%s", out);
#endif
break;
default:
printf("IOP: Unhandled service %d for module %s\n", callnum, name);
break;
}
}
else if (!strcmp(name, "sifman"))
{
switch (callnum)
{
case 5: #if DEBUG_HLE_IOP
printf("IOP: sceSifInit()\n");
#endif
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 7: #if DEBUG_HLE_IOP
printf("IOP: sceSifSetDma(%08x %08x)\n", a0, a1);
#endif
mipsinfo.i = 1; mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 8: #if DEBUG_HLE_IOP
printf("IOP: sceSifDmaStat(%08x)\n", a0);
#endif
mipsinfo.i = -1; mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 29: #if DEBUG_HLE_IOP
printf("IOP: sceSifCheckInit()\n");
#endif
mipsinfo.i = 1;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
default:
printf("IOP: Unhandled service %d for module %s\n", callnum, name);
break;
}
}
else if (!strcmp(name, "thbase"))
{
uint32 newAlloc;
switch (callnum)
{
case 4: #if DEBUG_THREADING
printf("IOP: CreateThread(%08x)\n", a0);
#endif
a0 &= 0x1fffff;
a0 /= 4;
#if DEBUG_THREADING
printf(" : flags %x routine %08x pri %x stacksize %d refCon %08x\n",
psx_ram[a0], psx_ram[a0+1], psx_ram[a0+2], psx_ram[a0+3], psx_ram[a0+4]);
#endif
newAlloc = psf2_get_loadaddr();
if (newAlloc & 0xf)
{
newAlloc &= ~0xf;
newAlloc += 16;
}
psf2_set_loadaddr(newAlloc + LE32(psx_ram[a0+3]));
threads[iNumThreads].iState = TS_CREATED;
threads[iNumThreads].stackloc = newAlloc;
threads[iNumThreads].flags = LE32(psx_ram[a0]);
threads[iNumThreads].routine = LE32(psx_ram[a0+2]);
threads[iNumThreads].stacksize = LE32(psx_ram[a0+3]);
threads[iNumThreads].refCon = LE32(psx_ram[a0+4]);
mipsinfo.i = iNumThreads;
iNumThreads++;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 6: #if DEBUG_THREADING
printf("IOP: StartThread(%d %d)\n", a0, a1);
#endif
FreezeThread(iCurThread, 1);
ThawThread(a0);
iCurThread = a0;
break;
case 20: #if DEBUG_THREADING
printf("IOP: GetThreadId()\n");
#endif
mipsinfo.i = iCurThread;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 24: #if DEBUG_THREADING
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
printf("IOP: SleepThread() [curThread %d, PC=%x]\n", iCurThread, mipsinfo.i);
#endif
FreezeThread(iCurThread, 1);
threads[iCurThread].iState = TS_SLEEPING;
iCurThread = -1;
ps2_reschedule();
break;
case 25: #if DEBUG_THREADING
printf("IOP: WakeupThread(%d)\n", a0);
#endif
threads[a0].iState = TS_READY;
break;
case 26: #if DEBUG_THREADING
printf("IOP: iWakeupThread(%d)\n", a0);
#endif
if (threads[a0].iState != TS_RUNNING)
{
threads[a0].iState = TS_READY;
}
break;
case 33: {
double dTicks;
int i;
#if DEBUG_THREADING
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
printf("IOP: DelayThread(%d) (PC=%x) [curthread = %d]\n", a0, mipsinfo.i, iCurThread);
#endif
if (a0 < 100)
{
a0 = 100;
}
dTicks = (double)a0;
FreezeThread(iCurThread, 1);
threads[iCurThread].iState = TS_WAITDELAY;
dTicks /= (double)1000000.0;
dTicks *= (double)36864000.0; threads[iCurThread].waitparm = (uint32)dTicks;
iCurThread = -1;
ps2_reschedule();
}
break;
case 34: #if DEBUG_HLE_IOP
printf("IOP: GetSystemTime(%x)\n", a0);
#endif
a0 &= 0x1fffff;
a0 /= 4;
psx_ram[a0] = LE32(sys_time & 0xffffffff); psx_ram[a0+1] = LE32(sys_time >> 32);
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 39: {
uint64 dTicks = (uint64)a0;
uint32 hi, lo;
#if DEBUG_HLE_IOP
printf("IOP: USec2SysClock(%d %08x)\n", a0, a1);
#endif
dTicks *= (uint64)36864000;
dTicks /= (uint64)1000000;
hi = dTicks>>32;
lo = dTicks & 0xffffffff;
psx_ram[((a1 & 0x1fffff)/4)] = LE32(lo);
psx_ram[((a1 & 0x1fffff)/4)+1] = LE32(hi);
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
break;
case 40: {
uint64 temp;
uint32 seconds, usec;
#if DEBUG_HLE_IOP
printf("IOP: SysClock2USec(%08x %08x %08x)\n", a0, a1, a2);
#endif
a0 &= 0x1fffff;
a1 &= 0x1fffff;
a2 &= 0x1fffff;
a0 /= 4;
a1 /= 4;
a2 /= 4;
temp = LE32(psx_ram[a0]);
temp |= (uint64)LE32(psx_ram[a0+1])<<32;
temp *= (uint64)1000000;
temp /= (uint64)36864000;
seconds = (temp / 1000000) & 0xffffffff;
usec = (temp % 1000000) & 0xffffffff;
psx_ram[a1] = LE32(seconds);
psx_ram[a2] = LE32(usec);
}
break;
default:
printf("IOP: Unhandled service %d for module %s\n", callnum, name);
break;
}
}
else if (!strcmp(name, "thevent"))
{
switch (callnum)
{
case 4: mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
#if DEBUG_HLE_IOP
printf("IOP: CreateEventFlag(%08x) (PC=%x)\n", a0, mipsinfo.i);
#endif
a0 &= 0x1fffff;
a0 /= 4;
evflags[iNumFlags].type = LE32(psx_ram[a0]);
evflags[iNumFlags].value = LE32(psx_ram[a0+1]);
evflags[iNumFlags].param = LE32(psx_ram[a0+2]);
evflags[iNumFlags].inUse = 1;
#if DEBUG_HLE_IOP
printf(" Flag %02d: type %d init %08x param %08x\n", iNumFlags, evflags[iNumFlags].type, evflags[iNumFlags].value, evflags[iNumFlags].param);
#endif
mipsinfo.i = iNumFlags+1;
iNumFlags++;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 6: a0--;
#if DEBUG_HLE_IOP
printf("IOP: SetEventFlag(%d %08x)\n", a0, a1);
#endif
evflags[a0].value |= a1;
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 7: a0--;
#if DEBUG_HLE_IOP
printf("IOP: iSetEventFlag(%08x %08x)\n", a0, a1);
#endif
evflags[a0].value |= a1;
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
for (i=0; i < iNumThreads; i++)
{
if ((threads[i].iState == TS_WAITEVFLAG) && (threads[i].waitparm == a0))
{
threads[i].iState = TS_READY;
}
}
break;
case 8: a0--;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
#if DEBUG_HLE_IOP
printf("IOP: ClearEventFlag(%d %08x) (PC=%x)\n", a0, a1, mipsinfo.i);
#endif
evflags[a0].value &= a1;
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 9: a0--;
#if DEBUG_HLE_IOP
printf("IOP: iClearEventFlag(%d %08x)\n", a0, a1);
#endif
evflags[a0].value &= a1;
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 10: a0--;
#if DEBUG_HLE_IOP
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
printf("IOP: WaitEventFlag(%d %08x %d %08x PC=%x)\n", a0, a1, a2, a3, mipsinfo.i);
#endif
if (!(evflags[a0].value & a1))
{
FreezeThread(iCurThread, 1);
threads[iCurThread].iState = TS_WAITEVFLAG;
threads[iCurThread].waitparm = a0;
iCurThread = -1;
ps2_reschedule();
}
else
{
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
break;
default:
printf("IOP: Unhandled service %d for module %s\n", callnum, name);
break;
}
}
else if (!strcmp(name, "thsemap"))
{
int foundthread;
switch (callnum)
{
case 4: #if DEBUG_HLE_IOP
printf("IOP: CreateSema(%08x)\n", a0);
#endif
mipsinfo.i = -1;
for (i = 0; i < SEMA_MAX; i++)
{
if (!semaphores[i].inuse)
{
mipsinfo.i = i;
break;
}
}
if (mipsinfo.i == -1)
{
printf("IOP: out of semaphores!\n");
}
a0 &= 0x7fffffff;
a0 /= 4;
if (mipsinfo.i != -1)
{
semaphores[mipsinfo.i].attr = LE32(psx_ram[a0]);
semaphores[mipsinfo.i].option = LE32(psx_ram[a0+1]);
semaphores[mipsinfo.i].init = LE32(psx_ram[a0+2]);
semaphores[mipsinfo.i].max = LE32(psx_ram[a0+3]);
semaphores[mipsinfo.i].current = semaphores[mipsinfo.i].init;
semaphores[mipsinfo.i].inuse = 1;
}
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 6: #if DEBUG_HLE_IOP
printf("IOP: SignalSema(%d) (current %d)\n", a0, semaphores[a0].current);
#endif
foundthread = 0;
for (i=0; i < iNumThreads; i++)
{
if ((threads[i].iState == TS_WAITSEMA) && (threads[i].waitparm == a0))
{
threads[i].iState = TS_READY;
semaphores[a0].threadsWaiting--;
foundthread = 1;
break;
}
}
mipsinfo.i = 0;
if (!foundthread)
{
if (semaphores[a0].current < semaphores[a0].max)
{
semaphores[a0].current++;
}
else
{
mipsinfo.i = -420; }
}
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 7: #if DEBUG_HLE_IOP
printf("IOP: iSignalSema(%d)\n", a0);
#endif
foundthread = 0;
for (i=0; i < iNumThreads; i++)
{
if ((threads[i].iState == TS_WAITSEMA) && (threads[i].waitparm == a0))
{
threads[i].iState = TS_READY;
semaphores[a0].threadsWaiting--;
foundthread = 1;
break;
}
}
mipsinfo.i = 0;
if (!foundthread)
{
if (semaphores[a0].current < semaphores[a0].max)
{
semaphores[a0].current++;
}
else
{
mipsinfo.i = -420; }
}
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 8: #if DEBUG_HLE_IOP
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
printf("IOP: WaitSema(%d) (cnt %d) (th %d) (PC=%x)\n", a0, iCurThread, semaphores[a0].current, mipsinfo.i);
#endif
if (semaphores[a0].current > 0)
{
semaphores[a0].current--;
}
else
{
FreezeThread(iCurThread, 1);
threads[iCurThread].iState = TS_WAITSEMA;
threads[iCurThread].waitparm = a0;
ps2_reschedule();
}
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
default:
printf("IOP: Unhandled service %d for module %s\n", callnum, name);
break;
}
}
else if (!strcmp(name, "timrman"))
{
switch (callnum)
{
case 4: #if DEBUG_HLE_IOP
printf("IOP: AllocHardTimer(%d %d %d)\n", a0, a1, a2);
#endif
if (a1 != 32)
{
printf("IOP: AllocHardTimer doesn't support 16-bit timers!\n");
}
iop_timers[iNumTimers].source = a0;
iop_timers[iNumTimers].prescale = a2;
mipsinfo.i = iNumTimers+1;
iNumTimers++;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 6: #if DEBUG_HLE_IOP
printf("IOP: FreeHardTimer(%d)\n", a0);
#endif
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 10: mipsinfo.i = iop_timers[a0-1].count;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 20: #if DEBUG_HLE_IOP
printf("IOP: SetTimerHandler(%d %d %08x %08x)\n", a0, a1, a2, a3);
#endif
iop_timers[a0-1].target = a1;
iop_timers[a0-1].handler = a2;
iop_timers[a0-1].hparam = a3;
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 22: #if DEBUG_HLE_IOP
printf("IOP: SetupHardTimer(%d %d %d %d)\n", a0, a1, a2, a3);
#endif
iop_timers[a0-1].source = a1;
iop_timers[a0-1].mode = a2;
iop_timers[a0-1].prescale = a3;
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 23: #if DEBUG_HLE_IOP
printf("IOP: StartHardTimer(%d)\n", a0);
#endif
iop_timers[a0-1].iActive = 1;
iop_timers[a0-1].count = 0;
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 24: #if DEBUG_HLE_IOP
printf("IOP: StopHardTimer(%d)\n", a0);
#endif
iop_timers[a0-1].iActive = 0;
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
default:
printf("IOP: Unhandled service %d for module %s\n", callnum, name);
break;
}
}
else if (!strcmp(name, "sysclib"))
{
switch (callnum)
{
case 12: {
uint8 *dst, *src;
#if DEBUG_HLE_IOP
printf("IOP: memcpy(%08x, %08x, %d)\n", a0, a1, a2);
#endif
dst = (uint8 *)&psx_ram[(a0&0x1fffff)/4];
src = (uint8 *)&psx_ram[(a1&0x1fffff)/4];
dst += a0 % 4;
src += a1 % 4;
while (a2)
{
*dst = *src;
dst++;
src++;
a2--;
}
mipsinfo.i = a0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
break;
case 13: {
uint8 *dst, *src;
#if DEBUG_HLE_IOP
printf("IOP: memmove(%08x, %08x, %d)\n", a0, a1, a2);
#endif
dst = (uint8 *)&psx_ram[(a0&0x1fffff)/4];
src = (uint8 *)&psx_ram[(a1&0x1fffff)/4];
dst += a0 % 4;
src += a1 % 4;
dst += a2 - 1;
src += a2 - 1;
while (a2)
{
*dst = *src;
dst--;
src--;
a2--;
}
mipsinfo.i = a0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
break;
case 14: {
uint8 *dst;
#if DEBUG_HLE_IOP
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
printf("IOP: memset(%08x, %02x, %d) [PC=%x]\n", a0, a1, a2, mipsinfo.i);
#endif
dst = (uint8 *)&psx_ram[(a0&0x1fffff)/4];
dst += (a0 & 3);
memset(dst, a1, a2);
}
break;
case 17: {
uint8 *dst;
#if DEBUG_HLE_IOP
printf("IOP: bzero(%08x, %08x)\n", a0, a1);
#endif
dst = (uint8 *)&psx_ram[(a0&0x1fffff)/4];
dst += (a0 & 3);
memset(dst, 0, a1);
}
break;
case 19: mname = (char *)psx_ram;
str1 = (char *)psx_ram;
mname += a0 & 0x1fffff;
str1 += a1 & 0x1fffff;
#if DEBUG_HLE_IOP
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
printf("IOP: sprintf(%08x, %s, ...) [PC=%08x]\n", a0, str1, (uint32)mipsinfo.i);
printf("%x %x %x %x\n", a0, a1, a2, a3);
#endif
iop_sprintf(mname, str1, CPUINFO_INT_REGISTER + MIPS_R6);
#if DEBUG_HLE_IOP
printf(" = [%s]\n", mname);
#endif
break;
case 23: {
uint8 *dst, *src;
#if DEBUG_HLE_IOP
printf("IOP: strcpy(%08x, %08x)\n", a0, a1);
#endif
dst = (uint8 *)&psx_ram[(a0&0x1fffff)/4];
src = (uint8 *)&psx_ram[(a1&0x1fffff)/4];
dst += a0 % 4;
src += a1 % 4;
while (*src != '\0')
{
*dst = *src;
dst++;
src++;
}
*dst = '\0';
mipsinfo.i = a0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
break;
case 27: {
char *dst;
#if DEBUG_HLE_IOP
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
printf("IOP: strlen(%08x) [PC=%x]\n", a0, mipsinfo.i);
#endif
dst = (char *)&psx_ram[(a0&0x1fffff)/4];
dst += (a0 & 3);
mipsinfo.i = strlen(dst);
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
break;
case 30: {
char *dst, *src;
#if DEBUG_HLE_IOP
printf("IOP: strncpy(%08x, %08x, %d)\n", a0, a1, a2);
#endif
dst = (char *)&psx_ram[(a0&0x1fffff)/4];
src = (char *)&psx_ram[(a1&0x1fffff)/4];
dst += a0 % 4;
src += a1 % 4;
while ((*src != '\0') && (a2 > 0))
{
*dst = *src;
dst++;
src++;
a2--;
}
*dst = '\0';
mipsinfo.i = a0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
}
break;
case 36: mname = (char *)&psx_ram[(a0 & 0x1fffff)/4];
mname += (a0 & 3);
if (a1)
{
printf("IOP: Unhandled strtol with non-NULL second parm\n");
}
mipsinfo.i = strtol(mname, NULL, a2);
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
default:
printf("IOP: Unhandled service %d for module %s\n", callnum, name);
break;
}
}
else if (!strcmp(name, "intrman"))
{
switch (callnum)
{
case 4: #if DEBUG_HLE_IOP
printf("IOP: RegisterIntrHandler(%d %08x %08x %08x)\n", a0, a1, a2, a3);
#endif
if (a0 == 9)
{
irq9_fval = a1;
irq9_cb = a2;
irq9_flag = a3;
}
if (a0 == 36)
{
dma4_fval = a1;
dma4_cb = a2;
dma4_flag = a3;
}
if (a0 == 40)
{
dma7_fval = a1;
dma7_cb = a2;
dma7_flag = a3;
}
break;
case 5: #if DEBUG_HLE_IOP
printf("IOP: ReleaseIntrHandler(%d)\n", a0);
#endif
break;
case 6: #if DEBUG_HLE_IOP
printf("IOP: EnableIntr(%d)\n", a0);
#endif
break;
case 7: #if DEBUG_HLE_IOP
printf("IOP: DisableIntr(%d)\n", a0);
#endif
break;
case 8: #if DEBUG_HLE_IOP
printf("IOP: CpuDisableIntr(%d)\n", a0);
#endif
break;
case 9: #if DEBUG_HLE_IOP
printf("IOP: CpuEnableIntr(%d)\n", a0);
#endif
break;
case 17: #if DEBUG_HLE_IOP
printf("IOP: CpuSuspendIntr\n");
#endif
if (intr_susp)
{
mipsinfo.i = -102;
}
else
{
mipsinfo.i = 0;
}
intr_susp = 1;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 18: #if DEBUG_HLE_IOP
printf("IOP: CpuResumeIntr\n");
#endif
intr_susp = 0;
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 23: #if DEBUG_HLE_IOP
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
printf("IOP: QueryIntrContext(PC=%x)\n", mipsinfo.i);
#endif
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
default:
printf("IOP: Unhandled service %d for module %s\n", callnum, name);
break;
}
}
else if (!strcmp(name, "loadcore"))
{
switch (callnum)
{
case 5: #if DEBUG_HLE_IOP
printf("IOP: FlushDcache()\n");
#endif
break;
case 6: a0 &= 0x1fffff;
#if DEBUG_HLE_IOP
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
printf("IOP: RegisterLibraryEntries(%08x) (PC=%x)\n", a0, mipsinfo.i);
#endif
if (psx_ram[a0/4] == LE32(0x41c00000))
{
a0 += 3*4;
memcpy(®libs[iNumLibs].name, &psx_ram[a0/4], 8);
reglibs[iNumLibs].name[8] = '\0';
#if DEBUG_HLE_IOP
printf("Lib name [%s]\n", ®libs[iNumLibs].name);
#endif
a0 += 2*4;
reglibs[iNumLibs].dispatch = a0;
iNumLibs++;
}
else
{
printf("ERROR: Entry table signature missing\n");
}
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
default:
printf("IOP: Unhandled service %d for module %s\n", callnum, name);
break;
}
}
else if (!strcmp(name, "sysmem"))
{
uint32 newAlloc;
switch (callnum)
{
case 4: newAlloc = psf2_get_loadaddr();
if (newAlloc & 15)
{
newAlloc &= ~15;
newAlloc += 16;
}
if (a1 & 15)
{
a1 &= ~15;
a1 += 16;
}
if (a1 == 1114112) {
printf("SH Hack: was %x now %x\n", newAlloc, 0x60000);
newAlloc = 0x60000;
}
psf2_set_loadaddr(newAlloc + a1);
#if DEBUG_HLE_IOP
printf("IOP: AllocMemory(%d, %d, %x) = %08x\n", a0, a1, a2, newAlloc|0x80000000);
#endif
mipsinfo.i = newAlloc; mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 5: #if DEBUG_HLE_IOP
printf("IOP: FreeMemory(%x)\n", a0);
#endif
break;
case 7: #if DEBUG_HLE_IOP
printf("IOP: QueryMaxFreeMemSize\n");
#endif
mipsinfo.i = (2*1024*1024) - psf2_get_loadaddr();
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 8: #if DEBUG_HLE_IOP
printf("IOP: QueryTotalFreeMemSize\n");
#endif
mipsinfo.i = (2*1024*1024) - psf2_get_loadaddr();
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 14: mname = (char *)psx_ram;
mname += a0 & 0x1fffff;
mname += (a0 & 3);
iop_sprintf(out, mname, CPUINFO_INT_REGISTER + MIPS_R5);
if (out[strlen(out)-1] != '\n')
{
strcat(out, "\n");
}
{
int ch;
for (ch = 0; ch < strlen(out); ch++)
{
if (out[ch] == 27)
{
out[ch] = ']';
}
}
}
#if DEBUG_HLE_IOP
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
printf("KTTY: %s [PC=%x]\n", out, mipsinfo.i);
#endif
#if 0 #endif
break;
default:
printf("IOP: Unhandled service %d for module %s\n", callnum, name);
break;
}
}
else if (!strcmp(name, "modload"))
{
uint8 *tempmem;
uint32 newAlloc;
switch (callnum)
{
case 7: mname = (char *)&psx_ram[(a0 & 0x1fffff)/4];
mname += 8;
str1 = (char *)&psx_ram[(a2 & 0x1fffff)/4];
#if DEBUG_HLE_IOP
printf("LoadStartModule: %s\n", mname);
#endif
newAlloc = psf2_get_loadaddr();
if (newAlloc & 0xf)
{
newAlloc &= ~0xf;
newAlloc += 16;
}
psf2_set_loadaddr(newAlloc + 2048);
tempmem = (uint8 *)malloc(2*1024*1024);
if (psf2_load_file(mname, tempmem, 2*1024*1024) != 0xffffffff)
{
uint32 start;
int i;
start = psf2_load_elf(tempmem, 2*1024*1024);
if (start != 0xffffffff)
{
uint32 args[20], numargs = 1, argofs;
uint8 *argwalk = (uint8 *)psx_ram, *argbase;
argwalk += (a2 & 0x1fffff);
argbase = argwalk;
args[0] = a0;
argofs = 0;
if (a1 > 0)
{
args[numargs] = a2;
numargs++;
while (a1)
{
if ((*argwalk == 0) && (a1 > 1))
{
args[numargs] = a2 + argofs + 1;
numargs++;
}
argwalk++;
argofs++;
a1--;
}
}
for (i = 0; i < numargs; i++)
{
#if DEBUG_HLE_IOP
#endif
psx_ram[(newAlloc/4)+i] = LE32(args[i]);
}
mipsinfo.i = numargs;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R4, &mipsinfo);
mipsinfo.i = 0x80000000 | newAlloc;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R5, &mipsinfo);
mipsinfo.i = start - 4;
mips_set_info(CPUINFO_INT_PC, &mipsinfo);
}
}
free(tempmem);
break;
default:
printf("IOP: Unhandled service %d for module %s\n", callnum, name);
break;
}
}
else if (!strcmp(name, "ioman"))
{
switch (callnum)
{
case 4: {
int i, slot2use;
slot2use = -1;
for (i = 0; i < MAX_FILE_SLOTS; i++)
{
if (filestat[i] == 0)
{
slot2use = i;
break;
}
}
if (slot2use == -1)
{
printf("IOP: out of file slots!\n");
mipsinfo.i = 0xffffffff;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
return;
}
mname = (char *)psx_ram;
mname += (a0 & 0x1fffff);
if (!strncmp(mname, "aofile:", 7))
{
mname += 8;
}
else if (!strncmp(mname, "hefile:", 7))
{
mname += 8;
}
else if (!strncmp(mname, "host0:", 6))
{
mname += 7;
}
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
#if DEBUG_HLE_IOP
printf("IOP: open(\"%s\") (PC=%08x)\n", mname, mipsinfo.i);
#endif
filedata[slot2use] = malloc(6*1024*1024);
filesize[slot2use] = psf2_load_file(mname, filedata[slot2use], 6*1024*1024);
filepos[slot2use] = 0;
filestat[slot2use] = 1;
if (filesize[slot2use] == 0xffffffff)
{
mipsinfo.i = filesize[slot2use];
}
else
{
mipsinfo.i = slot2use;
}
}
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 5: #if DEBUG_HLE_IOP
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
printf("IOP: close(%d) (PC=%08x)\n", a0, mipsinfo.i);
#endif
free(filedata[a0]);
filedata[a0] = (uint8 *)NULL;
filepos[a0] = 0;
filesize[a0] = 0;
filestat[a0] = 0;
break;
case 6: #if DEBUG_HLE_IOP
printf("IOP: read(%x %x %d) [pos %d size %d]\n", a0, a1, a2, filepos[a0], filesize[a0]);
#endif
if (filepos[a0] >= filesize[a0])
{
mipsinfo.i = 0;
}
else
{
uint8 *rp;
if ((filepos[a0] + a2) > filesize[a0])
{
a2 = filesize[a0] - filepos[a0];
}
rp = (uint8 *)psx_ram;
rp += (a1 & 0x1fffff);
memcpy(rp, &filedata[a0][filepos[a0]], a2);
filepos[a0] += a2;
mipsinfo.i = a2;
}
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 8: #if DEBUG_HLE_IOP
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
printf("IOP: lseek(%d, %d, %s) (PC=%08x)\n", a0, a1, seek_types[a2], mipsinfo.i);
#endif
switch (a2)
{
case 0: if (a1 <= filesize[a0])
{
filepos[a0] = a1;
}
break;
case 1: if ((a1 + filepos[a0]) < filesize[a0])
{
filepos[a0] += a1;
}
break;
case 2: filepos[a0] = filesize[a0] - a1;
break;
}
mipsinfo.i = filepos[a0];
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 20: #if DEBUG_HLE_IOP
printf("IOP: AddDrv(%x)\n", a0);
#endif
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
case 21: #if DEBUG_HLE_IOP
printf("IOP: DelDrv(%x)\n", a0);
#endif
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R2, &mipsinfo);
break;
default:
printf("IOP: Unhandled service %d for module %s\n", callnum, name);
}
}
else
{
int lib;
if (iNumLibs > 0)
{
for (lib = 0; lib < iNumLibs; lib++)
{
if (!strcmp(name, reglibs[lib].name))
{
#if DEBUG_HLE_IOP
uint32 PC;
mips_get_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
PC = mipsinfo.i;
#endif
mipsinfo.i = 0;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_DELAYV, &mipsinfo);
mips_set_info(CPUINFO_INT_REGISTER + MIPS_DELAYR, &mipsinfo);
mipsinfo.i = LE32(psx_ram[(reglibs[lib].dispatch/4) + callnum]);
#if DEBUG_HLE_IOP
printf("IOP: Calling %s (%d) service %d => %08x (parms %08x %08x %08x %08x) (PC=%x)\n",
reglibs[lib].name,
lib,
callnum,
(uint32)mipsinfo.i,
a0, a1, a2, a3, PC);
#endif
#if 0 #endif
mipsinfo.i -= 4;
mips_set_info(CPUINFO_INT_PC, &mipsinfo);
return;
}
}
}
printf("IOP: Unhandled service %d for module %s\n", callnum, name);
}
}