--- nono/vm/crtc.cpp 2026/04/29 17:05:24 1.1.1.11 +++ nono/vm/crtc.cpp 2026/04/29 17:05:28 1.1.1.12 @@ -14,6 +14,10 @@ // +$80..+$ff は何かが読める。 // 仕様は $e80480.w に1ポートあるので、これがワードで全域にミラーされている? // 全体としては この $800 バイトずつが繰り返して見える。 +// +// CRTC はデバイスの配置としては BusIO_B 相当で、バイトアクセスも行えるが、 +// 内部はバイトレジスタではなくワード単位を基本構造としている。そのため +// BusIO は使わず自力で処理する。ログの観点からもこのほうが都合がいい。 #include "crtc.h" #include "mfp.h" @@ -28,20 +32,6 @@ const busdata wait = busdata::Wait(9 * 4 CRTCDevice::CRTCDevice() : inherited(OBJ_CRTC) { - hsync_event.func = ToEventCallback(&CRTCDevice::HSyncCallback); - hsync_event.Regist("CRTC H-Sync"); - vdisp_event.func = ToEventCallback(&CRTCDevice::VDispCallback); - vdisp_event.Regist("CRTC V-Disp"); - - // ラスターコピーは実際には CRTC の機能ではなく TVRAM (VRAM チップ) の - // 機能だが、イベントの時間管理が発生するのは CRTC 側なのでここで管理。 - // X68030 搭載の VRAM チップは HM514402A だが、ここでは X68000 XVI 搭載の - // HM53461 の値を使用し、これが最小 190nsec * 2 らしいので - // とりあえず 400nsec としておく。 - raster_event.func = ToEventCallback(&CRTCDevice::RasterCallback); - raster_event.time = 400_nsec; - raster_event.Regist("CRTC Raster Copy"); - monitor.func = ToMonitorCallback(&CRTCDevice::MonitorUpdate); monitor.SetSize(62, 14); monitor.Regist(ID_MONITOR_CRTC); @@ -64,6 +54,23 @@ CRTCDevice::Init() renderer = GetRenderer(); tvram = GetTVRAMDevice(); + hsync_event.func = ToEventCallback(&CRTCDevice::HSyncCallback); + hsync_event.SetName("CRTC H-Sync"); + vdisp_event.func = ToEventCallback(&CRTCDevice::VDispCallback); + vdisp_event.SetName("CRTC V-Disp"); + scheduler->RegistEvent(hsync_event); + scheduler->RegistEvent(vdisp_event); + + // ラスターコピーは実際には CRTC の機能ではなく TVRAM (VRAM チップ) の + // 機能だが、イベントの時間管理が発生するのは CRTC 側なのでここで管理。 + // X68030 搭載の VRAM チップは HM514402A だが、ここでは X68000 XVI 搭載の + // HM53461 の値を使用し、これが最小 190nsec * 2 らしいので + // とりあえず 400nsec としておく。 + raster_event.func = ToEventCallback(&CRTCDevice::RasterCallback); + raster_event.time = 400_nsec; + raster_event.SetName("CRTC Raster Copy"); + scheduler->RegistEvent(raster_event); + return true; } @@ -84,52 +91,47 @@ CRTCDevice::ResetHard(bool poweron) scheduler->RestartEvent(vdisp_event); } -busdata -CRTCDevice::Read8(uint32 addr) +/*static*/ inline uint32 +CRTCDevice::Decoder(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.%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 -> $%02x", addr, data.Data()); - } - } - } - - data |= wait; - return data; + return addr & 0x7ff; } busdata -CRTCDevice::Read16(uint32 addr) +CRTCDevice::Read(busaddr addr) { - busdata data = Peek16(addr); + uint32 offset = Decoder(addr.Addr()); + busdata data = Peek2(offset); + + uint32 reqsize = addr.GetSize(); + if (reqsize == 1) { + if ((offset & 1) == 0) { + data >>= 8; + } else { + data &= 0xff; + } + data |= BusData::Size1; + } else { + data |= BusData::Size2; + } 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()); + uint32 regno = (offset >> 1) & 0x1f; + if (regno < countof(crtc.r)) { + // R20, R21 のみ読み出し可能だが、 + // R21 へのアクセスは多いのでログレベルを上げておく。 + int lv = (regno == 21) ? 3 : 2; + if (reqsize == 1) { + putlog(lv, "R%02u.%c -> $%02x", regno, + (((offset & 1) == 0) ? 'H' : 'L'), data.Data()); + } else { + putlog(lv, "R%02u -> $%04x", regno, data.Data()); + } } else { - putlog(3, "$%06x -> $%04x", addr, data.Data()); + putlog(3, "$%06x -> $%0*x", addr.Addr(), + reqsize * 2, data.Data()); } } } @@ -139,70 +141,61 @@ CRTCDevice::Read16(uint32 addr) } busdata -CRTCDevice::Write8(uint32 addr, uint32 data) +CRTCDevice::Write(busaddr addr, uint32 data) { busdata r; + uint32 offset = Decoder(addr.Addr()); + uint32 reqsize = addr.GetSize(); + uint32 datasize = std::min(2 - (offset & 1), reqsize); + data >>= (reqsize - datasize) * 8; - uint32 offset = addr & 0xfff; if (offset < 0x400) { // CRTC レジスタは 0x40 バイトでミラー - uint32 regno = (offset & 0x3f) / 2; + uint32 regno = (offset >> 1) & 0x1f; if (regno < countof(crtc.r)) { - uint32 tmp; - if ((addr & 1) == 0) { - tmp = (data << 8) | (crtc.r[regno] & 0xff); + if (datasize == 1) { + // バイト書き込み + if ((offset & 1) == 0) { + data = (data << 8) | (crtc.r[regno] & 0xff); + } else { + data = (crtc.r[regno] & 0xff00) | data; + } } else { - tmp = (crtc.r[regno] & 0xff00) | data; + // ワード書き込み } - SetReg(regno, tmp); + SetReg(regno, data); } else { // ここ何がいるんだ? - putlog(2, "$%06x <- $%02x", addr, data); + putlog(2, "$%06x <- $%0*x", addr.Addr(), datasize * 2, data); } } else { // 動作ポート if ((offset & 0x80) == 0) { // +$00..+$7f r.SetBusErr(); - } else { // +$80..+$ff - WriteOp(data); - } - } - - 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 + if (datasize == 1) { + // バイト書き込み + if ((offset & 1) == 0) { + data = (data << 8) | crtc.op; + } else { + data = (crtc.op & 0xff00) | data; + } + } else { + // ワード書き込み + } WriteOp(data); } } r |= wait; + r |= busdata::Size(datasize); return r; } busdata -CRTCDevice::Peek8(uint32 addr) +CRTCDevice::Peek1(uint32 addr) { - busdata data = Peek16(addr); + busdata data = Peek2(addr); if (data.IsOK()) { if ((addr & 1) == 0) { return data.Data() >> 8; @@ -210,19 +203,19 @@ CRTCDevice::Peek8(uint32 addr) return data.Data() & 0xff; } } else { - return busdata::BusErr; + return BusData::BusErr; } } // addr のワードとしての読み出し値を返す。 -// これは内部用で Read*() からも呼ばれるので、 -// バスエラーなら busdata::BusErr を返す。 +// これは内部用で Read() からも呼ばれるので、 +// バスエラーなら BusData::BusErr を返す。 busdata -CRTCDevice::Peek16(uint32 addr) const +CRTCDevice::Peek2(uint32 addr) const { busdata data; - uint32 offset = addr & 0xfff; + uint32 offset = Decoder(addr); if (offset < 0x400) { // CRTC レジスタは 0x40 バイトでミラー uint32 regno = (offset & 0x3f) / 2; @@ -324,28 +317,28 @@ CRTCDevice::SetReg(uint32 reg, uint32 da switch (reg) { case CRTC::R10: - putlog(2, "R%02d <- $%04x", reg, data); + putlog(2, "R%02u <- $%04x", reg, data); tvram->SetScrollX(crtc.r[10]); break; case CRTC::R11: - putlog(2, "R%02d <- $%04x", reg, data); + putlog(2, "R%02u <- $%04x", reg, data); tvram->SetScrollY(crtc.r[11]); break; case CRTC::R21: // 頻度が高いのでログレベルを上げておく - putlog(3, "R%02d <- $%04x", reg, data); + putlog(3, "R%02u <- $%04x", reg, data); tvram->SetAccessPlane(crtc.r[21]); break; case CRTC::R22: - putlog(3, "R%02d <- $%04x", reg, data); + putlog(3, "R%02u <- $%04x", reg, data); break; case CRTC::R23: // 頻度が高いのでログレベルを上げておく - putlog(3, "R%02d <- $%04x", reg, data); + putlog(3, "R%02u <- $%04x", reg, data); tvram->SetAccessMask(crtc.r[23]); break; default: - putlog(2, "R%02d <- $%04x (NOT IMPLEMENTED)", reg, data); + putlog(2, "R%02u <- $%04x (NOT IMPLEMENTED)", reg, data); break; } } @@ -357,7 +350,7 @@ CRTCDevice::WriteOp(uint32 data) uint16 oldop = crtc.op; crtc.op = data & 0x0b; - putlog(2, "$e80480.W <- $%04x", crtc.op); + putlog(2, "OP <- $%04x", crtc.op); uint16 change = oldop ^ crtc.op; @@ -366,16 +359,16 @@ CRTCDevice::WriteOp(uint32 data) if ((crtc.op & CRTC::OP_RC)) { // 0->1 開始 raster_copy = true; - putlog(3, "ラスターコピー指示"); + putlog(3, "Start Raster copy (ラスターコピー指示"); } else { // 1->0 は停止じゃなくキャンセル? raster_copy = false; - putlog(3, "ラスターコピーキャンセル"); + putlog(3, "Cancel Raster copy (ラスターコピーキャンセル)"); } } if ((change & 0x03)) { - putlog(0, "動作ポート $%02x <- $%02x (NOT IMPLEMENTED)", + putlog(0, "OP (動作ポート) $%02x <- $%02x (NOT IMPLEMENTED)", oldop & 0x03, crtc.op & 0x03); } } @@ -403,8 +396,8 @@ CRTCDevice::HSyncCallback(Event& ev) if (raster_copy) { raster_copy = false; - int src = (crtc.r[22] >> 8) * 4; - int dst = (crtc.r[22] & 0xff) * 4; + uint src = (crtc.r[22] >> 8) * 4; + uint dst = (crtc.r[22] & 0xff) * 4; tvram->RasterCopy(src, dst); // 所定時間後に完了させる @@ -446,7 +439,7 @@ CRTCDevice::VDispCallback(Event& ev) // 今はここで1画面まるごと作成 if (vdisp) { // Render に作画指示 - renderer->Render(); + renderer->NotifyRender(); } // 次のタイミングを計算