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

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

//
// Nereid バンクメモリ
//

// バンクメモリはロングワード単位でホストバイトオーダ配置なので、
// バイトアクセス、ワードアクセス時は HLB(), HLW() マクロを使用のこと。

#include "bankram.h"
#include "config.h"
#include "mpu.h"

// コンストラクタ
BankRAMDevice::BankRAMDevice(uint objid_, int ram_size_MB)
	: inherited(objid_)
{
	// ram_size_MB は正数のみ。負数は親側で処理する。
	assert(ram_size_MB >= 0);

	ram_size = ram_size_MB * 1024 * 1024;
	// 初期化は Init() で行う
}

// デストラクタ
BankRAMDevice::~BankRAMDevice()
{
}

// 初期化
bool
BankRAMDevice::Init()
{
	ram.reset(new(std::nothrow) uint8[ram_size]);
	if ((bool)ram == false) {
		warnx("Could not allocate %u bytes at %s", ram_size, __method__);
		return false;
	}

	wait = busdata::Wait(1 * mpu->GetClock_tsec());

	return true;
}

// 電源オン/リセット
void
BankRAMDevice::ResetHard(bool poweron)
{
	if (poweron) {
		// ノイズで埋めたいがとりあえず。
		memset(&ram[0], 0, ram_size);
	}

	// リセットでクリアされる。
	SetPage(0);

	memset(&accstat_read[0],  0, AccStat::BANKLEN);
	memset(&accstat_write[0], 0, AccStat::BANKLEN);
}

inline uint32
BankRAMDevice::Decoder(uint32 addr) const
{
	return pageaddr + (addr & 0xffff);
}

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

	accstat_read[offset >> AccStat::SHIFT] = AccStat::READ;

	data  = *(uint32 *)&ram[offset & ~3U];
	putlog(4, "$%06x ($%06x) -> $%08x", addr.Addr(), offset, data.Data());
	data |= wait;
	data |= BusData::Size4;
	return data;
}

busdata
BankRAMDevice::Write(busaddr addr, uint32 data)
{
	uint32 offset = Decoder(addr.Addr());
	uint32 reqsize = addr.GetSize();
	uint32 datasize = std::min(4 - (offset & 3U), reqsize);

	accstat_write[offset >> AccStat::SHIFT] = AccStat::WRITE;

	if (datasize == 4) {
		putlog(3, "$%06x ($%06x) <- $%08x", addr.Addr(), offset, data);
		*(uint32 *)&ram[offset] = data;
	} else if (datasize == 1) {
		data >>= (reqsize - datasize) * 8;
		putlog(3, "$%06x ($%06x) <- $%02x", addr.Addr(), offset, data);
		ram[HLB(offset)] = data;
	} else {
		data >>= (reqsize - datasize) * 8;
		putlog(3, "$%06x ($%06x) <- $%0*x", addr.Addr(), offset,
			datasize * 2, data);
		for (int i = datasize - 1; i >= 0; i--) {
			ram[HLB(offset + i)] = data;
			data >>= 8;
		}
	}

	busdata r = wait;
	r |= BusData::Size4;
	return r;
}

busdata
BankRAMDevice::Peek1(uint32 addr)
{
	uint32 offset = Decoder(addr);
	return ram[HLB(offset)];
}

bool
BankRAMDevice::Poke1(uint32 addr, uint32 data)
{
	if ((int32)data >= 0) {
		uint32 offset = Decoder(addr);
		ram[HLB(offset)] = data;
	}
	return true;
}

void
BankRAMDevice::SetPage(uint32 page_)
{
	page = page_;
	// XXX 4MB の時の折返し確認
	pageaddr = (page << 16) & (ram_size - 1);

	putlog(2, "Page <- $%02x", page);
}

void
BankRAMDevice::FetchAccStat(uint8 *acc)
{
	// 要素が8バイトと分かっていればこれだけで済む。
	static_assert(AccStat::BANKLEN == 8, "");

	// R|W をマージしながらコピー。
	uint64 tmp;
	tmp  = *(uint64 *)&accstat_read[0];
	tmp |= *(uint64 *)&accstat_write[0];
	*(uint64 *)acc = tmp;

	// 読んだのでリセット。
	memset(&accstat_read[0],  0, AccStat::BANKLEN);
	memset(&accstat_write[0], 0, AccStat::BANKLEN);
}

unix.superglobalmegacorp.com

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