diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 34cf8ee2..9c185fc0 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "102.11"; + static const string Version = "102.12"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/md/bus/bus.cpp b/higan/md/bus/bus.cpp index 0247edda..7b74cc7e 100644 --- a/higan/md/bus/bus.cpp +++ b/higan/md/bus/bus.cpp @@ -74,7 +74,7 @@ auto BusCPU::readIO(uint24 addr) -> uint16 { case 0xa1000a: return peripherals.controllerPort2->readControl(); case 0xa1000c: return peripherals.extensionPort->readControl(); - case 0xa11000: return !busAPU.granted(); + case 0xa11100: return !busAPU.granted(); } return 0x0000; diff --git a/higan/md/psg/noise.cpp b/higan/md/psg/noise.cpp index 978ecc89..128eec08 100644 --- a/higan/md/psg/noise.cpp +++ b/higan/md/psg/noise.cpp @@ -1,5 +1,5 @@ auto PSG::Noise::run() -> void { - if(--counter) return; + if(counter--) return; if(rate == 0) counter = 0x10; if(rate == 1) counter = 0x20; diff --git a/higan/md/psg/psg.cpp b/higan/md/psg/psg.cpp index 8e5a3da7..9d03ae7a 100644 --- a/higan/md/psg/psg.cpp +++ b/higan/md/psg/psg.cpp @@ -34,6 +34,7 @@ auto PSG::main() -> void { auto PSG::step(uint clocks) -> void { Thread::step(clocks); synchronize(cpu); + synchronize(apu); } auto PSG::power() -> void { diff --git a/higan/md/psg/tone.cpp b/higan/md/psg/tone.cpp index bae975d4..caa1af3b 100644 --- a/higan/md/psg/tone.cpp +++ b/higan/md/psg/tone.cpp @@ -1,5 +1,5 @@ auto PSG::Tone::run() -> void { - if(--counter) return; + if(counter--) return; counter = pitch; output ^= 1; diff --git a/higan/md/vdp/io.cpp b/higan/md/vdp/io.cpp index 6e5daab7..9eadb9d2 100644 --- a/higan/md/vdp/io.cpp +++ b/higan/md/vdp/io.cpp @@ -223,7 +223,7 @@ auto VDP::writeControlPort(uint16 data) -> void { //mode register 4 case 0x0c: { - io.tileWidth = data.bit(0) | data.bit(7) << 1; + io.displayWidth = data.bit(0) | data.bit(7) << 1; io.interlaceMode = data.bits(1,2); io.shadowHighlightEnable = data.bit(3); io.externalColorEnable = data.bit(4); diff --git a/higan/md/vdp/render.cpp b/higan/md/vdp/render.cpp index eaecb283..accb14cc 100644 --- a/higan/md/vdp/render.cpp +++ b/higan/md/vdp/render.cpp @@ -1,6 +1,14 @@ +auto VDP::frame() -> void { + latch.overscan = io.overscan; +} + auto VDP::scanline() -> void { - state.x = 0; if(++state.y >= 262) state.y = 0; + if(state.y == 0) frame(); + state.x = 0; + state.hcounter = 0; + + latch.displayWidth = io.displayWidth; if(state.y < screenHeight()) { planeA.scanline(state.y); @@ -36,9 +44,9 @@ auto VDP::run() -> void { } auto VDP::outputPixel(uint9 color) -> void { - for(auto n : range(4)) { + for(auto n : range(pixelWidth())) { state.output[ 0 + n] = color; state.output[1280 + n] = color; } - state.output += 4; + state.output += pixelWidth(); } diff --git a/higan/md/vdp/vdp.cpp b/higan/md/vdp/vdp.cpp index 52d7e5e1..21d64989 100644 --- a/higan/md/vdp/vdp.cpp +++ b/higan/md/vdp/vdp.cpp @@ -21,9 +21,9 @@ auto VDP::main() -> void { cpu.lower(CPU::Interrupt::VerticalBlank); } cpu.lower(CPU::Interrupt::HorizontalBlank); - for(uint x : range(320)) { + while(state.hcounter < 1280) { run(); - step(4); + step(pixelWidth()); } if(io.horizontalBlankInterruptEnable) { cpu.raise(CPU::Interrupt::HorizontalBlank); @@ -42,6 +42,7 @@ auto VDP::main() -> void { } auto VDP::step(uint clocks) -> void { + state.hcounter += clocks; while(clocks--) { dma.run(); Thread::step(1); @@ -58,6 +59,7 @@ auto VDP::power() -> void { create(VDP::Enter, system.colorburst() * 15.0 / 2.0); memory::fill(&io, sizeof(IO)); + memory::fill(&latch, sizeof(Latch)); memory::fill(&state, sizeof(State)); planeA.power(); diff --git a/higan/md/vdp/vdp.hpp b/higan/md/vdp/vdp.hpp index 9ade08be..6c289089 100644 --- a/higan/md/vdp/vdp.hpp +++ b/higan/md/vdp/vdp.hpp @@ -38,6 +38,7 @@ struct VDP : Thread { } dma; //render.cpp + auto frame() -> void; auto scanline() -> void; auto run() -> void; auto outputPixel(uint9 color) -> void; @@ -128,8 +129,9 @@ struct VDP : Thread { Sprite sprite; private: - auto screenWidth() const -> uint { return io.tileWidth ? 320 : 256; } - auto screenHeight() const -> uint { return io.overscan ? 240 : 224; } + auto pixelWidth() const -> uint { return latch.displayWidth ? 4 : 5; } + auto screenWidth() const -> uint { return latch.displayWidth ? 320 : 256; } + auto screenHeight() const -> uint { return latch.overscan ? 240 : 224; } //video RAM struct VRAM { @@ -193,7 +195,7 @@ private: uint1 externalInterruptEnable; //$0c mode register 4 - uint2 tileWidth; + uint2 displayWidth; uint2 interlaceMode; uint1 shadowHighlightEnable; uint1 externalColorEnable; @@ -208,8 +210,17 @@ private: uint8 dataIncrement; } io; + struct Latch { + //per-frame + uint1 overscan; + + //per-scanline + uint2 displayWidth; + } latch; + struct State { uint32* output = nullptr; + uint hcounter; uint x; uint y; } state; diff --git a/higan/md/ym2612/io.cpp b/higan/md/ym2612/io.cpp index 4423fdaa..08c2477b 100644 --- a/higan/md/ym2612/io.cpp +++ b/higan/md/ym2612/io.cpp @@ -1,9 +1,63 @@ auto YM2612::readStatus() -> uint8 { - return nall::random(); + //d7 = busy + return timerA.line << 0 | timerB.line << 1; } auto YM2612::writeAddress(uint9 data) -> void { + io.address = data; } auto YM2612::writeData(uint8 data) -> void { + switch(io.address) { + + //timer A period (high) + case 0x024: { + timerA.period.bits(2,9) = data.bits(0,7); + break; + } + + //timer A period (low) + case 0x025: { + timerA.period.bits(0,1) = data.bits(0,1); + break; + } + + //timer B period + case 0x026: { + timerB.period.bits(0,7) = data.bits(0,7); + break; + } + + //timer control + case 0x027: { + //d6,d7 = mode (unimplemented; treated as mode 0 always) + + //reload period on 0->1 transition + if(!timerA.enable && data.bit(0)) timerA.counter = timerA.period; + if(!timerB.enable && data.bit(1)) timerB.counter = timerB.period; + + timerA.enable = data.bit(0); + timerB.enable = data.bit(1); + timerA.irq = data.bit(2); + timerB.irq = data.bit(3); + + if(data.bit(4)) timerA.line = 0; + if(data.bit(5)) timerB.line = 0; + + break; + } + + //DAC sample + case 0x2a: { + dac.sample = data; + break; + } + + //DAC enable + case 0x2b: { + dac.enable = data.bit(7); + break; + } + + } } diff --git a/higan/md/ym2612/timer.cpp b/higan/md/ym2612/timer.cpp new file mode 100644 index 00000000..d8441f16 --- /dev/null +++ b/higan/md/ym2612/timer.cpp @@ -0,0 +1,33 @@ +auto YM2612::TimerA::run() -> void { + if(!enable) return; + if(++counter) return; + + counter = period; + line |= irq; +} + +auto YM2612::TimerA::power() -> void { + enable = 0; + irq = 0; + line = 0; + period = 0; + counter = 0; +} + +auto YM2612::TimerB::run() -> void { + if(!enable) return; + if(++divider) return; + if(++counter) return; + + counter = period; + line |= irq; +} + +auto YM2612::TimerB::power() -> void { + enable = 0; + irq = 0; + line = 0; + period = 0; + counter = 0; + divider = 0; +} diff --git a/higan/md/ym2612/ym2612.cpp b/higan/md/ym2612/ym2612.cpp index 87e9705a..27c95b7d 100644 --- a/higan/md/ym2612/ym2612.cpp +++ b/higan/md/ym2612/ym2612.cpp @@ -4,24 +4,41 @@ namespace MegaDrive { YM2612 ym2612; #include "io.cpp" +#include "timer.cpp" auto YM2612::Enter() -> void { while(true) scheduler.synchronize(), ym2612.main(); } auto YM2612::main() -> void { - stream->sample(0.0, 0.0); + timerA.run(); + timerB.run(); + + int output = 0; + if(dac.enable) output += dac.sample; + output <<= 5; + + stream->sample(output / 32768.0, output / 32768.0); step(1); } auto YM2612::step(uint clocks) -> void { Thread::step(clocks); synchronize(cpu); + synchronize(apu); } auto YM2612::power() -> void { create(YM2612::Enter, system.colorburst() * 15.0 / 7.0 / 144.0); stream = Emulator::audio.createStream(2, frequency()); + + memory::fill(&io, sizeof(IO)); + + timerA.power(); + timerB.power(); + + dac.enable = 0; + dac.sample = 0; } } diff --git a/higan/md/ym2612/ym2612.hpp b/higan/md/ym2612/ym2612.hpp index 328d1da5..63dbbae6 100644 --- a/higan/md/ym2612/ym2612.hpp +++ b/higan/md/ym2612/ym2612.hpp @@ -13,6 +13,41 @@ struct YM2612 : Thread { auto readStatus() -> uint8; auto writeAddress(uint9 data) -> void; auto writeData(uint8 data) -> void; + +private: + struct IO { + uint9 address; + } io; + + struct TimerA { + //timer.cpp + auto run() -> void; + auto power() -> void; + + uint1 enable; + uint1 irq; + uint1 line; + uint10 period; + uint10 counter; + } timerA; + + struct TimerB { + //timer.cpp + auto run() -> void; + auto power() -> void; + + uint1 enable; + uint1 irq; + uint1 line; + uint8 period; + uint8 counter; + uint4 divider; + } timerB; + + struct DAC { + uint1 enable; + uint8 sample; + } dac; }; extern YM2612 ym2612; diff --git a/higan/ms/psg/noise.cpp b/higan/ms/psg/noise.cpp index 8b22453e..a8ac734e 100644 --- a/higan/ms/psg/noise.cpp +++ b/higan/ms/psg/noise.cpp @@ -1,5 +1,5 @@ auto PSG::Noise::run() -> void { - if(--counter) return; + if(counter--) return; if(rate == 0) counter = 0x10; if(rate == 1) counter = 0x20; diff --git a/higan/ms/psg/tone.cpp b/higan/ms/psg/tone.cpp index 552f703b..914e3627 100644 --- a/higan/ms/psg/tone.cpp +++ b/higan/ms/psg/tone.cpp @@ -1,5 +1,5 @@ auto PSG::Tone::run() -> void { - if(--counter) return; + if(counter--) return; counter = pitch; output ^= 1; diff --git a/higan/processor/lr35902/disassembler.cpp b/higan/processor/lr35902/disassembler.cpp index 68fefd09..8cc962f8 100644 --- a/higan/processor/lr35902/disassembler.cpp +++ b/higan/processor/lr35902/disassembler.cpp @@ -1,7 +1,3 @@ -static auto hex(uintmax value, long precision = 0, char padchar = '0') -> string { - return nall::hex(value, precision, padchar); -} - auto LR35902::disassemble(uint16 pc) -> string { char output[80]; memset(output, ' ', sizeof output); diff --git a/higan/processor/m68k/instructions.cpp b/higan/processor/m68k/instructions.cpp index 492c4eab..e6c1c5fa 100644 --- a/higan/processor/m68k/instructions.cpp +++ b/higan/processor/m68k/instructions.cpp @@ -1131,7 +1131,7 @@ auto M68K::instructionTAS(EffectiveAddress with) -> void { } auto M68K::instructionTRAP(uint4 vector) -> void { - exception(Exception::Trap, vector); + exception(Exception::Trap, 32 + vector); } auto M68K::instructionTRAPV() -> void { diff --git a/higan/processor/r65816/disassembler.cpp b/higan/processor/r65816/disassembler.cpp index c7c0c8af..991e8a1b 100644 --- a/higan/processor/r65816/disassembler.cpp +++ b/higan/processor/r65816/disassembler.cpp @@ -1,7 +1,3 @@ -static auto hex(uintmax value, long precision = 0, char padchar = '0') -> string { - return nall::hex(value, precision, padchar); -} - auto R65816::dreadb(uint24 addr) -> uint8 { if((addr & 0x40ffff) >= 0x2000 && (addr & 0x40ffff) <= 0x5fff) { //$00-3f|80-bf:2000-5fff diff --git a/nall/arithmetic/natural.hpp b/nall/arithmetic/natural.hpp index fb5fff4a..a49527f4 100644 --- a/nall/arithmetic/natural.hpp +++ b/nall/arithmetic/natural.hpp @@ -343,6 +343,19 @@ inline auto to_vector(Pair value) -> vector { return result; } +/* +inline auto hex(const Pair& value, long precision = 0, char padchar = '0') -> string { + string text; + if(!upper(value)) { + text.append(hex(lower(value))); + } else { + text.append(hex(upper(value))); + text.append(hex(lower(value), TypeBits / 4, '0')); + } + return pad(text, precision, padchar); +} +*/ + } #undef ConcatenateType diff --git a/nall/string.hpp b/nall/string.hpp index 522398e2..00136cf5 100644 --- a/nall/string.hpp +++ b/nall/string.hpp @@ -63,11 +63,11 @@ template struct stringify; template inline auto print(P&&...) -> void; template inline auto print(FILE*, P&&...) -> void; template inline auto pad(const T& value, long precision = 0, char padchar = ' ') -> string; -template inline auto hex(T value, long precision = 0, char padchar = '0') -> string; -template inline auto octal(T value, long precision = 0, char padchar = '0') -> string; -template inline auto binary(T value, long precision = 0, char padchar = '0') -> string; -template inline auto pointer(const T* value, long precision = 0) -> string; +inline auto hex(uintmax value, long precision = 0, char padchar = '0') -> string; +inline auto octal(uintmax value, long precision = 0, char padchar = '0') -> string; +inline auto binary(uintmax value, long precision = 0, char padchar = '0') -> string; inline auto pointer(uintptr value, long precision = 0) -> string; +template inline auto pointer(const T* value, long precision = 0) -> string; //match.hpp inline auto tokenize(const char* s, const char* p) -> bool; diff --git a/nall/string/format.hpp b/nall/string/format.hpp index 536164be..1d10a67e 100644 --- a/nall/string/format.hpp +++ b/nall/string/format.hpp @@ -84,9 +84,9 @@ template auto pad(const T& value, long precision, char padchar) -> s return buffer; } -template auto hex(T value, long precision, char padchar) -> string { +auto hex(uintmax value, long precision, char padchar) -> string { string buffer; - buffer.resize(sizeof(T) * 2); + buffer.resize(sizeof(uintmax) * 2); char* p = buffer.get(); uint size = 0; @@ -101,9 +101,9 @@ template auto hex(T value, long precision, char padchar) -> string { return buffer; } -template auto octal(T value, long precision, char padchar) -> string { +auto octal(uintmax value, long precision, char padchar) -> string { string buffer; - buffer.resize(sizeof(T) * 3); + buffer.resize(sizeof(uintmax) * 3); char* p = buffer.get(); uint size = 0; @@ -117,9 +117,9 @@ template auto octal(T value, long precision, char padchar) -> string return buffer; } -template auto binary(T value, long precision, char padchar) -> string { +auto binary(uintmax value, long precision, char padchar) -> string { string buffer; - buffer.resize(sizeof(T) * 8); + buffer.resize(sizeof(uintmax) * 8); char* p = buffer.get(); uint size = 0; @@ -133,23 +133,14 @@ template auto binary(T value, long precision, char padchar) -> strin return buffer; } -template auto pointer(const T* value, long precision) -> string { - if(value == nullptr) return "(nullptr)"; - return {"0x", hex((uintptr)value, precision)}; -} - auto pointer(uintptr value, long precision) -> string { if(value == 0) return "(nullptr)"; return {"0x", hex(value, precision)}; } -/* -auto real(long double value) -> string { - string temp; - temp.resize(fromReal(nullptr, value)); - fromReal(temp.get(), value); - return temp; +template auto pointer(const T* value, long precision) -> string { + if(value == nullptr) return "(nullptr)"; + return {"0x", hex((uintptr)value, precision)}; } -*/ }