mirror of https://github.com/bsnes-emu/bsnes.git
v107.10
* improved Super Game Boy emulation and fixed SGB save states [LIJI32]
This commit is contained in:
parent
f3022fd907
commit
78a6a2e7d7
|
@ -32,7 +32,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "bsnes";
|
||||
static const string Version = "107.9";
|
||||
static const string Version = "107.10";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "https://byuu.org/";
|
||||
|
|
|
@ -127,13 +127,13 @@ static void display_vblank(GB_gameboy_t *gb)
|
|||
if (GB_is_hle_sgb(gb)) {
|
||||
GB_sgb_render(gb);
|
||||
}
|
||||
|
||||
|
||||
if (gb->turbo) {
|
||||
if (GB_timing_sync_turbo(gb)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!gb->disable_rendering && ((!(gb->io_registers[GB_IO_LCDC] & 0x80) || gb->stopped) || gb->frame_skip_state == GB_FRAMESKIP_LCD_TURNED_ON)) {
|
||||
/* LCD is off, set screen to white or black (if LCD is on in stop mode) */
|
||||
if (gb->sgb) {
|
||||
|
@ -423,7 +423,7 @@ static void render_pixel_if_possible(GB_gameboy_t *gb)
|
|||
gb->screen[gb->position_in_line + gb->current_line * WIDTH] = gb->sprite_palettes_rgb[oam_fifo_item->palette * 4 + pixel];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (gb->model & GB_MODEL_NO_SFC_BIT) {
|
||||
if (gb->icd_pixel_callback) {
|
||||
gb->icd_pixel_callback(gb, icd_pixel);
|
||||
|
@ -769,10 +769,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
|
|||
fifo_push_bg_row(&gb->bg_fifo, 0, 0, 0, false, false);
|
||||
/* Todo: find out actual access time of SCX */
|
||||
gb->position_in_line = - (gb->io_registers[GB_IO_SCX] & 7) - 8;
|
||||
|
||||
// Todo: unverified timing
|
||||
gb->current_lcd_line++;
|
||||
|
||||
gb->current_lcd_line++; // Todo: unverified timing
|
||||
if (gb->current_lcd_line == LINES && GB_is_sgb(gb)) {
|
||||
display_vblank(gb);
|
||||
}
|
||||
|
@ -912,7 +909,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
|
|||
}
|
||||
GB_SLEEP(gb, display, 11, LINE_LENGTH - gb->cycles_for_line);
|
||||
gb->mode_for_interrupt = 2;
|
||||
|
||||
|
||||
if (gb->icd_hreset_callback) {
|
||||
gb->icd_hreset_callback(gb);
|
||||
}
|
||||
|
|
|
@ -10,16 +10,15 @@ ICD icd;
|
|||
|
||||
namespace SameBoy {
|
||||
static auto hreset(GB_gameboy_t*) -> void {
|
||||
icd.ly++;
|
||||
icd.ppuScanline();
|
||||
icd.ppuHreset();
|
||||
}
|
||||
|
||||
static auto vreset(GB_gameboy_t*) -> void {
|
||||
icd.ly = 0;
|
||||
icd.ppuVreset();
|
||||
}
|
||||
|
||||
static auto icd_pixel(GB_gameboy_t*, uint8_t pixel) -> void {
|
||||
icd.ppuOutput(pixel);
|
||||
icd.ppuWrite(pixel);
|
||||
}
|
||||
|
||||
static auto joyp_write(GB_gameboy_t*, uint8_t value) -> void {
|
||||
|
@ -35,7 +34,7 @@ namespace SameBoy {
|
|||
static auto sample(GB_gameboy_t*, GB_sample_t* sample) -> void {
|
||||
float left = sample->left / 32768.0f;
|
||||
float right = sample->right / 32768.0f;
|
||||
icd.apuOutput(left, right);
|
||||
icd.apuWrite(left, right);
|
||||
}
|
||||
|
||||
static auto vblank(GB_gameboy_t*) -> void {
|
||||
|
@ -63,7 +62,8 @@ auto ICD::main() -> void {
|
|||
auto ICD::load() -> bool {
|
||||
information = {};
|
||||
|
||||
GB_random_set_enabled(false);
|
||||
//todo: connect to SFC random enable setting
|
||||
//GB_random_set_enabled(false);
|
||||
if(Frequency == 0) {
|
||||
GB_init(&sameboy, GB_MODEL_SGB_NO_SFC);
|
||||
GB_load_boot_rom_from_buffer(&sameboy, (const unsigned char*)&SGB1BootROM[0], 256);
|
||||
|
@ -96,7 +96,6 @@ auto ICD::load() -> bool {
|
|||
fp->read(data, size);
|
||||
GB_load_rom_from_buffer(&sameboy, data, size);
|
||||
} else return unload(), false;
|
||||
ly = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -104,10 +103,31 @@ auto ICD::unload() -> void {
|
|||
GB_free(&sameboy);
|
||||
}
|
||||
|
||||
auto ICD::power() -> void {
|
||||
auto ICD::power(bool reset) -> void {
|
||||
//SGB1 uses CPU oscillator; SGB2 uses dedicated oscillator
|
||||
create(ICD::Enter, (Frequency ? Frequency : system.cpuFrequency()) / 5.0);
|
||||
stream = Emulator::audio.createStream(2, uint((Frequency ? Frequency : system.cpuFrequency()) / 5.0 / 128.0));
|
||||
if(!reset) {
|
||||
stream = Emulator::audio.createStream(2, uint((Frequency ? Frequency : system.cpuFrequency()) / 5.0 / 128.0));
|
||||
}
|
||||
|
||||
for(auto& packet : this->packet) packet = {};
|
||||
packetSize = 0;
|
||||
|
||||
joypID = 3;
|
||||
joyp14Lock = 0;
|
||||
joyp15Lock = 0;
|
||||
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;
|
||||
|
@ -117,45 +137,8 @@ auto ICD::power() -> void {
|
|||
for(auto& r : r7000) r = 0x00;
|
||||
mltReq = 0;
|
||||
|
||||
for(auto& n : output) n = 0xff;
|
||||
readBank = 0;
|
||||
readAddress = 0;
|
||||
writeBank = 0;
|
||||
writeX = 0;
|
||||
writeY = 0;
|
||||
|
||||
packetSize = 0;
|
||||
joypID = 3;
|
||||
joyp15Lock = 0;
|
||||
joyp14Lock = 0;
|
||||
pulseLock = true;
|
||||
|
||||
GB_reset(&sameboy);
|
||||
}
|
||||
|
||||
auto ICD::reset() -> void {
|
||||
create(ICD::Enter, (Frequency ? Frequency : system.cpuFrequency()) / 5.0);
|
||||
|
||||
r6003 = 0x00;
|
||||
r6004 = 0xff;
|
||||
r6005 = 0xff;
|
||||
r6006 = 0xff;
|
||||
r6007 = 0xff;
|
||||
for(auto& r : r7000) r = 0x00;
|
||||
mltReq = 0;
|
||||
|
||||
for(auto& n : output) n = 0xff;
|
||||
readBank = 0;
|
||||
readAddress = 0;
|
||||
writeBank = 0;
|
||||
writeX = 0;
|
||||
writeY = 0;
|
||||
|
||||
packetSize = 0;
|
||||
joypID = 3;
|
||||
joyp15Lock = 0;
|
||||
joyp14Lock = 0;
|
||||
pulseLock = true;
|
||||
hcounter = 0;
|
||||
vcounter = 0;
|
||||
|
||||
GB_reset(&sameboy);
|
||||
}
|
||||
|
|
|
@ -8,13 +8,13 @@ struct ICD : Emulator::Platform, Thread {
|
|||
|
||||
auto load() -> bool;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void; //software reset
|
||||
auto power(bool reset = false) -> void;
|
||||
|
||||
//interface.cpp
|
||||
auto ppuScanline() -> void;
|
||||
auto ppuOutput(uint2 color) -> void;
|
||||
auto apuOutput(float left, float right) -> void;
|
||||
auto ppuHreset() -> void;
|
||||
auto ppuVreset() -> void;
|
||||
auto ppuWrite(uint2 color) -> void;
|
||||
auto apuWrite(float left, float right) -> void;
|
||||
auto joypWrite(bool p14, bool p15) -> void;
|
||||
|
||||
//io.cpp
|
||||
|
@ -33,21 +33,27 @@ struct ICD : Emulator::Platform, Thread {
|
|||
|
||||
private:
|
||||
struct Packet {
|
||||
auto operator[](uint addr) -> uint8& { return data[addr & 15]; }
|
||||
auto operator[](uint4 address) -> uint8& { return data[address]; }
|
||||
uint8 data[16];
|
||||
};
|
||||
Packet packet[64];
|
||||
uint packetSize;
|
||||
uint7 packetSize;
|
||||
|
||||
uint joypID;
|
||||
bool joyp15Lock;
|
||||
bool joyp14Lock;
|
||||
bool pulseLock;
|
||||
bool strobeLock;
|
||||
bool packetLock;
|
||||
uint2 joypID;
|
||||
uint1 joyp14Lock;
|
||||
uint1 joyp15Lock;
|
||||
uint1 pulseLock;
|
||||
uint1 strobeLock;
|
||||
uint1 packetLock;
|
||||
Packet joypPacket;
|
||||
uint8 packetOffset;
|
||||
uint8 bitData, bitOffset;
|
||||
uint4 packetOffset;
|
||||
uint8 bitData;
|
||||
uint3 bitOffset;
|
||||
|
||||
uint8 output[4 * 512];
|
||||
uint2 readBank;
|
||||
uint9 readAddress;
|
||||
uint2 writeBank;
|
||||
|
||||
uint8 r6003; //control port
|
||||
uint8 r6004; //joypad 1
|
||||
|
@ -57,12 +63,8 @@ private:
|
|||
uint8 r7000[16]; //JOYP packet data
|
||||
uint8 mltReq; //number of active joypads
|
||||
|
||||
uint8 output[4 * 512];
|
||||
uint readBank;
|
||||
uint readAddress;
|
||||
uint writeBank;
|
||||
uint writeX;
|
||||
uint writeY;
|
||||
uint8 hcounter;
|
||||
uint8 vcounter;
|
||||
|
||||
struct Information {
|
||||
uint pathID = 0;
|
||||
|
@ -74,7 +76,6 @@ public:
|
|||
//as the offsets of all member variables will be wrong compared to what the C SameBoy code expects.
|
||||
GB_gameboy_t sameboy;
|
||||
uint32_t bitmap[160 * 144];
|
||||
uint8_t ly = 0;
|
||||
};
|
||||
|
||||
extern ICD icd;
|
||||
|
|
|
@ -1,33 +1,35 @@
|
|||
|
||||
auto ICD::ppuScanline() -> void {
|
||||
if(++writeY == 8) {
|
||||
writeBank = (writeBank + 1) & 3;
|
||||
writeY = 0;
|
||||
}
|
||||
writeX = 0;
|
||||
auto ICD::ppuHreset() -> void {
|
||||
hcounter = 0;
|
||||
vcounter++;
|
||||
if((uint3)vcounter == 0) writeBank++;
|
||||
}
|
||||
|
||||
auto ICD::ppuOutput(uint2 color) -> void {
|
||||
if(writeX >= 160) return; // Unverified behavior
|
||||
if(writeY >= 8) return; // Should never happen
|
||||
|
||||
uint addr = (writeBank & 3) * 512 + writeY * 2 + writeX / 8 * 16;
|
||||
output[addr + 0] = (output[addr + 0] << 1) | !!(color & 1);
|
||||
output[addr + 1] = (output[addr + 1] << 1) | !!(color & 2);
|
||||
writeX++;
|
||||
auto ICD::ppuVreset() -> void {
|
||||
hcounter = 0;
|
||||
vcounter = 0;
|
||||
}
|
||||
|
||||
auto ICD::apuOutput(float left, float right) -> void {
|
||||
auto ICD::ppuWrite(uint2 color) -> void {
|
||||
auto x = (uint8)hcounter++;
|
||||
auto y = (uint3)vcounter;
|
||||
if(x >= 160) return; //unverified behavior
|
||||
|
||||
uint11 address = writeBank * 512 + y * 2 + x / 8 * 16;
|
||||
output[address + 0] = (output[address + 0] << 1) | !!(color & 1);
|
||||
output[address + 1] = (output[address + 1] << 1) | !!(color & 2);
|
||||
}
|
||||
|
||||
auto ICD::apuWrite(float left, float right) -> void {
|
||||
float samples[] = {left, right};
|
||||
stream->write(samples);
|
||||
}
|
||||
|
||||
auto ICD::joypWrite(bool p14, bool p15) -> void {
|
||||
//joypad handling
|
||||
if(p15 == 1 && p14 == 1) {
|
||||
if(joyp15Lock == 0 && joyp14Lock == 0) {
|
||||
joyp15Lock = 1;
|
||||
if(p14 == 1 && p15 == 1) {
|
||||
if(joyp14Lock == 0 && joyp15Lock == 0) {
|
||||
joyp14Lock = 1;
|
||||
joyp15Lock = 1;
|
||||
joypID++;
|
||||
if(mltReq == 0) joypID &= 0; //1-player mode
|
||||
if(mltReq == 1) joypID &= 1; //2-player mode
|
||||
|
@ -43,17 +45,17 @@ auto ICD::joypWrite(bool p14, bool p15) -> void {
|
|||
if(joypID == 3) joypad = r6007;
|
||||
|
||||
uint4 input = 0xf;
|
||||
if(p15 == 1 && p14 == 1) input = 0xf - joypID;
|
||||
if(p14 == 1 && p15 == 1) input = 0xf - joypID;
|
||||
if(p14 == 0) input &= bits(joypad,0-3); //d-pad
|
||||
if(p15 == 0) input &= bits(joypad,4-7); //buttons
|
||||
|
||||
GB_icd_set_joyp(&sameboy, input);
|
||||
|
||||
if(p15 == 0 && p14 == 1) joyp15Lock = 0;
|
||||
if(p15 == 1 && p14 == 0) joyp14Lock = 0;
|
||||
if(p14 == 0 && p15 == 1) joyp14Lock = 0;
|
||||
if(p14 == 1 && p15 == 0) joyp15Lock = 0;
|
||||
|
||||
//packet handling
|
||||
if(p15 == 0 && p14 == 0) { //pulse
|
||||
if(p14 == 0 && p15 == 0) { //pulse
|
||||
pulseLock = false;
|
||||
packetOffset = 0;
|
||||
bitOffset = 0;
|
||||
|
@ -64,13 +66,13 @@ auto ICD::joypWrite(bool p14, bool p15) -> void {
|
|||
|
||||
if(pulseLock) return;
|
||||
|
||||
if(p15 == 1 && p14 == 1) {
|
||||
if(p14 == 1 && p15 == 1) {
|
||||
strobeLock = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(strobeLock) {
|
||||
if(p15 == 1 || p14 == 1) { //malformed packet
|
||||
if(p14 == 1 || p15 == 1) { //malformed packet
|
||||
packetLock = false;
|
||||
pulseLock = true;
|
||||
bitOffset = 0;
|
||||
|
@ -80,13 +82,13 @@ auto ICD::joypWrite(bool p14, bool p15) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
//p15:1, p14:0 = 0
|
||||
//p15:0, p14:1 = 1
|
||||
bool bit = (p15 == 0);
|
||||
//p14:0, p15:1 = 0
|
||||
//p14:1, p15:0 = 1
|
||||
bool bit = p15 == 0;
|
||||
strobeLock = true;
|
||||
|
||||
if(packetLock) {
|
||||
if(p15 == 1 && p14 == 0) {
|
||||
if(p14 == 0 && p15 == 1) {
|
||||
if((joypPacket[0] >> 3) == 0x11) {
|
||||
mltReq = joypPacket[1] & 3;
|
||||
joypID = 3; //required: the next time P14==1 && P15==1; increment and start from ID=0 (Joypad 1)
|
||||
|
@ -99,11 +101,11 @@ auto ICD::joypWrite(bool p14, bool p15) -> void {
|
|||
return;
|
||||
}
|
||||
|
||||
bitData = (bit << 7) | (bitData >> 1);
|
||||
if(++bitOffset < 8) return;
|
||||
bitData = bit << 7 | bitData >> 1;
|
||||
if(++bitOffset) return;
|
||||
|
||||
bitOffset = 0;
|
||||
joypPacket[packetOffset] = bitData;
|
||||
if(++packetOffset < 16) return;
|
||||
if(++packetOffset) return;
|
||||
|
||||
packetLock = true;
|
||||
}
|
||||
|
|
|
@ -3,8 +3,7 @@ auto ICD::readIO(uint addr, uint8 data) -> uint8 {
|
|||
|
||||
//LY counter
|
||||
if(addr == 0x6000) {
|
||||
uint y = ly;
|
||||
return (y & ~7) | writeBank;
|
||||
return vcounter & ~7 | writeBank;
|
||||
}
|
||||
|
||||
//command ready port
|
||||
|
@ -54,7 +53,7 @@ auto ICD::writeIO(uint addr, uint8 data) -> void {
|
|||
//d1,d0: 0 = frequency divider (clock rate adjust)
|
||||
if(addr == 0x6003) {
|
||||
if((r6003 & 0x80) == 0x00 && (data & 0x80) == 0x80) {
|
||||
reset();
|
||||
power(true); //soft reset
|
||||
}
|
||||
auto frequency = system.cpuFrequency();
|
||||
switch(data & 3) {
|
||||
|
|
|
@ -3,25 +3,21 @@ auto ICD::serialize(serializer& s) -> void {
|
|||
|
||||
auto size = GB_get_save_state_size(&sameboy);
|
||||
auto data = new uint8_t[size];
|
||||
|
||||
if(s.mode() == serializer::Save) {
|
||||
GB_save_state_to_buffer(&sameboy, data);
|
||||
}
|
||||
|
||||
s.array(data, size);
|
||||
|
||||
if(s.mode() == serializer::Load) {
|
||||
GB_load_state_from_buffer(&sameboy, data, size);
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
|
||||
for(auto n : range(64)) s.array(packet[n].data);
|
||||
s.integer(packetSize);
|
||||
|
||||
s.integer(joypID);
|
||||
s.integer(joyp15Lock);
|
||||
s.integer(joyp14Lock);
|
||||
s.integer(joyp15Lock);
|
||||
s.integer(pulseLock);
|
||||
s.integer(strobeLock);
|
||||
s.integer(packetLock);
|
||||
|
@ -30,6 +26,11 @@ auto ICD::serialize(serializer& s) -> void {
|
|||
s.integer(bitData);
|
||||
s.integer(bitOffset);
|
||||
|
||||
s.array(output);
|
||||
s.integer(readBank);
|
||||
s.integer(readAddress);
|
||||
s.integer(writeBank);
|
||||
|
||||
s.integer(r6003);
|
||||
s.integer(r6004);
|
||||
s.integer(r6005);
|
||||
|
@ -38,10 +39,6 @@ auto ICD::serialize(serializer& s) -> void {
|
|||
s.array(r7000);
|
||||
s.integer(mltReq);
|
||||
|
||||
s.array(output);
|
||||
s.integer(readBank);
|
||||
s.integer(readAddress);
|
||||
s.integer(writeBank);
|
||||
s.integer(writeX);
|
||||
s.integer(writeY);
|
||||
s.integer(hcounter);
|
||||
s.integer(vcounter);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue