mirror of
https://github.com/DerKoun/bsnes-hd.git
synced 2025-04-02 10:52:49 -04:00
181 lines
4.8 KiB
C++
181 lines
4.8 KiB
C++
#include <sfc/sfc.hpp>
|
|
|
|
namespace SuperFamicom {
|
|
|
|
ICD icd;
|
|
#include "interface.cpp"
|
|
#include "io.cpp"
|
|
#include "boot-roms.cpp"
|
|
#include "serialization.cpp"
|
|
|
|
namespace SameBoy {
|
|
static auto hreset(GB_gameboy_t*) -> void {
|
|
icd.ppuHreset();
|
|
}
|
|
|
|
static auto vreset(GB_gameboy_t*) -> void {
|
|
icd.ppuVreset();
|
|
}
|
|
|
|
static auto icd_pixel(GB_gameboy_t*, uint8_t pixel) -> void {
|
|
icd.ppuWrite(pixel);
|
|
}
|
|
|
|
static auto joyp_write(GB_gameboy_t*, uint8_t value) -> void {
|
|
bool p14 = value & 0x10;
|
|
bool p15 = value & 0x20;
|
|
icd.joypWrite(p14, p15);
|
|
}
|
|
|
|
static auto read_memory(GB_gameboy_t*, uint16_t addr, uint8_t data) -> uint8_t {
|
|
if(auto replace = icd.cheats.find(addr, data)) return replace();
|
|
return data;
|
|
}
|
|
|
|
static auto rgb_encode(GB_gameboy_t*, uint8_t r, uint8_t g, uint8_t b) -> uint32_t {
|
|
return r << 16 | g << 8 | b << 0;
|
|
}
|
|
|
|
static auto sample(GB_gameboy_t*, GB_sample_t* sample) -> void {
|
|
float left = sample->left / 32768.0f;
|
|
float right = sample->right / 32768.0f;
|
|
icd.apuWrite(left, right);
|
|
}
|
|
|
|
static auto vblank(GB_gameboy_t*) -> void {
|
|
}
|
|
}
|
|
|
|
auto ICD::synchronizeCPU() -> void {
|
|
if(clock >= 0) scheduler.resume(cpu.thread);
|
|
}
|
|
|
|
auto ICD::Enter() -> void {
|
|
while(true) {
|
|
scheduler.synchronize();
|
|
icd.main();
|
|
}
|
|
}
|
|
|
|
auto ICD::main() -> void {
|
|
if(r6003 & 0x80) {
|
|
auto clocks = GB_run(&sameboy);
|
|
step(clocks >> 1);
|
|
} else { //DMG halted
|
|
apuWrite(0.0, 0.0);
|
|
step(128);
|
|
}
|
|
synchronizeCPU();
|
|
}
|
|
|
|
auto ICD::step(uint clocks) -> void {
|
|
clock += clocks * (uint64_t)cpu.frequency;
|
|
}
|
|
|
|
//SGB1 uses the CPU oscillator (~2.4% faster than a real Game Boy)
|
|
//SGB2 uses a dedicated oscillator (same speed as a real Game Boy)
|
|
auto ICD::clockFrequency() const -> uint {
|
|
return Frequency ? Frequency : system.cpuFrequency();
|
|
}
|
|
|
|
auto ICD::load() -> bool {
|
|
information = {};
|
|
|
|
GB_random_set_enabled(configuration.hacks.entropy != "None");
|
|
if(Frequency == 0) {
|
|
GB_init(&sameboy, GB_MODEL_SGB_NO_SFC);
|
|
GB_load_boot_rom_from_buffer(&sameboy, (const unsigned char*)&SGB1BootROM[0], 256);
|
|
} else {
|
|
GB_init(&sameboy, GB_MODEL_SGB2_NO_SFC);
|
|
GB_load_boot_rom_from_buffer(&sameboy, (const unsigned char*)&SGB2BootROM[0], 256);
|
|
}
|
|
GB_set_sample_rate_by_clocks(&sameboy, 256);
|
|
GB_set_highpass_filter_mode(&sameboy, GB_HIGHPASS_ACCURATE);
|
|
GB_set_icd_hreset_callback(&sameboy, &SameBoy::hreset);
|
|
GB_set_icd_vreset_callback(&sameboy, &SameBoy::vreset);
|
|
GB_set_icd_pixel_callback(&sameboy, &SameBoy::icd_pixel);
|
|
GB_set_joyp_write_callback(&sameboy, &SameBoy::joyp_write);
|
|
GB_set_read_memory_callback(&sameboy, &SameBoy::read_memory);
|
|
GB_set_rgb_encode_callback(&sameboy, &SameBoy::rgb_encode);
|
|
GB_apu_set_sample_callback(&sameboy, &SameBoy::sample);
|
|
GB_set_vblank_callback(&sameboy, &SameBoy::vblank);
|
|
GB_set_pixels_output(&sameboy, &bitmap[0]);
|
|
if(auto loaded = platform->load(ID::GameBoy, "Game Boy", "gb")) {
|
|
information.pathID = loaded.pathID;
|
|
} else return unload(), false;
|
|
if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
|
auto manifest = fp->reads();
|
|
cartridge.slotGameBoy.load(manifest);
|
|
} else return unload(), false;
|
|
if(auto fp = platform->open(pathID(), "program.rom", File::Read, File::Required)) {
|
|
auto size = fp->size();
|
|
auto data = (uint8_t*)malloc(size);
|
|
cartridge.information.sha256 = Hash::SHA256({data, (uint64_t)size}).digest();
|
|
fp->read(data, size);
|
|
GB_load_rom_from_buffer(&sameboy, data, size);
|
|
free(data);
|
|
} else return unload(), false;
|
|
if(auto fp = platform->open(pathID(), "save.ram", File::Read)) {
|
|
auto size = fp->size();
|
|
auto data = (uint8_t*)malloc(size);
|
|
fp->read(data, size);
|
|
GB_load_battery_from_buffer(&sameboy, data, size);
|
|
free(data);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
auto ICD::save() -> void {
|
|
if(auto size = GB_save_battery_size(&sameboy)) {
|
|
auto data = (uint8_t*)malloc(size);
|
|
GB_save_battery_to_buffer(&sameboy, data, size);
|
|
if(auto fp = platform->open(pathID(), "save.ram", File::Write)) {
|
|
fp->write(data, size);
|
|
}
|
|
free(data);
|
|
}
|
|
}
|
|
|
|
auto ICD::unload() -> void {
|
|
save();
|
|
GB_free(&sameboy);
|
|
}
|
|
|
|
auto ICD::power(bool reset) -> void {
|
|
auto frequency = clockFrequency() / 5;
|
|
create(ICD::Enter, frequency);
|
|
if(!reset) stream = Emulator::audio.createStream(2, frequency / 128);
|
|
|
|
for(auto& packet : this->packet) packet = {};
|
|
packetSize = 0;
|
|
|
|
joypID = 0;
|
|
joypLock = 1;
|
|
pulseLock = 1;
|
|
strobeLock = 0;
|
|
packetLock = 0;
|
|
joypPacket = {};
|
|
packetOffset = 0;
|
|
bitData = 0;
|
|
bitOffset = 0;
|
|
|
|
for(auto& n : output) n = 0xff;
|
|
readBank = 0;
|
|
readAddress = 0;
|
|
writeBank = 0;
|
|
|
|
r6003 = 0x00;
|
|
r6004 = 0xff;
|
|
r6005 = 0xff;
|
|
r6006 = 0xff;
|
|
r6007 = 0xff;
|
|
for(auto& r : r7000) r = 0x00;
|
|
mltReq = 0;
|
|
|
|
hcounter = 0;
|
|
vcounter = 0;
|
|
|
|
GB_reset(&sameboy);
|
|
}
|
|
|
|
}
|