summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/machine/nes_nxrom.c
blob: c3012cb4e985fbeafbaaf82644ed544f340b8de1 (plain) (blame)
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
/***********************************************************************************************************


 NES/Famicom cartridge emulation for Nintendo xxROM PCBs

 Copyright MESS Team.
 Visit http://mamedev.org for licensing and usage restrictions.


 Here we emulate the following PCBs

 * Nintendo NROM [mapper 0]
 * Nintendo AxROM [mapper 7]
 * Nintendo BxROM [mapper 34]
 * Nintendo CNROM [mapper 3 & 185]
 * Nintendo CPROM [mapper 13]
 * Nintendo GxROM/MxROM [mapper 66]
 * Nintendo UxROM [mapper 2] + Crazy Climbers variant [mapper 180]
 * Nintendo UN1ROM [mapper 94]

 Known issues on specific mappers:

 * 000 F1 Race requires more precise PPU timing. It currently has plenty of 1-line glitches.
 * 003 Firehouse Rescue has flashing graphics (same PPU issue as Back to the Future 2 & 3?)
 * 007 Marble Madness has small graphics corruptions
 * 034 Titanic 1912 (pirate BxROM) has missing gfx (same PPU issue of many Waixing titles almost for sure)

 ***********************************************************************************************************/


#include "emu.h"
#include "machine/nes_nxrom.h"

#include "sound/samples.h"

#ifdef NES_PCB_DEBUG
#define VERBOSE 1
#else
#define VERBOSE 0
#endif

#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)


//-------------------------------------------------
//  constructor
//-------------------------------------------------

const device_type NES_NROM = &device_creator<nes_nrom_device>;
const device_type NES_FCBASIC = &device_creator<nes_fcbasic_device>;
const device_type NES_AXROM = &device_creator<nes_axrom_device>;
const device_type NES_BXROM = &device_creator<nes_bxrom_device>;
const device_type NES_CNROM = &device_creator<nes_cnrom_device>;
const device_type NES_CPROM = &device_creator<nes_cprom_device>;
const device_type NES_GXROM = &device_creator<nes_gxrom_device>;
const device_type NES_UXROM = &device_creator<nes_uxrom_device>;
const device_type NES_UXROM_CC = &device_creator<nes_uxrom_cc_device>;
const device_type NES_UN1ROM = &device_creator<nes_un1rom_device>;


nes_nrom_device::nes_nrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
					: device_t(mconfig, type, name, tag, owner, clock, shortname, source),
						device_nes_cart_interface( mconfig, *this )
{
}

nes_nrom_device::nes_nrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: device_t(mconfig, NES_NROM, "NES Cart NROM PCB", tag, owner, clock, "nes_nrom", __FILE__),
						device_nes_cart_interface( mconfig, *this )
{
}

nes_fcbasic_device::nes_fcbasic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: nes_nrom_device(mconfig, NES_FCBASIC, "NES Cart Famicom BASIC PCB", tag, owner, clock, "nes_fcbasic", __FILE__)
{
}

nes_axrom_device::nes_axrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: nes_nrom_device(mconfig, NES_AXROM, "NES Cart AxROM PCB", tag, owner, clock, "nes_axrom", __FILE__)
{
}

nes_bxrom_device::nes_bxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: nes_nrom_device(mconfig, NES_BXROM, "NES Cart BxROM PCB", tag, owner, clock, "nes_bxrom", __FILE__)
{
}

nes_cnrom_device::nes_cnrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
					: nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
{
}

nes_cnrom_device::nes_cnrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: nes_nrom_device(mconfig, NES_CNROM, "NES Cart CNROM PCB", tag, owner, clock, "nes_cnrom", __FILE__)
{
}

nes_cprom_device::nes_cprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: nes_nrom_device(mconfig, NES_CPROM, "NES Cart CPROM PCB", tag, owner, clock, "nes_cprom", __FILE__)
{
}

nes_gxrom_device::nes_gxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: nes_nrom_device(mconfig, NES_GXROM, "NES Cart GxROM PCB", tag, owner, clock, "nes_gxrom", __FILE__)
{
}

nes_uxrom_device::nes_uxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: nes_nrom_device(mconfig, NES_UXROM, "NES Cart UxROM PCB", tag, owner, clock, "nes_uxrom", __FILE__)
{
}

nes_uxrom_cc_device::nes_uxrom_cc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: nes_nrom_device(mconfig, NES_UXROM_CC, "NES Cart UNROM M5 PCB (Crazy Climber)", tag, owner, clock, "nes_uxrom_cc", __FILE__)
{
}

nes_un1rom_device::nes_un1rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
					: nes_nrom_device(mconfig, NES_UN1ROM, "NES Cart UN1ROM PCB", tag, owner, clock, "nes_un1rom", __FILE__)
{
}


void nes_nrom_device::common_start()
{
	// PRG
	save_item(NAME(m_prg_bank));

	// CHR
	save_item(NAME(m_chr_source));
	save_item(NAME(m_chr_src));
	save_item(NAME(m_chr_orig));

	// NT
	save_item(NAME(m_mirroring));
	save_item(NAME(m_nt_src));
	save_item(NAME(m_nt_orig));
	save_item(NAME(m_nt_writable));
}

void nes_nrom_device::pcb_reset()
{
	m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
	prg32(0);
	chr8(0, m_chr_source);
}

void nes_axrom_device::device_start()
{
	common_start();
}

void nes_axrom_device::pcb_reset()
{
	m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
	prg32(0);
	chr8(0, m_chr_source);

	set_nt_mirroring(PPU_MIRROR_LOW);
}

void nes_bxrom_device::device_start()
{
	common_start();
}

void nes_bxrom_device::pcb_reset()
{
	m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
	prg32(0);
	chr8(0, m_chr_source);
}

void nes_cnrom_device::device_start()
{
	common_start();
	save_item(NAME(m_chr_open_bus));
}

void nes_cnrom_device::pcb_reset()
{
	m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
	prg32(0);
	chr8(0, m_chr_source);

	m_chr_open_bus = 0;
}

void nes_cprom_device::device_start()
{
	common_start();
}

void nes_cprom_device::pcb_reset()
{
	m_chr_source = CHRRAM;
	prg32(0);
	chr4_0(0, m_chr_source);
	chr4_4(0, m_chr_source);
}

void nes_gxrom_device::device_start()
{
	common_start();
}

void nes_gxrom_device::pcb_reset()
{
	m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
	prg32(0);
	chr8(0, m_chr_source);
}

void nes_uxrom_device::device_start()
{
	common_start();
}

void nes_uxrom_device::pcb_reset()
{
	m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
	prg16_89ab(0);
	prg16_cdef(m_prg_chunks - 1);
	chr8(0, m_chr_source);
}

void nes_uxrom_cc_device::device_start()
{
	common_start();
}

void nes_uxrom_cc_device::pcb_reset()
{
	m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
	prg32(0);
	chr8(0, m_chr_source);
}

void nes_un1rom_device::device_start()
{
	common_start();
}

void nes_un1rom_device::pcb_reset()
{
	m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
	prg16_89ab(0);
	prg16_cdef(m_prg_chunks - 1);
	chr8(0, m_chr_source);
}


/*-------------------------------------------------
 mapper specific handlers
 -------------------------------------------------*/

/*-------------------------------------------------

 NROM board emulation

 Games: Mario Bros., Super Mario Bros., Tennis and most of
 the first generation games

 iNES: mapper 0

 In MESS: Supported, no need of specific handlers or IRQ

 -------------------------------------------------*/


/*-------------------------------------------------

 AxROM board emulation

 Games: Arch Rivals, Battletoads, Cabal, Commando, Solstice

 writes to 0x8000-0xffff change PRG banks + sets mirroring

 AMROM has bus conflict
 AOROM has generally bus conflict too, but some later pcbs
 added some discrete component to disable ROM and avoid
 conflicts. No AOROM games is known to glitch due to lack of
 bus conflict, so it seems safe to emulate AOROM
 without bus conflict.

 iNES: mapper 7

 In MESS: Supported

 -------------------------------------------------*/

WRITE8_MEMBER(nes_axrom_device::write_h)
{
	LOG_MMC(("axrom write_h, offset: %04x, data: %02x\n", offset, data));

	// this pcb is subject to bus conflict
	data = account_bus_conflict(offset, data);

	set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
	prg32(data);
}

/*-------------------------------------------------

 BxROM board emulation

 writes to 0x8000-0xffff change PRG banks

 iNES: mapper 34

 -------------------------------------------------*/

WRITE8_MEMBER(nes_bxrom_device::write_h)
{
	/* This portion of the mapper is nearly identical to Mapper 7, except no one-screen mirroring */
	/* Deadly Towers is really a BxROM game - the demo screens look wrong using mapper 7. */
	LOG_MMC(("bxrom write_h, offset: %04x, data: %02x\n", offset, data));

	// this pcb is subject to bus conflict, but the same is not true for some pirate variants
	data = account_bus_conflict(offset, data);

	prg32(data);
}

/*-------------------------------------------------

 CNROM board emulation

 Games: B-Wings, Mighty Bomb Jack, Seicross, Spy vs. Spy,
 Adventure Island, Flipull, Friday 13th, GeGeGe no
 Kitarou, Ghostbusters, Gradius, Hokuto no Ken, Milon's
 Secret Castle

 writes to 0x8000-0xffff change CHR 8K banks

 missing BC?

 iNES: mappers 3 & 185 (the latter for games using Pins as
 protection)

 Notice that BANDAI_PT554 board (Aerobics Studio) uses very
 similar hardware but with an additional sound chip which
 gets writes to 0x6000 (currently unemulated in MESS)

 In MESS: Supported

 -------------------------------------------------*/

WRITE8_MEMBER(nes_cnrom_device::write_h)
{
	LOG_MMC(("cxrom write_h, offset: %04x, data: %02x\n", offset, data));

	// this pcb is subject to bus conflict, but the same is not true for some pirate variants
	data = account_bus_conflict(offset, data);

	if (m_ce_mask)
	{
		chr8(data & ~m_ce_mask, CHRROM);

		if ((data & m_ce_mask) == m_ce_state)
			m_chr_open_bus = 0;
		else
			m_chr_open_bus = 1;
	}
	else
		chr8(data, CHRROM);
}

READ8_MEMBER(nes_cnrom_device::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_access[bank][offset & 0x3ff];
}


/*-------------------------------------------------

 CPROM board emulation

 Games: Videomation

 writes to 0x8000-0xffff change CHR 4K lower banks

 iNES: mapper 13

 In MESS: Supported

 -------------------------------------------------*/

WRITE8_MEMBER(nes_cprom_device::write_h)
{
	LOG_MMC(("cprom write_h, offset: %04x, data: %02x\n", offset, data));

	// this pcb is subject to bus conflict
	data = account_bus_conflict(offset, data);

	chr4_4(data, CHRRAM);
}


/*-------------------------------------------------

 GxROM/MxROM board emulation

 writes to 0x8000-0xffff change PRG and CHR banks

 iNES: mapper 66

 -------------------------------------------------*/

WRITE8_MEMBER(nes_gxrom_device::write_h)
{
	LOG_MMC(("gxrom write_h, offset %04x, data: %02x\n", offset, data));

	// this pcb is subject to bus conflict
	data = account_bus_conflict(offset, data);

	prg32((data & 0xf0) >> 4);
	chr8(data & 0x0f, CHRROM);
}

/*-------------------------------------------------

 UxROM board emulation

 Games: Castlevania, Dragon Quest II, Duck Tales, MegaMan,
 Metal Gear

 writes to 0x8000-0xffff change PRG 16K lower banks

 iNES: mapper 2

 In MESS: Supported.

 -------------------------------------------------*/

WRITE8_MEMBER(nes_uxrom_device::write_h)
{
	LOG_MMC(("uxrom write_h, offset: %04x, data: %02x\n", offset, data));

	// this pcb is subject to bus conflict
	data = account_bus_conflict(offset, data);

	prg16_89ab(data);
}

/*-------------------------------------------------

 Nihon Bussan UNROM M5

 Games: Crazy Climber Jpn

 Very simple mapper: prg16_89ab is always set to bank 0,
 while prg16_cdef is set by writes to 0x8000-0xffff. The game
 uses a custom controller.

 iNES: mapper 180

 In MESS: Supported.

 -------------------------------------------------*/

WRITE8_MEMBER(nes_uxrom_cc_device::write_h)
{
	LOG_MMC(("uxrom_cc write_h, offset: %04x, data: %02x\n", offset, data));

	prg16_cdef(data);
}

/*-------------------------------------------------

 UN1ROM board emulation

 Games: Senjou no Okami

 writes to 0x8000-0xffff change PRG 16K lower banks

 iNES: mapper 94

 In MESS: Supported.

 -------------------------------------------------*/

WRITE8_MEMBER(nes_un1rom_device::write_h)
{
	LOG_MMC(("un1rom write_h, offset: %04x, data: %02x\n", offset, data));

	// this pcb is subject to bus conflict
	data = account_bus_conflict(offset, data);

	prg16_89ab(data >> 2);
}