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