new unif "KONAMI-QTAI" board (VRC-V code name) along with PPU hack for it (16-bit extra NT like in MMC5) for both New and Old PPUs. very hacky for new ppu, sorry.

This commit is contained in:
g0me3 2019-06-30 14:00:59 +03:00
parent 97c9cb0068
commit 7c9dca50bd
8 changed files with 1046 additions and 1038 deletions

View File

@ -1,90 +1,90 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2005 CaH4e3
*
* 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
*
* NTDEC, ASDER games
*
*/
#include "mapinc.h"
static uint8 reg[8];
static uint8 mirror, cmd, bank;
static uint8 *WRAM = NULL;
static SFORMAT StateRegs[] =
{
{ &cmd, 1, "CMD" },
{ &mirror, 1, "MIRR" },
{ &bank, 1, "BANK" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setmirror(mirror ^ 1);
setprg8(0x8000, reg[0]);
setprg8(0xA000, reg[1]);
setchr2(0x0000, (reg[2] >> 1));
setchr2(0x0800, (reg[3] >> 1));
setchr1(0x1000, ((bank & 0x10) << 4) | reg[4]);
setchr1(0x1400, ((bank & 0x20) << 3) | reg[5]);
setchr1(0x1800, ((bank & 0x40) << 2) | reg[6]);
setchr1(0x1C00, ((bank & 0x80) << 1) | reg[7]);
}
static DECLFW(M112Write) {
switch (A) {
case 0xe000: mirror = V & 1; Sync();; break;
case 0x8000: cmd = V & 7; break;
case 0xa000: reg[cmd] = V; Sync(); break;
case 0xc000: bank = V; Sync(); break;
}
}
static void M112Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
static void M112Power(void) {
bank = 0;
setprg16(0xC000, ~0);
setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M112Write);
SetWriteHandler(0x4020, 0x5FFF, M112Write);
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2005 CaH4e3
*
* 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
*
* NTDEC, ASDER games
*
*/
#include "mapinc.h"
static uint8 reg[8];
static uint8 mirror, cmd, bank;
static uint8 *WRAM = NULL;
static SFORMAT StateRegs[] =
{
{ &cmd, 1, "CMD" },
{ &mirror, 1, "MIRR" },
{ &bank, 1, "BANK" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setmirror(mirror ^ 1);
setprg8(0x8000, reg[0]);
setprg8(0xA000, reg[1]);
setchr2(0x0000, (reg[2] >> 1));
setchr2(0x0800, (reg[3] >> 1));
setchr1(0x1000, ((bank & 0x10) << 4) | reg[4]);
setchr1(0x1400, ((bank & 0x20) << 3) | reg[5]);
setchr1(0x1800, ((bank & 0x40) << 2) | reg[6]);
setchr1(0x1C00, ((bank & 0x80) << 1) | reg[7]);
}
static DECLFW(M112Write) {
switch (A) {
case 0xe000: mirror = V & 1; Sync();; break;
case 0x8000: cmd = V & 7; break;
case 0xa000: reg[cmd] = V; Sync(); break;
case 0xc000: bank = V; Sync(); break;
}
}
static void M112Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
static void M112Power(void) {
bank = 0;
setprg16(0xC000, ~0);
setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M112Write);
SetWriteHandler(0x4020, 0x5FFF, M112Write);
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(8, 0x6000, WRAM);
}
static void StateRestore(int version) {
Sync();
}
void Mapper112_Init(CartInfo *info) {
info->Power = M112Power;
info->Close = M112Close;
GameStateRestore = StateRestore;
WRAM = (uint8*)FCEU_gmalloc(8192);
SetupCartPRGMapping(0x10, WRAM, 8192, 1);
AddExState(WRAM, 8192, 0, "WRAM");
AddExState(&StateRegs, ~0, 0, 0);
}
}
static void StateRestore(int version) {
Sync();
}
void Mapper112_Init(CartInfo *info) {
info->Power = M112Power;
info->Close = M112Close;
GameStateRestore = StateRestore;
WRAM = (uint8*)FCEU_gmalloc(8192);
SetupCartPRGMapping(0x10, WRAM, 8192, 1);
AddExState(WRAM, 8192, 0, "WRAM");
AddExState(&StateRegs, ~0, 0, 0);
}

View File

@ -1,232 +1,232 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel 2006 CaH4e3
*
* 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
*
* It seems that 162/163/164 mappers are the same mapper with just different
* mapper modes enabled or disabled in software or hardware, need more nanjing
* carts
*/
#include "mapinc.h"
static uint8 laststrobe, trigger;
static uint8 reg[8];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static writefunc pcmwrite;
static void (*WSync)(void);
static SFORMAT StateRegs[] =
{
{ &laststrobe, 1, "STB" },
{ &trigger, 1, "TRG" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setprg8r(0x10, 0x6000, 0);
setprg32(0x8000, (reg[0] << 4) | (reg[1] & 0xF));
setchr8(0);
}
static void StateRestore(int version) {
WSync();
}
static DECLFR(ReadLow) {
switch (A & 0x7700) {
case 0x5100: return reg[2] | reg[0] | reg[1] | reg[3] ^ 0xff; break;
case 0x5500:
if (trigger)
return reg[2] | reg[1]; // Lei Dian Huang Bi Ka Qiu Chuan Shuo (NJ046) may broke other games
else
return 0;
}
return 4;
}
static void M163HB(void) {
if (reg[1] & 0x80) {
if (scanline == 239) {
setchr4(0x0000, 0);
setchr4(0x1000, 0);
} else if (scanline == 127) {
setchr4(0x0000, 1);
setchr4(0x1000, 1);
}
/*
if(scanline>=127) // Hu Lu Jin Gang (NJ039) (Ch) [!] don't like it
{
setchr4(0x0000,1);
setchr4(0x1000,1);
}
else
{
setchr4(0x0000,0);
setchr4(0x1000,0);
}
*/
}
}
static DECLFW(Write) {
switch (A & 0x7300) {
case 0x5100: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); break;
case 0x5300: reg[2] = V; break;
case 0x5200: reg[3] = V; WSync(); break;
}
}
static void Power(void) {
memset(reg, 0, 8);
reg[1] = 0xFF;
SetWriteHandler(0x5000, 0x5FFF, Write);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel 2006 CaH4e3
*
* 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
*
* It seems that 162/163/164 mappers are the same mapper with just different
* mapper modes enabled or disabled in software or hardware, need more nanjing
* carts
*/
#include "mapinc.h"
static uint8 laststrobe, trigger;
static uint8 reg[8];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static writefunc pcmwrite;
static void (*WSync)(void);
static SFORMAT StateRegs[] =
{
{ &laststrobe, 1, "STB" },
{ &trigger, 1, "TRG" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setprg8r(0x10, 0x6000, 0);
setprg32(0x8000, (reg[0] << 4) | (reg[1] & 0xF));
setchr8(0);
}
static void StateRestore(int version) {
WSync();
}
static DECLFR(ReadLow) {
switch (A & 0x7700) {
case 0x5100: return reg[2] | reg[0] | reg[1] | reg[3] ^ 0xff; break;
case 0x5500:
if (trigger)
return reg[2] | reg[1]; // Lei Dian Huang Bi Ka Qiu Chuan Shuo (NJ046) may broke other games
else
return 0;
}
return 4;
}
static void M163HB(void) {
if (reg[1] & 0x80) {
if (scanline == 239) {
setchr4(0x0000, 0);
setchr4(0x1000, 0);
} else if (scanline == 127) {
setchr4(0x0000, 1);
setchr4(0x1000, 1);
}
/*
if(scanline>=127) // Hu Lu Jin Gang (NJ039) (Ch) [!] don't like it
{
setchr4(0x0000,1);
setchr4(0x1000,1);
}
else
{
setchr4(0x0000,0);
setchr4(0x1000,0);
}
*/
}
}
static DECLFW(Write) {
switch (A & 0x7300) {
case 0x5100: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); break;
case 0x5300: reg[2] = V; break;
case 0x5200: reg[3] = V; WSync(); break;
}
}
static void Power(void) {
memset(reg, 0, 8);
reg[1] = 0xFF;
SetWriteHandler(0x5000, 0x5FFF, Write);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
WSync();
}
static void Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
void Mapper164_Init(CartInfo *info) {
info->Power = Power;
info->Close = Close;
WSync = Sync;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static DECLFW(Write2) {
if (A == 0x5101) {
if (laststrobe && !V) {
trigger ^= 1;
}
laststrobe = V;
} else if (A == 0x5100 && V == 6) //damn thoose protected games
setprg32(0x8000, 3);
else
switch (A & 0x7300) {
case 0x5200: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); if (!(reg[1] & 0x80) && (scanline < 128)) setchr8(0); /* setchr8(0); */ break;
case 0x5300: reg[2] = V; break;
case 0x5100: reg[3] = V; WSync(); break;
}
}
static void Power2(void) {
memset(reg, 0, 8);
laststrobe = 1;
pcmwrite = GetWriteHandler(0x4011);
SetReadHandler(0x5000, 0x5FFF, ReadLow);
SetWriteHandler(0x5000, 0x5FFF, Write2);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
WSync();
}
static void Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
void Mapper164_Init(CartInfo *info) {
info->Power = Power;
info->Close = Close;
WSync = Sync;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static DECLFW(Write2) {
if (A == 0x5101) {
if (laststrobe && !V) {
trigger ^= 1;
}
laststrobe = V;
} else if (A == 0x5100 && V == 6) //damn thoose protected games
setprg32(0x8000, 3);
else
switch (A & 0x7300) {
case 0x5200: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); if (!(reg[1] & 0x80) && (scanline < 128)) setchr8(0); /* setchr8(0); */ break;
case 0x5300: reg[2] = V; break;
case 0x5100: reg[3] = V; WSync(); break;
}
}
static void Power2(void) {
memset(reg, 0, 8);
laststrobe = 1;
pcmwrite = GetWriteHandler(0x4011);
SetReadHandler(0x5000, 0x5FFF, ReadLow);
SetWriteHandler(0x5000, 0x5FFF, Write2);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
WSync();
}
void Mapper163_Init(CartInfo *info) {
info->Power = Power2;
info->Close = Close;
WSync = Sync;
GameHBIRQHook = M163HB;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static void Sync3(void) {
setchr8(0);
setprg8r(0x10, 0x6000, 0);
switch (reg[3] & 7) {
case 0:
case 2: setprg32(0x8000, (reg[0] & 0xc) | (reg[1] & 2) | ((reg[2] & 0xf) << 4)); break;
case 1:
case 3: setprg32(0x8000, (reg[0] & 0xc) | (reg[2] & 0xf) << 4); break;
case 4:
case 6: setprg32(0x8000, (reg[0] & 0xe) | ((reg[1] >> 1) & 1) | ((reg[2] & 0xf) << 4)); break;
case 5:
case 7: setprg32(0x8000, (reg[0] & 0xf) | ((reg[2] & 0xf) << 4)); break;
}
}
static DECLFW(Write3) {
// FCEU_printf("bs %04x %02x\n",A,V);
reg[(A >> 8) & 3] = V;
WSync();
}
static void Power3(void) {
reg[0] = 3;
reg[1] = 0;
reg[2] = 0;
reg[3] = 7;
SetWriteHandler(0x5000, 0x5FFF, Write3);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
WSync();
}
void Mapper163_Init(CartInfo *info) {
info->Power = Power2;
info->Close = Close;
WSync = Sync;
GameHBIRQHook = M163HB;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static void Sync3(void) {
setchr8(0);
setprg8r(0x10, 0x6000, 0);
switch (reg[3] & 7) {
case 0:
case 2: setprg32(0x8000, (reg[0] & 0xc) | (reg[1] & 2) | ((reg[2] & 0xf) << 4)); break;
case 1:
case 3: setprg32(0x8000, (reg[0] & 0xc) | (reg[2] & 0xf) << 4); break;
case 4:
case 6: setprg32(0x8000, (reg[0] & 0xe) | ((reg[1] >> 1) & 1) | ((reg[2] & 0xf) << 4)); break;
case 5:
case 7: setprg32(0x8000, (reg[0] & 0xf) | ((reg[2] & 0xf) << 4)); break;
}
}
static DECLFW(Write3) {
// FCEU_printf("bs %04x %02x\n",A,V);
reg[(A >> 8) & 3] = V;
WSync();
}
static void Power3(void) {
reg[0] = 3;
reg[1] = 0;
reg[2] = 0;
reg[3] = 7;
SetWriteHandler(0x5000, 0x5FFF, Write3);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
WSync();
}
void UNLFS304_Init(CartInfo *info) {
info->Power = Power3;
info->Close = Close;
WSync = Sync3;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
WSync();
}
void UNLFS304_Init(CartInfo *info) {
info->Power = Power3;
info->Close = Close;
WSync = Sync3;
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,9 @@
* 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
*
* PEC-586 FC based computer series by DUNDA
*
*/
#include "mapinc.h"

View File

@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* VRC-5 (CAI Shogakko no Sansu)
* VRC-V (CAI Shogakko no Sansu)
*
*/
@ -25,12 +25,16 @@
#define CAI_DEBUG
static writefunc old2006wrap;
static writefunc old2007wrap;
static uint8 QTAINTRAM[2048];
static uint16 qtaintramofs;
// main tiles RAM is 8K in size, but unless other non-CHR ROM type carts,
// this one accesses the $0000 and $1000 pages based on extra NT RAM on board
// which is similar to MMC5 but much simpler because there are no additional
// bankings here.
// extra NT RAM handling is in PPU code now.
static uint16 CHRSIZE = 8192;
// there are two separate WRAMs 8K each, on main system cartridge (not battery
// backed), and one on the daughter cart (with battery). both are accessed
// via the same registers with additional selector flags.
static uint16 WRAMSIZE = 8192 + 8192;
static uint8 *CHRRAM = NULL;
static uint8 *WRAM = NULL;
@ -38,71 +42,80 @@ static uint8 *WRAM = NULL;
static uint8 IRQa, K4IRQ;
static uint32 IRQLatch, IRQCount;
// some kind of 16-bit text encoding (actually 15-bit) used in game resources
// may be converted by the hardware into the tile indexes for internal CHR ROM
// not sure whey they made it hardware, because most of calculations are just
// bit shifting. the main purpose of this table is to calculate actual CHR ROM
// bank for every character. there is a some kind of regularity, so this table
// may be calculated in software easily.
// table read out from hardware registers as is
static uint8 conv_tbl[128][4] = {
{ 0x40, 0x40, 0x40, 0x40 },
{ 0x41, 0x41, 0x41, 0x41 },
{ 0x42, 0x42, 0x42, 0x42 },
{ 0x43, 0x43, 0x43, 0x43 },
{ 0x44, 0x44, 0x44, 0x44 },
{ 0x45, 0x45, 0x45, 0x45 },
{ 0x46, 0x46, 0x46, 0x46 },
{ 0x47, 0x47, 0x47, 0x47 },
{ 0x40, 0x40, 0x40, 0x40 },
{ 0x41, 0x41, 0x41, 0x41 },
{ 0x42, 0x42, 0x42, 0x42 },
{ 0x43, 0x43, 0x43, 0x43 },
{ 0x44, 0x44, 0x44, 0x44 },
{ 0x45, 0x45, 0x45, 0x45 },
{ 0x46, 0x46, 0x46, 0x46 },
{ 0x47, 0x47, 0x47, 0x47 },
{ 0x40, 0x40, 0x48, 0x44 },
{ 0x41, 0x41, 0x49, 0x45 },
{ 0x42, 0x42, 0x4A, 0x46 },
{ 0x43, 0x43, 0x4B, 0x47 },
{ 0x44, 0x40, 0x48, 0x44 },
{ 0x45, 0x41, 0x49, 0x45 },
{ 0x46, 0x42, 0x4A, 0x46 },
{ 0x47, 0x43, 0x4B, 0x47 },
{ 0x40, 0x50, 0x58, 0x60 },
{ 0x41, 0x51, 0x59, 0x61 },
{ 0x42, 0x52, 0x5A, 0x62 },
{ 0x43, 0x53, 0x5B, 0x63 },
{ 0x44, 0x54, 0x5C, 0x64 },
{ 0x45, 0x55, 0x5D, 0x65 },
{ 0x46, 0x56, 0x5E, 0x66 },
{ 0x47, 0x57, 0x5F, 0x67 },
{ 0x40, 0x68, 0x70, 0x78 },
{ 0x41, 0x69, 0x71, 0x79 },
{ 0x42, 0x6A, 0x72, 0x7A },
{ 0x43, 0x6B, 0x73, 0x7B },
{ 0x44, 0x6C, 0x74, 0x7C },
{ 0x45, 0x6D, 0x75, 0x7D },
{ 0x46, 0x6E, 0x76, 0x7E },
{ 0x47, 0x6F, 0x77, 0x7F },
{ 0x40, 0x40, 0x48, 0x50 },
{ 0x41, 0x41, 0x49, 0x51 },
{ 0x42, 0x42, 0x4A, 0x52 },
{ 0x43, 0x43, 0x4B, 0x53 },
{ 0x44, 0x44, 0x4C, 0x54 },
{ 0x45, 0x45, 0x4D, 0x55 },
{ 0x46, 0x46, 0x4E, 0x56 },
{ 0x47, 0x47, 0x4F, 0x57 },
{ 0x40, 0x58, 0x60, 0x68 },
{ 0x41, 0x59, 0x61, 0x69 },
{ 0x42, 0x5A, 0x62, 0x6A },
{ 0x43, 0x5B, 0x63, 0x6B },
{ 0x44, 0x5C, 0x64, 0x6C },
{ 0x45, 0x5D, 0x65, 0x6D },
{ 0x46, 0x5E, 0x66, 0x6E },
{ 0x47, 0x5F, 0x67, 0x6F },
{ 0x40, 0x70, 0x78, 0x74 },
{ 0x41, 0x71, 0x79, 0x75 },
{ 0x42, 0x72, 0x7A, 0x76 },
{ 0x43, 0x73, 0x7B, 0x77 },
{ 0x44, 0x74, 0x7C, 0x74 },
{ 0x45, 0x75, 0x7D, 0x75 },
{ 0x46, 0x76, 0x7E, 0x76 },
{ 0x47, 0x77, 0x7F, 0x77 },
{ 0x40, 0x40, 0x40, 0x40 }, // 00 | A - 40 41 42 43 44 45 46 47
{ 0x41, 0x41, 0x41, 0x41 }, // 02 | B - 48 49 4A 4B 4C 4D 4E 4F
{ 0x42, 0x42, 0x42, 0x42 }, // 04 | C - 50 51 52 53 54 55 56 57
{ 0x43, 0x43, 0x43, 0x43 }, // 06 | D - 58 59 5A 5B 5C 5D 5E 5F
{ 0x44, 0x44, 0x44, 0x44 }, // 08 | E - 60 61 62 63 64 65 66 67
{ 0x45, 0x45, 0x45, 0x45 }, // 0A | F - 68 69 6A 6B 6C 6D 6E 6F
{ 0x46, 0x46, 0x46, 0x46 }, // 0C | G - 70 71 72 73 74 75 76 77
{ 0x47, 0x47, 0x47, 0x47 }, // 0E | H - 78 79 7A 7B 7C 7D 7E 7F
{ 0x40, 0x40, 0x40, 0x40 }, // 10 |
{ 0x41, 0x41, 0x41, 0x41 }, // 12 +----------------------------
{ 0x42, 0x42, 0x42, 0x42 }, // 14 | A A A A
{ 0x43, 0x43, 0x43, 0x43 }, // 16 | A A A A
{ 0x44, 0x44, 0x44, 0x44 }, // 18 | A A' B' A"
{ 0x45, 0x45, 0x45, 0x45 }, // 1A | A C D E
{ 0x46, 0x46, 0x46, 0x46 }, // 1C | A F G H
{ 0x47, 0x47, 0x47, 0x47 }, // 1E | A A B C
{ 0x40, 0x40, 0x48, 0x44 }, // 20 | A D E F
{ 0x41, 0x41, 0x49, 0x45 }, // 22 | A G H G"
{ 0x42, 0x42, 0x4A, 0x46 }, // 24 +----------------------------
{ 0x43, 0x43, 0x4B, 0x47 }, // 26 | A' - 40 41 42 43 40 41 42 43
{ 0x44, 0x40, 0x48, 0x44 }, // 28 | A" - 44 45 46 47 44 45 46 47
{ 0x45, 0x41, 0x49, 0x45 }, // 2A | B' - 48 49 4A 4B 48 49 4A 4B
{ 0x46, 0x42, 0x4A, 0x46 }, // 2C | G" - 74 75 76 77 74 75 76 77
{ 0x47, 0x43, 0x4B, 0x47 }, // 2E
{ 0x40, 0x50, 0x58, 0x60 }, // 30
{ 0x41, 0x51, 0x59, 0x61 }, // 32
{ 0x42, 0x52, 0x5A, 0x62 }, // 34
{ 0x43, 0x53, 0x5B, 0x63 }, // 36
{ 0x44, 0x54, 0x5C, 0x64 }, // 38
{ 0x45, 0x55, 0x5D, 0x65 }, // 3A
{ 0x46, 0x56, 0x5E, 0x66 }, // 3C
{ 0x47, 0x57, 0x5F, 0x67 }, // 3E
{ 0x40, 0x68, 0x70, 0x78 }, // 40
{ 0x41, 0x69, 0x71, 0x79 }, // 42
{ 0x42, 0x6A, 0x72, 0x7A }, // 44
{ 0x43, 0x6B, 0x73, 0x7B }, // 46
{ 0x44, 0x6C, 0x74, 0x7C }, // 48
{ 0x45, 0x6D, 0x75, 0x7D }, // 4A
{ 0x46, 0x6E, 0x76, 0x7E }, // 4C
{ 0x47, 0x6F, 0x77, 0x7F }, // 4E
{ 0x40, 0x40, 0x48, 0x50 }, // 50
{ 0x41, 0x41, 0x49, 0x51 }, // 52
{ 0x42, 0x42, 0x4A, 0x52 }, // 54
{ 0x43, 0x43, 0x4B, 0x53 }, // 56
{ 0x44, 0x44, 0x4C, 0x54 }, // 58
{ 0x45, 0x45, 0x4D, 0x55 }, // 5A
{ 0x46, 0x46, 0x4E, 0x56 }, // 5C
{ 0x47, 0x47, 0x4F, 0x57 }, // 5E
{ 0x40, 0x58, 0x60, 0x68 }, // 60
{ 0x41, 0x59, 0x61, 0x69 }, // 62
{ 0x42, 0x5A, 0x62, 0x6A }, // 64
{ 0x43, 0x5B, 0x63, 0x6B }, // 66
{ 0x44, 0x5C, 0x64, 0x6C }, // 68
{ 0x45, 0x5D, 0x65, 0x6D }, // 6A
{ 0x46, 0x5E, 0x66, 0x6E }, // 6C
{ 0x47, 0x5F, 0x67, 0x6F }, // 6E
{ 0x40, 0x70, 0x78, 0x74 }, // 70
{ 0x41, 0x71, 0x79, 0x75 }, // 72
{ 0x42, 0x72, 0x7A, 0x76 }, // 74
{ 0x43, 0x73, 0x7B, 0x77 }, // 76
{ 0x44, 0x74, 0x7C, 0x74 }, // 78
{ 0x45, 0x75, 0x7D, 0x75 }, // 7A
{ 0x46, 0x76, 0x7E, 0x76 }, // 7C
{ 0x47, 0x77, 0x7F, 0x77 }, // 7E
};
static uint8 regs[16];
@ -118,88 +131,54 @@ static SFORMAT StateRegs[] =
static void chrSync(void) {
setchr4r(0x10, 0x0000, regs[5] & 1);
// one more hack to make visible some screens in common. will be replaced with proper code later
setchr4r(0x10, 0x1000, QTAINTRAM[0] & 1);
// setchr4r(0x10, 0x1000, 1);
// 30.06.19 CaH4e3 there is much more complicated behaviour with second banking register, you may actually
// view the content of the internal character CHR rom via this window, but it is useless because hardware
// does not use this area to access the internal ROM. not sure why they did this, but I see no need to
// emulate this behaviour carefully, unless I find something that I missed...
setchr4r(0x10, 0x1000, 1);
}
static void Sync(void) {
chrSync();
setprg4r(0x10, 0x6000, (regs[0] & 1) | (regs[0] >> 2));
setprg4r(0x10, 0x7000, (regs[1] & 1) | (regs[1] >> 2));
#ifdef CAI_DEBUG
setprg8(0x8000, regs[2]);
setprg8(0xA000, regs[3]);
setprg8(0xC000, regs[4]);
setprg8(0xE000, ~0);
#else
setprg8r((regs[2] >> 6) & 1, 0x8000, (regs[2] & 0x3F));
setprg8r((regs[3] >> 6) & 1, 0xA000, (regs[3] & 0x3F));
setprg8r((regs[4] >> 6) & 1, 0xC000, (regs[4] & 0x3F));
setprg8r(1, 0xE000, ~0);
#endif
setprg4r(0x10, 0x6000, (regs[0] & 1) | (regs[0] >> 2)); // two 4K banks are identical, either internal or excernal
setprg4r(0x10, 0x7000, (regs[1] & 1) | (regs[1] >> 2)); // SRAMs may be mapped in any bank independently
if (PRGsize[0] == 1024 * 1024) {// hacky hacky way to run it as iNES rom for debugging purposes
setprg8(0x8000, regs[2]);
setprg8(0xA000, regs[3]);
setprg8(0xC000, regs[4]);
setprg8(0xE000, ~0);
} else {
setprg8r((regs[2] >> 6) & 1, 0x8000, (regs[2] & 0x3F));
setprg8r((regs[3] >> 6) & 1, 0xA000, (regs[3] & 0x3F));
setprg8r((regs[4] >> 6) & 1, 0xC000, (regs[4] & 0x3F));
setprg8r(1, 0xE000, ~0); // always sees the last bank of the external cart, so can't be booted without it.
}
setmirror(((regs[0xA]&2)>>1)^1);
}
static DECLFW(QTAiWrite) {
regs[(A & 0x0F00) >> 8] = V;
regs[(A & 0x0F00) >> 8] = V; // IRQ pretty the same as in other VRC mappers by Konami
switch (A) {
case 0xd600: {
IRQLatch &= 0xFF00;
IRQLatch |= V;
#ifdef CAI_DEBUG
FCEU_printf("irq latch lo=%02x\n", V);
#endif
break;
}
case 0xd700: {
IRQLatch &= 0x00FF;
IRQLatch |= V << 8;
#ifdef CAI_DEBUG
FCEU_printf("irq latch hi=%02x\n", V);
#endif
break;
}
case 0xd900: {
IRQCount = IRQLatch;
IRQa = V & 2;
K4IRQ = V & 1;
X6502_IRQEnd(FCEU_IQEXT);
#ifdef CAI_DEBUG
FCEU_printf("irq reload\n", V);
#endif
break;
}
case 0xd800: {
IRQa = K4IRQ;
X6502_IRQEnd(FCEU_IQEXT);
#ifdef CAI_DEBUG
FCEU_printf("irq stop\n", V);
#endif
break;
}
default:
#ifdef CAI_DEBUG
FCEU_printf("write %04x:%04x %d, %d\n", A, V, scanline, timestamp);
#endif
case 0xd600: IRQLatch &= 0xFF00; IRQLatch |= V; break;
case 0xd700: IRQLatch &= 0x00FF; IRQLatch |= V << 8; break;
case 0xd900: IRQCount = IRQLatch; IRQa = V & 2; K4IRQ = V & 1; X6502_IRQEnd(FCEU_IQEXT); break;
case 0xd800: IRQa = K4IRQ; X6502_IRQEnd(FCEU_IQEXT); break;
case 0xda00: qtaintramreg = regs[0xA] & 3; break; // register shadow to share it with ppu
}
Sync();
}
#ifdef CAI_DEBUG
static DECLFR(DebugExtNT) {
return QTAINTRAM[A & 0x07FF];
}
#endif
static DECLFR(QTAiRead) {
// OH = conv_tbl[DD00 >> 1][DC00 >> 6]
// OL = ((DC00 & 0x3F) << 2) + DB00
if (A == 0xDD00)
return conv_tbl[regs[0xD] >> 1][regs[0xC] >> 6];
else if (A == 0xDC00)
return ((regs[0xC] & 0x3F) << 2) + regs[0xB];
else
uint8 res1 = conv_tbl[regs[0xD] >> 1][(regs[0xC] >> 5) & 3];
uint8 res2 = ((regs[0xD] & 1) << 7) | ((regs[0xC] & 0x1F) << 2) | (regs[0xB] & 3);
if (A == 0xDD00) {
return res1;
} else if (A == 0xDC00) {
#ifdef CAI_DEBUG
FCEU_printf("%02x:%02x+%d -> %02x:%02x\n", regs[0xD], regs[0xC], regs[0xB], res1, res2);
#endif
return res2;
} else
return 0;
}
@ -213,38 +192,7 @@ static void VRC5IRQ(int a) {
}
}
// debug hack. mapper does not track ppu address himseld, instead the regular ppu offset is used
// these handlers must be moved in ppu code in order to be emulated properly.
//
static DECLFW(QTAi2006Wrap) {
if (regs[0xA] & 1)
qtaintramofs = (qtaintramofs << 8) | V;
else
old2006wrap(0x2006, V);
}
static DECLFW(QTAi2007Wrap) {
if (regs[0xA] & 1) {
QTAINTRAM[qtaintramofs & 0x07FF] = V;
qtaintramofs++;
} else
old2007wrap(0x2007, V);
}
static void QTAiPower(void) {
QTAIHack = 1;
qtaintramofs = 0;
old2006wrap = GetWriteHandler(0x2006);
old2007wrap = GetWriteHandler(0x2007);
SetWriteHandler(0x2006, 0x2006, QTAi2006Wrap);
SetWriteHandler(0x2007, 0x2007, QTAi2007Wrap);
#ifdef CAI_DEBUG
SetReadHandler(0x5000, 0x5FFF, DebugExtNT);
#endif
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
SetWriteHandler(0x8000, 0xFFFF, QTAiWrite);
@ -268,6 +216,8 @@ static void StateRestore(int version) {
}
void QTAi_Init(CartInfo *info) {
QTAIHack = 1;
info->Power = QTAiPower;
info->Close = QTAiClose;
GameStateRestore = StateRestore;
@ -284,7 +234,10 @@ void QTAi_Init(CartInfo *info) {
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE - 4096;
// note, only extrnal cart's SRAM is battery backed, the the part on the main cartridge is just
// an additional work ram. so we may save only half here, but I forgot what part is saved lol, will
// find out later.
info->SaveGameLen[0] = WRAMSIZE;
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -46,9 +46,11 @@ void FCEUI_RewindToLastAutosave(void);
char *FCEUI_GetAboutString();
extern uint64 timestampbase;
// MMC5 external shared buffers/vars
extern int MMC5Hack;
extern uint32 MMC5HackVROMMask;
extern uint8 *MMC5HackExNTARAMPtr;
extern int MMC5Hack, PEC586Hack, QTAIHack;
extern uint8 *MMC5HackVROMPTR;
extern uint8 MMC5HackCHRMode;
extern uint8 MMC5HackSPMode;
@ -56,6 +58,12 @@ extern uint8 MMC50x5130;
extern uint8 MMC5HackSPScroll;
extern uint8 MMC5HackSPPage;
extern int PEC586Hack;
// VRCV extarnal shared buffers/vars
extern int QTAIHack;
extern uint8 QTAINTRAM[2048];
extern uint8 qtaintramreg;
#define GAME_MEM_BLOCK_SIZE 131072

View File

@ -330,7 +330,7 @@ int fceuindbg = 0;
//0xFF shall indicate to use palette[0]
uint8 gNoBGFillColor = 0xFF;
int MMC5Hack = 0, PEC586Hack = 0, QTAIHack = 0;
int MMC5Hack = 0;
uint32 MMC5HackVROMMask = 0;
uint8 *MMC5HackExNTARAMPtr = 0;
uint8 *MMC5HackVROMPTR = 0;
@ -340,6 +340,12 @@ uint8 MMC50x5130 = 0;
uint8 MMC5HackSPScroll = 0;
uint8 MMC5HackSPPage = 0;
int PEC586Hack = 0;
int QTAIHack = 0;
uint8 QTAINTRAM[2048];
uint8 qtaintramreg;
uint8 VRAMBuffer = 0, PPUGenLatch = 0;
uint8 *vnapage[4];
uint8 PPUNTARAM = 0;
@ -426,8 +432,12 @@ inline void FFCEUX_PPUWrite_Default(uint32 A, uint8 V) {
if (PPUCHRRAM & (1 << (tmp >> 10)))
VPage[tmp >> 10][tmp] = V;
} else if (tmp < 0x3F00) {
if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10)))
vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V;
if (QTAIHack && (qtaintramreg & 1)) {
QTAINTRAM[((((tmp & 0xF00) >> 10) >> ((qtaintramreg >> 1)) & 1) << 10) | (tmp & 0x3FF)] = V;
} else {
if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10)))
vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V;
}
} else {
if (!(tmp & 3)) {
if (!(tmp & 0xC)) {
@ -955,8 +965,12 @@ static DECLFW(B2007) {
if (PPUCHRRAM & (1 << (tmp >> 10)))
VPage[tmp >> 10][tmp] = V;
} else if (tmp < 0x3F00) {
if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10)))
vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V;
if (QTAIHack && (qtaintramreg & 1)) {
QTAINTRAM[((((tmp & 0xF00) >> 10) >> ((qtaintramreg >> 1)) & 1) << 10) | (tmp & 0x3FF)] = V;
} else {
if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10)))
vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V;
}
} else {
if (!(tmp & 3)) {
if (!(tmp & 0xC))
@ -1196,6 +1210,12 @@ static void RefreshLine(int lastpixel) {
#include "pputile.inc"
}
#undef PPU_BGFETCH
} if (QTAIHack) {
#define PPU_VRC5FETCH
for (X1 = firsttile; X1 < lasttile; X1++) {
#include "pputile.inc"
}
#undef PPU_VRC5FETCH
} else {
for (X1 = firsttile; X1 < lasttile; X1++) {
#include "pputile.inc"
@ -1959,12 +1979,16 @@ void runppu(int x) {
//todo - consider making this a 3 or 4 slot fifo to keep from touching so much memory
struct BGData {
struct Record {
uint8 nt, pecnt, at, pt[2];
uint8 nt, pecnt, at, pt[2], qtnt;
INLINE void Read() {
NTRefreshAddr = RefreshAddr = ppur.get_ntread();
if (PEC586Hack)
ppur.s = (RefreshAddr & 0x200) >> 9;
else if (QTAIHack) {
qtnt = QTAINTRAM[((((RefreshAddr >> 10) & 3) >> ((qtaintramreg >> 1)) & 1) << 10) | (RefreshAddr & 0x3FF)];
ppur.s = qtnt & 0x3F;
}
pecnt = (RefreshAddr & 1) << 3;
nt = CALL_PPUREAD(RefreshAddr);
runppu(kFetchTime);
@ -1990,12 +2014,16 @@ struct BGData {
ppur.par = nt;
RefreshAddr = ppur.get_ptread();
if (PEC586Hack) {
if (ScreenON)
RENDER_LOG(RefreshAddr | pecnt);
pt[0] = CALL_PPUREAD(RefreshAddr | pecnt);
runppu(kFetchTime);
pt[1] = CALL_PPUREAD(RefreshAddr | pecnt);
runppu(kFetchTime);
} else if (QTAIHack && (qtnt & 0x40)) {
pt[0] = *(CHRptr[0] + RefreshAddr);
runppu(kFetchTime);
RefreshAddr |= 8;
pt[1] = *(CHRptr[0] + RefreshAddr);
runppu(kFetchTime);
} else {
if (ScreenON)
RENDER_LOG(RefreshAddr);

View File

@ -1,6 +1,9 @@
uint8 *C;
register uint8 cc;
uint32 vadr;
#ifdef PPU_VRC5FETCH
uint8 tmpd;
#endif
#ifndef PPUT_MMC5SP
register uint8 zz;
@ -42,7 +45,11 @@ if (X1 >= 2) {
#else
zz = RefreshAddr & 0x1F;
C = vnapage[(RefreshAddr >> 10) & 3];
vadr = (C[RefreshAddr & 0x3ff] << 4) + vofs; // Fetch name table byte.
#ifdef PPU_VRC5FETCH
tmpd = QTAINTRAM[((((RefreshAddr >> 10) & 3) >> ((qtaintramreg >> 1)) & 1) << 10) | (RefreshAddr & 0x3FF)];
vofs = ((tmpd & 0x3F) << 12) | ((RefreshAddr >> 12) & 7); // recalculate VROM offset
#endif
vadr = (C[RefreshAddr & 0x3ff] << 4) + vofs; // Fetch name table byte.
#endif
#ifdef PPUT_HOOK
@ -78,7 +85,16 @@ pshift[1] <<= 8;
#elif defined(PPUT_MMC5)
C = MMC5BGVRAMADR(vadr);
#else
#ifdef PPU_VRC5FETCH
if(tmpd & 0x40)
C = CHRptr[0] + vadr;
else
C = VRAMADR(vadr);
#else
C = VRAMADR(vadr);
#endif
#endif
#endif