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