@@ -2,7 +2,7 @@ INCFLAGS := -I$(CORE_DIR)/drivers/libretro -I$(CORE_DIR) -I$(CORE_DIR)/input -I$
|
|||||||
|
|
||||||
FCEU_SRC_DIRS := $(CORE_DIR)/boards $(CORE_DIR)/input $(CORE_DIR)/mappers
|
FCEU_SRC_DIRS := $(CORE_DIR)/boards $(CORE_DIR)/input $(CORE_DIR)/mappers
|
||||||
SOURCES_C := $(foreach dir,$(FCEU_SRC_DIRS),$(wildcard $(dir)/*.c))
|
SOURCES_C := $(foreach dir,$(FCEU_SRC_DIRS),$(wildcard $(dir)/*.c))
|
||||||
SOURCES_C += $(CORE_DIR)/ines.c $(CORE_DIR)/unif.c $(CORE_DIR)/x6502.c
|
SOURCES_C += $(CORE_DIR)/drivers/libretro/fceu/ines.c $(CORE_DIR)/drivers/libretro/fceu/unif.c $(CORE_DIR)/x6502.c
|
||||||
|
|
||||||
ifeq ($(WANT_GRIFFIN),1)
|
ifeq ($(WANT_GRIFFIN),1)
|
||||||
SOURCES_C += \
|
SOURCES_C += \
|
||||||
@@ -16,21 +16,21 @@ SOURCES_C += \
|
|||||||
$(CORE_DIR)/cheat.c \
|
$(CORE_DIR)/cheat.c \
|
||||||
$(CORE_DIR)/crc32.c \
|
$(CORE_DIR)/crc32.c \
|
||||||
$(CORE_DIR)/debug.c \
|
$(CORE_DIR)/debug.c \
|
||||||
$(CORE_DIR)/fceu-endian.c \
|
$(CORE_DIR)/drivers/libretro/fceu/fceu-endian.c \
|
||||||
$(CORE_DIR)/fceu-memory.c \
|
$(CORE_DIR)/drivers/libretro/fceu/fceu-memory.c \
|
||||||
$(CORE_DIR)/misc.c \
|
$(CORE_DIR)/drivers/libretro/fceu/misc.c \
|
||||||
$(CORE_DIR)/fceu.c \
|
$(CORE_DIR)/drivers/libretro/fceu/fceu.c \
|
||||||
$(CORE_DIR)/fds.c \
|
$(CORE_DIR)/drivers/libretro/fceu/fds.c \
|
||||||
$(CORE_DIR)/file.c \
|
$(CORE_DIR)/drivers/libretro/fceu/file.c \
|
||||||
$(CORE_DIR)/filter.c \
|
$(CORE_DIR)/filter.c \
|
||||||
$(CORE_DIR)/general.c \
|
$(CORE_DIR)/drivers/libretro/fceu/general.c \
|
||||||
$(CORE_DIR)/input.c \
|
$(CORE_DIR)/drivers/libretro/fceu/input.c \
|
||||||
$(CORE_DIR)/nsf.c \
|
$(CORE_DIR)/drivers/libretro/fceu/nsf.c \
|
||||||
$(CORE_DIR)/md5.c \
|
$(CORE_DIR)/md5.c \
|
||||||
$(CORE_DIR)/palette.c \
|
$(CORE_DIR)/palette.c \
|
||||||
$(CORE_DIR)/ppu.c \
|
$(CORE_DIR)/ppu.c \
|
||||||
$(CORE_DIR)/sound.c \
|
$(CORE_DIR)/sound.c \
|
||||||
$(CORE_DIR)/vsuni.c \
|
$(CORE_DIR)/vsuni.c \
|
||||||
$(CORE_DIR)/state.c \
|
$(CORE_DIR)/drivers/libretro/fceu/state.c \
|
||||||
$(CORE_DIR)/video.c
|
$(CORE_DIR)/drivers/libretro/fceu/video.c
|
||||||
endif
|
endif
|
||||||
|
|||||||
123
src/drivers/libretro/fceu/fceu-endian.c
Normal file
123
src/drivers/libretro/fceu/fceu-endian.c
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/* FCE Ultra - NES/Famicom Emulator
|
||||||
|
*
|
||||||
|
* Copyright notice for this file:
|
||||||
|
* Copyright (C) 2002 Xodnizel
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Contains file I/O functions that write/read data */
|
||||||
|
/* LSB first. */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "fceu-memory.h"
|
||||||
|
#include "fceu-types.h"
|
||||||
|
#include "fceu-endian.h"
|
||||||
|
|
||||||
|
void FlipByteOrder(uint8 *src, uint32 count)
|
||||||
|
{
|
||||||
|
uint8 *start = src;
|
||||||
|
uint8 *end = src + count - 1;
|
||||||
|
|
||||||
|
while(start < end)
|
||||||
|
{
|
||||||
|
uint8 tmp;
|
||||||
|
|
||||||
|
tmp = *end;
|
||||||
|
*end = *start;
|
||||||
|
*start = tmp;
|
||||||
|
end--;
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int write16le(uint16 b, FILE *fp)
|
||||||
|
{
|
||||||
|
uint8 s[2];
|
||||||
|
s[0] = b;
|
||||||
|
s[1] = b >> 8;
|
||||||
|
return((fwrite(s, 1, 2, fp) < 2) ? 0 : 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int write32le(uint32 b, FILE *fp)
|
||||||
|
{
|
||||||
|
uint8 s[4];
|
||||||
|
s[0] = b;
|
||||||
|
s[1] = b >> 8;
|
||||||
|
s[2] = b >> 16;
|
||||||
|
s[3] = b >> 24;
|
||||||
|
return((fwrite(s, 1, 4, fp) < 4) ? 0 : 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
int read32le(uint32 *Bufo, FILE *fp)
|
||||||
|
{
|
||||||
|
uint32 buf;
|
||||||
|
if (fread(&buf, 1, 4, fp) < 4)
|
||||||
|
return 0;
|
||||||
|
#ifdef MSB_FIRST
|
||||||
|
*(uint32*)Bufo = ((buf & 0xFF) << 24) | ((buf & 0xFF00) << 8) | ((buf & 0xFF0000) >> 8) | ((buf & 0xFF000000) >> 24);
|
||||||
|
#else
|
||||||
|
*(uint32*)Bufo = buf;
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int write32le_mem(uint32 b, memstream_t *mem)
|
||||||
|
{
|
||||||
|
uint8 s[4];
|
||||||
|
s[0]=b;
|
||||||
|
s[1]=b>>8;
|
||||||
|
s[2]=b>>16;
|
||||||
|
s[3]=b>>24;
|
||||||
|
return((memstream_write(mem, s, 4)<4)?0:4);
|
||||||
|
}
|
||||||
|
|
||||||
|
int read32le_mem(uint32 *Bufo, memstream_t *mem)
|
||||||
|
{
|
||||||
|
uint32 buf;
|
||||||
|
if(memstream_read(mem, &buf, 4)<4)
|
||||||
|
return 0;
|
||||||
|
#ifdef MSB_FIRST
|
||||||
|
*(uint32*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24);
|
||||||
|
#else
|
||||||
|
*(uint32*)Bufo=buf;
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read16le(char *d, FILE *fp)
|
||||||
|
{
|
||||||
|
#ifdef MSB_FIRST
|
||||||
|
int ret;
|
||||||
|
ret = fread(d + 1, 1, 1, fp);
|
||||||
|
ret += fread(d, 1, 1, fp);
|
||||||
|
return ret < 2 ? 0 : 2;
|
||||||
|
#else
|
||||||
|
return((fread(d, 1, 2, fp) < 2) ? 0 : 2);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_en32lsb(uint8 *buf, uint32 morp)
|
||||||
|
{
|
||||||
|
buf[0] = morp;
|
||||||
|
buf[1] = morp >> 8;
|
||||||
|
buf[2] = morp >> 16;
|
||||||
|
buf[3] = morp >> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 FCEU_de32lsb(uint8 *morp)
|
||||||
|
{
|
||||||
|
return(morp[0] | (morp[1] << 8) | (morp[2] << 16) | (morp[3] << 24));
|
||||||
|
}
|
||||||
18
src/drivers/libretro/fceu/fceu-endian.h
Normal file
18
src/drivers/libretro/fceu/fceu-endian.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef _FCEU_ENDIAN_H
|
||||||
|
#define _FCEU_ENDIAN_H
|
||||||
|
|
||||||
|
#include "fceu-memory.h"
|
||||||
|
#include "../memstream.h"
|
||||||
|
|
||||||
|
int write32le_mem(uint32 b, memstream_t *mem);
|
||||||
|
int read32le_mem(uint32 *Bufo, memstream_t *mem);
|
||||||
|
|
||||||
|
int write16le(uint16 b, FILE *fp);
|
||||||
|
int write32le(uint32 b, FILE *fp);
|
||||||
|
int read32le(uint32 *Bufo, FILE *fp);
|
||||||
|
void FlipByteOrder(uint8 *src, uint32 count);
|
||||||
|
|
||||||
|
void FCEU_en32lsb(uint8 *, uint32);
|
||||||
|
uint32 FCEU_de32lsb(uint8 *);
|
||||||
|
|
||||||
|
#endif
|
||||||
63
src/drivers/libretro/fceu/fceu-memory.c
Normal file
63
src/drivers/libretro/fceu/fceu-memory.c
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/* FCE Ultra - NES/Famicom Emulator
|
||||||
|
*
|
||||||
|
* Copyright notice for this file:
|
||||||
|
* Copyright (C) 2002 Xodnizel
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "fceu-types.h"
|
||||||
|
#include "fceu.h"
|
||||||
|
#include "fceu-memory.h"
|
||||||
|
#include "general.h"
|
||||||
|
|
||||||
|
void *FCEU_gmalloc(uint32 size)
|
||||||
|
{
|
||||||
|
void *ret;
|
||||||
|
ret = malloc(size);
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
FCEU_PrintError("Error allocating memory! Doing a hard exit.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *FCEU_malloc(uint32 size)
|
||||||
|
{
|
||||||
|
int retval = 0;
|
||||||
|
void *ret;
|
||||||
|
ret = (void*)malloc(size);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
FCEU_PrintError("Error allocating memory!");
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_free(void *ptr)
|
||||||
|
{
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_gfree(void *ptr)
|
||||||
|
{
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
50
src/drivers/libretro/fceu/fceu-memory.h
Normal file
50
src/drivers/libretro/fceu/fceu-memory.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/* FCE Ultra - NES/Famicom Emulator
|
||||||
|
*
|
||||||
|
* Copyright notice for this file:
|
||||||
|
* Copyright (C) 2002 Xodnizel
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Various macros for faster memory stuff
|
||||||
|
(at least that's the idea)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FCEU_MEMORY_H_
|
||||||
|
#define _FCEU_MEMORY_H_
|
||||||
|
|
||||||
|
#include "fceu-types.h"
|
||||||
|
#include "../memstream.h"
|
||||||
|
|
||||||
|
#define FCEU_dwmemset(d, c, n) { int _x; for (_x = n - 4; _x >= 0; _x -= 4) *(uint32*)& (d)[_x] = c; }
|
||||||
|
|
||||||
|
#define HAVE_MEMSTREAM
|
||||||
|
#define MEM_TYPE memstream_t
|
||||||
|
|
||||||
|
#define fwrite(ptr, size, nmemb, stream) memstream_write((stream), (ptr), (nmemb))
|
||||||
|
#define fclose(fp) memstream_close((fp))
|
||||||
|
#define fgetc(stream) memstream_getc((stream))
|
||||||
|
#define fputc(c, stream) memstream_putc((stream), (c))
|
||||||
|
#define ftell(a) memstream_pos((a))
|
||||||
|
#define fread(ptr, size, nmemb, stream) memstream_read((stream), (ptr), (nmemb))
|
||||||
|
#define fseek(stream, offset, whence) memstream_seek((stream), (offset), (whence))
|
||||||
|
|
||||||
|
void *FCEU_malloc(uint32 size);
|
||||||
|
void *FCEU_gmalloc(uint32 size);
|
||||||
|
void FCEU_gfree(void *ptr);
|
||||||
|
void FCEU_free(void *ptr);
|
||||||
|
void FASTAPASS(3) FCEU_memmove(void *d, void *s, uint32 l);
|
||||||
|
|
||||||
|
#endif
|
||||||
550
src/drivers/libretro/fceu/fceu.c
Normal file
550
src/drivers/libretro/fceu/fceu.c
Normal file
@@ -0,0 +1,550 @@
|
|||||||
|
/* FCE Ultra - NES/Famicom Emulator
|
||||||
|
*
|
||||||
|
* Copyright notice for this file:
|
||||||
|
* Copyright (C) 2003 Xodnizel
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include "fceu-types.h"
|
||||||
|
#include "x6502.h"
|
||||||
|
#include "fceu.h"
|
||||||
|
#include "ppu.h"
|
||||||
|
#include "sound.h"
|
||||||
|
#include "netplay.h"
|
||||||
|
#include "general.h"
|
||||||
|
#include "fceu-endian.h"
|
||||||
|
#include "fceu-memory.h"
|
||||||
|
|
||||||
|
#include "cart.h"
|
||||||
|
#include "nsf.h"
|
||||||
|
#include "fds.h"
|
||||||
|
#include "ines.h"
|
||||||
|
#include "unif.h"
|
||||||
|
#include "cheat.h"
|
||||||
|
#include "palette.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "video.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "file.h"
|
||||||
|
#include "crc32.h"
|
||||||
|
#include "vsuni.h"
|
||||||
|
|
||||||
|
uint64 timestampbase;
|
||||||
|
|
||||||
|
|
||||||
|
FCEUGI *GameInfo = NULL;
|
||||||
|
void (*GameInterface)(int h);
|
||||||
|
|
||||||
|
void (*GameStateRestore)(int version);
|
||||||
|
|
||||||
|
readfunc ARead[0x10000];
|
||||||
|
writefunc BWrite[0x10000];
|
||||||
|
static readfunc *AReadG;
|
||||||
|
static writefunc *BWriteG;
|
||||||
|
static int RWWrap = 0;
|
||||||
|
|
||||||
|
static DECLFW(BNull)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFR(ANull)
|
||||||
|
{
|
||||||
|
return(X.DB);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AllocGenieRW(void)
|
||||||
|
{
|
||||||
|
if (!(AReadG = (readfunc*)FCEU_malloc(0x8000 * sizeof(readfunc))))
|
||||||
|
return 0;
|
||||||
|
if (!(BWriteG = (writefunc*)FCEU_malloc(0x8000 * sizeof(writefunc))))
|
||||||
|
return 0;
|
||||||
|
RWWrap = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlushGenieRW(void)
|
||||||
|
{
|
||||||
|
int32 x;
|
||||||
|
|
||||||
|
if (RWWrap)
|
||||||
|
{
|
||||||
|
for (x = 0; x < 0x8000; x++)
|
||||||
|
{
|
||||||
|
ARead[x + 0x8000] = AReadG[x];
|
||||||
|
BWrite[x + 0x8000] = BWriteG[x];
|
||||||
|
}
|
||||||
|
free(AReadG);
|
||||||
|
free(BWriteG);
|
||||||
|
AReadG = 0;
|
||||||
|
BWriteG = 0;
|
||||||
|
}
|
||||||
|
RWWrap = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
readfunc FASTAPASS(1) GetReadHandler(int32 a)
|
||||||
|
{
|
||||||
|
if (a >= 0x8000 && RWWrap)
|
||||||
|
return AReadG[a - 0x8000];
|
||||||
|
else
|
||||||
|
return ARead[a];
|
||||||
|
}
|
||||||
|
|
||||||
|
void FASTAPASS(3) SetReadHandler(int32 start, int32 end, readfunc func)
|
||||||
|
{
|
||||||
|
int32 x;
|
||||||
|
|
||||||
|
if (!func)
|
||||||
|
func = ANull;
|
||||||
|
|
||||||
|
if (RWWrap)
|
||||||
|
for (x = end; x >= start; x--)
|
||||||
|
{
|
||||||
|
if (x >= 0x8000)
|
||||||
|
AReadG[x - 0x8000] = func;
|
||||||
|
else
|
||||||
|
ARead[x] = func;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (x = end; x >= start; x--)
|
||||||
|
ARead[x] = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
writefunc FASTAPASS(1) GetWriteHandler(int32 a)
|
||||||
|
{
|
||||||
|
if (RWWrap && a >= 0x8000)
|
||||||
|
return BWriteG[a - 0x8000];
|
||||||
|
else
|
||||||
|
return BWrite[a];
|
||||||
|
}
|
||||||
|
|
||||||
|
void FASTAPASS(3) SetWriteHandler(int32 start, int32 end, writefunc func)
|
||||||
|
{
|
||||||
|
int32 x;
|
||||||
|
|
||||||
|
if (!func)
|
||||||
|
func = BNull;
|
||||||
|
|
||||||
|
if (RWWrap)
|
||||||
|
for (x = end; x >= start; x--)
|
||||||
|
{
|
||||||
|
if (x >= 0x8000)
|
||||||
|
BWriteG[x - 0x8000] = func;
|
||||||
|
else
|
||||||
|
BWrite[x] = func;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (x = end; x >= start; x--)
|
||||||
|
BWrite[x] = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef COPYFAMI
|
||||||
|
uint8 RAM[0x4000];
|
||||||
|
#else
|
||||||
|
uint8 RAM[0x800];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8 PAL = 0;
|
||||||
|
|
||||||
|
static DECLFW(BRAML)
|
||||||
|
{
|
||||||
|
RAM[A] = V;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFR(ARAML)
|
||||||
|
{
|
||||||
|
return RAM[A];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef COPYFAMI
|
||||||
|
static DECLFW(BRAMH)
|
||||||
|
{
|
||||||
|
RAM[A & 0x7FF] = V;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFR(ARAMH)
|
||||||
|
{
|
||||||
|
return RAM[A & 0x7FF];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void FCEUI_CloseGame(void)
|
||||||
|
{
|
||||||
|
if (!GameInfo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (GameInfo->name)
|
||||||
|
free(GameInfo->name);
|
||||||
|
GameInfo->name = 0;
|
||||||
|
if (GameInfo->type != GIT_NSF)
|
||||||
|
FCEU_FlushGameCheats(0, 0);
|
||||||
|
GameInterface(GI_CLOSE);
|
||||||
|
ResetExState(0, 0);
|
||||||
|
FCEU_CloseGenie();
|
||||||
|
free(GameInfo);
|
||||||
|
GameInfo = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetGameLoaded(void)
|
||||||
|
{
|
||||||
|
if (GameInfo)
|
||||||
|
FCEUI_CloseGame();
|
||||||
|
|
||||||
|
GameStateRestore = NULL;
|
||||||
|
PPU_hook = NULL;
|
||||||
|
GameHBIRQHook = NULL;
|
||||||
|
|
||||||
|
if (GameExpSound.Kill)
|
||||||
|
GameExpSound.Kill();
|
||||||
|
memset(&GameExpSound, 0, sizeof(GameExpSound));
|
||||||
|
|
||||||
|
MapIRQHook = NULL;
|
||||||
|
MMC5Hack = 0;
|
||||||
|
PEC586Hack = 0;
|
||||||
|
PAL &= 1;
|
||||||
|
pale = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UNIFLoad(const char *name, FCEUFILE *fp);
|
||||||
|
int iNESLoad(const char *name, FCEUFILE *fp);
|
||||||
|
int FDSLoad(const char *name, FCEUFILE *fp);
|
||||||
|
int NSFLoad(FCEUFILE *fp);
|
||||||
|
|
||||||
|
FCEUGI *FCEUI_LoadGame(const char *name, uint8_t *databuf, size_t databufsize)
|
||||||
|
{
|
||||||
|
FCEUFILE *fp;
|
||||||
|
|
||||||
|
ResetGameLoaded();
|
||||||
|
|
||||||
|
GameInfo = malloc(sizeof(FCEUGI));
|
||||||
|
memset(GameInfo, 0, sizeof(FCEUGI));
|
||||||
|
|
||||||
|
GameInfo->soundchan = 0;
|
||||||
|
GameInfo->soundrate = 0;
|
||||||
|
GameInfo->name = 0;
|
||||||
|
GameInfo->type = GIT_CART;
|
||||||
|
GameInfo->vidsys = GIV_USER;
|
||||||
|
GameInfo->input[0] = GameInfo->input[1] = -1;
|
||||||
|
GameInfo->inputfc = -1;
|
||||||
|
GameInfo->cspecial = 0;
|
||||||
|
|
||||||
|
FCEU_printf("Loading %s...\n\n", name);
|
||||||
|
|
||||||
|
GetFileBase(name);
|
||||||
|
|
||||||
|
fp = FCEU_fopen(name, NULL, "rb", 0, databuf, databufsize);
|
||||||
|
|
||||||
|
if (!fp) {
|
||||||
|
FCEU_PrintError("Error opening \"%s\"!", name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iNESLoad(name, fp))
|
||||||
|
goto endlseq;
|
||||||
|
if (NSFLoad(fp))
|
||||||
|
goto endlseq;
|
||||||
|
if (UNIFLoad(name, fp))
|
||||||
|
goto endlseq;
|
||||||
|
if (FDSLoad(name, fp))
|
||||||
|
goto endlseq;
|
||||||
|
|
||||||
|
FCEU_PrintError("An error occurred while loading the file.");
|
||||||
|
FCEU_fclose(fp);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
endlseq:
|
||||||
|
FCEU_fclose(fp);
|
||||||
|
|
||||||
|
FCEU_ResetVidSys();
|
||||||
|
if (GameInfo->type != GIT_NSF)
|
||||||
|
if (FSettings.GameGenie)
|
||||||
|
FCEU_OpenGenie();
|
||||||
|
|
||||||
|
PowerNES();
|
||||||
|
FCEUSS_CheckStates();
|
||||||
|
|
||||||
|
if (GameInfo->type != GIT_NSF) {
|
||||||
|
FCEU_LoadGamePalette();
|
||||||
|
FCEU_LoadGameCheats(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
FCEU_ResetPalette();
|
||||||
|
FCEU_ResetMessages(); // Save state, status messages, etc.
|
||||||
|
|
||||||
|
return(GameInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CopyFamiLoad(void);
|
||||||
|
|
||||||
|
FCEUGI *FCEUI_CopyFamiStart(void)
|
||||||
|
{
|
||||||
|
ResetGameLoaded();
|
||||||
|
|
||||||
|
GameInfo = (FCEUGI*)malloc(sizeof(FCEUGI));
|
||||||
|
memset(GameInfo, 0, sizeof(FCEUGI));
|
||||||
|
|
||||||
|
GameInfo->soundchan = 0;
|
||||||
|
GameInfo->soundrate = 0;
|
||||||
|
GameInfo->name = "copyfami";
|
||||||
|
GameInfo->type = GIT_CART;
|
||||||
|
GameInfo->vidsys = GIV_USER;
|
||||||
|
GameInfo->input[0] = GameInfo->input[1] = -1;
|
||||||
|
GameInfo->inputfc = -1;
|
||||||
|
GameInfo->cspecial = 0;
|
||||||
|
|
||||||
|
FCEU_printf("Starting CopyFamicom...\n\n");
|
||||||
|
|
||||||
|
if (!CopyFamiLoad()) {
|
||||||
|
FCEU_PrintError("An error occurred while starting CopyFamicom.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FCEU_ResetVidSys();
|
||||||
|
if (GameInfo->type != GIT_NSF)
|
||||||
|
if (FSettings.GameGenie)
|
||||||
|
FCEU_OpenGenie();
|
||||||
|
|
||||||
|
PowerNES();
|
||||||
|
FCEUSS_CheckStates();
|
||||||
|
|
||||||
|
if (GameInfo->type != GIT_NSF) {
|
||||||
|
FCEU_LoadGamePalette();
|
||||||
|
FCEU_LoadGameCheats(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
FCEU_ResetPalette();
|
||||||
|
FCEU_ResetMessages(); // Save state, status messages, etc.
|
||||||
|
|
||||||
|
return(GameInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FCEUI_Initialize(void) {
|
||||||
|
if (!FCEU_InitVirtualVideo())
|
||||||
|
return 0;
|
||||||
|
memset(&FSettings, 0, sizeof(FSettings));
|
||||||
|
FSettings.UsrFirstSLine[0] = 8;
|
||||||
|
FSettings.UsrFirstSLine[1] = 0;
|
||||||
|
FSettings.UsrLastSLine[0] = 231;
|
||||||
|
FSettings.UsrLastSLine[1] = 239;
|
||||||
|
FSettings.SoundVolume = 100;
|
||||||
|
FCEUPPU_Init();
|
||||||
|
X6502_Init();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_Kill(void) {
|
||||||
|
FCEU_KillVirtualVideo();
|
||||||
|
FCEU_KillGenie();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int skip) {
|
||||||
|
int r, ssize;
|
||||||
|
|
||||||
|
FCEU_UpdateInput();
|
||||||
|
if (geniestage != 1) FCEU_ApplyPeriodicCheats();
|
||||||
|
r = FCEUPPU_Loop(skip);
|
||||||
|
|
||||||
|
ssize = FlushEmulateSound();
|
||||||
|
|
||||||
|
timestampbase += timestamp;
|
||||||
|
|
||||||
|
timestamp = 0;
|
||||||
|
|
||||||
|
*pXBuf = skip ? 0 : XBuf;
|
||||||
|
*SoundBuf = WaveFinal;
|
||||||
|
*SoundBufSize = ssize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ResetNES(void)
|
||||||
|
{
|
||||||
|
if (!GameInfo)
|
||||||
|
return;
|
||||||
|
GameInterface(GI_RESETM2);
|
||||||
|
FCEUSND_Reset();
|
||||||
|
FCEUPPU_Reset();
|
||||||
|
X6502_Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_MemoryRand(uint8 *ptr, uint32 size)
|
||||||
|
{
|
||||||
|
int x = 0;
|
||||||
|
while (size) {
|
||||||
|
// *ptr = (x & 4) ? 0xFF : 0x00; // Huang Di DEBUG MODE enabled by default
|
||||||
|
// Cybernoid NO MUSIC by default
|
||||||
|
// *ptr = (x & 4) ? 0x7F : 0x00; // Huang Di DEBUG MODE enabled by default
|
||||||
|
// Minna no Taabou no Nakayoshi Daisakusen DOESN'T BOOT
|
||||||
|
// Cybernoid NO MUSIC by default
|
||||||
|
// *ptr = (x & 1) ? 0x55 : 0xAA; // F-15 Sity War HISCORE is screwed...
|
||||||
|
// 1942 SCORE/HISCORE is screwed...
|
||||||
|
*ptr = 0xFF;
|
||||||
|
x++;
|
||||||
|
size--;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hand(X6502 *X, int type, uint32 A)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PowerNES(void)
|
||||||
|
{
|
||||||
|
if (!GameInfo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
FCEU_CheatResetRAM();
|
||||||
|
FCEU_CheatAddRAM(2, 0, RAM);
|
||||||
|
|
||||||
|
FCEU_GeniePower();
|
||||||
|
|
||||||
|
#ifndef COPYFAMI
|
||||||
|
FCEU_MemoryRand(RAM, 0x800);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SetReadHandler(0x0000, 0xFFFF, ANull);
|
||||||
|
SetWriteHandler(0x0000, 0xFFFF, BNull);
|
||||||
|
|
||||||
|
#ifdef COPYFAMI
|
||||||
|
SetReadHandler(0, 0x3FFF, ARAML);
|
||||||
|
SetWriteHandler(0, 0x3FFF, BRAML);
|
||||||
|
#else
|
||||||
|
SetReadHandler(0, 0x7FF, ARAML);
|
||||||
|
SetWriteHandler(0, 0x7FF, BRAML);
|
||||||
|
|
||||||
|
SetReadHandler(0x800, 0x1FFF, ARAMH); /* Part of a little */
|
||||||
|
SetWriteHandler(0x800, 0x1FFF, BRAMH); /* hack for a small speed boost. */
|
||||||
|
#endif
|
||||||
|
InitializeInput();
|
||||||
|
FCEUSND_Power();
|
||||||
|
FCEUPPU_Power();
|
||||||
|
|
||||||
|
/* Have the external game hardware "powered" after the internal NES stuff.
|
||||||
|
Needed for the NSF code and VS System code.
|
||||||
|
*/
|
||||||
|
GameInterface(GI_POWER);
|
||||||
|
if (GameInfo->type == GIT_VSUNI)
|
||||||
|
FCEU_VSUniPower();
|
||||||
|
|
||||||
|
timestampbase = 0;
|
||||||
|
X6502_Power();
|
||||||
|
FCEU_PowerCheats();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_ResetVidSys(void)
|
||||||
|
{
|
||||||
|
int w;
|
||||||
|
|
||||||
|
if (GameInfo->vidsys == GIV_NTSC)
|
||||||
|
w = 0;
|
||||||
|
else if (GameInfo->vidsys == GIV_PAL)
|
||||||
|
w = 1;
|
||||||
|
else
|
||||||
|
w = FSettings.PAL;
|
||||||
|
|
||||||
|
PAL = w ? 1 : 0;
|
||||||
|
|
||||||
|
FCEUPPU_SetVideoSystem(w);
|
||||||
|
SetSoundVariables();
|
||||||
|
}
|
||||||
|
|
||||||
|
FCEUS FSettings;
|
||||||
|
|
||||||
|
void FCEU_printf(char *format, ...)
|
||||||
|
{
|
||||||
|
char temp[2048];
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
vsprintf(temp, format, ap);
|
||||||
|
FCEUD_Message(temp);
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_PrintError(char *format, ...)
|
||||||
|
{
|
||||||
|
char temp[2048];
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
vsprintf(temp, format, ap);
|
||||||
|
FCEUD_PrintError(temp);
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall)
|
||||||
|
{
|
||||||
|
FSettings.UsrFirstSLine[0] = ntscf;
|
||||||
|
FSettings.UsrLastSLine[0] = ntscl;
|
||||||
|
FSettings.UsrFirstSLine[1] = palf;
|
||||||
|
FSettings.UsrLastSLine[1] = pall;
|
||||||
|
if (PAL)
|
||||||
|
{
|
||||||
|
FSettings.FirstSLine = FSettings.UsrFirstSLine[1];
|
||||||
|
FSettings.LastSLine = FSettings.UsrLastSLine[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FSettings.FirstSLine = FSettings.UsrFirstSLine[0];
|
||||||
|
FSettings.LastSLine = FSettings.UsrLastSLine[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_SetVidSystem(int a)
|
||||||
|
{
|
||||||
|
FSettings.PAL = a ? 1 : 0;
|
||||||
|
|
||||||
|
if (!GameInfo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
FCEU_ResetVidSys();
|
||||||
|
FCEU_ResetPalette();
|
||||||
|
}
|
||||||
|
|
||||||
|
int FCEUI_GetCurrentVidSystem(int *slstart, int *slend)
|
||||||
|
{
|
||||||
|
if (slstart)
|
||||||
|
*slstart = FSettings.FirstSLine;
|
||||||
|
if (slend)
|
||||||
|
*slend = FSettings.LastSLine;
|
||||||
|
return(PAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_SetGameGenie(int a)
|
||||||
|
{
|
||||||
|
FSettings.GameGenie = a ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_SetSnapName(int a)
|
||||||
|
{
|
||||||
|
FSettings.SnapName = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 FCEUI_GetDesiredFPS(void)
|
||||||
|
{
|
||||||
|
if (PAL)
|
||||||
|
return(838977920); // ~50.007
|
||||||
|
else
|
||||||
|
return(1008307711); // ~60.1
|
||||||
|
}
|
||||||
772
src/drivers/libretro/fceu/fds.c
Normal file
772
src/drivers/libretro/fceu/fds.c
Normal file
@@ -0,0 +1,772 @@
|
|||||||
|
/* FCE Ultra - NES/Famicom Emulator
|
||||||
|
*
|
||||||
|
* Copyright notice for this file:
|
||||||
|
* Copyright (C) 2002 Xodnizel
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "fceu-types.h"
|
||||||
|
#include "x6502.h"
|
||||||
|
#include "fceu.h"
|
||||||
|
#include "fds.h"
|
||||||
|
#include "sound.h"
|
||||||
|
#include "general.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "file.h"
|
||||||
|
#include "fceu-memory.h"
|
||||||
|
#include "cart.h"
|
||||||
|
#include "md5.h"
|
||||||
|
#include "netplay.h"
|
||||||
|
|
||||||
|
// TODO: Add code to put a delay in between the time a disk is inserted
|
||||||
|
// and the when it can be successfully read/written to. This should
|
||||||
|
// prevent writes to wrong places OR add code to prevent disk ejects
|
||||||
|
// when the virtual motor is on(mmm...virtual motor).
|
||||||
|
|
||||||
|
static DECLFR(FDSRead4030);
|
||||||
|
static DECLFR(FDSRead4031);
|
||||||
|
static DECLFR(FDSRead4032);
|
||||||
|
static DECLFR(FDSRead4033);
|
||||||
|
|
||||||
|
static DECLFW(FDSWrite);
|
||||||
|
|
||||||
|
static DECLFW(FDSWaveWrite);
|
||||||
|
static DECLFR(FDSWaveRead);
|
||||||
|
|
||||||
|
static DECLFR(FDSSRead);
|
||||||
|
static DECLFW(FDSSWrite);
|
||||||
|
|
||||||
|
static void FDSInit(void);
|
||||||
|
static void FDSClose(void);
|
||||||
|
|
||||||
|
static void FP_FASTAPASS(1) FDSFix(int a);
|
||||||
|
|
||||||
|
static uint8 FDSRegs[6];
|
||||||
|
static int32 IRQLatch, IRQCount;
|
||||||
|
static uint8 IRQa;
|
||||||
|
|
||||||
|
static uint8 *FDSRAM = NULL;
|
||||||
|
static uint32 FDSRAMSize;
|
||||||
|
static uint8 *FDSBIOS = NULL;
|
||||||
|
static uint32 FDSBIOSsize;
|
||||||
|
static uint8 *CHRRAM = NULL;
|
||||||
|
static uint32 CHRRAMSize;
|
||||||
|
|
||||||
|
/* Original disk data backup, to help in creating save states. */
|
||||||
|
static uint8 *diskdatao[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
static uint8 *diskdata[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
static uint32 TotalSides;
|
||||||
|
static uint8 DiskWritten = 0; /* Set to 1 if disk was written to. */
|
||||||
|
static uint8 writeskip;
|
||||||
|
static int32 DiskPtr;
|
||||||
|
static int32 DiskSeekIRQ;
|
||||||
|
static uint8 SelectDisk, InDisk;
|
||||||
|
|
||||||
|
uint32 lastDiskPtrRead, lastDiskPtrWrite;
|
||||||
|
|
||||||
|
#define DC_INC 1
|
||||||
|
|
||||||
|
void FDSGI(int h) {
|
||||||
|
switch (h) {
|
||||||
|
case GI_CLOSE: FDSClose(); break;
|
||||||
|
case GI_POWER: FDSInit(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FDSStateRestore(int version) {
|
||||||
|
int x;
|
||||||
|
|
||||||
|
setmirror(((FDSRegs[5] & 8) >> 3) ^ 1);
|
||||||
|
|
||||||
|
if (version >= 9810)
|
||||||
|
for (x = 0; x < TotalSides; x++) {
|
||||||
|
int b;
|
||||||
|
for (b = 0; b < 65500; b++)
|
||||||
|
diskdata[x][b] ^= diskdatao[x][b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FDSSound();
|
||||||
|
void FDSSoundReset(void);
|
||||||
|
void FDSSoundStateAdd(void);
|
||||||
|
static void RenderSound(void);
|
||||||
|
static void RenderSoundHQ(void);
|
||||||
|
|
||||||
|
static void FDSInit(void) {
|
||||||
|
memset(FDSRegs, 0, sizeof(FDSRegs));
|
||||||
|
lastDiskPtrRead = lastDiskPtrWrite = writeskip = DiskPtr = DiskSeekIRQ = 0;
|
||||||
|
|
||||||
|
setmirror(1);
|
||||||
|
setprg8(0xE000, 0); // BIOS
|
||||||
|
setprg32r(1, 0x6000, 0); // 32KB RAM
|
||||||
|
setchr8(0); // 8KB CHR RAM
|
||||||
|
|
||||||
|
MapIRQHook = FDSFix;
|
||||||
|
GameStateRestore = FDSStateRestore;
|
||||||
|
|
||||||
|
SetReadHandler(0x4030, 0x4030, FDSRead4030);
|
||||||
|
SetReadHandler(0x4031, 0x4031, FDSRead4031);
|
||||||
|
SetReadHandler(0x4032, 0x4032, FDSRead4032);
|
||||||
|
SetReadHandler(0x4033, 0x4033, FDSRead4033);
|
||||||
|
|
||||||
|
SetWriteHandler(0x4020, 0x4025, FDSWrite);
|
||||||
|
|
||||||
|
SetWriteHandler(0x6000, 0xDFFF, CartBW);
|
||||||
|
SetReadHandler(0x6000, 0xFFFF, CartBR);
|
||||||
|
|
||||||
|
IRQCount = IRQLatch = IRQa = 0;
|
||||||
|
|
||||||
|
FDSSoundReset();
|
||||||
|
InDisk = 0;
|
||||||
|
SelectDisk = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_FDSInsert(int oride) {
|
||||||
|
if (InDisk == 255) {
|
||||||
|
FCEU_DispMessage("Disk %d Side %s Inserted", SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A");
|
||||||
|
InDisk = SelectDisk;
|
||||||
|
} else {
|
||||||
|
FCEU_DispMessage("Disk %d Side %s Ejected", SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A");
|
||||||
|
InDisk = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_FDSEject(void) {
|
||||||
|
InDisk = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_FDSSelect(void) {
|
||||||
|
if (InDisk != 255) {
|
||||||
|
FCEU_DispMessage("Eject disk before selecting.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SelectDisk = ((SelectDisk + 1) % TotalSides) & 3;
|
||||||
|
FCEU_DispMessage("Disk %d Side %s Selected", SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FP_FASTAPASS(1) FDSFix(int a) {
|
||||||
|
if ((IRQa & 2) && IRQCount) {
|
||||||
|
IRQCount -= a;
|
||||||
|
if (IRQCount <= 0) {
|
||||||
|
if (!(IRQa & 1)) {
|
||||||
|
IRQa &= ~2;
|
||||||
|
IRQCount = IRQLatch = 0;
|
||||||
|
} else
|
||||||
|
IRQCount = IRQLatch;
|
||||||
|
X6502_IRQBegin(FCEU_IQEXT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (DiskSeekIRQ > 0) {
|
||||||
|
DiskSeekIRQ -= a;
|
||||||
|
if (DiskSeekIRQ <= 0) {
|
||||||
|
if (FDSRegs[5] & 0x80) {
|
||||||
|
X6502_IRQBegin(FCEU_IQEXT2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFR(FDSRead4030) {
|
||||||
|
uint8 ret = 0;
|
||||||
|
|
||||||
|
/* Cheap hack. */
|
||||||
|
if (X.IRQlow & FCEU_IQEXT) ret |= 1;
|
||||||
|
if (X.IRQlow & FCEU_IQEXT2) ret |= 2;
|
||||||
|
|
||||||
|
#ifdef FCEUDEF_DEBUGGER
|
||||||
|
if (!fceuindbg)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
X6502_IRQEnd(FCEU_IQEXT);
|
||||||
|
X6502_IRQEnd(FCEU_IQEXT2);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFR(FDSRead4031) {
|
||||||
|
static uint8 z = 0;
|
||||||
|
if (InDisk != 255) {
|
||||||
|
z = diskdata[InDisk][DiskPtr];
|
||||||
|
lastDiskPtrRead = DiskPtr;
|
||||||
|
#ifdef FCEUDEF_DEBUGGER
|
||||||
|
if (!fceuindbg)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (DiskPtr < 64999) DiskPtr++;
|
||||||
|
DiskSeekIRQ = 150;
|
||||||
|
X6502_IRQEnd(FCEU_IQEXT2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
static DECLFR(FDSRead4032) {
|
||||||
|
uint8 ret;
|
||||||
|
|
||||||
|
ret = X.DB & ~7;
|
||||||
|
if (InDisk == 255)
|
||||||
|
ret |= 5;
|
||||||
|
|
||||||
|
if (InDisk == 255 || !(FDSRegs[5] & 1) || (FDSRegs[5] & 2))
|
||||||
|
ret |= 2;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFR(FDSRead4033) {
|
||||||
|
return 0x80; // battery
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Begin FDS sound */
|
||||||
|
|
||||||
|
#define FDSClock (1789772.7272727272727272 / 2)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int64 cycles; // Cycles per PCM sample
|
||||||
|
int64 count; // Cycle counter
|
||||||
|
int64 envcount; // Envelope cycle counter
|
||||||
|
uint32 b19shiftreg60;
|
||||||
|
uint32 b24adder66;
|
||||||
|
uint32 b24latch68;
|
||||||
|
uint32 b17latch76;
|
||||||
|
int32 clockcount; // Counter to divide frequency by 8.
|
||||||
|
uint8 b8shiftreg88; // Modulation register.
|
||||||
|
uint8 amplitude[2]; // Current amplitudes.
|
||||||
|
uint8 speedo[2];
|
||||||
|
uint8 mwcount;
|
||||||
|
uint8 mwstart;
|
||||||
|
uint8 mwave[0x20]; // Modulation waveform
|
||||||
|
uint8 cwave[0x40]; // Game-defined waveform(carrier)
|
||||||
|
uint8 SPSG[0xB];
|
||||||
|
} FDSSOUND;
|
||||||
|
|
||||||
|
static FDSSOUND fdso;
|
||||||
|
|
||||||
|
#define SPSG fdso.SPSG
|
||||||
|
#define b19shiftreg60 fdso.b19shiftreg60
|
||||||
|
#define b24adder66 fdso.b24adder66
|
||||||
|
#define b24latch68 fdso.b24latch68
|
||||||
|
#define b17latch76 fdso.b17latch76
|
||||||
|
#define b8shiftreg88 fdso.b8shiftreg88
|
||||||
|
#define clockcount fdso.clockcount
|
||||||
|
#define amplitude fdso.amplitude
|
||||||
|
#define speedo fdso.speedo
|
||||||
|
|
||||||
|
void FDSSoundStateAdd(void) {
|
||||||
|
AddExState(fdso.cwave, 64, 0, "WAVE");
|
||||||
|
AddExState(fdso.mwave, 32, 0, "MWAV");
|
||||||
|
AddExState(amplitude, 2, 0, "AMPL");
|
||||||
|
AddExState(SPSG, 0xB, 0, "SPSG");
|
||||||
|
|
||||||
|
AddExState(&b8shiftreg88, 1, 0, "B88");
|
||||||
|
|
||||||
|
AddExState(&clockcount, 4, 1, "CLOC");
|
||||||
|
AddExState(&b19shiftreg60, 4, 1, "B60");
|
||||||
|
AddExState(&b24adder66, 4, 1, "B66");
|
||||||
|
AddExState(&b24latch68, 4, 1, "B68");
|
||||||
|
AddExState(&b17latch76, 4, 1, "B76");
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFR(FDSSRead) {
|
||||||
|
switch (A & 0xF) {
|
||||||
|
case 0x0: return(amplitude[0] | (X.DB & 0xC0));
|
||||||
|
case 0x2: return(amplitude[1] | (X.DB & 0xC0));
|
||||||
|
}
|
||||||
|
return(X.DB);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFW(FDSSWrite) {
|
||||||
|
if (FSettings.SndRate) {
|
||||||
|
if (FSettings.soundq >= 1)
|
||||||
|
RenderSoundHQ();
|
||||||
|
else
|
||||||
|
RenderSound();
|
||||||
|
}
|
||||||
|
A -= 0x4080;
|
||||||
|
switch (A) {
|
||||||
|
case 0x0:
|
||||||
|
case 0x4:
|
||||||
|
if (V & 0x80)
|
||||||
|
amplitude[(A & 0xF) >> 2] = V & 0x3F;
|
||||||
|
break;
|
||||||
|
case 0x7:
|
||||||
|
b17latch76 = 0;
|
||||||
|
SPSG[0x5] = 0;
|
||||||
|
break;
|
||||||
|
case 0x8:
|
||||||
|
b17latch76 = 0;
|
||||||
|
fdso.mwave[SPSG[0x5] & 0x1F] = V & 0x7;
|
||||||
|
SPSG[0x5] = (SPSG[0x5] + 1) & 0x1F;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SPSG[A] = V;
|
||||||
|
}
|
||||||
|
|
||||||
|
// $4080 - Fundamental wave amplitude data register 92
|
||||||
|
// $4082 - Fundamental wave frequency data register 58
|
||||||
|
// $4083 - Same as $4082($4083 is the upper 4 bits).
|
||||||
|
|
||||||
|
// $4084 - Modulation amplitude data register 78
|
||||||
|
// $4086 - Modulation frequency data register 72
|
||||||
|
// $4087 - Same as $4086($4087 is the upper 4 bits)
|
||||||
|
|
||||||
|
|
||||||
|
static void DoEnv() {
|
||||||
|
int x;
|
||||||
|
|
||||||
|
for (x = 0; x < 2; x++)
|
||||||
|
if (!(SPSG[x << 2] & 0x80) && !(SPSG[0x3] & 0x40)) {
|
||||||
|
static int counto[2] = { 0, 0 };
|
||||||
|
|
||||||
|
if (counto[x] <= 0) {
|
||||||
|
if (!(SPSG[x << 2] & 0x80)) {
|
||||||
|
if (SPSG[x << 2] & 0x40) {
|
||||||
|
if (amplitude[x] < 0x3F)
|
||||||
|
amplitude[x]++;
|
||||||
|
} else {
|
||||||
|
if (amplitude[x] > 0)
|
||||||
|
amplitude[x]--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
counto[x] = (SPSG[x << 2] & 0x3F);
|
||||||
|
} else
|
||||||
|
counto[x]--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFR(FDSWaveRead) {
|
||||||
|
return(fdso.cwave[A & 0x3f] | (X.DB & 0xC0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFW(FDSWaveWrite) {
|
||||||
|
if (SPSG[0x9] & 0x80)
|
||||||
|
fdso.cwave[A & 0x3f] = V & 0x3F;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ta;
|
||||||
|
static INLINE void ClockRise(void) {
|
||||||
|
if (!clockcount) {
|
||||||
|
ta++;
|
||||||
|
|
||||||
|
b19shiftreg60 = (SPSG[0x2] | ((SPSG[0x3] & 0xF) << 8));
|
||||||
|
b17latch76 = (SPSG[0x6] | ((SPSG[0x07] & 0xF) << 8)) + b17latch76;
|
||||||
|
|
||||||
|
if (!(SPSG[0x7] & 0x80)) {
|
||||||
|
int t = fdso.mwave[(b17latch76 >> 13) & 0x1F] & 7;
|
||||||
|
int t2 = amplitude[1];
|
||||||
|
int adj = 0;
|
||||||
|
|
||||||
|
if ((t & 3)) {
|
||||||
|
if ((t & 4))
|
||||||
|
adj -= (t2 * ((4 - (t & 3))));
|
||||||
|
else
|
||||||
|
adj += (t2 * ((t & 3)));
|
||||||
|
}
|
||||||
|
adj *= 2;
|
||||||
|
if (adj > 0x7F) adj = 0x7F;
|
||||||
|
if (adj < -0x80) adj = -0x80;
|
||||||
|
b8shiftreg88 = 0x80 + adj;
|
||||||
|
} else {
|
||||||
|
b8shiftreg88 = 0x80;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
b19shiftreg60 <<= 1;
|
||||||
|
b8shiftreg88 >>= 1;
|
||||||
|
}
|
||||||
|
b24adder66 = (b24latch68 + b19shiftreg60) & 0x1FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE void ClockFall(void) {
|
||||||
|
if ((b8shiftreg88 & 1))
|
||||||
|
b24latch68 = b24adder66;
|
||||||
|
clockcount = (clockcount + 1) & 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE int32 FDSDoSound(void) {
|
||||||
|
fdso.count += fdso.cycles;
|
||||||
|
if (fdso.count >= ((int64)1 << 40)) {
|
||||||
|
dogk:
|
||||||
|
fdso.count -= (int64)1 << 40;
|
||||||
|
ClockRise();
|
||||||
|
ClockFall();
|
||||||
|
fdso.envcount--;
|
||||||
|
if (fdso.envcount <= 0) {
|
||||||
|
fdso.envcount += SPSG[0xA] * 3;
|
||||||
|
DoEnv();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fdso.count >= 32768) goto dogk;
|
||||||
|
|
||||||
|
// Might need to emulate applying the amplitude to the waveform a bit better...
|
||||||
|
{
|
||||||
|
int k = amplitude[0];
|
||||||
|
if (k > 0x20) k = 0x20;
|
||||||
|
return (fdso.cwave[b24latch68 >> 19] * k) * 4 / ((SPSG[0x9] & 0x3) + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32 FBC = 0;
|
||||||
|
|
||||||
|
static void RenderSound(void) {
|
||||||
|
int32 end, start;
|
||||||
|
int32 x;
|
||||||
|
|
||||||
|
start = FBC;
|
||||||
|
end = (SOUNDTS << 16) / soundtsinc;
|
||||||
|
if (end <= start)
|
||||||
|
return;
|
||||||
|
FBC = end;
|
||||||
|
|
||||||
|
if (!(SPSG[0x9] & 0x80))
|
||||||
|
for (x = start; x < end; x++) {
|
||||||
|
uint32 t = FDSDoSound();
|
||||||
|
t += t >> 1;
|
||||||
|
t >>= 4;
|
||||||
|
Wave[x >> 4] += t; //(t>>2)-(t>>3); //>>3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RenderSoundHQ(void) {
|
||||||
|
uint32 x;
|
||||||
|
|
||||||
|
if (!(SPSG[0x9] & 0x80))
|
||||||
|
for (x = FBC; x < SOUNDTS; x++) {
|
||||||
|
uint32 t = FDSDoSound();
|
||||||
|
t += t >> 1;
|
||||||
|
WaveHi[x] += t; //(t<<2)-(t<<1);
|
||||||
|
}
|
||||||
|
FBC = SOUNDTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HQSync(int32 ts) {
|
||||||
|
FBC = ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FDSSound(int c) {
|
||||||
|
RenderSound();
|
||||||
|
FBC = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FDS_ESI(void) {
|
||||||
|
if (FSettings.SndRate) {
|
||||||
|
if (FSettings.soundq >= 1) {
|
||||||
|
fdso.cycles = (int64)1 << 39;
|
||||||
|
} else {
|
||||||
|
fdso.cycles = ((int64)1 << 40) * FDSClock;
|
||||||
|
fdso.cycles /= FSettings.SndRate * 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetReadHandler(0x4040, 0x407f, FDSWaveRead);
|
||||||
|
SetWriteHandler(0x4040, 0x407f, FDSWaveWrite);
|
||||||
|
SetWriteHandler(0x4080, 0x408A, FDSSWrite);
|
||||||
|
SetReadHandler(0x4090, 0x4092, FDSSRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FDSSoundReset(void) {
|
||||||
|
memset(&fdso, 0, sizeof(fdso));
|
||||||
|
FDS_ESI();
|
||||||
|
GameExpSound.HiSync = HQSync;
|
||||||
|
GameExpSound.HiFill = RenderSoundHQ;
|
||||||
|
GameExpSound.Fill = FDSSound;
|
||||||
|
GameExpSound.RChange = FDS_ESI;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFW(FDSWrite) {
|
||||||
|
switch (A) {
|
||||||
|
case 0x4020:
|
||||||
|
X6502_IRQEnd(FCEU_IQEXT);
|
||||||
|
IRQLatch &= 0xFF00;
|
||||||
|
IRQLatch |= V;
|
||||||
|
break;
|
||||||
|
case 0x4021:
|
||||||
|
X6502_IRQEnd(FCEU_IQEXT);
|
||||||
|
IRQLatch &= 0xFF;
|
||||||
|
IRQLatch |= V << 8;
|
||||||
|
break;
|
||||||
|
case 0x4022:
|
||||||
|
X6502_IRQEnd(FCEU_IQEXT);
|
||||||
|
IRQCount = IRQLatch;
|
||||||
|
IRQa = V & 3;
|
||||||
|
break;
|
||||||
|
case 0x4024:
|
||||||
|
if ((InDisk != 255) && !(FDSRegs[5] & 0x4) && (FDSRegs[3] & 0x1)) {
|
||||||
|
if (DiskPtr >= 0 && DiskPtr < 65500) {
|
||||||
|
if (writeskip)
|
||||||
|
writeskip--;
|
||||||
|
else if (DiskPtr >= 2) {
|
||||||
|
DiskWritten = 1;
|
||||||
|
diskdata[InDisk][DiskPtr - 2] = V;
|
||||||
|
lastDiskPtrWrite = DiskPtr - 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x4025:
|
||||||
|
X6502_IRQEnd(FCEU_IQEXT2);
|
||||||
|
if (InDisk != 255) {
|
||||||
|
if (!(V & 0x40)) {
|
||||||
|
if ((FDSRegs[5] & 0x40) && !(V & 0x10)) {
|
||||||
|
DiskSeekIRQ = 200;
|
||||||
|
DiskPtr -= 2;
|
||||||
|
}
|
||||||
|
if (DiskPtr < 0) DiskPtr = 0;
|
||||||
|
}
|
||||||
|
if (!(V & 0x4)) writeskip = 2;
|
||||||
|
if (V & 2) {
|
||||||
|
DiskPtr = 0; DiskSeekIRQ = 200;
|
||||||
|
}
|
||||||
|
if (V & 0x40) DiskSeekIRQ = 200;
|
||||||
|
}
|
||||||
|
setmirror(((V >> 3) & 1) ^ 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FDSRegs[A & 7] = V;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FreeFDSMemory(void) {
|
||||||
|
int x;
|
||||||
|
|
||||||
|
for (x = 0; x < TotalSides; x++)
|
||||||
|
if (diskdata[x]) {
|
||||||
|
free(diskdata[x]);
|
||||||
|
diskdata[x] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SubLoad(FCEUFILE *fp) {
|
||||||
|
struct md5_context md5;
|
||||||
|
uint8 header[16];
|
||||||
|
int x;
|
||||||
|
|
||||||
|
FCEU_fread(header, 16, 1, fp);
|
||||||
|
|
||||||
|
if (memcmp(header, "FDS\x1a", 4)) {
|
||||||
|
if (!(memcmp(header + 1, "*NINTENDO-HVC*", 14))) {
|
||||||
|
long t;
|
||||||
|
t = FCEU_fgetsize(fp);
|
||||||
|
if (t < 65500)
|
||||||
|
t = 65500;
|
||||||
|
TotalSides = t / 65500;
|
||||||
|
FCEU_fseek(fp, 0, SEEK_SET);
|
||||||
|
} else
|
||||||
|
return(0);
|
||||||
|
} else
|
||||||
|
TotalSides = header[4];
|
||||||
|
|
||||||
|
md5_starts(&md5);
|
||||||
|
|
||||||
|
if (TotalSides > 8) TotalSides = 8;
|
||||||
|
if (TotalSides < 1) TotalSides = 1;
|
||||||
|
|
||||||
|
for (x = 0; x < TotalSides; x++) {
|
||||||
|
diskdata[x] = (uint8*)FCEU_malloc(65500);
|
||||||
|
if (!diskdata[x]) {
|
||||||
|
int zol;
|
||||||
|
for (zol = 0; zol < x; zol++)
|
||||||
|
free(diskdata[zol]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
FCEU_fread(diskdata[x], 1, 65500, fp);
|
||||||
|
md5_update(&md5, diskdata[x], 65500);
|
||||||
|
}
|
||||||
|
md5_finish(&md5, GameInfo->MD5);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PreSave(void) {
|
||||||
|
int x;
|
||||||
|
for (x = 0; x < TotalSides; x++) {
|
||||||
|
int b;
|
||||||
|
for (b = 0; b < 65500; b++)
|
||||||
|
diskdata[x][b] ^= diskdatao[x][b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PostSave(void) {
|
||||||
|
int x;
|
||||||
|
for (x = 0; x < TotalSides; x++) {
|
||||||
|
int b;
|
||||||
|
for (b = 0; b < 65500; b++)
|
||||||
|
diskdata[x][b] ^= diskdatao[x][b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int FDSLoad(const char *name, FCEUFILE *fp) {
|
||||||
|
FILE *zp;
|
||||||
|
int x;
|
||||||
|
|
||||||
|
char *fn = FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0);
|
||||||
|
|
||||||
|
if (!(zp = fopen(fn, "rb"))) {
|
||||||
|
FCEU_PrintError("FDS BIOS ROM image missing!");
|
||||||
|
free(fn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(fn);
|
||||||
|
|
||||||
|
ResetCartMapping();
|
||||||
|
|
||||||
|
if (FDSBIOS)
|
||||||
|
free(FDSBIOS);
|
||||||
|
FDSBIOS = NULL;
|
||||||
|
if (FDSRAM)
|
||||||
|
free(FDSRAM);
|
||||||
|
FDSRAM = NULL;
|
||||||
|
if (CHRRAM)
|
||||||
|
free(CHRRAM);
|
||||||
|
CHRRAM = NULL;
|
||||||
|
|
||||||
|
FDSBIOSsize = 8192;
|
||||||
|
FDSBIOS = (uint8*)FCEU_gmalloc(FDSBIOSsize);
|
||||||
|
SetupCartPRGMapping(0, FDSBIOS, FDSBIOSsize, 0);
|
||||||
|
|
||||||
|
if (fread(FDSBIOS, 1, FDSBIOSsize, zp) != FDSBIOSsize) {
|
||||||
|
if (FDSBIOS)
|
||||||
|
free(FDSBIOS);
|
||||||
|
FDSBIOS = NULL;
|
||||||
|
fclose(zp);
|
||||||
|
FCEU_PrintError("Error reading FDS BIOS ROM image.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(zp);
|
||||||
|
|
||||||
|
FCEU_fseek(fp, 0, SEEK_SET);
|
||||||
|
|
||||||
|
FreeFDSMemory();
|
||||||
|
if (!SubLoad(fp)) {
|
||||||
|
if (FDSBIOS)
|
||||||
|
free(FDSBIOS);
|
||||||
|
FDSBIOS = NULL;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
FCEUFILE *tp;
|
||||||
|
char *fn = FCEU_MakeFName(FCEUMKF_FDS, 0, 0);
|
||||||
|
|
||||||
|
int x;
|
||||||
|
for (x = 0; x < TotalSides; x++) {
|
||||||
|
diskdatao[x] = (uint8*)FCEU_malloc(65500);
|
||||||
|
memcpy(diskdatao[x], diskdata[x], 65500);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tp = FCEU_fopen(fn, 0, "rb", 0, NULL, 0))) {
|
||||||
|
FCEU_printf("Disk was written. Auxillary FDS file open \"%s\".\n", fn);
|
||||||
|
FreeFDSMemory();
|
||||||
|
if (!SubLoad(tp)) {
|
||||||
|
FCEU_PrintError("Error reading auxillary FDS file.");
|
||||||
|
if (FDSBIOS)
|
||||||
|
free(FDSBIOS);
|
||||||
|
FDSBIOS = NULL;
|
||||||
|
free(fn);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
FCEU_fclose(tp);
|
||||||
|
DiskWritten = 1; /* For save state handling. */
|
||||||
|
}
|
||||||
|
free(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
GameInfo->type = GIT_FDS;
|
||||||
|
GameInterface = FDSGI;
|
||||||
|
|
||||||
|
SelectDisk = 0;
|
||||||
|
InDisk = 255;
|
||||||
|
|
||||||
|
ResetExState(PreSave, PostSave);
|
||||||
|
FDSSoundStateAdd();
|
||||||
|
|
||||||
|
for (x = 0; x < TotalSides; x++) {
|
||||||
|
char temp[5];
|
||||||
|
sprintf(temp, "DDT%d", x);
|
||||||
|
AddExState(diskdata[x], 65500, 0, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddExState(FDSRegs, sizeof(FDSRegs), 0, "FREG");
|
||||||
|
AddExState(&IRQCount, 4, 1, "IRQC");
|
||||||
|
AddExState(&IRQLatch, 4, 1, "IQL1");
|
||||||
|
AddExState(&IRQa, 1, 0, "IRQA");
|
||||||
|
AddExState(&writeskip, 1, 0, "WSKI");
|
||||||
|
AddExState(&DiskPtr, 4, 1, "DPTR");
|
||||||
|
AddExState(&DiskSeekIRQ, 4, 1, "DSIR");
|
||||||
|
AddExState(&SelectDisk, 1, 0, "SELD");
|
||||||
|
AddExState(&InDisk, 1, 0, "INDI");
|
||||||
|
AddExState(&DiskWritten, 1, 0, "DSKW");
|
||||||
|
|
||||||
|
CHRRAMSize = 8192;
|
||||||
|
CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSize);
|
||||||
|
memset(CHRRAM, 0, CHRRAMSize);
|
||||||
|
SetupCartCHRMapping(0, CHRRAM, CHRRAMSize, 1);
|
||||||
|
AddExState(CHRRAM, CHRRAMSize, 0, "CHRR");
|
||||||
|
|
||||||
|
FDSRAMSize = 32768;
|
||||||
|
FDSRAM = (uint8*)FCEU_gmalloc(FDSRAMSize);
|
||||||
|
memset(FDSRAM, 0, FDSRAMSize);
|
||||||
|
SetupCartPRGMapping(1, FDSRAM, FDSRAMSize, 1);
|
||||||
|
AddExState(FDSRAM, FDSRAMSize, 0, "FDSR");
|
||||||
|
|
||||||
|
SetupCartMirroring(0, 0, 0);
|
||||||
|
|
||||||
|
FCEU_printf(" Sides: %d\n\n", TotalSides);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FDSClose(void) {
|
||||||
|
FILE *fp;
|
||||||
|
int x;
|
||||||
|
char *fn = FCEU_MakeFName(FCEUMKF_FDS, 0, 0);
|
||||||
|
|
||||||
|
if (!DiskWritten) return;
|
||||||
|
|
||||||
|
if (!(fp = fopen(fn, "wb"))) {
|
||||||
|
free(fn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FCEU_printf("FDS Save \"%s\"\n", fn);
|
||||||
|
free(fn);
|
||||||
|
|
||||||
|
for (x = 0; x < TotalSides; x++) {
|
||||||
|
if (fwrite(diskdata[x], 1, 65500, fp) != 65500) {
|
||||||
|
FCEU_PrintError("Error saving FDS image!");
|
||||||
|
fclose(fp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (x = 0; x < TotalSides; x++)
|
||||||
|
if (diskdatao[x]) {
|
||||||
|
free(diskdatao[x]);
|
||||||
|
diskdatao[x] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeFDSMemory();
|
||||||
|
if (FDSBIOS)
|
||||||
|
free(FDSBIOS);
|
||||||
|
FDSBIOS = NULL;
|
||||||
|
if (FDSRAM)
|
||||||
|
free(FDSRAM);
|
||||||
|
FDSRAM = NULL;
|
||||||
|
if (CHRRAM)
|
||||||
|
free(CHRRAM);
|
||||||
|
CHRRAM = NULL;
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
185
src/drivers/libretro/fceu/file.c
Normal file
185
src/drivers/libretro/fceu/file.c
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
/* FCE Ultra - NES/Famicom Emulator
|
||||||
|
*
|
||||||
|
* Copyright notice for this file:
|
||||||
|
* Copyright (C) 2002 Xodnizel
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <direct.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "fceu-types.h"
|
||||||
|
#include "file.h"
|
||||||
|
#include "fceu-endian.h"
|
||||||
|
#include "fceu-memory.h"
|
||||||
|
#include "driver.h"
|
||||||
|
#include "general.h"
|
||||||
|
|
||||||
|
#ifndef __GNUC__
|
||||||
|
#define strcasecmp strcmp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static MEMWRAP *MakeMemWrap(void *tz, int type)
|
||||||
|
{
|
||||||
|
MEMWRAP *tmp;
|
||||||
|
|
||||||
|
if (!(tmp = (MEMWRAP*)FCEU_malloc(sizeof(MEMWRAP))))
|
||||||
|
goto doret;
|
||||||
|
tmp->location = 0;
|
||||||
|
|
||||||
|
fseek((FILE*)tz, 0, SEEK_END);
|
||||||
|
tmp->size = ftell((FILE*)tz);
|
||||||
|
fseek((FILE*)tz, 0, SEEK_SET);
|
||||||
|
if (!(tmp->data = (uint8*)FCEU_malloc(tmp->size)))
|
||||||
|
{
|
||||||
|
free(tmp);
|
||||||
|
tmp = 0;
|
||||||
|
goto doret;
|
||||||
|
}
|
||||||
|
fread(tmp->data, 1, tmp->size, (FILE*)tz);
|
||||||
|
|
||||||
|
doret:
|
||||||
|
if (type == 0)
|
||||||
|
fclose((FILE*)tz);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MEMWRAP *MakeMemWrapBuffer(void *tz, int type, uint8 *buffer, size_t bufsize)
|
||||||
|
{
|
||||||
|
MEMWRAP *tmp = (MEMWRAP*)FCEU_malloc(sizeof(MEMWRAP));
|
||||||
|
|
||||||
|
if (!tmp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
tmp->location = 0;
|
||||||
|
tmp->size = bufsize;
|
||||||
|
tmp->data = buffer;
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn,
|
||||||
|
char *mode, char *ext, uint8 *buffer, size_t bufsize)
|
||||||
|
{
|
||||||
|
FCEUFILE *fceufp = (FCEUFILE*)malloc(sizeof(FCEUFILE));
|
||||||
|
void *t = fopen(path, mode);
|
||||||
|
|
||||||
|
if (!t)
|
||||||
|
{
|
||||||
|
free(fceufp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek((FILE*)t, 0, SEEK_SET);
|
||||||
|
fceufp->type = 0;
|
||||||
|
if (buffer)
|
||||||
|
fceufp->fp = MakeMemWrapBuffer(t, 0, buffer, bufsize);
|
||||||
|
else
|
||||||
|
fceufp->fp = MakeMemWrap(t, 0);
|
||||||
|
return fceufp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FCEU_fclose(FCEUFILE *fp)
|
||||||
|
{
|
||||||
|
if (fp->fp)
|
||||||
|
free(fp->fp);
|
||||||
|
fp->fp = NULL;
|
||||||
|
free(fp);
|
||||||
|
fp = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 FCEU_fread(void *ptr, size_t element_size, size_t nmemb, FCEUFILE *fp)
|
||||||
|
{
|
||||||
|
uint32_t total = nmemb * element_size;
|
||||||
|
|
||||||
|
if (fp->fp->location >= fp->fp->size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if((fp->fp->location + total) > fp->fp->size)
|
||||||
|
{
|
||||||
|
int64_t ak = fp->fp->size - fp->fp->location;
|
||||||
|
|
||||||
|
memcpy((uint8_t*)ptr, fp->fp->data + fp->fp->location, ak);
|
||||||
|
|
||||||
|
fp->fp->location = fp->fp->size;
|
||||||
|
|
||||||
|
return (ak / element_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy((uint8_t*)ptr, fp->fp->data + fp->fp->location, total);
|
||||||
|
|
||||||
|
fp->fp->location += total;
|
||||||
|
|
||||||
|
return nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FCEU_fseek(FCEUFILE *fp, long offset, int whence)
|
||||||
|
{
|
||||||
|
switch (whence)
|
||||||
|
{
|
||||||
|
case SEEK_SET:
|
||||||
|
if (offset >= fp->fp->size)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
fp->fp->location = offset;
|
||||||
|
break;
|
||||||
|
case SEEK_CUR:
|
||||||
|
if ((offset + fp->fp->location) > fp->fp->size)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
fp->fp->location += offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FCEU_read32le(uint32 *Bufo, FCEUFILE *fp)
|
||||||
|
{
|
||||||
|
if ((fp->fp->location + 4) > fp->fp->size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*Bufo = FCEU_de32lsb(fp->fp->data + fp->fp->location);
|
||||||
|
|
||||||
|
fp->fp->location += 4;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FCEU_fgetc(FCEUFILE *fp)
|
||||||
|
{
|
||||||
|
if (fp->fp->location < fp->fp->size)
|
||||||
|
return fp->fp->data[fp->fp->location++];
|
||||||
|
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 FCEU_ftell(FCEUFILE *fp)
|
||||||
|
{
|
||||||
|
return fp->fp->location;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 FCEU_fgetsize(FCEUFILE *fp)
|
||||||
|
{
|
||||||
|
return fp->fp->size;
|
||||||
|
}
|
||||||
162
src/drivers/libretro/fceu/general.c
Normal file
162
src/drivers/libretro/fceu/general.c
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
/* FCE Ultra - NES/Famicom Emulator
|
||||||
|
*
|
||||||
|
* Copyright notice for this file:
|
||||||
|
* Copyright (C) 2002 Xodnizel
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <direct.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "fceu-types.h"
|
||||||
|
#include "fceu.h"
|
||||||
|
|
||||||
|
#include "general.h"
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
#include "driver.h"
|
||||||
|
|
||||||
|
#include "md5.h"
|
||||||
|
|
||||||
|
static char BaseDirectory[2048];
|
||||||
|
static char FileBase[2048];
|
||||||
|
static char FileExt[2048]; /* Includes the . character, as in ".nes" */
|
||||||
|
|
||||||
|
static char FileBaseDirectory[2048];
|
||||||
|
|
||||||
|
void FCEUI_SetBaseDirectory(char *dir)
|
||||||
|
{
|
||||||
|
strncpy(BaseDirectory, dir, 2047);
|
||||||
|
BaseDirectory[2047] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *odirs[FCEUIOD__COUNT] = { 0, 0, 0, 0, 0, 0 }; // odirs, odors. ^_^
|
||||||
|
|
||||||
|
void FCEUI_SetDirOverride(int which, char *n)
|
||||||
|
{
|
||||||
|
odirs[which] = n;
|
||||||
|
|
||||||
|
/* Rebuild cache of present states/movies. */
|
||||||
|
if (GameInfo)
|
||||||
|
{
|
||||||
|
if (which == FCEUIOD_STATE)
|
||||||
|
FCEUSS_CheckStates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef HAVE_ASPRINTF
|
||||||
|
static int asprintf(char **strp, const char *fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
if (!(*strp = malloc(2048)))
|
||||||
|
return(0);
|
||||||
|
ret = vsnprintf(*strp, 2048, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *FCEU_MakeFName(int type, int id1, char *cd1)
|
||||||
|
{
|
||||||
|
char *ret = 0;
|
||||||
|
struct stat tmpstat;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case FCEUMKF_GGROM:
|
||||||
|
asprintf(&ret, "%s"PSS "gg.rom", BaseDirectory);
|
||||||
|
break;
|
||||||
|
case FCEUMKF_FDSROM:
|
||||||
|
asprintf(&ret, "%s"PSS "disksys.rom", BaseDirectory);
|
||||||
|
break;
|
||||||
|
case FCEUMKF_PALETTE:
|
||||||
|
if (odirs[FCEUIOD_MISC])
|
||||||
|
asprintf(&ret, "%s"PSS "%s.pal", odirs[FCEUIOD_MISC], FileBase);
|
||||||
|
else
|
||||||
|
asprintf(&ret, "%s"PSS "gameinfo"PSS "%s.pal", BaseDirectory, FileBase);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = malloc(1);
|
||||||
|
*ret = '\0';
|
||||||
|
}
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetFileBase(const char *f)
|
||||||
|
{
|
||||||
|
const char *tp1, *tp3;
|
||||||
|
|
||||||
|
#if PSS_STYLE == 4
|
||||||
|
tp1 = ((char*)strrchr(f, ':'));
|
||||||
|
#elif PSS_STYLE == 1
|
||||||
|
tp1 = ((char*)strrchr(f, '/'));
|
||||||
|
#else
|
||||||
|
tp1 = ((char*)strrchr(f, '\\'));
|
||||||
|
#if PSS_STYLE != 3
|
||||||
|
tp3 = ((char*)strrchr(f, '/'));
|
||||||
|
if (tp1 < tp3) tp1 = tp3;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
if (!tp1)
|
||||||
|
{
|
||||||
|
tp1 = f;
|
||||||
|
strcpy(FileBaseDirectory, ".");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(FileBaseDirectory, f, tp1 - f);
|
||||||
|
FileBaseDirectory[tp1 - f] = 0;
|
||||||
|
tp1++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((tp3 = strrchr(f, '.')) != NULL) && (tp3 > tp1))
|
||||||
|
{
|
||||||
|
memcpy(FileBase, tp1, tp3 - tp1);
|
||||||
|
FileBase[tp3 - tp1] = 0;
|
||||||
|
strcpy(FileExt, tp3);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy(FileBase, tp1);
|
||||||
|
FileExt[0] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 uppow2(uint32 n)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
|
||||||
|
for (x = 31; x >= 0; x--)
|
||||||
|
if (n & (1 << x))
|
||||||
|
{
|
||||||
|
if ((1 << x) != n)
|
||||||
|
return(1 << (x + 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
839
src/drivers/libretro/fceu/ines.c
Normal file
839
src/drivers/libretro/fceu/ines.c
Normal file
@@ -0,0 +1,839 @@
|
|||||||
|
/* FCE Ultra - NES/Famicom Emulator
|
||||||
|
*
|
||||||
|
* Copyright notice for this file:
|
||||||
|
* Copyright (C) 1998 BERO
|
||||||
|
* Copyright (C) 2002 Xodnizel
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "fceu-types.h"
|
||||||
|
#include "x6502.h"
|
||||||
|
#include "fceu.h"
|
||||||
|
#include "cart.h"
|
||||||
|
#include "ppu.h"
|
||||||
|
|
||||||
|
#include "ines.h"
|
||||||
|
#include "unif.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "file.h"
|
||||||
|
#include "general.h"
|
||||||
|
#include "fceu-memory.h"
|
||||||
|
#include "crc32.h"
|
||||||
|
#include "md5.h"
|
||||||
|
#include "cheat.h"
|
||||||
|
#include "vsuni.h"
|
||||||
|
|
||||||
|
extern SFORMAT FCEUVSUNI_STATEINFO[];
|
||||||
|
|
||||||
|
uint8 *trainerpoo = NULL;
|
||||||
|
uint8 *ROM = NULL;
|
||||||
|
uint8 *VROM = NULL;
|
||||||
|
uint8 *ExtraNTARAM = NULL;
|
||||||
|
iNES_HEADER head;
|
||||||
|
|
||||||
|
CartInfo iNESCart;
|
||||||
|
|
||||||
|
uint8 Mirroring = 0;
|
||||||
|
uint32 ROM_size = 0;
|
||||||
|
uint32 VROM_size = 0;
|
||||||
|
|
||||||
|
static int CHRRAMSize = -1;
|
||||||
|
static int iNES_Init(int num);
|
||||||
|
|
||||||
|
static int MapperNo = 0;
|
||||||
|
|
||||||
|
static DECLFR(TrainerRead) {
|
||||||
|
return(trainerpoo[A & 0x1FF]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iNES_ExecPower() {
|
||||||
|
if (iNESCart.Power)
|
||||||
|
iNESCart.Power();
|
||||||
|
|
||||||
|
if (trainerpoo) {
|
||||||
|
int x;
|
||||||
|
for (x = 0; x < 512; x++) {
|
||||||
|
X6502_DMW(0x7000 + x, trainerpoo[x]);
|
||||||
|
if (X6502_DMR(0x7000 + x) != trainerpoo[x]) {
|
||||||
|
SetReadHandler(0x7000, 0x71FF, TrainerRead);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iNESGI(int h) {
|
||||||
|
switch (h) {
|
||||||
|
case GI_RESETM2:
|
||||||
|
if (iNESCart.Reset)
|
||||||
|
iNESCart.Reset();
|
||||||
|
break;
|
||||||
|
case GI_POWER:
|
||||||
|
iNES_ExecPower();
|
||||||
|
break;
|
||||||
|
case GI_CLOSE:
|
||||||
|
{
|
||||||
|
FCEU_SaveGameSave(&iNESCart);
|
||||||
|
if (iNESCart.Close)
|
||||||
|
iNESCart.Close();
|
||||||
|
if (ROM) {
|
||||||
|
free(ROM);
|
||||||
|
ROM = NULL;
|
||||||
|
}
|
||||||
|
if (VROM) {
|
||||||
|
free(VROM);
|
||||||
|
VROM = NULL;
|
||||||
|
}
|
||||||
|
if (trainerpoo) {
|
||||||
|
free(trainerpoo);
|
||||||
|
trainerpoo = NULL;
|
||||||
|
}
|
||||||
|
if (ExtraNTARAM) {
|
||||||
|
free(ExtraNTARAM);
|
||||||
|
ExtraNTARAM = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 iNESGameCRC32 = 0;
|
||||||
|
|
||||||
|
struct CRCMATCH {
|
||||||
|
uint32 crc;
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct INPSEL {
|
||||||
|
uint32 crc32;
|
||||||
|
int input1;
|
||||||
|
int input2;
|
||||||
|
int inputfc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void SetInput(void) {
|
||||||
|
static struct INPSEL moo[] =
|
||||||
|
{
|
||||||
|
{0x19b0a9f1, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // 6-in-1 (MGC-023)(Unl)[!]
|
||||||
|
{0x29de87af, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Aerobics Studio
|
||||||
|
{0xd89e5a67, SI_UNSET, SI_UNSET, SIFC_ARKANOID }, // Arkanoid (J)
|
||||||
|
{0x0f141525, SI_UNSET, SI_UNSET, SIFC_ARKANOID }, // Arkanoid 2(J)
|
||||||
|
{0x32fb0583, SI_UNSET, SI_ARKANOID, SIFC_NONE }, // Arkanoid(NES)
|
||||||
|
{0x60ad090a, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Athletic World
|
||||||
|
{0x48ca0ee1, SI_GAMEPAD, SI_GAMEPAD, SIFC_BWORLD }, // Barcode World
|
||||||
|
{0x4318a2f8, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Barker Bill's Trick Shooting
|
||||||
|
{0x6cca1c1f, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Dai Undoukai
|
||||||
|
{0x24598791, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Duck Hunt
|
||||||
|
{0xd5d6eac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Edu (As)
|
||||||
|
{0xe9a7fe9e, SI_UNSET, SI_MOUSE, SIFC_NONE }, // Educational Computer 2000
|
||||||
|
{0x8f7b1669, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // FP BASIC 3.3 by maxzhou88
|
||||||
|
{0xf7606810, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.0A
|
||||||
|
{0x895037bc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.1a
|
||||||
|
{0xb2530afc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 3.0
|
||||||
|
{0xea90f3e2, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Family Trainer: Running Stadium
|
||||||
|
{0xbba58be5, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Family Trainer: Manhattan Police
|
||||||
|
{0x3e58a87e, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Freedom Force
|
||||||
|
{0xd9f45be9, SI_GAMEPAD, SI_GAMEPAD, SIFC_QUIZKING }, // Gimme a Break ...
|
||||||
|
{0x1545bd13, SI_GAMEPAD, SI_GAMEPAD, SIFC_QUIZKING }, // Gimme a Break ... 2
|
||||||
|
{0x4e959173, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Gotcha! - The Sport!
|
||||||
|
{0xbeb8ab01, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Gumshoe
|
||||||
|
{0xff24d794, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Hogan's Alley
|
||||||
|
{0x21f85681, SI_GAMEPAD, SI_GAMEPAD, SIFC_HYPERSHOT }, // Hyper Olympic (Gentei Ban)
|
||||||
|
{0x980be936, SI_GAMEPAD, SI_GAMEPAD, SIFC_HYPERSHOT }, // Hyper Olympic
|
||||||
|
{0x915a53a7, SI_GAMEPAD, SI_GAMEPAD, SIFC_HYPERSHOT }, // Hyper Sports
|
||||||
|
{0x9fae4d46, SI_GAMEPAD, SI_GAMEPAD, SIFC_MAHJONG }, // Ide Yousuke Meijin no Jissen Mahjong
|
||||||
|
{0x7b44fb2a, SI_GAMEPAD, SI_GAMEPAD, SIFC_MAHJONG }, // Ide Yousuke Meijin no Jissen Mahjong 2
|
||||||
|
{0x2f128512, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Jogging Race
|
||||||
|
{0xbb33196f, SI_UNSET, SI_UNSET, SIFC_FKB }, // Keyboard Transformer
|
||||||
|
{0x8587ee00, SI_UNSET, SI_UNSET, SIFC_FKB }, // Keyboard Transformer
|
||||||
|
{0x543ab532, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // LIKO Color Lines
|
||||||
|
{0x368c19a8, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // LIKO Study Cartridge
|
||||||
|
{0x5ee6008e, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Mechanized Attack
|
||||||
|
{0x370ceb65, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Meiro Dai Sakusen
|
||||||
|
{0x3a1694f9, SI_GAMEPAD, SI_GAMEPAD, SIFC_4PLAYER }, // Nekketsu Kakutou Densetsu
|
||||||
|
{0x9d048ea4, SI_GAMEPAD, SI_GAMEPAD, SIFC_OEKAKIDS }, // Oeka Kids
|
||||||
|
{0x2a6559a1, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Operation Wolf (J)
|
||||||
|
{0xedc3662b, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Operation Wolf
|
||||||
|
{0x912989dc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Playbox BASIC
|
||||||
|
{0x9044550e, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Rairai Kyonshizu
|
||||||
|
{0xea90f3e2, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Running Stadium
|
||||||
|
{0x851eb9be, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // Shooting Range
|
||||||
|
{0x6435c095, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // Short Order/Eggsplode
|
||||||
|
{0xc043a8df, SI_UNSET, SI_MOUSE, SIFC_NONE }, // Shu Qi Yu - Shu Xue Xiao Zhuan Yuan (Ch)
|
||||||
|
{0x2cf5db05, SI_UNSET, SI_MOUSE, SIFC_NONE }, // Shu Qi Yu - Zhi Li Xiao Zhuan Yuan (Ch)
|
||||||
|
{0xad9c63e2, SI_GAMEPAD, SI_UNSET, SIFC_SHADOW }, // Space Shadow
|
||||||
|
{0x61d86167, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // Street Cop
|
||||||
|
{0xabb2f974, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Study and Game 32-in-1
|
||||||
|
{0x41ef9ac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor
|
||||||
|
{0x8b265862, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor
|
||||||
|
{0x82f1fb96, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor 1.0 Russian
|
||||||
|
{0x9f8f200a, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Super Mogura Tataki!! - Pokkun Moguraa
|
||||||
|
{0xd74b2719, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // Super Team Games
|
||||||
|
{0x74bea652, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // Supergun 3-in-1
|
||||||
|
{0x5e073a1b, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Supor English (Chinese)
|
||||||
|
{0x589b6b0d, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // SuporV20
|
||||||
|
{0x41401c6d, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // SuporV40
|
||||||
|
{0x23d17f5e, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // The Lone Ranger
|
||||||
|
{0xc3c0811d, SI_GAMEPAD, SI_GAMEPAD, SIFC_OEKAKIDS }, // The two "Oeka Kids" games
|
||||||
|
{0xde8fd935, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // To the Earth
|
||||||
|
{0x47232739, SI_GAMEPAD, SI_GAMEPAD, SIFC_TOPRIDER }, // Top Rider
|
||||||
|
{0x8a12a7d9, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Totsugeki Fuuun Takeshi Jou
|
||||||
|
{0xb8b9aca3, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Wild Gunman
|
||||||
|
{0x5112dc21, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Wild Gunman
|
||||||
|
{0xaf4010ea, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // World Class Track Meet
|
||||||
|
{0x00000000, SI_UNSET, SI_UNSET, SIFC_UNSET }
|
||||||
|
};
|
||||||
|
int x = 0;
|
||||||
|
|
||||||
|
while (moo[x].input1 >= 0 || moo[x].input2 >= 0 || moo[x].inputfc >= 0) {
|
||||||
|
if (moo[x].crc32 == iNESGameCRC32) {
|
||||||
|
GameInfo->input[0] = moo[x].input1;
|
||||||
|
GameInfo->input[1] = moo[x].input2;
|
||||||
|
GameInfo->inputfc = moo[x].inputfc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INESB_INCOMPLETE 1
|
||||||
|
#define INESB_CORRUPT 2
|
||||||
|
#define INESB_HACKED 4
|
||||||
|
|
||||||
|
struct BADINF {
|
||||||
|
uint64 md5partial;
|
||||||
|
uint8 *name;
|
||||||
|
uint32 type;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct BADINF BadROMImages[] =
|
||||||
|
{
|
||||||
|
#include "ines-bad.h"
|
||||||
|
};
|
||||||
|
|
||||||
|
void CheckBad(uint64 md5partial) {
|
||||||
|
int32 x = 0;
|
||||||
|
while (BadROMImages[x].name) {
|
||||||
|
if (BadROMImages[x].md5partial == md5partial) {
|
||||||
|
FCEU_PrintError("The copy game you have loaded, \"%s\", is bad, and will not work properly in FCE Ultra.", BadROMImages[x].name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct CHINF {
|
||||||
|
uint32 crc32;
|
||||||
|
int32 mapper;
|
||||||
|
int32 mirror;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void CheckHInfo(void) {
|
||||||
|
/* ROM images that have the battery-backed bit set in the header that really
|
||||||
|
don't have battery-backed RAM is not that big of a problem, so I'll
|
||||||
|
treat this differently by only listing games that should have battery-backed RAM.
|
||||||
|
|
||||||
|
Lower 64 bits of the MD5 hash.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static uint64 savie[] =
|
||||||
|
{
|
||||||
|
0xc04361e499748382LL, /* AD&D Heroes of the Lance */
|
||||||
|
0xb72ee2337ced5792LL, /* AD&D Hillsfar */
|
||||||
|
0x2b7103b7a27bd72fLL, /* AD&D Pool of Radiance */
|
||||||
|
0x498c10dc463cfe95LL, /* Battle Fleet */
|
||||||
|
0x854d7947a3177f57LL, /* Crystalis */
|
||||||
|
0x4a1f5336b86851b6LL, /* DW */
|
||||||
|
0xb0bcc02c843c1b79LL, /* DW */
|
||||||
|
0x2dcf3a98c7937c22LL, /* DW 2 */
|
||||||
|
0x98e55e09dfcc7533LL, /* DW 4*/
|
||||||
|
0x733026b6b72f2470LL, /* Dw 3 */
|
||||||
|
0x6917ffcaca2d8466LL, /* Famista '90 */
|
||||||
|
0x8da46db592a1fcf4LL, /* Faria */
|
||||||
|
0xedba17a2c4608d20LL, /* Final Fantasy */
|
||||||
|
0x91a6846d3202e3d6LL, /* Final Fantasy */
|
||||||
|
0x012df596e2b31174LL, /* Final Fantasy 1+2 */
|
||||||
|
0xf6b359a720549ecdLL, /* Final Fantasy 2 */
|
||||||
|
0x5a30da1d9b4af35dLL, /* Final Fantasy 3 */
|
||||||
|
0xd63dcc68c2b20adcLL, /* Final Fantasy J */
|
||||||
|
0x2ee3417ba8b69706LL, /* Hydlide 3*/
|
||||||
|
0xebbce5a54cf3ecc0LL, /* Justbreed */
|
||||||
|
0x6a858da551ba239eLL, /* Kaijuu Monogatari */
|
||||||
|
0x2db8f5d16c10b925LL, /* Kyonshiizu 2 */
|
||||||
|
0x04a31647de80fdabLL, /* Legend of Zelda */
|
||||||
|
0x94b9484862a26cbaLL, /* Legend of Zelda */
|
||||||
|
0xa40666740b7d22feLL, /* Mindseeker */
|
||||||
|
0x82000965f04a71bbLL, /* Mirai Shinwa Jarvas */
|
||||||
|
0x77b811b2760104b9LL, /* Mouryou Senki Madara */
|
||||||
|
0x11b69122efe86e8cLL, /* RPG Jinsei Game */
|
||||||
|
0x9aa1dc16c05e7de5LL, /* Startropics */
|
||||||
|
0x1b084107d0878bd0LL, /* Startropics 2*/
|
||||||
|
0xa70b495314f4d075LL, /* Ys 3 */
|
||||||
|
0x836c0ff4f3e06e45LL, /* Zelda 2 */
|
||||||
|
0 /* Abandon all hope if the game has 0 in the lower 64-bits of its MD5 hash */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct CHINF moo[] =
|
||||||
|
{
|
||||||
|
#include "ines-correct.h"
|
||||||
|
};
|
||||||
|
int32 tofix = 0, x;
|
||||||
|
uint64 partialmd5 = 0;
|
||||||
|
|
||||||
|
for (x = 0; x < 8; x++)
|
||||||
|
partialmd5 |= (uint64)iNESCart.MD5[15 - x] << (x * 8);
|
||||||
|
CheckBad(partialmd5);
|
||||||
|
|
||||||
|
x = 0;
|
||||||
|
do {
|
||||||
|
if (moo[x].crc32 == iNESGameCRC32) {
|
||||||
|
if (moo[x].mapper >= 0) {
|
||||||
|
if (moo[x].mapper & 0x800 && VROM_size) {
|
||||||
|
VROM_size = 0;
|
||||||
|
free(VROM);
|
||||||
|
VROM = NULL;
|
||||||
|
tofix |= 8;
|
||||||
|
}
|
||||||
|
if (MapperNo != (moo[x].mapper & 0xFF)) {
|
||||||
|
tofix |= 1;
|
||||||
|
MapperNo = moo[x].mapper & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (moo[x].mirror >= 0) {
|
||||||
|
if (moo[x].mirror == 8) {
|
||||||
|
if (Mirroring == 2) { /* Anything but hard-wired(four screen). */
|
||||||
|
tofix |= 2;
|
||||||
|
Mirroring = 0;
|
||||||
|
}
|
||||||
|
} else if (Mirroring != moo[x].mirror) {
|
||||||
|
if (Mirroring != (moo[x].mirror & ~4))
|
||||||
|
if ((moo[x].mirror & ~4) <= 2) /* Don't complain if one-screen mirroring
|
||||||
|
needs to be set(the iNES header can't
|
||||||
|
hold this information).
|
||||||
|
*/
|
||||||
|
tofix |= 2;
|
||||||
|
Mirroring = moo[x].mirror;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
x++;
|
||||||
|
} while (moo[x].mirror >= 0 || moo[x].mapper >= 0);
|
||||||
|
|
||||||
|
x = 0;
|
||||||
|
while (savie[x] != 0) {
|
||||||
|
if (savie[x] == partialmd5) {
|
||||||
|
if (!(head.ROM_type & 2)) {
|
||||||
|
tofix |= 4;
|
||||||
|
head.ROM_type |= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Games that use these iNES mappers tend to have the four-screen bit set
|
||||||
|
when it should not be.
|
||||||
|
*/
|
||||||
|
if ((MapperNo == 118 || MapperNo == 24 || MapperNo == 26) && (Mirroring == 2)) {
|
||||||
|
Mirroring = 0;
|
||||||
|
tofix |= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Four-screen mirroring implicitly set. */
|
||||||
|
if (MapperNo == 99)
|
||||||
|
Mirroring = 2;
|
||||||
|
|
||||||
|
if (tofix) {
|
||||||
|
char gigastr[768];
|
||||||
|
strcpy(gigastr, "The iNES header contains incorrect information. For now, the information will be corrected in RAM. ");
|
||||||
|
if (tofix & 1)
|
||||||
|
sprintf(gigastr + strlen(gigastr), "The mapper number should be set to %d. ", MapperNo);
|
||||||
|
if (tofix & 2) {
|
||||||
|
uint8 *mstr[3] = { "Horizontal", "Vertical", "Four-screen" };
|
||||||
|
sprintf(gigastr + strlen(gigastr), "Mirroring should be set to \"%s\". ", mstr[Mirroring & 3]);
|
||||||
|
}
|
||||||
|
if (tofix & 4)
|
||||||
|
strcat(gigastr, "The battery-backed bit should be set. ");
|
||||||
|
if (tofix & 8)
|
||||||
|
strcat(gigastr, "This game should not have any CHR ROM. ");
|
||||||
|
strcat(gigastr, "\n");
|
||||||
|
FCEU_printf("%s", gigastr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32 mapper;
|
||||||
|
void (*init)(CartInfo *);
|
||||||
|
} NewMI;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8 *name;
|
||||||
|
int32 number;
|
||||||
|
void (*init)(CartInfo *);
|
||||||
|
} BMAPPINGLocal;
|
||||||
|
|
||||||
|
static BMAPPINGLocal bmap[] = {
|
||||||
|
{"NROM", 0, NROM_Init},
|
||||||
|
{"MMC1", 1, Mapper1_Init},
|
||||||
|
{"UNROM", 2, UNROM_Init},
|
||||||
|
{"CNROM", 3, CNROM_Init},
|
||||||
|
{"MMC3", 4, Mapper4_Init},
|
||||||
|
{"MMC5", 5, Mapper5_Init},
|
||||||
|
{"FFE Rev. A", 6, Mapper6_Init},
|
||||||
|
{"ANROM", 7, ANROM_Init},
|
||||||
|
{"", 8, Mapper8_Init}, // Nogaems, it's worthless
|
||||||
|
{"MMC2", 9, Mapper9_Init},
|
||||||
|
{"MMC4", 10, Mapper10_Init},
|
||||||
|
{"Color Dreams", 11, Mapper11_Init},
|
||||||
|
{"REX DBZ 5", 12, Mapper12_Init},
|
||||||
|
{"CPROM", 13, CPROM_Init},
|
||||||
|
{"REX SL-1632", 14, UNLSL1632_Init},
|
||||||
|
{"100-in-1", 15, Mapper15_Init},
|
||||||
|
{"BANDAI 24C02", 16, Mapper16_Init},
|
||||||
|
{"FFE Rev. B", 17, Mapper17_Init},
|
||||||
|
{"JALECO SS880006", 18, Mapper18_Init}, // JF-NNX (EB89018-30007) boards
|
||||||
|
{"Namcot 106", 19, Mapper19_Init},
|
||||||
|
// {"", 20, Mapper20_Init},
|
||||||
|
{"Konami VRC2/VRC4 A", 21, Mapper21_Init},
|
||||||
|
{"Konami VRC2/VRC4 B", 22, Mapper22_Init},
|
||||||
|
{"Konami VRC2/VRC4 C", 23, Mapper23_Init},
|
||||||
|
{"Konami VRC6 Rev. A", 24, Mapper24_Init},
|
||||||
|
{"Konami VRC2/VRC4 D", 25, Mapper25_Init},
|
||||||
|
{"Konami VRC6 Rev. B", 26, Mapper26_Init},
|
||||||
|
{"CC-21 MI HUN CHE", 27, UNLCC21_Init}, // Former dupe for VRC2/VRC4 mapper, redefined with crc to mihunche boards
|
||||||
|
// {"", 28, Mapper28_Init}, // Custom Multidiscrete mapper for PDs
|
||||||
|
// {"", 29, Mapper29_Init},
|
||||||
|
// {"", 30, Mapper30_Init},
|
||||||
|
// {"", 31, Mapper31_Init},
|
||||||
|
{"IREM G-101", 32, Mapper32_Init},
|
||||||
|
{"TC0190FMC/TC0350FMR", 33, Mapper33_Init},
|
||||||
|
{"IREM I-IM/BNROM", 34, Mapper34_Init},
|
||||||
|
{"Wario Land 2", 35, UNLSC127_Init},
|
||||||
|
{"TXC Policeman", 36, Mapper36_Init},
|
||||||
|
{"PAL-ZZ SMB/TETRIS/NWC",37, Mapper37_Init},
|
||||||
|
{"Bit Corp.", 38, Mapper38_Init}, // Crime Busters
|
||||||
|
// {"", 39, Mapper39_Init},
|
||||||
|
{"SMB2j FDS", 40, Mapper40_Init},
|
||||||
|
{"CALTRON 6-in-1", 41, Mapper41_Init},
|
||||||
|
{"BIO MIRACLE FDS", 42, Mapper42_Init},
|
||||||
|
{"FDS SMB2j LF36", 43, Mapper43_Init},
|
||||||
|
{"MMC3 BMC PIRATE A", 44, Mapper44_Init},
|
||||||
|
{"MMC3 BMC PIRATE B", 45, Mapper45_Init},
|
||||||
|
{"RUMBLESTATION 15-in-1",46, Mapper46_Init},
|
||||||
|
{"NES-QJ SSVB/NWC", 47, Mapper47_Init},
|
||||||
|
{"TAITO TCxxx", 48, Mapper48_Init},
|
||||||
|
{"MMC3 BMC PIRATE C", 49, Mapper49_Init},
|
||||||
|
{"SMB2j FDS Rev. A", 50, Mapper50_Init},
|
||||||
|
{"11-in-1 BALL SERIES", 51, Mapper51_Init}, // 1993 year version
|
||||||
|
{"MMC3 BMC PIRATE D", 52, Mapper52_Init},
|
||||||
|
{"SUPERVISION 16-in-1", 53, Supervision16_Init},
|
||||||
|
// {"", 54, Mapper54_Init},
|
||||||
|
// {"", 55, Mapper55_Init},
|
||||||
|
// {"", 56, Mapper56_Init},
|
||||||
|
{"SIMBPLE BMC PIRATE A", 57, Mapper57_Init},
|
||||||
|
{"SIMBPLE BMC PIRATE B", 58, BMCGK192_Init},
|
||||||
|
{"", 59, Mapper59_Init}, // Check this out
|
||||||
|
{"SIMBPLE BMC PIRATE C", 60, BMCD1038_Init},
|
||||||
|
{"20-in-1 KAISER Rev. A",61, Mapper61_Init},
|
||||||
|
{"700-in-1", 62, Mapper62_Init},
|
||||||
|
// {"", 63, Mapper63_Init},
|
||||||
|
{"TENGEN RAMBO1", 64, Mapper64_Init},
|
||||||
|
{"IREM-H3001", 65, Mapper65_Init},
|
||||||
|
{"MHROM", 66, MHROM_Init},
|
||||||
|
{"SUNSOFT-FZII", 67, Mapper67_Init},
|
||||||
|
{"Sunsoft Mapper #4", 68, Mapper68_Init},
|
||||||
|
{"SUNSOFT-5/FME-7", 69, Mapper69_Init},
|
||||||
|
{"BA KAMEN DISCRETE", 70, Mapper70_Init},
|
||||||
|
{"CAMERICA BF9093", 71, Mapper71_Init},
|
||||||
|
{"JALECO JF-17", 72, Mapper72_Init},
|
||||||
|
{"KONAMI VRC3", 73, Mapper73_Init},
|
||||||
|
{"TW MMC3+VRAM Rev. A", 74, Mapper74_Init},
|
||||||
|
{"KONAMI VRC1", 75, Mapper75_Init},
|
||||||
|
{"NAMCOT 108 Rev. A", 76, Mapper76_Init},
|
||||||
|
{"IREM LROG017", 77, Mapper77_Init},
|
||||||
|
{"Irem 74HC161/32", 78, Mapper78_Init},
|
||||||
|
{"AVE/C&E/TXC BOARD", 79, Mapper79_Init},
|
||||||
|
{"TAITO X1-005 Rev. A", 80, Mapper80_Init},
|
||||||
|
// {"", 81, Mapper81_Init},
|
||||||
|
{"TAITO X1-017", 82, Mapper82_Init},
|
||||||
|
{"YOKO VRC Rev. B", 83, Mapper83_Init},
|
||||||
|
// {"", 84, Mapper84_Init},
|
||||||
|
{"KONAMI VRC7", 85, Mapper85_Init},
|
||||||
|
{"JALECO JF-13", 86, Mapper86_Init},
|
||||||
|
{"74*139/74 DISCRETE", 87, Mapper87_Init},
|
||||||
|
{"NAMCO 3433", 88, Mapper88_Init},
|
||||||
|
{"SUNSOFT-3", 89, Mapper89_Init}, // SUNSOFT-2 mapper
|
||||||
|
{"HUMMER/JY BOARD", 90, Mapper90_Init},
|
||||||
|
{"EARLY HUMMER/JY BOARD",91, Mapper91_Init},
|
||||||
|
{"JALECO JF-19", 92, Mapper92_Init},
|
||||||
|
{"SUNSOFT-3R", 93, SUNSOFT_UNROM_Init},// SUNSOFT-2 mapper with VRAM, different wiring
|
||||||
|
{"HVC-UN1ROM", 94, Mapper94_Init},
|
||||||
|
{"NAMCOT 108 Rev. B", 95, Mapper95_Init},
|
||||||
|
{"BANDAI OEKAKIDS", 96, Mapper96_Init},
|
||||||
|
{"IREM TAM-S1", 97, Mapper97_Init},
|
||||||
|
// {"", 98, Mapper98_Init},
|
||||||
|
{"VS Uni/Dual- system", 99, Mapper99_Init},
|
||||||
|
// {"", 100, Mapper100_Init},
|
||||||
|
{"", 101, Mapper101_Init},
|
||||||
|
// {"", 102, Mapper102_Init},
|
||||||
|
{"FDS DOKIDOKI FULL", 103, Mapper103_Init},
|
||||||
|
// {"", 104, Mapper104_Init},
|
||||||
|
{"NES-EVENT NWC1990", 105, Mapper105_Init},
|
||||||
|
{"SMB3 PIRATE A", 106, Mapper106_Init},
|
||||||
|
{"MAGIC CORP A", 107, Mapper107_Init},
|
||||||
|
{"FDS UNROM BOARD", 108, Mapper108_Init},
|
||||||
|
// {"", 109, Mapper109_Init},
|
||||||
|
// {"", 110, Mapper110_Init},
|
||||||
|
// {"", 111, Mapper111_Init},
|
||||||
|
{"ASDER/NTDEC BOARD", 112, Mapper112_Init},
|
||||||
|
{"HACKER/SACHEN BOARD", 113, Mapper113_Init},
|
||||||
|
{"MMC3 SG PROT. A", 114, Mapper114_Init},
|
||||||
|
{"MMC3 PIRATE A", 115, Mapper115_Init},
|
||||||
|
{"MMC1/MMC3/VRC PIRATE",116, UNLSL12_Init},
|
||||||
|
{"FUTURE MEDIA BOARD", 117, Mapper117_Init},
|
||||||
|
{"TSKROM", 118, TKSROM_Init},
|
||||||
|
{"NES-TQROM", 119, Mapper119_Init},
|
||||||
|
{"FDS TOBIDASE", 120, Mapper120_Init},
|
||||||
|
{"MMC3 PIRATE PROT. A", 121, Mapper121_Init},
|
||||||
|
// {"", 122, Mapper122_Init},
|
||||||
|
{"MMC3 PIRATE H2288", 123, UNLH2288_Init},
|
||||||
|
// {"", 124, Mapper124_Init},
|
||||||
|
{"FDS LH32", 125, LH32_Init},
|
||||||
|
// {"", 126, Mapper126_Init},
|
||||||
|
// {"", 127, Mapper127_Init},
|
||||||
|
// {"", 128, Mapper128_Init},
|
||||||
|
// {"", 129, Mapper129_Init},
|
||||||
|
// {"", 130, Mapper130_Init},
|
||||||
|
// {"", 131, Mapper131_Init},
|
||||||
|
{"TXC/MGENIUS 22111", 132, UNL22211_Init},
|
||||||
|
{"SA72008", 133, SA72008_Init},
|
||||||
|
{"MMC3 BMC PIRATE", 134, Mapper134_Init},
|
||||||
|
// {"", 135, Mapper135_Init},
|
||||||
|
{"TCU02", 136, TCU02_Init},
|
||||||
|
{"S8259D", 137, S8259D_Init},
|
||||||
|
{"S8259B", 138, S8259B_Init},
|
||||||
|
{"S8259C", 139, S8259C_Init},
|
||||||
|
{"JALECO JF-11/14", 140, Mapper140_Init},
|
||||||
|
{"S8259A", 141, S8259A_Init},
|
||||||
|
{"UNLKS7032", 142, UNLKS7032_Init},
|
||||||
|
{"TCA01", 143, TCA01_Init},
|
||||||
|
{"AGCI 50282", 144, Mapper144_Init},
|
||||||
|
{"SA72007", 145, SA72007_Init},
|
||||||
|
{"SA0161M", 146, SA0161M_Init},
|
||||||
|
{"TCU01", 147, TCU01_Init},
|
||||||
|
{"SA0037", 148, SA0037_Init},
|
||||||
|
{"SA0036", 149, SA0036_Init},
|
||||||
|
{"S74LS374N", 150, S74LS374N_Init},
|
||||||
|
{"", 151, Mapper151_Init},
|
||||||
|
{"", 152, Mapper152_Init},
|
||||||
|
{"BANDAI SRAM", 153, Mapper153_Init}, // Bandai board 16 with SRAM instead of EEPROM
|
||||||
|
{"", 154, Mapper154_Init},
|
||||||
|
{"", 155, Mapper155_Init},
|
||||||
|
{"", 156, Mapper156_Init},
|
||||||
|
{"BANDAI BARCODE", 157, Mapper157_Init},
|
||||||
|
// {"", 158, Mapper158_Init},
|
||||||
|
{"BANDAI 24C01", 159, Mapper159_Init}, // Different type of EEPROM on the bandai board
|
||||||
|
{"SA009", 160, SA009_Init},
|
||||||
|
// {"", 161, Mapper161_Init},
|
||||||
|
{"", 162, UNLFS304_Init},
|
||||||
|
{"", 163, Mapper163_Init},
|
||||||
|
{"", 164, Mapper164_Init},
|
||||||
|
{"", 165, Mapper165_Init},
|
||||||
|
{"SUBOR Rev. A", 166, Mapper166_Init},
|
||||||
|
{"SUBOR Rev. B", 167, Mapper167_Init},
|
||||||
|
{"", 168, Mapper168_Init},
|
||||||
|
// {"", 169, Mapper169_Init},
|
||||||
|
{"", 170, Mapper170_Init},
|
||||||
|
{"", 171, Mapper171_Init},
|
||||||
|
{"", 172, Mapper172_Init},
|
||||||
|
{"", 173, Mapper173_Init},
|
||||||
|
// {"", 174, Mapper174_Init},
|
||||||
|
{"", 175, Mapper175_Init},
|
||||||
|
{"BMCFK23C", 176, BMCFK23C_Init}, // zero 26-may-2012 - well, i have some WXN junk games that use 176 for instance ????. i dont know what game uses this BMCFK23C as mapper 176. we'll have to make a note when we find it.
|
||||||
|
{"", 177, Mapper177_Init},
|
||||||
|
{"", 178, Mapper178_Init},
|
||||||
|
// {"", 179, Mapper179_Init},
|
||||||
|
{"", 180, Mapper180_Init},
|
||||||
|
{"", 181, Mapper181_Init},
|
||||||
|
// {"", 182, Mapper182_Init}, // Deprecated, dupe
|
||||||
|
{"", 183, Mapper183_Init},
|
||||||
|
{"", 184, Mapper184_Init},
|
||||||
|
{"", 185, Mapper185_Init},
|
||||||
|
{"", 186, Mapper186_Init},
|
||||||
|
{"", 187, Mapper187_Init},
|
||||||
|
{"", 188, Mapper188_Init},
|
||||||
|
{"", 189, Mapper189_Init},
|
||||||
|
// {"", 190, Mapper190_Init},
|
||||||
|
{"", 191, Mapper191_Init},
|
||||||
|
{"TW MMC3+VRAM Rev. B", 192, Mapper192_Init},
|
||||||
|
{"NTDEC TC-112", 193, Mapper193_Init}, // War in the Gulf
|
||||||
|
{"TW MMC3+VRAM Rev. C", 194, Mapper194_Init},
|
||||||
|
{"TW MMC3+VRAM Rev. D", 195, Mapper195_Init},
|
||||||
|
{"", 196, Mapper196_Init},
|
||||||
|
{"", 197, Mapper197_Init},
|
||||||
|
{"TW MMC3+VRAM Rev. E", 198, Mapper198_Init},
|
||||||
|
{"", 199, Mapper199_Init},
|
||||||
|
{"", 200, Mapper200_Init},
|
||||||
|
{"", 201, Mapper201_Init},
|
||||||
|
{"", 202, Mapper202_Init},
|
||||||
|
{"", 203, Mapper203_Init},
|
||||||
|
{"", 204, Mapper204_Init},
|
||||||
|
{"", 205, Mapper205_Init},
|
||||||
|
{"NAMCOT 108 Rev. C", 206, Mapper206_Init}, // Deprecated, Used to be "DEIROM" whatever it means, but actually simple version of MMC3
|
||||||
|
{"TAITO X1-005 Rev. B", 207, Mapper207_Init},
|
||||||
|
{"", 208, Mapper208_Init},
|
||||||
|
{"", 209, Mapper209_Init},
|
||||||
|
{"", 210, Mapper210_Init},
|
||||||
|
{"", 211, Mapper211_Init},
|
||||||
|
{"", 212, Mapper212_Init},
|
||||||
|
{"", 213, Mapper213_Init},
|
||||||
|
{"", 214, Mapper214_Init},
|
||||||
|
{"", 215, UNL8237_Init},
|
||||||
|
{"", 216, Mapper216_Init},
|
||||||
|
{"", 217, Mapper217_Init}, // Redefined to a new Discrete BMC mapper
|
||||||
|
// {"", 218, Mapper218_Init},
|
||||||
|
{"UNLA9746", 219, UNLA9746_Init},
|
||||||
|
{"Debug Mapper", 220, UNLPEC586Init}, // UNLKS7057_Init},
|
||||||
|
{"UNLN625092", 221, UNLN625092_Init},
|
||||||
|
{"", 222, Mapper222_Init},
|
||||||
|
// {"", 223, Mapper223_Init},
|
||||||
|
// {"", 224, Mapper224_Init},
|
||||||
|
{"", 225, Mapper225_Init},
|
||||||
|
{"BMC 22+20-in-1", 226, Mapper226_Init},
|
||||||
|
{"", 227, Mapper227_Init},
|
||||||
|
{"", 228, Mapper228_Init},
|
||||||
|
{"", 229, Mapper229_Init},
|
||||||
|
{"BMC Contra+22-in-1", 230, Mapper230_Init},
|
||||||
|
{"", 231, Mapper231_Init},
|
||||||
|
{"BMC QUATTRO", 232, Mapper232_Init},
|
||||||
|
{"BMC 22+20-in-1 RST", 233, Mapper233_Init},
|
||||||
|
{"BMC MAXI", 234, Mapper234_Init},
|
||||||
|
{"", 235, Mapper235_Init},
|
||||||
|
// {"", 236, Mapper236_Init},
|
||||||
|
// {"", 237, Mapper237_Init},
|
||||||
|
{"UNL6035052", 238, UNL6035052_Init},
|
||||||
|
// {"", 239, Mapper239_Init},
|
||||||
|
{"", 240, Mapper240_Init},
|
||||||
|
{"", 241, Mapper241_Init},
|
||||||
|
{"", 242, Mapper242_Init},
|
||||||
|
{"S74LS374NA", 243, S74LS374NA_Init},
|
||||||
|
{"DECATHLON", 244, Mapper244_Init},
|
||||||
|
{"", 245, Mapper245_Init},
|
||||||
|
{"FONG SHEN BANG", 246, Mapper246_Init},
|
||||||
|
// {"", 247, Mapper247_Init},
|
||||||
|
// {"", 248, Mapper248_Init},
|
||||||
|
{"", 249, Mapper249_Init},
|
||||||
|
{"", 250, Mapper250_Init},
|
||||||
|
// {"", 251, Mapper251_Init}, // No good dumps for this mapper, use UNIF version
|
||||||
|
{"SAN GUO ZHI PIRATE", 252, Mapper252_Init},
|
||||||
|
{"DRAGON BALL PIRATE", 253, Mapper253_Init},
|
||||||
|
{"", 254, Mapper254_Init},
|
||||||
|
// {"", 255, Mapper255_Init}, // No good dumps for this mapper
|
||||||
|
{"", 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
int iNESLoad(const char *name, FCEUFILE *fp) {
|
||||||
|
struct md5_context md5;
|
||||||
|
char* mappername;
|
||||||
|
uint32 mappertest;
|
||||||
|
|
||||||
|
if (FCEU_fread(&head, 1, 16, fp) != 16)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (memcmp(&head, "NES\x1a", 4))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memset(&iNESCart, 0, sizeof(iNESCart));
|
||||||
|
|
||||||
|
if (!memcmp((char*)(&head) + 0x7, "DiskDude", 8)) {
|
||||||
|
memset((char*)(&head) + 0x7, 0, 0x9);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp((char*)(&head) + 0x7, "demiforce", 9)) {
|
||||||
|
memset((char*)(&head) + 0x7, 0, 0x9);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp((char*)(&head) + 0xA, "Ni03", 4)) {
|
||||||
|
if (!memcmp((char*)(&head) + 0x7, "Dis", 3))
|
||||||
|
memset((char*)(&head) + 0x7, 0, 0x9);
|
||||||
|
else
|
||||||
|
memset((char*)(&head) + 0xA, 0, 0x6);
|
||||||
|
}
|
||||||
|
|
||||||
|
MapperNo = (head.ROM_type >> 4);
|
||||||
|
MapperNo |= (head.ROM_type2 & 0xF0);
|
||||||
|
if (head.ROM_type & 8) {
|
||||||
|
Mirroring = 2;
|
||||||
|
} else
|
||||||
|
Mirroring = (head.ROM_type & 1);
|
||||||
|
|
||||||
|
if (!head.ROM_size)
|
||||||
|
ROM_size = 256;
|
||||||
|
else
|
||||||
|
ROM_size = uppow2(head.ROM_size);
|
||||||
|
|
||||||
|
VROM_size = uppow2(head.VROM_size);
|
||||||
|
|
||||||
|
|
||||||
|
if ((ROM = (uint8*)FCEU_malloc(ROM_size << 14)) == NULL)
|
||||||
|
return 0;
|
||||||
|
memset(ROM, 0xFF, ROM_size << 14);
|
||||||
|
|
||||||
|
if (VROM_size) {
|
||||||
|
if ((VROM = (uint8*)FCEU_malloc(VROM_size << 13)) == NULL) {
|
||||||
|
free(ROM);
|
||||||
|
ROM = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memset(VROM, 0xFF, VROM_size << 13);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (head.ROM_type & 4) { /* Trainer */
|
||||||
|
trainerpoo = (uint8*)FCEU_gmalloc(512);
|
||||||
|
FCEU_fread(trainerpoo, 512, 1, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResetCartMapping();
|
||||||
|
ResetExState(0, 0);
|
||||||
|
|
||||||
|
SetupCartPRGMapping(0, ROM, ROM_size << 14, 0);
|
||||||
|
|
||||||
|
if (head.ROM_size)
|
||||||
|
FCEU_fread(ROM, 0x4000, head.ROM_size, fp);
|
||||||
|
else
|
||||||
|
FCEU_fread(ROM, 0x4000, ROM_size, fp);
|
||||||
|
|
||||||
|
if (VROM_size)
|
||||||
|
FCEU_fread(VROM, 0x2000, VROM_size, fp);
|
||||||
|
|
||||||
|
md5_starts(&md5);
|
||||||
|
md5_update(&md5, ROM, ROM_size << 14);
|
||||||
|
|
||||||
|
iNESGameCRC32 = CalcCRC32(0, ROM, ROM_size << 14);
|
||||||
|
|
||||||
|
if (VROM_size) {
|
||||||
|
iNESGameCRC32 = CalcCRC32(iNESGameCRC32, VROM, VROM_size << 13);
|
||||||
|
md5_update(&md5, VROM, VROM_size << 13);
|
||||||
|
}
|
||||||
|
md5_finish(&md5, iNESCart.MD5);
|
||||||
|
memcpy(&GameInfo->MD5, &iNESCart.MD5, sizeof(iNESCart.MD5));
|
||||||
|
|
||||||
|
iNESCart.CRC32 = iNESGameCRC32;
|
||||||
|
|
||||||
|
FCEU_printf(" PRG ROM: %3d x 16KiB\n", ROM_size);
|
||||||
|
FCEU_printf(" CHR ROM: %3d x 8KiB\n", head.VROM_size);
|
||||||
|
FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32);
|
||||||
|
FCEU_printf(" ROM MD5: 0x%s\n", md5_asciistr(iNESCart.MD5));
|
||||||
|
mappername = "Not Listed";
|
||||||
|
|
||||||
|
for (mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) {
|
||||||
|
if (bmap[mappertest].number == MapperNo) {
|
||||||
|
mappername = bmap[mappertest].name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FCEU_printf(" Mapper #: %d\n", MapperNo);
|
||||||
|
FCEU_printf(" Mapper name: %s\n", mappername);
|
||||||
|
FCEU_printf(" Mirroring: %s\n", Mirroring == 2 ? "None (Four-screen)" : Mirroring ? "Vertical" : "Horizontal");
|
||||||
|
FCEU_printf(" Battery-backed: %s\n", (head.ROM_type & 2) ? "Yes" : "No");
|
||||||
|
FCEU_printf(" Trained: %s\n", (head.ROM_type & 4) ? "Yes" : "No");
|
||||||
|
|
||||||
|
SetInput();
|
||||||
|
CheckHInfo();
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
uint64 partialmd5 = 0;
|
||||||
|
|
||||||
|
for (x = 0; x < 8; x++) {
|
||||||
|
partialmd5 |= (uint64)iNESCart.MD5[7 - x] << (x * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
FCEU_VSUniCheck(partialmd5, &MapperNo, &Mirroring);
|
||||||
|
}
|
||||||
|
/* Must remain here because above functions might change value of
|
||||||
|
VROM_size and free(VROM).
|
||||||
|
*/
|
||||||
|
if (VROM_size)
|
||||||
|
SetupCartCHRMapping(0, VROM, VROM_size * 0x2000, 0);
|
||||||
|
|
||||||
|
if (Mirroring == 2) {
|
||||||
|
ExtraNTARAM = (uint8*)FCEU_gmalloc(2048);
|
||||||
|
SetupCartMirroring(4, 1, ExtraNTARAM);
|
||||||
|
} else if (Mirroring >= 0x10)
|
||||||
|
SetupCartMirroring(2 + (Mirroring & 1), 1, 0);
|
||||||
|
else
|
||||||
|
SetupCartMirroring(Mirroring & 1, (Mirroring & 4) >> 2, 0);
|
||||||
|
|
||||||
|
iNESCart.battery = (head.ROM_type & 2) ? 1 : 0;
|
||||||
|
iNESCart.mirror = Mirroring;
|
||||||
|
|
||||||
|
if (!iNES_Init(MapperNo))
|
||||||
|
FCEU_PrintError("iNES mapper #%d is not supported at all.", MapperNo);
|
||||||
|
|
||||||
|
FCEU_LoadGameSave(&iNESCart);
|
||||||
|
|
||||||
|
GameInterface = iNESGI;
|
||||||
|
FCEU_printf("\n");
|
||||||
|
|
||||||
|
if (strstr(name, "(E)") || strstr(name, "(e)")
|
||||||
|
|| strstr(name, "(Europe)") || strstr(name, "(PAL)")
|
||||||
|
|| strstr(name, "(F)") || strstr(name, "(f)")
|
||||||
|
|| strstr(name, "(G)") || strstr(name, "(g)")
|
||||||
|
|| strstr(name, "(I)") || strstr(name, "(i)"))
|
||||||
|
GameInfo->vidsys = GIV_PAL;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iNES_Init(int num) {
|
||||||
|
BMAPPINGLocal *tmp = bmap;
|
||||||
|
|
||||||
|
CHRRAMSize = -1;
|
||||||
|
|
||||||
|
if (GameInfo->type == GIT_VSUNI)
|
||||||
|
AddExState(FCEUVSUNI_STATEINFO, ~0, 0, 0);
|
||||||
|
|
||||||
|
while (tmp->init) {
|
||||||
|
if (num == tmp->number) {
|
||||||
|
UNIFchrrama = 0; // need here for compatibility with UNIF mapper code
|
||||||
|
if (!VROM_size) {
|
||||||
|
switch (num) { // FIXME, mapper or game data base with the board parameters and ROM/RAM sizes
|
||||||
|
case 13: CHRRAMSize = 16 * 1024; break;
|
||||||
|
case 6:
|
||||||
|
case 96: CHRRAMSize = 32 * 1024; break;
|
||||||
|
case 176: CHRRAMSize = 256 * 1024; break;
|
||||||
|
default: CHRRAMSize = 8 * 1024; break;
|
||||||
|
}
|
||||||
|
if ((VROM = (uint8*)malloc(CHRRAMSize)) == NULL) return 0;
|
||||||
|
UNIFchrrama = VROM;
|
||||||
|
SetupCartCHRMapping(0, VROM, CHRRAMSize, 1);
|
||||||
|
AddExState(VROM, CHRRAMSize, 0, "CHRR");
|
||||||
|
}
|
||||||
|
if (head.ROM_type & 8)
|
||||||
|
AddExState(ExtraNTARAM, 2048, 0, "EXNR");
|
||||||
|
tmp->init(&iNESCart);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
tmp++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
378
src/drivers/libretro/fceu/input.c
Normal file
378
src/drivers/libretro/fceu/input.c
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
/* FCE Ultra - NES/Famicom Emulator
|
||||||
|
*
|
||||||
|
* Copyright notice for this file:
|
||||||
|
* Copyright (C) 1998 BERO
|
||||||
|
* Copyright (C) 2002 Xodnizel
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "fceu-types.h"
|
||||||
|
#include "x6502.h"
|
||||||
|
|
||||||
|
#include "fceu.h"
|
||||||
|
#include "netplay.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "vsuni.h"
|
||||||
|
#include "fds.h"
|
||||||
|
|
||||||
|
extern INPUTC *FCEU_InitJoyPad(int w);
|
||||||
|
extern INPUTC *FCEU_InitZapper(int w);
|
||||||
|
extern INPUTC *FCEU_InitMouse(int w);
|
||||||
|
extern INPUTC *FCEU_InitPowerpadA(int w);
|
||||||
|
extern INPUTC *FCEU_InitPowerpadB(int w);
|
||||||
|
extern INPUTC *FCEU_InitArkanoid(int w);
|
||||||
|
|
||||||
|
extern INPUTCFC *FCEU_InitFami4(void);
|
||||||
|
extern INPUTCFC *FCEU_InitArkanoidFC(void);
|
||||||
|
extern INPUTCFC *FCEU_InitSpaceShadow(void);
|
||||||
|
extern INPUTCFC *FCEU_InitFKB(void);
|
||||||
|
extern INPUTCFC *FCEU_InitSuborKB(void);
|
||||||
|
extern INPUTCFC *FCEU_InitPEC586KB(void);
|
||||||
|
extern INPUTCFC *FCEU_InitHS(void);
|
||||||
|
extern INPUTCFC *FCEU_InitMahjong(void);
|
||||||
|
extern INPUTCFC *FCEU_InitQuizKing(void);
|
||||||
|
extern INPUTCFC *FCEU_InitFamilyTrainerA(void);
|
||||||
|
extern INPUTCFC *FCEU_InitFamilyTrainerB(void);
|
||||||
|
extern INPUTCFC *FCEU_InitOekaKids(void);
|
||||||
|
extern INPUTCFC *FCEU_InitTopRider(void);
|
||||||
|
extern INPUTCFC *FCEU_InitBarcodeWorld(void);
|
||||||
|
|
||||||
|
extern uint8 coinon;
|
||||||
|
|
||||||
|
static void *InputDataPtr[2];
|
||||||
|
uint8 LastStrobe;
|
||||||
|
|
||||||
|
static int JPAttrib[2] = { 0, 0 };
|
||||||
|
static int JPType[2] = { 0, 0 };
|
||||||
|
static INPUTC DummyJPort = { 0, 0, 0, 0, 0 };
|
||||||
|
static INPUTC *JPorts[2] = { &DummyJPort, &DummyJPort };
|
||||||
|
|
||||||
|
static int JPAttribFC = 0;
|
||||||
|
static int JPTypeFC = 0;
|
||||||
|
static void *InputDataPtrFC;
|
||||||
|
static INPUTCFC *FCExp = 0;
|
||||||
|
|
||||||
|
void (*InputScanlineHook)(uint8 *bg, uint8 *spr, uint32 linets, int final);
|
||||||
|
|
||||||
|
static DECLFR(JPRead)
|
||||||
|
{
|
||||||
|
uint8 ret = 0;
|
||||||
|
|
||||||
|
if (JPorts[A & 1]->Read)
|
||||||
|
ret |= JPorts[A & 1]->Read(A & 1);
|
||||||
|
|
||||||
|
if (FCExp)
|
||||||
|
if (FCExp->Read)
|
||||||
|
ret = FCExp->Read(A & 1, ret);
|
||||||
|
|
||||||
|
ret |= X.DB & 0xC0;
|
||||||
|
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFW(B4016)
|
||||||
|
{
|
||||||
|
if (FCExp)
|
||||||
|
if (FCExp->Write)
|
||||||
|
FCExp->Write(V & 7);
|
||||||
|
|
||||||
|
if (JPorts[0]->Write)
|
||||||
|
JPorts[0]->Write(V & 1);
|
||||||
|
if (JPorts[1]->Write)
|
||||||
|
JPorts[1]->Write(V & 1);
|
||||||
|
|
||||||
|
if ((LastStrobe & 1) && (!(V & 1)))
|
||||||
|
{
|
||||||
|
if (JPorts[0]->Strobe)
|
||||||
|
JPorts[0]->Strobe(0);
|
||||||
|
if (JPorts[1]->Strobe)
|
||||||
|
JPorts[1]->Strobe(1);
|
||||||
|
if (FCExp)
|
||||||
|
if (FCExp->Strobe)
|
||||||
|
FCExp->Strobe();
|
||||||
|
}
|
||||||
|
LastStrobe = V & 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_DrawInput(uint8 *buf)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
for (x = 0; x < 2; x++)
|
||||||
|
if (JPorts[x]->Draw)
|
||||||
|
JPorts[x]->Draw(x, buf, JPAttrib[x]);
|
||||||
|
if (FCExp)
|
||||||
|
if (FCExp->Draw)
|
||||||
|
FCExp->Draw(buf, JPAttribFC);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_UpdateInput(void)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
|
||||||
|
for (x = 0; x < 2; x++)
|
||||||
|
{
|
||||||
|
if (JPorts[x] && JPorts[x]->Update)
|
||||||
|
JPorts[x]->Update(x, InputDataPtr[x], JPAttrib[x]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FCExp && FCExp->Update)
|
||||||
|
FCExp->Update(InputDataPtrFC, JPAttribFC);
|
||||||
|
|
||||||
|
if (GameInfo && GameInfo->type == GIT_VSUNI)
|
||||||
|
if (coinon) coinon--;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFR(VSUNIRead0)
|
||||||
|
{
|
||||||
|
uint8 ret = 0;
|
||||||
|
|
||||||
|
if (JPorts[0]->Read)
|
||||||
|
ret |= (JPorts[0]->Read(0)) & 1;
|
||||||
|
|
||||||
|
ret |= (vsdip & 3) << 3;
|
||||||
|
if (coinon)
|
||||||
|
ret |= 0x4;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFR(VSUNIRead1)
|
||||||
|
{
|
||||||
|
uint8 ret = 0;
|
||||||
|
|
||||||
|
if (JPorts[1] && JPorts[1]->Read)
|
||||||
|
ret |= (JPorts[1]->Read(1)) & 1;
|
||||||
|
ret |= vsdip & 0xFC;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SLHLHook(uint8 *bg, uint8 *spr, uint32 linets, int final)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
|
||||||
|
for (x = 0; x < 2; x++)
|
||||||
|
if (JPorts[x] && JPorts[x]->SLHook)
|
||||||
|
JPorts[x]->SLHook(x, bg, spr, linets, final);
|
||||||
|
|
||||||
|
if (FCExp && FCExp->SLHook)
|
||||||
|
FCExp->SLHook(bg, spr, linets, final);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CheckSLHook(void)
|
||||||
|
{
|
||||||
|
InputScanlineHook = 0;
|
||||||
|
|
||||||
|
if (JPorts[0] && JPorts[0]->SLHook || JPorts[1] && JPorts[1]->SLHook)
|
||||||
|
InputScanlineHook = SLHLHook;
|
||||||
|
|
||||||
|
if (FCExp && FCExp->SLHook)
|
||||||
|
InputScanlineHook = SLHLHook;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FASTAPASS(1) SetInputStuff(int x)
|
||||||
|
{
|
||||||
|
switch (JPType[x])
|
||||||
|
{
|
||||||
|
case SI_NONE:
|
||||||
|
JPorts[x] = &DummyJPort;
|
||||||
|
break;
|
||||||
|
case SI_GAMEPAD:
|
||||||
|
JPorts[x] = FCEU_InitJoyPad(x);
|
||||||
|
break;
|
||||||
|
case SI_ARKANOID:
|
||||||
|
JPorts[x] = FCEU_InitArkanoid(x);
|
||||||
|
break;
|
||||||
|
case SI_MOUSE:
|
||||||
|
JPorts[x] = FCEU_InitMouse(x);
|
||||||
|
break;
|
||||||
|
case SI_ZAPPER:
|
||||||
|
JPorts[x] = FCEU_InitZapper(x);
|
||||||
|
break;
|
||||||
|
case SI_POWERPADA:
|
||||||
|
JPorts[x] = FCEU_InitPowerpadA(x);
|
||||||
|
break;
|
||||||
|
case SI_POWERPADB:
|
||||||
|
JPorts[x] = FCEU_InitPowerpadB(x);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CheckSLHook();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetInputStuffFC(void)
|
||||||
|
{
|
||||||
|
switch (JPTypeFC)
|
||||||
|
{
|
||||||
|
case SIFC_NONE:
|
||||||
|
FCExp = 0;
|
||||||
|
break;
|
||||||
|
case SIFC_ARKANOID:
|
||||||
|
FCExp = FCEU_InitArkanoidFC();
|
||||||
|
break;
|
||||||
|
case SIFC_SHADOW:
|
||||||
|
FCExp = FCEU_InitSpaceShadow();
|
||||||
|
break;
|
||||||
|
case SIFC_OEKAKIDS:
|
||||||
|
FCExp = FCEU_InitOekaKids();
|
||||||
|
break;
|
||||||
|
case SIFC_4PLAYER:
|
||||||
|
FCExp = FCEU_InitFami4();
|
||||||
|
break;
|
||||||
|
case SIFC_FKB:
|
||||||
|
FCExp = FCEU_InitFKB();
|
||||||
|
break;
|
||||||
|
case SIFC_SUBORKB:
|
||||||
|
FCExp = FCEU_InitSuborKB();
|
||||||
|
break;
|
||||||
|
case SIFC_PEC586KB:
|
||||||
|
FCExp = FCEU_InitPEC586KB();
|
||||||
|
break;
|
||||||
|
case SIFC_HYPERSHOT:
|
||||||
|
FCExp = FCEU_InitHS();
|
||||||
|
break;
|
||||||
|
case SIFC_MAHJONG:
|
||||||
|
FCExp = FCEU_InitMahjong();
|
||||||
|
break;
|
||||||
|
case SIFC_QUIZKING:
|
||||||
|
FCExp = FCEU_InitQuizKing();
|
||||||
|
break;
|
||||||
|
case SIFC_FTRAINERA:
|
||||||
|
FCExp = FCEU_InitFamilyTrainerA();
|
||||||
|
break;
|
||||||
|
case SIFC_FTRAINERB:
|
||||||
|
FCExp = FCEU_InitFamilyTrainerB();
|
||||||
|
break;
|
||||||
|
case SIFC_BWORLD:
|
||||||
|
FCExp = FCEU_InitBarcodeWorld();
|
||||||
|
break;
|
||||||
|
case SIFC_TOPRIDER:
|
||||||
|
FCExp = FCEU_InitTopRider();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CheckSLHook();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeInput(void)
|
||||||
|
{
|
||||||
|
LastStrobe = 0;
|
||||||
|
|
||||||
|
if (GameInfo && GameInfo->type == GIT_VSUNI)
|
||||||
|
{
|
||||||
|
SetReadHandler(0x4016, 0x4016, VSUNIRead0);
|
||||||
|
SetReadHandler(0x4017, 0x4017, VSUNIRead1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SetReadHandler(0x4016, 0x4017, JPRead);
|
||||||
|
|
||||||
|
SetWriteHandler(0x4016, 0x4016, B4016);
|
||||||
|
|
||||||
|
SetInputStuff(0);
|
||||||
|
SetInputStuff(1);
|
||||||
|
SetInputStuffFC();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_SetInput(int port, int type, void *ptr, int attrib)
|
||||||
|
{
|
||||||
|
JPAttrib[port] = attrib;
|
||||||
|
JPType[port] = type;
|
||||||
|
InputDataPtr[port] = ptr;
|
||||||
|
SetInputStuff(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_SetInputFC(int type, void *ptr, int attrib)
|
||||||
|
{
|
||||||
|
JPAttribFC = attrib;
|
||||||
|
JPTypeFC = type;
|
||||||
|
InputDataPtrFC = ptr;
|
||||||
|
SetInputStuffFC();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_DoSimpleCommand(int cmd)
|
||||||
|
{
|
||||||
|
switch (cmd)
|
||||||
|
{
|
||||||
|
case FCEUNPCMD_FDSINSERT:
|
||||||
|
FCEU_FDSInsert(-1);
|
||||||
|
break;
|
||||||
|
case FCEUNPCMD_FDSSELECT:
|
||||||
|
FCEU_FDSSelect();
|
||||||
|
break;
|
||||||
|
case FCEUNPCMD_FDSEJECT:
|
||||||
|
FCEU_FDSEject();
|
||||||
|
break;
|
||||||
|
case FCEUNPCMD_VSUNICOIN:
|
||||||
|
FCEU_VSUniCoin();
|
||||||
|
break;
|
||||||
|
case FCEUNPCMD_VSUNIDIP0:
|
||||||
|
case (FCEUNPCMD_VSUNIDIP0 + 1):
|
||||||
|
case (FCEUNPCMD_VSUNIDIP0 + 2):
|
||||||
|
case (FCEUNPCMD_VSUNIDIP0 + 3):
|
||||||
|
case (FCEUNPCMD_VSUNIDIP0 + 4):
|
||||||
|
case (FCEUNPCMD_VSUNIDIP0 + 5):
|
||||||
|
case (FCEUNPCMD_VSUNIDIP0 + 6):
|
||||||
|
case (FCEUNPCMD_VSUNIDIP0 + 7):
|
||||||
|
FCEU_VSUniToggleDIP(cmd - FCEUNPCMD_VSUNIDIP0);
|
||||||
|
break;
|
||||||
|
case FCEUNPCMD_POWER:
|
||||||
|
PowerNES();
|
||||||
|
break;
|
||||||
|
case FCEUNPCMD_RESET:
|
||||||
|
ResetNES();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_QSimpleCommand(int cmd)
|
||||||
|
{
|
||||||
|
FCEU_DoSimpleCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_FDSSelect(void)
|
||||||
|
{
|
||||||
|
FCEU_QSimpleCommand(FCEUNPCMD_FDSSELECT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FCEUI_FDSInsert(int oride)
|
||||||
|
{
|
||||||
|
FCEU_QSimpleCommand(FCEUNPCMD_FDSINSERT);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FCEUI_FDSEject(void)
|
||||||
|
{
|
||||||
|
FCEU_QSimpleCommand(FCEUNPCMD_FDSEJECT);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_VSUniToggleDIP(int w)
|
||||||
|
{
|
||||||
|
FCEU_QSimpleCommand(FCEUNPCMD_VSUNIDIP0 + w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_VSUniCoin(void)
|
||||||
|
{
|
||||||
|
FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_ResetNES(void)
|
||||||
|
{
|
||||||
|
FCEU_QSimpleCommand(FCEUNPCMD_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_PowerNES(void)
|
||||||
|
{
|
||||||
|
FCEU_QSimpleCommand(FCEUNPCMD_POWER);
|
||||||
|
}
|
||||||
|
|
||||||
20
src/drivers/libretro/fceu/misc.c
Normal file
20
src/drivers/libretro/fceu/misc.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "fceu-types.h"
|
||||||
|
#include "fceu.h"
|
||||||
|
|
||||||
|
#include "driver.h"
|
||||||
|
|
||||||
|
/* wave.c */
|
||||||
|
|
||||||
|
void FCEU_WriteWaveData(int32 *Buffer, int Count) { }
|
||||||
|
int FCEUI_EndWaveRecord(void) { return 0; }
|
||||||
|
int FCEUI_BeginWaveRecord(char *fn) { return 0; }
|
||||||
|
|
||||||
|
/* netplay.c */
|
||||||
|
int FCEUNET_SendFile(uint8 cmd, char *fn) { return 0; }
|
||||||
|
|
||||||
|
/* movie.c */
|
||||||
|
void FCEUMOV_AddJoy(uint8 *js) { }
|
||||||
|
void FCEUMOV_Stop(void) {}
|
||||||
|
void FCEUI_SelectMovie(int w) { }
|
||||||
519
src/drivers/libretro/fceu/nsf.c
Normal file
519
src/drivers/libretro/fceu/nsf.c
Normal file
@@ -0,0 +1,519 @@
|
|||||||
|
/* FCE Ultra - NES/Famicom Emulator
|
||||||
|
*
|
||||||
|
* Copyright notice for this file:
|
||||||
|
* Copyright (C) 2002 Xodnizel
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "fceu-types.h"
|
||||||
|
#include "x6502.h"
|
||||||
|
#include "fceu.h"
|
||||||
|
#include "video.h"
|
||||||
|
#include "sound.h"
|
||||||
|
#include "nsf.h"
|
||||||
|
#include "general.h"
|
||||||
|
#include "fceu-memory.h"
|
||||||
|
#include "file.h"
|
||||||
|
#include "fds.h"
|
||||||
|
#include "cart.h"
|
||||||
|
#include "input.h"
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159265358979323846
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static uint8 SongReload;
|
||||||
|
static int CurrentSong;
|
||||||
|
|
||||||
|
static DECLFW(NSF_write);
|
||||||
|
static DECLFR(NSF_read);
|
||||||
|
|
||||||
|
static int vismode = 1;
|
||||||
|
|
||||||
|
static uint8 NSFROM[0x30 + 6] =
|
||||||
|
{
|
||||||
|
/* 0x00 - NMI */
|
||||||
|
0x8D, 0xF4, 0x3F, /* Stop play routine NMIs. */
|
||||||
|
0xA2, 0xFF, 0x9A, /* Initialize the stack pointer. */
|
||||||
|
0xAD, 0xF0, 0x3F, /* See if we need to init. */
|
||||||
|
0xF0, 0x09, /* If 0, go to play routine playing. */
|
||||||
|
|
||||||
|
0xAD, 0xF1, 0x3F, /* Confirm and load A */
|
||||||
|
0xAE, 0xF3, 0x3F, /* Load X with PAL/NTSC byte */
|
||||||
|
|
||||||
|
0x20, 0x00, 0x00, /* JSR to init routine */
|
||||||
|
|
||||||
|
0xA9, 0x00,
|
||||||
|
0xAA,
|
||||||
|
0xA8,
|
||||||
|
0x20, 0x00, 0x00, /* JSR to play routine */
|
||||||
|
0x8D, 0xF5, 0x3F, /* Start play routine NMIs. */
|
||||||
|
0x90, 0xFE, /* Loopie time. */
|
||||||
|
|
||||||
|
/* 0x20 */
|
||||||
|
0x8D, 0xF3, 0x3F, /* Init init NMIs */
|
||||||
|
0x18,
|
||||||
|
0x90, 0xFE /* Loopie time. */
|
||||||
|
};
|
||||||
|
|
||||||
|
static DECLFR(NSFROMRead) {
|
||||||
|
return (NSFROM - 0x3800)[A];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int doreset = 0;
|
||||||
|
static int NSFNMIFlags;
|
||||||
|
static uint8 *NSFDATA = 0;
|
||||||
|
static int NSFMaxBank;
|
||||||
|
|
||||||
|
static int NSFSize;
|
||||||
|
static uint8 BSon;
|
||||||
|
static uint16 PlayAddr;
|
||||||
|
static uint16 InitAddr;
|
||||||
|
static uint16 LoadAddr;
|
||||||
|
|
||||||
|
static NSF_HEADER NSFHeader;
|
||||||
|
|
||||||
|
void NSFMMC5_Close(void);
|
||||||
|
static uint8 *ExWRAM = 0;
|
||||||
|
|
||||||
|
void NSFGI(int h) {
|
||||||
|
switch (h) {
|
||||||
|
case GI_CLOSE:
|
||||||
|
if (NSFDATA) {
|
||||||
|
free(NSFDATA); NSFDATA = 0;
|
||||||
|
}
|
||||||
|
if (ExWRAM) {
|
||||||
|
free(ExWRAM); ExWRAM = 0;
|
||||||
|
}
|
||||||
|
if (NSFHeader.SoundChip & 1) {
|
||||||
|
// NSFVRC6_Init();
|
||||||
|
} else if (NSFHeader.SoundChip & 2) {
|
||||||
|
// NSFVRC7_Init();
|
||||||
|
} else if (NSFHeader.SoundChip & 4) {
|
||||||
|
// FDSSoundReset();
|
||||||
|
} else if (NSFHeader.SoundChip & 8) {
|
||||||
|
NSFMMC5_Close();
|
||||||
|
} else if (NSFHeader.SoundChip & 0x10) {
|
||||||
|
// NSFN106_Init();
|
||||||
|
} else if (NSFHeader.SoundChip & 0x20) {
|
||||||
|
// NSFAY_Init();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GI_RESETM2:
|
||||||
|
case GI_POWER: NSF_init(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// First 32KB is reserved for sound chip emulation in the iNES mapper code.
|
||||||
|
|
||||||
|
static INLINE void BANKSET(uint32 A, uint32 bank) {
|
||||||
|
bank &= NSFMaxBank;
|
||||||
|
if (NSFHeader.SoundChip & 4)
|
||||||
|
memcpy(ExWRAM + (A - 0x6000), NSFDATA + (bank << 12), 4096);
|
||||||
|
else
|
||||||
|
setprg4(A, bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
int NSFLoad(FCEUFILE *fp) {
|
||||||
|
int x;
|
||||||
|
|
||||||
|
FCEU_fseek(fp, 0, SEEK_SET);
|
||||||
|
FCEU_fread(&NSFHeader, 1, 0x80, fp);
|
||||||
|
if (memcmp(NSFHeader.ID, "NESM\x1a", 5))
|
||||||
|
return 0;
|
||||||
|
NSFHeader.SongName[31] = NSFHeader.Artist[31] = NSFHeader.Copyright[31] = 0;
|
||||||
|
|
||||||
|
LoadAddr = NSFHeader.LoadAddressLow;
|
||||||
|
LoadAddr |= NSFHeader.LoadAddressHigh << 8;
|
||||||
|
|
||||||
|
if (LoadAddr < 0x6000) {
|
||||||
|
FCEUD_PrintError("Invalid load address.");
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
InitAddr = NSFHeader.InitAddressLow;
|
||||||
|
InitAddr |= NSFHeader.InitAddressHigh << 8;
|
||||||
|
|
||||||
|
PlayAddr = NSFHeader.PlayAddressLow;
|
||||||
|
PlayAddr |= NSFHeader.PlayAddressHigh << 8;
|
||||||
|
|
||||||
|
NSFSize = FCEU_fgetsize(fp) - 0x80;
|
||||||
|
|
||||||
|
NSFMaxBank = ((NSFSize + (LoadAddr & 0xfff) + 4095) / 4096);
|
||||||
|
NSFMaxBank = uppow2(NSFMaxBank);
|
||||||
|
|
||||||
|
if (!(NSFDATA = (uint8*)FCEU_malloc(NSFMaxBank * 4096)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
FCEU_fseek(fp, 0x80, SEEK_SET);
|
||||||
|
memset(NSFDATA, 0x00, NSFMaxBank * 4096);
|
||||||
|
FCEU_fread(NSFDATA + (LoadAddr & 0xfff), 1, NSFSize, fp);
|
||||||
|
|
||||||
|
NSFMaxBank--;
|
||||||
|
|
||||||
|
BSon = 0;
|
||||||
|
for (x = 0; x < 8; x++)
|
||||||
|
BSon |= NSFHeader.BankSwitch[x];
|
||||||
|
|
||||||
|
GameInfo->type = GIT_NSF;
|
||||||
|
GameInfo->input[0] = GameInfo->input[1] = SI_GAMEPAD;
|
||||||
|
GameInfo->cspecial = SIS_NSF;
|
||||||
|
|
||||||
|
for (x = 0;; x++) {
|
||||||
|
if (NSFROM[x] == 0x20) {
|
||||||
|
NSFROM[x + 1] = InitAddr & 0xFF;
|
||||||
|
NSFROM[x + 2] = InitAddr >> 8;
|
||||||
|
NSFROM[x + 8] = PlayAddr & 0xFF;
|
||||||
|
NSFROM[x + 9] = PlayAddr >> 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NSFHeader.VideoSystem == 0)
|
||||||
|
GameInfo->vidsys = GIV_NTSC;
|
||||||
|
else if (NSFHeader.VideoSystem == 1)
|
||||||
|
GameInfo->vidsys = GIV_PAL;
|
||||||
|
|
||||||
|
GameInterface = NSFGI;
|
||||||
|
|
||||||
|
FCEU_printf("NSF Loaded. File information:\n\n");
|
||||||
|
FCEU_printf(" Name: %s\n Artist: %s\n Copyright: %s\n\n", NSFHeader.SongName, NSFHeader.Artist, NSFHeader.Copyright);
|
||||||
|
if (NSFHeader.SoundChip) {
|
||||||
|
static char *tab[6] = { "Konami VRCVI", "Konami VRCVII", "Nintendo FDS", "Nintendo MMC5", "Namco 106", "Sunsoft FME-07" };
|
||||||
|
|
||||||
|
for (x = 0; x < 6; x++)
|
||||||
|
if (NSFHeader.SoundChip & (1 << x)) {
|
||||||
|
FCEU_printf(" Expansion hardware: %s\n", tab[x]);
|
||||||
|
NSFHeader.SoundChip = 1 << x; /* Prevent confusing weirdness if more than one bit is set. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (BSon)
|
||||||
|
FCEU_printf(" Bank-switched.\n");
|
||||||
|
FCEU_printf(" Load address: $%04x\n Init address: $%04x\n Play address: $%04x\n", LoadAddr, InitAddr, PlayAddr);
|
||||||
|
FCEU_printf(" %s\n", (NSFHeader.VideoSystem & 1) ? "PAL" : "NTSC");
|
||||||
|
FCEU_printf(" Starting song: %d / %d\n\n", NSFHeader.StartingSong, NSFHeader.TotalSongs);
|
||||||
|
|
||||||
|
if (NSFHeader.SoundChip & 4)
|
||||||
|
ExWRAM = FCEU_gmalloc(32768 + 8192);
|
||||||
|
else
|
||||||
|
ExWRAM = FCEU_gmalloc(8192);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFR(NSFVectorRead) {
|
||||||
|
if (((NSFNMIFlags & 1) && SongReload) || (NSFNMIFlags & 2) || doreset) {
|
||||||
|
if (A == 0xFFFA) return(0x00);
|
||||||
|
else if (A == 0xFFFB) return(0x38);
|
||||||
|
else if (A == 0xFFFC) return(0x20);
|
||||||
|
else if (A == 0xFFFD) {
|
||||||
|
doreset = 0; return(0x38);
|
||||||
|
}
|
||||||
|
return(X.DB);
|
||||||
|
} else
|
||||||
|
return(CartBR(A));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSFVRC6_Init(void);
|
||||||
|
void NSFVRC7_Init(void);
|
||||||
|
void NSFMMC5_Init(void);
|
||||||
|
void NSFN106_Init(void);
|
||||||
|
void NSFAY_Init(void);
|
||||||
|
|
||||||
|
void NSF_init(void) {
|
||||||
|
doreset = 1;
|
||||||
|
|
||||||
|
ResetCartMapping();
|
||||||
|
if (NSFHeader.SoundChip & 4) {
|
||||||
|
SetupCartPRGMapping(0, ExWRAM, 32768 + 8192, 1);
|
||||||
|
setprg32(0x6000, 0);
|
||||||
|
setprg8(0xE000, 4);
|
||||||
|
memset(ExWRAM, 0x00, 32768 + 8192);
|
||||||
|
SetWriteHandler(0x6000, 0xDFFF, CartBW);
|
||||||
|
SetReadHandler(0x6000, 0xFFFF, CartBR);
|
||||||
|
} else {
|
||||||
|
memset(ExWRAM, 0x00, 8192);
|
||||||
|
SetReadHandler(0x6000, 0x7FFF, CartBR);
|
||||||
|
SetWriteHandler(0x6000, 0x7FFF, CartBW);
|
||||||
|
SetupCartPRGMapping(0, NSFDATA, ((NSFMaxBank + 1) * 4096), 0);
|
||||||
|
SetupCartPRGMapping(1, ExWRAM, 8192, 1);
|
||||||
|
setprg8r(1, 0x6000, 0);
|
||||||
|
SetReadHandler(0x8000, 0xFFFF, CartBR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BSon) {
|
||||||
|
int32 x;
|
||||||
|
for (x = 0; x < 8; x++) {
|
||||||
|
if (NSFHeader.SoundChip & 4 && x >= 6)
|
||||||
|
BANKSET(0x6000 + (x - 6) * 4096, NSFHeader.BankSwitch[x]);
|
||||||
|
BANKSET(0x8000 + x * 4096, NSFHeader.BankSwitch[x]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int32 x;
|
||||||
|
for (x = (LoadAddr & 0xF000); x < 0x10000; x += 0x1000)
|
||||||
|
BANKSET(x, ((x - (LoadAddr & 0x7000)) >> 12));
|
||||||
|
}
|
||||||
|
|
||||||
|
SetReadHandler(0xFFFA, 0xFFFD, NSFVectorRead);
|
||||||
|
|
||||||
|
SetWriteHandler(0x2000, 0x3fff, 0);
|
||||||
|
SetReadHandler(0x2000, 0x37ff, 0);
|
||||||
|
SetReadHandler(0x3836, 0x3FFF, 0);
|
||||||
|
SetReadHandler(0x3800, 0x3835, NSFROMRead);
|
||||||
|
|
||||||
|
SetWriteHandler(0x5ff6, 0x5fff, NSF_write);
|
||||||
|
|
||||||
|
SetWriteHandler(0x3ff0, 0x3fff, NSF_write);
|
||||||
|
SetReadHandler(0x3ff0, 0x3fff, NSF_read);
|
||||||
|
|
||||||
|
|
||||||
|
if (NSFHeader.SoundChip & 1) {
|
||||||
|
NSFVRC6_Init();
|
||||||
|
} else if (NSFHeader.SoundChip & 2) {
|
||||||
|
NSFVRC7_Init();
|
||||||
|
} else if (NSFHeader.SoundChip & 4) {
|
||||||
|
FDSSoundReset();
|
||||||
|
} else if (NSFHeader.SoundChip & 8) {
|
||||||
|
NSFMMC5_Init();
|
||||||
|
} else if (NSFHeader.SoundChip & 0x10) {
|
||||||
|
NSFN106_Init();
|
||||||
|
} else if (NSFHeader.SoundChip & 0x20) {
|
||||||
|
NSFAY_Init();
|
||||||
|
}
|
||||||
|
CurrentSong = NSFHeader.StartingSong;
|
||||||
|
SongReload = 0xFF;
|
||||||
|
NSFNMIFlags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFW(NSF_write) {
|
||||||
|
switch (A) {
|
||||||
|
case 0x3FF3: NSFNMIFlags |= 1; break;
|
||||||
|
case 0x3FF4: NSFNMIFlags &= ~2; break;
|
||||||
|
case 0x3FF5: NSFNMIFlags |= 2; break;
|
||||||
|
|
||||||
|
case 0x5FF6:
|
||||||
|
case 0x5FF7: if (!(NSFHeader.SoundChip & 4)) return;
|
||||||
|
case 0x5FF8:
|
||||||
|
case 0x5FF9:
|
||||||
|
case 0x5FFA:
|
||||||
|
case 0x5FFB:
|
||||||
|
case 0x5FFC:
|
||||||
|
case 0x5FFD:
|
||||||
|
case 0x5FFE:
|
||||||
|
case 0x5FFF: if (!BSon) return;
|
||||||
|
A &= 0xF;
|
||||||
|
BANKSET((A * 4096), V);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFR(NSF_read) {
|
||||||
|
int x;
|
||||||
|
|
||||||
|
switch (A) {
|
||||||
|
case 0x3ff0: x = SongReload;
|
||||||
|
#ifdef FCEUDEF_DEBUGGER
|
||||||
|
if (!fceuindbg)
|
||||||
|
#endif
|
||||||
|
SongReload = 0;
|
||||||
|
return x;
|
||||||
|
case 0x3ff1:
|
||||||
|
#ifdef FCEUDEF_DEBUGGER
|
||||||
|
if (!fceuindbg)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
memset(RAM, 0x00, 0x800);
|
||||||
|
|
||||||
|
BWrite[0x4015](0x4015, 0x0);
|
||||||
|
for (x = 0; x < 0x14; x++)
|
||||||
|
BWrite[0x4000 + x](0x4000 + x, 0);
|
||||||
|
BWrite[0x4015](0x4015, 0xF);
|
||||||
|
|
||||||
|
if (NSFHeader.SoundChip & 4) {
|
||||||
|
BWrite[0x4017](0x4017, 0xC0); /* FDS BIOS writes $C0 */
|
||||||
|
BWrite[0x4089](0x4089, 0x80);
|
||||||
|
BWrite[0x408A](0x408A, 0xE8);
|
||||||
|
} else {
|
||||||
|
memset(ExWRAM, 0x00, 8192);
|
||||||
|
BWrite[0x4017](0x4017, 0xC0);
|
||||||
|
BWrite[0x4017](0x4017, 0xC0);
|
||||||
|
BWrite[0x4017](0x4017, 0x40);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BSon) {
|
||||||
|
for (x = 0; x < 8; x++)
|
||||||
|
BANKSET(0x8000 + x * 4096, NSFHeader.BankSwitch[x]);
|
||||||
|
}
|
||||||
|
return(CurrentSong - 1);
|
||||||
|
}
|
||||||
|
case 0x3FF3: return PAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 FCEU_GetJoyJoy(void);
|
||||||
|
|
||||||
|
static int special = 0;
|
||||||
|
|
||||||
|
void DrawNSF(uint8 *XBuf) {
|
||||||
|
char snbuf[16];
|
||||||
|
int x;
|
||||||
|
|
||||||
|
if (vismode == 0) return;
|
||||||
|
|
||||||
|
memset(XBuf, 0, 256 * 240);
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
int32 *Bufpl;
|
||||||
|
int32 mul = 0;
|
||||||
|
|
||||||
|
int l;
|
||||||
|
l = GetSoundBuffer(&Bufpl);
|
||||||
|
|
||||||
|
if (special == 0) {
|
||||||
|
if (FSettings.SoundVolume)
|
||||||
|
mul = 8192 * 240 / (16384 * FSettings.SoundVolume / 50);
|
||||||
|
for (x = 0; x < 256; x++) {
|
||||||
|
uint32 y;
|
||||||
|
y = 142 + ((Bufpl[(x * l) >> 8] * mul) >> 14);
|
||||||
|
if (y < 240)
|
||||||
|
XBuf[x + y * 256] = 3;
|
||||||
|
}
|
||||||
|
} else if (special == 1) {
|
||||||
|
if (FSettings.SoundVolume)
|
||||||
|
mul = 8192 * 240 / (8192 * FSettings.SoundVolume / 50);
|
||||||
|
for (x = 0; x < 256; x++) {
|
||||||
|
double r;
|
||||||
|
uint32 xp, yp;
|
||||||
|
|
||||||
|
r = (Bufpl[(x * l) >> 8] * mul) >> 14;
|
||||||
|
xp = 128 + r*cos(x*M_PI*2 / 256);
|
||||||
|
yp = 120 + r*sin(x*M_PI*2 / 256);
|
||||||
|
xp &= 255;
|
||||||
|
yp %= 240;
|
||||||
|
XBuf[xp + yp * 256] = 3;
|
||||||
|
}
|
||||||
|
} else if (special == 2) {
|
||||||
|
static double theta = 0;
|
||||||
|
if (FSettings.SoundVolume)
|
||||||
|
mul = 8192 * 240 / (16384 * FSettings.SoundVolume / 50);
|
||||||
|
for (x = 0; x < 128; x++) {
|
||||||
|
double xc, yc;
|
||||||
|
double r, t;
|
||||||
|
uint32 m, n;
|
||||||
|
|
||||||
|
xc = (double)128 - x;
|
||||||
|
yc = 0 - ((double)(((Bufpl[(x * l) >> 8]) * mul) >> 14));
|
||||||
|
t = M_PI + atan(yc / xc);
|
||||||
|
r = sqrt(xc * xc + yc * yc);
|
||||||
|
|
||||||
|
t += theta;
|
||||||
|
m = 128 + r*cos(t);
|
||||||
|
n = 120 + r*sin(t);
|
||||||
|
|
||||||
|
if (m < 256 && n < 240)
|
||||||
|
XBuf[m + n * 256] = 3;
|
||||||
|
}
|
||||||
|
for (x = 128; x < 256; x++) {
|
||||||
|
double xc, yc;
|
||||||
|
double r, t;
|
||||||
|
uint32 m, n;
|
||||||
|
|
||||||
|
xc = (double)x - 128;
|
||||||
|
yc = (double)((Bufpl[(x * l) >> 8] * mul) >> 14);
|
||||||
|
t = atan(yc / xc);
|
||||||
|
r = sqrt(xc * xc + yc * yc);
|
||||||
|
|
||||||
|
t += theta;
|
||||||
|
m = 128 + r*cos(t);
|
||||||
|
n = 120 + r*sin(t);
|
||||||
|
|
||||||
|
if (m < 256 && n < 240)
|
||||||
|
XBuf[m + n * 256] = 3;
|
||||||
|
}
|
||||||
|
theta += (double)M_PI / 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawTextTrans(XBuf + 10 * 256 + 4 + (((31 - strlen((char*)NSFHeader.SongName)) << 2)), 256, NSFHeader.SongName, 6);
|
||||||
|
DrawTextTrans(XBuf + 26 * 256 + 4 + (((31 - strlen((char*)NSFHeader.Artist)) << 2)), 256, NSFHeader.Artist, 6);
|
||||||
|
DrawTextTrans(XBuf + 42 * 256 + 4 + (((31 - strlen((char*)NSFHeader.Copyright)) << 2)), 256, NSFHeader.Copyright, 6);
|
||||||
|
|
||||||
|
DrawTextTrans(XBuf + 70 * 256 + 4 + (((31 - strlen("Song:")) << 2)), 256, (uint8*)"Song:", 6);
|
||||||
|
sprintf(snbuf, "<%d/%d>", CurrentSong, NSFHeader.TotalSongs);
|
||||||
|
DrawTextTrans(XBuf + 82 * 256 + 4 + (((31 - strlen(snbuf)) << 2)), 256, (uint8*)snbuf, 6);
|
||||||
|
|
||||||
|
{
|
||||||
|
static uint8 last = 0;
|
||||||
|
uint8 tmp;
|
||||||
|
tmp = FCEU_GetJoyJoy();
|
||||||
|
if ((tmp & JOY_RIGHT) && !(last & JOY_RIGHT)) {
|
||||||
|
if (CurrentSong < NSFHeader.TotalSongs) {
|
||||||
|
CurrentSong++;
|
||||||
|
SongReload = 0xFF;
|
||||||
|
}
|
||||||
|
} else if ((tmp & JOY_LEFT) && !(last & JOY_LEFT)) {
|
||||||
|
if (CurrentSong > 1) {
|
||||||
|
CurrentSong--;
|
||||||
|
SongReload = 0xFF;
|
||||||
|
}
|
||||||
|
} else if ((tmp & JOY_UP) && !(last & JOY_UP)) {
|
||||||
|
CurrentSong += 10;
|
||||||
|
if (CurrentSong > NSFHeader.TotalSongs) CurrentSong = NSFHeader.TotalSongs;
|
||||||
|
SongReload = 0xFF;
|
||||||
|
} else if ((tmp & JOY_DOWN) && !(last & JOY_DOWN)) {
|
||||||
|
CurrentSong -= 10;
|
||||||
|
if (CurrentSong < 1) CurrentSong = 1;
|
||||||
|
SongReload = 0xFF;
|
||||||
|
} else if ((tmp & JOY_START) && !(last & JOY_START))
|
||||||
|
SongReload = 0xFF;
|
||||||
|
else if ((tmp & JOY_A) && !(last & JOY_A)) {
|
||||||
|
special = (special + 1) % 3;
|
||||||
|
}
|
||||||
|
last = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoNSFFrame(void) {
|
||||||
|
if (((NSFNMIFlags & 1) && SongReload) || (NSFNMIFlags & 2))
|
||||||
|
TriggerNMI();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_NSFSetVis(int mode) {
|
||||||
|
vismode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FCEUI_NSFChange(int amount) {
|
||||||
|
CurrentSong += amount;
|
||||||
|
if (CurrentSong < 1) CurrentSong = 1;
|
||||||
|
else if (CurrentSong > NSFHeader.TotalSongs) CurrentSong = NSFHeader.TotalSongs;
|
||||||
|
SongReload = 0xFF;
|
||||||
|
|
||||||
|
return(CurrentSong);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns total songs */
|
||||||
|
int FCEUI_NSFGetInfo(uint8 *name, uint8 *artist, uint8 *copyright, int maxlen) {
|
||||||
|
strncpy(name, NSFHeader.SongName, maxlen);
|
||||||
|
strncpy(artist, NSFHeader.Artist, maxlen);
|
||||||
|
strncpy(copyright, NSFHeader.Copyright, maxlen);
|
||||||
|
return(NSFHeader.TotalSongs);
|
||||||
|
}
|
||||||
365
src/drivers/libretro/fceu/state.c
Normal file
365
src/drivers/libretro/fceu/state.c
Normal file
@@ -0,0 +1,365 @@
|
|||||||
|
/* FCE Ultra - NES/Famicom Emulator
|
||||||
|
*
|
||||||
|
* Copyright notice for this file:
|
||||||
|
* Copyright (C) 2002 Xodnizel
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <direct.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "fceu-types.h"
|
||||||
|
#include "x6502.h"
|
||||||
|
#include "fceu.h"
|
||||||
|
#include "sound.h"
|
||||||
|
#include "fceu-endian.h"
|
||||||
|
#include "fds.h"
|
||||||
|
#include "general.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "movie.h"
|
||||||
|
#include "fceu-memory.h"
|
||||||
|
#include "ppu.h"
|
||||||
|
#include "netplay.h"
|
||||||
|
#include "video.h"
|
||||||
|
|
||||||
|
static void (*SPreSave)(void);
|
||||||
|
static void (*SPostSave)(void);
|
||||||
|
|
||||||
|
static int SaveStateStatus[10];
|
||||||
|
|
||||||
|
static SFORMAT SFMDATA[64];
|
||||||
|
static int SFEXINDEX;
|
||||||
|
|
||||||
|
#define RLSB FCEUSTATE_RLSB //0x80000000
|
||||||
|
|
||||||
|
extern SFORMAT FCEUPPU_STATEINFO[];
|
||||||
|
extern SFORMAT FCEUSND_STATEINFO[];
|
||||||
|
extern SFORMAT FCEUCTRL_STATEINFO[];
|
||||||
|
|
||||||
|
|
||||||
|
SFORMAT SFCPU[] = {
|
||||||
|
{ &X.PC, 2 | RLSB, "PC\0" },
|
||||||
|
{ &X.A, 1, "A\0\0" },
|
||||||
|
{ &X.X, 1, "X\0\0" },
|
||||||
|
{ &X.Y, 1, "Y\0\0" },
|
||||||
|
{ &X.S, 1, "S\0\0" },
|
||||||
|
{ &X.P, 1, "P\0\0" },
|
||||||
|
{ &X.DB, 1, "DB"},
|
||||||
|
#ifdef COPYFAMI
|
||||||
|
{ RAM, 0x4000, "RAM" },
|
||||||
|
#else
|
||||||
|
{ RAM, 0x800, "RAM" },
|
||||||
|
#endif
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
SFORMAT SFCPUC[] = {
|
||||||
|
{ &X.jammed, 1, "JAMM" },
|
||||||
|
{ &X.IRQlow, 4 | RLSB, "IQLB" },
|
||||||
|
{ &X.tcount, 4 | RLSB, "ICoa" },
|
||||||
|
{ &X.count, 4 | RLSB, "ICou" },
|
||||||
|
{ ×tampbase, sizeof(timestampbase) | RLSB, "TSBS" },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int SubWrite(memstream_t *mem, SFORMAT *sf)
|
||||||
|
{
|
||||||
|
uint32 acc=0;
|
||||||
|
|
||||||
|
while(sf->v)
|
||||||
|
{
|
||||||
|
if(sf->s==~0) /* Link to another struct. */
|
||||||
|
{
|
||||||
|
uint32 tmp;
|
||||||
|
|
||||||
|
if(!(tmp=SubWrite(mem, (SFORMAT *)sf->v)))
|
||||||
|
return(0);
|
||||||
|
acc+=tmp;
|
||||||
|
sf++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
acc+=8; /* Description + size */
|
||||||
|
acc+=sf->s&(~RLSB);
|
||||||
|
|
||||||
|
if(mem) /* Are we writing or calculating the size of this block? */
|
||||||
|
{
|
||||||
|
memstream_write(mem, sf->desc, 4);
|
||||||
|
write32le_mem(sf->s&(~RLSB), mem);
|
||||||
|
|
||||||
|
#ifdef MSB_FIRST
|
||||||
|
if(sf->s&RLSB)
|
||||||
|
FlipByteOrder(sf->v,sf->s&(~RLSB));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memstream_write(mem, (uint8 *)sf->v, sf->s&(~RLSB));
|
||||||
|
/* Now restore the original byte order. */
|
||||||
|
#ifdef MSB_FIRST
|
||||||
|
if(sf->s&RLSB)
|
||||||
|
FlipByteOrder(sf->v,sf->s&(~RLSB));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
sf++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int WriteStateChunk(memstream_t *mem, int type, SFORMAT *sf)
|
||||||
|
{
|
||||||
|
int bsize;
|
||||||
|
|
||||||
|
memstream_putc(mem, type);
|
||||||
|
|
||||||
|
bsize = SubWrite(0,sf);
|
||||||
|
write32le_mem(bsize, mem);
|
||||||
|
|
||||||
|
if (!SubWrite(mem, sf))
|
||||||
|
return 0;
|
||||||
|
return bsize + 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SFORMAT *CheckS(SFORMAT *sf, uint32 tsize, char *desc)
|
||||||
|
{
|
||||||
|
while (sf->v)
|
||||||
|
{
|
||||||
|
if (sf->s == ~0)
|
||||||
|
{ /* Link to another SFORMAT structure. */
|
||||||
|
SFORMAT *tmp;
|
||||||
|
if ((tmp = CheckS((SFORMAT*)sf->v, tsize, desc)))
|
||||||
|
return(tmp);
|
||||||
|
sf++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(desc, sf->desc, 4))
|
||||||
|
{
|
||||||
|
if (tsize != (sf->s & (~RLSB)))
|
||||||
|
return(0);
|
||||||
|
return(sf);
|
||||||
|
}
|
||||||
|
sf++;
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ReadStateChunk(memstream_t *mem, SFORMAT *sf, int size)
|
||||||
|
{
|
||||||
|
SFORMAT *tmp;
|
||||||
|
int temp;
|
||||||
|
temp=memstream_pos(mem);
|
||||||
|
|
||||||
|
while(memstream_pos(mem)<temp+size)
|
||||||
|
{
|
||||||
|
uint32 tsize;
|
||||||
|
char toa[4];
|
||||||
|
if(memstream_read(mem, toa, 4)<=0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
read32le_mem(&tsize,mem);
|
||||||
|
|
||||||
|
if((tmp=CheckS(sf,tsize,toa)))
|
||||||
|
{
|
||||||
|
memstream_read(mem, (uint8 *)tmp->v, tmp->s&(~RLSB));
|
||||||
|
|
||||||
|
#ifdef MSB_FIRST
|
||||||
|
if(tmp->s&RLSB)
|
||||||
|
FlipByteOrder(tmp->v,tmp->s&(~RLSB));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memstream_seek(mem,tsize,SEEK_CUR);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ReadStateChunks(memstream_t *st, int32 totalsize)
|
||||||
|
{
|
||||||
|
int t;
|
||||||
|
uint32 size;
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
while (totalsize > 0)
|
||||||
|
{
|
||||||
|
t = memstream_getc(st);
|
||||||
|
if (t == EOF)
|
||||||
|
break;
|
||||||
|
if (!read32le_mem(&size,st))
|
||||||
|
break;
|
||||||
|
totalsize -= size + 5;
|
||||||
|
|
||||||
|
switch(t)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
if (!ReadStateChunk(st, SFCPU, size))
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (!ReadStateChunk(st, SFCPUC, size))
|
||||||
|
ret = 0;
|
||||||
|
else
|
||||||
|
X.mooPI = X.P; // Quick and dirty hack.
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (!ReadStateChunk(st, FCEUPPU_STATEINFO, size))
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (!ReadStateChunk(st, FCEUCTRL_STATEINFO, size))
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
if (!ReadStateChunk(st, FCEUSND_STATEINFO, size))
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
case 0x10:
|
||||||
|
if (!ReadStateChunk(st, SFMDATA, size))
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (memstream_seek(st, size, SEEK_CUR) < 0)
|
||||||
|
goto endo;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endo:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CurrentState = 0;
|
||||||
|
extern int geniestage;
|
||||||
|
|
||||||
|
void FCEUSS_Save_Mem(void)
|
||||||
|
{
|
||||||
|
memstream_t *mem = memstream_open(1);
|
||||||
|
|
||||||
|
uint32 totalsize;
|
||||||
|
uint8 header[16] = {0};
|
||||||
|
|
||||||
|
header[0] = 'F';
|
||||||
|
header[1] = 'C';
|
||||||
|
header[2] = 'S';
|
||||||
|
header[3] = 0xFF;
|
||||||
|
|
||||||
|
FCEU_en32lsb(header + 8, FCEU_VERSION_NUMERIC);
|
||||||
|
memstream_write(mem, header, 16);
|
||||||
|
|
||||||
|
FCEUPPU_SaveState();
|
||||||
|
totalsize = WriteStateChunk(mem, 1, SFCPU);
|
||||||
|
totalsize += WriteStateChunk(mem, 2, SFCPUC);
|
||||||
|
totalsize += WriteStateChunk(mem, 3, FCEUPPU_STATEINFO);
|
||||||
|
totalsize += WriteStateChunk(mem, 4, FCEUCTRL_STATEINFO);
|
||||||
|
totalsize += WriteStateChunk(mem, 5, FCEUSND_STATEINFO);
|
||||||
|
|
||||||
|
if (SPreSave)
|
||||||
|
SPreSave();
|
||||||
|
|
||||||
|
totalsize += WriteStateChunk(mem, 0x10, SFMDATA);
|
||||||
|
|
||||||
|
if (SPreSave)
|
||||||
|
SPostSave();
|
||||||
|
|
||||||
|
memstream_seek(mem, 4, SEEK_SET);
|
||||||
|
write32le_mem(totalsize, mem);
|
||||||
|
|
||||||
|
memstream_close(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUSS_Load_Mem(void)
|
||||||
|
{
|
||||||
|
memstream_t *mem = memstream_open(0);
|
||||||
|
|
||||||
|
uint8 header[16];
|
||||||
|
int stateversion;
|
||||||
|
int x;
|
||||||
|
|
||||||
|
memstream_read(mem, header, 16);
|
||||||
|
|
||||||
|
if (memcmp(header,"FCS",3) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (header[3] == 0xFF)
|
||||||
|
stateversion = FCEU_de32lsb(header + 8);
|
||||||
|
else
|
||||||
|
stateversion = header[3] * 100;
|
||||||
|
|
||||||
|
x = ReadStateChunks(mem, *(uint32*)(header + 4));
|
||||||
|
|
||||||
|
if (stateversion < 9500)
|
||||||
|
X.IRQlow=0;
|
||||||
|
|
||||||
|
if (GameStateRestore)
|
||||||
|
GameStateRestore(stateversion);
|
||||||
|
|
||||||
|
if (x)
|
||||||
|
{
|
||||||
|
FCEUPPU_LoadState(stateversion);
|
||||||
|
FCEUSND_LoadState(stateversion);
|
||||||
|
}
|
||||||
|
|
||||||
|
memstream_close(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUSS_CheckStates(void)
|
||||||
|
{
|
||||||
|
MEM_TYPE *st = NULL;
|
||||||
|
char *fn;
|
||||||
|
int ssel;
|
||||||
|
|
||||||
|
for (ssel = 0; ssel < 10; ssel++)
|
||||||
|
{
|
||||||
|
st = fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, ssel, 0), "rb");
|
||||||
|
free(fn);
|
||||||
|
if (st)
|
||||||
|
{
|
||||||
|
SaveStateStatus[ssel] = 1;
|
||||||
|
fclose(st);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SaveStateStatus[ssel] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentState = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetExState(void (*PreSave)(void), void (*PostSave)(void))
|
||||||
|
{
|
||||||
|
SPreSave = PreSave;
|
||||||
|
SPostSave = PostSave;
|
||||||
|
SFEXINDEX = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddExState(void *v, uint32 s, int type, char *desc)
|
||||||
|
{
|
||||||
|
memset(SFMDATA[SFEXINDEX].desc, 0, sizeof(SFMDATA[SFEXINDEX].desc));
|
||||||
|
if (desc)
|
||||||
|
strncpy(SFMDATA[SFEXINDEX].desc, desc, sizeof(SFMDATA[SFEXINDEX].desc));
|
||||||
|
SFMDATA[SFEXINDEX].v = v;
|
||||||
|
SFMDATA[SFEXINDEX].s = s;
|
||||||
|
if (type) SFMDATA[SFEXINDEX].s |= RLSB;
|
||||||
|
if (SFEXINDEX < 63) SFEXINDEX++;
|
||||||
|
SFMDATA[SFEXINDEX].v = 0; // End marker.
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_DrawSaveStates(uint8 *XBuf)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
626
src/drivers/libretro/fceu/unif.c
Normal file
626
src/drivers/libretro/fceu/unif.c
Normal file
@@ -0,0 +1,626 @@
|
|||||||
|
/* FCE Ultra - NES/Famicom Emulator
|
||||||
|
*
|
||||||
|
* Copyright notice for this file:
|
||||||
|
* Copyright (C) 2002 Xodnizel
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* TODO: Battery backup file saving, mirror force */
|
||||||
|
/* **INCOMPLETE** */
|
||||||
|
/* Override stuff: CHR RAM instead of CHR ROM, mirroring. */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "fceu-types.h"
|
||||||
|
#include "fceu.h"
|
||||||
|
#include "cart.h"
|
||||||
|
#include "unif.h"
|
||||||
|
#include "ines.h"
|
||||||
|
#include "general.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "fceu-endian.h"
|
||||||
|
#include "file.h"
|
||||||
|
#include "fceu-memory.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "md5.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char ID[4];
|
||||||
|
uint32 info;
|
||||||
|
} UNIF_HEADER;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *name;
|
||||||
|
void (*init)(CartInfo *);
|
||||||
|
int flags;
|
||||||
|
} BMAPPING;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *name;
|
||||||
|
int (*init)(FCEUFILE *fp);
|
||||||
|
} BFMAPPING;
|
||||||
|
|
||||||
|
CartInfo UNIFCart;
|
||||||
|
|
||||||
|
static int vramo;
|
||||||
|
static int mirrortodo;
|
||||||
|
static uint8 *boardname;
|
||||||
|
static uint8 *sboardname;
|
||||||
|
|
||||||
|
static uint32 CHRRAMSize;
|
||||||
|
uint8 *UNIFchrrama = 0;
|
||||||
|
|
||||||
|
static UNIF_HEADER unhead;
|
||||||
|
static UNIF_HEADER uchead;
|
||||||
|
|
||||||
|
|
||||||
|
static uint8 *malloced[32];
|
||||||
|
static uint32 mallocedsizes[32];
|
||||||
|
|
||||||
|
static int FixRomSize(uint32 size, uint32 minimum) {
|
||||||
|
uint32 x = 1;
|
||||||
|
|
||||||
|
if (size < minimum)
|
||||||
|
return minimum;
|
||||||
|
while (x < size)
|
||||||
|
x <<= 1;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FreeUNIF(void) {
|
||||||
|
int x;
|
||||||
|
if (UNIFchrrama) {
|
||||||
|
free(UNIFchrrama); UNIFchrrama = 0;
|
||||||
|
}
|
||||||
|
if (boardname) {
|
||||||
|
free(boardname); boardname = 0;
|
||||||
|
}
|
||||||
|
for (x = 0; x < 32; x++) {
|
||||||
|
if (malloced[x]) {
|
||||||
|
free(malloced[x]); malloced[x] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ResetUNIF(void) {
|
||||||
|
int x;
|
||||||
|
for (x = 0; x < 32; x++)
|
||||||
|
malloced[x] = 0;
|
||||||
|
vramo = 0;
|
||||||
|
boardname = 0;
|
||||||
|
mirrortodo = 0;
|
||||||
|
memset(&UNIFCart, 0, sizeof(UNIFCart));
|
||||||
|
UNIFchrrama = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8 exntar[2048];
|
||||||
|
|
||||||
|
static void MooMirroring(void) {
|
||||||
|
if (mirrortodo < 0x4)
|
||||||
|
SetupCartMirroring(mirrortodo, 1, 0);
|
||||||
|
else if (mirrortodo == 0x4) {
|
||||||
|
SetupCartMirroring(4, 1, exntar);
|
||||||
|
AddExState(exntar, 2048, 0, "EXNR");
|
||||||
|
} else
|
||||||
|
SetupCartMirroring(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DoMirroring(FCEUFILE *fp) {
|
||||||
|
int t;
|
||||||
|
uint32 i;
|
||||||
|
if (uchead.info == 1) {
|
||||||
|
if ((t = FCEU_fgetc(fp)) == EOF)
|
||||||
|
return(0);
|
||||||
|
mirrortodo = t;
|
||||||
|
{
|
||||||
|
static char *stuffo[6] = { "Horizontal", "Vertical", "$2000", "$2400", "\"Four-screen\"", "Controlled by Mapper Hardware" };
|
||||||
|
if (t < 6)
|
||||||
|
FCEU_printf(" Name/Attribute Table Mirroring: %s\n", stuffo[t]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FCEU_printf(" Incorrect Mirroring Chunk Size (%d). Data is:", uchead.info);
|
||||||
|
for (i = 0; i < uchead.info; i++) {
|
||||||
|
if ((t = FCEU_fgetc(fp)) == EOF)
|
||||||
|
return(0);
|
||||||
|
FCEU_printf(" %02x", t);
|
||||||
|
}
|
||||||
|
FCEU_printf("\n Default Name/Attribute Table Mirroring: Horizontal\n", uchead.info);
|
||||||
|
mirrortodo = 0;
|
||||||
|
}
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int NAME(FCEUFILE *fp) {
|
||||||
|
char namebuf[100];
|
||||||
|
int index;
|
||||||
|
int t;
|
||||||
|
|
||||||
|
FCEU_printf(" Name: ");
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
while ((t = FCEU_fgetc(fp)) > 0)
|
||||||
|
if (index < 99)
|
||||||
|
namebuf[index++] = t;
|
||||||
|
|
||||||
|
namebuf[index] = 0;
|
||||||
|
FCEU_printf("%s\n", namebuf);
|
||||||
|
|
||||||
|
if (!GameInfo->name) {
|
||||||
|
GameInfo->name = malloc(strlen(namebuf) + 1);
|
||||||
|
strcpy(GameInfo->name, namebuf);
|
||||||
|
}
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DINF(FCEUFILE *fp) {
|
||||||
|
char name[100], method[100];
|
||||||
|
uint8 d, m;
|
||||||
|
uint16 y;
|
||||||
|
int t;
|
||||||
|
|
||||||
|
if (FCEU_fread(name, 1, 100, fp) != 100)
|
||||||
|
return(0);
|
||||||
|
if ((t = FCEU_fgetc(fp)) == EOF) return(0);
|
||||||
|
d = t;
|
||||||
|
if ((t = FCEU_fgetc(fp)) == EOF) return(0);
|
||||||
|
m = t;
|
||||||
|
if ((t = FCEU_fgetc(fp)) == EOF) return(0);
|
||||||
|
y = t;
|
||||||
|
if ((t = FCEU_fgetc(fp)) == EOF) return(0);
|
||||||
|
y |= t << 8;
|
||||||
|
if (FCEU_fread(method, 1, 100, fp) != 100)
|
||||||
|
return(0);
|
||||||
|
name[99] = method[99] = 0;
|
||||||
|
FCEU_printf(" Dumped by: %s\n", name);
|
||||||
|
FCEU_printf(" Dumped with: %s\n", method);
|
||||||
|
{
|
||||||
|
char *months[12] = {
|
||||||
|
"January", "February", "March", "April", "May", "June", "July",
|
||||||
|
"August", "September", "October", "November", "December"
|
||||||
|
};
|
||||||
|
FCEU_printf(" Dumped on: %s %d, %d\n", months[(m - 1) % 12], d, y);
|
||||||
|
}
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CTRL(FCEUFILE *fp) {
|
||||||
|
int t;
|
||||||
|
uint32 i;
|
||||||
|
if (uchead.info == 1) {
|
||||||
|
if ((t = FCEU_fgetc(fp)) == EOF)
|
||||||
|
return(0);
|
||||||
|
/* The information stored in this byte isn't very helpful, but it's
|
||||||
|
better than nothing...maybe.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (t & 1)
|
||||||
|
GameInfo->input[0] = GameInfo->input[1] = SI_GAMEPAD;
|
||||||
|
else
|
||||||
|
GameInfo->input[0] = GameInfo->input[1] = SI_NONE;
|
||||||
|
if (t & 2)
|
||||||
|
GameInfo->input[1] = SI_ZAPPER;
|
||||||
|
} else {
|
||||||
|
FCEU_printf(" Incorrect Control Chunk Size (%d). Data is:", uchead.info);
|
||||||
|
for (i = 0; i < uchead.info; i++) {
|
||||||
|
t = FCEU_fgetc(fp);
|
||||||
|
FCEU_printf(" %02x", t);
|
||||||
|
}
|
||||||
|
FCEU_printf("\n");
|
||||||
|
GameInfo->input[0] = GameInfo->input[1] = SI_GAMEPAD;
|
||||||
|
}
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int TVCI(FCEUFILE *fp) {
|
||||||
|
int t;
|
||||||
|
if ((t = FCEU_fgetc(fp)) == EOF)
|
||||||
|
return(0);
|
||||||
|
if (t <= 2) {
|
||||||
|
char *stuffo[3] = { "NTSC", "PAL", "NTSC and PAL" };
|
||||||
|
if (t == 0)
|
||||||
|
GameInfo->vidsys = GIV_NTSC;
|
||||||
|
else if (t == 1)
|
||||||
|
GameInfo->vidsys = GIV_PAL;
|
||||||
|
FCEU_printf(" TV Standard Compatibility: %s\n", stuffo[t]);
|
||||||
|
}
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int EnableBattery(FCEUFILE *fp) {
|
||||||
|
FCEU_printf(" Battery-backed.\n");
|
||||||
|
if (FCEU_fgetc(fp) == EOF)
|
||||||
|
return(0);
|
||||||
|
UNIFCart.battery = 1;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int LoadPRG(FCEUFILE *fp) {
|
||||||
|
int z, t;
|
||||||
|
z = uchead.ID[3] - '0';
|
||||||
|
|
||||||
|
if (z < 0 || z > 15)
|
||||||
|
return(0);
|
||||||
|
FCEU_printf(" PRG ROM %d size: %d", z, (int)uchead.info);
|
||||||
|
if (malloced[z])
|
||||||
|
free(malloced[z]);
|
||||||
|
t = FixRomSize(uchead.info, 2048);
|
||||||
|
if (!(malloced[z] = (uint8*)FCEU_malloc(t)))
|
||||||
|
return(0);
|
||||||
|
mallocedsizes[z] = t;
|
||||||
|
memset(malloced[z] + uchead.info, 0xFF, t - uchead.info);
|
||||||
|
if (FCEU_fread(malloced[z], 1, uchead.info, fp) != uchead.info) {
|
||||||
|
FCEU_printf("Read Error!\n");
|
||||||
|
return(0);
|
||||||
|
} else
|
||||||
|
FCEU_printf("\n");
|
||||||
|
|
||||||
|
SetupCartPRGMapping(z, malloced[z], t, 0);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SetBoardName(FCEUFILE *fp) {
|
||||||
|
if (!(boardname = (uint8*)FCEU_malloc(uchead.info + 1)))
|
||||||
|
return(0);
|
||||||
|
FCEU_fread(boardname, 1, uchead.info, fp);
|
||||||
|
boardname[uchead.info] = 0;
|
||||||
|
FCEU_printf(" Board name: %s\n", boardname);
|
||||||
|
sboardname = boardname;
|
||||||
|
if (!memcmp(boardname, "NES-", 4) || !memcmp(boardname, "UNL-", 4) || !memcmp(boardname, "HVC-", 4) || !memcmp(boardname, "BTL-", 4) || !memcmp(boardname, "BMC-", 4))
|
||||||
|
sboardname += 4;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int LoadCHR(FCEUFILE *fp) {
|
||||||
|
int z, t;
|
||||||
|
z = uchead.ID[3] - '0';
|
||||||
|
if (z < 0 || z > 15)
|
||||||
|
return(0);
|
||||||
|
FCEU_printf(" CHR ROM %d size: %d", z, (int)uchead.info);
|
||||||
|
if (malloced[16 + z])
|
||||||
|
free(malloced[16 + z]);
|
||||||
|
t = FixRomSize(uchead.info, 8192);
|
||||||
|
if (!(malloced[16 + z] = (uint8*)FCEU_malloc(t)))
|
||||||
|
return(0);
|
||||||
|
mallocedsizes[16 + z] = t;
|
||||||
|
memset(malloced[16 + z] + uchead.info, 0xFF, t - uchead.info);
|
||||||
|
if (FCEU_fread(malloced[16 + z], 1, uchead.info, fp) != uchead.info) {
|
||||||
|
FCEU_printf("Read Error!\n");
|
||||||
|
return(0);
|
||||||
|
} else
|
||||||
|
FCEU_printf("\n");
|
||||||
|
|
||||||
|
SetupCartCHRMapping(z, malloced[16 + z], t, 0);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BMCFLAG_FORCE4 0x01
|
||||||
|
#define BMCFLAG_16KCHRR 0x02
|
||||||
|
#define BMCFLAG_32KCHRR 0x04
|
||||||
|
#define BMCFLAG_128KCHRR 0x08
|
||||||
|
#define BMCFLAG_256KCHRR 0x10
|
||||||
|
|
||||||
|
static BMAPPING bmap[] = {
|
||||||
|
{ "11160", BMC11160_Init, 0 },
|
||||||
|
{ "12-IN-1", BMC12IN1_Init, 0 },
|
||||||
|
{ "13in1JY110", BMC13in1JY110_Init, 0 },
|
||||||
|
{ "190in1", BMC190in1_Init, 0 },
|
||||||
|
{ "22211", UNL22211_Init, 0 },
|
||||||
|
{ "3D-BLOCK", UNL3DBlock_Init, 0 },
|
||||||
|
{ "411120-C", BMC411120C_Init, 0 },
|
||||||
|
{ "42in1ResetSwitch", Mapper226_Init, 0 },
|
||||||
|
{ "43272", UNL43272_Init, 0 },
|
||||||
|
{ "603-5052", UNL6035052_Init, 0 },
|
||||||
|
{ "64in1NoRepeat", BMC64in1nr_Init, 0 },
|
||||||
|
{ "70in1", BMC70in1_Init, 0 },
|
||||||
|
{ "70in1B", BMC70in1B_Init, 0 },
|
||||||
|
{ "810544-C-A1", BMC810544CA1_Init, 0 },
|
||||||
|
{ "8157", UNL8157_Init, 0 },
|
||||||
|
{ "8237", UNL8237_Init, 0 },
|
||||||
|
{ "8237A", UNL8237A_Init, 0 },
|
||||||
|
{ "830118C", BMC830118C_Init, 0 },
|
||||||
|
{ "A65AS", BMCA65AS_Init, 0 },
|
||||||
|
{ "AC08", AC08_Init, 0 },
|
||||||
|
{ "ANROM", ANROM_Init, 0 },
|
||||||
|
{ "AX5705", UNLAX5705_Init, 0 },
|
||||||
|
{ "BB", UNLBB_Init, 0 },
|
||||||
|
{ "BS-5", BMCBS5_Init, 0 },
|
||||||
|
{ "CC-21", UNLCC21_Init, 0 },
|
||||||
|
{ "CITYFIGHT", UNLCITYFIGHT_Init, 0 },
|
||||||
|
{ "10-24-C-A1", BMC1024CA1_Init, 0 },
|
||||||
|
{ "CNROM", CNROM_Init, 0 },
|
||||||
|
{ "CPROM", CPROM_Init, BMCFLAG_16KCHRR },
|
||||||
|
{ "D1038", BMCD1038_Init, 0 },
|
||||||
|
{ "DANCE", UNLOneBus_Init, 0 }, // redundant
|
||||||
|
{ "DANCE2000", UNLD2000_Init, 0 },
|
||||||
|
{ "DREAMTECH01", DreamTech01_Init, 0 },
|
||||||
|
{ "EDU2000", UNLEDU2000_Init, 0 },
|
||||||
|
{ "EKROM", EKROM_Init, 0 },
|
||||||
|
{ "ELROM", ELROM_Init, 0 },
|
||||||
|
{ "ETROM", ETROM_Init, 0 },
|
||||||
|
{ "EWROM", EWROM_Init, 0 },
|
||||||
|
{ "FK23C", BMCFK23C_Init, BMCFLAG_256KCHRR },
|
||||||
|
{ "FK23CA", BMCFK23CA_Init, BMCFLAG_256KCHRR },
|
||||||
|
{ "FS304", UNLFS304_Init, 0 },
|
||||||
|
{ "G-146", BMCG146_Init, 0 },
|
||||||
|
{ "GK-192", BMCGK192_Init, 0 },
|
||||||
|
{ "GS-2004", BMCGS2004_Init, 0 },
|
||||||
|
{ "GS-2013", BMCGS2013_Init, 0 },
|
||||||
|
{ "Ghostbusters63in1", BMCGhostbusters63in1_Init, 0 },
|
||||||
|
{ "H2288", UNLH2288_Init, 0 },
|
||||||
|
{ "HKROM", HKROM_Init, 0 },
|
||||||
|
{ "KOF97", UNLKOF97_Init, 0 },
|
||||||
|
{ "KONAMI-QTAI", Mapper190_Init, 0 },
|
||||||
|
{ "KS7012", UNLKS7012_Init, 0 },
|
||||||
|
{ "KS7013B", UNLKS7013B_Init, 0 },
|
||||||
|
{ "KS7017", UNLKS7017_Init, 0 },
|
||||||
|
{ "KS7030", UNLKS7030_Init, 0 },
|
||||||
|
{ "KS7031", UNLKS7031_Init, 0 },
|
||||||
|
{ "KS7032", UNLKS7032_Init, 0 },
|
||||||
|
{ "KS7037", UNLKS7037_Init, 0 },
|
||||||
|
{ "KS7057", UNLKS7057_Init, 0 },
|
||||||
|
{ "LE05", LE05_Init, 0 },
|
||||||
|
{ "LH10", LH10_Init, 0 },
|
||||||
|
{ "LH32", LH32_Init, 0 },
|
||||||
|
{ "LH53", LH53_Init, 0 },
|
||||||
|
{ "MALISB", UNLMaliSB_Init, 0 },
|
||||||
|
{ "MARIO1-MALEE2", MALEE_Init, 0 },
|
||||||
|
{ "MHROM", MHROM_Init, 0 },
|
||||||
|
{ "N625092", UNLN625092_Init, 0 },
|
||||||
|
{ "NROM", NROM_Init, 0 },
|
||||||
|
{ "NROM-128", NROM_Init, 0 },
|
||||||
|
{ "NROM-256", NROM_Init, 0 },
|
||||||
|
{ "NTBROM", Mapper68_Init, 0 },
|
||||||
|
{ "NTD-03", BMCNTD03_Init, 0 },
|
||||||
|
{ "NovelDiamond9999999in1", Novel_Init, 0 },
|
||||||
|
{ "OneBus", UNLOneBus_Init, 0 },
|
||||||
|
{ "PEC-586", UNLPEC586Init, 0 },
|
||||||
|
{ "RROM", NROM_Init, 0 },
|
||||||
|
{ "RROM-128", NROM_Init, 0 },
|
||||||
|
{ "SA-002", TCU02_Init, 0 },
|
||||||
|
{ "SA-0036", SA0036_Init, 0 },
|
||||||
|
{ "SA-0037", SA0037_Init, 0 },
|
||||||
|
{ "SA-009", SA009_Init, 0 },
|
||||||
|
{ "SA-016-1M", SA0161M_Init, 0 },
|
||||||
|
{ "SA-72007", SA72007_Init, 0 },
|
||||||
|
{ "SA-72008", SA72008_Init, 0 },
|
||||||
|
{ "SA-9602B", SA9602B_Init, BMCFLAG_32KCHRR },
|
||||||
|
{ "SA-NROM", TCA01_Init, 0 },
|
||||||
|
{ "SAROM", SAROM_Init, 0 },
|
||||||
|
{ "SBROM", SBROM_Init, 0 },
|
||||||
|
{ "SC-127", UNLSC127_Init, 0 },
|
||||||
|
{ "SCROM", SCROM_Init, 0 },
|
||||||
|
{ "SEROM", SEROM_Init, 0 },
|
||||||
|
{ "SGROM", SGROM_Init, 0 },
|
||||||
|
{ "SHERO", UNLSHeroes_Init, 0 },
|
||||||
|
{ "SKROM", SKROM_Init, 0 },
|
||||||
|
{ "SL12", UNLSL12_Init, 0 },
|
||||||
|
{ "SL1632", UNLSL1632_Init, 0 },
|
||||||
|
{ "SL1ROM", SL1ROM_Init, 0 },
|
||||||
|
{ "SLROM", SLROM_Init, 0 },
|
||||||
|
{ "SMB2J", UNLSMB2J_Init, 0 },
|
||||||
|
{ "SNROM", SNROM_Init, 0 },
|
||||||
|
{ "SOROM", SOROM_Init, 0 },
|
||||||
|
{ "SSS-NROM-256", SSSNROM_Init, 0 },
|
||||||
|
{ "SUNSOFT_UNROM", SUNSOFT_UNROM_Init, 0 }, // fix me, real pcb name, real pcb type
|
||||||
|
{ "Sachen-74LS374N", S74LS374N_Init, 0 },
|
||||||
|
{ "Sachen-74LS374NA", S74LS374NA_Init, 0 }, //seems to be custom mapper
|
||||||
|
{ "Sachen-8259A", S8259A_Init, 0 },
|
||||||
|
{ "Sachen-8259B", S8259B_Init, 0 },
|
||||||
|
{ "Sachen-8259C", S8259C_Init, 0 },
|
||||||
|
{ "Sachen-8259D", S8259D_Init, 0 },
|
||||||
|
{ "Super24in1SC03", Super24_Init, 0 },
|
||||||
|
{ "SuperHIK8in1", Mapper45_Init, 0 },
|
||||||
|
{ "Supervision16in1", Supervision16_Init, 0 },
|
||||||
|
{ "T-227-1", BMCT2271_Init, 0 },
|
||||||
|
{ "T-230", UNLT230_Init, 0 },
|
||||||
|
{ "T-262", BMCT262_Init, 0 },
|
||||||
|
{ "TBROM", TBROM_Init, 0 },
|
||||||
|
{ "TC-U01-1.5M", TCU01_Init, 0 },
|
||||||
|
{ "TEK90", Mapper90_Init, 0 },
|
||||||
|
{ "TEROM", TEROM_Init, 0 },
|
||||||
|
{ "TF1201", UNLTF1201_Init, 0 },
|
||||||
|
{ "TFROM", TFROM_Init, 0 },
|
||||||
|
{ "TGROM", TGROM_Init, 0 },
|
||||||
|
{ "TKROM", TKROM_Init, 0 },
|
||||||
|
{ "TKSROM", TKSROM_Init, 0 },
|
||||||
|
{ "TLROM", TLROM_Init, 0 },
|
||||||
|
{ "TLSROM", TLSROM_Init, 0 },
|
||||||
|
{ "TQROM", TQROM_Init, 0 },
|
||||||
|
{ "TR1ROM", TFROM_Init, BMCFLAG_FORCE4 },
|
||||||
|
{ "TSROM", TSROM_Init, 0 },
|
||||||
|
{ "TVROM", TLROM_Init, BMCFLAG_FORCE4 },
|
||||||
|
{ "Transformer", Transformer_Init, 0 },
|
||||||
|
{ "UNROM", UNROM_Init, 0 },
|
||||||
|
{ "UOROM", UNROM_Init, 0 },
|
||||||
|
{ "VRC7", UNLVRC7_Init, 0 },
|
||||||
|
{ "YOKO", UNLYOKO_Init, 0 },
|
||||||
|
{ "COOLBOY", COOLBOY_Init, BMCFLAG_256KCHRR },
|
||||||
|
{ "158B", UNL158B_Init, 0 },
|
||||||
|
{ "DRAGONFIGHTER", UNLBMW8544_Init, 0},
|
||||||
|
|
||||||
|
#ifdef COPYFAMI
|
||||||
|
{ "COPYFAMI_MMC3", MapperCopyFamiMMC3_Init, 0 },
|
||||||
|
{ "COPYFAMI", MapperCopyFami_Init, 0 },
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{ NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static BFMAPPING bfunc[] = {
|
||||||
|
{ "CTRL", CTRL },
|
||||||
|
{ "TVCI", TVCI },
|
||||||
|
{ "BATR", EnableBattery },
|
||||||
|
{ "MIRR", DoMirroring },
|
||||||
|
{ "PRG", LoadPRG },
|
||||||
|
{ "CHR", LoadCHR },
|
||||||
|
{ "NAME", NAME },
|
||||||
|
{ "MAPR", SetBoardName },
|
||||||
|
{ "DINF", DINF },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
int LoadUNIFChunks(FCEUFILE *fp) {
|
||||||
|
int x;
|
||||||
|
int t;
|
||||||
|
for (;; ) {
|
||||||
|
t = FCEU_fread(&uchead, 1, 4, fp);
|
||||||
|
if (t < 4) {
|
||||||
|
if (t > 0)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!(FCEU_read32le(&uchead.info, fp)))
|
||||||
|
return 0;
|
||||||
|
t = 0;
|
||||||
|
x = 0;
|
||||||
|
while (bfunc[x].name) {
|
||||||
|
if (!memcmp(&uchead, bfunc[x].name, strlen(bfunc[x].name))) {
|
||||||
|
if (!bfunc[x].init(fp))
|
||||||
|
return 0;
|
||||||
|
t = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
if (!t)
|
||||||
|
if (FCEU_fseek(fp, uchead.info, SEEK_CUR))
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int InitializeBoard(void) {
|
||||||
|
int x = 0;
|
||||||
|
|
||||||
|
if (!sboardname) return(0);
|
||||||
|
|
||||||
|
while (bmap[x].name) {
|
||||||
|
if (!strcmp((char*)sboardname, (char*)bmap[x].name)) {
|
||||||
|
if (!malloced[16]) {
|
||||||
|
if (bmap[x].flags & BMCFLAG_16KCHRR)
|
||||||
|
CHRRAMSize = 16;
|
||||||
|
else if (bmap[x].flags & BMCFLAG_32KCHRR)
|
||||||
|
CHRRAMSize = 32;
|
||||||
|
else if (bmap[x].flags & BMCFLAG_128KCHRR)
|
||||||
|
CHRRAMSize = 128;
|
||||||
|
else if (bmap[x].flags & BMCFLAG_256KCHRR)
|
||||||
|
CHRRAMSize = 256;
|
||||||
|
else
|
||||||
|
CHRRAMSize = 8;
|
||||||
|
CHRRAMSize <<= 10;
|
||||||
|
if ((UNIFchrrama = (uint8*)FCEU_malloc(CHRRAMSize))) {
|
||||||
|
SetupCartCHRMapping(0, UNIFchrrama, CHRRAMSize, 1);
|
||||||
|
AddExState(UNIFchrrama, CHRRAMSize, 0, "CHRR");
|
||||||
|
} else
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
if (bmap[x].flags & BMCFLAG_FORCE4)
|
||||||
|
mirrortodo = 4;
|
||||||
|
MooMirroring();
|
||||||
|
bmap[x].init(&UNIFCart);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
FCEU_PrintError("Board type not supported.");
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void UNIFGI(int h) {
|
||||||
|
switch (h) {
|
||||||
|
case GI_RESETM2:
|
||||||
|
if (UNIFCart.Reset)
|
||||||
|
UNIFCart.Reset();
|
||||||
|
break;
|
||||||
|
case GI_POWER:
|
||||||
|
if (UNIFCart.Power)
|
||||||
|
UNIFCart.Power();
|
||||||
|
if (UNIFchrrama) memset(UNIFchrrama, 0, 8192);
|
||||||
|
break;
|
||||||
|
case GI_CLOSE:
|
||||||
|
FCEU_SaveGameSave(&UNIFCart);
|
||||||
|
if (UNIFCart.Close)
|
||||||
|
UNIFCart.Close();
|
||||||
|
FreeUNIF();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int UNIFLoad(const char *name, FCEUFILE *fp) {
|
||||||
|
FCEU_fseek(fp, 0, SEEK_SET);
|
||||||
|
FCEU_fread(&unhead, 1, 4, fp);
|
||||||
|
if (memcmp(&unhead, "UNIF", 4))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ResetCartMapping();
|
||||||
|
|
||||||
|
ResetExState(0, 0);
|
||||||
|
ResetUNIF();
|
||||||
|
if (!FCEU_read32le(&unhead.info, fp))
|
||||||
|
goto aborto;
|
||||||
|
if (FCEU_fseek(fp, 0x20, SEEK_SET) < 0)
|
||||||
|
goto aborto;
|
||||||
|
if (!LoadUNIFChunks(fp))
|
||||||
|
goto aborto;
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
struct md5_context md5;
|
||||||
|
|
||||||
|
md5_starts(&md5);
|
||||||
|
|
||||||
|
for (x = 0; x < 32; x++)
|
||||||
|
if (malloced[x]) {
|
||||||
|
md5_update(&md5, malloced[x], mallocedsizes[x]);
|
||||||
|
}
|
||||||
|
md5_finish(&md5, UNIFCart.MD5);
|
||||||
|
FCEU_printf(" ROM MD5: 0x%s\n", md5_asciistr(UNIFCart.MD5));
|
||||||
|
memcpy(GameInfo->MD5, UNIFCart.MD5, sizeof(UNIFCart.MD5));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!InitializeBoard())
|
||||||
|
goto aborto;
|
||||||
|
|
||||||
|
FCEU_LoadGameSave(&UNIFCart);
|
||||||
|
GameInterface = UNIFGI;
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
aborto:
|
||||||
|
|
||||||
|
FreeUNIF();
|
||||||
|
ResetUNIF();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CopyFamiLoad() {
|
||||||
|
ResetCartMapping();
|
||||||
|
ResetExState(0, 0);
|
||||||
|
|
||||||
|
sboardname = "COPYFAMI";
|
||||||
|
if (!InitializeBoard())
|
||||||
|
goto aborto;
|
||||||
|
|
||||||
|
FCEU_LoadGameSave(&UNIFCart);
|
||||||
|
GameInterface = UNIFGI;
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
aborto:
|
||||||
|
|
||||||
|
FreeUNIF();
|
||||||
|
ResetUNIF();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
109
src/drivers/libretro/fceu/video.c
Normal file
109
src/drivers/libretro/fceu/video.c
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/* FCE Ultra - NES/Famicom Emulator
|
||||||
|
*
|
||||||
|
* Copyright notice for this file:
|
||||||
|
* Copyright (C) 2002 Xodnizel
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include "fceu-types.h"
|
||||||
|
#include "video.h"
|
||||||
|
#include "fceu.h"
|
||||||
|
#include "general.h"
|
||||||
|
#include "fceu-memory.h"
|
||||||
|
#include "crc32.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "palette.h"
|
||||||
|
#include "nsf.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "vsuni.h"
|
||||||
|
|
||||||
|
uint8 *XBuf = NULL;
|
||||||
|
|
||||||
|
void FCEU_KillVirtualVideo(void)
|
||||||
|
{
|
||||||
|
if (XBuf)
|
||||||
|
free(XBuf);
|
||||||
|
XBuf = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FCEU_InitVirtualVideo(void)
|
||||||
|
{
|
||||||
|
// 256 bytes per scanline, * 240 scanline maximum, +8 for alignment,
|
||||||
|
if (!XBuf)
|
||||||
|
XBuf = (uint8*)(FCEU_malloc(256 * 256 + 8));
|
||||||
|
|
||||||
|
if (!XBuf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (sizeof(uint8*) == 4)
|
||||||
|
{
|
||||||
|
uintptr_t m;
|
||||||
|
m = (uintptr_t)*XBuf;
|
||||||
|
m = (4 - m) & 3;
|
||||||
|
XBuf += m;
|
||||||
|
}
|
||||||
|
memset(XBuf, 128, 256 * 256);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int howlong;
|
||||||
|
static char errmsg[65];
|
||||||
|
|
||||||
|
#include "drawing.h"
|
||||||
|
|
||||||
|
void FCEUI_SaveSnapshot(void) { }
|
||||||
|
|
||||||
|
void FCEU_PutImage(void)
|
||||||
|
{
|
||||||
|
if (GameInfo->type == GIT_NSF)
|
||||||
|
DrawNSF(XBuf);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (GameInfo->type == GIT_VSUNI)
|
||||||
|
FCEU_VSUniDraw(XBuf);
|
||||||
|
}
|
||||||
|
if (howlong) howlong--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_PutImageDummy(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_DispMessage(char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
vsprintf(errmsg, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
howlong = 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_ResetMessages(void)
|
||||||
|
{
|
||||||
|
howlong = 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SaveSnapshot(void)
|
||||||
|
{
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
@@ -8,22 +8,22 @@
|
|||||||
#include "cheat.c"
|
#include "cheat.c"
|
||||||
#include "crc32.c"
|
#include "crc32.c"
|
||||||
#include "debug.c"
|
#include "debug.c"
|
||||||
#include "fceu-endian.c"
|
#include "drivers/libretro/fceu/fceu-endian.c"
|
||||||
#include "fceu-memory.c"
|
#include "drivers/libretro/fceu/fceu-memory.c"
|
||||||
#include "misc.c"
|
#include "drivers/libretro/fceu/misc.c"
|
||||||
#include "fceu.c"
|
#include "drivers/libretro/fceu/fceu.c"
|
||||||
#include "fds.c"
|
#include "drivers/libretro/fceu/fds.c"
|
||||||
#include "file.c"
|
#include "drivers/libretro/fceu/file.c"
|
||||||
#include "filter.c"
|
#include "filter.c"
|
||||||
#include "general.c"
|
#include "drivers/libretro/fceu/general.c"
|
||||||
#include "input.c"
|
#include "drivers/libretro/fceu/input.c"
|
||||||
#include "md5.c"
|
#include "md5.c"
|
||||||
#include "nsf.c"
|
#include "drivers/libretro/fceu/nsf.c"
|
||||||
#include "palette.c"
|
#include "palette.c"
|
||||||
#include "ppu.c"
|
#include "ppu.c"
|
||||||
#include "sound.c"
|
#include "sound.c"
|
||||||
#include "state.c"
|
#include "drivers/libretro/fceu/state.c"
|
||||||
#include "video.c"
|
#include "drivers/libretro/fceu/video.c"
|
||||||
#include "vsuni.c"
|
#include "vsuni.c"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -26,98 +26,70 @@
|
|||||||
#include "fceu-types.h"
|
#include "fceu-types.h"
|
||||||
#include "fceu-endian.h"
|
#include "fceu-endian.h"
|
||||||
|
|
||||||
void FlipByteOrder(uint8 *src, uint32 count)
|
void FlipByteOrder(uint8 *src, uint32 count) {
|
||||||
{
|
uint8 *start = src;
|
||||||
uint8 *start = src;
|
uint8 *end = src + count - 1;
|
||||||
uint8 *end = src + count - 1;
|
|
||||||
|
|
||||||
while(start < end)
|
if ((count & 1) || !count) return; /* This shouldn't happen. */
|
||||||
{
|
|
||||||
uint8 tmp;
|
|
||||||
|
|
||||||
tmp = *end;
|
while (count--) {
|
||||||
*end = *start;
|
uint8 tmp;
|
||||||
*start = tmp;
|
|
||||||
end--;
|
tmp = *end;
|
||||||
start++;
|
*end = *start;
|
||||||
}
|
*start = tmp;
|
||||||
|
end--;
|
||||||
|
start++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int write16le(uint16 b, FILE *fp)
|
int write16le(uint16 b, FILE *fp) {
|
||||||
{
|
uint8 s[2];
|
||||||
uint8 s[2];
|
s[0] = b;
|
||||||
s[0] = b;
|
s[1] = b >> 8;
|
||||||
s[1] = b >> 8;
|
return((fwrite(s, 1, 2, fp) < 2) ? 0 : 2);
|
||||||
return((fwrite(s, 1, 2, fp) < 2) ? 0 : 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int write32le(uint32 b, FILE *fp)
|
int write32le(uint32 b, FILE *fp) {
|
||||||
{
|
uint8 s[4];
|
||||||
uint8 s[4];
|
s[0] = b;
|
||||||
s[0] = b;
|
s[1] = b >> 8;
|
||||||
s[1] = b >> 8;
|
s[2] = b >> 16;
|
||||||
s[2] = b >> 16;
|
s[3] = b >> 24;
|
||||||
s[3] = b >> 24;
|
return((fwrite(s, 1, 4, fp) < 4) ? 0 : 4);
|
||||||
return((fwrite(s, 1, 4, fp) < 4) ? 0 : 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int read32le(uint32 *Bufo, FILE *fp)
|
int read32le(uint32 *Bufo, FILE *fp) {
|
||||||
{
|
uint32 buf;
|
||||||
uint32 buf;
|
if (fread(&buf, 1, 4, fp) < 4)
|
||||||
if (fread(&buf, 1, 4, fp) < 4)
|
return 0;
|
||||||
return 0;
|
#ifdef MSB_FIRST
|
||||||
#ifdef MSB_FIRST
|
*(uint32*)Bufo = ((buf & 0xFF) << 24) | ((buf & 0xFF00) << 8) | ((buf & 0xFF0000) >> 8) | ((buf & 0xFF000000) >> 24);
|
||||||
*(uint32*)Bufo = ((buf & 0xFF) << 24) | ((buf & 0xFF00) << 8) | ((buf & 0xFF0000) >> 8) | ((buf & 0xFF000000) >> 24);
|
#else
|
||||||
#else
|
*(uint32*)Bufo = buf;
|
||||||
*(uint32*)Bufo = buf;
|
#endif
|
||||||
#endif
|
return 1;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int write32le_mem(uint32 b, memstream_t *mem)
|
int read16le(char *d, FILE *fp) {
|
||||||
{
|
#ifdef MSB_FIRST
|
||||||
uint8 s[4];
|
int ret;
|
||||||
s[0]=b;
|
ret = fread(d + 1, 1, 1, fp);
|
||||||
s[1]=b>>8;
|
ret += fread(d, 1, 1, fp);
|
||||||
s[2]=b>>16;
|
return ret < 2 ? 0 : 2;
|
||||||
s[3]=b>>24;
|
#else
|
||||||
return((memstream_write(mem, s, 4)<4)?0:4);
|
return((fread(d, 1, 2, fp) < 2) ? 0 : 2);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int read32le_mem(uint32 *Bufo, memstream_t *mem)
|
void FCEU_en32lsb(uint8 *buf, uint32 morp) {
|
||||||
{
|
buf[0] = morp;
|
||||||
uint32 buf;
|
buf[1] = morp >> 8;
|
||||||
if(memstream_read(mem, &buf, 4)<4)
|
buf[2] = morp >> 16;
|
||||||
return 0;
|
buf[3] = morp >> 24;
|
||||||
#ifdef MSB_FIRST
|
|
||||||
*(uint32*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24);
|
|
||||||
#else
|
|
||||||
*(uint32*)Bufo=buf;
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int read16le(char *d, FILE *fp)
|
uint32 FCEU_de32lsb(uint8 *morp) {
|
||||||
{
|
return(morp[0] | (morp[1] << 8) | (morp[2] << 16) | (morp[3] << 24));
|
||||||
#ifdef MSB_FIRST
|
|
||||||
int ret;
|
|
||||||
ret = fread(d + 1, 1, 1, fp);
|
|
||||||
ret += fread(d, 1, 1, fp);
|
|
||||||
return ret < 2 ? 0 : 2;
|
|
||||||
#else
|
|
||||||
return((fread(d, 1, 2, fp) < 2) ? 0 : 2);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEU_en32lsb(uint8 *buf, uint32 morp)
|
|
||||||
{
|
|
||||||
buf[0] = morp;
|
|
||||||
buf[1] = morp >> 8;
|
|
||||||
buf[2] = morp >> 16;
|
|
||||||
buf[3] = morp >> 24;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 FCEU_de32lsb(uint8 *morp)
|
|
||||||
{
|
|
||||||
return(morp[0] | (morp[1] << 8) | (morp[2] << 16) | (morp[3] << 24));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,10 +2,6 @@
|
|||||||
#define _FCEU_ENDIAN_H
|
#define _FCEU_ENDIAN_H
|
||||||
|
|
||||||
#include "fceu-memory.h"
|
#include "fceu-memory.h"
|
||||||
#include <memstream.h>
|
|
||||||
|
|
||||||
int write32le_mem(uint32 b, memstream_t *mem);
|
|
||||||
int read32le_mem(uint32 *Bufo, memstream_t *mem);
|
|
||||||
|
|
||||||
int write16le(uint16 b, FILE *fp);
|
int write16le(uint16 b, FILE *fp);
|
||||||
int write32le(uint32 b, FILE *fp);
|
int write32le(uint32 b, FILE *fp);
|
||||||
|
|||||||
@@ -25,39 +25,64 @@
|
|||||||
#include "fceu-memory.h"
|
#include "fceu-memory.h"
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
|
|
||||||
void *FCEU_gmalloc(uint32 size)
|
void *FCEU_gmalloc(uint32 size) {
|
||||||
{
|
void *ret;
|
||||||
void *ret;
|
ret = malloc(size);
|
||||||
ret = malloc(size);
|
if (!ret) {
|
||||||
if (!ret)
|
FCEU_PrintError("Error allocating memory! Doing a hard exit.");
|
||||||
{
|
exit(1);
|
||||||
FCEU_PrintError("Error allocating memory! Doing a hard exit.");
|
}
|
||||||
exit(1);
|
return ret;
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *FCEU_malloc(uint32 size)
|
void *FCEU_malloc(uint32 size) {
|
||||||
{
|
void *ret;
|
||||||
int retval = 0;
|
ret = malloc(size);
|
||||||
void *ret;
|
if (!ret) {
|
||||||
ret = (void*)malloc(size);
|
FCEU_PrintError("Error allocating memory!");
|
||||||
|
return(0);
|
||||||
if (!ret)
|
}
|
||||||
{
|
return ret;
|
||||||
FCEU_PrintError("Error allocating memory!");
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEU_free(void *ptr)
|
void FCEU_free(void *ptr) { // Might do something with this and FCEU_malloc later...
|
||||||
{
|
|
||||||
free(ptr);
|
free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEU_gfree(void *ptr)
|
void FCEU_gfree(void *ptr) {
|
||||||
{
|
|
||||||
free(ptr);
|
free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FASTAPASS(3) FCEU_memmove(void *d, void *s, uint32 l) {
|
||||||
|
uint32 x;
|
||||||
|
int t;
|
||||||
|
|
||||||
|
/* Type really doesn't matter. */
|
||||||
|
t = (int)d;
|
||||||
|
t |= (int)s;
|
||||||
|
t |= (int)l;
|
||||||
|
|
||||||
|
if (t & 3) { // Not 4-byte aligned and/or length is not a multiple of 4.
|
||||||
|
uint8 *tmpd, *tmps;
|
||||||
|
|
||||||
|
tmpd = (uint8*)d;
|
||||||
|
tmps = (uint8*)s;
|
||||||
|
|
||||||
|
for (x = l; x; x--) { // This could be optimized further, though(more tests could be performed).
|
||||||
|
*tmpd = *tmps;
|
||||||
|
tmpd++;
|
||||||
|
tmps++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint32 *tmpd, *tmps;
|
||||||
|
|
||||||
|
tmpd = (uint32*)d;
|
||||||
|
tmps = (uint32*)s;
|
||||||
|
|
||||||
|
for (x = l >> 2; x; x--) {
|
||||||
|
*tmpd = *tmps;
|
||||||
|
tmpd++;
|
||||||
|
tmps++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,10 +26,12 @@
|
|||||||
#define _FCEU_MEMORY_H_
|
#define _FCEU_MEMORY_H_
|
||||||
|
|
||||||
#include "fceu-types.h"
|
#include "fceu-types.h"
|
||||||
#include <memstream.h>
|
|
||||||
|
|
||||||
#define FCEU_dwmemset(d, c, n) { int _x; for (_x = n - 4; _x >= 0; _x -= 4) *(uint32*)& (d)[_x] = c; }
|
#define FCEU_dwmemset(d, c, n) { int _x; for (_x = n - 4; _x >= 0; _x -= 4) *(uint32*)& (d)[_x] = c; }
|
||||||
|
|
||||||
|
#if defined(STATE_LIBRETRO) || defined(ENDIAN_LIBRETRO) || defined(GENERAL_LIBRETRO)
|
||||||
|
#include "drivers/libretro/memstream.h"
|
||||||
|
|
||||||
#define HAVE_MEMSTREAM
|
#define HAVE_MEMSTREAM
|
||||||
#define MEM_TYPE memstream_t
|
#define MEM_TYPE memstream_t
|
||||||
|
|
||||||
@@ -40,6 +42,9 @@
|
|||||||
#define ftell(a) memstream_pos((a))
|
#define ftell(a) memstream_pos((a))
|
||||||
#define fread(ptr, size, nmemb, stream) memstream_read((stream), (ptr), (nmemb))
|
#define fread(ptr, size, nmemb, stream) memstream_read((stream), (ptr), (nmemb))
|
||||||
#define fseek(stream, offset, whence) memstream_seek((stream), (offset), (whence))
|
#define fseek(stream, offset, whence) memstream_seek((stream), (offset), (whence))
|
||||||
|
#else
|
||||||
|
#define MEM_TYPE FILE
|
||||||
|
#endif
|
||||||
|
|
||||||
void *FCEU_malloc(uint32 size);
|
void *FCEU_malloc(uint32 size);
|
||||||
void *FCEU_gmalloc(uint32 size);
|
void *FCEU_gmalloc(uint32 size);
|
||||||
|
|||||||
295
src/fceu.c
295
src/fceu.c
@@ -41,6 +41,7 @@
|
|||||||
#include "cheat.h"
|
#include "cheat.h"
|
||||||
#include "palette.h"
|
#include "palette.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
#include "movie.h"
|
||||||
#include "video.h"
|
#include "video.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
@@ -61,17 +62,14 @@ static readfunc *AReadG;
|
|||||||
static writefunc *BWriteG;
|
static writefunc *BWriteG;
|
||||||
static int RWWrap = 0;
|
static int RWWrap = 0;
|
||||||
|
|
||||||
static DECLFW(BNull)
|
static DECLFW(BNull) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static DECLFR(ANull)
|
static DECLFR(ANull) {
|
||||||
{
|
|
||||||
return(X.DB);
|
return(X.DB);
|
||||||
}
|
}
|
||||||
|
|
||||||
int AllocGenieRW(void)
|
int AllocGenieRW(void) {
|
||||||
{
|
|
||||||
if (!(AReadG = (readfunc*)FCEU_malloc(0x8000 * sizeof(readfunc))))
|
if (!(AReadG = (readfunc*)FCEU_malloc(0x8000 * sizeof(readfunc))))
|
||||||
return 0;
|
return 0;
|
||||||
if (!(BWriteG = (writefunc*)FCEU_malloc(0x8000 * sizeof(writefunc))))
|
if (!(BWriteG = (writefunc*)FCEU_malloc(0x8000 * sizeof(writefunc))))
|
||||||
@@ -80,71 +78,62 @@ int AllocGenieRW(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlushGenieRW(void)
|
void FlushGenieRW(void) {
|
||||||
{
|
int32 x;
|
||||||
int32 x;
|
|
||||||
|
|
||||||
if (RWWrap)
|
if (RWWrap) {
|
||||||
{
|
for (x = 0; x < 0x8000; x++) {
|
||||||
for (x = 0; x < 0x8000; x++)
|
ARead[x + 0x8000] = AReadG[x];
|
||||||
{
|
BWrite[x + 0x8000] = BWriteG[x];
|
||||||
ARead[x + 0x8000] = AReadG[x];
|
}
|
||||||
BWrite[x + 0x8000] = BWriteG[x];
|
free(AReadG);
|
||||||
}
|
free(BWriteG);
|
||||||
free(AReadG);
|
AReadG = 0;
|
||||||
free(BWriteG);
|
BWriteG = 0;
|
||||||
AReadG = 0;
|
RWWrap = 0;
|
||||||
BWriteG = 0;
|
}
|
||||||
}
|
|
||||||
RWWrap = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
readfunc FASTAPASS(1) GetReadHandler(int32 a)
|
readfunc FASTAPASS(1) GetReadHandler(int32 a) {
|
||||||
{
|
|
||||||
if (a >= 0x8000 && RWWrap)
|
if (a >= 0x8000 && RWWrap)
|
||||||
return AReadG[a - 0x8000];
|
return AReadG[a - 0x8000];
|
||||||
else
|
else
|
||||||
return ARead[a];
|
return ARead[a];
|
||||||
}
|
}
|
||||||
|
|
||||||
void FASTAPASS(3) SetReadHandler(int32 start, int32 end, readfunc func)
|
void FASTAPASS(3) SetReadHandler(int32 start, int32 end, readfunc func) {
|
||||||
{
|
|
||||||
int32 x;
|
int32 x;
|
||||||
|
|
||||||
if (!func)
|
if (!func)
|
||||||
func = ANull;
|
func = ANull;
|
||||||
|
|
||||||
if (RWWrap)
|
if (RWWrap)
|
||||||
for (x = end; x >= start; x--)
|
for (x = end; x >= start; x--) {
|
||||||
{
|
if (x >= 0x8000)
|
||||||
if (x >= 0x8000)
|
AReadG[x - 0x8000] = func;
|
||||||
AReadG[x - 0x8000] = func;
|
else
|
||||||
else
|
ARead[x] = func;
|
||||||
ARead[x] = func;
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
for (x = end; x >= start; x--)
|
for (x = end; x >= start; x--)
|
||||||
ARead[x] = func;
|
ARead[x] = func;
|
||||||
}
|
}
|
||||||
|
|
||||||
writefunc FASTAPASS(1) GetWriteHandler(int32 a)
|
writefunc FASTAPASS(1) GetWriteHandler(int32 a) {
|
||||||
{
|
|
||||||
if (RWWrap && a >= 0x8000)
|
if (RWWrap && a >= 0x8000)
|
||||||
return BWriteG[a - 0x8000];
|
return BWriteG[a - 0x8000];
|
||||||
else
|
else
|
||||||
return BWrite[a];
|
return BWrite[a];
|
||||||
}
|
}
|
||||||
|
|
||||||
void FASTAPASS(3) SetWriteHandler(int32 start, int32 end, writefunc func)
|
void FASTAPASS(3) SetWriteHandler(int32 start, int32 end, writefunc func) {
|
||||||
{
|
|
||||||
int32 x;
|
int32 x;
|
||||||
|
|
||||||
if (!func)
|
if (!func)
|
||||||
func = BNull;
|
func = BNull;
|
||||||
|
|
||||||
if (RWWrap)
|
if (RWWrap)
|
||||||
for (x = end; x >= start; x--)
|
for (x = end; x >= start; x--) {
|
||||||
{
|
|
||||||
if (x >= 0x8000)
|
if (x >= 0x8000)
|
||||||
BWriteG[x - 0x8000] = func;
|
BWriteG[x - 0x8000] = func;
|
||||||
else
|
else
|
||||||
@@ -163,58 +152,50 @@ uint8 RAM[0x800];
|
|||||||
|
|
||||||
uint8 PAL = 0;
|
uint8 PAL = 0;
|
||||||
|
|
||||||
static DECLFW(BRAML)
|
static DECLFW(BRAML) {
|
||||||
{
|
|
||||||
RAM[A] = V;
|
RAM[A] = V;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DECLFR(ARAML)
|
static DECLFR(ARAML) {
|
||||||
{
|
|
||||||
return RAM[A];
|
return RAM[A];
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef COPYFAMI
|
#ifndef COPYFAMI
|
||||||
static DECLFW(BRAMH)
|
static DECLFW(BRAMH) {
|
||||||
{
|
|
||||||
RAM[A & 0x7FF] = V;
|
RAM[A & 0x7FF] = V;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DECLFR(ARAMH)
|
static DECLFR(ARAMH) {
|
||||||
{
|
|
||||||
return RAM[A & 0x7FF];
|
return RAM[A & 0x7FF];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void FCEUI_CloseGame(void)
|
static void CloseGame(void) {
|
||||||
{
|
if (GameInfo) {
|
||||||
if (!GameInfo)
|
if (FCEUnetplay)
|
||||||
return;
|
FCEUD_NetworkClose();
|
||||||
|
if (GameInfo->name) {
|
||||||
if (GameInfo->name)
|
free(GameInfo->name);
|
||||||
free(GameInfo->name);
|
GameInfo->name = 0;
|
||||||
GameInfo->name = 0;
|
}
|
||||||
if (GameInfo->type != GIT_NSF)
|
if (GameInfo->type != GIT_NSF)
|
||||||
FCEU_FlushGameCheats(0, 0);
|
FCEU_FlushGameCheats(0, 0);
|
||||||
GameInterface(GI_CLOSE);
|
GameInterface(GI_CLOSE);
|
||||||
ResetExState(0, 0);
|
ResetExState(0, 0);
|
||||||
FCEU_CloseGenie();
|
FCEU_CloseGenie();
|
||||||
free(GameInfo);
|
free(GameInfo);
|
||||||
GameInfo = 0;
|
GameInfo = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetGameLoaded(void)
|
void ResetGameLoaded(void) {
|
||||||
{
|
if (GameInfo) CloseGame();
|
||||||
if (GameInfo)
|
|
||||||
FCEUI_CloseGame();
|
|
||||||
|
|
||||||
GameStateRestore = NULL;
|
GameStateRestore = NULL;
|
||||||
PPU_hook = NULL;
|
PPU_hook = NULL;
|
||||||
GameHBIRQHook = NULL;
|
GameHBIRQHook = NULL;
|
||||||
|
|
||||||
if (GameExpSound.Kill)
|
if (GameExpSound.Kill)
|
||||||
GameExpSound.Kill();
|
GameExpSound.Kill();
|
||||||
memset(&GameExpSound, 0, sizeof(GameExpSound));
|
memset(&GameExpSound, 0, sizeof(GameExpSound));
|
||||||
|
|
||||||
MapIRQHook = NULL;
|
MapIRQHook = NULL;
|
||||||
MMC5Hack = 0;
|
MMC5Hack = 0;
|
||||||
PEC586Hack = 0;
|
PEC586Hack = 0;
|
||||||
@@ -227,77 +208,79 @@ int iNESLoad(const char *name, FCEUFILE *fp);
|
|||||||
int FDSLoad(const char *name, FCEUFILE *fp);
|
int FDSLoad(const char *name, FCEUFILE *fp);
|
||||||
int NSFLoad(FCEUFILE *fp);
|
int NSFLoad(FCEUFILE *fp);
|
||||||
|
|
||||||
FCEUGI *FCEUI_LoadGame(const char *name, uint8_t *databuf, size_t databufsize)
|
FCEUGI *FCEUI_LoadGame(const char *name) {
|
||||||
{
|
FCEUFILE *fp;
|
||||||
FCEUFILE *fp;
|
char *ipsfn;
|
||||||
|
|
||||||
ResetGameLoaded();
|
ResetGameLoaded();
|
||||||
|
|
||||||
GameInfo = malloc(sizeof(FCEUGI));
|
GameInfo = malloc(sizeof(FCEUGI));
|
||||||
memset(GameInfo, 0, sizeof(FCEUGI));
|
memset(GameInfo, 0, sizeof(FCEUGI));
|
||||||
|
|
||||||
GameInfo->soundchan = 0;
|
GameInfo->soundchan = 0;
|
||||||
GameInfo->soundrate = 0;
|
GameInfo->soundrate = 0;
|
||||||
GameInfo->name = 0;
|
GameInfo->name = 0;
|
||||||
GameInfo->type = GIT_CART;
|
GameInfo->type = GIT_CART;
|
||||||
GameInfo->vidsys = GIV_USER;
|
GameInfo->vidsys = GIV_USER;
|
||||||
GameInfo->input[0] = GameInfo->input[1] = -1;
|
GameInfo->input[0] = GameInfo->input[1] = -1;
|
||||||
GameInfo->inputfc = -1;
|
GameInfo->inputfc = -1;
|
||||||
GameInfo->cspecial = 0;
|
GameInfo->cspecial = 0;
|
||||||
|
|
||||||
FCEU_printf("Loading %s...\n\n", name);
|
FCEU_printf("Loading %s...\n\n", name);
|
||||||
|
|
||||||
GetFileBase(name);
|
GetFileBase(name);
|
||||||
|
|
||||||
fp = FCEU_fopen(name, NULL, "rb", 0, databuf, databufsize);
|
ipsfn = FCEU_MakeFName(FCEUMKF_IPS, 0, 0);
|
||||||
|
fp = FCEU_fopen(name, ipsfn, "rb", 0);
|
||||||
|
free(ipsfn);
|
||||||
|
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
FCEU_PrintError("Error opening \"%s\"!", name);
|
FCEU_PrintError("Error opening \"%s\"!", name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iNESLoad(name, fp))
|
if (iNESLoad(name, fp))
|
||||||
goto endlseq;
|
goto endlseq;
|
||||||
if (NSFLoad(fp))
|
if (NSFLoad(fp))
|
||||||
goto endlseq;
|
goto endlseq;
|
||||||
if (UNIFLoad(name, fp))
|
if (UNIFLoad(name, fp))
|
||||||
goto endlseq;
|
goto endlseq;
|
||||||
if (FDSLoad(name, fp))
|
if (FDSLoad(name, fp))
|
||||||
goto endlseq;
|
goto endlseq;
|
||||||
|
|
||||||
FCEU_PrintError("An error occurred while loading the file.");
|
FCEU_PrintError("An error occurred while loading the file.");
|
||||||
FCEU_fclose(fp);
|
FCEU_fclose(fp);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
endlseq:
|
endlseq:
|
||||||
FCEU_fclose(fp);
|
FCEU_fclose(fp);
|
||||||
|
|
||||||
FCEU_ResetVidSys();
|
FCEU_ResetVidSys();
|
||||||
if (GameInfo->type != GIT_NSF)
|
if (GameInfo->type != GIT_NSF)
|
||||||
if (FSettings.GameGenie)
|
if (FSettings.GameGenie)
|
||||||
FCEU_OpenGenie();
|
FCEU_OpenGenie();
|
||||||
|
|
||||||
PowerNES();
|
PowerNES();
|
||||||
FCEUSS_CheckStates();
|
FCEUSS_CheckStates();
|
||||||
|
FCEUMOV_CheckMovies();
|
||||||
|
|
||||||
if (GameInfo->type != GIT_NSF) {
|
if (GameInfo->type != GIT_NSF) {
|
||||||
FCEU_LoadGamePalette();
|
FCEU_LoadGamePalette();
|
||||||
FCEU_LoadGameCheats(0);
|
FCEU_LoadGameCheats(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
FCEU_ResetPalette();
|
FCEU_ResetPalette();
|
||||||
FCEU_ResetMessages(); // Save state, status messages, etc.
|
FCEU_ResetMessages(); // Save state, status messages, etc.
|
||||||
|
|
||||||
return(GameInfo);
|
return(GameInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CopyFamiLoad(void);
|
int CopyFamiLoad(void);
|
||||||
|
|
||||||
FCEUGI *FCEUI_CopyFamiStart(void)
|
FCEUGI *FCEUI_CopyFamiStart(void) {
|
||||||
{
|
|
||||||
ResetGameLoaded();
|
ResetGameLoaded();
|
||||||
|
|
||||||
GameInfo = (FCEUGI*)malloc(sizeof(FCEUGI));
|
GameInfo = malloc(sizeof(FCEUGI));
|
||||||
memset(GameInfo, 0, sizeof(FCEUGI));
|
memset(GameInfo, 0, sizeof(FCEUGI));
|
||||||
|
|
||||||
GameInfo->soundchan = 0;
|
GameInfo->soundchan = 0;
|
||||||
@@ -323,6 +306,7 @@ FCEUGI *FCEUI_CopyFamiStart(void)
|
|||||||
|
|
||||||
PowerNES();
|
PowerNES();
|
||||||
FCEUSS_CheckStates();
|
FCEUSS_CheckStates();
|
||||||
|
FCEUMOV_CheckMovies();
|
||||||
|
|
||||||
if (GameInfo->type != GIT_NSF) {
|
if (GameInfo->type != GIT_NSF) {
|
||||||
FCEU_LoadGamePalette();
|
FCEU_LoadGamePalette();
|
||||||
@@ -372,19 +356,20 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
|||||||
*SoundBufSize = ssize;
|
*SoundBufSize = ssize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FCEUI_CloseGame(void) {
|
||||||
|
CloseGame();
|
||||||
|
}
|
||||||
|
|
||||||
void ResetNES(void)
|
void ResetNES(void) {
|
||||||
{
|
FCEUMOV_AddCommand(FCEUNPCMD_RESET);
|
||||||
if (!GameInfo)
|
if (!GameInfo) return;
|
||||||
return;
|
|
||||||
GameInterface(GI_RESETM2);
|
GameInterface(GI_RESETM2);
|
||||||
FCEUSND_Reset();
|
FCEUSND_Reset();
|
||||||
FCEUPPU_Reset();
|
FCEUPPU_Reset();
|
||||||
X6502_Reset();
|
X6502_Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEU_MemoryRand(uint8 *ptr, uint32 size)
|
void FCEU_MemoryRand(uint8 *ptr, uint32 size) {
|
||||||
{
|
|
||||||
int x = 0;
|
int x = 0;
|
||||||
while (size) {
|
while (size) {
|
||||||
// *ptr = (x & 4) ? 0xFF : 0x00; // Huang Di DEBUG MODE enabled by default
|
// *ptr = (x & 4) ? 0xFF : 0x00; // Huang Di DEBUG MODE enabled by default
|
||||||
@@ -401,14 +386,12 @@ void FCEU_MemoryRand(uint8 *ptr, uint32 size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hand(X6502 *X, int type, uint32 A)
|
void hand(X6502 *X, int type, uint32 A) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowerNES(void)
|
void PowerNES(void) {
|
||||||
{
|
FCEUMOV_AddCommand(FCEUNPCMD_POWER);
|
||||||
if (!GameInfo)
|
if (!GameInfo) return;
|
||||||
return;
|
|
||||||
|
|
||||||
FCEU_CheatResetRAM();
|
FCEU_CheatResetRAM();
|
||||||
FCEU_CheatAddRAM(2, 0, RAM);
|
FCEU_CheatAddRAM(2, 0, RAM);
|
||||||
@@ -443,13 +426,13 @@ void PowerNES(void)
|
|||||||
if (GameInfo->type == GIT_VSUNI)
|
if (GameInfo->type == GIT_VSUNI)
|
||||||
FCEU_VSUniPower();
|
FCEU_VSUniPower();
|
||||||
|
|
||||||
|
|
||||||
timestampbase = 0;
|
timestampbase = 0;
|
||||||
X6502_Power();
|
X6502_Power();
|
||||||
FCEU_PowerCheats();
|
FCEU_PowerCheats();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEU_ResetVidSys(void)
|
void FCEU_ResetVidSys(void) {
|
||||||
{
|
|
||||||
int w;
|
int w;
|
||||||
|
|
||||||
if (GameInfo->vidsys == GIV_NTSC)
|
if (GameInfo->vidsys == GIV_NTSC)
|
||||||
@@ -467,8 +450,8 @@ void FCEU_ResetVidSys(void)
|
|||||||
|
|
||||||
FCEUS FSettings;
|
FCEUS FSettings;
|
||||||
|
|
||||||
void FCEU_printf(char *format, ...)
|
void FCEU_printf(char *format, ...) {
|
||||||
{
|
FILE *ofile;
|
||||||
char temp[2048];
|
char temp[2048];
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@@ -477,11 +460,14 @@ void FCEU_printf(char *format, ...)
|
|||||||
vsprintf(temp, format, ap);
|
vsprintf(temp, format, ap);
|
||||||
FCEUD_Message(temp);
|
FCEUD_Message(temp);
|
||||||
|
|
||||||
|
ofile = fopen("stdout.txt", "ab");
|
||||||
|
fwrite(temp, 1, strlen(temp), ofile);
|
||||||
|
fclose(ofile);
|
||||||
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEU_PrintError(char *format, ...)
|
void FCEU_PrintError(char *format, ...) {
|
||||||
{
|
|
||||||
char temp[2048];
|
char temp[2048];
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@@ -493,37 +479,29 @@ void FCEU_PrintError(char *format, ...)
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall)
|
void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall) {
|
||||||
{
|
|
||||||
FSettings.UsrFirstSLine[0] = ntscf;
|
FSettings.UsrFirstSLine[0] = ntscf;
|
||||||
FSettings.UsrLastSLine[0] = ntscl;
|
FSettings.UsrLastSLine[0] = ntscl;
|
||||||
FSettings.UsrFirstSLine[1] = palf;
|
FSettings.UsrFirstSLine[1] = palf;
|
||||||
FSettings.UsrLastSLine[1] = pall;
|
FSettings.UsrLastSLine[1] = pall;
|
||||||
if (PAL)
|
if (PAL) {
|
||||||
{
|
|
||||||
FSettings.FirstSLine = FSettings.UsrFirstSLine[1];
|
FSettings.FirstSLine = FSettings.UsrFirstSLine[1];
|
||||||
FSettings.LastSLine = FSettings.UsrLastSLine[1];
|
FSettings.LastSLine = FSettings.UsrLastSLine[1];
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
FSettings.FirstSLine = FSettings.UsrFirstSLine[0];
|
FSettings.FirstSLine = FSettings.UsrFirstSLine[0];
|
||||||
FSettings.LastSLine = FSettings.UsrLastSLine[0];
|
FSettings.LastSLine = FSettings.UsrLastSLine[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEUI_SetVidSystem(int a)
|
void FCEUI_SetVidSystem(int a) {
|
||||||
{
|
|
||||||
FSettings.PAL = a ? 1 : 0;
|
FSettings.PAL = a ? 1 : 0;
|
||||||
|
if (GameInfo) {
|
||||||
if (!GameInfo)
|
FCEU_ResetVidSys();
|
||||||
return;
|
FCEU_ResetPalette();
|
||||||
|
}
|
||||||
FCEU_ResetVidSys();
|
|
||||||
FCEU_ResetPalette();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int FCEUI_GetCurrentVidSystem(int *slstart, int *slend)
|
int FCEUI_GetCurrentVidSystem(int *slstart, int *slend) {
|
||||||
{
|
|
||||||
if (slstart)
|
if (slstart)
|
||||||
*slstart = FSettings.FirstSLine;
|
*slstart = FSettings.FirstSLine;
|
||||||
if (slend)
|
if (slend)
|
||||||
@@ -531,18 +509,15 @@ int FCEUI_GetCurrentVidSystem(int *slstart, int *slend)
|
|||||||
return(PAL);
|
return(PAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEUI_SetGameGenie(int a)
|
void FCEUI_SetGameGenie(int a) {
|
||||||
{
|
|
||||||
FSettings.GameGenie = a ? 1 : 0;
|
FSettings.GameGenie = a ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEUI_SetSnapName(int a)
|
void FCEUI_SetSnapName(int a) {
|
||||||
{
|
|
||||||
FSettings.SnapName = a;
|
FSettings.SnapName = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 FCEUI_GetDesiredFPS(void)
|
int32 FCEUI_GetDesiredFPS(void) {
|
||||||
{
|
|
||||||
if (PAL)
|
if (PAL)
|
||||||
return(838977920); // ~50.007
|
return(838977920); // ~50.007
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -614,7 +614,7 @@ int FDSLoad(const char *name, FCEUFILE *fp) {
|
|||||||
|
|
||||||
char *fn = FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0);
|
char *fn = FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0);
|
||||||
|
|
||||||
if (!(zp = fopen(fn, "rb"))) {
|
if (!(zp = FCEUD_UTF8fopen(fn, "rb"))) {
|
||||||
FCEU_PrintError("FDS BIOS ROM image missing!");
|
FCEU_PrintError("FDS BIOS ROM image missing!");
|
||||||
free(fn);
|
free(fn);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -669,7 +669,7 @@ int FDSLoad(const char *name, FCEUFILE *fp) {
|
|||||||
memcpy(diskdatao[x], diskdata[x], 65500);
|
memcpy(diskdatao[x], diskdata[x], 65500);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((tp = FCEU_fopen(fn, 0, "rb", 0, NULL, 0))) {
|
if ((tp = FCEU_fopen(fn, 0, "rb", 0))) {
|
||||||
FCEU_printf("Disk was written. Auxillary FDS file open \"%s\".\n", fn);
|
FCEU_printf("Disk was written. Auxillary FDS file open \"%s\".\n", fn);
|
||||||
FreeFDSMemory();
|
FreeFDSMemory();
|
||||||
if (!SubLoad(tp)) {
|
if (!SubLoad(tp)) {
|
||||||
@@ -737,7 +737,7 @@ void FDSClose(void) {
|
|||||||
|
|
||||||
if (!DiskWritten) return;
|
if (!DiskWritten) return;
|
||||||
|
|
||||||
if (!(fp = fopen(fn, "wb"))) {
|
if (!(fp = FCEUD_UTF8fopen(fn, "wb"))) {
|
||||||
free(fn);
|
free(fn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
536
src/file.c
536
src/file.c
@@ -27,6 +27,9 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "zlib.h"
|
||||||
|
#include "unzip.h"
|
||||||
|
|
||||||
#include "fceu-types.h"
|
#include "fceu-types.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "fceu-endian.h"
|
#include "fceu-endian.h"
|
||||||
@@ -34,152 +37,451 @@
|
|||||||
#include "driver.h"
|
#include "driver.h"
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8 *data;
|
||||||
|
uint32 size;
|
||||||
|
uint32 location;
|
||||||
|
} MEMWRAP;
|
||||||
|
|
||||||
|
void ApplyIPS(FILE *ips, MEMWRAP *dest) {
|
||||||
|
uint8 header[5];
|
||||||
|
uint32 count = 0;
|
||||||
|
|
||||||
|
FCEU_printf(" Applying IPS...\n");
|
||||||
|
if (fread(header, 1, 5, ips) != 5) {
|
||||||
|
fclose(ips);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (memcmp(header, "PATCH", 5)) {
|
||||||
|
fclose(ips);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fread(header, 1, 3, ips) == 3) {
|
||||||
|
uint32 offset = (header[0] << 16) | (header[1] << 8) | header[2];
|
||||||
|
uint16 size;
|
||||||
|
|
||||||
|
if (!memcmp(header, "EOF", 3)) {
|
||||||
|
FCEU_printf(" IPS EOF: Did %d patches\n\n", count);
|
||||||
|
fclose(ips);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = fgetc(ips) << 8;
|
||||||
|
size |= fgetc(ips);
|
||||||
|
if (!size) { /* RLE */
|
||||||
|
uint8 *start;
|
||||||
|
uint8 b;
|
||||||
|
size = fgetc(ips) << 8;
|
||||||
|
size |= fgetc(ips);
|
||||||
|
|
||||||
|
//FCEU_printf(" Offset: %8d Size: %5d RLE\n",offset,size);
|
||||||
|
|
||||||
|
if ((offset + size) > dest->size) {
|
||||||
|
uint8 *tmp;
|
||||||
|
|
||||||
|
// Probably a little slow.
|
||||||
|
tmp = (uint8*)realloc(dest->data, offset + size);
|
||||||
|
if (!tmp) {
|
||||||
|
FCEU_printf(" Oops. IPS patch %d(type RLE) goes beyond end of file. Could not allocate memory.\n", count);
|
||||||
|
fclose(ips);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dest->size = offset + size;
|
||||||
|
dest->data = tmp;
|
||||||
|
memset(dest->data + dest->size, 0, offset + size - dest->size);
|
||||||
|
}
|
||||||
|
b = fgetc(ips);
|
||||||
|
start = dest->data + offset;
|
||||||
|
do {
|
||||||
|
*start = b;
|
||||||
|
start++;
|
||||||
|
} while (--size);
|
||||||
|
} else { /* Normal patch */
|
||||||
|
//FCEU_printf(" Offset: %8d Size: %5d\n",offset,size);
|
||||||
|
if ((offset + size) > dest->size) {
|
||||||
|
uint8 *tmp;
|
||||||
|
|
||||||
|
// Probably a little slow.
|
||||||
|
tmp = (uint8*)realloc(dest->data, offset + size);
|
||||||
|
if (!tmp) {
|
||||||
|
FCEU_printf(" Oops. IPS patch %d(type normal) goes beyond end of file. Could not allocate memory.\n", count);
|
||||||
|
fclose(ips);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dest->data = tmp;
|
||||||
|
memset(dest->data + dest->size, 0, offset + size - dest->size);
|
||||||
|
}
|
||||||
|
fread(dest->data + offset, 1, size, ips);
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
fclose(ips);
|
||||||
|
FCEU_printf(" Hard IPS end!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static MEMWRAP *MakeMemWrap(void *tz, int type) {
|
||||||
|
MEMWRAP *tmp;
|
||||||
|
|
||||||
|
if (!(tmp = (MEMWRAP*)FCEU_malloc(sizeof(MEMWRAP))))
|
||||||
|
goto doret;
|
||||||
|
tmp->location = 0;
|
||||||
|
|
||||||
|
if (type == 0) {
|
||||||
|
fseek((FILE*)tz, 0, SEEK_END);
|
||||||
|
tmp->size = ftell((FILE*)tz);
|
||||||
|
fseek((FILE*)tz, 0, SEEK_SET);
|
||||||
|
if (!(tmp->data = (uint8*)FCEU_malloc(tmp->size))) {
|
||||||
|
free(tmp);
|
||||||
|
tmp = 0;
|
||||||
|
goto doret;
|
||||||
|
}
|
||||||
|
fread(tmp->data, 1, tmp->size, (FILE*)tz);
|
||||||
|
}
|
||||||
|
else if (type == 1) {
|
||||||
|
/* Bleck. The gzip file format has the size of the uncompressed data,
|
||||||
|
but I can't get to the info with the zlib interface(?). */
|
||||||
|
for (tmp->size = 0; gzgetc(tz) != EOF; tmp->size++) ;
|
||||||
|
gzseek(tz, 0, SEEK_SET);
|
||||||
|
if (!(tmp->data = (uint8*)FCEU_malloc(tmp->size))) {
|
||||||
|
free(tmp);
|
||||||
|
tmp = 0;
|
||||||
|
goto doret;
|
||||||
|
}
|
||||||
|
gzread(tz, tmp->data, tmp->size);
|
||||||
|
} else if (type == 2) {
|
||||||
|
unz_file_info ufo;
|
||||||
|
unzGetCurrentFileInfo(tz, &ufo, 0, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
tmp->size = ufo.uncompressed_size;
|
||||||
|
if (!(tmp->data = (uint8*)FCEU_malloc(ufo.uncompressed_size))) {
|
||||||
|
free(tmp);
|
||||||
|
tmp = 0;
|
||||||
|
goto doret;
|
||||||
|
}
|
||||||
|
unzReadCurrentFile(tz, tmp->data, ufo.uncompressed_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
doret:
|
||||||
|
if (type == 0) {
|
||||||
|
fclose((FILE*)tz);
|
||||||
|
}
|
||||||
|
else if (type == 1) {
|
||||||
|
gzclose(tz);
|
||||||
|
} else if (type == 2) {
|
||||||
|
unzCloseCurrentFile(tz);
|
||||||
|
unzClose(tz);
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef __GNUC__
|
#ifndef __GNUC__
|
||||||
#define strcasecmp strcmp
|
#define strcasecmp strcmp
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static MEMWRAP *MakeMemWrap(void *tz, int type)
|
|
||||||
{
|
|
||||||
MEMWRAP *tmp;
|
|
||||||
|
|
||||||
if (!(tmp = (MEMWRAP*)FCEU_malloc(sizeof(MEMWRAP))))
|
FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, char *mode, char *ext) {
|
||||||
goto doret;
|
FILE *ipsfile = 0;
|
||||||
tmp->location = 0;
|
FCEUFILE *fceufp;
|
||||||
|
void *t;
|
||||||
|
|
||||||
fseek((FILE*)tz, 0, SEEK_END);
|
if (strchr(mode, 'r'))
|
||||||
tmp->size = ftell((FILE*)tz);
|
ipsfile = FCEUD_UTF8fopen(ipsfn, "rb");
|
||||||
fseek((FILE*)tz, 0, SEEK_SET);
|
|
||||||
if (!(tmp->data = (uint8*)FCEU_malloc(tmp->size)))
|
|
||||||
{
|
|
||||||
free(tmp);
|
|
||||||
tmp = 0;
|
|
||||||
goto doret;
|
|
||||||
}
|
|
||||||
fread(tmp->data, 1, tmp->size, (FILE*)tz);
|
|
||||||
|
|
||||||
doret:
|
fceufp = (FCEUFILE*)malloc(sizeof(FCEUFILE));
|
||||||
if (type == 0)
|
|
||||||
fclose((FILE*)tz);
|
{
|
||||||
return tmp;
|
unzFile tz;
|
||||||
|
if ((tz = unzOpen(path))) { // If it's not a zip file, use regular file handlers.
|
||||||
|
// Assuming file type by extension usually works,
|
||||||
|
// but I don't like it. :)
|
||||||
|
if (unzGoToFirstFile(tz) == UNZ_OK) {
|
||||||
|
for (;; ) {
|
||||||
|
char tempu[512];// Longer filenames might be possible, but I don't
|
||||||
|
// think people would name files that long in zip files...
|
||||||
|
unzGetCurrentFileInfo(tz, 0, tempu, 512, 0, 0, 0, 0);
|
||||||
|
tempu[511] = 0;
|
||||||
|
if (strlen(tempu) >= 4) {
|
||||||
|
char *za = tempu + strlen(tempu) - 4;
|
||||||
|
|
||||||
|
if (!ext) {
|
||||||
|
if (!strcasecmp(za, ".nes") || !strcasecmp(za, ".fds") ||
|
||||||
|
!strcasecmp(za, ".nsf") || !strcasecmp(za, ".unf") ||
|
||||||
|
!strcasecmp(za, ".nez"))
|
||||||
|
break;
|
||||||
|
} else if (!strcasecmp(za, ext))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strlen(tempu) >= 5) {
|
||||||
|
if (!strcasecmp(tempu + strlen(tempu) - 5, ".unif"))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (unzGoToNextFile(tz) != UNZ_OK) {
|
||||||
|
if (unzGoToFirstFile(tz) != UNZ_OK) goto zpfail;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (unzOpenCurrentFile(tz) != UNZ_OK)
|
||||||
|
goto zpfail;
|
||||||
|
} else {
|
||||||
|
zpfail:
|
||||||
|
free(fceufp);
|
||||||
|
unzClose(tz);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!(fceufp->fp = MakeMemWrap(tz, 2))) {
|
||||||
|
free(fceufp);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
fceufp->type = 2;
|
||||||
|
if (ipsfile)
|
||||||
|
ApplyIPS(ipsfile, (MEMWRAP*)fceufp->fp);
|
||||||
|
return(fceufp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((t = FCEUD_UTF8fopen(path, "rb"))) {
|
||||||
|
uint32 magic;
|
||||||
|
|
||||||
|
magic = fgetc((FILE*)t);
|
||||||
|
magic |= fgetc((FILE*)t) << 8;
|
||||||
|
magic |= fgetc((FILE*)t) << 16;
|
||||||
|
|
||||||
|
if (magic != 0x088b1f) /* Not gzip... */
|
||||||
|
fclose((FILE*)t);
|
||||||
|
else { /* Probably gzip */
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = dup(fileno((FILE*)t));
|
||||||
|
|
||||||
|
fclose(t);
|
||||||
|
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
|
||||||
|
if ((t = gzdopen(fd, mode))) {
|
||||||
|
fceufp->type = 1;
|
||||||
|
fceufp->fp = t;
|
||||||
|
if (ipsfile) {
|
||||||
|
fceufp->fp = MakeMemWrap(t, 1);
|
||||||
|
gzclose(t);
|
||||||
|
|
||||||
|
if (fceufp->fp) {
|
||||||
|
free(fceufp);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fceufp->type = 3;
|
||||||
|
ApplyIPS(ipsfile, (MEMWRAP*)fceufp->fp);
|
||||||
|
}
|
||||||
|
return(fceufp);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((t = FCEUD_UTF8fopen(path, mode))) {
|
||||||
|
fseek((FILE*)t, 0, SEEK_SET);
|
||||||
|
fceufp->type = 0;
|
||||||
|
fceufp->fp = t;
|
||||||
|
if (ipsfile) {
|
||||||
|
if (!(fceufp->fp = MakeMemWrap(t, 0))) {
|
||||||
|
free(fceufp);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
fceufp->type = 3;
|
||||||
|
ApplyIPS(ipsfile, (MEMWRAP*)fceufp->fp);
|
||||||
|
}
|
||||||
|
return(fceufp);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(fceufp);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MEMWRAP *MakeMemWrapBuffer(void *tz, int type, uint8 *buffer, size_t bufsize)
|
int FCEU_fclose(FCEUFILE *fp) {
|
||||||
{
|
if (fp->type == 1) {
|
||||||
MEMWRAP *tmp = (MEMWRAP*)FCEU_malloc(sizeof(MEMWRAP));
|
gzclose(fp->fp);
|
||||||
|
} else if (fp->type >= 2) {
|
||||||
if (!tmp)
|
free(((MEMWRAP*)(fp->fp))->data);
|
||||||
return NULL;
|
((MEMWRAP*)(fp->fp))->data = 0;
|
||||||
|
free(fp->fp);
|
||||||
tmp->location = 0;
|
fp->fp = 0;
|
||||||
tmp->size = bufsize;
|
} else
|
||||||
tmp->data = buffer;
|
{
|
||||||
|
fclose((FILE*)fp->fp);
|
||||||
return tmp;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn,
|
|
||||||
char *mode, char *ext, uint8 *buffer, size_t bufsize)
|
|
||||||
{
|
|
||||||
FCEUFILE *fceufp = (FCEUFILE*)malloc(sizeof(FCEUFILE));
|
|
||||||
void *t = fopen(path, mode);
|
|
||||||
|
|
||||||
if (!t)
|
|
||||||
{
|
|
||||||
free(fceufp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fseek((FILE*)t, 0, SEEK_SET);
|
|
||||||
fceufp->type = 0;
|
|
||||||
if (buffer)
|
|
||||||
fceufp->fp = MakeMemWrapBuffer(t, 0, buffer, bufsize);
|
|
||||||
else
|
|
||||||
fceufp->fp = MakeMemWrap(t, 0);
|
|
||||||
return fceufp;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FCEU_fclose(FCEUFILE *fp)
|
|
||||||
{
|
|
||||||
if (fp->fp)
|
|
||||||
free(fp->fp);
|
|
||||||
fp->fp = NULL;
|
|
||||||
free(fp);
|
free(fp);
|
||||||
fp = 0;
|
fp = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 FCEU_fread(void *ptr, size_t element_size, size_t nmemb, FCEUFILE *fp)
|
uint64 FCEU_fread(void *ptr, size_t size, size_t nmemb, FCEUFILE *fp) {
|
||||||
{
|
if (fp->type == 1) {
|
||||||
uint32_t total = nmemb * element_size;
|
return gzread(fp->fp, ptr, size * nmemb);
|
||||||
|
} else if (fp->type >= 2) {
|
||||||
|
MEMWRAP *wz;
|
||||||
|
uint32 total = size * nmemb;
|
||||||
|
|
||||||
if (fp->fp->location >= fp->fp->size)
|
wz = (MEMWRAP*)fp->fp;
|
||||||
return 0;
|
if (wz->location >= wz->size) return 0;
|
||||||
|
|
||||||
if((fp->fp->location + total) > fp->fp->size)
|
if ((wz->location + total) > wz->size) {
|
||||||
{
|
int ak = wz->size - wz->location;
|
||||||
int64_t ak = fp->fp->size - fp->fp->location;
|
memcpy((uint8*)ptr, wz->data + wz->location, ak);
|
||||||
|
wz->location = wz->size;
|
||||||
memcpy((uint8_t*)ptr, fp->fp->data + fp->fp->location, ak);
|
return(ak / size);
|
||||||
|
} else {
|
||||||
fp->fp->location = fp->fp->size;
|
memcpy((uint8*)ptr, wz->data + wz->location, total);
|
||||||
|
wz->location += total;
|
||||||
return (ak / element_size);
|
return nmemb;
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
memcpy((uint8_t*)ptr, fp->fp->data + fp->fp->location, total);
|
{
|
||||||
|
return fread(ptr, size, nmemb, (FILE*)fp->fp);
|
||||||
fp->fp->location += total;
|
}
|
||||||
|
|
||||||
return nmemb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int FCEU_fseek(FCEUFILE *fp, long offset, int whence)
|
uint64 FCEU_fwrite(void *ptr, size_t size, size_t nmemb, FCEUFILE *fp) {
|
||||||
{
|
if (fp->type == 1) {
|
||||||
switch (whence)
|
return gzwrite(fp->fp, ptr, size * nmemb);
|
||||||
{
|
} else if (fp->type >= 2) {
|
||||||
case SEEK_SET:
|
return 0;
|
||||||
if (offset >= fp->fp->size)
|
} else
|
||||||
return -1;
|
return fwrite(ptr, size, nmemb, (FILE*)fp->fp);
|
||||||
|
}
|
||||||
|
|
||||||
fp->fp->location = offset;
|
int FCEU_fseek(FCEUFILE *fp, long offset, int whence) {
|
||||||
break;
|
if (fp->type == 1) {
|
||||||
case SEEK_CUR:
|
return((gzseek(fp->fp, offset, whence) > 0) ? 0 : -1);
|
||||||
if ((offset + fp->fp->location) > fp->fp->size)
|
} else if (fp->type >= 2) {
|
||||||
return -1;
|
MEMWRAP *wz;
|
||||||
|
wz = (MEMWRAP*)fp->fp;
|
||||||
|
|
||||||
fp->fp->location += offset;
|
switch (whence) {
|
||||||
break;
|
case SEEK_SET: if (offset >= wz->size)
|
||||||
}
|
return(-1);
|
||||||
|
wz->location = offset; break;
|
||||||
|
case SEEK_CUR: if (offset + wz->location > wz->size)
|
||||||
|
return(-1);
|
||||||
|
wz->location += offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else
|
||||||
|
return fseek((FILE*)fp->fp, offset, whence);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
uint64 FCEU_ftell(FCEUFILE *fp) {
|
||||||
|
if (fp->type == 1) {
|
||||||
|
return gztell(fp->fp);
|
||||||
|
} else if (fp->type >= 2) {
|
||||||
|
return(((MEMWRAP*)(fp->fp))->location);
|
||||||
|
} else
|
||||||
|
return ftell((FILE*)fp->fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_rewind(FCEUFILE *fp) {
|
||||||
|
if (fp->type == 1) {
|
||||||
|
gzrewind(fp->fp);
|
||||||
|
} else if (fp->type >= 2) {
|
||||||
|
((MEMWRAP*)(fp->fp))->location = 0;
|
||||||
|
} else
|
||||||
|
/* Rewind */
|
||||||
|
fseek(fp->fp, 0, SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FCEU_read16le(uint16 *val, FCEUFILE *fp) {
|
||||||
|
uint8 t[2];
|
||||||
|
|
||||||
|
if (fp->type >= 1) {
|
||||||
|
if (fp->type >= 2) {
|
||||||
|
MEMWRAP *wz;
|
||||||
|
wz = (MEMWRAP*)fp->fp;
|
||||||
|
if (wz->location + 2 > wz->size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*(uint32*)t = *(uint32*)(wz->data + wz->location);
|
||||||
|
wz->location += 2;
|
||||||
|
} else if (fp->type == 1)
|
||||||
|
if (gzread(fp->fp, &t, 2) != 2) return(0);
|
||||||
|
return(1);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
if (fread(t, 1, 2, (FILE*)fp->fp) != 2) return(0);
|
||||||
|
}
|
||||||
|
*val = t[0] | (t[1] << 8);
|
||||||
|
return(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int FCEU_read32le(uint32 *Bufo, FCEUFILE *fp)
|
int FCEU_read32le(uint32 *Bufo, FCEUFILE *fp)
|
||||||
{
|
{
|
||||||
if ((fp->fp->location + 4) > fp->fp->size)
|
if (fp->type >= 1) {
|
||||||
return 0;
|
uint8 t[4];
|
||||||
|
#ifdef MSB_FIRST
|
||||||
*Bufo = FCEU_de32lsb(fp->fp->data + fp->fp->location);
|
uint8 x[4];
|
||||||
|
#endif
|
||||||
fp->fp->location += 4;
|
if (fp->type >= 2) {
|
||||||
|
MEMWRAP *wz;
|
||||||
return 1;
|
wz = (MEMWRAP*)fp->fp;
|
||||||
|
if (wz->location + 4 > wz->size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*(uint32*)t = *(uint32*)(wz->data + wz->location);
|
||||||
|
wz->location += 4;
|
||||||
|
} else if (fp->type == 1)
|
||||||
|
gzread(fp->fp, &t, 4);
|
||||||
|
#ifdef MSB_FIRST
|
||||||
|
x[0] = t[3];
|
||||||
|
x[1] = t[2];
|
||||||
|
x[2] = t[1];
|
||||||
|
x[3] = t[0];
|
||||||
|
*(uint32*)Bufo = *(uint32*)x;
|
||||||
|
#else
|
||||||
|
*(uint32*)Bufo = *(uint32*)t;
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return read32le(Bufo, (FILE*)fp->fp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int FCEU_fgetc(FCEUFILE *fp)
|
int FCEU_fgetc(FCEUFILE *fp) {
|
||||||
{
|
if (fp->type == 1)
|
||||||
if (fp->fp->location < fp->fp->size)
|
return gzgetc(fp->fp);
|
||||||
return fp->fp->data[fp->fp->location++];
|
else if (fp->type >= 2) {
|
||||||
|
MEMWRAP *wz;
|
||||||
return EOF;
|
wz = (MEMWRAP*)fp->fp;
|
||||||
|
if (wz->location < wz->size)
|
||||||
|
return wz->data[wz->location++];
|
||||||
|
return EOF;
|
||||||
|
} else
|
||||||
|
return fgetc((FILE*)fp->fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 FCEU_ftell(FCEUFILE *fp)
|
uint64 FCEU_fgetsize(FCEUFILE *fp) {
|
||||||
{
|
if (fp->type == 1) {
|
||||||
return fp->fp->location;
|
int x, t;
|
||||||
|
t = gztell(fp->fp);
|
||||||
|
gzrewind(fp->fp);
|
||||||
|
for (x = 0; gzgetc(fp->fp) != EOF; x++) ;
|
||||||
|
gzseek(fp->fp, t, SEEK_SET);
|
||||||
|
return(x);
|
||||||
|
} else if (fp->type >= 2)
|
||||||
|
return ((MEMWRAP*)(fp->fp))->size;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
long t, r;
|
||||||
|
t = ftell((FILE*)fp->fp);
|
||||||
|
fseek((FILE*)fp->fp, 0, SEEK_END);
|
||||||
|
r = ftell((FILE*)fp->fp);
|
||||||
|
fseek((FILE*)fp->fp, t, SEEK_SET);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 FCEU_fgetsize(FCEUFILE *fp)
|
int FCEU_fisarchive(FCEUFILE *fp) {
|
||||||
{
|
if (fp->type == 2)
|
||||||
return fp->fp->size;
|
return 1;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
213
src/general.c
213
src/general.c
@@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
#include "movie.h"
|
||||||
|
|
||||||
#include "driver.h"
|
#include "driver.h"
|
||||||
|
|
||||||
@@ -47,24 +48,22 @@ static char FileExt[2048]; /* Includes the . character, as in ".nes" */
|
|||||||
|
|
||||||
static char FileBaseDirectory[2048];
|
static char FileBaseDirectory[2048];
|
||||||
|
|
||||||
void FCEUI_SetBaseDirectory(char *dir)
|
void FCEUI_SetBaseDirectory(char *dir) {
|
||||||
{
|
|
||||||
strncpy(BaseDirectory, dir, 2047);
|
strncpy(BaseDirectory, dir, 2047);
|
||||||
BaseDirectory[2047] = 0;
|
BaseDirectory[2047] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *odirs[FCEUIOD__COUNT] = { 0, 0, 0, 0, 0, 0 }; // odirs, odors. ^_^
|
static char *odirs[FCEUIOD__COUNT] = { 0, 0, 0, 0, 0, 0 }; // odirs, odors. ^_^
|
||||||
|
|
||||||
void FCEUI_SetDirOverride(int which, char *n)
|
void FCEUI_SetDirOverride(int which, char *n) {
|
||||||
{
|
|
||||||
odirs[which] = n;
|
odirs[which] = n;
|
||||||
|
|
||||||
/* Rebuild cache of present states/movies. */
|
if (GameInfo) { /* Rebuild cache of present states/movies. */
|
||||||
if (GameInfo)
|
if (which == FCEUIOD_STATE)
|
||||||
{
|
FCEUSS_CheckStates();
|
||||||
if (which == FCEUIOD_STATE)
|
else if (which == FCEUIOD_MOVIE)
|
||||||
FCEUSS_CheckStates();
|
FCEUMOV_CheckMovies();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HAVE_ASPRINTF
|
#ifndef HAVE_ASPRINTF
|
||||||
@@ -81,82 +80,136 @@ static int asprintf(char **strp, const char *fmt, ...) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char *FCEU_MakeFName(int type, int id1, char *cd1)
|
char *FCEU_MakeFName(int type, int id1, char *cd1) {
|
||||||
{
|
char *ret = 0;
|
||||||
char *ret = 0;
|
struct stat tmpstat;
|
||||||
struct stat tmpstat;
|
|
||||||
|
|
||||||
switch (type)
|
switch (type) {
|
||||||
{
|
case FCEUMKF_NPTEMP: asprintf(&ret, "%s"PSS "m590plqd94fo.tmp", BaseDirectory); break;
|
||||||
case FCEUMKF_GGROM:
|
case FCEUMKF_MOVIE:
|
||||||
asprintf(&ret, "%s"PSS "gg.rom", BaseDirectory);
|
if (odirs[FCEUIOD_STATE])
|
||||||
break;
|
asprintf(&ret, "%s"PSS "%s.%d.fcm", odirs[FCEUIOD_STATE], FileBase, id1);
|
||||||
case FCEUMKF_FDSROM:
|
else
|
||||||
asprintf(&ret, "%s"PSS "disksys.rom", BaseDirectory);
|
asprintf(&ret, "%s"PSS "fcs"PSS "%s.%d.fcm", BaseDirectory, FileBase, id1);
|
||||||
break;
|
if (stat(ret, &tmpstat) == -1) {
|
||||||
case FCEUMKF_PALETTE:
|
if (odirs[FCEUIOD_STATE])
|
||||||
if (odirs[FCEUIOD_MISC])
|
asprintf(&ret, "%s"PSS "%s.%s.%d.fcm", odirs[FCEUIOD_STATE], FileBase, md5_asciistr(GameInfo->MD5), id1);
|
||||||
asprintf(&ret, "%s"PSS "%s.pal", odirs[FCEUIOD_MISC], FileBase);
|
else
|
||||||
else
|
asprintf(&ret, "%s"PSS "fcs"PSS "%s.%s.%d.fcm", BaseDirectory, FileBase, md5_asciistr(GameInfo->MD5), id1);
|
||||||
asprintf(&ret, "%s"PSS "gameinfo"PSS "%s.pal", BaseDirectory, FileBase);
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
case FCEUMKF_STATE:
|
||||||
ret = malloc(1);
|
if (odirs[FCEUIOD_STATE])
|
||||||
*ret = '\0';
|
asprintf(&ret, "%s"PSS "%s.fc%d", odirs[FCEUIOD_STATE], FileBase, id1);
|
||||||
}
|
else
|
||||||
return(ret);
|
asprintf(&ret, "%s"PSS "fcs"PSS "%s.fc%d", BaseDirectory, FileBase, id1);
|
||||||
|
if (stat(ret, &tmpstat) == -1) {
|
||||||
|
// if(odirs[FCEUIOD_STATE])
|
||||||
|
// asprintf(&ret,"%s"PSS"%s.%s.fc%d",odirs[FCEUIOD_STATE],FileBase,md5_asciistr(GameInfo->MD5),id1);
|
||||||
|
// else
|
||||||
|
// asprintf(&ret,"%s"PSS"fcs"PSS"%s.%s.fc%d",BaseDirectory,FileBase,md5_asciistr(GameInfo->MD5),id1);
|
||||||
|
if (odirs[FCEUIOD_STATE])
|
||||||
|
asprintf(&ret, "%s"PSS "%s.fc%d", odirs[FCEUIOD_STATE], FileBase, id1);
|
||||||
|
else
|
||||||
|
asprintf(&ret, "%s"PSS "fcs"PSS "%s.fc%d", BaseDirectory, FileBase, id1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FCEUMKF_SNAP:
|
||||||
|
if (FSettings.SnapName) {
|
||||||
|
if (odirs[FCEUIOD_SNAPS])
|
||||||
|
asprintf(&ret, "%s"PSS "%s-%d.%s", odirs[FCEUIOD_SNAPS], FileBase, id1, cd1);
|
||||||
|
else
|
||||||
|
asprintf(&ret, "%s"PSS "snaps"PSS "%s-%d.%s", BaseDirectory, FileBase, id1, cd1);
|
||||||
|
} else {
|
||||||
|
if (odirs[FCEUIOD_SNAPS])
|
||||||
|
asprintf(&ret, "%s"PSS "%d.%s", odirs[FCEUIOD_SNAPS], id1, cd1);
|
||||||
|
else
|
||||||
|
asprintf(&ret, "%s"PSS "snaps"PSS "%d.%s", BaseDirectory, id1, cd1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FCEUMKF_FDS:
|
||||||
|
if (odirs[FCEUIOD_NV])
|
||||||
|
asprintf(&ret, "%s"PSS "%s.%s.fds", odirs[FCEUIOD_NV], FileBase, md5_asciistr(GameInfo->MD5));
|
||||||
|
else
|
||||||
|
asprintf(&ret, "%s"PSS "sav"PSS "%s.%s.fds", BaseDirectory, FileBase, md5_asciistr(GameInfo->MD5));
|
||||||
|
break;
|
||||||
|
case FCEUMKF_SAV:
|
||||||
|
if (odirs[FCEUIOD_NV])
|
||||||
|
asprintf(&ret, "%s"PSS "%s.%s", odirs[FCEUIOD_NV], FileBase, cd1);
|
||||||
|
else
|
||||||
|
asprintf(&ret, "%s"PSS "sav"PSS "%s.%s", BaseDirectory, FileBase, cd1);
|
||||||
|
if (stat(ret, &tmpstat) == -1) {
|
||||||
|
if (odirs[FCEUIOD_NV])
|
||||||
|
asprintf(&ret, "%s"PSS "%s.%s.%s", odirs[FCEUIOD_NV], FileBase, md5_asciistr(GameInfo->MD5), cd1);
|
||||||
|
else
|
||||||
|
asprintf(&ret, "%s"PSS "sav"PSS "%s.%s.%s", BaseDirectory, FileBase, md5_asciistr(GameInfo->MD5), cd1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FCEUMKF_CHEAT:
|
||||||
|
if (odirs[FCEUIOD_CHEATS])
|
||||||
|
asprintf(&ret, "%s"PSS "%s.cht", odirs[FCEUIOD_CHEATS], FileBase);
|
||||||
|
else
|
||||||
|
asprintf(&ret, "%s"PSS "cheats"PSS "%s.cht", BaseDirectory, FileBase);
|
||||||
|
break;
|
||||||
|
case FCEUMKF_IPS: asprintf(&ret, "%s"PSS "%s%s.ips", FileBaseDirectory, FileBase, FileExt);
|
||||||
|
break;
|
||||||
|
case FCEUMKF_GGROM: asprintf(&ret, "%s"PSS "gg.rom", BaseDirectory); break;
|
||||||
|
case FCEUMKF_FDSROM: asprintf(&ret, "%s"PSS "disksys.rom", BaseDirectory); break;
|
||||||
|
case FCEUMKF_PALETTE:
|
||||||
|
if (odirs[FCEUIOD_MISC])
|
||||||
|
asprintf(&ret, "%s"PSS "%s.pal", odirs[FCEUIOD_MISC], FileBase);
|
||||||
|
else
|
||||||
|
asprintf(&ret, "%s"PSS "gameinfo"PSS "%s.pal", BaseDirectory, FileBase);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = malloc(1);
|
||||||
|
*ret = '\0';
|
||||||
|
}
|
||||||
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetFileBase(const char *f)
|
void GetFileBase(const char *f) {
|
||||||
{
|
const char *tp1, *tp3;
|
||||||
const char *tp1, *tp3;
|
|
||||||
|
|
||||||
#if PSS_STYLE == 4
|
#if PSS_STYLE == 4
|
||||||
tp1 = ((char*)strrchr(f, ':'));
|
tp1 = ((char*)strrchr(f, ':'));
|
||||||
#elif PSS_STYLE == 1
|
#elif PSS_STYLE == 1
|
||||||
tp1 = ((char*)strrchr(f, '/'));
|
tp1 = ((char*)strrchr(f, '/'));
|
||||||
#else
|
#else
|
||||||
tp1 = ((char*)strrchr(f, '\\'));
|
tp1 = ((char*)strrchr(f, '\\'));
|
||||||
#if PSS_STYLE != 3
|
#if PSS_STYLE != 3
|
||||||
tp3 = ((char*)strrchr(f, '/'));
|
tp3 = ((char*)strrchr(f, '/'));
|
||||||
if (tp1 < tp3) tp1 = tp3;
|
if (tp1 < tp3) tp1 = tp3;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
if (!tp1)
|
if (!tp1) {
|
||||||
{
|
tp1 = f;
|
||||||
tp1 = f;
|
strcpy(FileBaseDirectory, ".");
|
||||||
strcpy(FileBaseDirectory, ".");
|
} else {
|
||||||
}
|
memcpy(FileBaseDirectory, f, tp1 - f);
|
||||||
else
|
FileBaseDirectory[tp1 - f] = 0;
|
||||||
{
|
tp1++;
|
||||||
memcpy(FileBaseDirectory, f, tp1 - f);
|
}
|
||||||
FileBaseDirectory[tp1 - f] = 0;
|
|
||||||
tp1++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((tp3 = strrchr(f, '.')) != NULL) && (tp3 > tp1))
|
if (((tp3 = strrchr(f, '.')) != NULL) && (tp3 > tp1)) {
|
||||||
{
|
memcpy(FileBase, tp1, tp3 - tp1);
|
||||||
memcpy(FileBase, tp1, tp3 - tp1);
|
FileBase[tp3 - tp1] = 0;
|
||||||
FileBase[tp3 - tp1] = 0;
|
strcpy(FileExt, tp3);
|
||||||
strcpy(FileExt, tp3);
|
} else {
|
||||||
}
|
strcpy(FileBase, tp1);
|
||||||
else
|
FileExt[0] = 0;
|
||||||
{
|
}
|
||||||
strcpy(FileBase, tp1);
|
|
||||||
FileExt[0] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 uppow2(uint32 n)
|
uint32 uppow2(uint32 n) {
|
||||||
{
|
int x;
|
||||||
int x;
|
|
||||||
|
|
||||||
for (x = 31; x >= 0; x--)
|
for (x = 31; x >= 0; x--)
|
||||||
if (n & (1 << x))
|
if (n & (1 << x)) {
|
||||||
{
|
if ((1 << x) != n)
|
||||||
if ((1 << x) != n)
|
return(1 << (x + 1));
|
||||||
return(1 << (x + 1));
|
break;
|
||||||
break;
|
}
|
||||||
}
|
return n;
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ uint8 *VROM = NULL;
|
|||||||
uint8 *ExtraNTARAM = NULL;
|
uint8 *ExtraNTARAM = NULL;
|
||||||
iNES_HEADER head;
|
iNES_HEADER head;
|
||||||
|
|
||||||
CartInfo iNESCart;
|
static CartInfo iNESCart;
|
||||||
|
|
||||||
uint8 Mirroring = 0;
|
uint8 Mirroring = 0;
|
||||||
uint32 ROM_size = 0;
|
uint32 ROM_size = 0;
|
||||||
|
|||||||
495
src/input.c
495
src/input.c
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#include "fceu.h"
|
#include "fceu.h"
|
||||||
#include "netplay.h"
|
#include "netplay.h"
|
||||||
|
#include "movie.h"
|
||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "vsuni.h"
|
#include "vsuni.h"
|
||||||
#include "fds.h"
|
#include "fds.h"
|
||||||
@@ -68,8 +70,127 @@ static INPUTCFC *FCExp = 0;
|
|||||||
|
|
||||||
void (*InputScanlineHook)(uint8 *bg, uint8 *spr, uint32 linets, int final);
|
void (*InputScanlineHook)(uint8 *bg, uint8 *spr, uint32 linets, int final);
|
||||||
|
|
||||||
static DECLFR(JPRead)
|
/*
|
||||||
{
|
#define DI 01
|
||||||
|
#define CLK 02
|
||||||
|
#define CS 04
|
||||||
|
#define OUT0 01
|
||||||
|
#define D3 01
|
||||||
|
#define D4 02
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8 state;
|
||||||
|
uint8 cmd;
|
||||||
|
uint8 addr;
|
||||||
|
uint8 iswritable;
|
||||||
|
uint16 acc;
|
||||||
|
uint16 data[128];
|
||||||
|
} EEPROM;
|
||||||
|
|
||||||
|
EEPROM serialROM[2];
|
||||||
|
uint8 oldCLK, bankFlip, DIFlip, OUT0state;
|
||||||
|
|
||||||
|
uint8 serialROMautomat(uint8 chip, uint16 data) {
|
||||||
|
uint8 resp = 1;
|
||||||
|
chip &= 1;
|
||||||
|
if (!(data & CS)) {
|
||||||
|
if (!(data & CLK)) {
|
||||||
|
uint8 state = serialROM[chip].state;
|
||||||
|
uint8 mask, i;
|
||||||
|
FCEU_printf("> state = %02x\n", serialROM[chip].state);
|
||||||
|
switch (serialROM[chip].cmd) {
|
||||||
|
case 0x00:
|
||||||
|
mask = ~(1 << (state & 7));
|
||||||
|
if (state < 8) {
|
||||||
|
serialROM[chip].addr &= mask;
|
||||||
|
serialROM[chip].addr |= ((data & 1) << (state & 7));
|
||||||
|
if (state == 7)
|
||||||
|
FCEU_printf("> addr = %02x\n", serialROM[chip].addr);
|
||||||
|
} else if (state < 15) {
|
||||||
|
serialROM[chip].acc &= mask;
|
||||||
|
serialROM[chip].acc |= ((data & 1) << (state & 7));
|
||||||
|
} else {
|
||||||
|
serialROM[chip].acc &= mask;
|
||||||
|
serialROM[chip].acc |= ((data & 1) << (state & 7));
|
||||||
|
serialROM[chip].cmd = serialROM[chip].acc;
|
||||||
|
FCEU_printf("> cmd = %02x\n", serialROM[chip].cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x01:
|
||||||
|
if (state < 30)
|
||||||
|
resp = (serialROM[chip].data[serialROM[chip].addr] >> (state & 15)) & 1;
|
||||||
|
else {
|
||||||
|
resp = (serialROM[chip].data[serialROM[chip].addr] >> (state & 15)) & 1;
|
||||||
|
serialROM[chip].cmd = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x06:
|
||||||
|
mask = ~(1 << (state & 15));
|
||||||
|
if (state < 30) {
|
||||||
|
serialROM[chip].acc &= mask;
|
||||||
|
serialROM[chip].acc |= ((data & 1) << (state & 15));
|
||||||
|
} else {
|
||||||
|
serialROM[chip].acc &= mask;
|
||||||
|
serialROM[chip].acc |= ((data & 1) << (state & 15));
|
||||||
|
if (serialROM[chip].iswritable)
|
||||||
|
serialROM[chip].data[serialROM[chip].addr] = serialROM[chip].acc;
|
||||||
|
serialROM[chip].cmd = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x0C:
|
||||||
|
for (i = 0; i < 128; i++)
|
||||||
|
serialROM[chip].data[i] = 0xFFFF;
|
||||||
|
serialROM[chip].cmd = 0;
|
||||||
|
resp = 1;
|
||||||
|
break;
|
||||||
|
case 0x0D:
|
||||||
|
serialROM[chip].cmd = 0;
|
||||||
|
resp = 1;
|
||||||
|
break;
|
||||||
|
case 0x09:
|
||||||
|
serialROM[chip].cmd = 0;
|
||||||
|
serialROM[chip].iswritable = 1;
|
||||||
|
break;
|
||||||
|
case 0x0B:
|
||||||
|
serialROM[chip].cmd = 0;
|
||||||
|
serialROM[chip].iswritable = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
serialROM[chip].cmd = 0;
|
||||||
|
serialROM[chip].state = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (serialROM[chip].cmd == 0) {
|
||||||
|
if (serialROM[chip].state > 15)
|
||||||
|
serialROM[chip].state = 0;
|
||||||
|
} else
|
||||||
|
serialROM[chip].state++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
serialROM[chip].cmd = 0;
|
||||||
|
serialROM[chip].state = 0;
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 serialROMstate(uint8 linestate) {
|
||||||
|
uint8 answ = 0, newCLK = linestate & CLK;
|
||||||
|
if ((!oldCLK) && newCLK) {
|
||||||
|
DIFlip ^= 1;
|
||||||
|
if (linestate && OUT0) {
|
||||||
|
serialROMautomat(bankFlip, 04 + DIFlip);
|
||||||
|
bankFlip ^= 1;
|
||||||
|
serialROMautomat(bankFlip, 02 + DIFlip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
answ = DIFlip ^ 1;
|
||||||
|
answ |= (serialROMautomat(bankFlip, newCLK + DIFlip) << 1);
|
||||||
|
oldCLK = newCLK;
|
||||||
|
return answ << 3;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
static DECLFR(JPRead) {
|
||||||
uint8 ret = 0;
|
uint8 ret = 0;
|
||||||
|
|
||||||
if (JPorts[A & 1]->Read)
|
if (JPorts[A & 1]->Read)
|
||||||
@@ -81,11 +202,21 @@ static DECLFR(JPRead)
|
|||||||
|
|
||||||
ret |= X.DB & 0xC0;
|
ret |= X.DB & 0xC0;
|
||||||
|
|
||||||
|
// if(A==0x4017)
|
||||||
|
//{
|
||||||
|
// ret |= serialROMstate(OUT0);
|
||||||
|
// serialROMstate(OUT0|CLK);
|
||||||
|
// FCEU_printf("> 4017 read %02x\n",ret);
|
||||||
|
// }
|
||||||
|
|
||||||
return(ret);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DECLFW(B4016)
|
static DECLFW(B4016) {
|
||||||
{
|
// OUT0state = V;
|
||||||
|
// serialROMstate(OUT0state|CLK);
|
||||||
|
// FCEU_printf("> 4016 write %02x\n",V);
|
||||||
|
|
||||||
if (FCExp)
|
if (FCExp)
|
||||||
if (FCExp->Write)
|
if (FCExp->Write)
|
||||||
FCExp->Write(V & 7);
|
FCExp->Write(V & 7);
|
||||||
@@ -95,284 +226,208 @@ static DECLFW(B4016)
|
|||||||
if (JPorts[1]->Write)
|
if (JPorts[1]->Write)
|
||||||
JPorts[1]->Write(V & 1);
|
JPorts[1]->Write(V & 1);
|
||||||
|
|
||||||
if ((LastStrobe & 1) && (!(V & 1)))
|
if ((LastStrobe & 1) && (!(V & 1))) {
|
||||||
{
|
// FCEUD_UpdateInput();
|
||||||
if (JPorts[0]->Strobe)
|
if (JPorts[0]->Strobe)
|
||||||
JPorts[0]->Strobe(0);
|
JPorts[0]->Strobe(0);
|
||||||
if (JPorts[1]->Strobe)
|
if (JPorts[1]->Strobe)
|
||||||
JPorts[1]->Strobe(1);
|
JPorts[1]->Strobe(1);
|
||||||
if (FCExp)
|
if (FCExp)
|
||||||
if (FCExp->Strobe)
|
if (FCExp->Strobe)
|
||||||
FCExp->Strobe();
|
FCExp->Strobe();
|
||||||
}
|
}
|
||||||
LastStrobe = V & 0x1;
|
LastStrobe = V & 0x1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEU_DrawInput(uint8 *buf)
|
void FCEU_DrawInput(uint8 *buf) {
|
||||||
{
|
int x;
|
||||||
int x;
|
for (x = 0; x < 2; x++)
|
||||||
for (x = 0; x < 2; x++)
|
if (JPorts[x]->Draw)
|
||||||
if (JPorts[x]->Draw)
|
JPorts[x]->Draw(x, buf, JPAttrib[x]);
|
||||||
JPorts[x]->Draw(x, buf, JPAttrib[x]);
|
if (FCExp)
|
||||||
if (FCExp)
|
if (FCExp->Draw)
|
||||||
if (FCExp->Draw)
|
FCExp->Draw(buf, JPAttribFC);
|
||||||
FCExp->Draw(buf, JPAttribFC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEU_UpdateInput(void)
|
void FCEU_UpdateInput(void) {
|
||||||
{
|
int x;
|
||||||
int x;
|
|
||||||
|
|
||||||
for (x = 0; x < 2; x++)
|
for (x = 0; x < 2; x++) {
|
||||||
{
|
if (JPorts[x]->Update)
|
||||||
if (JPorts[x] && JPorts[x]->Update)
|
JPorts[x]->Update(x, InputDataPtr[x], JPAttrib[x]);
|
||||||
JPorts[x]->Update(x, InputDataPtr[x], JPAttrib[x]);
|
}
|
||||||
}
|
if (FCExp)
|
||||||
|
if (FCExp->Update)
|
||||||
|
FCExp->Update(InputDataPtrFC, JPAttribFC);
|
||||||
|
|
||||||
if (FCExp && FCExp->Update)
|
if (GameInfo->type == GIT_VSUNI)
|
||||||
FCExp->Update(InputDataPtrFC, JPAttribFC);
|
if (coinon) coinon--;
|
||||||
|
|
||||||
if (GameInfo && GameInfo->type == GIT_VSUNI)
|
|
||||||
if (coinon) coinon--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static DECLFR(VSUNIRead0)
|
static DECLFR(VSUNIRead0) {
|
||||||
{
|
|
||||||
uint8 ret = 0;
|
|
||||||
|
|
||||||
if (JPorts[0]->Read)
|
|
||||||
ret |= (JPorts[0]->Read(0)) & 1;
|
|
||||||
|
|
||||||
ret |= (vsdip & 3) << 3;
|
|
||||||
if (coinon)
|
|
||||||
ret |= 0x4;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static DECLFR(VSUNIRead1)
|
|
||||||
{
|
|
||||||
uint8 ret = 0;
|
uint8 ret = 0;
|
||||||
|
|
||||||
if (JPorts[1] && JPorts[1]->Read)
|
if (JPorts[0]->Read)
|
||||||
|
ret |= (JPorts[0]->Read(0)) & 1;
|
||||||
|
|
||||||
|
ret |= (vsdip & 3) << 3;
|
||||||
|
if (coinon)
|
||||||
|
ret |= 0x4;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DECLFR(VSUNIRead1) {
|
||||||
|
uint8 ret = 0;
|
||||||
|
|
||||||
|
if (JPorts[1]->Read)
|
||||||
ret |= (JPorts[1]->Read(1)) & 1;
|
ret |= (JPorts[1]->Read(1)) & 1;
|
||||||
ret |= vsdip & 0xFC;
|
ret |= vsdip & 0xFC;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SLHLHook(uint8 *bg, uint8 *spr, uint32 linets, int final)
|
static void SLHLHook(uint8 *bg, uint8 *spr, uint32 linets, int final) {
|
||||||
{
|
int x;
|
||||||
int x;
|
for (x = 0; x < 2; x++)
|
||||||
|
if (JPorts[x]->SLHook)
|
||||||
for (x = 0; x < 2; x++)
|
JPorts[x]->SLHook(x, bg, spr, linets, final);
|
||||||
if (JPorts[x] && JPorts[x]->SLHook)
|
if (FCExp)
|
||||||
JPorts[x]->SLHook(x, bg, spr, linets, final);
|
if (FCExp->SLHook)
|
||||||
|
FCExp->SLHook(bg, spr, linets, final);
|
||||||
if (FCExp && FCExp->SLHook)
|
|
||||||
FCExp->SLHook(bg, spr, linets, final);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CheckSLHook(void)
|
static void CheckSLHook(void) {
|
||||||
{
|
InputScanlineHook = 0;
|
||||||
InputScanlineHook = 0;
|
if (JPorts[0]->SLHook || JPorts[1]->SLHook)
|
||||||
|
InputScanlineHook = SLHLHook;
|
||||||
if (JPorts[0] && JPorts[0]->SLHook || JPorts[1] && JPorts[1]->SLHook)
|
if (FCExp)
|
||||||
InputScanlineHook = SLHLHook;
|
if (FCExp->SLHook)
|
||||||
|
InputScanlineHook = SLHLHook;
|
||||||
if (FCExp && FCExp->SLHook)
|
|
||||||
InputScanlineHook = SLHLHook;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FASTAPASS(1) SetInputStuff(int x)
|
static void FASTAPASS(1) SetInputStuff(int x) {
|
||||||
{
|
switch (JPType[x]) {
|
||||||
switch (JPType[x])
|
case SI_NONE: JPorts[x] = &DummyJPort; break;
|
||||||
{
|
case SI_GAMEPAD: JPorts[x] = FCEU_InitJoyPad(x); break;
|
||||||
case SI_NONE:
|
case SI_ARKANOID: JPorts[x] = FCEU_InitArkanoid(x); break;
|
||||||
JPorts[x] = &DummyJPort;
|
case SI_MOUSE: JPorts[x] = FCEU_InitMouse(x); break;
|
||||||
break;
|
case SI_ZAPPER: JPorts[x] = FCEU_InitZapper(x); break;
|
||||||
case SI_GAMEPAD:
|
case SI_POWERPADA: JPorts[x] = FCEU_InitPowerpadA(x); break;
|
||||||
JPorts[x] = FCEU_InitJoyPad(x);
|
case SI_POWERPADB: JPorts[x] = FCEU_InitPowerpadB(x); break;
|
||||||
break;
|
}
|
||||||
case SI_ARKANOID:
|
|
||||||
JPorts[x] = FCEU_InitArkanoid(x);
|
|
||||||
break;
|
|
||||||
case SI_MOUSE:
|
|
||||||
JPorts[x] = FCEU_InitMouse(x);
|
|
||||||
break;
|
|
||||||
case SI_ZAPPER:
|
|
||||||
JPorts[x] = FCEU_InitZapper(x);
|
|
||||||
break;
|
|
||||||
case SI_POWERPADA:
|
|
||||||
JPorts[x] = FCEU_InitPowerpadA(x);
|
|
||||||
break;
|
|
||||||
case SI_POWERPADB:
|
|
||||||
JPorts[x] = FCEU_InitPowerpadB(x);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
CheckSLHook();
|
CheckSLHook();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetInputStuffFC(void)
|
static void SetInputStuffFC(void) {
|
||||||
{
|
switch (JPTypeFC) {
|
||||||
switch (JPTypeFC)
|
case SIFC_NONE: FCExp = 0; break;
|
||||||
{
|
case SIFC_ARKANOID: FCExp = FCEU_InitArkanoidFC(); break;
|
||||||
case SIFC_NONE:
|
case SIFC_SHADOW: FCExp = FCEU_InitSpaceShadow(); break;
|
||||||
FCExp = 0;
|
case SIFC_OEKAKIDS: FCExp = FCEU_InitOekaKids(); break;
|
||||||
break;
|
case SIFC_4PLAYER: FCExp = FCEU_InitFami4(); break;
|
||||||
case SIFC_ARKANOID:
|
case SIFC_FKB: FCExp = FCEU_InitFKB(); break;
|
||||||
FCExp = FCEU_InitArkanoidFC();
|
case SIFC_SUBORKB: FCExp = FCEU_InitSuborKB(); break;
|
||||||
break;
|
case SIFC_PEC586KB: FCExp = FCEU_InitPEC586KB(); break;
|
||||||
case SIFC_SHADOW:
|
case SIFC_HYPERSHOT: FCExp = FCEU_InitHS(); break;
|
||||||
FCExp = FCEU_InitSpaceShadow();
|
case SIFC_MAHJONG: FCExp = FCEU_InitMahjong(); break;
|
||||||
break;
|
case SIFC_QUIZKING: FCExp = FCEU_InitQuizKing(); break;
|
||||||
case SIFC_OEKAKIDS:
|
case SIFC_FTRAINERA: FCExp = FCEU_InitFamilyTrainerA(); break;
|
||||||
FCExp = FCEU_InitOekaKids();
|
case SIFC_FTRAINERB: FCExp = FCEU_InitFamilyTrainerB(); break;
|
||||||
break;
|
case SIFC_BWORLD: FCExp = FCEU_InitBarcodeWorld(); break;
|
||||||
case SIFC_4PLAYER:
|
case SIFC_TOPRIDER: FCExp = FCEU_InitTopRider(); break;
|
||||||
FCExp = FCEU_InitFami4();
|
}
|
||||||
break;
|
|
||||||
case SIFC_FKB:
|
|
||||||
FCExp = FCEU_InitFKB();
|
|
||||||
break;
|
|
||||||
case SIFC_SUBORKB:
|
|
||||||
FCExp = FCEU_InitSuborKB();
|
|
||||||
break;
|
|
||||||
case SIFC_PEC586KB:
|
|
||||||
FCExp = FCEU_InitPEC586KB();
|
|
||||||
break;
|
|
||||||
case SIFC_HYPERSHOT:
|
|
||||||
FCExp = FCEU_InitHS();
|
|
||||||
break;
|
|
||||||
case SIFC_MAHJONG:
|
|
||||||
FCExp = FCEU_InitMahjong();
|
|
||||||
break;
|
|
||||||
case SIFC_QUIZKING:
|
|
||||||
FCExp = FCEU_InitQuizKing();
|
|
||||||
break;
|
|
||||||
case SIFC_FTRAINERA:
|
|
||||||
FCExp = FCEU_InitFamilyTrainerA();
|
|
||||||
break;
|
|
||||||
case SIFC_FTRAINERB:
|
|
||||||
FCExp = FCEU_InitFamilyTrainerB();
|
|
||||||
break;
|
|
||||||
case SIFC_BWORLD:
|
|
||||||
FCExp = FCEU_InitBarcodeWorld();
|
|
||||||
break;
|
|
||||||
case SIFC_TOPRIDER:
|
|
||||||
FCExp = FCEU_InitTopRider();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
CheckSLHook();
|
CheckSLHook();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeInput(void)
|
void InitializeInput(void) {
|
||||||
{
|
LastStrobe = 0;
|
||||||
LastStrobe = 0;
|
if (GameInfo->type == GIT_VSUNI) {
|
||||||
|
SetReadHandler(0x4016, 0x4016, VSUNIRead0);
|
||||||
|
SetReadHandler(0x4017, 0x4017, VSUNIRead1);
|
||||||
|
} else
|
||||||
|
SetReadHandler(0x4016, 0x4017, JPRead);
|
||||||
|
|
||||||
if (GameInfo && GameInfo->type == GIT_VSUNI)
|
SetWriteHandler(0x4016, 0x4016, B4016);
|
||||||
{
|
|
||||||
SetReadHandler(0x4016, 0x4016, VSUNIRead0);
|
|
||||||
SetReadHandler(0x4017, 0x4017, VSUNIRead1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SetReadHandler(0x4016, 0x4017, JPRead);
|
|
||||||
|
|
||||||
SetWriteHandler(0x4016, 0x4016, B4016);
|
SetInputStuff(0);
|
||||||
|
SetInputStuff(1);
|
||||||
SetInputStuff(0);
|
SetInputStuffFC();
|
||||||
SetInputStuff(1);
|
|
||||||
SetInputStuffFC();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEUI_SetInput(int port, int type, void *ptr, int attrib)
|
void FCEUI_SetInput(int port, int type, void *ptr, int attrib) {
|
||||||
{
|
JPAttrib[port] = attrib;
|
||||||
JPAttrib[port] = attrib;
|
JPType[port] = type;
|
||||||
JPType[port] = type;
|
InputDataPtr[port] = ptr;
|
||||||
InputDataPtr[port] = ptr;
|
SetInputStuff(port);
|
||||||
SetInputStuff(port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEUI_SetInputFC(int type, void *ptr, int attrib)
|
void FCEUI_SetInputFC(int type, void *ptr, int attrib) {
|
||||||
{
|
|
||||||
JPAttribFC = attrib;
|
JPAttribFC = attrib;
|
||||||
JPTypeFC = type;
|
JPTypeFC = type;
|
||||||
InputDataPtrFC = ptr;
|
InputDataPtrFC = ptr;
|
||||||
SetInputStuffFC();
|
SetInputStuffFC();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEU_DoSimpleCommand(int cmd)
|
void FCEU_DoSimpleCommand(int cmd) {
|
||||||
{
|
switch (cmd) {
|
||||||
switch (cmd)
|
case FCEUNPCMD_FDSINSERT: FCEU_FDSInsert(-1); break;
|
||||||
{
|
case FCEUNPCMD_FDSSELECT: FCEU_FDSSelect(); break;
|
||||||
case FCEUNPCMD_FDSINSERT:
|
case FCEUNPCMD_FDSEJECT: FCEU_FDSEject(); break;
|
||||||
FCEU_FDSInsert(-1);
|
case FCEUNPCMD_VSUNICOIN: FCEU_VSUniCoin(); break;
|
||||||
break;
|
case FCEUNPCMD_VSUNIDIP0:
|
||||||
case FCEUNPCMD_FDSSELECT:
|
case (FCEUNPCMD_VSUNIDIP0 + 1):
|
||||||
FCEU_FDSSelect();
|
case (FCEUNPCMD_VSUNIDIP0 + 2):
|
||||||
break;
|
case (FCEUNPCMD_VSUNIDIP0 + 3):
|
||||||
case FCEUNPCMD_FDSEJECT:
|
case (FCEUNPCMD_VSUNIDIP0 + 4):
|
||||||
FCEU_FDSEject();
|
case (FCEUNPCMD_VSUNIDIP0 + 5):
|
||||||
break;
|
case (FCEUNPCMD_VSUNIDIP0 + 6):
|
||||||
case FCEUNPCMD_VSUNICOIN:
|
case (FCEUNPCMD_VSUNIDIP0 + 7):
|
||||||
FCEU_VSUniCoin();
|
FCEU_VSUniToggleDIP(cmd - FCEUNPCMD_VSUNIDIP0); break;
|
||||||
break;
|
case FCEUNPCMD_POWER: PowerNES(); break;
|
||||||
case FCEUNPCMD_VSUNIDIP0:
|
case FCEUNPCMD_RESET: ResetNES(); break;
|
||||||
case (FCEUNPCMD_VSUNIDIP0 + 1):
|
}
|
||||||
case (FCEUNPCMD_VSUNIDIP0 + 2):
|
|
||||||
case (FCEUNPCMD_VSUNIDIP0 + 3):
|
|
||||||
case (FCEUNPCMD_VSUNIDIP0 + 4):
|
|
||||||
case (FCEUNPCMD_VSUNIDIP0 + 5):
|
|
||||||
case (FCEUNPCMD_VSUNIDIP0 + 6):
|
|
||||||
case (FCEUNPCMD_VSUNIDIP0 + 7):
|
|
||||||
FCEU_VSUniToggleDIP(cmd - FCEUNPCMD_VSUNIDIP0);
|
|
||||||
break;
|
|
||||||
case FCEUNPCMD_POWER:
|
|
||||||
PowerNES();
|
|
||||||
break;
|
|
||||||
case FCEUNPCMD_RESET:
|
|
||||||
ResetNES();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEU_QSimpleCommand(int cmd)
|
void FCEU_QSimpleCommand(int cmd) {
|
||||||
{
|
#ifdef NETWORK
|
||||||
FCEU_DoSimpleCommand(cmd);
|
if (FCEUnetplay)
|
||||||
|
FCEUNET_SendCommand(cmd, 0);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (!FCEUMOV_IsPlaying())
|
||||||
|
FCEU_DoSimpleCommand(cmd);
|
||||||
|
else
|
||||||
|
FCEUMOV_AddCommand(cmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEUI_FDSSelect(void)
|
void FCEUI_FDSSelect(void) {
|
||||||
{
|
|
||||||
FCEU_QSimpleCommand(FCEUNPCMD_FDSSELECT);
|
FCEU_QSimpleCommand(FCEUNPCMD_FDSSELECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
int FCEUI_FDSInsert(int oride)
|
int FCEUI_FDSInsert(int oride) {
|
||||||
{
|
|
||||||
FCEU_QSimpleCommand(FCEUNPCMD_FDSINSERT);
|
FCEU_QSimpleCommand(FCEUNPCMD_FDSINSERT);
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int FCEUI_FDSEject(void)
|
int FCEUI_FDSEject(void) {
|
||||||
{
|
|
||||||
FCEU_QSimpleCommand(FCEUNPCMD_FDSEJECT);
|
FCEU_QSimpleCommand(FCEUNPCMD_FDSEJECT);
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEUI_VSUniToggleDIP(int w)
|
void FCEUI_VSUniToggleDIP(int w) {
|
||||||
{
|
|
||||||
FCEU_QSimpleCommand(FCEUNPCMD_VSUNIDIP0 + w);
|
FCEU_QSimpleCommand(FCEUNPCMD_VSUNIDIP0 + w);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEUI_VSUniCoin(void)
|
void FCEUI_VSUniCoin(void) {
|
||||||
{
|
|
||||||
FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN);
|
FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEUI_ResetNES(void)
|
void FCEUI_ResetNES(void) {
|
||||||
{
|
|
||||||
FCEU_QSimpleCommand(FCEUNPCMD_RESET);
|
FCEU_QSimpleCommand(FCEUNPCMD_RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEUI_PowerNES(void)
|
void FCEUI_PowerNES(void) {
|
||||||
{
|
|
||||||
FCEU_QSimpleCommand(FCEUNPCMD_POWER);
|
FCEU_QSimpleCommand(FCEUNPCMD_POWER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
498
src/state.c
498
src/state.c
@@ -18,6 +18,9 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* TODO: Add (better) file io error checking */
|
||||||
|
/* TODO: Change save state file format. */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -45,12 +48,15 @@ static void (*SPreSave)(void);
|
|||||||
static void (*SPostSave)(void);
|
static void (*SPostSave)(void);
|
||||||
|
|
||||||
static int SaveStateStatus[10];
|
static int SaveStateStatus[10];
|
||||||
|
static int StateShow;
|
||||||
|
|
||||||
|
|
||||||
static SFORMAT SFMDATA[64];
|
static SFORMAT SFMDATA[64];
|
||||||
static int SFEXINDEX;
|
static int SFEXINDEX;
|
||||||
|
|
||||||
#define RLSB FCEUSTATE_RLSB //0x80000000
|
#define RLSB FCEUSTATE_RLSB //0x80000000
|
||||||
|
|
||||||
|
|
||||||
extern SFORMAT FCEUPPU_STATEINFO[];
|
extern SFORMAT FCEUPPU_STATEINFO[];
|
||||||
extern SFORMAT FCEUSND_STATEINFO[];
|
extern SFORMAT FCEUSND_STATEINFO[];
|
||||||
extern SFORMAT FCEUCTRL_STATEINFO[];
|
extern SFORMAT FCEUCTRL_STATEINFO[];
|
||||||
@@ -81,274 +87,281 @@ SFORMAT SFCPUC[] = {
|
|||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static int SubWrite(memstream_t *mem, SFORMAT *sf)
|
static int SubWrite(MEM_TYPE *st, SFORMAT *sf) {
|
||||||
{
|
uint32 acc = 0;
|
||||||
uint32 acc=0;
|
|
||||||
|
|
||||||
while(sf->v)
|
while (sf->v) {
|
||||||
{
|
if (sf->s == ~0) { // Link to another struct.
|
||||||
if(sf->s==~0) /* Link to another struct. */
|
uint32 tmp;
|
||||||
{
|
|
||||||
uint32 tmp;
|
|
||||||
|
|
||||||
if(!(tmp=SubWrite(mem, (SFORMAT *)sf->v)))
|
if (!(tmp = SubWrite(st, (SFORMAT*)sf->v)))
|
||||||
return(0);
|
return(0);
|
||||||
acc+=tmp;
|
acc += tmp;
|
||||||
sf++;
|
sf++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
acc+=8; /* Description + size */
|
acc += 8; // Description + size
|
||||||
acc+=sf->s&(~RLSB);
|
acc += sf->s & (~RLSB);
|
||||||
|
|
||||||
if(mem) /* Are we writing or calculating the size of this block? */
|
if (st) { // Are we writing or calculating the size of this block? */
|
||||||
{
|
fwrite(sf->desc, 1, 4, st);
|
||||||
memstream_write(mem, sf->desc, 4);
|
write32le(sf->s & (~RLSB), st);
|
||||||
write32le_mem(sf->s&(~RLSB), mem);
|
|
||||||
|
|
||||||
#ifdef MSB_FIRST
|
#ifdef MSB_FIRST
|
||||||
if(sf->s&RLSB)
|
if (sf->s & RLSB)
|
||||||
FlipByteOrder(sf->v,sf->s&(~RLSB));
|
FlipByteOrder(sf->v, sf->s & (~RLSB));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
memstream_write(mem, (uint8 *)sf->v, sf->s&(~RLSB));
|
fwrite((uint8*)sf->v, 1, sf->s & (~RLSB), st);
|
||||||
/* Now restore the original byte order. */
|
/* Now restore the original byte order. */
|
||||||
#ifdef MSB_FIRST
|
#ifdef MSB_FIRST
|
||||||
if(sf->s&RLSB)
|
if (sf->s & RLSB)
|
||||||
FlipByteOrder(sf->v,sf->s&(~RLSB));
|
FlipByteOrder(sf->v, sf->s & (~RLSB));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
sf++;
|
sf++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return acc;
|
return(acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int WriteStateChunk(memstream_t *mem, int type, SFORMAT *sf)
|
static int WriteStateChunk(MEM_TYPE *st, int type, SFORMAT *sf) {
|
||||||
{
|
int bsize;
|
||||||
int bsize;
|
|
||||||
|
|
||||||
memstream_putc(mem, type);
|
fputc(type, st);
|
||||||
|
|
||||||
bsize = SubWrite(0,sf);
|
bsize = SubWrite(0, sf);
|
||||||
write32le_mem(bsize, mem);
|
write32le(bsize, st);
|
||||||
|
|
||||||
if (!SubWrite(mem, sf))
|
if (!SubWrite(st, sf)) return(0);
|
||||||
return 0;
|
return(bsize + 5);
|
||||||
return bsize + 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static SFORMAT *CheckS(SFORMAT *sf, uint32 tsize, char *desc)
|
static SFORMAT *CheckS(SFORMAT *sf, uint32 tsize, char *desc) {
|
||||||
{
|
while (sf->v) {
|
||||||
while (sf->v)
|
if (sf->s == ~0) { /* Link to another SFORMAT structure. */
|
||||||
{
|
SFORMAT *tmp;
|
||||||
if (sf->s == ~0)
|
if ((tmp = CheckS((SFORMAT*)sf->v, tsize, desc)))
|
||||||
{ /* Link to another SFORMAT structure. */
|
return(tmp);
|
||||||
SFORMAT *tmp;
|
sf++;
|
||||||
if ((tmp = CheckS((SFORMAT*)sf->v, tsize, desc)))
|
continue;
|
||||||
return(tmp);
|
}
|
||||||
sf++;
|
if (!strncmp(desc, sf->desc, 4)) {
|
||||||
continue;
|
if (tsize != (sf->s & (~RLSB)))
|
||||||
}
|
return(0);
|
||||||
if (!strncmp(desc, sf->desc, 4))
|
return(sf);
|
||||||
{
|
}
|
||||||
if (tsize != (sf->s & (~RLSB)))
|
sf++;
|
||||||
return(0);
|
}
|
||||||
return(sf);
|
return(0);
|
||||||
}
|
|
||||||
sf++;
|
|
||||||
}
|
|
||||||
return(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ReadStateChunk(memstream_t *mem, SFORMAT *sf, int size)
|
static int ReadStateChunk(MEM_TYPE *st, SFORMAT *sf, int size) {
|
||||||
{
|
SFORMAT *tmp;
|
||||||
SFORMAT *tmp;
|
int temp;
|
||||||
int temp;
|
temp = ftell(st);
|
||||||
temp=memstream_pos(mem);
|
|
||||||
|
|
||||||
while(memstream_pos(mem)<temp+size)
|
while (ftell(st) < temp + size) {
|
||||||
{
|
uint32 tsize;
|
||||||
uint32 tsize;
|
char toa[4];
|
||||||
char toa[4];
|
if (fread(toa, 1, 4, st) <= 0)
|
||||||
if(memstream_read(mem, toa, 4)<=0)
|
return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
read32le_mem(&tsize,mem);
|
read32le(&tsize, st);
|
||||||
|
|
||||||
if((tmp=CheckS(sf,tsize,toa)))
|
if ((tmp = CheckS(sf, tsize, toa))) {
|
||||||
{
|
fread((uint8*)tmp->v, 1, tmp->s & (~RLSB), st);
|
||||||
memstream_read(mem, (uint8 *)tmp->v, tmp->s&(~RLSB));
|
|
||||||
|
|
||||||
#ifdef MSB_FIRST
|
#ifdef MSB_FIRST
|
||||||
if(tmp->s&RLSB)
|
if (tmp->s & RLSB)
|
||||||
FlipByteOrder(tmp->v,tmp->s&(~RLSB));
|
FlipByteOrder(tmp->v, tmp->s & (~RLSB));
|
||||||
#endif
|
#endif
|
||||||
}
|
} else
|
||||||
else
|
fseek(st, tsize, SEEK_CUR);
|
||||||
memstream_seek(mem,tsize,SEEK_CUR);
|
} // while(...)
|
||||||
}
|
return 1;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ReadStateChunks(memstream_t *st, int32 totalsize)
|
static int ReadStateChunks(MEM_TYPE *st, int32 totalsize) {
|
||||||
{
|
int t;
|
||||||
int t;
|
uint32 size;
|
||||||
uint32 size;
|
int ret = 1;
|
||||||
int ret = 1;
|
|
||||||
|
|
||||||
while (totalsize > 0)
|
while (totalsize > 0) {
|
||||||
{
|
t = fgetc(st);
|
||||||
t = memstream_getc(st);
|
if (t == EOF) break;
|
||||||
if (t == EOF)
|
if (!read32le(&size, st)) break;
|
||||||
break;
|
totalsize -= size + 5;
|
||||||
if (!read32le_mem(&size,st))
|
|
||||||
break;
|
|
||||||
totalsize -= size + 5;
|
|
||||||
|
|
||||||
switch(t)
|
switch (t) {
|
||||||
{
|
case 1: if (!ReadStateChunk(st, SFCPU, size)) ret = 0; break;
|
||||||
case 1:
|
case 2:
|
||||||
if (!ReadStateChunk(st, SFCPU, size))
|
if (!ReadStateChunk(st, SFCPUC, size))
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
else {
|
||||||
case 2:
|
X.mooPI = X.P; // Quick and dirty hack.
|
||||||
if (!ReadStateChunk(st, SFCPUC, size))
|
}
|
||||||
ret = 0;
|
break;
|
||||||
else
|
case 3: if (!ReadStateChunk(st, FCEUPPU_STATEINFO, size)) ret = 0; break;
|
||||||
X.mooPI = X.P; // Quick and dirty hack.
|
case 4: if (!ReadStateChunk(st, FCEUCTRL_STATEINFO, size)) ret = 0; break;
|
||||||
break;
|
case 5: if (!ReadStateChunk(st, FCEUSND_STATEINFO, size)) ret = 0; break;
|
||||||
case 3:
|
case 0x10: if (!ReadStateChunk(st, SFMDATA, size)) ret = 0;
|
||||||
if (!ReadStateChunk(st, FCEUPPU_STATEINFO, size))
|
break;
|
||||||
ret = 0;
|
default: if (fseek(st, size, SEEK_CUR) < 0) goto endo; break;
|
||||||
break;
|
}
|
||||||
case 4:
|
}
|
||||||
if (!ReadStateChunk(st, FCEUCTRL_STATEINFO, size))
|
endo:
|
||||||
ret = 0;
|
return ret;
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
if (!ReadStateChunk(st, FCEUSND_STATEINFO, size))
|
|
||||||
ret = 0;
|
|
||||||
break;
|
|
||||||
case 0x10:
|
|
||||||
if (!ReadStateChunk(st, SFMDATA, size))
|
|
||||||
ret = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (memstream_seek(st, size, SEEK_CUR) < 0)
|
|
||||||
goto endo;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
endo:
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int CurrentState = 0;
|
int CurrentState = 0;
|
||||||
extern int geniestage;
|
extern int geniestage;
|
||||||
|
|
||||||
void FCEUSS_Save_Mem(void)
|
int FCEUSS_SaveFP(MEM_TYPE *st) {
|
||||||
{
|
static uint32 totalsize;
|
||||||
memstream_t *mem = memstream_open(1);
|
uint8 header[16] = { 0 };
|
||||||
|
|
||||||
uint32 totalsize;
|
header[0] = 'F';
|
||||||
uint8 header[16] = {0};
|
header[1] = 'C';
|
||||||
|
header[2] = 'S';
|
||||||
|
header[3] = 0xFF;
|
||||||
|
|
||||||
header[0] = 'F';
|
header[3] = 0xFF;
|
||||||
header[1] = 'C';
|
FCEU_en32lsb(header + 8, FCEU_VERSION_NUMERIC);
|
||||||
header[2] = 'S';
|
fwrite(header, 1, 16, st);
|
||||||
header[3] = 0xFF;
|
FCEUPPU_SaveState();
|
||||||
|
FCEUSND_SaveState();
|
||||||
|
totalsize = WriteStateChunk(st, 1, SFCPU);
|
||||||
|
totalsize += WriteStateChunk(st, 2, SFCPUC);
|
||||||
|
totalsize += WriteStateChunk(st, 3, FCEUPPU_STATEINFO);
|
||||||
|
totalsize += WriteStateChunk(st, 4, FCEUCTRL_STATEINFO);
|
||||||
|
totalsize += WriteStateChunk(st, 5, FCEUSND_STATEINFO);
|
||||||
|
if (SPreSave) SPreSave();
|
||||||
|
totalsize += WriteStateChunk(st, 0x10, SFMDATA);
|
||||||
|
if (SPreSave) SPostSave();
|
||||||
|
|
||||||
FCEU_en32lsb(header + 8, FCEU_VERSION_NUMERIC);
|
fseek(st, 4, SEEK_SET);
|
||||||
memstream_write(mem, header, 16);
|
write32le(totalsize, st);
|
||||||
|
return(1);
|
||||||
FCEUPPU_SaveState();
|
|
||||||
totalsize = WriteStateChunk(mem, 1, SFCPU);
|
|
||||||
totalsize += WriteStateChunk(mem, 2, SFCPUC);
|
|
||||||
totalsize += WriteStateChunk(mem, 3, FCEUPPU_STATEINFO);
|
|
||||||
totalsize += WriteStateChunk(mem, 4, FCEUCTRL_STATEINFO);
|
|
||||||
totalsize += WriteStateChunk(mem, 5, FCEUSND_STATEINFO);
|
|
||||||
|
|
||||||
if (SPreSave)
|
|
||||||
SPreSave();
|
|
||||||
|
|
||||||
totalsize += WriteStateChunk(mem, 0x10, SFMDATA);
|
|
||||||
|
|
||||||
if (SPreSave)
|
|
||||||
SPostSave();
|
|
||||||
|
|
||||||
memstream_seek(mem, 4, SEEK_SET);
|
|
||||||
write32le_mem(totalsize, mem);
|
|
||||||
|
|
||||||
memstream_close(mem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEUSS_Load_Mem(void)
|
void FCEUSS_Save(char *fname) {
|
||||||
{
|
MEM_TYPE *st = NULL;
|
||||||
memstream_t *mem = memstream_open(0);
|
char *fn;
|
||||||
|
|
||||||
uint8 header[16];
|
if (geniestage == 1) {
|
||||||
int stateversion;
|
FCEU_DispMessage("Cannot save FCS in GG screen.");
|
||||||
int x;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
memstream_read(mem, header, 16);
|
if (fname)
|
||||||
|
st = FCEUD_UTF8fopen(fname, "wb");
|
||||||
|
else {
|
||||||
|
st = FCEUD_UTF8fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, CurrentState, 0), "wb");
|
||||||
|
free(fn);
|
||||||
|
}
|
||||||
|
|
||||||
if (memcmp(header,"FCS",3) != 0)
|
if (st == NULL) {
|
||||||
return;
|
FCEU_DispMessage("State %d save error.", CurrentState);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (header[3] == 0xFF)
|
FCEUSS_SaveFP(st);
|
||||||
stateversion = FCEU_de32lsb(header + 8);
|
|
||||||
else
|
|
||||||
stateversion = header[3] * 100;
|
|
||||||
|
|
||||||
x = ReadStateChunks(mem, *(uint32*)(header + 4));
|
SaveStateStatus[CurrentState] = 1;
|
||||||
|
fclose(st);
|
||||||
if (stateversion < 9500)
|
FCEU_DispMessage("State %d saved.", CurrentState);
|
||||||
X.IRQlow=0;
|
|
||||||
|
|
||||||
if (GameStateRestore)
|
|
||||||
GameStateRestore(stateversion);
|
|
||||||
|
|
||||||
if (x)
|
|
||||||
{
|
|
||||||
FCEUPPU_LoadState(stateversion);
|
|
||||||
FCEUSND_LoadState(stateversion);
|
|
||||||
}
|
|
||||||
|
|
||||||
memstream_close(mem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEUSS_CheckStates(void)
|
int FCEUSS_LoadFP(MEM_TYPE *st) {
|
||||||
{
|
int x;
|
||||||
MEM_TYPE *st = NULL;
|
uint8 header[16];
|
||||||
char *fn;
|
int stateversion;
|
||||||
int ssel;
|
|
||||||
|
|
||||||
for (ssel = 0; ssel < 10; ssel++)
|
fread(&header, 1, 16, st);
|
||||||
{
|
if (memcmp(header, "FCS", 3))
|
||||||
st = fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, ssel, 0), "rb");
|
return(0);
|
||||||
free(fn);
|
|
||||||
if (st)
|
|
||||||
{
|
|
||||||
SaveStateStatus[ssel] = 1;
|
|
||||||
fclose(st);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SaveStateStatus[ssel] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentState = 0;
|
if (header[3] == 0xFF)
|
||||||
|
stateversion = FCEU_de32lsb(header + 8);
|
||||||
|
else
|
||||||
|
stateversion = header[3] * 100;
|
||||||
|
|
||||||
|
x = ReadStateChunks(st, *(uint32*)(header + 4));
|
||||||
|
if (stateversion < 9500) X.IRQlow = 0;
|
||||||
|
|
||||||
|
if (GameStateRestore) GameStateRestore(stateversion);
|
||||||
|
if (x) {
|
||||||
|
FCEUPPU_LoadState(stateversion);
|
||||||
|
FCEUSND_LoadState(stateversion);
|
||||||
|
}
|
||||||
|
return(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetExState(void (*PreSave)(void), void (*PostSave)(void))
|
int FCEUSS_Load(char *fname) {
|
||||||
{
|
MEM_TYPE *st;
|
||||||
|
char *fn;
|
||||||
|
|
||||||
|
if (geniestage == 1) {
|
||||||
|
FCEU_DispMessage("Cannot load FCS in GG screen.");
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fname)
|
||||||
|
st = FCEUD_UTF8fopen(fname, "rb");
|
||||||
|
else {
|
||||||
|
st = FCEUD_UTF8fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, CurrentState, fname), "rb");
|
||||||
|
free(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st == NULL) {
|
||||||
|
FCEU_DispMessage("State %d load error.", CurrentState);
|
||||||
|
SaveStateStatus[CurrentState] = 0;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FCEUSS_LoadFP(st)) {
|
||||||
|
SaveStateStatus[CurrentState] = 1;
|
||||||
|
FCEU_DispMessage("State %d loaded.", CurrentState);
|
||||||
|
SaveStateStatus[CurrentState] = 1;
|
||||||
|
fclose(st);
|
||||||
|
return(1);
|
||||||
|
} else {
|
||||||
|
SaveStateStatus[CurrentState] = 1;
|
||||||
|
FCEU_DispMessage("Error(s) reading state %d!", CurrentState);
|
||||||
|
fclose(st);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUSS_CheckStates(void) {
|
||||||
|
MEM_TYPE *st = NULL;
|
||||||
|
char *fn;
|
||||||
|
int ssel;
|
||||||
|
|
||||||
|
for (ssel = 0; ssel < 10; ssel++) {
|
||||||
|
st = FCEUD_UTF8fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, ssel, 0), "rb");
|
||||||
|
free(fn);
|
||||||
|
if (st) {
|
||||||
|
SaveStateStatus[ssel] = 1;
|
||||||
|
fclose(st);
|
||||||
|
} else
|
||||||
|
SaveStateStatus[ssel] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentState = 0;
|
||||||
|
StateShow = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetExState(void (*PreSave)(void), void (*PostSave)(void)) {
|
||||||
SPreSave = PreSave;
|
SPreSave = PreSave;
|
||||||
SPostSave = PostSave;
|
SPostSave = PostSave;
|
||||||
SFEXINDEX = 0;
|
SFEXINDEX = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddExState(void *v, uint32 s, int type, char *desc)
|
void AddExState(void *v, uint32 s, int type, char *desc) {
|
||||||
{
|
|
||||||
memset(SFMDATA[SFEXINDEX].desc, 0, sizeof(SFMDATA[SFEXINDEX].desc));
|
memset(SFMDATA[SFEXINDEX].desc, 0, sizeof(SFMDATA[SFEXINDEX].desc));
|
||||||
if (desc)
|
if (desc)
|
||||||
strncpy(SFMDATA[SFEXINDEX].desc, desc, sizeof(SFMDATA[SFEXINDEX].desc));
|
strncpy(SFMDATA[SFEXINDEX].desc, desc, sizeof(SFMDATA[SFEXINDEX].desc));
|
||||||
@@ -359,7 +372,52 @@ void AddExState(void *v, uint32 s, int type, char *desc)
|
|||||||
SFMDATA[SFEXINDEX].v = 0; // End marker.
|
SFMDATA[SFEXINDEX].v = 0; // End marker.
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEU_DrawSaveStates(uint8 *XBuf)
|
void FCEUI_SelectState(int w) {
|
||||||
{
|
if (w == -1) {
|
||||||
|
StateShow = 0; return;
|
||||||
|
}
|
||||||
|
FCEUI_SelectMovie(-1);
|
||||||
|
|
||||||
|
CurrentState = w;
|
||||||
|
StateShow = 180;
|
||||||
|
FCEU_DispMessage("-select state-");
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_SaveState(char *fname) {
|
||||||
|
StateShow = 0;
|
||||||
|
FCEUSS_Save(fname);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUI_LoadState(char *fname) {
|
||||||
|
StateShow = 0;
|
||||||
|
|
||||||
|
FCEUMOV_Stop();
|
||||||
|
|
||||||
|
/* For network play, be load the state locally, and then save the state to a temporary file,
|
||||||
|
and send that. This insures that if an older state is loaded that is missing some
|
||||||
|
information expected in newer save states, desynchronization won't occur(at least not
|
||||||
|
from this ;)).
|
||||||
|
*/
|
||||||
|
if (FCEUSS_Load(fname))
|
||||||
|
if (FCEUnetplay) {
|
||||||
|
char *fn = FCEU_MakeFName(FCEUMKF_NPTEMP, 0, 0);
|
||||||
|
MEM_TYPE *fp;
|
||||||
|
|
||||||
|
if ((fp = fopen(fn, "wb"))) {
|
||||||
|
if (FCEUSS_SaveFP(fp)) {
|
||||||
|
fclose(fp);
|
||||||
|
FCEUNET_SendFile(FCEUNPCMD_LOADSTATE, fn);
|
||||||
|
} else fclose(fp);
|
||||||
|
unlink(fn);
|
||||||
|
}
|
||||||
|
free(fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_DrawSaveStates(uint8 *XBuf) {
|
||||||
|
if (!StateShow) return;
|
||||||
|
|
||||||
|
FCEU_DrawNumberRow(XBuf, SaveStateStatus, CurrentState);
|
||||||
|
StateShow--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ typedef struct {
|
|||||||
int (*init)(FCEUFILE *fp);
|
int (*init)(FCEUFILE *fp);
|
||||||
} BFMAPPING;
|
} BFMAPPING;
|
||||||
|
|
||||||
CartInfo UNIFCart;
|
static CartInfo UNIFCart;
|
||||||
|
|
||||||
static int vramo;
|
static int vramo;
|
||||||
static int mirrortodo;
|
static int mirrortodo;
|
||||||
|
|||||||
264
src/video.c
264
src/video.c
@@ -22,6 +22,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "fceu-types.h"
|
#include "fceu-types.h"
|
||||||
#include "video.h"
|
#include "video.h"
|
||||||
@@ -30,65 +31,102 @@
|
|||||||
#include "fceu-memory.h"
|
#include "fceu-memory.h"
|
||||||
#include "crc32.h"
|
#include "crc32.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
#include "movie.h"
|
||||||
#include "palette.h"
|
#include "palette.h"
|
||||||
#include "nsf.h"
|
#include "nsf.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "vsuni.h"
|
#include "vsuni.h"
|
||||||
|
|
||||||
uint8 *XBuf = NULL;
|
uint8 *XBuf = NULL;
|
||||||
|
static uint8 *xbsave = NULL;
|
||||||
|
|
||||||
void FCEU_KillVirtualVideo(void)
|
void FCEU_KillVirtualVideo(void) {
|
||||||
{
|
if (xbsave) {
|
||||||
if (XBuf)
|
free(xbsave);
|
||||||
free(XBuf);
|
xbsave = 0;
|
||||||
XBuf = 0;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int FCEU_InitVirtualVideo(void)
|
int FCEU_InitVirtualVideo(void) {
|
||||||
{
|
if (!XBuf) // Some driver code may allocate XBuf externally.
|
||||||
// 256 bytes per scanline, * 240 scanline maximum, +8 for alignment,
|
// 256 bytes per scanline, * 240 scanline maximum, +8 for alignment,
|
||||||
if (!XBuf)
|
if (!(XBuf = (uint8*)(FCEU_malloc(256 * 256 + 8))))
|
||||||
XBuf = (uint8*)(FCEU_malloc(256 * 256 + 8));
|
return 0;
|
||||||
|
xbsave = XBuf;
|
||||||
|
|
||||||
if (!XBuf)
|
if (sizeof(uint8*) == 4) {
|
||||||
return 0;
|
uint32 m;
|
||||||
|
m = (uint32)XBuf;
|
||||||
if (sizeof(uint8*) == 4)
|
m = (4 - m) & 3;
|
||||||
{
|
XBuf += m;
|
||||||
uintptr_t m;
|
}
|
||||||
m = (uintptr_t)*XBuf;
|
memset(XBuf, 128, 256 * 256);
|
||||||
m = (4 - m) & 3;
|
return 1;
|
||||||
XBuf += m;
|
|
||||||
}
|
|
||||||
memset(XBuf, 128, 256 * 256);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int howlong;
|
static int howlong;
|
||||||
static char errmsg[65];
|
static char errmsg[65];
|
||||||
|
|
||||||
#include "drawing.h"
|
#include "drawing.h"
|
||||||
|
#ifdef FRAMESKIP
|
||||||
|
|
||||||
void FCEUI_SaveSnapshot(void) { }
|
//#define SHOWFPS
|
||||||
|
void ShowFPS(void);
|
||||||
|
void FCEU_PutImageDummy(void) {
|
||||||
|
#ifdef SHOWFPS
|
||||||
|
ShowFPS();
|
||||||
|
#endif
|
||||||
|
if (GameInfo->type != GIT_NSF) {
|
||||||
|
FCEU_DrawNTSCControlBars(XBuf);
|
||||||
|
FCEU_DrawSaveStates(XBuf);
|
||||||
|
FCEU_DrawMovies(XBuf);
|
||||||
|
}
|
||||||
|
if (howlong) howlong--; /* DrawMessage() */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void FCEU_PutImage(void)
|
static int dosnapsave = 0;
|
||||||
{
|
void FCEUI_SaveSnapshot(void) {
|
||||||
if (GameInfo->type == GIT_NSF)
|
dosnapsave = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ReallySnap(void) {
|
||||||
|
int x = SaveSnapshot();
|
||||||
|
if (!x)
|
||||||
|
FCEU_DispMessage("Error saving screen snapshot.");
|
||||||
|
else
|
||||||
|
FCEU_DispMessage("Screen snapshot %d saved.", x - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEU_PutImage(void) {
|
||||||
|
#ifdef SHOWFPS
|
||||||
|
ShowFPS();
|
||||||
|
#endif
|
||||||
|
if (GameInfo->type == GIT_NSF) {
|
||||||
DrawNSF(XBuf);
|
DrawNSF(XBuf);
|
||||||
else
|
// Save snapshot after NSF screen is drawn. Why would we want to
|
||||||
{
|
// do it before?
|
||||||
|
if (dosnapsave) {
|
||||||
|
ReallySnap();
|
||||||
|
dosnapsave = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Save snapshot before overlay stuff is written.
|
||||||
|
if (dosnapsave) {
|
||||||
|
ReallySnap();
|
||||||
|
dosnapsave = 0;
|
||||||
|
}
|
||||||
if (GameInfo->type == GIT_VSUNI)
|
if (GameInfo->type == GIT_VSUNI)
|
||||||
FCEU_VSUniDraw(XBuf);
|
FCEU_VSUniDraw(XBuf);
|
||||||
|
FCEU_DrawSaveStates(XBuf);
|
||||||
|
FCEU_DrawMovies(XBuf);
|
||||||
|
FCEU_DrawNTSCControlBars(XBuf);
|
||||||
}
|
}
|
||||||
if (howlong) howlong--;
|
DrawMessage();
|
||||||
|
FCEU_DrawInput(XBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEU_PutImageDummy(void)
|
void FCEU_DispMessage(char *format, ...) {
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void FCEU_DispMessage(char *format, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
@@ -98,12 +136,158 @@ void FCEU_DispMessage(char *format, ...)
|
|||||||
howlong = 180;
|
howlong = 180;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEU_ResetMessages(void)
|
void FCEU_ResetMessages(void) {
|
||||||
{
|
howlong = 0;
|
||||||
howlong = 180;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SaveSnapshot(void)
|
|
||||||
{
|
static int WritePNGChunk(FILE *fp, uint32 size, char *type, uint8 *data) {
|
||||||
|
uint32 crc;
|
||||||
|
|
||||||
|
uint8 tempo[4];
|
||||||
|
|
||||||
|
tempo[0] = size >> 24;
|
||||||
|
tempo[1] = size >> 16;
|
||||||
|
tempo[2] = size >> 8;
|
||||||
|
tempo[3] = size;
|
||||||
|
|
||||||
|
if (fwrite(tempo, 4, 1, fp) != 1)
|
||||||
|
return 0;
|
||||||
|
if (fwrite(type, 4, 1, fp) != 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
if (fwrite(data, 1, size, fp) != size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
crc = CalcCRC32(0, (uint8*)type, 4);
|
||||||
|
if (size)
|
||||||
|
crc = CalcCRC32(crc, data, size);
|
||||||
|
|
||||||
|
tempo[0] = crc >> 24;
|
||||||
|
tempo[1] = crc >> 16;
|
||||||
|
tempo[2] = crc >> 8;
|
||||||
|
tempo[3] = crc;
|
||||||
|
|
||||||
|
if (fwrite(tempo, 4, 1, fp) != 1)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SaveSnapshot(void) {
|
||||||
|
static uint32 lastu = 0;
|
||||||
|
|
||||||
|
char *fn = 0;
|
||||||
|
int totallines = FSettings.LastSLine - FSettings.FirstSLine + 1;
|
||||||
|
int x, u, y;
|
||||||
|
FILE *pp = NULL;
|
||||||
|
uint8 *compmem = NULL;
|
||||||
|
uLongf compmemsize = totallines * 263 + 12;
|
||||||
|
|
||||||
|
if (!(compmem = (uint8*)FCEU_malloc(compmemsize)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (u = lastu; u < 99999; u++) {
|
||||||
|
pp = FCEUD_UTF8fopen((fn = FCEU_MakeFName(FCEUMKF_SNAP, u, "png")), "rb");
|
||||||
|
if (pp == NULL) break;
|
||||||
|
fclose(pp);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastu = u;
|
||||||
|
|
||||||
|
if (!(pp = FCEUD_UTF8fopen(fn, "wb"))) {
|
||||||
|
free(fn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
free(fn);
|
||||||
|
{
|
||||||
|
static uint8 header[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
|
||||||
|
if (fwrite(header, 8, 1, pp) != 1)
|
||||||
|
goto PNGerr;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
uint8 chunko[13];
|
||||||
|
|
||||||
|
chunko[0] = chunko[1] = chunko[3] = 0;
|
||||||
|
chunko[2] = 0x1; // Width of 256
|
||||||
|
|
||||||
|
chunko[4] = chunko[5] = chunko[6] = 0;
|
||||||
|
chunko[7] = totallines; // Height
|
||||||
|
|
||||||
|
chunko[8] = 8; // bit depth
|
||||||
|
chunko[9] = 3; // Color type; indexed 8-bit
|
||||||
|
chunko[10] = 0; // compression: deflate
|
||||||
|
chunko[11] = 0; // Basic adapative filter set(though none are used).
|
||||||
|
chunko[12] = 0; // No interlace.
|
||||||
|
|
||||||
|
if (!WritePNGChunk(pp, 13, "IHDR", chunko))
|
||||||
|
goto PNGerr;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
uint8 pdata[256 * 3];
|
||||||
|
for (x = 0; x < 256; x++)
|
||||||
|
FCEUD_GetPalette(x, pdata + x * 3, pdata + x * 3 + 1, pdata + x * 3 + 2);
|
||||||
|
if (!WritePNGChunk(pp, 256 * 3, "PLTE", pdata))
|
||||||
|
goto PNGerr;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
uint8 *tmp = XBuf + FSettings.FirstSLine * 256;
|
||||||
|
uint8 *dest, *mal, *mork;
|
||||||
|
|
||||||
|
if (!(mal = mork = dest = (uint8*)malloc((totallines << 8) + totallines)))
|
||||||
|
goto PNGerr;
|
||||||
|
// mork=dest=XBuf;
|
||||||
|
|
||||||
|
for (y = 0; y < totallines; y++) {
|
||||||
|
*dest = 0; // No filter.
|
||||||
|
dest++;
|
||||||
|
for (x = 256; x; x--, tmp++, dest++)
|
||||||
|
*dest = *tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compress(compmem, &compmemsize, mork, (totallines << 8) + totallines) != Z_OK) {
|
||||||
|
if (mal) free(mal);
|
||||||
|
goto PNGerr;
|
||||||
|
}
|
||||||
|
if (mal) free(mal);
|
||||||
|
if (!WritePNGChunk(pp, compmemsize, "IDAT", compmem))
|
||||||
|
goto PNGerr;
|
||||||
|
}
|
||||||
|
if (!WritePNGChunk(pp, 0, "IEND", 0))
|
||||||
|
goto PNGerr;
|
||||||
|
|
||||||
|
free(compmem);
|
||||||
|
fclose(pp);
|
||||||
|
|
||||||
|
return u + 1;
|
||||||
|
|
||||||
|
PNGerr:
|
||||||
|
if (compmem)
|
||||||
|
free(compmem);
|
||||||
|
if (pp)
|
||||||
|
fclose(pp);
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SHOWFPS
|
||||||
|
uint64 FCEUD_GetTime(void);
|
||||||
|
uint64 FCEUD_GetTimeFreq(void);
|
||||||
|
|
||||||
|
static uint64 boop[60];
|
||||||
|
static int boopcount = 0;
|
||||||
|
|
||||||
|
void ShowFPS(void) {
|
||||||
|
uint64 da = FCEUD_GetTime() - boop[boopcount];
|
||||||
|
char fpsmsg[16];
|
||||||
|
int booplimit = PAL ? 50 : 60;
|
||||||
|
boop[boopcount] = FCEUD_GetTime();
|
||||||
|
|
||||||
|
sprintf(fpsmsg, "%8.1f", (double)booplimit / ((double)da / FCEUD_GetTimeFreq()));
|
||||||
|
DrawTextTrans(XBuf + (256 - 8 - 8 * 8) + (FSettings.FirstSLine + 4) * 256, 256, fpsmsg, 4);
|
||||||
|
// It's not averaging FPS over exactly 1 second, but it's close enough.
|
||||||
|
boopcount = (boopcount + 1) % booplimit;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user