--- nono/vm/lunafb.cpp 2026/04/29 17:05:24 1.1.1.5 +++ nono/vm/lunafb.cpp 2026/04/29 17:05:59 1.1.1.11 @@ -10,7 +10,7 @@ // SX-9100 のほうはこう書いてあってこっちが正しいようだ。 // +00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f -// b100 |RF| |BS| |共 通 B M P|プレーン#0 | +// b100 |RF|RF|RF|RF|BS| |共 通 B M P|プレーン#0 | // b110 |プレーン#1 |プレーン#2 |プレーン#3 |プレーン#4 | // b120 |プレーン#5 |プレーン#6 |プレーン#7 |FC| | // b130 |F0| |F1| |F2| |F3| | @@ -24,8 +24,8 @@ // b130 |F0| |F1| |F2| |F3| | // b140 |F4| |F5| |F6| |F7| | // -// RF: RFCNT (4バイト) -// BS: BMSEL (4バイト) +// RF: RFCNT (4バイト)。b100'0000 から b104'0000 の手前までこの1ポートのミラー。 +// BS: BMSEL (4バイト)。こっちは未確認だがたぶん RFCNT と同じ? // FC: 共通ファンクションセット // Fn: プレーン#n ファンクションセット // 1区画が 64KB。空白のところは未調査。 @@ -40,6 +40,8 @@ #include "lunafb.h" #include "bt45x.h" #include "builtinrom.h" +#include "busio.h" +#include "monitor.h" #include "mpu.h" // コンストラクタ @@ -50,9 +52,9 @@ LunafbDevice::LunafbDevice() ClearAlias(); AddAlias("Lunafb"); - monitor.func = ToMonitorCallback(&LunafbDevice::MonitorUpdate); - monitor.SetSize(39, 11); - monitor.Regist(ID_MONITOR_LUNAVC); + monitor = gMonitorManager->Regist(ID_MONITOR_LUNAVC, this); + monitor->SetCallback(&LunafbDevice::MonitorScreen); + monitor->SetSize(39, 11); } // デストラクタ @@ -69,21 +71,24 @@ LunafbDevice::Init() } auto bt45x = GetBT45xDevice(); - nplane = bt45x->GetPlaneCount(); - assert(nplane >= 0); plane_end = plane0base + 0x40000 * nplane; fcset_end = fcset0base + 0x40000 * nplane; // プレーン数によってメモリを確保 - mem.reset(new uint8 [0x40000 * nplane]); + size_t memsize = 0x40000 * nplane; + mem.reset(new(std::nothrow) uint8 [memsize]); + if ((bool)mem == false) { + warnx("Could not allocate %zu bytes at %s", memsize, __method__); + return false; + } // ホストパレットを取得。 palette = &(bt45x->GetHostPalette())[0]; // XXX とりあえず RAM と同じウェイトを入れておく (未調査) - wait = busdata::Wait(1 * mpu->GetClock_nsec()); + wait = busdata::Wait(1 * mpu->GetClock_tsec()); return true; } @@ -114,244 +119,150 @@ LunafbDevice::ResetHard(bool poweron) } busdata -LunafbDevice::Read8(uint32 addr) +LunafbDevice::Read(busaddr addr) { + uint32 paddr = addr.Addr(); busdata data; - if (plane0base <= addr && addr < plane_end) { + if (plane0base <= paddr && paddr < plane_end) { // プレーンの読み出し - data = mem[HLB(addr - plane0base)]; + data = *(uint32 *)&mem[(paddr & ~3U) - plane0base]; } else { // 残りは書き込み専用または不在 - putlog(1, "Read not-readable $%08x.B", addr); - data = 0xff; + putlog(1, "Read not-readable $%08x", paddr); + data = 0xffffffff; } data |= wait; + data |= BusData::Size4; return data; } busdata -LunafbDevice::Read16(uint32 addr) +LunafbDevice::Write(busaddr addr, uint32 data) { - busdata data; + uint32 paddr = addr.Addr(); - if (plane0base <= addr && addr < plane_end) { - // プレーンの読み出し - data = *(uint16 *)&mem[HLW(addr - plane0base)]; - } else { - // 残りは書き込み専用または不在 - putlog(1, "Read not-readable $%08x.W", addr); - data = 0xffff; + // RFCNT と BMSEL だけバスの処理が別。というよりバスの観点から言えば + // 本来別デバイスだが便宜上同じデバイスに同居している感じ。 + if (paddr < 0xb1080000) { + return WriteReg(addr, data); } - data |= wait; - return data; -} - -busdata -LunafbDevice::Read32(uint32 addr) -{ - busdata data; - if (plane0base <= addr && addr < plane_end) { - // プレーンの読み出し - data = *(uint32 *)&mem[addr - plane0base]; + uint32 reqsize = addr.GetSize(); + // 3バイトアクセスは面倒なので回避して .B/.W/.L に整列させる。 + uint32 datasize; + if (reqsize == 4 && (paddr & 3U) == 0) { + datasize = 4; } else { - // 残りは書き込み専用または不在 - putlog(1, "Read not-readable $%08x.L", addr); - data = 0xffffffff; + datasize = std::min(2 - (paddr & 1U), reqsize); } - data |= wait; - return data; -} + data >>= (reqsize - datasize) * 8; -busdata -LunafbDevice::Write8(uint32 addr, uint32 data) -{ - switch (addr) { - case 0xb1000000: - case 0xb1000001: - case 0xb1000002: - case 0xb1000003: - // このロングワード内へのバイトアクセスはロングワードにミラーされる - data = (data << 24) | (data << 16) | (data << 8) | data; - return Write32(addr & ~3, data); - case 0xb1040000: - case 0xb1040001: - case 0xb1040002: - case 0xb1040003: - // BMSEL はバイトアクセスできる? - putlog(0, "BMSEL $%08x <- $%02x (NOT IMPLEMENTED)", addr, data); - return wait; - } - - if (addr < 0xb1080000) { - // 空き。どうなる? - putlog(0, "Vacant $%08x <- $%02x (NOT IMPLEMENTED)", addr, data); - return wait; - } - if (addr < plane0base) { + if (paddr < plane0base) { // 共通ビットマッププレーン - WriteCommonBitmap8(addr, data); - return wait; - } + if (datasize == 4) { + WriteCommonBitmap32(paddr, data); + } else if (datasize == 2) { + WriteCommonBitmap16(paddr, data); + } else { + WriteCommonBitmap8(paddr, data); + } - if (__predict_true(addr < plane_end)) { + } else if (__predict_true(paddr < plane_end)) { // 存在するビットマッププレーン - uint32 reladdr = addr - plane0base; + uint32 reladdr = paddr - plane0base; uint plane = reladdr / 0x40000; uint32 offset = reladdr % 0x40000; - putlog(2, "Plane%d $%08x <- $%02x", plane, addr, data); - WritePlane8(plane, offset, data); + putlog(3, "Plane%u $%08x <- $%0*x", plane, paddr, datasize * 2, data); + + if (datasize == 4) { + WritePlane32(plane, offset, data); + } else if (datasize == 2) { + WritePlane16(plane, offset, data); + } else { + WritePlane8(plane, offset, data); + } SetDirty(offset); - return wait; - } - if (addr < plane7end) { + } else if (__predict_false(paddr < plane7end)) { // HW 設定によっては存在しないプレーン - uint32 reladdr = addr - plane0base; + uint32 reladdr = paddr - plane0base; uint plane = reladdr / 0x40000; - putlog(3, "Not-equipped Plane%d $%08x <- $%02x", plane, addr, data); - return wait; - } + putlog(3, "Not-equipped Plane%u $%08x <- $%0*x", + plane, paddr, datasize * 2, data); - // XXX ファンクションセットはバイトアクセスだとどうなる? - putlog(0, "$%08x <- $%02x (NOT IMPLEMENTED)", addr, data); - return wait; -} + } else if (paddr < 0xb1300000) { + // 共通ファンクションセット + // XXX ワード、バイトアクセスはどうなる? + uint rop = (paddr & 0x3f) / 4; + putlog(2, "Common FCSet $%08x <- $%0*x (%s)", + paddr, datasize * 2, data, RopStr(rop)); + WriteCommonFCSet(rop, data); -busdata -LunafbDevice::Write16(uint32 addr, uint32 data) -{ - switch (addr) { - case 0xb1000000: - case 0xb1000002: - // このロングワード内へのワードアクセスはロングワードにミラーされる - data = (data << 16) | data; - return Write32(addr & ~3, data); - case 0xb1040000: - case 0xb1040002: - // BMSEL はワードアクセスできる? - putlog(0, "BMSEL $%08x <- $%04x (NOT IMPLEMENTED)", addr, data); - return wait; - } - - if (addr < 0xb1080000) { - // 空き。どうなる? - putlog(0, "Vacant $%08x <- $%04x (NOT IMPLEMENTED)", addr, data); - return wait; - } - if (addr < plane0base) { - // 共通ビットマッププレーン - WriteCommonBitmap16(addr, data); - return wait; - } + } else if (__predict_true(paddr < fcset_end)) { + // 存在するファンクションセット + // XXX ワード、バイトアクセスはどうなる? + uint plane = (paddr - 0xb1300000) / 0x40000; + uint rop = (paddr & 0x3f) / 4; + putlog(2, "FCSet%u $%08x <- $%0*x (%s)", + plane, paddr, datasize * 2, data, RopStr(rop)); + fcset[plane] = rop; + fcmask[plane] = data; - if (__predict_true(addr < plane_end)) { - // 存在するビットマッププレーン - uint32 reladdr = addr - plane0base; - uint plane = reladdr / 0x40000; - uint32 offset = reladdr % 0x40000; + } else if (paddr < fcset7end) { + // HW 設定によっては存在しないファンクションセット + uint plane = (paddr - 0xb1300000) / 0x40000; + putlog(3, "Not-equipped FCSet%u $%08x <- $%0*x", + plane, paddr, datasize * 2, data); - putlog(2, "Plane%d $%08x <- $%04x", plane, addr, data); - WritePlane16(plane, offset, data); - SetDirty(offset); - return wait; - } + } else { + // 残りは全部空きのはずだが挙動未調査。 + putlog(0, "$%08x <- $%0*x (NOT IMPLEMENTED)", + paddr, datasize * 2, data); - if (addr < plane7end) { - // HW 設定によっては存在しないプレーン - uint32 reladdr = addr - plane0base; - uint plane = reladdr / 0x40000; - putlog(3, "Not-equipped Plane%d $%08x <- $%04x", plane, addr, data); - return wait; } - // XXX ファンクションセットはワードアクセスだとどうなる? - putlog(0, "$%08x <- $%04x (NOT IMPLEMENTED)", addr, data); - return wait; + busdata r = wait; + r |= busdata::Size(datasize); + return r; } busdata -LunafbDevice::Write32(uint32 addr, uint32 data) +LunafbDevice::WriteReg(busaddr addr, uint32 data) { - switch (addr) { - case 0xb1000000: + // RFCNT レジスタ部分は BusIO_L, NPORT=1 相当。 + // + // LUNA-88K PROM で `cw b1040000 0` した後、 + // `cs b1040000 0100` (RFCNT の上位ワードに $0100 を書き込む) を実行する + // と、垂直位置だけが変わる。RFCNT は上位ワードの下位 8 ビットが水平 + // スクロール位置、下位ワードの下位 10 ビットが垂直スクロール位置なので、 + // ロングワード全体に $0100'0100 を $00ff'03ff でマスクした結果の + // $0000'0100 が書き込まれたことになる。 + // m88200 のデータバスへの置き方と、このポートがロングワード固定で DBE* + // を細かくデコードしていないとすれば辻褄が合う。 + // 同様に `cs b1040002 0020` を実行すると LUNA-88K 実機では垂直位置と + // ともに水平位置も変わる。 + // + // BMSEL レジスタ部分は確認が難しいけどたぶん同じだと思うことにする。 + data = BusIO::DataMultiplexer_Write_L(addr, data); + + if (addr.Addr() < 0xb1040000) { // RFCNT WriteRFCNT(data); - return wait; - - case 0xb1040000: + } else { // BMSEL - bmsel = data & 0xf; + bmsel = data & ((1U << nplane) - 1); putlog(1, "BMSEL <- $%08x", data); - return wait; - } - - if (addr < 0xb1080000) { - putlog(0, "Vacant $%08x <- $%08x (NOT IMPLEMENTED)", addr, data); - return wait; - } - if (addr < plane0base) { - // 共通ビットマッププレーン - WriteCommonBitmap32(addr, data); - return wait; - } - - if (__predict_true(addr < plane_end)) { - // 存在するビットマッププレーン - uint32 reladdr = addr - plane0base; - uint plane = reladdr / 0x40000; - uint32 offset = reladdr % 0x40000; - - putlog(3, "Plane%d $%08x <- $%08x", plane, addr, data); - WritePlane32(plane, offset, data); - SetDirty(offset); - return wait; - } - - if (__predict_false(addr < plane7end)) { - // HW 設定によっては存在しないプレーン - uint32 reladdr = addr - plane0base; - uint plane = reladdr / 0x40000; - putlog(3, "Not-equipped Plane%d $%08x <- $%08x", plane, addr, data); - return wait; - } - - if (addr < 0xb1300000) { - // 共通ファンクションセット - uint rop = (addr & 0x3f) / 4; - putlog(2, "Common FCSet $%08x <- $%08x (%s)", - addr, data, RopStr(rop)); - WriteCommonFCSet(rop, data); - return wait; - } - - if (__predict_true(addr < fcset_end)) { - // 存在するファンクションセット - int plane = (addr - 0xb1300000) / 0x40000; - uint rop = (addr & 0x3f) / 4; - putlog(2, "FCSet%d $%08x <- $%08x (%s)", - plane, addr, data, RopStr(rop)); - fcset[plane] = rop; - fcmask[plane] = data; - return wait; - } - - if (addr < fcset7end) { - // HW 設定によっては存在しないファンクションセット - int plane = (addr - 0xb1300000) / 0x40000; - putlog(3, "Not-equipped FCSet%d $%08x <- $%08x", plane, addr, data); - return wait; } - // 残りは全部空きのはずだが挙動未調査。 - putlog(0, "$%08x <- $%08x (NOT IMPLEMENTED)", addr, data); - return wait; + busdata r = wait; + r |= BusData::Size4; + return r; } busdata -LunafbDevice::Peek8(uint32 addr) +LunafbDevice::Peek1(uint32 addr) { if (plane0base <= addr && addr < plane_end) { // プレーンの読み出し @@ -362,7 +273,7 @@ LunafbDevice::Peek8(uint32 addr) } bool -LunafbDevice::Poke8(uint32 addr, uint32 data) +LunafbDevice::Poke1(uint32 addr, uint32 data) { // 通常プレーンのみ越権書き込み可能とする? if (plane0base <= addr && addr < plane_end) { @@ -380,7 +291,7 @@ LunafbDevice::Poke8(uint32 addr, uint32 } void -LunafbDevice::MonitorUpdate(Monitor *, TextScreen& screen) +LunafbDevice::MonitorScreen(Monitor *, TextScreen& screen) { int i; @@ -394,16 +305,16 @@ LunafbDevice::MonitorUpdate(Monitor *, T // Plane#0 Sel THRU $ffffffff screen.Print(0, 0, "RFCNT: $%08x (X=%4ddot, Y=%4ddot)", rfcnt, xscroll, yscroll); - screen.Print(3, 2, "BMSEL=$%x ROP Mask", bmsel); + screen.Print(2, 2, "BMSEL=$%02x ROP Mask", bmsel); for (i = 0; i < nplane; i++) { - screen.Print(0, 3 + i, "Plane#%d %s %s $%08x", + screen.Print(0, 3 + i, "Plane#%u %s %s $%08x", i, - (bmsel & (1 << i)) ? "Sel" : "---", + (bmsel & (1U << i)) ? "Sel" : "---", RopStr(fcset[i]), fcmask[i]); } for (; i < MAX_PLANES; i++) { - screen.Print(0, 3 + i, TA::Disable, "Plane#%d (Not installed)", i); + screen.Print(0, 3 + i, TA::Disable, "Plane#%u (Not installed)", i); } } @@ -426,8 +337,8 @@ LunafbDevice::SetDirty(uint32 offset) // 9 8 7 6 5 4 3 2 1 0 // 更新フラグはラスタ単位 - int y = (offset >> 8); - dirty[y] = 1; + uint y = (offset >> 8); + dirty.line[y] = true; } // X 方向にはみ出したときに対応する仮想画面の Y 座標を返す。 @@ -480,7 +391,7 @@ LunafbDevice::WriteCommonBitmap8(uint32 uint32 offset = addr - 0xb1080000; putlog(2, "Common Plane $%08x <- $%02x", addr, data); for (int i = 0; i < nplane; i++) { - if ((bmsel & (1 << i))) { + if ((bmsel & (1U << i))) { WritePlane8(i, offset, data); } } @@ -494,7 +405,7 @@ LunafbDevice::WriteCommonBitmap16(uint32 uint32 offset = addr - 0xb1080000; putlog(2, "Common Plane $%08x <- $%04x", addr, data); for (int i = 0; i < nplane; i++) { - if ((bmsel & (1 << i))) { + if ((bmsel & (1U << i))) { WritePlane16(i, offset, data); } } @@ -508,7 +419,7 @@ LunafbDevice::WriteCommonBitmap32(uint32 uint32 offset = addr - 0xb1080000; putlog(2, "Common Plane $%08x <- $%08x", addr, data); for (int i = 0; i < nplane; i++) { - if ((bmsel & (1 << i))) { + if ((bmsel & (1U << i))) { WritePlane32(i, offset, data); } } @@ -520,7 +431,7 @@ void LunafbDevice::WriteCommonFCSet(uint rop, uint32 data) { for (int i = 0; i < nplane; i++) { - if ((bmsel & (1 << i))) { + if ((bmsel & (1U << i))) { fcset[i] = rop; fcmask[i] = data; } @@ -592,7 +503,7 @@ LunafbDevice::RasterOp(uint rop, uint32 vram = 0xffffffff; break; default: - VMPANIC("corrupted rop=%d", (int)rop); + VMPANIC("corrupted rop=%u", rop); } return vram; } @@ -685,7 +596,7 @@ LunafbDevice::UpdateInfo(TextScreen& scr screen.Puts(0, 0, "X= Y="); for (int i = 0; i < nplane; i++) { - screen.Print(15, i, "(P%d)", i); + screen.Print(15, i, "(P%u)", i); } // カーソルが範囲外ならここまで。 @@ -704,7 +615,7 @@ LunafbDevice::UpdateInfo(TextScreen& scr uint32 totaloffset = 0x40000 * i + planeoffset; uint8 data = mem[HLB(totaloffset)]; - screen.Print(15, i, "(P%d) $%08x: $%02x (%%", + screen.Print(15, i, "(P%u) $%08x: $%02x (%%", i, plane0base + totaloffset, data); // ビットパターン @@ -740,7 +651,7 @@ void LunafbDevice::EmuInitScreen() { // 同時書き込み設定 - bmsel = (1 << nplane) - 1; + bmsel = (1U << nplane) - 1; // ROP を初期化 WriteCommonFCSet(ROP::THRU, 0xffffffff); @@ -780,7 +691,7 @@ LunafbDevice::EmuPutc(uint x, uint y, ui // ピクセル座標 x, y を左上として文字 c を出力。 // 文字が VRAM からはみ出ないようにすること。 void -LunafbDevice::EmuPutc(uint x, uint y, uint c, int rop) +LunafbDevice::EmuPutc(uint x, uint y, uint c, uint rop) { uint32 addr = 0xb1080000 + (x / 32) * 4 + y * 256; uint32 bofs = x % 32;