summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSegher Boessenkool <segher@kernel.crashing.org>2010-02-17 04:20:49 +0100
committerSegher Boessenkool <segher@kernel.crashing.org>2010-02-17 04:20:49 +0100
commitae73b78f4917389d8db525ce5f7d48f232c5d048 (patch)
tree05bf83a53d11e46edd9f393214783526e34a8720
parenta4109d5c527d4e050d6021f78d26c0a24014e7c2 (diff)
Make timing virtual; sync with real time each video frame
-rw-r--r--emu.c102
-rw-r--r--io.c9
-rw-r--r--platform-sdl.c13
-rw-r--r--platform.h2
-rw-r--r--timer.c72
-rw-r--r--timer.h10
-rw-r--r--video.c8
7 files changed, 83 insertions, 133 deletions
diff --git a/emu.c b/emu.c
index 5b24524..a9170a1 100644
--- a/emu.c
+++ b/emu.c
@@ -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();
diff --git a/io.c b/io.c
index ddde04a..bc54089 100644
--- a/io.c
+++ b/io.c
@@ -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)
diff --git a/platform.h b/platform.h
index a9ce58f..57398f2 100644
--- a/platform.h
+++ b/platform.h
@@ -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, ...);
diff --git a/timer.c b/timer.c
index ed9988a..aa3b898 100644
--- a/timer.c
+++ b/timer.c
@@ -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();
}
diff --git a/timer.h b/timer.h
index 2f0fb25..3bc2f86 100644
--- a/timer.h
+++ b/timer.h
@@ -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
diff --git a/video.c b/video.c
index d98e6f0..a3e0e0f 100644
--- a/video.c
+++ b/video.c
@@ -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