--- nono/m680x0/m68030bus.cpp 2026/04/29 17:04:34 1.1.1.3 +++ nono/m680x0/m68030bus.cpp 2026/04/29 17:05:22 1.1.1.5 @@ -4,481 +4,363 @@ // Licensed under nono-license.txt // -// 論理アクセス +#include "mpu680x0.h" -// -// 1回の(アラインド)物理アクセスを担当するマクロ。 -// これらは続く _mmu テンプレートで使用する。 -// goto を含むことに注意。gcc 拡張式(?)に注意。 -// mmu_translate_* は fetch, read, write の3種だが、vm_phys_ は -// read, write しかないことに注意。物理バスに FC0 と FC1、つまりプログラム -// 空間かどうかの情報は出していないため。 -// - -#define FETCH(size) ({ \ - cpu->bus.paddr = cpu->bus.laddr; \ - if (use_mmu && m68030_mmu_translate_fetch(cpu) == false) \ - goto buserr; \ - uint64 data_ = vm_phys_read_##size(cpu->bus.paddr); \ - if ((int64)data_ < 0) \ - goto buserr; \ - data_; /* これが戻り値 */ \ -}) - -#define READ(size) ({ \ - cpu->bus.paddr = cpu->bus.laddr; \ - if (use_mmu && m68030_mmu_translate_read(cpu) == false) \ - goto buserr; \ - uint64 data_ = vm_phys_read_##size(cpu->bus.paddr); \ - if ((int64)data_ < 0) \ - goto buserr; \ - data_; /* これが戻り値 */ \ -}) - -#define WRITE(size, data) ({ \ - cpu->bus.paddr = cpu->bus.laddr; \ - if (use_mmu && m68030_mmu_translate_write(cpu) == false) \ - goto buserr; \ - int64 berr_ = vm_phys_write_##size(cpu->bus.paddr, (data)); \ - if (berr_ < 0) \ - goto buserr; \ - 0; /* 戻り値不要だけど一応 */ \ -}) - -// バスエラー時に SSW をセットする。 -// m68030_*_NN_mmu() 関数の下請け。 -static inline void -SET_SSW(m68kcpu *cpu, bool use_mmu, uint size) -{ - // サイズを設定 - cpu->bus.ssw &= ~SSW_SIZE_MASK; - cpu->bus.ssw |= size; - - if (use_mmu) { - // データアクセスなら再試行のため DataFault ビットをセット。 - // 命令アクセスなら RB をセット。 - if ((cpu->bus.ssw & FC_DATA)) { - cpu->bus.ssw |= SSW_DF; - } else { - cpu->bus.ssw |= SSW_RB; - } - } -} - -// -// MMU を考慮した下請けテンプレート。 -// 1回分のミスアラインドありのアクセスを担当。 -// +// 現在の FC での通常アクセス (MPU 内部から使用する) +// ミスアライン可。 +// バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。 +// uint32 fetch_{16,32}() +// uint32 read_{8,16,32}(laddr) +// void write_{8,16,32}(laddr, data) -template uint32 -m68030_fetch_16_mmu(m68kcpu *cpu) +// reg.pc からワードをフェッチし reg.pc を進める。 +uint32 +MPU680x0Device::fetch_16() { - uint64 data; + uint32 data; - data = FETCH(16); - // XXX バスエラー時に PC をインクリメントするタイミングは? - RegPC += 2; + if (__predict_true(icache_enable)) { + data = fetch_16_cache(reg.pc); + } else { + data = fetch_16_bus(reg.pc); + } + reg.pc += 2; return data; - - buserr: - SET_SSW(cpu, use_mmu, SSW_SIZE_WORD); - throw M68K_EXCEP_BUSERR; } -template uint32 -m68030_fetch_32_mmu(m68kcpu *cpu) +// reg.pc からロングワード(ミスアライン可)をフェッチし reg.pc を進める。 +uint32 +MPU680x0Device::fetch_32() { - uint64 data; + uint32 data; - if ((cpu->bus.laddr & 3) == 0) { - data = FETCH(32); + if (__predict_true(icache_enable)) { + data = fetch_32_cache(reg.pc); } else { - uint64 h, l; - - h = FETCH(16); - cpu->bus.laddr += 2; - - l = FETCH(16); - data = (h << 16) | l; + if ((reg.pc & 2) == 0) { + data = fetch_32_bus(reg.pc); + } else { + data = fetch_16_bus(reg.pc) << 16; + data |= fetch_16_bus(reg.pc + 2); + } } - // XXX バスエラー時に PC をインクリメントするタイミングは? - RegPC += 4; - return data; + reg.pc += 4; - buserr: - SET_SSW(cpu, use_mmu, SSW_SIZE_LONG); - throw M68K_EXCEP_BUSERR; + return data; } -template uint32 -m68030_read_8_mmu(m68kcpu *cpu) +uint32 +MPU680x0Device::read_8(uint32 addr) { - uint64 data; - - data = READ(8); - - if (1) - cpulog(2, "m68030_read_8 %08X -> %02X", cpu->bus.laddr, (uint32)data); - return data; - - buserr: - SET_SSW(cpu, use_mmu, SSW_SIZE_BYTE); - throw M68K_EXCEP_BUSERR; + busaddr laddr(addr, fc_data | busaddr::R); + return read_8_fc(laddr); } -template uint32 -m68030_read_16_mmu(m68kcpu *cpu) +uint32 +MPU680x0Device::read_16(uint32 addr) { - uint64 data; - - if ((cpu->bus.laddr & 1) == 0) { - data = READ(16); - } else { - uint64 h, l; - - h = READ(8); - cpu->bus.laddr += 1; - - l = READ(8); - data = (h << 8) | l; - } - - if (1) - cpulog(2, "m68030_read_16 %08X -> %04X", cpu->bus.laddr, (uint32)data); - return data; - - buserr: - SET_SSW(cpu, use_mmu, SSW_SIZE_WORD); - throw M68K_EXCEP_BUSERR; + busaddr laddr(addr, fc_data | busaddr::R); + return read_16_fc(laddr); } -template uint32 -m68030_read_32_mmu(m68kcpu *cpu) +uint32 +MPU680x0Device::read_32(uint32 addr) { - uint64 data; - - if ((cpu->bus.laddr & 3) == 0) { - data = READ(32); - } else if ((cpu->bus.laddr & 1) == 0) { - uint64 h, l; - - h = READ(16); - cpu->bus.laddr += 2; - - l = READ(16); - data = (h << 16) | l; - } else { - uint64 h, m, l; - - h = READ(8); - cpu->bus.laddr += 1; - - m = READ(16); - cpu->bus.laddr += 2; - - l = READ(8); - data = (h << 24) | (m << 8) | l; - } - - if (1) - cpulog(2, "m68030_read_32 %08X -> %08X", cpu->bus.laddr, (uint32)data); - return data; - - buserr: - SET_SSW(cpu, use_mmu, SSW_SIZE_LONG); - throw M68K_EXCEP_BUSERR; + busaddr laddr(addr, fc_data | busaddr::R); + return read_32_fc(laddr); } -template void -m68030_write_8_mmu(m68kcpu *cpu) +void +MPU680x0Device::write_8(uint32 addr, uint32 data) { - uint32 data = cpu->bus.data; - - if (1) - cpulog(2, "m68030_write_8 %08X <- %02X", cpu->bus.laddr, data); - - WRITE(8, data); - return; - - buserr: - SET_SSW(cpu, use_mmu, SSW_SIZE_BYTE); - throw M68K_EXCEP_BUSERR; + busaddr laddr(addr, fc_data | busaddr::W); + write_8_fc(laddr, data); } -template void -m68030_write_16_mmu(m68kcpu *cpu) +void +MPU680x0Device::write_16(uint32 addr, uint32 data) { - uint32 data = cpu->bus.data; - - if (1) - cpulog(2, "m68030_write_16 %08X <- %04X", cpu->bus.laddr, data); - - if ((cpu->bus.laddr & 1) == 0) { - WRITE(16, data); - } else { - WRITE(8, data >> 8); - - cpu->bus.laddr += 1; - WRITE(8, data & 0xff); - } - return; - - buserr: - SET_SSW(cpu, use_mmu, SSW_SIZE_WORD); - throw M68K_EXCEP_BUSERR; + busaddr laddr(addr, fc_data | busaddr::W); + write_16_fc(laddr, data); } -template void -m68030_write_32_mmu(m68kcpu *cpu) +void +MPU680x0Device::write_32(uint32 addr, uint32 data) { - uint32 data = cpu->bus.data; - - if (1) - cpulog(2, "m68030_write_32 %08X <- %08X", cpu->bus.laddr, data); - - if ((cpu->bus.laddr & 3) == 0) { - WRITE(32, data); - } else if ((cpu->bus.laddr & 1) == 0) { - WRITE(16, data >> 16); + busaddr laddr(addr, fc_data | busaddr::W); + write_32_fc(laddr, data); +} - cpu->bus.laddr += 2; - WRITE(16, data & 0xffff); - } else { - WRITE(8, data >> 24); +// FC 指定アクセス (MPU コアから使用する) +// ミスアライン可。 +// バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。 +// uint32 read_{8,16,32}_fc(busaddr) +// void write_{8,16,32}_fc(busaddr, data) +// (fetch は常に現在の FC でアクセスするので FC 指定版は不要) - cpu->bus.laddr += 1; - WRITE(16, (data >> 8) & 0xffff); +uint32 +MPU680x0Device::read_8_fc(busaddr addr) +{ + uint32 data; - cpu->bus.laddr += 2; - WRITE(8, data & 0xff); + if (1) { + data = read_8_bus(addr); } - return; - buserr: - SET_SSW(cpu, use_mmu, SSW_SIZE_LONG); - throw M68K_EXCEP_BUSERR; + return data; } -// m68030_{fetch,read,write}_NN() と m68030_{read,write}_NN_fc() の共通部分。 -// fetch には FC 指定版はないので分ける必要は本来ないけど対称性のため。 -// cpu->bus に必要な情報はセットされている。 -// _bus 接尾辞はバスアクセスというより bus 構造体を使ったアクセスという感じ。 - -static inline uint32 -m68030_fetch_16_bus(m68kcpu *cpu) +uint32 +MPU680x0Device::read_16_fc(busaddr addr) { - if (cpu->mmu_enable) { - return m68030_fetch_16_mmu(cpu); - } else { - return m68030_fetch_16_mmu(cpu); - } -} + uint32 data; -static inline uint32 -m68030_fetch_32_bus(m68kcpu *cpu) -{ - if (cpu->mmu_enable) { - return m68030_fetch_32_mmu(cpu); - } else { - return m68030_fetch_32_mmu(cpu); + if (1) { + // バスアクセスは要整列。 + if (__predict_true((addr & 1) == 0)) { + data = read_16_bus(addr); + } else { + data = read_8_bus(addr) << 8; + addr += 1; + data |= read_8_bus(addr); + } } -} -static uint32 -m68030_read_8_bus(m68kcpu *cpu) -{ -if(1)cpulog(2, "%s $%08x", __func__, cpu->bus.laddr); - if (cpu->mmu_enable) { - return m68030_read_8_mmu(cpu); - } else { - return m68030_read_8_mmu(cpu); - } + return data; } -static uint32 -m68030_read_16_bus(m68kcpu *cpu) +uint32 +MPU680x0Device::read_32_fc(busaddr addr) { -if(1)cpulog(2, "%s $%08x", __func__, cpu->bus.laddr); - if (cpu->mmu_enable) { - return m68030_read_16_mmu(cpu); - } else { - return m68030_read_16_mmu(cpu); - } -} + uint32 data; -static uint32 -m68030_read_32_bus(m68kcpu *cpu) -{ -if(1)cpulog(2, "%s $%08x", __func__, cpu->bus.laddr); - if (cpu->mmu_enable) { - return m68030_read_32_mmu(cpu); - } else { - return m68030_read_32_mmu(cpu); + if (1) { + // バスアクセスは要整列。 + if (__predict_true((addr & 3) == 0)) { + data = read_32_bus(addr); + } else if (__predict_true((addr & 1) == 0)) { + data = read_16_bus(addr) << 16; + addr += 2; + data |= read_16_bus(addr); + } else { + data = read_8_bus(addr) << 24; + addr += 1; + data |= read_16_bus(addr) << 8; + addr += 2; + data |= read_8_bus(addr); + } } + + return data; } -static void -m68030_write_8_bus(m68kcpu *cpu) +void +MPU680x0Device::write_8_fc(busaddr addr, uint32 data) { -if(1)cpulog(2, "%s $%08x", __func__, cpu->bus.laddr); - if (cpu->mmu_enable) { - m68030_write_8_mmu(cpu); - } else { - m68030_write_8_mmu(cpu); + if (1) { + write_8_bus(addr, data); } } -static void -m68030_write_16_bus(m68kcpu *cpu) +void +MPU680x0Device::write_16_fc(busaddr addr, uint32 data) { -if(1)cpulog(2, "%s $%08x", __func__, cpu->bus.laddr); - if (cpu->mmu_enable) { - m68030_write_16_mmu(cpu); - } else { - m68030_write_16_mmu(cpu); + if (1) { + // バスアクセスは要整列。 + if (__predict_true((addr & 1) == 0)) { + write_16_bus(addr, data); + } else { + write_8_bus(addr, data >> 8); + addr += 1; + write_8_bus(addr, data & 0xff); + } } } -static void -m68030_write_32_bus(m68kcpu *cpu) +void +MPU680x0Device::write_32_fc(busaddr addr, uint32 data) { -if(1)cpulog(2, "%s $%08x", __func__, cpu->bus.laddr); - if (cpu->mmu_enable) { - m68030_write_32_mmu(cpu); - } else { - m68030_write_32_mmu(cpu); + if (1) { + // バスアクセスは要整列。 + if (__predict_true((addr & 3) == 0)) { + write_32_bus(addr, data); + } else if (__predict_true((addr & 1) == 0)) { + write_16_bus(addr, data >> 16); + addr += 2; + write_16_bus(addr, data & 0xffff); + } else { + write_8_bus(addr, data >> 24); + addr += 1; + write_16_bus(addr, (data >> 8) & 0xffff); + addr += 2; + write_8_bus(addr, data & 0xff); + } } } -// -// CPU 内部からのメモリアクセスは常にこの8つ (またはこれを呼び出すヘルパー -// 関数) を呼ぶこと。 -// uint32 m68030_fetch_{16,32}(cpu) -// uint32 m68030_read_{8,16,32}(cpu, laddr) -// void m68030_write_{8,16,32}(cpu, laddr, data) -// +// 外部バスアクセス (MMU を含む) +// ミスアライン不可。 +// バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。 +// uint32 fetch_{16,32}_bus() +// uint32 read_{8,16,32}_bus(busaddr) +// void write_{8,16,32}_bus(busaddr, data) + +// goto を含むことに注意。gcc 拡張式(?) に注意。 +#define FETCH(size) ({ \ + bus.laddr.Set(addr, fc_inst); \ + bus.paddr = bus.laddr; \ + bus.ci = false; \ + if (__predict_true(mmu_enable)) { \ + if (__predict_false(TranslateFetch() == false)) \ + goto buserr; \ + } \ + busdata bd_ = mainbus->__CONCAT(Read,size)(bus.paddr); \ + if (bd_.IsBusErr()) \ + goto buserr; \ + bd_; /* これが戻り値 */ \ +}) +#define READ(size) ({ \ + bus.laddr = addr; \ + bus.paddr = addr; \ + bus.ci = false; \ + if (__predict_true(mmu_enable)) { \ + if (__predict_false(TranslateRead() == false)) \ + goto buserr; \ + } \ + busdata bd_ = mainbus->__CONCAT(Read,size)(bus.paddr); \ + if (bd_.IsBusErr()) \ + goto buserr; \ + bd_; /* これが戻り値 */ \ +}) +#define WRITE(size, data_) ({ \ + bus.laddr = addr; \ + bus.paddr = addr; \ + bus.ci = false; \ + if (__predict_true(mmu_enable)) { \ + if (__predict_false(TranslateWrite() == false)) \ + goto buserr; \ + } \ + busdata bd_ = mainbus->__CONCAT(Write,size)(bus.paddr, data_); \ + if (bd_.IsBusErr()) \ + goto buserr; \ + bd_; /* これが戻り値 */ \ +}) uint32 -m68030_fetch_16(m68kcpu *cpu) +MPU680x0Device::fetch_16_bus(uint32 addr) { - cpu->bus.ssw = SSW_BUS_R | cpu->bus.fc2 | FC_PROG; - cpu->bus.laddr = RegPC; - return m68030_fetch_16_bus(cpu); -} + busdata bd; -uint32 -m68030_fetch_32(m68kcpu *cpu) -{ - cpu->bus.ssw = SSW_BUS_R | cpu->bus.fc2 | FC_PROG; - cpu->bus.laddr = RegPC; - return m68030_fetch_32_bus(cpu); -} + bd = FETCH(16); + buswait += bd.GetWait(); + return bd.Data(); -uint32 -m68030_read_8(m68kcpu *cpu, uint32 addr) -{ - cpu->bus.ssw = SSW_BUS_R | cpu->bus.fc2 | FC_DATA; - cpu->bus.laddr = addr; - return m68030_read_8_bus(cpu); + buserr: + bus.size = M68K::SSW_SIZE_WORD; + throw M68K::EXCEP_BUSERR; } uint32 -m68030_read_16(m68kcpu *cpu, uint32 addr) +MPU680x0Device::fetch_32_bus(uint32 addr) { - cpu->bus.ssw = SSW_BUS_R | cpu->bus.fc2 | FC_DATA; - cpu->bus.laddr = addr; - return m68030_read_16_bus(cpu); + busdata bd; + + bd = FETCH(32); + buswait += bd.GetWait(); + return bd.Data(); + + buserr: + bus.size = M68K::SSW_SIZE_LONG; + throw M68K::EXCEP_BUSERR; } uint32 -m68030_read_32(m68kcpu *cpu, uint32 addr) +MPU680x0Device::read_8_bus(busaddr addr) { - cpu->bus.ssw = SSW_BUS_R | cpu->bus.fc2 | FC_DATA; - cpu->bus.laddr = addr; - return m68030_read_32_bus(cpu); -} + busdata data; -void -m68030_write_8(m68kcpu *cpu, uint32 addr, uint32 data) -{ - cpu->bus.ssw = SSW_BUS_W | cpu->bus.fc2 | FC_DATA; - cpu->bus.laddr = addr; - cpu->bus.data = data; - m68030_write_8_bus(cpu); -} + data = READ(8); + putlog(2, "read_8 %08x -> %02x", bus.laddr.Addr(), data.Data()); + buswait += data.GetWait(); + return data.Data(); -void -m68030_write_16(m68kcpu *cpu, uint32 addr, uint32 data) -{ - cpu->bus.ssw = SSW_BUS_W | cpu->bus.fc2 | FC_DATA; - cpu->bus.laddr = addr; - cpu->bus.data = data; - m68030_write_16_bus(cpu); + buserr: + bus.size = M68K::SSW_SIZE_BYTE; + throw M68K::EXCEP_BUSERR; } -void -m68030_write_32(m68kcpu *cpu, uint32 addr, uint32 data) +uint32 +MPU680x0Device::read_16_bus(busaddr addr) { - cpu->bus.ssw = SSW_BUS_W | cpu->bus.fc2 | FC_DATA; - cpu->bus.laddr = addr; - cpu->bus.data = data; - m68030_write_32_bus(cpu); -} + busdata data; -// -// MOVES 用の FC 指定版。 -// 通常アクセスが現在の FC 空間に対してだが、 -// こちらは SFC/DFC で指定された FC 空間に対してアクセスする。 -// + data = READ(16); + putlog(2, "read_16 %08x -> %04x", bus.laddr.Addr(), data.Data()); + buswait += data.GetWait(); + return data.Data(); -uint32 -m68030_read_8_fc(m68kcpu *cpu, uint32 addr) -{ - cpu->bus.ssw = SSW_BUS_R | RegSFC; - cpu->bus.laddr = addr; - return m68030_read_8_bus(cpu); + buserr: + bus.size = M68K::SSW_SIZE_WORD; + throw M68K::EXCEP_BUSERR; } uint32 -m68030_read_16_fc(m68kcpu *cpu, uint32 addr) +MPU680x0Device::read_32_bus(busaddr addr) { - cpu->bus.ssw = SSW_BUS_R | RegSFC; - cpu->bus.laddr = addr; - return m68030_read_16_bus(cpu); -} + busdata data; -uint32 -m68030_read_32_fc(m68kcpu *cpu, uint32 addr) -{ - cpu->bus.ssw = SSW_BUS_R | RegSFC; - cpu->bus.laddr = addr; - return m68030_read_32_bus(cpu); + data = READ(32); + putlog(2, "read_32 %08x -> %08x", bus.laddr.Addr(), data.Data()); + buswait += data.GetWait(); + return data.Data(); + + buserr: + bus.size = M68K::SSW_SIZE_LONG; + throw M68K::EXCEP_BUSERR; } void -m68030_write_8_fc(m68kcpu *cpu, uint32 addr, uint32 data) +MPU680x0Device::write_8_bus(busaddr addr, uint32 data) { - cpu->bus.ssw = SSW_BUS_W | RegDFC; - cpu->bus.laddr = addr; - cpu->bus.data = data; - m68030_write_8_bus(cpu); + busdata rd; + + rd = WRITE(8, data); + putlog(2, "write_8 %08x <- %02x", bus.laddr.Addr(), data); + buswait += rd.GetWait(); + return; + + buserr: + bus.size = M68K::SSW_SIZE_BYTE; + throw M68K::EXCEP_BUSERR; } void -m68030_write_16_fc(m68kcpu *cpu, uint32 addr, uint32 data) +MPU680x0Device::write_16_bus(busaddr addr, uint32 data) { - cpu->bus.ssw = SSW_BUS_W | RegDFC; - cpu->bus.laddr = addr; - cpu->bus.data = data; - m68030_write_16_bus(cpu); + busdata rd; + + rd = WRITE(16, data); + putlog(2, "write_16 %08x <- %04x", bus.laddr.Addr(), data); + buswait += rd.GetWait(); + return; + + buserr: + bus.size = M68K::SSW_SIZE_WORD; + throw M68K::EXCEP_BUSERR; } void -m68030_write_32_fc(m68kcpu *cpu, uint32 addr, uint32 data) +MPU680x0Device::write_32_bus(busaddr addr, uint32 data) { - cpu->bus.ssw = SSW_BUS_W | RegDFC; - cpu->bus.laddr = addr; - cpu->bus.data = data; - m68030_write_32_bus(cpu); + busdata rd; + + rd = WRITE(32, data); + putlog(2, "write_32 %08x <- %08x", bus.laddr.Addr(), data); + buswait += rd.GetWait(); + return; + + buserr: + bus.size = M68K::SSW_SIZE_LONG; + throw M68K::EXCEP_BUSERR; }