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

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;
1.1.1.2 ! root       20:        event.SetName("FDC");
1.1       root       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.