--- nono/vm/sprite.cpp 2026/04/29 17:05:25 1.1.1.11 +++ nono/vm/sprite.cpp 2026/04/29 17:05:43 1.1.1.13 @@ -9,7 +9,7 @@ // #include "sprite.h" -#include "mpu.h" +#include "event.h" // InsideOut p.135 // 書き込みは VRAM とレジスタで異なる。 @@ -22,7 +22,6 @@ const busdata read_wait = busdata::Wait( SpriteDevice::SpriteDevice() : inherited(OBJ_SPRITE) { - mem.reset(new uint8[4 * 8192]); } // デストラクタ @@ -30,111 +29,138 @@ SpriteDevice::~SpriteDevice() { } +// 初期化 +bool +SpriteDevice::Init() +{ + constexpr uint devlen = 4 * 8192; + mem.reset(new(std::nothrow) uint8[devlen]); + if ((bool)mem == false) { + warnx("Cannot allocate %u bytes at %s", devlen, __method__); + return false; + } + + return true; +} + // XXX ResetHard() 未調査 busdata -SpriteDevice::Read8(uint32 addr) +SpriteDevice::Read(busaddr addr) { busdata data; - if (addr >= 0xeb8000) { - data = mem[HB(addr - 0xeb8000)]; + uint32 paddr2 = addr.Addr() & ~1U; + data = Get16(paddr2); + putlog(3, "$%06x -> $%04x", paddr2, data.Data()); + data |= read_wait; + data |= BusData::Size2; + return data; +} + +busdata +SpriteDevice::Write(busaddr addr, uint32 data) +{ + uint32 paddr = addr.Addr(); + uint32 reqsize = addr.GetSize(); + uint32 datasize = std::min(2 - (paddr & 1U), reqsize); + data >>= (reqsize - datasize) * 8; + + uint32 paddr2 = paddr & ~1U; + if (datasize == 1) { + putlog(2, "$%06x <- $%02x", paddr, data); + uint32 tmp = Get16(paddr2); + if ((paddr & 1U) == 0) { + data = (data << 8) | (tmp & 0xff); + } else { + data = (tmp & 0xff00) | (data & 0xff); + } } else { - VMPANIC("not impl"); + putlog(2, "$%06x <- $%04x", paddr, data); } - data |= read_wait; + busdata r = Set16(paddr2, data); + r |= busdata::Size(datasize); + return r; +} + +busdata +SpriteDevice::Peek1(uint32 addr) +{ + busdata data = Get16(addr & ~1U); + if ((addr & 1U) == 0) { + return data >> 8; + } else { + return data & 0xff; + } return data; } +// 指定のアドレスの16ビット値を返す。 +// addr は偶数アドレスを指定すること。 busdata -SpriteDevice::Read16(uint32 addr) +SpriteDevice::Get16(uint32 addr) const { - busdata data; + assert((addr & 1U) == 0); if (addr >= 0xeb8000) { - data = *(uint16 *)&mem[addr - 0xeb8000]; - - } else if (addr < 0xeb0400) { - int n = (addr - 0xeb0000) / 8; + return *(uint16 *)&mem[addr - 0xeb8000]; + } + if (addr < 0xeb0400) { + uint n = (addr - 0xeb0000) / 8; switch (addr % 8) { case 0: - data = reg.sprite[n].xpos; - break; + return reg.sprite[n].xpos; case 2: - data = reg.sprite[n].ypos; - break; + return reg.sprite[n].ypos; case 4: - data = reg.sprite[n].col; - break; + return reg.sprite[n].col; case 6: - data = reg.sprite[n].prw; - break; - default: - __unreachable(); - } - } else if (0xeb0800 <= addr && addr < 0xeb0812) { - switch (addr) { - case 0xeb0800: - data = reg.bg0x; - break; - case 0xeb0802: - data = reg.bg0y; - break; - case 0xeb0804: - data = reg.bg1x; - break; - case 0xeb0806: - data = reg.bg1y; - break; - case 0xeb0808: - data = reg.bgctrl; - break; - case 0xeb080a: - data = reg.htotal; - break; - case 0xeb080c: - data = reg.hdisp; - break; - case 0xeb080e: - data = reg.vdisp; - break; - case 0xeb0810: - data = reg.res; - break; + return reg.sprite[n].prw; default: __unreachable(); } - } else { - data.SetBusErr(); } - data |= read_wait; - return data; -} - -busdata -SpriteDevice::Write8(uint32 addr, uint32 data) -{ - if (addr >= 0xeb8000) { - mem[HB(addr - 0xeb8000)] = data; - return vram_wait; - } else { - VMPANIC("not impl"); - return reg_wait; + switch (addr) { + case 0xeb0800: + return reg.bg0x; + case 0xeb0802: + return reg.bg0y; + case 0xeb0804: + return reg.bg1x; + case 0xeb0806: + return reg.bg1y; + case 0xeb0808: + return reg.bgctrl; + case 0xeb080a: + return reg.htotal; + case 0xeb080c: + return reg.hdisp; + case 0xeb080e: + return reg.vdisp; + case 0xeb0810: + return reg.res; + default: + break; } + + return BusData::BusErr; } +// addr は偶数アドレスを指定すること。 +// ウェイト値もしくは BusData::BusErr を返す。 busdata -SpriteDevice::Write16(uint32 addr, uint32 data) +SpriteDevice::Set16(uint32 addr, uint32 data) { - putlog(2, "$%06x <- $%04x", addr, data); + assert((addr & 1U) == 0); + if (addr >= 0xeb8000) { *(uint16 *)&mem[addr - 0xeb8000] = data; return vram_wait; } if (addr < 0xeb0400) { - int n = (addr - 0xeb0000) / 8; + uint n = (addr - 0xeb0000) / 8; switch (addr % 8) { case 0: reg.sprite[n].xpos = data & 0x3ff; @@ -148,6 +174,8 @@ SpriteDevice::Write16(uint32 addr, uint3 case 6: reg.sprite[n].prw = data & 0x3; break; + default: + __unreachable(); } return reg_wait; } @@ -180,6 +208,8 @@ SpriteDevice::Write16(uint32 addr, uint3 case 0xeb0810: reg.res = data & 0x1f; break; + default: + __unreachable(); } return reg_wait; } @@ -188,48 +218,3 @@ SpriteDevice::Write16(uint32 addr, uint3 r.SetBusErr(); return r; } - -busdata -SpriteDevice::Peek8(uint32 addr) -{ - if (addr >= 0xeb8000) { - return mem[HB(addr - 0xeb8000)]; - } - if (addr < 0xeb0400) { - int n = (addr - 0xeb0000) / 8; - switch (addr % 8) { - case 0: - return reg.sprite[n].xpos; - case 2: - return reg.sprite[n].ypos; - case 4: - return reg.sprite[n].col; - case 6: - return reg.sprite[n].prw; - } - } - if (0xeb0800 <= addr && addr < 0xeb0812) { - switch (addr) { - case 0xeb0800: - return reg.bg0x; - case 0xeb0802: - return reg.bg0y; - case 0xeb0804: - return reg.bg1x; - case 0xeb0806: - return reg.bg1y; - case 0xeb0808: - return reg.bgctrl; - case 0xeb080a: - return reg.htotal; - case 0xeb080c: - return reg.hdisp; - case 0xeb080e: - return reg.vdisp; - case 0xeb0810: - return reg.res; - } - } - - return busdata::BusErr; -}