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