Files
ci-libretro-fceumm/src/boards/txcchip.c
negativeExponent c42a1d8a8e Update
2022-02-20 06:46:45 +08:00

406 lines
9.7 KiB
C

/* FCEUmm - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2012 CaH4e3
* Copyright (C) 2019 Libretro Team
* Copyright (C) 2020
*
* 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
*
* TXC/Micro Genius simplified mapper
* updated 06-2019 http://wiki.nesdev.com/w/index.php/INES_Mapper_036
*
* Known games:
* - Strike Wolf (Asia) (Unl)
* - Policeman (Gluk Video) (unl)
* - F-15 City War (Spain) (Gluk Video) (Unl)
*
* TXC mappers, originally much complex banksitching
*
* 01-22111-000 (05-00002-010) (132, 22211) - MGC-001 Qi Wang
* 01-22110-000 (52S ) - MGC-002 2-in-1 Gun
* 01-22111-100 (02-00002-010) (173 ) - MGC-008 Mahjong Block
* (079 ) - MGC-012 Poke Block
* 01-22110-200 (05-00002-010) (036 ) - MGC-014 Strike Wolf
* 01-22000-400 (05-00002-010) (036 ) - MGC-015 Policeman
* 01-22017-000 (05-PT017-080) (189 ) - MGC-017 Thunder Warrior
* 01-11160-000 (04-02310-000) ( , 11160) - MGC-023 6-in-1
* 01-22270-000 (05-00002-010) (132, 22211) - MGC-xxx Creatom
* 01-22200-400 (------------) (079 ) - ET.03 F-15 City War
* (172 ) - 1991 Du Ma Racing
*
*/
/* added 2020-2-16
* Updated based on latest source
* Mappers 36, 132, 173
* Mappers 136, 147, 172
*/
#include "mapinc.h"
typedef struct {
uint8 mask;
uint8 isJV001;
uint8 accumulator;
uint8 inverter;
uint8 staging;
uint8 output;
uint8 increase;
uint8 Y;
uint8 invert;
} TXC;
static TXC txc;
static void Dummyfunc(void) { }
static void (*WSync)(void) = Dummyfunc;
static SFORMAT StateRegs[] =
{
{ &txc.accumulator, 1, "ACC0" },
{ &txc.inverter, 1, "INVR" },
{ &txc.staging, 1, "STG0" },
{ &txc.output, 1, "OUT0" },
{ &txc.increase, 1, "INC0" },
{ &txc.Y, 1, "YFLG" },
{ &txc.invert, 1, "INVT" },
{ 0 }
};
static uint8 TXC_CMDRead(void) {
uint8 ret = ((txc.accumulator & txc.mask) | ((txc.inverter ^ txc.invert) & ~txc.mask));
txc.Y = !txc.invert || ((ret & 0x10) != 0);
WSync();
return ret;
}
static DECLFW(TXC_CMDWrite) {
if (A & 0x8000) {
if (txc.isJV001)
txc.output = (txc.accumulator & 0x0F) | (txc.inverter & 0xF0);
else
txc.output = (txc.accumulator & 0x0F) | ((txc.inverter << 1) & 0x10);
} else {
switch (A & 0x103) {
case 0x100:
if (txc.increase)
txc.accumulator++;
else
txc.accumulator = ((txc.accumulator & ~txc.mask) | ((txc.staging ^ txc.invert) & txc.mask));
break;
case 0x101:
txc.invert = (V & 0x01) ? 0xFF : 0x00;
break;
case 0x102:
txc.staging = V & txc.mask;
txc.inverter = V & ~txc.mask;
break;
case 0x103:
txc.increase = ((V & 0x01) != 0);
break;
}
}
txc.Y = !txc.invert || ((V & 0x10) != 0);
WSync();
}
static void TXCRegReset(void) {
txc.output = 0;
txc.accumulator = 0;
txc.inverter = 0;
txc.staging = 0;
txc.increase = 0;
txc.Y = 0;
txc.mask = txc.isJV001 ? 0x0F : 0x07;
txc.invert = txc.isJV001 ? 0xFF : 0x00;
WSync();
}
static void GenTXCPower(void) {
TXCRegReset();
}
static void StateRestore(int version) {
WSync();
}
static void GenTXC_Init(CartInfo *info, void (*proc)(void), uint32 jv001) {
txc.isJV001 = jv001;
WSync = proc;
GameStateRestore = StateRestore;
AddExState(StateRegs, ~0, 0, 0);
}
static int CheckHash(CartInfo *info) {
int x = 0;
uint64 partialmd5 = 0;
/* These carts do not work with new mapper implementation.
* This is a hack to use previous mapper implementation for such carts. */
for (x = 0; x < 8; x++)
partialmd5 |= (uint64)info->MD5[15 - x] << (x * 8);
switch (partialmd5) {
case 0x2dd8f958850f21f4LL: /* Jin Gwok Sei Chuen Saang (Ch) [U][!] */
FCEU_printf(" WARNING: Using alternate mapper implementation.\n");
UNL22211_Init(info);
return 1;
}
return 0;
}
/* --------------- Mapper 36 --------------- */
static uint8 creg = 0;
static void M36Sync(void) {
setprg32(0x8000, txc.output & 0x03);
setchr8(creg & 0x0F);
}
static DECLFW(M36Write) {
if ((A & 0xF200) == 0x4200) creg = V;
TXC_CMDWrite(A, (V >> 4) & 0x03);
}
static DECLFR(M36Read) {
uint8 ret = X.DB;
if ((A & 0x103) == 0x100)
ret = (X.DB & 0xCF) | ((TXC_CMDRead() << 4) & 0x30);
return ret;
}
static void M36Power(void) {
creg = 0;
GenTXCPower();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetReadHandler(0x4100, 0x5FFF, M36Read);
SetWriteHandler(0x4100, 0xFFFF, M36Write);
}
void Mapper36_Init(CartInfo *info) {
GenTXC_Init(info, M36Sync, 0);
info->Power = M36Power;
AddExState(&creg, 1, 0, "CREG");
}
/* --------------- Mapper 132 --------------- */
static void M132Sync(void) {
setprg32(0x8000, (txc.output >> 2) & 0x01);
setchr8(txc.output & 0x03);
}
static DECLFW(M132Write) {
TXC_CMDWrite(A, V & 0x0F);
}
static DECLFR(M132Read) {
uint8 ret = X.DB;
if ((A & 0x103) == 0x100)
ret = ((X.DB & 0xF0) | (TXC_CMDRead() & 0x0F));
return ret;
}
static void M132Power(void) {
GenTXCPower();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetReadHandler(0x4100, 0x5FFF, M132Read);
SetWriteHandler(0x4100, 0xFFFF, M132Write);
}
void Mapper132_Init(CartInfo *info) {
if (CheckHash(info) != 0) return;
GenTXC_Init(info, M132Sync, 0);
info->Power = M132Power;
}
/* --------------- Mapper 173 --------------- */
static void M173Sync(void) {
setprg32(0x8000, 0);
if (CHRsize[0] > 0x2000)
setchr8(((txc.output & 0x01) | (txc.Y ? 0x02 : 0x00) | ((txc.output & 2) << 0x01)));
else
setchr8(0);
}
void Mapper173_Init(CartInfo *info) {
GenTXC_Init(info, M173Sync, 0);
info->Power = M132Power;
}
/* ---------------- Joy/Van ----------------- */
/* --------------- Mapper 136 --------------- */
static void M136Sync(void) {
setprg32(0x8000, (txc.output >> 4) & 0x01);
setchr8(txc.output & 0x07);
}
static DECLFW(M136Write) {
TXC_CMDWrite(A, V & 0x3F);
}
static DECLFR(M136Read) {
uint8 ret = X.DB;
if ((A & 0x103) == 0x100)
ret = ((X.DB & 0xC0) | (TXC_CMDRead() & 0x3F));
return ret;
}
static void M136Power(void) {
GenTXCPower();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetReadHandler(0x4100, 0x5FFF, M136Read);
SetWriteHandler(0x4100, 0xFFFF, M136Write);
}
void Mapper136_Init(CartInfo *info) {
GenTXC_Init(info, M136Sync, 1);
info->Power = M136Power;
}
/* --------------- Mapper 147 --------------- */
static void M147Sync(void) {
setprg32(0x8000, ((txc.output >> 4) & 0x02) | (txc.output & 0x01));
setchr8((txc.output >> 1) & 0x0F);
}
static DECLFW(M147Write) {
TXC_CMDWrite(A, ((V >> 2) & 0x3F) | ((V << 6) & 0xC0));
}
static DECLFR(M147Read) {
uint8 ret = X.DB;
if ((A & 0x103) == 0x100) {
uint8 value = TXC_CMDRead();
ret = ((value << 2) & 0xFC) | ((value >> 6) & 0x03);
}
return ret;
}
static void M147Power(void) {
GenTXCPower();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetReadHandler(0x4100, 0x5FFF, M147Read);
SetWriteHandler(0x4100, 0xFFFF, M147Write);
}
void Mapper147_Init(CartInfo *info) {
GenTXC_Init(info, M147Sync, 1);
info->Power = M147Power;
}
/* --------------- Mapper 172 --------------- */
static void M172Sync(void) {
setprg32(0x8000, 0);
setchr8(txc.output);
setmirror(txc.invert ? 1 : 0);
}
static uint8 GetValue(uint8 value) {
return (((value << 5) & 0x20) | ((value << 3) & 0x10) | ((value << 1) & 0x08) |
((value >> 1) & 0x04) | ((value >> 3) & 0x02) | ((value >> 5) & 0x01));
}
static DECLFW(M172Write) {
TXC_CMDWrite(A, GetValue(V));
}
static DECLFR(M172Read) {
uint8 ret = X.DB;
if ((A & 0x103) == 0x100)
ret = (X.DB & 0xC0) | GetValue(TXC_CMDRead());
return ret;
}
static void M172Power(void) {
GenTXCPower();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetReadHandler(0x4100, 0x5FFF, M172Read);
SetWriteHandler(0x4100, 0xFFFF, M172Write);
}
void Mapper172_Init(CartInfo *info) {
GenTXC_Init(info, M172Sync, 1);
info->Power = M172Power;
}
/* === LEGACY MAPPER IMPLEMENTATION === */
static uint8 reg[4], cmd, is172, is173;
static SFORMAT UNL22211StateRegs[] =
{
{ reg, 4, "REGS" },
{ &cmd, 1, "CMD" },
{ 0 }
};
static void UNL22211Sync(void) {
setprg32(0x8000, (reg[2] >> 2) & 1);
if (is172)
setchr8((((cmd ^ reg[2]) >> 3) & 2) | (((cmd ^ reg[2]) >> 5) & 1)); /* 1991 DU MA Racing probably CHR bank sequence is WRONG, so it is possible to
* rearrange CHR banks for normal UNIF board and mapper 172 is unneccessary */
else
setchr8(reg[2] & 3);
}
static DECLFW(UNL22211WriteLo) {
/* FCEU_printf("bs %04x %02x\n",A,V); */
reg[A & 3] = V;
}
static DECLFW(UNL22211WriteHi) {
/* FCEU_printf("bs %04x %02x\n",A,V); */
cmd = V;
UNL22211Sync();
}
static DECLFR(UNL22211ReadLo) {
return (reg[1] ^ reg[2]) | (is173 ? 0x01 : 0x40);
#if 0
if(reg[3])
return reg[2];
else
return X.DB;
#endif
}
static void UNL22211Power(void) {
UNL22211Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetReadHandler(0x4100, 0x4100, UNL22211ReadLo);
SetWriteHandler(0x4100, 0x4103, UNL22211WriteLo);
SetWriteHandler(0x8000, 0xFFFF, UNL22211WriteHi);
}
static void UNL22211StateRestore(int version) {
UNL22211Sync();
}
void UNL22211_Init(CartInfo *info) {
is172 = 0;
is173 = 0;
info->Power = UNL22211Power;
GameStateRestore = UNL22211StateRestore;
AddExState(&UNL22211StateRegs, ~0, 0, 0);
}