mirror of
https://github.com/dborth/fceugx.git
synced 2024-11-01 15:05:05 +01:00
472 lines
9.4 KiB
C++
472 lines
9.4 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 "mapinc.h"
|
|
|
|
static uint16 IRQCount;
|
|
static uint8 IRQa;
|
|
|
|
static uint8 WRAM[8192];
|
|
static uint8 IRAM[128];
|
|
|
|
static DECLFR(AWRAM)
|
|
{
|
|
return(WRAM[A-0x6000]);
|
|
}
|
|
|
|
static DECLFW(BWRAM)
|
|
{
|
|
WRAM[A-0x6000]=V;
|
|
}
|
|
|
|
void Mapper19_ESI(void);
|
|
|
|
static uint8 NTAPage[4];
|
|
|
|
static uint8 dopol;
|
|
static uint8 gorfus;
|
|
static uint8 gorko;
|
|
|
|
static void NamcoSound(int Count);
|
|
static void NamcoSoundHack(void);
|
|
static void DoNamcoSound(int32 *Wave, int Count);
|
|
static void DoNamcoSoundHQ(void);
|
|
static void SyncHQ(int32 ts);
|
|
|
|
static int is210; /* Lesser mapper. */
|
|
|
|
static uint8 PRG[3];
|
|
static uint8 CHR[8];
|
|
|
|
static SFORMAT N106_StateRegs[]={
|
|
{PRG,3,"PRG"},
|
|
{CHR,8,"CHR"},
|
|
{NTAPage,4,"NTA"},
|
|
{0}
|
|
};
|
|
|
|
static void SyncPRG(void)
|
|
{
|
|
setprg8(0x8000,PRG[0]);
|
|
setprg8(0xa000,PRG[1]);
|
|
setprg8(0xc000,PRG[2]);
|
|
setprg8(0xe000,0x3F);
|
|
}
|
|
|
|
static void NamcoIRQHook(int a)
|
|
{
|
|
if(IRQa)
|
|
{
|
|
IRQCount+=a;
|
|
if(IRQCount>=0x7FFF)
|
|
{
|
|
X6502_IRQBegin(FCEU_IQEXT);
|
|
IRQa=0;
|
|
IRQCount=0x7FFF; //7FFF;
|
|
}
|
|
}
|
|
}
|
|
|
|
static DECLFR(Namco_Read4800)
|
|
{
|
|
uint8 ret=IRAM[dopol&0x7f];
|
|
/* Maybe I should call NamcoSoundHack() here? */
|
|
if(!fceuindbg)
|
|
if(dopol&0x80)
|
|
dopol=(dopol&0x80)|((dopol+1)&0x7f);
|
|
return ret;
|
|
}
|
|
|
|
static DECLFR(Namco_Read5000)
|
|
{
|
|
return(IRQCount);
|
|
}
|
|
|
|
static DECLFR(Namco_Read5800)
|
|
{
|
|
return(IRQCount>>8);
|
|
}
|
|
|
|
static void DoNTARAMROM(int w, uint8 V)
|
|
{
|
|
NTAPage[w]=V;
|
|
if(V>=0xE0)
|
|
setntamem(NTARAM+((V&1)<<10), 1, w);
|
|
else
|
|
{
|
|
V&=CHRmask1[0];
|
|
setntamem(CHRptr[0]+(V<<10), 0, w);
|
|
}
|
|
}
|
|
|
|
static void FixNTAR(void)
|
|
{
|
|
int x;
|
|
for(x=0;x<4;x++)
|
|
DoNTARAMROM(x,NTAPage[x]);
|
|
}
|
|
|
|
static void DoCHRRAMROM(int x, uint8 V)
|
|
{
|
|
CHR[x]=V;
|
|
if(!is210 && !((gorfus>>((x>>2)+6))&1) && (V>=0xE0))
|
|
{
|
|
// printf("BLAHAHA: %d, %02x\n",x,V);
|
|
//setchr1r(0x10,x<<10,V&7);
|
|
}
|
|
else
|
|
setchr1(x<<10,V);
|
|
}
|
|
|
|
static void FixCRR(void)
|
|
{
|
|
int x;
|
|
for(x=0;x<8;x++)
|
|
DoCHRRAMROM(x,CHR[x]);
|
|
}
|
|
|
|
static DECLFW(Mapper19C0D8_write)
|
|
{
|
|
DoNTARAMROM((A-0xC000)>>11,V);
|
|
}
|
|
|
|
static uint32 FreqCache[8];
|
|
static uint32 EnvCache[8];
|
|
static uint32 LengthCache[8];
|
|
|
|
static void FixCache(int a,int V)
|
|
{
|
|
int w=(a>>3)&0x7;
|
|
switch(a&0x07)
|
|
{
|
|
case 0x00:FreqCache[w]&=~0x000000FF;FreqCache[w]|=V;break;
|
|
case 0x02:FreqCache[w]&=~0x0000FF00;FreqCache[w]|=V<<8;break;
|
|
case 0x04:FreqCache[w]&=~0x00030000;FreqCache[w]|=(V&3)<<16;
|
|
LengthCache[w]=(8-((V>>2)&7))<<2;
|
|
break;
|
|
case 0x07:EnvCache[w]=(double)(V&0xF)*576716;break;
|
|
}
|
|
}
|
|
|
|
static DECLFW(Mapper19_write)
|
|
{
|
|
A&=0xF800;
|
|
if(A>=0x8000 && A<=0xb800)
|
|
DoCHRRAMROM((A-0x8000)>>11,V);
|
|
else switch(A)
|
|
{
|
|
case 0x4800:
|
|
if(dopol&0x40)
|
|
{
|
|
if(FSettings.SndRate)
|
|
{
|
|
NamcoSoundHack();
|
|
GameExpSound.Fill=NamcoSound;
|
|
GameExpSound.HiFill=DoNamcoSoundHQ;
|
|
GameExpSound.HiSync=SyncHQ;
|
|
}
|
|
FixCache(dopol,V);
|
|
}
|
|
IRAM[dopol&0x7f]=V;
|
|
if(dopol&0x80)
|
|
dopol=(dopol&0x80)|((dopol+1)&0x7f);
|
|
break;
|
|
case 0xf800:
|
|
dopol=V;break;
|
|
case 0x5000:
|
|
IRQCount&=0xFF00;IRQCount|=V;X6502_IRQEnd(FCEU_IQEXT);break;
|
|
case 0x5800:
|
|
IRQCount&=0x00ff;IRQCount|=(V&0x7F)<<8;
|
|
IRQa=V&0x80;
|
|
X6502_IRQEnd(FCEU_IQEXT);
|
|
break;
|
|
case 0xE000:
|
|
gorko=V&0xC0;
|
|
PRG[0]=V&0x3F;
|
|
SyncPRG();
|
|
break;
|
|
case 0xE800:
|
|
gorfus=V&0xC0;
|
|
FixCRR();
|
|
PRG[1]=V&0x3F;
|
|
SyncPRG();
|
|
break;
|
|
case 0xF000:
|
|
PRG[2]=V&0x3F;
|
|
SyncPRG();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int dwave=0;
|
|
|
|
static void NamcoSoundHack(void)
|
|
{
|
|
int32 z,a;
|
|
if(FSettings.soundq>=1)
|
|
{
|
|
DoNamcoSoundHQ();
|
|
return;
|
|
}
|
|
z=((SOUNDTS<<16)/soundtsinc)>>4;
|
|
a=z-dwave;
|
|
if(a) DoNamcoSound(&Wave[dwave], a);
|
|
dwave+=a;
|
|
}
|
|
|
|
static void NamcoSound(int Count)
|
|
{
|
|
int32 z,a;
|
|
z=((SOUNDTS<<16)/soundtsinc)>>4;
|
|
a=z-dwave;
|
|
if(a) DoNamcoSound(&Wave[dwave], a);
|
|
dwave=0;
|
|
}
|
|
|
|
static uint32 PlayIndex[8];
|
|
static int32 vcount[8];
|
|
static int32 CVBC;
|
|
|
|
#define TOINDEX (16+1)
|
|
|
|
// 16:15
|
|
static void SyncHQ(int32 ts)
|
|
{
|
|
CVBC=ts;
|
|
}
|
|
|
|
|
|
/* Things to do:
|
|
1 Read freq low
|
|
2 Read freq mid
|
|
3 Read freq high
|
|
4 Read envelope
|
|
...?
|
|
*/
|
|
|
|
static INLINE uint32 FetchDuff(uint32 P, uint32 envelope)
|
|
{
|
|
uint32 duff;
|
|
duff=IRAM[((IRAM[0x46+(P<<3)]+(PlayIndex[P]>>TOINDEX))&0xFF)>>1];
|
|
if((IRAM[0x46+(P<<3)]+(PlayIndex[P]>>TOINDEX))&1)
|
|
duff>>=4;
|
|
duff&=0xF;
|
|
duff=(duff*envelope)>>16;
|
|
return(duff);
|
|
}
|
|
|
|
static void DoNamcoSoundHQ(void)
|
|
{
|
|
uint32 V; //mbg merge 7/17/06 made uint32
|
|
int32 P;
|
|
int32 cyclesuck=(((IRAM[0x7F]>>4)&7)+1)*15;
|
|
|
|
for(P=7;P>=(7-((IRAM[0x7F]>>4)&7));P--)
|
|
{
|
|
if((IRAM[0x44+(P<<3)]&0xE0) && (IRAM[0x47+(P<<3)]&0xF))
|
|
{
|
|
uint32 freq;
|
|
int32 vco;
|
|
uint32 duff2,lengo,envelope;
|
|
|
|
vco=vcount[P];
|
|
freq=FreqCache[P];
|
|
envelope=EnvCache[P];
|
|
lengo=LengthCache[P];
|
|
|
|
duff2=FetchDuff(P,envelope);
|
|
for(V=CVBC<<1;V<SOUNDTS<<1;V++)
|
|
{
|
|
WaveHi[V>>1]+=duff2;
|
|
if(!vco)
|
|
{
|
|
PlayIndex[P]+=freq;
|
|
while((PlayIndex[P]>>TOINDEX)>=lengo) PlayIndex[P]-=lengo<<TOINDEX;
|
|
duff2=FetchDuff(P,envelope);
|
|
vco=cyclesuck;
|
|
}
|
|
vco--;
|
|
}
|
|
vcount[P]=vco;
|
|
}
|
|
}
|
|
CVBC=SOUNDTS;
|
|
}
|
|
|
|
|
|
static void DoNamcoSound(int32 *Wave, int Count)
|
|
{
|
|
int P,V;
|
|
for(P=7;P>=7-((IRAM[0x7F]>>4)&7);P--)
|
|
{
|
|
if((IRAM[0x44+(P<<3)]&0xE0) && (IRAM[0x47+(P<<3)]&0xF))
|
|
{
|
|
int32 inc;
|
|
uint32 freq;
|
|
int32 vco;
|
|
uint32 duff,duff2,lengo,envelope;
|
|
|
|
vco=vcount[P];
|
|
freq=FreqCache[P];
|
|
envelope=EnvCache[P];
|
|
lengo=LengthCache[P];
|
|
|
|
if(!freq) {/*printf("Ack");*/ continue;}
|
|
|
|
{
|
|
int c=((IRAM[0x7F]>>4)&7)+1;
|
|
inc=(long double)(FSettings.SndRate<<15)/((long double)freq*21477272/((long double)0x400000*c*45));
|
|
}
|
|
|
|
duff=IRAM[(((IRAM[0x46+(P<<3)]+PlayIndex[P])&0xFF)>>1)];
|
|
if((IRAM[0x46+(P<<3)]+PlayIndex[P])&1)
|
|
duff>>=4;
|
|
duff&=0xF;
|
|
duff2=(duff*envelope)>>19;
|
|
for(V=0;V<Count*16;V++)
|
|
{
|
|
if(vco>=inc)
|
|
{
|
|
PlayIndex[P]++;
|
|
if(PlayIndex[P]>=lengo)
|
|
PlayIndex[P]=0;
|
|
vco-=inc;
|
|
duff=IRAM[(((IRAM[0x46+(P<<3)]+PlayIndex[P])&0xFF)>>1)];
|
|
if((IRAM[0x46+(P<<3)]+PlayIndex[P])&1)
|
|
duff>>=4;
|
|
duff&=0xF;
|
|
duff2=(duff*envelope)>>19;
|
|
}
|
|
Wave[V>>4]+=duff2;
|
|
vco+=0x8000;
|
|
}
|
|
vcount[P]=vco;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Mapper19_StateRestore(int version)
|
|
{
|
|
int x;
|
|
SyncPRG();
|
|
FixNTAR();
|
|
FixCRR();
|
|
for(x=0x40;x<0x80;x++)
|
|
FixCache(x,IRAM[x]);
|
|
}
|
|
|
|
static void M19SC(void)
|
|
{
|
|
if(FSettings.SndRate)
|
|
Mapper19_ESI();
|
|
}
|
|
|
|
void Mapper19_ESI(void)
|
|
{
|
|
GameExpSound.RChange=M19SC;
|
|
memset(vcount,0,sizeof(vcount));
|
|
memset(PlayIndex,0,sizeof(PlayIndex));
|
|
CVBC=0;
|
|
}
|
|
|
|
void NSFN106_Init(void)
|
|
{
|
|
SetWriteHandler(0xf800,0xffff,Mapper19_write);
|
|
SetWriteHandler(0x4800,0x4fff,Mapper19_write);
|
|
SetReadHandler(0x4800,0x4fff,Namco_Read4800);
|
|
Mapper19_ESI();
|
|
}
|
|
|
|
static int battery=0;
|
|
|
|
static void N106_Power(void)
|
|
{
|
|
int x;
|
|
SetReadHandler(0x8000,0xFFFF,CartBR);
|
|
SetWriteHandler(0x8000,0xffff,Mapper19_write);
|
|
SetWriteHandler(0x4020,0x5fff,Mapper19_write);
|
|
if(!is210)
|
|
{
|
|
SetWriteHandler(0xc000,0xdfff,Mapper19C0D8_write);
|
|
SetReadHandler(0x4800,0x4fff,Namco_Read4800);
|
|
SetReadHandler(0x5000,0x57ff,Namco_Read5000);
|
|
SetReadHandler(0x5800,0x5fff,Namco_Read5800);
|
|
NTAPage[0]=NTAPage[1]=NTAPage[2]=NTAPage[3]=0xFF;
|
|
FixNTAR();
|
|
}
|
|
|
|
SetReadHandler(0x6000,0x7FFF,AWRAM);
|
|
SetWriteHandler(0x6000,0x7FFF,BWRAM);
|
|
FCEU_CheatAddRAM(8,0x6000,WRAM);
|
|
|
|
gorfus=0xFF;
|
|
SyncPRG();
|
|
FixCRR();
|
|
|
|
if(!battery)
|
|
{
|
|
FCEU_dwmemset(WRAM,0,8192);
|
|
FCEU_dwmemset(IRAM,0,128);
|
|
}
|
|
for(x=0x40;x<0x80;x++)
|
|
FixCache(x,IRAM[x]);
|
|
}
|
|
|
|
void Mapper19_Init(CartInfo *info)
|
|
{
|
|
is210=0;
|
|
battery=info->battery;
|
|
info->Power=N106_Power;
|
|
|
|
MapIRQHook=NamcoIRQHook;
|
|
GameStateRestore=Mapper19_StateRestore;
|
|
GameExpSound.RChange=M19SC;
|
|
|
|
if(FSettings.SndRate)
|
|
Mapper19_ESI();
|
|
|
|
AddExState(WRAM, 8192, 0, "WRAM");
|
|
AddExState(IRAM, 128, 0, "IRAM");
|
|
AddExState(N106_StateRegs, ~0, 0, 0);
|
|
|
|
if(info->battery)
|
|
{
|
|
info->SaveGame[0]=WRAM;
|
|
info->SaveGameLen[0]=8192;
|
|
info->SaveGame[1]=IRAM;
|
|
info->SaveGameLen[1]=128;
|
|
}
|
|
}
|
|
|
|
static void Mapper210_StateRestore(int version)
|
|
{
|
|
SyncPRG();
|
|
FixCRR();
|
|
}
|
|
|
|
void Mapper210_Init(CartInfo *info)
|
|
{
|
|
is210=1;
|
|
GameStateRestore=Mapper210_StateRestore;
|
|
info->Power=N106_Power;
|
|
AddExState(WRAM, 8192, 0, "WRAM");
|
|
AddExState(N106_StateRegs, ~0, 0, 0);
|
|
}
|