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

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: #include "lunafb.h"
                      8: #include "bt454.h"
                      9: #include "cgrom.h"
                     10: #include "mpu.h"
                     11: 
                     12: //
                     13: // ビットマッププレーン
                     14: //
                     15: // Lunafb の VRAM はロングワード単位でホストバイトオーダ配置なので、
                     16: // バイトアクセス、ワードアクセス時は HLB(), HLW() マクロを使用のこと。
                     17: //
                     18: 
                     19: // SX-9100 のほうはこう書いてあってこっちが正しいようだ。
                     20: //      +00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
                     21: // b100 |RF|        |BS|        |共 通 B M P|プレーン#0 |
                     22: // b110 |プレーン#1 |プレーン#2 |プレーン#3 |プレーン#4 |
                     23: // b120 |プレーン#5 |プレーン#6 |プレーン#7 |FC|        |
                     24: // b130 |F0|        |F1|        |F2|        |F3|        |
                     25: // b140 |F4|        |F5|        |F6|        |F7|        |
                     26: //
                     27: // SX-7100 のほうはこう書いてあるがこうはなっていないようだ。
                     28: //      +00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
                     29: // b100 |RF|        |BS|        |共 通 B M P|FC|        |
                     30: // b110 |プレーン#0 |プレーン#1 |プレーン#2 |プレーン#3 |
                     31: // b120 |プレーン#4 |プレーン#5 |プレーン#6 |プレーン#7 |
                     32: // b130 |F0|        |F1|        |F2|        |F3|        |
                     33: // b140 |F4|        |F5|        |F6|        |F7|        |
                     34: //
                     35: // RF: RFCNT (4バイト)
                     36: // BS: BMSEL (4バイト)
                     37: // FC: 共通ファンクションセット
                     38: // Fn: プレーン#n ファンクションセット
                     39: // 1区画が 64KB。空白のところは未調査。
                     40: // 未装着のプレーン(#4..#7とか)は 0xff が読めるようだ。
                     41: // ファンクションセットが 64バイトで折り返してるか未調査だが、
                     42: // b130'0000 も b133'0000 も 0xff が読めるのでこの範囲全域でミラーかも。
                     43: // b150'0000 以降(b1ff'ffffまで) は BUSERR のようだ。
                     44: //
                     45: 
                     46: std::unique_ptr<LunafbDevice> gLunafb;
                     47: 
                     48: LunafbDevice::LunafbDevice()
                     49:        : inherited("Lunafb")
                     50: {
                     51:        devaddr = 0xb1000000;
                     52: 
                     53:        monitor.func = (MonitorCallback_t)&LunafbDevice::MonitorUpdate;
                     54:        monitor.SetSize(42, 11);
                     55:        monitor.Regist(ID_MONITOR_LUNAFB);
                     56: }
                     57: 
                     58: LunafbDevice::~LunafbDevice()
                     59: {
                     60: }
                     61: 
                     62: bool
                     63: LunafbDevice::Init()
                     64: {
                     65:        // XXX とりあえず。実際は設定による
                     66:        nplane = 1;
                     67:        plane_end = plane0base + 0x40000 * nplane;
                     68: 
                     69:        // プレーン数によってメモリを確保
                     70:        mem.reset(new uint8 [0x40000 * nplane]);
                     71: 
                     72:        return true;
                     73: }
                     74: 
                     75: bool
                     76: LunafbDevice::PowerOn()
                     77: {
                     78:        // XXX 実際は不定値だと思うけど、観測手段がないのでとりあえず。
                     79:        memset(&mem[0], 0xff, 0x40000 * nplane);
                     80:        return true;
                     81: }
                     82: 
                     83: void
                     84: LunafbDevice::ResetHard()
                     85: {
                     86:        // 厳密にどの時点でリセットされるのかは知らないけど
                     87:        bmsel = 0;
                     88: 
                     89:        // XXX 初期値の観測は困難なので適当
                     90:        rfcnt = 0;
                     91:        hscroll = 0;
                     92:        vscroll = 0;
                     93: 
                     94:        for (int i = 0; i < MAX_PLANES; i++) {
                     95:                fcs[i] = 5;
                     96:                mask[i] = 0xffffffff;
                     97:        }
                     98: 
                     99:        // XXX ここ?
                    100:        Invalidate();
                    101: }
                    102: 
                    103: uint64
                    104: LunafbDevice::Read8(uint32 addr)
                    105: {
                    106:        // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
                    107:        gMPU->AddCycle(1);
                    108: 
                    109:        if (plane0base <= addr && addr < plane_end) {
                    110:                // プレーンの読み出し
                    111:                return mem[HLB(addr - plane0base)];
                    112:        }
                    113:        // 残りは書き込み専用
                    114:        putlog(1, "%s: 未接続アドレス $%08x", __func__, addr);
                    115:        return 0xff;
                    116: }
                    117: 
                    118: uint64
                    119: LunafbDevice::Read16(uint32 addr)
                    120: {
                    121:        // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
                    122:        gMPU->AddCycle(1);
                    123: 
                    124:        if (plane0base <= addr && addr < plane_end) {
                    125:                // プレーンの読み出し
                    126:                return *(uint16 *)&mem[HLW(addr - plane0base)];
                    127:        }
                    128:        // 残りは書き込み専用
                    129:        putlog(1, "%s: 未接続アドレス $%08x", __func__, addr);
                    130:        return 0xffff;
                    131: }
                    132: 
                    133: uint64
                    134: LunafbDevice::Read32(uint32 addr)
                    135: {
                    136:        // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
                    137:        gMPU->AddCycle(1);
                    138: 
                    139:        if (plane0base <= addr && addr < plane_end) {
                    140:                // プレーンの読み出し
                    141:                return *(uint32 *)&mem[addr - plane0base];
                    142:        }
                    143:        // 残りは書き込み専用
                    144:        putlog(1, "%s: 未接続アドレス $%08x", __func__, addr);
                    145:        return 0xffffffff;
                    146: }
                    147: 
                    148: uint64
                    149: LunafbDevice::Write8(uint32 addr, uint32 data)
                    150: {
                    151:        // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
                    152:        gMPU->AddCycle(1);
                    153: 
                    154:        switch (addr) {
                    155:         case 0xb1000000:
                    156:         case 0xb1000001:
                    157:         case 0xb1000002:
                    158:         case 0xb1000003:
                    159:                // このロングワード内へのバイトアクセスはロングワードにミラーされる
                    160:                data = (data << 24) | (data << 16) | (data << 8) | data;
                    161:                return Write32(addr & ~3, data);
                    162:         case 0xb1040000:
                    163:         case 0xb1040001:
                    164:         case 0xb1040002:
                    165:         case 0xb1040003:
                    166:                // BMSEL はバイトアクセスできる?
                    167:                putlog(0, "未実装バイト書き込み $%08x <- $%02x", addr, data);
                    168:                return 0;
                    169:        }
                    170: 
                    171:        if (addr < 0xb1080000) {
                    172:                putlog(0, "未実装バイト書き込み $%08x <- $%02x", addr, data);
                    173:                return 0;
                    174:        }
                    175:        if (addr < plane0base) {
                    176:                // 共通ビットマッププレーン
                    177:                WriteCommonBitmap8(addr, data);
                    178:                return 0;
                    179:        }
                    180: 
                    181:        if (addr < plane7end) {
                    182:                // ビットマッププレーン
                    183:                uint32 reladdr = addr - plane0base;
                    184:                uint plane = reladdr / 0x40000;
                    185:                uint32 offset = reladdr % 0x40000;
                    186: 
                    187:                if (plane < nplane) {
                    188:                        // ビットマッププレーンN
                    189:                        putlog(2, "プレーン%d書き込み $%08x <- $%02x", plane, addr, data);
                    190:                        WritePlane8(plane, offset, data);
                    191:                        return 0;
                    192:                }
                    193:                // HW 設定によっては存在しないプレーンへの書き込み
                    194:                putlog(3, "不在プレーン%d書き込み $%08x <- $%02x",
                    195:                        plane, addr, data);
                    196:                return 0;
                    197:        }
                    198: 
                    199:        putlog(0, "未実装バイト書き込み $%08x <- $%02x", addr, data);
                    200:        return 0;
                    201: }
                    202: 
                    203: uint64
                    204: LunafbDevice::Write16(uint32 addr, uint32 data)
                    205: {
                    206:        // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
                    207:        gMPU->AddCycle(1);
                    208: 
                    209:        switch (addr) {
                    210:         case 0xb1000000:
                    211:         case 0xb1000002:
                    212:                // このロングワード内へのワードアクセスはロングワードにミラーされる
                    213:                data = (data << 16) | data;
                    214:                return Write32(addr & ~3, data);
                    215:         case 0xb1040000:
                    216:         case 0xb1040002:
                    217:                // BMSEL はワードアクセスできる?
                    218:                putlog(0, "未実装ワード書き込み $%08x <- $%04x", addr, data);
                    219:                return 0;
                    220:        }
                    221: 
                    222:        if (addr < 0xb1080000) {
                    223:                putlog(0, "未実装ワード書き込み $%08x <- $%04x", addr, data);
                    224:                return 0;
                    225:        }
                    226:        if (addr < plane0base) {
                    227:                // 共通ビットマッププレーン
                    228:                WriteCommonBitmap16(addr, data);
                    229:                return 0;
                    230:        }
                    231: 
                    232:        if (addr < plane7end) {
                    233:                // ビットマッププレーン
                    234:                uint32 reladdr = addr - plane0base;
                    235:                uint plane = reladdr / 0x40000;
                    236:                uint32 offset = reladdr % 0x40000;
                    237: 
                    238:                if (plane < nplane) {
                    239:                        // ビットマッププレーンN
                    240:                        putlog(2, "プレーン%d書き込み $%08x <- $%04x", plane, addr, data);
                    241:                        WritePlane16(plane, offset, data);
                    242:                        return 0;
                    243:                }
                    244:                // HW 設定によっては存在しないプレーンへの書き込み
                    245:                putlog(3, "不在プレーン%d書き込み $%08x <- $%04x",
                    246:                        plane, addr, data);
                    247:                return 0;
                    248:        }
                    249: 
                    250:        putlog(0, "未実装ワード書き込み $%08x <- $%04x", addr, data);
                    251:        return 0;
                    252: }
                    253: 
                    254: uint64
                    255: LunafbDevice::Write32(uint32 addr, uint32 data)
                    256: {
                    257:        // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
                    258:        gMPU->AddCycle(1);
                    259: 
                    260:        switch (addr) {
                    261:         case 0xb1000000:
                    262:                // RFCNT
                    263:                WriteRFCNT(data);
                    264:                return 0;
                    265: 
                    266:         case 0xb1040000:
                    267:                // BMSEL
                    268:                bmsel = data & 0xf;
                    269:                putlog(1, "BMSEL <- $%08x", data);
                    270:                return 0;
                    271:        }
                    272: 
                    273:        if (addr < 0xb1080000) {
                    274:                putlog(0, "未実装ロング書き込み $%08x <- $%08x", addr, data);
                    275:                return 0;
                    276:        }
                    277:        if (addr < plane0base) {
                    278:                // 共通ビットマッププレーン
                    279:                WriteCommonBitmap32(addr, data);
                    280:                return 0;
                    281:        }
                    282: 
                    283:        if (addr < plane7end) {
                    284:                // ビットマッププレーン
                    285:                uint32 reladdr = addr - plane0base;
                    286:                uint plane = reladdr / 0x40000;
                    287:                uint32 offset = reladdr % 0x40000;
                    288: 
                    289:                if (plane < nplane) {
                    290:                        // ビットマッププレーンN
                    291:                        putlog(3, "プレーン%d書き込み $%08x <- $%08x", plane, addr, data);
                    292:                        WritePlane32(plane, offset, data);
                    293:                        return 0;
                    294:                }
                    295:                // HW 設定によっては存在しないプレーンへの書き込み
                    296:                putlog(3, "不在プレーン%d書き込み $%08x <- $%08x",
                    297:                        plane, addr, data);
                    298:                return 0;
                    299:        }
                    300: 
                    301:        if (addr < 0xb1300000) {
                    302:                // 共通ファンクションセット
                    303:                uint rop = (addr & 0x3f) / 4;
                    304:                putlog(2, "共通FCSet 書き込み $%08x <- $%08x (%s)",
                    305:                        addr, data, RopStr(rop));
                    306:                for (int i = 0; i < nplane; i++) {
                    307:                        if ((bmsel & (1 << i))) {
                    308:                                fcs[i] = rop;
                    309:                                mask[i] = data;
                    310:                        }
                    311:                }
                    312:                return 0;
                    313:        }
                    314: 
                    315:        if (addr < fcset7end) {
                    316:                // ファンクションセット
                    317:                int plane = (addr - 0xb1300000) / 0x40000;
                    318: 
                    319:                if (plane < nplane) {
                    320:                        // ファンクションセットN
                    321:                        uint rop = (addr & 0x3f) / 4;
                    322:                        putlog(2, "FCSet%d書き込み $%08x <- $%08x (%s)",
                    323:                                plane, addr, data, RopStr(rop));
                    324:                        fcs[plane] = rop;
                    325:                        mask[plane] = data;
                    326:                        return 0;
                    327:                }
                    328:                // HW 設定によっては存在しない FCSet への書き込み
                    329:                putlog(3, "不在FCSet%d書き込み $%08x <- $%08x",
                    330:                        plane, addr, data);
                    331:                return 0;
                    332:        }
                    333: 
                    334:        putlog(0, "未実装ロング書き込み $%08x <- $%08x", addr, data);
                    335:        return 0;
                    336: }
                    337: 
                    338: uint64
                    339: LunafbDevice::Peek8(uint32 addr)
                    340: {
                    341:        if (plane0base <= addr && addr < plane_end) {
                    342:                // プレーンの読み出し
                    343:                return mem[HLB(addr - plane0base)];
                    344:        }
                    345:        // 残りは書き込み専用
                    346:        return 0xff;
                    347: }
                    348: 
                    349: void
                    350: LunafbDevice::MonitorUpdate(Monitor *, TextScreen& screen)
                    351: {
                    352:        int i;
                    353: 
                    354:        screen.Clear();
                    355: 
                    356:        // 0         1         2         3         4
                    357:        // 012345678901234567890123456789012345678901
                    358:        // RFCNT: $12345678 (X=-123dot, Y=1023dot)
                    359:        //
                    360:        //    BMSEL=$4 ROP  Mask           RGB    RGB
                    361:        // Plane#0 Sel THRU $ffffffff   $0:RGB $8:RGB
                    362:        screen.Print(0, 0, "RFCNT: $%08x (X=%ddot, Y=%ddot)",
                    363:                rfcnt, hscroll, vscroll);
                    364:        screen.Print(3, 2, "BMSEL=$%x ROP  Mask", bmsel);
                    365: 
                    366:        for (i = 0; i < nplane; i++) {
                    367:                screen.Print(0, 3 + i, "Plane#%d %s %s $%08x",
                    368:                        i,
                    369:                        (bmsel & (1 << i)) ? "Sel" : "---",
                    370:                        RopStr(fcs[i]), mask[i]);
                    371:        }
                    372:        for (; i < MAX_PLANES; i++) {
                    373:                screen.Print(0, 3 + i, TA::Disable, "Plane#%d (Not installed)", i);
                    374:        }
                    375: 
                    376:        // ついでなのでここで BT454 のパレットも表示。
                    377:        // 012345
                    378:        // $0:RGB
                    379:        const uint8 *pal = gBT454->reg.color;
                    380:        screen.Puts(29, 1, "<BT454>");
                    381:        screen.Puts(32, 2, "RGB    RGB");
                    382:        for (i = 0; i < 16; i++) {
                    383:                uint rgb =
                    384:                        ((pal[i * 3 + 0] & 0xf0) << 4) +
                    385:                        ((pal[i * 3 + 1] & 0xf0)     ) +
                    386:                        ((pal[i * 3 + 2] & 0xf0) >> 4);
                    387:                screen.Print(29 + (i / 8) * 7, (i % 8) + 3, "$%x:%03x", i, rgb);
                    388:        }
                    389: }
                    390: 
                    391: // 全画面の更新フラグを立てる
                    392: void
                    393: LunafbDevice::Invalidate()
                    394: {
                    395:        for (int i = 0; i < 1024; i++) {
                    396:                atomic_dirty[i] = 1;
                    397:        }
                    398: }
                    399: 
                    400: // RFCNT への書き込み
                    401: void
                    402: LunafbDevice::WriteRFCNT(uint32 data)
                    403: {
                    404:        // レジスタ値
                    405:        rfcnt = data;
                    406: 
                    407:        // 水平オフセットを計算
                    408:        // XXX マニュアルでは -8 まで指定できるように読めるが
                    409:        //     指定する方法が分からない。
                    410:        // XXX 193 以上を指定するとどうなるのか (とりあえずほっとく)
                    411:        //     実機の挙動を目分量で見ると、右にはみ出た部分は
                    412:        //     256 ラスタ先のラスタデータを描画しているようだ。
                    413:        hscroll = ((rfcnt >> 16) & 0xff) + 8;
                    414:        hscroll *= 4;
                    415: 
                    416:        // ラスタ(垂直)カウンタ
                    417:        vscroll = (rfcnt + 26) & 0x3ff;
                    418: 
                    419:        // 全画面更新
                    420:        Invalidate();
                    421: 
                    422:        putlog(1, "RFCNT <- $%08x (水平 %ddot, 垂直 %ddot)",
                    423:                data, hscroll, vscroll);
                    424: }
                    425: 
                    426: // 共通ビットマッププレーン バイト書き込み
                    427: void
                    428: LunafbDevice::WriteCommonBitmap8(uint32 addr, uint32 data)
                    429: {
                    430:        uint32 offset = addr - 0xb1080000;
                    431:        putlog(2, "共通プレーン書き込み $%08x <- $%02x", addr, data);
                    432:        for (int i = 0; i < nplane; i++) {
                    433:                if ((bmsel & (1 << i))) {
                    434:                        WritePlane8(i, offset, data);
                    435:                }
                    436:        }
                    437: }
                    438: 
                    439: // 共通ビットマッププレーン ワード書き込み
                    440: void
                    441: LunafbDevice::WriteCommonBitmap16(uint32 addr, uint32 data)
                    442: {
                    443:        uint32 offset = addr - 0xb1080000;
                    444:        putlog(2, "共通プレーン書き込み $%08x <- $%04x", addr, data);
                    445:        for (int i = 0; i < nplane; i++) {
                    446:                if ((bmsel & (1 << i))) {
                    447:                        WritePlane16(i, offset, data);
                    448:                }
                    449:        }
                    450: }
                    451: 
                    452: // 共通ビットマッププレーン ロング書き込み
                    453: void
                    454: LunafbDevice::WriteCommonBitmap32(uint32 addr, uint32 data)
                    455: {
                    456:        uint32 offset = addr - 0xb1080000;
                    457:        putlog(2, "共通プレーン書き込み $%08x <- $%08x", addr, data);
                    458:        for (int i = 0; i < nplane; i++) {
                    459:                if ((bmsel & (1 << i))) {
                    460:                        WritePlane32(i, offset, data);
                    461:                }
                    462:        }
                    463: }
                    464: 
                    465: static inline uint32
                    466: RasterOp(uint rop, uint32 data, uint32 m)
                    467: {
                    468:        switch (rop) {
                    469:         case 0:        // ZERO
                    470:                data = 0;
                    471:                break;
                    472:         case 1:        // AND1
                    473:                data &= m;
                    474:                break;
                    475:         case 2:        // AND2
                    476:                data = ~data & m;
                    477:                break;
                    478:         case 3:        // 使用不可
                    479:                // 本当はここにシリアルモード変更コマンドがあるらしい
                    480:                data = m;
                    481:                break;
                    482:         case 4:        // AND3
                    483:                data &= ~m;
                    484:                break;
                    485:         case 5:        // THROUGH
                    486:                break;
                    487:         case 6:        // EOR
                    488:                data ^= m;
                    489:                break;
                    490:         case 7:        // OR1
                    491:                data |= m;
                    492:                break;
                    493:         case 8:        // NOR
                    494:                data = ~data & ~m;
                    495:                break;
                    496:         case 9:        // ENOR
                    497:                data = (data & m) | (~data & ~m);
                    498:                break;
                    499:         case 10:       // INV1
                    500:                data = ~data;
                    501:                break;
                    502:         case 11:       // OR2
                    503:                data = ~data | m;
                    504:                break;
                    505:         case 12:       // INV2
                    506:                data = ~m;
                    507:                break;
                    508:         case 13:       // OR3
                    509:                data |= ~m;
                    510:                break;
                    511:         case 14:       // NAND
                    512:                data = ~data | ~m;
                    513:                break;
                    514:         case 15:       // ONE
                    515:                data = 0xffffffff;
                    516:                break;
                    517:        }
                    518:        return data;
                    519: }
                    520: 
                    521: // ROP 文字列を返す
                    522: const char *
                    523: LunafbDevice::RopStr(uint rop)
                    524: {
                    525:        static const char * ropstr[] = {
                    526:                "ZERO",
                    527:                "AND1",
                    528:                "AND2",
                    529:                "(3)",
                    530:                "AND3",
                    531:                "THRU", // THROUGH
                    532:                "EOR",
                    533:                "OR1",
                    534:                "NOR",
                    535:                "ENOR",
                    536:                "INV1",
                    537:                "OR2",
                    538:                "INV2",
                    539:                "OR3",
                    540:                "NAND",
                    541:                "ONE",
                    542:        };
                    543:        return ropstr[rop];
                    544: }
                    545: 
                    546: // プレーン バイト書き込み
                    547: void
                    548: LunafbDevice::WritePlane8(uint plane, uint32 offset, uint32 data)
                    549: {
                    550:        uint32 memoffset = plane * 0x40000 + offset;
                    551:        uint32 m;
                    552:        uint32 mask8;
                    553: 
                    554:        m = mem[HLB(memoffset)];
                    555:        data = RasterOp(fcs[plane], data, m);
                    556:        mask8 = mask[plane] >> (24 - (memoffset & 3) * 8);
                    557:        mem[HLB(memoffset)] = (data & mask8) | (m & ~mask8);
                    558:        atomic_dirty[offset / 256] = 1;
                    559: }
                    560: 
                    561: // プレーン ワード書き込み
                    562: void
                    563: LunafbDevice::WritePlane16(uint plane, uint32 offset, uint32 data)
                    564: {
                    565:        uint32 memoffset = plane * 0x40000 + offset;
                    566:        uint32 m;
                    567:        uint32 mask16;
                    568: 
                    569:        m = *(uint16 *)&mem[HLW(memoffset)];
                    570:        data = RasterOp(fcs[plane], data, m);
                    571:        if ((memoffset & 2) == 0) {
                    572:                // 上位ワード
                    573:                mask16 = mask[plane] >> 16;
                    574:        } else {
                    575:                // 下位ワード
                    576:                mask16 = mask[plane];
                    577:        }
                    578:        *(uint16 *)&mem[HLW(memoffset)] = (data & mask16) | (m & ~mask16);
                    579:        atomic_dirty[offset / 256] = 1;
                    580: }
                    581: 
                    582: // プレーン ロングワード書き込み
                    583: void
                    584: LunafbDevice::WritePlane32(uint plane, uint32 offset, uint32 data)
                    585: {
                    586:        uint32 memoffset = plane * 0x40000 + offset;
                    587:        uint32 m;
                    588: 
                    589:        m = *(uint32 *)&mem[memoffset];
                    590:        data = RasterOp(fcs[plane], data, m);
                    591:        *(uint32 *)&mem[memoffset] = (data & mask[plane]) | (m & ~mask[plane]);
                    592:        atomic_dirty[offset / 256] = 1;
                    593: }
                    594: 
                    595: 
                    596: // エミュレータによる画面出力
                    597: //
                    598: // VM 内からの操作ではなく、エミュレータ本体から画面を操作する
                    599: // エミュレーション ROM によるモニタコンソール用の機能。
                    600: // サービスを使いたい側 (EmuROM など) が任意の大きさの TextScreen を
                    601: // 用意し EmuConsoleOpen() をコールすると (現在のパレットのまま) 画面を
                    602: // クリアし、画面中央をこのテキスト VRAM の表示エリアとみなす。
                    603: // 以降は EmuConsoleUpdate() で TextScreen の内容に従って画面を更新し、
                    604: // 使用後は EmuConsoleClose() で再び画面をクリア (およびリソースの解放) を
                    605: // すること。
                    606: 
                    607: // エミュレータによる出力開始
                    608: void
                    609: LunafbDevice::EmuConsoleOpen(TextScreen *t)
                    610: {
                    611:        textscr = t;
                    612: 
                    613:        screen_w = textscr->GetCol();
                    614:        screen_h = textscr->GetRow();
                    615:        prev.resize(screen_w * screen_h);
                    616:        for (int i = 0; i < screen_w * screen_h; i++) {
                    617:                prev[i] = 0x0020;
                    618:        }
                    619: 
                    620:        // ざっくりセンタリングする
                    621:        origin_x = (1280 - screen_w * 12) / 2;
                    622:        origin_y = (1024 - screen_h * 24) / 2;
                    623:        // ただし横は 48ドット境界から始める
                    624:        // こうすると1(,2)文字目の24ビットが必ずワード境界から始まる。
                    625:        origin_x = (origin_x / 48) * 48;
                    626: 
                    627:        // 同時書き込み設定
                    628:        bmsel = (1 << nplane) - 1;
                    629: 
                    630:        // 全画面をクリア
                    631:        for (uint32 addr = 0xb1080000; addr < 0xb10c0000; addr += 4) {
                    632:                WriteCommonBitmap32(addr, 0);
                    633:        }
                    634: }
                    635: 
                    636: // エミュレータによる出力終了
                    637: void
                    638: LunafbDevice::EmuConsoleClose()
                    639: {
                    640:        // 全画面をクリア
                    641:        for (uint32 addr = 0xb1080000; addr < 0xb10c0000; addr += 4) {
                    642:                WriteCommonBitmap32(addr, 0);
                    643:        }
                    644:        // 同時書き込みも元に戻す
                    645:        bmsel = 0;
                    646: 
                    647:        textscr = NULL;
                    648:        prev.clear();
                    649: }
                    650: 
                    651: // エミュレータによる出力
                    652: // ts が出力するテキスト情報、oldts は前回の情報。
                    653: void
                    654: LunafbDevice::EmuConsoleUpdate()
                    655: {
                    656:        auto& text = textscr->GetBuf();
                    657: 
                    658:        // 12ドットフォントなので2文字ずつ (24ビットずつ) 更新する
                    659:        for (int y = 0; y < screen_h; y++) {
                    660:                for (int x = 0; x < screen_w; x += 2) {
                    661:                        // 2文字分の文字と属性
                    662:                        uint32 t32 = *(const uint32 *)&text[y * screen_w + x];
                    663:                        uint32 p32 = *(const uint32 *)&prev[y * screen_w + x];
                    664:                        if (t32 == p32) {
                    665:                                continue;
                    666:                        }
                    667:                        // ここからは変更があったので出力
                    668:                        *(uint32 *)&prev[y * screen_w + x] = t32;
                    669:                        // 2文字分として直接32ビットキャストして取り出した t32 だと
                    670:                        // エンディアンによって上下が変わるので、ここでは改めて
                    671:                        // 順序通りに2回取り出す
                    672:                        uint32 ch0 = text[y * screen_w + x];
                    673:                        uint32 ch1 = text[y * screen_w + x + 1];
                    674:                        // その文字のフォントデータ上でのオフセット
                    675:                        const uint8 * const fo0 = BuiltinCGROM::Get12x24(ch0 & 0xff);
                    676:                        const uint8 * const fo1 = BuiltinCGROM::Get12x24(ch1 & 0xff);
                    677: 
                    678:                        // 1,2文字目なら true、3,4文字目なら false
                    679:                        bool evenpair = ((x & 2) == 0);
                    680: 
                    681:                        // ビットマップ上の書き始めアドレス
                    682:                        uint32 addr = 0xb1080000 +
                    683:                                ((origin_y + y * 24) * 256) +
                    684:                                ((origin_x + x * 12) / 8);
                    685: 
                    686:                        for (int i = 0; i < 24; i++) {
                    687:                                // その文字のフォントデータ
                    688:                                uint32 fdat0 = be16toh(*(const uint16*)(fo0 + i * 2));
                    689:                                uint32 fdat1 = be16toh(*(const uint16*)(fo1 + i * 2));
                    690: 
                    691:                                // 属性はとりあえず反転のみサポート
                    692:                                if ((ch0 & TA::On)) {
                    693:                                        fdat0 = ~fdat0 & 0xfff0;
                    694:                                }
                    695:                                if ((ch1 & TA::On)) {
                    696:                                        fdat1 = ~fdat1 & 0xfff0;
                    697:                                }
                    698: 
                    699:                                // 1文字目と2文字目を組み合わせて 24bit にする
                    700:                                uint32 data = (fdat0 << 8) | (fdat1 >> 4);
                    701: 
                    702:                                // 書き込みは一度に 3バイトずつになるので、
                    703:                                // 効率化のため上位下位ペアで書き込みパターンを変える。
                    704:                                //
                    705:                                // | chr1 | chr2  | chr3 | chr4  |
                    706:                                // +----+----+----+----+----+----+
                    707:                                // | +0 | +1 | +2 | +3 | +4 | +5 |
                    708:                                // +----+----+----+----+----+----+
                    709:                                // |<-.Word->|<.B>|<.B>|<-.Word->|
                    710:                                if (evenpair) {
                    711:                                        WriteCommonBitmap16(addr, data >> 8);
                    712:                                        WriteCommonBitmap8(addr + 2, data & 0xff);
                    713:                                } else {
                    714:                                        WriteCommonBitmap8(addr, data >> 16);
                    715:                                        WriteCommonBitmap16(addr + 1, data & 0xffff);
                    716:                                }
                    717: 
                    718:                                addr += 256;    // 1ライン進める
                    719:                        }
                    720:                }
                    721:        }
                    722: }

unix.superglobalmegacorp.com

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