/* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2011 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 */ #ifdef COPYFAMI #include "__serial.h" #include "mapinc.h" #include "mmc3.h" /* #define DEBUG_SERIAL */ /* *** COPY FAMICOM EMULATION *** */ /* * * * $0000-$1FFF * $2000-$200F PPU * $2010-$3FFB * $3FFC-$3FFF * $4000-$7FFF APU / * $8000-$FFF9 CART/ROM * $FFFA-$FFFB CART/ NMI * $FFFE-$FFFF CART/ IRQ * * * * CTRL R/W $3FFC ---aenic ($00 at reset) * * c - * 0 - * 1 - * i - IRQ * 0 - * 1 - * n - NMI * 0 - * 1 - * e - NMI * 0 - * 1 - * a - AROM * 0 - * 1 - * * BANK R/W $3FFD ---mbbbb * * b - * m - ROM * * USBDATA R/W $3FFE dddddddd * * d - / * * STATUS R $3FFF vmnicptr * * r - USB * 0 - * 1 - * t - USB * 0 - * 1 - * p - USB * 0 - * 1 - * c - * 0 - * 1 - * i - IRQ * 0 - * 1 - * n - NMI * 0 - * 1 - * m - 10 VRAM () * v - VRAM * 0 - * 1 - * * AROM * * VRAM * 8000-FFFF */ #define CTRL 0x00 #define CCART 0x01 #define CVIRQ 0x02 #define CVNMI 0x04 #define CDNMI 0x08 #define CAROM 0x10 #define BANK 0x01 #define BMIRR 0x10 #define USB 0x02 #define STATUS 0x03 #define SRX 0x01 #define STX 0x02 #define SPEN 0x04 #define SCART 0x08 #define SIRQ 0x10 #define SNMI 0x20 #define SA10 0x40 #define SVRAM 0x80 #ifdef DEBUG_SERIAL static uint8 debug_serial_data[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x02, 0x14, 0x50, 0xB0, 0x02, 0x14, 0x50, 0xB0, 0x02, }; static uint32 debug_serial_data_size = sizeof(debug_serial_data); static uint32 debug_serial_data_pos; #endif static uint8 *CHRRAM = NULL; static uint32 CHRRAMSIZE; static uint8 regs[4]; static readfunc def_read_ram, def_read_rom; static writefunc def_write_ram; static SFORMAT StateRegs[] = { { regs, 4, "CREGS" }, { 0 } }; static void Sync() { FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); } static void MCopyFamiMMC3PW(uint32 A, uint8 V) { if (regs[CTRL] & CCART) setprg8(A, V); else setprg32r(1, 0x8000, (regs[BANK] & 0x0F) ^ 0x08); } static void MCopyFamiMMC3CW(uint32 A, uint8 V) { if ((regs[STATUS] & SCART) && (regs[CTRL] & CAROM)) setchr8r(0x10, 0); else setchr1r(0, A, V); } static void MCopyFamiMMC3MW(uint8 V) { if (regs[CTRL] & CAROM) { setmirror(MI_0 + ((regs[BANK] >> 4) & 1)); } else { A000B = V; setmirror((V & 1) ^ 1); } } static uint32 direction = 0xffffffff; static uint32 bytes_count = 0; static DECLFW(MCopyFamiWriteReg) { if (((A & 3) == USB) && !fceuindbg) { if (direction != 0) { direction = 0; bytes_count = 0; FCEU_printf(" >"); } #ifndef DEBUG_SERIAL while (!SerialSendChar(V)) { } ; #endif bytes_count++; /* FCEU_printf(" %02X",V); */ } else { regs[A & 3] = V; Sync(); } } static DECLFR(MCopyFamiReadReg) { #ifdef DEBUG_SERIAL if (debug_serial_data_pos == debug_serial_data_size) regs[STATUS] |= SRX; else regs[STATUS] &= ~SRX; #endif if (!fceuindbg) { #ifndef DEBUG_SERIAL if ((A & 3) == STATUS) { int data; if ((data = SerialGetChar()) == EOF) regs[STATUS] |= SRX; else regs[STATUS] &= ~SRX; regs[USB] = data & 0xff; } else #endif if ((A & 3) == USB) { #ifdef DEBUG_SERIAL regs[USB] = debug_serial_data[debug_serial_data_pos++]; #endif if (direction != 1) { if (direction != 0xffffffff) FCEU_printf(" bytes sent: %08x", bytes_count); direction = 1; bytes_count = 0; FCEU_printf("\n<"); } FCEU_printf(" %02X", regs[USB]); } } return regs[A & 3]; } static DECLFW(MCopyFamiMMC3Write) { if (regs[CTRL] & CAROM) { regs[BANK] = V & 0x1F; Sync(); } else { if (A >= 0xC000) MMC3_IRQWrite(A, V); else MMC3_CMDWrite(A, V); } } static DECLFW(MCopyFamiMMC3WriteNMI) { if (regs[CTRL] & CVNMI) def_write_ram(0x3FFC + (A & 1), V); else MCopyFamiMMC3Write(A, V); } static DECLFW(MCopyFamiMMC3WriteIRQ) { if (regs[CTRL] & CVIRQ) def_write_ram(0x3FFE + (A & 1), V); else MCopyFamiMMC3Write(A, V); } static DECLFR(MCopyFamiReadNMI) { if (regs[CTRL] & CVNMI) return def_read_ram(0x3FFC + (A & 1)); else return def_read_rom(A); } static DECLFR(MCopyFamiReadIRQ) { if (regs[CTRL] & CVIRQ) return def_read_ram(0x3FFE + (A & 1)); else return def_read_rom(A); } static void MCopyFamiMMC3Power(void) { regs[CTRL] = regs[USB] = 0; regs[STATUS] = SIRQ | SNMI | SVRAM; regs[BANK] = 0x08; #ifdef DEBUG_SERIAL debug_serial_data_pos = 0; #endif GenMMC3Power(); Sync(); def_write_ram = GetWriteHandler(0x3FFC); SetWriteHandler(0x3FFC, 0x3FFF, MCopyFamiWriteReg); def_read_ram = GetReadHandler(0x3FFC); SetReadHandler(0x3FFC, 0x3FFF, MCopyFamiReadReg); SetWriteHandler(0x8000, 0xFFF9, MCopyFamiMMC3Write); SetWriteHandler(0xFFFA, 0xFFFB, MCopyFamiMMC3WriteNMI); SetWriteHandler(0xFFFE, 0xFFFF, MCopyFamiMMC3WriteIRQ); def_read_rom = GetReadHandler(0xFFFA); SetReadHandler(0xFFFA, 0xFFFB, MCopyFamiReadNMI); SetReadHandler(0xFFFE, 0xFFFF, MCopyFamiReadIRQ); } static void MCopyFamiMMC3Reset(void) { regs[CTRL] = regs[USB] = 0; regs[STATUS] = SIRQ | SNMI | SVRAM; regs[BANK] = 0x08; #ifdef DEBUG_SERIAL debug_serial_data_pos = 0; #endif MMC3RegReset(); Sync(); } static void MCopyFamiClose(void) { if (CHRRAM) FCEU_gfree(CHRRAM); CHRRAM = NULL; SerialClose(); } static void StateRestore(int version) { Sync(); } void MapperCopyFamiMMC3_Init(CartInfo *info) { GenMMC3_Init(info, 512, 512, 8, 0); cwrap = MCopyFamiMMC3CW; pwrap = MCopyFamiMMC3PW; mwrap = MCopyFamiMMC3MW; info->Reset = MCopyFamiMMC3Reset; info->Power = MCopyFamiMMC3Power; info->Close = MCopyFamiClose; GameStateRestore = StateRestore; CHRRAMSIZE = 8192; CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); #ifndef DEBUG_SERIAL FCEU_printf("WAITING FOR PORT...\n"); while (!SerialOpen(20, 921600)) { } FCEU_printf("PORT READY.\n"); #endif AddExState(&StateRegs, ~0, 0, 0); } #endif