add main emulation loop with preliminary timing

Wed, 01 Dec 2010 21:29:44 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 01 Dec 2010 21:29:44 +0000
changeset 20
bea459bc22a8
parent 19
ea417ac1d83a
child 21
e31d2ede6c6b

add main emulation loop with preliminary timing

src/main.c file | annotate | diff | revisions
     1.1 --- a/src/main.c	Tue Nov 30 01:51:22 2010 +0000
     1.2 +++ b/src/main.c	Wed Dec 01 21:29:44 2010 +0000
     1.3 @@ -5,8 +5,9 @@
     1.4  #include <malloc.h>
     1.5  #include <string.h>
     1.6  
     1.7 +#include "SDL.h"
     1.8 +
     1.9  #include "musashi/m68k.h"
    1.10 -
    1.11  #include "version.h"
    1.12  #include "state.h"
    1.13  
    1.14 @@ -179,40 +180,74 @@
    1.15  	// 512K of RAM
    1.16  	state_init(512*1024);
    1.17  
    1.18 -	// set up musashi
    1.19 +	// set up musashi and reset the CPU
    1.20  	m68k_set_cpu_type(M68K_CPU_TYPE_68010);
    1.21  	m68k_pulse_reset();
    1.22 -
    1.23 -	char dasm[512];
    1.24 -	m68k_disassemble(dasm, 0x80001a, M68K_CPU_TYPE_68010);
    1.25 -	printf("%s\n", dasm);
    1.26 +/*
    1.27 +	size_t i = 0x80001a;
    1.28 +	size_t len;
    1.29 +	do {
    1.30 +		char dasm[512];
    1.31 +		len = m68k_disassemble(dasm, i, M68K_CPU_TYPE_68010);
    1.32 +		printf("%06X: %s\n", i, dasm);
    1.33 +		i += len;
    1.34 +	} while (i < 0x8000ff);
    1.35 +*/
    1.36  
    1.37  	// set up SDL
    1.38 +	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1) {
    1.39 +		printf("Could not initialise SDL: %s.\n", SDL_GetError());
    1.40 +		return -1;
    1.41 +	}
    1.42  
    1.43 -	// emulation loop!
    1.44 -	// repeat:
    1.45 -	// 		m68k_execute()
    1.46 -	// 		m68k_set_irq() every 60ms
    1.47 -	int32_t dwTimerTickCounter, dwCpuCycles;
    1.48 -	const int32_t CLOCKS_PER_TIMER_TICK = 10e6/60;		//< number of clocks per 60Hz timer tick
    1.49 -
    1.50 -	// initialise emulation variables
    1.51 -	dwTimerTickCounter = CLOCKS_PER_TIMER_TICK;
    1.52 +	/***
    1.53 +	 * The 3B1 CPU runs at 10MHz, with DMA running at 1MHz and video refreshing at
    1.54 +	 * around 60Hz (???), with a 60Hz periodic interrupt.
    1.55 +	 */
    1.56 +	const uint32_t TIMESLOT_FREQUENCY = 240;	// Hz
    1.57 +	const uint32_t MILLISECS_PER_TIMESLOT = 1e3 / TIMESLOT_FREQUENCY;
    1.58 +	const uint32_t CLOCKS_PER_60HZ = (10e6 / 60);
    1.59 +	uint32_t next_timeslot = SDL_GetTicks() + MILLISECS_PER_TIMESLOT;
    1.60 +	uint32_t clock_cycles = 0;
    1.61  	bool exitEmu = false;
    1.62  	for (;;) {
    1.63 -		dwCpuCycles = m68k_execute(10e6/60);
    1.64 -		dwTimerTickCounter -= dwCpuCycles;
    1.65 +		// Run the CPU for however many cycles we need to. CPU core clock is
    1.66 +		// 10MHz, and we're running at 240Hz/timeslot. Thus: 10e6/240 or
    1.67 +		// 41667 cycles per timeslot.
    1.68 +		clock_cycles += m68k_execute(10e6/TIMESLOT_FREQUENCY);
    1.69 +
    1.70 +		// TODO: run DMA here
    1.71  
    1.72 -		// check for timer tick expiry
    1.73 -		if (dwTimerTickCounter <= 0) {
    1.74 -			// TODO: Timer Tick IRQ
    1.75 -			
    1.76 +		// Is it time to run the 60Hz periodic interrupt yet?
    1.77 +		if (clock_cycles > CLOCKS_PER_60HZ) {
    1.78 +			// TODO: refresh screen
    1.79 +			// TODO: trigger periodic interrupt (if enabled)
    1.80 +			// decrement clock cycle counter, we've handled the intr.
    1.81 +			clock_cycles -= CLOCKS_PER_60HZ;
    1.82  		}
    1.83  
    1.84 +		printf("timeslot\n");
    1.85 +
    1.86 +		// make sure frame rate is equal to real time
    1.87 +		uint32_t now = SDL_GetTicks();
    1.88 +		if (now < next_timeslot) {
    1.89 +			// timeslot finished early -- eat up some time
    1.90 +			SDL_Delay(next_timeslot - now);
    1.91 +		} else {
    1.92 +			// timeslot finished late -- skip ahead to gain time
    1.93 +			// TODO: if this happens a lot, we should let the user know
    1.94 +			// that their PC might not be fast enough...
    1.95 +			next_timeslot = now;
    1.96 +		}
    1.97 +		// advance to the next timeslot
    1.98 +		next_timeslot += MILLISECS_PER_TIMESLOT;
    1.99 +
   1.100 +		// if we've been asked to exit the emulator, then do so.
   1.101  		if (exitEmu) break;
   1.102  	}
   1.103  
   1.104  	// shut down and exit
   1.105 +	SDL_Quit();
   1.106  
   1.107  	return 0;
   1.108  }