mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-14 15:42:07 +02:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
6b4104867f | ||
|
53fe43afd8 | ||
|
054bdd4094 | ||
|
ecf96726f9 | ||
|
cab5917806 | ||
|
c833b69087 | ||
|
1a065bafb1 | ||
|
ea077a7d96 | ||
|
a937f9b79b | ||
|
2d73086569 | ||
|
5810e69be3 | ||
|
a198e555dc |
@@ -48,39 +48,10 @@ all: build;
|
||||
|
||||
obj/libco.o: libco/libco.c libco/*
|
||||
|
||||
include $(snes)/Makefile
|
||||
include $(gameboy)/Makefile
|
||||
include $(ui)/Makefile
|
||||
|
||||
objects := $(patsubst %,obj/%.o,$(objects))
|
||||
|
||||
# targets
|
||||
build: ui_build $(objects)
|
||||
ifeq ($(platform),osx)
|
||||
test -d ../bsnes.app || mkdir -p ../bsnes.app/Contents/MacOS
|
||||
$(strip $(cpp) -o ../bsnes.app/Contents/MacOS/bsnes $(objects) $(link))
|
||||
else
|
||||
$(strip $(cpp) -o out/bsnes $(objects) $(link))
|
||||
endif
|
||||
|
||||
install:
|
||||
ifeq ($(platform),x)
|
||||
install -D -m 755 out/bsnes $(DESTDIR)$(prefix)/bin/bsnes
|
||||
install -D -m 644 data/bsnes.png $(DESTDIR)$(prefix)/share/pixmaps/bsnes.png
|
||||
install -D -m 644 data/bsnes.desktop $(DESTDIR)$(prefix)/share/applications/bsnes.desktop
|
||||
test -d ~/.bsnes || mkdir ~/.bsnes
|
||||
cp data/cheats.xml ~/.bsnes/cheats.xml
|
||||
chmod 777 ~/.bsnes ~/.bsnes/cheats.xml
|
||||
endif
|
||||
|
||||
uninstall:
|
||||
ifeq ($(platform),x)
|
||||
rm $(DESTDIR)$(prefix)/bin/bsnes
|
||||
rm $(DESTDIR)$(prefix)/share/pixmaps/bsnes.png
|
||||
rm $(DESTDIR)$(prefix)/share/applications/bsnes.desktop
|
||||
endif
|
||||
|
||||
clean: ui_clean
|
||||
clean:
|
||||
-@$(call delete,obj/*.o)
|
||||
-@$(call delete,obj/*.a)
|
||||
-@$(call delete,obj/*.so)
|
||||
@@ -94,6 +65,6 @@ clean: ui_clean
|
||||
-@$(call delete,*.manifest)
|
||||
|
||||
archive-all:
|
||||
tar -cjf bsnes.tar.bz2 data gameboy launcher libco nall obj out phoenix ruby snes ui ui-gameboy Makefile cc.bat clean.bat sync.sh
|
||||
tar -cjf bsnes.tar.bz2 data gameboy libco nall obj out phoenix ruby snes ui ui-gameboy Makefile cc.bat clean.bat sync.sh
|
||||
|
||||
help:;
|
||||
|
12893
bsnes/data/cheats.xml
12893
bsnes/data/cheats.xml
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
gameboy_objects := gameboy-system gameboy-scheduler
|
||||
gameboy_objects += gameboy-memory gameboy-cartridge
|
||||
gameboy_objects += gameboy-cpu gameboy-lcd
|
||||
gameboy_objects += gameboy-cpu gameboy-apu gameboy-lcd
|
||||
objects += $(gameboy_objects)
|
||||
|
||||
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-memory.o: $(gameboy)/memory/memory.cpp $(call rwildcard,$(gameboy)/memory/)
|
||||
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/)
|
||||
|
85
bsnes/gameboy/apu/apu.cpp
Executable file
85
bsnes/gameboy/apu/apu.cpp
Executable file
@@ -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;
|
||||
}
|
||||
|
||||
}
|
9
bsnes/gameboy/apu/apu.hpp
Executable file
9
bsnes/gameboy/apu/apu.hpp
Executable file
@@ -0,0 +1,9 @@
|
||||
struct APU : Processor, MMIO {
|
||||
#include "mmio/mmio.hpp"
|
||||
|
||||
void power();
|
||||
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
||||
extern APU apu;
|
248
bsnes/gameboy/apu/mmio/mmio.cpp
Executable file
248
bsnes/gameboy/apu/mmio/mmio.cpp
Executable file
@@ -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
|
102
bsnes/gameboy/apu/mmio/mmio.hpp
Executable file
102
bsnes/gameboy/apu/mmio/mmio.hpp
Executable file
@@ -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;
|
6
bsnes/gameboy/apu/serialization.cpp
Executable file
6
bsnes/gameboy/apu/serialization.cpp
Executable file
@@ -0,0 +1,6 @@
|
||||
#ifdef APU_CPP
|
||||
|
||||
void APU::serialize(serializer &s) {
|
||||
}
|
||||
|
||||
#endif
|
@@ -16,13 +16,14 @@ namespace GameBoy {
|
||||
#include "serialization.cpp"
|
||||
Cartridge cartridge;
|
||||
|
||||
void Cartridge::load(const string &xml, uint8_t *data, unsigned size) {
|
||||
void Cartridge::load(const string &xml, const uint8_t *data, unsigned size) {
|
||||
if(size == 0) size = 32768;
|
||||
romdata = allocate<uint8>(romsize = size, 0xff);
|
||||
if(data) memcpy(romdata, data, size);
|
||||
|
||||
//uint32_t crc = crc32_calculate(data, size);
|
||||
//print("CRC32 = ", hex<4>(crc), "\n");
|
||||
|
||||
romdata = new uint8[romsize = size];
|
||||
memcpy(romdata, data, size);
|
||||
|
||||
info.mapper = Mapper::Unknown;
|
||||
info.ram = false;
|
||||
info.battery = false;
|
||||
|
@@ -41,7 +41,7 @@ struct Cartridge : property<Cartridge> {
|
||||
uint8_t *ramdata;
|
||||
unsigned ramsize;
|
||||
|
||||
void load(const string &xml, uint8_t *data, unsigned size);
|
||||
void load(const string &xml, const uint8_t *data, unsigned size);
|
||||
void unload();
|
||||
|
||||
uint8 rom_read(unsigned addr);
|
||||
|
@@ -1,15 +1,15 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::HuC1::mmio_read(uint16 addr) {
|
||||
if((addr & 0xc000) == 0x0000) { //0000-3fff
|
||||
if(within<0x0000, 0x3fff>(addr)) {
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
||||
if((addr & 0xc000) == 0x4000) { //4000-7fff
|
||||
if(within<0x4000, 0x7fff>(addr)) {
|
||||
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0xa000) { //a000-bfff
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
|
||||
return 0x00;
|
||||
}
|
||||
@@ -18,27 +18,27 @@ uint8 Cartridge::HuC1::mmio_read(uint16 addr) {
|
||||
}
|
||||
|
||||
void Cartridge::HuC1::mmio_write(uint16 addr, uint8 data) {
|
||||
if((addr & 0xe000) == 0x0000) { //0000-1fff
|
||||
if(within<0x0000, 0x1fff>(addr)) {
|
||||
ram_enable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x2000) { //2000-3fff
|
||||
if(within<0x2000, 0x3fff>(addr)) {
|
||||
rom_select = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x4000) { //4000-5fff
|
||||
if(within<0x4000, 0x5fff>(addr)) {
|
||||
ram_select = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x6000) { //6000-7fff
|
||||
if(within<0x6000, 0x7fff>(addr)) {
|
||||
//unknown purpose
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0xa000) { //a000-bfff
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
|
||||
return;
|
||||
}
|
||||
|
@@ -1,15 +1,15 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::HuC3::mmio_read(uint16 addr) {
|
||||
if((addr & 0xc000) == 0x0000) { //0000-3fff
|
||||
if(within<0x0000, 0x3fff>(addr)) {
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
||||
if((addr & 0xc000) == 0x4000) { //4000-7fff
|
||||
if(within<0x4000, 0x7fff>(addr)) {
|
||||
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0xa000) { //a000-bfff
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
|
||||
return 0x00;
|
||||
}
|
||||
@@ -18,27 +18,27 @@ uint8 Cartridge::HuC3::mmio_read(uint16 addr) {
|
||||
}
|
||||
|
||||
void Cartridge::HuC3::mmio_write(uint16 addr, uint8 data) {
|
||||
if((addr & 0xe000) == 0x0000) { //0000-1fff
|
||||
if(within<0x0000, 0x1fff>(addr)) {
|
||||
ram_enable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x2000) { //2000-3fff
|
||||
if(within<0x2000, 0x3fff>(addr)) {
|
||||
rom_select = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x4000) { //4000-5fff
|
||||
if(within<0x4000, 0x5fff>(addr)) {
|
||||
ram_select = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x6000) { //6000-7fff
|
||||
if(within<0x6000, 0x7fff>(addr)) {
|
||||
//unknown purpose
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0xa000) { //a000-bfff
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
|
||||
return;
|
||||
}
|
||||
|
@@ -1,11 +1,11 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::MBC0::mmio_read(uint16 addr) {
|
||||
if((addr & 0x8000) == 0x0000) { //0000-7fff
|
||||
if(within<0x0000, 0x7fff>(addr)) {
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0xa000) { //a000-bfff
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
return cartridge.ram_read(addr & 0x1fff);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ uint8 Cartridge::MBC0::mmio_read(uint16 addr) {
|
||||
}
|
||||
|
||||
void Cartridge::MBC0::mmio_write(uint16 addr, uint8 data) {
|
||||
if((addr & 0xe000) == 0xa000) { //a000-bfff
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
cartridge.ram_write(addr & 0x1fff, data);
|
||||
return;
|
||||
}
|
||||
|
@@ -1,11 +1,11 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
|
||||
if((addr & 0xc000) == 0x0000) { //0000-3fff
|
||||
if(within<0x0000, 0x3fff>(addr)) {
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
||||
if((addr & 0xc000) == 0x4000) { //4000-7fff
|
||||
if(within<0x4000, 0x7fff>(addr)) {
|
||||
if(mode_select == 0) {
|
||||
return cartridge.rom_read((ram_select << 19) | (rom_select << 14) | (addr & 0x3fff));
|
||||
} else {
|
||||
@@ -13,7 +13,7 @@ uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
|
||||
}
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0xa000) { //a000-bfff
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
if(ram_enable) {
|
||||
if(mode_select == 0) {
|
||||
return cartridge.ram_read(addr & 0x1fff);
|
||||
@@ -28,27 +28,27 @@ uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
|
||||
}
|
||||
|
||||
void Cartridge::MBC1::mmio_write(uint16 addr, uint8 data) {
|
||||
if((addr & 0xe000) == 0x0000) { //0000-1fff
|
||||
if(within<0x0000, 0x1fff>(addr)) {
|
||||
ram_enable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x2000) { //2000-3fff
|
||||
if(within<0x2000, 0x3fff>(addr)) {
|
||||
rom_select = (data & 0x1f) + ((data & 0x1f) == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x4000) { //4000-5fff
|
||||
if(within<0x4000, 0x5fff>(addr)) {
|
||||
ram_select = data & 0x03;
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x6000) { //6000-7fff
|
||||
if(within<0x6000, 0x7fff>(addr)) {
|
||||
mode_select = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0xa000) { //a000-bfff
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
if(ram_enable) {
|
||||
if(mode_select == 0) {
|
||||
cartridge.ram_write(addr & 0x1fff, data);
|
||||
|
@@ -1,15 +1,15 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::MBC2::mmio_read(uint16 addr) {
|
||||
if((addr & 0xc000) == 0x0000) { //0000-3fff
|
||||
if(within<0x0000, 0x3fff>(addr)) {
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
||||
if((addr & 0xc000) == 0x4000) { //4000-7fff
|
||||
if(within<0x4000, 0x7fff>(addr)) {
|
||||
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
|
||||
}
|
||||
|
||||
if((addr & 0xfe00) == 0xa000) { //a000-a1ff
|
||||
if(within<0xa000, 0xa1ff>(addr)) {
|
||||
if(ram_enable) return cartridge.ram_read(addr & 0x1ff);
|
||||
return 0x00;
|
||||
}
|
||||
@@ -18,17 +18,17 @@ uint8 Cartridge::MBC2::mmio_read(uint16 addr) {
|
||||
}
|
||||
|
||||
void Cartridge::MBC2::mmio_write(uint16 addr, uint8 data) {
|
||||
if((addr & 0xe100) == 0x0000) { //0000-1fff [d8=0]
|
||||
ram_enable = (data & 0x0f) == 0x0a;
|
||||
if(within<0x0000, 0x1fff>(addr)) {
|
||||
if(!(addr & 0x0100)) ram_enable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe100) == 0x2100) { //2000-3fff [d8=1]
|
||||
rom_select = (data & 0x0f) + ((data & 0x0f) == 0);
|
||||
if(within<0x2000, 0x3fff>(addr)) {
|
||||
if( (addr & 0x0100)) rom_select = (data & 0x0f) + ((data & 0x0f) == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xfe00) == 0xa000) { //a000-a1ff
|
||||
if(within<0xa000, 0xa1ff>(addr)) {
|
||||
if(ram_enable) cartridge.ram_write(addr & 0x1ff, data & 0x0f);
|
||||
return;
|
||||
}
|
||||
|
@@ -19,15 +19,15 @@ void Cartridge::MBC3::second() {
|
||||
}
|
||||
|
||||
uint8 Cartridge::MBC3::mmio_read(uint16 addr) {
|
||||
if((addr & 0xc000) == 0x0000) { //0000-3fff
|
||||
if(within<0x0000, 0x3fff>(addr)) {
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
||||
if((addr & 0xc000) == 0x4000) { //4000-7fff
|
||||
if(within<0x4000, 0x7fff>(addr)) {
|
||||
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0xa000) { //a000-bfff
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
if(ram_enable) {
|
||||
if(ram_select >= 0x00 && ram_select <= 0x03) {
|
||||
return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
|
||||
@@ -45,22 +45,22 @@ uint8 Cartridge::MBC3::mmio_read(uint16 addr) {
|
||||
}
|
||||
|
||||
void Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) {
|
||||
if((addr & 0xe000) == 0x0000) { //0000-1fff
|
||||
if(within<0x0000, 0x1fff>(addr)) {
|
||||
ram_enable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x2000) { //2000-3fff
|
||||
if(within<0x2000, 0x3fff>(addr)) {
|
||||
rom_select = (data & 0x7f) + ((data & 0x7f) == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x4000) { //4000-5fff
|
||||
if(within<0x4000, 0x5fff>(addr)) {
|
||||
ram_select = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x6000) { //6000-7fff
|
||||
if(within<0x6000, 0x7fff>(addr)) {
|
||||
if(rtc_latch == 0 && data == 1) {
|
||||
rtc_latch_second = rtc_second;
|
||||
rtc_latch_minute = rtc_minute;
|
||||
@@ -72,7 +72,7 @@ void Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0xa000) { //a000-bfff
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
if(ram_enable) {
|
||||
if(ram_select >= 0x00 && ram_select <= 0x03) {
|
||||
cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
|
||||
|
@@ -1,15 +1,15 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::MBC5::mmio_read(uint16 addr) {
|
||||
if((addr & 0xc000) == 0x0000) { //0000-3fff
|
||||
if(within<0x0000, 0x3fff>(addr)) {
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
||||
if((addr & 0xc000) == 0x4000) { //4000-7fff
|
||||
if(within<0x4000, 0x7fff>(addr)) {
|
||||
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0xa000) { //a000-bfff
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
|
||||
return 0x00;
|
||||
}
|
||||
@@ -18,27 +18,27 @@ uint8 Cartridge::MBC5::mmio_read(uint16 addr) {
|
||||
}
|
||||
|
||||
void Cartridge::MBC5::mmio_write(uint16 addr, uint8 data) {
|
||||
if((addr & 0xe000) == 0x0000) { //0000-1fff
|
||||
if(within<0x0000, 0x1fff>(addr)) {
|
||||
ram_enable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xf000) == 0x2000) { //2000-2fff
|
||||
if(within<0x2000, 0x2fff>(addr)) {
|
||||
rom_select = (rom_select & 0x0100) | data;
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xf000) == 0x3000) { //3000-3fff
|
||||
if(within<0x3000, 0x3fff>(addr)) {
|
||||
rom_select = ((data & 1) << 8) | (rom_select & 0x00ff);
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x4000) { //4000-5fff
|
||||
if(within<0x4000, 0x5fff>(addr)) {
|
||||
ram_select = data & 0x0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0xa000) { //a000-bfff
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
|
||||
return;
|
||||
}
|
||||
|
@@ -1,19 +1,19 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::MMM01::mmio_read(uint16 addr) {
|
||||
if((addr & 0x8000) == 0x0000) {
|
||||
if(within<0x0000, 0x7fff>(addr)) {
|
||||
if(rom_mode == 0) return cartridge.rom_read(addr);
|
||||
}
|
||||
|
||||
if((addr & 0xc000) == 0x0000) {
|
||||
if(within<0x0000, 0x3fff>(addr)) {
|
||||
return cartridge.rom_read(0x8000 + (rom_base << 14) + (addr & 0x3fff));
|
||||
}
|
||||
|
||||
if((addr & 0xc000) == 0x4000) {
|
||||
if(within<0x4000, 0x7fff>(addr)) {
|
||||
return cartridge.rom_read(0x8000 + (rom_base << 14) + (rom_select << 14) + (addr & 0x3fff));
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0xa000) {
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
if(ram_enable) return cartridge.ram_read((ram_select << 13) + (addr & 0x1fff));
|
||||
return 0x00;
|
||||
}
|
||||
@@ -22,7 +22,7 @@ uint8 Cartridge::MMM01::mmio_read(uint16 addr) {
|
||||
}
|
||||
|
||||
void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
|
||||
if((addr & 0xe000) == 0x0000) { //0000-1fff
|
||||
if(within<0x0000, 0x1fff>(addr)) {
|
||||
if(rom_mode == 0) {
|
||||
rom_mode = 1;
|
||||
} else {
|
||||
@@ -30,7 +30,7 @@ void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
|
||||
}
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x2000) { //2000-3fff
|
||||
if(within<0x2000, 0x3fff>(addr)) {
|
||||
if(rom_mode == 0) {
|
||||
rom_base = data & 0x3f;
|
||||
} else {
|
||||
@@ -38,17 +38,17 @@ void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
|
||||
}
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x4000) { //4000-5fff
|
||||
if(within<0x4000, 0x5fff>(addr)) {
|
||||
if(rom_mode == 1) {
|
||||
ram_select = data;
|
||||
}
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0x6000) { //6000-7fff
|
||||
if(within<0x6000, 0x7fff>(addr)) {
|
||||
//unknown purpose
|
||||
}
|
||||
|
||||
if((addr & 0xe000) == 0xa000) { //a000-bfff
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
if(ram_enable) cartridge.ram_write((ram_select << 13) + (addr & 0x1fff), data);
|
||||
}
|
||||
}
|
||||
|
@@ -28,14 +28,30 @@ void CPU::main() {
|
||||
}
|
||||
|
||||
void CPU::interrupt_raise(CPU::Interrupt id) {
|
||||
switch(id) {
|
||||
case Interrupt::Vblank: status.interrupt_request_vblank = 1; break;
|
||||
case Interrupt::Stat : status.interrupt_request_stat = 1; break;
|
||||
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::Vblank) {
|
||||
status.interrupt_request_vblank = 1;
|
||||
if(status.interrupt_enable_vblank) status.halt = false;
|
||||
}
|
||||
|
||||
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() {
|
||||
@@ -104,12 +120,19 @@ void CPU::power() {
|
||||
status.timer1 = 0;
|
||||
status.timer2 = 0;
|
||||
status.timer3 = 0;
|
||||
status.timer4 = 0;
|
||||
|
||||
status.p15 = 0;
|
||||
status.p14 = 0;
|
||||
status.joyp = 0;
|
||||
status.mlt_req = 0;
|
||||
|
||||
status.serial_data = 0;
|
||||
status.serial_bits = 0;
|
||||
|
||||
status.serial_transfer = 0;
|
||||
status.serial_clock = 0;
|
||||
|
||||
status.div = 0;
|
||||
|
||||
status.tima = 0;
|
||||
|
@@ -23,6 +23,7 @@ struct CPU : Processor, MMIO {
|
||||
unsigned timer1;
|
||||
unsigned timer2;
|
||||
unsigned timer3;
|
||||
unsigned timer4;
|
||||
|
||||
//$ff00 JOYP
|
||||
bool p15;
|
||||
@@ -30,6 +31,14 @@ struct CPU : Processor, MMIO {
|
||||
uint8 joyp;
|
||||
uint8 mlt_req;
|
||||
|
||||
//$ff01 SB
|
||||
uint8 serial_data;
|
||||
unsigned serial_bits;
|
||||
|
||||
//$ff02 SC
|
||||
bool serial_transfer;
|
||||
bool serial_clock;
|
||||
|
||||
//$ff04 DIV
|
||||
uint8 div;
|
||||
|
||||
@@ -72,4 +81,4 @@ struct CPU : Processor, MMIO {
|
||||
CPU();
|
||||
};
|
||||
|
||||
extern CPU cpu;
|
||||
extern CPU cpu;
|
||||
|
@@ -31,6 +31,15 @@ uint8 CPU::mmio_read(uint16 addr) {
|
||||
| (status.joyp << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff01) { //SB
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
if(addr == 0xff02) { //SC
|
||||
return (status.serial_transfer << 7)
|
||||
| (status.serial_clock << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff04) { //DIV
|
||||
return status.div;
|
||||
}
|
||||
@@ -81,10 +90,14 @@ void CPU::mmio_write(uint16 addr, uint8 data) {
|
||||
}
|
||||
|
||||
if(addr == 0xff01) { //SB
|
||||
status.serial_data = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff02) { //SC
|
||||
status.serial_transfer = data & 0x80;
|
||||
status.serial_clock = data & 0x01;
|
||||
if(status.serial_transfer) status.serial_bits = 8;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -27,12 +27,19 @@ void CPU::serialize(serializer &s) {
|
||||
s.integer(status.timer1);
|
||||
s.integer(status.timer2);
|
||||
s.integer(status.timer3);
|
||||
s.integer(status.timer4);
|
||||
|
||||
s.integer(status.p15);
|
||||
s.integer(status.p14);
|
||||
s.integer(status.joyp);
|
||||
s.integer(status.mlt_req);
|
||||
|
||||
s.integer(status.serial_data);
|
||||
s.integer(status.serial_bits);
|
||||
|
||||
s.integer(status.serial_transfer);
|
||||
s.integer(status.serial_clock);
|
||||
|
||||
s.integer(status.div);
|
||||
s.integer(status.tima);
|
||||
s.integer(status.tma);
|
||||
|
@@ -64,10 +64,22 @@ void CPU::timer_stage2() { // 16384hz
|
||||
status.div++;
|
||||
|
||||
status.timer2 -= 4;
|
||||
if(++status.timer3 >= 4) timer_stage3();
|
||||
if(++status.timer3 >= 2) timer_stage3();
|
||||
}
|
||||
|
||||
void CPU::timer_stage3() { // 4096hz
|
||||
void CPU::timer_stage3() { // 8192hz
|
||||
if(status.serial_transfer && status.serial_clock) {
|
||||
if(--status.serial_bits == 0) {
|
||||
status.serial_transfer = 0;
|
||||
interrupt_raise(Interrupt::Serial);
|
||||
}
|
||||
}
|
||||
|
||||
status.timer3 -= 2;
|
||||
if(++status.timer4 >= 2) timer_stage4();
|
||||
}
|
||||
|
||||
void CPU::timer_stage4() { // 4096hz
|
||||
if(status.timer_enable && status.timer_clock == 0) {
|
||||
if(++status.tima == 0) {
|
||||
status.tima = status.tma;
|
||||
@@ -75,7 +87,7 @@ void CPU::timer_stage3() { // 4096hz
|
||||
}
|
||||
}
|
||||
|
||||
status.timer3 -= 4;
|
||||
status.timer4 -= 2;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -3,6 +3,7 @@ void timer_stage0();
|
||||
void timer_stage1();
|
||||
void timer_stage2();
|
||||
void timer_stage3();
|
||||
void timer_stage4();
|
||||
|
||||
//opcode.cpp
|
||||
void op_io();
|
||||
|
@@ -5,7 +5,7 @@
|
||||
namespace GameBoy {
|
||||
namespace Info {
|
||||
static const char Name[] = "bgameboy";
|
||||
static const char Version[] = "000.11";
|
||||
static const char Version[] = "000.13";
|
||||
static unsigned SerializerVersion = 1;
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,12 @@ namespace GameBoy {
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
template<uint16 lo, uint16 hi>
|
||||
alwaysinline bool within(uint16 addr) {
|
||||
static const uint16 mask = ~(hi ^ lo);
|
||||
return (addr & mask) == lo;
|
||||
}
|
||||
|
||||
struct Processor {
|
||||
cothread_t thread;
|
||||
unsigned frequency;
|
||||
@@ -51,5 +57,6 @@ namespace GameBoy {
|
||||
#include <gameboy/scheduler/scheduler.hpp>
|
||||
#include <gameboy/cartridge/cartridge.hpp>
|
||||
#include <gameboy/cpu/cpu.hpp>
|
||||
#include <gameboy/apu/apu.hpp>
|
||||
#include <gameboy/lcd/lcd.hpp>
|
||||
};
|
||||
|
@@ -19,7 +19,11 @@ void LCD::main() {
|
||||
|
||||
add_clocks(4);
|
||||
|
||||
if(status.lx == 320) {
|
||||
if(status.lx == 0) {
|
||||
if(status.interrupt_oam) cpu.interrupt_raise(CPU::Interrupt::Stat);
|
||||
}
|
||||
|
||||
if(status.lx == 252) {
|
||||
if(status.interrupt_hblank) cpu.interrupt_raise(CPU::Interrupt::Stat);
|
||||
}
|
||||
}
|
||||
|
@@ -17,9 +17,10 @@ uint8 LCD::mmio_read(uint16 addr) {
|
||||
|
||||
if(addr == 0xff41) { //STAT
|
||||
unsigned mode;
|
||||
if(status.ly >= 144) mode = 1; //Vblank
|
||||
else if(status.lx >= 320) mode = 0; //Hblank
|
||||
else mode = 3; //LCD transfer
|
||||
if(status.ly >= 144) mode = 1; //Vblank
|
||||
else if(status.lx < 80) mode = 2; //OAM
|
||||
else if(status.lx < 252) mode = 3; //LCD
|
||||
else mode = 0; //Hblank
|
||||
|
||||
return (status.interrupt_lyc << 6)
|
||||
| (status.interrupt_oam << 5)
|
||||
|
@@ -41,6 +41,7 @@ void System::serialize_all(serializer &s) {
|
||||
cartridge.serialize(s);
|
||||
system.serialize(s);
|
||||
cpu.serialize(s);
|
||||
apu.serialize(s);
|
||||
lcd.serialize(s);
|
||||
}
|
||||
|
||||
|
@@ -54,6 +54,7 @@ void System::power() {
|
||||
bus.power();
|
||||
cartridge.power();
|
||||
cpu.power();
|
||||
apu.power();
|
||||
lcd.power();
|
||||
scheduler.init();
|
||||
|
||||
|
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity type="win32" name="bsnes" version="1.0.0.0" processorArchitecture="x86"/>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*"/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
</assembly>
|
Binary file not shown.
Before Width: | Height: | Size: 22 KiB |
@@ -1,4 +0,0 @@
|
||||
@windres resource.rc resource.o
|
||||
@mingw32-g++ -std=gnu++0x -mwindows -s -O3 -fomit-frame-pointer -I.. -o ../out/bsnes launcher.cpp resource.o
|
||||
@del *.o
|
||||
@pause
|
@@ -1,2 +0,0 @@
|
||||
clear
|
||||
g++ -std=gnu++0x -s -O3 -fomit-frame-pointer -I.. -o ../out/bsnes launcher.cpp
|
@@ -1,54 +0,0 @@
|
||||
#include <nall/config.hpp>
|
||||
#include <nall/detect.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/foreach.hpp>
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
using namespace nall;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char path[PATH_MAX], *unused;
|
||||
#if !defined(PLATFORM_WIN)
|
||||
unused = realpath(argv[0], path);
|
||||
#else
|
||||
wchar_t **argw = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
unused = realpath(nall::utf8_t(argw[0]), path);
|
||||
#endif
|
||||
string realPath = dir(path);
|
||||
string basePath = string(dir(path), "bsnes-qt.cfg");
|
||||
unused = userpath(path);
|
||||
if(!strend(path, "/") && !strend(path, "\\")) strcat(path, "/");
|
||||
string userPath = string(path, ".bsnes/bsnes-qt.cfg");
|
||||
|
||||
configuration config;
|
||||
string profile;
|
||||
config.attach(profile = "", "system.profile");
|
||||
if(config.load(userPath) == false) config.load(basePath);
|
||||
if(profile == "") profile = "compatibility";
|
||||
|
||||
string binaryName = string("bsnes-", profile);
|
||||
#if defined(PLATFORM_WIN)
|
||||
binaryName << ".dll";
|
||||
#endif
|
||||
string fileName = string(realPath, binaryName);
|
||||
|
||||
#if !defined(PLATFORM_WIN)
|
||||
char **args = new char*[argc + 1];
|
||||
args[0] = strdup(binaryName);
|
||||
for(unsigned i = 1; i < argc; i++) args[i] = strdup(argv[i]);
|
||||
args[argc] = 0;
|
||||
execvp(args[0], args);
|
||||
execv(fileName, args);
|
||||
print("[bsnes] Error: unable to locate binary file: ", binaryName, "\n");
|
||||
#else
|
||||
STARTUPINFOW si;
|
||||
PROCESS_INFORMATION pi;
|
||||
memset(&si, 0, sizeof(STARTUPINFOW));
|
||||
if(!CreateProcessW(nall::utf16_t(fileName), GetCommandLineW(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
|
||||
MessageBoxA(0, string("Error: unable to locate binary file: ", binaryName), "bsnes", MB_OK);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
@@ -1,2 +0,0 @@
|
||||
1 24 "bsnes.Manifest"
|
||||
IDI_ICON1 ICON DISCARDABLE "bsnes.ico"
|
@@ -27,7 +27,7 @@ namespace nall {
|
||||
};
|
||||
|
||||
template<typename L> struct lambda : container {
|
||||
L object;
|
||||
mutable L object;
|
||||
R operator()(P... p) const { return object(std::forward<P>(p)...); }
|
||||
container* copy() const { return new lambda(object); }
|
||||
lambda(const L& object) : object(object) {}
|
||||
@@ -46,7 +46,7 @@ namespace nall {
|
||||
return *this;
|
||||
}
|
||||
|
||||
function(const function &source) { operator=(source); }
|
||||
function(const function &source) : callback(0) { operator=(source); }
|
||||
function() : callback(0) {}
|
||||
function(void *function) : callback(0) { if(function) callback = new global((R (*)(P...))function); }
|
||||
function(R (*function)(P...)) { callback = new global(function); }
|
||||
|
@@ -22,7 +22,7 @@ public:
|
||||
};
|
||||
|
||||
GameBoyCartridge::GameBoyCartridge(const uint8_t *romdata, unsigned romsize) {
|
||||
xml = "<?xml version='1.0' encoding='UTF-8'?>\n";
|
||||
xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
if(romsize < 0x4000) return;
|
||||
|
||||
info.mapper = "unknown";
|
||||
@@ -97,6 +97,7 @@ GameBoyCartridge::GameBoyCartridge(const uint8_t *romdata, unsigned romsize) {
|
||||
xml << " <ram size='" << hex(info.ramsize) << "' battery='" << info.battery << "'/>\n";
|
||||
|
||||
xml << "</cartridge>\n";
|
||||
xml.transform("'", "\"");
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -112,13 +112,13 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
|
||||
if(type == TypeBsx) {
|
||||
xml << "<cartridge/>";
|
||||
xmlMemoryMap = xml;
|
||||
xmlMemoryMap = xml.transform("'", "\"");
|
||||
return;
|
||||
}
|
||||
|
||||
if(type == TypeSufamiTurbo) {
|
||||
xml << "<cartridge/>";
|
||||
xmlMemoryMap = xml;
|
||||
xmlMemoryMap = xml.transform("'", "\"");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
xml << " <ram size='" << hex(gameboy_ram_size(data, size)) << "'/>\n";
|
||||
}
|
||||
xml << "</cartridge>\n";
|
||||
xmlMemoryMap = xml;
|
||||
xmlMemoryMap = xml.transform("'", "\"");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -279,19 +279,23 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
xml << " </superfx>\n";
|
||||
} else if(mapper == SA1ROM) {
|
||||
xml << " <sa1>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-ff:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <mcu>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='direct' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='direct' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='direct' address='c0-ff:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram>\n";
|
||||
xml << " <map mode='direct' address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='direct' address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " </mcu>\n";
|
||||
xml << " <iram size='800'>\n";
|
||||
xml << " <map mode='linear' address='00-3f:3000-37ff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:3000-37ff'/>\n";
|
||||
xml << " </iram>\n";
|
||||
xml << " <bwram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='40-4f:0000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </bwram>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:2200-23ff'/>\n";
|
||||
@@ -334,11 +338,14 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
xml << " </slot>\n";
|
||||
xml << " </bsx>\n";
|
||||
} else if(mapper == BSXROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <bsx>\n";
|
||||
xml << " <mcu>\n";
|
||||
xml << " <map address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map address='40-7f:0000-ffff'/>\n";
|
||||
xml << " <map address='c0-ff:0000-ffff'/>\n";
|
||||
xml << " <map address='20-3f:6000-7fff'/>\n";
|
||||
xml << " </mcu>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:5000-5fff'/>\n";
|
||||
xml << " <map address='80-bf:5000-5fff'/>\n";
|
||||
@@ -402,48 +409,72 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
if(has_dsp1) {
|
||||
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n";
|
||||
if(dsp1_mapper == DSP1LoROM1MB) {
|
||||
xml << " <dr mask='004000' test='000000'/>\n";
|
||||
xml << " <sr mask='004000' test='004000'/>\n";
|
||||
xml << " <map address='20-3f:8000-ffff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-ffff'/>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='20-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='20-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='a0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
} else if(dsp1_mapper == DSP1LoROM2MB) {
|
||||
xml << " <dr mask='004000' test='000000'/>\n";
|
||||
xml << " <sr mask='004000' test='004000'/>\n";
|
||||
xml << " <map address='60-6f:0000-7fff'/>\n";
|
||||
xml << " <map address='e0-ef:0000-7fff'/>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='60-6f:0000-3fff'/>\n";
|
||||
xml << " <map address='e0-ef:0000-3fff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='60-6f:4000-7fff'/>\n";
|
||||
xml << " <map address='e0-ef:4000-7fff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
} else if(dsp1_mapper == DSP1HiROM) {
|
||||
xml << " <dr mask='001000' test='000000'/>\n";
|
||||
xml << " <sr mask='001000' test='001000'/>\n";
|
||||
xml << " <map address='00-1f:6000-7fff'/>\n";
|
||||
xml << " <map address='80-9f:6000-7fff'/>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='00-1f:6000-6fff'/>\n";
|
||||
xml << " <map address='80-9f:6000-6fff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='00-1f:7000-7fff'/>\n";
|
||||
xml << " <map address='80-9f:7000-7fff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
}
|
||||
xml << " </necdsp>\n";
|
||||
}
|
||||
|
||||
if(has_dsp2) {
|
||||
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n";
|
||||
xml << " <dr mask='004000' test='000000'/>\n";
|
||||
xml << " <sr mask='004000' test='004000'/>\n";
|
||||
xml << " <map address='20-3f:8000-ffff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-ffff'/>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='20-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='20-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='a0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " </necdsp>\n";
|
||||
}
|
||||
|
||||
if(has_dsp3) {
|
||||
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n";
|
||||
xml << " <dr mask='004000' test='000000'/>\n";
|
||||
xml << " <sr mask='004000' test='004000'/>\n";
|
||||
xml << " <map address='20-3f:8000-ffff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-ffff'/>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='20-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='20-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='a0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " </necdsp>\n";
|
||||
}
|
||||
|
||||
if(has_dsp4) {
|
||||
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n";
|
||||
xml << " <dr mask='004000' test='000000'/>\n";
|
||||
xml << " <sr mask='004000' test='004000'/>\n";
|
||||
xml << " <map address='30-3f:8000-ffff'/>\n";
|
||||
xml << " <map address='b0-bf:8000-ffff'/>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='30-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='b0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='30-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='b0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " </necdsp>\n";
|
||||
}
|
||||
|
||||
@@ -456,21 +487,35 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
|
||||
if(has_st010) {
|
||||
xml << " <necdsp revision='upd96050' frequency='10000000' program='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n";
|
||||
xml << " <dr mask='080001' test='000000'/>\n";
|
||||
xml << " <sr mask='080001' test='000001'/>\n";
|
||||
xml << " <dp mask='080000' test='080000'/>\n";
|
||||
xml << " <map address='60-6f:0000-0fff'/>\n";
|
||||
xml << " <map address='e0-ef:0000-0fff'/>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='60:0000'/>\n";
|
||||
xml << " <map address='e0:0000'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='60:0001'/>\n";
|
||||
xml << " <map address='e0:0001'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " <dp>\n";
|
||||
xml << " <map address='68-6f:0000-0fff'/>\n";
|
||||
xml << " <map address='e8-ef:0000-0fff'/>\n";
|
||||
xml << " </dp>\n";
|
||||
xml << " </necdsp>\n";
|
||||
}
|
||||
|
||||
if(has_st011) {
|
||||
xml << " <necdsp revision='upd96050' frequency='15000000' program='st0011.bin' sha256='b71d71fa5f18ff39b2b3688e914a04d1286b613002ddde827529fdc54650a130'>\n";
|
||||
xml << " <dr mask='080001' test='000000'/>\n";
|
||||
xml << " <sr mask='080001' test='000001'/>\n";
|
||||
xml << " <dp mask='080000' test='080000'/>\n";
|
||||
xml << " <map address='60-6f:0000-0fff'/>\n";
|
||||
xml << " <map address='e0-ef:0000-0fff'/>\n";
|
||||
xml << " <necdsp revision='upd96050' frequency='15000000' program='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='60:0000'/>\n";
|
||||
xml << " <map address='e0:0000'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='60:0001'/>\n";
|
||||
xml << " <map address='e0:0001'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " <dp>\n";
|
||||
xml << " <map address='68-6f:0000-0fff'/>\n";
|
||||
xml << " <map address='e8-ef:0000-0fff'/>\n";
|
||||
xml << " </dp>\n";
|
||||
xml << " </necdsp>\n";
|
||||
}
|
||||
|
||||
@@ -482,7 +527,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
}
|
||||
|
||||
xml << "</cartridge>\n";
|
||||
xmlMemoryMap = xml;
|
||||
xmlMemoryMap = xml.transform("'", "\"");
|
||||
}
|
||||
|
||||
void SNESCartridge::read_header(const uint8_t *data, unsigned size) {
|
||||
|
@@ -145,10 +145,15 @@ namespace nall {
|
||||
inline unsigned strlcpy(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);
|
||||
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);
|
||||
template<unsigned length = 0, char padding = '0'> inline string decimal(uintmax_t value);
|
||||
template<unsigned length = 0, char padding = '0'> inline string binary(uintmax_t value);
|
||||
|
||||
inline string integer(intmax_t value);
|
||||
template<unsigned length = 0> inline string linteger(intmax_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 string fp(double value);
|
||||
|
||||
|
@@ -27,7 +27,151 @@ string substr(const char *src, unsigned start, unsigned length) {
|
||||
|
||||
/* 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;
|
||||
unsigned offset = 0;
|
||||
|
||||
@@ -38,7 +182,7 @@ template<unsigned length, char padding> string hex(uintmax_t value) {
|
||||
value >>= 4;
|
||||
} while(value);
|
||||
|
||||
while(offset < length) output[offset++] = padding;
|
||||
while(offset < length) output[offset++] = '0';
|
||||
output[offset--] = 0;
|
||||
|
||||
//reverse the string in-place
|
||||
@@ -51,55 +195,7 @@ template<unsigned length, char padding> string hex(uintmax_t value) {
|
||||
return output;
|
||||
}
|
||||
|
||||
template<unsigned length, char padding> string integer(intmax_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) {
|
||||
template<unsigned length> string binary(uintmax_t value) {
|
||||
string output;
|
||||
unsigned offset = 0;
|
||||
|
||||
@@ -109,7 +205,7 @@ template<unsigned length, char padding> string binary(uintmax_t value) {
|
||||
value >>= 1;
|
||||
} while(value);
|
||||
|
||||
while(offset < length) output[offset++] = padding;
|
||||
while(offset < length) output[offset++] = '0';
|
||||
output[offset--] = 0;
|
||||
|
||||
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
|
||||
|
@@ -46,7 +46,7 @@ namespace nall {
|
||||
void reserve(unsigned newsize) {
|
||||
newsize = bit::round(newsize); //round to nearest power of two (for amortized growth)
|
||||
|
||||
T *poolcopy = (T*)malloc(newsize * sizeof(T));
|
||||
T *poolcopy = (T*)calloc(newsize, sizeof(T));
|
||||
for(unsigned i = 0; i < min(objectsize, newsize); i++) new(poolcopy + i) T(pool[i]);
|
||||
for(unsigned i = 0; i < objectsize; i++) pool[i].~T();
|
||||
free(pool);
|
||||
|
@@ -107,6 +107,8 @@ struct Window : Widget {
|
||||
void setStatusText(const nall::string &text);
|
||||
void setMenuVisible(bool visible = true);
|
||||
void setStatusVisible(bool visible = true);
|
||||
bool fullscreen();
|
||||
void setFullscreen(bool fullscreen = true);
|
||||
Window();
|
||||
//private:
|
||||
struct Data;
|
||||
|
@@ -27,6 +27,11 @@ struct Widget::Data {
|
||||
|
||||
struct Window::Data {
|
||||
Font *defaultFont;
|
||||
bool isFullscreen;
|
||||
unsigned x;
|
||||
unsigned y;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
};
|
||||
|
||||
struct Canvas::Data {
|
||||
|
@@ -8,6 +8,11 @@ static gint Window_close(Window *window) {
|
||||
}
|
||||
|
||||
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
window->x = x;
|
||||
window->y = y;
|
||||
window->width = width;
|
||||
window->height = height;
|
||||
|
||||
object->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_move(GTK_WINDOW(object->widget), x, y);
|
||||
|
||||
@@ -55,8 +60,8 @@ Geometry Window::geometry() {
|
||||
}
|
||||
|
||||
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
gtk_window_move(GTK_WINDOW(object->widget), x, y);
|
||||
gtk_widget_set_size_request(object->formContainer, width, height);
|
||||
gtk_window_move(GTK_WINDOW(object->widget), window->x = x, window->y = y);
|
||||
gtk_widget_set_size_request(object->formContainer, window->width = width, window->height = height);
|
||||
}
|
||||
|
||||
void Window::setDefaultFont(Font &font) {
|
||||
@@ -93,7 +98,40 @@ void Window::setStatusVisible(bool visible) {
|
||||
gtk_widget_set_visible(object->status, visible);
|
||||
}
|
||||
|
||||
bool Window::fullscreen() {
|
||||
return window->isFullscreen;
|
||||
}
|
||||
|
||||
void Window::setFullscreen(bool fullscreen) {
|
||||
window->isFullscreen = fullscreen;
|
||||
if(fullscreen == true) {
|
||||
gtk_window_fullscreen(GTK_WINDOW(object->widget));
|
||||
gtk_window_set_decorated(GTK_WINDOW(object->widget), false);
|
||||
gtk_widget_set_size_request(object->widget, gdk_screen_width(), gdk_screen_height());
|
||||
} else {
|
||||
gtk_widget_set_size_request(object->widget, -1, -1);
|
||||
gtk_window_set_decorated(GTK_WINDOW(object->widget), true);
|
||||
gtk_window_unfullscreen(GTK_WINDOW(object->widget));
|
||||
|
||||
//at this point, GTK+ has not updated window geometry
|
||||
//this causes Window::geometry() calls to return incorrect info
|
||||
//thus, wait until the geometry has changed before continuing
|
||||
Geometry geom;
|
||||
time_t startTime = time(0);
|
||||
do {
|
||||
OS::run();
|
||||
Geometry geom = geometry();
|
||||
if(startTime - time(0) > 3) break; //prevent application from freezing
|
||||
} while(geom.x == 0 && geom.y == 0 && geom.width == gdk_screen_width() && geom.height == gdk_screen_height());
|
||||
}
|
||||
}
|
||||
|
||||
Window::Window() {
|
||||
window = new Window::Data;
|
||||
window->defaultFont = 0;
|
||||
window->isFullscreen = false;
|
||||
window->x = 0;
|
||||
window->y = 0;
|
||||
window->width = 0;
|
||||
window->height = 0;
|
||||
}
|
||||
|
@@ -140,6 +140,8 @@ struct Window : Widget {
|
||||
void setMenuVisible(bool visible = true);
|
||||
void setStatusVisible(bool visible = true);
|
||||
bool focused();
|
||||
bool fullscreen();
|
||||
void setFullscreen(bool fullscreen = true);
|
||||
Window();
|
||||
//private:
|
||||
struct Data;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
** Meta object code from reading C++ file 'qt.moc.hpp'
|
||||
**
|
||||
** Created: Mon Nov 1 06:26:59 2010
|
||||
** Created: Tue Jan 18 03:30:57 2011
|
||||
** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2)
|
||||
**
|
||||
** WARNING! All changes made in this file will be lost!
|
||||
|
@@ -3,6 +3,7 @@ void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, con
|
||||
window->move(x, y);
|
||||
|
||||
window->layout = new QVBoxLayout(window);
|
||||
window->layout->setAlignment(Qt::AlignTop);
|
||||
window->layout->setMargin(0);
|
||||
window->layout->setSpacing(0);
|
||||
window->layout->setSizeConstraint(QLayout::SetFixedSize);
|
||||
@@ -70,6 +71,28 @@ bool Window::focused() {
|
||||
return window->isActiveWindow() && !window->isMinimized();
|
||||
}
|
||||
|
||||
bool Window::fullscreen() {
|
||||
return window->isFullScreen();
|
||||
}
|
||||
|
||||
void Window::setFullscreen(bool fullscreen) {
|
||||
if(fullscreen == false) {
|
||||
window->showNormal();
|
||||
} else {
|
||||
window->showFullScreen();
|
||||
}
|
||||
|
||||
//Qt returns negative coordinates for x,y immediately after setFullscreen(false)
|
||||
//wait for Qt to return sane values, or until timeout occurs
|
||||
Geometry geom;
|
||||
time_t startTime = time(0);
|
||||
do {
|
||||
OS::run();
|
||||
geom = geometry();
|
||||
if(startTime - time(0) > 3) break;
|
||||
} while((signed)geom.x < 0 || (signed)geom.y < 0);
|
||||
}
|
||||
|
||||
Window::Window() {
|
||||
window = new Window::Data(*this);
|
||||
window->defaultFont = 0;
|
||||
|
@@ -26,6 +26,9 @@ struct Window::Data {
|
||||
COLORREF brushColor;
|
||||
HMENU menu;
|
||||
HWND status;
|
||||
bool isFullscreen;
|
||||
unsigned x;
|
||||
unsigned y;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
};
|
||||
|
@@ -2,7 +2,7 @@ void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, con
|
||||
widget->window = CreateWindowEx(
|
||||
0, L"phoenix_window", utf16_t(text),
|
||||
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
|
||||
x, y, width, height,
|
||||
window->x = x, window->y = y, window->width = width, window->height = height,
|
||||
0, 0, GetModuleHandle(0), 0
|
||||
);
|
||||
window->menu = CreateMenu();
|
||||
@@ -39,6 +39,13 @@ Geometry Window::geometry() {
|
||||
}
|
||||
|
||||
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
if(window->isFullscreen == false) {
|
||||
window->x = x;
|
||||
window->y = y;
|
||||
window->width = width;
|
||||
window->height = height;
|
||||
}
|
||||
|
||||
bool isVisible = visible();
|
||||
if(isVisible) setVisible(false);
|
||||
SetWindowPos(widget->window, NULL, x, y, width, height, SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
@@ -70,16 +77,33 @@ void Window::setStatusVisible(bool visible) {
|
||||
resize(window->width, window->height);
|
||||
}
|
||||
|
||||
bool Window::fullscreen() {
|
||||
return window->isFullscreen;
|
||||
}
|
||||
|
||||
void Window::setFullscreen(bool fullscreen) {
|
||||
window->isFullscreen = fullscreen;
|
||||
if(fullscreen == false) {
|
||||
SetWindowLong(widget->window, GWL_STYLE, WS_VISIBLE | WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX);
|
||||
setGeometry(window->x, window->y, window->width, window->height);
|
||||
} else {
|
||||
SetWindowLong(widget->window, GWL_STYLE, WS_VISIBLE | WS_POPUP);
|
||||
setGeometry(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
|
||||
}
|
||||
}
|
||||
|
||||
Window::Window() {
|
||||
window = new Window::Data;
|
||||
window->defaultFont = 0;
|
||||
window->brush = 0;
|
||||
window->isFullscreen = false;
|
||||
window->x = 0;
|
||||
window->y = 0;
|
||||
window->width = 0;
|
||||
window->height = 0;
|
||||
}
|
||||
|
||||
void Window::resize(unsigned width, unsigned height) {
|
||||
window->width = width;
|
||||
window->height = height;
|
||||
|
||||
SetWindowPos(widget->window, NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE | SWP_FRAMECHANGED);
|
||||
RECT rc;
|
||||
GetClientRect(widget->window, &rc);
|
||||
|
@@ -112,6 +112,8 @@ struct Window : Widget {
|
||||
void setStatusText(const nall::string &text);
|
||||
void setMenuVisible(bool visible = true);
|
||||
void setStatusVisible(bool visible = true);
|
||||
bool fullscreen();
|
||||
void setFullscreen(bool fullscreen = true);
|
||||
Window();
|
||||
//private:
|
||||
struct Data;
|
||||
|
@@ -4,7 +4,7 @@ snes_objects += snes-memory snes-cpucore snes-smpcore
|
||||
snes_objects += snes-cpu snes-smp snes-dsp snes-ppu
|
||||
snes_objects += snes-icd2 snes-superfx snes-sa1 snes-necdsp
|
||||
snes_objects += snes-bsx snes-srtc snes-sdd1 snes-spc7110 snes-cx4
|
||||
snes_objects += snes-obc1 snes-st0018
|
||||
snes_objects += snes-obc1 snes-st0018 snes-sufamiturbo
|
||||
snes_objects += snes-msu1 snes-serial
|
||||
objects += $(snes_objects)
|
||||
|
||||
@@ -28,8 +28,6 @@ else ifeq ($(profile),performance)
|
||||
snesppu := $(snes)/alt/ppu-performance
|
||||
endif
|
||||
|
||||
obj/libsnes.o: $(snes)/libsnes/libsnes.cpp $(snes)/libsnes/*
|
||||
|
||||
obj/snes-system.o : $(snes)/system/system.cpp $(call rwildcard,$(snes)/system/) $(call rwildcard,$(snes)/video/)
|
||||
obj/snes-memory.o : $(snes)/memory/memory.cpp $(call rwildcard,$(snes)/memory/)
|
||||
obj/snes-cpucore.o : $(snes)/cpu/core/core.cpp $(call rwildcard,$(snes)/cpu/core/)
|
||||
@@ -41,50 +39,17 @@ obj/snes-ppu.o : $(snesppu)/ppu.cpp $(call rwildcard,$(snesppu)/)
|
||||
obj/snes-cartridge.o: $(snes)/cartridge/cartridge.cpp $(snes)/cartridge/*
|
||||
obj/snes-cheat.o : $(snes)/cheat/cheat.cpp $(snes)/cheat/*
|
||||
|
||||
obj/snes-icd2.o : $(snes)/chip/icd2/icd2.cpp $(call rwildcard,$(snes)/chip/icd2/)
|
||||
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/)
|
||||
obj/snes-necdsp.o : $(snes)/chip/necdsp/necdsp.cpp $(call rwildcard,$(snes)/chip/necdsp/)
|
||||
obj/snes-bsx.o : $(snes)/chip/bsx/bsx.cpp $(snes)/chip/bsx/*
|
||||
obj/snes-srtc.o : $(snes)/chip/srtc/srtc.cpp $(snes)/chip/srtc/*
|
||||
obj/snes-sdd1.o : $(snes)/chip/sdd1/sdd1.cpp $(snes)/chip/sdd1/*
|
||||
obj/snes-spc7110.o : $(snes)/chip/spc7110/spc7110.cpp $(snes)/chip/spc7110/*
|
||||
obj/snes-cx4.o : $(snes)/chip/cx4/cx4.cpp $(snes)/chip/cx4/*
|
||||
obj/snes-obc1.o : $(snes)/chip/obc1/obc1.cpp $(snes)/chip/obc1/*
|
||||
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 #
|
||||
###########
|
||||
|
||||
snes_objects := $(patsubst %,obj/%.o,$(snes_objects))
|
||||
|
||||
library: $(snes_objects) obj/libsnes.o
|
||||
ifeq ($(platform),x)
|
||||
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 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 out/snes.dll -shared -Wl,--out-implib,libsnes.a $(snes_objects) obj/libsnes.o
|
||||
endif
|
||||
|
||||
library-install:
|
||||
ifeq ($(platform),x)
|
||||
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 out/libsnes.dylib /usr/local/lib/libsnes.dylib
|
||||
endif
|
||||
|
||||
library-uninstall:
|
||||
ifeq ($(platform),x)
|
||||
rm $(DESTDIR)$(prefix)/lib/libsnes.a
|
||||
rm $(DESTDIR)$(prefix)/lib/libsnes.so
|
||||
else ifeq ($(platform),osx)
|
||||
rm /usr/local/lib/libsnes.dylib
|
||||
endif
|
||||
obj/snes-icd2.o : $(snes)/chip/icd2/icd2.cpp $(call rwildcard,$(snes)/chip/icd2/)
|
||||
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/)
|
||||
obj/snes-necdsp.o : $(snes)/chip/necdsp/necdsp.cpp $(call rwildcard,$(snes)/chip/necdsp/)
|
||||
obj/snes-bsx.o : $(snes)/chip/bsx/bsx.cpp $(call rwildcard,$(snes)/chip/bsx/)
|
||||
obj/snes-srtc.o : $(snes)/chip/srtc/srtc.cpp $(snes)/chip/srtc/*
|
||||
obj/snes-sdd1.o : $(snes)/chip/sdd1/sdd1.cpp $(snes)/chip/sdd1/*
|
||||
obj/snes-spc7110.o : $(snes)/chip/spc7110/spc7110.cpp $(snes)/chip/spc7110/*
|
||||
obj/snes-cx4.o : $(snes)/chip/cx4/cx4.cpp $(snes)/chip/cx4/*
|
||||
obj/snes-obc1.o : $(snes)/chip/obc1/obc1.cpp $(snes)/chip/obc1/*
|
||||
obj/snes-st0018.o : $(snes)/chip/st0018/st0018.cpp $(snes)/chip/st0018/*
|
||||
obj/snes-sufamiturbo.o: $(snes)/chip/sufamiturbo/sufamiturbo.cpp $(snes)/chip/sufamiturbo/*
|
||||
obj/snes-msu1.o : $(snes)/chip/msu1/msu1.cpp $(snes)/chip/msu1/*
|
||||
obj/snes-serial.o : $(snes)/chip/serial/serial.cpp $(snes)/chip/serial/*
|
||||
|
@@ -90,6 +90,30 @@ void CPU::op_irq(uint16 vector) {
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
void CPU::enable() {
|
||||
function<uint8 (unsigned)> read = { &CPU::mmio_read, (CPU*)&cpu };
|
||||
function<void (unsigned, uint8)> write = { &CPU::mmio_write, (CPU*)&cpu };
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, read, write);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, read, write);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, read, write);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, read, write);
|
||||
|
||||
read = [](unsigned addr) { return cpu.wram[addr]; };
|
||||
write = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; };
|
||||
|
||||
bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
|
||||
bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
|
||||
bus.map(Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, read, write);
|
||||
}
|
||||
|
||||
void CPU::power() {
|
||||
regs.a = 0x0000;
|
||||
regs.x = 0x0000;
|
||||
|
@@ -1,5 +1,7 @@
|
||||
class CPU : public Processor, public CPUcore, public PPUcounter, public MMIO {
|
||||
class CPU : public Processor, public CPUcore, public PPUcounter {
|
||||
public:
|
||||
uint8 wram[128 * 1024];
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
array<Processor*> coprocessors;
|
||||
alwaysinline void step(unsigned clocks);
|
||||
@@ -20,6 +22,7 @@ public:
|
||||
debugvirtual void op_write(unsigned addr, uint8 data);
|
||||
|
||||
void enter();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
|
@@ -8,13 +8,11 @@ void CPUDebugger::op_step() {
|
||||
opcode_pc = regs.pc;
|
||||
|
||||
opcode_edge = true;
|
||||
if(debugger.step_cpu) {
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00);
|
||||
if(step_event && step_event()) {
|
||||
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();
|
||||
opcode_edge = false;
|
||||
|
||||
CPU::op_step();
|
||||
|
@@ -2,7 +2,7 @@ class CPUDebugger : public CPU, public ChipDebugger {
|
||||
public:
|
||||
bool property(unsigned id, string &name, string &value);
|
||||
|
||||
function<void ()> step_event;
|
||||
function<bool ()> step_event;
|
||||
|
||||
enum Usage {
|
||||
UsageRead = 0x80,
|
||||
|
@@ -5,6 +5,8 @@ void CPU::serialize(serializer &s) {
|
||||
CPUcore::core_serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(wram);
|
||||
|
||||
queue.serialize(s);
|
||||
s.array(port_data);
|
||||
|
||||
|
@@ -40,7 +40,7 @@ void DSP::write(uint8 addr, uint8 data) {
|
||||
}
|
||||
|
||||
void DSP::power() {
|
||||
spc_dsp.init(memory::apuram.data());
|
||||
spc_dsp.init(smp.apuram);
|
||||
spc_dsp.reset();
|
||||
spc_dsp.set_output(samplebuffer, 8192);
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ uint8 PPU::vram_mmio_read(uint16 addr) {
|
||||
uint8 data;
|
||||
|
||||
if(regs.display_disabled == true) {
|
||||
data = memory::vram[addr];
|
||||
data = vram[addr];
|
||||
} else {
|
||||
uint16 v = cpu.vcounter();
|
||||
uint16 h = cpu.hcounter();
|
||||
@@ -39,12 +39,12 @@ uint8 PPU::vram_mmio_read(uint16 addr) {
|
||||
data = 0x00;
|
||||
} else if(v == (!overscan() ? 224 : 239)) {
|
||||
if(h == 1362) {
|
||||
data = memory::vram[addr];
|
||||
data = vram[addr];
|
||||
} else {
|
||||
data = 0x00;
|
||||
}
|
||||
} else {
|
||||
data = memory::vram[addr];
|
||||
data = vram[addr];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,15 +53,15 @@ uint8 PPU::vram_mmio_read(uint16 addr) {
|
||||
|
||||
void PPU::vram_mmio_write(uint16 addr, uint8 data) {
|
||||
if(regs.display_disabled == true) {
|
||||
memory::vram[addr] = data;
|
||||
vram[addr] = data;
|
||||
} else {
|
||||
uint16 v = cpu.vcounter();
|
||||
uint16 h = cpu.hcounter();
|
||||
if(v == 0) {
|
||||
if(h <= 4) {
|
||||
memory::vram[addr] = data;
|
||||
vram[addr] = data;
|
||||
} else if(h == 6) {
|
||||
memory::vram[addr] = cpu.regs.mdr;
|
||||
vram[addr] = cpu.regs.mdr;
|
||||
} else {
|
||||
//no write
|
||||
}
|
||||
@@ -71,10 +71,10 @@ void PPU::vram_mmio_write(uint16 addr, uint8 data) {
|
||||
if(h <= 4) {
|
||||
//no write
|
||||
} else {
|
||||
memory::vram[addr] = data;
|
||||
vram[addr] = data;
|
||||
}
|
||||
} else {
|
||||
memory::vram[addr] = data;
|
||||
vram[addr] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,12 +85,12 @@ uint8 PPU::oam_mmio_read(uint16 addr) {
|
||||
uint8 data;
|
||||
|
||||
if(regs.display_disabled == true) {
|
||||
data = memory::oam[addr];
|
||||
data = oam[addr];
|
||||
} else {
|
||||
if(cpu.vcounter() < (!overscan() ? 225 : 240)) {
|
||||
data = memory::oam[regs.ioamaddr];
|
||||
data = oam[regs.ioamaddr];
|
||||
} else {
|
||||
data = memory::oam[addr];
|
||||
data = oam[addr];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,14 +104,14 @@ void PPU::oam_mmio_write(uint16 addr, uint8 data) {
|
||||
sprite_list_valid = false;
|
||||
|
||||
if(regs.display_disabled == true) {
|
||||
memory::oam[addr] = data;
|
||||
oam[addr] = data;
|
||||
update_sprite_list(addr, data);
|
||||
} else {
|
||||
if(cpu.vcounter() < (!overscan() ? 225 : 240)) {
|
||||
memory::oam[regs.ioamaddr] = data;
|
||||
oam[regs.ioamaddr] = data;
|
||||
update_sprite_list(regs.ioamaddr, data);
|
||||
} else {
|
||||
memory::oam[addr] = data;
|
||||
oam[addr] = data;
|
||||
update_sprite_list(addr, data);
|
||||
}
|
||||
}
|
||||
@@ -122,14 +122,14 @@ uint8 PPU::cgram_mmio_read(uint16 addr) {
|
||||
uint8 data;
|
||||
|
||||
if(1 || regs.display_disabled == true) {
|
||||
data = memory::cgram[addr];
|
||||
data = cgram[addr];
|
||||
} else {
|
||||
uint16 v = cpu.vcounter();
|
||||
uint16 h = cpu.hcounter();
|
||||
if(v < (!overscan() ? 225 : 240) && h >= 128 && h < 1096) {
|
||||
data = memory::cgram[regs.icgramaddr] & 0x7f;
|
||||
data = cgram[regs.icgramaddr] & 0x7f;
|
||||
} else {
|
||||
data = memory::cgram[addr];
|
||||
data = cgram[addr];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,14 +142,14 @@ void PPU::cgram_mmio_write(uint16 addr, uint8 data) {
|
||||
if(addr & 1) data &= 0x7f;
|
||||
|
||||
if(1 || regs.display_disabled == true) {
|
||||
memory::cgram[addr] = data;
|
||||
cgram[addr] = data;
|
||||
} else {
|
||||
uint16 v = cpu.vcounter();
|
||||
uint16 h = cpu.hcounter();
|
||||
if(v < (!overscan() ? 225 : 240) && h >= 128 && h < 1096) {
|
||||
memory::cgram[regs.icgramaddr] = data & 0x7f;
|
||||
cgram[regs.icgramaddr] = data & 0x7f;
|
||||
} else {
|
||||
memory::cgram[addr] = data;
|
||||
cgram[addr] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -122,13 +122,21 @@ void PPU::frame() {
|
||||
framecounter = (frameskip == 0 ? 0 : (framecounter + 1) % frameskip);
|
||||
}
|
||||
|
||||
void PPU::enable() {
|
||||
function<uint8 (unsigned)> read = { &PPU::mmio_read, (PPU*)&ppu };
|
||||
function<void (unsigned, uint8)> write = { &PPU::mmio_write, (PPU*)&ppu };
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write);
|
||||
}
|
||||
|
||||
void PPU::power() {
|
||||
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;
|
||||
foreach(n, vram) n = 0x00;
|
||||
foreach(n, oam) n = 0x00;
|
||||
foreach(n, cgram) n = 0x00;
|
||||
flush_tiledata_cache();
|
||||
|
||||
region = (system.region() == System::Region::NTSC ? 0 : 1); //0 = NTSC, 1 = PAL
|
||||
|
@@ -1,5 +1,9 @@
|
||||
class PPU : public Processor, public PPUcounter, public MMIO {
|
||||
class PPU : public Processor, public PPUcounter {
|
||||
public:
|
||||
uint8 vram[128 * 1024];
|
||||
uint8 oam[544];
|
||||
uint8 cgram[512];
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_cpu();
|
||||
@@ -56,6 +60,7 @@ public:
|
||||
void render_scanline();
|
||||
void frame();
|
||||
void enter();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
|
@@ -32,7 +32,7 @@ uint16 PPU::bg_get_tile(uint16 x, uint16 y) {
|
||||
if(x & 0x20) pos += bg_info[bg].scx;
|
||||
|
||||
const uint16 addr = regs.bg_scaddr[bg] + (pos << 1);
|
||||
return memory::vram[addr] + (memory::vram[addr + 1] << 8);
|
||||
return vram[addr] + (vram[addr + 1] << 8);
|
||||
}
|
||||
|
||||
#define setpixel_main(x) \
|
||||
|
@@ -32,8 +32,8 @@ void PPU::render_bg_tile(uint16 tile_num) {
|
||||
unsigned pos = tile_num * 16;
|
||||
unsigned y = 8;
|
||||
while(y--) {
|
||||
d0 = memory::vram[pos ];
|
||||
d1 = memory::vram[pos + 1];
|
||||
d0 = vram[pos ];
|
||||
d1 = vram[pos + 1];
|
||||
render_bg_tile_line_2bpp(0x80);
|
||||
render_bg_tile_line_2bpp(0x40);
|
||||
render_bg_tile_line_2bpp(0x20);
|
||||
@@ -52,10 +52,10 @@ void PPU::render_bg_tile(uint16 tile_num) {
|
||||
unsigned pos = tile_num * 32;
|
||||
unsigned y = 8;
|
||||
while(y--) {
|
||||
d0 = memory::vram[pos ];
|
||||
d1 = memory::vram[pos + 1];
|
||||
d2 = memory::vram[pos + 16];
|
||||
d3 = memory::vram[pos + 17];
|
||||
d0 = vram[pos ];
|
||||
d1 = vram[pos + 1];
|
||||
d2 = vram[pos + 16];
|
||||
d3 = vram[pos + 17];
|
||||
render_bg_tile_line_4bpp(0x80);
|
||||
render_bg_tile_line_4bpp(0x40);
|
||||
render_bg_tile_line_4bpp(0x20);
|
||||
@@ -74,14 +74,14 @@ void PPU::render_bg_tile(uint16 tile_num) {
|
||||
unsigned pos = tile_num * 64;
|
||||
unsigned y = 8;
|
||||
while(y--) {
|
||||
d0 = memory::vram[pos ];
|
||||
d1 = memory::vram[pos + 1];
|
||||
d2 = memory::vram[pos + 16];
|
||||
d3 = memory::vram[pos + 17];
|
||||
d4 = memory::vram[pos + 32];
|
||||
d5 = memory::vram[pos + 33];
|
||||
d6 = memory::vram[pos + 48];
|
||||
d7 = memory::vram[pos + 49];
|
||||
d0 = vram[pos ];
|
||||
d1 = vram[pos + 1];
|
||||
d2 = vram[pos + 16];
|
||||
d3 = vram[pos + 17];
|
||||
d4 = vram[pos + 32];
|
||||
d5 = vram[pos + 33];
|
||||
d6 = vram[pos + 48];
|
||||
d7 = vram[pos + 49];
|
||||
render_bg_tile_line_8bpp(0x80);
|
||||
render_bg_tile_line_8bpp(0x40);
|
||||
render_bg_tile_line_8bpp(0x20);
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
inline uint16 PPU::get_palette(uint8 index) {
|
||||
const unsigned addr = index << 1;
|
||||
return memory::cgram[addr] + (memory::cgram[addr + 1] << 8);
|
||||
return cgram[addr] + (cgram[addr + 1] << 8);
|
||||
}
|
||||
|
||||
//p = 00000bgr <palette data>
|
||||
|
@@ -71,8 +71,8 @@ void PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) {
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = memory::vram[(ty * 128 + tx) << 1];
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
} break;
|
||||
case 2: { //palette color 0 outside of screen area
|
||||
if((px | py) & ~1023) {
|
||||
@@ -82,8 +82,8 @@ void PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) {
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = memory::vram[(ty * 128 + tx) << 1];
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
}
|
||||
} break;
|
||||
case 3: { //character 0 repetition outside of screen area
|
||||
@@ -94,9 +94,9 @@ void PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) {
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = memory::vram[(ty * 128 + tx) << 1];
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
}
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
} break;
|
||||
}
|
||||
|
||||
|
@@ -16,6 +16,10 @@ void PPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(vram);
|
||||
s.array(oam);
|
||||
s.array(cgram);
|
||||
|
||||
s.integer(ppu1_version);
|
||||
s.integer(ppu2_version);
|
||||
|
||||
|
@@ -11,7 +11,7 @@ unsigned PPU::Background::get_tile(unsigned hoffset, unsigned voffset) {
|
||||
if(tile_x & 0x20) tile_pos += scx;
|
||||
|
||||
const uint16 tiledata_addr = regs.screen_addr + (tile_pos << 1);
|
||||
return (memory::vram[tiledata_addr + 0] << 0) + (memory::vram[tiledata_addr + 1] << 8);
|
||||
return (ppu.vram[tiledata_addr + 0] << 0) + (ppu.vram[tiledata_addr + 1] << 8);
|
||||
}
|
||||
|
||||
void PPU::Background::offset_per_tile(unsigned x, unsigned y, unsigned &hoffset, unsigned &voffset) {
|
||||
|
@@ -43,8 +43,8 @@ void PPU::Background::render_mode7() {
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = memory::vram[(ty * 128 + tx) << 1];
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
tile = ppu.vram[(ty * 128 + tx) << 1];
|
||||
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -56,8 +56,8 @@ void PPU::Background::render_mode7() {
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = memory::vram[(ty * 128 + tx) << 1];
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
tile = ppu.vram[(ty * 128 + tx) << 1];
|
||||
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -70,9 +70,9 @@ void PPU::Background::render_mode7() {
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = memory::vram[(ty * 128 + tx) << 1];
|
||||
tile = ppu.vram[(ty * 128 + tx) << 1];
|
||||
}
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
28
bsnes/snes/alt/ppu-performance/cache/cache.cpp
vendored
28
bsnes/snes/alt/ppu-performance/cache/cache.cpp
vendored
@@ -8,8 +8,8 @@ uint8* PPU::Cache::tile_2bpp(unsigned tile) {
|
||||
unsigned y = 8;
|
||||
unsigned color, d0, d1;
|
||||
while(y--) {
|
||||
d0 = memory::vram[offset + 0];
|
||||
d1 = memory::vram[offset + 1];
|
||||
d0 = ppu.vram[offset + 0];
|
||||
d1 = ppu.vram[offset + 1];
|
||||
#define render_line(mask) \
|
||||
color = !!(d0 & mask) << 0; \
|
||||
color |= !!(d1 & mask) << 1; \
|
||||
@@ -37,10 +37,10 @@ uint8* PPU::Cache::tile_4bpp(unsigned tile) {
|
||||
unsigned y = 8;
|
||||
unsigned color, d0, d1, d2, d3;
|
||||
while(y--) {
|
||||
d0 = memory::vram[offset + 0];
|
||||
d1 = memory::vram[offset + 1];
|
||||
d2 = memory::vram[offset + 16];
|
||||
d3 = memory::vram[offset + 17];
|
||||
d0 = ppu.vram[offset + 0];
|
||||
d1 = ppu.vram[offset + 1];
|
||||
d2 = ppu.vram[offset + 16];
|
||||
d3 = ppu.vram[offset + 17];
|
||||
#define render_line(mask) \
|
||||
color = !!(d0 & mask) << 0; \
|
||||
color |= !!(d1 & mask) << 1; \
|
||||
@@ -70,14 +70,14 @@ uint8* PPU::Cache::tile_8bpp(unsigned tile) {
|
||||
unsigned y = 8;
|
||||
unsigned color, d0, d1, d2, d3, d4, d5, d6, d7;
|
||||
while(y--) {
|
||||
d0 = memory::vram[offset + 0];
|
||||
d1 = memory::vram[offset + 1];
|
||||
d2 = memory::vram[offset + 16];
|
||||
d3 = memory::vram[offset + 17];
|
||||
d4 = memory::vram[offset + 32];
|
||||
d5 = memory::vram[offset + 33];
|
||||
d6 = memory::vram[offset + 48];
|
||||
d7 = memory::vram[offset + 49];
|
||||
d0 = ppu.vram[offset + 0];
|
||||
d1 = ppu.vram[offset + 1];
|
||||
d2 = ppu.vram[offset + 16];
|
||||
d3 = ppu.vram[offset + 17];
|
||||
d4 = ppu.vram[offset + 32];
|
||||
d5 = ppu.vram[offset + 33];
|
||||
d6 = ppu.vram[offset + 48];
|
||||
d7 = ppu.vram[offset + 49];
|
||||
#define render_line(mask) \
|
||||
color = !!(d0 & mask) << 0; \
|
||||
color |= !!(d1 & mask) << 1; \
|
||||
|
@@ -22,14 +22,14 @@ uint16 PPU::get_vram_addr() {
|
||||
}
|
||||
|
||||
uint8 PPU::vram_read(unsigned addr) {
|
||||
if(regs.display_disable) return memory::vram[addr];
|
||||
if(cpu.vcounter() >= display.height) return memory::vram[addr];
|
||||
if(regs.display_disable) return vram[addr];
|
||||
if(cpu.vcounter() >= display.height) return vram[addr];
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void PPU::vram_write(unsigned addr, uint8 data) {
|
||||
if(regs.display_disable || cpu.vcounter() >= display.height) {
|
||||
memory::vram[addr] = data;
|
||||
vram[addr] = data;
|
||||
cache.tilevalid[0][addr >> 4] = false;
|
||||
cache.tilevalid[1][addr >> 5] = false;
|
||||
cache.tilevalid[2][addr >> 6] = false;
|
||||
@@ -39,24 +39,24 @@ void PPU::vram_write(unsigned addr, uint8 data) {
|
||||
|
||||
uint8 PPU::oam_read(unsigned addr) {
|
||||
if(addr & 0x0200) addr &= 0x021f;
|
||||
if(regs.display_disable) return memory::oam[addr];
|
||||
if(cpu.vcounter() >= display.height) return memory::oam[addr];
|
||||
return memory::oam[0x0218];
|
||||
if(regs.display_disable) return oam[addr];
|
||||
if(cpu.vcounter() >= display.height) return oam[addr];
|
||||
return oam[0x0218];
|
||||
}
|
||||
|
||||
void PPU::oam_write(unsigned addr, uint8 data) {
|
||||
if(addr & 0x0200) addr &= 0x021f;
|
||||
if(!regs.display_disable && cpu.vcounter() < display.height) addr = 0x0218;
|
||||
memory::oam[addr] = data;
|
||||
oam.update_list(addr, data);
|
||||
oam[addr] = data;
|
||||
sprite.update_list(addr, data);
|
||||
}
|
||||
|
||||
uint8 PPU::cgram_read(unsigned addr) {
|
||||
return memory::cgram[addr];
|
||||
return cgram[addr];
|
||||
}
|
||||
|
||||
void PPU::cgram_write(unsigned addr, uint8 data) {
|
||||
memory::cgram[addr] = data;
|
||||
cgram[addr] = data;
|
||||
}
|
||||
|
||||
void PPU::mmio_update_video_mode() {
|
||||
@@ -66,7 +66,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg2.regs.mode = Background::Mode::BPP2; bg2.regs.priority0 = 7; bg2.regs.priority1 = 10;
|
||||
bg3.regs.mode = Background::Mode::BPP2; bg3.regs.priority0 = 2; bg3.regs.priority1 = 5;
|
||||
bg4.regs.mode = Background::Mode::BPP2; bg4.regs.priority0 = 1; bg4.regs.priority1 = 4;
|
||||
oam.regs.priority0 = 3; oam.regs.priority1 = 6; oam.regs.priority2 = 9; oam.regs.priority3 = 12;
|
||||
sprite.regs.priority0 = 3; sprite.regs.priority1 = 6; sprite.regs.priority2 = 9; sprite.regs.priority3 = 12;
|
||||
} break;
|
||||
|
||||
case 1: {
|
||||
@@ -78,12 +78,12 @@ void PPU::mmio_update_video_mode() {
|
||||
bg1.regs.priority0 = 5; bg1.regs.priority1 = 8;
|
||||
bg2.regs.priority0 = 4; bg2.regs.priority1 = 7;
|
||||
bg3.regs.priority0 = 1; bg3.regs.priority1 = 10;
|
||||
oam.regs.priority0 = 2; oam.regs.priority1 = 3; oam.regs.priority2 = 6; oam.regs.priority3 = 9;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 3; sprite.regs.priority2 = 6; sprite.regs.priority3 = 9;
|
||||
} else {
|
||||
bg1.regs.priority0 = 6; bg1.regs.priority1 = 9;
|
||||
bg2.regs.priority0 = 5; bg2.regs.priority1 = 8;
|
||||
bg3.regs.priority0 = 1; bg3.regs.priority1 = 3;
|
||||
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 7; oam.regs.priority3 = 10;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 7; sprite.regs.priority3 = 10;
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -94,7 +94,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 8;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
|
||||
} break;
|
||||
|
||||
case 3: {
|
||||
@@ -104,7 +104,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 8;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
|
||||
} break;
|
||||
|
||||
case 4: {
|
||||
@@ -114,7 +114,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 8;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
|
||||
} break;
|
||||
|
||||
case 5: {
|
||||
@@ -124,7 +124,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 8;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
|
||||
} break;
|
||||
|
||||
case 6: {
|
||||
@@ -133,7 +133,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg3.regs.mode = Background::Mode::Inactive;
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 2; bg1.regs.priority1 = 5;
|
||||
oam.regs.priority0 = 1; oam.regs.priority1 = 3; oam.regs.priority2 = 4; oam.regs.priority3 = 6;
|
||||
sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 6;
|
||||
} break;
|
||||
|
||||
case 7: {
|
||||
@@ -143,7 +143,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg3.regs.mode = Background::Mode::Inactive;
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 2; bg1.regs.priority1 = 2;
|
||||
oam.regs.priority0 = 1; oam.regs.priority1 = 3; oam.regs.priority2 = 4; oam.regs.priority3 = 5;
|
||||
sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 5;
|
||||
} else {
|
||||
bg1.regs.mode = Background::Mode::Mode7;
|
||||
bg2.regs.mode = Background::Mode::Mode7;
|
||||
@@ -151,7 +151,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 3;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 7;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 7;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
@@ -193,7 +193,7 @@ uint8 PPU::mmio_read(unsigned addr) {
|
||||
case 0x2138: { //OAMDATAREAD
|
||||
regs.ppu1_mdr = oam_read(regs.oam_addr);
|
||||
regs.oam_addr = (regs.oam_addr + 1) & 0x03ff;
|
||||
oam.set_first();
|
||||
sprite.set_first();
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
@@ -251,8 +251,8 @@ uint8 PPU::mmio_read(unsigned addr) {
|
||||
|
||||
case 0x213e: { //STAT77
|
||||
regs.ppu1_mdr &= 0x10;
|
||||
regs.ppu1_mdr |= oam.regs.time_over << 7;
|
||||
regs.ppu1_mdr |= oam.regs.range_over << 6;
|
||||
regs.ppu1_mdr |= sprite.regs.time_over << 7;
|
||||
regs.ppu1_mdr |= sprite.regs.range_over << 6;
|
||||
regs.ppu1_mdr |= 0x01; //version
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
@@ -283,30 +283,30 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
|
||||
switch(addr & 0xffff) {
|
||||
case 0x2100: { //INIDISP
|
||||
if(regs.display_disable && cpu.vcounter() == display.height) oam.address_reset();
|
||||
if(regs.display_disable && cpu.vcounter() == display.height) sprite.address_reset();
|
||||
regs.display_disable = data & 0x80;
|
||||
regs.display_brightness = data & 0x0f;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2101: { //OBSEL
|
||||
oam.regs.base_size = (data >> 5) & 7;
|
||||
oam.regs.nameselect = (data >> 3) & 3;
|
||||
oam.regs.tiledata_addr = (data & 3) << 14;
|
||||
oam.list_valid = false;
|
||||
sprite.regs.base_size = (data >> 5) & 7;
|
||||
sprite.regs.nameselect = (data >> 3) & 3;
|
||||
sprite.regs.tiledata_addr = (data & 3) << 14;
|
||||
sprite.list_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2102: { //OAMADDL
|
||||
regs.oam_baseaddr = (regs.oam_baseaddr & 0x0100) | (data << 0);
|
||||
oam.address_reset();
|
||||
sprite.address_reset();
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2103: { //OAMADDH
|
||||
regs.oam_priority = data & 0x80;
|
||||
regs.oam_baseaddr = ((data & 1) << 8) | (regs.oam_baseaddr & 0x00ff);
|
||||
oam.address_reset();
|
||||
sprite.address_reset();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
oam_write((regs.oam_addr & ~1) + 1, data);
|
||||
}
|
||||
regs.oam_addr = (regs.oam_addr + 1) & 0x03ff;
|
||||
oam.set_first();
|
||||
sprite.set_first();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -561,10 +561,10 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
screen.window.two_invert = data & 0x40;
|
||||
screen.window.one_enable = data & 0x20;
|
||||
screen.window.one_invert = data & 0x10;
|
||||
oam.window.two_enable = data & 0x08;
|
||||
oam.window.two_invert = data & 0x04;
|
||||
oam.window.one_enable = data & 0x02;
|
||||
oam.window.one_invert = data & 0x01;
|
||||
sprite.window.two_enable = data & 0x08;
|
||||
sprite.window.two_invert = data & 0x04;
|
||||
sprite.window.one_enable = data & 0x02;
|
||||
sprite.window.one_invert = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -598,12 +598,12 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
|
||||
case 0x212b: { //WOBJLOG
|
||||
screen.window.mask = (data >> 2) & 3;
|
||||
oam.window.mask = (data >> 0) & 3;
|
||||
sprite.window.mask = (data >> 0) & 3;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x212c: { //TM
|
||||
oam.regs.main_enable = data & 0x10;
|
||||
sprite.regs.main_enable = data & 0x10;
|
||||
bg4.regs.main_enable = data & 0x08;
|
||||
bg3.regs.main_enable = data & 0x04;
|
||||
bg2.regs.main_enable = data & 0x02;
|
||||
@@ -612,7 +612,7 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
case 0x212d: { //TS
|
||||
oam.regs.sub_enable = data & 0x10;
|
||||
sprite.regs.sub_enable = data & 0x10;
|
||||
bg4.regs.sub_enable = data & 0x08;
|
||||
bg3.regs.sub_enable = data & 0x04;
|
||||
bg2.regs.sub_enable = data & 0x02;
|
||||
@@ -621,7 +621,7 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
case 0x212e: { //TMW
|
||||
oam.window.main_enable = data & 0x10;
|
||||
sprite.window.main_enable = data & 0x10;
|
||||
bg4.window.main_enable = data & 0x08;
|
||||
bg3.window.main_enable = data & 0x04;
|
||||
bg2.window.main_enable = data & 0x02;
|
||||
@@ -630,7 +630,7 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
case 0x212f: { //TSW
|
||||
oam.window.sub_enable = data & 0x10;
|
||||
sprite.window.sub_enable = data & 0x10;
|
||||
bg4.window.sub_enable = data & 0x08;
|
||||
bg3.window.sub_enable = data & 0x04;
|
||||
bg2.window.sub_enable = data & 0x02;
|
||||
@@ -671,10 +671,10 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
regs.mode7_extbg = data & 0x40;
|
||||
regs.pseudo_hires = data & 0x08;
|
||||
regs.overscan = data & 0x04;
|
||||
oam.regs.interlace = data & 0x02;
|
||||
sprite.regs.interlace = data & 0x02;
|
||||
regs.interlace = data & 0x01;
|
||||
mmio_update_video_mode();
|
||||
oam.list_valid = false;
|
||||
sprite.list_valid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -695,17 +695,17 @@ void PPU::mmio_reset() {
|
||||
regs.latch_hcounter = 0;
|
||||
regs.latch_vcounter = 0;
|
||||
|
||||
oam.regs.first_sprite = 0;
|
||||
oam.list_valid = false;
|
||||
sprite.regs.first_sprite = 0;
|
||||
sprite.list_valid = false;
|
||||
|
||||
//$2100
|
||||
regs.display_disable = true;
|
||||
regs.display_brightness = 0;
|
||||
|
||||
//$2101
|
||||
oam.regs.base_size = 0;
|
||||
oam.regs.nameselect = 0;
|
||||
oam.regs.tiledata_addr = 0;
|
||||
sprite.regs.base_size = 0;
|
||||
sprite.regs.nameselect = 0;
|
||||
sprite.regs.tiledata_addr = 0;
|
||||
|
||||
//$2102-$2103
|
||||
regs.oam_baseaddr = 0;
|
||||
@@ -799,10 +799,10 @@ void PPU::mmio_reset() {
|
||||
bg4.window.two_enable = 0;
|
||||
bg4.window.two_invert = 0;
|
||||
|
||||
oam.window.one_enable = 0;
|
||||
oam.window.one_invert = 0;
|
||||
oam.window.two_enable = 0;
|
||||
oam.window.two_invert = 0;
|
||||
sprite.window.one_enable = 0;
|
||||
sprite.window.one_invert = 0;
|
||||
sprite.window.two_enable = 0;
|
||||
sprite.window.two_invert = 0;
|
||||
|
||||
screen.window.one_enable = 0;
|
||||
screen.window.one_invert = 0;
|
||||
@@ -820,7 +820,7 @@ void PPU::mmio_reset() {
|
||||
bg2.window.mask = 0;
|
||||
bg3.window.mask = 0;
|
||||
bg4.window.mask = 0;
|
||||
oam.window.mask = 0;
|
||||
sprite.window.mask = 0;
|
||||
screen.window.mask = 0;
|
||||
|
||||
//$212c
|
||||
@@ -828,28 +828,28 @@ void PPU::mmio_reset() {
|
||||
bg2.regs.main_enable = 0;
|
||||
bg3.regs.main_enable = 0;
|
||||
bg4.regs.main_enable = 0;
|
||||
oam.regs.main_enable = 0;
|
||||
sprite.regs.main_enable = 0;
|
||||
|
||||
//$212d
|
||||
bg1.regs.sub_enable = 0;
|
||||
bg2.regs.sub_enable = 0;
|
||||
bg3.regs.sub_enable = 0;
|
||||
bg4.regs.sub_enable = 0;
|
||||
oam.regs.sub_enable = 0;
|
||||
sprite.regs.sub_enable = 0;
|
||||
|
||||
//$212e
|
||||
bg1.window.main_enable = 0;
|
||||
bg2.window.main_enable = 0;
|
||||
bg3.window.main_enable = 0;
|
||||
bg4.window.main_enable = 0;
|
||||
oam.window.main_enable = 0;
|
||||
sprite.window.main_enable = 0;
|
||||
|
||||
//$212f
|
||||
bg1.window.sub_enable = 0;
|
||||
bg2.window.sub_enable = 0;
|
||||
bg3.window.sub_enable = 0;
|
||||
bg4.window.sub_enable = 0;
|
||||
oam.window.sub_enable = 0;
|
||||
sprite.window.sub_enable = 0;
|
||||
|
||||
//$2130
|
||||
screen.window.main_mask = 0;
|
||||
@@ -878,12 +878,12 @@ void PPU::mmio_reset() {
|
||||
regs.mode7_extbg = 0;
|
||||
regs.pseudo_hires = 0;
|
||||
regs.overscan = 0;
|
||||
oam.regs.interlace = 0;
|
||||
sprite.regs.interlace = 0;
|
||||
regs.interlace = 0;
|
||||
|
||||
//$213e
|
||||
oam.regs.time_over = 0;
|
||||
oam.regs.range_over = 0;
|
||||
sprite.regs.time_over = 0;
|
||||
sprite.regs.range_over = 0;
|
||||
|
||||
mmio_update_video_mode();
|
||||
}
|
||||
|
@@ -1,3 +1,9 @@
|
||||
public:
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
private:
|
||||
|
||||
struct Regs {
|
||||
//internal
|
||||
uint8 ppu1_mdr;
|
||||
@@ -86,6 +92,4 @@ uint8 cgram_read(unsigned addr);
|
||||
void cgram_write(unsigned addr, uint8 data);
|
||||
|
||||
void mmio_update_video_mode();
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
void mmio_reset();
|
||||
|
@@ -67,7 +67,7 @@ void PPU::render_scanline() {
|
||||
bg2.render();
|
||||
bg3.render();
|
||||
bg4.render();
|
||||
oam.render();
|
||||
sprite.render();
|
||||
screen.render();
|
||||
}
|
||||
|
||||
@@ -75,21 +75,29 @@ void PPU::scanline() {
|
||||
display.width = !hires() ? 256 : 512;
|
||||
display.height = !overscan() ? 225 : 240;
|
||||
if(vcounter() == 0) frame();
|
||||
if(vcounter() == display.height && regs.display_disable == false) oam.address_reset();
|
||||
if(vcounter() == display.height && regs.display_disable == false) sprite.address_reset();
|
||||
}
|
||||
|
||||
void PPU::frame() {
|
||||
oam.frame();
|
||||
sprite.frame();
|
||||
system.frame();
|
||||
display.interlace = regs.interlace;
|
||||
display.overscan = regs.overscan;
|
||||
display.framecounter = display.frameskip == 0 ? 0 : (display.framecounter + 1) % display.frameskip;
|
||||
}
|
||||
|
||||
void PPU::enable() {
|
||||
function<uint8 (unsigned)> read = { &PPU::mmio_read, (PPU*)&ppu };
|
||||
function<void (unsigned, uint8)> write = { &PPU::mmio_write, (PPU*)&ppu };
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write);
|
||||
}
|
||||
|
||||
void PPU::power() {
|
||||
foreach(n, memory::vram) n = 0;
|
||||
foreach(n, memory::oam) n = 0;
|
||||
foreach(n, memory::cgram) n = 0;
|
||||
foreach(n, vram) n = 0;
|
||||
foreach(n, oam) n = 0;
|
||||
foreach(n, cgram) n = 0;
|
||||
reset();
|
||||
}
|
||||
|
||||
@@ -112,10 +120,10 @@ void PPU::layer_enable(unsigned layer, unsigned priority, bool enable) {
|
||||
case 9: bg3.priority1_enable = enable; break;
|
||||
case 12: bg4.priority0_enable = enable; break;
|
||||
case 13: bg4.priority1_enable = enable; break;
|
||||
case 16: oam.priority0_enable = enable; break;
|
||||
case 17: oam.priority1_enable = enable; break;
|
||||
case 18: oam.priority2_enable = enable; break;
|
||||
case 19: oam.priority3_enable = enable; break;
|
||||
case 16: sprite.priority0_enable = enable; break;
|
||||
case 17: sprite.priority1_enable = enable; break;
|
||||
case 18: sprite.priority2_enable = enable; break;
|
||||
case 19: sprite.priority3_enable = enable; break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +138,7 @@ bg1(*this, Background::ID::BG1),
|
||||
bg2(*this, Background::ID::BG2),
|
||||
bg3(*this, Background::ID::BG3),
|
||||
bg4(*this, Background::ID::BG4),
|
||||
oam(*this),
|
||||
sprite(*this),
|
||||
screen(*this) {
|
||||
surface = new uint16[512 * 512];
|
||||
output = surface + 16 * 512;
|
||||
|
@@ -1,5 +1,9 @@
|
||||
class PPU : public Processor, public PPUcounter, public MMIO {
|
||||
class PPU : public Processor, public PPUcounter {
|
||||
public:
|
||||
uint8 vram[64 * 1024];
|
||||
uint8 oam[544];
|
||||
uint8 cgram[512];
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_cpu();
|
||||
@@ -10,6 +14,7 @@ public:
|
||||
bool hires() const;
|
||||
|
||||
void enter();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
void scanline();
|
||||
@@ -38,7 +43,7 @@ private:
|
||||
Background bg2;
|
||||
Background bg3;
|
||||
Background bg4;
|
||||
Sprite oam;
|
||||
Sprite sprite;
|
||||
Screen screen;
|
||||
|
||||
struct Display {
|
||||
|
@@ -2,11 +2,10 @@
|
||||
|
||||
unsigned PPU::Screen::get_palette(unsigned color) {
|
||||
#if defined(ARCH_LSB)
|
||||
static uint16 *cgram = (uint16*)memory::cgram.data();
|
||||
return cgram[color];
|
||||
return ((uint16*)ppu.cgram)[color];
|
||||
#else
|
||||
color <<= 1;
|
||||
return (memory::cgram[color + 0] << 0) + (memory::cgram[color + 1] << 8);
|
||||
return (ppu.cgram[color + 0] << 0) + (ppu.cgram[color + 1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -16,12 +16,16 @@ void PPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(vram);
|
||||
s.array(oam);
|
||||
s.array(cgram);
|
||||
|
||||
cache.serialize(s);
|
||||
bg1.serialize(s);
|
||||
bg2.serialize(s);
|
||||
bg3.serialize(s);
|
||||
bg4.serialize(s);
|
||||
oam.serialize(s);
|
||||
sprite.serialize(s);
|
||||
screen.serialize(s);
|
||||
|
||||
s.integer(display.interlace);
|
||||
|
@@ -9,13 +9,6 @@ namespace SNES {
|
||||
#include "xml.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
namespace memory {
|
||||
MappedRAM cartrom, cartram, cartrtc;
|
||||
MappedRAM bsxflash, bsxram, bsxpram;
|
||||
MappedRAM stArom, stAram;
|
||||
MappedRAM stBrom, stBram;
|
||||
};
|
||||
|
||||
Cartridge cartridge;
|
||||
|
||||
void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
|
||||
@@ -37,48 +30,25 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
|
||||
has_msu1 = false;
|
||||
has_serial = false;
|
||||
|
||||
nvram.reset();
|
||||
|
||||
parse_xml(xml_list);
|
||||
//print(xml_list[0], "\n\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
memory::cartram.map(allocate<uint8_t>(ram_size, 0xff), ram_size);
|
||||
ram.map(allocate<uint8>(ram_size, 0xff), ram_size);
|
||||
nvram.append({ "srm", ram.data(), ram.size() });
|
||||
}
|
||||
|
||||
if(has_srtc || has_spc7110rtc) {
|
||||
memory::cartrtc.map(allocate<uint8_t>(20, 0xff), 20);
|
||||
}
|
||||
rom.write_protect(true);
|
||||
ram.write_protect(false);
|
||||
|
||||
if(mode == Mode::Bsx) {
|
||||
memory::bsxram.map (allocate<uint8_t>( 32 * 1024, 0xff), 32 * 1024);
|
||||
memory::bsxpram.map(allocate<uint8_t>(512 * 1024, 0xff), 512 * 1024);
|
||||
}
|
||||
|
||||
if(mode == Mode::SufamiTurbo) {
|
||||
if(memory::stArom.data()) memory::stAram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
|
||||
if(memory::stBrom.data()) memory::stBram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
|
||||
}
|
||||
|
||||
memory::cartrom.write_protect(true);
|
||||
memory::cartram.write_protect(false);
|
||||
memory::cartrtc.write_protect(false);
|
||||
memory::bsxflash.write_protect(true);
|
||||
memory::bsxram.write_protect(false);
|
||||
memory::bsxpram.write_protect(false);
|
||||
memory::stArom.write_protect(true);
|
||||
memory::stAram.write_protect(false);
|
||||
memory::stBrom.write_protect(true);
|
||||
memory::stBram.write_protect(false);
|
||||
|
||||
unsigned checksum = ~0; foreach(n, memory::cartrom ) checksum = crc32_adjust(checksum, n);
|
||||
if(memory::bsxflash.size() != 0 && memory::bsxflash.size() != ~0) foreach(n, memory::bsxflash) checksum = crc32_adjust(checksum, n);
|
||||
if(memory::stArom.size() != 0 && memory::stArom.size() != ~0) foreach(n, memory::stArom ) checksum = crc32_adjust(checksum, n);
|
||||
if(memory::stBrom.size() != 0 && memory::stBrom.size() != ~0) foreach(n, memory::stBrom ) checksum = crc32_adjust(checksum, n);
|
||||
crc32 = ~checksum;
|
||||
crc32 = crc32_calculate(rom.data(), rom.size());
|
||||
|
||||
sha256_ctx sha;
|
||||
uint8_t shahash[32];
|
||||
sha256_init(&sha);
|
||||
sha256_chunk(&sha, memory::cartrom.data(), memory::cartrom.size());
|
||||
sha256_chunk(&sha, rom.data(), rom.size());
|
||||
sha256_final(&sha);
|
||||
sha256_hash(&sha, shahash);
|
||||
|
||||
@@ -86,24 +56,17 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
|
||||
foreach(n, shahash) hash << hex<2>(n);
|
||||
sha256 = hash;
|
||||
|
||||
bus.load_cart();
|
||||
system.load();
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
void Cartridge::unload() {
|
||||
memory::cartrom.reset();
|
||||
memory::cartram.reset();
|
||||
memory::cartrtc.reset();
|
||||
memory::bsxflash.reset();
|
||||
memory::bsxram.reset();
|
||||
memory::bsxpram.reset();
|
||||
memory::stArom.reset();
|
||||
memory::stAram.reset();
|
||||
memory::stBrom.reset();
|
||||
memory::stBram.reset();
|
||||
|
||||
if(loaded == false) return;
|
||||
bus.unload_cart();
|
||||
|
||||
system.unload();
|
||||
rom.reset();
|
||||
ram.reset();
|
||||
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
|
@@ -13,6 +13,9 @@ public:
|
||||
PAL,
|
||||
};
|
||||
|
||||
MappedRAM rom;
|
||||
MappedRAM ram;
|
||||
|
||||
//assigned externally to point to file-system datafiles (msu1 and serial)
|
||||
//example: "/path/to/filename.sfc" would set this to "/path/to/filename"
|
||||
readwrite<string> basename;
|
||||
@@ -39,9 +42,20 @@ public:
|
||||
readonly<bool> has_msu1;
|
||||
readonly<bool> has_serial;
|
||||
|
||||
struct NonVolatileRAM {
|
||||
const string id;
|
||||
uint8_t *data;
|
||||
unsigned size;
|
||||
unsigned slot;
|
||||
NonVolatileRAM() : id(""), data(0), size(0), slot(0) {}
|
||||
NonVolatileRAM(const string id, uint8_t *data, unsigned size, unsigned slot = 0)
|
||||
: id(id), data(data), size(size), slot(slot) {}
|
||||
};
|
||||
linear_vector<NonVolatileRAM> nvram;
|
||||
|
||||
struct Mapping {
|
||||
Memory *memory;
|
||||
MMIO *mmio;
|
||||
function<uint8 (unsigned)> read;
|
||||
function<void (unsigned, uint8)> write;
|
||||
Bus::MapMode mode;
|
||||
unsigned banklo;
|
||||
unsigned bankhi;
|
||||
@@ -51,10 +65,10 @@ public:
|
||||
unsigned size;
|
||||
|
||||
Mapping();
|
||||
Mapping(const function<uint8 (unsigned)>&, const function<void (unsigned, uint8)>&);
|
||||
Mapping(Memory&);
|
||||
Mapping(MMIO&);
|
||||
};
|
||||
array<Mapping> mapping;
|
||||
linear_vector<Mapping> mapping;
|
||||
|
||||
void load(Mode, const lstring&);
|
||||
void unload();
|
||||
@@ -92,11 +106,4 @@ private:
|
||||
void xml_parse_mode(Mapping&, const string&);
|
||||
};
|
||||
|
||||
namespace memory {
|
||||
extern MappedRAM cartrom, cartram, cartrtc;
|
||||
extern MappedRAM bsxflash, bsxram, bsxpram;
|
||||
extern MappedRAM stArom, stAram;
|
||||
extern MappedRAM stBrom, stBram;
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
||||
|
@@ -1,29 +1,7 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
void Cartridge::serialize(serializer &s) {
|
||||
if(memory::cartram.size() != 0 && memory::cartram.size() != ~0) {
|
||||
s.array(memory::cartram.data(), memory::cartram.size());
|
||||
}
|
||||
|
||||
if(memory::cartrtc.size() != 0 && memory::cartrtc.size() != ~0) {
|
||||
s.array(memory::cartrtc.data(), memory::cartrtc.size());
|
||||
}
|
||||
|
||||
if(memory::bsxram.size() != 0 && memory::bsxram.size() != ~0) {
|
||||
s.array(memory::bsxram.data(), memory::bsxram.size());
|
||||
}
|
||||
|
||||
if(memory::bsxpram.size() != 0 && memory::bsxpram.size() != ~0) {
|
||||
s.array(memory::bsxpram.data(), memory::bsxpram.size());
|
||||
}
|
||||
|
||||
if(memory::stAram.size() != 0 && memory::stAram.size() != ~0) {
|
||||
s.array(memory::stAram.data(), memory::stAram.size());
|
||||
}
|
||||
|
||||
if(memory::stBram.size() != 0 && memory::stBram.size() != ~0) {
|
||||
s.array(memory::stBram.data(), memory::stBram.size());
|
||||
}
|
||||
if(ram.data()) s.array(ram.data(), ram.size());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -52,6 +52,7 @@ void Cartridge::parse_xml_cartridge(const char *data) {
|
||||
}
|
||||
|
||||
void Cartridge::parse_xml_bsx(const char *data) {
|
||||
has_bsx_slot = true;
|
||||
}
|
||||
|
||||
void Cartridge::parse_xml_sufami_turbo(const char *data, bool slot) {
|
||||
@@ -63,13 +64,14 @@ void Cartridge::parse_xml_gameboy(const char *data) {
|
||||
void Cartridge::xml_parse_rom(xml_element &root) {
|
||||
foreach(leaf, root.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::cartrom);
|
||||
Mapping m(rom);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = rom.size();
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
@@ -82,13 +84,14 @@ void Cartridge::xml_parse_ram(xml_element &root) {
|
||||
|
||||
foreach(leaf, root.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::cartram);
|
||||
Mapping m(ram);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = ram_size;
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
@@ -107,7 +110,7 @@ void Cartridge::xml_parse_icd2(xml_element &root) {
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "map") {
|
||||
Mapping m((Memory&)icd2);
|
||||
Mapping m({ &ICD2::read, &icd2 }, { &ICD2::write, &icd2 });
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@@ -123,7 +126,7 @@ void Cartridge::xml_parse_superfx(xml_element &root) {
|
||||
if(node.name == "rom") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::fxrom);
|
||||
Mapping m(superfx.rom);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
@@ -140,20 +143,21 @@ void Cartridge::xml_parse_superfx(xml_element &root) {
|
||||
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::fxram);
|
||||
Mapping m(superfx.ram);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = ram_size;
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
} else if(node.name == "mmio") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(superfx);
|
||||
Mapping m({ &SuperFX::mmio_read, &superfx }, { &SuperFX::mmio_write, &superfx });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@@ -168,29 +172,44 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
|
||||
has_sa1 = true;
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "rom") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::vsprom);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
if(node.name == "mcu") {
|
||||
foreach(subnode, node.element) {
|
||||
if(subnode.name == "rom") {
|
||||
foreach(leaf, subnode.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m({ &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
} else if(subnode.name == "ram") {
|
||||
foreach(leaf, subnode.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m({ &SA1::mmc_cpu_read, &sa1 }, { &SA1::mmc_cpu_write, &sa1 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
} else if(node.name == "iram") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::cpuiram);
|
||||
Mapping m(sa1.cpuiram);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = 2048;
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
@@ -201,20 +220,21 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
|
||||
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::cc1bwram);
|
||||
Mapping m(sa1.cpubwram);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = ram_size;
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
} else if(node.name == "mmio") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(sa1);
|
||||
Mapping m({ &SA1::mmio_read, &sa1 }, { &SA1::mmio_write, &sa1 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@@ -276,33 +296,36 @@ void Cartridge::xml_parse_necdsp(xml_element &root) {
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "dr") {
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "mask") necdsp.drmask = hex(attr.content);
|
||||
if(attr.name == "test") necdsp.drtest = hex(attr.content);
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m({ &NECDSP::dr_read, &necdsp }, { &NECDSP::dr_write, &necdsp });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(node.name == "sr") {
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "mask") necdsp.srmask = hex(attr.content);
|
||||
if(attr.name == "test") necdsp.srtest = hex(attr.content);
|
||||
} else if(node.name == "sr") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m({ &NECDSP::sr_read, &necdsp }, { &NECDSP::sr_write, &necdsp });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(node.name == "dp") {
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "mask") necdsp.dpmask = hex(attr.content);
|
||||
if(attr.name == "test") necdsp.dptest = hex(attr.content);
|
||||
} else if(node.name == "dp") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m({ &NECDSP::dp_read, &necdsp }, { &NECDSP::dp_write, &necdsp });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(node.name == "map") {
|
||||
Mapping m(necdsp);
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
|
||||
if(program == "") {
|
||||
@@ -323,7 +346,7 @@ void Cartridge::xml_parse_bsx(xml_element &root) {
|
||||
if(node.name == "slot") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::bsxflash);
|
||||
Mapping m(bsxflash.memory);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
@@ -333,10 +356,20 @@ void Cartridge::xml_parse_bsx(xml_element &root) {
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
} else if(node.name == "mcu") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m({ &BSXCartridge::mcu_read, &bsxcartridge }, { &BSXCartridge::mcu_write, &bsxcartridge });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
} else if(node.name == "mmio") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(bsxcart);
|
||||
Mapping m({ &BSXCartridge::mmio_read, &bsxcartridge }, { &BSXCartridge::mmio_write, &bsxcartridge });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@@ -364,27 +397,29 @@ void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
|
||||
if(slot.name == "rom") {
|
||||
foreach(leaf, slot.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(slotid == 0 ? memory::stArom : memory::stBrom);
|
||||
Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom;
|
||||
Mapping m(memory);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
if(m.memory->size() > 0) mapping.append(m);
|
||||
if(memory.size() > 0) mapping.append(m);
|
||||
}
|
||||
}
|
||||
} else if(slot.name == "ram") {
|
||||
foreach(leaf, slot.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(slotid == 0 ? memory::stAram : memory::stBram);
|
||||
Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram;
|
||||
Mapping m(memory);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
if(m.memory->size() > 0) mapping.append(m);
|
||||
if(memory.size() > 0) mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -398,7 +433,7 @@ void Cartridge::xml_parse_srtc(xml_element &root) {
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "map") {
|
||||
Mapping m(srtc);
|
||||
Mapping m({ &SRTC::read, &srtc }, { &SRTC::write, &srtc });
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@@ -414,7 +449,7 @@ void Cartridge::xml_parse_sdd1(xml_element &root) {
|
||||
if(node.name == "mcu") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m((Memory&)sdd1);
|
||||
Mapping m({ &SDD1::mcu_read, &sdd1 }, { &SDD1::mcu_write, &sdd1 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@@ -424,7 +459,7 @@ void Cartridge::xml_parse_sdd1(xml_element &root) {
|
||||
} else if(node.name == "mmio") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m((MMIO&)sdd1);
|
||||
Mapping m({ &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@@ -443,7 +478,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
|
||||
if(node.name == "dcu") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(spc7110dcu);
|
||||
Mapping m({ &SPC7110::dcu_read, &spc7110 }, { &SPC7110::dcu_write, &spc7110 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@@ -453,7 +488,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
|
||||
} else if(node.name == "mcu") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(spc7110mcu);
|
||||
Mapping m({ &SPC7110::mcu_read, &spc7110 }, { &SPC7110::mcu_write, &spc7110 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "offset") spc7110.data_rom_offset = hex(attr.content);
|
||||
@@ -464,7 +499,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
|
||||
} else if(node.name == "mmio") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(spc7110);
|
||||
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@@ -478,7 +513,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
|
||||
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(spc7110ram);
|
||||
Mapping m({ &SPC7110::ram_read, &spc7110 }, { &SPC7110::ram_write, &spc7110 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
@@ -493,7 +528,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
|
||||
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(spc7110);
|
||||
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@@ -509,7 +544,7 @@ void Cartridge::xml_parse_cx4(xml_element &root) {
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "map") {
|
||||
Mapping m(cx4);
|
||||
Mapping m({ &Cx4::read, &cx4 }, { &Cx4::write, &cx4 });
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@@ -523,7 +558,7 @@ void Cartridge::xml_parse_obc1(xml_element &root) {
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "map") {
|
||||
Mapping m(obc1);
|
||||
Mapping m({ &OBC1::read, &obc1 }, { &OBC1::write, &obc1 });
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@@ -533,22 +568,11 @@ void Cartridge::xml_parse_obc1(xml_element &root) {
|
||||
}
|
||||
|
||||
void Cartridge::xml_parse_setarisc(xml_element &root) {
|
||||
unsigned program = 0;
|
||||
|
||||
foreach(attr, root.attribute) {
|
||||
if(attr.name == "program") {
|
||||
if(attr.content == "ST-0018") {
|
||||
program = 1;
|
||||
has_st0018 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MMIO *map[2] = { 0, &st0018 };
|
||||
has_st0018 = true;
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "map" && map[program]) {
|
||||
Mapping m(*map[program]);
|
||||
if(node.name == "map") {
|
||||
Mapping m({ &ST0018::mmio_read, &st0018 }, { &ST0018::mmio_write, &st0018 });
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@@ -561,16 +585,12 @@ void Cartridge::xml_parse_msu1(xml_element &root) {
|
||||
has_msu1 = true;
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "mmio") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(msu1);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
if(node.name == "map") {
|
||||
Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -611,22 +631,20 @@ void Cartridge::xml_parse_mode(Mapping &m, const string& data) {
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping() {
|
||||
memory = 0;
|
||||
mmio = 0;
|
||||
mode = Bus::MapMode::Direct;
|
||||
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping(Memory &memory_) {
|
||||
memory = &memory_;
|
||||
mmio = 0;
|
||||
Cartridge::Mapping::Mapping(Memory &memory) {
|
||||
read = { &Memory::read, &memory };
|
||||
write = { &Memory::write, &memory };
|
||||
mode = Bus::MapMode::Direct;
|
||||
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping(MMIO &mmio_) {
|
||||
memory = 0;
|
||||
mmio = &mmio_;
|
||||
Cartridge::Mapping::Mapping(const function<uint8 (unsigned)> &read_, const function<void (unsigned, uint8)> &write_) {
|
||||
read = read_;
|
||||
write = write_;
|
||||
mode = Bus::MapMode::Direct;
|
||||
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||
}
|
||||
|
@@ -1,2 +0,0 @@
|
||||
bool Cheat::active() const { return cheat_enabled; }
|
||||
bool Cheat::exists(unsigned addr) const { return bitmask[addr >> 3] & 1 << (addr & 7); }
|
@@ -15,7 +15,7 @@ void Cheat::enable(bool state) {
|
||||
}
|
||||
|
||||
void Cheat::synchronize() {
|
||||
memset(bitmask, 0x00, sizeof bitmask);
|
||||
memcpy(bus.lookup, lookup, 16 * 1024 * 1024);
|
||||
code_enabled = false;
|
||||
|
||||
for(unsigned i = 0; i < size(); i++) {
|
||||
@@ -26,16 +26,16 @@ void Cheat::synchronize() {
|
||||
code_enabled = true;
|
||||
|
||||
unsigned addr = mirror(code.addr[n]);
|
||||
bitmask[addr >> 3] |= 1 << (addr & 7);
|
||||
bus.lookup[addr] = 0xff;
|
||||
if((addr & 0xffe000) == 0x7e0000) {
|
||||
//mirror $7e:0000-1fff to $00-3f|80-bf:0000-1fff
|
||||
unsigned mirroraddr;
|
||||
for(unsigned x = 0; x <= 0x3f; x++) {
|
||||
mirroraddr = ((0x00 + x) << 16) + (addr & 0x1fff);
|
||||
bitmask[mirroraddr >> 3] |= 1 << (mirroraddr & 7);
|
||||
bus.lookup[mirroraddr] = 0xff;
|
||||
|
||||
mirroraddr = ((0x80 + x) << 16) + (addr & 0x1fff);
|
||||
bitmask[mirroraddr >> 3] |= 1 << (mirroraddr & 7);
|
||||
bus.lookup[mirroraddr] = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ void Cheat::synchronize() {
|
||||
cheat_enabled = system_enabled && code_enabled;
|
||||
}
|
||||
|
||||
bool Cheat::read(unsigned addr, uint8 &data) const {
|
||||
uint8 Cheat::read(unsigned addr) const {
|
||||
addr = mirror(addr);
|
||||
|
||||
for(unsigned i = 0; i < size(); i++) {
|
||||
@@ -53,20 +53,37 @@ bool Cheat::read(unsigned addr, uint8 &data) const {
|
||||
|
||||
for(unsigned n = 0; n < code.addr.size(); n++) {
|
||||
if(addr == mirror(code.addr[n])) {
|
||||
data = code.data[n];
|
||||
return true;
|
||||
return code.data[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void Cheat::init() {
|
||||
bus.reader[0xff] = [](unsigned addr) {
|
||||
bus.reader[cheat.lookup[addr]](bus.target[addr]);
|
||||
return cheat.read(addr);
|
||||
};
|
||||
|
||||
bus.writer[0xff] = [](unsigned addr, uint8 data) {
|
||||
return bus.writer[cheat.lookup[addr]](bus.target[addr], data);
|
||||
};
|
||||
|
||||
memcpy(lookup, bus.lookup, 16 * 1024 * 1024);
|
||||
}
|
||||
|
||||
Cheat::Cheat() {
|
||||
lookup = new uint8[16 * 1024 * 1024];
|
||||
system_enabled = true;
|
||||
synchronize();
|
||||
}
|
||||
|
||||
Cheat::~Cheat() {
|
||||
delete[] lookup;
|
||||
}
|
||||
|
||||
//===============
|
||||
//encode / decode
|
||||
//===============
|
||||
|
@@ -14,18 +14,17 @@ public:
|
||||
bool enabled() const;
|
||||
void enable(bool);
|
||||
void synchronize();
|
||||
bool read(unsigned, uint8&) const;
|
||||
|
||||
inline bool active() const;
|
||||
inline bool exists(unsigned addr) const;
|
||||
uint8 read(unsigned) const;
|
||||
void init();
|
||||
|
||||
Cheat();
|
||||
~Cheat();
|
||||
|
||||
static bool decode(const char*, unsigned&, uint8&, Type&);
|
||||
static bool encode(string&, unsigned, uint8, Type);
|
||||
|
||||
private:
|
||||
uint8 bitmask[0x200000];
|
||||
uint8 *lookup;
|
||||
bool system_enabled;
|
||||
bool code_enabled;
|
||||
bool cheat_enabled;
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
#define BSX_CPP
|
||||
namespace SNES {
|
||||
#include "bsx_base.cpp"
|
||||
#include "bsx_cart.cpp"
|
||||
#include "bsx_flash.cpp"
|
||||
#include "satellaview/satellaview.cpp"
|
||||
#include "cartridge/cartridge.cpp"
|
||||
#include "flash/flash.cpp"
|
||||
}
|
||||
|
@@ -1,71 +1,3 @@
|
||||
class BSXBase : public MMIO {
|
||||
public:
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
private:
|
||||
struct {
|
||||
uint8 r2188, r2189, r218a, r218b;
|
||||
uint8 r218c, r218d, r218e, r218f;
|
||||
uint8 r2190, r2191, r2192, r2193;
|
||||
uint8 r2194, r2195, r2196, r2197;
|
||||
uint8 r2198, r2199, r219a, r219b;
|
||||
uint8 r219c, r219d, r219e, r219f;
|
||||
|
||||
uint8 r2192_counter;
|
||||
uint8 r2192_hour, r2192_minute, r2192_second;
|
||||
} regs;
|
||||
};
|
||||
|
||||
class BSXCart : public MMIO {
|
||||
public:
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
BSXCart();
|
||||
~BSXCart();
|
||||
|
||||
private:
|
||||
struct {
|
||||
uint8 r[16];
|
||||
} regs;
|
||||
|
||||
void update_memory_map();
|
||||
};
|
||||
|
||||
class BSXFlash : public Memory {
|
||||
public:
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
unsigned size() const;
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
|
||||
private:
|
||||
struct {
|
||||
unsigned command;
|
||||
uint8 write_old;
|
||||
uint8 write_new;
|
||||
|
||||
bool flash_enable;
|
||||
bool read_enable;
|
||||
bool write_enable;
|
||||
} regs;
|
||||
};
|
||||
|
||||
extern BSXBase bsxbase;
|
||||
extern BSXCart bsxcart;
|
||||
extern BSXFlash bsxflash;
|
||||
#include "satellaview/satellaview.hpp"
|
||||
#include "cartridge/cartridge.hpp"
|
||||
#include "flash/flash.hpp"
|
||||
|
@@ -1,96 +0,0 @@
|
||||
#ifdef BSX_CPP
|
||||
|
||||
BSXCart bsxcart;
|
||||
|
||||
void BSXCart::init() {
|
||||
}
|
||||
|
||||
void BSXCart::enable() {
|
||||
}
|
||||
|
||||
void BSXCart::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void BSXCart::reset() {
|
||||
for(unsigned i = 0; i < 16; i++) regs.r[i] = 0x00;
|
||||
regs.r[0x07] = 0x80;
|
||||
regs.r[0x08] = 0x80;
|
||||
|
||||
update_memory_map();
|
||||
}
|
||||
|
||||
void BSXCart::update_memory_map() {
|
||||
Memory &cart = (regs.r[0x01] & 0x80) == 0x00 ? (Memory&)bsxflash : (Memory&)memory::bsxpram;
|
||||
|
||||
if((regs.r[0x02] & 0x80) == 0x00) {
|
||||
//LoROM mapping
|
||||
bus.map(Bus::MapMode::Linear, 0x00, 0x7d, 0x8000, 0xffff, cart);
|
||||
bus.map(Bus::MapMode::Linear, 0x80, 0xff, 0x8000, 0xffff, cart);
|
||||
} else {
|
||||
//HiROM mapping
|
||||
bus.map(Bus::MapMode::Shadow, 0x00, 0x3f, 0x8000, 0xffff, cart);
|
||||
bus.map(Bus::MapMode::Linear, 0x40, 0x7d, 0x0000, 0xffff, cart);
|
||||
bus.map(Bus::MapMode::Shadow, 0x80, 0xbf, 0x8000, 0xffff, cart);
|
||||
bus.map(Bus::MapMode::Linear, 0xc0, 0xff, 0x0000, 0xffff, cart);
|
||||
}
|
||||
|
||||
if(regs.r[0x03] & 0x80) {
|
||||
bus.map(Bus::MapMode::Linear, 0x60, 0x6f, 0x0000, 0xffff, memory::bsxpram);
|
||||
//bus.map(Bus::MapMode::Linear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
|
||||
}
|
||||
|
||||
if((regs.r[0x05] & 0x80) == 0x00) {
|
||||
bus.map(Bus::MapMode::Linear, 0x40, 0x4f, 0x0000, 0xffff, memory::bsxpram);
|
||||
}
|
||||
|
||||
if((regs.r[0x06] & 0x80) == 0x00) {
|
||||
bus.map(Bus::MapMode::Linear, 0x50, 0x5f, 0x0000, 0xffff, memory::bsxpram);
|
||||
}
|
||||
|
||||
if(regs.r[0x07] & 0x80) {
|
||||
bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom);
|
||||
}
|
||||
|
||||
if(regs.r[0x08] & 0x80) {
|
||||
bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom);
|
||||
}
|
||||
|
||||
bus.map(Bus::MapMode::Shadow, 0x20, 0x3f, 0x6000, 0x7fff, memory::bsxpram);
|
||||
bus.map(Bus::MapMode::Linear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
|
||||
}
|
||||
|
||||
uint8 BSXCart::mmio_read(unsigned addr) {
|
||||
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
|
||||
uint8 n = (addr >> 16) & 15;
|
||||
return regs.r[n];
|
||||
}
|
||||
|
||||
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
|
||||
return memory::bsxram.read(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void BSXCart::mmio_write(unsigned addr, uint8 data) {
|
||||
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
|
||||
uint8 n = (addr >> 16) & 15;
|
||||
regs.r[n] = data;
|
||||
if(n == 0x0e && data & 0x80) update_memory_map();
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
|
||||
return memory::bsxram.write(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
|
||||
}
|
||||
}
|
||||
|
||||
BSXCart::BSXCart() {
|
||||
}
|
||||
|
||||
BSXCart::~BSXCart() {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
149
bsnes/snes/chip/bsx/cartridge/cartridge.cpp
Executable file
149
bsnes/snes/chip/bsx/cartridge/cartridge.cpp
Executable file
@@ -0,0 +1,149 @@
|
||||
#ifdef BSX_CPP
|
||||
|
||||
BSXCartridge bsxcartridge;
|
||||
|
||||
void BSXCartridge::init() {
|
||||
}
|
||||
|
||||
void BSXCartridge::load() {
|
||||
sram.map(allocate<uint8>(32 * 1024, 0xff), 32 * 1024);
|
||||
sram.write_protect(false);
|
||||
cartridge.nvram.append({ "bss", sram.data(), sram.size() });
|
||||
|
||||
psram.map(allocate<uint8>(512 * 1024, 0xff), 512 * 1024);
|
||||
psram.write_protect(false);
|
||||
cartridge.nvram.append({ "bsp", psram.data(), psram.size() });
|
||||
}
|
||||
|
||||
void BSXCartridge::unload() {
|
||||
}
|
||||
|
||||
void BSXCartridge::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void BSXCartridge::reset() {
|
||||
for(unsigned i = 0; i < 16; i++) r[i] = 0x00;
|
||||
r[0x07] = 0x80;
|
||||
r[0x08] = 0x80;
|
||||
mmio_commit();
|
||||
}
|
||||
|
||||
uint8 BSXCartridge::memory_access(bool write, Memory &memory, unsigned addr, uint8 data) {
|
||||
if(write == 0) return memory_read(memory, addr);
|
||||
memory_write(memory, addr, data);
|
||||
}
|
||||
|
||||
uint8 BSXCartridge::memory_read(Memory &memory, unsigned addr) {
|
||||
addr = bus.mirror(addr, memory.size());
|
||||
return memory.read(addr);
|
||||
}
|
||||
|
||||
void BSXCartridge::memory_write(Memory &memory, unsigned addr, uint8 data) {
|
||||
addr = bus.mirror(addr, memory.size());
|
||||
return memory.write(addr, data);
|
||||
}
|
||||
|
||||
//mcu_access() allows mcu_read() and mcu_write() to share decoding logic
|
||||
uint8 BSXCartridge::mcu_access(bool write, unsigned addr, uint8 data) {
|
||||
if(within<0x00, 0x1f, 0x8000, 0xffff>(addr)) {
|
||||
if(r07 == 1) {
|
||||
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
|
||||
return memory_access(write, cartridge.rom, addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
if(within<0x80, 0x9f, 0x8000, 0xffff>(addr)) {
|
||||
if(r08 == 1) {
|
||||
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
|
||||
return memory_access(write, cartridge.rom, addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
if(within<0x20, 0x3f, 0x6000, 0x7fff>(addr)) {
|
||||
return memory_access(write, psram, addr, data);
|
||||
}
|
||||
|
||||
if(within<0x40, 0x4f, 0x0000, 0xffff>(addr)) {
|
||||
if(r05 == 0) return memory_access(write, psram, addr & 0x0fffff, data);
|
||||
}
|
||||
|
||||
if(within<0x50, 0x5f, 0x0000, 0xffff>(addr)) {
|
||||
if(r06 == 0) return memory_access(write, psram, addr & 0x0fffff, data);
|
||||
}
|
||||
|
||||
if(within<0x60, 0x6f, 0x0000, 0xffff>(addr)) {
|
||||
if(r03 == 1) return memory_access(write, psram, addr & 0x0fffff, data);
|
||||
}
|
||||
|
||||
if(within<0x70, 0x77, 0x0000, 0xffff>(addr)) {
|
||||
return memory_access(write, psram, addr & 0x07ffff, data);
|
||||
}
|
||||
|
||||
if(within<0x00, 0x3f, 0x8000, 0xffff>(addr)
|
||||
|| within<0x40, 0x7f, 0x0000, 0xffff>(addr)
|
||||
|| within<0x80, 0xbf, 0x8000, 0xffff>(addr)
|
||||
|| within<0xc0, 0xff, 0x0000, 0xffff>(addr)
|
||||
) {
|
||||
if(r02 == 0) addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff);
|
||||
Memory &memory = (r01 == 0 ? (Memory&)bsxflash : (Memory&)psram);
|
||||
return memory_access(write, memory, addr & 0x7fffff, data);
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
}
|
||||
|
||||
uint8 BSXCartridge::mcu_read(unsigned addr) {
|
||||
return mcu_access(0, addr);
|
||||
}
|
||||
|
||||
void BSXCartridge::mcu_write(unsigned addr, uint8 data) {
|
||||
mcu_access(1, addr, data);
|
||||
}
|
||||
|
||||
uint8 BSXCartridge::mmio_read(unsigned addr) {
|
||||
if(within<0x00, 0x0f, 0x5000, 0x5000>(addr)) {
|
||||
uint8 n = (addr >> 16) & 15;
|
||||
return r[n];
|
||||
}
|
||||
|
||||
if(within<0x10, 0x17, 0x5000, 0x5fff>(addr)) {
|
||||
return memory_read(sram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void BSXCartridge::mmio_write(unsigned addr, uint8 data) {
|
||||
if(within<0x00, 0x0f, 0x5000, 0x5000>(addr)) {
|
||||
uint8 n = (addr >> 16) & 15;
|
||||
r[n] = data;
|
||||
if(n == 0x0e && data & 0x80) mmio_commit();
|
||||
return;
|
||||
}
|
||||
|
||||
if(within<0x10, 0x17, 0x5000, 0x5fff>(addr)) {
|
||||
return memory_write(sram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
|
||||
}
|
||||
}
|
||||
|
||||
void BSXCartridge::mmio_commit() {
|
||||
r00 = r[0x00] & 0x80;
|
||||
r01 = r[0x01] & 0x80;
|
||||
r02 = r[0x02] & 0x80;
|
||||
r03 = r[0x03] & 0x80;
|
||||
r04 = r[0x04] & 0x80;
|
||||
r05 = r[0x05] & 0x80;
|
||||
r06 = r[0x06] & 0x80;
|
||||
r07 = r[0x07] & 0x80;
|
||||
r08 = r[0x08] & 0x80;
|
||||
r09 = r[0x09] & 0x80;
|
||||
r0a = r[0x0a] & 0x80;
|
||||
r0b = r[0x0b] & 0x80;
|
||||
r0c = r[0x0c] & 0x80;
|
||||
r0d = r[0x0d] & 0x80;
|
||||
r0e = r[0x0e] & 0x80;
|
||||
r0f = r[0x0f] & 0x80;
|
||||
}
|
||||
|
||||
#endif
|
32
bsnes/snes/chip/bsx/cartridge/cartridge.hpp
Executable file
32
bsnes/snes/chip/bsx/cartridge/cartridge.hpp
Executable file
@@ -0,0 +1,32 @@
|
||||
class BSXCartridge {
|
||||
public:
|
||||
MappedRAM sram;
|
||||
MappedRAM psram;
|
||||
|
||||
void init();
|
||||
void load();
|
||||
void unload();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 memory_access(bool write, Memory &memory, unsigned addr, uint8 data);
|
||||
uint8 memory_read(Memory &memory, unsigned addr);
|
||||
void memory_write(Memory &memory, unsigned addr, uint8 data);
|
||||
|
||||
uint8 mcu_access(bool write, unsigned addr, uint8 data = 0x00);
|
||||
uint8 mcu_read(unsigned addr);
|
||||
void mcu_write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
void mmio_commit();
|
||||
|
||||
private:
|
||||
uint8 r[16];
|
||||
bool r00, r01, r02, r03;
|
||||
bool r04, r05, r06, r07;
|
||||
bool r08, r09, r0a, r0b;
|
||||
bool r0c, r0d, r0e, r0f;
|
||||
};
|
||||
|
||||
extern BSXCartridge bsxcartridge;
|
@@ -2,8 +2,18 @@
|
||||
|
||||
BSXFlash bsxflash;
|
||||
|
||||
void BSXFlash::init() {}
|
||||
void BSXFlash::enable() {}
|
||||
void BSXFlash::init() {
|
||||
}
|
||||
|
||||
void BSXFlash::load() {
|
||||
if(memory.size() == 0) {
|
||||
memory.map(allocate<uint8>(1024 * 1024, 0xff), 1024 * 1024);
|
||||
}
|
||||
}
|
||||
|
||||
void BSXFlash::unload() {
|
||||
memory.reset();
|
||||
}
|
||||
|
||||
void BSXFlash::power() {
|
||||
reset();
|
||||
@@ -17,11 +27,11 @@ void BSXFlash::reset() {
|
||||
regs.flash_enable = false;
|
||||
regs.read_enable = false;
|
||||
regs.write_enable = false;
|
||||
memory::bsxflash.write_protect(!regs.write_enable);
|
||||
memory.write_protect(!regs.write_enable);
|
||||
}
|
||||
|
||||
unsigned BSXFlash::size() const {
|
||||
return memory::bsxflash.size();
|
||||
return memory.size();
|
||||
}
|
||||
|
||||
uint8 BSXFlash::read(unsigned addr) {
|
||||
@@ -48,7 +58,7 @@ uint8 BSXFlash::read(unsigned addr) {
|
||||
}
|
||||
}
|
||||
|
||||
return memory::bsxflash.read(addr);
|
||||
return memory.read(addr);
|
||||
}
|
||||
|
||||
void BSXFlash::write(unsigned addr, uint8 data) {
|
||||
@@ -67,11 +77,11 @@ void BSXFlash::write(unsigned addr, uint8 data) {
|
||||
regs.write_new = data;
|
||||
|
||||
if(regs.write_enable && regs.write_old == regs.write_new) {
|
||||
return memory::bsxflash.write(addr, data);
|
||||
return memory.write(addr, data);
|
||||
}
|
||||
} else {
|
||||
if(regs.write_enable) {
|
||||
return memory::bsxflash.write(addr, data);
|
||||
return memory.write(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,9 +121,8 @@ void BSXFlash::write(unsigned addr, uint8 data) {
|
||||
regs.write_enable = false;
|
||||
}
|
||||
|
||||
memory::bsxflash.write_protect(!regs.write_enable);
|
||||
memory.write_protect(!regs.write_enable);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
27
bsnes/snes/chip/bsx/flash/flash.hpp
Executable file
27
bsnes/snes/chip/bsx/flash/flash.hpp
Executable file
@@ -0,0 +1,27 @@
|
||||
class BSXFlash : public Memory {
|
||||
public:
|
||||
MappedRAM memory;
|
||||
|
||||
void init();
|
||||
void load();
|
||||
void unload();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
unsigned size() const;
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
|
||||
private:
|
||||
struct {
|
||||
unsigned command;
|
||||
uint8 write_old;
|
||||
uint8 write_new;
|
||||
|
||||
bool flash_enable;
|
||||
bool read_enable;
|
||||
bool write_enable;
|
||||
} regs;
|
||||
};
|
||||
|
||||
extern BSXFlash bsxflash;
|
@@ -1,23 +1,27 @@
|
||||
#ifdef BSX_CPP
|
||||
|
||||
BSXBase bsxbase;
|
||||
BSXSatellaview bsxsatellaview;
|
||||
|
||||
void BSXBase::init() {
|
||||
void BSXSatellaview::init() {
|
||||
}
|
||||
|
||||
void BSXBase::enable() {
|
||||
for(uint16 i = 0x2188; i <= 0x219f; i++) memory::mmio.map(i, *this);
|
||||
void BSXSatellaview::load() {
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2188, 0x219f, { &BSXSatellaview::mmio_read, &bsxsatellaview }, { &BSXSatellaview::mmio_write, &bsxsatellaview });
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2188, 0x219f, { &BSXSatellaview::mmio_read, &bsxsatellaview }, { &BSXSatellaview::mmio_write, &bsxsatellaview });
|
||||
}
|
||||
|
||||
void BSXBase::power() {
|
||||
void BSXSatellaview::unload() {
|
||||
}
|
||||
|
||||
void BSXSatellaview::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void BSXBase::reset() {
|
||||
void BSXSatellaview::reset() {
|
||||
memset(®s, 0x00, sizeof regs);
|
||||
}
|
||||
|
||||
uint8 BSXBase::mmio_read(unsigned addr) {
|
||||
uint8 BSXSatellaview::mmio_read(unsigned addr) {
|
||||
addr &= 0xffff;
|
||||
|
||||
switch(addr) {
|
||||
@@ -75,7 +79,7 @@ uint8 BSXBase::mmio_read(unsigned addr) {
|
||||
return cpu.regs.mdr;
|
||||
}
|
||||
|
||||
void BSXBase::mmio_write(unsigned addr, uint8 data) {
|
||||
void BSXSatellaview::mmio_write(unsigned addr, uint8 data) {
|
||||
addr &= 0xffff;
|
||||
|
||||
switch(addr) {
|
||||
@@ -137,4 +141,3 @@ void BSXBase::mmio_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
26
bsnes/snes/chip/bsx/satellaview/satellaview.hpp
Executable file
26
bsnes/snes/chip/bsx/satellaview/satellaview.hpp
Executable file
@@ -0,0 +1,26 @@
|
||||
class BSXSatellaview {
|
||||
public:
|
||||
void init();
|
||||
void load();
|
||||
void unload();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
private:
|
||||
struct {
|
||||
uint8 r2188, r2189, r218a, r218b;
|
||||
uint8 r218c, r218d, r218e, r218f;
|
||||
uint8 r2190, r2191, r2192, r2193;
|
||||
uint8 r2194, r2195, r2196, r2197;
|
||||
uint8 r2198, r2199, r219a, r219b;
|
||||
uint8 r219c, r219d, r219e, r219f;
|
||||
|
||||
uint8 r2192_counter;
|
||||
uint8 r2192_hour, r2192_minute, r2192_second;
|
||||
} regs;
|
||||
};
|
||||
|
||||
extern BSXSatellaview bsxsatellaview;
|
@@ -14,6 +14,7 @@ struct Coprocessor : Processor {
|
||||
#include <snes/chip/cx4/cx4.hpp>
|
||||
#include <snes/chip/obc1/obc1.hpp>
|
||||
#include <snes/chip/st0018/st0018.hpp>
|
||||
#include <snes/chip/sufamiturbo/sufamiturbo.hpp>
|
||||
#include <snes/chip/msu1/msu1.hpp>
|
||||
#include <snes/chip/serial/serial.hpp>
|
||||
|
||||
|
@@ -20,7 +20,10 @@ Cx4 cx4;
|
||||
void Cx4::init() {
|
||||
}
|
||||
|
||||
void Cx4::enable() {
|
||||
void Cx4::load() {
|
||||
}
|
||||
|
||||
void Cx4::unload() {
|
||||
}
|
||||
|
||||
uint32 Cx4::ldr(uint8 r) {
|
||||
|
@@ -1,7 +1,8 @@
|
||||
class Cx4 : public Memory {
|
||||
class Cx4 {
|
||||
public:
|
||||
void init();
|
||||
void enable();
|
||||
void load();
|
||||
void unload();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
|
@@ -31,13 +31,14 @@ void ICD2::enter() {
|
||||
void ICD2::init() {
|
||||
}
|
||||
|
||||
void ICD2::enable() {
|
||||
mmio[0] = memory::mmio.handle(0x2181);
|
||||
mmio[1] = memory::mmio.handle(0x2182);
|
||||
mmio[2] = memory::mmio.handle(0x420b);
|
||||
memory::mmio.map(0x2181, *this);
|
||||
memory::mmio.map(0x2182, *this);
|
||||
memory::mmio.map(0x420b, *this);
|
||||
void ICD2::load() {
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2181, 0x2182, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x420b, 0x420b, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2181, 0x2182, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x420b, 0x420b, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
|
||||
}
|
||||
|
||||
void ICD2::unload() {
|
||||
}
|
||||
|
||||
void ICD2::power() {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
class ICD2 : public GameBoy::Interface, public Coprocessor, public MMIO, public Memory {
|
||||
class ICD2 : public GameBoy::Interface, public Coprocessor {
|
||||
public:
|
||||
unsigned revision;
|
||||
|
||||
@@ -6,10 +6,14 @@ public:
|
||||
void enter();
|
||||
|
||||
void init();
|
||||
void enable();
|
||||
void load();
|
||||
void unload();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
|
||||
void serialize(serializer&);
|
||||
|
||||
private:
|
||||
|
@@ -1,9 +1,9 @@
|
||||
#ifdef ICD2_CPP
|
||||
|
||||
uint8 ICD2::mmio_read(unsigned addr) {
|
||||
if((uint16)addr == 0x2181) return mmio[0]->mmio_read(addr);
|
||||
if((uint16)addr == 0x2182) return mmio[1]->mmio_read(addr);
|
||||
if((uint16)addr == 0x420b) return mmio[2]->mmio_read(addr);
|
||||
if((uint16)addr == 0x2181) return cpu.mmio_read(addr);
|
||||
if((uint16)addr == 0x2182) return cpu.mmio_read(addr);
|
||||
if((uint16)addr == 0x420b) return cpu.mmio_read(addr);
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ void ICD2::mmio_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
}
|
||||
|
||||
if((uint16)addr == 0x2181) return mmio[0]->mmio_write(addr, r2181 = data);
|
||||
if((uint16)addr == 0x2182) return mmio[1]->mmio_write(addr, r2182 = data);
|
||||
if((uint16)addr == 0x420b) return mmio[2]->mmio_write(addr, data);
|
||||
if((uint16)addr == 0x2181) return cpu.mmio_write(addr, r2181 = data);
|
||||
if((uint16)addr == 0x2182) return cpu.mmio_write(addr, r2182 = data);
|
||||
if((uint16)addr == 0x420b) return cpu.mmio_write(addr, data);
|
||||
}
|
||||
|
||||
uint8 ICD2::read(unsigned addr) {
|
||||
|
@@ -1,6 +1,5 @@
|
||||
uint8 r2181;
|
||||
uint8 r2182;
|
||||
MMIO *mmio[3];
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
@@ -13,7 +12,5 @@ uint8 r6007;
|
||||
uint8 r7000[16];
|
||||
unsigned r7800;
|
||||
uint8 mlt_req;
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 vram[320];
|
||||
|
@@ -48,15 +48,19 @@ void MSU1::enter() {
|
||||
void MSU1::init() {
|
||||
}
|
||||
|
||||
void MSU1::enable() {
|
||||
audio.coprocessor_enable(true);
|
||||
audio.coprocessor_frequency(44100.0);
|
||||
|
||||
void MSU1::load() {
|
||||
if(datafile.open()) datafile.close();
|
||||
datafile.open(string(cartridge.basename(), ".msu"), file::mode::read);
|
||||
}
|
||||
|
||||
void MSU1::unload() {
|
||||
if(datafile.open()) datafile.close();
|
||||
}
|
||||
|
||||
void MSU1::power() {
|
||||
audio.coprocessor_enable(true);
|
||||
audio.coprocessor_frequency(44100.0);
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
@@ -129,7 +133,7 @@ void MSU1::mmio_write(unsigned addr, uint8 data) {
|
||||
if(addr == 0x2005) {
|
||||
mmio.audio_track = (mmio.audio_track & 0x00ff) | (data << 8);
|
||||
if(audiofile.open()) audiofile.close();
|
||||
if(audiofile.open(string(cartridge.basename(), "-", mmio.audio_track, ".pcm"), file::mode::read)) {
|
||||
if(audiofile.open(string(cartridge.basename(), "-", (unsigned)mmio.audio_track, ".pcm"), file::mode::read)) {
|
||||
uint32 header = audiofile.readm(4);
|
||||
if(header != 0x4d535531) { //verify 'MSU1' header
|
||||
audiofile.close();
|
||||
|
@@ -1,9 +1,10 @@
|
||||
class MSU1 : public Coprocessor, public MMIO {
|
||||
class MSU1 : public Coprocessor {
|
||||
public:
|
||||
static void Enter();
|
||||
void enter();
|
||||
void init();
|
||||
void enable();
|
||||
void load();
|
||||
void unload();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
|
@@ -21,7 +21,7 @@ void MSU1::serialize(serializer &s) {
|
||||
}
|
||||
|
||||
if(audiofile.open()) audiofile.close();
|
||||
if(audiofile.open(string(cartridge.basename(), "-", mmio.audio_track, ".pcm"), file::mode::read)) {
|
||||
if(audiofile.open(string(cartridge.basename(), "-", (unsigned)mmio.audio_track, ".pcm"), file::mode::read)) {
|
||||
audiofile.seek(mmio.audio_offset);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user