aboutsummaryrefslogtreecommitdiff
path: root/source/spc7110.c
diff options
context:
space:
mode:
authoraliaspider2014-10-29 05:36:07 +0100
committeraliaspider2014-10-29 05:36:07 +0100
commita6dc7abc9b8cc3986eda5a84141da7dc9e4e8f1a (patch)
tree6f82417b0ab41f3887dd025ee3b85254e28143da /source/spc7110.c
parent1d98e1c317fa19687ae6bc3cb8e550ef7531bf02 (diff)
downloadsnesemu-a6dc7abc9b8cc3986eda5a84141da7dc9e4e8f1a.tar.gz
snesemu-a6dc7abc9b8cc3986eda5a84141da7dc9e4e8f1a.tar.bz2
snesemu-a6dc7abc9b8cc3986eda5a84141da7dc9e4e8f1a.zip
start moving everything to C
Diffstat (limited to 'source/spc7110.c')
-rw-r--r--source/spc7110.c2285
1 files changed, 2285 insertions, 0 deletions
diff --git a/source/spc7110.c b/source/spc7110.c
new file mode 100644
index 0000000..3ae0cfd
--- /dev/null
+++ b/source/spc7110.c
@@ -0,0 +1,2285 @@
+/*******************************************************************************
+ Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
+
+ (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and
+ Jerremy Koot (jkoot@snes9x.com)
+
+ (c) Copyright 2001 - 2004 John Weidman (jweidman@slip.net)
+
+ (c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net),
+ funkyass (funkyass@spam.shaw.ca),
+ Joel Yliluoma (http://iki.fi/bisqwit/)
+ Kris Bleakley (codeviolation@hotmail.com),
+ Matthew Kendora,
+ Nach (n-a-c-h@users.sourceforge.net),
+ Peter Bortas (peter@bortas.org) and
+ zones (kasumitokoduck@yahoo.com)
+
+ C4 x86 assembler and some C emulation code
+ (c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com),
+ _Demo_ (_demo_@zsnes.com), and Nach
+
+ C4 C++ code
+ (c) Copyright 2003 Brad Jorsch
+
+ DSP-1 emulator code
+ (c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson,
+ John Weidman, neviksti (neviksti@hotmail.com),
+ Kris Bleakley, Andreas Naive
+
+ DSP-2 emulator code
+ (c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and
+ Lord Nightmare (lord_nightmare@users.sourceforge.net
+
+ OBC1 emulator code
+ (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and
+ Kris Bleakley
+ Ported from x86 assembler to C by sanmaiwashi
+
+ SPC7110 and RTC C++ emulator code
+ (c) Copyright 2002 Matthew Kendora with research by
+ zsKnight, John Weidman, and Dark Force
+
+ S-DD1 C emulator code
+ (c) Copyright 2003 Brad Jorsch with research by
+ Andreas Naive and John Weidman
+
+ S-RTC C emulator code
+ (c) Copyright 2001 John Weidman
+
+ ST010 C++ emulator code
+ (c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora
+
+ Super FX x86 assembler emulator code
+ (c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
+
+ Super FX C emulator code
+ (c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman
+
+
+ SH assembler code partly based on x86 assembler code
+ (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
+
+
+ Specific ports contains the works of other authors. See headers in
+ individual files.
+
+ Snes9x homepage: http://www.snes9x.com
+
+ Permission to use, copy, modify and distribute Snes9x in both binary and
+ source form, for non-commercial purposes, is hereby granted without fee,
+ providing that this license information and copyright notice appear with
+ all copies and any derived work.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event shall the authors be held liable for any damages
+ arising from the use of this software.
+
+ Snes9x is freeware for PERSONAL USE only. Commercial users should
+ seek permission of the copyright holders first. Commercial use includes
+ charging money for Snes9x or software derived from Snes9x.
+
+ The copyright holders request that bug fixes and improvements to the code
+ should be forwarded to them so everyone can benefit from the modifications
+ in future versions.
+
+ Super NES and Super Nintendo Entertainment System are trademarks of
+ Nintendo Co., Limited and its subsidiary companies.
+*******************************************************************************/
+
+#include "spc7110.h"
+#include "memmap.h"
+#include <time.h>
+#include <sys/stat.h>
+
+//Windows includes
+#ifdef __WIN32__
+#ifndef _XBOX // chdir and getcwd not supported on Xbox hardware
+#include <direct.h>
+#define chdir _chdir
+#define getcwd _getcwd
+#endif
+#define FREEZEFOLDER GUI.FreezeFileDir
+//zinx suggested this, for *nix compatibility
+#define PATH_MAX MAX_PATH
+#else // Unix
+#include "display.h"
+#include <limits.h>
+#include <unistd.h>
+#define FREEZEFOLDER S9xGetSnapshotDirectory ()
+#endif
+
+extern "C" const char *S9xGetFilename (const char *);
+extern "C" char *osd_GetPackDir();
+//really not needed, but usually MS adds the _ to POSIX functions,
+//while *nix doesn't, so this was to "un-M$" the function.
+#define splitpath _splitpath
+
+//not much headroom, but FEOEZ has 41 tables, I think, and SPL4 has 38.
+#define MAX_TABLES 48
+
+//default to using 5 megs of RAM for method 3 caching.
+uint16 cacheMegs=5;
+
+//using function pointers to initialize cache management
+void (*CleanUp7110)(void)=NULL;
+void (*LoadUp7110)(char*)=&SPC7110Load;
+void (*Copy7110)(void)=NULL;
+
+//size and offset of the pack data
+//offset and size of reads from pack
+typedef struct SPC7110DecompressionLocationStruct
+{
+ uint32 offset;
+ uint32 size;
+ uint16 used_offset;
+ uint16 used_len;
+} Data7110;
+
+//this maps an index.bin table to the decompression pack
+typedef struct SPC7110DecompressionIndexStruct
+{
+ int table;
+ bool is_file;
+ Data7110 location[256];
+} Index7110;
+
+//this contains all the data for the decompression pack.
+typedef struct SPC7110DecompressionPackStructure
+{
+ uint8* binfiles[MAX_TABLES];
+ Index7110 tableEnts[MAX_TABLES];
+ int last_table;
+ int idx;
+ uint8 last_idx;
+ uint16 last_offset;
+} Pack7110;
+
+
+char pfold[9]; //hack variable for log naming (each game makes a different log)
+Pack7110* decompack=NULL; //decompression pack uses a fair chunk of RAM, so dynalloc it.
+SPC7110Regs s7r; //SPC7110 registers, about 33KB
+S7RTC rtc_f9; //FEOEZ (and Shounen Jump no SHou) RTC
+void S9xUpdateRTC (); //S-RTC function hacked to work with the RTC
+
+//Emulate power on state
+void S9xSpc7110Init()
+{
+ s7r.DataRomOffset=0x00100000;//handy constant!
+ s7r.DataRomSize=Memory.CalculatedSize-s7r.DataRomOffset;
+ s7r.reg4800=0;
+ s7r.reg4801=0;
+ s7r.reg4802=0;
+ s7r.reg4803=0;
+ s7r.reg4804=0;
+ s7r.reg4805=0;
+ s7r.reg4806=0;
+ s7r.reg4807=0;
+ s7r.reg4808=0;
+ s7r.reg4809=0;
+ s7r.reg480A=0;
+ s7r.reg480B=0;
+ s7r.reg480C=0;
+ s7r.reg4811=0;
+ s7r.reg4812=0;
+ s7r.reg4813=0;
+ s7r.reg4814=0;
+ s7r.reg4815=0;
+ s7r.reg4816=0;
+ s7r.reg4817=0;
+ s7r.reg4818=0;
+ s7r.reg4820=0;
+ s7r.reg4821=0;
+ s7r.reg4822=0;
+ s7r.reg4823=0;
+ s7r.reg4824=0;
+ s7r.reg4825=0;
+ s7r.reg4826=0;
+ s7r.reg4827=0;
+ s7r.reg4828=0;
+ s7r.reg4829=0;
+ s7r.reg482A=0;
+ s7r.reg482B=0;
+ s7r.reg482C=0;
+ s7r.reg482D=0;
+ s7r.reg482E=0;
+ s7r.reg482F=0;
+ s7r.reg4830=0;
+ s7r.reg4831=0;
+ s7r.reg4832=1;
+ s7r.reg4833=2;
+ s7r.reg4834=0;
+ s7r.reg4840=0;
+ s7r.reg4841=0;
+ s7r.reg4842=0;
+ s7r.written=0;
+ s7r.offset_add=0;
+ s7r.AlignBy=1;
+
+ (*LoadUp7110)(osd_GetPackDir());
+
+ s7r.bank50Internal=0;
+ memset(s7r.bank50,0x00,DECOMP_BUFFER_SIZE);
+}
+
+
+//full cache decompression routine (memcpy) Method 1
+void MovePackData()
+{
+ //log the last entry
+ Data7110* log=&(decompack->tableEnts[decompack->idx].location[decompack->last_idx]);
+ if((log->used_len+log->used_offset)<(decompack->last_offset+(unsigned short)s7r.bank50Internal))
+ {
+ log->used_len=s7r.bank50Internal;
+ log->used_offset=decompack->last_offset;
+ }
+
+ //set up for next logging
+ decompack->last_offset=(s7r.reg4805)|(s7r.reg4806<<8);
+
+ decompack->last_idx=s7r.reg4804;
+
+ //start decompression
+ int table=(s7r.reg4803<<16)|(s7r.reg4802<<8)|s7r.reg4801;
+
+ //the table is a offset multiplier byte and a big-endian pointer
+ int j= 4*s7r.reg4804;
+ j+=s7r.DataRomOffset;
+ j+=table;
+
+ //set proper offsetting.
+ if(s7r.reg480B==0)
+ s7r.AlignBy=0;
+ else
+ {
+ switch(ROM[j])
+ {
+ case 0x03:
+ s7r.AlignBy=8;
+ break;
+ case 0x01:
+ s7r.AlignBy=2;
+ break;
+ case 0x02:
+ s7r.AlignBy=4;
+ break;
+ case 0x00:
+ default:
+ s7r.AlignBy=1;
+ break;
+ }
+ }
+ //note that we are still setting up for the next log.
+ decompack->last_offset*=s7r.AlignBy;
+ decompack->last_offset%=DECOMP_BUFFER_SIZE;
+
+ //find the table
+ if(table!=decompack->last_table)
+ {
+ int i=0;
+ while(i<MAX_TABLES&&decompack->tableEnts[i].table!=table)
+ i++;
+ if(i==MAX_TABLES)
+ {
+#ifdef _XBOX
+ FILE* fp=fopen("T:\\sp7err.out","a");
+#else
+ FILE* fp=fopen("sp7err.out","a");
+#endif
+
+// fprintf(fp, "Table Entry %06X:%02X not found\n", table, s7r.reg4804);
+ fclose(fp);
+ return;
+ }
+ decompack->idx=i;
+ decompack->last_table=table;
+ }
+
+ //copy data
+ if(decompack->binfiles[decompack->idx])
+ {
+ memcpy(s7r.bank50,
+ &(decompack->binfiles[decompack->idx][decompack->tableEnts[decompack->idx].location[s7r.reg4804].offset]),
+ decompack->tableEnts[decompack->idx].location[s7r.reg4804].size);
+ }
+}
+
+
+//this is similar to the last function, but it keeps the last 5 accessed files open,
+// and reads the data directly. Method 2
+void ReadPackData()
+{
+ static int table_age_2;
+ static int table_age_3;
+ static int table_age_4;
+ static int table_age_5;
+
+ int table=(s7r.reg4803<<16)|(s7r.reg4802<<8)|s7r.reg4801;
+
+ if(table==0)
+ {
+ table_age_2=table_age_3=table_age_4=table_age_5=MAX_TABLES;
+ return;
+ }
+
+ if(table_age_2==0&&table_age_3==0&&table_age_4==0&&table_age_5==0)
+ table_age_2=table_age_3=table_age_4=table_age_5=MAX_TABLES;
+ Data7110* log=&(decompack->tableEnts[decompack->idx].location[decompack->last_idx]);
+ if((log->used_len+log->used_offset)<(decompack->last_offset+(unsigned short)s7r.bank50Internal))
+ {
+ log->used_len=s7r.bank50Internal;
+ log->used_offset=decompack->last_offset;
+ }
+
+ decompack->last_offset=(s7r.reg4805)|(s7r.reg4806<<8);
+
+ decompack->last_idx=s7r.reg4804;
+
+ int j= 4*s7r.reg4804;
+ j+=s7r.DataRomOffset;
+ j+=table;
+
+ if(s7r.reg480B==0)
+ s7r.AlignBy=0;
+ else
+ {
+ switch(ROM[j])
+ {
+ case 0x03:
+ s7r.AlignBy=8;
+ break;
+ case 0x01:
+ s7r.AlignBy=2;
+ break;
+ case 0x02:
+ s7r.AlignBy=4;
+ break;
+ case 0x00:
+ default:
+ s7r.AlignBy=1;
+ break;
+ }
+ }
+ decompack->last_offset*=s7r.AlignBy;
+ decompack->last_offset%=DECOMP_BUFFER_SIZE;
+ if(table!=decompack->last_table)
+ {
+ int i=0;
+ while(i<MAX_TABLES&&decompack->tableEnts[i].table!=table)
+ i++;
+ if(i==MAX_TABLES)
+ {
+ FILE* fp=fopen("sp7err.out","a");
+// fprintf(fp, "Table Entry %06X:%02X not found\n", table, s7r.reg4804);
+ fclose(fp);
+ return;
+ }
+ if(i!= table_age_2 && i!= table_age_3 && i!= table_age_4 && i!= table_age_5)
+ {
+ if(table_age_5!=MAX_TABLES&&decompack->binfiles[table_age_5])
+ {
+ fclose((FILE*)(decompack->binfiles[table_age_5]));
+ (decompack->binfiles[table_age_5])=NULL;
+ }
+ table_age_5=table_age_4;
+ table_age_4=table_age_3;
+ table_age_3=table_age_2;
+ table_age_2=decompack->idx;
+ char name[PATH_MAX];
+ //open file
+ char drive [_MAX_DRIVE + 1];
+ char dir [_MAX_DIR + 1];
+ char fname [_MAX_FNAME + 1];
+ char ext [_MAX_EXT + 1];
+ if (strlen (FREEZEFOLDER))
+ {
+ //splitpath (Memory.ROMFilename, drive, dir, fname, ext);
+ strcpy (name, FREEZEFOLDER);
+ strcat (name, "/");
+ }
+ else
+ {
+ splitpath (Memory.ROMFilename, drive, dir, fname, ext);
+ strcpy(name, drive);
+ //strcat(filename, "\\");
+ strcat(name, dir);
+ }
+ strcat(name, pfold);
+ char bfname[11];
+ sprintf(bfname, "%06X.bin", table);
+ strcat(name, "/");
+ strcat(name, bfname);
+ decompack->binfiles[i]=(uint8*)fopen(name, "rb");
+ }
+ else
+ {
+ //fix tables in this case
+ if(table_age_5==i)
+ {
+ table_age_5=table_age_4;
+ table_age_4=table_age_3;
+ table_age_3=table_age_2;
+ table_age_2=decompack->idx;
+ }
+ if(table_age_4==i)
+ {
+ table_age_4=table_age_3;
+ table_age_3=table_age_2;
+ table_age_2=decompack->idx;
+ }
+ if(table_age_3==i)
+ {
+ table_age_3=table_age_2;
+ table_age_2=decompack->idx;
+ }
+ if(table_age_2==i)
+ {
+ table_age_2=decompack->idx;
+ }
+ }
+ decompack->idx=i;
+ decompack->last_table=table;
+ }
+ //do read here.
+ if(decompack->binfiles[decompack->idx])
+ {
+ fseek((FILE*)(decompack->binfiles[decompack->idx]), decompack->tableEnts[decompack->idx].location[s7r.reg4804].offset, 0);
+ fread(s7r.bank50,1, (decompack->tableEnts[decompack->idx].location[s7r.reg4804].size), (FILE*)(decompack->binfiles[decompack->idx]));
+ }
+}
+
+//Cache Method 3: some entries are cached, others are file handles.
+//use is_file to distinguish.
+void GetPackData()
+{
+ Data7110* log=&(decompack->tableEnts[decompack->idx].location[decompack->last_idx]);
+ if((log->used_len+log->used_offset)<(decompack->last_offset+(unsigned short)s7r.bank50Internal))
+ {
+ log->used_len=s7r.bank50Internal;
+ log->used_offset=decompack->last_offset;
+ }
+
+ decompack->last_offset=(s7r.reg4805)|(s7r.reg4806<<8);
+
+ decompack->last_idx=s7r.reg4804;
+ int table=(s7r.reg4803<<16)|(s7r.reg4802<<8)|s7r.reg4801;
+
+ int j= 4*s7r.reg4804;
+ j+=s7r.DataRomOffset;
+ j+=table;
+
+ if(s7r.reg480B==0)
+ s7r.AlignBy=0;
+ else
+ {
+ switch(ROM[j])
+ {
+ case 0x03:
+ s7r.AlignBy=8;
+ break;
+ case 0x01:
+ s7r.AlignBy=2;
+ break;
+ case 0x02:
+ s7r.AlignBy=4;
+ break;
+ case 0x00:
+ default:
+ s7r.AlignBy=1;
+ break;
+ }
+ }
+ decompack->last_offset*=s7r.AlignBy;
+ decompack->last_offset%=DECOMP_BUFFER_SIZE;
+ if(table!=decompack->last_table)
+ {
+ int i=0;
+ while(i<MAX_TABLES&&decompack->tableEnts[i].table!=table)
+ i++;
+ if(i==MAX_TABLES)
+ {
+ FILE* fp=fopen("sp7err.out","a");
+// fprintf(fp, "Table Entry %06X:%02X not found\n", table, s7r.reg4804);
+ fclose(fp);
+ return;
+ }
+ decompack->idx=i;
+ decompack->last_table=table;
+ }
+ if(decompack->binfiles[decompack->idx])
+ {
+ if(decompack->tableEnts[decompack->idx].is_file)
+ {
+ fseek((FILE*)decompack->binfiles[decompack->idx], decompack->tableEnts[decompack->idx].location[s7r.reg4804].offset, 0);
+ fread(s7r.bank50,1, (decompack->tableEnts[decompack->idx].location[s7r.reg4804].size), (FILE*)(decompack->binfiles[decompack->idx]));
+ }
+ else
+ {
+ memcpy(s7r.bank50,
+ &(decompack->binfiles[decompack->idx][decompack->tableEnts[decompack->idx].location[s7r.reg4804].offset]),
+ decompack->tableEnts[decompack->idx].location[s7r.reg4804].size);
+ }
+ }
+}
+
+extern "C"{
+//reads SPC7110 and RTC registers.
+uint8 S9xGetSPC7110(uint16 Address)
+{
+ switch (Address)
+ {
+ //decompressed data read port. decrements 4809-A (with wrap)
+ //4805-6 is the offset into the bank
+ //AlignBy is set (afaik) at decompression time, and is the offset multiplier
+ //bank50internal is an internal pointer to the actual byte to read.
+ //so you read from offset*multiplier + bank50internal
+ //the offset registers cannot be incremented due to the offset multiplier.
+ case 0x4800:
+ {
+ unsigned short count=s7r.reg4809|(s7r.reg480A<<8);
+ uint32 i, j;
+ j=(s7r.reg4805|(s7r.reg4806<<8));
+ j*=s7r.AlignBy;
+ i=j;
+ if(count >0)
+ count--;
+ else count = 0xFFFF;
+ s7r.reg4809=0x00ff&count;
+ s7r.reg480A=(0xff00&count)>>8;
+ i+=s7r.bank50Internal;
+ i%=DECOMP_BUFFER_SIZE;
+ s7r.reg4800=s7r.bank50[i];
+
+ s7r.bank50Internal++;
+ s7r.bank50Internal%=DECOMP_BUFFER_SIZE;
+ }
+ return s7r.reg4800;
+ //table register low
+ case 0x4801: return s7r.reg4801;
+ //table register middle
+ case 0x4802: return s7r.reg4802;
+ //table register high
+ case 0x4803: return s7r.reg4803;
+ //index of pointer in table (each entry is 4 bytes)
+ case 0x4804: return s7r.reg4804;
+ //offset register low
+ case 0x4805: return s7r.reg4805;
+ //offset register high
+ case 0x4806: return s7r.reg4806;
+ //DMA channel (not that I see this usually set,
+ //regardless of what channel DMA is on)
+ case 0x4807: return s7r.reg4807;
+ //C r/w option, unknown, defval:00 is what Dark Force says
+ //afaict, Snes9x doesn't use this at all.
+ case 0x4808: return s7r.reg4808;
+ //C-Length low
+ //counts down the number of bytes left to read from the decompression buffer.
+ //this is set by the ROM, and wraps on bounds.
+ case 0x4809: return s7r.reg4809;
+ //C Length high
+ case 0x480A: return s7r.reg480A;
+ //Offset enable.
+ //if this is zero, 4805-6 are useless. Emulated by setting AlignBy to 0
+ case 0x480B:
+ return s7r.reg480B;
+ //decompression finished: just emulated by switching each read.
+ case 0x480C:
+ s7r.reg480C^=0x80;
+ return s7r.reg480C^0x80;
+
+ //Data access port
+ //reads from the data ROM (anywhere over the first 8 mbits
+ //behavior is complex, will document later,
+ //possibly missing cases, because of the number of switches in play
+ case 0x4810:
+ if(s7r.written==0)
+ return 0;
+ if((s7r.written&0x07)==0x07)
+ {
+ uint32 i=(s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811;
+ i%=s7r.DataRomSize;
+ if(s7r.reg4818&0x02)
+ {
+ if(s7r.reg4818&0x08)
+ {
+ signed short r4814;
+ r4814=(s7r.reg4815<<8)|s7r.reg4814;
+ i+=r4814;
+ r4814++;
+ s7r.reg4815=(uint8)(r4814>>8);
+ s7r.reg4814=(uint8)(r4814&0x00FF);
+ }
+ else
+ {
+ unsigned short r4814;
+ r4814=(s7r.reg4815<<8)|s7r.reg4814;
+ i+=r4814;
+ if(r4814!=0xFFFF)
+ r4814++;
+ else r4814=0;
+ s7r.reg4815=(uint8)(r4814>>8);
+ s7r.reg4814=(uint8)(r4814&0x00FF);
+
+ }
+ }
+ i+=s7r.DataRomOffset;
+ uint8 tmp=ROM[i];
+ i=(s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811;
+
+ if(s7r.reg4818&0x02)
+ {
+ }
+ else if(s7r.reg4818&0x01)
+ {
+ if(s7r.reg4818&0x04)
+ {
+ signed short inc;
+ inc=(s7r.reg4817<<8)|s7r.reg4816;
+
+ if(!(s7r.reg4818&0x10))
+ i+=inc;
+ else
+ {
+ if(s7r.reg4818&0x08)
+ {
+ signed short r4814;
+ r4814=(s7r.reg4815<<8)|s7r.reg4814;
+ r4814+=inc;
+ s7r.reg4815=(r4814&0xFF00)>>8;
+ s7r.reg4814=r4814&0xFF;
+ }
+ else
+ {
+ unsigned short r4814;
+ r4814=(s7r.reg4815<<8)|s7r.reg4814;
+ r4814+=inc;
+ s7r.reg4815=(r4814&0xFF00)>>8;
+ s7r.reg4814=r4814&0xFF;
+
+ }
+ }
+ //is signed
+ }
+ else
+ {
+ uint16 inc;
+ inc=(s7r.reg4817<<8)|s7r.reg4816;
+ if(!(s7r.reg4818&0x10))
+ i+=inc;
+ else
+ {
+ if(s7r.reg4818&0x08)
+ {
+ signed short r4814;
+ r4814=(s7r.reg4815<<8)|s7r.reg4814;
+ r4814+=inc;
+ s7r.reg4815=(r4814&0xFF00)>>8;
+ s7r.reg4814=r4814&0xFF;
+ }
+ else
+ {
+ unsigned short r4814;
+ r4814=(s7r.reg4815<<8)|s7r.reg4814;
+ r4814+=inc;
+ s7r.reg4815=(r4814&0xFF00)>>8;
+ s7r.reg4814=r4814&0xFF;
+
+ }
+ }
+ }
+ }
+ else
+ {
+ if(!(s7r.reg4818&0x10))
+ i+=1;
+ else
+ {
+ if(s7r.reg4818&0x08)
+ {
+ signed short r4814;
+ r4814=(s7r.reg4815<<8)|s7r.reg4814;
+ r4814+=1;
+ s7r.reg4815=(r4814&0xFF00)>>8;
+ s7r.reg4814=r4814&0xFF;
+ }
+ else
+ {
+ unsigned short r4814;
+ r4814=(s7r.reg4815<<8)|s7r.reg4814;
+ r4814+=1;
+ s7r.reg4815=(r4814&0xFF00)>>8;
+ s7r.reg4814=r4814&0xFF;
+
+ }
+ }
+ }
+
+ i%=s7r.DataRomSize;
+ s7r.reg4811=i&0x00FF;
+ s7r.reg4812=(i&0x00FF00)>>8;
+ s7r.reg4813=((i&0xFF0000)>>16);
+ return tmp;
+ }
+ else return 0;
+ //direct read address low
+ case 0x4811: return s7r.reg4811;
+ //direct read address middle
+ case 0x4812: return s7r.reg4812;
+ //direct read access high
+ case 0x4813: return s7r.reg4813;
+ //read adjust low
+ case 0x4814: return s7r.reg4814;
+ //read adjust high
+ case 0x4815: return s7r.reg4815;
+ //read increment low
+ case 0x4816: return s7r.reg4816;
+ //read increment high
+ case 0x4817: return s7r.reg4817;
+ //Data ROM command mode
+ //essentially, this controls the insane code of $4810 and $481A
+ case 0x4818: return s7r.reg4818;
+ //read after adjust port
+ //what this does, besides more nasty stuff like 4810,
+ //I don't know. Just assume it is a different implementation of $4810,
+ //if it helps your sanity
+ case 0x481A:
+ if(s7r.written==0x1F)
+ {
+ uint32 i=((s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811);
+ if(s7r.reg4818&0x08)
+ {
+ short adj;
+ adj=((short)(s7r.reg4815<<8))|s7r.reg4814;
+ i+=adj;
+ }
+ else
+ {
+ uint16 adj;
+ adj=(s7r.reg4815<<8)|s7r.reg4814;
+ i+=adj;
+ }
+
+ i%=s7r.DataRomSize;
+ i+=s7r.DataRomOffset;
+ uint8 tmp=ROM[i];
+ i=((s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811);
+ if(0x60==(s7r.reg4818&0x60))
+ {
+ i=((s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811);
+
+ if(!(s7r.reg4818&0x10))
+ {
+ if(s7r.reg4818&0x08)
+ {
+ short adj;
+ adj=((short)(s7r.reg4815<<8))|s7r.reg4814;
+ i+=adj;
+ }
+ else
+ {
+ uint16 adj;
+ adj=(s7r.reg4815<<8)|s7r.reg4814;
+ i+=adj;
+ }
+ i%=s7r.DataRomSize;
+ s7r.reg4811=i&0x00FF;
+ s7r.reg4812=(i&0x00FF00)>>8;
+ s7r.reg4813=((i&0xFF0000)>>16);
+ }
+ else
+ {
+ if(s7r.reg4818&0x08)
+ {
+ short adj;
+ adj=((short)(s7r.reg4815<<8))|s7r.reg4814;
+ adj+=adj;
+ s7r.reg4815=(adj&0xFF00)>>8;
+ s7r.reg4814=adj&0xFF;
+ }
+ else
+ {
+ uint16 adj;
+ adj=(s7r.reg4815<<8)|s7r.reg4814;
+ adj+=adj;
+ s7r.reg4815=(adj&0xFF00)>>8;
+ s7r.reg4814=adj&0xFF;
+ }
+ }
+ }
+ return tmp;
+ }
+ else return 0;
+
+ //multiplicand low or dividend lowest
+ case 0x4820: return s7r.reg4820;
+ //multiplicand high or divdend lower
+ case 0x4821: return s7r.reg4821;
+ //dividend higher
+ case 0x4822: return s7r.reg4822;
+ //dividend highest
+ case 0x4823: return s7r.reg4823;
+ //multiplier low
+ case 0x4824: return s7r.reg4824;
+ //multiplier high
+ case 0x4825: return s7r.reg4825;
+ //divisor low
+ case 0x4826: return s7r.reg4826;
+ //divisor high
+ case 0x4827: return s7r.reg4827;
+
+ //result lowest
+ case 0x4828:
+ return s7r.reg4828;
+ //result lower
+ case 0x4829:
+ return s7r.reg4829;
+ //result higher
+ case 0x482A:
+ return s7r.reg482A;
+ //result highest
+ case 0x482B:
+ return s7r.reg482B;
+ //remainder (division) low
+ case 0x482C: return s7r.reg482C;
+ //remainder (division) high
+ case 0x482D: return s7r.reg482D;
+ //signed/unsigned
+ case 0x482E: return s7r.reg482E;
+ //finished flag, emulated as an on-read toggle.
+ case 0x482F:
+ if(s7r.reg482F)
+ {
+ s7r.reg482F=0;
+ return 0x80;
+ }
+ return 0;
+ break;
+
+ //SRAM toggle
+ case 0x4830:
+ return s7r.reg4830;
+ //DX bank mapping
+ case 0x4831:
+ return s7r.reg4831;
+ //EX bank mapping
+ case 0x4832:
+ return s7r.reg4832;
+ //FX bank mapping
+ case 0x4833:
+ return s7r.reg4833;
+ //SRAM mapping? We have no clue!
+ case 0x4834:
+ return s7r.reg4834;
+//RTC enable
+ case 0x4840:
+ if(!Settings.SPC7110RTC)
+ return Address>>8;
+ return s7r.reg4840;
+//command/index/value of RTC (essentially, zero unless we're in read mode
+ case 0x4841:
+ if(!Settings.SPC7110RTC)
+ return Address>>8;
+ if(rtc_f9.init)
+ {
+ S9xUpdateRTC();
+ uint8 tmp=rtc_f9.reg[rtc_f9.index];
+ rtc_f9.index++;
+ rtc_f9.index%=0x10;
+ return tmp;
+ }
+ else return 0;
+//RTC done flag
+ case 0x4842:
+ if(!Settings.SPC7110RTC)
+ return Address>>8;
+ s7r.reg4842^=0x80;
+ return s7r.reg4842^0x80;
+ default:
+ return 0x00;
+ }
+}
+}
+void S9xSetSPC7110 (uint8 data, uint16 Address)
+{
+ switch(Address)
+ {
+//Writes to $4800 are undefined.
+
+ //table low, middle, and high.
+ case 0x4801:
+ s7r.reg4801=data;
+ break;
+ case 0x4802:
+ s7r.reg4802=data;
+ break;
+ case 0x4803:
+ s7r.reg4803=data;
+ break;
+
+ //table index (4 byte entries, bigendian with a multiplier byte)
+ case 0x4804:
+ s7r.reg4804=data;
+ break;
+
+ //offset low
+ case 0x4805:
+ s7r.reg4805=data;
+ break;
+
+ //offset high, starts decompression
+ case 0x4806:
+ s7r.reg4806=data;
+ (*Copy7110)();
+ s7r.bank50Internal=0;
+ s7r.reg480C&=0x7F;
+ break;
+
+ //DMA channel register (Is it used??)
+ case 0x4807:
+ s7r.reg4807=data;
+ break;
+
+ //C r/w? I have no idea. If you get weird values written here before a bug,
+ //The Dumper should probably be contacted about running a test.
+ case 0x4808:
+ s7r.reg4808=data;
+ break;
+
+ //C-Length low
+ case 0x4809:
+ s7r.reg4809=data;
+ break;
+ //C-Length high
+ case 0x480A:
+ s7r.reg480A=data;
+ break;
+
+ //Offset enable
+ case 0x480B:
+ {
+ s7r.reg480B=data;
+ int table=(s7r.reg4803<<16)|(s7r.reg4802<<8)|s7r.reg4801;
+
+ int j= 4*s7r.reg4804;
+ j+=s7r.DataRomOffset;
+ j+=table;
+
+ if(s7r.reg480B==0)
+ s7r.AlignBy=0;
+ else
+ {
+ switch(ROM[j])
+ {
+ case 0x03:
+ s7r.AlignBy=8;
+ break;
+ case 0x01:
+ s7r.AlignBy=2;
+ break;
+ case 0x02:
+ s7r.AlignBy=4;
+ break;
+ case 0x00:
+ default:
+ s7r.AlignBy=1;
+ break;
+ }
+ }
+// s7r.decomp_set=true;
+ }
+ break;
+//$4810 is probably read only.
+
+ //Data port address low
+ case 0x4811:
+ s7r.reg4811=data;
+ s7r.written|=0x01;
+ break;
+
+ //data port address middle
+ case 0x4812:
+ s7r.reg4812=data;
+ s7r.written|=0x02;
+ break;
+
+ //data port address high
+ case 0x4813:
+ s7r.reg4813=data;
+ s7r.written|=0x04;
+ break;
+
+ //data port adjust low (has a funky immediate increment mode)
+ case 0x4814:
+ s7r.reg4814=data;
+ if(s7r.reg4818&0x02)
+ {
+ if((s7r.reg4818&0x20)&&!(s7r.reg4818&0x40))
+ {
+ s7r.offset_add|=0x01;
+ if(s7r.offset_add==3)
+ {
+ if(s7r.reg4818&0x10)
+ {
+ }
+ else
+ {
+ uint32 i=(s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811;
+ if(s7r.reg4818&0x08)
+ {
+ i+=(signed char)s7r.reg4814;
+ }
+ else
+ {
+ i+=s7r.reg4814;
+ }
+ i%=s7r.DataRomSize;
+ s7r.reg4811=i&0x00FF;
+ s7r.reg4812=(i&0x00FF00)>>8;
+ s7r.reg4813=((i&0xFF0000)>>16);
+ }
+ }
+ }
+ else if((s7r.reg4818&0x40)&&!(s7r.reg4818&0x20))
+ {
+ s7r.offset_add|=0x01;
+ if(s7r.offset_add==3)
+ {
+ if(s7r.reg4818&0x10)
+ {
+ }
+ else
+ {
+ uint32 i=(s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811;
+ if(s7r.reg4818&0x08)
+ {
+ short adj;
+ adj=((short)(s7r.reg4815<<8))|s7r.reg4814;
+ i+=adj;
+ }
+ else
+ {
+ uint16 adj;
+ adj=(s7r.reg4815<<8)|s7r.reg4814;
+ i+=adj;
+ }
+ i%=s7r.DataRomSize;
+ s7r.reg4811=i&0x00FF;
+ s7r.reg4812=(i&0x00FF00)>>8;
+ s7r.reg4813=((i&0xFF0000)>>16);
+ }
+ }
+
+ }
+ }
+
+ s7r.written|=0x08;
+ break;
+
+ //data port adjust high (has a funky immediate increment mode)
+ case 0x4815:
+ s7r.reg4815=data;
+ if(s7r.reg4818&0x02)
+ {
+ if(s7r.reg4818&0x20&&!(s7r.reg4818&0x40))
+ {
+ s7r.offset_add|=0x02;
+ if(s7r.offset_add==3)
+ {
+ if(s7r.reg4818&0x10)
+ {
+ }
+ else
+ {
+ uint32 i=(s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811;
+
+ if(s7r.reg4818&0x08)
+ {
+ i+=(signed char)s7r.reg4814;
+ }
+ else
+ {
+ i+=s7r.reg4814;
+ }
+ i%=s7r.DataRomSize;
+ s7r.reg4811=i&0x00FF;
+ s7r.reg4812=(i&0x00FF00)>>8;
+ s7r.reg4813=((i&0xFF0000)>>16);
+ }
+ }
+ }
+ else if(s7r.reg4818&0x40&&!(s7r.reg4818&0x20))
+ {
+ s7r.offset_add|=0x02;
+ if(s7r.offset_add==3)
+ {
+ if(s7r.reg4818&0x10)
+ {
+ }
+ else
+ {
+ uint32 i=(s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811;
+ if(s7r.reg4818&0x08)
+ {
+ short adj;
+ adj=((short)(s7r.reg4815<<8))|s7r.reg4814;
+ i+=adj;
+ }
+ else
+ {
+ uint16 adj;
+ adj=(s7r.reg4815<<8)|s7r.reg4814;
+ i+=adj;
+ }
+ i%=s7r.DataRomSize;
+ s7r.reg4811=i&0x00FF;
+ s7r.reg4812=(i&0x00FF00)>>8;
+ s7r.reg4813=((i&0xFF0000)>>16);
+ }
+ }
+ }
+ }
+ s7r.written|=0x10;
+ break;
+ //data port increment low
+ case 0x4816:
+ s7r.reg4816=data;
+ break;
+ //data port increment high
+ case 0x4817:
+ s7r.reg4817=data;
+ break;
+
+ //data port mode switches
+ //note that it starts inactive.
+ case 0x4818:
+ if((s7r.written&0x18)!=0x18)
+ break;
+ s7r.offset_add=0;
+ s7r.reg4818=data;
+ break;
+
+ //multiplicand low or dividend lowest
+ case 0x4820:
+ s7r.reg4820=data;
+ break;
+ //multiplicand high or dividend lower
+ case 0x4821:
+ s7r.reg4821=data;
+ break;
+ //dividend higher
+ case 0x4822:
+ s7r.reg4822=data;
+ break;
+ //dividend highest
+ case 0x4823:
+ s7r.reg4823=data;
+ break;
+ //multiplier low
+ case 0x4824:
+ s7r.reg4824=data;
+ break;
+ //multiplier high (triggers operation)
+ case 0x4825:
+ s7r.reg4825=data;
+ if(s7r.reg482E&0x01)
+ {
+ int mul;
+ short m1=(short)((s7r.reg4824)|(s7r.reg4825<<8));
+ short m2=(short)((s7r.reg4820)|(s7r.reg4821<<8));
+
+ mul=m1*m2;
+ s7r.reg4828=(uint8)(mul&0x000000FF);
+ s7r.reg4829=(uint8)((mul&0x0000FF00)>>8);
+ s7r.reg482A=(uint8)((mul&0x00FF0000)>>16);
+ s7r.reg482B=(uint8)((mul&0xFF000000)>>24);
+ }
+ else
+ {
+ uint32 mul;
+ uint16 m1=(uint16)((s7r.reg4824)|(s7r.reg4825<<8));
+ uint16 m2=(uint16)((s7r.reg4820)|(s7r.reg4821<<8));
+
+ mul=m1*m2;
+ s7r.reg4828=(uint8)(mul&0x000000FF);
+ s7r.reg4829=(uint8)((mul&0x0000FF00)>>8);
+ s7r.reg482A=(uint8)((mul&0x00FF0000)>>16);
+ s7r.reg482B=(uint8)((mul&0xFF000000)>>24);
+ }
+ s7r.reg482F=0x80;
+ break;
+ //divisor low
+ case 0x4826:
+ s7r.reg4826=data;
+ break;
+ //divisor high (triggers operation)
+ case 0x4827:
+ s7r.reg4827=data;
+ if(s7r.reg482E&0x01)
+ {
+ int quotient;
+ short remainder;
+ int dividend=(int)(s7r.reg4820|(s7r.reg4821<<8)|(s7r.reg4822<<16)|(s7r.reg4823<<24));
+ short divisor=(short)(s7r.reg4826|(s7r.reg4827<<8));
+ if(divisor != 0)
+ {
+ quotient=(int)(dividend/divisor);
+ remainder=(short)(dividend%divisor);
+ }
+ else
+ {
+ quotient=0;
+ remainder=dividend&0x0000FFFF;
+ }
+ s7r.reg4828=(uint8)(quotient&0x000000FF);
+ s7r.reg4829=(uint8)((quotient&0x0000FF00)>>8);
+ s7r.reg482A=(uint8)((quotient&0x00FF0000)>>16);
+ s7r.reg482B=(uint8)((quotient&0xFF000000)>>24);
+ s7r.reg482C=(uint8)remainder&0x00FF;
+ s7r.reg482D=(uint8)((remainder&0xFF00)>>8);
+ }
+ else
+ {
+ uint32 quotient;
+ uint16 remainder;
+ uint32 dividend=(uint32)(s7r.reg4820|(s7r.reg4821<<8)|(s7r.reg4822<<16)|(s7r.reg4823<<24));
+ uint16 divisor=(uint16)(s7r.reg4826|(s7r.reg4827<<8));
+ if(divisor != 0)
+ {
+ quotient=(uint32)(dividend/divisor);
+ remainder=(uint16)(dividend%divisor);
+ }
+ else
+ {
+ quotient=0;
+ remainder=dividend&0x0000FFFF;
+ }
+ s7r.reg4828=(uint8)(quotient&0x000000FF);
+ s7r.reg4829=(uint8)((quotient&0x0000FF00)>>8);
+ s7r.reg482A=(uint8)((quotient&0x00FF0000)>>16);
+ s7r.reg482B=(uint8)((quotient&0xFF000000)>>24);
+ s7r.reg482C=(uint8)remainder&0x00FF;
+ s7r.reg482D=(uint8)((remainder&0xFF00)>>8);
+ }
+ s7r.reg482F=0x80;
+ break;
+ //result registers are possibly read-only
+
+ //reset: writes here nuke the whole math unit
+ //Zero indicates unsigned math, resets with non-zero values turn on signed math
+ case 0x482E:
+ s7r.reg4820=s7r.reg4821=s7r.reg4822=s7r.reg4823=s7r.reg4824=s7r.reg4825=s7r.reg4826=s7r.reg4827=s7r.reg4828=s7r.reg4829=s7r.reg482A=s7r.reg482B=s7r.reg482C=s7r.reg482D=0;
+ s7r.reg482E=data;
+ break;
+
+ //math status register possibly read only
+
+ //SRAM toggle
+ case 0x4830:
+ Memory.SPC7110Sram(data);
+ s7r.reg4830=data;
+ break;
+ //Bank DX mapping
+ case 0x4831:
+ s7r.reg4831=data;
+ break;
+ //Bank EX mapping
+ case 0x4832:
+ s7r.reg4832=data;
+ break;
+ //Bank FX mapping
+ case 0x4833:
+ s7r.reg4833=data;
+ break;
+ //S-RAM mapping? who knows?
+ case 0x4834:
+ s7r.reg4834=data;
+ break;
+ //RTC Toggle
+ case 0x4840:
+ if(0==data)
+ {
+ S9xUpdateRTC();
+ // rtc_f9.init=false;
+ // rtc_f9.index=-1;
+ }
+ if(data&0x01)
+ {
+ s7r.reg4842=0x80;
+ //rtc_f9.last_used=time(NULL);//????
+ rtc_f9.init=false;
+ rtc_f9.index=-1;
+ }
+ s7r.reg4840=data;
+ break;
+ //RTC init/command/index register
+ case 0x4841:
+ if(rtc_f9.init)
+ {
+ if(-1==rtc_f9.index)
+ {
+ rtc_f9.index=data&0x0F;
+ break;
+ }
+ if(rtc_f9.control==0x0C)
+ {
+ rtc_f9.index=data&0x0F;
+ s7r.reg4842=0x80;
+ rtc_f9.last_used=time(NULL);
+ }
+ else
+ {
+
+ if(0x0D==rtc_f9.index)
+ {
+ if(data&0x08)
+ {
+ if(rtc_f9.reg[1]<3)
+ {
+ S9xUpdateRTC();
+ rtc_f9.reg[0]=0;
+ rtc_f9.reg[1]=0;
+ rtc_f9.last_used=time(NULL);
+ }
+ else
+ {
+ S9xUpdateRTC();
+ rtc_f9.reg[0]=0;
+ rtc_f9.reg[1]=0;
+ rtc_f9.last_used=time(NULL)-60;
+ S9xUpdateRTC();
+ rtc_f9.last_used=time(NULL);
+ }
+ data&=0x07;
+ }
+ if(rtc_f9.reg[0x0D]&0x01)
+ {
+ if(!(data%2))
+ {
+ rtc_f9.reg[rtc_f9.index&0x0F]=data;
+ rtc_f9.last_used=time(NULL)-1;
+ S9xUpdateRTC();
+ rtc_f9.last_used=time(NULL);
+ }
+ }
+ }
+ if(0x0F==rtc_f9.index)
+ {
+ if(data&0x01&&!(rtc_f9.reg[0x0F]&0x01))
+ {
+ S9xUpdateRTC();
+ rtc_f9.reg[0]=0;
+ rtc_f9.reg[1]=0;
+ rtc_f9.last_used=time(NULL);
+ }
+ if(data&0x02&&!(rtc_f9.reg[0x0F]&0x02))
+ {
+ S9xUpdateRTC();
+ rtc_f9.last_used=time(NULL);
+ }
+ }
+ rtc_f9.reg[rtc_f9.index&0x0F]=data;
+ s7r.reg4842=0x80;
+ rtc_f9.index=(rtc_f9.index+1)%0x10;
+ }
+ }
+ else
+ {
+ if(data==0x03||data==0x0C)
+ {
+ rtc_f9.init=true;
+ rtc_f9.control=data;
+ rtc_f9.index=-1;
+ }
+ }
+ break;
+ //writes to RTC status register aren't expected to be meaningful
+ default:
+ Address-=0x4800;
+ break;
+ //16 BIT MULTIPLIER: ($FF00) high byte, defval:00
+ }
+}
+extern "C"{
+//emulate the SPC7110's ability to remap banks Dx, Ex, and Fx.
+uint8 S9xGetSPC7110Byte(uint32 Address)
+{
+ uint32 i;
+ switch((Address&0x00F00000)>>16)
+ {
+ case 0xD0:
+ i=s7r.reg4831*0x00100000;
+ break;
+ case 0xE0:
+ i=s7r.reg4832*0x00100000;
+ break;
+ case 0xF0:
+ i=s7r.reg4833*0x00100000;
+ break;
+ default:i=0;
+ }
+ i+=Address&0x000FFFFF;
+ i+=s7r.DataRomOffset;
+ return ROM[i];
+}
+}
+/**********************************************************************************************/
+/* S9xSRTCDaysInMonth() */
+/* Return the number of days in a specific month for a certain year */
+/* copied directly for RTC functionality, separated in case of incompatibilities */
+/**********************************************************************************************/
+int S9xRTCDaysInMonth( int month, int year )
+{
+ int mdays;
+
+ switch ( month )
+ {
+ case 2:
+ if ( ( year % 4 == 0 ) ) // DKJM2 only uses 199x - 22xx
+ mdays = 29;
+ else
+ mdays = 28;
+ break;
+
+ case 4:
+ case 6:
+ case 9:
+ case 11:
+ mdays = 30;
+ break;
+
+ default: // months 1,3,5,7,8,10,12
+ mdays = 31;
+ break;
+ }
+
+ return mdays;
+}
+
+
+#define DAYTICKS (60*60*24)
+#define HOURTICKS (60*60)
+#define MINUTETICKS 60
+
+
+/**********************************************************************************************/
+/* S9xUpdateRTC() */
+/* Advance the RTC time */
+/**********************************************************************************************/
+
+void S9xUpdateRTC ()
+{
+ time_t cur_systime;
+ long time_diff;
+
+ // Keep track of game time by computing the number of seconds that pass on the system
+ // clock and adding the same number of seconds to the RTC clock structure.
+
+ if (rtc_f9.init && 0==(rtc_f9.reg[0x0D]&0x01) && 0==(rtc_f9.reg[0x0F]&0x03))
+ {
+ cur_systime = time (NULL);
+
+ // This method assumes one time_t clock tick is one second
+ // which should work on PCs and GNU systems.
+ // If your tick interval is different adjust the
+ // DAYTICK, HOURTICK, and MINUTETICK defines
+
+ time_diff = (long) (cur_systime - rtc_f9.last_used);
+ rtc_f9.last_used = cur_systime;
+
+ if ( time_diff > 0 )
+ {
+ int seconds;
+ int minutes;
+ int hours;
+ int days;
+ int month;
+ int year;
+ int temp_days;
+
+ int year_hundreds;
+ int year_tens;
+ int year_ones;
+
+
+ if ( time_diff > DAYTICKS )
+ {
+ days = time_diff / DAYTICKS;
+ time_diff = time_diff - days * DAYTICKS;
+ }
+ else
+ {
+ days = 0;
+ }
+
+ if ( time_diff > HOURTICKS )
+ {
+ hours = time_diff / HOURTICKS;
+ time_diff = time_diff - hours * HOURTICKS;
+ }
+ else
+ {
+ hours = 0;
+ }
+
+ if ( time_diff > MINUTETICKS )
+ {
+ minutes = time_diff / MINUTETICKS;
+ time_diff = time_diff - minutes * MINUTETICKS;
+ }
+ else
+ {
+ minutes = 0;
+ }
+
+ if ( time_diff > 0 )
+ {
+ seconds = time_diff;
+ }
+ else
+ {
+ seconds = 0;
+ }
+
+
+ seconds += (rtc_f9.reg[1]*10 + rtc_f9.reg[0]);
+ if ( seconds >= 60 )
+ {
+ seconds -= 60;
+ minutes += 1;
+ }
+
+ minutes += (rtc_f9.reg[3]*10 + rtc_f9.reg[2]);
+ if ( minutes >= 60 )
+ {
+ minutes -= 60;
+ hours += 1;
+ }
+
+ hours += (rtc_f9.reg[5]*10 + rtc_f9.reg[4]);
+ if ( hours >= 24 )
+ {
+ hours -= 24;
+ days += 1;
+ }
+
+ year = rtc_f9.reg[11]*10 + rtc_f9.reg[10];
+ year += ( 1900 );
+ month = rtc_f9.reg[8]+10*rtc_f9.reg[9];
+ rtc_f9.reg[12]+=days;
+ days += (rtc_f9.reg[7]*10 + rtc_f9.reg[6]);
+ if ( days > 0 )
+ {
+ while ( days > (temp_days = S9xRTCDaysInMonth( month, year )) )
+ {
+ days -= temp_days;
+ month += 1;
+ if ( month > 12 )
+ {
+ year += 1;
+ month = 1;
+ }
+ }
+ }
+
+ year_tens = year % 100;
+ year_ones = year_tens % 10;
+ year_tens /= 10;
+ year_hundreds = (year - 1000) / 100;
+
+ rtc_f9.reg[0] = seconds % 10;
+ rtc_f9.reg[1] = seconds / 10;
+ rtc_f9.reg[2] = minutes % 10;
+ rtc_f9.reg[3] = minutes / 10;
+ rtc_f9.reg[4] = hours % 10;
+ rtc_f9.reg[5] = hours / 10;
+ rtc_f9.reg[6] = days % 10;
+ rtc_f9.reg[7] = days / 10;
+ rtc_f9.reg[8] = month%10;
+ rtc_f9.reg[9] = month /10;
+ rtc_f9.reg[10] = year_ones;
+ rtc_f9.reg[11] = year_tens;
+ rtc_f9.reg[12] %= 7;
+ return;
+ }
+ }
+}
+extern "C"{
+
+//allows DMA from the ROM (is this even possible on the SPC7110?
+uint8* Get7110BasePtr(uint32 Address)
+{
+ uint32 i;
+ switch((Address&0x00F00000)>>16)
+ {
+ case 0xD0:
+ i=s7r.reg4831*0x100000;
+ break;
+ case 0xE0:
+ i=s7r.reg4832*0x100000;
+ break;
+ case 0xF0:
+ i=s7r.reg4833*0x100000;
+ break;
+ default:i=0;
+ }
+ i+=Address&0x000F0000;
+ return &ROM[i];
+}
+//end extern
+}
+
+//loads the index into memory.
+//index.bin is little-endian
+//format index (1)-table(3)-file offset(4)-length(4)
+bool Load7110Index(char* filename)
+{
+ FILE* fp;
+ uint8 buffer[12];
+ int table=0;
+ uint8 index=0;
+ uint32 offset=0;
+ uint32 size=0;
+ int i=0;
+ fp=fopen(filename, "rb");
+ if(NULL==fp)
+ return false;
+
+ int f_len;
+ //do
+ while(1)
+ {
+ i=0;
+ f_len= fread(buffer, 1, 12,fp);
+ if(f_len < 12) break;
+
+ table=(buffer[3]<<16)|(buffer[2]<<8)|buffer[1];
+ index=buffer[0];
+ offset=(buffer[7]<<24)|(buffer[6]<<16)|(buffer[5]<<8)|buffer[4];
+ size=(buffer[11]<<24)|(buffer[10]<<16)|(buffer[9]<<8)|buffer[8];
+ while(i<MAX_TABLES&&decompack->tableEnts[i].table!=table&&decompack->tableEnts[i].table!=0)
+ i++;
+ if(i==MAX_TABLES)
+ return false;
+ //added
+ decompack->tableEnts[i].table=table;
+ //-----
+ decompack->tableEnts[i].location[index].offset=offset;
+ decompack->tableEnts[i].location[index].size=size;
+ decompack->tableEnts[i].location[index].used_len=0;
+ decompack->tableEnts[i].location[index].used_offset=0;
+
+ }
+ //while(!feof(fp));
+ fclose(fp);
+ return true;
+}
+
+
+//Cache 1 load function
+void SPC7110Load(char* dirname)
+{
+ char temp_path[PATH_MAX];
+ int i=0;
+
+ decompack=new Pack7110;
+
+#ifndef _XBOX
+ getcwd(temp_path,PATH_MAX);
+#endif
+
+ ZeroMemory(decompack, sizeof(Pack7110));
+
+#ifndef _XBOX
+ if(-1==chdir(dirname))
+ {
+ S9xMessage(0,0,"Graphics Pack not found!");
+ }
+#endif
+
+#ifndef _XBOX
+ Load7110Index("index.bin");
+#else
+ // D:\\ is always app.path in Xbox
+ Load7110Index("d:\\index.bin");
+#endif
+
+ for(i=0;i<MAX_TABLES;i++)
+ {
+ if(decompack->tableEnts[i].table!=0)
+ {
+ char binname[PATH_MAX];
+#ifndef _XBOX
+ sprintf(binname,"%06X.bin",decompack->tableEnts[i].table);
+#else
+ sprintf(binname,"%s%06X.bin",filename,decompack->tableEnts[i].table);
+#endif
+ struct stat buf;
+ if(-1!=stat(binname, &buf))
+ decompack->binfiles[i]=new uint8[buf.st_size];
+ FILE* fp=fopen(binname, "rb");
+ if(fp)
+ {
+ fread(decompack->binfiles[i],buf.st_size,1,fp);
+ fclose(fp);
+ }
+ }
+ }
+
+#ifndef _XBOX
+ chdir(temp_path);
+#endif
+
+ Copy7110=&MovePackData;
+ CleanUp7110=&Del7110Gfx;
+#ifdef __WIN32__
+ #ifndef _XBOX
+ EnableMenuItem(GUI.hMenu, IDM_LOG_7110, MF_ENABLED);
+ #endif
+#endif
+}
+
+//Cache 2 load function
+void SPC7110Open(char* dirname)
+{
+ char temp_path[PATH_MAX];
+ int i=0;
+
+ decompack=new Pack7110;
+
+#ifndef _XBOX
+ getcwd(temp_path,PATH_MAX);
+#endif
+
+ ZeroMemory(decompack, sizeof(Pack7110));
+
+#ifndef _XBOX
+ if(-1==chdir(dirname))
+ {
+ S9xMessage(0,0,"Graphics Pack not found!");
+ }
+#endif
+
+#ifndef _XBOX
+ Load7110Index("index.bin");
+#else
+ // D:\\ is always app.path in Xbox
+ Load7110Index("d:\\index.bin");
+#endif
+
+ for (i=0; i<MAX_TABLES; i++)
+ decompack->binfiles[i]=NULL;
+
+ ReadPackData();
+
+#ifndef _XBOX
+ chdir(temp_path);
+#endif
+
+ Copy7110=&ReadPackData;
+ CleanUp7110=&Close7110Gfx;
+
+#ifdef __WIN32__
+ #ifndef _XBOX
+ EnableMenuItem(GUI.hMenu, IDM_LOG_7110, MF_ENABLED);
+ #endif
+#endif
+}
+
+//Cache 3's load function
+void SPC7110Grab(char* dirname)
+{
+ char temp_path[PATH_MAX];
+ int i=0;
+
+ decompack=new Pack7110;
+
+#ifndef _XBOX
+ getcwd(temp_path,PATH_MAX);
+#endif
+
+ int32 buffer_size=1024*1024*cacheMegs;//*some setting
+
+ ZeroMemory(decompack, sizeof(Pack7110));
+#ifndef _XBOX
+
+ if(-1==chdir(dirname))
+ {
+ S9xMessage(0,0,"Graphics Pack not found!");
+ }
+#endif
+
+#ifndef _XBOX
+ Load7110Index("index.bin");
+#else
+ // D:\\ is always app.path in Xbox
+ Load7110Index("d:\\index.bin");
+#endif
+
+ for(i=0;i<MAX_TABLES;i++)
+ {
+ if(decompack->tableEnts[i].table!=0)
+ {
+ char binname[PATH_MAX];
+#ifndef _XBOX
+ sprintf(binname,"%06X.bin",decompack->tableEnts[i].table);
+#else
+ sprintf(binname,"%s%06X.bin",filename,decompack->tableEnts[i].table);
+#endif
+ struct stat buf;
+//add load/no load calculations here
+ if(-1!=stat(binname, &buf))
+ {
+ if(buf.st_size<buffer_size)
+ decompack->binfiles[i]=new uint8[buf.st_size];
+ FILE* fp=fopen(binname, "rb");
+ //use them here
+ if(fp)
+ {
+ if(buf.st_size<buffer_size)
+ {
+ fread(decompack->binfiles[i],buf.st_size,1,fp);
+ fclose(fp);
+ buffer_size-=buf.st_size;
+ decompack->tableEnts[i].is_file=false;
+ }
+ else
+ {
+ decompack->binfiles[i]=(uint8*)fp;
+ decompack->tableEnts[i].is_file=true;
+ }
+ }
+ }
+ }
+ }
+
+#ifndef _XBOX
+ chdir(temp_path);
+#endif
+
+ Copy7110=&GetPackData;
+ CleanUp7110=&Drop7110Gfx;
+
+
+#ifdef __WIN32__
+ #ifndef _XBOX
+ EnableMenuItem(GUI.hMenu, IDM_LOG_7110, MF_ENABLED);
+ #endif
+#endif
+}
+
+//Cache 1 clean up function
+void Del7110Gfx()
+{
+ int i;
+ if(Settings.SPC7110)
+ {
+#ifdef __WIN32__
+ #ifndef _XBOX
+ EnableMenuItem(GUI.hMenu, IDM_LOG_7110, MF_GRAYED);
+ #endif
+#endif
+ Do7110Logging();
+ }
+ for(i=0;i<MAX_TABLES;i++)
+ {
+ if(decompack->binfiles[i]!=NULL)
+ {
+ delete []decompack->binfiles[i];
+ decompack->binfiles[i]=NULL;
+ }
+ }
+ Settings.SPC7110=false;
+ Settings.SPC7110RTC=false;
+ if(NULL!=decompack)
+ delete decompack;
+ decompack=NULL;
+ CleanUp7110=NULL;
+ Copy7110=NULL;
+}
+
+//Cache2 cleanup function
+void Close7110Gfx()
+{
+ int i;
+ if(Settings.SPC7110)
+ {
+#ifdef __WIN32__
+ #ifndef _XBOX
+ EnableMenuItem(GUI.hMenu, IDM_LOG_7110, MF_GRAYED);
+ #endif
+#endif
+ Do7110Logging();
+ }
+ for(i=0;i<MAX_TABLES;i++)
+ {
+ if(decompack->binfiles[i]!=NULL)
+ {
+ fclose((FILE*)decompack->binfiles[i]);
+ decompack->binfiles[i]=NULL;
+ }
+ }
+ Settings.SPC7110=false;
+ Settings.SPC7110RTC=false;
+ if(NULL!=decompack)
+ delete decompack;
+ decompack=NULL;
+ CleanUp7110=NULL;
+ Copy7110=NULL;
+}
+
+//cache 3's clean-up code
+void Drop7110Gfx()
+{
+ int i;
+ if(Settings.SPC7110)
+ {
+#ifdef __WIN32__
+ #ifndef _XBOX
+ EnableMenuItem(GUI.hMenu, IDM_LOG_7110, MF_GRAYED);
+ #endif
+#endif
+ Do7110Logging();
+ }
+ for(i=0;i<MAX_TABLES;i++)
+ {
+ if(decompack->binfiles[i]!=NULL)
+ {
+ if(decompack->tableEnts[i].is_file)
+ {
+ fclose((FILE*)decompack->binfiles[i]);
+ decompack->binfiles[i]=NULL;
+ }
+ else
+ {
+ delete []decompack->binfiles[i];
+ decompack->binfiles[i]=NULL;
+ }
+ }
+ }
+ Settings.SPC7110=false;
+ Settings.SPC7110RTC=false;
+ if(NULL!=decompack)
+ delete decompack;
+ decompack=NULL;
+ CleanUp7110=NULL;
+ Copy7110=NULL;
+}
+
+//emulate a reset.
+void S9xSpc7110Reset()
+{
+ s7r.reg4800=0;
+ s7r.reg4801=0;
+ s7r.reg4802=0;
+ s7r.reg4803=0;
+ s7r.reg4804=0;
+ s7r.reg4805=0;
+ s7r.reg4806=0;
+ s7r.reg4807=0;
+ s7r.reg4808=0;
+ s7r.reg4809=0;
+ s7r.reg480A=0;
+ s7r.reg480B=0;
+ s7r.reg480C=0;
+ s7r.reg4811=0;
+ s7r.reg4812=0;
+ s7r.reg4813=0;
+ s7r.reg4814=0;
+ s7r.reg4815=0;
+ s7r.reg4816=0;
+ s7r.reg4817=0;
+ s7r.reg4818=0;
+ s7r.reg4820=0;
+ s7r.reg4821=0;
+ s7r.reg4822=0;
+ s7r.reg4823=0;
+ s7r.reg4824=0;
+ s7r.reg4825=0;
+ s7r.reg4826=0;
+ s7r.reg4827=0;
+ s7r.reg4828=0;
+ s7r.reg4829=0;
+ s7r.reg482A=0;
+ s7r.reg482B=0;
+ s7r.reg482C=0;
+ s7r.reg482D=0;
+ s7r.reg482E=0;
+ s7r.reg482F=0;
+ s7r.reg4830=0;
+ s7r.reg4831=0;
+ s7r.reg4832=1;
+ s7r.reg4833=2;
+ s7r.reg4834=0;
+ s7r.reg4840=0;
+ s7r.reg4841=0;
+ s7r.reg4842=0;
+ s7r.written=0;
+ s7r.offset_add=0;
+ s7r.AlignBy=1;
+ s7r.bank50Internal=0;
+ memset(s7r.bank50,0x00,DECOMP_BUFFER_SIZE);
+}
+
+
+//outputs a cumulative log for the game.
+//there's nothing really weird here, just
+//reading the old log, and writing a new one.
+//note the logs are explicitly little-endian, not host byte order.
+void Do7110Logging()
+{
+ uint8 ent_temp;
+ FILE* flog;
+ int entries=0;
+
+ if(Settings.SPC7110)
+ {
+ //flush last read into logging
+ (*Copy7110)();
+
+ if(!strncmp((char*)&Memory.ROM [0xffc0], "SUPER POWER LEAG 4 ", 21))
+ {
+#ifdef _XBOX
+ flog=fopen("T:\\spl4-sp7.dat","rb");
+#else
+ flog=fopen("spl4-sp7.dat","rb");
+#endif
+ }
+ else if(!strncmp((char*)&Memory.ROM [0xffc0], "MOMOTETSU HAPPY ",21))
+ {
+#ifdef _XBOX
+ flog=fopen("T:\\smht-sp7.dat","rb");
+#else
+ flog=fopen("smht-sp7.dat","rb");
+#endif
+ }
+ else if(!strncmp((char*)&Memory.ROM [0xffc0], "HU TENGAI MAKYO ZERO ", 21))
+ {
+#ifdef _XBOX
+ flog=fopen("T:\\feoezsp7.dat","rb");
+#else
+ flog=fopen("feoezsp7.dat","rb");
+#endif
+ }
+ else if(!strncmp((char*)&Memory.ROM [0xffc0], "JUMP TENGAIMAKYO ZERO",21))
+ {
+#ifdef _XBOX
+ flog=fopen("T:\\sjumpsp7.dat","rb");
+#else
+ flog=fopen("sjumpsp7.dat","rb");
+#endif
+ }
+ else
+ {
+#ifdef _XBOX
+ flog=fopen("T:\\misc-sp7.dat","rb");
+#else
+ flog=fopen("misc-sp7.dat","rb");
+#endif
+ }
+
+ if(flog)
+ {
+ uint8 buffer[8];
+ int table=0;
+ uint16 offset=0;
+ uint16 length=0;
+ fseek(flog, 35,0);
+
+ int f_len;
+ //do
+ while(1)
+ {
+ int i=0;
+ Data7110 *log=NULL;
+ f_len= fread(buffer, 1, 8, flog);
+ if(f_len < 8) break;
+
+ table=buffer[0]|(buffer[1]<<8)|(buffer[2]<<16);
+ offset=buffer[6]|(buffer[7]<<8);
+ length=buffer[4]|(buffer[5]<<8);
+ while(i<MAX_TABLES&&log==NULL)
+ {
+ if(decompack->tableEnts[i].table==table)
+ {
+ log=&(decompack->tableEnts[i].location[(buffer[3])]);
+ if((log->used_offset+log->used_len)<(offset+length))
+ {
+ log->used_offset=offset;
+ log->used_len=length;
+ }
+ }
+ i++;
+ }
+ }
+ //while(!feof(flog));
+ fclose(flog);
+ }
+
+
+ if(!strncmp((char*)&Memory.ROM [0xffc0], "SUPER POWER LEAG 4 ", 21))
+ {
+#ifdef _XBOX // cwd could be the dvd-rom, so write to T:\\ which is storage region for each title
+ flog=fopen("T:\\spl4-sp7.dat","wb");
+#else
+ flog=fopen("spl4-sp7.dat","wb");
+#endif
+ }
+ else if(!strncmp((char*)&Memory.ROM [0xffc0], "MOMOTETSU HAPPY ",21))
+ {
+#ifdef _XBOX
+ flog=fopen("T:\\smht-sp7.dat","wb");
+#else
+ flog=fopen("smht-sp7.dat","wb");
+#endif
+ }
+ else if(!strncmp((char*)&Memory.ROM [0xffc0], "HU TENGAI MAKYO ZERO ", 21))
+ {
+#ifdef _XBOX
+ flog=fopen("T:\\feoezsp7.dat","wb");
+#else
+ flog=fopen("feoezsp7.dat","wb");
+#endif
+ }
+ else if(!strncmp((char*)&Memory.ROM [0xffc0], "JUMP TENGAIMAKYO ZERO",21))
+ {
+#ifdef _XBOX
+ flog=fopen("T:\\sjumpsp7.dat","wb");
+#else
+ flog=fopen("sjumpsp7.dat","wb");
+#endif
+ }
+ else
+ {
+#ifdef _XBOX
+ flog=fopen("T:\\misc-sp7.dat","wb");
+#else
+ flog=fopen("misc-sp7.dat","wb");
+#endif
+ }
+ //count entries
+ if(flog)
+ {
+ int j=0;
+ int temp=0;
+ for(j=0;j<MAX_TABLES;j++)
+ {
+ for(int k=0;k<256;k++)
+ {
+ if(decompack->tableEnts[j].location[k].used_len!=0)
+ entries++;
+ }
+ }
+ ent_temp=entries&0xFF;
+ fwrite(&ent_temp,1,1,flog);
+ ent_temp=(entries>>8)&0xFF;
+ fwrite(&ent_temp,1,1,flog);
+ ent_temp=(entries>>16)&0xFF;
+ fwrite(&ent_temp,1,1,flog);
+ ent_temp=(entries>>24)&0xFF;
+ fwrite(&ent_temp,1,1,flog);
+ fwrite(&temp,1,4,flog);
+ fwrite(&temp,1,4,flog);
+ fwrite(&temp,1,4,flog);
+ fwrite(&temp,1,4,flog);
+ fwrite(&temp,1,4,flog);
+ fwrite(&temp,1,4,flog);
+ fwrite(&temp,1,4,flog);
+
+ ent_temp=0;
+ fwrite(&ent_temp,1,1,flog);
+ ent_temp=0;
+ fwrite(&ent_temp,1,1,flog);
+ ent_temp=0;
+ fwrite(&ent_temp,1,1,flog);
+
+ for(j=0;j<MAX_TABLES;j++)
+ {
+ for(int k=0;k<256;k++)
+ {
+ if(decompack->tableEnts[j].location[k].used_len!=0)
+ {
+ ent_temp=decompack->tableEnts[j].table&0xFF;
+ fwrite(&ent_temp,1,1,flog);//801
+ ent_temp=(decompack->tableEnts[j].table>>8)&0xFF;;
+ fwrite(&ent_temp,1,1,flog);//802
+ ent_temp=(decompack->tableEnts[j].table>>16)&0xFF;;
+ fwrite(&ent_temp,1,1,flog);//803
+ ent_temp=k&0xFF;
+ fwrite(&ent_temp,1,1,flog);//804
+ ent_temp=decompack->tableEnts[j].location[k].used_len&0xFF;
+ fwrite(&ent_temp,1,1,flog);//lsb of
+ ent_temp=(decompack->tableEnts[j].location[k].used_len>>8)&0xFF;
+ fwrite(&ent_temp,1,1,flog);//msb of
+ ent_temp=(decompack->tableEnts[j].location[k].used_offset)&0xFF;
+ fwrite(&ent_temp,1,1,flog);//lsb of
+ ent_temp=(decompack->tableEnts[j].location[k].used_offset>>8)&0xFF;
+ fwrite(&ent_temp,1,1,flog);//msb of
+ }
+ }
+ }
+ fwrite(&temp,1,4,flog);
+ fwrite(&temp,1,4,flog);
+ fclose(flog);
+ }
+ }
+}
+bool8 S9xSaveSPC7110RTC (S7RTC *rtc_f9)
+{
+ FILE* fp;
+
+ if((fp=fopen(S9xGetFilename(".rtc"), "wb"))==NULL)
+ return (FALSE);
+ int i=0;
+ uint8 temp=0;
+ for (i=0;i<16;i++)
+ fwrite(&rtc_f9->reg[i],1,1,fp);
+ temp=rtc_f9->index&0x00FF;
+ fwrite(&temp,1,1,fp);
+ temp=(rtc_f9->index)>>8;
+ fwrite(&temp,1,1,fp);
+ temp=(uint8)rtc_f9->control;
+ fwrite(&temp,1,1,fp);
+ temp=(uint8)rtc_f9->init;
+ fwrite(&temp,1,1,fp);
+ temp=rtc_f9->last_used&0x00FF;
+ fwrite(&temp,1,1,fp);
+ temp=(rtc_f9->last_used>>8)&0x00FF;
+ fwrite(&temp,1,1,fp);
+ temp=(rtc_f9->last_used>>16)&0x00FF;
+ fwrite(&temp,1,1,fp);
+ temp=(rtc_f9->last_used>>24)&0x00FF;;
+ fwrite(&temp,1,1,fp);
+ fclose(fp);
+ return (TRUE);
+}
+
+bool8 S9xLoadSPC7110RTC (S7RTC *rtc_f9)
+{
+ FILE* fp;
+
+ if((fp=fopen(S9xGetFilename(".rtc"), "rb"))==NULL)
+ return (FALSE);
+ for (int i=0; i<16;i++)
+ {
+ fread(&(rtc_f9->reg[i]),1,1,fp);
+ }
+ uint8 temp=0;
+ fread(&temp,1,1,fp);
+ rtc_f9->index=temp;
+ fread(&temp,1,1,fp);
+ rtc_f9->index|=(temp<<8);
+ fread(&rtc_f9->control,1,1,fp);
+ fread(&rtc_f9->init,1,1,fp);
+
+ fread(&temp,1,1,fp);
+ rtc_f9->last_used=temp;
+ fread(&temp,1,1,fp);
+ rtc_f9->last_used|=(temp<<8);
+ fread(&temp,1,1,fp);
+ rtc_f9->last_used|=(temp<<16);
+ fread(&temp,1,1,fp);
+ rtc_f9->last_used|=(temp<<24);
+ fclose(fp);
+ return (TRUE);
+}
+