|
|
nono 0.5.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
#pragma once
//
// 1回の(アラインド)物理アクセスを担当するマクロ。
// これらは続く _mmu テンプレートで使用する。
// goto を含むことに注意。gcc 拡張式(?)に注意。
// Translate* は Fetch, Read, Write の3種だが、Mainbus には
// Read, Write しかないことに注意。物理バスに FC0 と FC1、つまりプログラム
// 空間かどうかの情報は出していないため。
//
#define FETCH(size) ({ \
bus.paddr = bus.laddr; \
if (use_mmu && TranslateFetch() == false) \
goto buserr; \
uint64 data_ = mainbus->__CONCAT(Read,size)(bus.paddr); \
if ((int64)data_ < 0) \
goto buserr; \
data_; /* これが戻り値 */ \
})
#define READ(size) ({ \
bus.paddr = bus.laddr; \
if (use_mmu && TranslateRead() == false) \
goto buserr; \
uint64 data_ = mainbus->__CONCAT(Read,size)(bus.paddr); \
if ((int64)data_ < 0) \
goto buserr; \
data_; /* これが戻り値 */ \
})
#define WRITE(size, data) ({ \
bus.paddr = bus.laddr; \
if (use_mmu && TranslateWrite() == false) \
goto buserr; \
int64 berr_ = mainbus->__CONCAT(Write,size)(bus.paddr, (data)); \
if (berr_ < 0) \
goto buserr; \
0; /* 戻り値不要だけど一応 */ \
})
//
// MMU を考慮した下請けテンプレート。
// 1回分のミスアラインドありのアクセスを担当。
//
template<bool use_mmu> uint32
fetch_16_mmu()
{
uint64 data;
data = FETCH(16);
// XXX バスエラー時に PC をインクリメントするタイミングは?
reg.pc += 2;
return data;
buserr:
bus.SET_SSW(use_mmu, M68K::SSW_SIZE_WORD);
throw M68K::EXCEP_BUSERR;
}
template<bool use_mmu> uint32
fetch_32_mmu()
{
uint64 data;
if ((bus.laddr & 3) == 0) {
data = FETCH(32);
} else {
uint64 h, l;
h = FETCH(16);
bus.laddr += 2;
l = FETCH(16);
data = (h << 16) | l;
}
// XXX バスエラー時に PC をインクリメントするタイミングは?
reg.pc += 4;
return data;
buserr:
bus.SET_SSW(use_mmu, M68K::SSW_SIZE_LONG);
throw M68K::EXCEP_BUSERR;
}
template<bool use_mmu> uint32
read_8_mmu()
{
uint64 data;
data = READ(8);
if (1)
putlog(2, "read_8 %08X -> %02X", bus.laddr, (uint32)data);
return data;
buserr:
bus.SET_SSW(use_mmu, M68K::SSW_SIZE_BYTE);
throw M68K::EXCEP_BUSERR;
}
template<bool use_mmu> uint32
read_16_mmu()
{
uint64 data;
if ((bus.laddr & 1) == 0) {
data = READ(16);
} else {
uint64 h, l;
h = READ(8);
bus.laddr += 1;
l = READ(8);
data = (h << 8) | l;
}
if (1)
putlog(2, "read_16 %08X -> %04X", bus.laddr, (uint32)data);
return data;
buserr:
bus.SET_SSW(use_mmu, M68K::SSW_SIZE_WORD);
throw M68K::EXCEP_BUSERR;
}
template<bool use_mmu> uint32
read_32_mmu()
{
uint64 data;
if ((bus.laddr & 3) == 0) {
data = READ(32);
} else if ((bus.laddr & 1) == 0) {
uint64 h, l;
h = READ(16);
bus.laddr += 2;
l = READ(16);
data = (h << 16) | l;
} else {
uint64 h, m, l;
h = READ(8);
bus.laddr += 1;
m = READ(16);
bus.laddr += 2;
l = READ(8);
data = (h << 24) | (m << 8) | l;
}
if (1)
putlog(2, "read_32 %08X -> %08X", bus.laddr, (uint32)data);
return data;
buserr:
bus.SET_SSW(use_mmu, M68K::SSW_SIZE_LONG);
throw M68K::EXCEP_BUSERR;
}
template<bool use_mmu> void
write_8_mmu()
{
uint32 data = bus.data;
if (1)
putlog(2, "write_8 %08X <- %02X", bus.laddr, data);
WRITE(8, data);
return;
buserr:
bus.SET_SSW(use_mmu, M68K::SSW_SIZE_BYTE);
throw M68K::EXCEP_BUSERR;
}
template<bool use_mmu> void
write_16_mmu()
{
uint32 data = bus.data;
if (1)
putlog(2, "write_16 %08X <- %04X", bus.laddr, data);
if ((bus.laddr & 1) == 0) {
WRITE(16, data);
} else {
WRITE(8, data >> 8);
bus.laddr += 1;
WRITE(8, data & 0xff);
}
return;
buserr:
bus.SET_SSW(use_mmu, M68K::SSW_SIZE_WORD);
throw M68K::EXCEP_BUSERR;
}
template<bool use_mmu> void
write_32_mmu()
{
uint32 data = bus.data;
if (1)
putlog(2, "write_32 %08X <- %08X", bus.laddr, data);
if ((bus.laddr & 3) == 0) {
WRITE(32, data);
} else if ((bus.laddr & 1) == 0) {
WRITE(16, data >> 16);
bus.laddr += 2;
WRITE(16, data & 0xffff);
} else {
WRITE(8, data >> 24);
bus.laddr += 1;
WRITE(16, (data >> 8) & 0xffff);
bus.laddr += 2;
WRITE(8, data & 0xff);
}
return;
buserr:
bus.SET_SSW(use_mmu, M68K::SSW_SIZE_LONG);
throw M68K::EXCEP_BUSERR;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.