From 8071da4c6a083ed8ad1626a9bf865bff3c28f2d7 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Tue, 21 Feb 2017 22:07:33 +1100 Subject: [PATCH] Update to v102r09 release. byuu says: Changelog: - MD: restructured DMA to a subclass of VDP - MD: implemented VRAM copy mode (fixes Langrisser II ... mostly) - MS: implemened PSG support [Cydrak] - GG: implemented PSG stereo sound support - MS: use the new struct Model {} design that other cores use The MS/GG PSG should be feature complete, but I don't have good tests for Game Gear stereo mode, nor for the noise channel. There's also a really weird behavior with when to reload the channel counters on volume register writes. I can confirm what Cydrak observed in that following the docs and reloading always creates serious audio distortion problems. So, more research is needed there. To get the correct sound out of the PSG, I have to run it at 3.58MHz / 16, which seems really weird to me. The docs make it sound like it's supposed to run at the full 3.58MHz. If we can really run it at 223.7KHz, then that's help reduce the overhead of PSG emulation, which will definitely come in handy for Mega Drive, and possibly later Mega CD, emulation. I have not implemented the PSG into the Mega Drive just yet. Nor have I implemented save states or cheat code support into the MS/GG cores yet. The latter is next on my list. --- higan/emulator/emulator.hpp | 2 +- higan/md/vdp/dma.cpp | 51 ++++++++++------- higan/md/vdp/io.cpp | 24 ++++---- higan/md/vdp/vdp.cpp | 3 +- higan/md/vdp/vdp.hpp | 34 ++++++------ higan/ms/bus/bus.cpp | 16 +++++- higan/ms/cartridge/cartridge.cpp | 9 ++- higan/ms/cpu/cpu.cpp | 2 +- higan/ms/interface/game-gear.cpp | 2 +- higan/ms/interface/master-system.cpp | 2 +- higan/ms/ms.hpp | 10 ++-- higan/ms/psg/io.cpp | 82 ++++++++++++++++++++++++++++ higan/ms/psg/noise.cpp | 30 ++++++++++ higan/ms/psg/psg.cpp | 49 ++++++++++++++++- higan/ms/psg/psg.hpp | 42 ++++++++++++++ higan/ms/psg/tone.cpp | 19 +++++++ higan/ms/system/peripherals.cpp | 2 +- higan/ms/system/system.hpp | 5 ++ higan/ms/vdp/io.cpp | 4 +- higan/ms/vdp/vdp.cpp | 8 +-- 20 files changed, 319 insertions(+), 77 deletions(-) create mode 100644 higan/ms/psg/io.cpp create mode 100644 higan/ms/psg/noise.cpp create mode 100644 higan/ms/psg/tone.cpp diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 681fe677..d6d9f093 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.08"; + static const string Version = "102.09"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/md/vdp/dma.cpp b/higan/md/vdp/dma.cpp index 67f544be..082ebde1 100644 --- a/higan/md/vdp/dma.cpp +++ b/higan/md/vdp/dma.cpp @@ -1,36 +1,45 @@ -auto VDP::dmaRun() -> void { - if(!io.dmaEnable) return; - if(!io.command.bit(5)) return; +auto VDP::DMA::run() -> void { + if(!io.enable || io.wait) return; + if(!vdp.io.command.bit(5)) return; - if(io.dmaMode <= 1) return dmaLoad(); - if(io.dmaMode == 2) return dmaFill(); - if(io.dmaMode == 3) return dmaCopy(); + if(io.mode <= 1) return load(); + if(io.mode == 2) return fill(); + if(io.mode == 3) return copy(); } -auto VDP::dmaLoad() -> void { +auto VDP::DMA::load() -> void { cpu.wait |= Wait::VDP_DMA; - auto data = busCPU.readWord(io.dmaMode.bit(0) << 23 | io.dmaSource << 1); - writeDataPort(data); + auto data = busCPU.readWord(io.mode.bit(0) << 23 | io.source << 1); + vdp.writeDataPort(data); - io.dmaSource.bits(0,15)++; - if(--io.dmaLength == 0) { - io.command.bit(5) = 0; + io.source.bits(0,15)++; + if(--io.length == 0) { + vdp.io.command.bit(5) = 0; cpu.wait &=~ Wait::VDP_DMA; } } -auto VDP::dmaFill() -> void { - if(io.dmaFillWait) return; +auto VDP::DMA::fill() -> void { + auto data = io.fill; + vdp.writeDataPort(data << 8 | data << 0); - auto data = io.dmaFillByte; - writeDataPort(data << 8 | data << 0); - - io.dmaSource.bits(0,15)++; - if(--io.dmaLength == 0) { - io.command.bit(5) = 0; + io.source.bits(0,15)++; + if(--io.length == 0) { + vdp.io.command.bit(5) = 0; } } -auto VDP::dmaCopy() -> void { +auto VDP::DMA::copy() -> void { + auto data = vdp.vram[io.source.bits(0,14)]; + vdp.writeDataPort(data); + + io.source.bits(0,15)++; + if(--io.length == 0) { + vdp.io.command.bit(5) = 0; + } +} + +auto VDP::DMA::power() -> void { + memory::fill(&io, sizeof(IO)); } diff --git a/higan/md/vdp/io.cpp b/higan/md/vdp/io.cpp index 66932ddc..28192d1f 100644 --- a/higan/md/vdp/io.cpp +++ b/higan/md/vdp/io.cpp @@ -74,8 +74,9 @@ auto VDP::writeDataPort(uint16 data) -> void { io.commandPending = false; //DMA VRAM fill - if(io.dmaFillWait.lower()) { - io.dmaFillByte = data >> 8; + if(dma.io.wait.lower()) { + dma.io.fill = data >> 8; + return; } //VRAM write @@ -132,7 +133,7 @@ auto VDP::writeControlPort(uint16 data) -> void { io.command.bits(2,5) = data.bits(4,7); io.address.bits(14,15) = data.bits(0,1); - io.dmaFillWait = io.dmaMode == 2 && io.command.bits(4,5) == 2; + if(dma.io.mode == 3) dma.io.wait = false; return; } @@ -162,12 +163,12 @@ auto VDP::writeControlPort(uint16 data) -> void { case 0x01: { io.videoMode = data.bit(2); io.overscan = data.bit(3); - io.dmaEnable = data.bit(4); + dma.io.enable = data.bit(4); io.verticalBlankInterruptEnable = data.bit(5); io.displayEnable = data.bit(6); io.externalVRAM = data.bit(7); - if(!io.dmaEnable) io.command.bit(5) = 0; + if(!dma.io.enable) io.command.bit(5) = 0; return; } @@ -280,32 +281,33 @@ auto VDP::writeControlPort(uint16 data) -> void { //DMA length case 0x13: { - io.dmaLength.bits(0,7) = data.bits(0,7); + dma.io.length.bits(0,7) = data.bits(0,7); return; } //DMA length case 0x14: { - io.dmaLength.bits(8,15) = data.bits(0,7); + dma.io.length.bits(8,15) = data.bits(0,7); return; } //DMA source case 0x15: { - io.dmaSource.bits(0,7) = data.bits(0,7); + dma.io.source.bits(0,7) = data.bits(0,7); return; } //DMA source case 0x16: { - io.dmaSource.bits(8,15) = data.bits(0,7); + dma.io.source.bits(8,15) = data.bits(0,7); return; } //DMA source case 0x17: { - io.dmaSource.bits(16,21) = data.bits(0,5); - io.dmaMode = data.bits(6,7); + dma.io.source.bits(16,21) = data.bits(0,5); + dma.io.mode = data.bits(6,7); + dma.io.wait = dma.io.mode.bit(1); return; } diff --git a/higan/md/vdp/vdp.cpp b/higan/md/vdp/vdp.cpp index e465d99c..38f6ec67 100644 --- a/higan/md/vdp/vdp.cpp +++ b/higan/md/vdp/vdp.cpp @@ -42,7 +42,7 @@ auto VDP::main() -> void { auto VDP::step(uint clocks) -> void { while(clocks--) { - dmaRun(); + dma.run(); Thread::step(1); synchronize(cpu); synchronize(apu); @@ -63,6 +63,7 @@ auto VDP::power() -> void { window.power(); planeB.power(); sprite.power(); + dma.power(); } } diff --git a/higan/md/vdp/vdp.hpp b/higan/md/vdp/vdp.hpp index c1169cb6..2c1eb505 100644 --- a/higan/md/vdp/vdp.hpp +++ b/higan/md/vdp/vdp.hpp @@ -19,10 +19,23 @@ struct VDP : Thread { auto writeControlPort(uint16 data) -> void; //dma.cpp - auto dmaRun() -> void; - auto dmaLoad() -> void; - auto dmaFill() -> void; - auto dmaCopy() -> void; + struct DMA { + auto run() -> void; + auto load() -> void; + auto fill() -> void; + auto copy() -> void; + + auto power() -> void; + + struct IO { + uint2 mode; + uint22 source; + uint16 length; + uint8 fill; + boolean enable; + boolean wait; + } io; + } dma; //render.cpp auto scanline() -> void; @@ -119,15 +132,10 @@ private: auto screenHeight() const -> uint { return io.overscan ? 240 : 224; } uint16 vram[32768]; - uint16 vramExpansion[32768]; //not present in stock Mega Drive hardware uint9 cram[64]; uint10 vsram[40]; struct IO { - //internal state - boolean dmaFillWait; - uint8 dmaFillByte; - //command uint6 command; uint16 address; @@ -142,7 +150,6 @@ private: //$01 mode register 2 uint1 videoMode; //0 = Master System; 1 = Mega Drive uint1 overscan; //0 = 224 lines; 1 = 240 lines - uint1 dmaEnable; uint1 verticalBlankInterruptEnable; uint1 displayEnable; uint1 externalVRAM; @@ -170,13 +177,6 @@ private: //$0f data port auto-increment value uint8 dataIncrement; - - //$13-$14 DMA length - uint16 dmaLength; - - //$15-$17 DMA source - uint22 dmaSource; - uint2 dmaMode; } io; struct State { diff --git a/higan/ms/bus/bus.cpp b/higan/ms/bus/bus.cpp index 36af0197..b85d9055 100644 --- a/higan/ms/bus/bus.cpp +++ b/higan/ms/bus/bus.cpp @@ -19,7 +19,7 @@ auto Bus::in(uint8 addr) -> uint8 { switch(addr >> 6) { case 0: { - if(system.model() == Model::GameGear) { + if(Model::GameGear()) { bool start = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 6); return start << 7 | 0x7f; } @@ -36,7 +36,7 @@ auto Bus::in(uint8 addr) -> uint8 { } case 3: { - if(system.model() == Model::MasterSystem) { + if(Model::MasterSystem()) { bool reset = !platform->inputPoll(ID::Port::Hardware, ID::Device::MasterSystemControls, 0); auto port1 = peripherals.controllerPort1->readData(); auto port2 = peripherals.controllerPort2->readData(); @@ -46,7 +46,8 @@ auto Bus::in(uint8 addr) -> uint8 { return port2.bits(2,5) << 0 | reset << 4 | 1 << 5 | port1.bit(6) << 6 | port2.bit(6) << 7; } } - if(system.model() == Model::GameGear) { + + if(Model::GameGear()) { bool up = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 0); bool down = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 1); bool left = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 2); @@ -61,6 +62,7 @@ auto Bus::in(uint8 addr) -> uint8 { return 0xff; } } + return 0xff; } @@ -70,8 +72,16 @@ auto Bus::in(uint8 addr) -> uint8 { } auto Bus::out(uint8 addr, uint8 data) -> void { + if(addr == 0x06) { + if(Model::GameGear()) return psg.balance(data); + } + switch(addr >> 6) { + case 1: { + return psg.write(data); + } + case 2: { return !addr.bit(0) ? vdp.data(data) : vdp.control(data); } diff --git a/higan/ms/cartridge/cartridge.cpp b/higan/ms/cartridge/cartridge.cpp index 4c25e486..91566cb7 100644 --- a/higan/ms/cartridge/cartridge.cpp +++ b/higan/ms/cartridge/cartridge.cpp @@ -8,17 +8,16 @@ Cartridge cartridge; auto Cartridge::load() -> bool { information = {}; - switch(system.model()) { - case Model::MasterSystem: + if(Model::MasterSystem()) { if(auto pathID = platform->load(ID::MasterSystem, "Master System", "ms")) { information.pathID = pathID(); } else return false; - break; - case Model::GameGear: + } + + if(Model::GameGear()) { if(auto pathID = platform->load(ID::GameGear, "Game Gear", "gg")) { information.pathID = pathID(); } else return false; - break; } if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) { diff --git a/higan/ms/cpu/cpu.cpp b/higan/ms/cpu/cpu.cpp index c616bd8d..1ade980e 100644 --- a/higan/ms/cpu/cpu.cpp +++ b/higan/ms/cpu/cpu.cpp @@ -31,7 +31,7 @@ auto CPU::step(uint clocks) -> void { //called once per frame auto CPU::pollPause() -> void { - if(system.model() == Model::MasterSystem) { + if(Model::MasterSystem()) { static bool pause = 0; bool state = platform->inputPoll(ID::Port::Hardware, ID::Device::MasterSystemControls, 1); if(!pause && state) setNMI(1); diff --git a/higan/ms/interface/game-gear.cpp b/higan/ms/interface/game-gear.cpp index 38d79dc0..b876084a 100644 --- a/higan/ms/interface/game-gear.cpp +++ b/higan/ms/interface/game-gear.cpp @@ -53,6 +53,6 @@ auto GameGearInterface::videoColor(uint32 color) -> uint64 { } auto GameGearInterface::load(uint id) -> bool { - if(id == ID::GameGear) return system.load(this, Model::GameGear); + if(id == ID::GameGear) return system.load(this, System::Model::GameGear); return false; } diff --git a/higan/ms/interface/master-system.cpp b/higan/ms/interface/master-system.cpp index 7bbf3d17..3d208e5d 100644 --- a/higan/ms/interface/master-system.cpp +++ b/higan/ms/interface/master-system.cpp @@ -69,6 +69,6 @@ auto MasterSystemInterface::videoColor(uint32 color) -> uint64 { } auto MasterSystemInterface::load(uint id) -> bool { - if(id == ID::MasterSystem) return system.load(this, Model::MasterSystem); + if(id == ID::MasterSystem) return system.load(this, System::Model::MasterSystem); return false; } diff --git a/higan/ms/ms.hpp b/higan/ms/ms.hpp index c3ba221b..f7a2f13a 100644 --- a/higan/ms/ms.hpp +++ b/higan/ms/ms.hpp @@ -16,11 +16,6 @@ namespace MasterSystem { extern Scheduler scheduler; struct Interface; - enum class Model : uint { - MasterSystem, - GameGear, - }; - struct Thread : Emulator::Thread { auto create(auto (*entrypoint)() -> void, double frequency) -> void { Emulator::Thread::create(entrypoint, frequency); @@ -32,6 +27,11 @@ namespace MasterSystem { } }; + struct Model { + inline static auto MasterSystem() -> bool; + inline static auto GameGear() -> bool; + }; + #include #include diff --git a/higan/ms/psg/io.cpp b/higan/ms/psg/io.cpp new file mode 100644 index 00000000..844b4345 --- /dev/null +++ b/higan/ms/psg/io.cpp @@ -0,0 +1,82 @@ +//note: tone is supposed to reload counters on volume writes +//however, if this is always done, the output is very grainy +//as such, this behavior is suppressed when pitch >= 2 (which is a hack) + +auto PSG::write(uint8 data) -> void { + bool l = data.bit(7); + if(l) select = data.bits(4,6); + + switch(select) { + + case 0: { + if(l) tone0.pitch.bits(0,3) = data.bits(0,3); + else tone0.pitch.bits(4,9) = data.bits(0,5); + break; + } + + case 1: { + tone0.volume = data.bits(0,3); + if(tone0.pitch < 2) { + tone0.output = 1; + tone0.counter = tone0.pitch; + } + break; + } + + case 2: { + if(l) tone1.pitch.bits(0,3) = data.bits(0,3); + else tone1.pitch.bits(4,9) = data.bits(0,5); + break; + } + + case 3: { + tone1.volume = data.bits(0,3); + if(tone1.pitch < 2) { + tone1.output = 1; + tone1.counter = tone1.pitch; + } + break; + } + + case 4: { + if(l) tone2.pitch.bits(0,3) = data.bits(0,3); + else tone2.pitch.bits(4,9) = data.bits(0,5); + break; + } + + case 5: { + tone2.volume = data.bits(0,3); + if(tone2.pitch < 2) { + tone2.output = 1; + tone2.counter = tone2.pitch; + } + break; + } + + case 6: { + noise.rate = data.bits(0,1); + noise.enable = data.bit(2); + noise.lfsr = 0x8000; + break; + } + + case 7: { + noise.volume = data.bits(0,3); + noise.output = 1; + break; + } + + } +} + +//Game Gear only +auto PSG::balance(uint8 data) -> void { + tone0.right = data.bit(0); + tone1.right = data.bit(1); + tone2.right = data.bit(2); + noise.right = data.bit(3); + tone0.left = data.bit(4); + tone1.left = data.bit(5); + tone2.left = data.bit(6); + noise.left = data.bit(7); +} diff --git a/higan/ms/psg/noise.cpp b/higan/ms/psg/noise.cpp new file mode 100644 index 00000000..e3c41123 --- /dev/null +++ b/higan/ms/psg/noise.cpp @@ -0,0 +1,30 @@ +auto PSG::Noise::run() -> void { + auto latch = clock; + + counter++; + if(rate < 3) { + clock ^= counter & ((16 << rate) - 1) == 0; + } else { + clock ^= psg.tone2.clock; + } + + if(!latch && clock) { + auto eor = enable ? ~lfsr >> 3 : 0; + lfsr = (lfsr ^ eor) << 15 | lfsr >> 1; + } + + output = lfsr.bit(0); +} + +auto PSG::Noise::power() -> void { + volume = ~0; + counter = 0; + enable = 0; + rate = 0; + lfsr = 0x8000; + clock = 0; + output = 0; + + left = 1; + right = 1; +} diff --git a/higan/ms/psg/psg.cpp b/higan/ms/psg/psg.cpp index 7c2376c2..d824ef69 100644 --- a/higan/ms/psg/psg.cpp +++ b/higan/ms/psg/psg.cpp @@ -3,14 +3,42 @@ namespace MasterSystem { PSG psg; +#include "io.cpp" +#include "tone.cpp" +#include "noise.cpp" auto PSG::Enter() -> void { while(true) scheduler.synchronize(), psg.main(); } auto PSG::main() -> void { + tone0.run(); + tone1.run(); + tone2.run(); + noise.run(); + + int left = 0; + if(tone0.output && tone0.left) left += levels[tone0.volume]; + if(tone1.output && tone1.left) left += levels[tone1.volume]; + if(tone2.output && tone2.left) left += levels[tone2.volume]; + if(noise.output && noise.left) left += levels[noise.volume]; + + lowpassLeft += (left - lowpassLeft) * 20.0 / 256.0; + left = left * 2.0 / 6.0 + lowpassLeft * 3.0 / 4.0; + left = sclamp<16>(left); + + int right = 0; + if(tone0.output && tone0.right) right += levels[tone0.volume]; + if(tone1.output && tone1.right) right += levels[tone1.volume]; + if(tone2.output && tone2.right) right += levels[tone2.volume]; + if(noise.output && noise.right) right += levels[noise.volume]; + + lowpassRight += (right - lowpassRight) * 20.0 / 256.0; + right = right * 2.0 / 6.0 + lowpassRight * 3.0 / 4.0; + right = sclamp<16>(right); + step(1); - stream->sample(0.0, 0.0); + stream->sample(left / 32768.0, right / 32768.0); } auto PSG::step(uint clocks) -> void { @@ -19,8 +47,23 @@ auto PSG::step(uint clocks) -> void { } auto PSG::power() -> void { - create(PSG::Enter, system.colorburst()); - stream = Emulator::audio.createStream(2, system.colorburst()); + //Master System is monaural; Game Gear is stereo + //use stereo mode for both; output same sample to both channels for Master System + create(PSG::Enter, system.colorburst() / 16.0); + stream = Emulator::audio.createStream(2, frequency()); + + select = 0; + lowpassLeft = 0; + lowpassRight = 0; + for(auto n : range(15)) { + levels[n] = 0x3fff * pow(2, n * -2.0 / 6.0) + 0.5; + } + levels[15] = 0; + + tone0.power(); + tone1.power(); + tone2.power(); + noise.power(); } } diff --git a/higan/ms/psg/psg.hpp b/higan/ms/psg/psg.hpp index 9b11454b..69d3c1fd 100644 --- a/higan/ms/psg/psg.hpp +++ b/higan/ms/psg/psg.hpp @@ -8,6 +8,48 @@ struct PSG : Thread { auto step(uint clocks) -> void; auto power() -> void; + + //io.cpp + auto write(uint8 data) -> void; + auto balance(uint8 data) -> void; + +private: + struct Tone { + //tone.cpp + auto run() -> void; + auto power() -> void; + + uint4 volume; + uint10 counter; + uint10 pitch; + uint1 clock; + uint1 output; + + uint1 left; + uint1 right; + } tone0, tone1, tone2; + + struct Noise { + //noise.cpp + auto run() -> void; + auto power() -> void; + + uint4 volume; + uint6 counter; + uint1 enable; + uint2 rate; + uint16 lfsr; + uint1 clock; + uint1 output; + + uint1 left; + uint1 right; + } noise; + + uint3 select; + int lowpassLeft; + int lowpassRight; + uint16 levels[16]; }; extern PSG psg; diff --git a/higan/ms/psg/tone.cpp b/higan/ms/psg/tone.cpp new file mode 100644 index 00000000..35877323 --- /dev/null +++ b/higan/ms/psg/tone.cpp @@ -0,0 +1,19 @@ +auto PSG::Tone::run() -> void { + clock = 0; + if(--counter) return; + + clock = 1; + counter = pitch; + output ^= 1; +} + +auto PSG::Tone::power() -> void { + volume = ~0; + counter = 0; + pitch = 0; + clock = 0; + output = 0; + + left = 1; + right = 1; +} diff --git a/higan/ms/system/peripherals.cpp b/higan/ms/system/peripherals.cpp index 5133ebdb..da23e6b0 100644 --- a/higan/ms/system/peripherals.cpp +++ b/higan/ms/system/peripherals.cpp @@ -15,7 +15,7 @@ auto Peripherals::reset() -> void { auto Peripherals::connect(uint port, uint device) -> void { cpu.peripherals.reset(); - if(system.model() == Model::MasterSystem) { + if(Model::MasterSystem()) { if(port == ID::Port::Controller1) { settings.controllerPort1 = device; if(!system.loaded()) return; diff --git a/higan/ms/system/system.hpp b/higan/ms/system/system.hpp index 8d8e1240..d1ee6e89 100644 --- a/higan/ms/system/system.hpp +++ b/higan/ms/system/system.hpp @@ -1,4 +1,6 @@ struct System { + enum class Model : uint { MasterSystem, GameGear }; + auto loaded() const -> bool { return information.loaded; } auto model() const -> Model { return information.model; } auto colorburst() const -> double { return information.colorburst; } @@ -33,3 +35,6 @@ struct Peripherals { extern System system; extern Peripherals peripherals; + +auto Model::MasterSystem() -> bool { return system.model() == System::Model::MasterSystem; } +auto Model::GameGear() -> bool { return system.model() == System::Model::GameGear; } diff --git a/higan/ms/vdp/io.cpp b/higan/ms/vdp/io.cpp index 3a716a46..d8a35eb1 100644 --- a/higan/ms/vdp/io.cpp +++ b/higan/ms/vdp/io.cpp @@ -51,8 +51,8 @@ auto VDP::data(uint8 data) -> void { vram[io.address++] = data; } else { uint mask = 0; - if(system.model() == Model::MasterSystem) mask = 0x1f; - if(system.model() == Model::GameGear) mask = 0x3f; + if(Model::MasterSystem()) mask = 0x1f; + if(Model::GameGear()) mask = 0x3f; cram[io.address++ & mask] = data; } } diff --git a/higan/ms/vdp/vdp.cpp b/higan/ms/vdp/vdp.cpp index 3568e024..b8025a24 100644 --- a/higan/ms/vdp/vdp.cpp +++ b/higan/ms/vdp/vdp.cpp @@ -72,7 +72,7 @@ auto VDP::step(uint clocks) -> void { } auto VDP::refresh() -> void { - if(system.model() == Model::MasterSystem) { + if(Model::MasterSystem()) { //center the video output vertically in the viewport uint32* screen = buffer; if(vlines() == 224) screen += 16 * 256; @@ -81,7 +81,7 @@ auto VDP::refresh() -> void { Emulator::video.refresh(screen, 256 * sizeof(uint32), 256, 240); } - if(system.model() == Model::GameGear) { + if(Model::GameGear()) { Emulator::video.refresh(buffer + 48 * 256 + 48, 256 * sizeof(uint32), 160, 144); } } @@ -107,11 +107,11 @@ auto VDP::power() -> void { } auto VDP::palette(uint5 index) -> uint12 { - if(system.model() == Model::MasterSystem) { + if(Model::MasterSystem()) { return cram[index]; } - if(system.model() == Model::GameGear) { + if(Model::GameGear()) { return cram[index * 2 + 0] << 0 | cram[index * 2 + 1] << 8; }