diff --git a/apu/apu.cpp b/apu/apu.cpp index e5143ff3..5dbd9319 100644 --- a/apu/apu.cpp +++ b/apu/apu.cpp @@ -180,15 +180,17 @@ #include "apu.h" #include "snapshot.h" #include "display.h" -#include "resampler.h" +#include "linear_resampler.h" +#include "hermite_resampler.h" #define APU_DEFAULT_INPUT_RATE 32000 #define APU_MINIMUM_SAMPLE_COUNT 512 #define APU_MINIMUM_SAMPLE_BLOCK 128 -#define APU_NUMERATOR_NTSC 5632 -#define APU_DENOMINATOR_NTSC 118125 -#define APU_NUMERATOR_PAL 102400 -#define APU_DENOMINATOR_PAL 2128137 +#define APU_NUMERATOR_NTSC 15664 +#define APU_DENOMINATOR_NTSC 328125 +#define APU_NUMERATOR_PAL 34176 +#define APU_DENOMINATOR_PAL 709379 +#define APU_DEFAULT_RESAMPLER HermiteResampler SNES_SPC *spc_core = NULL; @@ -224,8 +226,12 @@ namespace spc static int32 reference_time; static uint32 remainder; - static const int32 timing_hack_numerator = SNES_SPC::tempo_unit; - static int32 timing_hack_denominator = SNES_SPC::tempo_unit; + static const int timing_hack_numerator = SNES_SPC::tempo_unit; + static int timing_hack_denominator = SNES_SPC::tempo_unit; + /* Set these to NTSC for now. Will change to PAL in S9xAPUTimingSetSpeedup + if necessary on game load. */ + static uint32 ratio_numerator = APU_NUMERATOR_NTSC; + static uint32 ratio_denominator = APU_DENOMINATOR_NTSC; } static void EightBitize (uint8 *, int); @@ -445,7 +451,7 @@ bool8 S9xInitSound (int buffer_ms, int lag_ms) arguments. Use 2x in the resampler for buffer leveling with SoundSync */ if (!spc::resampler) { - spc::resampler = new Resampler(spc::buffer_size >> (Settings.SoundSync ? 0 : 1)); + spc::resampler = new APU_DEFAULT_RESAMPLER(spc::buffer_size >> (Settings.SoundSync ? 0 : 1)); if (!spc::resampler) { delete[] spc::landing_buffer; @@ -534,22 +540,14 @@ void S9xDeinitAPU (void) static inline int S9xAPUGetClock (int32 cpucycles) { - if (Settings.PAL) - return ((int) floor(((double) APU_NUMERATOR_PAL * spc::timing_hack_numerator * (cpucycles - spc::reference_time) + spc::remainder) / - ((double) APU_DENOMINATOR_PAL * spc::timing_hack_denominator))); - else - return (APU_NUMERATOR_NTSC * spc::timing_hack_numerator * (cpucycles - spc::reference_time) + spc::remainder) / - (APU_DENOMINATOR_NTSC * spc::timing_hack_denominator); + return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) / + spc::ratio_denominator; } static inline int S9xAPUGetClockRemainder (int32 cpucycles) { - if (Settings.PAL) - return ((int) fmod (((double) APU_NUMERATOR_PAL * spc::timing_hack_numerator * (cpucycles - spc::reference_time) + spc::remainder), - ((double) APU_DENOMINATOR_PAL * spc::timing_hack_denominator))); - else - return (APU_NUMERATOR_NTSC * spc::timing_hack_numerator * (cpucycles - spc::reference_time) + spc::remainder) % - (APU_DENOMINATOR_NTSC * spc::timing_hack_denominator); + return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) % + spc::ratio_denominator; } uint8 S9xAPUReadPort (int port) @@ -590,9 +588,12 @@ void S9xAPUTimingSetSpeedup (int ticks) if (ticks != 0) printf("APU speedup hack: %d\n", ticks); - spc_core->set_tempo(SNES_SPC::tempo_unit - ticks); - spc::timing_hack_denominator = SNES_SPC::tempo_unit - ticks; + spc_core->set_tempo(spc::timing_hack_denominator); + + spc::ratio_numerator = Settings.PAL ? APU_NUMERATOR_PAL : APU_NUMERATOR_NTSC; + spc::ratio_denominator = Settings.PAL ? APU_DENOMINATOR_PAL : APU_DENOMINATOR_NTSC; + spc::ratio_denominator = spc::ratio_denominator * spc::timing_hack_denominator / spc::timing_hack_numerator; UpdatePlaybackRate(); } diff --git a/apu/hermite_resampler.h b/apu/hermite_resampler.h new file mode 100644 index 00000000..30ee1032 --- /dev/null +++ b/apu/hermite_resampler.h @@ -0,0 +1,144 @@ +/* Simple resampler based on bsnes's ruby audio library */ + +#ifndef __HERMITE_RESAMPLER_H +#define __HERMITE_RESAMPLER_H + +#include "resampler.h" + +#undef CLAMP +#undef SHORT_CLAMP +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) +#define SHORT_CLAMP(n) ((short) CLAMP((n), -32768, 32767)) + +class HermiteResampler : public Resampler +{ + protected: + + double r_step; + double r_frac; + int r_left[4], r_right[4]; + + double + hermite (double mu1, double a, double b, double c, double d) + { + const double tension = 0.0; //-1 = low, 0 = normal, 1 = high + const double bias = 0.0; //-1 = left, 0 = even, 1 = right + + double mu2, mu3, m0, m1, a0, a1, a2, a3; + + mu2 = mu1 * mu1; + mu3 = mu2 * mu1; + + m0 = (b - a) * (1 + bias) * (1 - tension) / 2; + m0 += (c - b) * (1 - bias) * (1 - tension) / 2; + m1 = (c - b) * (1 + bias) * (1 - tension) / 2; + m1 += (d - c) * (1 - bias) * (1 - tension) / 2; + + a0 = +2 * mu3 - 3 * mu2 + 1; + a1 = mu3 - 2 * mu2 + mu1; + a2 = mu3 - mu2; + a3 = -2 * mu3 + 3 * mu2; + + return (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c); + } + + public: + HermiteResampler (int num_samples) : Resampler (num_samples) + { + clear (); + } + + ~HermiteResampler () + { + } + + void + time_ratio (double ratio) + { + r_step = ratio; + clear (); + } + + void + clear (void) + { + ring_buffer::clear (); + r_frac = 1.0; + r_left [0] = r_left [1] = r_left [2] = r_left [3] = 0; + r_right[0] = r_right[1] = r_right[2] = r_right[3] = 0; + } + + void + read (short *data, int num_samples) + { + int i_position = start >> 1; + short *internal_buffer = (short *) buffer; + int o_position = 0; + int consumed = 0; + + while (o_position < num_samples && consumed < buffer_size) + { + int s_left = internal_buffer[i_position]; + int s_right = internal_buffer[i_position + 1]; + int max_samples = buffer_size >> 1; + const double margin_of_error = 1.0e-10; + + if (fabs(r_step - 1.0) < margin_of_error) + { + data[o_position] = (short) s_left; + data[o_position + 1] = (short) s_right; + + o_position += 2; + i_position += 2; + if (i_position >= max_samples) + i_position -= max_samples; + consumed += 2; + + continue; + } + + while (r_frac <= 1.0 && o_position < num_samples) + { + data[o_position] = SHORT_CLAMP (hermite (r_frac, r_left [0], r_left [1], r_left [2], r_left [3])); + data[o_position + 1] = SHORT_CLAMP (hermite (r_frac, r_right[0], r_right[1], r_right[2], r_right[3])); + + o_position += 2; + + r_frac += r_step; + } + + if (r_frac > 1.0) + { + r_left [0] = r_left [1]; + r_left [1] = r_left [2]; + r_left [2] = r_left [3]; + r_left [3] = s_left; + + r_right[0] = r_right[1]; + r_right[1] = r_right[2]; + r_right[2] = r_right[3]; + r_right[3] = s_right; + + r_frac -= 1.0; + + i_position += 2; + if (i_position >= max_samples) + i_position -= max_samples; + consumed += 2; + } + } + + size -= consumed << 1; + start += consumed << 1; + if (start >= buffer_size) + start -= buffer_size; + } + + inline int + avail (void) + { + return (int) floor (((size >> 2) - r_frac) / r_step) * 2; + } +}; + +#endif /* __HERMITE_RESAMPLER_H */ diff --git a/apu/linear_resampler.h b/apu/linear_resampler.h new file mode 100644 index 00000000..35789db1 --- /dev/null +++ b/apu/linear_resampler.h @@ -0,0 +1,115 @@ +/* Simple fixed-point linear resampler by BearOso*/ + +#ifndef __LINEAR_RESAMPLER_H +#define __LINEAR_RESAMPLER_H + +#include "resampler.h" +#include "snes9x.h" + +static const int f_prec = 15; +static const uint32 f__one = (1 << f_prec); + +#define lerp(t, a, b) (((((b) - (a)) * (t)) >> f_prec) + (a)) + +class LinearResampler : public Resampler +{ + protected: + uint32 f__r_step; + uint32 f__inv_r_step; + uint32 f__r_frac; + int r_left, r_right; + + public: + LinearResampler (int num_samples) : Resampler (num_samples) + { + f__r_frac = 0; + } + + ~LinearResampler () + { + } + + void + time_ratio (double ratio) + { + if (ratio == 0.0) + ratio = 1.0; + f__r_step = (uint32) (ratio * f__one); + f__inv_r_step = (uint32) (f__one / ratio); + clear (); + } + + void + clear (void) + { + ring_buffer::clear (); + f__r_frac = 0; + r_left = 0; + r_right = 0; + } + + void + read (short *data, int num_samples) + { + int i_position = start >> 1; + short *internal_buffer = (short *) buffer; + int o_position = 0; + int consumed = 0; + int max_samples = (buffer_size >> 1); + + while (o_position < num_samples && consumed < buffer_size) + { + if (f__r_step == f__one) + { + data[o_position] = internal_buffer[i_position]; + data[o_position + 1] = internal_buffer[i_position + 1]; + + o_position += 2; + i_position += 2; + if (i_position >= max_samples) + i_position -= max_samples; + consumed += 2; + + continue; + } + + while (f__r_frac <= f__one && o_position < num_samples) + { + data[o_position] = lerp (f__r_frac, + r_left, + internal_buffer[i_position]); + data[o_position + 1] = lerp (f__r_frac, + r_right, + internal_buffer[i_position + 1]); + + o_position += 2; + + f__r_frac += f__r_step; + } + + if (f__r_frac > f__one) + { + f__r_frac -= f__one; + r_left = internal_buffer[i_position]; + r_right = internal_buffer[i_position + 1]; + i_position += 2; + if (i_position >= max_samples) + i_position -= max_samples; + consumed += 2; + } + } + + size -= consumed << 1; + start += consumed << 1; + if (start >= buffer_size) + start -= buffer_size; + } + + inline int + avail (void) + { + return (((size >> 2) * f__inv_r_step) - ((f__r_frac * f__inv_r_step) >> f_prec)) >> (f_prec - 1); + } +}; + +#endif /* __LINEAR_RESAMPLER_H */ diff --git a/apu/resampler.h b/apu/resampler.h index 51a32266..2e62addb 100644 --- a/apu/resampler.h +++ b/apu/resampler.h @@ -5,158 +5,56 @@ #include "ring_buffer.h" -#undef MIN -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -#undef CLAMP -#undef short_clamp -#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) -#define short_clamp(n) ((short) CLAMP((n), -32768, 32767)) - class Resampler : public ring_buffer { - protected: - - double r_step; - double r_frac; - int r_left[4], r_right[4]; - - double - hermite (double mu1, double a, double b, double c, double d) - { - const double tension = 0.0; //-1 = low, 0 = normal, 1 = high - const double bias = 0.0; //-1 = left, 0 = even, 1 = right - - double mu2, mu3, m0, m1, a0, a1, a2, a3; - - mu2 = mu1 * mu1; - mu3 = mu2 * mu1; - - m0 = (b - a) * (1 + bias) * (1 - tension) / 2; - m0 += (c - b) * (1 - bias) * (1 - tension) / 2; - m1 = (c - b) * (1 + bias) * (1 - tension) / 2; - m1 += (d - c) * (1 - bias) * (1 - tension) / 2; - - a0 = +2 * mu3 - 3 * mu2 + 1; - a1 = mu3 - 2 * mu2 + mu1; - a2 = mu3 - mu2; - a3 = -2 * mu3 + 3 * mu2; - - return (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c); - } - public: + virtual void clear (void) = 0; + virtual void time_ratio (double) = 0; + virtual void read (short *, int) = 0; + virtual int avail (void) = 0; + Resampler (int num_samples) : ring_buffer (num_samples << 1) { - r_frac = 0.0; } ~Resampler () { } - void - time_ratio (double ratio) - { - r_step = ratio; - clear (); - } - - void - clear (void) - { - ring_buffer::clear (); - r_frac = 0; - r_left [0] = r_left [1] = r_left [2] = r_left [3] = 0; - r_right[0] = r_right[1] = r_right[2] = r_right[3] = 0; - } - - void - read (short *data, int num_samples) - { - int i_position = start >> 1; - short *internal_buffer = (short *) buffer; - int o_position = 0; - int consumed = 0; - - while (o_position < num_samples && consumed < buffer_size) - { - int s_left = internal_buffer[i_position]; - int s_right = internal_buffer[i_position + 1]; - const double margin_of_error = 1.0e-10; - - if (fabs(r_step - 1.0) < margin_of_error) - { - data[o_position] = (short) s_left; - data[o_position + 1] = (short) s_right; - - o_position += 2; - i_position = (i_position + 2) % (buffer_size >> 1); - consumed += 2; - - continue; - } - - r_left [0] = r_left [1]; - r_left [1] = r_left [2]; - r_left [2] = r_left [3]; - r_left [3] = s_left; - - r_right[0] = r_right[1]; - r_right[1] = r_right[2]; - r_right[2] = r_right[3]; - r_right[3] = s_right; - - while (r_frac <= 1.0 && o_position < num_samples) - { - data[o_position] = short_clamp (hermite (r_frac, r_left [0], r_left [1], r_left [2], r_left [3])); - data[o_position + 1] = short_clamp (hermite (r_frac, r_right[0], r_right[1], r_right[2], r_right[3])); - - o_position += 2; - - r_frac += r_step; - } - - if (r_frac > 1.0) - { - r_frac -= 1.0; - i_position = (i_position + 2) % (buffer_size >> 1); - consumed += 2; - } - } - - size -= consumed << 1; - start = (start + (consumed << 1)) % buffer_size; - } - - bool + inline bool push (short *src, int num_samples) { if (max_write () < num_samples) return false; - ring_buffer::push ((unsigned char *) src, num_samples << 1); + !num_samples || ring_buffer::push ((unsigned char *) src, num_samples << 1); return true; } - int + inline int + space_empty (void) + { + return buffer_size - size; + } + + inline int + space_filled (void) + { + return size; + } + + inline int max_write (void) { return space_empty () >> 1; } - void + inline void resize (int num_samples) { ring_buffer::resize (num_samples << 1); } - - int - avail (void) - { - return (int) floor (((size >> 2) - r_frac) / r_step) * 2; - } }; #endif /* __RESAMPLER_H */ diff --git a/cpu.cpp b/cpu.cpp index 91c986cf..3e249cc5 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -207,22 +207,6 @@ static void S9xResetCPU (void) static void S9xSoftResetCPU (void) { - Registers.PBPC = 0; - Registers.PB = 0; - Registers.PCw = S9xGetWord(0xfffc); - OpenBus = Registers.PCh; - Registers.D.W = 0; - Registers.DB = 0; - Registers.SH = 1; - Registers.SL -= 3; - Registers.XH = 0; - Registers.YH = 0; - - ICPU.ShiftedPB = 0; - ICPU.ShiftedDB = 0; - SetFlags(MemoryFlag | IndexFlag | IRQ | Emulation); - ClearFlags(Decimal); - CPU.Cycles = 182; // Or 188. This is the cycle count just after the jump to the Reset Vector. CPU.PrevCycles = -1; CPU.V_Counter = 0; @@ -248,6 +232,22 @@ static void S9xSoftResetCPU (void) CPU.AutoSaveTimer = 0; CPU.SRAMModified = FALSE; + Registers.PBPC = 0; + Registers.PB = 0; + Registers.PCw = S9xGetWord(0xfffc); + OpenBus = Registers.PCh; + Registers.D.W = 0; + Registers.DB = 0; + Registers.SH = 1; + Registers.SL -= 3; + Registers.XH = 0; + Registers.YH = 0; + + ICPU.ShiftedPB = 0; + ICPU.ShiftedDB = 0; + SetFlags(MemoryFlag | IndexFlag | IRQ | Emulation); + ClearFlags(Decimal); + Timings.InterlaceField = FALSE; Timings.H_Max = Timings.H_Max_Master; Timings.V_Max = Timings.V_Max_Master; diff --git a/cpuexec.cpp b/cpuexec.cpp index d7f22db9..1b9d892b 100644 --- a/cpuexec.cpp +++ b/cpuexec.cpp @@ -307,8 +307,10 @@ void S9xMainLoop (void) if (SA1.Executing) S9xSA1MainLoop(); + #if (S9X_ACCURACY_LEVEL <= 2) while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); + #endif } S9xPackStatus(); @@ -355,10 +357,29 @@ void S9xClearIRQ (uint32 source) void S9xDoHEventProcessing (void) { +#ifdef DEBUGGER + static char eventname[13][32] = + { + "", + "HC_HBLANK_START_EVENT", + "HC_IRQ_1_3_EVENT ", + "HC_HDMA_START_EVENT ", + "HC_IRQ_3_5_EVENT ", + "HC_HCOUNTER_MAX_EVENT", + "HC_IRQ_5_7_EVENT ", + "HC_HDMA_INIT_EVENT ", + "HC_IRQ_7_9_EVENT ", + "HC_RENDER_EVENT ", + "HC_IRQ_9_A_EVENT ", + "HC_WRAM_REFRESH_EVENT", + "HC_IRQ_A_1_EVENT " + }; +#endif + #ifdef DEBUGGER if (Settings.TraceHCEvent) - S9xTraceFormattedMessage("--- HC event processing (%02d) expected HC:%04d executed HC:%04d", - CPU.WhichEvent, CPU.NextEvent, CPU.Cycles); + S9xTraceFormattedMessage("--- HC event processing (%s) expected HC:%04d executed HC:%04d", + eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles); #endif #ifdef CPU_SHUTDOWN @@ -366,13 +387,16 @@ void S9xDoHEventProcessing (void) #endif switch (CPU.WhichEvent) - { + { case HC_HBLANK_START_EVENT: S9xCheckMissingHTimerPosition(Timings.HBlankStart); - + S9xReschedule(); break; case HC_HDMA_START_EVENT: + S9xCheckMissingHTimerPosition(Timings.HDMAStart); + S9xReschedule(); + if (PPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight) { #ifdef DEBUGGER @@ -381,8 +405,6 @@ void S9xDoHEventProcessing (void) PPU.HDMA = S9xDoHDMA(PPU.HDMA); } - S9xCheckMissingHTimerPosition(Timings.HDMAStart); - break; case HC_HCOUNTER_MAX_EVENT: @@ -470,7 +492,7 @@ void S9xDoHEventProcessing (void) missing.dma_this_frame = 0; #endif IPPU.MaxBrightness = PPU.Brightness; - PPU.ForcedBlanking = (Memory.FillRAM [0x2100] >> 7) & 1; + PPU.ForcedBlanking = (Memory.FillRAM[0x2100] >> 7) & 1; if (!PPU.ForcedBlanking) { @@ -511,14 +533,21 @@ void S9xDoHEventProcessing (void) S9xStartScreenRefresh(); CPU.NextEvent = -1; + S9xReschedule(); break; case HC_HDMA_INIT_EVENT: - if (CPU.V_Counter == 0) - S9xStartHDMA(); - S9xCheckMissingHTimerPosition(Timings.HDMAInit); + S9xReschedule(); + + if (CPU.V_Counter == 0) + { + #ifdef DEBUGGER + S9xTraceFormattedMessage("*** HDMA Init HC:%04d, Channel:%02x", CPU.Cycles, PPU.HDMA); + #endif + S9xStartHDMA(); + } break; @@ -527,6 +556,7 @@ void S9xDoHEventProcessing (void) RenderLine((uint8) (CPU.V_Counter - FIRST_VISIBLE_LINE)); S9xCheckMissingHTimerPosition(Timings.RenderPos); + S9xReschedule(); break; @@ -534,10 +564,12 @@ void S9xDoHEventProcessing (void) #ifdef DEBUGGER S9xTraceFormattedMessage("*** WRAM Refresh HC:%04d", CPU.Cycles); #endif + S9xCheckMissingHTimerHalt(Timings.WRAMRefreshPos, SNES_WRAM_REFRESH_CYCLES); CPU.Cycles += SNES_WRAM_REFRESH_CYCLES; S9xCheckMissingHTimerPosition(Timings.WRAMRefreshPos); + S9xReschedule(); break; @@ -553,13 +585,13 @@ void S9xDoHEventProcessing (void) if (PPU.VTimerEnabled && (CPU.V_Counter == PPU.VTimerPosition)) S9xSetIRQ(PPU_IRQ_SOURCE); + S9xReschedule(); break; - } - - S9xReschedule(); + } #ifdef DEBUGGER if (Settings.TraceHCEvent) - S9xTraceFormattedMessage("--- HC event rescheduled (%02d) expected HC:%04d", CPU.WhichEvent, CPU.NextEvent); + S9xTraceFormattedMessage("--- HC event rescheduled (%s) expected HC:%04d current HC:%04d", + eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles); #endif } diff --git a/cpuops.cpp b/cpuops.cpp index c10a0c09..ea8d8653 100644 --- a/cpuops.cpp +++ b/cpuops.cpp @@ -190,7 +190,11 @@ #ifdef SA1_OPCODES #define AddCycles(n) { } #else -#define AddCycles(n) CPU.Cycles += n +#if (S9X_ACCURACY_LEVEL >= 3) +#define AddCycles(n) { CPU.Cycles += (n); while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); } +#else +#define AddCycles(n) { CPU.Cycles += (n); } +#endif #endif #include "cpuaddr.h" diff --git a/debug.cpp b/debug.cpp index 94918e68..555ca086 100644 --- a/debug.cpp +++ b/debug.cpp @@ -317,6 +317,10 @@ static int AddrModes[256] = 4, 11, 9, 20, 26, 7, 7, 13, 0, 16, 0, 0, 23, 15, 15, 18 // F }; +static uint8 S9xDebugGetByte (uint32); +static uint16 S9xDebugGetWord (uint32); +static uint8 S9xDebugSA1GetByte (uint32); +static uint16 S9xDebugSA1GetWord (uint32); static uint8 debug_cpu_op_print (char *, uint8, uint16); static uint8 debug_sa1_op_print (char *, uint8, uint16); static void debug_line_print (const char *); @@ -329,6 +333,107 @@ static void debug_whats_used (void); static void debug_whats_missing (void); +static uint8 S9xDebugGetByte (uint32 Address) +{ + int block = (Address & 0xffffff) >> MEMMAP_SHIFT; + uint8 *GetAddress = Memory.Map[block]; + uint8 byte = 0; + + if (GetAddress >= (uint8 *) CMemory::MAP_LAST) + { + byte = *(GetAddress + (Address & 0xffff)); + return (byte); + } + + switch ((pint) GetAddress) + { + case CMemory::MAP_LOROM_SRAM: + case CMemory::MAP_SA1RAM: + byte = *(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask)); + return (byte); + + case CMemory::MAP_LOROM_SRAM_B: + byte = *(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB)); + return (byte); + + case CMemory::MAP_HIROM_SRAM: + case CMemory::MAP_RONLY_SRAM: + byte = *(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)); + return (byte); + + case CMemory::MAP_BWRAM: + byte = *(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)); + return (byte); + + default: + return (byte); + } +} + +static uint16 S9xDebugGetWord (uint32 Address) +{ + uint16 word; + + word = S9xDebugGetByte(Address); + word |= S9xDebugGetByte(Address + 1) << 8; + + return (word); +} + +static uint8 S9xDebugSA1GetByte (uint32 Address) +{ + int block = (Address & 0xffffff) >> MEMMAP_SHIFT; + uint8 *GetAddress = SA1.Map[block]; + uint8 byte = 0; + + if (GetAddress >= (uint8 *) CMemory::MAP_LAST) + { + byte = *(GetAddress + (Address & 0xffff)); + return (byte); + } + + switch ((pint) GetAddress) + { + case CMemory::MAP_LOROM_SRAM: + case CMemory::MAP_SA1RAM: + byte = *(Memory.SRAM + (Address & 0xffff)); + return (byte); + + case CMemory::MAP_BWRAM: + byte = *(SA1.BWRAM + ((Address & 0x7fff) - 0x6000)); + return (byte); + + case CMemory::MAP_BWRAM_BITMAP: + Address -= 0x600000; + if (SA1.VirtualBitmapFormat == 2) + byte = (Memory.SRAM[(Address >> 2) & 0xffff] >> ((Address & 3) << 1)) & 3; + else + byte = (Memory.SRAM[(Address >> 1) & 0xffff] >> ((Address & 1) << 2)) & 15; + return (byte); + + case CMemory::MAP_BWRAM_BITMAP2: + Address = (Address & 0xffff) - 0x6000; + if (SA1.VirtualBitmapFormat == 2) + byte = (SA1.BWRAM[(Address >> 2) & 0xffff] >> ((Address & 3) << 1)) & 3; + else + byte = (SA1.BWRAM[(Address >> 1) & 0xffff] >> ((Address & 1) << 2)) & 15; + return (byte); + + default: + return (byte); + } +} + +static uint16 S9xDebugSA1GetWord (uint32 Address) +{ + uint16 word; + + word = S9xDebugSA1GetByte(Address); + word |= S9xDebugSA1GetByte(Address + 1) << 8; + + return (word); +} + static uint8 debug_cpu_op_print (char *Line, uint8 Bank, uint16 Address) { uint8 S9xOpcode; @@ -339,15 +444,12 @@ static uint8 debug_cpu_op_print (char *Line, uint8 Bank, uint16 Address) int8 SByte; uint8 Size = 0; - int32 Cycles = CPU.Cycles; - uint32 WaitAddress = CPU.WaitAddress; - - S9xOpcode = S9xGetByte((Bank << 16) + Address); + S9xOpcode = S9xDebugGetByte((Bank << 16) + Address); sprintf(Line, "$%02X:%04X %02X ", Bank, Address, S9xOpcode); - Operant[0] = S9xGetByte((Bank << 16) + Address + 1); - Operant[1] = S9xGetByte((Bank << 16) + Address + 2); - Operant[2] = S9xGetByte((Bank << 16) + Address + 3); + Operant[0] = S9xDebugGetByte((Bank << 16) + Address + 1); + Operant[1] = S9xDebugGetByte((Bank << 16) + Address + 2); + Operant[2] = S9xDebugGetByte((Bank << 16) + Address + 3); switch (AddrModes[S9xOpcode]) { @@ -505,7 +607,7 @@ static uint8 debug_cpu_op_print (char *Line, uint8 Bank, uint16 Address) Operant[0]); Word = Operant[0]; Word += Registers.D.W; - Word = S9xGetWord(Word); + Word = S9xDebugGetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); Size = 2; break; @@ -520,7 +622,7 @@ static uint8 debug_cpu_op_print (char *Line, uint8 Bank, uint16 Address) Word = Operant[0]; Word += Registers.D.W; Word += Registers.X.W; - Word = S9xGetWord(Word); + Word = S9xDebugGetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); Size = 2; break; @@ -534,7 +636,7 @@ static uint8 debug_cpu_op_print (char *Line, uint8 Bank, uint16 Address) Operant[0]); Word = Operant[0]; Word += Registers.D.W; - Word = S9xGetWord(Word); + Word = S9xDebugGetWord(Word); Word += Registers.Y.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); Size = 2; @@ -549,8 +651,8 @@ static uint8 debug_cpu_op_print (char *Line, uint8 Bank, uint16 Address) Operant[0]); Word = Operant[0]; Word += Registers.D.W; - Byte = S9xGetByte(Word + 2); - Word = S9xGetWord(Word); + Byte = S9xDebugGetByte(Word + 2); + Word = S9xDebugGetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Byte, Word); Size = 2; break; @@ -564,8 +666,8 @@ static uint8 debug_cpu_op_print (char *Line, uint8 Bank, uint16 Address) Operant[0]); Word = Operant[0]; Word += Registers.D.W; - Byte = S9xGetByte(Word + 2); - Word = S9xGetWord(Word); + Byte = S9xDebugGetByte(Word + 2); + Word = S9xDebugGetWord(Word); Word += Registers.Y.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, Byte, Word); Size = 2; @@ -670,7 +772,7 @@ static uint8 debug_cpu_op_print (char *Line, uint8 Bank, uint16 Address) Operant[0]); Word = Registers.S.W; Word += Operant[0]; - Word = S9xGetWord(Word); + Word = S9xDebugGetWord(Word); Word += Registers.Y.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); Size = 2; @@ -686,7 +788,7 @@ static uint8 debug_cpu_op_print (char *Line, uint8 Bank, uint16 Address) Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; - Word = S9xGetWord(Word); + Word = S9xDebugGetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Registers.PB, Word); Size = 3; break; @@ -701,8 +803,8 @@ static uint8 debug_cpu_op_print (char *Line, uint8 Bank, uint16 Address) Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; - Byte = S9xGetByte(Word + 2); - Word = S9xGetWord(Word); + Byte = S9xDebugGetByte(Word + 2); + Word = S9xDebugGetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Byte, Word); Size = 3; break; @@ -718,7 +820,7 @@ static uint8 debug_cpu_op_print (char *Line, uint8 Bank, uint16 Address) Operant[0]); Word = (Operant[1] << 8) | Operant[0]; Word += Registers.X.W; - Word = S9xGetWord(ICPU.ShiftedPB + Word); + Word = S9xDebugGetWord(ICPU.ShiftedPB + Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Registers.PB, Word); Size = 3; break; @@ -764,7 +866,7 @@ static uint8 debug_cpu_op_print (char *Line, uint8 Bank, uint16 Address) Operant[0]); Word = Operant[0]; Word += Registers.D.W; - Word = S9xGetWord(Word); + Word = S9xDebugGetWord(Word); sprintf(Line, "%-32s[$%04X]", Line, Word); Size = 2; break; @@ -782,14 +884,11 @@ static uint8 debug_cpu_op_print (char *Line, uint8 Bank, uint16 Address) CheckIRQ() ? 'I' : 'i', CheckZero() ? 'Z' : 'z', CheckCarry() ? 'C' : 'c', - (long) Cycles, + (long) CPU.Cycles, (long) CPU.V_Counter, IPPU.FrameCount, CPU.IRQActive); - CPU.Cycles = Cycles; - CPU.WaitAddress = WaitAddress; - return (Size); } @@ -803,12 +902,12 @@ static uint8 debug_sa1_op_print (char *Line, uint8 Bank, uint16 Address) int8 SByte; uint8 Size = 0; - S9xOpcode = S9xSA1GetByte((Bank << 16) + Address); + S9xOpcode = S9xDebugSA1GetByte((Bank << 16) + Address); sprintf(Line, "$%02X:%04X %02X ", Bank, Address, S9xOpcode); - Operant[0] = S9xSA1GetByte((Bank << 16) + Address + 1); - Operant[1] = S9xSA1GetByte((Bank << 16) + Address + 2); - Operant[2] = S9xSA1GetByte((Bank << 16) + Address + 3); + Operant[0] = S9xDebugSA1GetByte((Bank << 16) + Address + 1); + Operant[1] = S9xDebugSA1GetByte((Bank << 16) + Address + 2); + Operant[2] = S9xDebugSA1GetByte((Bank << 16) + Address + 3); switch (AddrModes[S9xOpcode]) { @@ -966,7 +1065,7 @@ static uint8 debug_sa1_op_print (char *Line, uint8 Bank, uint16 Address) Operant[0]); Word = Operant[0]; Word += SA1Registers.D.W; - Word = S9xSA1GetWord(Word); + Word = S9xDebugSA1GetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); Size = 2; break; @@ -981,7 +1080,7 @@ static uint8 debug_sa1_op_print (char *Line, uint8 Bank, uint16 Address) Word = Operant[0]; Word += SA1Registers.D.W; Word += SA1Registers.X.W; - Word = S9xSA1GetWord(Word); + Word = S9xDebugSA1GetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); Size = 2; break; @@ -995,7 +1094,7 @@ static uint8 debug_sa1_op_print (char *Line, uint8 Bank, uint16 Address) Operant[0]); Word = Operant[0]; Word += SA1Registers.D.W; - Word = S9xSA1GetWord(Word); + Word = S9xDebugSA1GetWord(Word); Word += SA1Registers.Y.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); Size = 2; @@ -1010,8 +1109,8 @@ static uint8 debug_sa1_op_print (char *Line, uint8 Bank, uint16 Address) Operant[0]); Word = Operant[0]; Word += SA1Registers.D.W; - Byte = S9xSA1GetByte(Word + 2); - Word = S9xSA1GetWord(Word); + Byte = S9xDebugSA1GetByte(Word + 2); + Word = S9xDebugSA1GetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Byte, Word); Size = 2; break; @@ -1025,8 +1124,8 @@ static uint8 debug_sa1_op_print (char *Line, uint8 Bank, uint16 Address) Operant[0]); Word = Operant[0]; Word += SA1Registers.D.W; - Byte = S9xSA1GetByte(Word + 2); - Word = S9xSA1GetWord(Word); + Byte = S9xDebugSA1GetByte(Word + 2); + Word = S9xDebugSA1GetWord(Word); Word += SA1Registers.Y.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, Byte, Word); Size = 2; @@ -1131,7 +1230,7 @@ static uint8 debug_sa1_op_print (char *Line, uint8 Bank, uint16 Address) Operant[0]); Word = SA1Registers.S.W; Word += Operant[0]; - Word = S9xSA1GetWord(Word); + Word = S9xDebugSA1GetWord(Word); Word += SA1Registers.Y.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); Size = 2; @@ -1147,7 +1246,7 @@ static uint8 debug_sa1_op_print (char *Line, uint8 Bank, uint16 Address) Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; - Word = S9xSA1GetWord(Word); + Word = S9xDebugSA1GetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, SA1Registers.PB, Word); Size = 3; break; @@ -1162,8 +1261,8 @@ static uint8 debug_sa1_op_print (char *Line, uint8 Bank, uint16 Address) Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; - Byte = S9xSA1GetByte(Word + 2); - Word = S9xSA1GetWord(Word); + Byte = S9xDebugSA1GetByte(Word + 2); + Word = S9xDebugSA1GetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Byte, Word); Size = 3; break; @@ -1179,7 +1278,7 @@ static uint8 debug_sa1_op_print (char *Line, uint8 Bank, uint16 Address) Operant[0]); Word = (Operant[1] << 8) | Operant[0]; Word += SA1Registers.X.W; - Word = S9xSA1GetWord(SA1.ShiftedPB + Word); + Word = S9xDebugSA1GetWord(SA1.ShiftedPB + Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, SA1Registers.PB, Word); Size = 3; break; @@ -1275,7 +1374,7 @@ static void debug_process_command (char *Line) if (fs) { for (int i = 0; i < Count; i++) - putc(S9xGetByte(Address + i), fs); + putc(S9xDebugGetByte(Address + i), fs); fclose(fs); } else @@ -1292,17 +1391,17 @@ static void debug_process_command (char *Line) printf("Vectors:\n"); sprintf(string, " 8 Bit 16 Bit "); debug_line_print(string); - sprintf(string, "ABT $00:%04X|$00:%04X", S9xGetWord(0xFFF8), S9xGetWord(0xFFE8)); + sprintf(string, "ABT $00:%04X|$00:%04X", S9xDebugGetWord(0xFFF8), S9xDebugGetWord(0xFFE8)); debug_line_print(string); - sprintf(string, "BRK $00:%04X|$00:%04X", S9xGetWord(0xFFFE), S9xGetWord(0xFFE6)); + sprintf(string, "BRK $00:%04X|$00:%04X", S9xDebugGetWord(0xFFFE), S9xDebugGetWord(0xFFE6)); debug_line_print(string); - sprintf(string, "COP $00:%04X|$00:%04X", S9xGetWord(0xFFF4), S9xGetWord(0xFFE4)); + sprintf(string, "COP $00:%04X|$00:%04X", S9xDebugGetWord(0xFFF4), S9xDebugGetWord(0xFFE4)); debug_line_print(string); - sprintf(string, "IRQ $00:%04X|$00:%04X", S9xGetWord(0xFFFE), S9xGetWord(0xFFEE)); + sprintf(string, "IRQ $00:%04X|$00:%04X", S9xDebugGetWord(0xFFFE), S9xDebugGetWord(0xFFEE)); debug_line_print(string); - sprintf(string, "NMI $00:%04X|$00:%04X", S9xGetWord(0xFFFA), S9xGetWord(0xFFEA)); + sprintf(string, "NMI $00:%04X|$00:%04X", S9xDebugGetWord(0xFFFA), S9xDebugGetWord(0xFFEA)); debug_line_print(string); - sprintf(string, "RES $00:%04X", S9xGetWord(0xFFFC)); + sprintf(string, "RES $00:%04X", S9xDebugGetWord(0xFFFC)); debug_line_print(string); } @@ -1733,7 +1832,6 @@ static void debug_process_command (char *Line) int CLine; int CByte; uint8 MemoryByte; - int32 Cycles = CPU.Cycles; if (Debug.Dump.Bank != 0 || Debug.Dump.Address != 0) { @@ -1756,7 +1854,7 @@ static void debug_process_command (char *Line) Address + CByte == 0x4210) MemoryByte = 0; else - MemoryByte = S9xGetByte((Bank << 16) + Address + CByte); + MemoryByte = S9xDebugGetByte((Bank << 16) + Address + CByte); sprintf(string, "%s %02X", string, MemoryByte); } @@ -1772,7 +1870,7 @@ static void debug_process_command (char *Line) Address + CByte == 0x4210) MemoryByte = 0; else - MemoryByte = S9xGetByte((Bank << 16) + Address + CByte); + MemoryByte = S9xDebugGetByte((Bank << 16) + Address + CByte); if (MemoryByte < 32 || MemoryByte >= 127) MemoryByte = '?'; @@ -1787,8 +1885,6 @@ static void debug_process_command (char *Line) Debug.Dump.Bank = Bank; Debug.Dump.Address = Address; - - CPU.Cycles = Cycles; } if (*Line == 'q') diff --git a/dma.cpp b/dma.cpp index ef8d7377..bd2c6f22 100644 --- a/dma.cpp +++ b/dma.cpp @@ -185,6 +185,8 @@ #include "missing.h" #endif +#define ADD_CYCLES(n) CPU.Cycles += (n) + extern uint8 *HDMAMemPointers[8]; extern int HDMA_ModeByteCounts[8]; extern SPC7110 s7emu; @@ -199,7 +201,7 @@ static inline bool8 addCyclesInDMA (uint8 dma_channel) { // Add 8 cycles per byte, sync APU, and do HC related events. // If HDMA was done in S9xDoHEventProcessing(), check if it used the same channel as DMA. - CPU.Cycles += SLOW_ONE_CYCLE; + ADD_CYCLES(SLOW_ONE_CYCLE); while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); @@ -245,7 +247,7 @@ bool8 S9xDoDMA (uint8 Channel) c = 0x10000; // 8 cycles per channel - CPU.Cycles += SLOW_ONE_CYCLE; + ADD_CYCLES(SLOW_ONE_CYCLE); // 8 cycles per byte while (c) { @@ -510,7 +512,7 @@ bool8 S9xDoDMA (uint8 Channel) uint8 Work; // 8 cycles per channel - CPU.Cycles += SLOW_ONE_CYCLE; + ADD_CYCLES(SLOW_ONE_CYCLE); if (!d->ReverseTransfer) { @@ -1315,7 +1317,7 @@ static inline bool8 HDMAReadLineCount (int d) uint8 line; line = S9xGetByte((DMA[d].ABank << 16) + DMA[d].Address); - CPU.Cycles += SLOW_ONE_CYCLE; + ADD_CYCLES(SLOW_ONE_CYCLE); if (!line) { @@ -1327,10 +1329,10 @@ static inline bool8 HDMAReadLineCount (int d) if (PPU.HDMA & (0xfe << d)) { DMA[d].Address++; - CPU.Cycles += SLOW_ONE_CYCLE * 2; + ADD_CYCLES(SLOW_ONE_CYCLE << 1); } else - CPU.Cycles += SLOW_ONE_CYCLE; + ADD_CYCLES(SLOW_ONE_CYCLE); DMA[d].IndirectAddress = S9xGetWord((DMA[d].ABank << 16) + DMA[d].Address); DMA[d].Address++; @@ -1358,7 +1360,7 @@ static inline bool8 HDMAReadLineCount (int d) if (DMA[d].HDMAIndirectAddressing) { - CPU.Cycles += SLOW_ONE_CYCLE << 1; + ADD_CYCLES(SLOW_ONE_CYCLE << 1); DMA[d].IndirectAddress = S9xGetWord((DMA[d].ABank << 16) + DMA[d].Address); DMA[d].Address += 2; HDMAMemPointers[d] = S9xGetMemPointer((DMA[d].IndirectBank << 16) + DMA[d].IndirectAddress); @@ -1390,7 +1392,7 @@ void S9xStartHDMA (void) // XXX: Not quite right... if (PPU.HDMA != 0) - CPU.Cycles += Timings.DMACPUSync; + ADD_CYCLES(Timings.DMACPUSync); for (uint8 i = 0; i < 8; i++) { @@ -1433,7 +1435,7 @@ uint8 S9xDoHDMA (uint8 byte) tmpch = CPU.CurrentDMAorHDMAChannel; // XXX: Not quite right... - CPU.Cycles += Timings.DMACPUSync; + ADD_CYCLES(Timings.DMACPUSync); for (uint8 mask = 1; mask; mask <<= 1, p++, d++) { @@ -1498,46 +1500,57 @@ uint8 S9xDoHDMA (uint8 byte) switch (p->TransferMode) { case 0: - CPU.Cycles += SLOW_ONE_CYCLE; DOBYTE(IAddr, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); break; case 5: - CPU.Cycles += 4 * SLOW_ONE_CYCLE; DOBYTE(IAddr + 0, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 1); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 2, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 3, 1); + ADD_CYCLES(SLOW_ONE_CYCLE); break; case 1: - CPU.Cycles += 2 * SLOW_ONE_CYCLE; DOBYTE(IAddr + 0, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 1); + ADD_CYCLES(SLOW_ONE_CYCLE); break; case 2: case 6: - CPU.Cycles += 2 * SLOW_ONE_CYCLE; DOBYTE(IAddr + 0, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); break; case 3: case 7: - CPU.Cycles += 4 * SLOW_ONE_CYCLE; DOBYTE(IAddr + 0, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 2, 1); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 3, 1); + ADD_CYCLES(SLOW_ONE_CYCLE); break; case 4: - CPU.Cycles += 4 * SLOW_ONE_CYCLE; DOBYTE(IAddr + 0, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 1); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 2, 2); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 3, 3); + ADD_CYCLES(SLOW_ONE_CYCLE); break; } @@ -1556,44 +1569,53 @@ uint8 S9xDoHDMA (uint8 byte) switch (p->TransferMode) { case 0: - CPU.Cycles += SLOW_ONE_CYCLE; S9xSetPPU(S9xGetByte(Addr), 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); break; case 5: - CPU.Cycles += 2 * SLOW_ONE_CYCLE; S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 1), 0x2101 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); Addr += 2; /* fall through */ case 1: - CPU.Cycles += 2 * SLOW_ONE_CYCLE; S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 1), 0x2101 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); break; case 2: case 6: - CPU.Cycles += 2 * SLOW_ONE_CYCLE; S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 1), 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); break; case 3: case 7: - CPU.Cycles += 4 * SLOW_ONE_CYCLE; S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 1), 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 2), 0x2101 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 3), 0x2101 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); break; case 4: - CPU.Cycles += 4 * SLOW_ONE_CYCLE; S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 1), 0x2101 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 2), 0x2102 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 3), 0x2103 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); break; } } @@ -1603,47 +1625,56 @@ uint8 S9xDoHDMA (uint8 byte) switch (p->TransferMode) { case 0: - CPU.Cycles += SLOW_ONE_CYCLE; S9xSetPPU(*HDMAMemPointers[d]++, 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); break; case 5: - CPU.Cycles += 2 * SLOW_ONE_CYCLE; S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2101 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); HDMAMemPointers[d] += 2; /* fall through */ case 1: - CPU.Cycles += 2 * SLOW_ONE_CYCLE; S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2101 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); HDMAMemPointers[d] += 2; break; case 2: case 6: - CPU.Cycles += 2 * SLOW_ONE_CYCLE; S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); HDMAMemPointers[d] += 2; break; case 3: case 7: - CPU.Cycles += 4 * SLOW_ONE_CYCLE; S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 2), 0x2101 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 3), 0x2101 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); HDMAMemPointers[d] += 4; break; case 4: - CPU.Cycles += 4 * SLOW_ONE_CYCLE; S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2101 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 2), 0x2102 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 3), 0x2103 + p->BAddress); + ADD_CYCLES(SLOW_ONE_CYCLE); HDMAMemPointers[d] += 4; break; } @@ -1665,46 +1696,57 @@ uint8 S9xDoHDMA (uint8 byte) switch (p->TransferMode) { case 0: - CPU.Cycles += SLOW_ONE_CYCLE; DOBYTE(IAddr, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); break; case 5: - CPU.Cycles += 4 * SLOW_ONE_CYCLE; DOBYTE(IAddr + 0, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 1); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 2, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 3, 1); + ADD_CYCLES(SLOW_ONE_CYCLE); break; case 1: - CPU.Cycles += 2 * SLOW_ONE_CYCLE; DOBYTE(IAddr + 0, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 1); + ADD_CYCLES(SLOW_ONE_CYCLE); break; case 2: case 6: - CPU.Cycles += 2 * SLOW_ONE_CYCLE; DOBYTE(IAddr + 0, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); break; case 3: case 7: - CPU.Cycles += 4 * SLOW_ONE_CYCLE; DOBYTE(IAddr + 0, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 2, 1); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 3, 1); + ADD_CYCLES(SLOW_ONE_CYCLE); break; case 4: - CPU.Cycles += 4 * SLOW_ONE_CYCLE; DOBYTE(IAddr + 0, 0); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 1); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 2, 2); + ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 3, 3); + ADD_CYCLES(SLOW_ONE_CYCLE); break; } @@ -1730,7 +1772,7 @@ uint8 S9xDoHDMA (uint8 byte) } } else - CPU.Cycles += SLOW_ONE_CYCLE; + ADD_CYCLES(SLOW_ONE_CYCLE); } } diff --git a/docs/porting.html b/docs/porting.html index 63d80376..9c62e23c 100644 --- a/docs/porting.html +++ b/docs/porting.html @@ -291,11 +291,6 @@
Called once a complete SNES screen has been rendered into the GFX.Screen
memory buffer, now is your chance to copy the SNES rendered screen to the host computer's screen memory. The problem is that you have to cope with different sized SNES rendered screens: 256*224, 256*239, 512*224, 512*239, 512*448 and 512*478.
bool8 S9xContinueUpdate (int width, int height)
- Similar to S9xDeinitUpdate
, but in interlace mode (512*448 or 512*478) only. Called once an even frame has been rendered into the GFX.Screen
memory buffer.
-
void S9xMessage (int type, int number, const char *message)
When Snes9x wants to display an error, information or warning message, it calls this function. Check in messages.h
for the types and individual message numbers that Snes9x currently passes as parameters.
@@ -384,7 +379,7 @@
The sound generation rate on a SNES is directly proportional to the video output rate. Displays that synchronize with the vertical refresh but have a slightly lower refresh-rate than the emulated system can experience sound drop-outs. It may be beneficial to provide an option for users to configure Settings.SoundInputRate
to suit their own systems. Setting Settings.SoundInputRate
to a value that matches the actual output rate (i.e. 31977hz for 59.96hz) or lower will allow the users to eliminate crackling. A range of 31000hz to 33000hz should be inclusive enough for all displays. Use of this setting paired with the S9xSyncSound
function can eliminate sound discontinuity.