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

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: 
                      7: #include "scc.h"
1.1.1.8   root        8: #include "bitops.h"
1.1.1.5   root        9: #include "interrupt.h"
1.1.1.8   root       10: #include "keyboard.h"
1.1.1.5   root       11: #include "mpu.h"
1.1       root       12: 
                     13: //          IODevice
                     14: //              |
                     15: //              v
                     16: //        upd7201Device  (uPD7201 と Z8530 の共通部分)
                     17: //              |
                     18: //    +---------+----------+
                     19: //    v                    v
                     20: // SIODevice           SCCDevice
                     21: // (LUNA, uPD7201)     (X68030, Z8530)
                     22: 
1.1.1.2   root       23: std::unique_ptr<SCCDevice> gSCC;
                     24: 
1.1       root       25: SCCDevice::SCCDevice()
1.1.1.7   root       26:        : inherited("SCC")
1.1       root       27: {
                     28:        devaddr = baseaddr;
                     29:        devlen  = 0x2000;
1.1.1.2   root       30: 
                     31:        cr.chan[0].desc = "Serial Port";
                     32:        cr.chan[1].desc = "Mouse";
1.1.1.7   root       33: 
                     34:        // X680x0 では SCC と呼ぶほうが通りがいい。
1.1.1.9 ! root       35:        for (int ch = 0; ch < txevent.size(); ch++) {
        !            36:                txevent[ch].SetName(string_format("SCC Ch%s TX", cr.chan[ch].name));
        !            37:        }
1.1.1.7   root       38:        monitor.Regist(ID_MONITOR_SCC);
1.1       root       39: }
                     40: 
                     41: SCCDevice::~SCCDevice()
                     42: {
                     43: }
                     44: 
                     45: // Z8530 は RD と WR を同時に Low にするとリセットがかかる。
                     46: // 回路図からは PEDEC から繋がってるという以上のことは分からないけど
                     47: // 普通に考えればハードリセットでリセットされるよな。
                     48: 
                     49: uint64
1.1.1.6   root       50: SCCDevice::Read(uint32 offset)
1.1       root       51: {
1.1.1.4   root       52:        gMPU->AddCycle(41);     // InsideOut p.135
                     53: 
1.1.1.6   root       54:        switch (offset) {
1.1.1.3   root       55:         case 0:        // $E98001
1.1       root       56:                return ReadCtrl(&cr.chan[1]);
                     57: 
1.1.1.3   root       58:         case 1:        // $E98003
1.1.1.8   root       59:                return ReadData(&cr.chan[1]);
1.1       root       60: 
1.1.1.3   root       61:         case 2:        // $E98005
1.1       root       62:                return ReadCtrl(&cr.chan[0]);
                     63: 
1.1.1.3   root       64:         case 3:        // $E98007
1.1       root       65:                putlog(0, "ChA データレジスタ読み込み (未実装)");
1.1.1.2   root       66:                return ReadData(&cr.chan[0]);
1.1       root       67:        }
1.1.1.3   root       68:        __unreachable();
1.1       root       69: }
                     70: 
                     71: uint64
1.1.1.6   root       72: SCCDevice::Write(uint32 offset, uint32 data)
1.1       root       73: {
1.1.1.4   root       74:        gMPU->AddCycle(49);     // InsideOut p.135
                     75: 
1.1.1.6   root       76:        switch (offset) {
1.1.1.3   root       77:         case 0:        // $E98001
1.1       root       78:                WriteCtrl(&cr.chan[1], data);
                     79:                return 0;
                     80: 
1.1.1.3   root       81:         case 1:        // $E98003
1.1       root       82:                WriteData(&cr.chan[1], data);
                     83:                return 0;
                     84: 
1.1.1.3   root       85:         case 2:        // $E98005
1.1       root       86:                WriteCtrl(&cr.chan[0], data);
                     87:                return 0;
                     88: 
1.1.1.3   root       89:         case 3:        // $E98007
1.1       root       90:                WriteData(&cr.chan[0], data);
                     91:                return 0;
                     92:        }
1.1.1.3   root       93:        __unreachable();
1.1       root       94: }
                     95: 
                     96: uint64
1.1.1.6   root       97: SCCDevice::Peek(uint32 offset)
1.1       root       98: {
1.1.1.6   root       99:        switch (offset) {
1.1.1.3   root      100:         case 0:        // $E98001
1.1.1.2   root      101:                return PeekCtrl(&cr.chan[1]);
                    102: 
1.1.1.3   root      103:         case 1:        // $E98003
1.1.1.8   root      104:                return PeekData(&cr.chan[1]);
1.1.1.2   root      105: 
1.1.1.3   root      106:         case 2:        // $E98005
1.1.1.2   root      107:                return PeekCtrl(&cr.chan[0]);
                    108: 
1.1.1.3   root      109:         case 3:        // $E98007
1.1.1.2   root      110:                return PeekData(&cr.chan[0]);
                    111:        }
1.1.1.3   root      112:        __unreachable();
1.1       root      113: }
                    114: 
1.1.1.9 ! root      115: // CR(WR) レジスタ名を返す。Z8530 では WRn のほうが通りがいい。
        !           116: const char *
        !           117: SCCDevice::CRName(const SIO::channel *chan, int ptr_) const
        !           118: {
        !           119:        assert(ptr_ < 16);
        !           120:        int idx = ptr_ * 2 + chan->id;
        !           121:        assert(idx < countof(wrnames));
        !           122:        return wrnames[idx];
        !           123: }
        !           124: 
        !           125: // SR(RR) レジスタ名を返す。Z8530 では RRn のほうが通りがいい。
        !           126: const char *
        !           127: SCCDevice::SRName(const SIO::channel *chan, int ptr_) const
        !           128: {
        !           129:        assert(ptr_ < 16);
        !           130:        int idx = ptr_ * 2 + chan->id;
        !           131:        assert(idx < countof(rrnames));
        !           132:        return rrnames[idx];
        !           133: }
        !           134: 
1.1       root      135: // Z8530 制御ポート読み込み
                    136: uint8
1.1.1.9 ! root      137: SCCDevice::ReadCtrl(SIO::channel *chan)
1.1       root      138: {
                    139:        return inherited::ReadCtrl(chan);
                    140: }
                    141: 
                    142: // Z8530 制御ポート書き込み
                    143: void
1.1.1.9 ! root      144: SCCDevice::WriteCtrl(SIO::channel *chan, uint32 data)
1.1       root      145: {
                    146:        switch (chan->ptr) {
                    147:         case 0:        // WR0
1.1.1.9 ! root      148:                WriteCR0(chan, data);
1.1       root      149:                break;
                    150: 
                    151:         case 2:        // WR2
                    152:                // Z8530 の WR2 は A/B 共通でベクタ設定
                    153:                putlog(2, "WR2 <- $%02x ベクタ設定", data);
                    154:                cr.vector = data;
                    155:                // アクセス後は WR0 へ戻す
                    156:                chan->ptr = 0;
                    157:                break;
                    158: 
                    159:         case 1:        // WR1
                    160:         case 3:
                    161:         case 4:
                    162:         case 5:
                    163:         case 6:
                    164:         case 7:
                    165:                inherited::WriteCtrl(chan, data);
                    166:                break;
                    167: 
                    168:         case 8:        // WR8
                    169:                WriteData(chan, data);
                    170:                // アクセス後は WR0 へ戻す
                    171:                chan->ptr = 0;
                    172:                break;
                    173: 
                    174:         case 9:        // WR9
1.1.1.9 ! root      175:                putlog(2, "%s <- $%02x", WRName(chan), data);
1.1       root      176:                switch ((data & 0xc0) >> 6) {
                    177:                 case 0:        // No Reset
                    178:                        break;
                    179:                 case 1:        // Channel Reset A
                    180:                        ResetChannel(&cr.chan[0]);
                    181:                        break;
                    182:                 case 2:        // Channel Reset B
                    183:                        ResetChannel(&cr.chan[1]);
                    184:                        break;
                    185:                 case 3:        // Force Hardware Reset
1.1.1.6   root      186:                        ResetHard();
1.1       root      187:                        break;
                    188:                 default:
                    189:                        __unreachable();
                    190:                }
                    191:                // アクセス後は WR0 へ戻す
                    192:                chan->ptr = 0;
                    193:                break;
                    194: 
1.1.1.5   root      195:         case 10:       // WR10
1.1.1.9 ! root      196:                putlog(2, "%s <- $%02x (未実装)", WRName(chan), data);
1.1.1.5   root      197:                chan->wr10 = data;
                    198:                // アクセス後は WR0 へ戻す
                    199:                chan->ptr = 0;
                    200:                break;
                    201: 
1.1       root      202:         case 11:       // WR11
1.1.1.9 ! root      203:                putlog(2, "%s <- $%02x (未実装)", WRName(chan), data);
1.1       root      204:                chan->wr11 = data;
                    205:                // アクセス後は WR0 へ戻す
                    206:                chan->ptr = 0;
                    207:                break;
                    208: 
                    209:         case 12:       // WR12
                    210:                chan->tc = (chan->tc & 0xff00) | data;
1.1.1.9 ! root      211:                putlog(2, "%s TC(L)=%04x", WRName(chan), chan->tc);
        !           212:                SetTXC(chan);
1.1       root      213:                // アクセス後は WR0 へ戻す
                    214:                chan->ptr = 0;
                    215:                break;
                    216: 
                    217:         case 13:       // WR13
                    218:                chan->tc = (chan->tc & 0x00ff) | (data << 8);
1.1.1.9 ! root      219:                putlog(2, "%s TC(H)=%04x", WRName(chan), chan->tc);
        !           220:                SetTXC(chan);
1.1       root      221:                // アクセス後は WR0 へ戻す
                    222:                chan->ptr = 0;
                    223:                break;
                    224: 
                    225:         case 14:       // WR14
1.1.1.9 ! root      226:                putlog(2, "%s <- $%02x (未実装)", WRName(chan), data);
1.1       root      227:                chan->wr14 = data;
                    228:                // アクセス後は WR0 へ戻す
                    229:                chan->ptr = 0;
                    230:                break;
                    231: 
                    232:         case 15:       // WR15
1.1.1.9 ! root      233:                putlog(2, "%s <- $%02x (未実装)", WRName(chan), data);
1.1       root      234:                chan->wr15 = data;
                    235:                // アクセス後は WR0 へ戻す
                    236:                chan->ptr = 0;
                    237:                break;
                    238: 
                    239:         default:
1.1.1.9 ! root      240:                PANIC("未実装レジスタ書き込み %s <- $%02x", WRName(chan), data);
        !           241:                break;
        !           242:        }
        !           243: }
        !           244: 
        !           245: // 内部の送信データクロックの設定
        !           246: void
        !           247: SCCDevice::SetTXC(SIO::channel *chan)
        !           248: {
        !           249:        // 5MHz = 200nsec
        !           250:        // 12bit = 2.4usec
        !           251:        txc12_ns = (2 * (chan->tc + 2)) * 2.4_usec;
        !           252: }
        !           253: 
        !           254: // CR0(WR0) 書き込み。
        !           255: // uPD7201 の CR0 とは微妙に互換性がないので似てるけど違うので注意。
        !           256: void
        !           257: SCCDevice::WriteCR0(SIO::channel *chan, uint32 data)
        !           258: {
        !           259:        uint cmd;
        !           260: 
        !           261:        // XXX b7,b6 (CRC Reset Command) は未対応。
        !           262:        // XXX コマンドが %001、%000 以外の時に PTR(レジスタセレクト) が同時に
        !           263:        //     指定されたらどうなるか。
        !           264:        chan->cr0 = data;
        !           265: 
        !           266:        if ((chan->cr0 & SIO::WR0_CRC)) {
        !           267:                putlog(0, "%s CRC リセット未実装", WRName(chan, 0));
        !           268:        }
        !           269: 
        !           270:        cmd = (chan->cr0 & SIO::WR0_CMD) >> 3;
        !           271:        switch (cmd) {
        !           272:         case 0:
        !           273:         case 1:
        !           274:                // コマンド 0、1 がレジスタ切り替え
        !           275:                chan->ptr = chan->cr0 & SIO::WR0_PTR;
        !           276:                putlog(3, "%s <- $%02x (ptr=%d)", WRName(chan, 0), data, chan->ptr);
        !           277:                break;
        !           278:         case 2:        // Reset Ext/Status Interrupts
        !           279:                ResetESIntr(chan);
        !           280:                break;
        !           281:         case 3:        // Send Abort
        !           282:                SendAbort(chan);
        !           283:                break;
        !           284:         case 4:        // Enable Int on Next Rx Character
        !           285:                EnableIntrOnNextRx(chan);
        !           286:                break;
        !           287:         case 5:        // Reset Tx Int Pending
        !           288:                ResetTxIntrPending(chan);
        !           289:                break;
        !           290:         case 6:        // Error Reset
        !           291:                ErrorReset(chan);
1.1       root      292:                break;
1.1.1.9 ! root      293:         case 7:        // Reset Highest IUS
        !           294:                ResetHighestIUS(chan);
        !           295:                break;
        !           296:         default:
        !           297:                __unreachable();
1.1       root      298:        }
                    299: }
                    300: 
1.1.1.8   root      301: void
1.1.1.9 ! root      302: SCCDevice::WriteCR5(SIO::channel *chan, uint32 data)
1.1.1.8   root      303: {
                    304:        bool rts = bit_falling(chan->cr5, data, SIO::CR5_RTS);
                    305: 
                    306:        inherited::WriteCR5(chan, data);
                    307: 
                    308:        if (chan->id == 1 && rts) {
                    309:                gKeyboard->MouseSendStart();
                    310:        }
                    311: }
                    312: 
1.1       root      313: // 割り込みを上げる
                    314: void
                    315: SCCDevice::Interrupt()
                    316: {
                    317:        putlog(0, "割り込み(未実装)");
1.1.1.5   root      318: //     gInterrupt->Raise(this);
                    319: }
                    320: 
                    321: // 割り込みアクノリッジ
                    322: int
                    323: SCCDevice::InterruptAcknowledge()
                    324: {
                    325:        return 0x50;    /* XXX 実際は WR2 とか要因で変わる */
1.1       root      326: }
1.1.1.9 ! root      327: 
        !           328: void
        !           329: SCCDevice::Tx(int ch, uint32 data)
        !           330: {
        !           331:        // TODO: シリアル送信
        !           332:        // ChA はシリアルポート
        !           333:        // ChB はマウスだが TxD は接続されていない
        !           334: }
        !           335: 
        !           336: // ログ表示用のレジスタ名
        !           337: /*static*/ const char * const
        !           338: SCCDevice::wrnames[32] = {
        !           339:        "WR0A",         "WR0B",
        !           340:        "WR1A",         "WR1B",
        !           341:        "WR2A",         "WR2B",
        !           342:        "WR3A",         "WR3B",
        !           343:        "WR4A",         "WR4B",
        !           344:        "WR5A",         "WR5B",
        !           345:        "WR6A",         "WR6B",
        !           346:        "WR7A",         "WR7B",
        !           347:        "WR8A",         "WR8B",
        !           348:        "WR9A",         "WR9B",
        !           349:        "WR10A",        "WR10B",
        !           350:        "WR11A",        "WR11B",
        !           351:        "WR12A",        "WR12B",
        !           352:        "WR13A",        "WR13B",
        !           353:        "WR14A",        "WR14B",
        !           354:        "WR15A",        "WR15B",
        !           355: };
        !           356: /*static*/ const char * const
        !           357: SCCDevice::rrnames[32] = {
        !           358:        "RR0A",         "RR0B",
        !           359:        "RR1A",         "RR1B",
        !           360:        "RR2A",         "RR2B",
        !           361:        "RR3A",         "RR3B",
        !           362:        "RR4A?",        "RR4A?",
        !           363:        "RR5A?",        "RR5A?",
        !           364:        "RR6A?",        "RR6A?",
        !           365:        "RR7A?",        "RR7A?",
        !           366:        "RR8A",         "RR8B",
        !           367:        "RR9A?",        "RR9A?",
        !           368:        "RR10A",        "RR10B",
        !           369:        "RR11A?",       "RR11A?",
        !           370:        "RR12A",        "RR12B",
        !           371:        "RR13A",        "RR13B",
        !           372:        "RR14A?",       "RR14A?",
        !           373:        "RR15A",        "RR15B",
        !           374: };

unix.superglobalmegacorp.com

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