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

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

// キャッシュ

#include "mpu680x0.h"
#include "m68030cache.h"

// 命令キャッシュから指定のアドレスをワードフェッチ。
// ここでは PC を進めたりはしない。
// バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。
uint32
MPU680x0Device::fetch_16_cache(uint32 addr)
{
	putlog(2, "%s addr=%08x", __func__, addr);
	// addr を含むロングワードを読み込んでから、上位か下位だけ返す。
	uint32 data = fetch_32_cache_aligned(addr & ~3);
	if ((addr & 2) == 0) {
		return data >> 16;
	} else {
		return data & 0xffff;
	}
}

// 命令キャッシュから指定のアドレス (ミスアライン可) をロングワードフェッチ。
// ここでは PC を進めたりはしない。
// バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。
uint32
MPU680x0Device::fetch_32_cache(uint32 addr)
{
	putlog(2, "%s addr=%08x", __func__, addr);
	if ((addr & 2) == 0) {
		return fetch_32_cache_aligned(addr);
	} else {
		uint32 data;
		data  = fetch_16_cache(addr) << 16;
		data |= fetch_16_cache(addr + 2);
		return data;
	}
}

// 命令キャッシュから指定のアドレスをロングワードフェッチ。
// addr の下位2ビットは無視される。
// ここでは PC を進めたりはしない。
uint32
MPU680x0Device::fetch_32_cache_aligned(uint32 addr)
{
	putlog(2, "%s addr=%08x", __func__, addr);
	uint32 tag = (addr & 0xffffff00) | (IsSuper() ? 1 : 0);
	uint32 idx = (addr & 0x000000f0) >> 4;

	auto& l = icache->line[idx];
	if (l.tag != tag) {
		// タグが一致しなければ、1ライン充填。
		// XXX 可能ならバースト転送?
		putlog(2, "%s line[%d] invalidate", __func__, idx);

		l.tag = tag;
		l.valid_all = 0;
		// XXX 未実装
		// FALLTHROUGH
	}

	// タグが一致した
	uint32 sel = (addr & 0x0000000c) >> 2;
	if (l.valid[sel] == 0) {
		// シングル充填。
		uint32 data = fetch_32_bus((addr & 0xfffffff0) + (sel << 2));
		if (__predict_true(bus.ci == false)) {
			l.data[sel] = data;
			l.valid[sel] = 1;
			putlog(2, "%s line[%d][%d] <- %08x", __func__, idx, sel, data);
		} else {
			putlog(2, "%s line[%d][%d] = %08x (CI)", __func__, idx, sel, data);
		}
		return data;
	}

	// エントリが有効
	putlog(2, "%s line[%d][%d] -> %08x", __func__, idx, sel, l.data[sel]);
	return l.data[sel];
}

#if 0
uint32
MPU680x0Device::read_8_cache(busaddr addr)
{
	printf("%s not implemented\n", __func__);
	return -1;
}

uint32
MPU680x0Device::read_16_cache(busaddr addr)
{
	printf("%s not implemented\n", __func__);
	return -1;
}

uint32
MPU680x0Device::read_32_cache(busaddr addr)
{
	printf("%s not implemented\n", __func__);
	return -1;
}

void
MPU680x0Device::write_8_cache(busaddr addr, uint32 data)
{
	printf("%s not implemented\n", __func__);
}

void
MPU680x0Device::write_16_cache(busaddr addr, uint32 data)
{
	printf("%s not implemented\n", __func__);
}

void
MPU680x0Device::write_32_cache(busaddr addr, uint32 data)
{
	printf("%s not implemented\n", __func__);
}
#endif

// CACR レジスタ書き込み
void
MPU680x0Device::SetCACR(uint32 newval)
{
	newval &= M68K::CACR_MASK;
	uint32 oldval = reg.cacr;
	uint32 chgval = oldval ^ newval;

	// EI
	if ((chgval & M68K::CACR_EI) != 0) {
		if ((newval & M68K::CACR_EI) != 0) {
			// 命令キャッシュ有効
			icache_enable = true;
			putlog(1, "I-Cache enabled");
		} else {
			// 命令キャッシュ無効
			icache_enable = false;
			putlog(1, "I-Cache disabled");
		}
	}

	// FI
	if ((chgval & M68K::CACR_FI) != 0) {
		icache_freeze = (newval & M68K::CACR_FI);
	}

	// CEI
	if ((chgval & M68K::CACR_CEI) != 0) {
		// CAAR の b7-2 で示されるロングワードを無効にする。
		uint32 idx = (reg.cacr & 0x000000f0) >> 4;
		uint32 num = (reg.cacr & 0x0000000c) >> 2;
		auto& l = icache->line[idx];
		l.valid[num] = 0;

		newval &= ~M68K::CACR_CEI;
	}

	// CI
	if ((chgval & M68K::CACR_CI) != 0) {
		// 命令キャッシュの全エントリをクリア。
		for (auto& l : icache->line) {
			l.valid_all = 0;
		}

		newval &= ~M68K::CACR_CI;
	}

	// データキャッシュは未実装。
	newval &= ~(M68K::CACR_CD | M68K::CACR_CED);

	// とりあえずレジスタイメージも保存。
	reg.cacr = newval;
}

unix.superglobalmegacorp.com

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