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