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