|
|
nono 1.7.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
//
// スプライトコントローラ
//
#include "sprite.h"
#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)
{
}
// デストラクタ
SpriteDevice::~SpriteDevice()
{
}
// 初期化
bool
SpriteDevice::Init()
{
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;
}
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;
}
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) {
uint 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;
default:
__unreachable();
}
}
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)
{
assert((addr & 1U) == 0);
if (addr >= 0xeb8000) {
*(uint16 *)&mem[addr - 0xeb8000] = data;
return vram_wait;
}
if (addr < 0xeb0400) {
uint n = (addr - 0xeb0000) / 8;
switch (addr % 8) {
case 0:
reg.sprite[n].xpos = data & 0x3ff;
break;
case 2:
reg.sprite[n].ypos = data & 0x3ff;
break;
case 4:
reg.sprite[n].col = data & 0xcfff;
break;
case 6:
reg.sprite[n].prw = data & 0x3;
break;
default:
__unreachable();
}
return reg_wait;
}
if (0xeb0800 <= addr && addr < 0xeb0812) {
switch (addr) {
case 0xeb0800:
reg.bg0x = data & 0x3ff;
break;
case 0xeb0802:
reg.bg0y = data & 0x3ff;
break;
case 0xeb0804:
reg.bg1x = data & 0x3ff;
break;
case 0xeb0806:
reg.bg1y = data & 0x3ff;
break;
case 0xeb0808:
reg.bgctrl = data & 0x23f;
break;
case 0xeb080a:
reg.htotal = data & 0xff;
break;
case 0xeb080c:
reg.hdisp = data & 0x3f;
break;
case 0xeb080e:
reg.vdisp = data & 0xff;
break;
case 0xeb0810:
reg.res = data & 0x1f;
break;
default:
__unreachable();
}
return reg_wait;
}
busdata r = reg_wait; // ?
r.SetBusErr();
return r;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.