--- nono/vm/mainbus.cpp 2026/04/29 17:05:24 1.1.1.3 +++ nono/vm/mainbus.cpp 2026/04/29 17:05:28 1.1.1.4 @@ -18,7 +18,7 @@ // // Access Map o o o x x // HV access o o o o ? -// Peek32 o o o x x +// Peek4 o o o x x // Singleton o o o x x // // もともと FC 付きアクセス機能を Mainbus からX68kIO に伸ばすために @@ -63,7 +63,7 @@ // // コンストラクタ -MainbusBaseDevice::MainbusBaseDevice(int objid_) +MainbusBaseDevice::MainbusBaseDevice(uint objid_) : inherited(objid_) { } @@ -79,44 +79,6 @@ MainbusBaseDevice::ResetByMPU() { } -// 必ず busaddr の方を呼ぶこと。 - -busdata -MainbusBaseDevice::Read8(uint32 addr) -{ - assertmsg(false, "%s should not be called", __FUNCTION__); -} - -busdata -MainbusBaseDevice::Read16(uint32 addr) -{ - assertmsg(false, "%s should not be called", __FUNCTION__); -} - -busdata -MainbusBaseDevice::Read32(uint32 addr) -{ - assertmsg(false, "%s should not be called", __FUNCTION__); -} - -busdata -MainbusBaseDevice::Write8(uint32 addr, uint32 data) -{ - assertmsg(false, "%s should not be called", __FUNCTION__); -} - -busdata -MainbusBaseDevice::Write16(uint32 addr, uint32 data) -{ - assertmsg(false, "%s should not be called", __FUNCTION__); -} - -busdata -MainbusBaseDevice::Write32(uint32 addr, uint32 data) -{ - assertmsg(false, "%s should not be called", __FUNCTION__); -} - // ブートページを切り替える際の共通処理。 // 派生クラスから呼ぶこと。 void @@ -160,9 +122,17 @@ MainbusBaseDevice::FormatDevName(const D // // コンストラクタ -MainbusDevice::MainbusDevice(int objid_) +MainbusDevice::MainbusDevice(uint objid_) : inherited(objid_) { + monitor_accstat.func = + ToMonitorCallback(&MainbusDevice::MonitorUpdateAccStat); + // 表示行数が機種ごとに異なるので継承側でセットしている。 + monitor_accstat.Regist(ID_MONITOR_ACCSTAT); + + // 通常は 32bit 空間全体 (そうでない機種はコンストラクタで上書きする) + accstat_baseaddr = 0; + accstat_bitlen = 32; } // デストラクタ @@ -170,100 +140,213 @@ MainbusDevice::~MainbusDevice() { } +// 初期化 +bool +MainbusDevice::Init() +{ + if (inherited::Init() == false) { + return false; + } + + // アクセス状況の表示用配列。 + accstat_rw.resize(AccStat::MAINLEN >> (32 - accstat_bitlen)); + + return true; +} + +// リセット +void +MainbusDevice::ResetHard(bool poweron) +{ + inherited::ResetHard(poweron); + + std::fill(accstat_read.begin(), accstat_read.end(), 0); + std::fill(accstat_write.begin(), accstat_write.end(), 0); +} + +// ハイパーバイザ的読み込み (ミスアライン可)。 +// addr はアドレスとサイズを指定すること。 +// バスエラーが起きればその時点で BusData::BusErr を返す。 +busdata +MainbusDevice::HVReadN(busaddr addr) +{ + addr |= BusAddr::SRead; + + uint32 reqsize = addr.GetSize(); + busdata data; + do { + busdata bd = Read(addr); + if (__predict_false(bd.IsBusErr())) { + return bd; + } + data |= DYNAMIC_BUS_SIZING_R(addr, bd); + } while (addr.GetSize() != 0); + + data |= busdata::Size(reqsize); + return data; +} + // ハイパーバイザ的読み込み busdata -MainbusDevice::HVRead8(uint32 addr) +MainbusDevice::HVRead1(uint32 paddr) { - busaddr baddr(addr, busaddr::Read | busaddr::S); - return Read8(baddr); + busaddr addr = busaddr(paddr) | BusAddr::Size1; + return HVReadN(addr); } // ハイパーバイザ的読み込み (ミスアライン可) busdata -MainbusDevice::HVRead16(uint32 addr) +MainbusDevice::HVRead2(uint32 paddr) { - busaddr baddr(addr, busaddr::Read | busaddr::S); - if (__predict_true((addr & 1) == 0)) { - return Read16(baddr); - } else { - busdata data; - data = Read8(baddr); - baddr += 1; - data |= Read8(baddr); - return data; - } + busaddr addr = busaddr(paddr) | BusAddr::Size2; + return HVReadN(addr); } // ハイパーバイザ的読み込み (ミスアライン可) busdata -MainbusDevice::HVRead32(uint32 addr) +MainbusDevice::HVRead4(uint32 paddr) { - if (__predict_true((addr & 3) == 0)) { - busaddr baddr(addr, busaddr::Read | busaddr::S); - return Read32(baddr); - } else { - busdata data; - data = HVRead16(addr + 0); - data <<= 16; - data |= HVRead16(addr + 2); - return data; - } + busaddr addr = busaddr(paddr) | BusAddr::Size4; + return HVReadN(addr); +} + +// ハイパーバイザ的書き込み (ミスアライン可)。 +// addr はアドレスとサイズを指定すること。属性は SRead 固定。 +// バスエラーが起きればその時点で busdata::BusErr を返す。 +busdata +MainbusDevice::HVWriteN(busaddr addr, uint32 data) +{ + addr |= BusAddr::SWrite; + do { + busdata r = Write(addr, data); + if (__predict_false(r.IsBusErr())) { + return r; + } + DYNAMIC_BUS_SIZING_W(addr, data, r); + } while (addr.GetSize() != 0); + + return 0; } // ハイパーバイザ的書き込み busdata -MainbusDevice::HVWrite8(uint32 addr, uint32 data) +MainbusDevice::HVWrite1(uint32 paddr, uint32 data) { - busaddr baddr(addr, busaddr::Write | busaddr::S); - return Write8(baddr, data); + busaddr addr = busaddr(paddr) | BusAddr::Size1; + return HVWriteN(addr, data); } // ハイパーバイザ的書き込み (ミスアライン可) busdata -MainbusDevice::HVWrite16(uint32 addr, uint32 data) +MainbusDevice::HVWrite2(uint32 paddr, uint32 data) { - busaddr baddr(addr, busaddr::Write | busaddr::S); - if (__predict_true((addr & 1) == 0)) { - return Write16(baddr, data); - } else { - busdata r; - r = Write8(baddr, data >> 8); - baddr += 1; - r |= Write8(baddr, data & 0xff); - return r; - } + busaddr addr = busaddr(paddr) | BusAddr::Size2; + return HVWriteN(addr, data); } // ハイパーバイザ的書き込み (ミスアライン可) busdata -MainbusDevice::HVWrite32(uint32 addr, uint32 data) +MainbusDevice::HVWrite4(uint32 paddr, uint32 data) { - if (__predict_true((addr & 3) == 0)) { - busaddr baddr(addr, busaddr::Write | busaddr::S); - return Write32(baddr, data); - } else { - busdata r; - r = HVWrite16(addr + 0, data >> 16); - r |= HVWrite16(addr + 2, data & 0xffff); - return r; - } + busaddr addr = busaddr(paddr) | BusAddr::Size4; + return HVWriteN(addr, data); } uint64 -MainbusDevice::Peek32(uint32 addr) +MainbusDevice::Peek4(uint32 addr) { uint64 data; if (__predict_false((addr & 3) != 0)) VMPANIC("unaligned access $%08x", addr); - data = Peek8(addr++) << 24; - data |= Peek8(addr++) << 16; - data |= Peek8(addr++) << 8; - data |= Peek8(addr); + data = Peek1(addr++) << 24; + data |= Peek1(addr++) << 16; + data |= Peek1(addr++) << 8; + data |= Peek1(addr); return data; } +void +MainbusDevice::MonitorUpdateAccStat(Monitor *, TextScreen& screen) +{ + std::array buf; + +#define UPDATE_RW(rw_ptr) do { \ + uint64 dst = *(uint64 *)(rw_ptr); \ + dst <<= 2; \ + dst &= 0xfcfcfcfc'fcfcfcfc; \ + dst |= src; \ + *(uint64 *)(rw_ptr) = dst; \ +} while (0) + + // R|W をマージしながらコピー。 + if (__predict_true(accstat_rw.size() == AccStat::MAINLEN)) { + // 全域。 + for (int i = 0; i < AccStat::MAINLEN; i += 8) { + uint64 src = *(uint64 *)&accstat_read[i] + | *(uint64 *)&accstat_write[i]; + UPDATE_RW(&accstat_rw[i]); + } + } else { + // NEWS なら表示に使うのは前 1/4 のみで、後ろはミラー。 + // ただしアドレス表記は $c000'0000 以降(後ろの 1/4)。 + uint offset = accstat_rw.size(); + uint ndiv = accstat_read.size() / offset; + for (int i = 0, iend = accstat_rw.size(); i < iend; i += 8) { + uint64 src = 0; + for (int j = 0; j < ndiv; j++) { + src |= *(uint64 *)&accstat_read[i + j * offset]; + src |= *(uint64 *)&accstat_write[i + j * offset]; + } + UPDATE_RW(&accstat_rw[i]); + } + } + + // 読んだのでリセット。 + std::fill(accstat_read.begin(), accstat_read.end(), 0); + std::fill(accstat_write.begin(), accstat_write.end(), 0); + + screen.Clear(); + + static_assert(AccStat::SHIFT >= 20, ""); + screen.Print(0, 0, + "Shows %ubit space. %uMB/char. 'R':Read, 'W':Write, 'A':Read+Write", + accstat_bitlen, 1U << (AccStat::SHIFT - 20)); + screen.Print(12, 1, + "+$00 +$01 +$02 +$03 +$04 +$05 +$06 +$07"); + + uint32 baseaddr = accstat_baseaddr; + for (int y = 0, yend = accstat_rw.size() / 64; y < yend; y++) { + const uint8 *a = &accstat_rw[y * 64]; + uint8 avail = accstat_avail[y]; + char *d = &buf[0]; + std::fill(buf.begin(), buf.end() - 1, ' '); + for (int i = 0; i < 8; i++) { + // 先頭に空白を入れといて、参照時は buf+1 から参照する。 + if ((i & 1) == 0) { + d++; + } + if ((int8)avail < 0) { + // 何かしらデバイスがある。16MB、8文字分。 + for (int j = 0; j < 8; j++) { + uint op = *a & 3; + *d++ = ".RWA"[op]; + a++; + } + } else { + // この 16MB には何のデバイスもない。 + d += 8; + a += 8; + } + avail <<= 1; + } + *d = '\0'; + screen.Print(0, y + 2, "$%02x00'0000: %s", + baseaddr + y * 0x08, &buf[1]); + } +} + // // 上位8ビットがテーブルで表せる構造のメインバス。 @@ -276,11 +359,6 @@ Mainbus24Device::Mainbus24Device() monitor.func = ToMonitorCallback(&Mainbus24Device::MonitorUpdate); monitor.SetSize(75, 33); monitor.Regist(ID_MONITOR_MAINBUS); - - monitor_accstat.func = - ToMonitorCallback(&Mainbus24Device::MonitorUpdateAccStat); - // 表示行数が機種ごとに異なるので継承側でセットしている。 - monitor_accstat.Regist(ID_MONITOR_ACCSTAT); } Mainbus24Device::~Mainbus24Device() @@ -292,7 +370,7 @@ Mainbus24Device::~Mainbus24Device() void Mainbus24Device::InitAccStat() { - for (int i = 0; i < accstat_area.size(); i++) { + for (int i = 0; i < accstat_avail.size(); i++) { uint bits = 0; for (int j = 0; j < 8; j++) { int n = i * 8 + j; @@ -302,14 +380,14 @@ Mainbus24Device::InitAccStat() bits |= 1; } } - accstat_area[i] = bits; + accstat_avail[i] = bits; } // デバッグ用 if (0) { - for (int i = 0; i < accstat_area.size(); i++) { + for (int i = 0; i < accstat_avail.size(); i++) { printf("%02x: ", i); - uint8 a = accstat_area[i]; + uint8 a = accstat_avail[i]; for (int j = 0; j < 8; j++) { if ((int8)a < 0) { printf("1"); @@ -323,84 +401,66 @@ Mainbus24Device::InitAccStat() } } -// リセット -void -Mainbus24Device::ResetHard(bool poweron) -{ - inherited::ResetHard(poweron); - - std::fill(accstat_read.begin(), accstat_read.end(), 0); - std::fill(accstat_write.begin(), accstat_write.end(), 0); -} - inline IODevice * Mainbus24Device::Decoder(uint32 addr) const { return devtable[addr >> 24]; } -#define READ(NN) do { \ - uint32 pa = addr.Addr(); \ - accstat_read[pa >> 21] = ACC_READ; \ - IODevice *dev = Decoder(pa); \ - return dev->__CONCAT(Read,NN)(pa); \ -} while (0) - -#define WRITE(NN) do { \ - uint32 pa = addr.Addr(); \ - accstat_write[pa >> 21] = ACC_WRITE; \ - IODevice *dev = Decoder(pa); \ - return dev->__CONCAT(Write,NN)(pa, data); \ -} while (0) - -busdata -Mainbus24Device::Read8(busaddr addr) -{ - READ(8); -} - -busdata -Mainbus24Device::Read16(busaddr addr) -{ - READ(16); -} - busdata -Mainbus24Device::Read32(busaddr addr) +Mainbus24Device::Read(busaddr addr) { - READ(32); + uint32 pa = addr.Addr(); + accstat_read[pa >> AccStat::SHIFT] = AccStat::READ; + IODevice *dev = Decoder(pa); + return dev->Read(addr); } busdata -Mainbus24Device::Write8(busaddr addr, uint32 data) +Mainbus24Device::Write(busaddr addr, uint32 data) { - WRITE(8); + uint32 pa = addr.Addr(); + accstat_write[pa >> AccStat::SHIFT] = AccStat::WRITE; + IODevice *dev = Decoder(pa); + return dev->Write(addr, data); } busdata -Mainbus24Device::Write16(busaddr addr, uint32 data) +Mainbus24Device::ReadBurst16(busaddr addr, uint32 *dst) { - WRITE(16); + uint32 pa = addr.Addr(); + IODevice *dev = Decoder(pa); + busdata r = dev->ReadBurst16(addr, dst); + if (__predict_true(r.IsBusErr() == false)) { + accstat_read[pa >> AccStat::SHIFT] = AccStat::READ; + } + return r; } busdata -Mainbus24Device::Write32(busaddr addr, uint32 data) +Mainbus24Device::WriteBurst16(busaddr addr, const uint32 *src) { - WRITE(32); + uint32 pa = addr.Addr(); + IODevice *dev = Decoder(pa); + busdata r = dev->WriteBurst16(addr, src); + if (__predict_true(r.IsBusErr() == false)) { + accstat_write[pa >> AccStat::SHIFT] = AccStat::WRITE; + } + return r; } busdata -Mainbus24Device::Peek8(uint32 addr) +Mainbus24Device::Peek1(uint32 addr) { IODevice *dev = Decoder(addr); - return dev->Peek8(addr); + return dev->Peek1(addr); } bool -Mainbus24Device::Poke8(uint32 addr, uint32 data) +Mainbus24Device::Poke1(uint32 addr, uint32 data) { IODevice *dev = Decoder(addr); - return dev->Poke8(addr, data); + return dev->Poke1(addr, data); } void @@ -427,76 +487,3 @@ Mainbus24Device::MonitorUpdate(Monitor * } } } - -void -Mainbus24Device::MonitorUpdateAccStat(Monitor *, TextScreen& screen) -{ - std::array buf; - uint32 baseaddr; - - // R|W をマージしながらコピー。 - if (__predict_true(acc.size() == accstat_read.size())) { - // LUNA なら全域。 - for (int i = 0, iend = acc.size(); i < iend; i += 4) { - uint32 tmp = 0; - tmp |= *(uint32 *)&accstat_read[i]; - tmp |= *(uint32 *)&accstat_write[i]; - *(uint32 *)&acc[i] = tmp; - } - baseaddr = 0; - } else { - // NEWS なら表示に使うのは前 1/4 のみで、後ろはミラー。 - // ただしアドレス表記は $c000'0000 以降(後ろの 1/4)。 - int offset = acc.size(); - int ndiv = accstat_read.size() / offset; - for (int i = 0, iend = acc.size(); i < iend; i += 4) { - uint32 tmp = 0; - for (int j = 0; j < ndiv; j++) { - tmp |= *(uint32 *)&accstat_read[i + j * offset]; - tmp |= *(uint32 *)&accstat_write[i + j * offset]; - } - *(uint32 *)&acc[i] = tmp; - } - baseaddr = 0xc0; - } - - // 読んだのでリセット。 - std::fill(accstat_read.begin(), accstat_read.end(), 0); - std::fill(accstat_write.begin(), accstat_write.end(), 0); - - screen.Clear(); - screen.Print(0, 0, - "Shows %dbit space. 2MB/char. 'R':Read, 'W':Write, 'A':Read+Write", - 1 + __builtin_clz((int)(accstat_read.size() / acc.size()))); - screen.Print(12, 1, - "+$00 +$01 +$02 +$03 +$04 +$05 +$06 +$07"); - - for (int y = 0, yend = acc.size() / 64; y < yend; y++) { - const uint8 *a = &acc[y * 64]; - uint8 area = accstat_area[y]; - char *d = &buf[0]; - std::fill(buf.begin(), buf.end() - 1, ' '); - for (int i = 0; i < 8; i++) { - // 先頭に空白を入れといて、参照時は buf+1 から参照する。 - if ((i & 1) == 0) { - d++; - } - if ((int8)area < 0) { - // 何かしらデバイスがある。16MB、8文字分。 - for (int j = 0; j < 8; j++) { - uint op = *a & 3; - *d++ = ".RWA"[op]; - a++; - } - } else { - // この 16MB には何のデバイスもない。 - d += 8; - a += 8; - } - area <<= 1; - } - *d = '\0'; - screen.Print(0, y + 2, "$%02x00'0000: %s", - baseaddr + y * 0x08, &buf[1]); - } -}