diff --git a/src/boards/116.c b/src/boards/116.c index d8ded64..465efb4 100644 --- a/src/boards/116.c +++ b/src/boards/116.c @@ -25,7 +25,7 @@ static uint8 submapper; static uint8 reg; -static uint8 init; /* Games switch between ASICs expecting registers to keep their value, so initialize each ASIC only on the first switch and use this bitfield */ +static uint8 init; /* Games switch between ASICs expecting registers to keep their value, so initialize each ASIC only on the first switch and use this bitfield to track it */ static uint8 game; static SFORMAT stateRegs[] = { diff --git a/src/boards/14.c b/src/boards/14.c index 1c974c3..ad47557 100644 --- a/src/boards/14.c +++ b/src/boards/14.c @@ -23,7 +23,7 @@ #include "asic_vrc2and4.h" static uint8 reg; -static uint8 init; /* Games switch between ASICs expecting registers to keep their value, so initialize each ASIC only on the first switch and use this bitfield */ +static uint8 init; /* Games switch between ASICs expecting registers to keep their value, so initialize each ASIC only on the first switch and use this bitfield to track it */ static void applyMode (uint8); static SFORMAT StateRegs[] = { diff --git a/src/boards/446.c b/src/boards/446.c index 3dfcb9d..0683c35 100644 --- a/src/boards/446.c +++ b/src/boards/446.c @@ -22,7 +22,7 @@ #include "asic_h3001.h" #include "asic_latch.h" #include "asic_mmc1.h" -#include "asic_mmc2.h" +#include "asic_mmc2and4.h" #include "asic_mmc3.h" #include "asic_pt8154.h" #include "asic_qj.h" @@ -37,7 +37,6 @@ static uint8 submapper; static uint8 reg[8]; - static void (*mapperSync)(int, int, int, int) = NULL; static void applyMode (uint8); @@ -118,8 +117,8 @@ static void sync_H3001 (int prgAND, int prgOR, int chrAND, int chrOR) { static void sync_PNROM (int prgAND, int prgOR, int chrAND, int chrOR) { MMC2_syncPRG(prgAND, prgOR &~prgAND); - MMC2_syncCHR(chrAND, chrOR &~chrAND); - MMC2_syncMirror(); + MMC24_syncCHR(chrAND, chrOR &~chrAND); + MMC24_syncMirror(); } static void sync_SKROM (int prgAND, int prgOR, int chrAND, int chrOR) { @@ -344,7 +343,7 @@ static void applyMode (uint8 clear) { break; case 0x109: mapperSync = sync_PNROM; - MMC2_activate(clear, sync); + MMC24_activate(clear, sync); break; case 0x10A: case 0x20A: mapperSync = sync_TxROM; @@ -404,7 +403,7 @@ void Mapper446_Init(CartInfo *info) { H3001_addExState(); Latch_addExState(); MMC1_addExState(); - MMC2_addExState(); + MMC24_addExState(); MMC3_addExState(); VRC1_addExState(); VRC24_addExState(); diff --git a/src/boards/468.c b/src/boards/468.c index a6ba217..6b5025e 100644 --- a/src/boards/468.c +++ b/src/boards/468.c @@ -7,7 +7,7 @@ * 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 @@ -18,93 +18,40 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* BlazePro CPLD-based multicarts - - Unsolved issue: how is CHR RAM write-protection triggered? - - Known problems: - - Forever Duo of NES 852-in-1 (rev1): - #A370 Time Lord: Hangs with glitchy status bar on NTSC and PAL but not Dendy - #A133 Galactic Crusader: Wrong mirroring - #A249 Mission Cobra: Wrong mirroring - - Legendary Games of NES 509-in-1: - #189 Huang Di Battle of Zhuolu: Wrong mirroring during intro - #227 Kid Niki Niki 2: Title screen animation flickers and looks strange - #234 Klax: Screen in wrong position during options screen - #365 Rocman X: Graphical garbage in waterfall (middle) level - #403 Star Wars: Blank tiles due to lack of CHR RAM write-protection - #404 The Empire Strikes Back: Blank tiles due to lack of CHR RAM write-protection - #460 Twin Dragons: Wrong mirroring - - Unlicensed Collection 142-in-1: - #59 Huang Di: Wrong mirroring during intro - #84 Ms. Pac-Man: Wrong mirroring - #102 Rocman X: Graphical garbage in waterfall (middle) level - #132 Trolls on Treasure Island: Wrong mirroring during map - - Unreleased Collection 73-in-1 (v1.01): - #38 Holy Diver: Wrong mirroring during first scene -*/ - #include "mapinc.h" -#include "state.h" +#include "asic_fme7.h" +#include "asic_latch.h" +#include "asic_mmc1.h" +#include "asic_mmc2and4.h" +#include "asic_mmc3.h" +#include "asic_vrc1.h" +#include "asic_vrc2and4.h" +#include "asic_vrc3.h" +#include "asic_vrc6.h" +#include "asic_vrc7.h" +#include "wram.h" static uint8 submapper; -static uint8 eeprom[16], eep_clock, state, command, output; /* Some strange serial EEPROM */ -static uint8 *WRAM; -static uint32 WRAMSIZE; +static uint8 reg[4]; /* Supervisor registers */ +static uint8 Custom_reg[4]; /* Registers for custom mappers */ +static uint8 eeprom[16], eep_clock, state, command, output; /* Serial EEPROM */ -static int prevSFEXINDEX; -extern int SFEXINDEX; -extern SFORMAT SFMDATA[64]; - -static uint8 mapper; /* 5700 MSB >>4 OR'd with submapper <<4 */ -static uint8 mapperFlags; /* 5700 LSB */ -static uint8 misc; /* 5601 */ -static uint8 misc2; /* 5702 */ -static void (*sync)(); - -static uint16 prgOR; -static uint8 prgAND; - -static uint8 regByte[16]; -static int16 regWord[9]; - -#include "468_mmc1.h" -#include "468_mmc24.h" -#include "468_mmc3.h" -#include "468_vrc1.h" -#include "468_vrc24.h" -#include "468_vrc3.h" -#include "468_vrc6.h" -#include "468_vrc7.h" -#include "468_fme7.h" -#include "468_discrete.h" -#include "468_cnrom.h" -#include "468_if12.h" -#include "468_lf36.h" -#include "468_nanjing.h" +static void (*mapperSync)(int) = NULL; +static void applyMode (uint8); static SFORMAT stateRegs[] = { - { &mapper, 1, "SUP0" }, - { &mapperFlags, 1, "SUP1" }, - { &misc, 1, "SUP2" }, - { &misc2, 1, "SUP3" }, - { &prgOR, 2, "SUP4" }, - { &prgAND, 1, "SUP5" }, - { eeprom, 16,"EEPR" }, - { &eep_clock, 1, "EEP0" }, - { &state, 1, "EEP1" }, - { &command, 1, "EEP2" }, - { &output, 1, "EEP3" }, - { regByte, 16,"REGB" }, - { regWord, 16,"REGW" }, + { ®, 4, "REGS" }, + { &Custom_reg, 4, "CURG" }, + { eeprom, 16, "EEPR" }, + { &eep_clock, 1, "EEP0" }, + { &state, 1, "EEP1" }, + { &command, 1, "EEP2" }, + { &output, 1, "EEP3" }, { 0 } }; -static const uint16 lut509[512] ={ /* Strange look-up table, used only by Legendary Games of NES 509-in-1 */ +/* Serial EEPROM */ +static const uint16 lut509[512] = { /* Look-up table, used only by Legendary Games of NES 509-in-1 */ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 0, 1, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 4, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, @@ -122,151 +69,457 @@ static const uint16 lut509[512] ={ /* Strange look-up table, used only by Legend void setPins(uint8 select, uint8 newClock, uint8 newData) { /* Serial EEPROM */ if (select) - state =0; + state = 0; else if (!eep_clock && !!newClock) { if (state <8) { - command =command <<1 | !!(newData)*1; - if (++state ==8 && (command &0xF0) !=0x50 && (command &0xF0) !=0xA0) state =0; + command = command <<1 | !!(newData)*1; + if (++state == 8 && (command &0xF0) != 0x50 && (command &0xF0) != 0xA0) state = 0; } else { - int mask =1 <<(15 -state); - int address =command &0x0F; - if ((command &0xF0) ==0xA0) { - eeprom[address] =eeprom[address] &~mask | !!(newData)*mask; - /* The "write" command also silently returns the content of a strange lookup table */ - output =!!(lut509[eeprom[0] | eeprom[1] | eeprom[2] <<8 &0x1FF] >>(address &1? 0: 8) &mask); + int mask = 1 <<(15 -state); + int address = command &0x0F; + if ((command &0xF0) == 0xA0) { + eeprom[address] = eeprom[address] &~mask | !!(newData)*mask; + /* The "write" command also silently returns the content of a lookup table */ + output = !!(lut509[eeprom[0] | eeprom[1] | eeprom[2] <<8 &0x1FF] >>(address &1? 0: 8) &mask); } else - if ((command &0xF0) ==0x50) - output =!!(eeprom[address] &mask); - - if (++state ==16) state =0; + if ((command &0xF0) == 0x50) + output = !!(eeprom[address] &mask); + + if (++state == 16) state = 0; } } - eep_clock =newClock; + eep_clock = newClock; } -static DECLFR(readReg); -static DECLFW(writeReg); -static void setMapper(uint8 clearRegs) { - int i; - if (clearRegs) { - for (i =0; i <16; i++) regByte[i] =0; - for (i =0; i < 8; i++) regWord[i] =0; - X6502_IRQEnd(FCEU_IQEXT); - } - SetReadHandler(0x5000, 0x5FFF, readReg); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x5000, 0x5FFF, writeReg); - SetWriteHandler(0x6000, 0xFFFF, CartBW); - MapIRQHook = NULL; - PPU_hook = NULL; - GameHBIRQHook = NULL; - setprg8r(0x10, 0x6000, 0); +/* Mapper syncs */ +static void sync () { + if (mapperSync) mapperSync(reg[submapper == 1? 2: 3] <<9 &0x2000 | reg[1] <<5 &0x1FE0 | reg[0] <<4 &0x0010); +} - switch(mapper) { /* 5700 MSB >>4 OR'd with submapper <<4 */ - case 0x00: case 0x01: case 0x32: MMC1_reset(clearRegs); break; - case 0x0A: MMC2_reset(clearRegs); break; - case 0x10: case 0x11: case 0x12: MMC3_reset(clearRegs); break; - case 0x08: MMC4_reset(clearRegs); break; - case 0x40: VRC1_reset(clearRegs); break; - case 0x20: case 0x21: case 0x22: case 0x23: VRC24_reset(clearRegs); break; - case 0x44: VRC3_reset(clearRegs); break; - case 0x30: case 0x31: VRC6_reset(clearRegs); break; - case 0x41: VRC7_reset(clearRegs); break; - case 0x07: LF36_reset(clearRegs); break; - case 0x50: FME7_reset(clearRegs); break; - case 0x0E: case 0x1E: NANJING_reset(clearRegs); break; - case 0x09: case 0x0B: case 0x17: case 0x37: UNROM_IF12_reset(clearRegs); break; - case 0x04: case 0x06: case 0x14: case 0x16: ANROM_BNROM_reset(clearRegs); break; - case 0x05: case 0x15: CNROM_BF9097_reset(clearRegs); break; - case 0x0C: case 0x0D: case 0x1C: case 0x1D: GNROM_reset(clearRegs); break; - default: break; +static void sync_AxROM (int prgOR) { + int prgAND = reg[0] &0x20? 0x0F: reg[0] &0x02? 0x03: 0x07; + setprg32(0x8000, Latch_data &prgAND | prgOR >>2 &~prgAND); + setchr8(0); + setmirror(Latch_data &0x10? MI_1: MI_0); +} + +static void sync_BxROM (int prgOR) { + int prgAND = reg[0] &0x20? 0x0F: reg[0] &0x02? 0x03: 0x07; + setprg32(0x8000, Latch_data &prgAND | prgOR >>2 &~prgAND); + setchr8(0); + setmirror(reg[0] &0x04? MI_H: MI_V); +} + +static void sync_FME7 (int prgOR) { + int prgAND = reg[0] &0x02? 0x0F: 0x1F; + FME7_syncWRAM(0); + FME7_syncPRG(prgAND, prgOR &~prgAND); + FME7_syncCHR(0xFF, 0x00); + FME7_syncMirror(); +} + +static void sync_FxROM (int prgOR) { + int prgAND = reg[0] &0x02? 0x07: 0x0F; + MMC24_syncWRAM(0); + MMC4_syncPRG(prgAND, prgOR >>1 &~prgAND); + MMC24_syncCHR(0xFF, 0x00); + MMC24_syncMirror(); +} + +static void sync_GNROM (int prgOR) { + int prgAND = reg[0] &0x08? 0x01: 0x03; + int value = prgOR &0x2000 && submapper != 1? (Latch_data >>4 &0x0F | Latch_data <<4 &0xF0): Latch_data; + prgOR = prgOR >>2 | reg[0] >>1 &0x02; + setprg32(0x8000, value >>0 &prgAND | prgOR &~prgAND); + setchr8(value >>4); + setmirror(reg[0] &0x10? MI_H: MI_V); +} + +static void sync_IF12 (int prgOR) { + int prgAND = reg[0] &0x02? 0x07: 0x0F; + setprg16(0x8000, Custom_reg[1] &prgAND | prgOR >>1 &~prgAND); + setprg16(0xC000, prgOR >>1 | prgAND); + setchr8(Custom_reg[0] >>1 &0x0F); + setmirror(Custom_reg[0] &0x01? MI_H: MI_V); +} + +static void sync_LF36 (int prgOR) { + prgOR |= reg[0] &0x08; + setprg8(0x8000, 0x04 | prgOR); + setprg8(0xA000, 0x05 | prgOR); + setprg8(0xC000, Custom_reg[0] &0x07 | prgOR); + setprg8(0xE000, 0x07 | prgOR); + setchr8(0); + setmirror(reg[0] &0x04? MI_H: MI_V); +} + +static void sync_Misc (int prgOR) { + if (reg[0] &0x02) { + setprg16(0x8000, Custom_reg[2] <<1 &0x0E | reg[0] &0x01 | prgOR >>1 &~0x0F); + setprg16(0xC000, Custom_reg[2] <<1 &0x0E | reg[0] &0x01 | prgOR >>1 &~0x0F); + setchr8(Custom_reg[0] &0x03); + } else { + setprg32(0x8000, Custom_reg[2] &0x07 | prgOR >>2 &~0x07); + setchr8(Custom_reg[0] &0x0F); } + if (reg[0] &0x08) + setmirror(reg[0] &0x04? MI_H: MI_V); + else + setmirror(Custom_reg[1] &0x10? MI_1: MI_0); +} + +static void sync_Nanjing (int prgOR) { + setprg32(0x8000, Custom_reg[2] <<4 &0x30 | Custom_reg[0] &0x0F | (Custom_reg[3] &0x04? 0x00: 0x03) | prgOR >>2); + setchr8(0); + setmirror(reg[0] &0x04? MI_H: MI_V); +} + +static void sync_PNROM (int prgOR) { + MMC24_syncWRAM(0); + MMC2_syncPRG(0x0F, prgOR &~0x0F); + MMC24_syncCHR(0xFF, 0x00); + MMC24_syncMirror(); +} + +static void sync_SxROM (int prgOR) { + int prgAND = reg[0] &0x02? (reg[0] &0x08? 0x03: 0x07): 0x0F; + MMC1_syncWRAM(0); + MMC1_syncPRG(prgAND, (prgOR >>1 | reg[0] &0x06) &~prgAND); + MMC1_syncCHR(0x1F, 0x00); + MMC1_syncMirror(); +} + +static void sync_SUROM (int prgOR) { + MMC1_syncWRAM(0); + MMC1_syncPRG(0x1F, prgOR >>1 &~0x1F); + MMC1_syncCHR(0x0F, 0x00); + MMC1_syncMirror(); +} + +static void sync_TxROM (int prgOR) { + int prgAND = reg[0] &0x08? (reg[0] &0x04? (reg[0] &0x02? (reg[2] &0x02? 0x07: 0x0F): 0x1F): 0x3F): 0x7F; + prgOR |= reg[2] &0x01? 0x0C: 0x00; + MMC3_syncWRAM(0); + MMC3_syncPRG(prgAND, prgOR &~prgAND); + MMC3_syncCHR(reg[0] &0x10? 0xFF: 0x7F, 0x00); + MMC3_syncMirror(); +} + +static void sync_TxSROM (int prgOR) { + int prgAND = reg[0] &0x08? (reg[0] &0x04? (reg[0] &0x02? (reg[2] &0x02? 0x07: 0x0F): 0x1F): 0x3F): 0x7F; + prgOR |= reg[2] &0x01? 0x0C: 0x00; + MMC3_syncWRAM(0); + MMC3_syncPRG(prgAND, prgOR &~prgAND); + MMC3_syncCHR(0x7F, 0x00); + switch(MMC3_getMirroring() &3) { /* Only A000=02 is TxSROM. H/V mirroring is necessary for Ys 1, modified for MMC3. */ + case 0: + setmirror(MI_V); + break; + case 1: + setmirror(MI_H); + break; + case 2: + setmirror(MMC3_getCHRBank(0) &0x80? MI_1: MI_0); + break; + case 3: + setmirror(MI_1); + break; + } +} + +static void sync_UxROM (int prgOR) { + int prgAND = reg[0] &0x02? 0x07: 0x0F; + setprg16(0x8000, Latch_data &prgAND | prgOR >>1 &~prgAND); + setprg16(0xC000, prgOR >>1 | prgAND); + setchr8(0); + setmirror(reg[0] &0x04? MI_H: MI_V); +} + +static void sync_UNROM512 (int prgOR) { + setprg16(0x8000, Latch_data &0x1F | prgOR >>1 &~0x1F); + setprg16(0xC000, prgOR >>1 | 0x1F); + setchr8(Latch_data >>5); + setmirror(reg[0] &0x04? MI_H: MI_V); +} + +static void sync_VRC1 (int prgOR) { + int prgAND = reg[0] &0x08? (reg[0] &0x04? (reg[0] &0x02? 0x0F: 0x1F): 0x3F): 0x7F; + VRC1_syncPRG(prgAND, prgOR &~prgAND); + VRC1_syncCHR(0x1F, 0x00); + VRC1_syncMirror(); +} + +static void sync_VRC24 (int prgOR) { + int prgAND = reg[0] &0x02? 0x0F: 0x1F; + VRC24_syncWRAM(0); + VRC24_syncPRG(prgAND, prgOR &~prgAND); + VRC24_syncCHR(0xFF, 0x00); + VRC24_syncMirror(); +} + +static void sync_VRC3 (int prgOR) { + VRC3_syncWRAM(0); + VRC3_syncPRG(0x07, prgOR >>1 &~0x07); + VRC3_syncCHR(0x01, 0x00); + setmirror(reg[0] &0x04? MI_H: MI_V); +} + +static void sync_VRC6 (int prgOR) { + int prgAND = reg[0] &0x02? 0x0F: 0x1F; + VRC6_syncWRAM(0); + VRC6_syncPRG(prgAND, prgOR &~prgAND); + VRC6_syncCHR(0xFF, 0x00); + VRC6_syncMirror(); +} + +static void sync_VRC7 (int prgOR) { + int prgAND = reg[0] &0x08? (reg[0] &0x04? (reg[0] &0x02? 0x0F: 0x1F): 0x3F): 0x7F; + VRC7_syncWRAM(0); + VRC7_syncPRG(prgAND, prgOR &~prgAND); + VRC7_syncCHR(0xFF, 0x00); + VRC7_syncMirror(); +} + +/* Mapper callbacks and handlers */ +static int SUROM_getPRGBank(uint8 bank) { + return MMC1_getPRGBank(bank) | MMC1_getCHRBank(0) &0x10; +} + +static DECLFW(IF12_writeReg) { + Custom_reg[A >>14 &1] = V; sync(); } +void FP_FASTAPASS(1) LF36_cpuCycle (int a) { + while (a--) { + if (Custom_reg[1] &1) { + if (!++Custom_reg[2]) ++Custom_reg[3]; + if (Custom_reg[3] &0x10) + X6502_IRQBegin(FCEU_IQEXT); + else + X6502_IRQEnd(FCEU_IQEXT); + } else { + Custom_reg[2] = Custom_reg[3] = 0; + X6502_IRQEnd(FCEU_IQEXT); + } + } +} + +static DECLFW(LF36_writeReg) { + switch(A >>13 &3) { + case 0: case 1: + Custom_reg[1] = A >>13 &1; + break; + case 3: + Custom_reg[0] = V; + sync(); + } +} + +static DECLFW(Misc_writeReg) { + switch(A >>12 &7) { + case 0: case 2: case 3: + Custom_reg[0] = V; + sync(); + break; + case 1: + Custom_reg[1] = V; + sync(); + break; + case 6: case 7: + Custom_reg[2] = V; + sync(); + break; + } +} + +static void Nanjing_scanline (void) { + if (Custom_reg[0] &0x80 && scanline <239) { + setchr4(0x0000, scanline >= 127? 1: 0); + setchr4(0x1000, scanline >= 127? 1: 0); + } else + setchr8(0); +} + +static DECLFW(Nanjing_writeReg) { + Custom_reg[A >>8 &3] = V; + sync(); +} + +/* Supervisor */ static DECLFR(readReg) { switch(A) { - case 0x5301: case 0x5601: - return output? 0x80: 0x00; - default: - return 0xFF; + case 0x5301: case 0x5601: + return output? 0x80: 0x00; + default: + return 0xFF; } } static DECLFW(writeReg) { switch(A) { - case 0x5301: - if (submapper ==0) setPins(!!(V &0x04), !!(V &0x02), !!(V &0x01)); - break; - case 0x5601: - if (~misc &0x80) { - misc =V; - if (submapper !=1) { - prgOR =prgOR &~0x2000 | V <<9 &0x2000; + case 0x5301: + if (submapper == 0) setPins(!!(V &0x04), !!(V &0x02), !!(V &0x01)); + break; + case 0x5601: + if (submapper == 1) setPins(!!(V &0x10), !!(V &0x02), !!(V &0x01)); + if (~reg[3] &0x80) { + reg[3] = V; sync(); } - } - if (submapper ==1) setPins(!!(V &0x10), !!(V &0x02), !!(V &0x01)); - break; - case 0x5700: - mapper =V >>4 | submapper <<4; - mapperFlags =V &0xF; - prgOR =prgOR &~0x0010 | V <<4 &0x0010; - setMapper(1); - break; - case 0x5701: - prgOR =prgOR &~0x1FE0 | V <<5 &0x1FE0; - sync(); - break; - case 0x5702: - if (submapper ==1) { - misc2 =V; - prgOR =prgOR &~0x2000 | V <<9 &0x2000; - setMapper(0); /* The misc2 value is required for prgAND by MMC3 and UNROM */ - } - break; + break; + case 0x5700: + reg[A &3] = V; + applyMode(1); + break; + case 0x5701: case 0x5702: + reg[A &3] = V; + sync(); + break; } } -static void reset(void) { - mapper =submapper <<4; - mapperFlags =0x0F; - misc =0; - misc2 =0; - prgOR =0x7FF0; - eep_clock =command =output =1; - command =state =0; - setMapper(1); +static void applyMode (uint8 clear) { + MapIRQHook = NULL; + PPU_hook = NULL; + GameHBIRQHook = NULL; + SetReadHandler(0x5000, 0x5FFF, readReg); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x5000, 0x5FFF, writeReg); + SetWriteHandler(0x6000, 0xFFFF, CartBW); + switch(submapper <<8 | reg[0] >>4) { + case 0x000: case 0x302: + mapperSync = sync_SxROM; + MMC1_activate(clear, sync, MMC1_TYPE_MMC1B, NULL, NULL, NULL, NULL); + break; + case 0x001: + mapperSync = sync_SUROM; + MMC1_activate(clear, sync, MMC1_TYPE_MMC1B, SUROM_getPRGBank, NULL, NULL, NULL); + break; + case 0x004: case 0x006: case 0x104: case 0x106: + mapperSync = reg[0] &0x08? sync_BxROM: sync_AxROM; + Latch_activate(clear, sync, 0x8000, 0xFFFF, NULL); + break; + case 0x005: case 0x105: + mapperSync = sync_Misc; /* NROM, CNROM, Fire Hawk */ + SetWriteHandler(0x8000, 0xFFFF, Misc_writeReg); + break; + case 0x007: + mapperSync = sync_LF36; /* SMB2J */ + MapIRQHook = LF36_cpuCycle; + SetWriteHandler(0x8000, 0xFFFF, LF36_writeReg); + break; + case 0x008: + mapperSync = sync_FxROM; + MMC24_activate(clear, sync); + break; + case 0x009: case 0x107: case 0x307: + if (reg[0] &0x08) { + mapperSync = sync_UxROM; + Latch_activate(clear, sync, 0x8000, 0xFFFF, NULL); + } else { + mapperSync = sync_IF12; /* Not Irem's actual IF-12 mapper, but something custom by BlazePro */ + SetWriteHandler(0x8000, 0xFFFF, IF12_writeReg); + } + break; + case 0x00A: + mapperSync = sync_PNROM; + MMC24_activate(clear, sync); + break; + case 0x00B: + mapperSync = sync_UNROM512; + Latch_activate(clear, sync, 0x8000, 0xFFFF, NULL); + break; + case 0x00C: case 0x00D: case 0x10C: case 0x10D: + mapperSync = sync_GNROM; + Latch_activate(clear, sync, 0x8000, 0xFFFF, NULL); + break; + case 0x00E: case 0x10E: + mapperSync = sync_Nanjing; /* Partial emulation only */ + GameHBIRQHook = Nanjing_scanline; + SetWriteHandler(0x5000, 0x53FF, Nanjing_writeReg); + break; + case 0x100: case 0x101: + mapperSync = sync_TxROM; + MMC3_activate(clear, sync, MMC3_TYPE_SHARP, NULL, NULL, NULL, NULL); + break; + case 0x102: + mapperSync = sync_TxSROM; + MMC3_activate(clear, sync, MMC3_TYPE_SHARP, NULL, NULL, NULL, NULL); + break; + case 0x200: + mapperSync = sync_VRC24; + VRC2_activate(clear, sync, 0x05, 0x0A, NULL, NULL, NULL, NULL); + break; + case 0x201: + mapperSync = sync_VRC24; + VRC4_activate(clear, sync, 0x05, 0x0A, 1, NULL, NULL, NULL, NULL, NULL); + break; + case 0x202: + mapperSync = sync_VRC24; + VRC2_activate(clear, sync, 0x0A, 0x05, NULL, NULL, NULL, NULL); + break; + case 0x203: + mapperSync = sync_VRC24; + VRC4_activate(clear, sync, 0x0A, 0x05, 1, NULL, NULL, NULL, NULL, NULL); + break; + case 0x300: + mapperSync = sync_VRC6; + VRC6_activate(clear, sync, 0x01, 0x02, NULL, NULL, NULL, NULL); + break; + case 0x400: + mapperSync = sync_VRC1; + VRC1_activate(clear, sync); + break; + case 0x401: + mapperSync = sync_VRC7; + VRC7_activate(clear, sync, 0x18); + break; + case 0x404: + mapperSync = sync_VRC3; + VRC3_activate(clear, sync); + break; + case 0x500: + mapperSync = sync_FME7; + FME7_activate(clear, sync); + break; + default: + break; + } } -static void power(void) { - int i; - for (i =0; i <16; i++) eeprom[i] =0; - reset(); +static void power() { + reg[0] = 0x0F; + reg[1] = 0xFF; + reg[2] = submapper == 1? 0x10: 0x00; + reg[3] = 0x00; + Custom_reg[0] = Custom_reg[1] = Custom_reg[2] = Custom_reg[3] = 0; + eep_clock = command = output = 1; + command = state = 0; + applyMode(1); } -static void close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} static void stateRestore(int version) { - setMapper(0); + applyMode(0); } void Mapper468_Init(CartInfo *info) { - submapper =info->submapper; - info->Reset =reset; - info->Power =power; - info->Close =close; - GameStateRestore =stateRestore; - - WRAMSIZE =8192; - WRAM =(uint8*) FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + submapper = info->submapper; + FME7_addExState(); + Latch_addExState(); + MMC1_addExState(); + MMC24_addExState(); + MMC3_addExState(); + VRC1_addExState(); + VRC24_addExState(); + VRC3_addExState(); + VRC6_addExState(); + VRC7_addExState(); + WRAM_init(info, 8); + info->Reset = power; + info->Power = power; + GameStateRestore = stateRestore; AddExState(stateRegs, ~0, 0, 0); - prevSFEXINDEX =SFEXINDEX; } diff --git a/src/boards/468_cnrom.h b/src/boards/468_cnrom.h deleted file mode 100644 index 00dc2dc..0000000 --- a/src/boards/468_cnrom.h +++ /dev/null @@ -1,45 +0,0 @@ -#define CNROM_reg regByte - -static void CNROM_sync () { - int OR =prgOR >>1; - if (mapperFlags &2) { - setprg16(0x8000, CNROM_reg[2] <<1 &0xE | mapperFlags &1 | OR &~0xF); - setprg16(0xC000, CNROM_reg[2] <<1 &0xE | mapperFlags &1 | OR &~0xF); - setchr8(CNROM_reg[0] &0x03); - } else { - OR >>=1; - setprg32(0x8000, CNROM_reg[2] &0x7 | OR &~0x7); - setchr8(CNROM_reg[0] &0x0F); - } - if (mapperFlags &8) - setmirror(mapperFlags &0x04? MI_H: MI_V); - else - setmirror(CNROM_reg[1] &0x10? MI_1: MI_0); -} - -static DECLFW(CNROM_writeReg) { - switch(A &0xE000) { - case 0x8000: case 0xA000: - CNROM_reg[0] =V; - break; - case 0xE000: - CNROM_reg[2] =V; - break; - } - sync(); -} - -static DECLFW(BF9097_writeMirroring) { - CNROM_reg[1] =V; - sync(); -} - -void CNROM_BF9097_reset(uint8 clearRegs) { /* This strange mapper is used for both (C)NROM games and FireHawk. What an absurd combination!*/ - sync =CNROM_sync; - SetWriteHandler(0x8000, 0xFFFF, CNROM_writeReg); - if (~mapperFlags &8) - SetWriteHandler(0x9000, 0x9FFF, BF9097_writeMirroring); - sync(); -} - -#undef CNROM_reg diff --git a/src/boards/468_discrete.h b/src/boards/468_discrete.h deleted file mode 100644 index e42c438..0000000 --- a/src/boards/468_discrete.h +++ /dev/null @@ -1,73 +0,0 @@ -#define latch regByte[0] - -static void ANROM_sync () { - int AND =prgAND >>2; - int OR =prgOR >>2; - setprg32(0x8000, latch &AND | OR &~AND); - setchr8(0); - setmirror(latch &0x10? MI_1: MI_0); -} - -static void BNROM_sync () { - int AND =prgAND >>2; - int OR =prgOR >>2; - setprg32(0x8000, latch &AND | OR &~AND); - setchr8(0); - setmirror(mapperFlags &4? MI_H: MI_V); -} - -static void GNROM_sync () { - int AND =prgAND >>2; - int OR =prgOR >>2 | (mapperFlags &4? 2: 0); - setprg32(0x8000, latch >>4 &AND | OR &~AND); - setchr8(latch &0x0F); - setmirror(mapper &1? MI_H: MI_V); -} - -static void UNROM_sync () { - int AND =prgAND >>1; - int OR =prgOR >>1; - setprg16(0x8000, latch &AND | OR &~AND); - setprg16(0xC000, 0xFF &AND | OR &~AND); - setchr8(0); - setmirror(mapperFlags &4? MI_H: MI_V); -} - -static DECLFW(DISCRETE_writeLatch) { - latch =V; - sync(); -} - -static DECLFW(Portopia_writeLatch) { - DISCRETE_writeLatch(A, A ==0xA000 && V ==0x00? 0x06: V); /* Strange hack, needed to get #282 "Portopia Serial Murder Case" on 852-in-1 running */ -} - -static DECLFW(ColorDreams_writeLatch) { - DISCRETE_writeLatch(A, V >>4 &0xF | V <<4 &0xF0); /* Sswap nibbles to mimic GNROM */ -} - - -void ANROM_BNROM_reset(uint8 clearRegs) { - sync =mapperFlags &8? BNROM_sync: ANROM_sync; - prgAND =(mapper ==0x06 || mapper ==0x16)? 0x3F: mapperFlags &2? 0x0F: 0x1F; - SetWriteHandler(0x8000, 0xFFFF, DISCRETE_writeLatch); - latch =0; - sync(); -} - -void GNROM_reset(uint8 clearRegs) { - sync =GNROM_sync; - prgAND =mapperFlags &8? 0x07: 0x0F; - SetWriteHandler(0x8000, 0xFFFF, misc &0x10 && mapper &~0x10? DISCRETE_writeLatch: ColorDreams_writeLatch); - latch =0; - sync(); -} - -void UNROM_reset(uint8 clearRegs) { - sync =UNROM_sync; - prgAND =mapper ==0x0B || misc2 &0x10? 0x3F: mapperFlags &2? 0x0F: 0x1F; - SetWriteHandler(0x8000, 0xFFFF, mapper ==0x09 && mapperFlags ==0xE? Portopia_writeLatch: DISCRETE_writeLatch); - sync(); -} - -#undef latch diff --git a/src/boards/468_fme7.h b/src/boards/468_fme7.h deleted file mode 100644 index 0e3d311..0000000 --- a/src/boards/468_fme7.h +++ /dev/null @@ -1,72 +0,0 @@ -#define FME7_reg regByte -#define FME7_index regByte[15] -#define FME7_counter regWord[0] - -static void FME7_sync() { - int AND =mapperFlags &8? 0xFF: 0x7F; - switch(FME7_reg[8] &0xC0) { - case 0x00: case 0x80: - setprg8(0x6000, FME7_reg[0x8] &prgAND | prgOR &~prgAND); - break; - case 0x40: - /* Open Bus */ - break; - case 0xC0: - setprg8r(0x10, 0x6000, 0); - break; - } - - setprg8(0x8000, FME7_reg[0x9] &prgAND | prgOR &~prgAND); - setprg8(0xA000, FME7_reg[0xA] &prgAND | prgOR &~prgAND); - setprg8(0xC000, FME7_reg[0xB] &prgAND | prgOR &~prgAND); - setprg8(0xE000, prgAND | prgOR &~prgAND); - setchr1(0x0000, FME7_reg[0x0] &AND); - setchr1(0x0400, FME7_reg[0x1] &AND); - setchr1(0x0800, FME7_reg[0x2] &AND); - setchr1(0x0C00, FME7_reg[0x3] &AND); - setchr1(0x1000, FME7_reg[0x4] &AND); - setchr1(0x1400, FME7_reg[0x5] &AND); - setchr1(0x1800, FME7_reg[0x6] &AND); - setchr1(0x1C00, FME7_reg[0x7] &AND); - setmirror(FME7_reg[0xC] &3 ^(FME7_reg[0xC] &2? 0: 1)); -} - -static DECLFW(FME7_writeIndex) { - FME7_index =V &0xF; -} - -static DECLFW(FME7_writeReg) { - switch(FME7_index) { - case 0xE: - FME7_counter =FME7_counter &0xFF00 |V; - break; - case 0xF: - FME7_counter =FME7_counter &0x00FF |V <<8; - break; - case 0xD: - X6502_IRQEnd(FCEU_IQEXT); - /* Falling through */ - default: - FME7_reg[FME7_index] =V; - sync(); - } -} - -static void FP_FASTAPASS(1) FME7_cpuCycle(int a) { - while (a--) { - if (FME7_reg[0xD] &0x80 && !--FME7_counter && FME7_reg[0xD] &0x01) X6502_IRQBegin(FCEU_IQEXT); - } -} - -void FME7_reset(uint8 clearRegs) { - sync =FME7_sync; - prgAND =mapperFlags &2? 0x0F: 0x1F; - MapIRQHook =FME7_cpuCycle; - SetWriteHandler(0x8000, 0x9FFF, FME7_writeIndex); - SetWriteHandler(0xA000, 0xBFFF, FME7_writeReg); - sync(); -} - -#undef FME7_reg -#undef FME7_index -#undef FME7_counter diff --git a/src/boards/468_if12.h b/src/boards/468_if12.h deleted file mode 100644 index 12ec1e7..0000000 --- a/src/boards/468_if12.h +++ /dev/null @@ -1,31 +0,0 @@ -#define IF12_reg regByte - -static void IF12_sync () { - int AND =prgAND >>1; - int OR =prgOR >>1; - setprg16(0x8000, IF12_reg[1] &AND | OR &~AND); - setprg16(0xC000, 0xFF &AND | OR &~AND); - setchr8(IF12_reg[0] >>1 &0xF); - setmirror(IF12_reg[0] &1? MI_H: MI_V); -} - -static DECLFW(IF12_writeReg) { - IF12_reg[A >>14 &1] =V; - sync(); -} - -void IF12_reset(uint8 clearRegs) { - sync =IF12_sync; - prgAND =mapperFlags &2? 0x0F: 0x1F; - SetWriteHandler(0x8000, 0xFFFF, IF12_writeReg); - sync(); -} - -void UNROM_IF12_reset(uint8 clearRegs) { - if (mapperFlags &8) - UNROM_reset(clearRegs); - else - IF12_reset(clearRegs); -} - -#undef IF12_reg diff --git a/src/boards/468_lf36.h b/src/boards/468_lf36.h deleted file mode 100644 index 73f9407..0000000 --- a/src/boards/468_lf36.h +++ /dev/null @@ -1,46 +0,0 @@ -#define LF36_prg regByte[0] -#define LF36_irq regByte[1] -#define LF36_counter regWord[0] - -static void LF36_sync () { - int OR =prgOR | mapperFlags &0x08; - setprg8(0x8000, 0x04 | OR); - setprg8(0xA000, 0x05 | OR); - setprg8(0xC000, LF36_prg &0x07 | OR); - setprg8(0xE000, 0x07 | OR); - setchr8(0); - setmirror(mapperFlags &4? MI_H: MI_V); -} - -static DECLFW(LF36_writeReg) { - switch (A &0xE000) { - case 0x8000: LF36_irq =0; break; - case 0xA000: LF36_irq =1; break; - case 0XE000: LF36_prg =V; sync(); break; - } -} - -static void FP_FASTAPASS(1) LF36_cpuCycle(int a) { - while (a--) { - if (LF36_irq) { - if (++LF36_counter &0x1000) - X6502_IRQBegin(FCEU_IQEXT); - else - X6502_IRQEnd(FCEU_IQEXT); - } else { - X6502_IRQEnd(FCEU_IQEXT); - LF36_counter =0; - } - } -} - -void LF36_reset(uint8 clearRegs) { - sync =LF36_sync; - MapIRQHook =LF36_cpuCycle; - SetWriteHandler(0x8000, 0xFFFF, LF36_writeReg); - sync(); -} - -#undef LF36_prg -#undef LF36_irq -#undef LF36_counter diff --git a/src/boards/468_mmc1.h b/src/boards/468_mmc1.h deleted file mode 100644 index b780ce2..0000000 --- a/src/boards/468_mmc1.h +++ /dev/null @@ -1,72 +0,0 @@ -#define MMC1_reg regByte -#define MMC1_control regByte[0] -#define MMC1_chr0 regByte[1] -#define MMC1_chr1 regByte[2] -#define MMC1_prg regByte[3] -#define MMC1_shift regByte[4] -#define MMC1_count regByte[5] -#define MMC1_filter regByte[6] - -static void MMC1_sync () { - int AND =prgAND >>1; - int OR =prgOR >>1 | (mapper &0x01? (MMC1_chr0 &0x10): (mapperFlags &0x06)); - if (MMC1_control &0x08) { /* 16 KiB mode */ - if (MMC1_control &0x04) { /* OR logic */ - setprg16(0x8000, MMC1_prg &AND | OR &~AND); - setprg16(0xC000, 0xFF &AND | OR &~AND); - } else { /* AND logic */ - setprg16(0x8000, 0 &AND | OR &~AND); - setprg16(0xC000, MMC1_prg &AND | OR &~AND); - } - } else - setprg32(0x8000, (MMC1_prg &AND | OR &~AND) >>1); - - AND =mapper &0x01? 0x0F: 0x1F; /* SUROM needs to have the upper PRG bank bit, which is in the CHR registers, masked off */ - if (MMC1_control &0x10) { /* 4 KiB mode */ - setchr4(0x0000, MMC1_chr0 &AND); - setchr4(0x1000, MMC1_chr1 &AND); - } else /* 8 KiB mode */ - setchr8(MMC1_chr0 >>1 &(AND >>1)); - - setmirror(MMC1_control &2? (MMC1_control &1? MI_H: MI_V): (MMC1_control &1? MI_1: MI_0)); -} - -static DECLFW(MMC1_writeReg) { - if (V &0x80) { - MMC1_shift =MMC1_count =0; - MMC1_control |=0x0C; - sync(); - } else - if (!MMC1_filter) { - MMC1_shift |=(V &1) <>13 &3] =MMC1_shift; - MMC1_count =0; - MMC1_shift =0; - sync(); - } - } - MMC1_filter =2; -} - -static void FP_FASTAPASS(1) MMC1_cpuCycle(int a) { - while (a--) if (MMC1_filter) MMC1_filter--; -} - -void MMC1_reset(uint8 clearRegs) { - sync =MMC1_sync; - MapIRQHook =MMC1_cpuCycle; - prgAND =mapperFlags &2? (mapperFlags &8? 0x07: 0x0F): 0x1F; - SetWriteHandler(0x8000, 0xFFFF, MMC1_writeReg); - if (clearRegs) MMC1_control =0x0C; - sync(); -} - -#undef MMC1_reg -#undef MMC1_control -#undef MMC1_chr0 -#undef MMC1_chr1 -#undef MMC1_prg -#undef MMC1_shift -#undef MMC1_count -#undef MMC1_filter diff --git a/src/boards/468_mmc24.h b/src/boards/468_mmc24.h deleted file mode 100644 index 398fcc0..0000000 --- a/src/boards/468_mmc24.h +++ /dev/null @@ -1,67 +0,0 @@ -#define MMC24_reg regByte - -static void MMC2_sync() { - setprg8(0x8000, MMC24_reg[0] &prgAND | prgOR &~prgAND); - setprg8(0xA000, 0xFD &prgAND | prgOR &~prgAND); - setprg8(0xC000, 0xFE &prgAND | prgOR &~prgAND); - setprg8(0xE000, 0xFF &prgAND | prgOR &~prgAND); - setchr4(0x0000, MMC24_reg[1 +MMC24_reg[6]]); - setchr4(0x1000, MMC24_reg[3 +MMC24_reg[7]]); - setmirror(MMC24_reg[5] &1? MI_H: MI_V); -} - -static void MMC4_sync() { - int AND =prgAND >>1; - int OR =prgOR >>1; - setprg16(0x8000, MMC24_reg[0] &AND | OR &~AND); - setprg16(0xC000, 0xFF &AND | OR &~AND); - setchr4(0x0000, MMC24_reg[1 +MMC24_reg[6]]); - setchr4(0x1000, MMC24_reg[3 +MMC24_reg[7]]); - setmirror(MMC24_reg[5] &1? MI_H: MI_V); -} - -static DECLFW(MMC24_writeReg) { - MMC24_reg[(A >>12) -0xA] =V; - sync(); -} - -static void FP_FASTAPASS(1) MMC24_ppuHook(uint32 A) { - uint8 l, h = A >> 8; - if (h >= 0x20 || ((h & 0xF) != 0xF)) return; - l = A & 0xF0; - if (h < 0x10) { - if (l == 0xD0) { - MMC24_reg[6] =0; - sync(); - } else if (l == 0xE0) { - MMC24_reg[6] =1; - sync(); - } - } else { - if (l == 0xD0) { - MMC24_reg[7] =0; - sync(); - } else if (l == 0xE0) { - MMC24_reg[7] =1; - sync(); - } - } -} - -void MMC2_reset(uint8 clearRegs) { - sync =MMC2_sync; - prgAND =0x0F; - PPU_hook =MMC24_ppuHook; - SetWriteHandler(0xA000, 0xFFFF, MMC24_writeReg); - sync(); -} - -void MMC4_reset(uint8 clearRegs) { - sync =MMC4_sync; - prgAND =mapperFlags &2? 0x0F: 0x1F; - PPU_hook =MMC24_ppuHook; - SetWriteHandler(0xA000, 0xFFFF, MMC24_writeReg); - sync(); -} - -#undef MMC24_reg diff --git a/src/boards/468_mmc3.h b/src/boards/468_mmc3.h deleted file mode 100644 index f46c64d..0000000 --- a/src/boards/468_mmc3.h +++ /dev/null @@ -1,80 +0,0 @@ -#define MMC3_reg regByte -#define MMC3_index regByte[8] -#define MMC3_mirroring regByte[9] -#define MMC3_wram regByte[10] -#define MMC3_reload regByte[11] -#define MMC3_count regByte[12] -#define MMC3_irq regByte[13] -#define MMC3_lastReg regByte[14] - -static void MMC3_sync () { - int chrAND =mapper &0x01? 0xFF: 0x7F; - int OR =prgOR | (misc2 &1? 12: 0); - setprg8(0x8000 ^(MMC3_index <<8 &0x4000), MMC3_reg[6] &prgAND | OR &~prgAND); - setprg8(0xA000, MMC3_reg[7] &prgAND | OR &~prgAND); - setprg8(0xC000 ^(MMC3_index <<8 &0x4000), 0xFE &prgAND | OR &~prgAND); - setprg8(0xE000, 0xFF &prgAND | OR &~prgAND); - setchr1(0x0000 ^(MMC3_index <<5 &0x1000),(MMC3_reg[0] &0xFE)&chrAND); - setchr1(0x0400 ^(MMC3_index <<5 &0x1000),(MMC3_reg[0] |0x01)&chrAND); - setchr1(0x0800 ^(MMC3_index <<5 &0x1000),(MMC3_reg[1] &0xFE)&chrAND); - setchr1(0x0C00 ^(MMC3_index <<5 &0x1000),(MMC3_reg[1] |0x01)&chrAND); - setchr1(0x1000 ^(MMC3_index <<5 &0x1000), MMC3_reg[2] &chrAND); - setchr1(0x1400 ^(MMC3_index <<5 &0x1000), MMC3_reg[3] &chrAND); - setchr1(0x1800 ^(MMC3_index <<5 &0x1000), MMC3_reg[4] &chrAND); - setchr1(0x1C00 ^(MMC3_index <<5 &0x1000), MMC3_reg[5] &chrAND); - - if (mapper &2) switch(MMC3_mirroring &3) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MMC3_reg[MMC3_lastReg] &0x80? MI_1: MI_0); break; - case 3: setmirror(MI_1); break; - } else - setmirror(MMC3_mirroring &1? MI_H: MI_V); -} - -static DECLFW(MMC3_writeReg) { - switch(A &0xE001) { - case 0x8000: MMC3_index =V; sync(); break; - case 0x8001: MMC3_reg[MMC3_index &7] =V; sync(); break; - case 0xA000: MMC3_mirroring =V; sync(); break; - case 0xA001: MMC3_wram =V; sync(); break; - case 0xC000: MMC3_reload =V; break; - case 0xC001: MMC3_count =0; break; - case 0xE000: MMC3_irq =0; X6502_IRQEnd(FCEU_IQEXT); break; - case 0xE001: MMC3_irq =1; break; - } -} - -static void MMC3_horizontalBlanking(void) { - MMC3_count =!MMC3_count? MMC3_reload: --MMC3_count; - if (!MMC3_count && MMC3_irq) X6502_IRQBegin(FCEU_IQEXT); -} - -static void FP_FASTAPASS(1) MMC3_ppuHook(uint32 A) { - A &=0x1FFF; - if (MMC3_index &0x80) A ^=0x1000; - if (A <0x1000) - MMC3_lastReg =A >>11; - else - MMC3_lastReg =(A >>10) -2; - if ((MMC3_mirroring &3) ==2) setmirror(MMC3_reg[MMC3_lastReg] &0x80? MI_1: MI_0); -} - -void MMC3_reset(uint8 clearRegs) { - sync =MMC3_sync; - GameHBIRQHook =MMC3_horizontalBlanking; - if (mapper &2) PPU_hook =MMC3_ppuHook; - prgAND =mapperFlags &8? (mapperFlags &4? (mapperFlags &2? (misc2 &2? 0x07: 0x0F): 0x1F): 0x3F): 0x7F; - SetWriteHandler(0x8000, 0xFFFF, MMC3_writeReg); - MMC3_mirroring =1; /* "Legendary Games of NES' 509-in-1"'s menu runs as MMC3 with H mirroring and expects that setting to stay when running a mapper 206 game such as Legend of Valkyrie. */ - sync(); -} - -#undef MMC3_reg -#undef MMC3_index -#undef MMC3_mirroring -#undef MMC3_wram -#undef MMC3_reload -#undef MMC3_count -#undef MMC3_irq -#undef MMC3_lastReg diff --git a/src/boards/468_nanjing.h b/src/boards/468_nanjing.h deleted file mode 100644 index fa5f555..0000000 --- a/src/boards/468_nanjing.h +++ /dev/null @@ -1,29 +0,0 @@ -#define NANJING_reg regByte - -static void NANJING_sync () { - setprg32(0x8000, NANJING_reg[2] <<4 &0x30 | NANJING_reg[0] &0x0F | (NANJING_reg[3] &4? 0x00: 0x03) | prgOR >>2); - setchr8(0); - setmirror(mapperFlags &4? MI_H: MI_V); -} - -static DECLFW(NANJING_writeReg) { - NANJING_reg[A >>8 &3] =V; - sync(); -} - -static void NANJING_horizontalBlanking(void) { - if (NANJING_reg[0] &0x80 && scanline <239) { /* Actual hardware cannot look at the current scanline number, but instead latches PA09 on PA13 rises. This does not seem possible with the current PPU emulation however. */ - setchr4(0x0000, scanline >=127? 1: 0); - setchr4(0x1000, scanline >=127? 1: 0); - } else - setchr8(0); -} - -void NANJING_reset(uint8 clearRegs) { - sync =NANJING_sync; - GameHBIRQHook = NANJING_horizontalBlanking; - SetWriteHandler(0x5000, 0x53FF, NANJING_writeReg); - sync(); -} - -#undef NANJING_reg diff --git a/src/boards/468_vrc1.h b/src/boards/468_vrc1.h deleted file mode 100644 index 087e65e..0000000 --- a/src/boards/468_vrc1.h +++ /dev/null @@ -1,25 +0,0 @@ -#define VRC1_reg regByte - -static void VRC1_sync () { - setprg8(0x8000, VRC1_reg[0] &prgAND | prgOR &~prgAND); - setprg8(0xA000, VRC1_reg[2] &prgAND | prgOR &~prgAND); - setprg8(0xC000, VRC1_reg[4] &prgAND | prgOR &~prgAND); - setprg8(0xE000, 0xFF &prgAND | prgOR &~prgAND); - setchr4(0x0000, VRC1_reg[6] &0x0F | VRC1_reg[1] <<3 &0x10); - setchr4(0x1000, VRC1_reg[7] &0x0F | VRC1_reg[1] <<2 &0x10); - setmirror(VRC1_reg[1] &1? MI_H: MI_V); -} - -static DECLFW(VRC1_writeReg) { - VRC1_reg[A >>12 &7] =V; - sync(); -} - -void VRC1_reset(uint8 clearRegs) { - sync =VRC1_sync; - prgAND =mapperFlags &8? (mapperFlags &4? (mapperFlags &2? 0x0F: 0x1F): 0x3F): 0x7F; - SetWriteHandler(0x8000, 0xFFFF, VRC1_writeReg); - sync(); -} - -#undef VRC1_reg diff --git a/src/boards/468_vrc24.h b/src/boards/468_vrc24.h deleted file mode 100644 index 9916147..0000000 --- a/src/boards/468_vrc24.h +++ /dev/null @@ -1,92 +0,0 @@ -#define VRC24_prg regByte -#define VRC24_mirroring regByte[2] -#define VRC24_misc regByte[3] -#define VRC24_chr regWord -#define VRCIRQ_latch regByte[13] -#define VRCIRQ_mode regByte[14] -#define VRCIRQ_count regByte[15] -#define VRCIRQ_cycles regWord[8] - -static void VRC24_sync() { - setprg8(0x8000 ^(VRC24_misc <<13 &0x4000), VRC24_prg[0] &prgAND | prgOR &~prgAND); - setprg8(0xA000, VRC24_prg[1] &prgAND | prgOR &~prgAND); - setprg8(0xC000 ^(VRC24_misc <<13 &0x4000), 0xFE &prgAND | prgOR &~prgAND); - setprg8(0xE000, 0xFF &prgAND | prgOR &~prgAND); - setchr1(0x0000, VRC24_chr[0]); - setchr1(0x0400, VRC24_chr[1]); - setchr1(0x0800, VRC24_chr[2]); - setchr1(0x0C00, VRC24_chr[3]); - setchr1(0x1000, VRC24_chr[4]); - setchr1(0x1400, VRC24_chr[5]); - setchr1(0x1800, VRC24_chr[6]); - setchr1(0x1C00, VRC24_chr[7]); - setmirror(VRC24_mirroring &3 ^(VRC24_mirroring &2? 0: 1)); -} - -static DECLFW(VRC24_writeReg) { - uint8 index; - A =A &0xF000 | (mapper &2? ((A &0xA? 1: 0) | (A &0x5? 2: 0)): ((A &0x5? 1: 0) | (A &0xA? 2: 0))); - switch (A &0xF000) { - case 0x8000: case 0xA000: - VRC24_prg[A >>13 &1] =V; - sync(); - break; - case 0x9000: - if (~A &2) - VRC24_mirroring =V & (mapper &1? 3: 1); - else - if (~A &1 && mapper &1) - VRC24_misc =V; - sync(); - break; - case 0xF000: - if (mapper &1) switch (A &3) { - case 0: VRCIRQ_latch =VRCIRQ_latch &0xF0 | V &0x0F; break; - case 1: VRCIRQ_latch =VRCIRQ_latch &0x0F | V <<4; break; - case 2: VRCIRQ_mode =V; - if (VRCIRQ_mode &0x02) { - VRCIRQ_count =VRCIRQ_latch; - VRCIRQ_cycles =341; - } - X6502_IRQEnd(FCEU_IQEXT); - break; - case 3: VRCIRQ_mode =VRCIRQ_mode &~0x02 | VRCIRQ_mode <<1 &0x02; - X6502_IRQEnd(FCEU_IQEXT); - break; - } - break; - default: - index =(A -0xB000) >>11 | A >>1 &1; - if (A &1) - VRC24_chr[index] =VRC24_chr[index] & 0x0F | V <<4; - else - VRC24_chr[index] =VRC24_chr[index] &~0x0F | V &0x0F; - sync(); - break; - } -} - -static void FP_FASTAPASS(1) VRCIRQ_cpuCycle(int a) { - while (a--) { - if (VRCIRQ_mode &0x02 && (VRCIRQ_mode &0x04 || (VRCIRQ_cycles -=3) <=0)) { - if (~VRCIRQ_mode &0x04) VRCIRQ_cycles +=341; - if (!++VRCIRQ_count) { - VRCIRQ_count =VRCIRQ_latch; - X6502_IRQBegin(FCEU_IQEXT); - } - } - } -} - -void VRC24_reset(uint8 clearRegs) { - sync =VRC24_sync; - prgAND =mapperFlags &2? 0x0F: 0x1F; - if (mapper &1) MapIRQHook =VRCIRQ_cpuCycle; - SetWriteHandler(0x8000, 0xFFFF, VRC24_writeReg); - sync(); -} - -#undef VRC24_prg -#undef VRC24_mirroring -#undef VRC24_misc -#undef VRC24_chr diff --git a/src/boards/468_vrc3.h b/src/boards/468_vrc3.h deleted file mode 100644 index 5553b23..0000000 --- a/src/boards/468_vrc3.h +++ /dev/null @@ -1,63 +0,0 @@ -#define VRC3_prg regByte[0] -#define VRC3_latch regWord[0] -#define VRC3_mode regByte[1] -#define VRC3_count regWord[1] - -static void VRC3_sync() { - int AND =prgAND >>1; - int OR =prgOR >>1; - setprg16(0x8000, VRC3_prg &AND | OR &~AND); - setprg16(0xC000, AND | OR &~AND); - setchr8(0); - setmirror(mapperFlags &4? MI_H: MI_V); -} - -static DECLFW(VRC3_writeReg) { - int shift; - switch(A &0xF000) { - case 0x8000: case 0x9000: case 0xA000: case 0xB000: - V &=0xF; - shift =A >>10 &0xC; - VRC3_latch =VRC3_latch &~(0xF <>1; - int OR =prgOR >>1; - setprg16(0x8000, VRC6_prg16 & AND | OR & ~AND); - setprg8(0xC000, VRC6_prg8 &prgAND | prgOR &~prgAND); - setprg8(0xE000, prgAND | prgOR &~prgAND); - setchr1(0x0000, VRC6_chr[0]); - setchr1(0x0400, VRC6_chr[1]); - setchr1(0x0800, VRC6_chr[2]); - setchr1(0x0C00, VRC6_chr[3]); - setchr1(0x1000, VRC6_chr[4]); - setchr1(0x1400, VRC6_chr[5]); - setchr1(0x1800, VRC6_chr[6]); - setchr1(0x1C00, VRC6_chr[7]); - setmirror((VRC6_misc &0xC ^(VRC6_misc &0x8? 0: 0x4)) >>2); -} - -static DECLFW(VRC6_writeReg) { - uint8 index; - switch (A &0xF003) { - case 0x8000: case 0x8001: case 0x8002: case 0x8003: - VRC6_prg16 =V; - sync(); - break; - case 0xB003: - VRC6_misc =V; - sync(); - break; - case 0xC000: case 0xC001: case 0xC002: case 0xC003: - VRC6_prg8 =V; - sync(); - break; - case 0xD000: case 0xD001: case 0xD002: case 0xD003: case 0xE000: case 0xE001: case 0xE002: case 0xE003: - index =(A -0xD000) >>10 | A &3; - VRC6_chr[index] =V; - sync(); - break; - case 0xF000: - VRCIRQ_latch =V; - break; - case 0xF001: - VRCIRQ_mode =V; - if (VRCIRQ_mode &0x02) { - VRCIRQ_count =VRCIRQ_latch; - VRCIRQ_cycles =341; - } - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xF002: - VRCIRQ_mode =VRCIRQ_mode &~0x02 | VRCIRQ_mode <<1 &0x02; - X6502_IRQEnd(FCEU_IQEXT); - break; - } -} - -void VRC6_reset(uint8 clearRegs) { - sync =VRC6_sync; - prgAND =mapperFlags &2? 0x0F: 0x1F; - MapIRQHook =VRCIRQ_cpuCycle; - SetWriteHandler(0x8000, 0xFFFF, VRC6_writeReg); - sync(); -} - -#undef VRC6_chr -#undef VRC6_prg16 -#undef VRC6_prg8 -#undef VRC6_misc diff --git a/src/boards/468_vrc7.h b/src/boards/468_vrc7.h deleted file mode 100644 index 24e5938..0000000 --- a/src/boards/468_vrc7.h +++ /dev/null @@ -1,82 +0,0 @@ -#define VRC7_chr regByte -#define VRC7_prg0 regByte[8] -#define VRC7_prg1 regByte[9] -#define VRC7_prg2 regByte[10] -#define VRC7_misc regByte[11] - -static void VRC7_sync() { - setprg8(0x8000, VRC7_prg0 &prgAND | prgOR &~prgAND); - setprg8(0xA000, VRC7_prg1 &prgAND | prgOR &~prgAND); - setprg8(0xC000, VRC7_prg2 &prgAND | prgOR &~prgAND); - setprg8(0xE000, prgAND | prgOR &~prgAND); - setchr1(0x0000, VRC7_chr[0]); - setchr1(0x0400, VRC7_chr[1]); - setchr1(0x0800, VRC7_chr[2]); - setchr1(0x0C00, VRC7_chr[3]); - setchr1(0x1000, VRC7_chr[4]); - setchr1(0x1400, VRC7_chr[5]); - setchr1(0x1800, VRC7_chr[6]); - setchr1(0x1C00, VRC7_chr[7]); - setmirror(VRC7_misc &3 ^(VRC7_misc &2? 0: 1)); -} - -static DECLFW(VRC7_writeReg) { - uint8 index; - A =A &0xF000 | (A &0x18? 1: 0) | (A &0x20? 2: 0); - switch (A &0xF003) { - case 0x8000: - VRC7_prg0 =V; - sync(); - break; - case 0x8001: - VRC7_prg1 =V; - sync(); - break; - case 0x9000: - VRC7_prg2 =V; - sync(); - break; - case 0x9001: case 0x9002: - /* sound */ - break; - case 0xA000: case 0xA001: case 0xB000: case 0xB001: case 0xC000: case 0xC001: case 0xD000: case 0xD001: - index =(A -0xA000) >>11 | A &1; - VRC7_chr[index] =V; - sync(); - break; - case 0xE000: - VRC7_misc =V; - sync(); - break; - case 0xE001: - VRCIRQ_latch =V; - break; - case 0xF000: - VRCIRQ_mode =V; - if (VRCIRQ_mode &0x02) { - VRCIRQ_count =VRCIRQ_latch; - VRCIRQ_cycles =341; - } - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xF001: - VRCIRQ_mode =VRCIRQ_mode &~0x02 | VRCIRQ_mode <<1 &0x02; - X6502_IRQEnd(FCEU_IQEXT); - break; - } -} - -void VRC7_reset(uint8 clearRegs) { - sync =VRC7_sync; - prgAND =mapperFlags &8? (mapperFlags &4? (mapperFlags &2? 0x0F: 0x1F): 0x3F): 0x7F; - MapIRQHook =VRCIRQ_cpuCycle; - SetWriteHandler(0x8000, 0xFFFF, VRC7_writeReg); - sync(); -} - -#undef VRC7_chr -#undef VRC7_prg0 -#undef VRC7_prg1 -#undef VRC7_prg2 -#undef VRC7_misc - diff --git a/src/boards/asic_fme7.c b/src/boards/asic_fme7.c new file mode 100644 index 0000000..124ec5e --- /dev/null +++ b/src/boards/asic_fme7.c @@ -0,0 +1,134 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2025 NewRisingSun + * + * 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 + */ + +#include "mapinc.h" +#include "asic_FME7.h" +#include "wram.h" + +static void (*FME7_cbSync)(); +static uint8 FME7_index; +static uint8 FME7_reg[16]; + +static SFORMAT FME7_stateRegs[] = { + { &FME7_index, 1, "FM7I" }, + { FME7_reg, 16, "FM7R" }, + { 0 } +}; + +void FME7_syncWRAM (int OR) { + if (PRGsize[0x10] && FME7_reg[8] &0x40) setprg8r(0x10, 0x6000, FME7_reg[8] | OR); +} + +void FME7_syncPRG (int AND, int OR) { + if (~FME7_reg[8] &0x40) setprg8(0x6000, FME7_reg[8] &AND | OR); + setprg8(0x8000, FME7_reg[ 9] &AND | OR); + setprg8(0xA000, FME7_reg[10] &AND | OR); + setprg8(0xC000, FME7_reg[11] &AND | OR); + setprg8(0xE000, 0xFF &AND | OR); +} + +void FME7_syncCHR (int AND, int OR) { + setchr1(0x0000, FME7_reg[0] &AND | OR); + setchr1(0x0400, FME7_reg[1] &AND | OR); + setchr1(0x0800, FME7_reg[2] &AND | OR); + setchr1(0x0C00, FME7_reg[3] &AND | OR); + setchr1(0x1000, FME7_reg[4] &AND | OR); + setchr1(0x1400, FME7_reg[5] &AND | OR); + setchr1(0x1800, FME7_reg[6] &AND | OR); + setchr1(0x1C00, FME7_reg[7] &AND | OR); +} + +void FME7_syncMirror () { + setmirror(FME7_reg[12] &2? (FME7_reg[12] &1? MI_1: MI_0): FME7_reg[12] &1? MI_H: MI_V); +} + +DECLFR(FME7_readWRAM) { + return ~FME7_reg[8] &0x40 || FME7_reg[8] &0x80? CartBR(A): A >>8; +} + +DECLFW(FME7_writeWRAM) { + if (FME7_reg[8] &0x80) CartBW(A, V); +} + +DECLFW(FME7_writeReg) { + if (A &0x2000) { + FME7_reg[FME7_index &0xF] = V; + if ((FME7_index &0xF) == 13) X6502_IRQEnd(FCEU_IQEXT); + FME7_cbSync(); + } else + FME7_index = V; +} + +void FP_FASTAPASS(1) FME7_cpuCycle (int a) { + while (a--) { + int16_t counter = FME7_reg[14] | FME7_reg[15] <<8; + if (FME7_reg[13] &0x80 && !--counter && FME7_reg[13] &0x01) X6502_IRQBegin(FCEU_IQEXT); + FME7_reg[14] = counter &0xFF; + FME7_reg[15] = counter >>8; + } +} + +static void FME7_clear () { + int i; + for (i = 0; i < 16; i++) FME7_reg[i] = 0; + FME7_cbSync(); +} + +static void FME7_setHandlers () { + SetReadHandler(0x6000, 0x7FFF, FME7_readWRAM); + SetWriteHandler(0x6000, 0x7FFF, FME7_writeWRAM); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xBFFF, FME7_writeReg); + MapIRQHook = FME7_cpuCycle; +} + +static void FME7_configure (void (*sync)()) { + FME7_cbSync = sync; +} + +void FME7_activate (uint8 clear, void (*sync)()) { + FME7_configure(sync); + FME7_setHandlers(); + if (clear) + FME7_clear(); + else + FME7_cbSync(); +} + +void FME7_addExState () { + AddExState(FME7_stateRegs, ~0, 0, 0); +} + +void FME7_restore (int version) { + FME7_cbSync(); +} + +void FME7_power () { + FME7_setHandlers(); + FME7_clear(); +} + +void FME7_init (CartInfo *info, void (*sync)()) { + FME7_addExState(); + FME7_configure(sync); + info->Power = FME7_power; + info->Reset = FME7_cbSync; + GameStateRestore = FME7_restore; +} diff --git a/src/boards/asic_fme7.h b/src/boards/asic_fme7.h new file mode 100644 index 0000000..1528e9f --- /dev/null +++ b/src/boards/asic_fme7.h @@ -0,0 +1,38 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2025 NewRisingSun + * + * 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 + */ + +#ifndef _ASIC_FME7_H +#define _ASIC_FME7_H + +void FME7_syncWRAM (int); +void FME7_syncPRG (int, int); +void FME7_syncCHR (int, int); +void FME7_syncMirror (); +DECLFR(FME7_readWRAM); +DECLFW(MMC3_writeWRAM); +DECLFW(FME7_writeReg); +void FP_FASTAPASS(1) FME7_cpuCycle (int); +void FME7_activate (uint8, void (*)()); +void FME7_addExState (); +void FME7_restore (int); +void FME7_power (); +void FME7_init (CartInfo *, void (*)()); + +#endif \ No newline at end of file diff --git a/src/boards/asic_mmc2.c b/src/boards/asic_mmc2.c deleted file mode 100644 index 52f494f..0000000 --- a/src/boards/asic_mmc2.c +++ /dev/null @@ -1,108 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2025 NewRisingSun - * - * 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 - */ - -#include "mapinc.h" -#include "asic_mmc2.h" - -static void (*MMC2_cbSync)(); -static uint8 MMC2_reg[6]; -static uint8 MMC2_latch[2]; - -static SFORMAT MMC2_state[] = { - { MMC2_reg, 6, "MC2R" }, - { MMC2_latch, 2, "MC2S" }, - { 0 } -}; - -static void (*MMC2_cbSync)(); - -void MMC2_syncPRG (int AND, int OR) { - setprg8(0x8000, MMC2_reg[0] &AND |OR); - setprg8(0xA000, 0xD &AND |OR); - setprg8(0xC000, 0xE &AND |OR); - setprg8(0xE000, 0xF &AND |OR); -} - -void MMC2_syncCHR (int AND, int OR) { - setchr4(0x0000, MMC2_reg[1 +MMC2_latch[0]] &AND |OR); - setchr4(0x1000, MMC2_reg[3 +MMC2_latch[1]] &AND |OR); -} - -void MMC2_syncMirror () { - setmirror(MMC2_reg[5] &1? MI_H: MI_V); -} - -static void FP_FASTAPASS(1) MMC2_trapPPUAddressChange (uint32 A) { - if ((A &0x2FF0) == 0xFD0 || (A &0x2FF0) == 0xFE0) { - MMC2_latch[A >>12 &1] = A >>5 &1; - MMC2_cbSync(); - } -} - -DECLFW(MMC2_write) { - MMC2_reg[(A >>12) -0xA] = V; - MMC2_cbSync(); -} - -static void MMC2_clear () { - MMC2_reg[0] = 0; MMC2_reg[1] = 0; MMC2_reg[2] = 2; MMC2_reg[3] = 0; MMC2_reg[4] = 0; MMC2_reg[5] = 0; - MMC2_latch[0] = 0; MMC2_latch[1] = 0; - MMC2_cbSync(); -} - -static void MMC2_setHandlers() { - SetReadHandler (0x8000, 0xFFFF, CartBR); - SetWriteHandler(0xA000, 0xFFFF, MMC2_write); - PPU_hook = MMC2_trapPPUAddressChange; -} - -static void MMC2_configure (void (*sync)()) { - MMC2_cbSync = sync; -} - -void MMC2_activate (uint8 clear, void (*sync)()) { - MMC2_configure(sync); - MMC2_setHandlers(); - if (clear) - MMC2_clear(); - else - MMC2_cbSync(); -} - -void MMC2_addExState () { - AddExState(MMC2_state, ~0, 0, 0); -} - -void MMC2_restore (int version) { - MMC2_cbSync(); -} - -void MMC2_power () { - MMC2_setHandlers(); - MMC2_clear(); -} - -void MMC2_init (CartInfo *info, void (*sync)()) { - MMC2_addExState(); - MMC2_configure(sync); - info->Power = MMC2_power; - info->Reset = MMC2_cbSync; - GameStateRestore = MMC2_restore; -} diff --git a/src/boards/asic_mmc2and4.c b/src/boards/asic_mmc2and4.c new file mode 100644 index 0000000..9be02c3 --- /dev/null +++ b/src/boards/asic_mmc2and4.c @@ -0,0 +1,117 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2025 NewRisingSun + * + * 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 + */ + +#include "mapinc.h" +#include "asic_mmc2and4.h" + +static void (*MMC24_cbSync)(); +static uint8 MMC24_reg[6]; +static uint8 MMC24_latch[2]; + +static SFORMAT MMC24_state[] = { + { MMC24_reg, 6, "MC2R" }, + { MMC24_latch, 2, "MC2S" }, + { 0 } +}; + +static void (*MMC24_cbSync)(); + +void MMC24_syncWRAM (int OR) { + if (PRGsize[0x10]) setprg8r(0x10, 0x6000, OR); +} + +void MMC2_syncPRG (int AND, int OR) { + setprg8(0x8000, MMC24_reg[0] &AND |OR); + setprg8(0xA000, 0xFD &AND |OR); + setprg8(0xC000, 0xFE &AND |OR); + setprg8(0xE000, 0xFF &AND |OR); +} + +void MMC4_syncPRG (int AND, int OR) { + setprg16(0x8000, MMC24_reg[0] &AND |OR); + setprg16(0xC000, 0xFF &AND |OR); +} + +void MMC24_syncCHR (int AND, int OR) { + setchr4(0x0000, MMC24_reg[1 +MMC24_latch[0]] &AND |OR); + setchr4(0x1000, MMC24_reg[3 +MMC24_latch[1]] &AND |OR); +} + +void MMC24_syncMirror () { + setmirror(MMC24_reg[5] &1? MI_H: MI_V); +} + +static void FP_FASTAPASS(1) MMC24_trapPPUAddressChange (uint32 A) { + if ((A &0x2FF0) == 0xFD0 || (A &0x2FF0) == 0xFE0) { + MMC24_latch[A >>12 &1] = A >>5 &1; + MMC24_cbSync(); + } +} + +DECLFW(MMC24_write) { + MMC24_reg[(A >>12) -0xA] = V; + MMC24_cbSync(); +} + +static void MMC24_clear () { + MMC24_reg[0] = 0; MMC24_reg[1] = 0; MMC24_reg[2] = 2; MMC24_reg[3] = 0; MMC24_reg[4] = 0; MMC24_reg[5] = 0; + MMC24_latch[0] = 0; MMC24_latch[1] = 0; + MMC24_cbSync(); +} + +static void MMC24_setHandlers() { + SetReadHandler (0x8000, 0xFFFF, CartBR); + SetWriteHandler(0xA000, 0xFFFF, MMC24_write); + PPU_hook = MMC24_trapPPUAddressChange; +} + +static void MMC24_configure (void (*sync)()) { + MMC24_cbSync = sync; +} + +void MMC24_activate (uint8 clear, void (*sync)()) { + MMC24_configure(sync); + MMC24_setHandlers(); + if (clear) + MMC24_clear(); + else + MMC24_cbSync(); +} + +void MMC24_addExState () { + AddExState(MMC24_state, ~0, 0, 0); +} + +void MMC24_restore (int version) { + MMC24_cbSync(); +} + +void MMC24_power () { + MMC24_setHandlers(); + MMC24_clear(); +} + +void MMC24_init (CartInfo *info, void (*sync)()) { + MMC24_addExState(); + MMC24_configure(sync); + info->Power = MMC24_power; + info->Reset = MMC24_cbSync; + GameStateRestore = MMC24_restore; +} diff --git a/src/boards/asic_mmc2.h b/src/boards/asic_mmc2and4.h similarity index 71% rename from src/boards/asic_mmc2.h rename to src/boards/asic_mmc2and4.h index 09d9036..176890c 100644 --- a/src/boards/asic_mmc2.h +++ b/src/boards/asic_mmc2and4.h @@ -18,17 +18,19 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _ASIC_MMC2_H -#define _ASIC_MMC2_H +#ifndef _ASIC_MMC2AND4_H +#define _ASIC_MMC2AND4_H +void MMC24_syncWRAM (int); void MMC2_syncPRG (int, int); -void MMC2_syncCHR (int, int); -void MMC2_syncMirror (); -DECLFW (MMC2_write); -void MMC2_power (); -void MMC2_restore (int); -void MMC2_addExState (); -void MMC2_activate (uint8, void (*)()); -void MMC2_init (CartInfo *, void (*)()); +void MMC4_syncPRG (int, int); +void MMC24_syncCHR (int, int); +void MMC24_syncMirror (); +DECLFW (MMC24_write); +void MMC24_power (); +void MMC24_restore (int); +void MMC24_addExState (); +void MMC24_activate (uint8, void (*)()); +void MMC24_init (CartInfo *, void (*)()); #endif diff --git a/src/boards/asic_mmc3.c b/src/boards/asic_mmc3.c index af018a6..fea628a 100644 --- a/src/boards/asic_mmc3.c +++ b/src/boards/asic_mmc3.c @@ -62,6 +62,10 @@ int MMC3_getCHRBank (uint8 bank) { return bank &4? MMC3_reg[bank -2]: MMC3_reg[bank >>1] &~1 | bank &1; } +int MMC3_getMirroring (void) { + return MMC3_mirroring; +} + DECLFR(MMC3_readWRAM) { if (MMC3_wramControl &0x80 || MMC3_type == MMC3_TYPE_AX5202P || MMC3_type == MMC3_TYPE_MMC6) return MMC3_cbReadWRAM? MMC3_cbReadWRAM(A): CartBR(A); diff --git a/src/boards/asic_mmc3.h b/src/boards/asic_mmc3.h index 448f1ab..773d4f0 100644 --- a/src/boards/asic_mmc3.h +++ b/src/boards/asic_mmc3.h @@ -30,6 +30,7 @@ void MMC3_syncWRAM (int); int MMC3_getPRGBank (uint8); int MMC3_getCHRBank (uint8); +int MMC3_getMirroring (void); void MMC3_syncPRG (int, int); void MMC3_syncCHR (int, int); void MMC3_syncMirror (); diff --git a/src/boards/asic_vrc7.h b/src/boards/asic_vrc7.h index a547cf5..8320468 100644 --- a/src/boards/asic_vrc7.h +++ b/src/boards/asic_vrc7.h @@ -25,9 +25,6 @@ void VRC7_syncWRAM (int); void VRC7_syncPRG (int, int); void VRC7_syncCHR (int, int); void VRC7_syncMirror (); -int VRC7_getPRGBank (uint8); -int VRC7_getCHRBank (uint8); -int VRC7_getNTBank (uint8); DECLFR(VRC7_readWRAM); DECLFW(MMC3_writeWRAM); DECLFW(VRC7_writeReg);