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

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

unix.superglobalmegacorp.com

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