File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / sram.cpp
Revision 1.1.1.17 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:59 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//

//
// SRAM
//

// SRAM はビッグエンディアンのままメモリに置かれるので、
// 必要ならアクセス時に都度変換すること。

#include "sram.h"
#include "config.h"
#include "mainapp.h"
#include "mainram.h"
#include <sys/mman.h>

// コンストラクタ
SRAMDevice::SRAMDevice()
	: inherited(OBJ_SRAM)
{
}

// デストラクタ
SRAMDevice::~SRAMDevice()
{
	if ((bool)file) {
		// この場合は mem は file が管理している。
		file.reset();
	} else {
		if (mem) {
			munmap(mem, sramsize);
		}
	}
}

// 初期化
bool
SRAMDevice::Init()
{
	// SRAM ファイルをオープン。
	if (gMainApp.GetVMDir().empty()) {
		// VM ディレクトリ指定がなければ、オンメモリに初期値を用意する。
		// Human68k モードで VM ディレクトリを指定しない場合に起きる。
		void *m = mmap(NULL, sramsize, PROT_READ | PROT_WRITE,
			MAP_ANON | MAP_SHARED, -1, 0);
		if (m == MAP_FAILED) {
			warn("%s: mmap", __method__);
			return false;
		}
		mem = (uint8 *)m;
		memcpy(mem, &initialdata[0], initialdata.size());
	} else {
		// VM ディレクトリ指定があれば、ファイルを開く。
		filename = gMainApp.GetVMDir() + "SRAM.DAT";
		try {
			file.reset(new MappedFile());
		} catch (...) { }
		if ((bool)file == false) {
			warnx("Failed to initialize MappedFile at %s", __method__);
			return false;
		}
		file->SetFilename(filename);
		file->SetDispname(string_format("SRAM \"%s\"", filename.c_str()));
		mem = file->OpenCreate(sramsize, &initialdata[0], initialdata.size());
		if (mem == NULL) {
			// エラーメッセージは表示済み。
			return false;
		}
	}

	// SRAM の RAM 容量欄を設定値に同期させる。
	// この処理はアプリケーション起動時に一回行われるのみで、
	// その後の VM 内のリセット等では動作しない。
	if (gConfig->Find("sram-sync-ramsize").AsBool()) {
		SyncRAMSize();
	}

	return true;
}

// リセット
void
SRAMDevice::ResetHard(bool poweron)
{
	// XXX 未調査
	writeable = false;
}

// SRAM の RAM 容量欄を設定値に同期させる。
void
SRAMDevice::SyncRAMSize()
{
	// SRAM の内容が無効なら何もしない。
	static const std::array<uint8, 7> magic {
		0x82, 0x77, '6', '8', '0', '0', '0'
	};
	for (int i = 0; i < magic.size(); i++) {
		if (mem[i] != magic[i]) {
			return;
		}
	}

	uint32 ramsize = (uint32)GetMainRAMDevice()->GetSize();

	// 値が違う時だけ表示したいので一旦読み出して比較
	uint32 cursize;
	cursize  = mem[0x08] << 24;
	cursize |= mem[0x09] << 16;
	cursize |= mem[0x0a] << 8;
	cursize |= mem[0x0b];
	if (cursize != ramsize) {
		if (gMainApp.GetVMDir().empty()) {
			// Human68k モードで -c のない時は表示不要。ダミー SRAM なので。
		} else {
			warnx("SRAM: Update ramsize %uMB", ramsize / 1024 / 1024);
		}

		mem[0x08] = ramsize >> 24;
		mem[0x09] = ramsize >> 16;
		mem[0x0a] = ramsize >> 8;
		mem[0x0b] = ramsize;
	}
}

// アドレスデコーダ
inline uint32
SRAMDevice::Decoder(uint32 addr) const
{
	uint32 offset = addr - baseaddr;
	assertmsg(offset < file->GetMemSize(),
		"offset=%x memlen=%x", offset, (uint)file->GetMemSize());
	return offset;
}

busdata
SRAMDevice::Read(busaddr addr)
{
	uint32 offset = Decoder(addr.Addr());
	busdata data;

	data  = Get16(offset & ~1U);
	data |= BusData::Size2;
	putlog(2, "$%06x -> $%04x", addr.Addr() & ~1U, data.Data());
	return data;
}

busdata
SRAMDevice::Write(busaddr addr, uint32 data)
{
	uint32 offset = Decoder(addr.Addr());
	uint32 reqsize = addr.GetSize();
	uint32 datasize = std::min(2 - (offset & 1), reqsize);
	data >>= (reqsize - datasize) * 8;

	if (writeable) {
		if (offset < 0x100) {
			putlog(1, "$%06x.%c <- $%0*x", addr.Addr(),
				(datasize == 1 ? 'B' : 'W'), datasize * 2, data);
		}
		if (datasize == 1) {
			mem[offset] = data;
		} else {
			*(uint16 *)&mem[offset] = htobe16(data);
		}
	} else {
		putlog(1, "Write protected $%06x.%c <- $%0*x", addr.Addr(),
			(datasize == 1 ? 'B' : 'W'), datasize * 2, data);
	}

	busdata r = busdata::Size(datasize);
	return r;
}

busdata
SRAMDevice::Peek1(uint32 addr)
{
	uint32 offset = Decoder(addr);
	uint32 data = Get16(offset & ~1U);

	if ((offset & 1) == 0) {
		return data >> 8;
	} else {
		return data & 0xff;
	}
}

bool
SRAMDevice::Poke1(uint32 addr, uint32 data)
{
	// WriteEnable() に関わらず変更する。
	// また Get8()、Get16() はこの変更の影響を受けないことに注意。

	if ((int32)data >= 0) {
		uint32 offset = Decoder(addr);
		mem[offset] = data;
	}
	return true;
}

void
SRAMDevice::WriteEnable(bool value)
{
	if (writeable == false && value == true) {
		putlog(1, "Write Enable");
	} else if (writeable == true && value == false) {
		putlog(1, "Write Disable");
	}

	writeable = value;
}

// SRAM から副作用なく読み出す。
// ただしホストファイル起動モードなら改変した値を返す。
uint32
SRAMDevice::Get16(uint32 offset) const
{
	if (gMainApp.exec_file) {
		switch (offset) {
		 case 0x0c:			// ROM 起動アドレス(.L)
			return (plutoaddr >> 16) & 0xffff;
		 case 0x0e:
			return plutoaddr & 0xffff;

		 case 0x18:			// 起動デバイス(.W) を ROM($a000) にする
			return 0xa000;

		 default:
			break;
		}
	}

	// 他は SRAM から
	uint32 data = *(uint16 *)&mem[offset];
	return be16toh(data);
}

// SRAM から副作用なくロングワードで読み出す。
// ただしホストファイル起動モードなら改変した値を返す。
uint32
SRAMDevice::Get32(uint32 offset) const
{
	uint32 data;

	data  = Get16(offset) << 16;
	data |= Get16(offset + 2);

	return data;
}

// X68030 が初期化した SRAM の初期値。
//
// 0000: 82 77 36 38 30 30 30 57  00 40 00 00 00 fc 00 00  |.w68000W.@......|
// 0010: 00 ed 01 00 ff ff ff ff  00 00 4e 07 00 10 00 00  |..........N.....|
// 0020: 00 00 ff ff 00 00 07 00  0e 00 0d 00 00 00 00 00  |................|
// 0030: f8 3e ff c0 ff fe de 6c  40 22 03 02 00 08 00 00  |.>.....l@"......|
// 0040: 00 00 00 00 00 00 00 00  00 ff f4 00 04 00 01 01  |................|
// 0050: 00 00 00 20 00 03 f9 01 (00 00 00 00 00 00 00 00) |... ............|
/*static*/ std::array<uint8, 0x58>
SRAMDevice::initialdata {
	0x82, 0x77, 0x36, 0x38, 0x30, 0x30, 0x30, 0x57,
	0x00, 0x40, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00,
	0x00, 0xed, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff,
	0x00, 0x00, 0x4e, 0x07, 0x00, 0x10, 0x00, 0x00,
	0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x07, 0x00,
	0x0e, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xf8, 0x3e, 0xff, 0xc0, 0xff, 0xfe, 0xde, 0x6c,
	0x40, 0x22, 0x03, 0x02, 0x00, 0x08, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0xff, 0xf4, 0x00, 0x04, 0x00, 0x01, 0x01,
	0x00, 0x00, 0x00, 0x20, 0x00, 0x03, 0xf9, 0x01,
};

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.