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

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

unix.superglobalmegacorp.com

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