Annotation of nono/vm/crtc.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.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);
1.1.1.9 ! root       38:        vdisp_event.Regist("CRTC V-Disp");
        !            39: 
        !            40:        // ラスターコピーにかかる時間は最小 190nsec * 2 らしいので
        !            41:        // とりあえず 400nsec としておく。
        !            42:        raster_event.func = ToEventCallback(&CRTCDevice::RasterCallback);
        !            43:        raster_event.time = 400_nsec;
        !            44:        raster_event.Regist("CRTC Raster Copy");
1.1.1.8   root       45: 
                     46:        monitor.func = ToMonitorCallback(&CRTCDevice::MonitorUpdate);
1.1.1.9 ! root       47:        monitor.SetSize(62, 14);
1.1.1.8   root       48:        monitor.Regist(ID_MONITOR_CRTC);
1.1       root       49: }
                     50: 
1.1.1.8   root       51: // デストラクタ
1.1       root       52: CRTCDevice::~CRTCDevice()
                     53: {
1.1.1.8   root       54:        gCRTC = NULL;
1.1       root       55: }
                     56: 
1.1.1.8   root       57: // リセット
1.1       root       58: void
1.1.1.8   root       59: CRTCDevice::ResetHard(bool poweron)
1.1       root       60: {
                     61:        // XXX 初期値適当
                     62:        crtc.r[20] = 0x0016;
                     63: 
                     64:        // XXX 適当
1.1.1.8   root       65:        // すぐに水平同期と垂直帰線期間を開始する
                     66:        hsync_event.time = 0;
                     67:        hsync_event.code = 1;
                     68:        gScheduler->RestartEvent(hsync_event);
1.1       root       69:        vdisp_event.time = 0;
                     70:        vdisp_event.code = 1;
1.1.1.8   root       71:        gScheduler->RestartEvent(vdisp_event);
1.1       root       72: }
                     73: 
                     74: uint64
1.1.1.6   root       75: CRTCDevice::Read(uint32 offset)
1.1       root       76: {
1.1.1.4   root       77:        uint64 data;
1.1       root       78: 
1.1.1.5   root       79:        gMPU->AddCycle(9);      // InsideOut p.135
                     80: 
1.1.1.6   root       81:        if (offset < 0x400 / 2) {               // CRTC レジスタ
1.1.1.4   root       82:                // 0x40 バイトでミラー
1.1.1.6   root       83:                offset &= (0x40 / 2) - 1;
1.1.1.4   root       84:                // R20, R21 のみ読み出し可能
1.1.1.6   root       85:                switch (offset) {
1.1.1.4   root       86:                 case 20:
1.1.1.6   root       87:                        data = crtc.r[offset];
                     88:                        putlog(2, "R%02d -> $%04x", offset, (uint32)data);
1.1.1.4   root       89:                        break;
                     90:                 case 21:
                     91:                        // R21 へのアクセスは多いのでログレベルを上げておく
1.1.1.6   root       92:                        data = crtc.r[offset];
                     93:                        putlog(3, "R%02d -> $%04x", offset, (uint32)data);
1.1.1.4   root       94:                        break;
                     95:                 default:
                     96:                        // それ以外は読み出し不可 ($00 が読める)
                     97:                        data = 0;
1.1.1.6   root       98:                        if (offset < countof(crtc.r)) {
                     99:                                putlog(3, "R%02d -> $%04x", offset, (uint32)data);
1.1.1.4   root      100:                        } else {
                    101:                                putlog(3, "$%06x -> $%04x", gMPU->GetPaddr(), (uint32)data);
                    102:                        }
                    103:                        break;
1.1       root      104:                }
                    105: 
1.1.1.4   root      106:        } else {                                        // 動作ポート
1.1.1.6   root      107:                if ((offset & (0x80 / 2)) == 0) {       // +$00..+$7f
1.1.1.4   root      108:                        data = (uint64)-1;
1.1.1.6   root      109:                } else {                                                        // +$80..+$ff
1.1.1.4   root      110:                        data = crtc.op;
1.1       root      111:                }
                    112:        }
                    113: 
                    114:        return data;
                    115: }
                    116: 
                    117: uint64
1.1.1.6   root      118: CRTCDevice::Write(uint32 offset, uint32 data)
1.1       root      119: {
1.1.1.5   root      120:        gMPU->AddCycle(9);      // InsideOut p.135
                    121: 
1.1.1.6   root      122:        if (offset < 0x400 / 2) {               // CRTC レジスタ
1.1.1.4   root      123:                // 0x40 バイトでミラー
1.1.1.6   root      124:                offset &= (0x40 / 2) - 1;
                    125:                if (offset < countof(crtc.r)) {
                    126:                        SetReg(offset, data);
1.1       root      127:                } else {
1.1.1.4   root      128:                        // ここ何がいるんだ?
                    129:                        putlog(2, "$%06x <- $%04x", gMPU->GetPaddr(), data);
1.1       root      130:                }
                    131: 
1.1.1.4   root      132:        } else {                                        // 動作ポート
1.1.1.6   root      133:                if ((offset & (0x80 / 2)) == 0) {       // +$00..+$7f
1.1.1.4   root      134:                        return (uint64)-1;
                    135:                } else {
1.1.1.8   root      136:                        WriteOp(data);
1.1       root      137:                }
                    138:        }
1.1.1.4   root      139: 
1.1       root      140:        return 0;
                    141: }
                    142: 
                    143: uint64
1.1.1.6   root      144: CRTCDevice::Peek(uint32 offset)
1.1       root      145: {
1.1.1.4   root      146:        uint64 data;
1.1       root      147: 
1.1.1.6   root      148:        if (offset < 0x400 / 2) {               // CRTC レジスタ
1.1.1.4   root      149:                // 0x40 バイトでミラー
1.1.1.6   root      150:                offset &= (0x40 / 2) - 1;
                    151:                if (offset == 20 || offset == 21) {
1.1.1.4   root      152:                        // R20, R21 のみ読み出し可能
1.1.1.6   root      153:                        data = crtc.r[offset];
1.1.1.4   root      154:                } else {
                    155:                        data = 0;
                    156:                }
1.1       root      157: 
1.1.1.4   root      158:        } else {                                        // 動作ポート
1.1.1.6   root      159:                if ((offset & (0x80 / 2)) == 0) {
1.1.1.4   root      160:                        data = (uint64)-1;
                    161:                } else {
                    162:                        data = crtc.op;
                    163:                }
1.1       root      164:        }
1.1.1.4   root      165: 
                    166:        return data;
1.1       root      167: }
                    168: 
1.1.1.8   root      169: void
                    170: CRTCDevice::MonitorUpdate(Monitor *, TextScreen& screen)
                    171: {
                    172:        int y;
                    173:        uint16 val;
                    174: 
                    175:        screen.Clear();
                    176:        y = 0;
1.1.1.9 ! root      177: 
        !           178:        screen.Print(0, y++, "R00:$%04x (V.Total)",      crtc.r[0]);
        !           179:        screen.Print(0, y++, "R01:$%04x (V.Sync End)",   crtc.r[1]);
        !           180:        screen.Print(0, y++, "R02:$%04x (V.Disp Start)", crtc.r[2]);
        !           181:        screen.Print(0, y++, "R02:$%04x (V.Disp End)",   crtc.r[3]);
        !           182: 
        !           183:        screen.Print(0, y++, "R04:$%04x (H.Total)",      crtc.r[4]);
        !           184:        screen.Print(0, y++, "R05:$%04x (H.Sync End)",   crtc.r[5]);
        !           185:        screen.Print(0, y++, "R06:$%04x (H.Disp Start)", crtc.r[6]);
        !           186:        screen.Print(0, y++, "R07:$%04x (H.Disp End)",   crtc.r[7]);
        !           187: 
1.1.1.8   root      188:        screen.Print(0, y++, "R10:$%04x (Text ScrollX)", crtc.r[10]);
                    189:        screen.Print(0, y++, "R11:$%04x (Text ScrollY)", crtc.r[11]);
                    190: 
1.1.1.9 ! root      191:        val = crtc.r[20];
        !           192:        screen.Print(0, y,   "R20:$%04x (Mode)", val);
        !           193:        screen.Print(29, y, TA::OnOff(val & CRTC::R20_MEM), "MEM");
        !           194:        static const char * const r20col_str[] = {
        !           195:                "16",
        !           196:                "256",
        !           197:                "undef",
        !           198:                "65536",
        !           199:        };
        !           200:        screen.Print(33, y, "COL=%s", r20col_str[(val >> 8) & 3]);
        !           201:        screen.Print(43, y, TA::OnOff(val & CRTC::R20_HF), "HF");
        !           202:        static const char * const r20vd_str[] = {
        !           203:                "256",
        !           204:                "512",
        !           205:                "1024",
        !           206:                "undef",
        !           207:        };
        !           208:        screen.Print(46, y, "VD=%s", r20vd_str[(val >> 2) & 3]);
        !           209:        static const char * const r20hd_str[] = {
        !           210:                "256",
        !           211:                "512",
        !           212:                "768",
        !           213:                "50MHz",
        !           214:        };
        !           215:        screen.Print(55, y, "HD=%s", r20hd_str[val & 3]);
        !           216:        y++;
        !           217: 
1.1.1.8   root      218:        val = crtc.r[21];
                    219:        screen.Print(0, y,   "R21:$%04x (Text Plane)", val);
                    220:        screen.Print(29, y,  "MEN=%c SA=%c AP=%%%c%c%c%c CP=%%%c%c%c%c",
                    221:                (val & 0x0200) ? '1' : '0',
                    222:                (val & 0x0100) ? '1' : '0',
                    223:                (val & 0x0080) ? '1' : '0',
                    224:                (val & 0x0040) ? '1' : '0',
                    225:                (val & 0x0020) ? '1' : '0',
                    226:                (val & 0x0010) ? '1' : '0',
                    227:                (val & 0x0008) ? '1' : '0',
                    228:                (val & 0x0004) ? '1' : '0',
                    229:                (val & 0x0002) ? '1' : '0',
                    230:                (val & 0x0001) ? '1' : '0');
                    231:        y++;
                    232: 
                    233:        val = crtc.r[22];
                    234:        screen.Print(0, y++, "R22:$%04x (Text Raster Copy) src=$%02x dst=$%02x",
                    235:                val, (val >> 8), (val & 0xff));
                    236: 
                    237:        screen.Print(0, y++, "R23:$%04x (Text Access Mask)", crtc.r[23]);
                    238: }
                    239: 
1.1.1.4   root      240: // CRTC レジスタへの書き込み。
                    241: // reg は CRTC::R00 .. CRTC::R23
1.1       root      242: void
1.1.1.4   root      243: CRTCDevice::SetReg(uint32 reg, uint32 data)
1.1       root      244: {
                    245:        crtc.r[reg] = data;
                    246: 
                    247:        switch (reg) {
1.1.1.4   root      248:         case CRTC::R10:
                    249:                putlog(2, "R%02d <- $%04x", reg, data);
                    250:                gTVRAM->SetScrollX(crtc.r[10]);
                    251:                break;
                    252:         case CRTC::R11:
                    253:                putlog(2, "R%02d <- $%04x", reg, data);
                    254:                gTVRAM->SetScrollY(crtc.r[11]);
                    255:                break;
1.1       root      256:         case CRTC::R21:
1.1.1.4   root      257:                // 頻度が高いのでログレベルを上げておく
                    258:                putlog(3, "R%02d <- $%04x", reg, data);
1.1.1.8   root      259:                gTVRAM->SetAccessPlane(crtc.r[21]);
                    260:                break;
                    261:         case CRTC::R22:
                    262:                putlog(3, "R%02d <- $%04x", reg, data);
                    263:                break;
                    264:         case CRTC::R23:
                    265:                // 頻度が高いのでログレベルを上げておく
                    266:                putlog(3, "R%02d <- $%04x", reg, data);
                    267:                gTVRAM->SetAccessMask(crtc.r[23]);
1.1       root      268:                break;
                    269:         default:
1.1.1.9 ! root      270:                putlog(2, "R%02d <- $%04x (NOT IMPLEMENTED)", reg, data);
1.1.1.4   root      271:                break;
1.1       root      272:        }
                    273: }
                    274: 
1.1.1.8   root      275: // 動作ポートへの書き込み。
                    276: void
                    277: CRTCDevice::WriteOp(uint32 data)
                    278: {
                    279:        uint16 oldop = crtc.op;
                    280: 
                    281:        crtc.op = data & 0x0b;
1.1.1.9 ! root      282:        putlog(2, "$e80480.W <- $%04x", crtc.op);
1.1.1.8   root      283: 
                    284:        uint16 change = oldop ^ crtc.op;
                    285: 
                    286:        if ((change & CRTC::OP_RC)) {
                    287:                // テキスト画面ラスターコピー
                    288:                if ((crtc.op & CRTC::OP_RC)) {
                    289:                        // 0->1 開始
1.1.1.9 ! root      290:                        raster_copy = true;
        !           291:                        putlog(3, "ラスターコピー指示");
1.1.1.8   root      292:                } else {
1.1.1.9 ! root      293:                        // 1->0 は停止じゃなくキャンセル?
        !           294:                        raster_copy = false;
        !           295:                        putlog(3, "ラスターコピーキャンセル");
1.1.1.8   root      296:                }
                    297:        }
                    298: 
                    299:        if ((change & 0x03)) {
1.1.1.9 ! root      300:                putlog(0, "動作ポート $%02x <- $%02x (NOT IMPLEMENTED)",
1.1.1.8   root      301:                        oldop & 0x03, crtc.op & 0x03);
                    302:        }
                    303: }
                    304: 
                    305: // 水平同期イベント
                    306: void
                    307: CRTCDevice::HSyncCallback(Event& ev)
                    308: {
1.1.1.9 ! root      309:        switch (ev.code) {
        !           310:         case 0:        // フロントポーチ
        !           311:                // フロントポーチ
        !           312:                ev.time = 2.07_usec;
        !           313:                ev.code++;
        !           314:                break;
1.1.1.8   root      315: 
1.1.1.9 ! root      316:         case 1:        // 水平同期パルス
1.1.1.8   root      317:                // 水平同期期間
                    318:                ev.time = 3.45_usec;
1.1.1.9 ! root      319:                ev.code++;
        !           320: 
        !           321:                // GPIP の状態を更新
        !           322:                gMFP->SetHSync(true);
        !           323: 
        !           324:                // ラスターコピーが指示されていたら実行
        !           325:                if (raster_copy) {
        !           326:                        raster_copy = false;
        !           327: 
        !           328:                        int src = (crtc.r[22] >> 8)   * 4;
        !           329:                        int dst = (crtc.r[22] & 0xff) * 4;
        !           330:                        gTVRAM->RasterCopy(src, dst);
        !           331: 
        !           332:                        // 所定時間後に完了させる
        !           333:                        gScheduler->RestartEvent(raster_event);
        !           334:                }
        !           335:                break;
        !           336: 
        !           337:         case 2:        // バックポーチ + 表示期間
        !           338:                // バックポーチ + Hdisp
        !           339:                ev.time = 4.14_usec + 22.09_usec;
1.1.1.8   root      340:                ev.code = 0;
1.1.1.9 ! root      341: 
        !           342:                // GPIP の状態を更新
        !           343:                gMFP->SetHSync(false);
        !           344:                break;
1.1.1.8   root      345:        }
1.1.1.9 ! root      346: 
1.1.1.8   root      347:        gScheduler->StartEvent(ev);
                    348: }
                    349: 
1.1.1.9 ! root      350: // ラスターコピー完了イベント
        !           351: void
        !           352: CRTCDevice::RasterCallback(Event& ev)
        !           353: {
        !           354:        // 終わったら動作ポートの RC ビットを %0 にする?
        !           355:        crtc.op &= ~CRTC::OP_RC;
        !           356: }
        !           357: 
1.1       root      358: // 垂直表示・帰線イベント
1.1.1.5   root      359: // ev.code が 1 なら表示期間開始(V-disp)、0 なら帰線期間開始(V-blank)。
1.1       root      360: void
1.1.1.5   root      361: CRTCDevice::VDispCallback(Event& ev)
1.1       root      362: {
1.1.1.8   root      363:        int vdisp = ev.code;
1.1.1.5   root      364: 
1.1       root      365:        // GPIP の状態を更新
1.1.1.5   root      366:        gMFP->SetVDisp(vdisp);
1.1       root      367: 
                    368:        // 今はここで1画面まるごと作成
1.1.1.5   root      369:        if (vdisp) {
1.1       root      370:                // Render に作画指示
                    371:                gRenderer->Render();
                    372:        }
                    373: 
                    374:        // 次のタイミングを計算
                    375:        // XXX まだ CRTC から計算していない
1.1.1.5   root      376:        if (vdisp) {
1.1       root      377:                // 垂直表示期間
1.1.1.5   root      378:                ev.time = 16250_usec;
                    379:                ev.code = 0;
1.1       root      380:        } else {
                    381:                // 垂直帰線期間
1.1.1.8   root      382:                ev.time = 191_usec + 1111_usec + 476_usec;
1.1.1.5   root      383:                ev.code = 1;
1.1       root      384:        }
1.1.1.8   root      385:        gScheduler->StartEvent(ev);
1.1       root      386: }

unix.superglobalmegacorp.com

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