--- nono/vm/mainram.cpp 2026/04/29 17:05:17 1.1.1.1 +++ nono/vm/mainram.cpp 2026/04/29 17:05:24 1.1.1.2 @@ -22,29 +22,6 @@ MainRAMDevice::MainRAMDevice() : inherited(OBJ_MAINRAM) { - // アクセスウェイト - switch (gMainApp.GetVMType()) { - case VMType::LUNA1: - // LUNA-I は1ウェイト。 - read_wait = 1; - write_wait = 1; - break; - - case VMType::LUNA88K: - // 取扱説明書p.21 に、CMMU からのアクセスタイムが - // リード(4byte)で 200ns、バーストリード(16byte)で 320ns - // ライト(4byte)で 160ns、バーストライト(16byte)で 280ns とある。 - // 25MHz は 40ns/clockで、この数値は CMMU からのアクセス全体の時間 - // らしいので、ここで加算するウェイトはそれから 2クロック引いたもの。 - read_wait = 3; - write_wait = 2; - break; - - case VMType::X68030: - default: - // X68030 ではシステムポートが設定するのでここでは不要。 - break; - } } // デストラクタ @@ -66,7 +43,10 @@ MainRAMDevice::Init() item.Err(); return false; } - // 下限以外の制約は機種による + + uint32 clock_nsec = mpu->GetClock_nsec(); + + // メモリの下限以外の制約は機種による。 switch (gMainApp.GetVMType()) { case VMType::X68030: // メインメモリは 12MB まで。 @@ -75,27 +55,44 @@ MainRAMDevice::Init() item.Err("Configurable maximum main memory size is 12 [MB]"); return false; } + + // ウェイトはシステムポートが設定するのでここでは不要。 break; case VMType::LUNA1: + { // 16MB までは、実機に合わせて 4MB 単位とする。 // see http://wiki.netbsd.org/ports/luna68k/luna68k_info/#hardware // - // 16MB を超える増設 (or 魔改造) 部分は 1MB 単位で 255MB までとする。 - // 実 ROM のメモリチェックは 32KB だかそのくらいずつ行われ、 - // 最後に番兵として Null 領域 (BusError ではなく) が必要。 - // 現行の構成をあまり変えない範囲なら厳密には (256MB - 32KB) が - // 上限だが、設定ファイルからの指定が 1MB 単位なので 255MB。 + // 16MB を超える増設 (or 魔改造) 部分は 1MB 単位とする。 if (ram_size_MB <= 16) { if (ram_size_MB % 4 != 0) { item.Err("For 16MB or less, must be specified in 4 [MB] unit"); return false; } - } else if (ram_size_MB > 255) { - item.Err("Configurable maximum RAM size is 255 [MB]"); + } else if (ram_size_MB > 512) { + item.Err("Configurable maximum RAM size is 512 [MB]"); return false; } + + // 実 ROM のメモリチェックは 32KB だかそのくらいずつ行われ、 + // 最後に番兵として NOP 領域 (BusError ではなく) が必要。 + // 現行の構成をあまり変えない範囲なら厳密には (256MB - 32KB) が + // 上限だが、サイズ指定が 1MB 単位なので 255MB を上限にする。 + auto prom = dynamic_cast(GetPROMDevice()); + if (prom) { + if (ram_size_MB > 255) { + item.Err("(Warning) Maximum RAM size with PROM is 255[MB]; " + "Clip RAM size to 255[MB]."); + ram_size_MB = 255; + } + } + + // 1ウェイトらしい? + read_wait = busdata::Wait(1 * clock_nsec); + write_wait = busdata::Wait(1 * clock_nsec); break; + } case VMType::LUNA88K: { @@ -107,8 +104,8 @@ MainRAMDevice::Init() item.Err("For 64MB or less, must be specified in 16 [MB] unit"); return false; } - } else if (ram_size_MB > 255) { - item.Err("Configurable maximum RAM size is 255 [MB]"); + } else if (ram_size_MB > 512) { + item.Err("Configurable maximum RAM size is 512 [MB]"); return false; } @@ -118,25 +115,59 @@ MainRAMDevice::Init() auto prom = dynamic_cast(GetPROMDevice()); if (prom && prom->GetROMVer() == 120) { if (ram_size_MB > 240) { - item.Err("Maximum RAM size with PROM 1.20 is 240 [MB]"); - return false; + item.Err("(warning) Maximum RAM size with PROM 1.20 is 240[MB];" + " Clip RAM size to 240[MB]."); + ram_size_MB = 240; } } + // 取扱説明書p.21 に、CMMU からのアクセスタイムが + // リード(4byte)で 200ns、バーストリード(16byte)で 320ns + // ライト(4byte)で 160ns、バーストライト(16byte)で 280ns とある。 + // 25MHz は 40ns/clock なのでそれぞれ、 + // リード(4byte)で 5 clock、バーストリード(16byte)で 8 clock + // ライト(4byte)で 4 clock、バーストライト(16byte)で 7 clock となる。 + // これは CMMU 以降のアクセスタイムらしいので、 + // リード3クロック、ライト2クロック引いたものをウェイトとしてみる? + // XXX 要確認。 + read_wait = busdata::Wait(2 * clock_nsec); + write_wait = busdata::Wait(2 * clock_nsec); break; } case VMType::NEWS: - // XXX とりあえず - memset(&mainram[0], 0, ram_size); + // 知らんけど 1ウェイトくらい入れておく。 + read_wait = busdata::Wait(1 * clock_nsec); + write_wait = busdata::Wait(1 * clock_nsec); + break; + + case VMType::VIRT68K: + // 1MB 単位で指定できる必要もないだろうから 16MB 単位に切り上げる。 + ram_size_MB = roundup(ram_size_MB, 16); + + // 最後の 16MB ブロックが I/O 空間なので、 + // メモリは最大で 4096 - 16 = 4080MB まで積める。 + if (ram_size_MB > 4080) { + item.Err("Configurable maximum RAM size is 4080 [MB]"); + return false; + } + + // ウェイト不要。 + read_wait = busdata::Wait(0); + write_wait = busdata::Wait(0); break; default: - PANIC("corrupted vmtype=%s", gMainApp.GetVMName().c_str()); + PANIC("vmtype=%s not configured", gMainApp.GetVMTypeStr().c_str()); } ram_size = ram_size_MB * 1024 * 1024; - mainram.reset(new uint8[ram_size]); + mainram.reset(new(std::nothrow) uint8[ram_size]); + if ((bool)mainram == false) { + errno = ENOMEM; + warn("MainRAM(%u bytes)", ram_size); + return false; + } // Human68k モードならここで一度だけメモリをゼロクリアする。 // この時は Human68k::Init() が MainRAM にプログラムを転送するため @@ -150,8 +181,6 @@ MainRAMDevice::Init() memset(&mainram[0], 0, ram_size); } - // devtable[] への RAM デバイスの配置はこの後 VM::Init 側で行っている - return true; } @@ -172,106 +201,104 @@ MainRAMDevice::ResetHard(bool poweron) // X68030 ではリセットで戻るはず。(LUNA は固定なので関係ない) if (gMainApp.IsX68030()) { - read_wait = 0; - write_wait = 0; + read_wait = busdata::Wait(0); + write_wait = busdata::Wait(0); } } -uint64 +busdata MainRAMDevice::Read8(uint32 addr) { - mpu->AddCycle(read_wait); - uint32 data; + busdata data; data = mainram[HLB(addr)]; - putlog(4, "$%08x.B -> $%02x", addr, data); + data |= read_wait; + putlog(4, "$%08x.B -> $%02x", addr, data.Data()); return data; } -uint64 +busdata MainRAMDevice::Read16(uint32 addr) { - mpu->AddCycle(read_wait); - uint32 data; + busdata data; data = *(uint16 *)&mainram[HLW(addr)]; - putlog(4, "$%08x.W -> $%04x", addr, data); + data |= read_wait; + putlog(4, "$%08x.W -> $%04x", addr, data.Data()); return data; } -uint64 +busdata MainRAMDevice::Read32(uint32 addr) { - mpu->AddCycle(read_wait); - uint32 data; + busdata data; data = *(uint32 *)&mainram[addr]; - putlog(4, "$%08x.L -> $%08x", addr, data); + data |= read_wait; + putlog(4, "$%08x.L -> $%08x", addr, data.Data()); return data; } -uint64 +busdata MainRAMDevice::Write8(uint32 addr, uint32 data) { - mpu->AddCycle(write_wait); mainram[HLB(addr)] = data; putlog(3, "$%08x.B <- $%02x", addr, data); - return 0; + return write_wait; } -uint64 +busdata MainRAMDevice::Write16(uint32 addr, uint32 data) { - mpu->AddCycle(write_wait); *(uint16 *)&mainram[HLW(addr)] = data; putlog(3, "$%08x.W <- $%04x", addr, data); - return 0; + return write_wait; } -uint64 +busdata MainRAMDevice::Write32(uint32 addr, uint32 data) { - mpu->AddCycle(write_wait); *(uint32 *)&mainram[addr] = data; putlog(3, "$%08x.L <- $%08x", addr, data); - return 0; + return write_wait; } -uint64 +busdata MainRAMDevice::Peek8(uint32 addr) { return mainram[HLB(addr)]; } -uint64 +bool MainRAMDevice::Poke8(uint32 addr, uint32 data) { if ((int32)data >= 0) { mainram[HLB(addr)] = data; } - return 0; + return true; } -// アクセスウェイトを設定 (X68030 でシステムポートから呼ばれる) +// アクセスウェイト [clock] を設定 (X68030 でシステムポートから呼ばれる) void MainRAMDevice::SetWait(uint32 wait) { - read_wait = wait; - write_wait = wait; + uint32 clock_nsec = mpu->GetClock_nsec(); + + read_wait = busdata::Wait(wait * clock_nsec); + write_wait = busdata::Wait(wait * clock_nsec); } -// info->path で指定されたホストの実行ファイルをゲストにロードする。 +// info で指定された実行ファイルをゲストにロードする。 bool -MainRAMDevice::LoadFromFile(LoadInfo *info) +MainRAMDevice::LoadExec(LoadInfo *info) { BootLoader loader(this); - return loader.LoadFromFile(info); + return loader.LoadExec(info); } -// info->data, size で指定されたバッファを実行ファイルとみなしてゲストに -// ロードする。 +// info で指定されたデータファイルをゲストにロードする。 bool -MainRAMDevice::LoadFromData(LoadInfo *info) +MainRAMDevice::LoadData(LoadInfo *info) { BootLoader loader(this); - return loader.LoadFromData(info); + return loader.LoadData(info); }