--- nono/vm/rom.cpp 2026/04/29 17:04:29 1.1.1.2 +++ nono/vm/rom.cpp 2026/04/29 17:06:00 1.1.1.15 @@ -1,136 +1,180 @@ // // nono -// Copyright (C) 2018 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// 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 (LUNA-I の PROM エミュレーション) +// | +-- Luna88kPROMEmuDevice (LUNA-88K の PROM エミュレーション) +// | +// +-- PROM0Device (LUNA* のブートページ切り替え用プロキシ) +// +-- IPLROM0Device (X680x0 のブートページ切り替え用プロキシ) + +#include "rom.h" +#include "autofd.h" +#include "mainapp.h" +#include "mpu.h" #include #include -#include #include -#include "rom.h" -#include "configfile.h" // // ROM 共通部 // -// ROM はビッグエンディアンのままメモリに置かれるので、 -// 必要ならアクセス時に都度変換すること。 -// -ROMDevice::ROMDevice() +ROMDevice::ROMDevice(uint objid_) + : inherited(objid_) { - logname = "rom"; - mask = 0xffffffff; } ROMDevice::~ROMDevice() { - if (file) { - free(file); - file = NULL; +} + +// ROM 用の領域を用意する。 +// 失敗した場合は warn 系でエラーメッセージを表示して false を返す。 +bool +ROMDevice::AllocROM(uint len, uint8 fill) +{ + imagebuf.reset(new(std::nothrow) uint8 [len]); + if ((bool)imagebuf == false) { + warnx("Could not allocate %u bytes at %s", len, __method__); + return false; } + memset(&imagebuf[0], fill, len); + mem = &imagebuf[0]; + mask = len - 1; + + return true; } // name の ROM を探してロードする。 // name はパスを含まないファイル名のみ。パスはこちらで探す。 -// mem は file をさす。 -// 失敗した場合はエラーメッセージを表示して false を返す。 +// 失敗した場合は warn 系でエラーメッセージを表示して false を返す。 bool -ROMDevice::LoadROM(const char *name, int size) +ROMDevice::LoadROM(const char *name, uint size) { struct stat st; - filename = gConfig->SearchFile(name); + assert(size != 0); + + // ファイル名 + filename = gMainApp.SearchFile(name); if (filename.empty()) { warnx("%s not found", name); return false; } + // メモリを確保 + imagebuf.reset(new(std::nothrow) uint8 [size]); + if ((bool)imagebuf == false) { + warnx("ROM \"%s\": Could not allocate %u bytes", + filename.c_str(), size); + return false; + } + // オープン - fd = open(filename.c_str(), O_RDONLY); - if (fd == -1) { - warn("ROM \"%s\" open failed", filename.c_str()); + autofd fd = open(filename.c_str(), O_RDONLY); + if (fd < 0) { + warn("ROM \"%s\"", filename.c_str()); return false; } - // ファイルサイズをチェック。 - // ファイルが短くても mmap はしれっと成功してしまうようだ。 - if (fstat(fd, &st) == -1) { - warn("ROM \"%s\" fstat failed", filename.c_str()); - close(fd); + // ファイルサイズを調べる + 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 %d)", - filename.c_str(), size, (int)st.st_size); - close(fd); + warnx("ROM \"%s\" is too short (filesize is expected %u but %jd)", + filename.c_str(), size, (intmax_t)st.st_size); return false; } if (st.st_size > size) { // 大きすぎるほうはワーニングだけでいいか - warnx("ROM \"%s\" is too large (ignore %d bytes)", - filename.c_str(), (int)st.st_size - size); + warnx("%s is too large (ignore %zu bytes)", + filename.c_str(), (size_t)st.st_size - size); } - // mmap - // ファイルには書き戻さないけど、オンメモリでハックを入れることが - // できるように MAP_PRIVATE を指定する。 - filesize = size; - file = (uint8 *)mmap(NULL, filesize, PROT_READ | PROT_WRITE, - MAP_PRIVATE, fd, 0); - if (file == MAP_FAILED) { - warn("ROM \"%s\" mmap failed", filename.c_str()); - close(fd); + // 読み込む + 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; } - mem = file; - return true; -} + fd.Close(); -uint64 -ROMDevice::Read8(uint32 addr) -{ - return mem[addr & mask]; + mem = &imagebuf[0]; + return true; } -uint64 -ROMDevice::Read16(uint32 addr) +busdata +ROMDevice::Read(busaddr addr) { - uint16 data; - data = *(uint16 *)&mem[addr & mask]; - return be16toh(data); -} + busdata data; -uint64 -ROMDevice::Read32(uint32 addr) -{ - uint32 data; - data = *(uint32 *)&mem[addr & mask]; - return be32toh(data); + uint32 paddr = addr.Addr() & ~3U; + data = be32toh(*(const uint32 *)&mem[paddr & mask]); + data |= wait; + data |= BusData::Size4; + putlog(4, "$%08x -> $%08x", paddr, data.Data()); + return data; } -uint64 -ROMDevice::Write8(uint32 addr, uint32 data) +busdata +ROMDevice::Write(busaddr addr, uint32 data) { - return (uint64)-1; + busdata r = write_op; + putlog(4, "$%08x.%u <- $%0*x", addr.Addr(), addr.GetSize(), + addr.GetSize() * 2, data); + r |= wait; + r |= BusData::Size4; + return r; } -uint64 -ROMDevice::Write16(uint32 addr, uint32 data) +busdata +ROMDevice::Peek1(uint32 addr) { - return (uint64)-1; + return mem[addr & mask]; } -uint64 -ROMDevice::Write32(uint32 addr, uint32 data) +// アクセスウェイト [clock] を設定。 +void +ROMDevice::SetWait(uint32 wait_) { - return (uint64)-1; + wait = busdata::Wait(wait_ * mpu->GetClock_tsec()); } -uint64 -ROMDevice::Peek8(uint32 addr) +// ファイル名を返す。なければ NULL を返す。 +const char * +ROMDevice::GetFilename() const { - return mem[addr & mask]; + if (filename.empty()) { + return NULL; + } else { + return filename.c_str(); + } }