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 {