--- nono/vm/sprite.cpp 2026/04/29 17:04:36 1.1.1.3 +++ nono/vm/sprite.cpp 2026/04/29 17:06:01 1.1.1.14 @@ -4,40 +4,110 @@ // Licensed under nono-license.txt // +// +// スプライトコントローラ +// + #include "sprite.h" -#include +#include "event.h" +// InsideOut p.135 +// 書き込みは VRAM とレジスタで異なる。 +// 読み込みは VRAM、レジスタとも 17 ウェイト。 +const busdata vram_wait = busdata::Wait(18 * 40_nsec); +const busdata reg_wait = busdata::Wait(20 * 40_nsec); +const busdata read_wait = busdata::Wait(17 * 40_nsec); + +// コンストラクタ SpriteDevice::SpriteDevice() + : inherited(OBJ_SPRITE) { - logname = "sprite"; - devname = "Sprite"; - devaddr = baseaddr; - devlen = 0x010000; - - mem.reset(new uint8[4 * 8192]); } +// デストラクタ SpriteDevice::~SpriteDevice() { } -uint64 -SpriteDevice::Read8(uint32 addr) +// 初期化 +bool +SpriteDevice::Init() { - if (addr >= 0xeb8000) { - return mem[HB(addr - 0xeb8000)]; + constexpr size_t devlen = 4 * 8192; + mem.reset(new(std::nothrow) uint8[devlen]); + if ((bool)mem == false) { + warnx("Could not allocate %zu bytes at %s", devlen, __method__); + return false; } - PANIC("not impl"); + + return true; +} + +// XXX ResetHard() 未調査 + +busdata +SpriteDevice::Read(busaddr addr) +{ + busdata data; + + 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 { + putlog(2, "$%06x <- $%04x", paddr, data); + } + + busdata r = Set16(paddr2, data); + r |= busdata::Size(datasize); + return r; } -uint64 -SpriteDevice::Read16(uint32 addr) +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::Get16(uint32 addr) const +{ + assert((addr & 1U) == 0); + if (addr >= 0xeb8000) { return *(uint16 *)&mem[addr - 0xeb8000]; } if (addr < 0xeb0400) { - int n = (addr - 0xeb0000) / 8; + uint n = (addr - 0xeb0000) / 8; switch (addr % 8) { case 0: return reg.sprite[n].xpos; @@ -47,54 +117,50 @@ SpriteDevice::Read16(uint32 addr) 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; + default: + __unreachable(); } } - return (uint64)-1; -} - -uint64 -SpriteDevice::Write8(uint32 addr, uint32 data) + 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::Set16(uint32 addr, uint32 data) { - if (addr >= 0xeb8000) { - mem[HB(addr - 0xeb8000)] = data; - return 0; - } - PANIC("not impl"); -} + assert((addr & 1U) == 0); -uint64 -SpriteDevice::Write16(uint32 addr, uint32 data) -{ - putlog(2, "Write16 $%06x <- $%04x", addr, data); if (addr >= 0xeb8000) { *(uint16 *)&mem[addr - 0xeb8000] = data; - return 0; + 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; @@ -108,8 +174,10 @@ SpriteDevice::Write16(uint32 addr, uint3 case 6: reg.sprite[n].prw = data & 0x3; break; + default: + __unreachable(); } - return 0; + return reg_wait; } if (0xeb0800 <= addr && addr < 0xeb0812) { switch (addr) { @@ -140,54 +208,13 @@ SpriteDevice::Write16(uint32 addr, uint3 case 0xeb0810: reg.res = data & 0x1f; break; + default: + __unreachable(); } - return 0; - } - - return (uint64)-1; -} - -uint64 -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 reg_wait; } - return (uint64)-1; + busdata r = reg_wait; // ? + r.SetBusErr(); + return r; }