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

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

unix.superglobalmegacorp.com

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