fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 632 lines 11 kB view raw
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}