--- nono/vm/prom.cpp 2026/04/29 17:04:50 1.1.1.5 +++ nono/vm/prom.cpp 2026/04/29 17:04:55 1.1.1.7 @@ -25,9 +25,8 @@ // コンストラクタ PROMDevice::PROMDevice() + : inherited("PROM") { - logname = "prom"; - devname = "PROM"; devaddr = 0x41000000; } @@ -43,7 +42,7 @@ PROMDevice::Init() switch (vmtype) { case VMTYPE_LUNA1: - return InitLuna(); + return InitLuna1(); case VMTYPE_LUNA88K: return InitLuna88k(); @@ -55,7 +54,7 @@ PROMDevice::Init() // LUNA-I の場合 bool -PROMDevice::InitLuna() +PROMDevice::InitLuna1() { devlen = 128 * 1024; mask = devlen - 1; @@ -123,10 +122,22 @@ PROMDevice::PowerOn() { // パフォーマンス測定に電源オン時の実時刻を記憶。 // Write8() 参照。 - start_time = ::GetRealTime(); + sw.Start(); return true; } +void +PROMDevice::ResetHard() +{ + // PROM への Write (RAM への切り替え) は何度も実行されるので、最初の + // 1回だけ処理するため、こちらでも状態を持つ。 + // Scheduler も同様のステートを持っているけど、あっちはリクエストと + // 現状の2つがあって、リクエスト投げて状態が変わるまでに遅延があるので + // たぶんこっちで処理したほうがいい。 + isrom = true; + gVM->SwitchBootPage(this, true); +} + uint64 PROMDevice::Read8(uint32 addr) { @@ -147,17 +158,17 @@ PROMDevice::Read8(uint32 addr) // 書き込みをバックドアにしたかったが dd で書き込めなさそうだったので // 読み込みを使う。ちゃんと調べてない。 if (__predict_false(addr == 0x42000004)) { - uint64 end, result; - uint64 vt; + uint64 rtime; + uint64 vtime; // 電源オン時からここまでの時間を表示するだけでリセット等はしない。 - end = ::GetRealTime(); - vt = gMPU->GetVirtTime(); - result = end - start_time; + sw.Stop(); + rtime = sw.Elapsed(); + vtime = gMPU->GetVirtTime(); putlog(0, "電源オンから %d.%03d 秒経過 %3.3f%%", - (int)(result / (1000 * 1000 * 1000)), - (int)((result / (1000 * 1000)) % 1000), - (double)vt / result * 100); + (int)(rtime / (1000 * 1000 * 1000)), + (int)((rtime / (1000 * 1000)) % 1000), + (double)vtime / rtime * 100); } // それ以外は通常動作 @@ -167,27 +178,50 @@ PROMDevice::Read8(uint32 addr) uint64 PROMDevice::Write8(uint32 addr, uint32 data) { - // LUNA では PROM への書き込みで 0番地付近を RAM に切り替えている。 - // nono では 0番地付近を ROM に見せること自体をしていないので、 - // ここでは何もしなくてよく、単に無視する。 - // LUNA-I だと最初に $41000000.B への書き込みがあるが、それ以降も - // $41000000.L への書き込みがあるようなので Write32() でも対処している。 + return Write(addr); +} - if (addr == 0x41000000) { - return 0; - } - return inherited::Write8(addr, data); +uint64 +PROMDevice::Write16(uint32 addr, uint32 data) +{ + return Write(addr); } uint64 PROMDevice::Write32(uint32 addr, uint32 data) { - // PROM への書き込みで 0番地付近を RAM に切り替えている。 - // すぐ上の Write8() のコメントも参照。 - // LUNA88K では $4100000c.L への書き込みが最初にある。 - // LUNA-I でも $41000000.L への書き込みがあるので、ここでは両方無視する。 - if (addr < 0x41000010) { - return 0; + return Write(addr); +} + +// Write{8,16,32} 共通。 +// LUNA では書き込みでバスエラーは起きない。 +// 電源オン後最初の書き込みでブートページを RAM に切り替える。 +uint64 +PROMDevice::Write(uint32 addr) +{ + if (__predict_false(isrom)) { + // LUNA では PROM への書き込みでブートページを RAM に切り替えている。 + // - LUNA-I では最初に $41000000.B への書き込みがあるが、 + // それ以降も $41000000.L への書き込みが(複数回)あるようだ。 + // - LUNA88K では $4100000c.L への書き込みがある。 + // よってアドレスを定めず PROM 全域への書き込みで最初の1回だけ発動 + // するようにしておく。サイズも今の所ワード(16bit)アクセスは確認して + // ないけど統一的に対処しておく。 + + // XXX PROM がブートページを担当してる期間に RAM (のはずのアドレス) + // への書き込みは起きるんだろうか? + if (addr < 0x41000000) { + putlogn("%s addr=$%08x", __func__, addr); + } + + // RAM に切り替え + isrom = false; + gVM->SwitchBootPage(this, false); } - return inherited::Write32(addr, data); + + // XXX ウェイト未調査 + gMPU->AddCycle(wait); + + // バスエラーは起きない + return 0; }