Annotation of nono/vm/scc.cpp, revision 1.1.1.10

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.10! root        7: //
        !             8: // SCC (Z8530)
        !             9: //
        !            10: 
1.1       root       11: #include "scc.h"
1.1.1.8   root       12: #include "bitops.h"
1.1.1.10! root       13: #include "hostcom.h"
1.1.1.8   root       14: #include "keyboard.h"
1.1.1.5   root       15: #include "mpu.h"
1.1       root       16: 
1.1.1.10! root       17: // グローバル参照用
        !            18: SCCDevice *gSCC;
1.1.1.2   root       19: 
1.1.1.10! root       20: // コンストラクタ
1.1       root       21: SCCDevice::SCCDevice()
1.1.1.7   root       22:        : inherited("SCC")
1.1       root       23: {
                     24:        devaddr = baseaddr;
                     25:        devlen  = 0x2000;
1.1.1.2   root       26: 
1.1.1.10! root       27:        mpscc.chan[0].desc = "Serial Port";
        !            28:        mpscc.chan[1].desc = "Mouse";
        !            29: 
        !            30:        // ポートアドレス。
        !            31:        // デバイス自身は自分が配置されるアドレスを知らなくてよい構造になって
        !            32:        // いるが、直接アクセスしたりする場合などに毎回アドレスを確認するのが
        !            33:        // 面倒なので(全機種で向きと間隔が異なる)、モニタで表示されてほしい。
        !            34:        mpscc.chan[1].ctrladdr = 0xe98001;
        !            35:        mpscc.chan[1].dataaddr = 0xe98003;
        !            36:        mpscc.chan[0].ctrladdr = 0xe98005;
        !            37:        mpscc.chan[0].dataaddr = 0xe98007;
1.1.1.7   root       38: 
                     39:        // X680x0 では SCC と呼ぶほうが通りがいい。
1.1.1.10! root       40:        // イベントの登録は親クラスで行ってある。
1.1.1.9   root       41:        for (int ch = 0; ch < txevent.size(); ch++) {
1.1.1.10! root       42:                auto& chan = mpscc.chan[ch];
        !            43:                txevent[ch].SetName(string_format("SCC Ch%c TX", chan.name));
        !            44:                rxevent[ch].SetName(string_format("SCC Ch%c RX", chan.name));
1.1.1.9   root       45:        }
1.1.1.10! root       46: 
        !            47:        monitor.func = ToMonitorCallback(&SCCDevice::MonitorUpdate);
        !            48:        monitor.SetSize(70, 35);
1.1.1.7   root       49:        monitor.Regist(ID_MONITOR_SCC);
1.1       root       50: }
                     51: 
1.1.1.10! root       52: // デストラクタ
1.1       root       53: SCCDevice::~SCCDevice()
                     54: {
1.1.1.10! root       55:        gSCC = NULL;
        !            56: }
        !            57: 
        !            58: // リセット
        !            59: void
        !            60: SCCDevice::ResetHard(bool poweron)
        !            61: {
        !            62:        // Z8530 は RD と WR を同時に Low にするとリセットがかかる。
        !            63:        // 回路図からは PEDEC から繋がってるという以上のことは分からないけど
        !            64:        // 普通に考えればハードリセットでリセットされるよな。
        !            65: 
        !            66:        // WR9 b2,3,4 = %0、b6,7 = %1
        !            67:        mpscc.disable_lower_chain = false;
        !            68:        mpscc.master_int_enable = false;
        !            69:        mpscc.status_high_low = false;
        !            70:        // XXX Reset
        !            71: 
        !            72:        for (auto& chan : mpscc.chan) {
        !            73:                ResetChannel(chan);
        !            74: 
        !            75:                // WR10 b5,6 = %0
        !            76:                chan.wr10 &= ~0x40;
        !            77: 
        !            78:                // WR11
        !            79:                chan.wr11 = 0x08;
        !            80: 
        !            81:                // WR14 b0-1 = %0
        !            82:                //
        !            83:                // b4 (Local Loopback) は p.2-15 ではチャンネルリセット時は %0、
        !            84:                // ハードリセット時は %1 に初期化されると書いてあるが、おそらく
        !            85:                // そんなことはないだろうし、p.5-20 の WR14 の説明には
        !            86:                // "This bit is reset by a channel or hardware reset." とあるので
        !            87:                // たぶんこっちのほうが正しい。
        !            88:                chan.wr14 &= ~0x03;
        !            89:        }
1.1       root       90: }
                     91: 
1.1.1.10! root       92: // チャンネルリセット
        !            93: void
        !            94: SCCDevice::ResetChannel(MPSCCChan& chan)
        !            95: {
        !            96:        // WR0 b0-7 = %0
        !            97:        chan.crc_cmd = 0;
        !            98:        chan.cmd = 0;
        !            99:        chan.ptr = 0;
        !           100: 
        !           101:        // WR1 b0,1,3,4,6,7 = %0
        !           102:        chan.esint_enable = false;
        !           103:        chan.txint_enable = false;
        !           104:        chan.rxint_mode   = MPSCCChan::RXINT_DISABLE;
        !           105:        chan.wait_func    = false;
        !           106:        chan.wait_enable  = false;
        !           107: 
        !           108:        // WR3 b0 = %0
        !           109:        chan.rx_enable = false;
        !           110: 
        !           111:        // WR4 b2 = %1
        !           112:        // b2,3 が StopBits 設定だが b2 だけ %1 にするらしい…。
        !           113:        // 少なくとも非同期モードにしときたいということだろうか。
        !           114:        chan.cr4 |= 0x04;
        !           115: 
        !           116:        // WR5 b1,2,3,4,7 = %0
        !           117:        chan.cr5 &= 0x61;
        !           118:        chan.tx_enable = false;
        !           119: 
        !           120:        // WR9 b5 = %0 (未実装ビット)
        !           121: 
        !           122:        // WR10 b0-4,7 = %0
        !           123:        chan.wr10 &= 0x60;
        !           124: 
        !           125:        // WR14 b2-4 = %0、b5 = %1
        !           126:        chan.wr14 &= 0xe3;
        !           127:        chan.wr14 |= 0x20;
        !           128: 
        !           129:        // WR15
        !           130:        chan.wr15 = 0xf8;
        !           131: 
        !           132:        // RR0 b0,1=%0、b2,6=%1
        !           133:        chan.tx_underrun = true;
        !           134: 
        !           135:        // RR1 b1,2=%1、b3-7=%0
        !           136:        chan.sr1 &= ~(MPSCC::SR1_ENDOFFRAME |
        !           137:                      MPSCC::SR1_FRAMEERROR |
        !           138:                      MPSCC::SR1_RXOVERRUN  |
        !           139:                      MPSCC::SR1_PARITYERROR);
        !           140:        chan.sr1 &= 0x08;
        !           141:        chan.sr1 |= 0x60;
        !           142: 
        !           143:        // RR3
        !           144:        chan.intpend = 0;
        !           145: 
        !           146:        // RR10 b0-5,7 = %0
        !           147:        chan.rr10 &= 0x40;
        !           148: 
        !           149:        ResetChannelCommon(chan);
        !           150: }
1.1       root      151: 
                    152: uint64
1.1.1.6   root      153: SCCDevice::Read(uint32 offset)
1.1       root      154: {
1.1.1.10! root      155:        uint64 data;
        !           156: 
1.1.1.4   root      157:        gMPU->AddCycle(41);     // InsideOut p.135
                    158: 
1.1.1.6   root      159:        switch (offset) {
1.1.1.3   root      160:         case 0:        // $E98001
1.1.1.10! root      161:                data = ReadCtrl(mpscc.chan[1]);
        !           162:                break;
1.1.1.3   root      163:         case 1:        // $E98003
1.1.1.10! root      164:                data = ReadData(mpscc.chan[1]);
        !           165:                break;
1.1.1.3   root      166:         case 2:        // $E98005
1.1.1.10! root      167:                data = ReadCtrl(mpscc.chan[0]);
        !           168:                break;
1.1.1.3   root      169:         case 3:        // $E98007
1.1       root      170:                putlog(0, "ChA データレジスタ読み込み (未実装)");
1.1.1.10! root      171:                data = ReadData(mpscc.chan[0]);
        !           172:                break;
        !           173:         default:
        !           174:                __unreachable();
1.1       root      175:        }
1.1.1.10! root      176:        return data;
1.1       root      177: }
                    178: 
                    179: uint64
1.1.1.6   root      180: SCCDevice::Write(uint32 offset, uint32 data)
1.1       root      181: {
1.1.1.4   root      182:        gMPU->AddCycle(49);     // InsideOut p.135
                    183: 
1.1.1.6   root      184:        switch (offset) {
1.1.1.3   root      185:         case 0:        // $E98001
1.1.1.10! root      186:                WriteCtrl(mpscc.chan[1], data);
        !           187:                break;
1.1.1.3   root      188:         case 1:        // $E98003
1.1.1.10! root      189:                WriteData(mpscc.chan[1], data);
        !           190:                break;
1.1.1.3   root      191:         case 2:        // $E98005
1.1.1.10! root      192:                WriteCtrl(mpscc.chan[0], data);
        !           193:                break;
1.1.1.3   root      194:         case 3:        // $E98007
1.1.1.10! root      195:                WriteData(mpscc.chan[0], data);
        !           196:                break;
        !           197:         default:
        !           198:                __unreachable();
1.1       root      199:        }
1.1.1.10! root      200:        return 0;
1.1       root      201: }
                    202: 
                    203: uint64
1.1.1.6   root      204: SCCDevice::Peek(uint32 offset)
1.1       root      205: {
1.1.1.10! root      206:        uint64 data;
        !           207: 
1.1.1.6   root      208:        switch (offset) {
1.1.1.3   root      209:         case 0:        // $E98001
1.1.1.10! root      210:                data = PeekCtrl(mpscc.chan[1]);
        !           211:                break;
1.1.1.3   root      212:         case 1:        // $E98003
1.1.1.10! root      213:                data = PeekData(mpscc.chan[1]);
        !           214:                break;
1.1.1.3   root      215:         case 2:        // $E98005
1.1.1.10! root      216:                data = PeekCtrl(mpscc.chan[0]);
        !           217:                break;
1.1.1.3   root      218:         case 3:        // $E98007
1.1.1.10! root      219:                data = PeekData(mpscc.chan[0]);
        !           220:                break;
        !           221:         default:
        !           222:                __unreachable();
1.1.1.2   root      223:        }
1.1.1.10! root      224:        return data;
1.1       root      225: }
                    226: 
1.1.1.10! root      227: // 書き込みレジスタ名を返す。
1.1.1.9   root      228: const char *
1.1.1.10! root      229: SCCDevice::CRName(const MPSCCChan& chan, int ptr_) const
1.1.1.9   root      230: {
                    231:        assert(ptr_ < 16);
1.1.1.10! root      232:        int idx = ptr_ * 2 + chan.id;
1.1.1.9   root      233:        assert(idx < countof(wrnames));
                    234:        return wrnames[idx];
                    235: }
                    236: 
1.1.1.10! root      237: // 読み込みレジスタ名を返す。
1.1.1.9   root      238: const char *
1.1.1.10! root      239: SCCDevice::SRName(const MPSCCChan& chan, int ptr_) const
1.1.1.9   root      240: {
                    241:        assert(ptr_ < 16);
1.1.1.10! root      242:        int idx = ptr_ * 2 + chan.id;
1.1.1.9   root      243:        assert(idx < countof(rrnames));
                    244:        return rrnames[idx];
                    245: }
                    246: 
1.1       root      247: // Z8530 制御ポート読み込み
                    248: uint8
1.1.1.10! root      249: SCCDevice::ReadCtrl(MPSCCChan& chan)
1.1       root      250: {
1.1.1.10! root      251:        uint8 data;
1.1       root      252: 
1.1.1.10! root      253:        // PTR とレジスタの対応 (Z8530 p.2-13)
        !           254:        //
        !           255:        // PTR Reg              PTR Reg         PTR Reg                 PTR Reg
        !           256:        // 0 = RR0              4 = (RR0)        8 = RR8                12 = RR12
        !           257:        // 1 = RR1              5 = (RR1)        9 = (RR13)             13 = RR13
        !           258:        // 2 = RR2              6 = (RR2)       10 = RR10               14 = RR14
        !           259:        // 3 = RR3              7 = (RR3)       11 = (RR15)             15 = RR15
1.1       root      260: 
1.1.1.10! root      261:        switch (chan.ptr) {
        !           262:         case 0:        // RR0
        !           263:         case 4:
        !           264:                data = GetRR0(chan);
1.1       root      265:                break;
                    266: 
1.1.1.10! root      267:         case 1:        // RR1
1.1       root      268:         case 5:
1.1.1.10! root      269:                data = chan.sr1;
        !           270:                break;
        !           271: 
        !           272:         case 2:
1.1       root      273:         case 6:
1.1.1.10! root      274:                if (chan.id == 0) {     // RR2A
        !           275:                        data = mpscc.vector;
        !           276:                } else {                        // RR2B
        !           277:                        // 割り込み要因で変化したベクタ
        !           278:                        data = GetSR2B();
        !           279:                }
        !           280:                break;
        !           281: 
        !           282:         case 3:
1.1       root      283:         case 7:
1.1.1.10! root      284:                if (chan.id == 0) {     // RR3A
        !           285:                        data = GetRR3A();
        !           286:                } else {                        // RR3B
        !           287:                        data = 0;
        !           288:                }
1.1       root      289:                break;
                    290: 
1.1.1.10! root      291:         case 8:
        !           292:         case 10:
        !           293:         case 12:
        !           294:         case 13:
        !           295:         case 9:
        !           296:         case 14:
        !           297:         case 15:
        !           298:         case 11:
        !           299:                putlog(0, "ReadCtrl 未実装 %d", chan.ptr);
        !           300:                data = 0xff;
1.1       root      301:                break;
                    302: 
1.1.1.10! root      303:         default:
        !           304:                __unreachable();
        !           305:        }
        !           306:        return data;
        !           307: }
        !           308: 
        !           309: // Z8530 制御ポート書き込み
        !           310: void
        !           311: SCCDevice::WriteCtrl(MPSCCChan& chan, uint32 data)
        !           312: {
        !           313:        // WR0 はコマンドかまたは次にアクセスするレジスタを指定する。
        !           314:        // WR0 以外のレジスタをアクセスすると、次のアクセスは WR0 に戻る。
        !           315: 
        !           316:        if (chan.ptr == 0) {
        !           317:                WriteWR0(chan, data);
        !           318:        } else {
        !           319:                switch (chan.ptr) {
        !           320:                 case 1:
        !           321:                        WriteWR1(chan, data);
1.1       root      322:                        break;
1.1.1.10! root      323:                 case 2:
        !           324:                        WriteWR2(data);
1.1       root      325:                        break;
1.1.1.10! root      326:                 case 3:
        !           327:                        WriteCR3(chan, data);
1.1       root      328:                        break;
1.1.1.10! root      329:                 case 4:
        !           330:                        WriteCR4(chan, data);
        !           331:                        break;
        !           332:                 case 5:
        !           333:                        WriteWR5(chan, data);
        !           334:                        break;
        !           335:                 case 6:
        !           336:                        WriteCR6(chan, data);
        !           337:                        break;
        !           338:                 case 7:
        !           339:                        WriteCR7(chan, data);
        !           340:                        break;
        !           341: 
        !           342:                 case 8:
        !           343:                        WriteData(chan, data);
        !           344:                        break;
        !           345:                 case 9:
        !           346:                        WriteWR9(data);
        !           347:                        break;
        !           348:                 case 10:
        !           349:                        WriteWR10(chan, data);
        !           350:                        break;
        !           351:                 case 11:
        !           352:                        WriteWR11(chan, data);
        !           353:                        break;
        !           354:                 case 12:
        !           355:                        WriteWR12(chan, data);
        !           356:                        break;
        !           357:                 case 13:
        !           358:                        WriteWR13(chan, data);
        !           359:                        break;
        !           360:                 case 14:
        !           361:                        WriteWR14(chan, data);
        !           362:                        break;
        !           363:                 case 15:
        !           364:                        WriteWR15(chan, data);
1.1       root      365:                        break;
                    366:                 default:
                    367:                        __unreachable();
                    368:                }
                    369:                // アクセス後は WR0 へ戻す
1.1.1.10! root      370:                chan.ptr = 0;
        !           371:        }
        !           372: }
1.1       root      373: 
1.1.1.10! root      374: // 制御ポートの Peek
        !           375: uint8
        !           376: SCCDevice::PeekCtrl(const MPSCCChan& chan) const
        !           377: {
        !           378:        uint8 data;
        !           379: 
        !           380:        switch (chan.ptr) {
        !           381:         case 0:        // RR0
        !           382:         case 4:
        !           383:                data = GetRR0(chan);
1.1.1.5   root      384:                break;
                    385: 
1.1.1.10! root      386:         case 1:        // RR1
        !           387:         case 5:
        !           388:                data = chan.sr1;
1.1       root      389:                break;
                    390: 
1.1.1.10! root      391:         case 2:
        !           392:         case 6:
        !           393:                if (chan.id == 0) {     // RR2A
        !           394:                        data = mpscc.vector;
        !           395:                } else {
        !           396:                        data = GetSR2B();
        !           397:                }
1.1       root      398:                break;
                    399: 
1.1.1.10! root      400:         case 3:
        !           401:         case 7:
        !           402:                if (chan.id == 0) {     // RR3A
        !           403:                        data = GetRR3A();
        !           404:                } else {                        // RR3B
        !           405:                        data = 0;
        !           406:                }
1.1       root      407:                break;
                    408: 
1.1.1.10! root      409:         case 8:
        !           410:                data = PeekData(chan);
1.1       root      411:                break;
                    412: 
1.1.1.10! root      413:         case 10:
        !           414:         case 12:
        !           415:         case 13:
        !           416:         case 9:
        !           417:         case 14:
        !           418:         case 15:
        !           419:         case 11:
        !           420:                putlog(0, "PeekCtrl 未実装 %d", chan.ptr);
        !           421:                data = 0xff;
1.1       root      422:                break;
                    423: 
                    424:         default:
1.1.1.10! root      425:                __unreachable();
        !           426:        }
        !           427:        return data;
        !           428: }
        !           429: 
        !           430: // WR1 レジスタの内容を取得
        !           431: uint8
        !           432: SCCDevice::GetWR1(const MPSCCChan& chan) const
        !           433: {
        !           434:        uint8 data = 0;
        !           435: 
        !           436:        if (chan.wait_enable)
        !           437:                data |= MPSCC::WR1_WAIT_EN;
        !           438:        if (chan.wait_func)
        !           439:                data |= MPSCC::WR1_WAIT_FUNC;
        !           440:        if (chan.wait_on_rx)
        !           441:                data |= MPSCC::WR1_WAIT_RX;
        !           442:        switch (chan.rxint_mode) {
        !           443:         case MPSCCChan::RXINT_DISABLE:
        !           444:                break;
        !           445:         case MPSCCChan::RXINT_1STCHAR:
        !           446:                data |= MPSCC::WR1_RXINT_1STCHAR;
1.1.1.9   root      447:                break;
1.1.1.10! root      448:         case MPSCCChan::RXINT_ALLCHAR:
        !           449:                data |= MPSCC::WR1_RXINT_ALLCHAR;
        !           450:                break;
        !           451:         case MPSCCChan::RXINT_SPONLY:
        !           452:                data |= MPSCC::WR1_RXINT_SPONLY;
        !           453:                break;
        !           454:         default:
        !           455:                __unreachable();
1.1.1.9   root      456:        }
1.1.1.10! root      457:        if (chan.sp_parity)
        !           458:                data |= MPSCC::WR1_SP_INC_PE;
        !           459:        if (chan.txint_enable)
        !           460:                data |= MPSCC::WR1_TXINT_EN;
        !           461:        if (chan.esint_enable)
        !           462:                data |= MPSCC::WR1_ESINT_EN;
        !           463: 
        !           464:        return data;
1.1.1.9   root      465: }
                    466: 
1.1.1.10! root      467: // WR9 レジスタの内容を取得
        !           468: uint8
        !           469: SCCDevice::GetWR9() const
1.1.1.9   root      470: {
1.1.1.10! root      471:        uint8 data = 0;
        !           472: 
        !           473:        data |= mpscc.wr9_cmd << 6;
        !           474:        if (mpscc.status_high_low)     data |= MPSCC::WR9_SHSL;
        !           475:        if (mpscc.master_int_enable)   data |= MPSCC::WR9_MIE;
        !           476:        if (mpscc.disable_lower_chain) data |= MPSCC::WR9_DLC;
        !           477:        if (!mpscc.vectored_mode)      data |= MPSCC::WR9_NV;
        !           478:        if (mpscc.sav_vis)             data |= MPSCC::WR9_VIS;
        !           479: 
        !           480:        return data;
1.1.1.9   root      481: }
                    482: 
1.1.1.10! root      483: // RR0 レジスタの内容を取得
        !           484: uint8
        !           485: SCCDevice::GetRR0(const MPSCCChan& chan) const
1.1.1.9   root      486: {
1.1.1.10! root      487:        uint8 data = 0;
        !           488: 
        !           489:        if (chan.break_detected)data |= MPSCC::RR0_BREAK;
        !           490:        if (chan.tx_underrun)   data |= MPSCC::RR0_TXUNDER;
        !           491:        if (chan.nCTS)                  data |= MPSCC::RR0_nCTS;
        !           492:        if (chan.nSYNC)                 data |= MPSCC::RR0_nSYNC;
        !           493:        if (chan.nDCD)                  data |= MPSCC::RR0_nDCD;
        !           494:        if (chan.txlen == 0)    data |= MPSCC::RR0_TXEMPTY;
        !           495:        if (false)                              data |= MPSCC::RR0_ZEROCNT;     // XXX TODO
        !           496:        if (chan.rxlen != 0)    data |= MPSCC::RR0_RXAVAIL;
        !           497: 
        !           498:        return data;
        !           499: }
        !           500: 
        !           501: // RR3A の内容を取得
        !           502: uint8
        !           503: SCCDevice::GetRR3A() const
        !           504: {
        !           505:        uint8 data = 0;
        !           506: 
        !           507:        if ((mpscc.chan[0].intpend & INTPEND_RX))
        !           508:                data |= MPSCC::RR3_RXA;
        !           509:        if ((mpscc.chan[0].intpend & INTPEND_TX))
        !           510:                data |= MPSCC::RR3_TXA;
        !           511:        if ((mpscc.chan[0].intpend & INTPEND_ES))
        !           512:                data |= MPSCC::RR3_ESA;
        !           513: 
        !           514:        if ((mpscc.chan[1].intpend & INTPEND_RX))
        !           515:                data |= MPSCC::RR3_RXB;
        !           516:        if ((mpscc.chan[1].intpend & INTPEND_TX))
        !           517:                data |= MPSCC::RR3_TXB;
        !           518:        if ((mpscc.chan[1].intpend & INTPEND_ES))
        !           519:                data |= MPSCC::RR3_ESB;
        !           520: 
        !           521:        return data;
        !           522: }
1.1.1.9   root      523: 
1.1.1.10! root      524: // WR0 への書き込み
        !           525: void
        !           526: SCCDevice::WriteWR0(MPSCCChan& chan, uint32 data)
        !           527: {
1.1.1.9   root      528:        // XXX b7,b6 (CRC Reset Command) は未対応。
                    529:        // XXX コマンドが %001、%000 以外の時に PTR(レジスタセレクト) が同時に
                    530:        //     指定されたらどうなるか。
1.1.1.10! root      531:        chan.crc_cmd = (data & MPSCC::CR0_CRC) >> 6;;
        !           532:        chan.cmd     = (data & MPSCC::CR0_CMD) >> 3;
1.1.1.9   root      533: 
1.1.1.10! root      534:        if (chan.crc_cmd != 0) {
        !           535:                // CRC は非同期モードでは不要のはず
        !           536:                putlog(3, "%s CRC リセット未実装 %d", WRName(chan, 0), chan.crc_cmd);
1.1.1.9   root      537:        }
                    538: 
1.1.1.10! root      539:        if (chan.cmd == 0 || chan.cmd == 1) {
1.1.1.9   root      540:                // コマンド 0、1 がレジスタ切り替え
1.1.1.10! root      541:                chan.ptr = data & MPSCC::WR0_PTR;
        !           542:                putlog(3, "%s <- $%02x (ptr=%d)", WRName(chan, 0), data, chan.ptr);
        !           543:        } else {
        !           544:                // それ以外ならコマンド発行
        !           545:                putlog(2, "%s <- $%02x", CRName(chan, 0), data);
        !           546: 
        !           547:                switch (chan.cmd) {
        !           548:                 case 2:        // Reset Ext/Status Interrupts
        !           549:                        ResetESIntr(chan);
        !           550:                        break;
        !           551:                 case 3:        // Send Abort
        !           552:                        SendAbort(chan);
        !           553:                        break;
        !           554:                 case 4:        // Enable Int on Next Rx Character
        !           555:                        EnableIntrOnNextRx(chan);
        !           556:                        break;
        !           557:                 case 5:        // Reset Tx Int Pending
        !           558:                        ResetTxIntrPending(chan);
        !           559:                        break;
        !           560:                 case 6:        // Error Reset
        !           561:                        ErrorReset(chan);
        !           562:                        break;
        !           563:                 case 7:        // Reset Highest IUS
        !           564:                        ResetHighestIUS(chan);
        !           565:                        break;
        !           566:                 default:
        !           567:                        __unreachable();
        !           568:                }
        !           569:        }
        !           570: }
        !           571: 
        !           572: // WR1[AB] への書き込み
        !           573: void
        !           574: SCCDevice::WriteWR1(MPSCCChan& chan, uint32 data)
        !           575: {
        !           576:        putlog(2, "%s <- $%02x", WRName(chan), data);
        !           577: 
        !           578:        chan.wait_enable  = (data & MPSCC::WR1_WAIT_EN);
        !           579:        chan.wait_func    = (data & MPSCC::WR1_WAIT_FUNC);
        !           580:        chan.wait_on_rx   = (data & MPSCC::WR1_WAIT_RX);
        !           581:        // SCC の RXINT は内部フォーマットと同じ値にしてあるのでそのまま代入可。
        !           582:        chan.rxint_mode   = (data >> 3) & 3;
        !           583:        chan.all_or_first = (chan.rxint_mode != 0);
        !           584:        chan.sp_parity    = (data & MPSCC::WR1_SP_INC_PE);
        !           585:        chan.txint_enable = (data & MPSCC::WR1_TXINT_EN);
        !           586:        chan.esint_enable = (data & MPSCC::WR1_ESINT_EN);
        !           587: }
        !           588: 
        !           589: // WR2 への書き込み
        !           590: void
        !           591: SCCDevice::WriteWR2(uint32 data)
        !           592: {
        !           593:        // Z8530 の WR2 は A/B 共通でベクタ設定
        !           594:        putlog(2, "WR2 <- $%02x (Set Vector)", data);
        !           595:        mpscc.vector = data;
        !           596: }
        !           597: 
        !           598: void
        !           599: SCCDevice::WriteWR5(MPSCCChan& chan, uint32 data)
        !           600: {
        !           601:        bool rts = bit_falling(chan.cr5, data, MPSCC::WR5_nRTS);
        !           602: 
        !           603:        inherited::WriteCR5(chan, data);
        !           604: 
        !           605:        if (chan.id == 1 && rts) {
        !           606:                gKeyboard->MouseSendStart();
        !           607:        }
        !           608: }
        !           609: 
        !           610: void
        !           611: SCCDevice::WriteWR9(uint32 data)
        !           612: {
        !           613:        putlog(2, "WR9  <- $%02x", data);
        !           614: 
        !           615:        mpscc.wr9_cmd = (data >> 6);
        !           616:        switch (mpscc.wr9_cmd) {
        !           617:         case 0:        // No Reset
1.1.1.9   root      618:                break;
1.1.1.10! root      619:         case 1:        // Channel Reset B
        !           620:                putlog(1, "Channel B Reset");
        !           621:                ResetChannel(mpscc.chan[1]);
1.1.1.9   root      622:                break;
1.1.1.10! root      623:         case 2:        // Channel Reset A
        !           624:                putlog(1, "Channel A Reset");
        !           625:                ResetChannel(mpscc.chan[0]);
1.1       root      626:                break;
1.1.1.10! root      627:         case 3:        // Force Hardware Reset
        !           628:                ResetHard(false);
1.1.1.9   root      629:                break;
                    630:         default:
                    631:                __unreachable();
1.1       root      632:        }
1.1.1.10! root      633: 
        !           634:        // これらはハードウェアリセットと同時に指定されたら、
        !           635:        // リセット後に処理のはず?
        !           636:        mpscc.status_high_low           = (data & MPSCC::WR9_SHSL);
        !           637:        mpscc.master_int_enable         = (data & MPSCC::WR9_MIE);
        !           638:        mpscc.disable_lower_chain       = (data & MPSCC::WR9_DLC);
        !           639:        mpscc.vectored_mode                     = !(data & MPSCC::WR9_NV);
        !           640:        mpscc.sav_vis                           = (data & MPSCC::WR9_VIS);
        !           641: 
        !           642:        // SHSL と VIS によって vis モードを再設定
        !           643:        if (mpscc.sav_vis) {
        !           644:                if (mpscc.status_high_low) {
        !           645:                        mpscc.vis = MPSCC::VIS_456;
        !           646:                } else {
        !           647:                        mpscc.vis = MPSCC::VIS_321;
        !           648:                }
        !           649:        } else {
        !           650:                mpscc.vis = MPSCC::VIS_FIXED;
        !           651:        }
1.1       root      652: }
                    653: 
1.1.1.8   root      654: void
1.1.1.10! root      655: SCCDevice::WriteWR10(MPSCCChan& chan, uint32 data)
1.1.1.8   root      656: {
1.1.1.10! root      657:        putlog(2, "%s <- $%02x (未実装)", WRName(chan), data);
        !           658:        chan.wr10 = data;
        !           659: }
1.1.1.8   root      660: 
1.1.1.10! root      661: void
        !           662: SCCDevice::WriteWR11(MPSCCChan& chan, uint32 data)
        !           663: {
        !           664:        putlog(2, "%s <- $%02x (未実装)", WRName(chan), data);
        !           665:        chan.wr11 = data;
        !           666: }
1.1.1.8   root      667: 
1.1.1.10! root      668: void
        !           669: SCCDevice::WriteWR12(MPSCCChan& chan, uint32 data)
        !           670: {
        !           671:        chan.tc = (chan.tc & 0xff00) | data;
        !           672:        putlog(2, "%s TC(L)=%04x", WRName(chan), chan.tc);
        !           673:        SetXC(chan);
        !           674: }
        !           675: 
        !           676: void
        !           677: SCCDevice::WriteWR13(MPSCCChan& chan, uint32 data)
        !           678: {
        !           679:        chan.tc = (chan.tc & 0x00ff) | (data << 8);
        !           680:        putlog(2, "%s TC(H)=%04x", WRName(chan), chan.tc);
        !           681:        SetXC(chan);
        !           682: }
        !           683: 
        !           684: void
        !           685: SCCDevice::WriteWR14(MPSCCChan& chan, uint32 data)
        !           686: {
        !           687:        putlog(2, "%s <- $%02x (未実装)", WRName(chan), data);
        !           688:        chan.wr14 = data;
        !           689: }
        !           690: 
        !           691: void
        !           692: SCCDevice::WriteWR15(MPSCCChan& chan, uint32 data)
        !           693: {
        !           694:        putlog(2, "%s <- $%02x (未実装)", WRName(chan), data);
        !           695:        chan.wr15 = data;
        !           696: }
        !           697: 
        !           698: // モニター
        !           699: void
        !           700: SCCDevice::MonitorUpdate(Monitor *, TextScreen& screen)
        !           701: {
        !           702:        uint wr9;
        !           703:        uint rr3a;
        !           704:        int y;
        !           705: 
        !           706:        wr9 = GetWR9();
        !           707:        rr3a = GetRR3A();
        !           708: 
        !           709:        screen.Clear();
        !           710:        for (int i = 0; i < 2; i++) {
        !           711:                int x = 0;
        !           712:                y = i * 16;
        !           713:                MonitorUpdateCh(screen, i, x, y);
        !           714:        }
        !           715: 
        !           716:        y = 32;
        !           717:        // WR9
        !           718:        screen.Print(0, y, "WR9 :$%02x", wr9);
        !           719:        static const char * const wr9_str[] = {
        !           720:                "", "", "-", "SHSL", "MIE", "DLC", "NV", "VIS"
        !           721:        };
        !           722:        MonitorReg(screen, 9, y, wr9, wr9_str);
        !           723:        static const char * const resetcmd_str[] = {
        !           724:        //   012345678
        !           725:                "(NoReset)",
        !           726:                "(RstChB)",
        !           727:                "(RstChA)",
        !           728:                "(HardRst)",
        !           729:        };
        !           730:        screen.Puts(9, y, resetcmd_str[wr9 >> 6]);
        !           731:        y++;
        !           732: 
        !           733:        // RR2B / RR2B
        !           734:        screen.Print(0, y, "RR2A:$%02x / RR2B:$%02x", mpscc.vector, GetSR2B());
        !           735:        y++;
        !           736: 
        !           737:        // RR3A
        !           738:        static const char * const rr3a_str[] = {
        !           739:                "-", "-", "RxA", "TxA", "ESA", "RxB", "TxB", "ESB"
        !           740:        };
        !           741:        screen.Print(0, y, "RR3A:$%02x", rr3a);
        !           742:        MonitorReg(screen, 9, y, rr3a, rr3a_str);
        !           743:        y++;
        !           744: }
        !           745: 
        !           746: // モニター (1チャンネル)
        !           747: void
        !           748: SCCDevice::MonitorUpdateCh(TextScreen& screen, int ch, int xbase, int ybase)
        !           749: {
        !           750:        const MPSCCChan& chan = mpscc.chan[ch];
        !           751:        uint crc;
        !           752:        uint cmd;
        !           753:        uint ptr;
        !           754:        uint wr0;
        !           755:        uint wr1;
        !           756:        uint wr3;
        !           757:        uint wr4;
        !           758:        uint wr5;
        !           759:        uint wr10;
        !           760:        uint wr11;
        !           761:        uint wr14;
        !           762:        uint wr15;
        !           763:        uint rr0;
        !           764:        uint rr1;
        !           765:        uint rr10;
        !           766:        uint rxlen;
        !           767:        uint tc;
        !           768:        int x;
        !           769:        int y;
        !           770: 
        !           771:        wr0 = GetCR0(chan);
        !           772:        crc = chan.crc_cmd;
        !           773:        cmd = chan.cmd;
        !           774:        ptr = chan.ptr;
        !           775:        wr1 = GetWR1(chan);
        !           776:        wr3 = GetCR3(chan);
        !           777:        wr4 = chan.cr4;
        !           778:        wr5 = GetCR5(chan);
        !           779:        wr10 = chan.wr10;
        !           780:        wr11 = chan.wr11;
        !           781:        tc   = chan.tc;
        !           782:        wr14 = chan.wr14;
        !           783:        wr15 = chan.wr15;
        !           784:        rr0 = GetRR0(chan);
        !           785:        rr1 = chan.sr1;
        !           786:        rr10 = chan.rr10;
        !           787:        rxlen = chan.rxlen;
        !           788: 
        !           789:        // 0         1         2         3         4         5         6
        !           790:        // 0123456789012345678901234567890123456789012345678901234567890123456789
        !           791:        //          0123 0123 0123 0123 0123 0123 0123 0123
        !           792:        // Channel A: Serial Console                          DataAddr    $000000
        !           793:        // WR0: $xx CRC=x     CMD=x          PTR=x            CtrlAddr    $000000
        !           794:        // WR1: $xx WE   0    WR   RXInt=x   0    TXEn ESEn
        !           795: 
        !           796:        x = xbase;
        !           797:        y = ybase;
        !           798:        screen.Print(x, y++, "Channel %c: %s", chan.name, chan.desc);
        !           799:        screen.Print(x, y++, "WR0: $%02x", wr0);
        !           800:        screen.Print(x, y++, "WR1: $%02x", wr1);
        !           801:        screen.Print(x, y++, "WR3: $%02x", wr3);
        !           802:        screen.Print(x, y++, "WR4: $%02x", wr4);
        !           803:        screen.Print(x, y++, "WR5: $%02x", wr5);
        !           804:        screen.Print(x, y++, "WR10:$%02x", wr10);
        !           805:        screen.Print(x, y++, "WR11:$%02x", wr11);
        !           806:        screen.Print(x, y++, "WR14:$%02x", wr14);
        !           807:        screen.Print(x, y++, "WR15:$%02x", wr15);
        !           808:        screen.Print(x, y++, "WR12/WR13:$%04x", tc);
        !           809:        screen.Print(x, y++, "RR0: $%02x", rr0);
        !           810:        screen.Print(x, y++, "RR1: $%02x", rr1);
        !           811:        screen.Print(x, y++, "RR10:$%02x", rr10);
        !           812:        screen.Print(x, y,   "RXbuf: %d", rxlen);
        !           813:        int i;
        !           814:        for (i = 0; i < rxlen; i++) {
        !           815:                screen.Print(x + 9 + i * 4, y, "$%02x", chan.rxbuf[i]);
1.1.1.8   root      816:        }
1.1.1.10! root      817:        for (; i < sizeof(chan.rxbuf); i++) {
        !           818:                screen.Print(x + 9 + i * 4, y, "---");
        !           819:        }
        !           820: 
        !           821:        y = ybase + 1;
        !           822:        x = xbase;
        !           823:        // WR0
        !           824:        screen.Print(x + 9, y, "CRC=%d", crc);
        !           825:        static const char * const cmd_str[] = {
        !           826:        //   012345678901234
        !           827:                "Null command",
        !           828:                "Point High",
        !           829:                "Reset E/S Int",
        !           830:                "Send Abort",
        !           831:                "EnableIntNextCh",
        !           832:                "Reset TxIntPend",
        !           833:                "Error Reset",
        !           834:                "ResetHighestIUS",
        !           835:        };
        !           836:        screen.Print(x + 19, y, "CMD=%d(%s)", cmd, cmd_str[cmd]);
        !           837:        screen.Print(x + 43 - (ptr > 9 ? 1 : 0), y, "PTR=%d", ptr);
        !           838:        y++;
        !           839: 
        !           840:        // WR1
        !           841:        static const char * const wr1_str[] = {
        !           842:                "Wait", "Func", "OnRx", "", "", "SpPE", "TxIE", "ESIE"
        !           843:        };
        !           844:        MonitorReg(screen, x + 9, y, wr1, wr1_str);
        !           845:        static const char * const rxint_str[] = {
        !           846:        //   012345678
        !           847:                "RxInt=Dis",
        !           848:                "RI=1stChr",
        !           849:                "RI=AllChr",
        !           850:                "RI=SPOnly",
        !           851:        };
        !           852:        screen.Puts(x + 24, y, rxint_str[(wr1 >> 3) & 3]);
        !           853:        y++;
        !           854: 
        !           855:        // WR3,WR4,WR5
        !           856:        y = MonitorUpdateCR345(screen, x, y, wr3, wr4, wr5);
        !           857: 
        !           858:        // WR10
        !           859:        screen.Puts(x +  9, y, TA::Disable, (wr10 & 0x80) ? "CRC1" : "CRC0");
        !           860:        static const char * const de_str[] = {
        !           861:        //       012345678
        !           862:                "Enc=NRZ",
        !           863:                "Enc=NRZI",
        !           864:                "Enc=FM(1)",
        !           865:                "Enc=FM(0)",
        !           866:        };
        !           867:        screen.Puts(x + 14, y, de_str[(wr10 >> 5) & 3]);
        !           868:        screen.Puts(x + 24, y, TA::Disable, (wr10 & 0x10) ? "1" : "0");
        !           869:        screen.Puts(x + 29, y, TA::Disable, (wr10 & 0x08) ? "1" : "0");
        !           870:        screen.Puts(x + 34, y, TA::Disable, (wr10 & 0x04) ? "1" : "0");
        !           871:        screen.Puts(x + 39, y, TA::Disable, (wr10 & 0x02) ? "1" : "0");
        !           872:        screen.Puts(x + 44, y, TA::Disable, (wr10 & 0x01) ? "1" : "0");
        !           873:        y++;
        !           874: 
        !           875:        // WR11
        !           876:        screen.Puts(x + 9, y, TA::OnOff(wr11 & 0x80), "XTAL");
        !           877:        static const char * const clksrc_str[] = {
        !           878:        //       45678
        !           879:                "!RTxC",
        !           880:                "!TRxC",
        !           881:                "BRG",
        !           882:                "DPLL",
        !           883:        };
        !           884:        screen.Print(x + 14, y, "RxC=%s", clksrc_str[(wr11 >> 5) & 3]);
        !           885:        screen.Print(x + 24, y, "TxC=%s", clksrc_str[(wr11 >> 3) & 3]);
        !           886:        screen.Puts(x + 34, y, TA::OnOff(wr11 & 0x04), "TOUT");
        !           887:        static const char * const clkout_str[] = {
        !           888:        //       012345678
        !           889:                "TRxC=DPLL",
        !           890:                "TRxC=BRG",
        !           891:                "TRxC=Clk",
        !           892:                "TRxC=Xtal",
        !           893:        };
        !           894:        screen.Puts(x + 39, y, clkout_str[(wr11 & 3)]);
        !           895:        y++;
        !           896: 
        !           897:        // WR14
        !           898:        static const char * const wr14_str[] = {
        !           899:                "", "", "", "LLB", "Echo", "DTRL", "BRGS", "BRGE",
        !           900:        };
        !           901:        MonitorReg(screen, x + 9, y, wr14, wr14_str);
        !           902:        static const char * const dpllcmd_str[] = {
        !           903:        //       01234567890123
        !           904:                "(DPLL nullcmd)",
        !           905:                "(EntSearchMod)",
        !           906:                "(ResetMissClk)",
        !           907:                "(Disable DPLL)",
        !           908:                "(Set SRC=BRG)",
        !           909:                "(Set SRC=RTxC)",
        !           910:                "(Set FM Mode)",
        !           911:                "(Set NRZIMode)",
        !           912:        };
        !           913:        screen.Puts(x + 9, y, dpllcmd_str[(wr14 >> 5)]);
        !           914:        y++;
        !           915: 
        !           916:        // WR15
        !           917:        static const char * const wr15_str[] = {
        !           918:                "BrIE", "TUIE", "CTIE", "SHIE", "DCIE", "-", "ZCIE", "-"
        !           919:        };
        !           920:        MonitorReg(screen, x + 9, y, wr15, wr15_str);
        !           921:        y++;
        !           922: 
        !           923:        // WR12/WR13
        !           924:        y++;
        !           925: 
        !           926:        // RR0
        !           927:        static const char * const rr0_str[] = {
        !           928:                "BrAb", "TxUn", "!CTS", "!SYN", "!DCD", "TxEm", "ZCnt", "RxAv"
        !           929:        };
        !           930:        MonitorReg(screen, x + 9, y, rr0, rr0_str);
        !           931:        y++;
        !           932: 
        !           933:        // RR1
        !           934:        MonitorUpdateSR1(screen, x, y, rr1);
        !           935:        y++;
        !           936: 
        !           937:        // RR10
        !           938:        static const char * const rr10_str[] = {
        !           939:                "1CM", "2CM", "-", "", "-", "-", "", "-"
        !           940:        };
        !           941:        MonitorReg(screen, x + 9, y, rr10, rr10_str);
        !           942:        screen.Puts(x + 24, y, TA::Disable, (rr10 & 0x10) ? "1" : "0");
        !           943:        screen.Puts(x + 39, y, TA::Disable, (rr10 & 0x02) ? "1" : "0");
        !           944:        y++;
        !           945: 
        !           946:        // 右列
        !           947:        y = ybase;
        !           948:        x = xbase + 51;
        !           949:        screen.Print(x, y++, "DataAddr    $%06x", chan.dataaddr);
        !           950:        screen.Print(x, y++, "CtrlAddr    $%06x", chan.ctrladdr);
        !           951:        y++;
        !           952:        screen.Print(x, y++, "Param  %12s", GetParamStr(chan).c_str());
        !           953:        screen.Print(x, y++, "Rx Bits/Frame    %2d", chan.rxbits);
        !           954:        screen.Print(x, y++, "Tx Bits/Frame    %2d", chan.txbits);
1.1.1.8   root      955: }
                    956: 
1.1.1.10! root      957: // 内部の送信データクロックの設定
1.1       root      958: void
1.1.1.10! root      959: SCCDevice::SetXC(MPSCCChan& chan)
1.1       root      960: {
1.1.1.10! root      961:        // 5MHz = 200nsec
        !           962:        // 12bit = 2.4usec
        !           963:        xc12_ns = (2 * (chan.tc + 2)) * 2.4_usec;
1.1.1.5   root      964: }
                    965: 
                    966: // 割り込みアクノリッジ
                    967: int
                    968: SCCDevice::InterruptAcknowledge()
                    969: {
1.1.1.10! root      970:        return GetSR2B();
        !           971: }
        !           972: 
        !           973: // ペンディングのうち最も優先度の高い割り込み要因を返す
        !           974: uint
        !           975: SCCDevice::GetHighestInt() const
        !           976: {
        !           977:        // 上から RxA, TxA, ESA, RxB, TxB, ESB の順 (Z8530 p.2-16)。
        !           978: 
        !           979:        if ((mpscc.chan[0].intpend & INTPEND_SP)) return MPSCC::VS_SPA;
        !           980:        if ((mpscc.chan[0].intpend & INTPEND_RX)) return MPSCC::VS_RxA;
        !           981:        if ((mpscc.chan[0].intpend & INTPEND_TX)) return MPSCC::VS_TxA;
        !           982:        if ((mpscc.chan[0].intpend & INTPEND_ES)) return MPSCC::VS_ESA;
        !           983:        if ((mpscc.chan[1].intpend & INTPEND_SP)) return MPSCC::VS_SPB;
        !           984:        if ((mpscc.chan[1].intpend & INTPEND_RX)) return MPSCC::VS_RxB;
        !           985:        if ((mpscc.chan[1].intpend & INTPEND_TX)) return MPSCC::VS_TxB;
        !           986:        if ((mpscc.chan[1].intpend & INTPEND_ES)) return MPSCC::VS_ESB;
        !           987: 
        !           988:        return MPSCC::VS_none;
1.1       root      989: }
1.1.1.9   root      990: 
                    991: void
                    992: SCCDevice::Tx(int ch, uint32 data)
                    993: {
1.1.1.10! root      994:        switch (ch) {
        !           995:         case 0:
        !           996:                hostcom->Tx(data);
        !           997:                break;
        !           998:         case 1:
        !           999:                // ChB はマウスだが TxD は接続されていない
        !          1000:                break;
        !          1001:         default:
        !          1002:                __unreachable();
        !          1003:        }
1.1.1.9   root     1004: }
                   1005: 
                   1006: // ログ表示用のレジスタ名
                   1007: /*static*/ const char * const
                   1008: SCCDevice::wrnames[32] = {
                   1009:        "WR0A",         "WR0B",
                   1010:        "WR1A",         "WR1B",
1.1.1.10! root     1011:        "WR2",          "WR2",
1.1.1.9   root     1012:        "WR3A",         "WR3B",
                   1013:        "WR4A",         "WR4B",
                   1014:        "WR5A",         "WR5B",
                   1015:        "WR6A",         "WR6B",
                   1016:        "WR7A",         "WR7B",
                   1017:        "WR8A",         "WR8B",
1.1.1.10! root     1018:        "WR9",          "WR9",
1.1.1.9   root     1019:        "WR10A",        "WR10B",
                   1020:        "WR11A",        "WR11B",
                   1021:        "WR12A",        "WR12B",
                   1022:        "WR13A",        "WR13B",
                   1023:        "WR14A",        "WR14B",
                   1024:        "WR15A",        "WR15B",
                   1025: };
                   1026: /*static*/ const char * const
                   1027: SCCDevice::rrnames[32] = {
                   1028:        "RR0A",         "RR0B",
                   1029:        "RR1A",         "RR1B",
                   1030:        "RR2A",         "RR2B",
                   1031:        "RR3A",         "RR3B",
1.1.1.10! root     1032:        "(RR0A)",       "(RR0B)",
        !          1033:        "(RR1A)",       "(RR1B)",
        !          1034:        "(RR2A)",       "(RR2B)",
        !          1035:        "(RR3A)",       "(RR3B)",
1.1.1.9   root     1036:        "RR8A",         "RR8B",
1.1.1.10! root     1037:        "(RR13A)",      "(RR13B)",
1.1.1.9   root     1038:        "RR10A",        "RR10B",
1.1.1.10! root     1039:        "(RR15A)",      "(RR15B)",
1.1.1.9   root     1040:        "RR12A",        "RR12B",
                   1041:        "RR13A",        "RR13B",
1.1.1.10! root     1042:        "RR14A",        "RR14B",
1.1.1.9   root     1043:        "RR15A",        "RR15B",
                   1044: };

unix.superglobalmegacorp.com

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