1 // license:BSD-3-Clause
2 // copyright-holders:David Haywood
3
4 /*
5 SH6578 NES clone hardware
6 enhanced NES, different to VT / OneBus systems
7
8 "UMC 1997.2 A35551S" on CPU die (maxx6in1)
9
10 video rendering is changed significantly compared to NES so not using NES PPU device
11 has 256x256 pixel pages, attributes are stored next to tile numbers (not in their own table after them) etc.
12
13 */
14
15 #include "emu.h"
16 #include "video/ppu2c0x_sh6578.h"
17 #include "cpu/m6502/m6502.h"
18 #include "sound/nes_apu.h"
19 #include "emupal.h"
20 #include "screen.h"
21 #include "speaker.h"
22 #include "machine/bankdev.h"
23 #include "machine/timer.h"
24
25 #define LOG_DMA (1U << 2)
26 #define LOG_PPU (1U << 1)
27
28 //#define VERBOSE (LOG_PPU)
29 #define VERBOSE (0)
30
31 #include "logmacro.h"
32
33 class nes_sh6578_state : public driver_device
34 {
35 public:
nes_sh6578_state(const machine_config & mconfig,device_type type,const char * tag)36 nes_sh6578_state(const machine_config& mconfig, device_type type, const char* tag) :
37 driver_device(mconfig, type, tag),
38 m_bank(*this, "cartbank"),
39 m_maincpu(*this, "maincpu"),
40 m_ppu(*this, "ppu"),
41 m_fullrom(*this, "fullrom"),
42 m_screen(*this, "screen"),
43 m_apu(*this, "nesapu"),
44 m_timer(*this, "timer"),
45 m_in(*this, "IN%u", 0U)
46 { }
47
48 void nes_sh6578(machine_config& config);
49 void nes_sh6578_pal(machine_config& config);
50
51 void init_nes_sh6578();
52
53 protected:
54 virtual void machine_start() override;
55 virtual void machine_reset() override;
56 virtual void video_start() override;
57
58 void sprite_dma_w(address_space &space, uint8_t data);
59
60 virtual void io_w(uint8_t data);
61 virtual void extio_w(uint8_t data);
62 bool m_isbanked;
63 required_memory_bank m_bank;
64
65 private:
66 required_device<cpu_device> m_maincpu;
67 required_device<ppu_sh6578_device> m_ppu;
68 required_device<address_map_bank_device> m_fullrom;
69 required_device<screen_device> m_screen;
70 required_device<nesapu_device> m_apu;
71 required_device<timer_device> m_timer;
72
73 uint8_t bankswitch_r(offs_t offset);
74 void bankswitch_w(offs_t offset, uint8_t data);
75
76 uint8_t dma_r(offs_t offset);
77 void dma_w(offs_t offset, uint8_t data);
78
79 uint8_t bank_r(int bank, uint16_t offset);
80 void bank_w(int bank, uint16_t offset, uint8_t data);
81
bank0_r(offs_t offset)82 uint8_t bank0_r(offs_t offset) { return bank_r(0, offset); }
bank0_w(offs_t offset,uint8_t data)83 void bank0_w(offs_t offset, uint8_t data) { bank_w(0, offset, data); }
bank1_r(offs_t offset)84 uint8_t bank1_r(offs_t offset) { return bank_r(1, offset); }
bank1_w(offs_t offset,uint8_t data)85 void bank1_w(offs_t offset, uint8_t data) { bank_w(1, offset, data); }
bank2_r(offs_t offset)86 uint8_t bank2_r(offs_t offset) { return bank_r(2, offset); }
bank2_w(offs_t offset,uint8_t data)87 void bank2_w(offs_t offset, uint8_t data) { bank_w(2, offset, data); }
bank3_r(offs_t offset)88 uint8_t bank3_r(offs_t offset) { return bank_r(3, offset); }
bank3_w(offs_t offset,uint8_t data)89 void bank3_w(offs_t offset, uint8_t data) { bank_w(3, offset, data); }
bank4_r(offs_t offset)90 uint8_t bank4_r(offs_t offset) { return bank_r(4, offset); }
bank4_w(offs_t offset,uint8_t data)91 void bank4_w(offs_t offset, uint8_t data) { bank_w(4, offset, data); }
bank5_r(offs_t offset)92 uint8_t bank5_r(offs_t offset) { return bank_r(5, offset); }
bank5_w(offs_t offset,uint8_t data)93 void bank5_w(offs_t offset, uint8_t data) { bank_w(5, offset, data); }
bank6_r(offs_t offset)94 uint8_t bank6_r(offs_t offset) { return bank_r(6, offset); }
bank6_w(offs_t offset,uint8_t data)95 void bank6_w(offs_t offset, uint8_t data) { bank_w(6, offset, data); }
bank7_r(offs_t offset)96 uint8_t bank7_r(offs_t offset) { return bank_r(7, offset); }
bank7_w(offs_t offset,uint8_t data)97 void bank7_w(offs_t offset, uint8_t data) { bank_w(7, offset, data); }
98
99 void timing_setting_control_w(uint8_t data);
100 void initial_startup_w(uint8_t data);
101 uint8_t irq_status_r();
102 void irq_mask_w(uint8_t data);
103 void timer_config_w(uint8_t data);
104 void timer_value_w(uint8_t data);
105
106 uint8_t io0_r();
107 uint8_t io1_r();
108
109 uint8_t psg1_4014_r();
110 uint8_t psg1_4015_r();
111 void psg1_4015_w(uint8_t data);
112 void psg1_4017_w(uint8_t data);
113 uint8_t apu_read_mem(offs_t offset);
114
115 DECLARE_WRITE_LINE_MEMBER(apu_irq);
116
117 int m_initial_startup_state;
118
119 uint8_t m_bankswitch[8];
120
121 uint8_t m_dma_control;
122 uint8_t m_dma_bank;
123 uint8_t m_dma_source[2];
124 uint8_t m_dma_dest[2];
125 uint8_t m_dma_length[2];
126
127 uint8_t m_irqmask;
128
129 void do_dma();
130
131 void rom_map(address_map& map);
132 void nes_sh6578_map(address_map& map);
133
134 //uint16_t get_tileaddress(uint8_t x, uint8_t y, bool ishigh);
135
136 uint32_t screen_update(screen_device& screen, bitmap_rgb32& bitmap, const rectangle& cliprect);
137
138 TIMER_DEVICE_CALLBACK_MEMBER(timer_expired);
139 int m_timerval;
140
141 // this might be game specific
142 uint8_t m_previo;
143 uint8_t m_iolatch[2];
144 required_ioport_array<2> m_in;
145 };
146
147 class nes_sh6578_abl_wikid_state : public nes_sh6578_state
148 {
149 public:
nes_sh6578_abl_wikid_state(const machine_config & mconfig,device_type type,const char * tag)150 nes_sh6578_abl_wikid_state(const machine_config& mconfig, device_type type, const char* tag) :
151 nes_sh6578_state(mconfig, type, tag)
152 { }
153
154 protected:
155 virtual void io_w(uint8_t data) override;
156 };
157
158 class nes_sh6578_max10in1_state : public nes_sh6578_state
159 {
160 public:
nes_sh6578_max10in1_state(const machine_config & mconfig,device_type type,const char * tag)161 nes_sh6578_max10in1_state(const machine_config& mconfig, device_type type, const char* tag) :
162 nes_sh6578_state(mconfig, type, tag)
163 { }
164
165 protected:
166 virtual void extio_w(uint8_t data) override;
167 virtual void machine_reset() override;
168 };
169
bank_r(int bank,uint16_t offset)170 uint8_t nes_sh6578_state::bank_r(int bank, uint16_t offset)
171 {
172 uint32_t address;
173 address = offset & 0x00fff; // 0x00fff part of address
174 address |= (m_bankswitch[bank] & 0xff) << 12; // 0xff000 part of address
175 return m_fullrom->read8(address);
176 }
177
bank_w(int bank,uint16_t offset,uint8_t data)178 void nes_sh6578_state::bank_w(int bank, uint16_t offset, uint8_t data)
179 {
180 uint32_t address;
181 address = offset & 0x00fff; // 0x00fff part of address
182 address |= (m_bankswitch[bank] & 0xff) << 12; // 0xff000 part of address
183 m_fullrom->write8(address, data);
184 }
185
sprite_dma_w(address_space & space,uint8_t data)186 void nes_sh6578_state::sprite_dma_w(address_space &space, uint8_t data)
187 {
188 m_ppu->spriteram_dma(space, data);
189 }
190
bankswitch_r(offs_t offset)191 uint8_t nes_sh6578_state::bankswitch_r(offs_t offset)
192 {
193 return m_bankswitch[offset];
194 }
195
bankswitch_w(offs_t offset,uint8_t data)196 void nes_sh6578_state::bankswitch_w(offs_t offset, uint8_t data)
197 {
198 m_bankswitch[offset] = data;
199 }
200
dma_r(offs_t offset)201 uint8_t nes_sh6578_state::dma_r(offs_t offset)
202 {
203 switch (offset)
204 {
205 case 0x00: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Control : %02x\n", machine().describe_context(), offset, m_dma_control); return m_dma_control & 0x7f;
206 case 0x01: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Bank Select\n", machine().describe_context(), offset); return m_dma_bank;
207 case 0x02: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Source Address Low\n", machine().describe_context(), offset); return m_dma_source[0];
208 case 0x03: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Source Address High\n", machine().describe_context(), offset); return m_dma_source[1];
209 case 0x04: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Destination Address Low\n", machine().describe_context(), offset); return m_dma_dest[0];
210 case 0x05: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Destination Address High\n", machine().describe_context(), offset); return m_dma_dest[1];
211 case 0x06: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Length Low\n", machine().describe_context(), offset); return m_dma_length[0];
212 case 0x07: LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_r offset %01x : DMA Length High\n", machine().describe_context(), offset); return m_dma_length[1];
213 }
214 return 0x00;
215 }
216
do_dma()217 void nes_sh6578_state::do_dma()
218 {
219
220 if (m_dma_control & 0x80)
221 {
222 uint16_t dma_source = m_dma_source[0] | (m_dma_source[1] << 8);
223 uint16_t dma_dest = m_dma_dest[0] | (m_dma_dest[1] << 8);
224 uint16_t dma_length = m_dma_length[0] | (m_dma_length[1] << 8);
225
226 LOGMASKED(LOG_DMA, "Doing DMA :%02x bank:%02x: source:%04x dest:%04x length:%04x\n", m_dma_control, m_dma_bank, dma_source, dma_dest, dma_length);
227
228 uint16_t realsourceaddress = dma_source;
229 uint16_t realdestaddress = dma_dest;
230
231 for (int i = 0; i <= dma_length; i++)
232 {
233 uint8_t readdat = 0x00;
234 if (realsourceaddress & 0x8000)
235 {
236 // reading from ROM?
237 uint32_t trueaddress = (realsourceaddress & 0x7fff) | ((m_dma_bank & 0x1f) * 0x8000);
238
239 readdat = m_fullrom->read8(trueaddress);
240 }
241 else
242 {
243 //logerror("reading from system area %04x\n", realsourceaddress);
244 uint32_t trueaddress = (realsourceaddress & 0x7fff);
245 readdat = m_maincpu->space(AS_PROGRAM).read_byte(trueaddress);
246 }
247
248 if (m_dma_control & 0x20)
249 {
250 //logerror("writing to WORK RAM %04x %02x\n", realdestaddress, readdat);
251 m_maincpu->space(AS_PROGRAM).write_byte(realdestaddress, readdat);
252 }
253 else
254 {
255 m_ppu->space(AS_PROGRAM).write_byte(realdestaddress, readdat);
256 }
257
258 realsourceaddress++;
259 realdestaddress++;
260 }
261 }
262
263 // but games seem to be making quite a few DMA writes with lengths that seem too large? buggy code?
264 //m_dma_length[0] = 0;
265 //m_dma_length[1] = 0;
266 }
267
dma_w(offs_t offset,uint8_t data)268 void nes_sh6578_state::dma_w(offs_t offset, uint8_t data)
269 {
270 switch (offset)
271 {
272 case 0x0:
273 LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Control : %02x\n", machine().describe_context(), offset, data);
274 m_dma_control = data;
275 do_dma();
276 break;
277
278 case 0x1:
279 LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Bank Select : %02x\n", machine().describe_context(), offset, data);
280 m_dma_bank = data;
281 break;
282
283 case 0x2:
284 LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Source Address Low : %02x\n", machine().describe_context(), offset, data);
285 m_dma_source[0] = data;
286 break;
287
288 case 0x3:
289 LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Source Address High : %02x\n", machine().describe_context(), offset, data);
290 m_dma_source[1] = data;
291 break;
292
293 case 0x4:
294 LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Destination Address Low : %02x\n", machine().describe_context(), offset, data);
295 m_dma_dest[0] = data;
296 break;
297
298 case 0x5:
299 LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Destination Address High : %02x\n", machine().describe_context(), offset, data);
300 m_dma_dest[1] = data;
301 break;
302
303 case 0x6:
304 LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Length Low : %02x\n", machine().describe_context(), offset, data);
305 m_dma_length[0] = data;
306 break;
307
308 case 0x7:
309 LOGMASKED(LOG_DMA, "%s: nes_sh6578_state::dma_w offset %01x : DMA Length High : %02x\n", machine().describe_context(), offset, data);
310 m_dma_length[1] = data;
311 break;
312 }
313 }
314
315
initial_startup_w(uint8_t data)316 void nes_sh6578_state::initial_startup_w(uint8_t data)
317 {
318 // there is also a timeframe in which this must happen
319 // if the writes are not correct the system does not operate
320 if (m_initial_startup_state == 0)
321 {
322 if (data == 0x65)
323 {
324 logerror("initial_startup_w VALID first write (0x65)\n");
325 m_initial_startup_state = 1;
326 }
327 else
328 {
329 logerror("initial_startup_w invalid first write (not 0x65)\n");
330 m_initial_startup_state = -1;
331 }
332 }
333 else if (m_initial_startup_state == 1)
334 {
335 if (data == 0x76)
336 {
337 logerror("initial_startup_w VALID second write (0x76)\n");
338 m_initial_startup_state = 2;
339 }
340 else
341 {
342 logerror("initial_startup_w invalid second write (not 0x76)\n");
343 m_initial_startup_state = -1;
344 }
345 }
346 else if (m_initial_startup_state == 2)
347 {
348 logerror("initial_startup_w invalid write (already passed) (%02x)\n", data);
349 }
350 else if (m_initial_startup_state == -1)
351 {
352 logerror("initial_startup_w invalid write (already failed) (%02x)\n", data);
353 }
354 }
355
irq_status_r()356 uint8_t nes_sh6578_state::irq_status_r()
357 {
358 logerror("%s: nes_sh6578_state::irq_status_r\n", machine().describe_context());
359 return machine().rand();
360 }
361
irq_mask_w(uint8_t data)362 void nes_sh6578_state::irq_mask_w(uint8_t data)
363 {
364 m_irqmask = data;
365
366 if (m_irqmask & 0x80)
367 m_maincpu->set_input_line(0, CLEAR_LINE);
368 }
369
timer_config_w(uint8_t data)370 void nes_sh6578_state::timer_config_w(uint8_t data)
371 {
372 logerror("%s: nes_sh6578_state::timer_config_w : %02x (at pos y: %d x: %d )\n", machine().describe_context(), data, m_screen->vpos(), m_screen->hpos() );
373
374 if ((data & 0x80) && (data & 0x20))
375 {
376 m_timer->adjust(m_screen->scan_period() * m_timerval);
377 }
378 else
379 {
380 m_timer->adjust(attotime::never);
381 }
382 }
383
timer_value_w(uint8_t data)384 void nes_sh6578_state::timer_value_w(uint8_t data)
385 {
386 logerror("%s: nes_sh6578_state::timer_value_w : %02x\n", machine().describe_context(), data);
387 m_timerval = data;
388 }
389
390
timing_setting_control_w(uint8_t data)391 void nes_sh6578_state::timing_setting_control_w(uint8_t data)
392 {
393 logerror("%s: nes_sh6578_state::timing_setting_control_w : %02x\n", machine().describe_context(), data);
394 }
395
396
io0_r()397 uint8_t nes_sh6578_state::io0_r()
398 {
399 uint8_t ret = m_iolatch[0] & 0x01;
400 m_iolatch[0] >>= 1;
401 return ret;
402 }
403
io1_r()404 uint8_t nes_sh6578_state::io1_r()
405 {
406 uint8_t ret = m_iolatch[1] & 0x01;
407 m_iolatch[1] >>= 1;
408 return ret;
409 }
410
io_w(uint8_t data)411 void nes_sh6578_state::io_w(uint8_t data)
412 {
413 if ((data != 0x00) && (data != 0x01) && (data != 0x02) && (data != 0x03))
414 logerror("%s: io_w : unexpected value : %02x\n", machine().describe_context(), data);
415
416 if ((m_previo & 0x01) != (data & 0x01))
417 {
418 // latch on rising or falling?
419 if (!(data & 0x01))
420 {
421 m_iolatch[0] = m_in[0]->read();
422 m_iolatch[1] = m_in[1]->read();
423 }
424 }
425
426 m_previo = data;
427 }
428
io_w(uint8_t data)429 void nes_sh6578_abl_wikid_state::io_w(uint8_t data)
430 {
431 nes_sh6578_state::io_w(data);
432
433 if (m_isbanked)
434 {
435 m_bank->set_entry((data>>1)&1);
436 }
437 }
438
extio_w(uint8_t data)439 void nes_sh6578_state::extio_w(uint8_t data)
440 {
441 logerror("%s: extio_w : %02x\n", machine().describe_context(), data);
442 }
443
extio_w(uint8_t data)444 void nes_sh6578_max10in1_state::extio_w(uint8_t data)
445 {
446 logerror("%s: extio_w : %02x (max10in1)\n", machine().describe_context(), data);
447
448 m_bank->set_entry((data & 0x80) >> 7);
449 }
450
451
452
453
454
psg1_4014_r()455 uint8_t nes_sh6578_state::psg1_4014_r()
456 {
457 return m_apu->read(0x14);
458 }
459
psg1_4015_r()460 uint8_t nes_sh6578_state::psg1_4015_r()
461 {
462 return m_apu->read(0x15);
463 }
464
psg1_4015_w(uint8_t data)465 void nes_sh6578_state::psg1_4015_w(uint8_t data)
466 {
467 m_apu->write(0x15, data);
468 }
469
psg1_4017_w(uint8_t data)470 void nes_sh6578_state::psg1_4017_w(uint8_t data)
471 {
472 m_apu->write(0x17, data);
473 }
474
WRITE_LINE_MEMBER(nes_sh6578_state::apu_irq)475 WRITE_LINE_MEMBER(nes_sh6578_state::apu_irq)
476 {
477 // unimplemented
478 }
479
apu_read_mem(offs_t offset)480 uint8_t nes_sh6578_state::apu_read_mem(offs_t offset)
481 {
482 return m_maincpu->space(AS_PROGRAM).read_byte(offset);
483 }
484
485
486
nes_sh6578_map(address_map & map)487 void nes_sh6578_state::nes_sh6578_map(address_map& map)
488 {
489 map(0x0000, 0x1fff).ram();
490 map(0x2000, 0x2007).rw(m_ppu, FUNC(ppu2c0x_device::read), FUNC(ppu2c0x_device::write));
491 map(0x2008, 0x2008).rw(m_ppu, FUNC(ppu_sh6578_device::read_extended), FUNC(ppu_sh6578_device::write_extended));
492
493 map(0x2040, 0x207f).rw(m_ppu, FUNC(ppu_sh6578_device::palette_read), FUNC(ppu_sh6578_device::palette_write));
494
495 map(0x4000, 0x4013).rw(m_apu, FUNC(nesapu_device::read), FUNC(nesapu_device::write));
496 map(0x4014, 0x4014).rw(FUNC(nes_sh6578_state::psg1_4014_r), FUNC(nes_sh6578_state::sprite_dma_w));
497 map(0x4015, 0x4015).rw(FUNC(nes_sh6578_state::psg1_4015_r), FUNC(nes_sh6578_state::psg1_4015_w));
498 map(0x4016, 0x4016).rw(FUNC(nes_sh6578_state::io0_r), FUNC(nes_sh6578_state::io_w));
499 map(0x4017, 0x4017).rw(FUNC(nes_sh6578_state::io1_r), FUNC(nes_sh6578_state::psg1_4017_w));
500
501 map(0x4020, 0x4020).w(FUNC(nes_sh6578_state::timing_setting_control_w));
502 //4021 write keyboard output port
503 //4022 read/write keyboard data control
504 //4023 read/write joystick,mouse control
505 //4024 read - mouse port / write - mouse baud
506 //4025 write - Printer Port
507 map(0x4026, 0x4026).w(FUNC(nes_sh6578_state::extio_w));
508 //4027 read/write - DAC data register
509
510 map(0x4031, 0x4031).w(FUNC(nes_sh6578_state::initial_startup_w));
511 map(0x4032, 0x4032).w(FUNC(nes_sh6578_state::irq_mask_w));
512 map(0x4033, 0x4033).r(FUNC(nes_sh6578_state::irq_status_r));
513 map(0x4034, 0x4034).w(FUNC(nes_sh6578_state::timer_config_w));
514 map(0x4035, 0x4035).w(FUNC(nes_sh6578_state::timer_value_w));
515
516 map(0x4040, 0x4047).rw(FUNC(nes_sh6578_state::bankswitch_r), FUNC(nes_sh6578_state::bankswitch_w));
517
518 map(0x4048, 0x404f).rw(FUNC(nes_sh6578_state::dma_r), FUNC(nes_sh6578_state::dma_w));
519
520 map(0x5000, 0x57ff).ram();
521
522 map(0x5800, 0x7fff).ram(); // cpatrolm seems to expect RAM here too?
523
524 map(0x8000, 0x8fff).rw(FUNC(nes_sh6578_state::bank0_r), FUNC(nes_sh6578_state::bank0_w));
525 map(0x9000, 0x9fff).rw(FUNC(nes_sh6578_state::bank1_r), FUNC(nes_sh6578_state::bank1_w));
526 map(0xa000, 0xafff).rw(FUNC(nes_sh6578_state::bank2_r), FUNC(nes_sh6578_state::bank2_w));
527 map(0xb000, 0xbfff).rw(FUNC(nes_sh6578_state::bank3_r), FUNC(nes_sh6578_state::bank3_w));
528 map(0xc000, 0xcfff).rw(FUNC(nes_sh6578_state::bank4_r), FUNC(nes_sh6578_state::bank4_w));
529 map(0xd000, 0xdfff).rw(FUNC(nes_sh6578_state::bank5_r), FUNC(nes_sh6578_state::bank5_w));
530 map(0xe000, 0xefff).rw(FUNC(nes_sh6578_state::bank6_r), FUNC(nes_sh6578_state::bank6_w));
531 map(0xf000, 0xffff).rw(FUNC(nes_sh6578_state::bank7_r), FUNC(nes_sh6578_state::bank7_w));
532 }
533
534 static INPUT_PORTS_START(nes_sh6578)
535 PORT_START("IN0")
536 PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(1)
537 PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(1)
538 PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(1)
539 PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_PLAYER(1)
540 PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_8WAY
541 PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_8WAY
542 PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_8WAY
543 PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_8WAY
544
545 PORT_START("IN1")
546 PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED )
547 INPUT_PORTS_END
548
video_start()549 void nes_sh6578_state::video_start()
550 {
551 }
552
machine_reset()553 void nes_sh6578_state::machine_reset()
554 {
555 for (int i = 0; i < 8; i++)
556 m_bankswitch[i] = i;
557
558 m_initial_startup_state = 0;
559 m_bank->set_entry(0);
560
561 m_irqmask = 0xff;
562 m_timerval = 0x00;
563 }
564
machine_reset()565 void nes_sh6578_max10in1_state::machine_reset()
566 {
567 nes_sh6578_state::machine_reset();
568 m_bank->set_entry(1);
569 }
570
machine_start()571 void nes_sh6578_state::machine_start()
572 {
573 m_bank->configure_entry(0, memregion("maincpu")->base() + 0x0000000);
574 m_bank->set_entry(0);
575
576 if (memregion("maincpu")->bytes() == 0x200000)
577 {
578 m_isbanked = true;
579 m_bank->configure_entry(1, memregion("maincpu")->base() + 0x100000);
580 }
581 else
582 {
583 m_isbanked = false;
584 }
585 }
586
587 // SH6578 can address 20-bit address space (1MB of ROM)
rom_map(address_map & map)588 void nes_sh6578_state::rom_map(address_map& map)
589 {
590 map(0x00000, 0xfffff).bankr("cartbank");
591 }
592
TIMER_DEVICE_CALLBACK_MEMBER(nes_sh6578_state::timer_expired)593 TIMER_DEVICE_CALLBACK_MEMBER(nes_sh6578_state::timer_expired)
594 {
595 if (!(m_irqmask & 0x80))
596 {
597 //printf("timer expired on line %d\n", m_screen->vpos());
598 m_maincpu->set_input_line(0, ASSERT_LINE);
599 }
600
601 m_timer->adjust(attotime::never);
602 }
603
604
605 // from n2a03.h verify that it actually uses these
606 #define N2A03_NTSC_XTAL XTAL(21'477'272)
607 #define N2A03_PAL_XTAL XTAL(26'601'712)
608 #define NTSC_APU_CLOCK (N2A03_NTSC_XTAL/12) /* 1.7897726666... MHz */
609 #define PAL_APU_CLOCK (N2A03_PAL_XTAL/16) /* 1.662607 MHz */
610 #define PALC_APU_CLOCK (N2A03_PAL_XTAL/15) /* 1.77344746666... MHz */
611
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)612 uint32_t nes_sh6578_state::screen_update(screen_device& screen, bitmap_rgb32& bitmap, const rectangle& cliprect)
613 {
614 return m_ppu->screen_update(screen, bitmap, cliprect);
615 }
616
nes_sh6578(machine_config & config)617 void nes_sh6578_state::nes_sh6578(machine_config& config)
618 {
619 /* basic machine hardware */
620 M6502(config, m_maincpu, NTSC_APU_CLOCK); // regular M6502 core, not N2A03?
621 m_maincpu->set_addrmap(AS_PROGRAM, &nes_sh6578_state::nes_sh6578_map);
622
623 ADDRESS_MAP_BANK(config, m_fullrom).set_map(&nes_sh6578_state::rom_map).set_options(ENDIANNESS_NATIVE, 8, 20, 0x100000);
624
625 PPU_SH6578(config, m_ppu, N2A03_NTSC_XTAL);
626 m_ppu->set_cpu_tag(m_maincpu);
627 m_ppu->int_callback().set_inputline(m_maincpu, INPUT_LINE_NMI);
628
629 /* video hardware */
630 SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
631 m_screen->set_refresh_hz(60.0988);
632 m_screen->set_vblank_time(ATTOSECONDS_IN_USEC((113.66/(NTSC_APU_CLOCK.dvalue()/1000000)) *
633 (ppu2c0x_device::VBLANK_LAST_SCANLINE_NTSC-ppu2c0x_device::VBLANK_FIRST_SCANLINE+1+2)));
634 m_screen->set_size(32*8, 262);
635 m_screen->set_visarea(0*8, 32*8-1, 0*8, 30*8-1);
636 m_screen->set_screen_update(FUNC(nes_sh6578_state::screen_update));
637
638 TIMER(config, m_timer).configure_generic(FUNC(nes_sh6578_state::timer_expired));
639
640 /* sound hardware */
641 SPEAKER(config, "mono").front_center();
642
643 // have to add the APU separately due to using M6502
644 NES_APU(config, m_apu, NTSC_APU_CLOCK);
645 m_apu->irq().set(FUNC(nes_sh6578_state::apu_irq));
646 m_apu->mem_read().set(FUNC(nes_sh6578_state::apu_read_mem));
647 m_apu->add_route(ALL_OUTPUTS, "mono", 0.50);
648 }
649
nes_sh6578_pal(machine_config & config)650 void nes_sh6578_state::nes_sh6578_pal(machine_config& config)
651 {
652 nes_sh6578(config);
653
654 m_maincpu->set_clock(PALC_APU_CLOCK);
655 m_apu->set_clock(PALC_APU_CLOCK);
656
657 PPU_SH6578PAL(config.replace(), m_ppu, N2A03_PAL_XTAL);
658 m_ppu->set_cpu_tag(m_maincpu);
659 m_ppu->int_callback().set_inputline(m_maincpu, INPUT_LINE_NMI);
660
661 m_screen->set_refresh_hz(50.0070);
662 m_screen->set_vblank_time(ATTOSECONDS_IN_USEC((113.66 / (PALC_APU_CLOCK.dvalue() / 1000000)) *
663 (ppu2c0x_device::VBLANK_LAST_SCANLINE_PAL - ppu2c0x_device::VBLANK_FIRST_SCANLINE_PALC + 1 + 2)));
664 m_screen->set_size(32 * 8, 312);
665 m_screen->set_visarea(0 * 8, 32 * 8 - 1, 0 * 8, 30 * 8 - 1);
666
667 }
668
init_nes_sh6578()669 void nes_sh6578_state::init_nes_sh6578()
670 {
671 }
672
673
674
675 ROM_START( bandgpad )
676 ROM_REGION( 0x100000, "maincpu", 0 )
677 ROM_LOAD( "gamepad.bin", 0x00000, 0x100000, CRC(e2fbb532) SHA1(e9170a7739a8355acbf263fe2b1d291951dc07f0) )
678 ROM_END
679
680 ROM_START( bandggcn )
681 ROM_REGION( 0x100000, "maincpu", 0 )
682 ROM_LOAD( "gogoconniechan.bin", 0x00000, 0x100000, CRC(715d66ae) SHA1(9326c227bad86eea85194a90f746c60dc032a323) )
683 ROM_END
684
685
686
687 ROM_START( ts_handy11 )
688 ROM_REGION( 0x100000, "maincpu", 0 )
689 ROM_LOAD( "tvplaypowercontroller.bin", 0x00000, 0x100000, CRC(9c7fe9ff) SHA1(c872e91ca835b66c9dd3b380e8374b51f12bcae0) ) // 29LV008B
690 ROM_END
691
692 ROM_START( cpatrolm )
693 ROM_REGION( 0x100000, "maincpu", 0 )
694 ROM_LOAD( "citypatrolman.bin", 0x00000, 0x100000, CRC(4b139c67) SHA1(a5b03f472a94ee879f58bbff201b671fbf4f1ea1) )
695 ROM_END
696
697 ROM_START( ablwikid )
698 ROM_REGION( 0x200000, "maincpu", 0 )
699 ROM_LOAD( "mx29f1610atc.u2", 0x00000, 0x200000, CRC(f16abf79) SHA1(aeccbb40d7fdd451ba8e5cca20464da2cf116461) )
700 ROM_END
701
702 ROM_START( maxx5in1 )
703 ROM_REGION( 0x100000, "maincpu", ROMREGION_ERASEFF )
704 ROM_LOAD( "vsmaxxcasino5_e28f008sa_89a2.bin", 0x00000, 0x100000, CRC(e3d8f24f) SHA1(121411e72d53eabe6be927d1db2f871d59a9e08e) )
705 ROM_END
706
707 ROM_START( maxx6in1 )
708 ROM_REGION( 0x100000, "maincpu", ROMREGION_ERASEFF )
709 ROM_LOAD( "maxx6in1.bin", 0x00000, 0x100000, CRC(8e582298) SHA1(89892b9095dbd5101cdf2477a66abd2cb11ad8c8) )
710 ROM_END
711
712 ROM_START( max10in1 )
713 ROM_REGION( 0x200000, "maincpu", ROMREGION_ERASEFF )
714 ROM_LOAD( "csmaxxcasino10.bin", 0x000000, 0x200000, CRC(2a05e9af) SHA1(fcf591c22ce8773f72e9d0fa0bae545f6a82a063) )
715 ROM_END
716
717 ROM_START( vsmaxx15 )
718 ROM_REGION( 0x100000, "maincpu", 0 )
719 ROM_LOAD( "vsmaxx15n1_e28f008sa_89a2.bin", 0x00000, 0x100000, CRC(713955ce) SHA1(f5ff02055fd4574cedc2f056d19388207a7244c0) )
720 ROM_END
721
722 ROM_START( vsmaxx25 )
723 ROM_REGION( 0x200000, "maincpu", 0 )
724 ROM_LOAD( "vsmaxx25_am29lv160dt_000122c4.bin", 0x00000, 0x200000, CRC(0efd1625) SHA1(34e83f748af3eee475c5b2b24ff03c00c1b5b8ed) )
725 ROM_END
726
727
728
729 CONS( 200?, maxx5in1, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Senario / JungleTac", "Vs Maxx 5-in-1 Casino / Senario Card & Casino Games", 0 ) // advertised on box as 'With Solitaire" (was there an even older version without it?)
730
731 CONS( 200?, maxx6in1, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Senario / JungleTac", "Vs Maxx 6-in-1 Casino / Senario Card & Casino Games", 0 ) // advertised on box as "With Texas Hold 'Em" (which is the added game since the 5-in-1)
732
733 CONS( 200?, max10in1, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_max10in1_state, init_nes_sh6578, "Senario / JungleTac", "Vs Maxx 10-in-1 Casino / Senario Card & Casino Games", 0 )
734
735 // titles below have various issues (DMA, split interrupt timing etc.)
736
737 // aka Wik!d Joystick, sometimes also called Air Blaster like the real Air Blaster game. Wik!d seems a rebranding (a 'gift' company) so did ABL reuse the Air Blaster name here instead?
738 CONS( 200?, ablwikid, 0, 0, nes_sh6578_pal, nes_sh6578, nes_sh6578_abl_wikid_state, init_nes_sh6578, "Advance Bright Ltd. / JungleTac", "Wikid Joystick 14-in-1", MACHINE_NOT_WORKING )
739
740 CONS( 2001?, ts_handy11, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Techno Source / JungleTac", "Handy Boy 11-in-1 (TV Play Power)", MACHINE_NOT_WORKING ) // possibly newer than 2001
741
742 // from a blue coloured unit, a yellow one exists, is it the same?
743 CONS( 2004?, vsmaxx15, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Senario / JungleTac", "Vs Maxx 15-in-1", MACHINE_NOT_WORKING )
744
745 // This is from the blue coloured unit with the 1p/2p slider (does it do anything / get read anywhere?)
746 // A version of the 25-in-1 on VT hardware also exists, with the downgraded version of Big Racing & removed copyrights etc. (probably the purple tinted version without the 1p/2p slider)
747 CONS( 2004?, vsmaxx25, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_max10in1_state, init_nes_sh6578, "Senario / JungleTac", "Vs Maxx 25-in-1", MACHINE_NOT_WORKING )
748
749 // titles below need inputs mapping to go further
750
751 CONS( 1997, bandgpad, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Bandai", "Multi Game Player Gamepad", MACHINE_NOT_WORKING )
752
753 CONS( 1997, bandggcn, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Bandai", "Go! Go! Connie-chan! Asobou Mouse", MACHINE_NOT_WORKING )
754
755 CONS( 200?, cpatrolm, 0, 0, nes_sh6578_pal, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "TimeTop", "City Patrolman", MACHINE_NOT_WORKING )
756
757