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