Skip to content

Commit 940c895

Browse files
authored
Merge pull request #767 from negativeExponent/add_m451_m471
Add mappers 451 and 471
2 parents 3f599cb + fb0b178 commit 940c895

File tree

8 files changed

+297
-2
lines changed

8 files changed

+297
-2
lines changed

src/CMakeLists.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,9 @@ set(SRC_CORE
447447
${CMAKE_CURRENT_SOURCE_DIR}/boards/34.cpp
448448
${CMAKE_CURRENT_SOURCE_DIR}/boards/354.cpp
449449
${CMAKE_CURRENT_SOURCE_DIR}/boards/413.cpp
450-
${CMAKE_CURRENT_SOURCE_DIR}/boards/36.cpp
450+
${CMAKE_CURRENT_SOURCE_DIR}/boards/471.cpp
451+
${CMAKE_CURRENT_SOURCE_DIR}/boards/451.cpp
452+
${CMAKE_CURRENT_SOURCE_DIR}/boards/36.cpp
451453
${CMAKE_CURRENT_SOURCE_DIR}/boards/3d-block.cpp
452454
${CMAKE_CURRENT_SOURCE_DIR}/boards/40.cpp
453455
${CMAKE_CURRENT_SOURCE_DIR}/boards/411120-c.cpp

src/boards/451.cpp

+216
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/* FCE Ultra - NES/Famicom Emulator
2+
*
3+
* Copyright notice for this file:
4+
* Copyright (C) 2024 negativeExponent
5+
*
6+
* This program is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 2 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19+
*/
20+
21+
/* NES 2.0 Mapper 451 is used for the homebrew game Haratyler HP/MP. It is
22+
* basically a homebrew TLROM-like circuit board that implements the MMC3
23+
* register's in an unusual fashion, and saves the high score to flash ROM */
24+
25+
#include "mapinc.h"
26+
#include "mmc3.h"
27+
#include "../ines.h"
28+
29+
const int ROM_CHIP = 0x00;
30+
const int CFI_CHIP = 0x10;
31+
const int FLASH_CHIP = 0x11;
32+
33+
const int FLASH_SECTOR_SIZE = 64 * 1024;
34+
const int magic_addr1 = 0x0555;
35+
const int magic_addr2 = 0x02AA;
36+
37+
static uint8 flash_state, flash_id_mode;
38+
static uint8 *flash_data;
39+
static uint16 flash_buffer_a[10];
40+
static uint8 flash_buffer_v[10];
41+
static uint8 flash_id[2];
42+
43+
static DECLFW(M451FlashWrite)
44+
{
45+
if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) {
46+
flash_buffer_a[flash_state] = (A & 0xFFF);
47+
flash_buffer_v[flash_state] = V;
48+
flash_state++;
49+
50+
// enter flash ID mode
51+
if ((flash_state == 2) &&
52+
(flash_buffer_a[0] == magic_addr1) && (flash_buffer_v[0] == 0xAA) &&
53+
(flash_buffer_a[1] == magic_addr2) && (flash_buffer_v[1] == 0x55) &&
54+
(flash_buffer_a[1] == magic_addr1) && (flash_buffer_v[1] == 0x90)) {
55+
flash_id_mode = 0;
56+
flash_state = 0;
57+
}
58+
59+
// erase sector
60+
if ((flash_state == 6) &&
61+
(flash_buffer_a[0] == magic_addr1) && (flash_buffer_v[0] == 0xAA) &&
62+
(flash_buffer_a[1] == magic_addr2) && (flash_buffer_v[1] == 0x55) &&
63+
(flash_buffer_a[2] == magic_addr1) && (flash_buffer_v[2] == 0x80) &&
64+
(flash_buffer_a[3] == magic_addr1) && (flash_buffer_v[3] == 0xAA) &&
65+
(flash_buffer_a[4] == magic_addr2) && (flash_buffer_v[4] == 0x55) &&
66+
(flash_buffer_v[5] == 0x30)) {
67+
int offset = &Page[A >> 11][A] - flash_data;
68+
int sector = offset / FLASH_SECTOR_SIZE;
69+
for (int i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++)
70+
flash_data[i % PRGsize[ROM_CHIP]] = 0xFF;
71+
FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE);
72+
}
73+
74+
// erase chip
75+
if ((flash_state == 6) &&
76+
(flash_buffer_a[0] == magic_addr1) && (flash_buffer_v[0] == 0xAA) &&
77+
(flash_buffer_a[1] == magic_addr2) && (flash_buffer_v[1] == 0x55) &&
78+
(flash_buffer_a[2] == magic_addr1) && (flash_buffer_v[2] == 0x80) &&
79+
(flash_buffer_a[3] == magic_addr1) && (flash_buffer_v[3] == 0xAA) &&
80+
(flash_buffer_a[4] == magic_addr2) && (flash_buffer_v[4] == 0x55) &&
81+
(flash_buffer_a[4] == magic_addr1) && (flash_buffer_v[4] == 0x10)) {
82+
memset(flash_data, 0xFF, PRGsize[ROM_CHIP]);
83+
FCEU_printf("Flash chip erased.\n");
84+
flash_state = 0;
85+
}
86+
87+
// write byte
88+
if ((flash_state == 4) &&
89+
(flash_buffer_a[0] == magic_addr1) && (flash_buffer_v[0] == 0xAA) &&
90+
(flash_buffer_a[1] == magic_addr2) && (flash_buffer_v[1] == 0x55) &&
91+
(flash_buffer_a[2] == magic_addr1) && (flash_buffer_v[2] == 0xA0)) {
92+
int offset = &Page[A >> 11][A] - flash_data;
93+
if (CartBR(A) != 0xFF) {
94+
FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset);
95+
}
96+
else {
97+
CartBW(A, V);
98+
}
99+
flash_state = 0;
100+
}
101+
}
102+
103+
// not a command
104+
if (((A & 0x00FF) != (magic_addr1 & 0x00FF)) && ((A & 0x00FF) != (magic_addr2 & 0x00FF))) {
105+
flash_state = 0;
106+
}
107+
108+
// reset
109+
if (V == 0xF0) {
110+
flash_state = 0;
111+
flash_id_mode = 0;
112+
}
113+
114+
FixMMC3PRG(MMC3_cmd);
115+
}
116+
117+
static void M451FixPRG(uint32 A, uint8 V) {
118+
setprg8r(FLASH_CHIP, 0x8000, 0);
119+
setprg8r(FLASH_CHIP, 0xA000, 0x10 | ((EXPREGS[0] << 2) & 0x08) | (EXPREGS[0] & 0x01));
120+
setprg8r(FLASH_CHIP, 0xC000, 0x20 | ((EXPREGS[0] << 2) & 0x08) | (EXPREGS[0] & 0x01));
121+
setprg8r(FLASH_CHIP, 0xE000, 0x30);
122+
}
123+
124+
static void M451FixCHR(uint32 A, uint8 V) {
125+
setchr8(EXPREGS[0] & 0x01);
126+
}
127+
128+
static DECLFR(M451Read) {
129+
if (flash_state == 0x90) {
130+
return flash_id[A & 1];
131+
}
132+
return CartBR(A);
133+
}
134+
135+
static DECLFW(M451Write) {
136+
M451FlashWrite(A, V);
137+
switch (A & 0xE000) {
138+
case 0xA000:
139+
MMC3_CMDWrite(0xA000, A & 0x01);
140+
break;
141+
case 0xC000:
142+
A &= 0xFF;
143+
MMC3_IRQWrite(0xC000, A - 1);
144+
MMC3_IRQWrite(0xC001, 0);
145+
MMC3_IRQWrite(0xE000 + ((A == 0xFF) ? 0x00 : 0x01), 0x00);
146+
break;
147+
case 0xE000:
148+
EXPREGS[0] = A & 0x03;
149+
FixMMC3PRG(MMC3_cmd);
150+
FixMMC3CHR(MMC3_cmd);
151+
break;
152+
}
153+
}
154+
155+
static void M451Power(void) {
156+
GenMMC3Power();
157+
SetReadHandler(0x8000, 0xFFFF, M451Read);
158+
SetWriteHandler(0x8000, 0xFFFF, M451Write);
159+
}
160+
161+
static void StateRestore(int version) {
162+
FixMMC3PRG(MMC3_cmd);
163+
FixMMC3CHR(MMC3_cmd);
164+
}
165+
166+
static void M451Close(void) {
167+
if(flash_data)
168+
FCEU_gfree(flash_data);
169+
flash_data = NULL;
170+
}
171+
172+
static void M451FlashReset(void)
173+
{
174+
if (flash_data)
175+
{
176+
size_t flash_size = PRGsize[ROM_CHIP];
177+
// Copy ROM to flash data
178+
for (size_t i = 0; i < flash_size; i++) {
179+
flash_data[i] = PRGptr[ROM_CHIP][i];
180+
}
181+
}
182+
}
183+
184+
void Mapper451_Init(CartInfo *info) {
185+
GenMMC3_Init(info, 512, 16, 0, 0);
186+
pwrap = M451FixPRG;
187+
cwrap = M451FixCHR;
188+
189+
info->Power = M451Power;
190+
info->Close = M451Close;
191+
GameStateRestore = StateRestore;
192+
193+
flash_state = 0;
194+
flash_id_mode = 0;
195+
info->battery = 1;
196+
197+
// Allocate memory for flash
198+
size_t flash_size = PRGsize[ROM_CHIP];
199+
flash_data = (uint8*)FCEU_gmalloc(flash_size);
200+
// Copy ROM to flash data
201+
for (size_t i = 0; i < flash_size; i++) {
202+
flash_data[i] = PRGptr[ROM_CHIP][i];
203+
}
204+
SetupCartPRGMapping(FLASH_CHIP, flash_data, flash_size, 1);
205+
info->addSaveGameBuf( flash_data, flash_size, M451FlashReset );
206+
207+
flash_id[0] = 0x37;
208+
flash_id[1] = 0x86;
209+
SetupCartPRGMapping(CFI_CHIP, flash_id, sizeof(flash_id), 0);
210+
211+
AddExState(flash_data, flash_size, 0, "FLSH");
212+
AddExState(&flash_state, sizeof(flash_state), 0, "FLST");
213+
AddExState(&flash_id_mode, sizeof(flash_id_mode), 0, "FLMD");
214+
AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA");
215+
AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV");
216+
}

src/boards/471.cpp

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/* FCEUmm - NES/Famicom Emulator
2+
*
3+
* Copyright notice for this file:
4+
* Copyright (C) 2024 negativeExponent
5+
*
6+
* This program is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 2 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19+
*/
20+
21+
/* NES 2.0 Mapper 471 denotes the Impact Soft IM1 circuit board, used for
22+
* Haratyler (without HG or MP) and Haraforce. It is basically INES Mapper 201
23+
* with the addition of a scanline IRQ.*/
24+
25+
#include "mapinc.h"
26+
27+
static uint32 latch;
28+
29+
static void Sync() {
30+
setprg32(0x8000, latch);
31+
setchr8(latch);
32+
}
33+
34+
static DECLFW(Write) {
35+
X6502_IRQEnd(FCEU_IQEXT);
36+
latch = A;
37+
Sync();
38+
}
39+
40+
static void Reset() {
41+
latch = 0;
42+
Sync();
43+
}
44+
45+
static void Power() {
46+
SetReadHandler(0x8000, 0xFFFF, CartBR);
47+
SetWriteHandler(0x8000, 0xFFFF, Write);
48+
Reset();
49+
}
50+
51+
static void StateRestore(int version) {
52+
Sync();
53+
}
54+
55+
static void HBHook() {
56+
X6502_IRQBegin(FCEU_IQEXT);
57+
}
58+
59+
void Mapper471_Init(CartInfo *info) {
60+
info->Power = Power;
61+
info->Reset = Reset;
62+
GameHBIRQHook = HBHook;
63+
GameStateRestore = StateRestore;
64+
AddExState(&latch, sizeof(latch), 0, "LATC");
65+
}
1.17 MB
Binary file not shown.

src/ines.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,8 @@ BMAPPINGLocal bmap[] = {
810810
{"Impact Soft MMC3 Flash Board", 406, Mapper406_Init },
811811
{"Super Russian Roulette", 413, Mapper413_Init },
812812
{"INX_007T_V01", 470, INX_007T_Init },
813+
{"Haratyler HP/MP", 451, Mapper451_Init },
814+
{"Impact Soft IM1", 471, Mapper471_Init },
813815

814816
{"KONAMI QTAi Board", 547, QTAi_Init },
815817

src/ines.h

+2
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,8 @@ void Mapper255_Init(CartInfo *);
281281
void Mapper354_Init(CartInfo *);
282282
void Mapper406_Init(CartInfo *);
283283
void Mapper413_Init(CartInfo *);
284+
void Mapper451_Init(CartInfo *);
285+
void Mapper471_Init(CartInfo *);
284286

285287
void INX_007T_Init(CartInfo* info);
286288
void GN45_Init(CartInfo *info); /* previously mapper 205 */

vc/vc14_fceux.vcxproj

+2
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,8 @@ xcopy /y /d "$(ProjectDir)\..\src\drivers\win\7z_64.dll" "$(OutDir)"</Command>
438438
<ClCompile Include="..\src\boards\34.cpp" />
439439
<ClCompile Include="..\src\boards\354.cpp" />
440440
<ClCompile Include="..\src\boards\413.cpp" />
441+
<ClCompile Include="..\src\boards\471.cpp" />
442+
<ClCompile Include="..\src\boards\451.cpp" />
441443
<ClCompile Include="..\src\boards\36.cpp" />
442444
<ClCompile Include="..\src\boards\3d-block.cpp" />
443445
<ClCompile Include="..\src\boards\40.cpp" />

vc/vc14_fceux.vcxproj.filters

+7-1
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,12 @@
11231123
<ClCompile Include="..\src\boards\413.cpp">
11241124
<Filter>boards</Filter>
11251125
</ClCompile>
1126+
<ClCompile Include="..\src\boards\471.cpp">
1127+
<Filter>boards</Filter>
1128+
</ClCompile>
1129+
<ClCompile Include="..\src\boards\451.cpp">
1130+
<Filter>boards</Filter>
1131+
</ClCompile>
11261132
<ClCompile Include="..\src\debugsymboltable.cpp" />
11271133
</ItemGroup>
11281134
<ItemGroup>
@@ -1976,4 +1982,4 @@
19761982
<ItemGroup>
19771983
<Image Include="..\src\drivers\win\res\bitmap21.bmp" />
19781984
</ItemGroup>
1979-
</Project>
1985+
</Project>

0 commit comments

Comments
 (0)