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

1.1       root        1: //
                      2: // nono
1.1.1.4   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.9 ! root        7: //
        !             8: // FDC (uPD72065B)
        !             9: //
        !            10: 
1.1       root       11: #include "fdc.h"
1.1.1.9 ! root       12: #include "mpu.h"
1.1.1.6   root       13: #include "pedec.h"
1.1       root       14: #include "scheduler.h"
                     15: 
1.1.1.9 ! root       16: // グローバル参照用
        !            17: FDCDevice *gFDC;
1.1.1.6   root       18: 
1.1       root       19: // コンストラクタ
                     20: FDCDevice::FDCDevice()
1.1.1.8   root       21:        : inherited("FDC")
1.1       root       22: {
                     23:        devaddr = baseaddr;
                     24:        devlen  = 0x2000;
                     25: 
1.1.1.9 ! root       26:        event.func = ToEventCallback(&FDCDevice::Callback);
        !            27:        event.Regist("FDC");
        !            28: 
        !            29:        // XXX ハック。ちゃんと作ること
        !            30:        fdd[0].ready = true;
        !            31:        fdd[1].ready = true;
        !            32:        fdd[2].ready = false;
        !            33:        fdd[3].ready = false;
1.1       root       34: }
                     35: 
                     36: // デストラクタ
                     37: FDCDevice::~FDCDevice()
                     38: {
1.1.1.9 ! root       39:        gFDC = NULL;
1.1       root       40: }
                     41: 
1.1.1.9 ! root       42: // リセット
1.1       root       43: void
1.1.1.9 ! root       44: FDCDevice::ResetHard(bool poweron)
1.1       root       45: {
                     46:        // XXX 他には
1.1.1.9 ! root       47:        gScheduler->StopEvent(event);
1.1       root       48:        idle_phase();
                     49: }
                     50: 
                     51: uint64
1.1.1.7   root       52: FDCDevice::Read(uint32 offset)
1.1       root       53: {
1.1.1.5   root       54:        gMPU->AddCycle(19);     // InsideOut p.135
                     55: 
1.1.1.7   root       56:        switch (offset) {
1.1.1.4   root       57:         case 0:
1.1       root       58:                return ReadStatus();
1.1.1.4   root       59:         case 1:
1.1       root       60:                return ReadData();
1.1.1.4   root       61:         case 2:
1.1       root       62:                return ReadDriveStatus();
1.1.1.4   root       63:         case 3:
                     64:                return 0xff;
1.1       root       65:        }
1.1.1.4   root       66:        __unreachable();
1.1       root       67: }
                     68: 
                     69: uint64
1.1.1.7   root       70: FDCDevice::Write(uint32 offset, uint32 data)
1.1       root       71: {
1.1.1.5   root       72:        gMPU->AddCycle(19);     // InsideOut p.135
                     73: 
1.1.1.7   root       74:        switch (offset) {
1.1.1.4   root       75:         case 0:
1.1.1.9 ! root       76:                putlog(0, "未実装コマンドレジスタ書き込み $%02x", data);
1.1.1.4   root       77:                return 0;
1.1       root       78: 
1.1.1.4   root       79:         case 1:
1.1       root       80:                WriteCmd(data);
                     81:                return 0;
1.1.1.4   root       82: 
                     83:         case 2:
1.1       root       84:                if ((data & 0x0f) != 0) {
                     85:                        fdc.drivesel = data & 0x0f;
                     86:                        putlog(1, "ドライブ選択%s%s%s%s",
                     87:                                (fdc.drivesel & 1) ? " #0" : "",
                     88:                                (fdc.drivesel & 2) ? " #1" : "",
                     89:                                (fdc.drivesel & 4) ? " #2" : "",
                     90:                                (fdc.drivesel & 8) ? " #3" : "");
                     91:                }
                     92:                if ((data & 0xe0) != 0) {
1.1.1.7   root       93:                        putlog(0, "未実装ビット書き込み $%06x <- $%02x",
                     94:                                gMPU->GetPaddr(), data);
1.1       root       95:                }
                     96:                return 0;
                     97: 
1.1.1.4   root       98:         case 3:
1.1       root       99:                fdc.is2DD = ((data & 0x10) != 0);
                    100:                fdc.accdrive = data & 3;
                    101:                putlog(1, "アクセスドライブ %s #%d",
                    102:                        fdc.is2DD ? "2DD" : "2HD",
                    103:                        fdc.accdrive);
                    104:                fdd[fdc.accdrive].motor = (data & 0x80);
                    105:                if (fdd[fdc.accdrive].motor) {
                    106:                        putlog(1, "ドライブ #%d モーターオン", fdc.accdrive);
                    107:                } else {
                    108:                        putlog(1, "ドライブ #%d モーターオフ", fdc.accdrive);
                    109:                }
                    110:                return 0;
                    111:        }
1.1.1.4   root      112:        __unreachable();
1.1       root      113: }
                    114: 
                    115: uint64
1.1.1.7   root      116: FDCDevice::Peek(uint32 offset)
1.1       root      117: {
1.1.1.4   root      118:        // XXX 未実装
1.1       root      119:        return 0xff;
                    120: }
                    121: 
                    122: // FDC ステータスレジスタ読み込み
                    123: uint32
                    124: FDCDevice::ReadStatus()
                    125: {
                    126:        uint8 stat = 0;
                    127: 
                    128:        if (fdc.RQM) {
                    129:                stat |= FDC::STAT_RQM;
                    130:        }
                    131:        if (fdc.DIO == DIOtoHost) {
                    132:                stat |= FDC::STAT_DIO;
                    133:        }
                    134:        if (fdc.NDM) {
                    135:                stat |= FDC::STAT_NDM;
                    136:        }
                    137:        if (fdc.CB) {
                    138:                stat |= FDC::STAT_CB;
                    139:        }
                    140:        for (int i = 0; i < 4; i++) {
                    141:                if (fdd[i].seek) {
                    142:                        stat |= (1 << i);
                    143:                }
                    144:        }
                    145: 
                    146:        putlog(2, "STAT -> $%02x", stat);
                    147:        return stat;
                    148: }
                    149: 
                    150: // FDC データレジスタ読み込み
                    151: uint32
                    152: FDCDevice::ReadData()
                    153: {
                    154:        uint8 data;
                    155: 
                    156:        data = 0xff;
                    157:        if (fdc.respos < fdc.reslen) {
                    158:                data = fdc.resbuf[fdc.respos++];
                    159:        }
                    160:        putlog(2, "DATA -> $%02x", data);
                    161: 
                    162:        if (fdc.respos == fdc.reslen) {
                    163:                idle_phase();
                    164:        }
                    165:        return data;
                    166: }
                    167: 
                    168: // ドライブステータスレジスタ読み込み
                    169: uint32
                    170: FDCDevice::ReadDriveStatus()
                    171: {
                    172:        uint8 data;
                    173: 
                    174:        // ディスク非挿入しかサポートしていない
                    175:        data = 0x00;
                    176:        putlog(1, "ドライブステータスレジスタ読み込み; ディスク非挿入");
                    177:        return data;
                    178: }
                    179: 
                    180: // FDC コマンドレジスタ書き込み
                    181: void
                    182: FDCDevice::WriteCmd(uint32 data)
                    183: {
                    184:        // cmdpos のインクリメントはログ表示の後で行なっている
                    185:        fdc.cmdbuf[fdc.cmdpos] = data;
                    186: 
                    187:        // 1バイト目はコマンドで、それによって長さが変わる。
                    188:        // コマンド名をログに表示したい。
                    189:        if (fdc.cmdpos == 0) {
                    190:                // コマンドはまず下位5ビットであたりをつける
                    191:                switch (data & FDC::CMD_MASK) {
                    192:                 case FDC::CMD_SPECIFY:
                    193:                        fdc.cmdlen = 3;
                    194:                        break;
                    195:                 case FDC::CMD_SENSE_DEVICE_STATUS:
                    196:                        fdc.cmdlen = 2;
                    197:                        break;
                    198:                 case FDC::CMD_SENSE_INTERRUPT_STATUS:
                    199:                        fdc.cmdlen = 1;
                    200:                        break;
                    201:                 case FDC::CMD_RECALIBRATE:
                    202:                        fdc.cmdlen = 2;
                    203:                        break;
                    204:                 case FDC::CMD_SEEK:
                    205:                        fdc.cmdlen = 3;
                    206:                        break;
                    207: 
                    208:                 default:
                    209:                        // 未実装コマンド
                    210:                        fdc.cmdlen = 1;
                    211:                }
                    212: 
                    213:                const char *cmdname = cmd2name(data & FDC::CMD_MASK);
                    214:                putlog(2, "CMD[%d] <- $%02x(%s)", fdc.cmdpos, data, cmdname);
                    215:        } else {
                    216:                putlog(2, "CMD[%d] <- $%02x", fdc.cmdpos, data);
                    217:                // CB は2バイト目から
                    218:                fdc.CB = true;
                    219:        }
                    220:        // ここでインクリメント
                    221:        fdc.cmdpos++;
                    222: 
                    223:        // 全部受け取ったらフェーズ遷移
                    224:        if (fdc.cmdpos >= fdc.cmdlen) {
                    225:                exec_phase();
                    226:        }
                    227: }
                    228: 
                    229: // idle フェーズに移行
                    230: void
                    231: FDCDevice::idle_phase()
                    232: {
                    233:        fdc.phase = PHASE_IDLE;
                    234:        fdc.RQM = true;
                    235:        fdc.DIO = DIOtoFDC;
                    236:        fdc.NDM = false;
                    237:        fdc.CB = false;
                    238:        fdc.cmdpos = 0;
                    239:        fdc.cmdlen = 0;
                    240:        fdc.respos = 0;
                    241:        fdc.reslen = 0;
                    242:        putlog(2, "Idle フェーズ");
                    243: }
                    244: 
                    245: // Exec フェーズに移行
                    246: void
                    247: FDCDevice::exec_phase()
                    248: {
                    249:        fdc.phase = PHASE_EXEC;
                    250:        fdc.DIO = DIOtoFDC;
                    251:        fdc.CB = true;
                    252:        if (fdc.nd) {
                    253:                fdc.NDM = true; // XXX ?
                    254:        }
                    255: 
                    256:        switch (fdc.cmdbuf[0] & FDC::CMD_MASK) {
                    257:         case FDC::CMD_SPECIFY:
                    258:                putlog(1, "Exec フェーズ: SPECIFY");
                    259:                fdc.srt = fdc.cmdbuf[1] >> 4;
                    260:                fdc.hut = fdc.cmdbuf[1] & 15;
                    261:                fdc.hlt = fdc.cmdbuf[2] >> 1;
                    262:                fdc.nd = (fdc.cmdbuf[2] & 1);
                    263:                idle_phase();
                    264:                break;
                    265: 
                    266:         case FDC::CMD_SENSE_DEVICE_STATUS:
                    267:                putlog(1, "Exec フェーズ: SENSE DEVICE STATUS");
1.1.1.9 ! root      268:                uint8 st3;
        !           269:                st3 = fdc.cmdbuf[1] & 0x07;
        !           270:                if ((force_ready || fdd[fdc.accdrive].ready) == true) {
        !           271:                        st3 |= FDC::ST3_RY;
        !           272:                }
        !           273:                fdc.resbuf[0] = st3;
1.1       root      274:                fdc.reslen = 1;
                    275:                result_phase();
                    276:                break;
                    277: 
                    278:         case FDC::CMD_SENSE_INTERRUPT_STATUS:
                    279:         {
                    280:                putlog(1, "Exec フェーズ: SENSE INTERRUPT STATUS");
1.1.1.6   root      281:                // XXX とりあえずここで割り込みを下げる。
                    282:                //     実際には割り込み状態をラッチして信号線に出すというコマンドで
                    283:                //     割り込み要因がオフになっていればそれによってネゲートされる
                    284:                //     ということのようだ。
1.1.1.9 ! root      285:                if (interrupt == false) {
        !           286:                        // XXX 割り込みが起きていないときは INVALID と同じらしい
        !           287:                        fdc.resbuf[0] = 0x80;
        !           288:                        fdc.reslen = 1;
        !           289:                        result_phase();
        !           290:                        break;
        !           291:                }
1.1.1.6   root      292:                gPEDEC->NegateINT(this);
1.1.1.9 ! root      293:                interrupt = false;
1.1       root      294:                // XXX まだフロッピー挿入はない
                    295:                uint8 st0 = 0;
                    296:                st0 |= FDC::ST0_IC_NT;
1.1.1.9 ! root      297:                if ((force_ready || fdd[fdc.accdrive].ready) == false) {
        !           298:                        st0 |= FDC::ST0_NR;
        !           299:                }
1.1       root      300:                st0 |= fdc.accdrive;
                    301:                fdc.resbuf[0] = st0;
                    302:                fdc.resbuf[1] = 0;      // XXX PCN
                    303:                fdc.reslen = 2;
                    304:                result_phase();
                    305:                break;
                    306:         }
                    307: 
                    308:         case FDC::CMD_RECALIBRATE:
                    309:                putlog(1, "Exec フェーズ: RECALIBRATE");
                    310:                fdd[fdc.accdrive].seek = true;
                    311:                // SEEK/RECALIBRATE では CB はセットされない
                    312:                fdc.CB = false;
                    313:                idle_phase();
                    314:                // XXX ヘッドの位置という概念がまだない
                    315:                event.time = 0;
1.1.1.9 ! root      316:                event.code = FDC::CMD_RECALIBRATE; // XXX コマンドをメンバ変数にするとか
        !           317:                gScheduler->RestartEvent(event);
1.1       root      318:                break;
                    319: 
                    320:         case FDC::CMD_SEEK:
                    321:                putlog(1, "Exec フェーズ: SEEK (未実装)");
                    322:                // SEEK/RECALIBRATE では CB はセットされない
                    323:                fdc.CB = false;
                    324:                idle_phase();
                    325:                break;
                    326: 
                    327:         default:
                    328:                putlog(0, "未実装 Exec フェーズ $%02x", fdc.cmdbuf[0]);
                    329:                break;
                    330:        }
                    331: }
                    332: 
                    333: // Result フェーズに移行
                    334: void
                    335: FDCDevice::result_phase()
                    336: {
                    337:        putlog(1, "Result フェーズ");
                    338:        fdc.phase = PHASE_RESULT;
                    339:        fdc.RQM = true;
                    340:        fdc.DIO = DIOtoHost;
                    341:        fdc.NDM = false;
                    342:        fdc.CB = true;
                    343: }
                    344: 
                    345: // イベントコールバック
                    346: void
1.1.1.5   root      347: FDCDevice::Callback(Event& ev)
1.1       root      348: {
1.1.1.5   root      349:        switch (ev.code) {
1.1       root      350:         case FDC::CMD_RECALIBRATE:
                    351:                fdd[fdc.accdrive].seek = false;
1.1.1.9 ! root      352:                fdc.DIO = DIOtoFDC;
1.1       root      353:                Interrupt();
                    354:                break;
                    355:        }
                    356: }
                    357: 
                    358: // 割り込みを上げる
                    359: void
                    360: FDCDevice::Interrupt()
                    361: {
1.1.1.6   root      362:        gPEDEC->AssertINT(this);
1.1.1.9 ! root      363:        interrupt = true;
        !           364: }
        !           365: 
        !           366: // 強制レディ信号の設定
        !           367: void
        !           368: FDCDevice::SetForceReady(bool force_ready_)
        !           369: {
        !           370:        force_ready = force_ready_;
1.1       root      371: }
                    372: 
                    373: // コマンド名
                    374: /* static */ const char *
                    375: FDCDevice::cmdnames_str[] = {
                    376:        NULL,                                           // 0x00
                    377:        NULL,                                           // 0x01
                    378:        "READ DIAGNOSTIC",                      // 0x02
                    379:        "SPECIFY",                                      // 0x03
                    380:        "SENSE DEVICE STATUS",          // 0x04
                    381:        "WRITE DATA",                           // 0x05
                    382:        "READ",                                         // 0x06
                    383:        "RECALIBRATE",                          // 0x07
                    384:        "SENSE INTERRUPT STATUS",       // 0x08
                    385:        "WRITE DELETED DATA",           // 0x09
                    386:        "READ ID",                                      // 0x0a
                    387:        NULL,                                           // 0x0b
                    388:        "READ DELETED DATA",            // 0x0c
                    389:        "WRITE ID",                                     // 0x0d
                    390:        NULL,                                           // 0x0e
                    391:        "SEEK",                                         // 0x0f
                    392:        NULL,                                           // 0x10
                    393:        "SCAN EQUAL",                           // 0x11
                    394:        NULL,                                           // 0x12
                    395:        NULL,                                           // 0x13
                    396:        "RESET STANDBY",                        // 0x14
                    397:        "SET STANDBY",                          // 0x15
                    398:        "SOFTWARE RESET",                       // 0x16
                    399:        NULL,                                           // 0x17
                    400:        NULL,                                           // 0x18
                    401:        "SCAN LOW OR EQUAL",            // 0x19
                    402:        NULL,                                           // 0x1a
                    403:        NULL,                                           // 0x1b
                    404:        NULL,                                           // 0x1c
                    405:        "SCAN HIGH OR EQUAL",           // 0x1d
                    406: };
                    407: 
                    408: // コマンドを名前に変換
                    409: /* static */ const char *
                    410: FDCDevice::cmd2name(uint32 cmd)
                    411: {
                    412:        if (cmd < countof(cmdnames_str) && cmdnames_str[cmd]) {
                    413:                return cmdnames_str[cmd];
                    414:        } else {
                    415:                return "?";
                    416:        }
                    417: }

unix.superglobalmegacorp.com

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