fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/arch/macplus/adb.c *
7 * Created: 2010-11-02 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2010-2012 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include "main.h"
24#include "adb.h"
25
26#include <stdlib.h>
27
28
29#ifndef DEBUG_ADB
30#define DEBUG_ADB 0
31#endif
32
33
34/* ADB bit cell time (100 us) */
35#define ADB_BIT_CLK (MAC_CPU_CLOCK / 10000)
36
37
38void adb_dev_reset (adb_dev_t *dev)
39{
40#if DEBUG_ADB >= 1
41 mac_log_deb ("adb: reset device %u\n", dev->default_addr);
42#endif
43
44 dev->current_addr = dev->default_addr;
45
46 dev->service_request = 0;
47
48 dev->reg[0] = 0;
49 dev->reg[1] = 0;
50 dev->reg[2] = 0;
51 dev->reg[3] = 0x6000;
52 dev->reg[3] |= (dev->default_addr & 0x0f) << 8;
53 dev->reg[3] |= dev->default_handler & 0xff;
54}
55
56void adb_dev_flush (adb_dev_t *dev)
57{
58 dev->service_request = 0;
59}
60
61unsigned adb_dev_talk (adb_dev_t *dev, unsigned reg, void *buf)
62{
63 unsigned char *tmp;
64
65 if (reg != 3) {
66 return (0);
67 }
68
69 tmp = buf;
70
71 tmp[1] = dev->reg[3] & 0xff;
72 tmp[0] = (dev->reg[3] >> 8) & 0xff;
73
74 return (2);
75}
76
77void adb_dev_talk_done (adb_dev_t *dev, unsigned reg)
78{
79}
80
81void adb_dev_listen (adb_dev_t *dev, unsigned reg, const void *buf, unsigned cnt)
82{
83 unsigned addr;
84 const unsigned char *src;
85
86 if ((reg != 3) || (cnt < 2)) {
87 return;
88 }
89
90 src = buf;
91
92 if (src[1] == 0xfe) {
93 addr = src[0] & 0x0f;
94
95#if DEBUG_ADB >= 1
96 mac_log_deb ("adb: device %u set address %u\n",
97 dev->current_addr, addr
98 );
99#endif
100
101 dev->current_addr = addr;
102 dev->reg[3] &= 0xf0ff;
103 dev->reg[3] |= addr << 8;
104 }
105#if DEBUG_ADB >= 1
106 else {
107 mac_log_deb ("adb: device %u set reg 3 0x%04x\n",
108 dev->current_addr, (src[0] << 8) | src[1]
109 );
110 }
111#endif
112}
113
114void adb_dev_del (adb_dev_t *dev)
115{
116 if (dev->del != NULL) {
117 dev->del (dev);
118 }
119 else {
120 free (dev);
121 }
122}
123
124void adb_dev_init (adb_dev_t *dev, unsigned addr, unsigned handler)
125{
126 dev->ext = NULL;
127
128 dev->current_addr = addr;
129 dev->default_addr = addr;
130 dev->default_handler = handler;
131
132 dev->service_request = 0;
133
134 dev->reg[0] = 0;
135 dev->reg[1] = 0;
136 dev->reg[2] = 0;
137 dev->reg[3] = 0x6000;
138 dev->reg[3] |= (dev->default_addr & 0x0f) << 8;
139 dev->reg[3] |= dev->default_handler & 0xff;
140
141 dev->del = NULL;
142
143 dev->reset = adb_dev_reset;
144 dev->flush = adb_dev_flush;
145 dev->talk = adb_dev_talk;
146 dev->talk_done = adb_dev_talk_done;
147 dev->listen = adb_dev_listen;
148}
149
150
151void adb_init (mac_adb_t *adb)
152{
153 adb->state = 3;
154
155 adb->writing = 0;
156
157 adb->cmd = 0;
158
159 adb->last_talk = 0;
160
161 adb->buf_idx = 0;
162 adb->buf_cnt = 0;
163
164 adb->bit_cnt = 0;
165 adb->bit_val = 0;
166
167 adb->clock = 0;
168 adb->scan_clock = 0;
169
170 adb->dev_cnt = 0;
171
172 adb->shift_in_ext = NULL;
173 adb->shift_in = NULL;
174
175 adb->shift_out_ext = NULL;
176 adb->shift_out = NULL;
177
178 adb->set_int_val = 0;
179 adb->set_int_ext = NULL;
180 adb->set_int = NULL;
181}
182
183void adb_free (mac_adb_t *adb)
184{
185 unsigned i;
186
187 if (adb == NULL) {
188 return;
189 }
190
191 for (i = 0; i < adb->dev_cnt; i++) {
192 adb_dev_del (adb->dev[i]);
193 }
194}
195
196mac_adb_t *mac_adb_new (void)
197{
198 mac_adb_t *adb;
199
200 adb = malloc (sizeof (mac_adb_t));
201
202 if (adb == NULL) {
203 return (NULL);
204 }
205
206 adb_init (adb);
207
208 return (adb);
209}
210
211void mac_adb_del (mac_adb_t *adb)
212{
213 if (adb != NULL) {
214 adb_free (adb);
215 free (adb);
216 }
217}
218
219void adb_set_shift_in_fct (mac_adb_t *adb, void *ext, void *fct)
220{
221 adb->shift_in_ext = ext;
222 adb->shift_in = fct;
223}
224
225void adb_set_shift_out_fct (mac_adb_t *adb, void *ext, void *fct)
226{
227 adb->shift_out_ext = ext;
228 adb->shift_out = fct;
229}
230
231void adb_set_int_fct (mac_adb_t *adb, void *ext, void *fct)
232{
233 adb->set_int_ext = ext;
234 adb->set_int = fct;
235}
236
237int adb_add_device (mac_adb_t *adb, adb_dev_t *dev)
238{
239 unsigned i;
240
241 for (i = 0; i < adb->dev_cnt; i++) {
242 if (adb->dev[i] == dev) {
243 return (1);
244 }
245 }
246
247 if (adb->dev_cnt >= 16) {
248 return (1);
249 }
250
251 adb->dev[adb->dev_cnt++] = dev;
252
253 return (0);
254}
255
256static
257adb_dev_t *adb_get_device (mac_adb_t *adb, unsigned addr)
258{
259 unsigned i;
260
261 for (i = 0; i < adb->dev_cnt; i++) {
262 if (adb->dev[i]->current_addr == addr) {
263 return (adb->dev[i]);
264 }
265 }
266
267 return (NULL);
268}
269
270static
271void adb_set_int (mac_adb_t *adb, int val)
272{
273 val = (val != 0);
274
275 if (adb->set_int_val == val) {
276 return;
277 }
278
279 adb->set_int_val = val;
280
281#if DEBUG_ADB >= 2
282 mac_log_deb ("adb: interrupt = %d\n", val != 0);
283#endif
284
285 if (adb->set_int != NULL) {
286 adb->set_int (adb->set_int_ext, val);
287 }
288}
289
290static
291void adb_set_service_request (mac_adb_t *adb, unsigned addr)
292{
293 unsigned i;
294
295 for (i = 0; i < adb->dev_cnt; i++) {
296 if (adb->dev[i]->service_request == 0) {
297 continue;
298 }
299
300 if (adb->dev[i]->current_addr == addr) {
301 continue;
302 }
303
304 if ((adb->dev[i]->reg[3] & 0x2000) == 0) {
305 continue;
306 }
307
308#if DEBUG_ADB >= 1
309 mac_log_deb ("adb: service request dev %u\n",
310 adb->dev[i]->current_addr
311 );
312#endif
313
314 adb_set_int (adb, 1);
315 }
316}
317
318void adb_reset (mac_adb_t *adb)
319{
320 unsigned i;
321
322#if DEBUG_ADB >= 1
323 mac_log_deb ("adb: reset\n");
324#endif
325
326 for (i = 0; i < adb->dev_cnt; i++) {
327 adb->dev[i]->reset (adb->dev[i]);
328 }
329
330 adb->state = 3;
331
332 adb->writing = 1;
333
334 adb->cmd = 0;
335
336 adb->last_talk = 0;
337
338 adb->buf_idx = 0;
339 adb->buf_cnt = 0;
340
341 adb->bit_cnt = 0;
342 adb->bit_val = 0;
343
344 adb->clock = 0;
345 adb->scan_clock = 0;
346
347 adb_set_int (adb, 0);
348}
349
350static
351void adb_cmd_reset (mac_adb_t *adb, unsigned char cmd)
352{
353#if DEBUG_ADB >= 1
354 mac_log_deb ("adb: cmd reset\n");
355#endif
356
357 adb_reset (adb);
358
359 adb->writing = 1;
360}
361
362static
363void adb_flush (mac_adb_t *adb, unsigned char cmd)
364{
365 unsigned addr;
366 adb_dev_t *dev;
367
368 adb->writing = 1;
369
370 addr = cmd >> 4;
371
372#if DEBUG_ADB >= 1
373 mac_log_deb ("adb: cmd flush dev %u\n", addr);
374#endif
375
376 dev = adb_get_device (adb, addr);
377
378 if (dev != NULL) {
379 dev->flush (dev);
380 }
381}
382
383static
384void adb_talk (mac_adb_t *adb, unsigned char cmd)
385{
386 unsigned addr, reg;
387 adb_dev_t *dev;
388
389 adb->writing = 1;
390
391 addr = (cmd >> 4) & 0x0f;
392 reg = cmd & 3;
393
394#if DEBUG_ADB >= 2
395 if (adb->state != 3) {
396 mac_log_deb ("adb: cmd talk dev %u reg %u\n", addr, reg);
397 }
398#endif
399
400 dev = adb_get_device (adb, addr);
401
402 if (dev == NULL) {
403 return;
404 }
405
406 adb->buf_cnt = dev->talk (dev, reg, adb->buf);
407
408 adb->last_talk = cmd;
409}
410
411static
412void adb_talk_done (mac_adb_t *adb, unsigned char cmd)
413{
414 adb_dev_t *dev;
415
416 dev = adb_get_device (adb, (cmd >> 4) & 0x0f);
417
418 if (dev != NULL) {
419 dev->talk_done (dev, cmd & 3);
420 }
421}
422
423static
424void adb_listen (mac_adb_t *adb, unsigned char cmd)
425{
426 unsigned addr, reg;
427 adb_dev_t *dev;
428
429 adb->writing = 0;
430
431 addr = (cmd >> 4) & 0x0f;
432 reg = cmd & 3;
433
434#if DEBUG_ADB >= 2
435 mac_log_deb ("adb: cmd listen dev %u reg %u cnt %u\n",
436 addr, reg, adb->buf_cnt
437 );
438#endif
439
440 dev = adb_get_device (adb, addr);
441
442 if (dev == NULL) {
443 return;
444 }
445
446 dev->listen (dev, reg, adb->buf, adb->buf_cnt);
447}
448
449static
450void adb_finish_transaction (mac_adb_t *adb)
451{
452 if (adb->buf_idx >= adb->buf_cnt) {
453 return;
454 }
455
456 if ((adb->cmd & 0x0c) == 0x08) {
457 adb_listen (adb, adb->cmd);
458 }
459}
460
461static
462void adb_start_transaction (mac_adb_t *adb, unsigned char cmd, int poll)
463{
464 adb_set_int (adb, 0);
465
466 adb->cmd = cmd;
467
468 adb->buf_idx = 0;
469 adb->buf_cnt = 0;
470
471 if ((cmd & 0x0f) == 0) {
472 adb_cmd_reset (adb, cmd);
473 }
474 else if ((cmd & 0x0c) == 0x0c) {
475 adb_talk (adb, cmd);
476 }
477 else if ((cmd & 0x0c) == 0x08) {
478 ; /* listen */
479 }
480 else if ((cmd & 0x0f) == 0x01) {
481 adb_flush (adb, cmd);
482 }
483 else {
484 mac_log_deb ("adb: unknown cmd (%02X)\n", cmd);
485 }
486
487 if (poll) {
488 adb_set_service_request (adb, (cmd >> 4) & 0x0f);
489 }
490}
491
492void mac_adb_set_state (mac_adb_t *adb, unsigned char val)
493{
494 val &= 3;
495
496 if (adb->state == val) {
497 return;
498 }
499
500 adb->clock += ADB_BIT_CLK;
501
502 if ((val == 0) || (val == 3)) {
503 adb_finish_transaction (adb);
504 }
505
506#if DEBUG_ADB >= 2
507 mac_log_deb ("adb: state = %u\n", val);
508#endif
509
510 adb->state = val;
511
512 adb_set_int (adb, 0);
513
514 if (val == 0) {
515 adb->writing = 0;
516
517 adb->buf_idx = 0;
518 adb->buf_cnt = 0;
519
520 adb->bit_cnt = 8;
521 adb->bit_val = 0;
522 }
523 else if ((val == 1) || (val == 2)) {
524 if (adb->writing) {
525 if (adb->buf_idx < adb->buf_cnt) {
526 adb->bit_cnt = 8;
527 adb->bit_val = adb->buf[adb->buf_idx++];
528
529 if (adb->buf_idx >= adb->buf_cnt) {
530 adb_talk_done (adb, adb->cmd);
531 }
532 }
533 else {
534 adb->bit_cnt = 8;
535 adb->bit_val = 0xaa;
536 adb_set_int (adb, 1);
537 }
538 }
539 else {
540 adb->bit_cnt = 8;
541 adb->bit_val = 0;
542 }
543 }
544 else if (val == 3) {
545 adb->writing = 1;
546
547 adb->buf_idx = 0;
548 adb->buf_cnt = 0;
549
550 adb->bit_cnt = 0;
551 adb->bit_val = 0;
552
553 adb->scan_clock = 0;
554 }
555}
556
557static
558void adb_clock_idle (mac_adb_t *adb, unsigned cnt)
559{
560 adb->scan_clock += cnt;
561
562 if (adb->scan_clock < 86170) {
563 return;
564 }
565
566 adb->scan_clock = 0;
567
568 if (adb->last_talk == 0) {
569 return;
570 }
571
572 adb_start_transaction (adb, adb->last_talk, 1);
573
574 if (adb->buf_idx < adb->buf_cnt) {
575 adb->bit_cnt = 8;
576 adb->bit_val = 0xaa;
577 }
578 else if (adb->set_int_val) {
579 adb->bit_cnt = 8;
580 adb->bit_val = 0xaa;
581 }
582}
583
584void mac_adb_clock (mac_adb_t *adb, unsigned cnt)
585{
586 if (adb->bit_cnt == 0) {
587 if (adb->state == 3) {
588 adb_clock_idle (adb, cnt);
589 }
590
591 return;
592 }
593
594 adb->scan_clock = 0;
595
596 if (cnt < adb->clock) {
597 adb->clock -= cnt;
598 return;
599 }
600
601 adb->clock = 0;
602
603 if (adb->writing) {
604 if (adb->shift_in != NULL) {
605 adb->shift_in (adb->shift_in_ext, (adb->bit_val >> 7) & 1);
606 }
607
608 adb->bit_val <<= 1;
609 adb->bit_cnt -= 1;
610 }
611 else {
612 adb->bit_val <<= 1;
613 adb->bit_cnt -= 1;
614
615 if (adb->shift_out != NULL) {
616 if (adb->shift_out (adb->shift_out_ext)) {
617 adb->bit_val |= 0x01;
618 }
619 }
620
621 if (adb->bit_cnt == 0) {
622 if (adb->state == 0) {
623 adb_start_transaction (adb, adb->bit_val, 0);
624 }
625 else if (adb->buf_cnt < 8) {
626 adb->buf[adb->buf_cnt++] = adb->bit_val;
627 }
628 }
629 }
630
631 adb->clock += ADB_BIT_CLK;
632}