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

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

unix.superglobalmegacorp.com

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