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