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