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