mirror of https://github.com/bsnes-emu/bsnes.git
Update to v074r08 release.
byuu says: The nall::function binding for the memory map apparently breaks when the debugger is enabled, as PPU:: becomes PPUdebugger::, etc; and C++ isn't smart enough to upconvert for us. Not sure how I am going to work around that yet ... Changelog: - improved GameBoy::CPU::Halt emulation, fixes Legend of Zelda intro water+world-map scrolling at the same time - added GameBoy::APU skeleton, and hooked up MMIO read/write for all registers - modified nall integer->string functions
This commit is contained in:
parent
c833b69087
commit
cab5917806
|
@ -1,6 +1,6 @@
|
||||||
gameboy_objects := gameboy-system gameboy-scheduler
|
gameboy_objects := gameboy-system gameboy-scheduler
|
||||||
gameboy_objects += gameboy-memory gameboy-cartridge
|
gameboy_objects += gameboy-memory gameboy-cartridge
|
||||||
gameboy_objects += gameboy-cpu gameboy-lcd
|
gameboy_objects += gameboy-cpu gameboy-apu gameboy-lcd
|
||||||
objects += $(gameboy_objects)
|
objects += $(gameboy_objects)
|
||||||
|
|
||||||
obj/gameboy-system.o: $(gameboy)/system/system.cpp $(call rwildcard,$(gameboy)/system/)
|
obj/gameboy-system.o: $(gameboy)/system/system.cpp $(call rwildcard,$(gameboy)/system/)
|
||||||
|
@ -8,4 +8,5 @@ obj/gameboy-scheduler.o: $(gameboy)/scheduler/scheduler.cpp $(call rwildcard,$(g
|
||||||
obj/gameboy-cartridge.o: $(gameboy)/cartridge/cartridge.cpp $(call rwildcard,$(gameboy)/cartridge/)
|
obj/gameboy-cartridge.o: $(gameboy)/cartridge/cartridge.cpp $(call rwildcard,$(gameboy)/cartridge/)
|
||||||
obj/gameboy-memory.o: $(gameboy)/memory/memory.cpp $(call rwildcard,$(gameboy)/memory/)
|
obj/gameboy-memory.o: $(gameboy)/memory/memory.cpp $(call rwildcard,$(gameboy)/memory/)
|
||||||
obj/gameboy-cpu.o: $(gameboy)/cpu/cpu.cpp $(call rwildcard,$(gameboy)/cpu/)
|
obj/gameboy-cpu.o: $(gameboy)/cpu/cpu.cpp $(call rwildcard,$(gameboy)/cpu/)
|
||||||
|
obj/gameboy-apu.o: $(gameboy)/apu/apu.cpp $(call rwildcard,$(gameboy)/apu/)
|
||||||
obj/gameboy-lcd.o: $(gameboy)/lcd/lcd.cpp $(call rwildcard,$(gameboy)/lcd/)
|
obj/gameboy-lcd.o: $(gameboy)/lcd/lcd.cpp $(call rwildcard,$(gameboy)/lcd/)
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
#include <gameboy/gameboy.hpp>
|
||||||
|
|
||||||
|
#define APU_CPP
|
||||||
|
namespace GameBoy {
|
||||||
|
|
||||||
|
#include "mmio/mmio.cpp"
|
||||||
|
#include "serialization.cpp"
|
||||||
|
APU apu;
|
||||||
|
|
||||||
|
void APU::power() {
|
||||||
|
for(unsigned n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this;
|
||||||
|
|
||||||
|
channel1.sweep_time = 0;
|
||||||
|
channel1.sweep_direction = 0;
|
||||||
|
channel1.sweep_shift = 0;
|
||||||
|
|
||||||
|
channel1.wave_pattern_duty = 0;
|
||||||
|
channel1.sound_length = 0;
|
||||||
|
|
||||||
|
channel1.initial_envelope_volume = 0;
|
||||||
|
channel1.envelope_direction = 0;
|
||||||
|
channel1.envelope_sweep = 0;
|
||||||
|
|
||||||
|
channel1.frequency = 0;
|
||||||
|
channel1.initialize = 0;
|
||||||
|
channel1.consecutive_selection = 0;
|
||||||
|
|
||||||
|
channel2.wave_pattern_duty = 0;
|
||||||
|
channel2.sound_length = 0;
|
||||||
|
|
||||||
|
channel2.initial_envelope_volume = 0;
|
||||||
|
channel2.envelope_direction = 0;
|
||||||
|
channel2.envelope_sweep = 0;
|
||||||
|
|
||||||
|
channel2.frequency = 0;
|
||||||
|
channel2.initialize = 0;
|
||||||
|
channel2.consecutive_selection = 0;
|
||||||
|
|
||||||
|
channel3.off = 0;
|
||||||
|
|
||||||
|
channel3.sound_length = 0;
|
||||||
|
|
||||||
|
channel3.output_level = 0;
|
||||||
|
|
||||||
|
channel3.frequency = 0;
|
||||||
|
channel3.initialize = 0;
|
||||||
|
channel3.consecutive_selection = 0;
|
||||||
|
|
||||||
|
for(unsigned n = 0; n < 16; n++) channel3.pattern[n] = 0;
|
||||||
|
|
||||||
|
channel4.sound_length = 0;
|
||||||
|
|
||||||
|
channel4.initial_envelope_volume = 0;
|
||||||
|
channel4.envelope_direction = 0;
|
||||||
|
channel4.envelope_sweep = 0;
|
||||||
|
|
||||||
|
channel4.shift_clock_frequency = 0;
|
||||||
|
channel4.counter_step_width = 0;
|
||||||
|
channel4.dividing_ratio = 0;
|
||||||
|
|
||||||
|
channel4.initialize = 0;
|
||||||
|
channel4.consecutive_selection = 0;
|
||||||
|
|
||||||
|
control.output_vin_to_so2 = 0;
|
||||||
|
control.so2_output_level = 0;
|
||||||
|
control.output_vin_to_so1 = 0;
|
||||||
|
control.so1_output_level = 0;
|
||||||
|
|
||||||
|
control.output_channel4_to_so2 = 0;
|
||||||
|
control.output_channel3_to_so2 = 0;
|
||||||
|
control.output_channel2_to_so2 = 0;
|
||||||
|
control.output_channel1_to_so2 = 0;
|
||||||
|
control.output_channel4_to_so1 = 0;
|
||||||
|
control.output_channel3_to_so1 = 0;
|
||||||
|
control.output_channel2_to_so1 = 0;
|
||||||
|
control.output_channel1_to_so1 = 0;
|
||||||
|
|
||||||
|
control.sound_on = 0;
|
||||||
|
control.channel4_on = 0;
|
||||||
|
control.channel3_on = 0;
|
||||||
|
control.channel2_on = 0;
|
||||||
|
control.channel1_on = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
struct APU : Processor, MMIO {
|
||||||
|
#include "mmio/mmio.hpp"
|
||||||
|
|
||||||
|
void power();
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern APU apu;
|
|
@ -0,0 +1,248 @@
|
||||||
|
#ifdef APU_CPP
|
||||||
|
|
||||||
|
uint8 APU::mmio_read(uint16 addr) {
|
||||||
|
if(addr == 0xff10) { //NR10
|
||||||
|
return (channel1.sweep_time << 4)
|
||||||
|
| (channel1.sweep_direction << 3)
|
||||||
|
| (channel1.sweep_shift << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff11) { //NR11
|
||||||
|
return (channel1.wave_pattern_duty << 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff12) { //NR12
|
||||||
|
return (channel1.initial_envelope_volume << 4)
|
||||||
|
| (channel1.envelope_direction << 3)
|
||||||
|
| (channel1.envelope_sweep << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff14) { //NR14
|
||||||
|
return (channel1.consecutive_selection << 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff16) { //NR21
|
||||||
|
return (channel2.wave_pattern_duty << 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff17) { //NR22
|
||||||
|
return (channel2.initial_envelope_volume << 4)
|
||||||
|
| (channel2.envelope_direction << 3)
|
||||||
|
| (channel2.envelope_sweep << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff19) { //NR24
|
||||||
|
return (channel2.consecutive_selection << 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff1a) { //NR30
|
||||||
|
return (channel3.off << 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff1b) { //NR31
|
||||||
|
return (channel3.sound_length << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff1c) { //NR32
|
||||||
|
return (channel3.output_level << 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff1e) { //NR34
|
||||||
|
return (channel3.consecutive_selection << 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff20) { //NR41
|
||||||
|
return (channel4.sound_length << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff21) { //NR42
|
||||||
|
return (channel4.initial_envelope_volume << 4)
|
||||||
|
| (channel4.envelope_direction << 3)
|
||||||
|
| (channel4.envelope_sweep << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff22) { //NR43
|
||||||
|
return (channel4.shift_clock_frequency << 4)
|
||||||
|
| (channel4.counter_step_width << 3)
|
||||||
|
| (channel4.dividing_ratio << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff23) { //NR44
|
||||||
|
return (channel4.consecutive_selection << 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff24) { //NR50
|
||||||
|
return (control.output_vin_to_so2 << 7)
|
||||||
|
| (control.so2_output_level << 4)
|
||||||
|
| (control.output_vin_to_so1 << 3)
|
||||||
|
| (control.so1_output_level << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff25) { //NR51
|
||||||
|
return (control.output_channel4_to_so2 << 7)
|
||||||
|
| (control.output_channel3_to_so2 << 6)
|
||||||
|
| (control.output_channel2_to_so2 << 5)
|
||||||
|
| (control.output_channel1_to_so2 << 4)
|
||||||
|
| (control.output_channel4_to_so1 << 3)
|
||||||
|
| (control.output_channel3_to_so1 << 2)
|
||||||
|
| (control.output_channel2_to_so1 << 1)
|
||||||
|
| (control.output_channel1_to_so1 << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff26) { //NR52
|
||||||
|
return (control.sound_on << 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr >= 0xff30 && addr <= 0xff3f) {
|
||||||
|
return channel3.pattern[addr & 15];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APU::mmio_write(uint16 addr, uint8 data) {
|
||||||
|
if(addr == 0xff10) { //NR10
|
||||||
|
channel1.sweep_time = (data >> 4) & 7;
|
||||||
|
channel1.sweep_direction = data & 0x08;
|
||||||
|
channel1.sweep_shift = data & 0x07;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff11) { //NR11
|
||||||
|
channel1.wave_pattern_duty = (data >> 6) & 3;
|
||||||
|
channel1.sound_length = data & 0x3f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff12) { //NR12
|
||||||
|
channel1.initial_envelope_volume = (data >> 4) & 15;
|
||||||
|
channel1.envelope_direction = data & 0x08;
|
||||||
|
channel1.envelope_sweep = data & 0x07;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff13) { //NR13
|
||||||
|
channel1.frequency = (channel1.frequency & 0x0700) | (data << 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff14) { //NR14
|
||||||
|
channel1.initialize = data & 0x80;
|
||||||
|
channel1.consecutive_selection = data & 0x40;
|
||||||
|
channel1.frequency = ((data & 7) << 8) | (channel1.frequency & 0x00ff);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff16) { //NR21
|
||||||
|
channel2.wave_pattern_duty = (data >> 6) & 3;
|
||||||
|
channel2.sound_length = data & 0x3f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff17) { //NR22
|
||||||
|
channel2.initial_envelope_volume = (data >> 4) & 15;
|
||||||
|
channel2.envelope_direction = data & 0x08;
|
||||||
|
channel2.envelope_sweep = data & 0x07;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff18) { //NR23
|
||||||
|
channel2.frequency = (channel2.frequency & 0x0700) | (data << 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff19) { //NR24
|
||||||
|
channel2.initialize = data & 0x80;
|
||||||
|
channel2.consecutive_selection = data & 0x40;
|
||||||
|
channel2.frequency = ((data & 7) << 8) | (channel2.frequency & 0x00ff);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff1a) { //NR30
|
||||||
|
channel3.off = data & 0x80;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff1b) { //NR31
|
||||||
|
channel3.sound_length = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff1c) { //NR32
|
||||||
|
channel3.output_level = (data >> 5) & 3;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff1d) { //NR33
|
||||||
|
channel3.frequency = (channel3.frequency & 0x0700) | (data << 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff1e) { //NR34
|
||||||
|
channel3.initialize = data & 0x80;
|
||||||
|
channel3.consecutive_selection = data & 0x40;
|
||||||
|
channel3.frequency = ((data & 7) << 8) | (channel3.frequency & 0x00ff);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff20) { //NR41
|
||||||
|
channel4.sound_length = data & 0x3f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff21) { //NR42
|
||||||
|
channel4.initial_envelope_volume = (data >> 3) & 15;
|
||||||
|
channel4.envelope_direction = data & 0x08;
|
||||||
|
channel4.envelope_sweep = data & 0x07;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff22) { //NR43
|
||||||
|
channel4.shift_clock_frequency = (data >> 4) & 15;
|
||||||
|
channel4.counter_step_width = data & 0x08;
|
||||||
|
channel4.dividing_ratio = data & 0x07;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff23) { //NR44
|
||||||
|
channel4.initialize = data & 0x80;
|
||||||
|
channel4.consecutive_selection = data & 0x40;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff24) { //NR50
|
||||||
|
control.output_vin_to_so2 = data & 0x80;
|
||||||
|
control.so2_output_level = (data >> 4) & 7;
|
||||||
|
control.output_vin_to_so1 = data & 0x08;
|
||||||
|
control.so1_output_level = (data >> 0) & 7;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff25) { //NR51
|
||||||
|
control.output_channel4_to_so2 = data & 0x80;
|
||||||
|
control.output_channel3_to_so2 = data & 0x40;
|
||||||
|
control.output_channel2_to_so2 = data & 0x20;
|
||||||
|
control.output_channel1_to_so2 = data & 0x10;
|
||||||
|
control.output_channel4_to_so1 = data & 0x08;
|
||||||
|
control.output_channel3_to_so1 = data & 0x04;
|
||||||
|
control.output_channel2_to_so1 = data & 0x02;
|
||||||
|
control.output_channel1_to_so1 = data & 0x01;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr == 0xff26) { //NR52
|
||||||
|
control.sound_on = data & 0x80;
|
||||||
|
control.channel4_on = data & 0x08;
|
||||||
|
control.channel3_on = data & 0x04;
|
||||||
|
control.channel2_on = data & 0x02;
|
||||||
|
control.channel1_on = data & 0x01;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr >= 0xff30 && addr <= 0xff3f) {
|
||||||
|
channel3.pattern[addr & 15] = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,102 @@
|
||||||
|
uint8 mmio_read(uint16 addr);
|
||||||
|
void mmio_write(uint16 addr, uint8 data);
|
||||||
|
|
||||||
|
struct Channel1 { //tone and sweep
|
||||||
|
//$ff10 NR10
|
||||||
|
unsigned sweep_time;
|
||||||
|
bool sweep_direction;
|
||||||
|
unsigned sweep_shift;
|
||||||
|
|
||||||
|
//$ff11 NR11
|
||||||
|
unsigned wave_pattern_duty;
|
||||||
|
unsigned sound_length;
|
||||||
|
|
||||||
|
//$ff12 NR12
|
||||||
|
unsigned initial_envelope_volume;
|
||||||
|
bool envelope_direction;
|
||||||
|
unsigned envelope_sweep;
|
||||||
|
|
||||||
|
//$ff13,$ff14 NR13,NR14
|
||||||
|
unsigned frequency;
|
||||||
|
bool initialize;
|
||||||
|
bool consecutive_selection;
|
||||||
|
} channel1;
|
||||||
|
|
||||||
|
struct Channel2 { //tone
|
||||||
|
//$ff16 NR21
|
||||||
|
unsigned wave_pattern_duty;
|
||||||
|
unsigned sound_length;
|
||||||
|
|
||||||
|
//$ff17 NR22
|
||||||
|
unsigned initial_envelope_volume;
|
||||||
|
bool envelope_direction;
|
||||||
|
unsigned envelope_sweep;
|
||||||
|
|
||||||
|
//$ff18,$ff19 NR23,NR24
|
||||||
|
unsigned frequency;
|
||||||
|
bool initialize;
|
||||||
|
bool consecutive_selection;
|
||||||
|
} channel2;
|
||||||
|
|
||||||
|
struct Channel3 { //wave output
|
||||||
|
//$ff1a NR30
|
||||||
|
bool off;
|
||||||
|
|
||||||
|
//$ff1b NR31
|
||||||
|
unsigned sound_length;
|
||||||
|
|
||||||
|
//$ff1c NR32
|
||||||
|
unsigned output_level;
|
||||||
|
|
||||||
|
//$ff1d,$ff1e NR33,NR34
|
||||||
|
unsigned frequency;
|
||||||
|
bool initialize;
|
||||||
|
bool consecutive_selection;
|
||||||
|
|
||||||
|
//$ff30-ff3f
|
||||||
|
uint8 pattern[16];
|
||||||
|
} channel3;
|
||||||
|
|
||||||
|
struct Channel4 { //noise
|
||||||
|
//$ff20 NR41
|
||||||
|
unsigned sound_length;
|
||||||
|
|
||||||
|
//$ff21 NR42
|
||||||
|
unsigned initial_envelope_volume;
|
||||||
|
bool envelope_direction;
|
||||||
|
unsigned envelope_sweep;
|
||||||
|
|
||||||
|
//$ff22 NR43
|
||||||
|
unsigned shift_clock_frequency;
|
||||||
|
bool counter_step_width;
|
||||||
|
unsigned dividing_ratio;
|
||||||
|
|
||||||
|
//$ff23 NR44
|
||||||
|
bool initialize;
|
||||||
|
bool consecutive_selection;
|
||||||
|
} channel4;
|
||||||
|
|
||||||
|
struct Control {
|
||||||
|
//$ff24 NR50
|
||||||
|
bool output_vin_to_so2;
|
||||||
|
unsigned so2_output_level;
|
||||||
|
bool output_vin_to_so1;
|
||||||
|
unsigned so1_output_level;
|
||||||
|
|
||||||
|
//$ff25 NR51
|
||||||
|
bool output_channel4_to_so2;
|
||||||
|
bool output_channel3_to_so2;
|
||||||
|
bool output_channel2_to_so2;
|
||||||
|
bool output_channel1_to_so2;
|
||||||
|
bool output_channel4_to_so1;
|
||||||
|
bool output_channel3_to_so1;
|
||||||
|
bool output_channel2_to_so1;
|
||||||
|
bool output_channel1_to_so1;
|
||||||
|
|
||||||
|
//$ff26 NR52
|
||||||
|
bool sound_on;
|
||||||
|
bool channel4_on;
|
||||||
|
bool channel3_on;
|
||||||
|
bool channel2_on;
|
||||||
|
bool channel1_on;
|
||||||
|
} control;
|
|
@ -0,0 +1,6 @@
|
||||||
|
#ifdef APU_CPP
|
||||||
|
|
||||||
|
void APU::serialize(serializer &s) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -28,14 +28,30 @@ void CPU::main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::interrupt_raise(CPU::Interrupt id) {
|
void CPU::interrupt_raise(CPU::Interrupt id) {
|
||||||
switch(id) {
|
if(id == Interrupt::Vblank) {
|
||||||
case Interrupt::Vblank: status.interrupt_request_vblank = 1; break;
|
status.interrupt_request_vblank = 1;
|
||||||
case Interrupt::Stat : status.interrupt_request_stat = 1; break;
|
if(status.interrupt_enable_vblank) status.halt = false;
|
||||||
case Interrupt::Timer : status.interrupt_request_timer = 1; break;
|
}
|
||||||
case Interrupt::Serial: status.interrupt_request_serial = 1; break;
|
|
||||||
case Interrupt::Joypad: status.interrupt_request_joypad = 1; status.stop = false; break;
|
if(id == Interrupt::Stat) {
|
||||||
|
status.interrupt_request_stat = 1;
|
||||||
|
if(status.interrupt_enable_stat) status.halt = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(id == Interrupt::Timer) {
|
||||||
|
status.interrupt_request_timer = 1;
|
||||||
|
if(status.interrupt_enable_timer) status.halt = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(id == Interrupt::Serial) {
|
||||||
|
status.interrupt_request_serial = 1;
|
||||||
|
if(status.interrupt_enable_serial) status.halt = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(id == Interrupt::Joypad) {
|
||||||
|
status.interrupt_request_joypad = 1;
|
||||||
|
if(status.interrupt_enable_joypad) status.halt = status.stop = false;
|
||||||
}
|
}
|
||||||
status.halt = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::interrupt_test() {
|
void CPU::interrupt_test() {
|
||||||
|
|
|
@ -72,4 +72,4 @@ struct CPU : Processor, MMIO {
|
||||||
CPU();
|
CPU();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CPU cpu;
|
extern CPU cpu;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
namespace GameBoy {
|
namespace GameBoy {
|
||||||
namespace Info {
|
namespace Info {
|
||||||
static const char Name[] = "bgameboy";
|
static const char Name[] = "bgameboy";
|
||||||
static const char Version[] = "000.11";
|
static const char Version[] = "000.12";
|
||||||
static unsigned SerializerVersion = 1;
|
static unsigned SerializerVersion = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,5 +51,6 @@ namespace GameBoy {
|
||||||
#include <gameboy/scheduler/scheduler.hpp>
|
#include <gameboy/scheduler/scheduler.hpp>
|
||||||
#include <gameboy/cartridge/cartridge.hpp>
|
#include <gameboy/cartridge/cartridge.hpp>
|
||||||
#include <gameboy/cpu/cpu.hpp>
|
#include <gameboy/cpu/cpu.hpp>
|
||||||
|
#include <gameboy/apu/apu.hpp>
|
||||||
#include <gameboy/lcd/lcd.hpp>
|
#include <gameboy/lcd/lcd.hpp>
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,6 +41,7 @@ void System::serialize_all(serializer &s) {
|
||||||
cartridge.serialize(s);
|
cartridge.serialize(s);
|
||||||
system.serialize(s);
|
system.serialize(s);
|
||||||
cpu.serialize(s);
|
cpu.serialize(s);
|
||||||
|
apu.serialize(s);
|
||||||
lcd.serialize(s);
|
lcd.serialize(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ void System::power() {
|
||||||
bus.power();
|
bus.power();
|
||||||
cartridge.power();
|
cartridge.power();
|
||||||
cpu.power();
|
cpu.power();
|
||||||
|
apu.power();
|
||||||
lcd.power();
|
lcd.power();
|
||||||
scheduler.init();
|
scheduler.init();
|
||||||
|
|
||||||
|
|
|
@ -145,10 +145,15 @@ namespace nall {
|
||||||
inline unsigned strlcpy(string &dest, const char *src, unsigned length);
|
inline unsigned strlcpy(string &dest, const char *src, unsigned length);
|
||||||
inline unsigned strlcat(string &dest, const char *src, unsigned length);
|
inline unsigned strlcat(string &dest, const char *src, unsigned length);
|
||||||
inline string substr(const char *src, unsigned start = 0, unsigned length = 0);
|
inline string substr(const char *src, unsigned start = 0, unsigned length = 0);
|
||||||
template<unsigned length = 0, char padding = '0'> inline string hex(uintmax_t value);
|
|
||||||
template<unsigned length = 0, char padding = '0'> inline string integer(intmax_t value);
|
inline string integer(intmax_t value);
|
||||||
template<unsigned length = 0, char padding = '0'> inline string decimal(uintmax_t value);
|
template<unsigned length = 0> inline string linteger(intmax_t value);
|
||||||
template<unsigned length = 0, char padding = '0'> inline string binary(uintmax_t value);
|
template<unsigned length = 0> inline string rinteger(intmax_t value);
|
||||||
|
inline string decimal(uintmax_t value);
|
||||||
|
template<unsigned length = 0> inline string ldecimal(uintmax_t value);
|
||||||
|
template<unsigned length = 0> inline string rdecimal(uintmax_t value);
|
||||||
|
template<unsigned length = 0> inline string hex(uintmax_t value);
|
||||||
|
template<unsigned length = 0> inline string binary(uintmax_t value);
|
||||||
inline unsigned fp(char *str, double value);
|
inline unsigned fp(char *str, double value);
|
||||||
inline string fp(double value);
|
inline string fp(double value);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,151 @@ string substr(const char *src, unsigned start, unsigned length) {
|
||||||
|
|
||||||
/* arithmetic <> string */
|
/* arithmetic <> string */
|
||||||
|
|
||||||
template<unsigned length, char padding> string hex(uintmax_t value) {
|
string integer(intmax_t value) {
|
||||||
|
bool negative = value < 0;
|
||||||
|
if(negative) value = abs(value);
|
||||||
|
|
||||||
|
char buffer[64];
|
||||||
|
unsigned size = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
unsigned n = value % 10;
|
||||||
|
buffer[size++] = '0' + n;
|
||||||
|
value /= 10;
|
||||||
|
} while(value);
|
||||||
|
buffer[size++] = negative ? '-' : '+';
|
||||||
|
buffer[size] = 0;
|
||||||
|
|
||||||
|
char result[size + 1];
|
||||||
|
memset(result, '0', size);
|
||||||
|
result[size] = 0;
|
||||||
|
|
||||||
|
for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||||
|
result[x] = buffer[y];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned length> string linteger(intmax_t value) {
|
||||||
|
bool negative = value < 0;
|
||||||
|
if(negative) value = abs(value);
|
||||||
|
|
||||||
|
char buffer[64];
|
||||||
|
unsigned size = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
unsigned n = value % 10;
|
||||||
|
buffer[size++] = '0' + n;
|
||||||
|
value /= 10;
|
||||||
|
} while(value);
|
||||||
|
buffer[size++] = negative ? '-' : '+';
|
||||||
|
buffer[size] = 0;
|
||||||
|
|
||||||
|
char result[length + 1];
|
||||||
|
memset(result, ' ', length);
|
||||||
|
result[length] = 0;
|
||||||
|
|
||||||
|
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
|
||||||
|
result[x] = buffer[y];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned length> string rinteger(intmax_t value) {
|
||||||
|
bool negative = value < 0;
|
||||||
|
if(negative) value = abs(value);
|
||||||
|
|
||||||
|
char buffer[64];
|
||||||
|
unsigned size = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
unsigned n = value % 10;
|
||||||
|
buffer[size++] = '0' + n;
|
||||||
|
value /= 10;
|
||||||
|
} while(value);
|
||||||
|
buffer[size++] = negative ? '-' : '+';
|
||||||
|
buffer[size] = 0;
|
||||||
|
|
||||||
|
char result[length + 1];
|
||||||
|
memset(result, ' ', length);
|
||||||
|
result[length] = 0;
|
||||||
|
|
||||||
|
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||||
|
result[x] = buffer[y];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
string decimal(uintmax_t value) {
|
||||||
|
char buffer[64];
|
||||||
|
unsigned size = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
unsigned n = value % 10;
|
||||||
|
buffer[size++] = '0' + n;
|
||||||
|
value /= 10;
|
||||||
|
} while(value);
|
||||||
|
buffer[size] = 0;
|
||||||
|
|
||||||
|
char result[size + 1];
|
||||||
|
memset(result, '0', size);
|
||||||
|
result[size] = 0;
|
||||||
|
|
||||||
|
for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||||
|
result[x] = buffer[y];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned length> string ldecimal(uintmax_t value) {
|
||||||
|
char buffer[64];
|
||||||
|
unsigned size = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
unsigned n = value % 10;
|
||||||
|
buffer[size++] = '0' + n;
|
||||||
|
value /= 10;
|
||||||
|
} while(value);
|
||||||
|
buffer[size] = 0;
|
||||||
|
|
||||||
|
char result[length + 1];
|
||||||
|
memset(result, ' ', length);
|
||||||
|
result[length] = 0;
|
||||||
|
|
||||||
|
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
|
||||||
|
result[x] = buffer[y];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned length> string rdecimal(uintmax_t value) {
|
||||||
|
char buffer[64];
|
||||||
|
unsigned size = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
unsigned n = value % 10;
|
||||||
|
buffer[size++] = '0' + n;
|
||||||
|
value /= 10;
|
||||||
|
} while(value);
|
||||||
|
buffer[size] = 0;
|
||||||
|
|
||||||
|
char result[length + 1];
|
||||||
|
memset(result, ' ', length);
|
||||||
|
result[length] = 0;
|
||||||
|
|
||||||
|
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
|
||||||
|
result[x] = buffer[y];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned length> string hex(uintmax_t value) {
|
||||||
string output;
|
string output;
|
||||||
unsigned offset = 0;
|
unsigned offset = 0;
|
||||||
|
|
||||||
|
@ -38,7 +182,7 @@ template<unsigned length, char padding> string hex(uintmax_t value) {
|
||||||
value >>= 4;
|
value >>= 4;
|
||||||
} while(value);
|
} while(value);
|
||||||
|
|
||||||
while(offset < length) output[offset++] = padding;
|
while(offset < length) output[offset++] = '0';
|
||||||
output[offset--] = 0;
|
output[offset--] = 0;
|
||||||
|
|
||||||
//reverse the string in-place
|
//reverse the string in-place
|
||||||
|
@ -51,55 +195,7 @@ template<unsigned length, char padding> string hex(uintmax_t value) {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned length, char padding> string integer(intmax_t value) {
|
template<unsigned length> string binary(uintmax_t value) {
|
||||||
string output;
|
|
||||||
unsigned offset = 0;
|
|
||||||
|
|
||||||
bool negative = value < 0;
|
|
||||||
if(negative) value = abs(value);
|
|
||||||
|
|
||||||
do {
|
|
||||||
unsigned n = value % 10;
|
|
||||||
output[offset++] = '0' + n;
|
|
||||||
value /= 10;
|
|
||||||
} while(value);
|
|
||||||
|
|
||||||
while(offset < length) output[offset++] = padding;
|
|
||||||
if(negative) output[offset++] = '-';
|
|
||||||
output[offset--] = 0;
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
|
||||||
char temp = output[i];
|
|
||||||
output[i] = output[offset - i];
|
|
||||||
output[offset - i] = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned length, char padding> string decimal(uintmax_t value) {
|
|
||||||
string output;
|
|
||||||
unsigned offset = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
unsigned n = value % 10;
|
|
||||||
output[offset++] = '0' + n;
|
|
||||||
value /= 10;
|
|
||||||
} while(value);
|
|
||||||
|
|
||||||
while(offset < length) output[offset++] = padding;
|
|
||||||
output[offset--] = 0;
|
|
||||||
|
|
||||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
|
||||||
char temp = output[i];
|
|
||||||
output[i] = output[offset - i];
|
|
||||||
output[offset - i] = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned length, char padding> string binary(uintmax_t value) {
|
|
||||||
string output;
|
string output;
|
||||||
unsigned offset = 0;
|
unsigned offset = 0;
|
||||||
|
|
||||||
|
@ -109,7 +205,7 @@ template<unsigned length, char padding> string binary(uintmax_t value) {
|
||||||
value >>= 1;
|
value >>= 1;
|
||||||
} while(value);
|
} while(value);
|
||||||
|
|
||||||
while(offset < length) output[offset++] = padding;
|
while(offset < length) output[offset++] = '0';
|
||||||
output[offset--] = 0;
|
output[offset--] = 0;
|
||||||
|
|
||||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
namespace Info {
|
namespace Info {
|
||||||
static const char Name[] = "bsnes";
|
static const char Name[] = "bsnes";
|
||||||
static const char Version[] = "074.07";
|
static const char Version[] = "074.08";
|
||||||
static const unsigned SerializerVersion = 17;
|
static const unsigned SerializerVersion = 17;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@ void Interface::video_refresh(const uint16_t *data, unsigned width, unsigned hei
|
||||||
video.refresh();
|
video.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
static signed frameCounter = 0;
|
static unsigned frameCounter = 0;
|
||||||
static time_t previous, current;
|
static time_t previous, current;
|
||||||
frameCounter++;
|
frameCounter++;
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ void CheatEditor::load(string filename) {
|
||||||
cheatList.reset();
|
cheatList.reset();
|
||||||
for(unsigned i = 0; i < 128; i++) {
|
for(unsigned i = 0; i < 128; i++) {
|
||||||
cheatList.addItem("");
|
cheatList.addItem("");
|
||||||
cheatText[i][CheatSlot] = decimal<3, ' '>(i + 1);
|
cheatText[i][CheatSlot] = rdecimal<3>(i + 1);
|
||||||
cheatText[i][CheatCode] = "";
|
cheatText[i][CheatCode] = "";
|
||||||
cheatText[i][CheatDesc] = "";
|
cheatText[i][CheatDesc] = "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ void StateManager::synchronize() {
|
||||||
void StateManager::refresh() {
|
void StateManager::refresh() {
|
||||||
for(unsigned i = 0; i < 32; i++) {
|
for(unsigned i = 0; i < 32; i++) {
|
||||||
stateList.setItem(i, {
|
stateList.setItem(i, {
|
||||||
decimal<2, ' '>(i + 1), "\t",
|
rdecimal<2>(i + 1), "\t",
|
||||||
slotLoadDescription(i)
|
slotLoadDescription(i)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue