diff options
author | Segher Boessenkool <segher@kernel.crashing.org> | 2010-02-17 04:20:49 +0100 |
---|---|---|
committer | Segher Boessenkool <segher@kernel.crashing.org> | 2010-02-17 04:20:49 +0100 |
commit | ae73b78f4917389d8db525ce5f7d48f232c5d048 (patch) | |
tree | 05bf83a53d11e46edd9f393214783526e34a8720 | |
parent | a4109d5c527d4e050d6021f78d26c0a24014e7c2 (diff) |
Make timing virtual; sync with real time each video frame
-rw-r--r-- | emu.c | 102 | ||||
-rw-r--r-- | io.c | 9 | ||||
-rw-r--r-- | platform-sdl.c | 13 | ||||
-rw-r--r-- | platform.h | 2 | ||||
-rw-r--r-- | timer.c | 72 | ||||
-rw-r--r-- | timer.h | 10 | ||||
-rw-r--r-- | video.c | 8 |
7 files changed, 83 insertions, 133 deletions
@@ -20,13 +20,11 @@ #define FREQ 50 -#define PERIOD (500000/FREQ) +#define PERIOD (1000000/FREQ) u16 mem[N_MEM]; -static u32 timer_handled; - static int trace = 0; static int trace_new = 0; static int store_trace = 0; @@ -48,7 +46,10 @@ static u8 irq_active, fiq_active; static u8 irq_enabled, fiq_enabled; static u64 insn_count; -static u32 cycle_count; // 1728 cycles/line for PAL, 1716 for NTSC +static u32 cycle_count; +static u32 line_count; +static const u32 cycles_per_line = 1728; // 1728 for PAL, 1716 for NTSC +static const u32 lines_per_field = 312; // 312 for PAL, 262 for NTSC u32 get_ds(void) @@ -762,11 +763,11 @@ bad: fatal("! UNIMPLEMENTED\n"); } -static u32 last_retrace_time = 0; - static void do_idle(void) { - u32 now = timer_now(); + static u32 last_retrace_time = 0; + + u32 now = get_realtime(); if (now < last_retrace_time + PERIOD) { // printf(" sleeping %dus\n", last_retrace_time + PERIOD - now); usleep(last_retrace_time + PERIOD - now); @@ -775,17 +776,16 @@ static void do_idle(void) u16 get_video_line(void) { - u32 now = timer_now(); - return (now - last_retrace_time) * 625 * FREQ / 2 / 1000000; // 525 for NTSC + return line_count; } -static void run_main(void) +static void run_line(void) { int idle = 0; for (;;) { - if (timer_triggered != timer_handled) - break; +// if (timer_triggered != timer_handled) +// break; if (trace) print_state(); @@ -797,20 +797,20 @@ static void run_main(void) if (cs_pc() == board->idle_pc) { idle++; - if (idle == 2) + if (idle == 2) { + cycle_count = 0; break; + } } step(); insn_count++; + if (cycle_count >= cycles_per_line) { +// printf("PING!\n"); + cycle_count -= cycles_per_line; + break; + } } - - if (timer_triggered != timer_handled) { - timer_run(); - timer_handled++; - timer_set(1000000/250); - } else - do_idle(); } static void do_controller(void) @@ -888,66 +888,64 @@ static void do_controller(void) struct timer timer_controller = { .name = "controller", - .time = 20000, + .time = 0, .interval = 20000, .run = do_controller }; static void run(void) { - run_main(); + for (line_count = 0; line_count < lines_per_field; line_count++) { + run_line(); - u32 now = timer_now(); + timer_run(cycles_per_line); - if (now - last_retrace_time >= PERIOD) { - static int count = 0; - count++; - if (count == 5) { - screen_needs_update = 1; - count = 0; - } + if (line_count == 240) + mem[0x2863] |= 1; // trigger vblank IRQ + if (line_count == mem[0x2836]) + mem[0x2863] |= 2; // trigger vpos IRQ - // video - // FIXME: make this better - static u32 which = 1; + maybe_enter_irq(); + } - mem[0x2863] |= which; - which ^= 3; +// static u32 last; +// u32 now = get_realtime(); +// printf("-> %uus for this field (cpu)\n", now - last); +// last = now; - last_retrace_time = now; + update_screen(); - if (do_extint1) { - mem[0x3d22] |= 0x0200; - do_extint1 = 0; - } - if (do_extint2) { - mem[0x3d22] |= 0x1000; - do_extint2 = 0; - } +// now = get_realtime(); +// printf("-> %uus for this field (gfx)\n", now - last); +// last = now; - // UART FIXME -mem[0x3d22] |= 0x0100; - } + do_controller(); - maybe_enter_irq(); + mem[0x3d22] |= 0x0100; // UART FIXME + if (do_extint1) { + mem[0x3d22] |= 0x0200; + do_extint1 = 0; + } + if (do_extint2) { + mem[0x3d22] |= 0x1000; + do_extint2 = 0; + } -#if 0 -// XXX: move this elsewhere if (pause_after_every_frame) { printf("*** paused, press a key to continue\n"); while (update_controller() == 0) ; } -#endif + + do_idle(); } void emu(void) { platform_init(); read_rom(0); - timer_init(); board_init(); io_init(); audio_init(); @@ -132,13 +132,13 @@ static void do_tmb2(void) static struct timer timer_tmb1 = { .name = "TMB1", - .interval = 1000000/8, + .interval = 27000000/8, .run = do_tmb1 }; static struct timer timer_tmb2 = { .name = "TMB2", - .interval = 1000000/128, + .interval = 27000000/128, .run = do_tmb2 }; @@ -190,12 +190,12 @@ void io_store(u16 val, u32 addr) if ((mem[addr] & 0x0003) != (val & 0x0003)) { u16 hz = 8 << (val & 0x0003); printf("*** TMB1 FREQ set to %dHz\n", hz); - timer_tmb1.interval = 1000000 / hz; + timer_tmb1.interval = 27000000 / hz; } if ((mem[addr] & 0x000c) != (val & 0x000c)) { u16 hz = 128 << ((val & 0x000c) >> 2); printf("*** TMB2 FREQ set to %dHz\n", hz); - timer_tmb2.interval = 1000000 / hz; + timer_tmb2.interval = 27000000 / hz; } break; @@ -225,7 +225,6 @@ void io_store(u16 val, u32 addr) break; case 0x3d22: // IRQ ack -//printf("######## ACK %04x\n", val); mem[addr] &= ~val; return; diff --git a/platform-sdl.c b/platform-sdl.c index 2199f1a..8e3e140 100644 --- a/platform-sdl.c +++ b/platform-sdl.c @@ -5,6 +5,7 @@ #include <stdio.h> #include <stdarg.h> #include <sys/stat.h> +#include <sys/time.h> #include <SDL.h> #include "types.h" @@ -260,6 +261,16 @@ char update_controller(void) return 0; } + +u32 get_realtime(void) +{ + struct timeval tv; + + gettimeofday(&tv, 0); + return 1000000*tv.tv_sec + tv.tv_usec; +} + + void warn(const char *format, ...) { va_list ap; @@ -275,6 +286,7 @@ void fatal(const char *format, ...) exit(1); } + static void mix(void *cookie, u8 *data, int n) { if (mute_audio) { @@ -285,6 +297,7 @@ static void mix(void *cookie, u8 *data, int n) audio_render((s16 *)data, n/2); } + void platform_init(void) { if (SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0) @@ -28,6 +28,8 @@ void save_eeprom(void *cookie, u8 *data, u32 len); void update_screen(void); char update_controller(void); +u32 get_realtime(void); + void fatal(const char *format, ...); void warn(const char *format, ...); @@ -2,52 +2,22 @@ // Licensed under the terms of the GNU GPL, version 2 // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt -#include <sys/time.h> -#include <signal.h> -#include <unistd.h> #include <stdio.h> #include "types.h" -#include "platform.h" #include "timer.h" -static int trace_timer = 1; - -volatile u32 timer_triggered; +static int trace_timer = 0; static struct timer *timers; -static u32 timer_time; - -u32 timer_now(void) -{ - struct timeval tv; - - gettimeofday(&tv, 0); - return 1000000*tv.tv_sec + tv.tv_usec; -} - -void timer_set(u32 usecs) -{ - struct itimerval it; - - it.it_value.tv_sec = usecs / 1000000; - it.it_value.tv_usec = usecs % 1000000; - it.it_interval.tv_sec = 0; - it.it_interval.tv_usec = 0; - - int err = setitimer(ITIMER_REAL, &it, 0); - if (err) - fatal("setitimer failed"); -} void timer_debug(void) { - printf("timer head = %u, now = %u\n", timer_time, timer_now()); struct timer *timer; for (timer = timers; timer; timer = timer->next) - printf("timer \"%s\" %dus\n", timer->name, timer->time); + printf("timer \"%s\" %u ticks\n", timer->name, timer->time); } void timer_add(struct timer *timer) @@ -55,7 +25,7 @@ void timer_add(struct timer *timer) if (timer->time == 0) timer->time = timer->interval; - u32 time = timer_now() - timer_time + timer->time; + u32 time = timer->time; struct timer **p = &timers; while (*p && (*p)->time <= time) { @@ -70,19 +40,18 @@ void timer_add(struct timer *timer) timer->next->time -= time; } -void timer_run(void) +void timer_run(u32 ticks) { - u32 now = timer_now(); - u32 elapsed = now - timer_time; +//printf("going to run for %u ticks...\n", ticks); +//timer_debug(); struct timer *timer; - while ((timer = timers) && timer->time <= elapsed) { + while ((timer = timers) && timer->time <= ticks) { timers = timer->next; - timer_time += timer->time; - elapsed -= timer->time; + ticks -= timer->time; if (trace_timer) - printf("running timer \"%s\" (%u)\n", timer->name, now); + printf("running timer \"%s\"\n", timer->name); if (timer->run) timer->run(); @@ -94,25 +63,8 @@ void timer_run(void) } if (timer) - timer->time -= elapsed; - timer_time = now; -} - -static void alarm_handler(int signo, siginfo_t *si, void *uc) -{ - timer_triggered++; -} - -void timer_init(void) -{ - struct sigaction sa; - - sa.sa_sigaction = alarm_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; - sigaction(SIGALRM, &sa, 0); - - timer_time = timer_now(); + timer->time -= ticks; - timer_set(1); +//printf("timers done:\n"); +//timer_debug(); } @@ -7,8 +7,6 @@ #include "types.h" -extern volatile u32 timer_triggered; - struct timer { const char *name; u32 time; @@ -19,13 +17,7 @@ struct timer { void timer_debug(void); -u32 timer_now(void); void timer_add(struct timer *timer); -void timer_run(void); - -// XXX: temp -void timer_set(u32 usecs); - -void timer_init(void); +void timer_run(u32 ticks); #endif @@ -23,8 +23,6 @@ int hide_page_2; int hide_sprites; int trace_unknown_video = 1; -int screen_needs_update; - static const u8 sizes[] = { 8, 16, 32, 64 }; static const u8 colour_sizes[] = { 2, 4, 6, 8 }; @@ -100,7 +98,7 @@ static void do_dma(u32 len) mem[dst+j] = mem[src+j]; mem[0x2872] = 0; - mem[0x2863] |= 0x0004; + mem[0x2863] |= 4; // trigger video DMA IRQ } void video_store(u16 val, u32 addr) @@ -176,10 +174,6 @@ void video_store(u16 val, u32 addr) case 0x2863: // video IRQ status mem[addr] &= ~val; - if (val & 1 && screen_needs_update) { - update_screen(); - screen_needs_update = 0; - } return; case 0x2870: // video DMA src |