--- nono/m680x0/m68030bus.cpp 2026/04/29 17:05:15 1.1.1.4 +++ nono/m680x0/m68030bus.cpp 2026/04/29 17:05:22 1.1.1.5 @@ -4,249 +4,363 @@ // Licensed under nono-license.txt // -// 論理アクセス - #include "mpu680x0.h" -// バスエラー時に SSW をセットする。 -// {fetch,read,write}_NN_mmu() 関数の下請け。 -void -m68kbus::SET_SSW(bool use_mmu, uint size) -{ - // サイズを設定 - ssw &= ~M68K::SSW_SIZE_MASK; - ssw |= size; - - if (use_mmu) { - // データアクセスなら再試行のため DataFault ビットをセット。 - // 命令アクセスなら RB をセット。 - if ((ssw & M68K::FC_DATA)) { - ssw |= M68K::SSW_DF; - } else { - ssw |= M68K::SSW_RB; - } - } -} - -// {fetch,read,write}_NN() と {read,write}_NN_fc() の共通部分。 -// fetch には FC 指定版はないので分ける必要は本来ないけど対称性のため。 -// bus に必要な情報はセットされている。 -// _bus 接尾辞はバスアクセスというより bus 構造体を使ったアクセスという感じ。 +// 現在の FC での通常アクセス (MPU 内部から使用する) +// ミスアライン可。 +// バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。 +// uint32 fetch_{16,32}() +// uint32 read_{8,16,32}(laddr) +// void write_{8,16,32}(laddr, data) -inline uint32 -MPU680x0Device::fetch_16_bus() +// reg.pc からワードをフェッチし reg.pc を進める。 +uint32 +MPU680x0Device::fetch_16() { - if (mmu_enable) { - return fetch_16_mmu(); + uint32 data; + + if (__predict_true(icache_enable)) { + data = fetch_16_cache(reg.pc); } else { - return fetch_16_mmu(); + data = fetch_16_bus(reg.pc); } + reg.pc += 2; + + return data; } -inline uint32 -MPU680x0Device::fetch_32_bus() +// reg.pc からロングワード(ミスアライン可)をフェッチし reg.pc を進める。 +uint32 +MPU680x0Device::fetch_32() { - if (mmu_enable) { - return fetch_32_mmu(); + uint32 data; + + if (__predict_true(icache_enable)) { + data = fetch_32_cache(reg.pc); } else { - return fetch_32_mmu(); + 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); + } } + reg.pc += 4; + + return data; } -inline uint32 -MPU680x0Device::read_8_bus() +uint32 +MPU680x0Device::read_8(uint32 addr) { -if(1)putlog(2, "%s $%08x", __func__, bus.laddr); - if (mmu_enable) { - return read_8_mmu(); - } else { - return read_8_mmu(); - } + busaddr laddr(addr, fc_data | busaddr::R); + return read_8_fc(laddr); } -inline uint32 -MPU680x0Device::read_16_bus() +uint32 +MPU680x0Device::read_16(uint32 addr) { -if(1)putlog(2, "%s $%08x", __func__, bus.laddr); - if (mmu_enable) { - return read_16_mmu(); - } else { - return read_16_mmu(); - } + busaddr laddr(addr, fc_data | busaddr::R); + return read_16_fc(laddr); } -inline uint32 -MPU680x0Device::read_32_bus() +uint32 +MPU680x0Device::read_32(uint32 addr) { -if(1)putlog(2, "%s $%08x", __func__, bus.laddr); - if (mmu_enable) { - return read_32_mmu(); - } else { - return read_32_mmu(); - } + busaddr laddr(addr, fc_data | busaddr::R); + return read_32_fc(laddr); } -inline void -MPU680x0Device::write_8_bus() +void +MPU680x0Device::write_8(uint32 addr, uint32 data) { -if(1)putlog(2, "%s $%08x", __func__, bus.laddr); - if (mmu_enable) { - write_8_mmu(); - } else { - write_8_mmu(); - } + busaddr laddr(addr, fc_data | busaddr::W); + write_8_fc(laddr, data); } -inline void -MPU680x0Device::write_16_bus() +void +MPU680x0Device::write_16(uint32 addr, uint32 data) { -if(1)putlog(2, "%s $%08x", __func__, bus.laddr); - if (mmu_enable) { - write_16_mmu(); - } else { - write_16_mmu(); - } + busaddr laddr(addr, fc_data | busaddr::W); + write_16_fc(laddr, data); } -inline void -MPU680x0Device::write_32_bus() +void +MPU680x0Device::write_32(uint32 addr, uint32 data) { -if(1)putlog(2, "%s $%08x", __func__, bus.laddr); - if (mmu_enable) { - write_32_mmu(); - } else { - write_32_mmu(); - } + busaddr laddr(addr, fc_data | busaddr::W); + write_32_fc(laddr, data); } -// -// CPU 内部からのメモリアクセスは常にこの8つ (またはこれを呼び出すヘルパー -// 関数) を呼ぶこと。 -// uint32 fetch_{16,32}() -// uint32 read_{8,16,32}(laddr) -// void write_{8,16,32}(laddr, data) -// +// FC 指定アクセス (MPU コアから使用する) +// ミスアライン可。 +// バスエラーが起きると例外 M68K::EXCEP_BUSERR をスローする。 +// uint32 read_{8,16,32}_fc(busaddr) +// void write_{8,16,32}_fc(busaddr, data) +// (fetch は常に現在の FC でアクセスするので FC 指定版は不要) uint32 -MPU680x0Device::fetch_16() +MPU680x0Device::read_8_fc(busaddr addr) { - bus.ssw = M68K::SSW_BUS_R | bus.fc2 | M68K::FC_PROG; - bus.laddr = reg.pc; - return fetch_16_bus(); -} + uint32 data; -uint32 -MPU680x0Device::fetch_32() -{ - bus.ssw = M68K::SSW_BUS_R | bus.fc2 | M68K::FC_PROG; - bus.laddr = reg.pc; - return fetch_32_bus(); + if (1) { + data = read_8_bus(addr); + } + + return data; } uint32 -MPU680x0Device::read_8(uint32 addr) +MPU680x0Device::read_16_fc(busaddr addr) { - bus.ssw = M68K::SSW_BUS_R | bus.fc2 | M68K::FC_DATA; - bus.laddr = addr; - return read_8_bus(); + uint32 data; + + 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); + } + } + + return data; } uint32 -MPU680x0Device::read_16(uint32 addr) +MPU680x0Device::read_32_fc(busaddr addr) { - bus.ssw = M68K::SSW_BUS_R | bus.fc2 | M68K::FC_DATA; - bus.laddr = addr; - return read_16_bus(); + uint32 data; + + 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; } -uint32 -MPU680x0Device::read_32(uint32 addr) +void +MPU680x0Device::write_8_fc(busaddr addr, uint32 data) { - bus.ssw = M68K::SSW_BUS_R | bus.fc2 | M68K::FC_DATA; - bus.laddr = addr; - return read_32_bus(); + if (1) { + write_8_bus(addr, data); + } } void -MPU680x0Device::write_8(uint32 addr, uint32 data) +MPU680x0Device::write_16_fc(busaddr addr, uint32 data) { - bus.ssw = M68K::SSW_BUS_W | bus.fc2 | M68K::FC_DATA; - bus.laddr = addr; - bus.data = data; - write_8_bus(); + 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); + } + } } void -MPU680x0Device::write_16(uint32 addr, uint32 data) +MPU680x0Device::write_32_fc(busaddr addr, uint32 data) { - bus.ssw = M68K::SSW_BUS_W | bus.fc2 | M68K::FC_DATA; - bus.laddr = addr; - bus.data = data; - write_16_bus(); + 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); + } + } } -void -MPU680x0Device::write_32(uint32 addr, uint32 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 +MPU680x0Device::fetch_16_bus(uint32 addr) { - bus.ssw = M68K::SSW_BUS_W | bus.fc2 | M68K::FC_DATA; - bus.laddr = addr; - bus.data = data; - write_32_bus(); + busdata bd; + + bd = FETCH(16); + buswait += bd.GetWait(); + return bd.Data(); + + buserr: + bus.size = M68K::SSW_SIZE_WORD; + throw M68K::EXCEP_BUSERR; } -// -// MOVES 用の FC 指定版。 -// 通常アクセスが現在の FC 空間に対してだが、 -// こちらは SFC/DFC で指定された FC 空間に対してアクセスする。 -// +uint32 +MPU680x0Device::fetch_32_bus(uint32 addr) +{ + busdata bd; + + bd = FETCH(32); + buswait += bd.GetWait(); + return bd.Data(); + + buserr: + bus.size = M68K::SSW_SIZE_LONG; + throw M68K::EXCEP_BUSERR; +} uint32 -MPU680x0Device::read_8_fc(uint32 addr) +MPU680x0Device::read_8_bus(busaddr addr) { - bus.ssw = M68K::SSW_BUS_R | reg.sfc; - bus.laddr = addr; - return read_8_bus(); + busdata data; + + data = READ(8); + putlog(2, "read_8 %08x -> %02x", bus.laddr.Addr(), data.Data()); + buswait += data.GetWait(); + return data.Data(); + + buserr: + bus.size = M68K::SSW_SIZE_BYTE; + throw M68K::EXCEP_BUSERR; } uint32 -MPU680x0Device::read_16_fc(uint32 addr) +MPU680x0Device::read_16_bus(busaddr addr) { - bus.ssw = M68K::SSW_BUS_R | reg.sfc; - bus.laddr = addr; - return read_16_bus(); + busdata data; + + data = READ(16); + putlog(2, "read_16 %08x -> %04x", bus.laddr.Addr(), data.Data()); + buswait += data.GetWait(); + return data.Data(); + + buserr: + bus.size = M68K::SSW_SIZE_WORD; + throw M68K::EXCEP_BUSERR; } uint32 -MPU680x0Device::read_32_fc(uint32 addr) +MPU680x0Device::read_32_bus(busaddr addr) { - bus.ssw = M68K::SSW_BUS_R | reg.sfc; - bus.laddr = addr; - return read_32_bus(); + busdata data; + + 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 -MPU680x0Device::write_8_fc(uint32 addr, uint32 data) +MPU680x0Device::write_8_bus(busaddr addr, uint32 data) { - bus.ssw = M68K::SSW_BUS_W | reg.dfc; - bus.laddr = addr; - bus.data = data; - write_8_bus(); + 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 -MPU680x0Device::write_16_fc(uint32 addr, uint32 data) +MPU680x0Device::write_16_bus(busaddr addr, uint32 data) { - bus.ssw = M68K::SSW_BUS_W | reg.dfc; - bus.laddr = addr; - bus.data = data; - write_16_bus(); + 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 -MPU680x0Device::write_32_fc(uint32 addr, uint32 data) +MPU680x0Device::write_32_bus(busaddr addr, uint32 data) { - bus.ssw = M68K::SSW_BUS_W | reg.dfc; - bus.laddr = addr; - bus.data = data; - write_32_bus(); + 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; }