From http://www.jwz.org/xscreensaver/xscreensaver-5.27.tar.gz
[xscreensaver] / hacks / m6502.c
1 /* -*- indent-tabs-mode:nil -*-
2  * Copyright (c) 2007 Jeremy English <jhe@jeremyenglish.org>
3  * 
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  * 
12  * Created: 07-May-2007 
13  */
14
15 #include <stdint.h> 
16 #include <string.h>
17 #include "screenhack.h"
18 #include "analogtv.h"
19 #include "asm6502.h"
20
21 # ifdef __GNUC__
22   __extension__  /* don't warn about "string length is greater than the length
23                     ISO C89 compilers are required to support" when includng
24                     the following data file... */
25 # endif
26 static const char * const demo_files[] = {
27 # include "m6502.h"
28 };
29
30
31 #ifndef USE_IPHONE
32 # define READ_FILES
33 #endif
34
35
36 /* We want to paint on a 32 by 32 grid of pixels. We will needed to
37    divided the screen up into chuncks */
38 enum {
39   SCREEN_W = ANALOGTV_VIS_LEN,
40   SCREEN_H = ANALOGTV_VISLINES,
41   NUM_PROGS = 9
42 };
43
44 struct state {
45   Display *dpy;
46   Window window;
47   
48   Bit8 pixels[32][32];
49
50   machine_6502 *machine;
51
52   analogtv *tv;
53   analogtv_input *inp;
54   analogtv_reception reception;
55   int pixw; /* pixel width */
56   int pixh;/* pixel height */
57   int topb;/* top boarder */
58   int field_ntsc[4];/* used for clearing the screen*/ 
59   int dt;/* how long to wait before changing the demo*/
60   int which;/* the program to run*/
61   int demos;/* number of demos included */
62   struct timeval start_time; 
63 };
64
65 static void
66 plot6502(Bit8 x, Bit8 y, Bit8 color, void *closure)
67 {
68   struct state *st = (struct state *) closure;
69   st->pixels[x][y] = color;
70 }
71
72 #undef countof
73 #define countof(x) (sizeof((x))/sizeof((*x)))
74
75
76 static void 
77 start_rand_bin_prog(machine_6502 *machine, struct state *st){
78   int n = st->which;
79   while(n == st->which)
80     n = random() % st->demos;
81   st->which = n;
82   m6502_start_eval_string(machine, demo_files[st->which], plot6502, st);
83 }
84
85 \f
86 /*
87  * get_time ()
88  *
89  * returns the total time elapsed since the beginning of the demo
90  */
91 static double get_time(struct state *st) {
92   struct timeval t;
93   float f;
94 #if GETTIMEOFDAY_TWO_ARGS
95   gettimeofday(&t, NULL);
96 #else
97   gettimeofday(&t);
98 #endif
99   t.tv_sec -= st->start_time.tv_sec;
100   f = ((double)t.tv_sec) + t.tv_usec*1e-6;
101   return f;
102 }
103
104 /*
105  * init_time ()
106  *
107  * initialises the timing structures
108  */
109 static void init_time(struct state *st) {
110 #if GETTIMEOFDAY_TWO_ARGS
111   gettimeofday(&st->start_time, NULL);
112 #else
113   gettimeofday(&st->start_time);
114 #endif
115 }
116
117 static void *
118 m6502_init (Display *dpy, Window window)
119 {
120   struct state *st = (struct state *) calloc (1, sizeof(*st));
121   unsigned int x, y;
122   int n = get_integer_resource(dpy, "displaytime", "Displaytime");
123   int dh;
124   st->demos = countof(demo_files);
125   st->which = random() % st->demos;
126   st->dt = n;
127   st->dpy = dpy;
128   st->window = window;
129   st->tv=analogtv_allocate(st->dpy, st->window);
130   analogtv_set_defaults(st->tv, "");
131   
132   st->machine = m6502_build();
133   st->inp=analogtv_input_allocate();
134   analogtv_setup_sync(st->inp, 1, 0);
135   
136   st->reception.input = st->inp;
137   st->reception.level = 2.0;
138   st->reception.ofs=0;
139   
140   st->reception.multipath=0.0;
141   st->pixw = SCREEN_W / 32;
142   st->pixh = SCREEN_H / 32;
143   dh = SCREEN_H % 32;
144   st->topb = dh / 2;
145
146   init_time(st);
147   
148   {
149 #ifdef READ_FILES
150     char *s = get_string_resource (dpy, "file", "File");
151     if (strlen(s) > 0)
152       m6502_start_eval_file(st->machine,s, plot6502, st);
153   else
154 #endif
155     start_rand_bin_prog(st->machine,st);
156   }
157
158   analogtv_lcp_to_ntsc(ANALOGTV_BLACK_LEVEL, 0.0, 0.0, st->field_ntsc);
159
160   analogtv_draw_solid(st->inp,
161                       ANALOGTV_VIS_START, ANALOGTV_VIS_END,
162                       ANALOGTV_TOP, ANALOGTV_BOT,
163                       st->field_ntsc);
164
165   for(x = 0; x < 32; x++)
166     for(y = 0; y < 32; y++)
167       st->pixels[x][y] = 0;
168
169   return st;
170 }
171
172 static void
173 paint_pixel(struct state *st, int x, int y, int idx)
174 {
175   double clr_tbl[16][3] = {
176     {  0,   0,   0},
177     {255, 255, 255},
178     {136,   0,   0},
179     {170, 255, 238},
180     {204,  68, 204},
181     {  0, 204,  85},
182     {  0,   0, 170},
183     {238, 238, 119},
184     {221, 136,  85},
185     {102,  68,   0},
186     {255, 119, 119},
187     { 51,  51,  51},
188     {119, 119, 119},
189     {170, 255, 102},
190     {  0, 136, 255},
191     {187, 187, 187}
192   };
193   int ntsc[4], i;
194   int rawy,rawi,rawq;
195   /* RGB conversion taken from analogtv draw xpm */
196   rawy=( 5*clr_tbl[idx][0] + 11*clr_tbl[idx][1] + 2*clr_tbl[idx][2]) / 64;
197   rawi=(10*clr_tbl[idx][0] -  4*clr_tbl[idx][1] - 5*clr_tbl[idx][2]) / 64;
198   rawq=( 3*clr_tbl[idx][0] -  8*clr_tbl[idx][1] + 5*clr_tbl[idx][2]) / 64;
199
200   ntsc[0]=rawy+rawq;
201   ntsc[1]=rawy-rawi;
202   ntsc[2]=rawy-rawq;
203   ntsc[3]=rawy+rawi;
204
205   for (i=0; i<4; i++) {
206     if (ntsc[i]>ANALOGTV_WHITE_LEVEL) ntsc[i]=ANALOGTV_WHITE_LEVEL;
207     if (ntsc[i]<ANALOGTV_BLACK_LEVEL) ntsc[i]=ANALOGTV_BLACK_LEVEL;
208   }
209
210       
211   x *= st->pixw;
212   y *= st->pixh;
213   y += st->topb;
214   analogtv_draw_solid(st->inp,
215                       ANALOGTV_VIS_START + x, ANALOGTV_VIS_START + x + st->pixw,
216                       ANALOGTV_TOP + y, ANALOGTV_TOP + y + st->pixh, ntsc);                           
217 }
218
219 static unsigned long
220 m6502_draw (Display *dpy, Window window, void *closure)
221 {
222   struct state *st = (struct state *) closure;
223   unsigned int x = 0, y = 0;
224   double te;
225   const analogtv_reception *reception = &st->reception;
226
227   m6502_next_eval(st->machine,500);
228
229   for (x = 0; x < 32; x++)
230     for (y = 0; y < 32; y++)
231       paint_pixel(st,x,y,st->pixels[x][y]);
232   
233   analogtv_reception_update(&st->reception);
234   analogtv_draw(st->tv, 0.04, &reception, 1);
235   te = get_time(st);
236   
237   if (te > st->dt){ /* do something more interesting here XXX */
238     for(x = 0; x < 32; x++)
239       for(y = 0; y < 32; y++)
240         st->pixels[x][y] = 0;
241     init_time(st);
242     start_rand_bin_prog(st->machine,st);
243   }
244
245 #ifdef USE_IPHONE
246   return 0;
247 #else
248   return 5000;
249 #endif
250 }
251
252
253 \f
254
255 static const char *m6502_defaults [] = {
256   ".background:      black",
257   ".foreground:      white",
258   "*file:",
259   "*displaytime:     20",
260   ANALOGTV_DEFAULTS
261   0
262 };
263
264 static XrmOptionDescRec m6502_options [] = {
265   { "-file",           ".file",     XrmoptionSepArg, 0 },
266   { "-displaytime",    ".displaytime", XrmoptionSepArg, 0},
267   ANALOGTV_OPTIONS
268   { 0, 0, 0, 0 }
269 };
270
271 static void
272 m6502_reshape (Display *dpy, Window window, void *closure, 
273                  unsigned int w, unsigned int h)
274 {
275   struct state *st = (struct state *) closure;
276   analogtv_reconfigure (st->tv);
277 }
278
279 static Bool
280 m6502_event (Display *dpy, Window window, void *closure, XEvent *event)
281 {
282   return False;
283 }
284
285 static void
286 m6502_free (Display *dpy, Window window, void *closure)
287 {
288   struct state *st = (struct state *) closure;
289   analogtv_release(st->tv);
290   free (st);
291 }
292
293 XSCREENSAVER_MODULE ("m6502", m6502)