X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=fceu.git;a=blobdiff_plain;f=fds.c;h=f0640a0f2ff98ebe0aa5a732bcd1a0b41172777d;hp=455acc5ed53a0ede9f331512dd2da17ac1bde9c4;hb=d97315ac0bca825d2d50a44453bc5652946e2c67;hpb=890e37ba2b8ea1c7593dc05926d7431e3bd00bfb diff --git a/fds.c b/fds.c index 455acc5..f0640a0 100644 --- a/fds.c +++ b/fds.c @@ -1,709 +1,895 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 Ben Parnell - * - * 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 -#include -#include - -#include "types.h" -#include "x6502.h" -#include "version.h" -#include "fce.h" -#include "fds.h" -#include "svga.h" -#include "sound.h" -#include "general.h" -#include "state.h" -#include "file.h" -#include "memory.h" -#include "cart.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(FDSWrite4020); -static DECLFW(FDSWrite4021); -static DECLFW(FDSWrite4022); -static DECLFW(FDSWrite4023); -static DECLFW(FDSWrite4024); -static DECLFW(FDSWrite4025); -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 FDSReset(void); -static void FP_FASTAPASS(1) FDSFix(int a); - -#define FDSRAM GameMemBlock -#define mapbyte1 (GameMemBlock+32768) -#define mapbyte2 (GameMemBlock+32768+8) -#define mapbyte3 (GameMemBlock+32768+16) -#define mapbyte4 (GameMemBlock+32768+24) // 8 bytes -#define CHRRAM (GameMemBlock+32768+32+64) - -#define IRQLatch (*(int32*)(CHRRAM+8192)) -#define IRQCount (*(int32*)(CHRRAM+8192+4)) -#define IRQa (*(CHRRAM+8192+8)) - -static void FDSClose(void); -static uint8 header[16]; -#define writeskip mapbyte2[0] - -static char FDSSaveName[2048]; - -uint8 FDSBIOS[8192]; -uint8 *diskdata[4]={0,0,0,0}; - -#define SideWrite mapbyte2[1] -#define DiskPtr (*(uint32*)(mapbyte2+4)) -#define dsr0 mapbyte2[2] -#define dsr1 mapbyte2[3] - -#define DC_INC 1 - -#define DiskSeekIRQ (*(int32*)(mapbyte3+4)) -#define SelectDisk mapbyte3[0] -#define InDisk mapbyte3[1] - -static void FDSReset(void) -{ - memset(mapbyte1,0,8); - memset(mapbyte2,0,8); - memset(mapbyte3+4,0,4); - memset(mapbyte4,0,8); -} - -void FDSGI(int h) -{ - switch(h) - { - case GI_CLOSE: FDSClose();break; - case GI_POWER: FDSReset();FDSInit();break; - } -} - -static void FDSStateRestore(int version) -{ - setmirror(((mapbyte1[5]&8)>>3)^1); -} - -void FDSSound(); -void FDSSoundReset(void); -void FDSSoundStateAdd(void); -static void RenderSound(void); - -static void FDSInit(void) -{ - dsr0=0; - dsr1=0x41; - setmirror(1); - if(InDisk!=255) - dsr1&=0xFE; - - 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,0x4020,FDSWrite4020); - SetWriteHandler(0x4021,0x4021,FDSWrite4021); - SetWriteHandler(0x4022,0x4022,FDSWrite4022); - SetWriteHandler(0x4023,0x4023,FDSWrite4023); - SetWriteHandler(0x4024,0x4024,FDSWrite4024); - SetWriteHandler(0x4025,0x4025,FDSWrite4025); - - SetWriteHandler(0x6000,0xdfff,FDSRAMWrite); - SetReadHandler(0x6000,0xdfff,FDSRAMRead); - SetReadHandler(0xE000,0xFFFF,FDSBIOSRead); - - IRQCount=IRQLatch=IRQa=0; - - FDSSoundReset(); -} - -void FDSControl(int what) -{ - switch(what) - { - case FDS_IDISK:dsr1&=0xFE; - if(InDisk==255) - { - FCEU_DispMessage("Disk %d Side %s Inserted", - SelectDisk>>1,(SelectDisk&1)?"B":"A"); - InDisk=SelectDisk; - } - else - FCEU_DispMessage("Jamming disks is a BAD IDEA"); - break; - case FDS_EJECT: - if(InDisk!=255) - FCEU_DispMessage("Disk Ejected"); - else - FCEU_DispMessage("Cannot Eject Air"); - dsr1|=1; - InDisk=255; - break; - case FDS_SELECT: - if(InDisk!=255) - { - FCEU_DispMessage("Eject disk before selecting."); - break; - } - SelectDisk=((SelectDisk+1)%header[4])&3; - FCEU_DispMessage("Disk %d Side %s Selected", - SelectDisk>>1,(SelectDisk&1)?"B":"A"); - break; - } -} - -static void FP_FASTAPASS(1) FDSFix(int a) -{ - if(IRQa) - { - IRQCount-=a; - if(IRQCount<=0) - { - IRQa=0; - dsr0|=1; - dsr0&=~2; - IRQCount=0xFFFF; - X6502_IRQBegin(FCEU_IQEXT); - } - } - if(DiskSeekIRQ>0) - { - DiskSeekIRQ-=a; - if(DiskSeekIRQ<=0) - { - if(mapbyte1[5]&0x80) - { - dsr0&=~1; - dsr0|=2; - TriggerIRQ(); - } - } - } -} - -void DiskControl(int which) -{ -if(mapbyte1[5]&1) - { - switch(which) - { - case DC_INC: - if(DiskPtr<64999) DiskPtr++; - //DiskSeekIRQ=160+100; - //DiskSeekIRQ=140; - //DiskSeekIRQ=160; - DiskSeekIRQ=150; - break; - } - } -} -static DECLFR(FDSRead4030) -{ - X6502_IRQEnd(FCEU_IQEXT); - return dsr0; -} - -static DECLFR(FDSRead4031) -{ - static uint8 z=0; - if(InDisk!=255) - { - z=diskdata[InDisk][DiskPtr]; - DiskControl(DC_INC); - } - return z; -} - -static DECLFR(FDSRead4032) -{ - return dsr1; -} - -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/8) - -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 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 - -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) - RenderSound(); - A-=0x4080; - switch(A) - { - case 0x0: - case 0x4: - if(!(V&0x80)) - { - // if(V&0x40) amplitude[(A&0xF)>>2]=0; - // else amplitude[(A&0xF)>>2]=0x3F; - } - else - amplitude[(A&0xF)>>2]=V&0x3F; - break; - case 0x7: b17latch76=0;SPSG[0x5]=0;break; - case 0x8: - //printf("%d:$%02x\n",SPSG[0x5],V); - 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[0x9+x]&0x80)) - { - static int counto[2]={0,0}; - - if(counto[x]<=0) - { - 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 INLINE void ClockRise(void) -{ - if(!clockcount) - { - b19shiftreg60=(SPSG[0x2]|((SPSG[0x3]&0xF)<<8)); - b17latch76=(SPSG[0x6]|((SPSG[0x07]&0x3)<<8))+b17latch76; - - if(!(SPSG[0x7]&0x80)) - { - b8shiftreg88=(amplitude[1]*((fdso.mwave[(b17latch76>>11)&0x1F]&7))); - //b8shiftreg88=((fdso.mwave[(b17latch76>>11)&0x1F]&7))|(amplitude[1]<<3); - } - else - { b8shiftreg88=0;} - } - else - { - b19shiftreg60<<=1; - b8shiftreg88>>=1; - } - b24adder66=(b24latch68+b19shiftreg60)&0xFFFFFF; -} - -static INLINE void ClockFall(void) -{ -// if(!(SPSG[0x7]&0x80)) - { - 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(); - } - if(fdso.count>=32768) goto dogk; - - fdso.envcount-=fdso.cycles; - if(fdso.envcount<=0) - { - // Fix this? - fdso.envcount+=((int64)1<<40)*FDSClock/1024; - DoEnv(); - } - - // Might need to emulate applying the amplitude to the waveform a bit better... - return (fdso.cwave[b24latch68>>18]*amplitude[0]); -} - -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>4]+=t>>3; - } -} - -void FDSSound(int c) -{ - RenderSound(); - FBC=c; -} - -static void FDS_ESI(void) -{ - if(FSettings.SndRate) - { - fdso.cycles=((int64)1<<40)*FDSClock; - fdso.cycles/=FSettings.SndRate OVERSAMPLE; - } -// fdso.cycles=(int64)32768*FDSClock/(FSettings.SndRate OVERSAMPLE); - 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.Fill=FDSSound; - GameExpSound.RChange=FDS_ESI; -} - - -static DECLFW(FDSWrite4020) -{ - X6502_IRQEnd(FCEU_IQEXT); - IRQLatch&=0xFF00; - IRQLatch|=V; - mapbyte1[0]=V; -} -static DECLFW(FDSWrite4021) -{ - X6502_IRQEnd(FCEU_IQEXT); - IRQLatch&=0xFF; - IRQLatch|=V<<8; - mapbyte1[1]=V; -} -static DECLFW(FDSWrite4022) -{ - X6502_IRQEnd(FCEU_IQEXT); - IRQCount=IRQLatch; - IRQa=V&2; - mapbyte1[2]=V; -} -static DECLFW(FDSWrite4023) -{ - mapbyte1[3]=V; -} -static DECLFW(FDSWrite4024) -{ - if(InDisk!=255 && !(mapbyte1[5]&0x4) && mapbyte1[3]&0x1) - { - if(DiskPtr>=0 && DiskPtr<65000) - { - if(writeskip) writeskip--; - else if(DiskPtr>=2) - { - SideWrite|=1<>3)&1)^1); -} -static void FreeFDSMemory(void) -{ - int x; - - for(x=0;x4) header[4]=4; - if(!header[4]) header[4]|=1; - for(x=0;x +#include +#include + +#include "types.h" +#include "x6502.h" +#include "fce.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" + +#include "svga.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>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(TotalSides==0) + { + FCEU_DispMessage("Not FDS; can't select disk."); + return; + } + if(InDisk!=255) + { + FCEU_DispMessage("Eject disk before selecting."); + return; + } + SelectDisk=((SelectDisk+1)%TotalSides)&3; + FCEU_DispMessage("Disk %d Side %c 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 0 + if(FSettings.soundq>=1) + RenderSoundHQ(); + else +#endif + 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>1; + t>>=4; + Wave[x>>4]+=t; //(t>>2)-(t>>3); //>>3; + } +} + +#if 0 +static void RenderSoundHQ(void) +{ + int32 x; + + if(!(SPSG[0x9]&0x80)) + for(x=FBC;x>1; + WaveHi[x]+=t; //(t<<2)-(t<<1); + } + FBC=SOUNDTS; +} +#endif + +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 0 + if(FSettings.soundq>=1) + { + fdso.cycles=(int64)1<<39; + } + else +#endif + { + 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=0;//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;x8) TotalSides=8; + if(TotalSides<1) TotalSides=1; + + for(x=0;x