mirror of https://github.com/bsnes-emu/bsnes.git
Update to 20100808 release.
byuu says: This fixes libsnes and debugger builds, and collapses bsnes/ppu/bppu to bsnes/ppu and bsnes/dsp/sdsp to bsnes/dsp. It also introduces bsnes/sync.sh, which will synchronize all of asnes/ with bsnes/, excepting the custom speed-focused modules. So far, that's bsnes/ppu (scanline renderer) and bsnes/dsp (state machine.) Should make keeping the two ports in sync much, much easier. It's basically the same thing as before, only you run sync.sh and have a few duplicated folders now. May make it clearer by creating a stub/ or src/ folder inside bsnes to do all of the copying, so that you only see the custom folders in bsnes/' root directory.
This commit is contained in:
parent
165f1e74b5
commit
b85025263a
2
Makefile
2
Makefile
|
@ -1,5 +1,5 @@
|
|||
include nall/Makefile
|
||||
snes := asnes
|
||||
snes := bsnes
|
||||
ui := qt
|
||||
|
||||
# compiler
|
||||
|
|
|
@ -50,22 +50,22 @@ snes_objects := $(patsubst %,obj/%.o,$(snes_objects))
|
|||
|
||||
library: $(snes_objects) obj/libsnes.o
|
||||
ifeq ($(platform),x)
|
||||
ar rcs obj/libsnes.a $(snes_objects) obj/libsnes.o
|
||||
$(cpp) -o obj/libsnes.so -shared -Wl,-soname,libsnes.so.1 $(snes_objects) obj/libsnes.o
|
||||
ar rcs out/libsnes.a $(snes_objects) obj/libsnes.o
|
||||
$(cpp) -o out/libsnes.so -shared -Wl,-soname,libsnes.so.1 $(snes_objects) obj/libsnes.o
|
||||
else ifeq ($(platform),osx)
|
||||
ar rcs obj/libsnes.a $(snes_objects) obj/libsnes.o
|
||||
$(cpp) -o obj/libsnes.dylib -install_name @executable_path/../Libraries/libsnes.dylib -shared -dynamiclib $(snes_objects) obj/libsnes.o
|
||||
ar rcs out/libsnes.a $(snes_objects) obj/libsnes.o
|
||||
$(cpp) -o out/libsnes.dylib -install_name @executable_path/../Libraries/libsnes.dylib -shared -dynamiclib $(snes_objects) obj/libsnes.o
|
||||
else ifeq ($(platform),win)
|
||||
$(cpp) -o obj/snes.dll -shared -Wl,--out-implib,libsnes.a $(snes_objects) obj/libsnes.o
|
||||
$(cpp) -o out/snes.dll -shared -Wl,--out-implib,libsnes.a $(snes_objects) obj/libsnes.o
|
||||
endif
|
||||
|
||||
library-install:
|
||||
ifeq ($(platform),x)
|
||||
install -D -m 755 obj/libsnes.a $(DESTDIR)$(prefix)/lib/libsnes.a
|
||||
install -D -m 755 obj/libsnes.so $(DESTDIR)$(prefix)/lib/libsnes.so
|
||||
install -D -m 755 out/libsnes.a $(DESTDIR)$(prefix)/lib/libsnes.a
|
||||
install -D -m 755 out/libsnes.so $(DESTDIR)$(prefix)/lib/libsnes.so
|
||||
ldconfig -n $(DESTDIR)$(prefix)/lib
|
||||
else ifeq ($(platform),osx)
|
||||
cp obj/libsnes.dylib /usr/local/lib/libsnes.dylib
|
||||
cp out/libsnes.dylib /usr/local/lib/libsnes.dylib
|
||||
endif
|
||||
|
||||
library-uninstall:
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
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; }
|
||||
|
||||
//$420b
|
||||
virtual unsigned dma_enable() { return 0; }
|
||||
|
||||
//$420c
|
||||
virtual unsigned hdma_enable() { return 0; }
|
||||
|
||||
//$420d
|
||||
virtual bool fastrom_enable() { return 0; }
|
||||
|
||||
//$43x0
|
||||
virtual bool dma_direction(unsigned) { return 0; }
|
||||
virtual bool dma_indirect(unsigned) { return 0; }
|
||||
virtual bool dma_reverse_transfer(unsigned) { return 0; }
|
||||
virtual bool dma_fixed_transfer(unsigned) { return 0; }
|
||||
virtual unsigned dma_transfer_mode(unsigned) { return 0; }
|
||||
|
||||
//$43x1
|
||||
virtual unsigned dma_bbus_address(unsigned) { return 0; }
|
||||
|
||||
//$43x2-$43x3
|
||||
virtual unsigned dma_abus_address(unsigned) { return 0; }
|
||||
|
||||
//$43x4
|
||||
virtual unsigned dma_abus_bank(unsigned) { return 0; }
|
||||
|
||||
//$43x5-$43x6
|
||||
virtual unsigned dma_transfer_size(unsigned) { return 0; }
|
||||
|
||||
//$43x7
|
||||
virtual unsigned dma_indirect_bank(unsigned) { return 0; }
|
||||
|
||||
//$43x8-$43x9
|
||||
virtual unsigned dma_table_address(unsigned addr) { return 0; }
|
||||
|
||||
//$43xa
|
||||
virtual unsigned dma_line_counter(unsigned addr) { return 0; }
|
||||
};
|
|
@ -1,6 +1,102 @@
|
|||
#ifdef CPU_CPP
|
||||
|
||||
void sCPUDebugger::op_step() {
|
||||
bool CPUDebugger::property(unsigned id, string &name, string &value) {
|
||||
unsigned n = 0;
|
||||
|
||||
//internal
|
||||
if(id == n++) { name = "S-CPU MDR"; value = string("0x", strhex<2>(mdr())); return true; }
|
||||
|
||||
//$2181-2183
|
||||
if(id == n++) { name = "$2181-$2183"; value = ""; return true; }
|
||||
if(id == n++) { name = "WRAM Address"; value = string("0x", strhex<6>(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("0x", strhex<2>(pio_bits())); return true; }
|
||||
|
||||
//$4202
|
||||
if(id == n++) { name = "$4202"; value = ""; return true; }
|
||||
if(id == n++) { name = "Multiplicand"; value = string("0x", strhex<2>(multiplicand())); return true; }
|
||||
|
||||
//$4203
|
||||
if(id == n++) { name = "$4203"; value = ""; return true; }
|
||||
if(id == n++) { name = "Multiplier"; value = string("0x", strhex<2>(multiplier())); return true; }
|
||||
|
||||
//$4204-$4205
|
||||
if(id == n++) { name = "$4204-$4205"; value = ""; return true; }
|
||||
if(id == n++) { name = "Dividend"; value = string("0x", strhex<4>(dividend())); return true; }
|
||||
|
||||
//$4206
|
||||
if(id == n++) { name = "$4206"; value = ""; return true; }
|
||||
if(id == n++) { name = "Divisor"; value = string("0x", strhex<2>(divisor())); return true; }
|
||||
|
||||
//$4207-$4208
|
||||
if(id == n++) { name = "$4207-$4208"; value = ""; return true; }
|
||||
if(id == n++) { name = "H-Time"; value = string("0x", strhex<4>(htime())); return true; }
|
||||
|
||||
//$4209-$420a
|
||||
if(id == n++) { name = "$4209-$420a"; value = ""; return true; }
|
||||
if(id == n++) { name = "V-Time"; value = string("0x", strhex<4>(vtime())); return true; }
|
||||
|
||||
//$420b
|
||||
if(id == n++) { name = "$420b"; value = ""; return true; }
|
||||
if(id == n++) { name = "DMA Enable"; value = string("0x", strhex<2>(dma_enable())); return true; }
|
||||
|
||||
//$420c
|
||||
if(id == n++) { name = "$420c"; value = ""; return true; }
|
||||
if(id == n++) { name = "HDMA Enable"; value = string("0x", strhex<2>(hdma_enable())); return true; }
|
||||
|
||||
//$420d
|
||||
if(id == n++) { name = "$420d"; value = ""; return true; }
|
||||
if(id == n++) { name = "FastROM Enable"; value = fastrom_enable(); return true; }
|
||||
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
if(id == n++) { name = string() << "DMA Channel " << i; return true; }
|
||||
|
||||
//$43x0
|
||||
if(id == n++) { name = "Direction"; value = dma_direction(i); return true; }
|
||||
if(id == n++) { name = "Indirect"; value = dma_indirect(i); return true; }
|
||||
if(id == n++) { name = "Reverse Transfer"; value = dma_reverse_transfer(i); return true; }
|
||||
if(id == n++) { name = "Fixed Transfer"; value = dma_fixed_transfer(i); return true; }
|
||||
if(id == n++) { name = "Transfer Mode"; value = dma_transfer_mode(i); return true; }
|
||||
|
||||
//$43x1
|
||||
if(id == n++) { name = "B-Bus Address"; value = string("0x", strhex<4>(dma_bbus_address(i))); return true; }
|
||||
|
||||
//$43x2-$43x3
|
||||
if(id == n++) { name = "A-Bus Address"; value = string("0x", strhex<4>(dma_abus_address(i))); return true; }
|
||||
|
||||
//$43x4
|
||||
if(id == n++) { name = "A-Bus Bank"; value = string("0x", strhex<2>(dma_abus_bank(i))); return true; }
|
||||
|
||||
//$43x5-$43x6
|
||||
if(id == n++) { name = "Transfer Size / Indirect Address"; value = string("0x", strhex<4>(dma_transfer_size(i))); return true; }
|
||||
|
||||
//$43x7
|
||||
if(id == n++) { name = "Indirect Bank"; value = string("0x", strhex<2>(dma_indirect_bank(i))); return true; }
|
||||
|
||||
//$43x8-$43x9
|
||||
if(id == n++) { name = "Table Address"; value = string("0x", strhex<4>(dma_table_address(i))); return true; }
|
||||
|
||||
//$43xa
|
||||
if(id == n++) { name = "Line Counter"; value = string("0x", strhex<2>(dma_line_counter(i))); return true; }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CPUDebugger::op_step() {
|
||||
bool break_event = false;
|
||||
|
||||
usage[regs.pc] &= ~(UsageFlagM | UsageFlagX);
|
||||
|
@ -15,75 +111,71 @@ void sCPUDebugger::op_step() {
|
|||
}
|
||||
|
||||
if(step_event) step_event();
|
||||
sCPU::op_step();
|
||||
CPU::op_step();
|
||||
synchronize_smp();
|
||||
}
|
||||
|
||||
uint8 sCPUDebugger::op_read(uint32 addr) {
|
||||
uint8 data = sCPU::op_read(addr);
|
||||
uint8 CPUDebugger::op_read(uint32 addr) {
|
||||
uint8 data = CPU::op_read(addr);
|
||||
usage[addr] |= UsageRead;
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Read, addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void sCPUDebugger::op_write(uint32 addr, uint8 data) {
|
||||
sCPU::op_write(addr, data);
|
||||
void CPUDebugger::op_write(uint32 addr, uint8 data) {
|
||||
CPU::op_write(addr, data);
|
||||
usage[addr] |= UsageWrite;
|
||||
usage[addr] &= ~UsageExec;
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Write, addr, data);
|
||||
}
|
||||
|
||||
sCPUDebugger::sCPUDebugger() {
|
||||
CPUDebugger::CPUDebugger() {
|
||||
usage = new uint8[1 << 24]();
|
||||
opcode_pc = 0x8000;
|
||||
}
|
||||
|
||||
sCPUDebugger::~sCPUDebugger() {
|
||||
CPUDebugger::~CPUDebugger() {
|
||||
delete[] usage;
|
||||
}
|
||||
|
||||
//===========
|
||||
//CPUDebugger
|
||||
//===========
|
||||
|
||||
//internal
|
||||
unsigned sCPUDebugger::mdr() { return regs.mdr; }
|
||||
unsigned CPUDebugger::mdr() { return regs.mdr; }
|
||||
|
||||
//$2181-$2183
|
||||
unsigned sCPUDebugger::wram_address() { return status.wram_addr; }
|
||||
unsigned CPUDebugger::wram_address() { return status.wram_addr; }
|
||||
|
||||
//$4016
|
||||
bool sCPUDebugger::joypad_strobe_latch() { return status.joypad_strobe_latch; }
|
||||
bool CPUDebugger::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; }
|
||||
bool CPUDebugger::nmi_enable() { return status.nmi_enabled; }
|
||||
bool CPUDebugger::hirq_enable() { return status.hirq_enabled; }
|
||||
bool CPUDebugger::virq_enable() { return status.virq_enabled; }
|
||||
bool CPUDebugger::auto_joypad_poll() { return status.auto_joypad_poll; }
|
||||
|
||||
//$4201
|
||||
unsigned sCPUDebugger::pio_bits() { return status.pio; }
|
||||
unsigned CPUDebugger::pio_bits() { return status.pio; }
|
||||
|
||||
//$4202
|
||||
unsigned sCPUDebugger::multiplicand() { return status.wrmpya; }
|
||||
unsigned CPUDebugger::multiplicand() { return status.wrmpya; }
|
||||
|
||||
//$4203
|
||||
unsigned sCPUDebugger::multiplier() { return status.wrmpyb; }
|
||||
unsigned CPUDebugger::multiplier() { return status.wrmpyb; }
|
||||
|
||||
//$4204-$4205
|
||||
unsigned sCPUDebugger::dividend() { return status.wrdiva; }
|
||||
unsigned CPUDebugger::dividend() { return status.wrdiva; }
|
||||
|
||||
//$4206
|
||||
unsigned sCPUDebugger::divisor() { return status.wrdivb; }
|
||||
unsigned CPUDebugger::divisor() { return status.wrdivb; }
|
||||
|
||||
//$4207-$4208
|
||||
unsigned sCPUDebugger::htime() { return status.hirq_pos; }
|
||||
unsigned CPUDebugger::htime() { return status.hirq_pos; }
|
||||
|
||||
//$4209-$420a
|
||||
unsigned sCPUDebugger::vtime() { return status.virq_pos; }
|
||||
unsigned CPUDebugger::vtime() { return status.virq_pos; }
|
||||
|
||||
//$420b
|
||||
unsigned sCPUDebugger::dma_enable() {
|
||||
unsigned CPUDebugger::dma_enable() {
|
||||
unsigned result = 0;
|
||||
for(unsigned n = 0; n < 8; n++) {
|
||||
result |= channel[n].dma_enabled << n;
|
||||
|
@ -92,7 +184,7 @@ unsigned sCPUDebugger::dma_enable() {
|
|||
}
|
||||
|
||||
//$420c
|
||||
unsigned sCPUDebugger::hdma_enable() {
|
||||
unsigned CPUDebugger::hdma_enable() {
|
||||
unsigned result = 0;
|
||||
for(unsigned n = 0; n < 8; n++) {
|
||||
result |= channel[n].hdma_enabled << n;
|
||||
|
@ -101,34 +193,34 @@ unsigned sCPUDebugger::hdma_enable() {
|
|||
}
|
||||
|
||||
//$420d
|
||||
bool sCPUDebugger::fastrom_enable() { return status.rom_speed; }
|
||||
bool CPUDebugger::fastrom_enable() { return status.rom_speed; }
|
||||
|
||||
//$43x0
|
||||
bool sCPUDebugger::dma_direction(unsigned n) { return channel[n].direction; }
|
||||
bool sCPUDebugger::dma_indirect(unsigned n) { return channel[n].hdma_indirect; }
|
||||
bool sCPUDebugger::dma_reverse_transfer(unsigned n) { return channel[n].reversexfer; }
|
||||
bool sCPUDebugger::dma_fixed_transfer(unsigned n) { return channel[n].fixedxfer; }
|
||||
unsigned sCPUDebugger::dma_transfer_mode(unsigned n) { return channel[n].xfermode; }
|
||||
bool CPUDebugger::dma_direction(unsigned n) { return channel[n].direction; }
|
||||
bool CPUDebugger::dma_indirect(unsigned n) { return channel[n].hdma_indirect; }
|
||||
bool CPUDebugger::dma_reverse_transfer(unsigned n) { return channel[n].reversexfer; }
|
||||
bool CPUDebugger::dma_fixed_transfer(unsigned n) { return channel[n].fixedxfer; }
|
||||
unsigned CPUDebugger::dma_transfer_mode(unsigned n) { return channel[n].xfermode; }
|
||||
|
||||
//$43x1
|
||||
unsigned sCPUDebugger::dma_bbus_address(unsigned n) { return 0x2100 + channel[n].destaddr; }
|
||||
unsigned CPUDebugger::dma_bbus_address(unsigned n) { return 0x2100 + channel[n].destaddr; }
|
||||
|
||||
//$43x2-$43x3
|
||||
unsigned sCPUDebugger::dma_abus_address(unsigned n) { return channel[n].srcaddr; }
|
||||
unsigned CPUDebugger::dma_abus_address(unsigned n) { return channel[n].srcaddr; }
|
||||
|
||||
//$43x4
|
||||
unsigned sCPUDebugger::dma_abus_bank(unsigned n) { return channel[n].srcbank; }
|
||||
unsigned CPUDebugger::dma_abus_bank(unsigned n) { return channel[n].srcbank; }
|
||||
|
||||
//$43x5-$43x6
|
||||
unsigned sCPUDebugger::dma_transfer_size(unsigned n) { return channel[n].xfersize; }
|
||||
unsigned CPUDebugger::dma_transfer_size(unsigned n) { return channel[n].xfersize; }
|
||||
|
||||
//$43x7
|
||||
unsigned sCPUDebugger::dma_indirect_bank(unsigned n) { return channel[n].hdma_ibank; }
|
||||
unsigned CPUDebugger::dma_indirect_bank(unsigned n) { return channel[n].hdma_ibank; }
|
||||
|
||||
//$43x8-$43x9
|
||||
unsigned sCPUDebugger::dma_table_address(unsigned n) { return channel[n].hdma_addr; }
|
||||
unsigned CPUDebugger::dma_table_address(unsigned n) { return channel[n].hdma_addr; }
|
||||
|
||||
//$43xa
|
||||
unsigned sCPUDebugger::dma_line_counter(unsigned n) { return channel[n].hdma_line_counter; }
|
||||
unsigned CPUDebugger::dma_line_counter(unsigned n) { return channel[n].hdma_line_counter; }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
class sCPUDebugger : public sCPU, public CPUDebugger {
|
||||
class CPUDebugger : public CPU, public ChipDebugger {
|
||||
public:
|
||||
bool property(unsigned id, string &name, string &value);
|
||||
|
||||
function<void ()> step_event;
|
||||
|
||||
enum Usage {
|
||||
|
@ -16,12 +18,8 @@ public:
|
|||
uint8 op_read(uint32 addr);
|
||||
void op_write(uint32 addr, uint8 data);
|
||||
|
||||
sCPUDebugger();
|
||||
~sCPUDebugger();
|
||||
|
||||
//===========
|
||||
//CPUDebugger
|
||||
//===========
|
||||
CPUDebugger();
|
||||
~CPUDebugger();
|
||||
|
||||
//internal
|
||||
unsigned mdr();
|
||||
|
|
|
@ -1,36 +1,87 @@
|
|||
#ifdef DSP_CPP
|
||||
|
||||
bool DSPDebugger::property(unsigned id, string &name, string &value) {
|
||||
unsigned n = 0;
|
||||
|
||||
if(id == n++) { name = "Main Volume - Left"; value = main_volume_left(); return true; }
|
||||
if(id == n++) { name = "Main Volume - Right"; value = main_volume_right(); return true; }
|
||||
if(id == n++) { name = "Echo Volume - Left"; value = echo_volume_left(); return true; }
|
||||
if(id == n++) { name = "Echo Volume - Right"; value = echo_volume_right(); return true; }
|
||||
if(id == n++) { name = "Key On"; value = string("0x", strhex<2>(key_on())); return true; }
|
||||
if(id == n++) { name = "Key Off"; value = string("0x", strhex<2>(key_off())); return true; }
|
||||
if(id == n++) { name = "Flag - Reset"; value = flag_reset(); return true; }
|
||||
if(id == n++) { name = "Flag - Mute"; value = flag_mute(); return true; }
|
||||
if(id == n++) { name = "Flag - Echo Disable"; value = flag_echo_disable(); return true; }
|
||||
if(id == n++) { name = "Flag - Noise Clock"; value = flag_noise_clock(); return true; }
|
||||
if(id == n++) { name = "Source End Block"; value = source_end_block(); return true; }
|
||||
if(id == n++) { name = "Echo Feedback"; value = echo_feedback(); return true; }
|
||||
if(id == n++) { name = "Pitch Modulation Enable"; value = string("0x", strhex<2>(pitch_modulation_enable())); return true; }
|
||||
if(id == n++) { name = "Noise Enable"; value = string("0x", strhex<2>(noise_enable())); return true; }
|
||||
if(id == n++) { name = "Echo Enable"; value = string("0x", strhex<2>(echo_enable())); return true; }
|
||||
if(id == n++) { name = "Source Directory"; value = source_directory(); return true; }
|
||||
if(id == n++) { name = "Echo Start Address"; value = echo_start_address(); return true; }
|
||||
if(id == n++) { name = "Echo Directory"; value = echo_directory(); return true; }
|
||||
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
if(id == n++) {
|
||||
name = string("Coefficient ", i);
|
||||
value = string("0x", strhex<2>(echo_filter_coefficient(i)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
if(id == n++) {
|
||||
name = string("Voice ", i);
|
||||
value = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
if(id == n++) { name = "Volume - Left"; value = voice_volume_left(i); return true; }
|
||||
if(id == n++) { name = "Volume - Right"; value = voice_volume_right(i); return true; }
|
||||
if(id == n++) { name = "Pitch Height"; value = string("0x", strhex<4>(voice_pitch_height(i))); return true; }
|
||||
if(id == n++) { name = "Source Number"; value = voice_source_number(i); return true; }
|
||||
if(id == n++) { name = "ADSR1"; value = voice_adsr1(i); return true; }
|
||||
if(id == n++) { name = "ADSR2"; value = voice_adsr2(i); return true; }
|
||||
if(id == n++) { name = "GAIN"; value = voice_gain(i); return true; }
|
||||
if(id == n++) { name = "ENVX"; value = voice_envx(i); return true; }
|
||||
if(id == n++) { name = "OUTX"; value = voice_outx(i); return true; }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========
|
||||
//DSPDebugger
|
||||
//===========
|
||||
|
||||
unsigned sDSPDebugger::main_volume_left() { return state.regs[0x0c]; }
|
||||
unsigned sDSPDebugger::main_volume_right() { return state.regs[0x1c]; }
|
||||
unsigned sDSPDebugger::echo_volume_left() { return state.regs[0x2c]; }
|
||||
unsigned sDSPDebugger::echo_volume_right() { return state.regs[0x3c]; }
|
||||
unsigned sDSPDebugger::key_on() { return state.regs[0x4c]; }
|
||||
unsigned sDSPDebugger::key_off() { return state.regs[0x5c]; }
|
||||
bool sDSPDebugger::flag_reset() { return state.regs[0x6c] & 0x80; }
|
||||
bool sDSPDebugger::flag_mute() { return state.regs[0x6c] & 0x40; }
|
||||
bool sDSPDebugger::flag_echo_disable() { return state.regs[0x6c] & 0x20; }
|
||||
unsigned sDSPDebugger::flag_noise_clock() { return state.regs[0x6c] & 0x1f; }
|
||||
unsigned sDSPDebugger::source_end_block() { return state.regs[0x7c]; }
|
||||
unsigned sDSPDebugger::echo_feedback() { return state.regs[0x0d]; }
|
||||
unsigned sDSPDebugger::pitch_modulation_enable() { return state.regs[0x2d]; }
|
||||
unsigned sDSPDebugger::noise_enable() { return state.regs[0x3d]; }
|
||||
unsigned sDSPDebugger::echo_enable() { return state.regs[0x4d]; }
|
||||
unsigned sDSPDebugger::source_directory() { return state.regs[0x5d]; }
|
||||
unsigned sDSPDebugger::echo_start_address() { return state.regs[0x6d]; }
|
||||
unsigned sDSPDebugger::echo_directory() { return state.regs[0x7d]; }
|
||||
unsigned sDSPDebugger::echo_filter_coefficient(unsigned n) { return state.regs[(n << 4) + 0x0f]; }
|
||||
unsigned sDSPDebugger::voice_volume_left(unsigned n) { return state.regs[(n << 4) + 0x00]; }
|
||||
unsigned sDSPDebugger::voice_volume_right(unsigned n) { return state.regs[(n << 4) + 0x01]; }
|
||||
unsigned sDSPDebugger::voice_pitch_height(unsigned n) { return state.regs[(n << 4) + 0x02] + (state.regs[(n << 4) + 0x03] << 8); }
|
||||
unsigned sDSPDebugger::voice_source_number(unsigned n) { return state.regs[(n << 4) + 0x04]; }
|
||||
unsigned sDSPDebugger::voice_adsr1(unsigned n) { return state.regs[(n << 4) + 0x05]; }
|
||||
unsigned sDSPDebugger::voice_adsr2(unsigned n) { return state.regs[(n << 4) + 0x06]; }
|
||||
unsigned sDSPDebugger::voice_gain(unsigned n) { return state.regs[(n << 4) + 0x07]; }
|
||||
unsigned sDSPDebugger::voice_envx(unsigned n) { return state.regs[(n << 4) + 0x08]; }
|
||||
unsigned sDSPDebugger::voice_outx(unsigned n) { return state.regs[(n << 4) + 0x09]; }
|
||||
unsigned DSPDebugger::main_volume_left() { return state.regs[0x0c]; }
|
||||
unsigned DSPDebugger::main_volume_right() { return state.regs[0x1c]; }
|
||||
unsigned DSPDebugger::echo_volume_left() { return state.regs[0x2c]; }
|
||||
unsigned DSPDebugger::echo_volume_right() { return state.regs[0x3c]; }
|
||||
unsigned DSPDebugger::key_on() { return state.regs[0x4c]; }
|
||||
unsigned DSPDebugger::key_off() { return state.regs[0x5c]; }
|
||||
bool DSPDebugger::flag_reset() { return state.regs[0x6c] & 0x80; }
|
||||
bool DSPDebugger::flag_mute() { return state.regs[0x6c] & 0x40; }
|
||||
bool DSPDebugger::flag_echo_disable() { return state.regs[0x6c] & 0x20; }
|
||||
unsigned DSPDebugger::flag_noise_clock() { return state.regs[0x6c] & 0x1f; }
|
||||
unsigned DSPDebugger::source_end_block() { return state.regs[0x7c]; }
|
||||
unsigned DSPDebugger::echo_feedback() { return state.regs[0x0d]; }
|
||||
unsigned DSPDebugger::pitch_modulation_enable() { return state.regs[0x2d]; }
|
||||
unsigned DSPDebugger::noise_enable() { return state.regs[0x3d]; }
|
||||
unsigned DSPDebugger::echo_enable() { return state.regs[0x4d]; }
|
||||
unsigned DSPDebugger::source_directory() { return state.regs[0x5d]; }
|
||||
unsigned DSPDebugger::echo_start_address() { return state.regs[0x6d]; }
|
||||
unsigned DSPDebugger::echo_directory() { return state.regs[0x7d]; }
|
||||
unsigned DSPDebugger::echo_filter_coefficient(unsigned n) { return state.regs[(n << 4) + 0x0f]; }
|
||||
unsigned DSPDebugger::voice_volume_left(unsigned n) { return state.regs[(n << 4) + 0x00]; }
|
||||
unsigned DSPDebugger::voice_volume_right(unsigned n) { return state.regs[(n << 4) + 0x01]; }
|
||||
unsigned DSPDebugger::voice_pitch_height(unsigned n) { return state.regs[(n << 4) + 0x02] + (state.regs[(n << 4) + 0x03] << 8); }
|
||||
unsigned DSPDebugger::voice_source_number(unsigned n) { return state.regs[(n << 4) + 0x04]; }
|
||||
unsigned DSPDebugger::voice_adsr1(unsigned n) { return state.regs[(n << 4) + 0x05]; }
|
||||
unsigned DSPDebugger::voice_adsr2(unsigned n) { return state.regs[(n << 4) + 0x06]; }
|
||||
unsigned DSPDebugger::voice_gain(unsigned n) { return state.regs[(n << 4) + 0x07]; }
|
||||
unsigned DSPDebugger::voice_envx(unsigned n) { return state.regs[(n << 4) + 0x08]; }
|
||||
unsigned DSPDebugger::voice_outx(unsigned n) { return state.regs[(n << 4) + 0x09]; }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
class sDSPDebugger : public sDSP, public DSPDebugger {
|
||||
class DSPDebugger : public DSP, public ChipDebugger {
|
||||
public:
|
||||
bool property(unsigned id, string &name, string &value);
|
||||
|
||||
//===========
|
||||
//DSPDebugger
|
||||
//===========
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
#ifdef DSP_CPP
|
||||
|
||||
bool DSPDebugger::property(unsigned id, string &name, string &value) {
|
||||
unsigned n = 0;
|
||||
|
||||
if(id == n++) { name = "Main Volume - Left"; value = main_volume_left(); return true; }
|
||||
if(id == n++) { name = "Main Volume - Right"; value = main_volume_right(); return true; }
|
||||
if(id == n++) { name = "Echo Volume - Left"; value = echo_volume_left(); return true; }
|
||||
if(id == n++) { name = "Echo Volume - Right"; value = echo_volume_right(); return true; }
|
||||
if(id == n++) { name = "Key On"; value = string("0x", strhex<2>(key_on())); return true; }
|
||||
if(id == n++) { name = "Key Off"; value = string("0x", strhex<2>(key_off())); return true; }
|
||||
if(id == n++) { name = "Flag - Reset"; value = flag_reset(); return true; }
|
||||
if(id == n++) { name = "Flag - Mute"; value = flag_mute(); return true; }
|
||||
if(id == n++) { name = "Flag - Echo Disable"; value = flag_echo_disable(); return true; }
|
||||
if(id == n++) { name = "Flag - Noise Clock"; value = flag_noise_clock(); return true; }
|
||||
if(id == n++) { name = "Source End Block"; value = source_end_block(); return true; }
|
||||
if(id == n++) { name = "Echo Feedback"; value = echo_feedback(); return true; }
|
||||
if(id == n++) { name = "Pitch Modulation Enable"; value = string("0x", strhex<2>(pitch_modulation_enable())); return true; }
|
||||
if(id == n++) { name = "Noise Enable"; value = string("0x", strhex<2>(noise_enable())); return true; }
|
||||
if(id == n++) { name = "Echo Enable"; value = string("0x", strhex<2>(echo_enable())); return true; }
|
||||
if(id == n++) { name = "Source Directory"; value = source_directory(); return true; }
|
||||
if(id == n++) { name = "Echo Start Address"; value = echo_start_address(); return true; }
|
||||
if(id == n++) { name = "Echo Directory"; value = echo_directory(); return true; }
|
||||
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
if(id == n++) {
|
||||
name = string("Coefficient ", i);
|
||||
value = string("0x", strhex<2>(echo_filter_coefficient(i)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
if(id == n++) {
|
||||
name = string("Voice ", i);
|
||||
value = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
if(id == n++) { name = "Volume - Left"; value = voice_volume_left(i); return true; }
|
||||
if(id == n++) { name = "Volume - Right"; value = voice_volume_right(i); return true; }
|
||||
if(id == n++) { name = "Pitch Height"; value = string("0x", strhex<4>(voice_pitch_height(i))); return true; }
|
||||
if(id == n++) { name = "Source Number"; value = voice_source_number(i); return true; }
|
||||
if(id == n++) { name = "ADSR1"; value = voice_adsr1(i); return true; }
|
||||
if(id == n++) { name = "ADSR2"; value = voice_adsr2(i); return true; }
|
||||
if(id == n++) { name = "GAIN"; value = voice_gain(i); return true; }
|
||||
if(id == n++) { name = "ENVX"; value = voice_envx(i); return true; }
|
||||
if(id == n++) { name = "OUTX"; value = voice_outx(i); return true; }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,32 +0,0 @@
|
|||
struct DSPDebugger : ChipDebugger {
|
||||
bool property(unsigned id, string &name, string &value);
|
||||
|
||||
virtual unsigned main_volume_left() { return 0; }
|
||||
virtual unsigned main_volume_right() { return 0; }
|
||||
virtual unsigned echo_volume_left() { return 0; }
|
||||
virtual unsigned echo_volume_right() { return 0; }
|
||||
virtual unsigned key_on() { return 0; }
|
||||
virtual unsigned key_off() { return 0; }
|
||||
virtual bool flag_reset() { return 0; }
|
||||
virtual bool flag_mute() { return 0; }
|
||||
virtual bool flag_echo_disable() { return 0; }
|
||||
virtual unsigned flag_noise_clock() { return 0; }
|
||||
virtual unsigned source_end_block() { return 0; }
|
||||
virtual unsigned echo_feedback() { return 0; }
|
||||
virtual unsigned pitch_modulation_enable() { return 0; }
|
||||
virtual unsigned noise_enable() { return 0; }
|
||||
virtual unsigned echo_enable() { return 0; }
|
||||
virtual unsigned source_directory() { return 0; }
|
||||
virtual unsigned echo_start_address() { return 0; }
|
||||
virtual unsigned echo_directory() { return 0; }
|
||||
virtual unsigned echo_filter_coefficient(unsigned) { return 0; }
|
||||
virtual unsigned voice_volume_left(unsigned) { return 0; }
|
||||
virtual unsigned voice_volume_right(unsigned) { return 0; }
|
||||
virtual unsigned voice_pitch_height(unsigned) { return 0; }
|
||||
virtual unsigned voice_source_number(unsigned) { return 0; }
|
||||
virtual unsigned voice_adsr1(unsigned) { return 0; }
|
||||
virtual unsigned voice_adsr2(unsigned) { return 0; }
|
||||
virtual unsigned voice_gain(unsigned) { return 0; }
|
||||
virtual unsigned voice_envx(unsigned) { return 0; }
|
||||
virtual unsigned voice_outx(unsigned) { return 0; }
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "asnes";
|
||||
static const char Version[] = "000.01";
|
||||
static const unsigned SerializerVersion = 12;
|
||||
}
|
||||
}
|
||||
|
||||
//#define DEBUGGER
|
|
@ -1,5 +1,5 @@
|
|||
#include "libsnes.hpp"
|
||||
#include <snes/snes.hpp>
|
||||
#include <snes.hpp>
|
||||
|
||||
#include <nall/snes/info.hpp>
|
||||
using namespace nall;
|
||||
|
|
|
@ -48,6 +48,9 @@ extern "C" {
|
|||
#define SNES_DEVICE_ID_JUSTIFIER_TRIGGER 2
|
||||
#define SNES_DEVICE_ID_JUSTIFIER_START 3
|
||||
|
||||
#define SNES_REGION_NTSC 0
|
||||
#define SNES_REGION_PAL 1
|
||||
|
||||
#define SNES_MEMORY_CARTRIDGE_RAM 0
|
||||
#define SNES_MEMORY_CARTRIDGE_RTC 1
|
||||
#define SNES_MEMORY_BSX_RAM 2
|
||||
|
|
|
@ -1,3 +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("0x", strhex<2>(ppu1_mdr())); return true; }
|
||||
if(id == n++) { name = "S-PPU2 MDR"; value = string("0x", strhex<2>(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("0x", strhex<4>(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("0x", strhex<4>(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("0x", strhex<4>(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("0x", strhex<4>(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("0x", strhex<4>(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("0x", strhex<4>(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("0x", strhex<4>(bg1_name_base_address())); return true; }
|
||||
if(id == n++) { name = "BG2 Name Base Address"; value = string("0x", strhex<4>(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("0x", strhex<4>(bg3_name_base_address())); return true; }
|
||||
if(id == n++) { name = "BG4 Name Base Address"; value = string("0x", strhex<4>(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("0x", strhex<4>(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("0x", strhex<4>(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_enable(); return true; }
|
||||
if(id == n++) { name = "OAM Interlace"; value = oam_interlace(); return true; }
|
||||
if(id == n++) { name = "Interlace"; value = interlace_enable(); 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
|
||||
|
|
|
@ -1,8 +1,250 @@
|
|||
class sPPUDebugger : public sPPU, public PPUDebugger {
|
||||
class PPUDebugger : public PPU, public ChipDebugger {
|
||||
public:
|
||||
bool property(unsigned id, string &name, string &value);
|
||||
|
||||
bool bg1_enabled[2];
|
||||
bool bg2_enabled[2];
|
||||
bool bg3_enabled[2];
|
||||
bool bg4_enabled[2];
|
||||
bool oam_enabled[4];
|
||||
|
||||
//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_enable() { return 0; }
|
||||
virtual bool oam_interlace() { return 0; }
|
||||
virtual bool interlace_enable() { 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; }
|
||||
};
|
||||
|
|
|
@ -1,243 +0,0 @@
|
|||
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_enable() { return 0; }
|
||||
virtual bool oam_interlace() { return 0; }
|
||||
virtual bool interlace_enable() { 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; }
|
||||
};
|
|
@ -1,6 +1,28 @@
|
|||
#ifdef SMP_CPP
|
||||
|
||||
void sSMPDebugger::op_step() {
|
||||
bool SMPDebugger::property(unsigned id, string &name, string &value) {
|
||||
unsigned n = 0;
|
||||
|
||||
//$00f0
|
||||
if(id == n++) { name = "$00f0"; value = ""; return true; }
|
||||
if(id == n++) { name = "Clock Speed"; value = clock_speed(); return true; }
|
||||
if(id == n++) { name = "Timers Enable"; value = timers_enable(); return true; }
|
||||
if(id == n++) { name = "RAM Disable"; value = ram_disable(); return true; }
|
||||
if(id == n++) { name = "RAM Writable"; value = ram_writable(); return true; }
|
||||
if(id == n++) { name = "Timers Disable"; value = timers_disable(); return true; }
|
||||
|
||||
//$00f1
|
||||
if(id == n++) { name = "$00f1"; value = ""; return true; }
|
||||
if(id == n++) { name = "IPLROM Enable"; value = iplrom_enable(); return true; }
|
||||
|
||||
//$00f2
|
||||
if(id == n++) { name = "$00f2"; value = ""; return true; }
|
||||
if(id == n++) { name = "DSP Address"; value = string("0x", strhex<2>(dsp_address())); return true; }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SMPDebugger::op_step() {
|
||||
bool break_event = false;
|
||||
|
||||
usage[regs.pc] |= UsageExec;
|
||||
|
@ -14,30 +36,30 @@ void sSMPDebugger::op_step() {
|
|||
}
|
||||
|
||||
if(step_event) step_event();
|
||||
sSMP::op_step();
|
||||
SMP::op_step();
|
||||
synchronize_cpu();
|
||||
}
|
||||
|
||||
uint8 sSMPDebugger::op_read(uint16 addr) {
|
||||
uint8 data = sSMP::op_read(addr);
|
||||
uint8 SMPDebugger::op_read(uint16 addr) {
|
||||
uint8 data = SMP::op_read(addr);
|
||||
usage[addr] |= UsageRead;
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Read, addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void sSMPDebugger::op_write(uint16 addr, uint8 data) {
|
||||
sSMP::op_write(addr, data);
|
||||
void SMPDebugger::op_write(uint16 addr, uint8 data) {
|
||||
SMP::op_write(addr, data);
|
||||
usage[addr] |= UsageWrite;
|
||||
usage[addr] &= ~UsageExec;
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Write, addr, data);
|
||||
}
|
||||
|
||||
sSMPDebugger::sSMPDebugger() {
|
||||
SMPDebugger::SMPDebugger() {
|
||||
usage = new uint8[1 << 16]();
|
||||
opcode_pc = 0xffc0;
|
||||
}
|
||||
|
||||
sSMPDebugger::~sSMPDebugger() {
|
||||
SMPDebugger::~SMPDebugger() {
|
||||
delete[] usage;
|
||||
}
|
||||
|
||||
|
@ -46,16 +68,16 @@ sSMPDebugger::~sSMPDebugger() {
|
|||
//===========
|
||||
|
||||
//$00f0
|
||||
unsigned sSMPDebugger::clock_speed() { return status.clock_speed; }
|
||||
bool sSMPDebugger::timers_enable() { return status.timers_enabled; }
|
||||
bool sSMPDebugger::ram_disable() { return status.ram_disabled; }
|
||||
bool sSMPDebugger::ram_writable() { return status.ram_writable; }
|
||||
bool sSMPDebugger::timers_disable() { return status.timers_disabled; }
|
||||
unsigned SMPDebugger::clock_speed() { return status.clock_speed; }
|
||||
bool SMPDebugger::timers_enable() { return status.timers_enabled; }
|
||||
bool SMPDebugger::ram_disable() { return status.ram_disabled; }
|
||||
bool SMPDebugger::ram_writable() { return status.ram_writable; }
|
||||
bool SMPDebugger::timers_disable() { return status.timers_disabled; }
|
||||
|
||||
//$00f1
|
||||
bool sSMPDebugger::iplrom_enable() { return status.iplrom_enabled; }
|
||||
bool SMPDebugger::iplrom_enable() { return status.iplrom_enabled; }
|
||||
|
||||
//$00f2
|
||||
unsigned sSMPDebugger::dsp_address() { return status.dsp_addr; }
|
||||
unsigned SMPDebugger::dsp_address() { return status.dsp_addr; }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
class sSMPDebugger : public sSMP, public SMPDebugger {
|
||||
class SMPDebugger : public SMP, public ChipDebugger {
|
||||
public:
|
||||
bool property(unsigned id, string &name, string &value);
|
||||
|
||||
function<void ()> step_event;
|
||||
|
||||
enum Usage {
|
||||
|
@ -14,8 +16,8 @@ public:
|
|||
uint8 op_read(uint16 addr);
|
||||
void op_write(uint16 addr, uint8 data);
|
||||
|
||||
sSMPDebugger();
|
||||
~sSMPDebugger();
|
||||
SMPDebugger();
|
||||
~SMPDebugger();
|
||||
|
||||
//===========
|
||||
//SMPDebugger
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
#ifdef SMP_CPP
|
||||
|
||||
bool SMPDebugger::property(unsigned id, string &name, string &value) {
|
||||
unsigned n = 0;
|
||||
|
||||
//$00f0
|
||||
if(id == n++) { name = "$00f0"; value = ""; return true; }
|
||||
if(id == n++) { name = "Clock Speed"; value = clock_speed(); return true; }
|
||||
if(id == n++) { name = "Timers Enable"; value = timers_enable(); return true; }
|
||||
if(id == n++) { name = "RAM Disable"; value = ram_disable(); return true; }
|
||||
if(id == n++) { name = "RAM Writable"; value = ram_writable(); return true; }
|
||||
if(id == n++) { name = "Timers Disable"; value = timers_disable(); return true; }
|
||||
|
||||
//$00f1
|
||||
if(id == n++) { name = "$00f1"; value = ""; return true; }
|
||||
if(id == n++) { name = "IPLROM Enable"; value = iplrom_enable(); return true; }
|
||||
|
||||
//$00f2
|
||||
if(id == n++) { name = "$00f2"; value = ""; return true; }
|
||||
if(id == n++) { name = "DSP Address"; value = string("0x", strhex<2>(dsp_address())); return true; }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,16 +0,0 @@
|
|||
struct SMPDebugger : ChipDebugger {
|
||||
bool property(unsigned id, string &name, string &value);
|
||||
|
||||
//$00f0
|
||||
virtual unsigned clock_speed() { return 0; }
|
||||
virtual bool timers_enable() { return 0; }
|
||||
virtual bool ram_disable() { return 0; }
|
||||
virtual bool ram_writable() { return 0; }
|
||||
virtual bool timers_disable() { return 0; }
|
||||
|
||||
//$00f1
|
||||
virtual bool iplrom_enable() { return 0; }
|
||||
|
||||
//$00f2
|
||||
virtual unsigned dsp_address() { return 0; }
|
||||
};
|
|
@ -2,7 +2,11 @@
|
|||
|
||||
void SMP::add_clocks(unsigned clocks) {
|
||||
step(clocks);
|
||||
#if !defined(DSP_STATE_MACHINE)
|
||||
synchronize_dsp();
|
||||
#else
|
||||
while(dsp.clock < 0) dsp.enter();
|
||||
#endif
|
||||
|
||||
//forcefully sync S-SMP to S-CPU in case chips are not communicating
|
||||
//sync if S-SMP is more than 24 samples ahead of S-CPU
|
||||
|
|
|
@ -1,12 +1,4 @@
|
|||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "asnes";
|
||||
static const char Version[] = "000";
|
||||
static const unsigned SerializerVersion = 12;
|
||||
}
|
||||
}
|
||||
|
||||
//#define DEBUGGER
|
||||
#include <info.hpp>
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
snes_core = sMemory sCPU sSMP sDSP bPPU
|
||||
|
||||
snes_objects := libco
|
||||
snes_objects += snes-system
|
||||
snes_objects += snes-cartridge snes-cheat
|
||||
snes_objects += snes-memory snes-cpu snes-cpucore snes-smp snes-smpcore snes-dsp snes-ppu
|
||||
snes_objects += $(foreach n,$(call strlower,$(snes_core)),snes-$n)
|
||||
snes_objects += snes-memory snes-cpucore snes-cpu snes-smpcore snes-smp snes-dsp snes-ppu
|
||||
snes_objects += snes-supergameboy snes-superfx snes-sa1
|
||||
snes_objects += snes-bsx snes-srtc snes-sdd1 snes-spc7110
|
||||
snes_objects += snes-cx4 snes-dsp1 snes-dsp2 snes-dsp3 snes-dsp4
|
||||
|
@ -12,44 +9,20 @@ snes_objects += snes-obc1 snes-st0010 snes-st0011 snes-st0018
|
|||
snes_objects += snes-msu1 snes-serial
|
||||
objects += $(snes_objects)
|
||||
|
||||
# libco
|
||||
obj/libco.o: libco/libco.c libco/*
|
||||
|
||||
# libsnes
|
||||
obj/libco.o : libco/libco.c libco/*
|
||||
obj/libsnes.o: $(snes)/libsnes/libsnes.cpp $(snes)/libsnes/*
|
||||
|
||||
# system
|
||||
obj/snes-system.o: $(snes)/system/system.cpp $(call rwildcard,$(snes)/system/) $(call rwildcard,$(snes)/video/)
|
||||
|
||||
# memory
|
||||
obj/snes-memory.o : $(snes)/memory/memory.cpp $(snes)/memory/*
|
||||
obj/snes-smemory.o: $(snes)/memory/smemory/smemory.cpp $(call rwildcard,$(snes)/memory/smemory/)
|
||||
|
||||
# cpu
|
||||
obj/snes-cpu.o : $(snes)/cpu/cpu.cpp $(snes)/cpu/*
|
||||
obj/snes-cpucore.o: $(snes)/cpu/core/core.cpp $(call rwildcard,$(snes)/cpu/core/)
|
||||
obj/snes-scpu.o : $(snes)/cpu/scpu/scpu.cpp $(call rwildcard,$(snes)/cpu/scpu/)
|
||||
|
||||
# smp
|
||||
obj/snes-smp.o : $(snes)/smp/smp.cpp $(snes)/smp/*
|
||||
obj/snes-smpcore.o: $(snes)/smp/core/core.cpp $(call rwildcard,$(snes)/smp/core/)
|
||||
obj/snes-ssmp.o : $(snes)/smp/ssmp/ssmp.cpp $(call rwildcard,$(snes)/smp/ssmp/)
|
||||
|
||||
# dsp
|
||||
obj/snes-dsp.o : $(snes)/dsp/dsp.cpp $(snes)/dsp/*
|
||||
obj/snes-sdsp.o: $(snes)/dsp/sdsp/sdsp.cpp $(snes)/dsp/sdsp/*
|
||||
obj/snes-adsp.o: $(snes)/dsp/adsp/adsp.cpp $(snes)/dsp/adsp/*
|
||||
|
||||
# ppu
|
||||
obj/snes-ppu.o : $(snes)/ppu/ppu.cpp $(snes)/ppu/*
|
||||
obj/snes-sppu.o: $(snes)/ppu/sppu/sppu.cpp $(call rwildcard,$(snes)/ppu/sppu/)
|
||||
obj/snes-bppu.o: $(snes)/ppu/bppu/bppu.cpp $(call rwildcard,$(snes)/ppu/bppu/)
|
||||
|
||||
# utilities
|
||||
obj/snes-system.o : $(snes)/system/system.cpp $(call rwildcard,$(snes)/system/) $(call rwildcard,$(snes)/video/)
|
||||
obj/snes-memory.o : $(snes)/memory/memory.cpp $(snes)/memory/*
|
||||
obj/snes-cpucore.o : $(snes)/cpu/core/core.cpp $(call rwildcard,$(snes)/cpu/core/)
|
||||
obj/snes-cpu.o : $(snes)/cpu/cpu.cpp $(snes)/cpu/*
|
||||
obj/snes-smpcore.o : $(snes)/smp/core/core.cpp $(call rwildcard,$(snes)/smp/core/)
|
||||
obj/snes-smp.o : $(snes)/smp/smp.cpp $(snes)/smp/*
|
||||
obj/snes-dsp.o : $(snes)/dsp/dsp.cpp $(snes)/dsp/*
|
||||
obj/snes-ppu.o : $(snes)/ppu/ppu.cpp $(snes)/ppu/*
|
||||
obj/snes-cartridge.o: $(snes)/cartridge/cartridge.cpp $(snes)/cartridge/*
|
||||
obj/snes-cheat.o : $(snes)/cheat/cheat.cpp $(snes)/cheat/*
|
||||
|
||||
# special chips
|
||||
obj/snes-supergameboy.o: $(snes)/chip/supergameboy/supergameboy.cpp $(call rwildcard,$(snes)/chip/supergameboy/)
|
||||
obj/snes-superfx.o : $(snes)/chip/superfx/superfx.cpp $(call rwildcard,$(snes)/chip/superfx/)
|
||||
obj/snes-sa1.o : $(snes)/chip/sa1/sa1.cpp $(call rwildcard,$(snes)/chip/sa1/)
|
||||
|
@ -69,27 +42,30 @@ obj/snes-st0018.o : $(snes)/chip/st0018/st0018.cpp $(snes)/chip/st0018/*
|
|||
obj/snes-msu1.o : $(snes)/chip/msu1/msu1.cpp $(snes)/chip/msu1/*
|
||||
obj/snes-serial.o : $(snes)/chip/serial/serial.cpp $(snes)/chip/serial/*
|
||||
|
||||
# library
|
||||
###########
|
||||
# library #
|
||||
###########
|
||||
|
||||
snes_objects := $(patsubst %,obj/%.o,$(snes_objects))
|
||||
|
||||
library: $(snes_objects) obj/libsnes.o
|
||||
ifeq ($(platform),x)
|
||||
ar rcs obj/libsnes.a $(snes_objects) obj/libsnes.o
|
||||
$(cpp) -o obj/libsnes.so -shared -Wl,-soname,libsnes.so.1 $(snes_objects) obj/libsnes.o
|
||||
ar rcs out/libsnes.a $(snes_objects) obj/libsnes.o
|
||||
$(cpp) -o out/libsnes.so -shared -Wl,-soname,libsnes.so.1 $(snes_objects) obj/libsnes.o
|
||||
else ifeq ($(platform),osx)
|
||||
ar rcs obj/libsnes.a $(snes_objects) obj/libsnes.o
|
||||
$(cpp) -o obj/libsnes.dylib -install_name @executable_path/../Libraries/libsnes.dylib -shared -dynamiclib $(snes_objects) obj/libsnes.o
|
||||
ar rcs out/libsnes.a $(snes_objects) obj/libsnes.o
|
||||
$(cpp) -o out/libsnes.dylib -install_name @executable_path/../Libraries/libsnes.dylib -shared -dynamiclib $(snes_objects) obj/libsnes.o
|
||||
else ifeq ($(platform),win)
|
||||
$(cpp) -o obj/snes.dll -shared -Wl,--out-implib,libsnes.a $(snes_objects) obj/libsnes.o
|
||||
$(cpp) -o out/snes.dll -shared -Wl,--out-implib,libsnes.a $(snes_objects) obj/libsnes.o
|
||||
endif
|
||||
|
||||
library-install:
|
||||
ifeq ($(platform),x)
|
||||
install -D -m 755 obj/libsnes.a $(DESTDIR)$(prefix)/lib/libsnes.a
|
||||
install -D -m 755 obj/libsnes.so $(DESTDIR)$(prefix)/lib/libsnes.so
|
||||
install -D -m 755 out/libsnes.a $(DESTDIR)$(prefix)/lib/libsnes.a
|
||||
install -D -m 755 out/libsnes.so $(DESTDIR)$(prefix)/lib/libsnes.so
|
||||
ldconfig -n $(DESTDIR)$(prefix)/lib
|
||||
else ifeq ($(platform),osx)
|
||||
cp obj/libsnes.dylib /usr/local/lib/libsnes.dylib
|
||||
cp out/libsnes.dylib /usr/local/lib/libsnes.dylib
|
||||
endif
|
||||
|
||||
library-uninstall:
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
#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("0x", strhex<2>(mdr())); return true; }
|
||||
|
||||
//$2181-2183
|
||||
if(id == n++) { name = "$2181-$2183"; value = ""; return true; }
|
||||
if(id == n++) { name = "WRAM Address"; value = string("0x", strhex<6>(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("0x", strhex<2>(pio_bits())); return true; }
|
||||
|
||||
//$4202
|
||||
if(id == n++) { name = "$4202"; value = ""; return true; }
|
||||
if(id == n++) { name = "Multiplicand"; value = string("0x", strhex<2>(multiplicand())); return true; }
|
||||
|
||||
//$4203
|
||||
if(id == n++) { name = "$4203"; value = ""; return true; }
|
||||
if(id == n++) { name = "Multiplier"; value = string("0x", strhex<2>(multiplier())); return true; }
|
||||
|
||||
//$4204-$4205
|
||||
if(id == n++) { name = "$4204-$4205"; value = ""; return true; }
|
||||
if(id == n++) { name = "Dividend"; value = string("0x", strhex<4>(dividend())); return true; }
|
||||
|
||||
//$4206
|
||||
if(id == n++) { name = "$4206"; value = ""; return true; }
|
||||
if(id == n++) { name = "Divisor"; value = string("0x", strhex<2>(divisor())); return true; }
|
||||
|
||||
//$4207-$4208
|
||||
if(id == n++) { name = "$4207-$4208"; value = ""; return true; }
|
||||
if(id == n++) { name = "H-Time"; value = string("0x", strhex<4>(htime())); return true; }
|
||||
|
||||
//$4209-$420a
|
||||
if(id == n++) { name = "$4209-$420a"; value = ""; return true; }
|
||||
if(id == n++) { name = "V-Time"; value = string("0x", strhex<4>(vtime())); return true; }
|
||||
|
||||
//$420b
|
||||
if(id == n++) { name = "$420b"; value = ""; return true; }
|
||||
if(id == n++) { name = "DMA Enable"; value = string("0x", strhex<2>(dma_enable())); return true; }
|
||||
|
||||
//$420c
|
||||
if(id == n++) { name = "$420c"; value = ""; return true; }
|
||||
if(id == n++) { name = "HDMA Enable"; value = string("0x", strhex<2>(hdma_enable())); return true; }
|
||||
|
||||
//$420d
|
||||
if(id == n++) { name = "$420d"; value = ""; return true; }
|
||||
if(id == n++) { name = "FastROM Enable"; value = fastrom_enable(); return true; }
|
||||
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
if(id == n++) { name = string() << "DMA Channel " << i; return true; }
|
||||
|
||||
//$43x0
|
||||
if(id == n++) { name = "Direction"; value = dma_direction(i); return true; }
|
||||
if(id == n++) { name = "Indirect"; value = dma_indirect(i); return true; }
|
||||
if(id == n++) { name = "Reverse Transfer"; value = dma_reverse_transfer(i); return true; }
|
||||
if(id == n++) { name = "Fixed Transfer"; value = dma_fixed_transfer(i); return true; }
|
||||
if(id == n++) { name = "Transfer Mode"; value = dma_transfer_mode(i); return true; }
|
||||
|
||||
//$43x1
|
||||
if(id == n++) { name = "B-Bus Address"; value = string("0x", strhex<4>(dma_bbus_address(i))); return true; }
|
||||
|
||||
//$43x2-$43x3
|
||||
if(id == n++) { name = "A-Bus Address"; value = string("0x", strhex<4>(dma_abus_address(i))); return true; }
|
||||
|
||||
//$43x4
|
||||
if(id == n++) { name = "A-Bus Bank"; value = string("0x", strhex<2>(dma_abus_bank(i))); return true; }
|
||||
|
||||
//$43x5-$43x6
|
||||
if(id == n++) { name = "Transfer Size / Indirect Address"; value = string("0x", strhex<4>(dma_transfer_size(i))); return true; }
|
||||
|
||||
//$43x7
|
||||
if(id == n++) { name = "Indirect Bank"; value = string("0x", strhex<2>(dma_indirect_bank(i))); return true; }
|
||||
|
||||
//$43x8-$43x9
|
||||
if(id == n++) { name = "Table Address"; value = string("0x", strhex<4>(dma_table_address(i))); return true; }
|
||||
|
||||
//$43xa
|
||||
if(id == n++) { name = "Line Counter"; value = string("0x", strhex<2>(dma_line_counter(i))); return true; }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,76 +0,0 @@
|
|||
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; }
|
||||
|
||||
//$420b
|
||||
virtual unsigned dma_enable() { return 0; }
|
||||
|
||||
//$420c
|
||||
virtual unsigned hdma_enable() { return 0; }
|
||||
|
||||
//$420d
|
||||
virtual bool fastrom_enable() { return 0; }
|
||||
|
||||
//$43x0
|
||||
virtual bool dma_direction(unsigned) { return 0; }
|
||||
virtual bool dma_indirect(unsigned) { return 0; }
|
||||
virtual bool dma_reverse_transfer(unsigned) { return 0; }
|
||||
virtual bool dma_fixed_transfer(unsigned) { return 0; }
|
||||
virtual unsigned dma_transfer_mode(unsigned) { return 0; }
|
||||
|
||||
//$43x1
|
||||
virtual unsigned dma_bbus_address(unsigned) { return 0; }
|
||||
|
||||
//$43x2-$43x3
|
||||
virtual unsigned dma_abus_address(unsigned) { return 0; }
|
||||
|
||||
//$43x4
|
||||
virtual unsigned dma_abus_bank(unsigned) { return 0; }
|
||||
|
||||
//$43x5-$43x6
|
||||
virtual unsigned dma_transfer_size(unsigned) { return 0; }
|
||||
|
||||
//$43x7
|
||||
virtual unsigned dma_indirect_bank(unsigned) { return 0; }
|
||||
|
||||
//$43x8-$43x9
|
||||
virtual unsigned dma_table_address(unsigned addr) { return 0; }
|
||||
|
||||
//$43xa
|
||||
virtual unsigned dma_line_counter(unsigned addr) { return 0; }
|
||||
};
|
|
@ -4,32 +4,135 @@
|
|||
namespace SNES {
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#include "cpu-debugger.cpp"
|
||||
#include "debugger/debugger.cpp"
|
||||
CPUDebugger cpu;
|
||||
#else
|
||||
CPU cpu;
|
||||
#endif
|
||||
|
||||
#include "serialization.cpp"
|
||||
#include "dma/dma.cpp"
|
||||
#include "memory/memory.cpp"
|
||||
#include "mmio/mmio.cpp"
|
||||
#include "timing/timing.cpp"
|
||||
|
||||
void CPU::step(unsigned clocks) {
|
||||
smp.clock -= clocks * (uint64)smp.frequency;
|
||||
ppu.clock -= clocks;
|
||||
for(unsigned i = 0; i < coprocessors.size(); i++) {
|
||||
Processor &chip = *coprocessors[i];
|
||||
chip.clock -= clocks * (uint64)chip.frequency;
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::synchronize_smp() {
|
||||
if(smp.clock < 0) co_switch(smp.thread);
|
||||
}
|
||||
|
||||
void CPU::synchronize_ppu() {
|
||||
if(ppu.clock < 0) co_switch(ppu.thread);
|
||||
}
|
||||
|
||||
void CPU::synchronize_coprocessor() {
|
||||
for(unsigned i = 0; i < coprocessors.size(); i++) {
|
||||
Processor &chip = *coprocessors[i];
|
||||
if(chip.clock < 0) co_switch(chip.thread);
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::Enter() { cpu.enter(); }
|
||||
|
||||
void CPU::power() {
|
||||
create(CPU::Enter, system.cpu_frequency());
|
||||
coprocessors.reset();
|
||||
void CPU::enter() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
if(status.interrupt_pending) {
|
||||
status.interrupt_pending = false;
|
||||
if(status.nmi_pending) {
|
||||
status.nmi_pending = false;
|
||||
status.interrupt_vector = (regs.e == false ? 0xffea : 0xfffa);
|
||||
op_irq();
|
||||
} else if(status.irq_pending) {
|
||||
status.irq_pending = false;
|
||||
status.interrupt_vector = (regs.e == false ? 0xffee : 0xfffe);
|
||||
op_irq();
|
||||
} else if(status.reset_pending) {
|
||||
status.reset_pending = false;
|
||||
add_clocks(186);
|
||||
regs.pc.l = bus.read(0xfffc);
|
||||
regs.pc.h = bus.read(0xfffd);
|
||||
}
|
||||
}
|
||||
|
||||
op_step();
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::op_step() {
|
||||
(this->*opcode_table[op_readpc()])();
|
||||
}
|
||||
|
||||
void CPU::op_irq() {
|
||||
op_read(regs.pc.d);
|
||||
op_io();
|
||||
if(!regs.e) op_writestack(regs.pc.b);
|
||||
op_writestack(regs.pc.h);
|
||||
op_writestack(regs.pc.l);
|
||||
op_writestack(regs.e ? (regs.p & ~0x10) : regs.p);
|
||||
rd.l = op_read(status.interrupt_vector + 0);
|
||||
regs.pc.b = 0x00;
|
||||
regs.p.i = 1;
|
||||
regs.p.d = 0;
|
||||
rd.h = op_read(status.interrupt_vector + 1);
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
void CPU::power() {
|
||||
cpu_version = config.cpu.version;
|
||||
|
||||
regs.a = regs.x = regs.y = 0x0000;
|
||||
regs.s = 0x01ff;
|
||||
|
||||
mmio_power();
|
||||
dma_power();
|
||||
timing_power();
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void CPU::reset() {
|
||||
create(CPU::Enter, system.cpu_frequency());
|
||||
create(Enter, system.cpu_frequency());
|
||||
coprocessors.reset();
|
||||
|
||||
PPUCounter::reset();
|
||||
}
|
||||
|
||||
void CPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
PPUCounter::serialize(s);
|
||||
s.integer(cpu_version);
|
||||
//note: some registers are not fully reset by SNES
|
||||
regs.pc = 0x000000;
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
regs.s.h = 0x01;
|
||||
regs.d = 0x0000;
|
||||
regs.db = 0x00;
|
||||
regs.p = 0x34;
|
||||
regs.e = 1;
|
||||
regs.mdr = 0x00;
|
||||
regs.wai = false;
|
||||
update_table();
|
||||
|
||||
mmio_reset();
|
||||
dma_reset();
|
||||
timing_reset();
|
||||
|
||||
apu_port[0] = 0x00;
|
||||
apu_port[1] = 0x00;
|
||||
apu_port[2] = 0x00;
|
||||
apu_port[3] = 0x00;
|
||||
}
|
||||
|
||||
CPU::CPU() {
|
||||
PPUCounter::scanline = { &CPU::scanline, this };
|
||||
}
|
||||
|
||||
CPU::~CPU() {
|
||||
|
|
|
@ -1,35 +1,136 @@
|
|||
#if defined(DEBUGGER)
|
||||
#include "cpu-debugger.hpp"
|
||||
#endif
|
||||
|
||||
class CPU : public Processor, public PPUCounter, public MMIO {
|
||||
class CPU : public Processor, public PPUCounter, public MMIO, public CPUcore {
|
||||
public:
|
||||
//synchronization
|
||||
array<Processor*> coprocessors;
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_smp();
|
||||
alwaysinline void synchronize_ppu();
|
||||
alwaysinline void synchronize_coprocessor();
|
||||
void synchronize_ppu();
|
||||
void synchronize_coprocessor();
|
||||
|
||||
static void Enter();
|
||||
virtual void enter() = 0;
|
||||
void enter();
|
||||
debugvirtual void op_step();
|
||||
void op_irq();
|
||||
bool interrupt_pending() { return status.interrupt_pending; }
|
||||
|
||||
//CPU version number
|
||||
//* 1 and 2 are known
|
||||
//* reported by $4210
|
||||
//* affects timing (DRAM refresh, HDMA init, etc)
|
||||
uint8 cpu_version;
|
||||
|
||||
virtual uint8 pio() = 0;
|
||||
virtual bool joylatch() = 0;
|
||||
virtual uint8 port_read(uint8 port) = 0;
|
||||
virtual void port_write(uint8 port, uint8 value) = 0;
|
||||
#include "dma/dma.hpp"
|
||||
#include "memory/memory.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "timing/timing.hpp"
|
||||
|
||||
virtual void scanline() = 0;
|
||||
virtual void power();
|
||||
virtual void reset();
|
||||
struct Status {
|
||||
bool interrupt_pending;
|
||||
uint16 interrupt_vector;
|
||||
|
||||
virtual void serialize(serializer&);
|
||||
unsigned clock_count;
|
||||
unsigned line_clocks;
|
||||
|
||||
//======
|
||||
//timing
|
||||
//======
|
||||
|
||||
bool irq_lock;
|
||||
|
||||
unsigned dram_refresh_position;
|
||||
bool dram_refreshed;
|
||||
|
||||
unsigned hdma_init_position;
|
||||
bool hdma_init_triggered;
|
||||
|
||||
unsigned hdma_position;
|
||||
bool hdma_triggered;
|
||||
|
||||
bool nmi_valid;
|
||||
bool nmi_line;
|
||||
bool nmi_transition;
|
||||
bool nmi_pending;
|
||||
bool nmi_hold;
|
||||
|
||||
bool irq_valid;
|
||||
bool irq_line;
|
||||
bool irq_transition;
|
||||
bool irq_pending;
|
||||
bool irq_hold;
|
||||
|
||||
bool reset_pending;
|
||||
|
||||
//===
|
||||
//DMA
|
||||
//===
|
||||
|
||||
bool dma_active;
|
||||
unsigned dma_counter;
|
||||
unsigned dma_clocks;
|
||||
bool dma_pending;
|
||||
bool hdma_pending;
|
||||
bool hdma_mode; //0 = init, 1 = run
|
||||
|
||||
//====
|
||||
//MMIO
|
||||
//====
|
||||
|
||||
//$2181-$2183
|
||||
uint32 wram_addr;
|
||||
|
||||
//$4016-$4017
|
||||
bool joypad_strobe_latch;
|
||||
uint32 joypad1_bits;
|
||||
uint32 joypad2_bits;
|
||||
|
||||
//$4200
|
||||
bool nmi_enabled;
|
||||
bool hirq_enabled, virq_enabled;
|
||||
bool auto_joypad_poll;
|
||||
|
||||
//$4201
|
||||
uint8 pio;
|
||||
|
||||
//$4202-$4203
|
||||
uint8 wrmpya;
|
||||
uint8 wrmpyb;
|
||||
|
||||
//$4204-$4206
|
||||
uint16 wrdiva;
|
||||
uint8 wrdivb;
|
||||
|
||||
//$4207-$420a
|
||||
uint16 hirq_pos, virq_pos;
|
||||
|
||||
//$420d
|
||||
unsigned rom_speed;
|
||||
|
||||
//$4214-$4217
|
||||
uint16 rddiv;
|
||||
uint16 rdmpy;
|
||||
|
||||
//$4218-$421f
|
||||
uint8 joy1l, joy1h;
|
||||
uint8 joy2l, joy2h;
|
||||
uint8 joy3l, joy3h;
|
||||
uint8 joy4l, joy4h;
|
||||
} status;
|
||||
|
||||
struct ALU {
|
||||
unsigned mpyctr;
|
||||
unsigned divctr;
|
||||
unsigned shift;
|
||||
} alu;
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
CPU();
|
||||
virtual ~CPU();
|
||||
~CPU();
|
||||
|
||||
friend class CPUDebugger;
|
||||
};
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.hpp"
|
||||
extern CPUDebugger cpu;
|
||||
#else
|
||||
extern CPU cpu;
|
||||
#endif
|
||||
|
|
|
@ -96,4 +96,131 @@ bool CPUDebugger::property(unsigned id, string &name, string &value) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void CPUDebugger::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::BreakEvent::CPUStep;
|
||||
scheduler.exit(Scheduler::ExitReason::DebuggerEvent);
|
||||
} else {
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00);
|
||||
}
|
||||
|
||||
if(step_event) step_event();
|
||||
CPU::op_step();
|
||||
synchronize_smp();
|
||||
}
|
||||
|
||||
uint8 CPUDebugger::op_read(uint32 addr) {
|
||||
uint8 data = CPU::op_read(addr);
|
||||
usage[addr] |= UsageRead;
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Read, addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void CPUDebugger::op_write(uint32 addr, uint8 data) {
|
||||
CPU::op_write(addr, data);
|
||||
usage[addr] |= UsageWrite;
|
||||
usage[addr] &= ~UsageExec;
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Write, addr, data);
|
||||
}
|
||||
|
||||
CPUDebugger::CPUDebugger() {
|
||||
usage = new uint8[1 << 24]();
|
||||
opcode_pc = 0x8000;
|
||||
}
|
||||
|
||||
CPUDebugger::~CPUDebugger() {
|
||||
delete[] usage;
|
||||
}
|
||||
|
||||
//internal
|
||||
unsigned CPUDebugger::mdr() { return regs.mdr; }
|
||||
|
||||
//$2181-$2183
|
||||
unsigned CPUDebugger::wram_address() { return status.wram_addr; }
|
||||
|
||||
//$4016
|
||||
bool CPUDebugger::joypad_strobe_latch() { return status.joypad_strobe_latch; }
|
||||
|
||||
//$4200
|
||||
bool CPUDebugger::nmi_enable() { return status.nmi_enabled; }
|
||||
bool CPUDebugger::hirq_enable() { return status.hirq_enabled; }
|
||||
bool CPUDebugger::virq_enable() { return status.virq_enabled; }
|
||||
bool CPUDebugger::auto_joypad_poll() { return status.auto_joypad_poll; }
|
||||
|
||||
//$4201
|
||||
unsigned CPUDebugger::pio_bits() { return status.pio; }
|
||||
|
||||
//$4202
|
||||
unsigned CPUDebugger::multiplicand() { return status.wrmpya; }
|
||||
|
||||
//$4203
|
||||
unsigned CPUDebugger::multiplier() { return status.wrmpyb; }
|
||||
|
||||
//$4204-$4205
|
||||
unsigned CPUDebugger::dividend() { return status.wrdiva; }
|
||||
|
||||
//$4206
|
||||
unsigned CPUDebugger::divisor() { return status.wrdivb; }
|
||||
|
||||
//$4207-$4208
|
||||
unsigned CPUDebugger::htime() { return status.hirq_pos; }
|
||||
|
||||
//$4209-$420a
|
||||
unsigned CPUDebugger::vtime() { return status.virq_pos; }
|
||||
|
||||
//$420b
|
||||
unsigned CPUDebugger::dma_enable() {
|
||||
unsigned result = 0;
|
||||
for(unsigned n = 0; n < 8; n++) {
|
||||
result |= channel[n].dma_enabled << n;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//$420c
|
||||
unsigned CPUDebugger::hdma_enable() {
|
||||
unsigned result = 0;
|
||||
for(unsigned n = 0; n < 8; n++) {
|
||||
result |= channel[n].hdma_enabled << n;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//$420d
|
||||
bool CPUDebugger::fastrom_enable() { return status.rom_speed; }
|
||||
|
||||
//$43x0
|
||||
bool CPUDebugger::dma_direction(unsigned n) { return channel[n].direction; }
|
||||
bool CPUDebugger::dma_indirect(unsigned n) { return channel[n].hdma_indirect; }
|
||||
bool CPUDebugger::dma_reverse_transfer(unsigned n) { return channel[n].reversexfer; }
|
||||
bool CPUDebugger::dma_fixed_transfer(unsigned n) { return channel[n].fixedxfer; }
|
||||
unsigned CPUDebugger::dma_transfer_mode(unsigned n) { return channel[n].xfermode; }
|
||||
|
||||
//$43x1
|
||||
unsigned CPUDebugger::dma_bbus_address(unsigned n) { return 0x2100 + channel[n].destaddr; }
|
||||
|
||||
//$43x2-$43x3
|
||||
unsigned CPUDebugger::dma_abus_address(unsigned n) { return channel[n].srcaddr; }
|
||||
|
||||
//$43x4
|
||||
unsigned CPUDebugger::dma_abus_bank(unsigned n) { return channel[n].srcbank; }
|
||||
|
||||
//$43x5-$43x6
|
||||
unsigned CPUDebugger::dma_transfer_size(unsigned n) { return channel[n].xfersize; }
|
||||
|
||||
//$43x7
|
||||
unsigned CPUDebugger::dma_indirect_bank(unsigned n) { return channel[n].hdma_ibank; }
|
||||
|
||||
//$43x8-$43x9
|
||||
unsigned CPUDebugger::dma_table_address(unsigned n) { return channel[n].hdma_addr; }
|
||||
|
||||
//$43xa
|
||||
unsigned CPUDebugger::dma_line_counter(unsigned n) { return channel[n].hdma_line_counter; }
|
||||
|
||||
#endif
|
|
@ -1,5 +1,7 @@
|
|||
class sCPUDebugger : public sCPU, public CPUDebugger {
|
||||
class CPUDebugger : public CPU, public ChipDebugger {
|
||||
public:
|
||||
bool property(unsigned id, string &name, string &value);
|
||||
|
||||
function<void ()> step_event;
|
||||
|
||||
enum Usage {
|
||||
|
@ -16,12 +18,8 @@ public:
|
|||
uint8 op_read(uint32 addr);
|
||||
void op_write(uint32 addr, uint8 data);
|
||||
|
||||
sCPUDebugger();
|
||||
~sCPUDebugger();
|
||||
|
||||
//===========
|
||||
//CPUDebugger
|
||||
//===========
|
||||
CPUDebugger();
|
||||
~CPUDebugger();
|
||||
|
||||
//internal
|
||||
unsigned mdr();
|
|
@ -1,23 +1,23 @@
|
|||
#ifdef SCPU_CPP
|
||||
#ifdef CPU_CPP
|
||||
|
||||
void sCPU::dma_add_clocks(unsigned clocks) {
|
||||
void CPU::dma_add_clocks(unsigned clocks) {
|
||||
status.dma_clocks += clocks;
|
||||
add_clocks(clocks);
|
||||
CPU::synchronize_ppu();
|
||||
CPU::synchronize_coprocessor();
|
||||
synchronize_ppu();
|
||||
synchronize_coprocessor();
|
||||
}
|
||||
|
||||
//=============
|
||||
//memory access
|
||||
//=============
|
||||
|
||||
bool sCPU::dma_transfer_valid(uint8 bbus, uint32 abus) {
|
||||
bool CPU::dma_transfer_valid(uint8 bbus, uint32 abus) {
|
||||
//transfers from WRAM to WRAM are invalid; chip only has one address bus
|
||||
if(bbus == 0x80 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sCPU::dma_addr_valid(uint32 abus) {
|
||||
bool CPU::dma_addr_valid(uint32 abus) {
|
||||
//A-bus access to B-bus or S-CPU registers are invalid
|
||||
if((abus & 0x40ff00) == 0x2100) return false; //$[00-3f|80-bf]:[2100-21ff]
|
||||
if((abus & 0x40fe00) == 0x4000) return false; //$[00-3f|80-bf]:[4000-41ff]
|
||||
|
@ -26,7 +26,7 @@ bool sCPU::dma_addr_valid(uint32 abus) {
|
|||
return true;
|
||||
}
|
||||
|
||||
uint8 sCPU::dma_read(uint32 abus) {
|
||||
uint8 CPU::dma_read(uint32 abus) {
|
||||
if(dma_addr_valid(abus) == false) return 0x00;
|
||||
return bus.read(abus);
|
||||
}
|
||||
|
@ -36,14 +36,14 @@ uint8 sCPU::dma_read(uint32 abus) {
|
|||
//cycle 1: write N+0 & read N+1 (parallel; one on A-bus, one on B-bus)
|
||||
//cycle 2: write N+1 & read N+2 (parallel)
|
||||
//cycle 3: write N+2
|
||||
void sCPU::dma_write(bool valid, unsigned addr, uint8 data) {
|
||||
void CPU::dma_write(bool valid, unsigned addr, uint8 data) {
|
||||
if(pipe.valid) bus.write(pipe.addr, pipe.data);
|
||||
pipe.valid = valid;
|
||||
pipe.addr = addr;
|
||||
pipe.data = data;
|
||||
}
|
||||
|
||||
void sCPU::dma_transfer(bool direction, uint8 bbus, uint32 abus) {
|
||||
void CPU::dma_transfer(bool direction, uint8 bbus, uint32 abus) {
|
||||
if(direction == 0) {
|
||||
dma_add_clocks(4);
|
||||
regs.mdr = dma_read(abus);
|
||||
|
@ -61,7 +61,7 @@ void sCPU::dma_transfer(bool direction, uint8 bbus, uint32 abus) {
|
|||
//address calculation
|
||||
//===================
|
||||
|
||||
uint8 sCPU::dma_bbus(unsigned i, unsigned index) {
|
||||
uint8 CPU::dma_bbus(unsigned i, unsigned index) {
|
||||
switch(channel[i].xfermode) { default:
|
||||
case 0: return (channel[i].destaddr); //0
|
||||
case 1: return (channel[i].destaddr + (index & 1)); //0,1
|
||||
|
@ -74,7 +74,7 @@ uint8 sCPU::dma_bbus(unsigned i, unsigned index) {
|
|||
}
|
||||
}
|
||||
|
||||
inline uint32 sCPU::dma_addr(unsigned i) {
|
||||
inline uint32 CPU::dma_addr(unsigned i) {
|
||||
uint32 r = (channel[i].srcbank << 16) | (channel[i].srcaddr);
|
||||
|
||||
if(channel[i].fixedxfer == false) {
|
||||
|
@ -88,11 +88,11 @@ inline uint32 sCPU::dma_addr(unsigned i) {
|
|||
return r;
|
||||
}
|
||||
|
||||
inline uint32 sCPU::hdma_addr(unsigned i) {
|
||||
inline uint32 CPU::hdma_addr(unsigned i) {
|
||||
return (channel[i].srcbank << 16) | (channel[i].hdma_addr++);
|
||||
}
|
||||
|
||||
inline uint32 sCPU::hdma_iaddr(unsigned i) {
|
||||
inline uint32 CPU::hdma_iaddr(unsigned i) {
|
||||
return (channel[i].hdma_ibank << 16) | (channel[i].hdma_iaddr++);
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@ inline uint32 sCPU::hdma_iaddr(unsigned i) {
|
|||
//channel status
|
||||
//==============
|
||||
|
||||
uint8 sCPU::dma_enabled_channels() {
|
||||
uint8 CPU::dma_enabled_channels() {
|
||||
uint8 r = 0;
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
if(channel[i].dma_enabled) r++;
|
||||
|
@ -108,18 +108,18 @@ uint8 sCPU::dma_enabled_channels() {
|
|||
return r;
|
||||
}
|
||||
|
||||
inline bool sCPU::hdma_active(unsigned i) {
|
||||
inline bool CPU::hdma_active(unsigned i) {
|
||||
return (channel[i].hdma_enabled && !channel[i].hdma_completed);
|
||||
}
|
||||
|
||||
inline bool sCPU::hdma_active_after(unsigned i) {
|
||||
inline bool CPU::hdma_active_after(unsigned i) {
|
||||
for(unsigned n = i + 1; n < 8; n++) {
|
||||
if(hdma_active(n) == true) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline uint8 sCPU::hdma_enabled_channels() {
|
||||
inline uint8 CPU::hdma_enabled_channels() {
|
||||
uint8 r = 0;
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
if(channel[i].hdma_enabled) r++;
|
||||
|
@ -127,7 +127,7 @@ inline uint8 sCPU::hdma_enabled_channels() {
|
|||
return r;
|
||||
}
|
||||
|
||||
inline uint8 sCPU::hdma_active_channels() {
|
||||
inline uint8 CPU::hdma_active_channels() {
|
||||
uint8 r = 0;
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
if(hdma_active(i) == true) r++;
|
||||
|
@ -139,7 +139,7 @@ inline uint8 sCPU::hdma_active_channels() {
|
|||
//core functions
|
||||
//==============
|
||||
|
||||
void sCPU::dma_run() {
|
||||
void CPU::dma_run() {
|
||||
dma_add_clocks(8);
|
||||
dma_write(false);
|
||||
dma_edge();
|
||||
|
@ -163,7 +163,7 @@ void sCPU::dma_run() {
|
|||
status.irq_lock = true;
|
||||
}
|
||||
|
||||
void sCPU::hdma_update(unsigned i) {
|
||||
void CPU::hdma_update(unsigned i) {
|
||||
dma_add_clocks(4);
|
||||
regs.mdr = dma_read((channel[i].srcbank << 16) | channel[i].hdma_addr);
|
||||
dma_add_clocks(4);
|
||||
|
@ -195,7 +195,7 @@ void sCPU::hdma_update(unsigned i) {
|
|||
}
|
||||
}
|
||||
|
||||
void sCPU::hdma_run() {
|
||||
void CPU::hdma_run() {
|
||||
dma_add_clocks(8);
|
||||
dma_write(false);
|
||||
|
||||
|
@ -224,14 +224,14 @@ void sCPU::hdma_run() {
|
|||
status.irq_lock = true;
|
||||
}
|
||||
|
||||
void sCPU::hdma_init_reset() {
|
||||
void CPU::hdma_init_reset() {
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
channel[i].hdma_completed = false;
|
||||
channel[i].hdma_do_transfer = false;
|
||||
}
|
||||
}
|
||||
|
||||
void sCPU::hdma_init() {
|
||||
void CPU::hdma_init() {
|
||||
dma_add_clocks(8);
|
||||
dma_write(false);
|
||||
|
||||
|
@ -251,7 +251,7 @@ void sCPU::hdma_init() {
|
|||
//initialization
|
||||
//==============
|
||||
|
||||
void sCPU::dma_power() {
|
||||
void CPU::dma_power() {
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
channel[i].dmap = 0xff;
|
||||
channel[i].direction = 1;
|
||||
|
@ -275,7 +275,7 @@ void sCPU::dma_power() {
|
|||
}
|
||||
}
|
||||
|
||||
void sCPU::dma_reset() {
|
||||
void CPU::dma_reset() {
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
channel[i].dma_enabled = false;
|
||||
channel[i].hdma_enabled = false;
|
|
@ -1,13 +1,13 @@
|
|||
#ifdef SCPU_CPP
|
||||
#ifdef CPU_CPP
|
||||
|
||||
void sCPU::op_io() {
|
||||
void CPU::op_io() {
|
||||
status.clock_count = 6;
|
||||
dma_edge();
|
||||
add_clocks(6);
|
||||
alu_edge();
|
||||
}
|
||||
|
||||
uint8 sCPU::op_read(uint32 addr) {
|
||||
uint8 CPU::op_read(uint32 addr) {
|
||||
status.clock_count = speed(addr);
|
||||
dma_edge();
|
||||
add_clocks(status.clock_count - 4);
|
||||
|
@ -17,7 +17,7 @@ uint8 sCPU::op_read(uint32 addr) {
|
|||
return regs.mdr;
|
||||
}
|
||||
|
||||
void sCPU::op_write(uint32 addr, uint8 data) {
|
||||
void CPU::op_write(uint32 addr, uint8 data) {
|
||||
alu_edge();
|
||||
status.clock_count = speed(addr);
|
||||
dma_edge();
|
||||
|
@ -25,7 +25,7 @@ void sCPU::op_write(uint32 addr, uint8 data) {
|
|||
bus.write(addr, regs.mdr = data);
|
||||
}
|
||||
|
||||
unsigned sCPU::speed(unsigned addr) const {
|
||||
unsigned CPU::speed(unsigned addr) const {
|
||||
if(addr & 0x408000) {
|
||||
if(addr & 0x800000) return status.rom_speed;
|
||||
return 8;
|
|
@ -1,35 +1,35 @@
|
|||
#ifdef SCPU_CPP
|
||||
#ifdef CPU_CPP
|
||||
|
||||
uint8 sCPU::pio() { return status.pio; }
|
||||
bool sCPU::joylatch() { return status.joypad_strobe_latch; }
|
||||
uint8 CPU::pio() { return status.pio; }
|
||||
bool CPU::joylatch() { return status.joypad_strobe_latch; }
|
||||
|
||||
//WMDATA
|
||||
uint8 sCPU::mmio_r2180() {
|
||||
uint8 CPU::mmio_r2180() {
|
||||
uint8 r = bus.read(0x7e0000 | status.wram_addr);
|
||||
status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
|
||||
return r;
|
||||
}
|
||||
|
||||
//WMDATA
|
||||
void sCPU::mmio_w2180(uint8 data) {
|
||||
void CPU::mmio_w2180(uint8 data) {
|
||||
bus.write(0x7e0000 | status.wram_addr, data);
|
||||
status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
|
||||
}
|
||||
|
||||
//WMADDL
|
||||
void sCPU::mmio_w2181(uint8 data) {
|
||||
void CPU::mmio_w2181(uint8 data) {
|
||||
status.wram_addr = (status.wram_addr & 0xffff00) | (data);
|
||||
status.wram_addr &= 0x01ffff;
|
||||
}
|
||||
|
||||
//WMADDM
|
||||
void sCPU::mmio_w2182(uint8 data) {
|
||||
void CPU::mmio_w2182(uint8 data) {
|
||||
status.wram_addr = (status.wram_addr & 0xff00ff) | (data << 8);
|
||||
status.wram_addr &= 0x01ffff;
|
||||
}
|
||||
|
||||
//WMADDH
|
||||
void sCPU::mmio_w2183(uint8 data) {
|
||||
void CPU::mmio_w2183(uint8 data) {
|
||||
status.wram_addr = (status.wram_addr & 0x00ffff) | (data << 16);
|
||||
status.wram_addr &= 0x01ffff;
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ void sCPU::mmio_w2183(uint8 data) {
|
|||
//bit 0 is shared between JOYSER0 and JOYSER1, therefore
|
||||
//strobing $4016.d0 affects both controller port latches.
|
||||
//$4017 bit 0 writes are ignored.
|
||||
void sCPU::mmio_w4016(uint8 data) {
|
||||
void CPU::mmio_w4016(uint8 data) {
|
||||
bool old_latch = status.joypad_strobe_latch;
|
||||
bool new_latch = data & 1;
|
||||
status.joypad_strobe_latch = new_latch;
|
||||
|
@ -51,7 +51,7 @@ void sCPU::mmio_w4016(uint8 data) {
|
|||
//JOYSER0
|
||||
//7-2 = MDR
|
||||
//1-0 = Joypad serial data
|
||||
uint8 sCPU::mmio_r4016() {
|
||||
uint8 CPU::mmio_r4016() {
|
||||
uint8 r = regs.mdr & 0xfc;
|
||||
r |= input.port_read(0) & 3;
|
||||
return r;
|
||||
|
@ -61,20 +61,20 @@ uint8 sCPU::mmio_r4016() {
|
|||
//7-5 = MDR
|
||||
//4-2 = Always 1 (pins are connected to GND)
|
||||
//1-0 = Joypad serial data
|
||||
uint8 sCPU::mmio_r4017() {
|
||||
uint8 CPU::mmio_r4017() {
|
||||
uint8 r = (regs.mdr & 0xe0) | 0x1c;
|
||||
r |= input.port_read(1) & 3;
|
||||
return r;
|
||||
}
|
||||
|
||||
//NMITIMEN
|
||||
void sCPU::mmio_w4200(uint8 data) {
|
||||
void CPU::mmio_w4200(uint8 data) {
|
||||
status.auto_joypad_poll = !!(data & 0x01);
|
||||
nmitimen_update(data);
|
||||
}
|
||||
|
||||
//WRIO
|
||||
void sCPU::mmio_w4201(uint8 data) {
|
||||
void CPU::mmio_w4201(uint8 data) {
|
||||
if((status.pio & 0x80) && !(data & 0x80)) {
|
||||
ppu.latch_counters();
|
||||
}
|
||||
|
@ -82,12 +82,12 @@ void sCPU::mmio_w4201(uint8 data) {
|
|||
}
|
||||
|
||||
//WRMPYA
|
||||
void sCPU::mmio_w4202(uint8 data) {
|
||||
void CPU::mmio_w4202(uint8 data) {
|
||||
status.wrmpya = data;
|
||||
}
|
||||
|
||||
//WRMPYB
|
||||
void sCPU::mmio_w4203(uint8 data) {
|
||||
void CPU::mmio_w4203(uint8 data) {
|
||||
status.rdmpy = 0;
|
||||
if(alu.mpyctr || alu.divctr) return;
|
||||
|
||||
|
@ -99,17 +99,17 @@ void sCPU::mmio_w4203(uint8 data) {
|
|||
}
|
||||
|
||||
//WRDIVL
|
||||
void sCPU::mmio_w4204(uint8 data) {
|
||||
void CPU::mmio_w4204(uint8 data) {
|
||||
status.wrdiva = (status.wrdiva & 0xff00) | (data);
|
||||
}
|
||||
|
||||
//WRDIVH
|
||||
void sCPU::mmio_w4205(uint8 data) {
|
||||
void CPU::mmio_w4205(uint8 data) {
|
||||
status.wrdiva = (status.wrdiva & 0x00ff) | (data << 8);
|
||||
}
|
||||
|
||||
//WRDIVB
|
||||
void sCPU::mmio_w4206(uint8 data) {
|
||||
void CPU::mmio_w4206(uint8 data) {
|
||||
status.rdmpy = status.wrdiva;
|
||||
if(alu.mpyctr || alu.divctr) return;
|
||||
|
||||
|
@ -120,31 +120,31 @@ void sCPU::mmio_w4206(uint8 data) {
|
|||
}
|
||||
|
||||
//HTIMEL
|
||||
void sCPU::mmio_w4207(uint8 data) {
|
||||
void CPU::mmio_w4207(uint8 data) {
|
||||
status.hirq_pos = (status.hirq_pos & ~0xff) | (data);
|
||||
status.hirq_pos &= 0x01ff;
|
||||
}
|
||||
|
||||
//HTIMEH
|
||||
void sCPU::mmio_w4208(uint8 data) {
|
||||
void CPU::mmio_w4208(uint8 data) {
|
||||
status.hirq_pos = (status.hirq_pos & 0xff) | (data << 8);
|
||||
status.hirq_pos &= 0x01ff;
|
||||
}
|
||||
|
||||
//VTIMEL
|
||||
void sCPU::mmio_w4209(uint8 data) {
|
||||
void CPU::mmio_w4209(uint8 data) {
|
||||
status.virq_pos = (status.virq_pos & ~0xff) | (data);
|
||||
status.virq_pos &= 0x01ff;
|
||||
}
|
||||
|
||||
//VTIMEH
|
||||
void sCPU::mmio_w420a(uint8 data) {
|
||||
void CPU::mmio_w420a(uint8 data) {
|
||||
status.virq_pos = (status.virq_pos & 0xff) | (data << 8);
|
||||
status.virq_pos &= 0x01ff;
|
||||
}
|
||||
|
||||
//DMAEN
|
||||
void sCPU::mmio_w420b(uint8 data) {
|
||||
void CPU::mmio_w420b(uint8 data) {
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
channel[i].dma_enabled = data & (1 << i);
|
||||
}
|
||||
|
@ -152,14 +152,14 @@ void sCPU::mmio_w420b(uint8 data) {
|
|||
}
|
||||
|
||||
//HDMAEN
|
||||
void sCPU::mmio_w420c(uint8 data) {
|
||||
void CPU::mmio_w420c(uint8 data) {
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
channel[i].hdma_enabled = data & (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
//MEMSEL
|
||||
void sCPU::mmio_w420d(uint8 data) {
|
||||
void CPU::mmio_w420d(uint8 data) {
|
||||
status.rom_speed = (data & 1 ? 6 : 8);
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ void sCPU::mmio_w420d(uint8 data) {
|
|||
//7 = NMI acknowledge
|
||||
//6-4 = MDR
|
||||
//3-0 = CPU (5a22) version
|
||||
uint8 sCPU::mmio_r4210() {
|
||||
uint8 CPU::mmio_r4210() {
|
||||
uint8 r = (regs.mdr & 0x70);
|
||||
r |= (uint8)(rdnmi()) << 7;
|
||||
r |= (cpu_version & 0x0f);
|
||||
|
@ -177,7 +177,7 @@ uint8 sCPU::mmio_r4210() {
|
|||
//TIMEUP
|
||||
//7 = IRQ acknowledge
|
||||
//6-0 = MDR
|
||||
uint8 sCPU::mmio_r4211() {
|
||||
uint8 CPU::mmio_r4211() {
|
||||
uint8 r = (regs.mdr & 0x7f);
|
||||
r |= (uint8)(timeup()) << 7;
|
||||
return r;
|
||||
|
@ -188,7 +188,7 @@ uint8 sCPU::mmio_r4211() {
|
|||
//6 = HBLANK acknowledge
|
||||
//5-1 = MDR
|
||||
//0 = JOYPAD acknowledge
|
||||
uint8 sCPU::mmio_r4212() {
|
||||
uint8 CPU::mmio_r4212() {
|
||||
uint8 r = (regs.mdr & 0x3e);
|
||||
uint16 vs = ppu.overscan() == false ? 225 : 240;
|
||||
|
||||
|
@ -205,104 +205,104 @@ uint8 sCPU::mmio_r4212() {
|
|||
}
|
||||
|
||||
//RDIO
|
||||
uint8 sCPU::mmio_r4213() {
|
||||
uint8 CPU::mmio_r4213() {
|
||||
return status.pio;
|
||||
}
|
||||
|
||||
//RDDIVL
|
||||
uint8 sCPU::mmio_r4214() {
|
||||
uint8 CPU::mmio_r4214() {
|
||||
return status.rddiv;
|
||||
}
|
||||
|
||||
//RDDIVH
|
||||
uint8 sCPU::mmio_r4215() {
|
||||
uint8 CPU::mmio_r4215() {
|
||||
return status.rddiv >> 8;
|
||||
}
|
||||
|
||||
//RDMPYL
|
||||
uint8 sCPU::mmio_r4216() {
|
||||
uint8 CPU::mmio_r4216() {
|
||||
return status.rdmpy;
|
||||
}
|
||||
|
||||
//RDMPYH
|
||||
uint8 sCPU::mmio_r4217() {
|
||||
uint8 CPU::mmio_r4217() {
|
||||
return status.rdmpy >> 8;
|
||||
}
|
||||
|
||||
//TODO: handle reads during joypad polling (v=225-227)
|
||||
uint8 sCPU::mmio_r4218() { return status.joy1l; } //JOY1L
|
||||
uint8 sCPU::mmio_r4219() { return status.joy1h; } //JOY1H
|
||||
uint8 sCPU::mmio_r421a() { return status.joy2l; } //JOY2L
|
||||
uint8 sCPU::mmio_r421b() { return status.joy2h; } //JOY2H
|
||||
uint8 sCPU::mmio_r421c() { return status.joy3l; } //JOY3L
|
||||
uint8 sCPU::mmio_r421d() { return status.joy3h; } //JOY3H
|
||||
uint8 sCPU::mmio_r421e() { return status.joy4l; } //JOY4L
|
||||
uint8 sCPU::mmio_r421f() { return status.joy4h; } //JOY4H
|
||||
uint8 CPU::mmio_r4218() { return status.joy1l; } //JOY1L
|
||||
uint8 CPU::mmio_r4219() { return status.joy1h; } //JOY1H
|
||||
uint8 CPU::mmio_r421a() { return status.joy2l; } //JOY2L
|
||||
uint8 CPU::mmio_r421b() { return status.joy2h; } //JOY2H
|
||||
uint8 CPU::mmio_r421c() { return status.joy3l; } //JOY3L
|
||||
uint8 CPU::mmio_r421d() { return status.joy3h; } //JOY3H
|
||||
uint8 CPU::mmio_r421e() { return status.joy4l; } //JOY4L
|
||||
uint8 CPU::mmio_r421f() { return status.joy4h; } //JOY4H
|
||||
|
||||
//DMAPx
|
||||
uint8 sCPU::mmio_r43x0(uint8 i) {
|
||||
uint8 CPU::mmio_r43x0(uint8 i) {
|
||||
return channel[i].dmap;
|
||||
}
|
||||
|
||||
//BBADx
|
||||
uint8 sCPU::mmio_r43x1(uint8 i) {
|
||||
uint8 CPU::mmio_r43x1(uint8 i) {
|
||||
return channel[i].destaddr;
|
||||
}
|
||||
|
||||
//A1TxL
|
||||
uint8 sCPU::mmio_r43x2(uint8 i) {
|
||||
uint8 CPU::mmio_r43x2(uint8 i) {
|
||||
return channel[i].srcaddr;
|
||||
}
|
||||
|
||||
//A1TxH
|
||||
uint8 sCPU::mmio_r43x3(uint8 i) {
|
||||
uint8 CPU::mmio_r43x3(uint8 i) {
|
||||
return channel[i].srcaddr >> 8;
|
||||
}
|
||||
|
||||
//A1Bx
|
||||
uint8 sCPU::mmio_r43x4(uint8 i) {
|
||||
uint8 CPU::mmio_r43x4(uint8 i) {
|
||||
return channel[i].srcbank;
|
||||
}
|
||||
|
||||
//DASxL
|
||||
//union { uint16 xfersize; uint16 hdma_iaddr; };
|
||||
uint8 sCPU::mmio_r43x5(uint8 i) {
|
||||
uint8 CPU::mmio_r43x5(uint8 i) {
|
||||
return channel[i].xfersize;
|
||||
}
|
||||
|
||||
//DASxH
|
||||
//union { uint16 xfersize; uint16 hdma_iaddr; };
|
||||
uint8 sCPU::mmio_r43x6(uint8 i) {
|
||||
uint8 CPU::mmio_r43x6(uint8 i) {
|
||||
return channel[i].xfersize >> 8;
|
||||
}
|
||||
|
||||
//DASBx
|
||||
uint8 sCPU::mmio_r43x7(uint8 i) {
|
||||
uint8 CPU::mmio_r43x7(uint8 i) {
|
||||
return channel[i].hdma_ibank;
|
||||
}
|
||||
|
||||
//A2AxL
|
||||
uint8 sCPU::mmio_r43x8(uint8 i) {
|
||||
uint8 CPU::mmio_r43x8(uint8 i) {
|
||||
return channel[i].hdma_addr;
|
||||
}
|
||||
|
||||
//A2AxH
|
||||
uint8 sCPU::mmio_r43x9(uint8 i) {
|
||||
uint8 CPU::mmio_r43x9(uint8 i) {
|
||||
return channel[i].hdma_addr >> 8;
|
||||
}
|
||||
|
||||
//NTRLx
|
||||
uint8 sCPU::mmio_r43xa(uint8 i) {
|
||||
uint8 CPU::mmio_r43xa(uint8 i) {
|
||||
return channel[i].hdma_line_counter;
|
||||
}
|
||||
|
||||
//???
|
||||
uint8 sCPU::mmio_r43xb(uint8 i) {
|
||||
uint8 CPU::mmio_r43xb(uint8 i) {
|
||||
return channel[i].unknown;
|
||||
}
|
||||
|
||||
//DMAPx
|
||||
void sCPU::mmio_w43x0(uint8 i, uint8 data) {
|
||||
void CPU::mmio_w43x0(uint8 i, uint8 data) {
|
||||
channel[i].dmap = data;
|
||||
channel[i].direction = data & 0x80;
|
||||
channel[i].hdma_indirect = data & 0x40;
|
||||
|
@ -312,66 +312,66 @@ void sCPU::mmio_w43x0(uint8 i, uint8 data) {
|
|||
}
|
||||
|
||||
//DDBADx
|
||||
void sCPU::mmio_w43x1(uint8 i, uint8 data) {
|
||||
void CPU::mmio_w43x1(uint8 i, uint8 data) {
|
||||
channel[i].destaddr = data;
|
||||
}
|
||||
|
||||
//A1TxL
|
||||
void sCPU::mmio_w43x2(uint8 i, uint8 data) {
|
||||
void CPU::mmio_w43x2(uint8 i, uint8 data) {
|
||||
channel[i].srcaddr = (channel[i].srcaddr & 0xff00) | (data);
|
||||
}
|
||||
|
||||
//A1TxH
|
||||
void sCPU::mmio_w43x3(uint8 i, uint8 data) {
|
||||
void CPU::mmio_w43x3(uint8 i, uint8 data) {
|
||||
channel[i].srcaddr = (channel[i].srcaddr & 0x00ff) | (data << 8);
|
||||
}
|
||||
|
||||
//A1Bx
|
||||
void sCPU::mmio_w43x4(uint8 i, uint8 data) {
|
||||
void CPU::mmio_w43x4(uint8 i, uint8 data) {
|
||||
channel[i].srcbank = data;
|
||||
}
|
||||
|
||||
//DASxL
|
||||
//union { uint16 xfersize; uint16 hdma_iaddr; };
|
||||
void sCPU::mmio_w43x5(uint8 i, uint8 data) {
|
||||
void CPU::mmio_w43x5(uint8 i, uint8 data) {
|
||||
channel[i].xfersize = (channel[i].xfersize & 0xff00) | (data);
|
||||
}
|
||||
|
||||
//DASxH
|
||||
//union { uint16 xfersize; uint16 hdma_iaddr; };
|
||||
void sCPU::mmio_w43x6(uint8 i, uint8 data) {
|
||||
void CPU::mmio_w43x6(uint8 i, uint8 data) {
|
||||
channel[i].xfersize = (channel[i].xfersize & 0x00ff) | (data << 8);
|
||||
}
|
||||
|
||||
//DASBx
|
||||
void sCPU::mmio_w43x7(uint8 i, uint8 data) {
|
||||
void CPU::mmio_w43x7(uint8 i, uint8 data) {
|
||||
channel[i].hdma_ibank = data;
|
||||
}
|
||||
|
||||
//A2AxL
|
||||
void sCPU::mmio_w43x8(uint8 i, uint8 data) {
|
||||
void CPU::mmio_w43x8(uint8 i, uint8 data) {
|
||||
channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | (data);
|
||||
}
|
||||
|
||||
//A2AxH
|
||||
void sCPU::mmio_w43x9(uint8 i, uint8 data) {
|
||||
void CPU::mmio_w43x9(uint8 i, uint8 data) {
|
||||
channel[i].hdma_addr = (channel[i].hdma_addr & 0x00ff) | (data << 8);
|
||||
}
|
||||
|
||||
//NTRLx
|
||||
void sCPU::mmio_w43xa(uint8 i, uint8 data) {
|
||||
void CPU::mmio_w43xa(uint8 i, uint8 data) {
|
||||
channel[i].hdma_line_counter = data;
|
||||
}
|
||||
|
||||
//???
|
||||
void sCPU::mmio_w43xb(uint8 i, uint8 data) {
|
||||
void CPU::mmio_w43xb(uint8 i, uint8 data) {
|
||||
channel[i].unknown = data;
|
||||
}
|
||||
|
||||
void sCPU::mmio_power() {
|
||||
void CPU::mmio_power() {
|
||||
}
|
||||
|
||||
void sCPU::mmio_reset() {
|
||||
void CPU::mmio_reset() {
|
||||
//$2181-$2183
|
||||
status.wram_addr = 0x000000;
|
||||
|
||||
|
@ -424,7 +424,7 @@ void sCPU::mmio_reset() {
|
|||
alu.shift = 0;
|
||||
}
|
||||
|
||||
uint8 sCPU::mmio_read(unsigned addr) {
|
||||
uint8 CPU::mmio_read(unsigned addr) {
|
||||
addr &= 0xffff;
|
||||
|
||||
//APU
|
||||
|
@ -481,7 +481,7 @@ uint8 sCPU::mmio_read(unsigned addr) {
|
|||
return regs.mdr;
|
||||
}
|
||||
|
||||
void sCPU::mmio_write(unsigned addr, uint8 data) {
|
||||
void CPU::mmio_write(unsigned addr, uint8 data) {
|
||||
addr &= 0xffff;
|
||||
|
||||
//APU
|
|
@ -1,134 +0,0 @@
|
|||
#ifdef SCPU_CPP
|
||||
|
||||
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::BreakEvent::CPUStep;
|
||||
scheduler.exit(Scheduler::ExitReason::DebuggerEvent);
|
||||
} else {
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00);
|
||||
}
|
||||
|
||||
if(step_event) step_event();
|
||||
sCPU::op_step();
|
||||
synchronize_smp();
|
||||
}
|
||||
|
||||
uint8 sCPUDebugger::op_read(uint32 addr) {
|
||||
uint8 data = sCPU::op_read(addr);
|
||||
usage[addr] |= UsageRead;
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Read, addr, data);
|
||||
return 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::Source::CPUBus, Debugger::Breakpoint::Mode::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.wrmpya; }
|
||||
|
||||
//$4203
|
||||
unsigned sCPUDebugger::multiplier() { return status.wrmpyb; }
|
||||
|
||||
//$4204-$4205
|
||||
unsigned sCPUDebugger::dividend() { return status.wrdiva; }
|
||||
|
||||
//$4206
|
||||
unsigned sCPUDebugger::divisor() { return status.wrdivb; }
|
||||
|
||||
//$4207-$4208
|
||||
unsigned sCPUDebugger::htime() { return status.hirq_pos; }
|
||||
|
||||
//$4209-$420a
|
||||
unsigned sCPUDebugger::vtime() { return status.virq_pos; }
|
||||
|
||||
//$420b
|
||||
unsigned sCPUDebugger::dma_enable() {
|
||||
unsigned result = 0;
|
||||
for(unsigned n = 0; n < 8; n++) {
|
||||
result |= channel[n].dma_enabled << n;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//$420c
|
||||
unsigned sCPUDebugger::hdma_enable() {
|
||||
unsigned result = 0;
|
||||
for(unsigned n = 0; n < 8; n++) {
|
||||
result |= channel[n].hdma_enabled << n;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//$420d
|
||||
bool sCPUDebugger::fastrom_enable() { return status.rom_speed; }
|
||||
|
||||
//$43x0
|
||||
bool sCPUDebugger::dma_direction(unsigned n) { return channel[n].direction; }
|
||||
bool sCPUDebugger::dma_indirect(unsigned n) { return channel[n].hdma_indirect; }
|
||||
bool sCPUDebugger::dma_reverse_transfer(unsigned n) { return channel[n].reversexfer; }
|
||||
bool sCPUDebugger::dma_fixed_transfer(unsigned n) { return channel[n].fixedxfer; }
|
||||
unsigned sCPUDebugger::dma_transfer_mode(unsigned n) { return channel[n].xfermode; }
|
||||
|
||||
//$43x1
|
||||
unsigned sCPUDebugger::dma_bbus_address(unsigned n) { return 0x2100 + channel[n].destaddr; }
|
||||
|
||||
//$43x2-$43x3
|
||||
unsigned sCPUDebugger::dma_abus_address(unsigned n) { return channel[n].srcaddr; }
|
||||
|
||||
//$43x4
|
||||
unsigned sCPUDebugger::dma_abus_bank(unsigned n) { return channel[n].srcbank; }
|
||||
|
||||
//$43x5-$43x6
|
||||
unsigned sCPUDebugger::dma_transfer_size(unsigned n) { return channel[n].xfersize; }
|
||||
|
||||
//$43x7
|
||||
unsigned sCPUDebugger::dma_indirect_bank(unsigned n) { return channel[n].hdma_ibank; }
|
||||
|
||||
//$43x8-$43x9
|
||||
unsigned sCPUDebugger::dma_table_address(unsigned n) { return channel[n].hdma_addr; }
|
||||
|
||||
//$43xa
|
||||
unsigned sCPUDebugger::dma_line_counter(unsigned n) { return channel[n].hdma_line_counter; }
|
||||
|
||||
#endif
|
|
@ -1,113 +0,0 @@
|
|||
#include <snes.hpp>
|
||||
|
||||
#define SCPU_CPP
|
||||
namespace SNES {
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.cpp"
|
||||
sCPUDebugger cpu;
|
||||
#else
|
||||
sCPU cpu;
|
||||
#endif
|
||||
|
||||
#include "serialization.cpp"
|
||||
#include "dma/dma.cpp"
|
||||
#include "memory/memory.cpp"
|
||||
#include "mmio/mmio.cpp"
|
||||
#include "timing/timing.cpp"
|
||||
|
||||
void sCPU::enter() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
if(status.interrupt_pending) {
|
||||
status.interrupt_pending = false;
|
||||
if(status.nmi_pending) {
|
||||
status.nmi_pending = false;
|
||||
status.interrupt_vector = (regs.e == false ? 0xffea : 0xfffa);
|
||||
op_irq();
|
||||
} else if(status.irq_pending) {
|
||||
status.irq_pending = false;
|
||||
status.interrupt_vector = (regs.e == false ? 0xffee : 0xfffe);
|
||||
op_irq();
|
||||
} else if(status.reset_pending) {
|
||||
status.reset_pending = false;
|
||||
add_clocks(186);
|
||||
regs.pc.l = bus.read(0xfffc);
|
||||
regs.pc.h = bus.read(0xfffd);
|
||||
}
|
||||
}
|
||||
|
||||
op_step();
|
||||
}
|
||||
}
|
||||
|
||||
void sCPU::op_step() {
|
||||
(this->*opcode_table[op_readpc()])();
|
||||
}
|
||||
|
||||
void sCPU::op_irq() {
|
||||
op_read(regs.pc.d);
|
||||
op_io();
|
||||
if(!regs.e) op_writestack(regs.pc.b);
|
||||
op_writestack(regs.pc.h);
|
||||
op_writestack(regs.pc.l);
|
||||
op_writestack(regs.e ? (regs.p & ~0x10) : regs.p);
|
||||
rd.l = op_read(status.interrupt_vector + 0);
|
||||
regs.pc.b = 0x00;
|
||||
regs.p.i = 1;
|
||||
regs.p.d = 0;
|
||||
rd.h = op_read(status.interrupt_vector + 1);
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
void sCPU::power() {
|
||||
CPU::power();
|
||||
|
||||
regs.a = regs.x = regs.y = 0x0000;
|
||||
regs.s = 0x01ff;
|
||||
|
||||
mmio_power();
|
||||
dma_power();
|
||||
timing_power();
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void sCPU::reset() {
|
||||
CPU::reset();
|
||||
|
||||
//note: some registers are not fully reset by SNES
|
||||
regs.pc = 0x000000;
|
||||
regs.x.h = 0x00;
|
||||
regs.y.h = 0x00;
|
||||
regs.s.h = 0x01;
|
||||
regs.d = 0x0000;
|
||||
regs.db = 0x00;
|
||||
regs.p = 0x34;
|
||||
regs.e = 1;
|
||||
regs.mdr = 0x00;
|
||||
regs.wai = false;
|
||||
update_table();
|
||||
|
||||
mmio_reset();
|
||||
dma_reset();
|
||||
timing_reset();
|
||||
|
||||
apu_port[0] = 0x00;
|
||||
apu_port[1] = 0x00;
|
||||
apu_port[2] = 0x00;
|
||||
apu_port[3] = 0x00;
|
||||
}
|
||||
|
||||
sCPU::sCPU() {
|
||||
PPUCounter::scanline = { &sCPU::scanline, this };
|
||||
}
|
||||
|
||||
sCPU::~sCPU() {
|
||||
}
|
||||
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
class sCPU : public CPU, public CPUcore {
|
||||
public:
|
||||
void enter();
|
||||
debugvirtual void op_step();
|
||||
void op_irq();
|
||||
bool interrupt_pending() { return status.interrupt_pending; }
|
||||
|
||||
#include "dma/dma.hpp"
|
||||
#include "memory/memory.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "timing/timing.hpp"
|
||||
|
||||
struct Status {
|
||||
bool interrupt_pending;
|
||||
uint16 interrupt_vector;
|
||||
|
||||
unsigned clock_count;
|
||||
unsigned line_clocks;
|
||||
|
||||
//======
|
||||
//timing
|
||||
//======
|
||||
|
||||
bool irq_lock;
|
||||
|
||||
unsigned dram_refresh_position;
|
||||
bool dram_refreshed;
|
||||
|
||||
unsigned hdma_init_position;
|
||||
bool hdma_init_triggered;
|
||||
|
||||
unsigned hdma_position;
|
||||
bool hdma_triggered;
|
||||
|
||||
bool nmi_valid;
|
||||
bool nmi_line;
|
||||
bool nmi_transition;
|
||||
bool nmi_pending;
|
||||
bool nmi_hold;
|
||||
|
||||
bool irq_valid;
|
||||
bool irq_line;
|
||||
bool irq_transition;
|
||||
bool irq_pending;
|
||||
bool irq_hold;
|
||||
|
||||
bool reset_pending;
|
||||
|
||||
//===
|
||||
//DMA
|
||||
//===
|
||||
|
||||
bool dma_active;
|
||||
unsigned dma_counter;
|
||||
unsigned dma_clocks;
|
||||
bool dma_pending;
|
||||
bool hdma_pending;
|
||||
bool hdma_mode; //0 = init, 1 = run
|
||||
|
||||
//====
|
||||
//MMIO
|
||||
//====
|
||||
|
||||
//$2181-$2183
|
||||
uint32 wram_addr;
|
||||
|
||||
//$4016-$4017
|
||||
bool joypad_strobe_latch;
|
||||
uint32 joypad1_bits;
|
||||
uint32 joypad2_bits;
|
||||
|
||||
//$4200
|
||||
bool nmi_enabled;
|
||||
bool hirq_enabled, virq_enabled;
|
||||
bool auto_joypad_poll;
|
||||
|
||||
//$4201
|
||||
uint8 pio;
|
||||
|
||||
//$4202-$4203
|
||||
uint8 wrmpya;
|
||||
uint8 wrmpyb;
|
||||
|
||||
//$4204-$4206
|
||||
uint16 wrdiva;
|
||||
uint8 wrdivb;
|
||||
|
||||
//$4207-$420a
|
||||
uint16 hirq_pos, virq_pos;
|
||||
|
||||
//$420d
|
||||
unsigned rom_speed;
|
||||
|
||||
//$4214-$4217
|
||||
uint16 rddiv;
|
||||
uint16 rdmpy;
|
||||
|
||||
//$4218-$421f
|
||||
uint8 joy1l, joy1h;
|
||||
uint8 joy2l, joy2h;
|
||||
uint8 joy3l, joy3h;
|
||||
uint8 joy4l, joy4h;
|
||||
} status;
|
||||
|
||||
struct ALU {
|
||||
unsigned mpyctr;
|
||||
unsigned divctr;
|
||||
unsigned shift;
|
||||
} alu;
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
sCPU();
|
||||
~sCPU();
|
||||
|
||||
friend class sCPUDebug;
|
||||
};
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.hpp"
|
||||
extern sCPUDebugger cpu;
|
||||
#else
|
||||
extern sCPU cpu;
|
||||
#endif
|
|
@ -1,8 +1,10 @@
|
|||
#ifdef SCPU_CPP
|
||||
#ifdef CPU_CPP
|
||||
|
||||
void sCPU::serialize(serializer &s) {
|
||||
CPU::serialize(s);
|
||||
void CPU::serialize(serializer &s) {
|
||||
CPUcore::core_serialize(s);
|
||||
Processor::serialize(s);
|
||||
PPUCounter::serialize(s);
|
||||
s.integer(cpu_version);
|
||||
|
||||
s.integer(status.interrupt_pending);
|
||||
s.integer(status.interrupt_vector);
|
|
@ -1,23 +0,0 @@
|
|||
void CPU::step(unsigned clocks) {
|
||||
smp.clock -= clocks * (uint64)smp.frequency;
|
||||
ppu.clock -= clocks;
|
||||
for(unsigned i = 0; i < coprocessors.size(); i++) {
|
||||
Processor &chip = *coprocessors[i];
|
||||
chip.clock -= clocks * (uint64)chip.frequency;
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::synchronize_smp() {
|
||||
if(smp.clock < 0) co_switch(smp.thread);
|
||||
}
|
||||
|
||||
void CPU::synchronize_ppu() {
|
||||
if(ppu.clock < 0) co_switch(ppu.thread);
|
||||
}
|
||||
|
||||
void CPU::synchronize_coprocessor() {
|
||||
for(unsigned i = 0; i < coprocessors.size(); i++) {
|
||||
Processor &chip = *coprocessors[i];
|
||||
if(chip.clock < 0) co_switch(chip.thread);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
#ifdef SCPU_CPP
|
||||
#ifdef CPU_CPP
|
||||
|
||||
//called once every four clock cycles;
|
||||
//as NMI steps by scanlines (divisible by 4) and IRQ by PPU 4-cycle dots.
|
||||
//
|
||||
//ppu.(vh)counter(n) returns the value of said counters n-clocks before current time;
|
||||
//it is used to emulate hardware communication delay between opcode and interrupt units.
|
||||
void sCPU::poll_interrupts() {
|
||||
void CPU::poll_interrupts() {
|
||||
//NMI hold
|
||||
if(status.nmi_hold) {
|
||||
status.nmi_hold = false;
|
||||
|
@ -46,7 +46,7 @@ void sCPU::poll_interrupts() {
|
|||
status.irq_valid = irq_valid;
|
||||
}
|
||||
|
||||
void sCPU::nmitimen_update(uint8 data) {
|
||||
void CPU::nmitimen_update(uint8 data) {
|
||||
bool nmi_enabled = status.nmi_enabled;
|
||||
bool virq_enabled = status.virq_enabled;
|
||||
bool hirq_enabled = status.hirq_enabled;
|
||||
|
@ -72,7 +72,7 @@ void sCPU::nmitimen_update(uint8 data) {
|
|||
status.irq_lock = true;
|
||||
}
|
||||
|
||||
bool sCPU::rdnmi() {
|
||||
bool CPU::rdnmi() {
|
||||
bool result = status.nmi_line;
|
||||
if(!status.nmi_hold) {
|
||||
status.nmi_line = false;
|
||||
|
@ -80,7 +80,7 @@ bool sCPU::rdnmi() {
|
|||
return result;
|
||||
}
|
||||
|
||||
bool sCPU::timeup() {
|
||||
bool CPU::timeup() {
|
||||
bool result = status.irq_line;
|
||||
if(!status.irq_hold) {
|
||||
status.irq_line = false;
|
||||
|
@ -89,14 +89,14 @@ bool sCPU::timeup() {
|
|||
return result;
|
||||
}
|
||||
|
||||
bool sCPU::nmi_test() {
|
||||
bool CPU::nmi_test() {
|
||||
if(!status.nmi_transition) return false;
|
||||
status.nmi_transition = false;
|
||||
regs.wai = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sCPU::irq_test() {
|
||||
bool CPU::irq_test() {
|
||||
if(!status.irq_transition && !regs.irq) return false;
|
||||
status.irq_transition = false;
|
||||
regs.wai = false;
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef SCPU_CPP
|
||||
#ifdef CPU_CPP
|
||||
|
||||
void sCPU::run_auto_joypad_poll() {
|
||||
void CPU::run_auto_joypad_poll() {
|
||||
uint16 joy1 = 0, joy2 = 0, joy3 = 0, joy4 = 0;
|
||||
for(unsigned i = 0; i < 16; i++) {
|
||||
uint8 port0 = input.port_read(0);
|
|
@ -1,13 +1,13 @@
|
|||
#ifdef SCPU_CPP
|
||||
#ifdef CPU_CPP
|
||||
|
||||
#include "irq.cpp"
|
||||
#include "joypad.cpp"
|
||||
|
||||
unsigned sCPU::dma_counter() {
|
||||
unsigned CPU::dma_counter() {
|
||||
return (status.dma_counter + hcounter()) & 7;
|
||||
}
|
||||
|
||||
void sCPU::add_clocks(unsigned clocks) {
|
||||
void CPU::add_clocks(unsigned clocks) {
|
||||
status.irq_lock = false;
|
||||
unsigned ticks = clocks >> 1;
|
||||
while(ticks--) {
|
||||
|
@ -27,7 +27,7 @@ void sCPU::add_clocks(unsigned clocks) {
|
|||
}
|
||||
|
||||
//called by ppu.tick() when Hcounter=0
|
||||
void sCPU::scanline() {
|
||||
void CPU::scanline() {
|
||||
status.dma_counter = (status.dma_counter + status.line_clocks) & 7;
|
||||
status.line_clocks = lineclocks();
|
||||
|
||||
|
@ -59,7 +59,7 @@ void sCPU::scanline() {
|
|||
}
|
||||
}
|
||||
|
||||
void sCPU::alu_edge() {
|
||||
void CPU::alu_edge() {
|
||||
if(alu.mpyctr) {
|
||||
alu.mpyctr--;
|
||||
if(status.rddiv & 1) status.rdmpy += alu.shift;
|
||||
|
@ -78,7 +78,7 @@ void sCPU::alu_edge() {
|
|||
}
|
||||
}
|
||||
|
||||
void sCPU::dma_edge() {
|
||||
void CPU::dma_edge() {
|
||||
//H/DMA pending && DMA inactive?
|
||||
//.. Run one full CPU cycle
|
||||
//.. HDMA pending && HDMA enabled ? DMA sync + HDMA run
|
||||
|
@ -143,7 +143,7 @@ void sCPU::dma_edge() {
|
|||
//
|
||||
//status.irq_lock is used to simulate hardware delay before interrupts can
|
||||
//trigger during certain events (immediately after DMA, writes to $4200, etc)
|
||||
void sCPU::last_cycle() {
|
||||
void CPU::last_cycle() {
|
||||
if(status.irq_lock == false) {
|
||||
status.nmi_pending |= nmi_test();
|
||||
status.irq_pending |= irq_test();
|
||||
|
@ -151,10 +151,10 @@ void sCPU::last_cycle() {
|
|||
}
|
||||
}
|
||||
|
||||
void sCPU::timing_power() {
|
||||
void CPU::timing_power() {
|
||||
}
|
||||
|
||||
void sCPU::timing_reset() {
|
||||
void CPU::timing_reset() {
|
||||
status.clock_count = 0;
|
||||
status.line_clocks = lineclocks();
|
||||
|
|
@ -1,613 +0,0 @@
|
|||
#include <snes.hpp>
|
||||
|
||||
#define ADSP_CPP
|
||||
namespace SNES {
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.cpp"
|
||||
aDSPDebugger dsp;
|
||||
#else
|
||||
aDSP dsp;
|
||||
#endif
|
||||
|
||||
#include "tables.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
void aDSP::enter() {
|
||||
#if !defined(DSP_STATE_MACHINE)
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
#endif
|
||||
run();
|
||||
#if !defined(DSP_STATE_MACHINE)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8 aDSP::readb(uint16 addr) {
|
||||
return spcram[addr];
|
||||
}
|
||||
|
||||
void aDSP::writeb(uint16 addr, uint8 data) {
|
||||
spcram[addr] = data;
|
||||
}
|
||||
|
||||
uint16 aDSP::readw(uint16 addr) {
|
||||
return (readb(addr + 0)) | (readb(addr + 1) << 8);
|
||||
}
|
||||
|
||||
void aDSP::writew(uint16 addr, uint16 data) {
|
||||
writeb(addr + 0, data);
|
||||
writeb(addr + 1, data >> 8);
|
||||
}
|
||||
|
||||
uint8 aDSP::read(uint8 addr) {
|
||||
addr &= 127;
|
||||
int v = addr >> 4;
|
||||
int n = addr & 15;
|
||||
|
||||
switch(addr) {
|
||||
case 0x00: case 0x10: case 0x20: case 0x30:
|
||||
case 0x40: case 0x50: case 0x60: case 0x70:
|
||||
return voice[v].VOLL;
|
||||
case 0x01: case 0x11: case 0x21: case 0x31:
|
||||
case 0x41: case 0x51: case 0x61: case 0x71:
|
||||
return voice[v].VOLR;
|
||||
case 0x02: case 0x12: case 0x22: case 0x32:
|
||||
case 0x42: case 0x52: case 0x62: case 0x72:
|
||||
return voice[v].PITCH;
|
||||
case 0x03: case 0x13: case 0x23: case 0x33:
|
||||
case 0x43: case 0x53: case 0x63: case 0x73:
|
||||
return voice[v].PITCH >> 8;
|
||||
case 0x04: case 0x14: case 0x24: case 0x34:
|
||||
case 0x44: case 0x54: case 0x64: case 0x74:
|
||||
return voice[v].SRCN;
|
||||
case 0x05: case 0x15: case 0x25: case 0x35:
|
||||
case 0x45: case 0x55: case 0x65: case 0x75:
|
||||
return voice[v].ADSR1;
|
||||
case 0x06: case 0x16: case 0x26: case 0x36:
|
||||
case 0x46: case 0x56: case 0x66: case 0x76:
|
||||
return voice[v].ADSR2;
|
||||
case 0x07: case 0x17: case 0x27: case 0x37:
|
||||
case 0x47: case 0x57: case 0x67: case 0x77:
|
||||
return voice[v].GAIN;
|
||||
case 0x08: case 0x18: case 0x28: case 0x38:
|
||||
case 0x48: case 0x58: case 0x68: case 0x78:
|
||||
return voice[v].ENVX;
|
||||
case 0x09: case 0x19: case 0x29: case 0x39:
|
||||
case 0x49: case 0x59: case 0x69: case 0x79:
|
||||
return voice[v].OUTX;
|
||||
|
||||
case 0x0f: case 0x1f: case 0x2f: case 0x3f:
|
||||
case 0x4f: case 0x5f: case 0x6f: case 0x7f:
|
||||
return status.FIR[v];
|
||||
|
||||
case 0x0c: return status.MVOLL;
|
||||
case 0x1c: return status.MVOLR;
|
||||
case 0x2c: return status.EVOLL;
|
||||
case 0x3c: return status.EVOLR;
|
||||
case 0x4c: return status.KON;
|
||||
case 0x5c: return status.KOFF;
|
||||
case 0x6c: return status.FLG;
|
||||
case 0x7c: return status.ENDX;
|
||||
|
||||
case 0x0d: return status.EFB;
|
||||
case 0x2d: return status.PMON;
|
||||
case 0x3d: return status.NON;
|
||||
case 0x4d: return status.EON;
|
||||
case 0x5d: return status.DIR;
|
||||
case 0x6d: return status.ESA;
|
||||
case 0x7d: return status.EDL;
|
||||
}
|
||||
|
||||
return dspram[addr];
|
||||
}
|
||||
|
||||
void aDSP::write(uint8 addr, uint8 data) {
|
||||
//0x80-0xff is a read-only mirror of 0x00-0x7f
|
||||
if(addr & 0x80)return;
|
||||
|
||||
int v = addr >> 4;
|
||||
int n = addr & 15;
|
||||
|
||||
switch(addr) {
|
||||
case 0x00: case 0x10: case 0x20: case 0x30:
|
||||
case 0x40: case 0x50: case 0x60: case 0x70:
|
||||
voice[v].VOLL = data;
|
||||
break;
|
||||
case 0x01: case 0x11: case 0x21: case 0x31:
|
||||
case 0x41: case 0x51: case 0x61: case 0x71:
|
||||
voice[v].VOLR = data;
|
||||
break;
|
||||
case 0x02: case 0x12: case 0x22: case 0x32:
|
||||
case 0x42: case 0x52: case 0x62: case 0x72:
|
||||
voice[v].PITCH &= 0xff00;
|
||||
voice[v].PITCH |= data;
|
||||
break;
|
||||
case 0x03: case 0x13: case 0x23: case 0x33:
|
||||
case 0x43: case 0x53: case 0x63: case 0x73:
|
||||
voice[v].PITCH &= 0x00ff;
|
||||
voice[v].PITCH |= data << 8;
|
||||
break;
|
||||
case 0x04: case 0x14: case 0x24: case 0x34:
|
||||
case 0x44: case 0x54: case 0x64: case 0x74:
|
||||
voice[v].SRCN = data;
|
||||
break;
|
||||
case 0x05: case 0x15: case 0x25: case 0x35:
|
||||
case 0x45: case 0x55: case 0x65: case 0x75:
|
||||
voice[v].ADSR1 = data;
|
||||
voice[v].AdjustEnvelope();
|
||||
break;
|
||||
case 0x06: case 0x16: case 0x26: case 0x36:
|
||||
case 0x46: case 0x56: case 0x66: case 0x76:
|
||||
voice[v].ADSR2 = data;
|
||||
//sustain_level = 0-7, 7 is a special case handled by ATTACK envx mode
|
||||
voice[v].env_sustain = (voice[v].ADSR_sus_level() + 1) << 8;
|
||||
voice[v].AdjustEnvelope();
|
||||
break;
|
||||
case 0x07: case 0x17: case 0x27: case 0x37:
|
||||
case 0x47: case 0x57: case 0x67: case 0x77:
|
||||
voice[v].GAIN = data;
|
||||
voice[v].AdjustEnvelope();
|
||||
break;
|
||||
case 0x08: case 0x18: case 0x28: case 0x38:
|
||||
case 0x48: case 0x58: case 0x68: case 0x78:
|
||||
voice[v].ENVX = data;
|
||||
break;
|
||||
case 0x09: case 0x19: case 0x29: case 0x39:
|
||||
case 0x49: case 0x59: case 0x69: case 0x79:
|
||||
voice[v].OUTX = data;
|
||||
break;
|
||||
|
||||
case 0x0f: case 0x1f: case 0x2f: case 0x3f:
|
||||
case 0x4f: case 0x5f: case 0x6f: case 0x7f:
|
||||
status.FIR[v] = data;
|
||||
break;
|
||||
|
||||
case 0x0c: status.MVOLL = data; break;
|
||||
case 0x1c: status.MVOLR = data; break;
|
||||
case 0x2c: status.EVOLL = data; break;
|
||||
case 0x3c: status.EVOLR = data; break;
|
||||
|
||||
case 0x4c:
|
||||
status.KON = data;
|
||||
status.kon = data;
|
||||
break;
|
||||
case 0x5c:
|
||||
status.KOFF = data;
|
||||
break;
|
||||
case 0x6c:
|
||||
status.FLG = data;
|
||||
status.noise_rate = rate_table[data & 0x1f];
|
||||
break;
|
||||
|
||||
case 0x7c:
|
||||
//read-only register, writes clear all bits of ENDX
|
||||
status.ENDX = 0;
|
||||
break;
|
||||
|
||||
case 0x0d: status.EFB = data; break;
|
||||
case 0x2d: status.PMON = data; break;
|
||||
case 0x3d: status.NON = data; break;
|
||||
case 0x4d: status.EON = data; break;
|
||||
case 0x5d: status.DIR = data; break;
|
||||
case 0x6d: status.ESA = data; break;
|
||||
case 0x7d: status.EDL = data; break;
|
||||
}
|
||||
|
||||
dspram[addr] = data;
|
||||
}
|
||||
|
||||
void aDSP::power() {
|
||||
DSP::power();
|
||||
|
||||
spcram = memory::apuram.data();
|
||||
memset(dspram, 0x00, 128);
|
||||
|
||||
for(int v = 0; v < 8; v++) {
|
||||
voice[v].VOLL = 0;
|
||||
voice[v].VOLR = 0;
|
||||
voice[v].PITCH = 0;
|
||||
voice[v].SRCN = 0;
|
||||
voice[v].ADSR1 = 0;
|
||||
voice[v].ADSR2 = 0;
|
||||
voice[v].GAIN = 0;
|
||||
|
||||
status.FIR[v] = 0;
|
||||
}
|
||||
|
||||
status.FLG = 0xe0;
|
||||
status.MVOLL = status.MVOLR = 0;
|
||||
status.EVOLL = status.EVOLR = 0;
|
||||
status.ENDX = 0;
|
||||
status.EFB = 0;
|
||||
status.PMON = 0;
|
||||
status.NON = 0;
|
||||
status.EON = 0;
|
||||
status.DIR = 0;
|
||||
status.ESA = 0;
|
||||
status.EDL = 0;
|
||||
|
||||
status.echo_length = 0;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void aDSP::reset() {
|
||||
DSP::reset();
|
||||
|
||||
status.KON = 0x00;
|
||||
status.KOFF = 0x00;
|
||||
status.FLG |= 0xe0;
|
||||
|
||||
status.kon = 0x00;
|
||||
status.esa = 0x00;
|
||||
|
||||
status.noise_ctr = 0;
|
||||
status.noise_rate = 0;
|
||||
status.noise_sample = 0x4000;
|
||||
|
||||
status.echo_index = 0;
|
||||
status.fir_buffer_index = 0;
|
||||
|
||||
for(int v = 0; v < 8; v++) {
|
||||
voice[v].ENVX = 0;
|
||||
voice[v].OUTX = 0;
|
||||
|
||||
voice[v].pitch_ctr = 0;
|
||||
|
||||
voice[v].brr_index = 0;
|
||||
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2));
|
||||
voice[v].brr_looped = false;
|
||||
voice[v].brr_data[0] = 0;
|
||||
voice[v].brr_data[1] = 0;
|
||||
voice[v].brr_data[2] = 0;
|
||||
voice[v].brr_data[3] = 0;
|
||||
voice[v].brr_data_index = 0;
|
||||
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_ctr = 0;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].env_mode = DIRECT;
|
||||
|
||||
status.fir_buffer[0][v] = 0;
|
||||
status.fir_buffer[1][v] = 0;
|
||||
}
|
||||
|
||||
dsp_counter = 0;
|
||||
}
|
||||
|
||||
void aDSP::run() {
|
||||
uint8 pmon;
|
||||
int32 sample;
|
||||
int32 msamplel, msampler;
|
||||
int32 esamplel, esampler;
|
||||
int32 fir_samplel, fir_sampler;
|
||||
pmon = status.PMON & ~status.NON & ~1;
|
||||
|
||||
if((dsp_counter++ & 1) == 0) {
|
||||
for(unsigned v = 0; v < 8; v++) {
|
||||
if(status.soft_reset()) {
|
||||
if(voice[v].env_state != SILENCE) {
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
if(status.KOFF & (1 << v)) {
|
||||
if(voice[v].env_state != SILENCE && voice[v].env_state != RELEASE) {
|
||||
voice[v].env_state = RELEASE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
if(status.kon & (1 << v)) {
|
||||
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2));
|
||||
voice[v].brr_index = -9;
|
||||
voice[v].brr_looped = false;
|
||||
voice[v].brr_data[0] = 0;
|
||||
voice[v].brr_data[1] = 0;
|
||||
voice[v].brr_data[2] = 0;
|
||||
voice[v].brr_data[3] = 0;
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_state = ATTACK;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
status.ENDX &= ~status.kon;
|
||||
status.kon = 0;
|
||||
}
|
||||
|
||||
/*****
|
||||
* update noise
|
||||
*****/
|
||||
status.noise_ctr += status.noise_rate;
|
||||
if(status.noise_ctr >= 0x7800) {
|
||||
status.noise_ctr -= 0x7800;
|
||||
status.noise_sample = (status.noise_sample >> 1) | (((status.noise_sample << 14) ^ (status.noise_sample << 13)) & 0x4000);
|
||||
}
|
||||
|
||||
msamplel = msampler = 0;
|
||||
esamplel = esampler = 0;
|
||||
|
||||
/*****
|
||||
* process voice channels
|
||||
*****/
|
||||
for(int v = 0; v < 8; v++) {
|
||||
if(voice[v].brr_index < -1) {
|
||||
voice[v].brr_index++;
|
||||
voice[v].OUTX = voice[v].outx = 0;
|
||||
voice[v].ENVX = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(voice[v].brr_index >= 0) {
|
||||
if(pmon & (1 << v)) {
|
||||
voice[v].pitch_ctr += (voice[v].pitch_rate() * (voice[v - 1].outx + 0x8000)) >> 15;
|
||||
} else {
|
||||
voice[v].pitch_ctr += voice[v].pitch_rate();
|
||||
}
|
||||
} else {
|
||||
voice[v].pitch_ctr = 0x3000;
|
||||
voice[v].brr_index = 0;
|
||||
}
|
||||
|
||||
/*****
|
||||
* decode BRR samples
|
||||
*****/
|
||||
while(voice[v].pitch_ctr >= 0) {
|
||||
voice[v].pitch_ctr -= 0x1000;
|
||||
|
||||
voice[v].brr_data_index++;
|
||||
voice[v].brr_data_index &= 3;
|
||||
|
||||
if(voice[v].brr_index == 0) {
|
||||
voice[v].brr_header = readb(voice[v].brr_ptr);
|
||||
|
||||
if(voice[v].brr_header_flags() == BRR_END) {
|
||||
status.ENDX |= (1 << v);
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
|
||||
#define S(x) voice[v].brr_data[(voice[v].brr_data_index + (x)) & 3]
|
||||
if(voice[v].env_state != SILENCE) {
|
||||
sample = readb(voice[v].brr_ptr + 1 + (voice[v].brr_index >> 1));
|
||||
if(voice[v].brr_index & 1) {
|
||||
sample = sclip<4>(sample);
|
||||
} else {
|
||||
sample = sclip<4>(sample >> 4);
|
||||
}
|
||||
|
||||
if(voice[v].brr_header_shift() <= 12) {
|
||||
sample = (sample << voice[v].brr_header_shift() >> 1);
|
||||
} else {
|
||||
sample &= ~0x7ff;
|
||||
}
|
||||
|
||||
switch(voice[v].brr_header_filter()) {
|
||||
case 0: //direct
|
||||
break;
|
||||
case 1: //15/16
|
||||
sample += S(-1) + ((-S(-1)) >> 4);
|
||||
break;
|
||||
case 2: //61/32 - 15/16
|
||||
sample += (S(-1) << 1) + ((-((S(-1) << 1) + S(-1))) >> 5)
|
||||
- S(-2) + (S(-2) >> 4);
|
||||
break;
|
||||
case 3: //115/64 - 13/16
|
||||
sample += (S(-1) << 1) + ((-(S(-1) + (S(-1) << 2) + (S(-1) << 3))) >> 6)
|
||||
- S(-2) + (((S(-2) << 1) + S(-2)) >> 4);
|
||||
break;
|
||||
}
|
||||
|
||||
S(0) = sample = sclip<15>(sclamp<16>(sample));
|
||||
} else {
|
||||
S(0) = sample = 0;
|
||||
}
|
||||
|
||||
if(++voice[v].brr_index > 15) {
|
||||
voice[v].brr_index = 0;
|
||||
if(voice[v].brr_header_flags() & BRR_END) {
|
||||
if(voice[v].brr_header_flags() & BRR_LOOP) {
|
||||
status.ENDX |= (1 << v);
|
||||
}
|
||||
voice[v].brr_ptr = readw((status.DIR << 8) + (voice[v].SRCN << 2) + 2);
|
||||
voice[v].brr_looped = true;
|
||||
} else {
|
||||
voice[v].brr_ptr += 9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****
|
||||
* volume envelope adjust
|
||||
*****/
|
||||
voice[v].env_ctr += voice[v].env_rate;
|
||||
|
||||
if(voice[v].env_ctr >= 0x7800) {
|
||||
voice[v].env_ctr -= 0x7800;
|
||||
switch(voice[v].env_mode) {
|
||||
case DIRECT:
|
||||
voice[v].env_rate = 0;
|
||||
break;
|
||||
case LINEAR_DEC:
|
||||
voice[v].envx -= 32;
|
||||
if(voice[v].envx <= 0) {
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
}
|
||||
break;
|
||||
case LINEAR_INC:
|
||||
voice[v].envx += 32;
|
||||
if(voice[v].envx >= 0x7ff) {
|
||||
voice[v].envx = 0x7ff;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
if(voice[v].ADSR_enabled() && voice[v].env_state == ATTACK) {
|
||||
voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY);
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXP_DEC:
|
||||
//multiply by 255/256ths
|
||||
voice[v].envx -= ((voice[v].envx - 1) >> 8) + 1;
|
||||
if(voice[v].ADSR_enabled() && voice[v].env_state == DECAY && voice[v].envx <= voice[v].env_sustain) {
|
||||
voice[v].env_state = SUSTAIN;
|
||||
voice[v].AdjustEnvelope();
|
||||
} else if(voice[v].envx <= 0) {
|
||||
voice[v].envx = 0;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
}
|
||||
break;
|
||||
case BENT_INC:
|
||||
if(voice[v].envx < 0x600) {
|
||||
voice[v].envx += 32;
|
||||
} else {
|
||||
voice[v].envx += 8;
|
||||
|
||||
if(voice[v].envx >= 0x7ff) {
|
||||
voice[v].envx = 0x7ff;
|
||||
voice[v].env_rate = 0;
|
||||
voice[v].env_mode = DIRECT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FAST_ATTACK:
|
||||
voice[v].envx += 0x400;
|
||||
if(voice[v].envx >= 0x7ff) {
|
||||
voice[v].envx = 0x7ff;
|
||||
|
||||
//attack raises to max envx. if sustain is also set to max envx, skip decay phase
|
||||
voice[v].env_state = ((voice[v].env_sustain == 0x800) ? SUSTAIN : DECAY);
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
break;
|
||||
case RELEASE_DEC:
|
||||
voice[v].envx -= 8;
|
||||
if(voice[v].envx <= 0) {
|
||||
voice[v].env_state = SILENCE;
|
||||
voice[v].AdjustEnvelope();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
voice[v].ENVX = voice[v].envx >> 4;
|
||||
|
||||
/*****
|
||||
* gaussian interpolation / noise
|
||||
*****/
|
||||
if(status.NON & (1 << v)) {
|
||||
sample = sclip<15>(status.noise_sample);
|
||||
} else {
|
||||
int32 d = voice[v].pitch_ctr >> 4; //-256 <= sample <= -1
|
||||
sample = ((gaussian_table[ -1 - d] * S(-3)) >> 11);
|
||||
sample += ((gaussian_table[255 - d] * S(-2)) >> 11);
|
||||
sample += ((gaussian_table[512 + d] * S(-1)) >> 11);
|
||||
sample = sclip <15>(sample);
|
||||
sample += ((gaussian_table[256 + d] * S( 0)) >> 11);
|
||||
sample = sclamp<15>(sample);
|
||||
}
|
||||
#undef S
|
||||
|
||||
/*****
|
||||
* envelope / volume adjust
|
||||
*****/
|
||||
sample = (sample * voice[v].envx) >> 11;
|
||||
voice[v].outx = sample << 1;
|
||||
voice[v].OUTX = sample >> 7;
|
||||
|
||||
if(!status.mute()) {
|
||||
msamplel += ((sample * voice[v].VOLL) >> 7) << 1;
|
||||
msampler += ((sample * voice[v].VOLR) >> 7) << 1;
|
||||
}
|
||||
|
||||
if((status.EON & (1 << v)) && status.echo_write()) {
|
||||
esamplel += ((sample * voice[v].VOLL) >> 7) << 1;
|
||||
esampler += ((sample * voice[v].VOLR) >> 7) << 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*****
|
||||
* echo (FIR) adjust
|
||||
*****/
|
||||
#define F(c,x) status.fir_buffer[c][(status.fir_buffer_index + (x)) & 7]
|
||||
status.fir_buffer_index++;
|
||||
F(0,0) = readw((status.esa << 8) + status.echo_index + 0);
|
||||
F(1,0) = readw((status.esa << 8) + status.echo_index + 2);
|
||||
|
||||
fir_samplel = (F(0,-0) * status.FIR[7] +
|
||||
F(0,-1) * status.FIR[6] +
|
||||
F(0,-2) * status.FIR[5] +
|
||||
F(0,-3) * status.FIR[4] +
|
||||
F(0,-4) * status.FIR[3] +
|
||||
F(0,-5) * status.FIR[2] +
|
||||
F(0,-6) * status.FIR[1] +
|
||||
F(0,-7) * status.FIR[0]);
|
||||
|
||||
fir_sampler = (F(1,-0) * status.FIR[7] +
|
||||
F(1,-1) * status.FIR[6] +
|
||||
F(1,-2) * status.FIR[5] +
|
||||
F(1,-3) * status.FIR[4] +
|
||||
F(1,-4) * status.FIR[3] +
|
||||
F(1,-5) * status.FIR[2] +
|
||||
F(1,-6) * status.FIR[1] +
|
||||
F(1,-7) * status.FIR[0]);
|
||||
#undef F
|
||||
|
||||
/*****
|
||||
* update echo buffer
|
||||
*****/
|
||||
if(status.echo_write()) {
|
||||
esamplel += (fir_samplel * status.EFB) >> 14;
|
||||
esampler += (fir_sampler * status.EFB) >> 14;
|
||||
|
||||
esamplel = sclamp<16>(esamplel);
|
||||
esampler = sclamp<16>(esampler);
|
||||
|
||||
writew((status.esa << 8) + status.echo_index + 0, esamplel);
|
||||
writew((status.esa << 8) + status.echo_index + 2, esampler);
|
||||
}
|
||||
|
||||
status.echo_index += 4;
|
||||
if(status.echo_index >= status.echo_length) {
|
||||
status.echo_index = 0;
|
||||
status.echo_length = (status.EDL & 0x0f) << 11;
|
||||
}
|
||||
|
||||
//ESA read occurs at roughly 22/32th sample
|
||||
//ESA fetch occurs at roughly 29/32th sample
|
||||
//as this is not a subsample-level S-DSP emulator,
|
||||
//simulate ~25/32th delay by caching ESA for one
|
||||
//complete sample ...
|
||||
status.esa = status.ESA;
|
||||
|
||||
/*****
|
||||
* main output adjust
|
||||
*****/
|
||||
if(!status.mute()) {
|
||||
msamplel = (msamplel * status.MVOLL) >> 7;
|
||||
msampler = (msampler * status.MVOLR) >> 7;
|
||||
|
||||
msamplel += (fir_samplel * status.EVOLL) >> 14;
|
||||
msampler += (fir_sampler * status.EVOLR) >> 14;
|
||||
|
||||
msamplel = sclamp<16>(msamplel);
|
||||
msampler = sclamp<16>(msampler);
|
||||
}
|
||||
|
||||
audio.sample(msamplel, msampler);
|
||||
step(32 * 3 * 8);
|
||||
synchronize_smp();
|
||||
}
|
||||
|
||||
aDSP::aDSP() {}
|
||||
aDSP::~aDSP() {}
|
||||
|
||||
}
|
|
@ -1,182 +0,0 @@
|
|||
class aDSP : public DSP {
|
||||
private:
|
||||
uint8 dspram[128];
|
||||
uint8 *spcram;
|
||||
|
||||
uint32 dsp_counter;
|
||||
|
||||
enum { BRR_END = 1, BRR_LOOP = 2 };
|
||||
|
||||
uint8 readb (uint16 addr);
|
||||
uint16 readw (uint16 addr);
|
||||
void writeb(uint16 addr, uint8 data);
|
||||
void writew(uint16 addr, uint16 data);
|
||||
|
||||
public:
|
||||
static const uint16 rate_table[32];
|
||||
static const int16 gaussian_table[512];
|
||||
|
||||
enum EnvelopeStates {
|
||||
ATTACK,
|
||||
DECAY,
|
||||
SUSTAIN,
|
||||
RELEASE,
|
||||
SILENCE
|
||||
};
|
||||
|
||||
enum EnvelopeModes {
|
||||
DIRECT,
|
||||
LINEAR_DEC,
|
||||
EXP_DEC,
|
||||
LINEAR_INC,
|
||||
BENT_INC,
|
||||
|
||||
FAST_ATTACK,
|
||||
RELEASE_DEC
|
||||
};
|
||||
|
||||
private:
|
||||
struct Status {
|
||||
//$0c,$1c
|
||||
int8 MVOLL, MVOLR;
|
||||
//$2c,$3c
|
||||
int8 EVOLL, EVOLR;
|
||||
//$4c,$5c
|
||||
uint8 KON, KOFF;
|
||||
//$6c
|
||||
uint8 FLG;
|
||||
//$7c
|
||||
uint8 ENDX;
|
||||
//$0d
|
||||
int8 EFB;
|
||||
//$2d,$3d,$4d
|
||||
uint8 PMON, NON, EON;
|
||||
//$5d
|
||||
uint8 DIR;
|
||||
//$6d,$7d
|
||||
uint8 ESA, EDL;
|
||||
|
||||
//$xf
|
||||
int8 FIR[8];
|
||||
|
||||
//internal variables
|
||||
uint8 kon, esa;
|
||||
|
||||
int16 noise_ctr, noise_rate;
|
||||
uint16 noise_sample;
|
||||
|
||||
uint16 echo_index, echo_length;
|
||||
int16 fir_buffer[2][8];
|
||||
uint8 fir_buffer_index;
|
||||
|
||||
//functions
|
||||
bool soft_reset() { return !!(FLG & 0x80); }
|
||||
bool mute() { return !!(FLG & 0x40); }
|
||||
bool echo_write() { return !(FLG & 0x20); }
|
||||
} status;
|
||||
|
||||
struct Voice {
|
||||
//$x0-$x1
|
||||
int8 VOLL, VOLR;
|
||||
//$x2-$x3
|
||||
int16 PITCH;
|
||||
//$x4
|
||||
uint8 SRCN;
|
||||
//$x5-$x7
|
||||
uint8 ADSR1, ADSR2, GAIN;
|
||||
//$x8-$x9
|
||||
uint8 ENVX, OUTX;
|
||||
|
||||
//internal variables
|
||||
int16 pitch_ctr;
|
||||
|
||||
int8 brr_index;
|
||||
uint16 brr_ptr;
|
||||
uint8 brr_header;
|
||||
bool brr_looped;
|
||||
|
||||
int16 brr_data[4];
|
||||
uint8 brr_data_index;
|
||||
|
||||
int16 envx;
|
||||
uint16 env_ctr, env_rate, env_sustain;
|
||||
uint32 env_state;
|
||||
uint32 env_mode;
|
||||
|
||||
int16 outx;
|
||||
|
||||
//functions
|
||||
int16 pitch_rate() { return PITCH & 0x3fff; }
|
||||
|
||||
uint8 brr_header_shift() { return brr_header >> 4; }
|
||||
uint8 brr_header_filter() { return (brr_header >> 2) & 3; }
|
||||
uint8 brr_header_flags() { return brr_header & 3; }
|
||||
|
||||
bool ADSR_enabled() { return !!(ADSR1 & 0x80); }
|
||||
uint8 ADSR_decay() { return (ADSR1 >> 4) & 7; }
|
||||
uint8 ADSR_attack() { return ADSR1 & 15; }
|
||||
uint8 ADSR_sus_level() { return ADSR2 >> 5; }
|
||||
uint8 ADSR_sus_rate() { return ADSR2 & 31; }
|
||||
|
||||
void AdjustEnvelope() {
|
||||
if(env_state == SILENCE) {
|
||||
env_mode = DIRECT;
|
||||
env_rate = 0;
|
||||
envx = 0;
|
||||
} else if(env_state == RELEASE) {
|
||||
env_mode = RELEASE_DEC;
|
||||
env_rate = 0x7800;
|
||||
} else if(ADSR_enabled()) {
|
||||
switch(env_state) {
|
||||
case ATTACK:
|
||||
env_rate = rate_table[(ADSR_attack() << 1) + 1];
|
||||
env_mode = (env_rate == 0x7800) ? FAST_ATTACK : LINEAR_INC;
|
||||
break;
|
||||
case DECAY:
|
||||
env_rate = rate_table[(ADSR_decay() << 1) + 0x10];
|
||||
env_mode = EXP_DEC;
|
||||
break;
|
||||
case SUSTAIN:
|
||||
env_rate = rate_table[ADSR_sus_rate()];
|
||||
env_mode = (env_rate == 0) ? DIRECT : EXP_DEC;
|
||||
break;
|
||||
}
|
||||
} else if(GAIN & 0x80) {
|
||||
switch(GAIN & 0x60) {
|
||||
case 0x00: env_mode = LINEAR_DEC; break;
|
||||
case 0x20: env_mode = EXP_DEC; break;
|
||||
case 0x40: env_mode = LINEAR_INC; break;
|
||||
case 0x60: env_mode = BENT_INC; break;
|
||||
}
|
||||
env_rate = rate_table[GAIN & 0x1f];
|
||||
} else {
|
||||
env_mode = DIRECT;
|
||||
env_rate = 0;
|
||||
envx = (GAIN & 0x7f) << 4;
|
||||
}
|
||||
}
|
||||
} voice[8];
|
||||
|
||||
public:
|
||||
void enter();
|
||||
void run();
|
||||
|
||||
uint8 read (uint8 addr);
|
||||
void write(uint8 addr, uint8 data);
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
aDSP();
|
||||
~aDSP();
|
||||
|
||||
friend class aDSPDebug;
|
||||
};
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.hpp"
|
||||
extern aDSPDebugger dsp;
|
||||
#else
|
||||
extern aDSP dsp;
|
||||
#endif
|
|
@ -1,3 +0,0 @@
|
|||
#ifdef ADSP_CPP
|
||||
|
||||
#endif
|
|
@ -1,3 +0,0 @@
|
|||
class aDSPDebugger : public aDSP, public DSPDebugger {
|
||||
public:
|
||||
};
|
|
@ -1,71 +0,0 @@
|
|||
#ifdef ADSP_CPP
|
||||
|
||||
void aDSP::serialize(serializer &s) {
|
||||
DSP::serialize(s);
|
||||
|
||||
s.array(dspram);
|
||||
s.integer(dsp_counter);
|
||||
|
||||
s.integer(status.MVOLL);
|
||||
s.integer(status.MVOLR);
|
||||
s.integer(status.EVOLL);
|
||||
s.integer(status.EVOLR);
|
||||
s.integer(status.KON);
|
||||
s.integer(status.KOFF);
|
||||
s.integer(status.FLG);
|
||||
s.integer(status.ENDX);
|
||||
s.integer(status.EFB);
|
||||
s.integer(status.PMON);
|
||||
s.integer(status.NON);
|
||||
s.integer(status.EON);
|
||||
s.integer(status.DIR);
|
||||
s.integer(status.ESA);
|
||||
s.integer(status.EDL);
|
||||
s.array(status.FIR);
|
||||
|
||||
s.integer(status.kon);
|
||||
s.integer(status.esa);
|
||||
|
||||
s.integer(status.noise_ctr);
|
||||
s.integer(status.noise_rate);
|
||||
s.integer(status.noise_sample);
|
||||
|
||||
s.integer(status.echo_index);
|
||||
s.integer(status.echo_length);
|
||||
s.array(status.fir_buffer[0]);
|
||||
s.array(status.fir_buffer[1]);
|
||||
s.integer(status.fir_buffer_index);
|
||||
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
s.integer(voice[i].VOLL);
|
||||
s.integer(voice[i].VOLR);
|
||||
s.integer(voice[i].PITCH);
|
||||
s.integer(voice[i].SRCN);
|
||||
s.integer(voice[i].ADSR1);
|
||||
s.integer(voice[i].ADSR2);
|
||||
s.integer(voice[i].GAIN);
|
||||
s.integer(voice[i].ENVX);
|
||||
s.integer(voice[i].OUTX);
|
||||
|
||||
s.integer(voice[i].pitch_ctr);
|
||||
|
||||
s.integer(voice[i].brr_index);
|
||||
s.integer(voice[i].brr_ptr);
|
||||
s.integer(voice[i].brr_header);
|
||||
s.integer(voice[i].brr_looped);
|
||||
|
||||
s.array(voice[i].brr_data);
|
||||
s.integer(voice[i].brr_data_index);
|
||||
|
||||
s.integer(voice[i].envx);
|
||||
s.integer(voice[i].env_ctr);
|
||||
s.integer(voice[i].env_rate);
|
||||
s.integer(voice[i].env_sustain);
|
||||
s.integer(voice[i].env_state);
|
||||
s.integer(voice[i].env_mode);
|
||||
|
||||
s.integer(voice[i].outx);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,77 +0,0 @@
|
|||
#ifdef ADSP_CPP
|
||||
|
||||
const uint16 aDSP::rate_table[32] = {
|
||||
0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C,
|
||||
0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180,
|
||||
0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00,
|
||||
0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800
|
||||
};
|
||||
|
||||
const int16 aDSP::gaussian_table[512] = {
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001,
|
||||
0x001, 0x001, 0x001, 0x002, 0x002, 0x002, 0x002, 0x002,
|
||||
0x002, 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004,
|
||||
0x004, 0x004, 0x004, 0x004, 0x005, 0x005, 0x005, 0x005,
|
||||
0x006, 0x006, 0x006, 0x006, 0x007, 0x007, 0x007, 0x008,
|
||||
0x008, 0x008, 0x009, 0x009, 0x009, 0x00A, 0x00A, 0x00A,
|
||||
0x00B, 0x00B, 0x00B, 0x00C, 0x00C, 0x00D, 0x00D, 0x00E,
|
||||
0x00E, 0x00F, 0x00F, 0x00F, 0x010, 0x010, 0x011, 0x011,
|
||||
0x012, 0x013, 0x013, 0x014, 0x014, 0x015, 0x015, 0x016,
|
||||
0x017, 0x017, 0x018, 0x018, 0x019, 0x01A, 0x01B, 0x01B,
|
||||
0x01C, 0x01D, 0x01D, 0x01E, 0x01F, 0x020, 0x020, 0x021,
|
||||
0x022, 0x023, 0x024, 0x024, 0x025, 0x026, 0x027, 0x028,
|
||||
0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, 0x030,
|
||||
0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038,
|
||||
0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x040, 0x041, 0x042,
|
||||
0x043, 0x045, 0x046, 0x047, 0x049, 0x04A, 0x04C, 0x04D,
|
||||
0x04E, 0x050, 0x051, 0x053, 0x054, 0x056, 0x057, 0x059,
|
||||
0x05A, 0x05C, 0x05E, 0x05F, 0x061, 0x063, 0x064, 0x066,
|
||||
0x068, 0x06A, 0x06B, 0x06D, 0x06F, 0x071, 0x073, 0x075,
|
||||
0x076, 0x078, 0x07A, 0x07C, 0x07E, 0x080, 0x082, 0x084,
|
||||
0x086, 0x089, 0x08B, 0x08D, 0x08F, 0x091, 0x093, 0x096,
|
||||
0x098, 0x09A, 0x09C, 0x09F, 0x0A1, 0x0A3, 0x0A6, 0x0A8,
|
||||
0x0AB, 0x0AD, 0x0AF, 0x0B2, 0x0B4, 0x0B7, 0x0BA, 0x0BC,
|
||||
0x0BF, 0x0C1, 0x0C4, 0x0C7, 0x0C9, 0x0CC, 0x0CF, 0x0D2,
|
||||
0x0D4, 0x0D7, 0x0DA, 0x0DD, 0x0E0, 0x0E3, 0x0E6, 0x0E9,
|
||||
0x0EC, 0x0EF, 0x0F2, 0x0F5, 0x0F8, 0x0FB, 0x0FE, 0x101,
|
||||
0x104, 0x107, 0x10B, 0x10E, 0x111, 0x114, 0x118, 0x11B,
|
||||
0x11E, 0x122, 0x125, 0x129, 0x12C, 0x130, 0x133, 0x137,
|
||||
0x13A, 0x13E, 0x141, 0x145, 0x148, 0x14C, 0x150, 0x153,
|
||||
0x157, 0x15B, 0x15F, 0x162, 0x166, 0x16A, 0x16E, 0x172,
|
||||
0x176, 0x17A, 0x17D, 0x181, 0x185, 0x189, 0x18D, 0x191,
|
||||
0x195, 0x19A, 0x19E, 0x1A2, 0x1A6, 0x1AA, 0x1AE, 0x1B2,
|
||||
0x1B7, 0x1BB, 0x1BF, 0x1C3, 0x1C8, 0x1CC, 0x1D0, 0x1D5,
|
||||
0x1D9, 0x1DD, 0x1E2, 0x1E6, 0x1EB, 0x1EF, 0x1F3, 0x1F8,
|
||||
0x1FC, 0x201, 0x205, 0x20A, 0x20F, 0x213, 0x218, 0x21C,
|
||||
0x221, 0x226, 0x22A, 0x22F, 0x233, 0x238, 0x23D, 0x241,
|
||||
0x246, 0x24B, 0x250, 0x254, 0x259, 0x25E, 0x263, 0x267,
|
||||
0x26C, 0x271, 0x276, 0x27B, 0x280, 0x284, 0x289, 0x28E,
|
||||
0x293, 0x298, 0x29D, 0x2A2, 0x2A6, 0x2AB, 0x2B0, 0x2B5,
|
||||
0x2BA, 0x2BF, 0x2C4, 0x2C9, 0x2CE, 0x2D3, 0x2D8, 0x2DC,
|
||||
0x2E1, 0x2E6, 0x2EB, 0x2F0, 0x2F5, 0x2FA, 0x2FF, 0x304,
|
||||
0x309, 0x30E, 0x313, 0x318, 0x31D, 0x322, 0x326, 0x32B,
|
||||
0x330, 0x335, 0x33A, 0x33F, 0x344, 0x349, 0x34E, 0x353,
|
||||
0x357, 0x35C, 0x361, 0x366, 0x36B, 0x370, 0x374, 0x379,
|
||||
0x37E, 0x383, 0x388, 0x38C, 0x391, 0x396, 0x39B, 0x39F,
|
||||
0x3A4, 0x3A9, 0x3AD, 0x3B2, 0x3B7, 0x3BB, 0x3C0, 0x3C5,
|
||||
0x3C9, 0x3CE, 0x3D2, 0x3D7, 0x3DC, 0x3E0, 0x3E5, 0x3E9,
|
||||
0x3ED, 0x3F2, 0x3F6, 0x3FB, 0x3FF, 0x403, 0x408, 0x40C,
|
||||
0x410, 0x415, 0x419, 0x41D, 0x421, 0x425, 0x42A, 0x42E,
|
||||
0x432, 0x436, 0x43A, 0x43E, 0x442, 0x446, 0x44A, 0x44E,
|
||||
0x452, 0x455, 0x459, 0x45D, 0x461, 0x465, 0x468, 0x46C,
|
||||
0x470, 0x473, 0x477, 0x47A, 0x47E, 0x481, 0x485, 0x488,
|
||||
0x48C, 0x48F, 0x492, 0x496, 0x499, 0x49C, 0x49F, 0x4A2,
|
||||
0x4A6, 0x4A9, 0x4AC, 0x4AF, 0x4B2, 0x4B5, 0x4B7, 0x4BA,
|
||||
0x4BD, 0x4C0, 0x4C3, 0x4C5, 0x4C8, 0x4CB, 0x4CD, 0x4D0,
|
||||
0x4D2, 0x4D5, 0x4D7, 0x4D9, 0x4DC, 0x4DE, 0x4E0, 0x4E3,
|
||||
0x4E5, 0x4E7, 0x4E9, 0x4EB, 0x4ED, 0x4EF, 0x4F1, 0x4F3,
|
||||
0x4F5, 0x4F6, 0x4F8, 0x4FA, 0x4FB, 0x4FD, 0x4FF, 0x500,
|
||||
0x502, 0x503, 0x504, 0x506, 0x507, 0x508, 0x50A, 0x50B,
|
||||
0x50C, 0x50D, 0x50E, 0x50F, 0x510, 0x511, 0x511, 0x512,
|
||||
0x513, 0x514, 0x514, 0x515, 0x516, 0x516, 0x517, 0x517,
|
||||
0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef SDSP_CPP
|
||||
#ifdef DSP_CPP
|
||||
|
||||
void sDSP::brr_decode(voice_t &v) {
|
||||
void DSP::brr_decode(voice_t &v) {
|
||||
//state.t_brr_byte = ram[v.brr_addr + v.brr_offset] cached from previous clock cycle
|
||||
int nybbles = (state.t_brr_byte << 8) + memory::apuram[(uint16)(v.brr_addr + v.brr_offset + 1)];
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
#ifdef SDSP_CPP
|
||||
#ifdef DSP_CPP
|
||||
|
||||
//counter_rate = number of samples per counter event
|
||||
//all rates are evenly divisible by counter_range (0x7800, 30720, or 2048 * 5 * 3)
|
||||
//note that rate[0] is a special case, which never triggers
|
||||
|
||||
const uint16 sDSP::counter_rate[32] = {
|
||||
const uint16 DSP::counter_rate[32] = {
|
||||
0, 2048, 1536,
|
||||
1280, 1024, 768,
|
||||
640, 512, 384,
|
||||
|
@ -22,7 +22,7 @@ const uint16 sDSP::counter_rate[32] = {
|
|||
//counter_offset = counter offset from zero
|
||||
//counters do not appear to be aligned at zero for all rates
|
||||
|
||||
const uint16 sDSP::counter_offset[32] = {
|
||||
const uint16 DSP::counter_offset[32] = {
|
||||
0, 0, 1040,
|
||||
536, 0, 1040,
|
||||
536, 0, 1040,
|
||||
|
@ -37,14 +37,14 @@ const uint16 sDSP::counter_offset[32] = {
|
|||
0,
|
||||
};
|
||||
|
||||
inline void sDSP::counter_tick() {
|
||||
inline void DSP::counter_tick() {
|
||||
state.counter--;
|
||||
if(state.counter < 0) state.counter = counter_range - 1;
|
||||
}
|
||||
|
||||
//return true if counter event should trigger
|
||||
|
||||
inline bool sDSP::counter_poll(unsigned rate) {
|
||||
inline bool DSP::counter_poll(unsigned rate) {
|
||||
if(rate == 0) return false;
|
||||
return (((unsigned)state.counter + counter_offset[rate]) % counter_rate[rate]) == 0;
|
||||
}
|
|
@ -51,4 +51,33 @@ bool DSPDebugger::property(unsigned id, string &name, string &value) {
|
|||
return false;
|
||||
}
|
||||
|
||||
unsigned DSPDebugger::main_volume_left() { return state.regs[0x0c]; }
|
||||
unsigned DSPDebugger::main_volume_right() { return state.regs[0x1c]; }
|
||||
unsigned DSPDebugger::echo_volume_left() { return state.regs[0x2c]; }
|
||||
unsigned DSPDebugger::echo_volume_right() { return state.regs[0x3c]; }
|
||||
unsigned DSPDebugger::key_on() { return state.regs[0x4c]; }
|
||||
unsigned DSPDebugger::key_off() { return state.regs[0x5c]; }
|
||||
bool DSPDebugger::flag_reset() { return state.regs[0x6c] & 0x80; }
|
||||
bool DSPDebugger::flag_mute() { return state.regs[0x6c] & 0x40; }
|
||||
bool DSPDebugger::flag_echo_disable() { return state.regs[0x6c] & 0x20; }
|
||||
unsigned DSPDebugger::flag_noise_clock() { return state.regs[0x6c] & 0x1f; }
|
||||
unsigned DSPDebugger::source_end_block() { return state.regs[0x7c]; }
|
||||
unsigned DSPDebugger::echo_feedback() { return state.regs[0x0d]; }
|
||||
unsigned DSPDebugger::pitch_modulation_enable() { return state.regs[0x2d]; }
|
||||
unsigned DSPDebugger::noise_enable() { return state.regs[0x3d]; }
|
||||
unsigned DSPDebugger::echo_enable() { return state.regs[0x4d]; }
|
||||
unsigned DSPDebugger::source_directory() { return state.regs[0x5d]; }
|
||||
unsigned DSPDebugger::echo_start_address() { return state.regs[0x6d]; }
|
||||
unsigned DSPDebugger::echo_directory() { return state.regs[0x7d]; }
|
||||
unsigned DSPDebugger::echo_filter_coefficient(unsigned n) { return state.regs[(n << 4) + 0x0f]; }
|
||||
unsigned DSPDebugger::voice_volume_left(unsigned n) { return state.regs[(n << 4) + 0x00]; }
|
||||
unsigned DSPDebugger::voice_volume_right(unsigned n) { return state.regs[(n << 4) + 0x01]; }
|
||||
unsigned DSPDebugger::voice_pitch_height(unsigned n) { return state.regs[(n << 4) + 0x02] + (state.regs[(n << 4) + 0x03] << 8); }
|
||||
unsigned DSPDebugger::voice_source_number(unsigned n) { return state.regs[(n << 4) + 0x04]; }
|
||||
unsigned DSPDebugger::voice_adsr1(unsigned n) { return state.regs[(n << 4) + 0x05]; }
|
||||
unsigned DSPDebugger::voice_adsr2(unsigned n) { return state.regs[(n << 4) + 0x06]; }
|
||||
unsigned DSPDebugger::voice_gain(unsigned n) { return state.regs[(n << 4) + 0x07]; }
|
||||
unsigned DSPDebugger::voice_envx(unsigned n) { return state.regs[(n << 4) + 0x08]; }
|
||||
unsigned DSPDebugger::voice_outx(unsigned n) { return state.regs[(n << 4) + 0x09]; }
|
||||
|
||||
#endif
|
|
@ -1,5 +1,7 @@
|
|||
class sDSPDebugger : public sDSP, public DSPDebugger {
|
||||
class DSPDebugger : public DSP, public ChipDebugger {
|
||||
public:
|
||||
bool property(unsigned id, string &name, string &value);
|
||||
|
||||
//===========
|
||||
//DSPDebugger
|
||||
//===========
|
|
@ -1,32 +0,0 @@
|
|||
struct DSPDebugger : ChipDebugger {
|
||||
bool property(unsigned id, string &name, string &value);
|
||||
|
||||
virtual unsigned main_volume_left() { return 0; }
|
||||
virtual unsigned main_volume_right() { return 0; }
|
||||
virtual unsigned echo_volume_left() { return 0; }
|
||||
virtual unsigned echo_volume_right() { return 0; }
|
||||
virtual unsigned key_on() { return 0; }
|
||||
virtual unsigned key_off() { return 0; }
|
||||
virtual bool flag_reset() { return 0; }
|
||||
virtual bool flag_mute() { return 0; }
|
||||
virtual bool flag_echo_disable() { return 0; }
|
||||
virtual unsigned flag_noise_clock() { return 0; }
|
||||
virtual unsigned source_end_block() { return 0; }
|
||||
virtual unsigned echo_feedback() { return 0; }
|
||||
virtual unsigned pitch_modulation_enable() { return 0; }
|
||||
virtual unsigned noise_enable() { return 0; }
|
||||
virtual unsigned echo_enable() { return 0; }
|
||||
virtual unsigned source_directory() { return 0; }
|
||||
virtual unsigned echo_start_address() { return 0; }
|
||||
virtual unsigned echo_directory() { return 0; }
|
||||
virtual unsigned echo_filter_coefficient(unsigned) { return 0; }
|
||||
virtual unsigned voice_volume_left(unsigned) { return 0; }
|
||||
virtual unsigned voice_volume_right(unsigned) { return 0; }
|
||||
virtual unsigned voice_pitch_height(unsigned) { return 0; }
|
||||
virtual unsigned voice_source_number(unsigned) { return 0; }
|
||||
virtual unsigned voice_adsr1(unsigned) { return 0; }
|
||||
virtual unsigned voice_adsr2(unsigned) { return 0; }
|
||||
virtual unsigned voice_gain(unsigned) { return 0; }
|
||||
virtual unsigned voice_envx(unsigned) { return 0; }
|
||||
virtual unsigned voice_outx(unsigned) { return 0; }
|
||||
};
|
|
@ -1,24 +1,350 @@
|
|||
//S-DSP emulator
|
||||
//note: this is basically a C++ cothreaded implementation of Shay Green's (blargg's) S-DSP emulator.
|
||||
//the actual algorithms, timing information, tables, variable names, etc were all from him.
|
||||
|
||||
#include <snes.hpp>
|
||||
|
||||
#define DSP_CPP
|
||||
namespace SNES {
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#include "dsp-debugger.cpp"
|
||||
#include "debugger/debugger.cpp"
|
||||
DSPDebugger dsp;
|
||||
#else
|
||||
DSP dsp;
|
||||
#endif
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
#define REG(n) state.regs[r_##n]
|
||||
#define VREG(n) state.regs[v.vidx + v_##n]
|
||||
|
||||
#if !defined(DSP_STATE_MACHINE)
|
||||
#define phase_start() while(true) { \
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) { \
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); \
|
||||
}
|
||||
#define phase(n)
|
||||
#define tick() step(3 * 8); synchronize_smp()
|
||||
#define phase_end() }
|
||||
#else
|
||||
#define phase_start() switch(phase_index) {
|
||||
#define phase(n) case n:
|
||||
#define tick() step(3 * 8); break
|
||||
#define phase_end() } phase_index = (phase_index + 1) & 31;
|
||||
#endif
|
||||
|
||||
#include "gaussian.cpp"
|
||||
#include "counter.cpp"
|
||||
#include "envelope.cpp"
|
||||
#include "brr.cpp"
|
||||
#include "misc.cpp"
|
||||
#include "voice.cpp"
|
||||
#include "echo.cpp"
|
||||
|
||||
/* timing */
|
||||
|
||||
void DSP::step(unsigned clocks) {
|
||||
clock += clocks;
|
||||
}
|
||||
|
||||
void DSP::synchronize_smp() {
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(smp.thread);
|
||||
}
|
||||
|
||||
void DSP::Enter() { dsp.enter(); }
|
||||
|
||||
void DSP::enter() {
|
||||
phase_start()
|
||||
|
||||
phase(0)
|
||||
voice_5(voice[0]);
|
||||
voice_2(voice[1]);
|
||||
tick();
|
||||
|
||||
phase(1)
|
||||
voice_6(voice[0]);
|
||||
voice_3(voice[1]);
|
||||
tick();
|
||||
|
||||
phase(2)
|
||||
voice_7(voice[0]);
|
||||
voice_4(voice[1]);
|
||||
voice_1(voice[3]);
|
||||
tick();
|
||||
|
||||
phase(3)
|
||||
voice_8(voice[0]);
|
||||
voice_5(voice[1]);
|
||||
voice_2(voice[2]);
|
||||
tick();
|
||||
|
||||
phase(4)
|
||||
voice_9(voice[0]);
|
||||
voice_6(voice[1]);
|
||||
voice_3(voice[2]);
|
||||
tick();
|
||||
|
||||
phase(5)
|
||||
voice_7(voice[1]);
|
||||
voice_4(voice[2]);
|
||||
voice_1(voice[4]);
|
||||
tick();
|
||||
|
||||
phase(6)
|
||||
voice_8(voice[1]);
|
||||
voice_5(voice[2]);
|
||||
voice_2(voice[3]);
|
||||
tick();
|
||||
|
||||
phase(7)
|
||||
voice_9(voice[1]);
|
||||
voice_6(voice[2]);
|
||||
voice_3(voice[3]);
|
||||
tick();
|
||||
|
||||
phase(8)
|
||||
voice_7(voice[2]);
|
||||
voice_4(voice[3]);
|
||||
voice_1(voice[5]);
|
||||
tick();
|
||||
|
||||
phase(9)
|
||||
voice_8(voice[2]);
|
||||
voice_5(voice[3]);
|
||||
voice_2(voice[4]);
|
||||
tick();
|
||||
|
||||
phase(10)
|
||||
voice_9(voice[2]);
|
||||
voice_6(voice[3]);
|
||||
voice_3(voice[4]);
|
||||
tick();
|
||||
|
||||
phase(11)
|
||||
voice_7(voice[3]);
|
||||
voice_4(voice[4]);
|
||||
voice_1(voice[6]);
|
||||
tick();
|
||||
|
||||
phase(12)
|
||||
voice_8(voice[3]);
|
||||
voice_5(voice[4]);
|
||||
voice_2(voice[5]);
|
||||
tick();
|
||||
|
||||
phase(13)
|
||||
voice_9(voice[3]);
|
||||
voice_6(voice[4]);
|
||||
voice_3(voice[5]);
|
||||
tick();
|
||||
|
||||
phase(14)
|
||||
voice_7(voice[4]);
|
||||
voice_4(voice[5]);
|
||||
voice_1(voice[7]);
|
||||
tick();
|
||||
|
||||
phase(15)
|
||||
voice_8(voice[4]);
|
||||
voice_5(voice[5]);
|
||||
voice_2(voice[6]);
|
||||
tick();
|
||||
|
||||
phase(16)
|
||||
voice_9(voice[4]);
|
||||
voice_6(voice[5]);
|
||||
voice_3(voice[6]);
|
||||
tick();
|
||||
|
||||
phase(17)
|
||||
voice_1(voice[0]);
|
||||
voice_7(voice[5]);
|
||||
voice_4(voice[6]);
|
||||
tick();
|
||||
|
||||
phase(18)
|
||||
voice_8(voice[5]);
|
||||
voice_5(voice[6]);
|
||||
voice_2(voice[7]);
|
||||
tick();
|
||||
|
||||
phase(19)
|
||||
voice_9(voice[5]);
|
||||
voice_6(voice[6]);
|
||||
voice_3(voice[7]);
|
||||
tick();
|
||||
|
||||
phase(20)
|
||||
voice_1(voice[1]);
|
||||
voice_7(voice[6]);
|
||||
voice_4(voice[7]);
|
||||
tick();
|
||||
|
||||
phase(21)
|
||||
voice_8(voice[6]);
|
||||
voice_5(voice[7]);
|
||||
voice_2(voice[0]);
|
||||
tick();
|
||||
|
||||
phase(22)
|
||||
voice_3a(voice[0]);
|
||||
voice_9(voice[6]);
|
||||
voice_6(voice[7]);
|
||||
echo_22();
|
||||
tick();
|
||||
|
||||
phase(23)
|
||||
voice_7(voice[7]);
|
||||
echo_23();
|
||||
tick();
|
||||
|
||||
phase(24)
|
||||
voice_8(voice[7]);
|
||||
echo_24();
|
||||
tick();
|
||||
|
||||
phase(25)
|
||||
voice_3b(voice[0]);
|
||||
voice_9(voice[7]);
|
||||
echo_25();
|
||||
tick();
|
||||
|
||||
phase(26)
|
||||
echo_26();
|
||||
tick();
|
||||
|
||||
phase(27)
|
||||
misc_27();
|
||||
echo_27();
|
||||
tick();
|
||||
|
||||
phase(28)
|
||||
misc_28();
|
||||
echo_28();
|
||||
tick();
|
||||
|
||||
phase(29)
|
||||
misc_29();
|
||||
echo_29();
|
||||
tick();
|
||||
|
||||
phase(30)
|
||||
misc_30();
|
||||
voice_3c(voice[0]);
|
||||
echo_30();
|
||||
tick();
|
||||
|
||||
phase(31)
|
||||
voice_4(voice[0]);
|
||||
voice_1(voice[2]);
|
||||
tick();
|
||||
|
||||
phase_end()
|
||||
}
|
||||
|
||||
/* register interface for S-SMP $00f2,$00f3 */
|
||||
|
||||
uint8 DSP::read(uint8 addr) {
|
||||
return state.regs[addr];
|
||||
}
|
||||
|
||||
void DSP::write(uint8 addr, uint8 data) {
|
||||
state.regs[addr] = data;
|
||||
|
||||
if((addr & 0x0f) == v_envx) {
|
||||
state.envx_buf = data;
|
||||
} else if((addr & 0x0f) == v_outx) {
|
||||
state.outx_buf = data;
|
||||
} else if(addr == r_kon) {
|
||||
state.new_kon = data;
|
||||
} else if(addr == r_endx) {
|
||||
//always cleared, regardless of data written
|
||||
state.endx_buf = 0;
|
||||
state.regs[r_endx] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* initialization */
|
||||
|
||||
void DSP::power() {
|
||||
create(DSP::Enter, system.apu_frequency());
|
||||
memset(&state.regs, 0, sizeof state.regs);
|
||||
state.echo_hist_pos = 0;
|
||||
state.every_other_sample = false;
|
||||
state.kon = 0;
|
||||
state.noise = 0;
|
||||
state.counter = 0;
|
||||
state.echo_offset = 0;
|
||||
state.echo_length = 0;
|
||||
state.new_kon = 0;
|
||||
state.endx_buf = 0;
|
||||
state.envx_buf = 0;
|
||||
state.outx_buf = 0;
|
||||
state.t_pmon = 0;
|
||||
state.t_non = 0;
|
||||
state.t_eon = 0;
|
||||
state.t_dir = 0;
|
||||
state.t_koff = 0;
|
||||
state.t_brr_next_addr = 0;
|
||||
state.t_adsr0 = 0;
|
||||
state.t_brr_header = 0;
|
||||
state.t_brr_byte = 0;
|
||||
state.t_srcn = 0;
|
||||
state.t_esa = 0;
|
||||
state.t_echo_disabled = 0;
|
||||
state.t_dir_addr = 0;
|
||||
state.t_pitch = 0;
|
||||
state.t_output = 0;
|
||||
state.t_looped = 0;
|
||||
state.t_echo_ptr = 0;
|
||||
state.t_main_out[0] = state.t_main_out[1] = 0;
|
||||
state.t_echo_out[0] = state.t_echo_out[1] = 0;
|
||||
state.t_echo_in[0] = state.t_echo_in[1] = 0;
|
||||
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
voice[i].buf_pos = 0;
|
||||
voice[i].interp_pos = 0;
|
||||
voice[i].brr_addr = 0;
|
||||
voice[i].brr_offset = 1;
|
||||
voice[i].vbit = 1 << i;
|
||||
voice[i].vidx = i * 0x10;
|
||||
voice[i].kon_delay = 0;
|
||||
voice[i].env_mode = env_release;
|
||||
voice[i].env = 0;
|
||||
voice[i].t_envx_out = 0;
|
||||
voice[i].hidden_env = 0;
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void DSP::reset() {
|
||||
create(DSP::Enter, system.apu_frequency());
|
||||
create(Enter, system.apu_frequency());
|
||||
|
||||
REG(flg) = 0xe0;
|
||||
|
||||
state.noise = 0x4000;
|
||||
state.echo_hist_pos = 0;
|
||||
state.every_other_sample = 1;
|
||||
state.echo_offset = 0;
|
||||
state.counter = 0;
|
||||
|
||||
phase_index = 0;
|
||||
}
|
||||
|
||||
void DSP::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
DSP::DSP() {
|
||||
static_assert(sizeof(int) >= 32 / 8, "int >= 32-bits");
|
||||
static_assert((int8)0x80 == -0x80, "8-bit sign extension");
|
||||
static_assert((int16)0x8000 == -0x8000, "16-bit sign extension");
|
||||
static_assert((uint16)0xffff0000 == 0, "16-bit unsigned clip");
|
||||
static_assert((-1 >> 1) == -1, "arithmetic shift right");
|
||||
|
||||
//-0x8000 <= n <= +0x7fff
|
||||
assert(sclamp<16>(+0x8000) == +0x7fff);
|
||||
assert(sclamp<16>(-0x8001) == -0x8000);
|
||||
}
|
||||
|
||||
DSP::~DSP() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
#if defined(DEBUGGER)
|
||||
#include "dsp-debugger.hpp"
|
||||
#endif
|
||||
|
||||
class DSP : public Processor {
|
||||
public:
|
||||
//synchronization
|
||||
|
@ -9,13 +5,177 @@ public:
|
|||
alwaysinline void synchronize_smp();
|
||||
|
||||
static void Enter();
|
||||
virtual void enter() = 0;
|
||||
void enter();
|
||||
|
||||
virtual uint8 read(uint8 addr) = 0;
|
||||
virtual void write(uint8 addr, uint8 data) = 0;
|
||||
uint8 read(uint8 addr);
|
||||
void write(uint8 addr, uint8 data);
|
||||
|
||||
virtual void power();
|
||||
virtual void reset();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
virtual void serialize(serializer&);
|
||||
void serialize(serializer&);
|
||||
DSP();
|
||||
~DSP();
|
||||
|
||||
protected:
|
||||
//DSP_STATE_MACHINE variable
|
||||
unsigned phase_index;
|
||||
|
||||
//global registers
|
||||
enum global_reg_t {
|
||||
r_mvoll = 0x0c, r_mvolr = 0x1c,
|
||||
r_evoll = 0x2c, r_evolr = 0x3c,
|
||||
r_kon = 0x4c, r_koff = 0x5c,
|
||||
r_flg = 0x6c, r_endx = 0x7c,
|
||||
r_efb = 0x0d, r_pmon = 0x2d,
|
||||
r_non = 0x3d, r_eon = 0x4d,
|
||||
r_dir = 0x5d, r_esa = 0x6d,
|
||||
r_edl = 0x7d, r_fir = 0x0f, //8 coefficients at 0x0f, 0x1f, ... 0x7f
|
||||
};
|
||||
|
||||
//voice registers
|
||||
enum voice_reg_t {
|
||||
v_voll = 0x00, v_volr = 0x01,
|
||||
v_pitchl = 0x02, v_pitchh = 0x03,
|
||||
v_srcn = 0x04, v_adsr0 = 0x05,
|
||||
v_adsr1 = 0x06, v_gain = 0x07,
|
||||
v_envx = 0x08, v_outx = 0x09,
|
||||
};
|
||||
|
||||
//internal envelope modes
|
||||
enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
|
||||
|
||||
//internal constants
|
||||
enum { echo_hist_size = 8 };
|
||||
enum { brr_buf_size = 12 };
|
||||
enum { brr_block_size = 9 };
|
||||
|
||||
//global state
|
||||
struct state_t {
|
||||
uint8 regs[128];
|
||||
|
||||
modulo_array<int, echo_hist_size> echo_hist[2]; //echo history keeps most recent 8 samples
|
||||
int echo_hist_pos;
|
||||
|
||||
bool every_other_sample; //toggles every sample
|
||||
int kon; //KON value when last checked
|
||||
int noise;
|
||||
int counter;
|
||||
int echo_offset; //offset from ESA in echo buffer
|
||||
int echo_length; //number of bytes that echo_offset will stop at
|
||||
|
||||
//hidden registers also written to when main register is written to
|
||||
int new_kon;
|
||||
int endx_buf;
|
||||
int envx_buf;
|
||||
int outx_buf;
|
||||
|
||||
//temporary state between clocks
|
||||
|
||||
//read once per sample
|
||||
int t_pmon;
|
||||
int t_non;
|
||||
int t_eon;
|
||||
int t_dir;
|
||||
int t_koff;
|
||||
|
||||
//read a few clocks ahead before used
|
||||
int t_brr_next_addr;
|
||||
int t_adsr0;
|
||||
int t_brr_header;
|
||||
int t_brr_byte;
|
||||
int t_srcn;
|
||||
int t_esa;
|
||||
int t_echo_disabled;
|
||||
|
||||
//internal state that is recalculated every sample
|
||||
int t_dir_addr;
|
||||
int t_pitch;
|
||||
int t_output;
|
||||
int t_looped;
|
||||
int t_echo_ptr;
|
||||
|
||||
//left/right sums
|
||||
int t_main_out[2];
|
||||
int t_echo_out[2];
|
||||
int t_echo_in [2];
|
||||
} state;
|
||||
|
||||
//voice state
|
||||
struct voice_t {
|
||||
modulo_array<int, brr_buf_size> buffer; //decoded samples
|
||||
int buf_pos; //place in buffer where next samples will be decoded
|
||||
int interp_pos; //relative fractional position in sample (0x1000 = 1.0)
|
||||
int brr_addr; //address of current BRR block
|
||||
int brr_offset; //current decoding offset in BRR block
|
||||
int vbit; //bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc
|
||||
int vidx; //voice channel register index: 0x00 for voice 0, 0x10 for voice 1, etc
|
||||
int kon_delay; //KON delay/current setup phase
|
||||
int env_mode;
|
||||
int env; //current envelope level
|
||||
int t_envx_out;
|
||||
int hidden_env; //used by GAIN mode 7, very obscure quirk
|
||||
} voice[8];
|
||||
|
||||
//gaussian
|
||||
static const int16 gaussian_table[512];
|
||||
int gaussian_interpolate(const voice_t &v);
|
||||
|
||||
//counter
|
||||
enum { counter_range = 2048 * 5 * 3 }; //30720 (0x7800)
|
||||
static const uint16 counter_rate[32];
|
||||
static const uint16 counter_offset[32];
|
||||
void counter_tick();
|
||||
bool counter_poll(unsigned rate);
|
||||
|
||||
//envelope
|
||||
void envelope_run(voice_t &v);
|
||||
|
||||
//brr
|
||||
void brr_decode(voice_t &v);
|
||||
|
||||
//misc
|
||||
void misc_27();
|
||||
void misc_28();
|
||||
void misc_29();
|
||||
void misc_30();
|
||||
|
||||
//voice
|
||||
void voice_output(voice_t &v, bool channel);
|
||||
void voice_1 (voice_t &v);
|
||||
void voice_2 (voice_t &v);
|
||||
void voice_3 (voice_t &v);
|
||||
void voice_3a(voice_t &v);
|
||||
void voice_3b(voice_t &v);
|
||||
void voice_3c(voice_t &v);
|
||||
void voice_4 (voice_t &v);
|
||||
void voice_5 (voice_t &v);
|
||||
void voice_6 (voice_t &v);
|
||||
void voice_7 (voice_t &v);
|
||||
void voice_8 (voice_t &v);
|
||||
void voice_9 (voice_t &v);
|
||||
|
||||
//echo
|
||||
int calc_fir(int i, bool channel);
|
||||
int echo_output(bool channel);
|
||||
void echo_read(bool channel);
|
||||
void echo_write(bool channel);
|
||||
void echo_22();
|
||||
void echo_23();
|
||||
void echo_24();
|
||||
void echo_25();
|
||||
void echo_26();
|
||||
void echo_27();
|
||||
void echo_28();
|
||||
void echo_29();
|
||||
void echo_30();
|
||||
|
||||
friend class DSPDebugger;
|
||||
};
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.hpp"
|
||||
extern DSPDebugger dsp;
|
||||
#else
|
||||
extern DSP dsp;
|
||||
#endif
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
#ifdef SDSP_CPP
|
||||
#ifdef DSP_CPP
|
||||
|
||||
int sDSP::calc_fir(int i, bool channel) {
|
||||
int DSP::calc_fir(int i, bool channel) {
|
||||
int s = state.echo_hist[channel][state.echo_hist_pos + i + 1];
|
||||
return (s * (int8)REG(fir + i * 0x10)) >> 6;
|
||||
}
|
||||
|
||||
int sDSP::echo_output(bool channel) {
|
||||
int DSP::echo_output(bool channel) {
|
||||
int output = (int16)((state.t_main_out[channel] * (int8)REG(mvoll + channel * 0x10)) >> 7)
|
||||
+ (int16)((state.t_echo_in [channel] * (int8)REG(evoll + channel * 0x10)) >> 7);
|
||||
return sclamp<16>(output);
|
||||
}
|
||||
|
||||
void sDSP::echo_read(bool channel) {
|
||||
void DSP::echo_read(bool channel) {
|
||||
unsigned addr = state.t_echo_ptr + channel * 2;
|
||||
uint8 lo = memory::apuram[(uint16)(addr + 0)];
|
||||
uint8 hi = memory::apuram[(uint16)(addr + 1)];
|
||||
|
@ -19,7 +19,7 @@ void sDSP::echo_read(bool channel) {
|
|||
state.echo_hist[channel].write(state.echo_hist_pos, s >> 1);
|
||||
}
|
||||
|
||||
void sDSP::echo_write(bool channel) {
|
||||
void DSP::echo_write(bool channel) {
|
||||
if(!(state.t_echo_disabled & 0x20)) {
|
||||
unsigned addr = state.t_echo_ptr + channel * 2;
|
||||
int s = state.t_echo_out[channel];
|
||||
|
@ -30,7 +30,7 @@ void sDSP::echo_write(bool channel) {
|
|||
state.t_echo_out[channel] = 0;
|
||||
}
|
||||
|
||||
void sDSP::echo_22() {
|
||||
void DSP::echo_22() {
|
||||
//history
|
||||
state.echo_hist_pos++;
|
||||
if(state.echo_hist_pos >= echo_hist_size) state.echo_hist_pos = 0;
|
||||
|
@ -46,7 +46,7 @@ void sDSP::echo_22() {
|
|||
state.t_echo_in[1] = r;
|
||||
}
|
||||
|
||||
void sDSP::echo_23() {
|
||||
void DSP::echo_23() {
|
||||
int l = calc_fir(1, 0) + calc_fir(2, 0);
|
||||
int r = calc_fir(1, 1) + calc_fir(2, 1);
|
||||
|
||||
|
@ -56,7 +56,7 @@ void sDSP::echo_23() {
|
|||
echo_read(1);
|
||||
}
|
||||
|
||||
void sDSP::echo_24() {
|
||||
void DSP::echo_24() {
|
||||
int l = calc_fir(3, 0) + calc_fir(4, 0) + calc_fir(5, 0);
|
||||
int r = calc_fir(3, 1) + calc_fir(4, 1) + calc_fir(5, 1);
|
||||
|
||||
|
@ -64,7 +64,7 @@ void sDSP::echo_24() {
|
|||
state.t_echo_in[1] += r;
|
||||
}
|
||||
|
||||
void sDSP::echo_25() {
|
||||
void DSP::echo_25() {
|
||||
int l = state.t_echo_in[0] + calc_fir(6, 0);
|
||||
int r = state.t_echo_in[1] + calc_fir(6, 1);
|
||||
|
||||
|
@ -78,7 +78,7 @@ void sDSP::echo_25() {
|
|||
state.t_echo_in[1] = sclamp<16>(r) & ~1;
|
||||
}
|
||||
|
||||
void sDSP::echo_26() {
|
||||
void DSP::echo_26() {
|
||||
//left output volumes
|
||||
//(save sample for next clock so we can output both together)
|
||||
state.t_main_out[0] = echo_output(0);
|
||||
|
@ -91,7 +91,7 @@ void sDSP::echo_26() {
|
|||
state.t_echo_out[1] = sclamp<16>(r) & ~1;
|
||||
}
|
||||
|
||||
void sDSP::echo_27() {
|
||||
void DSP::echo_27() {
|
||||
//output
|
||||
int outl = state.t_main_out[0];
|
||||
int outr = echo_output(1);
|
||||
|
@ -109,11 +109,11 @@ void sDSP::echo_27() {
|
|||
audio.sample(outl, outr);
|
||||
}
|
||||
|
||||
void sDSP::echo_28() {
|
||||
void DSP::echo_28() {
|
||||
state.t_echo_disabled = REG(flg);
|
||||
}
|
||||
|
||||
void sDSP::echo_29() {
|
||||
void DSP::echo_29() {
|
||||
state.t_esa = REG(esa);
|
||||
|
||||
if(!state.echo_offset) state.echo_length = (REG(edl) & 0x0f) << 11;
|
||||
|
@ -127,7 +127,7 @@ void sDSP::echo_29() {
|
|||
state.t_echo_disabled = REG(flg);
|
||||
}
|
||||
|
||||
void sDSP::echo_30() {
|
||||
void DSP::echo_30() {
|
||||
//write right echo
|
||||
echo_write(1);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef SDSP_CPP
|
||||
#ifdef DSP_CPP
|
||||
|
||||
void sDSP::envelope_run(voice_t &v) {
|
||||
void DSP::envelope_run(voice_t &v) {
|
||||
int env = v.env;
|
||||
|
||||
if(v.env_mode == env_release) { //60%
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef SDSP_CPP
|
||||
#ifdef DSP_CPP
|
||||
|
||||
const int16 sDSP::gaussian_table[512] = {
|
||||
const int16 DSP::gaussian_table[512] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
|
||||
2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5,
|
||||
|
@ -35,7 +35,7 @@ const int16 sDSP::gaussian_table[512] = {
|
|||
1299, 1300, 1300, 1301, 1302, 1302, 1303, 1303, 1303, 1304, 1304, 1304, 1304, 1304, 1305, 1305,
|
||||
};
|
||||
|
||||
int sDSP::gaussian_interpolate(const voice_t &v) {
|
||||
int DSP::gaussian_interpolate(const voice_t &v) {
|
||||
//make pointers into gaussian table based on fractional position between samples
|
||||
int offset = (v.interp_pos >> 4) & 0xff;
|
||||
const int16 *fwd = gaussian_table + 255 - offset;
|
|
@ -1,23 +1,23 @@
|
|||
#ifdef SDSP_CPP
|
||||
#ifdef DSP_CPP
|
||||
|
||||
void sDSP::misc_27() {
|
||||
void DSP::misc_27() {
|
||||
state.t_pmon = REG(pmon) & ~1; //voice 0 doesn't support PMON
|
||||
}
|
||||
|
||||
void sDSP::misc_28() {
|
||||
void DSP::misc_28() {
|
||||
state.t_non = REG(non);
|
||||
state.t_eon = REG(eon);
|
||||
state.t_dir = REG(dir);
|
||||
}
|
||||
|
||||
void sDSP::misc_29() {
|
||||
void DSP::misc_29() {
|
||||
state.every_other_sample ^= 1;
|
||||
if(state.every_other_sample) {
|
||||
state.new_kon &= ~state.kon; //clears KON 63 clocks after it was last read
|
||||
}
|
||||
}
|
||||
|
||||
void sDSP::misc_30() {
|
||||
void DSP::misc_30() {
|
||||
if(state.every_other_sample) {
|
||||
state.kon = state.new_kon;
|
||||
state.t_koff = REG(koff);
|
|
@ -1,36 +0,0 @@
|
|||
#ifdef SDSP_CPP
|
||||
|
||||
//===========
|
||||
//DSPDebugger
|
||||
//===========
|
||||
|
||||
unsigned sDSPDebugger::main_volume_left() { return state.regs[0x0c]; }
|
||||
unsigned sDSPDebugger::main_volume_right() { return state.regs[0x1c]; }
|
||||
unsigned sDSPDebugger::echo_volume_left() { return state.regs[0x2c]; }
|
||||
unsigned sDSPDebugger::echo_volume_right() { return state.regs[0x3c]; }
|
||||
unsigned sDSPDebugger::key_on() { return state.regs[0x4c]; }
|
||||
unsigned sDSPDebugger::key_off() { return state.regs[0x5c]; }
|
||||
bool sDSPDebugger::flag_reset() { return state.regs[0x6c] & 0x80; }
|
||||
bool sDSPDebugger::flag_mute() { return state.regs[0x6c] & 0x40; }
|
||||
bool sDSPDebugger::flag_echo_disable() { return state.regs[0x6c] & 0x20; }
|
||||
unsigned sDSPDebugger::flag_noise_clock() { return state.regs[0x6c] & 0x1f; }
|
||||
unsigned sDSPDebugger::source_end_block() { return state.regs[0x7c]; }
|
||||
unsigned sDSPDebugger::echo_feedback() { return state.regs[0x0d]; }
|
||||
unsigned sDSPDebugger::pitch_modulation_enable() { return state.regs[0x2d]; }
|
||||
unsigned sDSPDebugger::noise_enable() { return state.regs[0x3d]; }
|
||||
unsigned sDSPDebugger::echo_enable() { return state.regs[0x4d]; }
|
||||
unsigned sDSPDebugger::source_directory() { return state.regs[0x5d]; }
|
||||
unsigned sDSPDebugger::echo_start_address() { return state.regs[0x6d]; }
|
||||
unsigned sDSPDebugger::echo_directory() { return state.regs[0x7d]; }
|
||||
unsigned sDSPDebugger::echo_filter_coefficient(unsigned n) { return state.regs[(n << 4) + 0x0f]; }
|
||||
unsigned sDSPDebugger::voice_volume_left(unsigned n) { return state.regs[(n << 4) + 0x00]; }
|
||||
unsigned sDSPDebugger::voice_volume_right(unsigned n) { return state.regs[(n << 4) + 0x01]; }
|
||||
unsigned sDSPDebugger::voice_pitch_height(unsigned n) { return state.regs[(n << 4) + 0x02] + (state.regs[(n << 4) + 0x03] << 8); }
|
||||
unsigned sDSPDebugger::voice_source_number(unsigned n) { return state.regs[(n << 4) + 0x04]; }
|
||||
unsigned sDSPDebugger::voice_adsr1(unsigned n) { return state.regs[(n << 4) + 0x05]; }
|
||||
unsigned sDSPDebugger::voice_adsr2(unsigned n) { return state.regs[(n << 4) + 0x06]; }
|
||||
unsigned sDSPDebugger::voice_gain(unsigned n) { return state.regs[(n << 4) + 0x07]; }
|
||||
unsigned sDSPDebugger::voice_envx(unsigned n) { return state.regs[(n << 4) + 0x08]; }
|
||||
unsigned sDSPDebugger::voice_outx(unsigned n) { return state.regs[(n << 4) + 0x09]; }
|
||||
|
||||
#endif
|
|
@ -1,342 +0,0 @@
|
|||
//S-DSP emulator
|
||||
//note: this is basically a C++ cothreaded implementation of Shay Green's (blargg's) S-DSP emulator.
|
||||
//the actual algorithms, timing information, tables, variable names, etc were all from him.
|
||||
|
||||
#include <snes.hpp>
|
||||
|
||||
#define SDSP_CPP
|
||||
namespace SNES {
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.cpp"
|
||||
sDSPDebugger dsp;
|
||||
#else
|
||||
sDSP dsp;
|
||||
#endif
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
#define REG(n) state.regs[r_##n]
|
||||
#define VREG(n) state.regs[v.vidx + v_##n]
|
||||
|
||||
#if !defined(DSP_STATE_MACHINE)
|
||||
#define phase_start() while(true) { \
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) { \
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); \
|
||||
}
|
||||
#define phase(n)
|
||||
#define tick() step(3 * 8); synchronize_smp()
|
||||
#define phase_end() }
|
||||
#else
|
||||
#define phase_start() switch(phase_index) {
|
||||
#define phase(n) case n:
|
||||
#define tick() step(3 * 8); break
|
||||
#define phase_end() } phase_index = (phase_index + 1) & 31;
|
||||
#endif
|
||||
|
||||
#include "gaussian.cpp"
|
||||
#include "counter.cpp"
|
||||
#include "envelope.cpp"
|
||||
#include "brr.cpp"
|
||||
#include "misc.cpp"
|
||||
#include "voice.cpp"
|
||||
#include "echo.cpp"
|
||||
|
||||
/* timing */
|
||||
|
||||
void sDSP::enter() {
|
||||
phase_start()
|
||||
|
||||
phase(0)
|
||||
voice_5(voice[0]);
|
||||
voice_2(voice[1]);
|
||||
tick();
|
||||
|
||||
phase(1)
|
||||
voice_6(voice[0]);
|
||||
voice_3(voice[1]);
|
||||
tick();
|
||||
|
||||
phase(2)
|
||||
voice_7(voice[0]);
|
||||
voice_4(voice[1]);
|
||||
voice_1(voice[3]);
|
||||
tick();
|
||||
|
||||
phase(3)
|
||||
voice_8(voice[0]);
|
||||
voice_5(voice[1]);
|
||||
voice_2(voice[2]);
|
||||
tick();
|
||||
|
||||
phase(4)
|
||||
voice_9(voice[0]);
|
||||
voice_6(voice[1]);
|
||||
voice_3(voice[2]);
|
||||
tick();
|
||||
|
||||
phase(5)
|
||||
voice_7(voice[1]);
|
||||
voice_4(voice[2]);
|
||||
voice_1(voice[4]);
|
||||
tick();
|
||||
|
||||
phase(6)
|
||||
voice_8(voice[1]);
|
||||
voice_5(voice[2]);
|
||||
voice_2(voice[3]);
|
||||
tick();
|
||||
|
||||
phase(7)
|
||||
voice_9(voice[1]);
|
||||
voice_6(voice[2]);
|
||||
voice_3(voice[3]);
|
||||
tick();
|
||||
|
||||
phase(8)
|
||||
voice_7(voice[2]);
|
||||
voice_4(voice[3]);
|
||||
voice_1(voice[5]);
|
||||
tick();
|
||||
|
||||
phase(9)
|
||||
voice_8(voice[2]);
|
||||
voice_5(voice[3]);
|
||||
voice_2(voice[4]);
|
||||
tick();
|
||||
|
||||
phase(10)
|
||||
voice_9(voice[2]);
|
||||
voice_6(voice[3]);
|
||||
voice_3(voice[4]);
|
||||
tick();
|
||||
|
||||
phase(11)
|
||||
voice_7(voice[3]);
|
||||
voice_4(voice[4]);
|
||||
voice_1(voice[6]);
|
||||
tick();
|
||||
|
||||
phase(12)
|
||||
voice_8(voice[3]);
|
||||
voice_5(voice[4]);
|
||||
voice_2(voice[5]);
|
||||
tick();
|
||||
|
||||
phase(13)
|
||||
voice_9(voice[3]);
|
||||
voice_6(voice[4]);
|
||||
voice_3(voice[5]);
|
||||
tick();
|
||||
|
||||
phase(14)
|
||||
voice_7(voice[4]);
|
||||
voice_4(voice[5]);
|
||||
voice_1(voice[7]);
|
||||
tick();
|
||||
|
||||
phase(15)
|
||||
voice_8(voice[4]);
|
||||
voice_5(voice[5]);
|
||||
voice_2(voice[6]);
|
||||
tick();
|
||||
|
||||
phase(16)
|
||||
voice_9(voice[4]);
|
||||
voice_6(voice[5]);
|
||||
voice_3(voice[6]);
|
||||
tick();
|
||||
|
||||
phase(17)
|
||||
voice_1(voice[0]);
|
||||
voice_7(voice[5]);
|
||||
voice_4(voice[6]);
|
||||
tick();
|
||||
|
||||
phase(18)
|
||||
voice_8(voice[5]);
|
||||
voice_5(voice[6]);
|
||||
voice_2(voice[7]);
|
||||
tick();
|
||||
|
||||
phase(19)
|
||||
voice_9(voice[5]);
|
||||
voice_6(voice[6]);
|
||||
voice_3(voice[7]);
|
||||
tick();
|
||||
|
||||
phase(20)
|
||||
voice_1(voice[1]);
|
||||
voice_7(voice[6]);
|
||||
voice_4(voice[7]);
|
||||
tick();
|
||||
|
||||
phase(21)
|
||||
voice_8(voice[6]);
|
||||
voice_5(voice[7]);
|
||||
voice_2(voice[0]);
|
||||
tick();
|
||||
|
||||
phase(22)
|
||||
voice_3a(voice[0]);
|
||||
voice_9(voice[6]);
|
||||
voice_6(voice[7]);
|
||||
echo_22();
|
||||
tick();
|
||||
|
||||
phase(23)
|
||||
voice_7(voice[7]);
|
||||
echo_23();
|
||||
tick();
|
||||
|
||||
phase(24)
|
||||
voice_8(voice[7]);
|
||||
echo_24();
|
||||
tick();
|
||||
|
||||
phase(25)
|
||||
voice_3b(voice[0]);
|
||||
voice_9(voice[7]);
|
||||
echo_25();
|
||||
tick();
|
||||
|
||||
phase(26)
|
||||
echo_26();
|
||||
tick();
|
||||
|
||||
phase(27)
|
||||
misc_27();
|
||||
echo_27();
|
||||
tick();
|
||||
|
||||
phase(28)
|
||||
misc_28();
|
||||
echo_28();
|
||||
tick();
|
||||
|
||||
phase(29)
|
||||
misc_29();
|
||||
echo_29();
|
||||
tick();
|
||||
|
||||
phase(30)
|
||||
misc_30();
|
||||
voice_3c(voice[0]);
|
||||
echo_30();
|
||||
tick();
|
||||
|
||||
phase(31)
|
||||
voice_4(voice[0]);
|
||||
voice_1(voice[2]);
|
||||
tick();
|
||||
|
||||
phase_end()
|
||||
}
|
||||
|
||||
/* register interface for S-SMP $00f2,$00f3 */
|
||||
|
||||
uint8 sDSP::read(uint8 addr) {
|
||||
return state.regs[addr];
|
||||
}
|
||||
|
||||
void sDSP::write(uint8 addr, uint8 data) {
|
||||
state.regs[addr] = data;
|
||||
|
||||
if((addr & 0x0f) == v_envx) {
|
||||
state.envx_buf = data;
|
||||
} else if((addr & 0x0f) == v_outx) {
|
||||
state.outx_buf = data;
|
||||
} else if(addr == r_kon) {
|
||||
state.new_kon = data;
|
||||
} else if(addr == r_endx) {
|
||||
//always cleared, regardless of data written
|
||||
state.endx_buf = 0;
|
||||
state.regs[r_endx] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* initialization */
|
||||
|
||||
void sDSP::power() {
|
||||
DSP::power();
|
||||
|
||||
memset(&state.regs, 0, sizeof state.regs);
|
||||
state.echo_hist_pos = 0;
|
||||
state.every_other_sample = false;
|
||||
state.kon = 0;
|
||||
state.noise = 0;
|
||||
state.counter = 0;
|
||||
state.echo_offset = 0;
|
||||
state.echo_length = 0;
|
||||
state.new_kon = 0;
|
||||
state.endx_buf = 0;
|
||||
state.envx_buf = 0;
|
||||
state.outx_buf = 0;
|
||||
state.t_pmon = 0;
|
||||
state.t_non = 0;
|
||||
state.t_eon = 0;
|
||||
state.t_dir = 0;
|
||||
state.t_koff = 0;
|
||||
state.t_brr_next_addr = 0;
|
||||
state.t_adsr0 = 0;
|
||||
state.t_brr_header = 0;
|
||||
state.t_brr_byte = 0;
|
||||
state.t_srcn = 0;
|
||||
state.t_esa = 0;
|
||||
state.t_echo_disabled = 0;
|
||||
state.t_dir_addr = 0;
|
||||
state.t_pitch = 0;
|
||||
state.t_output = 0;
|
||||
state.t_looped = 0;
|
||||
state.t_echo_ptr = 0;
|
||||
state.t_main_out[0] = state.t_main_out[1] = 0;
|
||||
state.t_echo_out[0] = state.t_echo_out[1] = 0;
|
||||
state.t_echo_in[0] = state.t_echo_in[1] = 0;
|
||||
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
voice[i].buf_pos = 0;
|
||||
voice[i].interp_pos = 0;
|
||||
voice[i].brr_addr = 0;
|
||||
voice[i].brr_offset = 1;
|
||||
voice[i].vbit = 1 << i;
|
||||
voice[i].vidx = i * 0x10;
|
||||
voice[i].kon_delay = 0;
|
||||
voice[i].env_mode = env_release;
|
||||
voice[i].env = 0;
|
||||
voice[i].t_envx_out = 0;
|
||||
voice[i].hidden_env = 0;
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void sDSP::reset() {
|
||||
DSP::reset();
|
||||
|
||||
REG(flg) = 0xe0;
|
||||
|
||||
state.noise = 0x4000;
|
||||
state.echo_hist_pos = 0;
|
||||
state.every_other_sample = 1;
|
||||
state.echo_offset = 0;
|
||||
state.counter = 0;
|
||||
|
||||
phase_index = 0;
|
||||
}
|
||||
|
||||
sDSP::sDSP() {
|
||||
static_assert(sizeof(int) >= 32 / 8, "int >= 32-bits");
|
||||
static_assert((int8)0x80 == -0x80, "8-bit sign extension");
|
||||
static_assert((int16)0x8000 == -0x8000, "16-bit sign extension");
|
||||
static_assert((uint16)0xffff0000 == 0, "16-bit unsigned clip");
|
||||
static_assert((-1 >> 1) == -1, "arithmetic shift right");
|
||||
|
||||
//-0x8000 <= n <= +0x7fff
|
||||
assert(sclamp<16>(+0x8000) == +0x7fff);
|
||||
assert(sclamp<16>(-0x8001) == -0x8000);
|
||||
}
|
||||
|
||||
sDSP::~sDSP() {
|
||||
}
|
||||
|
||||
}
|
|
@ -1,176 +0,0 @@
|
|||
class sDSP : public DSP {
|
||||
public:
|
||||
void enter();
|
||||
|
||||
uint8 read(uint8 addr);
|
||||
void write(uint8 addr, uint8 data);
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
sDSP();
|
||||
~sDSP();
|
||||
|
||||
protected:
|
||||
//DSP_STATE_MACHINE variable
|
||||
unsigned phase_index;
|
||||
|
||||
//global registers
|
||||
enum global_reg_t {
|
||||
r_mvoll = 0x0c, r_mvolr = 0x1c,
|
||||
r_evoll = 0x2c, r_evolr = 0x3c,
|
||||
r_kon = 0x4c, r_koff = 0x5c,
|
||||
r_flg = 0x6c, r_endx = 0x7c,
|
||||
r_efb = 0x0d, r_pmon = 0x2d,
|
||||
r_non = 0x3d, r_eon = 0x4d,
|
||||
r_dir = 0x5d, r_esa = 0x6d,
|
||||
r_edl = 0x7d, r_fir = 0x0f, //8 coefficients at 0x0f, 0x1f, ... 0x7f
|
||||
};
|
||||
|
||||
//voice registers
|
||||
enum voice_reg_t {
|
||||
v_voll = 0x00, v_volr = 0x01,
|
||||
v_pitchl = 0x02, v_pitchh = 0x03,
|
||||
v_srcn = 0x04, v_adsr0 = 0x05,
|
||||
v_adsr1 = 0x06, v_gain = 0x07,
|
||||
v_envx = 0x08, v_outx = 0x09,
|
||||
};
|
||||
|
||||
//internal envelope modes
|
||||
enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
|
||||
|
||||
//internal constants
|
||||
enum { echo_hist_size = 8 };
|
||||
enum { brr_buf_size = 12 };
|
||||
enum { brr_block_size = 9 };
|
||||
|
||||
//global state
|
||||
struct state_t {
|
||||
uint8 regs[128];
|
||||
|
||||
modulo_array<int, echo_hist_size> echo_hist[2]; //echo history keeps most recent 8 samples
|
||||
int echo_hist_pos;
|
||||
|
||||
bool every_other_sample; //toggles every sample
|
||||
int kon; //KON value when last checked
|
||||
int noise;
|
||||
int counter;
|
||||
int echo_offset; //offset from ESA in echo buffer
|
||||
int echo_length; //number of bytes that echo_offset will stop at
|
||||
|
||||
//hidden registers also written to when main register is written to
|
||||
int new_kon;
|
||||
int endx_buf;
|
||||
int envx_buf;
|
||||
int outx_buf;
|
||||
|
||||
//temporary state between clocks
|
||||
|
||||
//read once per sample
|
||||
int t_pmon;
|
||||
int t_non;
|
||||
int t_eon;
|
||||
int t_dir;
|
||||
int t_koff;
|
||||
|
||||
//read a few clocks ahead before used
|
||||
int t_brr_next_addr;
|
||||
int t_adsr0;
|
||||
int t_brr_header;
|
||||
int t_brr_byte;
|
||||
int t_srcn;
|
||||
int t_esa;
|
||||
int t_echo_disabled;
|
||||
|
||||
//internal state that is recalculated every sample
|
||||
int t_dir_addr;
|
||||
int t_pitch;
|
||||
int t_output;
|
||||
int t_looped;
|
||||
int t_echo_ptr;
|
||||
|
||||
//left/right sums
|
||||
int t_main_out[2];
|
||||
int t_echo_out[2];
|
||||
int t_echo_in [2];
|
||||
} state;
|
||||
|
||||
//voice state
|
||||
struct voice_t {
|
||||
modulo_array<int, brr_buf_size> buffer; //decoded samples
|
||||
int buf_pos; //place in buffer where next samples will be decoded
|
||||
int interp_pos; //relative fractional position in sample (0x1000 = 1.0)
|
||||
int brr_addr; //address of current BRR block
|
||||
int brr_offset; //current decoding offset in BRR block
|
||||
int vbit; //bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc
|
||||
int vidx; //voice channel register index: 0x00 for voice 0, 0x10 for voice 1, etc
|
||||
int kon_delay; //KON delay/current setup phase
|
||||
int env_mode;
|
||||
int env; //current envelope level
|
||||
int t_envx_out;
|
||||
int hidden_env; //used by GAIN mode 7, very obscure quirk
|
||||
} voice[8];
|
||||
|
||||
//gaussian
|
||||
static const int16 gaussian_table[512];
|
||||
int gaussian_interpolate(const voice_t &v);
|
||||
|
||||
//counter
|
||||
enum { counter_range = 2048 * 5 * 3 }; //30720 (0x7800)
|
||||
static const uint16 counter_rate[32];
|
||||
static const uint16 counter_offset[32];
|
||||
void counter_tick();
|
||||
bool counter_poll(unsigned rate);
|
||||
|
||||
//envelope
|
||||
void envelope_run(voice_t &v);
|
||||
|
||||
//brr
|
||||
void brr_decode(voice_t &v);
|
||||
|
||||
//misc
|
||||
void misc_27();
|
||||
void misc_28();
|
||||
void misc_29();
|
||||
void misc_30();
|
||||
|
||||
//voice
|
||||
void voice_output(voice_t &v, bool channel);
|
||||
void voice_1 (voice_t &v);
|
||||
void voice_2 (voice_t &v);
|
||||
void voice_3 (voice_t &v);
|
||||
void voice_3a(voice_t &v);
|
||||
void voice_3b(voice_t &v);
|
||||
void voice_3c(voice_t &v);
|
||||
void voice_4 (voice_t &v);
|
||||
void voice_5 (voice_t &v);
|
||||
void voice_6 (voice_t &v);
|
||||
void voice_7 (voice_t &v);
|
||||
void voice_8 (voice_t &v);
|
||||
void voice_9 (voice_t &v);
|
||||
|
||||
//echo
|
||||
int calc_fir(int i, bool channel);
|
||||
int echo_output(bool channel);
|
||||
void echo_read(bool channel);
|
||||
void echo_write(bool channel);
|
||||
void echo_22();
|
||||
void echo_23();
|
||||
void echo_24();
|
||||
void echo_25();
|
||||
void echo_26();
|
||||
void echo_27();
|
||||
void echo_28();
|
||||
void echo_29();
|
||||
void echo_30();
|
||||
|
||||
friend class sDSPDebug;
|
||||
};
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.hpp"
|
||||
extern sDSPDebugger dsp;
|
||||
#else
|
||||
extern sDSP dsp;
|
||||
#endif
|
|
@ -1,8 +1,7 @@
|
|||
#ifdef SDSP_CPP
|
||||
|
||||
void sDSP::serialize(serializer &s) {
|
||||
DSP::serialize(s);
|
||||
#ifdef DSP_CPP
|
||||
|
||||
void DSP::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
s.integer(phase_index);
|
||||
|
||||
s.array(state.regs, 128);
|
|
@ -1,7 +0,0 @@
|
|||
void DSP::step(unsigned clocks) {
|
||||
clock += clocks;
|
||||
}
|
||||
|
||||
void DSP::synchronize_smp() {
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(smp.thread);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef SDSP_CPP
|
||||
#ifdef DSP_CPP
|
||||
|
||||
inline void sDSP::voice_output(voice_t &v, bool channel) {
|
||||
inline void DSP::voice_output(voice_t &v, bool channel) {
|
||||
//apply left/right volume
|
||||
int amp = (state.t_output * (int8)VREG(voll + channel)) >> 7;
|
||||
|
||||
|
@ -15,12 +15,12 @@ inline void sDSP::voice_output(voice_t &v, bool channel) {
|
|||
}
|
||||
}
|
||||
|
||||
void sDSP::voice_1(voice_t &v) {
|
||||
void DSP::voice_1(voice_t &v) {
|
||||
state.t_dir_addr = (state.t_dir << 8) + (state.t_srcn << 2);
|
||||
state.t_srcn = VREG(srcn);
|
||||
}
|
||||
|
||||
void sDSP::voice_2(voice_t &v) {
|
||||
void DSP::voice_2(voice_t &v) {
|
||||
//read sample pointer (ignored if not needed)
|
||||
uint16 addr = state.t_dir_addr;
|
||||
if(!v.kon_delay) addr += 2;
|
||||
|
@ -34,22 +34,22 @@ void sDSP::voice_2(voice_t &v) {
|
|||
state.t_pitch = VREG(pitchl);
|
||||
}
|
||||
|
||||
void sDSP::voice_3(voice_t &v) {
|
||||
void DSP::voice_3(voice_t &v) {
|
||||
voice_3a(v);
|
||||
voice_3b(v);
|
||||
voice_3c(v);
|
||||
}
|
||||
|
||||
void sDSP::voice_3a(voice_t &v) {
|
||||
void DSP::voice_3a(voice_t &v) {
|
||||
state.t_pitch += (VREG(pitchh) & 0x3f) << 8;
|
||||
}
|
||||
|
||||
void sDSP::voice_3b(voice_t &v) {
|
||||
void DSP::voice_3b(voice_t &v) {
|
||||
state.t_brr_byte = memory::apuram[(uint16)(v.brr_addr + v.brr_offset)];
|
||||
state.t_brr_header = memory::apuram[(uint16)(v.brr_addr)];
|
||||
}
|
||||
|
||||
void sDSP::voice_3c(voice_t &v) {
|
||||
void DSP::voice_3c(voice_t &v) {
|
||||
//pitch modulation using previous voice's output
|
||||
|
||||
if(state.t_pmon & v.vbit) {
|
||||
|
@ -113,7 +113,7 @@ void sDSP::voice_3c(voice_t &v) {
|
|||
if(!v.kon_delay) envelope_run(v);
|
||||
}
|
||||
|
||||
void sDSP::voice_4(voice_t &v) {
|
||||
void DSP::voice_4(voice_t &v) {
|
||||
//decode BRR
|
||||
state.t_looped = 0;
|
||||
if(v.interp_pos >= 0x4000) {
|
||||
|
@ -140,7 +140,7 @@ void sDSP::voice_4(voice_t &v) {
|
|||
voice_output(v, 0);
|
||||
}
|
||||
|
||||
void sDSP::voice_5(voice_t &v) {
|
||||
void DSP::voice_5(voice_t &v) {
|
||||
//output right
|
||||
voice_output(v, 1);
|
||||
|
||||
|
@ -151,22 +151,22 @@ void sDSP::voice_5(voice_t &v) {
|
|||
if(v.kon_delay == 5) state.endx_buf &= ~v.vbit;
|
||||
}
|
||||
|
||||
void sDSP::voice_6(voice_t &v) {
|
||||
void DSP::voice_6(voice_t &v) {
|
||||
state.outx_buf = state.t_output >> 8;
|
||||
}
|
||||
|
||||
void sDSP::voice_7(voice_t &v) {
|
||||
void DSP::voice_7(voice_t &v) {
|
||||
//update ENDX
|
||||
REG(endx) = (uint8)state.endx_buf;
|
||||
state.envx_buf = v.t_envx_out;
|
||||
}
|
||||
|
||||
void sDSP::voice_8(voice_t &v) {
|
||||
void DSP::voice_8(voice_t &v) {
|
||||
//update OUTX
|
||||
VREG(outx) = (uint8)state.outx_buf;
|
||||
}
|
||||
|
||||
void sDSP::voice_9(voice_t &v) {
|
||||
void DSP::voice_9(voice_t &v) {
|
||||
//update ENVX
|
||||
VREG(envx) = (uint8)state.envx_buf;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "067.07";
|
||||
static const unsigned SerializerVersion = 12;
|
||||
}
|
||||
}
|
||||
|
||||
#define DSP_STATE_MACHINE
|
||||
//#define DEBUGGER
|
|
@ -1,5 +1,5 @@
|
|||
#include "libsnes.hpp"
|
||||
#include <snes/snes.hpp>
|
||||
#include <snes.hpp>
|
||||
|
||||
#include <nall/snes/info.hpp>
|
||||
using namespace nall;
|
||||
|
|
|
@ -48,6 +48,9 @@ extern "C" {
|
|||
#define SNES_DEVICE_ID_JUSTIFIER_TRIGGER 2
|
||||
#define SNES_DEVICE_ID_JUSTIFIER_START 3
|
||||
|
||||
#define SNES_REGION_NTSC 0
|
||||
#define SNES_REGION_PAL 1
|
||||
|
||||
#define SNES_MEMORY_CARTRIDGE_RAM 0
|
||||
#define SNES_MEMORY_CARTRIDGE_RTC 1
|
||||
#define SNES_MEMORY_BSX_RAM 2
|
||||
|
|
|
@ -67,9 +67,3 @@ void Bus::write(unsigned addr, uint8 data) {
|
|||
Page &p = page[addr >> 8];
|
||||
return p.access->write(p.offset + addr, data);
|
||||
}
|
||||
|
||||
bool Bus::load_cart() { return false; }
|
||||
void Bus::unload_cart() {}
|
||||
|
||||
void Bus::power() {}
|
||||
void Bus::reset() {}
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
#define MEMORY_CPP
|
||||
namespace SNES {
|
||||
|
||||
Bus bus;
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
namespace memory {
|
||||
MMIOAccess mmio;
|
||||
StaticRAM wram(128 * 1024);
|
||||
|
@ -109,4 +113,46 @@ void Bus::map(
|
|||
}
|
||||
}
|
||||
|
||||
bool Bus::load_cart() {
|
||||
if(cartridge.loaded() == true) return false;
|
||||
|
||||
map_reset();
|
||||
map_xml();
|
||||
map_system();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Bus::unload_cart() {
|
||||
}
|
||||
|
||||
void Bus::map_reset() {
|
||||
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
|
||||
map(MapMode::Direct, 0x00, 0x3f, 0x2000, 0x5fff, memory::mmio);
|
||||
map(MapMode::Direct, 0x80, 0xbf, 0x2000, 0x5fff, memory::mmio);
|
||||
for(unsigned i = 0x2000; i <= 0x5fff; i++) memory::mmio.map(i, memory::mmio_unmapped);
|
||||
}
|
||||
|
||||
void Bus::map_xml() {
|
||||
foreach(m, cartridge.mapping) {
|
||||
if(m.memory) {
|
||||
map(m.mode, m.banklo, m.bankhi, m.addrlo, m.addrhi, *m.memory, m.offset, m.size);
|
||||
} else if(m.mmio) {
|
||||
for(unsigned i = m.addrlo; i <= m.addrhi; i++) memory::mmio.map(i, *m.mmio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Bus::map_system() {
|
||||
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, memory::wram, 0x000000, 0x002000);
|
||||
map(MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, memory::wram, 0x000000, 0x002000);
|
||||
map(MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, memory::wram);
|
||||
}
|
||||
|
||||
void Bus::power() {
|
||||
foreach(n, memory::wram) n = config.cpu.wram_init_value;
|
||||
}
|
||||
|
||||
void Bus::reset() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -77,18 +77,23 @@ struct Bus {
|
|||
alwaysinline uint8 read(unsigned addr);
|
||||
alwaysinline void write(unsigned addr, uint8 data);
|
||||
|
||||
virtual inline bool load_cart();
|
||||
virtual inline void unload_cart();
|
||||
bool load_cart();
|
||||
void unload_cart();
|
||||
|
||||
virtual inline void power();
|
||||
virtual inline void reset();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
struct Page {
|
||||
Memory *access;
|
||||
unsigned offset;
|
||||
} page[65536];
|
||||
|
||||
virtual void serialize(serializer&) {}
|
||||
void serialize(serializer&);
|
||||
|
||||
private:
|
||||
void map_reset();
|
||||
void map_xml();
|
||||
void map_system();
|
||||
};
|
||||
|
||||
namespace memory {
|
||||
|
@ -102,3 +107,5 @@ namespace memory {
|
|||
extern UnmappedMemory memory_unmapped;
|
||||
extern UnmappedMMIO mmio_unmapped;
|
||||
};
|
||||
|
||||
extern Bus bus;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef SMEMORY_CPP
|
||||
#ifdef MEMORY_CPP
|
||||
|
||||
void sBus::serialize(serializer &s) {
|
||||
void Bus::serialize(serializer &s) {
|
||||
s.array(memory::wram.data(), memory::wram.size());
|
||||
s.array(memory::apuram.data(), memory::apuram.size());
|
||||
s.array(memory::vram.data(), memory::vram.size());
|
|
@ -1,58 +0,0 @@
|
|||
#include <snes.hpp>
|
||||
|
||||
#define SMEMORY_CPP
|
||||
namespace SNES {
|
||||
|
||||
sBus bus;
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
void sBus::power() {
|
||||
foreach(n, memory::wram) n = config.cpu.wram_init_value;
|
||||
}
|
||||
|
||||
void sBus::reset() {
|
||||
}
|
||||
|
||||
bool sBus::load_cart() {
|
||||
if(cartridge.loaded() == true) return false;
|
||||
|
||||
map_reset();
|
||||
map_xml();
|
||||
map_system();
|
||||
return true;
|
||||
}
|
||||
|
||||
void sBus::unload_cart() {
|
||||
}
|
||||
|
||||
void sBus::map_reset() {
|
||||
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
|
||||
map(MapMode::Direct, 0x00, 0x3f, 0x2000, 0x5fff, memory::mmio);
|
||||
map(MapMode::Direct, 0x80, 0xbf, 0x2000, 0x5fff, memory::mmio);
|
||||
for(unsigned i = 0x2000; i <= 0x5fff; i++) memory::mmio.map(i, memory::mmio_unmapped);
|
||||
}
|
||||
|
||||
void sBus::map_xml() {
|
||||
foreach(m, cartridge.mapping) {
|
||||
if(m.memory) {
|
||||
map(m.mode, m.banklo, m.bankhi, m.addrlo, m.addrhi, *m.memory, m.offset, m.size);
|
||||
} else if(m.mmio) {
|
||||
for(unsigned i = m.addrlo; i <= m.addrhi; i++) memory::mmio.map(i, *m.mmio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sBus::map_system() {
|
||||
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, memory::wram, 0x000000, 0x002000);
|
||||
map(MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, memory::wram, 0x000000, 0x002000);
|
||||
map(MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, memory::wram);
|
||||
}
|
||||
|
||||
sBus::sBus() {
|
||||
}
|
||||
|
||||
sBus::~sBus() {
|
||||
}
|
||||
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
class sBus : public Bus {
|
||||
public:
|
||||
bool load_cart();
|
||||
void unload_cart();
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
sBus();
|
||||
~sBus();
|
||||
|
||||
private:
|
||||
void map_reset();
|
||||
void map_xml();
|
||||
void map_system();
|
||||
};
|
||||
|
||||
extern sBus bus;
|
|
@ -1,378 +0,0 @@
|
|||
#include <snes.hpp>
|
||||
|
||||
#define BPPU_CPP
|
||||
namespace SNES {
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.cpp"
|
||||
bPPUDebugger ppu;
|
||||
#else
|
||||
bPPU ppu;
|
||||
#endif
|
||||
|
||||
#include "memory/memory.cpp"
|
||||
#include "mmio/mmio.cpp"
|
||||
#include "render/render.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
void bPPU::enter() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
//H = 0 (initialize)
|
||||
scanline();
|
||||
add_clocks(10);
|
||||
|
||||
//H = 10 (cache mode7 registers + OAM address reset)
|
||||
cache.m7_hofs = regs.m7_hofs;
|
||||
cache.m7_vofs = regs.m7_vofs;
|
||||
cache.m7a = regs.m7a;
|
||||
cache.m7b = regs.m7b;
|
||||
cache.m7c = regs.m7c;
|
||||
cache.m7d = regs.m7d;
|
||||
cache.m7x = regs.m7x;
|
||||
cache.m7y = regs.m7y;
|
||||
if(vcounter() == (!overscan() ? 225 : 240)) {
|
||||
if(regs.display_disabled == false) {
|
||||
regs.oam_addr = regs.oam_baseaddr << 1;
|
||||
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
||||
}
|
||||
}
|
||||
add_clocks(502);
|
||||
|
||||
//H = 512 (render)
|
||||
render_scanline();
|
||||
add_clocks(640);
|
||||
|
||||
//H = 1152 (cache OBSEL)
|
||||
if(cache.oam_basesize != regs.oam_basesize) {
|
||||
cache.oam_basesize = regs.oam_basesize;
|
||||
sprite_list_valid = false;
|
||||
}
|
||||
cache.oam_nameselect = regs.oam_nameselect;
|
||||
cache.oam_tdaddr = regs.oam_tdaddr;
|
||||
add_clocks(lineclocks() - 1152); //seek to start of next scanline
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::add_clocks(unsigned clocks) {
|
||||
tick(clocks);
|
||||
step(clocks);
|
||||
synchronize_cpu();
|
||||
}
|
||||
|
||||
void bPPU::scanline() {
|
||||
line = vcounter();
|
||||
|
||||
if(line == 0) {
|
||||
frame();
|
||||
|
||||
//RTO flag reset
|
||||
regs.time_over = false;
|
||||
regs.range_over = false;
|
||||
}
|
||||
|
||||
if(line == 1) {
|
||||
//mosaic reset
|
||||
for(int bg = BG1; bg <= BG4; bg++) regs.bg_y[bg] = 1;
|
||||
regs.mosaic_countdown = regs.mosaic_size + 1;
|
||||
regs.mosaic_countdown--;
|
||||
} else {
|
||||
for(int bg = BG1; bg <= BG4; bg++) {
|
||||
if(!regs.mosaic_enabled[bg] || !regs.mosaic_countdown) regs.bg_y[bg] = line;
|
||||
}
|
||||
if(!regs.mosaic_countdown) regs.mosaic_countdown = regs.mosaic_size + 1;
|
||||
regs.mosaic_countdown--;
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::render_scanline() {
|
||||
if(line >= 1 && line < (!overscan() ? 225 : 240)) {
|
||||
render_line_oam_rto();
|
||||
render_line();
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::frame() {
|
||||
PPU::frame();
|
||||
system.frame();
|
||||
|
||||
if(field() == 0) {
|
||||
display.interlace = regs.interlace;
|
||||
regs.scanlines = (regs.overscan == false) ? 224 : 239;
|
||||
}
|
||||
}
|
||||
|
||||
void bPPU::power() {
|
||||
PPU::power();
|
||||
|
||||
for(unsigned i = 0; i < memory::vram.size(); i++) memory::vram[i] = 0x00;
|
||||
for(unsigned i = 0; i < memory::oam.size(); i++) memory::oam[i] = 0x00;
|
||||
for(unsigned i = 0; i < memory::cgram.size(); i++) memory::cgram[i] = 0x00;
|
||||
flush_tiledata_cache();
|
||||
|
||||
region = (system.region() == System::Region::NTSC ? 0 : 1); //0 = NTSC, 1 = PAL
|
||||
|
||||
regs.ioamaddr = 0x0000;
|
||||
regs.icgramaddr = 0x01ff;
|
||||
|
||||
//$2100
|
||||
regs.display_disabled = true;
|
||||
regs.display_brightness = 15;
|
||||
|
||||
//$2101
|
||||
regs.oam_basesize = 0;
|
||||
regs.oam_nameselect = 0;
|
||||
regs.oam_tdaddr = 0x0000;
|
||||
|
||||
cache.oam_basesize = 0;
|
||||
cache.oam_nameselect = 0;
|
||||
cache.oam_tdaddr = 0x0000;
|
||||
|
||||
//$2102-$2103
|
||||
regs.oam_baseaddr = 0x0000;
|
||||
regs.oam_addr = 0x0000;
|
||||
regs.oam_priority = false;
|
||||
regs.oam_firstsprite = 0;
|
||||
|
||||
//$2104
|
||||
regs.oam_latchdata = 0x00;
|
||||
|
||||
//$2105
|
||||
regs.bg_tilesize[BG1] = 0;
|
||||
regs.bg_tilesize[BG2] = 0;
|
||||
regs.bg_tilesize[BG3] = 0;
|
||||
regs.bg_tilesize[BG4] = 0;
|
||||
regs.bg3_priority = 0;
|
||||
regs.bg_mode = 0;
|
||||
|
||||
//$2106
|
||||
regs.mosaic_size = 0;
|
||||
regs.mosaic_enabled[BG1] = false;
|
||||
regs.mosaic_enabled[BG2] = false;
|
||||
regs.mosaic_enabled[BG3] = false;
|
||||
regs.mosaic_enabled[BG4] = false;
|
||||
regs.mosaic_countdown = 0;
|
||||
|
||||
//$2107-$210a
|
||||
regs.bg_scaddr[BG1] = 0x0000;
|
||||
regs.bg_scaddr[BG2] = 0x0000;
|
||||
regs.bg_scaddr[BG3] = 0x0000;
|
||||
regs.bg_scaddr[BG4] = 0x0000;
|
||||
regs.bg_scsize[BG1] = SC_32x32;
|
||||
regs.bg_scsize[BG2] = SC_32x32;
|
||||
regs.bg_scsize[BG3] = SC_32x32;
|
||||
regs.bg_scsize[BG4] = SC_32x32;
|
||||
|
||||
//$210b-$210c
|
||||
regs.bg_tdaddr[BG1] = 0x0000;
|
||||
regs.bg_tdaddr[BG2] = 0x0000;
|
||||
regs.bg_tdaddr[BG3] = 0x0000;
|
||||
regs.bg_tdaddr[BG4] = 0x0000;
|
||||
|
||||
//$210d-$2114
|
||||
regs.bg_ofslatch = 0x00;
|
||||
regs.m7_hofs = regs.m7_vofs = 0x0000;
|
||||
regs.bg_hofs[BG1] = regs.bg_vofs[BG1] = 0x0000;
|
||||
regs.bg_hofs[BG2] = regs.bg_vofs[BG2] = 0x0000;
|
||||
regs.bg_hofs[BG3] = regs.bg_vofs[BG3] = 0x0000;
|
||||
regs.bg_hofs[BG4] = regs.bg_vofs[BG4] = 0x0000;
|
||||
|
||||
//$2115
|
||||
regs.vram_incmode = 1;
|
||||
regs.vram_mapping = 0;
|
||||
regs.vram_incsize = 1;
|
||||
|
||||
//$2116-$2117
|
||||
regs.vram_addr = 0x0000;
|
||||
|
||||
//$211a
|
||||
regs.mode7_repeat = 0;
|
||||
regs.mode7_vflip = false;
|
||||
regs.mode7_hflip = false;
|
||||
|
||||
//$211b-$2120
|
||||
regs.m7_latch = 0x00;
|
||||
regs.m7a = 0x0000;
|
||||
regs.m7b = 0x0000;
|
||||
regs.m7c = 0x0000;
|
||||
regs.m7d = 0x0000;
|
||||
regs.m7x = 0x0000;
|
||||
regs.m7y = 0x0000;
|
||||
|
||||
//$2121
|
||||
regs.cgram_addr = 0x0000;
|
||||
|
||||
//$2122
|
||||
regs.cgram_latchdata = 0x00;
|
||||
|
||||
//$2123-$2125
|
||||
regs.window1_enabled[BG1] = false;
|
||||
regs.window1_enabled[BG2] = false;
|
||||
regs.window1_enabled[BG3] = false;
|
||||
regs.window1_enabled[BG4] = false;
|
||||
regs.window1_enabled[OAM] = false;
|
||||
regs.window1_enabled[COL] = false;
|
||||
|
||||
regs.window1_invert [BG1] = false;
|
||||
regs.window1_invert [BG2] = false;
|
||||
regs.window1_invert [BG3] = false;
|
||||
regs.window1_invert [BG4] = false;
|
||||
regs.window1_invert [OAM] = false;
|
||||
regs.window1_invert [COL] = false;
|
||||
|
||||
regs.window2_enabled[BG1] = false;
|
||||
regs.window2_enabled[BG2] = false;
|
||||
regs.window2_enabled[BG3] = false;
|
||||
regs.window2_enabled[BG4] = false;
|
||||
regs.window2_enabled[OAM] = false;
|
||||
regs.window2_enabled[COL] = false;
|
||||
|
||||
regs.window2_invert [BG1] = false;
|
||||
regs.window2_invert [BG2] = false;
|
||||
regs.window2_invert [BG3] = false;
|
||||
regs.window2_invert [BG4] = false;
|
||||
regs.window2_invert [OAM] = false;
|
||||
regs.window2_invert [COL] = false;
|
||||
|
||||
//$2126-$2129
|
||||
regs.window1_left = 0x00;
|
||||
regs.window1_right = 0x00;
|
||||
regs.window2_left = 0x00;
|
||||
regs.window2_right = 0x00;
|
||||
|
||||
//$212a-$212b
|
||||
regs.window_mask[BG1] = 0;
|
||||
regs.window_mask[BG2] = 0;
|
||||
regs.window_mask[BG3] = 0;
|
||||
regs.window_mask[BG4] = 0;
|
||||
regs.window_mask[OAM] = 0;
|
||||
regs.window_mask[COL] = 0;
|
||||
|
||||
//$212c-$212d
|
||||
regs.bg_enabled[BG1] = false;
|
||||
regs.bg_enabled[BG2] = false;
|
||||
regs.bg_enabled[BG3] = false;
|
||||
regs.bg_enabled[BG4] = false;
|
||||
regs.bg_enabled[OAM] = false;
|
||||
regs.bgsub_enabled[BG1] = false;
|
||||
regs.bgsub_enabled[BG2] = false;
|
||||
regs.bgsub_enabled[BG3] = false;
|
||||
regs.bgsub_enabled[BG4] = false;
|
||||
regs.bgsub_enabled[OAM] = false;
|
||||
|
||||
//$212e-$212f
|
||||
regs.window_enabled[BG1] = false;
|
||||
regs.window_enabled[BG2] = false;
|
||||
regs.window_enabled[BG3] = false;
|
||||
regs.window_enabled[BG4] = false;
|
||||
regs.window_enabled[OAM] = false;
|
||||
regs.sub_window_enabled[BG1] = false;
|
||||
regs.sub_window_enabled[BG2] = false;
|
||||
regs.sub_window_enabled[BG3] = false;
|
||||
regs.sub_window_enabled[BG4] = false;
|
||||
regs.sub_window_enabled[OAM] = false;
|
||||
|
||||
//$2130
|
||||
regs.color_mask = 0;
|
||||
regs.colorsub_mask = 0;
|
||||
regs.addsub_mode = false;
|
||||
regs.direct_color = false;
|
||||
|
||||
//$2131
|
||||
regs.color_mode = 0;
|
||||
regs.color_halve = false;
|
||||
regs.color_enabled[BACK] = false;
|
||||
regs.color_enabled[OAM] = false;
|
||||
regs.color_enabled[BG4] = false;
|
||||
regs.color_enabled[BG3] = false;
|
||||
regs.color_enabled[BG2] = false;
|
||||
regs.color_enabled[BG1] = false;
|
||||
|
||||
//$2132
|
||||
regs.color_r = 0x00;
|
||||
regs.color_g = 0x00;
|
||||
regs.color_b = 0x00;
|
||||
regs.color_rgb = 0x0000;
|
||||
|
||||
//$2133
|
||||
regs.mode7_extbg = false;
|
||||
regs.pseudo_hires = false;
|
||||
regs.overscan = false;
|
||||
regs.scanlines = 224;
|
||||
regs.oam_interlace = false;
|
||||
regs.interlace = false;
|
||||
|
||||
//$2137
|
||||
regs.hcounter = 0;
|
||||
regs.vcounter = 0;
|
||||
regs.latch_hcounter = 0;
|
||||
regs.latch_vcounter = 0;
|
||||
regs.counters_latched = false;
|
||||
|
||||
//$2139-$213a
|
||||
regs.vram_readbuffer = 0x0000;
|
||||
|
||||
//$213e
|
||||
regs.time_over = false;
|
||||
regs.range_over = false;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void bPPU::reset() {
|
||||
PPU::reset();
|
||||
PPU::frame();
|
||||
|
||||
//$2100
|
||||
regs.display_disabled = true;
|
||||
|
||||
display.interlace = false;
|
||||
display.overscan = false;
|
||||
regs.scanlines = 224;
|
||||
|
||||
memset(sprite_list, 0, sizeof(sprite_list));
|
||||
sprite_list_valid = false;
|
||||
|
||||
//open bus support
|
||||
regs.ppu1_mdr = 0xff;
|
||||
regs.ppu2_mdr = 0xff;
|
||||
|
||||
//bg line counters
|
||||
regs.bg_y[0] = 0;
|
||||
regs.bg_y[1] = 0;
|
||||
regs.bg_y[2] = 0;
|
||||
regs.bg_y[3] = 0;
|
||||
}
|
||||
|
||||
bPPU::bPPU() {
|
||||
alloc_tiledata_cache();
|
||||
|
||||
for(unsigned l = 0; l < 16; l++) {
|
||||
for(unsigned i = 0; i < 4096; i++) {
|
||||
mosaic_table[l][i] = (i / (l + 1)) * (l + 1);
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned l = 0; l < 16; l++) {
|
||||
for(unsigned r = 0; r < 32; r++) {
|
||||
for(unsigned g = 0; g < 32; g++) {
|
||||
for(unsigned b = 0; b < 32; b++) {
|
||||
double luma = (double)l / 15.0;
|
||||
unsigned ar = (luma * r + 0.5);
|
||||
unsigned ag = (luma * g + 0.5);
|
||||
unsigned ab = (luma * b + 0.5);
|
||||
light_table[l][(r << 10) + (g << 5) + b] = (ab << 10) + (ag << 5) + ar;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bPPU::~bPPU() {
|
||||
free_tiledata_cache();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
class bPPU : public PPU {
|
||||
public:
|
||||
#include "memory/memory.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "render/render.hpp"
|
||||
|
||||
void enter();
|
||||
void add_clocks(unsigned clocks);
|
||||
|
||||
uint8 region;
|
||||
unsigned line;
|
||||
|
||||
enum { NTSC = 0, PAL = 1 };
|
||||
enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5, COL = 5 };
|
||||
enum { SC_32x32 = 0, SC_64x32 = 1, SC_32x64 = 2, SC_64x64 = 3 };
|
||||
|
||||
struct {
|
||||
bool interlace;
|
||||
bool overscan;
|
||||
} display;
|
||||
|
||||
struct {
|
||||
//$2101
|
||||
uint8 oam_basesize;
|
||||
uint8 oam_nameselect;
|
||||
uint16 oam_tdaddr;
|
||||
|
||||
//$210d-$210e
|
||||
uint16 m7_hofs, m7_vofs;
|
||||
|
||||
//$211b-$2120
|
||||
uint16 m7a, m7b, m7c, m7d, m7x, m7y;
|
||||
} cache;
|
||||
|
||||
alwaysinline bool interlace() const { return display.interlace; }
|
||||
alwaysinline bool overscan() const { return display.overscan; }
|
||||
alwaysinline bool hires() const { return (regs.pseudo_hires || regs.bg_mode == 5 || regs.bg_mode == 6); }
|
||||
|
||||
uint16 light_table[16][32768];
|
||||
uint16 mosaic_table[16][4096];
|
||||
void render_line();
|
||||
|
||||
void update_oam_status();
|
||||
//required functions
|
||||
void run();
|
||||
void scanline();
|
||||
void render_scanline();
|
||||
void frame();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
bPPU();
|
||||
~bPPU();
|
||||
|
||||
friend class bPPUDebug;
|
||||
};
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.hpp"
|
||||
extern bPPUDebugger ppu;
|
||||
#else
|
||||
extern bPPU ppu;
|
||||
#endif
|
|
@ -1,290 +0,0 @@
|
|||
#ifdef BPPU_CPP
|
||||
|
||||
#include "render.cpp"
|
||||
|
||||
uint8 bPPUDebugger::vram_mmio_read(uint16 addr) {
|
||||
uint8 data = bPPU::vram_mmio_read(addr);
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::VRAM, Debugger::Breakpoint::Mode::Read, addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void bPPUDebugger::vram_mmio_write(uint16 addr, uint8 data) {
|
||||
bPPU::vram_mmio_write(addr, data);
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::VRAM, Debugger::Breakpoint::Mode::Write, addr, data);
|
||||
}
|
||||
|
||||
uint8 bPPUDebugger::oam_mmio_read(uint16 addr) {
|
||||
uint8 data = bPPU::oam_mmio_read(addr);
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::OAM, Debugger::Breakpoint::Mode::Read, addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void bPPUDebugger::oam_mmio_write(uint16 addr, uint8 data) {
|
||||
bPPU::oam_mmio_write(addr, data);
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::OAM, Debugger::Breakpoint::Mode::Write, addr, data);
|
||||
}
|
||||
|
||||
uint8 bPPUDebugger::cgram_mmio_read(uint16 addr) {
|
||||
uint8 data = bPPU::cgram_mmio_read(addr);
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CGRAM, Debugger::Breakpoint::Mode::Read, addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void bPPUDebugger::cgram_mmio_write(uint16 addr, uint8 data) {
|
||||
bPPU::cgram_mmio_write(addr, data);
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CGRAM, Debugger::Breakpoint::Mode::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_enable() { return regs.overscan; }
|
||||
bool bPPUDebugger::oam_interlace() { return regs.oam_interlace; }
|
||||
bool bPPUDebugger::interlace_enable() { 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,186 +0,0 @@
|
|||
#ifdef BPPU_CPP
|
||||
|
||||
void bPPU::serialize(serializer &s) {
|
||||
PPU::serialize(s);
|
||||
|
||||
s.integer(region);
|
||||
s.integer(line);
|
||||
|
||||
s.integer(display.interlace);
|
||||
s.integer(display.overscan);
|
||||
|
||||
s.integer(cache.oam_basesize);
|
||||
s.integer(cache.oam_nameselect);
|
||||
s.integer(cache.oam_tdaddr);
|
||||
|
||||
s.integer(regs.ppu1_mdr);
|
||||
s.integer(regs.ppu2_mdr);
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_y[n]);
|
||||
|
||||
s.integer(regs.ioamaddr);
|
||||
s.integer(regs.icgramaddr);
|
||||
|
||||
s.integer(regs.display_disabled);
|
||||
s.integer(regs.display_brightness);
|
||||
|
||||
s.integer(regs.oam_basesize);
|
||||
s.integer(regs.oam_nameselect);
|
||||
s.integer(regs.oam_tdaddr);
|
||||
|
||||
s.integer(regs.oam_baseaddr);
|
||||
s.integer(regs.oam_addr);
|
||||
s.integer(regs.oam_priority);
|
||||
s.integer(regs.oam_firstsprite);
|
||||
|
||||
s.integer(regs.oam_latchdata);
|
||||
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_tilesize[n]);
|
||||
s.integer(regs.bg3_priority);
|
||||
s.integer(regs.bg_mode);
|
||||
|
||||
s.integer(regs.mosaic_size);
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.mosaic_enabled[n]);
|
||||
s.integer(regs.mosaic_countdown);
|
||||
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_scaddr[n]);
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_scsize[n]);
|
||||
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_tdaddr[n]);
|
||||
|
||||
s.integer(regs.bg_ofslatch);
|
||||
s.integer(regs.m7_hofs);
|
||||
s.integer(regs.m7_vofs);
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_hofs[n]);
|
||||
for(unsigned n = 0; n < 4; n++) s.integer(regs.bg_vofs[n]);
|
||||
|
||||
s.integer(regs.vram_incmode);
|
||||
s.integer(regs.vram_mapping);
|
||||
s.integer(regs.vram_incsize);
|
||||
|
||||
s.integer(regs.vram_addr);
|
||||
|
||||
s.integer(regs.mode7_repeat);
|
||||
s.integer(regs.mode7_vflip);
|
||||
s.integer(regs.mode7_hflip);
|
||||
|
||||
s.integer(regs.m7_latch);
|
||||
s.integer(regs.m7a);
|
||||
s.integer(regs.m7b);
|
||||
s.integer(regs.m7c);
|
||||
s.integer(regs.m7d);
|
||||
s.integer(regs.m7x);
|
||||
s.integer(regs.m7y);
|
||||
|
||||
s.integer(regs.cgram_addr);
|
||||
|
||||
s.integer(regs.cgram_latchdata);
|
||||
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.window1_enabled[n]);
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.window1_invert [n]);
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.window2_enabled[n]);
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.window2_invert [n]);
|
||||
|
||||
s.integer(regs.window1_left);
|
||||
s.integer(regs.window1_right);
|
||||
s.integer(regs.window2_left);
|
||||
s.integer(regs.window2_right);
|
||||
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.window_mask[n]);
|
||||
for(unsigned n = 0; n < 5; n++) s.integer(regs.bg_enabled[n]);
|
||||
for(unsigned n = 0; n < 5; n++) s.integer(regs.bgsub_enabled[n]);
|
||||
for(unsigned n = 0; n < 5; n++) s.integer(regs.window_enabled[n]);
|
||||
for(unsigned n = 0; n < 5; n++) s.integer(regs.sub_window_enabled[n]);
|
||||
|
||||
s.integer(regs.color_mask);
|
||||
s.integer(regs.colorsub_mask);
|
||||
s.integer(regs.addsub_mode);
|
||||
s.integer(regs.direct_color);
|
||||
|
||||
s.integer(regs.color_mode);
|
||||
s.integer(regs.color_halve);
|
||||
for(unsigned n = 0; n < 6; n++) s.integer(regs.color_enabled[n]);
|
||||
|
||||
s.integer(regs.color_r);
|
||||
s.integer(regs.color_g);
|
||||
s.integer(regs.color_b);
|
||||
s.integer(regs.color_rgb);
|
||||
|
||||
s.integer(regs.mode7_extbg);
|
||||
s.integer(regs.pseudo_hires);
|
||||
s.integer(regs.overscan);
|
||||
s.integer(regs.scanlines);
|
||||
s.integer(regs.oam_interlace);
|
||||
s.integer(regs.interlace);
|
||||
|
||||
s.integer(regs.hcounter);
|
||||
s.integer(regs.vcounter);
|
||||
s.integer(regs.latch_hcounter);
|
||||
s.integer(regs.latch_vcounter);
|
||||
s.integer(regs.counters_latched);
|
||||
|
||||
s.integer(regs.vram_readbuffer);
|
||||
|
||||
s.integer(regs.time_over);
|
||||
s.integer(regs.range_over);
|
||||
s.integer(regs.oam_itemcount);
|
||||
s.integer(regs.oam_tilecount);
|
||||
|
||||
for(unsigned n = 0; n < 256; n++) {
|
||||
s.integer(pixel_cache[n].src_main);
|
||||
s.integer(pixel_cache[n].src_sub);
|
||||
s.integer(pixel_cache[n].bg_main);
|
||||
s.integer(pixel_cache[n].bg_sub);
|
||||
s.integer(pixel_cache[n].ce_main);
|
||||
s.integer(pixel_cache[n].ce_sub);
|
||||
s.integer(pixel_cache[n].pri_main);
|
||||
s.integer(pixel_cache[n].pri_sub);
|
||||
}
|
||||
|
||||
//better to just take a small speed hit than store all of bg_tiledata[3][] ...
|
||||
flush_tiledata_cache();
|
||||
|
||||
for(unsigned n = 0; n < 6; n++) {
|
||||
s.array(window[n].main, 256);
|
||||
s.array(window[n].sub, 256);
|
||||
}
|
||||
|
||||
for(unsigned n = 0; n < 4; n++) {
|
||||
s.integer(bg_info[n].tw);
|
||||
s.integer(bg_info[n].th);
|
||||
s.integer(bg_info[n].mx);
|
||||
s.integer(bg_info[n].my);
|
||||
s.integer(bg_info[n].scx);
|
||||
s.integer(bg_info[n].scy);
|
||||
}
|
||||
|
||||
for(unsigned n = 0; n < 128; n++) {
|
||||
s.integer(sprite_list[n].width);
|
||||
s.integer(sprite_list[n].height);
|
||||
s.integer(sprite_list[n].x);
|
||||
s.integer(sprite_list[n].y);
|
||||
s.integer(sprite_list[n].character);
|
||||
s.integer(sprite_list[n].use_nameselect);
|
||||
s.integer(sprite_list[n].vflip);
|
||||
s.integer(sprite_list[n].hflip);
|
||||
s.integer(sprite_list[n].palette);
|
||||
s.integer(sprite_list[n].priority);
|
||||
}
|
||||
s.integer(sprite_list_valid);
|
||||
s.integer(active_sprite);
|
||||
|
||||
s.array(oam_itemlist, 32);
|
||||
|
||||
for(unsigned n = 0; n < 34; n++) {
|
||||
s.integer(oam_tilelist[n].x);
|
||||
s.integer(oam_tilelist[n].y);
|
||||
s.integer(oam_tilelist[n].pri);
|
||||
s.integer(oam_tilelist[n].pal);
|
||||
s.integer(oam_tilelist[n].tile);
|
||||
s.integer(oam_tilelist[n].hflip);
|
||||
}
|
||||
|
||||
s.array(oam_line_pal, 256);
|
||||
s.array(oam_line_pri, 256);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,49 @@
|
|||
//PPUCounter emulates the H/V latch counters of the S-PPU2.
|
||||
//
|
||||
//real hardware has the S-CPU maintain its own copy of these counters that are
|
||||
//updated based on the state of the S-PPU Vblank and Hblank pins. emulating this
|
||||
//would require full lock-step synchronization for every clock tick.
|
||||
//to bypass this and allow the two to run out-of-order, both the CPU and PPU
|
||||
//classes inherit PPUcounter and keep their own counters.
|
||||
//the timers are kept in sync, as the only differences occur on V=240 and V=261,
|
||||
//based on interlace. thus, we need only synchronize and fetch interlace at any
|
||||
//point before this in the frame, which is handled internally by this class at
|
||||
//V=128.
|
||||
|
||||
class PPUCounter {
|
||||
public:
|
||||
alwaysinline void tick();
|
||||
alwaysinline void tick(unsigned clocks);
|
||||
|
||||
alwaysinline bool field () const;
|
||||
alwaysinline uint16 vcounter() const;
|
||||
alwaysinline uint16 hcounter() const;
|
||||
inline uint16 hdot() const;
|
||||
inline uint16 lineclocks() const;
|
||||
|
||||
alwaysinline bool field (unsigned offset) const;
|
||||
alwaysinline uint16 vcounter(unsigned offset) const;
|
||||
alwaysinline uint16 hcounter(unsigned offset) const;
|
||||
|
||||
inline void reset();
|
||||
function<void ()> scanline;
|
||||
void serialize(serializer&);
|
||||
|
||||
private:
|
||||
inline void vcounter_tick();
|
||||
|
||||
struct {
|
||||
bool interlace;
|
||||
bool field;
|
||||
uint16 vcounter;
|
||||
uint16 hcounter;
|
||||
} status;
|
||||
|
||||
struct {
|
||||
bool field[2048];
|
||||
uint16 vcounter[2048];
|
||||
uint16 hcounter[2048];
|
||||
|
||||
int32 index;
|
||||
} history;
|
||||
};
|
|
@ -1,5 +1,7 @@
|
|||
#ifdef PPU_CPP
|
||||
|
||||
#include "render.cpp"
|
||||
|
||||
bool PPUDebugger::property(unsigned id, string &name, string &value) {
|
||||
unsigned n = 0;
|
||||
|
||||
|
@ -302,4 +304,289 @@ bool PPUDebugger::property(unsigned id, string &name, string &value) {
|
|||
return false;
|
||||
}
|
||||
|
||||
uint8 PPUDebugger::vram_mmio_read(uint16 addr) {
|
||||
uint8 data = PPU::vram_mmio_read(addr);
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::VRAM, Debugger::Breakpoint::Mode::Read, addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void PPUDebugger::vram_mmio_write(uint16 addr, uint8 data) {
|
||||
PPU::vram_mmio_write(addr, data);
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::VRAM, Debugger::Breakpoint::Mode::Write, addr, data);
|
||||
}
|
||||
|
||||
uint8 PPUDebugger::oam_mmio_read(uint16 addr) {
|
||||
uint8 data = PPU::oam_mmio_read(addr);
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::OAM, Debugger::Breakpoint::Mode::Read, addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void PPUDebugger::oam_mmio_write(uint16 addr, uint8 data) {
|
||||
PPU::oam_mmio_write(addr, data);
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::OAM, Debugger::Breakpoint::Mode::Write, addr, data);
|
||||
}
|
||||
|
||||
uint8 PPUDebugger::cgram_mmio_read(uint16 addr) {
|
||||
uint8 data = PPU::cgram_mmio_read(addr);
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CGRAM, Debugger::Breakpoint::Mode::Read, addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void PPUDebugger::cgram_mmio_write(uint16 addr, uint8 data) {
|
||||
PPU::cgram_mmio_write(addr, data);
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CGRAM, Debugger::Breakpoint::Mode::Write, addr, data);
|
||||
}
|
||||
|
||||
PPUDebugger::PPUDebugger() {
|
||||
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 PPUDebugger::ppu1_mdr() { return regs.ppu1_mdr; }
|
||||
unsigned PPUDebugger::ppu2_mdr() { return regs.ppu2_mdr; }
|
||||
|
||||
//$2100
|
||||
bool PPUDebugger::display_disable() { return regs.display_disabled; }
|
||||
unsigned PPUDebugger::display_brightness() { return regs.display_brightness; }
|
||||
|
||||
//$2101
|
||||
unsigned PPUDebugger::oam_base_size() { return regs.oam_basesize; }
|
||||
unsigned PPUDebugger::oam_name_select() { return regs.oam_nameselect; }
|
||||
unsigned PPUDebugger::oam_name_base_address() { return regs.oam_tdaddr; }
|
||||
|
||||
//$2102-$2103
|
||||
unsigned PPUDebugger::oam_base_address() { return regs.oam_baseaddr; }
|
||||
bool PPUDebugger::oam_priority() { return regs.oam_priority; }
|
||||
|
||||
//$2105
|
||||
bool PPUDebugger::bg1_tile_size() { return regs.bg_tilesize[BG1]; }
|
||||
bool PPUDebugger::bg2_tile_size() { return regs.bg_tilesize[BG2]; }
|
||||
bool PPUDebugger::bg3_tile_size() { return regs.bg_tilesize[BG3]; }
|
||||
bool PPUDebugger::bg4_tile_size() { return regs.bg_tilesize[BG4]; }
|
||||
bool PPUDebugger::bg3_priority() { return regs.bg3_priority; }
|
||||
unsigned PPUDebugger::bg_mode() { return regs.bg_mode; }
|
||||
|
||||
//$2106
|
||||
unsigned PPUDebugger::mosaic_size() { return regs.mosaic_size; }
|
||||
bool PPUDebugger::bg1_mosaic_enable() { return regs.mosaic_enabled[BG1]; }
|
||||
bool PPUDebugger::bg2_mosaic_enable() { return regs.mosaic_enabled[BG2]; }
|
||||
bool PPUDebugger::bg3_mosaic_enable() { return regs.mosaic_enabled[BG3]; }
|
||||
bool PPUDebugger::bg4_mosaic_enable() { return regs.mosaic_enabled[BG4]; }
|
||||
|
||||
//$2107
|
||||
unsigned PPUDebugger::bg1_screen_address() { return regs.bg_scaddr[BG1]; }
|
||||
unsigned PPUDebugger::bg1_screen_size() { return regs.bg_scsize[BG1]; }
|
||||
|
||||
//$2108
|
||||
unsigned PPUDebugger::bg2_screen_address() { return regs.bg_scaddr[BG2]; }
|
||||
unsigned PPUDebugger::bg2_screen_size() { return regs.bg_scsize[BG2]; }
|
||||
|
||||
//$2109
|
||||
unsigned PPUDebugger::bg3_screen_address() { return regs.bg_scaddr[BG3]; }
|
||||
unsigned PPUDebugger::bg3_screen_size() { return regs.bg_scsize[BG3]; }
|
||||
|
||||
//$210a
|
||||
unsigned PPUDebugger::bg4_screen_address() { return regs.bg_scaddr[BG4]; }
|
||||
unsigned PPUDebugger::bg4_screen_size() { return regs.bg_scsize[BG4]; }
|
||||
|
||||
//$210b
|
||||
unsigned PPUDebugger::bg1_name_base_address() { return regs.bg_tdaddr[BG1]; }
|
||||
unsigned PPUDebugger::bg2_name_base_address() { return regs.bg_tdaddr[BG2]; }
|
||||
|
||||
//$210c
|
||||
unsigned PPUDebugger::bg3_name_base_address() { return regs.bg_tdaddr[BG3]; }
|
||||
unsigned PPUDebugger::bg4_name_base_address() { return regs.bg_tdaddr[BG4]; }
|
||||
|
||||
//$210d
|
||||
unsigned PPUDebugger::mode7_hoffset() { return regs.m7_hofs & 0x1fff; }
|
||||
unsigned PPUDebugger::bg1_hoffset() { return regs.bg_hofs[BG1] & 0x03ff; }
|
||||
|
||||
//$210e
|
||||
unsigned PPUDebugger::mode7_voffset() { return regs.m7_vofs & 0x1fff; }
|
||||
unsigned PPUDebugger::bg1_voffset() { return regs.bg_vofs[BG1] & 0x03ff; }
|
||||
|
||||
//$210f
|
||||
unsigned PPUDebugger::bg2_hoffset() { return regs.bg_hofs[BG2] & 0x03ff; }
|
||||
|
||||
//$2110
|
||||
unsigned PPUDebugger::bg2_voffset() { return regs.bg_vofs[BG2] & 0x03ff; }
|
||||
|
||||
//$2111
|
||||
unsigned PPUDebugger::bg3_hoffset() { return regs.bg_hofs[BG3] & 0x03ff; }
|
||||
|
||||
//$2112
|
||||
unsigned PPUDebugger::bg3_voffset() { return regs.bg_vofs[BG3] & 0x03ff; }
|
||||
|
||||
//$2113
|
||||
unsigned PPUDebugger::bg4_hoffset() { return regs.bg_hofs[BG4] & 0x03ff; }
|
||||
|
||||
//$2114
|
||||
unsigned PPUDebugger::bg4_voffset() { return regs.bg_vofs[BG4] & 0x03ff; }
|
||||
|
||||
//$2115
|
||||
bool PPUDebugger::vram_increment_mode() { return regs.vram_incmode; }
|
||||
unsigned PPUDebugger::vram_increment_formation() { return regs.vram_mapping; }
|
||||
unsigned PPUDebugger::vram_increment_size() { return regs.vram_incsize; }
|
||||
|
||||
//$2116-$2117
|
||||
unsigned PPUDebugger::vram_address() { return regs.vram_addr; }
|
||||
|
||||
//$211a
|
||||
unsigned PPUDebugger::mode7_repeat() { return regs.mode7_repeat; }
|
||||
bool PPUDebugger::mode7_vflip() { return regs.mode7_vflip; }
|
||||
bool PPUDebugger::mode7_hflip() { return regs.mode7_hflip; }
|
||||
|
||||
//$211b
|
||||
unsigned PPUDebugger::mode7_a() { return regs.m7a; }
|
||||
|
||||
//$211c
|
||||
unsigned PPUDebugger::mode7_b() { return regs.m7b; }
|
||||
|
||||
//$211d
|
||||
unsigned PPUDebugger::mode7_c() { return regs.m7c; }
|
||||
|
||||
//$211e
|
||||
unsigned PPUDebugger::mode7_d() { return regs.m7d; }
|
||||
|
||||
//$211f
|
||||
unsigned PPUDebugger::mode7_x() { return regs.m7x; }
|
||||
|
||||
//$2120
|
||||
unsigned PPUDebugger::mode7_y() { return regs.m7y; }
|
||||
|
||||
//$2121
|
||||
unsigned PPUDebugger::cgram_address() { return regs.cgram_addr; }
|
||||
|
||||
//$2123
|
||||
bool PPUDebugger::bg1_window1_enable() { return regs.window1_enabled[BG1]; }
|
||||
bool PPUDebugger::bg1_window1_invert() { return regs.window1_invert [BG1]; }
|
||||
bool PPUDebugger::bg1_window2_enable() { return regs.window2_enabled[BG1]; }
|
||||
bool PPUDebugger::bg1_window2_invert() { return regs.window2_invert [BG1]; }
|
||||
bool PPUDebugger::bg2_window1_enable() { return regs.window1_enabled[BG2]; }
|
||||
bool PPUDebugger::bg2_window1_invert() { return regs.window1_invert [BG2]; }
|
||||
bool PPUDebugger::bg2_window2_enable() { return regs.window2_enabled[BG2]; }
|
||||
bool PPUDebugger::bg2_window2_invert() { return regs.window2_invert [BG2]; }
|
||||
|
||||
//$2124
|
||||
bool PPUDebugger::bg3_window1_enable() { return regs.window1_enabled[BG3]; }
|
||||
bool PPUDebugger::bg3_window1_invert() { return regs.window1_invert [BG3]; }
|
||||
bool PPUDebugger::bg3_window2_enable() { return regs.window2_enabled[BG3]; }
|
||||
bool PPUDebugger::bg3_window2_invert() { return regs.window2_invert [BG3]; }
|
||||
bool PPUDebugger::bg4_window1_enable() { return regs.window1_enabled[BG4]; }
|
||||
bool PPUDebugger::bg4_window1_invert() { return regs.window1_invert [BG4]; }
|
||||
bool PPUDebugger::bg4_window2_enable() { return regs.window2_enabled[BG4]; }
|
||||
bool PPUDebugger::bg4_window2_invert() { return regs.window2_invert [BG4]; }
|
||||
|
||||
//$2125
|
||||
bool PPUDebugger::oam_window1_enable() { return regs.window1_enabled[OAM]; }
|
||||
bool PPUDebugger::oam_window1_invert() { return regs.window1_invert [OAM]; }
|
||||
bool PPUDebugger::oam_window2_enable() { return regs.window2_enabled[OAM]; }
|
||||
bool PPUDebugger::oam_window2_invert() { return regs.window2_invert [OAM]; }
|
||||
bool PPUDebugger::color_window1_enable() { return regs.window1_enabled[COL]; }
|
||||
bool PPUDebugger::color_window1_invert() { return regs.window1_invert [COL]; }
|
||||
bool PPUDebugger::color_window2_enable() { return regs.window2_enabled[COL]; }
|
||||
bool PPUDebugger::color_window2_invert() { return regs.window2_enabled[COL]; }
|
||||
|
||||
//$2126
|
||||
unsigned PPUDebugger::window1_left() { return regs.window1_left; }
|
||||
|
||||
//$2127
|
||||
unsigned PPUDebugger::window1_right() { return regs.window1_right; }
|
||||
|
||||
//$2128
|
||||
unsigned PPUDebugger::window2_left() { return regs.window2_left; }
|
||||
|
||||
//$2129
|
||||
unsigned PPUDebugger::window2_right() { return regs.window2_right; }
|
||||
|
||||
//$212a
|
||||
unsigned PPUDebugger::bg1_window_mask() { return regs.window_mask[BG1]; }
|
||||
unsigned PPUDebugger::bg2_window_mask() { return regs.window_mask[BG2]; }
|
||||
unsigned PPUDebugger::bg3_window_mask() { return regs.window_mask[BG3]; }
|
||||
unsigned PPUDebugger::bg4_window_mask() { return regs.window_mask[BG4]; }
|
||||
|
||||
//$212b
|
||||
unsigned PPUDebugger::oam_window_mask() { return regs.window_mask[OAM]; }
|
||||
unsigned PPUDebugger::color_window_mask() { return regs.window_mask[COL]; }
|
||||
|
||||
//$212c
|
||||
bool PPUDebugger::bg1_mainscreen_enable() { return regs.bg_enabled[BG1]; }
|
||||
bool PPUDebugger::bg2_mainscreen_enable() { return regs.bg_enabled[BG2]; }
|
||||
bool PPUDebugger::bg3_mainscreen_enable() { return regs.bg_enabled[BG3]; }
|
||||
bool PPUDebugger::bg4_mainscreen_enable() { return regs.bg_enabled[BG4]; }
|
||||
bool PPUDebugger::oam_mainscreen_enable() { return regs.bg_enabled[OAM]; }
|
||||
|
||||
//$212d
|
||||
bool PPUDebugger::bg1_subscreen_enable() { return regs.bgsub_enabled[BG1]; }
|
||||
bool PPUDebugger::bg2_subscreen_enable() { return regs.bgsub_enabled[BG2]; }
|
||||
bool PPUDebugger::bg3_subscreen_enable() { return regs.bgsub_enabled[BG3]; }
|
||||
bool PPUDebugger::bg4_subscreen_enable() { return regs.bgsub_enabled[BG4]; }
|
||||
bool PPUDebugger::oam_subscreen_enable() { return regs.bgsub_enabled[OAM]; }
|
||||
|
||||
//$212e
|
||||
bool PPUDebugger::bg1_mainscreen_window_enable() { return regs.window_enabled[BG1]; }
|
||||
bool PPUDebugger::bg2_mainscreen_window_enable() { return regs.window_enabled[BG2]; }
|
||||
bool PPUDebugger::bg3_mainscreen_window_enable() { return regs.window_enabled[BG3]; }
|
||||
bool PPUDebugger::bg4_mainscreen_window_enable() { return regs.window_enabled[BG4]; }
|
||||
bool PPUDebugger::oam_mainscreen_window_enable() { return regs.window_enabled[OAM]; }
|
||||
|
||||
//$212f
|
||||
bool PPUDebugger::bg1_subscreen_window_enable() { return regs.sub_window_enabled[BG1]; }
|
||||
bool PPUDebugger::bg2_subscreen_window_enable() { return regs.sub_window_enabled[BG2]; }
|
||||
bool PPUDebugger::bg3_subscreen_window_enable() { return regs.sub_window_enabled[BG3]; }
|
||||
bool PPUDebugger::bg4_subscreen_window_enable() { return regs.sub_window_enabled[BG4]; }
|
||||
bool PPUDebugger::oam_subscreen_window_enable() { return regs.sub_window_enabled[OAM]; }
|
||||
|
||||
//$2130
|
||||
unsigned PPUDebugger::color_mainscreen_window_mask() { return regs.color_mask; }
|
||||
unsigned PPUDebugger::color_subscreen_window_mask() { return regs.colorsub_mask; }
|
||||
bool PPUDebugger::color_add_subtract_mode() { return regs.addsub_mode; }
|
||||
bool PPUDebugger::direct_color() { return regs.direct_color; }
|
||||
|
||||
//$2131
|
||||
bool PPUDebugger::color_mode() { return regs.color_mode; }
|
||||
bool PPUDebugger::color_halve() { return regs.color_halve; }
|
||||
bool PPUDebugger::bg1_color_enable() { return regs.color_enabled[BG1]; }
|
||||
bool PPUDebugger::bg2_color_enable() { return regs.color_enabled[BG2]; }
|
||||
bool PPUDebugger::bg3_color_enable() { return regs.color_enabled[BG3]; }
|
||||
bool PPUDebugger::bg4_color_enable() { return regs.color_enabled[BG4]; }
|
||||
bool PPUDebugger::oam_color_enable() { return regs.color_enabled[OAM]; }
|
||||
bool PPUDebugger::back_color_enable() { return regs.color_enabled[BACK]; }
|
||||
|
||||
//$2132
|
||||
unsigned PPUDebugger::color_constant_blue() { return regs.color_b; }
|
||||
unsigned PPUDebugger::color_constant_green() { return regs.color_g; }
|
||||
unsigned PPUDebugger::color_constant_red() { return regs.color_r; }
|
||||
|
||||
//$2133
|
||||
bool PPUDebugger::mode7_extbg() { return regs.mode7_extbg; }
|
||||
bool PPUDebugger::pseudo_hires() { return regs.pseudo_hires; }
|
||||
bool PPUDebugger::overscan_enable() { return regs.overscan; }
|
||||
bool PPUDebugger::oam_interlace() { return regs.oam_interlace; }
|
||||
bool PPUDebugger::interlace_enable() { return regs.interlace; }
|
||||
|
||||
//$213c
|
||||
unsigned PPUDebugger::hcounter() { return PPU::hcounter(); }
|
||||
|
||||
//$213d
|
||||
unsigned PPUDebugger::vcounter() { return PPU::vcounter(); }
|
||||
|
||||
//$213e
|
||||
bool PPUDebugger::range_over() { return regs.range_over; }
|
||||
bool PPUDebugger::time_over() { return regs.time_over; }
|
||||
unsigned PPUDebugger::ppu1_version() { return PPU::ppu1_version; }
|
||||
|
||||
//$213f
|
||||
bool PPUDebugger::field() { return cpu.field(); }
|
||||
bool PPUDebugger::region() { return PPU::region; }
|
||||
unsigned PPUDebugger::ppu2_version() { return PPU::ppu2_version; }
|
||||
|
||||
#endif
|
|
@ -1,5 +1,7 @@
|
|||
class bPPUDebugger : public bPPU, public PPUDebugger {
|
||||
class PPUDebugger : public PPU, public ChipDebugger {
|
||||
public:
|
||||
bool property(unsigned id, string &name, string &value);
|
||||
|
||||
bool bg1_enabled[2];
|
||||
bool bg2_enabled[2];
|
||||
bool bg3_enabled[2];
|
||||
|
@ -24,7 +26,7 @@ public:
|
|||
void render_line_mode6();
|
||||
void render_line_mode7();
|
||||
|
||||
bPPUDebugger();
|
||||
PPUDebugger();
|
||||
|
||||
//===========
|
||||
//PPUDebugger
|
|
@ -1,4 +1,4 @@
|
|||
#ifdef BPPU_CPP
|
||||
#ifdef PPU_CPP
|
||||
|
||||
//render_line_modeN() taken from src/ppu/bppu/render/render.cpp
|
||||
//modified to support layer disable; accomplished by setting priority to zero
|
||||
|
@ -7,187 +7,187 @@
|
|||
//
|
||||
//note: render_line_(bg|oam|mode7) cannot be virtualized as they are templates
|
||||
|
||||
void bPPUDebugger::render_line_mode0() {
|
||||
void PPUDebugger::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1 | pri2 | pri3) PPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
|
||||
void bPPUDebugger::render_line_mode1() {
|
||||
void PPUDebugger::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1 | pri2 | pri3) PPU::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
PPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
}
|
||||
|
||||
void bPPUDebugger::render_line_mode2() {
|
||||
void PPUDebugger::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1 | pri2 | pri3) PPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
|
||||
void bPPUDebugger::render_line_mode3() {
|
||||
void PPUDebugger::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1 | pri2 | pri3) PPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
|
||||
void bPPUDebugger::render_line_mode4() {
|
||||
void PPUDebugger::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1 | pri2 | pri3) PPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
|
||||
void bPPUDebugger::render_line_mode5() {
|
||||
void PPUDebugger::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1 | pri2 | pri3) PPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
|
||||
void bPPUDebugger::render_line_mode6() {
|
||||
void PPUDebugger::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1 | pri2 | pri3) PPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
|
||||
void bPPUDebugger::render_line_mode7() {
|
||||
void PPUDebugger::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1 | pri2 | pri3) PPU::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
if(pri0 | pri1) PPU::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);
|
||||
PPU::render_line_oam(pri0, pri1, pri2, pri3);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
#ifdef BPPU_CPP
|
||||
#ifdef PPU_CPP
|
||||
|
||||
void bPPU::latch_counters() {
|
||||
void PPU::latch_counters() {
|
||||
regs.hcounter = cpu.hdot();
|
||||
regs.vcounter = cpu.vcounter();
|
||||
regs.counters_latched = true;
|
||||
}
|
||||
|
||||
uint16 bPPU::get_vram_address() {
|
||||
uint16 PPU::get_vram_address() {
|
||||
uint16 addr = regs.vram_addr;
|
||||
switch(regs.vram_mapping) {
|
||||
case 0: break; //direct mapping
|
||||
|
@ -22,7 +22,7 @@ uint16 bPPU::get_vram_address() {
|
|||
//been validated on hardware, as has the edge case where the S-CPU MDR can be written if the
|
||||
//write occurs during the very last clock cycle of vblank.
|
||||
|
||||
uint8 bPPU::vram_mmio_read(uint16 addr) {
|
||||
uint8 PPU::vram_mmio_read(uint16 addr) {
|
||||
uint8 data;
|
||||
|
||||
if(regs.display_disabled == true) {
|
||||
|
@ -51,7 +51,7 @@ uint8 bPPU::vram_mmio_read(uint16 addr) {
|
|||
return data;
|
||||
}
|
||||
|
||||
void bPPU::vram_mmio_write(uint16 addr, uint8 data) {
|
||||
void PPU::vram_mmio_write(uint16 addr, uint8 data) {
|
||||
if(regs.display_disabled == true) {
|
||||
memory::vram[addr] = data;
|
||||
} else {
|
||||
|
@ -79,7 +79,7 @@ void bPPU::vram_mmio_write(uint16 addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
uint8 bPPU::oam_mmio_read(uint16 addr) {
|
||||
uint8 PPU::oam_mmio_read(uint16 addr) {
|
||||
addr &= 0x03ff;
|
||||
if(addr & 0x0200) addr &= 0x021f;
|
||||
uint8 data;
|
||||
|
@ -97,7 +97,7 @@ uint8 bPPU::oam_mmio_read(uint16 addr) {
|
|||
return data;
|
||||
}
|
||||
|
||||
void bPPU::oam_mmio_write(uint16 addr, uint8 data) {
|
||||
void PPU::oam_mmio_write(uint16 addr, uint8 data) {
|
||||
addr &= 0x03ff;
|
||||
if(addr & 0x0200) addr &= 0x021f;
|
||||
|
||||
|
@ -114,7 +114,7 @@ void bPPU::oam_mmio_write(uint16 addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
uint8 bPPU::cgram_mmio_read(uint16 addr) {
|
||||
uint8 PPU::cgram_mmio_read(uint16 addr) {
|
||||
addr &= 0x01ff;
|
||||
uint8 data;
|
||||
|
||||
|
@ -134,7 +134,7 @@ uint8 bPPU::cgram_mmio_read(uint16 addr) {
|
|||
return data;
|
||||
}
|
||||
|
||||
void bPPU::cgram_mmio_write(uint16 addr, uint8 data) {
|
||||
void PPU::cgram_mmio_write(uint16 addr, uint8 data) {
|
||||
addr &= 0x01ff;
|
||||
if(addr & 1) data &= 0x7f;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef BPPU_CPP
|
||||
#ifdef PPU_CPP
|
||||
|
||||
//INIDISP
|
||||
void bPPU::mmio_w2100(uint8 value) {
|
||||
void PPU::mmio_w2100(uint8 value) {
|
||||
if(regs.display_disabled == true && cpu.vcounter() == (!overscan() ? 225 : 240)) {
|
||||
regs.oam_addr = regs.oam_baseaddr << 1;
|
||||
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
||||
|
@ -12,14 +12,14 @@ void bPPU::mmio_w2100(uint8 value) {
|
|||
}
|
||||
|
||||
//OBSEL
|
||||
void bPPU::mmio_w2101(uint8 value) {
|
||||
void PPU::mmio_w2101(uint8 value) {
|
||||
regs.oam_basesize = (value >> 5) & 7;
|
||||
regs.oam_nameselect = (value >> 3) & 3;
|
||||
regs.oam_tdaddr = (value & 3) << 14;
|
||||
}
|
||||
|
||||
//OAMADDL
|
||||
void bPPU::mmio_w2102(uint8 data) {
|
||||
void PPU::mmio_w2102(uint8 data) {
|
||||
regs.oam_baseaddr = (regs.oam_baseaddr & ~0xff) | (data << 0);
|
||||
regs.oam_baseaddr &= 0x01ff;
|
||||
regs.oam_addr = regs.oam_baseaddr << 1;
|
||||
|
@ -27,7 +27,7 @@ void bPPU::mmio_w2102(uint8 data) {
|
|||
}
|
||||
|
||||
//OAMADDH
|
||||
void bPPU::mmio_w2103(uint8 data) {
|
||||
void PPU::mmio_w2103(uint8 data) {
|
||||
regs.oam_priority = !!(data & 0x80);
|
||||
regs.oam_baseaddr = (regs.oam_baseaddr & 0xff) | (data << 8);
|
||||
regs.oam_baseaddr &= 0x01ff;
|
||||
|
@ -36,7 +36,7 @@ void bPPU::mmio_w2103(uint8 data) {
|
|||
}
|
||||
|
||||
//OAMDATA
|
||||
void bPPU::mmio_w2104(uint8 data) {
|
||||
void PPU::mmio_w2104(uint8 data) {
|
||||
if(regs.oam_addr & 0x0200) {
|
||||
oam_mmio_write(regs.oam_addr, data);
|
||||
} else if((regs.oam_addr & 1) == 0) {
|
||||
|
@ -52,7 +52,7 @@ void bPPU::mmio_w2104(uint8 data) {
|
|||
}
|
||||
|
||||
//BGMODE
|
||||
void bPPU::mmio_w2105(uint8 value) {
|
||||
void PPU::mmio_w2105(uint8 value) {
|
||||
regs.bg_tilesize[BG4] = !!(value & 0x80);
|
||||
regs.bg_tilesize[BG3] = !!(value & 0x40);
|
||||
regs.bg_tilesize[BG2] = !!(value & 0x20);
|
||||
|
@ -62,7 +62,7 @@ void bPPU::mmio_w2105(uint8 value) {
|
|||
}
|
||||
|
||||
//MOSAIC
|
||||
void bPPU::mmio_w2106(uint8 value) {
|
||||
void PPU::mmio_w2106(uint8 value) {
|
||||
regs.mosaic_size = (value >> 4) & 15;
|
||||
regs.mosaic_enabled[BG4] = !!(value & 0x08);
|
||||
regs.mosaic_enabled[BG3] = !!(value & 0x04);
|
||||
|
@ -71,43 +71,43 @@ void bPPU::mmio_w2106(uint8 value) {
|
|||
}
|
||||
|
||||
//BG1SC
|
||||
void bPPU::mmio_w2107(uint8 value) {
|
||||
void PPU::mmio_w2107(uint8 value) {
|
||||
regs.bg_scaddr[BG1] = (value & 0x7c) << 9;
|
||||
regs.bg_scsize[BG1] = value & 3;
|
||||
}
|
||||
|
||||
//BG2SC
|
||||
void bPPU::mmio_w2108(uint8 value) {
|
||||
void PPU::mmio_w2108(uint8 value) {
|
||||
regs.bg_scaddr[BG2] = (value & 0x7c) << 9;
|
||||
regs.bg_scsize[BG2] = value & 3;
|
||||
}
|
||||
|
||||
//BG3SC
|
||||
void bPPU::mmio_w2109(uint8 value) {
|
||||
void PPU::mmio_w2109(uint8 value) {
|
||||
regs.bg_scaddr[BG3] = (value & 0x7c) << 9;
|
||||
regs.bg_scsize[BG3] = value & 3;
|
||||
}
|
||||
|
||||
//BG4SC
|
||||
void bPPU::mmio_w210a(uint8 value) {
|
||||
void PPU::mmio_w210a(uint8 value) {
|
||||
regs.bg_scaddr[BG4] = (value & 0x7c) << 9;
|
||||
regs.bg_scsize[BG4] = value & 3;
|
||||
}
|
||||
|
||||
//BG12NBA
|
||||
void bPPU::mmio_w210b(uint8 value) {
|
||||
void PPU::mmio_w210b(uint8 value) {
|
||||
regs.bg_tdaddr[BG1] = (value & 0x07) << 13;
|
||||
regs.bg_tdaddr[BG2] = (value & 0x70) << 9;
|
||||
}
|
||||
|
||||
//BG34NBA
|
||||
void bPPU::mmio_w210c(uint8 value) {
|
||||
void PPU::mmio_w210c(uint8 value) {
|
||||
regs.bg_tdaddr[BG3] = (value & 0x07) << 13;
|
||||
regs.bg_tdaddr[BG4] = (value & 0x70) << 9;
|
||||
}
|
||||
|
||||
//BG1HOFS
|
||||
void bPPU::mmio_w210d(uint8 value) {
|
||||
void PPU::mmio_w210d(uint8 value) {
|
||||
regs.m7_hofs = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
|
||||
|
@ -116,7 +116,7 @@ void bPPU::mmio_w210d(uint8 value) {
|
|||
}
|
||||
|
||||
//BG1VOFS
|
||||
void bPPU::mmio_w210e(uint8 value) {
|
||||
void PPU::mmio_w210e(uint8 value) {
|
||||
regs.m7_vofs = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
|
||||
|
@ -125,43 +125,43 @@ void bPPU::mmio_w210e(uint8 value) {
|
|||
}
|
||||
|
||||
//BG2HOFS
|
||||
void bPPU::mmio_w210f(uint8 value) {
|
||||
void PPU::mmio_w210f(uint8 value) {
|
||||
regs.bg_hofs[BG2] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG2] >> 8) & 7);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG2VOFS
|
||||
void bPPU::mmio_w2110(uint8 value) {
|
||||
void PPU::mmio_w2110(uint8 value) {
|
||||
regs.bg_vofs[BG2] = (value << 8) | (regs.bg_ofslatch);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG3HOFS
|
||||
void bPPU::mmio_w2111(uint8 value) {
|
||||
void PPU::mmio_w2111(uint8 value) {
|
||||
regs.bg_hofs[BG3] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG3] >> 8) & 7);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG3VOFS
|
||||
void bPPU::mmio_w2112(uint8 value) {
|
||||
void PPU::mmio_w2112(uint8 value) {
|
||||
regs.bg_vofs[BG3] = (value << 8) | (regs.bg_ofslatch);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG4HOFS
|
||||
void bPPU::mmio_w2113(uint8 value) {
|
||||
void PPU::mmio_w2113(uint8 value) {
|
||||
regs.bg_hofs[BG4] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG4] >> 8) & 7);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//BG4VOFS
|
||||
void bPPU::mmio_w2114(uint8 value) {
|
||||
void PPU::mmio_w2114(uint8 value) {
|
||||
regs.bg_vofs[BG4] = (value << 8) | (regs.bg_ofslatch);
|
||||
regs.bg_ofslatch = value;
|
||||
}
|
||||
|
||||
//VMAIN
|
||||
void bPPU::mmio_w2115(uint8 value) {
|
||||
void PPU::mmio_w2115(uint8 value) {
|
||||
regs.vram_incmode = !!(value & 0x80);
|
||||
regs.vram_mapping = (value >> 2) & 3;
|
||||
switch(value & 3) {
|
||||
|
@ -173,7 +173,7 @@ void bPPU::mmio_w2115(uint8 value) {
|
|||
}
|
||||
|
||||
//VMADDL
|
||||
void bPPU::mmio_w2116(uint8 value) {
|
||||
void PPU::mmio_w2116(uint8 value) {
|
||||
regs.vram_addr = (regs.vram_addr & 0xff00) | value;
|
||||
uint16 addr = get_vram_address();
|
||||
regs.vram_readbuffer = vram_mmio_read(addr + 0);
|
||||
|
@ -181,7 +181,7 @@ void bPPU::mmio_w2116(uint8 value) {
|
|||
}
|
||||
|
||||
//VMADDH
|
||||
void bPPU::mmio_w2117(uint8 value) {
|
||||
void PPU::mmio_w2117(uint8 value) {
|
||||
regs.vram_addr = (value << 8) | (regs.vram_addr & 0x00ff);
|
||||
uint16 addr = get_vram_address();
|
||||
regs.vram_readbuffer = vram_mmio_read(addr + 0);
|
||||
|
@ -189,7 +189,7 @@ void bPPU::mmio_w2117(uint8 value) {
|
|||
}
|
||||
|
||||
//VMDATAL
|
||||
void bPPU::mmio_w2118(uint8 value) {
|
||||
void PPU::mmio_w2118(uint8 value) {
|
||||
uint16 addr = get_vram_address();
|
||||
vram_mmio_write(addr, value);
|
||||
bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
|
||||
|
@ -202,7 +202,7 @@ uint16 addr = get_vram_address();
|
|||
}
|
||||
|
||||
//VMDATAH
|
||||
void bPPU::mmio_w2119(uint8 value) {
|
||||
void PPU::mmio_w2119(uint8 value) {
|
||||
uint16 addr = get_vram_address() + 1;
|
||||
vram_mmio_write(addr, value);
|
||||
bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
|
||||
|
@ -215,50 +215,50 @@ uint16 addr = get_vram_address() + 1;
|
|||
}
|
||||
|
||||
//M7SEL
|
||||
void bPPU::mmio_w211a(uint8 value) {
|
||||
void PPU::mmio_w211a(uint8 value) {
|
||||
regs.mode7_repeat = (value >> 6) & 3;
|
||||
regs.mode7_vflip = !!(value & 0x02);
|
||||
regs.mode7_hflip = !!(value & 0x01);
|
||||
}
|
||||
|
||||
//M7A
|
||||
void bPPU::mmio_w211b(uint8 value) {
|
||||
void PPU::mmio_w211b(uint8 value) {
|
||||
regs.m7a = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//M7B
|
||||
void bPPU::mmio_w211c(uint8 value) {
|
||||
void PPU::mmio_w211c(uint8 value) {
|
||||
regs.m7b = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//M7C
|
||||
void bPPU::mmio_w211d(uint8 value) {
|
||||
void PPU::mmio_w211d(uint8 value) {
|
||||
regs.m7c = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//M7D
|
||||
void bPPU::mmio_w211e(uint8 value) {
|
||||
void PPU::mmio_w211e(uint8 value) {
|
||||
regs.m7d = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//M7X
|
||||
void bPPU::mmio_w211f(uint8 value) {
|
||||
void PPU::mmio_w211f(uint8 value) {
|
||||
regs.m7x = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//M7Y
|
||||
void bPPU::mmio_w2120(uint8 value) {
|
||||
void PPU::mmio_w2120(uint8 value) {
|
||||
regs.m7y = (value << 8) | regs.m7_latch;
|
||||
regs.m7_latch = value;
|
||||
}
|
||||
|
||||
//CGADD
|
||||
void bPPU::mmio_w2121(uint8 value) {
|
||||
void PPU::mmio_w2121(uint8 value) {
|
||||
regs.cgram_addr = value << 1;
|
||||
}
|
||||
|
||||
|
@ -270,7 +270,7 @@ void bPPU::mmio_w2121(uint8 value) {
|
|||
//anomie indicates writes to CGDATA work the same
|
||||
//as writes to OAMDATA's low table. need to verify
|
||||
//this on hardware.
|
||||
void bPPU::mmio_w2122(uint8 value) {
|
||||
void PPU::mmio_w2122(uint8 value) {
|
||||
if(!(regs.cgram_addr & 1)) {
|
||||
regs.cgram_latchdata = value;
|
||||
} else {
|
||||
|
@ -282,7 +282,7 @@ void bPPU::mmio_w2122(uint8 value) {
|
|||
}
|
||||
|
||||
//W12SEL
|
||||
void bPPU::mmio_w2123(uint8 value) {
|
||||
void PPU::mmio_w2123(uint8 value) {
|
||||
regs.window2_enabled[BG2] = !!(value & 0x80);
|
||||
regs.window2_invert [BG2] = !!(value & 0x40);
|
||||
regs.window1_enabled[BG2] = !!(value & 0x20);
|
||||
|
@ -294,7 +294,7 @@ void bPPU::mmio_w2123(uint8 value) {
|
|||
}
|
||||
|
||||
//W34SEL
|
||||
void bPPU::mmio_w2124(uint8 value) {
|
||||
void PPU::mmio_w2124(uint8 value) {
|
||||
regs.window2_enabled[BG4] = !!(value & 0x80);
|
||||
regs.window2_invert [BG4] = !!(value & 0x40);
|
||||
regs.window1_enabled[BG4] = !!(value & 0x20);
|
||||
|
@ -306,7 +306,7 @@ void bPPU::mmio_w2124(uint8 value) {
|
|||
}
|
||||
|
||||
//WOBJSEL
|
||||
void bPPU::mmio_w2125(uint8 value) {
|
||||
void PPU::mmio_w2125(uint8 value) {
|
||||
regs.window2_enabled[COL] = !!(value & 0x80);
|
||||
regs.window2_invert [COL] = !!(value & 0x40);
|
||||
regs.window1_enabled[COL] = !!(value & 0x20);
|
||||
|
@ -318,27 +318,27 @@ void bPPU::mmio_w2125(uint8 value) {
|
|||
}
|
||||
|
||||
//WH0
|
||||
void bPPU::mmio_w2126(uint8 value) {
|
||||
void PPU::mmio_w2126(uint8 value) {
|
||||
regs.window1_left = value;
|
||||
}
|
||||
|
||||
//WH1
|
||||
void bPPU::mmio_w2127(uint8 value) {
|
||||
void PPU::mmio_w2127(uint8 value) {
|
||||
regs.window1_right = value;
|
||||
}
|
||||
|
||||
//WH2
|
||||
void bPPU::mmio_w2128(uint8 value) {
|
||||
void PPU::mmio_w2128(uint8 value) {
|
||||
regs.window2_left = value;
|
||||
}
|
||||
|
||||
//WH3
|
||||
void bPPU::mmio_w2129(uint8 value) {
|
||||
void PPU::mmio_w2129(uint8 value) {
|
||||
regs.window2_right = value;
|
||||
}
|
||||
|
||||
//WBGLOG
|
||||
void bPPU::mmio_w212a(uint8 value) {
|
||||
void PPU::mmio_w212a(uint8 value) {
|
||||
regs.window_mask[BG4] = (value >> 6) & 3;
|
||||
regs.window_mask[BG3] = (value >> 4) & 3;
|
||||
regs.window_mask[BG2] = (value >> 2) & 3;
|
||||
|
@ -346,13 +346,13 @@ void bPPU::mmio_w212a(uint8 value) {
|
|||
}
|
||||
|
||||
//WOBJLOG
|
||||
void bPPU::mmio_w212b(uint8 value) {
|
||||
void PPU::mmio_w212b(uint8 value) {
|
||||
regs.window_mask[COL] = (value >> 2) & 3;
|
||||
regs.window_mask[OAM] = (value ) & 3;
|
||||
}
|
||||
|
||||
//TM
|
||||
void bPPU::mmio_w212c(uint8 value) {
|
||||
void PPU::mmio_w212c(uint8 value) {
|
||||
regs.bg_enabled[OAM] = !!(value & 0x10);
|
||||
regs.bg_enabled[BG4] = !!(value & 0x08);
|
||||
regs.bg_enabled[BG3] = !!(value & 0x04);
|
||||
|
@ -361,7 +361,7 @@ void bPPU::mmio_w212c(uint8 value) {
|
|||
}
|
||||
|
||||
//TS
|
||||
void bPPU::mmio_w212d(uint8 value) {
|
||||
void PPU::mmio_w212d(uint8 value) {
|
||||
regs.bgsub_enabled[OAM] = !!(value & 0x10);
|
||||
regs.bgsub_enabled[BG4] = !!(value & 0x08);
|
||||
regs.bgsub_enabled[BG3] = !!(value & 0x04);
|
||||
|
@ -370,7 +370,7 @@ void bPPU::mmio_w212d(uint8 value) {
|
|||
}
|
||||
|
||||
//TMW
|
||||
void bPPU::mmio_w212e(uint8 value) {
|
||||
void PPU::mmio_w212e(uint8 value) {
|
||||
regs.window_enabled[OAM] = !!(value & 0x10);
|
||||
regs.window_enabled[BG4] = !!(value & 0x08);
|
||||
regs.window_enabled[BG3] = !!(value & 0x04);
|
||||
|
@ -379,7 +379,7 @@ void bPPU::mmio_w212e(uint8 value) {
|
|||
}
|
||||
|
||||
//TSW
|
||||
void bPPU::mmio_w212f(uint8 value) {
|
||||
void PPU::mmio_w212f(uint8 value) {
|
||||
regs.sub_window_enabled[OAM] = !!(value & 0x10);
|
||||
regs.sub_window_enabled[BG4] = !!(value & 0x08);
|
||||
regs.sub_window_enabled[BG3] = !!(value & 0x04);
|
||||
|
@ -388,7 +388,7 @@ void bPPU::mmio_w212f(uint8 value) {
|
|||
}
|
||||
|
||||
//CGWSEL
|
||||
void bPPU::mmio_w2130(uint8 value) {
|
||||
void PPU::mmio_w2130(uint8 value) {
|
||||
regs.color_mask = (value >> 6) & 3;
|
||||
regs.colorsub_mask = (value >> 4) & 3;
|
||||
regs.addsub_mode = !!(value & 0x02);
|
||||
|
@ -396,7 +396,7 @@ void bPPU::mmio_w2130(uint8 value) {
|
|||
}
|
||||
|
||||
//CGADDSUB
|
||||
void bPPU::mmio_w2131(uint8 value) {
|
||||
void PPU::mmio_w2131(uint8 value) {
|
||||
regs.color_mode = !!(value & 0x80);
|
||||
regs.color_halve = !!(value & 0x40);
|
||||
regs.color_enabled[BACK] = !!(value & 0x20);
|
||||
|
@ -408,7 +408,7 @@ void bPPU::mmio_w2131(uint8 value) {
|
|||
}
|
||||
|
||||
//COLDATA
|
||||
void bPPU::mmio_w2132(uint8 value) {
|
||||
void PPU::mmio_w2132(uint8 value) {
|
||||
if(value & 0x80) regs.color_b = value & 0x1f;
|
||||
if(value & 0x40) regs.color_g = value & 0x1f;
|
||||
if(value & 0x20) regs.color_r = value & 0x1f;
|
||||
|
@ -419,7 +419,7 @@ void bPPU::mmio_w2132(uint8 value) {
|
|||
}
|
||||
|
||||
//SETINI
|
||||
void bPPU::mmio_w2133(uint8 value) {
|
||||
void PPU::mmio_w2133(uint8 value) {
|
||||
regs.mode7_extbg = !!(value & 0x40);
|
||||
regs.pseudo_hires = !!(value & 0x08);
|
||||
regs.overscan = !!(value & 0x04);
|
||||
|
@ -431,7 +431,7 @@ void bPPU::mmio_w2133(uint8 value) {
|
|||
}
|
||||
|
||||
//MPYL
|
||||
uint8 bPPU::mmio_r2134() {
|
||||
uint8 PPU::mmio_r2134() {
|
||||
uint32 r;
|
||||
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
|
||||
regs.ppu1_mdr = r;
|
||||
|
@ -439,7 +439,7 @@ uint32 r;
|
|||
}
|
||||
|
||||
//MPYM
|
||||
uint8 bPPU::mmio_r2135() {
|
||||
uint8 PPU::mmio_r2135() {
|
||||
uint32 r;
|
||||
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
|
||||
regs.ppu1_mdr = r >> 8;
|
||||
|
@ -447,7 +447,7 @@ uint32 r;
|
|||
}
|
||||
|
||||
//MPYH
|
||||
uint8 bPPU::mmio_r2136() {
|
||||
uint8 PPU::mmio_r2136() {
|
||||
uint32 r;
|
||||
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
|
||||
regs.ppu1_mdr = r >> 16;
|
||||
|
@ -455,7 +455,7 @@ uint32 r;
|
|||
}
|
||||
|
||||
//SLHV
|
||||
uint8 bPPU::mmio_r2137() {
|
||||
uint8 PPU::mmio_r2137() {
|
||||
if(cpu.pio() & 0x80) {
|
||||
latch_counters();
|
||||
}
|
||||
|
@ -463,7 +463,7 @@ uint8 bPPU::mmio_r2137() {
|
|||
}
|
||||
|
||||
//OAMDATAREAD
|
||||
uint8 bPPU::mmio_r2138() {
|
||||
uint8 PPU::mmio_r2138() {
|
||||
regs.ppu1_mdr = oam_mmio_read(regs.oam_addr);
|
||||
|
||||
regs.oam_addr++;
|
||||
|
@ -474,7 +474,7 @@ uint8 bPPU::mmio_r2138() {
|
|||
}
|
||||
|
||||
//VMDATALREAD
|
||||
uint8 bPPU::mmio_r2139() {
|
||||
uint8 PPU::mmio_r2139() {
|
||||
uint16 addr = get_vram_address();
|
||||
regs.ppu1_mdr = regs.vram_readbuffer;
|
||||
if(regs.vram_incmode == 0) {
|
||||
|
@ -487,7 +487,7 @@ uint16 addr = get_vram_address();
|
|||
}
|
||||
|
||||
//VMDATAHREAD
|
||||
uint8 bPPU::mmio_r213a() {
|
||||
uint8 PPU::mmio_r213a() {
|
||||
uint16 addr = get_vram_address() + 1;
|
||||
regs.ppu1_mdr = regs.vram_readbuffer >> 8;
|
||||
if(regs.vram_incmode == 1) {
|
||||
|
@ -503,7 +503,7 @@ uint16 addr = get_vram_address() + 1;
|
|||
//note: CGRAM palette data is 15-bits (0,bbbbb,ggggg,rrrrr)
|
||||
//therefore, the high byte read from each color does not
|
||||
//update bit 7 of the PPU2 MDR.
|
||||
uint8 bPPU::mmio_r213b() {
|
||||
uint8 PPU::mmio_r213b() {
|
||||
if(!(regs.cgram_addr & 1)) {
|
||||
regs.ppu2_mdr = cgram_mmio_read(regs.cgram_addr) & 0xff;
|
||||
} else {
|
||||
|
@ -516,7 +516,7 @@ uint8 bPPU::mmio_r213b() {
|
|||
}
|
||||
|
||||
//OPHCT
|
||||
uint8 bPPU::mmio_r213c() {
|
||||
uint8 PPU::mmio_r213c() {
|
||||
if(!regs.latch_hcounter) {
|
||||
regs.ppu2_mdr = regs.hcounter & 0xff;
|
||||
} else {
|
||||
|
@ -528,7 +528,7 @@ uint8 bPPU::mmio_r213c() {
|
|||
}
|
||||
|
||||
//OPVCT
|
||||
uint8 bPPU::mmio_r213d() {
|
||||
uint8 PPU::mmio_r213d() {
|
||||
if(!regs.latch_vcounter) {
|
||||
regs.ppu2_mdr = regs.vcounter & 0xff;
|
||||
} else {
|
||||
|
@ -540,7 +540,7 @@ uint8 bPPU::mmio_r213d() {
|
|||
}
|
||||
|
||||
//STAT77
|
||||
uint8 bPPU::mmio_r213e() {
|
||||
uint8 PPU::mmio_r213e() {
|
||||
uint8 r = 0x00;
|
||||
r |= (regs.time_over) ? 0x80 : 0x00;
|
||||
r |= (regs.range_over) ? 0x40 : 0x00;
|
||||
|
@ -551,7 +551,7 @@ uint8 r = 0x00;
|
|||
}
|
||||
|
||||
//STAT78
|
||||
uint8 bPPU::mmio_r213f() {
|
||||
uint8 PPU::mmio_r213f() {
|
||||
uint8 r = 0x00;
|
||||
regs.latch_hcounter = 0;
|
||||
regs.latch_vcounter = 0;
|
||||
|
@ -570,7 +570,7 @@ uint8 r = 0x00;
|
|||
return regs.ppu2_mdr;
|
||||
}
|
||||
|
||||
uint8 bPPU::mmio_read(unsigned addr) {
|
||||
uint8 PPU::mmio_read(unsigned addr) {
|
||||
cpu.synchronize_ppu();
|
||||
|
||||
switch(addr & 0xffff) {
|
||||
|
@ -609,7 +609,7 @@ uint8 bPPU::mmio_read(unsigned addr) {
|
|||
return cpu.regs.mdr;
|
||||
}
|
||||
|
||||
void bPPU::mmio_write(unsigned addr, uint8 data) {
|
||||
void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
cpu.synchronize_ppu();
|
||||
|
||||
switch(addr & 0xffff) {
|
|
@ -1,305 +0,0 @@
|
|||
#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("0x", strhex<2>(ppu1_mdr())); return true; }
|
||||
if(id == n++) { name = "S-PPU2 MDR"; value = string("0x", strhex<2>(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("0x", strhex<4>(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("0x", strhex<4>(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("0x", strhex<4>(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("0x", strhex<4>(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("0x", strhex<4>(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("0x", strhex<4>(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("0x", strhex<4>(bg1_name_base_address())); return true; }
|
||||
if(id == n++) { name = "BG2 Name Base Address"; value = string("0x", strhex<4>(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("0x", strhex<4>(bg3_name_base_address())); return true; }
|
||||
if(id == n++) { name = "BG4 Name Base Address"; value = string("0x", strhex<4>(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("0x", strhex<4>(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("0x", strhex<4>(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_enable(); return true; }
|
||||
if(id == n++) { name = "OAM Interlace"; value = oam_interlace(); return true; }
|
||||
if(id == n++) { name = "Interlace"; value = interlace_enable(); 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
|
|
@ -1,243 +0,0 @@
|
|||
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_enable() { return 0; }
|
||||
virtual bool oam_interlace() { return 0; }
|
||||
virtual bool interlace_enable() { 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; }
|
||||
};
|
|
@ -4,14 +4,116 @@
|
|||
namespace SNES {
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#include "ppu-debugger.cpp"
|
||||
#include "debugger/debugger.cpp"
|
||||
PPUDebugger ppu;
|
||||
#else
|
||||
PPU ppu;
|
||||
#endif
|
||||
|
||||
#include "memory/memory.cpp"
|
||||
#include "mmio/mmio.cpp"
|
||||
#include "render/render.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
void PPU::step(unsigned clocks) {
|
||||
clock += clocks;
|
||||
}
|
||||
|
||||
void PPU::synchronize_cpu() {
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||
}
|
||||
|
||||
void PPU::Enter() { ppu.enter(); }
|
||||
|
||||
void PPU::enter() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
//H = 0 (initialize)
|
||||
scanline();
|
||||
add_clocks(10);
|
||||
|
||||
//H = 10 (cache mode7 registers + OAM address reset)
|
||||
cache.m7_hofs = regs.m7_hofs;
|
||||
cache.m7_vofs = regs.m7_vofs;
|
||||
cache.m7a = regs.m7a;
|
||||
cache.m7b = regs.m7b;
|
||||
cache.m7c = regs.m7c;
|
||||
cache.m7d = regs.m7d;
|
||||
cache.m7x = regs.m7x;
|
||||
cache.m7y = regs.m7y;
|
||||
if(vcounter() == (!overscan() ? 225 : 240)) {
|
||||
if(regs.display_disabled == false) {
|
||||
regs.oam_addr = regs.oam_baseaddr << 1;
|
||||
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
||||
}
|
||||
}
|
||||
add_clocks(502);
|
||||
|
||||
//H = 512 (render)
|
||||
render_scanline();
|
||||
add_clocks(640);
|
||||
|
||||
//H = 1152 (cache OBSEL)
|
||||
if(cache.oam_basesize != regs.oam_basesize) {
|
||||
cache.oam_basesize = regs.oam_basesize;
|
||||
sprite_list_valid = false;
|
||||
}
|
||||
cache.oam_nameselect = regs.oam_nameselect;
|
||||
cache.oam_tdaddr = regs.oam_tdaddr;
|
||||
add_clocks(lineclocks() - 1152); //seek to start of next scanline
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::add_clocks(unsigned clocks) {
|
||||
tick(clocks);
|
||||
step(clocks);
|
||||
synchronize_cpu();
|
||||
}
|
||||
|
||||
void PPU::scanline() {
|
||||
line = vcounter();
|
||||
|
||||
if(line == 0) {
|
||||
frame();
|
||||
|
||||
//RTO flag reset
|
||||
regs.time_over = false;
|
||||
regs.range_over = false;
|
||||
}
|
||||
|
||||
if(line == 1) {
|
||||
//mosaic reset
|
||||
for(int bg = BG1; bg <= BG4; bg++) regs.bg_y[bg] = 1;
|
||||
regs.mosaic_countdown = regs.mosaic_size + 1;
|
||||
regs.mosaic_countdown--;
|
||||
} else {
|
||||
for(int bg = BG1; bg <= BG4; bg++) {
|
||||
if(!regs.mosaic_enabled[bg] || !regs.mosaic_countdown) regs.bg_y[bg] = line;
|
||||
}
|
||||
if(!regs.mosaic_countdown) regs.mosaic_countdown = regs.mosaic_size + 1;
|
||||
regs.mosaic_countdown--;
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::render_scanline() {
|
||||
if(line >= 1 && line < (!overscan() ? 225 : 240)) {
|
||||
render_line_oam_rto();
|
||||
render_line();
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::frame() {
|
||||
system.frame();
|
||||
|
||||
if(field() == 0) {
|
||||
display.interlace = regs.interlace;
|
||||
regs.scanlines = (regs.overscan == false) ? 224 : 239;
|
||||
}
|
||||
|
||||
//frame counter
|
||||
static signed framecount = 0;
|
||||
static time_t prev, curr;
|
||||
framecount++;
|
||||
|
@ -26,17 +128,249 @@ void PPU::frame() {
|
|||
}
|
||||
|
||||
void PPU::power() {
|
||||
create(PPU::Enter, system.cpu_frequency());
|
||||
|
||||
ppu1_version = config.ppu1.version;
|
||||
ppu2_version = config.ppu2.version;
|
||||
|
||||
for(unsigned i = 0; i < memory::vram.size(); i++) memory::vram[i] = 0x00;
|
||||
for(unsigned i = 0; i < memory::oam.size(); i++) memory::oam[i] = 0x00;
|
||||
for(unsigned i = 0; i < memory::cgram.size(); i++) memory::cgram[i] = 0x00;
|
||||
flush_tiledata_cache();
|
||||
|
||||
region = (system.region() == System::Region::NTSC ? 0 : 1); //0 = NTSC, 1 = PAL
|
||||
|
||||
regs.ioamaddr = 0x0000;
|
||||
regs.icgramaddr = 0x01ff;
|
||||
|
||||
//$2100
|
||||
regs.display_disabled = true;
|
||||
regs.display_brightness = 15;
|
||||
|
||||
//$2101
|
||||
regs.oam_basesize = 0;
|
||||
regs.oam_nameselect = 0;
|
||||
regs.oam_tdaddr = 0x0000;
|
||||
|
||||
cache.oam_basesize = 0;
|
||||
cache.oam_nameselect = 0;
|
||||
cache.oam_tdaddr = 0x0000;
|
||||
|
||||
//$2102-$2103
|
||||
regs.oam_baseaddr = 0x0000;
|
||||
regs.oam_addr = 0x0000;
|
||||
regs.oam_priority = false;
|
||||
regs.oam_firstsprite = 0;
|
||||
|
||||
//$2104
|
||||
regs.oam_latchdata = 0x00;
|
||||
|
||||
//$2105
|
||||
regs.bg_tilesize[BG1] = 0;
|
||||
regs.bg_tilesize[BG2] = 0;
|
||||
regs.bg_tilesize[BG3] = 0;
|
||||
regs.bg_tilesize[BG4] = 0;
|
||||
regs.bg3_priority = 0;
|
||||
regs.bg_mode = 0;
|
||||
|
||||
//$2106
|
||||
regs.mosaic_size = 0;
|
||||
regs.mosaic_enabled[BG1] = false;
|
||||
regs.mosaic_enabled[BG2] = false;
|
||||
regs.mosaic_enabled[BG3] = false;
|
||||
regs.mosaic_enabled[BG4] = false;
|
||||
regs.mosaic_countdown = 0;
|
||||
|
||||
//$2107-$210a
|
||||
regs.bg_scaddr[BG1] = 0x0000;
|
||||
regs.bg_scaddr[BG2] = 0x0000;
|
||||
regs.bg_scaddr[BG3] = 0x0000;
|
||||
regs.bg_scaddr[BG4] = 0x0000;
|
||||
regs.bg_scsize[BG1] = SC_32x32;
|
||||
regs.bg_scsize[BG2] = SC_32x32;
|
||||
regs.bg_scsize[BG3] = SC_32x32;
|
||||
regs.bg_scsize[BG4] = SC_32x32;
|
||||
|
||||
//$210b-$210c
|
||||
regs.bg_tdaddr[BG1] = 0x0000;
|
||||
regs.bg_tdaddr[BG2] = 0x0000;
|
||||
regs.bg_tdaddr[BG3] = 0x0000;
|
||||
regs.bg_tdaddr[BG4] = 0x0000;
|
||||
|
||||
//$210d-$2114
|
||||
regs.bg_ofslatch = 0x00;
|
||||
regs.m7_hofs = regs.m7_vofs = 0x0000;
|
||||
regs.bg_hofs[BG1] = regs.bg_vofs[BG1] = 0x0000;
|
||||
regs.bg_hofs[BG2] = regs.bg_vofs[BG2] = 0x0000;
|
||||
regs.bg_hofs[BG3] = regs.bg_vofs[BG3] = 0x0000;
|
||||
regs.bg_hofs[BG4] = regs.bg_vofs[BG4] = 0x0000;
|
||||
|
||||
//$2115
|
||||
regs.vram_incmode = 1;
|
||||
regs.vram_mapping = 0;
|
||||
regs.vram_incsize = 1;
|
||||
|
||||
//$2116-$2117
|
||||
regs.vram_addr = 0x0000;
|
||||
|
||||
//$211a
|
||||
regs.mode7_repeat = 0;
|
||||
regs.mode7_vflip = false;
|
||||
regs.mode7_hflip = false;
|
||||
|
||||
//$211b-$2120
|
||||
regs.m7_latch = 0x00;
|
||||
regs.m7a = 0x0000;
|
||||
regs.m7b = 0x0000;
|
||||
regs.m7c = 0x0000;
|
||||
regs.m7d = 0x0000;
|
||||
regs.m7x = 0x0000;
|
||||
regs.m7y = 0x0000;
|
||||
|
||||
//$2121
|
||||
regs.cgram_addr = 0x0000;
|
||||
|
||||
//$2122
|
||||
regs.cgram_latchdata = 0x00;
|
||||
|
||||
//$2123-$2125
|
||||
regs.window1_enabled[BG1] = false;
|
||||
regs.window1_enabled[BG2] = false;
|
||||
regs.window1_enabled[BG3] = false;
|
||||
regs.window1_enabled[BG4] = false;
|
||||
regs.window1_enabled[OAM] = false;
|
||||
regs.window1_enabled[COL] = false;
|
||||
|
||||
regs.window1_invert [BG1] = false;
|
||||
regs.window1_invert [BG2] = false;
|
||||
regs.window1_invert [BG3] = false;
|
||||
regs.window1_invert [BG4] = false;
|
||||
regs.window1_invert [OAM] = false;
|
||||
regs.window1_invert [COL] = false;
|
||||
|
||||
regs.window2_enabled[BG1] = false;
|
||||
regs.window2_enabled[BG2] = false;
|
||||
regs.window2_enabled[BG3] = false;
|
||||
regs.window2_enabled[BG4] = false;
|
||||
regs.window2_enabled[OAM] = false;
|
||||
regs.window2_enabled[COL] = false;
|
||||
|
||||
regs.window2_invert [BG1] = false;
|
||||
regs.window2_invert [BG2] = false;
|
||||
regs.window2_invert [BG3] = false;
|
||||
regs.window2_invert [BG4] = false;
|
||||
regs.window2_invert [OAM] = false;
|
||||
regs.window2_invert [COL] = false;
|
||||
|
||||
//$2126-$2129
|
||||
regs.window1_left = 0x00;
|
||||
regs.window1_right = 0x00;
|
||||
regs.window2_left = 0x00;
|
||||
regs.window2_right = 0x00;
|
||||
|
||||
//$212a-$212b
|
||||
regs.window_mask[BG1] = 0;
|
||||
regs.window_mask[BG2] = 0;
|
||||
regs.window_mask[BG3] = 0;
|
||||
regs.window_mask[BG4] = 0;
|
||||
regs.window_mask[OAM] = 0;
|
||||
regs.window_mask[COL] = 0;
|
||||
|
||||
//$212c-$212d
|
||||
regs.bg_enabled[BG1] = false;
|
||||
regs.bg_enabled[BG2] = false;
|
||||
regs.bg_enabled[BG3] = false;
|
||||
regs.bg_enabled[BG4] = false;
|
||||
regs.bg_enabled[OAM] = false;
|
||||
regs.bgsub_enabled[BG1] = false;
|
||||
regs.bgsub_enabled[BG2] = false;
|
||||
regs.bgsub_enabled[BG3] = false;
|
||||
regs.bgsub_enabled[BG4] = false;
|
||||
regs.bgsub_enabled[OAM] = false;
|
||||
|
||||
//$212e-$212f
|
||||
regs.window_enabled[BG1] = false;
|
||||
regs.window_enabled[BG2] = false;
|
||||
regs.window_enabled[BG3] = false;
|
||||
regs.window_enabled[BG4] = false;
|
||||
regs.window_enabled[OAM] = false;
|
||||
regs.sub_window_enabled[BG1] = false;
|
||||
regs.sub_window_enabled[BG2] = false;
|
||||
regs.sub_window_enabled[BG3] = false;
|
||||
regs.sub_window_enabled[BG4] = false;
|
||||
regs.sub_window_enabled[OAM] = false;
|
||||
|
||||
//$2130
|
||||
regs.color_mask = 0;
|
||||
regs.colorsub_mask = 0;
|
||||
regs.addsub_mode = false;
|
||||
regs.direct_color = false;
|
||||
|
||||
//$2131
|
||||
regs.color_mode = 0;
|
||||
regs.color_halve = false;
|
||||
regs.color_enabled[BACK] = false;
|
||||
regs.color_enabled[OAM] = false;
|
||||
regs.color_enabled[BG4] = false;
|
||||
regs.color_enabled[BG3] = false;
|
||||
regs.color_enabled[BG2] = false;
|
||||
regs.color_enabled[BG1] = false;
|
||||
|
||||
//$2132
|
||||
regs.color_r = 0x00;
|
||||
regs.color_g = 0x00;
|
||||
regs.color_b = 0x00;
|
||||
regs.color_rgb = 0x0000;
|
||||
|
||||
//$2133
|
||||
regs.mode7_extbg = false;
|
||||
regs.pseudo_hires = false;
|
||||
regs.overscan = false;
|
||||
regs.scanlines = 224;
|
||||
regs.oam_interlace = false;
|
||||
regs.interlace = false;
|
||||
|
||||
//$2137
|
||||
regs.hcounter = 0;
|
||||
regs.vcounter = 0;
|
||||
regs.latch_hcounter = 0;
|
||||
regs.latch_vcounter = 0;
|
||||
regs.counters_latched = false;
|
||||
|
||||
//$2139-$213a
|
||||
regs.vram_readbuffer = 0x0000;
|
||||
|
||||
//$213e
|
||||
regs.time_over = false;
|
||||
regs.range_over = false;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void PPU::reset() {
|
||||
create(PPU::Enter, system.cpu_frequency());
|
||||
|
||||
create(Enter, system.cpu_frequency());
|
||||
PPUCounter::reset();
|
||||
memset(surface, 0, 512 * 512 * sizeof(uint16));
|
||||
|
||||
frame();
|
||||
|
||||
//$2100
|
||||
regs.display_disabled = true;
|
||||
|
||||
display.interlace = false;
|
||||
display.overscan = false;
|
||||
regs.scanlines = 224;
|
||||
|
||||
memset(sprite_list, 0, sizeof(sprite_list));
|
||||
sprite_list_valid = false;
|
||||
|
||||
//open bus support
|
||||
regs.ppu1_mdr = 0xff;
|
||||
regs.ppu2_mdr = 0xff;
|
||||
|
||||
//bg line counters
|
||||
regs.bg_y[0] = 0;
|
||||
regs.bg_y[1] = 0;
|
||||
regs.bg_y[2] = 0;
|
||||
regs.bg_y[3] = 0;
|
||||
}
|
||||
|
||||
PPU::PPU() {
|
||||
|
@ -45,10 +379,33 @@ PPU::PPU() {
|
|||
|
||||
status.frames_updated = false;
|
||||
status.frames_executed = 0;
|
||||
|
||||
alloc_tiledata_cache();
|
||||
|
||||
for(unsigned l = 0; l < 16; l++) {
|
||||
for(unsigned i = 0; i < 4096; i++) {
|
||||
mosaic_table[l][i] = (i / (l + 1)) * (l + 1);
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned l = 0; l < 16; l++) {
|
||||
for(unsigned r = 0; r < 32; r++) {
|
||||
for(unsigned g = 0; g < 32; g++) {
|
||||
for(unsigned b = 0; b < 32; b++) {
|
||||
double luma = (double)l / 15.0;
|
||||
unsigned ar = (luma * r + 0.5);
|
||||
unsigned ag = (luma * g + 0.5);
|
||||
unsigned ab = (luma * b + 0.5);
|
||||
light_table[l][(r << 10) + (g << 5) + b] = (ab << 10) + (ag << 5) + ar;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PPU::~PPU() {
|
||||
delete[] surface;
|
||||
free_tiledata_cache();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,65 +1,10 @@
|
|||
#if defined(DEBUGGER)
|
||||
#include "ppu-debugger.hpp"
|
||||
#endif
|
||||
|
||||
//PPUCounter emulates the H/V latch counters of the S-PPU2.
|
||||
//
|
||||
//real hardware has the S-CPU maintain its own copy of these counters that are
|
||||
//updated based on the state of the S-PPU Vblank and Hblank pins. emulating this
|
||||
//would require full lock-step synchronization for every clock tick.
|
||||
//to bypass this and allow the two to run out-of-order, both the CPU and PPU
|
||||
//classes inherit PPUcounter and keep their own counters.
|
||||
//the timers are kept in sync, as the only differences occur on V=240 and V=261,
|
||||
//based on interlace. thus, we need only synchronize and fetch interlace at any
|
||||
//point before this in the frame, which is handled internally by this class at
|
||||
//V=128.
|
||||
|
||||
class PPUCounter {
|
||||
public:
|
||||
alwaysinline void tick();
|
||||
alwaysinline void tick(unsigned clocks);
|
||||
|
||||
alwaysinline bool field () const;
|
||||
alwaysinline uint16 vcounter() const;
|
||||
alwaysinline uint16 hcounter() const;
|
||||
inline uint16 hdot() const;
|
||||
inline uint16 lineclocks() const;
|
||||
|
||||
alwaysinline bool field (unsigned offset) const;
|
||||
alwaysinline uint16 vcounter(unsigned offset) const;
|
||||
alwaysinline uint16 hcounter(unsigned offset) const;
|
||||
|
||||
inline void reset();
|
||||
function<void ()> scanline;
|
||||
void serialize(serializer&);
|
||||
|
||||
private:
|
||||
inline void vcounter_tick();
|
||||
|
||||
struct {
|
||||
bool interlace;
|
||||
bool field;
|
||||
uint16 vcounter;
|
||||
uint16 hcounter;
|
||||
} status;
|
||||
|
||||
struct {
|
||||
bool field[2048];
|
||||
uint16 vcounter[2048];
|
||||
uint16 hcounter[2048];
|
||||
|
||||
int32 index;
|
||||
} history;
|
||||
};
|
||||
#include "counter/counter.hpp"
|
||||
|
||||
class PPU : public Processor, public PPUCounter, public MMIO {
|
||||
public:
|
||||
//synchronization
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_cpu();
|
||||
|
||||
static void Enter();
|
||||
virtual void enter() = 0;
|
||||
#include "memory/memory.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "render/render.hpp"
|
||||
|
||||
uint16 *surface;
|
||||
uint16 *output;
|
||||
|
@ -72,17 +17,66 @@ public:
|
|||
uint8 ppu1_version;
|
||||
uint8 ppu2_version;
|
||||
|
||||
virtual bool interlace() const = 0;
|
||||
virtual bool overscan() const = 0;
|
||||
virtual bool hires() const = 0;
|
||||
//synchronization
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_cpu();
|
||||
|
||||
virtual void latch_counters() = 0;
|
||||
static void Enter();
|
||||
void enter();
|
||||
void add_clocks(unsigned clocks);
|
||||
|
||||
virtual void frame();
|
||||
virtual void power();
|
||||
virtual void reset();
|
||||
uint8 region;
|
||||
unsigned line;
|
||||
|
||||
virtual void serialize(serializer&);
|
||||
enum { NTSC = 0, PAL = 1 };
|
||||
enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5, COL = 5 };
|
||||
enum { SC_32x32 = 0, SC_64x32 = 1, SC_32x64 = 2, SC_64x64 = 3 };
|
||||
|
||||
struct {
|
||||
bool interlace;
|
||||
bool overscan;
|
||||
} display;
|
||||
|
||||
struct {
|
||||
//$2101
|
||||
uint8 oam_basesize;
|
||||
uint8 oam_nameselect;
|
||||
uint16 oam_tdaddr;
|
||||
|
||||
//$210d-$210e
|
||||
uint16 m7_hofs, m7_vofs;
|
||||
|
||||
//$211b-$2120
|
||||
uint16 m7a, m7b, m7c, m7d, m7x, m7y;
|
||||
} cache;
|
||||
|
||||
alwaysinline bool interlace() const { return display.interlace; }
|
||||
alwaysinline bool overscan() const { return display.overscan; }
|
||||
alwaysinline bool hires() const { return (regs.pseudo_hires || regs.bg_mode == 5 || regs.bg_mode == 6); }
|
||||
|
||||
uint16 light_table[16][32768];
|
||||
uint16 mosaic_table[16][4096];
|
||||
void render_line();
|
||||
|
||||
void update_oam_status();
|
||||
//required functions
|
||||
void run();
|
||||
void scanline();
|
||||
void render_scanline();
|
||||
void frame();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
PPU();
|
||||
virtual ~PPU();
|
||||
~PPU();
|
||||
|
||||
friend class PPUDebugger;
|
||||
};
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.hpp"
|
||||
extern PPUDebugger ppu;
|
||||
#else
|
||||
extern PPU ppu;
|
||||
#endif
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifdef BPPU_CPP
|
||||
#ifdef PPU_CPP
|
||||
|
||||
//color addition / subtraction
|
||||
//thanks go to blargg for the optimized algorithms
|
||||
inline uint16 bPPU::addsub(uint32 x, uint32 y, bool halve) {
|
||||
inline uint16 PPU::addsub(uint32 x, uint32 y, bool halve) {
|
||||
if(!regs.color_mode) {
|
||||
if(!halve) {
|
||||
unsigned sum = x + y;
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef BPPU_CPP
|
||||
#ifdef PPU_CPP
|
||||
|
||||
//called once at the start of every rendered scanline
|
||||
void bPPU::update_bg_info() {
|
||||
void PPU::update_bg_info() {
|
||||
const unsigned hires = (regs.bg_mode == 5 || regs.bg_mode == 6);
|
||||
const unsigned width = (!hires ? 256 : 512);
|
||||
|
||||
|
@ -23,7 +23,7 @@ void bPPU::update_bg_info() {
|
|||
}
|
||||
|
||||
template<unsigned bg>
|
||||
uint16 bPPU::bg_get_tile(uint16 x, uint16 y) {
|
||||
uint16 PPU::bg_get_tile(uint16 x, uint16 y) {
|
||||
x = (x & bg_info[bg].mx) >> bg_info[bg].tw;
|
||||
y = (y & bg_info[bg].my) >> bg_info[bg].th;
|
||||
|
||||
|
@ -52,7 +52,7 @@ uint16 bPPU::bg_get_tile(uint16 x, uint16 y) {
|
|||
}
|
||||
|
||||
template<unsigned mode, unsigned bg, unsigned color_depth>
|
||||
void bPPU::render_line_bg(uint8 pri0_pos, uint8 pri1_pos) {
|
||||
void PPU::render_line_bg(uint8 pri0_pos, uint8 pri1_pos) {
|
||||
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false) return;
|
||||
|
||||
const bool bg_enabled = regs.bg_enabled[bg];
|
|
@ -1,4 +1,4 @@
|
|||
#ifdef BPPU_CPP
|
||||
#ifdef PPU_CPP
|
||||
|
||||
#define render_bg_tile_line_2bpp(mask) \
|
||||
col = !!(d0 & mask) << 0; \
|
||||
|
@ -24,7 +24,7 @@
|
|||
*dest++ = col
|
||||
|
||||
template<unsigned color_depth>
|
||||
void bPPU::render_bg_tile(uint16 tile_num) {
|
||||
void PPU::render_bg_tile(uint16 tile_num) {
|
||||
uint8 col, d0, d1, d2, d3, d4, d5, d6, d7;
|
||||
|
||||
if(color_depth == COLORDEPTH_4) {
|
||||
|
@ -100,7 +100,7 @@ void bPPU::render_bg_tile(uint16 tile_num) {
|
|||
#undef render_bg_tile_line_4bpp
|
||||
#undef render_bg_tile_line_8bpp
|
||||
|
||||
void bPPU::flush_pixel_cache() {
|
||||
void PPU::flush_pixel_cache() {
|
||||
uint16 main = get_palette(0);
|
||||
uint16 sub = (regs.pseudo_hires || regs.bg_mode == 5 || regs.bg_mode == 6)
|
||||
? main
|
||||
|
@ -119,7 +119,7 @@ void bPPU::flush_pixel_cache() {
|
|||
} while(i--);
|
||||
}
|
||||
|
||||
void bPPU::alloc_tiledata_cache() {
|
||||
void PPU::alloc_tiledata_cache() {
|
||||
bg_tiledata[TILE_2BIT] = new uint8_t[262144]();
|
||||
bg_tiledata[TILE_4BIT] = new uint8_t[131072]();
|
||||
bg_tiledata[TILE_8BIT] = new uint8_t[ 65536]();
|
||||
|
@ -129,13 +129,13 @@ void bPPU::alloc_tiledata_cache() {
|
|||
}
|
||||
|
||||
//marks all tiledata cache entries as dirty
|
||||
void bPPU::flush_tiledata_cache() {
|
||||
void PPU::flush_tiledata_cache() {
|
||||
for(unsigned i = 0; i < 4096; i++) bg_tiledata_state[TILE_2BIT][i] = 1;
|
||||
for(unsigned i = 0; i < 2048; i++) bg_tiledata_state[TILE_4BIT][i] = 1;
|
||||
for(unsigned i = 0; i < 1024; i++) bg_tiledata_state[TILE_8BIT][i] = 1;
|
||||
}
|
||||
|
||||
void bPPU::free_tiledata_cache() {
|
||||
void PPU::free_tiledata_cache() {
|
||||
delete[] bg_tiledata[TILE_2BIT];
|
||||
delete[] bg_tiledata[TILE_4BIT];
|
||||
delete[] bg_tiledata[TILE_8BIT];
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef BPPU_CPP
|
||||
#ifdef PPU_CPP
|
||||
|
||||
inline uint16 bPPU::get_palette(uint8 index) {
|
||||
inline uint16 PPU::get_palette(uint8 index) {
|
||||
const unsigned addr = index << 1;
|
||||
return memory::cgram[addr] + (memory::cgram[addr + 1] << 8);
|
||||
}
|
||||
|
@ -8,13 +8,13 @@ inline uint16 bPPU::get_palette(uint8 index) {
|
|||
//p = 00000bgr <palette data>
|
||||
//t = BBGGGRRR <tilemap data>
|
||||
//r = 0BBb00GGGg0RRRr0 <return data>
|
||||
inline uint16 bPPU::get_direct_color(uint8 p, uint8 t) {
|
||||
inline uint16 PPU::get_direct_color(uint8 p, uint8 t) {
|
||||
return ((t & 7) << 2) | ((p & 1) << 1) |
|
||||
(((t >> 3) & 7) << 7) | (((p >> 1) & 1) << 6) |
|
||||
((t >> 6) << 13) | ((p >> 2) << 12);
|
||||
}
|
||||
|
||||
inline uint16 bPPU::get_pixel_normal(uint32 x) {
|
||||
inline uint16 PPU::get_pixel_normal(uint32 x) {
|
||||
pixel_t &p = pixel_cache[x];
|
||||
uint16 src_main, src_sub;
|
||||
uint8 bg_sub;
|
||||
|
@ -49,7 +49,7 @@ inline uint16 bPPU::get_pixel_normal(uint32 x) {
|
|||
return src_main;
|
||||
}
|
||||
|
||||
inline uint16 bPPU::get_pixel_swap(uint32 x) {
|
||||
inline uint16 PPU::get_pixel_swap(uint32 x) {
|
||||
pixel_t &p = pixel_cache[x];
|
||||
uint16 src_main, src_sub;
|
||||
uint8 bg_sub;
|
||||
|
@ -84,7 +84,7 @@ inline uint16 bPPU::get_pixel_swap(uint32 x) {
|
|||
return src_main;
|
||||
}
|
||||
|
||||
inline void bPPU::render_line_output() {
|
||||
inline void PPU::render_line_output() {
|
||||
uint16 *ptr = (uint16*)output + (line * 1024) + ((interlace() && field()) ? 512 : 0);
|
||||
uint16 *luma = light_table[regs.display_brightness];
|
||||
uint16 curr, prev;
|
||||
|
@ -107,7 +107,7 @@ inline void bPPU::render_line_output() {
|
|||
}
|
||||
}
|
||||
|
||||
inline void bPPU::render_line_clear() {
|
||||
inline void PPU::render_line_clear() {
|
||||
uint16 *ptr = (uint16*)output + (line * 1024) + ((interlace() && field()) ? 512 : 0);
|
||||
uint16 width = (!regs.pseudo_hires && regs.bg_mode != 5 && regs.bg_mode != 6) ? 256 : 512;
|
||||
memset(ptr, 0, width * 2 * sizeof(uint16));
|
|
@ -1,4 +1,4 @@
|
|||
#ifdef BPPU_CPP
|
||||
#ifdef PPU_CPP
|
||||
|
||||
//bsnes mode7 renderer
|
||||
//
|
||||
|
@ -13,7 +13,7 @@
|
|||
#define CLIP(x) ( ((x) & 0x2000) ? ( (x) | ~0x03ff) : ((x) & 0x03ff) )
|
||||
|
||||
template<unsigned bg>
|
||||
void bPPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) {
|
||||
void PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) {
|
||||
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false) return;
|
||||
|
||||
int32 px, py;
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef BPPU_CPP
|
||||
#ifdef PPU_CPP
|
||||
|
||||
void bPPU::build_sprite_list() {
|
||||
void PPU::build_sprite_list() {
|
||||
if(sprite_list_valid == true) return;
|
||||
sprite_list_valid = true;
|
||||
|
||||
|
@ -55,7 +55,7 @@ void bPPU::build_sprite_list() {
|
|||
}
|
||||
}
|
||||
|
||||
bool bPPU::is_sprite_on_scanline() {
|
||||
bool PPU::is_sprite_on_scanline() {
|
||||
//if sprite is entirely offscreen and doesn't wrap around to the left side of the screen,
|
||||
//then it is not counted. this *should* be 256, and not 255, even though dot 256 is offscreen.
|
||||
sprite_item *spr = &sprite_list[active_sprite];
|
||||
|
@ -67,7 +67,7 @@ bool bPPU::is_sprite_on_scanline() {
|
|||
return false;
|
||||
}
|
||||
|
||||
void bPPU::load_oam_tiles() {
|
||||
void PPU::load_oam_tiles() {
|
||||
sprite_item *spr = &sprite_list[active_sprite];
|
||||
uint16 tile_width = spr->width >> 3;
|
||||
int x = spr->x;
|
||||
|
@ -120,7 +120,7 @@ void bPPU::load_oam_tiles() {
|
|||
}
|
||||
}
|
||||
|
||||
void bPPU::render_oam_tile(int tile_num) {
|
||||
void PPU::render_oam_tile(int tile_num) {
|
||||
oam_tileitem *t = &oam_tilelist[tile_num];
|
||||
uint8 *oam_td = (uint8*)bg_tiledata[COLORDEPTH_16];
|
||||
uint8 *oam_td_state = (uint8*)bg_tiledata_state[COLORDEPTH_16];
|
||||
|
@ -145,7 +145,7 @@ void bPPU::render_oam_tile(int tile_num) {
|
|||
}
|
||||
}
|
||||
|
||||
void bPPU::render_line_oam_rto() {
|
||||
void PPU::render_line_oam_rto() {
|
||||
build_sprite_list();
|
||||
|
||||
regs.oam_itemcount = 0;
|
||||
|
@ -190,7 +190,7 @@ void bPPU::render_line_oam_rto() {
|
|||
pixel_cache[x].ce_sub = (oam_line_pal[x] < 192); \
|
||||
}
|
||||
|
||||
void bPPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
|
||||
void PPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
|
||||
if(regs.bg_enabled[OAM] == false && regs.bgsub_enabled[OAM] == false) return;
|
||||
|
||||
for(unsigned s = 0; s < 34; s++) {
|
|
@ -1,4 +1,4 @@
|
|||
#ifdef BPPU_CPP
|
||||
#ifdef PPU_CPP
|
||||
|
||||
#include "cache.cpp"
|
||||
#include "windows.cpp"
|
||||
|
@ -11,7 +11,7 @@
|
|||
//Mode 0: ->
|
||||
// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
|
||||
// BG4B, BG3B, OAM0, BG4A, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3
|
||||
void bPPU::render_line_mode0() {
|
||||
void PPU::render_line_mode0() {
|
||||
render_line_bg<0, BG1, COLORDEPTH_4>(8, 11);
|
||||
render_line_bg<0, BG2, COLORDEPTH_4>(7, 10);
|
||||
render_line_bg<0, BG3, COLORDEPTH_4>(2, 5);
|
||||
|
@ -26,7 +26,7 @@ void bPPU::render_line_mode0() {
|
|||
//Mode 1 (pri=0): ->
|
||||
// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
|
||||
// BG3B, OAM0, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3
|
||||
void bPPU::render_line_mode1() {
|
||||
void PPU::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);
|
||||
|
@ -43,7 +43,7 @@ void bPPU::render_line_mode1() {
|
|||
//Mode 2: ->
|
||||
// 1, 2, 3, 4, 5, 6, 7, 8
|
||||
// BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3
|
||||
void bPPU::render_line_mode2() {
|
||||
void PPU::render_line_mode2() {
|
||||
render_line_bg<2, BG1, COLORDEPTH_16>(3, 7);
|
||||
render_line_bg<2, BG2, COLORDEPTH_16>(1, 5);
|
||||
render_line_oam(2, 4, 6, 8);
|
||||
|
@ -52,7 +52,7 @@ void bPPU::render_line_mode2() {
|
|||
//Mode 3: ->
|
||||
// 1, 2, 3, 4, 5, 6, 7, 8
|
||||
// BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3
|
||||
void bPPU::render_line_mode3() {
|
||||
void PPU::render_line_mode3() {
|
||||
render_line_bg<3, BG1, COLORDEPTH_256>(3, 7);
|
||||
render_line_bg<3, BG2, COLORDEPTH_16 >(1, 5);
|
||||
render_line_oam(2, 4, 6, 8);
|
||||
|
@ -61,7 +61,7 @@ void bPPU::render_line_mode3() {
|
|||
//Mode 4: ->
|
||||
// 1, 2, 3, 4, 5, 6, 7, 8
|
||||
// BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3
|
||||
void bPPU::render_line_mode4() {
|
||||
void PPU::render_line_mode4() {
|
||||
render_line_bg<4, BG1, COLORDEPTH_256>(3, 7);
|
||||
render_line_bg<4, BG2, COLORDEPTH_4 >(1, 5);
|
||||
render_line_oam(2, 4, 6, 8);
|
||||
|
@ -70,7 +70,7 @@ void bPPU::render_line_mode4() {
|
|||
//Mode 5: ->
|
||||
// 1, 2, 3, 4, 5, 6, 7, 8
|
||||
// BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3
|
||||
void bPPU::render_line_mode5() {
|
||||
void PPU::render_line_mode5() {
|
||||
render_line_bg<5, BG1, COLORDEPTH_16>(3, 7);
|
||||
render_line_bg<5, BG2, COLORDEPTH_4 >(1, 5);
|
||||
render_line_oam(2, 4, 6, 8);
|
||||
|
@ -79,7 +79,7 @@ void bPPU::render_line_mode5() {
|
|||
//Mode 6: ->
|
||||
// 1, 2, 3, 4, 5, 6
|
||||
// OAM0, BG1B, OAM1, OAM2, BG1A, OAM3
|
||||
void bPPU::render_line_mode6() {
|
||||
void PPU::render_line_mode6() {
|
||||
render_line_bg<6, BG1, COLORDEPTH_16>(2, 5);
|
||||
render_line_oam(1, 3, 4, 6);
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ void bPPU::render_line_mode6() {
|
|||
//Mode 7 EXTBG: ->
|
||||
// 1, 2, 3, 4, 5, 6, 7
|
||||
// BG2B, OAM0, BG1n, OAM1, BG2A, OAM2, OAM3
|
||||
void bPPU::render_line_mode7() {
|
||||
void PPU::render_line_mode7() {
|
||||
if(regs.mode7_extbg == false) {
|
||||
render_line_mode7<BG1>(2, 2);
|
||||
render_line_oam(1, 3, 4, 5);
|
||||
|
@ -102,7 +102,7 @@ void bPPU::render_line_mode7() {
|
|||
}
|
||||
}
|
||||
|
||||
void bPPU::render_line() {
|
||||
void PPU::render_line() {
|
||||
if(regs.display_disabled == true) {
|
||||
render_line_clear();
|
||||
return;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue