1 // license:BSD-3-Clause
2 // copyright-holders:Fabio Priuli
3 /***********************************************************************************************************
4
5
6 NES/Famicom cartridge emulation for pirate cart PCBs
7
8
9 Here we emulate the various PCBs used by Asian & Korean pirate games
10
11 TODO:
12 - Are the scrolling glitches (check status bar) in Magic Dragon correct? FWIW, NEStopia behaves similarly
13
14 ***********************************************************************************************************/
15
16
17 #include "emu.h"
18 #include "pirate.h"
19
20 #include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access ppu2c0x_device::BOTTOM_VISIBLE_SCANLINE
21 #include "screen.h"
22
23
24 #ifdef NES_PCB_DEBUG
25 #define VERBOSE 1
26 #else
27 #define VERBOSE 0
28 #endif
29
30 #define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
31
32
33 //-------------------------------------------------
34 // constructor
35 //-------------------------------------------------
36
37 DEFINE_DEVICE_TYPE(NES_AGCI_50282, nes_agci_device, "nes_agci50282", "NES Cart AGCI 50282 PCB")
38 DEFINE_DEVICE_TYPE(NES_DREAMTECH01, nes_dreamtech_device, "nes_dreamtech", "NES Cart Dreamtech01 PCB")
39 DEFINE_DEVICE_TYPE(NES_FUKUTAKE, nes_fukutake_device, "nes_futuremedia", "NES Cart Fukutake Study Box PCB")
40 DEFINE_DEVICE_TYPE(NES_FUTUREMEDIA, nes_futuremedia_device, "nes_fukutake", "NES Cart FutureMedia PCB")
41 DEFINE_DEVICE_TYPE(NES_MAGSERIES, nes_magseries_device, "nes_magseries", "NES Cart Magical Series PCB")
42 DEFINE_DEVICE_TYPE(NES_DAOU306, nes_daou306_device, "nes_daou306", "NES Cart Daou 306 PCB")
43 DEFINE_DEVICE_TYPE(NES_CC21, nes_cc21_device, "nes_cc21", "NES Cart CC-21 PCB")
44 DEFINE_DEVICE_TYPE(NES_XIAOZY, nes_xiaozy_device, "nes_xiaozy", "NES Cart Xiao Zhuan Yuan PCB")
45 DEFINE_DEVICE_TYPE(NES_EDU2K, nes_edu2k_device, "nes_edu2k", "NES Cart Educational Computer 2000 PCB")
46 DEFINE_DEVICE_TYPE(NES_T230, nes_t230_device, "nes_t230", "NES Cart T-230 PCB")
47 DEFINE_DEVICE_TYPE(NES_MK2, nes_mk2_device, "nes_mk2", "NES Cart Mortal Kombat 2 PCB")
48 DEFINE_DEVICE_TYPE(NES_WHERO, nes_whero_device, "nes_whero", "NES Cart World Heroes PCB")
49 DEFINE_DEVICE_TYPE(NES_43272, nes_43272_device, "nes_43272", "NES Cart UNL-43272 PCB")
50 DEFINE_DEVICE_TYPE(NES_TF1201, nes_tf1201_device, "nes_tf1201", "NES Cart UNL-TF1201 PCB")
51 DEFINE_DEVICE_TYPE(NES_CITYFIGHT, nes_cityfight_device, "nes_cityfight", "NES Cart City Fighter PCB")
52
53
nes_agci_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)54 nes_agci_device::nes_agci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
55 : nes_nrom_device(mconfig, NES_AGCI_50282, tag, owner, clock)
56 {
57 }
58
nes_dreamtech_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)59 nes_dreamtech_device::nes_dreamtech_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
60 : nes_nrom_device(mconfig, NES_DREAMTECH01, tag, owner, clock)
61 {
62 }
63
nes_fukutake_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)64 nes_fukutake_device::nes_fukutake_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
65 : nes_nrom_device(mconfig, NES_FUKUTAKE, tag, owner, clock), m_latch(0)
66 {
67 }
68
nes_futuremedia_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)69 nes_futuremedia_device::nes_futuremedia_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
70 : nes_nrom_device(mconfig, NES_FUTUREMEDIA, tag, owner, clock), m_irq_count(0), m_irq_count_latch(0), m_irq_clear(0), m_irq_enable(0)
71 {
72 }
73
nes_magseries_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)74 nes_magseries_device::nes_magseries_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
75 : nes_nrom_device(mconfig, NES_MAGSERIES, tag, owner, clock)
76 {
77 }
78
nes_daou306_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)79 nes_daou306_device::nes_daou306_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
80 : nes_nrom_device(mconfig, NES_DAOU306, tag, owner, clock)
81 {
82 }
83
nes_cc21_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)84 nes_cc21_device::nes_cc21_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
85 : nes_nrom_device(mconfig, NES_CC21, tag, owner, clock)
86 {
87 }
88
nes_xiaozy_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)89 nes_xiaozy_device::nes_xiaozy_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
90 : nes_nrom_device(mconfig, NES_XIAOZY, tag, owner, clock)
91 {
92 }
93
nes_edu2k_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)94 nes_edu2k_device::nes_edu2k_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
95 : nes_nrom_device(mconfig, NES_EDU2K, tag, owner, clock)
96 {
97 }
98
nes_t230_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)99 nes_t230_device::nes_t230_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
100 : nes_nrom_device(mconfig, NES_T230, tag, owner, clock), m_irq_count(0), m_irq_count_latch(0), m_irq_mode(0), m_irq_enable(0), m_irq_enable_latch(0)
101 {
102 }
103
nes_mk2_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)104 nes_mk2_device::nes_mk2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
105 : nes_nrom_device(mconfig, NES_MK2, tag, owner, clock), m_irq_count(0), m_irq_count_latch(0), m_irq_clear(0), m_irq_enable(0)
106 {
107 }
108
nes_whero_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)109 nes_whero_device::nes_whero_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
110 : nes_nrom_device(mconfig, NES_WHERO, tag, owner, clock), m_reg(0), m_irq_count(0), m_irq_count_latch(0), m_irq_enable(0), m_irq_enable_latch(0)
111 {
112 }
113
nes_43272_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)114 nes_43272_device::nes_43272_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
115 : nes_nrom_device(mconfig, NES_43272, tag, owner, clock), m_latch(0)
116 {
117 }
118
nes_tf1201_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)119 nes_tf1201_device::nes_tf1201_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
120 : nes_nrom_device(mconfig, NES_TF1201, tag, owner, clock), m_prg(0), m_swap(0), m_irq_count(0), m_irq_enable(0), m_irq_enable_latch(0)
121 {
122 }
123
nes_cityfight_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)124 nes_cityfight_device::nes_cityfight_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
125 : nes_nrom_device(mconfig, NES_CITYFIGHT, tag, owner, clock), m_prg_reg(0), m_prg_mode(0), m_irq_count(0), m_irq_enable(0), irq_timer(nullptr)
126 {
127 }
128
129
130
131
device_start()132 void nes_agci_device::device_start()
133 {
134 common_start();
135 }
136
pcb_reset()137 void nes_agci_device::pcb_reset()
138 {
139 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
140 prg32(0);
141 chr8(0, m_chr_source);
142 }
143
device_start()144 void nes_dreamtech_device::device_start()
145 {
146 common_start();
147 }
148
pcb_reset()149 void nes_dreamtech_device::pcb_reset()
150 {
151 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
152 prg16_89ab(0);
153 prg16_cdef(8);
154 chr8(0, m_chr_source);
155 }
156
device_start()157 void nes_fukutake_device::device_start()
158 {
159 common_start();
160 save_item(NAME(m_latch));
161
162 // 2816 (?) bytes of RAM
163 save_item(NAME(m_ram));
164 }
165
pcb_reset()166 void nes_fukutake_device::pcb_reset()
167 {
168 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
169 prg16_89ab(0);
170 prg16_cdef(0);
171 chr8(0, m_chr_source);
172
173 m_latch = 0;
174 }
175
device_start()176 void nes_futuremedia_device::device_start()
177 {
178 common_start();
179 save_item(NAME(m_irq_clear));
180 save_item(NAME(m_irq_enable));
181 save_item(NAME(m_irq_count));
182 save_item(NAME(m_irq_count_latch));
183 }
184
pcb_reset()185 void nes_futuremedia_device::pcb_reset()
186 {
187 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
188 prg16_89ab(0);
189 prg16_cdef(m_prg_chunks - 1);
190 chr8(0, m_chr_source);
191
192 m_irq_clear = 0;
193 m_irq_enable = 0;
194 m_irq_count = m_irq_count_latch = 0;
195 }
196
device_start()197 void nes_magseries_device::device_start()
198 {
199 common_start();
200 }
201
pcb_reset()202 void nes_magseries_device::pcb_reset()
203 {
204 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
205 prg32(0);
206 chr8(0, m_chr_source);
207 }
208
device_start()209 void nes_daou306_device::device_start()
210 {
211 common_start();
212 save_item(NAME(m_reg));
213 }
214
pcb_reset()215 void nes_daou306_device::pcb_reset()
216 {
217 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
218 prg16_89ab(m_prg_chunks - 2);
219 prg16_cdef(m_prg_chunks - 1);
220 chr8(0, m_chr_source);
221 set_nt_mirroring(PPU_MIRROR_LOW);
222
223 memset(m_reg, 0, sizeof(m_reg));
224 }
225
device_start()226 void nes_cc21_device::device_start()
227 {
228 common_start();
229 }
230
pcb_reset()231 void nes_cc21_device::pcb_reset()
232 {
233 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
234 prg32(0);
235 chr8(0, m_chr_source);
236 }
237
device_start()238 void nes_xiaozy_device::device_start()
239 {
240 common_start();
241 }
242
pcb_reset()243 void nes_xiaozy_device::pcb_reset()
244 {
245 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
246 prg32((m_prg_chunks - 1) >> 1);
247 chr8(0, m_chr_source);
248 }
249
device_start()250 void nes_edu2k_device::device_start()
251 {
252 common_start();
253 save_item(NAME(m_latch));
254 }
255
pcb_reset()256 void nes_edu2k_device::pcb_reset()
257 {
258 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
259 prg32(0);
260 chr8(0, m_chr_source);
261
262 m_latch = 0;
263 }
264
device_start()265 void nes_t230_device::device_start()
266 {
267 common_start();
268 save_item(NAME(m_irq_mode));
269 save_item(NAME(m_irq_enable));
270 save_item(NAME(m_irq_enable_latch));
271 save_item(NAME(m_irq_count));
272 save_item(NAME(m_irq_count_latch));
273 save_item(NAME(m_mmc_vrom_bank));
274 }
275
pcb_reset()276 void nes_t230_device::pcb_reset()
277 {
278 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
279 prg16_89ab(0);
280 prg16_cdef(m_prg_chunks - 1);
281 chr8(0, m_chr_source);
282
283 m_irq_mode = 0;
284 m_irq_enable = m_irq_enable_latch = 0;
285 m_irq_count = m_irq_count_latch = 0;
286
287 memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
288 }
289
device_start()290 void nes_mk2_device::device_start()
291 {
292 common_start();
293 save_item(NAME(m_irq_clear));
294 save_item(NAME(m_irq_enable));
295 save_item(NAME(m_irq_count));
296 save_item(NAME(m_irq_count_latch));
297 }
298
pcb_reset()299 void nes_mk2_device::pcb_reset()
300 {
301 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
302 prg16_89ab(m_prg_chunks - 1);
303 prg16_cdef(m_prg_chunks - 1);
304 chr8(0, m_chr_source);
305 set_nt_mirroring(PPU_MIRROR_VERT);
306
307 m_irq_clear = 0;
308 m_irq_enable = 0;
309 m_irq_count = m_irq_count_latch = 0;
310 }
311
312
device_start()313 void nes_whero_device::device_start()
314 {
315 common_start();
316 save_item(NAME(m_irq_enable));
317 save_item(NAME(m_irq_enable_latch));
318 save_item(NAME(m_irq_count));
319 save_item(NAME(m_irq_count_latch));
320 save_item(NAME(m_reg));
321 save_item(NAME(m_mmc_vrom_bank));
322 }
323
pcb_reset()324 void nes_whero_device::pcb_reset()
325 {
326 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
327 prg16_89ab(0);
328 prg16_cdef(m_prg_chunks - 1);
329 chr8(0x100, m_chr_source);
330
331 m_irq_enable = 0;
332 m_irq_enable_latch = 0;
333 m_irq_count = 0;
334 m_irq_count_latch = 0;
335
336 m_reg = 0;
337 memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
338 }
339
device_start()340 void nes_43272_device::device_start()
341 {
342 common_start();
343 save_item(NAME(m_latch));
344 }
345
pcb_reset()346 void nes_43272_device::pcb_reset()
347 {
348 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
349 prg32((m_prg_chunks - 1) >> 1);
350 chr8(0, m_chr_source);
351
352 m_latch = 0x81;
353 }
354
device_start()355 void nes_tf1201_device::device_start()
356 {
357 common_start();
358 save_item(NAME(m_prg));
359 save_item(NAME(m_swap));
360 save_item(NAME(m_irq_enable));
361 save_item(NAME(m_irq_enable_latch));
362 save_item(NAME(m_irq_count));
363 save_item(NAME(m_mmc_vrom_bank));
364 }
365
pcb_reset()366 void nes_tf1201_device::pcb_reset()
367 {
368 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
369 prg16_89ab(0);
370 prg16_cdef(m_prg_chunks - 1);
371 chr8(0, m_chr_source);
372
373 memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
374 m_prg = 0;
375 m_swap = 0;
376 m_irq_enable = 0;
377 m_irq_enable_latch = 0;
378 m_irq_count = 0;
379 }
380
device_start()381 void nes_cityfight_device::device_start()
382 {
383 common_start();
384 irq_timer = timer_alloc(TIMER_IRQ);
385 irq_timer->adjust(attotime::zero, 0, clocks_to_attotime(1));
386
387 save_item(NAME(m_prg_reg));
388 save_item(NAME(m_prg_mode));
389 save_item(NAME(m_irq_enable));
390 save_item(NAME(m_irq_count));
391 save_item(NAME(m_mmc_vrom_bank));
392 }
393
pcb_reset()394 void nes_cityfight_device::pcb_reset()
395 {
396 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
397 prg16_89ab(0);
398 prg16_cdef(m_prg_chunks - 1);
399 chr8(0, m_chr_source);
400
401 memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
402 m_prg_reg = 0;
403 m_prg_mode = 0;
404 m_irq_enable = 0;
405 m_irq_count = 0;
406 }
407
408
409
410 /*-------------------------------------------------
411 mapper specific handlers
412 -------------------------------------------------*/
413
414 /*-------------------------------------------------
415
416 AGCI 50282 bootleg board emulation
417
418 Games: Death Race
419
420 iNES: mapper 144
421
422 In MESS: Supported.
423
424 -------------------------------------------------*/
425
write_h(offs_t offset,uint8_t data)426 void nes_agci_device::write_h(offs_t offset, uint8_t data)
427 {
428 LOG_MMC(("agci write_h, offset: %04x, data: %02x\n", offset, data));
429
430 // this pcb is subject to bus conflict
431 uint8_t temp = account_bus_conflict(offset, 0xff);
432 data = (data & temp) | (temp & 1);
433
434 chr8(data >> 4, CHRROM);
435 prg32(data);
436 }
437
438 /*-------------------------------------------------
439
440 Board DREAMTECH01
441
442 Games: Korean Igo
443
444 In MESS: Supported
445
446 -------------------------------------------------*/
447
write_l(offs_t offset,uint8_t data)448 void nes_dreamtech_device::write_l(offs_t offset, uint8_t data)
449 {
450 LOG_MMC(("dreamtech write_l, offset: %04x, data: %02x\n", offset, data));
451 offset += 0x100;
452
453 if (offset == 0x1020) /* 0x5020 */
454 prg16_89ab(data);
455 }
456
457 /*-------------------------------------------------
458
459 Bootleg Board by Fukutake
460
461 Games: Study Box
462
463 iNES: mapper 186
464
465 In MESS: Unsupported.
466
467
468 -------------------------------------------------*/
469
write_l(offs_t offset,uint8_t data)470 void nes_fukutake_device::write_l(offs_t offset, uint8_t data)
471 {
472 LOG_MMC(("fukutake write_l, offset: %04x, data: %02x\n", offset, data));
473 offset += 0x100;
474
475 if (offset >= 0x200 && offset < 0x400)
476 {
477 if (offset & 1)
478 prg16_89ab(data);
479 else
480 m_latch = data >> 6;
481 }
482 else if (offset >= 0x400 && offset < 0xf00)
483 m_ram[offset - 0x400] = data;
484 }
485
read_l(offs_t offset)486 uint8_t nes_fukutake_device::read_l(offs_t offset)
487 {
488 LOG_MMC(("fukutake read_l, offset: %04x\n", offset));
489 offset += 0x100;
490
491 if (offset >= 0x200 && offset < 0x400)
492 {
493 if (offset == 0x200 || offset == 0x201 || offset == 0x203)
494 return 0x00;
495 else if (offset == 0x202)
496 return 0x40;
497 else
498 return 0xff;
499 }
500 else if (offset >= 0x400 && offset < 0xf00)
501 return m_ram[offset - 0x400];
502
503 return 0;
504 }
505
write_m(offs_t offset,uint8_t data)506 void nes_fukutake_device::write_m(offs_t offset, uint8_t data)
507 {
508 LOG_MMC(("fukutake write_m, offset: %04x, data: %02x\n", offset, data));
509 m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)] = data;
510 }
511
read_m(offs_t offset)512 uint8_t nes_fukutake_device::read_m(offs_t offset)
513 {
514 LOG_MMC(("fukutake read_m, offset: %04x\n", offset));
515 return m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)];
516 }
517
518 /*-------------------------------------------------
519
520 Bootleg Board by Future Media
521
522 Games: Crayon Shin-chan (C), San Guo Zhi 4 - Chi Bi Feng Yun
523
524 iNES: mapper 117
525
526 In MESS: Unsupported.
527
528 -------------------------------------------------*/
529
hblank_irq(int scanline,int vblank,int blanked)530 void nes_futuremedia_device::hblank_irq(int scanline, int vblank, int blanked)
531 {
532 // if (scanline < ppu2c0x_device::BOTTOM_VISIBLE_SCANLINE)
533 {
534 if (m_irq_enable && m_irq_count)
535 {
536 m_irq_count--;
537 if (!m_irq_count)
538 hold_irq_line();
539 }
540 }
541 }
542
write_h(offs_t offset,uint8_t data)543 void nes_futuremedia_device::write_h(offs_t offset, uint8_t data)
544 {
545 LOG_MMC(("futuremedia write_h, offset: %04x, data: %02x\n", offset, data));
546
547 switch (offset)
548 {
549 case 0x0000:
550 prg8_89(data);
551 break;
552 case 0x0001:
553 prg8_ab(data);
554 break;
555 case 0x0002:
556 prg8_cd(data);
557 break;
558 case 0x0003:
559 prg8_ef(data);
560 break;
561 case 0x2000:
562 case 0x2001:
563 case 0x2002:
564 case 0x2003:
565 case 0x2004:
566 case 0x2005:
567 case 0x2006:
568 case 0x2007:
569 chr1_x(offset & 0x07, data, CHRROM);
570 break;
571
572 case 0x5000:
573 set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
574 break;
575
576 case 0x4001:
577 m_irq_count_latch = data;
578 break;
579 case 0x4002:
580 // IRQ cleared
581 break;
582 case 0x4003:
583 m_irq_count = m_irq_count_latch;
584 break;
585 case 0x6000:
586 m_irq_enable = data & 0x01;
587 break;
588 }
589 }
590
591 /*-------------------------------------------------
592
593 Bootleg Board by Magic Series
594
595 Games: Magic Dragon
596
597 Very simple mapper: writes to 0x8000-0xffff set prg32 and chr8
598 banks
599
600 iNES: mapper 107
601
602 In MESS: Supported.
603
604 -------------------------------------------------*/
605
write_h(offs_t offset,uint8_t data)606 void nes_magseries_device::write_h(offs_t offset, uint8_t data)
607 {
608 LOG_MMC(("magseries write_h, offset: %04x, data: %02x\n", offset, data));
609
610 prg32(data >> 1);
611 chr8(data, CHRROM);
612 }
613
614 /*-------------------------------------------------
615
616 Open Corp DAOU306 board
617
618 Games: Metal Force (K)
619
620 iNES: mapper 156
621
622 In MESS: Supported.
623
624 Notes: Metal Force and Buzz & Waldog only use the first 4
625 regs and no mirroring. Janggun ui Adeul uses all features
626
627 -------------------------------------------------*/
628
write_h(offs_t offset,uint8_t data)629 void nes_daou306_device::write_h(offs_t offset, uint8_t data)
630 {
631 LOG_MMC(("daou306 write_h, offset: %04x, data: %02x\n", offset, data));
632 int reg = BIT(offset, 2) ? 8 : 0;
633
634 switch (offset)
635 {
636 case 0x4000:
637 case 0x4004:
638 m_reg[reg + 0] = data;
639 chr1_0(m_reg[0] | (m_reg[8] << 8), CHRROM);
640 break;
641 case 0x4001:
642 case 0x4005:
643 m_reg[reg + 1] = data;
644 chr1_1(m_reg[1] | (m_reg[9] << 8), CHRROM);
645 break;
646 case 0x4002:
647 case 0x4006:
648 m_reg[reg + 2] = data;
649 chr1_2(m_reg[2] | (m_reg[10] << 8), CHRROM);
650 break;
651 case 0x4003:
652 case 0x4007:
653 m_reg[reg + 3] = data;
654 chr1_3(m_reg[3] | (m_reg[11] << 8), CHRROM);
655 break;
656 case 0x4008:
657 case 0x400c:
658 m_reg[reg + 4] = data;
659 chr1_4(m_reg[4] | (m_reg[12] << 8), CHRROM);
660 break;
661 case 0x4009:
662 case 0x400d:
663 m_reg[reg + 5] = data;
664 chr1_5(m_reg[5] | (m_reg[13] << 8), CHRROM);
665 break;
666 case 0x400a:
667 case 0x400e:
668 m_reg[reg + 6] = data;
669 chr1_6(m_reg[6] | (m_reg[14] << 8), CHRROM);
670 break;
671 case 0x400b:
672 case 0x400f:
673 m_reg[reg + 7] = data;
674 chr1_7(m_reg[7] | (m_reg[15] << 8), CHRROM);
675 break;
676 case 0x4010:
677 prg16_89ab(data);
678 break;
679 case 0x4014:
680 if (data & 1)
681 set_nt_mirroring(PPU_MIRROR_HORZ);
682 else
683 set_nt_mirroring(PPU_MIRROR_VERT);
684 break;
685 }
686 }
687
688 /*-------------------------------------------------
689
690 Board UNL-CC-21
691
692 Games: Mi Hun Che
693
694 In MESS: Supported
695
696 -------------------------------------------------*/
697
write_h(offs_t offset,uint8_t data)698 void nes_cc21_device::write_h(offs_t offset, uint8_t data)
699 {
700 LOG_MMC(("cc21 write_h, offset: %04x, data: %02x\n", offset, data));
701
702 set_nt_mirroring(BIT(offset, 1) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
703 chr8((offset & 0x01), CHRROM);
704 }
705
706 /*-------------------------------------------------
707
708 Bootleg Board for Xiao Zhuan Yuan
709
710 Games: Shu Qi Yu - Zhi Li Xiao Zhuan Yuan
711
712 Very simple mapper: writes to 0x5ff1 set prg32 (to data>>1),
713 while writes to 0x5ff2 set chr8
714
715 iNES: mapper 176
716
717 In MESS: Supported.
718
719 -------------------------------------------------*/
720
write_l(offs_t offset,uint8_t data)721 void nes_xiaozy_device::write_l(offs_t offset, uint8_t data)
722 {
723 LOG_MMC(("xiaozy write_l, offset: %04x, data: %02x\n", offset, data));
724
725 switch (offset)
726 {
727 case 0x1ef1: /* 0x5ff1 */
728 prg32(data >> 1);
729 break;
730 case 0x1ef2: /* 0x5ff2 */
731 chr8(data, CHRROM);
732 break;
733 }
734 }
735
736 /*-------------------------------------------------
737
738 UNL-EDU2000
739
740 -------------------------------------------------*/
741
write_h(offs_t offset,uint8_t data)742 void nes_edu2k_device::write_h(offs_t offset, uint8_t data)
743 {
744 LOG_MMC(("edu2k write_h, offset: %04x, data: %02x\n", offset, data));
745
746 prg32(data & 0x1f);
747 m_latch = (data & 0xc0) >> 6;
748 }
749
write_m(offs_t offset,uint8_t data)750 void nes_edu2k_device::write_m(offs_t offset, uint8_t data)
751 {
752 LOG_MMC(("edu2k write_m, offset: %04x, data: %02x\n", offset, data));
753 m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)] = data;
754 }
755
read_m(offs_t offset)756 uint8_t nes_edu2k_device::read_m(offs_t offset)
757 {
758 LOG_MMC(("edu2k read_m, offset: %04x\n", offset));
759 return m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)];
760 }
761
762 /*-------------------------------------------------
763
764 Board UNL-T-230
765
766 Games: Dragon Ball Z IV (Unl)
767
768 This mapper appears to be similar to Konami VRC-2
769 but the game has no VROM and only 1 VRAM bank, so we
770 completely skip the chr bankswitch. If other games
771 using the same board and using CHR should surface,
772 we need to investigate this...
773
774 In MESS: Supported
775
776 -------------------------------------------------*/
777
778 // Identical to Konami IRQ
hblank_irq(int scanline,int vblank,int blanked)779 void nes_t230_device::hblank_irq(int scanline, int vblank, int blanked)
780 {
781 /* Increment & check the IRQ scanline counter */
782 if (m_irq_enable && (++m_irq_count == 0x100))
783 {
784 m_irq_count = m_irq_count_latch;
785 m_irq_enable = m_irq_enable_latch;
786 hold_irq_line();
787 }
788 }
789
write_h(offs_t offset,uint8_t data)790 void nes_t230_device::write_h(offs_t offset, uint8_t data)
791 {
792 LOG_MMC(("t230 write_h, offset: %04x, data: %02x\n", offset, data));
793
794 switch (offset & 0x700c)
795 {
796 case 0x0000:
797 break;
798 case 0x2000:
799 prg16_89ab(data);
800 break;
801 case 0x1000:
802 case 0x1004:
803 case 0x1008:
804 case 0x100c:
805 switch (data & 0x03)
806 {
807 case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
808 case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
809 case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
810 case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
811 }
812 break;
813
814 case 0x7000:
815 m_irq_count_latch &= ~0x0f;
816 m_irq_count_latch |= data & 0x0f;
817 break;
818 case 0x7004:
819 m_irq_count_latch &= ~0xf0;
820 m_irq_count_latch |= (data << 4) & 0xf0;
821 break;
822 case 0x7008:
823 m_irq_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode
824 m_irq_enable = data & 0x02;
825 m_irq_enable_latch = data & 0x01;
826 if (data & 0x02)
827 m_irq_count = m_irq_count_latch;
828 break;
829
830 default:
831 logerror("unl_t230_w uncaught offset: %04x value: %02x\n", offset, data);
832 break;
833 }
834 }
835
836 /*-------------------------------------------------
837
838 Bootleg Board for MK2
839
840 Games: Mortal Kombat II, Street Fighter III, Super Mario
841 Kart Rider
842
843 This board uses an IRQ system very similar to MMC3. We indeed
844 use mapper4_irq, but there is some small glitch!
845
846 iNES: mapper 91
847
848 In MESS: Supported.
849
850 -------------------------------------------------*/
851
852 // Same IRQ as MMC3
hblank_irq(int scanline,int vblank,int blanked)853 void nes_mk2_device::hblank_irq( int scanline, int vblank, int blanked )
854 {
855 if (scanline < ppu2c0x_device::BOTTOM_VISIBLE_SCANLINE)
856 {
857 int prior_count = m_irq_count;
858 if ((m_irq_count == 0) || m_irq_clear)
859 m_irq_count = m_irq_count_latch;
860 else
861 m_irq_count--;
862
863 if (m_irq_enable && !blanked && (m_irq_count == 0) && (prior_count || m_irq_clear))
864 {
865 LOG_MMC(("irq fired, scanline: %d\n", scanline));
866 hold_irq_line();
867 }
868 }
869 m_irq_clear = 0;
870 }
871
write_m(offs_t offset,uint8_t data)872 void nes_mk2_device::write_m(offs_t offset, uint8_t data)
873 {
874 LOG_MMC(("mk2 write_m, offset: %04x, data: %02x\n", offset, data));
875
876 switch (offset & 0x1000)
877 {
878 case 0x0000:
879 switch (offset & 0x03)
880 {
881 case 0x00: chr2_0(data, CHRROM); break;
882 case 0x01: chr2_2(data, CHRROM); break;
883 case 0x02: chr2_4(data, CHRROM); break;
884 case 0x03: chr2_6(data, CHRROM); break;
885 }
886 break;
887 case 0x1000:
888 switch (offset & 0x03)
889 {
890 case 0x00: prg8_89(data); break;
891 case 0x01: prg8_ab(data); break;
892 case 0x02: m_irq_enable = 0; m_irq_count = 0; break;
893 case 0x03: m_irq_enable = 1; m_irq_count = 7; break;
894 }
895 break;
896 default:
897 logerror("mk2 write_m, uncaught addr: %04x value: %02x\n", offset + 0x6000, data);
898 break;
899 }
900 }
901
902
903 /*-------------------------------------------------
904
905 UNL-WOLRDHERO board emulation
906
907
908 iNES:
909
910 -------------------------------------------------*/
911
912 // Same as Konami VRC IRQ...
hblank_irq(int scanline,int vblank,int blanked)913 void nes_whero_device::hblank_irq(int scanline, int vblank, int blanked)
914 {
915 /* Increment & check the IRQ scanline counter */
916 if (m_irq_enable && (++m_irq_count == 0x100))
917 {
918 m_irq_count = m_irq_count_latch;
919 m_irq_enable = m_irq_enable_latch;
920 hold_irq_line();
921 }
922 }
923
write_h(offs_t offset,uint8_t data)924 void nes_whero_device::write_h(offs_t offset, uint8_t data)
925 {
926 int bank, shift, mask1, mask2;
927 LOG_MMC(("World Hero write_h, offset: %04x, data: %02x\n", offset, data));
928
929 switch (offset & 0x70c3)
930 {
931 case 0x0000:
932 if (!m_reg)
933 prg8_89(data);
934 else
935 prg8_cd(data);
936 break;
937
938 case 0x1000:
939 switch (data & 0x03)
940 {
941 case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
942 case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
943 case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
944 case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
945 }
946 break;
947
948 case 0x1002:
949 case 0x1080:
950 if (m_reg != (data & 2))
951 {
952 m_reg = data & 2;
953 // swap banks!
954 prg8_89(m_prg_bank[2]);
955 prg8_cd(m_prg_bank[0]);
956 }
957 break;
958
959 case 0x2000:
960 prg8_ab(data);
961 break;
962
963 case 0x3000: case 0x3001: case 0x3002: case 0x3003:
964 case 0x4000: case 0x4001: case 0x4002: case 0x4003:
965 case 0x5000: case 0x5001: case 0x5002: case 0x5003:
966 case 0x6000: case 0x6001: case 0x6002: case 0x6003:
967 bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(offset, 1);
968 shift = (offset & 1) << 2;
969 mask1 = shift ? 0x00f : 0xff0;
970 mask2 = shift ? 0xff0 : 0x00f;
971 m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & mask1) | ((data << shift) & mask2);
972 chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
973 break;
974
975 case 0x7000:
976 m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f);
977 break;
978
979 case 0x7001:
980 m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4);
981 break;
982
983 case 0x7002:
984 // m_irq_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode
985 m_irq_enable = data & 0x02;
986 m_irq_enable_latch = data & 0x01;
987 if (data & 0x02)
988 m_irq_count = m_irq_count_latch;
989 break;
990
991 case 0x7003:
992 m_irq_enable = m_irq_enable_latch;
993 break;
994 }
995 }
996
997
998 /*-------------------------------------------------
999
1000 UNL-43272
1001
1002 Games: Gaau Hok Gwong Cheung
1003
1004 In MESS: Preliminary Supported
1005
1006 -------------------------------------------------*/
1007
write_h(offs_t offset,uint8_t data)1008 void nes_43272_device::write_h(offs_t offset, uint8_t data)
1009 {
1010 LOG_MMC(("unl_43272 write_h, offset: %04x, data: %02x\n", offset, data));
1011
1012 if ((m_latch & 0x81) == 0x81)
1013 prg32((m_latch & 0x38) >> 3);
1014
1015 m_latch = offset & 0xffff;
1016 }
1017
1018
read_h(offs_t offset)1019 uint8_t nes_43272_device::read_h(offs_t offset)
1020 {
1021 uint8_t mask = (m_latch & 0x400) ? 0xfe : 0xff;
1022 LOG_MMC(("unl_43272 read_h, offset: %04x\n", offset));
1023
1024 return hi_access_rom(offset & mask);
1025 }
1026
1027
1028 /*-------------------------------------------------
1029
1030 UNL-TF1201
1031
1032 Games:
1033
1034 In MESS: Preliminary Supported
1035
1036 -------------------------------------------------*/
1037
hblank_irq(int scanline,int vblank,int blanked)1038 void nes_tf1201_device::hblank_irq(int scanline, int vblank, int blanked)
1039 {
1040 if (m_irq_enable_latch != m_irq_enable && scanline < 240)
1041 m_irq_count -= 8;
1042
1043 if (m_irq_enable)
1044 {
1045 m_irq_count++;
1046 if ((m_irq_count & 0xff) == 238)
1047 hold_irq_line();
1048 }
1049 }
1050
update_prg()1051 void nes_tf1201_device::update_prg()
1052 {
1053 prg8_89(m_swap ? 0xff : m_prg);
1054 prg8_cd(m_swap ? m_prg : 0xff );
1055 }
1056
write_h(offs_t offset,uint8_t data)1057 void nes_tf1201_device::write_h(offs_t offset, uint8_t data)
1058 {
1059 int bank;
1060 LOG_MMC(("unl_tf1201 write_h, offset: %04x, data: %02x\n", offset, data));
1061
1062 offset = (offset & 0x7003) | ((offset & 0x0c) >> 2); // nestopia does not OR here...
1063
1064 switch (offset & 0x7003)
1065 {
1066 case 0x0000:
1067 m_prg = data;
1068 update_prg();
1069 break;
1070 case 0x1000:
1071 set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
1072 break;
1073 case 0x1001:
1074 m_swap = data & 0x03;
1075 update_prg();
1076 break;
1077 case 0x2000:
1078 prg8_ab(data);
1079 break;
1080 case 0x3000: case 0x3001: case 0x3002: case 0x3003:
1081 case 0x4000: case 0x4001: case 0x4002: case 0x4003:
1082 case 0x5000: case 0x5001: case 0x5002: case 0x5003:
1083 case 0x6000: case 0x6001: case 0x6002: case 0x6003:
1084 bank = (((offset - 0x3000) >> 11) | (offset & 0x1)) & 0x7;
1085 if (offset & 2)
1086 m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4);
1087 else
1088 m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0);
1089 chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source);
1090 break;
1091 case 0x7000:
1092 m_irq_count = (m_irq_count & 0xf0) | (data & 0x0f);
1093 break;
1094 case 0x7001:
1095 case 0x7003:
1096 m_irq_enable_latch = m_irq_enable;
1097 m_irq_enable = BIT(data, 1);
1098 break;
1099 case 0x7002:
1100 m_irq_count = (m_irq_count & 0x0f) | ((data & 0x0f) << 4);
1101 break;
1102 }
1103 }
1104
1105
1106 /*-------------------------------------------------
1107
1108 UNL-CITYFIGHT
1109
1110 Games:
1111
1112 Additional audio register not emulated yet!
1113
1114 In MESS: Preliminary Supported
1115
1116 -------------------------------------------------*/
1117
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)1118 void nes_cityfight_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
1119 {
1120 if (id == TIMER_IRQ)
1121 {
1122 if (m_irq_enable)
1123 {
1124 if (!m_irq_count)
1125 {
1126 hold_irq_line();
1127 m_irq_count = 0xffff;
1128 }
1129 else
1130 m_irq_count--;
1131 }
1132 }
1133 }
1134
update_prg()1135 void nes_cityfight_device::update_prg()
1136 {
1137 prg32(m_prg_reg >> 2);
1138 if (!m_prg_mode)
1139 prg8_cd(m_prg_reg);
1140 }
1141
write_h(offs_t offset,uint8_t data)1142 void nes_cityfight_device::write_h(offs_t offset, uint8_t data)
1143 {
1144 int bank;
1145 LOG_MMC(("unl_cityfight write_h, offset: %04x, data: %02x\n", offset, data));
1146
1147 switch (offset & 0x700c)
1148 {
1149 case 0x1000:
1150 switch (data & 0x03)
1151 {
1152 case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
1153 case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
1154 case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
1155 case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
1156 }
1157 m_prg_reg = data & 0xc;
1158 break;
1159 case 0x1004:
1160 case 0x1008:
1161 case 0x100c:
1162 if (offset & 0x800)
1163 LOG_MMC(("Extended Audio write, data %x!", data & 0x0f));//pcmwrite(0x4011, (V & 0xf) << 3);
1164 else
1165 m_prg_reg = data & 0xc;
1166 break;
1167
1168
1169 case 0x2000: case 0x2004: case 0x2008: case 0x200c:
1170 bank = 2 + BIT(offset, 3);
1171 if (offset & 4)
1172 m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4);
1173 else
1174 m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0);
1175 chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source);
1176 break;
1177 case 0x3000: case 0x3004: case 0x3008: case 0x300c:
1178 bank = 4 + BIT(offset, 3);
1179 if (offset & 4)
1180 m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4);
1181 else
1182 m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0);
1183 chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source);
1184 break;
1185 case 0x5000: case 0x5004: case 0x5008: case 0x500c:
1186 bank = 0 + BIT(offset, 3);
1187 if (offset & 4)
1188 m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4);
1189 else
1190 m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0);
1191 chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source);
1192 break;
1193 case 0x6000: case 0x6004: case 0x6008: case 0x600c:
1194 bank = 6 + BIT(offset, 3);
1195 if (offset & 4)
1196 m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4);
1197 else
1198 m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0);
1199 chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source);
1200 break;
1201
1202 case 0x4000:
1203 case 0x4004:
1204 case 0x4008:
1205 case 0x400c:
1206 m_prg_mode = data & 1;
1207
1208 case 0x7000:
1209 m_irq_count = (m_irq_count & 0x1e0) | ((data & 0x0f) << 1);
1210 break;
1211 case 0x7004:
1212 m_irq_count = (m_irq_count & 0x1e) | ((data & 0x0f) << 5);
1213 break;
1214 case 0x7008:
1215 m_irq_enable = BIT(data, 1);
1216 break;
1217 }
1218 }
1219
1220
1221 #ifdef UNUSED_FUNCTION
1222 /*-------------------------------------------------
1223
1224 FUJIYA Board - mapper 170 according to NEStopia
1225
1226 Is this possibly for the Fujiya Famikase series
1227 of educational titles? Is there any dump around?
1228
1229 -------------------------------------------------*/
1230
device_start()1231 void nes_fujiya_device::device_start()
1232 {
1233 common_start();
1234 save_item(NAME(m_latch));
1235 }
1236
pcb_reset()1237 void nes_fujiya_device::pcb_reset()
1238 {
1239 m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
1240 prg16_89ab(0);
1241 prg16_cdef(0);
1242 chr8(0, m_chr_source);
1243
1244 m_latch = 0;
1245 }
1246
write_m(offs_t offset,uint8_t data)1247 void nes_fujiya_device::write_m(offs_t offset, uint8_t data)
1248 {
1249 LOG_MMC(("fujiya write_m, offset: %04x, data: %02x\n", offset, data));
1250 offset += 0x6000;
1251
1252 if (offset == 0x6502 || offset == 0x7000)
1253 m_latch = (data & 0x40) << 1;
1254 }
1255
read_m(offs_t offset)1256 uint8_t nes_fujiya_device::read_m(offs_t offset)
1257 {
1258 LOG_MMC(("fujiya read_m, offset: %04x\n", offset));
1259 offset += 0x6000;
1260
1261 if (offset == 0x7001 || offset == 0x7777)
1262 return m_latch | ((offset >> 8) & 0x7f);
1263
1264 return get_open_bus(); // open bus
1265 }
1266 #endif
1267