GBHawk: performance optimizations
This commit is contained in:
parent
4494caac50
commit
527334f7e6
|
@ -59,6 +59,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
public int WAVE_decay_counter;
|
||||
public bool WAVE_decay_done;
|
||||
|
||||
public bool sound_update_needed;
|
||||
|
||||
// Audio Variables
|
||||
// derived
|
||||
public bool WAVE_DAC_pow;
|
||||
|
@ -625,8 +627,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
SQ1_output = DUTY_CYCLES[SQ1_duty * 8 + SQ1_duty_cntr] ? (SQ1_vol_state + DAC_OFST) : DAC_OFST;
|
||||
|
||||
// avoid aliasing at high frequenices
|
||||
//if (SQ1_frq > 0x7F0) { SQ1_output = 0; }
|
||||
sound_update_needed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -642,8 +643,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
SQ2_output = DUTY_CYCLES[SQ2_duty * 8 + SQ2_duty_cntr] ? (SQ2_vol_state + DAC_OFST) : DAC_OFST;
|
||||
|
||||
// avoid aliasing at high frequenices
|
||||
//if (SQ2_frq > 0x7F0) { SQ2_output = 0; }
|
||||
sound_update_needed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -687,6 +687,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
WAVE_wave_cntr++;
|
||||
WAVE_wave_cntr &= 0x1F;
|
||||
sample = Wave_RAM[WAVE_wave_cntr >> 1];
|
||||
|
||||
sound_update_needed = true;
|
||||
}
|
||||
}
|
||||
else if (!WAVE_decay_done && (++WAVE_decay_counter == 200))
|
||||
|
@ -696,18 +698,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
// wave state must decay slow enough that games that turn on and off the wave channel to fill wave RAM don't buzz too much
|
||||
if (!WAVE_DAC_pow)
|
||||
{
|
||||
if (WAVE_output > 0) { WAVE_output--; }
|
||||
if (WAVE_output > 0) { WAVE_output--; sound_update_needed = true; }
|
||||
else { WAVE_decay_done = true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (WAVE_output > DAC_OFST)
|
||||
{
|
||||
WAVE_output--;
|
||||
WAVE_output--; sound_update_needed = true;
|
||||
}
|
||||
else if (WAVE_output < DAC_OFST)
|
||||
{
|
||||
WAVE_output++;
|
||||
WAVE_output++; sound_update_needed = true;
|
||||
}
|
||||
else { WAVE_decay_done = true; }
|
||||
}
|
||||
|
@ -732,40 +734,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
|
||||
NOISE_output = (NOISE_LFSR & 1) > 0 ? DAC_OFST : (NOISE_vol_state + DAC_OFST);
|
||||
sound_update_needed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// add up components to each channel
|
||||
int L_final = 0;
|
||||
int R_final = 0;
|
||||
|
||||
if (AUD_CTRL_sq1_L_en) { L_final += SQ1_output; }
|
||||
if (AUD_CTRL_sq2_L_en) { L_final += SQ2_output; }
|
||||
if (AUD_CTRL_wave_L_en) { L_final += WAVE_output;}
|
||||
if (AUD_CTRL_noise_L_en) { L_final += NOISE_output; }
|
||||
|
||||
if (AUD_CTRL_sq1_R_en) { R_final += SQ1_output; }
|
||||
if (AUD_CTRL_sq2_R_en) { R_final += SQ2_output; }
|
||||
if (AUD_CTRL_wave_R_en) { R_final += WAVE_output; }
|
||||
if (AUD_CTRL_noise_R_en) { R_final += NOISE_output; }
|
||||
|
||||
L_final *= (AUD_CTRL_vol_L + 1) * 40;
|
||||
R_final *= (AUD_CTRL_vol_R + 1) * 40;
|
||||
|
||||
if (L_final != latched_sample_L)
|
||||
{
|
||||
_blip_L.AddDelta(master_audio_clock, L_final - latched_sample_L);
|
||||
latched_sample_L = L_final;
|
||||
}
|
||||
|
||||
if (R_final != latched_sample_R)
|
||||
{
|
||||
_blip_R.AddDelta(master_audio_clock, R_final - latched_sample_R);
|
||||
latched_sample_R = R_final;
|
||||
}
|
||||
|
||||
master_audio_clock++;
|
||||
|
||||
// frame sequencer ticks at a rate of 512 hz (or every time a 13 bit counter rolls over)
|
||||
// the sequencer is actually the timer DIV register
|
||||
// so if it's constantly written to, these values won't update
|
||||
|
@ -867,12 +839,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
if (SQ1_env_add)
|
||||
{
|
||||
if (SQ1_vol_state < 15) { SQ1_vol_state++; }
|
||||
if (SQ1_vol_state < 15) { SQ1_vol_state++; sound_update_needed = true; }
|
||||
else { SQ1_vol_done = true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SQ1_vol_state >= 1) { SQ1_vol_state--; }
|
||||
if (SQ1_vol_state >= 1) { SQ1_vol_state--; sound_update_needed = true; }
|
||||
else { SQ1_vol_done = true; }
|
||||
}
|
||||
}
|
||||
|
@ -889,12 +861,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
if (SQ2_env_add)
|
||||
{
|
||||
if (SQ2_vol_state < 15) { SQ2_vol_state++; }
|
||||
if (SQ2_vol_state < 15) { SQ2_vol_state++; sound_update_needed = true; }
|
||||
else { SQ2_vol_done = true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SQ2_vol_state >= 1) { SQ2_vol_state--; }
|
||||
if (SQ2_vol_state >= 1) { SQ2_vol_state--; sound_update_needed = true; }
|
||||
else { SQ2_vol_done = true; }
|
||||
}
|
||||
}
|
||||
|
@ -911,12 +883,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
{
|
||||
if (NOISE_env_add)
|
||||
{
|
||||
if (NOISE_vol_state < 15) { NOISE_vol_state++; }
|
||||
if (NOISE_vol_state < 15) { NOISE_vol_state++; sound_update_needed = true; }
|
||||
else { NOISE_vol_done = true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NOISE_vol_state >= 1) { NOISE_vol_state--; }
|
||||
if (NOISE_vol_state >= 1) { NOISE_vol_state--; sound_update_needed = true; }
|
||||
else { NOISE_vol_done = true; }
|
||||
}
|
||||
}
|
||||
|
@ -946,6 +918,40 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sound_update_needed)
|
||||
{
|
||||
// add up components to each channel
|
||||
int L_final = 0;
|
||||
int R_final = 0;
|
||||
|
||||
if (AUD_CTRL_sq1_L_en) { L_final += SQ1_output; }
|
||||
if (AUD_CTRL_sq2_L_en) { L_final += SQ2_output; }
|
||||
if (AUD_CTRL_wave_L_en) { L_final += WAVE_output; }
|
||||
if (AUD_CTRL_noise_L_en) { L_final += NOISE_output; }
|
||||
|
||||
if (AUD_CTRL_sq1_R_en) { R_final += SQ1_output; }
|
||||
if (AUD_CTRL_sq2_R_en) { R_final += SQ2_output; }
|
||||
if (AUD_CTRL_wave_R_en) { R_final += WAVE_output; }
|
||||
if (AUD_CTRL_noise_R_en) { R_final += NOISE_output; }
|
||||
|
||||
L_final *= (AUD_CTRL_vol_L + 1) * 40;
|
||||
R_final *= (AUD_CTRL_vol_R + 1) * 40;
|
||||
|
||||
if (L_final != latched_sample_L)
|
||||
{
|
||||
_blip_L.AddDelta(master_audio_clock, L_final - latched_sample_L);
|
||||
latched_sample_L = L_final;
|
||||
}
|
||||
|
||||
if (R_final != latched_sample_R)
|
||||
{
|
||||
_blip_R.AddDelta(master_audio_clock, R_final - latched_sample_R);
|
||||
latched_sample_R = R_final;
|
||||
}
|
||||
}
|
||||
master_audio_clock++;
|
||||
sound_update_needed = false;
|
||||
}
|
||||
|
||||
public void power_off()
|
||||
|
@ -1034,30 +1040,50 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
if (!NOISE_enable && ((Audio_Regs[NR42] & 0xF8) > 0)) { NOISE_output = DAC_OFST; }
|
||||
else if ((Audio_Regs[NR42] & 0xF8) == 0) { NOISE_output = 0; }
|
||||
|
||||
sound_update_needed = true;
|
||||
}
|
||||
|
||||
public void calculate_bias_gain_1()
|
||||
{
|
||||
if (!SQ1_enable && ((Audio_Regs[NR12] & 0xF8) > 0)) { SQ1_output = DAC_OFST; }
|
||||
else if ((Audio_Regs[NR12] & 0xF8) == 0) { SQ1_output = 0; }
|
||||
|
||||
sound_update_needed = true;
|
||||
}
|
||||
|
||||
public void calculate_bias_gain_2()
|
||||
{
|
||||
if (!SQ2_enable && ((Audio_Regs[NR22] & 0xF8) > 0)) { SQ2_output = DAC_OFST; }
|
||||
else if ((Audio_Regs[NR22] & 0xF8) == 0) { SQ2_output = 0; }
|
||||
|
||||
sound_update_needed = true;
|
||||
}
|
||||
|
||||
public void calculate_bias_gain_w()
|
||||
{
|
||||
if (!WAVE_enable && WAVE_DAC_pow) { WAVE_decay_counter = 0; WAVE_decay_done = false; }
|
||||
else if (!WAVE_DAC_pow) { WAVE_decay_counter = 0; WAVE_decay_done = false; }
|
||||
|
||||
sound_update_needed = true;
|
||||
}
|
||||
|
||||
public void calculate_bias_gain_n()
|
||||
{
|
||||
if (!NOISE_enable && ((Audio_Regs[NR42] & 0xF8) > 0)) { NOISE_output = DAC_OFST; }
|
||||
else if ((Audio_Regs[NR42] & 0xF8) == 0) { NOISE_output = 0; }
|
||||
|
||||
sound_update_needed = true;
|
||||
}
|
||||
|
||||
public void update_sound()
|
||||
{
|
||||
if (sound_update_needed)
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
|
@ -1145,6 +1171,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
ser.Sync(nameof(WAVE_decay_counter), ref WAVE_decay_counter);
|
||||
ser.Sync(nameof(WAVE_decay_done), ref WAVE_decay_done);
|
||||
|
||||
ser.Sync(nameof(sound_update_needed), ref sound_update_needed);
|
||||
ser.Sync(nameof(master_audio_clock), ref master_audio_clock);
|
||||
|
||||
ser.Sync(nameof(sample), ref sample);
|
||||
|
|
|
@ -1374,6 +1374,39 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
}
|
||||
|
||||
public override void DMA_tick()
|
||||
{
|
||||
if (DMA_clock >= 4)
|
||||
{
|
||||
DMA_OAM_access = false;
|
||||
if ((DMA_clock % 4) == 1)
|
||||
{
|
||||
// the cpu can't access memory during this time, but we still need the ppu to be able to.
|
||||
DMA_start = false;
|
||||
// Gekkio reports that A14 being high on DMA transfers always represent WRAM accesses
|
||||
// So transfers nominally from higher memory areas are actually still from there (i.e. FF -> DF)
|
||||
byte DMA_actual = DMA_addr;
|
||||
if (DMA_addr > 0xDF) { DMA_actual &= 0xDF; }
|
||||
DMA_byte = Core.ReadMemory((ushort)((DMA_actual << 8) + DMA_inc));
|
||||
DMA_start = true;
|
||||
}
|
||||
else if ((DMA_clock % 4) == 3)
|
||||
{
|
||||
Core.OAM[DMA_inc] = DMA_byte;
|
||||
|
||||
if (DMA_inc < (0xA0 - 1)) { DMA_inc++; }
|
||||
}
|
||||
}
|
||||
|
||||
DMA_clock++;
|
||||
|
||||
if (DMA_clock == 648)
|
||||
{
|
||||
DMA_start = false;
|
||||
DMA_OAM_access = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void process_sprite()
|
||||
{
|
||||
int y;
|
||||
|
@ -1414,66 +1447,27 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
if (SL_sprites[sl_use_index * 4 + 3].Bit(5))
|
||||
{
|
||||
int b0, b1, b2, b3, b4, b5, b6, b7 = 0;
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
b0 = (sprite_sel[i] & 0x01) << 7;
|
||||
b1 = (sprite_sel[i] & 0x02) << 5;
|
||||
b2 = (sprite_sel[i] & 0x04) << 3;
|
||||
b3 = (sprite_sel[i] & 0x08) << 1;
|
||||
b4 = (sprite_sel[i] & 0x10) >> 1;
|
||||
b5 = (sprite_sel[i] & 0x20) >> 3;
|
||||
b6 = (sprite_sel[i] & 0x40) >> 5;
|
||||
b7 = (sprite_sel[i] & 0x80) >> 7;
|
||||
|
||||
sprite_sel[i] = (byte)(b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7);
|
||||
sprite_sel[i] = (byte)(((sprite_sel[i] & 0x01) << 7) |
|
||||
((sprite_sel[i] & 0x02) << 5) |
|
||||
((sprite_sel[i] & 0x04) << 3) |
|
||||
((sprite_sel[i] & 0x08) << 1) |
|
||||
((sprite_sel[i] & 0x10) >> 1) |
|
||||
((sprite_sel[i] & 0x20) >> 3) |
|
||||
((sprite_sel[i] & 0x40) >> 5) |
|
||||
((sprite_sel[i] & 0x80) >> 7));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// normal DMA moves twice as fast in double speed mode on GBC
|
||||
// So give it it's own function so we can seperate it from PPU tick
|
||||
public override void DMA_tick()
|
||||
{
|
||||
if (DMA_clock >= 4)
|
||||
{
|
||||
DMA_OAM_access = false;
|
||||
if ((DMA_clock % 4) == 1)
|
||||
{
|
||||
// the cpu can't access memory during this time, but we still need the ppu to be able to.
|
||||
DMA_start = false;
|
||||
// Gekkio reports that A14 being high on DMA transfers always represent WRAM accesses
|
||||
// So transfers nominally from higher memory areas are actually still from there (i.e. FF -> DF)
|
||||
byte DMA_actual = DMA_addr;
|
||||
if (DMA_addr > 0xDF) { DMA_actual &= 0xDF; }
|
||||
DMA_byte = Core.ReadMemory((ushort)((DMA_actual << 8) + DMA_inc));
|
||||
DMA_start = true;
|
||||
}
|
||||
else if ((DMA_clock % 4) == 3)
|
||||
{
|
||||
Core.OAM[DMA_inc] = DMA_byte;
|
||||
|
||||
if (DMA_inc < (0xA0 - 1)) { DMA_inc++; }
|
||||
}
|
||||
}
|
||||
|
||||
DMA_clock++;
|
||||
|
||||
if (DMA_clock == 648)
|
||||
{
|
||||
DMA_start = false;
|
||||
DMA_OAM_access = true;
|
||||
}
|
||||
}
|
||||
|
||||
// order sprites according to x coordinate
|
||||
// order sprites according to x coordinate (in GB mode)
|
||||
// note that for sprites of equal x coordinate, priority goes to first on the list
|
||||
public override void reorder_and_assemble_sprites()
|
||||
{
|
||||
sprite_ordered_index = 0;
|
||||
|
||||
// In CGB mode, sprites are ordered solely based on their position in OAM, so they are already ordered
|
||||
|
||||
if (Core.GBC_compat)
|
||||
{
|
||||
for (int j = 0; j < SL_sprites_index; j++)
|
||||
|
@ -1507,48 +1501,44 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
|
||||
bool have_pixel = false;
|
||||
byte s_pixel = 0;
|
||||
byte sprite_attr = 0;
|
||||
|
||||
int low_bound = 0;
|
||||
int high_bound = 0;
|
||||
int t_index = 0;
|
||||
|
||||
for (int i = 0; i < 160; i++)
|
||||
{
|
||||
have_pixel = false;
|
||||
for (int j = 0; j < SL_sprites_index; j++)
|
||||
sprite_present_list[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = (SL_sprites_index - 1); i >= 0; i--)
|
||||
{
|
||||
if ((SL_sprites_ordered[i * 4] > 0) && ((SL_sprites_ordered[i * 4] - 8) < 160))
|
||||
{
|
||||
if ((i >= (SL_sprites_ordered[j * 4] - 8)) &&
|
||||
(i < SL_sprites_ordered[j * 4]) &&
|
||||
!have_pixel)
|
||||
low_bound = (SL_sprites_ordered[i * 4] >= 8) ? 0 : (8 - SL_sprites_ordered[i * 4]);
|
||||
high_bound = ((SL_sprites_ordered[i * 4] - 8) <= 152) ? 7 : (159 - (SL_sprites_ordered[i * 4] - 8));
|
||||
|
||||
for (int j = low_bound; j <= high_bound; j++)
|
||||
{
|
||||
// we can use the current sprite, so pick out a pixel for it
|
||||
int t_index = i - (SL_sprites_ordered[j * 4] - 8);
|
||||
t_index = 7 - j;
|
||||
|
||||
t_index = 7 - t_index;
|
||||
|
||||
sprite_data[0] = (byte)((SL_sprites_ordered[j * 4 + 1] >> t_index) & 1);
|
||||
sprite_data[1] = (byte)(((SL_sprites_ordered[j * 4 + 2] >> t_index) & 1) << 1);
|
||||
sprite_data[0] = (byte)((SL_sprites_ordered[i * 4 + 1] >> t_index) & 1);
|
||||
sprite_data[1] = (byte)(((SL_sprites_ordered[i * 4 + 2] >> t_index) & 1) << 1);
|
||||
|
||||
s_pixel = (byte)(sprite_data[0] + sprite_data[1]);
|
||||
sprite_attr = (byte)SL_sprites_ordered[j * 4 + 3];
|
||||
sprite_attr = (byte)SL_sprites_ordered[i * 4 + 3];
|
||||
|
||||
// pixel color of 0 is transparent, so if this is the case we don't have a pixel
|
||||
if (s_pixel != 0)
|
||||
{
|
||||
have_pixel = true;
|
||||
sprite_present_list[SL_sprites_ordered[i * 4] - (8 - j)] = 1;
|
||||
sprite_pixel_list[SL_sprites_ordered[i * 4] - (8 - j)] = s_pixel;
|
||||
sprite_attr_list[SL_sprites_ordered[i * 4] - (8 - j)] = sprite_attr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (have_pixel)
|
||||
{
|
||||
sprite_present_list[i] = 1;
|
||||
sprite_pixel_list[i] = s_pixel;
|
||||
sprite_attr_list[i] = sprite_attr;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite_present_list[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1333,8 +1333,40 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
fetch_sprite = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void DMA_tick()
|
||||
{
|
||||
if (DMA_clock >= 4)
|
||||
{
|
||||
DMA_OAM_access = false;
|
||||
if ((DMA_clock % 4) == 1)
|
||||
{
|
||||
// the cpu can't access memory during this time, but we still need the ppu to be able to.
|
||||
DMA_start = false;
|
||||
// Gekkio reports that A14 being high on DMA transfers always represent WRAM accesses
|
||||
// So transfers nominally from higher memory areas are actually still from there (i.e. FF -> DF)
|
||||
byte DMA_actual = DMA_addr;
|
||||
if (DMA_addr > 0xDF) { DMA_actual &= 0xDF; }
|
||||
DMA_byte = Core.ReadMemory((ushort)((DMA_actual << 8) + DMA_inc));
|
||||
DMA_start = true;
|
||||
}
|
||||
else if ((DMA_clock % 4) == 3)
|
||||
{
|
||||
Core.OAM[DMA_inc] = DMA_byte;
|
||||
|
||||
if (DMA_inc < (0xA0 - 1)) { DMA_inc++; }
|
||||
}
|
||||
}
|
||||
|
||||
DMA_clock++;
|
||||
|
||||
if (DMA_clock == 648)
|
||||
{
|
||||
DMA_start = false;
|
||||
DMA_OAM_access = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void process_sprite()
|
||||
|
@ -1377,60 +1409,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
if (SL_sprites[sl_use_index * 4 + 3].Bit(5))
|
||||
{
|
||||
int b0, b1, b2, b3, b4, b5, b6, b7 = 0;
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
b0 = (sprite_sel[i] & 0x01) << 7;
|
||||
b1 = (sprite_sel[i] & 0x02) << 5;
|
||||
b2 = (sprite_sel[i] & 0x04) << 3;
|
||||
b3 = (sprite_sel[i] & 0x08) << 1;
|
||||
b4 = (sprite_sel[i] & 0x10) >> 1;
|
||||
b5 = (sprite_sel[i] & 0x20) >> 3;
|
||||
b6 = (sprite_sel[i] & 0x40) >> 5;
|
||||
b7 = (sprite_sel[i] & 0x80) >> 7;
|
||||
|
||||
sprite_sel[i] = (byte)(b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7);
|
||||
sprite_sel[i] = (byte)(((sprite_sel[i] & 0x01) << 7) |
|
||||
((sprite_sel[i] & 0x02) << 5) |
|
||||
((sprite_sel[i] & 0x04) << 3) |
|
||||
((sprite_sel[i] & 0x08) << 1) |
|
||||
((sprite_sel[i] & 0x10) >> 1) |
|
||||
((sprite_sel[i] & 0x20) >> 3) |
|
||||
((sprite_sel[i] & 0x40) >> 5) |
|
||||
((sprite_sel[i] & 0x80) >> 7));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// normal DMA moves twice as fast in double speed mode on GBC
|
||||
// So give it it's own function so we can seperate it from PPU tick
|
||||
public override void DMA_tick()
|
||||
{
|
||||
if (DMA_clock >= 4)
|
||||
{
|
||||
DMA_OAM_access = false;
|
||||
if ((DMA_clock % 4) == 1)
|
||||
{
|
||||
// the cpu can't access memory during this time, but we still need the ppu to be able to.
|
||||
DMA_start = false;
|
||||
// Gekkio reports that A14 being high on DMA transfers always represent WRAM accesses
|
||||
// So transfers nominally from higher memory areas are actually still from there (i.e. FF -> DF)
|
||||
byte DMA_actual = DMA_addr;
|
||||
if (DMA_addr > 0xDF) { DMA_actual &= 0xDF; }
|
||||
DMA_byte = Core.ReadMemory((ushort)((DMA_actual << 8) + DMA_inc));
|
||||
DMA_start = true;
|
||||
}
|
||||
else if ((DMA_clock % 4) == 3)
|
||||
{
|
||||
Core.OAM[DMA_inc] = DMA_byte;
|
||||
|
||||
if (DMA_inc < (0xA0 - 1)) { DMA_inc++; }
|
||||
}
|
||||
}
|
||||
|
||||
DMA_clock++;
|
||||
|
||||
if (DMA_clock == 648)
|
||||
{
|
||||
DMA_start = false;
|
||||
DMA_OAM_access = true;
|
||||
}
|
||||
}
|
||||
|
||||
// order sprites according to x coordinate
|
||||
// note that for sprites of equal x coordinate, priority goes to first on the list
|
||||
public override void reorder_and_assemble_sprites()
|
||||
{
|
||||
sprite_ordered_index = 0;
|
||||
|
@ -1447,48 +1439,44 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
sprite_ordered_index++;
|
||||
}
|
||||
|
||||
bool have_pixel = false;
|
||||
byte s_pixel = 0;
|
||||
byte sprite_attr = 0;
|
||||
|
||||
int low_bound = 0;
|
||||
int high_bound = 0;
|
||||
int t_index = 0;
|
||||
|
||||
for (int i = 0; i < 160; i++)
|
||||
{
|
||||
have_pixel = false;
|
||||
for (int j = 0; j < SL_sprites_index; j++)
|
||||
sprite_present_list[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = (SL_sprites_index - 1); i >= 0; i--)
|
||||
{
|
||||
if ((SL_sprites_ordered[i * 4] > 0) && ((SL_sprites_ordered[i * 4] - 8) < 160))
|
||||
{
|
||||
if ((i >= (SL_sprites_ordered[j * 4] - 8)) &&
|
||||
(i < SL_sprites_ordered[j * 4]) &&
|
||||
!have_pixel)
|
||||
low_bound = (SL_sprites_ordered[i * 4] >= 8) ? 0 : (8 - SL_sprites_ordered[i * 4]);
|
||||
high_bound = ((SL_sprites_ordered[i * 4] - 8) <= 152) ? 7 : (159 - (SL_sprites_ordered[i * 4] - 8));
|
||||
|
||||
for (int j = low_bound; j <= high_bound; j++)
|
||||
{
|
||||
// we can use the current sprite, so pick out a pixel for it
|
||||
int t_index = i - (SL_sprites_ordered[j * 4] - 8);
|
||||
t_index = 7 - j;
|
||||
|
||||
t_index = 7 - t_index;
|
||||
|
||||
sprite_data[0] = (byte)((SL_sprites_ordered[j * 4 + 1] >> t_index) & 1);
|
||||
sprite_data[1] = (byte)(((SL_sprites_ordered[j * 4 + 2] >> t_index) & 1) << 1);
|
||||
sprite_data[0] = (byte)((SL_sprites_ordered[i * 4 + 1] >> t_index) & 1);
|
||||
sprite_data[1] = (byte)(((SL_sprites_ordered[i * 4 + 2] >> t_index) & 1) << 1);
|
||||
|
||||
s_pixel = (byte)(sprite_data[0] + sprite_data[1]);
|
||||
sprite_attr = (byte)SL_sprites_ordered[j * 4 + 3];
|
||||
sprite_attr = (byte)SL_sprites_ordered[i * 4 + 3];
|
||||
|
||||
// pixel color of 0 is transparent, so if this is the case we don't have a pixel
|
||||
if (s_pixel != 0)
|
||||
{
|
||||
have_pixel = true;
|
||||
sprite_present_list[SL_sprites_ordered[i * 4] - (8 - j)] = 1;
|
||||
sprite_pixel_list[SL_sprites_ordered[i * 4] - (8 - j)] = s_pixel;
|
||||
sprite_attr_list[SL_sprites_ordered[i * 4] - (8 - j)] = sprite_attr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (have_pixel)
|
||||
{
|
||||
sprite_present_list[i] = 1;
|
||||
sprite_pixel_list[i] = s_pixel;
|
||||
sprite_attr_list[i] = sprite_attr;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite_present_list[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -984,6 +984,39 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
|
||||
public override void DMA_tick()
|
||||
{
|
||||
if (DMA_clock >= 4)
|
||||
{
|
||||
DMA_OAM_access = false;
|
||||
if ((DMA_clock % 4) == 1)
|
||||
{
|
||||
// the cpu can't access memory during this time, but we still need the ppu to be able to.
|
||||
DMA_start = false;
|
||||
// Gekkio reports that A14 being high on DMA transfers always represent WRAM accesses
|
||||
// So transfers nominally from higher memory areas are actually still from there (i.e. FF -> DF)
|
||||
byte DMA_actual = DMA_addr;
|
||||
if (DMA_addr > 0xDF) { DMA_actual &= 0xDF; }
|
||||
DMA_byte = Core.ReadMemory((ushort)((DMA_actual << 8) + DMA_inc));
|
||||
DMA_start = true;
|
||||
}
|
||||
else if ((DMA_clock % 4) == 3)
|
||||
{
|
||||
Core.OAM[DMA_inc] = DMA_byte;
|
||||
|
||||
if (DMA_inc < (0xA0 - 1)) { DMA_inc++; }
|
||||
}
|
||||
}
|
||||
|
||||
DMA_clock++;
|
||||
|
||||
if (DMA_clock == 648)
|
||||
{
|
||||
DMA_start = false;
|
||||
DMA_OAM_access = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void process_sprite()
|
||||
{
|
||||
int y;
|
||||
|
@ -1023,58 +1056,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
|
||||
if (SL_sprites[sl_use_index * 4 + 3].Bit(5))
|
||||
{
|
||||
int b0, b1, b2, b3, b4, b5, b6, b7 = 0;
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
b0 = (sprite_sel[i] & 0x01) << 7;
|
||||
b1 = (sprite_sel[i] & 0x02) << 5;
|
||||
b2 = (sprite_sel[i] & 0x04) << 3;
|
||||
b3 = (sprite_sel[i] & 0x08) << 1;
|
||||
b4 = (sprite_sel[i] & 0x10) >> 1;
|
||||
b5 = (sprite_sel[i] & 0x20) >> 3;
|
||||
b6 = (sprite_sel[i] & 0x40) >> 5;
|
||||
b7 = (sprite_sel[i] & 0x80) >> 7;
|
||||
|
||||
sprite_sel[i] = (byte)(b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7);
|
||||
sprite_sel[i] = (byte)(((sprite_sel[i] & 0x01) << 7) |
|
||||
((sprite_sel[i] & 0x02) << 5) |
|
||||
((sprite_sel[i] & 0x04) << 3) |
|
||||
((sprite_sel[i] & 0x08) << 1) |
|
||||
((sprite_sel[i] & 0x10) >> 1) |
|
||||
((sprite_sel[i] & 0x20) >> 3) |
|
||||
((sprite_sel[i] & 0x40) >> 5) |
|
||||
((sprite_sel[i] & 0x80) >> 7));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// normal DMA moves twice as fast in double speed mode on GBC
|
||||
// So give it it's own function so we can seperate it from PPU tick
|
||||
public override void DMA_tick()
|
||||
{
|
||||
if (DMA_clock >= 4)
|
||||
{
|
||||
DMA_OAM_access = false;
|
||||
if ((DMA_clock % 4) == 1)
|
||||
{
|
||||
// the cpu can't access memory during this time, but we still need the ppu to be able to.
|
||||
DMA_start = false;
|
||||
// Gekkio reports that A14 being high on DMA transfers always represent WRAM accesses
|
||||
// So transfers nominally from higher memory areas are actually still from there (i.e. FF -> DF)
|
||||
byte DMA_actual = DMA_addr;
|
||||
if (DMA_addr > 0xDF) { DMA_actual &= 0xDF; }
|
||||
DMA_byte = Core.ReadMemory((ushort)((DMA_actual << 8) + DMA_inc));
|
||||
DMA_start = true;
|
||||
}
|
||||
else if ((DMA_clock % 4) == 3)
|
||||
{
|
||||
Core.OAM[DMA_inc] = DMA_byte;
|
||||
|
||||
if (DMA_inc < (0xA0 - 1)) { DMA_inc++; }
|
||||
}
|
||||
}
|
||||
|
||||
DMA_clock++;
|
||||
|
||||
if (DMA_clock == 648)
|
||||
{
|
||||
DMA_start = false;
|
||||
DMA_OAM_access = true;
|
||||
}
|
||||
}
|
||||
|
||||
// order sprites according to x coordinate
|
||||
// note that for sprites of equal x coordinate, priority goes to first on the list
|
||||
public override void reorder_and_assemble_sprites()
|
||||
|
@ -1098,48 +1093,44 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|||
}
|
||||
}
|
||||
|
||||
bool have_pixel = false;
|
||||
byte s_pixel = 0;
|
||||
byte sprite_attr = 0;
|
||||
|
||||
int low_bound = 0;
|
||||
int high_bound = 0;
|
||||
int t_index = 0;
|
||||
|
||||
for (int i = 0; i < 160; i++)
|
||||
{
|
||||
have_pixel = false;
|
||||
for (int j = 0; j < SL_sprites_index; j++)
|
||||
sprite_present_list[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = (SL_sprites_index - 1); i >= 0; i--)
|
||||
{
|
||||
if ((SL_sprites_ordered[i * 4] > 0) && ((SL_sprites_ordered[i * 4] - 8) < 160))
|
||||
{
|
||||
if ((i >= (SL_sprites_ordered[j * 4] - 8)) &&
|
||||
(i < SL_sprites_ordered[j * 4]) &&
|
||||
!have_pixel)
|
||||
low_bound = (SL_sprites_ordered[i * 4] >= 8) ? 0 : (8 - SL_sprites_ordered[i * 4]);
|
||||
high_bound = ((SL_sprites_ordered[i * 4] - 8) <= 152) ? 7 : (159 - (SL_sprites_ordered[i * 4] - 8));
|
||||
|
||||
for (int j = low_bound; j <= high_bound; j++)
|
||||
{
|
||||
// we can use the current sprite, so pick out a pixel for it
|
||||
int t_index = i - (SL_sprites_ordered[j * 4] - 8);
|
||||
t_index = 7 - j;
|
||||
|
||||
t_index = 7 - t_index;
|
||||
|
||||
sprite_data[0] = (byte)((SL_sprites_ordered[j * 4 + 1] >> t_index) & 1);
|
||||
sprite_data[1] = (byte)(((SL_sprites_ordered[j * 4 + 2] >> t_index) & 1) << 1);
|
||||
sprite_data[0] = (byte)((SL_sprites_ordered[i * 4 + 1] >> t_index) & 1);
|
||||
sprite_data[1] = (byte)(((SL_sprites_ordered[i * 4 + 2] >> t_index) & 1) << 1);
|
||||
|
||||
s_pixel = (byte)(sprite_data[0] + sprite_data[1]);
|
||||
sprite_attr = (byte)SL_sprites_ordered[j * 4 + 3];
|
||||
sprite_attr = (byte)SL_sprites_ordered[i * 4 + 3];
|
||||
|
||||
// pixel color of 0 is transparent, so if this is the case we don't have a pixel
|
||||
if (s_pixel != 0)
|
||||
{
|
||||
have_pixel = true;
|
||||
sprite_present_list[SL_sprites_ordered[i * 4] - (8 - j)] = 1;
|
||||
sprite_pixel_list[SL_sprites_ordered[i * 4] - (8 - j)] = s_pixel;
|
||||
sprite_attr_list[SL_sprites_ordered[i * 4] - (8 - j)] = sprite_attr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (have_pixel)
|
||||
{
|
||||
sprite_present_list[i] = 1;
|
||||
sprite_pixel_list[i] = s_pixel;
|
||||
sprite_attr_list[i] = sprite_attr;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite_present_list[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue