1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /**********************************************************************
4 
5     Sinclair ZX8302 emulation
6 
7 **********************************************************************/
8 
9 /*
10 
11     TODO:
12 
13     - set time
14     - read from microdrive
15     - write to microdrive
16     - DTR/CTS handling
17     - network
18 
19 */
20 
21 #include "emu.h"
22 #include "zx8302.h"
23 
24 #include "imagedev/microdrv.h"
25 
26 #include <ctime>
27 
28 
29 
30 //**************************************************************************
31 //  MACROS / CONSTANTS
32 //**************************************************************************
33 
34 #define LOG 0
35 
36 
37 // Monday 1st January 1979 00:00:00 UTC
38 static const int RTC_BASE_ADJUST = 283996800;
39 
40 
41 
42 //**************************************************************************
43 //  DEVICE DEFINITIONS
44 //**************************************************************************
45 
46 DEFINE_DEVICE_TYPE(ZX8302, zx8302_device, "zx8302", "Sinclair ZX8302")
47 
48 //**************************************************************************
49 //  INLINE HELPERS
50 //**************************************************************************
51 
52 //-------------------------------------------------
53 //  trigger_interrupt -
54 //-------------------------------------------------
55 
trigger_interrupt(uint8_t line)56 inline void zx8302_device::trigger_interrupt(uint8_t line)
57 {
58 	m_irq |= line;
59 
60 	m_out_ipl1l_cb(ASSERT_LINE);
61 }
62 
63 
64 //-------------------------------------------------
65 //  transmit_ipc_data - transmit IPC data
66 //-------------------------------------------------
67 
transmit_ipc_data()68 inline void zx8302_device::transmit_ipc_data()
69 {
70 	/*
71 
72 	    IPC <-> ZX8302 serial link protocol
73 	    ***********************************
74 
75 	    Send bit to IPC
76 	    ---------------
77 
78 	    1. ZX start bit (COMDATA = 0)
79 	    2. IPC clock (COMCTL = 0, COMTL = 1)
80 	    3. ZX data bit (COMDATA = 0/1)
81 	    4. IPC clock (COMCTL = 0, COMTL = 1)
82 	    5. ZX stop bit (COMDATA = 1)
83 
84 	    Receive bit from IPC
85 	    --------------------
86 
87 	    1. ZX start bit (COMDATA = 0)
88 	    2. IPC clock (COMCTL = 0, COMTL = 1)
89 	    3. IPC data bit (COMDATA = 0/1)
90 	    4. IPC clock (COMCTL = 0, COMTL = 1)
91 	    5. IPC stop bit (COMDATA = 1)
92 
93 	*/
94 
95 	switch (m_ipc_state)
96 	{
97 	case IPC_START:
98 		if (LOG) logerror("ZX8302 '%s' COMDATA Start Bit\n", tag());
99 
100 		m_out_comdata_cb(BIT(m_idr, 0));
101 		m_ipc_busy = 1;
102 		m_ipc_state = IPC_DATA;
103 		break;
104 
105 	case IPC_DATA:
106 		if (LOG) logerror("ZX8302 '%s' COMDATA Data Bit: %x\n", tag(), BIT(m_idr, 1));
107 
108 		m_comdata_to_ipc = BIT(m_idr, 1);
109 		m_out_comdata_cb(m_comdata_to_ipc);
110 		m_ipc_state = IPC_STOP;
111 		break;
112 
113 	case IPC_STOP:
114 		if (LOG) logerror("ZX8302 '%s' COMDATA Stop Bit\n", tag());
115 
116 		m_out_comdata_cb(BIT(m_idr, 2));
117 		m_ipc_busy = 0;
118 		break;
119 	}
120 }
121 
122 
123 
124 //**************************************************************************
125 //  LIVE DEVICE
126 //**************************************************************************
127 
128 //-------------------------------------------------
129 //  zx8302_device - constructor
130 //-------------------------------------------------
131 
zx8302_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)132 zx8302_device::zx8302_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
133 	: device_t(mconfig, ZX8302, tag, owner, clock),
134 		device_serial_interface(mconfig, *this),
135 		m_rtc_clock(0),
136 		m_out_ipl1l_cb(*this),
137 		m_out_baudx4_cb(*this),
138 		m_out_comdata_cb(*this),
139 		m_out_txd1_cb(*this),
140 		m_out_txd2_cb(*this),
141 		m_out_netout_cb(*this),
142 		m_out_mdselck_cb(*this),
143 		m_out_mdseld_cb(*this),
144 		m_out_mdrdw_cb(*this),
145 		m_out_erase_cb(*this),
146 		m_out_raw1_cb(*this),
147 		m_in_raw1_cb(*this),
148 		m_out_raw2_cb(*this),
149 		m_in_raw2_cb(*this),
150 		m_dtr1(0),
151 		m_cts2(0),
152 		m_idr(1),
153 		m_irq(0),
154 		m_ctr(time(nullptr) + RTC_BASE_ADJUST),
155 		m_status(0),
156 		m_comdata_from_ipc(1),
157 		m_comdata_to_cpu(1),
158 		m_comdata_to_ipc(1),
159 		m_comctl(1),
160 		m_ipc_state(0),
161 		m_ipc_busy(0),
162 		m_baudx4(0),
163 		m_track(0)
164 {
165 }
166 
167 
168 //-------------------------------------------------
169 //  device_start - device-specific startup
170 //-------------------------------------------------
171 
device_start()172 void zx8302_device::device_start()
173 {
174 	// resolve callbacks
175 	m_out_ipl1l_cb.resolve_safe();
176 	m_out_baudx4_cb.resolve_safe();
177 	m_out_comdata_cb.resolve_safe();
178 	m_out_txd1_cb.resolve_safe();
179 	m_out_txd2_cb.resolve_safe();
180 	m_out_netout_cb.resolve_safe();
181 	m_out_mdselck_cb.resolve_safe();
182 	m_out_mdseld_cb.resolve_safe();
183 	m_out_mdrdw_cb.resolve_safe();
184 	m_out_erase_cb.resolve_safe();
185 	m_out_raw1_cb.resolve_safe();
186 	m_in_raw1_cb.resolve_safe(0);
187 	m_out_raw2_cb.resolve_safe();
188 	m_in_raw2_cb.resolve_safe(0);
189 
190 	// allocate timers
191 	m_baudx4_timer = timer_alloc(TIMER_BAUDX4);
192 	m_rtc_timer = timer_alloc(TIMER_RTC);
193 	m_gap_timer = timer_alloc(TIMER_GAP);
194 
195 	m_rtc_timer->adjust(attotime::zero, 0, attotime::from_hz(m_rtc_clock / 32768));
196 	m_gap_timer->adjust(attotime::zero, 0, attotime::from_msec(31));
197 
198 	// register for state saving
199 	save_item(NAME(m_dtr1));
200 	save_item(NAME(m_cts2));
201 	save_item(NAME(m_idr));
202 	save_item(NAME(m_tcr));
203 	save_item(NAME(m_tdr));
204 	save_item(NAME(m_irq));
205 	save_item(NAME(m_ctr));
206 	save_item(NAME(m_status));
207 	save_item(NAME(m_comdata_from_ipc));
208 	save_item(NAME(m_comdata_to_cpu));
209 	save_item(NAME(m_comdata_to_ipc));
210 	save_item(NAME(m_comctl));
211 	save_item(NAME(m_ipc_state));
212 	save_item(NAME(m_ipc_busy));
213 	save_item(NAME(m_baudx4));
214 	save_item(NAME(m_mdv_data));
215 	save_item(NAME(m_track));
216 }
217 
218 
219 //-------------------------------------------------
220 //  device_timer - handler timer events
221 //-------------------------------------------------
222 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)223 void zx8302_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
224 {
225 	switch (id)
226 	{
227 	case TIMER_BAUDX4:
228 		m_baudx4 = !m_baudx4;
229 		m_out_baudx4_cb(m_baudx4);
230 		break;
231 
232 	case TIMER_RTC:
233 		m_ctr++;
234 		break;
235 
236 	case TIMER_GAP:
237 		trigger_interrupt(INT_GAP);
238 		break;
239 
240 	default:
241 		break;
242 	}
243 }
244 
245 
246 //-------------------------------------------------
247 //  tra_callback -
248 //-------------------------------------------------
249 
tra_callback()250 void zx8302_device::tra_callback()
251 {
252 	switch (m_tcr & MODE_MASK)
253 	{
254 	case MODE_SER1:
255 		m_out_txd1_cb(transmit_register_get_data_bit());
256 		break;
257 
258 	case MODE_SER2:
259 		m_out_txd2_cb(transmit_register_get_data_bit());
260 		break;
261 
262 	case MODE_MDV:
263 		// TODO
264 		break;
265 
266 	case MODE_NET:
267 		m_out_netout_cb(transmit_register_get_data_bit());
268 		break;
269 	}
270 }
271 
272 
273 //-------------------------------------------------
274 //  tra_complete -
275 //-------------------------------------------------
276 
tra_complete()277 void zx8302_device::tra_complete()
278 {
279 	m_status &= ~STATUS_TX_BUFFER_FULL;
280 
281 	trigger_interrupt(INT_TRANSMIT);
282 }
283 
284 
285 //-------------------------------------------------
286 //  rcv_callback -
287 //-------------------------------------------------
288 
rcv_callback()289 void zx8302_device::rcv_callback()
290 {
291 	switch (m_tcr & MODE_MASK)
292 	{
293 	case MODE_NET:
294 		receive_register_update_bit(m_rs232_rx);
295 		break;
296 	}
297 }
298 
299 
300 //-------------------------------------------------
301 //  rcv_complete -
302 //-------------------------------------------------
303 
rcv_complete()304 void zx8302_device::rcv_complete()
305 {
306 	// TODO
307 }
308 
309 
310 //-------------------------------------------------
311 //  rtc_r - real time clock read
312 //-------------------------------------------------
313 
rtc_r(offs_t offset)314 uint8_t zx8302_device::rtc_r(offs_t offset)
315 {
316 	uint8_t data = 0;
317 
318 	switch (offset)
319 	{
320 	case 0:
321 		data = (m_ctr >> 24) & 0xff;
322 		break;
323 	case 1:
324 		data = (m_ctr >> 16) & 0xff;
325 		break;
326 	case 2:
327 		data = (m_ctr >> 8) & 0xff;
328 		break;
329 	case 3:
330 		data = m_ctr & 0xff;
331 		break;
332 	}
333 
334 	return data;
335 }
336 
337 
338 //-------------------------------------------------
339 //  rtc_w - real time clock write
340 //-------------------------------------------------
341 
rtc_w(uint8_t data)342 void zx8302_device::rtc_w(uint8_t data)
343 {
344 	if (LOG) logerror("ZX8302 '%s' Set Real Time Clock: %02x\n", tag(), data);
345 }
346 
347 
348 //-------------------------------------------------
349 //  control_w - serial transmit clock
350 //-------------------------------------------------
351 
control_w(uint8_t data)352 void zx8302_device::control_w(uint8_t data)
353 {
354 	if (LOG) logerror("ZX8302 '%s' Transmit Control: %02x\n", tag(), data);
355 
356 	int baud = (19200 >> (data & BAUD_MASK));
357 	int baudx4 = baud * 4;
358 
359 	m_tcr = data;
360 
361 	m_baudx4_timer->adjust(attotime::zero, 0, attotime::from_hz(baudx4));
362 
363 	set_tra_rate(baud);
364 	set_data_frame(1, 8, PARITY_NONE, STOP_BITS_2);
365 }
366 
367 
368 //-------------------------------------------------
369 //  mdv_track_r - microdrive track data
370 //-------------------------------------------------
371 
mdv_track_r()372 uint8_t zx8302_device::mdv_track_r()
373 {
374 	if (LOG) logerror("ZX8302 '%s' Microdrive Track %u: %02x\n", tag(), m_track, m_mdv_data[m_track]);
375 
376 	uint8_t data = m_mdv_data[m_track];
377 
378 	m_track = !m_track;
379 
380 	return data;
381 }
382 
383 
384 //-------------------------------------------------
385 //  status_r - status register
386 //-------------------------------------------------
387 
status_r()388 uint8_t zx8302_device::status_r()
389 {
390 	/*
391 
392 	    bit     description
393 
394 	    0       Network port
395 	    1       Transmit buffer full
396 	    2       Receive buffer full
397 	    3       Microdrive GAP
398 	    4       SER1 DTR
399 	    5       SER2 CTS
400 	    6       IPC busy
401 	    7       COMDATA
402 
403 	*/
404 
405 	uint8_t data = 0;
406 
407 	// TODO network port
408 
409 	// serial status
410 	data |= m_status;
411 
412 	// TODO microdrive GAP
413 
414 	// data terminal ready
415 	data |= m_dtr1 << 4;
416 
417 	// clear to send
418 	data |= m_cts2 << 5;
419 
420 	// IPC busy
421 	data |= m_ipc_busy << 6;
422 
423 	// COMDATA
424 	data |= m_comdata_to_cpu << 7;
425 
426 	if (LOG) logerror("ZX8302 '%s' Status: %02x\n", tag(), data);
427 
428 	return data;
429 }
430 
431 
432 //-------------------------------------------------
433 //  ipc_command_w - IPC command
434 //-------------------------------------------------
435 // When the main CPU writes to the IPC it writes the lsn of 18003
436 // this is encoded as follows :
437 //
438 // b0 start bit
439 // b1 data bit
440 // b2 stop bit
441 // b3 extra stop bit.
442 //
443 // At startup the IPC sits in a loop waiting for the comdata bit to go
444 // high, the main CPU does this by writing 0x01 to output register.
445 
ipc_command_w(uint8_t data)446 void zx8302_device::ipc_command_w(uint8_t data)
447 {
448 	if (LOG) logerror("ZX8302 '%s' IPC Command: %02x\n", tag(), data);
449 
450 	m_idr = data;
451 	m_ipc_state = IPC_START;
452 
453 	transmit_ipc_data();
454 }
455 
456 
457 //-------------------------------------------------
458 //  mdv_control_w - microdrive control
459 //-------------------------------------------------
460 
mdv_control_w(uint8_t data)461 void zx8302_device::mdv_control_w(uint8_t data)
462 {
463 	/*
464 
465 	    bit     description
466 
467 	    0       MDSELDH
468 	    1       MDSELCKH
469 	    2       MDRDWL
470 	    3       ERASE
471 	    4
472 	    5
473 	    6
474 	    7
475 
476 	*/
477 
478 	if (LOG) logerror("ZX8302 '%s' Microdrive Control: %02x\n", tag(), data);
479 
480 	m_out_mdseld_cb(BIT(data, 0));
481 	m_out_mdselck_cb(BIT(data, 1));
482 	m_out_mdrdw_cb(BIT(data, 2));
483 	m_out_erase_cb(BIT(data, 3));
484 
485 	if (BIT(data, 1))
486 	{
487 		m_status &= ~STATUS_RX_BUFFER_FULL;
488 	}
489 }
490 
491 
492 //-------------------------------------------------
493 //  irq_status_r - interrupt status
494 //-------------------------------------------------
495 
irq_status_r()496 uint8_t zx8302_device::irq_status_r()
497 {
498 	if (LOG) logerror("ZX8302 '%s' Interrupt Status: %02x\n", tag(), m_irq);
499 
500 	return m_irq;
501 }
502 
503 
504 //-------------------------------------------------
505 //  irq_acknowledge_w - interrupt acknowledge
506 //-------------------------------------------------
507 
irq_acknowledge_w(uint8_t data)508 void zx8302_device::irq_acknowledge_w(uint8_t data)
509 {
510 	if (LOG) logerror("ZX8302 '%s' Interrupt Acknowledge: %02x\n", tag(), data);
511 
512 	m_irq &= ~data;
513 
514 	if (!m_irq)
515 	{
516 		m_out_ipl1l_cb(CLEAR_LINE);
517 	}
518 }
519 
520 
521 //-------------------------------------------------
522 //  data_w - transmit buffer
523 //-------------------------------------------------
524 
data_w(uint8_t data)525 void zx8302_device::data_w(uint8_t data)
526 {
527 	if (LOG) logerror("ZX8302 '%s' Data Register: %02x\n", tag(), data);
528 
529 	m_tdr = data;
530 	m_status |= STATUS_TX_BUFFER_FULL;
531 }
532 
533 
534 //-------------------------------------------------
535 //  vsync_w - vertical sync
536 //-------------------------------------------------
537 
WRITE_LINE_MEMBER(zx8302_device::vsync_w)538 WRITE_LINE_MEMBER( zx8302_device::vsync_w )
539 {
540 	if (state)
541 	{
542 		if (LOG) logerror("ZX8302 '%s' Frame Interrupt\n", tag());
543 
544 		trigger_interrupt(INT_FRAME);
545 	}
546 }
547 
548 
549 //-------------------------------------------------
550 //  comctl_w - IPC COMCTL
551 //-------------------------------------------------
552 
WRITE_LINE_MEMBER(zx8302_device::comctl_w)553 WRITE_LINE_MEMBER( zx8302_device::comctl_w )
554 {
555 	if (LOG) logerror("ZX8302 '%s' COMCTL: %x\n", tag(), state);
556 
557 	if (state)
558 	{
559 		transmit_ipc_data();
560 		m_comdata_to_cpu = m_comdata_from_ipc;
561 	}
562 }
563 
564 
565 //-------------------------------------------------
566 //  comdata_w - IPC COMDATA
567 //-------------------------------------------------
568 // IPC writing comdata to CPU
569 //
570 
WRITE_LINE_MEMBER(zx8302_device::comdata_w)571 WRITE_LINE_MEMBER( zx8302_device::comdata_w )
572 {
573 	if (LOG) logerror("ZX8302 '%s' COMDATA->CPU(pending): %x\n", tag(), state);
574 
575 	m_comdata_from_ipc = state;
576 }
577 
578 
579 //-------------------------------------------------
580 //  extint_w - external interrupt
581 //-------------------------------------------------
582 
WRITE_LINE_MEMBER(zx8302_device::extint_w)583 WRITE_LINE_MEMBER( zx8302_device::extint_w )
584 {
585 	if (LOG) logerror("ZX8302 '%s' EXTINT: %x\n", tag(), state);
586 
587 	if (state == ASSERT_LINE)
588 	{
589 		trigger_interrupt(INT_EXTERNAL);
590 	}
591 }
592 
WRITE_LINE_MEMBER(zx8302_device::write_netin)593 WRITE_LINE_MEMBER( zx8302_device::write_netin )
594 {
595 	m_rs232_rx = state;
596 	device_serial_interface::rx_w(state);
597 }
598 
WRITE_LINE_MEMBER(zx8302_device::write_dtr1)599 WRITE_LINE_MEMBER( zx8302_device::write_dtr1 )
600 {
601 	m_dtr1 = state;
602 }
603 
WRITE_LINE_MEMBER(zx8302_device::write_cts2)604 WRITE_LINE_MEMBER( zx8302_device::write_cts2 )
605 {
606 	m_cts2 = state;
607 }
608