|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.