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

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

unix.superglobalmegacorp.com

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