|
|
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.