This commit is contained in:
Asnivor 2018-05-10 10:42:44 +01:00
commit de00fbaf19
7 changed files with 167 additions and 165 deletions

View File

@ -9,8 +9,14 @@
means that we lower the priority of a state that goes at that index. Priority changes
depending on current frame and amount of states. States with biggest priority get erased
first. With a 4-bit battern and no initial gap between states, total frame coverage is
about 5 times state count. Initial state gap can screw up our patterns, so do all
calculations like gap isn't there, and take it back into account afterwards.
about 5 times state count.
Initial state gap can screw up our patterns, so do all the calculations like the gap
isn't there, and take it back into account afterwards. The algo only works with integral
greenzone, so we make it think it is integral by reducing the frame numbers. Before any
decay logic starts for each state, we check if it has a marker on it (in which case we
don't drop it) or appears inside the state gap (in which case we forcibly drop it). This
step doesn't involve numbers reduction.
_zeros values are essentialy the values of rshiftby here:
bitwise view frame rshiftby priority
@ -59,7 +65,7 @@ namespace BizHawk.Client.Common
for (; decayStates > 0 && _tsm.StateCount > 1;)
{
int baseStateIndex = _tsm.GetStateIndexByFrame(Global.Emulator.Frame);
int baseStateFrame = _tsm.GetStateFrameByIndex(baseStateIndex) / _step;
int baseStateFrame = _tsm.GetStateFrameByIndex(baseStateIndex) / _step; // reduce right away
int forwardPriority = -1000000;
int backwardPriority = -1000000;
int forwardFrame = -1;
@ -76,14 +82,18 @@ namespace BizHawk.Client.Common
else if (currentFrame % _step > 0)
{
// ignore the pattern if the state doesn't belong already, drop it blindly and skip everything
_tsm.RemoveState(currentFrame);
decayStates--;
if (_tsm.RemoveState(currentFrame))
{
// decrementing this if no state was removed is BAD
decayStates--;
// this is the kind of highly complex loops that might justify goto
goto next_state;
// this is the kind of highly complex loops that might justify goto
goto next_state;
}
}
else
{
// reduce to imaginary integral greenzone for all the decay logic
currentFrame /= _step;
}
@ -104,7 +114,7 @@ namespace BizHawk.Client.Common
for (int currentStateIndex = _tsm.StateCount - 1; currentStateIndex > baseStateIndex; currentStateIndex--)
{
int currentFrame = _tsm.GetStateFrameByIndex(currentStateIndex) / _step;
int currentFrame = _tsm.GetStateFrameByIndex(currentStateIndex);
if (_tsm.StateIsMarker(currentFrame))
{
@ -113,14 +123,18 @@ namespace BizHawk.Client.Common
else if (currentFrame % _step > 0)
{
// ignore the pattern if the state doesn't belong already, drop it blindly and skip everything
_tsm.RemoveState(currentFrame);
decayStates--;
if (_tsm.RemoveState(currentFrame))
{
// decrementing this if no state was removed is BAD
decayStates--;
// this is the kind of highly complex loops that might justify goto
goto next_state;
// this is the kind of highly complex loops that might justify goto
goto next_state;
}
}
else
{
// reduce to imaginary integral greenzone for all the decay logic
currentFrame /= _step;
}
@ -143,30 +157,46 @@ namespace BizHawk.Client.Common
{
if (baseStateFrame - forwardFrame > backwardFrame - baseStateFrame)
{
_tsm.RemoveState(forwardFrame * _step);
if (_tsm.RemoveState(forwardFrame * _step))
{
// decrementing this if no state was removed is BAD
decayStates--;
}
}
else
{
_tsm.RemoveState(backwardFrame * _step);
if (_tsm.RemoveState(backwardFrame * _step))
{
// decrementing this if no state was removed is BAD
decayStates--;
}
}
decayStates--;
}
else if (forwardFrame > -1)
{
_tsm.RemoveState(forwardFrame * _step);
decayStates--;
if (_tsm.RemoveState(forwardFrame * _step))
{
// decrementing this if no state was removed is BAD
decayStates--;
}
}
else if (backwardFrame > -1)
{
_tsm.RemoveState(backwardFrame * _step);
decayStates--;
if (_tsm.RemoveState(backwardFrame * _step))
{
// decrementing this if no state was removed is BAD
decayStates--;
}
}
else
{
// we're very sorry about failing to find states to remove, but we can't go beyond capacity, so remove at least something
// this shouldn't happen, but if we don't do it here, nothing good will happen either
_tsm.RemoveState(_tsm.GetStateFrameByIndex(1));
if (_tsm.RemoveState(_tsm.GetStateFrameByIndex(1)))
{
// decrementing this if no state was removed is BAD
decayStates--;
}
}
// this is the kind of highly complex loops that might justify goto

View File

@ -262,13 +262,13 @@ namespace BizHawk.Client.Common
return _movie.Markers.IsMarker(frame + 1);
}
public void RemoveState(int frame)
public bool RemoveState(int frame)
{
int index = _states.IndexOfKey(frame);
if (frame < 1 || index < 1)
{
return;
return false;
}
StateManagerState state = _states.Values[index];
@ -283,6 +283,8 @@ namespace BizHawk.Client.Common
}
_states.RemoveAt(index);
return true;
}
/// <summary>

View File

@ -4,8 +4,8 @@ namespace BizHawk.Emulation.Common.Components.LR35902
{
public partial class LR35902
{
private int totalExecutedCycles;
public int TotalExecutedCycles { get { return totalExecutedCycles; } set { totalExecutedCycles = value; } }
private ulong totalExecutedCycles;
public ulong TotalExecutedCycles { get { return totalExecutedCycles; } set { totalExecutedCycles = value; } }
private int EI_pending;
private bool interrupts_enabled;

View File

@ -295,7 +295,8 @@ namespace BizHawk.Emulation.Common.Components.LR35902
// call the interrupt processor after 4 extra cycles
if (!Halt_bug_3)
{
INTERRUPT_GBC_NOP();
INTERRUPT_GBC_NOP();
//INTERRUPT_();
}
else
{

View File

@ -58,9 +58,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public override byte ReadReg(int addr)
{
byte ret = 0;
//Console.WriteLine(Core.cpu.TotalExecutedCycles);
switch (addr)
{
{
case 0xFF40: ret = LCDC; break; // LCDC
case 0xFF41: ret = STAT; break; // STAT
case 0xFF42: ret = scroll_y; break; // SCY
@ -350,7 +350,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
cycle = 0;
LY_actual = LY;
LY += LY_inc;
Core.cpu.LY = LY;
// here is where LY = LYC gets cleared (but only if LY isnt 0 as that's a special case)
if (LY_inc == 1)
{
LYC_INT = false;
STAT &= 0xFB;
}
no_scan = false;
@ -359,6 +366,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
LY_inc = 1;
Core.in_vblank = false;
/*
VBL_INT = false;
if (STAT.Bit(3)) { HBL_INT = true; }
STAT &= 0xFC;
*/
// special note here, the y coordiate of the window is kept if the window is deactivated
// meaning it will pick up where it left off if re-enabled later
// so we don't reset it in the scanline loop
@ -368,8 +381,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
window_is_reset = true;
}
Core.cpu.LY = LY;
// Automatically restore access to VRAM at this time (force end drawing)
// Who Framed Roger Rabbit seems to run into this.
VRAM_access_write = true;
@ -381,34 +392,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
}
if (cycle == 452)
{
LY += LY_inc;
// here is where LY = LYC gets cleared (but only if LY isnt 0 as that's a special case)
if (LY_inc == 1)
{
LYC_INT = false;
STAT &= 0xFB;
}
else
{
VBL_INT = false;
if (STAT.Bit(3)) { HBL_INT = true; }
STAT &= 0xFC;
}
Core.cpu.LY = LY;
}
if ((LY == 153) && (cycle == 0))
{
LY = 0;
LY_inc = 0;
}
// exit vblank if LCD went from off to on
if (LCD_was_off)
{
@ -424,25 +407,25 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
// also, the LCD does not enter mode 2 on scanline 0 when first turned on
no_scan = true;
cycle = 4;
cycle = 8;
}
// the VBL stat is continuously asserted
if ((LY_actual >= 144))
if ((LY >= 144))
{
if (STAT.Bit(4))
{
if ((cycle >= 0) && (LY_actual == 144))
if ((cycle >= 4) && (LY == 144))
{
VBL_INT = true;
}
else if (LY_actual > 144)
else if (LY > 144)
{
VBL_INT = true;
}
}
if ((cycle == 0) && (LY_actual == 144)) {
if ((cycle == 4) && (LY == 144)) {
HBL_INT = false;
@ -454,15 +437,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
Core.REG_FF0F |= 0x01;
}
if ((LY_actual >= 144) && (cycle == 0))
if ((LY >= 144) && (cycle == 4))
{
// a special case of OAM mode 2 IRQ assertion, even though PPU Mode still is 1
if (STAT.Bit(5)) { OAM_INT = true; }
//if (STAT.Bit(5)) { OAM_INT = true; }
}
if ((LY_actual == 153) && (cycle == 4))
if ((LY == 153) && (cycle == 8))
{
LY_actual = 0;
LY = 0;
LY_inc = 0;
Core.cpu.LY = LY;
}
}
@ -475,7 +459,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
// there is no mode 2 (presumably it missed the trigger)
// mode 3 is very short, probably in some self test mode before turning on?
if (cycle == 4)
if (cycle == 8)
{
if (LY != LYC)
{
@ -491,9 +475,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
}
if (cycle == 80)
if (cycle == 84)
{
STAT &= 0xFC;
STAT |= 0x03;
OAM_INT = false;
@ -504,7 +487,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
VRAM_access_write = false;
}
if (cycle == 252)
if (cycle == 256)
{
STAT &= 0xFC;
OAM_INT = false;
@ -519,9 +502,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
else
{
if (cycle < 76)
if (cycle < 80)
{
if (cycle == 0)
if (cycle == 4)
{
// apparently, writes can make it to OAM one cycle longer then reads
OAM_access_write = false;
@ -529,24 +512,22 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
// here mode 2 will be set to true and interrupts fired if enabled
STAT &= 0xFC;
STAT |= 0x2;
if (STAT.Bit(5)) { OAM_INT = true; }
HBL_INT = false;
// DMG exits VBlank into mode 0, but not GBC, so this line is needed
// (This is important for Wacky Racers and Altered Space)
VBL_INT = false;
}
// here OAM scanning is performed
OAM_scan(cycle + 4);
OAM_scan(cycle);
}
else if (cycle >= 76 && LY_actual < 144)
else if ((cycle >= 80) && (LY < 144))
{
if (cycle == 76)
{
OAM_access_read = false;
OAM_access_write = true;
VRAM_access_read = false;
}
if (cycle == 80)
if (cycle == 84)
{
STAT &= 0xFC;
STAT |= 0x03;
@ -556,20 +537,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
// render the screen and handle hblank
render(cycle - 76);
render(cycle - 80);
}
}
if (cycle >= 452)
{
OAM_access_read = false;
OAM_scan(cycle - 452);
}
}
if ((LY_inc == 0))
{
if (cycle == 8)
if (cycle == 12)
{
LYC_INT = false;
STAT &= 0xFB;
@ -583,14 +558,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
// also a special case of OAM mode 2 IRQ assertion, even though PPU Mode still is 1
if (STAT.Bit(5)) { OAM_INT = true; }
//if (STAT.Bit(5)) { OAM_INT = true; }
}
if (cycle == 88) { OAM_INT = false; }
//if (cycle == 92) { OAM_INT = false; }
}
// here LY=LYC will be asserted
if ((cycle == 0) && (LY_actual != 0))
if ((cycle == 4) && (LY != 0))
{
if ((LY == LYC) && !STAT.Bit(2))
{
@ -613,7 +588,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
LCD_was_off = true;
LY = 0;
LY_actual = 0;
Core.cpu.LY = LY;
cycle = 0;
@ -647,6 +621,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
// i.e. just keeping track of the lowest x-value sprite
if (render_cycle == 0)
{
OAM_access_read = false;
OAM_access_write = true;
VRAM_access_read = false;
// window X is latched for the scanline, mid-line changes have no effect
window_x_latch = window_x;
@ -847,6 +825,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{
read_case = 8;
hbl_countdown = 5;
if (window_started)
{
hbl_countdown -= 2;
}
}
if (pixel_counter == 158 && window_started)
{
STAT &= 0xFC;
STAT |= 0x00;
if (STAT.Bit(3)) { HBL_INT = true; }
}
}
else if ((render_counter >= render_offset) && (pixel_counter < 0))
@ -1411,6 +1400,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
// TODO: maybe stat mode 2 flags are set at cycle 0 on visible scanlines?
if (OAM_cycle == 0)
{
OAM_access_read = false;
OAM_scan_index = 0;
SL_sprites_index = 0;
write_sprite = 0;

View File

@ -71,7 +71,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public int TotalExecutedCycles
{
get { return cpu.TotalExecutedCycles; }
get { return (int)cpu.TotalExecutedCycles; }
}
}
}

View File

@ -71,7 +71,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
x_tile = (int)Math.Floor((float)(scroll_x) / 8);
break;
case 0xFF44: // LY
LY = LY_actual = 0; /*reset*/
LY = 0; /*reset*/
break;
case 0xFF45: // LYC
LYC = value;
@ -125,7 +125,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
cycle = 0;
LY_actual = LY;
LY += LY_inc;
Core.cpu.LY = LY;
// here is where LY = LYC gets cleared (but only if LY isnt 0 as that's a special case)
if (LY_inc == 1)
{
LYC_INT = false;
STAT &= 0xFB;
}
no_scan = false;
@ -134,6 +142,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
LY_inc = 1;
Core.in_vblank = false;
VBL_INT = false;
if (STAT.Bit(3)) { HBL_INT = true; }
STAT &= 0xFC;
// special note here, the y coordiate of the window is kept if the window is deactivated
// meaning it will pick up where it left off if re-enabled later
// so we don't reset it in the scanline loop
@ -154,34 +167,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
}
if (cycle == 452)
{
LY += LY_inc;
// here is where LY = LYC gets cleared (but only if LY isnt 0 as that's a special case)
if (LY_inc == 1)
{
LYC_INT = false;
STAT &= 0xFB;
}
else
{
VBL_INT = false;
if (STAT.Bit(3)) { HBL_INT = true; }
STAT &= 0xFC;
}
Core.cpu.LY = LY;
}
if ((LY == 153) && (cycle == 0))
{
LY = 0;
LY_inc = 0;
}
// exit vblank if LCD went from off to on
if (LCD_was_off)
{
@ -197,25 +182,25 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
// also, the LCD does not enter mode 2 on scanline 0 when first turned on
no_scan = true;
cycle = 4;
cycle = 8;
}
// the VBL stat is continuously asserted
if ((LY_actual >= 144))
if ((LY >= 144))
{
if (STAT.Bit(4))
{
if ((cycle >= 0) && (LY_actual == 144))
if ((cycle >= 4) && (LY == 144))
{
VBL_INT = true;
}
else if (LY_actual > 144)
else if (LY > 144)
{
VBL_INT = true;
}
}
if ((cycle == 0) && (LY_actual == 144)) {
if ((cycle == 4) && (LY == 144)) {
HBL_INT = false;
@ -227,15 +212,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
Core.REG_FF0F |= 0x01;
}
if ((LY_actual >= 144) && (cycle == 0))
if ((LY >= 144) && (cycle == 4))
{
// a special case of OAM mode 2 IRQ assertion, even though PPU Mode still is 1
if (STAT.Bit(5)) { OAM_INT = true; }
}
if ((LY_actual == 153) && (cycle == 4))
if ((LY == 153) && (cycle == 8))
{
LY_actual = 0;
LY = 0;
LY_inc = 0;
Core.cpu.LY = LY;
}
}
@ -248,7 +234,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
// there is no mode 2 (presumably it missed the trigger)
// mode 3 is very short, probably in some self test mode before turning on?
if (cycle == 4)
if (cycle == 8)
{
if (LY != LYC)
{
@ -264,7 +250,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
}
if (cycle == 80)
if (cycle == 84)
{
STAT &= 0xFC;
@ -277,7 +263,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
VRAM_access_write = false;
}
if (cycle == 252)
if (cycle == 256)
{
STAT &= 0xFC;
OAM_INT = false;
@ -292,9 +278,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
else
{
if (cycle < 76)
if (cycle < 80)
{
if (cycle == 0)
if (cycle == 4)
{
// apparently, writes can make it to OAM one cycle longer then reads
OAM_access_write = false;
@ -308,18 +294,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
// here OAM scanning is performed
OAM_scan(cycle + 4);
OAM_scan(cycle);
}
else if ((cycle >= 76) && (LY_actual < 144))
else if ((cycle >= 80) && (LY < 144))
{
if (cycle == 76)
{
OAM_access_read = false;
OAM_access_write = true;
VRAM_access_read = false;
}
if (cycle == 80)
if (cycle == 84)
{
STAT &= 0xFC;
STAT |= 0x03;
@ -329,20 +308,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
// render the screen and handle hblank
render(cycle - 76);
render(cycle - 80);
}
}
if (cycle >= 452)
{
if (LY != 144) { OAM_access_read = false; }
OAM_scan(cycle - 452);
}
}
}
if ((LY_inc == 0))
{
if (cycle == 8)
if (cycle == 12)
{
LYC_INT = false;
STAT &= 0xFB;
@ -359,11 +332,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if (STAT.Bit(5)) { OAM_INT = true; }
}
if (cycle == 88) { OAM_INT = false; }
if (cycle == 92) { OAM_INT = false; }
}
// here LY=LYC will be asserted
if ((cycle == 0) && (LY_actual != 0))
if ((cycle == 4) && (LY != 0))
{
if ((LY == LYC) && !STAT.Bit(2))
{
@ -386,7 +359,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
LCD_was_off = true;
LY = 0;
LY_actual = 0;
Core.cpu.LY = LY;
cycle = 0;
@ -420,6 +392,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
// i.e. just keeping track of the lowest x-value sprite
if (render_cycle == 0)
{
OAM_access_read = false;
OAM_access_write = true;
VRAM_access_read = false;
// window X is latched for the scanline, mid-line changes have no effect
window_x_latch = window_x;
@ -924,14 +900,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{
if (LCDC.Bit(2))
{
y = LY_actual - (SL_sprites[sl_use_index * 4] - 16);
y = LY - (SL_sprites[sl_use_index * 4] - 16);
y = 15 - y;
sprite_sel[0] = Core.VRAM[(SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2];
sprite_sel[1] = Core.VRAM[(SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2 + 1];
}
else
{
y = LY_actual - (SL_sprites[sl_use_index * 4] - 16);
y = LY - (SL_sprites[sl_use_index * 4] - 16);
y = 7 - y;
sprite_sel[0] = Core.VRAM[SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2];
sprite_sel[1] = Core.VRAM[SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2 + 1];
@ -941,13 +917,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{
if (LCDC.Bit(2))
{
y = LY_actual - (SL_sprites[sl_use_index * 4] - 16);
y = LY - (SL_sprites[sl_use_index * 4] - 16);
sprite_sel[0] = Core.VRAM[(SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2];
sprite_sel[1] = Core.VRAM[(SL_sprites[sl_use_index * 4 + 2] & 0xFE) * 16 + y * 2 + 1];
}
else
{
y = LY_actual - (SL_sprites[sl_use_index * 4] - 16);
y = LY - (SL_sprites[sl_use_index * 4] - 16);
sprite_sel[0] = Core.VRAM[SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2];
sprite_sel[1] = Core.VRAM[SL_sprites[sl_use_index * 4 + 2] * 16 + y * 2 + 1];
}
@ -1085,6 +1061,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
// TODO: maybe stat mode 2 flags are set at cycle 0 on visible scanlines?
if (OAM_cycle == 0)
{
OAM_access_read = false;
OAM_scan_index = 0;
SL_sprites_index = 0;
write_sprite = 0;