--- nono/vm/mainram.cpp 2026/04/29 17:05:24 1.1.1.2 +++ nono/vm/mainram.cpp 2026/04/29 17:05:29 1.1.1.3 @@ -57,6 +57,7 @@ MainRAMDevice::Init() } // ウェイトはシステムポートが設定するのでここでは不要。 + // バースト用の線は回路図によると配線されていないようだ。 break; case VMType::LUNA1: @@ -88,9 +89,10 @@ MainRAMDevice::Init() } } - // 1ウェイトらしい? - read_wait = busdata::Wait(1 * clock_nsec); - write_wait = busdata::Wait(1 * clock_nsec); + // 通常サイクルは1ウェイトらしい? + // バーストウェイトは LUNA-88K の取説からの推論。 + normal_wait = busdata::Wait(1 * clock_nsec); + burst_wait = busdata::Wait(4 * clock_nsec); break; } @@ -130,15 +132,16 @@ MainRAMDevice::Init() // これは CMMU 以降のアクセスタイムらしいので、 // リード3クロック、ライト2クロック引いたものをウェイトとしてみる? // XXX 要確認。 - read_wait = busdata::Wait(2 * clock_nsec); - write_wait = busdata::Wait(2 * clock_nsec); + normal_wait = busdata::Wait(2 * clock_nsec); + burst_wait = busdata::Wait(5 * clock_nsec); break; } case VMType::NEWS: - // 知らんけど 1ウェイトくらい入れておく。 - read_wait = busdata::Wait(1 * clock_nsec); - write_wait = busdata::Wait(1 * clock_nsec); + // 知らんけど 1クロックくらい入れておく。 + normal_wait = busdata::Wait(1 * clock_nsec); + // NWS-1750 はバースト転送をサポートしていないようだ。 + // http://www.ceres.dti.ne.jp/tsutsui/netbsd/port-news68k.html#19991203 break; case VMType::VIRT68K: @@ -153,8 +156,8 @@ MainRAMDevice::Init() } // ウェイト不要。 - read_wait = busdata::Wait(0); - write_wait = busdata::Wait(0); + normal_wait = busdata::Wait(0); + burst_wait = busdata::Wait(0); break; default: @@ -201,88 +204,174 @@ MainRAMDevice::ResetHard(bool poweron) // X68030 ではリセットで戻るはず。(LUNA は固定なので関係ない) if (gMainApp.IsX68030()) { - read_wait = busdata::Wait(0); - write_wait = busdata::Wait(0); + normal_wait = busdata::Wait(0); } } busdata -MainRAMDevice::Read8(uint32 addr) +MainRAMDevice::Read(busaddr addr) { + uint32 paddr = addr.Addr(); busdata data; - data = mainram[HLB(addr)]; - data |= read_wait; - putlog(4, "$%08x.B -> $%02x", addr, data.Data()); + + data = *(uint32 *)&mainram[paddr & ~3]; + data |= normal_wait; + data |= BusData::Size4; return data; } busdata -MainRAMDevice::Read16(uint32 addr) +MainRAMDevice::Write(busaddr addr, uint32 data) { - busdata data; - data = *(uint16 *)&mainram[HLW(addr)]; - data |= read_wait; - putlog(4, "$%08x.W -> $%04x", addr, data.Data()); - return data; + uint32 paddr = addr.Addr(); + uint32 reqsize = addr.GetSize(); + uint32 datasize = std::min(4 - (paddr & 3U), reqsize); + + if (datasize == 4) { + *(uint32 *)&mainram[paddr] = data; + } else if (datasize == 1) { + data >>= (reqsize - datasize) * 8; + mainram[HLB(paddr)] = data; + } else { + data >>= (reqsize - datasize) * 8; + for (int i = datasize - 1; i >= 0; i--) { + mainram[HLB(paddr + i)] = data; + data >>= 8; + } + } + + busdata r = normal_wait; + r |= BusData::Size4; + return r; } busdata -MainRAMDevice::Read32(uint32 addr) +MainRAMDevice::ReadBurst16(busaddr addr, uint32 *dst) { - busdata data; - data = *(uint32 *)&mainram[addr]; - data |= read_wait; - putlog(4, "$%08x.L -> $%08x", addr, data.Data()); - return data; + uint32 paddr = addr.Addr(); + putlog(4, "$%08x BurstRead", paddr); + memcpy(dst, &mainram[paddr], 16); + return burst_wait; } busdata -MainRAMDevice::Write8(uint32 addr, uint32 data) +MainRAMDevice::WriteBurst16(busaddr addr, const uint32 *src) { - mainram[HLB(addr)] = data; - putlog(3, "$%08x.B <- $%02x", addr, data); - return write_wait; + uint32 paddr = addr.Addr(); + putlog(4, "$%08x BurstWrite", paddr); + memcpy(&mainram[paddr], src, 16); + return burst_wait; } busdata -MainRAMDevice::Write16(uint32 addr, uint32 data) +MainRAMDevice::Peek1(uint32 addr) { - *(uint16 *)&mainram[HLW(addr)] = data; - putlog(3, "$%08x.W <- $%04x", addr, data); - return write_wait; + return mainram[HLB(addr)]; } -busdata -MainRAMDevice::Write32(uint32 addr, uint32 data) +bool +MainRAMDevice::Poke1(uint32 addr, uint32 data) { - *(uint32 *)&mainram[addr] = data; - putlog(3, "$%08x.L <- $%08x", addr, data); - return write_wait; + if ((int32)data >= 0) { + mainram[HLB(addr)] = data; + } + return true; } -busdata -MainRAMDevice::Peek8(uint32 addr) +// 領域読み出し。 +// addr から totallen までが領域内なら転送して true を返す。 +// 領域外を指すなら何もせず false を返す。 +bool +MainRAMDevice::ReadMem(uint32 addr, void *dst_, uint32 totallen) { - return mainram[HLB(addr)]; + uint8 *dst = (uint8 *)dst_; + uintptr_t u = (uintptr_t)addr; + uint32 len; + + if (__predict_false(addr + totallen > GetSize())) { + return false; + } + + if (__predict_false(((u | (uintptr_t)dst) & 3) != 0)) { + if (((u ^ (uintptr_t)dst) & 3) || totallen < 4) { + len = totallen; + } else { + len = 4 - (uint32)(u & 3); + } + totallen -= len; + for (; len > 0; len--) { + *dst++ = mainram[HLB(addr)]; + addr++; + } + } + + len = totallen / 4; + for (; len > 0; len--) { + *(uint32 *)dst = be32toh(*(uint32 *)&mainram[addr]); + dst += 4; + addr += 4; + } + + len = totallen & 3; + for (; len > 0; len--) { + *dst++ = mainram[HLB(addr)]; + addr++; + } + + return true; } +// 領域書き込み。 +// addr から totallen までが領域内なら転送して true を返す。 +// 領域外を指すなら何もせず false を返す。 bool -MainRAMDevice::Poke8(uint32 addr, uint32 data) +MainRAMDevice::WriteMem(uint32 addr, const void *src_, uint32 totallen) { - if ((int32)data >= 0) { - mainram[HLB(addr)] = data; + const uint8 *src = (const uint8 *)src_; + uintptr_t u = (uintptr_t)addr; + uint32 len; + + if (__predict_false(addr + totallen > GetSize())) { + return false; + } + + if (__predict_false(((u | (uintptr_t)src) & 3) != 0)) { + if (((u ^ (uintptr_t)src) & 3) || totallen < 4) { + len = totallen; + } else { + len = 4 - (uint32)(u & 3); + } + totallen -= len; + for (; len > 0; len--) { + mainram[HLB(addr)] = *src++; + addr++; + } } + + len = totallen / 4; + for (; len > 0; len--) { + *(uint32 *)&mainram[addr] = be32toh(*(const uint32 *)src); + addr += 4; + src += 4; + } + + len = totallen & 3; + for (; len > 0; len--) { + mainram[HLB(addr)] = *src++; + addr++; + } + return true; } -// アクセスウェイト [clock] を設定 (X68030 でシステムポートから呼ばれる) +// アクセスウェイト [clock] を設定。 +// X68030 でシステムポートから呼ばれるため normal_wait のみ設定する。 void -MainRAMDevice::SetWait(uint32 wait) +MainRAMDevice::SetWait(uint32 wait_clock) { uint32 clock_nsec = mpu->GetClock_nsec(); - read_wait = busdata::Wait(wait * clock_nsec); - write_wait = busdata::Wait(wait * clock_nsec); + normal_wait = busdata::Wait(wait_clock * clock_nsec); } // info で指定された実行ファイルをゲストにロードする。