--- nono/m680x0/m68030bus.h 2026/04/29 17:04:34 1.1.1.2 +++ nono/m680x0/m68030bus.h 2026/04/29 17:05:15 1.1.1.3 @@ -6,52 +6,236 @@ #pragma once -#include "bus.h" +// +// 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回分のミスアラインドありのアクセスを担当。 +// -// 基本アクセス -extern uint32 m68030_fetch_8(m68kcpu *cpu); -extern uint32 m68030_fetch_16(m68kcpu *cpu); -extern uint32 m68030_fetch_32(m68kcpu *cpu); -extern uint32 m68030_read_8(m68kcpu *cpu, uint32 addr); -extern uint32 m68030_read_16(m68kcpu *cpu, uint32 addr); -extern uint32 m68030_read_32(m68kcpu *cpu, uint32 addr); -extern void m68030_write_8(m68kcpu *cpu, uint32 addr, uint32 data); -extern void m68030_write_16(m68kcpu *cpu, uint32 addr, uint32 data); -extern void m68030_write_32(m68kcpu *cpu, uint32 addr, uint32 data); -// FC 指定 -extern uint32 m68030_read_8_fc(m68kcpu *cpu, uint32 addr); -extern uint32 m68030_read_16_fc(m68kcpu *cpu, uint32 addr); -extern uint32 m68030_read_32_fc(m68kcpu *cpu, uint32 addr); -extern void m68030_write_8_fc(m68kcpu *cpu, uint32 addr, uint32 data); -extern void m68030_write_16_fc(m68kcpu *cpu, uint32 addr, uint32 data); -extern void m68030_write_32_fc(m68kcpu *cpu, uint32 addr, uint32 data); - -// 基本アクセスルーチンを使った便利サブルーチン -static inline void -m68030_push_16(m68kcpu *cpu, uint32 data) -{ - RegA(7) -= 2; - m68030_write_16(cpu, RegA(7), data); -} -static inline void -m68030_push_32(m68kcpu *cpu, uint32 data) -{ - RegA(7) -= 4; - m68030_write_32(cpu, RegA(7), data); +template 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; } -static inline uint32 -m68030_pop_16(m68kcpu *cpu) +template uint32 +fetch_32_mmu() { - uint32 data = m68030_read_16(cpu, RegA(7)); - RegA(7) += 2; + 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; } -static inline uint32 -m68030_pop_32(m68kcpu *cpu) +template uint32 +read_8_mmu() { - uint32 data = m68030_read_32(cpu, RegA(7)); - RegA(7) += 4; + 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 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 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 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 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 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; }