|
|
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;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.