1 // license:GPL-2.0+
2 // copyright-holders: Felipe Sanches
3 /***************************************************************************
4 
5   SONY PVE-500 Editing Control Unit
6   "A/B roll edit controller for professional video editing applications"
7 
8   Driver by Felipe Correa da Silva Sanches <juca@members.fsf.org>
9   Technical info at https://www.garoa.net.br/wiki/PVE-500
10 
11   Notes:
12   One can induce the self-diagnose by booting the device holding LEARN and P2-RESET buttons togheter
13   With the default keyboard map, this can be done by holding keys L and S while pressing F3.
14     (Don't forget to unlock the keyboard by using the UI TOGGLE key)
15 
16     This self-diagnose routine displays the value C817, which is the checksum value of the subcpu ROM
17   and afterwards it displays the following message:
18 
19   SELFdIAG Error___ _F3 F3_CtC3c
20 
21   which means it detected an error in the CTC circuitry (it means we're emulating it wrong!)
22   F3 is the coordinate of the subcpu EPROM chip in the PCB.
23 
24     According to the service manual, this error code means: "ICF3 CTC CH-3 counter operation failure (No interruption)"
25 
26   Known issues:
27   There's still an annoying blinking in the 7-seg display.
28 
29   Changelog:
30 
31      2014 SEP 01 [Felipe Sanches]:
32    * hooked-up MB8421 device (dual-port SRAM)
33 
34      2014 JUN 24 [Felipe Sanches]:
35    * figured out the multiplexing signals for the 7-seg display
36 
37      2014 JUN 23 [Felipe Sanches]:
38    * hooked-up the RS422 ports
39 
40    2014 JAN 14 [Felipe Sanches]:
41    * Initial driver skeleton
42 */
43 
44 #define LOG_7SEG_DISPLAY_SIGNALS 0
45 #define DEBUGGING_INDUCE_SELFDIAGNOSE 0
46 
47 #include "emu.h"
48 #include "bus/rs232/rs232.h" /* actually meant to be RS422 ports */
49 #include "cpu/mb88xx/mb88xx.h"
50 #include "cpu/z80/tmpz84c015.h"
51 #include "machine/clock.h"
52 #include "machine/cxd1095.h"
53 #include "machine/eepromser.h"
54 #include "machine/mb8421.h"
55 #include "machine/z80sio.h"
56 #include "sound/beep.h"
57 #include "speaker.h"
58 
59 #include "pve500.lh"
60 
61 #define IO_EXPANDER_PORTA 0
62 #define IO_EXPANDER_PORTB 1
63 #define IO_EXPANDER_PORTC 2
64 #define IO_EXPANDER_PORTD 3
65 #define IO_EXPANDER_PORTE 4
66 
67 class pve500_state : public driver_device
68 {
69 public:
pve500_state(const machine_config & mconfig,device_type type,const char * tag)70 	pve500_state(const machine_config &mconfig, device_type type, const char *tag)
71 		: driver_device(mconfig, type, tag)
72 		, m_maincpu(*this, "maincpu")
73 		, m_subcpu(*this, "subcpu")
74 		, m_cxdio(*this, "cxdio")
75 		, m_eeprom(*this, "eeprom")
76 		, m_buzzer(*this, "buzzer")
77 		, m_digits(*this, "digit%u", 0U)
78 	{ }
79 
80 	void pve500(machine_config &config);
81 
82 	void init_pve500();
83 
84 private:
85 	DECLARE_WRITE_LINE_MEMBER(mb8421_intl);
86 	DECLARE_WRITE_LINE_MEMBER(mb8421_intr);
87 	DECLARE_WRITE_LINE_MEMBER(GPI_w);
88 	DECLARE_WRITE_LINE_MEMBER(cxdio_reset_w);
89 	DECLARE_WRITE_LINE_MEMBER(external_monitor_w);
90 
91 	uint8_t io_ky_r();
92 	void io_sc_w(uint8_t data);
93 	void io_le_w(uint8_t data);
94 	void io_ld_w(uint8_t data);
95 	void io_sel_w(uint8_t data);
96 	void eeprom_w(uint8_t data);
97 	uint8_t eeprom_r();
98 	void maincpu_io(address_map &map);
99 	void maincpu_prg(address_map &map);
100 	void subcpu_io(address_map &map);
101 	void subcpu_prg(address_map &map);
102 
103 	virtual void machine_start() override;
104 	virtual void machine_reset() override;
105 	required_device<tmpz84c015_device> m_maincpu;
106 	required_device<tmpz84c015_device> m_subcpu;
107 	required_device<cxd1095_device> m_cxdio;
108 	required_device<eeprom_serial_er5911_device> m_eeprom;
109 	required_device<beep_device> m_buzzer;
110 	output_finder<27> m_digits;
111 
112 	uint8_t io_SEL, io_LD, io_LE, io_SC, io_KY;
113 	int LD_data[4];
114 };
115 
WRITE_LINE_MEMBER(pve500_state::GPI_w)116 WRITE_LINE_MEMBER(pve500_state::GPI_w)
117 {
118 	/* TODO: Implement-me */
119 }
120 
WRITE_LINE_MEMBER(pve500_state::cxdio_reset_w)121 WRITE_LINE_MEMBER(pve500_state::cxdio_reset_w)
122 {
123 	if (!state)
124 		m_cxdio->reset();
125 }
126 
WRITE_LINE_MEMBER(pve500_state::external_monitor_w)127 WRITE_LINE_MEMBER(pve500_state::external_monitor_w)
128 {
129 	/* TODO: Implement-me */
130 }
131 
132 static const z80_daisy_config maincpu_daisy_chain[] =
133 {
134 	{ "external_ctc" },
135 	{ "external_sio" },
136 	{ nullptr }
137 };
138 
139 
maincpu_io(address_map & map)140 void pve500_state::maincpu_io(address_map &map)
141 {
142 	map(0x00, 0x03).mirror(0xff00).rw("external_sio", FUNC(z80sio_device::cd_ba_r), FUNC(z80sio_device::cd_ba_w));
143 	map(0x08, 0x0B).mirror(0xff00).rw("external_ctc", FUNC(z80ctc_device::read), FUNC(z80ctc_device::write));
144 }
145 
maincpu_prg(address_map & map)146 void pve500_state::maincpu_prg(address_map &map)
147 {
148 	map(0x0000, 0xbfff).rom(); // ICB7: 48kbytes EPROM
149 	map(0xc000, 0xdfff).ram(); // ICD6: 8kbytes of RAM
150 	map(0xe000, 0xe7ff).mirror(0x1800).rw("mb8421", FUNC(mb8421_device::left_r), FUNC(mb8421_device::left_w));
151 }
152 
subcpu_io(address_map & map)153 void pve500_state::subcpu_io(address_map &map)
154 {
155 }
156 
subcpu_prg(address_map & map)157 void pve500_state::subcpu_prg(address_map &map)
158 {
159 	map(0x0000, 0x7fff).rom(); // ICG5: 32kbytes EPROM
160 	map(0x8000, 0x8007).mirror(0x3ff8).rw(m_cxdio, FUNC(cxd1095_device::read), FUNC(cxd1095_device::write));
161 	map(0xc000, 0xc7ff).mirror(0x3800).rw("mb8421", FUNC(mb8421_device::right_r), FUNC(mb8421_device::right_w));
162 }
163 
init_pve500()164 void pve500_state::init_pve500()
165 {
166 }
167 
168 static INPUT_PORTS_START( pve500 )
169 	PORT_START("SCAN0")
PORT_CODE(KEYCODE_5)170 	PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("TRANS")       PORT_CODE(KEYCODE_5)
171 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A/B")         PORT_CODE(KEYCODE_4)
172 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("FROM TO")     PORT_CODE(KEYCODE_3)
173 	PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P2")          PORT_CODE(KEYCODE_2)
174 	PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P1")          PORT_CODE(KEYCODE_1)
175 	PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_UNUSED)
176 	PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_UNUSED)
177 	PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ENTRY")       PORT_CODE(KEYCODE_SPACE)
178 
179 	PORT_START("SCAN1")
180 	PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ALL STOP")    PORT_CODE(KEYCODE_M)
181 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("LAST EDIT")   PORT_CODE(KEYCODE_I)
182 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("AUDIO SPLIT") PORT_CODE(KEYCODE_T)
183 	PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A2")          PORT_CODE(KEYCODE_9)
184 	PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ASMBL")       PORT_CODE(KEYCODE_6)
185 	PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("V")           PORT_CODE(KEYCODE_7)
186 	PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A1")          PORT_CODE(KEYCODE_8)
187 	PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ENTRY")       PORT_CODE(KEYCODE_SPACE)
188 
189 	PORT_START("SCAN2")
190 	PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RVW/JUMP")    PORT_CODE(KEYCODE_N)
191 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("AUTO EDIT")   PORT_CODE(KEYCODE_B)
192 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("PREVIEW")     PORT_CODE(KEYCODE_V)
193 	PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P-FF")        PORT_CODE(KEYCODE_R)
194 	PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P-REW")       PORT_CODE(KEYCODE_E)
195 	PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P-STILL")     PORT_CODE(KEYCODE_W)
196 	PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P-PLAY")      PORT_CODE(KEYCODE_Q)
197 	PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ENTRY")       PORT_CODE(KEYCODE_SPACE)
198 
199 	PORT_START("SCAN3")
200 	PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R-OUT")       PORT_CODE(KEYCODE_K)
201 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R-IN")        PORT_CODE(KEYCODE_J)
202 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("GO TO")       PORT_CODE(KEYCODE_H)
203 	PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P-OUT")       PORT_CODE(KEYCODE_G)
204 	PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P-IN")        PORT_CODE(KEYCODE_F)
205 	PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("TRIM+")       PORT_CODE(KEYCODE_U)
206 	PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("TRIM-")       PORT_CODE(KEYCODE_Y)
207 	PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ENTRY")       PORT_CODE(KEYCODE_SPACE)
208 
209 	PORT_START("SCAN4")
210 	PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R-FF")        PORT_CODE(KEYCODE_OPENBRACE)
211 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R-REW")       PORT_CODE(KEYCODE_QUOTE)
212 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R-STILL")     PORT_CODE(KEYCODE_P)
213 	PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R-PLAY")      PORT_CODE(KEYCODE_O)
214 	PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("EDIT")        PORT_CODE(KEYCODE_EQUALS)
215 	PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("REC")         PORT_CODE(KEYCODE_MINUS)
216 	PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_UNUSED)
217 	PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ENTRY")       PORT_CODE(KEYCODE_SPACE)
218 
219 	PORT_START("SCAN5")
220 		PORT_DIPNAME( 0x03, 0x02, "R-EDIT REF" )
221 		PORT_DIPSETTING(    0x02, "TC" )
222 		PORT_DIPSETTING(    0x00, "RTC" )
223 		PORT_DIPSETTING(    0x01, "CTL" )
224 
225 		PORT_DIPNAME( 0x0C, 0x08, "P2-EDIT REF" )
226 		PORT_DIPSETTING(    0x08, "TC" )
227 		PORT_DIPSETTING(    0x00, "RTC" )
228 		PORT_DIPSETTING(    0x04, "CTL" )
229 
230 		PORT_DIPNAME( 0x30, 0x20, "P1-EDIT REF" )
231 		PORT_DIPSETTING(    0x20, "TC" )
232 		PORT_DIPSETTING(    0x00, "RTC" )
233 		PORT_DIPSETTING(    0x10, "CTL" )
234 
235 	PORT_START("SCAN6")
236 		PORT_DIPNAME( 0x03, 0x02, "SYNCHRO" )
237 		PORT_DIPSETTING(    0x02, "ON/CF" )
238 		PORT_DIPSETTING(    0x00, "ON" )
239 		PORT_DIPSETTING(    0x01, "OFF" )
240 
241 		PORT_DIPNAME( 0x0C, 0x08, "PREROLL" )
242 		PORT_DIPSETTING(    0x08, "7" )
243 		PORT_DIPSETTING(    0x00, "5" )
244 		PORT_DIPSETTING(    0x04, "3" )
245 
246 	PORT_START("SCAN7")
247 	PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("TOTAL")       PORT_CODE(KEYCODE_CLOSEBRACE)
248 	PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("LEARN")       PORT_CODE(KEYCODE_L)
249 	PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("TRANS-1F")    PORT_CODE(KEYCODE_Z)
250 	PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("TRANS-10F")   PORT_CODE(KEYCODE_X)
251 	PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("TRANS-100F")  PORT_CODE(KEYCODE_C)
252 	PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R-RESET")     PORT_CODE(KEYCODE_A)
253 	PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P2-RESET")    PORT_CODE(KEYCODE_S)
254 	PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P1-RESET")    PORT_CODE(KEYCODE_D)
255 INPUT_PORTS_END
256 
257 void pve500_state::machine_start()
258 {
259 	io_LD = 0;
260 	io_SC = 0;
261 	io_LE = 0;
262 	io_SEL = 0;
263 	io_KY = 0;
264 	m_digits.resolve();
265 }
266 
machine_reset()267 void pve500_state::machine_reset()
268 {
269 	/* Setup beep */
270 	m_buzzer->set_state(0);
271 }
272 
WRITE_LINE_MEMBER(pve500_state::mb8421_intl)273 WRITE_LINE_MEMBER(pve500_state::mb8421_intl)
274 {
275 	// shared ram interrupt request from subcpu side
276 	m_maincpu->trg1(state);
277 }
278 
WRITE_LINE_MEMBER(pve500_state::mb8421_intr)279 WRITE_LINE_MEMBER(pve500_state::mb8421_intr)
280 {
281 	// shared ram interrupt request from maincpu side
282 	m_subcpu->trg1(state);
283 }
284 
eeprom_r()285 uint8_t pve500_state::eeprom_r()
286 {
287 	return (m_eeprom->ready_read() << 1) | m_eeprom->do_read();
288 }
289 
eeprom_w(uint8_t data)290 void pve500_state::eeprom_w(uint8_t data)
291 {
292 	m_eeprom->di_write( (data & (1 << 2)) ? ASSERT_LINE : CLEAR_LINE);
293 	m_eeprom->clk_write( (data & (1 << 3)) ? ASSERT_LINE : CLEAR_LINE);
294 	m_eeprom->cs_write( (data & (1 << 4)) ? ASSERT_LINE : CLEAR_LINE);
295 }
296 
io_ky_r()297 uint8_t pve500_state::io_ky_r()
298 {
299 	io_KY = 0x00;
300 	if (!BIT(io_SC, 0)) io_KY |= ioport("SCAN0")->read();
301 	if (!BIT(io_SC, 1)) io_KY |= ioport("SCAN1")->read();
302 	if (!BIT(io_SC, 2)) io_KY |= ioport("SCAN2")->read();
303 	if (!BIT(io_SC, 3)) io_KY |= ioport("SCAN3")->read();
304 	if (!BIT(io_SC, 4)) io_KY |= ioport("SCAN4")->read();
305 	if (!BIT(io_SC, 5)) io_KY |= ioport("SCAN5")->read();
306 	if (!BIT(io_SC, 6)) io_KY |= ioport("SCAN6")->read();
307 	if (!BIT(io_SC, 7)) io_KY |= ioport("SCAN7")->read();
308 #if DEBUGGING_INDUCE_SELFDIAGNOSE
309 	io_KY = 0x42; //according to procedure described in the service manual
310 #endif
311 	return io_KY;
312 }
313 
io_sc_w(uint8_t data)314 void pve500_state::io_sc_w(uint8_t data)
315 {
316 	const int swap[4] = {2,1,0,3};
317 
318 #if LOG_7SEG_DISPLAY_SIGNALS
319 	printf("CXD1095 PORTA (io_SC=%02X)\n", data);
320 #endif
321 	io_SC = data;
322 
323 	for (int j=0; j<8; j++){
324 		if (!BIT(io_SC,j)){
325 			int digits = (j < 3) ? 4 : 3;
326 			for (int i = 0; i < digits; i++)
327 			{
328 				assert(8*swap[i] + j < 27);
329 				m_digits[8*swap[i] + j] = LD_data[i];
330 			}
331 		}
332 	}
333 }
334 
io_le_w(uint8_t data)335 void pve500_state::io_le_w(uint8_t data)
336 {
337 #if LOG_7SEG_DISPLAY_SIGNALS
338 	printf("CXD1095 PORTB (io_LE=%02X)\n", data);
339 #endif
340 	io_LE = data;
341 }
342 
io_ld_w(uint8_t data)343 void pve500_state::io_ld_w(uint8_t data)
344 {
345 #if LOG_7SEG_DISPLAY_SIGNALS
346 	printf("CXD1095 PORTD (io_LD=%02X)\n", data);
347 #endif
348 	io_LD = data;
349 }
350 
io_sel_w(uint8_t data)351 void pve500_state::io_sel_w(uint8_t data)
352 {
353 #if LOG_7SEG_DISPLAY_SIGNALS
354 	printf("CXD1095 PORTE (io_SEL=%02X)\n", data);
355 #endif
356 	io_SEL = data;
357 	for (int i=0; i<4; i++){
358 		if (BIT(io_SEL, i)){
359 			LD_data[i] = 0x7F & bitswap<8>(io_LD ^ 0xFF, 7, 0, 1, 2, 3, 4, 5, 6);
360 		}
361 	}
362 }
363 
pve500(machine_config & config)364 void pve500_state::pve500(machine_config &config)
365 {
366 	/* Main CPU */
367 	TMPZ84C015(config, m_maincpu, 12_MHz_XTAL / 2); // TMPZ84C015BF-6
368 	m_maincpu->set_addrmap(AS_PROGRAM, &pve500_state::maincpu_prg);
369 	m_maincpu->set_addrmap(AS_IO, &pve500_state::maincpu_io);
370 	m_maincpu->set_daisy_config(maincpu_daisy_chain);
371 	m_maincpu->out_dtra_callback().set(FUNC(pve500_state::GPI_w));
372 	m_maincpu->out_dtrb_callback().set(m_buzzer, FUNC(beep_device::set_state)).invert();
373 	m_maincpu->out_txda_callback().set("recorder", FUNC(rs232_port_device::write_txd));
374 	m_maincpu->out_txdb_callback().set("player1", FUNC(rs232_port_device::write_txd));
375 
376 	z80ctc_device& ctc(Z80CTC(config, "external_ctc", 12_MHz_XTAL / 2));
377 	ctc.intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
378 
379 	z80sio_device& sio(Z80SIO(config, "external_sio", 12_MHz_XTAL / 2)); // TMPZ84C40AP-8
380 	sio.out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
381 	sio.out_txda_callback().set("player2", FUNC(rs232_port_device::write_txd));
382 	sio.out_txdb_callback().set("edl_inout", FUNC(rs232_port_device::write_txd));
383 
384 	/* Secondary CPU */
385 	TMPZ84C015(config, m_subcpu, 12_MHz_XTAL / 2); /* TMPZ84C015BF-6 */
386 	m_subcpu->set_addrmap(AS_PROGRAM, &pve500_state::subcpu_prg);
387 	m_subcpu->set_addrmap(AS_IO, &pve500_state::subcpu_io);
388 	m_subcpu->out_dtra_callback().set(FUNC(pve500_state::cxdio_reset_w));
389 	m_subcpu->out_dtrb_callback().set(FUNC(pve500_state::external_monitor_w));
390 	m_subcpu->out_txda_callback().set("switcher", FUNC(rs232_port_device::write_txd));
391 	m_subcpu->out_txdb_callback().set("serial_mixer", FUNC(rs232_port_device::write_txd));
392 
393 	// PIO callbacks
394 	m_subcpu->in_pa_callback().set(FUNC(pve500_state::eeprom_r));
395 	m_subcpu->out_pa_callback().set(FUNC(pve500_state::eeprom_w));
396 
397 	// ICG3: I/O Expander
398 	CXD1095(config, m_cxdio);
399 	m_cxdio->out_porta_cb().set(FUNC(pve500_state::io_sc_w));
400 	m_cxdio->out_portb_cb().set(FUNC(pve500_state::io_le_w));
401 	m_cxdio->in_portc_cb().set(FUNC(pve500_state::io_ky_r));
402 	m_cxdio->out_portd_cb().set(FUNC(pve500_state::io_ld_w));
403 	m_cxdio->out_porte_cb().set(FUNC(pve500_state::io_sel_w));
404 
405 	/* Search Dial MCUs */
406 	MB88201(config, "dial_mcu_left", 4_MHz_XTAL).set_disable(); /* PLAYER DIAL MCU */
407 	MB88201(config, "dial_mcu_right", 4_MHz_XTAL).set_disable(); /* RECORDER DIAL MCU */
408 
409 	/* Serial EEPROM (128 bytes, 8-bit data organization) */
410 	/* The EEPROM stores the setup data */
411 	EEPROM_MSM16911_8BIT(config, "eeprom");
412 
413 	/* FIX-ME: These are actually RS422 ports (except EDL IN/OUT which is indeed an RS232 port)*/
414 	rs232_port_device &recorder(RS232_PORT(config, "recorder", default_rs232_devices, nullptr));
415 	recorder.rxd_handler().set(m_maincpu, FUNC(tmpz84c015_device::rxa_w));
416 
417 	rs232_port_device &player1(RS232_PORT(config, "player1", default_rs232_devices, nullptr));
418 	player1.rxd_handler().set(m_maincpu, FUNC(tmpz84c015_device::rxb_w));
419 
420 	rs232_port_device &player2(RS232_PORT(config, "player2", default_rs232_devices, nullptr));
421 	player2.rxd_handler().set("external_sio", FUNC(z80sio_device::rxa_w));
422 
423 	rs232_port_device &edl_inout(RS232_PORT(config, "edl_inout", default_rs232_devices, nullptr));
424 	edl_inout.rxd_handler().set("external_sio", FUNC(z80sio_device::rxb_w));
425 
426 	rs232_port_device &switcher(RS232_PORT(config, "switcher", default_rs232_devices, nullptr));
427 	switcher.rxd_handler().set(m_subcpu, FUNC(tmpz84c015_device::rxa_w));
428 
429 	rs232_port_device &serial_mixer(RS232_PORT(config, "serial_mixer", default_rs232_devices, nullptr));
430 	serial_mixer.rxd_handler().set(m_subcpu, FUNC(tmpz84c015_device::rxb_w));
431 
432 	clock_device &clk1(CLOCK(config, "clk1", 12_MHz_XTAL / 20));
433 	clk1.signal_handler().set(m_maincpu, FUNC(tmpz84c015_device::rxca_w));
434 	clk1.signal_handler().append(m_maincpu, FUNC(tmpz84c015_device::txca_w));
435 	clk1.signal_handler().append(m_maincpu, FUNC(tmpz84c015_device::rxcb_w));
436 	clk1.signal_handler().append(m_maincpu, FUNC(tmpz84c015_device::txcb_w));
437 	clk1.signal_handler().append(m_subcpu, FUNC(tmpz84c015_device::rxca_w));
438 	clk1.signal_handler().append(m_subcpu, FUNC(tmpz84c015_device::txca_w));
439 	clk1.signal_handler().append(m_subcpu, FUNC(tmpz84c015_device::rxcb_w));
440 	clk1.signal_handler().append(m_subcpu, FUNC(tmpz84c015_device::txcb_w));
441 
442 	/* ICF5: 2kbytes of RAM shared between the two CPUs (dual-port RAM)*/
443 	mb8421_device &mb8421(MB8421(config, "mb8421"));
444 	mb8421.intl_callback().set(FUNC(pve500_state::mb8421_intl));
445 	mb8421.intr_callback().set(FUNC(pve500_state::mb8421_intr));
446 
447 	/* video hardware */
448 	config.set_default_layout(layout_pve500);
449 
450 	/* audio hardware */
451 	SPEAKER(config, "mono").front_center();
452 	BEEP(config, "buzzer", 12_MHz_XTAL / 3200).add_route(ALL_OUTPUTS, "mono", 0.05); // 3.75 kHz CLK2 coming out of IC D4 (frequency divider circuitry)
453 }
454 
455 ROM_START( pve500 )
456 	ROM_REGION( 0x10000, "maincpu", 0 )
457 	ROM_LOAD("pve500.icb7",  0x00000, 0x10000, CRC(1036709c) SHA1(207d6fcad5c2f081a138184060ce7bd02736965b) ) //48kbyte main-cpu program + 16kbyte of unreachable memory
458 
459 	ROM_REGION( 0x8000, "subcpu", 0 )
460 	ROM_LOAD("pve500.icg5",  0x00000, 0x8000, CRC(28cca60a) SHA1(308d70062653769250327ede7a4e1a8a76fc9ab9) ) //32kbyte sub-cpu program
461 
462 	ROM_REGION( 0x200, "dial_mcu_left", 0 ) /* PLAYER DIAL MCU */
463 	ROM_LOAD( "pve500.icd3", 0x0000, 0x0200, NO_DUMP )
464 
465 	ROM_REGION( 0x200, "dial_mcu_right", 0 ) /* RECORDER DIAL MCU */
466 	ROM_LOAD( "pve500.icc3", 0x0000, 0x0200, NO_DUMP )
467 
468 	ROM_REGION( 0x80, "eeprom", 0 ) /* The EEPROM stores the setup data */
469 	ROM_LOAD( "pve500.ice3", 0x0000, 0x080, NO_DUMP )
470 ROM_END
471 
472 //    YEAR  NAME    PARENT  COMPAT  MACHINE  INPUT   CLASS         INIT         COMPANY  FULLNAME   FLAGS
473 COMP( 1995, pve500, 0,      0,      pve500,  pve500, pve500_state, init_pve500, "SONY",  "PVE-500", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS)
474