bsnes-mt/bsnes/sfc/ppu/counter/counter-inline.hpp
2020-06-02 20:53:45 +03:00

84 lines
2.7 KiB
C++

auto PPUcounter::tick() -> void {
time.hcounter += 2; //increment by smallest unit of time.
if(time.hcounter == hperiod()) {
last.hperiod = hperiod();
time.hcounter = 0;
tickScanline();
}
}
auto PPUcounter::tick(uint clocks) -> void {
time.hcounter += clocks;
if(time.hcounter >= hperiod()) {
last.hperiod = hperiod();
time.hcounter -= hperiod();
tickScanline();
}
}
auto PPUcounter::tickScanline() -> void {
if(++time.vcounter == 128) {
//it's not important when this is captured: it is only needed at V=240 or V=311.
time.interlace = ppu.interlace();
time.vperiod += interlace() && !field();
}
if(vcounter() == vperiod()) {
last.vperiod = vperiod();
//this may be off by one until V=128, hence why vperiod() is a private function.
time.vperiod = Region::NTSC() ? 262 : 312;
time.vcounter = 0;
time.field ^= 1;
}
time.hperiod = 1364;
//NTSC and PAL scanline rates would not match up with color clocks if every scanline were 1364 clocks.
//to offset for this error, NTSC has one short scanline, and PAL has one long scanline.
if(Region::NTSC() && interlace() == 0 && field() == 1 && vcounter() == 240) time.hperiod -= 4;
if(Region::PAL() && interlace() == 1 && field() == 1 && vcounter() == 311) time.hperiod += 4;
if(scanline) scanline();
}
auto PPUcounter::interlace() const -> bool { return time.interlace; }
auto PPUcounter::field() const -> bool { return time.field; }
auto PPUcounter::vcounter() const -> uint { return time.vcounter; }
auto PPUcounter::hcounter() const -> uint { return time.hcounter; }
auto PPUcounter::vperiod() const -> uint { return time.vperiod; }
auto PPUcounter::hperiod() const -> uint { return time.hperiod; }
auto PPUcounter::vcounter(uint offset) const -> uint {
if(offset <= hcounter()) return vcounter();
if(vcounter() > 0) return vcounter() - 1;
return last.vperiod - 1;
}
auto PPUcounter::hcounter(uint offset) const -> uint {
if(offset <= hcounter()) return hcounter() - offset;
return hcounter() + last.hperiod - offset;
}
//one PPU dot = 4 CPU clocks.
//
//PPU dots 323 and 327 are 6 CPU clocks long.
//this does not apply to NTSC non-interlace scanline 240 on odd fields. this is
//because the PPU skips one dot to alter the color burst phase of the video signal.
//it is not known what happens for PAL 1368 clock scanlines.
//
//dot 323 range = {1292, 1294, 1296}
//dot 327 range = {1310, 1312, 1314}
auto PPUcounter::hdot() const -> uint {
if(hperiod() == 1360) {
return hcounter() >> 2;
} else {
return hcounter() - ((hcounter() > 1292) << 1) - ((hcounter() > 1310) << 1) >> 2;
}
}
auto PPUcounter::reset() -> void {
time = {};
last = {};
time.vperiod = last.vperiod = Region::NTSC() ? 262 : 312;
time.hperiod = last.hperiod = 1364;
}