Skip to content

Commit

Permalink
features: optimized DMA
Browse files Browse the repository at this point in the history
Run DMA syncs only when needed, instead of running them on
VDP steps. Thanks to this, the optimizeSteps option is no
longer needed, since we can optimize all cases safely.
  • Loading branch information
stelcheck committed May 10, 2021
1 parent 0625b6f commit edbe1e6
Show file tree
Hide file tree
Showing 8 changed files with 26 additions and 52 deletions.
4 changes: 3 additions & 1 deletion higan/emulator/scheduler-synchro/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Thread::~Thread() {
destroy();
}

auto Thread::active() const -> bool { return true; } // Todo: what does this mean if threads don't run
auto Thread::active() const -> bool { return _active; }
auto Thread::handle() const -> thread_handle_t* { return _handle; }
auto Thread::frequency() const -> uintmax { return _frequency; }
auto Thread::scalar() const -> uintmax { return _scalar; }
Expand Down Expand Up @@ -69,7 +69,9 @@ auto Thread::synchronize(Thread& thread, P&&... p) -> void {
//disable synchronization for auxiliary threads during scheduler synchronization.
//synchronization can begin inside of this while loop.
if(scheduler.synchronizing()) break;
thread._active = true;
thread.main();
thread._active = false;
}
thread._handle->parent = _parent;

Expand Down
1 change: 1 addition & 0 deletions higan/emulator/scheduler-synchro/thread.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct Thread {
uintmax _frequency = 0;
uintmax _scalar = 0;
uintmax _clock = 0;
bool _active;

friend class Scheduler;
};
6 changes: 1 addition & 5 deletions higan/md/interface/interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@ namespace higan::MegaDrive {
Interface* interface = nullptr;

auto MegaDriveInterface::configure(string name, double value) -> void {
if(name.match("vdp/optimizeSteps")) {
#if defined(PROFILE_PERFORMANCE)
vdp.optimizeSteps = (bool) value;
#endif
} else if(name.match("vdp/skipframe")) {
if(name.match("vdp/skipframe")) {
vdp.isSkipping = (bool) value;
} else if(name.match("cpu/overclock")) {
cpu.overclock = value / 7.0;
Expand Down
19 changes: 14 additions & 5 deletions higan/md/vdp-performance/dma.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
auto VDP::DMA::poll() -> void {
static bool locked = false;
if(locked) return;
locked = true;
if(cpu.active()) cpu.synchronize(apu, vdp);
if(apu.active()) apu.synchronize(cpu, vdp);
while(run());
locked = false;
}

auto VDP::DMA::run() -> bool {
if(!io.enable || io.wait) return false;

if(!vdp.io.command.bit(5)) return false;
if(io.mode <= 1) return load(), true;
if(io.mode == 2) return fill(), true;
if(!vdp.io.command.bit(4)) return false;
if(io.mode == 3) return copy(), true;

unreachable;
return false;
}

auto VDP::DMA::load() -> void {
active = 1;

auto data = cpu.read(1, 1, io.mode.bit(0) << 23 | io.source << 1);
auto address = io.mode.bit(0) << 23 | io.source << 1;
auto data = cpu.read(1, 1, address);
vdp.writeDataPort(data);

io.source.bit(0,15)++;
Expand Down Expand Up @@ -51,4 +60,4 @@ auto VDP::DMA::copy() -> void {
auto VDP::DMA::power() -> void {
active = 0;
io = {};
}
}
6 changes: 5 additions & 1 deletion higan/md/vdp-performance/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ auto VDP::writeDataPort(uint16 data) -> void {
if(io.address.bit(0)) data = data >> 8 | data << 8;
vram.write(address, data);
io.address += io.dataIncrement;
dma.poll();
return;
}

Expand Down Expand Up @@ -148,6 +149,7 @@ auto VDP::writeControlPort(uint16 data) -> void {

if(!dma.io.enable) io.command.bit(5) = 0;
if(dma.io.mode == 3) dma.io.wait = false;
dma.poll();
return;
}

Expand Down Expand Up @@ -182,6 +184,7 @@ auto VDP::writeControlPort(uint16 data) -> void {
io.displayEnable = data.bit(6);
vram.mode = data.bit(7);
if(!dma.io.enable) io.command.bit(5) = 0;
dma.poll();
return;
}

Expand Down Expand Up @@ -322,6 +325,7 @@ auto VDP::writeControlPort(uint16 data) -> void {
dma.io.source.bit(16,21) = data.bit(0,5);
dma.io.mode = data.bit(6,7);
dma.io.wait = dma.io.mode.bit(1);
dma.poll();
return;
}

Expand All @@ -331,4 +335,4 @@ auto VDP::writeControlPort(uint16 data) -> void {
}

}
}
}
35 changes: 1 addition & 34 deletions higan/md/vdp-performance/vdp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,8 @@ auto VDP::unload() -> void {
}

static uint counter = 0;
static uint dmaCounter = 0;

auto VDP::main() -> void {
#if defined(SCHEDULER_SYNCHRO)
if (dmaCounter > 0) {
dma.run();
Thread::step(1);
Thread::synchronize(apu);
dmaCounter--;
return;
}
#endif

switch(counter++) {
case 1:
//H = 0
Expand Down Expand Up @@ -126,29 +115,7 @@ auto VDP::main() -> void {

auto VDP::step(uint clocks) -> void {
state.hcounter += clocks;

if(optimizeSteps && (!dma.io.enable || dma.io.wait)) {
dma.active = 0;
Thread::step(clocks);
#if defined(SCHEDULER_SYNCHRO)
Thread::synchronize(apu);
#else
Thread::synchronize(cpu, apu);
#endif
} else {
#if defined(SCHEDULER_SYNCHRO)
dmaCounter = clocks - 1;
dma.run();
Thread::step(1);
Thread::synchronize(apu);
#else
while(clocks--) {
dma.run();
Thread::step(1);
Thread::synchronize(cpu, apu);
}
#endif
}
Thread::step(clocks);
}

auto VDP::refresh() -> void {
Expand Down
2 changes: 1 addition & 1 deletion higan/md/vdp-performance/vdp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ struct VDP : Thread {
double overclock = 0.5;

bool hasRendered = false;
bool optimizeSteps = false;
bool isSkipping = false;
bool skip;

Expand Down Expand Up @@ -89,6 +88,7 @@ struct VDP : Thread {

struct DMA {
//dma.cpp
alwaysinline auto poll() -> void;
alwaysinline auto run() -> bool;
alwaysinline auto load() -> void;
alwaysinline auto fill() -> void;
Expand Down
5 changes: 0 additions & 5 deletions higan/target-web/shell.html
Original file line number Diff line number Diff line change
Expand Up @@ -922,8 +922,6 @@
<div class="values">
<input type="checkbox" name="md-skipframe" id="md-skipframe" />
<label for="md-skipframe">Skip frame</label>
<input type="checkbox" name="md-optimizeSteps" id="md-optimizeSteps" />
<label for="md-optimizeSteps">VDP - Optimize DMA Steps</label>
<select name="md-cpu-overclock" id="md-cpu-overclock">
<option value="0.25">0.25</option>
<option value="0.5">0.5</option>
Expand Down Expand Up @@ -1457,9 +1455,6 @@
case 'skipframe':
Module.configure('vdp/skipframe', value);
return true;
case 'optimizeSteps':
Module.configure('vdp/optimizeSteps', value);
return true;
}
return false;
}
Expand Down

0 comments on commit edbe1e6

Please sign in to comment.