Annotation of nono/vm/lunafb.cpp, revision 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.