|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
1.1.1.2 root 8: // LUNA ビットマッププレーン
1.1 root 9: //
10:
11: // SX-9100 のほうはこう書いてあってこっちが正しいようだ。
12: // +00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
13: // b100 |RF| |BS| |共 通 B M P|プレーン#0 |
14: // b110 |プレーン#1 |プレーン#2 |プレーン#3 |プレーン#4 |
15: // b120 |プレーン#5 |プレーン#6 |プレーン#7 |FC| |
16: // b130 |F0| |F1| |F2| |F3| |
17: // b140 |F4| |F5| |F6| |F7| |
18: //
19: // SX-7100 のほうはこう書いてあるがこうはなっていないようだ。
20: // +00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
21: // b100 |RF| |BS| |共 通 B M P|FC| |
22: // b110 |プレーン#0 |プレーン#1 |プレーン#2 |プレーン#3 |
23: // b120 |プレーン#4 |プレーン#5 |プレーン#6 |プレーン#7 |
24: // b130 |F0| |F1| |F2| |F3| |
25: // b140 |F4| |F5| |F6| |F7| |
26: //
27: // RF: RFCNT (4バイト)
28: // BS: BMSEL (4バイト)
29: // FC: 共通ファンクションセット
30: // Fn: プレーン#n ファンクションセット
31: // 1区画が 64KB。空白のところは未調査。
32: // 未装着のプレーン(#4..#7とか)は 0xff が読めるようだ。
33: // ファンクションセットが 64バイトで折り返してるか未調査だが、
34: // b130'0000 も b133'0000 も 0xff が読めるのでこの範囲全域でミラーかも。
35: // b150'0000 以降(b1ff'ffffまで) は BUSERR のようだ。
36:
1.1.1.2 root 37: // Lunafb の VRAM はロングワード単位でホストバイトオーダ配置なので、
38: // バイトアクセス、ワードアクセス時は HLB(), HLW() マクロを使用のこと。
39:
40: #include "lunafb.h"
41: #include "bt454.h"
1.1.1.3 ! root 42: #include "builtinrom.h"
1.1.1.2 root 43: #include "config.h"
44: #include "mpu.h"
1.1 root 45:
1.1.1.2 root 46: // コンストラクタ
1.1 root 47: LunafbDevice::LunafbDevice()
1.1.1.2 root 48: : inherited("Lunafb", 2048, 1024)
1.1 root 49: {
50: devaddr = 0xb1000000;
51:
1.1.1.2 root 52: modify_mask = 0xffff;
53:
54: monitor.func = ToMonitorCallback(&LunafbDevice::MonitorUpdate);
1.1 root 55: monitor.SetSize(42, 11);
1.1.1.2 root 56: monitor.Regist(ID_MONITOR_LUNAVC);
1.1 root 57: }
58:
1.1.1.2 root 59: // デストラクタ
1.1 root 60: LunafbDevice::~LunafbDevice()
61: {
62: }
63:
1.1.1.2 root 64: // 初期化。
65: //
66: // 呼び出し順が際どいので注意。Lunafb::Init() と BT454::Init() とが相互に
67: // 参照しているが、このうち Lunafb::Init() が呼んでる BT454::GetHostPalette()
68: // は BT454::Init() 実行前でも取得できる。逆に BT454::Init() が呼んでる
69: // Lunafb::GetPlaneCount() は Lunafb::Init() の後でないと行えないので、
70: // vm_luna.cpp での初期化順は PlaneVRAM -> BT454 の順を維持すること。
1.1 root 71: bool
72: LunafbDevice::Init()
73: {
1.1.1.2 root 74: const ConfigItem& item = gConfig->Find("luna-video-plane");
75: if (item.TryInt(&nplane) == false) {
76: item.Err();
77: return false;
78: }
79: if (nplane != 1 && nplane != 4) {
80: item.Err("must be 1 or 4");
81: return false;
82: }
83:
1.1 root 84: plane_end = plane0base + 0x40000 * nplane;
1.1.1.3 ! root 85: fcset_end = fcset0base + 0x40000 * nplane;
1.1 root 86:
87: // プレーン数によってメモリを確保
88: mem.reset(new uint8 [0x40000 * nplane]);
89:
1.1.1.2 root 90: // ホストパレットを取得。
91: palette = gBT454->GetHostPalette();
1.1 root 92:
93: return true;
94: }
95:
1.1.1.2 root 96: // 電源オン/リセット
1.1 root 97: void
1.1.1.2 root 98: LunafbDevice::ResetHard(bool poweron)
1.1 root 99: {
1.1.1.2 root 100: if (poweron) {
101: // XXX 実際は不定値だと思うけど、観測手段がないのでとりあえず。
102: memset(&mem[0], 0xff, 0x40000 * nplane);
103: }
104:
1.1 root 105: // 厳密にどの時点でリセットされるのかは知らないけど
106: bmsel = 0;
107:
108: // XXX 初期値の観測は困難なので適当
109: rfcnt = 0;
1.1.1.2 root 110: xscroll = 0;
111: yscroll = 0;
1.1 root 112:
113: for (int i = 0; i < MAX_PLANES; i++) {
1.1.1.2 root 114: fcset[i] = 5;
115: fcmask[i] = 0xffffffff;
1.1 root 116: }
117:
118: // XXX ここ?
119: Invalidate();
120: }
121:
122: uint64
123: LunafbDevice::Read8(uint32 addr)
124: {
125: // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
126: gMPU->AddCycle(1);
127:
128: if (plane0base <= addr && addr < plane_end) {
129: // プレーンの読み出し
130: return mem[HLB(addr - plane0base)];
131: }
1.1.1.3 ! root 132: // 残りは書き込み専用または不在
! 133: putlog(1, "Read not-readable $%08x.B", addr);
1.1 root 134: return 0xff;
135: }
136:
137: uint64
138: LunafbDevice::Read16(uint32 addr)
139: {
140: // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
141: gMPU->AddCycle(1);
142:
143: if (plane0base <= addr && addr < plane_end) {
144: // プレーンの読み出し
145: return *(uint16 *)&mem[HLW(addr - plane0base)];
146: }
1.1.1.3 ! root 147: // 残りは書き込み専用または不在
! 148: putlog(1, "Read not-readable $%08x.W", addr);
1.1 root 149: return 0xffff;
150: }
151:
152: uint64
153: LunafbDevice::Read32(uint32 addr)
154: {
155: // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
156: gMPU->AddCycle(1);
157:
158: if (plane0base <= addr && addr < plane_end) {
159: // プレーンの読み出し
160: return *(uint32 *)&mem[addr - plane0base];
161: }
1.1.1.3 ! root 162: // 残りは書き込み専用または不在
! 163: putlog(1, "Read not-readable $%08x.L", addr);
1.1 root 164: return 0xffffffff;
165: }
166:
167: uint64
168: LunafbDevice::Write8(uint32 addr, uint32 data)
169: {
170: // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
171: gMPU->AddCycle(1);
172:
173: switch (addr) {
174: case 0xb1000000:
175: case 0xb1000001:
176: case 0xb1000002:
177: case 0xb1000003:
178: // このロングワード内へのバイトアクセスはロングワードにミラーされる
179: data = (data << 24) | (data << 16) | (data << 8) | data;
180: return Write32(addr & ~3, data);
181: case 0xb1040000:
182: case 0xb1040001:
183: case 0xb1040002:
184: case 0xb1040003:
185: // BMSEL はバイトアクセスできる?
1.1.1.3 ! root 186: putlog(0, "BMSEL $%08x <- $%02x (NOT IMPLEMENTED)", addr, data);
1.1 root 187: return 0;
188: }
189:
190: if (addr < 0xb1080000) {
1.1.1.3 ! root 191: // 空き。どうなる?
! 192: putlog(0, "Vacant $%08x <- $%02x (NOT IMPLEMENTED)", addr, data);
1.1 root 193: return 0;
194: }
195: if (addr < plane0base) {
196: // 共通ビットマッププレーン
197: WriteCommonBitmap8(addr, data);
198: return 0;
199: }
200:
1.1.1.3 ! root 201: if (__predict_true(addr < plane_end)) {
! 202: // 存在するビットマッププレーン
1.1 root 203: uint32 reladdr = addr - plane0base;
204: uint plane = reladdr / 0x40000;
205: uint32 offset = reladdr % 0x40000;
206:
1.1.1.3 ! root 207: putlog(2, "Plane%d $%08x <- $%02x", plane, addr, data);
! 208: WritePlane8(plane, offset, data);
! 209: SetDirty(offset);
! 210: return 0;
! 211: }
! 212:
! 213: if (addr < plane7end) {
! 214: // HW 設定によっては存在しないプレーン
! 215: uint32 reladdr = addr - plane0base;
! 216: uint plane = reladdr / 0x40000;
! 217: putlog(3, "Not-equipped Plane%d $%08x <- $%02x", plane, addr, data);
1.1 root 218: return 0;
219: }
220:
1.1.1.3 ! root 221: // XXX ファンクションセットはバイトアクセスだとどうなる?
! 222: putlog(0, "$%08x <- $%02x (NOT IMPLEMENTED)", addr, data);
1.1 root 223: return 0;
224: }
225:
226: uint64
227: LunafbDevice::Write16(uint32 addr, uint32 data)
228: {
229: // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
230: gMPU->AddCycle(1);
231:
232: switch (addr) {
233: case 0xb1000000:
234: case 0xb1000002:
235: // このロングワード内へのワードアクセスはロングワードにミラーされる
236: data = (data << 16) | data;
237: return Write32(addr & ~3, data);
238: case 0xb1040000:
239: case 0xb1040002:
240: // BMSEL はワードアクセスできる?
1.1.1.3 ! root 241: putlog(0, "BMSEL $%08x <- $%04x (NOT IMPLEMENTED)", addr, data);
1.1 root 242: return 0;
243: }
244:
245: if (addr < 0xb1080000) {
1.1.1.3 ! root 246: // 空き。どうなる?
! 247: putlog(0, "Vacant $%08x <- $%04x (NOT IMPLEMENTED)", addr, data);
1.1 root 248: return 0;
249: }
250: if (addr < plane0base) {
251: // 共通ビットマッププレーン
252: WriteCommonBitmap16(addr, data);
253: return 0;
254: }
255:
1.1.1.3 ! root 256: if (__predict_true(addr < plane_end)) {
! 257: // 存在するビットマッププレーン
1.1 root 258: uint32 reladdr = addr - plane0base;
259: uint plane = reladdr / 0x40000;
260: uint32 offset = reladdr % 0x40000;
261:
1.1.1.3 ! root 262: putlog(2, "Plane%d $%08x <- $%04x", plane, addr, data);
! 263: WritePlane16(plane, offset, data);
! 264: SetDirty(offset);
1.1 root 265: return 0;
266: }
267:
1.1.1.3 ! root 268: if (addr < plane7end) {
! 269: // HW 設定によっては存在しないプレーン
! 270: uint32 reladdr = addr - plane0base;
! 271: uint plane = reladdr / 0x40000;
! 272: putlog(3, "Not-equipped Plane%d $%08x <- $%04x", plane, addr, data);
! 273: return 0;
! 274: }
! 275:
! 276: // XXX ファンクションセットはワードアクセスだとどうなる?
! 277: putlog(0, "$%08x <- $%04x (NOT IMPLEMENTED)", addr, data);
1.1 root 278: return 0;
279: }
280:
281: uint64
282: LunafbDevice::Write32(uint32 addr, uint32 data)
283: {
284: // XXX とりあえず RAM と同じウェイトを入れておく (未調査)
285: gMPU->AddCycle(1);
286:
287: switch (addr) {
288: case 0xb1000000:
289: // RFCNT
290: WriteRFCNT(data);
291: return 0;
292:
293: case 0xb1040000:
294: // BMSEL
295: bmsel = data & 0xf;
296: putlog(1, "BMSEL <- $%08x", data);
297: return 0;
298: }
299:
300: if (addr < 0xb1080000) {
1.1.1.3 ! root 301: putlog(0, "Vacant $%08x <- $%08x (NOT IMPLEMENTED)", addr, data);
1.1 root 302: return 0;
303: }
304: if (addr < plane0base) {
305: // 共通ビットマッププレーン
306: WriteCommonBitmap32(addr, data);
307: return 0;
308: }
309:
1.1.1.3 ! root 310: if (__predict_true(addr < plane_end)) {
! 311: // 存在するビットマッププレーン
1.1 root 312: uint32 reladdr = addr - plane0base;
313: uint plane = reladdr / 0x40000;
314: uint32 offset = reladdr % 0x40000;
315:
1.1.1.3 ! root 316: putlog(3, "Plane%d $%08x <- $%08x", plane, addr, data);
! 317: WritePlane32(plane, offset, data);
! 318: SetDirty(offset);
! 319: return 0;
! 320: }
! 321:
! 322: if (__predict_false(addr < plane7end)) {
! 323: // HW 設定によっては存在しないプレーン
! 324: uint32 reladdr = addr - plane0base;
! 325: uint plane = reladdr / 0x40000;
! 326: putlog(3, "Not-equipped Plane%d $%08x <- $%08x", plane, addr, data);
1.1 root 327: return 0;
328: }
329:
330: if (addr < 0xb1300000) {
331: // 共通ファンクションセット
332: uint rop = (addr & 0x3f) / 4;
1.1.1.3 ! root 333: putlog(2, "Common FCSet $%08x <- $%08x (%s)",
1.1 root 334: addr, data, RopStr(rop));
1.1.1.2 root 335: WriteCommonFCSet(rop, data);
1.1 root 336: return 0;
337: }
338:
1.1.1.3 ! root 339: if (__predict_true(addr < fcset_end)) {
! 340: // 存在するファンクションセット
1.1 root 341: int plane = (addr - 0xb1300000) / 0x40000;
1.1.1.3 ! root 342: uint rop = (addr & 0x3f) / 4;
! 343: putlog(2, "FCSet%d $%08x <- $%08x (%s)",
1.1 root 344: plane, addr, data, RopStr(rop));
1.1.1.3 ! root 345: fcset[plane] = rop;
! 346: fcmask[plane] = data;
! 347: return 0;
! 348: }
! 349:
! 350: if (addr < fcset7end) {
! 351: // HW 設定によっては存在しないファンクションセット
! 352: int plane = (addr - 0xb1300000) / 0x40000;
! 353: putlog(3, "Not-equipped FCSet%d $%08x <- $%08x", plane, addr, data);
1.1 root 354: return 0;
355: }
356:
1.1.1.3 ! root 357: // 残りは全部空きのはずだが挙動未調査。
! 358: putlog(0, "$%08x <- $%08x (NOT IMPLEMENTED)", addr, data);
1.1 root 359: return 0;
360: }
361:
362: uint64
363: LunafbDevice::Peek8(uint32 addr)
364: {
365: if (plane0base <= addr && addr < plane_end) {
366: // プレーンの読み出し
367: return mem[HLB(addr - plane0base)];
368: }
369: // 残りは書き込み専用
370: return 0xff;
371: }
372:
373: void
374: LunafbDevice::MonitorUpdate(Monitor *, TextScreen& screen)
375: {
376: int i;
377:
378: screen.Clear();
379:
380: // 0 1 2 3 4
381: // 012345678901234567890123456789012345678901
382: // RFCNT: $12345678 (X=-123dot, Y=1023dot)
383: //
384: // BMSEL=$4 ROP Mask RGB RGB
385: // Plane#0 Sel THRU $ffffffff $0:RGB $8:RGB
386: screen.Print(0, 0, "RFCNT: $%08x (X=%ddot, Y=%ddot)",
1.1.1.2 root 387: rfcnt, xscroll, yscroll);
1.1 root 388: screen.Print(3, 2, "BMSEL=$%x ROP Mask", bmsel);
389:
390: for (i = 0; i < nplane; i++) {
391: screen.Print(0, 3 + i, "Plane#%d %s %s $%08x",
392: i,
393: (bmsel & (1 << i)) ? "Sel" : "---",
1.1.1.2 root 394: RopStr(fcset[i]), fcmask[i]);
1.1 root 395: }
396: for (; i < MAX_PLANES; i++) {
397: screen.Print(0, 3 + i, TA::Disable, "Plane#%d (Not installed)", i);
398: }
399:
400: // ついでなのでここで BT454 のパレットも表示。
401: // 012345
402: // $0:RGB
403: const uint8 *pal = gBT454->reg.color;
404: screen.Puts(29, 1, "<BT454>");
405: screen.Puts(32, 2, "RGB RGB");
406: for (i = 0; i < 16; i++) {
407: uint rgb =
408: ((pal[i * 3 + 0] & 0xf0) << 4) +
409: ((pal[i * 3 + 1] & 0xf0) ) +
410: ((pal[i * 3 + 2] & 0xf0) >> 4);
411: screen.Print(29 + (i / 8) * 7, (i % 8) + 3, "$%x:%03x", i, rgb);
412: }
413: }
414:
1.1.1.2 root 415: // offset の位置に対応する更新フラグを立てる。
416: // offset はプレーン先頭から (VRAM 先頭からでも同じ) のバイトオフセット。
417: inline void
418: LunafbDevice::SetDirty(uint32 offset)
419: {
420: // VRAM は横 2048 ドット(256バイト) x 縦 1024 ドットで、これを
421: // 横 128 ドット(16バイト) x 縦 16 ドットずつのブロックに分割する。
422: // ブロック数は横 16個 x 縦 64個。
423: //
424: // 1 0
425: // 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
426: // +-----------+-------+-------+-------+-----+
427: // VRAM | Y座標 (1024dot) | X (256byte) : 8bit|
428: // +-----------+-------+-------+-------+-----+
429: // : : : : :
430: // +-----------+-------+-------+-------------+
431: // Block | Y(64blks) | 16dot | X(16) | 128dot | *: X は 16 blocks
432: // +-----------+-------+-------+-------------+
433: // \ \ | |
434: // \ \ | |
435: // \ \ | |
436: // +-----------+-------+
437: // Dirty | Y(64blks) | X(16) |
438: // +-----------+-------+
439: // 9 8 7 6 5 4 3 2 1 0
440:
441: // x 座標(バイト単位 8 bit)の上位 4 bit
442: int x = (offset >> 4) & 0x0f;
443: // y 座標(10bit) の上位 6 bit
444: int y = (offset >> 8) & 0x3f0;
445:
446: // からインデックスを求める
447: int b = x + y;
448:
449: dirty[b] = 1;
450:
451: #if defined(PERF_HIT)
452: // どのロングワードが更新されたか
453: dirty_word[offset >> 2] = true;
454: #endif
1.1 root 455: }
456:
457: // RFCNT への書き込み
458: void
459: LunafbDevice::WriteRFCNT(uint32 data)
460: {
461: // レジスタ値
462: rfcnt = data;
463:
464: // 水平オフセットを計算
465: // XXX マニュアルでは -8 まで指定できるように読めるが
466: // 指定する方法が分からない。
467: // XXX 193 以上を指定するとどうなるのか (とりあえずほっとく)
468: // 実機の挙動を目分量で見ると、右にはみ出た部分は
469: // 256 ラスタ先のラスタデータを描画しているようだ。
1.1.1.2 root 470: xscroll = ((rfcnt >> 16) & 0xff) + 8;
471: xscroll *= 4;
1.1 root 472:
473: // ラスタ(垂直)カウンタ
1.1.1.2 root 474: yscroll = (rfcnt + 26) & 0x3ff;
1.1 root 475:
476: // 全画面更新
477: Invalidate();
478:
1.1.1.3 ! root 479: putlog(1, "RFCNT <- $%08x (H=%ddot, V=%ddot)", data, xscroll, yscroll);
1.1 root 480: }
481:
482: // 共通ビットマッププレーン バイト書き込み
483: void
484: LunafbDevice::WriteCommonBitmap8(uint32 addr, uint32 data)
485: {
486: uint32 offset = addr - 0xb1080000;
1.1.1.3 ! root 487: putlog(2, "Common Plane $%08x <- $%02x", addr, data);
1.1 root 488: for (int i = 0; i < nplane; i++) {
489: if ((bmsel & (1 << i))) {
490: WritePlane8(i, offset, data);
491: }
492: }
1.1.1.2 root 493: SetDirty(offset);
1.1 root 494: }
495:
496: // 共通ビットマッププレーン ワード書き込み
497: void
498: LunafbDevice::WriteCommonBitmap16(uint32 addr, uint32 data)
499: {
500: uint32 offset = addr - 0xb1080000;
1.1.1.3 ! root 501: putlog(2, "Common Plane $%08x <- $%04x", addr, data);
1.1 root 502: for (int i = 0; i < nplane; i++) {
503: if ((bmsel & (1 << i))) {
504: WritePlane16(i, offset, data);
505: }
506: }
1.1.1.2 root 507: SetDirty(offset);
1.1 root 508: }
509:
510: // 共通ビットマッププレーン ロング書き込み
511: void
512: LunafbDevice::WriteCommonBitmap32(uint32 addr, uint32 data)
513: {
514: uint32 offset = addr - 0xb1080000;
1.1.1.3 ! root 515: putlog(2, "Common Plane $%08x <- $%08x", addr, data);
1.1 root 516: for (int i = 0; i < nplane; i++) {
517: if ((bmsel & (1 << i))) {
518: WritePlane32(i, offset, data);
519: }
520: }
1.1.1.2 root 521: SetDirty(offset);
1.1 root 522: }
523:
1.1.1.2 root 524: // 共通ファンクションセット設定
525: void
526: LunafbDevice::WriteCommonFCSet(uint rop, uint32 data)
527: {
528: for (int i = 0; i < nplane; i++) {
529: if ((bmsel & (1 << i))) {
530: fcset[i] = rop;
531: fcmask[i] = data;
532: }
533: }
534: }
535:
536: // 現在の VRAM の値 vram と、書き込まれた値 data から
537: // 演算後 VRAM に書き戻すことになる値を返す。
538: // ここではマスクはまだ評価しない。
539: /*static*/ uint32
540: LunafbDevice::RasterOp(uint rop, uint32 vram, uint32 data)
1.1 root 541: {
542: switch (rop) {
1.1.1.2 root 543: case ROP::ZERO:
544: vram = 0;
1.1 root 545: break;
1.1.1.2 root 546: case ROP::AND1:
547: vram = vram & data;
1.1 root 548: break;
1.1.1.2 root 549: case ROP::AND2:
550: vram = vram & ~data;
1.1 root 551: break;
1.1.1.2 root 552: case ROP::cmd:
553: // 使用不可。本当はここにシリアルモード変更コマンドがあるらしい。
554:
555: // ログを出すためにはインスタンスが必要だが、普段は static 関数で
556: // 十分なので、ログを出す時だけグローバルインスタンスを参照する。
557: if (gPlaneVRAM->loglevel >= 0) {
558: gPlaneVRAM->putlogn("ROP 3 is used");
559: }
1.1 root 560: break;
1.1.1.2 root 561: case ROP::AND3:
562: vram = ~vram & data;
1.1 root 563: break;
1.1.1.2 root 564: case ROP::THRU:
565: vram = data;
1.1 root 566: break;
1.1.1.2 root 567: case ROP::EOR:
568: vram = vram ^ data;
1.1 root 569: break;
1.1.1.2 root 570: case ROP::OR1:
571: vram = vram | data;
1.1 root 572: break;
1.1.1.2 root 573: case ROP::NOR:
574: vram = ~vram & ~data;
1.1 root 575: break;
1.1.1.2 root 576: case ROP::ENOR:
577: vram = (vram & data) | (~vram & ~data);
1.1 root 578: break;
1.1.1.2 root 579: case ROP::INV1:
580: vram = ~data;
1.1 root 581: break;
1.1.1.2 root 582: case ROP::OR2:
583: vram = vram | ~data;
1.1 root 584: break;
1.1.1.2 root 585: case ROP::INV2:
586: vram = ~vram;
1.1 root 587: break;
1.1.1.2 root 588: case ROP::OR3:
589: vram = ~vram | data;
1.1 root 590: break;
1.1.1.2 root 591: case ROP::NAND:
592: vram = ~vram | ~data;
1.1 root 593: break;
1.1.1.2 root 594: case ROP::ONE:
595: vram = 0xffffffff;
1.1 root 596: break;
1.1.1.2 root 597: default:
598: __unreachable();
1.1 root 599: }
1.1.1.2 root 600: return vram;
1.1 root 601: }
602:
603: // ROP 文字列を返す
604: const char *
605: LunafbDevice::RopStr(uint rop)
606: {
607: static const char * ropstr[] = {
608: "ZERO",
609: "AND1",
610: "AND2",
611: "(3)",
612: "AND3",
613: "THRU", // THROUGH
614: "EOR",
615: "OR1",
616: "NOR",
617: "ENOR",
618: "INV1",
619: "OR2",
620: "INV2",
621: "OR3",
622: "NAND",
623: "ONE",
624: };
625: return ropstr[rop];
626: }
627:
1.1.1.2 root 628: // 個別プレーンへのバイト書き込み
629: // (dirty は変更しない)
1.1 root 630: void
631: LunafbDevice::WritePlane8(uint plane, uint32 offset, uint32 data)
632: {
633: uint32 memoffset = plane * 0x40000 + offset;
1.1.1.2 root 634: uint32 vram;
635: uint32 mask;
1.1 root 636:
1.1.1.2 root 637: vram = mem[HLB(memoffset)];
638: data = RasterOp(fcset[plane], vram, data);
639: mask = fcmask[plane] >> (24 - (memoffset & 3) * 8);
640: mem[HLB(memoffset)] = (data & mask) | (vram & ~mask);
1.1 root 641: }
642:
1.1.1.2 root 643: // 個別プレーンへのワード書き込み
644: // (dirty は変更しない)
1.1 root 645: void
646: LunafbDevice::WritePlane16(uint plane, uint32 offset, uint32 data)
647: {
648: uint32 memoffset = plane * 0x40000 + offset;
1.1.1.2 root 649: uint32 vram;
650: uint32 mask;
1.1 root 651:
1.1.1.2 root 652: vram = *(uint16 *)&mem[HLW(memoffset)];
653: data = RasterOp(fcset[plane], vram, data);
1.1 root 654: if ((memoffset & 2) == 0) {
655: // 上位ワード
1.1.1.2 root 656: mask = fcmask[plane] >> 16;
1.1 root 657: } else {
658: // 下位ワード
1.1.1.2 root 659: mask = fcmask[plane];
1.1 root 660: }
1.1.1.2 root 661: *(uint16 *)&mem[HLW(memoffset)] = (data & mask) | (vram & ~mask);
1.1 root 662: }
663:
1.1.1.2 root 664: // 個別プレーンへのロングワード書き込み
665: // (dirty は変更しない)
1.1 root 666: void
667: LunafbDevice::WritePlane32(uint plane, uint32 offset, uint32 data)
668: {
669: uint32 memoffset = plane * 0x40000 + offset;
1.1.1.2 root 670: uint32 vram;
671: uint32 mask;
1.1 root 672:
1.1.1.2 root 673: vram = *(uint32 *)&mem[memoffset];
674: data = RasterOp(fcset[plane], vram, data);
675: mask = fcmask[plane];
676: *(uint32 *)&mem[memoffset] = (data & mask) | (vram & ~mask);
1.1 root 677: }
678:
679:
680: // エミュレータによる画面出力
681: //
682: // VM 内からの操作ではなく、エミュレータ本体から画面を操作する
683: // エミュレーション ROM によるモニタコンソール用の機能。
1.1.1.2 root 684: // サービスを使いたい側 (EmuROM など) は EmuInitScreen() をコールすると
685: // (現在のパレットのまま) 画面をクリアする。
686: // 以降は EmuPutc() で文字を表示する。
1.1 root 687:
1.1.1.2 root 688: // エミュレータ出力用に画面を初期化する
689: void
690: LunafbDevice::EmuInitScreen()
691: {
1.1 root 692: // 同時書き込み設定
693: bmsel = (1 << nplane) - 1;
694:
1.1.1.2 root 695: // ROP を初期化
696: WriteCommonFCSet(ROP::THRU, 0xffffffff);
697:
1.1 root 698: // 全画面をクリア
1.1.1.2 root 699: EmuFill(0, 0, 2048, 1024, 0);
700: }
701:
702: // 矩形領域を data で埋める。
703: void
704: LunafbDevice::EmuFill(uint x, uint y, uint w, uint h, uint32 data)
705: {
706: // ロングワードアラインしていないケースは対応しない
707: assert(x % 32 == 0);
708: assert(w % 32 == 0);
709:
710: for (uint py = y; py < y + h; py++) {
711: uint32 addr = 0xb1080000 + (x / 32) * 4 + py * 256;
712: for (uint px = x; px < x + w; px += 32) {
713: WriteCommonBitmap32(addr, data);
714: addr += 4;
715: }
1.1 root 716: }
717: }
718:
1.1.1.2 root 719: // ピクセル座標 x, y を左上として文字 c を出力。
720: // 文字が VRAM からはみ出ないようにすること。
1.1 root 721: void
1.1.1.2 root 722: LunafbDevice::EmuPutc(uint x, uint y, uint c)
1.1 root 723: {
1.1.1.2 root 724: EmuPutc(x, y, c, ROP::THRU);
725: }
726:
727: // ピクセル座標 x, y を左上として文字 c を出力。
728: // 文字が VRAM からはみ出ないようにすること。
729: void
730: LunafbDevice::EmuPutc(uint x, uint y, uint c, int rop)
731: {
732: uint32 addr = 0xb1080000 + (x / 32) * 4 + y * 256;
733: uint32 bofs = x % 32;
734:
735: // マスク設定。上から 12bit にマスクを置いといて..
736: union64 mask {};
737: mask.h = 0xfff00000;
738:
739: // うまい具合にシフト
740: mask.q >>= bofs;
741:
742: // その文字のフォントデータ上でのアドレス
1.1.1.3 ! root 743: const uint8 * const fontaddr = Builtin::CGROM12x24(c & 0xff);
1.1.1.2 root 744:
745: for (int i = 0; i < 24; i++) {
746: // その文字のフォントデータ。
747: // データは MSB 側 12bit に入っているのでこれを 64bit MSB 詰めにする
748: union64 data {};
749: data.h = be16toh(*(const uint16*)(fontaddr + i * 2)) << 16;
750:
751: // うまい具合にシフト
752: data.q >>= bofs;
753:
754: WriteCommonFCSet(rop, mask.h);
755: WriteCommonBitmap32(addr, data.h);
756: if (mask.l) {
757: WriteCommonFCSet(rop, mask.l);
758: WriteCommonBitmap32(addr + 4, data.l);
759: }
760: addr += 256; // 1ライン進める
1.1 root 761: }
762:
1.1.1.2 root 763: // ROP を元に戻す
764: WriteCommonFCSet(ROP::THRU, 0xffffffff);
1.1 root 765: }
766:
1.1.1.2 root 767: // 画面を縦スクロールさせる。上スクロールのみサポート。
1.1 root 768: void
1.1.1.2 root 769: LunafbDevice::EmuScrollY(uint dy, uint sy, uint h)
1.1 root 770: {
1.1.1.2 root 771: assert(dy < sy);
1.1 root 772:
1.1.1.2 root 773: uint32 da = dy * 256;
774: uint32 sa = sy * 256;
775:
776: for (uint y = 0; y < h; y++) {
777: for (int i = 0; i < nplane; i++) {
778: memcpy(&mem[da + i * 0x40000], &mem[sa + i * 0x40000], 160);
1.1 root 779: }
1.1.1.2 root 780: da += 256;
781: sa += 256;
1.1 root 782: }
1.1.1.2 root 783:
784: Invalidate();
1.1 root 785: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.