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