--- nono/vm/romemu_virt68k.cpp 2026/04/29 17:05:24 1.1 +++ nono/vm/romemu_virt68k.cpp 2026/04/29 17:05:41 1.1.1.5 @@ -5,15 +5,39 @@ // // -// virt68k の IPLROM 相当の何か +// virt-m68k の IPLROM 相当の何か // +// IODevice +// | +// +- ROMDevice (LoadROM()、ウェイト、マスク等を持つ) +// | +- PROMDevice (LUNA* の PROM) +// | +- IPLROM1Device (X680x0 の IPLROM 後半) +// | +- IPLROM2Device (X680x0 の IPLROM 前半) +// | +- CGROMDevice (X680x0 の CGROM) +// | | +// | +- ROMEmuDevice +// | +- LunaPROMEmuDevice (LUNA PROM エミュレーションの共通部分) +// | | +- Luna1PROMEmuDevice (LUNA-I の PROM エミュレーション) +// | | +- Luna88kPROMEmuDevice (LUNA-88K の PROM エミュレーション) +// | +- NewsROMEmuDevice (NEWS の ROM エミュレーション) +// | +- ROM30EmuDevice (X68030 の ROM30 エミュレーション) +// | | +// | | +---------------------+ +// | +-| Virt68kROMEmuDevice | (virt-m68k の IPLROM 相当の何か) +// | +---------------------+ +// | +// +- PROM0Device (LUNA* のブートページ切り替え用プロキシ) +// +- IPLROM0Device (X680x0 のブートページ切り替え用プロキシ) + #include "romemu_virt68k.h" #include "autofd.h" #include "config.h" +#include "iodevstream.h" #include "mainapp.h" #include "mainram.h" #include "memorystream.h" +#include "mpu680x0.h" #include #include #include @@ -23,13 +47,6 @@ Virt68kROMEmuDevice::Virt68kROMEmuDevice() : inherited(OBJ_PROM) { - // 適当 - uint devlen = 4096; - imagebuf.reset(new uint8 [devlen]); - memset(&imagebuf[0], 0, devlen); - - mem = &imagebuf[0]; - mask = devlen - 1; } // デストラクタ @@ -41,32 +58,33 @@ Virt68kROMEmuDevice::~Virt68kROMEmuDevic bool Virt68kROMEmuDevice::Init() { - if (inherited::Init() == false) { + // ROM 領域を用意。サイズは適当。 + if (AllocROM(2048, 0) == false) { return false; } mainram = GetMainRAMDevice(); - MemoryStreamBE ms(imagebuf.get()); - ms.Write32(0x00001000); // +00: リセットベクタ SP - ms.Write32(0xff000400); // +04: リセットベクタ PC + MemoryStreamBE roms(imagebuf.get()); + roms.Write4(0x00001000); // +00: リセットベクタ SP + roms.Write4(0xff000400); // +04: リセットベクタ PC // ベクタ for (int i = 2; i < 256; i++) { - ms.Write32(0); + roms.Write4(0); } // リセット時に実行する命令 - ms.SetOffset(0x400); - ms.Write16(0x2039); // move.l (ROMIO_INIT),d0 - ms.Write32(ROMIO_INIT); - ms.Write16(0x0c80); // cmpi.l #0xffffffff,d0 - ms.Write32(0xffffffff); - ms.Write16(0x6704); // beq @f - ms.Write16(0x2040); // move.l d0,a0 ; ジャンプ先を a0 にセット - ms.Write16(0x4ed0); // jmp (a0) ; ジャンプ + roms.SetOffset(0x400); + roms.Write2(0x2039); // move.l (ROMIO_INIT),d0 + roms.Write4(ROMIO_INIT); + roms.Write2(0x0c80); // cmpi.l #0xffffffff,d0 + roms.Write4(0xffffffff); + roms.Write2(0x6704); // beq @f + roms.Write2(0x2040); // move.l d0,a0 ; ジャンプ先を a0 にセット + roms.Write2(0x4ed0); // jmp (a0) ; ジャンプ //@@: - ms.Write32(0x4e722700); // stop #0x2700 - ms.Write16(0x67fc); // bra @b + roms.Write4(0x4e722700); // stop #0x2700 + roms.Write2(0x67fc); // bra @b return true; } @@ -75,23 +93,25 @@ void Virt68kROMEmuDevice::ResetHard(bool poweron) { // 起動時に RAM にリセットベクタを書き込んでおく。(手抜き) - for (int i = 0; i < 8; i++) { - mainram->Write8(i, imagebuf[i]); - } + mainram->WriteMem(0, &imagebuf[0], 8); } -busdata -Virt68kROMEmuDevice::Read32(uint32 addr) +// ROMIO から読み出す。 +// ROMIO が応答すべきでなければ (uint64)-1 を返す。 +uint64 +Virt68kROMEmuDevice::ReadROMIO(busaddr addr) { - switch (addr) { - case ROMIO_INIT: - return ROM_Init(); + if (addr.GetSize() == 4) { + switch (addr.Addr()) { + case ROMIO_INIT: + return ROM_Init(); - default: - break; + default: + break; + } } - return inherited::Read32(addr); + return (uint64)-1; } uint32 @@ -105,7 +125,7 @@ Virt68kROMEmuDevice::ROM_Init() // カーネル側もそのように想定しているようだ。 info.loadsym = false; - if (mainram->LoadExec(&info) == false) { + if (BootLoader::LoadExec(mainram, &info) == false) { warnx("** Couldn't load specified host program."); return -1; } @@ -133,9 +153,11 @@ class BootInfo void Init(uint16 tag_, uint32 val_); void AddWord(uint32 val_); void AddLong(uint32 val_); + void AddString(const char *val_); uint32 GetWord(uint32 offset) const; uint32 GetLong(uint32 offset) const; + const char *GetString() const { return (const char *)bi_data.data(); } }; // コンストラクタ @@ -179,6 +201,16 @@ BootInfo::AddLong(uint32 val_) bi_data.push_back(val_); } +// データに文字列を追加する。 +void +BootInfo::AddString(const char *val_) +{ + for (const char *s = val_; *s; s++) { + bi_data.push_back(*s); + } + bi_data.push_back('\0'); +} + // offset の位置からの 16 ビット整数を取得。 uint32 BootInfo::GetWord(uint32 offset) const @@ -211,8 +243,8 @@ BootInfo::GetLong(uint32 offset) const // 伝統的な(?) NetBSD アーキテクチャは、ブートローダからカーネルへの // パラメータはレジスタ渡しかスタック渡しでアーキテクチャごとに固定の // フォーマットになっている。少なくともいくつかの m68k では。 -// NetBSD/virt68k では Linux/m68k の方式を採用しているようだ。QEMU が -// そうしてくるからそう受け取らざるを得なかったということかも知れないが。 +// NetBSD/virt68k では Linux/m68k の方式を採用しているようだが、 +// これは virt-m68k がそういう仕様だから。 // // NetBSD/virt68k のブートパラメータ BootInfo は、カーネルがロードされた // セクションの末尾 (リンカによってアドレスが求まる) 以降の次のロングワード @@ -241,20 +273,45 @@ Virt68kROMEmuDevice::MakeBootInfo(LoadIn { IODeviceStream ds(mainram, info->end); BootInfo bi; + uint32 cpu_type; + uint32 mmu_type; + uint32 fpu_type; + + auto mpu680x0 = GetMPU680x0Device(mpu); + switch (mpu680x0->GetMPUType()) { + case m680x0MPUType::M68030: + cpu_type = BI_CPU_68030; + mmu_type = BI_MMU_68030; + if (mpu680x0->HasFPU()) { + fpu_type = BI_FPU_68881; + } else { + fpu_type = 0; + } + break; + case m680x0MPUType::M68040: + cpu_type = BI_CPU_68040; + mmu_type = BI_MMU_68040; + fpu_type = BI_FPU_68040; + break; + default: + assert(false); + } bi.Init(BI_MACHTYPE, BI_MACH_VIRT); WriteBootInfo(ds, bi); - bi.Init(BI_CPUTYPE, BI_CPU_68030); + bi.Init(BI_CPUTYPE, cpu_type); WriteBootInfo(ds, bi); - bi.Init(BI_FPUTYPE, BI_FPU_68881); + bi.Init(BI_MMUTYPE, mmu_type); WriteBootInfo(ds, bi); - bi.Init(BI_MMUTYPE, BI_MMU_68030); - WriteBootInfo(ds, bi); + if (fpu_type != 0) { + bi.Init(BI_FPUTYPE, fpu_type); + WriteBootInfo(ds, bi); + } - uint32 ramsize = mainram->GetSize(); + uint32 ramsize = (uint32)mainram->GetSize(); // RAMDISK は (あれば) initrd イメージ置き場で、 // メモリセグメントとは別セグメントにする必要がある。 @@ -295,7 +352,7 @@ Virt68kROMEmuDevice::MakeBootInfo(LoadIn // ロード。 LoadInfo rdinfo(cpath, mdata, rdsize); rdinfo.start = (ramsize - rdsize) & ~0xfff; - bool rv = mainram->LoadData(&rdinfo); + bool rv = BootLoader::LoadData(mainram, &rdinfo); munmap(mdata, rdsize); if (rv == false) { warnx("** Couldn't load specified initrd."); @@ -372,6 +429,15 @@ Virt68kROMEmuDevice::MakeBootInfo(LoadIn bi.AddLong(8 + (2 - 1) * 32 + 0); // base irq WriteBootInfo(ds, bi); + // ブートパラメータ + const ConfigItem& bootparam_item = gConfig->Find("exec-bootparam"); + const std::string& bootparam = bootparam_item.AsString(); + if (bootparam.empty() == false) { + bi.Init(BI_COMMANDLINE); + bi.AddString(bootparam.c_str()); + WriteBootInfo(ds, bi); + } + bi.Init(BI_LAST); WriteBootInfo(ds, bi); @@ -486,15 +552,18 @@ Virt68kROMEmuDevice::WriteBootInfo(IODev case BI_RNG_SEED: buf = string_format("len=%u", bi.GetWord(0)); break; + case BI_COMMANDLINE: + buf = string_format("\"%s\"", bi.GetString()); + break; } putmsg(1, "BootInfo $%08x: %-14s: %s", stream.GetAddr(), tagname.c_str(), buf.c_str()); } // 出力。 - stream.Write16(bi.bi_tag); - stream.Write16(size); + stream.Write2(bi.bi_tag); + stream.Write2(size); for (const auto c : bi.bi_data) { - stream.Write8(c); + stream.Write1(c); } }