Annotation of nono/vm/lunafb.cpp, revision 1.1.1.11

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
1.1.1.2   root        8: // LUNA ビットマッププレーン
1.1       root        9: //
                     10: 
                     11: // SX-9100 のほうはこう書いてあってこっちが正しいようだ。
                     12: //      +00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
1.1.1.6   root       13: // b100 |RF|RF|RF|RF|BS|        |共 通 B M P|プレーン#0 |
1.1       root       14: // b110 |プレーン#1 |プレーン#2 |プレーン#3 |プレーン#4 |
                     15: // b120 |プレーン#5 |プレーン#6 |プレーン#7 |FC|        |
                     16: // b130 |F0|        |F1|        |F2|        |F3|        |
                     17: // b140 |F4|        |F5|        |F6|        |F7|        |
                     18: //
                     19: // SX-7100 のほうはこう書いてあるがこうはなっていないようだ。
                     20: //      +00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
                     21: // b100 |RF|        |BS|        |共 通 B M P|FC|        |
                     22: // b110 |プレーン#0 |プレーン#1 |プレーン#2 |プレーン#3 |
                     23: // b120 |プレーン#4 |プレーン#5 |プレーン#6 |プレーン#7 |
                     24: // b130 |F0|        |F1|        |F2|        |F3|        |
                     25: // b140 |F4|        |F5|        |F6|        |F7|        |
                     26: //
1.1.1.6   root       27: // RF: RFCNT (4バイト)。b100'0000 から b104'0000 の手前までこの1ポートのミラー。
                     28: // BS: BMSEL (4バイト)。こっちは未確認だがたぶん RFCNT と同じ?
1.1       root       29: // FC: 共通ファンクションセット
                     30: // Fn: プレーン#n ファンクションセット
                     31: // 1区画が 64KB。空白のところは未調査。
                     32: // 未装着のプレーン(#4..#7とか)は 0xff が読めるようだ。
                     33: // ファンクションセットが 64バイトで折り返してるか未調査だが、
                     34: // b130'0000 も b133'0000 も 0xff が読めるのでこの範囲全域でミラーかも。
                     35: // b150'0000 以降(b1ff'ffffまで) は BUSERR のようだ。
                     36: 
1.1.1.2   root       37: // Lunafb の VRAM はロングワード単位でホストバイトオーダ配置なので、
                     38: // バイトアクセス、ワードアクセス時は HLB(), HLW() マクロを使用のこと。
                     39: 
                     40: #include "lunafb.h"
1.1.1.4   root       41: #include "bt45x.h"
1.1.1.3   root       42: #include "builtinrom.h"
1.1.1.6   root       43: #include "busio.h"
1.1.1.7   root       44: #include "monitor.h"
1.1.1.2   root       45: #include "mpu.h"
1.1       root       46: 
1.1.1.2   root       47: // コンストラクタ
1.1       root       48: LunafbDevice::LunafbDevice()
1.1.1.4   root       49:        : inherited(2048, 1024)
1.1       root       50: {
1.1.1.4   root       51:        SetName("Lunafb");
                     52:        ClearAlias();
                     53:        AddAlias("Lunafb");
1.1.1.2   root       54: 
1.1.1.7   root       55:        monitor = gMonitorManager->Regist(ID_MONITOR_LUNAVC, this);
1.1.1.11! root       56:        monitor->SetCallback(&LunafbDevice::MonitorScreen);
1.1.1.7   root       57:        monitor->SetSize(39, 11);
1.1       root       58: }
                     59: 
1.1.1.2   root       60: // デストラクタ
1.1       root       61: LunafbDevice::~LunafbDevice()
                     62: {
                     63: }
                     64: 
1.1.1.4   root       65: // 初期化
1.1       root       66: bool
                     67: LunafbDevice::Init()
                     68: {
1.1.1.9   root       69:        if (inherited::Init() == false) {
                     70:                return false;
                     71:        }
                     72: 
1.1.1.4   root       73:        auto bt45x = GetBT45xDevice();
                     74:        nplane = bt45x->GetPlaneCount();
                     75: 
1.1       root       76:        plane_end = plane0base + 0x40000 * nplane;
1.1.1.3   root       77:        fcset_end = fcset0base + 0x40000 * nplane;
1.1       root       78: 
                     79:        // プレーン数によってメモリを確保
1.1.1.9   root       80:        size_t memsize = 0x40000 * nplane;
                     81:        mem.reset(new(std::nothrow) uint8 [memsize]);
                     82:        if ((bool)mem == false) {
1.1.1.11! root       83:                warnx("Could not allocate %zu bytes at %s", memsize, __method__);
1.1.1.9   root       84:                return false;
                     85:        }
1.1       root       86: 
1.1.1.2   root       87:        // ホストパレットを取得。
1.1.1.4   root       88:        palette = &(bt45x->GetHostPalette())[0];
1.1       root       89: 
1.1.1.5   root       90:        // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
1.1.1.11! root       91:        wait = busdata::Wait(1 * mpu->GetClock_tsec());
1.1.1.5   root       92: 
1.1       root       93:        return true;
                     94: }
                     95: 
1.1.1.2   root       96: // 電源オン/リセット
1.1       root       97: void
1.1.1.2   root       98: LunafbDevice::ResetHard(bool poweron)
1.1       root       99: {
1.1.1.5   root      100:        inherited::ResetHard(poweron);
                    101: 
1.1.1.2   root      102:        if (poweron) {
                    103:                // XXX 実際は不定値だと思うけど、観測手段がないのでとりあえず。
                    104:                memset(&mem[0], 0xff, 0x40000 * nplane);
                    105:        }
                    106: 
1.1       root      107:        // 厳密にどの時点でリセットされるのかは知らないけど
                    108:        bmsel = 0;
                    109: 
                    110:        // XXX 初期値の観測は困難なので適当
                    111:        rfcnt = 0;
1.1.1.2   root      112:        xscroll = 0;
                    113:        yscroll = 0;
1.1       root      114: 
                    115:        for (int i = 0; i < MAX_PLANES; i++) {
1.1.1.4   root      116:                fcset[i] = ROP::THRU;
1.1.1.2   root      117:                fcmask[i] = 0xffffffff;
1.1       root      118:        }
                    119: }
                    120: 
1.1.1.5   root      121: busdata
1.1.1.6   root      122: LunafbDevice::Read(busaddr addr)
1.1       root      123: {
1.1.1.6   root      124:        uint32 paddr = addr.Addr();
1.1.1.5   root      125:        busdata data;
1.1       root      126: 
1.1.1.6   root      127:        if (plane0base <= paddr && paddr < plane_end) {
1.1       root      128:                // プレーンの読み出し
1.1.1.6   root      129:                data = *(uint32 *)&mem[(paddr & ~3U) - plane0base];
1.1.1.5   root      130:        } else {
                    131:                // 残りは書き込み専用または不在
1.1.1.6   root      132:                putlog(1, "Read not-readable $%08x", paddr);
                    133:                data = 0xffffffff;
1.1       root      134:        }
1.1.1.5   root      135:        data |= wait;
1.1.1.6   root      136:        data |= BusData::Size4;
1.1.1.5   root      137:        return data;
1.1       root      138: }
                    139: 
1.1.1.5   root      140: busdata
1.1.1.6   root      141: LunafbDevice::Write(busaddr addr, uint32 data)
1.1       root      142: {
1.1.1.6   root      143:        uint32 paddr = addr.Addr();
1.1       root      144: 
1.1.1.6   root      145:        // RFCNT と BMSEL だけバスの処理が別。というよりバスの観点から言えば
                    146:        // 本来別デバイスだが便宜上同じデバイスに同居している感じ。
                    147:        if (paddr < 0xb1080000) {
                    148:                return WriteReg(addr, data);
1.1       root      149:        }
                    150: 
1.1.1.6   root      151:        uint32 reqsize = addr.GetSize();
                    152:        // 3バイトアクセスは面倒なので回避して .B/.W/.L に整列させる。
                    153:        uint32 datasize;
                    154:        if (reqsize == 4 && (paddr & 3U) == 0) {
                    155:                datasize = 4;
1.1.1.5   root      156:        } else {
1.1.1.6   root      157:                datasize = std::min(2 - (paddr & 1U), reqsize);
1.1       root      158:        }
1.1.1.6   root      159:        data >>= (reqsize - datasize) * 8;
1.1       root      160: 
1.1.1.6   root      161:        if (paddr < plane0base) {
1.1       root      162:                // 共通ビットマッププレーン
1.1.1.6   root      163:                if (datasize == 4) {
                    164:                        WriteCommonBitmap32(paddr, data);
                    165:                } else if (datasize == 2) {
                    166:                        WriteCommonBitmap16(paddr, data);
                    167:                } else {
                    168:                        WriteCommonBitmap8(paddr, data);
                    169:                }
1.1       root      170: 
1.1.1.6   root      171:        } else if (__predict_true(paddr < plane_end)) {
1.1.1.3   root      172:                // 存在するビットマッププレーン
1.1.1.6   root      173:                uint32 reladdr = paddr - plane0base;
1.1       root      174:                uint plane = reladdr / 0x40000;
                    175:                uint32 offset = reladdr % 0x40000;
                    176: 
1.1.1.6   root      177:                putlog(3, "Plane%u $%08x <- $%0*x", plane, paddr, datasize * 2, data);
                    178: 
                    179:                if (datasize == 4) {
                    180:                        WritePlane32(plane, offset, data);
                    181:                } else if (datasize == 2) {
                    182:                        WritePlane16(plane, offset, data);
                    183:                } else {
                    184:                        WritePlane8(plane, offset, data);
                    185:                }
1.1.1.3   root      186:                SetDirty(offset);
                    187: 
1.1.1.6   root      188:        } else if (__predict_false(paddr < plane7end)) {
1.1.1.3   root      189:                // HW 設定によっては存在しないプレーン
1.1.1.6   root      190:                uint32 reladdr = paddr - plane0base;
1.1.1.3   root      191:                uint plane = reladdr / 0x40000;
1.1.1.6   root      192:                putlog(3, "Not-equipped Plane%u $%08x <- $%0*x",
                    193:                        plane, paddr, datasize * 2, data);
1.1       root      194: 
1.1.1.6   root      195:        } else if (paddr < 0xb1300000) {
                    196:                // 共通ファンクションセット
                    197:                // XXX ワード、バイトアクセスはどうなる?
                    198:                uint rop = (paddr & 0x3f) / 4;
                    199:                putlog(2, "Common FCSet $%08x <- $%0*x (%s)",
                    200:                        paddr, datasize * 2, data, RopStr(rop));
                    201:                WriteCommonFCSet(rop, data);
1.1       root      202: 
1.1.1.6   root      203:        } else if (__predict_true(paddr < fcset_end)) {
                    204:                // 存在するファンクションセット
                    205:                // XXX ワード、バイトアクセスはどうなる?
                    206:                uint plane = (paddr - 0xb1300000) / 0x40000;
                    207:                uint rop = (paddr & 0x3f) / 4;
                    208:                putlog(2, "FCSet%u $%08x <- $%0*x (%s)",
                    209:                        plane, paddr, datasize * 2, data, RopStr(rop));
                    210:                fcset[plane] = rop;
                    211:                fcmask[plane] = data;
1.1       root      212: 
1.1.1.6   root      213:        } else if (paddr < fcset7end) {
                    214:                // HW 設定によっては存在しないファンクションセット
                    215:                uint plane = (paddr - 0xb1300000) / 0x40000;
                    216:                putlog(3, "Not-equipped FCSet%u $%08x <- $%0*x",
                    217:                        plane, paddr, datasize * 2, data);
1.1       root      218: 
1.1.1.6   root      219:        } else {
                    220:                // 残りは全部空きのはずだが挙動未調査。
                    221:                putlog(0, "$%08x <- $%0*x (NOT IMPLEMENTED)",
                    222:                        paddr, datasize * 2, data);
1.1       root      223: 
1.1.1.3   root      224:        }
                    225: 
1.1.1.6   root      226:        busdata r = wait;
                    227:        r |= busdata::Size(datasize);
                    228:        return r;
1.1       root      229: }
                    230: 
1.1.1.5   root      231: busdata
1.1.1.6   root      232: LunafbDevice::WriteReg(busaddr addr, uint32 data)
1.1       root      233: {
1.1.1.6   root      234:        // RFCNT レジスタ部分は BusIO_L, NPORT=1 相当。
                    235:        //
                    236:        // LUNA-88K PROM で `cw b1040000 0` した後、
                    237:        // `cs b1040000 0100` (RFCNT の上位ワードに $0100 を書き込む) を実行する
                    238:        // と、垂直位置だけが変わる。RFCNT は上位ワードの下位 8 ビットが水平
                    239:        // スクロール位置、下位ワードの下位 10 ビットが垂直スクロール位置なので、
                    240:        // ロングワード全体に $0100'0100 を $00ff'03ff でマスクした結果の
                    241:        // $0000'0100 が書き込まれたことになる。
                    242:        // m88200 のデータバスへの置き方と、このポートがロングワード固定で DBE*
                    243:        // を細かくデコードしていないとすれば辻褄が合う。
                    244:        // 同様に `cs b1040002 0020` を実行すると LUNA-88K 実機では垂直位置と
                    245:        // ともに水平位置も変わる。
                    246:        //
                    247:        // BMSEL レジスタ部分は確認が難しいけどたぶん同じだと思うことにする。
                    248:        data = BusIO::DataMultiplexer_Write_L(addr, data);
                    249: 
                    250:        if (addr.Addr() < 0xb1040000) {
1.1       root      251:                // RFCNT
                    252:                WriteRFCNT(data);
1.1.1.6   root      253:        } else {
1.1       root      254:                // BMSEL
1.1.1.10  root      255:                bmsel = data & ((1U << nplane) - 1);
1.1       root      256:                putlog(1, "BMSEL <- $%08x", data);
                    257:        }
                    258: 
1.1.1.6   root      259:        busdata r = wait;
                    260:        r |= BusData::Size4;
                    261:        return r;
1.1       root      262: }
                    263: 
1.1.1.5   root      264: busdata
1.1.1.6   root      265: LunafbDevice::Peek1(uint32 addr)
1.1       root      266: {
                    267:        if (plane0base <= addr && addr < plane_end) {
                    268:                // プレーンの読み出し
                    269:                return mem[HLB(addr - plane0base)];
                    270:        }
                    271:        // 残りは書き込み専用
                    272:        return 0xff;
                    273: }
                    274: 
1.1.1.5   root      275: bool
1.1.1.6   root      276: LunafbDevice::Poke1(uint32 addr, uint32 data)
1.1.1.4   root      277: {
                    278:        // 通常プレーンのみ越権書き込み可能とする?
                    279:        if (plane0base <= addr && addr < plane_end) {
                    280:                if ((int32)data >= 0) {
                    281:                        uint32 reladdr = addr - plane0base;
                    282:                        uint32 offset = reladdr % 0x40000;
                    283:                        // ROP の影響は受けずにメモリの内容を変更
                    284:                        mem[HLB(reladdr)] = data;
                    285:                        // この場合も画面を更新する
                    286:                        SetDirty(offset);
                    287:                }
1.1.1.5   root      288:                return true;
1.1.1.4   root      289:        }
1.1.1.5   root      290:        return false;
1.1.1.4   root      291: }
                    292: 
1.1       root      293: void
1.1.1.11! root      294: LunafbDevice::MonitorScreen(Monitor *, TextScreen& screen)
1.1       root      295: {
                    296:        int i;
                    297: 
                    298:        screen.Clear();
                    299: 
                    300:        // 0         1         2         3         4
                    301:        // 012345678901234567890123456789012345678901
                    302:        // RFCNT: $12345678 (X=-123dot, Y=1023dot)
                    303:        //
1.1.1.4   root      304:        //    BMSEL=$4 ROP  Mask
                    305:        // Plane#0 Sel THRU $ffffffff
                    306:        screen.Print(0, 0, "RFCNT: $%08x (X=%4ddot, Y=%4ddot)",
1.1.1.2   root      307:                rfcnt, xscroll, yscroll);
1.1.1.7   root      308:        screen.Print(2, 2, "BMSEL=$%02x ROP  Mask", bmsel);
1.1       root      309: 
                    310:        for (i = 0; i < nplane; i++) {
1.1.1.6   root      311:                screen.Print(0, 3 + i, "Plane#%u %s %s $%08x",
1.1       root      312:                        i,
1.1.1.10  root      313:                        (bmsel & (1U << i)) ? "Sel" : "---",
1.1.1.2   root      314:                        RopStr(fcset[i]), fcmask[i]);
1.1       root      315:        }
                    316:        for (; i < MAX_PLANES; i++) {
1.1.1.6   root      317:                screen.Print(0, 3 + i, TA::Disable, "Plane#%u (Not installed)", i);
1.1       root      318:        }
                    319: }
                    320: 
1.1.1.2   root      321: // offset の位置に対応する更新フラグを立てる。
1.1.1.4   root      322: // offset はプレーン先頭からのバイトオフセット。
1.1.1.2   root      323: inline void
                    324: LunafbDevice::SetDirty(uint32 offset)
                    325: {
1.1.1.4   root      326:        // VRAM は横 2048 ドット(256バイト) x 縦 1024 ドット。
1.1.1.2   root      327:        //
                    328:        //                1                               0
                    329:        //        4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
                    330:        //       +-----------+-------+-------+-------+-----+
                    331:        // VRAM  |  Y座標 (1024dot)  |  X (256byte)  : 8bit|
                    332:        //       +-----------+-------+-------+-------+-----+
1.1.1.4   root      333:        //       :                   :
                    334:        //       +-------------------+
                    335:        // Dirty |                   |
                    336:        //       +-------------------+
                    337:        //        9 8 7 6 5 4 3 2 1 0
                    338: 
                    339:        // 更新フラグはラスタ単位
1.1.1.6   root      340:        uint y = (offset >> 8);
1.1.1.7   root      341:        dirty.line[y] = true;
1.1.1.4   root      342: }
                    343: 
                    344: // X 方向にはみ出したときに対応する仮想画面の Y 座標を返す。
                    345: int
                    346: LunafbDevice::GetWrapY(int y) const
                    347: {
                    348:        // Lunafb の VRAM は、はみ出すと 256 ラスタ先のラスタの先頭から
                    349:        // 表示されるようだ。
                    350:        return (y + 256) % 1024;
1.1       root      351: }
                    352: 
                    353: // RFCNT への書き込み
                    354: void
                    355: LunafbDevice::WriteRFCNT(uint32 data)
                    356: {
                    357:        // レジスタ値
                    358:        rfcnt = data;
                    359: 
1.1.1.4   root      360:        // 水平オフセットを計算。
                    361:        // レジスタに設定できる値は 0..255 で、何ピクセル目から表示を開始するかを
                    362:        // 4 ピクセル単位で指定するもの。
                    363:        // ただし、実際に表示されるのは、(4ピクセル単位で) 設定値 +9 の位置から
                    364:        // (謎資料には 8 (というか -8) と書いてあるが実測は +9 のようだ)。
                    365:        // 設定値が 0 の時 X=36 ピクセル目から 1315 ピクセル目までを表示。
                    366:        // :
                    367:        // 設定値が 183 の時 X=768 ピクセル目から 2047 ピクセル目までを表示。
                    368:        // これが正常に表示できる範囲となる。
                    369:        // 184 以降を指定すると、右のはみ出る部分 (2048 ピクセル目以降に相当) は
                    370:        // 256 ラスタ先の X=0 からのデータが描画される (GetWrapY() 参照)。
                    371:        // 表示開始位置は設定値に必ず +9 (*4 [pixel]) されるため、X=0..35 の
                    372:        // ピクセルを (折り返しにより Y がずれた位置に見えることを除けば)
                    373:        // まともに表示する方法はない。まじかよ。
                    374:        xscroll = (rfcnt >> 16) & 0xff;
                    375:        xscroll = (xscroll + 9) * 4;
1.1       root      376: 
1.1.1.4   root      377:        // ラスタ(垂直)カウンタ。
                    378:        // XXX 26 は実際には CRTC2 によるパラメータ
1.1.1.2   root      379:        yscroll = (rfcnt + 26) & 0x3ff;
1.1       root      380: 
                    381:        // 全画面更新
                    382:        Invalidate();
                    383: 
1.1.1.3   root      384:        putlog(1, "RFCNT <- $%08x (H=%ddot, V=%ddot)", data, xscroll, yscroll);
1.1       root      385: }
                    386: 
                    387: // 共通ビットマッププレーン バイト書き込み
                    388: void
                    389: LunafbDevice::WriteCommonBitmap8(uint32 addr, uint32 data)
                    390: {
                    391:        uint32 offset = addr - 0xb1080000;
1.1.1.3   root      392:        putlog(2, "Common Plane $%08x <- $%02x", addr, data);
1.1       root      393:        for (int i = 0; i < nplane; i++) {
1.1.1.10  root      394:                if ((bmsel & (1U << i))) {
1.1       root      395:                        WritePlane8(i, offset, data);
                    396:                }
                    397:        }
1.1.1.2   root      398:        SetDirty(offset);
1.1       root      399: }
                    400: 
                    401: // 共通ビットマッププレーン ワード書き込み
                    402: void
                    403: LunafbDevice::WriteCommonBitmap16(uint32 addr, uint32 data)
                    404: {
                    405:        uint32 offset = addr - 0xb1080000;
1.1.1.3   root      406:        putlog(2, "Common Plane $%08x <- $%04x", addr, data);
1.1       root      407:        for (int i = 0; i < nplane; i++) {
1.1.1.10  root      408:                if ((bmsel & (1U << i))) {
1.1       root      409:                        WritePlane16(i, offset, data);
                    410:                }
                    411:        }
1.1.1.2   root      412:        SetDirty(offset);
1.1       root      413: }
                    414: 
                    415: // 共通ビットマッププレーン ロング書き込み
                    416: void
                    417: LunafbDevice::WriteCommonBitmap32(uint32 addr, uint32 data)
                    418: {
                    419:        uint32 offset = addr - 0xb1080000;
1.1.1.3   root      420:        putlog(2, "Common Plane $%08x <- $%08x", addr, data);
1.1       root      421:        for (int i = 0; i < nplane; i++) {
1.1.1.10  root      422:                if ((bmsel & (1U << i))) {
1.1       root      423:                        WritePlane32(i, offset, data);
                    424:                }
                    425:        }
1.1.1.2   root      426:        SetDirty(offset);
1.1       root      427: }
                    428: 
1.1.1.2   root      429: // 共通ファンクションセット設定
                    430: void
                    431: LunafbDevice::WriteCommonFCSet(uint rop, uint32 data)
                    432: {
                    433:        for (int i = 0; i < nplane; i++) {
1.1.1.10  root      434:                if ((bmsel & (1U << i))) {
1.1.1.2   root      435:                        fcset[i] = rop;
                    436:                        fcmask[i] = data;
                    437:                }
                    438:        }
                    439: }
                    440: 
                    441: // 現在の VRAM の値 vram と、書き込まれた値 data から
                    442: // 演算後 VRAM に書き戻すことになる値を返す。
                    443: // ここではマスクはまだ評価しない。
                    444: /*static*/ uint32
                    445: LunafbDevice::RasterOp(uint rop, uint32 vram, uint32 data)
1.1       root      446: {
                    447:        switch (rop) {
1.1.1.2   root      448:         case ROP::ZERO:
                    449:                vram = 0;
1.1       root      450:                break;
1.1.1.2   root      451:         case ROP::AND1:
                    452:                vram = vram & data;
1.1       root      453:                break;
1.1.1.2   root      454:         case ROP::AND2:
                    455:                vram = vram & ~data;
1.1       root      456:                break;
1.1.1.2   root      457:         case ROP::cmd:
1.1.1.4   root      458:         {
1.1.1.2   root      459:                // 使用不可。本当はここにシリアルモード変更コマンドがあるらしい。
                    460: 
                    461:                // ログを出すためにはインスタンスが必要だが、普段は static 関数で
                    462:                // 十分なので、ログを出す時だけグローバルインスタンスを参照する。
1.1.1.4   root      463:                auto planevram = GetPlaneVRAMDevice();
                    464:                if (planevram->loglevel >= 0) {
                    465:                        planevram->putlogn("ROP 3 is used");
1.1.1.2   root      466:                }
1.1       root      467:                break;
1.1.1.4   root      468:         }
1.1.1.2   root      469:         case ROP::AND3:
                    470:                vram = ~vram & data;
1.1       root      471:                break;
1.1.1.2   root      472:         case ROP::THRU:
                    473:                vram = data;
1.1       root      474:                break;
1.1.1.2   root      475:         case ROP::EOR:
                    476:                vram = vram ^ data;
1.1       root      477:                break;
1.1.1.2   root      478:         case ROP::OR1:
                    479:                vram = vram | data;
1.1       root      480:                break;
1.1.1.2   root      481:         case ROP::NOR:
                    482:                vram = ~vram & ~data;
1.1       root      483:                break;
1.1.1.2   root      484:         case ROP::ENOR:
                    485:                vram = (vram & data) | (~vram & ~data);
1.1       root      486:                break;
1.1.1.2   root      487:         case ROP::INV1:
                    488:                vram = ~data;
1.1       root      489:                break;
1.1.1.2   root      490:         case ROP::OR2:
                    491:                vram = vram | ~data;
1.1       root      492:                break;
1.1.1.2   root      493:         case ROP::INV2:
                    494:                vram = ~vram;
1.1       root      495:                break;
1.1.1.2   root      496:         case ROP::OR3:
                    497:                vram = ~vram | data;
1.1       root      498:                break;
1.1.1.2   root      499:         case ROP::NAND:
                    500:                vram = ~vram | ~data;
1.1       root      501:                break;
1.1.1.2   root      502:         case ROP::ONE:
                    503:                vram = 0xffffffff;
1.1       root      504:                break;
1.1.1.2   root      505:         default:
1.1.1.6   root      506:                VMPANIC("corrupted rop=%u", rop);
1.1       root      507:        }
1.1.1.2   root      508:        return vram;
1.1       root      509: }
                    510: 
                    511: // ROP 文字列を返す
                    512: const char *
                    513: LunafbDevice::RopStr(uint rop)
                    514: {
                    515:        static const char * ropstr[] = {
                    516:                "ZERO",
                    517:                "AND1",
                    518:                "AND2",
                    519:                "(3)",
                    520:                "AND3",
                    521:                "THRU", // THROUGH
                    522:                "EOR",
                    523:                "OR1",
                    524:                "NOR",
                    525:                "ENOR",
                    526:                "INV1",
                    527:                "OR2",
                    528:                "INV2",
                    529:                "OR3",
                    530:                "NAND",
                    531:                "ONE",
                    532:        };
                    533:        return ropstr[rop];
                    534: }
                    535: 
1.1.1.2   root      536: // 個別プレーンへのバイト書き込み
                    537: // (dirty は変更しない)
1.1       root      538: void
                    539: LunafbDevice::WritePlane8(uint plane, uint32 offset, uint32 data)
                    540: {
                    541:        uint32 memoffset = plane * 0x40000 + offset;
1.1.1.2   root      542:        uint32 vram;
                    543:        uint32 mask;
1.1       root      544: 
1.1.1.2   root      545:        vram = mem[HLB(memoffset)];
                    546:        data = RasterOp(fcset[plane], vram, data);
                    547:        mask = fcmask[plane] >> (24 - (memoffset & 3) * 8);
                    548:        mem[HLB(memoffset)] = (data & mask) | (vram & ~mask);
1.1       root      549: }
                    550: 
1.1.1.2   root      551: // 個別プレーンへのワード書き込み
                    552: // (dirty は変更しない)
1.1       root      553: void
                    554: LunafbDevice::WritePlane16(uint plane, uint32 offset, uint32 data)
                    555: {
                    556:        uint32 memoffset = plane * 0x40000 + offset;
1.1.1.2   root      557:        uint32 vram;
                    558:        uint32 mask;
1.1       root      559: 
1.1.1.2   root      560:        vram = *(uint16 *)&mem[HLW(memoffset)];
                    561:        data = RasterOp(fcset[plane], vram, data);
1.1       root      562:        if ((memoffset & 2) == 0) {
                    563:                // 上位ワード
1.1.1.2   root      564:                mask = fcmask[plane] >> 16;
1.1       root      565:        } else {
                    566:                // 下位ワード
1.1.1.2   root      567:                mask = fcmask[plane];
1.1       root      568:        }
1.1.1.2   root      569:        *(uint16 *)&mem[HLW(memoffset)] = (data & mask) | (vram & ~mask);
1.1       root      570: }
                    571: 
1.1.1.2   root      572: // 個別プレーンへのロングワード書き込み
                    573: // (dirty は変更しない)
1.1       root      574: void
                    575: LunafbDevice::WritePlane32(uint plane, uint32 offset, uint32 data)
                    576: {
                    577:        uint32 memoffset = plane * 0x40000 + offset;
1.1.1.2   root      578:        uint32 vram;
                    579:        uint32 mask;
1.1       root      580: 
1.1.1.2   root      581:        vram = *(uint32 *)&mem[memoffset];
                    582:        data = RasterOp(fcset[plane], vram, data);
                    583:        mask = fcmask[plane];
                    584:        *(uint32 *)&mem[memoffset] = (data & mask) | (vram & ~mask);
1.1       root      585: }
                    586: 
1.1.1.4   root      587: // (x, y) 位置のピクセル情報を screen に描画。(ビットマップモニタの情報欄)
                    588: void
                    589: LunafbDevice::UpdateInfo(TextScreen& screen, int x, int y) const
                    590: {
                    591:        screen.Clear();
                    592: 
                    593:        //0         1         2         3         4         5         6
                    594:        //012345678901234567890123456789012345678901234567890123456789012345
                    595:        //X=1024 Y=2024: (P0) $b10c0000: $00 (%00000000) ColorCode=$d
                    596: 
                    597:        screen.Puts(0, 0, "X=     Y=");
                    598:        for (int i = 0; i < nplane; i++) {
1.1.1.6   root      599:                screen.Print(15, i, "(P%u)", i);
1.1.1.4   root      600:        }
                    601: 
                    602:        // カーソルが範囲外ならここまで。
                    603:        if (x < 0) {
                    604:                return;
                    605:        }
                    606: 
                    607:        screen.Print(2, 0, "%4d Y=%4d", x, y);
                    608: 
                    609:        // 1プレーン内のバイトオフセット
                    610:        uint32 planeoffset = ((uint)y * 256) + ((uint)x / 8);
                    611: 
                    612:        uint cc = 0;
                    613:        for (int i = 0; i < nplane; i++) {
                    614:                // プレーン0先頭からのバイトオフセット
                    615:                uint32 totaloffset = 0x40000 * i + planeoffset;
                    616: 
                    617:                uint8 data = mem[HLB(totaloffset)];
1.1.1.6   root      618:                screen.Print(15, i, "(P%u) $%08x: $%02x (%%",
1.1.1.4   root      619:                        i, plane0base + totaloffset, data);
                    620: 
                    621:                // ビットパターン
                    622:                for (int m = 0x80; m != 0; m >>= 1) {
                    623:                        screen.Putc((data & m) ? '1' : '0');
                    624:                }
                    625:                screen.Putc(')');
                    626: 
                    627:                // カーソル位置をハイライト
                    628:                screen.Locate(37 + (x % 8), i);
                    629:                screen.SetAttr(TA::Em);
                    630: 
                    631:                // カラーコードを計算
                    632:                if ((data & (0x80U >> (x % 8))) != 0) {
                    633:                        cc |= (1U << i);
                    634:                }
                    635:        }
                    636: 
                    637:        screen.Print(47, 0, "ColorCode=$%x", cc);
                    638: }
                    639: 
1.1       root      640: 
                    641: // エミュレータによる画面出力
                    642: //
                    643: // VM 内からの操作ではなく、エミュレータ本体から画面を操作する
                    644: // エミュレーション ROM によるモニタコンソール用の機能。
1.1.1.2   root      645: // サービスを使いたい側 (EmuROM など) は EmuInitScreen() をコールすると
                    646: // (現在のパレットのまま) 画面をクリアする。
                    647: // 以降は EmuPutc() で文字を表示する。
1.1       root      648: 
1.1.1.2   root      649: // エミュレータ出力用に画面を初期化する
                    650: void
                    651: LunafbDevice::EmuInitScreen()
                    652: {
1.1       root      653:        // 同時書き込み設定
1.1.1.10  root      654:        bmsel = (1U << nplane) - 1;
1.1       root      655: 
1.1.1.2   root      656:        // ROP を初期化
                    657:        WriteCommonFCSet(ROP::THRU, 0xffffffff);
                    658: 
1.1       root      659:        // 全画面をクリア
1.1.1.2   root      660:        EmuFill(0, 0, 2048, 1024, 0);
1.1.1.4   root      661: 
                    662:        // 書き込みはプレーン#0 だけ。
                    663:        bmsel = 0x01;
1.1.1.2   root      664: }
                    665: 
                    666: // 矩形領域を data で埋める。
                    667: void
                    668: LunafbDevice::EmuFill(uint x, uint y, uint w, uint h, uint32 data)
                    669: {
                    670:        // ロングワードアラインしていないケースは対応しない
                    671:        assert(x % 32 == 0);
                    672:        assert(w % 32 == 0);
                    673: 
                    674:        for (uint py = y; py < y + h; py++) {
                    675:                uint32 addr = 0xb1080000 + (x / 32) * 4 + py * 256;
                    676:                for (uint px = x; px < x + w; px += 32) {
                    677:                        WriteCommonBitmap32(addr, data);
                    678:                        addr += 4;
                    679:                }
1.1       root      680:        }
                    681: }
                    682: 
1.1.1.2   root      683: // ピクセル座標 x, y を左上として文字 c を出力。
                    684: // 文字が VRAM からはみ出ないようにすること。
1.1       root      685: void
1.1.1.2   root      686: LunafbDevice::EmuPutc(uint x, uint y, uint c)
1.1       root      687: {
1.1.1.2   root      688:        EmuPutc(x, y, c, ROP::THRU);
                    689: }
                    690: 
                    691: // ピクセル座標 x, y を左上として文字 c を出力。
                    692: // 文字が VRAM からはみ出ないようにすること。
                    693: void
1.1.1.6   root      694: LunafbDevice::EmuPutc(uint x, uint y, uint c, uint rop)
1.1.1.2   root      695: {
                    696:        uint32 addr = 0xb1080000 + (x / 32) * 4 + y * 256;
                    697:        uint32 bofs = x % 32;
1.1.1.5   root      698:        int height = (c < 0x80) ? 24 : 12;
1.1.1.2   root      699: 
                    700:        // マスク設定。上から 12bit にマスクを置いといて..
                    701:        union64 mask {};
                    702:        mask.h = 0xfff00000;
                    703: 
                    704:        // うまい具合にシフト
                    705:        mask.q >>= bofs;
                    706: 
                    707:        // その文字のフォントデータ上でのアドレス
1.1.1.5   root      708:        const uint8 * const fontaddr = (c < 0x80)
                    709:                ? Builtin::CGROM12x24(c)
                    710:                : Builtin::CGROM12x12(c & 0x7f);
1.1.1.2   root      711: 
1.1.1.5   root      712:        for (int i = 0; i < height; i++) {
1.1.1.2   root      713:                // その文字のフォントデータ。
                    714:                // データは MSB 側 12bit に入っているのでこれを 64bit MSB 詰めにする
                    715:                union64 data {};
                    716:                data.h = be16toh(*(const uint16*)(fontaddr + i * 2)) << 16;
                    717: 
                    718:                // うまい具合にシフト
                    719:                data.q >>= bofs;
                    720: 
                    721:                WriteCommonFCSet(rop, mask.h);
                    722:                WriteCommonBitmap32(addr, data.h);
                    723:                if (mask.l) {
                    724:                        WriteCommonFCSet(rop, mask.l);
                    725:                        WriteCommonBitmap32(addr + 4, data.l);
                    726:                }
                    727:                addr += 256;    // 1ライン進める
1.1       root      728:        }
                    729: 
1.1.1.2   root      730:        // ROP を元に戻す
                    731:        WriteCommonFCSet(ROP::THRU, 0xffffffff);
1.1       root      732: }
                    733: 
1.1.1.2   root      734: // 画面を縦スクロールさせる。上スクロールのみサポート。
1.1       root      735: void
1.1.1.2   root      736: LunafbDevice::EmuScrollY(uint dy, uint sy, uint h)
1.1       root      737: {
1.1.1.2   root      738:        assert(dy < sy);
1.1       root      739: 
1.1.1.2   root      740:        uint32 da = dy * 256;
                    741:        uint32 sa = sy * 256;
                    742: 
                    743:        for (uint y = 0; y < h; y++) {
                    744:                for (int i = 0; i < nplane; i++) {
                    745:                        memcpy(&mem[da + i * 0x40000], &mem[sa + i * 0x40000], 160);
1.1       root      746:                }
1.1.1.2   root      747:                da += 256;
                    748:                sa += 256;
1.1       root      749:        }
1.1.1.2   root      750: 
                    751:        Invalidate();
1.1       root      752: }

unix.superglobalmegacorp.com

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