diff --git a/src/cpu.S b/src/cpu.S index e3784777..042989aa 100644 --- a/src/cpu.S +++ b/src/cpu.S @@ -32,8 +32,9 @@ #define DebugCurrEA SN(cpu65_debug) #define DebugCurrByte SN(cpu65_debug)+2 -#define DebugCurrOp SN(cpu65_debug)+3 -#define XCyclesCount SN(cpu65_debug)+4 +#define DebugCurrRW SN(cpu65_debug)+3 +#define DebugCycleCount SN(cpu65_debug)+4 +#define DebugCurrOpcode SN(cpu65_debug)+5 /* ------------------------------------------------------------------------- CPU (6502) Helper Routines @@ -57,7 +58,7 @@ (,EffectiveAddr_E,8); \ #define GetFromEA_B \ - orb $1, DebugCurrOp; \ + orb $1, DebugCurrRW; \ call *SN(cpu65_vmem) \ (,EffectiveAddr_E,8); @@ -71,7 +72,7 @@ (,EffectiveAddr_E,8); #define PutToEA_B \ - orb $2, DebugCurrOp; \ + orb $2, DebugCurrRW; \ orb %al, DebugCurrByte; \ call *SN(cpu65_vmem)+4 \ (,EffectiveAddr_E,8); @@ -90,10 +91,6 @@ call *SN(cpu65_vmem) \ (,EffectiveAddr_E,8); \ -// reset operation code before each instruction -#define ZeroOp movb $0, DebugCurrOp; \ - movb $0, XCyclesCount; - // NOTE: the orb functions as a move, but we want to // set the flags and we know %ah is zero #define Continue \ @@ -139,12 +136,12 @@ 9: #define BranchXCycles \ - incb XCyclesCount; /* +1 cycle branch taken */ \ + incb DebugCycleCount; /* +1 branch taken */ \ pushl %ebx; \ movw PC_Reg, %bx; \ addb %al, %bl; \ jnc 9f; \ - incb XCyclesCount; /* +1 cycle branch across pg boundary */ \ + incb DebugCycleCount; /* +1 branch across pg boundary */ \ 9: addw %ax, PC_Reg; \ popl %ebx; @@ -234,7 +231,7 @@ addb X_Reg, %al; \ jnc 9f; \ adcb $0, %ah; \ - incb XCyclesCount; /* +1 cycle on page boundary */ \ + incb DebugCycleCount; /* +1 cycle on page boundary */ \ 9: movl %eax, EffectiveAddr_E; #define GetAbs_Y \ @@ -242,7 +239,7 @@ addb Y_Reg, %al; \ jnc 9f; \ adcb $0, %ah; \ - incb XCyclesCount; /* +1 cycle on page boundary */ \ + incb DebugCycleCount; /* +1 cycle on page boundary */ \ 9: movl %eax, EffectiveAddr_E; /* Absolute Indirect Addressing - The second and third bytes of the @@ -309,7 +306,7 @@ addb Y_Reg, %al; \ jnc 9f; \ adcb $0, %ah; \ - incb XCyclesCount; /* +1 cycle on page boundary */ \ + incb DebugCycleCount; /* +1 cycle on page boundary */ \ 9: movl %eax, EffectiveAddr_E; #define DoADC_b GetFromEA_B \ @@ -464,7 +461,7 @@ // Decimal mode op_ADC_dec: - incb XCyclesCount // +1 cycle + incb DebugCycleCount // +1 cycle DoADC_d Continue @@ -1590,7 +1587,7 @@ op_RTS: ---------------------------------- */ op_SBC_dec: - incb XCyclesCount // +1 cycle + incb DebugCycleCount // +1 cycle DoSBC_d Continue @@ -1727,7 +1724,7 @@ op_STA_imm: op_STA_zpage: GetZPage DoSTA - incb XCyclesCount // +1 cycle on write + incb DebugCycleCount // +1 cycle on write Continue op_STA_zpage_x: @@ -1747,13 +1744,13 @@ op_STA_abs: op_STA_abs_x: GetAbs_X DoSTA - incb XCyclesCount // +1 cycle on write + incb DebugCycleCount // +1 cycle on write Continue op_STA_abs_y: GetAbs_Y DoSTA - incb XCyclesCount // +1 cycle on write + incb DebugCycleCount // +1 cycle on write Continue op_STA_ind_x: @@ -1764,7 +1761,7 @@ op_STA_ind_x: op_STA_ind_y: GetIndZPage_Y DoSTA - incb XCyclesCount // +1 cycle on write + incb DebugCycleCount // +1 cycle on write Continue // 65c02 : 0x92 @@ -1817,7 +1814,7 @@ op_RMB7_65c02: op_STX_zpage: GetZPage DoSTX - incb XCyclesCount // +1 cycle on write + incb DebugCycleCount // +1 cycle on write Continue // HACK : is this used? need to study coverage ... @@ -1838,7 +1835,7 @@ op_STX_abs: op_STY_zpage: GetZPage DoSTY - incb XCyclesCount // +1 cycle on write + incb DebugCycleCount // +1 cycle on write Continue op_STY_zpage_x: @@ -1860,7 +1857,7 @@ op_STY_abs: op_STZ_zpage: GetZPage DoSTZ - incb XCyclesCount // +1 cycle on write + incb DebugCycleCount // +1 cycle on write Continue // 65c02 : 0x74 @@ -1878,7 +1875,7 @@ op_STZ_abs: op_STZ_abs_x: GetAbs_X DoSTZ - incb XCyclesCount // +1 cycle on write + incb DebugCycleCount // +1 cycle on write Continue /* ---------------------------------- @@ -2664,8 +2661,10 @@ continue: SaveState call SN(timing_throttle) ReplaceState xorb %ah, %ah - ZeroOp + movb $0, DebugCurrRW + movb $0, DebugCycleCount GetFromPC_B + movb $al, DebugCurrOpcode jmp *cpu65__opcodes(,%eax,4) /* Exception handler */ diff --git a/src/cpu.h b/src/cpu.h index 54cb0277..115f7ffb 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -43,8 +43,9 @@ struct cpu65_extra { uint16_t ea; /* Last effective address */ uint8_t d; /* Last data byte written */ - uint8_t op; /* 1 = read occured, 2 = write, 3 = both */ - uint8_t xcycles; /* Last opcode extra cycles */ + uint8_t rw; /* 1 = read occured, 2 = write, 3 = both */ + uint8_t opcode; /* Last opcode */ + uint8_t opcycles; /* Last opcode extra cycles */ }; /* 6502 CPU models */ diff --git a/src/misc.c b/src/misc.c index 6e526305..d4138086 100644 --- a/src/misc.c +++ b/src/misc.c @@ -732,17 +732,19 @@ void c_read_random() { static void cpu_thread(void *dummyptr) { do { + LOG("cpu_thread : entering cpu65_run()..."); cpu65_run(); reinitialize(); } while (1); } static void main_thread(void *dummyptr) { + struct timespec abstime = { .tv_sec=0, .tv_nsec=8333333 }; // 120Hz do { - // sleep waiting for the cpu thread to ping us that it's sleeping... + // sleep waiting for the cpu thread to ping us to render pthread_mutex_lock(&mutex); - pthread_cond_wait(&cond, &mutex); + pthread_cond_timedwait(&cond, &mutex, &abstime); pthread_mutex_unlock(&mutex); c_periodic_update(0); diff --git a/src/timing.c b/src/timing.c index ec714681..f9816dec 100644 --- a/src/timing.c +++ b/src/timing.c @@ -17,16 +17,20 @@ #include #include #include +#include -#define DEFAULT_SLEEP 120 +#define CALIBRATE_HZ 120 -static unsigned int sleep_hz = DEFAULT_SLEEP; // sleep intervals per sec static unsigned long cpu_target_hz = APPLE2_HZ; // target clock speed -static unsigned long cycles_interval = APPLE2_HZ / DEFAULT_SLEEP; // Number of 65c02 instructions to be executed at sleep_hz -static unsigned long processing_interval = NANOSECONDS / DEFAULT_SLEEP; // Number of nanoseconds in sleep_hz intervals +static unsigned long calibrate_interval = NANOSECONDS / CALIBRATE_HZ; // calibration interval for drifting +static unsigned long cycle_nanoseconds = NANOSECONDS / APPLE2_HZ; // nanosecs per cycle +static unsigned int cycle_nanoseconds_count; static struct timespec deltat, t0, ti, tj; -static unsigned long cycle=0; + +static unsigned long cycle_count=0; // CPU cycle counter +static int spinloop_count=0; // spin loop counter + static long sleep_adjust=0; static long sleep_adjust_inc=0; @@ -58,73 +62,137 @@ static inline long timespec_nsecs(struct timespec t) { return t.tv_sec*NANOSECONDS + t.tv_nsec; } +// spin loop to throttle to target CPU Hz +static inline void _spin_loop(unsigned long c) +{ + static volatile unsigned int spinney=0; // volatile to prevent being optimized away + for (unsigned long i=0; i 0) + { + printf("oops long wait (>= %lu sec) adjusting loop count (%d -> %d)\n", deltat.tv_sec, spinloop_count, spinloop_count>>1); + spinloop_count >>= 1; + i = 0; + avg_spin_nsecs = 0; + continue; + } + + printf("spinloop = %lu nsec\n", deltat.tv_nsec); + avg_spin_nsecs += deltat.tv_nsec; + ++i; + } while (i instruction_interval_nsecs) + { + // spin for additional +/- X each instruction + spinloop_count += diff_nsecs / instruction_interval_nsecs; + spin_adjust_interval=INT_MAX; + } + else + { + // sub adjustment : spin for additional +/- 1 every interval + spin_adjust_count = diff_nsecs < 0 ? -1 : 1; + spin_adjust_interval = instruction_interval_nsecs / abs(diff_nsecs); } } + diff --git a/src/timing.h b/src/timing.h index 076a81b4..9d21c2cb 100644 --- a/src/timing.h +++ b/src/timing.h @@ -13,12 +13,11 @@ #ifndef _TIMING_H_ #define _TIMING_H_ -#define APPLE2_HZ 2040000 +#define APPLE2_HZ 1020000 #define NANOSECONDS 1000000000 -void timing_set_cpu_target_hz(unsigned long hz); - -void timing_set_sleep_hz(unsigned int hz); +// 0 = run as fast as possible, 1 = approximate apple, X = 1/X rate +void timing_set_cpu_scale(unsigned int scale); void timing_initialize();