From http://www.jwz.org/xscreensaver/xscreensaver-5.38.tar.gz
[xscreensaver] / hacks / m6502.c
index 705af37c2304b9ec9815ded71bec6d0f1e6f2c62..ce18e9d3d9af074e85182ff49f327f59787e9432 100644 (file)
  * Created: 07-May-2007 
  */
 
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if defined(HAVE_STDINT_H)
 #include <stdint.h> 
+#elif defined(HAVE_INTTYPES_H)
+#include <inttypes.h>
+#endif
 #include <string.h>
 #include "screenhack.h"
 #include "analogtv.h"
                     ISO C89 compilers are required to support" when includng
                     the following data file... */
 # endif
-const char * const demo_files[] = {
+static const char * const demo_files[] = {
 # include "m6502.h"
 };
 
 
+#ifndef HAVE_MOBILE
+# define READ_FILES
+#endif
+
+
 /* We want to paint on a 32 by 32 grid of pixels. We will needed to
    divided the screen up into chuncks */
 enum {
@@ -51,10 +63,14 @@ struct state {
   int pixh;/* pixel height */
   int topb;/* top boarder */
   int field_ntsc[4];/* used for clearing the screen*/ 
-  int dt;/* how long to wait before changing the demo*/
+  double dt;/* how long to wait before changing the demo*/
   int which;/* the program to run*/
   int demos;/* number of demos included */
-  struct timeval start_time; 
+  double start_time;
+  int reset_p;
+  char *file;
+  double last_frame, last_delay;
+  unsigned ips;
 };
 
 static void
@@ -74,48 +90,32 @@ start_rand_bin_prog(machine_6502 *machine, struct state *st){
   while(n == st->which)
     n = random() % st->demos;
   st->which = n;
-  start_eval_string(machine, demo_files[st->which], plot6502, st);
+  m6502_start_eval_string(machine, demo_files[st->which], plot6502, st);
 }
 
 \f
 /*
- * get_time ()
+ * double_time ()
  *
- * returns the total time elapsed since the beginning of the demo
+ * returns the current time as a floating-point value
  */
-static double get_time(struct state *st) {
+static double double_time(void) {
   struct timeval t;
-  float f;
+  double f;
 #if GETTIMEOFDAY_TWO_ARGS
   gettimeofday(&t, NULL);
 #else
   gettimeofday(&t);
 #endif
-  t.tv_sec -= st->start_time.tv_sec;
   f = ((double)t.tv_sec) + t.tv_usec*1e-6;
   return f;
 }
 
-/*
- * init_time ()
- *
- * initialises the timing structures
- */
-static void init_time(struct state *st) {
-#if GETTIMEOFDAY_TWO_ARGS
-  gettimeofday(&st->start_time, NULL);
-#else
-  gettimeofday(&st->start_time);
-#endif
-}
-
 static void *
 m6502_init (Display *dpy, Window window)
 {
   struct state *st = (struct state *) calloc (1, sizeof(*st));
-  unsigned int x, y;
-  char *s = get_string_resource (dpy, "file", "File");
-  int n = get_integer_resource(dpy, "displaytime", "Displaytime");
+  int n = get_float_resource(dpy, "displaytime", "Displaytime");
   int dh;
   st->demos = countof(demo_files);
   st->which = random() % st->demos;
@@ -125,7 +125,7 @@ m6502_init (Display *dpy, Window window)
   st->tv=analogtv_allocate(st->dpy, st->window);
   analogtv_set_defaults(st->tv, "");
   
-  st->machine = build6502();
+  st->machine = m6502_build();
   st->inp=analogtv_input_allocate();
   analogtv_setup_sync(st->inp, 1, 0);
   
@@ -139,12 +139,15 @@ m6502_init (Display *dpy, Window window)
   dh = SCREEN_H % 32;
   st->topb = dh / 2;
 
-  init_time(st);
-  
-  if (strlen(s) > 0)
-    start_eval_file(st->machine,s, plot6502, st);
-  else
-    start_rand_bin_prog(st->machine,st);
+  st->last_frame = double_time();
+  st->last_delay = 0;
+  st->ips = get_integer_resource(dpy, "ips", "IPS");
+
+#ifdef READ_FILES
+  st->file = get_string_resource (dpy, "file", "File");
+#endif
+
+  st->reset_p = 1;
 
   analogtv_lcp_to_ntsc(ANALOGTV_BLACK_LEVEL, 0.0, 0.0, st->field_ntsc);
 
@@ -153,10 +156,6 @@ m6502_init (Display *dpy, Window window)
                       ANALOGTV_TOP, ANALOGTV_BOT,
                       st->field_ntsc);
 
-  for(x = 0; x < 32; x++)
-    for(y = 0; y < 32; y++)
-      st->pixels[x][y] = 0;
-
   return st;
 }
 
@@ -212,29 +211,45 @@ m6502_draw (Display *dpy, Window window, void *closure)
 {
   struct state *st = (struct state *) closure;
   unsigned int x = 0, y = 0;
-  double te;
+  double now, last_delay = st->last_delay >= 0 ? st->last_delay : 0;
+  double insno = st->ips * ((1 / 29.97) + last_delay - st->last_delay);
+  const analogtv_reception *reception = &st->reception;
+
+  if (st->reset_p){ /* do something more interesting here XXX */
+    st->reset_p = 0;
+    for(x = 0; x < 32; x++)
+      for(y = 0; y < 32; y++)
+        st->pixels[x][y] = 0;
+    st->start_time = st->last_frame + last_delay;
 
-  next_eval(st->machine,500);
+#ifdef READ_FILES
+    if (st->file && *st->file)
+      m6502_start_eval_file(st->machine, st->file, plot6502, st);
+    else
+#endif
+      start_rand_bin_prog(st->machine,st);
+  }
+
+  if (insno < 10)
+    insno = 10;
+  else if (insno > 100000) /* Real 6502 went no faster than 3 MHz. */
+    insno = 100000;
+  m6502_next_eval(st->machine,insno);
 
   for (x = 0; x < 32; x++)
     for (y = 0; y < 32; y++)
       paint_pixel(st,x,y,st->pixels[x][y]);
   
-  analogtv_init_signal(st->tv, 0.04);
   analogtv_reception_update(&st->reception);
-  analogtv_add_signal(st->tv, &st->reception);
-  analogtv_draw(st->tv);
-  te = get_time(st);
-  
-  if (te > st->dt){ /* do something more interesting here XXX */
-    for(x = 0; x < 32; x++)
-      for(y = 0; y < 32; y++)
-       st->pixels[x][y] = 0;
-    init_time(st);
-    start_rand_bin_prog(st->machine,st);
-  }
+  analogtv_draw(st->tv, 0.04, &reception, 1);
+  now = double_time();
+  st->last_delay = (1 / 29.97) + st->last_frame + last_delay - now;
+  st->last_frame = now;
+
+  if (now - st->start_time > st->dt)
+    st->reset_p = 1;
 
-  return 10000;
+  return st->last_delay >= 0 ? st->last_delay * 1e6 : 0;
 }
 
 
@@ -244,15 +259,18 @@ static const char *m6502_defaults [] = {
   ".background:      black",
   ".foreground:      white",
   "*file:",
-  "*displaytime:     20",
+  "*displaytime:     30.0",     /* demoscene: 24s, dmsc: 48s, sierpinsky: 26s
+                                   sflake, two runs: 35s
+                                 */
+  "*ips:             15000",    /* Actual MOS 6502 ran at least 1 MHz. */
   ANALOGTV_DEFAULTS
-  "*TVContrast:      150",
   0
 };
 
 static XrmOptionDescRec m6502_options [] = {
   { "-file",           ".file",     XrmoptionSepArg, 0 },
   { "-displaytime",    ".displaytime", XrmoptionSepArg, 0},
+  { "-ips",            ".ips",         XrmoptionSepArg, 0},
   ANALOGTV_OPTIONS
   { 0, 0, 0, 0 }
 };
@@ -268,6 +286,12 @@ m6502_reshape (Display *dpy, Window window, void *closure,
 static Bool
 m6502_event (Display *dpy, Window window, void *closure, XEvent *event)
 {
+  struct state *st = (struct state *) closure;
+  if (screenhack_event_helper (dpy, window, event))
+    {
+      st->reset_p = 1;
+      return True;
+    }
   return False;
 }
 
@@ -276,6 +300,7 @@ m6502_free (Display *dpy, Window window, void *closure)
 {
   struct state *st = (struct state *) closure;
   analogtv_release(st->tv);
+  free (st->file);
   free (st);
 }