--- nono/vm/rom.cpp 2026/04/29 17:04:42 1.1.1.4 +++ nono/vm/rom.cpp 2026/04/29 17:04:59 1.1.1.7 @@ -4,21 +4,41 @@ // Licensed under nono-license.txt // +// ROM の共通部分 +// +// IODevice +// | +// | +-----------+ +// +--| ROMDevice | (LoadROM()、ウェイト、マスク等を持つ) +// | +-----------+ +// | | +// | +-- PROMDevice (LUNA* の PROM) +// | +-- IPLROM1Device (X680x0 の IPLROM 後半) +// | +-- IPLROM2Device (X680x0 の IPLROM 前半) +// | +-- CGROMDevice (X680x0 の CGROM) +// | +-- LunaPROMEmuDevice (LUNA PROM エミュレーションの共通部分) +// | | +// | +-- Luna1PROMEmuDevice (LUNA1 の PROM エミュレーション) +// | +-- Luna88kPROMEmuDevice (LUNA88K の PROM エミュレーション) +// | +// +-- PROM0Device (LUNA* のブートページ切り替え用プロキシ) +// +-- IPLROM0Device (X680x0 のブートページ切り替え用プロキシ) + #include "rom.h" +#include "autofd.h" #include "mainapp.h" -#include "mystring.h" +#include "mpu.h" +#include +#include +#include // // ROM 共通部 // -// ROM はビッグエンディアンのままメモリに置かれるので、 -// 必要ならアクセス時に都度変換すること。 -// -ROMDevice::ROMDevice() +ROMDevice::ROMDevice(const std::string& objname_) + : inherited(objname_) { - logname = "rom"; - mask = 0xffffffff; } @@ -26,33 +46,70 @@ ROMDevice::~ROMDevice() { } -void -ROMDevice::ResetHard() -{ - wait = 0; -} - // name の ROM を探してロードする。 // name はパスを含まないファイル名のみ。パスはこちらで探す。 -// mem は file をさす。 // 失敗した場合はエラーメッセージを表示して false を返す。 bool ROMDevice::LoadROM(const char *name, int size) { + struct stat st; + + assert(size > 0); + + // ファイル名 filename = gMainApp.SearchFile(name); if (filename.empty()) { warnx("%s not found", name); return false; } + // メモリを確保 + imagebuf.reset(new uint8 [size]); + if ((bool)imagebuf == false) { + warnx("ROM \"%s\": Cannot allocate memory (%d bytes)", + filename.c_str(), size); + return false; + } + // オープン - file.SetFilename(filename); - file.SetDispname(string_format("ROM \"%s\"", filename.c_str())); - mem = file.OpenRdOnly((off_t)size); - if (mem == NULL) { + autofd fd = open(filename.c_str(), O_RDONLY); + if (fd < 0) { + warn("ROM \"%s\"", filename.c_str()); + return false; + } + + // ファイルサイズを調べる + if (fstat(fd, &st) < 0) { + warn("ROM \"%s\" stat failed", filename.c_str()); + return false; + } + + if (st.st_size < size) { + warnx("ROM \"%s\" is too short (filesize is expected %d but %jd)", + filename.c_str(), size, (intmax_t)st.st_size); + return false; + } + if (st.st_size > size) { + // 大きすぎるほうはワーニングだけでいいか + warnx("%s is too large (ignore %zd bytes)", + filename.c_str(), (ssize_t)st.st_size - size); return false; } + // 読み込む + ssize_t n = read(fd, &imagebuf[0], size); + if (n < 0) { + warn("ROM \"%s\" read failed", filename.c_str()); + return false; + } + if (n < size) { + warnx("ROM \"%s\" read too short", filename.c_str()); + return false; + } + + fd.Close(); + + mem = &imagebuf[0]; return true; } @@ -85,21 +142,21 @@ uint64 ROMDevice::Write8(uint32 addr, uint32 data) { gMPU->AddCycle(wait); // ? - return (uint64)-1; + return write_op; } uint64 ROMDevice::Write16(uint32 addr, uint32 data) { gMPU->AddCycle(wait); // ? - return (uint64)-1; + return write_op; } uint64 ROMDevice::Write32(uint32 addr, uint32 data) { gMPU->AddCycle(wait); // ? - return (uint64)-1; + return write_op; } uint64