632 lines
15 KiB
C
632 lines
15 KiB
C
/*
|
|
Copyright (C) 1997-2007 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )
|
|
|
|
http://www.zsnes.com
|
|
http://sourceforge.net/projects/zsnes
|
|
https://zsnes.bountysource.com
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
version 2 as published by the Free Software Foundation.
|
|
|
|
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
|
|
#ifdef __UNIXSDL__
|
|
#include "gblhdr.h"
|
|
#include <dirent.h>
|
|
#else
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#endif
|
|
|
|
#include "asm_call.h"
|
|
#include "cfg.h"
|
|
#include "input.h"
|
|
#include "mmlib/mm.h"
|
|
#include "zpath.h"
|
|
|
|
//C++ style code in C
|
|
#define bool unsigned char
|
|
#define true 1
|
|
#define false 0
|
|
|
|
extern unsigned int xa, MessageOn, maxromspace;
|
|
extern unsigned char FPSOn, spcon, device1, device2;
|
|
extern char *Msgptr, CSStatus[], CSStatus2[], CSStatus3[];
|
|
|
|
unsigned short selc0040, selcA000, selcB800;
|
|
|
|
unsigned char *vidbuffer; // video buffer (1024x239 = 244736)
|
|
unsigned char *ngwinptr;
|
|
unsigned char *vidbufferofsa; // offset 1
|
|
unsigned char *vidbufferofsb; // offset 2
|
|
unsigned char *headdata;
|
|
unsigned char *romdata; // rom data (4MB = 4194304)
|
|
unsigned char *sfxramdata; // SuperFX Ram Data
|
|
unsigned char *setaramdata; // Seta ST010/ST011 SRam Data
|
|
unsigned char *wramdata; // stack (64K = 65536)
|
|
unsigned char *ram7f; // ram @ 7f = 65536
|
|
unsigned char *vram; // vram = 65536
|
|
unsigned char *sram; // sram = 65536*2 = 131072
|
|
#ifdef OLD_DEBUGGER
|
|
unsigned char *debugbuf; // debug buffer = 80x1000 = 80000
|
|
#endif
|
|
unsigned char regptra[49152];
|
|
unsigned char regptwa[49152];
|
|
unsigned char *regptr = regptra;
|
|
unsigned char *regptw = regptwa;
|
|
unsigned char *vcache2b; // 2-bit video cache
|
|
unsigned char *vcache4b; // 4-bit video cache
|
|
unsigned char *vcache8b; // 8-bit video cache
|
|
unsigned char *SPC7110PackPtr;
|
|
unsigned char *SPC7110IndexPtr;
|
|
unsigned char romispal; // 0 = NTSC, 1 = PAL
|
|
unsigned char newgfx16b;
|
|
|
|
unsigned char previdmode; // previous video mode
|
|
unsigned char cbitmode; // bit mode, 0=8bit, 1=16bit
|
|
|
|
unsigned char opexec268 = 142; // # of opcodes/scanline in 2.68Mhz mode
|
|
unsigned char opexec358 = 167; // # of opcodes/scanline in 3.58Mhz mode (228/180)
|
|
unsigned char opexec268cph = 42; // # of opcodes/hblank in 2.68Mhz mode
|
|
unsigned char opexec358cph = 45; // # of opcodes/hblank in 3.58Mhz mode (56/50)
|
|
unsigned char opexec268b = 142; // # of opcodes/scanline in 2.68Mhz mode
|
|
unsigned char opexec358b = 167; // # of opcodes/scanline in 3.58Mhz mode (228/180)
|
|
unsigned char opexec268cphb = 42; // # of opcodes/hblank in 2.68Mhz mode
|
|
unsigned char opexec358cphb = 45; // # of opcodes/hblank in 3.58Mhz mode (56/50)
|
|
unsigned char debugdisble = 1; // debugger disable. 0 = no, 1 = yes
|
|
unsigned char gammalevel16b = 0; // gamma level (16-bit engine)
|
|
unsigned char AddSub256 = 0; // screen add/sub in 256 colors
|
|
unsigned char dmadeddis = 0; // DMA deduction
|
|
unsigned char OldStyle = 1; // Old style joystick on
|
|
unsigned char SecondPort = 0; // Secondary Joystick Port Enabled (209h) (DOS port only)
|
|
|
|
unsigned char Doublevbuf = 1; // Double video buffer
|
|
unsigned char V8Mode = 0; // Vegetable mode! =) (Greyscale mode)
|
|
unsigned char fastmemptr = 0;
|
|
unsigned char ForcePal = 0; // 1 = NTSC, 2 = PAL
|
|
unsigned char finterleave = 0;
|
|
unsigned char DSPDisable = 0; // Disable DSP emulation
|
|
unsigned char MusicVol = 0;
|
|
unsigned char MMXextSupport = 0;
|
|
|
|
void init(), WaitForKey(), MMXCheck(), InitSPC(), DosExit();
|
|
void SystemInit(), StartUp(), MultiMouseInit();
|
|
|
|
void *alloc_ptr;
|
|
unsigned int alloc_size;
|
|
|
|
void alloc_help()
|
|
{
|
|
alloc_ptr=malloc(alloc_size);
|
|
}
|
|
|
|
extern bool input1gp;
|
|
extern bool input1mouse;
|
|
extern bool input2gp;
|
|
extern bool input2mouse;
|
|
extern bool input2scope;
|
|
extern bool input2just;
|
|
|
|
void cycleinputdevice1()
|
|
{
|
|
for (;;)
|
|
{
|
|
device1++;
|
|
if (device1 >= 2)
|
|
{
|
|
device1 = 0;
|
|
}
|
|
if (device1 == 0)
|
|
{
|
|
if (input1gp) { return; }
|
|
device1++;
|
|
}
|
|
if (device1 == 1)
|
|
{
|
|
if (input1mouse) { return; }
|
|
}
|
|
}
|
|
}
|
|
|
|
void cycleinputdevice2()
|
|
{
|
|
for (;;)
|
|
{
|
|
device2++;
|
|
if (device2 >= 5)
|
|
{
|
|
device2 = 0;
|
|
}
|
|
if (device2 == 0)
|
|
{
|
|
if (input2gp) { return; }
|
|
device2++;
|
|
}
|
|
if (device2 == 1)
|
|
{
|
|
if (input2mouse) { return; }
|
|
device2++;
|
|
}
|
|
if (device2 == 2)
|
|
{
|
|
if (input2scope) { return; }
|
|
device2++;
|
|
}
|
|
if (device2 == 3)
|
|
{
|
|
if (input2just) { return; }
|
|
device2++;
|
|
}
|
|
if (device2 == 4)
|
|
{
|
|
if (input2just) { return; }
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned char NoiseData[32768];
|
|
const unsigned char samplenoise[128] = {
|
|
27,232,234,138,187,246,176, 81, 25,241, 1,127,154,190,195,103,
|
|
231,165,220,238,232,189, 57,201,123, 75, 63,143,145,159, 13,236,
|
|
191,142, 56,164,222, 80, 88, 13,148,118,162,212,157,146,176, 0,
|
|
241, 88,244,238, 51,235,149, 50, 77,212,186,241, 88, 32, 23,206,
|
|
1, 24, 48,244,248,210,253, 77, 19,100, 83,222,108, 68, 11, 58,
|
|
152,161,223,245, 4,105, 3, 82, 15,130,171,242,141, 2,172,218,
|
|
152, 97,223,157, 93, 75, 83,238,104,238,131, 70, 22,252,180, 82,
|
|
110,123,106,133,183,209, 48,230,157,205, 27, 21,107, 63, 85,164};
|
|
|
|
void setnoise()
|
|
{
|
|
unsigned short ctr1, ctr2, ptr1=0;
|
|
unsigned char ptr2=0, ptr3=0;
|
|
|
|
for(ctr1=256;ctr1>0;ctr1--)
|
|
{
|
|
for(ctr2=128;ctr2>0;ctr2--,ptr1++)
|
|
{
|
|
NoiseData[ptr1] = (samplenoise[ptr2] + samplenoise[ptr3]);
|
|
ptr2=(ptr2+1)&0x7f;
|
|
ptr3=(ptr3-1)&0x7f;
|
|
}
|
|
ptr3=(ptr3-1)&0x7f;
|
|
}
|
|
}
|
|
|
|
static void outofmemory()
|
|
{
|
|
puts("You don't have enough memory to run this program!");
|
|
asm_call(DosExit);
|
|
}
|
|
|
|
extern unsigned char wramdataa[65536], ram7fa[65536];
|
|
|
|
#ifndef __MSDOS__
|
|
unsigned char *BitConv32Ptr = 0;
|
|
unsigned char *RGBtoYUVPtr = 0;
|
|
#endif
|
|
unsigned char *spcBuffera = 0;
|
|
unsigned char *spritetablea = 0;
|
|
unsigned char *vbufaptr = 0;
|
|
unsigned char *vbufeptr = 0;
|
|
unsigned char *ngwinptrb = 0;
|
|
unsigned char *vbufdptr = 0;
|
|
unsigned char *romaptr = 0;
|
|
unsigned char *vcache2bs = 0; // 2-bit video secondary cache
|
|
unsigned char *vcache4bs = 0; // 4-bit video secondary cache
|
|
unsigned char *vcache8bs = 0; // 8-bit video secondary cache
|
|
|
|
unsigned char vrama[65536];
|
|
|
|
unsigned char mode7tab[65536];
|
|
|
|
unsigned short fulladdtab[65536];
|
|
unsigned short VolumeConvTable[32768];
|
|
unsigned int dspWptr[256];
|
|
unsigned int dspRptr[256];
|
|
|
|
#define deallocmemhelp(p) if (p) { free(p); }
|
|
|
|
void deallocmem()
|
|
{
|
|
#ifndef __MSDOS__
|
|
deallocmemhelp(BitConv32Ptr);
|
|
deallocmemhelp(RGBtoYUVPtr);
|
|
#endif
|
|
deallocmemhelp(spcBuffera);
|
|
deallocmemhelp(spritetablea);
|
|
deallocmemhelp(vbufaptr);
|
|
deallocmemhelp(vbufeptr);
|
|
deallocmemhelp(ngwinptrb);
|
|
deallocmemhelp(vbufdptr);
|
|
deallocmemhelp(romaptr);
|
|
deallocmemhelp(vcache2bs);
|
|
deallocmemhelp(vcache4bs);
|
|
deallocmemhelp(vcache8bs);
|
|
deallocmemhelp(vcache2b);
|
|
deallocmemhelp(vcache4b);
|
|
deallocmemhelp(vcache8b);
|
|
#ifdef OLD_DEBUGGER
|
|
deallocmemhelp(debugbuf);
|
|
#endif
|
|
deallocmemhelp(sram);
|
|
deallocmemhelp(SPC7110PackPtr);
|
|
deallocmemhelp(SPC7110IndexPtr);
|
|
}
|
|
|
|
#define AllocmemFail(ptr, size) if (!(ptr = malloc(size))) { outofmemory(); }
|
|
|
|
static void allocmem()
|
|
{
|
|
#ifndef __MSDOS__
|
|
AllocmemFail(BitConv32Ptr, 4096+65536*16);
|
|
AllocmemFail(RGBtoYUVPtr,65536*4+4096);
|
|
#endif
|
|
AllocmemFail(spcBuffera,65536*4+4096);
|
|
AllocmemFail(spritetablea,256*512+4096);
|
|
AllocmemFail(vbufaptr,512*296*4+4096+512*296);
|
|
AllocmemFail(vbufeptr,288*2*256+4096);
|
|
AllocmemFail(ngwinptrb,256*224+4096);
|
|
AllocmemFail(vbufdptr,1024*296);
|
|
AllocmemFail(vcache2bs,65536*4*4+4096);
|
|
AllocmemFail(vcache4bs,65536*4*2+4096);
|
|
AllocmemFail(vcache8bs,65536*4+4096);
|
|
#ifdef OLD_DEBUGGER
|
|
AllocmemFail(debugbuf,80000);
|
|
#endif
|
|
AllocmemFail(sram,65536*2);
|
|
AllocmemFail(vcache2b,262144+256);
|
|
AllocmemFail(vcache4b,131072+256);
|
|
AllocmemFail(vcache8b,65536+256);
|
|
|
|
newgfx16b = 1;
|
|
if ((romaptr = malloc(0x600000+32768*2+4096)))
|
|
{
|
|
maxromspace = 0x600000;
|
|
}
|
|
else
|
|
{
|
|
if ((romaptr = malloc(0x400000+32768*2+4096)))
|
|
{
|
|
maxromspace = 0x400000;
|
|
}
|
|
else
|
|
{
|
|
if ((romaptr = malloc(0x200000+32768*2+4096)))
|
|
{
|
|
maxromspace = 0x200000;
|
|
}
|
|
else
|
|
{
|
|
outofmemory();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set up memory values
|
|
vidbuffer = vbufaptr;
|
|
vidbufferofsa = vbufaptr;
|
|
ngwinptr = ngwinptrb;
|
|
vidbufferofsb = vbufeptr;
|
|
|
|
headdata = romaptr;
|
|
romdata = romaptr;
|
|
sfxramdata = romaptr+0x400000;
|
|
setaramdata = romaptr+0x400000;
|
|
|
|
// Puts this ASM after the end of the ROM:
|
|
// CLI
|
|
// here: BRA here
|
|
// But why?
|
|
romdata[maxromspace+0] = 0x58;
|
|
romdata[maxromspace+1] = 0x80;
|
|
romdata[maxromspace+2] = 0xFE;
|
|
|
|
wramdata = wramdataa;
|
|
ram7f = ram7fa;
|
|
vram = vrama;
|
|
|
|
regptr -= 0x8000;
|
|
regptw -= 0x8000;
|
|
}
|
|
|
|
const unsigned int versionNumber = 0x00000097; // 1.51
|
|
char *ZVERSION = "1.51";
|
|
unsigned char txtfailedalignd[] = "Data Alignment Failure : ";
|
|
unsigned char txtfailedalignc[] = "Code Alignment Failure : ";
|
|
|
|
void zstart()
|
|
{
|
|
unsigned int ptr;
|
|
|
|
asm_call(MMXCheck);
|
|
asm_call(StartUp);
|
|
|
|
// Print welcome message.
|
|
printf("ZSNES v%s, (c) 1997-2007, ZSNES Team\n", ZVERSION);
|
|
puts("Be sure to check http://www.zsnes.com/ for the latest version.\n");
|
|
puts("ZSNES is written by the ZSNES Team (See AUTHORS.TXT)");
|
|
puts("ZSNES comes with ABSOLUTELY NO WARRANTY. This is free software,");
|
|
puts("and you are welcome to redistribute it under certain conditions;");
|
|
puts("please read 'LICENSE.TXT' thoroughly before doing so.\n");
|
|
puts("Use ZSNES -? for command line definitions.\n");
|
|
|
|
#ifndef __RELEASE__
|
|
puts("This is a work in progress build. It contains code which");
|
|
puts("May or may not be complete\n");
|
|
#ifdef __UNIXSDL__
|
|
puts("If this is supposed to be an official release, you forgot to");
|
|
puts("run configure with --enable-release, go rebuild.\n");
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef __UNIXSDL__
|
|
MultiMouseInit();
|
|
#endif
|
|
|
|
asm_call(SystemInit);
|
|
|
|
if (guioff && !*ZCartName)
|
|
{
|
|
puts("Will not start without a GUI unless a filename is supplied.");
|
|
exit(0);
|
|
}
|
|
else
|
|
{
|
|
extern bool romloadskip;
|
|
romloadskip = true;
|
|
}
|
|
|
|
#ifdef OPENSPC
|
|
OSPC_Init();
|
|
#else
|
|
setnoise();
|
|
asm_call(InitSPC);
|
|
#endif
|
|
|
|
allocmem();
|
|
|
|
if (!(spcon = !SPCDisable)) { soundon = 0; }
|
|
DSPDisable = !soundon;
|
|
|
|
if (!frameskip)
|
|
{
|
|
FPSOn = FPSAtStart;
|
|
}
|
|
|
|
gammalevel16b = gammalevel >> 1;
|
|
|
|
ptr = (unsigned int)&init;
|
|
if ((ptr & 3))
|
|
{
|
|
printf("%s%d", txtfailedalignc, (ptr & 0x1F));
|
|
asm_call(WaitForKey);
|
|
}
|
|
|
|
ptr = (unsigned int)&xa;
|
|
if ((ptr & 3))
|
|
{
|
|
printf("%s%d", txtfailedalignd, (ptr & 0x1F));
|
|
asm_call(WaitForKey);
|
|
}
|
|
|
|
asm_call(init);
|
|
}
|
|
|
|
static char *seconds_to_asc(unsigned int seconds)
|
|
{
|
|
static char buffer[50];
|
|
char *p = buffer;
|
|
unsigned int hours, minutes;
|
|
|
|
minutes = seconds/60;
|
|
seconds -= minutes*60;
|
|
hours = minutes/60;
|
|
minutes -= hours*60;
|
|
*buffer = 0;
|
|
|
|
if (hours)
|
|
{
|
|
sprintf(p, "%u hours ", hours);
|
|
p += strlen(p);
|
|
}
|
|
if (minutes)
|
|
{
|
|
sprintf(p, "%u min ", minutes);
|
|
p += strlen(p);
|
|
}
|
|
if (seconds)
|
|
{
|
|
sprintf(p, "%u sec", seconds);
|
|
p += strlen(p);
|
|
}
|
|
if (!*buffer)
|
|
{
|
|
strcpy(buffer, "0 sec");
|
|
}
|
|
return(buffer);
|
|
}
|
|
|
|
void DisplayBatteryStatus()
|
|
{
|
|
#ifndef __MSDOS__
|
|
int CheckBattery();
|
|
int CheckBatteryTime();
|
|
int CheckBatteryPercent();
|
|
|
|
*CSStatus2 = 0;
|
|
*CSStatus3 = 0;
|
|
|
|
switch (CheckBattery())
|
|
{
|
|
case -1: //No battery
|
|
strcpy(CSStatus, "No battery present");
|
|
break;
|
|
|
|
case 0: //Plugged in
|
|
{
|
|
int percent = CheckBatteryPercent();
|
|
|
|
strcpy(CSStatus, "PC is plugged in");
|
|
if (percent > 0)
|
|
{
|
|
sprintf(CSStatus2, "%d%% charged", percent);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 1: //Not plugged in
|
|
{
|
|
int percent = CheckBatteryPercent();
|
|
int battery_time = CheckBatteryTime();
|
|
|
|
strcpy(CSStatus, "PC is running off of battery");
|
|
if (battery_time > 0)
|
|
{
|
|
sprintf(CSStatus2, "Time remaining: %s", seconds_to_asc(battery_time));
|
|
}
|
|
if (percent > 0)
|
|
{
|
|
sprintf(CSStatus3, "%d%% remaining", percent);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
Msgptr = CSStatus;
|
|
MessageOn = 100;
|
|
#endif
|
|
}
|
|
|
|
// Make use of multiple mice.
|
|
|
|
#ifndef __MSDOS__
|
|
|
|
int MouseCount = 0;
|
|
|
|
unsigned short MouseMoveX[2];
|
|
unsigned short MouseMoveY[2];
|
|
unsigned short MouseButtons[2];
|
|
|
|
static bool MouseWaiting[2];
|
|
|
|
void MultiMouseShutdown(void)
|
|
{
|
|
MouseCount = 0;
|
|
ManyMouse_Quit();
|
|
}
|
|
|
|
void MultiMouseInit()
|
|
{
|
|
#ifdef linux
|
|
DIR *input_dir;
|
|
|
|
puts("Starting Mouse detection.");
|
|
input_dir = opendir("/dev/input");
|
|
if (input_dir)
|
|
{
|
|
struct dirent *ent;
|
|
while ((ent = readdir(input_dir)))
|
|
{
|
|
if (!strncasecmp(ent->d_name, "event", strlen("event")))
|
|
{
|
|
if (access_dir("/dev/input/", ent->d_name, R_OK))
|
|
{
|
|
printf("Unable to poll /dev/input/%s. Make sure you have read permissions to it.\n", ent->d_name);
|
|
}
|
|
}
|
|
}
|
|
closedir(input_dir);
|
|
}
|
|
else
|
|
{
|
|
puts("/dev/input does not exist or is inaccessable");
|
|
}
|
|
#endif
|
|
MouseCount = ManyMouse_Init();
|
|
printf("ManyMouse: %d mice detected.\n", MouseCount);
|
|
|
|
if (MouseCount > 1)
|
|
{
|
|
MouseMoveX[0] = MouseMoveX[1] = 0;
|
|
MouseMoveY[0] = MouseMoveY[1] = 0;
|
|
MouseButtons[0] = MouseButtons[1] = 0;
|
|
MouseWaiting[0] = MouseWaiting[1] = false;
|
|
atexit(MultiMouseShutdown);
|
|
|
|
printf("Using ManyMouse for:\nMouse 0: %s\nMouse 1: %s\n", ManyMouse_DeviceName(0), ManyMouse_DeviceName(1));
|
|
}
|
|
else
|
|
{
|
|
strcpy(CSStatus, "Dual mice not detected");
|
|
strcpy(CSStatus2, "");
|
|
strcpy(CSStatus3, "");
|
|
Msgptr = CSStatus;
|
|
MessageOn = 100;
|
|
|
|
MultiMouseShutdown();
|
|
}
|
|
}
|
|
|
|
#define BIT(x) (1 << (x))
|
|
#define MOUSE_BUTTON_HANDLE(mouse, bit, value) \
|
|
if (value) { mouse |= BIT(bit); } \
|
|
else { mouse &= ~BIT(bit); }
|
|
|
|
unsigned char mouse;
|
|
void MultiMouseProcess()
|
|
{
|
|
ManyMouseEvent event;
|
|
if (MouseWaiting[mouse])
|
|
{
|
|
MouseWaiting[mouse] = false;
|
|
}
|
|
else
|
|
{
|
|
MouseMoveX[mouse] = 0;
|
|
MouseMoveY[mouse] = 0;
|
|
|
|
while (ManyMouse_PollEvent(&event))
|
|
{
|
|
if (event.device != 0 && event.device != 1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//printf("Device: %d; Type: %d; Item: %d; Value: %d\n", event.device, event.type, event.item, event.value);
|
|
|
|
if ((event.device == (mouse^1)) && !MouseWaiting[event.device])
|
|
{
|
|
MouseMoveX[event.device] = 0;
|
|
MouseMoveY[event.device] = 0;
|
|
MouseWaiting[event.device] = true;
|
|
}
|
|
|
|
if (event.type == MANYMOUSE_EVENT_RELMOTION)
|
|
{
|
|
if (event.item == 0) { MouseMoveX[event.device] = event.value; }
|
|
else { MouseMoveY[event.device] = event.value; }
|
|
}
|
|
else if (event.type == MANYMOUSE_EVENT_BUTTON)
|
|
{
|
|
if (event.item == 0) { MOUSE_BUTTON_HANDLE(MouseButtons[event.device], 0, event.value); }
|
|
else if (event.item == 1) { MOUSE_BUTTON_HANDLE(MouseButtons[event.device], 1, event.value); }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|