Update to bsnes v059 release.

**Known issues:**
- button menus do not show up with Windows Vista/7 theme
- snesreader's multi-file archive dialog box doesn't redraw itself on
Windows when you choose different games

Windows Qt is buggy as always. Nothing we can do but keep waiting. I'm
also going to hold off on including pixel shaders until Direct3D PS
support is in. It's just going to annoy the 98% of users who can't use
them if I include them now. Yes, Windows OpenGL support is that bad.

Anyway, from v058 wip10, the following changes were made:
- cheat code editor grays out the slot#s when they are empty. I can't
put "Empty" in the text boxes for various reasons.
- added "Clear Selected" button and multi-selection support to cheat
editor. This is meant to quickly erase all slots.
- settings and tools windows start at 600x360 when bsnes.cfg is not
found / empty
- fixed the emulationSpeed section to start with input. instead of
config.
- open-folder concept requires the folders to end in .sfc to work now,
once again doesn't care what the ROM inside is named
(this is meant to mimic OS X .app folders)
- 21fx API extended to map to $2200, $2201 for now; mostly as a test
for A-bus access (21fx->VRAM DMA, etc)
(old $21fx registers remain for now)

I intend to release this on Saturday as-is even if a few small bugs
are reported. But if there's something major we can make another RC
build.
This commit is contained in:
byuu 2010-01-07 13:07:56 +00:00
parent 6ec765f2c4
commit 97a3a28d86
184 changed files with 4569 additions and 2378 deletions

View File

@ -26,7 +26,7 @@ ifeq ($(platform),x)
link += -s
ruby := video.glx video.xv video.qtraster video.sdl
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.ao
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao
ruby += input.sdl input.x
link += $(if $(findstring audio.openal,$(ruby)),-lopenal)

View File

@ -1,4 +1,4 @@
static const char bsnesVersion[] = "0.058";
static const char bsnesVersion[] = "0.059";
static const char bsnesTitle[] = "bsnes";
static const unsigned bsnesSerializerVersion = 4;
@ -15,6 +15,7 @@ static const unsigned bsnesSerializerVersion = 4;
#include <libco/libco.h>
#include <nall/algorithm.hpp>
#include <nall/any.hpp>
#include <nall/array.hpp>
#include <nall/bit.hpp>
#include <nall/detect.hpp>

View File

@ -7,6 +7,7 @@ namespace SNES {
#include "header.cpp"
#include "gameboyheader.cpp"
#include "serialization.cpp"
namespace memory {
MappedRAM cartrom, cartram, cartrtc;
@ -19,31 +20,28 @@ namespace memory {
Cartridge cartridge;
void Cartridge::load(Mode cartridge_mode) {
cartinfo_t cartinfo;
read_header(cartinfo, memory::cartrom.data(), memory::cartrom.size());
set_cartinfo(cartinfo);
mode = cartridge_mode;
read_header(memory::cartrom.data(), memory::cartrom.size());
set(mode, cartridge_mode);
if(cartinfo.ram_size > 0) {
memory::cartram.map(allocate<uint8_t>(cartinfo.ram_size, 0xff), cartinfo.ram_size);
if(ram_size > 0) {
memory::cartram.map(allocate<uint8_t>(ram_size, 0xff), ram_size);
}
if(cartinfo.srtc || cartinfo.spc7110rtc) {
if(has_srtc || has_spc7110rtc) {
memory::cartrtc.map(allocate<uint8_t>(20, 0xff), 20);
}
if(mode() == ModeBsx) {
if(mode == ModeBsx) {
memory::bsxram.map (allocate<uint8_t>( 32 * 1024, 0xff), 32 * 1024);
memory::bsxpram.map(allocate<uint8_t>(512 * 1024, 0xff), 512 * 1024);
}
if(mode() == ModeSufamiTurbo) {
if(mode == ModeSufamiTurbo) {
if(memory::stArom.data()) memory::stAram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
if(memory::stBrom.data()) memory::stBram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
}
if(mode() == ModeSuperGameBoy) {
if(mode == ModeSuperGameBoy) {
if(memory::gbrom.data()) {
unsigned ram_size = gameboy_ram_size();
unsigned rtc_size = gameboy_rtc_size();
@ -77,10 +75,10 @@ void Cartridge::load(Mode cartridge_mode) {
for(unsigned n = 0; n < memory::stBrom.size(); n++) checksum = crc32_adjust(checksum, memory::stBrom[n]);
if(memory::gbrom.size() != 0 && memory::gbrom.size() != ~0)
for(unsigned n = 0; n < memory::gbrom.size(); n++) checksum = crc32_adjust(checksum, memory::gbrom[n]);
set(crc32, ~checksum);
crc32 = ~checksum;
#if 0
fprintf(stdout, "crc32 = %.8x\n", crc32());
fprintf(stdout, "crc32 = %.8x\n", (unsigned)crc32);
sha256_ctx sha;
uint8_t shahash[32];
@ -96,7 +94,7 @@ void Cartridge::load(Mode cartridge_mode) {
bus.load_cart();
system.serialize_init();
set(loaded, true);
loaded = true;
}
void Cartridge::unload() {
@ -114,55 +112,17 @@ void Cartridge::unload() {
memory::gbram.reset();
memory::gbrtc.reset();
if(loaded() == false) return;
if(loaded == false) return;
bus.unload_cart();
set(loaded, false);
loaded = false;
}
Cartridge::Type Cartridge::detect_image_type(uint8_t *data, unsigned size) const {
cartinfo_t info;
read_header(info, data, size);
return info.type;
}
bool Cartridge::has_21fx() const { return s21fx.exists(); }
void Cartridge::serialize(serializer &s) {
if(memory::cartram.size() != 0 && memory::cartram.size() != ~0) {
s.array(memory::cartram.data(), memory::cartram.size());
}
if(memory::cartrtc.size() != 0 && memory::cartrtc.size() != ~0) {
s.array(memory::cartrtc.data(), memory::cartrtc.size());
}
if(memory::bsxram.size() != 0 && memory::bsxram.size() != ~0) {
s.array(memory::bsxram.data(), memory::bsxram.size());
}
if(memory::bsxpram.size() != 0 && memory::bsxpram.size() != ~0) {
s.array(memory::bsxpram.data(), memory::bsxpram.size());
}
if(memory::stAram.size() != 0 && memory::stAram.size() != ~0) {
s.array(memory::stAram.data(), memory::stAram.size());
}
if(memory::stBram.size() != 0 && memory::stBram.size() != ~0) {
s.array(memory::stBram.data(), memory::stBram.size());
}
if(memory::gbram.size() != 0 && memory::gbram.size() != ~0) {
s.array(memory::gbram.data(), memory::gbram.size());
}
if(memory::gbrtc.size() != 0 && memory::gbrtc.size() != ~0) {
s.array(memory::gbrtc.data(), memory::gbrtc.size());
}
bool Cartridge::has_21fx() const {
return s21fx.exists();
}
Cartridge::Cartridge() {
set(loaded, false);
loaded = false;
unload();
}
@ -170,62 +130,4 @@ Cartridge::~Cartridge() {
unload();
}
void Cartridge::set_cartinfo(const Cartridge::cartinfo_t &source) {
set(region, source.region);
set(mapper, source.mapper);
set(dsp1_mapper, source.dsp1_mapper);
set(has_bsx_slot, source.bsx_slot);
set(has_superfx, source.superfx);
set(has_sa1, source.sa1);
set(has_srtc, source.srtc);
set(has_sdd1, source.sdd1);
set(has_spc7110, source.spc7110);
set(has_spc7110rtc, source.spc7110rtc);
set(has_cx4, source.cx4);
set(has_dsp1, source.dsp1);
set(has_dsp2, source.dsp2);
set(has_dsp3, source.dsp3);
set(has_dsp4, source.dsp4);
set(has_obc1, source.obc1);
set(has_st010, source.st010);
set(has_st011, source.st011);
set(has_st018, source.st018);
}
//==========
//cartinfo_t
//==========
void Cartridge::cartinfo_t::reset() {
type = TypeUnknown;
mapper = LoROM;
dsp1_mapper = DSP1Unmapped;
region = NTSC;
rom_size = 0;
ram_size = 0;
bsx_slot = false;
superfx = false;
sa1 = false;
srtc = false;
sdd1 = false;
spc7110 = false;
spc7110rtc = false;
cx4 = false;
dsp1 = false;
dsp2 = false;
dsp3 = false;
dsp4 = false;
obc1 = false;
st010 = false;
st011 = false;
st018 = false;
}
Cartridge::cartinfo_t::cartinfo_t() {
reset();
}
}

View File

@ -1,4 +1,4 @@
class Cartridge : public property {
class Cartridge : property<Cartridge> {
public:
enum Mode {
ModeNormal,
@ -15,7 +15,8 @@ public:
TypeBsx,
TypeSufamiTurboBios,
TypeSufamiTurbo,
TypeSuperGameBoyBios,
TypeSuperGameBoy1Bios,
TypeSuperGameBoy2Bios,
TypeGameBoy,
TypeUnknown,
};
@ -46,61 +47,41 @@ public:
DSP1HiROM,
};
//properties can be read via operator(), eg "if(cartridge.loaded() == true)";
//warning: if loaded() == false, no other property is considered valid!
readonly<bool> loaded; //is a base cartridge inserted?
readonly<unsigned> crc32; //crc32 of all cartridges (base+slot(s))
property_t<bool> loaded; //is a base cartridge inserted?
property_t<unsigned> crc32; //crc32 of all files sans headers
readonly<Mode> mode;
readonly<Type> type;
readonly<Region> region;
readonly<MemoryMapper> mapper;
readonly<DSP1MemoryMapper> dsp1_mapper;
property_t<Mode> mode;
property_t<Region> region;
property_t<MemoryMapper> mapper;
property_t<DSP1MemoryMapper> dsp1_mapper;
property_t<bool> has_bsx_slot;
property_t<bool> has_superfx;
property_t<bool> has_sa1;
property_t<bool> has_srtc;
property_t<bool> has_sdd1;
property_t<bool> has_spc7110, has_spc7110rtc;
property_t<bool> has_cx4;
property_t<bool> has_dsp1, has_dsp2, has_dsp3, has_dsp4;
property_t<bool> has_obc1;
property_t<bool> has_st010, has_st011, has_st018;
readonly<bool> has_bsx_slot;
readonly<bool> has_superfx;
readonly<bool> has_sa1;
readonly<bool> has_srtc;
readonly<bool> has_sdd1;
readonly<bool> has_spc7110;
readonly<bool> has_spc7110rtc;
readonly<bool> has_cx4;
readonly<bool> has_dsp1;
readonly<bool> has_dsp2;
readonly<bool> has_dsp3;
readonly<bool> has_dsp4;
readonly<bool> has_obc1;
readonly<bool> has_st010;
readonly<bool> has_st011;
readonly<bool> has_st018;
bool has_21fx() const;
//main interface
void load(Mode);
void unload();
Type detect_image_type(uint8_t *data, unsigned size) const;
void serialize(serializer&);
Cartridge();
~Cartridge();
private:
struct cartinfo_t {
Type type;
Region region;
MemoryMapper mapper;
DSP1MemoryMapper dsp1_mapper;
unsigned rom_size, ram_size;
bool bsx_slot;
bool superfx;
bool sa1;
bool srtc;
bool sdd1;
bool spc7110, spc7110rtc;
bool cx4;
bool dsp1, dsp2, dsp3, dsp4;
bool obc1;
bool st010, st011, st018;
void reset();
cartinfo_t();
};
enum HeaderField {
CartName = 0x00,
Mapper = 0x15,
@ -115,10 +96,10 @@ private:
ResetVector = 0x3c,
};
void read_header(cartinfo_t &info, const uint8_t *data, unsigned size) const;
unsigned ram_size;
void read_header(const uint8_t *data, unsigned size);
unsigned find_header(const uint8_t *data, unsigned size) const;
unsigned score_header(const uint8_t *data, unsigned size, unsigned addr) const;
void set_cartinfo(const cartinfo_t&);
unsigned gameboy_ram_size() const;
unsigned gameboy_rtc_size() const;

View File

@ -1,7 +1,28 @@
#ifdef CARTRIDGE_CPP
void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size) const {
info.reset();
void Cartridge::read_header(const uint8_t *data, unsigned size) {
type = TypeUnknown;
mapper = LoROM;
dsp1_mapper = DSP1Unmapped;
region = NTSC;
ram_size = 0;
has_bsx_slot = false;
has_superfx = false;
has_sa1 = false;
has_srtc = false;
has_sdd1 = false;
has_spc7110 = false;
has_spc7110rtc = false;
has_cx4 = false;
has_dsp1 = false;
has_dsp2 = false;
has_dsp3 = false;
has_dsp4 = false;
has_obc1 = false;
has_st010 = false;
has_st011 = false;
has_st018 = false;
//=====================
//detect Game Boy carts
@ -10,23 +31,23 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size
if(size >= 0x0140) {
if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66
&& data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) {
info.type = TypeGameBoy;
type = TypeGameBoy;
return;
}
}
const unsigned index = find_header(data, size);
const uint8 mapper = data[index + Mapper];
const uint8 mapperid = data[index + Mapper];
const uint8 rom_type = data[index + RomType];
const uint8 rom_size = data[index + RomSize];
const uint8 company = data[index + Company];
const uint8 region = data[index + CartRegion] & 0x7f;
const uint8 regionid = data[index + CartRegion] & 0x7f;
info.ram_size = 1024 << (data[index + RamSize] & 7);
if(info.ram_size == 1024) info.ram_size = 0; //no RAM present, eg RamSize == 0
ram_size = 1024 << (data[index + RamSize] & 7);
if(ram_size == 1024) ram_size = 0; //no RAM present
//0, 1, 13 = NTSC; 2 - 12 = PAL
info.region = (region <= 1 || region >= 13) ? NTSC : PAL;
region = (regionid <= 1 || regionid >= 13) ? NTSC : PAL;
//=======================
//detect BS-X flash carts
@ -37,9 +58,9 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size
const uint8_t n15 = data[index + 0x15];
if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) {
info.type = TypeBsx;
info.mapper = BSXROM;
info.region = NTSC; //BS-X only released in Japan
type = TypeBsx;
mapper = BSXROM;
region = NTSC; //BS-X only released in Japan
return;
}
}
@ -52,21 +73,26 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size
if(!memcmp(data, "BANDAI SFC-ADX", 14)) {
if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) {
info.type = TypeSufamiTurboBios;
type = TypeSufamiTurboBios;
} else {
info.type = TypeSufamiTurbo;
type = TypeSufamiTurbo;
}
info.mapper = STROM;
info.region = NTSC; //Sufami Turbo only released in Japan
return; //RAM size handled internally by load_cart_st();
mapper = STROM;
region = NTSC; //Sufami Turbo only released in Japan
return; //RAM size handled outside this routine
}
//==========================
//detect Super Game Boy BIOS
//==========================
if(!memcmp(data + index, "Super GAMEBOY2", 14)) {
type = TypeSuperGameBoy2Bios;
return;
}
if(!memcmp(data + index, "Super GAMEBOY", 13)) {
info.type = TypeSuperGameBoyBios;
type = TypeSuperGameBoy1Bios;
return;
}
@ -80,118 +106,119 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size
uint8 n13 = data[index - 13];
if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) {
info.bsx_slot = true;
has_bsx_slot = true;
}
}
}
}
if(info.bsx_slot == true) {
if(has_bsx_slot) {
if(!memcmp(data + index, "Satellaview BS-X ", 21)) {
//BS-X base cart
info.type = TypeBsxBios;
info.mapper = BSXROM;
info.region = NTSC; //BS-X only released in Japan
return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
type = TypeBsxBios;
mapper = BSXROM;
region = NTSC; //BS-X only released in Japan
return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
} else {
info.type = TypeBsxSlotted;
info.mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
type = TypeBsxSlotted;
mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
region = NTSC; //BS-X slotted cartridges only released in Japan
}
} else {
//standard cart
info.type = TypeNormal;
type = TypeNormal;
if(index == 0x7fc0 && size >= 0x401000) {
info.mapper = ExLoROM;
} else if(index == 0x7fc0 && mapper == 0x32) {
info.mapper = ExLoROM;
mapper = ExLoROM;
} else if(index == 0x7fc0 && mapperid == 0x32) {
mapper = ExLoROM;
} else if(index == 0x7fc0) {
info.mapper = LoROM;
mapper = LoROM;
} else if(index == 0xffc0) {
info.mapper = HiROM;
mapper = HiROM;
} else { //index == 0x40ffc0
info.mapper = ExHiROM;
mapper = ExHiROM;
}
}
if(mapper == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
info.superfx = true;
info.mapper = SuperFXROM;
info.ram_size = 1024 << (data[index - 3] & 7);
if(info.ram_size == 1024) info.ram_size = 0;
if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
has_superfx = true;
mapper = SuperFXROM;
ram_size = 1024 << (data[index - 3] & 7);
if(ram_size == 1024) ram_size = 0;
}
if(mapper == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) {
info.sa1 = true;
info.mapper = SA1ROM;
if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) {
has_sa1 = true;
mapper = SA1ROM;
}
if(mapper == 0x35 && rom_type == 0x55) {
info.srtc = true;
if(mapperid == 0x35 && rom_type == 0x55) {
has_srtc = true;
}
if(mapper == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
info.sdd1 = true;
if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
has_sdd1 = true;
}
if(mapper == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
info.spc7110 = true;
info.spc7110rtc = (rom_type == 0xf9);
info.mapper = SPC7110ROM;
if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
has_spc7110 = true;
has_spc7110rtc = (rom_type == 0xf9);
mapper = SPC7110ROM;
}
if(mapper == 0x20 && rom_type == 0xf3) {
info.cx4 = true;
if(mapperid == 0x20 && rom_type == 0xf3) {
has_cx4 = true;
}
if((mapper == 0x20 || mapper == 0x21) && rom_type == 0x03) {
info.dsp1 = true;
if((mapperid == 0x20 || mapperid == 0x21) && rom_type == 0x03) {
has_dsp1 = true;
}
if(mapper == 0x30 && rom_type == 0x05 && company != 0xb2) {
info.dsp1 = true;
if(mapperid == 0x30 && rom_type == 0x05 && company != 0xb2) {
has_dsp1 = true;
}
if(mapper == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
info.dsp1 = true;
if(mapperid == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
has_dsp1 = true;
}
if(info.dsp1 == true) {
if((mapper & 0x2f) == 0x20 && size <= 0x100000) {
info.dsp1_mapper = DSP1LoROM1MB;
} else if((mapper & 0x2f) == 0x20) {
info.dsp1_mapper = DSP1LoROM2MB;
} else if((mapper & 0x2f) == 0x21) {
info.dsp1_mapper = DSP1HiROM;
if(has_dsp1 == true) {
if((mapperid & 0x2f) == 0x20 && size <= 0x100000) {
dsp1_mapper = DSP1LoROM1MB;
} else if((mapperid & 0x2f) == 0x20) {
dsp1_mapper = DSP1LoROM2MB;
} else if((mapperid & 0x2f) == 0x21) {
dsp1_mapper = DSP1HiROM;
}
}
if(mapper == 0x20 && rom_type == 0x05) {
info.dsp2 = true;
if(mapperid == 0x20 && rom_type == 0x05) {
has_dsp2 = true;
}
if(mapper == 0x30 && rom_type == 0x05 && company == 0xb2) {
info.dsp3 = true;
if(mapperid == 0x30 && rom_type == 0x05 && company == 0xb2) {
has_dsp3 = true;
}
if(mapper == 0x30 && rom_type == 0x03) {
info.dsp4 = true;
if(mapperid == 0x30 && rom_type == 0x03) {
has_dsp4 = true;
}
if(mapper == 0x30 && rom_type == 0x25) {
info.obc1 = true;
if(mapperid == 0x30 && rom_type == 0x25) {
has_obc1 = true;
}
if(mapper == 0x30 && rom_type == 0xf6 && rom_size >= 10) {
info.st010 = true;
if(mapperid == 0x30 && rom_type == 0xf6 && rom_size >= 10) {
has_st010 = true;
}
if(mapper == 0x30 && rom_type == 0xf6 && rom_size < 10) {
info.st011 = true;
if(mapperid == 0x30 && rom_type == 0xf6 && rom_size < 10) {
has_st011 = true;
}
if(mapper == 0x30 && rom_type == 0xf5) {
info.st018 = true;
if(mapperid == 0x30 && rom_type == 0xf5) {
has_st018 = true;
}
}

View File

@ -0,0 +1,37 @@
#ifdef CARTRIDGE_CPP
void Cartridge::serialize(serializer &s) {
if(memory::cartram.size() != 0 && memory::cartram.size() != ~0) {
s.array(memory::cartram.data(), memory::cartram.size());
}
if(memory::cartrtc.size() != 0 && memory::cartrtc.size() != ~0) {
s.array(memory::cartrtc.data(), memory::cartrtc.size());
}
if(memory::bsxram.size() != 0 && memory::bsxram.size() != ~0) {
s.array(memory::bsxram.data(), memory::bsxram.size());
}
if(memory::bsxpram.size() != 0 && memory::bsxpram.size() != ~0) {
s.array(memory::bsxpram.data(), memory::bsxpram.size());
}
if(memory::stAram.size() != 0 && memory::stAram.size() != ~0) {
s.array(memory::stAram.data(), memory::stAram.size());
}
if(memory::stBram.size() != 0 && memory::stBram.size() != ~0) {
s.array(memory::stBram.data(), memory::stBram.size());
}
if(memory::gbram.size() != 0 && memory::gbram.size() != ~0) {
s.array(memory::gbram.data(), memory::gbram.size());
}
if(memory::gbrtc.size() != 0 && memory::gbrtc.size() != ~0) {
s.array(memory::gbrtc.data(), memory::gbrtc.size());
}
}
#endif

View File

@ -1,3 +1,2 @@
unsigned Cheat::count() const { return code.size(); }
bool Cheat::active() const { return cheat_enabled; }
bool Cheat::exists(unsigned addr) const { return mask[addr >> 3] & 1 << (addr & 7); }
bool Cheat::exists(unsigned addr) const { return bitmask[addr >> 3] & 1 << (addr & 7); }

View File

@ -5,230 +5,73 @@ namespace SNES {
Cheat cheat;
Cheat::cheat_t& Cheat::cheat_t::operator=(const Cheat::cheat_t& source) {
enabled = source.enabled;
code = source.code;
desc = source.desc;
count = source.count;
addr.reset();
data.reset();
for(unsigned n = 0; n < count; n++) {
addr[n] = source.addr[n];
data[n] = source.data[n];
}
return *this;
bool Cheat::enabled() const {
return system_enabled;
}
//used to sort cheat code list by description
bool Cheat::cheat_t::operator<(const Cheat::cheat_t& source) {
return strcmp(desc, source.desc) < 0;
void Cheat::enable(bool state) {
system_enabled = state;
cheat_enabled = system_enabled && code_enabled;
}
//parse item ("0123-4567+89AB-CDEF"), return cheat_t item
//return true if code is valid, false otherwise
bool Cheat::decode(const char *s, Cheat::cheat_t &item) const {
item.enabled = false;
item.count = 0;
void Cheat::synchronize() {
memset(bitmask, 0x00, sizeof bitmask);
code_enabled = false;
string code = s;
code.replace(" ", "");
for(unsigned i = 0; i < size(); i++) {
const CheatCode &code = operator[](i);
if(code.enabled == false) continue;
lstring list;
list.split("+", code);
for(unsigned n = 0; n < code.addr.size(); n++) {
code_enabled = true;
for(unsigned n = 0; n < list.size(); n++) {
unsigned addr;
uint8_t data;
type_t type;
if(decode(list[n], addr, data, type) == false) {
item.count = 0;
return false;
unsigned addr = mirror(code.addr[n]);
bitmask[addr >> 3] |= 1 << (addr & 7);
if((addr & 0xffe000) == 0x7e0000) {
//mirror $7e:0000-1fff to $00-3f|80-bf:0000-1fff
unsigned mirroraddr;
for(unsigned x = 0; x <= 0x3f; x++) {
mirroraddr = ((0x00 + x) << 16) + (addr & 0x1fff);
bitmask[mirroraddr >> 3] |= 1 << (mirroraddr & 7);
mirroraddr = ((0x80 + x) << 16) + (addr & 0x1fff);
bitmask[mirroraddr >> 3] |= 1 << (mirroraddr & 7);
}
}
}
item.addr[item.count] = addr;
item.data[item.count] = data;
item.count++;
}
return true;
cheat_enabled = system_enabled && code_enabled;
}
//read() is used by MemBus::read() if Cheat::enabled(addr) returns true to look up cheat code.
//returns true if cheat code was found, false if it was not.
//when true, cheat code substitution value is stored in data.
bool Cheat::read(unsigned addr, uint8_t &data) const {
addr = mirror_address(addr);
for(unsigned i = 0; i < code.size(); i++) {
if(enabled(i) == false) continue;
bool Cheat::read(unsigned addr, uint8 &data) const {
addr = mirror(addr);
for(unsigned n = 0; n < code[i].count; n++) {
if(addr == mirror_address(code[i].addr[n])) {
data = code[i].data[n];
for(unsigned i = 0; i < size(); i++) {
const CheatCode &code = operator[](i);
if(code.enabled == false) continue;
for(unsigned n = 0; n < code.addr.size(); n++) {
if(addr == mirror(code.addr[n])) {
data = code.data[n];
return true;
}
}
}
//code not found, or code is disabled
return false;
}
//==============
//master control
//==============
//global cheat system enable/disable:
//if disabled, *all* cheat codes are disabled;
//otherwise only individually disabled codes are.
bool Cheat::enabled() const {
return cheat_system_enabled;
Cheat::Cheat() {
system_enabled = true;
synchronize();
}
void Cheat::enable() {
cheat_system_enabled = true;
cheat_enabled = (cheat_system_enabled && cheat_enabled_code_exists);
}
//===============
//encode / decode
//===============
void Cheat::disable() {
cheat_system_enabled = false;
cheat_enabled = false;
}
//================================
//cheat list manipulation routines
//================================
void Cheat::add(bool enable, const char *code_, const char *desc_) {
cheat_t item;
decode(code_, item);
unsigned i = code.size();
code[i] = item;
code[i].enabled = enable;
code[i].desc = desc_;
code[i].code = code_;
encode_description(code[i].desc);
update(code[i]);
update_cheat_status();
}
void Cheat::edit(unsigned i, bool enable, const char *code_, const char *desc_) {
cheat_t item;
decode(code_, item);
//disable current code and clear from code lookup table
code[i].enabled = false;
update(code[i]);
code[i] = item;
code[i].enabled = enable;
code[i].desc = desc_;
code[i].code = code_;
encode_description(code[i].desc);
update(code[i]);
update_cheat_status();
}
bool Cheat::remove(unsigned i) {
unsigned size = code.size();
if(i >= size) return false; //also verifies size cannot be < 1
for(unsigned n = i; n < size - 1; n++) code[n] = code[n + 1];
code.resize(size - 1);
update_cheat_status();
return true;
}
bool Cheat::get(unsigned i, cheat_t &item) const {
if(i >= code.size()) return false;
item = code[i];
decode_description(item.desc);
return true;
}
//==============================
//cheat status modifier routines
//==============================
bool Cheat::enabled(unsigned i) const {
return (i < code.size() ? code[i].enabled : false);
}
void Cheat::enable(unsigned i) {
if(i >= code.size()) return;
code[i].enabled = true;
update(code[i]);
update_cheat_status();
}
void Cheat::disable(unsigned i) {
if(i >= code.size()) return;
code[i].enabled = false;
update(code[i]);
update_cheat_status();
}
//===============================
//cheat file load / save routines
//
//file format:
//"description", status, nnnn-nnnn[+nnnn-nnnn...]\r\n
//...
//===============================
void Cheat::load(string data) {
data.replace("\r", "");
data.qreplace(" ", "");
lstring line;
line.split("\n", data);
for(unsigned i = 0; i < line.size(); i++) {
lstring part;
part.qsplit(",", line[i]);
if(part.size() != 3) continue;
trim(part[2], "\"");
add(part[0] == "enabled", /* code = */ part[1], /* desc = */ part[2]);
}
}
string Cheat::save() const {
string data;
for(unsigned i = 0; i < code.size(); i++) {
data << (code[i].enabled ? "enabled," : "disabled,")
<< code[i].code << ","
<< "\"" << code[i].desc << "\"\r\n";
}
return data;
}
void Cheat::clear() {
cheat_enabled_code_exists = false;
memset(mask, 0, 0x200000);
code.reset();
}
Cheat::Cheat() : cheat_system_enabled(true) {
clear();
}
//==================
//internal functions
//==================
//string <> binary code translation routines
//decode() "7e123456" -> 0x7e123456
//encode() 0x7e123456 -> "7e123456"
bool Cheat::decode(const char *s, unsigned &addr, uint8_t &data, type_t &type) const {
bool Cheat::decode(const char *s, unsigned &addr, uint8 &data, Type &type) {
string t = s;
strlower(t);
@ -274,9 +117,11 @@ bool Cheat::decode(const char *s, unsigned &addr, uint8_t &data, type_t &type) c
} else {
return false;
}
#undef ischr
}
bool Cheat::encode(string &s, unsigned addr, uint8_t data, type_t type) const {
bool Cheat::encode(string &s, unsigned addr, uint8 data, Type type) {
char t[16];
if(type == ProActionReplay) {
@ -306,90 +151,46 @@ bool Cheat::encode(string &s, unsigned addr, uint8_t data, type_t type) const {
}
}
//speed up S-CPU memory reads by disabling cheat code lookup when either:
//a) cheat system is disabled by user, or b) no enabled cheat codes exist
void Cheat::update_cheat_status() {
for(unsigned i = 0; i < code.size(); i++) {
if(code[i].enabled) {
cheat_enabled_code_exists = true;
cheat_enabled = (cheat_system_enabled && cheat_enabled_code_exists);
return;
//========
//internal
//========
unsigned Cheat::mirror(unsigned addr) const {
//$00-3f|80-bf:0000-1fff -> $7e:0000-1fff
if((addr & 0x40e000) == 0x000000) return (0x7e0000 + (addr & 0x1fff));
return addr;
}
//=========
//CheatCode
//=========
bool CheatCode::operator=(string s) {
addr.reset();
data.reset();
lstring list;
list.split("+", s.replace(" ", ""));
for(unsigned i = 0; i < list.size(); i++) {
unsigned addr_;
uint8 data_;
Cheat::Type type_;
if(Cheat::decode(list[i], addr_, data_, type_) == false) {
addr.reset();
data.reset();
return false;
}
addr.add(addr_);
data.add(data_);
}
cheat_enabled_code_exists = false;
cheat_enabled = false;
return true;
}
//address lookup table manipulation and mirroring
//mirror_address() 0x000000 -> 0x7e0000
//set() enable specified address, mirror accordingly
//clear() disable specified address, mirror accordingly
unsigned Cheat::mirror_address(unsigned addr) const {
if((addr & 0x40e000) != 0x0000) return addr;
//8k WRAM mirror
//$[00-3f|80-bf]:[0000-1fff] -> $7e:[0000-1fff]
return (0x7e0000 + (addr & 0x1fff));
CheatCode::CheatCode() {
enabled = false;
}
//updates mask[] table enabled bits;
//must be called after modifying item.enabled state.
void Cheat::update(const cheat_t &item) {
for(unsigned n = 0; n < item.count; n++) {
(item.enabled) ? set(item.addr[n]) : clear(item.addr[n]);
}
}
void Cheat::set(unsigned addr) {
addr = mirror_address(addr);
mask[addr >> 3] |= 1 << (addr & 7);
if((addr & 0xffe000) == 0x7e0000) {
//mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
unsigned mirror;
for(unsigned x = 0; x <= 0x3f; x++) {
mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] |= 1 << (mirror & 7);
mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] |= 1 << (mirror & 7);
}
}
}
void Cheat::clear(unsigned addr) {
addr = mirror_address(addr);
//if there is more than one cheat code using the same address,
//(eg with a different override value) then do not clear code
//lookup table entry.
uint8_t r;
if(read(addr, r) == true) return;
mask[addr >> 3] &= ~(1 << (addr & 7));
if((addr & 0xffe000) == 0x7e0000) {
//mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
unsigned mirror;
for(unsigned x = 0; x <= 0x3f; x++) {
mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] &= ~(1 << (mirror & 7));
mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] &= ~(1 << (mirror & 7));
}
}
}
//these two functions are used to safely store description text inside .cfg file format.
string& Cheat::encode_description(string &desc) const {
desc.replace("\"", "\\q");
desc.replace("\n", "\\n");
return desc;
}
string& Cheat::decode_description(string &desc) const {
desc.replace("\\q", "\"");
desc.replace("\\n", "\n");
return desc;
}
};

View File

@ -1,69 +1,35 @@
class Cheat {
struct CheatCode {
bool enabled;
array<unsigned> addr;
array<uint8> data;
bool operator=(string);
CheatCode();
};
class Cheat : public vector<CheatCode> {
public:
enum type_t {
ProActionReplay,
GameGenie,
};
struct cheat_t {
bool enabled;
string code;
string desc;
unsigned count;
array<unsigned> addr;
array<uint8_t> data;
cheat_t& operator=(const cheat_t&);
bool operator<(const cheat_t&);
};
bool decode(const char *s, cheat_t &item) const;
bool read(unsigned addr, uint8_t &data) const;
enum Type { ProActionReplay, GameGenie };
bool enabled() const;
void enable();
void disable();
void enable(bool);
void synchronize();
bool read(unsigned, uint8&) const;
inline unsigned count() const;
inline bool active() const;
inline bool exists(unsigned addr) const;
void add(bool enable, const char *code, const char *desc);
void edit(unsigned i, bool enable, const char *code, const char *desc);
bool remove(unsigned i);
bool get(unsigned i, cheat_t &item) const;
bool enabled(unsigned i) const;
void enable(unsigned i);
void disable(unsigned i);
void load(string data);
string save() const;
void clear();
Cheat();
static bool decode(const char*, unsigned&, uint8&, Type&);
static bool encode(string&, unsigned, uint8, Type);
private:
bool cheat_enabled; //cheat_enabled == (cheat_enabled_code_exists && cheat_system_enabled);
bool cheat_enabled_code_exists;
bool cheat_system_enabled;
uint8_t mask[0x200000];
vector<cheat_t> code;
bool decode(const char *str, unsigned &addr, uint8_t &data, type_t &type) const;
bool encode(string &str, unsigned addr, uint8_t data, type_t type) const;
void update_cheat_status();
unsigned mirror_address(unsigned addr) const;
void update(const cheat_t& item);
void set(unsigned addr);
void clear(unsigned addr);
string& encode_description(string &desc) const;
string& decode_description(string &desc) const;
uint8 bitmask[0x200000];
bool system_enabled;
bool code_enabled;
bool cheat_enabled;
unsigned mirror(unsigned) const;
};
extern Cheat cheat;

View File

@ -1,7 +1,9 @@
#include <../base.hpp>
//B-bus interface
//$21f0 command port (r/w)
//-------------------
//-------------------------
//$00 set data port address (sr[3-0] = address)
//$01 set audio track number (sr[1-0] = track number)
//$02 set volume (sr[1] = left, sr[0] = right)
@ -11,16 +13,37 @@
//d6 = audio port busy
//d5 = audio playing
//d4 = reserved (0)
//d3-d0 = version (1)
//d3-d0 = version (0)
//
//
//$21f1 parameter port (w)
//---------------------
//-------------------------
//(shift register)
//
//
//$21f2 data port (r)
//----------------
//--------------------
//(auto-increment read port)
//A-bus interface
//$2200 command port (r/w)
//-------------------------
//$00 set data port address (sr[3-0] = address)
//$01 set audio track number (sr[1-0] = track number)
//$02 set volume (sr[1] = left, sr[0] = right)
//$03 set audio state (sr[0].d1 = pause, sr[0].d0 = repeat)
//
//d7 = data port busy
//d6 = audio port busy
//d5 = audio playing
//d4 = reserved (0)
//d3-d0 = version (0)
//
//$2201 data port (r/w)
//----------------------
//(shift register)
//
//(auto-increment read port)
#define S21FX_CPP
@ -34,6 +57,10 @@ void S21fx::enter() {
scheduler.clock.cop_freq = 44100;
while(true) {
if(scheduler.sync == Scheduler::SyncAll) {
scheduler.exit(Scheduler::SynchronizeEvent);
}
int16 left = 0, right = 0;
if((mmio.status & AudioPlaying) && !mmio.audio_pause) {
@ -71,6 +98,9 @@ void S21fx::enable() {
memory::mmio.map(i, *this);
}
memory::mmio.map(0x2200, *this);
memory::mmio.map(0x2201, *this);
if(datafile.open()) datafile.close();
datafile.open(string() << basepath << "21fx.bin", file::mode_read);
}
@ -95,11 +125,11 @@ void S21fx::reset() {
uint8 S21fx::mmio_read(unsigned addr) {
addr &= 0xffff;
if(addr == 0x21f0) {
return mmio.status | 0x01;
if((addr == 0x21f0) || (addr == 0x2200)) {
return mmio.status | 0x00;
}
if(addr == 0x21f2) {
if((addr == 0x21f2) || (addr == 0x2201)) {
if(mmio.status & DataPortBusy) return 0x00;
mmio.data_offset++;
if(datafile.open()) return datafile.read();
@ -112,7 +142,7 @@ uint8 S21fx::mmio_read(unsigned addr) {
void S21fx::mmio_write(unsigned addr, uint8 data) {
addr &= 0xffff;
if(addr == 0x21f0) {
if((addr == 0x21f0) || (addr == 0x2200)) {
if(data == 0x00) {
mmio.data_offset = mmio.shift_register & 0xffffffff;
if(datafile.open()) {
@ -146,7 +176,7 @@ void S21fx::mmio_write(unsigned addr, uint8 data) {
mmio.shift_register = 0;
}
if(addr == 0x21f1) {
if((addr == 0x21f1) || (addr == 0x2201)) {
mmio.shift_register = (mmio.shift_register << 8) | data;
}
}

View File

@ -4,14 +4,14 @@ VBRBus vbrbus;
SA1Bus sa1bus;
namespace memory {
static StaticRAM iram(2048);
//accessed by:
static VectorSelectionPage vectorsp; //S-CPU + SA-1
static CPUIRAM cpuiram; //S-CPU
static SA1IRAM sa1iram; //SA-1
static SA1BWRAM sa1bwram; //SA-1
static CC1BWRAM cc1bwram; //S-CPU
static BitmapRAM bitmapram; //SA-1
StaticRAM iram(2048);
//accessed by:
VectorSelectionPage vectorsp; //S-CPU + SA-1
CPUIRAM cpuiram; //S-CPU
SA1IRAM sa1iram; //SA-1
SA1BWRAM sa1bwram; //SA-1
CC1BWRAM cc1bwram; //S-CPU
BitmapRAM bitmapram; //SA-1
}
//$230c (VDPL), $230d (VDPH) use this bus to read variable-length data.

View File

@ -43,3 +43,14 @@ struct BitmapRAM : Memory {
alwaysinline uint8 read(unsigned);
alwaysinline void write(unsigned, uint8);
};
namespace memory {
extern StaticRAM iram;
extern VectorSelectionPage vectorsp;
extern CPUIRAM cpuiram;
extern SA1IRAM sa1iram;
extern SA1BWRAM sa1bwram;
extern CC1BWRAM cc1bwram;
extern BitmapRAM bitmapram;
};

View File

@ -5,6 +5,7 @@ namespace SNES {
SA1 sa1;
#include "serialization.cpp"
#include "bus/bus.cpp"
#include "dma/dma.cpp"
#include "memory/memory.cpp"
@ -12,10 +13,15 @@ SA1 sa1;
void SA1::enter() {
while(true) {
while(mmio.sa1_rdyb || mmio.sa1_resb) {
if(scheduler.sync == Scheduler::SyncAll) {
scheduler.exit(Scheduler::SynchronizeEvent);
}
if(mmio.sa1_rdyb || mmio.sa1_resb) {
//SA-1 co-processor is asleep
tick();
scheduler.sync_copcpu();
continue;
}
if(status.interrupt_pending) {
@ -139,7 +145,7 @@ void SA1::reset() {
regs.e = 1;
regs.mdr = 0x00;
regs.wai = false;
update_table();
CPUcore::update_table();
status.tick_counter = 0;

View File

@ -30,6 +30,7 @@ public:
void power();
void reset();
void serialize(serializer&);
SA1();
};

View File

@ -0,0 +1,150 @@
#ifdef SA1_CPP
void SA1::serialize(serializer &s) {
CPUcore::core_serialize(s);
//sa1.hpp
s.integer(status.tick_counter);
s.integer(status.interrupt_pending);
s.integer(status.interrupt_vector);
s.integer(status.scanlines);
s.integer(status.vcounter);
s.integer(status.hcounter);
//bus/bus.hpp
s.array(memory::iram.data(), memory::iram.size());
memory::vectorsp.sync();
s.integer(memory::cc1bwram.dma);
//dma/dma.hpp
s.integer(dma.line);
//mmio/mmio.hpp
s.integer(mmio.sa1_irq);
s.integer(mmio.sa1_rdyb);
s.integer(mmio.sa1_resb);
s.integer(mmio.sa1_nmi);
s.integer(mmio.smeg);
s.integer(mmio.cpu_irqen);
s.integer(mmio.chdma_irqen);
s.integer(mmio.cpu_irqcl);
s.integer(mmio.chdma_irqcl);
s.integer(mmio.crv);
s.integer(mmio.cnv);
s.integer(mmio.civ);
s.integer(mmio.cpu_irq);
s.integer(mmio.cpu_ivsw);
s.integer(mmio.cpu_nvsw);
s.integer(mmio.cmeg);
s.integer(mmio.sa1_irqen);
s.integer(mmio.timer_irqen);
s.integer(mmio.dma_irqen);
s.integer(mmio.sa1_nmien);
s.integer(mmio.sa1_irqcl);
s.integer(mmio.timer_irqcl);
s.integer(mmio.dma_irqcl);
s.integer(mmio.sa1_nmicl);
s.integer(mmio.snv);
s.integer(mmio.siv);
s.integer(mmio.hvselb);
s.integer(mmio.ven);
s.integer(mmio.hen);
s.integer(mmio.hcnt);
s.integer(mmio.vcnt);
s.integer(mmio.cbmode);
s.integer(mmio.cb);
s.integer(mmio.dbmode);
s.integer(mmio.db);
s.integer(mmio.ebmode);
s.integer(mmio.eb);
s.integer(mmio.fbmode);
s.integer(mmio.fb);
s.integer(mmio.sbm);
s.integer(mmio.sw46);
s.integer(mmio.cbm);
s.integer(mmio.swen);
s.integer(mmio.cwen);
s.integer(mmio.bwp);
s.integer(mmio.siwp);
s.integer(mmio.ciwp);
s.integer(mmio.dmaen);
s.integer(mmio.dprio);
s.integer(mmio.cden);
s.integer(mmio.cdsel);
s.integer(mmio.dd);
s.integer(mmio.sd);
s.integer(mmio.chdend);
s.integer(mmio.dmasize);
s.integer(mmio.dmacb);
s.integer(mmio.dsa);
s.integer(mmio.dda);
s.integer(mmio.dtc);
s.integer(mmio.bbf);
s.array(mmio.brf);
s.integer(mmio.acm);
s.integer(mmio.md);
s.integer(mmio.ma);
s.integer(mmio.mb);
s.integer(mmio.hl);
s.integer(mmio.vb);
s.integer(mmio.va);
s.integer(mmio.vbit);
s.integer(mmio.cpu_irqfl);
s.integer(mmio.chdma_irqfl);
s.integer(mmio.sa1_irqfl);
s.integer(mmio.timer_irqfl);
s.integer(mmio.dma_irqfl);
s.integer(mmio.sa1_nmifl);
s.integer(mmio.hcr);
s.integer(mmio.vcr);
s.integer(mmio.mr);
s.integer(mmio.overflow);
}
#endif

View File

@ -3,11 +3,11 @@
SuperFXBus superfxbus;
namespace memory {
static SuperFXGSUROM gsurom;
static SuperFXGSURAM gsuram;
static SuperFXCPUROM fxrom;
static SuperFXCPURAM fxram;
};
SuperFXGSUROM gsurom;
SuperFXGSURAM gsuram;
SuperFXCPUROM fxrom;
SuperFXCPURAM fxram;
}
void SuperFXBus::init() {
map(MapDirect, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
@ -34,7 +34,7 @@ unsigned SuperFXGSUROM::size() const {
}
uint8 SuperFXGSUROM::read(unsigned addr) {
while(!superfx.regs.scmr.ron) {
while(!superfx.regs.scmr.ron && scheduler.sync != Scheduler::SyncAll) {
superfx.add_clocks(6);
scheduler.sync_copcpu();
}
@ -42,7 +42,7 @@ uint8 SuperFXGSUROM::read(unsigned addr) {
}
void SuperFXGSUROM::write(unsigned addr, uint8 data) {
while(!superfx.regs.scmr.ron) {
while(!superfx.regs.scmr.ron && scheduler.sync != Scheduler::SyncAll) {
superfx.add_clocks(6);
scheduler.sync_copcpu();
}
@ -54,7 +54,7 @@ unsigned SuperFXGSURAM::size() const {
}
uint8 SuperFXGSURAM::read(unsigned addr) {
while(!superfx.regs.scmr.ran) {
while(!superfx.regs.scmr.ran && scheduler.sync != Scheduler::SyncAll) {
superfx.add_clocks(6);
scheduler.sync_copcpu();
}
@ -62,7 +62,7 @@ uint8 SuperFXGSURAM::read(unsigned addr) {
}
void SuperFXGSURAM::write(unsigned addr, uint8 data) {
while(!superfx.regs.scmr.ran) {
while(!superfx.regs.scmr.ran && scheduler.sync != Scheduler::SyncAll) {
superfx.add_clocks(6);
scheduler.sync_copcpu();
}

View File

@ -25,3 +25,10 @@ struct SuperFXCPURAM : Memory {
uint8 read(unsigned);
void write(unsigned, uint8);
};
namespace memory {
extern SuperFXGSUROM gsurom;
extern SuperFXGSURAM gsuram;
extern SuperFXCPUROM fxrom;
extern SuperFXCPURAM fxram;
}

View File

@ -114,7 +114,7 @@ void SuperFX::op_bvs() {
//$10-1f(b1): move rN
template<int n> void SuperFX::op_to_r() {
if(regs.sfr.b == 0) {
regs.dreg = &regs.r[n];
regs.dreg = n;
} else {
regs.r[n] = regs.sr();
regs.reset();
@ -123,8 +123,8 @@ template<int n> void SuperFX::op_to_r() {
//$20-2f: with rN
template<int n> void SuperFX::op_with_r() {
regs.sreg = &regs.r[n];
regs.dreg = &regs.r[n];
regs.sreg = n;
regs.dreg = n;
regs.sfr.b = 1;
}
@ -519,7 +519,7 @@ template<int n> void SuperFX::op_sms_r() {
//$b0-bf(b1): moves rN
template<int n> void SuperFX::op_from_r() {
if(regs.sfr.b == 0) {
regs.sreg = &regs.r[n];
regs.sreg = n;
} else {
regs.dr() = regs.r[n];
regs.sfr.ov = (regs.dr() & 0x80);

View File

@ -149,17 +149,17 @@ struct regs_t {
uint16 ramar; //RAM buffer address register
uint8 ramdr; //RAM buffer data register
reg16_t *sreg, *dreg;
reg16_t& sr() { return *sreg; } //source register (from)
reg16_t& dr() { return *dreg; } //destination register (to)
unsigned sreg, dreg;
reg16_t& sr() { return r[sreg]; } //source register (from)
reg16_t& dr() { return r[dreg]; } //destination register (to)
void reset() {
sfr.b = 0;
sfr.alt1 = 0;
sfr.alt2 = 0;
sreg = &r[0];
dreg = &r[0];
sreg = 0;
dreg = 0;
}
} regs;

View File

@ -1,3 +1,5 @@
#ifdef SUPERFX_CPP
void SuperFX::disassemble_opcode(char *output) {
*output = 0;
@ -273,3 +275,5 @@ void SuperFX::disassemble_alt3(char *output) {
#undef op0
#undef op1
#undef op2
#endif

View File

@ -1,3 +1,5 @@
#ifdef SUPERFX_CPP
uint8 SuperFX::op_read(uint16 addr) {
uint16 offset = addr - regs.cbr;
if(offset < 512) {
@ -65,3 +67,5 @@ void SuperFX::memory_reset() {
pixelcache[n].bitpend = 0x00;
}
}
#endif

View File

@ -0,0 +1,94 @@
#ifdef SUPERFX_CPP
void SuperFX::serialize(serializer &s) {
//superfx.hpp
s.integer(clockmode);
s.integer(instruction_counter);
//core/registers.hpp
s.integer(regs.pipeline);
s.integer(regs.ramaddr);
s.integer(regs.r[ 0].data);
s.integer(regs.r[ 1].data);
s.integer(regs.r[ 2].data);
s.integer(regs.r[ 3].data);
s.integer(regs.r[ 4].data);
s.integer(regs.r[ 5].data);
s.integer(regs.r[ 6].data);
s.integer(regs.r[ 7].data);
s.integer(regs.r[ 8].data);
s.integer(regs.r[ 9].data);
s.integer(regs.r[10].data);
s.integer(regs.r[11].data);
s.integer(regs.r[12].data);
s.integer(regs.r[13].data);
s.integer(regs.r[14].data);
s.integer(regs.r[15].data);
s.integer(regs.sfr.irq);
s.integer(regs.sfr.b);
s.integer(regs.sfr.ih);
s.integer(regs.sfr.il);
s.integer(regs.sfr.alt2);
s.integer(regs.sfr.alt1);
s.integer(regs.sfr.r);
s.integer(regs.sfr.g);
s.integer(regs.sfr.ov);
s.integer(regs.sfr.s);
s.integer(regs.sfr.cy);
s.integer(regs.sfr.z);
s.integer(regs.pbr);
s.integer(regs.rombr);
s.integer(regs.rambr);
s.integer(regs.cbr);
s.integer(regs.scbr);
s.integer(regs.scmr.ht);
s.integer(regs.scmr.ron);
s.integer(regs.scmr.ran);
s.integer(regs.scmr.md);
s.integer(regs.colr);
s.integer(regs.por.obj);
s.integer(regs.por.freezehigh);
s.integer(regs.por.highnibble);
s.integer(regs.por.dither);
s.integer(regs.por.transparent);
s.integer(regs.bramr);
s.integer(regs.vcr);
s.integer(regs.cfgr.irq);
s.integer(regs.cfgr.ms0);
s.integer(regs.clsr);
s.integer(regs.romcl);
s.integer(regs.romdr);
s.integer(regs.ramcl);
s.integer(regs.ramar);
s.integer(regs.ramdr);
s.integer(regs.sreg);
s.integer(regs.dreg);
s.array(cache.buffer);
s.array(cache.valid);
for(unsigned i = 0; i < 2; i++) {
s.integer(pixelcache[i].offset);
s.integer(pixelcache[i].bitpend);
s.array(pixelcache[i].data);
}
//timing/timing.hpp
s.integer(cache_access_speed);
s.integer(memory_access_speed);
s.integer(r15_modified);
}
#endif

View File

@ -3,6 +3,7 @@
#define SUPERFX_CPP
namespace SNES {
#include "serialization.cpp"
#include "bus/bus.cpp"
#include "core/core.cpp"
#include "memory/memory.cpp"
@ -14,9 +15,14 @@ SuperFX superfx;
void SuperFX::enter() {
while(true) {
while(regs.sfr.g == 0) {
if(scheduler.sync == Scheduler::SyncAll) {
scheduler.exit(Scheduler::SynchronizeEvent);
}
if(regs.sfr.g == 0) {
add_clocks(6);
scheduler.sync_copcpu();
continue;
}
(this->*opcode_table[(regs.sfr & 0x0300) + peekpipe()])();
@ -70,4 +76,4 @@ void SuperFX::reset() {
timing_reset();
}
};
}

View File

@ -15,6 +15,8 @@ public:
void power();
void reset();
void serialize(serializer&);
private:
unsigned clockmode;
unsigned instruction_counter;

View File

@ -1,3 +1,5 @@
#ifdef SUPERFX_CPP
void SuperFX::add_clocks(unsigned clocks) {
if(regs.romcl) {
regs.romcl -= min(clocks, regs.romcl);
@ -91,3 +93,5 @@ void SuperFX::timing_reset() {
regs.ramar = 0;
regs.ramdr = 0;
}
#endif

View File

@ -9,12 +9,20 @@ void SuperGameBoy::enter() {
scheduler.clock.cop_freq = (version == SuperGameBoy1 ? 2147727 : 2097152);
if(!sgb_run) while(true) {
if(scheduler.sync == Scheduler::SyncAll) {
scheduler.exit(Scheduler::SynchronizeEvent);
}
audio.coprocessor_sample(0, 0);
scheduler.addclocks_cop(1);
scheduler.sync_copcpu();
}
while(true) {
if(scheduler.sync == Scheduler::SyncAll) {
scheduler.exit(Scheduler::SynchronizeEvent);
}
unsigned samples = sgb_run(samplebuffer, 16);
for(unsigned i = 0; i < samples; i++) {
int16 left = samplebuffer[i] >> 0;
@ -23,6 +31,7 @@ void SuperGameBoy::enter() {
//SNES audio is notoriously quiet; lower Game Boy samples to match SGB sound effects
audio.coprocessor_sample(left / 3, right / 3);
}
scheduler.addclocks_cop(samples);
scheduler.sync_copcpu();
}
@ -98,8 +107,7 @@ void SuperGameBoy::enable() {
}
void SuperGameBoy::power() {
//determine whether to use SGB1 or SGB2 mode based on the cartridge title (look for the '2')
version = memory::cartrom[0x7fcd] != 0x32 ? SuperGameBoy1 : SuperGameBoy2;
version = (cartridge.type() == Cartridge::TypeSuperGameBoy1Bios ? SuperGameBoy1 : SuperGameBoy2);
audio.coprocessor_enable(true);
audio.coprocessor_frequency(version == SuperGameBoy1 ? 2147727.0 : 2097152.0);
@ -111,7 +119,6 @@ void SuperGameBoy::power() {
sgb_ram(memory::gbram.data(), memory::gbram.size() == -1U ? 0 : memory::gbram.size());
sgb_rtc(memory::gbrtc.data(), memory::gbrtc.size() == -1U ? 0 : memory::gbrtc.size());
//determine whether to use SGB1 or SGB2 mode based on the cartridge title (look for the '2')
if(sgb_init) sgb_init(version);
if(sgb_power) sgb_power();
}

View File

@ -5,7 +5,7 @@ namespace SNES {
#include "serialization.cpp"
#include "algorithms.cpp"
#include "disasm/disasm.cpp"
#include "disassembler/disassembler.cpp"
#define L last_cycle();
#define A 0

View File

@ -2,7 +2,7 @@ class CPUcore {
public:
#include "registers.hpp"
#include "memory.hpp"
#include "disasm/disasm.hpp"
#include "disassembler/disassembler.hpp"
regs_t regs;
reg24_t aa, rd;

View File

@ -1,30 +0,0 @@
enum {
OPTYPE_DP = 0, //dp
OPTYPE_DPX, //dp,x
OPTYPE_DPY, //dp,y
OPTYPE_IDP, //(dp)
OPTYPE_IDPX, //(dp,x)
OPTYPE_IDPY, //(dp),y
OPTYPE_ILDP, //[dp]
OPTYPE_ILDPY, //[dp],y
OPTYPE_ADDR, //addr
OPTYPE_ADDRX, //addr,x
OPTYPE_ADDRY, //addr,y
OPTYPE_IADDRX, //(addr,x)
OPTYPE_ILADDR, //[addr]
OPTYPE_LONG, //long
OPTYPE_LONGX, //long, x
OPTYPE_SR, //sr,s
OPTYPE_ISRY, //(sr,s),y
OPTYPE_ADDR_PC, //pbr:addr
OPTYPE_IADDR_PC, //pbr:(addr)
OPTYPE_RELB, //relb
OPTYPE_RELW, //relw
};
void disassemble_opcode(char *output, uint32 addr);
uint8 dreadb(uint32 addr);
uint16 dreadw(uint32 addr);
uint32 dreadl(uint32 addr);
uint32 decode(uint8 offset_type, uint32 addr);
uint8 opcode_length();

View File

@ -1,3 +1,5 @@
#ifdef CPUCORE_CPP
uint8 CPUcore::dreadb(uint32 addr) {
if((addr & 0x40ffff) >= 0x2000 && (addr & 0x40ffff) <= 0x5fff) {
//$[00-3f|80-bf]:[2000-5fff]
@ -477,3 +479,5 @@ uint8 CPUcore::opcode_length() {
if(len == 6) return (regs.e || regs.p.x) ? 2 : 3;
return len;
}
#endif

View File

@ -0,0 +1,30 @@
enum {
OPTYPE_DP = 0, //dp
OPTYPE_DPX, //dp,x
OPTYPE_DPY, //dp,y
OPTYPE_IDP, //(dp)
OPTYPE_IDPX, //(dp,x)
OPTYPE_IDPY, //(dp),y
OPTYPE_ILDP, //[dp]
OPTYPE_ILDPY, //[dp],y
OPTYPE_ADDR, //addr
OPTYPE_ADDRX, //addr,x
OPTYPE_ADDRY, //addr,y
OPTYPE_IADDRX, //(addr,x)
OPTYPE_ILADDR, //[addr]
OPTYPE_LONG, //long
OPTYPE_LONGX, //long, x
OPTYPE_SR, //sr,s
OPTYPE_ISRY, //(sr,s),y
OPTYPE_ADDR_PC, //pbr:addr
OPTYPE_IADDR_PC, //pbr:(addr)
OPTYPE_RELB, //relb
OPTYPE_RELW, //relw
};
void disassemble_opcode(char *output, uint32 addr);
uint8 dreadb(uint32 addr);
uint16 dreadw(uint32 addr);
uint32 dreadl(uint32 addr);
uint32 decode(uint8 offset_type, uint32 addr);
uint8 opcode_length();

View File

@ -1,3 +1,5 @@
#ifdef CPUCORE_CPP
void CPUcore::op_nop() {
L op_io_irq();
}
@ -346,3 +348,5 @@ void CPUcore::op_per_n() {
op_writestackn(rd.h);
L op_writestackn(rd.l);
}
#endif

View File

@ -1,3 +1,5 @@
#ifdef CPUCORE_CPP
template<int bit, int val> void CPUcore::op_branch() {
if((bool)(regs.p & bit) != val) {
L rd.l = op_readpc();
@ -175,3 +177,5 @@ L rd.b = op_readstackn();
regs.pc.b = rd.b;
regs.pc.w = ++rd.w;
}
#endif

View File

@ -1,3 +1,5 @@
#ifdef CPUCORE_CPP
template<void (CPUcore::*op)()> void CPUcore::op_read_const_b() {
L rd.l = op_readpc();
call(op);
@ -273,3 +275,5 @@ template<void (CPUcore::*op)()> void CPUcore::op_read_isry_w() {
L rd.h = op_readdbr(aa.w + regs.y.w + 1);
call(op);
}
#endif

View File

@ -1,3 +1,5 @@
#ifdef CPUCORE_CPP
template<int n, int adjust> void CPUcore::op_adjust_imm_b() {
L op_io_irq();
regs.r[n].l += adjust;
@ -163,3 +165,5 @@ template<void (CPUcore::*op)()> void CPUcore::op_adjust_dpx_w() {
op_writedp(dp + regs.x.w + 1, rd.h);
L op_writedp(dp + regs.x.w + 0, rd.l);
}
#endif

View File

@ -1,3 +1,5 @@
#ifdef CPUCORE_CPP
template<int n> void CPUcore::op_write_addr_b() {
aa.l = op_readpc();
aa.h = op_readpc();
@ -193,3 +195,5 @@ void CPUcore::op_sta_isry_w() {
op_writedbr(aa.w + regs.y.w + 0, regs.a.l);
L op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
}
#endif

59
src/cpu/cpu-debugger.cpp Normal file
View File

@ -0,0 +1,59 @@
#ifdef CPU_CPP
bool CPUDebugger::property(unsigned id, string &name, string &value) {
unsigned n = 0;
//internal
if(id == n++) { name = "S-CPU MDR"; value = string::printf("0x%.2x", mdr()); return true; }
//$2181-2183
if(id == n++) { name = "$2181-$2183"; value = ""; return true; }
if(id == n++) { name = "WRAM Address"; value = string::printf("0x%.6x", wram_address()); return true; }
//$4016
if(id == n++) { name = "$4016"; value = ""; return true; }
if(id == n++) { name = "Joypad Strobe Latch"; value = joypad_strobe_latch(); return true; }
//$4200
if(id == n++) { name = "$4200"; value = ""; return true; }
if(id == n++) { name = "NMI Enable"; value = nmi_enable(); return true; }
if(id == n++) { name = "H-IRQ Enable"; value = hirq_enable(); return true; }
if(id == n++) { name = "V-IRQ Enable"; value = virq_enable(); return true; }
if(id == n++) { name = "Auto Joypad Poll"; value = auto_joypad_poll(); return true; }
//$4201
if(id == n++) { name = "$4201"; value = ""; return true; }
if(id == n++) { name = "PIO"; value = string::printf("0x%.2x", pio_bits()); return true; }
//$4202
if(id == n++) { name = "$4202"; value = ""; return true; }
if(id == n++) { name = "Multiplicand"; value = string::printf("0x%.2x", multiplicand()); return true; }
//$4203
if(id == n++) { name = "$4203"; value = ""; return true; }
if(id == n++) { name = "Multiplier"; value = string::printf("0x%.2x", multiplier()); return true; }
//$4204-$4205
if(id == n++) { name = "$4204-$4205"; value = ""; return true; }
if(id == n++) { name = "Dividend"; value = string::printf("0x%.4x", dividend()); return true; }
//$4206
if(id == n++) { name = "$4206"; value = ""; return true; }
if(id == n++) { name = "Divisor"; value = string::printf("0x%.2x", divisor()); return true; }
//$4207-$4208
if(id == n++) { name = "$4207-$4208"; value = ""; return true; }
if(id == n++) { name = "H-Time"; value = string::printf("0x%.4x", htime()); return true; }
//$4209-$420a
if(id == n++) { name = "$4209-$420a"; value = ""; return true; }
if(id == n++) { name = "V-Time"; value = string::printf("0x%.4x", vtime()); return true; }
//$420d
if(id == n++) { name = "$420d"; value = ""; return true; }
if(id == n++) { name = "FastROM Enable"; value = fastrom_enable(); return true; }
return false;
}
#endif

42
src/cpu/cpu-debugger.hpp Normal file
View File

@ -0,0 +1,42 @@
struct CPUDebugger : ChipDebugger {
bool property(unsigned id, string &name, string &value);
//internal
virtual unsigned mdr() { return 0; }
//$2181-2183
virtual unsigned wram_address() { return 0; }
//$4016
virtual bool joypad_strobe_latch() { return 0; }
//$4200
virtual bool nmi_enable() { return 0; }
virtual bool hirq_enable() { return 0; }
virtual bool virq_enable() { return 0; }
virtual bool auto_joypad_poll() { return 0; }
//$4201
virtual unsigned pio_bits() { return 0; }
//$4202
virtual unsigned multiplicand() { return 0; }
//$4203
virtual unsigned multiplier() { return 0; }
//$4204-$4205
virtual unsigned dividend() { return 0; }
//$4206
virtual unsigned divisor() { return 0; }
//$4207-$4208
virtual unsigned htime() { return 0; }
//$4209-$420a
virtual unsigned vtime() { return 0; }
//$420d
virtual bool fastrom_enable() { return 0; }
};

View File

@ -3,6 +3,10 @@
#define CPU_CPP
namespace SNES {
#if defined(DEBUGGER)
#include "cpu-debugger.cpp"
#endif
void CPU::power() {
cpu_version = config.cpu.version;
}

View File

@ -1,3 +1,7 @@
#if defined(DEBUGGER)
#include "cpu-debugger.hpp"
#endif
class CPU : public PPUcounter, public MMIO {
public:
virtual void enter() = 0;

View File

@ -1,45 +1,88 @@
#ifdef SCPU_CPP
void sCPUDebug::op_step() {
void sCPUDebugger::op_step() {
bool break_event = false;
if(debugger.step_cpu) {
debugger.break_event = Debugger::CPUStep;
scheduler.exit();
} else {
debugger.breakpoint_test(Debugger::Breakpoint::CPUBus, Debugger::Breakpoint::Exec, regs.pc, 0x00);
}
usage[regs.pc] &= ~(UsageFlagM | UsageFlagX);
usage[regs.pc] |= UsageExec | (regs.p.m << 1) | (regs.p.x << 0);
opcode_pc = regs.pc;
if(debugger.step_cpu) {
debugger.break_event = Debugger::CPUStep;
scheduler.exit(Scheduler::DebuggerEvent);
} else {
debugger.breakpoint_test(Debugger::Breakpoint::CPUBus, Debugger::Breakpoint::Exec, regs.pc, 0x00);
}
if(step_event) step_event();
sCPU::op_step();
scheduler.sync_cpusmp();
}
uint8 sCPUDebug::op_read(uint32 addr) {
uint8 sCPUDebugger::op_read(uint32 addr) {
uint8 data = sCPU::op_read(addr);
usage[addr] |= UsageRead;
debugger.breakpoint_test(Debugger::Breakpoint::CPUBus, Debugger::Breakpoint::Read, addr, data);
return data;
}
void sCPUDebug::op_write(uint32 addr, uint8 data) {
void sCPUDebugger::op_write(uint32 addr, uint8 data) {
sCPU::op_write(addr, data);
usage[addr] |= UsageWrite;
usage[addr] &= ~UsageExec;
debugger.breakpoint_test(Debugger::Breakpoint::CPUBus, Debugger::Breakpoint::Write, addr, data);
}
sCPUDebug::sCPUDebug() {
sCPUDebugger::sCPUDebugger() {
usage = new uint8[1 << 24]();
opcode_pc = 0x8000;
}
sCPUDebug::~sCPUDebug() {
sCPUDebugger::~sCPUDebugger() {
delete[] usage;
}
//===========
//CPUDebugger
//===========
//internal
unsigned sCPUDebugger::mdr() { return regs.mdr; }
//$2181-$2183
unsigned sCPUDebugger::wram_address() { return status.wram_addr; }
//$4016
bool sCPUDebugger::joypad_strobe_latch() { return status.joypad_strobe_latch; }
//$4200
bool sCPUDebugger::nmi_enable() { return status.nmi_enabled; }
bool sCPUDebugger::hirq_enable() { return status.hirq_enabled; }
bool sCPUDebugger::virq_enable() { return status.virq_enabled; }
bool sCPUDebugger::auto_joypad_poll() { return status.auto_joypad_poll; }
//$4201
unsigned sCPUDebugger::pio_bits() { return status.pio; }
//$4202
unsigned sCPUDebugger::multiplicand() { return status.mul_a; }
//$4203
unsigned sCPUDebugger::multiplier() { return status.mul_b; }
//$4204-$4205
unsigned sCPUDebugger::dividend() { return status.div_a; }
//$4206
unsigned sCPUDebugger::divisor() { return status.div_b; }
//$4207-$4208
unsigned sCPUDebugger::htime() { return status.hirq_pos; }
//$4209-$420a
unsigned sCPUDebugger::vtime() { return status.virq_pos; }
//$420d
bool sCPUDebugger::fastrom_enable() { return status.rom_speed; }
#endif

View File

@ -1,4 +1,4 @@
class sCPUDebug : public sCPU {
class sCPUDebugger : public sCPU, public CPUDebugger {
public:
function<void ()> step_event;
@ -16,6 +16,49 @@ public:
uint8 op_read(uint32 addr);
void op_write(uint32 addr, uint8 data);
sCPUDebug();
~sCPUDebug();
sCPUDebugger();
~sCPUDebugger();
//===========
//CPUDebugger
//===========
//internal
unsigned mdr();
//$2181-$2183
unsigned wram_address();
//$4016
bool joypad_strobe_latch();
//$4200
bool nmi_enable();
bool hirq_enable();
bool virq_enable();
bool auto_joypad_poll();
//$4201
unsigned pio_bits();
//$4202
unsigned multiplicand();
//$4203
unsigned multiplier();
//$4204-$4205
unsigned dividend();
//$4206
unsigned divisor();
//$4207-$4208
unsigned htime();
//$4209-$420a
unsigned vtime();
//$420d
bool fastrom_enable();
};

View File

@ -5,7 +5,7 @@ namespace SNES {
#if defined(DEBUGGER)
#include "debugger/debugger.cpp"
sCPUDebug cpu;
sCPUDebugger cpu;
#else
sCPU cpu;
#endif
@ -20,7 +20,7 @@ void sCPU::enter() {
while(true) {
if(scheduler.sync == Scheduler::SyncCpu) {
scheduler.sync = Scheduler::SyncAll;
scheduler.exit();
scheduler.exit(Scheduler::SynchronizeEvent);
}
if(status.interrupt_pending) {

View File

@ -100,7 +100,7 @@ public:
#if defined(DEBUGGER)
#include "debugger/debugger.hpp"
extern sCPUDebug cpu;
extern sCPUDebugger cpu;
#else
extern sCPU cpu;
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 935 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 995 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 978 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 900 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 927 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 966 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

View File

@ -1,7 +1,7 @@
#include <../base.hpp>
#define ADSP_CPP
namespaec SNES {
namespace SNES {
aDSP dsp;

View File

@ -1,3 +1,3 @@
class sDSPDebug : public sDSP {
class sDSPDebugger : public sDSP {
public:
};

View File

@ -9,7 +9,7 @@ namespace SNES {
#if defined(DEBUGGER)
#include "debugger/debugger.cpp"
sDSPDebug dsp;
sDSPDebugger dsp;
#else
sDSP dsp;
#endif
@ -20,7 +20,10 @@ namespace SNES {
#define VREG(n) state.regs[v.vidx + v_##n]
#if !defined(DSP_STATE_MACHINE)
#define phase_start() while(true) { if(scheduler.sync == Scheduler::SyncAll) scheduler.exit();
#define phase_start() while(true) { \
if(scheduler.sync == Scheduler::SyncAll) { \
scheduler.exit(Scheduler::SynchronizeEvent); \
}
#define phase(n)
#define tick() scheduler.addclocks_dsp(3 * 8); scheduler.sync_dspsmp()
#define phase_end() }

View File

@ -170,7 +170,7 @@ private:
#if defined(DEBUGGER)
#include "debugger/debugger.hpp"
extern sDSPDebug dsp;
extern sDSPDebugger dsp;
#else
extern sDSP dsp;
#endif

View File

@ -5,6 +5,10 @@
#endif
namespace SNES {
struct ChipDebugger {
virtual bool property(unsigned id, string &name, string &value) = 0;
};
#include "memory/memory.hpp"
#include "memory/smemory/smemory.hpp"

View File

@ -1,45 +1,91 @@
#ifndef NALL_PROPERTY_HPP
#define NALL_PROPERTY_HPP
//nall::property implements a variable container that disallows write access
//to non-derived objects. This requires use of property::set(), as C++ lacks
//the ability to make this implementation completely transparent.
//nall::property implements ownership semantics into container classes
//example: property<owner>::readonly<type> implies that only owner has full
//access to type; and all other code has readonly access.
//
//this code relies on extended friend semantics from C++0x to work, as it
//declares a friend class via a template paramter. it also exploits a bug in
//G++ 4.x to work even in C++98 mode.
//
//if compiling elsewhere, simply remove the friend class and private semantics
//property can be used either of two ways:
//struct foo {
// property<foo>::readonly<bool> x;
// property<foo>::readwrite<int> y;
//};
//-or-
//struct foo : property<foo> {
// readonly<bool> x;
// readwrite<int> y;
//};
//return types are const T& (byref) instead fo T (byval) to avoid major speed
//penalties for objects with expensive copy constructors
//operator-> provides access to underlying object type:
//readonly<Object> foo;
//foo->bar();
//... will call Object::bar();
//operator='s reference is constant so as to avoid leaking a reference handle
//that could bypass access restrictions
//both constant and non-constant operators are provided, though it may be
//necessary to cast first, for instance:
//struct foo : property<foo> { readonly<int> bar; } object;
//int main() { int value = const_cast<const foo&>(object); }
//writeonly is useful for objects that have non-const reads, but const writes.
//however, to avoid leaking handles, the interface is very restricted. the only
//way to write is via operator=, which requires conversion via eg copy
//constructor. example:
//struct foo {
// foo(bool value) { ... }
//};
//writeonly<foo> bar;
//bar = true;
namespace nall {
class property {
public:
template<typename T> class property_t;
template<typename C> struct property {
template<typename T> struct traits { typedef T type; };
protected:
template<typename T> T& get(property_t<T>&);
template<typename T> property_t<T>& set(property_t<T>&, const T);
public:
template<typename T>
class property_t {
public:
template<typename T> struct readonly {
const T* operator->() const { return &value; }
const T& operator()() const { return value; }
property_t() : value() {}
property_t(const T value_) : value(value_) {}
protected:
T value;
operator const T&() const { return value; }
private:
T* operator->() { return &value; }
operator T&() { return value; }
property_t& operator=(const T newValue) { value = newValue; return *this; }
friend T& property::get<T>(property_t<T>&);
friend property_t<T>& property::set<T>(property_t<T>&, const T);
const T& operator=(const T& value_) { return value = value_; }
T value;
friend class traits<C>::type;
};
template<typename T> struct writeonly {
void operator=(const T& value_) { value = value_; }
private:
const T* operator->() const { return &value; }
const T& operator()() const { return value; }
operator const T&() const { return value; }
T* operator->() { return &value; }
operator T&() { return value; }
T value;
friend class traits<C>::type;
};
template<typename T> struct readwrite {
const T* operator->() const { return &value; }
const T& operator()() const { return value; }
operator const T&() const { return value; }
T* operator->() { return &value; }
operator T&() { return value; }
const T& operator=(const T& value_) { return value = value_; }
T value;
};
};
template<typename T>
T& property::get(property::property_t<T> &p) {
return p.operator T&();
}
template<typename T>
property::property_t<T>& property::set(property::property_t<T> &p, const T value) {
return p.operator=(value);
}
}
#endif

View File

@ -1,6 +1,7 @@
#ifndef NALL_STRING_BASE_HPP
#define NALL_STRING_BASE_HPP
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -48,6 +49,8 @@ namespace nall {
class string {
public:
static string printf(const char*, ...);
inline void reserve(size_t);
inline unsigned length() const;

View File

@ -3,6 +3,15 @@
namespace nall {
inline string string::printf(const char *fmt, ...) {
static char text[4096];
va_list args;
va_start(args, fmt);
vsprintf(text, fmt, args);
va_end(args);
return text;
}
void string::reserve(size_t size_) {
if(size_ > size) {
size = size_;

View File

@ -43,6 +43,18 @@ namespace nall {
}
return result;
}
// "foo/bar.c" -> "c"
inline string extension(char const *name) {
for(signed i = strlen(name); i >= 0; i--) {
if(name[i] == '.') {
name += i + 1;
break;
}
}
string result = name;
return result;
}
}
#endif

View File

@ -1,110 +1,170 @@
/*
audio.pulseaudio (2008-10-31)
author: byuu
*/
//audio.pulseaudio (2010-01-05)
//author: RedDwarf
#include <pulse/simple.h>
#include <pulse/error.h>
#include <pulse/pulseaudio.h>
namespace ruby {
class pAudioPulseAudio {
public:
struct {
pa_simple *handle;
pa_mainloop *mainloop;
pa_context *context;
pa_stream *stream;
pa_sample_spec spec;
pa_buffer_attr buffer_attr;
bool first;
} device;
struct {
uint32_t *data;
size_t size;
unsigned offset;
} buffer;
struct {
bool synchronize;
unsigned frequency;
unsigned latency;
} settings;
bool cap(const string& name) {
if(name == Audio::Synchronize) return true;
if(name == Audio::Frequency) return true;
return false;
if(name == Audio::Latency) return true;
}
any get(const string& name) {
if(name == Audio::Synchronize) return settings.synchronize;
if(name == Audio::Frequency) return settings.frequency;
return false;
if(name == Audio::Latency) return settings.latency;
}
bool set(const string& name, const any& value) {
if(name == Audio::Frequency) {
settings.frequency = any_cast<unsigned>(value);
if(device.handle) init();
if(name == Audio::Synchronize) {
settings.synchronize = any_cast<bool>(value);
return true;
}
return false;
if(name == Audio::Frequency) {
settings.frequency = any_cast<unsigned>(value);
if(device.stream) {
pa_operation_unref(pa_stream_update_sample_rate(device.stream, settings.frequency, NULL, NULL));
}
return true;
}
if(name == Audio::Latency) {
settings.latency = any_cast<unsigned>(value);
if(device.stream) {
device.buffer_attr.tlength = pa_usec_to_bytes(settings.latency * PA_USEC_PER_MSEC, &device.spec);
pa_stream_set_buffer_attr(device.stream, &device.buffer_attr, NULL, NULL);
}
return true;
}
}
void sample(uint16_t left, uint16_t right) {
if(!device.handle) return;
pa_stream_begin_write(device.stream, (void**)&buffer.data, &buffer.size);
buffer.data[buffer.offset++] = left + (right << 16);
if(buffer.offset >= 64) {
int error;
pa_simple_write(device.handle, (const void*)buffer.data, buffer.offset * sizeof(uint32_t), &error);
buffer.offset = 0;
if((buffer.offset + 1) * pa_frame_size(&device.spec) <= buffer.size) return;
while(true) {
if(device.first) {
device.first = false;
pa_mainloop_iterate(device.mainloop, 0, NULL);
} else {
pa_mainloop_iterate(device.mainloop, 1, NULL);
}
unsigned length = pa_stream_writable_size(device.stream);
if(length >= buffer.offset * pa_frame_size(&device.spec)) break;
if(settings.synchronize == false) {
buffer.offset = 0;
return;
}
}
pa_stream_write(device.stream, (const void*)buffer.data, buffer.offset * pa_frame_size(&device.spec), NULL, 0LL, PA_SEEK_RELATIVE);
buffer.data = 0;
buffer.offset = 0;
}
void clear() {
}
bool init() {
term();
device.mainloop = pa_mainloop_new();
device.spec.format = PA_SAMPLE_S16LE;
device.context = pa_context_new(pa_mainloop_get_api(device.mainloop), "ruby::pulseaudio");
pa_context_connect(device.context, NULL, PA_CONTEXT_NOFLAGS, NULL);
pa_context_state_t cstate;
do {
pa_mainloop_iterate(device.mainloop, 1, NULL);
cstate = pa_context_get_state(device.context);
if(!PA_CONTEXT_IS_GOOD(cstate)) return false;
} while(cstate != PA_CONTEXT_READY);
device.spec.format = PA_SAMPLE_S16LE;
device.spec.channels = 2;
device.spec.rate = settings.frequency;
device.spec.rate = settings.frequency;
device.stream = pa_stream_new(device.context, "audio", &device.spec, NULL);
int error = 0;
device.handle = pa_simple_new(
0, //default server
"ruby::pulseaudio", //application name
PA_STREAM_PLAYBACK, //direction
0, //default device
"audio", //stream description
&device.spec, //sample format
0, //default channel map
0, //default buffering attributes
&error //error code
);
if(!device.handle) {
fprintf(stderr, "ruby::pulseaudio failed to initialize - %s\n", pa_strerror(error));
return false;
}
device.buffer_attr.maxlength = -1;
device.buffer_attr.tlength = pa_usec_to_bytes(settings.latency * PA_USEC_PER_MSEC, &device.spec);
device.buffer_attr.prebuf = -1;
device.buffer_attr.minreq = -1;
device.buffer_attr.fragsize = -1;
buffer.data = new uint32_t[64];
pa_stream_flags_t flags = (pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY | PA_STREAM_VARIABLE_RATE);
pa_stream_connect_playback(device.stream, NULL, &device.buffer_attr, flags, NULL, NULL);
pa_stream_state_t sstate;
do {
pa_mainloop_iterate(device.mainloop, 1, NULL);
sstate = pa_stream_get_state(device.stream);
if(!PA_STREAM_IS_GOOD(sstate)) return false;
} while(sstate != PA_STREAM_READY);
buffer.size = 960;
buffer.offset = 0;
device.first = true;
return true;
}
void term() {
if(device.handle) {
int error;
pa_simple_flush(device.handle, &error);
pa_simple_free(device.handle);
device.handle = 0;
if(buffer.data) {
pa_stream_cancel_write(device.stream);
buffer.data = 0;
}
if(buffer.data) {
delete[] buffer.data;
buffer.data = 0;
if(device.stream) {
pa_stream_disconnect(device.stream);
pa_stream_unref(device.stream);
device.stream = 0;
}
if(device.context) {
pa_context_disconnect(device.context);
pa_context_unref(device.context);
device.context = 0;
}
if(device.mainloop) {
pa_mainloop_free(device.mainloop);
device.mainloop = 0;
}
}
pAudioPulseAudio() {
device.handle = 0;
device.mainloop = 0;
device.context = 0;
device.stream = 0;
buffer.data = 0;
settings.synchronize = false;
settings.frequency = 22050;
settings.latency = 60;
}
~pAudioPulseAudio() {
@ -114,4 +174,4 @@ public:
DeclareAudio(PulseAudio)
};
}

View File

@ -0,0 +1,115 @@
//audio.pulseaudiosimple (2010-01-05)
//author: byuu
#include <pulse/simple.h>
#include <pulse/error.h>
namespace ruby {
class pAudioPulseAudioSimple {
public:
struct {
pa_simple *handle;
pa_sample_spec spec;
} device;
struct {
uint32_t *data;
unsigned offset;
} buffer;
struct {
unsigned frequency;
} settings;
bool cap(const string& name) {
if(name == Audio::Frequency) return true;
return false;
}
any get(const string& name) {
if(name == Audio::Frequency) return settings.frequency;
return false;
}
bool set(const string& name, const any& value) {
if(name == Audio::Frequency) {
settings.frequency = any_cast<unsigned>(value);
if(device.handle) init();
return true;
}
return false;
}
void sample(uint16_t left, uint16_t right) {
if(!device.handle) return;
buffer.data[buffer.offset++] = left + (right << 16);
if(buffer.offset >= 64) {
int error;
pa_simple_write(device.handle, (const void*)buffer.data, buffer.offset * sizeof(uint32_t), &error);
buffer.offset = 0;
}
}
void clear() {
}
bool init() {
term();
device.spec.format = PA_SAMPLE_S16LE;
device.spec.channels = 2;
device.spec.rate = settings.frequency;
int error = 0;
device.handle = pa_simple_new(
0, //default server
"ruby::pulseaudiosimple", //application name
PA_STREAM_PLAYBACK, //direction
0, //default device
"audio", //stream description
&device.spec, //sample format
0, //default channel map
0, //default buffering attributes
&error //error code
);
if(!device.handle) {
fprintf(stderr, "ruby::pulseaudiosimple failed to initialize - %s\n", pa_strerror(error));
return false;
}
buffer.data = new uint32_t[64];
buffer.offset = 0;
return true;
}
void term() {
if(device.handle) {
int error;
pa_simple_flush(device.handle, &error);
pa_simple_free(device.handle);
device.handle = 0;
}
if(buffer.data) {
delete[] buffer.data;
buffer.data = 0;
}
}
pAudioPulseAudioSimple() {
device.handle = 0;
buffer.data = 0;
settings.frequency = 22050;
}
~pAudioPulseAudioSimple() {
term();
}
};
DeclareAudio(PulseAudioSimple)
};

View File

@ -190,6 +190,10 @@ void AudioInterface::driver(const char *driver) {
else if(!strcmp(driver, "PulseAudio")) p = new AudioPulseAudio();
#endif
#ifdef AUDIO_PULSEAUDIOSIMPLE
else if(!strcmp(driver, "PulseAudioSimple")) p = new AudioPulseAudioSimple();
#endif
else p = new Audio();
}
@ -203,6 +207,8 @@ const char* AudioInterface::default_driver() {
return "OpenAL";
#elif defined(AUDIO_PULSEAUDIO)
return "PulseAudio";
#elif defined(AUDIO_PULSEAUDIOSIMPLE)
return "PulseAudioSimple";
#elif defined(AUDIO_AO)
return "libao";
#elif defined(AUDIO_OSS)
@ -240,6 +246,10 @@ const char* AudioInterface::driver_list() {
"PulseAudio;"
#endif
#if defined(AUDIO_PULSEAUDIOSIMPLE)
"PulseAudioSimple;"
#endif
#if defined(AUDIO_AO)
"libao;"
#endif

View File

@ -128,6 +128,10 @@
#include <ruby/audio/pulseaudio.cpp>
#endif
#ifdef AUDIO_PULSEAUDIOSIMPLE
#include <ruby/audio/pulseaudiosimple.cpp>
#endif
/* Input */
#define DeclareInput(Name) \

View File

@ -2,7 +2,7 @@
video.glx
author: byuu
license: public domain
last updated: 2009-12-08
last updated: 2010-01-05
Design notes:
SGI's GLX is the X11/Xlib interface to OpenGL.
@ -188,7 +188,6 @@ public:
settings.height = 256;
//vertical synchronization
if(!glSwapInterval) glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalEXT");
if(!glSwapInterval) glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalSGI");
if(!glSwapInterval) glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalMESA");
if( glSwapInterval) glSwapInterval(settings.synchronize);

View File

@ -110,7 +110,7 @@ public:
display = XOpenDisplay(0);
char env[512];
sprintf(env, "SDL_WINDOWID=%ld", settings.handle);
sprintf(env, "SDL_WINDOWID=%ld", (long int)settings.handle);
putenv(env);
SDL_InitSubSystem(SDL_INIT_VIDEO);

View File

@ -37,6 +37,9 @@ public:
XvImage *image;
XvFormat format;
uint32_t fourcc;
unsigned width;
unsigned height;
} device;
struct {
@ -81,11 +84,33 @@ public:
return false;
}
bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) {
settings.width = width;
settings.height = height;
void resize(unsigned width, unsigned height) {
if(device.width >= width && device.height >= height) return;
device.width = max(width, device.width);
device.height = max(height, device.height);
pitch = 1024 * 4;
XShmDetach(device.display, &device.shminfo);
shmdt(device.shminfo.shmaddr);
shmctl(device.shminfo.shmid, IPC_RMID, NULL);
XFree(device.image);
delete[] buffer;
device.image = XvShmCreateImage(device.display, device.port, device.fourcc, 0, device.width, device.height, &device.shminfo);
device.shminfo.shmid = shmget(IPC_PRIVATE, device.image->data_size, IPC_CREAT | 0777);
device.shminfo.shmaddr = device.image->data = (char*)shmat(device.shminfo.shmid, 0, 0);
device.shminfo.readOnly = false;
XShmAttach(device.display, &device.shminfo);
buffer = new uint32_t[device.width * device.height];
}
bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) {
if(width != settings.width || height != settings.height) {
resize(settings.width = width, settings.height = height);
}
pitch = device.width * 4;
return data = buffer;
}
@ -93,7 +118,7 @@ public:
}
void clear() {
memset(buffer, 0, 1024 * 1024 * sizeof(uint32_t));
memset(buffer, 0, device.width * device.height * sizeof(uint32_t));
//clear twice in case video is double buffered ...
refresh();
refresh();
@ -269,7 +294,10 @@ public:
return false;
}
device.image = XvShmCreateImage(device.display, device.port, device.fourcc, 0, 1024, 1024, &device.shminfo);
device.width = 256;
device.height = 256;
device.image = XvShmCreateImage(device.display, device.port, device.fourcc, 0, device.width, device.height, &device.shminfo);
if(!device.image) {
fprintf(stderr, "VideoXv: XShmCreateImage failed.\n");
return false;
@ -283,7 +311,7 @@ public:
return false;
}
buffer = new uint32_t[1024 * 1024];
buffer = new uint32_t[device.width * device.height];
settings.width = 256;
settings.height = 256;
init_yuv_tables();
@ -319,8 +347,8 @@ public:
for(unsigned y = 0; y < height; y++) {
memcpy(output, input, width * 4);
input += 1024;
output += 1024;
input += device.width;
output += device.width;
}
}
@ -336,8 +364,8 @@ public:
*output++ = p >> 16;
}
input += (1024 - width);
output += (1024 - width) * 3;
input += (device.width - width);
output += (device.width - width) * 3;
}
}
@ -351,8 +379,8 @@ public:
*output++ = ((p >> 8) & 0xf800) | ((p >> 5) & 0x07e0) | ((p >> 3) & 0x001f); //RGB32->RGB16
}
input += 1024 - width;
output += 1024 - width;
input += device.width - width;
output += device.width - width;
}
}
@ -366,8 +394,8 @@ public:
*output++ = ((p >> 9) & 0x7c00) | ((p >> 6) & 0x03e0) | ((p >> 3) & 0x001f); //RGB32->RGB15
}
input += 1024 - width;
output += 1024 - width;
input += device.width - width;
output += device.width - width;
}
}
@ -389,8 +417,8 @@ public:
*output++ = (v << 8) | ytable[p1];
}
input += 1024 - width;
output += 1024 - width;
input += device.width - width;
output += device.width - width;
}
}
@ -412,8 +440,8 @@ public:
*output++ = (ytable[p1] << 8) | v;
}
input += 1024 - width;
output += 1024 - width;
input += device.width - width;
output += device.width - width;
}
}

View File

@ -5,7 +5,7 @@ namespace SNES {
#if defined(DEBUGGER)
#include "debugger/debugger.cpp"
bPPUDebug ppu;
bPPUDebugger ppu;
#else
bPPU ppu;
#endif
@ -17,7 +17,9 @@ namespace SNES {
void bPPU::enter() {
while(true) {
if(scheduler.sync == Scheduler::SyncAll) scheduler.exit();
if(scheduler.sync == Scheduler::SyncAll) {
scheduler.exit(Scheduler::SynchronizeEvent);
}
//H = 0 (initialize)
scanline();

View File

@ -59,7 +59,7 @@ public:
#if defined(DEBUGGER)
#include "debugger/debugger.hpp"
extern bPPUDebug ppu;
extern bPPUDebugger ppu;
#else
extern bPPU ppu;
#endif

View File

@ -1,36 +1,290 @@
#ifdef BPPU_CPP
uint8 bPPUDebug::vram_mmio_read(uint16 addr) {
#include "render.cpp"
uint8 bPPUDebugger::vram_mmio_read(uint16 addr) {
uint8 data = bPPU::vram_mmio_read(addr);
debugger.breakpoint_test(Debugger::Breakpoint::VRAM, Debugger::Breakpoint::Read, addr, data);
return data;
}
void bPPUDebug::vram_mmio_write(uint16 addr, uint8 data) {
void bPPUDebugger::vram_mmio_write(uint16 addr, uint8 data) {
bPPU::vram_mmio_write(addr, data);
debugger.breakpoint_test(Debugger::Breakpoint::VRAM, Debugger::Breakpoint::Write, addr, data);
}
uint8 bPPUDebug::oam_mmio_read(uint16 addr) {
uint8 bPPUDebugger::oam_mmio_read(uint16 addr) {
uint8 data = bPPU::oam_mmio_read(addr);
debugger.breakpoint_test(Debugger::Breakpoint::OAM, Debugger::Breakpoint::Read, addr, data);
return data;
}
void bPPUDebug::oam_mmio_write(uint16 addr, uint8 data) {
void bPPUDebugger::oam_mmio_write(uint16 addr, uint8 data) {
bPPU::oam_mmio_write(addr, data);
debugger.breakpoint_test(Debugger::Breakpoint::OAM, Debugger::Breakpoint::Write, addr, data);
}
uint8 bPPUDebug::cgram_mmio_read(uint16 addr) {
uint8 bPPUDebugger::cgram_mmio_read(uint16 addr) {
uint8 data = bPPU::cgram_mmio_read(addr);
debugger.breakpoint_test(Debugger::Breakpoint::CGRAM, Debugger::Breakpoint::Read, addr, data);
return data;
}
void bPPUDebug::cgram_mmio_write(uint16 addr, uint8 data) {
void bPPUDebugger::cgram_mmio_write(uint16 addr, uint8 data) {
bPPU::cgram_mmio_write(addr, data);
debugger.breakpoint_test(Debugger::Breakpoint::CGRAM, Debugger::Breakpoint::Write, addr, data);
}
bPPUDebugger::bPPUDebugger() {
bg1_enabled[0] = bg1_enabled[1] = true;
bg2_enabled[0] = bg2_enabled[1] = true;
bg3_enabled[0] = bg3_enabled[1] = true;
bg4_enabled[0] = bg4_enabled[1] = true;
oam_enabled[0] = oam_enabled[1] = oam_enabled[2] = oam_enabled[3] = true;
}
//===========
//PPUDebugger
//===========
//internal
unsigned bPPUDebugger::ppu1_mdr() { return regs.ppu1_mdr; }
unsigned bPPUDebugger::ppu2_mdr() { return regs.ppu2_mdr; }
//$2100
bool bPPUDebugger::display_disable() { return regs.display_disabled; }
unsigned bPPUDebugger::display_brightness() { return regs.display_brightness; }
//$2101
unsigned bPPUDebugger::oam_base_size() { return regs.oam_basesize; }
unsigned bPPUDebugger::oam_name_select() { return regs.oam_nameselect; }
unsigned bPPUDebugger::oam_name_base_address() { return regs.oam_tdaddr; }
//$2102-$2103
unsigned bPPUDebugger::oam_base_address() { return regs.oam_baseaddr; }
bool bPPUDebugger::oam_priority() { return regs.oam_priority; }
//$2105
bool bPPUDebugger::bg1_tile_size() { return regs.bg_tilesize[BG1]; }
bool bPPUDebugger::bg2_tile_size() { return regs.bg_tilesize[BG2]; }
bool bPPUDebugger::bg3_tile_size() { return regs.bg_tilesize[BG3]; }
bool bPPUDebugger::bg4_tile_size() { return regs.bg_tilesize[BG4]; }
bool bPPUDebugger::bg3_priority() { return regs.bg3_priority; }
unsigned bPPUDebugger::bg_mode() { return regs.bg_mode; }
//$2106
unsigned bPPUDebugger::mosaic_size() { return regs.mosaic_size; }
bool bPPUDebugger::bg1_mosaic_enable() { return regs.mosaic_enabled[BG1]; }
bool bPPUDebugger::bg2_mosaic_enable() { return regs.mosaic_enabled[BG2]; }
bool bPPUDebugger::bg3_mosaic_enable() { return regs.mosaic_enabled[BG3]; }
bool bPPUDebugger::bg4_mosaic_enable() { return regs.mosaic_enabled[BG4]; }
//$2107
unsigned bPPUDebugger::bg1_screen_address() { return regs.bg_scaddr[BG1]; }
unsigned bPPUDebugger::bg1_screen_size() { return regs.bg_scsize[BG1]; }
//$2108
unsigned bPPUDebugger::bg2_screen_address() { return regs.bg_scaddr[BG2]; }
unsigned bPPUDebugger::bg2_screen_size() { return regs.bg_scsize[BG2]; }
//$2109
unsigned bPPUDebugger::bg3_screen_address() { return regs.bg_scaddr[BG3]; }
unsigned bPPUDebugger::bg3_screen_size() { return regs.bg_scsize[BG3]; }
//$210a
unsigned bPPUDebugger::bg4_screen_address() { return regs.bg_scaddr[BG4]; }
unsigned bPPUDebugger::bg4_screen_size() { return regs.bg_scsize[BG4]; }
//$210b
unsigned bPPUDebugger::bg1_name_base_address() { return regs.bg_tdaddr[BG1]; }
unsigned bPPUDebugger::bg2_name_base_address() { return regs.bg_tdaddr[BG2]; }
//$210c
unsigned bPPUDebugger::bg3_name_base_address() { return regs.bg_tdaddr[BG3]; }
unsigned bPPUDebugger::bg4_name_base_address() { return regs.bg_tdaddr[BG4]; }
//$210d
unsigned bPPUDebugger::mode7_hoffset() { return regs.m7_hofs & 0x1fff; }
unsigned bPPUDebugger::bg1_hoffset() { return regs.bg_hofs[BG1] & 0x03ff; }
//$210e
unsigned bPPUDebugger::mode7_voffset() { return regs.m7_vofs & 0x1fff; }
unsigned bPPUDebugger::bg1_voffset() { return regs.bg_vofs[BG1] & 0x03ff; }
//$210f
unsigned bPPUDebugger::bg2_hoffset() { return regs.bg_hofs[BG2] & 0x03ff; }
//$2110
unsigned bPPUDebugger::bg2_voffset() { return regs.bg_vofs[BG2] & 0x03ff; }
//$2111
unsigned bPPUDebugger::bg3_hoffset() { return regs.bg_hofs[BG3] & 0x03ff; }
//$2112
unsigned bPPUDebugger::bg3_voffset() { return regs.bg_vofs[BG3] & 0x03ff; }
//$2113
unsigned bPPUDebugger::bg4_hoffset() { return regs.bg_hofs[BG4] & 0x03ff; }
//$2114
unsigned bPPUDebugger::bg4_voffset() { return regs.bg_vofs[BG4] & 0x03ff; }
//$2115
bool bPPUDebugger::vram_increment_mode() { return regs.vram_incmode; }
unsigned bPPUDebugger::vram_increment_formation() { return regs.vram_mapping; }
unsigned bPPUDebugger::vram_increment_size() { return regs.vram_incsize; }
//$2116-$2117
unsigned bPPUDebugger::vram_address() { return regs.vram_addr; }
//$211a
unsigned bPPUDebugger::mode7_repeat() { return regs.mode7_repeat; }
bool bPPUDebugger::mode7_vflip() { return regs.mode7_vflip; }
bool bPPUDebugger::mode7_hflip() { return regs.mode7_hflip; }
//$211b
unsigned bPPUDebugger::mode7_a() { return regs.m7a; }
//$211c
unsigned bPPUDebugger::mode7_b() { return regs.m7b; }
//$211d
unsigned bPPUDebugger::mode7_c() { return regs.m7c; }
//$211e
unsigned bPPUDebugger::mode7_d() { return regs.m7d; }
//$211f
unsigned bPPUDebugger::mode7_x() { return regs.m7x; }
//$2120
unsigned bPPUDebugger::mode7_y() { return regs.m7y; }
//$2121
unsigned bPPUDebugger::cgram_address() { return regs.cgram_addr; }
//$2123
bool bPPUDebugger::bg1_window1_enable() { return regs.window1_enabled[BG1]; }
bool bPPUDebugger::bg1_window1_invert() { return regs.window1_invert [BG1]; }
bool bPPUDebugger::bg1_window2_enable() { return regs.window2_enabled[BG1]; }
bool bPPUDebugger::bg1_window2_invert() { return regs.window2_invert [BG1]; }
bool bPPUDebugger::bg2_window1_enable() { return regs.window1_enabled[BG2]; }
bool bPPUDebugger::bg2_window1_invert() { return regs.window1_invert [BG2]; }
bool bPPUDebugger::bg2_window2_enable() { return regs.window2_enabled[BG2]; }
bool bPPUDebugger::bg2_window2_invert() { return regs.window2_invert [BG2]; }
//$2124
bool bPPUDebugger::bg3_window1_enable() { return regs.window1_enabled[BG3]; }
bool bPPUDebugger::bg3_window1_invert() { return regs.window1_invert [BG3]; }
bool bPPUDebugger::bg3_window2_enable() { return regs.window2_enabled[BG3]; }
bool bPPUDebugger::bg3_window2_invert() { return regs.window2_invert [BG3]; }
bool bPPUDebugger::bg4_window1_enable() { return regs.window1_enabled[BG4]; }
bool bPPUDebugger::bg4_window1_invert() { return regs.window1_invert [BG4]; }
bool bPPUDebugger::bg4_window2_enable() { return regs.window2_enabled[BG4]; }
bool bPPUDebugger::bg4_window2_invert() { return regs.window2_invert [BG4]; }
//$2125
bool bPPUDebugger::oam_window1_enable() { return regs.window1_enabled[OAM]; }
bool bPPUDebugger::oam_window1_invert() { return regs.window1_invert [OAM]; }
bool bPPUDebugger::oam_window2_enable() { return regs.window2_enabled[OAM]; }
bool bPPUDebugger::oam_window2_invert() { return regs.window2_invert [OAM]; }
bool bPPUDebugger::color_window1_enable() { return regs.window1_enabled[COL]; }
bool bPPUDebugger::color_window1_invert() { return regs.window1_invert [COL]; }
bool bPPUDebugger::color_window2_enable() { return regs.window2_enabled[COL]; }
bool bPPUDebugger::color_window2_invert() { return regs.window2_enabled[COL]; }
//$2126
unsigned bPPUDebugger::window1_left() { return regs.window1_left; }
//$2127
unsigned bPPUDebugger::window1_right() { return regs.window1_right; }
//$2128
unsigned bPPUDebugger::window2_left() { return regs.window2_left; }
//$2129
unsigned bPPUDebugger::window2_right() { return regs.window2_right; }
//$212a
unsigned bPPUDebugger::bg1_window_mask() { return regs.window_mask[BG1]; }
unsigned bPPUDebugger::bg2_window_mask() { return regs.window_mask[BG2]; }
unsigned bPPUDebugger::bg3_window_mask() { return regs.window_mask[BG3]; }
unsigned bPPUDebugger::bg4_window_mask() { return regs.window_mask[BG4]; }
//$212b
unsigned bPPUDebugger::oam_window_mask() { return regs.window_mask[OAM]; }
unsigned bPPUDebugger::color_window_mask() { return regs.window_mask[COL]; }
//$212c
bool bPPUDebugger::bg1_mainscreen_enable() { return regs.bg_enabled[BG1]; }
bool bPPUDebugger::bg2_mainscreen_enable() { return regs.bg_enabled[BG2]; }
bool bPPUDebugger::bg3_mainscreen_enable() { return regs.bg_enabled[BG3]; }
bool bPPUDebugger::bg4_mainscreen_enable() { return regs.bg_enabled[BG4]; }
bool bPPUDebugger::oam_mainscreen_enable() { return regs.bg_enabled[OAM]; }
//$212d
bool bPPUDebugger::bg1_subscreen_enable() { return regs.bgsub_enabled[BG1]; }
bool bPPUDebugger::bg2_subscreen_enable() { return regs.bgsub_enabled[BG2]; }
bool bPPUDebugger::bg3_subscreen_enable() { return regs.bgsub_enabled[BG3]; }
bool bPPUDebugger::bg4_subscreen_enable() { return regs.bgsub_enabled[BG4]; }
bool bPPUDebugger::oam_subscreen_enable() { return regs.bgsub_enabled[OAM]; }
//$212e
bool bPPUDebugger::bg1_mainscreen_window_enable() { return regs.window_enabled[BG1]; }
bool bPPUDebugger::bg2_mainscreen_window_enable() { return regs.window_enabled[BG2]; }
bool bPPUDebugger::bg3_mainscreen_window_enable() { return regs.window_enabled[BG3]; }
bool bPPUDebugger::bg4_mainscreen_window_enable() { return regs.window_enabled[BG4]; }
bool bPPUDebugger::oam_mainscreen_window_enable() { return regs.window_enabled[OAM]; }
//$212f
bool bPPUDebugger::bg1_subscreen_window_enable() { return regs.sub_window_enabled[BG1]; }
bool bPPUDebugger::bg2_subscreen_window_enable() { return regs.sub_window_enabled[BG2]; }
bool bPPUDebugger::bg3_subscreen_window_enable() { return regs.sub_window_enabled[BG3]; }
bool bPPUDebugger::bg4_subscreen_window_enable() { return regs.sub_window_enabled[BG4]; }
bool bPPUDebugger::oam_subscreen_window_enable() { return regs.sub_window_enabled[OAM]; }
//$2130
unsigned bPPUDebugger::color_mainscreen_window_mask() { return regs.color_mask; }
unsigned bPPUDebugger::color_subscreen_window_mask() { return regs.colorsub_mask; }
bool bPPUDebugger::color_add_subtract_mode() { return regs.addsub_mode; }
bool bPPUDebugger::direct_color() { return regs.direct_color; }
//$2131
bool bPPUDebugger::color_mode() { return regs.color_mode; }
bool bPPUDebugger::color_halve() { return regs.color_halve; }
bool bPPUDebugger::bg1_color_enable() { return regs.color_enabled[BG1]; }
bool bPPUDebugger::bg2_color_enable() { return regs.color_enabled[BG2]; }
bool bPPUDebugger::bg3_color_enable() { return regs.color_enabled[BG3]; }
bool bPPUDebugger::bg4_color_enable() { return regs.color_enabled[BG4]; }
bool bPPUDebugger::oam_color_enable() { return regs.color_enabled[OAM]; }
bool bPPUDebugger::back_color_enable() { return regs.color_enabled[BACK]; }
//$2132
unsigned bPPUDebugger::color_constant_blue() { return regs.color_b; }
unsigned bPPUDebugger::color_constant_green() { return regs.color_g; }
unsigned bPPUDebugger::color_constant_red() { return regs.color_r; }
//$2133
bool bPPUDebugger::mode7_extbg() { return regs.mode7_extbg; }
bool bPPUDebugger::pseudo_hires() { return regs.pseudo_hires; }
bool bPPUDebugger::overscan() { return regs.overscan; }
bool bPPUDebugger::oam_interlace() { return regs.oam_interlace; }
bool bPPUDebugger::interlace() { return regs.interlace; }
//$213c
unsigned bPPUDebugger::hcounter() { return bPPU::hcounter(); }
//$213d
unsigned bPPUDebugger::vcounter() { return bPPU::vcounter(); }
//$213e
bool bPPUDebugger::range_over() { return regs.range_over; }
bool bPPUDebugger::time_over() { return regs.time_over; }
unsigned bPPUDebugger::ppu1_version() { return PPU::ppu1_version; }
//$213f
bool bPPUDebugger::field() { return cpu.field(); }
bool bPPUDebugger::region() { return bPPU::region; }
unsigned bPPUDebugger::ppu2_version() { return PPU::ppu2_version; }
#endif

View File

@ -1,5 +1,11 @@
class bPPUDebug : public bPPU {
class bPPUDebugger : public bPPU, public PPUDebugger {
public:
bool bg1_enabled[2];
bool bg2_enabled[2];
bool bg3_enabled[2];
bool bg4_enabled[2];
bool oam_enabled[4];
uint8 vram_mmio_read(uint16 addr);
void vram_mmio_write(uint16 addr, uint8 data);
@ -8,4 +14,259 @@ public:
uint8 cgram_mmio_read(uint16 addr);
void cgram_mmio_write(uint16 addr, uint8 data);
void render_line_mode0();
void render_line_mode1();
void render_line_mode2();
void render_line_mode3();
void render_line_mode4();
void render_line_mode5();
void render_line_mode6();
void render_line_mode7();
bPPUDebugger();
//===========
//PPUDebugger
//===========
//internal
unsigned ppu1_mdr();
unsigned ppu2_mdr();
//$2100
bool display_disable();
unsigned display_brightness();
//$2101
unsigned oam_base_size();
unsigned oam_name_select();
unsigned oam_name_base_address();
//$2102-$2103
unsigned oam_base_address();
bool oam_priority();
//$2105
bool bg1_tile_size();
bool bg2_tile_size();
bool bg3_tile_size();
bool bg4_tile_size();
bool bg3_priority();
unsigned bg_mode();
//$2106
unsigned mosaic_size();
bool bg1_mosaic_enable();
bool bg2_mosaic_enable();
bool bg3_mosaic_enable();
bool bg4_mosaic_enable();
//$2107
unsigned bg1_screen_address();
unsigned bg1_screen_size();
//$2108
unsigned bg2_screen_address();
unsigned bg2_screen_size();
//$2109
unsigned bg3_screen_address();
unsigned bg3_screen_size();
//$210a
unsigned bg4_screen_address();
unsigned bg4_screen_size();
//$210b
unsigned bg1_name_base_address();
unsigned bg2_name_base_address();
//$210c
unsigned bg3_name_base_address();
unsigned bg4_name_base_address();
//$210d
unsigned mode7_hoffset();
unsigned bg1_hoffset();
//$210e
unsigned mode7_voffset();
unsigned bg1_voffset();
//$210f
unsigned bg2_hoffset();
//$2110
unsigned bg2_voffset();
//$2111
unsigned bg3_hoffset();
//$2112
unsigned bg3_voffset();
//$2113
unsigned bg4_hoffset();
//$2114
unsigned bg4_voffset();
//$2115
bool vram_increment_mode();
unsigned vram_increment_formation();
unsigned vram_increment_size();
//$2116-$2117
unsigned vram_address();
//$211a
unsigned mode7_repeat();
bool mode7_vflip();
bool mode7_hflip();
//$211b
unsigned mode7_a();
//$211c
unsigned mode7_b();
//$211d
unsigned mode7_c();
//$211e
unsigned mode7_d();
//$211f
unsigned mode7_x();
//$2120
unsigned mode7_y();
//$2121
unsigned cgram_address();
//$2123
bool bg1_window1_enable();
bool bg1_window1_invert();
bool bg1_window2_enable();
bool bg1_window2_invert();
bool bg2_window1_enable();
bool bg2_window1_invert();
bool bg2_window2_enable();
bool bg2_window2_invert();
//$2124
bool bg3_window1_enable();
bool bg3_window1_invert();
bool bg3_window2_enable();
bool bg3_window2_invert();
bool bg4_window1_enable();
bool bg4_window1_invert();
bool bg4_window2_enable();
bool bg4_window2_invert();
//$2125
bool oam_window1_enable();
bool oam_window1_invert();
bool oam_window2_enable();
bool oam_window2_invert();
bool color_window1_enable();
bool color_window1_invert();
bool color_window2_enable();
bool color_window2_invert();
//$2126
unsigned window1_left();
//$2127
unsigned window1_right();
//$2128
unsigned window2_left();
//$2129
unsigned window2_right();
//$212a
unsigned bg1_window_mask();
unsigned bg2_window_mask();
unsigned bg3_window_mask();
unsigned bg4_window_mask();
//$212b
unsigned oam_window_mask();
unsigned color_window_mask();
//$212c
bool bg1_mainscreen_enable();
bool bg2_mainscreen_enable();
bool bg3_mainscreen_enable();
bool bg4_mainscreen_enable();
bool oam_mainscreen_enable();
//$212d
bool bg1_subscreen_enable();
bool bg2_subscreen_enable();
bool bg3_subscreen_enable();
bool bg4_subscreen_enable();
bool oam_subscreen_enable();
//$212e
bool bg1_mainscreen_window_enable();
bool bg2_mainscreen_window_enable();
bool bg3_mainscreen_window_enable();
bool bg4_mainscreen_window_enable();
bool oam_mainscreen_window_enable();
//$212f
bool bg1_subscreen_window_enable();
bool bg2_subscreen_window_enable();
bool bg3_subscreen_window_enable();
bool bg4_subscreen_window_enable();
bool oam_subscreen_window_enable();
//$2130
unsigned color_mainscreen_window_mask();
unsigned color_subscreen_window_mask();
bool color_add_subtract_mode();
bool direct_color();
//$2131
bool color_mode();
bool color_halve();
bool bg1_color_enable();
bool bg2_color_enable();
bool bg3_color_enable();
bool bg4_color_enable();
bool oam_color_enable();
bool back_color_enable();
//$2132
unsigned color_constant_blue();
unsigned color_constant_green();
unsigned color_constant_red();
//$2133
bool mode7_extbg();
bool pseudo_hires();
bool overscan();
bool oam_interlace();
bool interlace();
//$213c
unsigned hcounter();
//$213d
unsigned vcounter();
//$213e
bool range_over();
bool time_over();
unsigned ppu1_version();
//$213f
bool field();
bool region();
unsigned ppu2_version();
};

View File

@ -0,0 +1,194 @@
#ifdef BPPU_CPP
//render_line_modeN() taken from src/ppu/bppu/render/render.cpp
//modified to support layer disable; accomplished by setting priority to zero
//a priority of zero won't override the back layer, effectively nullifying it
//for speed, rendering loop is skipped entirely if all priorities are disabled
//
//note: render_line_(bg|oam|mode7) cannot be virtualized as they are templates
void bPPUDebugger::render_line_mode0() {
unsigned pri0, pri1, pri2, pri3;
pri0 = bg1_enabled[0] ? 8 : 0;
pri1 = bg1_enabled[1] ? 11 : 0;
if(pri0 | pri1) bPPU::render_line_bg<0, BG1, COLORDEPTH_4>(pri0, pri1);
pri0 = bg2_enabled[0] ? 7 : 0;
pri1 = bg2_enabled[1] ? 10 : 0;
if(pri0 | pri1) bPPU::render_line_bg<0, BG2, COLORDEPTH_4>(pri0, pri1);
pri0 = bg3_enabled[0] ? 2 : 0;
pri1 = bg3_enabled[1] ? 5 : 0;
if(pri0 | pri1) bPPU::render_line_bg<0, BG3, COLORDEPTH_4>(pri0, pri1);
pri0 = bg4_enabled[0] ? 1 : 0;
pri1 = bg4_enabled[1] ? 4 : 0;
if(pri0 | pri1) bPPU::render_line_bg<0, BG4, COLORDEPTH_4>(pri0, pri1);
pri0 = oam_enabled[0] ? 3 : 0;
pri1 = oam_enabled[1] ? 6 : 0;
pri2 = oam_enabled[2] ? 9 : 0;
pri3 = oam_enabled[3] ? 12 : 0;
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
}
void bPPUDebugger::render_line_mode1() {
unsigned pri0, pri1, pri2, pri3;
if(regs.bg3_priority) {
pri0 = bg1_enabled[0] ? 5 : 0;
pri1 = bg1_enabled[1] ? 8 : 0;
if(pri0 | pri1) bPPU::render_line_bg<1, BG1, COLORDEPTH_16>(pri0, pri1);
pri0 = bg2_enabled[0] ? 4 : 0;
pri1 = bg2_enabled[1] ? 7 : 0;
if(pri0 | pri1) bPPU::render_line_bg<1, BG2, COLORDEPTH_16>(pri0, pri1);
pri0 = bg3_enabled[0] ? 1 : 0;
pri1 = bg3_enabled[1] ? 10 : 0;
if(pri0 | pri1) bPPU::render_line_bg<1, BG3, COLORDEPTH_4>(pri0, pri1);
pri0 = oam_enabled[0] ? 2 : 0;
pri1 = oam_enabled[1] ? 3 : 0;
pri2 = oam_enabled[2] ? 6 : 0;
pri3 = oam_enabled[3] ? 9 : 0;
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
} else {
pri0 = bg1_enabled[0] ? 6 : 0;
pri1 = bg1_enabled[1] ? 9 : 0;
if(pri0 | pri1) bPPU::render_line_bg<1, BG1, COLORDEPTH_16>(pri0, pri1);
pri0 = bg2_enabled[0] ? 5 : 0;
pri1 = bg2_enabled[1] ? 8 : 0;
if(pri0 | pri1) bPPU::render_line_bg<1, BG2, COLORDEPTH_16>(pri0, pri1);
pri0 = bg3_enabled[0] ? 1 : 0;
pri1 = bg3_enabled[1] ? 3 : 0;
if(pri0 | pri1) bPPU::render_line_bg<1, BG3, COLORDEPTH_4>(pri0, pri1);
pri0 = oam_enabled[0] ? 2 : 0;
pri1 = oam_enabled[1] ? 4 : 0;
pri2 = oam_enabled[2] ? 7 : 0;
pri3 = oam_enabled[3] ? 10 : 0;
bPPU::render_line_oam(pri0, pri1, pri2, pri3);
}
}
void bPPUDebugger::render_line_mode2() {
unsigned pri0, pri1, pri2, pri3;
pri0 = bg1_enabled[0] ? 3 : 0;
pri1 = bg1_enabled[1] ? 7 : 0;
if(pri0 | pri1) bPPU::render_line_bg<2, BG1, COLORDEPTH_16>(pri0, pri1);
pri0 = bg2_enabled[0] ? 1 : 0;
pri1 = bg2_enabled[1] ? 5 : 0;
if(pri0 | pri1) bPPU::render_line_bg<2, BG2, COLORDEPTH_16>(pri0, pri1);
pri0 = oam_enabled[0] ? 2 : 0;
pri1 = oam_enabled[1] ? 4 : 0;
pri2 = oam_enabled[2] ? 6 : 0;
pri3 = oam_enabled[3] ? 8 : 0;
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
}
void bPPUDebugger::render_line_mode3() {
unsigned pri0, pri1, pri2, pri3;
pri0 = bg1_enabled[0] ? 3 : 0;
pri1 = bg1_enabled[1] ? 7 : 0;
if(pri0 | pri1) bPPU::render_line_bg<3, BG1, COLORDEPTH_256>(pri0, pri1);
pri0 = bg2_enabled[0] ? 1 : 0;
pri1 = bg2_enabled[1] ? 5 : 0;
if(pri0 | pri1) bPPU::render_line_bg<3, BG2, COLORDEPTH_16>(pri0, pri1);
pri0 = oam_enabled[0] ? 2 : 0;
pri1 = oam_enabled[1] ? 4 : 0;
pri2 = oam_enabled[2] ? 6 : 0;
pri3 = oam_enabled[3] ? 8 : 0;
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
}
void bPPUDebugger::render_line_mode4() {
unsigned pri0, pri1, pri2, pri3;
pri0 = bg1_enabled[0] ? 3 : 0;
pri1 = bg1_enabled[1] ? 7 : 0;
if(pri0 | pri1) bPPU::render_line_bg<4, BG1, COLORDEPTH_256>(pri0, pri1);
pri0 = bg2_enabled[0] ? 1 : 0;
pri1 = bg2_enabled[1] ? 5 : 0;
if(pri0 | pri1) bPPU::render_line_bg<4, BG2, COLORDEPTH_4>(pri0, pri1);
pri0 = oam_enabled[0] ? 2 : 0;
pri1 = oam_enabled[1] ? 4 : 0;
pri2 = oam_enabled[2] ? 6 : 0;
pri3 = oam_enabled[3] ? 8 : 0;
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
}
void bPPUDebugger::render_line_mode5() {
unsigned pri0, pri1, pri2, pri3;
pri0 = bg1_enabled[0] ? 3 : 0;
pri1 = bg1_enabled[1] ? 7 : 0;
if(pri0 | pri1) bPPU::render_line_bg<5, BG1, COLORDEPTH_16>(pri0, pri1);
pri0 = bg2_enabled[0] ? 1 : 0;
pri1 = bg2_enabled[1] ? 5 : 0;
if(pri0 | pri1) bPPU::render_line_bg<5, BG2, COLORDEPTH_4>(pri0, pri1);
pri0 = oam_enabled[0] ? 2 : 0;
pri1 = oam_enabled[1] ? 4 : 0;
pri2 = oam_enabled[2] ? 6 : 0;
pri3 = oam_enabled[3] ? 8 : 0;
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
}
void bPPUDebugger::render_line_mode6() {
unsigned pri0, pri1, pri2, pri3;
pri0 = bg1_enabled[0] ? 2 : 0;
pri1 = bg1_enabled[1] ? 5 : 0;
if(pri0 | pri1) bPPU::render_line_bg<6, BG1, COLORDEPTH_16>(pri0, pri1);
pri0 = oam_enabled[0] ? 1 : 0;
pri1 = oam_enabled[1] ? 3 : 0;
pri2 = oam_enabled[2] ? 4 : 0;
pri3 = oam_enabled[3] ? 6 : 0;
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
}
void bPPUDebugger::render_line_mode7() {
unsigned pri0, pri1, pri2, pri3;
if(regs.mode7_extbg == false) {
pri0 = bg1_enabled[0] ? 2 : 0;
pri1 = bg1_enabled[1] ? 2 : 0;
if(pri0 | pri1) bPPU::render_line_mode7<BG1>(pri0, pri1);
pri0 = oam_enabled[0] ? 1 : 0;
pri1 = oam_enabled[1] ? 3 : 0;
pri2 = oam_enabled[2] ? 4 : 0;
pri3 = oam_enabled[3] ? 5 : 0;
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
} else {
pri0 = bg1_enabled[0] ? 3 : 0;
pri1 = bg1_enabled[1] ? 3 : 0;
if(pri0 | pri1) bPPU::render_line_mode7<BG1>(pri0, pri1);
pri0 = bg2_enabled[0] ? 1 : 0;
pri1 = bg2_enabled[1] ? 5 : 0;
if(pri0 | pri1) bPPU::render_line_mode7<BG2>(pri0, pri1);
pri0 = oam_enabled[0] ? 2 : 0;
pri1 = oam_enabled[1] ? 4 : 0;
pri2 = oam_enabled[2] ? 6 : 0;
pri3 = oam_enabled[3] ? 7 : 0;
bPPU::render_line_oam(pri0, pri1, pri2, pri3);
}
}
#endif

View File

@ -55,10 +55,6 @@ template<unsigned mode, unsigned bg, unsigned color_depth>
void bPPU::render_line_bg(uint8 pri0_pos, uint8 pri1_pos) {
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false) return;
if(render_enabled(bg, 0) == false) pri0_pos = 0;
if(render_enabled(bg, 1) == false) pri1_pos = 0;
if(pri0_pos == 0 && pri1_pos == 0) return;
const bool bg_enabled = regs.bg_enabled[bg];
const bool bgsub_enabled = regs.bgsub_enabled[bg];

View File

@ -16,10 +16,6 @@ template<unsigned bg>
void bPPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) {
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false) return;
if(render_enabled(bg, 0) == false) pri0_pos = 0;
if(render_enabled(bg, 1) == false) pri1_pos = 1;
if(pri0_pos == 0 && pri1_pos == 0) return;
int32 px, py;
int32 tx, ty, tile, palette;

View File

@ -189,12 +189,6 @@ void bPPU::render_line_oam_rto() {
void bPPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
if(regs.bg_enabled[OAM] == false && regs.bgsub_enabled[OAM] == false) return;
if(render_enabled(OAM, 0) == false) pri0_pos = 0;
if(render_enabled(OAM, 1) == false) pri1_pos = 0;
if(render_enabled(OAM, 2) == false) pri2_pos = 0;
if(render_enabled(OAM, 3) == false) pri3_pos = 0;
if(pri0_pos == 0 && pri1_pos == 0 && pri2_pos == 0 && pri3_pos == 0) return;
for(unsigned s = 0; s < 34; s++) {
if(oam_tilelist[s].tile == 0xffff) continue;
render_oam_tile(s);

View File

@ -8,17 +8,6 @@
#include "addsub.cpp"
#include "line.cpp"
bool bPPU::render_enabled(unsigned bg, unsigned pri) const {
switch(bg) {
case BG1: return config.ppu.bg1_enabled[pri];
case BG2: return config.ppu.bg2_enabled[pri];
case BG3: return config.ppu.bg3_enabled[pri];
case BG4: return config.ppu.bg4_enabled[pri];
case OAM: return config.ppu.oam_enabled[pri];
}
return true;
}
//Mode 0: ->
// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
// BG4B, BG3B, OAM0, BG4A, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3
@ -41,12 +30,12 @@ void bPPU::render_line_mode1() {
if(regs.bg3_priority) {
render_line_bg<1, BG1, COLORDEPTH_16>(5, 8);
render_line_bg<1, BG2, COLORDEPTH_16>(4, 7);
render_line_bg<1, BG3, COLORDEPTH_4 >( 1, 10);
render_line_bg<1, BG3, COLORDEPTH_4 >(1, 10);
render_line_oam(2, 3, 6, 9);
} else {
render_line_bg<1, BG1, COLORDEPTH_16>(6, 9);
render_line_bg<1, BG2, COLORDEPTH_16>(5, 8);
render_line_bg<1, BG3, COLORDEPTH_4 >( 1, 3);
render_line_bg<1, BG3, COLORDEPTH_4 >(1, 3);
render_line_oam(2, 4, 7, 10);
}
}

View File

@ -1,14 +1,12 @@
//render.cpp
bool render_enabled(unsigned bg, unsigned pri) const;
inline void render_line_mode0();
inline void render_line_mode1();
inline void render_line_mode2();
inline void render_line_mode3();
inline void render_line_mode4();
inline void render_line_mode5();
inline void render_line_mode6();
inline void render_line_mode7();
debugvirtual inline void render_line_mode0();
debugvirtual inline void render_line_mode1();
debugvirtual inline void render_line_mode2();
debugvirtual inline void render_line_mode3();
debugvirtual inline void render_line_mode4();
debugvirtual inline void render_line_mode5();
debugvirtual inline void render_line_mode6();
debugvirtual inline void render_line_mode7();
//cache.cpp
enum { COLORDEPTH_4 = 0, COLORDEPTH_16 = 1, COLORDEPTH_256 = 2 };

305
src/ppu/ppu-debugger.cpp Normal file
View File

@ -0,0 +1,305 @@
#ifdef PPU_CPP
bool PPUDebugger::property(unsigned id, string &name, string &value) {
unsigned n = 0;
//internal
if(id == n++) { name = "S-PPU1 MDR"; value = string::printf("0x%.2x", ppu1_mdr()); return true; }
if(id == n++) { name = "S-PPU2 MDR"; value = string::printf("0x%.2x", ppu2_mdr()); return true; }
//$2100
if(id == n++) { name = "$2100"; value = ""; return true; }
if(id == n++) { name = "Display Disable"; value = display_disable(); return true; }
if(id == n++) { name = "Display Brightness"; value = display_brightness(); return true; }
//$2101
if(id == n++) { name = "$2101"; value = ""; return true; }
if(id == n++) { name = "OAM Base Size"; value = oam_base_size(); return true; }
if(id == n++) { name = "OAM Name Select"; value = oam_name_select(); return true; }
if(id == n++) { name = "OAM Name Base Address"; value = string::printf("0x%.4x", oam_name_base_address()); return true; }
//$2102-$2103
if(id == n++) { name = "$2102-$2103"; value = ""; return true; }
if(id == n++) { name = "OAM Base Address"; value = string::printf("0x%.4x", oam_base_address()); return true; }
if(id == n++) { name = "OAM Priority"; value = oam_priority(); return true; }
//$2105
if(id == n++) { name = "$2105"; value = ""; return true; }
if(id == n++) { name = "BG1 Tile Size"; value = bg1_tile_size() ? "16x16" : "8x8"; return true; }
if(id == n++) { name = "BG2 Tile Size"; value = bg2_tile_size() ? "16x16" : "8x8"; return true; }
if(id == n++) { name = "BG3 Tile Size"; value = bg3_tile_size() ? "16x16" : "8x8"; return true; }
if(id == n++) { name = "BG4 Tile Size"; value = bg4_tile_size() ? "16x16" : "8x8"; return true; }
if(id == n++) { name = "BG3 Priority"; value = bg3_priority(); return true; }
if(id == n++) { name = "BG Mode"; value = bg_mode(); return true; }
//$2106
if(id == n++) { name = "$2106"; value = ""; return true; }
if(id == n++) { name = "Mosaic Size"; value = mosaic_size(); return true; }
if(id == n++) { name = "BG1 Mosaic Enable"; value = bg1_mosaic_enable(); return true; }
if(id == n++) { name = "BG2 Mosaic Enable"; value = bg2_mosaic_enable(); return true; }
if(id == n++) { name = "BG3 Mosaic Enable"; value = bg3_mosaic_enable(); return true; }
if(id == n++) { name = "BG4 Mosaic Enable"; value = bg4_mosaic_enable(); return true; }
static char screen_size[4][8] = { "32x32", "32x64", "64x32", "64x64" };
//$2107
if(id == n++) { name = "$2107"; value = ""; return true; }
if(id == n++) { name = "BG1 Screen Address"; value = string::printf("0x%.4x", bg1_screen_address()); return true; }
if(id == n++) { name = "BG1 Screen Size"; value = screen_size[bg1_screen_size()]; return true; }
//$2108
if(id == n++) { name = "$2108"; value = ""; return true; }
if(id == n++) { name = "BG2 Screen Address"; value = string::printf("0x%.4x", bg2_screen_address()); return true; }
if(id == n++) { name = "BG2 Screen Size"; value = screen_size[bg2_screen_size()]; return true; }
//$2109
if(id == n++) { name = "$2109"; value = ""; return true; }
if(id == n++) { name = "BG3 Screen Address"; value = string::printf("0x%.4x", bg3_screen_address()); return true; }
if(id == n++) { name = "BG3 Screen Size"; value = screen_size[bg3_screen_size()]; return true; }
//$210a
if(id == n++) { name = "$210a"; value = ""; return true; }
if(id == n++) { name = "BG4 Screen Address"; value = string::printf("0x%.4x", bg4_screen_address()); return true; }
if(id == n++) { name = "BG4 Screen Size"; value = screen_size[bg4_screen_size()]; return true; }
//$210b
if(id == n++) { name = "$210b"; value = ""; return true; }
if(id == n++) { name = "BG1 Name Base Address"; value = string::printf("0x%.4x", bg1_name_base_address()); return true; }
if(id == n++) { name = "BG2 Name Base Address"; value = string::printf("0x%.4x", bg2_name_base_address()); return true; }
//$210c
if(id == n++) { name = "$210c"; value = ""; return true; }
if(id == n++) { name = "BG3 Name Base Address"; value = string::printf("0x%.4x", bg3_name_base_address()); return true; }
if(id == n++) { name = "BG4 Name Base Address"; value = string::printf("0x%.4x", bg4_name_base_address()); return true; }
//$210d
if(id == n++) { name = "$210d"; value = ""; return true; }
if(id == n++) { name = "Mode 7 Scroll H-offset"; value = mode7_hoffset(); return true; }
if(id == n++) { name = "BG1 Scroll H-offset"; value = bg1_hoffset(); return true; }
//$210e
if(id == n++) { name = "$210e"; value = ""; return true; }
if(id == n++) { name = "Mode 7 Scroll V-offset"; value = mode7_voffset(); return true; }
if(id == n++) { name = "BG1 Scroll V-offset"; value = bg1_voffset(); return true; }
//$210f
if(id == n++) { name = "$210f"; value = ""; return true; }
if(id == n++) { name = "BG2 Scroll H-offset"; value = bg2_hoffset(); return true; }
//$2110
if(id == n++) { name = "$2110"; value = ""; return true; }
if(id == n++) { name = "BG2 Scroll V-offset"; value = bg2_voffset(); return true; }
//$2111
if(id == n++) { name = "$2111"; value = ""; return true; }
if(id == n++) { name = "BG3 Scroll H-offset"; value = bg3_hoffset(); return true; }
//$2112
if(id == n++) { name = "$2112"; value = ""; return true; }
if(id == n++) { name = "BG3 Scroll V-offset"; value = bg3_voffset(); return true; }
//$2113
if(id == n++) { name = "$2113"; value = ""; return true; }
if(id == n++) { name = "BG4 Scroll H-offset"; value = bg4_hoffset(); return true; }
//$2114
if(id == n++) { name = "$2114"; value = ""; return true; }
if(id == n++) { name = "BG4 Scroll V-offset"; value = bg4_voffset(); return true; }
//$2115
if(id == n++) { name = "$2115"; value = ""; return true; }
if(id == n++) { name = "VRAM Increment Mode"; value = (unsigned)vram_increment_mode(); return true; }
if(id == n++) { name = "VRAM Increment Formation"; value = vram_increment_formation(); return true; }
if(id == n++) { name = "VRAM Increment Size"; value = vram_increment_size(); return true; }
//$2116-$2117
if(id == n++) { name = "$2116-$2117"; value = ""; return true; }
if(id == n++) { name = "VRAM Address"; value = string::printf("0x%.4x", vram_address()); return true; }
//$211a
if(id == n++) { name = "$211a"; value = ""; return true; }
if(id == n++) { name = "Mode 7 Repeat"; value = mode7_repeat(); return true; }
if(id == n++) { name = "Mode 7 V-flip"; value = mode7_vflip(); return true; }
if(id == n++) { name = "Mode 7 H-flip"; value = mode7_hflip(); return true; }
//$211b
if(id == n++) { name = "$211b"; value = ""; return true; }
if(id == n++) { name = "Mode 7 A"; value = mode7_a(); return true; }
//$211c
if(id == n++) { name = "$211c"; value = ""; return true; }
if(id == n++) { name = "Mode 7 B"; value = mode7_b(); return true; }
//$211d
if(id == n++) { name = "$211d"; value = ""; return true; }
if(id == n++) { name = "Mode 7 C"; value = mode7_c(); return true; }
//$211e
if(id == n++) { name = "$211e"; value = ""; return true; }
if(id == n++) { name = "Mode 7 D"; value = mode7_d(); return true; }
//$211f
if(id == n++) { name = "$211f"; value = ""; return true; }
if(id == n++) { name = "Mode 7 X"; value = mode7_x(); return true; }
//$2120
if(id == n++) { name = "$2120"; value = ""; return true; }
if(id == n++) { name = "Mode 7 Y"; value = mode7_y(); return true; }
//$2121
if(id == n++) { name = "$2121"; value = ""; return true; }
if(id == n++) { name = "CGRAM Address"; value = string::printf("0x%.4x", cgram_address()); return true; }
//$2123
if(id == n++) { name = "$2123"; value = ""; return true; }
if(id == n++) { name = "BG1 Window 1 Enable"; value = bg1_window1_enable(); return true; }
if(id == n++) { name = "BG1 Window 1 Invert"; value = bg1_window1_invert(); return true; }
if(id == n++) { name = "BG1 Window 2 Enable"; value = bg1_window2_enable(); return true; }
if(id == n++) { name = "BG1 Window 2 Invert"; value = bg1_window2_invert(); return true; }
if(id == n++) { name = "BG2 Window 1 Enable"; value = bg2_window1_enable(); return true; }
if(id == n++) { name = "BG2 Window 1 Invert"; value = bg2_window1_invert(); return true; }
if(id == n++) { name = "BG2 Window 2 Enable"; value = bg2_window2_enable(); return true; }
if(id == n++) { name = "BG2 Window 2 Invert"; value = bg2_window2_invert(); return true; }
//$2124
if(id == n++) { name = "$2124"; value = ""; return true; }
if(id == n++) { name = "BG3 Window 1 Enable"; value = bg3_window1_enable(); return true; }
if(id == n++) { name = "BG3 Window 1 Invert"; value = bg3_window1_invert(); return true; }
if(id == n++) { name = "BG3 Window 2 Enable"; value = bg3_window2_enable(); return true; }
if(id == n++) { name = "BG3 Window 2 Invert"; value = bg3_window2_invert(); return true; }
if(id == n++) { name = "BG4 Window 1 Enable"; value = bg4_window1_enable(); return true; }
if(id == n++) { name = "BG4 Window 1 Invert"; value = bg4_window1_invert(); return true; }
if(id == n++) { name = "BG4 Window 2 Enable"; value = bg4_window2_enable(); return true; }
if(id == n++) { name = "BG4 Window 2 Invert"; value = bg4_window2_invert(); return true; }
//$2125
if(id == n++) { name = "$2125"; value = ""; return true; }
if(id == n++) { name = "OAM Window 1 Enable"; value = oam_window1_enable(); return true; }
if(id == n++) { name = "OAM Window 1 Invert"; value = oam_window1_invert(); return true; }
if(id == n++) { name = "OAM Window 2 Enable"; value = oam_window2_enable(); return true; }
if(id == n++) { name = "OAM Window 2 Invert"; value = oam_window2_invert(); return true; }
if(id == n++) { name = "Color Window 1 Enable"; value = color_window1_enable(); return true; }
if(id == n++) { name = "Color Window 1 Invert"; value = color_window1_invert(); return true; }
if(id == n++) { name = "Color Window 2 Enable"; value = color_window2_enable(); return true; }
if(id == n++) { name = "Color Window 2 Invert"; value = color_window2_invert(); return true; }
//$2126
if(id == n++) { name = "$2126"; value = ""; return true; }
if(id == n++) { name = "Window 1 Left"; value = window1_left(); return true; }
//$2127
if(id == n++) { name = "$2127"; value = ""; return true; }
if(id == n++) { name = "Window 1 Right"; value = window1_right(); return true; }
//$2128
if(id == n++) { name = "$2128"; value = ""; return true; }
if(id == n++) { name = "Window 2 Left"; value = window2_left(); return true; }
//$2129
if(id == n++) { name = "$2129"; value = ""; return true; }
if(id == n++) { name = "Window 2 Right"; value = window2_right(); return true; }
static char window_mask_mode[4][8] = { "OR", "AND", "XOR", "XNOR" };
//$212a
if(id == n++) { name = "$212a"; value = ""; return true; }
if(id == n++) { name = "BG1 Window Mask"; value = window_mask_mode[bg1_window_mask()]; return true; }
if(id == n++) { name = "BG2 Window Mask"; value = window_mask_mode[bg2_window_mask()]; return true; }
if(id == n++) { name = "BG3 Window Mask"; value = window_mask_mode[bg3_window_mask()]; return true; }
if(id == n++) { name = "BG4 Window Mask"; value = window_mask_mode[bg4_window_mask()]; return true; }
//$212b
if(id == n++) { name = "$212b"; value = ""; return true; }
if(id == n++) { name = "OAM Window Mask"; value = window_mask_mode[oam_window_mask()]; return true; }
if(id == n++) { name = "Color Window Mask"; value = window_mask_mode[color_window_mask()]; return true; }
//$212c
if(id == n++) { name = "$212c"; value = ""; return true; }
if(id == n++) { name = "BG1 Mainscreen Enable"; value = bg1_mainscreen_enable(); return true; }
if(id == n++) { name = "BG2 Mainscreen Enable"; value = bg2_mainscreen_enable(); return true; }
if(id == n++) { name = "BG3 Mainscreen Enable"; value = bg3_mainscreen_enable(); return true; }
if(id == n++) { name = "BG4 Mainscreen Enable"; value = bg4_mainscreen_enable(); return true; }
if(id == n++) { name = "OAM Mainscreen Enable"; value = oam_mainscreen_enable(); return true; }
//$212d
if(id == n++) { name = "$212d"; value = ""; return true; }
if(id == n++) { name = "BG1 Subscreen Enable"; value = bg1_subscreen_enable(); return true; }
if(id == n++) { name = "BG2 Subscreen Enable"; value = bg2_subscreen_enable(); return true; }
if(id == n++) { name = "BG3 Subscreen Enable"; value = bg3_subscreen_enable(); return true; }
if(id == n++) { name = "BG4 Subscreen Enable"; value = bg4_subscreen_enable(); return true; }
if(id == n++) { name = "OAM Subscreen Enable"; value = oam_subscreen_enable(); return true; }
//$212e
if(id == n++) { name = "$212e"; value = ""; return true; }
if(id == n++) { name = "BG1 Mainscreen Window Enable"; value = bg1_mainscreen_window_enable(); return true; }
if(id == n++) { name = "BG2 Mainscreen Window Enable"; value = bg2_mainscreen_window_enable(); return true; }
if(id == n++) { name = "BG3 Mainscreen Window Enable"; value = bg3_mainscreen_window_enable(); return true; }
if(id == n++) { name = "BG4 Mainscreen Window Enable"; value = bg4_mainscreen_window_enable(); return true; }
if(id == n++) { name = "OAM Mainscreen Window Enable"; value = oam_mainscreen_window_enable(); return true; }
//$212f
if(id == n++) { name = "$212f"; value = ""; return true; }
if(id == n++) { name = "BG1 Subscreen Window Enable"; value = bg1_subscreen_window_enable(); return true; }
if(id == n++) { name = "BG2 Subscreen Window Enable"; value = bg2_subscreen_window_enable(); return true; }
if(id == n++) { name = "BG3 Subscreen Window Enable"; value = bg3_subscreen_window_enable(); return true; }
if(id == n++) { name = "BG4 Subscreen Window Enable"; value = bg4_subscreen_window_enable(); return true; }
if(id == n++) { name = "OAM Subscreen Window Enable"; value = oam_subscreen_window_enable(); return true; }
static char color_window_mask_mode[4][32] = { "Always", "Never", "Inside Window Only", "Outside Window Only" };
//$2130
if(id == n++) { name = "$2130"; value = ""; return true; }
if(id == n++) { name = "Color Mainscreen Window Mask"; value = color_window_mask_mode[color_mainscreen_window_mask()]; return true; }
if(id == n++) { name = "Color Subscreen Window Mask"; value = color_window_mask_mode[color_subscreen_window_mask()]; return true; }
if(id == n++) { name = "Color Add/Subtract Mode"; value = !color_add_subtract_mode() ? "Fixed Color" : "Subscreen"; return true; }
if(id == n++) { name = "Direct Color"; value = direct_color(); return true; }
//$2131
if(id == n++) { name = "$2131"; value = ""; return true; }
if(id == n++) { name = "Color Mode"; value = !color_mode() ? "Add" : "Subtract"; return true; }
if(id == n++) { name = "Color Halve"; value = color_halve(); return true; }
if(id == n++) { name = "BG1 Color Enable"; value = bg1_color_enable(); return true; }
if(id == n++) { name = "BG2 Color Enable"; value = bg2_color_enable(); return true; }
if(id == n++) { name = "BG3 Color Enable"; value = bg3_color_enable(); return true; }
if(id == n++) { name = "BG4 Color Enable"; value = bg4_color_enable(); return true; }
if(id == n++) { name = "OAM Color Enable"; value = oam_color_enable(); return true; }
if(id == n++) { name = "Back Color Enable"; value = back_color_enable(); return true; }
//$2132
if(id == n++) { name = "$2132"; value = ""; return true; }
if(id == n++) { name = "Color Constant - Blue"; value = color_constant_blue(); return true; }
if(id == n++) { name = "Color Constant - Green"; value = color_constant_green(); return true; }
if(id == n++) { name = "Color Constant - Red"; value = color_constant_red(); return true; }
//$2133
if(id == n++) { name = "$2133"; value = ""; return true; }
if(id == n++) { name = "Mode 7 EXTBG"; value = mode7_extbg(); return true; }
if(id == n++) { name = "Pseudo Hires"; value = pseudo_hires(); return true; }
if(id == n++) { name = "Overscan"; value = overscan(); return true; }
if(id == n++) { name = "OAM Interlace"; value = oam_interlace(); return true; }
if(id == n++) { name = "Interlace"; value = interlace(); return true; }
//$213c
if(id == n++) { name = "$213c"; value = ""; return true; }
if(id == n++) { name = "H-counter"; value = hcounter(); return true; }
//$213d
if(id == n++) { name = "$213d"; value = ""; return true; }
if(id == n++) { name = "V-counter"; value = vcounter(); return true; }
//$213e
if(id == n++) { name = "$213e"; value = ""; return true; }
if(id == n++) { name = "Range Over"; value = range_over(); return true; }
if(id == n++) { name = "Time Over"; value = time_over(); return true; }
if(id == n++) { name = "S-PPU1 Version"; value = ppu1_version(); return true; }
//$213f
if(id == n++) { name = "$213f"; value = ""; return true; }
if(id == n++) { name = "Field"; value = field(); return true; }
if(id == n++) { name = "Region"; value = !region() ? "NTSC" : "PAL"; return true; }
if(id == n++) { name = "S-PPU2 Version"; value = ppu2_version(); return true; }
return false;
}
#endif

243
src/ppu/ppu-debugger.hpp Normal file
View File

@ -0,0 +1,243 @@
struct PPUDebugger : ChipDebugger {
bool property(unsigned id, string &name, string &value);
//internal
virtual unsigned ppu1_mdr() { return 0; }
virtual unsigned ppu2_mdr() { return 0; }
//$2100
virtual bool display_disable() { return 0; }
virtual unsigned display_brightness() { return 0; }
//$2101
virtual unsigned oam_base_size() { return 0; }
virtual unsigned oam_name_select() { return 0; }
virtual unsigned oam_name_base_address() { return 0; }
//$2102-$2103
virtual unsigned oam_base_address() { return 0; }
virtual bool oam_priority() { return 0; }
//$2105
virtual bool bg1_tile_size() { return 0; }
virtual bool bg2_tile_size() { return 0; }
virtual bool bg3_tile_size() { return 0; }
virtual bool bg4_tile_size() { return 0; }
virtual bool bg3_priority() { return 0; }
virtual unsigned bg_mode() { return 0; }
//$2106
virtual unsigned mosaic_size() { return 0; }
virtual bool bg1_mosaic_enable() { return 0; }
virtual bool bg2_mosaic_enable() { return 0; }
virtual bool bg3_mosaic_enable() { return 0; }
virtual bool bg4_mosaic_enable() { return 0; }
//$2107
virtual unsigned bg1_screen_address() { return 0; }
virtual unsigned bg1_screen_size() { return 0; }
//$2108
virtual unsigned bg2_screen_address() { return 0; }
virtual unsigned bg2_screen_size() { return 0; }
//$2109
virtual unsigned bg3_screen_address() { return 0; }
virtual unsigned bg3_screen_size() { return 0; }
//$210a
virtual unsigned bg4_screen_address() { return 0; }
virtual unsigned bg4_screen_size() { return 0; }
//$210b
virtual unsigned bg1_name_base_address() { return 0; }
virtual unsigned bg2_name_base_address() { return 0; }
//$210c
virtual unsigned bg3_name_base_address() { return 0; }
virtual unsigned bg4_name_base_address() { return 0; }
//$210d
virtual unsigned mode7_hoffset() { return 0; }
virtual unsigned bg1_hoffset() { return 0; }
//$210e
virtual unsigned mode7_voffset() { return 0; }
virtual unsigned bg1_voffset() { return 0; }
//$210f
virtual unsigned bg2_hoffset() { return 0; }
//$2110
virtual unsigned bg2_voffset() { return 0; }
//$2111
virtual unsigned bg3_hoffset() { return 0; }
//$2112
virtual unsigned bg3_voffset() { return 0; }
//$2113
virtual unsigned bg4_hoffset() { return 0; }
//$2114
virtual unsigned bg4_voffset() { return 0; }
//$2115
virtual bool vram_increment_mode() { return 0; }
virtual unsigned vram_increment_formation() { return 0; }
virtual unsigned vram_increment_size() { return 0; }
//$2116-$2117
virtual unsigned vram_address() { return 0; }
//$211a
virtual unsigned mode7_repeat() { return 0; }
virtual bool mode7_vflip() { return 0; }
virtual bool mode7_hflip() { return 0; }
//$211b
virtual unsigned mode7_a() { return 0; }
//$211c
virtual unsigned mode7_b() { return 0; }
//$211d
virtual unsigned mode7_c() { return 0; }
//$211e
virtual unsigned mode7_d() { return 0; }
//$211f
virtual unsigned mode7_x() { return 0; }
//$2120
virtual unsigned mode7_y() { return 0; }
//$2121
virtual unsigned cgram_address() { return 0; }
//$2123
virtual bool bg1_window1_enable() { return 0; }
virtual bool bg1_window1_invert() { return 0; }
virtual bool bg1_window2_enable() { return 0; }
virtual bool bg1_window2_invert() { return 0; }
virtual bool bg2_window1_enable() { return 0; }
virtual bool bg2_window1_invert() { return 0; }
virtual bool bg2_window2_enable() { return 0; }
virtual bool bg2_window2_invert() { return 0; }
//$2124
virtual bool bg3_window1_enable() { return 0; }
virtual bool bg3_window1_invert() { return 0; }
virtual bool bg3_window2_enable() { return 0; }
virtual bool bg3_window2_invert() { return 0; }
virtual bool bg4_window1_enable() { return 0; }
virtual bool bg4_window1_invert() { return 0; }
virtual bool bg4_window2_enable() { return 0; }
virtual bool bg4_window2_invert() { return 0; }
//$2125
virtual bool oam_window1_enable() { return 0; }
virtual bool oam_window1_invert() { return 0; }
virtual bool oam_window2_enable() { return 0; }
virtual bool oam_window2_invert() { return 0; }
virtual bool color_window1_enable() { return 0; }
virtual bool color_window1_invert() { return 0; }
virtual bool color_window2_enable() { return 0; }
virtual bool color_window2_invert() { return 0; }
//$2126
virtual unsigned window1_left() { return 0; }
//$2127
virtual unsigned window1_right() { return 0; }
//$2128
virtual unsigned window2_left() { return 0; }
//$2129
virtual unsigned window2_right() { return 0; }
//$212a
virtual unsigned bg1_window_mask() { return 0; }
virtual unsigned bg2_window_mask() { return 0; }
virtual unsigned bg3_window_mask() { return 0; }
virtual unsigned bg4_window_mask() { return 0; }
//$212b
virtual unsigned oam_window_mask() { return 0; }
virtual unsigned color_window_mask() { return 0; }
//$212c
virtual bool bg1_mainscreen_enable() { return 0; }
virtual bool bg2_mainscreen_enable() { return 0; }
virtual bool bg3_mainscreen_enable() { return 0; }
virtual bool bg4_mainscreen_enable() { return 0; }
virtual bool oam_mainscreen_enable() { return 0; }
//$212d
virtual bool bg1_subscreen_enable() { return 0; }
virtual bool bg2_subscreen_enable() { return 0; }
virtual bool bg3_subscreen_enable() { return 0; }
virtual bool bg4_subscreen_enable() { return 0; }
virtual bool oam_subscreen_enable() { return 0; }
//$212e
virtual bool bg1_mainscreen_window_enable() { return 0; }
virtual bool bg2_mainscreen_window_enable() { return 0; }
virtual bool bg3_mainscreen_window_enable() { return 0; }
virtual bool bg4_mainscreen_window_enable() { return 0; }
virtual bool oam_mainscreen_window_enable() { return 0; }
//$212f
virtual bool bg1_subscreen_window_enable() { return 0; }
virtual bool bg2_subscreen_window_enable() { return 0; }
virtual bool bg3_subscreen_window_enable() { return 0; }
virtual bool bg4_subscreen_window_enable() { return 0; }
virtual bool oam_subscreen_window_enable() { return 0; }
//$2130
virtual unsigned color_mainscreen_window_mask() { return 0; }
virtual unsigned color_subscreen_window_mask() { return 0; }
virtual bool color_add_subtract_mode() { return 0; }
virtual bool direct_color() { return 0; }
//$2131
virtual bool color_mode() { return 0; }
virtual bool color_halve() { return 0; }
virtual bool bg1_color_enable() { return 0; }
virtual bool bg2_color_enable() { return 0; }
virtual bool bg3_color_enable() { return 0; }
virtual bool bg4_color_enable() { return 0; }
virtual bool oam_color_enable() { return 0; }
virtual bool back_color_enable() { return 0; }
//$2132
virtual unsigned color_constant_blue() { return 0; }
virtual unsigned color_constant_green() { return 0; }
virtual unsigned color_constant_red() { return 0; }
//$2133
virtual bool mode7_extbg() { return 0; }
virtual bool pseudo_hires() { return 0; }
virtual bool overscan() { return 0; }
virtual bool oam_interlace() { return 0; }
virtual bool interlace() { return 0; }
//$213c
virtual unsigned hcounter() { return 0; }
//$213d
virtual unsigned vcounter() { return 0; }
//$213e
virtual bool range_over() { return 0; }
virtual bool time_over() { return 0; }
virtual unsigned ppu1_version() { return 0; }
//$213f
virtual bool field() { return 0; }
virtual bool region() { return 0; }
virtual unsigned ppu2_version() { return 0; }
};

View File

@ -3,6 +3,10 @@
#define PPU_CPP
namespace SNES {
#if defined(DEBUGGER)
#include "ppu-debugger.cpp"
#endif
#include "serialization.cpp"
void PPU::enable_renderer(bool r) { status.render_output = r; }

View File

@ -1,3 +1,7 @@
#if defined(DEBUGGER)
#include "ppu-debugger.hpp"
#endif
//PPUcounter emulates the H/V latch counters of the S-PPU2.
//
//real hardware has the S-CPU maintain its own copy of these counters that are

View File

@ -5,7 +5,7 @@ namespace SNES {
#include "serialization.cpp"
#include "algorithms.cpp"
#include "disasm/disasm.cpp"
#include "disassembler/disassembler.cpp"
#define A 0
#define X 1

View File

@ -2,7 +2,7 @@ class SMPcore {
public:
#include "registers.hpp"
#include "memory.hpp"
#include "disasm/disasm.hpp"
#include "disassembler/disassembler.hpp"
regs_t regs;
uint16 dp, sp, rd, wr, bit, ya;

View File

@ -1,3 +1,5 @@
#ifdef SMPCORE_CPP
void SMPcore::op_nop() {
op_io();
}
@ -142,3 +144,5 @@ void SMPcore::op_div_ya_x() {
regs.p.n = !!(regs.a & 0x80);
regs.p.z = (regs.a == 0);
}
#endif

View File

@ -1,3 +1,5 @@
#ifdef SMPCORE_CPP
template<int to, int from> void SMPcore::op_mov_reg_reg() {
op_io();
regs.r[to] = regs.r[from];
@ -194,3 +196,5 @@ void SMPcore::op_mov1_bit_c() {
op_io();
op_writeaddr(dp, rd);
}
#endif

View File

@ -1,3 +1,5 @@
#ifdef SMPCORE_CPP
void SMPcore::op_bra() {
rd = op_readpc();
op_io();
@ -146,3 +148,5 @@ void SMPcore::op_reti() {
op_io();
regs.pc = rd;
}
#endif

View File

@ -1,3 +1,5 @@
#ifdef SMPCORE_CPP
template<uint8 (SMPcore::*op)(uint8, uint8), int n>
void SMPcore::op_read_reg_const() {
rd = op_readpc();
@ -148,3 +150,5 @@ template<int op> void SMPcore::op_or1_bit() {
op_io();
regs.p.c = regs.p.c | ((bool)(rd & (1 << bit)) ^ op);
}
#endif

View File

@ -1,3 +1,5 @@
#ifdef SMPCORE_CPP
template<uint8 (SMPcore::*op)(uint8), int n>
void SMPcore::op_adjust_reg() {
op_io();
@ -52,3 +54,5 @@ void SMPcore::op_adjustw_dp() {
regs.p.n = (rd & 0x8000);
regs.p.z = (rd == 0);
}
#endif

View File

@ -1,43 +1,43 @@
#ifdef SSMP_CPP
void sSMPDebug::op_step() {
void sSMPDebugger::op_step() {
bool break_event = false;
if(debugger.step_smp) {
debugger.break_event = Debugger::SMPStep;
scheduler.exit();
} else {
debugger.breakpoint_test(Debugger::Breakpoint::APURAM, Debugger::Breakpoint::Exec, regs.pc, 0x00);
}
usage[regs.pc] |= UsageExec;
opcode_pc = regs.pc;
if(debugger.step_smp) {
debugger.break_event = Debugger::SMPStep;
scheduler.exit(Scheduler::DebuggerEvent);
} else {
debugger.breakpoint_test(Debugger::Breakpoint::APURAM, Debugger::Breakpoint::Exec, regs.pc, 0x00);
}
if(step_event) step_event();
sSMP::op_step();
scheduler.sync_smpcpu();
}
uint8 sSMPDebug::op_read(uint16 addr) {
uint8 sSMPDebugger::op_read(uint16 addr) {
uint8 data = sSMP::op_read(addr);
usage[addr] |= UsageRead;
debugger.breakpoint_test(Debugger::Breakpoint::APURAM, Debugger::Breakpoint::Read, addr, data);
return data;
}
void sSMPDebug::op_write(uint16 addr, uint8 data) {
void sSMPDebugger::op_write(uint16 addr, uint8 data) {
sSMP::op_write(addr, data);
usage[addr] |= UsageWrite;
usage[addr] &= ~UsageExec;
debugger.breakpoint_test(Debugger::Breakpoint::APURAM, Debugger::Breakpoint::Write, addr, data);
}
sSMPDebug::sSMPDebug() {
sSMPDebugger::sSMPDebugger() {
usage = new uint8[1 << 16]();
opcode_pc = 0xffc0;
}
sSMPDebug::~sSMPDebug() {
sSMPDebugger::~sSMPDebugger() {
delete[] usage;
}

Some files were not shown because too many files have changed in this diff Show More