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.
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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); }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ public:
|
|||
void power();
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
SA1();
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 = ®s.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 = ®s.r[n];
|
||||
regs.dreg = ®s.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 = ®s.r[n];
|
||||
regs.sreg = n;
|
||||
} else {
|
||||
regs.dr() = regs.r[n];
|
||||
regs.sfr.ov = (regs.dr() & 0x80);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ public:
|
|||
void power();
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
|
||||
private:
|
||||
unsigned clockmode;
|
||||
unsigned instruction_counter;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
|
@ -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
|
|
@ -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();
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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; }
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
#if defined(DEBUGGER)
|
||||
#include "cpu-debugger.hpp"
|
||||
#endif
|
||||
|
||||
class CPU : public PPUcounter, public MMIO {
|
||||
public:
|
||||
virtual void enter() = 0;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -100,7 +100,7 @@ public:
|
|||
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.hpp"
|
||||
extern sCPUDebug cpu;
|
||||
extern sCPUDebugger cpu;
|
||||
#else
|
||||
extern sCPU cpu;
|
||||
#endif
|
||||
|
|
After Width: | Height: | Size: 574 B |
After Width: | Height: | Size: 685 B |
After Width: | Height: | Size: 581 B |
After Width: | Height: | Size: 611 B |
After Width: | Height: | Size: 378 B |
After Width: | Height: | Size: 935 B |
Before Width: | Height: | Size: 995 B |
Before Width: | Height: | Size: 978 B |
Before Width: | Height: | Size: 848 B |
Before Width: | Height: | Size: 900 B |
Before Width: | Height: | Size: 927 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 482 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 966 B |
Before Width: | Height: | Size: 100 KiB |
|
@ -1,7 +1,7 @@
|
|||
#include <../base.hpp>
|
||||
|
||||
#define ADSP_CPP
|
||||
namespaec SNES {
|
||||
namespace SNES {
|
||||
|
||||
aDSP dsp;
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
class sDSPDebug : public sDSP {
|
||||
class sDSPDebugger : public sDSP {
|
||||
public:
|
||||
};
|
||||
|
|
|
@ -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() }
|
||||
|
|
|
@ -170,7 +170,7 @@ private:
|
|||
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.hpp"
|
||||
extern sDSPDebug dsp;
|
||||
extern sDSPDebugger dsp;
|
||||
#else
|
||||
extern sDSP dsp;
|
||||
#endif
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -128,6 +128,10 @@
|
|||
#include <ruby/audio/pulseaudio.cpp>
|
||||
#endif
|
||||
|
||||
#ifdef AUDIO_PULSEAUDIOSIMPLE
|
||||
#include <ruby/audio/pulseaudiosimple.cpp>
|
||||
#endif
|
||||
|
||||
/* Input */
|
||||
|
||||
#define DeclareInput(Name) \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -59,7 +59,7 @@ public:
|
|||
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.hpp"
|
||||
extern bPPUDebug ppu;
|
||||
extern bPPUDebugger ppu;
|
||||
#else
|
||||
extern bPPU ppu;
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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
|
|
@ -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; }
|
||||
};
|
|
@ -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; }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|