--- nono/vm/mainram.cpp 2026/04/29 17:05:24 1.1.1.2 +++ nono/vm/mainram.cpp 2026/04/29 17:06:00 1.1.1.6 @@ -8,20 +8,20 @@ // メインメモリ // +// MainRAM はロングワード単位でホストバイトオーダ配置なので、 +// バイトアクセス、ワードアクセス時は HLB(), HLW() マクロを使用のこと。 + #include "mainram.h" #include "config.h" #include "mainapp.h" #include "mpu.h" #include "prom.h" -// MainRAM はロングワード単位でホストバイトオーダ配置なので、 -// バイトアクセス、ワードアクセス時は HLB(), HLW() マクロを使用のこと。 -/*static*/ std::unique_ptr MainRAMDevice::mainram; - // コンストラクタ MainRAMDevice::MainRAMDevice() : inherited(OBJ_MAINRAM) { + clear_on_boot = true; } // デストラクタ @@ -33,10 +33,6 @@ MainRAMDevice::~MainRAMDevice() bool MainRAMDevice::Init() { - if (inherited::Init() == false) { - return false; - } - const ConfigItem& item = gConfig->Find("ram-size"); int ram_size_MB = item.AsInt(); if (ram_size_MB < 1) { @@ -44,7 +40,7 @@ MainRAMDevice::Init() return false; } - uint32 clock_nsec = mpu->GetClock_nsec(); + uint64 clock_tsec = mpu->GetClock_tsec(); // メモリの下限以外の制約は機種による。 switch (gMainApp.GetVMType()) { @@ -57,6 +53,7 @@ MainRAMDevice::Init() } // ウェイトはシステムポートが設定するのでここでは不要。 + // バースト用の線は回路図によると配線されていないようだ。 break; case VMType::LUNA1: @@ -88,9 +85,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_tsec); + burst_wait = busdata::Wait(4 * clock_tsec); break; } @@ -130,15 +128,18 @@ 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_tsec); + burst_wait = busdata::Wait(5 * clock_tsec); break; } case VMType::NEWS: - // 知らんけど 1ウェイトくらい入れておく。 - read_wait = busdata::Wait(1 * clock_nsec); - write_wait = busdata::Wait(1 * clock_nsec); + // 電源オン時に RAM に書き込んでいるため、クリアしない。 + clear_on_boot = false; + // 知らんけど 1クロックくらい入れておく。 + normal_wait = busdata::Wait(1 * clock_tsec); + // NWS-1750 はバースト転送をサポートしていないようだ。 + // http://www.ceres.dti.ne.jp/tsutsui/netbsd/port-news68k.html#19991203 break; case VMType::VIRT68K: @@ -153,19 +154,18 @@ MainRAMDevice::Init() } // ウェイト不要。 - read_wait = busdata::Wait(0); - write_wait = busdata::Wait(0); + normal_wait = busdata::Wait(0); + burst_wait = busdata::Wait(0); break; default: PANIC("vmtype=%s not configured", gMainApp.GetVMTypeStr().c_str()); } - ram_size = ram_size_MB * 1024 * 1024; + ram_size = (size_t)ram_size_MB * 1024 * 1024; mainram.reset(new(std::nothrow) uint8[ram_size]); if ((bool)mainram == false) { - errno = ENOMEM; - warn("MainRAM(%u bytes)", ram_size); + warnx("Could not allocate MainRAM(%zu bytes)", ram_size); return false; } @@ -179,6 +179,7 @@ MainRAMDevice::Init() // 必要がある。 if (gMainApp.human_mode) { memset(&mainram[0], 0, ram_size); + clear_on_boot = false; } return true; @@ -189,11 +190,7 @@ void MainRAMDevice::ResetHard(bool poweron) { if (poweron) { - if (gMainApp.human_mode || gMainApp.IsNEWS()) { - // Human モードと NEWS は Init() がメモリに書き込むので - // ここでクリアしない。うーん。 - } else { - // 通常モードならメモリをクリア + if (clear_on_boot) { // XXX ノイズを用意するべき memset(&mainram[0], 0, ram_size); } @@ -201,73 +198,73 @@ 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()); - return data; -} -busdata -MainRAMDevice::Read16(uint32 addr) -{ - busdata data; - data = *(uint16 *)&mainram[HLW(addr)]; - data |= read_wait; - putlog(4, "$%08x.W -> $%04x", addr, data.Data()); + data = *(uint32 *)&mainram[paddr & ~3]; + data |= normal_wait; + data |= BusData::Size4; return data; } busdata -MainRAMDevice::Read32(uint32 addr) +MainRAMDevice::Write(busaddr addr, uint32 data) { - busdata data; - data = *(uint32 *)&mainram[addr]; - data |= read_wait; - putlog(4, "$%08x.L -> $%08x", 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 -MainRAMDevice::Write8(uint32 addr, uint32 data) -{ - mainram[HLB(addr)] = data; - putlog(3, "$%08x.B <- $%02x", addr, data); - return write_wait; + busdata r = normal_wait; + r |= BusData::Size4; + return r; } busdata -MainRAMDevice::Write16(uint32 addr, uint32 data) +MainRAMDevice::ReadBurst16(busaddr addr, uint32 *dst) { - *(uint16 *)&mainram[HLW(addr)] = data; - putlog(3, "$%08x.W <- $%04x", addr, data); - return write_wait; + uint32 paddr = addr.Addr(); + putlog(4, "$%08x BurstRead", paddr); + memcpy(dst, &mainram[paddr], 16); + return burst_wait; } busdata -MainRAMDevice::Write32(uint32 addr, uint32 data) +MainRAMDevice::WriteBurst16(busaddr addr, const uint32 *src) { - *(uint32 *)&mainram[addr] = data; - putlog(3, "$%08x.L <- $%08x", addr, data); - return write_wait; + uint32 paddr = addr.Addr(); + putlog(4, "$%08x BurstWrite", paddr); + memcpy(&mainram[paddr], src, 16); + return burst_wait; } busdata -MainRAMDevice::Peek8(uint32 addr) +MainRAMDevice::Peek1(uint32 addr) { return mainram[HLB(addr)]; } bool -MainRAMDevice::Poke8(uint32 addr, uint32 data) +MainRAMDevice::Poke1(uint32 addr, uint32 data) { if ((int32)data >= 0) { mainram[HLB(addr)] = data; @@ -275,30 +272,96 @@ MainRAMDevice::Poke8(uint32 addr, uint32 return true; } -// アクセスウェイト [clock] を設定 (X68030 でシステムポートから呼ばれる) -void -MainRAMDevice::SetWait(uint32 wait) +// 領域読み出し。 +// addr から totallen までが領域内なら転送して true を返す。 +// 領域外を指すなら何もせず false を返す。 +bool +MainRAMDevice::ReadMem(uint32 addr, void *dst_, uint32 totallen) { - uint32 clock_nsec = mpu->GetClock_nsec(); + uint8 *dst = (uint8 *)dst_; + uintptr_t u = (uintptr_t)addr; + uint32 len; + + if (__predict_false(addr + totallen > GetSize())) { + return false; + } - read_wait = busdata::Wait(wait * clock_nsec); - write_wait = busdata::Wait(wait * clock_nsec); + 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; } -// info で指定された実行ファイルをゲストにロードする。 +// 領域書き込み。 +// addr から totallen までが領域内なら転送して true を返す。 +// 領域外を指すなら何もせず false を返す。 bool -MainRAMDevice::LoadExec(LoadInfo *info) +MainRAMDevice::WriteMem(uint32 addr, const void *src_, uint32 totallen) { - BootLoader loader(this); + const uint8 *src = (const uint8 *)src_; + uintptr_t u = (uintptr_t)addr; + uint32 len; + + if (__predict_false(addr + totallen > GetSize())) { + return false; + } - return loader.LoadExec(info); + 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; } -// info で指定されたデータファイルをゲストにロードする。 -bool -MainRAMDevice::LoadData(LoadInfo *info) +// アクセスウェイト [clock] を設定。 +// X68030 でシステムポートから呼ばれるため normal_wait のみ設定する。 +void +MainRAMDevice::SetWait(uint32 wait_clock) { - BootLoader loader(this); - - return loader.LoadData(info); + normal_wait = busdata::Wait(wait_clock * mpu->GetClock_tsec()); }