|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2018 [email protected]
4: //
5:
6: #include "bitmap.h"
7: #include "bt454.h"
1.1.1.3 ! root 8: #include "cgrom.h"
1.1 root 9:
10: //
11: // ビットマッププレーン
12: //
13: // Bitmap の VRAM はロングワード単位でホストバイトオーダ配置なので、
14: // バイトアクセス、ワードアクセス時は HLB(), HLW() マクロを使用のこと。
15: //
16:
17: // SX-9100 のほうはこう書いてあってこっちが正しいようだ。
18: // +00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
19: // b100 |RF| |BS| |共 通 B M P|プレーン#0 |
20: // b110 |プレーン#1 |プレーン#2 |プレーン#3 |プレーン#4 |
21: // b120 |プレーン#5 |プレーン#6 |プレーン#7 |FC| |
22: // b130 |F0| |F1| |F2| |F3| |
23: // b140 |F4| |F5| |F6| |F7| |
24: //
25: // SX-7100 のほうはこう書いてあるがこうはなっていないようだ。
26: // +00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
27: // b100 |RF| |BS| |共 通 B M P|FC| |
28: // b110 |プレーン#0 |プレーン#1 |プレーン#2 |プレーン#3 |
29: // b120 |プレーン#4 |プレーン#5 |プレーン#6 |プレーン#7 |
30: // b130 |F0| |F1| |F2| |F3| |
31: // b140 |F4| |F5| |F6| |F7| |
32: //
33: // RF: RFCNT (4バイト)
34: // BS: BMSEL (4バイト)
35: // FC: 共通ファンクションセット
36: // Fn: プレーン#n ファンクションセット
37: // 1区画が 64KB。空白のところは未調査。
1.1.1.3 ! root 38: // 未装着のプレーン(#4..#7とか)は 0xff が読めるようだ。
! 39: // ファンクションセットが 64バイトで折り返してるか未調査だが、
! 40: // b130'0000 も b133'0000 も 0xff が読めるのでこの範囲全域でミラーかも。
! 41: // b150'0000 以降(b1ff'ffffまで) は BUSERR のようだ。
! 42: //
1.1 root 43:
1.1.1.3 ! root 44: std::unique_ptr<BitmapDevice> gBitmap;
1.1 root 45:
46: BitmapDevice::BitmapDevice()
47: {
48: logname = "bitmap";
49: devname = "Bitmap";
50: devaddr = 0xb1000000;
51: monitor.Init(42, 11);
52:
53: // XXX とりあえず。実際は設定による
54: nplane = 1;
55: // プレーン数によってメモリを確保
1.1.1.3 ! root 56: mem.reset(new uint8 [0x40000 * nplane]);
1.1 root 57: }
58:
59: BitmapDevice::~BitmapDevice()
60: {
61: }
62:
63: void
64: BitmapDevice::ResetHard()
65: {
66: // 厳密にどの時点でリセットされるのかは知らないけど
67: bmsel = 0;
68:
69: // RFCNT の初期値は観測困難なので、とりあえず無視。
70:
71: for (int i = 0; i < MAX_PLANES; i++) {
72: fcs[i] = 5;
73: mask[i] = 0xffffffff;
74: }
75:
76: // XXX ここ?
77: Invalidate();
78: }
79:
80: uint64
81: BitmapDevice::Read8(uint32 addr)
82: {
83: if (addr < plane0base) {
84: // 書き込み専用
85: return 0xff;
86: }
87: if (addr < plane0base + 0x40000 * nplane) {
88: // プレーンの読み出し
89: return mem[HLB(addr - plane0base)];
90: }
91: // 残りは書き込み専用
92: return 0xff;
93: }
94:
95: uint64
96: BitmapDevice::Read16(uint32 addr)
97: {
98: if (addr < plane0base) {
99: // 書き込み専用
100: return 0xffff;
101: }
102: if (addr < plane0base + 0x40000 * nplane) {
103: // プレーンの読み出し
104: return *(uint16 *)&mem[HLW(addr - plane0base)];
105: }
106: // 残りは書き込み専用
107: return 0xffff;
108: }
109:
110: uint64
111: BitmapDevice::Read32(uint32 addr)
112: {
113: if (addr < plane0base) {
114: // 書き込み専用
115: return 0xffffffff;
116: }
117: if (addr < plane0base + 0x40000 * nplane) {
118: // プレーンの読み出し
119: return *(uint32 *)&mem[addr - plane0base];
120: }
121: // 残りは書き込み専用
122: return 0xffffffff;
123: }
124:
125: uint64
126: BitmapDevice::Write8(uint32 addr, uint32 data)
127: {
128: switch (addr) {
129: case 0xb1000000:
130: case 0xb1000001:
131: case 0xb1000002:
132: case 0xb1000003:
133: // このロングワード内へのバイトアクセスはロングワードにミラーされる
134: data = (data << 24) | (data << 16) | (data << 8) | data;
135: return Write32(addr & ~3, data);
136: case 0xb1040000:
137: case 0xb1040001:
138: case 0xb1040002:
139: case 0xb1040003:
140: // BMSEL はバイトアクセスできる?
141: putlog(0, "未実装バイト書き込み $%08x <- $%02x", addr, data);
142: return 0;
143: }
144:
145: if (addr < 0xb1080000) {
146: putlog(0, "未実装バイト書き込み $%08x <- $%02x", addr, data);
147: return 0;
148: }
149: if (addr < plane0base) {
150: // 共通ビットマッププレーン
151: WriteCommonBitmap8(addr, data);
152: return 0;
153: }
154:
155: if (addr < plane7end) {
156: // ビットマッププレーン
157: uint32 reladdr = addr - plane0base;
158: uint plane = reladdr / 0x40000;
159: uint32 offset = reladdr % 0x40000;
160:
161: if (plane < nplane) {
162: // ビットマッププレーンN
163: putlog(2, "プレーン%d書き込み $%08x <- $%02x", plane, addr, data);
164: WritePlane8(plane, offset, data);
165: return 0;
166: }
167: // HW 設定によっては存在しないプレーンへの書き込み
168: putlog(3, "不在プレーン%d書き込み $%08x <- $%02x",
169: plane, addr, data);
170: return 0;
171: }
172:
173: putlog(0, "未実装バイト書き込み $%08x <- $%02x", addr, data);
174: return 0;
175: }
176:
177: uint64
178: BitmapDevice::Write16(uint32 addr, uint32 data)
179: {
180: switch (addr) {
181: case 0xb1000000:
182: case 0xb1000002:
183: // このロングワード内へのワードアクセスはロングワードにミラーされる
184: data = (data << 16) | data;
185: return Write32(addr & ~3, data);
186: case 0xb1040000:
187: case 0xb1040002:
188: // BMSEL はワードアクセスできる?
189: putlog(0, "未実装ワード書き込み $%08x <- $%04x", addr, data);
190: return 0;
191: }
192:
193: if (addr < 0xb1080000) {
194: putlog(0, "未実装ワード書き込み $%08x <- $%04x", addr, data);
195: return 0;
196: }
197: if (addr < plane0base) {
198: // 共通ビットマッププレーン
199: WriteCommonBitmap16(addr, data);
200: return 0;
201: }
202:
203: if (addr < plane7end) {
204: // ビットマッププレーン
205: uint32 reladdr = addr - plane0base;
206: uint plane = reladdr / 0x40000;
207: uint32 offset = reladdr % 0x40000;
208:
209: if (plane < nplane) {
210: // ビットマッププレーンN
211: putlog(2, "プレーン%d書き込み $%08x <- $%04x", plane, addr, data);
212: WritePlane16(plane, offset, data);
213: return 0;
214: }
215: // HW 設定によっては存在しないプレーンへの書き込み
216: putlog(3, "不在プレーン%d書き込み $%08x <- $%04x",
217: plane, addr, data);
218: return 0;
219: }
220:
221: putlog(0, "未実装ワード書き込み $%08x <- $%04x", addr, data);
222: return 0;
223: }
224:
225: uint64
226: BitmapDevice::Write32(uint32 addr, uint32 data)
227: {
228: switch (addr) {
229: case 0xb1000000:
230: // RFCNT
231: WriteRFCNT(data);
232: return 0;
233:
234: case 0xb1040000:
235: // BMSEL
236: bmsel = data & 0xf;
237: putlog(1, "BMSEL <- $%08x", data);
238: return 0;
239: }
240:
241: if (addr < 0xb1080000) {
242: putlog(0, "未実装ロング書き込み $%08x <- $%08x", addr, data);
243: return 0;
244: }
245: if (addr < plane0base) {
246: // 共通ビットマッププレーン
247: WriteCommonBitmap32(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(3, "プレーン%d書き込み $%08x <- $%08x", plane, addr, data);
260: WritePlane32(plane, offset, data);
261: return 0;
262: }
263: // HW 設定によっては存在しないプレーンへの書き込み
264: putlog(3, "不在プレーン%d書き込み $%08x <- $%08x",
265: plane, addr, data);
266: return 0;
267: }
268:
269: if (addr < 0xb1300000) {
270: // 共通ファンクションセット
271: uint rop = (addr & 0x3f) / 4;
272: putlog(2, "共通FCSet 書き込み $%08x <- $%08x (%s)",
273: addr, data, RopStr(rop));
274: for (int i = 0; i < nplane; i++) {
275: if ((bmsel & (1 << i))) {
276: fcs[i] = rop;
277: mask[i] = data;
278: }
279: }
280: return 0;
281: }
282:
283: if (addr < fcset7end) {
284: // ファンクションセット
285: int plane = (addr - 0xb1300000) / 0x40000;
286:
287: if (plane < nplane) {
288: // ファンクションセットN
289: uint rop = (addr & 0x3f) / 4;
290: putlog(2, "FCSet%d書き込み $%08x <- $%08x (%s)",
291: plane, addr, data, RopStr(rop));
292: fcs[plane] = rop;
293: mask[plane] = data;
294: return 0;
295: }
296: // HW 設定によっては存在しない FCSet への書き込み
297: putlog(3, "不在FCSet%d書き込み $%08x <- $%08x",
298: plane, addr, data);
299: return 0;
300: }
301:
302: putlog(0, "未実装ロング書き込み $%08x <- $%08x", addr, data);
303: return 0;
304: }
305:
306: uint64
307: BitmapDevice::Peek8(uint32 addr)
308: {
309: if (addr < plane0base) {
310: // 書き込み専用
311: return 0xff;
312: }
313: if (addr < plane0base + 0x40000 * nplane) {
314: // プレーンの読み出し
315: return mem[HLB(addr - plane0base)];
316: }
317: // 残りは書き込み専用
318: return 0xff;
319: }
320:
321: bool
322: BitmapDevice::MonitorUpdate()
323: {
324: int i;
325:
326: monitor.Clear();
327:
328: // 0 1 2 3 4
329: // 012345678901234567890123456789012345678901
330: // RFCNT: $12345678 (X=-123dot, Y=1023dot)
331: //
332: // BMSEL=$4 ROP Mask RGB RGB
333: // Plane#0 Sel THRU $ffffffff $0:RGB $8:RGB
334: monitor.Print(0, 0, "RFCNT: $%08x (X=%ddot, Y=%ddot)",
335: rfcnt, hscroll, vscroll);
336: monitor.Print(3, 2, "BMSEL=$%x ROP Mask", bmsel);
337:
338: for (i = 0; i < nplane; i++) {
339: monitor.Print(0, 3 + i, "Plane#%d %s %s $%08x",
340: i,
341: (bmsel & (1 << i)) ? "Sel" : "---",
342: RopStr(fcs[i]), mask[i]);
343: }
344: for (; i < MAX_PLANES; i++) {
345: monitor.Print(0, 3 + i, TA::Disable, "Plane#%d (Not installed)", i);
346: }
347:
348: // ついでなのでここで BT454 のパレットも表示。
349: // 012345
350: // $0:RGB
351: const uint8 *pal = gBT454->reg.color;
352: monitor.Print(29, 1, "<BT454>");
353: monitor.Print(32, 2, "RGB RGB");
354: for (i = 0; i < 16; i++) {
355: uint rgb =
356: ((pal[i * 3 + 0] & 0xf0) << 4) +
357: ((pal[i * 3 + 1] & 0xf0) ) +
358: ((pal[i * 3 + 2] & 0xf0) >> 4);
359: monitor.Print(29 + (i / 8) * 7, (i % 8) + 3, "$%x:%03x", i, rgb);
360: }
361:
362: return true;
363: }
364:
365: // 全画面の更新フラグを立てる
366: void
367: BitmapDevice::Invalidate()
368: {
369: for (int i = 0; i < 1024; i++) {
370: atomic_dirty[i] = 1;
371: }
372: }
373:
374: // RFCNT への書き込み
375: void
376: BitmapDevice::WriteRFCNT(uint32 data)
377: {
378: // レジスタ値
379: rfcnt = data;
380:
381: // 水平オフセットを計算
382: // XXX マニュアルでは -8 まで指定できるように読めるが
383: // 指定する方法が分からない。
384: // XXX 193 以上を指定するとどうなるのか (とりあえずほっとく)
385: // 実機の挙動を目分量で見ると、右にはみ出た部分は
386: // 256 ラスタ先のラスタデータを描画しているようだ。
387: hscroll = ((rfcnt >> 16) & 0xff) + 8;
388: hscroll *= 4;
389:
390: // ラスタ(垂直)カウンタ
1.1.1.2 root 391: vscroll = (rfcnt + 26) & 0x3ff;
1.1 root 392:
393: // 全画面更新
394: Invalidate();
395:
396: putlog(1, "RFCNT <- $%08x (水平 %ddot, 垂直 %ddot)",
397: data, hscroll, vscroll);
398: }
399:
400: // 共通ビットマッププレーン バイト書き込み
401: void
402: BitmapDevice::WriteCommonBitmap8(uint32 addr, uint32 data)
403: {
404: uint32 offset = addr - 0xb1080000;
405: putlog(2, "共通プレーン書き込み $%08x <- $%02x", addr, data);
406: for (int i = 0; i < nplane; i++) {
407: if ((bmsel & (1 << i))) {
408: WritePlane8(i, offset, data);
409: }
410: }
411: }
412:
413: // 共通ビットマッププレーン ワード書き込み
414: void
415: BitmapDevice::WriteCommonBitmap16(uint32 addr, uint32 data)
416: {
417: uint32 offset = addr - 0xb1080000;
418: putlog(2, "共通プレーン書き込み $%08x <- $%04x", addr, data);
419: for (int i = 0; i < nplane; i++) {
420: if ((bmsel & (1 << i))) {
421: WritePlane16(i, offset, data);
422: }
423: }
424: }
425:
426: // 共通ビットマッププレーン ロング書き込み
427: void
428: BitmapDevice::WriteCommonBitmap32(uint32 addr, uint32 data)
429: {
430: uint32 offset = addr - 0xb1080000;
431: putlog(2, "共通プレーン書き込み $%08x <- $%08x", addr, data);
432: for (int i = 0; i < nplane; i++) {
433: if ((bmsel & (1 << i))) {
434: WritePlane32(i, offset, data);
435: }
436: }
437: }
438:
439: static inline uint32
440: RasterOp(uint rop, uint32 data, uint32 m)
441: {
442: switch (rop) {
443: case 0: // ZERO
444: data = 0;
445: break;
446: case 1: // AND1
447: data &= m;
448: break;
449: case 2: // AND2
450: data = ~data & m;
451: break;
452: case 3: // 使用不可
453: // 本当はここにシリアルモード変更コマンドがあるらしい
454: data = m;
455: break;
456: case 4: // AND3
457: data &= ~m;
458: break;
459: case 5: // THROUGH
460: break;
461: case 6: // EOR
462: data ^= m;
463: break;
464: case 7: // OR1
465: data |= m;
466: break;
467: case 8: // NOR
468: data = ~data & ~m;
469: break;
470: case 9: // ENOR
471: data = (data & m) | (~data & ~m);
472: break;
473: case 10: // INV1
474: data = ~data;
475: break;
476: case 11: // OR2
477: data = ~data | m;
478: break;
479: case 12: // INV2
480: data = ~m;
481: break;
482: case 13: // OR3
483: data |= ~m;
484: break;
485: case 14: // NAND
486: data = ~data | ~m;
487: break;
488: case 15: // ONE
489: data = 0xffffffff;
490: break;
491: }
492: return data;
493: }
494:
495: // ROP 文字列を返す
496: const char *
497: BitmapDevice::RopStr(uint rop)
498: {
499: static const char * ropstr[] = {
500: "ZERO",
501: "AND1",
502: "AND2",
503: "(3)",
504: "AND3",
505: "THRU", // THROUGH
506: "EOR",
507: "OR1",
508: "NOR",
509: "ENOR",
510: "INV1",
511: "OR2",
512: "INV2",
513: "OR3",
514: "NAND",
515: "ONE",
516: };
517: return ropstr[rop];
518: }
519:
520: // プレーン バイト書き込み
521: void
522: BitmapDevice::WritePlane8(uint plane, uint32 offset, uint32 data)
523: {
524: uint32 memoffset = plane * 0x40000 + offset;
525: uint32 m;
526: uint32 mask8;
527:
528: m = mem[HLB(memoffset)];
529: data = RasterOp(fcs[plane], data, m);
530: mask8 = mask[plane] >> (24 - (memoffset & 3) * 8);
531: mem[HLB(memoffset)] = (data & mask8) | (m & ~mask8);
532: atomic_dirty[offset / 256] = 1;
533: }
534:
535: // プレーン ワード書き込み
536: void
537: BitmapDevice::WritePlane16(uint plane, uint32 offset, uint32 data)
538: {
539: uint32 memoffset = plane * 0x40000 + offset;
540: uint32 m;
541: uint32 mask16;
542:
543: m = *(uint16 *)&mem[HLW(memoffset)];
544: data = RasterOp(fcs[plane], data, m);
545: if ((memoffset & 2) == 0) {
546: // 上位ワード
547: mask16 = mask[plane] >> 16;
548: } else {
549: // 下位ワード
550: mask16 = mask[plane];
551: }
552: *(uint16 *)&mem[HLW(memoffset)] = (data & mask16) | (m & ~mask16);
553: atomic_dirty[offset / 256] = 1;
554: }
555:
556: // プレーン ロングワード書き込み
557: void
558: BitmapDevice::WritePlane32(uint plane, uint32 offset, uint32 data)
559: {
560: uint32 memoffset = plane * 0x40000 + offset;
561: uint32 m;
562:
563: m = *(uint32 *)&mem[memoffset];
564: data = RasterOp(fcs[plane], data, m);
565: *(uint32 *)&mem[memoffset] = (data & mask[plane]) | (m & ~mask[plane]);
566: atomic_dirty[offset / 256] = 1;
567: }
1.1.1.3 ! root 568:
! 569:
! 570: // エミュレータによる画面出力
! 571: //
! 572: // VM 内からの操作ではなく、エミュレータ本体から画面を操作する
! 573: // エミュレーション ROM によるモニタコンソール用の機能。
! 574: // サービスを使いたい側 (EmuROM など) が任意の大きさの TextScreen を
! 575: // 用意し EmuConsoleOpen() をコールすると (現在のパレットのまま) 画面を
! 576: // クリアし、画面中央をこのテキスト VRAM の表示エリアとみなす。
! 577: // 以降は EmuConsoleUpdate() で TextScreen の内容に従って画面を更新し、
! 578: // 使用後は EmuConsoleClose() で再び画面をクリア (およびリソースの解放) を
! 579: // すること。
! 580:
! 581: // エミュレータによる出力開始
! 582: void
! 583: BitmapDevice::EmuConsoleOpen(TextScreen *t)
! 584: {
! 585: textscr = t;
! 586:
! 587: screen_w = textscr->GetCol();
! 588: screen_h = textscr->GetRow();
! 589: prev.reset(new uint16[screen_w * screen_h]);
! 590: for (int i = 0; i < screen_w * screen_h; i++) {
! 591: prev[i] = 0x0020;
! 592: }
! 593:
! 594: // ざっくりセンタリングする
! 595: origin_x = (1280 - screen_w * 12) / 2;
! 596: origin_y = (1024 - screen_h * 24) / 2;
! 597: // ただし横は 48ドット境界から始める
! 598: // こうすると1(,2)文字目の24ビットが必ずワード境界から始まる。
! 599: origin_x = (origin_x / 48) * 48;
! 600:
! 601: // 同時書き込み設定
! 602: bmsel = (1 << nplane) - 1;
! 603:
! 604: // 全画面をクリア
! 605: for (uint32 addr = 0xb1080000; addr < 0xb10c0000; addr += 4) {
! 606: WriteCommonBitmap32(addr, 0);
! 607: }
! 608: }
! 609:
! 610: // エミュレータによる出力終了
! 611: void
! 612: BitmapDevice::EmuConsoleClose()
! 613: {
! 614: // 全画面をクリア
! 615: for (uint32 addr = 0xb1080000; addr < 0xb10c0000; addr += 4) {
! 616: WriteCommonBitmap32(addr, 0);
! 617: }
! 618: // 同時書き込みも元に戻す
! 619: bmsel = 0;
! 620:
! 621: textscr = NULL;
! 622: prev.reset();
! 623: }
! 624:
! 625: // エミュレータによる出力
! 626: // ts が出力するテキスト情報、oldts は前回の情報。
! 627: void
! 628: BitmapDevice::EmuConsoleUpdate()
! 629: {
! 630: const uint16 *text = textscr->GetBuf();
! 631:
! 632: // 12ドットフォントなので2文字ずつ (24ビットずつ) 更新する
! 633: for (int y = 0; y < screen_h; y++) {
! 634: for (int x = 0; x < screen_w; x += 2) {
! 635: // 2文字分の文字と属性
! 636: uint32 t32 = *(const uint32 *)&text[y * screen_w + x];
! 637: uint32 p32 = *(const uint32 *)&prev[y * screen_w + x];
! 638: if (t32 == p32) {
! 639: continue;
! 640: }
! 641: // ここからは変更があったので出力
! 642: *(uint32 *)&prev[y * screen_w + x] = t32;
! 643: // 2文字分として直接32ビットキャストして取り出した t32 だと
! 644: // エンディアンによって上下が変わるので、ここでは改めて
! 645: // 順序通りに2回取り出す
! 646: uint32 ch0 = text[y * screen_w + x];
! 647: uint32 ch1 = text[y * screen_w + x + 1];
! 648: // その文字のフォントデータ上でのオフセット
! 649: uint32 fo0 = 0x3d000 + (ch0 & 0xff) * 48;
! 650: uint32 fo1 = 0x3d000 + (ch1 & 0xff) * 48;
! 651:
! 652: // 1,2文字目なら true、3,4文字目なら false
! 653: bool evenpair = ((x & 2) == 0);
! 654:
! 655: // ビットマップ上の書き始めアドレス
! 656: uint32 addr = 0xb1080000 +
! 657: ((origin_y + y * 24) * 256) +
! 658: ((origin_x + x * 12) / 8);
! 659:
! 660: for (int i = 0; i < 24; i++) {
! 661: // その文字のフォントデータ
! 662: uint32 fdat0 = be16toh(*(uint16*)(&builtin_cgrom[fo0 + i * 2]));
! 663: uint32 fdat1 = be16toh(*(uint16*)(&builtin_cgrom[fo1 + i * 2]));
! 664:
! 665: // 属性はとりあえず反転のみサポート
! 666: if ((ch0 & TA::On)) {
! 667: fdat0 = ~fdat0 & 0xfff0;
! 668: }
! 669: if ((ch1 & TA::On)) {
! 670: fdat1 = ~fdat1 & 0xfff0;
! 671: }
! 672:
! 673: // 1文字目と2文字目を組み合わせて 24bit にする
! 674: uint32 data = (fdat0 << 8) | (fdat1 >> 4);
! 675:
! 676: // 書き込みは一度に 3バイトずつになるので、
! 677: // 効率化のため上位下位ペアで書き込みパターンを変える。
! 678: //
! 679: // | chr1 | chr2 | chr3 | chr4 |
! 680: // +----+----+----+----+----+----+
! 681: // | +0 | +1 | +2 | +3 | +4 | +5 |
! 682: // +----+----+----+----+----+----+
! 683: // |<-.Word->|<.B>|<.B>|<-.Word->|
! 684: if (evenpair) {
! 685: WriteCommonBitmap16(addr, data >> 8);
! 686: WriteCommonBitmap8(addr + 2, data & 0xff);
! 687: } else {
! 688: WriteCommonBitmap8(addr, data >> 16);
! 689: WriteCommonBitmap16(addr + 1, data & 0xffff);
! 690: }
! 691:
! 692: addr += 256; // 1ライン進める
! 693: }
! 694: }
! 695: }
! 696: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.