2024-07-03 18:15:28 +08:00
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.IO ;
using System.Runtime.InteropServices ;
using System.Threading ;
using System.Xml ;
2024-07-03 18:22:22 +08:00
namespace MyNes.Core
2024-07-03 18:15:28 +08:00
{
2024-07-03 18:22:22 +08:00
public class NesEmu
{
2024-07-04 21:06:41 +08:00
[StructLayout(LayoutKind.Explicit)]
private struct CPURegister
{
[FieldOffset(0)]
internal byte l ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
[FieldOffset(1)]
internal byte h ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
[FieldOffset(0)]
internal ushort v ;
}
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private enum RequestMode
{
None ,
HardReset ,
SoftReset ,
LoadState ,
SaveState ,
TakeSnapshot
}
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int [ ] [ ] dmc_freq_table = new int [ 3 ] [ ]
{
new int [ 16 ]
{
428 , 380 , 340 , 320 , 286 , 254 , 226 , 214 , 190 , 160 ,
142 , 128 , 106 , 84 , 72 , 54
} ,
new int [ 16 ]
{
398 , 354 , 316 , 298 , 276 , 236 , 210 , 198 , 176 , 148 ,
132 , 118 , 98 , 78 , 66 , 50
} ,
new int [ 16 ]
{
428 , 380 , 340 , 320 , 286 , 254 , 226 , 214 , 190 , 160 ,
142 , 128 , 106 , 84 , 72 , 54
}
} ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int dmc_output_a ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int dmc_output ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int dmc_period_devider ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool dmc_irq_enabled ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool dmc_loop_flag ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte dmc_rate_index ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort dmc_addr_refresh ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int dmc_size_refresh ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool dmc_dmaEnabled ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte dmc_dmaByte ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int dmc_dmaBits ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool dmc_bufferFull ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte dmc_dmaBuffer ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int dmc_dmaSize ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort dmc_dmaAddr ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort [ ] [ ] nos_freq_table = new ushort [ 3 ] [ ]
{
new ushort [ 16 ]
{
4 , 8 , 16 , 32 , 64 , 96 , 128 , 160 , 202 , 254 ,
380 , 508 , 762 , 1016 , 2034 , 4068
} ,
new ushort [ 16 ]
{
4 , 7 , 14 , 30 , 60 , 88 , 118 , 148 , 188 , 236 ,
354 , 472 , 708 , 944 , 1890 , 3778
} ,
new ushort [ 16 ]
{
4 , 8 , 16 , 32 , 64 , 96 , 128 , 160 , 202 , 254 ,
380 , 508 , 762 , 1016 , 2034 , 4068
}
} ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool nos_length_halt ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool nos_constant_volume_envelope ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte nos_volume_devider_period ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort nos_timer ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool nos_mode ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int nos_period_devider ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool nos_length_enabled ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int nos_length_counter ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool nos_envelope_start_flag ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte nos_envelope_devider ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte nos_envelope_decay_level_counter ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte nos_envelope ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int nos_output ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int nos_shift_reg ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int nos_feedback ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool nos_ignore_reload ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte [ ] [ ] sq_duty_cycle_sequences = new byte [ 4 ] [ ]
{
new byte [ 8 ] { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 } ,
new byte [ 8 ] { 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 } ,
new byte [ 8 ] { 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 } ,
new byte [ 8 ] { 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 }
} ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte [ ] sq_duration_table = new byte [ 32 ]
{
10 , 254 , 20 , 2 , 40 , 4 , 80 , 6 , 160 , 8 ,
60 , 10 , 14 , 12 , 26 , 14 , 12 , 16 , 24 , 18 ,
48 , 20 , 96 , 22 , 192 , 24 , 72 , 26 , 16 , 28 ,
32 , 30
} ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq1_duty_cycle ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq1_length_halt ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq1_constant_volume_envelope ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq1_volume_devider_period ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq1_sweep_enable ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq1_sweep_devider_period ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq1_sweep_negate ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq1_sweep_shift_count ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int sq1_timer ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int sq1_period_devider ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq1_seqencer ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq1_length_enabled ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int sq1_length_counter ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq1_envelope_start_flag ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq1_envelope_devider ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq1_envelope_decay_level_counter ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq1_envelope ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int sq1_sweep_counter ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq1_sweep_reload ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int sq1_sweep_change ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq1_valid_freq ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int sq1_output ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq1_ignore_reload ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte [ ] trl_step_seq = new byte [ 32 ]
{
15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 7 , 6 ,
5 , 4 , 3 , 2 , 1 , 0 , 0 , 1 , 2 , 3 ,
4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 ,
14 , 15
} ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool trl_liner_control_flag ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte trl_liner_control_reload ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort trl_timer ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool trl_length_enabled ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte trl_length_counter ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool trl_liner_control_reload_flag ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte trl_liner_counter ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int trl_output ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int trl_period_devider ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int trl_step ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool trl_ignore_reload ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte apu_reg_io_db ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte apu_reg_io_addr ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool apu_reg_access_happened ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool apu_reg_access_w ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static Action [ ] apu_reg_update_func ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static Action [ ] apu_reg_read_func ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static Action [ ] apu_reg_write_func ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static Action apu_update_playback_func ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool apu_odd_cycle ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool apu_irq_enabled ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool apu_irq_flag ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool apu_irq_do_it ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
internal static bool apu_irq_delta_occur ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool apu_seq_mode ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int apu_ferq_f ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int apu_ferq_l ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int apu_ferq_e ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int apu_cycle_f ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int apu_cycle_f_t ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int apu_cycle_e ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int apu_cycle_l ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool apu_odd_l ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool apu_check_irq ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool apu_do_env ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool apu_do_length ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static bool SoundEnabled ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static double audio_playback_amplitude = 1.5 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static int audio_playback_peek_limit = 124 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool audio_playback_dac_initialized ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static int cpu_speed ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static short [ ] audio_samples ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int audio_w_pos ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int audio_samples_added ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
internal static int audio_samples_count ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int [ ] [ ] [ ] [ ] [ ] mix_table ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static double audio_x ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static double audio_y ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static double audio_y_av ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static double audio_y_timer ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static double audio_timer_ratio = 40.0 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static double audio_timer ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static SoundLowPassFilter audio_low_pass_filter_14K ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static SoundHighPassFilter audio_high_pass_filter_90 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static SoundHighPassFilter audio_high_pass_filter_440 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static SoundDCBlockerFilter audio_dc_blocker_filter ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool audio_sq1_outputable ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool audio_sq2_outputable ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool audio_nos_outputable ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool audio_trl_outputable ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool audio_dmc_outputable ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool audio_signal_outputed ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool apu_use_external_sound ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static CPURegister cpu_reg_pc ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static CPURegister cpu_reg_sp ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static CPURegister cpu_reg_ea ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte cpu_reg_a ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte cpu_reg_x ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte cpu_reg_y ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool cpu_flag_n ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool cpu_flag_v ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool cpu_flag_d ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool cpu_flag_i ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool cpu_flag_z ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool cpu_flag_c ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte cpu_m ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte cpu_opcode ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte cpu_byte_temp ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int cpu_int_temp ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int cpu_int_temp1 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte cpu_dummy ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool cpu_bool_tmp ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static CPURegister temp_add ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool CPU_IRQ_PIN ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool CPU_NMI_PIN ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool cpu_suspend_nmi ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool cpu_suspend_irq ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static Action [ ] cpu_addressings ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static Action [ ] cpu_instructions ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int dma_DMCDMAWaitCycles ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int dma_OAMDMAWaitCycles ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool dma_isOamDma ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int dma_oamdma_i ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool dma_DMCOn ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool dma_OAMOn ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool dma_DMC_occurring ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool dma_OAM_occurring ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int dma_OAMFinishCounter ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort dma_Oamaddress ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int dma_OAMCYCLE ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte dma_latch ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte dma_dummy ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort reg_2004 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
internal static int IRQFlags = 0 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool PPU_NMI_Current ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool PPU_NMI_Old ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private const int IRQ_APU = 1 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
internal const int IRQ_DMC = 2 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
internal const int IRQ_BOARD = 8 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort InterruptVector ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte [ ] mem_wram ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
internal static Board mem_board ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static MemReadAccess [ ] mem_read_accesses ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static MemWriteAccess [ ] mem_write_accesses ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool BUS_RW ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort BUS_ADDRESS ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static string SRAMFileName ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static string GMFileName ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int PORT0 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int PORT1 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int inputStrobe ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static IJoypadConnecter joypad1 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static IJoypadConnecter joypad2 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static IJoypadConnecter joypad3 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static IJoypadConnecter joypad4 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static IShortcutsHandler shortucts ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static bool IsFourPlayers ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte [ ] reverseLookup = new byte [ 256 ]
{
0 , 128 , 64 , 192 , 32 , 160 , 96 , 224 , 16 , 144 ,
80 , 208 , 48 , 176 , 112 , 240 , 8 , 136 , 72 , 200 ,
40 , 168 , 104 , 232 , 24 , 152 , 88 , 216 , 56 , 184 ,
120 , 248 , 4 , 132 , 68 , 196 , 36 , 164 , 100 , 228 ,
20 , 148 , 84 , 212 , 52 , 180 , 116 , 244 , 12 , 140 ,
76 , 204 , 44 , 172 , 108 , 236 , 28 , 156 , 92 , 220 ,
60 , 188 , 124 , 252 , 2 , 130 , 66 , 194 , 34 , 162 ,
98 , 226 , 18 , 146 , 82 , 210 , 50 , 178 , 114 , 242 ,
10 , 138 , 74 , 202 , 42 , 170 , 106 , 234 , 26 , 154 ,
90 , 218 , 58 , 186 , 122 , 250 , 6 , 134 , 70 , 198 ,
38 , 166 , 102 , 230 , 22 , 150 , 86 , 214 , 54 , 182 ,
118 , 246 , 14 , 142 , 78 , 206 , 46 , 174 , 110 , 238 ,
30 , 158 , 94 , 222 , 62 , 190 , 126 , 254 , 1 , 129 ,
65 , 193 , 33 , 161 , 97 , 225 , 17 , 145 , 81 , 209 ,
49 , 177 , 113 , 241 , 9 , 137 , 73 , 201 , 41 , 169 ,
105 , 233 , 25 , 153 , 89 , 217 , 57 , 185 , 121 , 249 ,
5 , 133 , 69 , 197 , 37 , 165 , 101 , 229 , 21 , 149 ,
85 , 213 , 53 , 181 , 117 , 245 , 13 , 141 , 77 , 205 ,
45 , 173 , 109 , 237 , 29 , 157 , 93 , 221 , 61 , 189 ,
125 , 253 , 3 , 131 , 67 , 195 , 35 , 163 , 99 , 227 ,
19 , 147 , 83 , 211 , 51 , 179 , 115 , 243 , 11 , 139 ,
75 , 203 , 43 , 171 , 107 , 235 , 27 , 155 , 91 , 219 ,
59 , 187 , 123 , 251 , 7 , 135 , 71 , 199 , 39 , 167 ,
103 , 231 , 23 , 151 , 87 , 215 , 55 , 183 , 119 , 247 ,
15 , 143 , 79 , 207 , 47 , 175 , 111 , 239 , 31 , 159 ,
95 , 223 , 63 , 191 , 127 , 255
} ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static Action [ ] ppu_v_clocks ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static Action [ ] ppu_h_clocks ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static Action [ ] ppu_bkg_fetches ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static Action [ ] ppu_spr_fetches ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static Action [ ] ppu_oam_phases ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int [ ] ppu_bkg_pixels ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int [ ] ppu_spr_pixels ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int [ ] ppu_screen_pixels ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int [ ] ppu_palette ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int ppu_clock_h ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
internal static ushort ppu_clock_v ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort ppu_clock_vblank_start ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort ppu_clock_vblank_end ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_use_odd_cycle ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_use_odd_swap ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_odd_swap_done ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_is_nmi_time ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_frame_finished ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte [ ] ppu_oam_bank ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte [ ] ppu_oam_bank_secondary ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte [ ] ppu_palette_bank ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_reg_io_db ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_reg_io_addr ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_reg_access_happened ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_reg_access_w ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static Action [ ] ppu_reg_update_func ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static Action [ ] ppu_reg_read_func ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_reg_2000_vram_address_increament ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort ppu_reg_2000_background_pattern_table_address ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
internal static byte ppu_reg_2000_Sprite_size ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_reg_2000_VBI ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_reg_2001_show_background ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_reg_2001_show_sprites ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int ppu_reg_2001_grayscale ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int ppu_reg_2001_emphasis ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_reg_2002_SpriteOverflow ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_reg_2002_Sprite0Hit ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_reg_2002_VblankStartedFlag ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_reg_2003_oam_addr ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort ppu_vram_addr ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_vram_data ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort ppu_vram_addr_temp ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort ppu_vram_addr_access_temp ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_vram_flip_flop ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_vram_finex ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort ppu_bkgfetch_nt_addr ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_bkgfetch_nt_data ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort ppu_bkgfetch_at_addr ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_bkgfetch_at_data ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort ppu_bkgfetch_lb_addr ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_bkgfetch_lb_data ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort ppu_bkgfetch_hb_addr ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_bkgfetch_hb_data ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int ppu_sprfetch_slot ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_sprfetch_y_data ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_sprfetch_t_data ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_sprfetch_at_data ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_sprfetch_x_data ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort ppu_sprfetch_lb_addr ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_sprfetch_lb_data ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static ushort ppu_sprfetch_hb_addr ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_sprfetch_hb_data ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
internal static bool ppu_is_sprfetch ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int ppu_bkg_render_i ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int ppu_bkg_render_pos ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int ppu_bkg_render_tmp_val ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int ppu_bkg_current_pixel ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int ppu_spr_current_pixel ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int ppu_current_pixel ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int ppu_render_x ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int ppu_render_y ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_oamev_n ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_oamev_m ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_oamev_compare ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_oamev_slot ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_fetch_data ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte ppu_phase_index ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool ppu_sprite0_should_hit ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int ppu_temp_comparator ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static bool ON ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static bool PAUSED ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static bool isPaused ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static string CurrentFilePath ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static bool FrameLimiterEnabled ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static Thread mainThread ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static double fps_time_last ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static double fps_time_start ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static double fps_time_token ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static double fps_time_dead ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static double fps_time_period ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static double fps_time_frame_time ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static double emu_time_target_fps = 60.0 ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool emu_frame_clocking_mode ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool emu_frame_done ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool render_initialized ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static RenderVideoFrame render_video ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static RenderAudioSamples render_audio ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static TogglePause render_audio_toggle_pause ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static GetIsPlaying render_audio_get_is_playing ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool render_audio_is_playing ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static EmuRegion Region ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int SystemIndex ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static RequestMode emu_request_mode = RequestMode . None ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static bool FrameSkipEnabled ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static int FrameSkipInterval ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int FrameSkipCounter ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq2_duty_cycle ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq2_length_halt ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq2_constant_volume_envelope ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq2_volume_devider_period ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq2_sweep_enable ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq2_sweep_devider_period ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq2_sweep_negate ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq2_sweep_shift_count ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int sq2_timer ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int sq2_period_devider ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq2_seqencer ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq2_length_enabled ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int sq2_length_counter ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq2_envelope_start_flag ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq2_envelope_devider ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq2_envelope_decay_level_counter ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte sq2_envelope ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int sq2_sweep_counter ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq2_sweep_reload ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int sq2_sweep_change ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq2_valid_freq ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static int sq2_output ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static bool sq2_ignore_reload ;
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
private static byte register_p
{
get
{
return ( byte ) ( ( cpu_flag_n ? 128 u : 0 u ) | ( cpu_flag_v ? 64 u : 0 u ) | ( cpu_flag_d ? 8 u : 0 u ) | ( cpu_flag_i ? 4 u : 0 u ) | ( cpu_flag_z ? 2 u : 0 u ) | ( cpu_flag_c ? 1 u : 0 u ) | 0x20 u ) ;
}
set
{
cpu_flag_n = ( value & 0x80 ) ! = 0 ;
cpu_flag_v = ( value & 0x40 ) ! = 0 ;
cpu_flag_d = ( value & 8 ) ! = 0 ;
cpu_flag_i = ( value & 4 ) ! = 0 ;
cpu_flag_z = ( value & 2 ) ! = 0 ;
cpu_flag_c = ( value & 1 ) ! = 0 ;
}
}
2024-07-03 18:15:28 +08:00
2024-07-04 21:06:41 +08:00
public static GameGenieCode [ ] GameGenieCodes
{
get
{
if ( mem_board ! = null )
{
return mem_board . GameGenieCodes ;
}
return null ;
}
}
public static bool IsGameGenieActive
{
get
{
if ( mem_board ! = null )
{
return mem_board . IsGameGenieActive ;
}
return false ;
}
set
{
if ( mem_board ! = null )
{
mem_board . IsGameGenieActive = value ;
}
}
}
public static bool IsGameFoundOnDB
{
get
{
if ( mem_board ! = null )
{
return mem_board . IsGameFoundOnDB ;
}
return false ;
}
}
public static NesCartDatabaseGameInfo GameInfo
{
get
{
if ( mem_board ! = null )
{
return mem_board . GameInfo ;
}
return NesCartDatabaseGameInfo . Empty ;
}
}
public static NesCartDatabaseCartridgeInfo GameCartInfo
{
get
{
if ( mem_board ! = null )
{
return mem_board . GameCartInfo ;
}
return new NesCartDatabaseCartridgeInfo ( ) ;
}
}
public static string SHA1 = > mem_board . SHA1 ;
public static event EventHandler EmuShutdown ;
private static void DMCHardReset ( )
{
dmc_output_a = 0 ;
dmc_output = 0 ;
dmc_period_devider = 0 ;
dmc_loop_flag = false ;
dmc_rate_index = 0 ;
dmc_irq_enabled = false ;
dmc_dmaAddr = 49152 ;
dmc_addr_refresh = 49152 ;
dmc_size_refresh = 0 ;
dmc_dmaBits = 1 ;
dmc_dmaByte = 1 ;
dmc_period_devider = 0 ;
dmc_dmaEnabled = false ;
dmc_bufferFull = false ;
dmc_dmaSize = 0 ;
}
private static void DMCSoftReset ( )
{
DMCHardReset ( ) ;
}
private static void DMCClock ( )
{
dmc_period_devider - - ;
if ( dmc_period_devider > 0 )
{
return ;
}
dmc_period_devider = dmc_freq_table [ SystemIndex ] [ dmc_rate_index ] ;
if ( dmc_dmaEnabled )
{
if ( ( ( uint ) dmc_dmaByte & ( true ? 1 u : 0 u ) ) ! = 0 )
{
if ( dmc_output_a < = 125 )
{
dmc_output_a + = 2 ;
}
}
else if ( dmc_output_a > = 2 )
{
dmc_output_a - = 2 ;
}
dmc_dmaByte > > = 1 ;
}
dmc_dmaBits - - ;
if ( dmc_dmaBits = = 0 )
{
dmc_dmaBits = 8 ;
if ( dmc_bufferFull )
{
dmc_bufferFull = false ;
dmc_dmaEnabled = true ;
dmc_dmaByte = dmc_dmaBuffer ;
if ( dmc_dmaSize > 0 )
{
AssertDMCDMA ( ) ;
}
}
else
{
dmc_dmaEnabled = false ;
}
}
if ( audio_dmc_outputable )
{
dmc_output = dmc_output_a ;
}
audio_signal_outputed = true ;
}
private static void DMCDoDMA ( )
{
dmc_bufferFull = true ;
Read ( ref dmc_dmaAddr , out dmc_dmaBuffer ) ;
if ( dmc_dmaAddr = = ushort . MaxValue )
{
dmc_dmaAddr = 32768 ;
}
else
{
dmc_dmaAddr + + ;
}
if ( dmc_dmaSize > 0 )
{
dmc_dmaSize - - ;
}
if ( dmc_dmaSize = = 0 )
{
if ( dmc_loop_flag )
{
dmc_dmaSize = dmc_size_refresh ;
dmc_dmaAddr = dmc_addr_refresh ;
}
else if ( dmc_irq_enabled )
{
IRQFlags | = 2 ;
apu_irq_delta_occur = true ;
}
}
}
private static void APUOnRegister4010 ( )
{
if ( apu_reg_access_w )
{
dmc_irq_enabled = ( apu_reg_io_db & 0x80 ) ! = 0 ;
dmc_loop_flag = ( apu_reg_io_db & 0x40 ) ! = 0 ;
if ( ! dmc_irq_enabled )
{
apu_irq_delta_occur = false ;
IRQFlags & = - 3 ;
}
dmc_rate_index = ( byte ) ( apu_reg_io_db & 0xF u ) ;
}
}
private static void APUOnRegister4011 ( )
{
if ( apu_reg_access_w )
{
dmc_output_a = ( byte ) ( apu_reg_io_db & 0x7F ) ;
}
}
private static void APUOnRegister4012 ( )
{
if ( apu_reg_access_w )
{
dmc_addr_refresh = ( ushort ) ( ( uint ) ( apu_reg_io_db < < 6 ) | 0xC000 u ) ;
}
}
private static void APUOnRegister4013 ( )
{
if ( apu_reg_access_w )
{
dmc_size_refresh = ( apu_reg_io_db < < 4 ) | 1 ;
}
}
private static void DMCOn4015 ( )
{
apu_irq_delta_occur = false ;
IRQFlags & = - 3 ;
}
private static void DMCRead4015 ( )
{
if ( dmc_dmaSize > 0 )
{
apu_reg_io_db = ( byte ) ( ( apu_reg_io_db & 0xEF u ) | 0x10 u ) ;
}
}
private static void DMCWriteState ( ref BinaryWriter bin )
{
bin . Write ( dmc_output_a ) ;
bin . Write ( dmc_output ) ;
bin . Write ( dmc_period_devider ) ;
bin . Write ( dmc_irq_enabled ) ;
bin . Write ( dmc_loop_flag ) ;
bin . Write ( dmc_rate_index ) ;
bin . Write ( dmc_addr_refresh ) ;
bin . Write ( dmc_size_refresh ) ;
bin . Write ( dmc_dmaEnabled ) ;
bin . Write ( dmc_dmaByte ) ;
bin . Write ( dmc_dmaBits ) ;
bin . Write ( dmc_bufferFull ) ;
bin . Write ( dmc_dmaBuffer ) ;
bin . Write ( dmc_dmaSize ) ;
bin . Write ( dmc_dmaAddr ) ;
}
private static void DMCReadState ( ref BinaryReader bin )
{
dmc_output_a = bin . ReadInt32 ( ) ;
dmc_output = bin . ReadInt32 ( ) ;
dmc_period_devider = bin . ReadInt32 ( ) ;
dmc_irq_enabled = bin . ReadBoolean ( ) ;
dmc_loop_flag = bin . ReadBoolean ( ) ;
dmc_rate_index = bin . ReadByte ( ) ;
dmc_addr_refresh = bin . ReadUInt16 ( ) ;
dmc_size_refresh = bin . ReadInt32 ( ) ;
dmc_dmaEnabled = bin . ReadBoolean ( ) ;
dmc_dmaByte = bin . ReadByte ( ) ;
dmc_dmaBits = bin . ReadInt32 ( ) ;
dmc_bufferFull = bin . ReadBoolean ( ) ;
dmc_dmaBuffer = bin . ReadByte ( ) ;
dmc_dmaSize = bin . ReadInt32 ( ) ;
dmc_dmaAddr = bin . ReadUInt16 ( ) ;
}
private static void NOSHardReset ( )
{
nos_length_halt = false ;
nos_constant_volume_envelope = false ;
nos_volume_devider_period = 0 ;
nos_shift_reg = 1 ;
nos_timer = 0 ;
nos_mode = false ;
nos_period_devider = 0 ;
nos_length_enabled = false ;
nos_length_counter = 0 ;
nos_envelope_start_flag = false ;
nos_envelope_devider = 0 ;
nos_envelope_decay_level_counter = 0 ;
nos_envelope = 0 ;
nos_output = 0 ;
nos_feedback = 0 ;
nos_ignore_reload = false ;
}
private static void NOSSoftReset ( )
{
NOSHardReset ( ) ;
}
private static void NOSClock ( )
{
nos_period_devider - - ;
if ( nos_period_devider > 0 )
{
return ;
}
nos_period_devider = nos_timer ;
if ( nos_mode )
{
nos_feedback = ( ( nos_shift_reg > > 6 ) & 1 ) ^ ( nos_shift_reg & 1 ) ;
}
else
{
nos_feedback = ( ( nos_shift_reg > > 1 ) & 1 ) ^ ( nos_shift_reg & 1 ) ;
}
nos_shift_reg > > = 1 ;
nos_shift_reg = ( nos_shift_reg & 0x3FFF ) | ( ( nos_feedback & 1 ) < < 14 ) ;
if ( nos_length_counter > 0 & & ( nos_shift_reg & 1 ) = = 0 )
{
if ( audio_nos_outputable )
{
nos_output = nos_envelope ;
}
}
else
{
nos_output = 0 ;
}
audio_signal_outputed = true ;
}
private static void NOSClockLength ( )
{
if ( nos_length_counter > 0 & & ! nos_length_halt )
{
nos_length_counter - - ;
if ( apu_reg_access_happened & & apu_reg_io_addr = = 15 & & apu_reg_access_w )
{
nos_ignore_reload = true ;
}
}
}
private static void NOSClockEnvelope ( )
{
if ( nos_envelope_start_flag )
{
nos_envelope_start_flag = false ;
nos_envelope_decay_level_counter = 15 ;
nos_envelope_devider = ( byte ) ( nos_volume_devider_period + 1 ) ;
}
else if ( nos_envelope_devider > 0 )
{
nos_envelope_devider - - ;
}
else
{
nos_envelope_devider = ( byte ) ( nos_volume_devider_period + 1 ) ;
if ( nos_envelope_decay_level_counter > 0 )
{
nos_envelope_decay_level_counter - - ;
}
else if ( nos_length_halt )
{
nos_envelope_decay_level_counter = 15 ;
}
}
nos_envelope = ( nos_constant_volume_envelope ? nos_volume_devider_period : nos_envelope_decay_level_counter ) ;
}
private static void APUOnRegister400C ( )
{
if ( apu_reg_access_w )
{
nos_volume_devider_period = ( byte ) ( apu_reg_io_db & 0xF u ) ;
nos_length_halt = ( apu_reg_io_db & 0x20 ) ! = 0 ;
nos_constant_volume_envelope = ( apu_reg_io_db & 0x10 ) ! = 0 ;
nos_envelope = ( nos_constant_volume_envelope ? nos_volume_devider_period : nos_envelope_decay_level_counter ) ;
}
}
private static void APUOnRegister400D ( )
{
}
private static void APUOnRegister400E ( )
{
if ( apu_reg_access_w )
{
nos_timer = ( ushort ) ( nos_freq_table [ SystemIndex ] [ apu_reg_io_db & 0xF ] / 2 ) ;
nos_mode = ( apu_reg_io_db & 0x80 ) = = 128 ;
}
}
private static void APUOnRegister400F ( )
{
if ( apu_reg_access_w )
{
if ( nos_length_enabled & & ! nos_ignore_reload )
{
nos_length_counter = sq_duration_table [ apu_reg_io_db > > 3 ] ;
}
if ( nos_ignore_reload )
{
nos_ignore_reload = false ;
}
nos_envelope_start_flag = true ;
}
}
private static void NOSOn4015 ( )
{
nos_length_enabled = ( apu_reg_io_db & 8 ) ! = 0 ;
if ( ! nos_length_enabled )
{
nos_length_counter = 0 ;
}
}
private static void NOSRead4015 ( )
{
if ( nos_length_counter > 0 )
{
apu_reg_io_db = ( byte ) ( ( apu_reg_io_db & 0xF7 u ) | 8 u ) ;
}
}
private static void NOSWriteState ( ref BinaryWriter bin )
{
bin . Write ( nos_length_halt ) ;
bin . Write ( nos_constant_volume_envelope ) ;
bin . Write ( nos_volume_devider_period ) ;
bin . Write ( nos_timer ) ;
bin . Write ( nos_mode ) ;
bin . Write ( nos_period_devider ) ;
bin . Write ( nos_length_enabled ) ;
bin . Write ( nos_length_counter ) ;
bin . Write ( nos_envelope_start_flag ) ;
bin . Write ( nos_envelope_devider ) ;
bin . Write ( nos_envelope_decay_level_counter ) ;
bin . Write ( nos_envelope ) ;
bin . Write ( nos_output ) ;
bin . Write ( nos_shift_reg ) ;
bin . Write ( nos_feedback ) ;
bin . Write ( nos_ignore_reload ) ;
}
private static void NOSReadState ( ref BinaryReader bin )
{
nos_length_halt = bin . ReadBoolean ( ) ;
nos_constant_volume_envelope = bin . ReadBoolean ( ) ;
nos_volume_devider_period = bin . ReadByte ( ) ;
nos_timer = bin . ReadUInt16 ( ) ;
nos_mode = bin . ReadBoolean ( ) ;
nos_period_devider = bin . ReadInt32 ( ) ;
nos_length_enabled = bin . ReadBoolean ( ) ;
nos_length_counter = bin . ReadInt32 ( ) ;
nos_envelope_start_flag = bin . ReadBoolean ( ) ;
nos_envelope_devider = bin . ReadByte ( ) ;
nos_envelope_decay_level_counter = bin . ReadByte ( ) ;
nos_envelope = bin . ReadByte ( ) ;
nos_output = bin . ReadInt32 ( ) ;
nos_shift_reg = bin . ReadInt32 ( ) ;
nos_feedback = bin . ReadInt32 ( ) ;
nos_ignore_reload = bin . ReadBoolean ( ) ;
}
private static void SQ1HardReset ( )
{
sq1_duty_cycle = 0 ;
sq1_length_halt = false ;
sq1_constant_volume_envelope = false ;
sq1_volume_devider_period = 0 ;
sq1_sweep_enable = false ;
sq1_sweep_devider_period = 0 ;
sq1_sweep_negate = false ;
sq1_sweep_shift_count = 0 ;
sq1_timer = 0 ;
sq1_period_devider = 0 ;
sq1_seqencer = 0 ;
sq1_length_enabled = false ;
sq1_length_counter = 0 ;
sq1_envelope_start_flag = false ;
sq1_envelope_devider = 0 ;
sq1_envelope_decay_level_counter = 0 ;
sq1_envelope = 0 ;
sq1_sweep_counter = 0 ;
sq1_sweep_reload = false ;
sq1_sweep_change = 0 ;
sq1_valid_freq = false ;
sq1_output = 0 ;
sq1_ignore_reload = false ;
}
private static void SQ1SoftReset ( )
{
SQ1HardReset ( ) ;
}
private static void SQ1Clock ( )
{
sq1_period_devider - - ;
if ( sq1_period_devider > 0 )
{
return ;
}
sq1_period_devider = sq1_timer + 1 ;
sq1_seqencer = ( byte ) ( ( uint ) ( sq1_seqencer + 1 ) & 7 u ) ;
if ( sq1_length_counter > 0 & & sq1_valid_freq )
{
if ( audio_sq1_outputable )
{
sq1_output = sq_duty_cycle_sequences [ sq1_duty_cycle ] [ sq1_seqencer ] * sq1_envelope ;
}
}
else
{
sq1_output = 0 ;
}
audio_signal_outputed = true ;
}
private static void SQ1ClockLength ( )
{
if ( sq1_length_counter > 0 & & ! sq1_length_halt )
{
sq1_length_counter - - ;
if ( apu_reg_access_happened & & apu_reg_io_addr = = 3 & & apu_reg_access_w )
{
sq1_ignore_reload = true ;
}
}
sq1_sweep_counter - - ;
if ( sq1_sweep_counter = = 0 )
{
sq1_sweep_counter = sq1_sweep_devider_period + 1 ;
if ( sq1_sweep_enable & & sq1_sweep_shift_count > 0 & & sq1_valid_freq )
{
sq1_sweep_change = sq1_timer > > ( int ) sq1_sweep_shift_count ;
sq1_timer + = ( sq1_sweep_negate ? ( ~ sq1_sweep_change ) : sq1_sweep_change ) ;
SQ1CalculateValidFreq ( ) ;
}
}
if ( sq1_sweep_reload )
{
sq1_sweep_counter = sq1_sweep_devider_period + 1 ;
sq1_sweep_reload = false ;
}
}
private static void SQ1ClockEnvelope ( )
{
if ( sq1_envelope_start_flag )
{
sq1_envelope_start_flag = false ;
sq1_envelope_decay_level_counter = 15 ;
sq1_envelope_devider = ( byte ) ( sq1_volume_devider_period + 1 ) ;
}
else if ( sq1_envelope_devider > 0 )
{
sq1_envelope_devider - - ;
}
else
{
sq1_envelope_devider = ( byte ) ( sq1_volume_devider_period + 1 ) ;
if ( sq1_envelope_decay_level_counter > 0 )
{
sq1_envelope_decay_level_counter - - ;
}
else if ( sq1_length_halt )
{
sq1_envelope_decay_level_counter = 15 ;
}
}
sq1_envelope = ( sq1_constant_volume_envelope ? sq1_volume_devider_period : sq1_envelope_decay_level_counter ) ;
}
private static void APUOnRegister4000 ( )
{
if ( apu_reg_access_w )
{
sq1_duty_cycle = ( byte ) ( ( apu_reg_io_db & 0xC0 ) > > 6 ) ;
sq1_volume_devider_period = ( byte ) ( apu_reg_io_db & 0xF u ) ;
sq1_length_halt = ( apu_reg_io_db & 0x20 ) ! = 0 ;
sq1_constant_volume_envelope = ( apu_reg_io_db & 0x10 ) ! = 0 ;
sq1_envelope = ( sq1_constant_volume_envelope ? sq1_volume_devider_period : sq1_envelope_decay_level_counter ) ;
}
}
private static void APUOnRegister4001 ( )
{
if ( apu_reg_access_w )
{
sq1_sweep_enable = ( apu_reg_io_db & 0x80 ) = = 128 ;
sq1_sweep_devider_period = ( byte ) ( ( uint ) ( apu_reg_io_db > > 4 ) & 7 u ) ;
sq1_sweep_negate = ( apu_reg_io_db & 8 ) = = 8 ;
sq1_sweep_shift_count = ( byte ) ( apu_reg_io_db & 7 u ) ;
sq1_sweep_reload = true ;
SQ1CalculateValidFreq ( ) ;
}
}
private static void APUOnRegister4002 ( )
{
if ( apu_reg_access_w )
{
sq1_timer = ( sq1_timer & 0xFF00 ) | apu_reg_io_db ;
SQ1CalculateValidFreq ( ) ;
}
}
private static void APUOnRegister4003 ( )
{
if ( apu_reg_access_w )
{
sq1_timer = ( sq1_timer & 0xFF ) | ( ( apu_reg_io_db & 7 ) < < 8 ) ;
if ( sq1_length_enabled & & ! sq1_ignore_reload )
{
sq1_length_counter = sq_duration_table [ apu_reg_io_db > > 3 ] ;
}
if ( sq1_ignore_reload )
{
sq1_ignore_reload = false ;
}
sq1_seqencer = 0 ;
sq1_envelope_start_flag = true ;
SQ1CalculateValidFreq ( ) ;
}
}
private static void SQ1On4015 ( )
{
sq1_length_enabled = ( apu_reg_io_db & 1 ) ! = 0 ;
if ( ! sq1_length_enabled )
{
sq1_length_counter = 0 ;
}
}
private static void SQ1Read4015 ( )
{
if ( sq1_length_counter > 0 )
{
apu_reg_io_db = ( byte ) ( ( apu_reg_io_db & 0xFE u ) | 1 u ) ;
}
}
private static void SQ1CalculateValidFreq ( )
{
sq1_valid_freq = sq1_timer > = 8 & & ( sq1_sweep_negate | | ( ( sq1_timer + ( sq1_timer > > ( int ) sq1_sweep_shift_count ) ) & 0x800 ) = = 0 ) ;
}
private static void SQ1WriteState ( ref BinaryWriter bin )
{
bin . Write ( sq1_duty_cycle ) ;
bin . Write ( sq1_length_halt ) ;
bin . Write ( sq1_constant_volume_envelope ) ;
bin . Write ( sq1_volume_devider_period ) ;
bin . Write ( sq1_sweep_enable ) ;
bin . Write ( sq1_sweep_devider_period ) ;
bin . Write ( sq1_sweep_negate ) ;
bin . Write ( sq1_sweep_shift_count ) ;
bin . Write ( sq1_timer ) ;
bin . Write ( sq1_period_devider ) ;
bin . Write ( sq1_seqencer ) ;
bin . Write ( sq1_length_enabled ) ;
bin . Write ( sq1_length_counter ) ;
bin . Write ( sq1_envelope_start_flag ) ;
bin . Write ( sq1_envelope_devider ) ;
bin . Write ( sq1_envelope_decay_level_counter ) ;
bin . Write ( sq1_envelope ) ;
bin . Write ( sq1_sweep_counter ) ;
bin . Write ( sq1_sweep_reload ) ;
bin . Write ( sq1_sweep_change ) ;
bin . Write ( sq1_valid_freq ) ;
bin . Write ( sq1_output ) ;
bin . Write ( sq1_ignore_reload ) ;
}
private static void SQ1ReadState ( ref BinaryReader bin )
{
sq1_duty_cycle = bin . ReadByte ( ) ;
sq1_length_halt = bin . ReadBoolean ( ) ;
sq1_constant_volume_envelope = bin . ReadBoolean ( ) ;
sq1_volume_devider_period = bin . ReadByte ( ) ;
sq1_sweep_enable = bin . ReadBoolean ( ) ;
sq1_sweep_devider_period = bin . ReadByte ( ) ;
sq1_sweep_negate = bin . ReadBoolean ( ) ;
sq1_sweep_shift_count = bin . ReadByte ( ) ;
sq1_timer = bin . ReadInt32 ( ) ;
sq1_period_devider = bin . ReadInt32 ( ) ;
sq1_seqencer = bin . ReadByte ( ) ;
sq1_length_enabled = bin . ReadBoolean ( ) ;
sq1_length_counter = bin . ReadInt32 ( ) ;
sq1_envelope_start_flag = bin . ReadBoolean ( ) ;
sq1_envelope_devider = bin . ReadByte ( ) ;
sq1_envelope_decay_level_counter = bin . ReadByte ( ) ;
sq1_envelope = bin . ReadByte ( ) ;
sq1_sweep_counter = bin . ReadInt32 ( ) ;
sq1_sweep_reload = bin . ReadBoolean ( ) ;
sq1_sweep_change = bin . ReadInt32 ( ) ;
sq1_valid_freq = bin . ReadBoolean ( ) ;
sq1_output = bin . ReadInt32 ( ) ;
sq1_ignore_reload = bin . ReadBoolean ( ) ;
}
private static void TRLHardReset ( )
{
trl_liner_control_flag = false ;
trl_liner_control_reload = 0 ;
trl_timer = 0 ;
trl_length_enabled = false ;
trl_length_counter = 0 ;
trl_liner_control_reload_flag = false ;
trl_liner_counter = 0 ;
trl_output = 0 ;
trl_period_devider = 0 ;
trl_step = 0 ;
trl_ignore_reload = false ;
}
private static void TRLSoftReset ( )
{
TRLHardReset ( ) ;
}
private static void TRLClock ( )
{
trl_period_devider - - ;
if ( trl_period_devider > 0 )
{
return ;
}
trl_period_devider = trl_timer + 1 ;
if ( trl_length_counter > 0 & & trl_liner_counter > 0 & & trl_timer > = 4 )
{
trl_step + + ;
trl_step & = 31 ;
if ( audio_trl_outputable )
{
trl_output = trl_step_seq [ trl_step ] ;
}
}
audio_signal_outputed = true ;
}
private static void TRLClockLength ( )
{
if ( trl_length_counter > 0 & & ! trl_liner_control_flag )
{
trl_length_counter - - ;
if ( apu_reg_access_happened & & apu_reg_io_addr = = 11 & & apu_reg_access_w )
{
trl_ignore_reload = true ;
}
}
}
private static void TRLClockEnvelope ( )
{
if ( trl_liner_control_reload_flag )
{
trl_liner_counter = trl_liner_control_reload ;
}
else if ( trl_liner_counter > 0 )
{
trl_liner_counter - - ;
}
if ( ! trl_liner_control_flag )
{
trl_liner_control_reload_flag = false ;
}
}
private static void APUOnRegister4008 ( )
{
if ( apu_reg_access_w )
{
trl_liner_control_flag = ( apu_reg_io_db & 0x80 ) = = 128 ;
trl_liner_control_reload = ( byte ) ( apu_reg_io_db & 0x7F u ) ;
}
}
private static void APUOnRegister4009 ( )
{
}
private static void APUOnRegister400A ( )
{
if ( apu_reg_access_w )
{
trl_timer = ( ushort ) ( ( trl_timer & 0x7F00 u ) | apu_reg_io_db ) ;
}
}
private static void APUOnRegister400B ( )
{
if ( apu_reg_access_w )
{
trl_timer = ( ushort ) ( ( trl_timer & 0xFF u ) | ( uint ) ( ( apu_reg_io_db & 7 ) < < 8 ) ) ;
if ( trl_length_enabled & & ! trl_ignore_reload )
{
trl_length_counter = sq_duration_table [ apu_reg_io_db > > 3 ] ;
}
if ( trl_ignore_reload )
{
trl_ignore_reload = false ;
}
trl_liner_control_reload_flag = true ;
}
}
private static void TRLOn4015 ( )
{
trl_length_enabled = ( apu_reg_io_db & 4 ) ! = 0 ;
if ( ! trl_length_enabled )
{
trl_length_counter = 0 ;
}
}
private static void TRLRead4015 ( )
{
if ( trl_length_counter > 0 )
{
apu_reg_io_db = ( byte ) ( ( apu_reg_io_db & 0xFB u ) | 4 u ) ;
}
}
private static void TRLWriteState ( ref BinaryWriter bin )
{
bin . Write ( trl_liner_control_flag ) ;
bin . Write ( trl_liner_control_reload ) ;
bin . Write ( trl_timer ) ;
bin . Write ( trl_length_enabled ) ;
bin . Write ( trl_length_counter ) ;
bin . Write ( trl_liner_control_reload_flag ) ;
bin . Write ( trl_liner_counter ) ;
bin . Write ( trl_output ) ;
bin . Write ( trl_period_devider ) ;
bin . Write ( trl_step ) ;
bin . Write ( trl_ignore_reload ) ;
}
private static void TRLReadState ( ref BinaryReader bin )
{
trl_liner_control_flag = bin . ReadBoolean ( ) ;
trl_liner_control_reload = bin . ReadByte ( ) ;
trl_timer = bin . ReadUInt16 ( ) ;
trl_length_enabled = bin . ReadBoolean ( ) ;
trl_length_counter = bin . ReadByte ( ) ;
trl_liner_control_reload_flag = bin . ReadBoolean ( ) ;
trl_liner_counter = bin . ReadByte ( ) ;
trl_output = bin . ReadInt32 ( ) ;
trl_period_devider = bin . ReadInt32 ( ) ;
trl_step = bin . ReadInt32 ( ) ;
trl_ignore_reload = bin . ReadBoolean ( ) ;
}
private static void APUInitialize ( )
{
apu_reg_update_func = new Action [ 32 ] ;
apu_reg_read_func = new Action [ 32 ] ;
apu_reg_write_func = new Action [ 32 ] ;
for ( int i = 0 ; i < 32 ; i + + )
{
apu_reg_update_func [ i ] = APUBlankAccess ;
apu_reg_read_func [ i ] = APUBlankAccess ;
apu_reg_write_func [ i ] = APUBlankAccess ;
}
apu_reg_update_func [ 0 ] = APUOnRegister4000 ;
apu_reg_update_func [ 1 ] = APUOnRegister4001 ;
apu_reg_update_func [ 2 ] = APUOnRegister4002 ;
apu_reg_update_func [ 3 ] = APUOnRegister4003 ;
apu_reg_update_func [ 4 ] = APUOnRegister4004 ;
apu_reg_update_func [ 5 ] = APUOnRegister4005 ;
apu_reg_update_func [ 6 ] = APUOnRegister4006 ;
apu_reg_update_func [ 7 ] = APUOnRegister4007 ;
apu_reg_update_func [ 8 ] = APUOnRegister4008 ;
apu_reg_update_func [ 9 ] = APUOnRegister4009 ;
apu_reg_update_func [ 10 ] = APUOnRegister400A ;
apu_reg_update_func [ 11 ] = APUOnRegister400B ;
apu_reg_update_func [ 12 ] = APUOnRegister400C ;
apu_reg_update_func [ 13 ] = APUOnRegister400D ;
apu_reg_update_func [ 14 ] = APUOnRegister400E ;
apu_reg_update_func [ 15 ] = APUOnRegister400F ;
apu_reg_update_func [ 16 ] = APUOnRegister4010 ;
apu_reg_update_func [ 17 ] = APUOnRegister4011 ;
apu_reg_update_func [ 18 ] = APUOnRegister4012 ;
apu_reg_update_func [ 19 ] = APUOnRegister4013 ;
apu_reg_update_func [ 21 ] = APUOnRegister4015 ;
apu_reg_update_func [ 22 ] = APUOnRegister4016 ;
apu_reg_update_func [ 23 ] = APUOnRegister4017 ;
apu_reg_read_func [ 21 ] = APURead4015 ;
apu_reg_read_func [ 22 ] = APURead4016 ;
apu_reg_read_func [ 23 ] = APURead4017 ;
apu_reg_write_func [ 20 ] = APUWrite4014 ;
apu_reg_write_func [ 21 ] = APUWrite4015 ;
audio_low_pass_filter_14K = new SoundLowPassFilter ( 0.00815686 ) ;
audio_high_pass_filter_90 = new SoundHighPassFilter ( 0.999835 ) ;
audio_high_pass_filter_440 = new SoundHighPassFilter ( 0.996039 ) ;
audio_dc_blocker_filter = new SoundDCBlockerFilter ( 0.995 ) ;
apu_update_playback_func = APUUpdatePlaybackWithFilters ;
}
public static void ApplyAudioSettings ( bool all = true )
{
SoundEnabled = MyNesMain . RendererSettings . Audio_SoundEnabled ;
audio_sq1_outputable = MyNesMain . RendererSettings . Audio_ChannelEnabled_SQ1 ;
audio_sq2_outputable = MyNesMain . RendererSettings . Audio_ChannelEnabled_SQ2 ;
audio_nos_outputable = MyNesMain . RendererSettings . Audio_ChannelEnabled_NOZ ;
audio_trl_outputable = MyNesMain . RendererSettings . Audio_ChannelEnabled_TRL ;
audio_dmc_outputable = MyNesMain . RendererSettings . Audio_ChannelEnabled_DMC ;
if ( apu_use_external_sound )
{
mem_board . APUApplyChannelsSettings ( ) ;
}
if ( all )
{
CalculateAudioPlaybackValues ( ) ;
}
}
private static void APUHardReset ( )
{
apu_reg_io_db = 0 ;
apu_reg_io_addr = 0 ;
apu_reg_access_happened = false ;
apu_reg_access_w = false ;
apu_seq_mode = false ;
apu_odd_cycle = true ;
apu_cycle_f_t = 0 ;
apu_cycle_e = 4 ;
apu_cycle_f = 4 ;
apu_cycle_l = 4 ;
apu_odd_l = false ;
apu_check_irq = false ;
apu_do_env = false ;
apu_do_length = false ;
switch ( Region )
{
case EmuRegion . NTSC :
cpu_speed = 1789773 ;
apu_ferq_f = 14914 ;
apu_ferq_e = 3728 ;
apu_ferq_l = 7456 ;
break ;
case EmuRegion . PALB :
cpu_speed = 1662607 ;
apu_ferq_f = 14914 ;
apu_ferq_e = 3728 ;
apu_ferq_l = 7456 ;
break ;
case EmuRegion . DENDY :
cpu_speed = 1773448 ;
apu_ferq_f = 14914 ;
apu_ferq_e = 3728 ;
apu_ferq_l = 7456 ;
break ;
}
Tracer . WriteLine ( "NES: cpu speed = " + cpu_speed ) ;
SQ1HardReset ( ) ;
SQ2HardReset ( ) ;
NOSHardReset ( ) ;
DMCHardReset ( ) ;
TRLHardReset ( ) ;
apu_irq_enabled = true ;
apu_irq_flag = false ;
reg_2004 = 8196 ;
CalculateAudioPlaybackValues ( ) ;
apu_use_external_sound = mem_board . enable_external_sound ;
if ( apu_use_external_sound )
{
Tracer . WriteInformation ( "External sound channels has been enabled on apu." ) ;
}
}
private static void APUSoftReset ( )
{
apu_reg_io_db = 0 ;
apu_reg_io_addr = 0 ;
apu_reg_access_happened = false ;
apu_reg_access_w = false ;
apu_seq_mode = false ;
apu_odd_cycle = false ;
apu_cycle_f_t = 0 ;
apu_cycle_e = 4 ;
apu_cycle_f = 4 ;
apu_cycle_l = 4 ;
apu_odd_l = false ;
apu_check_irq = false ;
apu_do_env = false ;
apu_do_length = false ;
apu_irq_enabled = true ;
apu_irq_flag = false ;
SQ1SoftReset ( ) ;
SQ2SoftReset ( ) ;
TRLSoftReset ( ) ;
NOSSoftReset ( ) ;
DMCSoftReset ( ) ;
}
private static void APUIORead ( ref ushort addr , out byte value )
{
if ( addr > = 16416 )
{
mem_board . ReadEX ( ref addr , out value ) ;
return ;
}
apu_reg_io_addr = ( byte ) ( addr & 0x1F u ) ;
apu_reg_access_happened = true ;
apu_reg_access_w = false ;
apu_reg_read_func [ apu_reg_io_addr ] ( ) ;
value = apu_reg_io_db ;
}
private static void APUIOWrite ( ref ushort addr , ref byte value )
{
if ( addr > = 16416 )
{
mem_board . WriteEX ( ref addr , ref value ) ;
return ;
}
apu_reg_io_addr = ( byte ) ( addr & 0x1F u ) ;
apu_reg_io_db = value ;
apu_reg_access_w = true ;
apu_reg_access_happened = true ;
apu_reg_write_func [ apu_reg_io_addr ] ( ) ;
}
private static void APUBlankAccess ( )
{
}
private static void APUWrite4014 ( )
{
dma_Oamaddress = ( ushort ) ( apu_reg_io_db < < 8 ) ;
AssertOAMDMA ( ) ;
}
private static void APUWrite4015 ( )
{
if ( ( apu_reg_io_db & 0x10 u ) ! = 0 )
{
if ( dmc_dmaSize = = 0 )
{
dmc_dmaSize = dmc_size_refresh ;
dmc_dmaAddr = dmc_addr_refresh ;
}
}
else
{
dmc_dmaSize = 0 ;
}
if ( ! dmc_bufferFull & & dmc_dmaSize > 0 )
{
AssertDMCDMA ( ) ;
}
}
private static void APUOnRegister4015 ( )
{
if ( apu_reg_access_w )
{
SQ1On4015 ( ) ;
SQ2On4015 ( ) ;
NOSOn4015 ( ) ;
TRLOn4015 ( ) ;
DMCOn4015 ( ) ;
}
else
{
apu_irq_flag = false ;
IRQFlags & = - 2 ;
}
}
private static void APUOnRegister4016 ( )
{
if ( ! apu_reg_access_w )
{
return ;
}
if ( inputStrobe > ( apu_reg_io_db & 1 ) )
{
if ( IsFourPlayers )
{
PORT0 = ( joypad3 . GetData ( ) < < 8 ) | joypad1 . GetData ( ) | 0x1010000 ;
PORT1 = ( joypad4 . GetData ( ) < < 8 ) | joypad2 . GetData ( ) | 0x2020000 ;
}
else
{
PORT0 = joypad1 . GetData ( ) | 0x1010100 ;
PORT1 = joypad2 . GetData ( ) | 0x2020200 ;
}
}
inputStrobe = apu_reg_io_db & 1 ;
}
private static void APUOnRegister4017 ( )
{
if ( apu_reg_access_w )
{
apu_seq_mode = ( apu_reg_io_db & 0x80 ) ! = 0 ;
apu_irq_enabled = ( apu_reg_io_db & 0x40 ) = = 0 ;
apu_cycle_e = - 1 ;
apu_cycle_l = - 1 ;
apu_cycle_f = - 1 ;
apu_odd_l = false ;
apu_do_length = apu_seq_mode ;
apu_do_env = apu_seq_mode ;
apu_check_irq = false ;
if ( ! apu_irq_enabled )
{
apu_irq_flag = false ;
IRQFlags & = - 2 ;
}
}
}
private static void APURead4015 ( )
{
apu_reg_io_db & = 32 ;
SQ1Read4015 ( ) ;
SQ2Read4015 ( ) ;
NOSRead4015 ( ) ;
TRLRead4015 ( ) ;
DMCRead4015 ( ) ;
if ( apu_irq_flag )
{
apu_reg_io_db = ( byte ) ( ( apu_reg_io_db & 0xBF u ) | 0x40 u ) ;
}
if ( apu_irq_delta_occur )
{
apu_reg_io_db = ( byte ) ( ( apu_reg_io_db & 0x7F u ) | 0x80 u ) ;
}
}
private static void APURead4016 ( )
{
apu_reg_io_db = ( byte ) ( ( uint ) PORT0 & 1 u ) ;
PORT0 > > = 1 ;
}
private static void APURead4017 ( )
{
apu_reg_io_db = ( byte ) ( ( uint ) PORT1 & 1 u ) ;
PORT1 > > = 1 ;
}
private static void APUClock ( )
{
apu_odd_cycle = ! apu_odd_cycle ;
if ( apu_do_env )
{
APUClockEnvelope ( ) ;
}
if ( apu_do_length )
{
APUClockDuration ( ) ;
}
if ( apu_odd_cycle )
{
apu_cycle_f + + ;
if ( apu_cycle_f > = apu_ferq_f )
{
apu_cycle_f = - 1 ;
apu_check_irq = true ;
apu_cycle_f_t = 3 ;
}
apu_cycle_e + + ;
if ( apu_cycle_e > = apu_ferq_e )
{
apu_cycle_e = - 1 ;
if ( apu_check_irq )
{
if ( ! apu_seq_mode )
{
apu_do_env = true ;
}
else
{
apu_cycle_e = 4 ;
}
}
else
{
apu_do_env = true ;
}
}
apu_cycle_l + + ;
if ( apu_cycle_l > = apu_ferq_l )
{
apu_odd_l = ! apu_odd_l ;
apu_cycle_l = ( apu_odd_l ? ( - 2 ) : ( - 1 ) ) ;
if ( apu_check_irq & & apu_seq_mode )
{
apu_cycle_l = 3730 ;
apu_odd_l = true ;
}
else
{
apu_do_length = true ;
}
}
SQ1Clock ( ) ;
SQ2Clock ( ) ;
NOSClock ( ) ;
if ( apu_use_external_sound )
{
mem_board . OnAPUClock ( ) ;
}
if ( apu_reg_access_happened )
{
apu_reg_access_happened = false ;
apu_reg_update_func [ apu_reg_io_addr ] ( ) ;
}
}
TRLClock ( ) ;
DMCClock ( ) ;
if ( apu_check_irq )
{
if ( ! apu_seq_mode )
{
APUCheckIRQ ( ) ;
}
apu_cycle_f_t - - ;
if ( apu_cycle_f_t = = 0 )
{
apu_check_irq = false ;
}
}
if ( apu_use_external_sound )
{
mem_board . OnAPUClockSingle ( ) ;
}
apu_update_playback_func ( ) ;
}
private static void APUClockDuration ( )
{
SQ1ClockLength ( ) ;
SQ2ClockLength ( ) ;
NOSClockLength ( ) ;
TRLClockLength ( ) ;
if ( apu_use_external_sound )
{
mem_board . OnAPUClockDuration ( ) ;
}
apu_do_length = false ;
}
private static void APUClockEnvelope ( )
{
SQ1ClockEnvelope ( ) ;
SQ2ClockEnvelope ( ) ;
NOSClockEnvelope ( ) ;
TRLClockEnvelope ( ) ;
if ( apu_use_external_sound )
{
mem_board . OnAPUClockEnvelope ( ) ;
}
apu_do_env = false ;
}
private static void APUCheckIRQ ( )
{
if ( apu_irq_enabled )
{
apu_irq_flag = true ;
}
if ( apu_irq_flag )
{
IRQFlags | = 1 ;
}
}
private static void CalculateAudioPlaybackValues ( )
{
audio_timer_ratio = ( double ) cpu_speed / ( double ) MyNesMain . RendererSettings . Audio_Frequency ;
audio_playback_peek_limit = MyNesMain . RendererSettings . Audio_InternalPeekLimit ;
audio_samples_count = MyNesMain . RendererSettings . Audio_InternalSamplesCount ;
audio_playback_amplitude = MyNesMain . RendererSettings . Audio_PlaybackAmplitude ;
audio_samples = new short [ audio_samples_count ] ;
audio_w_pos = 0 ;
audio_samples_added = 0 ;
audio_timer = 0.0 ;
audio_x = ( audio_y = 0.0 ) ;
Tracer . WriteLine ( "AUDIO: frequency = " + MyNesMain . RendererSettings . Audio_Frequency ) ;
Tracer . WriteLine ( "AUDIO: timer ratio = " + audio_timer_ratio ) ;
Tracer . WriteLine ( "AUDIO: internal samples count = " + audio_samples_count ) ;
Tracer . WriteLine ( "AUDIO: amplitude = " + audio_playback_amplitude ) ;
if ( MyNesMain . RendererSettings . Audio_EnableFilters )
{
apu_update_playback_func = APUUpdatePlaybackWithFilters ;
audio_low_pass_filter_14K = new SoundLowPassFilter ( SoundLowPassFilter . GetK ( ( double ) cpu_speed / 14000.0 , 14000.0 ) ) ;
audio_high_pass_filter_90 = new SoundHighPassFilter ( SoundHighPassFilter . GetK ( ( double ) cpu_speed / 90.0 , 90.0 ) ) ;
audio_high_pass_filter_440 = new SoundHighPassFilter ( SoundHighPassFilter . GetK ( ( double ) cpu_speed / 440.0 , 440.0 ) ) ;
}
else
{
apu_update_playback_func = APUUpdatePlaybackWithoutFilters ;
}
InitializeDACTables ( force_intitialize : false ) ;
}
public static void InitializeDACTables ( bool force_intitialize )
{
if ( audio_playback_dac_initialized & & ! force_intitialize )
{
return ;
}
int [ ] array = new int [ 5 ] ;
mix_table = new int [ 16 ] [ ] [ ] [ ] [ ] ;
for ( int i = 0 ; i < 16 ; i + + )
{
mix_table [ i ] = new int [ 16 ] [ ] [ ] [ ] ;
for ( int j = 0 ; j < 16 ; j + + )
{
mix_table [ i ] [ j ] = new int [ 16 ] [ ] [ ] ;
for ( int k = 0 ; k < 16 ; k + + )
{
mix_table [ i ] [ j ] [ k ] = new int [ 16 ] [ ] ;
for ( int l = 0 ; l < 16 ; l + + )
{
mix_table [ i ] [ j ] [ k ] [ l ] = new int [ 128 ] ;
for ( int m = 0 ; m < 128 ; m + + )
{
if ( MyNesMain . RendererSettings . Audio_UseDefaultMixer )
{
double num = 95.88 / ( 8128.0 / ( double ) ( i + j ) + 100.0 ) ;
double num2 = 159.79 / ( 1.0 / ( ( double ) k / 8227.0 + ( double ) l / 12241.0 + ( double ) m / 22638.0 ) + 100.0 ) ;
mix_table [ i ] [ j ] [ k ] [ l ] [ m ] = ( int ) Math . Ceiling ( ( num + num2 ) * audio_playback_amplitude ) ;
continue ;
}
GetPrec ( i , 255 , 2048 , out array [ 0 ] ) ;
GetPrec ( j , 255 , 2048 , out array [ 1 ] ) ;
GetPrec ( l , 255 , 2048 , out array [ 2 ] ) ;
GetPrec ( k , 255 , 2048 , out array [ 3 ] ) ;
GetPrec ( m , 255 , 2048 , out array [ 4 ] ) ;
array [ 4 ] / = 2 ;
int num3 = array [ 0 ] + array [ 1 ] + array [ 2 ] + array [ 3 ] + array [ 4 ] ;
num3 / = 5 ;
mix_table [ i ] [ j ] [ k ] [ l ] [ m ] = num3 ;
}
}
}
}
}
audio_playback_dac_initialized = true ;
}
private static void APUUpdatePlaybackWithFilters ( )
{
if ( ! SoundEnabled )
{
return ;
}
audio_x = mix_table [ sq1_output ] [ sq2_output ] [ trl_output ] [ nos_output ] [ dmc_output ] ;
if ( apu_use_external_sound )
{
audio_x = ( audio_x + mem_board . APUGetSample ( ) * audio_playback_amplitude ) / 2.0 ;
}
audio_high_pass_filter_90 . DoFiltering ( audio_x , out audio_y ) ;
audio_high_pass_filter_440 . DoFiltering ( audio_y , out audio_y ) ;
audio_low_pass_filter_14K . DoFiltering ( audio_y , out audio_y ) ;
audio_y_av + = audio_y ;
audio_y_timer + = 1.0 ;
audio_timer + = 1.0 ;
if ( ! ( audio_timer > = audio_timer_ratio ) )
{
return ;
}
if ( audio_y_timer > 0.0 )
{
audio_y = audio_y_av / audio_y_timer ;
}
else
{
audio_y = 0.0 ;
}
audio_y_av = 0.0 ;
audio_y_timer = 0.0 ;
audio_timer - = audio_timer_ratio ;
if ( audio_w_pos < audio_samples_count )
{
if ( audio_y > ( double ) audio_playback_peek_limit )
{
audio_y = audio_playback_peek_limit ;
}
if ( audio_y < ( double ) ( - audio_playback_peek_limit ) )
{
audio_y = - audio_playback_peek_limit ;
}
audio_samples [ audio_w_pos ] = ( short ) audio_y ;
if ( MyNesMain . WaveRecorder . IsRecording )
{
MyNesMain . WaveRecorder . AddSample ( ( short ) audio_y ) ;
}
audio_w_pos + + ;
audio_samples_added + + ;
}
audio_y = 0.0 ;
}
private static void APUUpdatePlaybackWithoutFilters ( )
{
if ( ! SoundEnabled )
{
return ;
}
audio_y = mix_table [ sq1_output ] [ sq2_output ] [ trl_output ] [ nos_output ] [ dmc_output ] / 2 ;
if ( apu_use_external_sound )
{
audio_y = ( audio_y + mem_board . APUGetSample ( ) * audio_playback_amplitude ) / 2.0 ;
}
audio_y_av + = audio_y ;
audio_y_timer + = 1.0 ;
audio_timer + = 1.0 ;
if ( ! ( audio_timer > = audio_timer_ratio ) )
{
return ;
}
if ( audio_y_timer > 0.0 )
{
audio_y = audio_y_av / audio_y_timer ;
}
else
{
audio_y = 0.0 ;
}
audio_y_av = 0.0 ;
audio_y_timer = 0.0 ;
audio_timer - = audio_timer_ratio ;
if ( audio_w_pos < audio_samples_count )
{
if ( audio_y > ( double ) audio_playback_peek_limit )
{
audio_y = audio_playback_peek_limit ;
}
if ( audio_y < ( double ) ( - audio_playback_peek_limit ) )
{
audio_y = - audio_playback_peek_limit ;
}
audio_samples [ audio_w_pos ] = ( short ) audio_y ;
if ( MyNesMain . WaveRecorder . IsRecording )
{
MyNesMain . WaveRecorder . AddSample ( ( short ) audio_y ) ;
}
audio_w_pos + + ;
audio_samples_added + + ;
}
audio_y = 0.0 ;
}
private static void GetPrec ( int inVal , int inMax , int outMax , out int val )
{
val = outMax * inVal / inMax ;
}
private static void APUWriteState ( ref BinaryWriter bin )
{
bin . Write ( apu_reg_io_db ) ;
bin . Write ( apu_reg_io_addr ) ;
bin . Write ( apu_reg_access_happened ) ;
bin . Write ( apu_reg_access_w ) ;
bin . Write ( apu_odd_cycle ) ;
bin . Write ( apu_irq_enabled ) ;
bin . Write ( apu_irq_flag ) ;
bin . Write ( apu_irq_delta_occur ) ;
bin . Write ( apu_seq_mode ) ;
bin . Write ( apu_ferq_f ) ;
bin . Write ( apu_ferq_l ) ;
bin . Write ( apu_ferq_e ) ;
bin . Write ( apu_cycle_f ) ;
bin . Write ( apu_cycle_e ) ;
bin . Write ( apu_cycle_l ) ;
bin . Write ( apu_odd_l ) ;
bin . Write ( apu_cycle_f_t ) ;
bin . Write ( apu_check_irq ) ;
bin . Write ( apu_do_env ) ;
bin . Write ( apu_do_length ) ;
SQ1WriteState ( ref bin ) ;
SQ2WriteState ( ref bin ) ;
NOSWriteState ( ref bin ) ;
TRLWriteState ( ref bin ) ;
DMCWriteState ( ref bin ) ;
}
private static void APUReadState ( ref BinaryReader bin )
{
apu_reg_io_db = bin . ReadByte ( ) ;
apu_reg_io_addr = bin . ReadByte ( ) ;
apu_reg_access_happened = bin . ReadBoolean ( ) ;
apu_reg_access_w = bin . ReadBoolean ( ) ;
apu_odd_cycle = bin . ReadBoolean ( ) ;
apu_irq_enabled = bin . ReadBoolean ( ) ;
apu_irq_flag = bin . ReadBoolean ( ) ;
apu_irq_delta_occur = bin . ReadBoolean ( ) ;
apu_seq_mode = bin . ReadBoolean ( ) ;
apu_ferq_f = bin . ReadInt32 ( ) ;
apu_ferq_l = bin . ReadInt32 ( ) ;
apu_ferq_e = bin . ReadInt32 ( ) ;
apu_cycle_f = bin . ReadInt32 ( ) ;
apu_cycle_e = bin . ReadInt32 ( ) ;
apu_cycle_l = bin . ReadInt32 ( ) ;
apu_odd_l = bin . ReadBoolean ( ) ;
apu_cycle_f_t = bin . ReadInt32 ( ) ;
apu_check_irq = bin . ReadBoolean ( ) ;
apu_do_env = bin . ReadBoolean ( ) ;
apu_do_length = bin . ReadBoolean ( ) ;
SQ1ReadState ( ref bin ) ;
SQ2ReadState ( ref bin ) ;
NOSReadState ( ref bin ) ;
TRLReadState ( ref bin ) ;
DMCReadState ( ref bin ) ;
}
private static byte register_pb ( )
{
return ( byte ) ( ( cpu_flag_n ? 128 u : 0 u ) | ( cpu_flag_v ? 64 u : 0 u ) | ( cpu_flag_d ? 8 u : 0 u ) | ( cpu_flag_i ? 4 u : 0 u ) | ( cpu_flag_z ? 2 u : 0 u ) | ( cpu_flag_c ? 1 u : 0 u ) | 0x30 u ) ;
}
private static void CPUInitialize ( )
{
cpu_addressings = new Action [ 256 ]
{
Imp____ , IndX_R_ , ImA____ , IndX_W_ , Zpg_R__ , Zpg_R__ , Zpg_RW_ , Zpg_W__ , ImA____ , Imm____ ,
ImA____ , Imm____ , Abs_R__ , Abs_R__ , Abs_RW_ , Abs_W__ , Imp____ , IndY_R_ , Imp____ , IndY_W_ ,
ZpgX_R_ , ZpgX_R_ , ZpgX_RW , ZpgX_W_ , ImA____ , AbsY_R_ , ImA____ , AbsY_W_ , AbsX_R_ , AbsX_R_ ,
AbsX_RW , AbsX_W_ , Imp____ , IndX_R_ , ImA____ , IndX_W_ , Zpg_R__ , Zpg_R__ , Zpg_RW_ , Zpg_W__ ,
ImA____ , Imm____ , ImA____ , Imm____ , Abs_R__ , Abs_R__ , Abs_RW_ , Abs_W__ , Imp____ , IndY_R_ ,
Imp____ , IndY_W_ , ZpgX_R_ , ZpgX_R_ , ZpgX_RW , ZpgX_W_ , ImA____ , AbsY_R_ , ImA____ , AbsY_W_ ,
AbsX_R_ , AbsX_R_ , AbsX_RW , AbsX_W_ , ImA____ , IndX_R_ , ImA____ , IndX_W_ , Zpg_R__ , Zpg_R__ ,
Zpg_RW_ , Zpg_W__ , ImA____ , Imm____ , ImA____ , Imm____ , Abs_W__ , Abs_R__ , Abs_RW_ , Abs_W__ ,
Imp____ , IndY_R_ , Imp____ , IndY_W_ , ZpgX_R_ , ZpgX_R_ , ZpgX_RW , ZpgX_W_ , ImA____ , AbsY_R_ ,
ImA____ , AbsY_W_ , AbsX_R_ , AbsX_R_ , AbsX_RW , AbsX_W_ , ImA____ , IndX_R_ , ImA____ , IndX_W_ ,
Zpg_R__ , Zpg_R__ , Zpg_RW_ , Zpg_W__ , ImA____ , Imm____ , ImA____ , Imm____ , Imp____ , Abs_R__ ,
Abs_RW_ , Abs_W__ , Imp____ , IndY_R_ , Imp____ , IndY_W_ , ZpgX_R_ , ZpgX_R_ , ZpgX_RW , ZpgX_W_ ,
ImA____ , AbsY_R_ , ImA____ , AbsY_W_ , AbsX_R_ , AbsX_R_ , AbsX_RW , AbsX_W_ , Imm____ , IndX_W_ ,
Imm____ , IndX_W_ , Zpg_W__ , Zpg_W__ , Zpg_W__ , Zpg_W__ , ImA____ , Imm____ , ImA____ , Imm____ ,
Abs_W__ , Abs_W__ , Abs_W__ , Abs_W__ , Imp____ , IndY_W_ , Imp____ , IndY_W_ , ZpgX_W_ , ZpgX_W_ ,
ZpgY_W_ , ZpgY_W_ , ImA____ , AbsY_W_ , ImA____ , AbsY_W_ , Abs_W__ , AbsX_W_ , Abs_W__ , AbsY_W_ ,
Imm____ , IndX_R_ , Imm____ , IndX_R_ , Zpg_R__ , Zpg_R__ , Zpg_R__ , Zpg_R__ , ImA____ , Imm____ ,
ImA____ , Imm____ , Abs_R__ , Abs_R__ , Abs_R__ , Abs_R__ , Imp____ , IndY_R_ , Imp____ , IndY_R_ ,
ZpgX_R_ , ZpgX_R_ , ZpgY_R_ , ZpgY_R_ , ImA____ , AbsY_R_ , ImA____ , AbsY_R_ , AbsX_R_ , AbsX_R_ ,
AbsY_R_ , AbsY_R_ , Imm____ , IndX_R_ , Imm____ , IndX_R_ , Zpg_R__ , Zpg_R__ , Zpg_RW_ , Zpg_R__ ,
ImA____ , Imm____ , ImA____ , Imm____ , Abs_R__ , Abs_R__ , Abs_RW_ , Abs_R__ , Imp____ , IndY_R_ ,
Imp____ , IndY_RW , ZpgX_R_ , ZpgX_R_ , ZpgX_RW , ZpgX_RW , ImA____ , AbsY_R_ , ImA____ , AbsY_RW ,
AbsX_R_ , AbsX_R_ , AbsX_RW , AbsX_RW , Imm____ , IndX_R_ , Imm____ , IndX_W_ , Zpg_R__ , Zpg_R__ ,
Zpg_RW_ , Zpg_W__ , ImA____ , Imm____ , ImA____ , Imm____ , Abs_R__ , Abs_R__ , Abs_RW_ , Abs_W__ ,
Imp____ , IndY_R_ , Imp____ , IndY_W_ , ZpgX_R_ , ZpgX_R_ , ZpgX_RW , ZpgX_W_ , ImA____ , AbsY_R_ ,
ImA____ , AbsY_W_ , AbsX_R_ , AbsX_R_ , AbsX_RW , AbsX_W_
} ;
cpu_instructions = new Action [ 256 ]
{
BRK__ , ORA__ , NOP__ , SLO__ , NOP__ , ORA__ , ASL_M , SLO__ , PHP__ , ORA__ ,
ASL_A , ANC__ , NOP__ , ORA__ , ASL_M , SLO__ , BPL__ , ORA__ , NOP__ , SLO__ ,
NOP__ , ORA__ , ASL_M , SLO__ , CLC__ , ORA__ , NOP__ , SLO__ , NOP__ , ORA__ ,
ASL_M , SLO__ , JSR__ , AND__ , NOP__ , RLA__ , BIT__ , AND__ , ROL_M , RLA__ ,
PLP__ , AND__ , ROL_A , ANC__ , BIT__ , AND__ , ROL_M , RLA__ , BMI__ , AND__ ,
NOP__ , RLA__ , NOP__ , AND__ , ROL_M , RLA__ , SEC__ , AND__ , NOP__ , RLA__ ,
NOP__ , AND__ , ROL_M , RLA__ , RTI__ , EOR__ , NOP__ , SRE__ , NOP__ , EOR__ ,
LSR_M , SRE__ , PHA__ , EOR__ , LSR_A , ALR__ , JMP__ , EOR__ , LSR_M , SRE__ ,
BVC__ , EOR__ , NOP__ , SRE__ , NOP__ , EOR__ , LSR_M , SRE__ , CLI__ , EOR__ ,
NOP__ , SRE__ , NOP__ , EOR__ , LSR_M , SRE__ , RTS__ , ADC__ , NOP__ , RRA__ ,
NOP__ , ADC__ , ROR_M , RRA__ , PLA__ , ADC__ , ROR_A , ARR__ , JMP_I , ADC__ ,
ROR_M , RRA__ , BVS__ , ADC__ , NOP__ , RRA__ , NOP__ , ADC__ , ROR_M , RRA__ ,
SEI__ , ADC__ , NOP__ , RRA__ , NOP__ , ADC__ , ROR_M , RRA__ , NOP__ , STA__ ,
NOP__ , SAX__ , STY__ , STA__ , STX__ , SAX__ , DEY__ , NOP__ , TXA__ , XAA__ ,
STY__ , STA__ , STX__ , SAX__ , BCC__ , STA__ , NOP__ , AHX__ , STY__ , STA__ ,
STX__ , SAX__ , TYA__ , STA__ , TXS__ , XAS__ , SHY__ , STA__ , SHX__ , AHX__ ,
LDY__ , LDA__ , LDX__ , LAX__ , LDY__ , LDA__ , LDX__ , LAX__ , TAY__ , LDA__ ,
TAX__ , LAX__ , LDY__ , LDA__ , LDX__ , LAX__ , BCS__ , LDA__ , NOP__ , LAX__ ,
LDY__ , LDA__ , LDX__ , LAX__ , CLV__ , LDA__ , TSX__ , LAR__ , LDY__ , LDA__ ,
LDX__ , LAX__ , CPY__ , CMP__ , NOP__ , DCP__ , CPY__ , CMP__ , DEC__ , DCP__ ,
INY__ , CMP__ , DEX__ , AXS__ , CPY__ , CMP__ , DEC__ , DCP__ , BNE__ , CMP__ ,
NOP__ , DCP__ , NOP__ , CMP__ , DEC__ , DCP__ , CLD__ , CMP__ , NOP__ , DCP__ ,
NOP__ , CMP__ , DEC__ , DCP__ , CPX__ , SBC__ , NOP__ , ISC__ , CPX__ , SBC__ ,
INC__ , ISC__ , INX__ , SBC__ , NOP__ , SBC__ , CPX__ , SBC__ , INC__ , ISC__ ,
BEQ__ , SBC__ , NOP__ , ISC__ , NOP__ , SBC__ , INC__ , ISC__ , SED__ , SBC__ ,
NOP__ , ISC__ , NOP__ , SBC__ , INC__ , ISC__
} ;
}
private static void CPUClock ( )
{
Read ( ref cpu_reg_pc . v , out cpu_opcode ) ;
cpu_reg_pc . v + + ;
cpu_addressings [ cpu_opcode ] ( ) ;
cpu_instructions [ cpu_opcode ] ( ) ;
if ( CPU_IRQ_PIN | | CPU_NMI_PIN )
{
Read ( ref cpu_reg_pc . v , out cpu_dummy ) ;
Read ( ref cpu_reg_pc . v , out cpu_dummy ) ;
Interrupt ( ) ;
}
}
private static void CPUHardReset ( )
{
cpu_reg_a = 0 ;
cpu_reg_x = 0 ;
cpu_reg_y = 0 ;
cpu_reg_sp . l = 253 ;
cpu_reg_sp . h = 1 ;
ushort addr = 65532 ;
mem_board . ReadPRG ( ref addr , out cpu_reg_pc . l ) ;
addr + + ;
mem_board . ReadPRG ( ref addr , out cpu_reg_pc . h ) ;
register_p = 0 ;
cpu_flag_i = true ;
cpu_reg_ea . v = 0 ;
cpu_opcode = 0 ;
CPU_IRQ_PIN = false ;
CPU_NMI_PIN = false ;
cpu_suspend_nmi = false ;
cpu_suspend_irq = false ;
IRQFlags = 0 ;
}
private static void CPUSoftReset ( )
{
cpu_flag_i = true ;
cpu_reg_sp . v - = 3 ;
ushort addr = 65532 ;
Read ( ref addr , out cpu_reg_pc . l ) ;
addr + + ;
Read ( ref addr , out cpu_reg_pc . h ) ;
}
private static void Imp____ ( )
{
}
private static void IndX_R_ ( )
{
temp_add . h = 0 ;
Read ( ref cpu_reg_pc . v , out temp_add . l ) ;
cpu_reg_pc . v + + ;
Read ( ref temp_add . v , out cpu_dummy ) ;
temp_add . l + = cpu_reg_x ;
Read ( ref temp_add . v , out cpu_reg_ea . l ) ;
temp_add . l + + ;
Read ( ref temp_add . v , out cpu_reg_ea . h ) ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
private static void IndX_W_ ( )
{
temp_add . h = 0 ;
Read ( ref cpu_reg_pc . v , out temp_add . l ) ;
cpu_reg_pc . v + + ;
Read ( ref temp_add . v , out cpu_dummy ) ;
temp_add . l + = cpu_reg_x ;
Read ( ref temp_add . v , out cpu_reg_ea . l ) ;
temp_add . l + + ;
Read ( ref temp_add . v , out cpu_reg_ea . h ) ;
}
private static void IndX_RW ( )
{
temp_add . h = 0 ;
Read ( ref cpu_reg_pc . v , out temp_add . l ) ;
cpu_reg_pc . v + + ;
Read ( ref temp_add . v , out cpu_dummy ) ;
temp_add . l + = cpu_reg_x ;
Read ( ref temp_add . v , out cpu_reg_ea . l ) ;
temp_add . l + + ;
Read ( ref temp_add . v , out cpu_reg_ea . h ) ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
private static void IndY_R_ ( )
{
temp_add . h = 0 ;
Read ( ref cpu_reg_pc . v , out temp_add . l ) ;
cpu_reg_pc . v + + ;
Read ( ref temp_add . v , out cpu_reg_ea . l ) ;
temp_add . l + + ;
Read ( ref temp_add . v , out cpu_reg_ea . h ) ;
cpu_reg_ea . l + = cpu_reg_y ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
if ( cpu_reg_ea . l < cpu_reg_y )
{
cpu_reg_ea . h + + ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
}
private static void IndY_W_ ( )
{
temp_add . h = 0 ;
Read ( ref cpu_reg_pc . v , out temp_add . l ) ;
cpu_reg_pc . v + + ;
Read ( ref temp_add . v , out cpu_reg_ea . l ) ;
temp_add . l + + ;
Read ( ref temp_add . v , out cpu_reg_ea . h ) ;
cpu_reg_ea . l + = cpu_reg_y ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
if ( cpu_reg_ea . l < cpu_reg_y )
{
cpu_reg_ea . h + + ;
}
}
private static void IndY_RW ( )
{
temp_add . h = 0 ;
Read ( ref cpu_reg_pc . v , out temp_add . l ) ;
cpu_reg_pc . v + + ;
Read ( ref temp_add . v , out cpu_reg_ea . l ) ;
temp_add . l + + ;
Read ( ref temp_add . v , out cpu_reg_ea . h ) ;
cpu_reg_ea . l + = cpu_reg_y ;
Read ( ref cpu_reg_ea . v , out cpu_dummy ) ;
if ( cpu_reg_ea . l < cpu_reg_y )
{
cpu_reg_ea . h + + ;
}
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
private static void Zpg_R__ ( )
{
cpu_reg_ea . h = 0 ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
private static void Zpg_W__ ( )
{
cpu_reg_ea . h = 0 ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
}
private static void Zpg_RW_ ( )
{
cpu_reg_ea . h = 0 ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
private static void ZpgX_R_ ( )
{
cpu_reg_ea . h = 0 ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_ea . v , out cpu_dummy ) ;
cpu_reg_ea . l + = cpu_reg_x ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
private static void ZpgX_W_ ( )
{
cpu_reg_ea . h = 0 ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_ea . v , out cpu_dummy ) ;
cpu_reg_ea . l + = cpu_reg_x ;
}
private static void ZpgX_RW ( )
{
cpu_reg_ea . h = 0 ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_ea . v , out cpu_dummy ) ;
cpu_reg_ea . l + = cpu_reg_x ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
private static void ZpgY_R_ ( )
{
cpu_reg_ea . h = 0 ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_ea . v , out cpu_dummy ) ;
cpu_reg_ea . l + = cpu_reg_y ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
private static void ZpgY_W_ ( )
{
cpu_reg_ea . h = 0 ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_ea . v , out cpu_dummy ) ;
cpu_reg_ea . l + = cpu_reg_y ;
}
private static void ZpgY_RW ( )
{
cpu_reg_ea . h = 0 ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_ea . v , out cpu_dummy ) ;
cpu_reg_ea . l + = cpu_reg_y ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
private static void Imm____ ( )
{
Read ( ref cpu_reg_pc . v , out cpu_m ) ;
cpu_reg_pc . v + + ;
}
private static void ImA____ ( )
{
Read ( ref cpu_reg_pc . v , out cpu_dummy ) ;
}
private static void Abs_R__ ( )
{
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . h ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
private static void Abs_W__ ( )
{
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . h ) ;
cpu_reg_pc . v + + ;
}
private static void Abs_RW_ ( )
{
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . h ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
private static void AbsX_R_ ( )
{
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . h ) ;
cpu_reg_pc . v + + ;
cpu_reg_ea . l + = cpu_reg_x ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
if ( cpu_reg_ea . l < cpu_reg_x )
{
cpu_reg_ea . h + + ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
}
private static void AbsX_W_ ( )
{
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . h ) ;
cpu_reg_pc . v + + ;
cpu_reg_ea . l + = cpu_reg_x ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
if ( cpu_reg_ea . l < cpu_reg_x )
{
cpu_reg_ea . h + + ;
}
}
private static void AbsX_RW ( )
{
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . h ) ;
cpu_reg_pc . v + + ;
cpu_reg_ea . l + = cpu_reg_x ;
Read ( ref cpu_reg_ea . v , out cpu_dummy ) ;
if ( cpu_reg_ea . l < cpu_reg_x )
{
cpu_reg_ea . h + + ;
}
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
private static void AbsY_R_ ( )
{
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . h ) ;
cpu_reg_pc . v + + ;
cpu_reg_ea . l + = cpu_reg_y ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
if ( cpu_reg_ea . l < cpu_reg_y )
{
cpu_reg_ea . h + + ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
}
private static void AbsY_W_ ( )
{
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . h ) ;
cpu_reg_pc . v + + ;
cpu_reg_ea . l + = cpu_reg_y ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
if ( cpu_reg_ea . l < cpu_reg_y )
{
cpu_reg_ea . h + + ;
}
}
private static void AbsY_RW ( )
{
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . h ) ;
cpu_reg_pc . v + + ;
cpu_reg_ea . l + = cpu_reg_y ;
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
if ( cpu_reg_ea . l < cpu_reg_y )
{
cpu_reg_ea . h + + ;
}
Read ( ref cpu_reg_ea . v , out cpu_m ) ;
}
private static void Interrupt ( )
{
Push ( ref cpu_reg_pc . h ) ;
Push ( ref cpu_reg_pc . l ) ;
cpu_dummy = ( ( cpu_opcode = = 0 ) ? register_pb ( ) : register_p ) ;
Push ( ref cpu_dummy ) ;
temp_add . v = InterruptVector ;
cpu_suspend_nmi = true ;
cpu_flag_i = true ;
CPU_NMI_PIN = false ;
Read ( ref temp_add . v , out cpu_reg_pc . l ) ;
temp_add . v + + ;
Read ( ref temp_add . v , out cpu_reg_pc . h ) ;
cpu_suspend_nmi = false ;
}
private static void Branch ( ref bool condition )
{
Read ( ref cpu_reg_pc . v , out cpu_byte_temp ) ;
cpu_reg_pc . v + + ;
if ( ! condition )
{
return ;
}
cpu_suspend_irq = true ;
Read ( ref cpu_reg_pc . v , out cpu_dummy ) ;
cpu_reg_pc . l + = cpu_byte_temp ;
cpu_suspend_irq = false ;
if ( cpu_byte_temp > = 128 )
{
if ( cpu_reg_pc . l > = cpu_byte_temp )
{
Read ( ref cpu_reg_pc . v , out cpu_dummy ) ;
cpu_reg_pc . h - - ;
}
}
else if ( cpu_reg_pc . l < cpu_byte_temp )
{
Read ( ref cpu_reg_pc . v , out cpu_dummy ) ;
cpu_reg_pc . h + + ;
}
}
private static void Push ( ref byte val )
{
Write ( ref cpu_reg_sp . v , ref val ) ;
cpu_reg_sp . l - - ;
}
private static void Pull ( out byte val )
{
cpu_reg_sp . l + + ;
Read ( ref cpu_reg_sp . v , out val ) ;
}
private static void ADC__ ( )
{
cpu_int_temp = cpu_reg_a + cpu_m + ( cpu_flag_c ? 1 : 0 ) ;
cpu_flag_v = ( ( cpu_int_temp ^ cpu_reg_a ) & ( cpu_int_temp ^ cpu_m ) & 0x80 ) ! = 0 ;
cpu_flag_n = ( cpu_int_temp & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_int_temp & 0xFF ) = = 0 ;
cpu_flag_c = cpu_int_temp > > 8 ! = 0 ;
cpu_reg_a = ( byte ) ( ( uint ) cpu_int_temp & 0xFF u ) ;
}
private static void AHX__ ( )
{
cpu_byte_temp = ( byte ) ( ( uint ) ( cpu_reg_a & cpu_reg_x ) & 7 u ) ;
Write ( ref cpu_reg_ea . v , ref cpu_byte_temp ) ;
}
private static void ALR__ ( )
{
cpu_reg_a & = cpu_m ;
cpu_flag_c = ( cpu_reg_a & 1 ) ! = 0 ;
cpu_reg_a > > = 1 ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) ! = 0 ;
cpu_flag_z = cpu_reg_a = = 0 ;
}
private static void ANC__ ( )
{
cpu_reg_a & = cpu_m ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) ! = 0 ;
cpu_flag_z = cpu_reg_a = = 0 ;
cpu_flag_c = ( cpu_reg_a & 0x80 ) ! = 0 ;
}
private static void AND__ ( )
{
cpu_reg_a & = cpu_m ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) = = 128 ;
cpu_flag_z = cpu_reg_a = = 0 ;
}
private static void ARR__ ( )
{
cpu_reg_a = ( byte ) ( ( uint ) ( ( cpu_m & cpu_reg_a ) > > 1 ) | ( cpu_flag_c ? 128 u : 0 u ) ) ;
cpu_flag_z = ( cpu_reg_a & 0xFF ) = = 0 ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) ! = 0 ;
cpu_flag_c = ( cpu_reg_a & 0x40 ) ! = 0 ;
cpu_flag_v = ( ( ( cpu_reg_a < < 1 ) ^ cpu_reg_a ) & 0x40 ) ! = 0 ;
}
private static void AXS__ ( )
{
cpu_int_temp = ( cpu_reg_a & cpu_reg_x ) - cpu_m ;
cpu_flag_n = ( cpu_int_temp & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_int_temp & 0xFF ) = = 0 ;
cpu_flag_c = ~ cpu_int_temp > > 8 ! = 0 ;
cpu_reg_x = ( byte ) ( ( uint ) cpu_int_temp & 0xFF u ) ;
}
private static void ASL_M ( )
{
cpu_flag_c = ( cpu_m & 0x80 ) = = 128 ;
Write ( ref cpu_reg_ea . v , ref cpu_m ) ;
cpu_m = ( byte ) ( ( uint ) ( cpu_m < < 1 ) & 0xFE u ) ;
Write ( ref cpu_reg_ea . v , ref cpu_m ) ;
cpu_flag_n = ( cpu_m & 0x80 ) = = 128 ;
cpu_flag_z = cpu_m = = 0 ;
}
private static void ASL_A ( )
{
cpu_flag_c = ( cpu_reg_a & 0x80 ) = = 128 ;
cpu_reg_a = ( byte ) ( ( uint ) ( cpu_reg_a < < 1 ) & 0xFE u ) ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) = = 128 ;
cpu_flag_z = cpu_reg_a = = 0 ;
}
private static void BCC__ ( )
{
cpu_bool_tmp = ! cpu_flag_c ;
Branch ( ref cpu_bool_tmp ) ;
}
private static void BCS__ ( )
{
Branch ( ref cpu_flag_c ) ;
}
private static void BEQ__ ( )
{
Branch ( ref cpu_flag_z ) ;
}
private static void BIT__ ( )
{
cpu_flag_n = ( cpu_m & 0x80 ) ! = 0 ;
cpu_flag_v = ( cpu_m & 0x40 ) ! = 0 ;
cpu_flag_z = ( cpu_m & cpu_reg_a ) = = 0 ;
}
private static void BRK__ ( )
{
Read ( ref cpu_reg_pc . v , out cpu_dummy ) ;
cpu_reg_pc . v + + ;
Interrupt ( ) ;
}
private static void BPL__ ( )
{
cpu_bool_tmp = ! cpu_flag_n ;
Branch ( ref cpu_bool_tmp ) ;
}
private static void BNE__ ( )
{
cpu_bool_tmp = ! cpu_flag_z ;
Branch ( ref cpu_bool_tmp ) ;
}
private static void BMI__ ( )
{
Branch ( ref cpu_flag_n ) ;
}
private static void BVC__ ( )
{
cpu_bool_tmp = ! cpu_flag_v ;
Branch ( ref cpu_bool_tmp ) ;
}
private static void BVS__ ( )
{
Branch ( ref cpu_flag_v ) ;
}
private static void SED__ ( )
{
cpu_flag_d = true ;
}
private static void CLC__ ( )
{
cpu_flag_c = false ;
}
private static void CLD__ ( )
{
cpu_flag_d = false ;
}
private static void CLV__ ( )
{
cpu_flag_v = false ;
}
private static void CMP__ ( )
{
cpu_int_temp = cpu_reg_a - cpu_m ;
cpu_flag_n = ( cpu_int_temp & 0x80 ) = = 128 ;
cpu_flag_c = cpu_reg_a > = cpu_m ;
cpu_flag_z = cpu_int_temp = = 0 ;
}
private static void CPX__ ( )
{
cpu_int_temp = cpu_reg_x - cpu_m ;
cpu_flag_n = ( cpu_int_temp & 0x80 ) = = 128 ;
cpu_flag_c = cpu_reg_x > = cpu_m ;
cpu_flag_z = cpu_int_temp = = 0 ;
}
private static void CPY__ ( )
{
cpu_int_temp = cpu_reg_y - cpu_m ;
cpu_flag_n = ( cpu_int_temp & 0x80 ) = = 128 ;
cpu_flag_c = cpu_reg_y > = cpu_m ;
cpu_flag_z = cpu_int_temp = = 0 ;
}
private static void CLI__ ( )
{
cpu_flag_i = false ;
}
private static void DCP__ ( )
{
Write ( ref cpu_reg_ea . v , ref cpu_m ) ;
cpu_m - - ;
Write ( ref cpu_reg_ea . v , ref cpu_m ) ;
cpu_int_temp = cpu_reg_a - cpu_m ;
cpu_flag_n = ( cpu_int_temp & 0x80 ) ! = 0 ;
cpu_flag_z = cpu_int_temp = = 0 ;
cpu_flag_c = ~ cpu_int_temp > > 8 ! = 0 ;
}
private static void DEC__ ( )
{
Write ( ref cpu_reg_ea . v , ref cpu_m ) ;
cpu_m - - ;
Write ( ref cpu_reg_ea . v , ref cpu_m ) ;
cpu_flag_n = ( cpu_m & 0x80 ) = = 128 ;
cpu_flag_z = cpu_m = = 0 ;
}
private static void DEY__ ( )
{
cpu_reg_y - - ;
cpu_flag_z = cpu_reg_y = = 0 ;
cpu_flag_n = ( cpu_reg_y & 0x80 ) = = 128 ;
}
private static void DEX__ ( )
{
cpu_reg_x - - ;
cpu_flag_z = cpu_reg_x = = 0 ;
cpu_flag_n = ( cpu_reg_x & 0x80 ) = = 128 ;
}
private static void EOR__ ( )
{
cpu_reg_a ^ = cpu_m ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) = = 128 ;
cpu_flag_z = cpu_reg_a = = 0 ;
}
private static void INC__ ( )
{
Write ( ref cpu_reg_ea . v , ref cpu_m ) ;
cpu_m + + ;
Write ( ref cpu_reg_ea . v , ref cpu_m ) ;
cpu_flag_n = ( cpu_m & 0x80 ) = = 128 ;
cpu_flag_z = cpu_m = = 0 ;
}
private static void INX__ ( )
{
cpu_reg_x + + ;
cpu_flag_z = cpu_reg_x = = 0 ;
cpu_flag_n = ( cpu_reg_x & 0x80 ) = = 128 ;
}
private static void INY__ ( )
{
cpu_reg_y + + ;
cpu_flag_n = ( cpu_reg_y & 0x80 ) = = 128 ;
cpu_flag_z = cpu_reg_y = = 0 ;
}
private static void ISC__ ( )
{
Read ( ref cpu_reg_ea . v , out cpu_byte_temp ) ;
Write ( ref cpu_reg_ea . v , ref cpu_byte_temp ) ;
cpu_byte_temp + + ;
Write ( ref cpu_reg_ea . v , ref cpu_byte_temp ) ;
cpu_int_temp = cpu_byte_temp ^ 0xFF ;
cpu_int_temp1 = cpu_reg_a + cpu_int_temp + ( cpu_flag_c ? 1 : 0 ) ;
cpu_flag_n = ( cpu_int_temp1 & 0x80 ) ! = 0 ;
cpu_flag_v = ( ( cpu_int_temp1 ^ cpu_reg_a ) & ( cpu_int_temp1 ^ cpu_int_temp ) & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_int_temp1 & 0xFF ) = = 0 ;
cpu_flag_c = cpu_int_temp1 > > 8 ! = 0 ;
cpu_reg_a = ( byte ) ( ( uint ) cpu_int_temp1 & 0xFF u ) ;
}
private static void JMP__ ( )
{
cpu_reg_pc . v = cpu_reg_ea . v ;
}
private static void JMP_I ( )
{
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . h ) ;
Read ( ref cpu_reg_ea . v , out cpu_reg_pc . l ) ;
cpu_reg_ea . l + + ;
Read ( ref cpu_reg_ea . v , out cpu_reg_pc . h ) ;
}
private static void JSR__ ( )
{
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . l ) ;
cpu_reg_pc . v + + ;
Write ( ref cpu_reg_sp . v , ref cpu_reg_ea . l ) ;
Push ( ref cpu_reg_pc . h ) ;
Push ( ref cpu_reg_pc . l ) ;
Read ( ref cpu_reg_pc . v , out cpu_reg_ea . h ) ;
cpu_reg_pc . v = cpu_reg_ea . v ;
}
private static void LAR__ ( )
{
cpu_reg_sp . l & = cpu_m ;
cpu_reg_a = cpu_reg_sp . l ;
cpu_reg_x = cpu_reg_sp . l ;
cpu_flag_n = ( cpu_reg_sp . l & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_reg_sp . l & 0xFF ) = = 0 ;
}
private static void LAX__ ( )
{
cpu_reg_x = ( cpu_reg_a = cpu_m ) ;
cpu_flag_n = ( cpu_reg_x & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_reg_x & 0xFF ) = = 0 ;
}
private static void LDA__ ( )
{
cpu_reg_a = cpu_m ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) = = 128 ;
cpu_flag_z = cpu_reg_a = = 0 ;
}
private static void LDX__ ( )
{
cpu_reg_x = cpu_m ;
cpu_flag_n = ( cpu_reg_x & 0x80 ) = = 128 ;
cpu_flag_z = cpu_reg_x = = 0 ;
}
private static void LDY__ ( )
{
cpu_reg_y = cpu_m ;
cpu_flag_n = ( cpu_reg_y & 0x80 ) = = 128 ;
cpu_flag_z = cpu_reg_y = = 0 ;
}
private static void LSR_A ( )
{
cpu_flag_c = ( cpu_reg_a & 1 ) = = 1 ;
cpu_reg_a > > = 1 ;
cpu_flag_z = cpu_reg_a = = 0 ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) ! = 0 ;
}
private static void LSR_M ( )
{
cpu_flag_c = ( cpu_m & 1 ) = = 1 ;
Write ( ref cpu_reg_ea . v , ref cpu_m ) ;
cpu_m > > = 1 ;
Write ( ref cpu_reg_ea . v , ref cpu_m ) ;
cpu_flag_z = cpu_m = = 0 ;
cpu_flag_n = ( cpu_m & 0x80 ) ! = 0 ;
}
private static void NOP__ ( )
{
}
private static void ORA__ ( )
{
cpu_reg_a | = cpu_m ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) = = 128 ;
cpu_flag_z = cpu_reg_a = = 0 ;
}
private static void PHA__ ( )
{
Push ( ref cpu_reg_a ) ;
}
private static void PHP__ ( )
{
cpu_dummy = register_pb ( ) ;
Push ( ref cpu_dummy ) ;
}
private static void PLA__ ( )
{
Read ( ref cpu_reg_sp . v , out cpu_dummy ) ;
Pull ( out cpu_reg_a ) ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) = = 128 ;
cpu_flag_z = cpu_reg_a = = 0 ;
}
private static void PLP__ ( )
{
Read ( ref cpu_reg_sp . v , out cpu_dummy ) ;
Pull ( out cpu_dummy ) ;
register_p = cpu_dummy ;
}
private static void RLA__ ( )
{
Read ( ref cpu_reg_ea . v , out cpu_byte_temp ) ;
Write ( ref cpu_reg_ea . v , ref cpu_byte_temp ) ;
cpu_dummy = ( byte ) ( ( uint ) ( cpu_byte_temp < < 1 ) | ( cpu_flag_c ? 1 u : 0 u ) ) ;
Write ( ref cpu_reg_ea . v , ref cpu_dummy ) ;
cpu_flag_n = ( cpu_dummy & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_dummy & 0xFF ) = = 0 ;
cpu_flag_c = ( cpu_byte_temp & 0x80 ) ! = 0 ;
cpu_reg_a & = cpu_dummy ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_reg_a & 0xFF ) = = 0 ;
}
private static void ROL_A ( )
{
cpu_byte_temp = ( byte ) ( ( uint ) ( cpu_reg_a < < 1 ) | ( cpu_flag_c ? 1 u : 0 u ) ) ;
cpu_flag_n = ( cpu_byte_temp & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_byte_temp & 0xFF ) = = 0 ;
cpu_flag_c = ( cpu_reg_a & 0x80 ) ! = 0 ;
cpu_reg_a = cpu_byte_temp ;
}
private static void ROL_M ( )
{
Write ( ref cpu_reg_ea . v , ref cpu_m ) ;
cpu_byte_temp = ( byte ) ( ( uint ) ( cpu_m < < 1 ) | ( cpu_flag_c ? 1 u : 0 u ) ) ;
Write ( ref cpu_reg_ea . v , ref cpu_byte_temp ) ;
cpu_flag_n = ( cpu_byte_temp & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_byte_temp & 0xFF ) = = 0 ;
cpu_flag_c = ( cpu_m & 0x80 ) ! = 0 ;
}
private static void ROR_A ( )
{
cpu_byte_temp = ( byte ) ( ( uint ) ( cpu_reg_a > > 1 ) | ( cpu_flag_c ? 128 u : 0 u ) ) ;
cpu_flag_n = ( cpu_byte_temp & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_byte_temp & 0xFF ) = = 0 ;
cpu_flag_c = ( cpu_reg_a & 1 ) ! = 0 ;
cpu_reg_a = cpu_byte_temp ;
}
private static void ROR_M ( )
{
Write ( ref cpu_reg_ea . v , ref cpu_m ) ;
cpu_byte_temp = ( byte ) ( ( uint ) ( cpu_m > > 1 ) | ( cpu_flag_c ? 128 u : 0 u ) ) ;
Write ( ref cpu_reg_ea . v , ref cpu_byte_temp ) ;
cpu_flag_n = ( cpu_byte_temp & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_byte_temp & 0xFF ) = = 0 ;
cpu_flag_c = ( cpu_m & 1 ) ! = 0 ;
}
private static void RRA__ ( )
{
Read ( ref cpu_reg_ea . v , out cpu_byte_temp ) ;
Write ( ref cpu_reg_ea . v , ref cpu_byte_temp ) ;
cpu_dummy = ( byte ) ( ( uint ) ( cpu_byte_temp > > 1 ) | ( cpu_flag_c ? 128 u : 0 u ) ) ;
Write ( ref cpu_reg_ea . v , ref cpu_dummy ) ;
cpu_flag_n = ( cpu_dummy & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_dummy & 0xFF ) = = 0 ;
cpu_flag_c = ( cpu_byte_temp & 1 ) ! = 0 ;
cpu_byte_temp = cpu_dummy ;
cpu_int_temp = cpu_reg_a + cpu_byte_temp + ( cpu_flag_c ? 1 : 0 ) ;
cpu_flag_n = ( cpu_int_temp & 0x80 ) ! = 0 ;
cpu_flag_v = ( ( cpu_int_temp ^ cpu_reg_a ) & ( cpu_int_temp ^ cpu_byte_temp ) & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_int_temp & 0xFF ) = = 0 ;
cpu_flag_c = cpu_int_temp > > 8 ! = 0 ;
cpu_reg_a = ( byte ) cpu_int_temp ;
}
private static void RTI__ ( )
{
Read ( ref cpu_reg_sp . v , out cpu_dummy ) ;
Pull ( out cpu_dummy ) ;
register_p = cpu_dummy ;
Pull ( out cpu_reg_pc . l ) ;
Pull ( out cpu_reg_pc . h ) ;
}
private static void RTS__ ( )
{
Read ( ref cpu_reg_sp . v , out cpu_dummy ) ;
Pull ( out cpu_reg_pc . l ) ;
Pull ( out cpu_reg_pc . h ) ;
cpu_reg_pc . v + + ;
Read ( ref cpu_reg_pc . v , out cpu_dummy ) ;
}
private static void SAX__ ( )
{
cpu_dummy = ( byte ) ( cpu_reg_x & cpu_reg_a ) ;
Write ( ref cpu_reg_ea . v , ref cpu_dummy ) ;
}
private static void SBC__ ( )
{
cpu_m ^ = byte . MaxValue ;
cpu_int_temp = cpu_reg_a + cpu_m + ( cpu_flag_c ? 1 : 0 ) ;
cpu_flag_n = ( cpu_int_temp & 0x80 ) ! = 0 ;
cpu_flag_v = ( ( cpu_int_temp ^ cpu_reg_a ) & ( cpu_int_temp ^ cpu_m ) & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_int_temp & 0xFF ) = = 0 ;
cpu_flag_c = cpu_int_temp > > 8 ! = 0 ;
cpu_reg_a = ( byte ) cpu_int_temp ;
}
private static void SEC__ ( )
{
cpu_flag_c = true ;
}
private static void SEI__ ( )
{
cpu_flag_i = true ;
}
private static void SHX__ ( )
{
cpu_byte_temp = ( byte ) ( cpu_reg_x & ( cpu_reg_ea . h + 1 ) ) ;
Read ( ref cpu_reg_ea . v , out cpu_dummy ) ;
cpu_reg_ea . l + = cpu_reg_y ;
if ( cpu_reg_ea . l < cpu_reg_y )
{
cpu_reg_ea . h = cpu_byte_temp ;
}
Write ( ref cpu_reg_ea . v , ref cpu_byte_temp ) ;
}
private static void SHY__ ( )
{
cpu_byte_temp = ( byte ) ( cpu_reg_y & ( cpu_reg_ea . h + 1 ) ) ;
Read ( ref cpu_reg_ea . v , out cpu_dummy ) ;
cpu_reg_ea . l + = cpu_reg_x ;
if ( cpu_reg_ea . l < cpu_reg_x )
{
cpu_reg_ea . h = cpu_byte_temp ;
}
Write ( ref cpu_reg_ea . v , ref cpu_byte_temp ) ;
}
private static void SLO__ ( )
{
Read ( ref cpu_reg_ea . v , out cpu_byte_temp ) ;
cpu_flag_c = ( cpu_byte_temp & 0x80 ) ! = 0 ;
Write ( ref cpu_reg_ea . v , ref cpu_byte_temp ) ;
cpu_byte_temp < < = 1 ;
Write ( ref cpu_reg_ea . v , ref cpu_byte_temp ) ;
cpu_flag_n = ( cpu_byte_temp & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_byte_temp & 0xFF ) = = 0 ;
cpu_reg_a | = cpu_byte_temp ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_reg_a & 0xFF ) = = 0 ;
}
private static void SRE__ ( )
{
Read ( ref cpu_reg_ea . v , out cpu_byte_temp ) ;
cpu_flag_c = ( cpu_byte_temp & 1 ) ! = 0 ;
Write ( ref cpu_reg_ea . v , ref cpu_byte_temp ) ;
cpu_byte_temp > > = 1 ;
Write ( ref cpu_reg_ea . v , ref cpu_byte_temp ) ;
cpu_flag_n = ( cpu_byte_temp & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_byte_temp & 0xFF ) = = 0 ;
cpu_reg_a ^ = cpu_byte_temp ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_reg_a & 0xFF ) = = 0 ;
}
private static void STA__ ( )
{
Write ( ref cpu_reg_ea . v , ref cpu_reg_a ) ;
}
private static void STX__ ( )
{
Write ( ref cpu_reg_ea . v , ref cpu_reg_x ) ;
}
private static void STY__ ( )
{
Write ( ref cpu_reg_ea . v , ref cpu_reg_y ) ;
}
private static void TAX__ ( )
{
cpu_reg_x = cpu_reg_a ;
cpu_flag_n = ( cpu_reg_x & 0x80 ) = = 128 ;
cpu_flag_z = cpu_reg_x = = 0 ;
}
private static void TAY__ ( )
{
cpu_reg_y = cpu_reg_a ;
cpu_flag_n = ( cpu_reg_y & 0x80 ) = = 128 ;
cpu_flag_z = cpu_reg_y = = 0 ;
}
private static void TSX__ ( )
{
cpu_reg_x = cpu_reg_sp . l ;
cpu_flag_n = ( cpu_reg_x & 0x80 ) ! = 0 ;
cpu_flag_z = cpu_reg_x = = 0 ;
}
private static void TXA__ ( )
{
cpu_reg_a = cpu_reg_x ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) = = 128 ;
cpu_flag_z = cpu_reg_a = = 0 ;
}
private static void TXS__ ( )
{
cpu_reg_sp . l = cpu_reg_x ;
}
private static void TYA__ ( )
{
cpu_reg_a = cpu_reg_y ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) = = 128 ;
cpu_flag_z = cpu_reg_a = = 0 ;
}
private static void XAA__ ( )
{
cpu_reg_a = ( byte ) ( cpu_reg_x & cpu_m ) ;
cpu_flag_n = ( cpu_reg_a & 0x80 ) ! = 0 ;
cpu_flag_z = ( cpu_reg_a & 0xFF ) = = 0 ;
}
private static void XAS__ ( )
{
cpu_reg_sp . l = ( byte ) ( cpu_reg_a & cpu_reg_x ) ;
Write ( ref cpu_reg_ea . v , ref cpu_reg_sp . l ) ;
}
private static void CPUWriteState ( ref BinaryWriter bin )
{
bin . Write ( cpu_reg_pc . v ) ;
bin . Write ( cpu_reg_sp . v ) ;
bin . Write ( cpu_reg_ea . v ) ;
bin . Write ( cpu_reg_a ) ;
bin . Write ( cpu_reg_x ) ;
bin . Write ( cpu_reg_y ) ;
bin . Write ( cpu_flag_n ) ;
bin . Write ( cpu_flag_v ) ;
bin . Write ( cpu_flag_d ) ;
bin . Write ( cpu_flag_i ) ;
bin . Write ( cpu_flag_z ) ;
bin . Write ( cpu_flag_c ) ;
bin . Write ( cpu_m ) ;
bin . Write ( cpu_opcode ) ;
bin . Write ( cpu_byte_temp ) ;
bin . Write ( cpu_int_temp ) ;
bin . Write ( cpu_int_temp1 ) ;
bin . Write ( cpu_dummy ) ;
bin . Write ( cpu_bool_tmp ) ;
bin . Write ( temp_add . v ) ;
bin . Write ( CPU_IRQ_PIN ) ;
bin . Write ( CPU_NMI_PIN ) ;
bin . Write ( cpu_suspend_nmi ) ;
bin . Write ( cpu_suspend_irq ) ;
}
private static void CPUReadState ( ref BinaryReader bin )
{
cpu_reg_pc . v = bin . ReadUInt16 ( ) ;
cpu_reg_sp . v = bin . ReadUInt16 ( ) ;
cpu_reg_ea . v = bin . ReadUInt16 ( ) ;
cpu_reg_a = bin . ReadByte ( ) ;
cpu_reg_x = bin . ReadByte ( ) ;
cpu_reg_y = bin . ReadByte ( ) ;
cpu_flag_n = bin . ReadBoolean ( ) ;
cpu_flag_v = bin . ReadBoolean ( ) ;
cpu_flag_d = bin . ReadBoolean ( ) ;
cpu_flag_i = bin . ReadBoolean ( ) ;
cpu_flag_z = bin . ReadBoolean ( ) ;
cpu_flag_c = bin . ReadBoolean ( ) ;
cpu_m = bin . ReadByte ( ) ;
cpu_opcode = bin . ReadByte ( ) ;
cpu_byte_temp = bin . ReadByte ( ) ;
cpu_int_temp = bin . ReadInt32 ( ) ;
cpu_int_temp1 = bin . ReadInt32 ( ) ;
cpu_dummy = bin . ReadByte ( ) ;
cpu_bool_tmp = bin . ReadBoolean ( ) ;
temp_add . v = bin . ReadUInt16 ( ) ;
CPU_IRQ_PIN = bin . ReadBoolean ( ) ;
CPU_NMI_PIN = bin . ReadBoolean ( ) ;
cpu_suspend_nmi = bin . ReadBoolean ( ) ;
cpu_suspend_irq = bin . ReadBoolean ( ) ;
}
private static void DMAHardReset ( )
{
dma_DMCDMAWaitCycles = 0 ;
dma_OAMDMAWaitCycles = 0 ;
dma_isOamDma = false ;
dma_oamdma_i = 0 ;
dma_DMCOn = false ;
dma_OAMOn = false ;
dma_DMC_occurring = false ;
dma_OAM_occurring = false ;
dma_OAMFinishCounter = 0 ;
dma_Oamaddress = 0 ;
dma_OAMCYCLE = 0 ;
dma_latch = 0 ;
reg_2004 = 8196 ;
}
private static void DMASoftReset ( )
{
dma_DMCDMAWaitCycles = 0 ;
dma_OAMDMAWaitCycles = 0 ;
dma_isOamDma = false ;
dma_oamdma_i = 0 ;
dma_DMCOn = false ;
dma_OAMOn = false ;
dma_DMC_occurring = false ;
dma_OAM_occurring = false ;
dma_OAMFinishCounter = 0 ;
dma_Oamaddress = 0 ;
dma_OAMCYCLE = 0 ;
dma_latch = 0 ;
}
internal static void AssertDMCDMA ( )
{
if ( dma_OAM_occurring )
{
if ( dma_OAMCYCLE < 508 )
{
dma_DMCDMAWaitCycles = ( BUS_RW ? 1 : 0 ) ;
}
else
{
dma_DMCDMAWaitCycles = 4 - ( 512 - dma_OAMCYCLE ) ;
}
}
else
{
if ( dma_DMC_occurring )
{
return ;
}
dma_DMCDMAWaitCycles = ( BUS_RW ? 3 : 2 ) ;
if ( dma_OAMFinishCounter = = 3 )
{
dma_DMCDMAWaitCycles + + ;
}
}
dma_isOamDma = false ;
dma_DMCOn = true ;
}
private static void AssertOAMDMA ( )
{
if ( ! dma_OAM_occurring )
{
dma_OAMDMAWaitCycles = ( apu_odd_cycle ? 1 : 2 ) ;
dma_isOamDma = true ;
dma_OAMOn = true ;
}
}
private static void DMAClock ( )
{
if ( dma_OAMFinishCounter > 0 )
{
dma_OAMFinishCounter - - ;
}
if ( ! BUS_RW )
{
if ( dma_DMCDMAWaitCycles > 0 )
{
dma_DMCDMAWaitCycles - - ;
}
if ( dma_OAMDMAWaitCycles > 0 )
{
dma_OAMDMAWaitCycles - - ;
}
return ;
}
if ( dma_DMCOn )
{
dma_DMC_occurring = true ;
dma_DMCOn = false ;
if ( dma_DMCDMAWaitCycles > 0 )
{
if ( BUS_ADDRESS = = 16406 | | BUS_ADDRESS = = 16407 )
{
Read ( ref BUS_ADDRESS , out dma_dummy ) ;
dma_DMCDMAWaitCycles - - ;
while ( dma_DMCDMAWaitCycles > 0 )
{
EmuClockComponents ( ) ;
dma_DMCDMAWaitCycles - - ;
}
}
else
{
if ( dma_DMCDMAWaitCycles > 0 )
{
EmuClockComponents ( ) ;
dma_DMCDMAWaitCycles - - ;
}
while ( dma_DMCDMAWaitCycles > 0 )
{
Read ( ref BUS_ADDRESS , out dma_dummy ) ;
dma_DMCDMAWaitCycles - - ;
}
}
}
DMCDoDMA ( ) ;
dma_DMC_occurring = false ;
}
if ( ! dma_OAMOn )
{
return ;
}
dma_OAM_occurring = true ;
dma_OAMOn = false ;
if ( dma_OAMDMAWaitCycles > 0 )
{
if ( BUS_ADDRESS = = 16406 | | BUS_ADDRESS = = 16407 )
{
Read ( ref BUS_ADDRESS , out dma_dummy ) ;
dma_OAMDMAWaitCycles - - ;
while ( dma_OAMDMAWaitCycles > 0 )
{
EmuClockComponents ( ) ;
dma_OAMDMAWaitCycles - - ;
}
}
else
{
if ( dma_OAMDMAWaitCycles > 0 )
{
EmuClockComponents ( ) ;
dma_OAMDMAWaitCycles - - ;
}
while ( dma_OAMDMAWaitCycles > 0 )
{
Read ( ref BUS_ADDRESS , out dma_dummy ) ;
dma_OAMDMAWaitCycles - - ;
}
}
}
dma_OAMCYCLE = 0 ;
for ( dma_oamdma_i = 0 ; dma_oamdma_i < 256 ; dma_oamdma_i + + )
{
Read ( ref dma_Oamaddress , out dma_latch ) ;
dma_OAMCYCLE + + ;
Write ( ref reg_2004 , ref dma_latch ) ;
dma_OAMCYCLE + + ;
dma_Oamaddress = ( ushort ) ( + + dma_Oamaddress & 0xFFFF u ) ;
}
dma_OAMCYCLE = 0 ;
dma_OAMFinishCounter = 5 ;
dma_OAM_occurring = false ;
}
private static void DMAWriteState ( ref BinaryWriter bin )
{
bin . Write ( dma_DMCDMAWaitCycles ) ;
bin . Write ( dma_OAMDMAWaitCycles ) ;
bin . Write ( dma_isOamDma ) ;
bin . Write ( dma_oamdma_i ) ;
bin . Write ( dma_DMCOn ) ;
bin . Write ( dma_OAMOn ) ;
bin . Write ( dma_DMC_occurring ) ;
bin . Write ( dma_OAM_occurring ) ;
bin . Write ( dma_OAMFinishCounter ) ;
bin . Write ( dma_Oamaddress ) ;
bin . Write ( dma_OAMCYCLE ) ;
bin . Write ( dma_latch ) ;
bin . Write ( dma_dummy ) ;
}
private static void DMAReadState ( ref BinaryReader bin )
{
dma_DMCDMAWaitCycles = bin . ReadInt32 ( ) ;
dma_OAMDMAWaitCycles = bin . ReadInt32 ( ) ;
dma_isOamDma = bin . ReadBoolean ( ) ;
dma_oamdma_i = bin . ReadInt32 ( ) ;
dma_DMCOn = bin . ReadBoolean ( ) ;
dma_OAMOn = bin . ReadBoolean ( ) ;
dma_DMC_occurring = bin . ReadBoolean ( ) ;
dma_OAM_occurring = bin . ReadBoolean ( ) ;
dma_OAMFinishCounter = bin . ReadInt32 ( ) ;
dma_Oamaddress = bin . ReadUInt16 ( ) ;
dma_OAMCYCLE = bin . ReadInt32 ( ) ;
dma_latch = bin . ReadByte ( ) ;
dma_dummy = bin . ReadByte ( ) ;
}
private static void PollInterruptStatus ( )
{
if ( ! cpu_suspend_nmi )
{
if ( PPU_NMI_Current & ! PPU_NMI_Old )
{
CPU_NMI_PIN = true ;
}
PPU_NMI_Old = ( PPU_NMI_Current = false ) ;
}
if ( ! cpu_suspend_irq )
{
CPU_IRQ_PIN = ! cpu_flag_i & & IRQFlags ! = 0 ;
}
if ( CPU_NMI_PIN )
{
InterruptVector = 65530 ;
}
else
{
InterruptVector = 65534 ;
}
}
private static void InterruptsWriteState ( ref BinaryWriter bin )
{
bin . Write ( IRQFlags ) ;
bin . Write ( PPU_NMI_Current ) ;
bin . Write ( PPU_NMI_Old ) ;
bin . Write ( InterruptVector ) ;
}
private static void InterruptsReadState ( ref BinaryReader bin )
{
IRQFlags = bin . ReadInt32 ( ) ;
PPU_NMI_Current = bin . ReadBoolean ( ) ;
PPU_NMI_Old = bin . ReadBoolean ( ) ;
InterruptVector = bin . ReadUInt16 ( ) ;
}
public static void SetupGameGenie ( bool IsGameGenieActive , GameGenieCode [ ] GameGenieCodes )
{
if ( mem_board ! = null )
{
mem_board . SetupGameGenie ( IsGameGenieActive , GameGenieCodes ) ;
}
}
private static void MEMInitialize ( IRom rom )
{
Tracer . WriteLine ( "Looking for mapper # " + rom . MapperNumber + "...." ) ;
if ( MyNesMain . IsBoardExist ( rom . MapperNumber ) )
{
Tracer . WriteLine ( "Mapper # " + rom . MapperNumber + " located, assigning..." ) ;
mem_board = MyNesMain . GetBoard ( rom . MapperNumber ) ;
Tracer . WriteInformation ( "Mapper # " + rom . MapperNumber + " assigned successfully." ) ;
if ( mem_board . HasIssues )
{
Tracer . WriteWarning ( MNInterfaceLanguage . Mapper + " # " + mem_board . MapperNumber + " [" + mem_board . Name + "] " + MNInterfaceLanguage . Message_Error17 ) ;
MyNesMain . VideoProvider . WriteWarningNotification ( MNInterfaceLanguage . Mapper + " # " + mem_board . MapperNumber + " [" + mem_board . Name + "] " + MNInterfaceLanguage . Message_Error17 , instant : false ) ;
}
}
else
{
Tracer . WriteError ( "Mapper # " + rom . MapperNumber + " IS NOT LOCATED, mapper is not supported or unable to find it." ) ;
MyNesMain . VideoProvider . WriteErrorNotification ( MNInterfaceLanguage . Mapper + " # " + rom . MapperNumber + " " + MNInterfaceLanguage . Message_Error14 , instant : false ) ;
mem_board = MyNesMain . GetBoard ( 0 ) ;
Tracer . WriteWarning ( "Mapper # 0 [NROM] will be used instead, assigned successfully." ) ;
MyNesMain . VideoProvider . WriteErrorNotification ( MNInterfaceLanguage . Mapper + " # 0 [NROM] " + MNInterfaceLanguage . Message_Error15 , instant : false ) ;
}
mem_read_accesses = new MemReadAccess [ 65536 ] ;
mem_write_accesses = new MemWriteAccess [ 65536 ] ;
MEMMap ( MEMReadWRAM , new ushort [ 2 ] { 0 , 4096 } ) ;
MEMMap ( MEMWriteWRAM , new ushort [ 2 ] { 0 , 4096 } ) ;
MEMMap ( PPUIORead , new ushort [ 2 ] { 8192 , 12288 } ) ;
MEMMap ( PPUIOWrite , new ushort [ 2 ] { 8192 , 12288 } ) ;
MEMMap ( APUIORead , new ushort [ 1 ] { 16384 } ) ;
MEMMap ( APUIOWrite , new ushort [ 1 ] { 16384 } ) ;
MEMMap ( mem_board . ReadEX , new ushort [ 1 ] { 20480 } ) ;
MEMMap ( mem_board . WriteEX , new ushort [ 1 ] { 20480 } ) ;
MEMMap ( mem_board . ReadSRM , new ushort [ 2 ] { 24576 , 28672 } ) ;
MEMMap ( mem_board . WriteSRM , new ushort [ 2 ] { 24576 , 28672 } ) ;
MEMMap ( mem_board . ReadPRG , new ushort [ 8 ] { 32768 , 36864 , 40960 , 45056 , 49152 , 53248 , 57344 , 61440 } ) ;
MEMMap ( mem_board . WritePRG , new ushort [ 8 ] { 32768 , 36864 , 40960 , 45056 , 49152 , 53248 , 57344 , 61440 } ) ;
mem_board . Initialize ( rom ) ;
mem_wram = new byte [ 2048 ] ;
}
private static void MEMHardReset ( )
{
mem_wram = new byte [ 2048 ] ;
mem_wram [ 8 ] = 247 ;
mem_wram [ 9 ] = 239 ;
mem_wram [ 10 ] = 223 ;
mem_wram [ 15 ] = 191 ;
Tracer . WriteLine ( "Reading SRAM ..." ) ;
SRAMFileName = Path . Combine ( MyNesMain . EmuSettings . SRAMFolder , Path . GetFileNameWithoutExtension ( CurrentFilePath ) + ".srm" ) ;
if ( File . Exists ( SRAMFileName ) )
{
FileStream fileStream = new FileStream ( SRAMFileName , FileMode . Open , FileAccess . Read ) ;
byte [ ] array = new byte [ fileStream . Length ] ;
fileStream . Read ( array , 0 , array . Length ) ;
fileStream . Flush ( ) ;
fileStream . Close ( ) ;
byte [ ] outData = new byte [ 0 ] ;
ZlipWrapper . DecompressData ( array , out outData ) ;
mem_board . LoadSRAM ( outData ) ;
Tracer . WriteLine ( "SRAM read successfully." ) ;
}
else
{
Tracer . WriteLine ( "SRAM file not found; rom has no SRAM or file not exist." ) ;
}
ReloadGameGenieCodes ( ) ;
mem_board . HardReset ( ) ;
}
public static void ReloadGameGenieCodes ( )
{
Tracer . WriteLine ( "Reading game genie codes (if available)...." ) ;
GMFileName = Path . Combine ( MyNesMain . EmuSettings . GameGenieFolder , Path . GetFileNameWithoutExtension ( CurrentFilePath ) + ".txt" ) ;
mem_board . GameGenieCodes = new GameGenieCode [ 0 ] ;
if ( File . Exists ( GMFileName ) )
{
XmlReaderSettings xmlReaderSettings = new XmlReaderSettings ( ) ;
xmlReaderSettings . DtdProcessing = DtdProcessing . Ignore ;
xmlReaderSettings . IgnoreWhitespace = true ;
XmlReader xmlReader = XmlReader . Create ( GMFileName , xmlReaderSettings ) ;
xmlReader . Read ( ) ;
xmlReader . Read ( ) ;
if ( xmlReader . Name ! = "MyNesGameGenieCodesList" )
{
xmlReader . Close ( ) ;
return ;
}
GameGenie gameGenie = new GameGenie ( ) ;
List < GameGenieCode > list = new List < GameGenieCode > ( ) ;
while ( xmlReader . Read ( ) )
{
if ( xmlReader . Name = = "Code" )
{
GameGenieCode item = default ( GameGenieCode ) ;
item . Enabled = true ;
xmlReader . MoveToAttribute ( "code" ) ;
item . Name = xmlReader . Value . ToString ( ) ;
if ( item . Name . Length = = 6 )
{
item . Address = gameGenie . GetGGAddress ( gameGenie . GetCodeAsHEX ( item . Name ) , 6 ) | 0x8000 ;
item . Value = gameGenie . GetGGValue ( gameGenie . GetCodeAsHEX ( item . Name ) , 6 ) ;
item . IsCompare = false ;
}
else
{
item . Address = gameGenie . GetGGAddress ( gameGenie . GetCodeAsHEX ( item . Name ) , 8 ) | 0x8000 ;
item . Value = gameGenie . GetGGValue ( gameGenie . GetCodeAsHEX ( item . Name ) , 8 ) ;
item . Compare = gameGenie . GetGGCompareValue ( gameGenie . GetCodeAsHEX ( item . Name ) ) ;
item . IsCompare = true ;
}
list . Add ( item ) ;
}
}
xmlReader . Close ( ) ;
if ( list . Count > 0 )
{
mem_board . GameGenieCodes = list . ToArray ( ) ;
Tracer . WriteInformation ( "Game Genie codes loaded successfully, total of " + list . Count ) ;
}
else
{
Tracer . WriteError ( "There is no Game Genie code in the file to load." ) ;
}
}
else
{
Tracer . WriteWarning ( "No Game Genie file found for this game." ) ;
}
}
private static void MEMMap ( MemReadAccess readAccess , ushort [ ] addresses )
{
for ( int i = 0 ; i < addresses . Length ; i + + )
{
mem_read_accesses [ ( addresses [ i ] & 0xF000 ) > > 12 ] = readAccess ;
}
}
private static void MEMMap ( MemWriteAccess writeAccess , ushort [ ] addresses )
{
for ( int i = 0 ; i < addresses . Length ; i + + )
{
mem_write_accesses [ ( addresses [ i ] & 0xF000 ) > > 12 ] = writeAccess ;
}
}
private static void MEMReadWRAM ( ref ushort addr , out byte value )
{
value = mem_wram [ addr & 0x7FF ] ;
}
private static void MEMWriteWRAM ( ref ushort addr , ref byte value )
{
mem_wram [ addr & 0x7FF ] = value ;
}
internal static void Read ( ref ushort addr , out byte value )
{
BUS_RW = true ;
BUS_ADDRESS = addr ;
EmuClockComponents ( ) ;
mem_read_accesses [ ( addr & 0xF000 ) > > 12 ] ( ref addr , out value ) ;
}
private static void Write ( ref ushort addr , ref byte value )
{
BUS_RW = false ;
BUS_ADDRESS = addr ;
EmuClockComponents ( ) ;
mem_write_accesses [ ( addr & 0xF000 ) > > 12 ] ( ref addr , ref value ) ;
}
internal static void SaveSRAM ( )
{
if ( mem_board ! = null & & MyNesMain . EmuSettings . SaveSRAMAtEmuShutdown & & mem_board . SRAMSaveRequired )
{
Tracer . WriteLine ( "Saving SRAM ..." ) ;
byte [ ] outData = new byte [ 0 ] ;
ZlipWrapper . CompressData ( mem_board . GetSRAMBuffer ( ) , out outData ) ;
FileStream fileStream = new FileStream ( SRAMFileName , FileMode . Create , FileAccess . Write ) ;
fileStream . Write ( outData , 0 , outData . Length ) ;
fileStream . Flush ( ) ;
fileStream . Close ( ) ;
Tracer . WriteLine ( "SRAM saved successfully." ) ;
}
}
private static void MEMWriteState ( ref BinaryWriter bin )
{
mem_board . WriteStateData ( ref bin ) ;
bin . Write ( mem_wram ) ;
bin . Write ( BUS_RW ) ;
bin . Write ( BUS_ADDRESS ) ;
}
private static void MEMReadState ( ref BinaryReader bin )
{
mem_board . ReadStateData ( ref bin ) ;
bin . Read ( mem_wram , 0 , mem_wram . Length ) ;
BUS_RW = bin . ReadBoolean ( ) ;
BUS_ADDRESS = bin . ReadUInt16 ( ) ;
}
private static void PORTSInitialize ( )
{
if ( joypad1 = = null )
{
joypad1 = new BlankJoypad ( ) ;
}
if ( joypad2 = = null )
{
joypad2 = new BlankJoypad ( ) ;
}
if ( joypad3 = = null )
{
joypad3 = new BlankJoypad ( ) ;
}
if ( joypad4 = = null )
{
joypad4 = new BlankJoypad ( ) ;
}
if ( shortucts = = null )
{
shortucts = new BlankShortuctsHandler ( ) ;
}
}
public static void SetupShortcutsHandler ( IShortcutsHandler hh )
{
shortucts = hh ;
}
public static void SetupControllers ( IJoypadConnecter joy1 , IJoypadConnecter joy2 , IJoypadConnecter joy3 , IJoypadConnecter joy4 )
{
joypad1 = joy1 ;
joypad2 = joy2 ;
joypad3 = joy3 ;
joypad4 = joy4 ;
}
public static void SetupVSUnisystemDIP ( IVSUnisystemDIPConnecter uni )
{
}
public static void SetupControllersP1 ( IJoypadConnecter joy )
{
joypad1 = joy ;
}
public static void SetupControllersP2 ( IJoypadConnecter joy )
{
joypad2 = joy ;
}
public static void SetupControllersP3 ( IJoypadConnecter joy )
{
joypad3 = joy ;
}
public static void SetupControllersP4 ( IJoypadConnecter joy )
{
joypad4 = joy ;
}
public static void DestroyJoypads ( )
{
if ( joypad1 = = null )
{
joypad1 = new BlankJoypad ( ) ;
}
else
{
joypad1 . Destroy ( ) ;
}
if ( joypad2 = = null )
{
joypad2 = new BlankJoypad ( ) ;
}
else
{
joypad1 . Destroy ( ) ;
}
if ( joypad3 = = null )
{
joypad3 = new BlankJoypad ( ) ;
}
else
{
joypad1 . Destroy ( ) ;
}
if ( joypad4 = = null )
{
joypad4 = new BlankJoypad ( ) ;
}
else
{
joypad1 . Destroy ( ) ;
}
}
private static void PORTWriteState ( ref BinaryWriter bin )
{
bin . Write ( PORT0 ) ;
bin . Write ( PORT1 ) ;
bin . Write ( inputStrobe ) ;
}
private static void PORTReadState ( ref BinaryReader bin )
{
PORT0 = bin . ReadInt32 ( ) ;
PORT1 = bin . ReadInt32 ( ) ;
inputStrobe = bin . ReadInt32 ( ) ;
}
public static void SetupPalette ( int [ ] pal )
{
ppu_palette = pal ;
}
private static void PPUInitialize ( )
{
ppu_reg_update_func = new Action [ 8 ] { PPUOnRegister2000 , PPUOnRegister2001 , PPUOnRegister2002 , PPUOnRegister2003 , PPUOnRegister2004 , PPUOnRegister2005 , PPUOnRegister2006 , PPUOnRegister2007 } ;
ppu_reg_read_func = new Action [ 8 ] { PPURead2000 , PPURead2001 , PPURead2002 , PPURead2003 , PPURead2004 , PPURead2005 , PPURead2006 , PPURead2007 } ;
ppu_bkg_fetches = new Action [ 8 ] { PPUBKFetch0 , PPUBKFetch1 , PPUBKFetch2 , PPUBKFetch3 , PPUBKFetch4 , PPUBKFetch5 , PPUBKFetch6 , PPUBKFetch7 } ;
ppu_spr_fetches = new Action [ 8 ] { PPUBKFetch0 , PPUBKFetch1 , PPUBKFetch2 , PPUBKFetch3 , PPUSPRFetch0 , PPUSPRFetch1 , PPUSPRFetch2 , PPUSPRFetch3 } ;
ppu_oam_phases = new Action [ 9 ] { PPUOamPhase0 , PPUOamPhase1 , PPUOamPhase2 , PPUOamPhase3 , PPUOamPhase4 , PPUOamPhase5 , PPUOamPhase6 , PPUOamPhase7 , PPUOamPhase8 } ;
ppu_h_clocks = new Action [ 341 ] ;
ppu_h_clocks [ 0 ] = PPUHClock_000_Idle ;
for ( int i = 1 ; i < 257 ; i + + )
{
ppu_h_clocks [ i ] = PPUHClock_1_256_BKGClocks ;
}
for ( int j = 257 ; j < 321 ; j + + )
{
ppu_h_clocks [ j ] = PPUHClock_257_320_SPRClocks ;
}
for ( int k = 321 ; k < 337 ; k + + )
{
ppu_h_clocks [ k ] = PPUHClock_321_336_DUMClocks ;
}
for ( int l = 337 ; l < 341 ; l + + )
{
ppu_h_clocks [ l ] = PPUHClock_337_340_DUMClocks ;
}
ppu_v_clocks = new Action [ 320 ] ;
for ( int m = 0 ; m < 240 ; m + + )
{
ppu_v_clocks [ m ] = PPUScanlineRender ;
}
ppu_v_clocks [ 240 ] = PPUScanlineVBLANK ;
ppu_oam_bank = new byte [ 256 ] ;
ppu_oam_bank_secondary = new byte [ 32 ] ;
ppu_palette_bank = new byte [ 32 ] ;
ppu_bkg_pixels = new int [ 512 ] ;
ppu_spr_pixels = new int [ 512 ] ;
ppu_screen_pixels = new int [ 61440 ] ;
ppu_palette = NTSCPaletteGenerator . GeneratePalette ( ) ;
}
private static void PPUHardReset ( )
{
ppu_reg_2001_grayscale = 243 ;
switch ( Region )
{
case EmuRegion . NTSC :
ppu_clock_vblank_start = 241 ;
ppu_clock_vblank_end = 261 ;
ppu_use_odd_cycle = true ;
break ;
case EmuRegion . PALB :
ppu_clock_vblank_start = 241 ;
ppu_clock_vblank_end = 311 ;
ppu_use_odd_cycle = false ;
break ;
case EmuRegion . DENDY :
{
ppu_clock_vblank_start = 291 ;
ppu_clock_vblank_end = 311 ;
for ( int i = 241 ; i < = 290 ; i + + )
{
ppu_v_clocks [ i ] = PPUScanlineVBLANK ;
}
ppu_use_odd_cycle = false ;
break ;
}
}
ppu_v_clocks [ ppu_clock_vblank_start ] = PPUScanlineVBLANKStart ;
for ( int j = ppu_clock_vblank_start + 1 ; j < = ppu_clock_vblank_end - 1 ; j + + )
{
ppu_v_clocks [ j ] = PPUScanlineVBLANK ;
}
ppu_v_clocks [ ppu_clock_vblank_end ] = PPUScanlineVBLANKEnd ;
ppu_oam_bank = new byte [ 256 ] ;
ppu_oam_bank_secondary = new byte [ 32 ] ;
PPUOamReset ( ) ;
ppu_palette_bank = new byte [ 32 ]
{
9 , 1 , 0 , 1 , 0 , 2 , 2 , 13 , 8 , 16 ,
8 , 36 , 0 , 0 , 4 , 44 , 9 , 1 , 52 , 3 ,
0 , 4 , 0 , 20 , 8 , 58 , 0 , 2 , 0 , 32 ,
44 , 8
} ;
ppu_reg_io_db = 0 ;
ppu_reg_io_addr = 0 ;
ppu_reg_access_happened = false ;
ppu_reg_access_w = false ;
ppu_reg_2000_vram_address_increament = 1 ;
ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites = 0 ;
ppu_reg_2000_background_pattern_table_address = 0 ;
ppu_reg_2000_Sprite_size = 0 ;
ppu_reg_2000_VBI = false ;
ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen = false ;
ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen = false ;
ppu_reg_2001_show_background = false ;
ppu_reg_2001_show_sprites = false ;
ppu_reg_2001_grayscale = 63 ;
ppu_reg_2001_emphasis = 0 ;
ppu_reg_2002_SpriteOverflow = false ;
ppu_reg_2002_Sprite0Hit = false ;
ppu_reg_2002_VblankStartedFlag = false ;
ppu_reg_2003_oam_addr = 0 ;
ppu_is_sprfetch = false ;
ppu_use_odd_swap = false ;
ppu_clock_h = 0 ;
ppu_clock_v = 0 ;
}
private static void PPUClock ( )
{
mem_board . OnPPUClock ( ) ;
ppu_v_clocks [ ppu_clock_v ] ( ) ;
ppu_clock_h + + ;
if ( ppu_clock_h > = 341 )
{
mem_board . OnPPUScanlineTick ( ) ;
if ( ppu_clock_v = = ppu_clock_vblank_end )
{
ppu_clock_v = 0 ;
ppu_frame_finished = true ;
}
else
{
ppu_clock_v + + ;
}
ppu_clock_h - = 341 ;
}
if ( ppu_reg_access_happened )
{
ppu_reg_access_happened = false ;
ppu_reg_update_func [ ppu_reg_io_addr ] ( ) ;
}
}
public static int GetPixel ( int x , int y )
{
return ppu_screen_pixels [ y * 256 + x ] ;
}
private static void PPUScanlineRender ( )
{
ppu_h_clocks [ ppu_clock_h ] ( ) ;
}
private static void PPUScanlineVBLANKStart ( )
{
ppu_is_nmi_time = ( ppu_clock_h > = 1 ) & ( ppu_clock_h < = 3 ) ;
if ( ppu_is_nmi_time )
{
if ( ppu_clock_h = = 1 )
{
ppu_reg_2002_VblankStartedFlag = true ;
}
PPU_NMI_Current = ppu_reg_2002_VblankStartedFlag & ppu_reg_2000_VBI ;
}
}
private static void PPUScanlineVBLANKEnd ( )
{
ppu_is_nmi_time = ( ppu_clock_h > = 1 ) & ( ppu_clock_h < = 3 ) ;
if ( ppu_clock_h = = 1 )
{
ppu_reg_2002_Sprite0Hit = false ;
ppu_reg_2002_VblankStartedFlag = false ;
ppu_reg_2002_SpriteOverflow = false ;
}
PPUScanlineRender ( ) ;
if ( ppu_use_odd_cycle & & ppu_clock_h = = 339 )
{
ppu_use_odd_swap = ! ppu_use_odd_swap ;
if ( ! ppu_use_odd_swap & ( ppu_reg_2001_show_background | | ppu_reg_2001_show_sprites ) )
{
ppu_odd_swap_done = true ;
ppu_clock_h + + ;
}
}
}
private static void PPUScanlineVBLANK ( )
{
}
private static void PPUHClock_000_Idle ( )
{
if ( ppu_odd_swap_done )
{
ppu_bkg_fetches [ 1 ] ( ) ;
ppu_odd_swap_done = false ;
}
}
private static void PPUHClock_1_256_BKGClocks ( )
{
if ( ppu_reg_2001_show_background | | ppu_reg_2001_show_sprites )
{
if ( ppu_clock_v ! = ppu_clock_vblank_end )
{
if ( ppu_clock_h > 0 & & ppu_clock_h < 65 )
{
ppu_oam_bank_secondary [ ( ppu_clock_h - 1 ) & 0x1F ] = byte . MaxValue ;
}
else
{
if ( ppu_clock_h = = 65 )
{
PPUOamReset ( ) ;
}
if ( ( ( ppu_clock_h - 1 ) & 1 ) = = 0 )
{
PPUOamEvFetch ( ) ;
}
else
{
ppu_oam_phases [ ppu_phase_index ] ( ) ;
}
if ( ppu_clock_h = = 256 )
{
PPUOamClear ( ) ;
}
}
}
ppu_bkg_fetches [ ( ppu_clock_h - 1 ) & 7 ] ( ) ;
if ( ppu_clock_v < 240 )
{
RenderPixel ( ) ;
}
}
else
{
if ( ppu_clock_v > = 240 )
{
return ;
}
if ( ( ppu_vram_addr & 0x3F00 ) = = 16128 )
{
if ( ( ppu_vram_addr & 3 ) = = 0 )
{
ppu_screen_pixels [ ppu_clock_h - 1 + ppu_clock_v * 256 ] = ppu_palette [ ( ppu_palette_bank [ ppu_vram_addr & 0xC ] & ppu_reg_2001_grayscale ) | ppu_reg_2001_emphasis ] ;
}
else
{
ppu_screen_pixels [ ppu_clock_h - 1 + ppu_clock_v * 256 ] = ppu_palette [ ( ppu_palette_bank [ ppu_vram_addr & 0x1F ] & ppu_reg_2001_grayscale ) | ppu_reg_2001_emphasis ] ;
}
}
else
{
ppu_screen_pixels [ ppu_clock_h - 1 + ppu_clock_v * 256 ] = ppu_palette [ ( ppu_palette_bank [ 0 ] & ppu_reg_2001_grayscale ) | ppu_reg_2001_emphasis ] ;
}
}
}
private static void PPUHClock_257_320_SPRClocks ( )
{
if ( ppu_reg_2001_show_background | | ppu_reg_2001_show_sprites )
{
ppu_spr_fetches [ ( ppu_clock_h - 1 ) & 7 ] ( ) ;
if ( ppu_clock_h = = 257 )
{
ppu_vram_addr = ( ushort ) ( ( ppu_vram_addr & 0x7BE0 u ) | ( ppu_vram_addr_temp & 0x41F u ) ) ;
}
if ( ppu_clock_v = = ppu_clock_vblank_end & & ppu_clock_h > = 280 & & ppu_clock_h < = 304 )
{
ppu_vram_addr = ( ushort ) ( ( ppu_vram_addr & 0x41F u ) | ( ppu_vram_addr_temp & 0x7BE0 u ) ) ;
}
}
}
private static void PPUHClock_321_336_DUMClocks ( )
{
if ( ppu_reg_2001_show_background | | ppu_reg_2001_show_sprites )
{
ppu_bkg_fetches [ ( ppu_clock_h - 1 ) & 7 ] ( ) ;
}
}
private static void PPUHClock_337_340_DUMClocks ( )
{
if ( ppu_reg_2001_show_background | | ppu_reg_2001_show_sprites )
{
ppu_bkg_fetches [ ( ppu_clock_h - 1 ) & 1 ] ( ) ;
}
}
private static void PPUBKFetch0 ( )
{
ppu_bkgfetch_nt_addr = ( ushort ) ( 0x2000 u | ( ppu_vram_addr & 0xFFF u ) ) ;
mem_board . OnPPUAddressUpdate ( ref ppu_bkgfetch_nt_addr ) ;
}
private static void PPUBKFetch1 ( )
{
mem_board . ReadNMT ( ref ppu_bkgfetch_nt_addr , out ppu_bkgfetch_nt_data ) ;
}
private static void PPUBKFetch2 ( )
{
ppu_bkgfetch_at_addr = ( ushort ) ( 0x23C0 u | ( ppu_vram_addr & 0xC00 u ) | ( ( uint ) ( ppu_vram_addr > > 4 ) & 0x38 u ) | ( ( uint ) ( ppu_vram_addr > > 2 ) & 7 u ) ) ;
mem_board . OnPPUAddressUpdate ( ref ppu_bkgfetch_at_addr ) ;
}
private static void PPUBKFetch3 ( )
{
mem_board . ReadNMT ( ref ppu_bkgfetch_at_addr , out ppu_bkgfetch_at_data ) ;
ppu_bkgfetch_at_data = ( byte ) ( ppu_bkgfetch_at_data > > ( ( ( ppu_vram_addr > > 4 ) & 4 ) | ( ppu_vram_addr & 2 ) ) ) ;
}
private static void PPUBKFetch4 ( )
{
ppu_bkgfetch_lb_addr = ( ushort ) ( ( uint ) ( ppu_reg_2000_background_pattern_table_address | ( ppu_bkgfetch_nt_data < < 4 ) ) | ( ( uint ) ( ppu_vram_addr > > 12 ) & 7 u ) ) ;
mem_board . OnPPUAddressUpdate ( ref ppu_bkgfetch_lb_addr ) ;
}
private static void PPUBKFetch5 ( )
{
mem_board . ReadCHR ( ref ppu_bkgfetch_lb_addr , out ppu_bkgfetch_lb_data ) ;
}
private static void PPUBKFetch6 ( )
{
ppu_bkgfetch_hb_addr = ( ushort ) ( ( uint ) ( ppu_reg_2000_background_pattern_table_address | ( ppu_bkgfetch_nt_data < < 4 ) ) | 8 u | ( ( uint ) ( ppu_vram_addr > > 12 ) & 7 u ) ) ;
mem_board . OnPPUAddressUpdate ( ref ppu_bkgfetch_hb_addr ) ;
}
private static void PPUBKFetch7 ( )
{
mem_board . ReadCHR ( ref ppu_bkgfetch_hb_addr , out ppu_bkgfetch_hb_data ) ;
ppu_bkg_render_pos = ppu_clock_h + 8 ;
ppu_bkg_render_pos % = 336 ;
if ( ppu_clock_h = = 256 )
{
if ( ( ppu_vram_addr & 0x7000 ) ! = 28672 )
{
ppu_vram_addr + = 4096 ;
}
else
{
ppu_vram_addr ^ = 28672 ;
switch ( ppu_vram_addr & 0x3E0 )
{
case 928 :
ppu_vram_addr ^ = 2976 ;
break ;
case 992 :
ppu_vram_addr ^ = 992 ;
break ;
default :
ppu_vram_addr + = 32 ;
break ;
}
}
}
else if ( ( ppu_vram_addr & 0x1F ) = = 31 )
{
ppu_vram_addr ^ = 1055 ;
}
else
{
ppu_vram_addr + + ;
}
for ( ppu_bkg_render_i = 0 ; ppu_bkg_render_i < 8 ; ppu_bkg_render_i + + )
{
ppu_bkg_render_tmp_val = ( ( ppu_bkgfetch_at_data < < 2 ) & 0xC ) | ( ( ppu_bkgfetch_lb_data > > 7 ) & 1 ) | ( ( ppu_bkgfetch_hb_data > > 6 ) & 2 ) ;
ppu_bkg_pixels [ ppu_bkg_render_i + ppu_bkg_render_pos ] = ppu_bkg_render_tmp_val ;
ppu_bkgfetch_lb_data < < = 1 ;
ppu_bkgfetch_hb_data < < = 1 ;
}
}
private static void PPUSPRFetch0 ( )
{
ppu_sprfetch_slot = ( ppu_clock_h - 1 > > 3 ) & 7 ;
ppu_sprfetch_slot = 7 - ppu_sprfetch_slot ;
ppu_sprfetch_y_data = ppu_oam_bank_secondary [ ppu_sprfetch_slot * 4 ] ;
ppu_sprfetch_t_data = ppu_oam_bank_secondary [ ppu_sprfetch_slot * 4 + 1 ] ;
ppu_sprfetch_at_data = ppu_oam_bank_secondary [ ppu_sprfetch_slot * 4 + 2 ] ;
ppu_sprfetch_x_data = ppu_oam_bank_secondary [ ppu_sprfetch_slot * 4 + 3 ] ;
ppu_temp_comparator = ( ppu_clock_v - ppu_sprfetch_y_data ) ^ ( ( ( ppu_sprfetch_at_data & 0x80 u ) ! = 0 ) ? 15 : 0 ) ;
if ( ppu_reg_2000_Sprite_size = = 16 )
{
ppu_sprfetch_lb_addr = ( ushort ) ( ( ( uint ) ( ppu_sprfetch_t_data < < 12 ) & 0x1000 u ) | ( ( uint ) ( ppu_sprfetch_t_data < < 4 ) & 0xFE0 u ) | ( ( uint ) ( ppu_temp_comparator < < 1 ) & 0x10 u ) | ( ( uint ) ppu_temp_comparator & 7 u ) ) ;
}
else
{
ppu_sprfetch_lb_addr = ( ushort ) ( ( uint ) ( ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites | ( ppu_sprfetch_t_data < < 4 ) ) | ( ( uint ) ppu_temp_comparator & 7 u ) ) ;
}
mem_board . OnPPUAddressUpdate ( ref ppu_sprfetch_lb_addr ) ;
}
private static void PPUSPRFetch1 ( )
{
ppu_is_sprfetch = true ;
mem_board . ReadCHR ( ref ppu_sprfetch_lb_addr , out ppu_sprfetch_lb_data ) ;
ppu_is_sprfetch = false ;
if ( ( ppu_sprfetch_at_data & 0x40 u ) ! = 0 )
{
ppu_sprfetch_lb_data = reverseLookup [ ppu_sprfetch_lb_data ] ;
}
}
private static void PPUSPRFetch2 ( )
{
ppu_sprfetch_hb_addr = ( ushort ) ( ppu_sprfetch_lb_addr | 8 u ) ;
mem_board . OnPPUAddressUpdate ( ref ppu_sprfetch_hb_addr ) ;
}
private static void PPUSPRFetch3 ( )
{
ppu_is_sprfetch = true ;
mem_board . ReadCHR ( ref ppu_sprfetch_hb_addr , out ppu_sprfetch_hb_data ) ;
ppu_is_sprfetch = false ;
if ( ( ppu_sprfetch_at_data & 0x40 u ) ! = 0 )
{
ppu_sprfetch_hb_data = reverseLookup [ ppu_sprfetch_hb_data ] ;
}
if ( ppu_sprfetch_x_data = = byte . MaxValue )
{
return ;
}
for ( ppu_bkg_render_i = 0 ; ppu_bkg_render_i < 8 ; ppu_bkg_render_i + + )
{
if ( ppu_sprfetch_x_data < byte . MaxValue )
{
ppu_bkg_render_tmp_val = ( ( ppu_sprfetch_at_data < < 2 ) & 0xC ) | ( ( ppu_sprfetch_lb_data > > 7 ) & 1 ) | ( ( ppu_sprfetch_hb_data > > 6 ) & 2 ) ;
if ( ( ( uint ) ppu_bkg_render_tmp_val & 3 u ) ! = 0 )
{
ppu_spr_pixels [ ppu_sprfetch_x_data ] = ppu_bkg_render_tmp_val ;
if ( ppu_sprfetch_slot = = 0 & & ppu_sprite0_should_hit )
{
ppu_spr_pixels [ ppu_sprfetch_x_data ] | = 16384 ;
}
if ( ( ppu_sprfetch_at_data & 0x20 ) = = 0 )
{
ppu_spr_pixels [ ppu_sprfetch_x_data ] | = 32768 ;
}
}
ppu_sprfetch_lb_data < < = 1 ;
ppu_sprfetch_hb_data < < = 1 ;
ppu_sprfetch_x_data + + ;
}
}
}
private static void PPUOamReset ( )
{
ppu_oamev_n = 0 ;
ppu_oamev_m = 0 ;
ppu_oamev_slot = 0 ;
ppu_phase_index = 0 ;
ppu_sprite0_should_hit = false ;
}
private static void PPUOamClear ( )
{
for ( int i = 0 ; i < ppu_spr_pixels . Length ; i + + )
{
ppu_spr_pixels [ i ] = 0 ;
}
}
private static void PPUOamEvFetch ( )
{
ppu_fetch_data = ppu_oam_bank [ ppu_oamev_n * 4 + ppu_oamev_m ] ;
}
private static void PPUOamPhase0 ( )
{
ppu_oamev_compare = ppu_clock_v > = ppu_fetch_data & & ppu_clock_v < ppu_fetch_data + ppu_reg_2000_Sprite_size ;
if ( ppu_oamev_compare )
{
ppu_oam_bank_secondary [ ppu_oamev_slot * 4 ] = ppu_fetch_data ;
ppu_oamev_m = 1 ;
ppu_phase_index + + ;
if ( ppu_oamev_n = = 0 )
{
ppu_sprite0_should_hit = true ;
}
}
else
{
ppu_oamev_m = 0 ;
ppu_oamev_n + + ;
if ( ppu_oamev_n = = 64 )
{
ppu_oamev_n = 0 ;
ppu_phase_index = 8 ;
}
}
}
private static void PPUOamPhase1 ( )
{
ppu_oam_bank_secondary [ ppu_oamev_slot * 4 + ppu_oamev_m ] = ppu_fetch_data ;
ppu_oamev_m = 2 ;
ppu_phase_index + + ;
}
private static void PPUOamPhase2 ( )
{
ppu_oam_bank_secondary [ ppu_oamev_slot * 4 + ppu_oamev_m ] = ppu_fetch_data ;
ppu_oamev_m = 3 ;
ppu_phase_index + + ;
}
private static void PPUOamPhase3 ( )
{
ppu_oam_bank_secondary [ ppu_oamev_slot * 4 + ppu_oamev_m ] = ppu_fetch_data ;
ppu_oamev_m = 0 ;
ppu_oamev_n + + ;
ppu_oamev_slot + + ;
if ( ppu_oamev_n = = 64 )
{
ppu_oamev_n = 0 ;
ppu_phase_index = 8 ;
}
else if ( ppu_oamev_slot < 8 )
{
ppu_phase_index = 0 ;
}
else if ( ppu_oamev_slot = = 8 )
{
ppu_phase_index = 4 ;
}
}
private static void PPUOamPhase4 ( )
{
ppu_oamev_compare = ppu_clock_v > = ppu_fetch_data & & ppu_clock_v < ppu_fetch_data + ppu_reg_2000_Sprite_size ;
if ( ppu_oamev_compare )
{
ppu_oamev_m = 1 ;
ppu_phase_index + + ;
ppu_reg_2002_SpriteOverflow = true ;
return ;
}
ppu_oamev_m + + ;
if ( ppu_oamev_m = = 4 )
{
ppu_oamev_m = 0 ;
}
ppu_oamev_n + + ;
if ( ppu_oamev_n = = 64 )
{
ppu_oamev_n = 0 ;
ppu_phase_index = 8 ;
}
else
{
ppu_phase_index = 4 ;
}
}
private static void PPUOamPhase5 ( )
{
ppu_oamev_m = 2 ;
ppu_phase_index + + ;
}
private static void PPUOamPhase6 ( )
{
ppu_oamev_m = 3 ;
ppu_phase_index + + ;
}
private static void PPUOamPhase7 ( )
{
ppu_oamev_m = 0 ;
ppu_oamev_n + + ;
if ( ppu_oamev_n = = 64 )
{
ppu_oamev_n = 0 ;
}
ppu_phase_index = 8 ;
}
private static void PPUOamPhase8 ( )
{
ppu_oamev_n + + ;
if ( ppu_oamev_n > = 64 )
{
ppu_oamev_n = 0 ;
}
}
private static void RenderPixel ( )
{
if ( ppu_clock_v = = ppu_clock_vblank_end )
{
return ;
}
ppu_render_x = ppu_clock_h - 1 ;
ppu_render_y = ppu_clock_v * 256 ;
if ( ppu_render_x < 8 )
{
if ( ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen )
{
ppu_bkg_current_pixel = 0x3F00 | ppu_bkg_pixels [ ppu_render_x + ppu_vram_finex ] ;
}
else
{
ppu_bkg_current_pixel = 16128 ;
}
if ( ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen )
{
ppu_spr_current_pixel = 0x3F10 | ppu_spr_pixels [ ppu_render_x ] ;
}
else
{
ppu_spr_current_pixel = 16144 ;
}
}
else
{
if ( ! ppu_reg_2001_show_background )
{
ppu_bkg_current_pixel = 16128 ;
}
else
{
ppu_bkg_current_pixel = 0x3F00 | ppu_bkg_pixels [ ppu_render_x + ppu_vram_finex ] ;
}
if ( ! ppu_reg_2001_show_sprites | | ppu_clock_v = = 0 )
{
ppu_spr_current_pixel = 16144 ;
}
else
{
ppu_spr_current_pixel = 0x3F10 | ppu_spr_pixels [ ppu_render_x ] ;
}
}
ppu_current_pixel = 0 ;
if ( ( ( uint ) ppu_spr_current_pixel & 0x8000 u ) ! = 0 )
{
ppu_current_pixel = ppu_spr_current_pixel ;
}
else
{
ppu_current_pixel = ppu_bkg_current_pixel ;
}
if ( ( ppu_bkg_current_pixel & 3 ) = = 0 )
{
ppu_current_pixel = ppu_spr_current_pixel ;
}
else if ( ( ppu_spr_current_pixel & 3 ) = = 0 )
{
ppu_current_pixel = ppu_bkg_current_pixel ;
}
else if ( ( ( uint ) ppu_spr_pixels [ ppu_render_x ] & 0x4000 u ) ! = 0 )
{
ppu_reg_2002_Sprite0Hit = true ;
}
if ( ( ppu_current_pixel & 3 ) = = 0 )
{
ppu_screen_pixels [ ppu_render_x + ppu_render_y ] = ppu_palette [ ( ppu_palette_bank [ ppu_current_pixel & 0xC ] & ppu_reg_2001_grayscale ) | ppu_reg_2001_emphasis ] ;
}
else
{
ppu_screen_pixels [ ppu_render_x + ppu_render_y ] = ppu_palette [ ( ppu_palette_bank [ ppu_current_pixel & 0x1F ] & ppu_reg_2001_grayscale ) | ppu_reg_2001_emphasis ] ;
}
}
private static void PPUIORead ( ref ushort addr , out byte value )
{
ppu_reg_io_addr = ( byte ) ( addr & 7 u ) ;
ppu_reg_access_happened = true ;
ppu_reg_access_w = false ;
ppu_reg_read_func [ ppu_reg_io_addr ] ( ) ;
value = ppu_reg_io_db ;
}
private static void PPUIOWrite ( ref ushort addr , ref byte value )
{
ppu_reg_io_addr = ( byte ) ( addr & 7 u ) ;
ppu_reg_io_db = value ;
ppu_reg_access_w = true ;
ppu_reg_access_happened = true ;
}
private static void PPUOnRegister2000 ( )
{
if ( ppu_reg_access_w )
{
ppu_vram_addr_temp = ( ushort ) ( ( ppu_vram_addr_temp & 0x73FF u ) | ( uint ) ( ( ppu_reg_io_db & 3 ) < < 10 ) ) ;
if ( ( ppu_reg_io_db & 4 u ) ! = 0 )
{
ppu_reg_2000_vram_address_increament = 32 ;
}
else
{
ppu_reg_2000_vram_address_increament = 1 ;
}
if ( ( ppu_reg_io_db & 8 u ) ! = 0 )
{
ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites = 4096 ;
}
else
{
ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites = 0 ;
}
if ( ( ppu_reg_io_db & 0x10 u ) ! = 0 )
{
ppu_reg_2000_background_pattern_table_address = 4096 ;
}
else
{
ppu_reg_2000_background_pattern_table_address = 0 ;
}
if ( ( ppu_reg_io_db & 0x20 u ) ! = 0 )
{
ppu_reg_2000_Sprite_size = 16 ;
}
else
{
ppu_reg_2000_Sprite_size = 8 ;
}
if ( ! ppu_reg_2000_VBI & & ( ppu_reg_io_db & 0x80 u ) ! = 0 & & ppu_reg_2002_VblankStartedFlag )
{
PPU_NMI_Current = true ;
}
ppu_reg_2000_VBI = ( ppu_reg_io_db & 0x80 ) ! = 0 ;
if ( ! ppu_reg_2000_VBI & & ppu_is_nmi_time )
{
PPU_NMI_Current = false ;
}
}
}
private static void PPUOnRegister2001 ( )
{
if ( ppu_reg_access_w )
{
ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen = ( ppu_reg_io_db & 2 ) ! = 0 ;
ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen = ( ppu_reg_io_db & 4 ) ! = 0 ;
ppu_reg_2001_show_background = ( ppu_reg_io_db & 8 ) ! = 0 ;
ppu_reg_2001_show_sprites = ( ppu_reg_io_db & 0x10 ) ! = 0 ;
ppu_reg_2001_grayscale = ( ( ( ( uint ) ppu_reg_io_db & ( true ? 1 u : 0 u ) ) ! = 0 ) ? 48 : 63 ) ;
ppu_reg_2001_emphasis = ( ppu_reg_io_db & 0xE0 ) < < 1 ;
}
}
private static void PPUOnRegister2002 ( )
{
if ( ! ppu_reg_access_w )
{
ppu_vram_flip_flop = false ;
ppu_reg_2002_VblankStartedFlag = false ;
if ( ppu_clock_v = = ppu_clock_vblank_start )
{
PPU_NMI_Current = ppu_reg_2002_VblankStartedFlag & ppu_reg_2000_VBI ;
}
}
}
private static void PPUOnRegister2003 ( )
{
if ( ppu_reg_access_w )
{
ppu_reg_2003_oam_addr = ppu_reg_io_db ;
}
}
private static void PPUOnRegister2004 ( )
{
if ( ppu_reg_access_w )
{
if ( ppu_clock_v < 240 & & IsRenderingOn ( ) )
{
ppu_reg_io_db = byte . MaxValue ;
}
if ( ( ppu_reg_2003_oam_addr & 3 ) = = 2 )
{
ppu_reg_io_db & = 227 ;
}
ppu_oam_bank [ ppu_reg_2003_oam_addr ] = ppu_reg_io_db ;
ppu_reg_2003_oam_addr = ( byte ) ( ( uint ) ( ppu_reg_2003_oam_addr + 1 ) & 0xFF u ) ;
}
}
private static void PPUOnRegister2005 ( )
{
if ( ppu_reg_access_w )
{
if ( ! ppu_vram_flip_flop )
{
ppu_vram_addr_temp = ( ushort ) ( ( ppu_vram_addr_temp & 0x7FE0 u ) | ( uint ) ( ( ppu_reg_io_db & 0xF8 ) > > 3 ) ) ;
ppu_vram_finex = ( byte ) ( ppu_reg_io_db & 7 u ) ;
}
else
{
ppu_vram_addr_temp = ( ushort ) ( ( ppu_vram_addr_temp & 0xC1F u ) | ( uint ) ( ( ppu_reg_io_db & 7 ) < < 12 ) | ( uint ) ( ( ppu_reg_io_db & 0xF8 ) < < 2 ) ) ;
}
ppu_vram_flip_flop = ! ppu_vram_flip_flop ;
}
}
private static void PPUOnRegister2006 ( )
{
if ( ppu_reg_access_w )
{
if ( ! ppu_vram_flip_flop )
{
ppu_vram_addr_temp = ( ushort ) ( ( ppu_vram_addr_temp & 0xFF u ) | ( uint ) ( ( ppu_reg_io_db & 0x3F ) < < 8 ) ) ;
}
else
{
ppu_vram_addr_temp = ( ushort ) ( ( ppu_vram_addr_temp & 0x7F00 u ) | ppu_reg_io_db ) ;
ppu_vram_addr = ppu_vram_addr_temp ;
mem_board . OnPPUAddressUpdate ( ref ppu_vram_addr ) ;
}
ppu_vram_flip_flop = ! ppu_vram_flip_flop ;
}
}
private static void PPUOnRegister2007 ( )
{
if ( ppu_reg_access_w )
{
ppu_vram_addr_access_temp = ( ushort ) ( ppu_vram_addr & 0x3FFF u ) ;
if ( ppu_vram_addr_access_temp < 8192 )
{
mem_board . WriteCHR ( ref ppu_vram_addr_access_temp , ref ppu_reg_io_db ) ;
}
else if ( ppu_vram_addr_access_temp < 16128 )
{
mem_board . WriteNMT ( ref ppu_vram_addr_access_temp , ref ppu_reg_io_db ) ;
}
else if ( ( ppu_vram_addr_access_temp & 3 u ) ! = 0 )
{
ppu_palette_bank [ ppu_vram_addr_access_temp & 0x1F ] = ppu_reg_io_db ;
}
else
{
ppu_palette_bank [ ppu_vram_addr_access_temp & 0xC ] = ppu_reg_io_db ;
}
}
else
{
if ( ( ppu_vram_addr & 0x3F00 ) = = 16128 )
{
ppu_vram_addr_access_temp = ( ushort ) ( ppu_vram_addr & 0x2FFF u ) ;
}
else
{
ppu_vram_addr_access_temp = ( ushort ) ( ppu_vram_addr & 0x3FFF u ) ;
}
if ( ppu_vram_addr_access_temp < 8192 )
{
mem_board . ReadCHR ( ref ppu_vram_addr_access_temp , out ppu_vram_data ) ;
}
else if ( ppu_vram_addr_access_temp < 16128 )
{
mem_board . ReadNMT ( ref ppu_vram_addr_access_temp , out ppu_vram_data ) ;
}
}
ppu_vram_addr = ( ushort ) ( ( uint ) ( ppu_vram_addr + ppu_reg_2000_vram_address_increament ) & 0x7FFF u ) ;
mem_board . OnPPUAddressUpdate ( ref ppu_vram_addr ) ;
}
private static void PPURead2000 ( )
{
}
private static void PPURead2001 ( )
{
}
private static void PPURead2002 ( )
{
ppu_reg_io_db = ( byte ) ( ( ppu_reg_io_db & 0xDF u ) | ( ppu_reg_2002_SpriteOverflow ? 32 u : 0 u ) ) ;
ppu_reg_io_db = ( byte ) ( ( ppu_reg_io_db & 0xBF u ) | ( ppu_reg_2002_Sprite0Hit ? 64 u : 0 u ) ) ;
ppu_reg_io_db = ( byte ) ( ( ppu_reg_io_db & 0x7F u ) | ( ppu_reg_2002_VblankStartedFlag ? 128 u : 0 u ) ) ;
}
private static void PPURead2003 ( )
{
}
private static void PPURead2004 ( )
{
ppu_reg_io_db = ppu_oam_bank [ ppu_reg_2003_oam_addr ] ;
if ( ppu_clock_v < 240 & & IsRenderingOn ( ) )
{
if ( ppu_clock_h < 64 )
{
ppu_reg_io_db = byte . MaxValue ;
}
else if ( ppu_clock_h < 192 )
{
ppu_reg_io_db = ppu_oam_bank [ ( ppu_clock_h - 64 < < 1 ) & 0xFC ] ;
}
else if ( ppu_clock_h < 256 )
{
ppu_reg_io_db = ( ( ( ppu_clock_h & 1 ) = = 1 ) ? ppu_oam_bank [ 252 ] : ppu_oam_bank [ ( ppu_clock_h - 192 < < 1 ) & 0xFC ] ) ;
}
else if ( ppu_clock_h < 320 )
{
ppu_reg_io_db = byte . MaxValue ;
}
else
{
ppu_reg_io_db = ppu_oam_bank [ 0 ] ;
}
}
}
private static void PPURead2005 ( )
{
}
private static void PPURead2006 ( )
{
}
private static void PPURead2007 ( )
{
ppu_vram_addr_access_temp = ( ushort ) ( ppu_vram_addr & 0x3FFF u ) ;
if ( ppu_vram_addr_access_temp < 16128 )
{
ppu_reg_io_db = ppu_vram_data ;
}
else if ( ( ppu_vram_addr_access_temp & 3 u ) ! = 0 )
{
ppu_reg_io_db = ppu_palette_bank [ ppu_vram_addr_access_temp & 0x1F ] ;
}
else
{
ppu_reg_io_db = ppu_palette_bank [ ppu_vram_addr_access_temp & 0xC ] ;
}
}
internal static bool IsRenderingOn ( )
{
if ( ! ppu_reg_2001_show_background )
{
return ppu_reg_2001_show_sprites ;
}
return true ;
}
internal static bool IsInRender ( )
{
if ( ppu_clock_v > = 240 )
{
return ppu_clock_v = = ppu_clock_vblank_end ;
}
return true ;
}
private static void PPUWriteState ( ref BinaryWriter bin )
{
bin . Write ( ppu_clock_h ) ;
bin . Write ( ppu_clock_v ) ;
bin . Write ( ppu_clock_vblank_start ) ;
bin . Write ( ppu_clock_vblank_end ) ;
bin . Write ( ppu_use_odd_cycle ) ;
bin . Write ( ppu_use_odd_swap ) ;
bin . Write ( ppu_is_nmi_time ) ;
bin . Write ( ppu_frame_finished ) ;
bin . Write ( ppu_oam_bank ) ;
bin . Write ( ppu_oam_bank_secondary ) ;
bin . Write ( ppu_palette_bank ) ;
bin . Write ( ppu_reg_io_db ) ;
bin . Write ( ppu_reg_io_addr ) ;
bin . Write ( ppu_reg_access_happened ) ;
bin . Write ( ppu_reg_access_w ) ;
bin . Write ( ppu_reg_2000_vram_address_increament ) ;
bin . Write ( ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites ) ;
bin . Write ( ppu_reg_2000_background_pattern_table_address ) ;
bin . Write ( ppu_reg_2000_Sprite_size ) ;
bin . Write ( ppu_reg_2000_VBI ) ;
bin . Write ( ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen ) ;
bin . Write ( ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen ) ;
bin . Write ( ppu_reg_2001_show_background ) ;
bin . Write ( ppu_reg_2001_show_sprites ) ;
bin . Write ( ppu_reg_2001_grayscale ) ;
bin . Write ( ppu_reg_2001_emphasis ) ;
bin . Write ( ppu_reg_2002_SpriteOverflow ) ;
bin . Write ( ppu_reg_2002_Sprite0Hit ) ;
bin . Write ( ppu_reg_2002_VblankStartedFlag ) ;
bin . Write ( ppu_reg_2003_oam_addr ) ;
bin . Write ( ppu_vram_addr ) ;
bin . Write ( ppu_vram_data ) ;
bin . Write ( ppu_vram_addr_temp ) ;
bin . Write ( ppu_vram_addr_access_temp ) ;
bin . Write ( ppu_vram_flip_flop ) ;
bin . Write ( ppu_vram_finex ) ;
bin . Write ( ppu_bkgfetch_nt_addr ) ;
bin . Write ( ppu_bkgfetch_nt_data ) ;
bin . Write ( ppu_bkgfetch_at_addr ) ;
bin . Write ( ppu_bkgfetch_at_data ) ;
bin . Write ( ppu_bkgfetch_lb_addr ) ;
bin . Write ( ppu_bkgfetch_lb_data ) ;
bin . Write ( ppu_bkgfetch_hb_addr ) ;
bin . Write ( ppu_bkgfetch_hb_data ) ;
bin . Write ( ppu_sprfetch_slot ) ;
bin . Write ( ppu_sprfetch_y_data ) ;
bin . Write ( ppu_sprfetch_t_data ) ;
bin . Write ( ppu_sprfetch_at_data ) ;
bin . Write ( ppu_sprfetch_x_data ) ;
bin . Write ( ppu_sprfetch_lb_addr ) ;
bin . Write ( ppu_sprfetch_lb_data ) ;
bin . Write ( ppu_sprfetch_hb_addr ) ;
bin . Write ( ppu_sprfetch_hb_data ) ;
bin . Write ( ppu_bkg_render_i ) ;
bin . Write ( ppu_bkg_render_pos ) ;
bin . Write ( ppu_bkg_render_tmp_val ) ;
bin . Write ( ppu_bkg_current_pixel ) ;
bin . Write ( ppu_spr_current_pixel ) ;
bin . Write ( ppu_current_pixel ) ;
bin . Write ( ppu_render_x ) ;
bin . Write ( 0 ) ;
bin . Write ( ppu_oamev_n ) ;
bin . Write ( ppu_oamev_m ) ;
bin . Write ( ppu_oamev_compare ) ;
bin . Write ( ppu_oamev_slot ) ;
bin . Write ( ppu_fetch_data ) ;
bin . Write ( ppu_phase_index ) ;
bin . Write ( ppu_sprite0_should_hit ) ;
}
private static void PPUReadState ( ref BinaryReader bin )
{
ppu_clock_h = bin . ReadInt32 ( ) ;
ppu_clock_v = bin . ReadUInt16 ( ) ;
ppu_clock_vblank_start = bin . ReadUInt16 ( ) ;
ppu_clock_vblank_end = bin . ReadUInt16 ( ) ;
ppu_use_odd_cycle = bin . ReadBoolean ( ) ;
ppu_use_odd_swap = bin . ReadBoolean ( ) ;
ppu_is_nmi_time = bin . ReadBoolean ( ) ;
ppu_frame_finished = bin . ReadBoolean ( ) ;
bin . Read ( ppu_oam_bank , 0 , ppu_oam_bank . Length ) ;
bin . Read ( ppu_oam_bank_secondary , 0 , ppu_oam_bank_secondary . Length ) ;
bin . Read ( ppu_palette_bank , 0 , ppu_palette_bank . Length ) ;
ppu_reg_io_db = bin . ReadByte ( ) ;
ppu_reg_io_addr = bin . ReadByte ( ) ;
ppu_reg_access_happened = bin . ReadBoolean ( ) ;
ppu_reg_access_w = bin . ReadBoolean ( ) ;
ppu_reg_2000_vram_address_increament = bin . ReadByte ( ) ;
ppu_reg_2000_sprite_pattern_table_address_for_8x8_sprites = bin . ReadUInt16 ( ) ;
ppu_reg_2000_background_pattern_table_address = bin . ReadUInt16 ( ) ;
ppu_reg_2000_Sprite_size = bin . ReadByte ( ) ;
ppu_reg_2000_VBI = bin . ReadBoolean ( ) ;
ppu_reg_2001_show_background_in_leftmost_8_pixels_of_screen = bin . ReadBoolean ( ) ;
ppu_reg_2001_show_sprites_in_leftmost_8_pixels_of_screen = bin . ReadBoolean ( ) ;
ppu_reg_2001_show_background = bin . ReadBoolean ( ) ;
ppu_reg_2001_show_sprites = bin . ReadBoolean ( ) ;
ppu_reg_2001_grayscale = bin . ReadInt32 ( ) ;
ppu_reg_2001_emphasis = bin . ReadInt32 ( ) ;
ppu_reg_2002_SpriteOverflow = bin . ReadBoolean ( ) ;
ppu_reg_2002_Sprite0Hit = bin . ReadBoolean ( ) ;
ppu_reg_2002_VblankStartedFlag = bin . ReadBoolean ( ) ;
ppu_reg_2003_oam_addr = bin . ReadByte ( ) ;
ppu_vram_addr = bin . ReadUInt16 ( ) ;
ppu_vram_data = bin . ReadByte ( ) ;
ppu_vram_addr_temp = bin . ReadUInt16 ( ) ;
ppu_vram_addr_access_temp = bin . ReadUInt16 ( ) ;
ppu_vram_flip_flop = bin . ReadBoolean ( ) ;
ppu_vram_finex = bin . ReadByte ( ) ;
ppu_bkgfetch_nt_addr = bin . ReadUInt16 ( ) ;
ppu_bkgfetch_nt_data = bin . ReadByte ( ) ;
ppu_bkgfetch_at_addr = bin . ReadUInt16 ( ) ;
ppu_bkgfetch_at_data = bin . ReadByte ( ) ;
ppu_bkgfetch_lb_addr = bin . ReadUInt16 ( ) ;
ppu_bkgfetch_lb_data = bin . ReadByte ( ) ;
ppu_bkgfetch_hb_addr = bin . ReadUInt16 ( ) ;
ppu_bkgfetch_hb_data = bin . ReadByte ( ) ;
ppu_sprfetch_slot = bin . ReadInt32 ( ) ;
ppu_sprfetch_y_data = bin . ReadByte ( ) ;
ppu_sprfetch_t_data = bin . ReadByte ( ) ;
ppu_sprfetch_at_data = bin . ReadByte ( ) ;
ppu_sprfetch_x_data = bin . ReadByte ( ) ;
ppu_sprfetch_lb_addr = bin . ReadUInt16 ( ) ;
ppu_sprfetch_lb_data = bin . ReadByte ( ) ;
ppu_sprfetch_hb_addr = bin . ReadUInt16 ( ) ;
ppu_sprfetch_hb_data = bin . ReadByte ( ) ;
ppu_bkg_render_i = bin . ReadInt32 ( ) ;
ppu_bkg_render_pos = bin . ReadInt32 ( ) ;
ppu_bkg_render_tmp_val = bin . ReadInt32 ( ) ;
ppu_bkg_current_pixel = bin . ReadInt32 ( ) ;
ppu_spr_current_pixel = bin . ReadInt32 ( ) ;
ppu_current_pixel = bin . ReadInt32 ( ) ;
ppu_render_x = bin . ReadInt32 ( ) ;
bin . ReadInt32 ( ) ;
ppu_oamev_n = bin . ReadByte ( ) ;
ppu_oamev_m = bin . ReadByte ( ) ;
ppu_oamev_compare = bin . ReadBoolean ( ) ;
ppu_oamev_slot = bin . ReadByte ( ) ;
ppu_fetch_data = bin . ReadByte ( ) ;
ppu_phase_index = bin . ReadByte ( ) ;
ppu_sprite0_should_hit = bin . ReadBoolean ( ) ;
}
internal static void CheckGame ( string fileName , out bool valid )
{
string text = Path . GetExtension ( fileName ) . ToLower ( ) ;
if ( text ! = null & & text = = ".nes" )
{
Tracer . WriteLine ( "Checking INES header ..." ) ;
INes nes = new INes ( ) ;
nes . Load ( fileName , loadDumps : false ) ;
valid = nes . IsValid ;
Tracer . WriteLine ( "INES header is valid." ) ;
}
else
{
Tracer . WriteWarning ( "File format is not supported. Format: " + Path . GetExtension ( fileName ) ) ;
valid = false ;
}
}
internal static void Initialize ( )
{
Tracer . WriteLine ( "Loading database file ..." ) ;
NesCartDatabase . LoadDatabase ( out bool success ) ;
if ( success )
{
Tracer . WriteInformation ( "Nes Cart database file loaded successfully." ) ;
}
else
{
Tracer . WriteError ( "Error loading Nes Cart database file." ) ;
}
FrameLimiterEnabled = true ;
CPUInitialize ( ) ;
PPUInitialize ( ) ;
APUInitialize ( ) ;
PORTSInitialize ( ) ;
}
internal static void SetupRenderingMethods ( RenderVideoFrame renderVideo , RenderAudioSamples renderAudio , TogglePause renderTogglePause , GetIsPlaying renderGetIsPlaying )
{
render_initialized = false ;
render_video = renderVideo ;
render_audio = renderAudio ;
render_audio_toggle_pause = renderTogglePause ;
render_audio_get_is_playing = renderGetIsPlaying ;
render_initialized = render_video ! = null & & render_audio ! = null & & render_audio_toggle_pause ! = null & & render_audio_get_is_playing ! = null ;
if ( render_initialized )
{
Tracer . WriteInformation ( "Renderer methods initialized successfully." ) ;
return ;
}
Tracer . WriteError ( "ERROR RENDERER INITIALIZING !!" ) ;
Tracer . WriteError ( "Faild to initialize the renderers methods. Please use the method 'SetupRenderingMethods' to initialize the renderers methods before you can run the emulation." ) ;
}
public static void LoadGame ( string fileName , out bool success , bool useThread )
{
if ( ! render_initialized )
{
Tracer . WriteError ( "NO RENDERER INITIALIZED !! EMU CANNOT BE INTIALIZED WITHOUT A RENDERER !!" ) ;
Tracer . WriteError ( "Please use the method 'SetupRenderingMethods' to initialize the renderers methods before you can run the emulation." ) ;
success = false ;
return ;
}
string text = Path . GetExtension ( fileName ) . ToLower ( ) ;
if ( text ! = null & & text = = ".nes" )
{
Tracer . WriteLine ( "Checking INES header ..." ) ;
INes nes = new INes ( ) ;
nes . Load ( fileName , loadDumps : true ) ;
if ( nes . IsValid )
{
emu_request_mode = RequestMode . None ;
CurrentFilePath = fileName ;
if ( ON )
{
ShutDown ( ) ;
}
Tracer . WriteLine ( "INES header is valid, loading game ..." ) ;
ApplyRegionSetting ( ) ;
MEMInitialize ( nes ) ;
ApplyAudioSettings ( ) ;
ApplyFrameSkipSettings ( ) ;
ApplyPaletteSetting ( ) ;
PORTSInitialize ( ) ;
hardReset ( ) ;
Tracer . WriteLine ( "EMU is ready." ) ;
success = true ;
emu_frame_clocking_mode = ! useThread ;
ON = true ;
PAUSED = false ;
if ( useThread )
{
Tracer . WriteLine ( "Running in a thread ... using custom frame limiter." ) ;
FrameLimiterEnabled = true ;
mainThread = new Thread ( EmuClock ) ;
mainThread . Start ( ) ;
}
MyNesMain . VideoProvider . SignalToggle ( started : true ) ;
MyNesMain . AudioProvider . SignalToggle ( started : true ) ;
}
else
{
success = false ;
}
}
else
{
success = false ;
}
}
public static void HardReset ( )
{
PAUSED = true ;
emu_request_mode = RequestMode . HardReset ;
}
private static void hardReset ( )
{
if ( MyNesMain . WaveRecorder . IsRecording )
{
MyNesMain . WaveRecorder . Stop ( ) ;
}
render_audio_toggle_pause ( paused : true ) ;
switch ( Region )
{
case EmuRegion . NTSC :
emu_time_target_fps = 60.0988 ;
break ;
case EmuRegion . PALB :
case EmuRegion . DENDY :
emu_time_target_fps = 50.0 ;
break ;
}
fps_time_period = 1.0 / emu_time_target_fps ;
MEMHardReset ( ) ;
CPUHardReset ( ) ;
PPUHardReset ( ) ;
APUHardReset ( ) ;
DMAHardReset ( ) ;
render_audio_toggle_pause ( paused : false ) ;
MyNesMain . VideoProvider . WriteWarningNotification ( MNInterfaceLanguage . Message_HardReset , instant : false ) ;
}
public static void SoftReset ( )
{
PAUSED = true ;
emu_request_mode = RequestMode . SoftReset ;
}
private static void softReset ( )
{
CPUSoftReset ( ) ;
APUSoftReset ( ) ;
MyNesMain . VideoProvider . WriteWarningNotification ( MNInterfaceLanguage . Message_SoftReset , instant : false ) ;
}
public static void SaveState ( )
{
PAUSED = true ;
emu_request_mode = RequestMode . SaveState ;
}
public static void LoadState ( )
{
PAUSED = true ;
emu_request_mode = RequestMode . LoadState ;
}
internal static void TakeSnapshot ( )
{
PAUSED = true ;
emu_request_mode = RequestMode . TakeSnapshot ;
}
public static void ShutDown ( )
{
MyNesMain . VideoProvider . SignalToggle ( started : false ) ;
MyNesMain . AudioProvider . SignalToggle ( started : false ) ;
if ( MyNesMain . WaveRecorder . IsRecording )
{
MyNesMain . WaveRecorder . Stop ( ) ;
}
render_audio_get_is_playing ( out render_audio_is_playing ) ;
if ( render_audio_is_playing )
{
render_audio_toggle_pause ( paused : true ) ;
}
Tracer . WriteLine ( "Shutting down the emulation core..." ) ;
ON = false ;
if ( mainThread ! = null )
{
Tracer . WriteLine ( "Aborting thread .." ) ;
while ( mainThread . IsAlive )
{
}
mainThread . Abort ( ) ;
mainThread = null ;
}
SaveSRAM ( ) ;
Tracer . WriteInformation ( "Emulation core shutdown successfully." ) ;
NesEmu . EmuShutdown ? . Invoke ( null , new EventArgs ( ) ) ;
}
internal static void EMUClockFrame ( )
{
emu_frame_done = false ;
while ( ! emu_frame_done & & ON )
{
if ( ! PAUSED )
{
CPUClock ( ) ;
}
else
{
Thread . Sleep ( 100 ) ;
}
}
}
private static void EmuClock ( )
{
while ( ON )
{
if ( ! PAUSED )
{
CPUClock ( ) ;
if ( ppu_frame_finished )
{
FrameFinished ( ) ;
}
continue ;
}
render_audio_get_is_playing ( out render_audio_is_playing ) ;
if ( render_audio_is_playing )
{
render_audio_toggle_pause ( paused : true ) ;
}
Thread . Sleep ( 100 ) ;
shortucts . Update ( ) ;
switch ( emu_request_mode )
{
case RequestMode . HardReset :
hardReset ( ) ;
PAUSED = false ;
emu_request_mode = RequestMode . None ;
break ;
case RequestMode . SoftReset :
softReset ( ) ;
PAUSED = false ;
emu_request_mode = RequestMode . None ;
break ;
case RequestMode . SaveState :
StateHandler . SaveState ( ) ;
PAUSED = false ;
emu_request_mode = RequestMode . None ;
break ;
case RequestMode . LoadState :
StateHandler . LoadState ( ) ;
PAUSED = false ;
emu_request_mode = RequestMode . None ;
break ;
case RequestMode . TakeSnapshot :
MyNesMain . VideoProvider . TakeSnapshot ( ) ;
PAUSED = false ;
emu_request_mode = RequestMode . None ;
break ;
}
isPaused = true ;
}
}
internal static void EmuClockComponents ( )
{
PPUClock ( ) ;
PollInterruptStatus ( ) ;
PPUClock ( ) ;
PPUClock ( ) ;
APUClock ( ) ;
DMAClock ( ) ;
mem_board . OnCPUClock ( ) ;
}
internal static void ApplyFrameSkipSettings ( )
{
FrameSkipEnabled = MyNesMain . RendererSettings . FrameSkipEnabled ;
FrameSkipInterval = MyNesMain . RendererSettings . FrameSkipInterval ;
}
private static void FrameFinished ( )
{
if ( ! FrameSkipEnabled )
{
render_video ( ref ppu_screen_pixels ) ;
}
else
{
FrameSkipCounter + + ;
if ( FrameSkipCounter > = FrameSkipInterval )
{
render_video ( ref ppu_screen_pixels ) ;
FrameSkipCounter = 0 ;
}
}
isPaused = false ;
ppu_frame_finished = false ;
emu_frame_done = true ;
joypad1 . Update ( ) ;
joypad2 . Update ( ) ;
if ( IsFourPlayers )
{
joypad3 . Update ( ) ;
joypad4 . Update ( ) ;
}
shortucts . Update ( ) ;
if ( SoundEnabled )
{
render_audio_get_is_playing ( out render_audio_is_playing ) ;
if ( ! render_audio_is_playing )
{
render_audio_toggle_pause ( paused : false ) ;
}
render_audio ( ref audio_samples , ref audio_samples_added ) ;
audio_w_pos = 0 ;
audio_samples_added = 0 ;
audio_timer = 0.0 ;
}
fps_time_token = GetTime ( ) - fps_time_start ;
if ( FrameLimiterEnabled )
{
if ( fps_time_token > 0.0 )
{
fps_time_dead = fps_time_period - fps_time_token ;
if ( fps_time_dead > 0.0 )
{
Thread . Sleep ( ( int ) Math . Floor ( fps_time_dead * 1000.0 ) ) ;
fps_time_dead = GetTime ( ) - fps_time_start ;
while ( fps_time_period - fps_time_dead > 0.0 )
{
fps_time_dead = GetTime ( ) - fps_time_start ;
}
}
}
fps_time_last = GetTime ( ) ;
fps_time_frame_time = fps_time_last - fps_time_start ;
}
fps_time_start = GetTime ( ) ;
}
private static double GetTime ( )
{
return ( double ) Stopwatch . GetTimestamp ( ) / ( double ) Stopwatch . Frequency ;
}
public static void GetSpeedValues ( out double frame_time , out double immediate_frame_time )
{
frame_time = fps_time_token ;
immediate_frame_time = fps_time_frame_time ;
}
public static void SetFramePeriod ( ref double period )
{
fps_time_period = period ;
}
public static void ApplyRegionSetting ( )
{
switch ( ( RegionSetting ) MyNesMain . EmuSettings . RegionSetting )
{
case RegionSetting . AUTO :
Tracer . WriteLine ( "REGION = AUTO" ) ;
Region = EmuRegion . NTSC ;
if ( CurrentFilePath . Contains ( "(E)" ) )
{
Region = EmuRegion . PALB ;
}
Tracer . WriteLine ( "REGION SELECTED: " + Region ) ;
break ;
case RegionSetting . ForceNTSC :
Tracer . WriteLine ( "REGION: FORCE NTSC" ) ;
Region = EmuRegion . NTSC ;
break ;
case RegionSetting . ForcePALB :
Tracer . WriteLine ( "REGION: FORCE PALB" ) ;
Region = EmuRegion . PALB ;
break ;
case RegionSetting . ForceDENDY :
Tracer . WriteLine ( "REGION: FORCE DENDY" ) ;
Region = EmuRegion . DENDY ;
break ;
}
SystemIndex = ( int ) Region ;
}
public static void ApplyPaletteSetting ( )
{
Tracer . WriteLine ( "Loading palette generators values from settings..." ) ;
NTSCPaletteGenerator . brightness = MyNesMain . RendererSettings . Palette_NTSC_brightness ;
NTSCPaletteGenerator . contrast = MyNesMain . RendererSettings . Palette_NTSC_contrast ;
NTSCPaletteGenerator . gamma = MyNesMain . RendererSettings . Palette_NTSC_gamma ;
NTSCPaletteGenerator . hue_tweak = MyNesMain . RendererSettings . Palette_NTSC_hue_tweak ;
NTSCPaletteGenerator . saturation = MyNesMain . RendererSettings . Palette_NTSC_saturation ;
PALBPaletteGenerator . brightness = MyNesMain . RendererSettings . Palette_PALB_brightness ;
PALBPaletteGenerator . contrast = MyNesMain . RendererSettings . Palette_PALB_contrast ;
PALBPaletteGenerator . gamma = MyNesMain . RendererSettings . Palette_PALB_gamma ;
PALBPaletteGenerator . hue_tweak = MyNesMain . RendererSettings . Palette_PALB_hue_tweak ;
PALBPaletteGenerator . saturation = MyNesMain . RendererSettings . Palette_PALB_saturation ;
Tracer . WriteLine ( "Setting up palette ...." ) ;
switch ( ( PaletteSelectSetting ) MyNesMain . RendererSettings . Palette_PaletteSetting )
{
case PaletteSelectSetting . AUTO :
Tracer . WriteLine ( "Palette set to auto detect depending on region." ) ;
switch ( Region )
{
case EmuRegion . NTSC :
SetupPalette ( NTSCPaletteGenerator . GeneratePalette ( ) ) ;
Tracer . WriteLine ( "Region is NTSC, Palette set from NTSC generator." ) ;
break ;
case EmuRegion . PALB :
case EmuRegion . DENDY :
SetupPalette ( PALBPaletteGenerator . GeneratePalette ( ) ) ;
Tracer . WriteLine ( "Region is PALB/DENDY, Palette set from PALB generator." ) ;
break ;
}
break ;
case PaletteSelectSetting . ForceNTSC :
Tracer . WriteLine ( "Palette set to always use NTSC palette generator." ) ;
SetupPalette ( NTSCPaletteGenerator . GeneratePalette ( ) ) ;
Tracer . WriteLine ( "Palette set from NTSC generator." ) ;
break ;
case PaletteSelectSetting . ForcePALB :
Tracer . WriteLine ( "Palette set to always use PALB palette generator." ) ;
SetupPalette ( NTSCPaletteGenerator . GeneratePalette ( ) ) ;
Tracer . WriteLine ( "Palette set from PALB generator." ) ;
break ;
case PaletteSelectSetting . File :
{
Tracer . WriteLine ( "Palette set to load from file." ) ;
var paletteFileStream = MyNesMain . FileManager . OpenPaletteFile ( ) ;
if ( paletteFileStream ! = null )
{
PaletteFileWrapper . LoadFile ( paletteFileStream , out var palette ) ;
SetupPalette ( palette ) ;
Tracer . WriteLine ( "Palette set from file" ) ;
break ;
}
Tracer . WriteError ( "Palette from file is not exist is not exist. Setting up palette from generators." ) ;
switch ( Region )
{
case EmuRegion . NTSC :
SetupPalette ( NTSCPaletteGenerator . GeneratePalette ( ) ) ;
Tracer . WriteLine ( "Region is NTSC, Palette set from NTSC generator." ) ;
break ;
case EmuRegion . PALB :
case EmuRegion . DENDY :
SetupPalette ( PALBPaletteGenerator . GeneratePalette ( ) ) ;
Tracer . WriteLine ( "Region is PALB/DENDY, Palette set from PALB generator." ) ;
break ;
}
break ;
}
}
}
internal static void WriteStateData ( ref BinaryWriter bin )
{
APUWriteState ( ref bin ) ;
CPUWriteState ( ref bin ) ;
DMAWriteState ( ref bin ) ;
InterruptsWriteState ( ref bin ) ;
MEMWriteState ( ref bin ) ;
PORTWriteState ( ref bin ) ;
PPUWriteState ( ref bin ) ;
}
internal static void ReadStateData ( ref BinaryReader bin )
{
APUReadState ( ref bin ) ;
CPUReadState ( ref bin ) ;
DMAReadState ( ref bin ) ;
InterruptsReadState ( ref bin ) ;
MEMReadState ( ref bin ) ;
PORTReadState ( ref bin ) ;
PPUReadState ( ref bin ) ;
}
private static void SQ2HardReset ( )
{
sq2_duty_cycle = 0 ;
sq2_length_halt = false ;
sq2_constant_volume_envelope = false ;
sq2_volume_devider_period = 0 ;
sq2_sweep_enable = false ;
sq2_sweep_devider_period = 0 ;
sq2_sweep_negate = false ;
sq2_sweep_shift_count = 0 ;
sq2_timer = 0 ;
sq2_period_devider = 0 ;
sq2_seqencer = 0 ;
sq2_length_enabled = false ;
sq2_length_counter = 0 ;
sq2_envelope_start_flag = false ;
sq2_envelope_devider = 0 ;
sq2_envelope_decay_level_counter = 0 ;
sq2_envelope = 0 ;
sq2_sweep_counter = 0 ;
sq2_sweep_reload = false ;
sq2_sweep_change = 0 ;
sq2_valid_freq = false ;
sq2_output = 0 ;
sq2_ignore_reload = false ;
}
private static void SQ2SoftReset ( )
{
SQ2HardReset ( ) ;
}
private static void SQ2Clock ( )
{
sq2_period_devider - - ;
if ( sq2_period_devider > 0 )
{
return ;
}
sq2_period_devider = sq2_timer + 1 ;
sq2_seqencer = ( byte ) ( ( uint ) ( sq2_seqencer + 1 ) & 7 u ) ;
if ( sq2_length_counter > 0 & & sq2_valid_freq )
{
if ( audio_sq2_outputable )
{
sq2_output = sq_duty_cycle_sequences [ sq2_duty_cycle ] [ sq2_seqencer ] * sq2_envelope ;
}
}
else
{
sq2_output = 0 ;
}
audio_signal_outputed = true ;
}
private static void SQ2ClockLength ( )
{
if ( sq2_length_counter > 0 & & ! sq2_length_halt )
{
sq2_length_counter - - ;
if ( apu_reg_access_happened & & apu_reg_io_addr = = 7 & & apu_reg_access_w )
{
sq2_ignore_reload = true ;
}
}
sq2_sweep_counter - - ;
if ( sq2_sweep_counter = = 0 )
{
sq2_sweep_counter = sq2_sweep_devider_period + 1 ;
if ( sq2_sweep_enable & & sq2_sweep_shift_count > 0 & & sq2_valid_freq )
{
sq2_sweep_change = sq2_timer > > ( int ) sq2_sweep_shift_count ;
sq2_timer + = ( sq2_sweep_negate ? ( - sq2_sweep_change ) : sq2_sweep_change ) ;
SQ2CalculateValidFreq ( ) ;
}
}
else if ( sq2_sweep_reload )
{
sq2_sweep_counter = sq2_sweep_devider_period + 1 ;
sq2_sweep_reload = false ;
}
}
private static void SQ2ClockEnvelope ( )
{
if ( sq2_envelope_start_flag )
{
sq2_envelope_start_flag = false ;
sq2_envelope_decay_level_counter = 15 ;
sq2_envelope_devider = ( byte ) ( sq2_volume_devider_period + 1 ) ;
}
else if ( sq2_envelope_devider > 0 )
{
sq2_envelope_devider - - ;
}
else
{
sq2_envelope_devider = ( byte ) ( sq2_volume_devider_period + 1 ) ;
if ( sq2_envelope_decay_level_counter > 0 )
{
sq2_envelope_decay_level_counter - - ;
}
else if ( sq2_length_halt )
{
sq2_envelope_decay_level_counter = 15 ;
}
}
sq2_envelope = ( sq2_constant_volume_envelope ? sq2_volume_devider_period : sq2_envelope_decay_level_counter ) ;
}
private static void APUOnRegister4004 ( )
{
if ( apu_reg_access_w )
{
sq2_duty_cycle = ( byte ) ( ( apu_reg_io_db & 0xC0 ) > > 6 ) ;
sq2_volume_devider_period = ( byte ) ( apu_reg_io_db & 0xF u ) ;
sq2_length_halt = ( apu_reg_io_db & 0x20 ) ! = 0 ;
sq2_constant_volume_envelope = ( apu_reg_io_db & 0x10 ) ! = 0 ;
sq2_envelope = ( sq2_constant_volume_envelope ? sq2_volume_devider_period : sq2_envelope_decay_level_counter ) ;
}
}
private static void APUOnRegister4005 ( )
{
if ( apu_reg_access_w )
{
sq2_sweep_enable = ( apu_reg_io_db & 0x80 ) = = 128 ;
sq2_sweep_devider_period = ( byte ) ( ( uint ) ( apu_reg_io_db > > 4 ) & 7 u ) ;
sq2_sweep_negate = ( apu_reg_io_db & 8 ) = = 8 ;
sq2_sweep_shift_count = ( byte ) ( apu_reg_io_db & 7 u ) ;
sq2_sweep_reload = true ;
SQ2CalculateValidFreq ( ) ;
}
}
private static void APUOnRegister4006 ( )
{
if ( apu_reg_access_w )
{
sq2_timer = ( sq2_timer & 0xFF00 ) | apu_reg_io_db ;
SQ2CalculateValidFreq ( ) ;
}
}
private static void APUOnRegister4007 ( )
{
if ( apu_reg_access_w )
{
sq2_timer = ( sq2_timer & 0xFF ) | ( ( apu_reg_io_db & 7 ) < < 8 ) ;
if ( sq2_length_enabled & & ! sq2_ignore_reload )
{
sq2_length_counter = sq_duration_table [ apu_reg_io_db > > 3 ] ;
}
if ( sq2_ignore_reload )
{
sq2_ignore_reload = false ;
}
sq2_seqencer = 0 ;
sq2_envelope_start_flag = true ;
SQ2CalculateValidFreq ( ) ;
}
}
private static void SQ2On4015 ( )
{
sq2_length_enabled = ( apu_reg_io_db & 2 ) ! = 0 ;
if ( ! sq2_length_enabled )
{
sq2_length_counter = 0 ;
}
}
private static void SQ2Read4015 ( )
{
if ( sq2_length_counter > 0 )
{
apu_reg_io_db = ( byte ) ( ( apu_reg_io_db & 0xFD u ) | 2 u ) ;
}
}
private static void SQ2CalculateValidFreq ( )
{
sq2_valid_freq = sq2_timer > = 8 & & ( sq2_sweep_negate | | ( ( sq2_timer + ( sq2_timer > > ( int ) sq2_sweep_shift_count ) ) & 0x800 ) = = 0 ) ;
}
private static void SQ2WriteState ( ref BinaryWriter bin )
{
bin . Write ( sq2_duty_cycle ) ;
bin . Write ( sq2_length_halt ) ;
bin . Write ( sq2_constant_volume_envelope ) ;
bin . Write ( sq2_volume_devider_period ) ;
bin . Write ( sq2_sweep_enable ) ;
bin . Write ( sq2_sweep_devider_period ) ;
bin . Write ( sq2_sweep_negate ) ;
bin . Write ( sq2_sweep_shift_count ) ;
bin . Write ( sq2_timer ) ;
bin . Write ( sq2_period_devider ) ;
bin . Write ( sq2_seqencer ) ;
bin . Write ( sq2_length_enabled ) ;
bin . Write ( sq2_length_counter ) ;
bin . Write ( sq2_envelope_start_flag ) ;
bin . Write ( sq2_envelope_devider ) ;
bin . Write ( sq2_envelope_decay_level_counter ) ;
bin . Write ( sq2_envelope ) ;
bin . Write ( sq2_sweep_counter ) ;
bin . Write ( sq2_sweep_reload ) ;
bin . Write ( sq2_sweep_change ) ;
bin . Write ( sq2_valid_freq ) ;
bin . Write ( sq2_output ) ;
bin . Write ( sq2_ignore_reload ) ;
}
private static void SQ2ReadState ( ref BinaryReader bin )
{
sq2_duty_cycle = bin . ReadByte ( ) ;
sq2_length_halt = bin . ReadBoolean ( ) ;
sq2_constant_volume_envelope = bin . ReadBoolean ( ) ;
sq2_volume_devider_period = bin . ReadByte ( ) ;
sq2_sweep_enable = bin . ReadBoolean ( ) ;
sq2_sweep_devider_period = bin . ReadByte ( ) ;
sq2_sweep_negate = bin . ReadBoolean ( ) ;
sq2_sweep_shift_count = bin . ReadByte ( ) ;
sq2_timer = bin . ReadInt32 ( ) ;
sq2_period_devider = bin . ReadInt32 ( ) ;
sq2_seqencer = bin . ReadByte ( ) ;
sq2_length_enabled = bin . ReadBoolean ( ) ;
sq2_length_counter = bin . ReadInt32 ( ) ;
sq2_envelope_start_flag = bin . ReadBoolean ( ) ;
sq2_envelope_devider = bin . ReadByte ( ) ;
sq2_envelope_decay_level_counter = bin . ReadByte ( ) ;
sq2_envelope = bin . ReadByte ( ) ;
sq2_sweep_counter = bin . ReadInt32 ( ) ;
sq2_sweep_reload = bin . ReadBoolean ( ) ;
sq2_sweep_change = bin . ReadInt32 ( ) ;
sq2_valid_freq = bin . ReadBoolean ( ) ;
sq2_output = bin . ReadInt32 ( ) ;
sq2_ignore_reload = bin . ReadBoolean ( ) ;
}
2024-07-03 18:22:22 +08:00
}
2024-07-03 15:40:13 +08:00
}