|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2020 nono project ! 4: // Licensed under nono-license.txt ! 5: // ! 6: ! 7: // ! 8: // Bt454/458 ! 9: // ! 10: ! 11: // 仕様書には $c100_0000 と書いてあるが、PROM も NetBSD カーネルも ! 12: // $c110_0000 にアクセスしている。実際にはアドレスバスの上位寄りは未接続の ! 13: // 箇所が多くほとんどの場所でミラーが見えているので問題はない。 ! 14: // ! 15: // LUNA-I、LUNA-88K どちらでも (というかここはビデオボードなので本体関係なく) ! 16: // Bt454 ならバイトポートが連続配置 (BusIO_B 相当)、 ! 17: // Bt458 ならバイトポートがロングワード配置 (たぶん BusIO_BFFF 相当、未確認) ! 18: // となっているようだ。このため、ここでは BusIO を使わず自力でデコードする。 ! 19: // ! 20: // ソフトウェアから判別は以下の要領で行える。 ! 21: // 先頭の1バイトは 1or4bpp ボード(連続配置)、8bpp ボード(ロングワード配置)の ! 22: // どちらでもアドレスレジスタなので、ここに $00 を書き込んでから読み返す。 ! 23: // $0f が読み出せたら Bt454 なので 1or4bpp ボード、$00 が読み出せたら Bt458 ! 24: // なので 8bpp ボードと分かる。Bt458 のデータバスは8ビットクリーンだが、 ! 25: // Bt454 のデータバスは4ビットしかなく下位ニブルは常に $f になるため。 ! 26: // ! 27: // LUNA-I の PROM v4.22 は 8bpp ボードに対応していない。 ! 28: ! 29: #include "bt45x.h" ! 30: #include "config.h" ! 31: #include "mainapp.h" ! 32: #include "mpu.h" ! 33: #include "planevram.h" ! 34: #include "prom.h" ! 35: #include "renderer.h" ! 36: #include "uimessage.h" ! 37: ! 38: // Bt454 の下位ニブル用マスク ! 39: #define LOW_NIBBLE (0x0f) ! 40: ! 41: // コンストラクタ ! 42: BT45xDevice::BT45xDevice() ! 43: : inherited(OBJ_BT45x) ! 44: { ! 45: // func, size は Init() で決まる ! 46: monitor.Regist(ID_MONITOR_BT45x); ! 47: } ! 48: ! 49: // デストラクタ ! 50: BT45xDevice::~BT45xDevice() ! 51: { ! 52: } ! 53: ! 54: // 初期化 ! 55: bool ! 56: BT45xDevice::Init() ! 57: { ! 58: if (inherited::Init() == false) { ! 59: return false; ! 60: } ! 61: ! 62: renderer = GetRenderer(); ! 63: ! 64: // 設定からプレーン数を取得 ! 65: const ConfigItem& item = gConfig->Find("luna-video-plane"); ! 66: if (item.TryInt(&nplane) == false) { ! 67: item.Err(); ! 68: return false; ! 69: } ! 70: if (nplane != 1 && nplane != 4 && nplane != 8) { ! 71: item.Err("Must be 1, 4, or 8"); ! 72: return false; ! 73: } ! 74: ! 75: // それによってモデル分け。1bpp/4bpp なら Bt454、8bpp なら Bt458。 ! 76: if (nplane <= 4) { ! 77: bt454 = true; ! 78: palettes = 16; ! 79: low_nibble = LOW_NIBBLE; ! 80: readmask = 0x0f; ! 81: ! 82: monitor.func = ToMonitorCallback(&BT45xDevice::MonitorUpdate454); ! 83: monitor.SetSize(63, 3); ! 84: } else { ! 85: bt454 = false; ! 86: palettes = 256; ! 87: low_nibble = 0; ! 88: // 初期化されないそうなのでゴミを入れておく ! 89: readmask = 0xcc; ! 90: ! 91: monitor.func = ToMonitorCallback(&BT45xDevice::MonitorUpdate458); ! 92: monitor.SetSize(116, 18); ! 93: ! 94: // LUNA-I の PROM v4.22 は 8bpp ボードをサポートしておらず PROM の ! 95: // 画面は真っ暗のままになる。その後 OS が再初期化すれば使えるようには ! 96: // なるが、PROM が映らずびっくりするのでメッセージだけ表示して、 ! 97: // 実行は継続する。他の ROM バージョンは未調査。 ! 98: auto prom = dynamic_cast<PROMDevice *>(GetPROMDevice()); ! 99: if (gMainApp.IsLUNA1() && prom != NULL) { ! 100: int ver = prom->GetROMVer(); ! 101: if (ver <= 422) { ! 102: warnx("Warning: PROM v%d.%02d does not support 8bpp board.", ! 103: ver / 100, ver % 100); ! 104: // 実行は継続 ! 105: } ! 106: } ! 107: } ! 108: ! 109: color.resize(palettes * 3); ! 110: hostcolor.resize(palettes); ! 111: return true; ! 112: } ! 113: ! 114: // リセット ! 115: void ! 116: BT45xDevice::ResetHard(bool poweron) ! 117: { ! 118: idx = 0; ! 119: ! 120: // ReadMask、BlinkMask は初期化されない (初期値も不明) ! 121: ! 122: // XXX Bt45x のレジスタの初期値は不明なのでとりあえず全部黒にしておく ! 123: memset(&color[0], 0, color.size()); ! 124: for (int i = 0; i < countof(color); i++) { ! 125: MakeHostColor(i); ! 126: } ! 127: Notify(); ! 128: } ! 129: ! 130: /* static */ const char ! 131: BT45xDevice::rgbstr[3] = { 'R', 'G', 'B' }; ! 132: ! 133: // LUNA のビデオボードは Bt454 か Bt458 かでバイト配置が異なるようだ。 ! 134: ! 135: uint64 ! 136: BT45xDevice::Read8(uint32 addr) ! 137: { ! 138: if (bt454) { ! 139: // バイトポートが連続、4バイトでミラー ! 140: return Read(addr & 3); ! 141: } else { ! 142: // バイトポートがロングワード配置、隙間は何が見えるか不明、 ! 143: // たぶん16バイトでミラー。 ! 144: addr &= 15; ! 145: if (addr % 4 == 0) { ! 146: return Read(addr / 4); ! 147: } else { ! 148: return 0xff; ! 149: } ! 150: } ! 151: } ! 152: ! 153: uint64 ! 154: BT45xDevice::Write8(uint32 addr, uint32 data) ! 155: { ! 156: if (bt454) { ! 157: // バイトポートが連続、4バイトでミラー ! 158: return Write(addr & 3, data); ! 159: } else { ! 160: // バイトポートがロングワード配置、隙間は何が見えるか不明、 ! 161: // たぶん16バイトでミラー。 ! 162: addr &= 15; ! 163: if (addr % 4 == 0) { ! 164: return Write(addr / 4, data); ! 165: } else { ! 166: return 0; ! 167: } ! 168: } ! 169: } ! 170: ! 171: uint64 ! 172: BT45xDevice::Peek8(uint32 addr) ! 173: { ! 174: if (bt454) { ! 175: // バイトポートが連続、4バイトでミラー ! 176: return Peek(addr & 3); ! 177: } else { ! 178: // バイトポートがロングワード配置、隙間は何が見えるか不明、 ! 179: // たぶん16バイトでミラー。 ! 180: addr &= 15; ! 181: if (addr % 4 == 0) { ! 182: return Peek(addr / 4); ! 183: } else { ! 184: return 0xff; ! 185: } ! 186: } ! 187: } ! 188: ! 189: // こっちがマッピング非依存のバイトポートアクセス ! 190: uint64 ! 191: BT45xDevice::Read(uint32 offset) ! 192: { ! 193: uint32 data; ! 194: ! 195: switch (offset) { ! 196: case 0: // アドレスレジスタ ! 197: data = ReadAddress(); ! 198: break; ! 199: ! 200: case 1: // カラーパレットレジスタ ! 201: data = ReadPalette(); ! 202: break; ! 203: ! 204: case 2: // Bt454 ならリセット(?)、Bt458 なら各種制御レジスタ ! 205: data = ReadControl(); ! 206: break; ! 207: ! 208: case 3: ! 209: putlog(0, "Read Overlay Register (NOT IMPLEMENTED)"); ! 210: data = 0xff; ! 211: break; ! 212: ! 213: default: ! 214: VMPANIC("corrupted offset=%d", offset); ! 215: } ! 216: ! 217: return data; ! 218: } ! 219: ! 220: // こっちがマッピング非依存のバイトポートアクセス ! 221: uint64 ! 222: BT45xDevice::Write(uint32 offset, uint32 data) ! 223: { ! 224: // Bt454 なら書き込みデータのうち有効なのは上位ニブルだけ ! 225: ! 226: switch (offset) { ! 227: case 0: // アドレスレジスタ ! 228: WriteAddress(data); ! 229: break; ! 230: ! 231: case 1: // カラーパレットレジスタ ! 232: WritePalette(data); ! 233: break; ! 234: ! 235: case 2: // Bt454 ならリセット(?)、Bt458 なら各種制御レジスタ ! 236: WriteControl(data); ! 237: break; ! 238: ! 239: case 3: ! 240: putlog(0, "Overlay Register <- $%02x (NOT IMPLEMENTED)", data); ! 241: break; ! 242: ! 243: default: ! 244: VMPANIC("corrupted offset=%d", offset); ! 245: } ! 246: return 0; ! 247: } ! 248: ! 249: // こっちがマッピング非依存のバイトポートアクセス ! 250: uint64 ! 251: BT45xDevice::Peek(uint32 offset) ! 252: { ! 253: uint8 data; ! 254: ! 255: switch (offset) { ! 256: case 0: // アドレスレジスタ ! 257: data = idx / 3; ! 258: data &= readmask; ! 259: break; ! 260: ! 261: case 1: // カラーパレットレジスタ ! 262: // 今読み出そうとしたら読み出せるやつ ! 263: data = color[idx]; ! 264: break; ! 265: ! 266: case 2: // Bt454 ならリセット(?)、Bt458 なら各種制御レジスタ ! 267: data = PeekControl(); ! 268: break; ! 269: ! 270: case 3: ! 271: // 未実装 ! 272: data = 0xff; ! 273: break; ! 274: ! 275: default: ! 276: data = 0xff; ! 277: break; ! 278: } ! 279: ! 280: if (bt454) { ! 281: data = (data << 4) | LOW_NIBBLE; ! 282: } ! 283: return data; ! 284: } ! 285: ! 286: // Bt454 ! 287: void ! 288: BT45xDevice::MonitorUpdate454(Monitor *, TextScreen& screen) ! 289: { ! 290: screen.Clear(); ! 291: screen.Puts(0, 0, "Model: Bt454"); ! 292: ! 293: // 01234567 ! 294: // $0 $1 ! 295: // RGB RGB ! 296: ! 297: for (int i = 0; i < 16; i++) { ! 298: screen.Print(i * 4, 1, "$%x", i); ! 299: screen.Puts(i * 4, 2, strhex(Palette454ToInt(i), 3).c_str()); ! 300: } ! 301: } ! 302: ! 303: // Bt458 ! 304: void ! 305: BT45xDevice::MonitorUpdate458(Monitor *, TextScreen& screen) ! 306: { ! 307: screen.Clear(); ! 308: screen.Puts(0, 0, "Model: Bt458"); ! 309: ! 310: // 012345678901 ! 311: // +$0 +$1 ! 312: // $00: RRGGBB RRGGBB ! 313: ! 314: for (int i = 0; i < 16; i++) { ! 315: screen.Print(5 + i * 7, 1, "+$%x", i); ! 316: } ! 317: int c = 0; ! 318: for (int y = 0; y < 16; y++) { ! 319: screen.Print(0, y + 2, "$%02x:", y * 16); ! 320: for (int x = 0; x < 16; x++) { ! 321: screen.Print(5 + x * 7, y + 2, "%06x", Palette458ToInt(c)); ! 322: c++; ! 323: } ! 324: } ! 325: } ! 326: ! 327: // idx 番目のレジスタ値からホストパレットを作成。 ! 328: void ! 329: BT45xDevice::MakeHostColor(int idx_) ! 330: { ! 331: assert(idx_ < color.size()); ! 332: int col = idx_ / 3; ! 333: int ab = idx_ % 3; ! 334: ! 335: if (nplane == 1) { ! 336: // 1bpp (モノクロプレーン) なら R,G,B のうち G の値だけを使用 ! 337: if (ab == 1) { ! 338: hostcolor[col].r = color[col * 3 + 1]; ! 339: hostcolor[col].g = color[col * 3 + 1]; ! 340: hostcolor[col].b = color[col * 3 + 1]; ! 341: } ! 342: } else { ! 343: // カラープレーンなら代入するだけ ! 344: switch (ab) { ! 345: case 0: ! 346: hostcolor[col].r = color[col * 3 + ab]; ! 347: break; ! 348: case 1: ! 349: hostcolor[col].g = color[col * 3 + ab]; ! 350: break; ! 351: case 2: ! 352: hostcolor[col].b = color[col * 3 + ab]; ! 353: break; ! 354: default: ! 355: VMPANIC("corrupted ab=%d", ab); ! 356: } ! 357: } ! 358: ! 359: // 通知が必要なら別途行うこと。 ! 360: } ! 361: ! 362: // 通知 ! 363: void ! 364: BT45xDevice::Notify() ! 365: { ! 366: // パレット変更が起きたことをレンダラに通知 ! 367: renderer->Invalidate2(); ! 368: ! 369: // UI にも通知 ! 370: UIMessage::Post(UIMessage::PALETTE); ! 371: } ! 372: ! 373: // アドレスレジスタ読み込み。 ! 374: uint32 ! 375: BT45xDevice::ReadAddress() ! 376: { ! 377: uint32 data; ! 378: ! 379: // 今の(今からアクセスする)パレット番号を返す。 ! 380: data = idx / 3; ! 381: // Bt458 ならこれをマスクする? ! 382: data &= readmask; ! 383: if (bt454) { ! 384: data = (data << 4) | LOW_NIBBLE; ! 385: } ! 386: putlog(2, "Address Register -> $%02x", data); ! 387: ! 388: // アドレスレジスタアクセスで ab カウンタは 0 にリセットされる ! 389: idx = (idx / 3) * 3; ! 390: ! 391: return data; ! 392: } ! 393: ! 394: // パレットレジスタ読み込み。 ! 395: uint32 ! 396: BT45xDevice::ReadPalette() ! 397: { ! 398: uint32 data; ! 399: ! 400: // Bt454 の場合 color[] の上位下位4ビットは同じ値にしてある ! 401: data = color[idx] | low_nibble; ! 402: putlog(2, "Color Palette $%x(%c) -> $%02x", ! 403: idx / 3, rgbstr[idx % 3], data); ! 404: ! 405: // アクセスするたびにインクリメントする。 ! 406: idx++; ! 407: if (idx >= color.size()) { ! 408: idx = 0; ! 409: } ! 410: ! 411: return data; ! 412: } ! 413: ! 414: // Bt454 ならリセット(?)、 ! 415: // Bt458 なら各種制御レジスタの読み込み。 ! 416: uint32 ! 417: BT45xDevice::ReadControl() ! 418: { ! 419: uint32 data; ! 420: ! 421: if (bt454) { ! 422: // ADDRa,b を 0 にする? D0-D3 は 0 になる?? ! 423: // データシートが雑でよく分からん… ! 424: idx = (idx / 3) * 3; ! 425: data = 0x00 | LOW_NIBBLE; ! 426: putlog(2, "reset ab"); ! 427: } else { ! 428: // Bt458 なら、この時点のアドレスによってコマンド処理 ! 429: uint addr = idx / 3; ! 430: switch (addr) { ! 431: case 0x04: ! 432: data = readmask; ! 433: putlog(2, "Read ReadMask -> $%02x", data); ! 434: break; ! 435: case 0x05: ! 436: data = blinkmask; ! 437: putlog(2, "Read BlinkMask -> $%02x", data); ! 438: break; ! 439: case 0x06: ! 440: data = command; ! 441: putlog(2, "Read Command -> $%02x", data); ! 442: break; ! 443: case 0x07: ! 444: data = testreg; ! 445: putlog(2, "Read Test -> $%02x", data); ! 446: break; ! 447: default: ! 448: data = 0; ! 449: putlog(0, "Read $%02x (NOT IMPLEMENTED)", addr); ! 450: break; ! 451: } ! 452: } ! 453: ! 454: return data; ! 455: } ! 456: ! 457: // アドレスレジスタ書き込み。 ! 458: void ! 459: BT45xDevice::WriteAddress(uint32 data) ! 460: { ! 461: // 今からアクセスするパレット番号。 ! 462: // アドレスレジスタアクセスで ab カウンタは 0 にリセットされる。 ! 463: // data はパレット番号だが idx は配列のインデックスなので 3倍。 ! 464: putlog(2, "Address Register <- $%02x", data); ! 465: if (bt454) { ! 466: data >>= 4; ! 467: } ! 468: idx = data * 3; ! 469: } ! 470: ! 471: // パレットレジスタ書き込み。 ! 472: void ! 473: BT45xDevice::WritePalette(uint32 data) ! 474: { ! 475: // Bt454 なら上位下位4ビットに同じ値を置くことで 0 .. 255 にする。 ! 476: if (bt454) { ! 477: data = (data & 0xf0) | ((data >> 4) & 0x0f); ! 478: } ! 479: color[idx] = data; ! 480: ! 481: if (loglevel == 1) { ! 482: // ログレベル1なら RGB が書き込まれた時点で表示。 ! 483: // 大体はこれくらいの表示で構わないはず。 ! 484: if (idx % 3 == 2) { ! 485: if (bt454) { ! 486: putlogn("Color Palette $%x = (%x,%x,%x)", ! 487: idx / 3, ! 488: color[idx - 2] >> 4, ! 489: color[idx - 1] >> 4, ! 490: color[idx ] >> 4); ! 491: } else { ! 492: putlogn("Color Palette $%02x = (%02x,%02x,%02x)", ! 493: idx / 3, ! 494: color[idx - 2], ! 495: color[idx - 1], ! 496: color[idx ]); ! 497: } ! 498: } ! 499: } else if (loglevel >= 2) { ! 500: if (bt454) { ! 501: putlogn("Color Palette $%x(%c) <- $%02x", ! 502: idx / 3, rgbstr[idx % 3], data); ! 503: } else { ! 504: putlogn("Color Palette $%02x(%c) <- $%02x", ! 505: idx / 3, rgbstr[idx % 3], data); ! 506: } ! 507: } ! 508: ! 509: // ホストカラーを計算。 ! 510: // (Bt458 では?) Blue を書き込んだところで色情報がストアされるっぽい? ! 511: MakeHostColor(idx); ! 512: Notify(); ! 513: ! 514: // ホストカラー計算後にインクリメントする。 ! 515: idx++; ! 516: if (idx >= color.size()) { ! 517: idx = 0; ! 518: } ! 519: } ! 520: ! 521: // Bt454 ならリセット(?)、 ! 522: // Bt458 なら各種制御レジスタへの書き込み。 ! 523: void ! 524: BT45xDevice::WriteControl(uint32 data) ! 525: { ! 526: if (bt454) { ! 527: // ab カウンタを 0 にする? データは無視されるようだ ! 528: idx = (idx / 3) * 3; ! 529: putlog(2, "reset ab"); ! 530: } else { ! 531: // Bt458 なら、この時点のアドレスによってコマンド処理。 ! 532: uint addr = idx / 3; ! 533: switch (addr) { ! 534: case 0x04: ! 535: WriteRMask(data); ! 536: break; ! 537: case 0x05: ! 538: WriteBMask(data); ! 539: break; ! 540: case 0x06: ! 541: WriteCommand(data); ! 542: break; ! 543: case 0x07: ! 544: WriteTest(data); ! 545: break; ! 546: default: ! 547: putlog(1, "Unknown command $%02x <- $%02x", addr, data); ! 548: break; ! 549: } ! 550: } ! 551: } ! 552: ! 553: // Bt458 Read Mask の書き込み。 ! 554: void ! 555: BT45xDevice::WriteRMask(uint32 data) ! 556: { ! 557: readmask = data; ! 558: putlog(1, "Write ReadMask <- $%02x", readmask); ! 559: } ! 560: ! 561: // Bt458 Blink Mask の書き込み。 ! 562: void ! 563: BT45xDevice::WriteBMask(uint32 data) ! 564: { ! 565: // 未実装 ! 566: blinkmask = data; ! 567: if (blinkmask != 0x00) { ! 568: putlog(0, "Write BlinkMask <- $%02x (NOT IMPLEMENTED)", blinkmask); ! 569: } else { ! 570: putlog(1, "Write BlinkMask <- $%02x", blinkmask); ! 571: } ! 572: } ! 573: ! 574: // Bt458 コマンドレジスタへの書き込み。 ! 575: void ! 576: BT45xDevice::WriteCommand(uint32 data) ! 577: { ! 578: command = data; ! 579: putlog(1, "Write Command <- $%02x", command); ! 580: ! 581: // 未実装 ! 582: if ((command & 0x80)) { ! 583: putlog(0, "5:1 Multiplex (NOT IMPLEMENTED)"); ! 584: } ! 585: if ((command & 0x40) == 0) { ! 586: putlog(0, "Use overlay color0 (NOT IMPLEMENTED)"); ! 587: } ! 588: if ((command & 0x0c)) { ! 589: putlog(0, "Blink enable (NOT IMPLEMENTED)"); ! 590: } ! 591: if ((command & 0x03)) { ! 592: putlog(0, "Display enable (NOT IMPLEMENTED)"); ! 593: } ! 594: } ! 595: ! 596: // テストレジスタへの書き込み。 ! 597: void ! 598: BT45xDevice::WriteTest(uint32 data) ! 599: { ! 600: // 未実装 ! 601: testreg = data; ! 602: if (testreg != 0x00) { ! 603: putlog(0, "Write Test <- $%02x (NOT IMPLEMENTED)", testreg); ! 604: } else { ! 605: // カーネルが初期化時にアクセスに来る ! 606: putlog(1, "Write Test <- $%02x (NOT IMPLEMENTED)", testreg); ! 607: } ! 608: } ! 609: ! 610: // 制御レジスタを読み出す。(Peek() 用) ! 611: uint32 ! 612: BT45xDevice::PeekControl() const ! 613: { ! 614: if (bt454) { ! 615: return 0x00; ! 616: } else { ! 617: uint addr = idx / 3; ! 618: switch (addr) { ! 619: case 0x04: ! 620: return readmask; ! 621: case 0x05: ! 622: return blinkmask; ! 623: case 0x06: ! 624: return command; ! 625: case 0x07: ! 626: return testreg; ! 627: default: ! 628: // XXX ? ! 629: return 0; ! 630: } ! 631: } ! 632: } ! 633: ! 634: // ゲストパレットを uint32 形式にしたものの一覧を返す。(GUI 用) ! 635: const std::vector<uint32> ! 636: BT45xDevice::GetIntPalette() const ! 637: { ! 638: std::vector<uint32> ipal; ! 639: ! 640: if (bt454) { ! 641: for (int i = 0; i < palettes; i++) { ! 642: ipal.push_back(Palette454ToInt(i)); ! 643: } ! 644: } else { ! 645: for (int i = 0; i < palettes; i++) { ! 646: ipal.push_back(Palette458ToInt(i)); ! 647: } ! 648: } ! 649: return ipal; ! 650: } ! 651: ! 652: // Bt454 のパレット番号 n の生データを uint32 で返す。 ! 653: // Bt454 の場合は RGB 各4ビットを右詰め。$0000'0RGB。 ! 654: uint32 ! 655: BT45xDevice::Palette454ToInt(int n) const ! 656: { ! 657: return ((color[n * 3 + 0] & 0xf0) << 4) | ! 658: ((color[n * 3 + 1] & 0xf0) ) | ! 659: ((color[n * 3 + 2] & 0x0f) ); ! 660: } ! 661: ! 662: // Bt458 のパレット番号 n の生データを uint32 で返す。 ! 663: // Bt458 の場合は RGB 各8ビットを右詰め。$00RR'GGBB。 ! 664: uint32 ! 665: BT45xDevice::Palette458ToInt(int n) const ! 666: { ! 667: return (color[n * 3 + 0] << 16) | ! 668: (color[n * 3 + 1] << 8) | ! 669: color[n * 3 + 2]; ! 670: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.