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

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
                     13: // b100 |RF|        |BS|        |共 通 B M P|プレーン#0 |
                     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: //
                     27: // RF: RFCNT (4バイト)
                     28: // BS: BMSEL (4バイト)
                     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"
        !            41: #include "bt454.h"
        !            42: #include "cgrom.h"
        !            43: #include "config.h"
        !            44: #include "mpu.h"
1.1       root       45: 
1.1.1.2 ! root       46: // コンストラクタ
1.1       root       47: LunafbDevice::LunafbDevice()
1.1.1.2 ! root       48:        : inherited("Lunafb", 2048, 1024)
1.1       root       49: {
                     50:        devaddr = 0xb1000000;
                     51: 
1.1.1.2 ! root       52:        modify_mask = 0xffff;
        !            53: 
        !            54:        monitor.func = ToMonitorCallback(&LunafbDevice::MonitorUpdate);
1.1       root       55:        monitor.SetSize(42, 11);
1.1.1.2 ! root       56:        monitor.Regist(ID_MONITOR_LUNAVC);
1.1       root       57: }
                     58: 
1.1.1.2 ! root       59: // デストラクタ
1.1       root       60: LunafbDevice::~LunafbDevice()
                     61: {
                     62: }
                     63: 
1.1.1.2 ! root       64: // 初期化。
        !            65: //
        !            66: // 呼び出し順が際どいので注意。Lunafb::Init() と BT454::Init() とが相互に
        !            67: // 参照しているが、このうち Lunafb::Init() が呼んでる BT454::GetHostPalette()
        !            68: // は BT454::Init() 実行前でも取得できる。逆に BT454::Init() が呼んでる
        !            69: // Lunafb::GetPlaneCount() は Lunafb::Init() の後でないと行えないので、
        !            70: // vm_luna.cpp での初期化順は PlaneVRAM -> BT454 の順を維持すること。
1.1       root       71: bool
                     72: LunafbDevice::Init()
                     73: {
1.1.1.2 ! root       74:        const ConfigItem& item = gConfig->Find("luna-video-plane");
        !            75:        if (item.TryInt(&nplane) == false) {
        !            76:                item.Err();
        !            77:                return false;
        !            78:        }
        !            79:        if (nplane != 1 && nplane != 4) {
        !            80:                item.Err("must be 1 or 4");
        !            81:                return false;
        !            82:        }
        !            83: 
1.1       root       84:        plane_end = plane0base + 0x40000 * nplane;
                     85: 
                     86:        // プレーン数によってメモリを確保
                     87:        mem.reset(new uint8 [0x40000 * nplane]);
                     88: 
1.1.1.2 ! root       89:        // ホストパレットを取得。
        !            90:        palette = gBT454->GetHostPalette();
1.1       root       91: 
                     92:        return true;
                     93: }
                     94: 
1.1.1.2 ! root       95: // 電源オン/リセット
1.1       root       96: void
1.1.1.2 ! root       97: LunafbDevice::ResetHard(bool poweron)
1.1       root       98: {
1.1.1.2 ! root       99:        if (poweron) {
        !           100:                // XXX 実際は不定値だと思うけど、観測手段がないのでとりあえず。
        !           101:                memset(&mem[0], 0xff, 0x40000 * nplane);
        !           102:        }
        !           103: 
1.1       root      104:        // 厳密にどの時点でリセットされるのかは知らないけど
                    105:        bmsel = 0;
                    106: 
                    107:        // XXX 初期値の観測は困難なので適当
                    108:        rfcnt = 0;
1.1.1.2 ! root      109:        xscroll = 0;
        !           110:        yscroll = 0;
1.1       root      111: 
                    112:        for (int i = 0; i < MAX_PLANES; i++) {
1.1.1.2 ! root      113:                fcset[i] = 5;
        !           114:                fcmask[i] = 0xffffffff;
1.1       root      115:        }
                    116: 
                    117:        // XXX ここ?
                    118:        Invalidate();
                    119: }
                    120: 
                    121: uint64
                    122: LunafbDevice::Read8(uint32 addr)
                    123: {
                    124:        // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
                    125:        gMPU->AddCycle(1);
                    126: 
                    127:        if (plane0base <= addr && addr < plane_end) {
                    128:                // プレーンの読み出し
                    129:                return mem[HLB(addr - plane0base)];
                    130:        }
                    131:        // 残りは書き込み専用
                    132:        putlog(1, "%s: 未接続アドレス $%08x", __func__, addr);
                    133:        return 0xff;
                    134: }
                    135: 
                    136: uint64
                    137: LunafbDevice::Read16(uint32 addr)
                    138: {
                    139:        // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
                    140:        gMPU->AddCycle(1);
                    141: 
                    142:        if (plane0base <= addr && addr < plane_end) {
                    143:                // プレーンの読み出し
                    144:                return *(uint16 *)&mem[HLW(addr - plane0base)];
                    145:        }
                    146:        // 残りは書き込み専用
                    147:        putlog(1, "%s: 未接続アドレス $%08x", __func__, addr);
                    148:        return 0xffff;
                    149: }
                    150: 
                    151: uint64
                    152: LunafbDevice::Read32(uint32 addr)
                    153: {
                    154:        // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
                    155:        gMPU->AddCycle(1);
                    156: 
                    157:        if (plane0base <= addr && addr < plane_end) {
                    158:                // プレーンの読み出し
                    159:                return *(uint32 *)&mem[addr - plane0base];
                    160:        }
                    161:        // 残りは書き込み専用
                    162:        putlog(1, "%s: 未接続アドレス $%08x", __func__, addr);
                    163:        return 0xffffffff;
                    164: }
                    165: 
                    166: uint64
                    167: LunafbDevice::Write8(uint32 addr, uint32 data)
                    168: {
                    169:        // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
                    170:        gMPU->AddCycle(1);
                    171: 
                    172:        switch (addr) {
                    173:         case 0xb1000000:
                    174:         case 0xb1000001:
                    175:         case 0xb1000002:
                    176:         case 0xb1000003:
                    177:                // このロングワード内へのバイトアクセスはロングワードにミラーされる
                    178:                data = (data << 24) | (data << 16) | (data << 8) | data;
                    179:                return Write32(addr & ~3, data);
                    180:         case 0xb1040000:
                    181:         case 0xb1040001:
                    182:         case 0xb1040002:
                    183:         case 0xb1040003:
                    184:                // BMSEL はバイトアクセスできる?
                    185:                putlog(0, "未実装バイト書き込み $%08x <- $%02x", addr, data);
                    186:                return 0;
                    187:        }
                    188: 
                    189:        if (addr < 0xb1080000) {
                    190:                putlog(0, "未実装バイト書き込み $%08x <- $%02x", addr, data);
                    191:                return 0;
                    192:        }
                    193:        if (addr < plane0base) {
                    194:                // 共通ビットマッププレーン
                    195:                WriteCommonBitmap8(addr, data);
                    196:                return 0;
                    197:        }
                    198: 
                    199:        if (addr < plane7end) {
                    200:                // ビットマッププレーン
                    201:                uint32 reladdr = addr - plane0base;
                    202:                uint plane = reladdr / 0x40000;
                    203:                uint32 offset = reladdr % 0x40000;
                    204: 
                    205:                if (plane < nplane) {
                    206:                        // ビットマッププレーンN
                    207:                        putlog(2, "プレーン%d書き込み $%08x <- $%02x", plane, addr, data);
                    208:                        WritePlane8(plane, offset, data);
1.1.1.2 ! root      209:                        SetDirty(offset);
1.1       root      210:                        return 0;
                    211:                }
                    212:                // HW 設定によっては存在しないプレーンへの書き込み
                    213:                putlog(3, "不在プレーン%d書き込み $%08x <- $%02x",
                    214:                        plane, addr, data);
                    215:                return 0;
                    216:        }
                    217: 
                    218:        putlog(0, "未実装バイト書き込み $%08x <- $%02x", addr, data);
                    219:        return 0;
                    220: }
                    221: 
                    222: uint64
                    223: LunafbDevice::Write16(uint32 addr, uint32 data)
                    224: {
                    225:        // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
                    226:        gMPU->AddCycle(1);
                    227: 
                    228:        switch (addr) {
                    229:         case 0xb1000000:
                    230:         case 0xb1000002:
                    231:                // このロングワード内へのワードアクセスはロングワードにミラーされる
                    232:                data = (data << 16) | data;
                    233:                return Write32(addr & ~3, data);
                    234:         case 0xb1040000:
                    235:         case 0xb1040002:
                    236:                // BMSEL はワードアクセスできる?
                    237:                putlog(0, "未実装ワード書き込み $%08x <- $%04x", addr, data);
                    238:                return 0;
                    239:        }
                    240: 
                    241:        if (addr < 0xb1080000) {
                    242:                putlog(0, "未実装ワード書き込み $%08x <- $%04x", addr, data);
                    243:                return 0;
                    244:        }
                    245:        if (addr < plane0base) {
                    246:                // 共通ビットマッププレーン
                    247:                WriteCommonBitmap16(addr, data);
                    248:                return 0;
                    249:        }
                    250: 
                    251:        if (addr < plane7end) {
                    252:                // ビットマッププレーン
                    253:                uint32 reladdr = addr - plane0base;
                    254:                uint plane = reladdr / 0x40000;
                    255:                uint32 offset = reladdr % 0x40000;
                    256: 
                    257:                if (plane < nplane) {
                    258:                        // ビットマッププレーンN
                    259:                        putlog(2, "プレーン%d書き込み $%08x <- $%04x", plane, addr, data);
                    260:                        WritePlane16(plane, offset, data);
1.1.1.2 ! root      261:                        SetDirty(offset);
1.1       root      262:                        return 0;
                    263:                }
                    264:                // HW 設定によっては存在しないプレーンへの書き込み
                    265:                putlog(3, "不在プレーン%d書き込み $%08x <- $%04x",
                    266:                        plane, addr, data);
                    267:                return 0;
                    268:        }
                    269: 
                    270:        putlog(0, "未実装ワード書き込み $%08x <- $%04x", addr, data);
                    271:        return 0;
                    272: }
                    273: 
                    274: uint64
                    275: LunafbDevice::Write32(uint32 addr, uint32 data)
                    276: {
                    277:        // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
                    278:        gMPU->AddCycle(1);
                    279: 
                    280:        switch (addr) {
                    281:         case 0xb1000000:
                    282:                // RFCNT
                    283:                WriteRFCNT(data);
                    284:                return 0;
                    285: 
                    286:         case 0xb1040000:
                    287:                // BMSEL
                    288:                bmsel = data & 0xf;
                    289:                putlog(1, "BMSEL <- $%08x", data);
                    290:                return 0;
                    291:        }
                    292: 
                    293:        if (addr < 0xb1080000) {
                    294:                putlog(0, "未実装ロング書き込み $%08x <- $%08x", addr, data);
                    295:                return 0;
                    296:        }
                    297:        if (addr < plane0base) {
                    298:                // 共通ビットマッププレーン
                    299:                WriteCommonBitmap32(addr, data);
                    300:                return 0;
                    301:        }
                    302: 
                    303:        if (addr < plane7end) {
                    304:                // ビットマッププレーン
                    305:                uint32 reladdr = addr - plane0base;
                    306:                uint plane = reladdr / 0x40000;
                    307:                uint32 offset = reladdr % 0x40000;
                    308: 
                    309:                if (plane < nplane) {
                    310:                        // ビットマッププレーンN
                    311:                        putlog(3, "プレーン%d書き込み $%08x <- $%08x", plane, addr, data);
                    312:                        WritePlane32(plane, offset, data);
1.1.1.2 ! root      313:                        SetDirty(offset);
1.1       root      314:                        return 0;
                    315:                }
                    316:                // HW 設定によっては存在しないプレーンへの書き込み
                    317:                putlog(3, "不在プレーン%d書き込み $%08x <- $%08x",
                    318:                        plane, addr, data);
                    319:                return 0;
                    320:        }
                    321: 
                    322:        if (addr < 0xb1300000) {
                    323:                // 共通ファンクションセット
                    324:                uint rop = (addr & 0x3f) / 4;
                    325:                putlog(2, "共通FCSet 書き込み $%08x <- $%08x (%s)",
                    326:                        addr, data, RopStr(rop));
1.1.1.2 ! root      327:                WriteCommonFCSet(rop, data);
1.1       root      328:                return 0;
                    329:        }
                    330: 
                    331:        if (addr < fcset7end) {
                    332:                // ファンクションセット
                    333:                int plane = (addr - 0xb1300000) / 0x40000;
                    334: 
                    335:                if (plane < nplane) {
                    336:                        // ファンクションセットN
                    337:                        uint rop = (addr & 0x3f) / 4;
                    338:                        putlog(2, "FCSet%d書き込み $%08x <- $%08x (%s)",
                    339:                                plane, addr, data, RopStr(rop));
1.1.1.2 ! root      340:                        fcset[plane] = rop;
        !           341:                        fcmask[plane] = data;
1.1       root      342:                        return 0;
                    343:                }
                    344:                // HW 設定によっては存在しない FCSet への書き込み
                    345:                putlog(3, "不在FCSet%d書き込み $%08x <- $%08x",
                    346:                        plane, addr, data);
                    347:                return 0;
                    348:        }
                    349: 
                    350:        putlog(0, "未実装ロング書き込み $%08x <- $%08x", addr, data);
                    351:        return 0;
                    352: }
                    353: 
                    354: uint64
                    355: LunafbDevice::Peek8(uint32 addr)
                    356: {
                    357:        if (plane0base <= addr && addr < plane_end) {
                    358:                // プレーンの読み出し
                    359:                return mem[HLB(addr - plane0base)];
                    360:        }
                    361:        // 残りは書き込み専用
                    362:        return 0xff;
                    363: }
                    364: 
                    365: void
                    366: LunafbDevice::MonitorUpdate(Monitor *, TextScreen& screen)
                    367: {
                    368:        int i;
                    369: 
                    370:        screen.Clear();
                    371: 
                    372:        // 0         1         2         3         4
                    373:        // 012345678901234567890123456789012345678901
                    374:        // RFCNT: $12345678 (X=-123dot, Y=1023dot)
                    375:        //
                    376:        //    BMSEL=$4 ROP  Mask           RGB    RGB
                    377:        // Plane#0 Sel THRU $ffffffff   $0:RGB $8:RGB
                    378:        screen.Print(0, 0, "RFCNT: $%08x (X=%ddot, Y=%ddot)",
1.1.1.2 ! root      379:                rfcnt, xscroll, yscroll);
1.1       root      380:        screen.Print(3, 2, "BMSEL=$%x ROP  Mask", bmsel);
                    381: 
                    382:        for (i = 0; i < nplane; i++) {
                    383:                screen.Print(0, 3 + i, "Plane#%d %s %s $%08x",
                    384:                        i,
                    385:                        (bmsel & (1 << i)) ? "Sel" : "---",
1.1.1.2 ! root      386:                        RopStr(fcset[i]), fcmask[i]);
1.1       root      387:        }
                    388:        for (; i < MAX_PLANES; i++) {
                    389:                screen.Print(0, 3 + i, TA::Disable, "Plane#%d (Not installed)", i);
                    390:        }
                    391: 
                    392:        // ついでなのでここで BT454 のパレットも表示。
                    393:        // 012345
                    394:        // $0:RGB
                    395:        const uint8 *pal = gBT454->reg.color;
                    396:        screen.Puts(29, 1, "<BT454>");
                    397:        screen.Puts(32, 2, "RGB    RGB");
                    398:        for (i = 0; i < 16; i++) {
                    399:                uint rgb =
                    400:                        ((pal[i * 3 + 0] & 0xf0) << 4) +
                    401:                        ((pal[i * 3 + 1] & 0xf0)     ) +
                    402:                        ((pal[i * 3 + 2] & 0xf0) >> 4);
                    403:                screen.Print(29 + (i / 8) * 7, (i % 8) + 3, "$%x:%03x", i, rgb);
                    404:        }
                    405: }
                    406: 
1.1.1.2 ! root      407: // offset の位置に対応する更新フラグを立てる。
        !           408: // offset はプレーン先頭から (VRAM 先頭からでも同じ) のバイトオフセット。
        !           409: inline void
        !           410: LunafbDevice::SetDirty(uint32 offset)
        !           411: {
        !           412:        // VRAM は横 2048 ドット(256バイト) x 縦 1024 ドットで、これを
        !           413:        // 横 128 ドット(16バイト) x 縦 16 ドットずつのブロックに分割する。
        !           414:        // ブロック数は横 16個 x 縦 64個。
        !           415:        //
        !           416:        //                1                               0
        !           417:        //        4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
        !           418:        //       +-----------+-------+-------+-------+-----+
        !           419:        // VRAM  |  Y座標 (1024dot)  |  X (256byte)  : 8bit|
        !           420:        //       +-----------+-------+-------+-------+-----+
        !           421:        //       :           :       :       :             :
        !           422:        //       +-----------+-------+-------+-------------+
        !           423:        // Block | Y(64blks) | 16dot | X(16) |   128dot    | *: X は 16 blocks
        !           424:        //       +-----------+-------+-------+-------------+
        !           425:        //        \          \     |       |
        !           426:        //          \          \   |       |
        !           427:        //            \          \ |       |
        !           428:        //               +-----------+-------+
        !           429:        // Dirty         | Y(64blks) | X(16) |
        !           430:        //               +-----------+-------+
        !           431:        //                9 8 7 6 5 4 3 2 1 0
        !           432: 
        !           433:        // x 座標(バイト単位 8 bit)の上位 4 bit
        !           434:        int x = (offset >> 4) & 0x0f;
        !           435:        // y 座標(10bit) の上位 6 bit
        !           436:        int y = (offset >> 8) & 0x3f0;
        !           437: 
        !           438:        // からインデックスを求める
        !           439:        int b = x + y;
        !           440: 
        !           441:        dirty[b] = 1;
        !           442: 
        !           443: #if defined(PERF_HIT)
        !           444:        // どのロングワードが更新されたか
        !           445:        dirty_word[offset >> 2] = true;
        !           446: #endif
1.1       root      447: }
                    448: 
                    449: // RFCNT への書き込み
                    450: void
                    451: LunafbDevice::WriteRFCNT(uint32 data)
                    452: {
                    453:        // レジスタ値
                    454:        rfcnt = data;
                    455: 
                    456:        // 水平オフセットを計算
                    457:        // XXX マニュアルでは -8 まで指定できるように読めるが
                    458:        //     指定する方法が分からない。
                    459:        // XXX 193 以上を指定するとどうなるのか (とりあえずほっとく)
                    460:        //     実機の挙動を目分量で見ると、右にはみ出た部分は
                    461:        //     256 ラスタ先のラスタデータを描画しているようだ。
1.1.1.2 ! root      462:        xscroll = ((rfcnt >> 16) & 0xff) + 8;
        !           463:        xscroll *= 4;
1.1       root      464: 
                    465:        // ラスタ(垂直)カウンタ
1.1.1.2 ! root      466:        yscroll = (rfcnt + 26) & 0x3ff;
1.1       root      467: 
                    468:        // 全画面更新
                    469:        Invalidate();
                    470: 
                    471:        putlog(1, "RFCNT <- $%08x (水平 %ddot, 垂直 %ddot)",
1.1.1.2 ! root      472:                data, xscroll, yscroll);
1.1       root      473: }
                    474: 
                    475: // 共通ビットマッププレーン バイト書き込み
                    476: void
                    477: LunafbDevice::WriteCommonBitmap8(uint32 addr, uint32 data)
                    478: {
                    479:        uint32 offset = addr - 0xb1080000;
                    480:        putlog(2, "共通プレーン書き込み $%08x <- $%02x", addr, data);
                    481:        for (int i = 0; i < nplane; i++) {
                    482:                if ((bmsel & (1 << i))) {
                    483:                        WritePlane8(i, offset, data);
                    484:                }
                    485:        }
1.1.1.2 ! root      486:        SetDirty(offset);
1.1       root      487: }
                    488: 
                    489: // 共通ビットマッププレーン ワード書き込み
                    490: void
                    491: LunafbDevice::WriteCommonBitmap16(uint32 addr, uint32 data)
                    492: {
                    493:        uint32 offset = addr - 0xb1080000;
                    494:        putlog(2, "共通プレーン書き込み $%08x <- $%04x", addr, data);
                    495:        for (int i = 0; i < nplane; i++) {
                    496:                if ((bmsel & (1 << i))) {
                    497:                        WritePlane16(i, offset, data);
                    498:                }
                    499:        }
1.1.1.2 ! root      500:        SetDirty(offset);
1.1       root      501: }
                    502: 
                    503: // 共通ビットマッププレーン ロング書き込み
                    504: void
                    505: LunafbDevice::WriteCommonBitmap32(uint32 addr, uint32 data)
                    506: {
                    507:        uint32 offset = addr - 0xb1080000;
                    508:        putlog(2, "共通プレーン書き込み $%08x <- $%08x", addr, data);
                    509:        for (int i = 0; i < nplane; i++) {
                    510:                if ((bmsel & (1 << i))) {
                    511:                        WritePlane32(i, offset, data);
                    512:                }
                    513:        }
1.1.1.2 ! root      514:        SetDirty(offset);
1.1       root      515: }
                    516: 
1.1.1.2 ! root      517: // 共通ファンクションセット設定
        !           518: void
        !           519: LunafbDevice::WriteCommonFCSet(uint rop, uint32 data)
        !           520: {
        !           521:        for (int i = 0; i < nplane; i++) {
        !           522:                if ((bmsel & (1 << i))) {
        !           523:                        fcset[i] = rop;
        !           524:                        fcmask[i] = data;
        !           525:                }
        !           526:        }
        !           527: }
        !           528: 
        !           529: // 現在の VRAM の値 vram と、書き込まれた値 data から
        !           530: // 演算後 VRAM に書き戻すことになる値を返す。
        !           531: // ここではマスクはまだ評価しない。
        !           532: /*static*/ uint32
        !           533: LunafbDevice::RasterOp(uint rop, uint32 vram, uint32 data)
1.1       root      534: {
                    535:        switch (rop) {
1.1.1.2 ! root      536:         case ROP::ZERO:
        !           537:                vram = 0;
1.1       root      538:                break;
1.1.1.2 ! root      539:         case ROP::AND1:
        !           540:                vram = vram & data;
1.1       root      541:                break;
1.1.1.2 ! root      542:         case ROP::AND2:
        !           543:                vram = vram & ~data;
1.1       root      544:                break;
1.1.1.2 ! root      545:         case ROP::cmd:
        !           546:                // 使用不可。本当はここにシリアルモード変更コマンドがあるらしい。
        !           547: 
        !           548:                // ログを出すためにはインスタンスが必要だが、普段は static 関数で
        !           549:                // 十分なので、ログを出す時だけグローバルインスタンスを参照する。
        !           550:                if (gPlaneVRAM->loglevel >= 0) {
        !           551:                        gPlaneVRAM->putlogn("ROP 3 is used");
        !           552:                }
1.1       root      553:                break;
1.1.1.2 ! root      554:         case ROP::AND3:
        !           555:                vram = ~vram & data;
1.1       root      556:                break;
1.1.1.2 ! root      557:         case ROP::THRU:
        !           558:                vram = data;
1.1       root      559:                break;
1.1.1.2 ! root      560:         case ROP::EOR:
        !           561:                vram = vram ^ data;
1.1       root      562:                break;
1.1.1.2 ! root      563:         case ROP::OR1:
        !           564:                vram = vram | data;
1.1       root      565:                break;
1.1.1.2 ! root      566:         case ROP::NOR:
        !           567:                vram = ~vram & ~data;
1.1       root      568:                break;
1.1.1.2 ! root      569:         case ROP::ENOR:
        !           570:                vram = (vram & data) | (~vram & ~data);
1.1       root      571:                break;
1.1.1.2 ! root      572:         case ROP::INV1:
        !           573:                vram = ~data;
1.1       root      574:                break;
1.1.1.2 ! root      575:         case ROP::OR2:
        !           576:                vram = vram | ~data;
1.1       root      577:                break;
1.1.1.2 ! root      578:         case ROP::INV2:
        !           579:                vram = ~vram;
1.1       root      580:                break;
1.1.1.2 ! root      581:         case ROP::OR3:
        !           582:                vram = ~vram | data;
1.1       root      583:                break;
1.1.1.2 ! root      584:         case ROP::NAND:
        !           585:                vram = ~vram | ~data;
1.1       root      586:                break;
1.1.1.2 ! root      587:         case ROP::ONE:
        !           588:                vram = 0xffffffff;
1.1       root      589:                break;
1.1.1.2 ! root      590:         default:
        !           591:                __unreachable();
1.1       root      592:        }
1.1.1.2 ! root      593:        return vram;
1.1       root      594: }
                    595: 
                    596: // ROP 文字列を返す
                    597: const char *
                    598: LunafbDevice::RopStr(uint rop)
                    599: {
                    600:        static const char * ropstr[] = {
                    601:                "ZERO",
                    602:                "AND1",
                    603:                "AND2",
                    604:                "(3)",
                    605:                "AND3",
                    606:                "THRU", // THROUGH
                    607:                "EOR",
                    608:                "OR1",
                    609:                "NOR",
                    610:                "ENOR",
                    611:                "INV1",
                    612:                "OR2",
                    613:                "INV2",
                    614:                "OR3",
                    615:                "NAND",
                    616:                "ONE",
                    617:        };
                    618:        return ropstr[rop];
                    619: }
                    620: 
1.1.1.2 ! root      621: // 個別プレーンへのバイト書き込み
        !           622: // (dirty は変更しない)
1.1       root      623: void
                    624: LunafbDevice::WritePlane8(uint plane, uint32 offset, uint32 data)
                    625: {
                    626:        uint32 memoffset = plane * 0x40000 + offset;
1.1.1.2 ! root      627:        uint32 vram;
        !           628:        uint32 mask;
1.1       root      629: 
1.1.1.2 ! root      630:        vram = mem[HLB(memoffset)];
        !           631:        data = RasterOp(fcset[plane], vram, data);
        !           632:        mask = fcmask[plane] >> (24 - (memoffset & 3) * 8);
        !           633:        mem[HLB(memoffset)] = (data & mask) | (vram & ~mask);
1.1       root      634: }
                    635: 
1.1.1.2 ! root      636: // 個別プレーンへのワード書き込み
        !           637: // (dirty は変更しない)
1.1       root      638: void
                    639: LunafbDevice::WritePlane16(uint plane, uint32 offset, uint32 data)
                    640: {
                    641:        uint32 memoffset = plane * 0x40000 + offset;
1.1.1.2 ! root      642:        uint32 vram;
        !           643:        uint32 mask;
1.1       root      644: 
1.1.1.2 ! root      645:        vram = *(uint16 *)&mem[HLW(memoffset)];
        !           646:        data = RasterOp(fcset[plane], vram, data);
1.1       root      647:        if ((memoffset & 2) == 0) {
                    648:                // 上位ワード
1.1.1.2 ! root      649:                mask = fcmask[plane] >> 16;
1.1       root      650:        } else {
                    651:                // 下位ワード
1.1.1.2 ! root      652:                mask = fcmask[plane];
1.1       root      653:        }
1.1.1.2 ! root      654:        *(uint16 *)&mem[HLW(memoffset)] = (data & mask) | (vram & ~mask);
1.1       root      655: }
                    656: 
1.1.1.2 ! root      657: // 個別プレーンへのロングワード書き込み
        !           658: // (dirty は変更しない)
1.1       root      659: void
                    660: LunafbDevice::WritePlane32(uint plane, uint32 offset, uint32 data)
                    661: {
                    662:        uint32 memoffset = plane * 0x40000 + offset;
1.1.1.2 ! root      663:        uint32 vram;
        !           664:        uint32 mask;
1.1       root      665: 
1.1.1.2 ! root      666:        vram = *(uint32 *)&mem[memoffset];
        !           667:        data = RasterOp(fcset[plane], vram, data);
        !           668:        mask = fcmask[plane];
        !           669:        *(uint32 *)&mem[memoffset] = (data & mask) | (vram & ~mask);
1.1       root      670: }
                    671: 
                    672: 
                    673: // エミュレータによる画面出力
                    674: //
                    675: // VM 内からの操作ではなく、エミュレータ本体から画面を操作する
                    676: // エミュレーション ROM によるモニタコンソール用の機能。
1.1.1.2 ! root      677: // サービスを使いたい側 (EmuROM など) は EmuInitScreen() をコールすると
        !           678: // (現在のパレットのまま) 画面をクリアする。
        !           679: // 以降は EmuPutc() で文字を表示する。
1.1       root      680: 
1.1.1.2 ! root      681: // エミュレータ出力用に画面を初期化する
        !           682: void
        !           683: LunafbDevice::EmuInitScreen()
        !           684: {
1.1       root      685:        // 同時書き込み設定
                    686:        bmsel = (1 << nplane) - 1;
                    687: 
1.1.1.2 ! root      688:        // ROP を初期化
        !           689:        WriteCommonFCSet(ROP::THRU, 0xffffffff);
        !           690: 
1.1       root      691:        // 全画面をクリア
1.1.1.2 ! root      692:        EmuFill(0, 0, 2048, 1024, 0);
        !           693: }
        !           694: 
        !           695: // 矩形領域を data で埋める。
        !           696: void
        !           697: LunafbDevice::EmuFill(uint x, uint y, uint w, uint h, uint32 data)
        !           698: {
        !           699:        // ロングワードアラインしていないケースは対応しない
        !           700:        assert(x % 32 == 0);
        !           701:        assert(w % 32 == 0);
        !           702: 
        !           703:        for (uint py = y; py < y + h; py++) {
        !           704:                uint32 addr = 0xb1080000 + (x / 32) * 4 + py * 256;
        !           705:                for (uint px = x; px < x + w; px += 32) {
        !           706:                        WriteCommonBitmap32(addr, data);
        !           707:                        addr += 4;
        !           708:                }
1.1       root      709:        }
                    710: }
                    711: 
1.1.1.2 ! root      712: // ピクセル座標 x, y を左上として文字 c を出力。
        !           713: // 文字が VRAM からはみ出ないようにすること。
1.1       root      714: void
1.1.1.2 ! root      715: LunafbDevice::EmuPutc(uint x, uint y, uint c)
1.1       root      716: {
1.1.1.2 ! root      717:        EmuPutc(x, y, c, ROP::THRU);
        !           718: }
        !           719: 
        !           720: // ピクセル座標 x, y を左上として文字 c を出力。
        !           721: // 文字が VRAM からはみ出ないようにすること。
        !           722: void
        !           723: LunafbDevice::EmuPutc(uint x, uint y, uint c, int rop)
        !           724: {
        !           725:        uint32 addr = 0xb1080000 + (x / 32) * 4 + y * 256;
        !           726:        uint32 bofs = x % 32;
        !           727: 
        !           728:        // マスク設定。上から 12bit にマスクを置いといて..
        !           729:        union64 mask {};
        !           730:        mask.h = 0xfff00000;
        !           731: 
        !           732:        // うまい具合にシフト
        !           733:        mask.q >>= bofs;
        !           734: 
        !           735:        // その文字のフォントデータ上でのアドレス
        !           736:        const uint8 * const fontaddr = BuiltinCGROM::Get12x24(c & 0xff);
        !           737: 
        !           738:        for (int i = 0; i < 24; i++) {
        !           739:                // その文字のフォントデータ。
        !           740:                // データは MSB 側 12bit に入っているのでこれを 64bit MSB 詰めにする
        !           741:                union64 data {};
        !           742:                data.h = be16toh(*(const uint16*)(fontaddr + i * 2)) << 16;
        !           743: 
        !           744:                // うまい具合にシフト
        !           745:                data.q >>= bofs;
        !           746: 
        !           747:                WriteCommonFCSet(rop, mask.h);
        !           748:                WriteCommonBitmap32(addr, data.h);
        !           749:                if (mask.l) {
        !           750:                        WriteCommonFCSet(rop, mask.l);
        !           751:                        WriteCommonBitmap32(addr + 4, data.l);
        !           752:                }
        !           753:                addr += 256;    // 1ライン進める
1.1       root      754:        }
                    755: 
1.1.1.2 ! root      756:        // ROP を元に戻す
        !           757:        WriteCommonFCSet(ROP::THRU, 0xffffffff);
1.1       root      758: }
                    759: 
1.1.1.2 ! root      760: // 画面を縦スクロールさせる。上スクロールのみサポート。
1.1       root      761: void
1.1.1.2 ! root      762: LunafbDevice::EmuScrollY(uint dy, uint sy, uint h)
1.1       root      763: {
1.1.1.2 ! root      764:        assert(dy < sy);
1.1       root      765: 
1.1.1.2 ! root      766:        uint32 da = dy * 256;
        !           767:        uint32 sa = sy * 256;
        !           768: 
        !           769:        for (uint y = 0; y < h; y++) {
        !           770:                for (int i = 0; i < nplane; i++) {
        !           771:                        memcpy(&mem[da + i * 0x40000], &mem[sa + i * 0x40000], 160);
1.1       root      772:                }
1.1.1.2 ! root      773:                da += 256;
        !           774:                sa += 256;
1.1       root      775:        }
1.1.1.2 ! root      776: 
        !           777:        Invalidate();
1.1       root      778: }

unix.superglobalmegacorp.com

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