diff options
Diffstat (limited to 'hacks/m6502.c')
-rw-r--r-- | hacks/m6502.c | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/hacks/m6502.c b/hacks/m6502.c new file mode 100644 index 0000000..ce18e9d --- /dev/null +++ b/hacks/m6502.c @@ -0,0 +1,307 @@ +/* -*- indent-tabs-mode:nil -*- + * Copyright (c) 2007 Jeremy English <jhe@jeremyenglish.org> + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * 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" +#include "asm6502.h" + +# ifdef __GNUC__ + __extension__ /* don't warn about "string length is greater than the length + ISO C89 compilers are required to support" when includng + the following data file... */ +# endif +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 { + SCREEN_W = ANALOGTV_VIS_LEN, + SCREEN_H = ANALOGTV_VISLINES, + NUM_PROGS = 9 +}; + +struct state { + Display *dpy; + Window window; + + Bit8 pixels[32][32]; + + machine_6502 *machine; + + analogtv *tv; + analogtv_input *inp; + analogtv_reception reception; + int pixw; /* pixel width */ + int pixh;/* pixel height */ + int topb;/* top boarder */ + int field_ntsc[4];/* used for clearing the screen*/ + double dt;/* how long to wait before changing the demo*/ + int which;/* the program to run*/ + int demos;/* number of demos included */ + double start_time; + int reset_p; + char *file; + double last_frame, last_delay; + unsigned ips; +}; + +static void +plot6502(Bit8 x, Bit8 y, Bit8 color, void *closure) +{ + struct state *st = (struct state *) closure; + st->pixels[x][y] = color; +} + +#undef countof +#define countof(x) (sizeof((x))/sizeof((*x))) + + +static void +start_rand_bin_prog(machine_6502 *machine, struct state *st){ + int n = st->which; + while(n == st->which) + n = random() % st->demos; + st->which = n; + m6502_start_eval_string(machine, demo_files[st->which], plot6502, st); +} + + +/* + * double_time () + * + * returns the current time as a floating-point value + */ +static double double_time(void) { + struct timeval t; + double f; +#if GETTIMEOFDAY_TWO_ARGS + gettimeofday(&t, NULL); +#else + gettimeofday(&t); +#endif + f = ((double)t.tv_sec) + t.tv_usec*1e-6; + return f; +} + +static void * +m6502_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + int n = get_float_resource(dpy, "displaytime", "Displaytime"); + int dh; + st->demos = countof(demo_files); + st->which = random() % st->demos; + st->dt = n; + st->dpy = dpy; + st->window = window; + st->tv=analogtv_allocate(st->dpy, st->window); + analogtv_set_defaults(st->tv, ""); + + st->machine = m6502_build(); + st->inp=analogtv_input_allocate(); + analogtv_setup_sync(st->inp, 1, 0); + + st->reception.input = st->inp; + st->reception.level = 2.0; + st->reception.ofs=0; + + st->reception.multipath=0.0; + st->pixw = SCREEN_W / 32; + st->pixh = SCREEN_H / 32; + dh = SCREEN_H % 32; + st->topb = dh / 2; + + 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); + + analogtv_draw_solid(st->inp, + ANALOGTV_VIS_START, ANALOGTV_VIS_END, + ANALOGTV_TOP, ANALOGTV_BOT, + st->field_ntsc); + + return st; +} + +static void +paint_pixel(struct state *st, int x, int y, int idx) +{ + double clr_tbl[16][3] = { + { 0, 0, 0}, + {255, 255, 255}, + {136, 0, 0}, + {170, 255, 238}, + {204, 68, 204}, + { 0, 204, 85}, + { 0, 0, 170}, + {238, 238, 119}, + {221, 136, 85}, + {102, 68, 0}, + {255, 119, 119}, + { 51, 51, 51}, + {119, 119, 119}, + {170, 255, 102}, + { 0, 136, 255}, + {187, 187, 187} + }; + int ntsc[4], i; + int rawy,rawi,rawq; + /* RGB conversion taken from analogtv draw xpm */ + rawy=( 5*clr_tbl[idx][0] + 11*clr_tbl[idx][1] + 2*clr_tbl[idx][2]) / 64; + rawi=(10*clr_tbl[idx][0] - 4*clr_tbl[idx][1] - 5*clr_tbl[idx][2]) / 64; + rawq=( 3*clr_tbl[idx][0] - 8*clr_tbl[idx][1] + 5*clr_tbl[idx][2]) / 64; + + ntsc[0]=rawy+rawq; + ntsc[1]=rawy-rawi; + ntsc[2]=rawy-rawq; + ntsc[3]=rawy+rawi; + + for (i=0; i<4; i++) { + if (ntsc[i]>ANALOGTV_WHITE_LEVEL) ntsc[i]=ANALOGTV_WHITE_LEVEL; + if (ntsc[i]<ANALOGTV_BLACK_LEVEL) ntsc[i]=ANALOGTV_BLACK_LEVEL; + } + + + x *= st->pixw; + y *= st->pixh; + y += st->topb; + analogtv_draw_solid(st->inp, + ANALOGTV_VIS_START + x, ANALOGTV_VIS_START + x + st->pixw, + ANALOGTV_TOP + y, ANALOGTV_TOP + y + st->pixh, ntsc); +} + +static unsigned long +m6502_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + unsigned int x = 0, y = 0; + 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; + +#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_reception_update(&st->reception); + 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 st->last_delay >= 0 ? st->last_delay * 1e6 : 0; +} + + + + +static const char *m6502_defaults [] = { + ".background: black", + ".foreground: white", + "*file:", + "*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 + 0 +}; + +static XrmOptionDescRec m6502_options [] = { + { "-file", ".file", XrmoptionSepArg, 0 }, + { "-displaytime", ".displaytime", XrmoptionSepArg, 0}, + { "-ips", ".ips", XrmoptionSepArg, 0}, + ANALOGTV_OPTIONS + { 0, 0, 0, 0 } +}; + +static void +m6502_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + analogtv_reconfigure (st->tv); +} + +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; +} + +static void +m6502_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + analogtv_release(st->tv); + free (st->file); + free (st); +} + +XSCREENSAVER_MODULE ("m6502", m6502) |