Annotation of nono/vm/crtc.cpp, revision 1.1.1.8

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.8 ! root        7: //
        !             8: // CRTC
        !             9: //
1.1       root       10: 
1.1.1.4   root       11: // e80000..e803ff 内は $40 バイトでミラー。
                     12: // e80400..e807ff 内は 256 バイトでミラーになっており、このうち
                     13: // +$00..+$7f はバスエラー、
                     14: // +$80..+$ff は何かが読める。
                     15: // 仕様は $e80480.w に1ポートあるので、これがワードで全域にミラーされている?
                     16: // 全体としては この $800 バイトずつが繰り返して見える。
                     17: 
1.1.1.8 ! root       18: #include "crtc.h"
        !            19: #include "mfp.h"
        !            20: #include "mpu.h"
        !            21: #include "renderer.h"
        !            22: #include "scheduler.h"
        !            23: #include "tvram.h"
        !            24: 
        !            25: // グローバル参照用
        !            26: CRTCDevice *gCRTC;
1.1.1.4   root       27: 
1.1.1.8 ! root       28: // コンストラクタ
1.1       root       29: CRTCDevice::CRTCDevice()
1.1.1.7   root       30:        : inherited("CRTC")
1.1       root       31: {
                     32:        devaddr = 0xe80000;
                     33:        devlen  = 0x2000;
                     34: 
1.1.1.8 ! root       35:        hsync_event.func = ToEventCallback(&CRTCDevice::HSyncCallback);
        !            36:        hsync_event.Regist("CRTC H-Sync");
        !            37:        vdisp_event.func = ToEventCallback(&CRTCDevice::VDispCallback);
        !            38:        vdisp_event.Regist("CRTC V-DISP");
        !            39: 
        !            40:        monitor.func = ToMonitorCallback(&CRTCDevice::MonitorUpdate);
        !            41:        monitor.SetSize(60, 5);
        !            42:        monitor.Regist(ID_MONITOR_CRTC);
1.1       root       43: }
                     44: 
1.1.1.8 ! root       45: // デストラクタ
1.1       root       46: CRTCDevice::~CRTCDevice()
                     47: {
1.1.1.8 ! root       48:        gCRTC = NULL;
1.1       root       49: }
                     50: 
1.1.1.8 ! root       51: // リセット
1.1       root       52: void
1.1.1.8 ! root       53: CRTCDevice::ResetHard(bool poweron)
1.1       root       54: {
                     55:        // XXX 初期値適当
                     56:        crtc.r[20] = 0x0016;
                     57: 
                     58:        // XXX 適当
1.1.1.8 ! root       59:        // すぐに水平同期と垂直帰線期間を開始する
        !            60:        hsync_event.time = 0;
        !            61:        hsync_event.code = 1;
        !            62:        gScheduler->RestartEvent(hsync_event);
1.1       root       63:        vdisp_event.time = 0;
                     64:        vdisp_event.code = 1;
1.1.1.8 ! root       65:        gScheduler->RestartEvent(vdisp_event);
1.1       root       66: }
                     67: 
                     68: uint64
1.1.1.6   root       69: CRTCDevice::Read(uint32 offset)
1.1       root       70: {
1.1.1.4   root       71:        uint64 data;
1.1       root       72: 
1.1.1.5   root       73:        gMPU->AddCycle(9);      // InsideOut p.135
                     74: 
1.1.1.6   root       75:        if (offset < 0x400 / 2) {               // CRTC レジスタ
1.1.1.4   root       76:                // 0x40 バイトでミラー
1.1.1.6   root       77:                offset &= (0x40 / 2) - 1;
1.1.1.4   root       78:                // R20, R21 のみ読み出し可能
1.1.1.6   root       79:                switch (offset) {
1.1.1.4   root       80:                 case 20:
1.1.1.6   root       81:                        data = crtc.r[offset];
                     82:                        putlog(2, "R%02d -> $%04x", offset, (uint32)data);
1.1.1.4   root       83:                        break;
                     84:                 case 21:
                     85:                        // R21 へのアクセスは多いのでログレベルを上げておく
1.1.1.6   root       86:                        data = crtc.r[offset];
                     87:                        putlog(3, "R%02d -> $%04x", offset, (uint32)data);
1.1.1.4   root       88:                        break;
                     89:                 default:
                     90:                        // それ以外は読み出し不可 ($00 が読める)
                     91:                        data = 0;
1.1.1.6   root       92:                        if (offset < countof(crtc.r)) {
                     93:                                putlog(3, "R%02d -> $%04x", offset, (uint32)data);
1.1.1.4   root       94:                        } else {
                     95:                                putlog(3, "$%06x -> $%04x", gMPU->GetPaddr(), (uint32)data);
                     96:                        }
                     97:                        break;
1.1       root       98:                }
                     99: 
1.1.1.4   root      100:        } else {                                        // 動作ポート
1.1.1.6   root      101:                if ((offset & (0x80 / 2)) == 0) {       // +$00..+$7f
1.1.1.4   root      102:                        data = (uint64)-1;
1.1.1.6   root      103:                } else {                                                        // +$80..+$ff
1.1.1.4   root      104:                        data = crtc.op;
1.1       root      105:                }
                    106:        }
                    107: 
                    108:        return data;
                    109: }
                    110: 
                    111: uint64
1.1.1.6   root      112: CRTCDevice::Write(uint32 offset, uint32 data)
1.1       root      113: {
1.1.1.5   root      114:        gMPU->AddCycle(9);      // InsideOut p.135
                    115: 
1.1.1.6   root      116:        if (offset < 0x400 / 2) {               // CRTC レジスタ
1.1.1.4   root      117:                // 0x40 バイトでミラー
1.1.1.6   root      118:                offset &= (0x40 / 2) - 1;
                    119:                if (offset < countof(crtc.r)) {
                    120:                        SetReg(offset, data);
1.1       root      121:                } else {
1.1.1.4   root      122:                        // ここ何がいるんだ?
                    123:                        putlog(2, "$%06x <- $%04x", gMPU->GetPaddr(), data);
1.1       root      124:                }
                    125: 
1.1.1.4   root      126:        } else {                                        // 動作ポート
1.1.1.6   root      127:                if ((offset & (0x80 / 2)) == 0) {       // +$00..+$7f
1.1.1.4   root      128:                        return (uint64)-1;
                    129:                } else {
1.1.1.8 ! root      130:                        WriteOp(data);
1.1       root      131:                }
                    132:        }
1.1.1.4   root      133: 
1.1       root      134:        return 0;
                    135: }
                    136: 
                    137: uint64
1.1.1.6   root      138: CRTCDevice::Peek(uint32 offset)
1.1       root      139: {
1.1.1.4   root      140:        uint64 data;
1.1       root      141: 
1.1.1.6   root      142:        if (offset < 0x400 / 2) {               // CRTC レジスタ
1.1.1.4   root      143:                // 0x40 バイトでミラー
1.1.1.6   root      144:                offset &= (0x40 / 2) - 1;
                    145:                if (offset == 20 || offset == 21) {
1.1.1.4   root      146:                        // R20, R21 のみ読み出し可能
1.1.1.6   root      147:                        data = crtc.r[offset];
1.1.1.4   root      148:                } else {
                    149:                        data = 0;
                    150:                }
1.1       root      151: 
1.1.1.4   root      152:        } else {                                        // 動作ポート
1.1.1.6   root      153:                if ((offset & (0x80 / 2)) == 0) {
1.1.1.4   root      154:                        data = (uint64)-1;
                    155:                } else {
                    156:                        data = crtc.op;
                    157:                }
1.1       root      158:        }
1.1.1.4   root      159: 
                    160:        return data;
1.1       root      161: }
                    162: 
1.1.1.8 ! root      163: void
        !           164: CRTCDevice::MonitorUpdate(Monitor *, TextScreen& screen)
        !           165: {
        !           166:        int y;
        !           167:        uint16 val;
        !           168: 
        !           169:        screen.Clear();
        !           170: 
        !           171:        y = 0;
        !           172:        screen.Print(0, y++, "R10:$%04x (Text ScrollX)", crtc.r[10]);
        !           173:        screen.Print(0, y++, "R11:$%04x (Text ScrollY)", crtc.r[11]);
        !           174: 
        !           175:        val = crtc.r[21];
        !           176:        screen.Print(0, y,   "R21:$%04x (Text Plane)", val);
        !           177:        screen.Print(29, y,  "MEN=%c SA=%c AP=%%%c%c%c%c CP=%%%c%c%c%c",
        !           178:                (val & 0x0200) ? '1' : '0',
        !           179:                (val & 0x0100) ? '1' : '0',
        !           180:                (val & 0x0080) ? '1' : '0',
        !           181:                (val & 0x0040) ? '1' : '0',
        !           182:                (val & 0x0020) ? '1' : '0',
        !           183:                (val & 0x0010) ? '1' : '0',
        !           184:                (val & 0x0008) ? '1' : '0',
        !           185:                (val & 0x0004) ? '1' : '0',
        !           186:                (val & 0x0002) ? '1' : '0',
        !           187:                (val & 0x0001) ? '1' : '0');
        !           188:        y++;
        !           189: 
        !           190:        val = crtc.r[22];
        !           191:        screen.Print(0, y++, "R22:$%04x (Text Raster Copy) src=$%02x dst=$%02x",
        !           192:                val, (val >> 8), (val & 0xff));
        !           193: 
        !           194:        screen.Print(0, y++, "R23:$%04x (Text Access Mask)", crtc.r[23]);
        !           195: }
        !           196: 
1.1.1.4   root      197: // CRTC レジスタへの書き込み。
                    198: // reg は CRTC::R00 .. CRTC::R23
1.1       root      199: void
1.1.1.4   root      200: CRTCDevice::SetReg(uint32 reg, uint32 data)
1.1       root      201: {
                    202:        crtc.r[reg] = data;
                    203: 
                    204:        switch (reg) {
1.1.1.4   root      205:         case CRTC::R10:
                    206:                putlog(2, "R%02d <- $%04x", reg, data);
                    207:                gTVRAM->SetScrollX(crtc.r[10]);
                    208:                break;
                    209:         case CRTC::R11:
                    210:                putlog(2, "R%02d <- $%04x", reg, data);
                    211:                gTVRAM->SetScrollY(crtc.r[11]);
                    212:                break;
1.1       root      213:         case CRTC::R21:
1.1.1.4   root      214:                // 頻度が高いのでログレベルを上げておく
                    215:                putlog(3, "R%02d <- $%04x", reg, data);
1.1.1.8 ! root      216:                gTVRAM->SetAccessPlane(crtc.r[21]);
        !           217:                break;
        !           218:         case CRTC::R22:
        !           219:                putlog(3, "R%02d <- $%04x", reg, data);
        !           220:                break;
        !           221:         case CRTC::R23:
        !           222:                // 頻度が高いのでログレベルを上げておく
        !           223:                putlog(3, "R%02d <- $%04x", reg, data);
        !           224:                gTVRAM->SetAccessMask(crtc.r[23]);
1.1       root      225:                break;
                    226:         default:
1.1.1.4   root      227:                putlog(2, "R%02d <- $%04x (未実装)", reg, data);
                    228:                break;
1.1       root      229:        }
                    230: }
                    231: 
1.1.1.8 ! root      232: // 動作ポートへの書き込み。
        !           233: void
        !           234: CRTCDevice::WriteOp(uint32 data)
        !           235: {
        !           236:        uint16 oldop = crtc.op;
        !           237: 
        !           238:        crtc.op = data & 0x0b;
        !           239:        putlog(2, "$E80480.W <- $%04x", crtc.op);
        !           240: 
        !           241:        uint16 change = oldop ^ crtc.op;
        !           242: 
        !           243:        if ((change & CRTC::OP_RC)) {
        !           244:                // テキスト画面ラスターコピー
        !           245:                if ((crtc.op & CRTC::OP_RC)) {
        !           246:                        // 0->1 開始
        !           247:                        StartRasterCopy();
        !           248: 
        !           249:                        // XXX 本当は終わったら 0 にするはず
        !           250:                        crtc.op &= ~CRTC::OP_RC;
        !           251:                } else {
        !           252:                        // 1->0 停止
        !           253:                        // XXX 今の所一瞬で終わるので…
        !           254:                        //StopRasterCopy();
        !           255:                }
        !           256:        }
        !           257: 
        !           258:        if ((change & 0x03)) {
        !           259:                putlog(0, "動作ポート $%02x->$%02x 未実装",
        !           260:                        oldop & 0x03, crtc.op & 0x03);
        !           261:        }
        !           262: }
        !           263: 
        !           264: // テキスト画面のラスターコピー開始
        !           265: void
        !           266: CRTCDevice::StartRasterCopy()
        !           267: {
        !           268:        int src = (crtc.r[22] >> 8)   * 4;
        !           269:        int dst = (crtc.r[22] & 0xff) * 4;
        !           270: 
        !           271:        gTVRAM->RasterCopy(src, dst);
        !           272: }
        !           273: 
        !           274: // 水平同期イベント
        !           275: void
        !           276: CRTCDevice::HSyncCallback(Event& ev)
        !           277: {
        !           278:        int hsync = ev.code;
        !           279: 
        !           280:        // GPIP の状態を更新
        !           281:        gMFP->SetHSync(hsync);
        !           282: 
        !           283:        // 次のタイミングを計算
        !           284:        if (hsync) {
        !           285:                // 水平同期期間
        !           286:                ev.time = 3.45_usec;
        !           287:                ev.code = 0;
        !           288:        } else {
        !           289:                //
        !           290:                ev.time = 22.09_usec + 4.14_usec + 2.07_usec;
        !           291:                ev.code = 1;
        !           292:        }
        !           293:        gScheduler->StartEvent(ev);
        !           294: }
        !           295: 
1.1       root      296: // 垂直表示・帰線イベント
1.1.1.5   root      297: // ev.code が 1 なら表示期間開始(V-disp)、0 なら帰線期間開始(V-blank)。
1.1       root      298: void
1.1.1.5   root      299: CRTCDevice::VDispCallback(Event& ev)
1.1       root      300: {
1.1.1.8 ! root      301:        int vdisp = ev.code;
1.1.1.5   root      302: 
1.1       root      303:        // GPIP の状態を更新
1.1.1.5   root      304:        gMFP->SetVDisp(vdisp);
1.1       root      305: 
                    306:        // 今はここで1画面まるごと作成
1.1.1.5   root      307:        if (vdisp) {
1.1       root      308:                // Render に作画指示
                    309:                gRenderer->Render();
                    310:        }
                    311: 
                    312:        // 次のタイミングを計算
                    313:        // XXX まだ CRTC から計算していない
1.1.1.5   root      314:        if (vdisp) {
1.1       root      315:                // 垂直表示期間
1.1.1.5   root      316:                ev.time = 16250_usec;
                    317:                ev.code = 0;
1.1       root      318:        } else {
                    319:                // 垂直帰線期間
1.1.1.8 ! root      320:                ev.time = 191_usec + 1111_usec + 476_usec;
1.1.1.5   root      321:                ev.code = 1;
1.1       root      322:        }
1.1.1.8 ! root      323:        gScheduler->StartEvent(ev);
1.1       root      324: }

unix.superglobalmegacorp.com

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