bsnes/higan/ms/vdp/vdp.cpp

123 lines
2.6 KiB
C++
Raw Normal View History

#include <ms/ms.hpp>
namespace MasterSystem {
VDP vdp;
#include "io.cpp"
#include "background.cpp"
#include "sprite.cpp"
Update to v102r10 release. byuu says: Changelog: - removed Emulator::Interface::Capabilities¹ - MS: improved the PSG emulation a bit - MS: added cheat code support - MS: added save state support² - MD: emulated the PSG³ ¹: there's really no point to it anymore. I intend to add cheat codes to the GBA core, as well as both cheat codes and save states to the Mega Drive core. I no longer intend to emulate any new systems, so these values will always be true. Further, the GUI doesn't respond to these values to disable those features anymore ever since the hiro rewrite, so they're double useless. ²: right now, the Z80 core is using a pointer for HL-\>(IX,IY) overrides. But I can't reliably serialize pointers, so I need to convert the Z80 core to use an integer here. The save states still appear to work fine, but there's the potential for an instruction to execute incorrectly if you're incredibly unlucky, so this needs to be fixed as soon as possible. Further, I still need a way to serialize array<T, Size> objects, and I should also add nall::Boolean serialization support. ³: I don't have a system in place to share identical sound chips. But this chip is so incredibly simple that it's not really much trouble to duplicate it. Further, I can strip out the stereo sound support code from the Game Gear portion, so it's even tinier. Note that the Mega Drive only just barely uses the PSG. Not at all in Altered Beast, and only for a tiny part of the BGM music on Sonic 1, plus his jump sound effect.
2017-02-22 21:25:01 +00:00
#include "serialization.cpp"
auto VDP::Enter() -> void {
while(true) scheduler.synchronize(), vdp.main();
}
auto VDP::main() -> void {
if(io.vcounter <= vlines()) {
if(io.lcounter-- == 0) {
io.lcounter = io.lineCounter;
io.intLine = 1;
}
} else {
io.lcounter = io.lineCounter;
}
if(io.vcounter == vlines() + 1) {
io.intFrame = 1;
}
background.scanline();
sprite.scanline();
//684 clocks/scanline
uint y = io.vcounter;
if(y < vlines()) {
uint32* screen = buffer + (24 + y) * 256;
for(uint x : range(256)) {
background.run();
sprite.run();
step(2);
uint12 color = palette(io.backdropColor);
if(background.output.color && (background.output.priority || !sprite.output.color)) {
color = palette(background.output.palette << 4 | background.output.color);
} else if(sprite.output.color) {
color = palette(16 | sprite.output.color);
}
if(x <= 7 && io.leftClip) color = palette(io.backdropColor);
if(!io.displayEnable) color = 0;
*screen++ = color;
}
} else {
//Vblank
step(512);
}
step(172);
if(io.vcounter == 240) scheduler.exit(Scheduler::Event::Frame);
}
auto VDP::step(uint clocks) -> void {
while(clocks--) {
if(++io.hcounter == 684) {
io.hcounter = 0;
if(++io.vcounter == 262) {
io.vcounter = 0;
}
}
cpu.setINT((io.lineInterrupts && io.intLine) || (io.frameInterrupts && io.intFrame));
Thread::step(1);
synchronize(cpu);
}
}
auto VDP::refresh() -> void {
if(Model::MasterSystem()) {
//center the video output vertically in the viewport
uint32* screen = buffer;
if(vlines() == 224) screen += 16 * 256;
if(vlines() == 240) screen += 24 * 256;
Emulator::video.refresh(screen, 256 * sizeof(uint32), 256, 240);
}
if(Model::GameGear()) {
Emulator::video.refresh(buffer + 48 * 256 + 48, 256 * sizeof(uint32), 160, 144);
}
}
auto VDP::vlines() -> uint {
if(io.lines240) return 240;
if(io.lines224) return 224;
return 192;
}
auto VDP::vblank() -> bool {
return io.vcounter >= vlines();
}
auto VDP::power() -> void {
create(VDP::Enter, system.colorburst() * 15.0 / 5.0);
memory::fill(&buffer, sizeof(buffer));
memory::fill(&io, sizeof(IO));
background.power();
sprite.power();
}
auto VDP::palette(uint5 index) -> uint12 {
if(Model::MasterSystem()) {
return cram[index];
}
if(Model::GameGear()) {
return cram[index * 2 + 0] << 0 | cram[index * 2 + 1] << 8;
}
return 0;
}
}