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