mirror of
https://github.com/dborth/fceugx.git
synced 2024-12-26 08:31:56 +01:00
344 lines
6.8 KiB
C
344 lines
6.8 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 int is209;
|
|
|
|
static uint8 IRQMode; // from $c001
|
|
static uint8 IRQPre; // from $c004
|
|
static uint8 IRQPreSize; // from $c007
|
|
static uint8 IRQCount; // from $c005
|
|
static uint8 IRQXOR; // Loaded from $C006
|
|
static uint8 IRQa; // $c002, $c003, and $c000
|
|
|
|
static uint8 mul[2];
|
|
static uint8 regie;
|
|
|
|
static uint8 tkcom[4];
|
|
static uint8 prgb[4];
|
|
static uint8 chrlow[8];
|
|
static uint8 chrhigh[8];
|
|
|
|
static uint16 names[4];
|
|
static uint8 tekker;
|
|
|
|
static SFORMAT Tek_StateRegs[]={
|
|
{&IRQCount, 1, "IRQC"},
|
|
{&IRQa, 1, "IRQa"},
|
|
{mul, 2, "MUL"},
|
|
{®ie, 1, "REGI"},
|
|
{tkcom, 4, "TKCO"},
|
|
{prgb, 4, "PRGB"},
|
|
{chrlow, 4, "CHRL"},
|
|
{chrhigh, 8, "CHRH"},
|
|
{&names[0], 2|FCEUSTATE_RLSB, "NMS0"},
|
|
{&names[1], 2|FCEUSTATE_RLSB, "NMS1"},
|
|
{&names[2], 2|FCEUSTATE_RLSB, "NMS2"},
|
|
{&names[3], 2|FCEUSTATE_RLSB, "NMS3"},
|
|
{&tekker, 1, "TEKR"},
|
|
{0}
|
|
};
|
|
|
|
static DECLFR(tekread)
|
|
{
|
|
//FCEU_printf("READ READ READ: $%04x, $%04x\n",A,X.PC);
|
|
switch(A)
|
|
{
|
|
case 0x5000:return(tekker);
|
|
case 0x5800:return(mul[0]*mul[1]);
|
|
case 0x5801:return((mul[0]*mul[1])>>8);
|
|
case 0x5803:return(regie);
|
|
default:break;
|
|
}
|
|
return(X.DB);
|
|
}
|
|
|
|
static void mira(void)
|
|
{
|
|
if(tkcom[0]&0x20 && is209)
|
|
{
|
|
int x;
|
|
if(tkcom[0] & 0x40) // Name tables are ROM-only
|
|
{
|
|
for(x=0;x<4;x++)
|
|
setntamem(CHRptr[0]+(((names[x])&CHRmask1[0])<<10), 0, x);
|
|
}
|
|
else // Name tables can be RAM or ROM.
|
|
{
|
|
for(x=0;x<4;x++)
|
|
{
|
|
if((tkcom[2]&0x80) == (names[x]&0x80)) // RAM selected.
|
|
setntamem(NTARAM + ((names[x]&0x1)<<10),1,x);
|
|
else
|
|
setntamem(CHRptr[0]+(((names[x])&CHRmask1[0])<<10), 0, x);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(tkcom[1]&3){
|
|
case 0:setmirror(MI_V);break;
|
|
case 1:setmirror(MI_H);break;
|
|
case 2:setmirror(MI_0);break;
|
|
case 3:setmirror(MI_1);break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void tekprom(void)
|
|
{
|
|
switch(tkcom[0]&3)
|
|
{
|
|
case 1: // 16 KB
|
|
setprg16(0x8000,prgb[0]);
|
|
setprg16(0xC000,prgb[2]);
|
|
break;
|
|
case 2: //2 = 8 KB ??
|
|
if(tkcom[0]&0x4)
|
|
{
|
|
setprg8(0x8000,prgb[0]);
|
|
setprg8(0xa000,prgb[1]);
|
|
setprg8(0xc000,prgb[2]);
|
|
setprg8(0xe000,prgb[3]);
|
|
}
|
|
else
|
|
{
|
|
if(tkcom[0]&0x80)
|
|
setprg8(0x6000,prgb[3]);
|
|
setprg8(0x8000,prgb[0]);
|
|
setprg8(0xa000,prgb[1]);
|
|
setprg8(0xc000,prgb[2]);
|
|
setprg8(0xe000,~0);
|
|
}
|
|
break;
|
|
case 0:
|
|
case 3:
|
|
setprg8(0x8000,prgb[0]);
|
|
setprg8(0xa000,prgb[1]);
|
|
setprg8(0xc000,prgb[2]);
|
|
setprg8(0xe000,prgb[3]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void tekvrom(void)
|
|
{
|
|
int x;
|
|
|
|
switch(tkcom[0]&0x18)
|
|
{
|
|
case 0x00: // 8KB
|
|
setchr8(chrlow[0]|(chrhigh[0]<<8));
|
|
break;
|
|
case 0x08: // 4KB
|
|
for(x=0;x<8;x+=4)
|
|
setchr4(x<<10,chrlow[x]|(chrhigh[x]<<8));
|
|
break;
|
|
case 0x10: // 2KB
|
|
for(x=0;x<8;x+=2)
|
|
setchr2(x<<10,chrlow[x]|(chrhigh[x]<<8));
|
|
break;
|
|
case 0x18: // 1KB
|
|
for(x=0;x<8;x++)
|
|
setchr1(x<<10,(chrlow[x]|(chrhigh[x]<<8)));
|
|
break;
|
|
}
|
|
}
|
|
|
|
static DECLFW(Mapper90_write)
|
|
{
|
|
//printf("$%04x:$%02x\n",A,V);
|
|
|
|
if(A==0x5800) mul[0]=V;
|
|
else if(A==0x5801) mul[1]=V;
|
|
else if(A==0x5803) regie=V;
|
|
|
|
|
|
//if(A>=0xc000 && A<=0xc007)
|
|
// FCEU_printf("$%04x:$%02x $%04x, %d, %d\n",A,V,X.PC,scanline,timestamp);
|
|
|
|
A&=0xF007;
|
|
if(A>=0x8000 && A<=0x8003)
|
|
{
|
|
prgb[A&3]=V;
|
|
tekprom();
|
|
}
|
|
else if(A>=0x9000 && A<=0x9007)
|
|
{
|
|
chrlow[A&7]=V;
|
|
tekvrom();
|
|
}
|
|
else if(A>=0xa000 && A<=0xa007)
|
|
{
|
|
chrhigh[A&7]=V;
|
|
tekvrom();
|
|
}
|
|
else if(A>=0xb000 && A<=0xb007)
|
|
{
|
|
//printf("$%04x:$%02x\n",A,V);
|
|
if(A&4)
|
|
{
|
|
names[A&3]&=0x00FF;
|
|
names[A&3]|=V<<8;
|
|
}
|
|
else
|
|
{
|
|
names[A&3]&=0xFF00;
|
|
names[A&3]|=V;
|
|
}
|
|
mira();
|
|
}
|
|
else if(A>=0xd000 && A<=0xdfff)
|
|
{
|
|
tkcom[A&3]=V;
|
|
tekprom();
|
|
tekvrom();
|
|
mira();
|
|
}
|
|
else switch(A)
|
|
{
|
|
case 0xc000: IRQa=V&1;if(!(V&1)) X6502_IRQEnd(FCEU_IQEXT);break;
|
|
case 0xc002: IRQa=0;X6502_IRQEnd(FCEU_IQEXT);break;
|
|
case 0xc003: IRQa=1;break;
|
|
|
|
case 0xc001: IRQMode=V;break;
|
|
case 0xc004: IRQPre=V^IRQXOR;break;
|
|
case 0xc005: IRQCount=V^IRQXOR;break;
|
|
case 0xc006: IRQXOR=V;break;
|
|
case 0xc007: IRQPreSize=V;break;
|
|
}
|
|
|
|
}
|
|
|
|
static void CCL(void)
|
|
{
|
|
if((IRQMode>>6) == 1) // Count Up
|
|
{
|
|
IRQCount++;
|
|
if((IRQCount == 0) && IRQa)
|
|
X6502_IRQBegin(FCEU_IQEXT);
|
|
}
|
|
else if((IRQMode>>6) == 2) // Count down
|
|
{
|
|
IRQCount--;
|
|
if((IRQCount == 0xFF) && IRQa)
|
|
X6502_IRQBegin(FCEU_IQEXT);
|
|
}
|
|
}
|
|
|
|
static void ClockCounter(void)
|
|
{
|
|
uint8 premask;
|
|
|
|
if(IRQMode & 0x4) premask = 0x7;
|
|
else premask = 0xFF;
|
|
|
|
if((IRQMode>>6) == 1) // Count up
|
|
{
|
|
IRQPre++;
|
|
|
|
if((IRQPre & premask) == 0)
|
|
CCL();
|
|
}
|
|
else if((IRQMode>>6) == 2) // Count down
|
|
{
|
|
IRQPre--;
|
|
//printf("%d\n",IRQPre);
|
|
if((IRQPre & premask) == premask)
|
|
CCL();
|
|
}
|
|
}
|
|
|
|
static void SLWrap(void)
|
|
{
|
|
int x;
|
|
for(x=0;x<8;x++) ClockCounter(); // 8 PPU A10 0->1 transitions per scanline(usually)
|
|
}
|
|
/*
|
|
static uint32 lasta;
|
|
static void FP_FASTAPASS(1) YARGH(uint32 A)
|
|
{
|
|
if((A&0x1000) && !(lasta & 0x1000))
|
|
ClockCounter();
|
|
|
|
lasta = A;
|
|
}
|
|
*/
|
|
|
|
static void togglie()
|
|
{
|
|
tekker^=0xFF;
|
|
}
|
|
|
|
static void m90rest(int version)
|
|
{
|
|
mira();
|
|
}
|
|
|
|
static void M90Power(void)
|
|
{
|
|
SetWriteHandler(0x5000,0xffff,Mapper90_write);
|
|
SetReadHandler(0x5000,0x5fff,tekread);
|
|
|
|
SetReadHandler(0x6000,0xffff,CartBR);
|
|
|
|
mul[0]=mul[1]=regie=0xFF;
|
|
|
|
tkcom[0]=tkcom[1]=tkcom[2]=tkcom[3]=0xFF;
|
|
|
|
memset(prgb,0xff,sizeof(prgb));
|
|
memset(chrlow,0xff,sizeof(chrlow));
|
|
memset(chrhigh,0xff,sizeof(chrhigh));
|
|
memset(names,0x00,sizeof(names));
|
|
|
|
tekker=0;
|
|
|
|
prgb[0]=0xFF;
|
|
prgb[1]=0xFF;
|
|
prgb[2]=0xFF;
|
|
prgb[3]=0xFF;
|
|
tekprom();
|
|
tekvrom();
|
|
}
|
|
|
|
void Mapper90_Init(CartInfo *info)
|
|
{
|
|
is209=0;
|
|
info->Reset=togglie;
|
|
info->Power=M90Power;
|
|
//PPU_hook = YARGH;
|
|
GameHBIRQHook2 = SLWrap;
|
|
GameStateRestore=m90rest;
|
|
AddExState(Tek_StateRegs, ~0, 0, 0);
|
|
}
|
|
|
|
void Mapper209_Init(CartInfo *info)
|
|
{
|
|
is209=1;
|
|
info->Reset=togglie;
|
|
info->Power=M90Power;
|
|
//PPU_hook = YARGH;
|
|
GameHBIRQHook2 = SLWrap;
|
|
GameStateRestore=m90rest;
|
|
AddExState(Tek_StateRegs, ~0, 0, 0);
|
|
}
|
|
|