1
2
3
4
5
6
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
|
/*****************************************************************************************
NES MMC Emulation
MESS source file to handle various Multi-Memory Controllers (aka Mappers) used by NES carts.
Many information about the mappers below come from the wonderful doc written by Disch.
Current info (when used) are based on v0.6.1 of his docs.
You can find the latest version of the doc at http://www.romhacking.net/docs/362/
Missing components:
* Currently, we are not emulating 4-screen mirroring (only 3 games use it)
* We need a better way to implement CPU cycle based IRQ. Currently we update their counter once every scanline
but, with this approach, every time 114 clocks have passed and for certain games it is too much!
* We need to emulate additional sound hardware in mappers 019, 024, 026, 069, 085 (and possibly other ones)
* We need to emulate EEPROM in mapper 016 and 159
* Barcode World (mapper 069) and Datach games (mapper 157) need Barcode Reader emulation
Notice that for mapper 157, the barcode reader enters in the irq, so glitches may be related to this!
* Karaoke Studio (mapper 188) misses input devices
Known issues on specific mappers:
* 000 F1 Race requires more precise PPU timing. It currently has plenty of 1-line glitches.
* 001 Yoshi flashes in-game. Back to the Future have heavily corrupted graphics (since forever).
* 001 SOROM boards do not properly handle the two WRAM/Battery banks
* 002, 003, 094, 097, 152 Bus conflict?
* 003 Firehouse Rescue has flashing graphics
* 004 Mendel Palace has never worked properly
* 004 Ninja Gaiden 2 has flashing bg graphics in the second level
* 005 has issues (see e.g. Just Breed or Metal Slader Glory), RAM banking needs hardware flags to determine size
* 007 Marble Madness has small graphics corruptions
* 014 in-game graphics is glitched
* 015 Shanghai Tycoon has corrupted graphics
* 033 has still some graphics problem (e.g. missing text in Akira)
* 034 Impossible Mission II does not show graphics
* 038 seems to miss inputs. separate reads?
* 042 Ai Senshi Nicol has broken graphics (our Mapper 42 implementation does not handle CHR banks)
* 048 Don Doko Don 2 freezes when you reach the first boss
* 051 only half of the games work
* 064 has many IRQ problems (due to the way we implement CPU based IRQ) - see Skull & Crossbones.
Klax has problems as well (even if it uses scanline based IRQ, according to Disch's docs).
* 067 some 1-line glitches that cannot be solved without a better implementation for cycle-based IRQs
* 071 Fire Hawk is flashing all the times.
* 072, 086, 092 lack samples support (maybe others as well)
* 073 16 bit IRQ mode is not implemented
* 077 Requires 4-screen mirroring. Currently, it is very glitchy
* 083 has serious glitches
* 088 Quinty has never worked properly
* 096 is preliminary (no correct chr switch in connection to PPU)
* 104 Not all the games work
* 107 Are the scrolling glitches (check status bar) correct? NEStopia behaves similarly
* 112 Master Shooter is not working and misses some graphics
* 117 In-game glitches
* 119 Pin Bot has glitches when the ball is in the upper half of the screen
* 133 Qi Wang starts with corrupted graphics (ingame seems better)
* 143 are Dancing Block borders (in the intro) correct?
* 158 In addition to IRQ problems (same as 64), mirroring was just a guess (wrong?). info needed!
* 164 preliminary - no sprites?
* 176 has some graphics problem
* 178 Fan Kong Jin Ying is not working (but not even in NEStopia)
* 180 Crazy Climber controller?
* 187, 198, 208, 215 have some PRG banking issues - preliminary!
* 188 needs mic input (reads from 0x6000-0x7fff)
* 197 Super Fighter 3 has some glitch in-game (maybe mirroring?)
* 222 is only preliminar (wrong IRQ, mirroring or CHR banking?)
* 225 115-in-1 has glitches in the menu (games seem fine)
* 229 is preliminary
* 230 not working yet (needs a value to flip at reset)
* 232 has graphics glitches
* 241 Commandos is not working (but not even in NEStopia)
* 242 In Dragon Quest VIII graphics of the main character is not drawn (it seems similar to Shanghai Tycoon [map15]
because in place of the missing graphics we get glitches in the left border)
* 249 only half of the games work (and Du Bao Ying Hao seems to suffer the same problem as DQ8 and Shanghai Tycoon)
* 255 does not really select game (same in NEStopia apparently)
A few Mappers suffer of hardware conflict: original dumpers have used the same mapper number for more than
a kind of boards. In these cases (and only in these cases) we exploit nes.hsi to set up accordingly
emulation. Games which requires this hack are the following:
* 032 - Major League needs hardwired mirroring (missing windows and glitched field in top view, otherwise)
* 034 - Impossible Mission II is not like BxROM games (it writes to 0x7ffd-0x7fff, instead of 0x8000). It is still
unplayable though (see above)
* 071 - Fire Hawk is different from other Camerica games (no hardwired mirroring). Without crc_hack no helicopter graphics
* 078 - Cosmo Carrier needs a different mirroring than Holy Diver
* 113 - HES 6-in-1 requires mirroring (check Bookyman playfield), while other games break with this (check AV Soccer)
* 153 - Famicom Jump II uses a different board (or the same in a very different way)
* 242 - DQ8 has no mirroring (missing graphics is due to other reasons though)
crc_hacks have been added also to handle a few wiring settings which would require submappers:
* CHR protection pins for mapper 185
* VRC-2, VRC-4 and VRC-6 line wiring
Known issues on specific UNIF boards:
* BMC-GS2004 is not working
* BMC-GS2013 is not working
* BMC-WS some games have corrupted graphics (e.g. Galaxian)
* UNL-8237 is not working
* UNL-KOF97 is not working
Details to investigate:
* 034 writes to 0x8000-0xffff should not be used for NINA-001 and BNROM, only unlicensed BxROM...
* 144 we ignore writes to 0x8000 while NEStopia does not. is it a problem?
* 240 we do not map writes to 0x4020-0x40ff. is this a problem?
* some other emus uses mapper 210 for mapper 019 games without additional sound hardware and mirroring capabilities
(in 210 mirroring is hardwired). However, simply initializing mirroring to Vertical in 019 seems to fix all glitches
in 210 games, so there seems to be no reason to have this duplicate mapper
Some mappers copy PRG rom in SRAM region. Below is a list of those which does it (in MESS) to further
investigate if we are supporting them in the right way (e.g. do any of the following have conflicts with SRAM?):
* 065 (Gimmick! breaks badly without it)
* 040, 042, 050
Remember that the MMC # does not equal the mapper #. In particular, Mapper 4 is
in fact MMC3, Mapper 9 is MMC2 and Mapper 10 is MMC4. Makes perfect sense, right?
TODO:
- add more info
- add missing mappers
****************************************************************************************/
#include "emu.h"
#include "cpu/m6502/m6502.h"
#include "video/ppu2c0x.h"
#include "includes/nes.h"
#include "includes/nes_mmc.h"
#include "sound/nes_apu.h"
#ifdef MAME_DEBUG
#define VERBOSE 1
#else
#define VERBOSE 0
#endif
#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
#define LOG_FDS(x) do { if (VERBOSE) logerror x; } while (0)
static void ffe_irq( device_t *device, int scanline, int vblank, int blanked );
/*************************************************************
Base emulation (see drivers/nes.c):
memory 0x0000-0x1fff RAM
0x2000-0x3fff PPU
0x4000-0x4017 APU
0x4018-0x5fff Expansion Area
0x6000-0x7fff PRG RAM
0x8000-0xffff PRG ROM
nes_chr_r/w take care of RAM, nes_nt_r/w take care of PPU.
for mapper specific emulation, we generically setup the
following handlers:
- nes_low_mapper_r/w take care of accesses to 0x4100-0x5fff
(calling state->m_mmc_write_low/state->m_mmc_read_low)
- state->m_mmc_write/read_mid take care of 0x6000-0x7fff
- state->m_mmc_write/read take care of access to 0x8000-0xffff
(most mappers only writes in this area)
some mappers may access 0x4018-0x4100: this must be taken
care separately in init_nes_core
*************************************************************/
WRITE8_MEMBER(nes_state::nes_chr_w)
{
int bank = offset >> 10;
if (m_chr_map[bank].source == CHRRAM)
{
m_chr_map[bank].access[offset & 0x3ff] = data;
}
}
READ8_MEMBER(nes_state::nes_chr_r)
{
int bank = offset >> 10;
// a few CNROM boards contained copy protection schemes through
// suitably configured diodes, so that subsequent CHR reads can
// give actual VROM content or open bus values.
// For most boards, chr_open_bus remains always zero.
if (m_chr_open_bus)
return 0xff;
return m_chr_map[bank].access[offset & 0x3ff];
}
WRITE8_MEMBER(nes_state::nes_nt_w)
{
int page = ((offset & 0xc00) >> 10);
if (m_nt_page[page].writable == 0)
return;
m_nt_page[page].access[offset & 0x3ff] = data;
}
READ8_MEMBER(nes_state::nes_nt_r)
{
int page = ((offset & 0xc00) >> 10);
if (m_nt_page[page].source == MMC5FILL)
{
if ((offset & 0x3ff) >= 0x3c0)
return m_MMC5_floodattr;
return m_MMC5_floodtile;
}
return m_nt_page[page].access[offset & 0x3ff];
}
WRITE8_MEMBER(nes_state::nes_low_mapper_w)
{
if (!m_mmc_write_low.isnull())
(m_mmc_write_low)(space, offset, data, mem_mask);
else
logerror("Unimplemented LOW mapper write, offset: %04x, data: %02x\n", offset + 0x4100, data);
}
READ8_MEMBER(nes_state::nes_low_mapper_r)
{
if (!m_mmc_read_low.isnull())
return (m_mmc_read_low)(space, offset, mem_mask);
else
logerror("Unimplemented LOW mapper read, offset: %04x\n", offset + 0x4100);
return 0;
}
/*************************************************************
Helpers to handle MMC
*************************************************************/
void nes_carts_state::wram_bank(int bank, int source)
{
nes_state *state = machine().driver_data<nes_state>();
assert(m_battery || m_prg_ram);
if (source == NES_BATTERY)
{
bank &= (m_battery_size / 0x2000) - 1;
m_prg_bank[4] = m_battery_bank5_start + bank;
}
else
{
bank &= (m_wram_size / 0x2000) - 1;
m_prg_bank[4] = m_prgram_bank5_start + bank;
}
state->update_prg_banks(4, 4);
}
INLINE void prg_bank_refresh( running_machine &machine )
{
nes_state *state = machine.driver_data<nes_state>();
state->update_prg_banks(0, 3);
}
/* PRG ROM in 8K, 16K or 32K blocks */
void nes_carts_state::prg32(int bank)
{
/* if there is only 16k PRG, return */
if (!(m_prg_chunks >> 1))
return;
/* assumes that bank references a 32k chunk */
bank &= ((m_prg_chunks >> 1) - 1);
m_prg_bank[0] = bank * 4 + 0;
m_prg_bank[1] = bank * 4 + 1;
m_prg_bank[2] = bank * 4 + 2;
m_prg_bank[3] = bank * 4 + 3;
prg_bank_refresh(machine());
}
void nes_carts_state::prg16_89ab(int bank)
{
/* assumes that bank references a 16k chunk */
bank &= (m_prg_chunks - 1);
m_prg_bank[0] = bank * 2 + 0;
m_prg_bank[1] = bank * 2 + 1;
prg_bank_refresh(machine());
}
void nes_carts_state::prg16_cdef(int bank)
{
/* assumes that bank references a 16k chunk */
bank &= (m_prg_chunks - 1);
m_prg_bank[2] = bank * 2 + 0;
m_prg_bank[3] = bank * 2 + 1;
prg_bank_refresh(machine());
}
void nes_carts_state::prg8_89(int bank)
{
/* assumes that bank references an 8k chunk */
bank &= ((m_prg_chunks << 1) - 1);
m_prg_bank[0] = bank;
prg_bank_refresh(machine());
}
void nes_carts_state::prg8_ab(int bank)
{
/* assumes that bank references an 8k chunk */
bank &= ((m_prg_chunks << 1) - 1);
m_prg_bank[1] = bank;
prg_bank_refresh(machine());
}
void nes_carts_state::prg8_cd(int bank)
{
/* assumes that bank references an 8k chunk */
bank &= ((m_prg_chunks << 1) - 1);
m_prg_bank[2] = bank;
prg_bank_refresh(machine());
}
void nes_carts_state::prg8_ef(int bank)
{
/* assumes that bank references an 8k chunk */
bank &= ((m_prg_chunks << 1) - 1);
m_prg_bank[3] = bank;
prg_bank_refresh(machine());
}
/* We define an additional helper to map PRG-ROM to 0x6000-0x7000 */
// TODO: are we implementing this correctly in the mappers which uses it? check!
void nes_carts_state::prg8_67(int bank)
{
/* assumes that bank references an 8k chunk */
bank &= ((m_prg_chunks << 1) - 1);
m_prg_bank[4] = bank;
membank("bank5")->set_entry(m_prg_bank[4]);
}
/* We also define an additional helper to map 8k PRG-ROM to one of the banks (passed as parameter) */
void nes_carts_state::prg8_x(int start, int bank)
{
assert(start < 4);
/* assumes that bank references an 8k chunk */
bank &= ((m_prg_chunks << 1) - 1);
m_prg_bank[start] = bank;
prg_bank_refresh(machine());
}
/* CHR ROM in 1K, 2K, 4K or 8K blocks */
// this can be probably removed later, but it is useful while testing xml and unf handling with VRAM & VROM
INLINE void chr_sanity_check( running_machine &machine, int source )
{
nes_state *state = machine.driver_data<nes_state>();
if (source == CHRRAM && state->m_vram == NULL)
fatalerror("CHRRAM bankswitch with no VRAM\n");
if (source == CHRROM && state->m_vrom == NULL)
fatalerror("CHRROM bankswitch with no VROM\n");
}
void nes_carts_state::chr8(int bank, int source)
{
chr_sanity_check(machine(), source);
if (source == CHRRAM)
{
bank &= (m_vram_chunks - 1);
for (int i = 0; i < 8; i++)
{
m_chr_map[i].source = source;
m_chr_map[i].origin = (bank * 0x2000) + (i * 0x400); // for save state uses!
m_chr_map[i].access = &m_vram[m_chr_map[i].origin];
}
}
else
{
bank &= (m_chr_chunks - 1);
for (int i = 0; i < 8; i++)
{
m_chr_map[i].source = source;
m_chr_map[i].origin = (bank * 0x2000) + (i * 0x400); // for save state uses!
m_chr_map[i].access = &m_vrom[m_chr_map[i].origin];
}
}
}
void nes_carts_state::chr4_x(int start, int bank, int source)
{
chr_sanity_check(machine(), source);
if (source == CHRRAM)
{
bank &= ((m_vram_chunks << 1) - 1);
for (int i = 0; i < 4; i++)
{
m_chr_map[i + start].source = source;
m_chr_map[i + start].origin = (bank * 0x1000) + (i * 0x400); // for save state uses!
m_chr_map[i + start].access = &m_vram[m_chr_map[i + start].origin];
}
}
else
{
bank &= ((m_chr_chunks << 1) - 1);
for (int i = 0; i < 4; i++)
{
m_chr_map[i + start].source = source;
m_chr_map[i + start].origin = (bank * 0x1000) + (i * 0x400); // for save state uses!
m_chr_map[i + start].access = &m_vrom[m_chr_map[i + start].origin];
}
}
}
void nes_carts_state::chr2_x(int start, int bank, int source)
{
chr_sanity_check(machine(), source);
if (source == CHRRAM)
{
bank &= ((m_vram_chunks << 2) - 1);
for (int i = 0; i < 2; i++)
{
m_chr_map[i + start].source = source;
m_chr_map[i + start].origin = (bank * 0x800) + (i * 0x400); // for save state uses!
m_chr_map[i + start].access = &m_vram[m_chr_map[i + start].origin];
}
}
else
{
bank &= ((m_chr_chunks << 2) - 1);
for (int i = 0; i < 2; i++)
{
m_chr_map[i + start].source = source;
m_chr_map[i + start].origin = (bank * 0x800) + (i * 0x400); // for save state uses!
m_chr_map[i + start].access = &m_vrom[m_chr_map[i + start].origin];
}
}
}
void nes_carts_state::chr1_x(int start, int bank, int source)
{
chr_sanity_check(machine(), source);
if (source == CHRRAM)
{
bank &= ((m_vram_chunks << 3) - 1);
m_chr_map[start].source = source;
m_chr_map[start].origin = (bank * 0x400); // for save state uses!
m_chr_map[start].access = &m_vram[m_chr_map[start].origin];
}
else
{
bank &= ((m_chr_chunks << 3) - 1);
m_chr_map[start].source = source;
m_chr_map[start].origin = (bank * 0x400); // for save state uses!
m_chr_map[start].access = &m_vrom[m_chr_map[start].origin];
}
}
/* NameTable paging and mirroring */
void nes_carts_state::set_nt_page(int page, int source, int bank, int writable)
{
UINT8* base_ptr;
switch (source)
{
case CART_NTRAM:
base_ptr = m_extended_ntram;
break;
case MMC5FILL:
base_ptr = NULL;
break;
case ROM:
base_ptr = m_vrom;
break;
case EXRAM:
base_ptr = m_mapper_ram;
break;
case CIRAM:
default:
base_ptr = m_ciram;
break;
}
page &= 3; /* mask down to the 4 logical pages */
m_nt_page[page].source = source;
if (base_ptr != NULL)
{
m_nt_page[page].origin = bank * 0x400;
m_nt_page[page].access = base_ptr + m_nt_page[page].origin;
}
m_nt_page[page].writable = writable;
}
void nes_carts_state::set_nt_mirroring(int mirroring)
{
/* setup our videomem handlers based on mirroring */
switch (mirroring)
{
case PPU_MIRROR_VERT:
set_nt_page(0, CIRAM, 0, 1);
set_nt_page(1, CIRAM, 1, 1);
set_nt_page(2, CIRAM, 0, 1);
set_nt_page(3, CIRAM, 1, 1);
break;
case PPU_MIRROR_HORZ:
set_nt_page(0, CIRAM, 0, 1);
set_nt_page(1, CIRAM, 0, 1);
set_nt_page(2, CIRAM, 1, 1);
set_nt_page(3, CIRAM, 1, 1);
break;
case PPU_MIRROR_HIGH:
set_nt_page(0, CIRAM, 1, 1);
set_nt_page(1, CIRAM, 1, 1);
set_nt_page(2, CIRAM, 1, 1);
set_nt_page(3, CIRAM, 1, 1);
break;
case PPU_MIRROR_LOW:
set_nt_page(0, CIRAM, 0, 1);
set_nt_page(1, CIRAM, 0, 1);
set_nt_page(2, CIRAM, 0, 1);
set_nt_page(3, CIRAM, 0, 1);
break;
case PPU_MIRROR_NONE:
case PPU_MIRROR_4SCREEN:
default:
/* external RAM needs to be used somehow. */
/* but as a default, we'll arbitrarily set vertical so as not to crash*/
/* mappers should use set_nt_page and assign which pages are which */
logerror("Mapper set 4-screen mirroring without supplying external nametable memory!\n");
set_nt_page(0, CIRAM, 0, 1);
set_nt_page(1, CIRAM, 0, 1);
set_nt_page(2, CIRAM, 1, 1);
set_nt_page(3, CIRAM, 1, 1);
break;
}
}
/* Other custom mirroring helpers are defined below: Waixing games use waixing_set_mirror (which swaps
MIRROR_HIGH and MIRROR_LOW compared to the above) and Sachen games use sachen_set_mirror (which has
a slightly different MIRROR_HIGH, with page 0 set to 0) */
/*************************************************************
Support for xml list
*************************************************************/
/* Include emulation of NES PCBs for softlist */
#include "machine/nes_pcb.c"
/*************************************************************
Support for .unf Files
*************************************************************/
/* Include emulation of UNIF Boards for .unf files */
#include "machine/nes_unif.c"
/*************************************************************
Support for .nes Files
*************************************************************/
/* Include emulation of iNES Mappers for .nes files */
#include "machine/nes_ines.c"
|