--- nono/vm/sram.cpp 2026/04/29 17:04:32 1.1.1.3 +++ nono/vm/sram.cpp 2026/04/29 17:05:14 1.1.1.10 @@ -1,109 +1,151 @@ // // nono -// Copyright (C) 2017 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // -#include "mainapp.h" -#include "sram.h" -#include -#include -#include - // // SRAM // + // SRAM はビッグエンディアンのままメモリに置かれるので、 // 必要ならアクセス時に都度変換すること。 -// -std::unique_ptr gSRAM; +#include "sram.h" +#include "config.h" +#include "mainapp.h" +#include "ram.h" +#include + +// グローバル参照用 +SRAMDevice *gSRAM; +// コンストラクタ SRAMDevice::SRAMDevice() + : inherited("SRAM") { - logname = "sram"; - devname = "SRAM"; devaddr = baseaddr; - devlen = 0x10000; // 通常実際は16KBだが64KB分占有しておく - - fd = -1; + devlen = 0x4000; } +// デストラクタ SRAMDevice::~SRAMDevice() { - if (mem) { - munmap(mem, memlen); - mem = NULL; - memlen = 0; - } - if (fd >= 0) { - close(fd); - fd = -1; - } + gSRAM = NULL; } bool SRAMDevice::Init() { - struct stat st; - - filename = gMainApp.GetVMDir() + "SRAM030.DAT"; - memlen = 16 * 1024; - - fd = open(filename.c_str(), O_RDWR); - if (fd == -1) { - warn("SRAM \"%s\" open failed", filename.c_str()); + filename = gMainApp.GetVMDir() + "SRAM.DAT"; + file.SetFilename(filename); + file.SetDispname(string_format("SRAM \"%s\"", filename.c_str())); + mem = file.OpenCreate(16 * 1024); + if (mem == NULL) { return false; } - // ファイルサイズをチェック。 - // ファイルが短くても mmap はしれっと成功してしまうようだ。 - if (fstat(fd, &st) == -1) { - warn("SRAM \"%s\" fstat failed", filename.c_str()); - close(fd); - return false; - } - if (st.st_size < memlen) { - warnx("SRAM \"%s\" is too short (filesize is expected %d but %d)", - filename.c_str(), memlen, (int)st.st_size); - close(fd); - return false; - } - if (st.st_size > memlen) { - // 大きすぎるほうはワーニングだけでいいか - warnx("SRAM \"%s\" is too large (ignore %d bytes)", - filename.c_str(), (int)st.st_size - memlen); + // SRAM の RAM 容量欄を設定値に同期させる。 + // この処理はアプリケーション起動時に一回行われるのみで、 + // その後の VM 内のリセット等では動作しない。 + bool sync = gConfig->Find("sram-sync-ramsize").AsInt(); + if (sync) { + SyncRAMSize(); } - mem = (uint8 *)mmap(NULL, memlen, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); - if (mem == MAP_FAILED) { - warn("SRAM \"%s\" mmap failed", filename.c_str()); - close(fd); - return false; + return true; +} + +// リセット +void +SRAMDevice::ResetHard(bool poweron) +{ + // XXX 未調査 + writeable = false; +} + +// SRAM の RAM 容量欄を設定値に同期させる。 +void +SRAMDevice::SyncRAMSize() +{ + // SRAM の内容が無効なら何もしない。 + static const std::array magic { + 0x82, 0x77, '6', '8', '0', '0', '0' + }; + for (int i = 0; i < magic.size(); i++) { + if (mem[i] != magic[i]) { + return; + } } - return true; + uint32 ramsize = gRAM->GetSize(); + + // 値が違う時だけ表示したいので一旦読み出して比較 + uint32 cursize; + cursize = mem[0x08] << 24; + cursize |= mem[0x09] << 16; + cursize |= mem[0x0a] << 8; + cursize |= mem[0x0b]; + if (cursize != ramsize) { + // ここは Init() なので putmsg() は使えない + warnx("SRAM: Update ramsize %dMB", ramsize / 1024 / 1024); + + mem[0x08] = ramsize >> 24; + mem[0x09] = ramsize >> 16; + mem[0x0a] = ramsize >> 8; + mem[0x0b] = ramsize; + } } // アドレスデコーダ inline uint64 SRAMDevice::Decoder(uint32 addr) const { - return addr - baseaddr; + uint32 offset = addr - baseaddr; + assertmsg(offset < file.GetMemSize(), + "offset=%x memlen=%x", offset, (int)file.GetMemSize()); + return offset; } uint64 SRAMDevice::Read8(uint32 addr) { uint32 offset = Decoder(addr); - return mem[offset]; + uint32 data; + + // ホストファイル起動モードなら起動アドレスとして Pluto-X を見せる。 + if (gMainApp.exec_file) { + data = PeekHostBoot(offset); + if ((int32)data >= 0) { + if ((offset & 1) == 0) { + data = data >> 8; + } else { + data = data & 0xff; + } + return data; + } + } + + data = mem[offset]; + return data; } uint64 SRAMDevice::Read16(uint32 addr) { uint32 offset = Decoder(addr); - return be16toh(*(uint16 *)&mem[offset]); + uint32 data; + + // ホストファイル起動モードなら起動アドレスとして Pluto-X を見せる。 + if (gMainApp.exec_file) { + data = PeekHostBoot(offset); + if ((int32)data >= 0) { + return data; + } + } + + data = be16toh(*(uint16 *)&mem[offset]); + return data; } uint64 @@ -113,11 +155,11 @@ SRAMDevice::Write8(uint32 addr, uint32 d if (writeable) { if (offset < 0x100) { - putlog(1, "更新 $%06x <- $%02x", addr, data); + putlog(1, "$%06x.B <- $%02x", addr, data); } mem[offset] = data; } else { - putlog(1, "書き込み禁止 $%06x <- $%02x", addr, data); + putlog(1, "Write protected $%06x.B <- $%02x", addr, data); } return 0; } @@ -129,11 +171,11 @@ SRAMDevice::Write16(uint32 addr, uint32 if (writeable) { if (offset < 0x100) { - putlog(1, "更新 $%06x <- $%04x", addr, data); + putlog(1, "$%06x.W <- $%04x", addr, data); } *(uint16 *)&mem[offset] = htobe16(data); } else { - putlog(1, "書き込み禁止 $%06x <- $%04x", addr, data); + putlog(1, "Write protected $%06x.W <- $%04x", addr, data); } return 0; } @@ -142,6 +184,20 @@ uint64 SRAMDevice::Peek8(uint32 addr) { uint32 offset = Decoder(addr); + + // ホストファイル起動モードなら起動アドレスとして Pluto-X を見せる。 + if (gMainApp.exec_file) { + uint32 data = PeekHostBoot(offset); + if ((int32)data >= 0) { + if ((offset & 1) == 0) { + data = data >> 8; + } else { + data = data & 0xff; + } + return data; + } + } + return mem[offset]; } @@ -149,10 +205,46 @@ void SRAMDevice::write_enable(bool value) { if (writeable == false && value == true) { - putlog(1, "書き込み許可"); + putlog(1, "Write Enable"); } else if (writeable == true && value == false) { - putlog(1, "書き込み禁止"); + putlog(1, "Write Disable"); } writeable = value; } + +// ホストファイル起動用の読み出し値を返す。 +// offset はワード境界であること。戻り値はホストバイトオーダのワード値。 +// 本来の SRAM の値を読み出してよいところについては (uint32)-1 を返す。 +// +// mem[] は SRAM.DAT を直接 mmap(2) しており書き換えておくことは出来ないため、 +// ホストファイル起動モードなら読み出し時に動的に値を返す。 +uint32 +SRAMDevice::PeekHostBoot(uint32 offset) const +{ + switch (offset) { + case 0x0c: // ROM 起動アドレス(H) + return (plutoaddr >> 16); + case 0x0e: // ROM 起動アドレス(L) + return (plutoaddr & 0xffff); + case 0x18: // 起動デバイスを ROM にする + return 0xa000; + default: + break; + } + return (uint32)-1; +} + +// SRAM $ed000c.L ROM 起動アドレスを返す +uint32 +SRAMDevice::GetROMAddr() const +{ + uint32 data; + + data = mem[0x0c] << 24; + data |= mem[0x0d] << 16; + data |= mem[0x0e] << 8; + data |= mem[0x0f]; + + return data; +}