|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2018 [email protected] ! 4: // ! 5: ! 6: #include "bitmap.h" ! 7: #include "bt454.h" ! 8: ! 9: // ! 10: // ビットマッププレーン ! 11: // ! 12: // Bitmap の VRAM はロングワード単位でホストバイトオーダ配置なので、 ! 13: // バイトアクセス、ワードアクセス時は HLB(), HLW() マクロを使用のこと。 ! 14: // ! 15: ! 16: // SX-9100 のほうはこう書いてあってこっちが正しいようだ。 ! 17: // +00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ! 18: // b100 |RF| |BS| |共 通 B M P|プレーン#0 | ! 19: // b110 |プレーン#1 |プレーン#2 |プレーン#3 |プレーン#4 | ! 20: // b120 |プレーン#5 |プレーン#6 |プレーン#7 |FC| | ! 21: // b130 |F0| |F1| |F2| |F3| | ! 22: // b140 |F4| |F5| |F6| |F7| | ! 23: // ! 24: // SX-7100 のほうはこう書いてあるがこうはなっていないようだ。 ! 25: // +00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ! 26: // b100 |RF| |BS| |共 通 B M P|FC| | ! 27: // b110 |プレーン#0 |プレーン#1 |プレーン#2 |プレーン#3 | ! 28: // b120 |プレーン#4 |プレーン#5 |プレーン#6 |プレーン#7 | ! 29: // b130 |F0| |F1| |F2| |F3| | ! 30: // b140 |F4| |F5| |F6| |F7| | ! 31: // ! 32: // RF: RFCNT (4バイト) ! 33: // BS: BMSEL (4バイト) ! 34: // FC: 共通ファンクションセット ! 35: // Fn: プレーン#n ファンクションセット ! 36: // 1区画が 64KB。空白のところは未調査。 ! 37: ! 38: BitmapDevice *gBitmap; ! 39: ! 40: BitmapDevice::BitmapDevice() ! 41: { ! 42: logname = "bitmap"; ! 43: devname = "Bitmap"; ! 44: devaddr = 0xb1000000; ! 45: monitor.Init(42, 11); ! 46: ! 47: // XXX とりあえず。実際は設定による ! 48: nplane = 1; ! 49: // プレーン数によってメモリを確保 ! 50: mem = new uint8 [0x40000 * nplane]; ! 51: } ! 52: ! 53: BitmapDevice::~BitmapDevice() ! 54: { ! 55: if (mem) { ! 56: delete[] mem; ! 57: } ! 58: } ! 59: ! 60: void ! 61: BitmapDevice::ResetHard() ! 62: { ! 63: // 厳密にどの時点でリセットされるのかは知らないけど ! 64: bmsel = 0; ! 65: ! 66: // RFCNT の初期値は観測困難なので、とりあえず無視。 ! 67: ! 68: for (int i = 0; i < MAX_PLANES; i++) { ! 69: fcs[i] = 5; ! 70: mask[i] = 0xffffffff; ! 71: } ! 72: ! 73: // XXX ここ? ! 74: Invalidate(); ! 75: } ! 76: ! 77: uint64 ! 78: BitmapDevice::Read8(uint32 addr) ! 79: { ! 80: if (addr < plane0base) { ! 81: // 書き込み専用 ! 82: return 0xff; ! 83: } ! 84: if (addr < plane0base + 0x40000 * nplane) { ! 85: // プレーンの読み出し ! 86: return mem[HLB(addr - plane0base)]; ! 87: } ! 88: // 残りは書き込み専用 ! 89: return 0xff; ! 90: } ! 91: ! 92: uint64 ! 93: BitmapDevice::Read16(uint32 addr) ! 94: { ! 95: if (addr < plane0base) { ! 96: // 書き込み専用 ! 97: return 0xffff; ! 98: } ! 99: if (addr < plane0base + 0x40000 * nplane) { ! 100: // プレーンの読み出し ! 101: return *(uint16 *)&mem[HLW(addr - plane0base)]; ! 102: } ! 103: // 残りは書き込み専用 ! 104: return 0xffff; ! 105: } ! 106: ! 107: uint64 ! 108: BitmapDevice::Read32(uint32 addr) ! 109: { ! 110: if (addr < plane0base) { ! 111: // 書き込み専用 ! 112: return 0xffffffff; ! 113: } ! 114: if (addr < plane0base + 0x40000 * nplane) { ! 115: // プレーンの読み出し ! 116: return *(uint32 *)&mem[addr - plane0base]; ! 117: } ! 118: // 残りは書き込み専用 ! 119: return 0xffffffff; ! 120: } ! 121: ! 122: uint64 ! 123: BitmapDevice::Write8(uint32 addr, uint32 data) ! 124: { ! 125: switch (addr) { ! 126: case 0xb1000000: ! 127: case 0xb1000001: ! 128: case 0xb1000002: ! 129: case 0xb1000003: ! 130: // このロングワード内へのバイトアクセスはロングワードにミラーされる ! 131: data = (data << 24) | (data << 16) | (data << 8) | data; ! 132: return Write32(addr & ~3, data); ! 133: case 0xb1040000: ! 134: case 0xb1040001: ! 135: case 0xb1040002: ! 136: case 0xb1040003: ! 137: // BMSEL はバイトアクセスできる? ! 138: putlog(0, "未実装バイト書き込み $%08x <- $%02x", addr, data); ! 139: return 0; ! 140: } ! 141: ! 142: if (addr < 0xb1080000) { ! 143: putlog(0, "未実装バイト書き込み $%08x <- $%02x", addr, data); ! 144: return 0; ! 145: } ! 146: if (addr < plane0base) { ! 147: // 共通ビットマッププレーン ! 148: WriteCommonBitmap8(addr, data); ! 149: return 0; ! 150: } ! 151: ! 152: if (addr < plane7end) { ! 153: // ビットマッププレーン ! 154: uint32 reladdr = addr - plane0base; ! 155: uint plane = reladdr / 0x40000; ! 156: uint32 offset = reladdr % 0x40000; ! 157: ! 158: if (plane < nplane) { ! 159: // ビットマッププレーンN ! 160: putlog(2, "プレーン%d書き込み $%08x <- $%02x", plane, addr, data); ! 161: WritePlane8(plane, offset, data); ! 162: return 0; ! 163: } ! 164: // HW 設定によっては存在しないプレーンへの書き込み ! 165: putlog(3, "不在プレーン%d書き込み $%08x <- $%02x", ! 166: plane, addr, data); ! 167: return 0; ! 168: } ! 169: ! 170: putlog(0, "未実装バイト書き込み $%08x <- $%02x", addr, data); ! 171: return 0; ! 172: } ! 173: ! 174: uint64 ! 175: BitmapDevice::Write16(uint32 addr, uint32 data) ! 176: { ! 177: switch (addr) { ! 178: case 0xb1000000: ! 179: case 0xb1000002: ! 180: // このロングワード内へのワードアクセスはロングワードにミラーされる ! 181: data = (data << 16) | data; ! 182: return Write32(addr & ~3, data); ! 183: case 0xb1040000: ! 184: case 0xb1040002: ! 185: // BMSEL はワードアクセスできる? ! 186: putlog(0, "未実装ワード書き込み $%08x <- $%04x", addr, data); ! 187: return 0; ! 188: } ! 189: ! 190: if (addr < 0xb1080000) { ! 191: putlog(0, "未実装ワード書き込み $%08x <- $%04x", addr, data); ! 192: return 0; ! 193: } ! 194: if (addr < plane0base) { ! 195: // 共通ビットマッププレーン ! 196: WriteCommonBitmap16(addr, data); ! 197: return 0; ! 198: } ! 199: ! 200: if (addr < plane7end) { ! 201: // ビットマッププレーン ! 202: uint32 reladdr = addr - plane0base; ! 203: uint plane = reladdr / 0x40000; ! 204: uint32 offset = reladdr % 0x40000; ! 205: ! 206: if (plane < nplane) { ! 207: // ビットマッププレーンN ! 208: putlog(2, "プレーン%d書き込み $%08x <- $%04x", plane, addr, data); ! 209: WritePlane16(plane, offset, data); ! 210: return 0; ! 211: } ! 212: // HW 設定によっては存在しないプレーンへの書き込み ! 213: putlog(3, "不在プレーン%d書き込み $%08x <- $%04x", ! 214: plane, addr, data); ! 215: return 0; ! 216: } ! 217: ! 218: putlog(0, "未実装ワード書き込み $%08x <- $%04x", addr, data); ! 219: return 0; ! 220: } ! 221: ! 222: uint64 ! 223: BitmapDevice::Write32(uint32 addr, uint32 data) ! 224: { ! 225: switch (addr) { ! 226: case 0xb1000000: ! 227: // RFCNT ! 228: WriteRFCNT(data); ! 229: return 0; ! 230: ! 231: case 0xb1040000: ! 232: // BMSEL ! 233: bmsel = data & 0xf; ! 234: putlog(1, "BMSEL <- $%08x", data); ! 235: return 0; ! 236: } ! 237: ! 238: if (addr < 0xb1080000) { ! 239: putlog(0, "未実装ロング書き込み $%08x <- $%08x", addr, data); ! 240: return 0; ! 241: } ! 242: if (addr < plane0base) { ! 243: // 共通ビットマッププレーン ! 244: WriteCommonBitmap32(addr, data); ! 245: return 0; ! 246: } ! 247: ! 248: if (addr < plane7end) { ! 249: // ビットマッププレーン ! 250: uint32 reladdr = addr - plane0base; ! 251: uint plane = reladdr / 0x40000; ! 252: uint32 offset = reladdr % 0x40000; ! 253: ! 254: if (plane < nplane) { ! 255: // ビットマッププレーンN ! 256: putlog(3, "プレーン%d書き込み $%08x <- $%08x", plane, addr, data); ! 257: WritePlane32(plane, offset, data); ! 258: return 0; ! 259: } ! 260: // HW 設定によっては存在しないプレーンへの書き込み ! 261: putlog(3, "不在プレーン%d書き込み $%08x <- $%08x", ! 262: plane, addr, data); ! 263: return 0; ! 264: } ! 265: ! 266: if (addr < 0xb1300000) { ! 267: // 共通ファンクションセット ! 268: uint rop = (addr & 0x3f) / 4; ! 269: putlog(2, "共通FCSet 書き込み $%08x <- $%08x (%s)", ! 270: addr, data, RopStr(rop)); ! 271: for (int i = 0; i < nplane; i++) { ! 272: if ((bmsel & (1 << i))) { ! 273: fcs[i] = rop; ! 274: mask[i] = data; ! 275: } ! 276: } ! 277: return 0; ! 278: } ! 279: ! 280: if (addr < fcset7end) { ! 281: // ファンクションセット ! 282: int plane = (addr - 0xb1300000) / 0x40000; ! 283: ! 284: if (plane < nplane) { ! 285: // ファンクションセットN ! 286: uint rop = (addr & 0x3f) / 4; ! 287: putlog(2, "FCSet%d書き込み $%08x <- $%08x (%s)", ! 288: plane, addr, data, RopStr(rop)); ! 289: fcs[plane] = rop; ! 290: mask[plane] = data; ! 291: return 0; ! 292: } ! 293: // HW 設定によっては存在しない FCSet への書き込み ! 294: putlog(3, "不在FCSet%d書き込み $%08x <- $%08x", ! 295: plane, addr, data); ! 296: return 0; ! 297: } ! 298: ! 299: putlog(0, "未実装ロング書き込み $%08x <- $%08x", addr, data); ! 300: return 0; ! 301: } ! 302: ! 303: uint64 ! 304: BitmapDevice::Peek8(uint32 addr) ! 305: { ! 306: if (addr < plane0base) { ! 307: // 書き込み専用 ! 308: return 0xff; ! 309: } ! 310: if (addr < plane0base + 0x40000 * nplane) { ! 311: // プレーンの読み出し ! 312: return mem[HLB(addr - plane0base)]; ! 313: } ! 314: // 残りは書き込み専用 ! 315: return 0xff; ! 316: } ! 317: ! 318: bool ! 319: BitmapDevice::MonitorUpdate() ! 320: { ! 321: int i; ! 322: ! 323: monitor.Clear(); ! 324: ! 325: // 0 1 2 3 4 ! 326: // 012345678901234567890123456789012345678901 ! 327: // RFCNT: $12345678 (X=-123dot, Y=1023dot) ! 328: // ! 329: // BMSEL=$4 ROP Mask RGB RGB ! 330: // Plane#0 Sel THRU $ffffffff $0:RGB $8:RGB ! 331: monitor.Print(0, 0, "RFCNT: $%08x (X=%ddot, Y=%ddot)", ! 332: rfcnt, hscroll, vscroll); ! 333: monitor.Print(3, 2, "BMSEL=$%x ROP Mask", bmsel); ! 334: ! 335: for (i = 0; i < nplane; i++) { ! 336: monitor.Print(0, 3 + i, "Plane#%d %s %s $%08x", ! 337: i, ! 338: (bmsel & (1 << i)) ? "Sel" : "---", ! 339: RopStr(fcs[i]), mask[i]); ! 340: } ! 341: for (; i < MAX_PLANES; i++) { ! 342: monitor.Print(0, 3 + i, TA::Disable, "Plane#%d (Not installed)", i); ! 343: } ! 344: ! 345: // ついでなのでここで BT454 のパレットも表示。 ! 346: // 012345 ! 347: // $0:RGB ! 348: const uint8 *pal = gBT454->reg.color; ! 349: monitor.Print(29, 1, "<BT454>"); ! 350: monitor.Print(32, 2, "RGB RGB"); ! 351: for (i = 0; i < 16; i++) { ! 352: uint rgb = ! 353: ((pal[i * 3 + 0] & 0xf0) << 4) + ! 354: ((pal[i * 3 + 1] & 0xf0) ) + ! 355: ((pal[i * 3 + 2] & 0xf0) >> 4); ! 356: monitor.Print(29 + (i / 8) * 7, (i % 8) + 3, "$%x:%03x", i, rgb); ! 357: } ! 358: ! 359: return true; ! 360: } ! 361: ! 362: // 全画面の更新フラグを立てる ! 363: void ! 364: BitmapDevice::Invalidate() ! 365: { ! 366: for (int i = 0; i < 1024; i++) { ! 367: atomic_dirty[i] = 1; ! 368: } ! 369: } ! 370: ! 371: // RFCNT への書き込み ! 372: void ! 373: BitmapDevice::WriteRFCNT(uint32 data) ! 374: { ! 375: // レジスタ値 ! 376: rfcnt = data; ! 377: ! 378: // 水平オフセットを計算 ! 379: // XXX マニュアルでは -8 まで指定できるように読めるが ! 380: // 指定する方法が分からない。 ! 381: // XXX 193 以上を指定するとどうなるのか (とりあえずほっとく) ! 382: // 実機の挙動を目分量で見ると、右にはみ出た部分は ! 383: // 256 ラスタ先のラスタデータを描画しているようだ。 ! 384: hscroll = ((rfcnt >> 16) & 0xff) + 8; ! 385: hscroll *= 4; ! 386: ! 387: // ラスタ(垂直)カウンタ ! 388: // マニュアルには +26 オフセットすると書いてあるように読めるが、 ! 389: // 手元の実機では +49 でいい感じになるようだ。なんでかは知らん。 ! 390: // ROM モニタで ! 391: // > b1000000;,a ! 392: // > h ! 393: // > h ! 394: // とした時の画面上下のヘルプメッセージのフォントの見切れ方で検証。 ! 395: vscroll = (rfcnt + 49) & 0x3ff; ! 396: ! 397: // 全画面更新 ! 398: Invalidate(); ! 399: ! 400: putlog(1, "RFCNT <- $%08x (水平 %ddot, 垂直 %ddot)", ! 401: data, hscroll, vscroll); ! 402: } ! 403: ! 404: // 共通ビットマッププレーン バイト書き込み ! 405: void ! 406: BitmapDevice::WriteCommonBitmap8(uint32 addr, uint32 data) ! 407: { ! 408: uint32 offset = addr - 0xb1080000; ! 409: putlog(2, "共通プレーン書き込み $%08x <- $%02x", addr, data); ! 410: for (int i = 0; i < nplane; i++) { ! 411: if ((bmsel & (1 << i))) { ! 412: WritePlane8(i, offset, data); ! 413: } ! 414: } ! 415: } ! 416: ! 417: // 共通ビットマッププレーン ワード書き込み ! 418: void ! 419: BitmapDevice::WriteCommonBitmap16(uint32 addr, uint32 data) ! 420: { ! 421: uint32 offset = addr - 0xb1080000; ! 422: putlog(2, "共通プレーン書き込み $%08x <- $%04x", addr, data); ! 423: for (int i = 0; i < nplane; i++) { ! 424: if ((bmsel & (1 << i))) { ! 425: WritePlane16(i, offset, data); ! 426: } ! 427: } ! 428: } ! 429: ! 430: // 共通ビットマッププレーン ロング書き込み ! 431: void ! 432: BitmapDevice::WriteCommonBitmap32(uint32 addr, uint32 data) ! 433: { ! 434: uint32 offset = addr - 0xb1080000; ! 435: putlog(2, "共通プレーン書き込み $%08x <- $%08x", addr, data); ! 436: for (int i = 0; i < nplane; i++) { ! 437: if ((bmsel & (1 << i))) { ! 438: WritePlane32(i, offset, data); ! 439: } ! 440: } ! 441: } ! 442: ! 443: static inline uint32 ! 444: RasterOp(uint rop, uint32 data, uint32 m) ! 445: { ! 446: switch (rop) { ! 447: case 0: // ZERO ! 448: data = 0; ! 449: break; ! 450: case 1: // AND1 ! 451: data &= m; ! 452: break; ! 453: case 2: // AND2 ! 454: data = ~data & m; ! 455: break; ! 456: case 3: // 使用不可 ! 457: // 本当はここにシリアルモード変更コマンドがあるらしい ! 458: data = m; ! 459: break; ! 460: case 4: // AND3 ! 461: data &= ~m; ! 462: break; ! 463: case 5: // THROUGH ! 464: break; ! 465: case 6: // EOR ! 466: data ^= m; ! 467: break; ! 468: case 7: // OR1 ! 469: data |= m; ! 470: break; ! 471: case 8: // NOR ! 472: data = ~data & ~m; ! 473: break; ! 474: case 9: // ENOR ! 475: data = (data & m) | (~data & ~m); ! 476: break; ! 477: case 10: // INV1 ! 478: data = ~data; ! 479: break; ! 480: case 11: // OR2 ! 481: data = ~data | m; ! 482: break; ! 483: case 12: // INV2 ! 484: data = ~m; ! 485: break; ! 486: case 13: // OR3 ! 487: data |= ~m; ! 488: break; ! 489: case 14: // NAND ! 490: data = ~data | ~m; ! 491: break; ! 492: case 15: // ONE ! 493: data = 0xffffffff; ! 494: break; ! 495: } ! 496: return data; ! 497: } ! 498: ! 499: // ROP 文字列を返す ! 500: const char * ! 501: BitmapDevice::RopStr(uint rop) ! 502: { ! 503: static const char * ropstr[] = { ! 504: "ZERO", ! 505: "AND1", ! 506: "AND2", ! 507: "(3)", ! 508: "AND3", ! 509: "THRU", // THROUGH ! 510: "EOR", ! 511: "OR1", ! 512: "NOR", ! 513: "ENOR", ! 514: "INV1", ! 515: "OR2", ! 516: "INV2", ! 517: "OR3", ! 518: "NAND", ! 519: "ONE", ! 520: }; ! 521: return ropstr[rop]; ! 522: } ! 523: ! 524: // プレーン バイト書き込み ! 525: void ! 526: BitmapDevice::WritePlane8(uint plane, uint32 offset, uint32 data) ! 527: { ! 528: uint32 memoffset = plane * 0x40000 + offset; ! 529: uint32 m; ! 530: uint32 mask8; ! 531: ! 532: m = mem[HLB(memoffset)]; ! 533: data = RasterOp(fcs[plane], data, m); ! 534: mask8 = mask[plane] >> (24 - (memoffset & 3) * 8); ! 535: mem[HLB(memoffset)] = (data & mask8) | (m & ~mask8); ! 536: atomic_dirty[offset / 256] = 1; ! 537: } ! 538: ! 539: // プレーン ワード書き込み ! 540: void ! 541: BitmapDevice::WritePlane16(uint plane, uint32 offset, uint32 data) ! 542: { ! 543: uint32 memoffset = plane * 0x40000 + offset; ! 544: uint32 m; ! 545: uint32 mask16; ! 546: ! 547: m = *(uint16 *)&mem[HLW(memoffset)]; ! 548: data = RasterOp(fcs[plane], data, m); ! 549: if ((memoffset & 2) == 0) { ! 550: // 上位ワード ! 551: mask16 = mask[plane] >> 16; ! 552: } else { ! 553: // 下位ワード ! 554: mask16 = mask[plane]; ! 555: } ! 556: *(uint16 *)&mem[HLW(memoffset)] = (data & mask16) | (m & ~mask16); ! 557: atomic_dirty[offset / 256] = 1; ! 558: } ! 559: ! 560: // プレーン ロングワード書き込み ! 561: void ! 562: BitmapDevice::WritePlane32(uint plane, uint32 offset, uint32 data) ! 563: { ! 564: uint32 memoffset = plane * 0x40000 + offset; ! 565: uint32 m; ! 566: ! 567: m = *(uint32 *)&mem[memoffset]; ! 568: data = RasterOp(fcs[plane], data, m); ! 569: *(uint32 *)&mem[memoffset] = (data & mask[plane]) | (m & ~mask[plane]); ! 570: atomic_dirty[offset / 256] = 1; ! 571: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.