|
|
1.1 ! root 1: /* ! 2: * scc.cpp - SCC 85C30 emulation code ! 3: * ! 4: * Adaptions to Hatari: ! 5: * ! 6: * Copyright 2018 Thomas Huth ! 7: * ! 8: * Original code taken from Aranym: ! 9: * ! 10: * Copyright (c) 2001-2004 Petr Stehlik of ARAnyM dev team ! 11: * 2010 Jean Conter ! 12: * ! 13: * This code is free software; you can redistribute it and/or modify ! 14: * it under the terms of the GNU General Public License as published by ! 15: * the Free Software Foundation; either version 2 of the License, or ! 16: * (at your option) any later version. ! 17: * ! 18: * This code is distributed in the hope that it will be useful, ! 19: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 20: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 21: * GNU General Public License for more details. ! 22: * ! 23: * You should have received a copy of the GNU General Public License ! 24: * along with ARAnyM; if not, write to the Free Software ! 25: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! 26: */ ! 27: ! 28: #include "main.h" ! 29: ! 30: #if HAVE_TERMIOS_H ! 31: # include <termios.h> ! 32: # include <unistd.h> ! 33: #endif ! 34: #if HAVE_SYS_IOCTL_H ! 35: # include <sys/ioctl.h> ! 36: #endif ! 37: #include <sys/types.h> ! 38: #include <sys/stat.h> ! 39: #include <fcntl.h> ! 40: #include <errno.h> ! 41: ! 42: #include "configuration.h" ! 43: #include "ioMem.h" ! 44: #include "log.h" ! 45: #include "memorySnapShot.h" ! 46: #include "scc.h" ! 47: ! 48: #if 0 ! 49: #define bug printf ! 50: #define D(x) x ! 51: #else ! 52: #define bug(...) ! 53: #define D(x) ! 54: #endif ! 55: ! 56: #ifndef O_NONBLOCK ! 57: # ifdef O_NDELAY ! 58: # define O_NONBLOCK O_NDELAY ! 59: # else ! 60: # define O_NONBLOCK 0 ! 61: # endif ! 62: #endif ! 63: ! 64: #define RCA 0 ! 65: #define TBE 2 ! 66: #define CTS 5 ! 67: ! 68: struct SCC { ! 69: uint8_t regs[16]; ! 70: int charcount; ! 71: int rd_handle, wr_handle; ! 72: uint16_t oldTBE; ! 73: uint16_t oldStatus; ! 74: bool bFileHandleIsATTY; ! 75: }; ! 76: ! 77: static struct SCC scc[2]; ! 78: ! 79: static int active_reg; ! 80: static uint8_t RR3, RR3M; // common to channel A & B ! 81: ! 82: bool SCC_IsAvailable(CNF_PARAMS *cnf) ! 83: { ! 84: return ConfigureParams.System.nMachineType == MACHINE_MEGA_STE ! 85: || ConfigureParams.System.nMachineType == MACHINE_TT ! 86: || ConfigureParams.System.nMachineType == MACHINE_FALCON; ! 87: } ! 88: ! 89: void SCC_Init(void) ! 90: { ! 91: SCC_Reset(); ! 92: ! 93: scc[0].oldTBE = scc[1].oldTBE = 0; ! 94: scc[0].oldStatus = scc[1].oldStatus = 0; ! 95: ! 96: scc[0].rd_handle = scc[0].wr_handle = -1; ! 97: scc[1].rd_handle = scc[1].wr_handle = -1; ! 98: ! 99: D(bug("SCC: interface initialized\n")); ! 100: ! 101: if (!ConfigureParams.RS232.bEnableSccB || !SCC_IsAvailable(&ConfigureParams)) ! 102: return; ! 103: ! 104: if (ConfigureParams.RS232.sSccBInFileName[0] && ! 105: strcmp(ConfigureParams.RS232.sSccBInFileName, ConfigureParams.RS232.sSccBOutFileName) == 0) ! 106: { ! 107: #if HAVE_TERMIOS_H ! 108: scc[1].rd_handle = open(ConfigureParams.RS232.sSccBInFileName, O_RDWR | O_NONBLOCK); ! 109: if (scc[1].rd_handle >= 0) ! 110: { ! 111: if (isatty(scc[1].rd_handle)) ! 112: { ! 113: scc[1].wr_handle = scc[1].rd_handle; ! 114: } ! 115: else ! 116: { ! 117: Log_Printf(LOG_ERROR, "SCC_Init: Setting SCC-B input and output " ! 118: "to the same file only works with tty devices.\n"); ! 119: close(scc[1].rd_handle); ! 120: scc[1].rd_handle = -1; ! 121: } ! 122: } ! 123: else ! 124: { ! 125: Log_Printf(LOG_ERROR, "SCC_Init: Can not open device '%s'\n", ! 126: ConfigureParams.RS232.sSccBInFileName); ! 127: } ! 128: #else ! 129: Log_Printf(LOG_ERROR, "SCC_Init: Setting SCC-B input and output " ! 130: "to the same file is not supported on this system.\n"); ! 131: #endif ! 132: } ! 133: else ! 134: { ! 135: if (ConfigureParams.RS232.sSccBInFileName[0]) ! 136: { ! 137: scc[1].rd_handle = open(ConfigureParams.RS232.sSccBInFileName, O_RDONLY | O_NONBLOCK); ! 138: if (scc[1].rd_handle < 0) ! 139: { ! 140: Log_Printf(LOG_ERROR, "SCC_Init: Can not open input file '%s'\n", ! 141: ConfigureParams.RS232.sSccBInFileName); ! 142: } ! 143: } ! 144: if (ConfigureParams.RS232.sSccBOutFileName[0]) ! 145: { ! 146: scc[1].wr_handle = open(ConfigureParams.RS232.sSccBOutFileName, ! 147: O_CREAT | O_WRONLY | O_NONBLOCK, S_IRUSR | S_IWUSR); ! 148: if (scc[1].wr_handle < 0) ! 149: { ! 150: Log_Printf(LOG_ERROR, "SCC_Init: Can not open output file '%s'\n", ! 151: ConfigureParams.RS232.sSccBOutFileName); ! 152: } ! 153: } ! 154: } ! 155: if (scc[1].rd_handle == -1 && scc[1].wr_handle == -1) ! 156: { ! 157: ConfigureParams.RS232.bEnableSccB = false; ! 158: } ! 159: } ! 160: ! 161: void SCC_UnInit(void) ! 162: { ! 163: D(bug("SCC: interface destroyed\n")); ! 164: if (scc[1].rd_handle >= 0) ! 165: { ! 166: if (scc[1].wr_handle == scc[1].rd_handle) ! 167: scc[1].wr_handle = -1; ! 168: close(scc[1].rd_handle); ! 169: scc[1].rd_handle = -1; ! 170: } ! 171: if (scc[1].wr_handle >= 0) ! 172: { ! 173: close(scc[1].wr_handle); ! 174: scc[1].wr_handle = -1; ! 175: } ! 176: } ! 177: ! 178: void SCC_MemorySnapShot_Capture(bool bSave) ! 179: { ! 180: MemorySnapShot_Store(&active_reg, sizeof(active_reg)); ! 181: MemorySnapShot_Store(&RR3, sizeof(RR3)); ! 182: MemorySnapShot_Store(&RR3M, sizeof(RR3M)); ! 183: for (int c = 0; c < 2; c++) ! 184: { ! 185: MemorySnapShot_Store(scc[c].regs, sizeof(scc[c].regs)); ! 186: MemorySnapShot_Store(&scc[c].charcount, sizeof(scc[c].charcount)); ! 187: MemorySnapShot_Store(&scc[c].oldTBE, sizeof(scc[c].oldTBE)); ! 188: MemorySnapShot_Store(&scc[c].oldStatus, sizeof(scc[c].oldStatus)); ! 189: } ! 190: } ! 191: ! 192: static void SCC_channelAreset(void) ! 193: { ! 194: scc[0].regs[15] = 0xF8; ! 195: scc[0].regs[14] = 0xA0; ! 196: scc[0].regs[11] = 0x08; ! 197: scc[0].regs[9] = 0; ! 198: RR3 &= ~0x38; ! 199: RR3M &= ~0x38; ! 200: scc[0].regs[0] = 1 << TBE; // RR0A ! 201: } ! 202: ! 203: static void SCC_channelBreset(void) ! 204: { ! 205: scc[1].regs[15] = 0xF8; ! 206: scc[1].regs[14] = 0xA0; ! 207: scc[1].regs[11] = 0x08; ! 208: scc[0].regs[9] = 0; // single WR9 ! 209: RR3 &= ~7; ! 210: RR3M &= ~7; ! 211: scc[1].regs[0] = 1 << TBE; // RR0B ! 212: } ! 213: ! 214: void SCC_Reset() ! 215: { ! 216: active_reg = 0; ! 217: memset(scc[0].regs, 0, sizeof(scc[0].regs)); ! 218: memset(scc[1].regs, 0, sizeof(scc[1].regs)); ! 219: SCC_channelAreset(); ! 220: SCC_channelBreset(); ! 221: RR3 = 0; ! 222: RR3M = 0; ! 223: scc[0].charcount = scc[1].charcount = 0; ! 224: } ! 225: ! 226: static void TriggerSCC(bool enable) ! 227: { ! 228: if (enable) ! 229: { ! 230: Log_Printf(LOG_TODO, "TriggerSCC\n"); ! 231: } ! 232: } ! 233: ! 234: static uint8_t SCC_serial_getData(int channel) ! 235: { ! 236: uint8_t value = 0; ! 237: int nb; ! 238: ! 239: D(bug("SCC: getData\n")); ! 240: if (scc[channel].rd_handle >= 0) ! 241: { ! 242: nb = read(scc[channel].rd_handle, &value, 1); ! 243: if (nb < 0) ! 244: { ! 245: D(bug("SCC: impossible to get data\n")); ! 246: } ! 247: } ! 248: return value; ! 249: } ! 250: ! 251: static void SCC_serial_setData(int channel, uint8_t value) ! 252: { ! 253: int nb; ! 254: ! 255: D(bug("SCC: setData\n")); ! 256: if (scc[channel].wr_handle >= 0) ! 257: { ! 258: do ! 259: { ! 260: nb = write(scc[channel].wr_handle, &value, 1); ! 261: } while (nb < 0 && (errno == EAGAIN || errno == EINTR)); ! 262: } ! 263: } ! 264: ! 265: #if HAVE_TERMIOS_H ! 266: static void SCC_serial_setBaudAttr(int handle, speed_t new_speed) ! 267: { ! 268: struct termios options; ! 269: ! 270: if (handle < 0) ! 271: return; ! 272: ! 273: tcgetattr(handle, &options); ! 274: ! 275: cfsetispeed(&options, new_speed); ! 276: cfsetospeed(&options, new_speed); ! 277: ! 278: options.c_cflag |= (CLOCAL | CREAD); ! 279: options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // raw input ! 280: options.c_iflag &= ~(ICRNL); // CR is not CR+LF ! 281: ! 282: tcsetattr(handle, TCSANOW, &options); ! 283: } ! 284: #endif ! 285: ! 286: static void SCC_serial_setBaud(int channel, int value) ! 287: { ! 288: #if HAVE_TERMIOS_H ! 289: speed_t new_speed = B0; ! 290: ! 291: D(bug("SCC: setBaud %i\n", value)); ! 292: ! 293: switch (value) ! 294: { ! 295: case 230400: new_speed = B230400; break; ! 296: case 115200: new_speed = B115200; break; ! 297: case 57600: new_speed = B57600; break; ! 298: case 38400: new_speed = B38400; break; ! 299: case 19200: new_speed = B19200; break; ! 300: case 9600: new_speed = B9600; break; ! 301: case 4800: new_speed = B4800; break; ! 302: case 2400: new_speed = B2400; break; ! 303: case 1800: new_speed = B1800; break; ! 304: case 1200: new_speed = B1200; break; ! 305: case 600: new_speed = B600; break; ! 306: case 300: new_speed = B300; break; ! 307: case 200: new_speed = B200; break; ! 308: case 150: new_speed = B150; break; ! 309: case 134: new_speed = B134; break; ! 310: case 110: new_speed = B110; break; ! 311: case 75: new_speed = B75; break; ! 312: case 50: new_speed = B50; break; ! 313: default: D(bug("SCC: unsupported baud rate %i\n", value)); break; ! 314: } ! 315: ! 316: if (new_speed == B0) ! 317: return; ! 318: ! 319: SCC_serial_setBaudAttr(scc[channel].rd_handle, new_speed); ! 320: if (scc[channel].rd_handle != scc[channel].wr_handle) ! 321: SCC_serial_setBaudAttr(scc[channel].wr_handle, new_speed); ! 322: #endif ! 323: } ! 324: ! 325: static inline uint16_t SCC_getTBE(int chn) ! 326: { ! 327: uint16_t value = 0; ! 328: ! 329: #if defined(HAVE_SYS_IOCTL_H) && defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT) ! 330: int status = 0; ! 331: if (ioctl(scc[chn].wr_handle, TIOCSERGETLSR, &status) < 0) // OK with ttyS0, not OK with ttyUSB0 ! 332: { ! 333: // D(bug("SCC: Can't get LSR")); ! 334: value |= (1<<TBE); // only for serial USB ! 335: } ! 336: else if (status & TIOCSER_TEMT) ! 337: { ! 338: value = (1 << TBE); // this is a real TBE for ttyS0 ! 339: if ((scc[chn].oldTBE & (1 << TBE)) == 0) ! 340: { ! 341: value |= 0x200; ! 342: } // TBE rise=>TxIP (based on real TBE) ! 343: } ! 344: #endif ! 345: ! 346: scc[chn].oldTBE = value; ! 347: return value; ! 348: } ! 349: ! 350: static uint16_t SCC_serial_getStatus(int chn) ! 351: { ! 352: uint16_t value = 0; ! 353: uint16_t diff; ! 354: ! 355: #if defined(HAVE_SYS_IOCTL_H) && defined(FIONREAD) ! 356: if (scc[chn].rd_handle >= 0) ! 357: { ! 358: int nbchar = 0; ! 359: ! 360: if (ioctl(scc[chn].rd_handle, FIONREAD, &nbchar) < 0) ! 361: { ! 362: D(bug("SCC: Can't get input fifo count\n")); ! 363: } ! 364: scc[chn].charcount = nbchar; // to optimize input (see UGLY in handleWrite) ! 365: if (nbchar > 0) ! 366: value = 0x0401; // RxIC+RBF ! 367: } ! 368: #endif ! 369: #if defined(HAVE_SYS_IOCTL_H) && defined(TIOCMGET) ! 370: if (scc[chn].wr_handle >= 0 && scc[chn].bFileHandleIsATTY) ! 371: { ! 372: int status = 0; ! 373: ! 374: value |= SCC_getTBE(chn); // TxIC ! 375: value |= (1 << TBE); // fake TBE to optimize output (for ttyS0) ! 376: if (ioctl(scc[chn].wr_handle, TIOCMGET, &status) < 0) ! 377: { ! 378: D(bug("SCC: Can't get status\n")); ! 379: } ! 380: if (status & TIOCM_CTS) ! 381: value |= (1 << CTS); ! 382: } ! 383: #endif ! 384: ! 385: if (scc[chn].wr_handle >= 0 && !scc[chn].bFileHandleIsATTY) ! 386: { ! 387: /* Output is a normal file, thus always set Clear-To-Send ! 388: * and Transmit-Buffer-Empty: */ ! 389: value |= (1 << CTS) | (1 << TBE); ! 390: } ! 391: else if (scc[chn].wr_handle < 0) ! 392: { ! 393: /* If not connected, signal transmit-buffer-empty anyway to ! 394: * avoid that the program blocks while polling this bit */ ! 395: value |= (1 << TBE); ! 396: } ! 397: ! 398: diff = scc[chn].oldStatus ^ value; ! 399: if (diff & (1 << CTS)) ! 400: value |= 0x100; // ext status IC on CTS change ! 401: ! 402: D(bug("SCC: getStatus 0x%04x\n", value)); ! 403: ! 404: scc[chn].oldStatus = value; ! 405: return value; ! 406: } ! 407: ! 408: static void SCC_serial_setRTS(int chn, bool value) ! 409: { ! 410: #if defined(HAVE_SYS_IOCTL_H) && defined(TIOCMGET) ! 411: int status = 0; ! 412: ! 413: if (scc[chn].wr_handle >= 0 && scc[chn].bFileHandleIsATTY) ! 414: { ! 415: if (ioctl(scc[chn].wr_handle, TIOCMGET, &status) < 0) ! 416: { ! 417: D(bug("SCC: Can't get status for RTS\n")); ! 418: } ! 419: if (value) ! 420: status |= TIOCM_RTS; ! 421: else ! 422: status &= ~TIOCM_RTS; ! 423: ioctl(scc[chn].wr_handle, TIOCMSET, &status); ! 424: } ! 425: #endif ! 426: } ! 427: ! 428: static void SCC_serial_setDTR(int chn, bool value) ! 429: { ! 430: #if defined(HAVE_SYS_IOCTL_H) && defined(TIOCMGET) ! 431: int status = 0; ! 432: ! 433: if (scc[chn].wr_handle >= 0 && scc[chn].bFileHandleIsATTY) ! 434: { ! 435: if (ioctl(scc[chn].wr_handle, TIOCMGET, &status) < 0) ! 436: { ! 437: D(bug("SCC: Can't get status for DTR\n")); ! 438: } ! 439: if (value) ! 440: status |= TIOCM_DTR; ! 441: else ! 442: status &= ~TIOCM_DTR; ! 443: ioctl(scc[chn].wr_handle, TIOCMSET, &status); ! 444: } ! 445: #endif ! 446: } ! 447: ! 448: static uint8_t SCC_ReadControl(int chn) ! 449: { ! 450: uint8_t value = 0; ! 451: uint16_t temp; ! 452: ! 453: switch (active_reg) ! 454: { ! 455: case 0: // RR0 ! 456: temp = SCC_serial_getStatus(chn); ! 457: scc[chn].regs[0] = temp & 0xFF; // define CTS(5), TBE(2) and RBF=RCA(0) ! 458: if (chn) ! 459: RR3 = RR3M & (temp >> 8); // define RxIP(2), TxIP(1) and ExtIP(0) ! 460: else if (scc[0].regs[9] == 0x20) ! 461: RR3 |= 0x8; ! 462: value = scc[chn].regs[0]; ! 463: break; ! 464: case 2: // not really useful (RR2 seems unaccessed...) ! 465: value = scc[0].regs[2]; ! 466: if (chn == 0) // vector base only for RR2A ! 467: break; ! 468: if ((scc[0].regs[9] & 1) == 0) // no status bit added ! 469: break; ! 470: // status bit added to vector ! 471: if (scc[0].regs[9] & 0x10) // modify high bits ! 472: { ! 473: if (RR3 == 0) ! 474: { ! 475: value |= 0x60; ! 476: break; ! 477: } ! 478: if (RR3 & 32) ! 479: { ! 480: value |= 0x30; // A RxIP ! 481: break; ! 482: } ! 483: if (RR3 & 16) ! 484: { ! 485: value |= 0x10; // A TxIP ! 486: break; ! 487: } ! 488: if (RR3 & 8) ! 489: { ! 490: value |= 0x50; // A Ext IP ! 491: break; ! 492: } ! 493: if (RR3 & 4) ! 494: { ! 495: value |= 0x20; // B RBF ! 496: break; ! 497: } ! 498: if (RR3 & 2) ! 499: break; // B TBE ! 500: if (RR3 & 1) ! 501: value |= 0x40; // B Ext Status ! 502: } ! 503: else // modify low bits ! 504: { ! 505: if (RR3 == 0) ! 506: { ! 507: value |= 6; // no one ! 508: break; ! 509: } ! 510: if (RR3 & 32) ! 511: { ! 512: value |= 0xC; // A RxIP ! 513: break; ! 514: } ! 515: if (RR3 & 16) ! 516: { ! 517: value |= 0x8; // A TxIP ! 518: break; ! 519: } ! 520: if (RR3 & 8) ! 521: { ! 522: value |= 0xA; // A Ext IP ! 523: break; ! 524: } ! 525: if (RR3 & 4) ! 526: { ! 527: value |= 4; // B RBF ! 528: break; ! 529: } ! 530: if (RR3 & 2) ! 531: break; // B TBE ! 532: if (RR3 & 1) ! 533: value |= 2; // B Ext Status (CTS) ! 534: } ! 535: break; ! 536: case 3: ! 537: value = chn ? 0 : RR3; // access on A channel only ! 538: break; ! 539: case 4: // RR0 ! 540: value = scc[chn].regs[0]; ! 541: break; ! 542: case 8: // DATA reg ! 543: scc[chn].regs[8] = SCC_serial_getData(chn); ! 544: value = scc[chn].regs[8]; ! 545: break; ! 546: case 9: // WR13 ! 547: value = scc[chn].regs[13]; ! 548: break; ! 549: case 11: // WR15 ! 550: case 15: // EXT/STATUS IT Ctrl ! 551: value = scc[chn].regs[15] &= 0xFA; // mask out D2 and D0 ! 552: break; ! 553: case 12: // BRG LSB ! 554: case 13: // BRG MSB ! 555: value = scc[chn].regs[active_reg]; ! 556: break; ! 557: ! 558: default: // RR5,RR6,RR7,RR10,RR14 not processed ! 559: D(bug("scc : unprocessed read address=$%x *********\n", active_reg)); ! 560: value = 0; ! 561: break; ! 562: } ! 563: ! 564: return value; ! 565: } ! 566: ! 567: static uint8_t SCC_handleRead(uint32_t addr) ! 568: { ! 569: uint8_t value = 0; ! 570: int channel; ! 571: ! 572: addr &= 0x6; ! 573: channel = (addr >= 4) ? 1 : 0; // 0 = channel A, 1 = channel B ! 574: switch (addr) ! 575: { ! 576: case 0: // channel A ! 577: case 4: // channel B ! 578: value = SCC_ReadControl(channel); ! 579: break; ! 580: case 2: // channel A ! 581: case 6: // channel B ! 582: scc[channel].regs[8] = SCC_serial_getData(channel); ! 583: value = scc[channel].regs[8]; ! 584: break; ! 585: default: ! 586: D(bug("scc : illegal read address=$%x\n", addr)); ! 587: break; ! 588: } ! 589: ! 590: active_reg = 0; // next access for RR0 or WR0 ! 591: ! 592: return value; ! 593: } ! 594: ! 595: static void SCC_WriteControl(int chn, uint8_t value) ! 596: { ! 597: uint32_t BaudRate; ! 598: int i; ! 599: ! 600: if (active_reg == 0) ! 601: { ! 602: ! 603: if (value <= 15) ! 604: { ! 605: active_reg = value & 0x0f; ! 606: } ! 607: else ! 608: { ! 609: if ((value & 0x38) == 0x38) // Reset Highest IUS (last operation in IT service routine) ! 610: { ! 611: for (i = 0x20; i; i >>= 1) ! 612: { ! 613: if (RR3 & i) ! 614: break; ! 615: } ! 616: #define UGLY ! 617: #ifdef UGLY ! 618: // tricky & ugly speed improvement for input ! 619: if (i == 4) // RxIP ! 620: { ! 621: scc[chn].charcount--; ! 622: if (scc[chn].charcount <= 0) ! 623: RR3 &= ~4; // optimize input; don't reset RxIP when chars are buffered ! 624: } ! 625: else ! 626: { ! 627: RR3 &= ~i; ! 628: } ! 629: #else ! 630: RR3 &= ~i; ! 631: #endif ! 632: } ! 633: else if ((value & 0x38) == 0x28) // Reset Tx int pending ! 634: { ! 635: if (chn) ! 636: RR3 &= ~2; // channel B ! 637: else ! 638: RR3 &= ~0x10; // channel A ! 639: } ! 640: else if ((value & 0x38) == 0x10) // Reset Ext/Status ints ! 641: { ! 642: if (chn) ! 643: RR3 &= ~1; // channel B ! 644: else ! 645: RR3 &= ~8; // channel A ! 646: } ! 647: // Clear SCC flag if no pending IT or no properly ! 648: // configured WR9. Must be done here to avoid ! 649: // scc_do_Interrupt call without pending IT ! 650: TriggerSCC((RR3 & RR3M) && ((0xB & scc[0].regs[9]) == 9)); ! 651: } ! 652: return; ! 653: } ! 654: ! 655: // active_reg > 0: ! 656: scc[chn].regs[active_reg] = value; ! 657: if (active_reg == 2) ! 658: { ! 659: scc[0].regs[active_reg] = value; // single WR2 on SCC ! 660: } ! 661: else if (active_reg == 8) ! 662: { ! 663: SCC_serial_setData(chn, value); ! 664: } ! 665: else if (active_reg == 1) // Tx/Rx interrupt enable ! 666: { ! 667: if (chn == 0) ! 668: { ! 669: // channel A ! 670: if (value & 1) ! 671: RR3M |= 8; ! 672: else ! 673: RR3 &= ~8; // no IP(RR3) if not enabled(RR3M) ! 674: if (value & 2) ! 675: RR3M |= 16; ! 676: else ! 677: RR3 &= ~16; ! 678: if (value & 0x18) ! 679: RR3M |= 32; ! 680: else ! 681: RR3 &= ~32; ! 682: } ! 683: else ! 684: { ! 685: // channel B ! 686: if (value & 1) ! 687: RR3M |= 1; ! 688: else ! 689: RR3 &= ~1; ! 690: if (value & 2) ! 691: RR3M |= 2; ! 692: else ! 693: RR3 &= ~2; ! 694: if (value & 0x18) ! 695: RR3M |= 4; ! 696: else ! 697: RR3 &= ~4; ! 698: // set or clear SCC flag if necessary (see later) ! 699: } ! 700: } ! 701: else if (active_reg == 5) // Transmit parameter and control ! 702: { ! 703: SCC_serial_setRTS(chn, value & 2); ! 704: SCC_serial_setDTR(chn, value & 128); ! 705: // Tx character format & Tx CRC would be selected also here (8 bits/char and no CRC assumed) ! 706: } ! 707: else if (active_reg == 9) // Master interrupt control (common for both channels) ! 708: { ! 709: scc[0].regs[9] = value; // single WR9 (accessible by both channels) ! 710: if (value & 0x40) ! 711: { ! 712: SCC_channelBreset(); ! 713: } ! 714: if (value & 0x80) ! 715: { ! 716: SCC_channelAreset(); ! 717: } ! 718: // set or clear SCC flag accordingly (see later) ! 719: } ! 720: else if (active_reg == 13) // set baud rate according to WR13 and WR12 ! 721: { ! 722: // Normally we have to set the baud rate according ! 723: // to clock source (WR11) and clock mode (WR4) ! 724: // In fact, we choose the baud rate from the value stored in WR12 & WR13 ! 725: // Note: we assume that WR13 is always written last (after WR12) ! 726: // we tried to be more or less compatible with HSMODEM (see below) ! 727: // 75 and 50 bauds are preserved because 153600 and 76800 were not available ! 728: // 3600 and 2000 were also unavailable and are remapped to 57600 and 38400 respectively ! 729: BaudRate = 0; ! 730: switch (value) ! 731: { ! 732: case 0: ! 733: switch (scc[chn].regs[12]) ! 734: { ! 735: case 0: // HSMODEM for 200 mapped to 230400 ! 736: BaudRate = 230400; ! 737: break; ! 738: case 2: // HSMODEM for 150 mapped to 115200 ! 739: BaudRate = 115200; ! 740: break; ! 741: case 6: // HSMODEM for 134 mapped to 57600 ! 742: case 0x7e: // HSMODEM for 3600 remapped to 57600 ! 743: case 0x44: // normal for 3600 remapped to 57600 ! 744: BaudRate = 57600; ! 745: break; ! 746: case 0xa: // HSMODEM for 110 mapped to 38400 ! 747: case 0xe4: // HSMODEM for 2000 remapped to 38400 ! 748: case 0x7c: // normal for 2000 remapped to 38400 ! 749: BaudRate = 38400; ! 750: break; ! 751: case 0x16: // HSMODEM for 19200 ! 752: case 0xb: // normal for 19200 ! 753: BaudRate = 19200; ! 754: break; ! 755: case 0x2e: // HSMODEM for 9600 ! 756: case 0x18: // normal for 9600 ! 757: BaudRate = 9600; ! 758: break; ! 759: case 0x5e: // HSMODEM for 4800 ! 760: case 0x32: // normal for 4800 ! 761: BaudRate = 4800; ! 762: break; ! 763: case 0xbe: // HSMODEM for 2400 ! 764: case 0x67: // normal ! 765: BaudRate = 2400; ! 766: break; ! 767: case 0xfe: // HSMODEM for 1800 ! 768: case 0x8a: // normal for 1800 ! 769: BaudRate = 1800; ! 770: break; ! 771: case 0xd0: // normal for 1200 ! 772: BaudRate = 1200; ! 773: break; ! 774: case 1: // HSMODEM for 75 kept to 75 ! 775: BaudRate = 75; ! 776: break; ! 777: case 4: // HSMODEM for 50 kept to 50 ! 778: BaudRate = 50; ! 779: break; ! 780: default: ! 781: D(bug("SCC: unexpected LSB constant for baud rate\n")); ! 782: break; ! 783: } ! 784: break; ! 785: case 1: ! 786: switch (scc[chn].regs[12]) ! 787: { ! 788: case 0xa1: // normal for 600 ! 789: BaudRate = 600; ! 790: break; ! 791: case 0x7e: // HSMODEM for 1200 ! 792: BaudRate = 1200; ! 793: break; ! 794: } ! 795: break; ! 796: case 2: ! 797: if (scc[chn].regs[12] == 0xfe) ! 798: BaudRate = 600; //HSMODEM ! 799: break; ! 800: case 3: ! 801: if (scc[chn].regs[12] == 0x45) ! 802: BaudRate = 300; //normal ! 803: break; ! 804: case 4: ! 805: if (scc[chn].regs[12] == 0xe8) ! 806: BaudRate = 200; //normal ! 807: break; ! 808: case 5: ! 809: if (scc[chn].regs[12] == 0xfe) ! 810: BaudRate = 300; //HSMODEM ! 811: break; ! 812: case 6: ! 813: if (scc[chn].regs[12] == 0x8c) ! 814: BaudRate = 150; //normal ! 815: break; ! 816: case 7: ! 817: if (scc[chn].regs[12] == 0x4d) ! 818: BaudRate = 134; //normal ! 819: break; ! 820: case 8: ! 821: if (scc[chn].regs[12] == 0xee) ! 822: BaudRate = 110; //normal ! 823: break; ! 824: case 0xd: ! 825: if (scc[chn].regs[12] == 0x1a) ! 826: BaudRate = 75; //normal ! 827: break; ! 828: case 0x13: ! 829: if (scc[chn].regs[12] == 0xa8) ! 830: BaudRate = 50; //normal ! 831: break; ! 832: case 0xff: // HSMODEM dummy value->silently ignored ! 833: break; ! 834: default: ! 835: D(bug("SCC: unexpected MSB constant for baud rate\n")); ! 836: break; ! 837: } ! 838: if (BaudRate) // set only if defined ! 839: SCC_serial_setBaud(chn, BaudRate); ! 840: ! 841: /* summary of baud rates: ! 842: Rsconf Falcon Falcon(+HSMODEM) Hatari Hatari(+HSMODEM) ! 843: 0 19200 19200 19200 19200 ! 844: 1 9600 9600 9600 9600 ! 845: 2 4800 4800 4800 4800 ! 846: 3 3600 3600 57600 57600 ! 847: 4 2400 2400 2400 2400 ! 848: 5 2000 2000 38400 38400 ! 849: 6 1800 1800 1800 1800 ! 850: 7 1200 1200 1200 1200 ! 851: 8 600 600 600 600 ! 852: 9 300 300 300 300 ! 853: 10 200 230400 200 230400 ! 854: 11 150 115200 150 115200 ! 855: 12 134 57600 134 57600 ! 856: 13 110 38400 110 38400 ! 857: 14 75 153600 75 75 ! 858: 15 50 76800 50 50 ! 859: */ ! 860: } ! 861: else if (active_reg == 15) // external status int control ! 862: { ! 863: if (value & 1) ! 864: { ! 865: D(bug("SCC WR7 prime not yet processed\n")); ! 866: } ! 867: } ! 868: ! 869: // set or clear SCC flag accordingly. Yes it's ugly but avoids unnecessary useless calls ! 870: if (active_reg == 1 || active_reg == 2 || active_reg == 9) ! 871: TriggerSCC((RR3 & RR3M) && ((0xB & scc[0].regs[9]) == 9)); ! 872: ! 873: active_reg = 0; // next access for RR0 or WR0 ! 874: } ! 875: ! 876: static void SCC_handleWrite(uint32_t addr, uint8_t value) ! 877: { ! 878: int channel; ! 879: ! 880: addr &= 0x6; ! 881: channel = (addr >= 4) ? 1 : 0; // 0 = channel A, 1 = channel B ! 882: switch (addr) ! 883: { ! 884: case 0: ! 885: case 4: ! 886: SCC_WriteControl(channel, value); ! 887: break; ! 888: case 2: // channel A ! 889: case 6: // channel B ! 890: SCC_serial_setData(channel, value); ! 891: break; ! 892: default: ! 893: D(bug( "scc : illegal write address =$%x\n", addr)); ! 894: break; ! 895: } ! 896: } ! 897: ! 898: void SCC_IRQ(void) ! 899: { ! 900: uint16_t temp; ! 901: temp = SCC_serial_getStatus(0); ! 902: if (scc[0].regs[9] == 0x20) ! 903: temp |= 0x800; // fake ExtStatusChange for HSMODEM install ! 904: scc[1].regs[0] = temp & 0xFF; // RR0B ! 905: RR3 = RR3M & (temp >> 8); ! 906: if (RR3 && (scc[0].regs[9] & 0xB) == 9) ! 907: TriggerSCC(true); ! 908: } ! 909: ! 910: ! 911: // return : vector number, or zero if no interrupt ! 912: int SCC_doInterrupt() ! 913: { ! 914: int vector; ! 915: uint8_t i; ! 916: for (i = 0x20 ; i ; i >>= 1) // highest priority first ! 917: { ! 918: if (RR3 & i & RR3M) ! 919: break ; ! 920: } ! 921: vector = scc[0].regs[2]; // WR2 = base of vectored interrupts for SCC ! 922: if ((scc[0].regs[9] & 3) == 0) ! 923: return vector; // no status included in vector ! 924: if ((scc[0].regs[9] & 0x32) != 0) // shouldn't happen with TOS, (to be completed if needed) ! 925: { ! 926: D(bug( "unexpected WR9 contents \n")); ! 927: // no Soft IACK, Status Low control bit expected, no NV ! 928: return 0; ! 929: } ! 930: switch (i) ! 931: { ! 932: case 0: /* this shouldn't happen :-) */ ! 933: D(bug( "scc_do_interrupt called with no pending interrupt\n")); ! 934: vector = 0; // cancel ! 935: break; ! 936: case 1: ! 937: vector |= 2; // Ch B Ext/status change ! 938: break; ! 939: case 2: ! 940: break;// Ch B Transmit buffer Empty ! 941: case 4: ! 942: vector |= 4; // Ch B Receive Char available ! 943: break; ! 944: case 8: ! 945: vector |= 0xA; // Ch A Ext/status change ! 946: break; ! 947: case 16: ! 948: vector |= 8; // Ch A Transmit Buffer Empty ! 949: break; ! 950: case 32: ! 951: vector |= 0xC; // Ch A Receive Char available ! 952: break; ! 953: // special receive condition not yet processed ! 954: } ! 955: #if 0 ! 956: D(bug( "SCC_doInterrupt : vector %d\n", vector)); ! 957: #endif ! 958: return vector ; ! 959: } ! 960: ! 961: ! 962: void SCC_IoMem_ReadByte(void) ! 963: { ! 964: int i; ! 965: ! 966: for (i = 0; i < nIoMemAccessSize; i++) ! 967: { ! 968: uint32_t addr = IoAccessBaseAddress + i; ! 969: if (addr & 1) ! 970: IoMem[addr] = SCC_handleRead(addr); ! 971: else ! 972: IoMem[addr] = 0xff; ! 973: } ! 974: } ! 975: ! 976: void SCC_IoMem_WriteByte(void) ! 977: { ! 978: int i; ! 979: ! 980: for (i = 0; i < nIoMemAccessSize; i++) ! 981: { ! 982: uint32_t addr = IoAccessBaseAddress + i; ! 983: if (addr & 1) ! 984: SCC_handleWrite(addr, IoMem[addr]); ! 985: } ! 986: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.