Annotation of hatari/src/scc.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.