Annotation of hatari/src/scc.c, revision 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.