Mercurial > audlegacy
changeset 857:e1f9f03f9fbe trunk
[svn] - revert (commit 2/2)
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/Makefile.in Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,26 @@ +include ../../../mk/rules.mk +include ../../../mk/objective.mk + +OBJECTIVE_LIBS = libsexypsf.so + +LIBDIR = $(plugindir)/$(INPUT_PLUGIN_DIR) + +SOURCES = \ + PsxBios.c \ + PsxCounters.c \ + PsxDma.c \ + Spu.c \ + PsxMem.c \ + PsxHw.c \ + Misc.c \ + R3000A.c \ + PsxInterpreter.c \ + PsxHLE.c \ + spu/spu.c \ + xmms.c + +LIBADD = -lz + +OBJECTS = ${SOURCES:.c=.o} + +CFLAGS += -Wno-nonnull -fPIC -DPIC $(GTK_CFLAGS) -I../../../intl -I../../.. -Ispu/ -I.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/Misc.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,469 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> + +#include "PsxCommon.h" +#include "driver.h" + +// LOAD STUFF + +typedef struct { + unsigned char id[8]; + u32 text; + u32 data; + u32 pc0; + u32 gp0; + u32 t_addr; + u32 t_size; + u32 d_addr; + u32 d_size; + u32 b_addr; + u32 b_size; + u32 S_addr;//normal must a s not a S but error (???) + u32 s_size; + u32 SavedSP; + u32 SavedFP; + u32 SavedGP; + u32 SavedRA; + u32 SavedS0; +} PACKSTRUCT EXE_HEADER; + +static long TimeToMS(const char *str) +{ + int x,c=0; + int acc=0; + char s[100]; + + strncpy(s,str,100); + s[99]=0; + + for(x=strlen(s);x>=0;x--) + if(s[x]=='.' || s[x]==',') + { + acc=atoi(s+x+1); + s[x]=0; + } + else if(s[x]==':') + { + if(c==0) acc+=atoi(s+x+1)*10; + else if(c==1) acc+=atoi(s+x+(x?1:0))*10*60; + c++; + s[x]=0; + } + else if(x==0) + { + if(c==0) acc+=atoi(s+x)*10; + else if(c==1) acc+=atoi(s+x)*10*60; + else if(c==2) acc+=atoi(s+x)*10*60*60; + } + acc*=100; // To milliseconds. + return(acc); +} + +char *GetFileWithBase(char *f, char *newfile) +{ + static char *ret; + char *tp1; + + #if PSS_STYLE==1 + tp1=((char *)strrchr(f,'/')); + #else + tp1=((char *)strrchr(f,'\\')); + #if PSS_STYLE!=3 + { + char *tp3; + + tp3=((char *)strrchr(f,'/')); + if(tp1<tp3) tp1=tp3; + } + #endif + #endif + if(!tp1) + { + ret=malloc(strlen(newfile)+1); + strcpy(ret,newfile); + } + else + { + ret=malloc(tp1-f+2+strlen(newfile)); // 1(NULL), 1(/). + memcpy(ret,f,tp1-f); + ret[tp1-f]='/'; + ret[tp1-f+1]=0; + strcat(ret,newfile); + } + return(ret); +} + +static int GetKeyVal(char *buf, char **key, char **val) +{ + char *tmp; + + tmp=buf; + + /* First, convert any weirdo ASCII characters to spaces. */ + while(*tmp++) if(*tmp>0 && *tmp<0x20) *tmp=0x20; + + /* Strip off white space off end of string(which should be the "value"). */ + for(tmp=buf+strlen(buf)-1;tmp>=buf;tmp--) + { + if(*tmp != 0x20) break; + *tmp=0; + } + + /* Now, search for the first non-whitespace character. */ + while(*buf == 0x20) buf++; + + tmp=buf; + while((*buf != 0x20) && (*buf != '=')) + { + if(!*buf) return(0); /* Null character. */ + buf++; + } + + /* Allocate memory, copy string, and terminate string. */ + if(!(*key=malloc(buf-tmp+1))) return(0); + strncpy(*key,tmp,buf-tmp); + (*key)[(buf-tmp)]=0; + + /* Search for "=" character. */ + while(*buf != '=') + { + if(!*buf) return(0); /* Null character. */ + buf++; + } + + buf++; /* Skip over equals character. */ + + /* Remove leading whitespace on value. */ + while(*buf == 0x20) + { + if(!*buf) return(0); /* Null character. */ + buf++; + } + + /* Allocate memory, and copy string over. Trailing whitespace was eliminated + earlier. + */ + + if(!(*val=malloc(strlen(buf)+1))) return(0); + strcpy(*val,buf); + + //puts(*key); + //puts(*val); + + return(1); +} + +static void FreeTags(PSFTAG *tags) +{ + while(tags) + { + PSFTAG *tmp=tags->next; + + free(tags->key); + free(tags->value); + free(tags); + + tags=tmp; + } +} + +static void AddKV(PSFTAG **tag, char *key, char *val) +{ + PSFTAG *tmp; + + tmp=malloc(sizeof(PSFTAG)); + memset(tmp,0,sizeof(PSFTAG)); + + tmp->key=key; + tmp->value=val; + tmp->next=0; + + if(!*tag) *tag=tmp; + else + { + PSFTAG *rec; + rec=*tag; + while(rec->next) rec=rec->next; + rec->next=tmp; + } + +} + +typedef struct { + int num; + char *value; +} LIBNCACHE; + +static int ccomp(const void *v1, const void *v2) +{ + const LIBNCACHE *a1,*a2; + a1=v1; a2=v2; + + return(a1->num - a2->num); +} + +static PSFINFO *LoadPSF(char *path, int level, int type) // Type==1 for just info load. +{ + FILE *fp; + EXE_HEADER tmpHead; + unsigned char *in,*out=0; + u8 head[4]; + u32 reserved; + u32 complen; + u32 crc32; + uLongf outlen; + PSFINFO *psfi; + PSFINFO *tmpi; + + if(!(fp=fopen(path,"rb"))) + { + printf("path %s failed to load\n", path); + return(0); + } + + fread(head,1,4,fp); + if(memcmp(head,"PSF\x01",4)) return(0); + + psfi=malloc(sizeof(PSFINFO)); + memset(psfi,0,sizeof(PSFINFO)); + psfi->stop=~0; + psfi->fade=0; + + fread(&reserved,1,4,fp); + fread(&complen,1,4,fp); + complen=BFLIP32(complen); + + fread(&crc32,1,4,fp); + crc32=BFLIP32(crc32); + + fseek(fp,reserved,SEEK_CUR); + + if(type) + fseek(fp,complen,SEEK_CUR); + else + { + in=malloc(complen); + out=malloc(1024*1024*2+0x800); + fread(in,1,complen,fp); + outlen=1024*1024*2; + uncompress(out,&outlen,in,complen); + free(in); + memcpy(&tmpHead,out,sizeof(EXE_HEADER)); + psxRegs.pc = BFLIP32(tmpHead.pc0); + psxRegs.GPR.n.gp = BFLIP32(tmpHead.gp0); + psxRegs.GPR.n.sp = BFLIP32(tmpHead.S_addr); + if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00; + + if(level) + { + LoadPSXMem(BFLIP32(tmpHead.t_addr),BFLIP32(tmpHead.t_size),out+0x800); + free(out); + } + } + + { + u8 tagdata[5]; + if(fread(tagdata,1,5,fp)==5) + { + if(!memcmp(tagdata,"[TAG]",5)) + { + char linebuf[1024]; + + while(fgets(linebuf,1024,fp)) + { + int x; + char *key=0,*value=0; + + if(!GetKeyVal(linebuf,&key,&value)) + { + if(key) free(key); + if(value) free(value); + continue; + } + + AddKV(&psfi->tags,key,value); + + if(!level) + { + static char *yoinks[8]={"title","artist","game","year","genre", + "copyright","psfby","comment"}; + char **yoinks2[8]={&psfi->title,&psfi->artist,&psfi->game,&psfi->year,&psfi->genre, + &psfi->copyright,&psfi->psfby,&psfi->comment}; + for(x=0;x<8;x++) + if(!strcasecmp(key,yoinks[x])) + *yoinks2[x]=value; + if(!strcasecmp(key,"length")) + psfi->stop=TimeToMS(value); + else if(!strcasecmp(key,"fade")) + psfi->fade=TimeToMS(value); + } + + if(!strcasecmp(key,"_lib") && !type) + { + char *tmpfn; + /* Load file name "value" from the directory specified in + the full path(directory + file name) "path" + */ + tmpfn=GetFileWithBase(path,value); + if(!(tmpi=LoadPSF(tmpfn,level+1,0))) + { + free(key); + free(value); + free(tmpfn); + if(!level) free(out); + fclose(fp); + FreeTags(psfi->tags); + free(psfi); + return(0); + } + FreeTags(tmpi->tags); + free(tmpi); + free(tmpfn); + } + } + } + } + } + + fclose(fp); + + /* Now, if we're at level 0(main PSF), load the main executable, and any libN stuff */ + if(!level && !type) + { + LoadPSXMem(BFLIP32(tmpHead.t_addr),BFLIP32(tmpHead.t_size),out+0x800); + free(out); + } + + if(!type) /* Load libN */ + { + LIBNCACHE *cache; + PSFTAG *tag; + unsigned int libncount=0; + unsigned int cur=0; + + tag=psfi->tags; + while(tag) + { + if(!strncasecmp(tag->key,"_lib",4) && tag->key[4]) + libncount++; + tag=tag->next; + } + + if(libncount) + { + cache=malloc(sizeof(LIBNCACHE)*libncount); + + tag=psfi->tags; + while(tag) + { + if(!strncasecmp(tag->key,"_lib",4) && tag->key[4]) + { + cache[cur].num=atoi(&tag->key[4]); + cache[cur].value=tag->value; + cur++; + } + tag=tag->next; + } + qsort(cache, libncount, sizeof(LIBNCACHE), ccomp); + for(cur=0;cur<libncount;cur++) + { + u32 ba[3]; + char *tmpfn; + + if(cache[cur].num < 2) continue; + + ba[0]=psxRegs.pc; + ba[1]=psxRegs.GPR.n.gp; + ba[2]=psxRegs.GPR.n.sp; + + /* Load file name "value" from the directory specified in + the full path(directory + file name) "path" + */ + tmpfn=GetFileWithBase(path,cache[cur].value); + if(!(tmpi=LoadPSF(tmpfn,level+1,0))) + { + //free(key); + //free(value); + //free(tmpfn); + //fclose(fp); + //return(0); + } + free(tmpfn); + FreeTags(tmpi->tags); + free(tmpi); + + psxRegs.pc=ba[0]; + psxRegs.GPR.n.gp=ba[1]; + psxRegs.GPR.n.sp=ba[2]; + } + free(cache); + + } // if(libncount) + + } // if(!type) + + return(psfi); +} + +void sexypsf_freepsfinfo(PSFINFO *info) +{ + FreeTags(info->tags); + free(info); +} + +PSFINFO *sexypsf_getpsfinfo(char *path) +{ + PSFINFO *ret; + if(!(ret=LoadPSF(path,0,1))) return(0); + if(ret->stop==(u32)~0) ret->fade=0; + ret->length=ret->stop+ret->fade; + return(ret); +} + +PSFINFO *sexypsf_load(char *path) +{ + PSFINFO *ret; + + psxInit(); + psxReset(); + + SPUinit(); + SPUopen(); + + if(!(ret=LoadPSF(path,0,0))) + { + psxShutdown(); + return(0); + } + + if(ret->stop==(u32)~0) ret->fade=0; // Infinity+anything is still infinity...or is it? + SPUsetlength(ret->stop,ret->fade); + ret->length=ret->stop+ret->fade; + + return(ret); +} + +void sexypsf_execute(void) +{ + psxCpu->Execute(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/Misc.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,22 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __MISC_H__ +#define __MISC_H__ + +#endif /* __MISC_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/PsxBios.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,1367 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <ctype.h> + +#include "PsxCommon.h" +//We try to emulate bios :) HELP US :P + +#ifdef NONONO +char *biosA0n[256] = { +// 0x00 + "open", "lseek", "read", "write", + "close", "ioctl", "exit", "sys_a0_07", + "getc", "putc", "todigit", "atof", + "strtoul", "strtol", "abs", "labs", +// 0x10 + "atoi", "atol", "atob", "setjmp", + "longjmp", "strcat", "strncat", "strcmp", + "strncmp", "strcpy", "strncpy", "strlen", + "index", "rindex", "strchr", "strrchr", +// 0x20 + "strpbrk", "strspn", "strcspn", "strtok", + "strstr", "toupper", "tolower", "bcopy", + "bzero", "bcmp", "memcpy", "memset", + "memmove", "memcmp", "memchr", "rand", +// 0x30 + "srand", "qsort", "strtod", "malloc", + "free", "lsearch", "bsearch", "calloc", + "realloc", "InitHeap", "_exit", "getchar", + "putchar", "gets", "puts", "printf", +// 0x40 + "sys_a0_40", "LoadTest", "Load", "Exec", + "FlushCache", "InstallInterruptHandler", "GPU_dw", "mem2vram", + "SendGPUStatus", "GPU_cw", "GPU_cwb", "SendPackets", + "sys_a0_4c", "GetGPUStatus", "GPU_sync", "sys_a0_4f", +// 0x50 + "sys_a0_50", "LoadExec", "GetSysSp", "sys_a0_53", + "_96_init()", "_bu_init()", "_96_remove()", "sys_a0_57", + "sys_a0_58", "sys_a0_59", "sys_a0_5a", "dev_tty_init", + "dev_tty_open", "sys_a0_5d", "dev_tty_ioctl","dev_cd_open", +// 0x60 + "dev_cd_read", "dev_cd_close", "dev_cd_firstfile", "dev_cd_nextfile", + "dev_cd_chdir", "dev_card_open", "dev_card_read", "dev_card_write", + "dev_card_close", "dev_card_firstfile", "dev_card_nextfile","dev_card_erase", + "dev_card_undelete","dev_card_format", "dev_card_rename", "dev_card_6f", +// 0x70 + "_bu_init", "_96_init", "_96_remove", "sys_a0_73", + "sys_a0_74", "sys_a0_75", "sys_a0_76", "sys_a0_77", + "_96_CdSeekL", "sys_a0_79", "sys_a0_7a", "sys_a0_7b", + "_96_CdGetStatus", "sys_a0_7d", "_96_CdRead", "sys_a0_7f", +// 0x80 + "sys_a0_80", "sys_a0_81", "sys_a0_82", "sys_a0_83", + "sys_a0_84", "_96_CdStop", "sys_a0_86", "sys_a0_87", + "sys_a0_88", "sys_a0_89", "sys_a0_8a", "sys_a0_8b", + "sys_a0_8c", "sys_a0_8d", "sys_a0_8e", "sys_a0_8f", +// 0x90 + "sys_a0_90", "sys_a0_91", "sys_a0_92", "sys_a0_93", + "sys_a0_94", "sys_a0_95", "AddCDROMDevice", "AddMemCardDevide", + "DisableKernelIORedirection", "EnableKernelIORedirection", "sys_a0_9a", "sys_a0_9b", + "SetConf", "GetConf", "sys_a0_9e", "SetMem", +// 0xa0 + "_boot", "SystemError", "EnqueueCdIntr", "DequeueCdIntr", + "sys_a0_a4", "ReadSector", "get_cd_status", "bufs_cb_0", + "bufs_cb_1", "bufs_cb_2", "bufs_cb_3", "_card_info", + "_card_load", "_card_auto", "bufs_cd_4", "sys_a0_af", +// 0xb0 + "sys_a0_b0", "sys_a0_b1", "do_a_long_jmp", "sys_a0_b3", + "?? sub_function", +}; + +char *biosB0n[256] = { +// 0x00 + "SysMalloc", "sys_b0_01", "sys_b0_02", "sys_b0_03", + "sys_b0_04", "sys_b0_05", "sys_b0_06", "DeliverEvent", + "OpenEvent", "CloseEvent", "WaitEvent", "TestEvent", + "EnableEvent", "DisableEvent", "OpenTh", "CloseTh", +// 0x10 + "ChangeTh", "sys_b0_11", "InitPAD", "StartPAD", + "StopPAD", "PAD_init", "PAD_dr", "ReturnFromExecption", + "ResetEntryInt", "HookEntryInt", "sys_b0_1a", "sys_b0_1b", + "sys_b0_1c", "sys_b0_1d", "sys_b0_1e", "sys_b0_1f", +// 0x20 + "UnDeliverEvent", "sys_b0_21", "sys_b0_22", "sys_b0_23", + "sys_b0_24", "sys_b0_25", "sys_b0_26", "sys_b0_27", + "sys_b0_28", "sys_b0_29", "sys_b0_2a", "sys_b0_2b", + "sys_b0_2c", "sys_b0_2d", "sys_b0_2e", "sys_b0_2f", +// 0x30 + "sys_b0_30", "sys_b0_31", "open", "lseek", + "read", "write", "close", "ioctl", + "exit", "sys_b0_39", "getc", "putc", + "getchar", "putchar", "gets", "puts", +// 0x40 + "cd", "format", "firstfile", "nextfile", + "rename", "delete", "undelete", "AddDevice", + "RemoteDevice", "PrintInstalledDevices", "InitCARD", "StartCARD", + "StopCARD", "sys_b0_4d", "_card_write", "_card_read", +// 0x50 + "_new_card", "Krom2RawAdd", "sys_b0_52", "sys_b0_53", + "_get_errno", "_get_error", "GetC0Table", "GetB0Table", + "_card_chan", "sys_b0_59", "sys_b0_5a", "ChangeClearPAD", + "_card_status", "_card_wait", +}; + +char *biosC0n[256] = { +// 0x00 + "InitRCnt", "InitException", "SysEnqIntRP", "SysDeqIntRP", + "get_free_EvCB_slot", "get_free_TCB_slot", "ExceptionHandler", "InstallExeptionHandler", + "SysInitMemory", "SysInitKMem", "ChangeClearRCnt", "SystemError", + "InitDefInt", "sys_c0_0d", "sys_c0_0e", "sys_c0_0f", +// 0x10 + "sys_c0_10", "sys_c0_11", "InstallDevices", "FlushStfInOutPut", + "sys_c0_14", "_cdevinput", "_cdevscan", "_circgetc", + "_circputc", "ioabort", "sys_c0_1a", "KernelRedirect", + "PatchAOTable", +}; +#endif + +//#define r0 (psxRegs.GPR.n.r0) +#define at (psxRegs.GPR.n.at) +#define v0 (psxRegs.GPR.n.v0) +#define v1 (psxRegs.GPR.n.v1) +#define a0 (psxRegs.GPR.n.a0) +#define a1 (psxRegs.GPR.n.a1) +#define a2 (psxRegs.GPR.n.a2) +#define a3 (psxRegs.GPR.n.a3) +#define t0 (psxRegs.GPR.n.t0) +#define t1 (psxRegs.GPR.n.t1) +#define t2 (psxRegs.GPR.n.t2) +#define t3 (psxRegs.GPR.n.t3) +#define t4 (psxRegs.GPR.n.t4) +#define t5 (psxRegs.GPR.n.t5) +#define t6 (psxRegs.GPR.n.t6) +#define t7 (psxRegs.GPR.n.t7) +#define s0 (psxRegs.GPR.n.s0) +#define s1 (psxRegs.GPR.n.s1) +#define s2 (psxRegs.GPR.n.s2) +#define s3 (psxRegs.GPR.n.s3) +#define s4 (psxRegs.GPR.n.s4) +#define s5 (psxRegs.GPR.n.s5) +#define s6 (psxRegs.GPR.n.s6) +#define s7 (psxRegs.GPR.n.s7) +#define t8 (psxRegs.GPR.n.t6) +#define t9 (psxRegs.GPR.n.t7) +#define k0 (psxRegs.GPR.n.k0) +#define k1 (psxRegs.GPR.n.k1) +#define gp (psxRegs.GPR.n.gp) +#define sp (psxRegs.GPR.n.sp) +#define fp (psxRegs.GPR.n.s8) +#define ra (psxRegs.GPR.n.ra) +#define pc0 (psxRegs.pc) + +#define Ra0 ((char*)PSXM(a0)) +#define Ra1 ((char*)PSXM(a1)) +#define Ra2 ((char*)PSXM(a2)) +#define Ra3 ((char*)PSXM(a3)) +#define Rv0 ((char*)PSXM(v0)) +#define Rsp ((char*)PSXM(sp)) + + +typedef struct _malloc_chunk { + u32 stat; + u32 size; + u32 fd; + u32 bk; +} PACKSTRUCT malloc_chunk; + +#define INUSE 0x1 + +typedef struct { + u32 desc; + s32 status; + s32 mode; + u32 fhandler; +} PACKSTRUCT EvCB[32]; + +#define EvStUNUSED 0x0000 +#define EvStWAIT 0x1000 +#define EvStACTIVE 0x2000 +#define EvStALREADY 0x4000 + +#define EvMdINTR 0x1000 +#define EvMdNOINTR 0x2000 + +typedef struct { + s32 status; + s32 mode; + u32 reg[32]; + u32 func; +} PACKSTRUCT TCB; + +static u32 *jmp_int; + +static u32 regs[35]; +static EvCB *Event; + +//static EvCB *HwEV; // 0xf0 +//static EvCB *EvEV; // 0xf1 +static EvCB *RcEV; // 0xf2 +//static EvCB *UeEV; // 0xf3 +//static EvCB *SwEV; // 0xf4 +//static EvCB *ThEV; // 0xff + +static u32 heap_addr; +static u32 SysIntRP[8]; +static TCB Thread[8]; +static int CurThread; + +static INLINE void softCall(u32 pc) { + pc0 = pc; + ra = 0x80001000; + while (pc0 != 0x80001000) psxCpu->ExecuteBlock(); +} + +static INLINE void softCall2(u32 pc) { + u32 sra = ra; + pc0 = pc; + ra = 0x80001000; + while (pc0 != 0x80001000) psxCpu->ExecuteBlock(); + ra = sra; +} + +static INLINE void DeliverEvent(u32 ev, u32 spec) { + if (Event[ev][spec].status != BFLIP32S(EvStACTIVE)) return; + +// Event[ev][spec].status = BFLIP32S(EvStALREADY); + if (Event[ev][spec].mode == BFLIP32S(EvMdINTR)) { + softCall2(BFLIP32S(Event[ev][spec].fhandler)); + } else Event[ev][spec].status = BFLIP32S(EvStALREADY); +} + +/* * +// * +// * +// System calls A0 */ + +/* Abs and labs do the same thing? */ + +static void bios_abs() { // 0x0e + if((s32)a0 < 0) v0=0-(s32)a0; + else v0=a0; + //v0 = abs(a0); + pc0 = ra; +} + +static void bios_labs() { // 0x0f + if((s32)a0 < 0) v0=0-(s32)a0; + else v0=a0; + //v0 = labs(a0); + pc0 = ra; +} + +static void bios_atoi() { // 0x10 + v0 = atoi((char *)Ra0); + pc0 = ra; +} + +static void bios_atol() { // 0x11 + v0 = atoi((char *)Ra0); + pc0 = ra; +} + +static void bios_setjmp() { // 13 + u32 *jmp_buf= (u32*)Ra0; + int i; + + jmp_buf[0] = BFLIP32(ra); + jmp_buf[1] = BFLIP32(sp); + jmp_buf[2] = BFLIP32(fp); + for (i=0; i<8; i++) // s0-s7 + jmp_buf[3+i] = BFLIP32(psxRegs.GPR.r[16+i]); + jmp_buf[11] = BFLIP32(gp); + + v0 = 0; pc0 = ra; +} + +static void bios_longjmp() { //14 + u32 *jmp_buf= (u32*)Ra0; + int i; + + ra = BFLIP32(jmp_buf[0]); /* ra */ + sp = BFLIP32(jmp_buf[1]); /* sp */ + fp = BFLIP32(jmp_buf[2]); /* fp */ + for (i=0; i<8; i++) // s0-s7 + psxRegs.GPR.r[16+i] = BFLIP32(jmp_buf[3+i]); + gp = BFLIP32(jmp_buf[11]); /* gp */ + + v0 = a1; pc0 = ra; +} + +static void bios_strcat() { // 0x15 + u32 dest,src; + + dest=a0; + src=a1; + + while(PSXMu8(dest) != 0) dest++; /* Move to end of first string. */ + while(PSXMu8(src) != 0) + { + if(PSXM(dest) && PSXM(src)) + PSXMu8(dest)=PSXMu8(src); + src++; + dest++; + } + PSXMu8(dest) = 0; /* Append null character. */ + //strcat(Ra0, Ra1); + + v0 = a0; + pc0 = ra; +} + +/*0x16*/ +static void bios_strncat() +{ + u32 dest,src,count; + + dest=a0; + src=a1; + count=a2; + + while(PSXMu8(dest) != 0) dest++; /* Move to end of first string. */ + while(PSXMu8(src) != 0 && count) + { + if(PSXM(dest) && PSXM(src)) + PSXMu8(dest)=PSXMu8(src); + src++; + dest++; + count--; + } + PSXMu8(dest) = 0; /* Append null character. */ + + //strncat(Ra0, Ra1, a2); + v0 = a0; + pc0 = ra; +} + +static void bios_strcmp() { // 0x17 + v0 = strcmp(Ra0, Ra1); + pc0 = ra; +} + +static void bios_strncmp() { // 0x18 + u32 max=a2; + u32 string1=a0; + u32 string2=a1; + s8 tmpv=0; + + while(max>0) + { + u8 tmp1=PSXMuR8(string1); + u8 tmp2=PSXMuR8(string2); + + if(!tmp1 || !tmp2) break; + + tmpv=tmp1-tmp2; + if(tmpv) break; + if(!tmp1 || !tmp2) break; + if(!PSXM(string1) || !PSXM(string2)) break; + max--; + string1++; + string2++; + } + if(tmpv>0) v0=1; + else if(tmpv<0) v0=-1; + else v0=0; + //printf("%s:%s, %d, %d\n",Ra0,Ra1,a2,v0); + //v0 = strncmp(Ra0, Ra1, a2); + pc0 = ra; +} + +/*0x19*/ +static void bios_strcpy() +{ + u32 src=a1,dest=a0; + u8 val; + + do + { + val=PSXMu8(src); + PSXMu8(dest)=val; + src++; + dest++; + } while(val); + //strcpy(Ra0, Ra1); + v0 = a0; + pc0 = ra; +} +/*0x1a*/ +static void bios_strncpy() +{ + u32 src=a1,dest=a0,max=a2; + u8 val; + + do + { + val=PSXMu8(src); + PSXMu8(dest)=val; + src++; + dest++; + max--; + } while(val && max); + + //strncpy(Ra0, Ra1, a2); + v0 = a0; + pc0 = ra; +} + +/*0x1b*/ +static void bios_strlen() +{ + u32 src=a0; + + while(PSXMu8(src)) src++; + + v0 = src-a0; + pc0 = ra; +} + +static void bios_index() { // 0x1c + char *pcA0 = (char *)Ra0; + char *pcRet = strchr(pcA0, a1); + if(pcRet) + v0 = a0 + pcRet - pcA0; + else + v0 = 0; + pc0 = ra; +} + +static void bios_rindex() { // 0x1d + char *pcA0 = (char *)Ra0; + char *pcRet = strrchr(pcA0, a1); + if(pcRet) + v0 = a0 + pcRet - pcA0; + else + v0 = 0; + pc0 = ra; +} + +static void bios_strchr() { // 0x1e + char *pcA0 = (char *)Ra0; + char *pcRet = strchr(pcA0, a1); + if(pcRet) + v0 = a0 + pcRet - pcA0; + else + v0 = 0; + pc0 = ra; +} + +static void bios_strrchr() { // 0x1f + char *pcA0 = (char *)Ra0; + char *pcRet = strrchr(pcA0, a1); + if(pcRet) + v0 = a0 + pcRet - pcA0; + else + v0 = 0; + pc0 = ra; +} + +static void bios_strpbrk() { // 0x20 + char *pcA0 = (char *)Ra0; + char *pcRet = strpbrk(pcA0, (char *)Ra1); + if(pcRet) + v0 = a0 + pcRet - pcA0; + else + v0 = 0; + pc0 = ra; +} + +static void bios_strspn() { v0 = strspn ((char *)Ra0, (char *)Ra1); pc0 = ra;}/*21*/ +static void bios_strcspn() { v0 = strcspn((char *)Ra0, (char *)Ra1); pc0 = ra;}/*22*/ + +#ifdef MOO +static void bios_strtok() { // 0x23 + char *pcA0 = (char *)Ra0; + char *pcRet = strtok(pcA0, (char *)Ra1); + if(pcRet) + v0 = a0 + pcRet - pcA0; + else + v0 = 0; + pc0 = ra; +} +#endif + +static void bios_strstr() { // 0x24 + char *pcA0 = (char *)Ra0; + char *pcRet = strstr(pcA0, (char *)Ra1); + if(pcRet) + v0 = a0 + pcRet - pcA0; + else + v0 = 0; + pc0 = ra; +} + +/*0x25*/ +static void bios_toupper() {v0 = toupper(a0); pc0 = ra;} + +/*0x26*/ +static void bios_tolower() {v0 = tolower(a0); pc0 = ra;} + +/*0x27*/ +static void bios_bcopy() +{ + u32 dest=a1, src=a0, len=a2; + + while(len--) + { + PSXMu8(dest)=PSXMu8(src); + dest++; + src++; + } + //memcpy(Ra1,Ra0,a2); + pc0=ra; +} + +/*0x28*/ +static void bios_bzero() +{ + u32 dest=a0, len=a1; + + while(len--) + { + PSXMu8(dest)=0; + dest++; + } + + //memset(Ra0,0,a1); + pc0=ra; +} + +/*0x29*/ +static void bios_bcmp() {v0 = memcmp(Ra0,Ra1,a2); pc0=ra; } + +/*0x2a*/ +static void bios_memcpy() +{ + u32 dest=a0, src=a1, len=a2; + + while(len--) + { + PSXMu8(dest)=PSXMu8(src); + dest++; + src++; + } + //memcpy(Ra0, Ra1, a2); + v0 = a0; + pc0 = ra; +} + +static void bios_memset() /*0x2b*/ +{ + u32 len=a2; + u32 dest=a0; + + while(len--) + { + if(PSXM(dest)) PSXMu8(dest)=a1; + dest++; + } + //memset(Ra0, a1, a2); + v0 = a0; + pc0 = ra; +} + +#ifdef MOO +/*0x2c*/void bios_memmove() {memmove(Ra0, Ra1, a2); v0 = a0; pc0 = ra;} +#endif + +/*0x2d*/ +static void bios_memcmp() +{ + v0 = memcmp(Ra0, Ra1, a2); + pc0 = ra; +} + +static void bios_memchr() { // 2e + void *ret = memchr(Ra0, a1, a2); + if (ret != NULL) v0 = (u32)((char*)ret - Ra0) + a0; + else v0 = 0; + pc0 = ra; +} + +static void bios_rand() { // 2f + v0 = 1+(int) (32767.0*rand()/(RAND_MAX+1.0)); + pc0 = ra; +} + +static void bios_srand() { // 30 + srand(a0); pc0 = ra; +} + +static void bios_malloc() { // 33 + u32 chunk; + u32 fd; + + /* a0: Number of bytes to allocate. */ + + chunk = heap_addr; + + /* Search for first chunk that's large enough and not currently + being used. + */ + while( (a0 > BFLIP32(((malloc_chunk*)PSXM(chunk)) ->size)) || + (BFLIP32( ((malloc_chunk*)PSXM(chunk))->stat ) == INUSE) + ) + chunk=((malloc_chunk*)PSXM(chunk)) -> fd; + //printf("%08x\n",chunk); + + /* split free chunk */ + fd = chunk + sizeof(malloc_chunk) + a0; + ((malloc_chunk*)PSXM(fd))->stat = ((malloc_chunk*)PSXM(chunk))->stat; + ((malloc_chunk*)PSXM(fd))->size = BFLIP32(BFLIP32(((malloc_chunk*)PSXM(chunk))->size) - a0); + ((malloc_chunk*)PSXM(fd))->fd = ((malloc_chunk*)PSXM(chunk))->fd; + ((malloc_chunk*)PSXM(fd))->bk = chunk; + + /* set new chunk */ + ((malloc_chunk*)PSXM(chunk))->stat = BFLIP32(INUSE); + ((malloc_chunk*)PSXM(chunk))->size = BFLIP32(a0); + ((malloc_chunk*)PSXM(chunk))->fd = fd; + + v0 = chunk + sizeof(malloc_chunk); + v0|= 0x80000000; + // printf ("malloc %lx,%lx\n", v0, a0); + pc0 = ra; +} + +static void bios_InitHeap() { // 39 + malloc_chunk *chunk; + + heap_addr = a0; // Ra0 + + chunk = (malloc_chunk *)PSXM(heap_addr); + chunk->stat = 0; + if (((a0 & 0x1fffff) + a1)>= 0x200000) + chunk->size = BFLIP32(0x1ffffc - (a0 & 0x1fffff)); + else chunk->size = BFLIP32(a1); + chunk->fd = 0; + chunk->bk = 0; + + pc0 = ra; +} + +static void bios_FlushCache() { // 44 + + pc0 = ra; +} + +static void bios__bu_init() { // 70 + + DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004 + DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004 + + pc0 = ra; +} + +static void bios__96_init() { // 71 + + pc0 = ra; +} + +static void bios__96_remove() { // 72 + + pc0 = ra; +} + +/* System calls B0 */ + +static void bios_SetRCnt() { // 02 + + a0&= 0x3; + if (a0 != 3) { + u32 mode=0; + + psxRcntWtarget(a0, a1); + if (a2&0x1000) mode|= 0x050; // Interrupt Mode + if (a2&0x0100) mode|= 0x008; // Count to 0xffff + if (a2&0x0010) mode|= 0x001; // Timer stop mode + if (a0 == 2) { if (a2&0x0001) mode|= 0x200; } // System Clock mode + else { if (a2&0x0001) mode|= 0x100; } // System Clock mode + + psxRcntWmode(a0, mode); + } + pc0 = ra; +} + +static void bios_GetRCnt() { // 03 + + a0&= 0x3; + if (a0 != 3) v0 = psxRcntRcount(a0); + else v0 = 0; + pc0 = ra; +} + +static void bios_StartRCnt() { // 04 + + a0&= 0x3; + if (a0 != 3) psxHu32(0x1074)|= BFLIP32(1<<(a0+4)); + else psxHu32(0x1074)|= BFLIP32(0x1); + v0 = 1; pc0 = ra; +} + +static void bios_StopRCnt() { // 05 + + a0&= 0x3; + if (a0 != 3) psxHu32(0x1074)&= BFLIP32(~(1<<(a0+4))); + else psxHu32(0x1074)&= BFLIP32(~0x1); + pc0 = ra; +} + +static void bios_ResetRCnt() { // 06 + + a0&= 0x3; + if (a0 != 3) { + psxRcntWmode(a0, 0); + psxRcntWtarget(a0, 0); + psxRcntWcount(a0, 0); + } + pc0 = ra; +} + + +/* gets ev for use with Event */ +#define GetEv() \ + ev = (a0 >> 24) & 0xf; \ + if (ev == 0xf) ev = 0x5; \ + ev*= 32; \ + ev+= a0&0x1f; + +/* gets spec for use with Event */ +#define GetSpec() \ + spec = 0; \ + switch (a1) { \ + case 0x0301: spec = 16; break; \ + case 0x0302: spec = 17; break; \ + default: \ + for (i=0; i<16; i++) if (a1 & (1 << i)) { spec = i; break; } \ + break; \ + } + +static void bios_DeliverEvent() { // 07 + int ev, spec; + int i; + + GetEv(); + GetSpec(); + + DeliverEvent(ev, spec); + + pc0 = ra; +} + +static void bios_OpenEvent() { // 08 + int ev, spec; + int i; + + GetEv(); + GetSpec(); + + Event[ev][spec].status = BFLIP32S(EvStWAIT); + Event[ev][spec].mode = BFLIP32(a2); + Event[ev][spec].fhandler = BFLIP32(a3); + + v0 = ev | (spec << 8); + pc0 = ra; +} + +static void bios_CloseEvent() { // 09 + int ev, spec; + + ev = a0 & 0xff; + spec = (a0 >> 8) & 0xff; + + Event[ev][spec].status = BFLIP32S(EvStUNUSED); + + v0 = 1; pc0 = ra; +} + +static void bios_WaitEvent() { // 0a + int ev, spec; + + ev = a0 & 0xff; + spec = (a0 >> 8) & 0xff; + + Event[ev][spec].status = BFLIP32S(EvStACTIVE); + + v0 = 1; pc0 = ra; +} + +static void bios_TestEvent() { // 0b + int ev, spec; + + ev = a0 & 0xff; + spec = (a0 >> 8) & 0xff; + + if (Event[ev][spec].status == BFLIP32S(EvStALREADY)) { + Event[ev][spec].status = BFLIP32S(EvStACTIVE); v0 = 1; + } else v0 = 0; + + pc0 = ra; +} + +static void bios_EnableEvent() { // 0c + int ev, spec; + + ev = a0 & 0xff; + spec = (a0 >> 8) & 0xff; + + Event[ev][spec].status = BFLIP32S(EvStACTIVE); + + v0 = 1; pc0 = ra; +} + +static void bios_DisableEvent() { // 0d + int ev, spec; + + ev = a0 & 0xff; + spec = (a0 >> 8) & 0xff; + + Event[ev][spec].status = BFLIP32S(EvStWAIT); + + v0 = 1; pc0 = ra; +} + +/* + * long OpenTh(long (*func)(), unsigned long sp, unsigned long gp); + */ + +static void bios_OpenTh() { // 0e + int th; + + for (th=1; th<8; th++) + if (Thread[th].status == 0) break; + + Thread[th].status = BFLIP32(1); + Thread[th].func = BFLIP32(a0); + Thread[th].reg[29] = BFLIP32(a1); + Thread[th].reg[28] = BFLIP32(a2); + + v0 = th; pc0 = ra; +} + +/* + * int CloseTh(long thread); + */ + +static void bios_CloseTh() { // 0f + int th = a0 & 0xff; + + if (Thread[th].status == 0) { + v0 = 0; + } else { + Thread[th].status = 0; + v0 = 1; + } + + pc0 = ra; +} + +/* + * int ChangeTh(long thread); + */ + +static void bios_ChangeTh() { // 10 + int th = a0 & 0xff; + + if (Thread[th].status == 0 || CurThread == th) { + v0 = 0; + + pc0 = ra; + } else { + v0 = 1; + + if (Thread[CurThread].status == BFLIP32S(2)) { + Thread[CurThread].status = BFLIP32S(1); + Thread[CurThread].func = BFLIP32(ra); + memcpy(Thread[CurThread].reg, psxRegs.GPR.r, 32*4); + } + + memcpy(psxRegs.GPR.r, Thread[th].reg, 32*4); + pc0 = BFLIP32(Thread[th].func); + Thread[th].status = BFLIP32(2); + CurThread = th; + } +} + +static void bios_ReturnFromException() { // 17 + memcpy(psxRegs.GPR.r, regs, 32*4); + psxRegs.GPR.n.lo = regs[32]; + psxRegs.GPR.n.hi = regs[33]; + + pc0 = psxRegs.CP0.n.EPC; + if (psxRegs.CP0.n.Cause & 0x80000000) pc0+=4; + + psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) | + ((psxRegs.CP0.n.Status & 0x3c) >> 2); +} + +static void bios_ResetEntryInt() { // 18 + + jmp_int = NULL; + pc0 = ra; +} + +static void bios_HookEntryInt() { // 19 + + jmp_int = (u32*)Ra0; + pc0 = ra; +} + +static void bios_UnDeliverEvent() { // 0x20 + int ev, spec; + int i; + + GetEv(); + GetSpec(); + + if (Event[ev][spec].status == BFLIP32S(EvStALREADY) && + Event[ev][spec].mode == BFLIP32S(EvMdNOINTR)) + Event[ev][spec].status = BFLIP32S(EvStACTIVE); + + pc0 = ra; +} + +static void bios_GetC0Table() { // 56 + + v0 = 0x674; pc0 = ra; +} + +static void bios_GetB0Table() { // 57 + + v0 = 0x874; pc0 = ra; +} + +/* System calls C0 */ + +/* + * int SysEnqIntRP(int index , long *queue); + */ + +static void bios_SysEnqIntRP() { // 02 + + SysIntRP[a0] = a1; + + v0 = 0; pc0 = ra; +} + +/* + * int SysDeqIntRP(int index , long *queue); + */ + +static void bios_SysDeqIntRP() { // 03 + + SysIntRP[a0] = 0; + + v0 = 0; pc0 = ra; +} + +static void bios_ChangeClearRCnt() { // 0a + u32 *ptr; + + ptr = (u32*)PSXM((a0 << 2) + 0x8600); + v0 = BFLIP32(*ptr); + *ptr = BFLIP32(a1); + +// psxRegs.CP0.n.Status|= 0x404; + pc0 = ra; +} + +static void bios_dummy() { + pc0 = ra; +} + +void (*biosA0[256])(); +void (*biosB0[256])(); +void (*biosC0[256])(); + +void psxBiosInit() { + u32 base, size; + u32 *ptr; + int i; + + heap_addr=0; + CurThread = 0; + jmp_int = NULL; + + for(i = 0; i < 256; i++) { + biosA0[i] = NULL; + biosB0[i] = NULL; + biosC0[i] = NULL; + } + + for(i = 0; i < 256; i++) { + if (biosA0[i] == NULL) biosA0[i] = bios_dummy; + if (biosB0[i] == NULL) biosB0[i] = bios_dummy; + if (biosC0[i] == NULL) biosC0[i] = bios_dummy; + } + + biosA0[0x0e] = bios_abs; + biosA0[0x0f] = bios_labs; + biosA0[0x10] = bios_atoi; + biosA0[0x11] = bios_atol; + //biosA0[0x12] = bios_atob; + biosA0[0x13] = bios_setjmp; + biosA0[0x14] = bios_longjmp; + + biosA0[0x15] = bios_strcat; + biosA0[0x16] = bios_strncat; + biosA0[0x17] = bios_strcmp; + biosA0[0x18] = bios_strncmp; + biosA0[0x19] = bios_strcpy; + biosA0[0x1a] = bios_strncpy; + biosA0[0x1b] = bios_strlen; + biosA0[0x1c] = bios_index; + biosA0[0x1d] = bios_rindex; + biosA0[0x1e] = bios_strchr; + biosA0[0x1f] = bios_strrchr; + biosA0[0x20] = bios_strpbrk; + biosA0[0x21] = bios_strspn; + biosA0[0x22] = bios_strcspn; + //biosA0[0x23] = bios_strtok; + biosA0[0x24] = bios_strstr; + biosA0[0x25] = bios_toupper; + biosA0[0x26] = bios_tolower; + biosA0[0x27] = bios_bcopy; + biosA0[0x28] = bios_bzero; + biosA0[0x29] = bios_bcmp; + biosA0[0x2a] = bios_memcpy; + biosA0[0x2b] = bios_memset; + //biosA0[0x2c] = bios_memmove; + biosA0[0x2c] = bios_memcpy; /* Our code should be compatible + with both memcpy and memmove + semantics. */ + biosA0[0x2d] = bios_memcmp; + biosA0[0x2e] = bios_memchr; + + biosA0[0x2f] = bios_rand; + biosA0[0x30] = bios_srand; + + //biosA0[0x31] = bios_qsort; + //biosA0[0x32] = bios_strtod; + biosA0[0x33] = bios_malloc; + //biosA0[0x34] = bios_free; + //biosA0[0x35] = bios_lsearch; + //biosA0[0x36] = bios_bsearch; + //biosA0[0x37] = bios_calloc; + //biosA0[0x38] = bios_realloc; + biosA0[0x39] = bios_InitHeap; + //biosA0[0x3a] = bios__exit; + biosA0[0x44] = bios_FlushCache; + //biosA0[0x45] = bios_InstallInterruptHandler; + //biosA0[0x4f] = bios_sys_a0_4f; + //biosA0[0x50] = bios_sys_a0_50; + biosA0[0x70] = bios__bu_init; + biosA0[0x71] = bios__96_init; + biosA0[0x72] = bios__96_remove; + //biosA0[0x73] = bios_sys_a0_73; + //biosA0[0x74] = bios_sys_a0_74; + //biosA0[0x75] = bios_sys_a0_75; + //biosA0[0x76] = bios_sys_a0_76; + //biosA0[0x77] = bios_sys_a0_77; + //biosA0[0x78] = bios__96_CdSeekL; + //biosA0[0x79] = bios_sys_a0_79; + //biosA0[0x7a] = bios_sys_a0_7a; + //biosA0[0x7b] = bios_sys_a0_7b; + //biosA0[0x7c] = bios__96_CdGetStatus; + //biosA0[0x7d] = bios_sys_a0_7d; + //biosA0[0x7e] = bios__96_CdRead; + //biosA0[0x7f] = bios_sys_a0_7f; + //biosA0[0x80] = bios_sys_a0_80; + //biosA0[0x81] = bios_sys_a0_81; + //biosA0[0x82] = bios_sys_a0_82; + //biosA0[0x83] = bios_sys_a0_83; + //biosA0[0x84] = bios_sys_a0_84; + //biosA0[0x85] = bios__96_CdStop; + //biosA0[0x86] = bios_sys_a0_86; + //biosA0[0x87] = bios_sys_a0_87; + //biosA0[0x88] = bios_sys_a0_88; + //biosA0[0x89] = bios_sys_a0_89; + //biosA0[0x8a] = bios_sys_a0_8a; + //biosA0[0x8b] = bios_sys_a0_8b; + //biosA0[0x8c] = bios_sys_a0_8c; + //biosA0[0x8d] = bios_sys_a0_8d; + //biosA0[0x8e] = bios_sys_a0_8e; + //biosA0[0x8f] = bios_sys_a0_8f; + //biosA0[0x90] = bios_sys_a0_90; + //biosA0[0x91] = bios_sys_a0_91; + //biosA0[0x92] = bios_sys_a0_92; + //biosA0[0x93] = bios_sys_a0_93; + //biosA0[0x94] = bios_sys_a0_94; + //biosA0[0x95] = bios_sys_a0_95; + //biosA0[0x96] = bios_AddCDROMDevice; + //biosA0[0x97] = bios_AddMemCardDevide; + //biosA0[0x98] = bios_DisableKernelIORedirection; + //biosA0[0x99] = bios_EnableKernelIORedirection; + //biosA0[0x9a] = bios_sys_a0_9a; + //biosA0[0x9b] = bios_sys_a0_9b; + //biosA0[0x9c] = bios_SetConf; + //biosA0[0x9d] = bios_GetConf; + //biosA0[0x9e] = bios_sys_a0_9e; + //biosA0[0x9f] = bios_SetMem; + //biosA0[0xa0] = bios__boot; + //biosA0[0xa1] = bios_SystemError; + //biosA0[0xa2] = bios_EnqueueCdIntr; + //biosA0[0xa3] = bios_DequeueCdIntr; + //biosA0[0xa4] = bios_sys_a0_a4; + //biosA0[0xa5] = bios_ReadSector; + //biosA0[0xa6] = bios_get_cd_status; + //biosA0[0xa7] = bios_bufs_cb_0; + //biosA0[0xa8] = bios_bufs_cb_1; + //biosA0[0xa9] = bios_bufs_cb_2; + //biosA0[0xaa] = bios_bufs_cb_3; + //biosA0[0xab] = bios__card_info; + //biosA0[0xac] = bios__card_load; + //biosA0[0axd] = bios__card_auto; + //biosA0[0xae] = bios_bufs_cd_4; + //biosA0[0xaf] = bios_sys_a0_af; + //biosA0[0xb0] = bios_sys_a0_b0; + //biosA0[0xb1] = bios_sys_a0_b1; + //biosA0[0xb2] = bios_do_a_long_jmp + //biosA0[0xb3] = bios_sys_a0_b3; + //biosA0[0xb4] = bios_sub_function; +//*******************B0 CALLS**************************** + //biosB0[0x00] = bios_SysMalloc; + //biosB0[0x01] = bios_sys_b0_01; + biosB0[0x02] = bios_SetRCnt; + biosB0[0x03] = bios_GetRCnt; + biosB0[0x04] = bios_StartRCnt; + biosB0[0x05] = bios_StopRCnt; + biosB0[0x06] = bios_ResetRCnt; + biosB0[0x07] = bios_DeliverEvent; + biosB0[0x08] = bios_OpenEvent; + biosB0[0x09] = bios_CloseEvent; + biosB0[0x0a] = bios_WaitEvent; + biosB0[0x0b] = bios_TestEvent; + biosB0[0x0c] = bios_EnableEvent; + biosB0[0x0d] = bios_DisableEvent; + biosB0[0x0e] = bios_OpenTh; + biosB0[0x0f] = bios_CloseTh; + biosB0[0x10] = bios_ChangeTh; + //biosB0[0x11] = bios_bios_b0_11; + biosB0[0x17] = bios_ReturnFromException; + biosB0[0x18] = bios_ResetEntryInt; + biosB0[0x19] = bios_HookEntryInt; + //biosB0[0x1a] = bios_sys_b0_1a; + //biosB0[0x1b] = bios_sys_b0_1b; + //biosB0[0x1c] = bios_sys_b0_1c; + //biosB0[0x1d] = bios_sys_b0_1d; + //biosB0[0x1e] = bios_sys_b0_1e; + //biosB0[0x1f] = bios_sys_b0_1f; + biosB0[0x20] = bios_UnDeliverEvent; + //biosB0[0x21] = bios_sys_b0_21; + //biosB0[0x22] = bios_sys_b0_22; + //biosB0[0x23] = bios_sys_b0_23; + //biosB0[0x24] = bios_sys_b0_24; + //biosB0[0x25] = bios_sys_b0_25; + //biosB0[0x26] = bios_sys_b0_26; + //biosB0[0x27] = bios_sys_b0_27; + //biosB0[0x28] = bios_sys_b0_28; + //biosB0[0x29] = bios_sys_b0_29; + //biosB0[0x2a] = bios_sys_b0_2a; + //biosB0[0x2b] = bios_sys_b0_2b; + //biosB0[0x2c] = bios_sys_b0_2c; + //biosB0[0x2d] = bios_sys_b0_2d; + //biosB0[0x2e] = bios_sys_b0_2e; + //biosB0[0x2f] = bios_sys_b0_2f; + //biosB0[0x30] = bios_sys_b0_30; + //biosB0[0x31] = bios_sys_b0_31; + biosB0[0x56] = bios_GetC0Table; + biosB0[0x57] = bios_GetB0Table; + //biosB0[0x58] = bios__card_chan; + //biosB0[0x59] = bios_sys_b0_59; + //biosB0[0x5a] = bios_sys_b0_5a; + //biosB0[0x5c] = bios__card_status; + //biosB0[0x5d] = bios__card_wait; +//*******************C0 CALLS**************************** + //biosC0[0x00] = bios_InitRCnt; + //biosC0[0x01] = bios_InitException; + biosC0[0x02] = bios_SysEnqIntRP; + biosC0[0x03] = bios_SysDeqIntRP; + //biosC0[0x04] = bios_get_free_EvCB_slot; + //biosC0[0x05] = bios_get_free_TCB_slot; + //biosC0[0x06] = bios_ExceptionHandler; + //biosC0[0x07] = bios_InstallExeptionHandler; + //biosC0[0x08] = bios_SysInitMemory; + //biosC0[0x09] = bios_SysInitKMem; + biosC0[0x0a] = bios_ChangeClearRCnt; + //biosC0[0x0b] = bios_SystemError; + //biosC0[0x0c] = bios_InitDefInt; + //biosC0[0x0d] = bios_sys_c0_0d; + //biosC0[0x0e] = bios_sys_c0_0e; + //biosC0[0x0f] = bios_sys_c0_0f; + //biosC0[0x10] = bios_sys_c0_10; + //biosC0[0x11] = bios_sys_c0_11; + //biosC0[0x12] = bios_InstallDevices; + //biosC0[0x13] = bios_FlushStfInOutPut; + //biosC0[0x14] = bios_sys_c0_14; + //biosC0[0x15] = bios__cdevinput; + //biosC0[0x16] = bios__cdevscan; + //biosC0[0x17] = bios__circgetc; + //biosC0[0x18] = bios__circputc; + //biosC0[0x19] = bios_ioabort; + //biosC0[0x1a] = bios_sys_c0_1a + //biosC0[0x1b] = bios_KernelRedirect; + //biosC0[0x1c] = bios_PatchAOTable; +//************** THE END *************************************** + + base = 0x1000; + size = sizeof(EvCB) * 32; + Event = (void *)&psxR[base]; base+= size*6; + memset(Event, 0, size * 6); + //HwEV = Event; + //EvEV = Event + 32; + RcEV = Event + 32*2; + //UeEV = Event + 32*3; + //SwEV = Event + 32*4; + //ThEV = Event + 32*5; + + ptr = (u32*)&psxM[0x0874]; // b0 table + ptr[0] = BFLIP32(0x4c54 - 0x884); + + ptr = (u32*)&psxM[0x0674]; // c0 table + ptr[6] = BFLIP32(0xc80); + + memset(SysIntRP, 0, sizeof(SysIntRP)); + memset(Thread, 0, sizeof(Thread)); + Thread[0].status = BFLIP32(2); // main thread + + psxMu32(0x0150) = BFLIP32(0x160); + psxMu32(0x0154) = BFLIP32(0x320); + psxMu32(0x0160) = BFLIP32(0x248); + strcpy(&psxM[0x248], "bu"); + +/* psxMu32(0x0ca8) = BFLIP32(0x1f410004); + psxMu32(0x0cf0) = BFLIP32(0x3c020000); + psxMu32(0x0cf4) = BFLIP32(0x2442641c); + psxMu32(0x09e0) = BFLIP32(0x43d0); + psxMu32(0x4d98) = BFLIP32(0x946f000a); +*/ + // opcode HLE + psxRu32(0x0000) = BFLIP32((0x3b << 26) | 4); + psxMu32(0x0000) = BFLIP32((0x3b << 26) | 0); + psxMu32(0x00a0) = BFLIP32((0x3b << 26) | 1); + psxMu32(0x00b0) = BFLIP32((0x3b << 26) | 2); + psxMu32(0x00c0) = BFLIP32((0x3b << 26) | 3); + psxMu32(0x4c54) = BFLIP32((0x3b << 26) | 0); + psxMu32(0x8000) = BFLIP32((0x3b << 26) | 5); + psxMu32(0x07a0) = BFLIP32((0x3b << 26) | 0); + psxMu32(0x0884) = BFLIP32((0x3b << 26) | 0); + psxMu32(0x0894) = BFLIP32((0x3b << 26) | 0); +} + +void psxBiosShutdown() { +} + +void biosInterrupt() { + if (BFLIP32(psxHu32(0x1070)) & 0x1) { // Vsync + if (RcEV[3][1].status == BFLIP32S(EvStACTIVE)) { + softCall(BFLIP32(RcEV[3][1].fhandler)); +// hwWrite32(0x1f801070, ~(1)); + } + } + + if (BFLIP32(psxHu32(0x1070)) & 0x70) { // Rcnt 0,1,2 + int i; + + for (i=0; i<3; i++) { + if (BFLIP32(psxHu32(0x1070)) & (1 << (i+4))) { + if (RcEV[i][1].status == BFLIP32S(EvStACTIVE)) { + softCall(BFLIP32(RcEV[i][1].fhandler)); + psxHwWrite32(0x1f801070, ~(1 << (i+4))); + } + } + } + } +} + +static INLINE void SaveRegs() { + memcpy(regs, psxRegs.GPR.r, 32*4); + regs[32] = psxRegs.GPR.n.lo; + regs[33] = psxRegs.GPR.n.hi; + regs[34] = psxRegs.pc; +} + +void psxBiosException() { + int i; + + switch (psxRegs.CP0.n.Cause & 0x3c) { + case 0x00: // Interrupt +#ifdef PSXCPU_LOG +// PSXCPU_LOG("interrupt\n"); +#endif + SaveRegs(); + + biosInterrupt(); + + for (i=0; i<8; i++) { + if (SysIntRP[i]) { + u32 *queue = (u32*)PSXM(SysIntRP[i]); + + s0 = BFLIP32(queue[2]); + softCall(BFLIP32(queue[1])); + } + } + + if (jmp_int != NULL) { + int i; + + psxHwWrite32(0x1f801070, 0xffffffff); + + ra = BFLIP32(jmp_int[0]); + sp = BFLIP32(jmp_int[1]); + fp = BFLIP32(jmp_int[2]); + for (i=0; i<8; i++) // s0-s7 + psxRegs.GPR.r[16+i] = BFLIP32(jmp_int[3+i]); + gp = BFLIP32(jmp_int[11]); + + v0 = 1; + pc0 = ra; + return; + } + psxHwWrite16(0x1f801070, 0); + break; + case 0x20: // Syscall +#ifdef PSXCPU_LOG +// PSXCPU_LOG("syscall exp %x\n", a0); +#endif + switch (a0) { + case 1: // EnterCritical - disable irq's + psxRegs.CP0.n.Status&=~0x404; break; + case 2: // ExitCritical - enable irq's + psxRegs.CP0.n.Status|= 0x404; break; + } + pc0 = psxRegs.CP0.n.EPC + 4; + + psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) | + ((psxRegs.CP0.n.Status & 0x3c) >> 2); + return; + default: +#ifdef PSXCPU_LOG + PSXCPU_LOG("unk exp\n"); +#endif + break; + } + + pc0 = psxRegs.CP0.n.EPC; + if (psxRegs.CP0.n.Cause & 0x80000000) pc0+=4; + + psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) | + ((psxRegs.CP0.n.Status & 0x3c) >> 2); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/PsxBios.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,34 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PSXBIOS_H__ +#define __PSXBIOS_H__ + +extern char *biosA0n[256]; +extern char *biosB0n[256]; +extern char *biosC0n[256]; + +void psxBiosInit(); +void psxBiosShutdown(); +void psxBiosException(); + +extern void (*biosA0[256])(); +extern void (*biosB0[256])(); +extern void (*biosC0[256])(); + +#endif /* __PSXBIOS_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/PsxCommon.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,59 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PSXCOMMON_H__ +#define __PSXCOMMON_H__ + +#if PSS_STYLE==2 + +#define PSS "\\" +#define PS '\\' + +#elif PSS_STYLE==1 + +#define PSS "/" +#define PS '/' + +#elif PSS_STYLE==3 + +#define PSS "\\" +#define PS '\\' +#endif + +#include <zlib.h> + +#include <sys/types.h> +#include "types.h" + +void __Log(char *fmt, ...); + +#define BIAS 2 +#define PSXCLK 33868800 /* 33.8688 Mhz */ + +#include "R3000A.h" +#include "PsxMem.h" +#include "PsxHw.h" +#include "PsxBios.h" +#include "PsxDma.h" +#include "PsxCounters.h" +#include "PsxHLE.h" +#include "Spu.h" +#include "Misc.h" +#include "spu/spu.h" + +#endif /* __PSXCOMMON_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/PsxCounters.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,247 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <string.h> + +#include "PsxCommon.h" + +static int cnts = 4; +static u32 last=0; + +static void psxRcntUpd(u32 index) { + psxCounters[index].sCycle = psxRegs.cycle; + if (((!(psxCounters[index].mode & 1)) || (index!=2)) && + psxCounters[index].mode & 0x30) { + if (psxCounters[index].mode & 0x10) { // Interrupt on target + psxCounters[index].Cycle = ((psxCounters[index].target - psxCounters[index].count) * psxCounters[index].rate) / BIAS; + } else { // Interrupt on 0xffff + psxCounters[index].Cycle = ((0xffff - psxCounters[index].count) * psxCounters[index].rate) / BIAS; + } + } else psxCounters[index].Cycle = 0xffffffff; +} + +static void psxRcntReset(u32 index) { + psxCounters[index].count = 0; + psxRcntUpd(index); + + psxHu32(0x1070)|= BFLIP32(psxCounters[index].interrupt); + if (!(psxCounters[index].mode & 0x40)) { // Only 1 interrupt + psxCounters[index].Cycle = 0xffffffff; + } +} + +static void psxRcntSet() { + int i; + + psxNextCounter = 0x7fffffff; + psxNextsCounter = psxRegs.cycle; + + for (i=0; i<cnts; i++) { + s32 count; + + if (psxCounters[i].Cycle == 0xffffffff) continue; + + count = psxCounters[i].Cycle - (psxRegs.cycle - psxCounters[i].sCycle); + + if (count < 0) { + psxNextCounter = 0; break; + } + + if (count < (s32)psxNextCounter) { + psxNextCounter = count; + } + } +} + +void psxRcntInit() { + + memset(psxCounters, 0, sizeof(psxCounters)); + + psxCounters[0].rate = 1; psxCounters[0].interrupt = 0x10; + psxCounters[1].rate = 1; psxCounters[1].interrupt = 0x20; + psxCounters[2].rate = 1; psxCounters[2].interrupt = 64; + + psxCounters[3].interrupt = 1; + psxCounters[3].mode = 0x58; // The VSync counter mode + psxCounters[3].target = 1; + psxUpdateVSyncRate(); + + cnts = 4; + + psxRcntUpd(0); psxRcntUpd(1); psxRcntUpd(2); psxRcntUpd(3); + psxRcntSet(); + last=0; +} + + +int CounterSPURun(void) +{ + u32 cycles; + + if(psxRegs.cycle<last) + { + cycles=0xFFFFFFFF-last; + cycles+=psxRegs.cycle; + } + else + cycles=psxRegs.cycle-last; + + if(cycles>=16) + { + if(!SPUasync(cycles)) return(0); + last=psxRegs.cycle; + } + return(1); +} + +/* Set by spu irq stuff in spu code to number of cpu cycles to back + up(if necessary). Very crazy hack. Eh, not implemented. Hmm. + TODO! +*/ +s32 spuirqvoodoo=-1; + +void CounterDeadLoopSkip() +{ + s32 min,x,lmin; + + lmin=0x7FFFFFFF; + + for(x=0;x<4;x++) + { + if (psxCounters[x].Cycle != 0xffffffff) + { + min=psxCounters[x].Cycle; + min-=(psxRegs.cycle - psxCounters[x].sCycle); + if(min<lmin) lmin=min; +// if(min<0) exit(); +// printf("Poo: %d, ",min); + } + } + + if(lmin>0) + { +// printf("skip %u\n",lmin); + psxRegs.cycle+=lmin; + } +} + +void psxUpdateVSyncRate() { + //if (Config.PsxType) // ntsc - 0 | pal - 1 + // psxCounters[3].rate = (PSXCLK / 50);// / BIAS; + //else + psxCounters[3].rate = (PSXCLK / 60);// / BIAS; +} + +void psxRcntUpdate() +{ + if ((psxRegs.cycle - psxCounters[3].sCycle) >= psxCounters[3].Cycle) { + //printf("%d\n",(psxRegs.cycle - psxCounters[3].sCycle)- psxCounters[3].Cycle); + psxRcntUpd(3); + psxHu32(0x1070)|= BFLIP32(1); + } + if ((psxRegs.cycle - psxCounters[0].sCycle) >= psxCounters[0].Cycle) { + psxRcntReset(0); + } + + if ((psxRegs.cycle - psxCounters[1].sCycle) >= psxCounters[1].Cycle) { + psxRcntReset(1); + } + + if ((psxRegs.cycle - psxCounters[2].sCycle) >= psxCounters[2].Cycle) { + psxRcntReset(2); + } + + psxRcntSet(); + +} + +void psxRcntWcount(u32 index, u32 value) { + psxCounters[index].count = value; + psxRcntUpd(index); + psxRcntSet(); +} + +void psxRcntWmode(u32 index, u32 value) { + psxCounters[index].mode = value; + psxCounters[index].count = 0; + + if(index == 0) { + switch (value & 0x300) { + case 0x100: + psxCounters[index].rate = ((psxCounters[3].rate /** BIAS*/) / 386) / 262; // seems ok + break; + default: + psxCounters[index].rate = 1; + } + } + else if(index == 1) { + switch (value & 0x300) { + case 0x100: + psxCounters[index].rate = (psxCounters[3].rate /** BIAS*/) / 262; // seems ok + //psxCounters[index].rate = (PSXCLK / 60)/262; //(psxCounters[3].rate*16/262); + //printf("%d\n",psxCounters[index].rate); + break; + default: + psxCounters[index].rate = 1; + } + } + else if(index == 2) { + switch (value & 0x300) { + case 0x200: + psxCounters[index].rate = 8; // 1/8 speed + break; + default: + psxCounters[index].rate = 1; // normal speed + } + } + + // Need to set a rate and target + psxRcntUpd(index); + psxRcntSet(); +} + +void psxRcntWtarget(u32 index, u32 value) { +// SysPrintf("writeCtarget[%ld] = %lx\n", index, value); + psxCounters[index].target = value; + psxRcntUpd(index); + psxRcntSet(); +} + +u32 psxRcntRcount(u32 index) { + u32 ret; + +// if ((!(psxCounters[index].mode & 1)) || (index!=2)) { + if (psxCounters[index].mode & 0x08) { // Wrap at target + //if (Config.RCntFix) { // Parasite Eve 2 + // ret = (psxCounters[index].count + /*BIAS **/ ((psxRegs.cycle - psxCounters[index].sCycle) / psxCounters[index].rate)) & 0xffff; + //} else { + ret = (psxCounters[index].count + BIAS * ((psxRegs.cycle - psxCounters[index].sCycle) / psxCounters[index].rate)) & 0xffff; + //} + } else { // Wrap at 0xffff + ret = (psxCounters[index].count + BIAS * (psxRegs.cycle / psxCounters[index].rate)) & 0xffff; + //if (Config.RCntFix) { // Vandal Hearts 1/2 + // ret/= 16; + //} + } +// return (psxCounters[index].count + BIAS * ((psxRegs.cycle - psxCounters[index].sCycle) / psxCounters[index].rate)) & 0xffff; +// } else return 0; + +// SysPrintf("readCcount[%ld] = %lx (mode %lx, target %lx, cycle %lx)\n", index, ret, psxCounters[index].mode, psxCounters[index].target, psxRegs.cycle); + + return ret; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/PsxCounters.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,43 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PSXCOUNTERS_H__ +#define __PSXCOUNTERS_H__ + +typedef struct { + u32 count, mode, target; + u32 sCycle, Cycle, rate, interrupt; +} psxCounter; + +psxCounter psxCounters[5]; + +u32 psxNextCounter, psxNextsCounter; + +void psxRcntInit(); +void psxRcntUpdate(); +void psxRcntWcount(u32 index, u32 value); +void psxRcntWmode(u32 index, u32 value); +void psxRcntWtarget(u32 index, u32 value); +u32 psxRcntRcount(u32 index); + +void psxUpdateVSyncRate(); + +int CounterSPURun(void); +void CounterDeadLoopSkip(); + +#endif /* __PSXCOUNTERS_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/PsxDma.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,59 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PsxCommon.h" + +void psxDma4(u32 madr, u32 bcr, u32 chcr) { // SPU + switch (chcr) { + case 0x01000201: //cpu to spu transfer + { + bcr= (bcr>>16) * (bcr&0xffff) * 2; + + //printf("%08x, %08x\n",madr,bcr); + SPUwriteDMAMem(madr, bcr); + } + break; + case 0x01000200: //spu to cpu transfer + { + //printf("%08x\n",madr); + SPUreadDMAMem (madr, (bcr >> 16) * (bcr & 0xffff) * 2); + } + break; + } +} + +void psxDma6(u32 madr, u32 bcr, u32 chcr) { + u32 *mem = (u32 *)PSXM(madr); + +#ifdef PSXDMA_LOG + PSXDMA_LOG("*** DMA 6 - OT *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); +#endif + + if (chcr == 0x11000002) { + while (bcr--) { + *mem-- = (madr - 4) & 0xffffff; + madr -= 4; + } + mem++; *mem = 0xffffff; + } else { + // Unknown option +#ifdef PSXDMA_LOG + PSXDMA_LOG("*** DMA 6 - OT unknown *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); +#endif + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/PsxDma.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,27 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PSXDMA_H__ +#define __PSXDMA_H__ + +void psxDma2(u32 madr, u32 bcr, u32 chcr); +void psxDma3(u32 madr, u32 bcr, u32 chcr); +void psxDma4(u32 madr, u32 bcr, u32 chcr); +void psxDma6(u32 madr, u32 bcr, u32 chcr); + +#endif /* __PSXDMA_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/PsxHLE.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,93 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "PsxCommon.h" + +static void hleDummy() { + psxRegs.pc = psxRegs.GPR.n.ra; + + psxBranchTest(); +} + +static void hleA0() { + u32 call = psxRegs.GPR.n.t1 & 0xff; + + if (biosA0[call]) biosA0[call](); + //else + // printf("Unknown A0: %08x\n",call); + psxBranchTest(); +} + +static void hleB0() { + u32 call = psxRegs.GPR.n.t1 & 0xff; + + if (biosB0[call]) biosB0[call](); + //else + // printf("Unknown B0: %08x\n",call); + + psxBranchTest(); +} + +static void hleC0() { + u32 call = psxRegs.GPR.n.t1 & 0xff; + + if (biosC0[call]) biosC0[call](); + //else + // printf("Unknown C0: %08x\n",call); + + psxBranchTest(); +} + +static void hleBootstrap() { // 0xbfc00000 + //SysPrintf("hleBootstrap\n"); +} + +typedef struct { + u32 _pc0; + u32 gp0; + u32 t_addr; + u32 t_size; + u32 d_addr; + u32 d_size; + u32 b_addr; + u32 b_size; + u32 S_addr; + u32 s_size; + u32 _sp,_fp,_gp,ret,base; +} PACKSTRUCT EXEC; + +static void hleExecRet() { + EXEC *header = (EXEC*)PSXM(psxRegs.GPR.n.s0); + + //SysPrintf("ExecRet %x: %x\n", psxRegs.GPR.n.s0, header->ret); + + psxRegs.GPR.n.ra = BFLIP32(header->ret); + psxRegs.GPR.n.sp = BFLIP32(header->_sp); + psxRegs.GPR.n.s8 = BFLIP32(header->_fp); + psxRegs.GPR.n.gp = BFLIP32(header->_gp); + psxRegs.GPR.n.s0 = BFLIP32(header->base); + + psxRegs.GPR.n.v0 = 1; + psxRegs.pc = psxRegs.GPR.n.ra; +} + +void (*psxHLEt[256])() = { + hleDummy, hleA0, hleB0, hleC0, + hleBootstrap, hleExecRet +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/PsxHLE.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,24 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PSXHLE_H__ +#define __PSXHLE_H__ + +extern void (*psxHLEt[256])(); + +#endif /* __PSXHLE_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/PsxHw.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,236 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> +#include <string.h> + +#include "PsxCommon.h" + +#define HW_DMA4_MADR (psxHu32(0x10c0)) // SPU DMA +#define HW_DMA4_BCR (psxHu32(0x10c4)) +#define HW_DMA4_CHCR (psxHu32(0x10c8)) + +#define HW_DMA_PCR (psxHu32(0x10f0)) +#define HW_DMA_ICR (psxHu32(0x10f4)) + +void psxHwReset() { + memset(psxH, 0, 0x10000); + psxRcntInit(); +} + +u8 psxHwRead8(u32 add) { + u8 hard; + + switch (add) { + default: + hard = psxHu8(add); + return hard; + } + return hard; +} + +u16 psxHwRead16(u32 add) { + u16 hard; + + switch (add) { + case 0x1f801100: + hard = psxRcntRcount(0); + return hard; + case 0x1f801104: + hard = psxCounters[0].mode; + return hard; + case 0x1f801108: + hard = psxCounters[0].target; + return hard; + case 0x1f801110: + hard = psxRcntRcount(1); + return hard; + case 0x1f801114: + hard = psxCounters[1].mode; + return hard; + case 0x1f801118: + hard = psxCounters[1].target; + return hard; + case 0x1f801120: + hard = psxRcntRcount(2); + return hard; + case 0x1f801124: + hard = psxCounters[2].mode; + return hard; + case 0x1f801128: + hard = psxCounters[2].target; + return hard; + + default: + if (add>=0x1f801c00 && add<0x1f801e00) { + hard = SPUreadRegister(add); + } else { + hard = BFLIP16(psxHu16(add)); + } + return hard; + } + return hard; +} + +u32 psxHwRead32(u32 add) { + u32 hard; + + switch (add) { + // time for rootcounters :) + case 0x1f801100: + hard = psxRcntRcount(0); + return hard; + case 0x1f801104: + hard = psxCounters[0].mode; + return hard; + case 0x1f801108: + hard = psxCounters[0].target; + return hard; + case 0x1f801110: + hard = psxRcntRcount(1); + return hard; + case 0x1f801114: + hard = psxCounters[1].mode; + return hard; + case 0x1f801118: + hard = psxCounters[1].target; + return hard; + case 0x1f801120: + hard = psxRcntRcount(2); + return hard; + case 0x1f801124: + hard = psxCounters[2].mode; + return hard; + case 0x1f801128: + hard = psxCounters[2].target; + return hard; + + default: + hard = BFLIP32(psxHu32(add)); + return hard; + } + return hard; +} + +void psxHwWrite8(u32 add, u8 value) { + switch (add) { + default: + psxHu8(add) = value; + return; + } + psxHu8(add) = value; +} + +void psxHwWrite16(u32 add, u16 value) { + switch (add) { + + case 0x1f801070: + psxHu16(0x1070) &= BFLIP16( BFLIP16(psxHu16(0x1074)) & value); + return; + case 0x1f801100: + psxRcntWcount(0, value); return; + case 0x1f801104: + psxRcntWmode(0, value); return; + case 0x1f801108: + psxRcntWtarget(0, value); return; + + case 0x1f801110: + psxRcntWcount(1, value); return; + case 0x1f801114: + psxRcntWmode(1, value); return; + case 0x1f801118: + psxRcntWtarget(1, value); return; + + case 0x1f801120: + psxRcntWcount(2, value); return; + case 0x1f801124: + psxRcntWmode(2, value); return; + case 0x1f801128: + psxRcntWtarget(2, value); return; + + default: + if (add>=0x1f801c00 && add<0x1f801e00) { + SPUwriteRegister(add, value); + return; + } + + psxHu16(add) = BFLIP16(value); + return; + } + psxHu16(add) = BFLIP16(value); +} + +#define DMA_INTERRUPT(n) \ + if (BFLIP32(HW_DMA_ICR) & (1 << (16 + n))) { \ + HW_DMA_ICR|= BFLIP32(1 << (24 + n)); \ + psxHu32(0x1070) |= BFLIP32(8); \ + } + +#define DmaExec(n) { \ + if (BFLIP32(HW_DMA##n##_CHCR) & 0x01000000 && BFLIP32(HW_DMA_PCR) & (8 << (n * 4))) { \ + psxDma##n(BFLIP32(HW_DMA##n##_MADR), BFLIP32(HW_DMA##n##_BCR), BFLIP32(HW_DMA##n##_CHCR)); \ + HW_DMA##n##_CHCR &= BFLIP32(~0x01000000); \ + DMA_INTERRUPT(n); \ + } \ +} + +void psxHwWrite32(u32 add, u32 value) { + switch (add) { + case 0x1f801070: + psxHu32(0x1070) &= BFLIP32(BFLIP32(psxHu32(0x1074)) & value); + return; + case 0x1f8010c8: + HW_DMA4_CHCR = BFLIP32(value); // DMA4 chcr (SPU DMA) + DmaExec(4); + return; + case 0x1f8010f4: + { + u32 tmp = (~value) & BFLIP32(HW_DMA_ICR); + HW_DMA_ICR = BFLIP32(((tmp ^ value) & 0xffffff) ^ tmp); + return; + } + + case 0x1f801100: + psxRcntWcount(0, value & 0xffff); return; + case 0x1f801104: + psxRcntWmode(0, value); return; + case 0x1f801108: + psxRcntWtarget(0, value & 0xffff); return; + // HW_DMA_ICR&= (~value)&0xff000000; + + case 0x1f801110: + psxRcntWcount(1, value & 0xffff); return; + case 0x1f801114: + psxRcntWmode(1, value); return; + case 0x1f801118: + psxRcntWtarget(1, value & 0xffff); return; + + case 0x1f801120: + psxRcntWcount(2, value & 0xffff); return; + case 0x1f801124: + psxRcntWmode(2, value); return; + case 0x1f801128: + psxRcntWtarget(2, value & 0xffff); return; + + default: + psxHu32(add) = BFLIP32(value); + return; + } + psxHu32(add) = BFLIP32(value); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/PsxHw.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,30 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PSXHW_H__ +#define __PSXHW_H__ + +void psxHwReset(); +u8 psxHwRead8 (u32 add); +u16 psxHwRead16(u32 add); +u32 psxHwRead32(u32 add); +void psxHwWrite8 (u32 add, u8 value); +void psxHwWrite16(u32 add, u16 value); +void psxHwWrite32(u32 add, u32 value); + +#endif /* __PSXHW_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/PsxInterpreter.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,747 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdlib.h> + +#include "PsxCommon.h" + +static int branch; +static int branch2; +static u32 branchPC; + +// These macros are used to assemble the repassembler functions + +// if(!PSXM(psxRegs.pc)) puts("Whoops"); +// Fix this... + +// printf("%08x ", psxRegs.pc); + +#define execI() { \ + psxRegs.code = BFLIP32(PSXMu32(psxRegs.pc)); \ + \ + psxRegs.pc+= 4; psxRegs.cycle++; \ + psxBSC[psxRegs.code >> 26](); \ +} + +// Subsets +static void (*psxBSC[64])(); +static void (*psxSPC[64])(); +static void (*psxREG[32])(); +static void (*psxCP0[32])(); + +static void delayRead(int reg, u32 bpc) { + u32 rold, rnew; + +// SysPrintf("delayRead at %x!\n", psxRegs.pc); + + rold = psxRegs.GPR.r[reg]; + psxBSC[psxRegs.code >> 26](); // branch delay load + rnew = psxRegs.GPR.r[reg]; + + psxRegs.pc = bpc; + + psxBranchTest(); + + psxRegs.GPR.r[reg] = rold; + execI(); // first branch opcode + psxRegs.GPR.r[reg] = rnew; + + branch = 0; +} + +static void delayWrite(int reg, u32 bpc) { + +/* SysPrintf("delayWrite at %x!\n", psxRegs.pc); + +// SysPrintf("%s\n", disR3000AF(psxRegs.code, psxRegs.pc-4)); +// SysPrintf("%s\n", disR3000AF(PSXMu32(bpc), bpc));*/ + + // no changes from normal behavior + + psxBSC[psxRegs.code >> 26](); + + branch = 0; + psxRegs.pc = bpc; + + psxBranchTest(); +} + +static void delayReadWrite(int reg, u32 bpc) { + +// SysPrintf("delayReadWrite at %x!\n", psxRegs.pc); + + // the branch delay load is skipped + + branch = 0; + psxRegs.pc = bpc; + + psxBranchTest(); +} + +// this defines shall be used with the tmp +// of the next func (instead of _Funct_...) +#define _tFunct_ ((tmp ) & 0x3F) // The funct part of the instruction register +#define _tRd_ ((tmp >> 11) & 0x1F) // The rd part of the instruction register +#define _tRt_ ((tmp >> 16) & 0x1F) // The rt part of the instruction register +#define _tRs_ ((tmp >> 21) & 0x1F) // The rs part of the instruction register +#define _tSa_ ((tmp >> 6) & 0x1F) // The sa part of the instruction register + +static void psxDelayTest(u32 reg, u32 bpc) { + u32 tmp; + + tmp = BFLIP32(PSXMu32(bpc)); + branch = 1; + + switch (tmp >> 26) { + case 0x00: // SPECIAL + switch (_tFunct_) { + case 0x00: // SLL + if (!tmp) break; // NOP + case 0x02: case 0x03: // SRL/SRA + if (_tRd_ == reg && _tRt_ == reg) { + delayReadWrite(reg, bpc); return; + } else if (_tRt_ == reg) { + delayRead(reg, bpc); return; + } else if (_tRd_ == reg) { + delayWrite(reg, bpc); return; + } + break; + + case 0x08: // JR + if (_tRs_ == reg) { + delayRead(reg, bpc); return; + } + break; + case 0x09: // JALR + if (_tRd_ == reg && _tRs_ == reg) { + delayReadWrite(reg, bpc); return; + } else if (_tRs_ == reg) { + delayRead(reg, bpc); return; + } else if (_tRd_ == reg) { + delayWrite(reg, bpc); return; + } + break; + + // SYSCALL/BREAK just a break; + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x2a: case 0x2b: // ADD/ADDU... + case 0x04: case 0x06: case 0x07: // SLLV... + if (_tRd_ == reg && (_tRt_ == reg || _tRs_ == reg)) { + delayReadWrite(reg, bpc); return; + } else if (_tRt_ == reg || _tRs_ == reg) { + delayRead(reg, bpc); return; + } else if (_tRd_ == reg) { + delayWrite(reg, bpc); return; + } + break; + + case 0x10: case 0x12: // MFHI/MFLO + if (_tRd_ == reg) { + delayWrite(reg, bpc); return; + } + break; + case 0x11: case 0x13: // MTHI/MTLO + if (_tRs_ == reg) { + delayRead(reg, bpc); return; + } + break; + + case 0x18: case 0x19: + case 0x1a: case 0x1b: // MULT/DIV... + if (_tRt_ == reg || _tRs_ == reg) { + delayRead(reg, bpc); return; + } + break; + } + break; + + case 0x01: // REGIMM + switch (_tRt_) { + case 0x00: case 0x02: + case 0x10: case 0x12: // BLTZ/BGEZ... + if (_tRs_ == reg) { + delayRead(reg, bpc); return; + } + break; + } + break; + + // J would be just a break; + case 0x03: // JAL + if (31 == reg) { + delayWrite(reg, bpc); return; + } + break; + + case 0x04: case 0x05: // BEQ/BNE + if (_tRs_ == reg || _tRt_ == reg) { + delayRead(reg, bpc); return; + } + break; + + case 0x06: case 0x07: // BLEZ/BGTZ + if (_tRs_ == reg) { + delayRead(reg, bpc); return; + } + break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: // ADDI/ADDIU... + if (_tRt_ == reg && _tRs_ == reg) { + delayReadWrite(reg, bpc); return; + } else if (_tRs_ == reg) { + delayRead(reg, bpc); return; + } else if (_tRt_ == reg) { + delayWrite(reg, bpc); return; + } + break; + + case 0x0f: // LUI + if (_tRt_ == reg) { + delayWrite(reg, bpc); return; + } + break; + + case 0x10: // COP0 + switch (_tFunct_) { + case 0x00: // MFC0 + if (_tRt_ == reg) { delayWrite(reg, bpc); return; } + break; + case 0x02: // CFC0 + if (_tRt_ == reg) { delayWrite(reg, bpc); return; } + break; + case 0x04: // MTC0 + if (_tRt_ == reg) { delayRead(reg, bpc); return; } + break; + case 0x06: // CTC0 + if (_tRt_ == reg) { delayRead(reg, bpc); return; } + break; + // RFE just a break; + } + break; + + case 0x22: case 0x26: // LWL/LWR + if (_tRt_ == reg) { + delayReadWrite(reg, bpc); return; + } else if (_tRs_ == reg) { + delayRead(reg, bpc); return; + } + break; + + case 0x20: case 0x21: case 0x23: + case 0x24: case 0x25: // LB/LH/LW/LBU/LHU + if (_tRt_ == reg && _tRs_ == reg) { + delayReadWrite(reg, bpc); return; + } else if (_tRs_ == reg) { + delayRead(reg, bpc); return; + } else if (_tRt_ == reg) { + delayWrite(reg, bpc); return; + } + break; + + case 0x28: case 0x29: case 0x2a: + case 0x2b: case 0x2e: // SB/SH/SWL/SW/SWR + if (_tRt_ == reg || _tRs_ == reg) { + delayRead(reg, bpc); return; + } + break; + + case 0x32: case 0x3a: // LWC2/SWC2 + if (_tRs_ == reg) { + delayRead(reg, bpc); return; + } + break; + } + psxBSC[psxRegs.code >> 26](); + + branch = 0; + psxRegs.pc = bpc; + + psxBranchTest(); +} + +static void psxNULL(void); + +static INLINE void doBranch(u32 tar) { + u32 tmp; + + branch2 = branch = 1; + branchPC = tar; + + psxRegs.code = BFLIP32(PSXMu32(psxRegs.pc)); + + psxRegs.pc+= 4; psxRegs.cycle++; + + // check for load delay + tmp = psxRegs.code >> 26; + switch (tmp) { + case 0x10: // COP0 + switch (_Rs_) { + case 0x00: // MFC0 + case 0x02: // CFC0 + psxDelayTest(_Rt_, branchPC); + return; + } + break; + case 0x32: // LWC2 + psxDelayTest(_Rt_, branchPC); + return; + default: + if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR + psxDelayTest(_Rt_, branchPC); + return; + } + break; + } + + psxBSC[psxRegs.code >> 26](); + + if((psxRegs.pc-8)==branchPC && !(psxRegs.code>>26)) + { + //printf("%08x\n",psxRegs.code>>26); + CounterDeadLoopSkip(); + } + branch = 0; + psxRegs.pc = branchPC; + + psxBranchTest(); +} + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ +static void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow) +static void psxADDIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im +static void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im +static void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im +static void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im +static void psxSLTI() { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed) +static void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < ((u32)_ImmU_); } // Rt = Rs < Im (Unsigned) + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ +static void psxADD() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow) +static void psxADDU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt +static void psxSUB() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow) +static void psxSUBU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt +static void psxAND() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt +static void psxOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt +static void psxXOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt +static void psxNOR() { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt +static void psxSLT() { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed) +static void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned) + +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ +static void psxDIV() { + if (_i32(_rRt_) != 0) { + _rLo_ = _i32(_rRs_) / _i32(_rRt_); + _rHi_ = _i32(_rRs_) % _i32(_rRt_); + } +} + +static void psxDIVU() { + if (_rRt_ != 0) { + _rLo_ = _rRs_ / _rRt_; + _rHi_ = _rRs_ % _rRt_; + } +} + +static void psxMULT() { + u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_)); + + psxRegs.GPR.n.lo = (u32)(res & 0xffffffff); + psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff); +} + +static void psxMULTU() { + u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_)); + + psxRegs.GPR.n.lo = (u32)(res & 0xffffffff); + psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff); +} + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ +#define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_); +#define RepZBranchLinki32(op) if(_i32(_rRs_) op 0) { _SetLink(31); doBranch(_BranchTarget_); } + +static void psxBGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0 +static void psxBGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link +static void psxBGTZ() { RepZBranchi32(>) } // Branch if Rs > 0 +static void psxBLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0 +static void psxBLTZ() { RepZBranchi32(<) } // Branch if Rs < 0 +static void psxBLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +static void psxSLL() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa +static void psxSRA() { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic) +static void psxSRL() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical) + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ +static void psxSLLV() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) << _u32(_rRs_); } // Rd = Rt << rs +static void psxSRAV() { if (!_Rd_) return; _rRd_ = _i32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (arithmetic) +static void psxSRLV() { if (!_Rd_) return; _rRd_ = _u32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (logical) + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ +static void psxLUI() { if (!_Rt_) return; _rRt_ = psxRegs.code << 16; } // Upper halfword of Rt = Im + +/********************************************************* +* Move from HI/LO to GPR * +* Format: OP rd * +*********************************************************/ +static void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi +static void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo + +/********************************************************* +* Move to GPR to HI/LO & Register jump * +* Format: OP rs * +*********************************************************/ +static void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs +static void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs + +/********************************************************* +* Special purpose instructions * +* Format: OP * +*********************************************************/ +static void psxBREAK() { + // Break exception - psx rom doens't handles this +} + +static void psxSYSCALL() { + psxRegs.pc -= 4; + psxException(0x20, branch); +} + +static void psxRFE() { + psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) | + ((psxRegs.CP0.n.Status & 0x3c) >> 2); +} + +/********************************************************* +* Register branch logic * +* Format: OP rs, rt, offset * +*********************************************************/ +#define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) { doBranch(_BranchTarget_); } + +static void psxBEQ() { RepBranchi32(==) } // Branch if Rs == Rt +static void psxBNE() { RepBranchi32(!=) } // Branch if Rs != Rt + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ +static void psxJ() { doBranch(_JumpTarget_); } +static void psxJAL() { _SetLink(31); doBranch(_JumpTarget_); } + +/********************************************************* +* Register jump * +* Format: OP rs, rd * +*********************************************************/ +static void psxJR() { doBranch(_u32(_rRs_)); } +static void psxJALR() { if (_Rd_) { _SetLink(_Rd_); } doBranch(_u32(_rRs_)); } + +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ + +#define _oB_ (_u32(_rRs_) + _Imm_) + +static void psxLB() { + if (_Rt_) { + _rRt_ = (s8)psxMemRead8(_oB_); + } else { + psxMemRead8(_oB_); + } +} + +static void psxLBU() { + if (_Rt_) { + _rRt_ = psxMemRead8(_oB_); + } else { + psxMemRead8(_oB_); + } +} + +static void psxLH() { + if (_Rt_) { + _rRt_ = (s16)psxMemRead16(_oB_); + } else { + psxMemRead16(_oB_); + } +} + +static void psxLHU() { + if (_Rt_) { + _rRt_ = psxMemRead16(_oB_); + } else { + psxMemRead16(_oB_); + } +} + +static void psxLW() { + if (_Rt_) { + _rRt_ = psxMemRead32(_oB_); + } else { + psxMemRead32(_oB_); + } +} + +static u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 }; +static u32 LWL_SHIFT[4] = { 24, 16, 8, 0 }; + +static void psxLWL() { + u32 addr = _oB_; + u32 shift = addr & 3; + u32 mem = psxMemRead32(addr & ~3); + + if (!_Rt_) return; + _rRt_ = ( _u32(_rRt_) & LWL_MASK[shift]) | + ( mem << LWL_SHIFT[shift]); + + /* + Mem = 1234. Reg = abcd + + 0 4bcd (mem << 24) | (reg & 0x00ffffff) + 1 34cd (mem << 16) | (reg & 0x0000ffff) + 2 234d (mem << 8) | (reg & 0x000000ff) + 3 1234 (mem ) | (reg & 0x00000000) + */ +} + +static u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 }; +static u32 LWR_SHIFT[4] = { 0, 8, 16, 24 }; + +static void psxLWR() { + u32 addr = _oB_; + u32 shift = addr & 3; + u32 mem = psxMemRead32(addr & ~3); + + if (!_Rt_) return; + _rRt_ = ( _u32(_rRt_) & LWR_MASK[shift]) | + ( mem >> LWR_SHIFT[shift]); + + /* + Mem = 1234. Reg = abcd + + 0 1234 (mem ) | (reg & 0x00000000) + 1 a123 (mem >> 8) | (reg & 0xff000000) + 2 ab12 (mem >> 16) | (reg & 0xffff0000) + 3 abc1 (mem >> 24) | (reg & 0xffffff00) + */ +} + +static void psxSB() { psxMemWrite8 (_oB_, _u8 (_rRt_)); } +static void psxSH() { psxMemWrite16(_oB_, _u16(_rRt_)); } +static void psxSW() { psxMemWrite32(_oB_, _u32(_rRt_)); } + +static const u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 }; +static const u32 SWL_SHIFT[4] = { 24, 16, 8, 0 }; + +static void psxSWL() { + u32 addr = _oB_; + u32 shift = addr & 3; + u32 mem = psxMemRead32(addr & ~3); + + psxMemWrite32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) | + ( mem & SWL_MASK[shift]) ); + /* + Mem = 1234. Reg = abcd + + 0 123a (reg >> 24) | (mem & 0xffffff00) + 1 12ab (reg >> 16) | (mem & 0xffff0000) + 2 1abc (reg >> 8) | (mem & 0xff000000) + 3 abcd (reg ) | (mem & 0x00000000) + */ +} + +static const u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff }; +static const u32 SWR_SHIFT[4] = { 0, 8, 16, 24 }; + +static void psxSWR() { + u32 addr = _oB_; + u32 shift = addr & 3; + u32 mem = psxMemRead32(addr & ~3); + + psxMemWrite32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) | + ( mem & SWR_MASK[shift]) ); + + /* + Mem = 1234. Reg = abcd + + 0 abcd (reg ) | (mem & 0x00000000) + 1 bcd4 (reg << 8) | (mem & 0x000000ff) + 2 cd34 (reg << 16) | (mem & 0x0000ffff) + 3 d234 (reg << 24) | (mem & 0x00ffffff) + */ +} + +/********************************************************* +* Moves between GPR and COPx * +* Format: OP rt, fs * +*********************************************************/ +static void psxMFC0() { if (!_Rt_) return; _rRt_ = (int)_rFs_; } +static void psxCFC0() { if (!_Rt_) return; _rRt_ = (int)_rFs_; } + +static INLINE void MTC0(int reg, u32 val) { + switch (reg) { + case 13: // Cause + psxRegs.CP0.n.Cause = val & ~(0xfc00); + + // the next code is untested, if u know please + // tell me if it works ok or not (linuzappz) + if (psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x0300 && + psxRegs.CP0.n.Status & 0x1) { + psxException(psxRegs.CP0.n.Cause, 0); + } + break; + + default: + psxRegs.CP0.r[reg] = val; + break; + } +} + +static void psxMTC0() { MTC0(_Rd_, _u32(_rRt_)); } +static void psxCTC0() { MTC0(_Rd_, _u32(_rRt_)); } + +/********************************************************* +* Unknow instruction (would generate an exception) * +* Format: ? * +*********************************************************/ +static void psxNULL() { +#ifdef PSXCPU_LOG + PSXCPU_LOG("psx: Unimplemented op %x\n", psxRegs.code); +#endif +} + +static void psxSPECIAL() { + psxSPC[_Funct_](); +} + +static void psxREGIMM() { + psxREG[_Rt_](); +} + +static void psxCOP0() { + psxCP0[_Rs_](); +} + +static void psxHLE() { + psxHLEt[psxRegs.code & 0xff](); +} + +static void (*psxBSC[64])() = { + psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ, + psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI , + psxCOP0 , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, + psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL, + psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxHLE , psxNULL, psxNULL, psxNULL, psxNULL +}; + + +static void (*psxSPC[64])() = { + psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV, + psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL, + psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL, + psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL, + psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR , + psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL, + psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL, + psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL +}; + +static void (*psxREG[32])() = { + psxBLTZ , psxBGEZ , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxBLTZAL, psxBGEZAL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL +}; + +static void (*psxCP0[32])() = { + psxMFC0, psxNULL, psxCFC0, psxNULL, psxMTC0, psxNULL, psxCTC0, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxRFE , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL +}; + + +/////////////////////////////////////////// + +static int intInit() { + return 0; +} + +static void intReset() { + branch=branch2=0; +} + +static void intExecute() { + for (;;) + { + if(!CounterSPURun()) + { + psxShutdown(); + return; + } + SPUendflush(); + execI(); + } +} + +static void intExecuteBlock() { + branch2 = 0; + while (!branch2) execI(); +} + +static void intClear(u32 Addr, u32 Size) { +} + +static void intShutdown() { +} + +R3000Acpu psxInt = { + intInit, + intReset, + intExecute, + intExecuteBlock, + intClear, + intShutdown +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/PsxMem.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,248 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <string.h> +#include <stdlib.h> + +#include "PsxCommon.h" + +void LoadPSXMem(u32 address, s32 length, unsigned char *data) +{ + //printf("%08x %08x\n",address,length); + while(length>0) + { + if(address&65535) + { + u32 tmplen; + + //puts("Squishy"); + tmplen=((65536-(address&65535))>(u32)length)?(u32)length:65536-(address&65535); + if(psxMemLUT[address>>16]) + memcpy((char *)(psxMemLUT[address>>16]+(address&65535)),data,tmplen); + address+=tmplen; + data+=tmplen; + length-=tmplen; + //printf("%08x %08x\n",address,tmplen); + continue; + } + if(psxMemLUT[address>>16]) + { + memcpy((char *)(psxMemLUT[address>>16]),data,(length<65536)?length:65536); + } + data+=65536; + address+=65536; + length-=65536; + } +} + +static int writeok; +int psxMemInit() { + int i; + + writeok=1; + + psxMemLUT = malloc(0x10000 * sizeof *psxMemLUT); + memset(psxMemLUT, 0, 0x10000 * sizeof *psxMemLUT); + + psxM = (char*)malloc(0x00200000); + psxP = (char*)malloc(0x00010000); + psxH = (char*)malloc(0x00010000); + psxR = (char*)malloc(0x00080000); + if (psxMemLUT == NULL || psxM == NULL || psxP == NULL || psxH == NULL || psxR == NULL) { + printf("Error allocating memory"); return -1; + } + + for (i=0; i<0x80; i++) psxMemLUT[i + 0x0000] = &psxM[(i & 0x1f) << 16]; + + memcpy(psxMemLUT + 0x8000, psxMemLUT, 0x80 * sizeof *psxMemLUT); + memcpy(psxMemLUT + 0xa000, psxMemLUT, 0x80 * sizeof *psxMemLUT); + + for (i=0; i<0x01; i++) psxMemLUT[i + 0x1f00] = &psxP[i << 16]; + + for (i=0; i<0x01; i++) psxMemLUT[i + 0x1f80] = &psxH[i << 16]; + + for (i=0; i<0x08; i++) psxMemLUT[i + 0xbfc0] = &psxR[i << 16]; + + return 0; +} + +void psxMemReset() { + memset(psxM, 0, 0x00200000); + memset(psxP, 0, 0x00010000); +} + +void psxMemShutdown() { + if (psxM) + free(psxM); + + if (psxP) + free(psxP); + + if (psxH) + free(psxH); + + if (psxR) + free(psxR); + + if (psxMemLUT) + free(psxMemLUT); + + psxM = psxP = psxH = psxR = NULL; + psxMemLUT = NULL; +} + +u8 psxMemRead8(u32 mem) { + char *p; + u32 t; + + t = mem >> 16; + if (t == 0x1f80) { + if (mem < 0x1f801000) + return psxHu8(mem); + else + return psxHwRead8(mem); + } else { + p = (char *)(psxMemLUT[t]); + if (p != NULL) { + return *(u8 *)(p + (mem & 0xffff)); + } else { + return 0; + } + } +} + +u16 psxMemRead16(u32 mem) { + char *p; + u32 t; + + t = mem >> 16; + if (t == 0x1f80) { + if (mem < 0x1f801000) + return BFLIP16(psxHu16(mem)); + else + return psxHwRead16(mem); + } else { + p = (char *)(psxMemLUT[t]); + if (p != NULL) { + return BFLIP16(*(u16 *)(p + (mem & 0xffff))); + } else { + return 0; + } + } +} + +u32 psxMemRead32(u32 mem) { + char *p; + u32 t; + + t = mem >> 16; + if (t == 0x1f80) { + if (mem < 0x1f801000) + return BFLIP32(psxHu32(mem)); + else + return psxHwRead32(mem); + } else { + p = (char *)(psxMemLUT[t]); + if (p != NULL) { + return BFLIP32(*(u32 *)(p + (mem & 0xffff))); + } else { + return 0; + } + } +} + +void psxMemWrite8(u32 mem, u8 value) { + char *p; + u32 t; + + t = mem >> 16; + if (t == 0x1f80) { + if (mem < 0x1f801000) + psxHu8(mem) = value; + else + psxHwWrite8(mem, value); + } else { + p = (char *)(psxMemLUT[t]); + if (p != NULL) { + *(u8 *)(p + (mem & 0xffff)) = value; + } + } +} + +void psxMemWrite16(u32 mem, u16 value) { + char *p; + u32 t; + + t = mem >> 16; + if (t == 0x1f80) { + if (mem < 0x1f801000) + psxHu16(mem) = BFLIP16(value); + else + psxHwWrite16(mem, value); + } else { + p = (char *)(psxMemLUT[t]); + if (p != NULL) { + *(u16 *)(p + (mem & 0xffff)) = BFLIP16(value); + } + } +} + +void psxMemWrite32(u32 mem, u32 value) { + char *p; + u32 t; + +// if ((mem&0x1fffff) == 0x71E18 || value == 0x48088800) SysPrintf("t2fix!!\n"); + t = mem >> 16; + if (t == 0x1f80) { + if (mem < 0x1f801000) + psxHu32(mem) = BFLIP32(value); + else + psxHwWrite32(mem, value); + } else { + p = (char *)(psxMemLUT[t]); + if (p != NULL) { + *(u32 *)(p + (mem & 0xffff)) = BFLIP32(value); + } else { + if (mem != 0xfffe0130) { + + } else { + int i; + + switch (value) { + case 0x800: case 0x804: + if (writeok == 0) break; + writeok = 0; + memset(psxMemLUT + 0x0000, 0, 0x80 * sizeof *psxMemLUT); + memset(psxMemLUT + 0x8000, 0, 0x80 * sizeof *psxMemLUT); + memset(psxMemLUT + 0xa000, 0, 0x80 * sizeof *psxMemLUT); + break; + case 0x1e988: + if (writeok == 1) break; + writeok = 1; + for (i=0; i<0x80; i++) psxMemLUT[i + 0x0000] = &psxM[(i & 0x1f) << 16]; + memcpy(psxMemLUT + 0x8000, psxMemLUT, 0x80 * sizeof *psxMemLUT); + memcpy(psxMemLUT + 0xa000, psxMemLUT, 0x80 * sizeof *psxMemLUT); + break; + default: + break; + } + } + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/PsxMem.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,87 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PSXMEMORY_H__ +#define __PSXMEMORY_H__ + +#ifdef MSB_FIRST +static INLINE u16 BFLIP16(u16 x) +{ + return( ((x>>8)&0xFF)| ((x&0xFF)<<8) ); +} + +static INLINE u32 BFLIP32(u32 x) +{ + return ( ((x>>24)&0xFF) | ((x>>8)&0xFF00) | ((x<<8)&0xFF0000) | ((x<<24)&0xFF000000) ); +} +#else +static INLINE u16 BFLIP16(u16 x) +{ + return x; +} + +static INLINE u32 BFLIP32(u32 x) +{ + return x; +} +#endif + +static INLINE s32 BFLIP32S(s32 x) +{ return (s32)BFLIP32((u32)x); } + +static INLINE s16 BFLIP16S(s16 x) +{ return (s16)BFLIP16((u16)x); } + +char *psxM; +#define psxMu32(mem) (*(u32*)&psxM[(mem) & 0x1fffff]) + +char *psxP; +char *psxR; +#define psxRu32(mem) (*(u32*)&psxR[(mem) & 0x7ffff]) + +char *psxH; + +#define psxHu8(mem) (*(u8*) &psxH[(mem) & 0xffff]) + +#define psxHu16(mem) (*(u16*)&psxH[(mem) & 0xffff]) +#define psxHu32(mem) (*(u32*)&psxH[(mem) & 0xffff]) + +char **psxMemLUT; + +#define PSXM(mem) (psxMemLUT[(mem) >> 16] == 0 ? NULL : (void*)(psxMemLUT[(mem) >> 16] + ((mem) & 0xffff))) + +#define PSXMu8(mem) (*(u8 *)PSXM(mem)) +#define PSXMu32(mem) (*(u32*)PSXM(mem)) + +#define PSXMuR8(mem) (PSXM(mem)?PSXMu8(mem):0) +#define PSXMuW8(mem,val) (PSXM(mem)?PSXMu8(mem)=val:;) + +int psxMemInit(); +void psxMemReset(); +void psxMemShutdown(); + +u8 psxMemRead8 (u32 mem); +u16 psxMemRead16(u32 mem); +u32 psxMemRead32(u32 mem); +void psxMemWrite8 (u32 mem, u8 value); +void psxMemWrite16(u32 mem, u16 value); +void psxMemWrite32(u32 mem, u32 value); + +void LoadPSXMem(u32 address, s32 length, unsigned char *data); + +#endif /* __PSXMEMORY_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/R3000A.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,97 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "PsxCommon.h" + +int psxInit() { + + psxCpu = &psxInt; + + if (psxMemInit() == -1) return -1; + + return psxCpu->Init(); +} + +void psxReset() { + psxCpu->Reset(); + psxMemReset(); + + memset(&psxRegs, 0, sizeof(psxRegs)); + + psxRegs.pc = 0xbfc00000; // Start in bootstrap + psxRegs.CP0.r[12] = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1 + psxRegs.CP0.r[15] = 0x00000002; // PRevID = Revision ID, same as R3000A + + psxHwReset(); + psxBiosInit(); +} + +void psxShutdown() { + psxMemShutdown(); + psxBiosShutdown(); + + psxCpu->Shutdown(); + SPUclose(); +} + +void psxException(u32 code, u32 bd) { + // Set the Cause + psxRegs.CP0.n.Cause = code; + +#ifdef PSXCPU_LOG + if (bd) PSXCPU_LOG("bd set\n"); +#endif + // Set the EPC & PC + if (bd) { + psxRegs.CP0.n.Cause|= 0x80000000; + psxRegs.CP0.n.EPC = (psxRegs.pc - 4); + } else + psxRegs.CP0.n.EPC = (psxRegs.pc); + + if (psxRegs.CP0.n.Status & 0x400000) + psxRegs.pc = 0xbfc00180; + else + psxRegs.pc = 0x80000080; + + // Set the Status + psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status &~0x3f) | + ((psxRegs.CP0.n.Status & 0xf) << 2); + + psxBiosException(); +} + +void psxBranchTest() { + if ((psxRegs.cycle - psxNextsCounter) >= psxNextCounter) + psxRcntUpdate(); + + if (psxHu32(0x1070) & psxHu32(0x1074)) { + if ((psxRegs.CP0.n.Status & 0x401) == 0x401) { + psxException(0x400, 0); + } + } + +} +void psxExecuteBios() { + while (psxRegs.pc != 0x80030000) + psxCpu->ExecuteBlock(); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/R3000A.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,122 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __R3000A_H__ +#define __R3000A_H__ + +#include <stdio.h> + +#include "PsxCommon.h" + +typedef struct { + int (*Init)(); + void (*Reset)(); + void (*Execute)(); /* executes up to a break */ + void (*ExecuteBlock)(); /* executes up to a jump */ + void (*Clear)(u32 Addr, u32 Size); + void (*Shutdown)(); +} R3000Acpu; + +R3000Acpu *psxCpu; +extern R3000Acpu psxInt; + +typedef union { + struct { + u32 r0, at, v0, v1, a0, a1, a2, a3, + t0, t1, t2, t3, t4, t5, t6, t7, + s0, s1, s2, s3, s4, s5, s6, s7, + t8, t9, k0, k1, gp, sp, s8, ra, lo, hi; + } n PACKSTRUCT; + u32 r[34]; /* Lo, Hi in r[33] and r[34] */ +} psxGPRRegs; + +typedef union { + struct { + u32 Index, Random, EntryLo0, EntryLo1, + Context, PageMask, Wired, Reserved0, + BadVAddr, Count, EntryHi, Compare, + Status, Cause, EPC, PRid, + Config, LLAddr, WatchLO, WatchHI, + XContext, Reserved1, Reserved2, Reserved3, + Reserved4, Reserved5, ECC, CacheErr, + TagLo, TagHi, ErrorEPC, Reserved6; + } n PACKSTRUCT; + u32 r[32]; +} psxCP0Regs; + +typedef struct { + psxGPRRegs GPR; /* General Purpose Registers */ + psxCP0Regs CP0; /* Coprocessor0 Registers */ + u32 pc; /* Program counter */ + u32 code; /* The instruction */ + u32 cycle; + u32 interrupt; +} psxRegisters; + +psxRegisters psxRegs; + +#define _i32(x) (s32)x +#define _u32(x) (u32)x + +#define _i16(x) (s16)x +#define _u16(x) (u32)x + +#define _i8(x) (s8)x +#define _u8(x) (u8)x + +/**** R3000A Instruction Macros ****/ +#define _PC_ psxRegs.pc // The next PC to be executed + +#define _Funct_ ((psxRegs.code ) & 0x3F) // The funct part of the instruction register +#define _Rd_ ((psxRegs.code >> 11) & 0x1F) // The rd part of the instruction register +#define _Rt_ ((psxRegs.code >> 16) & 0x1F) // The rt part of the instruction register +#define _Rs_ ((psxRegs.code >> 21) & 0x1F) // The rs part of the instruction register +#define _Sa_ ((psxRegs.code >> 6) & 0x1F) // The sa part of the instruction register +#define _Im_ ((u16)psxRegs.code) // The immediate part of the instruction register +#define _Target_ (psxRegs.code & 0x03ffffff) // The target part of the instruction register + +#define _Imm_ ((s16)psxRegs.code) // sign-extended immediate +#define _ImmU_ (psxRegs.code&0xffff) // zero-extended immediate + +#define _rRs_ psxRegs.GPR.r[_Rs_] // Rs register +#define _rRt_ psxRegs.GPR.r[_Rt_] // Rt register +#define _rRd_ psxRegs.GPR.r[_Rd_] // Rd register +#define _rSa_ psxRegs.GPR.r[_Sa_] // Sa register +#define _rFs_ psxRegs.CP0.r[_Rd_] // Fs register + +#define _c2dRs_ psxRegs.CP2D.r[_Rs_] // Rs cop2 data register +#define _c2dRt_ psxRegs.CP2D.r[_Rt_] // Rt cop2 data register +#define _c2dRd_ psxRegs.CP2D.r[_Rd_] // Rd cop2 data register +#define _c2dSa_ psxRegs.CP2D.r[_Sa_] // Sa cop2 data register + +#define _rHi_ psxRegs.GPR.n.hi // The HI register +#define _rLo_ psxRegs.GPR.n.lo // The LO register + +#define _JumpTarget_ ((_Target_ * 4) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction +#define _BranchTarget_ ((s16)_Im_ * 4 + _PC_) // Calculates the target during a branch instruction + +#define _SetLink(x) psxRegs.GPR.r[x] = _PC_ + 4; // Sets the return address in the link register + +int psxInit(); +void psxReset(); +void psxShutdown(); +void psxException(u32 code, u32 bd); +void psxBranchTest(); +void psxExecuteBios(); + +#endif /* __R3000A_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/Spu.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,23 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PsxCommon.h" + +void SPUirq(void) { + psxHu32(0x1070)|=BFLIP32(0x200); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/Spu.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,41 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __SPU_H__ +#define __SPU_H__ + +#define H_SPUirqAddr 0x0da4 +#define H_SPUaddr 0x0da6 +#define H_SPUdata 0x0da8 +#define H_SPUctrl 0x0daa +#define H_SPUstat 0x0dae +#define H_SPUon1 0x0d88 +#define H_SPUon2 0x0d8a +#define H_SPUoff1 0x0d8c +#define H_SPUoff2 0x0d8e + + +void SPUirq(void); +u16 SPUreadRegister(u32 reg); +void SPUwriteRegister(u32 reg, u16 val); +int SPUasync(u32 cycle); +void SPUwriteDMAMem(u32 usPSXMem,int iSize); +void SPUreadDMAMem(u32 usPSXMem,int iSize); + + +#endif /* __SPU_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/driver.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,26 @@ +#include "types.h" + +typedef struct __PSFTAG +{ + char *key; + char *value; + struct __PSFTAG *next; +} PSFTAG; + +typedef struct { + u32 length; + u32 stop; + u32 fade; + char *title,*artist,*game,*year,*genre,*psfby,*comment,*copyright; + PSFTAG *tags; +} PSFINFO; + +int sexypsf_seek(u32 t); +void sexypsf_stop(void); +void sexypsf_execute(void); + +PSFINFO *sexypsf_load(char *path); +PSFINFO *sexypsf_getpsfinfo(char *path); +void sexypsf_freepsfinfo(PSFINFO *info); + +void sexypsf_update(unsigned char*,long);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/spu.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,637 @@ +/*************************************************************************** + spu.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/03/01 - linuzappz +// - libraryName changes using ALSA +// +// 2003/02/28 - Pete +// - added option for type of interpolation +// - adjusted spu irqs again (Thousant Arms, Valkyrie Profile) +// - added MONO support for MSWindows DirectSound +// +// 2003/02/20 - kode54 +// - amended interpolation code, goto GOON could skip initialization of gpos and cause segfault +// +// 2003/02/19 - kode54 +// - moved SPU IRQ handler and changed sample flag processing +// +// 2003/02/18 - kode54 +// - moved ADSR calculation outside of the sample decode loop, somehow I doubt that +// ADSR timing is relative to the frequency at which a sample is played... I guess +// this remains to be seen, and I don't know whether ADSR is applied to noise channels... +// +// 2003/02/09 - kode54 +// - one-shot samples now process the end block before stopping +// - in light of removing fmod hack, now processing ADSR on frequency channel as well +// +// 2003/02/08 - kode54 +// - replaced easy interpolation with gaussian +// - removed fmod averaging hack +// - changed .sinc to be updated from .iRawPitch, no idea why it wasn't done this way already (<- Pete: because I sometimes fail to see the obvious, haharhar :) +// +// 2003/02/08 - linuzappz +// - small bugfix for one usleep that was 1 instead of 1000 +// - added iDisStereo for no stereo (Linux) +// +// 2003/01/22 - Pete +// - added easy interpolation & small noise adjustments +// +// 2003/01/19 - Pete +// - added Neill's reverb +// +// 2003/01/12 - Pete +// - added recording window handlers +// +// 2003/01/06 - Pete +// - added Neill's ADSR timings +// +// 2002/12/28 - Pete +// - adjusted spu irq handling, fmod handling and loop handling +// +// 2002/08/14 - Pete +// - added extra reverb +// +// 2002/06/08 - linuzappz +// - SPUupdate changed for SPUasync +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#define _IN_SPU + +#include "stdafx.h" +#include "externals.h" +#include "spu.h" +#include "regs.h" +#include "registers.h" + +#include "PsxMem.h" +#include "driver.h" + +//////////////////////////////////////////////////////////////////////// +// globals +//////////////////////////////////////////////////////////////////////// + +// psx buffer / addresses + +static u16 regArea[0x200]; +static u16 spuMem[256*1024]; +static u8 * spuMemC; +static u8 * pSpuIrq=0; +static u8 * pSpuBuffer; + +// user settings +static int iVolume; + +// MAIN infos struct for each channel + +static SPUCHAN s_chan[MAXCHAN+1]; // channel + 1 infos (1 is security for fmod handling) +static REVERBInfo rvb; + +static u32 dwNoiseVal=1; // global noise generator + +static u16 spuCtrl=0; // some vars to store psx reg infos +static u16 spuStat=0; +static u16 spuIrq=0; +static u32 spuAddr=0xffffffff; // address into spu mem +static int bSPUIsOpen=0; + +static const int f[5][2] = { + { 0, 0 }, + { 60, 0 }, + { 115, -52 }, + { 98, -55 }, + { 122, -60 } }; +s16 * pS; + +//////////////////////////////////////////////////////////////////////// +// CODE AREA +//////////////////////////////////////////////////////////////////////// + +// dirty inline func includes + +#include "reverb.c" +#include "adsr.c" + +// Try this to increase speed. +#include "registers.c" +#include "dma.c" + +//////////////////////////////////////////////////////////////////////// +// helpers for so-called "gauss interpolation" + +#define gval0 (((int *)(&s_chan[ch].SB[29]))[gpos]) +#define gval(x) (((int *)(&s_chan[ch].SB[29]))[(gpos+x)&3]) + +#include "gauss_i.h" + +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// START SOUND... called by main thread to setup a new sound on a channel +//////////////////////////////////////////////////////////////////////// + +static INLINE void StartSound(int ch) +{ + StartADSR(ch); + + s_chan[ch].pCurr=s_chan[ch].pStart; // set sample start + + s_chan[ch].s_1=0; // init mixing vars + s_chan[ch].s_2=0; + s_chan[ch].iSBPos=28; + + s_chan[ch].bNew=0; // init channel flags + s_chan[ch].bStop=0; + s_chan[ch].bOn=1; + + s_chan[ch].SB[29]=0; // init our interpolation helpers + s_chan[ch].SB[30]=0; + + s_chan[ch].spos=0x40000L;s_chan[ch].SB[28]=0; // -> start with more decoding +} + +//////////////////////////////////////////////////////////////////////// +// MAIN SPU FUNCTION +// here is the main job handler... thread, timer or direct func call +// basically the whole sound processing is done in this fat func! +//////////////////////////////////////////////////////////////////////// + +static u32 sampcount; +static u32 decaybegin; +static u32 decayend; + +// Counting to 65536 results in full volume offage. +void SPUsetlength(s32 stop, s32 fade) +{ + if(stop==~0) + { + decaybegin=~0; + } + else + { + stop=(stop*441)/10; + fade=(fade*441)/10; + + decaybegin=stop; + decayend=stop+fade; + } +} + +static s32 seektime; +static s32 poo; +int sexypsf_seek(u32 t) +{ + seektime=t*441/10; + if(seektime>sampcount) return(1); + return(0); +} + +#define CLIP(_x) {if(_x>32767) _x=32767; if(_x<-32767) _x=-32767;} +int SPUasync(u32 cycles) +{ + int volmul=iVolume; + static s32 dosampies; + s32 temp; + + poo+=cycles; + dosampies=poo/384; + if(!dosampies) return(1); + poo-=dosampies*384; + temp=dosampies; + + while(temp) + { + s32 revLeft=0, revRight=0; + s32 sl=0, sr=0; + int ch,fa; + + temp--; + //--------------------------------------------------// + //- main channel loop -// + //--------------------------------------------------// + { + for(ch=0;ch<MAXCHAN;ch++) // loop em all. + { + if(s_chan[ch].bNew) StartSound(ch); // start new sound + if(!s_chan[ch].bOn) continue; // channel not playing? next + + + if(s_chan[ch].iActFreq!=s_chan[ch].iUsedFreq) // new psx frequency? + { + s_chan[ch].iUsedFreq=s_chan[ch].iActFreq; // -> take it and calc steps + s_chan[ch].sinc=s_chan[ch].iRawPitch<<4; + if(!s_chan[ch].sinc) s_chan[ch].sinc=1; + } + + while(s_chan[ch].spos>=0x10000L) + { + if(s_chan[ch].iSBPos==28) // 28 reached? + { + int predict_nr,shift_factor,flags,d,s; + u8* start;unsigned int nSample; + int s_1,s_2; + + start=s_chan[ch].pCurr; // set up the current pos + + if (start == (u8*)-1) // special "stop" sign + { + s_chan[ch].bOn=0; // -> turn everything off + s_chan[ch].ADSRX.lVolume=0; + s_chan[ch].ADSRX.EnvelopeVol=0; + goto ENDX; // -> and done for this channel + } + + s_chan[ch].iSBPos=0; // Reset buffer play index. + + //////////////////////////////////////////// spu irq handler here? mmm... do it later + + s_1=s_chan[ch].s_1; + s_2=s_chan[ch].s_2; + + predict_nr=(int)*start;start++; + shift_factor=predict_nr&0xf; + predict_nr >>= 4; + flags=(int)*start;start++; + + // -------------------------------------- // + // Decode new samples into s_chan[ch].SB[0 through 27] + for (nSample=0;nSample<28;start++) + { + d=(int)*start; + s=((d&0xf)<<12); + if(s&0x8000) s|=0xffff0000; + + fa=(s >> shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1;s_1=fa; + s=((d & 0xf0) << 8); + + s_chan[ch].SB[nSample++]=fa; + + if(s&0x8000) s|=0xffff0000; + fa=(s>>shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1;s_1=fa; + + s_chan[ch].SB[nSample++]=fa; + } + + //////////////////////////////////////////// irq check + + if(spuCtrl&0x40) // irq active? + { + if((pSpuIrq > start-16 && // irq address reached? + pSpuIrq <= start) || + ((flags&1) && // special: irq on looping addr, when stop/loop flag is set + (pSpuIrq > s_chan[ch].pLoop-16 && + pSpuIrq <= s_chan[ch].pLoop))) + { + //extern s32 spuirqvoodoo; + s_chan[ch].iIrqDone=1; // -> debug flag + SPUirq(); + //puts("IRQ"); + //if(spuirqvoodoo!=-1) + //{ + // spuirqvoodoo=temp*384; + // temp=0; + //} + } + } + + //////////////////////////////////////////// flag handler + + if((flags&4) && (!s_chan[ch].bIgnoreLoop)) + s_chan[ch].pLoop=start-16; // loop adress + + if(flags&1) // 1: stop/loop + { + // We play this block out first... + //if(!(flags&2)) // 1+2: do loop... otherwise: stop + if(flags!=3 || s_chan[ch].pLoop==NULL) // PETE: if we don't check exactly for 3, loop hang ups will happen (DQ4, for example) + { // and checking if pLoop is set avoids crashes, yeah + start = (u8*)-1; + } + else + { + start = s_chan[ch].pLoop; + } + } + + s_chan[ch].pCurr=start; // store values for next cycle + s_chan[ch].s_1=s_1; + s_chan[ch].s_2=s_2; + + //////////////////////////////////////////// + } + + fa=s_chan[ch].SB[s_chan[ch].iSBPos++]; // get sample data + + if((spuCtrl&0x4000)==0) fa=0; // muted? + else CLIP(fa); + + { + int gpos; + gpos = s_chan[ch].SB[28]; + gval0 = fa; + gpos = (gpos+1) & 3; + s_chan[ch].SB[28] = gpos; + } + s_chan[ch].spos -= 0x10000L; + } + + //////////////////////////////////////////////// + // noise handler... just produces some noise data + // surely wrong... and no noise frequency (spuCtrl&0x3f00) will be used... + // and sometimes the noise will be used as fmod modulation... pfff + + if(s_chan[ch].bNoise) + { + //puts("Noise"); + if((dwNoiseVal<<=1)&0x80000000L) + { + dwNoiseVal^=0x0040001L; + fa=((dwNoiseVal>>2)&0x7fff); + fa=-fa; + } + else fa=(dwNoiseVal>>2)&0x7fff; + + // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val + fa=s_chan[ch].iOldNoise+((fa-s_chan[ch].iOldNoise)/((0x001f-((spuCtrl&0x3f00)>>9))+1)); + if(fa>32767L) fa=32767L; + if(fa<-32767L) fa=-32767L; + s_chan[ch].iOldNoise=fa; + + } //---------------------------------------- + else // NO NOISE (NORMAL SAMPLE DATA) HERE + { + int vl, vr, gpos; + vl = (s_chan[ch].spos >> 6) & ~3; + gpos = s_chan[ch].SB[28]; + vr=(gauss[vl]*gval0)>>9; + vr+=(gauss[vl+1]*gval(1))>>9; + vr+=(gauss[vl+2]*gval(2))>>9; + vr+=(gauss[vl+3]*gval(3))>>9; + fa = vr>>2; + } + + s_chan[ch].sval = (MixADSR(ch) * fa)>>10; // / 1023; // add adsr + if(s_chan[ch].bFMod==2) // fmod freq channel + { + int NP=s_chan[ch+1].iRawPitch; + NP=((32768L+s_chan[ch].sval)*NP)>>15; ///32768L; + + if(NP>0x3fff) NP=0x3fff; + if(NP<0x1) NP=0x1; + + // mmmm... if I do this, all is screwed + // s_chan[ch+1].iRawPitch=NP; + + NP=(44100L*NP)/(4096L); // calc frequency + + s_chan[ch+1].iActFreq=NP; + s_chan[ch+1].iUsedFreq=NP; + s_chan[ch+1].sinc=(((NP/10)<<16)/4410); + if(!s_chan[ch+1].sinc) s_chan[ch+1].sinc=1; + + // mmmm... set up freq decoding positions? + // s_chan[ch+1].iSBPos=28; + // s_chan[ch+1].spos=0x10000L; + } + else + { + ////////////////////////////////////////////// + // ok, left/right sound volume (psx volume goes from 0 ... 0x3fff) + int tmpl,tmpr; + + tmpl=(s_chan[ch].sval*s_chan[ch].iLeftVolume)>>14; + tmpr=(s_chan[ch].sval*s_chan[ch].iRightVolume)>>14; + + sl+=tmpl; + sr+=tmpr; + + if(((rvb.Enabled>>ch)&1) && (spuCtrl&0x80)) + { + revLeft+=tmpl; + revRight+=tmpr; + } + } + + s_chan[ch].spos += s_chan[ch].sinc; + ENDX: ; + } + } + + /////////////////////////////////////////////////////// + // mix all channels (including reverb) into one buffer + MixREVERBLeftRight(&sl,&sr,revLeft,revRight); + if(sampcount>=decaybegin) + { + s32 dmul; + if(decaybegin!=~0) // Is anyone REALLY going to be playing a song + // for 13 hours? + { + if(sampcount>=decayend) return(0); + dmul=256-(256*(sampcount-decaybegin)/(decayend-decaybegin)); + sl=(sl*dmul)>>8; + sr=(sr*dmul)>>8; + } + } + sampcount++; + sl=(sl*volmul)>>8; + sr=(sr*volmul)>>8; + + //{ + // static double asl=0; + // static double asr=0; + + // asl+=(sl-asl)/5; + // asr+=(sl-asr)/5; + + //sl-=asl; + //sr-=asr; + + // if(sl>32767 || sl < -32767) printf("Left: %d, %f\n",sl,asl); + // if(sr>32767 || sr < -32767) printf("Right: %d, %f\n",sl,asl); + //} + + if(sl>32767) sl=32767; if(sl<-32767) sl=-32767; + if(sr>32767) sr=32767; if(sr<-32767) sr=-32767; + *pS++=sl; + *pS++=sr; + } + + return(1); +} + +void sexypsf_stop(void) +{ + decaybegin=decayend=0; +} + +void SPUendflush(void) +{ + if((seektime!=~0) && seektime>sampcount) + { + pS=(s16 *)pSpuBuffer; + sexypsf_update(0,0); + } + else if((u8*)pS>((u8*)pSpuBuffer+1024)) + { + sexypsf_update((u8*)pSpuBuffer,(u8*)pS-(u8*)pSpuBuffer); + pS=(s16 *)pSpuBuffer; + } +} + +#ifdef TIMEO +static u64 begintime; +static u64 SexyTime64(void) +{ + struct timeval tv; + u64 ret; + + gettimeofday(&tv,0); + ret=tv.tv_sec; + ret*=1000000; + ret+=tv.tv_usec; + return(ret); +} +#endif +//////////////////////////////////////////////////////////////////////// +// INIT/EXIT STUFF +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// SPUINIT: this func will be called first by the main emu +//////////////////////////////////////////////////////////////////////// + +int SPUinit(void) +{ + spuMemC=(u8*)spuMem; // just small setup + memset((void *)s_chan,0,MAXCHAN*sizeof(SPUCHAN)); + memset((void *)&rvb,0,sizeof(REVERBInfo)); + memset(regArea,0,sizeof(regArea)); + memset(spuMem,0,sizeof(spuMem)); + InitADSR(); + sampcount=poo=0; + seektime=~0; + #ifdef TIMEO + begintime=SexyTime64(); + #endif + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// SETUPSTREAMS: init most of the spu buffers +//////////////////////////////////////////////////////////////////////// + +void SetupStreams(void) +{ + int i; + + pSpuBuffer=(u8*)malloc(32768); // alloc mixing buffer + pS=(s16 *)pSpuBuffer; + + for(i=0;i<MAXCHAN;i++) // loop sound channels + { + s_chan[i].ADSRX.SustainLevel = 1024; // -> init sustain + s_chan[i].iIrqDone=0; + s_chan[i].pLoop=spuMemC; + s_chan[i].pStart=spuMemC; + s_chan[i].pCurr=spuMemC; + } +} + +//////////////////////////////////////////////////////////////////////// +// REMOVESTREAMS: free most buffer +//////////////////////////////////////////////////////////////////////// + +void RemoveStreams(void) +{ + free(pSpuBuffer); // free mixing buffer + pSpuBuffer=NULL; + + #ifdef TIMEO + { + u64 tmp; + tmp=SexyTime64(); + tmp-=begintime; + if(tmp) + tmp=(u64)sampcount*1000000/tmp; + printf("%lld samples per second\n",tmp); + } + #endif +} + + +//////////////////////////////////////////////////////////////////////// +// SPUOPEN: called by main emu after init +//////////////////////////////////////////////////////////////////////// + +int SPUopen(void) +{ + if(bSPUIsOpen) return 0; // security for some stupid main emus + spuIrq=0; + + spuStat=spuCtrl=0; + spuAddr=0xffffffff; + dwNoiseVal=1; + + spuMemC=(u8*)spuMem; + memset((void *)s_chan,0,(MAXCHAN+1)*sizeof(SPUCHAN)); + pSpuIrq=0; + + iVolume=192; //85; + SetupStreams(); // prepare streaming + + bSPUIsOpen=1; + + return 1; +} + +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// SPUCLOSE: called before shutdown +//////////////////////////////////////////////////////////////////////// + +int SPUclose(void) +{ + if(!bSPUIsOpen) return 0; // some security + + bSPUIsOpen=0; // no more open + + RemoveStreams(); // no more streaming + + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// SPUSHUTDOWN: called by main emu on final exit +//////////////////////////////////////////////////////////////////////// + +int SPUshutdown(void) +{ + return 0; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/spu/adsr.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,618 @@ +/*************************************************************************** + adsr.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/01/06 - Pete +// - added Neill's ADSR timings +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#define _IN_ADSR + +// will be included from spu.c +#ifdef _IN_SPU + +//////////////////////////////////////////////////////////////////////// +// ADSR func +//////////////////////////////////////////////////////////////////////// + +static u32 RateTable[160]; + +static void InitADSR(void) // INIT ADSR +{ + u32 r,rs,rd;int i; + + memset(RateTable,0,sizeof(u32)*160); // build the rate table according to Neill's rules (see at bottom of file) + + r=3;rs=1;rd=0; + + for(i=32;i<160;i++) // we start at pos 32 with the real values... everything before is 0 + { + if(r<0x3FFFFFFF) + { + r+=rs; + rd++;if(rd==5) {rd=1;rs*=2;} + } + if(r>0x3FFFFFFF) r=0x3FFFFFFF; + + RateTable[i]=r; + } +} + +//////////////////////////////////////////////////////////////////////// + +static INLINE void StartADSR(int ch) // MIX ADSR +{ + s_chan[ch].ADSRX.lVolume=1; // and init some adsr vars + s_chan[ch].ADSRX.State=0; + s_chan[ch].ADSRX.EnvelopeVol=0; +} + +//////////////////////////////////////////////////////////////////////// + +static INLINE int MixADSR(int ch) // MIX ADSR +{ + static const int sexytable[8]= + {0,4,6,8,9,10,11,12}; + + if(s_chan[ch].bStop) // should be stopped: + { // do release + if(s_chan[ch].ADSRX.ReleaseModeExp) + { + s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18+32+sexytable[(s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7]]; + } + else + { + s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x0C + 32]; + } + + if(s_chan[ch].ADSRX.EnvelopeVol<0) + { + s_chan[ch].ADSRX.EnvelopeVol=0; + s_chan[ch].bOn=0; + s_chan[ch].bNoise=0; + } + + s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; + return s_chan[ch].ADSRX.lVolume; + } + else // not stopped yet? + { + if(s_chan[ch].ADSRX.State==0) // -> attack + { + if(s_chan[ch].ADSRX.AttackModeExp) + { + if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000) + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32]; + else + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x18 + 32]; + } + else + { + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32]; + } + + if(s_chan[ch].ADSRX.EnvelopeVol<0) + { + s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF; + s_chan[ch].ADSRX.State=1; + } + + s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; + return s_chan[ch].ADSRX.lVolume; + } + //--------------------------------------------------// + if(s_chan[ch].ADSRX.State==1) // -> decay + { + s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+32+sexytable[(s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7]]; + + if(s_chan[ch].ADSRX.EnvelopeVol<0) s_chan[ch].ADSRX.EnvelopeVol=0; + if(((s_chan[ch].ADSRX.EnvelopeVol>>27)&0xF) <= s_chan[ch].ADSRX.SustainLevel) + { + s_chan[ch].ADSRX.State=2; + } + + s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; + return s_chan[ch].ADSRX.lVolume; + } + //--------------------------------------------------// + if(s_chan[ch].ADSRX.State==2) // -> sustain + { + if(s_chan[ch].ADSRX.SustainIncrease) + { + if(s_chan[ch].ADSRX.SustainModeExp) + { + if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000) + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32]; + else + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x18 + 32]; + } + else + { + s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32]; + } + + if(s_chan[ch].ADSRX.EnvelopeVol<0) + { + s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF; + } + } + else + { + if(s_chan[ch].ADSRX.SustainModeExp) + s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B+32+sexytable[(s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7]]; + else + s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x0F + 32]; + + if(s_chan[ch].ADSRX.EnvelopeVol<0) + { + s_chan[ch].ADSRX.EnvelopeVol=0; + } + } + s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; + return s_chan[ch].ADSRX.lVolume; + } + } + return 0; +} + +#endif + +/* +James Higgs ADSR investigations: + +PSX SPU Envelope Timings +~~~~~~~~~~~~~~~~~~~~~~~~ + +First, here is an extract from doomed's SPU doc, which explains the basics +of the SPU "volume envelope": + +*** doomed doc extract start *** + +-------------------------------------------------------------------------- +Voices. +-------------------------------------------------------------------------- +The SPU has 24 hardware voices. These voices can be used to reproduce sample +data, noise or can be used as frequency modulator on the next voice. +Each voice has it's own programmable ADSR envelope filter. The main volume +can be programmed independently for left and right output. + +The ADSR envelope filter works as follows: +Ar = Attack rate, which specifies the speed at which the volume increases + from zero to it's maximum value, as soon as the note on is given. The + slope can be set to lineair or exponential. +Dr = Decay rate specifies the speed at which the volume decreases to the + sustain level. Decay is always decreasing exponentially. +Sl = Sustain level, base level from which sustain starts. +Sr = Sustain rate is the rate at which the volume of the sustained note + increases or decreases. This can be either lineair or exponential. +Rr = Release rate is the rate at which the volume of the note decreases + as soon as the note off is given. + + lvl | + ^ | /\Dr __ + Sl _| _ / _ \__--- \ + | / ---__ \ Rr + | /Ar Sr \ \ + | / \\ + |/___________________\________ + ->time + +The overal volume can also be set to sweep up or down lineairly or +exponentially from it's current value. This can be done seperately +for left and right. + +Relevant SPU registers: +------------------------------------------------------------- +$1f801xx8 Attack/Decay/Sustain level +bit |0f|0e 0d 0c 0b 0a 09 08|07 06 05 04|03 02 01 00| +desc.|Am| Ar |Dr |Sl | + +Am 0 Attack mode Linear + 1 Exponential + +Ar 0-7f attack rate +Dr 0-f decay rate +Sl 0-f sustain level +------------------------------------------------------------- +$1f801xxa Sustain rate, Release Rate. +bit |0f|0e|0d|0c 0b 0a 09 08 07 06|05|04 03 02 01 00| +desc.|Sm|Sd| 0| Sr |Rm|Rr | + +Sm 0 sustain rate mode linear + 1 exponential +Sd 0 sustain rate mode increase + 1 decrease +Sr 0-7f Sustain Rate +Rm 0 Linear decrease + 1 Exponential decrease +Rr 0-1f Release Rate + +Note: decay mode is always Expontial decrease, and thus cannot +be set. +------------------------------------------------------------- +$1f801xxc Current ADSR volume +bit |0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00| +desc.|ADSRvol | + +ADSRvol Returns the current envelope volume when + read. +-- James' Note: return range: 0 -> 32767 + +*** doomed doc extract end *** + +By using a small PSX proggie to visualise the envelope as it was played, +the following results for envelope timing were obtained: + +1. Attack rate value (linear mode) + + Attack value range: 0 -> 127 + + Value | 48 | 52 | 56 | 60 | 64 | 68 | 72 | | 80 | + ----------------------------------------------------------------- + Frames | 11 | 21 | 42 | 84 | 169| 338| 676| |2890| + + Note: frames is no. of PAL frames to reach full volume (100% + amplitude) + + Hmm, noticing that the time taken to reach full volume doubles + every time we add 4 to our attack value, we know the equation is + of form: + frames = k * 2 ^ (value / 4) + + (You may ponder about envelope generator hardware at this point, + or maybe not... :) + + By substituting some stuff and running some checks, we get: + + k = 0.00257 (close enuf) + + therefore, + frames = 0.00257 * 2 ^ (value / 4) + If you just happen to be writing an emulator, then you can probably + use an equation like: + + %volume_increase_per_tick = 1 / frames + + + ------------------------------------ + Pete: + ms=((1<<(value>>2))*514)/10000 + ------------------------------------ + +2. Decay rate value (only has log mode) + + Decay value range: 0 -> 15 + + Value | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | + ------------------------------------------------ + frames | | | | | 6 | 12 | 24 | 47 | + + Note: frames here is no. of PAL frames to decay to 50% volume. + + formula: frames = k * 2 ^ (value) + + Substituting, we get: k = 0.00146 + + Further info on logarithmic nature: + frames to decay to sustain level 3 = 3 * frames to decay to + sustain level 9 + + Also no. of frames to 25% volume = roughly 1.85 * no. of frames to + 50% volume. + + Frag it - just use linear approx. + + ------------------------------------ + Pete: + ms=((1<<value)*292)/10000 + ------------------------------------ + + +3. Sustain rate value (linear mode) + + Sustain rate range: 0 -> 127 + + Value | 48 | 52 | 56 | 60 | 64 | 68 | 72 | + ------------------------------------------- + frames | 9 | 19 | 37 | 74 | 147| 293| 587| + + Here, frames = no. of PAL frames for volume amplitude to go from 100% + to 0% (or vice-versa). + + Same formula as for attack value, just a different value for k: + + k = 0.00225 + + ie: frames = 0.00225 * 2 ^ (value / 4) + + For emulation purposes: + + %volume_increase_or_decrease_per_tick = 1 / frames + + ------------------------------------ + Pete: + ms=((1<<(value>>2))*450)/10000 + ------------------------------------ + + +4. Release rate (linear mode) + + Release rate range: 0 -> 31 + + Value | 13 | 14 | 15 | 16 | 17 | + --------------------------------------------------------------- + frames | 18 | 36 | 73 | 146| 292| + + Here, frames = no. of PAL frames to decay from 100% vol to 0% vol + after "note-off" is triggered. + + Formula: frames = k * 2 ^ (value) + + And so: k = 0.00223 + + ------------------------------------ + Pete: + ms=((1<<value)*446)/10000 + ------------------------------------ + + +Other notes: + +Log stuff not figured out. You may get some clues from the "Decay rate" +stuff above. For emu purposes it may not be important - use linear +approx. + +To get timings in millisecs, multiply frames by 20. + + + +- James Higgs 17/6/2000 +james7780@yahoo.com + +//--------------------------------------------------------------- + +OLD adsr mixing according to james' rules... has to be called +every one millisecond + + + i32 v,v2,lT,l1,l2,l3; + + if(s_chan[ch].bStop) // psx wants to stop? -> release phase + { + if(s_chan[ch].ADSR.ReleaseVal!=0) // -> release not 0: do release (if 0: stop right now) + { + if(!s_chan[ch].ADSR.ReleaseVol) // --> release just started? set up the release stuff + { + s_chan[ch].ADSR.ReleaseStartTime=s_chan[ch].ADSR.lTime; + s_chan[ch].ADSR.ReleaseVol=s_chan[ch].ADSR.lVolume; + s_chan[ch].ADSR.ReleaseTime = // --> calc how long does it take to reach the wanted sus level + (s_chan[ch].ADSR.ReleaseTime* + s_chan[ch].ADSR.ReleaseVol)/1024; + } + // -> NO release exp mode used (yet) + v=s_chan[ch].ADSR.ReleaseVol; // -> get last volume + lT=s_chan[ch].ADSR.lTime- // -> how much time is past? + s_chan[ch].ADSR.ReleaseStartTime; + l1=s_chan[ch].ADSR.ReleaseTime; + + if(lT<l1) // -> we still have to release + { + v=v-((v*lT)/l1); // --> calc new volume + } + else // -> release is over: now really stop that sample + {v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;} + } + else // -> release IS 0: release at once + { + v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0; + } + } + else + {//--------------------------------------------------// not in release phase: + v=1024; + lT=s_chan[ch].ADSR.lTime; + l1=s_chan[ch].ADSR.AttackTime; + + if(lT<l1) // attack + { // no exp mode used (yet) +// if(s_chan[ch].ADSR.AttackModeExp) +// { +// v=(v*lT)/l1; +// } +// else + { + v=(v*lT)/l1; + } + if(v==0) v=1; + } + else // decay + { // should be exp, but who cares? ;) + l2=s_chan[ch].ADSR.DecayTime; + v2=s_chan[ch].ADSR.SustainLevel; + + lT-=l1; + if(lT<l2) + { + v-=(((v-v2)*lT)/l2); + } + else // sustain + { // no exp mode used (yet) + l3=s_chan[ch].ADSR.SustainTime; + lT-=l2; + if(s_chan[ch].ADSR.SustainModeDec>0) + { + if(l3!=0) v2+=((v-v2)*lT)/l3; + else v2=v; + } + else + { + if(l3!=0) v2-=(v2*lT)/l3; + else v2=v; + } + + if(v2>v) v2=v; + if(v2<=0) {v2=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;} + + v=v2; + } + } + } + + //----------------------------------------------------// + // ok, done for this channel, so increase time + + s_chan[ch].ADSR.lTime+=1; // 1 = 1.020408f ms; + + if(v>1024) v=1024; // adjust volume + if(v<0) v=0; + s_chan[ch].ADSR.lVolume=v; // store act volume + + return v; // return the volume factor +*/ + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + + +/* +----------------------------------------------------------------------------- +Neill Corlett +Playstation SPU envelope timing notes +----------------------------------------------------------------------------- + +This is preliminary. This may be wrong. But the model described herein fits +all of my experimental data, and it's just simple enough to sound right. + +ADSR envelope level ranges from 0x00000000 to 0x7FFFFFFF internally. +The value returned by channel reg 0xC is (envelope_level>>16). + +Each sample, an increment or decrement value will be added to or +subtracted from this envelope level. + +Create the rate log table. The values double every 4 entries. + entry #0 = 4 + + 4, 5, 6, 7, + 8,10,12,14, + 16,20,24,28, ... + + entry #40 = 4096... + entry #44 = 8192... + entry #48 = 16384... + entry #52 = 32768... + entry #56 = 65536... + +increments and decrements are in terms of ratelogtable[n] +n may exceed the table bounds (plan on n being between -32 and 127). +table values are all clipped between 0x00000000 and 0x3FFFFFFF + +when you "voice on", the envelope is always fully reset. +(yes, it may click. the real thing does this too.) + +envelope level begins at zero. + +each state happens for at least 1 cycle +(transitions are not instantaneous) +this may result in some oddness: if the decay rate is uberfast, it will cut +the envelope from full down to half in one sample, potentially skipping over +the sustain level + +ATTACK +------ +- if the envelope level has overflowed past the max, clip to 0x7FFFFFFF and + proceed to DECAY. + +Linear attack mode: +- line extends upward to 0x7FFFFFFF +- increment per sample is ratelogtable[(Ar^0x7F)-0x10] + +Logarithmic attack mode: +if envelope_level < 0x60000000: + - line extends upward to 0x60000000 + - increment per sample is ratelogtable[(Ar^0x7F)-0x10] +else: + - line extends upward to 0x7FFFFFFF + - increment per sample is ratelogtable[(Ar^0x7F)-0x18] + +DECAY +----- +- if ((envelope_level>>27)&0xF) <= Sl, proceed to SUSTAIN. + Do not clip to the sustain level. +- current line ends at (envelope_level & 0x07FFFFFF) +- decrement per sample depends on (envelope_level>>28)&0x7 + 0: ratelogtable[(4*(Dr^0x1F))-0x18+0] + 1: ratelogtable[(4*(Dr^0x1F))-0x18+4] + 2: ratelogtable[(4*(Dr^0x1F))-0x18+6] + 3: ratelogtable[(4*(Dr^0x1F))-0x18+8] + 4: ratelogtable[(4*(Dr^0x1F))-0x18+9] + 5: ratelogtable[(4*(Dr^0x1F))-0x18+10] + 6: ratelogtable[(4*(Dr^0x1F))-0x18+11] + 7: ratelogtable[(4*(Dr^0x1F))-0x18+12] + (note that this is the same as the release rate formula, except that + decay rates 10-1F aren't possible... those would be slower in theory) + +SUSTAIN +------- +- no terminating condition except for voice off +- Sd=0 (increase) behavior is identical to ATTACK for both log and linear. +- Sd=1 (decrease) behavior: +Linear sustain decrease: +- line extends to 0x00000000 +- decrement per sample is ratelogtable[(Sr^0x7F)-0x0F] +Logarithmic sustain decrease: +- current line ends at (envelope_level & 0x07FFFFFF) +- decrement per sample depends on (envelope_level>>28)&0x7 + 0: ratelogtable[(Sr^0x7F)-0x1B+0] + 1: ratelogtable[(Sr^0x7F)-0x1B+4] + 2: ratelogtable[(Sr^0x7F)-0x1B+6] + 3: ratelogtable[(Sr^0x7F)-0x1B+8] + 4: ratelogtable[(Sr^0x7F)-0x1B+9] + 5: ratelogtable[(Sr^0x7F)-0x1B+10] + 6: ratelogtable[(Sr^0x7F)-0x1B+11] + 7: ratelogtable[(Sr^0x7F)-0x1B+12] + +RELEASE +------- +- if the envelope level has overflowed to negative, clip to 0 and QUIT. + +Linear release mode: +- line extends to 0x00000000 +- decrement per sample is ratelogtable[(4*(Rr^0x1F))-0x0C] + +Logarithmic release mode: +- line extends to (envelope_level & 0x0FFFFFFF) +- decrement per sample depends on (envelope_level>>28)&0x7 + 0: ratelogtable[(4*(Rr^0x1F))-0x18+0] + 1: ratelogtable[(4*(Rr^0x1F))-0x18+4] + 2: ratelogtable[(4*(Rr^0x1F))-0x18+6] + 3: ratelogtable[(4*(Rr^0x1F))-0x18+8] + 4: ratelogtable[(4*(Rr^0x1F))-0x18+9] + 5: ratelogtable[(4*(Rr^0x1F))-0x18+10] + 6: ratelogtable[(4*(Rr^0x1F))-0x18+11] + 7: ratelogtable[(4*(Rr^0x1F))-0x18+12] + +----------------------------------------------------------------------------- +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/spu/adsr.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,28 @@ +/*************************************************************************** + adsr.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +static INLINE void StartADSR(int ch); +static INLINE int MixADSR(int ch);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/spu/dma.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,75 @@ +/*************************************************************************** + dma.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_DMA + +//#include "externals.h" +//////////////////////////////////////////////////////////////////////// +// READ DMA (many values) +//////////////////////////////////////////////////////////////////////// + +void SPUreadDMAMem(u32 usPSXMem,int iSize) +{ + int i; + + for(i=0;i<iSize;i++) + { + *(u16 *)PSXM(usPSXMem)=spuMem[spuAddr>>1]; // spu addr got by writeregister + usPSXMem+=2; + spuAddr+=2; // inc spu addr + if(spuAddr>0x7ffff) spuAddr=0; // wrap + } +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +// to investigate: do sound data updates by writedma affect spu +// irqs? Will an irq be triggered, if new data is written to +// the memory irq address? + +//////////////////////////////////////////////////////////////////////// +// WRITE DMA (many values) +//////////////////////////////////////////////////////////////////////// + +void SPUwriteDMAMem(u32 usPSXMem,int iSize) +{ + int i; + + for(i=0;i<iSize;i++) + { + spuMem[spuAddr>>1] = *(u16 *)PSXM(usPSXMem); + usPSXMem+=2; // spu addr got by writeregister + spuAddr+=2; // inc spu addr + if(spuAddr>0x7ffff) spuAddr=0; // wrap + } +} + +//////////////////////////////////////////////////////////////////////// +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/spu/dma.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,31 @@ +/*************************************************************************** + dma.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +u16 CALLBACK SPUreadDMA(void); +void CALLBACK SPUreadDMAMem(u16 * pusPSXMem,int iSize); +void CALLBACK SPUwriteDMA(u16 val); +void CALLBACK SPUwriteDMAMem(u16 * pusPSXMem,int iSize);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/spu/externals.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,177 @@ +/*************************************************************************** + externals.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +#include "types.h" +#include "PsxMem.h" + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +//////////////////////////////////////////////////////////////////////// +// spu defines +//////////////////////////////////////////////////////////////////////// + +// num of channels +#define MAXCHAN 24 + +/////////////////////////////////////////////////////////// +// struct defines +/////////////////////////////////////////////////////////// + +// ADSR INFOS PER CHANNEL +typedef struct +{ + int AttackModeExp; + s32 AttackTime; + s32 DecayTime; + s32 SustainLevel; + int SustainModeExp; + s32 SustainModeDec; + s32 SustainTime; + int ReleaseModeExp; + u32 ReleaseVal; + s32 ReleaseTime; + s32 ReleaseStartTime; + s32 ReleaseVol; + s32 lTime; + s32 lVolume; +} ADSRInfo; + +typedef struct +{ + int State; + int AttackModeExp; + int AttackRate; + int DecayRate; + int SustainLevel; + int SustainModeExp; + int SustainIncrease; + int SustainRate; + int ReleaseModeExp; + int ReleaseRate; + int EnvelopeVol; + s32 lVolume; + s32 lDummy1; + s32 lDummy2; +} ADSRInfoEx; + +/////////////////////////////////////////////////////////// + +// Tmp Flags + +// used for debug channel muting +#define FLAG_MUTE 1 + +/////////////////////////////////////////////////////////// + +// MAIN CHANNEL STRUCT +typedef struct +{ + int bNew; // start flag + + int iSBPos; // mixing stuff + int spos; + int sinc; + int SB[32+1]; + int sval; + + u8 * pStart; // start ptr into sound mem + u8 * pCurr; // current pos in sound mem + u8 * pLoop; // loop ptr in sound mem + + int bOn; // is channel active (sample playing?) + int bStop; // is channel stopped (sample _can_ still be playing, ADSR Release phase) + int iActFreq; // current psx pitch + int iUsedFreq; // current pc pitch + int iLeftVolume; // left volume + int iLeftVolRaw; // left psx volume value + int bIgnoreLoop; // ignore loop bit, if an external loop address is used + int iRightVolume; // right volume + int iRightVolRaw; // right psx volume value + int iRawPitch; // raw pitch (0...3fff) + int iIrqDone; // debug irq done flag + int s_1; // last decoding infos + int s_2; + int bRVBActive; // reverb active flag + int iRVBOffset; // reverb offset + int iRVBRepeat; // reverb repeat + int bNoise; // noise active flag + int bFMod; // freq mod (0=off, 1=sound channel, 2=freq channel) + int iOldNoise; // old noise val for this channel + ADSRInfo ADSR; // active ADSR settings + ADSRInfoEx ADSRX; // next ADSR settings (will be moved to active on sample start) + +} SPUCHAN; + +/////////////////////////////////////////////////////////// + +typedef struct +{ + int StartAddr; // reverb area start addr in samples + int CurrAddr; // reverb area curr addr in samples + + int Enabled; + int VolLeft; + int VolRight; + int iLastRVBLeft; + int iLastRVBRight; + int iRVBLeft; + int iRVBRight; + + + int FB_SRC_A; // (offset) + int FB_SRC_B; // (offset) + int IIR_ALPHA; // (coef.) + int ACC_COEF_A; // (coef.) + int ACC_COEF_B; // (coef.) + int ACC_COEF_C; // (coef.) + int ACC_COEF_D; // (coef.) + int IIR_COEF; // (coef.) + int FB_ALPHA; // (coef.) + int FB_X; // (coef.) + int IIR_DEST_A0; // (offset) + int IIR_DEST_A1; // (offset) + int ACC_SRC_A0; // (offset) + int ACC_SRC_A1; // (offset) + int ACC_SRC_B0; // (offset) + int ACC_SRC_B1; // (offset) + int IIR_SRC_A0; // (offset) + int IIR_SRC_A1; // (offset) + int IIR_DEST_B0; // (offset) + int IIR_DEST_B1; // (offset) + int ACC_SRC_C0; // (offset) + int ACC_SRC_C1; // (offset) + int ACC_SRC_D0; // (offset) + int ACC_SRC_D1; // (offset) + int IIR_SRC_B1; // (offset) + int IIR_SRC_B0; // (offset) + int MIX_DEST_A0; // (offset) + int MIX_DEST_A1; // (offset) + int MIX_DEST_B0; // (offset) + int MIX_DEST_B1; // (offset) + int IN_COEF_L; // (coef.) + int IN_COEF_R; // (coef.) +} REVERBInfo;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/spu/gauss_i.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,163 @@ +/*************************************************************************** + gauss_i.h - description + ----------------------- + begin : Sun Feb 08 2003 + copyright : (C) 2003 by Chris Moeller, eh, whatever + email : chris@kode54.tk + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/02/08 - kode54 +// - generated by interleaving table from gauss.h from the libopenspc +// project; a gaussian bell curve table logged from the SPC-700, +// though Neill says he logged the same curve from a PSX SPU. Also +// says that interleaving the coefficients together runs faster. Meh. +// +//*************************************************************************// + +#ifndef GAUSS_H +#define GAUSS_H + +// 1024 entries +const int gauss[]={ + 0x172, 0x519, 0x176, 0x000, 0x16E, 0x519, 0x17A, 0x000, + 0x16A, 0x518, 0x17D, 0x000, 0x166, 0x518, 0x181, 0x000, + 0x162, 0x518, 0x185, 0x000, 0x15F, 0x518, 0x189, 0x000, + 0x15B, 0x518, 0x18D, 0x000, 0x157, 0x517, 0x191, 0x000, + 0x153, 0x517, 0x195, 0x000, 0x150, 0x517, 0x19A, 0x000, + 0x14C, 0x516, 0x19E, 0x000, 0x148, 0x516, 0x1A2, 0x000, + 0x145, 0x515, 0x1A6, 0x000, 0x141, 0x514, 0x1AA, 0x000, + 0x13E, 0x514, 0x1AE, 0x000, 0x13A, 0x513, 0x1B2, 0x000, + 0x137, 0x512, 0x1B7, 0x001, 0x133, 0x511, 0x1BB, 0x001, + 0x130, 0x511, 0x1BF, 0x001, 0x12C, 0x510, 0x1C3, 0x001, + 0x129, 0x50F, 0x1C8, 0x001, 0x125, 0x50E, 0x1CC, 0x001, + 0x122, 0x50D, 0x1D0, 0x001, 0x11E, 0x50C, 0x1D5, 0x001, + 0x11B, 0x50B, 0x1D9, 0x001, 0x118, 0x50A, 0x1DD, 0x001, + 0x114, 0x508, 0x1E2, 0x001, 0x111, 0x507, 0x1E6, 0x002, + 0x10E, 0x506, 0x1EB, 0x002, 0x10B, 0x504, 0x1EF, 0x002, + 0x107, 0x503, 0x1F3, 0x002, 0x104, 0x502, 0x1F8, 0x002, + 0x101, 0x500, 0x1FC, 0x002, 0x0FE, 0x4FF, 0x201, 0x002, + 0x0FB, 0x4FD, 0x205, 0x003, 0x0F8, 0x4FB, 0x20A, 0x003, + 0x0F5, 0x4FA, 0x20F, 0x003, 0x0F2, 0x4F8, 0x213, 0x003, + 0x0EF, 0x4F6, 0x218, 0x003, 0x0EC, 0x4F5, 0x21C, 0x004, + 0x0E9, 0x4F3, 0x221, 0x004, 0x0E6, 0x4F1, 0x226, 0x004, + 0x0E3, 0x4EF, 0x22A, 0x004, 0x0E0, 0x4ED, 0x22F, 0x004, + 0x0DD, 0x4EB, 0x233, 0x005, 0x0DA, 0x4E9, 0x238, 0x005, + 0x0D7, 0x4E7, 0x23D, 0x005, 0x0D4, 0x4E5, 0x241, 0x005, + 0x0D2, 0x4E3, 0x246, 0x006, 0x0CF, 0x4E0, 0x24B, 0x006, + 0x0CC, 0x4DE, 0x250, 0x006, 0x0C9, 0x4DC, 0x254, 0x006, + 0x0C7, 0x4D9, 0x259, 0x007, 0x0C4, 0x4D7, 0x25E, 0x007, + 0x0C1, 0x4D5, 0x263, 0x007, 0x0BF, 0x4D2, 0x267, 0x008, + 0x0BC, 0x4D0, 0x26C, 0x008, 0x0BA, 0x4CD, 0x271, 0x008, + 0x0B7, 0x4CB, 0x276, 0x009, 0x0B4, 0x4C8, 0x27B, 0x009, + 0x0B2, 0x4C5, 0x280, 0x009, 0x0AF, 0x4C3, 0x284, 0x00A, + 0x0AD, 0x4C0, 0x289, 0x00A, 0x0AB, 0x4BD, 0x28E, 0x00A, + 0x0A8, 0x4BA, 0x293, 0x00B, 0x0A6, 0x4B7, 0x298, 0x00B, + 0x0A3, 0x4B5, 0x29D, 0x00B, 0x0A1, 0x4B2, 0x2A2, 0x00C, + 0x09F, 0x4AF, 0x2A6, 0x00C, 0x09C, 0x4AC, 0x2AB, 0x00D, + 0x09A, 0x4A9, 0x2B0, 0x00D, 0x098, 0x4A6, 0x2B5, 0x00E, + 0x096, 0x4A2, 0x2BA, 0x00E, 0x093, 0x49F, 0x2BF, 0x00F, + 0x091, 0x49C, 0x2C4, 0x00F, 0x08F, 0x499, 0x2C9, 0x00F, + 0x08D, 0x496, 0x2CE, 0x010, 0x08B, 0x492, 0x2D3, 0x010, + 0x089, 0x48F, 0x2D8, 0x011, 0x086, 0x48C, 0x2DC, 0x011, + 0x084, 0x488, 0x2E1, 0x012, 0x082, 0x485, 0x2E6, 0x013, + 0x080, 0x481, 0x2EB, 0x013, 0x07E, 0x47E, 0x2F0, 0x014, + 0x07C, 0x47A, 0x2F5, 0x014, 0x07A, 0x477, 0x2FA, 0x015, + 0x078, 0x473, 0x2FF, 0x015, 0x076, 0x470, 0x304, 0x016, + 0x075, 0x46C, 0x309, 0x017, 0x073, 0x468, 0x30E, 0x017, + 0x071, 0x465, 0x313, 0x018, 0x06F, 0x461, 0x318, 0x018, + 0x06D, 0x45D, 0x31D, 0x019, 0x06B, 0x459, 0x322, 0x01A, + 0x06A, 0x455, 0x326, 0x01B, 0x068, 0x452, 0x32B, 0x01B, + 0x066, 0x44E, 0x330, 0x01C, 0x064, 0x44A, 0x335, 0x01D, + 0x063, 0x446, 0x33A, 0x01D, 0x061, 0x442, 0x33F, 0x01E, + 0x05F, 0x43E, 0x344, 0x01F, 0x05E, 0x43A, 0x349, 0x020, + 0x05C, 0x436, 0x34E, 0x020, 0x05A, 0x432, 0x353, 0x021, + 0x059, 0x42E, 0x357, 0x022, 0x057, 0x42A, 0x35C, 0x023, + 0x056, 0x425, 0x361, 0x024, 0x054, 0x421, 0x366, 0x024, + 0x053, 0x41D, 0x36B, 0x025, 0x051, 0x419, 0x370, 0x026, + 0x050, 0x415, 0x374, 0x027, 0x04E, 0x410, 0x379, 0x028, + 0x04D, 0x40C, 0x37E, 0x029, 0x04C, 0x408, 0x383, 0x02A, + 0x04A, 0x403, 0x388, 0x02B, 0x049, 0x3FF, 0x38C, 0x02C, + 0x047, 0x3FB, 0x391, 0x02D, 0x046, 0x3F6, 0x396, 0x02E, + 0x045, 0x3F2, 0x39B, 0x02F, 0x043, 0x3ED, 0x39F, 0x030, + 0x042, 0x3E9, 0x3A4, 0x031, 0x041, 0x3E5, 0x3A9, 0x032, + 0x040, 0x3E0, 0x3AD, 0x033, 0x03E, 0x3DC, 0x3B2, 0x034, + 0x03D, 0x3D7, 0x3B7, 0x035, 0x03C, 0x3D2, 0x3BB, 0x036, + 0x03B, 0x3CE, 0x3C0, 0x037, 0x03A, 0x3C9, 0x3C5, 0x038, + 0x038, 0x3C5, 0x3C9, 0x03A, 0x037, 0x3C0, 0x3CE, 0x03B, + 0x036, 0x3BB, 0x3D2, 0x03C, 0x035, 0x3B7, 0x3D7, 0x03D, + 0x034, 0x3B2, 0x3DC, 0x03E, 0x033, 0x3AD, 0x3E0, 0x040, + 0x032, 0x3A9, 0x3E5, 0x041, 0x031, 0x3A4, 0x3E9, 0x042, + 0x030, 0x39F, 0x3ED, 0x043, 0x02F, 0x39B, 0x3F2, 0x045, + 0x02E, 0x396, 0x3F6, 0x046, 0x02D, 0x391, 0x3FB, 0x047, + 0x02C, 0x38C, 0x3FF, 0x049, 0x02B, 0x388, 0x403, 0x04A, + 0x02A, 0x383, 0x408, 0x04C, 0x029, 0x37E, 0x40C, 0x04D, + 0x028, 0x379, 0x410, 0x04E, 0x027, 0x374, 0x415, 0x050, + 0x026, 0x370, 0x419, 0x051, 0x025, 0x36B, 0x41D, 0x053, + 0x024, 0x366, 0x421, 0x054, 0x024, 0x361, 0x425, 0x056, + 0x023, 0x35C, 0x42A, 0x057, 0x022, 0x357, 0x42E, 0x059, + 0x021, 0x353, 0x432, 0x05A, 0x020, 0x34E, 0x436, 0x05C, + 0x020, 0x349, 0x43A, 0x05E, 0x01F, 0x344, 0x43E, 0x05F, + 0x01E, 0x33F, 0x442, 0x061, 0x01D, 0x33A, 0x446, 0x063, + 0x01D, 0x335, 0x44A, 0x064, 0x01C, 0x330, 0x44E, 0x066, + 0x01B, 0x32B, 0x452, 0x068, 0x01B, 0x326, 0x455, 0x06A, + 0x01A, 0x322, 0x459, 0x06B, 0x019, 0x31D, 0x45D, 0x06D, + 0x018, 0x318, 0x461, 0x06F, 0x018, 0x313, 0x465, 0x071, + 0x017, 0x30E, 0x468, 0x073, 0x017, 0x309, 0x46C, 0x075, + 0x016, 0x304, 0x470, 0x076, 0x015, 0x2FF, 0x473, 0x078, + 0x015, 0x2FA, 0x477, 0x07A, 0x014, 0x2F5, 0x47A, 0x07C, + 0x014, 0x2F0, 0x47E, 0x07E, 0x013, 0x2EB, 0x481, 0x080, + 0x013, 0x2E6, 0x485, 0x082, 0x012, 0x2E1, 0x488, 0x084, + 0x011, 0x2DC, 0x48C, 0x086, 0x011, 0x2D8, 0x48F, 0x089, + 0x010, 0x2D3, 0x492, 0x08B, 0x010, 0x2CE, 0x496, 0x08D, + 0x00F, 0x2C9, 0x499, 0x08F, 0x00F, 0x2C4, 0x49C, 0x091, + 0x00F, 0x2BF, 0x49F, 0x093, 0x00E, 0x2BA, 0x4A2, 0x096, + 0x00E, 0x2B5, 0x4A6, 0x098, 0x00D, 0x2B0, 0x4A9, 0x09A, + 0x00D, 0x2AB, 0x4AC, 0x09C, 0x00C, 0x2A6, 0x4AF, 0x09F, + 0x00C, 0x2A2, 0x4B2, 0x0A1, 0x00B, 0x29D, 0x4B5, 0x0A3, + 0x00B, 0x298, 0x4B7, 0x0A6, 0x00B, 0x293, 0x4BA, 0x0A8, + 0x00A, 0x28E, 0x4BD, 0x0AB, 0x00A, 0x289, 0x4C0, 0x0AD, + 0x00A, 0x284, 0x4C3, 0x0AF, 0x009, 0x280, 0x4C5, 0x0B2, + 0x009, 0x27B, 0x4C8, 0x0B4, 0x009, 0x276, 0x4CB, 0x0B7, + 0x008, 0x271, 0x4CD, 0x0BA, 0x008, 0x26C, 0x4D0, 0x0BC, + 0x008, 0x267, 0x4D2, 0x0BF, 0x007, 0x263, 0x4D5, 0x0C1, + 0x007, 0x25E, 0x4D7, 0x0C4, 0x007, 0x259, 0x4D9, 0x0C7, + 0x006, 0x254, 0x4DC, 0x0C9, 0x006, 0x250, 0x4DE, 0x0CC, + 0x006, 0x24B, 0x4E0, 0x0CF, 0x006, 0x246, 0x4E3, 0x0D2, + 0x005, 0x241, 0x4E5, 0x0D4, 0x005, 0x23D, 0x4E7, 0x0D7, + 0x005, 0x238, 0x4E9, 0x0DA, 0x005, 0x233, 0x4EB, 0x0DD, + 0x004, 0x22F, 0x4ED, 0x0E0, 0x004, 0x22A, 0x4EF, 0x0E3, + 0x004, 0x226, 0x4F1, 0x0E6, 0x004, 0x221, 0x4F3, 0x0E9, + 0x004, 0x21C, 0x4F5, 0x0EC, 0x003, 0x218, 0x4F6, 0x0EF, + 0x003, 0x213, 0x4F8, 0x0F2, 0x003, 0x20F, 0x4FA, 0x0F5, + 0x003, 0x20A, 0x4FB, 0x0F8, 0x003, 0x205, 0x4FD, 0x0FB, + 0x002, 0x201, 0x4FF, 0x0FE, 0x002, 0x1FC, 0x500, 0x101, + 0x002, 0x1F8, 0x502, 0x104, 0x002, 0x1F3, 0x503, 0x107, + 0x002, 0x1EF, 0x504, 0x10B, 0x002, 0x1EB, 0x506, 0x10E, + 0x002, 0x1E6, 0x507, 0x111, 0x001, 0x1E2, 0x508, 0x114, + 0x001, 0x1DD, 0x50A, 0x118, 0x001, 0x1D9, 0x50B, 0x11B, + 0x001, 0x1D5, 0x50C, 0x11E, 0x001, 0x1D0, 0x50D, 0x122, + 0x001, 0x1CC, 0x50E, 0x125, 0x001, 0x1C8, 0x50F, 0x129, + 0x001, 0x1C3, 0x510, 0x12C, 0x001, 0x1BF, 0x511, 0x130, + 0x001, 0x1BB, 0x511, 0x133, 0x001, 0x1B7, 0x512, 0x137, + 0x000, 0x1B2, 0x513, 0x13A, 0x000, 0x1AE, 0x514, 0x13E, + 0x000, 0x1AA, 0x514, 0x141, 0x000, 0x1A6, 0x515, 0x145, + 0x000, 0x1A2, 0x516, 0x148, 0x000, 0x19E, 0x516, 0x14C, + 0x000, 0x19A, 0x517, 0x150, 0x000, 0x195, 0x517, 0x153, + 0x000, 0x191, 0x517, 0x157, 0x000, 0x18D, 0x518, 0x15B, + 0x000, 0x189, 0x518, 0x15F, 0x000, 0x185, 0x518, 0x162, + 0x000, 0x181, 0x518, 0x166, 0x000, 0x17D, 0x518, 0x16A, + 0x000, 0x17A, 0x519, 0x16E, 0x000, 0x176, 0x519, 0x172}; +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/spu/registers.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,490 @@ +/*************************************************************************** + registers.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +/* ChangeLog + + February 8, 2004 - xodnizel + - Fixed setting of reverb volume. Just typecast val("u16") to s16. + Also adjusted the normal channel volume to be one less than what it was before when the + "phase invert" bit is set. I'm assuming it's just in two's complement. + + 2003/02/09 - kode54 + - removed &0x3fff from reverb volume registers, fixes a few games, + hopefully won't be breaking anything + + 2003/01/19 - Pete + - added Neill's reverb + + 2003/01/06 - Pete + - added Neill's ADSR timings + + 2002/05/15 - Pete + - generic cleanup for the Peops release + +*/ + +//#include "stdafx.h" + +#define _IN_REGISTERS + +//#include "externals.h" +//#include "registers.h" +//#include "regs.h" + +//////////////////////////////////////////////////////////////////////// +// WRITE REGISTERS: called by main emu +//////////////////////////////////////////////////////////////////////// + +void SPUwriteRegister(u32 reg, u16 val) +{ + const u32 r=reg&0xfff; + regArea[(r-0xc00)>>1] = val; + + if(r>=0x0c00 && r<0x0d80) // some channel info? + { + int ch=(r>>4)-0xc0; // calc channel + + //if(ch==20) printf("%08x: %04x\n",reg,val); + + switch(r&0x0f) + { + //------------------------------------------------// r volume + case 0: + SetVolumeLR(0,(u8)ch,val); + break; + //------------------------------------------------// l volume + case 2: + SetVolumeLR(1,(u8)ch,val); + break; + //------------------------------------------------// pitch + case 4: + SetPitch(ch,val); + break; + //------------------------------------------------// start + case 6: + s_chan[ch].pStart=spuMemC+((u32) val<<3); + break; + //------------------------------------------------// level with pre-calcs + case 8: + { + const u32 lval=val; // DEBUG CHECK + //---------------------------------------------// + s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0; + s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f; + s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f; + s_chan[ch].ADSRX.SustainLevel=lval & 0x000f; + //---------------------------------------------// + } + break; + //------------------------------------------------// adsr times with pre-calcs + case 10: + { + const u32 lval=val; // DEBUG CHECK + + //----------------------------------------------// + s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0; + s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1; + s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f; + s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0; + s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f; + //----------------------------------------------// + } + break; + //------------------------------------------------// adsr volume... mmm have to investigate this + //case 0xC: + // break; + //------------------------------------------------// + case 0xE: // loop? + s_chan[ch].pLoop=spuMemC+((u32) val<<3); + s_chan[ch].bIgnoreLoop=1; + break; + //------------------------------------------------// + } + return; + } + + switch(r) + { + //-------------------------------------------------// + case H_SPUaddr: + spuAddr = (u32) val<<3; + break; + //-------------------------------------------------// + case H_SPUdata: + spuMem[spuAddr>>1] = BFLIP16(val); + spuAddr+=2; + if(spuAddr>0x7ffff) spuAddr=0; + break; + //-------------------------------------------------// + case H_SPUctrl: + spuCtrl=val; + break; + //-------------------------------------------------// + case H_SPUstat: + spuStat=val & 0xf800; + break; + //-------------------------------------------------// + case H_SPUReverbAddr: + if(val==0xFFFF || val<=0x200) + {rvb.StartAddr=rvb.CurrAddr=0;} + else + { + const s32 iv=(u32)val<<2; + if(rvb.StartAddr!=iv) + { + rvb.StartAddr=(u32)val<<2; + rvb.CurrAddr=rvb.StartAddr; + } + } + break; + //-------------------------------------------------// + case H_SPUirqAddr: + spuIrq = val; + pSpuIrq=spuMemC+((u32) val<<3); + break; + //-------------------------------------------------// + /* Volume settings appear to be at least 15-bit unsigned in this case. + Definitely NOT 15-bit signed. Probably 16-bit signed, so s16 type cast. + Check out "Chrono Cross: Shadow's End Forest" + */ + case H_SPUrvolL: + rvb.VolLeft=(s16)val; + //printf("%d\n",val); + break; + //-------------------------------------------------// + case H_SPUrvolR: + rvb.VolRight=(s16)val; + //printf("%d\n",val); + break; + //-------------------------------------------------// + +/* + case H_ExtLeft: + //auxprintf("EL %d\n",val); + break; + //-------------------------------------------------// + case H_ExtRight: + //auxprintf("ER %d\n",val); + break; + //-------------------------------------------------// + case H_SPUmvolL: + //auxprintf("ML %d\n",val); + break; + //-------------------------------------------------// + case H_SPUmvolR: + //auxprintf("MR %d\n",val); + break; + //-------------------------------------------------// + case H_SPUMute1: + //printf("M0 %04x\n",val); + break; + //-------------------------------------------------// + case H_SPUMute2: + // printf("M1 %04x\n",val); + break; +*/ + //-------------------------------------------------// + case H_SPUon1: + SoundOn(0,16,val); + break; + //-------------------------------------------------// + case H_SPUon2: + // printf("Boop: %08x: %04x\n",reg,val); + SoundOn(16,24,val); + break; + //-------------------------------------------------// + case H_SPUoff1: + SoundOff(0,16,val); + break; + //-------------------------------------------------// + case H_SPUoff2: + SoundOff(16,24,val); + // printf("Boop: %08x: %04x\n",reg,val); + break; + //-------------------------------------------------// + case H_FMod1: + FModOn(0,16,val); + break; + //-------------------------------------------------// + case H_FMod2: + FModOn(16,24,val); + break; + //-------------------------------------------------// + case H_Noise1: + NoiseOn(0,16,val); + break; + //-------------------------------------------------// + case H_Noise2: + NoiseOn(16,24,val); + break; + //-------------------------------------------------// + case H_RVBon1: + rvb.Enabled&=~0xFFFF; + rvb.Enabled|=val; + break; + + //-------------------------------------------------// + case H_RVBon2: + rvb.Enabled&=0xFFFF; + rvb.Enabled|=val<<16; + break; + + //-------------------------------------------------// + case H_Reverb+0: + rvb.FB_SRC_A=val; + break; + + case H_Reverb+2 : rvb.FB_SRC_B=(s16)val; break; + case H_Reverb+4 : rvb.IIR_ALPHA=(s16)val; break; + case H_Reverb+6 : rvb.ACC_COEF_A=(s16)val; break; + case H_Reverb+8 : rvb.ACC_COEF_B=(s16)val; break; + case H_Reverb+10 : rvb.ACC_COEF_C=(s16)val; break; + case H_Reverb+12 : rvb.ACC_COEF_D=(s16)val; break; + case H_Reverb+14 : rvb.IIR_COEF=(s16)val; break; + case H_Reverb+16 : rvb.FB_ALPHA=(s16)val; break; + case H_Reverb+18 : rvb.FB_X=(s16)val; break; + case H_Reverb+20 : rvb.IIR_DEST_A0=(s16)val; break; + case H_Reverb+22 : rvb.IIR_DEST_A1=(s16)val; break; + case H_Reverb+24 : rvb.ACC_SRC_A0=(s16)val; break; + case H_Reverb+26 : rvb.ACC_SRC_A1=(s16)val; break; + case H_Reverb+28 : rvb.ACC_SRC_B0=(s16)val; break; + case H_Reverb+30 : rvb.ACC_SRC_B1=(s16)val; break; + case H_Reverb+32 : rvb.IIR_SRC_A0=(s16)val; break; + case H_Reverb+34 : rvb.IIR_SRC_A1=(s16)val; break; + case H_Reverb+36 : rvb.IIR_DEST_B0=(s16)val; break; + case H_Reverb+38 : rvb.IIR_DEST_B1=(s16)val; break; + case H_Reverb+40 : rvb.ACC_SRC_C0=(s16)val; break; + case H_Reverb+42 : rvb.ACC_SRC_C1=(s16)val; break; + case H_Reverb+44 : rvb.ACC_SRC_D0=(s16)val; break; + case H_Reverb+46 : rvb.ACC_SRC_D1=(s16)val; break; + case H_Reverb+48 : rvb.IIR_SRC_B1=(s16)val; break; + case H_Reverb+50 : rvb.IIR_SRC_B0=(s16)val; break; + case H_Reverb+52 : rvb.MIX_DEST_A0=(s16)val; break; + case H_Reverb+54 : rvb.MIX_DEST_A1=(s16)val; break; + case H_Reverb+56 : rvb.MIX_DEST_B0=(s16)val; break; + case H_Reverb+58 : rvb.MIX_DEST_B1=(s16)val; break; + case H_Reverb+60 : rvb.IN_COEF_L=(s16)val; break; + case H_Reverb+62 : rvb.IN_COEF_R=(s16)val; break; + } + +} + +//////////////////////////////////////////////////////////////////////// +// READ REGISTER: called by main emu +//////////////////////////////////////////////////////////////////////// + +u16 SPUreadRegister(u32 reg) +{ + const u32 r=reg&0xfff; + + if(r>=0x0c00 && r<0x0d80) + { + switch(r&0x0f) + { + case 0xC: // get adsr vol + { + const int ch=(r>>4)-0xc0; + if(s_chan[ch].bNew) return 1; // we are started, but not processed? return 1 + if(s_chan[ch].ADSRX.lVolume && // same here... we haven't decoded one sample yet, so no envelope yet. return 1 as well + !s_chan[ch].ADSRX.EnvelopeVol) + return 1; + return (u16)(s_chan[ch].ADSRX.EnvelopeVol>>16); + } + + case 0xE: // get loop address + { + const int ch=(r>>4)-0xc0; + if(s_chan[ch].pLoop==NULL) return 0; + return (u16)((s_chan[ch].pLoop-spuMemC)>>3); + } + } + } + + switch(r) + { + case H_SPUctrl: + return spuCtrl; + + case H_SPUstat: + return spuStat; + + case H_SPUaddr: + return (u16)(spuAddr>>3); + + case H_SPUdata: + { + u16 s=BFLIP16(spuMem[spuAddr>>1]); + spuAddr+=2; + if(spuAddr>0x7ffff) spuAddr=0; + return s; + } + + case H_SPUirqAddr: + return spuIrq; + + //case H_SPUIsOn1: + // return IsSoundOn(0,16); + + //case H_SPUIsOn2: + // return IsSoundOn(16,24); + + } + + return regArea[(r-0xc00)>>1]; +} + +//////////////////////////////////////////////////////////////////////// +// SOUND ON register write +//////////////////////////////////////////////////////////////////////// + +static void SoundOn(int start,int end,u16 val) // SOUND ON PSX COMAND +{ + int ch; + + for(ch=start;ch<end;ch++,val>>=1) // loop channels + { + if((val&1) && s_chan[ch].pStart) // mmm... start has to be set before key on !?! + { + s_chan[ch].bIgnoreLoop=0; + s_chan[ch].bNew=1; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// SOUND OFF register write +//////////////////////////////////////////////////////////////////////// + +static void SoundOff(int start,int end,u16 val) // SOUND OFF PSX COMMAND +{ + int ch; + for(ch=start;ch<end;ch++,val>>=1) // loop channels + { + if(val&1) // && s_chan[i].bOn) mmm... + { + s_chan[ch].bStop=1; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// FMOD register write +//////////////////////////////////////////////////////////////////////// + +static void FModOn(int start,int end,u16 val) // FMOD ON PSX COMMAND +{ + int ch; + + for(ch=start;ch<end;ch++,val>>=1) // loop channels + { + if(val&1) // -> fmod on/off + { + if(ch>0) + { + s_chan[ch].bFMod=1; // --> sound channel + s_chan[ch-1].bFMod=2; // --> freq channel + } + } + else + { + s_chan[ch].bFMod=0; // --> turn off fmod + } + } +} + +//////////////////////////////////////////////////////////////////////// +// NOISE register write +//////////////////////////////////////////////////////////////////////// + +static void NoiseOn(int start,int end,u16 val) // NOISE ON PSX COMMAND +{ + int ch; + + for(ch=start;ch<end;ch++,val>>=1) // loop channels + { + if(val&1) // -> noise on/off + { + s_chan[ch].bNoise=1; + } + else + { + s_chan[ch].bNoise=0; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// LEFT VOLUME register write +//////////////////////////////////////////////////////////////////////// + +// please note: sweep is wrong. + +static void SetVolumeLR(int right, u8 ch,s16 vol) // LEFT VOLUME +{ + //if(vol&0xc000) + //printf("%d %08x\n",right,vol); + if(right) + s_chan[ch].iRightVolRaw=vol; + else + s_chan[ch].iLeftVolRaw=vol; + + if(vol&0x8000) // sweep? + { + s16 sInc=1; // -> sweep up? + if(vol&0x2000) sInc=-1; // -> or down? + if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this + vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64 + vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half! + vol*=128; + vol&=0x3fff; + //puts("Sweep"); + } + else // no sweep: + { + if(vol&0x4000) + vol=(vol&0x3FFF)-0x4000; + else + vol&=0x3FFF; + + //if(vol&0x4000) // -> mmm... phase inverted? have to investigate this + // vol=0-(0x3fff-(vol&0x3fff)); + //else + // vol&=0x3fff; + } + if(right) + s_chan[ch].iRightVolume=vol; + else + s_chan[ch].iLeftVolume=vol; // store volume +} + +//////////////////////////////////////////////////////////////////////// +// PITCH register write +//////////////////////////////////////////////////////////////////////// + +static void SetPitch(int ch,u16 val) // SET PITCH +{ + int NP; + if(val>0x3fff) NP=0x3fff; // get pitch val + else NP=val; + + s_chan[ch].iRawPitch=NP; + + NP=(44100L*NP)/4096L; // calc frequency + if(NP<1) NP=1; // some security + s_chan[ch].iActFreq=NP; // store frequency +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/spu/registers.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,153 @@ +/*************************************************************************** + registers.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#define H_SPUReverbAddr 0x0da2 +#define H_SPUirqAddr 0x0da4 +#define H_SPUaddr 0x0da6 +#define H_SPUdata 0x0da8 +#define H_SPUctrl 0x0daa +#define H_SPUstat 0x0dae +#define H_SPUmvolL 0x0d80 +#define H_SPUmvolR 0x0d82 +#define H_SPUrvolL 0x0d84 +#define H_SPUrvolR 0x0d86 +#define H_SPUon1 0x0d88 +#define H_SPUon2 0x0d8a +#define H_SPUoff1 0x0d8c +#define H_SPUoff2 0x0d8e +#define H_FMod1 0x0d90 +#define H_FMod2 0x0d92 +#define H_Noise1 0x0d94 +#define H_Noise2 0x0d96 +#define H_RVBon1 0x0d98 +#define H_RVBon2 0x0d9a +#define H_SPUMute1 0x0d9c +#define H_SPUMute2 0x0d9e +#define H_CDLeft 0x0db0 +#define H_CDRight 0x0db2 +#define H_ExtLeft 0x0db4 +#define H_ExtRight 0x0db6 +#define H_Reverb 0x0dc0 +#define H_SPUPitch0 0x0c04 +#define H_SPUPitch1 0x0c14 +#define H_SPUPitch2 0x0c24 +#define H_SPUPitch3 0x0c34 +#define H_SPUPitch4 0x0c44 +#define H_SPUPitch5 0x0c54 +#define H_SPUPitch6 0x0c64 +#define H_SPUPitch7 0x0c74 +#define H_SPUPitch8 0x0c84 +#define H_SPUPitch9 0x0c94 +#define H_SPUPitch10 0x0ca4 +#define H_SPUPitch11 0x0cb4 +#define H_SPUPitch12 0x0cc4 +#define H_SPUPitch13 0x0cd4 +#define H_SPUPitch14 0x0ce4 +#define H_SPUPitch15 0x0cf4 +#define H_SPUPitch16 0x0d04 +#define H_SPUPitch17 0x0d14 +#define H_SPUPitch18 0x0d24 +#define H_SPUPitch19 0x0d34 +#define H_SPUPitch20 0x0d44 +#define H_SPUPitch21 0x0d54 +#define H_SPUPitch22 0x0d64 +#define H_SPUPitch23 0x0d74 + +#define H_SPUStartAdr0 0x0c06 +#define H_SPUStartAdr1 0x0c16 +#define H_SPUStartAdr2 0x0c26 +#define H_SPUStartAdr3 0x0c36 +#define H_SPUStartAdr4 0x0c46 +#define H_SPUStartAdr5 0x0c56 +#define H_SPUStartAdr6 0x0c66 +#define H_SPUStartAdr7 0x0c76 +#define H_SPUStartAdr8 0x0c86 +#define H_SPUStartAdr9 0x0c96 +#define H_SPUStartAdr10 0x0ca6 +#define H_SPUStartAdr11 0x0cb6 +#define H_SPUStartAdr12 0x0cc6 +#define H_SPUStartAdr13 0x0cd6 +#define H_SPUStartAdr14 0x0ce6 +#define H_SPUStartAdr15 0x0cf6 +#define H_SPUStartAdr16 0x0d06 +#define H_SPUStartAdr17 0x0d16 +#define H_SPUStartAdr18 0x0d26 +#define H_SPUStartAdr19 0x0d36 +#define H_SPUStartAdr20 0x0d46 +#define H_SPUStartAdr21 0x0d56 +#define H_SPUStartAdr22 0x0d66 +#define H_SPUStartAdr23 0x0d76 + +#define H_SPULoopAdr0 0x0c0e +#define H_SPULoopAdr1 0x0c1e +#define H_SPULoopAdr2 0x0c2e +#define H_SPULoopAdr3 0x0c3e +#define H_SPULoopAdr4 0x0c4e +#define H_SPULoopAdr5 0x0c5e +#define H_SPULoopAdr6 0x0c6e +#define H_SPULoopAdr7 0x0c7e +#define H_SPULoopAdr8 0x0c8e +#define H_SPULoopAdr9 0x0c9e +#define H_SPULoopAdr10 0x0cae +#define H_SPULoopAdr11 0x0cbe +#define H_SPULoopAdr12 0x0cce +#define H_SPULoopAdr13 0x0cde +#define H_SPULoopAdr14 0x0cee +#define H_SPULoopAdr15 0x0cfe +#define H_SPULoopAdr16 0x0d0e +#define H_SPULoopAdr17 0x0d1e +#define H_SPULoopAdr18 0x0d2e +#define H_SPULoopAdr19 0x0d3e +#define H_SPULoopAdr20 0x0d4e +#define H_SPULoopAdr21 0x0d5e +#define H_SPULoopAdr22 0x0d6e +#define H_SPULoopAdr23 0x0d7e + +#define H_SPU_ADSRLevel0 0x0c08 +#define H_SPU_ADSRLevel1 0x0c18 +#define H_SPU_ADSRLevel2 0x0c28 +#define H_SPU_ADSRLevel3 0x0c38 +#define H_SPU_ADSRLevel4 0x0c48 +#define H_SPU_ADSRLevel5 0x0c58 +#define H_SPU_ADSRLevel6 0x0c68 +#define H_SPU_ADSRLevel7 0x0c78 +#define H_SPU_ADSRLevel8 0x0c88 +#define H_SPU_ADSRLevel9 0x0c98 +#define H_SPU_ADSRLevel10 0x0ca8 +#define H_SPU_ADSRLevel11 0x0cb8 +#define H_SPU_ADSRLevel12 0x0cc8 +#define H_SPU_ADSRLevel13 0x0cd8 +#define H_SPU_ADSRLevel14 0x0ce8 +#define H_SPU_ADSRLevel15 0x0cf8 +#define H_SPU_ADSRLevel16 0x0d08 +#define H_SPU_ADSRLevel17 0x0d18 +#define H_SPU_ADSRLevel18 0x0d28 +#define H_SPU_ADSRLevel19 0x0d38 +#define H_SPU_ADSRLevel20 0x0d48 +#define H_SPU_ADSRLevel21 0x0d58 +#define H_SPU_ADSRLevel22 0x0d68 +#define H_SPU_ADSRLevel23 0x0d78 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/spu/regs.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,34 @@ +/*************************************************************************** + regs.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +static void SoundOn(int start,int end,u16 val); +static void SoundOff(int start,int end,u16 val); +static void FModOn(int start,int end,u16 val); +static void NoiseOn(int start,int end,u16 val); +static void SetVolumeLR(int right, u8 ch,s16 vol); +static void SetPitch(int ch,u16 val); +void SPUwriteRegister(u32 reg, u16 val);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/spu/reverb.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,383 @@ +/*************************************************************************** + reverb.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/03/17 - xodnizel +// - Implemented Neill's 44.1Khz-22050Hz downsampling data +// I also need to check if the ~4 sample delay doesn't screw any sounds +// up by making things too out of phase. It could be fixed easily(elsewhere). +// +// 2003/01/19 - Pete +// - added Neill's reverb (see at the end of file) +// +// 2002/12/26 - Pete +// - adjusted reverb handling +// +// 2002/08/14 - Pete +// - added extra reverb +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#define _IN_REVERB + +// will be included from spu.c +#ifdef _IN_SPU + +//////////////////////////////////////////////////////////////////////// +// globals +//////////////////////////////////////////////////////////////////////// + +// REVERB info and timing vars... + +//////////////////////////////////////////////////////////////////////// + +static INLINE s64 g_buffer(int iOff) // get_buffer content helper: takes care about wraps +{ + s16 * p=(s16 *)spuMem; + iOff=(iOff*4)+rvb.CurrAddr; + while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000); + while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff); + return (int)(s16)BFLIP16(*(p+iOff)); +} + +//////////////////////////////////////////////////////////////////////// + +static INLINE void s_buffer(int iOff,int iVal) // set_buffer content helper: takes care about wraps and clipping +{ + s16 * p=(s16 *)spuMem; + iOff=(iOff*4)+rvb.CurrAddr; + while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000); + while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff); + if(iVal<-32768L) iVal=-32768L; + if(iVal>32767L) iVal=32767L; + *(p+iOff)=(s16)BFLIP16((s16)iVal); +} + +//////////////////////////////////////////////////////////////////////// + +static INLINE void s_buffer1(int iOff,int iVal) // set_buffer (+1 sample) content helper: takes care about wraps and clipping +{ + s16 * p=(s16 *)spuMem; + iOff=(iOff*4)+rvb.CurrAddr+1; + while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000); + while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff); + if(iVal<-32768L) iVal=-32768L;if(iVal>32767L) iVal=32767L; + *(p+iOff)=(s16)BFLIP16((s16)iVal); +} + +static INLINE void MixREVERBLeftRight(s32 *oleft, s32 *oright, s32 inleft, s32 inright) +{ + static s32 downbuf[2][8]; + static s32 upbuf[2][8]; + static int dbpos=0,ubpos=0; + static s32 downcoeffs[8]={ /* Symmetry is sexy. */ + 1283,5344,10895,15243, + 15243,10895,5344,1283 + }; + int x; + + if(!rvb.StartAddr) // reverb is off + { + rvb.iRVBLeft=rvb.iRVBRight=0; + return; + } + + //if(inleft<-32767 || inleft>32767) printf("%d\n",inleft); + //if(inright<-32767 || inright>32767) printf("%d\n",inright); + downbuf[0][dbpos]=inleft; + downbuf[1][dbpos]=inright; + dbpos=(dbpos+1)&7; + + if(dbpos&1) // we work on every second left value: downsample to 22 khz + { + if(spuCtrl&0x80) // -> reverb on? oki + { + int ACC0,ACC1,FB_A0,FB_A1,FB_B0,FB_B1; + s32 INPUT_SAMPLE_L=0; + s32 INPUT_SAMPLE_R=0; + + for(x=0;x<8;x++) + { + INPUT_SAMPLE_L+=(downbuf[0][(dbpos+x)&7]*downcoeffs[x])>>8; /* Lose insignificant + digits to prevent + overflow(check this) */ + INPUT_SAMPLE_R+=(downbuf[1][(dbpos+x)&7]*downcoeffs[x])>>8; + } + + INPUT_SAMPLE_L>>=(16-8); + INPUT_SAMPLE_R>>=(16-8); + { + const s64 IIR_INPUT_A0 = ((g_buffer(rvb.IIR_SRC_A0) * rvb.IIR_COEF)>>15) + ((INPUT_SAMPLE_L * rvb.IN_COEF_L)>>15); + const s64 IIR_INPUT_A1 = ((g_buffer(rvb.IIR_SRC_A1) * rvb.IIR_COEF)>>15) + ((INPUT_SAMPLE_R * rvb.IN_COEF_R)>>15); + const s64 IIR_INPUT_B0 = ((g_buffer(rvb.IIR_SRC_B0) * rvb.IIR_COEF)>>15) + ((INPUT_SAMPLE_L * rvb.IN_COEF_L)>>15); + const s64 IIR_INPUT_B1 = ((g_buffer(rvb.IIR_SRC_B1) * rvb.IIR_COEF)>>15) + ((INPUT_SAMPLE_R * rvb.IN_COEF_R)>>15); + const s64 IIR_A0 = ((IIR_INPUT_A0 * rvb.IIR_ALPHA)>>15) + ((g_buffer(rvb.IIR_DEST_A0) * (32768L - rvb.IIR_ALPHA))>>15); + const s64 IIR_A1 = ((IIR_INPUT_A1 * rvb.IIR_ALPHA)>>15) + ((g_buffer(rvb.IIR_DEST_A1) * (32768L - rvb.IIR_ALPHA))>>15); + const s64 IIR_B0 = ((IIR_INPUT_B0 * rvb.IIR_ALPHA)>>15) + ((g_buffer(rvb.IIR_DEST_B0) * (32768L - rvb.IIR_ALPHA))>>15); + const s64 IIR_B1 = ((IIR_INPUT_B1 * rvb.IIR_ALPHA)>>15) + ((g_buffer(rvb.IIR_DEST_B1) * (32768L - rvb.IIR_ALPHA))>>15); + + s_buffer1(rvb.IIR_DEST_A0, IIR_A0); + s_buffer1(rvb.IIR_DEST_A1, IIR_A1); + s_buffer1(rvb.IIR_DEST_B0, IIR_B0); + s_buffer1(rvb.IIR_DEST_B1, IIR_B1); + + ACC0 = ((g_buffer(rvb.ACC_SRC_A0) * rvb.ACC_COEF_A)>>15) + + ((g_buffer(rvb.ACC_SRC_B0) * rvb.ACC_COEF_B)>>15) + + ((g_buffer(rvb.ACC_SRC_C0) * rvb.ACC_COEF_C)>>15) + + ((g_buffer(rvb.ACC_SRC_D0) * rvb.ACC_COEF_D)>>15); + ACC1 = ((g_buffer(rvb.ACC_SRC_A1) * rvb.ACC_COEF_A)>>15) + + ((g_buffer(rvb.ACC_SRC_B1) * rvb.ACC_COEF_B)>>15) + + ((g_buffer(rvb.ACC_SRC_C1) * rvb.ACC_COEF_C)>>15) + + ((g_buffer(rvb.ACC_SRC_D1) * rvb.ACC_COEF_D)>>15); + + FB_A0 = g_buffer(rvb.MIX_DEST_A0 - rvb.FB_SRC_A); + FB_A1 = g_buffer(rvb.MIX_DEST_A1 - rvb.FB_SRC_A); + FB_B0 = g_buffer(rvb.MIX_DEST_B0 - rvb.FB_SRC_B); + FB_B1 = g_buffer(rvb.MIX_DEST_B1 - rvb.FB_SRC_B); + + s_buffer(rvb.MIX_DEST_A0, ACC0 - ((FB_A0 * rvb.FB_ALPHA)>>15)); + s_buffer(rvb.MIX_DEST_A1, ACC1 - ((FB_A1 * rvb.FB_ALPHA)>>15)); + + s_buffer(rvb.MIX_DEST_B0, ((rvb.FB_ALPHA * ACC0)>>15) - ((FB_A0 * (int)(rvb.FB_ALPHA^0xFFFF8000))>>15) - ((FB_B0 * rvb.FB_X)>>15)); + s_buffer(rvb.MIX_DEST_B1, ((rvb.FB_ALPHA * ACC1)>>15) - ((FB_A1 * (int)(rvb.FB_ALPHA^0xFFFF8000))>>15) - ((FB_B1 * rvb.FB_X)>>15)); + + rvb.iRVBLeft = (g_buffer(rvb.MIX_DEST_A0)+g_buffer(rvb.MIX_DEST_B0))/3; + rvb.iRVBRight = (g_buffer(rvb.MIX_DEST_A1)+g_buffer(rvb.MIX_DEST_B1))/3; + + rvb.iRVBLeft = ((s64)rvb.iRVBLeft * rvb.VolLeft) >> 14; + rvb.iRVBRight = ((s64)rvb.iRVBRight * rvb.VolRight) >> 14; + + upbuf[0][ubpos]=rvb.iRVBLeft; + upbuf[1][ubpos]=rvb.iRVBRight; + ubpos=(ubpos+1)&7; + } // Bracket hack(et). + } + else // -> reverb off + { + rvb.iRVBLeft=rvb.iRVBRight=0; + return; + } + rvb.CurrAddr++; + if(rvb.CurrAddr>0x3ffff) rvb.CurrAddr=rvb.StartAddr; + } + else + { + upbuf[0][ubpos]=0; + upbuf[1][ubpos]=0; + ubpos=(ubpos+1)&7; + } + { + s32 retl=0,retr=0; + for(x=0;x<8;x++) + { + retl+=(upbuf[0][(ubpos+x)&7]*downcoeffs[x])>>8; + retr+=(upbuf[1][(ubpos+x)&7]*downcoeffs[x])>>8; + } + retl>>=(16-8-1); /* -1 To adjust for the null padding. */ + retr>>=(16-8-1); + + *oleft+=retl; + *oright+=retr; + } +} + +//////////////////////////////////////////////////////////////////////// + +#endif + +/* +----------------------------------------------------------------------------- +PSX reverb hardware notes +by Neill Corlett +----------------------------------------------------------------------------- + +Yadda yadda disclaimer yadda probably not perfect yadda well it's okay anyway +yadda yadda. + +----------------------------------------------------------------------------- + +Basics +------ + +- The reverb buffer is 22khz 16-bit mono PCM. +- It starts at the reverb address given by 1DA2, extends to + the end of sound RAM, and wraps back to the 1DA2 address. + +Setting the address at 1DA2 resets the current reverb work address. + +This work address ALWAYS increments every 1/22050 sec., regardless of +whether reverb is enabled (bit 7 of 1DAA set). + +And the contents of the reverb buffer ALWAYS play, scaled by the +"reverberation depth left/right" volumes (1D84/1D86). +(which, by the way, appear to be scaled so 3FFF=approx. 1.0, 4000=-1.0) + +----------------------------------------------------------------------------- + +Register names +-------------- + +These are probably not their real names. +These are probably not even correct names. +We will use them anyway, because we can. + +1DC0: FB_SRC_A (offset) +1DC2: FB_SRC_B (offset) +1DC4: IIR_ALPHA (coef.) +1DC6: ACC_COEF_A (coef.) +1DC8: ACC_COEF_B (coef.) +1DCA: ACC_COEF_C (coef.) +1DCC: ACC_COEF_D (coef.) +1DCE: IIR_COEF (coef.) +1DD0: FB_ALPHA (coef.) +1DD2: FB_X (coef.) +1DD4: IIR_DEST_A0 (offset) +1DD6: IIR_DEST_A1 (offset) +1DD8: ACC_SRC_A0 (offset) +1DDA: ACC_SRC_A1 (offset) +1DDC: ACC_SRC_B0 (offset) +1DDE: ACC_SRC_B1 (offset) +1DE0: IIR_SRC_A0 (offset) +1DE2: IIR_SRC_A1 (offset) +1DE4: IIR_DEST_B0 (offset) +1DE6: IIR_DEST_B1 (offset) +1DE8: ACC_SRC_C0 (offset) +1DEA: ACC_SRC_C1 (offset) +1DEC: ACC_SRC_D0 (offset) +1DEE: ACC_SRC_D1 (offset) +1DF0: IIR_SRC_B1 (offset) +1DF2: IIR_SRC_B0 (offset) +1DF4: MIX_DEST_A0 (offset) +1DF6: MIX_DEST_A1 (offset) +1DF8: MIX_DEST_B0 (offset) +1DFA: MIX_DEST_B1 (offset) +1DFC: IN_COEF_L (coef.) +1DFE: IN_COEF_R (coef.) + +The coefficients are signed fractional values. +-32768 would be -1.0 + 32768 would be 1.0 (if it were possible... the highest is of course 32767) + +The offsets are (byte/8) offsets into the reverb buffer. +i.e. you multiply them by 8, you get byte offsets. +You can also think of them as (samples/4) offsets. +They appear to be signed. They can be negative. +None of the documented presets make them negative, though. + +Yes, 1DF0 and 1DF2 appear to be backwards. Not a typo. + +----------------------------------------------------------------------------- + +What it does +------------ + +We take all reverb sources: +- regular channels that have the reverb bit on +- cd and external sources, if their reverb bits are on +and mix them into one stereo 44100hz signal. + +Lowpass/downsample that to 22050hz. The PSX uses a proper bandlimiting +algorithm here, but I haven't figured out the hysterically exact specifics. +I use an 8-tap filter with these coefficients, which are nice but probably +not the real ones: + +0.037828187894 +0.157538631280 +0.321159685278 +0.449322115345 +0.449322115345 +0.321159685278 +0.157538631280 +0.037828187894 + +So we have two input samples (INPUT_SAMPLE_L, INPUT_SAMPLE_R) every 22050hz. + +* IN MY EMULATION, I divide these by 2 to make it clip less. + (and of course the L/R output coefficients are adjusted to compensate) + The real thing appears to not do this. + +At every 22050hz tick: +- If the reverb bit is enabled (bit 7 of 1DAA), execute the reverb + steady-state algorithm described below +- AFTERWARDS, retrieve the "wet out" L and R samples from the reverb buffer + (This part may not be exactly right and I guessed at the coefs. TODO: check later.) + L is: 0.333 * (buffer[MIX_DEST_A0] + buffer[MIX_DEST_B0]) + R is: 0.333 * (buffer[MIX_DEST_A1] + buffer[MIX_DEST_B1]) +- Advance the current buffer position by 1 sample + +The wet out L and R are then upsampled to 44100hz and played at the +"reverberation depth left/right" (1D84/1D86) volume, independent of the main +volume. + +----------------------------------------------------------------------------- + +Reverb steady-state +------------------- + +The reverb steady-state algorithm is fairly clever, and of course by +"clever" I mean "batshit insane". + +buffer[x] is relative to the current buffer position, not the beginning of +the buffer. Note that all buffer offsets must wrap around so they're +contained within the reverb work area. + +Clipping is performed at the end... maybe also sooner, but definitely at +the end. + +IIR_INPUT_A0 = buffer[IIR_SRC_A0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L; +IIR_INPUT_A1 = buffer[IIR_SRC_A1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R; +IIR_INPUT_B0 = buffer[IIR_SRC_B0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L; +IIR_INPUT_B1 = buffer[IIR_SRC_B1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R; + +IIR_A0 = IIR_INPUT_A0 * IIR_ALPHA + buffer[IIR_DEST_A0] * (1.0 - IIR_ALPHA); +IIR_A1 = IIR_INPUT_A1 * IIR_ALPHA + buffer[IIR_DEST_A1] * (1.0 - IIR_ALPHA); +IIR_B0 = IIR_INPUT_B0 * IIR_ALPHA + buffer[IIR_DEST_B0] * (1.0 - IIR_ALPHA); +IIR_B1 = IIR_INPUT_B1 * IIR_ALPHA + buffer[IIR_DEST_B1] * (1.0 - IIR_ALPHA); + +buffer[IIR_DEST_A0 + 1sample] = IIR_A0; +buffer[IIR_DEST_A1 + 1sample] = IIR_A1; +buffer[IIR_DEST_B0 + 1sample] = IIR_B0; +buffer[IIR_DEST_B1 + 1sample] = IIR_B1; + +ACC0 = buffer[ACC_SRC_A0] * ACC_COEF_A + + buffer[ACC_SRC_B0] * ACC_COEF_B + + buffer[ACC_SRC_C0] * ACC_COEF_C + + buffer[ACC_SRC_D0] * ACC_COEF_D; +ACC1 = buffer[ACC_SRC_A1] * ACC_COEF_A + + buffer[ACC_SRC_B1] * ACC_COEF_B + + buffer[ACC_SRC_C1] * ACC_COEF_C + + buffer[ACC_SRC_D1] * ACC_COEF_D; + +FB_A0 = buffer[MIX_DEST_A0 - FB_SRC_A]; +FB_A1 = buffer[MIX_DEST_A1 - FB_SRC_A]; +FB_B0 = buffer[MIX_DEST_B0 - FB_SRC_B]; +FB_B1 = buffer[MIX_DEST_B1 - FB_SRC_B]; + +buffer[MIX_DEST_A0] = ACC0 - FB_A0 * FB_ALPHA; +buffer[MIX_DEST_A1] = ACC1 - FB_A1 * FB_ALPHA; +buffer[MIX_DEST_B0] = (FB_ALPHA * ACC0) - FB_A0 * (FB_ALPHA^0x8000) - FB_B0 * FB_X; +buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB_X; + +----------------------------------------------------------------------------- +*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/spu/spu.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,637 @@ +/*************************************************************************** + spu.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2003/03/01 - linuzappz +// - libraryName changes using ALSA +// +// 2003/02/28 - Pete +// - added option for type of interpolation +// - adjusted spu irqs again (Thousant Arms, Valkyrie Profile) +// - added MONO support for MSWindows DirectSound +// +// 2003/02/20 - kode54 +// - amended interpolation code, goto GOON could skip initialization of gpos and cause segfault +// +// 2003/02/19 - kode54 +// - moved SPU IRQ handler and changed sample flag processing +// +// 2003/02/18 - kode54 +// - moved ADSR calculation outside of the sample decode loop, somehow I doubt that +// ADSR timing is relative to the frequency at which a sample is played... I guess +// this remains to be seen, and I don't know whether ADSR is applied to noise channels... +// +// 2003/02/09 - kode54 +// - one-shot samples now process the end block before stopping +// - in light of removing fmod hack, now processing ADSR on frequency channel as well +// +// 2003/02/08 - kode54 +// - replaced easy interpolation with gaussian +// - removed fmod averaging hack +// - changed .sinc to be updated from .iRawPitch, no idea why it wasn't done this way already (<- Pete: because I sometimes fail to see the obvious, haharhar :) +// +// 2003/02/08 - linuzappz +// - small bugfix for one usleep that was 1 instead of 1000 +// - added iDisStereo for no stereo (Linux) +// +// 2003/01/22 - Pete +// - added easy interpolation & small noise adjustments +// +// 2003/01/19 - Pete +// - added Neill's reverb +// +// 2003/01/12 - Pete +// - added recording window handlers +// +// 2003/01/06 - Pete +// - added Neill's ADSR timings +// +// 2002/12/28 - Pete +// - adjusted spu irq handling, fmod handling and loop handling +// +// 2002/08/14 - Pete +// - added extra reverb +// +// 2002/06/08 - linuzappz +// - SPUupdate changed for SPUasync +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#define _IN_SPU + +#include "stdafx.h" +#include "externals.h" +#include "spu.h" +#include "regs.h" +#include "registers.h" + +#include "PsxMem.h" +#include "driver.h" + +//////////////////////////////////////////////////////////////////////// +// globals +//////////////////////////////////////////////////////////////////////// + +// psx buffer / addresses + +static u16 regArea[0x200]; +static u16 spuMem[256*1024]; +static u8 * spuMemC; +static u8 * pSpuIrq=0; +static u8 * pSpuBuffer; + +// user settings +static int iVolume; + +// MAIN infos struct for each channel + +static SPUCHAN s_chan[MAXCHAN+1]; // channel + 1 infos (1 is security for fmod handling) +static REVERBInfo rvb; + +static u32 dwNoiseVal=1; // global noise generator + +static u16 spuCtrl=0; // some vars to store psx reg infos +static u16 spuStat=0; +static u16 spuIrq=0; +static u32 spuAddr=0xffffffff; // address into spu mem +static int bSPUIsOpen=0; + +static const int f[5][2] = { + { 0, 0 }, + { 60, 0 }, + { 115, -52 }, + { 98, -55 }, + { 122, -60 } }; +s16 * pS; + +//////////////////////////////////////////////////////////////////////// +// CODE AREA +//////////////////////////////////////////////////////////////////////// + +// dirty inline func includes + +#include "reverb.c" +#include "adsr.c" + +// Try this to increase speed. +#include "registers.c" +#include "dma.c" + +//////////////////////////////////////////////////////////////////////// +// helpers for so-called "gauss interpolation" + +#define gval0 (((int *)(&s_chan[ch].SB[29]))[gpos]) +#define gval(x) (((int *)(&s_chan[ch].SB[29]))[(gpos+x)&3]) + +#include "gauss_i.h" + +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// START SOUND... called by main thread to setup a new sound on a channel +//////////////////////////////////////////////////////////////////////// + +static INLINE void StartSound(int ch) +{ + StartADSR(ch); + + s_chan[ch].pCurr=s_chan[ch].pStart; // set sample start + + s_chan[ch].s_1=0; // init mixing vars + s_chan[ch].s_2=0; + s_chan[ch].iSBPos=28; + + s_chan[ch].bNew=0; // init channel flags + s_chan[ch].bStop=0; + s_chan[ch].bOn=1; + + s_chan[ch].SB[29]=0; // init our interpolation helpers + s_chan[ch].SB[30]=0; + + s_chan[ch].spos=0x40000L;s_chan[ch].SB[28]=0; // -> start with more decoding +} + +//////////////////////////////////////////////////////////////////////// +// MAIN SPU FUNCTION +// here is the main job handler... thread, timer or direct func call +// basically the whole sound processing is done in this fat func! +//////////////////////////////////////////////////////////////////////// + +static u32 sampcount; +static u32 decaybegin; +static u32 decayend; + +// Counting to 65536 results in full volume offage. +void SPUsetlength(s32 stop, s32 fade) +{ + if(stop==~0) + { + decaybegin=~0; + } + else + { + stop=(stop*441)/10; + fade=(fade*441)/10; + + decaybegin=stop; + decayend=stop+fade; + } +} + +static u32 seektime; +static s32 poo; +int sexypsf_seek(u32 t) +{ + seektime=t*441/10; + if(seektime>sampcount) return(1); + return(0); +} + +#define CLIP(_x) {if(_x>32767) _x=32767; if(_x<-32767) _x=-32767;} +int SPUasync(u32 cycles) +{ + int volmul=iVolume; + static s32 dosampies; + s32 temp; + + poo+=cycles; + dosampies=poo/384; + if(!dosampies) return(1); + poo-=dosampies*384; + temp=dosampies; + + while(temp) + { + s32 revLeft=0, revRight=0; + s32 sl=0, sr=0; + int ch,fa; + + temp--; + //--------------------------------------------------// + //- main channel loop -// + //--------------------------------------------------// + { + for(ch=0;ch<MAXCHAN;ch++) // loop em all. + { + if(s_chan[ch].bNew) StartSound(ch); // start new sound + if(!s_chan[ch].bOn) continue; // channel not playing? next + + + if(s_chan[ch].iActFreq!=s_chan[ch].iUsedFreq) // new psx frequency? + { + s_chan[ch].iUsedFreq=s_chan[ch].iActFreq; // -> take it and calc steps + s_chan[ch].sinc=s_chan[ch].iRawPitch<<4; + if(!s_chan[ch].sinc) s_chan[ch].sinc=1; + } + + while(s_chan[ch].spos>=0x10000L) + { + if(s_chan[ch].iSBPos==28) // 28 reached? + { + int predict_nr,shift_factor,flags,d,s; + u8* start;unsigned int nSample; + int s_1,s_2; + + start=s_chan[ch].pCurr; // set up the current pos + + if (start == (u8*)-1) // special "stop" sign + { + s_chan[ch].bOn=0; // -> turn everything off + s_chan[ch].ADSRX.lVolume=0; + s_chan[ch].ADSRX.EnvelopeVol=0; + goto ENDX; // -> and done for this channel + } + + s_chan[ch].iSBPos=0; // Reset buffer play index. + + //////////////////////////////////////////// spu irq handler here? mmm... do it later + + s_1=s_chan[ch].s_1; + s_2=s_chan[ch].s_2; + + predict_nr=(int)*start;start++; + shift_factor=predict_nr&0xf; + predict_nr >>= 4; + flags=(int)*start;start++; + + // -------------------------------------- // + // Decode new samples into s_chan[ch].SB[0 through 27] + for (nSample=0;nSample<28;start++) + { + d=(int)*start; + s=((d&0xf)<<12); + if(s&0x8000) s|=0xffff0000; + + fa=(s >> shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1;s_1=fa; + s=((d & 0xf0) << 8); + + s_chan[ch].SB[nSample++]=fa; + + if(s&0x8000) s|=0xffff0000; + fa=(s>>shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1;s_1=fa; + + s_chan[ch].SB[nSample++]=fa; + } + + //////////////////////////////////////////// irq check + + if(spuCtrl&0x40) // irq active? + { + if((pSpuIrq > start-16 && // irq address reached? + pSpuIrq <= start) || + ((flags&1) && // special: irq on looping addr, when stop/loop flag is set + (pSpuIrq > s_chan[ch].pLoop-16 && + pSpuIrq <= s_chan[ch].pLoop))) + { + //extern s32 spuirqvoodoo; + s_chan[ch].iIrqDone=1; // -> debug flag + SPUirq(); + //puts("IRQ"); + //if(spuirqvoodoo!=-1) + //{ + // spuirqvoodoo=temp*384; + // temp=0; + //} + } + } + + //////////////////////////////////////////// flag handler + + if((flags&4) && (!s_chan[ch].bIgnoreLoop)) + s_chan[ch].pLoop=start-16; // loop adress + + if(flags&1) // 1: stop/loop + { + // We play this block out first... + //if(!(flags&2)) // 1+2: do loop... otherwise: stop + if(flags!=3 || s_chan[ch].pLoop==NULL) // PETE: if we don't check exactly for 3, loop hang ups will happen (DQ4, for example) + { // and checking if pLoop is set avoids crashes, yeah + start = (u8*)-1; + } + else + { + start = s_chan[ch].pLoop; + } + } + + s_chan[ch].pCurr=start; // store values for next cycle + s_chan[ch].s_1=s_1; + s_chan[ch].s_2=s_2; + + //////////////////////////////////////////// + } + + fa=s_chan[ch].SB[s_chan[ch].iSBPos++]; // get sample data + + if((spuCtrl&0x4000)==0) fa=0; // muted? + else CLIP(fa); + + { + int gpos; + gpos = s_chan[ch].SB[28]; + gval0 = fa; + gpos = (gpos+1) & 3; + s_chan[ch].SB[28] = gpos; + } + s_chan[ch].spos -= 0x10000L; + } + + //////////////////////////////////////////////// + // noise handler... just produces some noise data + // surely wrong... and no noise frequency (spuCtrl&0x3f00) will be used... + // and sometimes the noise will be used as fmod modulation... pfff + + if(s_chan[ch].bNoise) + { + //puts("Noise"); + if((dwNoiseVal<<=1)&0x80000000L) + { + dwNoiseVal^=0x0040001L; + fa=((dwNoiseVal>>2)&0x7fff); + fa=-fa; + } + else fa=(dwNoiseVal>>2)&0x7fff; + + // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val + fa=s_chan[ch].iOldNoise+((fa-s_chan[ch].iOldNoise)/((0x001f-((spuCtrl&0x3f00)>>9))+1)); + if(fa>32767L) fa=32767L; + if(fa<-32767L) fa=-32767L; + s_chan[ch].iOldNoise=fa; + + } //---------------------------------------- + else // NO NOISE (NORMAL SAMPLE DATA) HERE + { + int vl, vr, gpos; + vl = (s_chan[ch].spos >> 6) & ~3; + gpos = s_chan[ch].SB[28]; + vr=(gauss[vl]*gval0)>>9; + vr+=(gauss[vl+1]*gval(1))>>9; + vr+=(gauss[vl+2]*gval(2))>>9; + vr+=(gauss[vl+3]*gval(3))>>9; + fa = vr>>2; + } + + s_chan[ch].sval = (MixADSR(ch) * fa)>>10; // / 1023; // add adsr + if(s_chan[ch].bFMod==2) // fmod freq channel + { + int NP=s_chan[ch+1].iRawPitch; + NP=((32768L+s_chan[ch].sval)*NP)>>15; ///32768L; + + if(NP>0x3fff) NP=0x3fff; + if(NP<0x1) NP=0x1; + + // mmmm... if I do this, all is screwed + // s_chan[ch+1].iRawPitch=NP; + + NP=(44100L*NP)/(4096L); // calc frequency + + s_chan[ch+1].iActFreq=NP; + s_chan[ch+1].iUsedFreq=NP; + s_chan[ch+1].sinc=(((NP/10)<<16)/4410); + if(!s_chan[ch+1].sinc) s_chan[ch+1].sinc=1; + + // mmmm... set up freq decoding positions? + // s_chan[ch+1].iSBPos=28; + // s_chan[ch+1].spos=0x10000L; + } + else + { + ////////////////////////////////////////////// + // ok, left/right sound volume (psx volume goes from 0 ... 0x3fff) + int tmpl,tmpr; + + tmpl=(s_chan[ch].sval*s_chan[ch].iLeftVolume)>>14; + tmpr=(s_chan[ch].sval*s_chan[ch].iRightVolume)>>14; + + sl+=tmpl; + sr+=tmpr; + + if(((rvb.Enabled>>ch)&1) && (spuCtrl&0x80)) + { + revLeft+=tmpl; + revRight+=tmpr; + } + } + + s_chan[ch].spos += s_chan[ch].sinc; + ENDX: ; + } + } + + /////////////////////////////////////////////////////// + // mix all channels (including reverb) into one buffer + MixREVERBLeftRight(&sl,&sr,revLeft,revRight); + if(sampcount>=decaybegin) + { + s32 dmul; + if(decaybegin!=(u32)~0) // Is anyone REALLY going to be playing a song + // for 13 hours? + { + if(sampcount>=decayend) return(0); + dmul=256-(256*(sampcount-decaybegin)/(decayend-decaybegin)); + sl=(sl*dmul)>>8; + sr=(sr*dmul)>>8; + } + } + sampcount++; + sl=(sl*volmul)>>8; + sr=(sr*volmul)>>8; + + //{ + // static double asl=0; + // static double asr=0; + + // asl+=(sl-asl)/5; + // asr+=(sl-asr)/5; + + //sl-=asl; + //sr-=asr; + + // if(sl>32767 || sl < -32767) printf("Left: %d, %f\n",sl,asl); + // if(sr>32767 || sr < -32767) printf("Right: %d, %f\n",sl,asl); + //} + + if(sl>32767) sl=32767; if(sl<-32767) sl=-32767; + if(sr>32767) sr=32767; if(sr<-32767) sr=-32767; + *pS++=sl; + *pS++=sr; + } + + return(1); +} + +void sexypsf_stop(void) +{ + decaybegin=decayend=0; +} + +void SPUendflush(void) +{ + if((seektime!=(u32)~0) && seektime>sampcount) + { + pS=(s16 *)pSpuBuffer; + sexypsf_update(0,0); + } + else if((u8*)pS>((u8*)pSpuBuffer+1024)) + { + sexypsf_update((u8*)pSpuBuffer,(u8*)pS-(u8*)pSpuBuffer); + pS=(s16 *)pSpuBuffer; + } +} + +#ifdef TIMEO +static u64 begintime; +static u64 SexyTime64(void) +{ + struct timeval tv; + u64 ret; + + gettimeofday(&tv,0); + ret=tv.tv_sec; + ret*=1000000; + ret+=tv.tv_usec; + return(ret); +} +#endif +//////////////////////////////////////////////////////////////////////// +// INIT/EXIT STUFF +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// SPUINIT: this func will be called first by the main emu +//////////////////////////////////////////////////////////////////////// + +int SPUinit(void) +{ + spuMemC=(u8*)spuMem; // just small setup + memset((void *)s_chan,0,MAXCHAN*sizeof(SPUCHAN)); + memset((void *)&rvb,0,sizeof(REVERBInfo)); + memset(regArea,0,sizeof(regArea)); + memset(spuMem,0,sizeof(spuMem)); + InitADSR(); + sampcount=poo=0; + seektime=(u32)~0; + #ifdef TIMEO + begintime=SexyTime64(); + #endif + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// SETUPSTREAMS: init most of the spu buffers +//////////////////////////////////////////////////////////////////////// + +void SetupStreams(void) +{ + int i; + + pSpuBuffer=(u8*)malloc(32768); // alloc mixing buffer + pS=(s16 *)pSpuBuffer; + + for(i=0;i<MAXCHAN;i++) // loop sound channels + { + s_chan[i].ADSRX.SustainLevel = 1024; // -> init sustain + s_chan[i].iIrqDone=0; + s_chan[i].pLoop=spuMemC; + s_chan[i].pStart=spuMemC; + s_chan[i].pCurr=spuMemC; + } +} + +//////////////////////////////////////////////////////////////////////// +// REMOVESTREAMS: free most buffer +//////////////////////////////////////////////////////////////////////// + +void RemoveStreams(void) +{ + free(pSpuBuffer); // free mixing buffer + pSpuBuffer=NULL; + + #ifdef TIMEO + { + u64 tmp; + tmp=SexyTime64(); + tmp-=begintime; + if(tmp) + tmp=(u64)sampcount*1000000/tmp; + printf("%lld samples per second\n",tmp); + } + #endif +} + + +//////////////////////////////////////////////////////////////////////// +// SPUOPEN: called by main emu after init +//////////////////////////////////////////////////////////////////////// + +int SPUopen(void) +{ + if(bSPUIsOpen) return 0; // security for some stupid main emus + spuIrq=0; + + spuStat=spuCtrl=0; + spuAddr=0xffffffff; + dwNoiseVal=1; + + spuMemC=(u8*)spuMem; + memset((void *)s_chan,0,(MAXCHAN+1)*sizeof(SPUCHAN)); + pSpuIrq=0; + + iVolume=128; //85; + SetupStreams(); // prepare streaming + + bSPUIsOpen=1; + + return 1; +} + +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// SPUCLOSE: called before shutdown +//////////////////////////////////////////////////////////////////////// + +int SPUclose(void) +{ + if(!bSPUIsOpen) return 0; // some security + + bSPUIsOpen=0; // no more open + + RemoveStreams(); // no more streaming + + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// SPUSHUTDOWN: called by main emu on final exit +//////////////////////////////////////////////////////////////////////// + +int SPUshutdown(void) +{ + return 0; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/spu/spu.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,8 @@ +int SPUinit(void); +int SPUopen(void); +void SPUsetlength(s32 stop, s32 fade); +int SPUclose(void); +void SPUendflush(void); + +// External, called by SPU code. +void SPUirq(void);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/spu/stdafx.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,31 @@ +/*************************************************************************** + StdAfx.h - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/05/15 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#define INLINE inline
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/types.h Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,23 @@ +#ifndef _SPSF_TYPES_H__ +#define _SPSF_TYPES_H__ + +#include <inttypes.h> + +#define INLINE inline + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + + + +/* For gcc only? */ +#define PACKSTRUCT __attribute__ ((packed)) + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Input/sexypsf/xmms.c Sun Mar 19 13:21:35 2006 -0800 @@ -0,0 +1,283 @@ +/* sexyPSF - PSF1 player + * Copyright (C) 2002-2004 xodnizel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "audacious/output.h" +#include "audacious/plugin.h" +#include "libaudacious/titlestring.h" +#include "libaudacious/util.h" +#include "libaudacious/vfs.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "driver.h" + +#define CMD_SEEK 0x80000000 +#define CMD_STOP 0x40000000 + +#define uint32 u32 +#define int16 short + +static volatile uint32 command; +static volatile int playing=0; +static volatile int nextsong=0; + +extern InputPlugin sexypsf_ip; +static char *fnsave=NULL; + +static gchar *get_title_psf(gchar *fn); +static int paused; +static GThread *dethread; +static PSFINFO *PSFInfo=NULL; + + +InputPlugin *get_iplugin_info(void) + { + sexypsf_ip.description = "sexyPSF PSF1 Player 0.4.8"; + return &sexypsf_ip; + } + +static int is_our_file(gchar *filename) { + VFSFile *file; + gchar magic[4]; + + // Filter out psflib [we use them, but we can't play them] + gchar *tmps; + static const gchar *teststr = "psflib"; + if (strlen(teststr) < strlen(filename)) { + tmps = filename + strlen(filename); + tmps -= strlen(teststr); + if (!strcasecmp(tmps, teststr)) + return 0; + } + if ((file = vfs_fopen(filename,"rb"))) { + vfs_fread(magic,1,4,file); + //Only allow PSF1 for now. + if (!strncmp(magic,"PSF\x01",4)) { + vfs_fclose(file); + return 1; + } + } + return 0; +} + +static void SI(gchar *filename) +{ + gchar *name = get_title_psf(filename); + sexypsf_ip.set_info(name,PSFInfo->length,44100*2*2*8,44100,2); + g_free(name); +} + +void sexypsf_update(unsigned char *Buffer, long count) +{ + int mask = ~((((16 / 8) * 2)) - 1); + + while(count>0) + { + int t=sexypsf_ip.output->buffer_free() & mask; + if(t>count) + produce_audio(sexypsf_ip.output->written_time(), FMT_S16_NE, 2, count, Buffer, NULL); + else + { + if(t) + produce_audio(sexypsf_ip.output->written_time(), FMT_S16_NE, 2, t, Buffer, NULL); + usleep((count-t)*1000*5/441/2); + } + count-=t; + Buffer+=t; + } + if(command&CMD_SEEK) + { + int t=(command&~(CMD_SEEK|CMD_STOP))*1000; + + if(sexypsf_seek(t)) + sexypsf_ip.output->flush(t); + else // Negative time! Must make a C time machine. + { + sexypsf_stop(); + return; + } + command&=~CMD_SEEK; + } + if(command&CMD_STOP) + sexypsf_stop(); +} + +static void *sexypsf_playloop(void *arg) +{ +dofunky: + + sexypsf_execute(); + + /* We have reached the end of the song. Now what... */ + sexypsf_ip.output->buffer_free(); + sexypsf_ip.output->buffer_free(); + + while(!(command&CMD_STOP)) + { + if(command&CMD_SEEK) + { + int t=(command&~(CMD_SEEK|CMD_STOP))*1000; + sexypsf_ip.output->flush(t); + if(!(PSFInfo=sexypsf_load(fnsave))) + break; + sexypsf_seek(t); + command&=~CMD_SEEK; + goto dofunky; + } + if(!sexypsf_ip.output->buffer_playing()) break; + usleep(2000); + } + sexypsf_ip.output->close_audio(); + if(!(command&CMD_STOP)) nextsong=1; + g_thread_exit(NULL); + return(NULL); +} + +static void sexypsf_xmms_play(char *fn) +{ + if(playing) + return; + nextsong=0; + paused = 0; + if(!sexypsf_ip.output->open_audio(FMT_S16_NE, 44100, 2)) + { + puts("Error opening audio."); + return; + } + fnsave=malloc(strlen(fn)+1); + strcpy(fnsave,fn); + if(!(PSFInfo=sexypsf_load(fn))) + { + sexypsf_ip.output->close_audio(); + nextsong=1; + } + else + { + command=0; + SI(fn); + playing=1; + dethread = g_thread_create((GThreadFunc)sexypsf_playloop,NULL,TRUE,NULL); + } +} + +static void sexypsf_xmms_stop(void) +{ + if(!playing) return; + + if(paused) + sexypsf_ip.output->pause(0); + paused = 0; + + command=CMD_STOP; + g_thread_join(dethread); + playing = 0; + + if(fnsave) + { + free(fnsave); + fnsave=NULL; + } + sexypsf_freepsfinfo(PSFInfo); + PSFInfo=NULL; +} + +static void sexypsf_xmms_pause(short p) +{ + if(!playing) return; + sexypsf_ip.output->pause(p); + paused = p; +} + +static void sexypsf_xmms_seek(int time) +{ + if(!playing) return; + command=CMD_SEEK|time; +} + +static int sexypsf_xmms_gettime(void) +{ + if(nextsong) + return(-1); + if(!playing) return(0); + return sexypsf_ip.output->output_time(); +} + +static void sexypsf_xmms_getsonginfo(char *fn, char **title, int *length) +{ + PSFINFO *tmp; + + if((tmp=sexypsf_getpsfinfo(fn))) { + *length = tmp->length; + *title = get_title_psf(fn); + sexypsf_freepsfinfo(tmp); + } +} + +static gchar *get_title_psf(gchar *fn) { + gchar *title; + PSFINFO *tmp = sexypsf_getpsfinfo(fn); + + if (tmp->length) { + TitleInput *tinput; + + tinput = bmp_title_input_new(); + + tinput->performer = g_strdup(tmp->artist); + tinput->album_name = g_strdup(tmp->game); + tinput->track_name = g_strdup(tmp->title); + tinput->file_name = g_path_get_basename(fn); + tinput->file_path = g_path_get_dirname(fn); + + title = xmms_get_titlestring(xmms_get_gentitle_format(), + tinput); + g_free(tinput); + } + else + title = g_path_get_basename(fn); + + return title; +} + +InputPlugin sexypsf_ip = +{ + 0, + 0, + "Plays PSF1 files.", + 0, + 0, + 0, + is_our_file, + 0, + sexypsf_xmms_play, + sexypsf_xmms_stop, + sexypsf_xmms_pause, + sexypsf_xmms_seek, + 0, + sexypsf_xmms_gettime, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + sexypsf_xmms_getsonginfo, + 0, + 0 +};