GB Video: Convert to mTiming

This commit is contained in:
Jeffrey Pfau 2016-09-18 19:06:20 -07:00
parent 6243b7fd3b
commit bf9be29ad5
5 changed files with 185 additions and 189 deletions

View File

@ -36,6 +36,17 @@ void mTimingSchedule(struct mTiming* timing, struct mTimingEvent* event, int32_t
*mTimingEventListAppend(&timing->events) = event; *mTimingEventListAppend(&timing->events) = event;
} }
void mTimingDeschedule(struct mTiming* timing, struct mTimingEvent* event) {
size_t e;
for (e = 0; e < mTimingEventListSize(&timing->events); ++e) {
struct mTimingEvent* next = *mTimingEventListGetPointer(&timing->events, e);
if (next == event) {
mTimingEventListShift(&timing->events, e, 1);
return;
}
}
}
void mTimingTick(struct mTiming* timing, int32_t cycles) { void mTimingTick(struct mTiming* timing, int32_t cycles) {
timing->masterCycles += cycles; timing->masterCycles += cycles;
while (mTimingEventListSize(&timing->events)) { while (mTimingEventListSize(&timing->events)) {

View File

@ -29,6 +29,7 @@ void mTimingInit(struct mTiming* timing);
void mTimingDeinit(struct mTiming* timing); void mTimingDeinit(struct mTiming* timing);
void mTimingClear(struct mTiming* timing); void mTimingClear(struct mTiming* timing);
void mTimingSchedule(struct mTiming* timing, struct mTimingEvent*, int32_t when); void mTimingSchedule(struct mTiming* timing, struct mTimingEvent*, int32_t when);
void mTimingDeschedule(struct mTiming* timing, struct mTimingEvent*);
void mTimingTick(struct mTiming* timing, int32_t cycles); void mTimingTick(struct mTiming* timing, int32_t cycles);
int32_t mTimingNextEvent(struct mTiming* timing); int32_t mTimingNextEvent(struct mTiming* timing);

View File

@ -549,14 +549,6 @@ void GBProcessEvents(struct LR35902Core* cpu) {
nextEvent = testEvent; nextEvent = testEvent;
} }
testEvent = GBVideoProcessEvents(&gb->video, cycles >> gb->doubleSpeed);
if (testEvent != INT_MAX) {
testEvent <<= gb->doubleSpeed;
if (testEvent < nextEvent) {
nextEvent = testEvent;
}
}
testEvent = GBAudioProcessEvents(&gb->audio, cycles >> gb->doubleSpeed); testEvent = GBAudioProcessEvents(&gb->audio, cycles >> gb->doubleSpeed);
if (testEvent != INT_MAX) { if (testEvent != INT_MAX) {
testEvent <<= gb->doubleSpeed; testEvent <<= gb->doubleSpeed;

View File

@ -27,6 +27,12 @@ static void GBVideoDummyRendererPutPixels(struct GBVideoRenderer* renderer, size
static void _cleanOAM(struct GBVideo* video, int y); static void _cleanOAM(struct GBVideo* video, int y);
static void _endMode0(struct mTiming* timing, void* context, uint32_t cyclesLate);
static void _endMode1(struct mTiming* timing, void* context, uint32_t cyclesLate);
static void _endMode2(struct mTiming* timing, void* context, uint32_t cyclesLate);
static void _endMode3(struct mTiming* timing, void* context, uint32_t cyclesLate);
static void _updateFrameCount(struct mTiming* timing, void* context, uint32_t cyclesLate);
static struct GBVideoRenderer dummyRenderer = { static struct GBVideoRenderer dummyRenderer = {
.init = GBVideoDummyRendererInit, .init = GBVideoDummyRendererInit,
.deinit = GBVideoDummyRendererDeinit, .deinit = GBVideoDummyRendererDeinit,
@ -45,6 +51,13 @@ void GBVideoInit(struct GBVideo* video) {
video->renderer->cache = NULL; video->renderer->cache = NULL;
video->vram = 0; video->vram = 0;
video->frameskip = 0; video->frameskip = 0;
video->modeEvent.context = video;
video->modeEvent.name = "GB Video Mode";
video->modeEvent.callback = NULL;
video->frameEvent.context = video;
video->frameEvent.name = "GB Video Frame";
video->frameEvent.callback = _updateFrameCount;
} }
void GBVideoReset(struct GBVideo* video) { void GBVideoReset(struct GBVideo* video) {
@ -53,13 +66,6 @@ void GBVideoReset(struct GBVideo* video) {
video->mode = 1; video->mode = 1;
video->stat = 1; video->stat = 1;
video->nextEvent = INT_MAX;
video->eventDiff = 0;
video->nextMode = INT_MAX;
video->dotCounter = INT_MIN;
video->nextFrame = INT_MAX;
video->frameCounter = 0; video->frameCounter = 0;
video->frameskipCounter = 0; video->frameskipCounter = 0;
@ -90,43 +96,30 @@ void GBVideoAssociateRenderer(struct GBVideo* video, struct GBVideoRenderer* ren
video->renderer->init(video->renderer, video->p->model); video->renderer->init(video->renderer, video->p->model);
} }
int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) { void _endMode0(struct mTiming* timing, void* context, uint32_t cyclesLate) {
video->eventDiff += cycles; struct GBVideo* video = context;
if (video->nextEvent != INT_MAX) {
video->nextEvent -= cycles;
}
if (video->nextEvent <= 0) {
if (video->nextMode != INT_MAX) {
video->nextMode -= video->eventDiff;
}
if (video->nextFrame != INT_MAX) {
video->nextFrame -= video->eventDiff;
}
video->nextEvent = INT_MAX;
GBVideoProcessDots(video);
if (video->nextMode <= 0) {
int lyc = video->p->memory.io[REG_LYC];
switch (video->mode) {
case 0:
if (video->frameskipCounter <= 0) { if (video->frameskipCounter <= 0) {
video->renderer->finishScanline(video->renderer, video->ly); video->renderer->finishScanline(video->renderer, video->ly);
} }
int lyc = video->p->memory.io[REG_LYC];
int32_t next;
++video->ly; ++video->ly;
video->p->memory.io[REG_LY] = video->ly; video->p->memory.io[REG_LY] = video->ly;
video->stat = GBRegisterSTATSetLYC(video->stat, lyc == video->ly); video->stat = GBRegisterSTATSetLYC(video->stat, lyc == video->ly);
if (video->ly < GB_VIDEO_VERTICAL_PIXELS) { if (video->ly < GB_VIDEO_VERTICAL_PIXELS) {
video->nextMode = GB_VIDEO_MODE_2_LENGTH + (video->p->memory.io[REG_SCX] & 7); // TODO: Cache SCX & 7 in case it changes during mode 2
next = GB_VIDEO_MODE_2_LENGTH + (video->p->memory.io[REG_SCX] & 7);
video->mode = 2; video->mode = 2;
video->modeEvent.callback = _endMode2;
if (!GBRegisterSTATIsHblankIRQ(video->stat) && GBRegisterSTATIsOAMIRQ(video->stat)) { if (!GBRegisterSTATIsHblankIRQ(video->stat) && GBRegisterSTATIsOAMIRQ(video->stat)) {
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
} }
} else { } else {
video->nextMode = GB_VIDEO_HORIZONTAL_LENGTH; next = GB_VIDEO_HORIZONTAL_LENGTH;
video->mode = 1; video->mode = 1;
video->modeEvent.callback = _endMode1;
if (video->nextFrame != 0) { _updateFrameCount(timing, video, cyclesLate);
video->nextFrame = 0;
}
if (GBRegisterSTATIsVblankIRQ(video->stat) || GBRegisterSTATIsOAMIRQ(video->stat)) { if (GBRegisterSTATIsVblankIRQ(video->stat) || GBRegisterSTATIsOAMIRQ(video->stat)) {
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
@ -142,16 +135,26 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
} }
GBUpdateIRQs(video->p); GBUpdateIRQs(video->p);
break; video->stat = GBRegisterSTATSetMode(video->stat, video->mode);
case 1: video->p->memory.io[REG_STAT] = video->stat;
mTimingSchedule(timing, &video->modeEvent, (next << video->p->doubleSpeed) - cyclesLate);
}
void _endMode1(struct mTiming* timing, void* context, uint32_t cyclesLate) {
struct GBVideo* video = context;
if (!GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC])) {
return;
}
int lyc = video->p->memory.io[REG_LYC];
// TODO: One M-cycle delay // TODO: One M-cycle delay
++video->ly; ++video->ly;
int32_t next;
if (video->ly == GB_VIDEO_VERTICAL_TOTAL_PIXELS + 1) { if (video->ly == GB_VIDEO_VERTICAL_TOTAL_PIXELS + 1) {
video->ly = 0; video->ly = 0;
video->p->memory.io[REG_LY] = video->ly; video->p->memory.io[REG_LY] = video->ly;
// TODO: Cache SCX & 7 in case it changes during mode 2 next = GB_VIDEO_MODE_2_LENGTH + (video->p->memory.io[REG_SCX] & 7);
video->nextMode = GB_VIDEO_MODE_2_LENGTH + (video->p->memory.io[REG_SCX] & 7);
video->mode = 2; video->mode = 2;
video->modeEvent.callback = _endMode2;
if (GBRegisterSTATIsOAMIRQ(video->stat)) { if (GBRegisterSTATIsOAMIRQ(video->stat)) {
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
GBUpdateIRQs(video->p); GBUpdateIRQs(video->p);
@ -160,55 +163,68 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
if (video->p->memory.mbcType == GB_MBC7 && video->p->memory.rotation && video->p->memory.rotation->sample) { if (video->p->memory.mbcType == GB_MBC7 && video->p->memory.rotation && video->p->memory.rotation->sample) {
video->p->memory.rotation->sample(video->p->memory.rotation); video->p->memory.rotation->sample(video->p->memory.rotation);
} }
break;
} else if (video->ly == GB_VIDEO_VERTICAL_TOTAL_PIXELS) { } else if (video->ly == GB_VIDEO_VERTICAL_TOTAL_PIXELS) {
video->p->memory.io[REG_LY] = 0; video->p->memory.io[REG_LY] = 0;
video->nextMode = GB_VIDEO_HORIZONTAL_LENGTH - 8; next = GB_VIDEO_HORIZONTAL_LENGTH - 8;
} else if (video->ly == GB_VIDEO_VERTICAL_TOTAL_PIXELS - 1) { } else if (video->ly == GB_VIDEO_VERTICAL_TOTAL_PIXELS - 1) {
video->p->memory.io[REG_LY] = video->ly; video->p->memory.io[REG_LY] = video->ly;
video->nextMode = 8; next = 8;
} else { } else {
video->p->memory.io[REG_LY] = video->ly; video->p->memory.io[REG_LY] = video->ly;
video->nextMode = GB_VIDEO_HORIZONTAL_LENGTH; next = GB_VIDEO_HORIZONTAL_LENGTH;
} }
video->stat = GBRegisterSTATSetMode(video->stat, video->mode);
video->stat = GBRegisterSTATSetLYC(video->stat, lyc == video->p->memory.io[REG_LY]); video->stat = GBRegisterSTATSetLYC(video->stat, lyc == video->p->memory.io[REG_LY]);
if (GBRegisterSTATIsLYCIRQ(video->stat) && lyc == video->p->memory.io[REG_LY]) { if (video->ly && GBRegisterSTATIsLYCIRQ(video->stat) && lyc == video->p->memory.io[REG_LY]) {
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
GBUpdateIRQs(video->p); GBUpdateIRQs(video->p);
} }
break; video->p->memory.io[REG_STAT] = video->stat;
case 2: mTimingSchedule(timing, &video->modeEvent, (next << video->p->doubleSpeed) - cyclesLate);
}
void _endMode2(struct mTiming* timing, void* context, uint32_t cyclesLate) {
struct GBVideo* video = context;
_cleanOAM(video, video->ly); _cleanOAM(video, video->ly);
video->dotCounter = 0;
video->nextEvent = GB_VIDEO_HORIZONTAL_LENGTH;
video->x = 0; video->x = 0;
// TODO: Estimate sprite timings better video->dotClock = timing->masterCycles - cyclesLate;
video->nextMode = GB_VIDEO_MODE_3_LENGTH_BASE + video->objMax * 11 - (video->p->memory.io[REG_SCX] & 7); int32_t next = GB_VIDEO_MODE_3_LENGTH_BASE + video->objMax * 11 - (video->p->memory.io[REG_SCX] & 7);
video->mode = 3; video->mode = 3;
break; video->modeEvent.callback = _endMode3;
case 3: video->stat = GBRegisterSTATSetMode(video->stat, video->mode);
video->nextMode = GB_VIDEO_MODE_0_LENGTH_BASE - video->objMax * 11; video->p->memory.io[REG_STAT] = video->stat;
video->mode = 0; mTimingSchedule(timing, &video->modeEvent, (next << video->p->doubleSpeed) - cyclesLate);
}
void _endMode3(struct mTiming* timing, void* context, uint32_t cyclesLate) {
struct GBVideo* video = context;
GBVideoProcessDots(video);
if (GBRegisterSTATIsHblankIRQ(video->stat)) { if (GBRegisterSTATIsHblankIRQ(video->stat)) {
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
GBUpdateIRQs(video->p); GBUpdateIRQs(video->p);
} }
if (video->ly < GB_VIDEO_VERTICAL_PIXELS && video->p->memory.isHdma && video->p->memory.io[REG_HDMA5] != 0xFF) { if (video->ly < GB_VIDEO_VERTICAL_PIXELS && video->p->memory.isHdma && video->p->memory.io[REG_HDMA5] != 0xFF) {
video->p->memory.hdmaRemaining = 0x10; video->p->memory.hdmaRemaining = 0x10;
mTimingSchedule(&video->p->timing, &video->p->memory.hdmaEvent, 0); mTimingSchedule(timing, &video->p->memory.hdmaEvent, 0);
}
break;
} }
video->mode = 0;
video->modeEvent.callback = _endMode0;
video->stat = GBRegisterSTATSetMode(video->stat, video->mode); video->stat = GBRegisterSTATSetMode(video->stat, video->mode);
video->p->memory.io[REG_STAT] = video->stat; video->p->memory.io[REG_STAT] = video->stat;
int32_t next = GB_VIDEO_MODE_0_LENGTH_BASE - video->objMax * 11;
mTimingSchedule(timing, &video->modeEvent, (next << video->p->doubleSpeed) - cyclesLate);
} }
if (video->nextFrame <= 0) {
if (video->p->cpu->executionState == LR35902_CORE_FETCH) {
GBFrameEnded(video->p);
video->nextFrame = GB_VIDEO_TOTAL_LENGTH;
video->nextEvent = GB_VIDEO_TOTAL_LENGTH;
void _updateFrameCount(struct mTiming* timing, void* context, uint32_t cyclesLate) {
UNUSED(cyclesLate);
struct GBVideo* video = context;
if (video->p->cpu->executionState != LR35902_CORE_FETCH) {
mTimingSchedule(timing, &video->frameEvent, 4 - ((video->p->cpu->executionState + 1) & 3));
return;
}
GBFrameEnded(video->p);
--video->frameskipCounter; --video->frameskipCounter;
if (video->frameskipCounter < 0) { if (video->frameskipCounter < 0) {
mCoreSyncPostFrame(video->p->sync); mCoreSyncPostFrame(video->p->sync);
@ -216,30 +232,23 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
} }
++video->frameCounter; ++video->frameCounter;
// TODO: Move to common code
if (video->p->stream && video->p->stream->postVideoFrame) { if (video->p->stream && video->p->stream->postVideoFrame) {
const color_t* pixels; const color_t* pixels;
size_t stride; size_t stride;
video->renderer->getPixels(video->renderer, &stride, (const void**) &pixels); video->renderer->getPixels(video->renderer, &stride, (const void**) &pixels);
video->p->stream->postVideoFrame(video->p->stream, pixels, stride); video->p->stream->postVideoFrame(video->p->stream, pixels, stride);
} }
struct mCoreCallbacks* callbacks = video->p->coreCallbacks; struct mCoreCallbacks* callbacks = video->p->coreCallbacks;
if (callbacks && callbacks->videoFrameStarted) { if (callbacks && callbacks->videoFrameStarted) {
callbacks->videoFrameStarted(callbacks->context); callbacks->videoFrameStarted(callbacks->context);
} }
} else {
video->nextFrame = 4 - ((video->p->cpu->executionState + 1) & 3); if (!GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC])) {
if (video->nextFrame < video->nextEvent) { mTimingSchedule(timing, &video->frameEvent, GB_VIDEO_TOTAL_LENGTH);
video->nextEvent = video->nextFrame;
} }
} }
}
if (video->nextMode < video->nextEvent) {
video->nextEvent = video->nextMode;
}
video->eventDiff = 0;
}
return video->nextEvent;
}
static void _cleanOAM(struct GBVideo* video, int y) { static void _cleanOAM(struct GBVideo* video, int y) {
// TODO: GBC differences // TODO: GBC differences
@ -267,20 +276,17 @@ static void _cleanOAM(struct GBVideo* video, int y) {
} }
void GBVideoProcessDots(struct GBVideo* video) { void GBVideoProcessDots(struct GBVideo* video) {
if (video->mode != 3 || video->dotCounter < 0) { if (video->mode != 3) {
return; return;
} }
int oldX = video->x; int oldX = video->x;
video->x = video->dotCounter + video->eventDiff + (video->p->cpu->cycles >> video->p->doubleSpeed); video->x = (video->p->timing.masterCycles - video->dotClock + video->p->cpu->cycles) >> video->p->doubleSpeed;
if (video->x > GB_VIDEO_HORIZONTAL_PIXELS) { if (video->x > GB_VIDEO_HORIZONTAL_PIXELS) {
video->x = GB_VIDEO_HORIZONTAL_PIXELS; video->x = GB_VIDEO_HORIZONTAL_PIXELS;
} else if (video->x < 0) { } else if (video->x < 0) {
mLOG(GB, FATAL, "Video dot clock went negative!"); mLOG(GB, FATAL, "Video dot clock went negative!");
video->x = oldX; video->x = oldX;
} }
if (video->x == GB_VIDEO_HORIZONTAL_PIXELS) {
video->dotCounter = INT_MIN;
}
if (video->frameskipCounter <= 0) { if (video->frameskipCounter <= 0) {
video->renderer->drawRange(video->renderer, oldX, video->x, video->ly, video->objThisLine, video->objMax); video->renderer->drawRange(video->renderer, oldX, video->x, video->ly, video->objThisLine, video->objMax);
} }
@ -289,9 +295,10 @@ void GBVideoProcessDots(struct GBVideo* video) {
void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value) { void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value) {
if (!GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC]) && GBRegisterLCDCIsEnable(value)) { if (!GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC]) && GBRegisterLCDCIsEnable(value)) {
video->mode = 2; video->mode = 2;
video->nextMode = GB_VIDEO_MODE_2_LENGTH - 5; // TODO: Why is this fudge factor needed? Might be related to T-cycles for load/store differing video->modeEvent.callback = _endMode2;
video->nextEvent = video->nextMode; int32_t next = GB_VIDEO_MODE_2_LENGTH - 5; // TODO: Why is this fudge factor needed? Might be related to T-cycles for load/store differing
video->eventDiff = -video->p->cpu->cycles >> video->p->doubleSpeed; mTimingSchedule(&video->p->timing, &video->modeEvent, next << video->p->doubleSpeed);
video->ly = 0; video->ly = 0;
video->p->memory.io[REG_LY] = 0; video->p->memory.io[REG_LY] = 0;
// TODO: Does this read as 0 for 4 T-cycles? // TODO: Does this read as 0 for 4 T-cycles?
@ -302,21 +309,16 @@ void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value) {
GBUpdateIRQs(video->p); GBUpdateIRQs(video->p);
} }
video->p->memory.io[REG_STAT] = video->stat; video->p->memory.io[REG_STAT] = video->stat;
mTimingDeschedule(&video->p->timing, &video->frameEvent);
if (video->p->cpu->cycles + (video->nextEvent << video->p->doubleSpeed) < video->p->cpu->nextEvent) {
video->p->cpu->nextEvent = video->p->cpu->cycles + (video->nextEvent << video->p->doubleSpeed);
}
return;
} }
if (GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC]) && !GBRegisterLCDCIsEnable(value)) { if (GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC]) && !GBRegisterLCDCIsEnable(value)) {
video->mode = 0; video->stat = GBRegisterSTATSetMode(video->stat, 0);
video->nextMode = INT_MAX;
video->nextEvent = video->nextFrame;
video->stat = GBRegisterSTATSetMode(video->stat, video->mode);
video->p->memory.io[REG_STAT] = video->stat; video->p->memory.io[REG_STAT] = video->stat;
video->ly = 0; video->ly = 0;
video->p->memory.io[REG_LY] = 0; video->p->memory.io[REG_LY] = 0;
mTimingSchedule(&video->p->timing, &video->frameEvent, GB_VIDEO_TOTAL_LENGTH);
} }
video->p->memory.io[REG_STAT] = video->stat;
} }
void GBVideoWriteSTAT(struct GBVideo* video, GBRegisterSTAT value) { void GBVideoWriteSTAT(struct GBVideo* video, GBRegisterSTAT value) {
@ -486,10 +488,6 @@ static void GBVideoDummyRendererPutPixels(struct GBVideoRenderer* renderer, size
void GBVideoSerialize(const struct GBVideo* video, struct GBSerializedState* state) { void GBVideoSerialize(const struct GBVideo* video, struct GBSerializedState* state) {
STORE_16LE(video->x, 0, &state->video.x); STORE_16LE(video->x, 0, &state->video.x);
STORE_16LE(video->ly, 0, &state->video.ly); STORE_16LE(video->ly, 0, &state->video.ly);
STORE_32LE(video->nextEvent, 0, &state->video.nextEvent);
STORE_32LE(video->eventDiff, 0, &state->video.eventDiff);
STORE_32LE(video->nextMode, 0, &state->video.nextMode);
STORE_32LE(video->dotCounter, 0, &state->video.dotCounter);
STORE_32LE(video->frameCounter, 0, &state->video.frameCounter); STORE_32LE(video->frameCounter, 0, &state->video.frameCounter);
state->video.vramCurrentBank = video->vramCurrentBank; state->video.vramCurrentBank = video->vramCurrentBank;
@ -513,10 +511,6 @@ void GBVideoSerialize(const struct GBVideo* video, struct GBSerializedState* sta
void GBVideoDeserialize(struct GBVideo* video, const struct GBSerializedState* state) { void GBVideoDeserialize(struct GBVideo* video, const struct GBSerializedState* state) {
LOAD_16LE(video->x, 0, &state->video.x); LOAD_16LE(video->x, 0, &state->video.x);
LOAD_16LE(video->ly, 0, &state->video.ly); LOAD_16LE(video->ly, 0, &state->video.ly);
LOAD_32LE(video->nextEvent, 0, &state->video.nextEvent);
LOAD_32LE(video->eventDiff, 0, &state->video.eventDiff);
LOAD_32LE(video->nextMode, 0, &state->video.nextMode);
LOAD_32LE(video->dotCounter, 0, &state->video.dotCounter);
LOAD_32LE(video->frameCounter, 0, &state->video.frameCounter); LOAD_32LE(video->frameCounter, 0, &state->video.frameCounter);
video->vramCurrentBank = state->video.vramCurrentBank; video->vramCurrentBank = state->video.vramCurrentBank;

View File

@ -9,6 +9,7 @@
#include "util/common.h" #include "util/common.h"
#include "core/interface.h" #include "core/interface.h"
#include "core/timing.h"
#include "gb/interface.h" #include "gb/interface.h"
#include "gb/memory.h" #include "gb/memory.h"
@ -101,13 +102,10 @@ struct GBVideo {
int mode; int mode;
int32_t nextEvent; struct mTimingEvent modeEvent;
int32_t eventDiff; struct mTimingEvent frameEvent;
int32_t nextMode; uint32_t dotClock;
int32_t dotCounter;
int32_t nextFrame;
uint8_t* vram; uint8_t* vram;
uint8_t* vramBank; uint8_t* vramBank;