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