#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <zlib.h>
#include "ao.h"
#include "eng_protos.h"
#include "cpuintrf.h"
#include "psx.h"
#include "peops2/stdafx.h"
#include "peops2/externals.h"
#include "peops2/regs.h"
#include "peops2/registers.h"
#include "peops2/spu.h"
#include "corlett.h"
#define DEBUG_LOADER (0)
#define MAX_FS (32)
#define ELF32_R_SYM(val) ((val) >> 8)
#define ELF32_R_TYPE(val) ((val) & 0xff)
static corlett_t *c = NULL;
static char psfby[256];
static char *spu_pOutput;
extern uint32 psx_ram[(2*1024*1024)/4];
extern uint32 initial_ram[(2*1024*1024)/4];
static uint32 initialPC, initialSP;
static uint32 loadAddr, lengthMS, fadeMS;
static uint8 *filesys[MAX_FS];
static uint8 *lib_raw_file;
static uint32 fssize[MAX_FS];
static int num_fs;
extern void mips_init( void );
extern void mips_reset( void *param );
extern int mips_execute( int cycles );
extern void mips_set_info(UINT32 state, union cpuinfo *info);
extern void psx_hw_init(void);
extern void ps2_hw_slice(void);
extern void ps2_hw_frame(void);
extern void setlength2(int32 stop, int32 fade);
static uint32 secname(uint8 *start, uint32 strndx, uint32 shoff, uint32 shentsize, uint32 name)
{
uint32 offset, shent;
shent = shoff + (shentsize * strndx);
offset = start[shent+16] | start[shent+17]<<8 | start[shent+18]<<16 | start[shent+19]<<24;
offset += name;
return offset;
}
static void do_iopmod(uint8 *start, uint32 offset)
{
uint32 nameoffs, saddr, heap, tsize, dsize, bsize, vers2;
nameoffs = start[offset] | start[offset+1]<<8 | start[offset+2]<<16 | start[offset+3]<<24;
saddr = start[offset+4] | start[offset+5]<<8 | start[offset+6]<<16 | start[offset+7]<<24;
heap = start[offset+8] | start[offset+9]<<8 | start[offset+10]<<16 | start[offset+11]<<24;
tsize = start[offset+12] | start[offset+13]<<8 | start[offset+14]<<16 | start[offset+15]<<24;
dsize = start[offset+16] | start[offset+17]<<8 | start[offset+18]<<16 | start[offset+19]<<24;
bsize = start[offset+20] | start[offset+21]<<8 | start[offset+22]<<16 | start[offset+23]<<24;
vers2 = start[offset+24] | start[offset+25]<<8;
#if DEBUG_LOADER
printf("vers: %04x name [%s]\n", vers2, &start[offset+26]);
#endif
}
uint32 psf2_load_elf(uint8 *start, uint32 len)
{
uint32 entry, phoff, shoff, phentsize, shentsize, phnum, shnum, shstrndx;
uint32 name, type, flags, addr, offset, size, shent;
uint32 totallen;
int i, rec;
if (loadAddr & 3)
{
loadAddr &= ~3;
loadAddr += 4;
}
#if DEBUG_LOADER
printf("psf2_load_elf: starting at %08x\n", loadAddr | 0x80000000);
#endif
if ((start[0] != 0x7f) || (start[1] != 'E') || (start[2] != 'L') || (start[3] != 'F'))
{
printf("Not an ELF file\n");
return 0xffffffff;
}
entry = start[24] | start[25]<<8 | start[26]<<16 | start[27]<<24; phoff = start[28] | start[29]<<8 | start[30]<<16 | start[31]<<24; shoff = start[32] | start[33]<<8 | start[34]<<16 | start[35]<<24;
phentsize = start[42] | start[43]<<8; phnum = start[44] | start[45]<<8; shentsize = start[46] | start[47]<<8; shnum = start[48] | start[49]<<8; shstrndx = start[50] | start[51]<<8;
shent = shoff;
totallen = 0;
for (i = 0; i < shnum; i++)
{
name = start[shent] | start[shent+1]<<8 | start[shent+2]<<16 | start[shent+3]<<24;
type = start[shent+4] | start[shent+5]<<8 | start[shent+6]<<16 | start[shent+7]<<24;
flags = start[shent+8] | start[shent+9]<<8 | start[shent+10]<<16 | start[shent+11]<<24;
addr = start[shent+12] | start[shent+13]<<8 | start[shent+14]<<16 | start[shent+15]<<24;
offset = start[shent+16] | start[shent+17]<<8 | start[shent+18]<<16 | start[shent+19]<<24;
size = start[shent+20] | start[shent+21]<<8 | start[shent+22]<<16 | start[shent+23]<<24;
switch (type)
{
case 0: break;
case 1: memcpy(&psx_ram[(loadAddr + addr)/4], &start[offset], size);
totallen += size;
break;
case 2: break;
case 3: break;
case 8: memset(&psx_ram[(loadAddr + addr)/4], 0, size);
totallen += size;
break;
case 9: for (rec = 0; rec < (size/8); rec++)
{
uint32 offs, info, target, temp, val, vallo;
static uint32 hi16offs = 0, hi16target = 0;
offs = start[offset+(rec*8)] | start[offset+1+(rec*8)]<<8 | start[offset+2+(rec*8)]<<16 | start[offset+3+(rec*8)]<<24;
info = start[offset+4+(rec*8)] | start[offset+5+(rec*8)]<<8 | start[offset+6+(rec*8)]<<16 | start[offset+7+(rec*8)]<<24;
target = LE32(psx_ram[(loadAddr+offs)/4]);
switch (ELF32_R_TYPE(info))
{
case 2: target += loadAddr;
break;
case 4: temp = (target & 0x03ffffff);
target &= 0xfc000000;
temp += (loadAddr>>2);
target |= temp;
break;
case 5: hi16offs = offs;
hi16target = target;
break;
case 6: vallo = ((target & 0xffff) ^ 0x8000) - 0x8000;
val = ((hi16target & 0xffff) << 16) + vallo;
val += loadAddr;
val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff;
hi16target = (hi16target & ~0xffff) | val;
val = loadAddr + vallo;
target = (target & ~0xffff) | (val & 0xffff);
psx_ram[(loadAddr+hi16offs)/4] = LE32(hi16target);
break;
default:
printf("FATAL: Unknown MIPS ELF relocation!\n");
return 0xffffffff;
break;
}
psx_ram[(loadAddr+offs)/4] = LE32(target);
}
break;
case 0x70000080: do_iopmod(start, offset);
break;
default:
#if DEBUG_LOADER
printf("Unhandled ELF section type %d\n", type);
#endif
break;
}
shent += shentsize;
}
entry += loadAddr;
entry |= 0x80000000;
loadAddr += totallen;
#if DEBUG_LOADER
printf("psf2_load_elf: entry PC %08x\n", entry);
#endif
return entry;
}
static uint32 load_file_ex(uint8 *top, uint8 *start, uint32 len, char *file, uint8 *buf, uint32 buflen)
{
int32 numfiles, i, j;
uint8 *cptr;
uint32 offs, uncomp, bsize, cofs, uofs;
uint32 X;
uLongf dlength;
int uerr;
char matchname[512], *remainder;
i = 0;
while ((file[i] != '/') && (file[i] != '\\') && (file[i] != '\0'))
{
matchname[i] = file[i];
i++;
}
matchname[i] = '\0';
remainder = &file[i+1];
cptr = start + 4;
numfiles = start[0] | start[1]<<8 | start[2]<<16 | start[3]<<24;
for (i = 0; i < numfiles; i++)
{
offs = cptr[36] | cptr[37]<<8 | cptr[38]<<16 | cptr[39]<<24;
uncomp = cptr[40] | cptr[41]<<8 | cptr[42]<<16 | cptr[43]<<24;
bsize = cptr[44] | cptr[45]<<8 | cptr[46]<<16 | cptr[47]<<24;
#if DEBUG_LOADER
printf("[%s vs %s]: ofs %08x uncomp %08x bsize %08x\n", cptr, matchname, offs, uncomp, bsize);
#endif
if (!strcasecmp((char *)cptr, matchname))
{
if ((uncomp == 0) && (bsize == 0))
{
#if DEBUG_LOADER
printf("Drilling into subdirectory [%s] with [%s] at offset %x\n", matchname, remainder, offs);
#endif
return load_file_ex(top, &top[offs], len-offs, remainder, buf, buflen);
}
X = (uncomp + bsize - 1) / bsize;
cofs = offs + (X*4);
uofs = 0;
for (j = 0; j < X; j++)
{
uint32 usize;
usize = top[offs+(j*4)] | top[offs+1+(j*4)]<<8 | top[offs+2+(j*4)]<<16 | top[offs+3+(j*4)]<<24;
dlength = buflen - uofs;
uerr = uncompress(&buf[uofs], &dlength, &top[cofs], usize);
if (uerr != Z_OK)
{
printf("Decompress fail: %x %d!\n", dlength, uerr);
return 0xffffffff;
}
cofs += usize;
uofs += dlength;
}
return uncomp;
}
else
{
cptr += 48;
}
}
return 0xffffffff;
}
static uint32 load_file(int fs, char *file, uint8 *buf, uint32 buflen)
{
return load_file_ex(filesys[fs], filesys[fs], fssize[fs], file, buf, buflen);
}
#if 0#endif
uint32 psf2_load_file(char *file, uint8 *buf, uint32 buflen)
{
int i;
uint32 flen;
for (i = 0; i < num_fs; i++)
{
flen = load_file(i, file, buf, buflen);
if (flen != 0xffffffff)
{
return flen;
}
}
return 0xffffffff;
}
int32 psf2_start(uint8 *buffer, uint32 length)
{
uint8 *file, *lib_decoded;
uint32 irx_len;
uint64 file_len, lib_raw_length, lib_len;
uint8 *buf;
union cpuinfo mipsinfo;
corlett_t *lib;
loadAddr = 0x23f00;
memset(psx_ram, 0, 2*1024*1024);
if (corlett_decode(buffer, length, &file, &file_len, &c) != AO_SUCCESS)
{
return AO_FAIL;
}
if (file_len > 0) printf("ERROR: PSF2 can't have a program section! ps %08x\n", file_len);
#if DEBUG_LOADER
printf("FS section: size %x\n", c->res_size);
#endif
num_fs = 1;
filesys[0] = (uint8 *)c->res_section;
fssize[0] = c->res_size;
if (c->lib[0] != 0)
{
uint64 tmp_length;
#if DEBUG_LOADER
printf("Loading library: %s\n", c->lib);
#endif
if (ao_get_lib(c->lib, &lib_raw_file, &tmp_length) != AO_SUCCESS)
{
return AO_FAIL;
}
lib_raw_length = tmp_length;
if (corlett_decode(lib_raw_file, lib_raw_length, &lib_decoded, &lib_len, &lib) != AO_SUCCESS)
{
free(lib_raw_file);
return AO_FAIL;
}
#if DEBUG_LOADER
printf("Lib FS section: size %x bytes\n", lib->res_size);
#endif
num_fs++;
filesys[1] = (uint8 *)lib->res_section;
fssize[1] = lib->res_size;
}
#if 0 #endif
buf = (uint8 *)malloc(512*1024);
irx_len = psf2_load_file("psf2.irx", buf, 512*1024);
if (irx_len != 0xffffffff)
{
initialPC = psf2_load_elf(buf, irx_len);
initialSP = 0x801ffff0;
}
free(buf);
if (initialPC == 0xffffffff)
{
return AO_FAIL;
}
lengthMS = psfTimeToMS(c->inf_length);
fadeMS = psfTimeToMS(c->inf_fade);
if (lengthMS == 0)
{
lengthMS = ~0;
}
setlength2(lengthMS, fadeMS);
mips_init();
mips_reset(NULL);
mipsinfo.i = initialPC;
mips_set_info(CPUINFO_INT_PC, &mipsinfo);
mipsinfo.i = initialSP;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R29, &mipsinfo);
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R30, &mipsinfo);
mipsinfo.i = 0x80000000;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
mipsinfo.i = 2; mips_set_info(CPUINFO_INT_REGISTER + MIPS_R4, &mipsinfo);
mipsinfo.i = 0x80000004; mips_set_info(CPUINFO_INT_REGISTER + MIPS_R5, &mipsinfo);
psx_ram[1] = LE32(0x80000008);
buf = (uint8 *)&psx_ram[2];
strcpy((char *)buf, "aofile:/");
psx_ram[0] = LE32(FUNCT_HLECALL);
memcpy(initial_ram, psx_ram, 2*1024*1024);
psx_hw_init();
SPU2init();
SPU2open(NULL);
return AO_SUCCESS;
}
void ps2_update(unsigned char *pSound, long lBytes)
{
memcpy(spu_pOutput, pSound, lBytes); }
int32 psf2_gen(int16 *buffer, uint32 samples)
{
int i;
spu_pOutput = (char *)buffer;
for (i = 0; i < samples; i++)
{
SPU2async(1);
ps2_hw_slice();
}
ps2_hw_frame();
return AO_SUCCESS;
}
int32 psf2_stop(void)
{
SPU2close();
if (c->lib[0] != 0)
{
free(lib_raw_file);
}
free(c);
return AO_SUCCESS;
}
int32 psf2_command(int32 command, int32 parameter)
{
union cpuinfo mipsinfo;
uint32 lengthMS, fadeMS;
switch (command)
{
case COMMAND_RESTART:
SPU2close();
memcpy(psx_ram, initial_ram, 2*1024*1024);
mips_init();
mips_reset(NULL);
psx_hw_init();
SPU2init();
SPU2open(NULL);
mipsinfo.i = initialPC;
mips_set_info(CPUINFO_INT_PC, &mipsinfo);
mipsinfo.i = initialSP;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R29, &mipsinfo);
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R30, &mipsinfo);
mipsinfo.i = 0x80000000;
mips_set_info(CPUINFO_INT_REGISTER + MIPS_R31, &mipsinfo);
mipsinfo.i = 2; mips_set_info(CPUINFO_INT_REGISTER + MIPS_R4, &mipsinfo);
mipsinfo.i = 0x80000004; mips_set_info(CPUINFO_INT_REGISTER + MIPS_R5, &mipsinfo);
psx_hw_init();
lengthMS = psfTimeToMS(c->inf_length);
fadeMS = psfTimeToMS(c->inf_fade);
if (lengthMS == 0)
{
lengthMS = ~0;
}
setlength2(lengthMS, fadeMS);
return AO_SUCCESS;
}
return AO_FAIL;
}
int32 psf2_fill_info(ao_display_info *info)
{
if (c == NULL)
return AO_FAIL;
strcpy(info->title[1], "Name: ");
sprintf(info->info[1], "%s", c->inf_title);
strcpy(info->title[2], "Game: ");
sprintf(info->info[2], "%s", c->inf_game);
strcpy(info->title[3], "Artist: ");
sprintf(info->info[3], "%s", c->inf_artist);
strcpy(info->title[4], "Copyright: ");
sprintf(info->info[4], "%s", c->inf_copy);
strcpy(info->title[5], "Year: ");
sprintf(info->info[5], "%s", c->inf_year);
strcpy(info->title[6], "Length: ");
sprintf(info->info[6], "%s", c->inf_length);
strcpy(info->title[7], "Fade: ");
sprintf(info->info[7], "%s", c->inf_fade);
strcpy(info->title[8], "Ripper: ");
sprintf(info->info[8], "%s", psfby);
return AO_SUCCESS;
}
uint32 psf2_get_loadaddr(void)
{
return loadAddr;
}
void psf2_set_loadaddr(uint32 new)
{
loadAddr = new;
}