File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / sprite.cpp
Revision 1.1.1.14 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:06:01 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
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;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.