--- nono/vm/crtc.cpp 2026/04/29 17:05:17 1.1.1.10 +++ nono/vm/crtc.cpp 2026/04/29 17:05:24 1.1.1.11 @@ -17,11 +17,13 @@ #include "crtc.h" #include "mfp.h" -#include "mpu.h" #include "renderer.h" #include "scheduler.h" #include "tvram.h" +// InsideOut p.135 +const busdata wait = busdata::Wait(9 * 40_nsec); + // コンストラクタ CRTCDevice::CRTCDevice() : inherited(OBJ_CRTC) @@ -82,93 +84,158 @@ CRTCDevice::ResetHard(bool poweron) scheduler->RestartEvent(vdisp_event); } -uint64 -CRTCDevice::Read(uint32 offset) +busdata +CRTCDevice::Read8(uint32 addr) { - uint64 data; - - mpu->AddCycle(9); // InsideOut p.135 + busdata data = Peek16(addr); - if (offset < 0x400 / 2) { // CRTC レジスタ - // 0x40 バイトでミラー - offset &= (0x40 / 2) - 1; - // R20, R21 のみ読み出し可能 - switch (offset) { - case 20: - data = crtc.r[offset]; - putlog(2, "R%02d -> $%04x", offset, (uint32)data); - break; - case 21: - // R21 へのアクセスは多いのでログレベルを上げておく - data = crtc.r[offset]; - putlog(3, "R%02d -> $%04x", offset, (uint32)data); - break; - default: - // それ以外は読み出し不可 ($00 が読める) - data = 0; - if (offset < countof(crtc.r)) { - putlog(3, "R%02d -> $%04x", offset, (uint32)data); + if (__predict_false(loglevel >= 2)) { + uint32 offset = addr & 0xfff; + if (offset < 0x400) { + // CRTC レジスタは 0x40 バイトでミラー + uint32 regno = (offset & 0x3f) / 2; + // R20, R21 のみ読み出し可能だが、 + // R21 へのアクセスは多いのでログレベルを上げておく。 + if (regno == 21) { + putlog(3, "R%02d.%c -> $%02x", regno, + (((addr & 1) == 0) ? 'H' : 'L'), data.Data()); + } else if (regno < countof(crtc.r)) { + putlogn("R%02d.%c -> $%02x", regno, + (((addr & 1) == 0) ? 'H' : 'L'), data.Data()); } else { - putlog(3, "$%06x -> $%04x", mpu->GetPaddr(), (uint32)data); + putlog(3, "$%06x -> $%02x", addr, data.Data()); } - break; } + } - } else { // 動作ポート - if ((offset & (0x80 / 2)) == 0) { // +$00..+$7f - data = (uint64)-1; - } else { // +$80..+$ff - data = crtc.op; + data |= wait; + return data; +} + +busdata +CRTCDevice::Read16(uint32 addr) +{ + busdata data = Peek16(addr); + + if (__predict_false(loglevel >= 2)) { + uint32 offset = addr & 0xfff; + if (offset < 0x400) { + // CRTC レジスタは 0x40 バイトでミラー + uint32 regno = (offset & 0x3f) / 2; + // R20, R21 のみ読み出し可能だが、 + // R21 へのアクセスは多いのでログレベルを上げておく + if (regno == 21) { + putlog(3, "R%02d -> $%04x", regno, data.Data()); + } else if (regno < countof(crtc.r)) { + putlog(2, "R%02d -> $%04x", regno, data.Data()); + } else { + putlog(3, "$%06x -> $%04x", addr, data.Data()); + } } } + data |= wait; return data; } -uint64 -CRTCDevice::Write(uint32 offset, uint32 data) +busdata +CRTCDevice::Write8(uint32 addr, uint32 data) { - mpu->AddCycle(9); // InsideOut p.135 + busdata r; - if (offset < 0x400 / 2) { // CRTC レジスタ - // 0x40 バイトでミラー - offset &= (0x40 / 2) - 1; - if (offset < countof(crtc.r)) { - SetReg(offset, data); + uint32 offset = addr & 0xfff; + if (offset < 0x400) { + // CRTC レジスタは 0x40 バイトでミラー + uint32 regno = (offset & 0x3f) / 2; + if (regno < countof(crtc.r)) { + uint32 tmp; + if ((addr & 1) == 0) { + tmp = (data << 8) | (crtc.r[regno] & 0xff); + } else { + tmp = (crtc.r[regno] & 0xff00) | data; + } + SetReg(regno, tmp); } else { // ここ何がいるんだ? - putlog(2, "$%06x <- $%04x", mpu->GetPaddr(), data); + putlog(2, "$%06x <- $%02x", addr, data); } + } else { + // 動作ポート + if ((offset & 0x80) == 0) { // +$00..+$7f + r.SetBusErr(); + } else { // +$80..+$ff + WriteOp(data); + } + } - } else { // 動作ポート - if ((offset & (0x80 / 2)) == 0) { // +$00..+$7f - return (uint64)-1; + r |= wait; + return r; +} + +busdata +CRTCDevice::Write16(uint32 addr, uint32 data) +{ + busdata r; + + uint32 offset = addr & 0xfff; + if (offset < 0x400) { + // CRTC レジスタは 0x40 バイトでミラー + uint32 regno = (offset & 0x3f) / 2; + if (regno < countof(crtc.r)) { + SetReg(regno, data); } else { + // ここ何がいるんだ? + putlog(2, "$%06x <- $%04x", addr, data); + } + } else { // 動作ポート + if ((offset & 0x80) == 0) { // +$00..+$7f + r.SetBusErr(); + } else { // +$80..+$ff WriteOp(data); } } - return 0; + r |= wait; + return r; } -uint64 -CRTCDevice::Peek(uint32 offset) +busdata +CRTCDevice::Peek8(uint32 addr) { - uint64 data; + busdata data = Peek16(addr); + if (data.IsOK()) { + if ((addr & 1) == 0) { + return data.Data() >> 8; + } else { + return data.Data() & 0xff; + } + } else { + return busdata::BusErr; + } +} - if (offset < 0x400 / 2) { // CRTC レジスタ - // 0x40 バイトでミラー - offset &= (0x40 / 2) - 1; - if (offset == 20 || offset == 21) { +// addr のワードとしての読み出し値を返す。 +// これは内部用で Read*() からも呼ばれるので、 +// バスエラーなら busdata::BusErr を返す。 +busdata +CRTCDevice::Peek16(uint32 addr) const +{ + busdata data; + + uint32 offset = addr & 0xfff; + if (offset < 0x400) { + // CRTC レジスタは 0x40 バイトでミラー + uint32 regno = (offset & 0x3f) / 2; + if (regno == 20 || regno == 21) { // R20, R21 のみ読み出し可能 - data = crtc.r[offset]; + data = crtc.r[regno]; } else { data = 0; } - - } else { // 動作ポート - if ((offset & (0x80 / 2)) == 0) { - data = (uint64)-1; + } else { + // 動作ポート + if ((offset & 0x80) == 0) { + data.SetBusErr(); } else { data = crtc.op; }