mirror of
https://github.com/dborth/fceugx.git
synced 2024-11-01 15:05:05 +01:00
875 lines
16 KiB
C
875 lines
16 KiB
C
/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "types.h"
|
|
#include "x6502.h"
|
|
#include "fceu.h"
|
|
#include "fds.h"
|
|
#include "sound.h"
|
|
#include "general.h"
|
|
#include "state.h"
|
|
#include "file.h"
|
|
#include "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 DECLFR(FDSBIOSRead);
|
|
static DECLFR(FDSRAMRead);
|
|
static DECLFW(FDSRAMWrite);
|
|
static void FDSInit(void);
|
|
static void FP_FASTAPASS(1) FDSFix(int a);
|
|
|
|
#define FDSRAM GameMemBlock
|
|
#define CHRRAM (GameMemBlock+32768)
|
|
|
|
static uint8 FDSRegs[6];
|
|
static int32 IRQLatch,IRQCount;
|
|
static uint8 IRQa;
|
|
static void FDSClose(void);
|
|
|
|
static uint8 FDSBIOS[8192];
|
|
|
|
/* 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 unsigned int TotalSides;
|
|
static uint8 DiskWritten=0; /* Set to 1 if disk was written to. */
|
|
static uint8 writeskip;
|
|
static uint32 DiskPtr;
|
|
static int32 DiskSeekIRQ;
|
|
static uint8 SelectDisk,InDisk;
|
|
|
|
#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));
|
|
writeskip=DiskPtr=DiskSeekIRQ=0;
|
|
setmirror(1);
|
|
|
|
setprg8r(0,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,FDSRAMWrite);
|
|
SetReadHandler(0x6000,0xdfff,FDSRAMRead);
|
|
SetReadHandler(0xE000,0xFFFF,FDSBIOSRead);
|
|
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;
|
|
//IRQCount=IRQLatch; //0xFFFF;
|
|
X6502_IRQBegin(FCEU_IQEXT);
|
|
//printf("IRQ: %d\n",timestamp);
|
|
// printf("IRQ: %d\n",scanline);
|
|
}
|
|
}
|
|
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;
|
|
|
|
if(!fceuindbg)
|
|
{
|
|
X6502_IRQEnd(FCEU_IQEXT);
|
|
X6502_IRQEnd(FCEU_IQEXT2);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static DECLFR(FDSRead4031)
|
|
{
|
|
static uint8 z=0;
|
|
if(InDisk!=255)
|
|
{
|
|
z=diskdata[InDisk][DiskPtr];
|
|
if(!fceuindbg)
|
|
{
|
|
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
|
|
}
|
|
|
|
static DECLFW(FDSRAMWrite)
|
|
{
|
|
(FDSRAM-0x6000)[A]=V;
|
|
}
|
|
|
|
static DECLFR(FDSBIOSRead)
|
|
{
|
|
return (FDSBIOS-0xE000)[A];
|
|
}
|
|
|
|
static DECLFR(FDSRAMRead)
|
|
{
|
|
return (FDSRAM-0x6000)[A];
|
|
}
|
|
|
|
/* 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; //)>0x20?0x20:(V&0x3F);
|
|
break;
|
|
case 0x5://printf("$%04x:$%02x\n",A,V);
|
|
break;
|
|
case 0x7: b17latch76=0;SPSG[0x5]=0;//printf("$%04x:$%02x\n",A,V);
|
|
break;
|
|
case 0x8:
|
|
b17latch76=0;
|
|
// printf("%d:$%02x, $%02x\n",SPSG[0x5],V,b17latch76);
|
|
fdso.mwave[SPSG[0x5]&0x1F]=V&0x7;
|
|
SPSG[0x5]=(SPSG[0x5]+1)&0x1F;
|
|
break;
|
|
}
|
|
//if(A>=0x7 && A!=0x8 && A<=0xF)
|
|
//if(A==0xA || A==0x9)
|
|
//printf("$%04x:$%02x\n",A,V);
|
|
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)
|
|
{
|
|
//printf("$%04x:$%02x, %d\n",A,V,SPSG[0x9]&0x80);
|
|
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;
|
|
//if(adj) printf("%d ",adj);
|
|
b8shiftreg88=0x80 + adj;
|
|
}
|
|
else
|
|
{
|
|
b8shiftreg88=0x80;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
b19shiftreg60<<=1;
|
|
b8shiftreg88>>=1;
|
|
}
|
|
// b24adder66=(b24latch68+b19shiftreg60)&0x3FFFFFF;
|
|
b24adder66=(b24latch68+b19shiftreg60)&0x1FFFFFF;
|
|
}
|
|
|
|
static INLINE void ClockFall(void)
|
|
{
|
|
//if(!(SPSG[0x7]&0x80))
|
|
{
|
|
if((b8shiftreg88&1)) // || clockcount==7)
|
|
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)
|
|
{
|
|
int32 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 DECLFR(FDSBIOSPatch)
|
|
{
|
|
if(FDSRegs[5]&0x4)
|
|
{
|
|
X.X=FDSRead4031(0x4031);
|
|
FDSWrite(0x4024,X.A);
|
|
X.A=X.X;
|
|
return(0x60);
|
|
}
|
|
else
|
|
{
|
|
return(0x58);
|
|
//puts("Write");
|
|
}
|
|
}
|
|
*/
|
|
|
|
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;
|
|
}
|
|
}
|
|
// fdso.cycles=(int64)32768*FDSClock/(FSettings.SndRate *16);
|
|
SetReadHandler(0x4040,0x407f,FDSWaveRead);
|
|
SetWriteHandler(0x4040,0x407f,FDSWaveWrite);
|
|
SetWriteHandler(0x4080,0x408A,FDSSWrite);
|
|
SetReadHandler(0x4090,0x4092,FDSSRead);
|
|
|
|
//SetReadHandler(0xE7A3,0xE7A3,FDSBIOSPatch);
|
|
}
|
|
|
|
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)
|
|
{
|
|
//extern int scanline;
|
|
//FCEU_printf("$%04x:$%02x, %d\n",A,V,scanline);
|
|
switch(A)
|
|
{
|
|
case 0x4020:
|
|
X6502_IRQEnd(FCEU_IQEXT);
|
|
IRQLatch&=0xFF00;
|
|
IRQLatch|=V;
|
|
// printf("$%04x:$%02x\n",A,V);
|
|
break;
|
|
case 0x4021:
|
|
X6502_IRQEnd(FCEU_IQEXT);
|
|
IRQLatch&=0xFF;
|
|
IRQLatch|=V<<8;
|
|
// printf("$%04x:$%02x\n",A,V);
|
|
break;
|
|
case 0x4022:
|
|
X6502_IRQEnd(FCEU_IQEXT);
|
|
IRQCount=IRQLatch;
|
|
IRQa=V&3;
|
|
// printf("$%04x:$%02x\n",A,V);
|
|
break;
|
|
case 0x4023: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;
|
|
}
|
|
}
|
|
}
|
|
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,FCEUGameInfo->MD5);
|
|
return(1);
|
|
}
|
|
|
|
static void PreSave(void)
|
|
{
|
|
int x;
|
|
|
|
//if(DiskWritten)
|
|
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;
|
|
|
|
//if(DiskWritten)
|
|
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_fseek(fp,0,SEEK_SET);
|
|
|
|
if(!SubLoad(fp))
|
|
return(0);
|
|
|
|
|
|
fn = FCEU_MakeFName(FCEUMKF_FDSROM,0,0);
|
|
|
|
if(!(zp=FCEUD_UTF8fopen(fn,"rb")))
|
|
{
|
|
FCEU_PrintError("FDS BIOS ROM image missing!");
|
|
FreeFDSMemory();
|
|
free(fn);
|
|
return 0;
|
|
}
|
|
|
|
free(fn);
|
|
|
|
if(fread(FDSBIOS,1,8192,zp)!=8192)
|
|
{
|
|
fclose(zp);
|
|
FreeFDSMemory();
|
|
FCEU_PrintError("Error reading FDS BIOS ROM image.");
|
|
return 0;
|
|
}
|
|
|
|
fclose(zp);
|
|
|
|
|
|
{
|
|
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)))
|
|
{
|
|
FreeFDSMemory();
|
|
if(!SubLoad(tp))
|
|
{
|
|
FCEU_PrintError("Error reading auxillary FDS file.");
|
|
free(fn);
|
|
return(0);
|
|
}
|
|
FCEU_fclose(tp);
|
|
DiskWritten=1; /* For save state handling. */
|
|
}
|
|
free(fn);
|
|
}
|
|
|
|
FCEUGameInfo->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(FDSRAM,32768,0,"FDSR");
|
|
AddExState(FDSRegs,sizeof(FDSRegs),0,"FREG");
|
|
AddExState(CHRRAM,8192,0,"CHRR");
|
|
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");
|
|
|
|
ResetCartMapping();
|
|
SetupCartCHRMapping(0,CHRRAM,8192,1);
|
|
SetupCartMirroring(0,0,0);
|
|
memset(CHRRAM,0,8192);
|
|
memset(FDSRAM,0,32768);
|
|
|
|
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=FCEUD_UTF8fopen(fn,"wb")))
|
|
{
|
|
free(fn);
|
|
return;
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
FreeFDSMemory();
|
|
fclose(fp);
|
|
}
|