1 // license:BSD-3-Clause
2 // copyright-holders:Wilbert Pol
3 /***************************************************************************
4 
5   pcfx.cpp
6 
7   Driver file to handle emulation of the NEC PC-FX.
8 
9 ***************************************************************************/
10 
11 
12 #include "emu.h"
13 #include "cpu/v810/v810.h"
14 #include "sound/huc6230.h"
15 #include "video/huc6261.h"
16 #include "video/huc6270.h"
17 #include "video/huc6271.h"
18 #include "video/huc6272.h"
19 #include "screen.h"
20 #include "speaker.h"
21 
22 class pcfx_state : public driver_device
23 {
24 public:
pcfx_state(const machine_config & mconfig,device_type type,const char * tag)25 	pcfx_state(const machine_config &mconfig, device_type type, const char *tag)
26 		: driver_device(mconfig, type, tag),
27 		m_maincpu(*this, "maincpu"),
28 		m_huc6261(*this, "huc6261") { }
29 
30 	void pcfx(machine_config &config);
31 
32 private:
33 	enum
34 	{
35 		TIMER_PAD_FUNC
36 	};
37 	uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
38 
39 	uint16_t irq_read(offs_t offset);
40 	void irq_write(offs_t offset, uint16_t data);
41 	uint16_t pad_r(offs_t offset);
42 	void pad_w(offs_t offset, uint16_t data);
43 	uint8_t extio_r(offs_t offset);
44 	void extio_w(offs_t offset, uint8_t data);
45 
46 	DECLARE_WRITE_LINE_MEMBER( irq8_w );
47 	DECLARE_WRITE_LINE_MEMBER( irq9_w );
48 	DECLARE_WRITE_LINE_MEMBER( irq10_w );
49 	DECLARE_WRITE_LINE_MEMBER( irq11_w );
50 	DECLARE_WRITE_LINE_MEMBER( irq12_w );
51 	DECLARE_WRITE_LINE_MEMBER( irq13_w );
52 	DECLARE_WRITE_LINE_MEMBER( irq14_w );
53 	DECLARE_WRITE_LINE_MEMBER( irq15_w );
54 	TIMER_CALLBACK_MEMBER(pad_func);
55 
56 	void pcfx_io(address_map &map);
57 	void pcfx_mem(address_map &map);
58 
59 	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
60 
61 	virtual void machine_reset() override;
62 
63 	// Interrupt controller (component unknown)
64 	uint16_t m_irq_mask;
65 	uint16_t m_irq_pending;
66 	uint8_t m_irq_priority[8];
67 
68 	struct pcfx_pad_t
69 	{
70 		uint8_t ctrl[2];
71 		uint8_t status[2];
72 		uint32_t latch[2];
73 	};
74 
75 	pcfx_pad_t m_pad;
76 
77 	inline void check_irqs();
78 	inline void set_irq_line(int line, int state);
79 
80 	required_device<cpu_device> m_maincpu;
81 	required_device<huc6261_device> m_huc6261;
82 };
83 
84 
extio_r(offs_t offset)85 uint8_t pcfx_state::extio_r(offs_t offset)
86 {
87 	address_space &io_space = m_maincpu->space(AS_IO);
88 
89 	return io_space.read_byte(offset);
90 }
91 
extio_w(offs_t offset,uint8_t data)92 void pcfx_state::extio_w(offs_t offset, uint8_t data)
93 {
94 	address_space &io_space = m_maincpu->space(AS_IO);
95 
96 	io_space.write_byte(offset, data);
97 }
98 
pcfx_mem(address_map & map)99 void pcfx_state::pcfx_mem(address_map &map)
100 {
101 	map(0x00000000, 0x001FFFFF).ram();   /* RAM */
102 //  map(0x80000000, 0x807FFFFF).rw(FUNC(pcfx_state::extio_r), FUNC(pcfx_state::extio_w));    /* EXTIO */
103 	map(0xE0000000, 0xE7FFFFFF).noprw();   /* BackUp RAM */
104 	map(0xE8000000, 0xE9FFFFFF).noprw();   /* Extended BackUp RAM */
105 	map(0xF8000000, 0xF8000007).noprw();   /* PIO */
106 	map(0xFFF00000, 0xFFFFFFFF).rom().region("ipl", 0);  /* ROM */
107 }
108 
pad_r(offs_t offset)109 uint16_t pcfx_state::pad_r(offs_t offset)
110 {
111 	uint16_t res;
112 	uint8_t port_type = ((offset<<1) & 0x80) >> 7;
113 
114 	if(((offset<<1) & 0x40) == 0)
115 	{
116 		// status
117 		/*
118 		---- x---
119 		---- ---x incoming data state (0=available)
120 		*/
121 		res = m_pad.status[port_type];
122 		//printf("STATUS %d\n",port_type);
123 	}
124 	else
125 	{
126 		// received data
127 		//printf("RX %d\n",port_type);
128 		res = m_pad.latch[port_type] >> (((offset<<1) & 2) ? 16 : 0);
129 
130 		if(((offset<<1) & 0x02) == 0)
131 		{
132 			m_pad.status[port_type] &= ~8; // clear latch on LSB read according to docs
133 			set_irq_line(11, 0);
134 		}
135 	}
136 
137 	return res;
138 }
139 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)140 void pcfx_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
141 {
142 	switch (id)
143 	{
144 	case TIMER_PAD_FUNC:
145 		pad_func(ptr, param);
146 		break;
147 	default:
148 		throw emu_fatalerror("Unknown id in pcfx_state::device_timer");
149 	}
150 }
151 
TIMER_CALLBACK_MEMBER(pcfx_state::pad_func)152 TIMER_CALLBACK_MEMBER(pcfx_state::pad_func)
153 {
154 	const char *const padnames[] = { "P1", "P2" };
155 
156 	m_pad.latch[param] = ioport(padnames[param])->read();
157 	m_pad.status[param] |= 8;
158 	m_pad.ctrl[param] &= ~1; // ack TX line
159 	// TODO: pad IRQ
160 	set_irq_line(11, 1);
161 }
162 
pad_w(offs_t offset,uint16_t data)163 void pcfx_state::pad_w(offs_t offset, uint16_t data)
164 {
165 	uint8_t port_type = ((offset<<1) & 0x80) >> 7;
166 
167 	if(((offset<<1) & 0x40) == 0)
168 	{
169 		// control
170 		/*
171 		---- -x-- receiver enable
172 		---- --x- enable multi-tap
173 		---- ---x enable send (0->1 transition)
174 		*/
175 		if(data & 1 && (!(m_pad.ctrl[port_type] & 1)))
176 		{
177 			timer_set(attotime::from_usec(1000), TIMER_PAD_FUNC, port_type); // TODO: time
178 		}
179 
180 		m_pad.ctrl[port_type] = data & 7;
181 		//printf("%04x CONTROL %d\n",data,port_type);
182 	}
183 	else
184 	{
185 		// transmitted data
186 		//printf("%04x TX %d\n",data,port_type);
187 	}
188 }
189 
190 
pcfx_io(address_map & map)191 void pcfx_state::pcfx_io(address_map &map)
192 {
193 	map(0x00000000, 0x000000FF).rw(FUNC(pcfx_state::pad_r), FUNC(pcfx_state::pad_w)); /* PAD */
194 	map(0x00000100, 0x000001FF).w("huc6230", FUNC(huc6230_device::write)).umask32(0x00ff00ff);   /* HuC6230 */
195 	map(0x00000200, 0x000002FF).m("huc6271", FUNC(huc6271_device::regs)).umask32(0x0000ffff);   /* HuC6271 */
196 	map(0x00000300, 0x000003FF).rw(m_huc6261, FUNC(huc6261_device::read), FUNC(huc6261_device::write)).umask32(0x0000ffff);  /* HuC6261 */
197 	map(0x00000400, 0x000004FF).rw("huc6270_a", FUNC(huc6270_device::read), FUNC(huc6270_device::write)).umask32(0x0000ffff); /* HuC6270-A */
198 	map(0x00000500, 0x000005FF).rw("huc6270_b", FUNC(huc6270_device::read), FUNC(huc6270_device::write)).umask32(0x0000ffff); /* HuC6270-B */
199 	map(0x00000600, 0x000006FF).rw("huc6272", FUNC(huc6272_device::read), FUNC(huc6272_device::write));    /* HuC6272 */
200 	map(0x00000C80, 0x00000C83).noprw();
201 	map(0x00000E00, 0x00000EFF).rw(FUNC(pcfx_state::irq_read), FUNC(pcfx_state::irq_write)).umask32(0x0000ffff);    /* Interrupt controller */
202 	map(0x00000F00, 0x00000FFF).noprw();
203 //  map(0x00600000, 0x006FFFFF).r(FUNC(pcfx_state::scsi_ctrl_r));
204 	map(0x00780000, 0x007FFFFF).rom().region("scsi_rom", 0);
205 	map(0x80500000, 0x805000FF).noprw();   /* HuC6273 */
206 }
207 
208 
209 static INPUT_PORTS_START( pcfx )
210 	/*
211 	xxxx ---- ---- ---- ID (0xf = 6 button pad, 0xe = multitap, 0xd = mouse, 0 = none)
212 	*/
213 	PORT_START("P1")
214 	PORT_BIT( 0xf0000000, IP_ACTIVE_LOW, IPT_UNKNOWN ) // ID pad
215 	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("P1 Button I")
216 	PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("P1 Button II")
217 	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("P1 Button III")
218 	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_NAME("P1 Button IV")
219 	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(1) PORT_NAME("P1 Button V")
220 	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(1) PORT_NAME("P1 Button VI")
221 	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_SELECT ) PORT_PLAYER(1) PORT_NAME("P1 Select Button")
222 	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_START1 ) PORT_PLAYER(1) PORT_NAME("P1 RUN Button")
223 	PORT_BIT( 0x00000100, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_NAME("P1 Up")
224 	PORT_BIT( 0x00000200, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_NAME("P1 Right")
225 	PORT_BIT( 0x00000400, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_NAME("P1 Down")
226 	PORT_BIT( 0x00000800, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_NAME("P1 Left")
227 	PORT_BIT( 0x00001000, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_PLAYER(1) PORT_NAME("P1 Switch 1")
228 	PORT_BIT( 0x00004000, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_PLAYER(1) PORT_NAME("P1 Switch 2")
229 	PORT_BIT( 0x0fffa000, IP_ACTIVE_LOW, IPT_UNKNOWN )
230 
231 	PORT_START("P2")
232 	PORT_BIT( 0xf0000000, IP_ACTIVE_HIGH, IPT_UNKNOWN ) // ID unconnect
233 	PORT_BIT( 0x0fffffff, IP_ACTIVE_LOW, IPT_UNKNOWN )
234 INPUT_PORTS_END
235 
236 
irq_read(offs_t offset)237 uint16_t pcfx_state::irq_read(offs_t offset)
238 {
239 	uint16_t data = 0;
240 
241 	switch( offset )
242 	{
243 		// Interrupts pending
244 		// Same bit order as mask
245 		case 0x00/4:
246 			data = m_irq_pending;
247 			break;
248 
249 		// Interrupt mask
250 		case 0x40/4:
251 			data = m_irq_mask;
252 			break;
253 
254 		// Interrupt priority 0
255 		case 0x80/4:
256 			data = m_irq_priority[4] | ( m_irq_priority[5] << 3 ) | ( m_irq_priority[6] << 6 ) | ( m_irq_priority[7] << 9 );
257 			break;
258 
259 		// Interrupt priority 1
260 		case 0xC0/4:
261 			data = m_irq_priority[0] | ( m_irq_priority[1] << 3 ) | ( m_irq_priority[2] << 6 ) | ( m_irq_priority[3] << 9 );
262 			break;
263 	}
264 
265 	return data;
266 }
267 
268 
irq_write(offs_t offset,uint16_t data)269 void pcfx_state::irq_write(offs_t offset, uint16_t data)
270 {
271 	switch( offset )
272 	{
273 		// Interrupts pending
274 		case 0x00/4:
275 			logerror("irq_write: Attempt to write to irq pending register\n");
276 			break;
277 
278 		// Interrupt mask
279 		// --------x------- Mask interrupt level 8  (Unknown)
280 		// ---------x------ Mask interrupt level 9  (Timer)
281 		// ----------x----- Mask interrupt level 10 (Unknown)
282 		// -----------x---- Mask interrupt level 11 (Pad)
283 		// ------------x--- Mask interrupt level 12 (HuC6270-A)
284 		// -------------x-- Mask interrupt level 13 (HuC6272)
285 		// --------------x- Mask interrupt level 14 (HuC6270-B)
286 		// ---------------x Mask interrupt level 15 (HuC6273)
287 		// 0 - allow, 1 - ignore interrupt
288 		case 0x40/4:
289 			m_irq_mask = data;
290 			check_irqs();
291 			break;
292 
293 		// Interrupt priority 0
294 		// ----xxx--------- Priority level interrupt 12
295 		// -------xxx------ Priority level interrupt 13
296 		// ----------xxx--- Priority level interrupt 14
297 		// -------------xxx Priority level interrupt 15
298 		case 0x80/4:
299 			m_irq_priority[7] = ( data >> 0 ) & 0x07;
300 			m_irq_priority[6] = ( data >> 3 ) & 0x07;
301 			m_irq_priority[5] = ( data >> 6 ) & 0x07;
302 			m_irq_priority[4] = ( data >> 9 ) & 0x07;
303 			check_irqs();
304 			break;
305 
306 		// Interrupt priority 1
307 		// ----xxx--------- Priority level interrupt 8
308 		// -------xxx------ Priority level interrupt 9
309 		// ----------xxx--- Priority level interrupt 10
310 		// -------------xxx Priority level interrupt 11
311 		case 0xC0/4:
312 			m_irq_priority[3] = ( data >> 0 ) & 0x07;
313 			m_irq_priority[2] = ( data >> 3 ) & 0x07;
314 			m_irq_priority[1] = ( data >> 6 ) & 0x07;
315 			m_irq_priority[0] = ( data >> 9 ) & 0x07;
316 			check_irqs();
317 			break;
318 	}
319 }
320 
321 
check_irqs()322 inline void pcfx_state::check_irqs()
323 {
324 	uint16_t active_irqs = m_irq_pending & ~m_irq_mask;
325 	int highest_prio = -1;
326 
327 	for (auto & elem : m_irq_priority)
328 	{
329 		if ( active_irqs & 0x80 )
330 		{
331 			if ( elem >= highest_prio )
332 			{
333 				highest_prio = elem;
334 			}
335 		}
336 		active_irqs <<= 1;
337 	}
338 
339 	if ( highest_prio >= 0 )
340 	{
341 		m_maincpu->set_input_line(8 + highest_prio, ASSERT_LINE );
342 	}
343 	else
344 	{
345 		m_maincpu->set_input_line(0, CLEAR_LINE );
346 	}
347 }
348 
349 
set_irq_line(int line,int state)350 inline void pcfx_state::set_irq_line(int line, int state)
351 {
352 	if ( state )
353 	{
354 //printf("Setting irq line %d\n", line);
355 		m_irq_pending |= ( 1 << ( 15 - line ) );
356 	}
357 	else
358 	{
359 //printf("Clearing irq line %d\n", line);
360 		m_irq_pending &= ~( 1 << ( 15 - line ) );
361 	}
362 	check_irqs();
363 }
364 
WRITE_LINE_MEMBER(pcfx_state::irq8_w)365 WRITE_LINE_MEMBER( pcfx_state::irq8_w )
366 {
367 	set_irq_line(8, state);
368 }
369 
WRITE_LINE_MEMBER(pcfx_state::irq9_w)370 WRITE_LINE_MEMBER( pcfx_state::irq9_w )
371 {
372 	set_irq_line(9, state);
373 }
374 
WRITE_LINE_MEMBER(pcfx_state::irq10_w)375 WRITE_LINE_MEMBER( pcfx_state::irq10_w )
376 {
377 	set_irq_line(10, state);
378 }
379 
WRITE_LINE_MEMBER(pcfx_state::irq11_w)380 WRITE_LINE_MEMBER( pcfx_state::irq11_w )
381 {
382 	set_irq_line(11, state);
383 }
384 
WRITE_LINE_MEMBER(pcfx_state::irq12_w)385 WRITE_LINE_MEMBER( pcfx_state::irq12_w )
386 {
387 	set_irq_line(12, state);
388 }
389 
WRITE_LINE_MEMBER(pcfx_state::irq13_w)390 WRITE_LINE_MEMBER( pcfx_state::irq13_w )
391 {
392 	set_irq_line(13, state);
393 }
394 
WRITE_LINE_MEMBER(pcfx_state::irq14_w)395 WRITE_LINE_MEMBER( pcfx_state::irq14_w )
396 {
397 	set_irq_line(14, state);
398 }
399 
WRITE_LINE_MEMBER(pcfx_state::irq15_w)400 WRITE_LINE_MEMBER( pcfx_state::irq15_w )
401 {
402 	set_irq_line(15, state);
403 }
404 
405 
machine_reset()406 void pcfx_state::machine_reset()
407 {
408 	m_irq_mask = 0xFF;
409 	m_irq_pending = 0;
410 }
411 
412 
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)413 uint32_t pcfx_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
414 {
415 	m_huc6261->video_update( bitmap, cliprect );
416 	return 0;
417 }
418 
419 
pcfx(machine_config & config)420 void pcfx_state::pcfx(machine_config &config)
421 {
422 	V810(config, m_maincpu, XTAL(21'477'272));
423 	m_maincpu->set_addrmap(AS_PROGRAM, &pcfx_state::pcfx_mem);
424 	m_maincpu->set_addrmap(AS_IO, &pcfx_state::pcfx_io);
425 
426 	screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
427 	screen.set_screen_update(FUNC(pcfx_state::screen_update));
428 	screen.set_raw(XTAL(21'477'272), huc6261_device::WPF, 64, 64 + 1024 + 64, huc6261_device::LPF, 18, 18 + 242);
429 
430 	huc6270_device &huc6270_a(HUC6270(config, "huc6270_a", 0));
431 	huc6270_a.set_vram_size(0x20000);
432 	huc6270_a.irq().set(FUNC(pcfx_state::irq12_w));
433 
434 	huc6270_device &huc6270_b(HUC6270(config, "huc6270_b", 0));
435 	huc6270_b.set_vram_size(0x20000);
436 	huc6270_b.irq().set(FUNC(pcfx_state::irq14_w));
437 
438 	HUC6261(config, m_huc6261, XTAL(21'477'272));
439 	m_huc6261->set_vdc1_tag("huc6270_a");
440 	m_huc6261->set_vdc2_tag("huc6270_b");
441 	m_huc6261->set_king_tag("huc6272");
442 
443 	huc6272_device &huc6272(HUC6272(config, "huc6272", XTAL(21'477'272)));
444 	huc6272.irq_changed_callback().set(FUNC(pcfx_state::irq13_w));
445 	huc6272.set_rainbow_tag("huc6271");
446 
447 	HUC6271(config, "huc6271", XTAL(21'477'272));
448 
449 	SOFTWARE_LIST(config, "cd_list").set_original("pcfx");
450 
451 	/* sound hardware */
452 	SPEAKER(config, "lspeaker").front_left();
453 	SPEAKER(config, "rspeaker").front_right();
454 
455 	huc6230_device &huc6230(HuC6230(config, "huc6230", XTAL(21'477'272)));
456 	huc6230.adpcm_update_cb<0>().set("huc6272", FUNC(huc6272_device::adpcm_update_0));
457 	huc6230.adpcm_update_cb<1>().set("huc6272", FUNC(huc6272_device::adpcm_update_1));
458 	huc6230.vca_callback().set("huc6272", FUNC(huc6272_device::cdda_update));
459 	huc6230.add_route(0, "lspeaker", 1.0);
460 	huc6230.add_route(1, "rspeaker", 1.0);
461 }
462 
463 
464 ROM_START( pcfx )
465 	ROM_REGION32_LE( 0x100000, "ipl", 0 )
466 	ROM_SYSTEM_BIOS( 0, "v100", "BIOS v1.00 - 2 Sep 1994" )
467 	ROMX_LOAD( "pcfxbios.bin", 0x000000, 0x100000, CRC(76ffb97a) SHA1(1a77fd83e337f906aecab27a1604db064cf10074), ROM_BIOS(0) )
468 	ROM_SYSTEM_BIOS( 1, "v101", "BIOS v1.01 - 5 Dec 1994" )
469 	ROMX_LOAD( "pcfxv101.bin", 0x000000, 0x100000, CRC(236102c9) SHA1(8b662f7548078be52a871565e19511ccca28c5c8), ROM_BIOS(1) )
470 
471 	ROM_REGION32_LE( 0x80000, "scsi_rom", 0 )
472 	ROM_LOAD( "fx-scsi.rom", 0x00000, 0x80000, CRC(f3e60e5e) SHA1(65482a23ac5c10a6095aee1db5824cca54ead6e5) )
473 ROM_END
474 
475 
476 ROM_START( pcfxga )
477 	ROM_REGION32_LE( 0x100000, "ipl", 0 )
478 	ROM_LOAD( "pcfxga.rom", 0x000000, 0x100000, CRC(41c3776b) SHA1(a9372202a5db302064c994fcda9b24d29bb1b41c) )
479 
480 	ROM_REGION32_LE( 0x80000, "scsi_rom", ROMREGION_ERASEFF )
481 ROM_END
482 
483 
484 /***************************************************************************
485 
486   Game driver(s)
487 
488 ***************************************************************************/
489 
490 //    YEAR  NAME    PARENT  COMPAT  MACHINE  INPUT  CLASS       INIT        COMPANY  FULLNAME                  FLAGS
491 CONS( 1994, pcfx,   0,      0,      pcfx,    pcfx,  pcfx_state, empty_init, "NEC",   "PC-FX",                  MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
492 CONS( 199?, pcfxga, pcfx,   0,      pcfx,    pcfx,  pcfx_state, empty_init, "NEC",   "PC-FX/GA (PC ISA Card)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
493