From 72b6a8b32e73c27346f96327e15e15e9e00357f5 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Mon, 11 Jan 2016 21:31:30 +1100 Subject: [PATCH] Update to v096r04 release. byuu says: Changelog: - fixed S-DD1 RAM writes (Star Ocean audio fixed) - applied all of the DMG test ROM fixes discussed earlier; passes many more test ROMs now - at least until the GBVideoPlayer is working: for debugging purposes, CPU/PPU single-step now instead of sync just-in-time (~30% slower) - fixed OS X crash on NSTextView (hopefully, would be very odd if not) Unfortunately passing these test ROMs caused my favorite GB/GBC game to break all of its graphics =( Shin Megami Tensei - Devichil - Kuro no Sho (Japan) is all garbled now. I'm really quite bummed by this ... but I guess I'll go through and revert r04's fixes one at a time until I find what's causing it. On the plus side, Astro Rabby is playable now. Still acts weird when pressing B/A on the first screen, but the start button will start the game. EDIT: got it. Shin Megami Tensei - Devichil requires FF4F (VBK) to be readable. Before, it was always returning 0x00. With my return 0xFF patch, that broke. But it should be returning the VBK value, which also fixes it. Also need to handle FF68/FF6A reads. Was really hoping that'd help GBVideoPlayer too, but nope. It doesn't read any of those three registers. --- higan/emulator/emulator.hpp | 7 +-- higan/emulator/interface.hpp | 5 +- higan/fc/fc.hpp | 6 +- higan/fc/interface/interface.hpp | 4 -- higan/gb/apu/apu.cpp | 47 ++++++--------- higan/gb/apu/apu.hpp | 1 - higan/gb/apu/master/master.cpp | 42 ++++++++++++-- higan/gb/apu/master/master.hpp | 3 +- higan/gb/apu/noise/noise.cpp | 48 ++++++++++++---- higan/gb/apu/noise/noise.hpp | 6 +- higan/gb/apu/serialization.cpp | 1 - higan/gb/apu/square1/square1.cpp | 38 +++++++++--- higan/gb/apu/square1/square1.hpp | 3 +- higan/gb/apu/square2/square2.cpp | 36 ++++++++++-- higan/gb/apu/square2/square2.hpp | 3 +- higan/gb/apu/wave/wave.cpp | 73 ++++++++++++++++-------- higan/gb/apu/wave/wave.hpp | 10 ++-- higan/gb/cpu/cpu.cpp | 8 +-- higan/gb/cpu/cpu.hpp | 6 +- higan/gb/cpu/memory.cpp | 6 +- higan/gb/cpu/mmio.cpp | 6 +- higan/gb/cpu/serialization.cpp | 2 +- higan/gb/cpu/timing.cpp | 61 +++++++++++--------- higan/gb/gb.hpp | 7 +-- higan/gb/interface/interface.hpp | 4 -- higan/gb/ppu/ppu.cpp | 10 ++-- higan/gba/gba.hpp | 6 +- higan/gba/interface/interface.hpp | 4 -- higan/processor/lr35902/instructions.cpp | 14 ++--- higan/sfc/coprocessor/sdd1/sdd1.cpp | 20 ++----- higan/sfc/interface/interface.hpp | 4 -- higan/sfc/sfc.hpp | 6 +- hiro/cocoa/widget/text-edit.cpp | 6 +- 33 files changed, 297 insertions(+), 206 deletions(-) diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index ceede127..5e949d23 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -1,5 +1,4 @@ -#ifndef EMULATOR_HPP -#define EMULATOR_HPP +#pragma once #include #include @@ -7,7 +6,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "096.03"; + static const string Version = "096.04"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; @@ -55,5 +54,3 @@ template struct hook R> { #endif using varuint = varuint_t; - -#endif diff --git a/higan/emulator/interface.hpp b/higan/emulator/interface.hpp index d752aa6e..0999cbf4 100644 --- a/higan/emulator/interface.hpp +++ b/higan/emulator/interface.hpp @@ -1,5 +1,4 @@ -#ifndef EMULATOR_INTERFACE_HPP -#define EMULATOR_INTERFACE_HPP +#pragma once namespace Emulator { @@ -113,5 +112,3 @@ struct Interface { }; } - -#endif diff --git a/higan/fc/fc.hpp b/higan/fc/fc.hpp index 2003b7a7..1e237d3d 100644 --- a/higan/fc/fc.hpp +++ b/higan/fc/fc.hpp @@ -1,5 +1,4 @@ -#ifndef FC_HPP -#define FC_HPP +#pragma once #include #include @@ -53,7 +52,6 @@ namespace Famicom { #include #include #include - #include } -#endif +#include diff --git a/higan/fc/interface/interface.hpp b/higan/fc/interface/interface.hpp index 3e7076c1..f79fe94f 100644 --- a/higan/fc/interface/interface.hpp +++ b/higan/fc/interface/interface.hpp @@ -1,6 +1,4 @@ -#ifndef FC_HPP namespace Famicom { -#endif struct ID { enum : uint { @@ -58,6 +56,4 @@ private: extern Interface* interface; -#ifndef FC_HPP } -#endif diff --git a/higan/gb/apu/apu.cpp b/higan/gb/apu/apu.cpp index 451cd655..21353885 100644 --- a/higan/gb/apu/apu.cpp +++ b/higan/gb/apu/apu.cpp @@ -65,7 +65,6 @@ auto APU::power() -> void { create(Main, 2 * 1024 * 1024); for(uint n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this; - for(auto& n : mmio_data) n = 0x00; sequencer_base = 0; sequencer_step = 0; @@ -74,42 +73,30 @@ auto APU::power() -> void { wave.power(); noise.power(); master.power(); + + LinearFeedbackShiftRegisterGenerator r; + for(auto& n : wave.pattern) n = r(); } auto APU::mmio_read(uint16 addr) -> uint8 { - static const uint8 table[48] = { - 0x80, 0x3f, 0x00, 0xff, 0xbf, //square1 - 0xff, 0x3f, 0x00, 0xff, 0xbf, //square2 - 0x7f, 0xff, 0x9f, 0xff, 0xbf, //wave - 0xff, 0xff, 0x00, 0x00, 0xbf, //noise - 0x00, 0x00, 0x70, //master - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //unmapped - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern - }; - - if(addr == 0xff26) { - uint8 data = master.enable << 7; - if(square1.enable) data |= 0x01; - if(square2.enable) data |= 0x02; - if( wave.enable) data |= 0x04; - if( noise.enable) data |= 0x08; - return data | table[addr - 0xff10]; - } - - if(addr >= 0xff10 && addr <= 0xff3f) return mmio_data[addr - 0xff10] | table[addr - 0xff10]; +//if(!master.enable && addr != 0xff26) return 0xff; + if(addr >= 0xff10 && addr <= 0xff14) return square1.read(addr); + if(addr >= 0xff15 && addr <= 0xff19) return square2.read(addr); + if(addr >= 0xff1a && addr <= 0xff1e) return wave.read(addr); + if(addr >= 0xff1f && addr <= 0xff23) return noise.read(addr); + if(addr >= 0xff24 && addr <= 0xff26) return master.read(addr); + if(addr >= 0xff30 && addr <= 0xff3f) return wave.read(addr); return 0xff; } auto APU::mmio_write(uint16 addr, uint8 data) -> void { - if(addr >= 0xff10 && addr <= 0xff3f) mmio_data[addr - 0xff10] = data; - - if(addr >= 0xff10 && addr <= 0xff14) return square1.write (addr - 0xff10, data); - if(addr >= 0xff15 && addr <= 0xff19) return square2.write (addr - 0xff15, data); - if(addr >= 0xff1a && addr <= 0xff1e) return wave.write (addr - 0xff1a, data); - if(addr >= 0xff1f && addr <= 0xff23) return noise.write (addr - 0xff1f, data); - if(addr >= 0xff24 && addr <= 0xff26) return master.write (addr - 0xff24, data); - if(addr >= 0xff30 && addr <= 0xff3f) return wave.write_pattern(addr - 0xff30, data); + if(!master.enable && addr != 0xff26) return; + if(addr >= 0xff10 && addr <= 0xff14) return square1.write(addr, data); + if(addr >= 0xff15 && addr <= 0xff19) return square2.write(addr, data); + if(addr >= 0xff1a && addr <= 0xff1e) return wave.write(addr, data); + if(addr >= 0xff1f && addr <= 0xff23) return noise.write(addr, data); + if(addr >= 0xff24 && addr <= 0xff26) return master.write(addr, data); + if(addr >= 0xff30 && addr <= 0xff3f) return wave.write(addr, data); } } diff --git a/higan/gb/apu/apu.hpp b/higan/gb/apu/apu.hpp index 043aff75..51d92e03 100644 --- a/higan/gb/apu/apu.hpp +++ b/higan/gb/apu/apu.hpp @@ -15,7 +15,6 @@ struct APU : Thread, MMIO { #include "noise/noise.hpp" #include "master/master.hpp" - uint8 mmio_data[48]; uint12 sequencer_base; uint3 sequencer_step; diff --git a/higan/gb/apu/master/master.cpp b/higan/gb/apu/master/master.cpp index 201a8ebc..e47d4132 100644 --- a/higan/gb/apu/master/master.cpp +++ b/higan/gb/apu/master/master.cpp @@ -39,15 +39,42 @@ auto APU::Master::run() -> void { right >>= 1; } -auto APU::Master::write(uint r, uint8 data) -> void { - if(r == 0) { //$ff24 NR50 +auto APU::Master::read(uint16 addr) -> uint8 { + if(addr == 0xff24) { //NR50 + return left_in_enable << 7 | left_volume << 4 | right_in_enable << 3 | right_volume; + } + + if(addr == 0xff25) { //NR51 + return channel4_left_enable << 7 + | channel3_left_enable << 6 + | channel2_left_enable << 5 + | channel1_left_enable << 4 + | channel4_right_enable << 3 + | channel3_right_enable << 2 + | channel2_right_enable << 1 + | channel1_right_enable << 0; + } + + if(addr == 0xff26) { //NR52 + return enable << 7 | 0x70 + | apu.noise.enable << 3 + | apu.wave.enable << 2 + | apu.square2.enable << 1 + | apu.square1.enable << 0; + } + + return 0xff; +} + +auto APU::Master::write(uint16 addr, uint8 data) -> void { + if(addr == 0xff24) { //NR50 left_in_enable = data & 0x80; left_volume = (data >> 4) & 7; right_in_enable = data & 0x08; right_volume = (data >> 0) & 7; } - if(r == 1) { //$ff25 NR51 + if(addr == 0xff25) { //NR51 channel4_left_enable = data & 0x80; channel3_left_enable = data & 0x40; channel2_left_enable = data & 0x20; @@ -58,8 +85,15 @@ auto APU::Master::write(uint r, uint8 data) -> void { channel1_right_enable = data & 0x01; } - if(r == 2) { //$ff26 NR52 + if(addr == 0xff26) { //NR52 enable = data & 0x80; + if(!enable) { + apu.square1.power(); + apu.square2.power(); + apu.wave.power(); + apu.noise.power(); + power(); + } } } diff --git a/higan/gb/apu/master/master.hpp b/higan/gb/apu/master/master.hpp index c3c0e493..0cdfe8db 100644 --- a/higan/gb/apu/master/master.hpp +++ b/higan/gb/apu/master/master.hpp @@ -1,6 +1,7 @@ struct Master { auto run() -> void; - auto write(uint r, uint8 data) -> void; + auto read(uint16 addr) -> uint8; + auto write(uint16 addr, uint8 data) -> void; auto power() -> void; auto serialize(serializer&) -> void; diff --git a/higan/gb/apu/noise/noise.cpp b/higan/gb/apu/noise/noise.cpp index fc17f0d2..1796c92b 100644 --- a/higan/gb/apu/noise/noise.cpp +++ b/higan/gb/apu/noise/noise.cpp @@ -2,9 +2,14 @@ auto APU::Noise::dac_enable() const -> bool { return (envelope_volume || envelope_direction); } +auto APU::Noise::get_period() const -> uint { + static const uint table[] = {4, 8, 16, 24, 32, 40, 48, 56}; + return table[divisor] << frequency; +} + auto APU::Noise::run() -> void { if(period && --period == 0) { - period = divisor << frequency; + period = get_period(); if(frequency < 14) { bool bit = (lfsr ^ (lfsr >> 1)) & 1; lfsr = (lfsr >> 1) ^ (bit << (narrow_lfsr ? 6 : 14)); @@ -18,7 +23,7 @@ auto APU::Noise::run() -> void { } auto APU::Noise::clock_length() -> void { - if(enable && counter) { + if(counter) { if(++length == 0) enable = false; } } @@ -31,27 +36,50 @@ auto APU::Noise::clock_envelope() -> void { } } -auto APU::Noise::write(uint r, uint8 data) -> void { - if(r == 1) { //$ff20 NR41 +auto APU::Noise::read(uint16 addr) -> uint8 { + if(addr == 0xff1f) { //NR40 + return 0xff; + } + + if(addr == 0xff20) { //NR41 + return 0xff; + } + + if(addr == 0xff21) { //NR42 + return envelope_volume << 4 | envelope_direction << 3 | envelope_frequency; + } + + if(addr == 0xff22) { //NR43 + return frequency << 4 | narrow_lfsr << 3 | divisor; + } + + if(addr == 0xff23) { //NR44 + return 0x80 | counter << 6 | 0x3f; + } + + return 0xff; +} + +auto APU::Noise::write(uint16 addr, uint8 data) -> void { + if(addr == 0xff20) { //NR41 length = data & 0x3f; } - if(r == 2) { //$ff21 NR42 + if(addr == 0xff21) { //NR42 envelope_volume = data >> 4; envelope_direction = data & 0x08; envelope_frequency = data & 0x07; if(dac_enable() == false) enable = false; } - if(r == 3) { //$ff22 NR43 + if(addr == 0xff22) { //NR43 frequency = data >> 4; narrow_lfsr = data & 0x08; - divisor = (data & 0x07) << 3; - if(divisor == 0) divisor = 4; - period = divisor << frequency; + divisor = data & 0x07; + period = get_period(); } - if(r == 4) { //$ff34 NR44 + if(addr == 0xff23) { //NR44 bool initialize = data & 0x80; counter = data & 0x40; diff --git a/higan/gb/apu/noise/noise.hpp b/higan/gb/apu/noise/noise.hpp index 3f3f8797..095cedf7 100644 --- a/higan/gb/apu/noise/noise.hpp +++ b/higan/gb/apu/noise/noise.hpp @@ -1,10 +1,12 @@ struct Noise { auto dac_enable() const -> bool; + auto get_period() const -> uint; auto run() -> void; auto clock_length() -> void; auto clock_envelope() -> void; - auto write(uint r, uint8 data) -> void; + auto read(uint16 addr) -> uint8; + auto write(uint16 addr, uint8 data) -> void; auto power() -> void; auto serialize(serializer&) -> void; @@ -16,7 +18,7 @@ struct Noise { uint3 envelope_frequency; uint4 frequency; bool narrow_lfsr; - uint divisor; + uint3 divisor; bool counter; int16 output; diff --git a/higan/gb/apu/serialization.cpp b/higan/gb/apu/serialization.cpp index 037273dc..58becd79 100644 --- a/higan/gb/apu/serialization.cpp +++ b/higan/gb/apu/serialization.cpp @@ -1,7 +1,6 @@ auto APU::serialize(serializer& s) -> void { Thread::serialize(s); - s.array(mmio_data); s.integer(sequencer_base); s.integer(sequencer_step); diff --git a/higan/gb/apu/square1/square1.cpp b/higan/gb/apu/square1/square1.cpp index f6d07ad5..70f7709f 100644 --- a/higan/gb/apu/square1/square1.cpp +++ b/higan/gb/apu/square1/square1.cpp @@ -37,7 +37,7 @@ auto APU::Square1::sweep(bool update) -> void { } auto APU::Square1::clock_length() -> void { - if(counter && enable) { + if(counter) { if(++length == 0) enable = false; } } @@ -58,31 +58,55 @@ auto APU::Square1::clock_envelope() -> void { } } -auto APU::Square1::write(uint r, uint8 data) -> void { - if(r == 0) { //$ff10 NR10 +auto APU::Square1::read(uint16 addr) -> uint8 { + if(addr == 0xff10) { //NR10 + return 0x80 | sweep_frequency << 4 | sweep_direction << 3 | sweep_shift; + } + + if(addr == 0xff11) { //NR11 + return duty << 6 | 0x3f; + } + + if(addr == 0xff12) { //NR12 + return envelope_volume << 4 | envelope_direction << 3 | envelope_frequency; + } + + if(addr == 0xff13) { //NR13 + return 0xff; + } + + if(addr == 0xff14) { //NR14 + return 0x80 | counter << 6 | 0x3f; + } + + return 0xff; +} + +auto APU::Square1::write(uint16 addr, uint8 data) -> void { + if(addr == 0xff10) { //NR10 if(sweep_negate && sweep_direction && !(data & 0x08)) enable = false; sweep_frequency = (data >> 4) & 7; sweep_direction = data & 0x08; sweep_shift = data & 0x07; } - if(r == 1) { //$ff11 NR11 + if(addr == 0xff11) { //NR11 duty = data >> 6; length = data & 0x3f; } - if(r == 2) { //$ff12 NR12 + if(addr == 0xff12) { //NR12 envelope_volume = data >> 4; envelope_direction = data & 0x08; envelope_frequency = data & 0x07; if(dac_enable() == false) enable = false; } - if(r == 3) { //$ff13 NR13 + if(addr == 0xff13) { //NR13 frequency = (frequency & 0x0700) | data; } - if(r == 4) { //$ff14 NR14 + if(addr == 0xff14) { //NR14 bool initialize = data & 0x80; counter = data & 0x40; frequency = ((data & 7) << 8) | (frequency & 0x00ff); diff --git a/higan/gb/apu/square1/square1.hpp b/higan/gb/apu/square1/square1.hpp index eb975653..4bd8b344 100644 --- a/higan/gb/apu/square1/square1.hpp +++ b/higan/gb/apu/square1/square1.hpp @@ -6,7 +6,8 @@ struct Square1 { auto clock_length() -> void; auto clock_sweep() -> void; auto clock_envelope() -> void; - auto write(uint r, uint8 data) -> void; + auto read(uint16 addr) -> uint8; + auto write(uint16 addr, uint8 data) -> void; auto power() -> void; auto serialize(serializer&) -> void; diff --git a/higan/gb/apu/square2/square2.cpp b/higan/gb/apu/square2/square2.cpp index 02be430a..af3ecccc 100644 --- a/higan/gb/apu/square2/square2.cpp +++ b/higan/gb/apu/square2/square2.cpp @@ -21,7 +21,7 @@ auto APU::Square2::run() -> void { } auto APU::Square2::clock_length() -> void { - if(counter && enable) { + if(counter) { if(++length == 0) enable = false; } } @@ -34,24 +34,48 @@ auto APU::Square2::clock_envelope() -> void { } } -auto APU::Square2::write(uint r, uint8 data) -> void { - if(r == 1) { //$ff16 NR21 +auto APU::Square2::read(uint16 addr) -> uint8 { + if(addr == 0xff15) { //NR20 + return 0xff; + } + + if(addr == 0xff16) { //NR21 + return duty << 6 | 0x3f; + } + + if(addr == 0xff17) { //NR22 + return envelope_volume << 4 | envelope_direction << 3 | envelope_frequency; + } + + if(addr == 0xff18) { //NR23 + return 0xff; + } + + if(addr == 0xff19) { //NR24 + return 0x80 | counter << 6 | 0x3f; + } + + return 0xff; +} + +auto APU::Square2::write(uint16 addr, uint8 data) -> void { + if(addr == 0xff16) { //NR21 duty = data >> 6; length = (data & 0x3f); } - if(r == 2) { //$ff17 NR22 + if(addr == 0xff17) { //NR22 envelope_volume = data >> 4; envelope_direction = data & 0x08; envelope_frequency = data & 0x07; if(dac_enable() == false) enable = false; } - if(r == 3) { //$ff18 NR23 + if(addr == 0xff18) { //NR23 frequency = (frequency & 0x0700) | data; } - if(r == 4) { //$ff19 NR24 + if(addr == 0xff19) { //NR24 bool initialize = data & 0x80; counter = data & 0x40; frequency = ((data & 7) << 8) | (frequency & 0x00ff); diff --git a/higan/gb/apu/square2/square2.hpp b/higan/gb/apu/square2/square2.hpp index 9655f641..db9025c6 100644 --- a/higan/gb/apu/square2/square2.hpp +++ b/higan/gb/apu/square2/square2.hpp @@ -4,7 +4,8 @@ struct Square2 { auto run() -> void; auto clock_length() -> void; auto clock_envelope() -> void; - auto write(uint r, uint8 data) -> void; + auto read(uint16 addr) -> uint8; + auto write(uint16 addr, uint8 data) -> void; auto power() -> void; auto serialize(serializer&) -> void; diff --git a/higan/gb/apu/wave/wave.cpp b/higan/gb/apu/wave/wave.cpp index c2fc4326..cd04178f 100644 --- a/higan/gb/apu/wave/wave.cpp +++ b/higan/gb/apu/wave/wave.cpp @@ -1,45 +1,73 @@ +auto APU::Wave::get_pattern(uint5 offset) const -> uint4 { + return pattern[offset >> 1] >> (offset & 1 ? 0 : 4); +} + auto APU::Wave::run() -> void { if(period && --period == 0) { period = 1 * (2048 - frequency); - pattern_sample = pattern[++pattern_offset]; + pattern_sample = get_pattern(++pattern_offset); } - uint4 sample = pattern_sample >> volume_shift; + static const uint shift[] = {4, 0, 1, 2}; //0%, 100%, 50%, 25% + uint4 sample = pattern_sample >> shift[volume]; if(enable == false) sample = 0; output = sample; } auto APU::Wave::clock_length() -> void { - if(enable && counter) { + if(counter) { if(++length == 0) enable = false; } } -auto APU::Wave::write(uint r, uint8 data) -> void { - if(r == 0) { //$ff1a NR30 +auto APU::Wave::read(uint16 addr) -> uint8 { + if(addr == 0xff1a) { //NR30 + return dac_enable << 7 | 0x7f; + } + + if(addr == 0xff1b) { //NR31 + return 0xff; + } + + if(addr == 0xff1c) { //NR32 + return 0x80 | volume << 5 | 0x1f; + } + + if(addr == 0xff1d) { //NR33 + return 0xff; + } + + if(addr == 0xff1e) { //NR34 + return 0x80 | counter << 6 | 0x3f; + } + + if(addr >= 0xff30 && addr <= 0xff3f) { + return pattern[addr & 15]; + } + + return 0xff; +} + +auto APU::Wave::write(uint16 addr, uint8 data) -> void { + if(addr == 0xff1a) { //NR30 dac_enable = data & 0x80; if(dac_enable == false) enable = false; } - if(r == 1) { //$ff1b NR31 + if(addr == 0xff1b) { //NR31 length = data; } - if(r == 2) { //$ff1c NR32 - switch((data >> 5) & 3) { - case 0: volume_shift = 4; break; // 0% - case 1: volume_shift = 0; break; //100% - case 2: volume_shift = 1; break; // 50% - case 3: volume_shift = 2; break; // 25% - } + if(addr == 0xff1c) { //NR32 + volume = data >> 5; } - if(r == 3) { //$ff1d NR33 + if(addr == 0xff1d) { //NR33 frequency = (frequency & 0x0700) | data; } - if(r == 4) { //$ff1e NR34 + if(addr == 0xff1e) { //NR34 bool initialize = data & 0x80; counter = data & 0x40; frequency = ((data & 7) << 8) | (frequency & 0x00ff); @@ -50,25 +78,20 @@ auto APU::Wave::write(uint r, uint8 data) -> void { pattern_offset = 0; } } -} -auto APU::Wave::write_pattern(uint p, uint8 data) -> void { - p <<= 1; - pattern[p + 0] = (data >> 4) & 15; - pattern[p + 1] = (data >> 0) & 15; + if(addr >= 0xff30 && addr <= 0xff3f) { + pattern[addr & 15] = data; + } } auto APU::Wave::power() -> void { enable = 0; dac_enable = 0; - volume_shift = 0; + volume = 0; frequency = 0; counter = 0; - LinearFeedbackShiftRegisterGenerator r; - for(auto& n : pattern) n = r() & 15; - output = 0; length = 0; period = 0; @@ -80,7 +103,7 @@ auto APU::Wave::serialize(serializer& s) -> void { s.integer(enable); s.integer(dac_enable); - s.integer(volume_shift); + s.integer(volume); s.integer(frequency); s.integer(counter); s.array(pattern); diff --git a/higan/gb/apu/wave/wave.hpp b/higan/gb/apu/wave/wave.hpp index 7d215721..9a39ef7d 100644 --- a/higan/gb/apu/wave/wave.hpp +++ b/higan/gb/apu/wave/wave.hpp @@ -1,8 +1,10 @@ struct Wave { + auto get_pattern(uint5 offset) const -> uint4; + auto run() -> void; auto clock_length() -> void; - auto write(uint r, uint8 data) -> void; - auto write_pattern(uint p, uint8 data) -> void; + auto read(uint16 addr) -> uint8; + auto write(uint16 addr, uint8 data) -> void; auto power() -> void; auto serialize(serializer&) -> void; @@ -10,10 +12,10 @@ struct Wave { bool enable; bool dac_enable; - uint volume_shift; + uint2 volume; uint11 frequency; bool counter; - uint8 pattern[32]; + uint8 pattern[16]; int16 output; uint8 length; diff --git a/higan/gb/cpu/cpu.cpp b/higan/gb/cpu/cpu.cpp index 99e9b4da..3c2289d4 100644 --- a/higan/gb/cpu/cpu.cpp +++ b/higan/gb/cpu/cpu.cpp @@ -81,13 +81,13 @@ auto CPU::interrupt_test() -> void { } auto CPU::interrupt_exec(uint16 pc) -> void { + op_io(); + op_io(); + op_io(); r.ime = 0; op_write(--r[SP], r[PC] >> 8); op_write(--r[SP], r[PC] >> 0); r[PC] = pc; - op_io(); - op_io(); - op_io(); } auto CPU::stop() -> bool { @@ -201,8 +201,8 @@ auto CPU::power() -> void { status.interrupt_enable_vblank = 0; oamdma.active = false; + oamdma.clock = 0; oamdma.bank = 0; - oamdma.offset = 0; } } diff --git a/higan/gb/cpu/cpu.hpp b/higan/gb/cpu/cpu.hpp index 1fe4a373..02fdd800 100644 --- a/higan/gb/cpu/cpu.hpp +++ b/higan/gb/cpu/cpu.hpp @@ -36,7 +36,7 @@ struct CPU : Processor::LR35902, Thread, MMIO { auto hblank() -> void; struct Status { - uint clock; + uint22 clock; //$ff00 JOYP bool p15; @@ -53,7 +53,7 @@ struct CPU : Processor::LR35902, Thread, MMIO { bool serial_clock; //$ff04 DIV - uint8 div; + uint16 div; //$ff05 TIMA uint8 tima; @@ -109,8 +109,8 @@ struct CPU : Processor::LR35902, Thread, MMIO { struct OAMDMA { bool active; + uint clock; uint8 bank; - uint8 offset; } oamdma; uint8 wram[32768]; //GB=8192, GBC=32768 diff --git a/higan/gb/cpu/memory.cpp b/higan/gb/cpu/memory.cpp index ac219397..6b743415 100644 --- a/higan/gb/cpu/memory.cpp +++ b/higan/gb/cpu/memory.cpp @@ -6,14 +6,16 @@ auto CPU::op_io() -> void { auto CPU::op_read(uint16 addr) -> uint8 { cycle_edge(); add_clocks(4); - if(oamdma.active && (addr < 0xff80 || addr == 0xffff)) return 0xff; + //OAM is inaccessible during OAMDMA transfer + if(oamdma.active && oamdma.clock >= 8 && addr >= 0xfe00 && addr <= 0xfe9f) return 0xff; return bus.read(addr); } auto CPU::op_write(uint16 addr, uint8 data) -> void { cycle_edge(); add_clocks(4); - if(oamdma.active && (addr < 0xff80 || addr == 0xffff)) return; + //OAM is inaccessible during OAMDMA transfer + if(oamdma.active && oamdma.clock >= 8 && addr >= 0xfe00 && addr <= 0xfe9f) return; bus.write(addr, data); } diff --git a/higan/gb/cpu/mmio.cpp b/higan/gb/cpu/mmio.cpp index c9e5b29d..104e169e 100644 --- a/higan/gb/cpu/mmio.cpp +++ b/higan/gb/cpu/mmio.cpp @@ -53,7 +53,7 @@ auto CPU::mmio_read(uint16 addr) -> uint8 { } if(addr == 0xff04) { //DIV - return status.div; + return status.div >> 8; } if(addr == 0xff05) { //TIMA @@ -188,8 +188,8 @@ auto CPU::mmio_write(uint16 addr, uint8 data) -> void { if(addr == 0xff46) { //DMA oamdma.active = true; + oamdma.clock = 0; oamdma.bank = data; - oamdma.offset = 0; return; } @@ -225,7 +225,7 @@ auto CPU::mmio_write(uint16 addr, uint8 data) -> void { if(status.dma_mode == 0) { do { - for(unsigned n = 0; n < 16; n++) { + for(auto n : range(16)) { dma_write(status.dma_target++, dma_read(status.dma_source++)); } add_clocks(8 << status.speed_double); diff --git a/higan/gb/cpu/serialization.cpp b/higan/gb/cpu/serialization.cpp index a1a0df75..bc13028d 100644 --- a/higan/gb/cpu/serialization.cpp +++ b/higan/gb/cpu/serialization.cpp @@ -55,6 +55,6 @@ auto CPU::serialize(serializer& s) -> void { s.integer(status.interrupt_enable_vblank); s.integer(oamdma.active); + s.integer(oamdma.clock); s.integer(oamdma.bank); - s.integer(oamdma.offset); } diff --git a/higan/gb/cpu/timing.cpp b/higan/gb/cpu/timing.cpp index eaeb1654..6af540d4 100644 --- a/higan/gb/cpu/timing.cpp +++ b/higan/gb/cpu/timing.cpp @@ -3,37 +3,44 @@ // 154 scanlines/frame auto CPU::add_clocks(uint clocks) -> void { - if(oamdma.active) { - for(uint n = 0; n < 4 * clocks; n++) { - bus.write(0xfe00 + oamdma.offset, bus.read((oamdma.bank << 8) + oamdma.offset)); - if(++oamdma.offset == 160) { - oamdma.active = false; - break; + if(system.sgb()) system.clocks_executed += clocks; + + while(clocks--) { + if(oamdma.active) { + uint offset = oamdma.clock++; + if((offset & 3) == 0) { + offset >>= 2; + if(offset == 0) { + //warm-up + } else if(offset == 161) { + //cool-down; disable + oamdma.active = false; + } else { + bus.write(0xfe00 + offset - 1, bus.read((oamdma.bank << 8) + offset - 1)); + } } } + + if(++status.clock == 0) { + cartridge.mbc3.second(); + } + + //4MHz / N(hz) - 1 = mask + status.div++; + if((status.div & 15) == 0) timer_262144hz(); + if((status.div & 63) == 0) timer_65536hz(); + if((status.div & 255) == 0) timer_16384hz(); + if((status.div & 511) == 0) timer_8192hz(); + if((status.div & 1023) == 0) timer_4096hz(); + + ppu.clock -= ppu.frequency; + if(ppu.clock < 0) co_switch(scheduler.active_thread = ppu.thread); + + apu.clock -= apu.frequency; + if(apu.clock < 0) co_switch(scheduler.active_thread = apu.thread); } - system.clocks_executed += clocks; if(system.sgb()) scheduler.exit(Scheduler::ExitReason::StepEvent); - - status.clock += clocks; - if(status.clock >= 4 * 1024 * 1024) { - status.clock -= 4 * 1024 * 1024; - cartridge.mbc3.second(); - } - - //4MHz / N(hz) - 1 = mask - if((status.clock & 15) == 0) timer_262144hz(); - if((status.clock & 63) == 0) timer_65536hz(); - if((status.clock & 255) == 0) timer_16384hz(); - if((status.clock & 511) == 0) timer_8192hz(); - if((status.clock & 1023) == 0) timer_4096hz(); - - ppu.clock -= clocks * ppu.frequency; - if(ppu.clock < 0) co_switch(scheduler.active_thread = ppu.thread); - - apu.clock -= clocks * apu.frequency; - if(apu.clock < 0) co_switch(scheduler.active_thread = apu.thread); } auto CPU::timer_262144hz() -> void { @@ -61,8 +68,6 @@ auto CPU::timer_16384hz() -> void { interrupt_raise(Interrupt::Timer); } } - - status.div++; } auto CPU::timer_8192hz() -> void { diff --git a/higan/gb/gb.hpp b/higan/gb/gb.hpp index 1a7cb16e..3d7c53c3 100644 --- a/higan/gb/gb.hpp +++ b/higan/gb/gb.hpp @@ -1,5 +1,4 @@ -#ifndef GB_HPP -#define GB_HPP +#pragma once #include #include @@ -52,6 +51,6 @@ namespace GameBoy { #include #include #include -}; +} -#endif +#include diff --git a/higan/gb/interface/interface.hpp b/higan/gb/interface/interface.hpp index b7f5fcb2..6436b656 100644 --- a/higan/gb/interface/interface.hpp +++ b/higan/gb/interface/interface.hpp @@ -1,6 +1,4 @@ -#ifndef GB_HPP namespace GameBoy { -#endif struct ID { enum : uint { @@ -72,6 +70,4 @@ private: extern Interface* interface; -#ifndef GB_HPP } -#endif diff --git a/higan/gb/ppu/ppu.cpp b/higan/gb/ppu/ppu.cpp index 5caa160b..d0bbf130 100644 --- a/higan/gb/ppu/ppu.cpp +++ b/higan/gb/ppu/ppu.cpp @@ -45,10 +45,12 @@ auto PPU::main() -> void { } auto PPU::add_clocks(uint clocks) -> void { - status.lx += clocks; - clock += clocks * cpu.frequency; - if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) { - co_switch(scheduler.active_thread = cpu.thread); + while(clocks--) { + status.lx++; + clock += cpu.frequency; + if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) { + co_switch(scheduler.active_thread = cpu.thread); + } } } diff --git a/higan/gba/gba.hpp b/higan/gba/gba.hpp index 1ab24d1a..dbc80a80 100644 --- a/higan/gba/gba.hpp +++ b/higan/gba/gba.hpp @@ -1,5 +1,4 @@ -#ifndef GBA_HPP -#define GBA_HPP +#pragma once #include #include @@ -56,7 +55,6 @@ namespace GameBoyAdvance { }; #include - #include #include #include #include @@ -67,4 +65,4 @@ namespace GameBoyAdvance { #include } -#endif +#include diff --git a/higan/gba/interface/interface.hpp b/higan/gba/interface/interface.hpp index ccaf3233..675f72d6 100644 --- a/higan/gba/interface/interface.hpp +++ b/higan/gba/interface/interface.hpp @@ -1,6 +1,4 @@ -#ifndef GBA_HPP namespace GameBoyAdvance { -#endif struct ID { enum : uint { @@ -55,6 +53,4 @@ private: extern Interface* interface; -#ifndef GBA_HPP } -#endif diff --git a/higan/processor/lr35902/instructions.cpp b/higan/processor/lr35902/instructions.cpp index 5760aae3..2c575b92 100644 --- a/higan/processor/lr35902/instructions.cpp +++ b/higan/processor/lr35902/instructions.cpp @@ -103,9 +103,9 @@ auto LR35902::op_ld_sp_hl() { } template auto LR35902::op_push_rr() { + op_io(); op_write(--r[SP], r[x] >> 8); op_write(--r[SP], r[x] >> 0); - op_io(); } template auto LR35902::op_pop_rr() { @@ -297,24 +297,24 @@ template auto LR35902::op_dec_rr() { } auto LR35902::op_add_sp_n() { - op_io(); - op_io(); int n = (int8)op_read(r[PC]++); r.f.z = 0; r.f.n = 0; r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f; r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff; r[SP] += n; + op_io(); + op_io(); } auto LR35902::op_ld_hl_sp_n() { - op_io(); int n = (int8)op_read(r[PC]++); r.f.z = 0; r.f.n = 0; r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f; r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff; r[HL] = r[SP] + n; + op_io(); } //rotate/shift commands @@ -618,20 +618,20 @@ template auto LR35902::op_jr_f_n() { auto LR35902::op_call_nn() { uint8 lo = op_read(r[PC]++); uint8 hi = op_read(r[PC]++); + op_io(); op_write(--r[SP], r[PC] >> 8); op_write(--r[SP], r[PC] >> 0); r[PC] = (hi << 8) | (lo << 0); - op_io(); } template auto LR35902::op_call_f_nn() { uint8 lo = op_read(r[PC]++); uint8 hi = op_read(r[PC]++); if(r.f[x] == y) { + op_io(); op_write(--r[SP], r[PC] >> 8); op_write(--r[SP], r[PC] >> 0); r[PC] = (hi << 8) | (lo << 0); - op_io(); } } @@ -661,8 +661,8 @@ auto LR35902::op_reti() { } template auto LR35902::op_rst_n() { + op_io(); op_write(--r[SP], r[PC] >> 8); op_write(--r[SP], r[PC] >> 0); r[PC] = n; - op_io(); } diff --git a/higan/sfc/coprocessor/sdd1/sdd1.cpp b/higan/sfc/coprocessor/sdd1/sdd1.cpp index 62b05b3b..3a3e3aa7 100644 --- a/higan/sfc/coprocessor/sdd1/sdd1.cpp +++ b/higan/sfc/coprocessor/sdd1/sdd1.cpp @@ -146,26 +146,14 @@ auto SDD1::mcurom_read(uint addr, uint8) -> uint8 { auto SDD1::mcurom_write(uint addr, uint8 data) -> void { } +//map address=00-3f,80-bf:6000-7fff mask=0xe000 +//map address=70-7d:0000-7fff mask=0x8000 auto SDD1::mcuram_read(uint addr, uint8 data) -> uint8 { - if((addr & 0x60e000) == 0x006000) { //$00-3f,80-bf:6000-7fff - return ram.read(addr & 0x1fff, data); - } - - if((addr & 0xf08000) == 0x700000) { //$70-7f:0000-7fff - return ram.read(addr & 0x1fff, data); - } - - return data; + return ram.read(addr & 0x1fff, data); } auto SDD1::mcuram_write(uint addr, uint8 data) -> void { - if((addr & 0x60e000) == 0x006000) { //$00-3f,80-bf:6000-7fff - return ram.write(addr & 0x1fff, data); - } - - if((addr & 0xf08000) == 0x700000) { //$70-7f:0000-7fff - return ram.write(addr & 0x1fff, data); - } + return ram.write(addr & 0x1fff, data); } } diff --git a/higan/sfc/interface/interface.hpp b/higan/sfc/interface/interface.hpp index 8a67722a..cd4ffbcb 100644 --- a/higan/sfc/interface/interface.hpp +++ b/higan/sfc/interface/interface.hpp @@ -1,6 +1,4 @@ -#ifndef SFC_HPP namespace SuperFamicom { -#endif struct ID { enum : uint { @@ -126,6 +124,4 @@ struct Interface : Emulator::Interface { extern Interface* interface; -#ifndef SFC_HPP } -#endif diff --git a/higan/sfc/sfc.hpp b/higan/sfc/sfc.hpp index 767bce3e..1f7396b4 100644 --- a/higan/sfc/sfc.hpp +++ b/higan/sfc/sfc.hpp @@ -1,5 +1,4 @@ -#ifndef SFC_HPP -#define SFC_HPP +#pragma once #include #include @@ -71,10 +70,9 @@ namespace SuperFamicom { #include #include #include - #include #include #include } -#endif +#include diff --git a/hiro/cocoa/widget/text-edit.cpp b/hiro/cocoa/widget/text-edit.cpp index c22756f4..8be57b00 100644 --- a/hiro/cocoa/widget/text-edit.cpp +++ b/hiro/cocoa/widget/text-edit.cpp @@ -78,15 +78,13 @@ auto pTextEdit::setCursor(Cursor cursor) -> void { auto pTextEdit::setEditable(bool editable) -> void { @autoreleasepool { - [[cocoaView content] setEditable:editable]; + [[cocoaView content] setEditable:(editable && self().enabled(true))]; } } auto pTextEdit::setEnabled(bool enabled) -> void { pWidget::setEnabled(enabled); - @autoreleasepool { - [[cocoaView content] setEnabled:enabled]; - } + setEditable(self().editable); //Cocoa lacks NSTextView::setEnabled; simulate via setEnabled() } auto pTextEdit::setFont(const Font& font) -> void {