fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 1318 lines 22 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/chipset/e8530.c * 7 * Created: 2007-11-11 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2007-2020 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 <stdlib.h> 24#include <stdio.h> 25 26#include "e8530.h" 27 28 29#define DEBUG_SCC 0 30 31 32#define scc_get_chn(chn) (((chn) == 0) ? 'A' : 'B') 33 34 35static 36void e8530_init_chn (e8530_t *scc, unsigned chn) 37{ 38 e8530_chn_t *c; 39 40 c = &scc->chn[chn]; 41 42 c->txd_empty = 1; 43 c->rxd_empty = 1; 44 45 c->int_on_next_rx = 0; 46 47 c->char_clk_cnt = 0; 48 c->char_clk_div = 16384; 49 50 c->read_char_cnt = 0; 51 c->read_char_max = 1; 52 53 c->write_char_cnt = 0; 54 c->write_char_max = 1; 55 56 c->rtxc = 0; 57 58 c->tx_i = 0; 59 c->tx_j = 0; 60 61 c->rx_i = 0; 62 c->rx_j = 0; 63 64 c->set_inp_ext = NULL; 65 c->set_inp = NULL; 66 67 c->set_out_ext = NULL; 68 c->set_out = NULL; 69 70 c->set_rts_ext = NULL; 71 c->set_rts = NULL; 72 73 c->set_comm_ext = NULL; 74 c->set_comm = NULL; 75} 76 77void e8530_init (e8530_t *scc) 78{ 79 scc->index = 0; 80 81 scc->pclk = 0; 82 83 e8530_init_chn (scc, 0); 84 e8530_init_chn (scc, 1); 85 86 scc->irq_ext = NULL; 87 scc->irq = NULL; 88 scc->irq_val = 0; 89} 90 91void e8530_free (e8530_t *scc) 92{ 93} 94 95e8530_t *e8530_new (void) 96{ 97 e8530_t *scc; 98 99 if ((scc = malloc (sizeof (e8530_t))) == NULL) { 100 return (NULL); 101 } 102 103 e8530_init (scc); 104 105 return (scc); 106} 107 108void e8530_del (e8530_t *scc) 109{ 110 if (scc != NULL) { 111 e8530_free (scc); 112 free (scc); 113 } 114} 115 116void e8530_set_irq_fct (e8530_t *scc, void *ext, void *fct) 117{ 118 scc->irq_ext = ext; 119 scc->irq = fct; 120} 121 122void e8530_set_inp_fct (e8530_t *scc, unsigned chn, void *ext, void *fct) 123{ 124 if (chn < 2) { 125 scc->chn[chn].set_inp_ext = ext; 126 scc->chn[chn].set_inp = fct; 127 } 128} 129 130void e8530_set_out_fct (e8530_t *scc, unsigned chn, void *ext, void *fct) 131{ 132 if (chn < 2) { 133 scc->chn[chn].set_out_ext = ext; 134 scc->chn[chn].set_out = fct; 135 } 136} 137 138void e8530_set_rts_fct (e8530_t *scc, unsigned chn, void *ext, void *fct) 139{ 140 if (chn < 2) { 141 scc->chn[chn].set_rts_ext = ext; 142 scc->chn[chn].set_rts = fct; 143 } 144} 145 146void e8530_set_comm_fct (e8530_t *scc, unsigned chn, void *ext, void *fct) 147{ 148 if (chn < 2) { 149 scc->chn[chn].set_comm_ext = ext; 150 scc->chn[chn].set_comm = fct; 151 } 152} 153 154void e8530_set_multichar (e8530_t *scc, unsigned chn, unsigned read_max, unsigned write_max) 155{ 156 if (chn > 1) { 157 return; 158 } 159 160 scc->chn[chn].read_char_cnt = 0; 161 scc->chn[chn].read_char_max = (read_max < 1) ? 1 : read_max; 162 163 scc->chn[chn].write_char_cnt = 0; 164 scc->chn[chn].write_char_max = (write_max < 1) ? 1 : write_max; 165} 166 167void e8530_set_clock (e8530_t *scc, unsigned long pclk, unsigned long rtxca, unsigned long rtxcb) 168{ 169 scc->pclk = pclk; 170 scc->chn[0].rtxc = rtxca; 171 scc->chn[1].rtxc = rtxcb; 172} 173 174static 175void e8530_set_irq (e8530_t *scc, unsigned char val) 176{ 177 if (scc->irq_val == val) { 178 return; 179 } 180 181 scc->irq_val = val; 182 183 if (scc->irq != NULL) { 184 scc->irq (scc->irq_ext, val); 185 } 186} 187 188static 189void e8530_set_rts (e8530_t *scc, unsigned chn, unsigned char val) 190{ 191 e8530_chn_t *c; 192 193 c = &scc->chn[chn]; 194 195 if (c->set_rts != NULL) { 196 c->set_rts (c->set_rts_ext, val != 0); 197 } 198} 199 200static 201void e8530_set_int_cond (e8530_t *scc, unsigned chn, unsigned char cond) 202{ 203 e8530_chn_t *c0, *c; 204 205 c = &scc->chn[chn]; 206 c0 = &scc->chn[0]; 207 208 if ((cond & 0x01) && (c->wr[1] & 0x01)) { 209 /* ext */ 210 211 /* should check if IP is already set */ 212 213 c0->rr[3] |= (chn == 0) ? 0x08 : 0x01; 214 215 c->rr0_latch_msk = c->wr[15]; 216 c->rr0_latch_val = c->rr[0]; 217 } 218 219 if ((cond & 0x02) && (c->wr[1] & 0x02)) { 220 /* transmit interrupt */ 221 c0->rr[3] |= (chn == 0) ? 0x10 : 0x02; 222 } 223 224 if ((cond & 0x04) && (c->wr[1] & 0x18)) { 225 /* receive interrupt */ 226 int data, spec, irq; 227 228 data = (c->rxd_empty == 0); 229 spec = (c->rr[0] & 0x80) != 0; 230 irq = 0; 231 232 switch ((c->wr[1] >> 3) & 3) { 233 case 0: /* disabled */ 234 irq = 0; 235 break; 236 237 case 1: /* rx int on first char / special condition */ 238 irq = (data && c->int_on_next_rx) || spec; 239 break; 240 241 case 2: /* rx int on all chars / special condition */ 242 irq = data || spec; 243 break; 244 245 case 3: /* rx int on special condition */ 246 irq = spec; 247 break; 248 } 249 250 if (data) { 251 c->int_on_next_rx = 0; 252 } 253 254 if (irq) { 255 c0->rr[3] |= (chn == 0) ? 0x20 : 0x04; 256 } 257 } 258 259 if ((c0->wr[9] & 0x08) == 0) { 260 /* MIE == 0 */ 261 e8530_set_irq (scc, 0); 262 return; 263 } 264 265 e8530_set_irq (scc, c0->rr[3] != 0); 266} 267 268static 269void e8530_clr_int_cond (e8530_t *scc, unsigned chn, unsigned char cond) 270{ 271 e8530_chn_t *c, *c0; 272 273 c = &scc->chn[chn]; 274 c0 = &scc->chn[0]; 275 276 if (cond & 0x01) { 277 /* ext */ 278 279 c0->rr[3] &= (chn == 0) ? ~0x08 : ~0x01; 280 281 c->rr0_latch_msk = 0; 282 } 283 284 if (cond & 0x02) { 285 /* transmit interrupt */ 286 c0->rr[3] &= (chn == 0) ? ~0x10 : ~0x02; 287 } 288 289 if (cond & 0x04) { 290 /* receive interrupt */ 291 c0->rr[3] &= (chn == 0) ? ~0x20 : ~0x04; 292 } 293 294 if ((c0->wr[9] & 0x08) == 0) { 295 /* MIE == 0 */ 296 e8530_set_irq (scc, 0); 297 return; 298 } 299 300 e8530_set_irq (scc, c0->rr[3] != 0); 301} 302 303/* 304 * Move a character from the input queue to RxD and adjust interrupt 305 * conditions. 306 */ 307static 308void e8530_check_rxd (e8530_t *scc, unsigned chn) 309{ 310 e8530_chn_t *c; 311 312 c = &scc->chn[chn]; 313 314 if (c->rx_i == c->rx_j) { 315 return; 316 } 317 318 if (c->read_char_cnt == 0) { 319 return; 320 } 321 322 if ((c->wr[3] & 0x01) == 0) { 323 /* receiver disabled */ 324 return; 325 } 326 327 if (c->rxd_empty == 0) { 328 /* should overwrite old character */ 329 return; 330 } 331 332 c->read_char_cnt -= 1; 333 334 c->rr[8] = c->rxbuf[c->rx_j]; 335 c->rx_j = (c->rx_j + 1) % E8530_BUF_MAX; 336 337 if (c->set_inp != NULL) { 338 c->set_inp (c->set_inp_ext, 1); 339 } 340 341 c->rr[0] |= 0x01; 342 c->rxd_empty = 0; 343 344 e8530_set_int_cond (scc, chn, 0x04); 345} 346 347/* 348 * Move a character from TxD to the output queue and adjust interrupt 349 * conditions. 350 */ 351static 352void e8530_check_txd (e8530_t *scc, unsigned chn) 353{ 354 e8530_chn_t *c; 355 unsigned char val; 356 357 c = &scc->chn[chn]; 358 359 if (c->write_char_cnt == 0) { 360 return; 361 } 362 363 if (((c->tx_i + 1) % E8530_BUF_MAX) == c->tx_j) { 364 return; 365 } 366 367 if (c->txd_empty) { 368 /* tx underrun */ 369 c->rr[0] |= 0x40; 370 return; 371 } 372 373 c->write_char_cnt -= 1; 374 375 val = c->wr[8]; 376 377 c->txbuf[c->tx_i] = val; 378 c->tx_i = (c->tx_i + 1) % E8530_BUF_MAX; 379 380 if (c->set_out != NULL) { 381 c->set_out (c->set_out_ext, val); 382 } 383 384 c->rr[0] |= 0x04; 385 c->txd_empty = 1; 386 387 e8530_set_int_cond (scc, chn, 0x02); 388 389#if DEBUG_SCC 390 fprintf (stderr, "SCC %c: send %02X\n", scc_get_chn (chn), val); 391#endif 392} 393 394 395static 396unsigned e8530_get_clock_mode (e8530_t *scc, unsigned chn) 397{ 398 switch ((scc->chn[chn].wr[4] >> 6) & 3) { 399 case 0: 400 return (1); 401 402 case 1: 403 return (16); 404 405 case 2: 406 return (32); 407 408 case 3: 409 return (64); 410 } 411 412 return (0); 413} 414 415static 416unsigned e8530_get_bits_per_char (e8530_t *scc, unsigned chn) 417{ 418 switch ((scc->chn[chn].wr[5] >> 5) & 3) { 419 case 0: 420 return (5); 421 422 case 1: 423 return (7); 424 425 case 2: 426 return (6); 427 428 case 3: 429 return (8); 430 } 431 432 return (0); 433} 434 435static 436unsigned e8530_get_parity (e8530_t *scc, unsigned chn) 437{ 438 switch (scc->chn[chn].wr[4] & 3) { 439 case 0: 440 return (0); 441 442 case 1: /* odd */ 443 return (1); 444 445 case 2: 446 return (0); 447 448 case 3: /* even */ 449 return (2); 450 } 451 452 return (0); 453} 454 455/* 456 * Get 2 * the number of stop bits 457 */ 458static 459unsigned e8530_get_stop_bits (e8530_t *scc, unsigned chn) 460{ 461 switch ((scc->chn[chn].wr[4] >> 2) & 3) { 462 case 0: 463 return (0); 464 465 case 1: 466 return (2); 467 468 case 2: 469 return (3); 470 471 case 3: 472 return (4); 473 474 } 475 476 return (0); 477} 478 479/* 480 * Update the communication parameters and call the callback function 481 */ 482static 483void e8530_set_params (e8530_t *scc, unsigned chn) 484{ 485 unsigned long bps, clk, mul, div; 486 e8530_chn_t *c; 487 488 c = &scc->chn[chn]; 489 490 c->bpc = e8530_get_bits_per_char (scc, chn); 491 c->parity = e8530_get_parity (scc, chn); 492 c->stop = e8530_get_stop_bits (scc, chn); 493 494 mul = e8530_get_clock_mode (scc, chn); 495 496 if (c->stop == 0) { 497 /* sync mode */ 498 mul = 1; 499 } 500 501 if (c->wr[14] & 0x01) { 502 /* baud rate generator enabled */ 503 504 if (c->wr[14] & 0x02) { 505 clk = scc->pclk; 506 } 507 else { 508 clk = c->rtxc; 509 } 510 511 div = (c->wr[13] << 8) | c->wr[12]; 512 div = 2 * mul * (div + 2); 513 514 c->char_clk_div = ((2 * c->bpc + c->stop + 2) * div) / 2; 515 516 if (c->parity != 0) { 517 c->char_clk_div += div; 518 } 519 520 bps = clk / div; 521 } 522 else { 523 c->char_clk_div = 16384; 524 bps = 0; 525 } 526 527 c->bps = bps; 528 529 if (c->set_comm != NULL) { 530 c->set_comm (c->set_comm_ext, c->bps, c->parity, c->bpc, c->stop); 531 } 532 533#if DEBUG_SCC 534 { 535 static const char p[3] = { 'N', 'O', 'E' }; 536 static const char *s[5] = { "0", "", "1", "1.5", "2" }; 537 538 fprintf (stderr, "SCC %c: %lu%c%u%s\n", 539 scc_get_chn (chn), c->bps, p[c->parity], c->bpc, s[c->stop] 540 ); 541 } 542#endif 543} 544 545 546/* 547 * Set new RR0 value reflecting the external status and set an 548 * interrupt condition if an enabled status changed. 549 */ 550static 551void e8530_set_rr0 (e8530_t *scc, unsigned chn, unsigned char val) 552{ 553 unsigned char old; 554 555 chn &= 1; 556 557 old = scc->chn[chn].rr[0]; 558 scc->chn[chn].rr[0] = val; 559 560 if ((old ^ val) & scc->chn[chn].wr[15] & 0xfa) { 561 e8530_set_int_cond (scc, chn, 0x01); 562 } 563} 564 565 566/* 567 * RR0: transmit/receive buffer status and external status 568 */ 569static 570unsigned char e8530_get_rr0 (e8530_t *scc, unsigned chn) 571{ 572 unsigned char val; 573 574 val = scc->chn[chn].rr[0] & ~scc->chn[chn].rr0_latch_msk; 575 val |= scc->chn[chn].rr0_latch_val & scc->chn[chn].rr0_latch_msk; 576 577 return (val); 578} 579 580/* 581 * RR2: interrupt vector 582 * If read from channel B, include status 583 */ 584static 585unsigned char e8530_get_rr2 (e8530_t *scc, unsigned chn) 586{ 587 unsigned char val; 588 e8530_chn_t *c0; 589 590 c0 = &scc->chn[0]; 591 592 val = c0->rr[2]; 593 594 if (chn == 1) { 595 unsigned char st; 596 597 /* include status in vector */ 598 599 if (c0->rr[3] & 0x20) { 600 /* chn a rx */ 601 st = 0x06 | (0x03 << 3); 602 } 603 else if (c0->rr[3] & 0x10) { 604 /* chn a tx */ 605 st = 0x04 | (0x01 << 3); 606 } 607 else if (c0->rr[3] & 0x08) { 608 /* chn a ext */ 609 st = 0x05 | (0x05 << 3); 610 } 611 else if (c0->rr[3] & 0x04) { 612 /* chn b rx */ 613 st = 0x02 | (0x02 << 3); 614 } 615 else if (c0->rr[3] & 0x02) { 616 /* chn b tx */ 617 st = 0x00 | (0x00 << 3); 618 } 619 else if (c0->rr[3] & 0x01) { 620 /* chn b ext */ 621 st = 0x01 | (0x04 << 3); 622 } 623 else { 624 st = 0x03 | (0x06 << 3); 625 } 626 627 if (c0->wr[9] & 0x10) { 628 /* status high */ 629 val = (val & 0x70) | ((st & 0x38) << 1); 630 } 631 else { 632 val = (val & 0xf1) | ((st & 0x07) << 1); 633 } 634 } 635 636 return (val); 637} 638 639/* 640 * RR3: interrupt pending 641 */ 642static 643unsigned char e8530_get_rr3 (e8530_t *scc, unsigned chn) 644{ 645 if (chn != 0) { 646 return (0); 647 } 648 649 return (scc->chn[0].rr[3]); 650} 651 652/* 653 * RR8: receive buffer 654 */ 655static 656unsigned char e8530_get_rr8 (e8530_t *scc, unsigned chn) 657{ 658 e8530_chn_t *c; 659 unsigned char val; 660 661 c = &scc->chn[chn]; 662 663 val = c->rr[8]; 664 665 c->rr[0] &= ~0x01; 666 c->rxd_empty = 1; 667 668 e8530_clr_int_cond (scc, chn, 0x04); 669 670 e8530_check_rxd (scc, chn); 671 672 return (val); 673} 674 675static 676unsigned char e8530_get_reg (e8530_t *scc, unsigned chn, unsigned reg) 677{ 678 unsigned char val; 679 680 chn &= 1; 681 682 switch (reg) { 683 case 0x00: 684 val = e8530_get_rr0 (scc, chn); 685 break; 686 687 case 0x02: 688 val = e8530_get_rr2 (scc, chn); 689 break; 690 691 case 0x03: 692 val = e8530_get_rr3 (scc, chn); 693 break; 694 695 case 0x08: 696 val = e8530_get_rr8 (scc, chn); 697 break; 698 699 default: 700 val = scc->chn[chn].rr[reg & 15]; 701 break; 702 } 703 704 705 scc->index = 0; 706 707#if DEBUG_SCC 708 fprintf (stderr, "SCC %c: get RR%u -> %02x\n", 709 scc_get_chn (chn), reg, val 710 ); 711#endif 712 713 return (val); 714} 715 716/* 717 * WR0: command register 718 */ 719static 720void e8530_set_wr0 (e8530_t *scc, unsigned chn, unsigned char val) 721{ 722 scc->chn[chn].wr[0] = val; 723 724 scc->index = val & 7; 725 726 switch ((val >> 3) & 7) { 727 case 0x00: /* null command */ 728 break; 729 730 case 0x01: /* point high */ 731 scc->index += 8; 732 break; 733 734 case 0x02: /* reset external/status interrupts */ 735 e8530_clr_int_cond (scc, chn, 0x01); 736 break; 737 738 case 0x03: /* send abort */ 739 break; 740 741 case 0x04: /* enable interrupt on next rx character */ 742 scc->chn[chn].int_on_next_rx = 1; 743 break; 744 745 case 0x05: /* reset tx interrupt pending */ 746 e8530_clr_int_cond (scc, chn, 0x02); 747 break; 748 749 case 0x06: /* error reset */ 750 scc->chn[chn].rr[1] &= 0x7f; 751 break; 752 753 case 0x07: /* reset highest ius */ 754 break; 755 } 756} 757 758/* 759 * WR1: transmit/receive interrupt and data transfer mode definition 760 */ 761static 762void e8530_set_wr1 (e8530_t *scc, unsigned chn, unsigned char val) 763{ 764 scc->chn[chn].wr[1] = val; 765 766 e8530_set_int_cond (scc, chn, 0x00); 767} 768 769/* 770 * WR2: interrupt vector 771 */ 772static 773void e8530_set_wr2 (e8530_t *scc, unsigned char val) 774{ 775 scc->chn[0].wr[2] = val; 776 scc->chn[1].wr[2] = val; 777 778 scc->chn[0].rr[2] = val; 779 scc->chn[1].rr[2] = val; 780} 781 782/* 783 * WR3: receive parameters and control 784 */ 785static 786void e8530_set_wr3 (e8530_t *scc, unsigned chn, unsigned char val) 787{ 788 e8530_chn_t *c; 789 790 c = &scc->chn[chn]; 791 792 if (c->wr[3] ^ val) { 793 if (val & 0x01) { 794#if DEBUG_SCC >= 1 795 fprintf (stderr, "SCC %c: receiver enable\n", scc_get_chn (chn)); 796#endif 797 c->int_on_next_rx = 1; 798 c->rxd_empty = 1; 799 } 800 else { 801 c->rr[0] &= ~0x01; 802 e8530_clr_int_cond (scc, chn, 0x04); 803#if DEBUG_SCC >= 1 804 fprintf (stderr, "SCC %c: receiver disable\n", scc_get_chn (chn)); 805#endif 806 } 807 } 808 809 if (val & 0x10) { 810#if DEBUG_SCC >= 1 811 if ((c->rr[0] & 0x10) == 0) { 812 fprintf (stderr, "SCC %c: sync/hunt mode\n", scc_get_chn (chn)); 813 } 814#endif 815 c->rr[0] |= 0x10; 816 } 817 818 c->wr[3] = val; 819} 820 821/* 822 * WR4: transmit/receive miscellaneous parameters and modes 823 */ 824static 825void e8530_set_wr4 (e8530_t *scc, unsigned chn, unsigned char val) 826{ 827 scc->chn[chn].wr[4] = val; 828 829 e8530_set_params (scc, chn); 830} 831 832/* 833 * WR5: transmit parameters and controls 834 */ 835static 836void e8530_set_wr5 (e8530_t *scc, unsigned chn, unsigned char val) 837{ 838 e8530_chn_t *c; 839 unsigned char old; 840 841 c = &scc->chn[chn]; 842 843 old = c->wr[5]; 844 c->wr[5] = val; 845 846 if ((old ^ val) & 0x02) { 847 e8530_set_rts (scc, chn, (val & 0x02) != 0); 848 } 849 850 e8530_set_params (scc, chn); 851} 852 853/* 854 * WR8: transmit buffer 855 */ 856static 857void e8530_set_wr8 (e8530_t *scc, unsigned chn, unsigned char val) 858{ 859 e8530_chn_t *c; 860 861 c = &scc->chn[chn]; 862 863 c->wr[8] = val; 864 865 c->rr[0] &= ~0x04; 866 c->txd_empty = 0; 867 868 e8530_clr_int_cond (scc, chn, 0x02); 869 870 e8530_check_txd (scc, chn); 871 872#if DEBUG_SCC 873 fprintf (stderr, "SCC %c: send %02X\n", scc_get_chn (chn), val); 874#endif 875} 876 877/* 878 * WR9: Master interrupt control 879 */ 880static 881void e8530_set_wr9 (e8530_t *scc, unsigned char val) 882{ 883 unsigned char old; 884 885 old = scc->chn[0].wr[9]; 886 887 scc->chn[0].wr[9] = val; 888 scc->chn[1].wr[9] = val; 889 890 if ((old ^ val) & val & 0x08) { 891 /* MIE was enabled, re-check pending interrupts */ 892 e8530_set_int_cond (scc, 0, 0); 893 e8530_set_int_cond (scc, 1, 0); 894 } 895} 896 897/* 898 * WR10: miscellaneous transmitter/receiver control bits 899 */ 900static 901void e8530_set_wr10 (e8530_t *scc, unsigned chn, unsigned char val) 902{ 903 scc->chn[chn].wr[10] = val; 904} 905 906/* 907 * WR11: clock mode control 908 */ 909static 910void e8530_set_wr11 (e8530_t *scc, unsigned chn, unsigned char val) 911{ 912 scc->chn[chn].wr[11] = val; 913} 914 915/* 916 * WR12: baud rate generator low byte 917 */ 918static 919void e8530_set_wr12 (e8530_t *scc, unsigned chn, unsigned char val) 920{ 921 scc->chn[chn].wr[12] = val; 922 923 e8530_set_params (scc, chn); 924} 925 926/* 927 * WR13: baud rate generator high byte 928 */ 929static 930void e8530_set_wr13 (e8530_t *scc, unsigned chn, unsigned char val) 931{ 932 scc->chn[chn].wr[13] = val; 933 934 e8530_set_params (scc, chn); 935} 936 937/* 938 * WR14: miscellaneous control bits 939 */ 940static 941void e8530_set_wr14 (e8530_t *scc, unsigned chn, unsigned char val) 942{ 943 scc->chn[chn].wr[14] = val; 944 945#if DEBUG_SCC 946 if ((val & 0xe0) != 0) { 947 fprintf (stderr, "SCC %c: dpll cmd: %u\n", 948 scc_get_chn (chn), (val >> 5) & 7 949 ); 950 } 951#endif 952 953 e8530_set_params (scc, chn); 954} 955 956/* 957 * WR15: external/status interrupt control 958 */ 959static 960void e8530_set_wr15 (e8530_t *scc, unsigned chn, unsigned char val) 961{ 962 scc->chn[chn].wr[15] = val; 963 scc->chn[chn].rr[15] = val; 964} 965 966void e8530_set_reg (e8530_t *scc, unsigned chn, unsigned reg, unsigned char val) 967{ 968 chn &= 1; 969 970#if DEBUG_SCC 971 fprintf (stderr, "SCC %c: set WR%u <- %02x\n", 972 scc_get_chn (chn), reg, val 973 ); 974#endif 975 976 switch (reg) { 977 case 0x00: 978 e8530_set_wr0 (scc, chn, val); 979 break; 980 981 case 0x01: 982 e8530_set_wr1 (scc, chn, val); 983 break; 984 985 case 0x02: 986 e8530_set_wr2 (scc, val); 987 break; 988 989 case 0x03: 990 e8530_set_wr3 (scc, chn, val); 991 break; 992 993 case 0x04: 994 e8530_set_wr4 (scc, chn, val); 995 break; 996 997 case 0x05: 998 e8530_set_wr5 (scc, chn, val); 999 break; 1000 1001 case 0x08: 1002 e8530_set_wr8 (scc, chn, val); 1003 break; 1004 1005 case 0x09: 1006 e8530_set_wr9 (scc, val); 1007 break; 1008 1009 case 0x0a: 1010 e8530_set_wr10 (scc, chn, val); 1011 break; 1012 1013 case 0x0b: 1014 e8530_set_wr11 (scc, chn, val); 1015 break; 1016 1017 case 0x0c: 1018 e8530_set_wr12 (scc, chn, val); 1019 break; 1020 1021 case 0x0d: 1022 e8530_set_wr13 (scc, chn, val); 1023 break; 1024 1025 case 0x0e: 1026 e8530_set_wr14 (scc, chn, val); 1027 break; 1028 1029 case 0x0f: 1030 e8530_set_wr15 (scc, chn, val); 1031 break; 1032 1033 default: 1034 scc->chn[chn].wr[reg & 15] = val; 1035 break; 1036 } 1037 1038 if (reg != 0) { 1039 scc->index = 0; 1040 } 1041} 1042 1043 1044unsigned char e8530_get_ctl (e8530_t *scc, unsigned chn) 1045{ 1046 return (e8530_get_reg (scc, chn & 1, scc->index)); 1047} 1048 1049unsigned char e8530_get_ctl_a (e8530_t *scc) 1050{ 1051 return (e8530_get_reg (scc, 0, scc->index)); 1052} 1053 1054unsigned char e8530_get_ctl_b (e8530_t *scc) 1055{ 1056 return (e8530_get_reg (scc, 1, scc->index)); 1057} 1058 1059void e8530_set_ctl (e8530_t *scc, unsigned chn, unsigned char val) 1060{ 1061 e8530_set_reg (scc, chn & 1, scc->index, val); 1062} 1063 1064void e8530_set_ctl_a (e8530_t *scc, unsigned char val) 1065{ 1066 e8530_set_reg (scc, 0, scc->index, val); 1067} 1068 1069void e8530_set_ctl_b (e8530_t *scc, unsigned char val) 1070{ 1071 e8530_set_reg (scc, 1, scc->index, val); 1072} 1073 1074unsigned char e8530_get_data (e8530_t *scc, unsigned chn) 1075{ 1076 return (e8530_get_reg (scc, chn & 1, 8)); 1077} 1078 1079unsigned char e8530_get_data_a (e8530_t *scc) 1080{ 1081 return (e8530_get_reg (scc, 0, 8)); 1082} 1083 1084unsigned char e8530_get_data_b (e8530_t *scc) 1085{ 1086 return (e8530_get_reg (scc, 1, 8)); 1087} 1088 1089void e8530_set_data (e8530_t *scc, unsigned chn, unsigned char val) 1090{ 1091 e8530_set_reg (scc, chn & 1, 8, val); 1092} 1093 1094void e8530_set_data_a (e8530_t *scc, unsigned char val) 1095{ 1096 e8530_set_reg (scc, 0, 8, val); 1097} 1098 1099void e8530_set_data_b (e8530_t *scc, unsigned char val) 1100{ 1101 e8530_set_reg (scc, 1, 8, val); 1102} 1103 1104 1105void e8530_set_dcd (e8530_t *scc, unsigned chn, unsigned char val) 1106{ 1107 unsigned char old; 1108 1109 chn &= 1; 1110 old = scc->chn[chn].rr[0]; 1111 1112 if (val) { 1113 old &= ~0x08; 1114 } 1115 else { 1116 old |= 0x08; 1117 } 1118 1119 e8530_set_rr0 (scc, chn, old); 1120} 1121 1122void e8530_set_dcd_a (e8530_t *scc, unsigned char val) 1123{ 1124 e8530_set_dcd (scc, 0, val); 1125} 1126 1127void e8530_set_dcd_b (e8530_t *scc, unsigned char val) 1128{ 1129 e8530_set_dcd (scc, 1, val); 1130} 1131 1132void e8530_set_cts (e8530_t *scc, unsigned chn, unsigned char val) 1133{ 1134 unsigned char rr0; 1135 1136 chn &= 1; 1137 rr0 = scc->chn[chn].rr[0]; 1138 1139 if (val) { 1140 rr0 &= ~0x20; 1141 } 1142 else { 1143 rr0 |= 0x20; 1144 } 1145 1146 e8530_set_rr0 (scc, chn, rr0); 1147} 1148 1149void e8530_set_cts_a (e8530_t *scc, unsigned char val) 1150{ 1151 e8530_set_cts (scc, 0, val); 1152} 1153 1154void e8530_set_cts_b (e8530_t *scc, unsigned char val) 1155{ 1156 e8530_set_cts (scc, 1, val); 1157} 1158 1159void e8530_receive (e8530_t *scc, unsigned chn, unsigned char val) 1160{ 1161 e8530_chn_t *c; 1162 1163 chn &= 1; 1164 c = &scc->chn[chn]; 1165 1166 if (((c->rx_i + 1) % E8530_BUF_MAX) != c->rx_j) { 1167 c->rxbuf[c->rx_i] = val; 1168 c->rx_i = (c->rx_i + 1) % E8530_BUF_MAX; 1169 } 1170} 1171 1172void e8530_receive_a (e8530_t *scc, unsigned char val) 1173{ 1174 e8530_receive (scc, 0, val); 1175} 1176 1177void e8530_receive_b (e8530_t *scc, unsigned char val) 1178{ 1179 e8530_receive (scc, 1, val); 1180} 1181 1182unsigned char e8530_send (e8530_t *scc, unsigned chn) 1183{ 1184 unsigned char val; 1185 e8530_chn_t *c; 1186 1187 chn &= 1; 1188 c = &scc->chn[chn]; 1189 1190 if (c->tx_i == c->tx_j) { 1191 return (0); 1192 } 1193 1194 val = c->txbuf[c->tx_j]; 1195 c->tx_j = (c->tx_j + 1) % E8530_BUF_MAX; 1196 1197 return (val); 1198} 1199 1200unsigned char e8530_send_a (e8530_t *scc) 1201{ 1202 return (e8530_send (scc, 0)); 1203} 1204 1205unsigned char e8530_send_b (e8530_t *scc) 1206{ 1207 return (e8530_send (scc, 1)); 1208} 1209 1210int e8530_inp_full (e8530_t *scc, unsigned chn) 1211{ 1212 e8530_chn_t *c; 1213 1214 chn &= 1; 1215 c = &scc->chn[chn]; 1216 1217 if (((c->rx_i + 1) % E8530_BUF_MAX) == c->rx_j) { 1218 return (1); 1219 } 1220 1221 return (0); 1222} 1223 1224int e8530_out_empty (e8530_t *scc, unsigned chn) 1225{ 1226 e8530_chn_t *c; 1227 1228 chn &= 1; 1229 c = &scc->chn[chn]; 1230 1231 if (c->tx_i == c->tx_j) { 1232 return (1); 1233 } 1234 1235 return (0); 1236} 1237 1238static 1239void e8530_reset_channel (e8530_t *scc, unsigned chn) 1240{ 1241 e8530_chn_t *c; 1242 1243 chn &= 1; 1244 c = &scc->chn[chn]; 1245 1246 c->rr[0] |= 0x04; /* tx empty */ 1247// c->rr[0] |= 0x20; /* cts */ 1248 c->rr[1] |= 0x01; /* all sent */ 1249 1250 c->rr0_latch_msk = 0; 1251 1252 c->bps = 0; 1253 c->parity = 0; 1254 c->bpc = 0; 1255 c->stop = 0; 1256 1257 c->tx_i = 0; 1258 c->tx_j = 0; 1259 1260 c->rx_i = 0; 1261 c->rx_j = 0; 1262} 1263 1264void e8530_reset (e8530_t *scc) 1265{ 1266 unsigned i; 1267 1268 scc->index = 0; 1269 1270 for (i = 0; i < 16; i++) { 1271 scc->chn[0].rr[i] = 0; 1272 scc->chn[0].wr[i] = 0; 1273 scc->chn[1].rr[i] = 0; 1274 scc->chn[1].wr[i] = 0; 1275 } 1276 1277 e8530_reset_channel (scc, 0); 1278 e8530_reset_channel (scc, 1); 1279 1280 e8530_set_rts (scc, 0, 0); 1281 e8530_set_rts (scc, 1, 0); 1282 1283 e8530_set_irq (scc, 0); 1284} 1285 1286static inline 1287void e8530_chn_clock (e8530_t *scc, unsigned chn, unsigned n) 1288{ 1289 e8530_chn_t *c; 1290 1291 c = &scc->chn[chn]; 1292 1293 if (n < c->char_clk_cnt) { 1294 c->char_clk_cnt -= n; 1295 return; 1296 } 1297 else { 1298 n -= c->char_clk_cnt; 1299 } 1300 1301 if (n > c->char_clk_div) { 1302 n = n % c->char_clk_div; 1303 } 1304 1305 c->char_clk_cnt = c->char_clk_div - n; 1306 1307 c->read_char_cnt = c->read_char_max; 1308 c->write_char_cnt = c->write_char_max; 1309 1310 e8530_check_rxd (scc, chn); 1311 e8530_check_txd (scc, chn); 1312} 1313 1314void e8530_clock (e8530_t *scc, unsigned n) 1315{ 1316 e8530_chn_clock (scc, 0, n); 1317 e8530_chn_clock (scc, 1, n); 1318}