File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / rom.cpp
Revision 1.1.1.15 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:06:00 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
//

//
// 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 <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>

//
// ROM 共通部
//

ROMDevice::ROMDevice(uint objid_)
	: inherited(objid_)
{
	mask = 0xffffffff;
}

ROMDevice::~ROMDevice()
{
}

// 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 はパスを含まないファイル名のみ。パスはこちらで探す。
// 失敗した場合は warn 系でエラーメッセージを表示して false を返す。
bool
ROMDevice::LoadROM(const char *name, uint size)
{
	struct stat st;

	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;
	}

	// オープン
	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 %u but %jd)",
			filename.c_str(), size, (intmax_t)st.st_size);
		return false;
	}
	if (st.st_size > size) {
		// 大きすぎるほうはワーニングだけでいいか
		warnx("%s is too large (ignore %zu bytes)",
			filename.c_str(), (size_t)st.st_size - size);
	}

	// 読み込む
	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;
}

busdata
ROMDevice::Read(busaddr addr)
{
	busdata 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;
}

busdata
ROMDevice::Write(busaddr addr, uint32 data)
{
	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;
}

busdata
ROMDevice::Peek1(uint32 addr)
{
	return mem[addr & mask];
}

// アクセスウェイト [clock] を設定。
void
ROMDevice::SetWait(uint32 wait_)
{
	wait = busdata::Wait(wait_ * mpu->GetClock_tsec());
}

// ファイル名を返す。なければ NULL を返す。
const char *
ROMDevice::GetFilename() const
{
	if (filename.empty()) {
		return NULL;
	} else {
		return filename.c_str();
	}
}

unix.superglobalmegacorp.com

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