Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
97a3a28d86 | ||
|
6ec765f2c4 | ||
|
54c7b4692d |
@@ -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)
|
||||
@@ -81,6 +81,7 @@ objects += system cartridge cheat
|
||||
objects += memory smemory cpu cpucore scpu smp smpcore ssmp sdsp ppu bppu
|
||||
objects += supergameboy superfx sa1
|
||||
objects += bsx srtc sdd1 spc7110 cx4 dsp1 dsp2 dsp3 dsp4 obc1 st010 st011 st018
|
||||
objects += 21fx
|
||||
|
||||
######################
|
||||
### implicit rules ###
|
||||
@@ -182,6 +183,7 @@ obj/obc1.o : chip/obc1/obc1.cpp chip/obc1/*
|
||||
obj/st010.o : chip/st010/st010.cpp chip/st010/*
|
||||
obj/st011.o : chip/st011/st011.cpp chip/st011/*
|
||||
obj/st018.o : chip/st018/st018.cpp chip/st018/*
|
||||
obj/21fx.o : chip/21fx/21fx.cpp chip/21fx/*
|
||||
|
||||
###############
|
||||
### targets ###
|
||||
|
@@ -1,6 +1,6 @@
|
||||
static const char bsnesVersion[] = "0.056";
|
||||
static const char bsnesVersion[] = "0.059";
|
||||
static const char bsnesTitle[] = "bsnes";
|
||||
static const unsigned bsnesSaveStateVersion = 3;
|
||||
static const unsigned bsnesSerializerVersion = 4;
|
||||
|
||||
//S-DSP can be encapsulated into a state machine using #define magic
|
||||
//this avoids ~2.048m co_switch() calls per second (~5% speedup)
|
||||
@@ -15,6 +15,7 @@ static const unsigned bsnesSaveStateVersion = 3;
|
||||
#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,53 +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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -168,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,60 +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;
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
//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,
|
||||
@@ -114,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
37
src/cartridge/serialization.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
void Cartridge::serialize(serializer &s) {
|
||||
if(memory::cartram.size() != 0 && memory::cartram.size() != ~0) {
|
||||
s.array(memory::cartram.data(), memory::cartram.size());
|
||||
}
|
||||
|
||||
if(memory::cartrtc.size() != 0 && memory::cartrtc.size() != ~0) {
|
||||
s.array(memory::cartrtc.data(), memory::cartrtc.size());
|
||||
}
|
||||
|
||||
if(memory::bsxram.size() != 0 && memory::bsxram.size() != ~0) {
|
||||
s.array(memory::bsxram.data(), memory::bsxram.size());
|
||||
}
|
||||
|
||||
if(memory::bsxpram.size() != 0 && memory::bsxpram.size() != ~0) {
|
||||
s.array(memory::bsxpram.data(), memory::bsxpram.size());
|
||||
}
|
||||
|
||||
if(memory::stAram.size() != 0 && memory::stAram.size() != ~0) {
|
||||
s.array(memory::stAram.data(), memory::stAram.size());
|
||||
}
|
||||
|
||||
if(memory::stBram.size() != 0 && memory::stBram.size() != ~0) {
|
||||
s.array(memory::stBram.data(), memory::stBram.size());
|
||||
}
|
||||
|
||||
if(memory::gbram.size() != 0 && memory::gbram.size() != ~0) {
|
||||
s.array(memory::gbram.data(), memory::gbram.size());
|
||||
}
|
||||
|
||||
if(memory::gbrtc.size() != 0 && memory::gbrtc.size() != ~0) {
|
||||
s.array(memory::gbrtc.data(), memory::gbrtc.size());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -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;
|
||||
|
195
src/chip/21fx/21fx.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
#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)
|
||||
//$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)
|
||||
//
|
||||
//
|
||||
//$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
|
||||
namespace SNES {
|
||||
|
||||
S21fx s21fx;
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
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) {
|
||||
if(audiofile.open()) {
|
||||
if(audiofile.end()) {
|
||||
if(!mmio.audio_repeat) mmio.status &= ~AudioPlaying;
|
||||
audiofile.seek(mmio.audio_offset = 58);
|
||||
} else {
|
||||
mmio.audio_offset += 4;
|
||||
left = audiofile.readl(2);
|
||||
right = audiofile.readl(2);
|
||||
}
|
||||
} else {
|
||||
mmio.status &= ~AudioPlaying;
|
||||
}
|
||||
}
|
||||
|
||||
left = sclamp<16>((double)left * (double)mmio.audio_volume_left / 255.0);
|
||||
right = sclamp<16>((double)right * (double)mmio.audio_volume_right / 255.0);
|
||||
|
||||
audio.coprocessor_sample(left, right);
|
||||
scheduler.addclocks_cop(1);
|
||||
scheduler.sync_copcpu();
|
||||
}
|
||||
}
|
||||
|
||||
void S21fx::init() {
|
||||
}
|
||||
|
||||
void S21fx::enable() {
|
||||
audio.coprocessor_enable(true);
|
||||
audio.coprocessor_frequency(44100.0);
|
||||
|
||||
for(unsigned i = 0x21f0; i <= 0x21f7; i++) {
|
||||
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);
|
||||
}
|
||||
|
||||
void S21fx::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void S21fx::reset() {
|
||||
mmio.status = DataPortBusy | AudioBusy;
|
||||
mmio.shift_register = 0;
|
||||
|
||||
mmio.data_offset = 0;
|
||||
mmio.audio_offset = 0;
|
||||
mmio.audio_track = 0;
|
||||
mmio.audio_volume_left = 255;
|
||||
mmio.audio_volume_right = 255;
|
||||
mmio.audio_repeat = false;
|
||||
mmio.audio_pause = false;
|
||||
}
|
||||
|
||||
uint8 S21fx::mmio_read(unsigned addr) {
|
||||
addr &= 0xffff;
|
||||
|
||||
if((addr == 0x21f0) || (addr == 0x2200)) {
|
||||
return mmio.status | 0x00;
|
||||
}
|
||||
|
||||
if((addr == 0x21f2) || (addr == 0x2201)) {
|
||||
if(mmio.status & DataPortBusy) return 0x00;
|
||||
mmio.data_offset++;
|
||||
if(datafile.open()) return datafile.read();
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void S21fx::mmio_write(unsigned addr, uint8 data) {
|
||||
addr &= 0xffff;
|
||||
|
||||
if((addr == 0x21f0) || (addr == 0x2200)) {
|
||||
if(data == 0x00) {
|
||||
mmio.data_offset = mmio.shift_register & 0xffffffff;
|
||||
if(datafile.open()) {
|
||||
datafile.seek(mmio.data_offset);
|
||||
}
|
||||
mmio.status &= ~DataPortBusy;
|
||||
}
|
||||
|
||||
if(data == 0x01) {
|
||||
mmio.audio_track = mmio.shift_register & 0xffff;
|
||||
if(audiofile.open()) audiofile.close();
|
||||
char track[16];
|
||||
sprintf(track, "%.5u", mmio.audio_track);
|
||||
if(audiofile.open(string() << basepath << "audio" << track << ".wav", file::mode_read)) {
|
||||
audiofile.seek(mmio.audio_offset = 58); //skip WAV header
|
||||
}
|
||||
mmio.status &= ~(AudioBusy | AudioPlaying);
|
||||
}
|
||||
|
||||
if(data == 0x02) {
|
||||
mmio.audio_volume_left = mmio.shift_register >> 8;
|
||||
mmio.audio_volume_right = mmio.shift_register >> 0;
|
||||
}
|
||||
|
||||
if(data == 0x03) {
|
||||
mmio.status |= AudioPlaying;
|
||||
mmio.audio_repeat = mmio.shift_register & 1;
|
||||
mmio.audio_pause = mmio.shift_register & 2;
|
||||
}
|
||||
|
||||
mmio.shift_register = 0;
|
||||
}
|
||||
|
||||
if((addr == 0x21f1) || (addr == 0x2201)) {
|
||||
mmio.shift_register = (mmio.shift_register << 8) | data;
|
||||
}
|
||||
}
|
||||
|
||||
void S21fx::base(const string& path) {
|
||||
basepath = path;
|
||||
}
|
||||
|
||||
bool S21fx::exists() {
|
||||
return file::exists(string() << basepath << "21fx.bin");
|
||||
}
|
||||
|
||||
S21fx::S21fx() {
|
||||
}
|
||||
|
||||
}
|
44
src/chip/21fx/21fx.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
class S21fx : public MMIO {
|
||||
public:
|
||||
void enter();
|
||||
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
void base(const string &path);
|
||||
bool exists();
|
||||
|
||||
void serialize(serializer&);
|
||||
S21fx();
|
||||
|
||||
private:
|
||||
string basepath;
|
||||
file datafile;
|
||||
file audiofile;
|
||||
|
||||
enum Flag {
|
||||
DataPortBusy = 0x80,
|
||||
AudioBusy = 0x40,
|
||||
AudioPlaying = 0x20,
|
||||
};
|
||||
|
||||
struct MMIO {
|
||||
uint8 status;
|
||||
uint64 shift_register;
|
||||
|
||||
uint32 data_offset;
|
||||
uint32 audio_offset;
|
||||
uint16 audio_track;
|
||||
uint8 audio_volume_left;
|
||||
uint8 audio_volume_right;
|
||||
bool audio_repeat;
|
||||
bool audio_pause;
|
||||
} mmio;
|
||||
};
|
||||
|
||||
extern S21fx s21fx;
|
31
src/chip/21fx/serialization.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifdef S21FX_CPP
|
||||
|
||||
void S21fx::serialize(serializer &s) {
|
||||
s.integer(mmio.status);
|
||||
s.integer(mmio.shift_register);
|
||||
|
||||
s.integer(mmio.data_offset);
|
||||
s.integer(mmio.audio_offset);
|
||||
s.integer(mmio.audio_track);
|
||||
s.integer(mmio.audio_volume_left);
|
||||
s.integer(mmio.audio_volume_right);
|
||||
s.integer(mmio.audio_repeat);
|
||||
s.integer(mmio.audio_pause);
|
||||
|
||||
//flush file handles and indices, as a different track may be playing,
|
||||
//or the file offsets may be at the wrong location ...
|
||||
|
||||
if(datafile.open()) datafile.close();
|
||||
if(datafile.open(string() << basepath << "21fx.bin", file::mode_read)) {
|
||||
datafile.seek(mmio.data_offset);
|
||||
}
|
||||
|
||||
if(audiofile.open()) audiofile.close();
|
||||
char track[16];
|
||||
sprintf(track, "%.5u", mmio.audio_track);
|
||||
if(audiofile.open(string() << basepath << "audio" << track << ".wav", file::mode_read)) {
|
||||
audiofile.seek(mmio.audio_offset);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -14,3 +14,4 @@
|
||||
#include "st010/st010.hpp"
|
||||
#include "st011/st011.hpp"
|
||||
#include "st018/st018.hpp"
|
||||
#include "21fx/21fx.hpp"
|
||||
|
@@ -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();
|
||||
};
|
||||
|
||||
|
150
src/chip/sa1/serialization.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
#ifdef SA1_CPP
|
||||
|
||||
void SA1::serialize(serializer &s) {
|
||||
CPUcore::core_serialize(s);
|
||||
|
||||
//sa1.hpp
|
||||
s.integer(status.tick_counter);
|
||||
|
||||
s.integer(status.interrupt_pending);
|
||||
s.integer(status.interrupt_vector);
|
||||
|
||||
s.integer(status.scanlines);
|
||||
s.integer(status.vcounter);
|
||||
s.integer(status.hcounter);
|
||||
|
||||
//bus/bus.hpp
|
||||
s.array(memory::iram.data(), memory::iram.size());
|
||||
|
||||
memory::vectorsp.sync();
|
||||
|
||||
s.integer(memory::cc1bwram.dma);
|
||||
|
||||
//dma/dma.hpp
|
||||
s.integer(dma.line);
|
||||
|
||||
//mmio/mmio.hpp
|
||||
s.integer(mmio.sa1_irq);
|
||||
s.integer(mmio.sa1_rdyb);
|
||||
s.integer(mmio.sa1_resb);
|
||||
s.integer(mmio.sa1_nmi);
|
||||
s.integer(mmio.smeg);
|
||||
|
||||
s.integer(mmio.cpu_irqen);
|
||||
s.integer(mmio.chdma_irqen);
|
||||
|
||||
s.integer(mmio.cpu_irqcl);
|
||||
s.integer(mmio.chdma_irqcl);
|
||||
|
||||
s.integer(mmio.crv);
|
||||
|
||||
s.integer(mmio.cnv);
|
||||
|
||||
s.integer(mmio.civ);
|
||||
|
||||
s.integer(mmio.cpu_irq);
|
||||
s.integer(mmio.cpu_ivsw);
|
||||
s.integer(mmio.cpu_nvsw);
|
||||
s.integer(mmio.cmeg);
|
||||
|
||||
s.integer(mmio.sa1_irqen);
|
||||
s.integer(mmio.timer_irqen);
|
||||
s.integer(mmio.dma_irqen);
|
||||
s.integer(mmio.sa1_nmien);
|
||||
|
||||
s.integer(mmio.sa1_irqcl);
|
||||
s.integer(mmio.timer_irqcl);
|
||||
s.integer(mmio.dma_irqcl);
|
||||
s.integer(mmio.sa1_nmicl);
|
||||
|
||||
s.integer(mmio.snv);
|
||||
|
||||
s.integer(mmio.siv);
|
||||
|
||||
s.integer(mmio.hvselb);
|
||||
s.integer(mmio.ven);
|
||||
s.integer(mmio.hen);
|
||||
|
||||
s.integer(mmio.hcnt);
|
||||
|
||||
s.integer(mmio.vcnt);
|
||||
|
||||
s.integer(mmio.cbmode);
|
||||
s.integer(mmio.cb);
|
||||
|
||||
s.integer(mmio.dbmode);
|
||||
s.integer(mmio.db);
|
||||
|
||||
s.integer(mmio.ebmode);
|
||||
s.integer(mmio.eb);
|
||||
|
||||
s.integer(mmio.fbmode);
|
||||
s.integer(mmio.fb);
|
||||
|
||||
s.integer(mmio.sbm);
|
||||
|
||||
s.integer(mmio.sw46);
|
||||
s.integer(mmio.cbm);
|
||||
|
||||
s.integer(mmio.swen);
|
||||
|
||||
s.integer(mmio.cwen);
|
||||
|
||||
s.integer(mmio.bwp);
|
||||
|
||||
s.integer(mmio.siwp);
|
||||
|
||||
s.integer(mmio.ciwp);
|
||||
|
||||
s.integer(mmio.dmaen);
|
||||
s.integer(mmio.dprio);
|
||||
s.integer(mmio.cden);
|
||||
s.integer(mmio.cdsel);
|
||||
s.integer(mmio.dd);
|
||||
s.integer(mmio.sd);
|
||||
|
||||
s.integer(mmio.chdend);
|
||||
s.integer(mmio.dmasize);
|
||||
s.integer(mmio.dmacb);
|
||||
|
||||
s.integer(mmio.dsa);
|
||||
|
||||
s.integer(mmio.dda);
|
||||
|
||||
s.integer(mmio.dtc);
|
||||
|
||||
s.integer(mmio.bbf);
|
||||
|
||||
s.array(mmio.brf);
|
||||
|
||||
s.integer(mmio.acm);
|
||||
s.integer(mmio.md);
|
||||
|
||||
s.integer(mmio.ma);
|
||||
|
||||
s.integer(mmio.mb);
|
||||
|
||||
s.integer(mmio.hl);
|
||||
s.integer(mmio.vb);
|
||||
|
||||
s.integer(mmio.va);
|
||||
s.integer(mmio.vbit);
|
||||
|
||||
s.integer(mmio.cpu_irqfl);
|
||||
s.integer(mmio.chdma_irqfl);
|
||||
|
||||
s.integer(mmio.sa1_irqfl);
|
||||
s.integer(mmio.timer_irqfl);
|
||||
s.integer(mmio.dma_irqfl);
|
||||
s.integer(mmio.sa1_nmifl);
|
||||
|
||||
s.integer(mmio.hcr);
|
||||
|
||||
s.integer(mmio.vcr);
|
||||
|
||||
s.integer(mmio.mr);
|
||||
|
||||
s.integer(mmio.overflow);
|
||||
}
|
||||
|
||||
#endif
|
@@ -55,10 +55,10 @@ uint8 SDD1::mmio_read(unsigned addr) {
|
||||
}
|
||||
|
||||
switch(addr) {
|
||||
case 0x4804: return (mmc[0] >> 20) & 7;
|
||||
case 0x4805: return (mmc[1] >> 20) & 7;
|
||||
case 0x4806: return (mmc[2] >> 20) & 7;
|
||||
case 0x4807: return (mmc[3] >> 20) & 7;
|
||||
case 0x4804: return mmc[0] >> 20;
|
||||
case 0x4805: return mmc[1] >> 20;
|
||||
case 0x4806: return mmc[2] >> 20;
|
||||
case 0x4807: return mmc[3] >> 20;
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
@@ -84,10 +84,10 @@ void SDD1::mmio_write(unsigned addr, uint8 data) {
|
||||
case 0x4800: sdd1_enable = data; break;
|
||||
case 0x4801: xfer_enable = data; break;
|
||||
|
||||
case 0x4804: mmc[0] = (data & 7) << 20; break;
|
||||
case 0x4805: mmc[1] = (data & 7) << 20; break;
|
||||
case 0x4806: mmc[2] = (data & 7) << 20; break;
|
||||
case 0x4807: mmc[3] = (data & 7) << 20; break;
|
||||
case 0x4804: mmc[0] = data << 20; break;
|
||||
case 0x4805: mmc[1] = data << 20; break;
|
||||
case 0x4806: mmc[2] = data << 20; break;
|
||||
case 0x4807: mmc[3] = data << 20; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -535,17 +535,17 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) {
|
||||
|
||||
case 0x4831: {
|
||||
r4831 = data;
|
||||
dx_offset = datarom_addr((data & 7) * 0x100000);
|
||||
dx_offset = datarom_addr(data * 0x100000);
|
||||
} break;
|
||||
|
||||
case 0x4832: {
|
||||
r4832 = data;
|
||||
ex_offset = datarom_addr((data & 7) * 0x100000);
|
||||
ex_offset = datarom_addr(data * 0x100000);
|
||||
} break;
|
||||
|
||||
case 0x4833: {
|
||||
r4833 = data;
|
||||
fx_offset = datarom_addr((data & 7) * 0x100000);
|
||||
fx_offset = datarom_addr(data * 0x100000);
|
||||
} break;
|
||||
|
||||
case 0x4834: r4834 = data; break;
|
||||
|
@@ -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
|
||||
|
94
src/chip/superfx/serialization.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#ifdef SUPERFX_CPP
|
||||
|
||||
void SuperFX::serialize(serializer &s) {
|
||||
//superfx.hpp
|
||||
s.integer(clockmode);
|
||||
s.integer(instruction_counter);
|
||||
|
||||
//core/registers.hpp
|
||||
s.integer(regs.pipeline);
|
||||
s.integer(regs.ramaddr);
|
||||
|
||||
s.integer(regs.r[ 0].data);
|
||||
s.integer(regs.r[ 1].data);
|
||||
s.integer(regs.r[ 2].data);
|
||||
s.integer(regs.r[ 3].data);
|
||||
s.integer(regs.r[ 4].data);
|
||||
s.integer(regs.r[ 5].data);
|
||||
s.integer(regs.r[ 6].data);
|
||||
s.integer(regs.r[ 7].data);
|
||||
s.integer(regs.r[ 8].data);
|
||||
s.integer(regs.r[ 9].data);
|
||||
s.integer(regs.r[10].data);
|
||||
s.integer(regs.r[11].data);
|
||||
s.integer(regs.r[12].data);
|
||||
s.integer(regs.r[13].data);
|
||||
s.integer(regs.r[14].data);
|
||||
s.integer(regs.r[15].data);
|
||||
|
||||
s.integer(regs.sfr.irq);
|
||||
s.integer(regs.sfr.b);
|
||||
s.integer(regs.sfr.ih);
|
||||
s.integer(regs.sfr.il);
|
||||
s.integer(regs.sfr.alt2);
|
||||
s.integer(regs.sfr.alt1);
|
||||
s.integer(regs.sfr.r);
|
||||
s.integer(regs.sfr.g);
|
||||
s.integer(regs.sfr.ov);
|
||||
s.integer(regs.sfr.s);
|
||||
s.integer(regs.sfr.cy);
|
||||
s.integer(regs.sfr.z);
|
||||
|
||||
s.integer(regs.pbr);
|
||||
s.integer(regs.rombr);
|
||||
s.integer(regs.rambr);
|
||||
s.integer(regs.cbr);
|
||||
s.integer(regs.scbr);
|
||||
|
||||
s.integer(regs.scmr.ht);
|
||||
s.integer(regs.scmr.ron);
|
||||
s.integer(regs.scmr.ran);
|
||||
s.integer(regs.scmr.md);
|
||||
|
||||
s.integer(regs.colr);
|
||||
|
||||
s.integer(regs.por.obj);
|
||||
s.integer(regs.por.freezehigh);
|
||||
s.integer(regs.por.highnibble);
|
||||
s.integer(regs.por.dither);
|
||||
s.integer(regs.por.transparent);
|
||||
|
||||
s.integer(regs.bramr);
|
||||
s.integer(regs.vcr);
|
||||
|
||||
s.integer(regs.cfgr.irq);
|
||||
s.integer(regs.cfgr.ms0);
|
||||
|
||||
s.integer(regs.clsr);
|
||||
|
||||
s.integer(regs.romcl);
|
||||
s.integer(regs.romdr);
|
||||
|
||||
s.integer(regs.ramcl);
|
||||
s.integer(regs.ramar);
|
||||
s.integer(regs.ramdr);
|
||||
|
||||
s.integer(regs.sreg);
|
||||
s.integer(regs.dreg);
|
||||
|
||||
s.array(cache.buffer);
|
||||
s.array(cache.valid);
|
||||
|
||||
for(unsigned i = 0; i < 2; i++) {
|
||||
s.integer(pixelcache[i].offset);
|
||||
s.integer(pixelcache[i].bitpend);
|
||||
s.array(pixelcache[i].data);
|
||||
}
|
||||
|
||||
//timing/timing.hpp
|
||||
s.integer(cache_access_speed);
|
||||
s.integer(memory_access_speed);
|
||||
s.integer(r15_modified);
|
||||
}
|
||||
|
||||
#endif
|
@@ -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
|
||||
|
@@ -6,13 +6,23 @@ namespace SNES {
|
||||
SuperGameBoy supergameboy;
|
||||
|
||||
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(10);
|
||||
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;
|
||||
@@ -21,7 +31,8 @@ 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 * 10);
|
||||
|
||||
scheduler.addclocks_cop(samples);
|
||||
scheduler.sync_copcpu();
|
||||
}
|
||||
}
|
||||
@@ -96,8 +107,10 @@ void SuperGameBoy::enable() {
|
||||
}
|
||||
|
||||
void SuperGameBoy::power() {
|
||||
version = (cartridge.type() == Cartridge::TypeSuperGameBoy1Bios ? SuperGameBoy1 : SuperGameBoy2);
|
||||
|
||||
audio.coprocessor_enable(true);
|
||||
audio.coprocessor_frequency(2147727.2);
|
||||
audio.coprocessor_frequency(version == SuperGameBoy1 ? 2147727.0 : 2097152.0);
|
||||
|
||||
bus.map(Bus::MapDirect, 0x00, 0x3f, 0x6000, 0x7fff, *this);
|
||||
bus.map(Bus::MapDirect, 0x80, 0xbf, 0x6000, 0x7fff, *this);
|
||||
@@ -106,8 +119,7 @@ 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(memory::cartrom[0x7fcd] != 0x32 ? SuperGameBoy1 : SuperGameBoy2);
|
||||
if(sgb_init) sgb_init(version);
|
||||
if(sgb_power) sgb_power();
|
||||
}
|
||||
|
||||
@@ -121,6 +133,7 @@ void SuperGameBoy::unload() {
|
||||
|
||||
void SuperGameBoy::serialize(serializer &s) {
|
||||
s.integer(row);
|
||||
s.integer(version);
|
||||
if(sgb_serialize) sgb_serialize(s);
|
||||
}
|
||||
|
||||
|
@@ -20,6 +20,7 @@ public:
|
||||
private:
|
||||
uint32_t samplebuffer[4096];
|
||||
unsigned row;
|
||||
bool version;
|
||||
|
||||
enum { SuperGameBoy1 = 0, SuperGameBoy2 = 1 };
|
||||
function<void (uint8_t*, unsigned)> sgb_rom;
|
||||
|
@@ -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);
|
||||
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]
|
||||
@@ -102,7 +104,7 @@ uint32 CPUcore::decode(uint8 offset_type, uint32 addr) {
|
||||
return(r & 0xffffff);
|
||||
}
|
||||
|
||||
void CPUcore::disassemble_opcode(char *output) {
|
||||
void CPUcore::disassemble_opcode(char *output, uint32 addr) {
|
||||
static reg24_t pc;
|
||||
char t[256];
|
||||
char *s = output;
|
||||
@@ -112,7 +114,7 @@ void CPUcore::disassemble_opcode(char *output) {
|
||||
return;
|
||||
}
|
||||
|
||||
pc.d = regs.pc.d;
|
||||
pc.d = addr;
|
||||
sprintf(s, "%.6x ", (uint32)pc.d);
|
||||
|
||||
uint8 op = dreadb(pc.d); pc.w++;
|
||||
@@ -477,3 +479,5 @@ uint8 CPUcore::opcode_length() {
|
||||
if(len == 6) return (regs.e || regs.p.x) ? 2 : 3;
|
||||
return len;
|
||||
}
|
||||
|
||||
#endif
|
30
src/cpu/core/disassembler/disassembler.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
enum {
|
||||
OPTYPE_DP = 0, //dp
|
||||
OPTYPE_DPX, //dp,x
|
||||
OPTYPE_DPY, //dp,y
|
||||
OPTYPE_IDP, //(dp)
|
||||
OPTYPE_IDPX, //(dp,x)
|
||||
OPTYPE_IDPY, //(dp),y
|
||||
OPTYPE_ILDP, //[dp]
|
||||
OPTYPE_ILDPY, //[dp],y
|
||||
OPTYPE_ADDR, //addr
|
||||
OPTYPE_ADDRX, //addr,x
|
||||
OPTYPE_ADDRY, //addr,y
|
||||
OPTYPE_IADDRX, //(addr,x)
|
||||
OPTYPE_ILADDR, //[addr]
|
||||
OPTYPE_LONG, //long
|
||||
OPTYPE_LONGX, //long, x
|
||||
OPTYPE_SR, //sr,s
|
||||
OPTYPE_ISRY, //(sr,s),y
|
||||
OPTYPE_ADDR_PC, //pbr:addr
|
||||
OPTYPE_IADDR_PC, //pbr:(addr)
|
||||
OPTYPE_RELB, //relb
|
||||
OPTYPE_RELW, //relw
|
||||
};
|
||||
|
||||
void disassemble_opcode(char *output, uint32 addr);
|
||||
uint8 dreadb(uint32 addr);
|
||||
uint16 dreadw(uint32 addr);
|
||||
uint32 dreadl(uint32 addr);
|
||||
uint32 decode(uint8 offset_type, uint32 addr);
|
||||
uint8 opcode_length();
|
@@ -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
|
||||
|
59
src/cpu/cpu-debugger.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifdef CPU_CPP
|
||||
|
||||
bool CPUDebugger::property(unsigned id, string &name, string &value) {
|
||||
unsigned n = 0;
|
||||
|
||||
//internal
|
||||
if(id == n++) { name = "S-CPU MDR"; value = string::printf("0x%.2x", mdr()); return true; }
|
||||
|
||||
//$2181-2183
|
||||
if(id == n++) { name = "$2181-$2183"; value = ""; return true; }
|
||||
if(id == n++) { name = "WRAM Address"; value = string::printf("0x%.6x", wram_address()); return true; }
|
||||
|
||||
//$4016
|
||||
if(id == n++) { name = "$4016"; value = ""; return true; }
|
||||
if(id == n++) { name = "Joypad Strobe Latch"; value = joypad_strobe_latch(); return true; }
|
||||
|
||||
//$4200
|
||||
if(id == n++) { name = "$4200"; value = ""; return true; }
|
||||
if(id == n++) { name = "NMI Enable"; value = nmi_enable(); return true; }
|
||||
if(id == n++) { name = "H-IRQ Enable"; value = hirq_enable(); return true; }
|
||||
if(id == n++) { name = "V-IRQ Enable"; value = virq_enable(); return true; }
|
||||
if(id == n++) { name = "Auto Joypad Poll"; value = auto_joypad_poll(); return true; }
|
||||
|
||||
//$4201
|
||||
if(id == n++) { name = "$4201"; value = ""; return true; }
|
||||
if(id == n++) { name = "PIO"; value = string::printf("0x%.2x", pio_bits()); return true; }
|
||||
|
||||
//$4202
|
||||
if(id == n++) { name = "$4202"; value = ""; return true; }
|
||||
if(id == n++) { name = "Multiplicand"; value = string::printf("0x%.2x", multiplicand()); return true; }
|
||||
|
||||
//$4203
|
||||
if(id == n++) { name = "$4203"; value = ""; return true; }
|
||||
if(id == n++) { name = "Multiplier"; value = string::printf("0x%.2x", multiplier()); return true; }
|
||||
|
||||
//$4204-$4205
|
||||
if(id == n++) { name = "$4204-$4205"; value = ""; return true; }
|
||||
if(id == n++) { name = "Dividend"; value = string::printf("0x%.4x", dividend()); return true; }
|
||||
|
||||
//$4206
|
||||
if(id == n++) { name = "$4206"; value = ""; return true; }
|
||||
if(id == n++) { name = "Divisor"; value = string::printf("0x%.2x", divisor()); return true; }
|
||||
|
||||
//$4207-$4208
|
||||
if(id == n++) { name = "$4207-$4208"; value = ""; return true; }
|
||||
if(id == n++) { name = "H-Time"; value = string::printf("0x%.4x", htime()); return true; }
|
||||
|
||||
//$4209-$420a
|
||||
if(id == n++) { name = "$4209-$420a"; value = ""; return true; }
|
||||
if(id == n++) { name = "V-Time"; value = string::printf("0x%.4x", vtime()); return true; }
|
||||
|
||||
//$420d
|
||||
if(id == n++) { name = "$420d"; value = ""; return true; }
|
||||
if(id == n++) { name = "FastROM Enable"; value = fastrom_enable(); return true; }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
42
src/cpu/cpu-debugger.hpp
Normal file
@@ -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,34 +1,88 @@
|
||||
#ifdef SCPU_CPP
|
||||
|
||||
void sCPUDebug::op_step() {
|
||||
void sCPUDebugger::op_step() {
|
||||
bool break_event = false;
|
||||
|
||||
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.exit(Scheduler::DebuggerEvent);
|
||||
} else {
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::CPUBus, Debugger::Breakpoint::Exec, regs.pc, 0x00);
|
||||
}
|
||||
|
||||
if(debugger.trace_cpu) {
|
||||
char t[256];
|
||||
disassemble_opcode(t);
|
||||
debugger.tracefile.print(string() << t << "\n");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
sCPUDebugger::sCPUDebugger() {
|
||||
usage = new uint8[1 << 24]();
|
||||
opcode_pc = 0x8000;
|
||||
}
|
||||
|
||||
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,6 +1,64 @@
|
||||
class sCPUDebug : public sCPU {
|
||||
class sCPUDebugger : public sCPU, public CPUDebugger {
|
||||
public:
|
||||
function<void ()> step_event;
|
||||
|
||||
enum Usage {
|
||||
UsageRead = 0x80,
|
||||
UsageWrite = 0x40,
|
||||
UsageExec = 0x20,
|
||||
UsageFlagM = 0x02,
|
||||
UsageFlagX = 0x01,
|
||||
};
|
||||
uint8 *usage;
|
||||
uint32 opcode_pc; //points to the current opcode, used to backtrace on read/write breakpoints
|
||||
|
||||
void op_step();
|
||||
uint8 op_read(uint32 addr);
|
||||
void op_write(uint32 addr, uint8 data);
|
||||
|
||||
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
|
||||
|
BIN
src/data/icons-16x16/applications-multimedia.png
Normal file
After Width: | Height: | Size: 592 B |
BIN
src/data/icons-16x16/audio-volume-high.png
Normal file
After Width: | Height: | Size: 685 B |
Before Width: | Height: | Size: 477 B |
BIN
src/data/icons-16x16/folder.png
Normal file
After Width: | Height: | Size: 581 B |
BIN
src/data/icons-16x16/media-playback-start.png
Normal file
After Width: | Height: | Size: 660 B |
BIN
src/data/icons-16x16/media-playback-stop.png
Normal file
After Width: | Height: | Size: 429 B |
BIN
src/data/icons-16x16/media-record.png
Normal file
After Width: | Height: | Size: 653 B |
BIN
src/data/icons-16x16/preferences-system.png
Normal file
After Width: | Height: | Size: 611 B |
Before Width: | Height: | Size: 995 B |
Before Width: | Height: | Size: 978 B |
Before Width: | Height: | Size: 848 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"
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
||||
#if defined(PLATFORM_X)
|
||||
#if defined(PLATFORM_X) || defined(PLATFORM_OSX)
|
||||
#include <dlfcn.h>
|
||||
#elif defined(PLATFORM_WIN)
|
||||
#include <windows.h>
|
||||
@@ -52,6 +52,34 @@ namespace nall {
|
||||
return dlsym((void*)handle, name);
|
||||
}
|
||||
|
||||
inline void library::close() {
|
||||
if(!handle) return;
|
||||
dlclose((void*)handle);
|
||||
handle = 0;
|
||||
}
|
||||
#elif defined(PLATFORM_OSX)
|
||||
inline bool library::open(const char *name) {
|
||||
if(handle) close();
|
||||
char *t = new char[strlen(name) + 256];
|
||||
strcpy(t, "lib");
|
||||
strcat(t, name);
|
||||
strcat(t, ".dylib");
|
||||
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
|
||||
if(!handle) {
|
||||
strcpy(t, "/usr/local/lib/lib");
|
||||
strcat(t, name);
|
||||
strcat(t, ".dylib");
|
||||
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
|
||||
}
|
||||
delete[] t;
|
||||
return handle;
|
||||
}
|
||||
|
||||
inline void* library::sym(const char *name) {
|
||||
if(!handle) return 0;
|
||||
return dlsym((void*)handle, name);
|
||||
}
|
||||
|
||||
inline void library::close() {
|
||||
if(!handle) return;
|
||||
dlclose((void*)handle);
|
||||
|
@@ -136,7 +136,7 @@ namespace nall {
|
||||
function() { data.fn_call = 0; }
|
||||
|
||||
function(void *fn) {
|
||||
data.fn_call = &fn_call_global;
|
||||
data.fn_call = fn ? &fn_call_global : 0;
|
||||
data.fn_global = (R (*)(PL))fn;
|
||||
}
|
||||
|
||||
|
@@ -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,7 +1,5 @@
|
||||
/*
|
||||
audio.alsa (2008-08-12)
|
||||
authors: Nach, RedDwarf
|
||||
*/
|
||||
//audio.alsa (2009-11-30)
|
||||
//authors: BearOso, byuu, Nach, RedDwarf
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
@@ -77,6 +75,22 @@ public:
|
||||
buffer.data[buffer.length++] = left + (right << 16);
|
||||
if(buffer.length < device.period_size) return;
|
||||
|
||||
snd_pcm_sframes_t avail;
|
||||
do {
|
||||
avail = snd_pcm_avail_update(device.handle);
|
||||
if(avail < 0) snd_pcm_recover(device.handle, avail, 1);
|
||||
if(avail < buffer.length) {
|
||||
if(settings.synchronize == false) {
|
||||
buffer.length = 0;
|
||||
return;
|
||||
}
|
||||
int error = snd_pcm_wait(device.handle, -1);
|
||||
if(error < 0) snd_pcm_recover(device.handle, error, 1);
|
||||
}
|
||||
} while(avail < buffer.length);
|
||||
|
||||
//below code has issues with PulseAudio sound server
|
||||
#if 0
|
||||
if(settings.synchronize == false) {
|
||||
snd_pcm_sframes_t avail = snd_pcm_avail_update(device.handle);
|
||||
if(avail < device.period_size) {
|
||||
@@ -84,6 +98,7 @@ public:
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t *buffer_ptr = buffer.data;
|
||||
int i = 4;
|
||||
@@ -114,12 +129,13 @@ public:
|
||||
bool init() {
|
||||
term();
|
||||
|
||||
if(snd_pcm_open(&device.handle, device.name, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
|
||||
if(snd_pcm_open(&device.handle, device.name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) {
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* //below code will not work with 24khz frequency rate (ALSA library bug)
|
||||
//below code will not work with 24khz frequency rate (ALSA library bug)
|
||||
#if 0
|
||||
if(snd_pcm_set_params(device.handle, device.format, SND_PCM_ACCESS_RW_INTERLEAVED,
|
||||
device.channels, settings.frequency, 1, settings.latency * 1000) < 0) {
|
||||
//failed to set device parameters
|
||||
@@ -129,7 +145,8 @@ public:
|
||||
|
||||
if(snd_pcm_get_params(device.handle, &device.buffer_size, &device.period_size) < 0) {
|
||||
device.period_size = settings.latency * 1000 * 1e-6 * settings.frequency / 4;
|
||||
}*/
|
||||
}
|
||||
#endif
|
||||
|
||||
snd_pcm_hw_params_t *hwparams;
|
||||
snd_pcm_sw_params_t *swparams;
|
||||
|
@@ -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)
|
||||
|
||||
};
|
||||
}
|
||||
|
115
src/lib/ruby/audio/pulseaudiosimple.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
//audio.pulseaudiosimple (2010-01-05)
|
||||
//author: byuu
|
||||
|
||||
#include <pulse/simple.h>
|
||||
#include <pulse/error.h>
|
||||
|
||||
namespace ruby {
|
||||
|
||||
class pAudioPulseAudioSimple {
|
||||
public:
|
||||
struct {
|
||||
pa_simple *handle;
|
||||
pa_sample_spec spec;
|
||||
} device;
|
||||
|
||||
struct {
|
||||
uint32_t *data;
|
||||
unsigned offset;
|
||||
} buffer;
|
||||
|
||||
struct {
|
||||
unsigned frequency;
|
||||
} settings;
|
||||
|
||||
bool cap(const string& name) {
|
||||
if(name == Audio::Frequency) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
any get(const string& name) {
|
||||
if(name == Audio::Frequency) return settings.frequency;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool set(const string& name, const any& value) {
|
||||
if(name == Audio::Frequency) {
|
||||
settings.frequency = any_cast<unsigned>(value);
|
||||
if(device.handle) init();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void sample(uint16_t left, uint16_t right) {
|
||||
if(!device.handle) return;
|
||||
|
||||
buffer.data[buffer.offset++] = left + (right << 16);
|
||||
if(buffer.offset >= 64) {
|
||||
int error;
|
||||
pa_simple_write(device.handle, (const void*)buffer.data, buffer.offset * sizeof(uint32_t), &error);
|
||||
buffer.offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
}
|
||||
|
||||
bool init() {
|
||||
term();
|
||||
|
||||
device.spec.format = PA_SAMPLE_S16LE;
|
||||
device.spec.channels = 2;
|
||||
device.spec.rate = settings.frequency;
|
||||
|
||||
int error = 0;
|
||||
device.handle = pa_simple_new(
|
||||
0, //default server
|
||||
"ruby::pulseaudiosimple", //application name
|
||||
PA_STREAM_PLAYBACK, //direction
|
||||
0, //default device
|
||||
"audio", //stream description
|
||||
&device.spec, //sample format
|
||||
0, //default channel map
|
||||
0, //default buffering attributes
|
||||
&error //error code
|
||||
);
|
||||
if(!device.handle) {
|
||||
fprintf(stderr, "ruby::pulseaudiosimple failed to initialize - %s\n", pa_strerror(error));
|
||||
return false;
|
||||
}
|
||||
|
||||
buffer.data = new uint32_t[64];
|
||||
buffer.offset = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void term() {
|
||||
if(device.handle) {
|
||||
int error;
|
||||
pa_simple_flush(device.handle, &error);
|
||||
pa_simple_free(device.handle);
|
||||
device.handle = 0;
|
||||
}
|
||||
|
||||
if(buffer.data) {
|
||||
delete[] buffer.data;
|
||||
buffer.data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pAudioPulseAudioSimple() {
|
||||
device.handle = 0;
|
||||
buffer.data = 0;
|
||||
settings.frequency = 22050;
|
||||
}
|
||||
|
||||
~pAudioPulseAudioSimple() {
|
||||
term();
|
||||
}
|
||||
};
|
||||
|
||||
DeclareAudio(PulseAudioSimple)
|
||||
|
||||
};
|
@@ -14,7 +14,6 @@ InputInterface input;
|
||||
const char *Video::Handle = "Handle";
|
||||
const char *Video::Synchronize = "Synchronize";
|
||||
const char *Video::Filter = "Filter";
|
||||
const char *Video::GLSL = "GLSL";
|
||||
const char *Video::FragmentShader = "FragmentShader";
|
||||
const char *Video::VertexShader = "VertexShader";
|
||||
|
||||
@@ -191,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();
|
||||
}
|
||||
|
||||
@@ -204,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)
|
||||
@@ -241,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) \
|
||||
|
@@ -3,7 +3,6 @@ public:
|
||||
static const char *Handle;
|
||||
static const char *Synchronize;
|
||||
static const char *Filter;
|
||||
static const char *GLSL;
|
||||
static const char *FragmentShader;
|
||||
static const char *VertexShader;
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
video.glx
|
||||
author: byuu
|
||||
license: public domain
|
||||
last updated: 2008-08-20
|
||||
last updated: 2010-01-05
|
||||
|
||||
Design notes:
|
||||
SGI's GLX is the X11/Xlib interface to OpenGL.
|
||||
@@ -34,6 +34,8 @@ static Bool glx_wait_for_map_notify(Display *d, XEvent *e, char *arg) {
|
||||
|
||||
class pVideoGLX : public OpenGL {
|
||||
public:
|
||||
int (*glSwapInterval)(int);
|
||||
|
||||
Display *display;
|
||||
int screen;
|
||||
Window xwindow;
|
||||
@@ -60,7 +62,6 @@ public:
|
||||
if(name == Video::Handle) return true;
|
||||
if(name == Video::Synchronize) return true;
|
||||
if(name == Video::Filter) return true;
|
||||
if(name == Video::GLSL) return true;
|
||||
if(name == Video::FragmentShader) return true;
|
||||
if(name == Video::VertexShader) return true;
|
||||
return false;
|
||||
@@ -82,7 +83,7 @@ public:
|
||||
if(name == Video::Synchronize) {
|
||||
if(settings.synchronize != any_cast<bool>(value)) {
|
||||
settings.synchronize = any_cast<bool>(value);
|
||||
if(glxcontext) init();
|
||||
if(glSwapInterval) glSwapInterval(settings.synchronize);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -151,11 +152,8 @@ public:
|
||||
|
||||
//let GLX determine the best Visual to use for GL output; provide a few hints
|
||||
//note: some video drivers will override double buffering attribute
|
||||
int elements = 0;
|
||||
int attributelist[] = { GLX_RGBA, None };
|
||||
int attributelist_sync[] = { GLX_RGBA, GLX_DOUBLEBUFFER, None };
|
||||
XVisualInfo *vi = glXChooseVisual(display, screen,
|
||||
settings.synchronize ? attributelist_sync : attributelist);
|
||||
int attributelist[] = { GLX_RGBA, GLX_DOUBLEBUFFER, None };
|
||||
XVisualInfo *vi = glXChooseVisual(display, screen, attributelist);
|
||||
|
||||
//Window settings.handle has already been realized, most likely with DefaultVisual.
|
||||
//GLX requires that the GL output window has the same Visual as the GLX context.
|
||||
@@ -190,13 +188,9 @@ public:
|
||||
settings.height = 256;
|
||||
|
||||
//vertical synchronization
|
||||
int (*glSwapInterval)(int);
|
||||
glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalEXT");
|
||||
if(glSwapInterval) glSwapInterval(settings.synchronize);
|
||||
glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalSGI");
|
||||
if(glSwapInterval) glSwapInterval(settings.synchronize);
|
||||
glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalMESA");
|
||||
if(glSwapInterval) glSwapInterval(settings.synchronize);
|
||||
if(!glSwapInterval) glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalSGI");
|
||||
if(!glSwapInterval) glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalMESA");
|
||||
if( glSwapInterval) glSwapInterval(settings.synchronize);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -220,7 +214,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
pVideoGLX() {
|
||||
pVideoGLX() : glSwapInterval(0) {
|
||||
settings.handle = 0;
|
||||
settings.synchronize = false;
|
||||
xwindow = 0;
|
||||
|
@@ -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);
|
||||
|
@@ -9,6 +9,8 @@ namespace ruby {
|
||||
|
||||
class pVideoWGL : public OpenGL {
|
||||
public:
|
||||
BOOL (APIENTRY *glSwapInterval)(int);
|
||||
|
||||
HDC display;
|
||||
HGLRC wglcontext;
|
||||
HWND window;
|
||||
@@ -27,7 +29,6 @@ public:
|
||||
if(name == Video::Handle) return true;
|
||||
if(name == Video::Synchronize) return true;
|
||||
if(name == Video::Filter) return true;
|
||||
if(name == Video::GLSL) return true;
|
||||
if(name == Video::FragmentShader) return true;
|
||||
if(name == Video::VertexShader) return true;
|
||||
return false;
|
||||
@@ -105,7 +106,7 @@ public:
|
||||
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
|
||||
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | (settings.synchronize ? PFD_DOUBLEBUFFER : 0);
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
|
||||
display = GetDC(settings.handle);
|
||||
@@ -120,9 +121,8 @@ public:
|
||||
settings.height = 256;
|
||||
|
||||
//vertical synchronization
|
||||
BOOL (APIENTRY *glSwapInterval)(int);
|
||||
glSwapInterval = (BOOL (APIENTRY*)(int))glGetProcAddress("wglSwapIntervalEXT");
|
||||
if(glSwapInterval) glSwapInterval(settings.synchronize);
|
||||
if(!glSwapInterval) glSwapInterval = (BOOL (APIENTRY*)(int))glGetProcAddress("wglSwapIntervalEXT");
|
||||
if( glSwapInterval) glSwapInterval(settings.synchronize);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -136,7 +136,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
pVideoWGL() {
|
||||
pVideoWGL() : glSwapInterval(0) {
|
||||
settings.handle = 0;
|
||||
settings.synchronize = false;
|
||||
settings.filter = 0;
|
||||
|
@@ -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,5 +5,3 @@ mkdir nall
|
||||
mkdir ruby
|
||||
xcopy /E ..\..\..\nall nall
|
||||
xcopy /E ..\..\..\ruby ruby
|
||||
del ruby\test*
|
||||
del ruby\cc.*
|
||||
|
@@ -8,5 +8,3 @@ cp -r ../../../ruby ./ruby
|
||||
|
||||
rm -r libco/doc
|
||||
rm -r libco/test
|
||||
rm ruby/test*
|
||||
rm ruby/cc.*
|
||||
|
@@ -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();
|
||||
};
|
||||
|
194
src/ppu/bppu/debugger/render.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
#ifdef BPPU_CPP
|
||||
|
||||
//render_line_modeN() taken from src/ppu/bppu/render/render.cpp
|
||||
//modified to support layer disable; accomplished by setting priority to zero
|
||||
//a priority of zero won't override the back layer, effectively nullifying it
|
||||
//for speed, rendering loop is skipped entirely if all priorities are disabled
|
||||
//
|
||||
//note: render_line_(bg|oam|mode7) cannot be virtualized as they are templates
|
||||
|
||||
void bPPUDebugger::render_line_mode0() {
|
||||
unsigned pri0, pri1, pri2, pri3;
|
||||
|
||||
pri0 = bg1_enabled[0] ? 8 : 0;
|
||||
pri1 = bg1_enabled[1] ? 11 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<0, BG1, COLORDEPTH_4>(pri0, pri1);
|
||||
|
||||
pri0 = bg2_enabled[0] ? 7 : 0;
|
||||
pri1 = bg2_enabled[1] ? 10 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<0, BG2, COLORDEPTH_4>(pri0, pri1);
|
||||
|
||||
pri0 = bg3_enabled[0] ? 2 : 0;
|
||||
pri1 = bg3_enabled[1] ? 5 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<0, BG3, COLORDEPTH_4>(pri0, pri1);
|
||||
|
||||
pri0 = bg4_enabled[0] ? 1 : 0;
|
||||
pri1 = bg4_enabled[1] ? 4 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<0, BG4, COLORDEPTH_4>(pri0, pri1);
|
||||
|
||||
pri0 = oam_enabled[0] ? 3 : 0;
|
||||
pri1 = oam_enabled[1] ? 6 : 0;
|
||||
pri2 = oam_enabled[2] ? 9 : 0;
|
||||
pri3 = oam_enabled[3] ? 12 : 0;
|
||||
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
|
||||
void bPPUDebugger::render_line_mode1() {
|
||||
unsigned pri0, pri1, pri2, pri3;
|
||||
|
||||
if(regs.bg3_priority) {
|
||||
pri0 = bg1_enabled[0] ? 5 : 0;
|
||||
pri1 = bg1_enabled[1] ? 8 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<1, BG1, COLORDEPTH_16>(pri0, pri1);
|
||||
|
||||
pri0 = bg2_enabled[0] ? 4 : 0;
|
||||
pri1 = bg2_enabled[1] ? 7 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<1, BG2, COLORDEPTH_16>(pri0, pri1);
|
||||
|
||||
pri0 = bg3_enabled[0] ? 1 : 0;
|
||||
pri1 = bg3_enabled[1] ? 10 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<1, BG3, COLORDEPTH_4>(pri0, pri1);
|
||||
|
||||
pri0 = oam_enabled[0] ? 2 : 0;
|
||||
pri1 = oam_enabled[1] ? 3 : 0;
|
||||
pri2 = oam_enabled[2] ? 6 : 0;
|
||||
pri3 = oam_enabled[3] ? 9 : 0;
|
||||
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
} else {
|
||||
pri0 = bg1_enabled[0] ? 6 : 0;
|
||||
pri1 = bg1_enabled[1] ? 9 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<1, BG1, COLORDEPTH_16>(pri0, pri1);
|
||||
|
||||
pri0 = bg2_enabled[0] ? 5 : 0;
|
||||
pri1 = bg2_enabled[1] ? 8 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<1, BG2, COLORDEPTH_16>(pri0, pri1);
|
||||
|
||||
pri0 = bg3_enabled[0] ? 1 : 0;
|
||||
pri1 = bg3_enabled[1] ? 3 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<1, BG3, COLORDEPTH_4>(pri0, pri1);
|
||||
|
||||
pri0 = oam_enabled[0] ? 2 : 0;
|
||||
pri1 = oam_enabled[1] ? 4 : 0;
|
||||
pri2 = oam_enabled[2] ? 7 : 0;
|
||||
pri3 = oam_enabled[3] ? 10 : 0;
|
||||
bPPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
}
|
||||
|
||||
void bPPUDebugger::render_line_mode2() {
|
||||
unsigned pri0, pri1, pri2, pri3;
|
||||
|
||||
pri0 = bg1_enabled[0] ? 3 : 0;
|
||||
pri1 = bg1_enabled[1] ? 7 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<2, BG1, COLORDEPTH_16>(pri0, pri1);
|
||||
|
||||
pri0 = bg2_enabled[0] ? 1 : 0;
|
||||
pri1 = bg2_enabled[1] ? 5 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<2, BG2, COLORDEPTH_16>(pri0, pri1);
|
||||
|
||||
pri0 = oam_enabled[0] ? 2 : 0;
|
||||
pri1 = oam_enabled[1] ? 4 : 0;
|
||||
pri2 = oam_enabled[2] ? 6 : 0;
|
||||
pri3 = oam_enabled[3] ? 8 : 0;
|
||||
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
|
||||
void bPPUDebugger::render_line_mode3() {
|
||||
unsigned pri0, pri1, pri2, pri3;
|
||||
|
||||
pri0 = bg1_enabled[0] ? 3 : 0;
|
||||
pri1 = bg1_enabled[1] ? 7 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<3, BG1, COLORDEPTH_256>(pri0, pri1);
|
||||
|
||||
pri0 = bg2_enabled[0] ? 1 : 0;
|
||||
pri1 = bg2_enabled[1] ? 5 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<3, BG2, COLORDEPTH_16>(pri0, pri1);
|
||||
|
||||
pri0 = oam_enabled[0] ? 2 : 0;
|
||||
pri1 = oam_enabled[1] ? 4 : 0;
|
||||
pri2 = oam_enabled[2] ? 6 : 0;
|
||||
pri3 = oam_enabled[3] ? 8 : 0;
|
||||
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
|
||||
void bPPUDebugger::render_line_mode4() {
|
||||
unsigned pri0, pri1, pri2, pri3;
|
||||
|
||||
pri0 = bg1_enabled[0] ? 3 : 0;
|
||||
pri1 = bg1_enabled[1] ? 7 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<4, BG1, COLORDEPTH_256>(pri0, pri1);
|
||||
|
||||
pri0 = bg2_enabled[0] ? 1 : 0;
|
||||
pri1 = bg2_enabled[1] ? 5 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<4, BG2, COLORDEPTH_4>(pri0, pri1);
|
||||
|
||||
pri0 = oam_enabled[0] ? 2 : 0;
|
||||
pri1 = oam_enabled[1] ? 4 : 0;
|
||||
pri2 = oam_enabled[2] ? 6 : 0;
|
||||
pri3 = oam_enabled[3] ? 8 : 0;
|
||||
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
|
||||
void bPPUDebugger::render_line_mode5() {
|
||||
unsigned pri0, pri1, pri2, pri3;
|
||||
|
||||
pri0 = bg1_enabled[0] ? 3 : 0;
|
||||
pri1 = bg1_enabled[1] ? 7 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<5, BG1, COLORDEPTH_16>(pri0, pri1);
|
||||
|
||||
pri0 = bg2_enabled[0] ? 1 : 0;
|
||||
pri1 = bg2_enabled[1] ? 5 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<5, BG2, COLORDEPTH_4>(pri0, pri1);
|
||||
|
||||
pri0 = oam_enabled[0] ? 2 : 0;
|
||||
pri1 = oam_enabled[1] ? 4 : 0;
|
||||
pri2 = oam_enabled[2] ? 6 : 0;
|
||||
pri3 = oam_enabled[3] ? 8 : 0;
|
||||
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
|
||||
void bPPUDebugger::render_line_mode6() {
|
||||
unsigned pri0, pri1, pri2, pri3;
|
||||
|
||||
pri0 = bg1_enabled[0] ? 2 : 0;
|
||||
pri1 = bg1_enabled[1] ? 5 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_bg<6, BG1, COLORDEPTH_16>(pri0, pri1);
|
||||
|
||||
pri0 = oam_enabled[0] ? 1 : 0;
|
||||
pri1 = oam_enabled[1] ? 3 : 0;
|
||||
pri2 = oam_enabled[2] ? 4 : 0;
|
||||
pri3 = oam_enabled[3] ? 6 : 0;
|
||||
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
|
||||
void bPPUDebugger::render_line_mode7() {
|
||||
unsigned pri0, pri1, pri2, pri3;
|
||||
|
||||
if(regs.mode7_extbg == false) {
|
||||
pri0 = bg1_enabled[0] ? 2 : 0;
|
||||
pri1 = bg1_enabled[1] ? 2 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_mode7<BG1>(pri0, pri1);
|
||||
|
||||
pri0 = oam_enabled[0] ? 1 : 0;
|
||||
pri1 = oam_enabled[1] ? 3 : 0;
|
||||
pri2 = oam_enabled[2] ? 4 : 0;
|
||||
pri3 = oam_enabled[3] ? 5 : 0;
|
||||
if(pri0 | pri1 | pri2 | pri3) bPPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
} else {
|
||||
pri0 = bg1_enabled[0] ? 3 : 0;
|
||||
pri1 = bg1_enabled[1] ? 3 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_mode7<BG1>(pri0, pri1);
|
||||
|
||||
pri0 = bg2_enabled[0] ? 1 : 0;
|
||||
pri1 = bg2_enabled[1] ? 5 : 0;
|
||||
if(pri0 | pri1) bPPU::render_line_mode7<BG2>(pri0, pri1);
|
||||
|
||||
pri0 = oam_enabled[0] ? 2 : 0;
|
||||
pri1 = oam_enabled[1] ? 4 : 0;
|
||||
pri2 = oam_enabled[2] ? 6 : 0;
|
||||
pri3 = oam_enabled[3] ? 7 : 0;
|
||||
bPPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -30,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,12 +1,12 @@
|
||||
//render.cpp
|
||||
inline void render_line_mode0();
|
||||
inline void render_line_mode1();
|
||||
inline void render_line_mode2();
|
||||
inline void render_line_mode3();
|
||||
inline void render_line_mode4();
|
||||
inline void render_line_mode5();
|
||||
inline void render_line_mode6();
|
||||
inline void render_line_mode7();
|
||||
debugvirtual inline void render_line_mode0();
|
||||
debugvirtual inline void render_line_mode1();
|
||||
debugvirtual inline void render_line_mode2();
|
||||
debugvirtual inline void render_line_mode3();
|
||||
debugvirtual inline void render_line_mode4();
|
||||
debugvirtual inline void render_line_mode5();
|
||||
debugvirtual inline void render_line_mode6();
|
||||
debugvirtual inline void render_line_mode7();
|
||||
|
||||
//cache.cpp
|
||||
enum { COLORDEPTH_4 = 0, COLORDEPTH_16 = 1, COLORDEPTH_256 = 2 };
|
||||
|
305
src/ppu/ppu-debugger.cpp
Normal file
@@ -0,0 +1,305 @@
|
||||
#ifdef PPU_CPP
|
||||
|
||||
bool PPUDebugger::property(unsigned id, string &name, string &value) {
|
||||
unsigned n = 0;
|
||||
|
||||
//internal
|
||||
if(id == n++) { name = "S-PPU1 MDR"; value = string::printf("0x%.2x", ppu1_mdr()); return true; }
|
||||
if(id == n++) { name = "S-PPU2 MDR"; value = string::printf("0x%.2x", ppu2_mdr()); return true; }
|
||||
|
||||
//$2100
|
||||
if(id == n++) { name = "$2100"; value = ""; return true; }
|
||||
if(id == n++) { name = "Display Disable"; value = display_disable(); return true; }
|
||||
if(id == n++) { name = "Display Brightness"; value = display_brightness(); return true; }
|
||||
|
||||
//$2101
|
||||
if(id == n++) { name = "$2101"; value = ""; return true; }
|
||||
if(id == n++) { name = "OAM Base Size"; value = oam_base_size(); return true; }
|
||||
if(id == n++) { name = "OAM Name Select"; value = oam_name_select(); return true; }
|
||||
if(id == n++) { name = "OAM Name Base Address"; value = string::printf("0x%.4x", oam_name_base_address()); return true; }
|
||||
|
||||
//$2102-$2103
|
||||
if(id == n++) { name = "$2102-$2103"; value = ""; return true; }
|
||||
if(id == n++) { name = "OAM Base Address"; value = string::printf("0x%.4x", oam_base_address()); return true; }
|
||||
if(id == n++) { name = "OAM Priority"; value = oam_priority(); return true; }
|
||||
|
||||
//$2105
|
||||
if(id == n++) { name = "$2105"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG1 Tile Size"; value = bg1_tile_size() ? "16x16" : "8x8"; return true; }
|
||||
if(id == n++) { name = "BG2 Tile Size"; value = bg2_tile_size() ? "16x16" : "8x8"; return true; }
|
||||
if(id == n++) { name = "BG3 Tile Size"; value = bg3_tile_size() ? "16x16" : "8x8"; return true; }
|
||||
if(id == n++) { name = "BG4 Tile Size"; value = bg4_tile_size() ? "16x16" : "8x8"; return true; }
|
||||
if(id == n++) { name = "BG3 Priority"; value = bg3_priority(); return true; }
|
||||
if(id == n++) { name = "BG Mode"; value = bg_mode(); return true; }
|
||||
|
||||
//$2106
|
||||
if(id == n++) { name = "$2106"; value = ""; return true; }
|
||||
if(id == n++) { name = "Mosaic Size"; value = mosaic_size(); return true; }
|
||||
if(id == n++) { name = "BG1 Mosaic Enable"; value = bg1_mosaic_enable(); return true; }
|
||||
if(id == n++) { name = "BG2 Mosaic Enable"; value = bg2_mosaic_enable(); return true; }
|
||||
if(id == n++) { name = "BG3 Mosaic Enable"; value = bg3_mosaic_enable(); return true; }
|
||||
if(id == n++) { name = "BG4 Mosaic Enable"; value = bg4_mosaic_enable(); return true; }
|
||||
|
||||
static char screen_size[4][8] = { "32x32", "32x64", "64x32", "64x64" };
|
||||
|
||||
//$2107
|
||||
if(id == n++) { name = "$2107"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG1 Screen Address"; value = string::printf("0x%.4x", bg1_screen_address()); return true; }
|
||||
if(id == n++) { name = "BG1 Screen Size"; value = screen_size[bg1_screen_size()]; return true; }
|
||||
|
||||
//$2108
|
||||
if(id == n++) { name = "$2108"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG2 Screen Address"; value = string::printf("0x%.4x", bg2_screen_address()); return true; }
|
||||
if(id == n++) { name = "BG2 Screen Size"; value = screen_size[bg2_screen_size()]; return true; }
|
||||
|
||||
//$2109
|
||||
if(id == n++) { name = "$2109"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG3 Screen Address"; value = string::printf("0x%.4x", bg3_screen_address()); return true; }
|
||||
if(id == n++) { name = "BG3 Screen Size"; value = screen_size[bg3_screen_size()]; return true; }
|
||||
|
||||
//$210a
|
||||
if(id == n++) { name = "$210a"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG4 Screen Address"; value = string::printf("0x%.4x", bg4_screen_address()); return true; }
|
||||
if(id == n++) { name = "BG4 Screen Size"; value = screen_size[bg4_screen_size()]; return true; }
|
||||
|
||||
//$210b
|
||||
if(id == n++) { name = "$210b"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG1 Name Base Address"; value = string::printf("0x%.4x", bg1_name_base_address()); return true; }
|
||||
if(id == n++) { name = "BG2 Name Base Address"; value = string::printf("0x%.4x", bg2_name_base_address()); return true; }
|
||||
|
||||
//$210c
|
||||
if(id == n++) { name = "$210c"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG3 Name Base Address"; value = string::printf("0x%.4x", bg3_name_base_address()); return true; }
|
||||
if(id == n++) { name = "BG4 Name Base Address"; value = string::printf("0x%.4x", bg4_name_base_address()); return true; }
|
||||
|
||||
//$210d
|
||||
if(id == n++) { name = "$210d"; value = ""; return true; }
|
||||
if(id == n++) { name = "Mode 7 Scroll H-offset"; value = mode7_hoffset(); return true; }
|
||||
if(id == n++) { name = "BG1 Scroll H-offset"; value = bg1_hoffset(); return true; }
|
||||
|
||||
//$210e
|
||||
if(id == n++) { name = "$210e"; value = ""; return true; }
|
||||
if(id == n++) { name = "Mode 7 Scroll V-offset"; value = mode7_voffset(); return true; }
|
||||
if(id == n++) { name = "BG1 Scroll V-offset"; value = bg1_voffset(); return true; }
|
||||
|
||||
//$210f
|
||||
if(id == n++) { name = "$210f"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG2 Scroll H-offset"; value = bg2_hoffset(); return true; }
|
||||
|
||||
//$2110
|
||||
if(id == n++) { name = "$2110"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG2 Scroll V-offset"; value = bg2_voffset(); return true; }
|
||||
|
||||
//$2111
|
||||
if(id == n++) { name = "$2111"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG3 Scroll H-offset"; value = bg3_hoffset(); return true; }
|
||||
|
||||
//$2112
|
||||
if(id == n++) { name = "$2112"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG3 Scroll V-offset"; value = bg3_voffset(); return true; }
|
||||
|
||||
//$2113
|
||||
if(id == n++) { name = "$2113"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG4 Scroll H-offset"; value = bg4_hoffset(); return true; }
|
||||
|
||||
//$2114
|
||||
if(id == n++) { name = "$2114"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG4 Scroll V-offset"; value = bg4_voffset(); return true; }
|
||||
|
||||
//$2115
|
||||
if(id == n++) { name = "$2115"; value = ""; return true; }
|
||||
if(id == n++) { name = "VRAM Increment Mode"; value = (unsigned)vram_increment_mode(); return true; }
|
||||
if(id == n++) { name = "VRAM Increment Formation"; value = vram_increment_formation(); return true; }
|
||||
if(id == n++) { name = "VRAM Increment Size"; value = vram_increment_size(); return true; }
|
||||
|
||||
//$2116-$2117
|
||||
if(id == n++) { name = "$2116-$2117"; value = ""; return true; }
|
||||
if(id == n++) { name = "VRAM Address"; value = string::printf("0x%.4x", vram_address()); return true; }
|
||||
|
||||
//$211a
|
||||
if(id == n++) { name = "$211a"; value = ""; return true; }
|
||||
if(id == n++) { name = "Mode 7 Repeat"; value = mode7_repeat(); return true; }
|
||||
if(id == n++) { name = "Mode 7 V-flip"; value = mode7_vflip(); return true; }
|
||||
if(id == n++) { name = "Mode 7 H-flip"; value = mode7_hflip(); return true; }
|
||||
|
||||
//$211b
|
||||
if(id == n++) { name = "$211b"; value = ""; return true; }
|
||||
if(id == n++) { name = "Mode 7 A"; value = mode7_a(); return true; }
|
||||
|
||||
//$211c
|
||||
if(id == n++) { name = "$211c"; value = ""; return true; }
|
||||
if(id == n++) { name = "Mode 7 B"; value = mode7_b(); return true; }
|
||||
|
||||
//$211d
|
||||
if(id == n++) { name = "$211d"; value = ""; return true; }
|
||||
if(id == n++) { name = "Mode 7 C"; value = mode7_c(); return true; }
|
||||
|
||||
//$211e
|
||||
if(id == n++) { name = "$211e"; value = ""; return true; }
|
||||
if(id == n++) { name = "Mode 7 D"; value = mode7_d(); return true; }
|
||||
|
||||
//$211f
|
||||
if(id == n++) { name = "$211f"; value = ""; return true; }
|
||||
if(id == n++) { name = "Mode 7 X"; value = mode7_x(); return true; }
|
||||
|
||||
//$2120
|
||||
if(id == n++) { name = "$2120"; value = ""; return true; }
|
||||
if(id == n++) { name = "Mode 7 Y"; value = mode7_y(); return true; }
|
||||
|
||||
//$2121
|
||||
if(id == n++) { name = "$2121"; value = ""; return true; }
|
||||
if(id == n++) { name = "CGRAM Address"; value = string::printf("0x%.4x", cgram_address()); return true; }
|
||||
|
||||
//$2123
|
||||
if(id == n++) { name = "$2123"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG1 Window 1 Enable"; value = bg1_window1_enable(); return true; }
|
||||
if(id == n++) { name = "BG1 Window 1 Invert"; value = bg1_window1_invert(); return true; }
|
||||
if(id == n++) { name = "BG1 Window 2 Enable"; value = bg1_window2_enable(); return true; }
|
||||
if(id == n++) { name = "BG1 Window 2 Invert"; value = bg1_window2_invert(); return true; }
|
||||
if(id == n++) { name = "BG2 Window 1 Enable"; value = bg2_window1_enable(); return true; }
|
||||
if(id == n++) { name = "BG2 Window 1 Invert"; value = bg2_window1_invert(); return true; }
|
||||
if(id == n++) { name = "BG2 Window 2 Enable"; value = bg2_window2_enable(); return true; }
|
||||
if(id == n++) { name = "BG2 Window 2 Invert"; value = bg2_window2_invert(); return true; }
|
||||
|
||||
//$2124
|
||||
if(id == n++) { name = "$2124"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG3 Window 1 Enable"; value = bg3_window1_enable(); return true; }
|
||||
if(id == n++) { name = "BG3 Window 1 Invert"; value = bg3_window1_invert(); return true; }
|
||||
if(id == n++) { name = "BG3 Window 2 Enable"; value = bg3_window2_enable(); return true; }
|
||||
if(id == n++) { name = "BG3 Window 2 Invert"; value = bg3_window2_invert(); return true; }
|
||||
if(id == n++) { name = "BG4 Window 1 Enable"; value = bg4_window1_enable(); return true; }
|
||||
if(id == n++) { name = "BG4 Window 1 Invert"; value = bg4_window1_invert(); return true; }
|
||||
if(id == n++) { name = "BG4 Window 2 Enable"; value = bg4_window2_enable(); return true; }
|
||||
if(id == n++) { name = "BG4 Window 2 Invert"; value = bg4_window2_invert(); return true; }
|
||||
|
||||
//$2125
|
||||
if(id == n++) { name = "$2125"; value = ""; return true; }
|
||||
if(id == n++) { name = "OAM Window 1 Enable"; value = oam_window1_enable(); return true; }
|
||||
if(id == n++) { name = "OAM Window 1 Invert"; value = oam_window1_invert(); return true; }
|
||||
if(id == n++) { name = "OAM Window 2 Enable"; value = oam_window2_enable(); return true; }
|
||||
if(id == n++) { name = "OAM Window 2 Invert"; value = oam_window2_invert(); return true; }
|
||||
if(id == n++) { name = "Color Window 1 Enable"; value = color_window1_enable(); return true; }
|
||||
if(id == n++) { name = "Color Window 1 Invert"; value = color_window1_invert(); return true; }
|
||||
if(id == n++) { name = "Color Window 2 Enable"; value = color_window2_enable(); return true; }
|
||||
if(id == n++) { name = "Color Window 2 Invert"; value = color_window2_invert(); return true; }
|
||||
|
||||
//$2126
|
||||
if(id == n++) { name = "$2126"; value = ""; return true; }
|
||||
if(id == n++) { name = "Window 1 Left"; value = window1_left(); return true; }
|
||||
|
||||
//$2127
|
||||
if(id == n++) { name = "$2127"; value = ""; return true; }
|
||||
if(id == n++) { name = "Window 1 Right"; value = window1_right(); return true; }
|
||||
|
||||
//$2128
|
||||
if(id == n++) { name = "$2128"; value = ""; return true; }
|
||||
if(id == n++) { name = "Window 2 Left"; value = window2_left(); return true; }
|
||||
|
||||
//$2129
|
||||
if(id == n++) { name = "$2129"; value = ""; return true; }
|
||||
if(id == n++) { name = "Window 2 Right"; value = window2_right(); return true; }
|
||||
|
||||
static char window_mask_mode[4][8] = { "OR", "AND", "XOR", "XNOR" };
|
||||
|
||||
//$212a
|
||||
if(id == n++) { name = "$212a"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG1 Window Mask"; value = window_mask_mode[bg1_window_mask()]; return true; }
|
||||
if(id == n++) { name = "BG2 Window Mask"; value = window_mask_mode[bg2_window_mask()]; return true; }
|
||||
if(id == n++) { name = "BG3 Window Mask"; value = window_mask_mode[bg3_window_mask()]; return true; }
|
||||
if(id == n++) { name = "BG4 Window Mask"; value = window_mask_mode[bg4_window_mask()]; return true; }
|
||||
|
||||
//$212b
|
||||
if(id == n++) { name = "$212b"; value = ""; return true; }
|
||||
if(id == n++) { name = "OAM Window Mask"; value = window_mask_mode[oam_window_mask()]; return true; }
|
||||
if(id == n++) { name = "Color Window Mask"; value = window_mask_mode[color_window_mask()]; return true; }
|
||||
|
||||
//$212c
|
||||
if(id == n++) { name = "$212c"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG1 Mainscreen Enable"; value = bg1_mainscreen_enable(); return true; }
|
||||
if(id == n++) { name = "BG2 Mainscreen Enable"; value = bg2_mainscreen_enable(); return true; }
|
||||
if(id == n++) { name = "BG3 Mainscreen Enable"; value = bg3_mainscreen_enable(); return true; }
|
||||
if(id == n++) { name = "BG4 Mainscreen Enable"; value = bg4_mainscreen_enable(); return true; }
|
||||
if(id == n++) { name = "OAM Mainscreen Enable"; value = oam_mainscreen_enable(); return true; }
|
||||
|
||||
//$212d
|
||||
if(id == n++) { name = "$212d"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG1 Subscreen Enable"; value = bg1_subscreen_enable(); return true; }
|
||||
if(id == n++) { name = "BG2 Subscreen Enable"; value = bg2_subscreen_enable(); return true; }
|
||||
if(id == n++) { name = "BG3 Subscreen Enable"; value = bg3_subscreen_enable(); return true; }
|
||||
if(id == n++) { name = "BG4 Subscreen Enable"; value = bg4_subscreen_enable(); return true; }
|
||||
if(id == n++) { name = "OAM Subscreen Enable"; value = oam_subscreen_enable(); return true; }
|
||||
|
||||
//$212e
|
||||
if(id == n++) { name = "$212e"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG1 Mainscreen Window Enable"; value = bg1_mainscreen_window_enable(); return true; }
|
||||
if(id == n++) { name = "BG2 Mainscreen Window Enable"; value = bg2_mainscreen_window_enable(); return true; }
|
||||
if(id == n++) { name = "BG3 Mainscreen Window Enable"; value = bg3_mainscreen_window_enable(); return true; }
|
||||
if(id == n++) { name = "BG4 Mainscreen Window Enable"; value = bg4_mainscreen_window_enable(); return true; }
|
||||
if(id == n++) { name = "OAM Mainscreen Window Enable"; value = oam_mainscreen_window_enable(); return true; }
|
||||
|
||||
//$212f
|
||||
if(id == n++) { name = "$212f"; value = ""; return true; }
|
||||
if(id == n++) { name = "BG1 Subscreen Window Enable"; value = bg1_subscreen_window_enable(); return true; }
|
||||
if(id == n++) { name = "BG2 Subscreen Window Enable"; value = bg2_subscreen_window_enable(); return true; }
|
||||
if(id == n++) { name = "BG3 Subscreen Window Enable"; value = bg3_subscreen_window_enable(); return true; }
|
||||
if(id == n++) { name = "BG4 Subscreen Window Enable"; value = bg4_subscreen_window_enable(); return true; }
|
||||
if(id == n++) { name = "OAM Subscreen Window Enable"; value = oam_subscreen_window_enable(); return true; }
|
||||
|
||||
static char color_window_mask_mode[4][32] = { "Always", "Never", "Inside Window Only", "Outside Window Only" };
|
||||
|
||||
//$2130
|
||||
if(id == n++) { name = "$2130"; value = ""; return true; }
|
||||
if(id == n++) { name = "Color Mainscreen Window Mask"; value = color_window_mask_mode[color_mainscreen_window_mask()]; return true; }
|
||||
if(id == n++) { name = "Color Subscreen Window Mask"; value = color_window_mask_mode[color_subscreen_window_mask()]; return true; }
|
||||
if(id == n++) { name = "Color Add/Subtract Mode"; value = !color_add_subtract_mode() ? "Fixed Color" : "Subscreen"; return true; }
|
||||
if(id == n++) { name = "Direct Color"; value = direct_color(); return true; }
|
||||
|
||||
//$2131
|
||||
if(id == n++) { name = "$2131"; value = ""; return true; }
|
||||
if(id == n++) { name = "Color Mode"; value = !color_mode() ? "Add" : "Subtract"; return true; }
|
||||
if(id == n++) { name = "Color Halve"; value = color_halve(); return true; }
|
||||
if(id == n++) { name = "BG1 Color Enable"; value = bg1_color_enable(); return true; }
|
||||
if(id == n++) { name = "BG2 Color Enable"; value = bg2_color_enable(); return true; }
|
||||
if(id == n++) { name = "BG3 Color Enable"; value = bg3_color_enable(); return true; }
|
||||
if(id == n++) { name = "BG4 Color Enable"; value = bg4_color_enable(); return true; }
|
||||
if(id == n++) { name = "OAM Color Enable"; value = oam_color_enable(); return true; }
|
||||
if(id == n++) { name = "Back Color Enable"; value = back_color_enable(); return true; }
|
||||
|
||||
//$2132
|
||||
if(id == n++) { name = "$2132"; value = ""; return true; }
|
||||
if(id == n++) { name = "Color Constant - Blue"; value = color_constant_blue(); return true; }
|
||||
if(id == n++) { name = "Color Constant - Green"; value = color_constant_green(); return true; }
|
||||
if(id == n++) { name = "Color Constant - Red"; value = color_constant_red(); return true; }
|
||||
|
||||
//$2133
|
||||
if(id == n++) { name = "$2133"; value = ""; return true; }
|
||||
if(id == n++) { name = "Mode 7 EXTBG"; value = mode7_extbg(); return true; }
|
||||
if(id == n++) { name = "Pseudo Hires"; value = pseudo_hires(); return true; }
|
||||
if(id == n++) { name = "Overscan"; value = overscan(); return true; }
|
||||
if(id == n++) { name = "OAM Interlace"; value = oam_interlace(); return true; }
|
||||
if(id == n++) { name = "Interlace"; value = interlace(); return true; }
|
||||
|
||||
//$213c
|
||||
if(id == n++) { name = "$213c"; value = ""; return true; }
|
||||
if(id == n++) { name = "H-counter"; value = hcounter(); return true; }
|
||||
|
||||
//$213d
|
||||
if(id == n++) { name = "$213d"; value = ""; return true; }
|
||||
if(id == n++) { name = "V-counter"; value = vcounter(); return true; }
|
||||
|
||||
//$213e
|
||||
if(id == n++) { name = "$213e"; value = ""; return true; }
|
||||
if(id == n++) { name = "Range Over"; value = range_over(); return true; }
|
||||
if(id == n++) { name = "Time Over"; value = time_over(); return true; }
|
||||
if(id == n++) { name = "S-PPU1 Version"; value = ppu1_version(); return true; }
|
||||
|
||||
//$213f
|
||||
if(id == n++) { name = "$213f"; value = ""; return true; }
|
||||
if(id == n++) { name = "Field"; value = field(); return true; }
|
||||
if(id == n++) { name = "Region"; value = !region() ? "NTSC" : "PAL"; return true; }
|
||||
if(id == n++) { name = "S-PPU2 Version"; value = ppu2_version(); return true; }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
243
src/ppu/ppu-debugger.hpp
Normal file
@@ -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; }
|
||||
|